@cello-protocol/cli 0.0.44 → 0.0.46

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.
@@ -0,0 +1,60 @@
1
+ /**
2
+ * DOD-CLI-PARITY-1 §3 — the bash-adapter contract.
3
+ *
4
+ * This is what makes `cello` a real programmatic interface rather than a human-only UI: any
5
+ * bash-capable agent can drive a CELLO node with `cello <cmd> | jq` + `$?`, with no MCP dependency.
6
+ *
7
+ * The contract, applied identically by every parity command:
8
+ * - stdout = the daemon's IPC response as JSON, one object per invocation (compact by default —
9
+ * scripts and agents are the first-class consumer; `--pretty` for humans).
10
+ * - exit 0 when the response is ok:true; non-zero otherwise.
11
+ * - a FAILED response goes to stderr, VERBATIM — every field the daemon sent (reason, guidance,
12
+ * and extras like the read-before-write cursor) survives untouched, and stdout stays EMPTY so a
13
+ * piping script can never mistake an error body for a result.
14
+ *
15
+ * The verbatim rule is the DOD-SENDRAW-1 / DOD-LOGOUT-WAIT-1 lesson at the CLI surface: report the
16
+ * outcome, never the intent. A command that reports success for a failed IPC call is a lie, and
17
+ * absence of ok:true is NOT evidence of success — an unrecognized shape fails loud rather than
18
+ * being optimistically passed off as a result.
19
+ */
20
+ function render(value, pretty) {
21
+ return pretty ? JSON.stringify(value, null, 2) : JSON.stringify(value);
22
+ }
23
+ /**
24
+ * Turn a daemon IPC response into the (stdout, stderr, exitCode) triple the contract demands.
25
+ * The response is passed through UNMODIFIED in both directions — this function decides the stream
26
+ * and the exit code, and is never allowed to rewrite, summarize, or invent the body.
27
+ */
28
+ export function emitIpcResult(result, opts = {}) {
29
+ // The exit code keys on `ok === false`, not on `ok === true`, because the daemon has TWO response
30
+ // conventions and only one of them carries `ok`:
31
+ // (a) ok-bearing — { ok: true, … } / { ok: false, reason, guidance }
32
+ // (b) payload-only — a bare result with NO `ok` at all: cello_list_agents returns { agents: [] },
33
+ // cello_await_session returns { type: "timeout" | … }. (Verified against daemon.ts, not
34
+ // assumed.)
35
+ // `ok: false` is the daemon's ONE failure convention; a genuine transport/daemon failure THROWS
36
+ // and is handled by the caller as a transport error. So a payload without `ok` is a result, and
37
+ // routing it to stderr (as an earlier draft of this contract did) would report working commands
38
+ // as broken — `cello agents` would exit 1 on success.
39
+ //
40
+ // This does NOT weaken the no-fabricated-success rule: we never synthesize an ok:true, never
41
+ // rewrite a body, and never swallow an ok:false. We report exactly what the daemon said.
42
+ const failed = result.ok === false;
43
+ if (failed) {
44
+ return { stdout: "", stderr: render(result, opts.pretty), exitCode: 1 };
45
+ }
46
+ return { stdout: render(result, opts.pretty), stderr: "", exitCode: 0 };
47
+ }
48
+ /**
49
+ * A transport/daemon-level failure (socket unreachable, daemon not running, thrown error) — still
50
+ * a structured, machine-parseable JSON error on stderr, so a bash agent branches on the same shape
51
+ * whether the daemon rejected the call or never received it.
52
+ */
53
+ export function emitTransportError(reason, guidance, opts = {}) {
54
+ return {
55
+ stdout: "",
56
+ stderr: render({ ok: false, reason, guidance }, opts.pretty),
57
+ exitCode: 1,
58
+ };
59
+ }
60
+ //# sourceMappingURL=json-out.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"json-out.js","sourceRoot":"","sources":["../src/json-out.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAaH,SAAS,MAAM,CAAC,KAAc,EAAE,MAA2B;IACzD,OAAO,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC;AACzE,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,aAAa,CAC3B,MAA+B,EAC/B,OAAoB,EAAE;IAEtB,kGAAkG;IAClG,iDAAiD;IACjD,wEAAwE;IACxE,oGAAoG;IACpG,8FAA8F;IAC9F,kBAAkB;IAClB,gGAAgG;IAChG,gGAAgG;IAChG,gGAAgG;IAChG,sDAAsD;IACtD,EAAE;IACF,6FAA6F;IAC7F,yFAAyF;IACzF,MAAM,MAAM,GAAG,MAAM,CAAC,EAAE,KAAK,KAAK,CAAC;IACnC,IAAI,MAAM,EAAE,CAAC;QACX,OAAO,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,IAAI,CAAC,MAAM,CAAC,EAAE,QAAQ,EAAE,CAAC,EAAE,CAAC;IAC1E,CAAC;IACD,OAAO,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,IAAI,CAAC,MAAM,CAAC,EAAE,MAAM,EAAE,EAAE,EAAE,QAAQ,EAAE,CAAC,EAAE,CAAC;AAC1E,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,kBAAkB,CAAC,MAAc,EAAE,QAAgB,EAAE,OAAoB,EAAE;IACzF,OAAO;QACL,MAAM,EAAE,EAAE;QACV,MAAM,EAAE,MAAM,CAAC,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,EAAE,IAAI,CAAC,MAAM,CAAC;QAC5D,QAAQ,EAAE,CAAC;KACZ,CAAC;AACJ,CAAC"}
@@ -0,0 +1,170 @@
1
+ /**
2
+ * DOD-CLI-PARITY-1 Phases 1-2 — every daemon capability that was MCP-only, reachable from `cello`.
3
+ *
4
+ * Bash is the universal agent adapter: with these commands any bash-capable agent (not just Claude
5
+ * Code or Hermes) operates a CELLO node — connect, send, receive, seal — with no MCP dependency.
6
+ *
7
+ * Each command is a THIN PASS-THROUGH: parse args → call the SAME daemon IPC handler the
8
+ * corresponding cello_* MCP tool calls → emit the response under the §3 contract (json-out.ts).
9
+ * No daemon changes, no second IPC client, no logic that the daemon owns (validation, tier bounds,
10
+ * agent_id resolution) is duplicated here — the CLI surfaces the daemon's verdict, verbatim.
11
+ *
12
+ * ── The per-invocation current-agent problem (why `use-agent` persists) ──────────────────────
13
+ * The daemon's "current agent" is PER-CONNECTION state. The MCP shim holds one long-lived socket,
14
+ * so `cello_use_agent` sticks for the whole session. The CLI is the opposite: a fresh process and a
15
+ * fresh connection per invocation, torn down microseconds later. A naive `cello use-agent alice`
16
+ * pass-through would therefore set state on a dying socket and report ok:true while changing NOTHING
17
+ * for the next command — a fabricated success of exactly the kind §3 forbids.
18
+ *
19
+ * So the selection is DURABLE: `use-agent` calls the real handler (which validates the agent and
20
+ * auto-starts it — AUTOSTART-1) and, only if the daemon says ok, persists the name. Every
21
+ * agent-scoped command then REPLAYS `cello_use_agent` on its new connection before dispatching.
22
+ * That is not a parallel path — it is the same replay the MCP proxy performs after a reconnect
23
+ * (ipc-proxy.ts invariant 1), reusing the existing handler.
24
+ *
25
+ * Agent resolution, in order: explicit `--agent` > the persisted selection > (omitted, so the
26
+ * daemon applies its own sole-online-agent fallback, and stays ambiguous → no_current_agent when
27
+ * two or more are online). If a replay FAILS, the command STOPS and surfaces that error — it never
28
+ * shrugs and lets the daemon's fallback quietly run the work as a different agent.
29
+ */
30
+ import { type EmittedOutput, type EmitOptions } from "./json-out.js";
31
+ export type CliOutput = EmittedOutput;
32
+ /** Options every parity command accepts. */
33
+ export interface ParityOptions extends EmitOptions {
34
+ /** `--agent <name>` — overrides the persisted selection for this invocation only. */
35
+ agent?: string;
36
+ }
37
+ /**
38
+ * The persisted agent selection, or undefined if none was ever made.
39
+ *
40
+ * ENOENT — never selected — is the ONLY swallowed error (review F4). A blanket catch here would let
41
+ * an unreadable file (EACCES, EISDIR, a corrupt mount) read as "no selection", after which the
42
+ * daemon's sole-online fallback would quietly run the command as whatever agent happens to be up:
43
+ * the operator's selection silently replaced by a different identity, exit 0. Anything that is not
44
+ * "the file isn't there" is a real failure and is thrown.
45
+ */
46
+ export declare function readCurrentAgent(celloDir: string): Promise<string | undefined>;
47
+ /**
48
+ * The ONE place a CLI command's daemon IPC method is named (review T2).
49
+ *
50
+ * The registry's `ipcMethod` field is set FROM this map, and every function below dispatches FROM
51
+ * this map — so the field that DoD §9's parity test audits is, by construction, the literal that is
52
+ * actually sent. Previously the two were independent strings: the registry could say
53
+ * `cello_contact_set_moniker` while the code called `cello_contact_set_away`, and the audit — which
54
+ * only read the metadata — would happily pass. A comment-in-a-field is not a guarantee; this is.
55
+ */
56
+ /**
57
+ * CLI command name → the daemon IPC method it calls.
58
+ *
59
+ * The KEYS are the CLI/MCP capability names (DOD-ONBOARD-HELP-1 §2b: one vocabulary). The VALUES
60
+ * are the daemon's IPC WIRE names, which deliberately do NOT move — the shim maps tool
61
+ * `cello_agents` onto the existing `cello_list_agents` method. Renaming the wire would break a new
62
+ * daemon talking to an OLD connect shim; connect has no daemon dependency, so nothing pins the two
63
+ * together. That asymmetry is the whole reason this table exists rather than a string concat.
64
+ */
65
+ export declare const IPC_METHODS: {
66
+ readonly agents: "cello_list_agents";
67
+ readonly "start-agent": "cello_start_agent";
68
+ readonly "stop-agent": "cello_stop_agent";
69
+ readonly "use-agent": "cello_use_agent";
70
+ readonly inbox: "cello_check_notifications";
71
+ readonly transcript: "cello_get_transcript";
72
+ readonly "sealed-receipt": "cello_get_sealed_receipt";
73
+ readonly "initiate-session": "cello_initiate_session";
74
+ readonly send: "cello_send";
75
+ readonly receive: "cello_receive";
76
+ readonly "receive-session": "cello_receive_session";
77
+ readonly "close-session": "cello_close_session";
78
+ readonly "await-session": "cello_await_session";
79
+ readonly contacts: "cello_contact_list";
80
+ readonly "contact-add": "cello_contact_add";
81
+ readonly "contact-remove": "cello_contact_remove";
82
+ readonly "contact-set-tier": "cello_contact_set_tier";
83
+ readonly "contact-set-away": "cello_contact_set_away";
84
+ readonly "contact-set-moniker": "cello_contact_set_moniker";
85
+ };
86
+ /** `cello agents` → cello_list_agents. Daemon-wide, not agent-scoped. */
87
+ export declare function listAgents(celloDir: string, opts: ParityOptions): Promise<CliOutput>;
88
+ /** `cello start-agent <name>` → cello_start_agent. Brings an agent online WITHOUT claiming current. */
89
+ export declare function startAgent(celloDir: string, name: string, opts: ParityOptions): Promise<CliOutput>;
90
+ /**
91
+ * `cello stop-agent <name>` → cello_stop_agent.
92
+ *
93
+ * Also CLEARS the persisted selection when it names this agent (review F1). The daemon clears a
94
+ * stopped agent from every connection's current-agent state; the CLI's durable mirror of that state
95
+ * must follow, or the next command would try to act as an agent the operator just stopped.
96
+ */
97
+ export declare function stopAgent(celloDir: string, name: string, opts: ParityOptions): Promise<CliOutput>;
98
+ /**
99
+ * `cello use-agent <name>` → cello_use_agent, and — only if the daemon accepts it — persists the
100
+ * selection so it survives this process. The handler auto-starts the agent if offline (AUTOSTART-1).
101
+ * A rejected selection is NEVER written: a later command must not silently act as an agent the
102
+ * daemon refused.
103
+ */
104
+ export declare function useAgent(celloDir: string, name: string, opts: ParityOptions): Promise<CliOutput>;
105
+ /** `cello inbox [--scope current|all]` → cello_check_notifications (the push-loss reconciler). */
106
+ export declare function inbox(celloDir: string, opts: ParityOptions & {
107
+ scope?: "current" | "all";
108
+ }): Promise<CliOutput>;
109
+ /** `cello transcript <session-id>` → cello_get_transcript (durable, survives a daemon restart). */
110
+ export declare function transcript(celloDir: string, sessionId: string, opts: ParityOptions): Promise<CliOutput>;
111
+ /**
112
+ * `cello sealed-receipt <session-id>` → cello_get_sealed_receipt.
113
+ *
114
+ * NOT in the brief's mapping table, which listed cello_get_sealed_receipt as "already covered by
115
+ * `receipts`". It is not: `cello receipts <name>` calls cello_get_relay_receipts — a DIFFERENT
116
+ * handler (relay ordering receipts). The notarized bilateral SEAL receipt — the artifact the whole
117
+ * close ceremony exists to produce, and the one an arbitrator reads — had no CLI surface at all.
118
+ * Added under the standing rule: a real, non-stub handler with no CLI command gets one.
119
+ */
120
+ export declare function sealedReceipt(celloDir: string, sessionId: string, opts: ParityOptions): Promise<CliOutput>;
121
+ /** `cello contact <pubkey> add` → cello_contact_add. */
122
+ export declare function contactAdd(celloDir: string, pubkey: string, opts: ParityOptions): Promise<CliOutput>;
123
+ /** `cello contact remove <pubkey>` → cello_contact_remove. */
124
+ export declare function contactRemove(celloDir: string, pubkey: string, opts: ParityOptions): Promise<CliOutput>;
125
+ /** `cello contacts` → cello_contact_list. */
126
+ export declare function contactList(celloDir: string, opts: ParityOptions): Promise<CliOutput>;
127
+ /** `cello contact set-tier <pubkey> <tier>` → cello_contact_set_tier. */
128
+ export declare function contactSetTier(celloDir: string, pubkey: string, tier: number, opts: ParityOptions): Promise<CliOutput>;
129
+ /** `cello contact set-away <pubkey> <message>` → cello_contact_set_away (empty message clears it). */
130
+ export declare function contactSetAway(celloDir: string, pubkey: string, message: string | null, opts: ParityOptions): Promise<CliOutput>;
131
+ /** `cello contact set-moniker <pubkey> <moniker>` → cello_contact_set_moniker (per-CONTACT pet name). */
132
+ export declare function contactSetMoniker(celloDir: string, pubkey: string, moniker: string | null, opts: ParityOptions): Promise<CliOutput>;
133
+ /** `cello initiate-session <target-pubkey>` → cello_initiate_session. Prints the session_id. */
134
+ export declare function initiate(celloDir: string, targetPubkey: string, opts: ParityOptions): Promise<CliOutput>;
135
+ /**
136
+ * `cello send <session-id> <message>` → cello_send.
137
+ *
138
+ * Honors read-before-write exactly as the MCP tool does: if the daemon returns session_not_current
139
+ * (with its cursor), that verdict is surfaced VERBATIM and the command exits non-zero. It is never
140
+ * auto-fixed by silently reading the transcript first — the operator/agent must catch up explicitly,
141
+ * because a send that "worked" after a hidden read is a send whose ordering guarantees are a fiction.
142
+ */
143
+ export declare function send(celloDir: string, sessionId: string, content: string, opts: ParityOptions & {
144
+ governanceDecisions?: Record<string, string>;
145
+ }): Promise<CliOutput>;
146
+ /**
147
+ * `cello receive <session-id> [--since-seq N] [--timeout-ms N]` → cello_receive.
148
+ * Mirrors the MCP semantics exactly: with since_seq it is a stateless catch-up BATCH (no replay
149
+ * race, timeout ignored); without it, it BLOCKS for the next live message until timeout_ms.
150
+ */
151
+ export declare function receive(celloDir: string, sessionId: string, opts: ParityOptions & {
152
+ sinceSeq?: number;
153
+ timeoutMs?: number;
154
+ }): Promise<CliOutput>;
155
+ /** `cello receive-session <session-id> [--timeout-ms N]` → cello_receive_session. */
156
+ export declare function receiveSession(celloDir: string, sessionId: string, opts: ParityOptions & {
157
+ timeoutMs?: number;
158
+ }): Promise<CliOutput>;
159
+ /**
160
+ * `cello close-session <session-id> [--force]` → cello_close_session. Normally triggers the bilateral seal
161
+ * ceremony. --force is passed ONLY when asked for (mirroring the shim), since it forfeits the seal.
162
+ */
163
+ export declare function closeSession(celloDir: string, sessionId: string, opts: ParityOptions & {
164
+ force?: boolean;
165
+ }): Promise<CliOutput>;
166
+ /** `cello await-session [--timeout-ms N]` → cello_await_session. Blocks for an inbound doorbell. */
167
+ export declare function awaitSession(celloDir: string, opts: ParityOptions & {
168
+ timeoutMs?: number;
169
+ }): Promise<CliOutput>;
170
+ //# sourceMappingURL=parity-commands.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"parity-commands.d.ts","sourceRoot":"","sources":["../src/parity-commands.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,326 @@
1
+ /**
2
+ * DOD-CLI-PARITY-1 Phases 1-2 — every daemon capability that was MCP-only, reachable from `cello`.
3
+ *
4
+ * Bash is the universal agent adapter: with these commands any bash-capable agent (not just Claude
5
+ * Code or Hermes) operates a CELLO node — connect, send, receive, seal — with no MCP dependency.
6
+ *
7
+ * Each command is a THIN PASS-THROUGH: parse args → call the SAME daemon IPC handler the
8
+ * corresponding cello_* MCP tool calls → emit the response under the §3 contract (json-out.ts).
9
+ * No daemon changes, no second IPC client, no logic that the daemon owns (validation, tier bounds,
10
+ * agent_id resolution) is duplicated here — the CLI surfaces the daemon's verdict, verbatim.
11
+ *
12
+ * ── The per-invocation current-agent problem (why `use-agent` persists) ──────────────────────
13
+ * The daemon's "current agent" is PER-CONNECTION state. The MCP shim holds one long-lived socket,
14
+ * so `cello_use_agent` sticks for the whole session. The CLI is the opposite: a fresh process and a
15
+ * fresh connection per invocation, torn down microseconds later. A naive `cello use-agent alice`
16
+ * pass-through would therefore set state on a dying socket and report ok:true while changing NOTHING
17
+ * for the next command — a fabricated success of exactly the kind §3 forbids.
18
+ *
19
+ * So the selection is DURABLE: `use-agent` calls the real handler (which validates the agent and
20
+ * auto-starts it — AUTOSTART-1) and, only if the daemon says ok, persists the name. Every
21
+ * agent-scoped command then REPLAYS `cello_use_agent` on its new connection before dispatching.
22
+ * That is not a parallel path — it is the same replay the MCP proxy performs after a reconnect
23
+ * (ipc-proxy.ts invariant 1), reusing the existing handler.
24
+ *
25
+ * Agent resolution, in order: explicit `--agent` > the persisted selection > (omitted, so the
26
+ * daemon applies its own sole-online-agent fallback, and stays ambiguous → no_current_agent when
27
+ * two or more are online). If a replay FAILS, the command STOPS and surfaces that error — it never
28
+ * shrugs and lets the daemon's fallback quietly run the work as a different agent.
29
+ */
30
+ import { join } from "node:path";
31
+ import { readFile, writeFile, unlink } from "node:fs/promises";
32
+ import { connectToDaemon, readLock } from "@cello-protocol/daemon";
33
+ import { emitIpcResult, emitTransportError } from "./json-out.js";
34
+ /** Where `cello use-agent` records the selection: a plain text file the operator can read/delete. */
35
+ function currentAgentPath(celloDir) {
36
+ return join(celloDir, "current-agent");
37
+ }
38
+ /**
39
+ * The persisted agent selection, or undefined if none was ever made.
40
+ *
41
+ * ENOENT — never selected — is the ONLY swallowed error (review F4). A blanket catch here would let
42
+ * an unreadable file (EACCES, EISDIR, a corrupt mount) read as "no selection", after which the
43
+ * daemon's sole-online fallback would quietly run the command as whatever agent happens to be up:
44
+ * the operator's selection silently replaced by a different identity, exit 0. Anything that is not
45
+ * "the file isn't there" is a real failure and is thrown.
46
+ */
47
+ export async function readCurrentAgent(celloDir) {
48
+ try {
49
+ const raw = (await readFile(currentAgentPath(celloDir), "utf8")).trim();
50
+ return raw.length > 0 ? raw : undefined;
51
+ }
52
+ catch (err) {
53
+ if (err?.code === "ENOENT")
54
+ return undefined; // never selected
55
+ throw err;
56
+ }
57
+ }
58
+ /**
59
+ * Forget the persisted selection. Called by `stop-agent` (review F1): the daemon clears an agent
60
+ * from every connection's current-agent state when it is stopped, so the CLI's durable mirror of
61
+ * that state must be cleared too. Leaving it behind was a genuine defect — see stopAgent().
62
+ */
63
+ async function clearCurrentAgent(celloDir) {
64
+ try {
65
+ await unlink(currentAgentPath(celloDir));
66
+ }
67
+ catch (err) {
68
+ if (err?.code !== "ENOENT")
69
+ throw err;
70
+ }
71
+ }
72
+ async function writeCurrentAgent(celloDir, name) {
73
+ await writeFile(currentAgentPath(celloDir), name + "\n", "utf8");
74
+ }
75
+ /**
76
+ * Open a daemon connection, establish the current agent (if one is selected), run `fn`, and always
77
+ * close. Transport failures come back as structured JSON on stderr — so a bash agent branches on
78
+ * the same shape whether the daemon rejected the call or never received it.
79
+ */
80
+ async function withDaemon(celloDir, opts, agentScoped, fn) {
81
+ const lock = await readLock(join(celloDir, "daemon.lock"));
82
+ if (!lock) {
83
+ return emitTransportError("daemon_not_running", "No daemon is running. Start it with 'cello login', then retry.", opts);
84
+ }
85
+ let client;
86
+ try {
87
+ client = await connectToDaemon(lock.socketPath);
88
+ }
89
+ catch (err) {
90
+ return emitTransportError("daemon_unreachable", `Could not connect to the daemon at ${lock.socketPath}: ${err instanceof Error ? err.message : String(err)}. It may be mid-shutdown — check 'cello status'.`, opts);
91
+ }
92
+ try {
93
+ await client.send("ipc.connect", { clientType: "cli" });
94
+ if (agentScoped) {
95
+ // Review F2 — an EMPTY --agent must never be treated as "no --agent". `--agent "$VAR"` with
96
+ // VAR unset yields "", which is not nullish: it would suppress the persisted selection, fail
97
+ // the truthiness check below, run NO replay, and let the daemon's sole-online fallback execute
98
+ // the command as whatever agent happened to be up — exit 0, wrong identity, silently. That is
99
+ // the exact misroute this module exists to prevent, and the bash idiom makes it likely.
100
+ if (opts.agent !== undefined && opts.agent.trim() === "") {
101
+ return emitTransportError("missing_agent_value", "--agent was given an empty value (an unset shell variable?). Name an agent explicitly, or omit --agent to use the selection from 'cello use-agent'.", opts);
102
+ }
103
+ const selected = opts.agent ?? (await readCurrentAgent(celloDir));
104
+ if (selected) {
105
+ // Review F1 — the replay must not RESURRECT a stopped agent. cello_use_agent auto-starts an
106
+ // offline agent (AUTOSTART-1), so replaying it blindly meant `cello stop-agent alice` could
107
+ // be silently undone by the very next read-only command (`cello inbox`), bringing alice back
108
+ // online and reachable with no signal. Stopping an agent is kill-switch-adjacent; a command
109
+ // that reads must never re-arm it. The MCP surface never does this — the daemon clears the
110
+ // agent from every connection on stop, and later calls get no_current_agent.
111
+ //
112
+ // So: only replay an agent that is ALREADY ONLINE. An offline selection fails loud, naming
113
+ // the remedy, rather than quietly starting it or quietly running as someone else.
114
+ if (!(await isAgentOnline(client, selected))) {
115
+ return emitTransportError("selected_agent_offline", `Agent '${selected}' is not online, so this command was not run as it. Bring it online with 'cello start-agent ${selected}' (or select another with 'cello use-agent <name>'). It is NOT auto-started here: that would silently undo a deliberate 'cello stop-agent'.`, opts);
116
+ }
117
+ // The agent is online — claim it for this connection. A refusal (retired/unknown) stops the
118
+ // command: continuing would let the sole-online fallback run it as a DIFFERENT agent.
119
+ const used = (await client.send("cello_use_agent", { name: selected }));
120
+ if (used.ok !== true) {
121
+ // Defensive: cello_use_agent is ok-bearing on every path today, but if it ever returned an
122
+ // ok-less body, emitIpcResult would print IT as this command's successful result. Fail loud
123
+ // on any shape that is not an explicit ok:false, rather than pass off the wrong body.
124
+ if (used.ok === false)
125
+ return emitIpcResult(used, opts);
126
+ return emitTransportError("unexpected_replay_response", `Selecting agent '${selected}' returned an unrecognized response, so the command was not run. This is a daemon/CLI version mismatch — check 'cello status'.`, opts);
127
+ }
128
+ }
129
+ // No selection at all → send nothing, and let the daemon apply its own documented fallback
130
+ // (sole online agent; ambiguous → no_current_agent). Guessing here would misroute.
131
+ }
132
+ const result = await fn(client);
133
+ return emitIpcResult(result, opts);
134
+ }
135
+ catch (err) {
136
+ return emitTransportError("ipc_error", `The daemon call failed: ${err instanceof Error ? err.message : String(err)}`, opts);
137
+ }
138
+ finally {
139
+ client.close();
140
+ }
141
+ }
142
+ /**
143
+ * Is this agent currently ONLINE? Asked via cello_list_agents (a real handler, no new IPC path) so
144
+ * the replay can refuse to auto-start a stopped agent (review F1). Fails CLOSED: any unexpected
145
+ * shape reads as "not online", which fails the command loud rather than resurrecting an agent the
146
+ * operator deliberately stopped.
147
+ */
148
+ async function isAgentOnline(client, name) {
149
+ const res = (await client.send("cello_list_agents"));
150
+ return (res.agents ?? []).some((a) => a.name === name && a.state === "online");
151
+ }
152
+ /** The common case: one IPC call, agent-scoped unless stated otherwise. */
153
+ function ipcCommand(celloDir, method, params, opts, agentScoped = true) {
154
+ return withDaemon(celloDir, opts, agentScoped, async (client) => {
155
+ return (await client.send(method, params));
156
+ });
157
+ }
158
+ /** Drop undefined values so an omitted optional param is ABSENT, not an explicit `undefined`. */
159
+ function defined(params) {
160
+ return Object.fromEntries(Object.entries(params).filter(([, v]) => v !== undefined));
161
+ }
162
+ /**
163
+ * The ONE place a CLI command's daemon IPC method is named (review T2).
164
+ *
165
+ * The registry's `ipcMethod` field is set FROM this map, and every function below dispatches FROM
166
+ * this map — so the field that DoD §9's parity test audits is, by construction, the literal that is
167
+ * actually sent. Previously the two were independent strings: the registry could say
168
+ * `cello_contact_set_moniker` while the code called `cello_contact_set_away`, and the audit — which
169
+ * only read the metadata — would happily pass. A comment-in-a-field is not a guarantee; this is.
170
+ */
171
+ /**
172
+ * CLI command name → the daemon IPC method it calls.
173
+ *
174
+ * The KEYS are the CLI/MCP capability names (DOD-ONBOARD-HELP-1 §2b: one vocabulary). The VALUES
175
+ * are the daemon's IPC WIRE names, which deliberately do NOT move — the shim maps tool
176
+ * `cello_agents` onto the existing `cello_list_agents` method. Renaming the wire would break a new
177
+ * daemon talking to an OLD connect shim; connect has no daemon dependency, so nothing pins the two
178
+ * together. That asymmetry is the whole reason this table exists rather than a string concat.
179
+ */
180
+ export const IPC_METHODS = {
181
+ agents: "cello_list_agents",
182
+ "start-agent": "cello_start_agent",
183
+ "stop-agent": "cello_stop_agent",
184
+ "use-agent": "cello_use_agent",
185
+ inbox: "cello_check_notifications",
186
+ transcript: "cello_get_transcript",
187
+ "sealed-receipt": "cello_get_sealed_receipt",
188
+ "initiate-session": "cello_initiate_session",
189
+ send: "cello_send",
190
+ receive: "cello_receive",
191
+ "receive-session": "cello_receive_session",
192
+ "close-session": "cello_close_session",
193
+ "await-session": "cello_await_session",
194
+ contacts: "cello_contact_list",
195
+ "contact-add": "cello_contact_add",
196
+ "contact-remove": "cello_contact_remove",
197
+ "contact-set-tier": "cello_contact_set_tier",
198
+ "contact-set-away": "cello_contact_set_away",
199
+ "contact-set-moniker": "cello_contact_set_moniker",
200
+ };
201
+ // ─── Group A: agent lifecycle ──────────────────────────────────────────────────────────────────
202
+ /** `cello agents` → cello_list_agents. Daemon-wide, not agent-scoped. */
203
+ export function listAgents(celloDir, opts) {
204
+ return ipcCommand(celloDir, IPC_METHODS.agents, {}, opts, false);
205
+ }
206
+ /** `cello start-agent <name>` → cello_start_agent. Brings an agent online WITHOUT claiming current. */
207
+ export function startAgent(celloDir, name, opts) {
208
+ return ipcCommand(celloDir, IPC_METHODS["start-agent"], { name }, opts, false);
209
+ }
210
+ /**
211
+ * `cello stop-agent <name>` → cello_stop_agent.
212
+ *
213
+ * Also CLEARS the persisted selection when it names this agent (review F1). The daemon clears a
214
+ * stopped agent from every connection's current-agent state; the CLI's durable mirror of that state
215
+ * must follow, or the next command would try to act as an agent the operator just stopped.
216
+ */
217
+ export async function stopAgent(celloDir, name, opts) {
218
+ const out = await ipcCommand(celloDir, IPC_METHODS["stop-agent"], { name }, opts, false);
219
+ if (out.exitCode === 0 && (await readCurrentAgent(celloDir)) === name) {
220
+ await clearCurrentAgent(celloDir);
221
+ }
222
+ return out;
223
+ }
224
+ /**
225
+ * `cello use-agent <name>` → cello_use_agent, and — only if the daemon accepts it — persists the
226
+ * selection so it survives this process. The handler auto-starts the agent if offline (AUTOSTART-1).
227
+ * A rejected selection is NEVER written: a later command must not silently act as an agent the
228
+ * daemon refused.
229
+ */
230
+ export async function useAgent(celloDir, name, opts) {
231
+ const out = await ipcCommand(celloDir, IPC_METHODS["use-agent"], { name }, opts, false);
232
+ if (out.exitCode === 0)
233
+ await writeCurrentAgent(celloDir, name);
234
+ return out;
235
+ }
236
+ /** `cello inbox [--scope current|all]` → cello_check_notifications (the push-loss reconciler). */
237
+ export function inbox(celloDir, opts) {
238
+ return ipcCommand(celloDir, IPC_METHODS.inbox, defined({ scope: opts.scope }), opts);
239
+ }
240
+ /** `cello transcript <session-id>` → cello_get_transcript (durable, survives a daemon restart). */
241
+ export function transcript(celloDir, sessionId, opts) {
242
+ return ipcCommand(celloDir, IPC_METHODS.transcript, { session_id: sessionId }, opts);
243
+ }
244
+ /**
245
+ * `cello sealed-receipt <session-id>` → cello_get_sealed_receipt.
246
+ *
247
+ * NOT in the brief's mapping table, which listed cello_get_sealed_receipt as "already covered by
248
+ * `receipts`". It is not: `cello receipts <name>` calls cello_get_relay_receipts — a DIFFERENT
249
+ * handler (relay ordering receipts). The notarized bilateral SEAL receipt — the artifact the whole
250
+ * close ceremony exists to produce, and the one an arbitrator reads — had no CLI surface at all.
251
+ * Added under the standing rule: a real, non-stub handler with no CLI command gets one.
252
+ */
253
+ export function sealedReceipt(celloDir, sessionId, opts) {
254
+ return ipcCommand(celloDir, IPC_METHODS["sealed-receipt"], { session_id: sessionId }, opts);
255
+ }
256
+ // Review F3: the WHOLE address book now speaks the §3 contract, not just the three new sub-verbs.
257
+ // Previously add/remove/list/tier/away went through the legacy path (errors pretty-printed to
258
+ // STDOUT, no --pretty) while the new set-moniker used the parity path (errors to stderr) — so a
259
+ // bash script branching on stderr got DIFFERENT conventions between sub-verbs of the same command.
260
+ // One command, one contract. (Behavior change, journaled: contact failures now print JSON on stderr
261
+ // rather than stdout; the exit codes were already correct.)
262
+ /** `cello contact <pubkey> add` → cello_contact_add. */
263
+ export function contactAdd(celloDir, pubkey, opts) {
264
+ return ipcCommand(celloDir, IPC_METHODS["contact-add"], { pubkey }, opts);
265
+ }
266
+ /** `cello contact remove <pubkey>` → cello_contact_remove. */
267
+ export function contactRemove(celloDir, pubkey, opts) {
268
+ return ipcCommand(celloDir, IPC_METHODS["contact-remove"], { pubkey }, opts);
269
+ }
270
+ /** `cello contacts` → cello_contact_list. */
271
+ export function contactList(celloDir, opts) {
272
+ return ipcCommand(celloDir, IPC_METHODS.contacts, {}, opts);
273
+ }
274
+ /** `cello contact set-tier <pubkey> <tier>` → cello_contact_set_tier. */
275
+ export function contactSetTier(celloDir, pubkey, tier, opts) {
276
+ return ipcCommand(celloDir, IPC_METHODS["contact-set-tier"], { pubkey, tier }, opts);
277
+ }
278
+ /** `cello contact set-away <pubkey> <message>` → cello_contact_set_away (empty message clears it). */
279
+ export function contactSetAway(celloDir, pubkey, message, opts) {
280
+ return ipcCommand(celloDir, IPC_METHODS["contact-set-away"], { pubkey, message }, opts);
281
+ }
282
+ /** `cello contact set-moniker <pubkey> <moniker>` → cello_contact_set_moniker (per-CONTACT pet name). */
283
+ export function contactSetMoniker(celloDir, pubkey, moniker, opts) {
284
+ return ipcCommand(celloDir, IPC_METHODS["contact-set-moniker"], { pubkey, moniker }, opts);
285
+ }
286
+ // ─── Group B: live conversation (mirrors the MCP params EXACTLY) ───────────────────────────────
287
+ /** `cello initiate-session <target-pubkey>` → cello_initiate_session. Prints the session_id. */
288
+ export function initiate(celloDir, targetPubkey, opts) {
289
+ return ipcCommand(celloDir, IPC_METHODS["initiate-session"], { target_pubkey: targetPubkey }, opts);
290
+ }
291
+ /**
292
+ * `cello send <session-id> <message>` → cello_send.
293
+ *
294
+ * Honors read-before-write exactly as the MCP tool does: if the daemon returns session_not_current
295
+ * (with its cursor), that verdict is surfaced VERBATIM and the command exits non-zero. It is never
296
+ * auto-fixed by silently reading the transcript first — the operator/agent must catch up explicitly,
297
+ * because a send that "worked" after a hidden read is a send whose ordering guarantees are a fiction.
298
+ */
299
+ export function send(celloDir, sessionId, content, opts) {
300
+ return ipcCommand(celloDir, "cello_send", defined({ session_id: sessionId, content, governance_decisions: opts.governanceDecisions }), opts);
301
+ }
302
+ /**
303
+ * `cello receive <session-id> [--since-seq N] [--timeout-ms N]` → cello_receive.
304
+ * Mirrors the MCP semantics exactly: with since_seq it is a stateless catch-up BATCH (no replay
305
+ * race, timeout ignored); without it, it BLOCKS for the next live message until timeout_ms.
306
+ */
307
+ export function receive(celloDir, sessionId, opts) {
308
+ return ipcCommand(celloDir, "cello_receive", defined({ session_id: sessionId, timeout_ms: opts.timeoutMs, since_seq: opts.sinceSeq }), opts);
309
+ }
310
+ /** `cello receive-session <session-id> [--timeout-ms N]` → cello_receive_session. */
311
+ export function receiveSession(celloDir, sessionId, opts) {
312
+ return ipcCommand(celloDir, "cello_receive_session", defined({ session_id: sessionId, timeout_ms: opts.timeoutMs }), opts);
313
+ }
314
+ /**
315
+ * `cello close-session <session-id> [--force]` → cello_close_session. Normally triggers the bilateral seal
316
+ * ceremony. --force is passed ONLY when asked for (mirroring the shim), since it forfeits the seal.
317
+ */
318
+ export function closeSession(celloDir, sessionId, opts) {
319
+ const params = opts.force ? { session_id: sessionId, force: true } : { session_id: sessionId };
320
+ return ipcCommand(celloDir, IPC_METHODS["close-session"], params, opts);
321
+ }
322
+ /** `cello await-session [--timeout-ms N]` → cello_await_session. Blocks for an inbound doorbell. */
323
+ export function awaitSession(celloDir, opts) {
324
+ return ipcCommand(celloDir, IPC_METHODS["await-session"], defined({ timeout_ms: opts.timeoutMs }), opts);
325
+ }
326
+ //# sourceMappingURL=parity-commands.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"parity-commands.js","sourceRoot":"","sources":["../src/parity-commands.ts"],"names":[],"mappings":"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"}