@heyamiko/amiko-cli 0.4.9 → 0.4.11
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/bun.lock +147 -0
- package/dist/__tests__/cli-non-tty.test.js +74 -0
- package/dist/cli.js +18 -32
- package/dist/headless.js +218 -0
- package/package.json +7 -4
- package/src/__tests__/cli-non-tty.test.ts +86 -0
- package/src/cli.tsx +20 -32
- package/src/headless.ts +222 -0
package/bun.lock
CHANGED
|
@@ -19,6 +19,7 @@
|
|
|
19
19
|
"@types/react-dom": "^18.2.0",
|
|
20
20
|
"tsx": "^4.7.0",
|
|
21
21
|
"typescript": "^5.4.0",
|
|
22
|
+
"vitest": "^4.1.3",
|
|
22
23
|
},
|
|
23
24
|
},
|
|
24
25
|
},
|
|
@@ -97,6 +98,12 @@
|
|
|
97
98
|
|
|
98
99
|
"@babel/runtime": ["@babel/runtime@7.28.6", "", {}, "sha512-05WQkdpL9COIMz4LjTxGpPNCdlpyimKppYNoJ5Di5EUObifl8t4tuLuUBBZEpoLYOmfvIWrsp9fCl0HoPRVTdA=="],
|
|
99
100
|
|
|
101
|
+
"@emnapi/core": ["@emnapi/core@1.9.1", "", { "dependencies": { "@emnapi/wasi-threads": "1.2.0", "tslib": "^2.4.0" } }, "sha512-mukuNALVsoix/w1BJwFzwXBN/dHeejQtuVzcDsfOEsdpCumXb/E9j8w11h5S54tT1xhifGfbbSm/ICrObRb3KA=="],
|
|
102
|
+
|
|
103
|
+
"@emnapi/runtime": ["@emnapi/runtime@1.9.1", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-VYi5+ZVLhpgK4hQ0TAjiQiZ6ol0oe4mBx7mVv7IflsiEp0OWoVsp/+f9Vc1hOhE0TtkORVrI1GvzyreqpgWtkA=="],
|
|
104
|
+
|
|
105
|
+
"@emnapi/wasi-threads": ["@emnapi/wasi-threads@1.2.0", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-N10dEJNSsUx41Z6pZsXU8FjPjpBEplgH24sfkmITrBED1/U2Esum9F3lfLrMjKHHjmi557zQn7kR9R+XWXu5Rg=="],
|
|
106
|
+
|
|
100
107
|
"@esbuild/aix-ppc64": ["@esbuild/aix-ppc64@0.27.2", "", { "os": "aix", "cpu": "ppc64" }, "sha512-GZMB+a0mOMZs4MpDbj8RJp4cw+w1WV5NYD6xzgvzUJ5Ek2jerwfO2eADyI6ExDSUED+1X8aMbegahsJi+8mgpw=="],
|
|
101
108
|
|
|
102
109
|
"@esbuild/android-arm": ["@esbuild/android-arm@0.27.2", "", { "os": "android", "cpu": "arm" }, "sha512-DVNI8jlPa7Ujbr1yjU2PfUSRtAUZPG9I1RwW4F4xFB1Imiu2on0ADiI/c3td+KmDtVKNbi+nffGDQMfcIMkwIA=="],
|
|
@@ -153,6 +160,8 @@
|
|
|
153
160
|
|
|
154
161
|
"@isaacs/cliui": ["@isaacs/cliui@8.0.2", "", { "dependencies": { "string-width": "5.1.2", "string-width-cjs": "npm:string-width@4.2.3", "strip-ansi": "7.1.2", "strip-ansi-cjs": "npm:strip-ansi@6.0.1", "wrap-ansi": "8.1.0", "wrap-ansi-cjs": "npm:wrap-ansi@7.0.0" } }, "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA=="],
|
|
155
162
|
|
|
163
|
+
"@jridgewell/sourcemap-codec": ["@jridgewell/sourcemap-codec@1.5.5", "", {}, "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og=="],
|
|
164
|
+
|
|
156
165
|
"@mariozechner/pi-agent-core": ["@mariozechner/pi-agent-core@0.50.1", "", { "dependencies": { "@mariozechner/pi-ai": "0.50.1", "@mariozechner/pi-tui": "0.50.1" } }, "sha512-rW/CwANMGjqXcDvOT09ljHeNxfPHp/1hWamJrk9JamzkqVS+UHrFTJdc5qPv+O0naNDRUGBr6woer22C6F8BOA=="],
|
|
157
166
|
|
|
158
167
|
"@mariozechner/pi-ai": ["@mariozechner/pi-ai@0.50.1", "", { "dependencies": { "@anthropic-ai/sdk": "0.71.2", "@aws-sdk/client-bedrock-runtime": "3.975.0", "@google/genai": "1.34.0", "@mistralai/mistralai": "1.10.0", "@sinclair/typebox": "0.34.48", "ajv": "8.17.1", "ajv-formats": "3.0.1", "chalk": "5.6.2", "openai": "6.10.0", "partial-json": "0.1.7", "proxy-agent": "6.5.0", "undici": "7.19.2", "zod-to-json-schema": "3.25.1" }, "bin": { "pi-ai": "dist/cli.js" } }, "sha512-t8qUHHqz3tgK4r3f/msRKK2QbhvlDjBCjOJlTn7iJDwVAWABO8EYwf0BzkB0RGrGkiIOKhDwEVbB4jD3VxaKnA=="],
|
|
@@ -161,8 +170,44 @@
|
|
|
161
170
|
|
|
162
171
|
"@mistralai/mistralai": ["@mistralai/mistralai@1.10.0", "", { "dependencies": { "zod": "3.25.76", "zod-to-json-schema": "3.25.1" } }, "sha512-tdIgWs4Le8vpvPiUEWne6tK0qbVc+jMenujnvTqOjogrJUsCSQhus0tHTU1avDDh5//Rq2dFgP9mWRAdIEoBqg=="],
|
|
163
172
|
|
|
173
|
+
"@napi-rs/wasm-runtime": ["@napi-rs/wasm-runtime@1.1.3", "", { "dependencies": { "@tybys/wasm-util": "^0.10.1" }, "peerDependencies": { "@emnapi/core": "^1.7.1", "@emnapi/runtime": "^1.7.1" } }, "sha512-xK9sGVbJWYb08+mTJt3/YV24WxvxpXcXtP6B172paPZ+Ts69Re9dAr7lKwJoeIx8OoeuimEiRZ7umkiUVClmmQ=="],
|
|
174
|
+
|
|
175
|
+
"@oxc-project/types": ["@oxc-project/types@0.123.0", "", {}, "sha512-YtECP/y8Mj1lSHiUWGSRzy/C6teUKlS87dEfuVKT09LgQbUsBW1rNg+MiJ4buGu3yuADV60gbIvo9/HplA56Ew=="],
|
|
176
|
+
|
|
164
177
|
"@pkgjs/parseargs": ["@pkgjs/parseargs@0.11.0", "", {}, "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg=="],
|
|
165
178
|
|
|
179
|
+
"@rolldown/binding-android-arm64": ["@rolldown/binding-android-arm64@1.0.0-rc.13", "", { "os": "android", "cpu": "arm64" }, "sha512-5ZiiecKH2DXAVJTNN13gNMUcCDg4Jy8ZjbXEsPnqa248wgOVeYRX0iqXXD5Jz4bI9BFHgKsI2qmyJynstbmr+g=="],
|
|
180
|
+
|
|
181
|
+
"@rolldown/binding-darwin-arm64": ["@rolldown/binding-darwin-arm64@1.0.0-rc.13", "", { "os": "darwin", "cpu": "arm64" }, "sha512-tz/v/8G77seu8zAB3A5sK3UFoOl06zcshEzhUO62sAEtrEuW/H1CcyoupOrD+NbQJytYgA4CppXPzlrmp4JZKA=="],
|
|
182
|
+
|
|
183
|
+
"@rolldown/binding-darwin-x64": ["@rolldown/binding-darwin-x64@1.0.0-rc.13", "", { "os": "darwin", "cpu": "x64" }, "sha512-8DakphqOz8JrMYWTJmWA+vDJxut6LijZ8Xcdc4flOlAhU7PNVwo2MaWBF9iXjJAPo5rC/IxEFZDhJ3GC7NHvug=="],
|
|
184
|
+
|
|
185
|
+
"@rolldown/binding-freebsd-x64": ["@rolldown/binding-freebsd-x64@1.0.0-rc.13", "", { "os": "freebsd", "cpu": "x64" }, "sha512-4wBQFfjDuXYN/SVI8inBF3Aa+isq40rc6VMFbk5jcpolUBTe5cYnMsHZ51nFWsx3PVyyNN3vgoESki0Hmr/4BA=="],
|
|
186
|
+
|
|
187
|
+
"@rolldown/binding-linux-arm-gnueabihf": ["@rolldown/binding-linux-arm-gnueabihf@1.0.0-rc.13", "", { "os": "linux", "cpu": "arm" }, "sha512-JW/e4yPIXLms+jmnbwwy5LA/LxVwZUWLN8xug+V200wzaVi5TEGIWQlh8o91gWYFxW609euI98OCCemmWGuPrw=="],
|
|
188
|
+
|
|
189
|
+
"@rolldown/binding-linux-arm64-gnu": ["@rolldown/binding-linux-arm64-gnu@1.0.0-rc.13", "", { "os": "linux", "cpu": "arm64" }, "sha512-ZfKWpXiUymDnavepCaM6KG/uGydJ4l2nBmMxg60Ci4CbeefpqjPWpfaZM7PThOhk2dssqBAcwLc6rAyr0uTdXg=="],
|
|
190
|
+
|
|
191
|
+
"@rolldown/binding-linux-arm64-musl": ["@rolldown/binding-linux-arm64-musl@1.0.0-rc.13", "", { "os": "linux", "cpu": "arm64" }, "sha512-bmRg3O6Z0gq9yodKKWCIpnlH051sEfdVwt+6m5UDffAQMUUqU0xjnQqqAUm+Gu7ofAAly9DqiQDtKu2nPDEABA=="],
|
|
192
|
+
|
|
193
|
+
"@rolldown/binding-linux-ppc64-gnu": ["@rolldown/binding-linux-ppc64-gnu@1.0.0-rc.13", "", { "os": "linux", "cpu": "ppc64" }, "sha512-8Wtnbw4k7pMYN9B/mOEAsQ8HOiq7AZ31Ig4M9BKn2So4xRaFEhtCSa4ZJaOutOWq50zpgR4N5+L/opnlaCx8wQ=="],
|
|
194
|
+
|
|
195
|
+
"@rolldown/binding-linux-s390x-gnu": ["@rolldown/binding-linux-s390x-gnu@1.0.0-rc.13", "", { "os": "linux", "cpu": "s390x" }, "sha512-D/0Nlo8mQuxSMohNJUF2lDXWRsFDsHldfRRgD9bRgktj+EndGPj4DOV37LqDKPYS+osdyhZEH7fTakTAEcW7qg=="],
|
|
196
|
+
|
|
197
|
+
"@rolldown/binding-linux-x64-gnu": ["@rolldown/binding-linux-x64-gnu@1.0.0-rc.13", "", { "os": "linux", "cpu": "x64" }, "sha512-eRrPvat2YaVQcwwKi/JzOP6MKf1WRnOCr+VaI3cTWz3ZoLcP/654z90lVCJ4dAuMEpPdke0n+qyAqXDZdIC4rA=="],
|
|
198
|
+
|
|
199
|
+
"@rolldown/binding-linux-x64-musl": ["@rolldown/binding-linux-x64-musl@1.0.0-rc.13", "", { "os": "linux", "cpu": "x64" }, "sha512-PsdONiFRp8hR8KgVjTWjZ9s7uA3uueWL0t74/cKHfM4dR5zXYv4AjB8BvA+QDToqxAFg4ZkcVEqeu5F7inoz5w=="],
|
|
200
|
+
|
|
201
|
+
"@rolldown/binding-openharmony-arm64": ["@rolldown/binding-openharmony-arm64@1.0.0-rc.13", "", { "os": "none", "cpu": "arm64" }, "sha512-hCNXgC5dI3TVOLrPT++PKFNZ+1EtS0mLQwfXXXSUD/+rGlB65gZDwN/IDuxLpQP4x8RYYHqGomlUXzpO8aVI2w=="],
|
|
202
|
+
|
|
203
|
+
"@rolldown/binding-wasm32-wasi": ["@rolldown/binding-wasm32-wasi@1.0.0-rc.13", "", { "dependencies": { "@emnapi/core": "1.9.1", "@emnapi/runtime": "1.9.1", "@napi-rs/wasm-runtime": "^1.1.2" }, "cpu": "none" }, "sha512-viLS5C5et8NFtLWw9Sw3M/w4vvnVkbWkO7wSNh3C+7G1+uCkGpr6PcjNDSFcNtmXY/4trjPBqUfcOL+P3sWy/g=="],
|
|
204
|
+
|
|
205
|
+
"@rolldown/binding-win32-arm64-msvc": ["@rolldown/binding-win32-arm64-msvc@1.0.0-rc.13", "", { "os": "win32", "cpu": "arm64" }, "sha512-Fqa3Tlt1xL4wzmAYxGNFV36Hb+VfPc9PYU+E25DAnswXv3ODDu/yyWjQDbXMo5AGWkQVjLgQExuVu8I/UaZhPQ=="],
|
|
206
|
+
|
|
207
|
+
"@rolldown/binding-win32-x64-msvc": ["@rolldown/binding-win32-x64-msvc@1.0.0-rc.13", "", { "os": "win32", "cpu": "x64" }, "sha512-/pLI5kPkGEi44TDlnbio3St/5gUFeN51YWNAk/Gnv6mEQBOahRBh52qVFVBpmrnU01n2yysvBML9Ynu7K4kGAQ=="],
|
|
208
|
+
|
|
209
|
+
"@rolldown/pluginutils": ["@rolldown/pluginutils@1.0.0-rc.13", "", {}, "sha512-3ngTAv6F/Py35BsYbeeLeecvhMKdsKm4AoOETVhAA+Qc8nrA2I0kF7oa93mE9qnIurngOSpMnQ0x2nQY2FPviA=="],
|
|
210
|
+
|
|
166
211
|
"@sinclair/typebox": ["@sinclair/typebox@0.34.48", "", {}, "sha512-kKJTNuK3AQOrgjjotVxMrCn1sUJwM76wMszfq1kdU4uYVJjvEWuFQ6HgvLt4Xz3fSmZlTOxJ/Ie13KnIcWQXFA=="],
|
|
167
212
|
|
|
168
213
|
"@smithy/abort-controller": ["@smithy/abort-controller@4.2.8", "", { "dependencies": { "@smithy/types": "4.12.0", "tslib": "2.8.1" } }, "sha512-peuVfkYHAmS5ybKxWcfraK7WBBP0J+rkfUcbHJJKQ4ir3UAUNQI+Y4Vt/PqSzGqgloJ5O1dk7+WzNL8wcCSXbw=="],
|
|
@@ -255,8 +300,18 @@
|
|
|
255
300
|
|
|
256
301
|
"@smithy/uuid": ["@smithy/uuid@1.1.0", "", { "dependencies": { "tslib": "2.8.1" } }, "sha512-4aUIteuyxtBUhVdiQqcDhKFitwfd9hqoSDYY2KRXiWtgoWJ9Bmise+KfEPDiVHWeJepvF8xJO9/9+WDIciMFFw=="],
|
|
257
302
|
|
|
303
|
+
"@standard-schema/spec": ["@standard-schema/spec@1.1.0", "", {}, "sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w=="],
|
|
304
|
+
|
|
258
305
|
"@tootallnate/quickjs-emscripten": ["@tootallnate/quickjs-emscripten@0.23.0", "", {}, "sha512-C5Mc6rdnsaJDjO3UpGW/CQTHtCKaYlScZTly4JIu97Jxo/odCiH0ITnDXSJPTOrEKk/ycSZ0AOgTmkDtkOsvIA=="],
|
|
259
306
|
|
|
307
|
+
"@tybys/wasm-util": ["@tybys/wasm-util@0.10.1", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg=="],
|
|
308
|
+
|
|
309
|
+
"@types/chai": ["@types/chai@5.2.3", "", { "dependencies": { "@types/deep-eql": "*", "assertion-error": "^2.0.1" } }, "sha512-Mw558oeA9fFbv65/y4mHtXDs9bPnFMZAL/jxdPFUpOHHIXX91mcgEHbS5Lahr+pwZFR8A7GQleRWeI6cGFC2UA=="],
|
|
310
|
+
|
|
311
|
+
"@types/deep-eql": ["@types/deep-eql@4.0.2", "", {}, "sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw=="],
|
|
312
|
+
|
|
313
|
+
"@types/estree": ["@types/estree@1.0.8", "", {}, "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w=="],
|
|
314
|
+
|
|
260
315
|
"@types/mime-types": ["@types/mime-types@2.1.4", "", {}, "sha512-lfU4b34HOri+kAY5UheuFMWPDOI+OPceBSHZKp69gEyTL/mmJ4cnU6Y/rlme3UL3GyOn6Y42hyIEw0/q8sWx5w=="],
|
|
261
316
|
|
|
262
317
|
"@types/node": ["@types/node@20.19.30", "", { "dependencies": { "undici-types": "6.21.0" } }, "sha512-WJtwWJu7UdlvzEAUm484QNg5eAoq5QR08KDNx7g45Usrs2NtOPiX8ugDqmKdXkyL03rBqU5dYNYVQetEpBHq2g=="],
|
|
@@ -267,6 +322,20 @@
|
|
|
267
322
|
|
|
268
323
|
"@types/react-dom": ["@types/react-dom@18.3.7", "", { "peerDependencies": { "@types/react": "18.3.27" } }, "sha512-MEe3UeoENYVFXzoXEWsvcpg6ZvlrFNlOQ7EOsvhI3CfAXwzPfO8Qwuxd40nepsYKqyyVQnTdEfv68q91yLcKrQ=="],
|
|
269
324
|
|
|
325
|
+
"@vitest/expect": ["@vitest/expect@4.1.3", "", { "dependencies": { "@standard-schema/spec": "^1.1.0", "@types/chai": "^5.2.2", "@vitest/spy": "4.1.3", "@vitest/utils": "4.1.3", "chai": "^6.2.2", "tinyrainbow": "^3.1.0" } }, "sha512-CW8Q9KMtXDGHj0vCsqui0M5KqRsu0zm0GNDW7Gd3U7nZ2RFpPKSCpeCXoT+/+5zr1TNlsoQRDEz+LzZUyq6gnQ=="],
|
|
326
|
+
|
|
327
|
+
"@vitest/mocker": ["@vitest/mocker@4.1.3", "", { "dependencies": { "@vitest/spy": "4.1.3", "estree-walker": "^3.0.3", "magic-string": "^0.30.21" }, "peerDependencies": { "msw": "^2.4.9", "vite": "^6.0.0 || ^7.0.0 || ^8.0.0" }, "optionalPeers": ["msw", "vite"] }, "sha512-XN3TrycitDQSzGRnec/YWgoofkYRhouyVQj4YNsJ5r/STCUFqMrP4+oxEv3e7ZbLi4og5kIHrZwekDJgw6hcjw=="],
|
|
328
|
+
|
|
329
|
+
"@vitest/pretty-format": ["@vitest/pretty-format@4.1.3", "", { "dependencies": { "tinyrainbow": "^3.1.0" } }, "sha512-hYqqwuMbpkkBodpRh4k4cQSOELxXky1NfMmQvOfKvV8zQHz8x8Dla+2wzElkMkBvSAJX5TRGHJAQvK0TcOafwg=="],
|
|
330
|
+
|
|
331
|
+
"@vitest/runner": ["@vitest/runner@4.1.3", "", { "dependencies": { "@vitest/utils": "4.1.3", "pathe": "^2.0.3" } }, "sha512-VwgOz5MmT0KhlUj40h02LWDpUBVpflZ/b7xZFA25F29AJzIrE+SMuwzFf0b7t4EXdwRNX61C3B6auIXQTR3ttA=="],
|
|
332
|
+
|
|
333
|
+
"@vitest/snapshot": ["@vitest/snapshot@4.1.3", "", { "dependencies": { "@vitest/pretty-format": "4.1.3", "@vitest/utils": "4.1.3", "magic-string": "^0.30.21", "pathe": "^2.0.3" } }, "sha512-9l+k/J9KG5wPJDX9BcFFzhhwNjwkRb8RsnYhaT1vPY7OufxmQFc9sZzScRCPTiETzl37mrIWVY9zxzmdVeJwDQ=="],
|
|
334
|
+
|
|
335
|
+
"@vitest/spy": ["@vitest/spy@4.1.3", "", {}, "sha512-ujj5Uwxagg4XUIfAUyRQxAg631BP6e9joRiN99mr48Bg9fRs+5mdUElhOoZ6rP5mBr8Bs3lmrREnkrQWkrsTCw=="],
|
|
336
|
+
|
|
337
|
+
"@vitest/utils": ["@vitest/utils@4.1.3", "", { "dependencies": { "@vitest/pretty-format": "4.1.3", "convert-source-map": "^2.0.0", "tinyrainbow": "^3.1.0" } }, "sha512-Pc/Oexse/khOWsGB+w3q4yzA4te7W4gpZZAvk+fr8qXfTURZUMj5i7kuxsNK5mP/dEB6ao3jfr0rs17fHhbHdw=="],
|
|
338
|
+
|
|
270
339
|
"agent-base": ["agent-base@7.1.4", "", {}, "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ=="],
|
|
271
340
|
|
|
272
341
|
"ajv": ["ajv@8.17.1", "", { "dependencies": { "fast-deep-equal": "3.1.3", "fast-uri": "3.1.0", "json-schema-traverse": "1.0.0", "require-from-string": "2.0.2" } }, "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g=="],
|
|
@@ -281,6 +350,8 @@
|
|
|
281
350
|
|
|
282
351
|
"arr-rotate": ["arr-rotate@1.0.0", "", {}, "sha512-yOzOZcR9Tn7enTF66bqKorGGH0F36vcPaSWg8fO0c0UYb3LX3VMXj5ZxEqQLNOecAhlRJ7wYZja5i4jTlnbIfQ=="],
|
|
283
352
|
|
|
353
|
+
"assertion-error": ["assertion-error@2.0.1", "", {}, "sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA=="],
|
|
354
|
+
|
|
284
355
|
"ast-types": ["ast-types@0.13.4", "", { "dependencies": { "tslib": "2.8.1" } }, "sha512-x1FCFnFifvYDDzTaLII71vG5uvDwgtmDTEVWAxrgeiR8VjMONcCXJx7E+USjDtHlwFmt9MysbqgF9b9Vjr6w+w=="],
|
|
285
356
|
|
|
286
357
|
"auto-bind": ["auto-bind@5.0.1", "", {}, "sha512-ooviqdwwgfIfNmDwo94wlshcdzfO64XV0Cg6oDsDYBJfITDz1EngD2z7DkbvCWn+XIMsIqW27sEVF6qcpJrRcg=="],
|
|
@@ -299,6 +370,8 @@
|
|
|
299
370
|
|
|
300
371
|
"buffer-equal-constant-time": ["buffer-equal-constant-time@1.0.1", "", {}, "sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA=="],
|
|
301
372
|
|
|
373
|
+
"chai": ["chai@6.2.2", "", {}, "sha512-NUPRluOfOiTKBKvWPtSD4PhFvWCqOi0BGStNWs57X9js7XGTprSmFoz5F0tWhR4WPjNeR9jXqdC7/UpSJTnlRg=="],
|
|
374
|
+
|
|
302
375
|
"chalk": ["chalk@5.6.2", "", {}, "sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA=="],
|
|
303
376
|
|
|
304
377
|
"ci-info": ["ci-info@3.9.0", "", {}, "sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ=="],
|
|
@@ -315,6 +388,8 @@
|
|
|
315
388
|
|
|
316
389
|
"color-name": ["color-name@1.1.4", "", {}, "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="],
|
|
317
390
|
|
|
391
|
+
"convert-source-map": ["convert-source-map@2.0.0", "", {}, "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg=="],
|
|
392
|
+
|
|
318
393
|
"convert-to-spaces": ["convert-to-spaces@2.0.1", "", {}, "sha512-rcQ1bsQO9799wq24uE5AM2tAILy4gXGIK/njFWcVQkGNZ96edlpY+A7bjwvzjYvLDyzmG1MmMLZhpcsb+klNMQ=="],
|
|
319
394
|
|
|
320
395
|
"cross-spawn": ["cross-spawn@7.0.6", "", { "dependencies": { "path-key": "3.1.1", "shebang-command": "2.0.0", "which": "2.0.2" } }, "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA=="],
|
|
@@ -327,12 +402,16 @@
|
|
|
327
402
|
|
|
328
403
|
"degenerator": ["degenerator@5.0.1", "", { "dependencies": { "ast-types": "0.13.4", "escodegen": "2.1.0", "esprima": "4.0.1" } }, "sha512-TllpMR/t0M5sqCXfj85i4XaAzxmS5tVA16dqvdkMwGmzI+dXLXnw3J+3Vdv7VKw+ThlTMboK6i9rnZ6Nntj5CQ=="],
|
|
329
404
|
|
|
405
|
+
"detect-libc": ["detect-libc@2.1.2", "", {}, "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ=="],
|
|
406
|
+
|
|
330
407
|
"eastasianwidth": ["eastasianwidth@0.2.0", "", {}, "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA=="],
|
|
331
408
|
|
|
332
409
|
"ecdsa-sig-formatter": ["ecdsa-sig-formatter@1.0.11", "", { "dependencies": { "safe-buffer": "5.2.1" } }, "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ=="],
|
|
333
410
|
|
|
334
411
|
"emoji-regex": ["emoji-regex@9.2.2", "", {}, "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg=="],
|
|
335
412
|
|
|
413
|
+
"es-module-lexer": ["es-module-lexer@2.0.0", "", {}, "sha512-5POEcUuZybH7IdmGsD8wlf0AI55wMecM9rVBTI/qEAy2c1kTOm3DjFYjrBdI2K3BaJjJYfYFeRtM0t9ssnRuxw=="],
|
|
414
|
+
|
|
336
415
|
"esbuild": ["esbuild@0.27.2", "", { "optionalDependencies": { "@esbuild/aix-ppc64": "0.27.2", "@esbuild/android-arm": "0.27.2", "@esbuild/android-arm64": "0.27.2", "@esbuild/android-x64": "0.27.2", "@esbuild/darwin-arm64": "0.27.2", "@esbuild/darwin-x64": "0.27.2", "@esbuild/freebsd-arm64": "0.27.2", "@esbuild/freebsd-x64": "0.27.2", "@esbuild/linux-arm": "0.27.2", "@esbuild/linux-arm64": "0.27.2", "@esbuild/linux-ia32": "0.27.2", "@esbuild/linux-loong64": "0.27.2", "@esbuild/linux-mips64el": "0.27.2", "@esbuild/linux-ppc64": "0.27.2", "@esbuild/linux-riscv64": "0.27.2", "@esbuild/linux-s390x": "0.27.2", "@esbuild/linux-x64": "0.27.2", "@esbuild/netbsd-arm64": "0.27.2", "@esbuild/netbsd-x64": "0.27.2", "@esbuild/openbsd-arm64": "0.27.2", "@esbuild/openbsd-x64": "0.27.2", "@esbuild/openharmony-arm64": "0.27.2", "@esbuild/sunos-x64": "0.27.2", "@esbuild/win32-arm64": "0.27.2", "@esbuild/win32-ia32": "0.27.2", "@esbuild/win32-x64": "0.27.2" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-HyNQImnsOC7X9PMNaCIeAm4ISCQXs5a5YasTXVliKv4uuBo1dKrG0A+uQS8M5eXjVMnLg3WgXaKvprHlFJQffw=="],
|
|
337
416
|
|
|
338
417
|
"escape-string-regexp": ["escape-string-regexp@2.0.0", "", {}, "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w=="],
|
|
@@ -343,8 +422,12 @@
|
|
|
343
422
|
|
|
344
423
|
"estraverse": ["estraverse@5.3.0", "", {}, "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA=="],
|
|
345
424
|
|
|
425
|
+
"estree-walker": ["estree-walker@3.0.3", "", { "dependencies": { "@types/estree": "^1.0.0" } }, "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g=="],
|
|
426
|
+
|
|
346
427
|
"esutils": ["esutils@2.0.3", "", {}, "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g=="],
|
|
347
428
|
|
|
429
|
+
"expect-type": ["expect-type@1.3.0", "", {}, "sha512-knvyeauYhqjOYvQ66MznSMs83wmHrCycNEN6Ao+2AeYEfxUIkuiVxdEa1qlGEPK+We3n0THiDciYSsCcgW/DoA=="],
|
|
430
|
+
|
|
348
431
|
"extend": ["extend@3.0.2", "", {}, "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g=="],
|
|
349
432
|
|
|
350
433
|
"fast-deep-equal": ["fast-deep-equal@3.1.3", "", {}, "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q=="],
|
|
@@ -353,6 +436,8 @@
|
|
|
353
436
|
|
|
354
437
|
"fast-xml-parser": ["fast-xml-parser@5.2.5", "", { "dependencies": { "strnum": "2.1.2" }, "bin": { "fxparser": "src/cli/cli.js" } }, "sha512-pfX9uG9Ki0yekDHx2SiuRIyFdyAr1kMIMitPvb0YBo8SUfKvia7w7FIyd/l6av85pFYRhZscS75MwMnbvY+hcQ=="],
|
|
355
438
|
|
|
439
|
+
"fdir": ["fdir@6.5.0", "", { "peerDependencies": { "picomatch": "^3 || ^4" }, "optionalPeers": ["picomatch"] }, "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg=="],
|
|
440
|
+
|
|
356
441
|
"fetch-blob": ["fetch-blob@3.2.0", "", { "dependencies": { "node-domexception": "1.0.0", "web-streams-polyfill": "3.3.3" } }, "sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ=="],
|
|
357
442
|
|
|
358
443
|
"figures": ["figures@5.0.0", "", { "dependencies": { "escape-string-regexp": "5.0.0", "is-unicode-supported": "1.3.0" } }, "sha512-ej8ksPF4x6e5wvK9yevct0UCXh8TTFlWGVLlgjZuoBH1HwjIfKE/IdL5mq89sFA7zELi1VhKpmtDnrs7zWyeyg=="],
|
|
@@ -419,6 +504,30 @@
|
|
|
419
504
|
|
|
420
505
|
"jws": ["jws@4.0.1", "", { "dependencies": { "jwa": "2.0.1", "safe-buffer": "5.2.1" } }, "sha512-EKI/M/yqPncGUUh44xz0PxSidXFr/+r0pA70+gIYhjv+et7yxM+s29Y+VGDkovRofQem0fs7Uvf4+YmAdyRduA=="],
|
|
421
506
|
|
|
507
|
+
"lightningcss": ["lightningcss@1.32.0", "", { "dependencies": { "detect-libc": "^2.0.3" }, "optionalDependencies": { "lightningcss-android-arm64": "1.32.0", "lightningcss-darwin-arm64": "1.32.0", "lightningcss-darwin-x64": "1.32.0", "lightningcss-freebsd-x64": "1.32.0", "lightningcss-linux-arm-gnueabihf": "1.32.0", "lightningcss-linux-arm64-gnu": "1.32.0", "lightningcss-linux-arm64-musl": "1.32.0", "lightningcss-linux-x64-gnu": "1.32.0", "lightningcss-linux-x64-musl": "1.32.0", "lightningcss-win32-arm64-msvc": "1.32.0", "lightningcss-win32-x64-msvc": "1.32.0" } }, "sha512-NXYBzinNrblfraPGyrbPoD19C1h9lfI/1mzgWYvXUTe414Gz/X1FD2XBZSZM7rRTrMA8JL3OtAaGifrIKhQ5yQ=="],
|
|
508
|
+
|
|
509
|
+
"lightningcss-android-arm64": ["lightningcss-android-arm64@1.32.0", "", { "os": "android", "cpu": "arm64" }, "sha512-YK7/ClTt4kAK0vo6w3X+Pnm0D2cf2vPHbhOXdoNti1Ga0al1P4TBZhwjATvjNwLEBCnKvjJc2jQgHXH0NEwlAg=="],
|
|
510
|
+
|
|
511
|
+
"lightningcss-darwin-arm64": ["lightningcss-darwin-arm64@1.32.0", "", { "os": "darwin", "cpu": "arm64" }, "sha512-RzeG9Ju5bag2Bv1/lwlVJvBE3q6TtXskdZLLCyfg5pt+HLz9BqlICO7LZM7VHNTTn/5PRhHFBSjk5lc4cmscPQ=="],
|
|
512
|
+
|
|
513
|
+
"lightningcss-darwin-x64": ["lightningcss-darwin-x64@1.32.0", "", { "os": "darwin", "cpu": "x64" }, "sha512-U+QsBp2m/s2wqpUYT/6wnlagdZbtZdndSmut/NJqlCcMLTWp5muCrID+K5UJ6jqD2BFshejCYXniPDbNh73V8w=="],
|
|
514
|
+
|
|
515
|
+
"lightningcss-freebsd-x64": ["lightningcss-freebsd-x64@1.32.0", "", { "os": "freebsd", "cpu": "x64" }, "sha512-JCTigedEksZk3tHTTthnMdVfGf61Fky8Ji2E4YjUTEQX14xiy/lTzXnu1vwiZe3bYe0q+SpsSH/CTeDXK6WHig=="],
|
|
516
|
+
|
|
517
|
+
"lightningcss-linux-arm-gnueabihf": ["lightningcss-linux-arm-gnueabihf@1.32.0", "", { "os": "linux", "cpu": "arm" }, "sha512-x6rnnpRa2GL0zQOkt6rts3YDPzduLpWvwAF6EMhXFVZXD4tPrBkEFqzGowzCsIWsPjqSK+tyNEODUBXeeVHSkw=="],
|
|
518
|
+
|
|
519
|
+
"lightningcss-linux-arm64-gnu": ["lightningcss-linux-arm64-gnu@1.32.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-0nnMyoyOLRJXfbMOilaSRcLH3Jw5z9HDNGfT/gwCPgaDjnx0i8w7vBzFLFR1f6CMLKF8gVbebmkUN3fa/kQJpQ=="],
|
|
520
|
+
|
|
521
|
+
"lightningcss-linux-arm64-musl": ["lightningcss-linux-arm64-musl@1.32.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-UpQkoenr4UJEzgVIYpI80lDFvRmPVg6oqboNHfoH4CQIfNA+HOrZ7Mo7KZP02dC6LjghPQJeBsvXhJod/wnIBg=="],
|
|
522
|
+
|
|
523
|
+
"lightningcss-linux-x64-gnu": ["lightningcss-linux-x64-gnu@1.32.0", "", { "os": "linux", "cpu": "x64" }, "sha512-V7Qr52IhZmdKPVr+Vtw8o+WLsQJYCTd8loIfpDaMRWGUZfBOYEJeyJIkqGIDMZPwPx24pUMfwSxxI8phr/MbOA=="],
|
|
524
|
+
|
|
525
|
+
"lightningcss-linux-x64-musl": ["lightningcss-linux-x64-musl@1.32.0", "", { "os": "linux", "cpu": "x64" }, "sha512-bYcLp+Vb0awsiXg/80uCRezCYHNg1/l3mt0gzHnWV9XP1W5sKa5/TCdGWaR/zBM2PeF/HbsQv/j2URNOiVuxWg=="],
|
|
526
|
+
|
|
527
|
+
"lightningcss-win32-arm64-msvc": ["lightningcss-win32-arm64-msvc@1.32.0", "", { "os": "win32", "cpu": "arm64" }, "sha512-8SbC8BR40pS6baCM8sbtYDSwEVQd4JlFTOlaD3gWGHfThTcABnNDBda6eTZeqbofalIJhFx0qKzgHJmcPTnGdw=="],
|
|
528
|
+
|
|
529
|
+
"lightningcss-win32-x64-msvc": ["lightningcss-win32-x64-msvc@1.32.0", "", { "os": "win32", "cpu": "x64" }, "sha512-Amq9B/SoZYdDi1kFrojnoqPLxYhQ4Wo5XiL8EVJrVsB8ARoC1PWW6VGtT0WKCemjy8aC+louJnjS7U18x3b06Q=="],
|
|
530
|
+
|
|
422
531
|
"lodash": ["lodash@4.17.23", "", {}, "sha512-LgVTMpQtIopCi79SJeDiP0TfWi5CNEc/L/aRdTh3yIvmZXTnheWpKjSZhnvMl8iXbC1tFg9gdHHDMLoV7CnG+w=="],
|
|
423
532
|
|
|
424
533
|
"lodash.isequal": ["lodash.isequal@4.5.0", "", {}, "sha512-pDo3lu8Jhfjqls6GkMgpahsF9kCyayhgykjyLMNFTKWrpVdAQtYyB4muAMWozBB4ig/dtWAmsMxLEI8wuz+DYQ=="],
|
|
@@ -427,6 +536,8 @@
|
|
|
427
536
|
|
|
428
537
|
"lru-cache": ["lru-cache@7.18.3", "", {}, "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA=="],
|
|
429
538
|
|
|
539
|
+
"magic-string": ["magic-string@0.30.21", "", { "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.5" } }, "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ=="],
|
|
540
|
+
|
|
430
541
|
"marked": ["marked@15.0.12", "", { "bin": { "marked": "bin/marked.js" } }, "sha512-8dD6FusOQSrpv9Z1rdNMdlSgQOIP880DHqnohobOmYLElGEqAL/JvxvuxZO16r4HtjTlfPRDC1hbvxC9dPN2nA=="],
|
|
431
542
|
|
|
432
543
|
"mime-db": ["mime-db@1.54.0", "", {}, "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ=="],
|
|
@@ -441,12 +552,16 @@
|
|
|
441
552
|
|
|
442
553
|
"ms": ["ms@2.1.3", "", {}, "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="],
|
|
443
554
|
|
|
555
|
+
"nanoid": ["nanoid@3.3.11", "", { "bin": { "nanoid": "bin/nanoid.cjs" } }, "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w=="],
|
|
556
|
+
|
|
444
557
|
"netmask": ["netmask@2.0.2", "", {}, "sha512-dBpDMdxv9Irdq66304OLfEmQ9tbNRFnFTuZiLo+bD+r332bBmMJ8GBLXklIXXgxd3+v9+KUnZaUR5PJMa75Gsg=="],
|
|
445
558
|
|
|
446
559
|
"node-domexception": ["node-domexception@1.0.0", "", {}, "sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ=="],
|
|
447
560
|
|
|
448
561
|
"node-fetch": ["node-fetch@3.3.2", "", { "dependencies": { "data-uri-to-buffer": "4.0.1", "fetch-blob": "3.2.0", "formdata-polyfill": "4.0.10" } }, "sha512-dRB78srN/l6gqWulah9SrxeYnxeddIG30+GOqK/9OlLVyLg3HPnr6SqOWTWOXKRwC2eGYCkZ59NNuSgvSrpgOA=="],
|
|
449
562
|
|
|
563
|
+
"obug": ["obug@2.1.1", "", {}, "sha512-uTqF9MuPraAQ+IsnPf366RG4cP9RtUi7MLO1N3KEc+wb0a6yKpeL0lmk2IB1jY5KHPAlTc6T/JRdC/YqxHNwkQ=="],
|
|
564
|
+
|
|
450
565
|
"onetime": ["onetime@5.1.2", "", { "dependencies": { "mimic-fn": "2.1.0" } }, "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg=="],
|
|
451
566
|
|
|
452
567
|
"openai": ["openai@6.10.0", "", { "optionalDependencies": { "ws": "8.19.0", "zod": "3.25.76" }, "bin": { "openai": "bin/cli" } }, "sha512-ITxOGo7rO3XRMiKA5l7tQ43iNNu+iXGFAcf2t+aWVzzqRaS0i7m1K2BhxNdaveB+5eENhO0VY1FkiZzhBk4v3A=="],
|
|
@@ -465,6 +580,14 @@
|
|
|
465
580
|
|
|
466
581
|
"path-scurry": ["path-scurry@1.11.1", "", { "dependencies": { "lru-cache": "10.4.3", "minipass": "7.1.2" } }, "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA=="],
|
|
467
582
|
|
|
583
|
+
"pathe": ["pathe@2.0.3", "", {}, "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w=="],
|
|
584
|
+
|
|
585
|
+
"picocolors": ["picocolors@1.1.1", "", {}, "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA=="],
|
|
586
|
+
|
|
587
|
+
"picomatch": ["picomatch@4.0.4", "", {}, "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A=="],
|
|
588
|
+
|
|
589
|
+
"postcss": ["postcss@8.5.9", "", { "dependencies": { "nanoid": "^3.3.11", "picocolors": "^1.1.1", "source-map-js": "^1.2.1" } }, "sha512-7a70Nsot+EMX9fFU3064K/kdHWZqGVY+BADLyXc8Dfv+mTLLVl6JzJpPaCZ2kQL9gIJvKXSLMHhqdRRjwQeFtw=="],
|
|
590
|
+
|
|
468
591
|
"proxy-agent": ["proxy-agent@6.5.0", "", { "dependencies": { "agent-base": "7.1.4", "debug": "4.4.3", "http-proxy-agent": "7.0.2", "https-proxy-agent": "7.0.6", "lru-cache": "7.18.3", "pac-proxy-agent": "7.2.0", "proxy-from-env": "1.1.0", "socks-proxy-agent": "8.0.5" } }, "sha512-TmatMXdr2KlRiA2CyDu8GqR8EjahTG3aY3nXjdzFyoZbmB8hrBsTyMezhULIXKnC0jpfjlmiZ3+EaCzoInSu/A=="],
|
|
469
592
|
|
|
470
593
|
"proxy-from-env": ["proxy-from-env@1.1.0", "", {}, "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg=="],
|
|
@@ -483,6 +606,8 @@
|
|
|
483
606
|
|
|
484
607
|
"rimraf": ["rimraf@5.0.10", "", { "dependencies": { "glob": "10.5.0" }, "bin": { "rimraf": "dist/esm/bin.mjs" } }, "sha512-l0OE8wL34P4nJH/H2ffoaniAokM2qSmrtXHmlpvYr5AVVX8msAyW0l8NVJFDxlSK4u3Uh/f41cQheDVdnYijwQ=="],
|
|
485
608
|
|
|
609
|
+
"rolldown": ["rolldown@1.0.0-rc.13", "", { "dependencies": { "@oxc-project/types": "=0.123.0", "@rolldown/pluginutils": "1.0.0-rc.13" }, "optionalDependencies": { "@rolldown/binding-android-arm64": "1.0.0-rc.13", "@rolldown/binding-darwin-arm64": "1.0.0-rc.13", "@rolldown/binding-darwin-x64": "1.0.0-rc.13", "@rolldown/binding-freebsd-x64": "1.0.0-rc.13", "@rolldown/binding-linux-arm-gnueabihf": "1.0.0-rc.13", "@rolldown/binding-linux-arm64-gnu": "1.0.0-rc.13", "@rolldown/binding-linux-arm64-musl": "1.0.0-rc.13", "@rolldown/binding-linux-ppc64-gnu": "1.0.0-rc.13", "@rolldown/binding-linux-s390x-gnu": "1.0.0-rc.13", "@rolldown/binding-linux-x64-gnu": "1.0.0-rc.13", "@rolldown/binding-linux-x64-musl": "1.0.0-rc.13", "@rolldown/binding-openharmony-arm64": "1.0.0-rc.13", "@rolldown/binding-wasm32-wasi": "1.0.0-rc.13", "@rolldown/binding-win32-arm64-msvc": "1.0.0-rc.13", "@rolldown/binding-win32-x64-msvc": "1.0.0-rc.13" }, "bin": { "rolldown": "bin/cli.mjs" } }, "sha512-bvVj8YJmf0rq4pSFmH7laLa6pYrhghv3PRzrCdRAr23g66zOKVJ4wkvFtgohtPLWmthgg8/rkaqRHrpUEh0Zbw=="],
|
|
610
|
+
|
|
486
611
|
"safe-buffer": ["safe-buffer@5.2.1", "", {}, "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ=="],
|
|
487
612
|
|
|
488
613
|
"scheduler": ["scheduler@0.23.2", "", { "dependencies": { "loose-envify": "1.4.0" } }, "sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ=="],
|
|
@@ -491,6 +616,8 @@
|
|
|
491
616
|
|
|
492
617
|
"shebang-regex": ["shebang-regex@3.0.0", "", {}, "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A=="],
|
|
493
618
|
|
|
619
|
+
"siginfo": ["siginfo@2.0.0", "", {}, "sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g=="],
|
|
620
|
+
|
|
494
621
|
"signal-exit": ["signal-exit@3.0.7", "", {}, "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ=="],
|
|
495
622
|
|
|
496
623
|
"slice-ansi": ["slice-ansi@6.0.0", "", { "dependencies": { "ansi-styles": "6.2.3", "is-fullwidth-code-point": "4.0.0" } }, "sha512-6bn4hRfkTvDfUoEQYkERg0BVF1D0vrX9HEkMl08uDiNWvVvjylLHvZFZWkDo6wjT8tUctbYl1nCOuE66ZTaUtA=="],
|
|
@@ -503,8 +630,14 @@
|
|
|
503
630
|
|
|
504
631
|
"source-map": ["source-map@0.6.1", "", {}, "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g=="],
|
|
505
632
|
|
|
633
|
+
"source-map-js": ["source-map-js@1.2.1", "", {}, "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA=="],
|
|
634
|
+
|
|
506
635
|
"stack-utils": ["stack-utils@2.0.6", "", { "dependencies": { "escape-string-regexp": "2.0.0" } }, "sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ=="],
|
|
507
636
|
|
|
637
|
+
"stackback": ["stackback@0.0.2", "", {}, "sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw=="],
|
|
638
|
+
|
|
639
|
+
"std-env": ["std-env@4.0.0", "", {}, "sha512-zUMPtQ/HBY3/50VbpkupYHbRroTRZJPRLvreamgErJVys0ceuzMkD44J/QjqhHjOzK42GQ3QZIeFG1OYfOtKqQ=="],
|
|
640
|
+
|
|
508
641
|
"string-width": ["string-width@5.1.2", "", { "dependencies": { "eastasianwidth": "0.2.0", "emoji-regex": "9.2.2", "strip-ansi": "7.1.2" } }, "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA=="],
|
|
509
642
|
|
|
510
643
|
"string-width-cjs": ["string-width@4.2.3", "", { "dependencies": { "emoji-regex": "8.0.0", "is-fullwidth-code-point": "3.0.0", "strip-ansi": "6.0.1" } }, "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g=="],
|
|
@@ -515,6 +648,14 @@
|
|
|
515
648
|
|
|
516
649
|
"strnum": ["strnum@2.1.2", "", {}, "sha512-l63NF9y/cLROq/yqKXSLtcMeeyOfnSQlfMSlzFt/K73oIaD8DGaQWd7Z34X9GPiKqP5rbSh84Hl4bOlLcjiSrQ=="],
|
|
517
650
|
|
|
651
|
+
"tinybench": ["tinybench@2.9.0", "", {}, "sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg=="],
|
|
652
|
+
|
|
653
|
+
"tinyexec": ["tinyexec@1.1.1", "", {}, "sha512-VKS/ZaQhhkKFMANmAOhhXVoIfBXblQxGX1myCQ2faQrfmobMftXeJPcZGp0gS07ocvGJWDLZGyOZDadDBqYIJg=="],
|
|
654
|
+
|
|
655
|
+
"tinyglobby": ["tinyglobby@0.2.16", "", { "dependencies": { "fdir": "^6.5.0", "picomatch": "^4.0.4" } }, "sha512-pn99VhoACYR8nFHhxqix+uvsbXineAasWm5ojXoN8xEwK5Kd3/TrhNn1wByuD52UxWRLy8pu+kRMniEi6Eq9Zg=="],
|
|
656
|
+
|
|
657
|
+
"tinyrainbow": ["tinyrainbow@3.1.0", "", {}, "sha512-Bf+ILmBgretUrdJxzXM0SgXLZ3XfiaUuOj/IKQHuTXip+05Xn+uyEYdVg0kYDipTBcLrCVyUzAPz7QmArb0mmw=="],
|
|
658
|
+
|
|
518
659
|
"ts-algebra": ["ts-algebra@2.0.0", "", {}, "sha512-FPAhNPFMrkwz76P7cdjdmiShwMynZYN6SgOujD1urY4oNm80Ou9oMdmbR45LotcKOXoy7wSmHkRFE6Mxbrhefw=="],
|
|
519
660
|
|
|
520
661
|
"tslib": ["tslib@2.8.1", "", {}, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="],
|
|
@@ -529,10 +670,16 @@
|
|
|
529
670
|
|
|
530
671
|
"undici-types": ["undici-types@6.21.0", "", {}, "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ=="],
|
|
531
672
|
|
|
673
|
+
"vite": ["vite@8.0.7", "", { "dependencies": { "lightningcss": "^1.32.0", "picomatch": "^4.0.4", "postcss": "^8.5.8", "rolldown": "1.0.0-rc.13", "tinyglobby": "^0.2.15" }, "optionalDependencies": { "fsevents": "~2.3.3" }, "peerDependencies": { "@types/node": "^20.19.0 || >=22.12.0", "@vitejs/devtools": "^0.1.0", "esbuild": "^0.27.0 || ^0.28.0", "jiti": ">=1.21.0", "less": "^4.0.0", "sass": "^1.70.0", "sass-embedded": "^1.70.0", "stylus": ">=0.54.8", "sugarss": "^5.0.0", "terser": "^5.16.0", "tsx": "^4.8.1", "yaml": "^2.4.2" }, "optionalPeers": ["@types/node", "@vitejs/devtools", "esbuild", "jiti", "less", "sass", "sass-embedded", "stylus", "sugarss", "terser", "tsx", "yaml"], "bin": { "vite": "bin/vite.js" } }, "sha512-P1PbweD+2/udplnThz3btF4cf6AgPky7kk23RtHUkJIU5BIxwPprhRGmOAHs6FTI7UiGbTNrgNP6jSYD6JaRnw=="],
|
|
674
|
+
|
|
675
|
+
"vitest": ["vitest@4.1.3", "", { "dependencies": { "@vitest/expect": "4.1.3", "@vitest/mocker": "4.1.3", "@vitest/pretty-format": "4.1.3", "@vitest/runner": "4.1.3", "@vitest/snapshot": "4.1.3", "@vitest/spy": "4.1.3", "@vitest/utils": "4.1.3", "es-module-lexer": "^2.0.0", "expect-type": "^1.3.0", "magic-string": "^0.30.21", "obug": "^2.1.1", "pathe": "^2.0.3", "picomatch": "^4.0.3", "std-env": "^4.0.0-rc.1", "tinybench": "^2.9.0", "tinyexec": "^1.0.2", "tinyglobby": "^0.2.15", "tinyrainbow": "^3.1.0", "vite": "^6.0.0 || ^7.0.0 || ^8.0.0", "why-is-node-running": "^2.3.0" }, "peerDependencies": { "@edge-runtime/vm": "*", "@opentelemetry/api": "^1.9.0", "@types/node": "^20.0.0 || ^22.0.0 || >=24.0.0", "@vitest/browser-playwright": "4.1.3", "@vitest/browser-preview": "4.1.3", "@vitest/browser-webdriverio": "4.1.3", "@vitest/coverage-istanbul": "4.1.3", "@vitest/coverage-v8": "4.1.3", "@vitest/ui": "4.1.3", "happy-dom": "*", "jsdom": "*" }, "optionalPeers": ["@edge-runtime/vm", "@opentelemetry/api", "@types/node", "@vitest/browser-playwright", "@vitest/browser-preview", "@vitest/browser-webdriverio", "@vitest/coverage-istanbul", "@vitest/coverage-v8", "@vitest/ui", "happy-dom", "jsdom"], "bin": { "vitest": "vitest.mjs" } }, "sha512-DBc4Tx0MPNsqb9isoyOq00lHftVx/KIU44QOm2q59npZyLUkENn8TMFsuzuO+4U2FUa9rgbbPt3udrP25GcjXw=="],
|
|
676
|
+
|
|
532
677
|
"web-streams-polyfill": ["web-streams-polyfill@3.3.3", "", {}, "sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw=="],
|
|
533
678
|
|
|
534
679
|
"which": ["which@2.0.2", "", { "dependencies": { "isexe": "2.0.0" }, "bin": { "node-which": "./bin/node-which" } }, "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA=="],
|
|
535
680
|
|
|
681
|
+
"why-is-node-running": ["why-is-node-running@2.3.0", "", { "dependencies": { "siginfo": "^2.0.0", "stackback": "0.0.2" }, "bin": { "why-is-node-running": "cli.js" } }, "sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w=="],
|
|
682
|
+
|
|
536
683
|
"widest-line": ["widest-line@4.0.1", "", { "dependencies": { "string-width": "5.1.2" } }, "sha512-o0cyEG0e8GPzT4iGHphIOh0cJOV8fivsXxddQasHPHfoZf1ZexrfeA21w2NaEN1RHE+fXlfISmOE8R9N3u3Qig=="],
|
|
537
684
|
|
|
538
685
|
"wrap-ansi": ["wrap-ansi@8.1.0", "", { "dependencies": { "ansi-styles": "6.2.3", "string-width": "5.1.2", "strip-ansi": "7.1.2" } }, "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ=="],
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import { describe, it, expect } from "vitest";
|
|
2
|
+
import { execFile } from "node:child_process";
|
|
3
|
+
import { join, dirname } from "node:path";
|
|
4
|
+
import { fileURLToPath } from "node:url";
|
|
5
|
+
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
6
|
+
const CLI_PATH = join(__dirname, "..", "..", "dist", "cli.js");
|
|
7
|
+
function runCli(args = [], stdin) {
|
|
8
|
+
return new Promise((resolve) => {
|
|
9
|
+
const child = execFile("node", [CLI_PATH, ...args], {
|
|
10
|
+
timeout: 10000,
|
|
11
|
+
env: { ...process.env, HOME: "/tmp/amiko-cli-test" },
|
|
12
|
+
}, (error, stdout, stderr) => {
|
|
13
|
+
resolve({
|
|
14
|
+
stdout: stdout || "",
|
|
15
|
+
stderr: stderr || "",
|
|
16
|
+
code: error?.code === "ETIMEDOUT" ? 0 : error?.status ?? 0,
|
|
17
|
+
});
|
|
18
|
+
});
|
|
19
|
+
if (stdin !== undefined) {
|
|
20
|
+
child.stdin?.write(stdin);
|
|
21
|
+
}
|
|
22
|
+
child.stdin?.end();
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
describe("amiko-cli non-TTY behavior", () => {
|
|
26
|
+
it("does not crash with RangeError in piped mode", async () => {
|
|
27
|
+
const result = await runCli();
|
|
28
|
+
const combined = result.stdout + result.stderr;
|
|
29
|
+
expect(combined).not.toContain("RangeError");
|
|
30
|
+
expect(combined).not.toContain("Invalid count value");
|
|
31
|
+
});
|
|
32
|
+
it("enters headless mode when stdin is not a TTY", async () => {
|
|
33
|
+
const result = await runCli([], "/help\n");
|
|
34
|
+
const combined = result.stdout + result.stderr;
|
|
35
|
+
expect(combined).toContain("headless");
|
|
36
|
+
expect(combined).toContain("Commands:");
|
|
37
|
+
});
|
|
38
|
+
it("--headless flag is recognized", async () => {
|
|
39
|
+
const result = await runCli(["--headless"], "/help\n");
|
|
40
|
+
const combined = result.stdout + result.stderr;
|
|
41
|
+
expect(combined).toContain("headless");
|
|
42
|
+
expect(combined).toContain("Commands:");
|
|
43
|
+
});
|
|
44
|
+
it("headless /help lists available commands", async () => {
|
|
45
|
+
const result = await runCli([], "/help\n");
|
|
46
|
+
expect(result.stdout).toContain("/exit");
|
|
47
|
+
expect(result.stdout).toContain("/memory");
|
|
48
|
+
expect(result.stdout).toContain("/model");
|
|
49
|
+
expect(result.stdout).toContain("/search");
|
|
50
|
+
});
|
|
51
|
+
});
|
|
52
|
+
describe("String.repeat patch", () => {
|
|
53
|
+
it("clamps negative values to empty string", () => {
|
|
54
|
+
const origRepeat = String.prototype.repeat;
|
|
55
|
+
String.prototype.repeat = function (count) {
|
|
56
|
+
return origRepeat.call(this, Math.max(0, Math.floor(count)));
|
|
57
|
+
};
|
|
58
|
+
try {
|
|
59
|
+
expect("─".repeat(-2)).toBe("");
|
|
60
|
+
expect("─".repeat(-1)).toBe("");
|
|
61
|
+
expect("─".repeat(0)).toBe("");
|
|
62
|
+
expect("─".repeat(1)).toBe("─");
|
|
63
|
+
expect("─".repeat(3)).toBe("───");
|
|
64
|
+
expect("x".repeat(2.9)).toBe("xx");
|
|
65
|
+
}
|
|
66
|
+
finally {
|
|
67
|
+
String.prototype.repeat = origRepeat;
|
|
68
|
+
}
|
|
69
|
+
});
|
|
70
|
+
it("original String.repeat throws on negative values", () => {
|
|
71
|
+
expect(() => "x".repeat(-2)).toThrow(RangeError);
|
|
72
|
+
expect(() => "x".repeat(-1)).toThrow(RangeError);
|
|
73
|
+
});
|
|
74
|
+
});
|
package/dist/cli.js
CHANGED
|
@@ -6,11 +6,15 @@ import { initWorkspace } from "./workspace.js";
|
|
|
6
6
|
import { createSessionFile } from "./session.js";
|
|
7
7
|
import { App } from "./app.js";
|
|
8
8
|
import { loadConfigFile } from "./configFile.js";
|
|
9
|
+
import { runHeadless } from "./headless.js";
|
|
9
10
|
function parseArgs(argv) {
|
|
10
11
|
const overrides = {};
|
|
11
12
|
for (let i = 0; i < argv.length; i += 1) {
|
|
12
13
|
const arg = argv[i];
|
|
13
14
|
switch (arg) {
|
|
15
|
+
case "--headless":
|
|
16
|
+
overrides.headless = true;
|
|
17
|
+
break;
|
|
14
18
|
case "--workspace":
|
|
15
19
|
case "-w":
|
|
16
20
|
overrides.workspacePath = argv[i + 1];
|
|
@@ -61,44 +65,26 @@ function parseArgs(argv) {
|
|
|
61
65
|
return overrides;
|
|
62
66
|
}
|
|
63
67
|
async function main() {
|
|
64
|
-
|
|
65
|
-
//
|
|
66
|
-
//
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
console.log(" --workspace, -w <path> Workspace directory");
|
|
73
|
-
console.log(" --model <provider/model> Model override");
|
|
74
|
-
console.log(" --session <id> Resume session");
|
|
75
|
-
console.log(" --thinking <level> off|minimal|low|medium|high|xhigh");
|
|
76
|
-
process.exit(0);
|
|
77
|
-
}
|
|
78
|
-
if (flag === "-v" || flag === "--version") {
|
|
79
|
-
const { readFileSync } = await import("node:fs");
|
|
80
|
-
const { fileURLToPath } = await import("node:url");
|
|
81
|
-
const { dirname, join } = await import("node:path");
|
|
82
|
-
try {
|
|
83
|
-
const pkgPath = join(dirname(fileURLToPath(import.meta.url)), "..", "package.json");
|
|
84
|
-
const pkg = JSON.parse(readFileSync(pkgPath, "utf8"));
|
|
85
|
-
console.log(pkg.version);
|
|
86
|
-
}
|
|
87
|
-
catch {
|
|
88
|
-
console.log("unknown");
|
|
89
|
-
}
|
|
90
|
-
process.exit(0);
|
|
91
|
-
}
|
|
92
|
-
console.error("amiko-cli requires an interactive terminal (TTY). Cannot render UI in piped/non-TTY mode.");
|
|
93
|
-
process.exit(1);
|
|
94
|
-
}
|
|
68
|
+
// Ink's render-border.js calls box.top.repeat(contentWidth) where
|
|
69
|
+
// contentWidth = width - 2. When yoga computes a zero-width node (common
|
|
70
|
+
// in non-TTY / piped environments), contentWidth goes negative and
|
|
71
|
+
// String.repeat() throws. Patch String.repeat to clamp to 0.
|
|
72
|
+
const origRepeat = String.prototype.repeat;
|
|
73
|
+
String.prototype.repeat = function (count) {
|
|
74
|
+
return origRepeat.call(this, Math.max(0, Math.floor(count)));
|
|
75
|
+
};
|
|
95
76
|
const config = loadConfig();
|
|
96
|
-
const overrides = parseArgs(argv);
|
|
77
|
+
const overrides = parseArgs(process.argv.slice(2));
|
|
97
78
|
const finalConfig = { ...config, ...overrides };
|
|
98
79
|
const workspace = await initWorkspace(finalConfig.workspacePath);
|
|
99
80
|
const persisted = await loadConfigFile(workspace.root);
|
|
100
81
|
const mergedConfig = { ...finalConfig, ...persisted, ...overrides };
|
|
101
82
|
const sessionFile = await createSessionFile(workspace.sessionsDir, finalConfig.sessionId);
|
|
83
|
+
// Auto-detect non-TTY or explicit --headless flag
|
|
84
|
+
if (overrides.headless || !process.stdout.isTTY) {
|
|
85
|
+
await runHeadless(mergedConfig, workspace, sessionFile.path);
|
|
86
|
+
return;
|
|
87
|
+
}
|
|
102
88
|
render(_jsx(App, { config: mergedConfig, workspace: workspace, sessionPath: sessionFile.path }));
|
|
103
89
|
}
|
|
104
90
|
main().catch((error) => {
|
package/dist/headless.js
ADDED
|
@@ -0,0 +1,218 @@
|
|
|
1
|
+
import { createInterface } from "node:readline";
|
|
2
|
+
import { parseCommand } from "./commands.js";
|
|
3
|
+
import { buildPrompt } from "./prompt.js";
|
|
4
|
+
import { appendSession } from "./session.js";
|
|
5
|
+
import { readWorkspaceFiles } from "./workspace.js";
|
|
6
|
+
import { createPiAgent } from "./agent/piAgent.js";
|
|
7
|
+
import { qmdSearch, qmdGet, qmdCollectionAdd, qmdEmbed } from "./memory/qmd.js";
|
|
8
|
+
import { saveConfigFile } from "./configFile.js";
|
|
9
|
+
import { getModels, getProviders } from "@mariozechner/pi-ai";
|
|
10
|
+
export async function runHeadless(config, workspace, sessionPath) {
|
|
11
|
+
const agent = await createPiAgent(config);
|
|
12
|
+
let currentModel = config.model
|
|
13
|
+
?? (config.modelProvider && config.modelId ? `${config.modelProvider}/${config.modelId}` : "auto");
|
|
14
|
+
if (currentModel === "auto") {
|
|
15
|
+
const value = agent.getCurrentModel?.();
|
|
16
|
+
if (value)
|
|
17
|
+
currentModel = value;
|
|
18
|
+
}
|
|
19
|
+
if (agent.onEvent) {
|
|
20
|
+
agent.onEvent((event) => {
|
|
21
|
+
if (event?.type === "tool_execution_start") {
|
|
22
|
+
const lines = [`[tool] ${event.toolName} start`];
|
|
23
|
+
if (event.args?.command)
|
|
24
|
+
lines.push(` command: ${event.args.command}`);
|
|
25
|
+
console.log(lines.join("\n"));
|
|
26
|
+
}
|
|
27
|
+
if (event?.type === "tool_execution_end") {
|
|
28
|
+
const resultText = event.result?.content
|
|
29
|
+
? event.result.content.map((c) => (c.text ? c.text : "")).join("\n")
|
|
30
|
+
: "";
|
|
31
|
+
const summary = resultText.trim() || "(no output)";
|
|
32
|
+
console.log(`[tool] ${event.toolName} done\n${summary}`);
|
|
33
|
+
}
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
console.log(`amiko-cli (headless) | model: ${currentModel} | workspace: ${workspace.root}`);
|
|
37
|
+
console.log("Type a message or /command. Press Ctrl+D to exit.");
|
|
38
|
+
const rl = createInterface({
|
|
39
|
+
input: process.stdin,
|
|
40
|
+
output: process.stdout,
|
|
41
|
+
prompt: "> ",
|
|
42
|
+
terminal: false,
|
|
43
|
+
});
|
|
44
|
+
rl.prompt();
|
|
45
|
+
for await (const line of rl) {
|
|
46
|
+
const trimmed = line.trim();
|
|
47
|
+
if (!trimmed) {
|
|
48
|
+
rl.prompt();
|
|
49
|
+
continue;
|
|
50
|
+
}
|
|
51
|
+
const command = parseCommand(trimmed);
|
|
52
|
+
if (command) {
|
|
53
|
+
await handleCommand(command.name, command.args, {
|
|
54
|
+
config, workspace, sessionPath, agent, currentModel,
|
|
55
|
+
setModel: (m) => { currentModel = m; },
|
|
56
|
+
});
|
|
57
|
+
rl.prompt();
|
|
58
|
+
continue;
|
|
59
|
+
}
|
|
60
|
+
console.log(`[user] ${trimmed}`);
|
|
61
|
+
await appendSession(sessionPath, "user", trimmed);
|
|
62
|
+
const workspaceData = await readWorkspaceFiles(workspace);
|
|
63
|
+
let hits = [];
|
|
64
|
+
if (config.qmdEnabled) {
|
|
65
|
+
hits = await qmdSearch({
|
|
66
|
+
qmdBin: config.qmdBin,
|
|
67
|
+
query: trimmed,
|
|
68
|
+
limit: config.qmdLimit,
|
|
69
|
+
collection: config.qmdCollection,
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
if (config.qmdFull && hits.length > 0) {
|
|
73
|
+
const expanded = [];
|
|
74
|
+
for (const hit of hits) {
|
|
75
|
+
const docId = hit.path || hit.id;
|
|
76
|
+
if (!docId) {
|
|
77
|
+
expanded.push(hit);
|
|
78
|
+
continue;
|
|
79
|
+
}
|
|
80
|
+
const text = await qmdGet({ qmdBin: config.qmdBin, docId, full: true });
|
|
81
|
+
expanded.push({ ...hit, snippet: text || hit.snippet });
|
|
82
|
+
}
|
|
83
|
+
hits = expanded;
|
|
84
|
+
}
|
|
85
|
+
const prompt = buildPrompt({
|
|
86
|
+
identity: workspaceData.identity,
|
|
87
|
+
personality: workspaceData.personality,
|
|
88
|
+
memory: workspaceData.memory,
|
|
89
|
+
hits,
|
|
90
|
+
});
|
|
91
|
+
let assistantText = "";
|
|
92
|
+
try {
|
|
93
|
+
for await (const chunk of agent.streamReply({ prompt, userMessage: trimmed })) {
|
|
94
|
+
process.stdout.write(chunk);
|
|
95
|
+
assistantText += chunk;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
catch (error) {
|
|
99
|
+
const message = error.message || "unknown error";
|
|
100
|
+
assistantText += `\n[error] ${message}\n`;
|
|
101
|
+
console.error(`[error] ${message}`);
|
|
102
|
+
}
|
|
103
|
+
if (!assistantText.endsWith("\n"))
|
|
104
|
+
process.stdout.write("\n");
|
|
105
|
+
if (assistantText) {
|
|
106
|
+
await appendSession(sessionPath, "assistant", assistantText);
|
|
107
|
+
}
|
|
108
|
+
rl.prompt();
|
|
109
|
+
}
|
|
110
|
+
process.exit(0);
|
|
111
|
+
}
|
|
112
|
+
async function handleCommand(name, args, ctx) {
|
|
113
|
+
switch (name) {
|
|
114
|
+
case "exit":
|
|
115
|
+
process.exit(0);
|
|
116
|
+
case "help":
|
|
117
|
+
console.log("Commands: /help /exit /search <query> /memory /session /plan /identity /personality /index [collection] /model [provider[/id]]");
|
|
118
|
+
return;
|
|
119
|
+
case "memory": {
|
|
120
|
+
const data = await readWorkspaceFiles(ctx.workspace);
|
|
121
|
+
console.log(`MEMORY.md:\n\n${data.memory.trim() || "(empty)"}`);
|
|
122
|
+
return;
|
|
123
|
+
}
|
|
124
|
+
case "session":
|
|
125
|
+
console.log(`Session file: ${ctx.sessionPath}`);
|
|
126
|
+
return;
|
|
127
|
+
case "plan":
|
|
128
|
+
console.log("Plan file: PLAN.md");
|
|
129
|
+
return;
|
|
130
|
+
case "identity": {
|
|
131
|
+
const data = await readWorkspaceFiles(ctx.workspace);
|
|
132
|
+
console.log(`IDENTITY.md:\n\n${data.identity.trim() || "(empty)"}`);
|
|
133
|
+
return;
|
|
134
|
+
}
|
|
135
|
+
case "personality": {
|
|
136
|
+
const data = await readWorkspaceFiles(ctx.workspace);
|
|
137
|
+
console.log(`PERSONALITY.md:\n\n${data.personality.trim() || "(empty)"}`);
|
|
138
|
+
return;
|
|
139
|
+
}
|
|
140
|
+
case "index": {
|
|
141
|
+
if (!ctx.config.qmdEnabled) {
|
|
142
|
+
console.log("QMD is disabled.");
|
|
143
|
+
return;
|
|
144
|
+
}
|
|
145
|
+
const collName = args || ctx.config.qmdCollection || "amiko";
|
|
146
|
+
const added = await qmdCollectionAdd({ qmdBin: ctx.config.qmdBin, name: collName, path: ctx.workspace.root });
|
|
147
|
+
if (!added) {
|
|
148
|
+
console.log("Failed to add QMD collection.");
|
|
149
|
+
return;
|
|
150
|
+
}
|
|
151
|
+
const embedded = await qmdEmbed({ qmdBin: ctx.config.qmdBin, collection: collName });
|
|
152
|
+
console.log(embedded ? `Indexed QMD collection "${collName}".` : `Collection "${collName}" added, but embedding failed.`);
|
|
153
|
+
return;
|
|
154
|
+
}
|
|
155
|
+
case "search": {
|
|
156
|
+
if (!args) {
|
|
157
|
+
console.log("Usage: /search <query>");
|
|
158
|
+
return;
|
|
159
|
+
}
|
|
160
|
+
if (!ctx.config.qmdEnabled) {
|
|
161
|
+
console.log("QMD is disabled.");
|
|
162
|
+
return;
|
|
163
|
+
}
|
|
164
|
+
const hits = await qmdSearch({ qmdBin: ctx.config.qmdBin, query: args, limit: ctx.config.qmdLimit, collection: ctx.config.qmdCollection });
|
|
165
|
+
if (hits.length === 0) {
|
|
166
|
+
console.log("No memory hits.");
|
|
167
|
+
return;
|
|
168
|
+
}
|
|
169
|
+
const formatted = hits.map((hit, i) => {
|
|
170
|
+
const label = hit.title || hit.path || hit.id;
|
|
171
|
+
const score = hit.score ? ` (${hit.score.toFixed(2)})` : "";
|
|
172
|
+
return `${i + 1}. ${label}${score}`;
|
|
173
|
+
}).join("\n");
|
|
174
|
+
console.log(formatted);
|
|
175
|
+
return;
|
|
176
|
+
}
|
|
177
|
+
case "model": {
|
|
178
|
+
if (!args) {
|
|
179
|
+
const providers = getProviders().sort();
|
|
180
|
+
console.log(`Current model: ${ctx.currentModel}\nProviders:\n${providers.map((p, i) => ` ${i + 1}. ${p}`).join("\n")}`);
|
|
181
|
+
return;
|
|
182
|
+
}
|
|
183
|
+
const slashParts = args.includes("/") ? args.split("/") : [];
|
|
184
|
+
let provider = args.split(" ")[0];
|
|
185
|
+
let modelId = args.split(" ")[1];
|
|
186
|
+
if (slashParts.length >= 2) {
|
|
187
|
+
provider = slashParts[0]?.trim();
|
|
188
|
+
modelId = slashParts.slice(1).join("/").trim();
|
|
189
|
+
}
|
|
190
|
+
if (provider && !modelId) {
|
|
191
|
+
const models = getModels(provider);
|
|
192
|
+
if (models.length === 0) {
|
|
193
|
+
console.log(`Unknown provider: ${provider}`);
|
|
194
|
+
return;
|
|
195
|
+
}
|
|
196
|
+
console.log(`Models for ${provider}:\n${models.map((m) => m.id).sort().join("\n")}`);
|
|
197
|
+
return;
|
|
198
|
+
}
|
|
199
|
+
if (!provider || !modelId) {
|
|
200
|
+
console.log("Usage: /model <provider>/<modelId>");
|
|
201
|
+
return;
|
|
202
|
+
}
|
|
203
|
+
if (!ctx.agent.setModel) {
|
|
204
|
+
console.log("Agent does not support model switching.");
|
|
205
|
+
return;
|
|
206
|
+
}
|
|
207
|
+
const result = ctx.agent.setModel(provider, modelId);
|
|
208
|
+
console.log(result.message);
|
|
209
|
+
if (result.ok) {
|
|
210
|
+
ctx.setModel(`${provider}/${modelId}`);
|
|
211
|
+
await saveConfigFile(ctx.workspace.root, { model: `${provider}/${modelId}`, modelProvider: provider, modelId });
|
|
212
|
+
}
|
|
213
|
+
return;
|
|
214
|
+
}
|
|
215
|
+
default:
|
|
216
|
+
console.log(`Unknown command: ${name}`);
|
|
217
|
+
}
|
|
218
|
+
}
|
package/package.json
CHANGED
|
@@ -1,20 +1,22 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@heyamiko/amiko-cli",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.11",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"bin": {
|
|
6
6
|
"amiko": "dist/cli.js"
|
|
7
7
|
},
|
|
8
8
|
"scripts": {
|
|
9
9
|
"dev": "tsx src/cli.tsx",
|
|
10
|
-
"build": "tsc -p tsconfig.json"
|
|
10
|
+
"build": "tsc -p tsconfig.json",
|
|
11
|
+
"test": "vitest run",
|
|
12
|
+
"test:watch": "vitest"
|
|
11
13
|
},
|
|
12
14
|
"dependencies": {
|
|
13
15
|
"@mariozechner/pi-agent-core": "*",
|
|
14
16
|
"@mariozechner/pi-ai": "*",
|
|
17
|
+
"@sinclair/typebox": "^0.34.41",
|
|
15
18
|
"ink": "^4.4.1",
|
|
16
19
|
"ink-select-input": "^5.0.0",
|
|
17
|
-
"@sinclair/typebox": "^0.34.41",
|
|
18
20
|
"react": "^18.2.0",
|
|
19
21
|
"react-dom": "^18.2.0"
|
|
20
22
|
},
|
|
@@ -23,6 +25,7 @@
|
|
|
23
25
|
"@types/react": "^18.2.0",
|
|
24
26
|
"@types/react-dom": "^18.2.0",
|
|
25
27
|
"tsx": "^4.7.0",
|
|
26
|
-
"typescript": "^5.4.0"
|
|
28
|
+
"typescript": "^5.4.0",
|
|
29
|
+
"vitest": "^4.1.3"
|
|
27
30
|
}
|
|
28
31
|
}
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import { describe, it, expect } from "vitest";
|
|
2
|
+
import { execFile } from "node:child_process";
|
|
3
|
+
import { join, dirname } from "node:path";
|
|
4
|
+
import { fileURLToPath } from "node:url";
|
|
5
|
+
|
|
6
|
+
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
7
|
+
const CLI_PATH = join(__dirname, "..", "..", "dist", "cli.js");
|
|
8
|
+
|
|
9
|
+
function runCli(args: string[] = [], stdin?: string): Promise<{ stdout: string; stderr: string; code: number | null }> {
|
|
10
|
+
return new Promise((resolve) => {
|
|
11
|
+
const child = execFile("node", [CLI_PATH, ...args], {
|
|
12
|
+
timeout: 10000,
|
|
13
|
+
env: { ...process.env, HOME: "/tmp/amiko-cli-test" },
|
|
14
|
+
}, (error, stdout, stderr) => {
|
|
15
|
+
resolve({
|
|
16
|
+
stdout: stdout || "",
|
|
17
|
+
stderr: stderr || "",
|
|
18
|
+
code: error?.code === "ETIMEDOUT" ? 0 : (error as any)?.status ?? 0,
|
|
19
|
+
});
|
|
20
|
+
});
|
|
21
|
+
if (stdin !== undefined) {
|
|
22
|
+
child.stdin?.write(stdin);
|
|
23
|
+
}
|
|
24
|
+
child.stdin?.end();
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
describe("amiko-cli non-TTY behavior", () => {
|
|
29
|
+
it("does not crash with RangeError in piped mode", async () => {
|
|
30
|
+
const result = await runCli();
|
|
31
|
+
const combined = result.stdout + result.stderr;
|
|
32
|
+
|
|
33
|
+
expect(combined).not.toContain("RangeError");
|
|
34
|
+
expect(combined).not.toContain("Invalid count value");
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
it("enters headless mode when stdin is not a TTY", async () => {
|
|
38
|
+
const result = await runCli([], "/help\n");
|
|
39
|
+
const combined = result.stdout + result.stderr;
|
|
40
|
+
|
|
41
|
+
expect(combined).toContain("headless");
|
|
42
|
+
expect(combined).toContain("Commands:");
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
it("--headless flag is recognized", async () => {
|
|
46
|
+
const result = await runCli(["--headless"], "/help\n");
|
|
47
|
+
const combined = result.stdout + result.stderr;
|
|
48
|
+
|
|
49
|
+
expect(combined).toContain("headless");
|
|
50
|
+
expect(combined).toContain("Commands:");
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
it("headless /help lists available commands", async () => {
|
|
54
|
+
const result = await runCli([], "/help\n");
|
|
55
|
+
|
|
56
|
+
expect(result.stdout).toContain("/exit");
|
|
57
|
+
expect(result.stdout).toContain("/memory");
|
|
58
|
+
expect(result.stdout).toContain("/model");
|
|
59
|
+
expect(result.stdout).toContain("/search");
|
|
60
|
+
});
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
describe("String.repeat patch", () => {
|
|
64
|
+
it("clamps negative values to empty string", () => {
|
|
65
|
+
const origRepeat = String.prototype.repeat;
|
|
66
|
+
String.prototype.repeat = function (count: number) {
|
|
67
|
+
return origRepeat.call(this, Math.max(0, Math.floor(count)));
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
try {
|
|
71
|
+
expect("─".repeat(-2)).toBe("");
|
|
72
|
+
expect("─".repeat(-1)).toBe("");
|
|
73
|
+
expect("─".repeat(0)).toBe("");
|
|
74
|
+
expect("─".repeat(1)).toBe("─");
|
|
75
|
+
expect("─".repeat(3)).toBe("───");
|
|
76
|
+
expect("x".repeat(2.9)).toBe("xx");
|
|
77
|
+
} finally {
|
|
78
|
+
String.prototype.repeat = origRepeat;
|
|
79
|
+
}
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
it("original String.repeat throws on negative values", () => {
|
|
83
|
+
expect(() => "x".repeat(-2)).toThrow(RangeError);
|
|
84
|
+
expect(() => "x".repeat(-1)).toThrow(RangeError);
|
|
85
|
+
});
|
|
86
|
+
});
|
package/src/cli.tsx
CHANGED
|
@@ -6,6 +6,7 @@ import { initWorkspace } from "./workspace.js";
|
|
|
6
6
|
import { createSessionFile } from "./session.js";
|
|
7
7
|
import { App } from "./app.js";
|
|
8
8
|
import { loadConfigFile } from "./configFile.js";
|
|
9
|
+
import { runHeadless } from "./headless.js";
|
|
9
10
|
|
|
10
11
|
type ArgOverrides = Partial<{
|
|
11
12
|
workspacePath: string;
|
|
@@ -19,6 +20,7 @@ type ArgOverrides = Partial<{
|
|
|
19
20
|
modelProvider?: string;
|
|
20
21
|
modelId?: string;
|
|
21
22
|
thinkingLevel?: "off" | "minimal" | "low" | "medium" | "high" | "xhigh";
|
|
23
|
+
headless?: boolean;
|
|
22
24
|
}>;
|
|
23
25
|
|
|
24
26
|
function parseArgs(argv: string[]): ArgOverrides {
|
|
@@ -26,6 +28,9 @@ function parseArgs(argv: string[]): ArgOverrides {
|
|
|
26
28
|
for (let i = 0; i < argv.length; i += 1) {
|
|
27
29
|
const arg = argv[i];
|
|
28
30
|
switch (arg) {
|
|
31
|
+
case "--headless":
|
|
32
|
+
overrides.headless = true;
|
|
33
|
+
break;
|
|
29
34
|
case "--workspace":
|
|
30
35
|
case "-w":
|
|
31
36
|
overrides.workspacePath = argv[i + 1];
|
|
@@ -77,46 +82,29 @@ function parseArgs(argv: string[]): ArgOverrides {
|
|
|
77
82
|
}
|
|
78
83
|
|
|
79
84
|
async function main() {
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
//
|
|
83
|
-
//
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
console.log("Usage: amiko [options]");
|
|
89
|
-
console.log(" --workspace, -w <path> Workspace directory");
|
|
90
|
-
console.log(" --model <provider/model> Model override");
|
|
91
|
-
console.log(" --session <id> Resume session");
|
|
92
|
-
console.log(" --thinking <level> off|minimal|low|medium|high|xhigh");
|
|
93
|
-
process.exit(0);
|
|
94
|
-
}
|
|
95
|
-
if (flag === "-v" || flag === "--version") {
|
|
96
|
-
const { readFileSync } = await import("node:fs");
|
|
97
|
-
const { fileURLToPath } = await import("node:url");
|
|
98
|
-
const { dirname, join } = await import("node:path");
|
|
99
|
-
try {
|
|
100
|
-
const pkgPath = join(dirname(fileURLToPath(import.meta.url)), "..", "package.json");
|
|
101
|
-
const pkg = JSON.parse(readFileSync(pkgPath, "utf8"));
|
|
102
|
-
console.log(pkg.version);
|
|
103
|
-
} catch {
|
|
104
|
-
console.log("unknown");
|
|
105
|
-
}
|
|
106
|
-
process.exit(0);
|
|
107
|
-
}
|
|
108
|
-
console.error("amiko-cli requires an interactive terminal (TTY). Cannot render UI in piped/non-TTY mode.");
|
|
109
|
-
process.exit(1);
|
|
110
|
-
}
|
|
85
|
+
// Ink's render-border.js calls box.top.repeat(contentWidth) where
|
|
86
|
+
// contentWidth = width - 2. When yoga computes a zero-width node (common
|
|
87
|
+
// in non-TTY / piped environments), contentWidth goes negative and
|
|
88
|
+
// String.repeat() throws. Patch String.repeat to clamp to 0.
|
|
89
|
+
const origRepeat = String.prototype.repeat;
|
|
90
|
+
String.prototype.repeat = function (count: number) {
|
|
91
|
+
return origRepeat.call(this, Math.max(0, Math.floor(count)));
|
|
92
|
+
};
|
|
111
93
|
|
|
112
94
|
const config = loadConfig();
|
|
113
|
-
const overrides = parseArgs(argv);
|
|
95
|
+
const overrides = parseArgs(process.argv.slice(2));
|
|
114
96
|
const finalConfig = { ...config, ...overrides };
|
|
115
97
|
const workspace = await initWorkspace(finalConfig.workspacePath);
|
|
116
98
|
const persisted = await loadConfigFile(workspace.root);
|
|
117
99
|
const mergedConfig = { ...finalConfig, ...persisted, ...overrides };
|
|
118
100
|
const sessionFile = await createSessionFile(workspace.sessionsDir, finalConfig.sessionId);
|
|
119
101
|
|
|
102
|
+
// Auto-detect non-TTY or explicit --headless flag
|
|
103
|
+
if (overrides.headless || !process.stdout.isTTY) {
|
|
104
|
+
await runHeadless(mergedConfig, workspace, sessionFile.path);
|
|
105
|
+
return;
|
|
106
|
+
}
|
|
107
|
+
|
|
120
108
|
render(<App config={mergedConfig} workspace={workspace} sessionPath={sessionFile.path} />);
|
|
121
109
|
}
|
|
122
110
|
|
package/src/headless.ts
ADDED
|
@@ -0,0 +1,222 @@
|
|
|
1
|
+
import { createInterface } from "node:readline";
|
|
2
|
+
import { AppConfig, Message, MemoryHit } from "./types.js";
|
|
3
|
+
import { parseCommand } from "./commands.js";
|
|
4
|
+
import { buildPrompt } from "./prompt.js";
|
|
5
|
+
import { appendSession } from "./session.js";
|
|
6
|
+
import { readWorkspaceFiles, WorkspaceFiles } from "./workspace.js";
|
|
7
|
+
import { createPiAgent } from "./agent/piAgent.js";
|
|
8
|
+
import { qmdSearch, qmdGet, qmdCollectionAdd, qmdEmbed } from "./memory/qmd.js";
|
|
9
|
+
import { saveConfigFile } from "./configFile.js";
|
|
10
|
+
import { getModels, getProviders, type KnownProvider } from "@mariozechner/pi-ai";
|
|
11
|
+
|
|
12
|
+
export async function runHeadless(
|
|
13
|
+
config: AppConfig,
|
|
14
|
+
workspace: WorkspaceFiles,
|
|
15
|
+
sessionPath: string,
|
|
16
|
+
) {
|
|
17
|
+
const agent = await createPiAgent(config);
|
|
18
|
+
let currentModel = config.model
|
|
19
|
+
?? (config.modelProvider && config.modelId ? `${config.modelProvider}/${config.modelId}` : "auto");
|
|
20
|
+
|
|
21
|
+
if (currentModel === "auto") {
|
|
22
|
+
const value = agent.getCurrentModel?.();
|
|
23
|
+
if (value) currentModel = value;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
if (agent.onEvent) {
|
|
27
|
+
agent.onEvent((event) => {
|
|
28
|
+
if (event?.type === "tool_execution_start") {
|
|
29
|
+
const lines = [`[tool] ${event.toolName} start`];
|
|
30
|
+
if (event.args?.command) lines.push(` command: ${event.args.command}`);
|
|
31
|
+
console.log(lines.join("\n"));
|
|
32
|
+
}
|
|
33
|
+
if (event?.type === "tool_execution_end") {
|
|
34
|
+
const resultText = event.result?.content
|
|
35
|
+
? event.result.content.map((c: any) => (c.text ? c.text : "")).join("\n")
|
|
36
|
+
: "";
|
|
37
|
+
const summary = resultText.trim() || "(no output)";
|
|
38
|
+
console.log(`[tool] ${event.toolName} done\n${summary}`);
|
|
39
|
+
}
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
console.log(`amiko-cli (headless) | model: ${currentModel} | workspace: ${workspace.root}`);
|
|
44
|
+
console.log("Type a message or /command. Press Ctrl+D to exit.");
|
|
45
|
+
|
|
46
|
+
const rl = createInterface({
|
|
47
|
+
input: process.stdin,
|
|
48
|
+
output: process.stdout,
|
|
49
|
+
prompt: "> ",
|
|
50
|
+
terminal: false,
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
rl.prompt();
|
|
54
|
+
|
|
55
|
+
for await (const line of rl) {
|
|
56
|
+
const trimmed = line.trim();
|
|
57
|
+
if (!trimmed) {
|
|
58
|
+
rl.prompt();
|
|
59
|
+
continue;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
const command = parseCommand(trimmed);
|
|
63
|
+
if (command) {
|
|
64
|
+
await handleCommand(command.name, command.args, {
|
|
65
|
+
config, workspace, sessionPath, agent, currentModel,
|
|
66
|
+
setModel: (m: string) => { currentModel = m; },
|
|
67
|
+
});
|
|
68
|
+
rl.prompt();
|
|
69
|
+
continue;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
console.log(`[user] ${trimmed}`);
|
|
73
|
+
await appendSession(sessionPath, "user", trimmed);
|
|
74
|
+
|
|
75
|
+
const workspaceData = await readWorkspaceFiles(workspace);
|
|
76
|
+
|
|
77
|
+
let hits: MemoryHit[] = [];
|
|
78
|
+
if (config.qmdEnabled) {
|
|
79
|
+
hits = await qmdSearch({
|
|
80
|
+
qmdBin: config.qmdBin,
|
|
81
|
+
query: trimmed,
|
|
82
|
+
limit: config.qmdLimit,
|
|
83
|
+
collection: config.qmdCollection,
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
if (config.qmdFull && hits.length > 0) {
|
|
88
|
+
const expanded: MemoryHit[] = [];
|
|
89
|
+
for (const hit of hits) {
|
|
90
|
+
const docId = hit.path || hit.id;
|
|
91
|
+
if (!docId) { expanded.push(hit); continue; }
|
|
92
|
+
const text = await qmdGet({ qmdBin: config.qmdBin, docId, full: true });
|
|
93
|
+
expanded.push({ ...hit, snippet: text || hit.snippet });
|
|
94
|
+
}
|
|
95
|
+
hits = expanded;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
const prompt = buildPrompt({
|
|
99
|
+
identity: workspaceData.identity,
|
|
100
|
+
personality: workspaceData.personality,
|
|
101
|
+
memory: workspaceData.memory,
|
|
102
|
+
hits,
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
let assistantText = "";
|
|
106
|
+
try {
|
|
107
|
+
for await (const chunk of agent.streamReply({ prompt, userMessage: trimmed })) {
|
|
108
|
+
process.stdout.write(chunk);
|
|
109
|
+
assistantText += chunk;
|
|
110
|
+
}
|
|
111
|
+
} catch (error) {
|
|
112
|
+
const message = (error as Error).message || "unknown error";
|
|
113
|
+
assistantText += `\n[error] ${message}\n`;
|
|
114
|
+
console.error(`[error] ${message}`);
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
if (!assistantText.endsWith("\n")) process.stdout.write("\n");
|
|
118
|
+
|
|
119
|
+
if (assistantText) {
|
|
120
|
+
await appendSession(sessionPath, "assistant", assistantText);
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
rl.prompt();
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
process.exit(0);
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
async function handleCommand(
|
|
130
|
+
name: string,
|
|
131
|
+
args: string,
|
|
132
|
+
ctx: {
|
|
133
|
+
config: AppConfig;
|
|
134
|
+
workspace: WorkspaceFiles;
|
|
135
|
+
sessionPath: string;
|
|
136
|
+
agent: any;
|
|
137
|
+
currentModel: string;
|
|
138
|
+
setModel: (m: string) => void;
|
|
139
|
+
},
|
|
140
|
+
) {
|
|
141
|
+
switch (name) {
|
|
142
|
+
case "exit":
|
|
143
|
+
process.exit(0);
|
|
144
|
+
case "help":
|
|
145
|
+
console.log("Commands: /help /exit /search <query> /memory /session /plan /identity /personality /index [collection] /model [provider[/id]]");
|
|
146
|
+
return;
|
|
147
|
+
case "memory": {
|
|
148
|
+
const data = await readWorkspaceFiles(ctx.workspace);
|
|
149
|
+
console.log(`MEMORY.md:\n\n${data.memory.trim() || "(empty)"}`);
|
|
150
|
+
return;
|
|
151
|
+
}
|
|
152
|
+
case "session":
|
|
153
|
+
console.log(`Session file: ${ctx.sessionPath}`);
|
|
154
|
+
return;
|
|
155
|
+
case "plan":
|
|
156
|
+
console.log("Plan file: PLAN.md");
|
|
157
|
+
return;
|
|
158
|
+
case "identity": {
|
|
159
|
+
const data = await readWorkspaceFiles(ctx.workspace);
|
|
160
|
+
console.log(`IDENTITY.md:\n\n${data.identity.trim() || "(empty)"}`);
|
|
161
|
+
return;
|
|
162
|
+
}
|
|
163
|
+
case "personality": {
|
|
164
|
+
const data = await readWorkspaceFiles(ctx.workspace);
|
|
165
|
+
console.log(`PERSONALITY.md:\n\n${data.personality.trim() || "(empty)"}`);
|
|
166
|
+
return;
|
|
167
|
+
}
|
|
168
|
+
case "index": {
|
|
169
|
+
if (!ctx.config.qmdEnabled) { console.log("QMD is disabled."); return; }
|
|
170
|
+
const collName = args || ctx.config.qmdCollection || "amiko";
|
|
171
|
+
const added = await qmdCollectionAdd({ qmdBin: ctx.config.qmdBin, name: collName, path: ctx.workspace.root });
|
|
172
|
+
if (!added) { console.log("Failed to add QMD collection."); return; }
|
|
173
|
+
const embedded = await qmdEmbed({ qmdBin: ctx.config.qmdBin, collection: collName });
|
|
174
|
+
console.log(embedded ? `Indexed QMD collection "${collName}".` : `Collection "${collName}" added, but embedding failed.`);
|
|
175
|
+
return;
|
|
176
|
+
}
|
|
177
|
+
case "search": {
|
|
178
|
+
if (!args) { console.log("Usage: /search <query>"); return; }
|
|
179
|
+
if (!ctx.config.qmdEnabled) { console.log("QMD is disabled."); return; }
|
|
180
|
+
const hits = await qmdSearch({ qmdBin: ctx.config.qmdBin, query: args, limit: ctx.config.qmdLimit, collection: ctx.config.qmdCollection });
|
|
181
|
+
if (hits.length === 0) { console.log("No memory hits."); return; }
|
|
182
|
+
const formatted = hits.map((hit, i) => {
|
|
183
|
+
const label = hit.title || hit.path || hit.id;
|
|
184
|
+
const score = hit.score ? ` (${hit.score.toFixed(2)})` : "";
|
|
185
|
+
return `${i + 1}. ${label}${score}`;
|
|
186
|
+
}).join("\n");
|
|
187
|
+
console.log(formatted);
|
|
188
|
+
return;
|
|
189
|
+
}
|
|
190
|
+
case "model": {
|
|
191
|
+
if (!args) {
|
|
192
|
+
const providers = getProviders().sort();
|
|
193
|
+
console.log(`Current model: ${ctx.currentModel}\nProviders:\n${providers.map((p, i) => ` ${i + 1}. ${p}`).join("\n")}`);
|
|
194
|
+
return;
|
|
195
|
+
}
|
|
196
|
+
const slashParts = args.includes("/") ? args.split("/") : [];
|
|
197
|
+
let provider = args.split(" ")[0];
|
|
198
|
+
let modelId = args.split(" ")[1];
|
|
199
|
+
if (slashParts.length >= 2) {
|
|
200
|
+
provider = slashParts[0]?.trim();
|
|
201
|
+
modelId = slashParts.slice(1).join("/").trim();
|
|
202
|
+
}
|
|
203
|
+
if (provider && !modelId) {
|
|
204
|
+
const models = getModels(provider as KnownProvider);
|
|
205
|
+
if (models.length === 0) { console.log(`Unknown provider: ${provider}`); return; }
|
|
206
|
+
console.log(`Models for ${provider}:\n${models.map((m) => m.id).sort().join("\n")}`);
|
|
207
|
+
return;
|
|
208
|
+
}
|
|
209
|
+
if (!provider || !modelId) { console.log("Usage: /model <provider>/<modelId>"); return; }
|
|
210
|
+
if (!ctx.agent.setModel) { console.log("Agent does not support model switching."); return; }
|
|
211
|
+
const result = ctx.agent.setModel(provider, modelId);
|
|
212
|
+
console.log(result.message);
|
|
213
|
+
if (result.ok) {
|
|
214
|
+
ctx.setModel(`${provider}/${modelId}`);
|
|
215
|
+
await saveConfigFile(ctx.workspace.root, { model: `${provider}/${modelId}`, modelProvider: provider, modelId });
|
|
216
|
+
}
|
|
217
|
+
return;
|
|
218
|
+
}
|
|
219
|
+
default:
|
|
220
|
+
console.log(`Unknown command: ${name}`);
|
|
221
|
+
}
|
|
222
|
+
}
|