@mycadet/cli 0.12.7 → 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/README.md +2 -2
- package/knip.json +1 -1
- package/node_modules/@mycadet/assistant-api/events/cloud-disconnected.ts +21 -0
- package/node_modules/@mycadet/assistant-api/events/host-bash.ts +1 -1
- package/node_modules/@mycadet/assistant-api/events/host-cu.ts +1 -1
- package/node_modules/@mycadet/assistant-api/events/host-file.ts +1 -1
- package/node_modules/@mycadet/assistant-api/events/notification-intent.ts +1 -1
- package/node_modules/@mycadet/assistant-api/events/show-cloud-login.ts +18 -0
- package/node_modules/@mycadet/assistant-api/index.ts +11 -11
- package/node_modules/@mycadet/assistant-api/node_modules/@mycadet/service-contracts/package.json +2 -2
- package/node_modules/@mycadet/{service-contracts/src/platform-credential.ts → assistant-api/node_modules/@mycadet/service-contracts/src/cloud-credential.ts} +9 -9
- package/node_modules/@mycadet/assistant-api/node_modules/@mycadet/service-contracts/src/handles.ts +3 -3
- package/node_modules/@mycadet/assistant-api/node_modules/@mycadet/service-contracts/src/index.ts +1 -1
- package/node_modules/@mycadet/assistant-api/node_modules/@mycadet/service-contracts/src/ingress.ts +11 -5
- package/node_modules/@mycadet/assistant-api/node_modules/@mycadet/service-contracts/src/remote-web-pairing.ts +1 -1
- package/node_modules/@mycadet/assistant-api/node_modules/@mycadet/service-contracts/src/rpc.ts +14 -14
- package/node_modules/@mycadet/assistant-api/node_modules/@mycadet/service-contracts/src/trust-rules.ts +5 -5
- package/node_modules/@mycadet/assistant-api/responses/home.ts +1 -1
- package/node_modules/@mycadet/assistant-api/surfaces.ts +4 -4
- package/node_modules/@mycadet/avatar-manifest/src/__tests__/notification-avatar.test.ts +1 -1
- package/node_modules/@mycadet/avatar-manifest/src/notification-avatar.ts +2 -2
- package/node_modules/@mycadet/environments/src/seeds.ts +6 -6
- package/node_modules/@mycadet/environments/src/shell.test.ts +1 -1
- package/node_modules/@mycadet/environments/src/types.ts +6 -6
- package/node_modules/@mycadet/local-mode/node_modules/@mycadet/avatar-manifest/src/__tests__/notification-avatar.test.ts +1 -1
- package/node_modules/@mycadet/local-mode/node_modules/@mycadet/avatar-manifest/src/notification-avatar.ts +2 -2
- package/node_modules/@mycadet/local-mode/node_modules/@mycadet/environments/src/seeds.ts +6 -6
- package/node_modules/@mycadet/local-mode/node_modules/@mycadet/environments/src/shell.test.ts +1 -1
- package/node_modules/@mycadet/local-mode/node_modules/@mycadet/environments/src/types.ts +6 -6
- package/node_modules/@mycadet/local-mode/node_modules/@mycadet/service-contracts/package.json +2 -2
- package/node_modules/@mycadet/{assistant-api/node_modules/@mycadet/service-contracts/src/platform-credential.ts → local-mode/node_modules/@mycadet/service-contracts/src/cloud-credential.ts} +9 -9
- package/node_modules/@mycadet/local-mode/node_modules/@mycadet/service-contracts/src/handles.ts +3 -3
- package/node_modules/@mycadet/local-mode/node_modules/@mycadet/service-contracts/src/index.ts +1 -1
- package/node_modules/@mycadet/local-mode/node_modules/@mycadet/service-contracts/src/ingress.ts +11 -5
- package/node_modules/@mycadet/local-mode/node_modules/@mycadet/service-contracts/src/remote-web-pairing.ts +1 -1
- package/node_modules/@mycadet/local-mode/node_modules/@mycadet/service-contracts/src/rpc.ts +14 -14
- package/node_modules/@mycadet/local-mode/node_modules/@mycadet/service-contracts/src/trust-rules.ts +5 -5
- package/node_modules/@mycadet/local-mode/src/__tests__/pair.test.ts +5 -5
- package/node_modules/@mycadet/local-mode/src/__tests__/retire.test.ts +1 -1
- package/node_modules/@mycadet/local-mode/src/config.ts +2 -2
- package/node_modules/@mycadet/local-mode/src/index.ts +1 -1
- package/node_modules/@mycadet/local-mode/src/lockfile-contract.test.ts +3 -3
- package/node_modules/@mycadet/local-mode/src/lockfile-contract.ts +10 -5
- package/node_modules/@mycadet/local-mode/src/lockfile.test.ts +15 -15
- package/node_modules/@mycadet/local-mode/src/lockfile.ts +9 -9
- package/node_modules/@mycadet/local-mode/src/pair.ts +2 -2
- package/node_modules/@mycadet/local-mode/src/retire.ts +3 -3
- package/node_modules/@mycadet/local-mode/src/teleport-backup-policy.ts +2 -2
- package/node_modules/@mycadet/local-mode/src/unpair.ts +2 -2
- package/node_modules/@mycadet/service-contracts/package.json +2 -2
- package/node_modules/@mycadet/{local-mode/node_modules/@mycadet/service-contracts/src/platform-credential.ts → service-contracts/src/cloud-credential.ts} +9 -9
- package/node_modules/@mycadet/service-contracts/src/handles.ts +3 -3
- package/node_modules/@mycadet/service-contracts/src/index.ts +1 -1
- package/node_modules/@mycadet/service-contracts/src/ingress.ts +11 -5
- package/node_modules/@mycadet/service-contracts/src/remote-web-pairing.ts +1 -1
- package/node_modules/@mycadet/service-contracts/src/rpc.ts +14 -14
- package/node_modules/@mycadet/service-contracts/src/trust-rules.ts +5 -5
- package/package.json +3 -2
- package/src/__tests__/assistant-api-key-resolution.test.ts +6 -6
- package/src/__tests__/{assistant-client-platform-auth.test.ts → assistant-client-cloud-auth.test.ts} +10 -10
- package/src/__tests__/assistant-client-refresh.test.ts +2 -2
- package/src/__tests__/backup.test.ts +86 -91
- package/src/__tests__/client-token.test.ts +1 -1
- package/src/__tests__/client-tui-refresh.test.ts +1 -1
- package/src/__tests__/client-web-config.test.ts +2 -2
- package/src/__tests__/{platform-client.test.ts → cloud-client.test.ts} +59 -59
- package/src/__tests__/{platform-releases.test.ts → cloud-releases.test.ts} +28 -18
- package/src/__tests__/{cloudflare-tunnel.test.ts → cloudflare.test.ts} +1 -1
- package/src/__tests__/connect-import.test.ts +55 -39
- package/src/__tests__/debug.test.ts +38 -38
- package/src/__tests__/ensure-binary.test.ts +182 -0
- package/src/__tests__/guardian-token.test.ts +149 -56
- package/src/__tests__/hatch-provider-secrets.test.ts +2 -2
- package/src/__tests__/helpers/guardian-token.ts +22 -0
- package/src/__tests__/helpers/http.ts +10 -0
- package/src/__tests__/nginx-ingress.test.ts +21 -20
- package/src/__tests__/ngrok-spawn.test.ts +49 -0
- package/src/__tests__/orphan-detection.test.ts +1 -1
- package/src/__tests__/pair.test.ts +1 -8
- package/src/__tests__/{ps-platform-status.test.ts → ps-cloud-status.test.ts} +79 -26
- package/src/__tests__/ps-table.test.ts +79 -0
- package/src/__tests__/{recover.test.ts → restore.test.ts} +29 -28
- package/src/__tests__/retire.test.ts +58 -199
- package/src/__tests__/root-process-lockfile.test.ts +99 -0
- package/src/__tests__/sleep.test.ts +19 -19
- package/src/__tests__/statefulset.test.ts +8 -8
- package/src/__tests__/{tailscale-tunnel.test.ts → tailscale.test.ts} +2 -2
- package/src/__tests__/teleport-backup.test.ts +3 -3
- package/src/__tests__/teleport.test.ts +181 -197
- package/src/__tests__/tunnel.test.ts +257 -222
- package/src/__tests__/uninstall.test.ts +13 -4
- package/src/__tests__/upgrade-local.test.ts +3 -3
- package/src/__tests__/upgrade-replay-env.test.ts +12 -12
- package/src/__tests__/wake.test.ts +260 -43
- package/src/__tests__/workos-pkce.test.ts +2 -2
- package/src/commands/backup.ts +24 -24
- package/src/commands/client.ts +76 -76
- package/src/commands/completions.test.ts +104 -0
- package/src/commands/completions.ts +87 -0
- package/src/commands/debug.ts +20 -20
- package/src/commands/exec.ts +12 -12
- package/src/commands/flags.ts +2 -2
- package/src/commands/hatch.ts +23 -23
- package/src/commands/login.ts +22 -22
- package/src/commands/logs.ts +8 -8
- package/src/commands/ps.ts +244 -86
- package/src/commands/restart.ts +30 -0
- package/src/commands/restore.ts +140 -22
- package/src/commands/retire.ts +48 -150
- package/src/commands/rollback.ts +20 -26
- package/src/commands/setup.ts +2 -2
- package/src/commands/sleep.ts +2 -2
- package/src/commands/teleport.ts +109 -109
- package/src/commands/terminal.ts +158 -18
- package/src/commands/tunnel.ts +138 -157
- package/src/commands/uninstall.ts +57 -9
- package/src/commands/unpair.ts +3 -3
- package/src/commands/upgrade.ts +30 -54
- package/src/commands/use.ts +1 -1
- package/src/commands/wake.ts +166 -50
- package/src/index.ts +18 -9
- package/src/lib/__tests__/{platform-client-signed-url.test.ts → cloud-client-signed-url.test.ts} +16 -16
- package/src/lib/__tests__/docker.test.ts +168 -20
- package/src/lib/__tests__/job-polling.test.ts +2 -2
- package/src/lib/__tests__/local-runtime-client.test.ts +4 -4
- package/src/lib/__tests__/runtime-url.test.ts +1 -1
- package/src/lib/assistant-api-key-resolution.ts +5 -5
- package/src/lib/assistant-client.ts +8 -8
- package/src/lib/assistant-config.ts +58 -12
- package/src/lib/{platform-client.ts → cloud-client.ts} +107 -98
- package/src/lib/cloud-login.ts +24 -24
- package/src/lib/{platform-releases.ts → cloud-releases.ts} +11 -9
- package/src/lib/cloud-values.ts +3 -0
- package/src/lib/config-utils.ts +1 -1
- package/src/lib/detached-process.ts +1 -1
- package/src/lib/docker.ts +260 -53
- package/src/lib/ensure-binary.ts +171 -0
- package/src/lib/environments/__tests__/paths.test.ts +2 -2
- package/src/lib/environments/__tests__/resolve.test.ts +26 -26
- package/src/lib/environments/resolve.ts +8 -8
- package/src/lib/flag-args.test.ts +1 -1
- package/src/lib/flag-args.ts +1 -1
- package/src/lib/guardian-token.ts +37 -5
- package/src/lib/hatch-local.ts +19 -23
- package/src/lib/health-check.ts +6 -6
- package/src/lib/ingress-config.ts +8 -35
- package/src/lib/job-polling.ts +2 -2
- package/src/lib/live-voice/connection.ts +12 -12
- package/src/lib/live-voice/tunnel.test.ts +11 -11
- package/src/lib/live-voice/tunnel.ts +15 -15
- package/src/lib/local-runtime-client.ts +20 -20
- package/src/lib/local.ts +10 -31
- package/src/lib/nginx-ingress.ts +42 -15
- package/src/lib/pair.ts +1 -1
- package/src/lib/process.ts +1 -1
- package/src/lib/provider-secrets.ts +3 -3
- package/src/lib/retire-apple-container.ts +1 -1
- package/src/lib/runtime-url.ts +8 -8
- package/src/lib/statefulset.ts +2 -2
- package/src/lib/sync-cloud-assistants.ts +19 -19
- package/src/lib/teleport-backup.ts +4 -4
- package/src/lib/terminal-client.ts +17 -17
- package/src/lib/terminal-session.ts +24 -24
- package/src/lib/{tunnel-edge.ts → tunnel.ts} +199 -11
- package/src/lib/tunnels/cadet.ts +29 -0
- package/src/lib/{cloudflare-tunnel.ts → tunnels/cloudflare.ts} +36 -15
- package/src/lib/tunnels/gateway-notify.ts +61 -0
- package/src/lib/{ngrok.ts → tunnels/ngrok.ts} +350 -89
- package/src/lib/{tailscale-tunnel.ts → tunnels/tailscale.ts} +53 -9
- package/src/lib/upgrade-lifecycle.ts +8 -21
- package/src/lib/upgrade-preflight.ts +2 -2
- package/src/lib/workos-pkce.ts +5 -5
- package/node_modules/@mycadet/assistant-api/events/platform-disconnected.ts +0 -21
- package/node_modules/@mycadet/assistant-api/events/show-platform-login.ts +0 -20
- package/src/commands/recover.ts +0 -131
- package/src/commands/roadmap.ts +0 -459
- package/src/commands/ssh.ts +0 -144
- package/src/commands/workflows.ts +0 -305
- package/src/lib/managed-cloud.ts +0 -3
package/src/commands/ps.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { isCloudHome } from "../lib/cloud-values.js";
|
|
2
2
|
import { join } from "path";
|
|
3
3
|
|
|
4
4
|
import {
|
|
@@ -11,6 +11,7 @@ import {
|
|
|
11
11
|
getDaemonPidPath,
|
|
12
12
|
loadAllAssistants,
|
|
13
13
|
lookupAssistantByIdentifier,
|
|
14
|
+
readRootProcesses,
|
|
14
15
|
type AssistantEntry,
|
|
15
16
|
} from "../lib/assistant-config";
|
|
16
17
|
import { parseAssistantTargetArg } from "../lib/assistant-target-args.js";
|
|
@@ -23,7 +24,7 @@ import {
|
|
|
23
24
|
fetchManagedPs,
|
|
24
25
|
type ManagedProcessEntry,
|
|
25
26
|
} from "../lib/health-check";
|
|
26
|
-
import {
|
|
27
|
+
import { readCloudToken } from "../lib/cloud-client";
|
|
27
28
|
import { dockerResourceNames } from "../lib/docker";
|
|
28
29
|
import { existsSync } from "fs";
|
|
29
30
|
import {
|
|
@@ -44,45 +45,112 @@ import {
|
|
|
44
45
|
|
|
45
46
|
// ── Table formatting helpers ────────────────────────────────────
|
|
46
47
|
|
|
48
|
+
/** What each row's `type` column says: the KIND of process the row describes. */
|
|
49
|
+
const ASSISTANT_TYPE = "🧑🚀 Assistant";
|
|
50
|
+
const TUNNEL_TYPE = "🚇 Tunnel";
|
|
51
|
+
const APP_TYPE = "🌐 App";
|
|
52
|
+
|
|
47
53
|
interface TableRow {
|
|
48
54
|
name: string;
|
|
55
|
+
type: string;
|
|
49
56
|
status: string;
|
|
50
57
|
info: string;
|
|
51
58
|
}
|
|
52
59
|
|
|
53
60
|
interface ColWidths {
|
|
54
61
|
name: number;
|
|
62
|
+
type: number;
|
|
55
63
|
status: number;
|
|
56
64
|
info: number;
|
|
57
65
|
}
|
|
58
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
|
+
|
|
59
113
|
function pad(s: string, w: number): string {
|
|
60
|
-
return s + " ".repeat(Math.max(0, w - s
|
|
114
|
+
return s + " ".repeat(Math.max(0, w - displayWidth(s)));
|
|
61
115
|
}
|
|
62
116
|
|
|
63
117
|
function computeColWidths(
|
|
64
118
|
rows: TableRow[],
|
|
65
|
-
headers: TableRow = {
|
|
119
|
+
headers: TableRow = {
|
|
120
|
+
name: "NAME",
|
|
121
|
+
type: "TYPE",
|
|
122
|
+
status: "STATUS",
|
|
123
|
+
info: "INFO",
|
|
124
|
+
},
|
|
66
125
|
): ColWidths {
|
|
67
126
|
const all = [headers, ...rows];
|
|
68
127
|
return {
|
|
69
|
-
name: Math.max(...all.map((r) => r.name
|
|
70
|
-
|
|
71
|
-
|
|
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))),
|
|
72
135
|
};
|
|
73
136
|
}
|
|
74
137
|
|
|
75
|
-
function formatRow(r: TableRow, colWidths: ColWidths): string {
|
|
76
|
-
return ` ${pad(r.name, colWidths.name)} ${pad(r.status, colWidths.status)} ${r.info}`;
|
|
138
|
+
export function formatRow(r: TableRow, colWidths: ColWidths): string {
|
|
139
|
+
return ` ${pad(r.name, colWidths.name)} ${pad(r.type, colWidths.type)} ${pad(r.status, colWidths.status)} ${r.info}`;
|
|
77
140
|
}
|
|
78
141
|
|
|
79
142
|
function printTable(
|
|
80
143
|
rows: TableRow[],
|
|
81
|
-
headers: TableRow = {
|
|
144
|
+
headers: TableRow = {
|
|
145
|
+
name: "PROCESS",
|
|
146
|
+
type: "TYPE",
|
|
147
|
+
status: "STATUS",
|
|
148
|
+
info: "INFO",
|
|
149
|
+
},
|
|
82
150
|
): void {
|
|
83
151
|
const colWidths = computeColWidths(rows, headers);
|
|
84
152
|
console.log(formatRow(headers, colWidths));
|
|
85
|
-
const sep = ` ${"-".repeat(colWidths.name)} ${"-".repeat(colWidths.status)} ${"-".repeat(colWidths.info)}`;
|
|
153
|
+
const sep = ` ${"-".repeat(colWidths.name)} ${"-".repeat(colWidths.type)} ${"-".repeat(colWidths.status)} ${"-".repeat(colWidths.info)}`;
|
|
86
154
|
console.log(sep);
|
|
87
155
|
for (const row of rows) {
|
|
88
156
|
console.log(formatRow(row, colWidths));
|
|
@@ -108,6 +176,7 @@ function flattenProcessTree(
|
|
|
108
176
|
rows.push({
|
|
109
177
|
name:
|
|
110
178
|
depth === 0 ? entry.name : `${" ".repeat(depth - 1)}├─ ${entry.name}`,
|
|
179
|
+
type: ASSISTANT_TYPE,
|
|
111
180
|
status: withStatusEmoji(STATUS_LABELS[entry.status]),
|
|
112
181
|
info: entry.info ?? "",
|
|
113
182
|
});
|
|
@@ -118,6 +187,7 @@ function flattenProcessTree(
|
|
|
118
187
|
const prefix = `${" ".repeat(depth)}${isLast ? "└─" : "├─"} ${child.name}`;
|
|
119
188
|
rows.push({
|
|
120
189
|
name: prefix,
|
|
190
|
+
type: ASSISTANT_TYPE,
|
|
121
191
|
status: withStatusEmoji(STATUS_LABELS[child.status]),
|
|
122
192
|
info: child.info ?? "",
|
|
123
193
|
});
|
|
@@ -284,9 +354,7 @@ async function getLocalProcesses(entry: AssistantEntry): Promise<TableRow[]> {
|
|
|
284
354
|
// tree (assistant + every child it owns, built from the OS process table)
|
|
285
355
|
// with the gateway's own entry appended — no hard-coded subsystem list to
|
|
286
356
|
// drift out of sync with what the assistant actually spawns.
|
|
287
|
-
const tree = gatewayUrl
|
|
288
|
-
? await fetchGatewayPs(gatewayUrl, token)
|
|
289
|
-
: null;
|
|
357
|
+
const tree = gatewayUrl ? await fetchGatewayPs(gatewayUrl, token) : null;
|
|
290
358
|
|
|
291
359
|
const rows: TableRow[] =
|
|
292
360
|
tree && tree.length > 0
|
|
@@ -303,6 +371,7 @@ async function getLocalProcesses(entry: AssistantEntry): Promise<TableRow[]> {
|
|
|
303
371
|
});
|
|
304
372
|
rows.push({
|
|
305
373
|
name: "credential-executor",
|
|
374
|
+
type: ASSISTANT_TYPE,
|
|
306
375
|
status: withStatusEmoji(ces.running ? "running" : "not running"),
|
|
307
376
|
info: ces.running ? formatDetectionInfo(ces) : "not detected",
|
|
308
377
|
});
|
|
@@ -349,6 +418,7 @@ async function detectLocalProcessesFallback(
|
|
|
349
418
|
|
|
350
419
|
return results.map((proc, i) => ({
|
|
351
420
|
name: allSpecs[i].name,
|
|
421
|
+
type: ASSISTANT_TYPE,
|
|
352
422
|
status: withStatusEmoji(proc.running ? "running" : "not running"),
|
|
353
423
|
info: proc.running ? formatDetectionInfo(proc) : "not detected",
|
|
354
424
|
}));
|
|
@@ -393,12 +463,14 @@ async function getDockerProcesses(entry: AssistantEntry): Promise<TableRow[]> {
|
|
|
393
463
|
if (!state) {
|
|
394
464
|
return {
|
|
395
465
|
name,
|
|
466
|
+
type: ASSISTANT_TYPE,
|
|
396
467
|
status: withStatusEmoji("not found"),
|
|
397
468
|
info: `container ${containerName}`,
|
|
398
469
|
};
|
|
399
470
|
}
|
|
400
471
|
return {
|
|
401
472
|
name,
|
|
473
|
+
type: ASSISTANT_TYPE,
|
|
402
474
|
status: withStatusEmoji(state === "running" ? "running" : state),
|
|
403
475
|
info: `container ${containerName}`,
|
|
404
476
|
};
|
|
@@ -412,6 +484,7 @@ async function getDockerProcesses(entry: AssistantEntry): Promise<TableRow[]> {
|
|
|
412
484
|
const alive = isLocalProcessAlive(watcherPid);
|
|
413
485
|
results.push({
|
|
414
486
|
name: "file-watcher",
|
|
487
|
+
type: ASSISTANT_TYPE,
|
|
415
488
|
status: withStatusEmoji(alive ? "running" : "not running"),
|
|
416
489
|
info: alive ? `PID ${watcherPid}` : "not detected",
|
|
417
490
|
});
|
|
@@ -430,44 +503,39 @@ function locationFor(entry: AssistantEntry): string {
|
|
|
430
503
|
return entry.runtimeUrl ?? "unknown — no runtime URL recorded";
|
|
431
504
|
}
|
|
432
505
|
|
|
433
|
-
async function
|
|
506
|
+
async function getAssistantProcessRows(
|
|
507
|
+
entry: AssistantEntry,
|
|
508
|
+
): Promise<TableRow[]> {
|
|
434
509
|
const cloud = entry.cloud;
|
|
435
510
|
|
|
436
|
-
console.log(`Processes for ${formatAssistantReference(entry)}
|
|
511
|
+
console.log(`Processes for ${formatAssistantReference(entry)} — ${cloud}:`);
|
|
437
512
|
console.log(`Location: ${locationFor(entry)}\n`);
|
|
438
513
|
|
|
439
514
|
if (cloud === "local") {
|
|
440
|
-
|
|
441
|
-
printTable(rows);
|
|
442
|
-
return;
|
|
515
|
+
return getLocalProcesses(entry);
|
|
443
516
|
}
|
|
444
517
|
|
|
445
518
|
if (cloud === "docker") {
|
|
446
|
-
|
|
447
|
-
printTable(rows);
|
|
448
|
-
return;
|
|
519
|
+
return getDockerProcesses(entry);
|
|
449
520
|
}
|
|
450
521
|
|
|
451
|
-
if (
|
|
522
|
+
if (isCloudHome(cloud)) {
|
|
452
523
|
console.log(` Cadet Cloud ID: ${entry.assistantId}\n`);
|
|
453
524
|
|
|
454
525
|
const psData = await fetchManagedPs(entry.runtimeUrl, entry.assistantId);
|
|
455
526
|
|
|
456
527
|
if (!psData) {
|
|
457
|
-
|
|
528
|
+
return [
|
|
458
529
|
{
|
|
459
530
|
name: "assistant",
|
|
531
|
+
type: ASSISTANT_TYPE,
|
|
460
532
|
status: withStatusEmoji("unreachable"),
|
|
461
533
|
info: "could not reach Cadet Cloud API — run `cadet login`",
|
|
462
534
|
},
|
|
463
535
|
];
|
|
464
|
-
printTable(rows);
|
|
465
|
-
return;
|
|
466
536
|
}
|
|
467
537
|
|
|
468
|
-
|
|
469
|
-
printTable(rows);
|
|
470
|
-
return;
|
|
538
|
+
return flattenProcessTree(psData.processes);
|
|
471
539
|
}
|
|
472
540
|
|
|
473
541
|
if (cloud === "apple-container") {
|
|
@@ -476,6 +544,7 @@ async function showAssistantProcesses(entry: AssistantEntry): Promise<void> {
|
|
|
476
544
|
const rows: TableRow[] = [
|
|
477
545
|
{
|
|
478
546
|
name: "container",
|
|
547
|
+
type: ASSISTANT_TYPE,
|
|
479
548
|
status: withStatusEmoji(socketAlive ? "running" : "not running"),
|
|
480
549
|
info: socketAlive
|
|
481
550
|
? `mgmt ${mgmtSocket}`
|
|
@@ -487,12 +556,12 @@ async function showAssistantProcesses(entry: AssistantEntry): Promise<void> {
|
|
|
487
556
|
const health = await checkHealth(entry.runtimeUrl, token);
|
|
488
557
|
rows.push({
|
|
489
558
|
name: "gateway",
|
|
559
|
+
type: ASSISTANT_TYPE,
|
|
490
560
|
status: withStatusEmoji(health.status),
|
|
491
561
|
info: entry.runtimeUrl + (health.detail ? ` | ${health.detail}` : ""),
|
|
492
562
|
});
|
|
493
563
|
}
|
|
494
|
-
|
|
495
|
-
return;
|
|
564
|
+
return rows;
|
|
496
565
|
}
|
|
497
566
|
|
|
498
567
|
if (cloud === "paired") {
|
|
@@ -500,15 +569,14 @@ async function showAssistantProcesses(entry: AssistantEntry): Promise<void> {
|
|
|
500
569
|
// list — probe the remote gateway's health over the bearer token instead.
|
|
501
570
|
const token = loadGuardianToken(entry.assistantId)?.accessToken;
|
|
502
571
|
const health = await checkHealth(entry.runtimeUrl, token);
|
|
503
|
-
|
|
572
|
+
return [
|
|
504
573
|
{
|
|
505
574
|
name: "gateway",
|
|
575
|
+
type: ASSISTANT_TYPE,
|
|
506
576
|
status: withStatusEmoji(health.status),
|
|
507
577
|
info: entry.runtimeUrl + (health.detail ? ` | ${health.detail}` : ""),
|
|
508
578
|
},
|
|
509
579
|
];
|
|
510
|
-
printTable(rows);
|
|
511
|
-
return;
|
|
512
580
|
}
|
|
513
581
|
|
|
514
582
|
let output: string;
|
|
@@ -525,7 +593,7 @@ async function showAssistantProcesses(entry: AssistantEntry): Promise<void> {
|
|
|
525
593
|
const msg = error instanceof Error ? error.message : String(error);
|
|
526
594
|
if (msg.includes("timed out")) {
|
|
527
595
|
console.warn(`Warning: remote process listing timed out — ${msg}`);
|
|
528
|
-
return;
|
|
596
|
+
return [];
|
|
529
597
|
}
|
|
530
598
|
console.error(`Failed to list processes: ${msg}`);
|
|
531
599
|
process.exit(1);
|
|
@@ -535,16 +603,93 @@ async function showAssistantProcesses(entry: AssistantEntry): Promise<void> {
|
|
|
535
603
|
|
|
536
604
|
if (procs.length === 0) {
|
|
537
605
|
console.log("No cadet processes found on the remote instance.");
|
|
538
|
-
return;
|
|
606
|
+
return [];
|
|
539
607
|
}
|
|
540
608
|
|
|
541
|
-
|
|
609
|
+
return procs.map((p) => ({
|
|
542
610
|
name: classifyProcess(p.command),
|
|
611
|
+
type: ASSISTANT_TYPE,
|
|
543
612
|
status: withStatusEmoji("running"),
|
|
544
613
|
info: `PID ${p.pid} | ${p.command.slice(0, 80)}`,
|
|
545
614
|
}));
|
|
615
|
+
}
|
|
616
|
+
|
|
617
|
+
// ── Root-managed process rows (tunnel agent, app edge) ──────────
|
|
546
618
|
|
|
547
|
-
|
|
619
|
+
/** A CLI-managed process row, plus the assistant it fronts (when recorded). */
|
|
620
|
+
interface RootManagedRow {
|
|
621
|
+
row: TableRow;
|
|
622
|
+
assistantId?: string;
|
|
623
|
+
}
|
|
624
|
+
|
|
625
|
+
/**
|
|
626
|
+
* Rows for the CLI-managed processes recorded at the lockfile root: the
|
|
627
|
+
* `tunnel` agent and the `app` nginx edge. Pids are liveness-checked so a
|
|
628
|
+
* stale entry reads as not running rather than as a lie. Each row carries the
|
|
629
|
+
* assistant it fronts so the listing can nest it under that assistant.
|
|
630
|
+
*/
|
|
631
|
+
async function getRootManagedRows(): Promise<RootManagedRow[]> {
|
|
632
|
+
const { tunnel, app } = readRootProcesses();
|
|
633
|
+
const rows: RootManagedRow[] = [];
|
|
634
|
+
|
|
635
|
+
if (tunnel) {
|
|
636
|
+
const alive = isLocalProcessAlive(tunnel.pid);
|
|
637
|
+
rows.push({
|
|
638
|
+
assistantId: tunnel.assistantId,
|
|
639
|
+
row: {
|
|
640
|
+
name: tunnel.provider ?? "unknown provider",
|
|
641
|
+
type: TUNNEL_TYPE,
|
|
642
|
+
status: withStatusEmoji(alive ? "running" : "not running"),
|
|
643
|
+
info: alive ? `PID ${tunnel.pid}` : `PID ${tunnel.pid} (exited)`,
|
|
644
|
+
},
|
|
645
|
+
});
|
|
646
|
+
}
|
|
647
|
+
if (app) {
|
|
648
|
+
const alive = isLocalProcessAlive(app.pid);
|
|
649
|
+
rows.push({
|
|
650
|
+
assistantId: app.assistantId,
|
|
651
|
+
row: {
|
|
652
|
+
name: "nginx edge",
|
|
653
|
+
type: APP_TYPE,
|
|
654
|
+
status: withStatusEmoji(alive ? "running" : "not running"),
|
|
655
|
+
info: alive ? `PID ${app.pid}` : `PID ${app.pid} (exited)`,
|
|
656
|
+
},
|
|
657
|
+
});
|
|
658
|
+
}
|
|
659
|
+
return rows;
|
|
660
|
+
}
|
|
661
|
+
|
|
662
|
+
/**
|
|
663
|
+
* Fold the CLI-managed process rows into ONE table with the assistant rows:
|
|
664
|
+
* a process fronts an assistant when it recorded that assistant's id, and
|
|
665
|
+
* those rows nest under it; anything unattributed (or fronting an assistant
|
|
666
|
+
* this environment no longer lists) renders at the bottom, machine-level.
|
|
667
|
+
*/
|
|
668
|
+
async function assistantRowsWithRootProcesses(
|
|
669
|
+
assistants: AssistantEntry[],
|
|
670
|
+
healths: AssistantHealth[],
|
|
671
|
+
activeAssistantId: string | null,
|
|
672
|
+
): Promise<TableRow[]> {
|
|
673
|
+
const nestedByAssistant = new Map<string, TableRow[]>();
|
|
674
|
+
const unattributed: TableRow[] = [];
|
|
675
|
+
const knownIds = new Set(assistants.map((entry) => entry.assistantId));
|
|
676
|
+
for (const managed of await getRootManagedRows()) {
|
|
677
|
+
if (managed.assistantId && knownIds.has(managed.assistantId)) {
|
|
678
|
+
const nested = nestedByAssistant.get(managed.assistantId) ?? [];
|
|
679
|
+
nested.push({ ...managed.row, name: ` └ ${managed.row.name}` });
|
|
680
|
+
nestedByAssistant.set(managed.assistantId, nested);
|
|
681
|
+
} else {
|
|
682
|
+
unattributed.push(managed.row);
|
|
683
|
+
}
|
|
684
|
+
}
|
|
685
|
+
|
|
686
|
+
const rows: TableRow[] = [];
|
|
687
|
+
assistants.forEach((entry, i) => {
|
|
688
|
+
rows.push(formatAssistantListRow(entry, activeAssistantId, healths[i]!));
|
|
689
|
+
rows.push(...(nestedByAssistant.get(entry.assistantId) ?? []));
|
|
690
|
+
});
|
|
691
|
+
rows.push(...unattributed);
|
|
692
|
+
return rows;
|
|
548
693
|
}
|
|
549
694
|
|
|
550
695
|
// ── List all assistants (no arg) ────────────────────────────────
|
|
@@ -590,7 +735,7 @@ async function getAssistantListHealth(
|
|
|
590
735
|
: { status: "unknown", detail: "no runtime URL" };
|
|
591
736
|
}
|
|
592
737
|
|
|
593
|
-
if (
|
|
738
|
+
if (isCloudHome(entry.cloud)) {
|
|
594
739
|
return checkManagedHealth(entry.runtimeUrl, entry.assistantId);
|
|
595
740
|
}
|
|
596
741
|
|
|
@@ -611,6 +756,7 @@ function formatAssistantListRow(
|
|
|
611
756
|
const prefix = entry.assistantId === activeAssistantId ? "* " : " ";
|
|
612
757
|
return {
|
|
613
758
|
name: prefix + getAssistantDisplayName(entry),
|
|
759
|
+
type: ASSISTANT_TYPE,
|
|
614
760
|
status: withStatusEmoji(health.status),
|
|
615
761
|
info: infoParts.join(" | "),
|
|
616
762
|
};
|
|
@@ -630,13 +776,13 @@ export async function listAllAssistants(verbose: boolean): Promise<void> {
|
|
|
630
776
|
|
|
631
777
|
// Sync cloud assistants (when logged in) before listing. Login status has
|
|
632
778
|
// its own command — `cadet whoami` — so ps stays silent about it.
|
|
633
|
-
const
|
|
634
|
-
if (!
|
|
779
|
+
const cloudToken = readCloudToken();
|
|
780
|
+
if (!cloudToken) {
|
|
635
781
|
log?.("No platform token found — skipping cloud sync");
|
|
636
782
|
} else {
|
|
637
783
|
// A failed sync (offline, expired token) just means cloud-managed
|
|
638
784
|
// assistants may be stale — the local list still renders.
|
|
639
|
-
await syncCloudAssistants(
|
|
785
|
+
await syncCloudAssistants(cloudToken, { log });
|
|
640
786
|
}
|
|
641
787
|
console.log("");
|
|
642
788
|
|
|
@@ -654,6 +800,7 @@ export async function listAllAssistants(verbose: boolean): Promise<void> {
|
|
|
654
800
|
console.log("\nOrphaned processes detected:\n");
|
|
655
801
|
const rows: TableRow[] = orphans.map((o) => ({
|
|
656
802
|
name: o.name,
|
|
803
|
+
type: ASSISTANT_TYPE,
|
|
657
804
|
status: withStatusEmoji("running"),
|
|
658
805
|
info: `PID ${o.pid} (from ${o.source})`,
|
|
659
806
|
}));
|
|
@@ -666,60 +813,71 @@ export async function listAllAssistants(verbose: boolean): Promise<void> {
|
|
|
666
813
|
return;
|
|
667
814
|
}
|
|
668
815
|
|
|
669
|
-
const
|
|
670
|
-
assistants.map(
|
|
671
|
-
formatAssistantListRow(
|
|
672
|
-
entry,
|
|
673
|
-
activeAssistantId,
|
|
674
|
-
await getAssistantListHealth(entry),
|
|
675
|
-
),
|
|
676
|
-
),
|
|
816
|
+
const healths = await Promise.all(
|
|
817
|
+
assistants.map((entry) => getAssistantListHealth(entry)),
|
|
677
818
|
);
|
|
678
819
|
|
|
679
|
-
printTable(
|
|
680
|
-
|
|
820
|
+
printTable(
|
|
821
|
+
await assistantRowsWithRootProcesses(
|
|
822
|
+
assistants,
|
|
823
|
+
healths,
|
|
824
|
+
activeAssistantId,
|
|
825
|
+
),
|
|
826
|
+
{ name: "NAME", type: "TYPE", status: "STATUS", info: "INFO" },
|
|
827
|
+
);
|
|
681
828
|
}
|
|
682
829
|
|
|
683
830
|
// ── Entry point ─────────────────────────────────────────────────
|
|
684
831
|
|
|
685
832
|
export const ps = Object.assign(
|
|
686
833
|
async function ps(): Promise<void> {
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
834
|
+
const args = process.argv.slice(3);
|
|
835
|
+
if (args.includes("--help") || args.includes("-h")) {
|
|
836
|
+
console.log("Usage: cadet ps [<name-or-id>] [--verbose]");
|
|
837
|
+
console.log("");
|
|
838
|
+
console.log(
|
|
839
|
+
"List all assistants, or show processes for a specific assistant.",
|
|
840
|
+
);
|
|
841
|
+
console.log("");
|
|
842
|
+
console.log("Arguments:");
|
|
843
|
+
console.log(
|
|
844
|
+
" <name-or-id> Show processes for the assistant display name or ID",
|
|
845
|
+
);
|
|
846
|
+
console.log("");
|
|
847
|
+
console.log("Options:");
|
|
848
|
+
console.log(
|
|
849
|
+
" --verbose Show diagnostic logs (platform sync, auth issues)",
|
|
850
|
+
);
|
|
851
|
+
process.exit(0);
|
|
852
|
+
}
|
|
706
853
|
|
|
707
|
-
|
|
708
|
-
|
|
854
|
+
const verbose = args.includes("--verbose");
|
|
855
|
+
const assistantIdentifier = parseAssistantTargetArg(args);
|
|
709
856
|
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
857
|
+
if (!assistantIdentifier) {
|
|
858
|
+
await listAllAssistants(verbose);
|
|
859
|
+
return;
|
|
860
|
+
}
|
|
714
861
|
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
862
|
+
const result = lookupAssistantByIdentifier(assistantIdentifier);
|
|
863
|
+
if (result.status !== "found") {
|
|
864
|
+
console.error(formatAssistantLookupError(assistantIdentifier, result));
|
|
865
|
+
process.exit(1);
|
|
866
|
+
}
|
|
720
867
|
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
868
|
+
const rows = await getAssistantProcessRows(result.entry);
|
|
869
|
+
// The CLI-managed processes (root lockfile) that front THIS assistant ride
|
|
870
|
+
// the same table; ones fronting another assistant stay in the list view.
|
|
871
|
+
for (const managed of await getRootManagedRows()) {
|
|
872
|
+
if (
|
|
873
|
+
managed.assistantId &&
|
|
874
|
+
managed.assistantId !== result.entry.assistantId
|
|
875
|
+
) {
|
|
876
|
+
continue;
|
|
877
|
+
}
|
|
878
|
+
rows.push(managed.row);
|
|
879
|
+
}
|
|
880
|
+
printTable(rows);
|
|
881
|
+
},
|
|
882
|
+
{ description: "List assistants" },
|
|
724
883
|
);
|
|
725
|
-
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { sleep } from "./sleep.js";
|
|
2
|
+
import { wake } from "./wake.js";
|
|
3
|
+
|
|
4
|
+
export const restart = Object.assign(
|
|
5
|
+
async function restart(): Promise<void> {
|
|
6
|
+
const args = process.argv.slice(3);
|
|
7
|
+
if (args.includes("--help") || args.includes("-h")) {
|
|
8
|
+
console.log(
|
|
9
|
+
"Usage: cadet restart [<name> | --all] [--force] [--wait [<duration>]] [--repair-guardian]",
|
|
10
|
+
);
|
|
11
|
+
console.log("");
|
|
12
|
+
console.log("Sleep, then wake the assistant.");
|
|
13
|
+
console.log("");
|
|
14
|
+
console.log(
|
|
15
|
+
"Arguments and flags pass through to `cadet sleep` and `cadet wake`.",
|
|
16
|
+
);
|
|
17
|
+
console.log(
|
|
18
|
+
" --repair-guardian Re-provision the guardian token during the wake",
|
|
19
|
+
);
|
|
20
|
+
process.exit(0);
|
|
21
|
+
}
|
|
22
|
+
if (args.includes("--all") && args.includes("--repair-guardian")) {
|
|
23
|
+
console.error("Error: --all cannot be combined with --repair-guardian.");
|
|
24
|
+
process.exit(1);
|
|
25
|
+
}
|
|
26
|
+
await sleep();
|
|
27
|
+
await wake();
|
|
28
|
+
},
|
|
29
|
+
{ description: "Sleep, then wake the assistant" },
|
|
30
|
+
);
|