@earendil-works/pi-coding-agent 0.77.0 → 0.78.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +63 -1
- package/README.md +10 -2
- package/dist/cli/args.d.ts +1 -0
- package/dist/cli/args.d.ts.map +1 -1
- package/dist/cli/args.js +15 -0
- package/dist/cli/args.js.map +1 -1
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +9 -1
- package/dist/config.js.map +1 -1
- package/dist/core/agent-session.d.ts +3 -1
- package/dist/core/agent-session.d.ts.map +1 -1
- package/dist/core/agent-session.js +7 -1
- package/dist/core/agent-session.js.map +1 -1
- package/dist/core/auth-storage.d.ts.map +1 -1
- package/dist/core/auth-storage.js +4 -3
- package/dist/core/auth-storage.js.map +1 -1
- package/dist/core/compaction/branch-summarization.d.ts +3 -1
- package/dist/core/compaction/branch-summarization.d.ts.map +1 -1
- package/dist/core/compaction/branch-summarization.js +9 -3
- package/dist/core/compaction/branch-summarization.js.map +1 -1
- package/dist/core/export-html/template.js +19 -6
- package/dist/core/extensions/index.d.ts +1 -1
- package/dist/core/extensions/index.d.ts.map +1 -1
- package/dist/core/extensions/index.js.map +1 -1
- package/dist/core/extensions/runner.d.ts +4 -2
- package/dist/core/extensions/runner.d.ts.map +1 -1
- package/dist/core/extensions/runner.js +13 -1
- package/dist/core/extensions/runner.js.map +1 -1
- package/dist/core/extensions/types.d.ts +7 -1
- package/dist/core/extensions/types.d.ts.map +1 -1
- package/dist/core/extensions/types.js.map +1 -1
- package/dist/core/footer-data-provider.d.ts +2 -0
- package/dist/core/footer-data-provider.d.ts.map +1 -1
- package/dist/core/footer-data-provider.js +29 -1
- package/dist/core/footer-data-provider.js.map +1 -1
- package/dist/core/model-resolver.d.ts.map +1 -1
- package/dist/core/model-resolver.js +3 -0
- package/dist/core/model-resolver.js.map +1 -1
- package/dist/core/package-manager.d.ts +2 -0
- package/dist/core/package-manager.d.ts.map +1 -1
- package/dist/core/package-manager.js +22 -6
- package/dist/core/package-manager.js.map +1 -1
- package/dist/core/provider-attribution.d.ts +4 -0
- package/dist/core/provider-attribution.d.ts.map +1 -0
- package/dist/core/provider-attribution.js +72 -0
- package/dist/core/provider-attribution.js.map +1 -0
- package/dist/core/provider-display-names.d.ts.map +1 -1
- package/dist/core/provider-display-names.js +3 -0
- package/dist/core/provider-display-names.js.map +1 -1
- package/dist/core/sdk.d.ts.map +1 -1
- package/dist/core/sdk.js +7 -33
- package/dist/core/sdk.js.map +1 -1
- package/dist/core/session-manager.d.ts.map +1 -1
- package/dist/core/session-manager.js +92 -68
- package/dist/core/session-manager.js.map +1 -1
- package/dist/core/tools/edit.d.ts.map +1 -1
- package/dist/core/tools/edit.js +7 -10
- package/dist/core/tools/edit.js.map +1 -1
- package/dist/core/tools/find.d.ts.map +1 -1
- package/dist/core/tools/find.js.map +1 -1
- package/dist/core/tools/grep.d.ts.map +1 -1
- package/dist/core/tools/grep.js.map +1 -1
- package/dist/core/tools/ls.d.ts.map +1 -1
- package/dist/core/tools/ls.js +5 -7
- package/dist/core/tools/ls.js.map +1 -1
- package/dist/core/tools/read.d.ts.map +1 -1
- package/dist/core/tools/read.js +6 -7
- package/dist/core/tools/read.js.map +1 -1
- package/dist/core/tools/render-utils.d.ts +5 -2
- package/dist/core/tools/render-utils.d.ts.map +1 -1
- package/dist/core/tools/render-utils.js +17 -1
- package/dist/core/tools/render-utils.js.map +1 -1
- package/dist/core/tools/write.d.ts.map +1 -1
- package/dist/core/tools/write.js +5 -6
- package/dist/core/tools/write.js.map +1 -1
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/dist/main.d.ts.map +1 -1
- package/dist/main.js +8 -0
- package/dist/main.js.map +1 -1
- package/dist/modes/interactive/components/login-dialog.d.ts +0 -1
- package/dist/modes/interactive/components/login-dialog.d.ts.map +1 -1
- package/dist/modes/interactive/components/login-dialog.js +3 -12
- package/dist/modes/interactive/components/login-dialog.js.map +1 -1
- package/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
- package/dist/modes/interactive/components/tool-execution.js +22 -0
- package/dist/modes/interactive/components/tool-execution.js.map +1 -1
- package/dist/modes/interactive/interactive-mode.d.ts +3 -0
- package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-mode.js +36 -0
- package/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/dist/modes/print-mode.d.ts.map +1 -1
- package/dist/modes/print-mode.js +1 -0
- package/dist/modes/print-mode.js.map +1 -1
- package/dist/modes/rpc/rpc-mode.d.ts.map +1 -1
- package/dist/modes/rpc/rpc-mode.js +1 -0
- package/dist/modes/rpc/rpc-mode.js.map +1 -1
- package/dist/utils/git.d.ts.map +1 -1
- package/dist/utils/git.js +54 -22
- package/dist/utils/git.js.map +1 -1
- package/dist/utils/open-browser.d.ts +9 -0
- package/dist/utils/open-browser.d.ts.map +1 -0
- package/dist/utils/open-browser.js +22 -0
- package/dist/utils/open-browser.js.map +1 -0
- package/docs/containerization.md +111 -0
- package/docs/docs.json +4 -0
- package/docs/extensions.md +36 -11
- package/docs/index.md +1 -0
- package/docs/providers.md +5 -0
- package/docs/quickstart.md +1 -0
- package/docs/rpc.md +3 -2
- package/docs/session-format.md +1 -1
- package/docs/sessions.md +8 -0
- package/docs/settings.md +1 -1
- package/docs/terminal-setup.md +2 -0
- package/docs/tui.md +12 -3
- package/docs/usage.md +6 -1
- package/examples/extensions/README.md +1 -0
- package/examples/extensions/custom-header.ts +1 -1
- package/examples/extensions/custom-provider-anthropic/package-lock.json +2 -2
- package/examples/extensions/custom-provider-anthropic/package.json +1 -1
- package/examples/extensions/custom-provider-gitlab-duo/index.ts +53 -2
- package/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
- package/examples/extensions/doom-overlay/index.ts +1 -1
- package/examples/extensions/gondolin/index.ts +531 -0
- package/examples/extensions/gondolin/package-lock.json +185 -0
- package/examples/extensions/gondolin/package.json +19 -0
- package/examples/extensions/handoff.ts +1 -1
- package/examples/extensions/interactive-shell.ts +1 -1
- package/examples/extensions/overlay-qa-tests.ts +152 -81
- package/examples/extensions/qna.ts +1 -1
- package/examples/extensions/question.ts +1 -1
- package/examples/extensions/questionnaire.ts +1 -1
- package/examples/extensions/sandbox/package-lock.json +2 -2
- package/examples/extensions/sandbox/package.json +1 -1
- package/examples/extensions/snake.ts +1 -1
- package/examples/extensions/space-invaders.ts +1 -1
- package/examples/extensions/summarize.ts +1 -1
- package/examples/extensions/tic-tac-toe.ts +1 -1
- package/examples/extensions/todo.ts +1 -1
- package/examples/extensions/tools.ts +5 -0
- package/examples/extensions/with-deps/package-lock.json +2 -2
- package/examples/extensions/with-deps/package.json +1 -1
- package/npm-shrinkwrap.json +12 -12
- package/package.json +5 -4
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "pi-extension-gondolin",
|
|
3
|
+
"version": "0.78.1",
|
|
4
|
+
"lockfileVersion": 3,
|
|
5
|
+
"requires": true,
|
|
6
|
+
"packages": {
|
|
7
|
+
"": {
|
|
8
|
+
"name": "pi-extension-gondolin",
|
|
9
|
+
"version": "0.78.1",
|
|
10
|
+
"dependencies": {
|
|
11
|
+
"@earendil-works/gondolin": "0.12.0"
|
|
12
|
+
}
|
|
13
|
+
},
|
|
14
|
+
"node_modules/@cto.af/wtf8": {
|
|
15
|
+
"version": "0.0.5",
|
|
16
|
+
"resolved": "https://registry.npmjs.org/@cto.af/wtf8/-/wtf8-0.0.5.tgz",
|
|
17
|
+
"integrity": "sha512-LfUFi+Vv4eDzj+XAtR89e3wwjXA/NZjUSwU5NhwbBrLecxPaBYFy3exCuc1j+D4UZeOVdqlsl8G7LmOt18V0tg==",
|
|
18
|
+
"license": "MIT",
|
|
19
|
+
"engines": {
|
|
20
|
+
"node": ">=20"
|
|
21
|
+
}
|
|
22
|
+
},
|
|
23
|
+
"node_modules/@earendil-works/gondolin": {
|
|
24
|
+
"version": "0.12.0",
|
|
25
|
+
"resolved": "https://registry.npmjs.org/@earendil-works/gondolin/-/gondolin-0.12.0.tgz",
|
|
26
|
+
"integrity": "sha512-BXbvzQKb5QmxY5NtthRDONJTu7+IDKbzqWGrJyyNXMP7N681Tx0Q9TK8pK1ba8nUvYQTipNJyGZOsJfYiZll1A==",
|
|
27
|
+
"license": "Apache-2.0",
|
|
28
|
+
"dependencies": {
|
|
29
|
+
"cbor2": "^2.3.0",
|
|
30
|
+
"node-forge": "^1.3.3",
|
|
31
|
+
"ssh2": "^1.17.0",
|
|
32
|
+
"undici": "^6.21.0"
|
|
33
|
+
},
|
|
34
|
+
"bin": {
|
|
35
|
+
"gondolin": "dist/bin/gondolin.js"
|
|
36
|
+
},
|
|
37
|
+
"engines": {
|
|
38
|
+
"node": ">=23.6.0"
|
|
39
|
+
},
|
|
40
|
+
"optionalDependencies": {
|
|
41
|
+
"@earendil-works/gondolin-krun-runner-darwin-arm64": "0.12.0",
|
|
42
|
+
"@earendil-works/gondolin-krun-runner-linux-x64": "0.12.0"
|
|
43
|
+
}
|
|
44
|
+
},
|
|
45
|
+
"node_modules/@earendil-works/gondolin-krun-runner-darwin-arm64": {
|
|
46
|
+
"version": "0.12.0",
|
|
47
|
+
"resolved": "https://registry.npmjs.org/@earendil-works/gondolin-krun-runner-darwin-arm64/-/gondolin-krun-runner-darwin-arm64-0.12.0.tgz",
|
|
48
|
+
"integrity": "sha512-ftDlusht4PcT7Y3TuPrZIKrCXy3isiBTVMvlXYK0pcud2uXY6uwFTGeunYgP+8ND/60ddb+MImqbfmkcK8B84A==",
|
|
49
|
+
"cpu": [
|
|
50
|
+
"arm64"
|
|
51
|
+
],
|
|
52
|
+
"license": "Apache-2.0",
|
|
53
|
+
"optional": true,
|
|
54
|
+
"os": [
|
|
55
|
+
"darwin"
|
|
56
|
+
],
|
|
57
|
+
"bin": {
|
|
58
|
+
"gondolin-krun-runner": "bin/gondolin-krun-runner"
|
|
59
|
+
}
|
|
60
|
+
},
|
|
61
|
+
"node_modules/@earendil-works/gondolin-krun-runner-linux-x64": {
|
|
62
|
+
"version": "0.12.0",
|
|
63
|
+
"resolved": "https://registry.npmjs.org/@earendil-works/gondolin-krun-runner-linux-x64/-/gondolin-krun-runner-linux-x64-0.12.0.tgz",
|
|
64
|
+
"integrity": "sha512-RRYsgwe2r5ApKmFNy469QgwnyjAHpAs9XANdWpTd9ol4iUYOY3sX7e0xIooAKxd+ktxGI4N/xRWicwGen3D/Ow==",
|
|
65
|
+
"cpu": [
|
|
66
|
+
"x64"
|
|
67
|
+
],
|
|
68
|
+
"license": "Apache-2.0",
|
|
69
|
+
"optional": true,
|
|
70
|
+
"os": [
|
|
71
|
+
"linux"
|
|
72
|
+
],
|
|
73
|
+
"bin": {
|
|
74
|
+
"gondolin-krun-runner": "bin/gondolin-krun-runner"
|
|
75
|
+
}
|
|
76
|
+
},
|
|
77
|
+
"node_modules/asn1": {
|
|
78
|
+
"version": "0.2.6",
|
|
79
|
+
"resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.6.tgz",
|
|
80
|
+
"integrity": "sha512-ix/FxPn0MDjeyJ7i/yoHGFt/EX6LyNbxSEhPPXODPL+KB0VPk86UYfL0lMdy+KCnv+fmvIzySwaK5COwqVbWTQ==",
|
|
81
|
+
"license": "MIT",
|
|
82
|
+
"dependencies": {
|
|
83
|
+
"safer-buffer": "~2.1.0"
|
|
84
|
+
}
|
|
85
|
+
},
|
|
86
|
+
"node_modules/bcrypt-pbkdf": {
|
|
87
|
+
"version": "1.0.2",
|
|
88
|
+
"resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz",
|
|
89
|
+
"integrity": "sha512-qeFIXtP4MSoi6NLqO12WfqARWWuCKi2Rn/9hJLEmtB5yTNr9DqFWkJRCf2qShWzPeAMRnOgCrq0sg/KLv5ES9w==",
|
|
90
|
+
"license": "BSD-3-Clause",
|
|
91
|
+
"dependencies": {
|
|
92
|
+
"tweetnacl": "^0.14.3"
|
|
93
|
+
}
|
|
94
|
+
},
|
|
95
|
+
"node_modules/buildcheck": {
|
|
96
|
+
"version": "0.0.7",
|
|
97
|
+
"resolved": "https://registry.npmjs.org/buildcheck/-/buildcheck-0.0.7.tgz",
|
|
98
|
+
"integrity": "sha512-lHblz4ahamxpTmnsk+MNTRWsjYKv965MwOrSJyeD588rR3Jcu7swE+0wN5F+PbL5cjgu/9ObkhfzEPuofEMwLA==",
|
|
99
|
+
"optional": true,
|
|
100
|
+
"engines": {
|
|
101
|
+
"node": ">=10.0.0"
|
|
102
|
+
}
|
|
103
|
+
},
|
|
104
|
+
"node_modules/cbor2": {
|
|
105
|
+
"version": "2.3.0",
|
|
106
|
+
"resolved": "https://registry.npmjs.org/cbor2/-/cbor2-2.3.0.tgz",
|
|
107
|
+
"integrity": "sha512-76WB3hq8BoaGkMkBVJ27fW5LJU+qqDLEpgRNCG/SYKhODWXpVPOTD4UcUto3IEzYLA52nsvbhb0wabhHDn3qXg==",
|
|
108
|
+
"license": "MIT",
|
|
109
|
+
"dependencies": {
|
|
110
|
+
"@cto.af/wtf8": "0.0.5"
|
|
111
|
+
},
|
|
112
|
+
"engines": {
|
|
113
|
+
"node": ">=20"
|
|
114
|
+
}
|
|
115
|
+
},
|
|
116
|
+
"node_modules/cpu-features": {
|
|
117
|
+
"version": "0.0.10",
|
|
118
|
+
"resolved": "https://registry.npmjs.org/cpu-features/-/cpu-features-0.0.10.tgz",
|
|
119
|
+
"integrity": "sha512-9IkYqtX3YHPCzoVg1Py+o9057a3i0fp7S530UWokCSaFVTc7CwXPRiOjRjBQQ18ZCNafx78YfnG+HALxtVmOGA==",
|
|
120
|
+
"hasInstallScript": true,
|
|
121
|
+
"optional": true,
|
|
122
|
+
"dependencies": {
|
|
123
|
+
"buildcheck": "~0.0.6",
|
|
124
|
+
"nan": "^2.19.0"
|
|
125
|
+
},
|
|
126
|
+
"engines": {
|
|
127
|
+
"node": ">=10.0.0"
|
|
128
|
+
}
|
|
129
|
+
},
|
|
130
|
+
"node_modules/nan": {
|
|
131
|
+
"version": "2.27.0",
|
|
132
|
+
"resolved": "https://registry.npmjs.org/nan/-/nan-2.27.0.tgz",
|
|
133
|
+
"integrity": "sha512-hC+0LidcL3XE4rp1C4H54KujgXKzbfyTngZTwBByQxsOxCEKZT0MPQ4hOKUH2jU1OYstqdDH4onyHPDzcV0XdQ==",
|
|
134
|
+
"license": "MIT",
|
|
135
|
+
"optional": true
|
|
136
|
+
},
|
|
137
|
+
"node_modules/node-forge": {
|
|
138
|
+
"version": "1.4.0",
|
|
139
|
+
"resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.4.0.tgz",
|
|
140
|
+
"integrity": "sha512-LarFH0+6VfriEhqMMcLX2F7SwSXeWwnEAJEsYm5QKWchiVYVvJyV9v7UDvUv+w5HO23ZpQTXDv/GxdDdMyOuoQ==",
|
|
141
|
+
"license": "(BSD-3-Clause OR GPL-2.0)",
|
|
142
|
+
"engines": {
|
|
143
|
+
"node": ">= 6.13.0"
|
|
144
|
+
}
|
|
145
|
+
},
|
|
146
|
+
"node_modules/safer-buffer": {
|
|
147
|
+
"version": "2.1.2",
|
|
148
|
+
"resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
|
|
149
|
+
"integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==",
|
|
150
|
+
"license": "MIT"
|
|
151
|
+
},
|
|
152
|
+
"node_modules/ssh2": {
|
|
153
|
+
"version": "1.17.0",
|
|
154
|
+
"resolved": "https://registry.npmjs.org/ssh2/-/ssh2-1.17.0.tgz",
|
|
155
|
+
"integrity": "sha512-wPldCk3asibAjQ/kziWQQt1Wh3PgDFpC0XpwclzKcdT1vql6KeYxf5LIt4nlFkUeR8WuphYMKqUA56X4rjbfgQ==",
|
|
156
|
+
"hasInstallScript": true,
|
|
157
|
+
"dependencies": {
|
|
158
|
+
"asn1": "^0.2.6",
|
|
159
|
+
"bcrypt-pbkdf": "^1.0.2"
|
|
160
|
+
},
|
|
161
|
+
"engines": {
|
|
162
|
+
"node": ">=10.16.0"
|
|
163
|
+
},
|
|
164
|
+
"optionalDependencies": {
|
|
165
|
+
"cpu-features": "~0.0.10",
|
|
166
|
+
"nan": "^2.23.0"
|
|
167
|
+
}
|
|
168
|
+
},
|
|
169
|
+
"node_modules/tweetnacl": {
|
|
170
|
+
"version": "0.14.5",
|
|
171
|
+
"resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz",
|
|
172
|
+
"integrity": "sha512-KXXFFdAbFXY4geFIwoyNK+f5Z1b7swfXABfL7HXCmoIWMKU3dmS26672A4EeQtDzLKy7SXmfBu51JolvEKwtGA==",
|
|
173
|
+
"license": "Unlicense"
|
|
174
|
+
},
|
|
175
|
+
"node_modules/undici": {
|
|
176
|
+
"version": "6.26.0",
|
|
177
|
+
"resolved": "https://registry.npmjs.org/undici/-/undici-6.26.0.tgz",
|
|
178
|
+
"integrity": "sha512-4yqz8a3n5HmGTlsbADNtr/dJlhkh/55Rq798G6ibiULcXbDtaLpTl1pvdqcbFfeoj3iSi52lePFM7h9H21cw/A==",
|
|
179
|
+
"license": "MIT",
|
|
180
|
+
"engines": {
|
|
181
|
+
"node": ">=18.17"
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "pi-extension-gondolin",
|
|
3
|
+
"private": true,
|
|
4
|
+
"version": "0.78.1",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"scripts": {
|
|
7
|
+
"clean": "echo 'nothing to clean'",
|
|
8
|
+
"build": "echo 'nothing to build'",
|
|
9
|
+
"check": "echo 'nothing to check'"
|
|
10
|
+
},
|
|
11
|
+
"pi": {
|
|
12
|
+
"extensions": [
|
|
13
|
+
"./index.ts"
|
|
14
|
+
]
|
|
15
|
+
},
|
|
16
|
+
"dependencies": {
|
|
17
|
+
"@earendil-works/gondolin": "0.12.0"
|
|
18
|
+
}
|
|
19
|
+
}
|
|
@@ -81,7 +81,7 @@ export default function (pi: ExtensionAPI) {
|
|
|
81
81
|
pi.registerCommand("handoff", {
|
|
82
82
|
description: "Transfer context to a new focused session",
|
|
83
83
|
handler: async (args, ctx) => {
|
|
84
|
-
if (
|
|
84
|
+
if (ctx.mode !== "tui") {
|
|
85
85
|
ctx.ui.notify("handoff requires interactive mode", "error");
|
|
86
86
|
return;
|
|
87
87
|
}
|
|
@@ -146,7 +146,7 @@ export default function (pi: ExtensionAPI) {
|
|
|
146
146
|
}
|
|
147
147
|
|
|
148
148
|
// No UI available (print mode, RPC, etc.)
|
|
149
|
-
if (
|
|
149
|
+
if (ctx.mode !== "tui") {
|
|
150
150
|
return {
|
|
151
151
|
result: { output: "(interactive commands require TUI)", exitCode: 1, cancelled: false, truncated: false },
|
|
152
152
|
};
|
|
@@ -15,13 +15,13 @@
|
|
|
15
15
|
* /overlay-sidepanel - Responsive sidepanel (hides when terminal < 100 cols)
|
|
16
16
|
* /overlay-toggle - Toggle visibility demo (demonstrates OverlayHandle.setHidden)
|
|
17
17
|
* /overlay-passive - Non-capturing overlay demo (passive info panel alongside active overlay)
|
|
18
|
-
* /overlay-focus - Focus cycling and rendering order with
|
|
18
|
+
* /overlay-focus - Focus cycling, input routing, dismissal, and rendering order with overlays
|
|
19
19
|
* /overlay-streaming - Multiple input panels with simulated streaming (Tab to cycle focus)
|
|
20
20
|
*/
|
|
21
21
|
|
|
22
22
|
import type { ExtensionAPI, ExtensionCommandContext, Theme } from "@earendil-works/pi-coding-agent";
|
|
23
23
|
import type { Component, OverlayAnchor, OverlayHandle, OverlayOptions, TUI } from "@earendil-works/pi-tui";
|
|
24
|
-
import { matchesKey, truncateToWidth, visibleWidth } from "@earendil-works/pi-tui";
|
|
24
|
+
import { Input, matchesKey, truncateToWidth, visibleWidth } from "@earendil-works/pi-tui";
|
|
25
25
|
import { spawn } from "child_process";
|
|
26
26
|
|
|
27
27
|
// Global handle for toggle demo (in real code, use a more elegant pattern)
|
|
@@ -272,9 +272,9 @@ export default function (pi: ExtensionAPI) {
|
|
|
272
272
|
},
|
|
273
273
|
});
|
|
274
274
|
|
|
275
|
-
// Focus cycling demo - demonstrates focus(),
|
|
275
|
+
// Focus cycling demo - demonstrates focus(), input routing, per-panel dismissal, and rendering order
|
|
276
276
|
pi.registerCommand("overlay-focus", {
|
|
277
|
-
description: "Test focus cycling and rendering order with
|
|
277
|
+
description: "Test focus cycling, input routing, dismissal, and rendering order with overlays",
|
|
278
278
|
handler: async (_args: string, ctx: ExtensionCommandContext) => {
|
|
279
279
|
ctx.ui.setEditorText("");
|
|
280
280
|
await ctx.ui.custom<void>((tui, theme, _kb, done) => new FocusDemoController(tui, theme, done), {
|
|
@@ -1031,57 +1031,66 @@ class TimerPanel extends BaseOverlay {
|
|
|
1031
1031
|
|
|
1032
1032
|
// === Focus cycling demo ===
|
|
1033
1033
|
|
|
1034
|
+
type FocusPanelColor = "error" | "success" | "accent";
|
|
1035
|
+
type FocusPanelConfig = { label: string; color: FocusPanelColor; options: OverlayOptions };
|
|
1036
|
+
type FocusPanelEntry = { panel: FocusPanel; handle: OverlayHandle };
|
|
1037
|
+
|
|
1038
|
+
const FOCUS_PANEL_CONFIGS = [
|
|
1039
|
+
{ label: "Alpha", color: "error", options: { row: 2, col: 4, width: 34 } },
|
|
1040
|
+
{ label: "Beta", color: "success", options: { row: 5, col: 28, width: 34 } },
|
|
1041
|
+
{ label: "Gamma", color: "accent", options: { row: 8, col: 52, width: 34 } },
|
|
1042
|
+
] satisfies FocusPanelConfig[];
|
|
1043
|
+
|
|
1034
1044
|
class FocusDemoController extends BaseOverlay {
|
|
1035
|
-
private tui: TUI;
|
|
1036
|
-
private
|
|
1037
|
-
private
|
|
1038
|
-
private
|
|
1039
|
-
private done: () => void;
|
|
1045
|
+
private readonly tui: TUI;
|
|
1046
|
+
private entries: FocusPanelEntry[] = [];
|
|
1047
|
+
private readonly done: () => void;
|
|
1048
|
+
private closed = false;
|
|
1040
1049
|
|
|
1041
1050
|
constructor(tui: TUI, theme: Theme, done: () => void) {
|
|
1042
1051
|
super(theme);
|
|
1043
1052
|
this.tui = tui;
|
|
1044
1053
|
this.done = done;
|
|
1045
|
-
const colors = ["error", "success", "accent"] as const;
|
|
1046
|
-
const labels = ["Alpha", "Beta", "Gamma"];
|
|
1047
1054
|
|
|
1048
|
-
for (
|
|
1049
|
-
const panel = new FocusPanel(
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
colors[i]!,
|
|
1053
|
-
() => this.cycleFocus(),
|
|
1054
|
-
() => this.close(),
|
|
1055
|
-
);
|
|
1056
|
-
const handle = this.tui.showOverlay(panel, {
|
|
1057
|
-
nonCapturing: true,
|
|
1058
|
-
row: 2,
|
|
1059
|
-
col: 5 + i * 6,
|
|
1060
|
-
width: 28,
|
|
1061
|
-
});
|
|
1062
|
-
panel.handle = handle;
|
|
1063
|
-
this.panels.push(panel);
|
|
1064
|
-
this.handles.push(handle);
|
|
1055
|
+
for (const config of FOCUS_PANEL_CONFIGS) {
|
|
1056
|
+
const panel = new FocusPanel({ theme, config, controller: this });
|
|
1057
|
+
const handle = this.tui.showOverlay(panel, { nonCapturing: true, ...config.options });
|
|
1058
|
+
this.entries.push({ panel, handle });
|
|
1065
1059
|
}
|
|
1060
|
+
|
|
1061
|
+
this.focusFirstOpenPanel();
|
|
1066
1062
|
}
|
|
1067
1063
|
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
}
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1064
|
+
focusNext(current: FocusPanel, direction: 1 | -1 = 1): void {
|
|
1065
|
+
const openEntries = this.openEntries();
|
|
1066
|
+
const currentOpenPosition = openEntries.findIndex((entry) => entry.panel === current);
|
|
1067
|
+
if (currentOpenPosition === -1) throw new Error(`Panel ${current.label} is not open`);
|
|
1068
|
+
const nextOpenPosition = (currentOpenPosition + direction + openEntries.length) % openEntries.length;
|
|
1069
|
+
this.focusEntryAt(openEntries, nextOpenPosition);
|
|
1070
|
+
}
|
|
1071
|
+
|
|
1072
|
+
dismiss(panel: FocusPanel): void {
|
|
1073
|
+
const openEntries = this.openEntries();
|
|
1074
|
+
const currentOpenPosition = openEntries.findIndex((candidate) => candidate.panel === panel);
|
|
1075
|
+
if (currentOpenPosition === -1) return;
|
|
1076
|
+
const entry = openEntries[currentOpenPosition];
|
|
1077
|
+
if (!entry) throw new Error(`Invalid focus panel index ${currentOpenPosition}`);
|
|
1078
|
+
const remainingEntries = openEntries.filter((candidate) => candidate.panel !== panel);
|
|
1079
|
+
|
|
1080
|
+
entry.panel.closed = true;
|
|
1081
|
+
entry.handle.hide();
|
|
1082
|
+
if (remainingEntries.length === 0) {
|
|
1083
|
+
this.close();
|
|
1084
|
+
return;
|
|
1077
1085
|
}
|
|
1078
|
-
|
|
1086
|
+
|
|
1087
|
+
this.focusEntryAt(remainingEntries, currentOpenPosition % remainingEntries.length);
|
|
1079
1088
|
}
|
|
1080
1089
|
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
this.
|
|
1084
|
-
this.
|
|
1090
|
+
close(): void {
|
|
1091
|
+
if (this.closed) return;
|
|
1092
|
+
this.closed = true;
|
|
1093
|
+
this.hidePanels();
|
|
1085
1094
|
this.done();
|
|
1086
1095
|
}
|
|
1087
1096
|
|
|
@@ -1089,86 +1098,148 @@ class FocusDemoController extends BaseOverlay {
|
|
|
1089
1098
|
if (matchesKey(data, "escape") || matchesKey(data, "ctrl+c")) {
|
|
1090
1099
|
this.close();
|
|
1091
1100
|
} else if (matchesKey(data, "tab")) {
|
|
1092
|
-
this.
|
|
1101
|
+
this.focusFirstOpenPanel();
|
|
1093
1102
|
}
|
|
1094
1103
|
}
|
|
1095
1104
|
|
|
1096
1105
|
render(width: number): string[] {
|
|
1097
1106
|
const th = this.theme;
|
|
1098
|
-
const focused = this.
|
|
1107
|
+
const focused = this.entries.find((entry) => entry.handle.isFocused())?.panel.label ?? "Controller";
|
|
1099
1108
|
return this.box(
|
|
1100
1109
|
[
|
|
1101
1110
|
"",
|
|
1102
1111
|
` Current focus: ${th.fg("accent", focused)}`,
|
|
1103
1112
|
"",
|
|
1104
1113
|
" Three overlapping panels above are",
|
|
1105
|
-
`
|
|
1106
|
-
"
|
|
1114
|
+
` ${th.fg("accent", "nonCapturing")} overlays controlled with`,
|
|
1115
|
+
" raw OverlayHandle.focus()/hide().",
|
|
1107
1116
|
"",
|
|
1108
|
-
"
|
|
1109
|
-
"
|
|
1117
|
+
" Type in the focused panel's input.",
|
|
1118
|
+
" Focused panel renders on top.",
|
|
1110
1119
|
"",
|
|
1111
|
-
th.fg("dim", " Tab = cycle
|
|
1120
|
+
th.fg("dim", " Tab/Shift+Tab = cycle panels"),
|
|
1121
|
+
th.fg("dim", " Esc/Ctrl+D = dismiss panel"),
|
|
1122
|
+
th.fg("dim", " Ctrl+C = close all"),
|
|
1112
1123
|
"",
|
|
1113
1124
|
],
|
|
1114
1125
|
width,
|
|
1115
|
-
"Focus Demo",
|
|
1126
|
+
"Focus + Input Demo",
|
|
1116
1127
|
);
|
|
1117
1128
|
}
|
|
1118
1129
|
|
|
1119
1130
|
override dispose(): void {
|
|
1120
|
-
|
|
1131
|
+
if (this.closed) return;
|
|
1132
|
+
this.closed = true;
|
|
1133
|
+
this.hidePanels();
|
|
1134
|
+
}
|
|
1135
|
+
|
|
1136
|
+
private focusFirstOpenPanel(): void {
|
|
1137
|
+
const firstOpen = this.openEntries()[0];
|
|
1138
|
+
if (firstOpen) {
|
|
1139
|
+
firstOpen.handle.focus();
|
|
1140
|
+
this.tui.requestRender();
|
|
1141
|
+
}
|
|
1142
|
+
}
|
|
1143
|
+
|
|
1144
|
+
private focusEntryAt(entries: FocusPanelEntry[], index: number): void {
|
|
1145
|
+
const entry = entries[index];
|
|
1146
|
+
if (!entry) throw new Error(`Invalid focus panel index ${index}`);
|
|
1147
|
+
entry.handle.focus();
|
|
1148
|
+
this.tui.requestRender();
|
|
1149
|
+
}
|
|
1150
|
+
|
|
1151
|
+
private hidePanels(): void {
|
|
1152
|
+
for (const entry of this.entries) {
|
|
1153
|
+
if (!entry.panel.closed) {
|
|
1154
|
+
entry.panel.closed = true;
|
|
1155
|
+
entry.handle.hide();
|
|
1156
|
+
}
|
|
1157
|
+
}
|
|
1158
|
+
this.entries = [];
|
|
1159
|
+
}
|
|
1160
|
+
|
|
1161
|
+
private openEntries(): FocusPanelEntry[] {
|
|
1162
|
+
return this.entries.filter((entry) => !entry.panel.closed);
|
|
1121
1163
|
}
|
|
1122
1164
|
}
|
|
1123
1165
|
|
|
1124
1166
|
class FocusPanel extends BaseOverlay {
|
|
1125
|
-
|
|
1167
|
+
focused = false;
|
|
1168
|
+
closed = false;
|
|
1126
1169
|
readonly label: string;
|
|
1127
|
-
private color:
|
|
1128
|
-
private
|
|
1129
|
-
private
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
1170
|
+
private readonly color: FocusPanelColor;
|
|
1171
|
+
private readonly controller: FocusDemoController;
|
|
1172
|
+
private readonly input = new Input();
|
|
1173
|
+
private inputs: string[] = [];
|
|
1174
|
+
|
|
1175
|
+
constructor({
|
|
1176
|
+
theme,
|
|
1177
|
+
config,
|
|
1178
|
+
controller,
|
|
1179
|
+
}: {
|
|
1180
|
+
theme: Theme;
|
|
1181
|
+
config: FocusPanelConfig;
|
|
1182
|
+
controller: FocusDemoController;
|
|
1183
|
+
}) {
|
|
1138
1184
|
super(theme);
|
|
1139
|
-
this.label = label;
|
|
1140
|
-
this.color = color;
|
|
1141
|
-
this.
|
|
1142
|
-
this.onClose = onClose;
|
|
1185
|
+
this.label = config.label;
|
|
1186
|
+
this.color = config.color;
|
|
1187
|
+
this.controller = controller;
|
|
1143
1188
|
}
|
|
1144
1189
|
|
|
1145
1190
|
handleInput(data: string): void {
|
|
1146
1191
|
if (matchesKey(data, "tab")) {
|
|
1147
|
-
this.
|
|
1148
|
-
} else if (matchesKey(data, "
|
|
1149
|
-
this.
|
|
1192
|
+
this.controller.focusNext(this);
|
|
1193
|
+
} else if (matchesKey(data, "shift+tab")) {
|
|
1194
|
+
this.controller.focusNext(this, -1);
|
|
1195
|
+
} else if (matchesKey(data, "escape") || matchesKey(data, "ctrl+d")) {
|
|
1196
|
+
this.controller.dismiss(this);
|
|
1197
|
+
} else if (matchesKey(data, "ctrl+c")) {
|
|
1198
|
+
this.controller.close();
|
|
1199
|
+
} else if (matchesKey(data, "return")) {
|
|
1200
|
+
this.inputs.push("Enter");
|
|
1201
|
+
} else if (matchesKey(data, "up")) {
|
|
1202
|
+
this.inputs.push("↑");
|
|
1203
|
+
} else if (matchesKey(data, "down")) {
|
|
1204
|
+
this.inputs.push("↓");
|
|
1205
|
+
} else if (matchesKey(data, "left")) {
|
|
1206
|
+
this.input.handleInput(data);
|
|
1207
|
+
this.inputs.push("←");
|
|
1208
|
+
} else if (matchesKey(data, "right")) {
|
|
1209
|
+
this.input.handleInput(data);
|
|
1210
|
+
this.inputs.push("→");
|
|
1211
|
+
} else if (matchesKey(data, "backspace")) {
|
|
1212
|
+
this.input.handleInput(data);
|
|
1213
|
+
this.inputs.push("Backspace");
|
|
1214
|
+
} else {
|
|
1215
|
+
this.input.handleInput(data);
|
|
1216
|
+
this.inputs.push(JSON.stringify(data));
|
|
1150
1217
|
}
|
|
1151
1218
|
}
|
|
1152
1219
|
|
|
1153
1220
|
render(width: number): string[] {
|
|
1154
1221
|
const th = this.theme;
|
|
1155
|
-
const focused = this.handle?.isFocused() ?? false;
|
|
1156
1222
|
const innerW = Math.max(1, width - 2);
|
|
1157
|
-
const border = (c: string) => th.fg(this.color, c);
|
|
1223
|
+
const border = (c: string) => th.fg(this.focused ? this.color : "dim", c);
|
|
1158
1224
|
const padLine = (s: string) => truncateToWidth(s, innerW, "...", true);
|
|
1225
|
+
const recent = this.inputs.length === 0 ? "(none)" : this.inputs.slice(-6).join(" ");
|
|
1159
1226
|
const lines: string[] = [];
|
|
1160
1227
|
|
|
1228
|
+
this.input.focused = this.focused;
|
|
1229
|
+
const [inputLine = ""] = this.input.render(Math.max(1, innerW - 8));
|
|
1161
1230
|
lines.push(border(`╭${"─".repeat(innerW)}╮`));
|
|
1162
|
-
lines.push(
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
lines.push(border("│") + padLine(th.fg("dim", " (passive)")) + border("│"));
|
|
1170
|
-
}
|
|
1231
|
+
lines.push(
|
|
1232
|
+
border("│") +
|
|
1233
|
+
padLine(
|
|
1234
|
+
` ${th.fg(this.color, this.label)} ${this.focused ? th.fg("success", "FOCUSED") : th.fg("dim", "visible")}`,
|
|
1235
|
+
) +
|
|
1236
|
+
border("│"),
|
|
1237
|
+
);
|
|
1171
1238
|
lines.push(border("│") + padLine("") + border("│"));
|
|
1239
|
+
lines.push(border("│") + padLine(` Input: ${inputLine}`) + border("│"));
|
|
1240
|
+
lines.push(border("│") + padLine(` Keys: ${recent}`) + border("│"));
|
|
1241
|
+
lines.push(border("│") + padLine(th.fg("dim", " Tab/Shift+Tab focus")) + border("│"));
|
|
1242
|
+
lines.push(border("│") + padLine(th.fg("dim", " Esc/Ctrl+D dismiss")) + border("│"));
|
|
1172
1243
|
lines.push(border(`╰${"─".repeat(innerW)}╯`));
|
|
1173
1244
|
|
|
1174
1245
|
return lines;
|
|
@@ -31,7 +31,7 @@ export default function (pi: ExtensionAPI) {
|
|
|
31
31
|
pi.registerCommand("qna", {
|
|
32
32
|
description: "Extract questions from last assistant message into editor",
|
|
33
33
|
handler: async (_args, ctx) => {
|
|
34
|
-
if (
|
|
34
|
+
if (ctx.mode !== "tui") {
|
|
35
35
|
ctx.ui.notify("qna requires interactive mode", "error");
|
|
36
36
|
return;
|
|
37
37
|
}
|
|
@@ -41,7 +41,7 @@ export default function question(pi: ExtensionAPI) {
|
|
|
41
41
|
parameters: QuestionParams,
|
|
42
42
|
|
|
43
43
|
async execute(_toolCallId, params, _signal, _onUpdate, ctx) {
|
|
44
|
-
if (
|
|
44
|
+
if (ctx.mode !== "tui") {
|
|
45
45
|
return {
|
|
46
46
|
content: [{ type: "text", text: "Error: UI not available (running in non-interactive mode)" }],
|
|
47
47
|
details: {
|
|
@@ -82,7 +82,7 @@ export default function questionnaire(pi: ExtensionAPI) {
|
|
|
82
82
|
parameters: QuestionnaireParams,
|
|
83
83
|
|
|
84
84
|
async execute(_toolCallId, params, _signal, _onUpdate, ctx) {
|
|
85
|
-
if (
|
|
85
|
+
if (ctx.mode !== "tui") {
|
|
86
86
|
return errorResult("Error: UI not available (running in non-interactive mode)");
|
|
87
87
|
}
|
|
88
88
|
if (params.questions.length === 0) {
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pi-extension-sandbox",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.8.1",
|
|
4
4
|
"lockfileVersion": 3,
|
|
5
5
|
"requires": true,
|
|
6
6
|
"packages": {
|
|
7
7
|
"": {
|
|
8
8
|
"name": "pi-extension-sandbox",
|
|
9
|
-
"version": "1.
|
|
9
|
+
"version": "1.8.1",
|
|
10
10
|
"dependencies": {
|
|
11
11
|
"@anthropic-ai/sandbox-runtime": "^0.0.26"
|
|
12
12
|
}
|
|
@@ -529,7 +529,7 @@ export default function (pi: ExtensionAPI) {
|
|
|
529
529
|
description: "Play Space Invaders!",
|
|
530
530
|
|
|
531
531
|
handler: async (_args, ctx) => {
|
|
532
|
-
if (
|
|
532
|
+
if (ctx.mode !== "tui") {
|
|
533
533
|
ctx.ui.notify("Space Invaders requires interactive mode", "error");
|
|
534
534
|
return;
|
|
535
535
|
}
|
|
@@ -779,7 +779,7 @@ Decide the target cell first, then dump every action for the turn in one go.
|
|
|
779
779
|
description: "Play tic-tac-toe against the agent",
|
|
780
780
|
|
|
781
781
|
handler: async (_args, ctx) => {
|
|
782
|
-
if (
|
|
782
|
+
if (ctx.mode !== "tui") {
|
|
783
783
|
ctx.ui.notify("Tic-tac-toe requires interactive mode", "error");
|
|
784
784
|
return;
|
|
785
785
|
}
|
|
@@ -284,7 +284,7 @@ export default function (pi: ExtensionAPI) {
|
|
|
284
284
|
pi.registerCommand("todos", {
|
|
285
285
|
description: "Show all todos on the current branch",
|
|
286
286
|
handler: async (_args, ctx) => {
|
|
287
|
-
if (
|
|
287
|
+
if (ctx.mode !== "tui") {
|
|
288
288
|
ctx.ui.notify("/todos requires interactive mode", "error");
|
|
289
289
|
return;
|
|
290
290
|
}
|
|
@@ -67,6 +67,11 @@ export default function toolsExtension(pi: ExtensionAPI) {
|
|
|
67
67
|
pi.registerCommand("tools", {
|
|
68
68
|
description: "Enable/disable tools",
|
|
69
69
|
handler: async (_args, ctx) => {
|
|
70
|
+
if (ctx.mode !== "tui") {
|
|
71
|
+
ctx.ui.notify("/tools requires TUI mode", "error");
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
74
|
+
|
|
70
75
|
// Refresh tool list
|
|
71
76
|
allTools = pi.getAllTools();
|
|
72
77
|
|