@vellumai/cli 0.4.49 → 0.4.51
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 +111 -0
- package/knip.json +6 -0
- package/package.json +3 -1
- package/src/commands/hatch.ts +4 -0
- package/src/commands/ps.ts +3 -1
- package/src/components/DefaultMainScreen.tsx +115 -8
- package/src/index.ts +99 -23
- package/src/lib/docker.ts +49 -3
- package/src/lib/health-check.ts +87 -0
- package/src/lib/http-client.ts +0 -66
- package/src/lib/local.ts +57 -36
- package/src/lib/terminal-capabilities.ts +0 -7
package/bun.lock
CHANGED
|
@@ -20,6 +20,7 @@
|
|
|
20
20
|
"@types/qrcode-terminal": "^0.12.2",
|
|
21
21
|
"@types/react": "^19.2.14",
|
|
22
22
|
"eslint": "^10.0.0",
|
|
23
|
+
"knip": "^5.86.0",
|
|
23
24
|
"prettier": "^3.8.1",
|
|
24
25
|
"typescript": "^5.9.3",
|
|
25
26
|
"typescript-eslint": "^8.55.0",
|
|
@@ -29,6 +30,12 @@
|
|
|
29
30
|
"packages": {
|
|
30
31
|
"@alcalzone/ansi-tokenize": ["@alcalzone/ansi-tokenize@0.2.5", "", { "dependencies": { "ansi-styles": "^6.2.1", "is-fullwidth-code-point": "^5.0.0" } }, "sha512-3NX/MpTdroi0aKz134A6RC2Gb2iXVECN4QaAXnvCIxxIm3C3AVB1mkUe8NaaiyvOpDfsrqWhYtj+Q6a62RrTsw=="],
|
|
31
32
|
|
|
33
|
+
"@emnapi/core": ["@emnapi/core@1.9.0", "", { "dependencies": { "@emnapi/wasi-threads": "1.2.0", "tslib": "^2.4.0" } }, "sha512-0DQ98G9ZQZOxfUcQn1waV2yS8aWdZ6kJMbYCJB3oUBecjWYO1fqJ+a1DRfPF3O5JEkwqwP1A9QEN/9mYm2Yd0w=="],
|
|
34
|
+
|
|
35
|
+
"@emnapi/runtime": ["@emnapi/runtime@1.9.0", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-QN75eB0IH2ywSpRpNddCRfQIhmJYBCJ1x5Lb3IscKAL8bMnVAKnRg8dCoXbHzVLLH7P38N2Z3mtulB7W0J0FKw=="],
|
|
36
|
+
|
|
37
|
+
"@emnapi/wasi-threads": ["@emnapi/wasi-threads@1.2.0", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-N10dEJNSsUx41Z6pZsXU8FjPjpBEplgH24sfkmITrBED1/U2Esum9F3lfLrMjKHHjmi557zQn7kR9R+XWXu5Rg=="],
|
|
38
|
+
|
|
32
39
|
"@eslint-community/eslint-utils": ["@eslint-community/eslint-utils@4.9.1", "", { "dependencies": { "eslint-visitor-keys": "^3.4.3" }, "peerDependencies": { "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" } }, "sha512-phrYmNiYppR7znFEdqgfWHXR6NCkZEK7hwWDHZUjit/2/U0r6XvkDl0SYnoM51Hq7FhCGdLDT6zxCCOY1hexsQ=="],
|
|
33
40
|
|
|
34
41
|
"@eslint-community/regexpp": ["@eslint-community/regexpp@4.12.2", "", {}, "sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew=="],
|
|
@@ -51,6 +58,56 @@
|
|
|
51
58
|
|
|
52
59
|
"@humanwhocodes/retry": ["@humanwhocodes/retry@0.4.3", "", {}, "sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ=="],
|
|
53
60
|
|
|
61
|
+
"@napi-rs/wasm-runtime": ["@napi-rs/wasm-runtime@1.1.1", "", { "dependencies": { "@emnapi/core": "^1.7.1", "@emnapi/runtime": "^1.7.1", "@tybys/wasm-util": "^0.10.1" } }, "sha512-p64ah1M1ld8xjWv3qbvFwHiFVWrq1yFvV4f7w+mzaqiR4IlSgkqhcRdHwsGgomwzBH51sRY4NEowLxnaBjcW/A=="],
|
|
62
|
+
|
|
63
|
+
"@nodelib/fs.scandir": ["@nodelib/fs.scandir@2.1.5", "", { "dependencies": { "@nodelib/fs.stat": "2.0.5", "run-parallel": "^1.1.9" } }, "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g=="],
|
|
64
|
+
|
|
65
|
+
"@nodelib/fs.stat": ["@nodelib/fs.stat@2.0.5", "", {}, "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A=="],
|
|
66
|
+
|
|
67
|
+
"@nodelib/fs.walk": ["@nodelib/fs.walk@1.2.8", "", { "dependencies": { "@nodelib/fs.scandir": "2.1.5", "fastq": "^1.6.0" } }, "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg=="],
|
|
68
|
+
|
|
69
|
+
"@oxc-resolver/binding-android-arm-eabi": ["@oxc-resolver/binding-android-arm-eabi@11.19.1", "", { "os": "android", "cpu": "arm" }, "sha512-aUs47y+xyXHUKlbhqHUjBABjvycq6YSD7bpxSW7vplUmdzAlJ93yXY6ZR0c1o1x5A/QKbENCvs3+NlY8IpIVzg=="],
|
|
70
|
+
|
|
71
|
+
"@oxc-resolver/binding-android-arm64": ["@oxc-resolver/binding-android-arm64@11.19.1", "", { "os": "android", "cpu": "arm64" }, "sha512-oolbkRX+m7Pq2LNjr/kKgYeC7bRDMVTWPgxBGMjSpZi/+UskVo4jsMU3MLheZV55jL6c3rNelPl4oD60ggYmqA=="],
|
|
72
|
+
|
|
73
|
+
"@oxc-resolver/binding-darwin-arm64": ["@oxc-resolver/binding-darwin-arm64@11.19.1", "", { "os": "darwin", "cpu": "arm64" }, "sha512-nUC6d2i3R5B12sUW4O646qD5cnMXf2oBGPLIIeaRfU9doJRORAbE2SGv4eW6rMqhD+G7nf2Y8TTJTLiiO3Q/dQ=="],
|
|
74
|
+
|
|
75
|
+
"@oxc-resolver/binding-darwin-x64": ["@oxc-resolver/binding-darwin-x64@11.19.1", "", { "os": "darwin", "cpu": "x64" }, "sha512-cV50vE5+uAgNcFa3QY1JOeKDSkM/9ReIcc/9wn4TavhW/itkDGrXhw9jaKnkQnGbjJ198Yh5nbX/Gr2mr4Z5jQ=="],
|
|
76
|
+
|
|
77
|
+
"@oxc-resolver/binding-freebsd-x64": ["@oxc-resolver/binding-freebsd-x64@11.19.1", "", { "os": "freebsd", "cpu": "x64" }, "sha512-xZOQiYGFxtk48PBKff+Zwoym7ScPAIVp4c14lfLxizO2LTTTJe5sx9vQNGrBymrf/vatSPNMD4FgsaaRigPkqw=="],
|
|
78
|
+
|
|
79
|
+
"@oxc-resolver/binding-linux-arm-gnueabihf": ["@oxc-resolver/binding-linux-arm-gnueabihf@11.19.1", "", { "os": "linux", "cpu": "arm" }, "sha512-lXZYWAC6kaGe/ky2su94e9jN9t6M0/6c+GrSlCqL//XO1cxi5lpAhnJYdyrKfm0ZEr/c7RNyAx3P7FSBcBd5+A=="],
|
|
80
|
+
|
|
81
|
+
"@oxc-resolver/binding-linux-arm-musleabihf": ["@oxc-resolver/binding-linux-arm-musleabihf@11.19.1", "", { "os": "linux", "cpu": "arm" }, "sha512-veG1kKsuK5+t2IsO9q0DErYVSw2azvCVvWHnfTOS73WE0STdLLB7Q1bB9WR+yHPQM76ASkFyRbogWo1GR1+WbQ=="],
|
|
82
|
+
|
|
83
|
+
"@oxc-resolver/binding-linux-arm64-gnu": ["@oxc-resolver/binding-linux-arm64-gnu@11.19.1", "", { "os": "linux", "cpu": "arm64" }, "sha512-heV2+jmXyYnUrpUXSPugqWDRpnsQcDm2AX4wzTuvgdlZfoNYO0O3W2AVpJYaDn9AG4JdM6Kxom8+foE7/BcSig=="],
|
|
84
|
+
|
|
85
|
+
"@oxc-resolver/binding-linux-arm64-musl": ["@oxc-resolver/binding-linux-arm64-musl@11.19.1", "", { "os": "linux", "cpu": "arm64" }, "sha512-jvo2Pjs1c9KPxMuMPIeQsgu0mOJF9rEb3y3TdpsrqwxRM+AN6/nDDwv45n5ZrUnQMsdBy5gIabioMKnQfWo9ew=="],
|
|
86
|
+
|
|
87
|
+
"@oxc-resolver/binding-linux-ppc64-gnu": ["@oxc-resolver/binding-linux-ppc64-gnu@11.19.1", "", { "os": "linux", "cpu": "ppc64" }, "sha512-vLmdNxWCdN7Uo5suays6A/+ywBby2PWBBPXctWPg5V0+eVuzsJxgAn6MMB4mPlshskYbppjpN2Zg83ArHze9gQ=="],
|
|
88
|
+
|
|
89
|
+
"@oxc-resolver/binding-linux-riscv64-gnu": ["@oxc-resolver/binding-linux-riscv64-gnu@11.19.1", "", { "os": "linux", "cpu": "none" }, "sha512-/b+WgR+VTSBxzgOhDO7TlMXC1ufPIMR6Vj1zN+/x+MnyXGW7prTLzU9eW85Aj7Th7CCEG9ArCbTeqxCzFWdg2w=="],
|
|
90
|
+
|
|
91
|
+
"@oxc-resolver/binding-linux-riscv64-musl": ["@oxc-resolver/binding-linux-riscv64-musl@11.19.1", "", { "os": "linux", "cpu": "none" }, "sha512-YlRdeWb9j42p29ROh+h4eg/OQ3dTJlpHSa+84pUM9+p6i3djtPz1q55yLJhgW9XfDch7FN1pQ/Vd6YP+xfRIuw=="],
|
|
92
|
+
|
|
93
|
+
"@oxc-resolver/binding-linux-s390x-gnu": ["@oxc-resolver/binding-linux-s390x-gnu@11.19.1", "", { "os": "linux", "cpu": "s390x" }, "sha512-EDpafVOQWF8/MJynsjOGFThcqhRHy417sRyLfQmeiamJ8qVhSKAn2Dn2VVKUGCjVB9C46VGjhNo7nOPUi1x6uA=="],
|
|
94
|
+
|
|
95
|
+
"@oxc-resolver/binding-linux-x64-gnu": ["@oxc-resolver/binding-linux-x64-gnu@11.19.1", "", { "os": "linux", "cpu": "x64" }, "sha512-NxjZe+rqWhr+RT8/Ik+5ptA3oz7tUw361Wa5RWQXKnfqwSSHdHyrw6IdcTfYuml9dM856AlKWZIUXDmA9kkiBQ=="],
|
|
96
|
+
|
|
97
|
+
"@oxc-resolver/binding-linux-x64-musl": ["@oxc-resolver/binding-linux-x64-musl@11.19.1", "", { "os": "linux", "cpu": "x64" }, "sha512-cM/hQwsO3ReJg5kR+SpI69DMfvNCp+A/eVR4b4YClE5bVZwz8rh2Nh05InhwI5HR/9cArbEkzMjcKgTHS6UaNw=="],
|
|
98
|
+
|
|
99
|
+
"@oxc-resolver/binding-openharmony-arm64": ["@oxc-resolver/binding-openharmony-arm64@11.19.1", "", { "os": "none", "cpu": "arm64" }, "sha512-QF080IowFB0+9Rh6RcD19bdgh49BpQHUW5TajG1qvWHvmrQznTZZjYlgE2ltLXyKY+qs4F/v5xuX1XS7Is+3qA=="],
|
|
100
|
+
|
|
101
|
+
"@oxc-resolver/binding-wasm32-wasi": ["@oxc-resolver/binding-wasm32-wasi@11.19.1", "", { "dependencies": { "@napi-rs/wasm-runtime": "^1.1.1" }, "cpu": "none" }, "sha512-w8UCKhX826cP/ZLokXDS6+milN8y4X7zidsAttEdWlVoamTNf6lhBJldaWr3ukTDiye7s4HRcuPEPOXNC432Vg=="],
|
|
102
|
+
|
|
103
|
+
"@oxc-resolver/binding-win32-arm64-msvc": ["@oxc-resolver/binding-win32-arm64-msvc@11.19.1", "", { "os": "win32", "cpu": "arm64" }, "sha512-nJ4AsUVZrVKwnU/QRdzPCCrO0TrabBqgJ8pJhXITdZGYOV28TIYystV1VFLbQ7DtAcaBHpocT5/ZJnF78YJPtQ=="],
|
|
104
|
+
|
|
105
|
+
"@oxc-resolver/binding-win32-ia32-msvc": ["@oxc-resolver/binding-win32-ia32-msvc@11.19.1", "", { "os": "win32", "cpu": "ia32" }, "sha512-EW+ND5q2Tl+a3pH81l1QbfgbF3HmqgwLfDfVithRFheac8OTcnbXt/JxqD2GbDkb7xYEqy1zNaVFRr3oeG8npA=="],
|
|
106
|
+
|
|
107
|
+
"@oxc-resolver/binding-win32-x64-msvc": ["@oxc-resolver/binding-win32-x64-msvc@11.19.1", "", { "os": "win32", "cpu": "x64" }, "sha512-6hIU3RQu45B+VNTY4Ru8ppFwjVS/S5qwYyGhBotmjxfEKk41I2DlGtRfGJndZ5+6lneE2pwloqunlOyZuX/XAw=="],
|
|
108
|
+
|
|
109
|
+
"@tybys/wasm-util": ["@tybys/wasm-util@0.10.1", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg=="],
|
|
110
|
+
|
|
54
111
|
"@types/bun": ["@types/bun@1.3.9", "", { "dependencies": { "bun-types": "1.3.9" } }, "sha512-KQ571yULOdWJiMH+RIWIOZ7B2RXQGpL1YQrBtLIV3FqDcCu6FsbFUBwhdKUlCKUpS3PJDsHlJ1QKlpxoVR+xtw=="],
|
|
55
112
|
|
|
56
113
|
"@types/esrecurse": ["@types/esrecurse@4.3.1", "", {}, "sha512-xJBAbDifo5hpffDBuHl0Y8ywswbiAp/Wi7Y/GtAgSlZyIABppyurxVueOPE8LUQOxdlgi6Zqce7uoEpqNTeiUw=="],
|
|
@@ -107,6 +164,8 @@
|
|
|
107
164
|
|
|
108
165
|
"brace-expansion": ["brace-expansion@5.0.2", "", { "dependencies": { "balanced-match": "^4.0.2" } }, "sha512-Pdk8c9poy+YhOgVWw1JNN22/HcivgKWwpxKq04M/jTmHyCZn12WPJebZxdjSa5TmBqISrUSgNYU3eRORljfCCw=="],
|
|
109
166
|
|
|
167
|
+
"braces": ["braces@3.0.3", "", { "dependencies": { "fill-range": "^7.1.1" } }, "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA=="],
|
|
168
|
+
|
|
110
169
|
"bun-types": ["bun-types@1.3.9", "", { "dependencies": { "@types/node": "*" } }, "sha512-+UBWWOakIP4Tswh0Bt0QD0alpTY8cb5hvgiYeWCMet9YukHbzuruIEeXC2D7nMJPB12kbh8C7XJykSexEqGKJg=="],
|
|
111
170
|
|
|
112
171
|
"camelcase": ["camelcase@5.3.1", "", {}, "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg=="],
|
|
@@ -167,20 +226,30 @@
|
|
|
167
226
|
|
|
168
227
|
"fast-deep-equal": ["fast-deep-equal@3.1.3", "", {}, "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q=="],
|
|
169
228
|
|
|
229
|
+
"fast-glob": ["fast-glob@3.3.3", "", { "dependencies": { "@nodelib/fs.stat": "^2.0.2", "@nodelib/fs.walk": "^1.2.3", "glob-parent": "^5.1.2", "merge2": "^1.3.0", "micromatch": "^4.0.8" } }, "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg=="],
|
|
230
|
+
|
|
170
231
|
"fast-json-stable-stringify": ["fast-json-stable-stringify@2.1.0", "", {}, "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw=="],
|
|
171
232
|
|
|
172
233
|
"fast-levenshtein": ["fast-levenshtein@2.0.6", "", {}, "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw=="],
|
|
173
234
|
|
|
235
|
+
"fastq": ["fastq@1.20.1", "", { "dependencies": { "reusify": "^1.0.4" } }, "sha512-GGToxJ/w1x32s/D2EKND7kTil4n8OVk/9mycTc4VDza13lOvpUZTGX3mFSCtV9ksdGBVzvsyAVLM6mHFThxXxw=="],
|
|
236
|
+
|
|
237
|
+
"fd-package-json": ["fd-package-json@2.0.0", "", { "dependencies": { "walk-up-path": "^4.0.0" } }, "sha512-jKmm9YtsNXN789RS/0mSzOC1NUq9mkVd65vbSSVsKdjGvYXBuE4oWe2QOEoFeRmJg+lPuZxpmrfFclNhoRMneQ=="],
|
|
238
|
+
|
|
174
239
|
"fdir": ["fdir@6.5.0", "", { "peerDependencies": { "picomatch": "^3 || ^4" }, "optionalPeers": ["picomatch"] }, "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg=="],
|
|
175
240
|
|
|
176
241
|
"file-entry-cache": ["file-entry-cache@8.0.0", "", { "dependencies": { "flat-cache": "^4.0.0" } }, "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ=="],
|
|
177
242
|
|
|
243
|
+
"fill-range": ["fill-range@7.1.1", "", { "dependencies": { "to-regex-range": "^5.0.1" } }, "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg=="],
|
|
244
|
+
|
|
178
245
|
"find-up": ["find-up@5.0.0", "", { "dependencies": { "locate-path": "^6.0.0", "path-exists": "^4.0.0" } }, "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng=="],
|
|
179
246
|
|
|
180
247
|
"flat-cache": ["flat-cache@4.0.1", "", { "dependencies": { "flatted": "^3.2.9", "keyv": "^4.5.4" } }, "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw=="],
|
|
181
248
|
|
|
182
249
|
"flatted": ["flatted@3.3.3", "", {}, "sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg=="],
|
|
183
250
|
|
|
251
|
+
"formatly": ["formatly@0.3.0", "", { "dependencies": { "fd-package-json": "^2.0.0" }, "bin": { "formatly": "bin/index.mjs" } }, "sha512-9XNj/o4wrRFyhSMJOvsuyMwy8aUfBaZ1VrqHVfohyXf0Sw0e+yfKG+xZaY3arGCOMdwFsqObtzVOc1gU9KiT9w=="],
|
|
252
|
+
|
|
184
253
|
"get-caller-file": ["get-caller-file@2.0.5", "", {}, "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg=="],
|
|
185
254
|
|
|
186
255
|
"get-east-asian-width": ["get-east-asian-width@1.5.0", "", {}, "sha512-CQ+bEO+Tva/qlmw24dCejulK5pMzVnUOFOijVogd3KQs07HnRIgp8TGipvCCRT06xeYEbpbgwaCxglFyiuIcmA=="],
|
|
@@ -203,8 +272,12 @@
|
|
|
203
272
|
|
|
204
273
|
"is-in-ci": ["is-in-ci@2.0.0", "", { "bin": { "is-in-ci": "cli.js" } }, "sha512-cFeerHriAnhrQSbpAxL37W1wcJKUUX07HyLWZCW1URJT/ra3GyUTzBgUnh24TMVfNTV2Hij2HLxkPHFZfOZy5w=="],
|
|
205
274
|
|
|
275
|
+
"is-number": ["is-number@7.0.0", "", {}, "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng=="],
|
|
276
|
+
|
|
206
277
|
"isexe": ["isexe@2.0.0", "", {}, "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw=="],
|
|
207
278
|
|
|
279
|
+
"jiti": ["jiti@2.6.1", "", { "bin": { "jiti": "lib/jiti-cli.mjs" } }, "sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ=="],
|
|
280
|
+
|
|
208
281
|
"json-buffer": ["json-buffer@3.0.1", "", {}, "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ=="],
|
|
209
282
|
|
|
210
283
|
"json-schema-traverse": ["json-schema-traverse@0.4.1", "", {}, "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg=="],
|
|
@@ -215,14 +288,22 @@
|
|
|
215
288
|
|
|
216
289
|
"keyv": ["keyv@4.5.4", "", { "dependencies": { "json-buffer": "3.0.1" } }, "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw=="],
|
|
217
290
|
|
|
291
|
+
"knip": ["knip@5.86.0", "", { "dependencies": { "@nodelib/fs.walk": "^1.2.3", "fast-glob": "^3.3.3", "formatly": "^0.3.0", "jiti": "^2.6.0", "minimist": "^1.2.8", "oxc-resolver": "^11.19.1", "picocolors": "^1.1.1", "picomatch": "^4.0.1", "smol-toml": "^1.5.2", "strip-json-comments": "5.0.3", "unbash": "^2.2.0", "yaml": "^2.8.2", "zod": "^4.1.11" }, "peerDependencies": { "@types/node": ">=18", "typescript": ">=5.0.4 <7" }, "bin": { "knip": "bin/knip.js", "knip-bun": "bin/knip-bun.js" } }, "sha512-tGpRCbP+L+VysXnAp1bHTLQ0k/SdC3M3oX18+Cpiqax1qdS25iuCPzpK8LVmAKARZv0Ijri81Wq09Rzk0JTl+Q=="],
|
|
292
|
+
|
|
218
293
|
"levn": ["levn@0.4.1", "", { "dependencies": { "prelude-ls": "^1.2.1", "type-check": "~0.4.0" } }, "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ=="],
|
|
219
294
|
|
|
220
295
|
"locate-path": ["locate-path@6.0.0", "", { "dependencies": { "p-locate": "^5.0.0" } }, "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw=="],
|
|
221
296
|
|
|
297
|
+
"merge2": ["merge2@1.4.1", "", {}, "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg=="],
|
|
298
|
+
|
|
299
|
+
"micromatch": ["micromatch@4.0.8", "", { "dependencies": { "braces": "^3.0.3", "picomatch": "^2.3.1" } }, "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA=="],
|
|
300
|
+
|
|
222
301
|
"mimic-fn": ["mimic-fn@2.1.0", "", {}, "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg=="],
|
|
223
302
|
|
|
224
303
|
"minimatch": ["minimatch@10.2.1", "", { "dependencies": { "brace-expansion": "^5.0.2" } }, "sha512-MClCe8IL5nRRmawL6ib/eT4oLyeKMGCghibcDWK+J0hh0Q8kqSdia6BvbRMVk6mPa6WqUa5uR2oxt6C5jd533A=="],
|
|
225
304
|
|
|
305
|
+
"minimist": ["minimist@1.2.8", "", {}, "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA=="],
|
|
306
|
+
|
|
226
307
|
"ms": ["ms@2.1.3", "", {}, "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="],
|
|
227
308
|
|
|
228
309
|
"natural-compare": ["natural-compare@1.4.0", "", {}, "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw=="],
|
|
@@ -231,6 +312,8 @@
|
|
|
231
312
|
|
|
232
313
|
"optionator": ["optionator@0.9.4", "", { "dependencies": { "deep-is": "^0.1.3", "fast-levenshtein": "^2.0.6", "levn": "^0.4.1", "prelude-ls": "^1.2.1", "type-check": "^0.4.0", "word-wrap": "^1.2.5" } }, "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g=="],
|
|
233
314
|
|
|
315
|
+
"oxc-resolver": ["oxc-resolver@11.19.1", "", { "optionalDependencies": { "@oxc-resolver/binding-android-arm-eabi": "11.19.1", "@oxc-resolver/binding-android-arm64": "11.19.1", "@oxc-resolver/binding-darwin-arm64": "11.19.1", "@oxc-resolver/binding-darwin-x64": "11.19.1", "@oxc-resolver/binding-freebsd-x64": "11.19.1", "@oxc-resolver/binding-linux-arm-gnueabihf": "11.19.1", "@oxc-resolver/binding-linux-arm-musleabihf": "11.19.1", "@oxc-resolver/binding-linux-arm64-gnu": "11.19.1", "@oxc-resolver/binding-linux-arm64-musl": "11.19.1", "@oxc-resolver/binding-linux-ppc64-gnu": "11.19.1", "@oxc-resolver/binding-linux-riscv64-gnu": "11.19.1", "@oxc-resolver/binding-linux-riscv64-musl": "11.19.1", "@oxc-resolver/binding-linux-s390x-gnu": "11.19.1", "@oxc-resolver/binding-linux-x64-gnu": "11.19.1", "@oxc-resolver/binding-linux-x64-musl": "11.19.1", "@oxc-resolver/binding-openharmony-arm64": "11.19.1", "@oxc-resolver/binding-wasm32-wasi": "11.19.1", "@oxc-resolver/binding-win32-arm64-msvc": "11.19.1", "@oxc-resolver/binding-win32-ia32-msvc": "11.19.1", "@oxc-resolver/binding-win32-x64-msvc": "11.19.1" } }, "sha512-qE/CIg/spwrTBFt5aKmwe3ifeDdLfA2NESN30E42X/lII5ClF8V7Wt6WIJhcGZjp0/Q+nQ+9vgxGk//xZNX2hg=="],
|
|
316
|
+
|
|
234
317
|
"p-limit": ["p-limit@3.1.0", "", { "dependencies": { "yocto-queue": "^0.1.0" } }, "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ=="],
|
|
235
318
|
|
|
236
319
|
"p-locate": ["p-locate@5.0.0", "", { "dependencies": { "p-limit": "^3.0.2" } }, "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw=="],
|
|
@@ -243,6 +326,8 @@
|
|
|
243
326
|
|
|
244
327
|
"path-key": ["path-key@3.1.1", "", {}, "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q=="],
|
|
245
328
|
|
|
329
|
+
"picocolors": ["picocolors@1.1.1", "", {}, "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA=="],
|
|
330
|
+
|
|
246
331
|
"picomatch": ["picomatch@4.0.3", "", {}, "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q=="],
|
|
247
332
|
|
|
248
333
|
"pngjs": ["pngjs@7.0.0", "", {}, "sha512-LKWqWJRhstyYo9pGvgor/ivk2w94eSjE3RGVuzLGlr3NmD8bf7RcYGze1mNdEHRP6TRP6rMuDHk5t44hnTRyow=="],
|
|
@@ -257,6 +342,8 @@
|
|
|
257
342
|
|
|
258
343
|
"qrcode-terminal": ["qrcode-terminal@0.12.0", "", { "bin": { "qrcode-terminal": "./bin/qrcode-terminal.js" } }, "sha512-EXtzRZmC+YGmGlDFbXKxQiMZNwCLEO6BANKXG4iCtSIM0yqc/pappSx3RIKr4r0uh5JsBckOXeKrB3Iz7mdQpQ=="],
|
|
259
344
|
|
|
345
|
+
"queue-microtask": ["queue-microtask@1.2.3", "", {}, "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A=="],
|
|
346
|
+
|
|
260
347
|
"react": ["react@19.2.4", "", {}, "sha512-9nfp2hYpCwOjAN+8TZFGhtWEwgvWHXqESH8qT89AT/lWklpLON22Lc8pEtnpsZz7VmawabSU0gCjnj8aC0euHQ=="],
|
|
261
348
|
|
|
262
349
|
"react-devtools-core": ["react-devtools-core@6.1.5", "", { "dependencies": { "shell-quote": "^1.6.1", "ws": "^7" } }, "sha512-ePrwPfxAnB+7hgnEr8vpKxL9cmnp7F322t8oqcPshbIQQhDKgFDW4tjhF2wjVbdXF9O/nyuy3sQWd9JGpiLPvA=="],
|
|
@@ -269,6 +356,10 @@
|
|
|
269
356
|
|
|
270
357
|
"restore-cursor": ["restore-cursor@4.0.0", "", { "dependencies": { "onetime": "^5.1.0", "signal-exit": "^3.0.2" } }, "sha512-I9fPXU9geO9bHOt9pHHOhOkYerIMsmVaWB0rA2AI9ERh/+x/i7MV5HKBNrg+ljO5eoPVgCcnFuRjJ9uH6I/3eg=="],
|
|
271
358
|
|
|
359
|
+
"reusify": ["reusify@1.1.0", "", {}, "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw=="],
|
|
360
|
+
|
|
361
|
+
"run-parallel": ["run-parallel@1.2.0", "", { "dependencies": { "queue-microtask": "^1.2.2" } }, "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA=="],
|
|
362
|
+
|
|
272
363
|
"scheduler": ["scheduler@0.27.0", "", {}, "sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q=="],
|
|
273
364
|
|
|
274
365
|
"semver": ["semver@7.7.4", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA=="],
|
|
@@ -285,20 +376,28 @@
|
|
|
285
376
|
|
|
286
377
|
"slice-ansi": ["slice-ansi@7.1.2", "", { "dependencies": { "ansi-styles": "^6.2.1", "is-fullwidth-code-point": "^5.0.0" } }, "sha512-iOBWFgUX7caIZiuutICxVgX1SdxwAVFFKwt1EvMYYec/NWO5meOJ6K5uQxhrYBdQJne4KxiqZc+KptFOWFSI9w=="],
|
|
287
378
|
|
|
379
|
+
"smol-toml": ["smol-toml@1.6.0", "", {}, "sha512-4zemZi0HvTnYwLfrpk/CF9LOd9Lt87kAt50GnqhMpyF9U3poDAP2+iukq2bZsO/ufegbYehBkqINbsWxj4l4cw=="],
|
|
380
|
+
|
|
288
381
|
"stack-utils": ["stack-utils@2.0.6", "", { "dependencies": { "escape-string-regexp": "^2.0.0" } }, "sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ=="],
|
|
289
382
|
|
|
290
383
|
"string-width": ["string-width@8.2.0", "", { "dependencies": { "get-east-asian-width": "^1.5.0", "strip-ansi": "^7.1.2" } }, "sha512-6hJPQ8N0V0P3SNmP6h2J99RLuzrWz2gvT7VnK5tKvrNqJoyS9W4/Fb8mo31UiPvy00z7DQXkP2hnKBVav76thw=="],
|
|
291
384
|
|
|
292
385
|
"strip-ansi": ["strip-ansi@7.1.2", "", { "dependencies": { "ansi-regex": "^6.0.1" } }, "sha512-gmBGslpoQJtgnMAvOVqGZpEz9dyoKTCzy2nfz/n8aIFhN/jCE/rCmcxabB6jOOHV+0WNnylOxaxBQPSvcWklhA=="],
|
|
293
386
|
|
|
387
|
+
"strip-json-comments": ["strip-json-comments@5.0.3", "", {}, "sha512-1tB5mhVo7U+ETBKNf92xT4hrQa3pm0MZ0PQvuDnWgAAGHDsfp4lPSpiS6psrSiet87wyGPh9ft6wmhOMQ0hDiw=="],
|
|
388
|
+
|
|
294
389
|
"tagged-tag": ["tagged-tag@1.0.0", "", {}, "sha512-yEFYrVhod+hdNyx7g5Bnkkb0G6si8HJurOoOEgC8B/O0uXLHlaey/65KRv6cuWBNhBgHKAROVpc7QyYqE5gFng=="],
|
|
295
390
|
|
|
296
391
|
"terminal-size": ["terminal-size@4.0.1", "", {}, "sha512-avMLDQpUI9I5XFrklECw1ZEUPJhqzcwSWsyyI8blhRLT+8N1jLJWLWWYQpB2q2xthq8xDvjZPISVh53T/+CLYQ=="],
|
|
297
392
|
|
|
298
393
|
"tinyglobby": ["tinyglobby@0.2.15", "", { "dependencies": { "fdir": "^6.5.0", "picomatch": "^4.0.3" } }, "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ=="],
|
|
299
394
|
|
|
395
|
+
"to-regex-range": ["to-regex-range@5.0.1", "", { "dependencies": { "is-number": "^7.0.0" } }, "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ=="],
|
|
396
|
+
|
|
300
397
|
"ts-api-utils": ["ts-api-utils@2.4.0", "", { "peerDependencies": { "typescript": ">=4.8.4" } }, "sha512-3TaVTaAv2gTiMB35i3FiGJaRfwb3Pyn/j3m/bfAvGe8FB7CF6u+LMYqYlDh7reQf7UNvoTvdfAqHGmPGOSsPmA=="],
|
|
301
398
|
|
|
399
|
+
"tslib": ["tslib@2.8.1", "", {}, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="],
|
|
400
|
+
|
|
302
401
|
"type-check": ["type-check@0.4.0", "", { "dependencies": { "prelude-ls": "^1.2.1" } }, "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew=="],
|
|
303
402
|
|
|
304
403
|
"type-fest": ["type-fest@5.4.4", "", { "dependencies": { "tagged-tag": "^1.0.0" } }, "sha512-JnTrzGu+zPV3aXIUhnyWJj4z/wigMsdYajGLIYakqyOW1nPllzXEJee0QQbHj+CTIQtXGlAjuK0UY+2xTyjVAw=="],
|
|
@@ -307,10 +406,14 @@
|
|
|
307
406
|
|
|
308
407
|
"typescript-eslint": ["typescript-eslint@8.56.0", "", { "dependencies": { "@typescript-eslint/eslint-plugin": "8.56.0", "@typescript-eslint/parser": "8.56.0", "@typescript-eslint/typescript-estree": "8.56.0", "@typescript-eslint/utils": "8.56.0" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", "typescript": ">=4.8.4 <6.0.0" } }, "sha512-c7toRLrotJ9oixgdW7liukZpsnq5CZ7PuKztubGYlNppuTqhIoWfhgHo/7EU0v06gS2l/x0i2NEFK1qMIf0rIg=="],
|
|
309
408
|
|
|
409
|
+
"unbash": ["unbash@2.2.0", "", {}, "sha512-X2wH19RAPZE3+ldGicOkoj/SIA83OIxcJ6Cuaw23hf8Xc6fQpvZXY0SftE2JgS0QhYLUG4uwodSI3R53keyh7w=="],
|
|
410
|
+
|
|
310
411
|
"undici-types": ["undici-types@7.16.0", "", {}, "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw=="],
|
|
311
412
|
|
|
312
413
|
"uri-js": ["uri-js@4.4.1", "", { "dependencies": { "punycode": "^2.1.0" } }, "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg=="],
|
|
313
414
|
|
|
415
|
+
"walk-up-path": ["walk-up-path@4.0.0", "", {}, "sha512-3hu+tD8YzSLGuFYtPRb48vdhKMi0KQV5sn+uWr8+7dMEq/2G/dtLrdDinkLjqq5TIbIBjYJ4Ax/n3YiaW7QM8A=="],
|
|
416
|
+
|
|
314
417
|
"which": ["which@2.0.2", "", { "dependencies": { "isexe": "^2.0.0" }, "bin": { "node-which": "./bin/node-which" } }, "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA=="],
|
|
315
418
|
|
|
316
419
|
"which-module": ["which-module@2.0.1", "", {}, "sha512-iBdZ57RDvnOR9AGBhML2vFZf7h8vmBjhoaZqODJBFWHVtKkDmKuHai3cx5PgVMrX5YDNp27AofYbAwctSS+vhQ=="],
|
|
@@ -325,6 +428,8 @@
|
|
|
325
428
|
|
|
326
429
|
"y18n": ["y18n@4.0.3", "", {}, "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ=="],
|
|
327
430
|
|
|
431
|
+
"yaml": ["yaml@2.8.2", "", { "bin": { "yaml": "bin.mjs" } }, "sha512-mplynKqc1C2hTVYxd0PU2xQAc22TI1vShAYGksCCfxbn/dFwnHTNi1bvYsBTkhdUNtGIf5xNOg938rrSSYvS9A=="],
|
|
432
|
+
|
|
328
433
|
"yargs": ["yargs@15.4.1", "", { "dependencies": { "cliui": "^6.0.0", "decamelize": "^1.2.0", "find-up": "^4.1.0", "get-caller-file": "^2.0.1", "require-directory": "^2.1.1", "require-main-filename": "^2.0.0", "set-blocking": "^2.0.0", "string-width": "^4.2.0", "which-module": "^2.0.0", "y18n": "^4.0.0", "yargs-parser": "^18.1.2" } }, "sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A=="],
|
|
329
434
|
|
|
330
435
|
"yargs-parser": ["yargs-parser@18.1.3", "", { "dependencies": { "camelcase": "^5.0.0", "decamelize": "^1.2.0" } }, "sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ=="],
|
|
@@ -333,6 +438,8 @@
|
|
|
333
438
|
|
|
334
439
|
"yoga-layout": ["yoga-layout@3.2.1", "", {}, "sha512-0LPOt3AxKqMdFBZA3HBAt/t/8vIKq7VaQYbuA8WxCgung+p9TVyKRYdpvCb80HcdTN2NkbIKbhNwKUfm3tQywQ=="],
|
|
335
440
|
|
|
441
|
+
"zod": ["zod@4.3.6", "", {}, "sha512-rftlrkhHZOcjDwkGlnUtZZkvaPHCsDATp4pGpuOOMDaTdDDXF91wuVDJoWoPsKX/3YPQ5fHuF3STjcYyKr+Qhg=="],
|
|
442
|
+
|
|
336
443
|
"@eslint-community/eslint-utils/eslint-visitor-keys": ["eslint-visitor-keys@3.4.3", "", {}, "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag=="],
|
|
337
444
|
|
|
338
445
|
"@typescript-eslint/eslint-plugin/ignore": ["ignore@7.0.5", "", {}, "sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg=="],
|
|
@@ -345,6 +452,10 @@
|
|
|
345
452
|
|
|
346
453
|
"cliui/wrap-ansi": ["wrap-ansi@6.2.0", "", { "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", "strip-ansi": "^6.0.0" } }, "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA=="],
|
|
347
454
|
|
|
455
|
+
"fast-glob/glob-parent": ["glob-parent@5.1.2", "", { "dependencies": { "is-glob": "^4.0.1" } }, "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow=="],
|
|
456
|
+
|
|
457
|
+
"micromatch/picomatch": ["picomatch@2.3.1", "", {}, "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA=="],
|
|
458
|
+
|
|
348
459
|
"qrcode/pngjs": ["pngjs@5.0.0", "", {}, "sha512-40QW5YalBNfQo5yRYmiw7Yz6TKKVr3h6970B2YE+3fQpsWcrbj1PzJgxeJ19DRQjhMbKPIuMY8rFaXc8moolVw=="],
|
|
349
460
|
|
|
350
461
|
"react-devtools-core/ws": ["ws@7.5.10", "", { "peerDependencies": { "bufferutil": "^4.0.1", "utf-8-validate": "^5.0.2" }, "optionalPeers": ["bufferutil", "utf-8-validate"] }, "sha512-+dbF1tHwZpXcbOJdVOkzLDxZP1ailvSxM6ZweXTegylPny803bFhA+vqBYw4s31NSAk4S2Qz+AKXK9a4wkdjcQ=="],
|
package/knip.json
ADDED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vellumai/cli",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.51",
|
|
4
4
|
"description": "CLI tools for vellum-assistant",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"exports": {
|
|
@@ -17,6 +17,7 @@
|
|
|
17
17
|
"format": "prettier --write .",
|
|
18
18
|
"format:check": "prettier --check .",
|
|
19
19
|
"lint": "eslint",
|
|
20
|
+
"lint:unused": "knip --include files,dependencies,unlisted",
|
|
20
21
|
"test": "bun test",
|
|
21
22
|
"typecheck": "bunx tsc --noEmit"
|
|
22
23
|
},
|
|
@@ -38,6 +39,7 @@
|
|
|
38
39
|
"@types/qrcode-terminal": "^0.12.2",
|
|
39
40
|
"@types/react": "^19.2.14",
|
|
40
41
|
"eslint": "^10.0.0",
|
|
42
|
+
"knip": "^5.86.0",
|
|
41
43
|
"prettier": "^3.8.1",
|
|
42
44
|
"typescript": "^5.9.3",
|
|
43
45
|
"typescript-eslint": "^8.55.0"
|
package/src/commands/hatch.ts
CHANGED
|
@@ -760,6 +760,10 @@ async function hatchLocal(
|
|
|
760
760
|
console.log(` Species: ${species}`);
|
|
761
761
|
console.log("");
|
|
762
762
|
|
|
763
|
+
if (!process.env.APP_VERSION) {
|
|
764
|
+
process.env.APP_VERSION = cliPkg.version;
|
|
765
|
+
}
|
|
766
|
+
|
|
763
767
|
await startLocalDaemon(watch, resources);
|
|
764
768
|
|
|
765
769
|
let runtimeUrl: string;
|
package/src/commands/ps.ts
CHANGED
|
@@ -6,7 +6,7 @@ import {
|
|
|
6
6
|
loadAllAssistants,
|
|
7
7
|
type AssistantEntry,
|
|
8
8
|
} from "../lib/assistant-config";
|
|
9
|
-
import { checkHealth } from "../lib/health-check";
|
|
9
|
+
import { checkHealth, checkManagedHealth } from "../lib/health-check";
|
|
10
10
|
import {
|
|
11
11
|
classifyProcess,
|
|
12
12
|
detectOrphanedProcesses,
|
|
@@ -359,6 +359,8 @@ async function listAllAssistants(): Promise<void> {
|
|
|
359
359
|
} else {
|
|
360
360
|
health = await checkHealth(a.localUrl ?? a.runtimeUrl, a.bearerToken);
|
|
361
361
|
}
|
|
362
|
+
} else if (a.cloud === "vellum") {
|
|
363
|
+
health = await checkManagedHealth(a.runtimeUrl, a.assistantId);
|
|
362
364
|
} else {
|
|
363
365
|
health = await checkHealth(a.localUrl ?? a.runtimeUrl, a.bearerToken);
|
|
364
366
|
}
|
|
@@ -500,6 +500,9 @@ async function handleScopeSelection(
|
|
|
500
500
|
|
|
501
501
|
export const TYPING_FRAMES = ["⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"];
|
|
502
502
|
|
|
503
|
+
/** ASCII-safe spinner frames for the connection screen. */
|
|
504
|
+
const CONNECTION_SPINNER_FRAMES = ["|", "/", "-", "\\"];
|
|
505
|
+
|
|
503
506
|
export interface ToolCallInfo {
|
|
504
507
|
name: string;
|
|
505
508
|
input: Record<string, unknown>;
|
|
@@ -675,6 +678,75 @@ function SpinnerDisplay({ text }: { text: string }): ReactElement {
|
|
|
675
678
|
);
|
|
676
679
|
}
|
|
677
680
|
|
|
681
|
+
type ConnectionState = "connecting" | "connected" | "error";
|
|
682
|
+
|
|
683
|
+
function ConnectionScreen({
|
|
684
|
+
state,
|
|
685
|
+
errorMessage,
|
|
686
|
+
species,
|
|
687
|
+
terminalRows,
|
|
688
|
+
terminalColumns,
|
|
689
|
+
onRetry,
|
|
690
|
+
onExit,
|
|
691
|
+
}: {
|
|
692
|
+
state: ConnectionState;
|
|
693
|
+
errorMessage?: string;
|
|
694
|
+
species: Species;
|
|
695
|
+
terminalRows: number;
|
|
696
|
+
terminalColumns: number;
|
|
697
|
+
onRetry: () => void;
|
|
698
|
+
onExit: () => void;
|
|
699
|
+
}): ReactElement {
|
|
700
|
+
const [frameIndex, setFrameIndex] = useState(0);
|
|
701
|
+
|
|
702
|
+
useEffect(() => {
|
|
703
|
+
if (state !== "connecting") return;
|
|
704
|
+
const timer = setInterval(() => {
|
|
705
|
+
setFrameIndex((prev) => (prev + 1) % CONNECTION_SPINNER_FRAMES.length);
|
|
706
|
+
}, 150);
|
|
707
|
+
return () => clearInterval(timer);
|
|
708
|
+
}, [state]);
|
|
709
|
+
|
|
710
|
+
useInput((input, key) => {
|
|
711
|
+
if (key.ctrl && input === "c") {
|
|
712
|
+
onExit();
|
|
713
|
+
}
|
|
714
|
+
if (state === "error" && input === "r") {
|
|
715
|
+
onRetry();
|
|
716
|
+
}
|
|
717
|
+
});
|
|
718
|
+
|
|
719
|
+
const config = SPECIES_CONFIG[species];
|
|
720
|
+
const title = `Vellum ${config.hatchedEmoji} ${species}`;
|
|
721
|
+
const width = Math.min(terminalColumns, MAX_TOTAL_WIDTH);
|
|
722
|
+
|
|
723
|
+
return (
|
|
724
|
+
<Box
|
|
725
|
+
flexDirection="column"
|
|
726
|
+
height={terminalRows}
|
|
727
|
+
width={width}
|
|
728
|
+
justifyContent="center"
|
|
729
|
+
alignItems="center"
|
|
730
|
+
>
|
|
731
|
+
<Text dimColor bold>
|
|
732
|
+
{title}
|
|
733
|
+
</Text>
|
|
734
|
+
<Text> </Text>
|
|
735
|
+
{state === "connecting" ? (
|
|
736
|
+
<Text dimColor>
|
|
737
|
+
{CONNECTION_SPINNER_FRAMES[frameIndex]} Connecting to assistant...
|
|
738
|
+
</Text>
|
|
739
|
+
) : (
|
|
740
|
+
<>
|
|
741
|
+
<Text color="red">Failed to connect: {errorMessage}</Text>
|
|
742
|
+
<Text> </Text>
|
|
743
|
+
<Text dimColor>Press r to retry or Ctrl+C to quit</Text>
|
|
744
|
+
</>
|
|
745
|
+
)}
|
|
746
|
+
</Box>
|
|
747
|
+
);
|
|
748
|
+
}
|
|
749
|
+
|
|
678
750
|
export function renderErrorMainScreen(error: unknown): number {
|
|
679
751
|
const msg = error instanceof Error ? error.message : String(error);
|
|
680
752
|
console.log(
|
|
@@ -1224,6 +1296,11 @@ function ChatApp({
|
|
|
1224
1296
|
const [healthStatus, setHealthStatus] = useState<string | undefined>(
|
|
1225
1297
|
undefined,
|
|
1226
1298
|
);
|
|
1299
|
+
const [connectionState, setConnectionState] =
|
|
1300
|
+
useState<ConnectionState>("connecting");
|
|
1301
|
+
const [connectionError, setConnectionError] = useState<string | undefined>(
|
|
1302
|
+
undefined,
|
|
1303
|
+
);
|
|
1227
1304
|
const prevFeedLengthRef = useRef(0);
|
|
1228
1305
|
const busyRef = useRef(false);
|
|
1229
1306
|
const connectedRef = useRef(false);
|
|
@@ -1240,7 +1317,7 @@ function ChatApp({
|
|
|
1240
1317
|
const headerHeight = calculateHeaderHeight(species, terminalColumns);
|
|
1241
1318
|
|
|
1242
1319
|
const isCompact = terminalColumns < COMPACT_THRESHOLD;
|
|
1243
|
-
const compactInputAreaHeight =
|
|
1320
|
+
const compactInputAreaHeight = 1; // input row only, no separators
|
|
1244
1321
|
const inputAreaHeight = isCompact
|
|
1245
1322
|
? compactInputAreaHeight
|
|
1246
1323
|
: INPUT_AREA_HEIGHT;
|
|
@@ -1476,6 +1553,8 @@ function ChatApp({
|
|
|
1476
1553
|
return false;
|
|
1477
1554
|
}
|
|
1478
1555
|
connectingRef.current = true;
|
|
1556
|
+
setConnectionState("connecting");
|
|
1557
|
+
setConnectionError(undefined);
|
|
1479
1558
|
const h = handleRef_.current;
|
|
1480
1559
|
|
|
1481
1560
|
h.showSpinner("Connecting...");
|
|
@@ -1538,12 +1617,15 @@ function ChatApp({
|
|
|
1538
1617
|
|
|
1539
1618
|
connectedRef.current = true;
|
|
1540
1619
|
connectingRef.current = false;
|
|
1620
|
+
setConnectionState("connected");
|
|
1541
1621
|
return true;
|
|
1542
1622
|
} catch (err) {
|
|
1543
1623
|
h.hideSpinner();
|
|
1544
1624
|
connectingRef.current = false;
|
|
1545
1625
|
h.updateHealthStatus("unreachable");
|
|
1546
1626
|
const msg = err instanceof Error ? err.message : String(err);
|
|
1627
|
+
setConnectionState("error");
|
|
1628
|
+
setConnectionError(msg);
|
|
1547
1629
|
h.addStatus(
|
|
1548
1630
|
`${statusEmoji("unreachable")} Failed to connect: ${msg}`,
|
|
1549
1631
|
"red",
|
|
@@ -2065,6 +2147,7 @@ function ChatApp({
|
|
|
2065
2147
|
role: "assistant",
|
|
2066
2148
|
content: msg.content,
|
|
2067
2149
|
});
|
|
2150
|
+
process.stdout.write("\x07");
|
|
2068
2151
|
h.setBusy(false);
|
|
2069
2152
|
h.hideSpinner();
|
|
2070
2153
|
return;
|
|
@@ -2174,6 +2257,13 @@ function ChatApp({
|
|
|
2174
2257
|
updateHealthStatus,
|
|
2175
2258
|
]);
|
|
2176
2259
|
|
|
2260
|
+
const retryConnection = useCallback(() => {
|
|
2261
|
+
if (connectingRef.current) return; // already retrying
|
|
2262
|
+
connectedRef.current = false;
|
|
2263
|
+
setConnectionState("connecting");
|
|
2264
|
+
ensureConnected();
|
|
2265
|
+
}, [ensureConnected]);
|
|
2266
|
+
|
|
2177
2267
|
useEffect(() => {
|
|
2178
2268
|
ensureConnected();
|
|
2179
2269
|
}, [ensureConnected]);
|
|
@@ -2262,6 +2352,20 @@ function ChatApp({
|
|
|
2262
2352
|
}
|
|
2263
2353
|
}, [selection]);
|
|
2264
2354
|
|
|
2355
|
+
if (connectionState !== "connected") {
|
|
2356
|
+
return (
|
|
2357
|
+
<ConnectionScreen
|
|
2358
|
+
state={connectionState}
|
|
2359
|
+
errorMessage={connectionError}
|
|
2360
|
+
species={species}
|
|
2361
|
+
terminalRows={terminalRows}
|
|
2362
|
+
terminalColumns={terminalColumns}
|
|
2363
|
+
onRetry={retryConnection}
|
|
2364
|
+
onExit={onExit}
|
|
2365
|
+
/>
|
|
2366
|
+
);
|
|
2367
|
+
}
|
|
2368
|
+
|
|
2265
2369
|
return (
|
|
2266
2370
|
<Box flexDirection="column" height={terminalRows}>
|
|
2267
2371
|
<DefaultMainScreen
|
|
@@ -2274,8 +2378,9 @@ function ChatApp({
|
|
|
2274
2378
|
<Box flexDirection="column" flexGrow={1} overflow="hidden">
|
|
2275
2379
|
{visibleWindow.hiddenAbove > 0 ? (
|
|
2276
2380
|
<Text dimColor>
|
|
2277
|
-
{
|
|
2278
|
-
|
|
2381
|
+
{isCompact
|
|
2382
|
+
? `\u2191 ${visibleWindow.hiddenAbove} more above`
|
|
2383
|
+
: `\u2191 ${visibleWindow.hiddenAbove} more above (Shift+\u2191/Cmd+\u2191)`}
|
|
2279
2384
|
</Text>
|
|
2280
2385
|
) : null}
|
|
2281
2386
|
|
|
@@ -2341,12 +2446,14 @@ function ChatApp({
|
|
|
2341
2446
|
|
|
2342
2447
|
{!selection && !secretInput ? (
|
|
2343
2448
|
<Box flexDirection="column" flexShrink={0}>
|
|
2344
|
-
|
|
2345
|
-
|
|
2346
|
-
|
|
2347
|
-
|
|
2449
|
+
{isCompact ? null : (
|
|
2450
|
+
<Text dimColor>
|
|
2451
|
+
{unicodeOrFallback("\u2500", "-").repeat(terminalColumns)}
|
|
2452
|
+
</Text>
|
|
2453
|
+
)}
|
|
2454
|
+
<Box paddingLeft={isCompact ? 0 : 1} height={1} flexShrink={0}>
|
|
2348
2455
|
<Text color="green" bold>
|
|
2349
|
-
|
|
2456
|
+
{isCompact ? ">" : "you>"}
|
|
2350
2457
|
{" "}
|
|
2351
2458
|
</Text>
|
|
2352
2459
|
<TextInput
|
package/src/index.ts
CHANGED
|
@@ -15,6 +15,13 @@ import { ssh } from "./commands/ssh";
|
|
|
15
15
|
import { tunnel } from "./commands/tunnel";
|
|
16
16
|
import { use } from "./commands/use";
|
|
17
17
|
import { wake } from "./commands/wake";
|
|
18
|
+
import {
|
|
19
|
+
getActiveAssistant,
|
|
20
|
+
findAssistantByName,
|
|
21
|
+
loadLatestAssistant,
|
|
22
|
+
setActiveAssistant,
|
|
23
|
+
} from "./lib/assistant-config";
|
|
24
|
+
import { checkHealth } from "./lib/health-check";
|
|
18
25
|
|
|
19
26
|
const commands = {
|
|
20
27
|
clean,
|
|
@@ -37,37 +44,106 @@ const commands = {
|
|
|
37
44
|
|
|
38
45
|
type CommandName = keyof typeof commands;
|
|
39
46
|
|
|
47
|
+
function printHelp(): void {
|
|
48
|
+
console.log("Usage: vellum <command> [options]");
|
|
49
|
+
console.log("");
|
|
50
|
+
console.log("Commands:");
|
|
51
|
+
console.log(" clean Kill orphaned vellum processes");
|
|
52
|
+
console.log(" client Connect to a hatched assistant");
|
|
53
|
+
console.log(" hatch Create a new assistant instance");
|
|
54
|
+
console.log(" login Log in to the Vellum platform");
|
|
55
|
+
console.log(" logout Log out of the Vellum platform");
|
|
56
|
+
console.log(" pair Pair with a remote assistant via QR code");
|
|
57
|
+
console.log(
|
|
58
|
+
" ps List assistants (or processes for a specific assistant)",
|
|
59
|
+
);
|
|
60
|
+
console.log(" recover Restore a previously retired local assistant");
|
|
61
|
+
console.log(" retire Delete an assistant instance");
|
|
62
|
+
console.log(" setup Configure API keys interactively");
|
|
63
|
+
console.log(" sleep Stop the assistant process");
|
|
64
|
+
console.log(" ssh SSH into a remote assistant instance");
|
|
65
|
+
console.log(" tunnel Create a tunnel for a locally hosted assistant");
|
|
66
|
+
console.log(" use Set the active assistant for commands");
|
|
67
|
+
console.log(" wake Start the assistant and gateway");
|
|
68
|
+
console.log(" whoami Show current logged-in user");
|
|
69
|
+
console.log("");
|
|
70
|
+
console.log("Options:");
|
|
71
|
+
console.log(
|
|
72
|
+
" --no-color, --plain Disable colored output (honors NO_COLOR env)",
|
|
73
|
+
);
|
|
74
|
+
console.log(" --version, -v Show version");
|
|
75
|
+
console.log(" --help, -h Show this help");
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Check for --no-color / --plain flags and set NO_COLOR env var
|
|
80
|
+
* before any terminal capability detection runs.
|
|
81
|
+
*
|
|
82
|
+
* Per https://no-color.org/, setting NO_COLOR to any non-empty value
|
|
83
|
+
* signals that color output should be suppressed.
|
|
84
|
+
*/
|
|
85
|
+
function applyNoColorFlags(argv: string[]): void {
|
|
86
|
+
if (argv.includes("--no-color") || argv.includes("--plain")) {
|
|
87
|
+
process.env.NO_COLOR = "1";
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* If a running assistant is detected, launch the TUI client and return true.
|
|
93
|
+
* Otherwise return false so the caller can fall back to help text.
|
|
94
|
+
*/
|
|
95
|
+
async function tryLaunchClient(): Promise<boolean> {
|
|
96
|
+
const activeName = getActiveAssistant();
|
|
97
|
+
const entry = activeName
|
|
98
|
+
? findAssistantByName(activeName)
|
|
99
|
+
: loadLatestAssistant();
|
|
100
|
+
|
|
101
|
+
if (!entry) return false;
|
|
102
|
+
|
|
103
|
+
const url = entry.localUrl || entry.runtimeUrl;
|
|
104
|
+
if (!url) return false;
|
|
105
|
+
|
|
106
|
+
const result = await checkHealth(url, entry.bearerToken);
|
|
107
|
+
if (result.status !== "healthy") return false;
|
|
108
|
+
|
|
109
|
+
// Ensure the resolved assistant is active so client() can find it
|
|
110
|
+
// (client() independently reads the active assistant from config).
|
|
111
|
+
setActiveAssistant(String(entry.assistantId));
|
|
112
|
+
|
|
113
|
+
await client();
|
|
114
|
+
return true;
|
|
115
|
+
}
|
|
116
|
+
|
|
40
117
|
async function main() {
|
|
41
118
|
const args = process.argv.slice(2);
|
|
42
|
-
|
|
119
|
+
|
|
120
|
+
// Must run before any command or terminal-capabilities usage
|
|
121
|
+
applyNoColorFlags(args);
|
|
122
|
+
|
|
123
|
+
// Global flags that are not command names
|
|
124
|
+
const GLOBAL_FLAGS = new Set(["--no-color", "--plain"]);
|
|
125
|
+
const commandName = args.find((a) => !GLOBAL_FLAGS.has(a));
|
|
126
|
+
|
|
127
|
+
// Strip global flags from process.argv so subcommands that parse
|
|
128
|
+
// process.argv.slice(3) don't see them as positional arguments.
|
|
129
|
+
const filteredArgs = args.filter((a) => !GLOBAL_FLAGS.has(a));
|
|
130
|
+
process.argv = [...process.argv.slice(0, 2), ...filteredArgs];
|
|
43
131
|
|
|
44
132
|
if (commandName === "--version" || commandName === "-v") {
|
|
45
133
|
console.log(`@vellumai/cli v${cliPkg.version}`);
|
|
46
134
|
process.exit(0);
|
|
47
135
|
}
|
|
48
136
|
|
|
49
|
-
if (
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
console.log(
|
|
60
|
-
" ps List assistants (or processes for a specific assistant)",
|
|
61
|
-
);
|
|
62
|
-
console.log(" recover Restore a previously retired local assistant");
|
|
63
|
-
console.log(" retire Delete an assistant instance");
|
|
64
|
-
console.log(" setup Configure API keys interactively");
|
|
65
|
-
console.log(" sleep Stop the assistant process");
|
|
66
|
-
console.log(" ssh SSH into a remote assistant instance");
|
|
67
|
-
console.log(" tunnel Create a tunnel for a locally hosted assistant");
|
|
68
|
-
console.log(" use Set the active assistant for commands");
|
|
69
|
-
console.log(" wake Start the assistant and gateway");
|
|
70
|
-
console.log(" whoami Show current logged-in user");
|
|
137
|
+
if (commandName === "--help" || commandName === "-h") {
|
|
138
|
+
printHelp();
|
|
139
|
+
process.exit(0);
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
if (!commandName) {
|
|
143
|
+
const launched = await tryLaunchClient();
|
|
144
|
+
if (!launched) {
|
|
145
|
+
printHelp();
|
|
146
|
+
}
|
|
71
147
|
process.exit(0);
|
|
72
148
|
}
|
|
73
149
|
|
package/src/lib/docker.ts
CHANGED
|
@@ -7,7 +7,6 @@ import { saveAssistantEntry, setActiveAssistant } from "./assistant-config";
|
|
|
7
7
|
import type { AssistantEntry } from "./assistant-config";
|
|
8
8
|
import { DEFAULT_GATEWAY_PORT } from "./constants";
|
|
9
9
|
import type { Species } from "./constants";
|
|
10
|
-
import { discoverPublicUrl } from "./local";
|
|
11
10
|
import { generateRandomSuffix } from "./random-name";
|
|
12
11
|
import { exec, execOutput } from "./step-runner";
|
|
13
12
|
import {
|
|
@@ -34,6 +33,36 @@ async function ensureDockerInstalled(): Promise<void> {
|
|
|
34
33
|
}
|
|
35
34
|
|
|
36
35
|
if (!installed) {
|
|
36
|
+
// Check whether Homebrew is available before attempting to use it.
|
|
37
|
+
let hasBrew = false;
|
|
38
|
+
try {
|
|
39
|
+
await execOutput("brew", ["--version"]);
|
|
40
|
+
hasBrew = true;
|
|
41
|
+
} catch {
|
|
42
|
+
// brew not found
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
if (!hasBrew) {
|
|
46
|
+
console.log("🍺 Homebrew not found. Installing Homebrew...");
|
|
47
|
+
try {
|
|
48
|
+
await exec("bash", [
|
|
49
|
+
"-c",
|
|
50
|
+
'NONINTERACTIVE=1 /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"',
|
|
51
|
+
]);
|
|
52
|
+
} catch (err) {
|
|
53
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
54
|
+
throw new Error(
|
|
55
|
+
`Failed to install Homebrew. Please install Docker manually from https://www.docker.com/products/docker-desktop/\n${message}`,
|
|
56
|
+
);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// Homebrew on Apple Silicon installs to /opt/homebrew; add it to PATH
|
|
60
|
+
// so subsequent brew/colima/docker invocations work in this session.
|
|
61
|
+
if (!process.env.PATH?.includes("/opt/homebrew")) {
|
|
62
|
+
process.env.PATH = `/opt/homebrew/bin:/opt/homebrew/sbin:${process.env.PATH}`;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
37
66
|
console.log("🐳 Docker not found. Installing via Homebrew...");
|
|
38
67
|
try {
|
|
39
68
|
await exec("brew", ["install", "colima", "docker"]);
|
|
@@ -58,6 +87,21 @@ async function ensureDockerInstalled(): Promise<void> {
|
|
|
58
87
|
try {
|
|
59
88
|
await exec("docker", ["info"]);
|
|
60
89
|
} catch {
|
|
90
|
+
let hasColima = false;
|
|
91
|
+
try {
|
|
92
|
+
await execOutput("colima", ["version"]);
|
|
93
|
+
hasColima = true;
|
|
94
|
+
} catch {
|
|
95
|
+
// colima not found
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
if (!hasColima) {
|
|
99
|
+
throw new Error(
|
|
100
|
+
"Docker daemon is not running and Colima is not installed.\n" +
|
|
101
|
+
"Please start Docker Desktop, or install Colima with 'brew install colima' and run 'colima start'.",
|
|
102
|
+
);
|
|
103
|
+
}
|
|
104
|
+
|
|
61
105
|
console.log("🚀 Docker daemon not running. Starting Colima...");
|
|
62
106
|
try {
|
|
63
107
|
await exec("colima", ["start"]);
|
|
@@ -326,8 +370,10 @@ export async function hatchDocker(
|
|
|
326
370
|
);
|
|
327
371
|
}
|
|
328
372
|
|
|
329
|
-
|
|
330
|
-
|
|
373
|
+
// Docker containers bind to 0.0.0.0 so localhost always works. Skip
|
|
374
|
+
// mDNS/LAN discovery — the .local hostname often fails to resolve on the
|
|
375
|
+
// host machine itself (mDNS is designed for cross-device discovery).
|
|
376
|
+
const runtimeUrl = `http://localhost:${gatewayPort}`;
|
|
331
377
|
const dockerEntry: AssistantEntry = {
|
|
332
378
|
assistantId: instanceName,
|
|
333
379
|
runtimeUrl,
|
package/src/lib/health-check.ts
CHANGED
|
@@ -10,6 +10,93 @@ export interface HealthCheckResult {
|
|
|
10
10
|
detail: string | null;
|
|
11
11
|
}
|
|
12
12
|
|
|
13
|
+
interface OrgListResponse {
|
|
14
|
+
results: { id: string }[];
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
async function fetchOrganizationId(
|
|
18
|
+
platformUrl: string,
|
|
19
|
+
token: string,
|
|
20
|
+
): Promise<{ orgId: string } | { error: string }> {
|
|
21
|
+
try {
|
|
22
|
+
const response = await fetch(`${platformUrl}/v1/organizations/`, {
|
|
23
|
+
headers: { "X-Session-Token": token },
|
|
24
|
+
});
|
|
25
|
+
if (!response.ok) {
|
|
26
|
+
return { error: `org lookup failed (${response.status})` };
|
|
27
|
+
}
|
|
28
|
+
const body = (await response.json()) as OrgListResponse;
|
|
29
|
+
const orgId = body.results?.[0]?.id;
|
|
30
|
+
if (!orgId) {
|
|
31
|
+
return { error: "no organization found" };
|
|
32
|
+
}
|
|
33
|
+
return { orgId };
|
|
34
|
+
} catch {
|
|
35
|
+
return { error: "org lookup unreachable" };
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export async function checkManagedHealth(
|
|
40
|
+
runtimeUrl: string,
|
|
41
|
+
assistantId: string,
|
|
42
|
+
): Promise<HealthCheckResult> {
|
|
43
|
+
const { readPlatformToken } = await import("./platform-client.js");
|
|
44
|
+
const token = readPlatformToken();
|
|
45
|
+
if (!token) {
|
|
46
|
+
return {
|
|
47
|
+
status: "error (auth)",
|
|
48
|
+
detail: "not logged in — run `vellum login`",
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
const orgResult = await fetchOrganizationId(runtimeUrl, token);
|
|
53
|
+
if ("error" in orgResult) {
|
|
54
|
+
return {
|
|
55
|
+
status: "error (auth)",
|
|
56
|
+
detail: orgResult.error,
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
const { orgId } = orgResult;
|
|
60
|
+
|
|
61
|
+
try {
|
|
62
|
+
const url = `${runtimeUrl}/v1/assistants/${encodeURIComponent(assistantId)}/healthz/`;
|
|
63
|
+
const controller = new AbortController();
|
|
64
|
+
const timeoutId = setTimeout(
|
|
65
|
+
() => controller.abort(),
|
|
66
|
+
HEALTH_CHECK_TIMEOUT_MS,
|
|
67
|
+
);
|
|
68
|
+
|
|
69
|
+
const headers: Record<string, string> = {
|
|
70
|
+
"X-Session-Token": token,
|
|
71
|
+
"Vellum-Organization-Id": orgId,
|
|
72
|
+
};
|
|
73
|
+
|
|
74
|
+
const response = await fetch(url, {
|
|
75
|
+
signal: controller.signal,
|
|
76
|
+
headers,
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
clearTimeout(timeoutId);
|
|
80
|
+
|
|
81
|
+
if (!response.ok) {
|
|
82
|
+
return { status: `error (${response.status})`, detail: null };
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
const data = (await response.json()) as HealthResponse;
|
|
86
|
+
const status = data.status || "unknown";
|
|
87
|
+
return {
|
|
88
|
+
status,
|
|
89
|
+
detail: status !== "healthy" ? (data.message ?? null) : null,
|
|
90
|
+
};
|
|
91
|
+
} catch (error) {
|
|
92
|
+
const status =
|
|
93
|
+
error instanceof Error && error.name === "AbortError"
|
|
94
|
+
? "timeout"
|
|
95
|
+
: "unreachable";
|
|
96
|
+
return { status, detail: null };
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
13
100
|
export async function checkHealth(
|
|
14
101
|
runtimeUrl: string,
|
|
15
102
|
bearerToken?: string,
|
package/src/lib/http-client.ts
CHANGED
|
@@ -1,23 +1,3 @@
|
|
|
1
|
-
import { readFileSync } from "fs";
|
|
2
|
-
import { homedir } from "os";
|
|
3
|
-
import { join } from "path";
|
|
4
|
-
|
|
5
|
-
import { DEFAULT_DAEMON_PORT } from "./constants.js";
|
|
6
|
-
|
|
7
|
-
/**
|
|
8
|
-
* Resolve the HTTP port for the daemon runtime server.
|
|
9
|
-
* Uses RUNTIME_HTTP_PORT env var, or the default (7821).
|
|
10
|
-
*/
|
|
11
|
-
export function resolveDaemonPort(overridePort?: number): number {
|
|
12
|
-
if (overridePort !== undefined) return overridePort;
|
|
13
|
-
const envPort = process.env.RUNTIME_HTTP_PORT;
|
|
14
|
-
if (envPort) {
|
|
15
|
-
const parsed = parseInt(envPort, 10);
|
|
16
|
-
if (!isNaN(parsed)) return parsed;
|
|
17
|
-
}
|
|
18
|
-
return DEFAULT_DAEMON_PORT;
|
|
19
|
-
}
|
|
20
|
-
|
|
21
1
|
/**
|
|
22
2
|
* Build the base URL for the daemon HTTP server.
|
|
23
3
|
*/
|
|
@@ -25,23 +5,6 @@ export function buildDaemonUrl(port: number): string {
|
|
|
25
5
|
return `http://127.0.0.1:${port}`;
|
|
26
6
|
}
|
|
27
7
|
|
|
28
|
-
/**
|
|
29
|
-
* Read the HTTP bearer token from `<vellumDir>/http-token`.
|
|
30
|
-
* Respects BASE_DATA_DIR for named instances.
|
|
31
|
-
* Returns undefined if the token file doesn't exist or is empty.
|
|
32
|
-
*/
|
|
33
|
-
export function readHttpToken(instanceDir?: string): string | undefined {
|
|
34
|
-
const baseDataDir =
|
|
35
|
-
instanceDir ?? (process.env.BASE_DATA_DIR?.trim() || homedir());
|
|
36
|
-
const tokenPath = join(baseDataDir, ".vellum", "http-token");
|
|
37
|
-
try {
|
|
38
|
-
const token = readFileSync(tokenPath, "utf-8").trim();
|
|
39
|
-
return token || undefined;
|
|
40
|
-
} catch {
|
|
41
|
-
return undefined;
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
|
|
45
8
|
/**
|
|
46
9
|
* Perform an HTTP health check against the daemon's `/healthz` endpoint.
|
|
47
10
|
* Returns true if the daemon responds with HTTP 200, false otherwise.
|
|
@@ -82,32 +45,3 @@ export async function waitForDaemonReady(
|
|
|
82
45
|
}
|
|
83
46
|
return false;
|
|
84
47
|
}
|
|
85
|
-
|
|
86
|
-
/**
|
|
87
|
-
* Make an authenticated HTTP request to the daemon.
|
|
88
|
-
*
|
|
89
|
-
* @param port - The daemon's HTTP port
|
|
90
|
-
* @param path - The request path (e.g. `/v1/sessions`)
|
|
91
|
-
* @param options - Fetch options (method, body, etc.)
|
|
92
|
-
* @param bearerToken - The bearer token for authentication
|
|
93
|
-
* @returns The fetch Response
|
|
94
|
-
*/
|
|
95
|
-
export async function httpSend(
|
|
96
|
-
port: number,
|
|
97
|
-
path: string,
|
|
98
|
-
options: RequestInit = {},
|
|
99
|
-
bearerToken?: string,
|
|
100
|
-
): Promise<Response> {
|
|
101
|
-
const url = `${buildDaemonUrl(port)}${path}`;
|
|
102
|
-
const headers: Record<string, string> = {
|
|
103
|
-
"Content-Type": "application/json",
|
|
104
|
-
...(options.headers as Record<string, string> | undefined),
|
|
105
|
-
};
|
|
106
|
-
if (bearerToken) {
|
|
107
|
-
headers["Authorization"] = `Bearer ${bearerToken}`;
|
|
108
|
-
}
|
|
109
|
-
return fetch(url, {
|
|
110
|
-
...options,
|
|
111
|
-
headers,
|
|
112
|
-
});
|
|
113
|
-
}
|
package/src/lib/local.ts
CHANGED
|
@@ -528,46 +528,77 @@ export async function discoverPublicUrl(
|
|
|
528
528
|
): Promise<string | undefined> {
|
|
529
529
|
const effectivePort = port ?? GATEWAY_PORT;
|
|
530
530
|
|
|
531
|
-
//
|
|
532
|
-
// timeout (1s) doesn't block startup when a local address is immediately
|
|
533
|
-
// available.
|
|
531
|
+
// Start cloud metadata lookup (may take up to 1s on non-cloud hosts).
|
|
534
532
|
const cloudIpPromise = discoverCloudExternalIp();
|
|
535
533
|
|
|
536
|
-
// Resolve local address synchronously (no I/O).
|
|
537
|
-
const
|
|
534
|
+
// Resolve local address synchronously (no I/O) — does not log.
|
|
535
|
+
const localResult = discoverLocalUrl(effectivePort);
|
|
536
|
+
|
|
537
|
+
// Race: if cloud IP resolves quickly, prefer it; otherwise return the
|
|
538
|
+
// local URL immediately instead of blocking on the full metadata timeout.
|
|
539
|
+
const cloudIp = await Promise.race([
|
|
540
|
+
cloudIpPromise,
|
|
541
|
+
// Give cloud metadata a short grace period (150ms) before falling back
|
|
542
|
+
// to the local address. This is enough for on-cloud hosts where the
|
|
543
|
+
// metadata endpoint responds in single-digit ms, but avoids the full
|
|
544
|
+
// 1s timeout on non-cloud machines.
|
|
545
|
+
new Promise<undefined>((resolve) =>
|
|
546
|
+
setTimeout(() => resolve(undefined), 150),
|
|
547
|
+
),
|
|
548
|
+
]);
|
|
538
549
|
|
|
539
|
-
const cloudIp = await cloudIpPromise;
|
|
540
550
|
if (cloudIp) {
|
|
541
551
|
console.log(` Discovered external IP: ${cloudIp}`);
|
|
542
552
|
return `http://${cloudIp}:${effectivePort}`;
|
|
543
553
|
}
|
|
544
554
|
|
|
545
|
-
|
|
555
|
+
// Log the local address source only when we actually use it.
|
|
556
|
+
if (localResult.source === "hostname") {
|
|
557
|
+
console.log(` Discovered macOS local hostname: ${localResult.label}`);
|
|
558
|
+
} else if (localResult.source === "lan") {
|
|
559
|
+
console.log(` Discovered LAN IP: ${localResult.label}`);
|
|
560
|
+
}
|
|
561
|
+
|
|
562
|
+
return localResult.url;
|
|
546
563
|
}
|
|
547
564
|
|
|
548
565
|
/**
|
|
549
566
|
* Resolve a LAN-reachable URL without any async I/O. Returns the best local
|
|
550
|
-
* address or falls back to localhost.
|
|
567
|
+
* address or falls back to localhost. Does not emit any logs — the caller
|
|
568
|
+
* decides whether to log based on which result is actually used.
|
|
551
569
|
*/
|
|
552
|
-
function discoverLocalUrl(effectivePort: number):
|
|
570
|
+
function discoverLocalUrl(effectivePort: number): {
|
|
571
|
+
url: string;
|
|
572
|
+
source: "hostname" | "lan" | "localhost";
|
|
573
|
+
label?: string;
|
|
574
|
+
} {
|
|
553
575
|
// On macOS, prefer the .local hostname (Bonjour/mDNS) so other devices on
|
|
554
576
|
// the same network can reach the gateway by name.
|
|
555
577
|
if (platform() === "darwin") {
|
|
556
578
|
const localHostname = getMacLocalHostname();
|
|
557
579
|
if (localHostname) {
|
|
558
|
-
|
|
559
|
-
|
|
580
|
+
return {
|
|
581
|
+
url: `http://${localHostname}:${effectivePort}`,
|
|
582
|
+
source: "hostname",
|
|
583
|
+
label: localHostname,
|
|
584
|
+
};
|
|
560
585
|
}
|
|
561
586
|
}
|
|
562
587
|
|
|
563
588
|
const lanIp = getLocalLanIPv4();
|
|
564
589
|
if (lanIp) {
|
|
565
|
-
|
|
566
|
-
|
|
590
|
+
return {
|
|
591
|
+
url: `http://${lanIp}:${effectivePort}`,
|
|
592
|
+
source: "lan",
|
|
593
|
+
label: lanIp,
|
|
594
|
+
};
|
|
567
595
|
}
|
|
568
596
|
|
|
569
597
|
// Final fallback to localhost when no LAN address could be discovered.
|
|
570
|
-
return
|
|
598
|
+
return {
|
|
599
|
+
url: `http://localhost:${effectivePort}`,
|
|
600
|
+
source: "localhost",
|
|
601
|
+
};
|
|
571
602
|
}
|
|
572
603
|
|
|
573
604
|
/**
|
|
@@ -692,18 +723,14 @@ export async function startLocalDaemon(
|
|
|
692
723
|
watch: boolean = false,
|
|
693
724
|
resources: LocalInstanceResources,
|
|
694
725
|
): Promise<void> {
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
726
|
+
// Check for a compiled daemon binary adjacent to the CLI executable.
|
|
727
|
+
// This covers both the desktop app (VELLUM_DESKTOP_APP) and the case where
|
|
728
|
+
// the user runs the compiled CLI directly from the terminal (e.g. via a
|
|
729
|
+
// /usr/local/bin/vellum symlink into the app bundle).
|
|
730
|
+
const daemonBinary = join(dirname(process.execPath), "vellum-daemon");
|
|
731
|
+
if (existsSync(daemonBinary) && !watch) {
|
|
698
732
|
// In watch mode, skip the bundled binary and use source (bun --watch
|
|
699
733
|
// only works with source files, not compiled binaries).
|
|
700
|
-
const daemonBinary = join(dirname(process.execPath), "vellum-daemon");
|
|
701
|
-
if (!existsSync(daemonBinary)) {
|
|
702
|
-
throw new Error(
|
|
703
|
-
`vellum-daemon binary not found at ${daemonBinary}.\n` +
|
|
704
|
-
" Ensure the daemon binary is bundled alongside the CLI in the app bundle.",
|
|
705
|
-
);
|
|
706
|
-
}
|
|
707
734
|
|
|
708
735
|
const pidFile = resources.pidFile;
|
|
709
736
|
|
|
@@ -772,6 +799,7 @@ export async function startLocalDaemon(
|
|
|
772
799
|
// Forward optional config env vars the daemon may need
|
|
773
800
|
for (const key of [
|
|
774
801
|
"ANTHROPIC_API_KEY",
|
|
802
|
+
"APP_VERSION",
|
|
775
803
|
"BASE_DATA_DIR",
|
|
776
804
|
"QDRANT_HTTP_PORT",
|
|
777
805
|
"QDRANT_URL",
|
|
@@ -943,18 +971,11 @@ export async function startGateway(
|
|
|
943
971
|
|
|
944
972
|
let gateway;
|
|
945
973
|
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
//
|
|
949
|
-
//
|
|
950
|
-
|
|
951
|
-
if (!existsSync(gatewayBinary)) {
|
|
952
|
-
throw new Error(
|
|
953
|
-
`vellum-gateway binary not found at ${gatewayBinary}.\n` +
|
|
954
|
-
" Ensure the gateway binary is bundled alongside the CLI in the app bundle.",
|
|
955
|
-
);
|
|
956
|
-
}
|
|
957
|
-
|
|
974
|
+
const gatewayBinary = join(dirname(process.execPath), "vellum-gateway");
|
|
975
|
+
if (existsSync(gatewayBinary) && !watch) {
|
|
976
|
+
// Use the compiled gateway binary when available (desktop app or compiled
|
|
977
|
+
// CLI invoked from the terminal). In watch mode, skip the bundled binary
|
|
978
|
+
// and use source (bun --watch only works with source files).
|
|
958
979
|
const gatewayLogFd = openLogFile("hatch.log");
|
|
959
980
|
gateway = spawn(gatewayBinary, [], {
|
|
960
981
|
detached: true,
|
|
@@ -107,13 +107,6 @@ export function getTerminalCapabilities(): TerminalCapabilities {
|
|
|
107
107
|
return _cached;
|
|
108
108
|
}
|
|
109
109
|
|
|
110
|
-
// ── Convenience helpers ──────────────────────────────────────
|
|
111
|
-
|
|
112
|
-
/** True when colors should be used (any level above "none"). */
|
|
113
|
-
export function supportsColor(): boolean {
|
|
114
|
-
return getTerminalCapabilities().colorLevel !== "none";
|
|
115
|
-
}
|
|
116
|
-
|
|
117
110
|
/**
|
|
118
111
|
* Return `fancy` when unicode is supported, otherwise `fallback`.
|
|
119
112
|
*
|