fix: refresh pi dependency compatibility
Update Pi packages to 0.79.9 and align pi-ask with current TUI/RPC behavior. - guard custom ask/settings flows to TUI mode with a clear non-TUI fallback - reset config cache on extension reload so edited settings are picked up - clean up remote ask flow listeners on session shutdown - forward editor focus/invalidation and keep @ file autocomplete explicit - document the non-TUI contract and cover the compatibility fixes with tests
This commit is contained in:
+3
-3
@@ -255,9 +255,9 @@ Dirty dismiss:
|
||||
- when `Confirm dismiss when dirty` is enabled, cancelling or dismissing a dirty ask flow requires the same action a second time
|
||||
- the dirty-dismiss warning stays visible until the user changes tabs in the ask flow
|
||||
|
||||
## Non-interactive mode
|
||||
## Non-TUI and non-interactive modes
|
||||
|
||||
If `ctx.hasUI === false`, the tool returns a `Needs user input` message in `content` and a cancelled result in `details`.
|
||||
The rich ask flow uses `ctx.ui.custom()` and opens only in TUI mode. In print, JSON, RPC, or any other non-TUI mode, the tool returns a `Needs user input: ask_user requires interactive TUI mode.` message in `content` and a cancelled result in `details` instead of opening custom UI.
|
||||
|
||||
Validation is handled inside the tool so malformed calls produce the same structured error shape as other invalid payloads instead of relying on pre-execution schema failures.
|
||||
|
||||
@@ -269,7 +269,7 @@ When enabled, pi-ask emits one best-effort external notification per ask session
|
||||
|
||||
## Remote inter-extension events
|
||||
|
||||
pi-ask exposes a local `pi.events` contract for trusted Pi extensions. It does not expose a network API and does not automate terminal keystrokes.
|
||||
pi-ask exposes a local `pi.events` contract for trusted Pi extensions. It does not expose a network API and does not automate terminal keystrokes. RPC or headless integrations should use a trusted in-process bridge extension that consumes these events rather than expecting the TUI-only custom surface to open.
|
||||
|
||||
Channels:
|
||||
|
||||
|
||||
+7
-7
@@ -93,9 +93,9 @@
|
||||
"@biomejs/biome": "2.4.12",
|
||||
"@commitlint/cli": "^19.8.1",
|
||||
"@commitlint/config-conventional": "^19.8.1",
|
||||
"@earendil-works/pi-ai": "0.75.4",
|
||||
"@earendil-works/pi-coding-agent": "0.75.4",
|
||||
"@earendil-works/pi-tui": "0.75.4",
|
||||
"@earendil-works/pi-ai": "0.79.9",
|
||||
"@earendil-works/pi-coding-agent": "0.79.9",
|
||||
"@earendil-works/pi-tui": "0.79.9",
|
||||
"@semantic-release/changelog": "^6.0.3",
|
||||
"@semantic-release/commit-analyzer": "^13.0.1",
|
||||
"@semantic-release/git": "^10.0.1",
|
||||
@@ -118,10 +118,10 @@
|
||||
},
|
||||
"pnpm": {
|
||||
"overrides": {
|
||||
"@earendil-works/pi-agent-core": "0.75.4",
|
||||
"@earendil-works/pi-ai": "0.75.4",
|
||||
"@earendil-works/pi-tui": "0.75.4",
|
||||
"@earendil-works/pi-coding-agent": "0.75.4"
|
||||
"@earendil-works/pi-agent-core": "0.79.9",
|
||||
"@earendil-works/pi-ai": "0.79.9",
|
||||
"@earendil-works/pi-tui": "0.79.9",
|
||||
"@earendil-works/pi-coding-agent": "0.79.9"
|
||||
},
|
||||
"ignoredBuiltDependencies": [
|
||||
"lefthook"
|
||||
|
||||
Generated
+130
-105
@@ -5,10 +5,10 @@ settings:
|
||||
excludeLinksFromLockfile: false
|
||||
|
||||
overrides:
|
||||
'@earendil-works/pi-agent-core': 0.75.4
|
||||
'@earendil-works/pi-ai': 0.75.4
|
||||
'@earendil-works/pi-tui': 0.75.4
|
||||
'@earendil-works/pi-coding-agent': 0.75.4
|
||||
'@earendil-works/pi-agent-core': 0.79.9
|
||||
'@earendil-works/pi-ai': 0.79.9
|
||||
'@earendil-works/pi-tui': 0.79.9
|
||||
'@earendil-works/pi-coding-agent': 0.79.9
|
||||
|
||||
importers:
|
||||
|
||||
@@ -24,14 +24,14 @@ importers:
|
||||
specifier: ^19.8.1
|
||||
version: 19.8.1
|
||||
'@earendil-works/pi-ai':
|
||||
specifier: 0.75.4
|
||||
version: 0.75.4(ws@8.20.0)(zod@4.3.6)
|
||||
specifier: 0.79.9
|
||||
version: 0.79.9(ws@8.20.0)(zod@4.3.6)
|
||||
'@earendil-works/pi-coding-agent':
|
||||
specifier: 0.75.4
|
||||
version: 0.75.4(ws@8.20.0)(zod@4.3.6)
|
||||
specifier: 0.79.9
|
||||
version: 0.79.9(ws@8.20.0)(zod@4.3.6)
|
||||
'@earendil-works/pi-tui':
|
||||
specifier: 0.75.4
|
||||
version: 0.75.4
|
||||
specifier: 0.79.9
|
||||
version: 0.79.9
|
||||
'@semantic-release/changelog':
|
||||
specifier: ^6.0.3
|
||||
version: 6.0.3(semantic-release@25.0.3(typescript@6.0.2))
|
||||
@@ -367,22 +367,22 @@ packages:
|
||||
resolution: {integrity: sha512-ZJoS8oSq2CAZEpc/YI9SulLrdiIyXeHb/OGqGrkUP6Q7YV+0ouNAa7GjqRdXeQPncHQIDz/jbCTlHScvYvO/gA==}
|
||||
engines: {node: '>=v18'}
|
||||
|
||||
'@earendil-works/pi-agent-core@0.75.4':
|
||||
resolution: {integrity: sha512-cGYbysb4EqUf0B28OeqFq2ppm1XF3bYBOP71q9dv38yf/UJfzMjiXBeNelrcio+QWIoVrW+xzYm7sMzYIUc9Og==}
|
||||
'@earendil-works/pi-agent-core@0.79.9':
|
||||
resolution: {integrity: sha512-GsFbPR85nhncKoU9++fTKa11PzwUkAmkrKXo97dBOzi10Td72rVV6vmfxKjwPLHTzRbJMa0byr12YhODZ59yLA==}
|
||||
engines: {node: '>=22.19.0'}
|
||||
|
||||
'@earendil-works/pi-ai@0.75.4':
|
||||
resolution: {integrity: sha512-m/w8Hh3vQ0rAycwJiJWdzkypkn4295f4eq/966lDRy8aX5sk6bgYXH8TQmL16TO7Uwc7MbJG0QoyFHgX8RqXUQ==}
|
||||
'@earendil-works/pi-ai@0.79.9':
|
||||
resolution: {integrity: sha512-fHmgNMONwCCE7bQAKbcz76sgm3iQuA7km1mpIc4H5xXd9+zhPh/faULz6ARkgjQE0EufHnfZPJY39+lNf8Sa9g==}
|
||||
engines: {node: '>=22.19.0'}
|
||||
hasBin: true
|
||||
|
||||
'@earendil-works/pi-coding-agent@0.75.4':
|
||||
resolution: {integrity: sha512-Fb+FRo08b5H9pYKbQJ708/5OKL0+K/yclhfCMEhrBzSPTZZ4c85nY1YsBo4qwL20ohBMlBezHMRuHzcJ1ylEoQ==}
|
||||
'@earendil-works/pi-coding-agent@0.79.9':
|
||||
resolution: {integrity: sha512-8TZ796Zn0NE4vmhxG9hv4ZtJDGJzhqMjlmFg8ZkUKxfqB7LJa4ums2jSJKtnyAZfAamN6VzqzN0A82RNDqv8Ag==}
|
||||
engines: {node: '>=22.19.0'}
|
||||
hasBin: true
|
||||
|
||||
'@earendil-works/pi-tui@0.75.4':
|
||||
resolution: {integrity: sha512-PDhKU7u6fmEcvHUFHzrRwGc/Ytokj/hO+X4RPf+MWKEGpvg3B1vHv88Ee+Dy33004tYkQF5YeXV4btJZcp5x1g==}
|
||||
'@earendil-works/pi-tui@0.79.9':
|
||||
resolution: {integrity: sha512-XcqfoGyoX64OSMQklMR1vG2MRi1TCPSUERRCmPDvYKCK6LtZoBqJ6idNCLRklNYveCj4gHDOzOsLhGqn04jmYw==}
|
||||
engines: {node: '>=22.19.0'}
|
||||
|
||||
'@google/genai@1.52.0':
|
||||
@@ -394,76 +394,81 @@ packages:
|
||||
'@modelcontextprotocol/sdk':
|
||||
optional: true
|
||||
|
||||
'@mariozechner/clipboard-darwin-arm64@0.3.6':
|
||||
resolution: {integrity: sha512-HjaisYCAbHi/1+N1yDAQHc8ZXGffufIUT5NSOSVR3f3AuMDusxTtnbK8tZ7JFDkShua1oNGZoNwQHsc8MPtE0Q==}
|
||||
'@mariozechner/clipboard-darwin-arm64@0.3.9':
|
||||
resolution: {integrity: sha512-BfgV7vCEWZwJwZJw03r6bP5+tf0iI/ANuQYCxi9RNn7FrWB3yzGuMKCrNLRl6V761vXRdL8+OqZ0wd4TqlsNOQ==}
|
||||
engines: {node: '>= 10'}
|
||||
cpu: [arm64]
|
||||
os: [darwin]
|
||||
|
||||
'@mariozechner/clipboard-darwin-universal@0.3.6':
|
||||
resolution: {integrity: sha512-8BWtPjOtJOJoykml3w0fx0zRrfWP31mXrJwfoA7xzNprkZw1uolCNfgmjDiVBseoKjp16EGITz7bN+61qn8dWA==}
|
||||
'@mariozechner/clipboard-darwin-universal@0.3.9':
|
||||
resolution: {integrity: sha512-BGGR4iA9Z2shAjI65eI5xtyb3LYNlDW9X3gxKxDbqtbnREohsrqznov6zpKoIrsRWpzlYVEdKphS7ksJ0/ndSQ==}
|
||||
engines: {node: '>= 10'}
|
||||
os: [darwin]
|
||||
|
||||
'@mariozechner/clipboard-darwin-x64@0.3.6':
|
||||
resolution: {integrity: sha512-p9syiZD1kU4I+1ya7f7g+zD1GiUvR8fdlRlNmgsZNWlyjtc8rlV2EjTLd/35x1LsdBq020GVvtzp0ZmPgBI09Q==}
|
||||
'@mariozechner/clipboard-darwin-x64@0.3.9':
|
||||
resolution: {integrity: sha512-4kURmCbS6nt8uYhtmWpUcJWyPHfmAr5dTpXD1nO3pIfa+TSQ9DbrGOYCKH+aEFW47XhQ4Vp8ZTszie+wfFvDKg==}
|
||||
engines: {node: '>= 10'}
|
||||
cpu: [x64]
|
||||
os: [darwin]
|
||||
|
||||
'@mariozechner/clipboard-linux-arm64-gnu@0.3.6':
|
||||
resolution: {integrity: sha512-5JFf5rGofrm+V29HNF+wLthXphHdQpMbKDUYJ5tML6/Z5DLlLOV/9Ak4kDPtYyZ+Dzf+kAusE0VsFg4+tfP1IA==}
|
||||
'@mariozechner/clipboard-linux-arm64-gnu@0.3.9':
|
||||
resolution: {integrity: sha512-g59OkUGP2DDfCOIKypHeYgv2M55u/cKvXa5dSxFbEJ34XvIQMdcVmpKCkGUro3ZgefXiGVdwguvTMQGpHWzIXw==}
|
||||
engines: {node: '>= 10'}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@mariozechner/clipboard-linux-arm64-musl@0.3.6':
|
||||
resolution: {integrity: sha512-JlVjxxw0GbGC0djXYWRIqyteO3J1KZ/QG3udlEFaOD5TLOM1FnmXXAPDQBqr+aBVr720ef9K00dirYnJ0LDCtw==}
|
||||
'@mariozechner/clipboard-linux-arm64-musl@0.3.9':
|
||||
resolution: {integrity: sha512-AGuJdgKsmJdm4Pych7kv3sqe591ERRaAHW3xjLooiFzn8J+PxUyof++7YZrB5Y5tpnTO+K18Og3taj2NpluCRQ==}
|
||||
engines: {node: '>= 10'}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
libc: [musl]
|
||||
|
||||
'@mariozechner/clipboard-linux-riscv64-gnu@0.3.6':
|
||||
resolution: {integrity: sha512-4t8BUi5zZ+L77otFQVnVSlaTyAX4TVk9EqQm4syMrEQp96trFEHEwwNHcNEBGzYv5+K7mxay50TthYkz47OWzQ==}
|
||||
'@mariozechner/clipboard-linux-riscv64-gnu@0.3.9':
|
||||
resolution: {integrity: sha512-DXBEAiuMpk7dhS1a9NzNxVAFi1vaKoPu7rQNgY8LIDLGrK3lnIp3nT10DUum+PKVJoJppIP+NAA8IZe4DMNDPw==}
|
||||
engines: {node: '>= 10'}
|
||||
cpu: [riscv64]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@mariozechner/clipboard-linux-x64-gnu@0.3.6':
|
||||
resolution: {integrity: sha512-trtPwcNLW37irwQCJLtCxLw757jjJZk3TSnY/MU9bhtWtA3K9b/eLW0e4RGhUXDoFRds9opNWWaUDuFLa8dm0w==}
|
||||
'@mariozechner/clipboard-linux-x64-gnu@0.3.9':
|
||||
resolution: {integrity: sha512-WORrMLd6EpElEME7JRKfSaY34nW1P5LbdgK5YNCS1ncG2LqmITsSMEJ8nh2mpvxb3TxqbOOKgY7k9eMJYlW9Mw==}
|
||||
engines: {node: '>= 10'}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
libc: [glibc]
|
||||
|
||||
'@mariozechner/clipboard-linux-x64-musl@0.3.6':
|
||||
resolution: {integrity: sha512-WfnzIvOCCWQiN0MmltCEo6cLceUDbYe+I7xyFZjaps5A+2Op/M2CY7Rey+C4ucQhrvmpoHmTSFgY9ODWk7snoA==}
|
||||
'@mariozechner/clipboard-linux-x64-musl@0.3.9':
|
||||
resolution: {integrity: sha512-/DHn+1DrfL6oRaPPWXaOKvonFFrni666fxd+zFqiQEfvBH0tsHVWjq9iqBk0oDp0qaPA72lIMy5BptxISBEhZQ==}
|
||||
engines: {node: '>= 10'}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
libc: [musl]
|
||||
|
||||
'@mariozechner/clipboard-win32-arm64-msvc@0.3.6':
|
||||
resolution: {integrity: sha512-+8+1aHYsBPUjmW3otmWlg+Hijt0iJvoBBs5e0mxFeUd4gDaKMB8Bn6x7c6KVtscg7E5j5NFXnwQqNSIAO4p8zQ==}
|
||||
'@mariozechner/clipboard-win32-arm64-msvc@0.3.9':
|
||||
resolution: {integrity: sha512-O5FHD3ErkMwMhNzAfu3ggy0ug4z7btZuoQgwwxlzPrwV2bxlD6WDpqBY4NCgICAgZdDKdp+loUEKVAVt8aYnhQ==}
|
||||
engines: {node: '>= 10'}
|
||||
cpu: [arm64]
|
||||
os: [win32]
|
||||
|
||||
'@mariozechner/clipboard-win32-x64-msvc@0.3.6':
|
||||
resolution: {integrity: sha512-S4xfPmERC8ZkiLHe3vekZCjdDwNEETCuvCgQK2kP6/TnvmUkq1y2Pk+DjM4t8uh9KMX9bH4zs5ePcKa8GTXmfg==}
|
||||
'@mariozechner/clipboard-win32-x64-msvc@0.3.9':
|
||||
resolution: {integrity: sha512-ihQC3EufqEY81vhXBgVBtK4prL+wc62zJsSvxrgz7K1hsdt6OObz6v9p3Rn1OG3GJksTTKMJF0u/guMISHPhSA==}
|
||||
engines: {node: '>= 10'}
|
||||
cpu: [x64]
|
||||
os: [win32]
|
||||
|
||||
'@mariozechner/clipboard@0.3.6':
|
||||
resolution: {integrity: sha512-MXdtr+6+ntlIVHdrZYuZNQydu6o8yZswFJ2Ln81j2O/Y9B/LDHvEaIm95xWNPkjGTWriSOeLnQJRFs6dYb60bg==}
|
||||
'@mariozechner/clipboard@0.3.9':
|
||||
resolution: {integrity: sha512-ABnA53mdfkGZwOFUdZNv2S0CWGO/EIuPj8Vv9xmBFmSYg/qFc7ihO6q5FcQjvoE67kZpWkEc4AhD6B/os04yuA==}
|
||||
engines: {node: '>= 10'}
|
||||
|
||||
'@mistralai/mistralai@2.2.1':
|
||||
resolution: {integrity: sha512-uKU8CZmL2RzYKmplsU01hii4p3pe4HqJefpWNRWXm1Tcm0Sm4xXfwSLIy4k7ZCPlbETCGcp69E7hZs+WOJ5itQ==}
|
||||
'@mistralai/mistralai@2.2.6':
|
||||
resolution: {integrity: sha512-W8pX7zHxjJvMIpw8JMxeJEleapXX0Q9NPszdNzqkM3MIEoIGPObdodujj+WHteXEvGfaP/AMwlNyRfEzSY6dQQ==}
|
||||
peerDependencies:
|
||||
'@opentelemetry/api': ^1.9.0
|
||||
peerDependenciesMeta:
|
||||
'@opentelemetry/api':
|
||||
optional: true
|
||||
|
||||
'@nodable/entities@2.1.0':
|
||||
resolution: {integrity: sha512-nyT7T3nbMyBI/lvr6L5TyWbFJAI9FTgVRakNoBqCD+PmID8DzFrrNdLLtHMwMszOtqZa8PAOV24ZqDnQrhQINA==}
|
||||
@@ -516,6 +521,14 @@ packages:
|
||||
'@octokit/types@16.0.0':
|
||||
resolution: {integrity: sha512-sKq+9r1Mm4efXW1FCk7hFSeJo4QKreL/tTbR0rz/qx/r1Oa2VV83LTA/H/MuCOX7uCIJmQVRKBcbmWoySjAnSg==}
|
||||
|
||||
'@opentelemetry/api@1.9.0':
|
||||
resolution: {integrity: sha512-3giAOQvZiH5F9bMlMiv8+GSPMeqg0dbaeo58/0SlA9sxSqZhnUtxzX9/2FzyhS9sWQf5S0GJE0AKBrFqjpeYcg==}
|
||||
engines: {node: '>=8.0.0'}
|
||||
|
||||
'@opentelemetry/semantic-conventions@1.41.1':
|
||||
resolution: {integrity: sha512-/UhIkaZgPutTFmQ7RnIJGgDXZmtEJ7Dvi86xNTFWcnRxVRNk/aotsqDJYeEvDP+FSMB2SdW+pQzNMcWP0rwuNA==}
|
||||
engines: {node: '>=14'}
|
||||
|
||||
'@pnpm/config.env-replace@1.1.0':
|
||||
resolution: {integrity: sha512-htyl8TWnKL7K/ESFa1oW2UB5lVDxuF5DpM7tBi6Hu2LNL3mWkIzNLG6N4zoCUP1lCKNxWy/3iu8mS8MvToGd6w==}
|
||||
engines: {node: '>=12.22.0'}
|
||||
@@ -636,6 +649,10 @@ packages:
|
||||
resolution: {integrity: sha512-GGP3O9QFD24uGeAXYUjwSTXARoqpZykHadOmA8G5vfJPK0/DC67qa//0qvqrJzL1xc8WQWX7/yc7fwudjPHPhA==}
|
||||
engines: {node: '>=14.0.0'}
|
||||
|
||||
'@smithy/node-http-handler@4.7.3':
|
||||
resolution: {integrity: sha512-/jPhevcTFPMVl6KNjbaI47iOg1zxC7IsnX4PQDGVZKMFceOXtB8IEYaB7a9VvkP/3oC60WzTeKocvSI7vLT0vA==}
|
||||
engines: {node: '>=18.0.0'}
|
||||
|
||||
'@smithy/node-http-handler@4.7.4':
|
||||
resolution: {integrity: sha512-HIeF+1vrDGzPkkv39Hj2vlHSXHY3p958jd/8ZnePIY6+ZOsQX8coyEUKO5yQu4r0bQIVsbpotVIrXXwyycMStQ==}
|
||||
engines: {node: '>=18.0.0'}
|
||||
@@ -644,10 +661,6 @@ packages:
|
||||
resolution: {integrity: sha512-e5UtkMvsatzBfbeBZjEOt0k0Z3BEsjTFL/n6fdO5vtBLe67tdy0dX7xw2DU7uZ3acwoHyeCqpU2Fzb7pxwHb6Q==}
|
||||
engines: {node: '>=18.0.0'}
|
||||
|
||||
'@smithy/types@4.14.1':
|
||||
resolution: {integrity: sha512-59b5HtSVrVR/eYNei3BUj3DCPKD/G7EtDDe7OEJE7i7FtQFugYo6MxbotS8mVJkLNVf8gYaAlEBwwtJ9HzhWSg==}
|
||||
engines: {node: '>=18.0.0'}
|
||||
|
||||
'@smithy/types@4.14.2':
|
||||
resolution: {integrity: sha512-P+otAxbV4CqBybp7EkcJCrig63yE2E7PuNVOmilVMRcx/O+QDzGULTrKsq4DV13gSfak9ObPrWaHl/9bL5YcWw==}
|
||||
engines: {node: '>=18.0.0'}
|
||||
@@ -1182,10 +1195,6 @@ packages:
|
||||
resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==}
|
||||
engines: {node: 6.* || 8.* || >= 10.*}
|
||||
|
||||
get-east-asian-width@1.5.0:
|
||||
resolution: {integrity: sha512-CQ+bEO+Tva/qlmw24dCejulK5pMzVnUOFOijVogd3KQs07HnRIgp8TGipvCCRT06xeYEbpbgwaCxglFyiuIcmA==}
|
||||
engines: {node: '>=18'}
|
||||
|
||||
get-east-asian-width@1.6.0:
|
||||
resolution: {integrity: sha512-QRbvDIbx6YklUe6RxeTeleMR0yv3cYH6PsPZHcnVn7xv7zO1BHN8r0XETu8n6Ye3Q+ahtSarc3WgtNWmehIBfA==}
|
||||
engines: {node: '>=18'}
|
||||
@@ -1487,9 +1496,6 @@ packages:
|
||||
jws@4.0.1:
|
||||
resolution: {integrity: sha512-EKI/M/yqPncGUUh44xz0PxSidXFr/+r0pA70+gIYhjv+et7yxM+s29Y+VGDkovRofQem0fs7Uvf4+YmAdyRduA==}
|
||||
|
||||
koffi@2.16.2:
|
||||
resolution: {integrity: sha512-owU0MRwv6xkrVqCd+33uw6BaYppkTRXbO/rVdJNI2dvZG0gzyRhYwW25eWtc5pauwK8TGh3AbkFONSezdykfSA==}
|
||||
|
||||
lefthook-darwin-arm64@2.1.6:
|
||||
resolution: {integrity: sha512-hyB7eeiX78BS66f70byTJacDLC/xV1vgMv9n+idFUsrM7J3Udd/ag9Ag5NP3t0eN0EqQqAtrNnt35EH01lxnRQ==}
|
||||
cpu: [arm64]
|
||||
@@ -1640,6 +1646,11 @@ packages:
|
||||
engines: {node: '>= 18'}
|
||||
hasBin: true
|
||||
|
||||
marked@18.0.5:
|
||||
resolution: {integrity: sha512-S6GcvALHg6K4ohtu4E7x0a1AqhAjp6cV8KhLSyN9qVapnzJkusVBxZRcIU9AeYsbe6P1hKDusSbEOzGyyuce6w==}
|
||||
engines: {node: '>= 20'}
|
||||
hasBin: true
|
||||
|
||||
meow@12.1.1:
|
||||
resolution: {integrity: sha512-BhXM0Au22RwUneMPwSCnyhTOizdWoIEPU9sp0Aqa1PnDMR5Wv2FGXYDjuzJEIX+Eo2Rb8xuYe5jrnm5QowQFkw==}
|
||||
engines: {node: '>=16.10'}
|
||||
@@ -2107,6 +2118,11 @@ packages:
|
||||
engines: {node: '>=10'}
|
||||
hasBin: true
|
||||
|
||||
semver@7.8.0:
|
||||
resolution: {integrity: sha512-AcM7dV/5ul4EekoQ29Agm5vri8JNqRyj39o0qpX6vDF2GZrtutZl5RwgD1XnZjiTAfncsJhMI48QQH3sN87YNA==}
|
||||
engines: {node: '>=10'}
|
||||
hasBin: true
|
||||
|
||||
shebang-command@2.0.0:
|
||||
resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==}
|
||||
engines: {node: '>=8'}
|
||||
@@ -2350,8 +2366,8 @@ packages:
|
||||
resolution: {integrity: sha512-xXnp4kTyor2Zq+J1FfPI6Eq3ew5h6Vl0F/8d9XU5zZQf1tX9s2Su1/3PiMmUANFULpmksxkClamIZcaUqryHsQ==}
|
||||
engines: {node: '>=20.18.1'}
|
||||
|
||||
undici@8.3.0:
|
||||
resolution: {integrity: sha512-TkUDgb6tl7KOGZ+7e8E3d2FYgUQgF6z5YypqjWmixVQSQERFcVrVg0ySADm2LVLRh5ljAaHTCR5Fmz3Q34rB7Q==}
|
||||
undici@8.5.0:
|
||||
resolution: {integrity: sha512-xamtWoB1EshgjpmlXd7GGm2VfdDtw1+rD8uhry8pSNW3If6S8E0m2T2+orSKeZXEn/aPJMviCpDBA65WJt8zhg==}
|
||||
engines: {node: '>=22.19.0'}
|
||||
|
||||
unicode-emoji-modifier-base@1.0.0:
|
||||
@@ -2572,7 +2588,7 @@ snapshots:
|
||||
'@smithy/core': 3.24.4
|
||||
'@smithy/fetch-http-handler': 5.4.4
|
||||
'@smithy/node-http-handler': 4.7.4
|
||||
'@smithy/types': 4.14.1
|
||||
'@smithy/types': 4.14.2
|
||||
tslib: 2.8.1
|
||||
|
||||
'@aws-sdk/core@3.974.13':
|
||||
@@ -2721,7 +2737,7 @@ snapshots:
|
||||
'@aws-sdk/nested-clients': 3.997.11
|
||||
'@aws-sdk/types': 3.973.9
|
||||
'@smithy/core': 3.24.4
|
||||
'@smithy/types': 4.14.1
|
||||
'@smithy/types': 4.14.2
|
||||
tslib: 2.8.1
|
||||
|
||||
'@aws-sdk/token-providers@3.1052.0':
|
||||
@@ -2962,9 +2978,9 @@ snapshots:
|
||||
picocolors: 1.1.1
|
||||
optional: true
|
||||
|
||||
'@earendil-works/pi-agent-core@0.75.4(ws@8.20.0)(zod@4.3.6)':
|
||||
'@earendil-works/pi-agent-core@0.79.9(ws@8.20.0)(zod@4.3.6)':
|
||||
dependencies:
|
||||
'@earendil-works/pi-ai': 0.75.4(ws@8.20.0)(zod@4.3.6)
|
||||
'@earendil-works/pi-ai': 0.79.9(ws@8.20.0)(zod@4.3.6)
|
||||
ignore: 7.0.5
|
||||
typebox: 1.1.38
|
||||
yaml: 2.9.0
|
||||
@@ -2976,12 +2992,14 @@ snapshots:
|
||||
- ws
|
||||
- zod
|
||||
|
||||
'@earendil-works/pi-ai@0.75.4(ws@8.20.0)(zod@4.3.6)':
|
||||
'@earendil-works/pi-ai@0.79.9(ws@8.20.0)(zod@4.3.6)':
|
||||
dependencies:
|
||||
'@anthropic-ai/sdk': 0.91.1(zod@4.3.6)
|
||||
'@aws-sdk/client-bedrock-runtime': 3.1048.0
|
||||
'@google/genai': 1.52.0
|
||||
'@mistralai/mistralai': 2.2.1
|
||||
'@mistralai/mistralai': 2.2.6(@opentelemetry/api@1.9.0)
|
||||
'@opentelemetry/api': 1.9.0
|
||||
'@smithy/node-http-handler': 4.7.3
|
||||
http-proxy-agent: 7.0.2
|
||||
https-proxy-agent: 7.0.6
|
||||
openai: 6.26.0(ws@8.20.0)(zod@4.3.6)
|
||||
@@ -2995,11 +3013,11 @@ snapshots:
|
||||
- ws
|
||||
- zod
|
||||
|
||||
'@earendil-works/pi-coding-agent@0.75.4(ws@8.20.0)(zod@4.3.6)':
|
||||
'@earendil-works/pi-coding-agent@0.79.9(ws@8.20.0)(zod@4.3.6)':
|
||||
dependencies:
|
||||
'@earendil-works/pi-agent-core': 0.75.4(ws@8.20.0)(zod@4.3.6)
|
||||
'@earendil-works/pi-ai': 0.75.4(ws@8.20.0)(zod@4.3.6)
|
||||
'@earendil-works/pi-tui': 0.75.4
|
||||
'@earendil-works/pi-agent-core': 0.79.9(ws@8.20.0)(zod@4.3.6)
|
||||
'@earendil-works/pi-ai': 0.79.9(ws@8.20.0)(zod@4.3.6)
|
||||
'@earendil-works/pi-tui': 0.79.9
|
||||
'@silvia-odwyer/photon-node': 0.3.4
|
||||
chalk: 5.6.2
|
||||
cross-spawn: 7.0.6
|
||||
@@ -3011,11 +3029,12 @@ snapshots:
|
||||
jiti: 2.7.0
|
||||
minimatch: 10.2.5
|
||||
proper-lockfile: 4.1.2
|
||||
semver: 7.8.0
|
||||
typebox: 1.1.38
|
||||
undici: 8.3.0
|
||||
undici: 8.5.0
|
||||
yaml: 2.9.0
|
||||
optionalDependencies:
|
||||
'@mariozechner/clipboard': 0.3.6
|
||||
'@mariozechner/clipboard': 0.3.9
|
||||
transitivePeerDependencies:
|
||||
- '@modelcontextprotocol/sdk'
|
||||
- bufferutil
|
||||
@@ -3024,12 +3043,10 @@ snapshots:
|
||||
- ws
|
||||
- zod
|
||||
|
||||
'@earendil-works/pi-tui@0.75.4':
|
||||
'@earendil-works/pi-tui@0.79.9':
|
||||
dependencies:
|
||||
get-east-asian-width: 1.6.0
|
||||
marked: 15.0.12
|
||||
optionalDependencies:
|
||||
koffi: 2.16.2
|
||||
marked: 18.0.5
|
||||
|
||||
'@google/genai@1.52.0':
|
||||
dependencies:
|
||||
@@ -3042,55 +3059,58 @@ snapshots:
|
||||
- supports-color
|
||||
- utf-8-validate
|
||||
|
||||
'@mariozechner/clipboard-darwin-arm64@0.3.6':
|
||||
'@mariozechner/clipboard-darwin-arm64@0.3.9':
|
||||
optional: true
|
||||
|
||||
'@mariozechner/clipboard-darwin-universal@0.3.6':
|
||||
'@mariozechner/clipboard-darwin-universal@0.3.9':
|
||||
optional: true
|
||||
|
||||
'@mariozechner/clipboard-darwin-x64@0.3.6':
|
||||
'@mariozechner/clipboard-darwin-x64@0.3.9':
|
||||
optional: true
|
||||
|
||||
'@mariozechner/clipboard-linux-arm64-gnu@0.3.6':
|
||||
'@mariozechner/clipboard-linux-arm64-gnu@0.3.9':
|
||||
optional: true
|
||||
|
||||
'@mariozechner/clipboard-linux-arm64-musl@0.3.6':
|
||||
'@mariozechner/clipboard-linux-arm64-musl@0.3.9':
|
||||
optional: true
|
||||
|
||||
'@mariozechner/clipboard-linux-riscv64-gnu@0.3.6':
|
||||
'@mariozechner/clipboard-linux-riscv64-gnu@0.3.9':
|
||||
optional: true
|
||||
|
||||
'@mariozechner/clipboard-linux-x64-gnu@0.3.6':
|
||||
'@mariozechner/clipboard-linux-x64-gnu@0.3.9':
|
||||
optional: true
|
||||
|
||||
'@mariozechner/clipboard-linux-x64-musl@0.3.6':
|
||||
'@mariozechner/clipboard-linux-x64-musl@0.3.9':
|
||||
optional: true
|
||||
|
||||
'@mariozechner/clipboard-win32-arm64-msvc@0.3.6':
|
||||
'@mariozechner/clipboard-win32-arm64-msvc@0.3.9':
|
||||
optional: true
|
||||
|
||||
'@mariozechner/clipboard-win32-x64-msvc@0.3.6':
|
||||
'@mariozechner/clipboard-win32-x64-msvc@0.3.9':
|
||||
optional: true
|
||||
|
||||
'@mariozechner/clipboard@0.3.6':
|
||||
'@mariozechner/clipboard@0.3.9':
|
||||
optionalDependencies:
|
||||
'@mariozechner/clipboard-darwin-arm64': 0.3.6
|
||||
'@mariozechner/clipboard-darwin-universal': 0.3.6
|
||||
'@mariozechner/clipboard-darwin-x64': 0.3.6
|
||||
'@mariozechner/clipboard-linux-arm64-gnu': 0.3.6
|
||||
'@mariozechner/clipboard-linux-arm64-musl': 0.3.6
|
||||
'@mariozechner/clipboard-linux-riscv64-gnu': 0.3.6
|
||||
'@mariozechner/clipboard-linux-x64-gnu': 0.3.6
|
||||
'@mariozechner/clipboard-linux-x64-musl': 0.3.6
|
||||
'@mariozechner/clipboard-win32-arm64-msvc': 0.3.6
|
||||
'@mariozechner/clipboard-win32-x64-msvc': 0.3.6
|
||||
'@mariozechner/clipboard-darwin-arm64': 0.3.9
|
||||
'@mariozechner/clipboard-darwin-universal': 0.3.9
|
||||
'@mariozechner/clipboard-darwin-x64': 0.3.9
|
||||
'@mariozechner/clipboard-linux-arm64-gnu': 0.3.9
|
||||
'@mariozechner/clipboard-linux-arm64-musl': 0.3.9
|
||||
'@mariozechner/clipboard-linux-riscv64-gnu': 0.3.9
|
||||
'@mariozechner/clipboard-linux-x64-gnu': 0.3.9
|
||||
'@mariozechner/clipboard-linux-x64-musl': 0.3.9
|
||||
'@mariozechner/clipboard-win32-arm64-msvc': 0.3.9
|
||||
'@mariozechner/clipboard-win32-x64-msvc': 0.3.9
|
||||
optional: true
|
||||
|
||||
'@mistralai/mistralai@2.2.1':
|
||||
'@mistralai/mistralai@2.2.6(@opentelemetry/api@1.9.0)':
|
||||
dependencies:
|
||||
'@opentelemetry/semantic-conventions': 1.41.1
|
||||
ws: 8.20.0
|
||||
zod: 4.3.6
|
||||
zod-to-json-schema: 3.25.2(zod@4.3.6)
|
||||
optionalDependencies:
|
||||
'@opentelemetry/api': 1.9.0
|
||||
transitivePeerDependencies:
|
||||
- bufferutil
|
||||
- utf-8-validate
|
||||
@@ -3157,6 +3177,10 @@ snapshots:
|
||||
dependencies:
|
||||
'@octokit/openapi-types': 27.0.0
|
||||
|
||||
'@opentelemetry/api@1.9.0': {}
|
||||
|
||||
'@opentelemetry/semantic-conventions@1.41.1': {}
|
||||
|
||||
'@pnpm/config.env-replace@1.1.0': {}
|
||||
|
||||
'@pnpm/network.ca-file@1.0.2':
|
||||
@@ -3322,6 +3346,12 @@ snapshots:
|
||||
dependencies:
|
||||
tslib: 2.8.1
|
||||
|
||||
'@smithy/node-http-handler@4.7.3':
|
||||
dependencies:
|
||||
'@smithy/core': 3.24.4
|
||||
'@smithy/types': 4.14.2
|
||||
tslib: 2.8.1
|
||||
|
||||
'@smithy/node-http-handler@4.7.4':
|
||||
dependencies:
|
||||
'@smithy/core': 3.24.4
|
||||
@@ -3334,10 +3364,6 @@ snapshots:
|
||||
'@smithy/types': 4.14.2
|
||||
tslib: 2.8.1
|
||||
|
||||
'@smithy/types@4.14.1':
|
||||
dependencies:
|
||||
tslib: 2.8.1
|
||||
|
||||
'@smithy/types@4.14.2':
|
||||
dependencies:
|
||||
tslib: 2.8.1
|
||||
@@ -3902,8 +3928,6 @@ snapshots:
|
||||
|
||||
get-caller-file@2.0.5: {}
|
||||
|
||||
get-east-asian-width@1.5.0: {}
|
||||
|
||||
get-east-asian-width@1.6.0: {}
|
||||
|
||||
get-stream@6.0.1: {}
|
||||
@@ -4195,9 +4219,6 @@ snapshots:
|
||||
jwa: 2.0.1
|
||||
safe-buffer: 5.2.1
|
||||
|
||||
koffi@2.16.2:
|
||||
optional: true
|
||||
|
||||
lefthook-darwin-arm64@2.1.6:
|
||||
optional: true
|
||||
|
||||
@@ -4323,6 +4344,8 @@ snapshots:
|
||||
|
||||
marked@15.0.12: {}
|
||||
|
||||
marked@18.0.5: {}
|
||||
|
||||
meow@12.1.1: {}
|
||||
|
||||
meow@13.2.0: {}
|
||||
@@ -4393,7 +4416,7 @@ snapshots:
|
||||
|
||||
normalize-package-data@8.0.0:
|
||||
dependencies:
|
||||
hosted-git-info: 9.0.2
|
||||
hosted-git-info: 9.0.3
|
||||
semver: 7.7.4
|
||||
validate-npm-package-license: 3.0.4
|
||||
|
||||
@@ -4722,6 +4745,8 @@ snapshots:
|
||||
|
||||
semver@7.7.4: {}
|
||||
|
||||
semver@7.8.0: {}
|
||||
|
||||
shebang-command@2.0.0:
|
||||
dependencies:
|
||||
shebang-regex: 3.0.0
|
||||
@@ -4782,7 +4807,7 @@ snapshots:
|
||||
string-width@7.2.0:
|
||||
dependencies:
|
||||
emoji-regex: 10.6.0
|
||||
get-east-asian-width: 1.5.0
|
||||
get-east-asian-width: 1.6.0
|
||||
strip-ansi: 7.2.0
|
||||
|
||||
string_decoder@1.1.1:
|
||||
@@ -4928,7 +4953,7 @@ snapshots:
|
||||
|
||||
undici@7.25.0: {}
|
||||
|
||||
undici@8.3.0: {}
|
||||
undici@8.5.0: {}
|
||||
|
||||
unicode-emoji-modifier-base@1.0.0: {}
|
||||
|
||||
|
||||
@@ -79,8 +79,8 @@ async function runAnswerCommand(
|
||||
ctx: ExtensionCommandContext,
|
||||
remoteAsk?: RemoteAskRuntime
|
||||
): Promise<void> {
|
||||
if (!ctx.hasUI) {
|
||||
ctx.ui.notify("/answer requires interactive UI.", "error");
|
||||
if (ctx.mode !== "tui") {
|
||||
ctx.ui.notify("/answer requires interactive TUI mode.", "error");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -253,8 +253,8 @@ async function runReplayCommand(
|
||||
source: AskPayloadSource;
|
||||
}
|
||||
): Promise<void> {
|
||||
if (!ctx.hasUI) {
|
||||
ctx.ui.notify("Ask replay requires interactive UI.", "error");
|
||||
if (ctx.mode !== "tui") {
|
||||
ctx.ui.notify("Ask replay requires interactive TUI mode.", "error");
|
||||
return;
|
||||
}
|
||||
const lookup = findLatestPayloadInCurrentBranch(ctx, options.source);
|
||||
|
||||
@@ -8,7 +8,7 @@ export function registerAskSettingsCommand(pi: ExtensionAPI) {
|
||||
pi.registerCommand("ask-settings", {
|
||||
description: "Open ask settings",
|
||||
handler: async (_args: string, ctx: ExtensionCommandContext) => {
|
||||
await showAskSettings(ctx.ui);
|
||||
await showAskSettings(ctx);
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
@@ -153,8 +153,8 @@ function formatNonInteractiveMessage(
|
||||
state: ReturnType<typeof createInitialState>
|
||||
): string {
|
||||
const lines = [
|
||||
"Needs user input: ask_user requires interactive UI.",
|
||||
"Run same tool call in interactive session, or ask user these questions manually:",
|
||||
"Needs user input: ask_user requires interactive TUI mode.",
|
||||
"Run same tool call in interactive TUI mode, or ask user these questions manually:",
|
||||
];
|
||||
|
||||
for (const [index, question] of state.questions.entries()) {
|
||||
|
||||
+1
-1
@@ -67,7 +67,7 @@ async function executeAskTool(
|
||||
source: "tool",
|
||||
sourceEntryId: toolCallId,
|
||||
});
|
||||
if (!ctx.hasUI) {
|
||||
if (ctx.mode !== "tui") {
|
||||
return nonInteractiveResponse(validation.state);
|
||||
}
|
||||
ctx.ui.setWorkingVisible(false);
|
||||
|
||||
@@ -171,6 +171,10 @@ export function getAskConfigStore(): AskConfigStore {
|
||||
return askConfigStore;
|
||||
}
|
||||
|
||||
export function resetAskConfigStore(): void {
|
||||
askConfigStore = undefined;
|
||||
}
|
||||
|
||||
export function getAskConfigPath(): string {
|
||||
return join(getAgentDir(), "extensions", "eko24ive-pi-ask.json");
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
|
||||
import { registerAnswerCommands } from "./answer-commands.ts";
|
||||
import { registerAskSettingsCommand } from "./ask-settings-command.ts";
|
||||
import { registerAskTool } from "./ask-tool.ts";
|
||||
import { resetAskConfigStore } from "./config/store.ts";
|
||||
import { createRemoteAskRuntime } from "./remote-ask.ts";
|
||||
|
||||
const PACKAGE_ROOT = resolve(dirname(fileURLToPath(import.meta.url)), "..");
|
||||
@@ -15,10 +16,14 @@ const CONFIGURATION_DOC_PATH = resolve(
|
||||
const PI_ASK_CONFIG_PROMPT = `When the user asks to configure, customize, debug, or explain @eko24ive/pi-ask settings or keymaps, first read ${CONFIGURATION_DOC_PATH} and follow it as the source of truth before editing config files.`;
|
||||
|
||||
export default function askExtension(pi: ExtensionAPI) {
|
||||
resetAskConfigStore();
|
||||
pi.on("before_agent_start", async (event) => ({
|
||||
systemPrompt: `${event.systemPrompt}\n\n${PI_ASK_CONFIG_PROMPT}`,
|
||||
}));
|
||||
const remoteAsk = createRemoteAskRuntime(pi.events);
|
||||
pi.on("session_shutdown", () => {
|
||||
remoteAsk.disposeAll();
|
||||
});
|
||||
registerAskTool(pi, remoteAsk);
|
||||
registerAskSettingsCommand(pi);
|
||||
registerAnswerCommands(pi, remoteAsk);
|
||||
|
||||
+6
-2
@@ -95,6 +95,7 @@ export interface RemoteAskFlowHandle {
|
||||
}
|
||||
|
||||
export interface RemoteAskRuntime {
|
||||
disposeAll: () => void;
|
||||
startFlow: (flow: RemoteAskFlowInput) => RemoteAskFlowHandle;
|
||||
}
|
||||
|
||||
@@ -102,12 +103,15 @@ type EventBus = ExtensionAPI["events"];
|
||||
|
||||
export function createRemoteAskRuntime(events: EventBus): RemoteAskRuntime {
|
||||
const activeFlows = new Map<string, ActiveRemoteAskFlow>();
|
||||
|
||||
events.on(PI_ASK_SUBMIT_EVENT, (data) => {
|
||||
const unsubscribeSubmit = events.on(PI_ASK_SUBMIT_EVENT, (data) => {
|
||||
handleSubmitEvent(events, activeFlows, data);
|
||||
});
|
||||
|
||||
return {
|
||||
disposeAll() {
|
||||
activeFlows.clear();
|
||||
unsubscribeSubmit();
|
||||
},
|
||||
startFlow(flow) {
|
||||
return startRemoteAskFlow(events, activeFlows, flow);
|
||||
},
|
||||
|
||||
@@ -13,10 +13,13 @@ const FD_BINARY_NAMES =
|
||||
* themselves when reusing CombinedAutocompleteProvider for `@` file mentions.
|
||||
*/
|
||||
export function createAskAutocompleteProvider(cwd: string) {
|
||||
return new CombinedAutocompleteProvider(
|
||||
[],
|
||||
cwd,
|
||||
findAutocompleteBinary(FD_BINARY_NAMES)
|
||||
return Object.assign(
|
||||
new CombinedAutocompleteProvider(
|
||||
[],
|
||||
cwd,
|
||||
findAutocompleteBinary(FD_BINARY_NAMES)
|
||||
),
|
||||
{ triggerCharacters: ["@"] }
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
+14
-2
@@ -113,6 +113,12 @@ export async function runAskFlow(
|
||||
presentSingleAsMulti:
|
||||
options.presentSingleAsMulti ?? config.behaviour.presentSingleAsMulti,
|
||||
};
|
||||
if (ctx.mode !== "tui") {
|
||||
return {
|
||||
...toAskResult(createInitialState(params, flowOptions)),
|
||||
cancelled: true,
|
||||
};
|
||||
}
|
||||
return ctx.ui.custom<AskResult>((...args) =>
|
||||
createAskFlowController(args, {
|
||||
...params,
|
||||
@@ -172,9 +178,15 @@ function createAskFlowController(
|
||||
});
|
||||
|
||||
return {
|
||||
get focused() {
|
||||
return controller.editor.focused;
|
||||
},
|
||||
set focused(value: boolean) {
|
||||
controller.editor.focused = value;
|
||||
},
|
||||
render: (width: number) => renderController(controller, width),
|
||||
invalidate() {
|
||||
// The editor manages its own async autocomplete redraws.
|
||||
controller.editor.invalidate();
|
||||
},
|
||||
handleInput(data: string) {
|
||||
handleControllerInput(controller, data);
|
||||
@@ -536,7 +548,7 @@ function showSettingsModal(controller: AskFlowController) {
|
||||
return;
|
||||
}
|
||||
controller.settingsOpen = true;
|
||||
showAskSettings(controller.ctx.ui).finally(() => {
|
||||
showAskSettings(controller.ctx).finally(() => {
|
||||
controller.settingsOpen = false;
|
||||
refresh(controller);
|
||||
});
|
||||
|
||||
@@ -3,11 +3,15 @@ import { getAskConfigPath, getAskConfigStore } from "../config/store.ts";
|
||||
import { AskSettingsList } from "./settings-list.ts";
|
||||
|
||||
export async function showAskSettings(
|
||||
ui: Pick<ExtensionContext, "ui">["ui"]
|
||||
ctx: Pick<ExtensionContext, "mode" | "ui">
|
||||
): Promise<void> {
|
||||
if (ctx.mode !== "tui") {
|
||||
ctx.ui.notify("/ask-settings requires interactive TUI mode.", "error");
|
||||
return;
|
||||
}
|
||||
const store = getAskConfigStore();
|
||||
const { config, notice } = await store.ensureLoaded();
|
||||
return ui.custom<void>(
|
||||
return ctx.ui.custom<void>(
|
||||
(tui, theme, _keybindings, done) =>
|
||||
new AskSettingsList(theme, {
|
||||
configPath: getAskConfigPath(),
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
import assert from "node:assert/strict";
|
||||
import test from "node:test";
|
||||
import { registerAnswerCommands } from "../src/answer-commands.ts";
|
||||
|
||||
function registerCommands() {
|
||||
const commands = new Map<
|
||||
string,
|
||||
{ handler: (args: string, ctx: any) => Promise<void> }
|
||||
>();
|
||||
registerAnswerCommands({
|
||||
registerCommand(
|
||||
name: string,
|
||||
command: { handler: (args: string, ctx: any) => Promise<void> }
|
||||
) {
|
||||
commands.set(name, command);
|
||||
},
|
||||
} as never);
|
||||
return commands;
|
||||
}
|
||||
|
||||
test("answer commands do not open custom UI outside TUI mode", async () => {
|
||||
const commands = registerCommands();
|
||||
const notifications: Array<{ message: string; type: string }> = [];
|
||||
let customOpened = false;
|
||||
const ctx = {
|
||||
mode: "rpc",
|
||||
ui: {
|
||||
custom() {
|
||||
customOpened = true;
|
||||
},
|
||||
notify(message: string, type: string) {
|
||||
notifications.push({ message, type });
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
await commands.get("answer")?.handler("", ctx);
|
||||
await commands.get("answer:again")?.handler("", ctx);
|
||||
await commands.get("ask:replay")?.handler("", ctx);
|
||||
|
||||
assert.equal(customOpened, false);
|
||||
assert.deepEqual(notifications, [
|
||||
{ message: "/answer requires interactive TUI mode.", type: "error" },
|
||||
{ message: "Ask replay requires interactive TUI mode.", type: "error" },
|
||||
{ message: "Ask replay requires interactive TUI mode.", type: "error" },
|
||||
]);
|
||||
});
|
||||
@@ -37,6 +37,7 @@ test("registers /ask-settings and opens the shared settings overlay", async () =
|
||||
|
||||
const customCalls: Array<{ options: unknown; lines: string[] }> = [];
|
||||
await commands.get("ask-settings")?.handler("", {
|
||||
mode: "tui",
|
||||
ui: {
|
||||
custom(callback: any, options: unknown) {
|
||||
const done = () => {
|
||||
@@ -75,3 +76,40 @@ test("registers /ask-settings and opens the shared settings overlay", async () =
|
||||
delete process.env.PI_CODING_AGENT_DIR;
|
||||
await rm(agentDir, { force: true, recursive: true });
|
||||
});
|
||||
|
||||
test("/ask-settings notifies outside TUI instead of opening custom UI", async () => {
|
||||
const commands = new Map<
|
||||
string,
|
||||
{ handler: (args: string, ctx: any) => Promise<void> }
|
||||
>();
|
||||
registerAskSettingsCommand({
|
||||
registerCommand(
|
||||
name: string,
|
||||
command: { handler: (args: string, ctx: any) => Promise<void> }
|
||||
) {
|
||||
commands.set(name, command);
|
||||
},
|
||||
} as never);
|
||||
|
||||
const notifications: Array<{ message: string; type: string }> = [];
|
||||
let customOpened = false;
|
||||
await commands.get("ask-settings")?.handler("", {
|
||||
mode: "rpc",
|
||||
ui: {
|
||||
custom() {
|
||||
customOpened = true;
|
||||
},
|
||||
notify(message: string, type: string) {
|
||||
notifications.push({ message, type });
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
assert.equal(customOpened, false);
|
||||
assert.deepEqual(notifications, [
|
||||
{
|
||||
message: "/ask-settings requires interactive TUI mode.",
|
||||
type: "error",
|
||||
},
|
||||
]);
|
||||
});
|
||||
|
||||
+22
-3
@@ -4,7 +4,7 @@ import { registerAskTool } from "../src/ask-tool.ts";
|
||||
import type { AskParams } from "../src/types.ts";
|
||||
|
||||
const NON_INTERACTIVE_MESSAGE_RE =
|
||||
/Needs user input: ask_user requires interactive UI\./;
|
||||
/Needs user input: ask_user requires interactive TUI mode\./;
|
||||
const FIRST_QUESTION_RE = /1\. Goal: What should I optimize for\?/;
|
||||
const SPEED_OPTION_RE = /- Speed \[speed\]/;
|
||||
const CUSTOM_OPTION_RE = /- Type your own \[custom\]/;
|
||||
@@ -47,8 +47,8 @@ function registerMockTool() {
|
||||
};
|
||||
}
|
||||
|
||||
function makeCtx(hasUi: boolean): unknown {
|
||||
return { [HAS_UI]: hasUi };
|
||||
function makeCtx(hasUi: boolean, mode = hasUi ? "tui" : "print"): unknown {
|
||||
return { [HAS_UI]: hasUi, mode };
|
||||
}
|
||||
|
||||
function sampleParams(): AskParams {
|
||||
@@ -113,6 +113,25 @@ test("ask tool returns pending questions in non-interactive mode", async () => {
|
||||
assert.match(result.content[0].text, CUSTOM_OPTION_RE);
|
||||
});
|
||||
|
||||
test("ask tool does not open custom UI outside TUI mode", async () => {
|
||||
const { tool } = registerMockTool();
|
||||
let customOpened = false;
|
||||
|
||||
const result = await tool.execute("call-1", sampleParams(), undefined, noop, {
|
||||
[HAS_UI]: true,
|
||||
mode: "rpc",
|
||||
ui: {
|
||||
custom() {
|
||||
customOpened = true;
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
assert.equal(customOpened, false);
|
||||
assert.equal(result.details.cancelled, true);
|
||||
assert.match(result.content[0].text, NON_INTERACTIVE_MESSAGE_RE);
|
||||
});
|
||||
|
||||
test("ask tool includes custom answer fallback for preview questions", async () => {
|
||||
const { tool } = registerMockTool();
|
||||
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
import assert from "node:assert/strict";
|
||||
import test from "node:test";
|
||||
import { createAskAutocompleteProvider } from "../src/ui/autocomplete.ts";
|
||||
|
||||
test("ask autocomplete explicitly triggers on file mention marker", () => {
|
||||
const provider = createAskAutocompleteProvider(process.cwd());
|
||||
|
||||
assert.deepEqual(provider.triggerCharacters, ["@"]);
|
||||
});
|
||||
@@ -5,7 +5,11 @@ import { dirname, join } from "node:path";
|
||||
import test from "node:test";
|
||||
import { DEFAULT_ASK_CONFIG } from "../src/config/defaults.ts";
|
||||
import type { AskConfig } from "../src/config/schema.ts";
|
||||
import { AskConfigStore } from "../src/config/store.ts";
|
||||
import {
|
||||
AskConfigStore,
|
||||
getAskConfigStore,
|
||||
resetAskConfigStore,
|
||||
} from "../src/config/store.ts";
|
||||
|
||||
const DEFAULT_KEYMAPS_NOTICE_PATTERN =
|
||||
/Using default ask keymaps for this session/;
|
||||
@@ -31,6 +35,38 @@ async function makeTempPath(name: string): Promise<string> {
|
||||
return join(root, "eko24ive-pi-ask.json");
|
||||
}
|
||||
|
||||
test("resetAskConfigStore reloads the global store from disk", async () => {
|
||||
const root = await import("node:fs/promises").then(({ mkdtemp }) =>
|
||||
mkdtemp(join(tmpdir(), "pi-ask-config-reset-"))
|
||||
);
|
||||
const path = join(root, "extensions", "eko24ive-pi-ask.json");
|
||||
await mkdir(dirname(path), { recursive: true });
|
||||
await writeFile(
|
||||
path,
|
||||
JSON.stringify({
|
||||
...expectedConfigFile(),
|
||||
behaviour: {
|
||||
...DEFAULT_ASK_CONFIG.behaviour,
|
||||
autoSubmitWhenAnsweredWithoutNotes: true,
|
||||
},
|
||||
})
|
||||
);
|
||||
process.env.PI_CODING_AGENT_DIR = root;
|
||||
resetAskConfigStore();
|
||||
getAskConfigStore().setConfig(DEFAULT_ASK_CONFIG);
|
||||
|
||||
resetAskConfigStore();
|
||||
const result = await getAskConfigStore().ensureLoaded();
|
||||
|
||||
assert.equal(
|
||||
result.config.behaviour.autoSubmitWhenAnsweredWithoutNotes,
|
||||
true
|
||||
);
|
||||
delete process.env.PI_CODING_AGENT_DIR;
|
||||
resetAskConfigStore();
|
||||
await rm(root, { force: true, recursive: true });
|
||||
});
|
||||
|
||||
test("config store writes defaults when file is missing", async () => {
|
||||
const path = await makeTempPath("pi-ask-config-missing-");
|
||||
const store = new AskConfigStore(path);
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import assert from "node:assert/strict";
|
||||
import test from "node:test";
|
||||
import { Editor } from "@earendil-works/pi-tui";
|
||||
import { DEFAULT_ASK_CONFIG } from "../src/config/defaults.ts";
|
||||
import { getAskConfigStore } from "../src/config/store.ts";
|
||||
import { createInitialState } from "../src/state/create.ts";
|
||||
@@ -279,6 +280,7 @@ test("custom editor submit key controls actual editor submission", async () => {
|
||||
const resultPromise = runAskFlow(
|
||||
{
|
||||
cwd: process.cwd(),
|
||||
mode: "tui",
|
||||
ui: {
|
||||
custom(callback: (...args: unknown[]) => unknown) {
|
||||
return new Promise((resolve) => {
|
||||
@@ -331,6 +333,78 @@ function plainTheme() {
|
||||
};
|
||||
}
|
||||
|
||||
test("ask flow forwards focus and invalidation to its editor", async () => {
|
||||
getAskConfigStore().setConfig({
|
||||
...DEFAULT_ASK_CONFIG,
|
||||
notifications: {
|
||||
...DEFAULT_ASK_CONFIG.notifications,
|
||||
enabled: false,
|
||||
},
|
||||
});
|
||||
const originalInvalidate = Editor.prototype.invalidate;
|
||||
let invalidateCalls = 0;
|
||||
Editor.prototype.invalidate = function patchedInvalidate(this: Editor) {
|
||||
invalidateCalls += 1;
|
||||
return originalInvalidate.call(this);
|
||||
};
|
||||
let component:
|
||||
| {
|
||||
focused: boolean;
|
||||
handleInput(data: string): void;
|
||||
invalidate(): void;
|
||||
}
|
||||
| undefined;
|
||||
|
||||
try {
|
||||
const resultPromise = runAskFlow(
|
||||
{
|
||||
cwd: process.cwd(),
|
||||
mode: "tui",
|
||||
ui: {
|
||||
custom(callback: (...args: unknown[]) => unknown) {
|
||||
return new Promise((resolve) => {
|
||||
component = callback(
|
||||
{
|
||||
requestRender() {
|
||||
// Rendering is not needed for this controller test.
|
||||
},
|
||||
},
|
||||
plainTheme(),
|
||||
{},
|
||||
resolve
|
||||
) as typeof component;
|
||||
});
|
||||
},
|
||||
},
|
||||
} as never,
|
||||
{
|
||||
questions: [
|
||||
{
|
||||
id: "q1",
|
||||
prompt: "Question?",
|
||||
options: [{ value: "a", label: "A" }],
|
||||
},
|
||||
],
|
||||
}
|
||||
);
|
||||
|
||||
await new Promise((resolve) => setImmediate(resolve));
|
||||
assert(component);
|
||||
component.focused = true;
|
||||
assert.equal(component.focused, true);
|
||||
component.focused = false;
|
||||
assert.equal(component.focused, false);
|
||||
component.invalidate();
|
||||
assert.equal(invalidateCalls, 1);
|
||||
component.handleInput("\x1b");
|
||||
const result = await resultPromise;
|
||||
assert.equal(result.cancelled, true);
|
||||
} finally {
|
||||
Editor.prototype.invalidate = originalInvalidate;
|
||||
getAskConfigStore().setConfig(DEFAULT_ASK_CONFIG);
|
||||
}
|
||||
});
|
||||
|
||||
test("custom configured note shortcuts are used at runtime", () => {
|
||||
const navigation = createInitialState({
|
||||
questions: [
|
||||
|
||||
@@ -172,6 +172,45 @@ test("started event questions are cloned", async () => {
|
||||
assert.equal(questions[0].options[0].label, "Yes");
|
||||
});
|
||||
|
||||
test("remote runtime disposes active flows and submit listener", () => {
|
||||
const bus = new TestEventBus();
|
||||
const remoteAsk = createRemoteAskRuntime(bus as never);
|
||||
let submitCalls = 0;
|
||||
const flow = remoteAsk.startFlow({
|
||||
source: "tool",
|
||||
questions: createInitialState({
|
||||
questions: [
|
||||
{
|
||||
id: "decision",
|
||||
prompt: "Proceed?",
|
||||
options: [{ value: "yes", label: "Yes" }],
|
||||
},
|
||||
],
|
||||
}).questions,
|
||||
onSubmit: () => {
|
||||
submitCalls += 1;
|
||||
return { ok: true };
|
||||
},
|
||||
});
|
||||
remoteAsk.disposeAll();
|
||||
|
||||
bus.emit(PI_ASK_SUBMIT_EVENT, {
|
||||
version: 1,
|
||||
requestId: "request-1",
|
||||
flowId: flow.flowId,
|
||||
response: {
|
||||
kind: "answer",
|
||||
answers: { decision: { values: ["yes"] } },
|
||||
},
|
||||
});
|
||||
|
||||
assert.equal(submitCalls, 0);
|
||||
assert.equal(
|
||||
bus.events.some((event) => event.channel === PI_ASK_SUBMIT_RESULT_EVENT),
|
||||
false
|
||||
);
|
||||
});
|
||||
|
||||
test("remote submit resolves an active ask flow and emits lifecycle events", async () => {
|
||||
getAskConfigStore().setConfig({
|
||||
...DEFAULT_ASK_CONFIG,
|
||||
@@ -197,6 +236,7 @@ test("remote submit resolves an active ask flow and emits lifecycle events", asy
|
||||
const result = await runAskFlow(
|
||||
{
|
||||
cwd: process.cwd(),
|
||||
mode: "tui",
|
||||
ui: {
|
||||
custom(callback: (...args: unknown[]) => unknown) {
|
||||
return new Promise((resolve) => {
|
||||
|
||||
Reference in New Issue
Block a user