@mycadet/cli 0.12.8 → 0.12.9
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/node_modules/@mycadet/assistant-api/events/show-cloud-login.ts +2 -2
- package/node_modules/@mycadet/assistant-api/node_modules/@mycadet/service-contracts/package.json +1 -1
- package/node_modules/@mycadet/local-mode/node_modules/@mycadet/service-contracts/package.json +1 -1
- package/node_modules/@mycadet/service-contracts/package.json +1 -1
- package/package.json +2 -2
- package/src/__tests__/cloud-releases.test.ts +23 -13
- package/src/__tests__/ensure-binary.test.ts +182 -0
- package/src/__tests__/nginx-ingress.test.ts +3 -2
- package/src/__tests__/ngrok-spawn.test.ts +49 -0
- package/src/__tests__/ps-table.test.ts +79 -0
- package/src/__tests__/tailscale.test.ts +1 -1
- package/src/__tests__/teleport.test.ts +1 -1
- package/src/__tests__/tunnel.test.ts +21 -14
- package/src/__tests__/uninstall.test.ts +1 -1
- package/src/__tests__/wake.test.ts +2 -2
- package/src/commands/backup.ts +3 -3
- package/src/commands/completions.test.ts +104 -0
- package/src/commands/completions.ts +87 -0
- package/src/commands/exec.ts +7 -7
- package/src/commands/flags.ts +2 -2
- package/src/commands/hatch.ts +1 -1
- package/src/commands/logs.ts +7 -7
- package/src/commands/ps.ts +57 -8
- package/src/commands/restore.ts +2 -2
- package/src/commands/retire.ts +2 -2
- package/src/commands/rollback.ts +2 -2
- package/src/commands/sleep.ts +2 -2
- package/src/commands/teleport.ts +16 -16
- package/src/commands/terminal.ts +1 -1
- package/src/commands/tunnel.ts +78 -55
- package/src/commands/uninstall.ts +4 -4
- package/src/commands/upgrade.ts +8 -8
- package/src/commands/use.ts +1 -1
- package/src/commands/wake.ts +6 -6
- package/src/index.ts +15 -0
- package/src/lib/__tests__/docker.test.ts +168 -20
- package/src/lib/__tests__/job-polling.test.ts +1 -1
- package/src/lib/cloud-releases.ts +6 -4
- package/src/lib/docker.ts +150 -44
- package/src/lib/ensure-binary.ts +171 -0
- package/src/lib/flag-args.test.ts +1 -1
- package/src/lib/flag-args.ts +1 -1
- package/src/lib/guardian-token.ts +1 -1
- package/src/lib/hatch-local.ts +1 -1
- package/src/lib/job-polling.ts +1 -1
- package/src/lib/local.ts +1 -1
- package/src/lib/nginx-ingress.ts +2 -2
- package/src/lib/pair.ts +1 -1
- package/src/lib/sync-cloud-assistants.ts +2 -2
- package/src/lib/tunnels/cloudflare.ts +21 -11
- package/src/lib/tunnels/ngrok.ts +198 -108
- package/src/lib/tunnels/tailscale.ts +34 -4
- package/src/lib/upgrade-lifecycle.ts +5 -4
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
import { afterEach, beforeEach, describe, expect, test } from "bun:test";
|
|
2
|
+
import { mkdtempSync, rmSync } from "fs";
|
|
3
|
+
import { tmpdir } from "os";
|
|
4
|
+
import { join } from "path";
|
|
5
|
+
|
|
6
|
+
import { saveAssistantEntry } from "../lib/assistant-config.js";
|
|
7
|
+
import { completeCadet } from "./completions.js";
|
|
8
|
+
|
|
9
|
+
const COMMAND_NAMES = [
|
|
10
|
+
"backup",
|
|
11
|
+
"clean",
|
|
12
|
+
"client",
|
|
13
|
+
"completions",
|
|
14
|
+
"confirm",
|
|
15
|
+
"connect",
|
|
16
|
+
"hatch",
|
|
17
|
+
"ps",
|
|
18
|
+
"retire",
|
|
19
|
+
"sleep",
|
|
20
|
+
"use",
|
|
21
|
+
"wake",
|
|
22
|
+
];
|
|
23
|
+
|
|
24
|
+
describe("completeCadet", () => {
|
|
25
|
+
let lockfileDir: string;
|
|
26
|
+
let prevLockfileDir: string | undefined;
|
|
27
|
+
|
|
28
|
+
beforeEach(() => {
|
|
29
|
+
lockfileDir = mkdtempSync(join(tmpdir(), "cadet-completions-"));
|
|
30
|
+
prevLockfileDir = process.env.CADET_LOCKFILE_DIR;
|
|
31
|
+
process.env.CADET_LOCKFILE_DIR = lockfileDir;
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
afterEach(() => {
|
|
35
|
+
if (prevLockfileDir === undefined) delete process.env.CADET_LOCKFILE_DIR;
|
|
36
|
+
else process.env.CADET_LOCKFILE_DIR = prevLockfileDir;
|
|
37
|
+
rmSync(lockfileDir, { recursive: true, force: true });
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
function seed(id: string): void {
|
|
41
|
+
saveAssistantEntry({
|
|
42
|
+
assistantId: id,
|
|
43
|
+
cloud: "docker",
|
|
44
|
+
runtimeUrl: "http://localhost:7830",
|
|
45
|
+
hatchedAt: new Date().toISOString(),
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
test("no words yet offers every command name, sorted", () => {
|
|
50
|
+
const input: string[] = [];
|
|
51
|
+
expect(completeCadet(input, COMMAND_NAMES)).toEqual(
|
|
52
|
+
[...COMMAND_NAMES].sort(),
|
|
53
|
+
);
|
|
54
|
+
// The word under the cursor is popped from a COPY — the caller's array
|
|
55
|
+
// (bash's COMP_WORDS) must come back untouched.
|
|
56
|
+
expect(input).toEqual([]);
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
test("first positional of an assistant-name command offers known assistant names", () => {
|
|
60
|
+
seed("quill-owl-d4e5f6");
|
|
61
|
+
seed("fable-fox-a1b2c3");
|
|
62
|
+
// `cadet retire <TAB>` — the empty trailing word is the word being completed.
|
|
63
|
+
expect(completeCadet(["retire", ""], COMMAND_NAMES)).toEqual([
|
|
64
|
+
"fable-fox-a1b2c3",
|
|
65
|
+
"quill-owl-d4e5f6",
|
|
66
|
+
]);
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
test("partial words are returned unfiltered — the shell does prefix filtering", () => {
|
|
70
|
+
seed("quill-owl-d4e5f6");
|
|
71
|
+
seed("fable-fox-a1b2c3");
|
|
72
|
+
expect(completeCadet(["retire", "fable"], COMMAND_NAMES)).toEqual([
|
|
73
|
+
"fable-fox-a1b2c3",
|
|
74
|
+
"quill-owl-d4e5f6",
|
|
75
|
+
]);
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
test("flag prefixes fall through to the shell default (no candidates)", () => {
|
|
79
|
+
seed("fable-fox-a1b2c3");
|
|
80
|
+
expect(completeCadet(["retire", "--"], COMMAND_NAMES)).toEqual([]);
|
|
81
|
+
expect(completeCadet(["retire", "--name"], COMMAND_NAMES)).toEqual([]);
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
test("deeper positionals of an assistant-name command offer nothing", () => {
|
|
85
|
+
seed("fable-fox-a1b2c3");
|
|
86
|
+
expect(
|
|
87
|
+
completeCadet(["exec", "fable-fox-a1b2c3", ""], COMMAND_NAMES),
|
|
88
|
+
).toEqual([]);
|
|
89
|
+
expect(
|
|
90
|
+
completeCadet(["logs", "fable-fox-a1b2c3", "tail", ""], COMMAND_NAMES),
|
|
91
|
+
).toEqual([]);
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
test("commands that take no assistant name offer nothing after the command word", () => {
|
|
95
|
+
seed("fable-fox-a1b2c3");
|
|
96
|
+
expect(completeCadet(["hatch", ""], COMMAND_NAMES)).toEqual([]);
|
|
97
|
+
expect(completeCadet(["ps", ""], COMMAND_NAMES)).toEqual([]);
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
test("an unreadable/empty lockfile completes quietly with no names", () => {
|
|
101
|
+
// No entries seeded — the lockfile dir exists but has no lockfile.json.
|
|
102
|
+
expect(completeCadet(["retire", ""], COMMAND_NAMES)).toEqual([]);
|
|
103
|
+
});
|
|
104
|
+
});
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import { loadAllAssistants } from "../lib/assistant-config.js";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Commands whose first positional argument is an assistant name — completing
|
|
5
|
+
* their first word offers the names of known assistants (from the lockfile)
|
|
6
|
+
* instead of falling through to shell file completion.
|
|
7
|
+
*/
|
|
8
|
+
const ASSISTANT_NAME_COMMANDS = new Set([
|
|
9
|
+
"exec",
|
|
10
|
+
"logs",
|
|
11
|
+
"message",
|
|
12
|
+
"restart",
|
|
13
|
+
"restore",
|
|
14
|
+
"retire",
|
|
15
|
+
"rollback",
|
|
16
|
+
"sleep",
|
|
17
|
+
"teleport",
|
|
18
|
+
"terminal",
|
|
19
|
+
"tunnel",
|
|
20
|
+
"unpair",
|
|
21
|
+
"upgrade",
|
|
22
|
+
"use",
|
|
23
|
+
"wake",
|
|
24
|
+
]);
|
|
25
|
+
|
|
26
|
+
/** Assistant names known to this CLI's lockfile; [] when the lockfile is unreadable. */
|
|
27
|
+
function assistantNames(): string[] {
|
|
28
|
+
try {
|
|
29
|
+
return loadAllAssistants()
|
|
30
|
+
.map((entry) => entry.assistantId)
|
|
31
|
+
.sort();
|
|
32
|
+
} catch {
|
|
33
|
+
return [];
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Resolve completion candidates for the word the cursor is on.
|
|
39
|
+
*
|
|
40
|
+
* `words` carries every command-line word after `cadet` up to the cursor,
|
|
41
|
+
* INCLUDING the (possibly empty) word being completed — the same shape bash
|
|
42
|
+
* passes via `COMP_WORDS[@]:1`. The returned list is UNFILTERED: the shell
|
|
43
|
+
* (`compgen -W`) does the prefix filtering, so the CLI only decides WHAT
|
|
44
|
+
* KIND of thing completes here.
|
|
45
|
+
*/
|
|
46
|
+
export function completeCadet(
|
|
47
|
+
input: string[],
|
|
48
|
+
commandNames: readonly string[],
|
|
49
|
+
): string[] {
|
|
50
|
+
const words = [...input];
|
|
51
|
+
const toComplete = words.pop() ?? "";
|
|
52
|
+
const preceding = words;
|
|
53
|
+
|
|
54
|
+
// Completing the command word itself (or nothing typed yet).
|
|
55
|
+
if (preceding.length === 0) {
|
|
56
|
+
return [...commandNames].sort();
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// First positional of an assistant-name command: offer instance names.
|
|
60
|
+
// Flag prefixes fall through to shell default (no flag completion yet).
|
|
61
|
+
if (
|
|
62
|
+
preceding.length === 1 &&
|
|
63
|
+
ASSISTANT_NAME_COMMANDS.has(preceding[0]) &&
|
|
64
|
+
!toComplete.startsWith("-")
|
|
65
|
+
) {
|
|
66
|
+
return assistantNames();
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
return [];
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
const BASH_COMPLETION_SCRIPT = `# bash completion for the cadet CLI — load with: eval "$(cadet completions)"
|
|
73
|
+
_cadet_completions() {
|
|
74
|
+
local candidates
|
|
75
|
+
candidates=$(cadet __complete "\${COMP_WORDS[@]:1}" 2>/dev/null)
|
|
76
|
+
COMPREPLY=($(compgen -W "$candidates" -- "\${COMP_WORDS[COMP_CWORD]}"))
|
|
77
|
+
}
|
|
78
|
+
complete -F _cadet_completions cadet`;
|
|
79
|
+
|
|
80
|
+
// ── Entry point ─────────────────────────────────────────────────
|
|
81
|
+
|
|
82
|
+
export const completions = Object.assign(
|
|
83
|
+
async function completions(): Promise<void> {
|
|
84
|
+
console.log(BASH_COMPLETION_SCRIPT);
|
|
85
|
+
},
|
|
86
|
+
{ description: `Print bash completion setup (eval "$(cadet completions)")` },
|
|
87
|
+
);
|
package/src/commands/exec.ts
CHANGED
|
@@ -75,28 +75,28 @@ export const exec = Object.assign(
|
|
|
75
75
|
console.log("");
|
|
76
76
|
console.log("Arguments:");
|
|
77
77
|
console.log(
|
|
78
|
-
" <name> Name of the assistant
|
|
78
|
+
" <name> Name of the assistant, defaults to active",
|
|
79
79
|
);
|
|
80
80
|
console.log(
|
|
81
81
|
" <command...> Command and arguments to run (after --)",
|
|
82
82
|
);
|
|
83
83
|
console.log("");
|
|
84
84
|
console.log("Options:");
|
|
85
|
-
console.log(" --service <svc> Target service
|
|
85
|
+
console.log(" --service <svc> Target service, defaults to assistant");
|
|
86
86
|
console.log(
|
|
87
87
|
" -it Interactive mode with TTY (like docker exec -it)",
|
|
88
88
|
);
|
|
89
89
|
console.log(
|
|
90
|
-
" --timeout <secs> Timeout in seconds
|
|
90
|
+
" --timeout <secs> Timeout in seconds — default 30, 0 = no timeout",
|
|
91
91
|
);
|
|
92
92
|
console.log(
|
|
93
|
-
" --verbose Show debug output
|
|
93
|
+
" --verbose Show debug output",
|
|
94
94
|
);
|
|
95
95
|
console.log("");
|
|
96
96
|
console.log("Services:");
|
|
97
|
-
console.log(" assistant
|
|
98
|
-
console.log(" gateway
|
|
99
|
-
console.log(" credential-executor
|
|
97
|
+
console.log(" assistant");
|
|
98
|
+
console.log(" gateway");
|
|
99
|
+
console.log(" credential-executor");
|
|
100
100
|
console.log("");
|
|
101
101
|
console.log("Examples:");
|
|
102
102
|
console.log(" cadet exec -- ls -la /workspace");
|
package/src/commands/flags.ts
CHANGED
|
@@ -59,7 +59,7 @@ function printFlagTable(flags: FeatureFlagEntry[]): void {
|
|
|
59
59
|
console.log(formatRow(row));
|
|
60
60
|
}
|
|
61
61
|
console.log("");
|
|
62
|
-
console.log("* = overridden
|
|
62
|
+
console.log("* = overridden");
|
|
63
63
|
}
|
|
64
64
|
|
|
65
65
|
function printHelp(): void {
|
|
@@ -67,7 +67,7 @@ function printHelp(): void {
|
|
|
67
67
|
console.log("");
|
|
68
68
|
console.log("Show and toggle feature flags for the active assistant.");
|
|
69
69
|
console.log(
|
|
70
|
-
"Reads from the gateway's merged flag state
|
|
70
|
+
"Reads from the gateway's merged flag state.",
|
|
71
71
|
);
|
|
72
72
|
console.log("");
|
|
73
73
|
console.log("Subcommands:");
|
package/src/commands/hatch.ts
CHANGED
|
@@ -76,7 +76,7 @@ function parseArgs(): HatchArgs {
|
|
|
76
76
|
" --watch Run assistant and gateway in watch mode (hot reload on source changes)",
|
|
77
77
|
);
|
|
78
78
|
console.log(
|
|
79
|
-
" --source <path> Build images from a local source tree at <path
|
|
79
|
+
" --source <path> Build images from a local source tree at <path>. Useful for callers that want each run to pick up local CLI changes.",
|
|
80
80
|
);
|
|
81
81
|
console.log(
|
|
82
82
|
" --keep-alive Stay alive after hatch, exit when gateway stops",
|
package/src/commands/logs.ts
CHANGED
|
@@ -32,19 +32,19 @@ function printHelp(): void {
|
|
|
32
32
|
console.log("");
|
|
33
33
|
console.log("Arguments:");
|
|
34
34
|
console.log(
|
|
35
|
-
" <name> Name of the assistant
|
|
35
|
+
" <name> Name of the assistant, defaults to latest",
|
|
36
36
|
);
|
|
37
37
|
console.log("");
|
|
38
38
|
console.log("Options:");
|
|
39
|
-
console.log(" -f, --follow Follow log output
|
|
40
|
-
console.log(" -n, --tail <N> Show last N lines
|
|
39
|
+
console.log(" -f, --follow Follow log output");
|
|
40
|
+
console.log(" -n, --tail <N> Show last N lines");
|
|
41
41
|
console.log(" -t, --timestamps Show timestamps on each line");
|
|
42
42
|
console.log(
|
|
43
|
-
" --since <time> Show logs since timestamp or relative
|
|
43
|
+
" --since <time> Show logs since timestamp or relative, e.g. 10m or 2h",
|
|
44
44
|
);
|
|
45
45
|
console.log(" --until <time> Show logs until timestamp or relative");
|
|
46
46
|
console.log(
|
|
47
|
-
" -s, --service <name> Filter to a specific service
|
|
47
|
+
" -s, --service <name> Filter to a specific service",
|
|
48
48
|
);
|
|
49
49
|
console.log(" -h, --help Show this help");
|
|
50
50
|
}
|
|
@@ -186,13 +186,13 @@ async function showLocalLogs(
|
|
|
186
186
|
|
|
187
187
|
if (opts.since && !sinceDate) {
|
|
188
188
|
console.error(
|
|
189
|
-
`Error: Could not parse --since value '${opts.since}'. Use relative
|
|
189
|
+
`Error: Could not parse --since value '${opts.since}'. Use a relative value such as 10m or 2h, or ISO format.`,
|
|
190
190
|
);
|
|
191
191
|
process.exit(1);
|
|
192
192
|
}
|
|
193
193
|
if (opts.until && !untilDate) {
|
|
194
194
|
console.error(
|
|
195
|
-
`Error: Could not parse --until value '${opts.until}'. Use relative
|
|
195
|
+
`Error: Could not parse --until value '${opts.until}'. Use a relative value such as 10m or 2h, or ISO format.`,
|
|
196
196
|
);
|
|
197
197
|
process.exit(1);
|
|
198
198
|
}
|
package/src/commands/ps.ts
CHANGED
|
@@ -64,8 +64,54 @@ interface ColWidths {
|
|
|
64
64
|
info: number;
|
|
65
65
|
}
|
|
66
66
|
|
|
67
|
+
/**
|
|
68
|
+
* Terminal display width for table alignment: emoji render two cells wide
|
|
69
|
+
* (including ZWJ sequences like 🧑🚀 and VS16 pairs like ⚠️), while the ZWJ
|
|
70
|
+
* and variation selectors themselves render zero. `.length` counts UTF-16
|
|
71
|
+
* units and none of that, which is what broke the STATUS and INFO columns
|
|
72
|
+
* whenever an emoji appeared in an earlier one.
|
|
73
|
+
*/
|
|
74
|
+
export function displayWidth(s: string): number {
|
|
75
|
+
const chars = [...s];
|
|
76
|
+
let width = 0;
|
|
77
|
+
// A ZWJ joins the previous and next glyphs into ONE grapheme (🧑🚀 renders
|
|
78
|
+
// as a single 2-cell astronaut), so the glyph after a ZWJ adds no width.
|
|
79
|
+
let joinedByZwj = false;
|
|
80
|
+
for (let i = 0; i < chars.length; i++) {
|
|
81
|
+
const cp = chars[i]?.codePointAt(0) ?? 0;
|
|
82
|
+
// Zero-width: the joiner, the variation selectors, skin-tone modifiers.
|
|
83
|
+
if (cp === 0x200d) {
|
|
84
|
+
joinedByZwj = true;
|
|
85
|
+
continue;
|
|
86
|
+
}
|
|
87
|
+
if (cp === 0xfe0e || cp === 0xfe0f) continue;
|
|
88
|
+
if (cp >= 0x1f3fb && cp <= 0x1f3ff) continue;
|
|
89
|
+
const next = chars[i + 1]?.codePointAt(0);
|
|
90
|
+
if (!joinedByZwj) {
|
|
91
|
+
// A VS16 after a narrow symbol forces emoji presentation — two cells.
|
|
92
|
+
width += isWideCodePoint(cp) || next === 0xfe0f ? 2 : 1;
|
|
93
|
+
}
|
|
94
|
+
joinedByZwj = false;
|
|
95
|
+
}
|
|
96
|
+
return width;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
function isWideCodePoint(cp: number): boolean {
|
|
100
|
+
return (
|
|
101
|
+
(cp >= 0x1100 && cp <= 0x115f) || // Hangul Jamo
|
|
102
|
+
(cp >= 0x2e80 && cp <= 0x303e) || // CJK radicals and punctuation
|
|
103
|
+
(cp >= 0x3040 && cp <= 0x318f) || // Hiragana, Katakana, bopomofo
|
|
104
|
+
(cp >= 0xac00 && cp <= 0xd7a3) || // Hangul syllables
|
|
105
|
+
(cp >= 0xf900 && cp <= 0xfaff) || // CJK compatibility ideographs
|
|
106
|
+
(cp >= 0xfe30 && cp <= 0xfe6f) || // CJK compatibility forms
|
|
107
|
+
(cp >= 0xff00 && cp <= 0xff60) || // fullwidth forms
|
|
108
|
+
(cp >= 0xffe0 && cp <= 0xffe6) ||
|
|
109
|
+
cp >= 0x1f000 // emoji and symbol blocks (🟢, 🚀, 🧑, …)
|
|
110
|
+
);
|
|
111
|
+
}
|
|
112
|
+
|
|
67
113
|
function pad(s: string, w: number): string {
|
|
68
|
-
return s + " ".repeat(Math.max(0, w - s
|
|
114
|
+
return s + " ".repeat(Math.max(0, w - displayWidth(s)));
|
|
69
115
|
}
|
|
70
116
|
|
|
71
117
|
function computeColWidths(
|
|
@@ -79,14 +125,17 @@ function computeColWidths(
|
|
|
79
125
|
): ColWidths {
|
|
80
126
|
const all = [headers, ...rows];
|
|
81
127
|
return {
|
|
82
|
-
name: Math.max(...all.map((r) => r.name
|
|
83
|
-
type: Math.max(...all.map((r) => r.type
|
|
84
|
-
status: Math.max(
|
|
85
|
-
|
|
128
|
+
name: Math.max(...all.map((r) => displayWidth(r.name))),
|
|
129
|
+
type: Math.max(...all.map((r) => displayWidth(r.type))),
|
|
130
|
+
status: Math.max(
|
|
131
|
+
...all.map((r) => displayWidth(r.status)),
|
|
132
|
+
"checking...".length,
|
|
133
|
+
),
|
|
134
|
+
info: Math.max(...all.map((r) => displayWidth(r.info))),
|
|
86
135
|
};
|
|
87
136
|
}
|
|
88
137
|
|
|
89
|
-
function formatRow(r: TableRow, colWidths: ColWidths): string {
|
|
138
|
+
export function formatRow(r: TableRow, colWidths: ColWidths): string {
|
|
90
139
|
return ` ${pad(r.name, colWidths.name)} ${pad(r.type, colWidths.type)} ${pad(r.status, colWidths.status)} ${r.info}`;
|
|
91
140
|
}
|
|
92
141
|
|
|
@@ -459,7 +508,7 @@ async function getAssistantProcessRows(
|
|
|
459
508
|
): Promise<TableRow[]> {
|
|
460
509
|
const cloud = entry.cloud;
|
|
461
510
|
|
|
462
|
-
console.log(`Processes for ${formatAssistantReference(entry)}
|
|
511
|
+
console.log(`Processes for ${formatAssistantReference(entry)} — ${cloud}:`);
|
|
463
512
|
console.log(`Location: ${locationFor(entry)}\n`);
|
|
464
513
|
|
|
465
514
|
if (cloud === "local") {
|
|
@@ -830,5 +879,5 @@ export const ps = Object.assign(
|
|
|
830
879
|
}
|
|
831
880
|
printTable(rows);
|
|
832
881
|
},
|
|
833
|
-
{ description: "List assistants
|
|
882
|
+
{ description: "List assistants" },
|
|
834
883
|
);
|
package/src/commands/restore.ts
CHANGED
|
@@ -474,7 +474,7 @@ async function restorePlatform(
|
|
|
474
474
|
}
|
|
475
475
|
}
|
|
476
476
|
// Transient error (5xx, network) — retry
|
|
477
|
-
console.warn(`Polling failed
|
|
477
|
+
console.warn(`Polling failed: ${msg}. Retrying...`);
|
|
478
478
|
continue;
|
|
479
479
|
}
|
|
480
480
|
|
|
@@ -680,7 +680,7 @@ export const restore = Object.assign(
|
|
|
680
680
|
}
|
|
681
681
|
|
|
682
682
|
const sizeMB = formatBundleSizeMb(bundleFileSizeBytes(fromPath));
|
|
683
|
-
console.log(`Reading ${fromPath}
|
|
683
|
+
console.log(`Reading ${fromPath} — ${sizeMB} MB...`);
|
|
684
684
|
|
|
685
685
|
// Detect topology and route platform assistants through Django import
|
|
686
686
|
const cloud =
|
package/src/commands/retire.ts
CHANGED
|
@@ -287,12 +287,12 @@ async function retireInner(): Promise<void> {
|
|
|
287
287
|
console.log("");
|
|
288
288
|
console.log("Delete an assistant instance and archive its data.");
|
|
289
289
|
console.log(
|
|
290
|
-
"With no name or ID, retires the active assistant
|
|
290
|
+
"With no name or ID, retires the active assistant — see `cadet use`. By default, retire prints the assistant name, ID, cloud, and runtime before asking for confirmation.",
|
|
291
291
|
);
|
|
292
292
|
console.log("");
|
|
293
293
|
console.log("Arguments:");
|
|
294
294
|
console.log(
|
|
295
|
-
" <name-or-id> Assistant display name or ID to retire
|
|
295
|
+
" <name-or-id> Assistant display name or ID to retire, defaults to the active assistant",
|
|
296
296
|
);
|
|
297
297
|
console.log("");
|
|
298
298
|
console.log("Options:");
|
package/src/commands/rollback.ts
CHANGED
|
@@ -51,12 +51,12 @@ function parseArgs(): { name: string | null; version: string | null } {
|
|
|
51
51
|
console.log("");
|
|
52
52
|
console.log("Arguments:");
|
|
53
53
|
console.log(
|
|
54
|
-
" <name> Name of the assistant
|
|
54
|
+
" <name> Name of the assistant, defaults to active or only assistant",
|
|
55
55
|
);
|
|
56
56
|
console.log("");
|
|
57
57
|
console.log("Options:");
|
|
58
58
|
console.log(
|
|
59
|
-
" --version <version> Target version
|
|
59
|
+
" --version <version> Target version, optional for managed — omit to roll back to previous",
|
|
60
60
|
);
|
|
61
61
|
console.log("");
|
|
62
62
|
console.log("Examples:");
|
package/src/commands/sleep.ts
CHANGED
|
@@ -71,7 +71,7 @@ export const sleep = Object.assign(
|
|
|
71
71
|
console.log("");
|
|
72
72
|
console.log("Arguments:");
|
|
73
73
|
console.log(
|
|
74
|
-
" <name> Name of the assistant to stop
|
|
74
|
+
" <name> Name of the assistant to stop, defaults to active or only local",
|
|
75
75
|
);
|
|
76
76
|
console.log("");
|
|
77
77
|
console.log("Options:");
|
|
@@ -88,7 +88,7 @@ export const sleep = Object.assign(
|
|
|
88
88
|
" schedules) to finish before stopping. Waits as long as it",
|
|
89
89
|
);
|
|
90
90
|
console.log(
|
|
91
|
-
" takes by default; pass a duration
|
|
91
|
+
" takes by default; pass a duration, e.g. --wait 90s or --wait 10m",
|
|
92
92
|
);
|
|
93
93
|
console.log(
|
|
94
94
|
" to bound the wait. Ctrl-C cancels and leaves the assistant running.",
|
package/src/commands/teleport.ts
CHANGED
|
@@ -100,7 +100,7 @@ function printHelp(): void {
|
|
|
100
100
|
console.log(
|
|
101
101
|
"The source and target must be different environments. Same-environment",
|
|
102
102
|
);
|
|
103
|
-
console.log("transfers
|
|
103
|
+
console.log("transfers such as local to local are not supported.");
|
|
104
104
|
console.log("");
|
|
105
105
|
console.log(
|
|
106
106
|
"Before exporting, the source assistant is backed up. Platform sources",
|
|
@@ -159,7 +159,7 @@ function printHelp(): void {
|
|
|
159
159
|
" Import data from my-local into existing docker assistant my-docker",
|
|
160
160
|
);
|
|
161
161
|
console.log(
|
|
162
|
-
"
|
|
162
|
+
" or hatch a new docker assistant named my-docker if it doesn't exist",
|
|
163
163
|
);
|
|
164
164
|
console.log("");
|
|
165
165
|
console.log(" cadet teleport --from my-local --platform");
|
|
@@ -415,7 +415,7 @@ async function backupSourceBeforeTeleport(
|
|
|
415
415
|
cloud: string,
|
|
416
416
|
displayName: string,
|
|
417
417
|
): Promise<void> {
|
|
418
|
-
console.log(`Backing up ${displayName}
|
|
418
|
+
console.log(`Backing up ${displayName} on ${cloud}...`);
|
|
419
419
|
try {
|
|
420
420
|
if (isCloudHome(cloud)) {
|
|
421
421
|
const cloudToken = readCloudToken();
|
|
@@ -443,7 +443,7 @@ async function backupSourceBeforeTeleport(
|
|
|
443
443
|
timeoutMs: LOCAL_SOURCE_BACKUP_TIMEOUT_MS,
|
|
444
444
|
});
|
|
445
445
|
if (!backupPath) {
|
|
446
|
-
throw new Error("backup export failed
|
|
446
|
+
throw new Error("backup export failed — see the warning above");
|
|
447
447
|
}
|
|
448
448
|
pruneOldBackups(entry.assistantId, 3, "pre-teleport");
|
|
449
449
|
console.log(`Backup saved: ${backupPath}`);
|
|
@@ -470,7 +470,7 @@ async function exportFromAssistant(
|
|
|
470
470
|
const cloudToken = readCloudToken();
|
|
471
471
|
if (!cloudToken) {
|
|
472
472
|
console.error(
|
|
473
|
-
"Not logged in. Run 'cadet login' first
|
|
473
|
+
"Not logged in. Run 'cadet login' first.",
|
|
474
474
|
);
|
|
475
475
|
process.exit(1);
|
|
476
476
|
}
|
|
@@ -688,7 +688,7 @@ async function importToAssistant(
|
|
|
688
688
|
const cloudToken = readCloudToken();
|
|
689
689
|
if (!cloudToken) {
|
|
690
690
|
console.error(
|
|
691
|
-
"Not logged in. Run 'cadet login' first
|
|
691
|
+
"Not logged in. Run 'cadet login' first.",
|
|
692
692
|
);
|
|
693
693
|
process.exit(1);
|
|
694
694
|
}
|
|
@@ -990,7 +990,7 @@ export async function resolveOrHatchTarget(
|
|
|
990
990
|
);
|
|
991
991
|
process.exit(1);
|
|
992
992
|
}
|
|
993
|
-
console.log(`Target: ${targetName}
|
|
993
|
+
console.log(`Target: ${targetName} — ${targetEnv}`);
|
|
994
994
|
return existing;
|
|
995
995
|
}
|
|
996
996
|
|
|
@@ -1204,7 +1204,7 @@ async function tryInjectCloudCredentials(
|
|
|
1204
1204
|
): Promise<void> {
|
|
1205
1205
|
const token = readCloudToken();
|
|
1206
1206
|
if (!token) {
|
|
1207
|
-
console.log(" Skipped cloud credential injection
|
|
1207
|
+
console.log(" Skipped cloud credential injection — not logged in.");
|
|
1208
1208
|
return;
|
|
1209
1209
|
}
|
|
1210
1210
|
|
|
@@ -1393,13 +1393,13 @@ export const teleport = Object.assign(
|
|
|
1393
1393
|
? fromEntry.runtimeUrl
|
|
1394
1394
|
: undefined;
|
|
1395
1395
|
|
|
1396
|
-
console.log(`Exporting from ${from}
|
|
1396
|
+
console.log(`Exporting from ${from} on ${fromCloud}...`);
|
|
1397
1397
|
const { bundleKey } = await exportFromAssistant(
|
|
1398
1398
|
fromEntry,
|
|
1399
1399
|
fromCloud,
|
|
1400
1400
|
bundleCloudUrl,
|
|
1401
1401
|
);
|
|
1402
|
-
console.log(`Importing to ${existingTarget.assistantId}
|
|
1402
|
+
console.log(`Importing to ${existingTarget.assistantId} on ${toCloud}...`);
|
|
1403
1403
|
await importToAssistant(
|
|
1404
1404
|
existingTarget,
|
|
1405
1405
|
toCloud,
|
|
@@ -1410,7 +1410,7 @@ export const teleport = Object.assign(
|
|
|
1410
1410
|
} else {
|
|
1411
1411
|
// No existing target — just describe what would happen
|
|
1412
1412
|
console.log("Dry run summary:");
|
|
1413
|
-
console.log(` Would export data from: ${from}
|
|
1413
|
+
console.log(` Would export data from: ${from} on ${fromCloud}`);
|
|
1414
1414
|
console.log(` Would upload bundle via signed URL`);
|
|
1415
1415
|
console.log(
|
|
1416
1416
|
` Would hatch a new ${targetEnv} assistant${targetName ? ` named '${targetName}'` : ""}`,
|
|
@@ -1482,7 +1482,7 @@ export const teleport = Object.assign(
|
|
|
1482
1482
|
// resolveOrHatchTarget writes to the new entry).
|
|
1483
1483
|
await backupSourceBeforeTeleport(fromEntry, fromCloud, from);
|
|
1484
1484
|
|
|
1485
|
-
console.log(`Exporting from ${from}
|
|
1485
|
+
console.log(`Exporting from ${from} on ${fromCloud}...`);
|
|
1486
1486
|
const bundleCloudUrl = targetCloudUrl ?? getCloudUrl();
|
|
1487
1487
|
const { bundleKey } = await exportFromAssistant(
|
|
1488
1488
|
fromEntry,
|
|
@@ -1495,7 +1495,7 @@ export const teleport = Object.assign(
|
|
|
1495
1495
|
const toCloud = toEntry.cloud;
|
|
1496
1496
|
|
|
1497
1497
|
// Import from GCS
|
|
1498
|
-
console.log(`Importing to ${toEntry.assistantId}
|
|
1498
|
+
console.log(`Importing to ${toEntry.assistantId} on ${toCloud}...`);
|
|
1499
1499
|
await importToAssistant(
|
|
1500
1500
|
toEntry,
|
|
1501
1501
|
toCloud,
|
|
@@ -1555,7 +1555,7 @@ export const teleport = Object.assign(
|
|
|
1555
1555
|
await backupSourceBeforeTeleport(fromEntry, fromCloud, from);
|
|
1556
1556
|
|
|
1557
1557
|
// Export from source (bundle lives in GCS after this returns).
|
|
1558
|
-
console.log(`Exporting from ${from}
|
|
1558
|
+
console.log(`Exporting from ${from} on ${fromCloud}...`);
|
|
1559
1559
|
const { bundleKey } = await exportFromAssistant(
|
|
1560
1560
|
fromEntry,
|
|
1561
1561
|
fromCloud,
|
|
@@ -1632,7 +1632,7 @@ export const teleport = Object.assign(
|
|
|
1632
1632
|
}
|
|
1633
1633
|
|
|
1634
1634
|
// Import to target (also GCS-driven)
|
|
1635
|
-
console.log(`Importing to ${toEntry.assistantId}
|
|
1635
|
+
console.log(`Importing to ${toEntry.assistantId} on ${toCloud}...`);
|
|
1636
1636
|
await importToAssistant(
|
|
1637
1637
|
toEntry,
|
|
1638
1638
|
toCloud,
|
|
@@ -1660,7 +1660,7 @@ export const teleport = Object.assign(
|
|
|
1660
1660
|
removeAssistantEntry(fromEntry.assistantId);
|
|
1661
1661
|
console.log(`Source assistant '${from}' retired.`);
|
|
1662
1662
|
} else {
|
|
1663
|
-
console.log(`Source assistant '${from}' kept
|
|
1663
|
+
console.log(`Source assistant '${from}' kept via --keep-source.`);
|
|
1664
1664
|
}
|
|
1665
1665
|
}
|
|
1666
1666
|
|
package/src/commands/terminal.ts
CHANGED
|
@@ -71,7 +71,7 @@ function printHelp(): void {
|
|
|
71
71
|
console.log("");
|
|
72
72
|
console.log("Options:");
|
|
73
73
|
console.log(
|
|
74
|
-
" <name> Name of the assistant
|
|
74
|
+
" <name> Name of the assistant, defaults to active",
|
|
75
75
|
);
|
|
76
76
|
console.log(
|
|
77
77
|
" --assistant <name> Explicit assistant name (alternative to positional)",
|