@cotal-ai/cli 0.16.0 → 0.18.0
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/cotal-skills/skills/team-topology/SKILL.md +1 -1
- package/dist/command.d.ts.map +1 -1
- package/dist/command.js +13 -0
- package/dist/command.js.map +1 -1
- package/dist/commands/agents.d.ts +15 -15
- package/dist/commands/agents.d.ts.map +1 -1
- package/dist/commands/agents.js +187 -77
- package/dist/commands/agents.js.map +1 -1
- package/dist/commands/clean.d.ts.map +1 -1
- package/dist/commands/clean.js +4 -3
- package/dist/commands/clean.js.map +1 -1
- package/dist/commands/describe.d.ts +72 -0
- package/dist/commands/describe.d.ts.map +1 -0
- package/dist/commands/describe.js +148 -0
- package/dist/commands/describe.js.map +1 -0
- package/dist/commands/doctor.d.ts.map +1 -1
- package/dist/commands/doctor.js +27 -8
- package/dist/commands/doctor.js.map +1 -1
- package/dist/commands/down-manifest.d.ts.map +1 -1
- package/dist/commands/down-manifest.js +38 -18
- package/dist/commands/down-manifest.js.map +1 -1
- package/dist/commands/down.d.ts +9 -0
- package/dist/commands/down.d.ts.map +1 -1
- package/dist/commands/down.js +38 -10
- package/dist/commands/down.js.map +1 -1
- package/dist/commands/ext.d.ts.map +1 -1
- package/dist/commands/ext.js +16 -10
- package/dist/commands/ext.js.map +1 -1
- package/dist/commands/join.d.ts.map +1 -1
- package/dist/commands/join.js +2 -4
- package/dist/commands/join.js.map +1 -1
- package/dist/commands/meshes-add.d.ts +17 -0
- package/dist/commands/meshes-add.d.ts.map +1 -1
- package/dist/commands/meshes-add.js +72 -4
- package/dist/commands/meshes-add.js.map +1 -1
- package/dist/commands/meshes-wizard.d.ts +3 -0
- package/dist/commands/meshes-wizard.d.ts.map +1 -1
- package/dist/commands/meshes-wizard.js +78 -6
- package/dist/commands/meshes-wizard.js.map +1 -1
- package/dist/commands/meshes.d.ts +4 -0
- package/dist/commands/meshes.d.ts.map +1 -1
- package/dist/commands/meshes.js +14 -4
- package/dist/commands/meshes.js.map +1 -1
- package/dist/commands/models.d.ts.map +1 -1
- package/dist/commands/models.js +2 -2
- package/dist/commands/models.js.map +1 -1
- package/dist/commands/spawn-manifest.d.ts.map +1 -1
- package/dist/commands/spawn-manifest.js +22 -12
- package/dist/commands/spawn-manifest.js.map +1 -1
- package/dist/commands/spawn.d.ts +5 -0
- package/dist/commands/spawn.d.ts.map +1 -1
- package/dist/commands/spawn.js +5 -3
- package/dist/commands/spawn.js.map +1 -1
- package/dist/commands/status.js +25 -5
- package/dist/commands/status.js.map +1 -1
- package/dist/commands/up.d.ts +17 -2
- package/dist/commands/up.d.ts.map +1 -1
- package/dist/commands/up.js +685 -50
- package/dist/commands/up.js.map +1 -1
- package/dist/console/app.d.ts +1 -1
- package/dist/console/app.d.ts.map +1 -1
- package/dist/console/app.js +16 -5
- package/dist/console/app.js.map +1 -1
- package/dist/console/commands.d.ts.map +1 -1
- package/dist/console/commands.js +5 -5
- package/dist/console/commands.js.map +1 -1
- package/dist/console/root.d.ts.map +1 -1
- package/dist/console/root.js +6 -1
- package/dist/console/root.js.map +1 -1
- package/dist/ext-loader.d.ts.map +1 -1
- package/dist/ext-loader.js +1 -0
- package/dist/ext-loader.js.map +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +23 -0
- package/dist/index.js.map +1 -1
- package/dist/lib/attach-client.d.ts +37 -4
- package/dist/lib/attach-client.d.ts.map +1 -1
- package/dist/lib/attach-client.js +88 -18
- package/dist/lib/attach-client.js.map +1 -1
- package/dist/lib/auth-proc.d.ts +3 -1
- package/dist/lib/auth-proc.d.ts.map +1 -1
- package/dist/lib/auth-proc.js +15 -4
- package/dist/lib/auth-proc.js.map +1 -1
- package/dist/lib/connect.d.ts +1 -1
- package/dist/lib/connect.d.ts.map +1 -1
- package/dist/lib/connect.js +1 -1
- package/dist/lib/connect.js.map +1 -1
- package/dist/lib/control.d.ts +48 -12
- package/dist/lib/control.d.ts.map +1 -1
- package/dist/lib/control.js +258 -46
- package/dist/lib/control.js.map +1 -1
- package/dist/lib/delivery-proc.d.ts +19 -4
- package/dist/lib/delivery-proc.d.ts.map +1 -1
- package/dist/lib/delivery-proc.js +129 -43
- package/dist/lib/delivery-proc.js.map +1 -1
- package/dist/lib/join-target.d.ts +112 -0
- package/dist/lib/join-target.d.ts.map +1 -0
- package/dist/lib/join-target.js +130 -0
- package/dist/lib/join-target.js.map +1 -0
- package/dist/lib/manager-proc.d.ts +48 -5
- package/dist/lib/manager-proc.d.ts.map +1 -1
- package/dist/lib/manager-proc.js +131 -30
- package/dist/lib/manager-proc.js.map +1 -1
- package/dist/lib/manifest/ledger.d.ts +52 -8
- package/dist/lib/manifest/ledger.d.ts.map +1 -1
- package/dist/lib/manifest/ledger.js +77 -19
- package/dist/lib/manifest/ledger.js.map +1 -1
- package/dist/lib/manifest/live.d.ts +21 -16
- package/dist/lib/manifest/live.d.ts.map +1 -1
- package/dist/lib/manifest/live.js +33 -20
- package/dist/lib/manifest/live.js.map +1 -1
- package/dist/lib/restore.d.ts.map +1 -1
- package/dist/lib/restore.js +21 -3
- package/dist/lib/restore.js.map +1 -1
- package/dist/view/mesh-view.js +2 -2
- package/dist/view/mesh-view.js.map +1 -1
- package/package.json +4 -3
- package/dist/lib/pid.d.ts +0 -23
- package/dist/lib/pid.d.ts.map +0 -1
- package/dist/lib/pid.js +0 -39
- package/dist/lib/pid.js.map +0 -1
package/dist/lib/manager-proc.js
CHANGED
|
@@ -4,29 +4,46 @@ import { DEFAULT_SERVER } from "@cotal-ai/core";
|
|
|
4
4
|
import { selfArgv } from "./self-exec.js";
|
|
5
5
|
import { resolveSpace } from "./status.js";
|
|
6
6
|
import { cotalPath } from "./paths.js";
|
|
7
|
-
|
|
7
|
+
import { parsePid, probeLiveness } from "@cotal-ai/workspace";
|
|
8
|
+
/** Exported so the delivery cutover preflight can NAME the pid it refused on: an error that says
|
|
9
|
+
* "cannot be attributed" without saying which pid is not actionable. */
|
|
10
|
+
export const MANAGER_PID_PATH = () => cotalPath("manager.pid");
|
|
11
|
+
const PID_PATH = MANAGER_PID_PATH;
|
|
8
12
|
/** Sibling marker of `manager.pid`: written by THIS build's manager (which no longer hosts Plane-3 —
|
|
9
13
|
* the server-side delivery daemon does). Its presence beside a live `manager.pid` proves the manager is
|
|
10
14
|
* "delivery-aware" / non-hosting. A live `manager.pid` WITHOUT this marker is an OLD (pre-delivery-daemon)
|
|
11
15
|
* manager that still calls `startPlane3` — the delivery preflight stops it before the daemon binds, so an
|
|
12
16
|
* old hosting manager never double-binds `fanout`/`reader` against the new daemon. */
|
|
13
17
|
const DELIVERY_AWARE_MARKER = () => cotalPath("manager.delivery-aware");
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
/** True if the manager we started for this folder is still running (pid file + liveness). */
|
|
24
|
-
export function managerUp() {
|
|
18
|
+
/** The recorded manager's liveness, THREE-VALUED plus absent, because collapsing it to a boolean is
|
|
19
|
+
* what made this dangerous. Both collapses are silent and both are wrong:
|
|
20
|
+
* `!== "dead"` -> an `unknown` reports UP forever; no retry clears it and nothing starts.
|
|
21
|
+
* `=== "alive"` -> an `unknown` reports DOWN and a second manager launches onto a possibly-live one.
|
|
22
|
+
* `unknown` is REACHABLE on a real kernel, not just under a test shim: a Linux seccomp filter
|
|
23
|
+
* (`SECCOMP_RET_ERRNO`) or an LSM policy can return an arbitrary errno for `kill(pid, 0)` without
|
|
24
|
+
* executing it at all, and libuv preserves it. Proven with a live seccomp BPF filter, not by
|
|
25
|
+
* interposition. So the caller has to SEE the third state and refuse. */
|
|
26
|
+
export function managerLiveness(probe = probeLiveness) {
|
|
25
27
|
const p = PID_PATH();
|
|
26
28
|
if (!existsSync(p))
|
|
27
|
-
return
|
|
28
|
-
const
|
|
29
|
-
|
|
29
|
+
return "absent";
|
|
30
|
+
const raw = readFileSync(p, "utf8").trim();
|
|
31
|
+
if (raw === "")
|
|
32
|
+
return "absent"; // a pre-protocol husk: nothing is behind it
|
|
33
|
+
const pid = parsePid(raw);
|
|
34
|
+
// NOT `absent`. Folding non-empty corrupt content into "no manager recorded" is what let the
|
|
35
|
+
// ensure paths OVERWRITE it and launch a replacement, which is the same defect as deleting it:
|
|
36
|
+
// that record may front a live process nobody can identify. `absent` means no pidfile (or an
|
|
37
|
+
// empty husk); corrupt content is its own state and every action path must refuse on it.
|
|
38
|
+
if (pid === undefined)
|
|
39
|
+
return "unattributable";
|
|
40
|
+
return probe(pid);
|
|
41
|
+
}
|
|
42
|
+
/** True only if the manager is PROVABLY running. `unknown` is not up, and callers that would ACT on
|
|
43
|
+
* that answer must use {@link managerLiveness} instead: this boolean cannot express the difference
|
|
44
|
+
* between "not running" and "cannot tell", and acting on the difference is the whole point. */
|
|
45
|
+
export function managerUp() {
|
|
46
|
+
return managerLiveness() === "alive";
|
|
30
47
|
}
|
|
31
48
|
/** True if the live manager carries a delivery-aware marker BOUND to its current pid (i.e. it's THIS
|
|
32
49
|
* build, non-hosting). Fail-closed: the marker stores the pid it was written for, and this requires it
|
|
@@ -79,6 +96,8 @@ export function startManagerDetached(o = {}) {
|
|
|
79
96
|
...(o.launch ? ["--launch", o.launch] : []),
|
|
80
97
|
...(o.resumeAttempt ? ["--resume-attempt", o.resumeAttempt] : []),
|
|
81
98
|
...(o.resumeCommitToken ? ["--resume-commit-token", o.resumeCommitToken] : []),
|
|
99
|
+
// P2 item 6: the broker ws listener port (loopback) for the console session client's wsUrl.
|
|
100
|
+
...(o.wsPort !== undefined ? ["--ws-port", String(o.wsPort)] : []),
|
|
82
101
|
];
|
|
83
102
|
// This is an INTERNAL child re-exec: the `up`/`spawn` that reached here already ran the first-run
|
|
84
103
|
// connector seed, so the manager skips it on boot (a direct `cotal supervise` still seeds).
|
|
@@ -95,28 +114,110 @@ export function startManagerDetached(o = {}) {
|
|
|
95
114
|
* one detached. Best-effort — callers treat it as non-fatal. A caller that needs THE manager to
|
|
96
115
|
* carry a runtime/launch spec (`up -f`) must stop any leftover manager first — a reused one is
|
|
97
116
|
* taken as-is. */
|
|
98
|
-
|
|
99
|
-
|
|
117
|
+
/** Refuse to stand a manager up OVER a record we cannot read or attribute.
|
|
118
|
+
*
|
|
119
|
+
* Exported because `ensureManager` is not the only path that starts one: `cotal spawn -f` calls
|
|
120
|
+
* `startManagerDetached` directly after its own lease checks, and so skipped this entirely. A lease
|
|
121
|
+
* says nobody is ANSWERING; it does not say the recorded pid is dead. Overwriting an unknown or
|
|
122
|
+
* unattributable record is the same defect as deleting it, reached through a different verb, which
|
|
123
|
+
* is the third time that shape has appeared in this change. Any future starter calls this first. */
|
|
124
|
+
export function assertManagerRecordReplaceable(probe = probeLiveness) {
|
|
125
|
+
const state = managerLiveness(probe);
|
|
126
|
+
if (state === "unattributable")
|
|
127
|
+
throw new Error(`the manager pidfile at ${PID_PATH()} holds content that is not a pid (${JSON.stringify(readFileSync(PID_PATH(), "utf8").trim())}).\n` +
|
|
128
|
+
`Refusing to start a manager over it: that record may front a live process nobody can identify, and overwriting it would orphan the process while reporting a healthy control plane.\n` +
|
|
129
|
+
`NEXT: find and stop that process, then remove \`.cotal/manager.pid\` by hand.`);
|
|
130
|
+
if (state === "unknown")
|
|
131
|
+
throw new Error(`the recorded manager pid (${readFileSync(PID_PATH(), "utf8").trim()}) cannot be attributed: the kernel answered neither "running" nor "no such process" (a seccomp filter or LSM policy does this inside some sandboxes).\n` +
|
|
132
|
+
`Refusing to start a manager over it: it may still be running and bound to the control plane.\n` +
|
|
133
|
+
`NEXT: verify with \`ps -p <pid>\`. If it is gone, remove \`.cotal/manager.pid\` and re-run.`);
|
|
134
|
+
}
|
|
135
|
+
export function ensureManager(o = {}, probe = probeLiveness) {
|
|
136
|
+
const state = managerLiveness(probe);
|
|
137
|
+
if (state === "alive")
|
|
100
138
|
return { running: true };
|
|
139
|
+
assertManagerRecordReplaceable(probe); // refuses on unknown / unattributable
|
|
101
140
|
startManagerDetached(o);
|
|
102
141
|
return { running: true };
|
|
103
142
|
}
|
|
104
|
-
/**
|
|
105
|
-
*
|
|
106
|
-
|
|
143
|
+
/** Blocking sleep. DO NOT reintroduce this for death-waiting: it blocks the event loop, so a child
|
|
144
|
+
* of this process is never reaped, remains a signalable zombie, and reads `alive` forever. That
|
|
145
|
+
* turned `cotal up` + Ctrl-C into an exit-1 that left the broker running. Death-waits await. */
|
|
146
|
+
// (sleepSync removed: see above.)
|
|
147
|
+
/** Stop the detached (pty) manager if we started one, and remove its records ONLY once it is gone.
|
|
148
|
+
*
|
|
149
|
+
* THIS USED TO CATCH EVERY SIGNAL FAILURE AS "already gone" AND DELETE THE RECORDS ANYWAY. That was
|
|
150
|
+
* survivable while `EPERM` was misread as dead, because the caller never got here: the cutover
|
|
151
|
+
* preflight skipped a manager it thought was not running. Resolving `EPERM` to `alive` (the fix this
|
|
152
|
+
* change exists for) makes the preflight recognise ANOTHER USER's live manager and call this, at
|
|
153
|
+
* which point the old code sent a signal it was not permitted to send, swallowed the refusal, and
|
|
154
|
+
* deleted the pidfile and marker of a process that was still running and still bound to Plane 3.
|
|
155
|
+
* A correct fix upstream reaching a latent destructive bug downstream is the worst shape available,
|
|
156
|
+
* so this refuses instead: records are removed only on proven death, never on a signal we could not
|
|
157
|
+
* send or a death we could not confirm. Found by review, with a kernel seccomp proof. */
|
|
158
|
+
export async function stopManager(probe = probeLiveness, signal = undefined) {
|
|
159
|
+
const send = signal ?? ((pid, sig) => process.kill(pid, sig));
|
|
107
160
|
const p = PID_PATH();
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
161
|
+
const marker = DELIVERY_AWARE_MARKER();
|
|
162
|
+
const clear = () => {
|
|
163
|
+
rmSync(marker, { force: true });
|
|
164
|
+
rmSync(p, { force: true });
|
|
165
|
+
};
|
|
166
|
+
if (!existsSync(p)) {
|
|
167
|
+
rmSync(marker, { force: true }); // a marker with no pid records nothing
|
|
168
|
+
return "already-gone";
|
|
169
|
+
}
|
|
170
|
+
const raw = readFileSync(p, "utf8").trim();
|
|
171
|
+
const pid = parsePid(raw);
|
|
172
|
+
if (pid === undefined) {
|
|
173
|
+
// An EMPTY pidfile is a pre-protocol husk with nothing behind it, and clearing it is safe. ANY
|
|
174
|
+
// OTHER unattributable content (garbled, fractional, out of range) may still front a LIVE
|
|
175
|
+
// process we cannot identify or signal, so removing it would orphan that process while
|
|
176
|
+
// reporting a clean stop. The contract at the top of pid.ts says such content is never a pid to
|
|
177
|
+
// delete a record against; this is that rule at the destructive end, matching down.ts:298-311
|
|
178
|
+
// and stopAuthService, which already refuse. My first version cleared it.
|
|
179
|
+
if (raw === "") {
|
|
180
|
+
clear();
|
|
181
|
+
return "already-gone";
|
|
115
182
|
}
|
|
116
|
-
|
|
117
|
-
|
|
183
|
+
throw new Error(`the manager pidfile at ${p} is unattributable (${JSON.stringify(raw)}): it may still front a running process nobody can identify.\n` +
|
|
184
|
+
`Refusing to remove it or report a clean stop; the delivery-aware marker is preserved with it.\n` +
|
|
185
|
+
`NEXT: find and stop that process, then remove the file by hand.`);
|
|
186
|
+
}
|
|
187
|
+
const before = probe(pid);
|
|
188
|
+
if (before === "dead") {
|
|
189
|
+
clear();
|
|
190
|
+
return "already-gone";
|
|
191
|
+
}
|
|
192
|
+
if (before === "unknown")
|
|
193
|
+
throw new Error(`refusing to stop manager pid ${pid}: its liveness cannot be determined (the kernel answered neither "running" nor "no such process"; a seccomp filter or LSM policy does this).\n` +
|
|
194
|
+
`The pidfile and delivery-aware marker are LEFT IN PLACE: deleting them would orphan a process that may still be bound to the control plane.\n` +
|
|
195
|
+
`NEXT: verify with \`ps -p ${pid}\`, then stop it yourself or remove \`.cotal/manager.pid\` if it is gone.`);
|
|
196
|
+
try {
|
|
197
|
+
send(pid, "SIGTERM");
|
|
198
|
+
}
|
|
199
|
+
catch (e) {
|
|
200
|
+
const code = e.code;
|
|
201
|
+
if (code === "ESRCH") {
|
|
202
|
+
clear(); // died between the probe and the signal, which is an ordinary race and genuinely gone
|
|
203
|
+
return "already-gone";
|
|
118
204
|
}
|
|
205
|
+
throw new Error(`refusing to stop manager pid ${pid}: the signal was rejected (${code ?? "unknown error"}).\n` +
|
|
206
|
+
`EPERM here means the process belongs to another user, so it is running and NOT ours to stop. The pidfile and marker are LEFT IN PLACE.\n` +
|
|
207
|
+
`NEXT: stop it as its owner, or remove \`.cotal/manager.pid\` if you are certain it is gone.`);
|
|
119
208
|
}
|
|
120
|
-
|
|
209
|
+
// The signal was accepted, which is not the same as the process being gone. Prove it before
|
|
210
|
+
// removing the record, bounded, because a record deleted while its process lives is the defect.
|
|
211
|
+
// AWAIT, never a blocking sleep: this process spawned the manager, so the event loop must run
|
|
212
|
+
// for it to be reaped. A blocked loop leaves a zombie that still answers kill(pid,0).
|
|
213
|
+
for (let i = 0; i < 40 && probe(pid) === "alive"; i++)
|
|
214
|
+
await new Promise((r) => setTimeout(r, 50));
|
|
215
|
+
const after = probe(pid);
|
|
216
|
+
if (after !== "dead")
|
|
217
|
+
throw new Error(`manager pid ${pid} accepted SIGTERM but was still ${after === "alive" ? "running" : "unattributable"} after 2s.\n` +
|
|
218
|
+
`The pidfile and marker are LEFT IN PLACE rather than recording a stop that did not happen.\n` +
|
|
219
|
+
`NEXT: check \`ps -p ${pid}\` and stop it directly if it is wedged.`);
|
|
220
|
+
clear();
|
|
221
|
+
return "stopped";
|
|
121
222
|
}
|
|
122
223
|
//# sourceMappingURL=manager-proc.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"manager-proc.js","sourceRoot":"","sources":["../../src/lib/manager-proc.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AACtD,OAAO,EAAE,UAAU,EAAE,QAAQ,EAAE,SAAS,EAAE,SAAS,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AAC1G,OAAO,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAChD,OAAO,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAC1C,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAC3C,OAAO,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"manager-proc.js","sourceRoot":"","sources":["../../src/lib/manager-proc.ts"],"names":[],"mappings":"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"}
|
|
@@ -5,6 +5,7 @@ declare const LedgerAgentSchema: z.ZodObject<{
|
|
|
5
5
|
name: z.ZodString;
|
|
6
6
|
id: z.ZodString;
|
|
7
7
|
hash: z.ZodString;
|
|
8
|
+
lifecycleUid: z.ZodOptional<z.ZodString>;
|
|
8
9
|
}, z.core.$strict>;
|
|
9
10
|
declare const LedgerSchema: z.ZodObject<{
|
|
10
11
|
apiVersion: z.ZodLiteral<"cotal-ledger/v1">;
|
|
@@ -22,6 +23,7 @@ declare const LedgerSchema: z.ZodObject<{
|
|
|
22
23
|
name: z.ZodString;
|
|
23
24
|
id: z.ZodString;
|
|
24
25
|
hash: z.ZodString;
|
|
26
|
+
lifecycleUid: z.ZodOptional<z.ZodString>;
|
|
25
27
|
}, z.core.$strict>>;
|
|
26
28
|
}, z.core.$strict>;
|
|
27
29
|
}, z.core.$strict>;
|
|
@@ -54,13 +56,54 @@ export declare function writeLedger(root: string, ledger: MeshLedger, opts?: {
|
|
|
54
56
|
* ledger is proven before the caller deletes anything (no partial "validated the class I'm about to
|
|
55
57
|
* delete" flow). Throws on any deviation. */
|
|
56
58
|
export declare function loadLedger(path: string): MeshLedger;
|
|
57
|
-
/**
|
|
58
|
-
*
|
|
59
|
-
*
|
|
59
|
+
/** Build the ledger row for ONE launched agent, and PARSE it rather than assert it.
|
|
60
|
+
*
|
|
61
|
+
* WHICH SIDE EACH FIELD COMES FROM IS THE WHOLE POINT. `requested` and `hash` are the DEPLOY
|
|
62
|
+
* CALLER'S OWN inputs — it submitted the manifest key and resolved the drift hash before it ever
|
|
63
|
+
* called the manager — so they are read from the plan. Only the SPAWNED identity (`name`, `id`,
|
|
64
|
+
* `lifecycleUid`) can come from the reply, and that is exactly what the v0.4 action acceptance
|
|
65
|
+
* floor carries (P2 item 2 ruling 3: the manifest details are deliberately NOT in the launch
|
|
66
|
+
* output contract, because the caller can re-derive them). Reaching across the wire for a value
|
|
67
|
+
* already in local scope is what broke this: the reply stopped carrying them, `as` could not warn,
|
|
68
|
+
* `JSON.stringify` dropped the undefined keys, and the row only failed months later at teardown.
|
|
69
|
+
*
|
|
70
|
+
* PARSE, NEVER CAST. A cast is a claim about a shape the compiler then stops checking; the whole
|
|
71
|
+
* defect lived in the gap between that claim and the wire. This throws at WRITE time, naming the
|
|
72
|
+
* field, instead of persisting a record the reader will refuse. */
|
|
73
|
+
export declare function buildLedgerAgentRow(planned: {
|
|
74
|
+
requested: string;
|
|
75
|
+
hash: string;
|
|
76
|
+
}, spawned: {
|
|
77
|
+
name?: unknown;
|
|
78
|
+
id?: unknown;
|
|
79
|
+
lifecycleUid?: unknown;
|
|
80
|
+
}): LedgerAgent;
|
|
81
|
+
/** Every valid ledger under `<root>/.cotal/manifests/`. Foreign files are skipped (a targeted
|
|
82
|
+
* `down -f --run <id>` names one directly); used to resolve a `down -f cotal.yaml` to its run by
|
|
83
|
+
* `manifestHash`.
|
|
84
|
+
*
|
|
85
|
+
* A REFUSED file is NOT the same as an absent one, and collapsing the two cost a release. When a
|
|
86
|
+
* file under this root is named for its own `runId` but fails validation, it is OURS and broken,
|
|
87
|
+
* not somebody else's: swallowing that turned a zod error NAMING the missing fields into
|
|
88
|
+
* `findLedgerByHash`'s "was it edited since `spawn -f`?", which accuses the operator of editing a
|
|
89
|
+
* manifest they never touched. So refusals are RETURNED alongside the valid rows and the caller
|
|
90
|
+
* decides; the message that already existed is surfaced rather than replaced. */
|
|
60
91
|
export declare function listLedgers(root: string): Array<{
|
|
61
92
|
path: string;
|
|
62
93
|
ledger: MeshLedger;
|
|
63
94
|
}>;
|
|
95
|
+
/** {@link listLedgers} plus the files this root REFUSED, so a caller can tell "no ledger here" from
|
|
96
|
+
* "a ledger I could not read". `refused` carries the validator's own message verbatim. */
|
|
97
|
+
export declare function listLedgerFiles(root: string): {
|
|
98
|
+
valid: Array<{
|
|
99
|
+
path: string;
|
|
100
|
+
ledger: MeshLedger;
|
|
101
|
+
}>;
|
|
102
|
+
refused: Array<{
|
|
103
|
+
path: string;
|
|
104
|
+
why: string;
|
|
105
|
+
}>;
|
|
106
|
+
};
|
|
64
107
|
/** Resolve a `down -f cotal.yaml` to its ledger by the manifest's content hash. Fails (never
|
|
65
108
|
* guesses) when nothing matches (edited file) or more than one does — `--run <id>` is the escape. */
|
|
66
109
|
export declare function findLedgerByHash(root: string, manifestHash: string): {
|
|
@@ -73,11 +116,12 @@ export declare function findLedgerByRun(root: string, runId: string): {
|
|
|
73
116
|
path: string;
|
|
74
117
|
ledger: MeshLedger;
|
|
75
118
|
};
|
|
76
|
-
/** Derive an owned agent's cred path under the known auth root
|
|
77
|
-
*
|
|
78
|
-
* the workspace's single filename source for the kind (
|
|
119
|
+
/** Derive an owned agent's cred path under the known auth root from the SPAWNED name (+ the
|
|
120
|
+
* recorded lifecycle uid when the row carries one). The ledger never stores a cred path; teardown
|
|
121
|
+
* derives it here through the workspace's single filename source for the kind (the guarded
|
|
79
122
|
* segment refuses any name that could escape the creds dir), so teardown can never derive a
|
|
80
|
-
* DIFFERENT path than provisioning wrote
|
|
81
|
-
|
|
123
|
+
* DIFFERENT path than provisioning wrote: a uid-carrying row maps to the lifecycle-keyed file its
|
|
124
|
+
* spawn materialized, a pre-split row to the legacy name-keyed one. */
|
|
125
|
+
export declare function ownedCredPath(root: string, spawnedName: string, lifecycleUid?: string): string;
|
|
82
126
|
export {};
|
|
83
127
|
//# sourceMappingURL=ledger.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ledger.d.ts","sourceRoot":"","sources":["../../../src/lib/manifest/ledger.ts"],"names":[],"mappings":"AAkBA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAIxB,eAAO,MAAM,cAAc,oBAAoB,CAAC;AAOhD,QAAA,MAAM,iBAAiB
|
|
1
|
+
{"version":3,"file":"ledger.d.ts","sourceRoot":"","sources":["../../../src/lib/manifest/ledger.ts"],"names":[],"mappings":"AAkBA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAIxB,eAAO,MAAM,cAAc,oBAAoB,CAAC;AAOhD,QAAA,MAAM,iBAAiB;;;;;;kBAcrB,CAAC;AAEH,QAAA,MAAM,YAAY;;;;;;;;;;;;;;;;;;;kBAgBhB,CAAC;AAEH,MAAM,MAAM,UAAU,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,YAAY,CAAC,CAAC;AACtD,MAAM,MAAM,WAAW,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,iBAAiB,CAAC,CAAC;AAE5D;;sCAEsC;AACtC,wBAAgB,WAAW,CAAC,IAAI,EAAE;IAChC,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,YAAY,EAAE,MAAM,CAAC;IACrB,YAAY,EAAE,MAAM,CAAC;IACrB,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,MAAM,EAAE,WAAW,EAAE,CAAC;CACvB,GAAG,UAAU,CAYb;AAED;;6FAE6F;AAC7F,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAEtD;AAED;;0EAE0E;AAC1E,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,UAAU,EAAE,IAAI,GAAE;IAAE,MAAM,CAAC,EAAE,OAAO,CAAA;CAAO,GAAG,MAAM,CAcrG;AAED;;;8CAG8C;AAC9C,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,UAAU,CAmCnD;AAED;;;;;;;;;;;;;oEAaoE;AACpE,wBAAgB,mBAAmB,CACjC,OAAO,EAAE;IAAE,SAAS,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,EAC5C,OAAO,EAAE;IAAE,IAAI,CAAC,EAAE,OAAO,CAAC;IAAC,EAAE,CAAC,EAAE,OAAO,CAAC;IAAC,YAAY,CAAC,EAAE,OAAO,CAAA;CAAE,GAChE,WAAW,CAab;AAED;;;;;;;;;kFASkF;AAClF,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,KAAK,CAAC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,UAAU,CAAA;CAAE,CAAC,CAErF;AAED;2FAC2F;AAC3F,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG;IAC7C,KAAK,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,UAAU,CAAA;KAAE,CAAC,CAAC;IACnD,OAAO,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CAC/C,CA4BA;AAED;sGACsG;AACtG,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,GAAG;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,UAAU,CAAA;CAAE,CAezG;AAED;gCACgC;AAChC,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,UAAU,CAAA;CAAE,CAUjG;AAED;;;;;wEAKwE;AACxE,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,EAAE,YAAY,CAAC,EAAE,MAAM,GAAG,MAAM,CAK9F"}
|
|
@@ -18,7 +18,7 @@ import { readFileSync, writeFileSync, readdirSync, renameSync, lstatSync } from
|
|
|
18
18
|
import { join } from "node:path";
|
|
19
19
|
import { z } from "zod";
|
|
20
20
|
import { assertValidChannel, assertValidName, ensureDirNoSymlink, isConcreteChannel, realDirNoSymlink } from "@cotal-ai/core";
|
|
21
|
-
import { agentSecretFilePaths } from "@cotal-ai/workspace";
|
|
21
|
+
import { agentLifecycleSecretFilePaths, agentSecretFilePaths } from "@cotal-ai/workspace";
|
|
22
22
|
export const LEDGER_VERSION = "cotal-ledger/v1";
|
|
23
23
|
// Path-/route-safe token (run id, agent name) and an alphanumeric content hash — same shapes the
|
|
24
24
|
// launch spec uses, so the ledger can't smuggle a traversal/injection string into a derived path.
|
|
@@ -35,6 +35,9 @@ const LedgerAgentSchema = z.strictObject({
|
|
|
35
35
|
id: z.string().min(1),
|
|
36
36
|
/** The resolved hash at spawn (drift/stale detection on re-apply). */
|
|
37
37
|
hash: z.string().regex(HASH, "hash must be alphanumeric"),
|
|
38
|
+
/** The incarnation's lifecycle UID from the spawn reply (SPEC 13.1). Optional: rows written by a
|
|
39
|
+
* pre-split generation carry none, and their creds stay filed under the name-keyed path. */
|
|
40
|
+
lifecycleUid: z.string().regex(/^[a-z0-9]{26,32}$/, "lifecycleUid must be a lifecycle uid token").optional(),
|
|
38
41
|
});
|
|
39
42
|
const LedgerSchema = z.strictObject({
|
|
40
43
|
apiVersion: z.literal(LEDGER_VERSION),
|
|
@@ -141,23 +144,64 @@ export function loadLedger(path) {
|
|
|
141
144
|
}
|
|
142
145
|
return led;
|
|
143
146
|
}
|
|
144
|
-
/**
|
|
145
|
-
*
|
|
146
|
-
*
|
|
147
|
+
/** Build the ledger row for ONE launched agent, and PARSE it rather than assert it.
|
|
148
|
+
*
|
|
149
|
+
* WHICH SIDE EACH FIELD COMES FROM IS THE WHOLE POINT. `requested` and `hash` are the DEPLOY
|
|
150
|
+
* CALLER'S OWN inputs — it submitted the manifest key and resolved the drift hash before it ever
|
|
151
|
+
* called the manager — so they are read from the plan. Only the SPAWNED identity (`name`, `id`,
|
|
152
|
+
* `lifecycleUid`) can come from the reply, and that is exactly what the v0.4 action acceptance
|
|
153
|
+
* floor carries (P2 item 2 ruling 3: the manifest details are deliberately NOT in the launch
|
|
154
|
+
* output contract, because the caller can re-derive them). Reaching across the wire for a value
|
|
155
|
+
* already in local scope is what broke this: the reply stopped carrying them, `as` could not warn,
|
|
156
|
+
* `JSON.stringify` dropped the undefined keys, and the row only failed months later at teardown.
|
|
157
|
+
*
|
|
158
|
+
* PARSE, NEVER CAST. A cast is a claim about a shape the compiler then stops checking; the whole
|
|
159
|
+
* defect lived in the gap between that claim and the wire. This throws at WRITE time, naming the
|
|
160
|
+
* field, instead of persisting a record the reader will refuse. */
|
|
161
|
+
export function buildLedgerAgentRow(planned, spawned) {
|
|
162
|
+
const parsed = LedgerAgentSchema.safeParse({
|
|
163
|
+
requested: planned.requested,
|
|
164
|
+
hash: planned.hash,
|
|
165
|
+
name: spawned.name,
|
|
166
|
+
id: spawned.id,
|
|
167
|
+
// Omit rather than pass undefined: a pre-split manager's reply carries no uid, and the row must
|
|
168
|
+
// stay name-keyed in that case rather than carry an explicit empty.
|
|
169
|
+
...(spawned.lifecycleUid !== undefined ? { lifecycleUid: spawned.lifecycleUid } : {}),
|
|
170
|
+
});
|
|
171
|
+
if (!parsed.success)
|
|
172
|
+
throw new Error(`refusing to record an unreadable ledger row for "${planned.requested}": ${parsed.error.issues.map((i) => `${i.path.join(".")}: ${i.message}`).join("; ")}`);
|
|
173
|
+
return parsed.data;
|
|
174
|
+
}
|
|
175
|
+
/** Every valid ledger under `<root>/.cotal/manifests/`. Foreign files are skipped (a targeted
|
|
176
|
+
* `down -f --run <id>` names one directly); used to resolve a `down -f cotal.yaml` to its run by
|
|
177
|
+
* `manifestHash`.
|
|
178
|
+
*
|
|
179
|
+
* A REFUSED file is NOT the same as an absent one, and collapsing the two cost a release. When a
|
|
180
|
+
* file under this root is named for its own `runId` but fails validation, it is OURS and broken,
|
|
181
|
+
* not somebody else's: swallowing that turned a zod error NAMING the missing fields into
|
|
182
|
+
* `findLedgerByHash`'s "was it edited since `spawn -f`?", which accuses the operator of editing a
|
|
183
|
+
* manifest they never touched. So refusals are RETURNED alongside the valid rows and the caller
|
|
184
|
+
* decides; the message that already existed is surfaced rather than replaced. */
|
|
147
185
|
export function listLedgers(root) {
|
|
186
|
+
return listLedgerFiles(root).valid;
|
|
187
|
+
}
|
|
188
|
+
/** {@link listLedgers} plus the files this root REFUSED, so a caller can tell "no ledger here" from
|
|
189
|
+
* "a ledger I could not read". `refused` carries the validator's own message verbatim. */
|
|
190
|
+
export function listLedgerFiles(root) {
|
|
148
191
|
// Prove `.cotal/manifests` is a real (non-symlink) directory chain before reading under it — a
|
|
149
192
|
// symlinked parent could redirect `down -f` to attacker-chosen ledgers.
|
|
150
193
|
const dir = realDirNoSymlink(root, ".cotal", "manifests");
|
|
151
194
|
if (!dir)
|
|
152
|
-
return [];
|
|
195
|
+
return { valid: [], refused: [] };
|
|
153
196
|
let names;
|
|
154
197
|
try {
|
|
155
198
|
names = readdirSync(dir);
|
|
156
199
|
}
|
|
157
200
|
catch {
|
|
158
|
-
return [];
|
|
201
|
+
return { valid: [], refused: [] };
|
|
159
202
|
}
|
|
160
|
-
const
|
|
203
|
+
const valid = [];
|
|
204
|
+
const refused = [];
|
|
161
205
|
for (const n of names) {
|
|
162
206
|
if (!n.endsWith(".json") || n.startsWith("."))
|
|
163
207
|
continue;
|
|
@@ -166,20 +210,31 @@ export function listLedgers(root) {
|
|
|
166
210
|
const ledger = loadLedger(p);
|
|
167
211
|
if (`${ledger.runId}.json` !== n)
|
|
168
212
|
continue; // filename must match the declared runId (no spoofed authority)
|
|
169
|
-
|
|
213
|
+
valid.push({ path: p, ledger });
|
|
170
214
|
}
|
|
171
|
-
catch {
|
|
172
|
-
|
|
215
|
+
catch (e) {
|
|
216
|
+
// A file named `<runId>.json` is a ledger THIS root wrote; a validation failure on it is our
|
|
217
|
+
// own bad record, not a foreign file. Keep the validator's message: it names the offending
|
|
218
|
+
// field, which is the whole diagnosis.
|
|
219
|
+
refused.push({ path: p, why: e.message });
|
|
173
220
|
}
|
|
174
221
|
}
|
|
175
|
-
return
|
|
222
|
+
return { valid, refused };
|
|
176
223
|
}
|
|
177
224
|
/** Resolve a `down -f cotal.yaml` to its ledger by the manifest's content hash. Fails (never
|
|
178
225
|
* guesses) when nothing matches (edited file) or more than one does — `--run <id>` is the escape. */
|
|
179
226
|
export function findLedgerByHash(root, manifestHash) {
|
|
180
|
-
const
|
|
181
|
-
|
|
227
|
+
const { valid, refused } = listLedgerFiles(root);
|
|
228
|
+
const matches = valid.filter((l) => l.ledger.manifestHash === manifestHash);
|
|
229
|
+
if (matches.length === 0) {
|
|
230
|
+
// A REFUSED ledger is not an absent one. Reporting "was it edited?" while holding a validator
|
|
231
|
+
// error that names the offending field sends the operator to look at a file that is fine, and
|
|
232
|
+
// hides the record that is not. Report what we actually know, and never let the accusation
|
|
233
|
+
// stand in for a diagnosis we already have.
|
|
234
|
+
if (refused.length)
|
|
235
|
+
throw new Error(`this root has ${refused.length} ledger(s) it cannot read, so a matching run may exist but be unreadable - fix or remove them, then retry:\n${refused.map((r) => ` ${r.path}: ${r.why}`).join("\n")}`);
|
|
182
236
|
throw new Error(`no ledger matches this manifest's current contents (was it edited since \`spawn -f\`?) - tear down by run id: \`cotal down -f <file> --run <id>\``);
|
|
237
|
+
}
|
|
183
238
|
if (matches.length > 1)
|
|
184
239
|
throw new Error(`${matches.length} runs share this manifest - name one: ${matches.map((m) => m.ledger.runId).join(", ")} (\`--run <id>\`)`);
|
|
185
240
|
return matches[0];
|
|
@@ -199,13 +254,16 @@ export function findLedgerByRun(root, runId) {
|
|
|
199
254
|
throw new Error(`ledger ${path}: declares runId "${ledger.runId}", not "${runId}" - refusing`);
|
|
200
255
|
return { path, ledger };
|
|
201
256
|
}
|
|
202
|
-
/** Derive an owned agent's cred path under the known auth root
|
|
203
|
-
*
|
|
204
|
-
* the workspace's single filename source for the kind (
|
|
257
|
+
/** Derive an owned agent's cred path under the known auth root from the SPAWNED name (+ the
|
|
258
|
+
* recorded lifecycle uid when the row carries one). The ledger never stores a cred path; teardown
|
|
259
|
+
* derives it here through the workspace's single filename source for the kind (the guarded
|
|
205
260
|
* segment refuses any name that could escape the creds dir), so teardown can never derive a
|
|
206
|
-
* DIFFERENT path than provisioning wrote
|
|
207
|
-
|
|
261
|
+
* DIFFERENT path than provisioning wrote: a uid-carrying row maps to the lifecycle-keyed file its
|
|
262
|
+
* spawn materialized, a pre-split row to the legacy name-keyed one. */
|
|
263
|
+
export function ownedCredPath(root, spawnedName, lifecycleUid) {
|
|
208
264
|
assertValidName(spawnedName); // manifest-level refusal first, with the ledger's own phrasing
|
|
209
|
-
return
|
|
265
|
+
return lifecycleUid
|
|
266
|
+
? agentLifecycleSecretFilePaths(root, spawnedName, lifecycleUid).creds
|
|
267
|
+
: agentSecretFilePaths(root, spawnedName).creds;
|
|
210
268
|
}
|
|
211
269
|
//# sourceMappingURL=ledger.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ledger.js","sourceRoot":"","sources":["../../../src/lib/manifest/ledger.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AACH,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AACtD,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,WAAW,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AAC1F,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,kBAAkB,EAAE,eAAe,EAAE,kBAAkB,EAAE,iBAAiB,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAC9H,OAAO,EAAE,oBAAoB,EAAE,MAAM,qBAAqB,CAAC;
|
|
1
|
+
{"version":3,"file":"ledger.js","sourceRoot":"","sources":["../../../src/lib/manifest/ledger.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,15 +1,19 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Live-mesh helpers for `cotal spawn -f` — the network half: a transient, invisible probe endpoint
|
|
3
|
-
* for reading the roster + membership feed, and the
|
|
4
|
-
* `launch`
|
|
5
|
-
*
|
|
3
|
+
* for reading the roster + membership feed, and the manager calls that drive the running manager's
|
|
4
|
+
* `launch`/`ps` — over the v0.4 ep rails (1c.2c): the deployer credential/view carries the
|
|
5
|
+
* tier-matched instrument rows (static = admin set; user-mode deployer view = privileged set + an
|
|
6
|
+
* owner-equality `launch` row, the manager's ledger-derived admin flag governs). (Channel-registry
|
|
6
7
|
* reads use `readChannelRegistry`, which connects itself.)
|
|
7
8
|
*/
|
|
8
|
-
import { CotalEndpoint, type ControlReply, type
|
|
9
|
+
import { CotalEndpoint, type ControlReply, type MeshLaunchSpec, type Presence } from "@cotal-ai/core";
|
|
9
10
|
export interface MeshConn {
|
|
10
11
|
space: string;
|
|
11
12
|
server: string;
|
|
12
13
|
creds?: string;
|
|
14
|
+
/** The deploy credential's v0.4 lifecycle uid (static: the instrument mint's; user: the
|
|
15
|
+
* bearer's ledger claim) — the probe endpoint's caller triple is keyed on it. */
|
|
16
|
+
lifecycleUid?: string;
|
|
13
17
|
/** User mode: the "deployer" VIEW material — a bearer SOURCE (a deploy spans several ≤5-min
|
|
14
18
|
* token lives across launch readiness waits) + sentinel + the pinned principal a source-mode
|
|
15
19
|
* endpoint requires. */
|
|
@@ -26,20 +30,21 @@ export declare function connectProbe(conn: MeshConn): Promise<CotalEndpoint>;
|
|
|
26
30
|
/** Let the presence KV replay settle (roster count steady across two polls, ≤1s), then snapshot the
|
|
27
31
|
* live peers — mirrors the dedup probe in `cotal spawn`. */
|
|
28
32
|
export declare function settleRoster(ep: CotalEndpoint): Promise<Presence[]>;
|
|
29
|
-
/** Poll the manager
|
|
30
|
-
* so it needs a moment to connect
|
|
31
|
-
* deploy credential
|
|
32
|
-
export declare function waitManagerReady(ep: CotalEndpoint, timeoutMs?: number
|
|
33
|
+
/** Poll the manager until it answers `ps` on the ep rails — it may have just been started
|
|
34
|
+
* detached, so it needs a moment to connect, register its service, and come up. Returns false on
|
|
35
|
+
* timeout. The deploy credential's instrument rows carry the read regardless of tier. */
|
|
36
|
+
export declare function waitManagerReady(ep: CotalEndpoint, timeoutMs?: number): Promise<boolean>;
|
|
33
37
|
/** Poll until the manager lease for this space is GONE (a crashed holder's key lingers until the bucket
|
|
34
38
|
* TTL). Returns true once absent, false on timeout. `spawn -f` uses this to wait out a STALE lease
|
|
35
39
|
* before standing up a replacement — a held lease alone is not proof a manager is alive. */
|
|
36
40
|
export declare function waitLeaseGone(ep: CotalEndpoint, timeoutMs: number): Promise<boolean>;
|
|
37
|
-
/** Ask the running manager to launch one resolved agent from the run spec —
|
|
38
|
-
* a static
|
|
39
|
-
*
|
|
40
|
-
*
|
|
41
|
-
* we pass the runId, never a path. When the
|
|
42
|
-
* `spec` and the resolved spec rides the
|
|
43
|
-
* untrusted input and persists it under its own
|
|
44
|
-
|
|
41
|
+
/** Ask the running manager to launch one resolved agent from the run spec — the v0.4 `launch`
|
|
42
|
+
* command, capability-only: a static deploy credential holds it via the admin instrument set (a
|
|
43
|
+
* spawn-capable agent holds no row at all), a user-mode deployer view holds the owner-equality
|
|
44
|
+
* variant (the manager's ledger-derived admin flag keeps spec-owner === caller-owner there). The
|
|
45
|
+
* manager derives `.cotal/run/<runId>.json` itself; we pass the runId, never a path. When the
|
|
46
|
+
* serving manager lives in ANOTHER checkout/host, pass `spec` and the resolved spec rides the
|
|
47
|
+
* control plane inline — the manager validates it as untrusted input and persists it under its own
|
|
48
|
+
* run tree before launching. */
|
|
49
|
+
export declare function launchAgent(ep: CotalEndpoint, runId: string, name: string, spec?: MeshLaunchSpec): Promise<ControlReply>;
|
|
45
50
|
//# sourceMappingURL=live.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"live.d.ts","sourceRoot":"","sources":["../../../src/lib/manifest/live.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"live.d.ts","sourceRoot":"","sources":["../../../src/lib/manifest/live.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,OAAO,EAAE,aAAa,EAAmB,KAAK,YAAY,EAAE,KAAK,cAAc,EAAE,KAAK,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAGvH,MAAM,WAAW,QAAQ;IACvB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;IACf;sFACkF;IAClF,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB;;6BAEyB;IACzB,IAAI,CAAC,EAAE;QAAE,MAAM,EAAE,MAAM,OAAO,CAAC,MAAM,CAAC,CAAC;QAAC,aAAa,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC;CAC/F;AAID;4EAC4E;AAC5E,wBAAsB,YAAY,CAAC,IAAI,EAAE,QAAQ,GAAG,OAAO,CAAC,aAAa,CAAC,CAoBzE;AAED;6DAC6D;AAC7D,wBAAsB,YAAY,CAAC,EAAE,EAAE,aAAa,GAAG,OAAO,CAAC,QAAQ,EAAE,CAAC,CASzE;AAED;;0FAE0F;AAC1F,wBAAsB,gBAAgB,CAAC,EAAE,EAAE,aAAa,EAAE,SAAS,SAAS,GAAG,OAAO,CAAC,OAAO,CAAC,CAY9F;AAED;;6FAE6F;AAC7F,wBAAsB,aAAa,CAAC,EAAE,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAO1F;AAED;;;;;;;iCAOiC;AACjC,wBAAsB,WAAW,CAAC,EAAE,EAAE,aAAa,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,cAAc,GAAG,OAAO,CAAC,YAAY,CAAC,CAY9H"}
|