@mnemom/mnemom 0.17.34-next.1 → 0.17.34-next.3
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/dist/base-url-proxy.mjs +18 -4
- package/dist/commands/agent-config.js +5 -1
- package/dist/commands/agent-doctor.d.ts +9 -0
- package/dist/commands/agent-doctor.js +4 -0
- package/dist/commands/agent-run.d.ts +14 -6
- package/dist/commands/agent-run.js +44 -27
- package/dist/commands/agent-session.d.ts +1 -2
- package/dist/commands/agent-session.js +1 -2
- package/dist/commands/agent-setup.d.ts +6 -0
- package/dist/commands/agent-setup.js +12 -1
- package/dist/commands/agent-share-test-issuer.d.ts +67 -0
- package/dist/commands/agent-share-test-issuer.js +139 -0
- package/dist/commands/agent-share.d.ts +7 -1
- package/dist/commands/agent-share.js +14 -4
- package/dist/commands/agent.d.ts +18 -5
- package/dist/commands/agent.js +186 -59
- package/dist/commands/durable-doctor.d.ts +50 -0
- package/dist/commands/durable-doctor.js +186 -0
- package/dist/commands/durable-lock.d.ts +261 -0
- package/dist/commands/durable-lock.js +600 -0
- package/dist/commands/durable-sessions.d.ts +87 -0
- package/dist/commands/durable-sessions.js +303 -0
- package/dist/commands/durable-verbs.d.ts +116 -0
- package/dist/commands/durable-verbs.js +393 -0
- package/dist/commands/scan.d.ts +12 -1
- package/dist/commands/scan.js +22 -3
- package/dist/commands/wrap.js +1 -1
- package/dist/durable/adopt-live.js +5 -8
- package/dist/durable/adopt.d.ts +8 -0
- package/dist/durable/adopt.js +27 -6
- package/dist/durable/cwd-rule.d.ts +9 -1
- package/dist/durable/cwd-rule.js +18 -0
- package/dist/durable/flock.d.ts +26 -0
- package/dist/durable/flock.js +80 -0
- package/dist/durable/launch-spec.d.ts +9 -1
- package/dist/durable/launch-spec.js +11 -4
- package/dist/durable/seat-proxy-entry.d.ts +11 -0
- package/dist/durable/seat-proxy-entry.js +25 -0
- package/dist/durable/seat-proxy.d.ts +107 -0
- package/dist/durable/seat-proxy.js +599 -0
- package/dist/durable/seat-socket.d.ts +46 -0
- package/dist/durable/seat-socket.js +179 -0
- package/dist/durable/seat-spec-validator.d.ts +28 -0
- package/dist/durable/seat-spec-validator.js +59 -0
- package/dist/durable/test-mode.mjs +105 -0
- package/dist/durable/turn-chain.d.ts +55 -0
- package/dist/durable/turn-chain.js +178 -0
- package/dist/host/auto-continue.d.ts +67 -0
- package/dist/host/auto-continue.js +118 -0
- package/dist/host/bootid.d.ts +13 -0
- package/dist/host/bootid.js +41 -0
- package/dist/host/client.d.ts +125 -0
- package/dist/host/client.js +171 -0
- package/dist/host/commands.d.ts +2 -0
- package/dist/host/commands.js +122 -0
- package/dist/host/control.d.ts +33 -0
- package/dist/host/control.js +144 -0
- package/dist/host/daemon.d.ts +221 -0
- package/dist/host/daemon.js +616 -0
- package/dist/host/gate.d.ts +46 -0
- package/dist/host/gate.js +82 -0
- package/dist/host/grant.d.ts +24 -0
- package/dist/host/grant.js +24 -0
- package/dist/host/instance.d.ts +35 -0
- package/dist/host/instance.js +62 -0
- package/dist/host/integrity.d.ts +35 -0
- package/dist/host/integrity.js +115 -0
- package/dist/host/launchd.d.ts +16 -0
- package/dist/host/launchd.js +45 -0
- package/dist/host/lock.d.ts +20 -0
- package/dist/host/lock.js +63 -0
- package/dist/host/owner.d.ts +58 -0
- package/dist/host/owner.js +123 -0
- package/dist/host/plist.d.ts +16 -0
- package/dist/host/plist.js +85 -0
- package/dist/host/procs.d.ts +27 -0
- package/dist/host/procs.js +105 -0
- package/dist/host/run.d.ts +65 -0
- package/dist/host/run.js +299 -0
- package/dist/host/runtime.d.ts +8 -0
- package/dist/host/runtime.js +22 -0
- package/dist/host/s1-names.d.ts +23 -0
- package/dist/host/s1-names.js +22 -0
- package/dist/host/seat-credential.d.ts +27 -0
- package/dist/host/seat-credential.js +41 -0
- package/dist/host/seat-launch-main.d.ts +1 -0
- package/dist/host/seat-launch-main.js +59 -0
- package/dist/host/seat-launch.d.ts +116 -0
- package/dist/host/seat-launch.js +302 -0
- package/dist/host/seat.d.ts +48 -0
- package/dist/host/seat.js +149 -0
- package/dist/host/state.d.ts +33 -0
- package/dist/host/state.js +117 -0
- package/dist/host/status.d.ts +101 -0
- package/dist/host/status.js +307 -0
- package/dist/host/tmux.d.ts +56 -0
- package/dist/host/tmux.js +182 -0
- package/dist/host/transcript.d.ts +30 -0
- package/dist/host/transcript.js +130 -0
- package/dist/host/verbs.d.ts +52 -0
- package/dist/host/verbs.js +282 -0
- package/dist/index.d.ts +8 -6
- package/dist/index.js +209 -43
- package/dist/lib/agent.d.ts +13 -29
- package/dist/lib/agent.js +17 -29
- package/dist/lib/claude-bin.d.ts +6 -0
- package/dist/lib/claude-bin.js +26 -0
- package/dist/lib/claude-plugin.d.ts +11 -2
- package/dist/lib/claude-plugin.js +10 -1
- package/dist/lib/commit-report.d.ts +5 -4
- package/dist/lib/commit-report.js +6 -9
- package/dist/lib/config.d.ts +8 -1
- package/dist/lib/config.js +28 -0
- package/dist/lib/durable/api.d.ts +136 -0
- package/dist/lib/durable/api.js +220 -0
- package/dist/lib/durable/codes.d.ts +8 -0
- package/dist/lib/durable/codes.js +2 -0
- package/dist/lib/durable/gate.d.ts +48 -0
- package/dist/lib/durable/gate.js +122 -0
- package/dist/lib/durable/handover.d.ts +101 -0
- package/dist/lib/durable/handover.js +175 -0
- package/dist/lib/durable/launch.d.ts +199 -0
- package/dist/lib/durable/launch.js +461 -0
- package/dist/lib/durable/launching.d.ts +15 -0
- package/dist/lib/durable/launching.js +70 -0
- package/dist/lib/durable/live.d.ts +190 -0
- package/dist/lib/durable/live.js +633 -0
- package/dist/lib/durable/refusal.d.ts +57 -0
- package/dist/lib/durable/refusal.js +78 -0
- package/dist/lib/durable/view.d.ts +83 -0
- package/dist/lib/durable/view.js +244 -0
- package/dist/lib/experimental.d.ts +0 -9
- package/dist/lib/experimental.js +18 -17
- package/dist/lib/launcher-config.d.ts +13 -0
- package/dist/lib/launcher-config.js +32 -0
- package/dist/lib/runner/exec-append.d.ts +15 -0
- package/dist/lib/runner/exec-append.js +2 -0
- package/dist/lib/runner/executor-client.d.ts +2 -1
- package/dist/lib/runner/executor-state.d.ts +10 -0
- package/dist/lib/runner/executor-state.js +24 -0
- package/dist/lib/runner/github-base.d.ts +24 -0
- package/dist/lib/runner/github-base.js +27 -0
- package/dist/lib/runner/job.d.ts +9 -4
- package/dist/lib/runner/job.js +43 -15
- package/dist/lib/runner/oidc.d.ts +3 -2
- package/dist/lib/runner/oidc.js +7 -4
- package/dist/lib/runner/options.d.ts +6 -0
- package/dist/lib/runner/options.js +19 -1
- package/dist/lib/runner/phases.d.ts +7 -4
- package/dist/lib/runner/phases.js +8 -4
- package/dist/lib/runner/proxy.d.ts +5 -1
- package/dist/lib/runner/proxy.js +7 -1
- package/dist/lib/scan/cost-per-pr.d.ts +93 -0
- package/dist/lib/scan/cost-per-pr.js +101 -0
- package/dist/lib/scan/record.d.ts +27 -1
- package/dist/lib/scan/record.js +114 -16
- package/dist/lib/scan/report-email.d.ts +26 -6
- package/dist/lib/scan/report-email.js +32 -3
- package/dist/lib/scan/scan.d.ts +3 -0
- package/dist/lib/scan/scan.js +13 -1
- package/dist/lib/subscription-login.d.ts +15 -0
- package/dist/lib/subscription-login.js +28 -1
- package/dist/vendor/durable-contract/index.js +240 -18
- package/dist/vendor/shared/durable-contract/admission.d.ts +240 -0
- package/dist/vendor/shared/durable-contract/admission.js +533 -0
- package/dist/vendor/shared/durable-contract/arm.d.ts +51 -0
- package/dist/vendor/shared/durable-contract/arm.js +133 -0
- package/dist/vendor/shared/durable-contract/canonical.d.ts +29 -0
- package/dist/vendor/shared/durable-contract/canonical.js +98 -0
- package/dist/vendor/shared/durable-contract/cell-id.d.ts +22 -0
- package/dist/vendor/shared/durable-contract/cell-id.js +38 -0
- package/dist/vendor/shared/durable-contract/cli-output.d.ts +342 -0
- package/dist/vendor/shared/durable-contract/cli-output.js +201 -0
- package/dist/vendor/shared/durable-contract/cli-surface.d.ts +119 -0
- package/dist/vendor/shared/durable-contract/cli-surface.js +270 -0
- package/dist/vendor/shared/durable-contract/codes.d.ts +537 -0
- package/dist/vendor/shared/durable-contract/codes.js +475 -0
- package/dist/vendor/shared/durable-contract/constants.d.ts +153 -0
- package/dist/vendor/shared/durable-contract/constants.js +179 -0
- package/dist/vendor/shared/durable-contract/doors.d.ts +119 -0
- package/dist/vendor/shared/durable-contract/doors.js +249 -0
- package/dist/vendor/shared/durable-contract/envelope.d.ts +103 -0
- package/dist/vendor/shared/durable-contract/envelope.js +317 -0
- package/dist/vendor/shared/durable-contract/events.d.ts +147 -0
- package/dist/vendor/shared/durable-contract/events.js +630 -0
- package/dist/vendor/shared/durable-contract/executor-state.d.ts +41 -0
- package/dist/vendor/shared/durable-contract/executor-state.js +32 -0
- package/dist/vendor/shared/durable-contract/fixlines.d.ts +318 -0
- package/dist/vendor/shared/durable-contract/fixlines.js +483 -0
- package/dist/vendor/shared/durable-contract/freeze-record.d.ts +787 -0
- package/dist/vendor/shared/durable-contract/freeze-record.js +361 -0
- package/dist/vendor/shared/durable-contract/index.d.ts +36 -0
- package/dist/vendor/shared/durable-contract/index.js +37 -0
- package/dist/vendor/shared/durable-contract/journal-approvals.d.ts +29 -0
- package/dist/vendor/shared/durable-contract/journal-approvals.js +60 -0
- package/dist/vendor/shared/durable-contract/keys.d.ts +24 -0
- package/dist/vendor/shared/durable-contract/keys.js +66 -0
- package/dist/vendor/shared/durable-contract/lock.d.ts +128 -0
- package/dist/vendor/shared/durable-contract/lock.js +151 -0
- package/dist/vendor/shared/durable-contract/names.d.ts +25 -0
- package/dist/vendor/shared/durable-contract/names.js +78 -0
- package/dist/vendor/shared/durable-contract/owner-verbs.d.ts +175 -0
- package/dist/vendor/shared/durable-contract/owner-verbs.js +403 -0
- package/dist/vendor/shared/durable-contract/paths.d.ts +23 -0
- package/dist/vendor/shared/durable-contract/paths.js +35 -0
- package/dist/vendor/shared/durable-contract/pure-fn.d.ts +48 -0
- package/dist/vendor/shared/durable-contract/pure-fn.js +89 -0
- package/dist/vendor/shared/durable-contract/routes.d.ts +205 -0
- package/dist/vendor/shared/durable-contract/routes.js +315 -0
- package/dist/vendor/shared/durable-contract/schema.d.ts +126 -0
- package/dist/vendor/shared/durable-contract/schema.js +441 -0
- package/dist/vendor/shared/durable-contract/seal.d.ts +54 -0
- package/dist/vendor/shared/durable-contract/seal.js +99 -0
- package/dist/vendor/shared/durable-contract/secret-scope.d.ts +28 -0
- package/dist/vendor/shared/durable-contract/secret-scope.js +76 -0
- package/dist/vendor/shared/durable-contract/session-id.d.ts +21 -0
- package/dist/vendor/shared/durable-contract/session-id.js +58 -0
- package/dist/vendor/shared/durable-contract/spec.d.ts +162 -0
- package/dist/vendor/shared/durable-contract/spec.js +286 -0
- package/dist/vendor/shared/durable-contract/states.d.ts +96 -0
- package/dist/vendor/shared/durable-contract/states.js +218 -0
- package/dist/vendor/shared/durable-contract/telemetry.d.ts +94 -0
- package/dist/vendor/shared/durable-contract/telemetry.js +180 -0
- package/dist/vendor/shared/durable-contract/test-mode.d.ts +62 -0
- package/dist/vendor/shared/durable-contract/test-mode.js +140 -0
- package/dist/vendor/shared/durable-contract/turn.d.ts +57 -0
- package/dist/vendor/shared/durable-contract/turn.js +81 -0
- package/dist/vendor/shared/durable-contract/vectors.d.ts +191 -0
- package/dist/vendor/shared/durable-contract/vectors.js +208 -0
- package/package.json +3 -2
- package/plugins/integrity-manifest.json +35 -0
- package/plugins/mnemom/hooks/hooks.json +15 -1
- package/plugins/mnemom/hooks/register.tsx +60 -2
- package/plugins/mnemom/hooks/seat-hello.mjs +116 -0
- package/dist/commands/agent-implicit-notice.d.ts +0 -31
- package/dist/commands/agent-implicit-notice.js +0 -73
|
@@ -0,0 +1,303 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `mnemom agent sessions` and `mnemom agent show <name>` with the `durable` gate on (BACKBONE C1;
|
|
3
|
+
* C01-R12, R24, R25, R27, R28; C11-R27): read from the server registry, never from the local
|
|
4
|
+
* ledger. With the gate off these are not reached and the ledger commands run exactly as today.
|
|
5
|
+
*
|
|
6
|
+
* sessions one row per session: name, user-facing state (of the EFFECTIVE state), agent,
|
|
7
|
+
* machine, spend (guard_state.spend_usd to cents for locked rows, `-` for tracked) and
|
|
8
|
+
* last activity; under a row, its fix line and the grant warning when they apply.
|
|
9
|
+
* show the S1 SHOW_KEYS sections in order (the --json keys are the same strings, same
|
|
10
|
+
* order); keys that do not apply to a tracked session print NA_TEXT (null in --json).
|
|
11
|
+
*
|
|
12
|
+
* A registry that is absent for this caller (route 404, not entitled 403) falls back to the ledger
|
|
13
|
+
* command (`fallback`); an unreachable one refuses with session_registry_unavailable.
|
|
14
|
+
*/
|
|
15
|
+
import { APPROVALS_TEXT_M1, JOURNAL_TAIL_N, NA_TEXT, OUTAGE_TEXT_M1, SEAT_TEXT_M1, SHOW_KEYS, SHOW_KEYS_LOCKED_ONLY, STORAGE_TEXT_M1, } from "../vendor/shared/durable-contract/fixlines.js";
|
|
16
|
+
import { RegistryAnswerError, RegistryUnavailable, } from "../lib/durable/api.js";
|
|
17
|
+
import { DurableRefusal, printDurableRefusal } from "../lib/durable/refusal.js";
|
|
18
|
+
import { effectiveOf, grantWarning, isEnded, isLocked, lastActivity, liveRow, machineText, reasonOf, rowFixLine, spendJson, spendText, stateLabel, userState, } from "../lib/durable/view.js";
|
|
19
|
+
const registryDown = (detail) => new DurableRefusal({
|
|
20
|
+
code: "session_registry_unavailable",
|
|
21
|
+
message: `mnemom agent: the session registry is unreachable (${detail})`,
|
|
22
|
+
fix: null,
|
|
23
|
+
});
|
|
24
|
+
/** Rows from the registry, or "absent" (route 404 / not entitled 403). Down -> a refusal is thrown. */
|
|
25
|
+
export async function readRows(api, filter) {
|
|
26
|
+
try {
|
|
27
|
+
return await api.listSessions(filter);
|
|
28
|
+
}
|
|
29
|
+
catch (e) {
|
|
30
|
+
if (e instanceof RegistryUnavailable)
|
|
31
|
+
throw registryDown(e.message);
|
|
32
|
+
if (e instanceof RegistryAnswerError) {
|
|
33
|
+
if (e.answer.status === 403 || e.answer.status === 404)
|
|
34
|
+
return "absent";
|
|
35
|
+
throw registryDown(`HTTP ${e.answer.status}`);
|
|
36
|
+
}
|
|
37
|
+
throw e;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
/** Newest first by last activity (rows without one last, input order kept among equals). */
|
|
41
|
+
export function newestFirst(rows) {
|
|
42
|
+
const t = (r) => {
|
|
43
|
+
const v = lastActivity(r);
|
|
44
|
+
const n = v ? Date.parse(v) : NaN;
|
|
45
|
+
return Number.isFinite(n) ? n : -Infinity;
|
|
46
|
+
};
|
|
47
|
+
return rows
|
|
48
|
+
.map((r, i) => ({ r, i }))
|
|
49
|
+
.sort((a, b) => t(b.r) - t(a.r) || a.i - b.i)
|
|
50
|
+
.map((x) => x.r);
|
|
51
|
+
}
|
|
52
|
+
const SESSIONS_DEFAULT_LIMIT = 20;
|
|
53
|
+
/** One row's --json document and its fix / grant lines (the human table prints the same). */
|
|
54
|
+
export function sessionJson(row, launcherKey, home) {
|
|
55
|
+
const nameHeld = !isEnded(row);
|
|
56
|
+
const machine = isLocked(row) ? machineText(row) : NA_TEXT;
|
|
57
|
+
return {
|
|
58
|
+
name: row.name ?? null,
|
|
59
|
+
conversation_id: row.conversation_id,
|
|
60
|
+
state: stateLabel(row),
|
|
61
|
+
internal_state: row.state,
|
|
62
|
+
effective_state: effectiveOf(row),
|
|
63
|
+
state_reason: reasonOf(row),
|
|
64
|
+
durable_mode: isLocked(row) ? "locked" : "tracked",
|
|
65
|
+
agent: row.agent_name ?? row.agent_id,
|
|
66
|
+
machine: machine === NA_TEXT ? null : machine,
|
|
67
|
+
spend: spendJson(row),
|
|
68
|
+
last_activity: lastActivity(row),
|
|
69
|
+
fix: rowFixLine(row, { launcherKey, nameHeld }, home),
|
|
70
|
+
grant_warning: isLocked(row) && !isEnded(row) ? grantWarning(row, home.nowMs) : null,
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
export async function durableSessionsCommand(opts, deps, fallback) {
|
|
74
|
+
let rows;
|
|
75
|
+
try {
|
|
76
|
+
rows = await readRows(deps.api, {});
|
|
77
|
+
}
|
|
78
|
+
catch (e) {
|
|
79
|
+
if (e instanceof DurableRefusal)
|
|
80
|
+
return printDurableRefusal(e, opts.json === true, deps);
|
|
81
|
+
throw e;
|
|
82
|
+
}
|
|
83
|
+
if (rows === "absent")
|
|
84
|
+
return fallback();
|
|
85
|
+
const shown = newestFirst(rows).slice(0, opts.all ? undefined : SESSIONS_DEFAULT_LIMIT);
|
|
86
|
+
const key = deps.launcherKey();
|
|
87
|
+
const home = await deps.home();
|
|
88
|
+
const docs = shown.map((r) => sessionJson(r, key, home));
|
|
89
|
+
if (opts.json) {
|
|
90
|
+
deps.out(JSON.stringify(docs, null, 2));
|
|
91
|
+
return 0;
|
|
92
|
+
}
|
|
93
|
+
if (docs.length === 0) {
|
|
94
|
+
deps.out("No sessions yet. Start one with `mnemom agent <name>`.");
|
|
95
|
+
return 0;
|
|
96
|
+
}
|
|
97
|
+
const header = ["NAME", "STATE", "AGENT", "MACHINE", "SPEND", "LAST ACTIVITY"];
|
|
98
|
+
const cells = shown.map((r, i) => {
|
|
99
|
+
const d = docs[i];
|
|
100
|
+
return [
|
|
101
|
+
d.name ?? d.conversation_id.slice(0, 8),
|
|
102
|
+
d.state,
|
|
103
|
+
d.agent,
|
|
104
|
+
d.machine ?? NA_TEXT,
|
|
105
|
+
spendText(r),
|
|
106
|
+
d.last_activity ?? NA_TEXT,
|
|
107
|
+
];
|
|
108
|
+
});
|
|
109
|
+
const widths = header.map((h, c) => Math.max(h.length, ...cells.map((row) => (row[c] ?? "").length)));
|
|
110
|
+
const line = (vals) => vals
|
|
111
|
+
.map((v, c) => (c === vals.length - 1 ? v : v.padEnd(widths[c] ?? 0)))
|
|
112
|
+
.join(" ")
|
|
113
|
+
.trimEnd();
|
|
114
|
+
deps.out(line(header));
|
|
115
|
+
cells.forEach((row, i) => {
|
|
116
|
+
deps.out(line(row));
|
|
117
|
+
const d = docs[i];
|
|
118
|
+
if (d.fix)
|
|
119
|
+
deps.out(` fix: ${d.fix}`);
|
|
120
|
+
if (d.grant_warning)
|
|
121
|
+
deps.out(` ${d.grant_warning}`);
|
|
122
|
+
});
|
|
123
|
+
return 0;
|
|
124
|
+
}
|
|
125
|
+
const rec = (v) => v !== null && typeof v === "object" && !Array.isArray(v) ? v : {};
|
|
126
|
+
const strOrNull = (v) => (typeof v === "string" && v !== "" ? v : null);
|
|
127
|
+
const numOrNull = (v) => typeof v === "number" && Number.isFinite(v) ? v : null;
|
|
128
|
+
/** The show document: SHOW_KEYS in order; locked-only keys are null on a tracked session. */
|
|
129
|
+
export function showDocument(i) {
|
|
130
|
+
const { row } = i;
|
|
131
|
+
const d = i.detail ?? {};
|
|
132
|
+
const locked = isLocked(row);
|
|
133
|
+
const s = sessionJson(row, i.launcherKey, i.home);
|
|
134
|
+
const charter = rec(d.charter);
|
|
135
|
+
const guard = rec(row.guard_state ?? d.guard_state);
|
|
136
|
+
const goalSrc = rec(d.goal);
|
|
137
|
+
const journalSrc = Array.isArray(d.journal) ? d.journal : Array.isArray(d.events) ? d.events : [];
|
|
138
|
+
const doc = {
|
|
139
|
+
state: {
|
|
140
|
+
state: userState(row),
|
|
141
|
+
label: s.state,
|
|
142
|
+
internal_state: s.internal_state,
|
|
143
|
+
effective_state: s.effective_state,
|
|
144
|
+
state_reason: s.state_reason,
|
|
145
|
+
fix: s.fix,
|
|
146
|
+
},
|
|
147
|
+
machine: {
|
|
148
|
+
machine: s.machine,
|
|
149
|
+
executor_id: row.home_executor_id ?? row.home_executor?.id ?? null,
|
|
150
|
+
hostname: row.home_executor?.hostname ?? null,
|
|
151
|
+
grant_warning: s.grant_warning,
|
|
152
|
+
},
|
|
153
|
+
sharing: {
|
|
154
|
+
other_live_sessions: i.others === null ? null : i.others.map((o) => o.name ?? o.conversation_id),
|
|
155
|
+
durable_only: i.durableOnly === "protocol_error" ? null : i.durableOnly,
|
|
156
|
+
durable_only_error: i.durableOnly === "protocol_error" ? "protocol_error" : null,
|
|
157
|
+
},
|
|
158
|
+
goal: Object.keys(goalSrc).length === 0
|
|
159
|
+
? null
|
|
160
|
+
: {
|
|
161
|
+
statement: strOrNull(goalSrc.statement),
|
|
162
|
+
requirements: Array.isArray(goalSrc.requirements) ? goalSrc.requirements : [],
|
|
163
|
+
},
|
|
164
|
+
rules: strOrNull(charter.profile ?? d.rules ?? d.profile),
|
|
165
|
+
pins: {
|
|
166
|
+
card_hash_prefix: strOrNull(charter.card_hash_prefix ?? d.card_hash_prefix),
|
|
167
|
+
policy_engine_major: numOrNull(charter.policy_engine_major ?? d.policy_engine_major),
|
|
168
|
+
},
|
|
169
|
+
limits: {
|
|
170
|
+
budget_usd: numOrNull(guard.budget_usd ?? row.budget_usd),
|
|
171
|
+
spend: s.spend,
|
|
172
|
+
max_turns: numOrNull(guard.max_turns ?? charter.max_turns),
|
|
173
|
+
max_duration_s: numOrNull(guard.max_duration_s ?? charter.max_duration_s),
|
|
174
|
+
},
|
|
175
|
+
approvals: APPROVALS_TEXT_M1,
|
|
176
|
+
outage: OUTAGE_TEXT_M1,
|
|
177
|
+
storage: STORAGE_TEXT_M1,
|
|
178
|
+
seat: SEAT_TEXT_M1,
|
|
179
|
+
journal: journalSrc.slice(-JOURNAL_TAIL_N).map((e) => {
|
|
180
|
+
const r = rec(e);
|
|
181
|
+
return { kind: strOrNull(r.kind ?? r.event), at: strOrNull(r.at ?? r.created_at) };
|
|
182
|
+
}),
|
|
183
|
+
};
|
|
184
|
+
if (!locked)
|
|
185
|
+
for (const k of SHOW_KEYS_LOCKED_ONLY)
|
|
186
|
+
doc[k] = null;
|
|
187
|
+
return doc;
|
|
188
|
+
}
|
|
189
|
+
/** The human lines of a show document, one section per SHOW_KEYS entry, in order. */
|
|
190
|
+
export function showLines(name, doc) {
|
|
191
|
+
const lines = [name];
|
|
192
|
+
const put = (k, v) => {
|
|
193
|
+
lines.push(` ${`${k}:`.padEnd(11)}${v}`);
|
|
194
|
+
};
|
|
195
|
+
for (const k of SHOW_KEYS) {
|
|
196
|
+
const v = doc[k];
|
|
197
|
+
if (v === null) {
|
|
198
|
+
put(k, NA_TEXT);
|
|
199
|
+
continue;
|
|
200
|
+
}
|
|
201
|
+
const r = rec(v);
|
|
202
|
+
switch (k) {
|
|
203
|
+
case "state": {
|
|
204
|
+
put(k, `${String(r.label)} (${String(r.internal_state)})`);
|
|
205
|
+
if (r.fix)
|
|
206
|
+
lines.push(` fix: ${String(r.fix)}`);
|
|
207
|
+
break;
|
|
208
|
+
}
|
|
209
|
+
case "machine":
|
|
210
|
+
put(k, String(r.machine ?? NA_TEXT));
|
|
211
|
+
if (r.grant_warning)
|
|
212
|
+
lines.push(` ${String(r.grant_warning)}`);
|
|
213
|
+
break;
|
|
214
|
+
case "sharing": {
|
|
215
|
+
// Only a list actually read is "no other live sessions"; an unread one is unknown.
|
|
216
|
+
const others = Array.isArray(r.other_live_sessions) ? r.other_live_sessions : null;
|
|
217
|
+
const only = r.durable_only === true
|
|
218
|
+
? "; agent is durable-only"
|
|
219
|
+
: r.durable_only_error === "protocol_error"
|
|
220
|
+
? "; durable-only unknown (protocol error: the agent record has no agent_durable_only)"
|
|
221
|
+
: "";
|
|
222
|
+
const live = others === null
|
|
223
|
+
? "other live sessions unknown (session registry unavailable)"
|
|
224
|
+
: others.length === 0
|
|
225
|
+
? "no other live sessions"
|
|
226
|
+
: others.join(", ");
|
|
227
|
+
put(k, `${live}${only}`);
|
|
228
|
+
break;
|
|
229
|
+
}
|
|
230
|
+
case "goal":
|
|
231
|
+
put(k, String(r.statement ?? NA_TEXT));
|
|
232
|
+
break;
|
|
233
|
+
case "pins":
|
|
234
|
+
put(k, `card ${String(r.card_hash_prefix ?? NA_TEXT)} · policy engine ${String(r.policy_engine_major ?? NA_TEXT)}`);
|
|
235
|
+
break;
|
|
236
|
+
case "limits":
|
|
237
|
+
put(k, `budget ${r.budget_usd ?? NA_TEXT} (spent ${String(r.spend ?? NA_TEXT)}) · max turns ${r.max_turns ?? NA_TEXT} · time ${r.max_duration_s ?? NA_TEXT}`);
|
|
238
|
+
break;
|
|
239
|
+
case "journal": {
|
|
240
|
+
const j = Array.isArray(v) ? v : [];
|
|
241
|
+
put(k, j.length === 0 ? NA_TEXT : `${j.length} recent`);
|
|
242
|
+
for (const e of j)
|
|
243
|
+
lines.push(` ${String(rec(e).at ?? "")} ${String(rec(e).kind ?? "")}`.trimEnd());
|
|
244
|
+
break;
|
|
245
|
+
}
|
|
246
|
+
default:
|
|
247
|
+
put(k, String(v));
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
return lines;
|
|
251
|
+
}
|
|
252
|
+
/** A 200 agent record's agent_durable_only: a boolean, or a protocol error when it is missing. */
|
|
253
|
+
export function durableOnlyOf(body) {
|
|
254
|
+
const v = rec(rec(body).agent ?? body).agent_durable_only;
|
|
255
|
+
return typeof v === "boolean" ? v : "protocol_error";
|
|
256
|
+
}
|
|
257
|
+
export async function durableShowCommand(ref, opts, deps, fallback) {
|
|
258
|
+
// No ref, or a ref that names no registry session: the ledger show (a cid prefix, or the newest).
|
|
259
|
+
if (ref === undefined)
|
|
260
|
+
return fallback();
|
|
261
|
+
let rows;
|
|
262
|
+
try {
|
|
263
|
+
rows = await readRows(deps.api, { name: ref });
|
|
264
|
+
}
|
|
265
|
+
catch (e) {
|
|
266
|
+
if (e instanceof DurableRefusal)
|
|
267
|
+
return printDurableRefusal(e, opts.json === true, deps);
|
|
268
|
+
throw e;
|
|
269
|
+
}
|
|
270
|
+
if (rows === "absent")
|
|
271
|
+
return fallback();
|
|
272
|
+
const row = liveRow(rows) ?? newestFirst(rows)[0] ?? null;
|
|
273
|
+
if (row === null)
|
|
274
|
+
return fallback();
|
|
275
|
+
const [detail, siblings, durableOnly] = await Promise.all([
|
|
276
|
+
deps.api
|
|
277
|
+
.getSession(row.conversation_id, row.agent_id, "goal")
|
|
278
|
+
.then((a) => (a.status === 200 ? rec(rec(a.body).session ?? a.body) : null))
|
|
279
|
+
.catch(() => null),
|
|
280
|
+
readRows(deps.api, { agentId: row.agent_id }).catch(() => "absent"),
|
|
281
|
+
deps.api
|
|
282
|
+
.getAgent(row.agent_id)
|
|
283
|
+
.then((a) => (a.status === 200 ? durableOnlyOf(a.body) : null))
|
|
284
|
+
.catch(() => null),
|
|
285
|
+
]);
|
|
286
|
+
const others = siblings === "absent"
|
|
287
|
+
? null
|
|
288
|
+
: siblings.filter((o) => o.conversation_id !== row.conversation_id && !isEnded(o));
|
|
289
|
+
const doc = showDocument({
|
|
290
|
+
row,
|
|
291
|
+
detail,
|
|
292
|
+
others,
|
|
293
|
+
durableOnly,
|
|
294
|
+
launcherKey: deps.launcherKey(),
|
|
295
|
+
home: await deps.home(),
|
|
296
|
+
});
|
|
297
|
+
if (opts.json)
|
|
298
|
+
deps.out(JSON.stringify(doc, null, 2));
|
|
299
|
+
else
|
|
300
|
+
for (const l of showLines(row.name ?? ref, doc))
|
|
301
|
+
deps.out(l);
|
|
302
|
+
return 0;
|
|
303
|
+
}
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The flat durable owner verbs (BACKBONE C1; S1 owner-verbs.ts, ROUTES.own_*; C11, C16):
|
|
3
|
+
*
|
|
4
|
+
* mnemom agent pause|resume|done|kill <name> [--json]
|
|
5
|
+
* mnemom agent amend <name> [--budget <n>] [--turns <n>] [--json]
|
|
6
|
+
* mnemom agent sessions unlock <name>
|
|
7
|
+
* mnemom agent containment pause|resume <agent>
|
|
8
|
+
*
|
|
9
|
+
* The API decides (S1 owner-verb table, first match wins); the CLI resolves the name through the
|
|
10
|
+
* registry, sends the verb, and renders the answer: a refusal with its S1 fix line and machine
|
|
11
|
+
* code, a 200 no-op with its state, a 202 device step (user_code + verification_uri_complete,
|
|
12
|
+
* polled at the server interval with the 202's device_code and client_id; never a token printed
|
|
13
|
+
* or kept), or the applied change. `done`/`kill` on a tracked session also stop the local tracked
|
|
14
|
+
* claude after the 200 (final F04; SIGTERM, SIGKILL after TRACKED_STOP_GRACE_S).
|
|
15
|
+
*
|
|
16
|
+
* Every dependency is injected (`DurableVerbDeps`), so each branch is unit-tested.
|
|
17
|
+
*/
|
|
18
|
+
import { type LauncherKey } from "../vendor/shared/durable-contract/fixlines.js";
|
|
19
|
+
import type { RouteName } from "../vendor/shared/durable-contract/routes.js";
|
|
20
|
+
import { type ApiAnswer, type RegistryRow } from "../lib/durable/api.js";
|
|
21
|
+
import { DurableRefusal } from "../lib/durable/refusal.js";
|
|
22
|
+
/** The slice of DurableApi the verbs use (a fake in tests). */
|
|
23
|
+
export interface VerbApi {
|
|
24
|
+
listSessions(filter: {
|
|
25
|
+
name?: string;
|
|
26
|
+
agentId?: string;
|
|
27
|
+
}): Promise<RegistryRow[]>;
|
|
28
|
+
ownerVerb(route: RouteName, cid: string, agentId: string, body?: unknown): Promise<ApiAnswer>;
|
|
29
|
+
containment(orgId: string, agentId: string, verb: "pause" | "resume"): Promise<ApiAnswer>;
|
|
30
|
+
getAgent(agentId: string): Promise<ApiAnswer>;
|
|
31
|
+
/** Agents by name across the caller's orgs (the org fleet; JWT). */
|
|
32
|
+
agentsByName(name: string): Promise<Array<{
|
|
33
|
+
id: string;
|
|
34
|
+
org_id: string;
|
|
35
|
+
}>>;
|
|
36
|
+
devicePoll(deviceCode: string, clientId: string): Promise<ApiAnswer>;
|
|
37
|
+
credentialType(): Promise<"jwt" | "api-key" | "none">;
|
|
38
|
+
}
|
|
39
|
+
export interface DurableVerbDeps {
|
|
40
|
+
api: VerbApi;
|
|
41
|
+
launcherKey: () => LauncherKey;
|
|
42
|
+
out: (line: string) => void;
|
|
43
|
+
err: (line: string) => void;
|
|
44
|
+
sleep: (ms: number) => Promise<void>;
|
|
45
|
+
now: () => number;
|
|
46
|
+
/** Stop the local tracked claude of a session (done/kill on tracked, final F04). Absent: nothing to stop. */
|
|
47
|
+
stopTrackedClaude?: (row: RegistryRow, graceS: number) => Promise<void>;
|
|
48
|
+
}
|
|
49
|
+
export type OwnerVerbWord = "pause" | "resume" | "done" | "kill";
|
|
50
|
+
/** The session a verb acts on: the non-terminal row holding the name, else the newest row. */
|
|
51
|
+
export declare function resolveTarget(api: VerbApi, name: string): Promise<RegistryRow>;
|
|
52
|
+
/**
|
|
53
|
+
* A refusal from an API answer: the API's message and code, its rendered fix (details.fix, as the
|
|
54
|
+
* API already applied the fix-line rule), else the CLI's catalogue fallback for that code.
|
|
55
|
+
*/
|
|
56
|
+
export declare function refusalFromAnswer(a: ApiAnswer, name: string, launcherKey: LauncherKey, row?: RegistryRow): DurableRefusal;
|
|
57
|
+
/** The catalogue fix the CLI prints when the API body carries none. */
|
|
58
|
+
export declare function fallbackFix(code: string, details: Record<string, unknown>, name: string, launcherKey: LauncherKey, row?: RegistryRow): string | null;
|
|
59
|
+
/** The device-step fields of a 202 body (C16-R01). */
|
|
60
|
+
export interface DeviceStep {
|
|
61
|
+
user_code: string;
|
|
62
|
+
verification_uri_complete: string;
|
|
63
|
+
device_code: string;
|
|
64
|
+
interval: number;
|
|
65
|
+
client_id: string;
|
|
66
|
+
approval_id?: string;
|
|
67
|
+
}
|
|
68
|
+
export declare function deviceStepOf(body: unknown): DeviceStep | null;
|
|
69
|
+
/** How long the CLI keeps polling a device step before giving up (the approval TTL). */
|
|
70
|
+
export declare const DEVICE_STEP_POLL_MAX_MS: number;
|
|
71
|
+
/**
|
|
72
|
+
* Print the device step and poll until it resolves. 0 when applied; throws a DurableRefusal when
|
|
73
|
+
* denied, expired or refused. Never prints the device_code or any token.
|
|
74
|
+
*/
|
|
75
|
+
export declare function runDeviceStep(step: DeviceStep, note: string | null, deps: DurableVerbDeps): Promise<number>;
|
|
76
|
+
/** Run one verb end to end and return its exit status (refusals rendered here). */
|
|
77
|
+
export declare function runVerb(verb: OwnerVerbWord | "amend" | "unlock", name: string, body: Record<string, unknown>, opts: {
|
|
78
|
+
json?: boolean;
|
|
79
|
+
}, deps: DurableVerbDeps): Promise<number>;
|
|
80
|
+
/**
|
|
81
|
+
* Confirm an applied done / kill: the answer's own `{changed: true, state}` when it names the ended
|
|
82
|
+
* state, else one re-read of the session by conversation id. Throws a refusal (nothing stopped
|
|
83
|
+
* locally) when neither shows the session ended.
|
|
84
|
+
*/
|
|
85
|
+
export declare function confirmEnded(verb: "done" | "kill", row: RegistryRow, a: ApiAnswer, api: VerbApi, name: string): Promise<void>;
|
|
86
|
+
export declare function handleVerbError(e: unknown, json: boolean, deps: DurableVerbDeps): number;
|
|
87
|
+
/** Parse a positive amount (amend --budget); `integer` for a count (amend --turns). */
|
|
88
|
+
export declare function parsePositive(flag: string, raw: string | undefined, integer?: boolean): number | undefined;
|
|
89
|
+
export declare function amendCommand(name: string, opts: {
|
|
90
|
+
budget?: string;
|
|
91
|
+
turns?: string;
|
|
92
|
+
json?: boolean;
|
|
93
|
+
}, deps: DurableVerbDeps): Promise<number>;
|
|
94
|
+
export declare function unlockCommand(name: string, deps: DurableVerbDeps): Promise<number>;
|
|
95
|
+
/**
|
|
96
|
+
* `mnemom agent containment pause|resume <agent>` (BACKBONE C1, amendment 35; C16-R30): a thin
|
|
97
|
+
* verb over POST /v1/orgs/{org}/agents/{id}/pause|resume. The org comes from the agent record,
|
|
98
|
+
* never the active org. It needs a session login: on an API-key-only credential, or the api's
|
|
99
|
+
* 403 org_scope_requires_session, it exits non-zero with the containment_login line and never
|
|
100
|
+
* sends the API key or prints the raw 403.
|
|
101
|
+
*/
|
|
102
|
+
export declare function containmentCommand(verb: "pause" | "resume", agentRef: string, deps: DurableVerbDeps): Promise<number>;
|
|
103
|
+
/** An agent id as the CLI recognises one (lib/api.ts resolveAgentId). */
|
|
104
|
+
export declare const AGENT_ID_RE: RegExp;
|
|
105
|
+
/**
|
|
106
|
+
* The containment target and its org, from the agent record (never the active org): an id is read
|
|
107
|
+
* with GET /v1/agents/{id}; a name is looked up in the caller's org fleets and must match exactly one.
|
|
108
|
+
*/
|
|
109
|
+
export declare function resolveContainmentAgent(agentRef: string, deps: DurableVerbDeps, launcherKey: LauncherKey): Promise<{
|
|
110
|
+
orgId: string;
|
|
111
|
+
agentId: string;
|
|
112
|
+
}>;
|
|
113
|
+
/** The thin verbs (pause/resume/done/kill) with no body. */
|
|
114
|
+
export declare function ownerVerbCommand(verb: OwnerVerbWord, name: string, opts: {
|
|
115
|
+
json?: boolean;
|
|
116
|
+
}, deps: DurableVerbDeps): Promise<number>;
|