@mycadet/cli 0.12.6-dev.202610082233.54244ee → 0.12.7
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/eslint.config.mjs +7 -0
- package/node_modules/@mycadet/local-mode/src/__tests__/environment.test.ts +1 -4
- package/node_modules/@mycadet/local-mode/src/config.ts +14 -19
- package/node_modules/@mycadet/local-mode/src/index.ts +5 -0
- package/node_modules/@mycadet/local-mode/src/local-signing-key.ts +73 -0
- package/node_modules/@mycadet/local-mode/src/lockfile.ts +18 -3
- package/package.json +4 -3
- package/src/__tests__/assistant-config.test.ts +30 -28
- package/src/__tests__/debug.test.ts +8 -8
- package/src/__tests__/default-main-screen-formatting.test.ts +5 -4
- package/src/__tests__/flags.test.ts +2 -2
- package/src/__tests__/hatch-provider-secrets.test.ts +3 -3
- package/src/__tests__/ingress-config.test.ts +2 -2
- package/src/__tests__/login-loopback.test.ts +1 -1
- package/src/__tests__/nginx-ingress.test.ts +68 -76
- package/src/__tests__/pair.test.ts +135 -121
- package/src/__tests__/platform-client.test.ts +2 -2
- package/src/__tests__/recover.test.ts +96 -3
- package/src/__tests__/retire.test.ts +5 -3
- package/src/__tests__/signing-key-continuity.test.ts +261 -0
- package/src/__tests__/sleep.test.ts +189 -6
- package/src/__tests__/tailscale-tunnel.test.ts +1 -1
- package/src/__tests__/uninstall.test.ts +171 -0
- package/src/__tests__/upgrade-local.test.ts +16 -3
- package/src/__tests__/use.test.ts +2 -2
- package/src/__tests__/wake-error.test.ts +76 -0
- package/src/__tests__/wake.test.ts +309 -36
- package/src/commands/backup.ts +6 -2
- package/src/commands/clean.ts +6 -2
- package/src/commands/client.ts +91 -41
- package/src/commands/confirm.ts +6 -2
- package/src/commands/connect.ts +6 -2
- package/src/commands/debug.ts +6 -2
- package/src/commands/devices.ts +6 -2
- package/src/commands/events.ts +6 -2
- package/src/commands/exec.ts +50 -12
- package/src/commands/flags.ts +6 -2
- package/src/commands/gateway.ts +6 -2
- package/src/commands/hatch.ts +6 -2
- package/src/commands/login.ts +26 -356
- package/src/commands/logs.ts +6 -2
- package/src/commands/message.ts +6 -2
- package/src/commands/pair.ts +6 -2
- package/src/commands/ps.ts +7 -2
- package/src/commands/recover.ts +21 -16
- package/src/commands/restore.ts +6 -2
- package/src/commands/retire.ts +6 -2
- package/src/commands/roadmap.ts +6 -2
- package/src/commands/rollback.ts +6 -2
- package/src/commands/setup.ts +76 -9
- package/src/commands/sleep.ts +131 -31
- package/src/commands/ssh.ts +6 -2
- package/src/commands/teleport.ts +6 -2
- package/src/commands/terminal.ts +6 -2
- package/src/commands/tunnel.ts +6 -2
- package/src/commands/uninstall.ts +228 -0
- package/src/commands/unpair.ts +6 -2
- package/src/commands/upgrade.ts +13 -8
- package/src/commands/use.ts +6 -2
- package/src/commands/voice.ts +6 -2
- package/src/commands/wake.ts +69 -37
- package/src/commands/workflows.ts +6 -2
- package/src/components/DefaultMainScreen.tsx +250 -36
- package/src/index.ts +23 -55
- package/src/lib/assistant-config.ts +27 -13
- package/src/lib/backup-ops.ts +3 -4
- package/src/lib/cli-error.ts +5 -0
- package/src/lib/client-identity.ts +8 -10
- package/src/lib/cloud-login.ts +422 -0
- package/src/lib/color.ts +16 -0
- package/src/lib/default-main-screen-formatting.ts +32 -8
- package/src/lib/environments/__tests__/paths.test.ts +9 -11
- package/src/lib/environments/paths.ts +2 -20
- package/src/lib/guardian-token.ts +72 -18
- package/src/lib/hatch-local.ts +52 -1
- package/src/lib/health-check.ts +24 -15
- package/src/lib/lifecycle-reporter.ts +9 -1
- package/src/lib/local-hatch-lock.ts +19 -27
- package/src/lib/local-runtime-client.ts +25 -14
- package/src/lib/local.ts +17 -43
- package/src/lib/ngrok.ts +48 -16
- package/src/lib/platform-client.ts +141 -72
- package/src/lib/retire-archive.ts +4 -4
- package/src/lib/retire-local.ts +2 -25
- package/src/lib/teleport-backup.ts +23 -9
- package/src/lib/terminal-client.ts +21 -9
- package/src/lib/tunnel-edge.ts +11 -13
- package/src/lib/upgrade-lifecycle.ts +16 -4
- package/src/lib/workos-pkce.ts +52 -21
package/src/commands/client.ts
CHANGED
|
@@ -10,6 +10,7 @@ import {
|
|
|
10
10
|
getActiveAssistant,
|
|
11
11
|
lookupAssistantByIdentifier,
|
|
12
12
|
resolveAssistant,
|
|
13
|
+
resolveConversationKey,
|
|
13
14
|
saveAssistantEntry,
|
|
14
15
|
type AssistantEntry,
|
|
15
16
|
} from "../lib/assistant-config";
|
|
@@ -76,9 +77,47 @@ import { relaunchDetached } from "../lib/detached-process.js";
|
|
|
76
77
|
import { probePort } from "../lib/port-probe.js";
|
|
77
78
|
import { openBrowser } from "../lib/open-browser";
|
|
78
79
|
import { findWebDistDir } from "../lib/web-dist.js";
|
|
80
|
+
import { z } from "zod";
|
|
81
|
+
|
|
82
|
+
const AssistantIdBodySchema = z.object({
|
|
83
|
+
assistantId: z.string().optional(),
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
const TokenBodySchema = z.object({ token: z.unknown() }).nullable();
|
|
87
|
+
|
|
88
|
+
const SyncPlatformBodySchema = z.object({
|
|
89
|
+
syncPlatform: z.unknown().optional(),
|
|
90
|
+
platformAssistants: z.array(z.record(z.string(), z.unknown())).optional(),
|
|
91
|
+
organizationId: z.string().optional(),
|
|
92
|
+
rename: z
|
|
93
|
+
.object({ assistantId: z.string(), name: z.string() })
|
|
94
|
+
.optional(),
|
|
95
|
+
assistant: z.record(z.string(), z.unknown()).optional(),
|
|
96
|
+
activeAssistant: z.string().optional(),
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
const RemoteBodySchema = z.object({ remote: z.string().optional() });
|
|
100
|
+
|
|
101
|
+
const UnpairBodySchema = z.object({
|
|
102
|
+
assistantId: z.unknown().optional(),
|
|
103
|
+
hashedDeviceId: z.unknown().optional(),
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
const DeviceBodySchema = z.object({
|
|
107
|
+
address: z.unknown().optional(),
|
|
108
|
+
handle: z.unknown().optional(),
|
|
109
|
+
name: z.unknown().optional(),
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
function errnoCode(error: unknown): string | undefined {
|
|
113
|
+
if (!(error instanceof Error)) return undefined;
|
|
114
|
+
if (!("code" in error) || typeof error.code !== "string") return undefined;
|
|
115
|
+
return error.code;
|
|
116
|
+
}
|
|
79
117
|
|
|
80
118
|
const SUPPORTED_INTERFACES = ["cli", "web"] as const;
|
|
81
119
|
type SupportedInterface = (typeof SUPPORTED_INTERFACES)[number];
|
|
120
|
+
const SupportedInterfaceSchema = z.enum(SUPPORTED_INTERFACES);
|
|
82
121
|
|
|
83
122
|
const ANSI = {
|
|
84
123
|
reset: "\x1b[0m",
|
|
@@ -298,13 +337,14 @@ export function parseArgs(): ParsedArgs {
|
|
|
298
337
|
assistantName = undefined;
|
|
299
338
|
} else if ((flag === "--interface" || flag === "-i") && flagArgs[i + 1]) {
|
|
300
339
|
const value = flagArgs[++i];
|
|
301
|
-
|
|
340
|
+
const parsedInterface = SupportedInterfaceSchema.safeParse(value);
|
|
341
|
+
if (!parsedInterface.success) {
|
|
302
342
|
console.error(
|
|
303
343
|
`Unknown interface '${value}'. Supported: ${SUPPORTED_INTERFACES.join(", ")}.`,
|
|
304
344
|
);
|
|
305
345
|
process.exit(1);
|
|
306
346
|
}
|
|
307
|
-
interfaceId =
|
|
347
|
+
interfaceId = parsedInterface.data;
|
|
308
348
|
}
|
|
309
349
|
}
|
|
310
350
|
|
|
@@ -364,10 +404,6 @@ ${ANSI.bold}OPTIONS:${ANSI.reset}
|
|
|
364
404
|
--disable-platform Suppress all outbound platform API calls
|
|
365
405
|
-h, --help Show this help message
|
|
366
406
|
|
|
367
|
-
${ANSI.bold}DEFAULTS:${ANSI.reset}
|
|
368
|
-
Reads from ~/.cadet.lock.json (created by cadet hatch).
|
|
369
|
-
Override with flags above.
|
|
370
|
-
|
|
371
407
|
${ANSI.bold}EXAMPLES:${ANSI.reset}
|
|
372
408
|
cadet client
|
|
373
409
|
cadet client mycadet-foo
|
|
@@ -551,10 +587,11 @@ async function handleLocalEndpoints(
|
|
|
551
587
|
return Response.json({ ok: true });
|
|
552
588
|
}
|
|
553
589
|
if (req.method === "POST") {
|
|
554
|
-
const
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
const token =
|
|
590
|
+
const parsed = TokenBodySchema.safeParse(
|
|
591
|
+
await req.json().catch(() => null),
|
|
592
|
+
);
|
|
593
|
+
const token =
|
|
594
|
+
parsed.success && parsed.data ? parsed.data.token : undefined;
|
|
558
595
|
if (typeof token !== "string" || !/^[A-Za-z0-9]+$/.test(token)) {
|
|
559
596
|
return Response.json(
|
|
560
597
|
{ ok: false, error: "Invalid token" },
|
|
@@ -578,9 +615,11 @@ async function handleLocalEndpoints(
|
|
|
578
615
|
return new Response(null, { status: result.status });
|
|
579
616
|
}
|
|
580
617
|
if (req.method === "POST") {
|
|
581
|
-
let body:
|
|
618
|
+
let body: z.infer<typeof SyncPlatformBodySchema>;
|
|
582
619
|
try {
|
|
583
|
-
|
|
620
|
+
const parsed = SyncPlatformBodySchema.safeParse(await req.json());
|
|
621
|
+
if (!parsed.success) throw new Error("invalid body");
|
|
622
|
+
body = parsed.data;
|
|
584
623
|
} catch {
|
|
585
624
|
return Response.json(
|
|
586
625
|
{ ok: false, error: "Invalid JSON body" },
|
|
@@ -588,24 +627,23 @@ async function handleLocalEndpoints(
|
|
|
588
627
|
);
|
|
589
628
|
}
|
|
590
629
|
let result;
|
|
591
|
-
if (body.syncPlatform &&
|
|
630
|
+
if (body.syncPlatform && body.platformAssistants) {
|
|
592
631
|
result = replacePlatformAssistants(
|
|
593
632
|
lockfilePaths,
|
|
594
|
-
body.platformAssistants
|
|
595
|
-
body.organizationId
|
|
633
|
+
body.platformAssistants,
|
|
634
|
+
body.organizationId,
|
|
596
635
|
);
|
|
597
|
-
} else if (body.rename
|
|
598
|
-
const rename = body.rename as Record<string, unknown>;
|
|
636
|
+
} else if (body.rename) {
|
|
599
637
|
result = renameLockfileAssistantIfPresent(
|
|
600
638
|
lockfilePaths,
|
|
601
|
-
rename.assistantId
|
|
602
|
-
rename.name
|
|
639
|
+
body.rename.assistantId,
|
|
640
|
+
body.rename.name,
|
|
603
641
|
);
|
|
604
642
|
} else {
|
|
605
643
|
result = upsertRendererLockfileAssistant(
|
|
606
644
|
lockfilePaths,
|
|
607
|
-
body.assistant
|
|
608
|
-
body.activeAssistant
|
|
645
|
+
body.assistant ?? {},
|
|
646
|
+
body.activeAssistant,
|
|
609
647
|
);
|
|
610
648
|
}
|
|
611
649
|
return Response.json(result, { status: result.ok ? 200 : result.status });
|
|
@@ -621,10 +659,8 @@ async function handleLocalEndpoints(
|
|
|
621
659
|
const contentType = req.headers.get("content-type") ?? "";
|
|
622
660
|
if (contentType.includes("json")) {
|
|
623
661
|
try {
|
|
624
|
-
const
|
|
625
|
-
|
|
626
|
-
};
|
|
627
|
-
if (body.remote) remote = body.remote;
|
|
662
|
+
const parsed = RemoteBodySchema.safeParse(await req.json());
|
|
663
|
+
if (parsed.success && parsed.data.remote) remote = parsed.data.remote;
|
|
628
664
|
} catch {
|
|
629
665
|
return Response.json(
|
|
630
666
|
{ ok: false, error: "Invalid JSON body" },
|
|
@@ -659,8 +695,9 @@ async function handleLocalEndpoints(
|
|
|
659
695
|
|
|
660
696
|
let assistantId: string | undefined;
|
|
661
697
|
try {
|
|
662
|
-
const
|
|
663
|
-
|
|
698
|
+
const parsed = AssistantIdBodySchema.safeParse(await req.json());
|
|
699
|
+
if (!parsed.success) throw new Error("invalid body");
|
|
700
|
+
assistantId = parsed.data.assistantId;
|
|
664
701
|
} catch {
|
|
665
702
|
return Response.json(
|
|
666
703
|
{ ok: false, error: "Invalid JSON body" },
|
|
@@ -710,8 +747,9 @@ async function handleLocalEndpoints(
|
|
|
710
747
|
|
|
711
748
|
let assistantId: string | undefined;
|
|
712
749
|
try {
|
|
713
|
-
const
|
|
714
|
-
|
|
750
|
+
const parsed = AssistantIdBodySchema.safeParse(await req.json());
|
|
751
|
+
if (!parsed.success) throw new Error("invalid body");
|
|
752
|
+
assistantId = parsed.data.assistantId;
|
|
715
753
|
} catch {
|
|
716
754
|
return Response.json(
|
|
717
755
|
{ ok: false, error: "Invalid JSON body" },
|
|
@@ -746,7 +784,9 @@ async function handleLocalEndpoints(
|
|
|
746
784
|
|
|
747
785
|
let body: { assistantId?: unknown; hashedDeviceId?: unknown };
|
|
748
786
|
try {
|
|
749
|
-
|
|
787
|
+
const parsed = UnpairBodySchema.safeParse(await req.json());
|
|
788
|
+
if (!parsed.success) throw new Error("invalid body");
|
|
789
|
+
body = parsed.data;
|
|
750
790
|
} catch {
|
|
751
791
|
return Response.json(
|
|
752
792
|
{ ok: false, error: "Invalid JSON body" },
|
|
@@ -805,11 +845,9 @@ async function handleLocalEndpoints(
|
|
|
805
845
|
|
|
806
846
|
let body: { address?: unknown; handle?: unknown; name?: unknown };
|
|
807
847
|
try {
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
name?: unknown;
|
|
812
|
-
};
|
|
848
|
+
const parsed = DeviceBodySchema.safeParse(await req.json());
|
|
849
|
+
if (!parsed.success) throw new Error("invalid body");
|
|
850
|
+
body = parsed.data;
|
|
813
851
|
} catch {
|
|
814
852
|
return Response.json(
|
|
815
853
|
{ ok: false, error: "Invalid JSON body" },
|
|
@@ -1047,10 +1085,11 @@ type WebFetchHandler = (
|
|
|
1047
1085
|
) => Promise<Response>;
|
|
1048
1086
|
|
|
1049
1087
|
function isAddrInUse(err: unknown): boolean {
|
|
1050
|
-
const
|
|
1088
|
+
const code = errnoCode(err);
|
|
1089
|
+
const message = err instanceof Error ? err.message : undefined;
|
|
1051
1090
|
return (
|
|
1052
|
-
|
|
1053
|
-
/EADDRINUSE|address already in use/i.test(
|
|
1091
|
+
code === "EADDRINUSE" ||
|
|
1092
|
+
/EADDRINUSE|address already in use/i.test(message ?? "")
|
|
1054
1093
|
);
|
|
1055
1094
|
}
|
|
1056
1095
|
|
|
@@ -1590,7 +1629,8 @@ export async function resolveFreshBearerToken(
|
|
|
1590
1629
|
return refreshed?.accessToken ?? bearerToken;
|
|
1591
1630
|
}
|
|
1592
1631
|
|
|
1593
|
-
export
|
|
1632
|
+
export const client = Object.assign(
|
|
1633
|
+
async function client(): Promise<void> {
|
|
1594
1634
|
const {
|
|
1595
1635
|
runtimeUrl,
|
|
1596
1636
|
assistantId,
|
|
@@ -1673,6 +1713,13 @@ export async function client(): Promise<void> {
|
|
|
1673
1713
|
};
|
|
1674
1714
|
}
|
|
1675
1715
|
|
|
1716
|
+
// The CLI addresses its chat conversation by a client-minted uuid key
|
|
1717
|
+
// (web's temp-client-id pattern) — resolve-or-mint once, persisted on the
|
|
1718
|
+
// entry, so every session shares one conversation.
|
|
1719
|
+
const lookup = lookupAssistantByIdentifier(assistantId);
|
|
1720
|
+
const conversationKey =
|
|
1721
|
+
lookup.status === "found" ? resolveConversationKey(lookup.entry) : undefined;
|
|
1722
|
+
|
|
1676
1723
|
const { renderChatApp } = await import("../components/DefaultMainScreen");
|
|
1677
1724
|
|
|
1678
1725
|
process.stdout.write("\x1b[2J\x1b[H");
|
|
@@ -1688,6 +1735,9 @@ export async function client(): Promise<void> {
|
|
|
1688
1735
|
console.log(`${ANSI.dim}Disconnected.${ANSI.reset}`);
|
|
1689
1736
|
process.exit(0);
|
|
1690
1737
|
},
|
|
1691
|
-
{ auth, assistantName, workspaceRoot },
|
|
1738
|
+
{ auth, assistantName, workspaceRoot, conversationKey },
|
|
1692
1739
|
);
|
|
1693
|
-
}
|
|
1740
|
+
},
|
|
1741
|
+
{ description: "Connect to a hatched assistant" },
|
|
1742
|
+
);
|
|
1743
|
+
|
package/src/commands/confirm.ts
CHANGED
|
@@ -103,7 +103,8 @@ function exitWithUsage(error: string): never {
|
|
|
103
103
|
process.exit(1);
|
|
104
104
|
}
|
|
105
105
|
|
|
106
|
-
export
|
|
106
|
+
export const confirm = Object.assign(
|
|
107
|
+
async function confirm(): Promise<void> {
|
|
107
108
|
const rawArgs = process.argv.slice(3);
|
|
108
109
|
|
|
109
110
|
if (rawArgs.includes("--help") || rawArgs.includes("-h")) {
|
|
@@ -141,4 +142,7 @@ export async function confirm(): Promise<void> {
|
|
|
141
142
|
: `Confirmation not accepted`,
|
|
142
143
|
);
|
|
143
144
|
}
|
|
144
|
-
}
|
|
145
|
+
},
|
|
146
|
+
{ description: "Resolve a pending tool confirmation on an assistant" },
|
|
147
|
+
);
|
|
148
|
+
|
package/src/commands/connect.ts
CHANGED
|
@@ -11,7 +11,8 @@ function printUsage(): void {
|
|
|
11
11
|
);
|
|
12
12
|
}
|
|
13
13
|
|
|
14
|
-
export
|
|
14
|
+
export const connect = Object.assign(
|
|
15
|
+
async function connect(): Promise<void> {
|
|
15
16
|
const args = process.argv.slice(3);
|
|
16
17
|
const subcommand = args[0];
|
|
17
18
|
|
|
@@ -28,4 +29,7 @@ export async function connect(): Promise<void> {
|
|
|
28
29
|
console.error(`Unknown subcommand: ${subcommand}`);
|
|
29
30
|
printUsage();
|
|
30
31
|
process.exit(1);
|
|
31
|
-
}
|
|
32
|
+
},
|
|
33
|
+
{ description: "Pair with an assistant running on another machine [beta]" },
|
|
34
|
+
);
|
|
35
|
+
|
package/src/commands/debug.ts
CHANGED
|
@@ -78,7 +78,8 @@ Examples:
|
|
|
78
78
|
`);
|
|
79
79
|
}
|
|
80
80
|
|
|
81
|
-
export
|
|
81
|
+
export const debug = Object.assign(
|
|
82
|
+
async function debug(): Promise<void> {
|
|
82
83
|
const args = process.argv.slice(3);
|
|
83
84
|
if (args.includes("--help") || args.includes("-h")) {
|
|
84
85
|
printHelp();
|
|
@@ -182,7 +183,10 @@ export async function debugBundle(): Promise<void> {
|
|
|
182
183
|
console.log(
|
|
183
184
|
"Debug bundle sent to Cadet. Staff can open it for the next 7 days.",
|
|
184
185
|
);
|
|
185
|
-
}
|
|
186
|
+
},
|
|
187
|
+
{ description: "Send Cadet staff a debug bundle of a self-hosted assistant" },
|
|
188
|
+
);
|
|
189
|
+
|
|
186
190
|
|
|
187
191
|
async function daemonAccessToken(
|
|
188
192
|
entry: {
|
package/src/commands/devices.ts
CHANGED
|
@@ -279,7 +279,8 @@ async function revokeDevice(
|
|
|
279
279
|
);
|
|
280
280
|
}
|
|
281
281
|
|
|
282
|
-
export
|
|
282
|
+
export const devices = Object.assign(
|
|
283
|
+
async function devices(): Promise<void> {
|
|
283
284
|
const rawArgs = process.argv.slice(3);
|
|
284
285
|
|
|
285
286
|
if (rawArgs.includes("--help") || rawArgs.includes("-h")) {
|
|
@@ -311,4 +312,7 @@ export async function devices(): Promise<void> {
|
|
|
311
312
|
const entry = resolveTargetAssistant(nameArg);
|
|
312
313
|
const base = resolveLoopbackBase(entry);
|
|
313
314
|
await listDevices(entry, base, jsonOutput);
|
|
314
|
-
}
|
|
315
|
+
},
|
|
316
|
+
{ description: "List or revoke devices paired to a local assistant [beta]" },
|
|
317
|
+
);
|
|
318
|
+
|
package/src/commands/events.ts
CHANGED
|
@@ -113,7 +113,8 @@ export function renderMarkdown(event: AssistantEvent): void {
|
|
|
113
113
|
}
|
|
114
114
|
}
|
|
115
115
|
|
|
116
|
-
export
|
|
116
|
+
export const events = Object.assign(
|
|
117
|
+
async function events(): Promise<void> {
|
|
117
118
|
const rawArgs = process.argv.slice(3);
|
|
118
119
|
|
|
119
120
|
if (rawArgs.includes("--help") || rawArgs.includes("-h")) {
|
|
@@ -157,4 +158,7 @@ export async function events(): Promise<void> {
|
|
|
157
158
|
renderMarkdown(event);
|
|
158
159
|
}
|
|
159
160
|
}
|
|
160
|
-
}
|
|
161
|
+
},
|
|
162
|
+
{ description: "Stream events from a running assistant" },
|
|
163
|
+
);
|
|
164
|
+
|
package/src/commands/exec.ts
CHANGED
|
@@ -1,5 +1,9 @@
|
|
|
1
|
+
import { existsSync } from "fs";
|
|
2
|
+
import { join } from "path";
|
|
3
|
+
|
|
1
4
|
import { isManagedCloud } from "../lib/managed-cloud.js";
|
|
2
5
|
import { spawn } from "child_process";
|
|
6
|
+
import { red } from "../lib/color";
|
|
3
7
|
|
|
4
8
|
import { resolveAssistant } from "../lib/assistant-config";
|
|
5
9
|
import { dockerResourceNames } from "../lib/docker";
|
|
@@ -26,7 +30,7 @@ function normalizeService(raw: string): ServiceName {
|
|
|
26
30
|
const normalized = SERVICE_ALIASES[raw];
|
|
27
31
|
if (!normalized) {
|
|
28
32
|
console.error(
|
|
29
|
-
`Unknown service '${raw}'. Valid services: assistant, gateway, credential-executor
|
|
33
|
+
red(`Unknown service '${raw}'. Valid services: assistant, gateway, credential-executor`),
|
|
30
34
|
);
|
|
31
35
|
process.exit(1);
|
|
32
36
|
}
|
|
@@ -48,7 +52,8 @@ function resolveDockerContainer(
|
|
|
48
52
|
}
|
|
49
53
|
}
|
|
50
54
|
|
|
51
|
-
export
|
|
55
|
+
export const exec = Object.assign(
|
|
56
|
+
async function exec(): Promise<void> {
|
|
52
57
|
const rawArgs = process.argv.slice(3);
|
|
53
58
|
|
|
54
59
|
// Only check for help flags before the -- separator so that
|
|
@@ -103,8 +108,10 @@ export async function exec(): Promise<void> {
|
|
|
103
108
|
|
|
104
109
|
if (dashDashIndex === -1) {
|
|
105
110
|
console.error(
|
|
106
|
-
|
|
107
|
-
"
|
|
111
|
+
red(
|
|
112
|
+
"Error: missing '--' separator before command.\n" +
|
|
113
|
+
"Usage: cadet exec [<name>] -- <command...>",
|
|
114
|
+
),
|
|
108
115
|
);
|
|
109
116
|
process.exit(1);
|
|
110
117
|
}
|
|
@@ -112,7 +119,7 @@ export async function exec(): Promise<void> {
|
|
|
112
119
|
const command = rawArgs.slice(dashDashIndex + 1);
|
|
113
120
|
|
|
114
121
|
if (command.length === 0) {
|
|
115
|
-
console.error("Error: no command specified after '--'.");
|
|
122
|
+
console.error(red("Error: no command specified after '--'."));
|
|
116
123
|
process.exit(1);
|
|
117
124
|
}
|
|
118
125
|
|
|
@@ -130,7 +137,7 @@ export async function exec(): Promise<void> {
|
|
|
130
137
|
} else if (preArgs[i] === "--timeout" && preArgs[i + 1]) {
|
|
131
138
|
const secs = Number(preArgs[++i]);
|
|
132
139
|
if (!Number.isFinite(secs) || secs < 0) {
|
|
133
|
-
console.error("Error: --timeout must be a non-negative number.");
|
|
140
|
+
console.error(red("Error: --timeout must be a non-negative number."));
|
|
134
141
|
process.exit(1);
|
|
135
142
|
}
|
|
136
143
|
timeoutMs = secs === 0 ? 0 : secs * 1000;
|
|
@@ -147,9 +154,9 @@ export async function exec(): Promise<void> {
|
|
|
147
154
|
|
|
148
155
|
if (!entry) {
|
|
149
156
|
if (nameArg) {
|
|
150
|
-
console.error(`No assistant instance found with name '${nameArg}'.`);
|
|
157
|
+
console.error(red(`No assistant instance found with name '${nameArg}'.`));
|
|
151
158
|
} else {
|
|
152
|
-
console.error("No assistant instance found. Run `cadet hatch` first.");
|
|
159
|
+
console.error(red("No assistant instance found. Run `cadet hatch` first."));
|
|
153
160
|
}
|
|
154
161
|
process.exit(1);
|
|
155
162
|
}
|
|
@@ -157,9 +164,37 @@ export async function exec(): Promise<void> {
|
|
|
157
164
|
const cloud = entry.cloud;
|
|
158
165
|
|
|
159
166
|
if (cloud === "local") {
|
|
167
|
+
const instanceDir = entry.resources?.instanceDir;
|
|
168
|
+
if (!instanceDir) {
|
|
169
|
+
console.error(
|
|
170
|
+
red(
|
|
171
|
+
`Error: assistant '${entry.assistantId}' has no local instance directory recorded.`,
|
|
172
|
+
),
|
|
173
|
+
);
|
|
174
|
+
process.exit(1);
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
const workspaceDir = join(instanceDir, "workspace");
|
|
178
|
+
const socketPath = join(workspaceDir, "assistant.sock");
|
|
179
|
+
if (!existsSync(socketPath)) {
|
|
180
|
+
console.error(
|
|
181
|
+
red(
|
|
182
|
+
`Error: the assistant runtime is not reachable (no socket at ${socketPath}).`,
|
|
183
|
+
),
|
|
184
|
+
);
|
|
185
|
+
console.error(
|
|
186
|
+
red("Start it with `cadet wake`, or check `cadet ps` for its status."),
|
|
187
|
+
);
|
|
188
|
+
process.exit(1);
|
|
189
|
+
}
|
|
190
|
+
|
|
160
191
|
const child = spawn(command[0], command.slice(1), {
|
|
161
192
|
stdio: "inherit",
|
|
162
193
|
windowsHide: true,
|
|
194
|
+
env: {
|
|
195
|
+
...process.env,
|
|
196
|
+
CADET_WORKSPACE_DIR: workspaceDir,
|
|
197
|
+
},
|
|
163
198
|
});
|
|
164
199
|
await new Promise<void>((resolve) => {
|
|
165
200
|
child.on("close", (code) => {
|
|
@@ -167,7 +202,7 @@ export async function exec(): Promise<void> {
|
|
|
167
202
|
resolve();
|
|
168
203
|
});
|
|
169
204
|
child.on("error", (err) => {
|
|
170
|
-
console.error(`Error: ${err.message}`);
|
|
205
|
+
console.error(red(`Error: ${err.message}`));
|
|
171
206
|
process.exitCode = 1;
|
|
172
207
|
resolve();
|
|
173
208
|
});
|
|
@@ -212,7 +247,7 @@ export async function exec(): Promise<void> {
|
|
|
212
247
|
const token = readPlatformToken();
|
|
213
248
|
if (!token) {
|
|
214
249
|
console.error(
|
|
215
|
-
"Not logged in. Run `cadet login` first to authenticate with Cadet Cloud.",
|
|
250
|
+
red("Not logged in. Run `cadet login` first to authenticate with Cadet Cloud."),
|
|
216
251
|
);
|
|
217
252
|
process.exit(1);
|
|
218
253
|
}
|
|
@@ -244,6 +279,9 @@ export async function exec(): Promise<void> {
|
|
|
244
279
|
return;
|
|
245
280
|
}
|
|
246
281
|
|
|
247
|
-
console.error(`Error: 'cadet exec' is not supported for ${cloud} instances.`);
|
|
282
|
+
console.error(red(`Error: 'cadet exec' is not supported for ${cloud} instances.`));
|
|
248
283
|
process.exit(1);
|
|
249
|
-
}
|
|
284
|
+
},
|
|
285
|
+
{ description: "Execute a command inside an assistant's container" },
|
|
286
|
+
);
|
|
287
|
+
|
package/src/commands/flags.ts
CHANGED
|
@@ -203,7 +203,8 @@ async function setFlag(
|
|
|
203
203
|
console.log(`Flag "${key}" set to ${value}`);
|
|
204
204
|
}
|
|
205
205
|
|
|
206
|
-
export
|
|
206
|
+
export const flags = Object.assign(
|
|
207
|
+
async function flags(): Promise<void> {
|
|
207
208
|
const args = process.argv.slice(3);
|
|
208
209
|
|
|
209
210
|
if (args.includes("--help") || args.includes("-h")) {
|
|
@@ -248,4 +249,7 @@ export async function flags(): Promise<void> {
|
|
|
248
249
|
console.error(`Unknown subcommand: ${subcommand}`);
|
|
249
250
|
printHelp();
|
|
250
251
|
process.exit(1);
|
|
251
|
-
}
|
|
252
|
+
},
|
|
253
|
+
{ description: "Show and toggle feature flags" },
|
|
254
|
+
);
|
|
255
|
+
|
package/src/commands/gateway.ts
CHANGED
|
@@ -9,7 +9,8 @@ function printUsage(): void {
|
|
|
9
9
|
console.log(" token Manage gateway authentication tokens");
|
|
10
10
|
}
|
|
11
11
|
|
|
12
|
-
export
|
|
12
|
+
export const gateway = Object.assign(
|
|
13
|
+
async function gateway(): Promise<void> {
|
|
13
14
|
const args = process.argv.slice(3);
|
|
14
15
|
const subcommand = args[0];
|
|
15
16
|
|
|
@@ -26,4 +27,7 @@ export async function gateway(): Promise<void> {
|
|
|
26
27
|
console.error(`Unknown subcommand: ${subcommand}`);
|
|
27
28
|
printUsage();
|
|
28
29
|
process.exit(1);
|
|
29
|
-
}
|
|
30
|
+
},
|
|
31
|
+
{ description: "Gateway management commands" },
|
|
32
|
+
);
|
|
33
|
+
|
package/src/commands/hatch.ts
CHANGED
|
@@ -222,7 +222,8 @@ function getCliVersion(): string {
|
|
|
222
222
|
return cliPkg.version ?? "unknown";
|
|
223
223
|
}
|
|
224
224
|
|
|
225
|
-
export
|
|
225
|
+
export const hatch = Object.assign(
|
|
226
|
+
async function hatch(): Promise<void> {
|
|
226
227
|
const cliVersion = getCliVersion();
|
|
227
228
|
console.log(`@mycadet/cli v${cliVersion}`);
|
|
228
229
|
|
|
@@ -314,7 +315,10 @@ export async function hatch(): Promise<void> {
|
|
|
314
315
|
|
|
315
316
|
console.error(`Error: Remote host '${remote}' is not yet supported.`);
|
|
316
317
|
process.exit(1);
|
|
317
|
-
}
|
|
318
|
+
},
|
|
319
|
+
{ description: "Create a new assistant instance" },
|
|
320
|
+
);
|
|
321
|
+
|
|
318
322
|
|
|
319
323
|
async function hatchCadetPlatform(): Promise<void> {
|
|
320
324
|
const token = readPlatformToken();
|