@antseed/cli 0.1.178 → 0.1.179

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.
Files changed (39) hide show
  1. package/README.md +3 -0
  2. package/dist/cli/commands/apps/index.d.ts +42 -0
  3. package/dist/cli/commands/apps/index.d.ts.map +1 -0
  4. package/dist/cli/commands/apps/index.js +224 -0
  5. package/dist/cli/commands/apps/index.js.map +1 -0
  6. package/dist/cli/commands/apps/index.test.d.ts +2 -0
  7. package/dist/cli/commands/apps/index.test.d.ts.map +1 -0
  8. package/dist/cli/commands/apps/index.test.js +206 -0
  9. package/dist/cli/commands/apps/index.test.js.map +1 -0
  10. package/dist/cli/commands/buyer/deposit.d.ts.map +1 -1
  11. package/dist/cli/commands/buyer/deposit.js +9 -1
  12. package/dist/cli/commands/buyer/deposit.js.map +1 -1
  13. package/dist/cli/index.js +2 -0
  14. package/dist/cli/index.js.map +1 -1
  15. package/dist/gateway/gateway.test.js +31 -0
  16. package/dist/gateway/gateway.test.js.map +1 -1
  17. package/dist/gateway/server.d.ts.map +1 -1
  18. package/dist/gateway/server.js +4 -1
  19. package/dist/gateway/server.js.map +1 -1
  20. package/dist/proxy/buyer-proxy.d.ts.map +1 -1
  21. package/dist/proxy/buyer-proxy.js +9 -1
  22. package/dist/proxy/buyer-proxy.js.map +1 -1
  23. package/dist/proxy/buyer-proxy.test.js +77 -0
  24. package/dist/proxy/buyer-proxy.test.js.map +1 -1
  25. package/dist/proxy/credential-headers.d.ts +17 -0
  26. package/dist/proxy/credential-headers.d.ts.map +1 -0
  27. package/dist/proxy/credential-headers.js +29 -0
  28. package/dist/proxy/credential-headers.js.map +1 -0
  29. package/dist/proxy/deposit-watcher.d.ts +19 -0
  30. package/dist/proxy/deposit-watcher.d.ts.map +1 -1
  31. package/dist/proxy/deposit-watcher.js +44 -8
  32. package/dist/proxy/deposit-watcher.js.map +1 -1
  33. package/dist/proxy/deposit-watcher.test.js +27 -4
  34. package/dist/proxy/deposit-watcher.test.js.map +1 -1
  35. package/dist/system-proxy/proxy-server.js +2 -2
  36. package/dist/system-proxy/proxy-server.js.map +1 -1
  37. package/dist/system-proxy/proxy-server.test.js +40 -0
  38. package/dist/system-proxy/proxy-server.test.js.map +1 -1
  39. package/package.json +7 -6
package/README.md CHANGED
@@ -46,6 +46,9 @@ Command-line interface and web dashboard for the AntSeed Network — a P2P netwo
46
46
  | `antseed buyer set-authorized-wallet [--self]` | Authorize an external wallet in the browser, or authorize the buyer wallet itself |
47
47
  | `antseed buyer balance` | Check wallet and deposit balance |
48
48
  | `antseed network browse` | Browse peers, models, and pricing (same catalog as `/v1/models`) |
49
+ | `antseed apps [--json]` / `antseed apps status [--json]` | List every supported connected app (OpenCode, Codex, Claude Code, Claude Desktop, Hermes, Droid, T3 Code, pi, GooeyPi, Crush, Goose, Zed) with installed / connected / config path. `--json` output carries `"schemaVersion": 1` |
50
+ | `antseed apps connect <app> [--port <buyerPort>]` | Point the app's own config at the buyer proxy (default port: running buyer, then `buyer.proxyPort`, then 8377). Backs up the original to `<file>.antseed.bak`; also patches WSL installs on Windows. The app requests the `antseed` model, which needs a default route on the buyer (desktop model picker or `POST /_antseed/route`); connect warns when none is set |
51
+ | `antseed apps disconnect <app>` | Remove only what AntSeed added, restoring replaced values. The desktop app's Connected apps screen reflects CLI connects and disconnects |
49
52
  | **Session** | |
50
53
  | `antseed buyer connection get` | Show current session state (pinned service, peer) |
51
54
  | `antseed buyer connection set` | Update service/peer overrides on a running proxy |
