@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.
- package/dist/arg-parse.d.ts +20 -0
- package/dist/arg-parse.d.ts.map +1 -0
- package/dist/arg-parse.js +30 -0
- package/dist/arg-parse.js.map +1 -0
- package/dist/bin/cello.d.ts +8 -5
- package/dist/bin/cello.d.ts.map +1 -1
- package/dist/bin/cello.js +42 -197
- package/dist/bin/cello.js.map +1 -1
- package/dist/cli-args.d.ts +27 -19
- package/dist/cli-args.d.ts.map +1 -1
- package/dist/cli-args.js +49 -103
- package/dist/cli-args.js.map +1 -1
- package/dist/commands.d.ts.map +1 -1
- package/dist/commands.js +4 -3
- package/dist/commands.js.map +1 -1
- package/dist/hermes/assets.d.ts +2 -2
- package/dist/hermes/assets.d.ts.map +1 -1
- package/dist/hermes/assets.js +11 -11
- package/dist/hermes/install-hermes.d.ts +1 -1
- package/dist/hermes/install-hermes.js +3 -3
- package/dist/hermes/install-hermes.js.map +1 -1
- package/dist/json-out.d.ts +41 -0
- package/dist/json-out.d.ts.map +1 -0
- package/dist/json-out.js +60 -0
- package/dist/json-out.js.map +1 -0
- package/dist/parity-commands.d.ts +170 -0
- package/dist/parity-commands.d.ts.map +1 -0
- package/dist/parity-commands.js +326 -0
- package/dist/parity-commands.js.map +1 -0
- package/dist/registry.d.ts +86 -0
- package/dist/registry.d.ts.map +1 -0
- package/dist/registry.js +754 -0
- package/dist/registry.js.map +1 -0
- package/package.json +2 -2
package/dist/json-out.js
ADDED
|
@@ -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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"}
|