@@ -0,0 +1,42 @@
1
+ import { type Command } from 'commander';
2
+ import { type ConnectedAppStatus } from '@antseed/connected-apps';
3
+ /** Bump when a field of the --json output changes meaning or is removed. */
4
+ export declare const APPS_JSON_SCHEMA_VERSION = 1;
5
+ export declare const DEFAULT_BUYER_PORT = 8377;
6
+ export type AppsContext = {
7
+ dataDir: string;
8
+ configPath: string;
9
+ };
10
+ export type AppsStatusReport = {
11
+ schemaVersion: typeof APPS_JSON_SCHEMA_VERSION;
12
+ apps: ConnectedAppStatus[];
13
+ };
14
+ export type AppsActionReport = {
15
+ schemaVersion: typeof APPS_JSON_SCHEMA_VERSION;
16
+ ok: boolean;
17
+ action: 'connect' | 'disconnect';
18
+ app: string;
19
+ displayName?: string;
20
+ /** connect only: buyer proxy port written into the config. */
21
+ buyerPort?: number;
22
+ /** disconnect only: false when the config carried nothing AntSeed added. */
23
+ changed?: boolean;
24
+ connected?: boolean;
25
+ configPath?: string;
26
+ warnings?: string[];
27
+ error?: string;
28
+ };
29
+ /** Buyer proxy port from buyer.state.json / config buyer.proxyPort, else 8377. */
30
+ export declare function resolveDefaultBuyerPort(ctx: AppsContext): Promise<number>;
31
+ export declare function getAppsStatus(ctx: AppsContext): AppsStatusReport;
32
+ /**
33
+ * The buyer's default route (`defaultRoutedModel` in buyer.state.json), which
34
+ * resolves the `antseed` model alias the patched configs carry. Null when no
35
+ * route is set — the buyer then rejects alias requests with no_default_route.
36
+ */
37
+ export declare function readDefaultRoutedModel(dataDir: string): string | null;
38
+ export declare function noDefaultRouteWarning(buyerPort: number): string;
39
+ export declare function connectApp(ctx: AppsContext, name: string, buyerPort?: number): Promise<AppsActionReport>;
40
+ export declare function disconnectApp(ctx: AppsContext, name: string): AppsActionReport;
41
+ export declare function registerAppsCommands(program: Command): void;
42
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/cli/commands/apps/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAwB,KAAK,OAAO,EAAE,MAAM,WAAW,CAAA;AAE9D,OAAO,EAUL,KAAK,kBAAkB,EACxB,MAAM,yBAAyB,CAAA;AAOhC,4EAA4E;AAC5E,eAAO,MAAM,wBAAwB,IAAI,CAAA;AACzC,eAAO,MAAM,kBAAkB,OAAO,CAAA;AAEtC,MAAM,MAAM,WAAW,GAAG;IACxB,OAAO,EAAE,MAAM,CAAA;IACf,UAAU,EAAE,MAAM,CAAA;CACnB,CAAA;AAED,MAAM,MAAM,gBAAgB,GAAG;IAC7B,aAAa,EAAE,OAAO,wBAAwB,CAAA;IAC9C,IAAI,EAAE,kBAAkB,EAAE,CAAA;CAC3B,CAAA;AAED,MAAM,MAAM,gBAAgB,GAAG;IAC7B,aAAa,EAAE,OAAO,wBAAwB,CAAA;IAC9C,EAAE,EAAE,OAAO,CAAA;IACX,MAAM,EAAE,SAAS,GAAG,YAAY,CAAA;IAChC,GAAG,EAAE,MAAM,CAAA;IACX,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,8DAA8D;IAC9D,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,4EAA4E;IAC5E,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,SAAS,CAAC,EAAE,OAAO,CAAA;IACnB,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAA;IACnB,KAAK,CAAC,EAAE,MAAM,CAAA;CACf,CAAA;AAUD,kFAAkF;AAClF,wBAAsB,uBAAuB,CAAC,GAAG,EAAE,WAAW,GAAG,OAAO,CAAC,MAAM,CAAC,CAO/E;AAED,wBAAgB,aAAa,CAAC,GAAG,EAAE,WAAW,GAAG,gBAAgB,CAMhE;AAED;;;;GAIG;AACH,wBAAgB,sBAAsB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAQrE;AAED,wBAAgB,qBAAqB,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAI/D;AAQD,wBAAsB,UAAU,CAAC,GAAG,EAAE,WAAW,EAAE,IAAI,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,gBAAgB,CAAC,CAqC9G;AAED,wBAAgB,aAAa,CAAC,GAAG,EAAE,WAAW,EAAE,IAAI,EAAE,MAAM,GAAG,gBAAgB,CA+B9E;AAgDD,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAiC3D"}
@@ -0,0 +1,224 @@
1
+ import { InvalidArgumentError } from 'commander';
2
+ import chalk from 'chalk';
3
+ import { connectedAppStatus, findConnectedAppProfile, loadConnectedAppProfiles, markProfileConnected, markProfileDisconnected, removeConfigPatch, wslTargetsPath, writeConfigPatch, } from '@antseed/connected-apps';
4
+ import { mkdirSync, readFileSync } from 'node:fs';
5
+ import { dirname, join } from 'node:path';
6
+ import { getGlobalOptions } from '../types.js';
7
+ import { parsePositiveInteger } from '../parse-positive-integer.js';
8
+ import { resolveDefaultAntseedBaseUrl } from '../wrapped-tools.js';
9
+ /** Bump when a field of the --json output changes meaning or is removed. */
10
+ export const APPS_JSON_SCHEMA_VERSION = 1;
11
+ export const DEFAULT_BUYER_PORT = 8377;
12
+ function profiles() {
13
+ return loadConnectedAppProfiles();
14
+ }
15
+ function unknownAppError(name, all) {
16
+ return `Unknown app "${name}". Supported apps: ${all.map((profile) => profile.name).join(', ')}`;
17
+ }
18
+ /** Buyer proxy port from buyer.state.json / config buyer.proxyPort, else 8377. */
19
+ export async function resolveDefaultBuyerPort(ctx) {
20
+ try {
21
+ const port = Number(new URL(await resolveDefaultAntseedBaseUrl(ctx.dataDir, ctx.configPath)).port);
22
+ return Number.isInteger(port) && port > 0 && port <= 65535 ? port : DEFAULT_BUYER_PORT;
23
+ }
24
+ catch {
25
+ return DEFAULT_BUYER_PORT;
26
+ }
27
+ }
28
+ export function getAppsStatus(ctx) {
29
+ const targets = wslTargetsPath(ctx.dataDir);
30
+ return {
31
+ schemaVersion: APPS_JSON_SCHEMA_VERSION,
32
+ apps: profiles().map((profile) => connectedAppStatus(profile, targets)),
33
+ };
34
+ }
35
+ /**
36
+ * The buyer's default route (`defaultRoutedModel` in buyer.state.json), which
37
+ * resolves the `antseed` model alias the patched configs carry. Null when no
38
+ * route is set — the buyer then rejects alias requests with no_default_route.
39
+ */
40
+ export function readDefaultRoutedModel(dataDir) {
41
+ try {
42
+ const state = JSON.parse(readFileSync(join(dataDir, 'buyer.state.json'), 'utf8'));
43
+ const model = typeof state['defaultRoutedModel'] === 'string' ? state['defaultRoutedModel'].trim() : '';
44
+ return model.length > 0 ? model : null;
45
+ }
46
+ catch {
47
+ return null;
48
+ }
49
+ }
50
+ export function noDefaultRouteWarning(buyerPort) {
51
+ return 'No default route is set on the buyer, so requests for model "antseed" will fail with no_default_route. '
52
+ + 'Pick a model in the AntSeed desktop app, or set one on the running buyer: '
53
+ + `curl -X POST http://localhost:${buyerPort}/_antseed/route -H 'content-type: application/json' -d '{"model":"<peerId>@<service>"}'`;
54
+ }
55
+ function ensureStateDir(ctx) {
56
+ const targets = wslTargetsPath(ctx.dataDir);
57
+ mkdirSync(dirname(targets), { recursive: true });
58
+ return targets;
59
+ }
60
+ export async function connectApp(ctx, name, buyerPort) {
61
+ const all = profiles();
62
+ const profile = findConnectedAppProfile(name, all);
63
+ if (!profile) {
64
+ return { schemaVersion: APPS_JSON_SCHEMA_VERSION, ok: false, action: 'connect', app: name, error: unknownAppError(name, all) };
65
+ }
66
+ const port = buyerPort ?? await resolveDefaultBuyerPort(ctx);
67
+ const warnings = [];
68
+ if (!readDefaultRoutedModel(ctx.dataDir))
69
+ warnings.push(noDefaultRouteWarning(port));
70
+ if (profile.configPatch.format === 'claude-desktop') {
71
+ warnings.push('Claude Desktop is routed through the AntSeed desktop app\'s local Claude gateway; it only works while the desktop app is running.');
72
+ }
73
+ try {
74
+ writeConfigPatch(profile.configPatch, port, ensureStateDir(ctx));
75
+ }
76
+ catch (err) {
77
+ return {
78
+ schemaVersion: APPS_JSON_SCHEMA_VERSION,
79
+ ok: false,
80
+ action: 'connect',
81
+ app: profile.name,
82
+ displayName: profile.displayName,
83
+ error: err instanceof Error ? err.message : String(err),
84
+ };
85
+ }
86
+ markProfileConnected(ctx.dataDir, profile.name);
87
+ const status = connectedAppStatus(profile, wslTargetsPath(ctx.dataDir));
88
+ return {
89
+ schemaVersion: APPS_JSON_SCHEMA_VERSION,
90
+ ok: true,
91
+ action: 'connect',
92
+ app: profile.name,
93
+ displayName: profile.displayName,
94
+ buyerPort: port,
95
+ connected: status.connected,
96
+ configPath: status.configPath,
97
+ ...(warnings.length > 0 ? { warnings } : {}),
98
+ };
99
+ }
100
+ export function disconnectApp(ctx, name) {
101
+ const all = profiles();
102
+ const profile = findConnectedAppProfile(name, all);
103
+ if (!profile) {
104
+ return { schemaVersion: APPS_JSON_SCHEMA_VERSION, ok: false, action: 'disconnect', app: name, error: unknownAppError(name, all) };
105
+ }
106
+ let changed;
107
+ try {
108
+ changed = removeConfigPatch(profile.configPatch, ensureStateDir(ctx));
109
+ }
110
+ catch (err) {
111
+ return {
112
+ schemaVersion: APPS_JSON_SCHEMA_VERSION,
113
+ ok: false,
114
+ action: 'disconnect',
115
+ app: profile.name,
116
+ displayName: profile.displayName,
117
+ error: err instanceof Error ? err.message : String(err),
118
+ };
119
+ }
120
+ markProfileDisconnected(ctx.dataDir, profile.name);
121
+ const status = connectedAppStatus(profile, wslTargetsPath(ctx.dataDir));
122
+ return {
123
+ schemaVersion: APPS_JSON_SCHEMA_VERSION,
124
+ ok: true,
125
+ action: 'disconnect',
126
+ app: profile.name,
127
+ displayName: profile.displayName,
128
+ changed,
129
+ connected: status.connected,
130
+ configPath: status.configPath,
131
+ };
132
+ }
133
+ function printStatus(report) {
134
+ const nameWidth = Math.max(3, ...report.apps.map((app) => app.name.length));
135
+ const labelWidth = Math.max(4, ...report.apps.map((app) => app.displayName.length));
136
+ console.log(chalk.bold(`${'APP'.padEnd(nameWidth)} ${'NAME'.padEnd(labelWidth)} ${'INSTALLED'} ${'CONNECTED'} CONFIG`));
137
+ for (const app of report.apps) {
138
+ const installed = (app.installed ? 'yes' : 'no').padEnd(9);
139
+ const connected = (app.connected ? 'yes' : 'no').padEnd(9);
140
+ console.log([
141
+ app.name.padEnd(nameWidth),
142
+ app.displayName.padEnd(labelWidth),
143
+ app.installed ? chalk.green(installed) : chalk.dim(installed),
144
+ app.connected ? chalk.green(connected) : chalk.dim(connected),
145
+ chalk.dim(app.configPath),
146
+ ].join(' '));
147
+ }
148
+ }
149
+ function parseBuyerPort(value) {
150
+ const port = parsePositiveInteger(value);
151
+ if (port > 65535)
152
+ throw new InvalidArgumentError('Must be a port between 1 and 65535.');
153
+ return port;
154
+ }
155
+ function emit(report, json) {
156
+ if (!report.ok)
157
+ process.exitCode = 1;
158
+ if (json) {
159
+ console.log(JSON.stringify(report, null, 2));
160
+ return;
161
+ }
162
+ if (!report.ok) {
163
+ console.error(chalk.red(report.error ?? `${report.action} failed`));
164
+ return;
165
+ }
166
+ const label = report.displayName ?? report.app;
167
+ if (report.action === 'connect') {
168
+ console.log(chalk.green(`${label}: connected to the AntSeed buyer on port ${report.buyerPort}`));
169
+ console.log(chalk.dim(`Config: ${report.configPath}`));
170
+ console.log(chalk.dim('The app uses the model "antseed", which the buyer resolves to its current default route. Restart the app if it is running.'));
171
+ }
172
+ else if (report.changed) {
173
+ console.log(chalk.green(`${label}: disconnected; AntSeed's settings were removed from ${report.configPath}`));
174
+ }
175
+ else {
176
+ console.log(chalk.dim(`${label}: nothing to disconnect (no AntSeed settings found)`));
177
+ }
178
+ for (const warning of report.warnings ?? [])
179
+ console.log(chalk.yellow(warning));
180
+ }
181
+ export function registerAppsCommands(program) {
182
+ const apps = program
183
+ .command('apps')
184
+ .description('Connect local AI tools (Codex, Claude Code, OpenCode, …) to the AntSeed buyer by editing their config')
185
+ .option('--json', 'print machine-readable JSON')
186
+ .action((options) => {
187
+ runStatus(apps, options.json === true);
188
+ });
189
+ apps.command('status')
190
+ .description('List every supported app: installed, connected, and its config path')
191
+ .option('--json', 'print machine-readable JSON')
192
+ .action((options, command) => {
193
+ runStatus(command, options.json === true || command.optsWithGlobals()['json'] === true);
194
+ });
195
+ apps.command('connect')
196
+ .description('Point an app\'s config at the AntSeed buyer proxy (backs up the original first)')
197
+ .argument('<app>', 'app name, as listed by `antseed apps`')
198
+ .option('--port <buyerPort>', 'buyer proxy port (default: running buyer / buyer.proxyPort / 8377)', parseBuyerPort)
199
+ .option('--json', 'print machine-readable JSON')
200
+ .action(async (app, options, command) => {
201
+ const ctx = context(command);
202
+ emit(await connectApp(ctx, app, options.port), options.json === true || command.optsWithGlobals()['json'] === true);
203
+ });
204
+ apps.command('disconnect')
205
+ .description('Remove only what AntSeed added to an app\'s config, restoring replaced values')
206
+ .argument('<app>', 'app name, as listed by `antseed apps`')
207
+ .option('--json', 'print machine-readable JSON')
208
+ .action((app, options, command) => {
209
+ emit(disconnectApp(context(command), app), options.json === true || command.optsWithGlobals()['json'] === true);
210
+ });
211
+ }
212
+ function context(command) {
213
+ const globalOptions = getGlobalOptions(command);
214
+ return { dataDir: globalOptions.dataDir, configPath: globalOptions.config };
215
+ }
216
+ function runStatus(command, json) {
217
+ const report = getAppsStatus(context(command));
218
+ if (json) {
219
+ console.log(JSON.stringify(report, null, 2));
220
+ return;
221
+ }
222
+ printStatus(report);
223
+ }
224
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/cli/commands/apps/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,oBAAoB,EAAgB,MAAM,WAAW,CAAA;AAC9D,OAAO,KAAK,MAAM,OAAO,CAAA;AACzB,OAAO,EACL,kBAAkB,EAClB,uBAAuB,EACvB,wBAAwB,EACxB,oBAAoB,EACpB,uBAAuB,EACvB,iBAAiB,EACjB,cAAc,EACd,gBAAgB,GAGjB,MAAM,yBAAyB,CAAA;AAChC,OAAO,EAAE,SAAS,EAAE,YAAY,EAAE,MAAM,SAAS,CAAA;AACjD,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAA;AACzC,OAAO,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAA;AAC9C,OAAO,EAAE,oBAAoB,EAAE,MAAM,8BAA8B,CAAA;AACnE,OAAO,EAAE,4BAA4B,EAAE,MAAM,qBAAqB,CAAA;AAElE,4EAA4E;AAC5E,MAAM,CAAC,MAAM,wBAAwB,GAAG,CAAC,CAAA;AACzC,MAAM,CAAC,MAAM,kBAAkB,GAAG,IAAI,CAAA;AA4BtC,SAAS,QAAQ;IACf,OAAO,wBAAwB,EAAE,CAAA;AACnC,CAAC;AAED,SAAS,eAAe,CAAC,IAAY,EAAE,GAAmC;IACxE,OAAO,gBAAgB,IAAI,sBAAsB,GAAG,CAAC,GAAG,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAA;AAClG,CAAC;AAED,kFAAkF;AAClF,MAAM,CAAC,KAAK,UAAU,uBAAuB,CAAC,GAAgB;IAC5D,IAAI,CAAC;QACH,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI,GAAG,CAAC,MAAM,4BAA4B,CAAC,GAAG,CAAC,OAAO,EAAE,GAAG,CAAC,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC,CAAA;QAClG,OAAO,MAAM,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,IAAI,GAAG,CAAC,IAAI,IAAI,IAAI,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,kBAAkB,CAAA;IACxF,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,kBAAkB,CAAA;IAC3B,CAAC;AACH,CAAC;AAED,MAAM,UAAU,aAAa,CAAC,GAAgB;IAC5C,MAAM,OAAO,GAAG,cAAc,CAAC,GAAG,CAAC,OAAO,CAAC,CAAA;IAC3C,OAAO;QACL,aAAa,EAAE,wBAAwB;QACvC,IAAI,EAAE,QAAQ,EAAE,CAAC,GAAG,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,kBAAkB,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;KACxE,CAAA;AACH,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,sBAAsB,CAAC,OAAe;IACpD,IAAI,CAAC;QACH,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,IAAI,CAAC,OAAO,EAAE,kBAAkB,CAAC,EAAE,MAAM,CAAC,CAA4B,CAAA;QAC5G,MAAM,KAAK,GAAG,OAAO,KAAK,CAAC,oBAAoB,CAAC,KAAK,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,oBAAoB,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAA;QACvG,OAAO,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAA;IACxC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAA;IACb,CAAC;AACH,CAAC;AAED,MAAM,UAAU,qBAAqB,CAAC,SAAiB;IACrD,OAAO,yGAAyG;UAC5G,4EAA4E;UAC5E,iCAAiC,SAAS,yFAAyF,CAAA;AACzI,CAAC;AAED,SAAS,cAAc,CAAC,GAAgB;IACtC,MAAM,OAAO,GAAG,cAAc,CAAC,GAAG,CAAC,OAAO,CAAC,CAAA;IAC3C,SAAS,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAA;IAChD,OAAO,OAAO,CAAA;AAChB,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,UAAU,CAAC,GAAgB,EAAE,IAAY,EAAE,SAAkB;IACjF,MAAM,GAAG,GAAG,QAAQ,EAAE,CAAA;IACtB,MAAM,OAAO,GAAG,uBAAuB,CAAC,IAAI,EAAE,GAAG,CAAC,CAAA;IAClD,IAAI,CAAC,OAAO,EAAE,CAAC;QACb,OAAO,EAAE,aAAa,EAAE,wBAAwB,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,SAAS,EAAE,GAAG,EAAE,IAAI,EAAE,KAAK,EAAE,eAAe,CAAC,IAAI,EAAE,GAAG,CAAC,EAAE,CAAA;IAChI,CAAC;IACD,MAAM,IAAI,GAAG,SAAS,IAAI,MAAM,uBAAuB,CAAC,GAAG,CAAC,CAAA;IAC5D,MAAM,QAAQ,GAAa,EAAE,CAAA;IAC7B,IAAI,CAAC,sBAAsB,CAAC,GAAG,CAAC,OAAO,CAAC;QAAE,QAAQ,CAAC,IAAI,CAAC,qBAAqB,CAAC,IAAI,CAAC,CAAC,CAAA;IACpF,IAAI,OAAO,CAAC,WAAW,CAAC,MAAM,KAAK,gBAAgB,EAAE,CAAC;QACpD,QAAQ,CAAC,IAAI,CAAC,mIAAmI,CAAC,CAAA;IACpJ,CAAC;IACD,IAAI,CAAC;QACH,gBAAgB,CAAC,OAAO,CAAC,WAAW,EAAE,IAAI,EAAE,cAAc,CAAC,GAAG,CAAC,CAAC,CAAA;IAClE,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,OAAO;YACL,aAAa,EAAE,wBAAwB;YACvC,EAAE,EAAE,KAAK;YACT,MAAM,EAAE,SAAS;YACjB,GAAG,EAAE,OAAO,CAAC,IAAI;YACjB,WAAW,EAAE,OAAO,CAAC,WAAW;YAChC,KAAK,EAAE,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC;SACxD,CAAA;IACH,CAAC;IACD,oBAAoB,CAAC,GAAG,CAAC,OAAO,EAAE,OAAO,CAAC,IAAI,CAAC,CAAA;IAC/C,MAAM,MAAM,GAAG,kBAAkB,CAAC,OAAO,EAAE,cAAc,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAA;IACvE,OAAO;QACL,aAAa,EAAE,wBAAwB;QACvC,EAAE,EAAE,IAAI;QACR,MAAM,EAAE,SAAS;QACjB,GAAG,EAAE,OAAO,CAAC,IAAI;QACjB,WAAW,EAAE,OAAO,CAAC,WAAW;QAChC,SAAS,EAAE,IAAI;QACf,SAAS,EAAE,MAAM,CAAC,SAAS;QAC3B,UAAU,EAAE,MAAM,CAAC,UAAU;QAC7B,GAAG,CAAC,QAAQ,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;KAC7C,CAAA;AACH,CAAC;AAED,MAAM,UAAU,aAAa,CAAC,GAAgB,EAAE,IAAY;IAC1D,MAAM,GAAG,GAAG,QAAQ,EAAE,CAAA;IACtB,MAAM,OAAO,GAAG,uBAAuB,CAAC,IAAI,EAAE,GAAG,CAAC,CAAA;IAClD,IAAI,CAAC,OAAO,EAAE,CAAC;QACb,OAAO,EAAE,aAAa,EAAE,wBAAwB,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,YAAY,EAAE,GAAG,EAAE,IAAI,EAAE,KAAK,EAAE,eAAe,CAAC,IAAI,EAAE,GAAG,CAAC,EAAE,CAAA;IACnI,CAAC;IACD,IAAI,OAAgB,CAAA;IACpB,IAAI,CAAC;QACH,OAAO,GAAG,iBAAiB,CAAC,OAAO,CAAC,WAAW,EAAE,cAAc,CAAC,GAAG,CAAC,CAAC,CAAA;IACvE,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,OAAO;YACL,aAAa,EAAE,wBAAwB;YACvC,EAAE,EAAE,KAAK;YACT,MAAM,EAAE,YAAY;YACpB,GAAG,EAAE,OAAO,CAAC,IAAI;YACjB,WAAW,EAAE,OAAO,CAAC,WAAW;YAChC,KAAK,EAAE,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC;SACxD,CAAA;IACH,CAAC;IACD,uBAAuB,CAAC,GAAG,CAAC,OAAO,EAAE,OAAO,CAAC,IAAI,CAAC,CAAA;IAClD,MAAM,MAAM,GAAG,kBAAkB,CAAC,OAAO,EAAE,cAAc,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAA;IACvE,OAAO;QACL,aAAa,EAAE,wBAAwB;QACvC,EAAE,EAAE,IAAI;QACR,MAAM,EAAE,YAAY;QACpB,GAAG,EAAE,OAAO,CAAC,IAAI;QACjB,WAAW,EAAE,OAAO,CAAC,WAAW;QAChC,OAAO;QACP,SAAS,EAAE,MAAM,CAAC,SAAS;QAC3B,UAAU,EAAE,MAAM,CAAC,UAAU;KAC9B,CAAA;AACH,CAAC;AAED,SAAS,WAAW,CAAC,MAAwB;IAC3C,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,GAAG,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAA;IAC3E,MAAM,UAAU,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,GAAG,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC,CAAA;IACnF,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,KAAK,CAAC,MAAM,CAAC,SAAS,CAAC,KAAK,MAAM,CAAC,MAAM,CAAC,UAAU,CAAC,KAAK,WAAW,KAAK,WAAW,UAAU,CAAC,CAAC,CAAA;IAC3H,KAAK,MAAM,GAAG,IAAI,MAAM,CAAC,IAAI,EAAE,CAAC;QAC9B,MAAM,SAAS,GAAG,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAA;QAC1D,MAAM,SAAS,GAAG,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAA;QAC1D,OAAO,CAAC,GAAG,CAAC;YACV,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC;YAC1B,GAAG,CAAC,WAAW,CAAC,MAAM,CAAC,UAAU,CAAC;YAClC,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,SAAS,CAAC;YAC7D,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,SAAS,CAAC;YAC7D,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,UAAU,CAAC;SAC1B,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAA;IACf,CAAC;AACH,CAAC;AAED,SAAS,cAAc,CAAC,KAAa;IACnC,MAAM,IAAI,GAAG,oBAAoB,CAAC,KAAK,CAAC,CAAA;IACxC,IAAI,IAAI,GAAG,KAAK;QAAE,MAAM,IAAI,oBAAoB,CAAC,qCAAqC,CAAC,CAAA;IACvF,OAAO,IAAI,CAAA;AACb,CAAC;AAED,SAAS,IAAI,CAAC,MAAwB,EAAE,IAAa;IACnD,IAAI,CAAC,MAAM,CAAC,EAAE;QAAE,OAAO,CAAC,QAAQ,GAAG,CAAC,CAAA;IACpC,IAAI,IAAI,EAAE,CAAC;QACT,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAA;QAC5C,OAAM;IACR,CAAC;IACD,IAAI,CAAC,MAAM,CAAC,EAAE,EAAE,CAAC;QACf,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,MAAM,CAAC,KAAK,IAAI,GAAG,MAAM,CAAC,MAAM,SAAS,CAAC,CAAC,CAAA;QACnE,OAAM;IACR,CAAC;IACD,MAAM,KAAK,GAAG,MAAM,CAAC,WAAW,IAAI,MAAM,CAAC,GAAG,CAAA;IAC9C,IAAI,MAAM,CAAC,MAAM,KAAK,SAAS,EAAE,CAAC;QAChC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,KAAK,4CAA4C,MAAM,CAAC,SAAS,EAAE,CAAC,CAAC,CAAA;QAChG,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,WAAW,MAAM,CAAC,UAAU,EAAE,CAAC,CAAC,CAAA;QACtD,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,4HAA4H,CAAC,CAAC,CAAA;IACtJ,CAAC;SAAM,IAAI,MAAM,CAAC,OAAO,EAAE,CAAC;QAC1B,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,KAAK,wDAAwD,MAAM,CAAC,UAAU,EAAE,CAAC,CAAC,CAAA;IAC/G,CAAC;SAAM,CAAC;QACN,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,KAAK,qDAAqD,CAAC,CAAC,CAAA;IACvF,CAAC;IACD,KAAK,MAAM,OAAO,IAAI,MAAM,CAAC,QAAQ,IAAI,EAAE;QAAE,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAA;AACjF,CAAC;AAED,MAAM,UAAU,oBAAoB,CAAC,OAAgB;IACnD,MAAM,IAAI,GAAG,OAAO;SACjB,OAAO,CAAC,MAAM,CAAC;SACf,WAAW,CAAC,uGAAuG,CAAC;SACpH,MAAM,CAAC,QAAQ,EAAE,6BAA6B,CAAC;SAC/C,MAAM,CAAC,CAAC,OAA2B,EAAE,EAAE;QACtC,SAAS,CAAC,IAAI,EAAE,OAAO,CAAC,IAAI,KAAK,IAAI,CAAC,CAAA;IACxC,CAAC,CAAC,CAAA;IAEJ,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC;SACnB,WAAW,CAAC,qEAAqE,CAAC;SAClF,MAAM,CAAC,QAAQ,EAAE,6BAA6B,CAAC;SAC/C,MAAM,CAAC,CAAC,OAA2B,EAAE,OAAgB,EAAE,EAAE;QACxD,SAAS,CAAC,OAAO,EAAE,OAAO,CAAC,IAAI,KAAK,IAAI,IAAI,OAAO,CAAC,eAAe,EAAE,CAAC,MAAM,CAAC,KAAK,IAAI,CAAC,CAAA;IACzF,CAAC,CAAC,CAAA;IAEJ,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC;SACpB,WAAW,CAAC,iFAAiF,CAAC;SAC9F,QAAQ,CAAC,OAAO,EAAE,uCAAuC,CAAC;SAC1D,MAAM,CAAC,oBAAoB,EAAE,oEAAoE,EAAE,cAAc,CAAC;SAClH,MAAM,CAAC,QAAQ,EAAE,6BAA6B,CAAC;SAC/C,MAAM,CAAC,KAAK,EAAE,GAAW,EAAE,OAA0C,EAAE,OAAgB,EAAE,EAAE;QAC1F,MAAM,GAAG,GAAG,OAAO,CAAC,OAAO,CAAC,CAAA;QAC5B,IAAI,CAAC,MAAM,UAAU,CAAC,GAAG,EAAE,GAAG,EAAE,OAAO,CAAC,IAAI,CAAC,EAAE,OAAO,CAAC,IAAI,KAAK,IAAI,IAAI,OAAO,CAAC,eAAe,EAAE,CAAC,MAAM,CAAC,KAAK,IAAI,CAAC,CAAA;IACrH,CAAC,CAAC,CAAA;IAEJ,IAAI,CAAC,OAAO,CAAC,YAAY,CAAC;SACvB,WAAW,CAAC,+EAA+E,CAAC;SAC5F,QAAQ,CAAC,OAAO,EAAE,uCAAuC,CAAC;SAC1D,MAAM,CAAC,QAAQ,EAAE,6BAA6B,CAAC;SAC/C,MAAM,CAAC,CAAC,GAAW,EAAE,OAA2B,EAAE,OAAgB,EAAE,EAAE;QACrE,IAAI,CAAC,aAAa,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,GAAG,CAAC,EAAE,OAAO,CAAC,IAAI,KAAK,IAAI,IAAI,OAAO,CAAC,eAAe,EAAE,CAAC,MAAM,CAAC,KAAK,IAAI,CAAC,CAAA;IACjH,CAAC,CAAC,CAAA;AACN,CAAC;AAED,SAAS,OAAO,CAAC,OAAgB;IAC/B,MAAM,aAAa,GAAG,gBAAgB,CAAC,OAAO,CAAC,CAAA;IAC/C,OAAO,EAAE,OAAO,EAAE,aAAa,CAAC,OAAO,EAAE,UAAU,EAAE,aAAa,CAAC,MAAM,EAAE,CAAA;AAC7E,CAAC;AAED,SAAS,SAAS,CAAC,OAAgB,EAAE,IAAa;IAChD,MAAM,MAAM,GAAG,aAAa,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,CAAA;IAC9C,IAAI,IAAI,EAAE,CAAC;QACT,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAA;QAC5C,OAAM;IACR,CAAC;IACD,WAAW,CAAC,MAAM,CAAC,CAAA;AACrB,CAAC"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=index.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.test.d.ts","sourceRoot":"","sources":["../../../../src/cli/commands/apps/index.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,206 @@
1
+ import test from 'node:test';
2
+ import assert from 'node:assert/strict';
3
+ import { spawnSync } from 'node:child_process';
4
+ import { existsSync } from 'node:fs';
5
+ import { mkdir, mkdtemp, readFile, rm, writeFile } from 'node:fs/promises';
6
+ import { tmpdir } from 'node:os';
7
+ import { dirname, join, resolve } from 'node:path';
8
+ import { fileURLToPath } from 'node:url';
9
+ import { DEFAULT_APP_PROFILES } from '@antseed/connected-apps';
10
+ const CLI_INDEX = resolve(dirname(fileURLToPath(import.meta.url)), '..', '..', 'index.js');
11
+ async function createWorkspace() {
12
+ const home = await mkdtemp(join(tmpdir(), 'antseed-apps-'));
13
+ const dataDir = join(home, '.antseed');
14
+ const binDir = join(home, 'empty-bin');
15
+ await mkdir(dataDir, { recursive: true });
16
+ await mkdir(binDir, { recursive: true });
17
+ return { home, dataDir, configPath: join(dataDir, 'config.json'), binDir };
18
+ }
19
+ function run(ws, args) {
20
+ const result = spawnSync(process.execPath, [CLI_INDEX, '--data-dir', ws.dataDir, '--config', ws.configPath, ...args], {
21
+ encoding: 'utf8',
22
+ env: {
23
+ ...process.env,
24
+ HOME: ws.home,
25
+ USERPROFILE: ws.home,
26
+ // Keep install probes hermetic: no real `codex`/`claude`/… on PATH.
27
+ PATH: ws.binDir,
28
+ XDG_CONFIG_HOME: join(ws.home, '.config'),
29
+ },
30
+ });
31
+ return { status: result.status, stdout: result.stdout, stderr: result.stderr };
32
+ }
33
+ function json(ws, args) {
34
+ const result = run(ws, [...args, '--json']);
35
+ assert.ok(result.stdout.trim().length > 0, `no JSON output for ${args.join(' ')}: ${result.stderr}`);
36
+ return JSON.parse(result.stdout);
37
+ }
38
+ function homePath(ws, tildePath) {
39
+ return join(ws.home, tildePath.replace(/^~\//, ''));
40
+ }
41
+ /**
42
+ * A pre-existing user config per app, so disconnect must restore it exactly.
43
+ * Droid and Claude Code replace user values and restore them from their
44
+ * `.antseed.state.json` sidecar, so their originals collide with managed keys
45
+ * on purpose. The other formats remove only what AntSeed added — a value they
46
+ * overwrite (e.g. a top-level codex `model`) is not put back except via the
47
+ * `.antseed.bak` backup, and JSONC comments are not preserved — so their
48
+ * originals avoid managed keys. That is the desktop's existing behaviour.
49
+ */
50
+ const ORIGINAL_CONFIGS = {
51
+ opencode: [{ path: '~/.config/opencode/opencode.jsonc', content: '{\n "theme": "dark",\n "provider": {}\n}\n' }],
52
+ codex: [{ path: '~/.codex/config.toml', content: 'approval_policy = "on-request"\n\n[profiles.work]\nmodel = "o3"\n' }],
53
+ 'claude-code': [{ path: '~/.claude/settings.json', content: '{\n "model": "opus",\n "env": {\n "FOO": "bar",\n "ANTHROPIC_BASE_URL": "https://example.test"\n }\n}\n' }],
54
+ hermes: [{ path: '~/.hermes/config.yaml', content: 'display:\n theme: dark\nproviders:\n openrouter:\n api: https://openrouter.ai/api/v1\nmodel:\n temperature: 1\n' }],
55
+ droid: [{ path: '~/.factory/settings.json', content: '{\n "model": "claude-opus",\n "customModels": []\n}\n' }],
56
+ t3code: [{ path: '~/.t3/userdata/settings.json', content: '{\n "theme": "light"\n}\n' }],
57
+ pi: [
58
+ { path: '~/.pi/agent/models.json', content: '{\n "providers": {}\n}\n' },
59
+ { path: '~/.pi/agent/settings.json', content: '{\n "theme": "dark"\n}\n' },
60
+ ],
61
+ crush: [{ path: '~/.config/crush/crush.json', content: '{\n "options": {},\n "providers": {}\n}\n' }],
62
+ goose: [{ path: '~/.config/goose/config.yaml', content: 'GOOSE_TEMPERATURE: 0.5\n' }],
63
+ zed: [{ path: '~/.config/zed/settings.json', content: '{\n "ui_font_size": 16\n}\n' }],
64
+ };
65
+ const DEFAULT_NAMES = DEFAULT_APP_PROFILES.map((profile) => profile['name']);
66
+ test('apps status lists every default profile with a versioned schema', async () => {
67
+ const ws = await createWorkspace();
68
+ try {
69
+ const report = json(ws, ['apps', 'status']);
70
+ assert.equal(report.schemaVersion, 1);
71
+ assert.deepEqual(report.apps.map((app) => app.name), DEFAULT_NAMES);
72
+ for (const app of report.apps) {
73
+ assert.equal(app.connected, false, `${app.name} must start disconnected`);
74
+ assert.equal(typeof app.configPath, 'string');
75
+ }
76
+ // `antseed apps --json` is the same listing.
77
+ assert.deepEqual(json(ws, ['apps']), report);
78
+ // Human output lists every app too.
79
+ const text = run(ws, ['apps']);
80
+ assert.equal(text.status, 0);
81
+ for (const name of DEFAULT_NAMES)
82
+ assert.match(text.stdout, new RegExp(`^${name}\\s`, 'm'));
83
+ }
84
+ finally {
85
+ await rm(ws.home, { recursive: true, force: true });
86
+ }
87
+ });
88
+ test('apps connect rejects unknown apps and lists the supported ones', async () => {
89
+ const ws = await createWorkspace();
90
+ try {
91
+ const result = run(ws, ['apps', 'connect', 'nope', '--json']);
92
+ assert.equal(result.status, 1);
93
+ const report = JSON.parse(result.stdout);
94
+ assert.equal(report.ok, false);
95
+ assert.match(report.error ?? '', /Supported apps: opencode, codex/);
96
+ }
97
+ finally {
98
+ await rm(ws.home, { recursive: true, force: true });
99
+ }
100
+ });
101
+ test('apps connect fails cleanly when an install-probed tool is missing', async () => {
102
+ const ws = await createWorkspace();
103
+ try {
104
+ const result = run(ws, ['apps', 'connect', 'codex', '--json']);
105
+ assert.equal(result.status, 1);
106
+ assert.match(JSON.parse(result.stdout).error ?? '', /codex was not found/);
107
+ assert.equal(existsSync(join(ws.home, '.codex', 'config.toml')), false);
108
+ assert.equal(existsSync(join(ws.dataDir, 'system-proxy', 'system-proxy.desktop.json')), false);
109
+ }
110
+ finally {
111
+ await rm(ws.home, { recursive: true, force: true });
112
+ }
113
+ });
114
+ for (const [name, files] of Object.entries(ORIGINAL_CONFIGS)) {
115
+ test(`apps connect → status → disconnect restores ${name} byte-identically`, async () => {
116
+ const ws = await createWorkspace();
117
+ try {
118
+ for (const file of files) {
119
+ await mkdir(dirname(homePath(ws, file.path)), { recursive: true });
120
+ await writeFile(homePath(ws, file.path), file.content, 'utf8');
121
+ }
122
+ // Desktop state written by an earlier desktop session must survive.
123
+ const statePath = join(ws.dataDir, 'system-proxy', 'system-proxy.desktop.json');
124
+ await mkdir(dirname(statePath), { recursive: true });
125
+ await writeFile(statePath, JSON.stringify({ peerId: 'p', activeProfileNames: ['zz-other'], setupProfileNames: ['zz-other'] }), 'utf8');
126
+ const before = json(ws, ['apps', 'status']).apps.find((app) => app.name === name);
127
+ assert.equal(before?.installed, true);
128
+ assert.equal(before?.connected, false);
129
+ const connected = json(ws, ['apps', 'connect', name, '--port', '9123']);
130
+ assert.equal(connected.ok, true, connected.error);
131
+ assert.equal(connected.buyerPort, 9123);
132
+ assert.equal(connected.connected, true);
133
+ const patched = await readFile(homePath(ws, files[0].path), 'utf8');
134
+ assert.match(patched, /9123/);
135
+ assert.equal(existsSync(`${homePath(ws, files[0].path)}.antseed.bak`), true);
136
+ const after = json(ws, ['apps', 'status']).apps.find((app) => app.name === name);
137
+ assert.equal(after?.connected, true);
138
+ let state = JSON.parse(await readFile(statePath, 'utf8'));
139
+ assert.deepEqual(state['activeProfileNames'], ['zz-other', name]);
140
+ assert.deepEqual(state['setupProfileNames'], ['zz-other', name]);
141
+ assert.equal(state['peerId'], 'p');
142
+ const disconnected = json(ws, ['apps', 'disconnect', name]);
143
+ assert.equal(disconnected.ok, true, disconnected.error);
144
+ assert.equal(disconnected.changed, true);
145
+ assert.equal(disconnected.connected, false);
146
+ for (const file of files) {
147
+ assert.equal(await readFile(homePath(ws, file.path), 'utf8'), file.content, `${file.path} not restored`);
148
+ assert.equal(existsSync(`${homePath(ws, file.path)}.antseed.state.json`), false);
149
+ }
150
+ state = JSON.parse(await readFile(statePath, 'utf8'));
151
+ assert.deepEqual(state['activeProfileNames'], ['zz-other']);
152
+ assert.deepEqual(state['setupProfileNames'], ['zz-other', name]);
153
+ // Second disconnect is a no-op.
154
+ assert.equal(json(ws, ['apps', 'disconnect', name]).changed, false);
155
+ }
156
+ finally {
157
+ await rm(ws.home, { recursive: true, force: true });
158
+ }
159
+ });
160
+ }
161
+ test('apps connect defaults the port from buyer config, then 8377', async () => {
162
+ const ws = await createWorkspace();
163
+ try {
164
+ await mkdir(join(ws.home, '.config', 'zed'), { recursive: true });
165
+ assert.equal(json(ws, ['apps', 'connect', 'zed']).buyerPort, 8377);
166
+ await writeFile(ws.configPath, JSON.stringify({ buyer: { proxyPort: 8411 } }), 'utf8');
167
+ assert.equal(json(ws, ['apps', 'connect', 'zed']).buyerPort, 8411);
168
+ await writeFile(join(ws.dataDir, 'buyer.state.json'), JSON.stringify({ port: 8499 }), 'utf8');
169
+ assert.equal(json(ws, ['apps', 'connect', 'zed']).buyerPort, 8499);
170
+ assert.match(await readFile(join(ws.home, '.config', 'zed', 'settings.json'), 'utf8'), /localhost:8499\/v1/);
171
+ }
172
+ finally {
173
+ await rm(ws.home, { recursive: true, force: true });
174
+ }
175
+ });
176
+ test('apps connect creates a missing config and disconnect leaves no AntSeed entry', async () => {
177
+ const ws = await createWorkspace();
178
+ try {
179
+ // Claude Code with no settings.json yet: the .claude dir is the install signal.
180
+ await mkdir(join(ws.home, '.claude'), { recursive: true });
181
+ assert.equal(json(ws, ['apps', 'connect', 'claude-code']).ok, true);
182
+ assert.equal(existsSync(join(ws.home, '.claude', 'settings.json')), true);
183
+ assert.equal(json(ws, ['apps', 'disconnect', 'claude-code']).changed, true);
184
+ // Config did not exist before connect, so disconnect removes it again.
185
+ assert.equal(existsSync(join(ws.home, '.claude', 'settings.json')), false);
186
+ }
187
+ finally {
188
+ await rm(ws.home, { recursive: true, force: true });
189
+ }
190
+ });
191
+ test('apps connect warns when the buyer has no default route', async () => {
192
+ const ws = await createWorkspace();
193
+ try {
194
+ await mkdir(join(ws.home, '.config', 'zed'), { recursive: true });
195
+ const withoutRoute = json(ws, ['apps', 'connect', 'zed']);
196
+ assert.equal(withoutRoute.ok, true);
197
+ assert.ok(withoutRoute.warnings?.some((warning) => /no default route/i.test(warning)), JSON.stringify(withoutRoute.warnings));
198
+ await writeFile(join(ws.dataDir, 'buyer.state.json'), JSON.stringify({ port: 8499, defaultRoutedModel: 'claude-sonnet' }), 'utf8');
199
+ const withRoute = json(ws, ['apps', 'connect', 'zed']);
200
+ assert.equal(withRoute.warnings?.some((warning) => /no default route/i.test(warning)) ?? false, false);
201
+ }
202
+ finally {
203
+ await rm(ws.home, { recursive: true, force: true });
204
+ }
205
+ });
206
+ //# sourceMappingURL=index.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.test.js","sourceRoot":"","sources":["../../../../src/cli/commands/apps/index.test.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"deposit.d.ts","sourceRoot":"","sources":["../../../../src/cli/commands/buyer/deposit.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AA8BxC,MAAM,WAAW,qBAAqB;IACpC,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,KAAK,EAAE,OAAO,CAAA;IACd,OAAO,CAAC,EAAE,MAAM,CAAA;CACjB;AAySD,wBAAsB,gBAAgB,CAAC,GAAG,EAAE,OAAO,EAAE,OAAO,EAAE,qBAAqB,GAAG,OAAO,CAAC,IAAI,CAAC,CA0DlG;AASD,wBAAgB,2BAA2B,CAAC,QAAQ,EAAE,OAAO,GAAG,IAAI,CAQnE;AAED,2EAA2E;AAC3E,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAK3D"}
1
+ {"version":3,"file":"deposit.d.ts","sourceRoot":"","sources":["../../../../src/cli/commands/buyer/deposit.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AA8BxC,MAAM,WAAW,qBAAqB;IACpC,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,KAAK,EAAE,OAAO,CAAA;IACd,OAAO,CAAC,EAAE,MAAM,CAAA;CACjB;AAgTD,wBAAsB,gBAAgB,CAAC,GAAG,EAAE,OAAO,EAAE,OAAO,EAAE,qBAAqB,GAAG,OAAO,CAAC,IAAI,CAAC,CA0DlG;AASD,wBAAgB,2BAA2B,CAAC,QAAQ,EAAE,OAAO,GAAG,IAAI,CAQnE;AAED,2EAA2E;AAC3E,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAK3D"}
@@ -66,7 +66,15 @@ function renderEvent(spinner, event) {
66
66
  spinner.text = `Sweeping ${formatUsdc(BigInt(event.amountBaseUnits ?? '0'))} USDC into your deposits balance...`;
67
67
  return false;
68
68
  case 'deferred':
69
- spinner.text = 'Deposit deferred: your deposits balance is at its credit limit. Funds stay in the wallet and sweep when headroom frees up.';
69
+ if (event.reason === 'below-minimum') {
70
+ const have = BigInt(event.amountBaseUnits ?? '0');
71
+ const need = BigInt(event.minRequiredBaseUnits ?? '0');
72
+ const shortfall = need > have ? need - have : 0n;
73
+ spinner.text = `Waiting for more USDC: the wallet holds ${formatUsdc(have)} USDC but a deposit needs ${formatUsdc(need)} USDC (minimum plus relay fee). Send ${formatUsdc(shortfall)} USDC more.`;
74
+ }
75
+ else {
76
+ spinner.text = 'Deposit deferred: your deposits balance is at its credit limit. Funds stay in the wallet and sweep when headroom frees up.';
77
+ }
70
78
  return false;
71
79
  case 'error':
72
80
  spinner.text = `${event.error ?? 'Sweep attempt failed'} (retrying automatically)`;