@cotal-ai/cli 0.11.3 → 0.11.4
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/command.d.ts.map +1 -1
- package/dist/command.js +58 -0
- package/dist/command.js.map +1 -1
- package/dist/commands/ext.d.ts +6 -0
- package/dist/commands/ext.d.ts.map +1 -1
- package/dist/commands/ext.js +50 -47
- package/dist/commands/ext.js.map +1 -1
- package/dist/commands/models.d.ts.map +1 -1
- package/dist/commands/models.js +3 -2
- package/dist/commands/models.js.map +1 -1
- package/dist/commands/setup.d.ts.map +1 -1
- package/dist/commands/setup.js +24 -7
- package/dist/commands/setup.js.map +1 -1
- package/dist/commands/spawn-manifest.js +1 -1
- package/dist/commands/spawn-manifest.js.map +1 -1
- package/dist/commands/spawn.d.ts +7 -1
- package/dist/commands/spawn.d.ts.map +1 -1
- package/dist/commands/spawn.js +11 -0
- package/dist/commands/spawn.js.map +1 -1
- package/dist/commands/up.d.ts +2 -0
- package/dist/commands/up.d.ts.map +1 -1
- package/dist/commands/up.js +14 -5
- package/dist/commands/up.js.map +1 -1
- package/dist/ext-loader.d.ts +3 -1
- package/dist/ext-loader.d.ts.map +1 -1
- package/dist/ext-loader.js +13 -62
- package/dist/ext-loader.js.map +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +9 -3
- package/dist/index.js.map +1 -1
- package/dist/lib/auth-proc.d.ts.map +1 -1
- package/dist/lib/auth-proc.js +3 -0
- package/dist/lib/auth-proc.js.map +1 -1
- package/dist/lib/delivery-proc.d.ts.map +1 -1
- package/dist/lib/delivery-proc.js +3 -1
- package/dist/lib/delivery-proc.js.map +1 -1
- package/dist/lib/ext-mutation.d.ts +17 -0
- package/dist/lib/ext-mutation.d.ts.map +1 -0
- package/dist/lib/ext-mutation.js +23 -0
- package/dist/lib/ext-mutation.js.map +1 -0
- package/dist/lib/manager-proc.d.ts.map +1 -1
- package/dist/lib/manager-proc.js +3 -1
- package/dist/lib/manager-proc.js.map +1 -1
- package/dist/lib/manifest/apply.d.ts +4 -3
- package/dist/lib/manifest/apply.d.ts.map +1 -1
- package/dist/lib/manifest/apply.js +9 -7
- package/dist/lib/manifest/apply.js.map +1 -1
- package/dist/lib/up-report.d.ts +9 -0
- package/dist/lib/up-report.d.ts.map +1 -0
- package/dist/lib/up-report.js +12 -0
- package/dist/lib/up-report.js.map +1 -0
- package/dist/seed/authority.d.ts +54 -0
- package/dist/seed/authority.d.ts.map +1 -0
- package/dist/seed/authority.js +94 -0
- package/dist/seed/authority.js.map +1 -0
- package/dist/seed/lock.d.ts +109 -0
- package/dist/seed/lock.d.ts.map +1 -0
- package/dist/seed/lock.js +168 -0
- package/dist/seed/lock.js.map +1 -0
- package/dist/seed/paths.d.ts +66 -0
- package/dist/seed/paths.d.ts.map +1 -0
- package/dist/seed/paths.js +149 -0
- package/dist/seed/paths.js.map +1 -0
- package/dist/seed/reconcile.d.ts +16 -0
- package/dist/seed/reconcile.d.ts.map +1 -0
- package/dist/seed/reconcile.js +431 -0
- package/dist/seed/reconcile.js.map +1 -0
- package/dist/seed/store.d.ts +18 -0
- package/dist/seed/store.d.ts.map +1 -0
- package/dist/seed/store.js +58 -0
- package/dist/seed/store.js.map +1 -0
- package/package.json +3 -3
|
@@ -0,0 +1,431 @@
|
|
|
1
|
+
import { existsSync, readFileSync, renameSync } from "node:fs";
|
|
2
|
+
import { spawnSync } from "node:child_process";
|
|
3
|
+
import { randomBytes } from "node:crypto";
|
|
4
|
+
import { join } from "node:path";
|
|
5
|
+
import { OFFICIAL_CONNECTORS, extensionPackageDir, installedExtensionVersion, loadExtensionsManifest, quarantineExtensionsManifest, } from "@cotal-ai/workspace";
|
|
6
|
+
import { c } from "../ui.js";
|
|
7
|
+
import { selfArgv } from "../lib/self-exec.js";
|
|
8
|
+
import { claimExtensionMutation } from "../lib/ext-mutation.js";
|
|
9
|
+
import { SEED_BUILTINS, seedGeneration, stampPath } from "./paths.js";
|
|
10
|
+
import { acquireReconcileLock, clearChildMarker, clearCursor, clearRecovery, readCursor, readRecovery, reconcileLockActive, recoveryPending, sanitizeCorruptCrashState, seedChildStatus, writeCursor, writePendingChildMarker, writeRecovery, } from "./lock.js";
|
|
11
|
+
import { ensureWitness, everSeededUnion, quarantineCorruptSeedState, readAuthority, readStamp, readWitness, recoverAuthorityFromBackup, writeAuthority, writeStamp, } from "./authority.js";
|
|
12
|
+
import { gcSeedStore, stageSeedPayload } from "./store.js";
|
|
13
|
+
/** Auto reconcile for the boot gate: silent no-op when the stamp is current and healthy. */
|
|
14
|
+
export async function reconcileSeededConnectors() {
|
|
15
|
+
await reconcile("auto");
|
|
16
|
+
}
|
|
17
|
+
/** `cotal ext seed [--repair|--reset|--force]`: the maintenance entry. Prints a summary. */
|
|
18
|
+
export async function runSeed(flags) {
|
|
19
|
+
const mode = flags.reset ? "reset" : flags.repair ? "repair" : flags.force ? "force" : "auto";
|
|
20
|
+
const result = await reconcile(mode);
|
|
21
|
+
if (result.noop) {
|
|
22
|
+
console.log(c.green("✓ built-in connectors up to date"));
|
|
23
|
+
return;
|
|
24
|
+
}
|
|
25
|
+
const parts = [];
|
|
26
|
+
if (result.seeded.length)
|
|
27
|
+
parts.push(`seeded ${result.seeded.join(", ")}`);
|
|
28
|
+
if (result.refreshed.length)
|
|
29
|
+
parts.push(`refreshed ${result.refreshed.join(", ")}`);
|
|
30
|
+
if (result.removedKept.length)
|
|
31
|
+
parts.push(`kept removed ${result.removedKept.join(", ")}`);
|
|
32
|
+
console.log(c.green(`✓ connectors reconciled`) + (parts.length ? c.dim(` - ${parts.join("; ")}`) : ""));
|
|
33
|
+
}
|
|
34
|
+
const NOOP = { noop: true, seeded: [], refreshed: [], removedKept: [] };
|
|
35
|
+
async function reconcile(mode) {
|
|
36
|
+
const generation = seedGeneration();
|
|
37
|
+
// Cheap lock-free pre-check: the steady state (stamp current, authority intact) is the common case
|
|
38
|
+
// on EVERY command and must not pay a lock acquire. Health checks run FIRST so a lost authority or a
|
|
39
|
+
// crashed reconcile is caught before the stamp is trusted.
|
|
40
|
+
if (mode === "auto") {
|
|
41
|
+
const cursor = readCursor();
|
|
42
|
+
// A crash cursor OR an outstanding maintenance-recovery obligation means a seed/repair was
|
|
43
|
+
// interrupted. A LIVE lock holder ⇒ it is in flight: fall through and WAIT on the lock, then
|
|
44
|
+
// re-check the fast path (it will have stamped). No live holder ⇒ it crashed → fail loud.
|
|
45
|
+
if (cursor || recoveryPending()) {
|
|
46
|
+
if (!reconcileLockActive()) {
|
|
47
|
+
const child = seedChildStatus();
|
|
48
|
+
if (child.kind === "live")
|
|
49
|
+
throw new Error(`a connector seed child (pid ${child.pid}) is still installing - retry once it finishes`);
|
|
50
|
+
if (child.kind === "ambiguous")
|
|
51
|
+
throw new Error(`a connector seed may be mid-flight (marker ${child.path}) - if no cotal process is running, remove it, then run \`cotal ext seed --repair\``);
|
|
52
|
+
throw new Error("a previous connector seed or repair was interrupted - run `cotal ext seed --repair`");
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
else if (readWitness() && authorityIntact() && readStamp()?.generation === generation && !reconcileLockActive()) {
|
|
56
|
+
// Steady state AND no reconcile in flight. The lock check is LAST (immediately before NOOP) so
|
|
57
|
+
// it is the linearization point: a `--force` that link-publishes the lock during the slower
|
|
58
|
+
// health/stamp reads is still caught here, and we fall through to acquire/wait rather than
|
|
59
|
+
// racing past into the command while it mutates the prefix.
|
|
60
|
+
return NOOP;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
const lock = acquireReconcileLock();
|
|
64
|
+
try {
|
|
65
|
+
// Claim the mutation lock INSIDE the reconcile lock's finally: if it throws (an operator `cotal
|
|
66
|
+
// ext` op holds it past the wait), the reconcile lock is still released, not leaked. The reconcile
|
|
67
|
+
// takes a modest bounded wait (a brief operator op shouldn't fail the boot-gate); operators
|
|
68
|
+
// themselves fail fast.
|
|
69
|
+
const releaseMutation = claimExtensionMutation({ waitMs: 30000 });
|
|
70
|
+
try {
|
|
71
|
+
return await runUnderLocks(mode, generation, lock.nonce);
|
|
72
|
+
}
|
|
73
|
+
finally {
|
|
74
|
+
releaseMutation();
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
finally {
|
|
78
|
+
lock.release();
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
/** Authority present, readable, and structurally valid (a corrupt one is NOT intact — it routes to
|
|
82
|
+
* the fail-loud path). */
|
|
83
|
+
function authorityIntact() {
|
|
84
|
+
try {
|
|
85
|
+
return readAuthority() !== undefined;
|
|
86
|
+
}
|
|
87
|
+
catch {
|
|
88
|
+
return false;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
async function runUnderLocks(mode, generation, nonce) {
|
|
92
|
+
// Refuse to touch the prefix while an orphaned seed child (a crashed parent's still-running
|
|
93
|
+
// installer) is mutating it — reclaiming the lock does not stop that process. An ambiguous marker
|
|
94
|
+
// (pending with a dead parent, or corrupt) is fail-loud: we cannot prove no installer is running.
|
|
95
|
+
const child = seedChildStatus();
|
|
96
|
+
if (child.kind === "live")
|
|
97
|
+
throw new Error(`a connector seed child (pid ${child.pid}) is still installing - retry once it finishes`);
|
|
98
|
+
if (child.kind === "ambiguous")
|
|
99
|
+
throw new Error(`a connector seed may be mid-flight (marker ${child.path}) - if no cotal process is running, remove it and retry`);
|
|
100
|
+
// Maintenance modes must survive a corrupt manifest / corrupt seed state: quarantine the unreadable
|
|
101
|
+
// file(s) aside so the reads below (and the commit) can't wedge on them. `manifestRebuilt` ⇒ reconcile
|
|
102
|
+
// against ON-DISK truth (a quarantined manifest has no reliable "removed" record); `repairAllSeeded`
|
|
103
|
+
// ⇒ an unidentifiable interrupted install → reinstall every seeded built-in. Both obligations are
|
|
104
|
+
// journaled durably by prepareMaintenanceState (recovery marker) so a repair SIGKILL after the
|
|
105
|
+
// quarantine still honors them on the next run.
|
|
106
|
+
let manifestRebuilt = false;
|
|
107
|
+
let repairAllSeeded = false;
|
|
108
|
+
if (mode === "repair" || mode === "reset") {
|
|
109
|
+
({ manifestRebuilt, repairAllSeeded } = prepareMaintenanceState(mode));
|
|
110
|
+
}
|
|
111
|
+
// Health preamble — BEFORE the stamp fast path. A cursor OR a recovery obligation means a prior
|
|
112
|
+
// seed/repair was interrupted. In maintenance mode they are kept and cleared only at the final commit.
|
|
113
|
+
const cursor = readCursor();
|
|
114
|
+
if (cursor) {
|
|
115
|
+
if (mode === "auto")
|
|
116
|
+
throw new Error(`a previous connector seed was interrupted (package "${cursor.package}", phase ${cursor.phase}) - run \`cotal ext seed --repair\``);
|
|
117
|
+
console.error(c.dim(`recovering from an interrupted seed (package "${cursor.package}") …`));
|
|
118
|
+
}
|
|
119
|
+
if (mode === "auto" && !cursor && recoveryPending())
|
|
120
|
+
throw new Error("a previous connector repair was interrupted - run `cotal ext seed --repair`");
|
|
121
|
+
const everSeeded = resolveEverSeeded(mode, generation);
|
|
122
|
+
// Stamp fast path under the lock: a competing boot may have reconciled while we waited. Only when no
|
|
123
|
+
// cursor or recovery obligation is outstanding (an interrupted run must proceed, not short-circuit).
|
|
124
|
+
if (mode === "auto" && !cursor && !recoveryPending() && readWitness() && readStamp()?.generation === generation)
|
|
125
|
+
return NOOP;
|
|
126
|
+
const stampGen = readStamp()?.generation;
|
|
127
|
+
const repairTarget = mode === "repair" ? cursor?.package : undefined;
|
|
128
|
+
const seeded = [];
|
|
129
|
+
const refreshed = [];
|
|
130
|
+
const removedKept = [];
|
|
131
|
+
for (const name of SEED_BUILTINS) {
|
|
132
|
+
const entry = installedEntry(name);
|
|
133
|
+
const wasSeeded = everSeeded.has(name) && mode !== "reset";
|
|
134
|
+
if (name === repairTarget) {
|
|
135
|
+
// The interrupted package (the cursor only ever names an ADD in progress — removals never write
|
|
136
|
+
// it): re-install it regardless of current manifest state, whether the crash tore the files or
|
|
137
|
+
// died before the manifest commit. Verified below before the cursor is cleared.
|
|
138
|
+
seedOne(name, generation, nonce, true);
|
|
139
|
+
verifyInstalled(name);
|
|
140
|
+
everSeeded.add(name);
|
|
141
|
+
refreshed.push(name);
|
|
142
|
+
}
|
|
143
|
+
else if (!wasSeeded) {
|
|
144
|
+
seedOne(name, generation, nonce, mode === "reset" || mode === "force");
|
|
145
|
+
everSeeded.add(name);
|
|
146
|
+
seeded.push(name);
|
|
147
|
+
}
|
|
148
|
+
else if (entry) {
|
|
149
|
+
// Refresh policy: any --force; for connectors WE seeded (source === "seeded") a strictly-newer
|
|
150
|
+
// generation; on an unknown-cursor --repair (repairAllSeeded) every seeded built-in; and on an
|
|
151
|
+
// ordinary --repair a seeded entry that is not fully intact on disk (a partial tear — main may
|
|
152
|
+
// survive while a required file is gone). An operator-managed official entry (no seeded marker)
|
|
153
|
+
// is never auto-refreshed on upgrade — only --force may replace it.
|
|
154
|
+
const isSeeded = entry.source === "seeded";
|
|
155
|
+
const torn = mode === "repair" && isSeeded && (repairAllSeeded || !isIntact(name));
|
|
156
|
+
const refresh = mode === "force" || torn || (isSeeded && isStrictlyNewer(generation, stampGen));
|
|
157
|
+
if (refresh) {
|
|
158
|
+
seedOne(name, generation, nonce, true);
|
|
159
|
+
verifyInstalled(name);
|
|
160
|
+
refreshed.push(name);
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
else if (manifestRebuilt && installedExtensionVersion(OFFICIAL_CONNECTORS[name])) {
|
|
164
|
+
// The manifest was corrupt and quarantined, but this connector is STILL on disk: its entry was
|
|
165
|
+
// lost with the manifest, not removed. Re-seed it to rebuild the record (a quarantined manifest
|
|
166
|
+
// carries no reliable "removed" fact — only on-disk presence can distinguish the two).
|
|
167
|
+
seedOne(name, generation, nonce, true);
|
|
168
|
+
verifyInstalled(name);
|
|
169
|
+
refreshed.push(name);
|
|
170
|
+
}
|
|
171
|
+
else {
|
|
172
|
+
removedKept.push(name); // seeded before, deliberately removed (or absent on disk) → leave removed
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
// Commit: authority (+ backup) → witness → stamp (LAST); THEN drop the cursor + recovery obligation
|
|
176
|
+
// and GC old stores. The cursor and recovery marker are cleared only here, so an interruption
|
|
177
|
+
// anywhere above (including a repair that quarantined then died mid-reinstall) is still a detectable,
|
|
178
|
+
// recoverable partial run on the next boot.
|
|
179
|
+
writeAuthority(everSeeded);
|
|
180
|
+
ensureWitness(generation);
|
|
181
|
+
writeStamp(generation);
|
|
182
|
+
clearCursor();
|
|
183
|
+
clearRecovery();
|
|
184
|
+
gcSeedStore(generation, loadExtensionsManifest().extensions.map((e) => e.spec));
|
|
185
|
+
return { noop: false, seeded, refreshed, removedKept };
|
|
186
|
+
}
|
|
187
|
+
/** Quarantine any corrupt manifest / seed-state so a maintenance run rebuilds clean instead of wedging
|
|
188
|
+
* on the same unreadable read, and DURABLY journal the resulting obligation BEFORE the destructive
|
|
189
|
+
* quarantine — so a repair SIGKILL'd after the quarantine but before the reinstalls doesn't forget it.
|
|
190
|
+
* `manifestRebuilt` ⇒ reconcile the built-ins against ON-DISK truth; `repairAllSeeded` ⇒ reinstall +
|
|
191
|
+
* verify every seeded built-in (an unidentifiable interrupted install). Both are UNIONED with any
|
|
192
|
+
* obligation a prior crashed maintenance already recorded. Third-party entries in an unrecoverable
|
|
193
|
+
* manifest are lost — reported, not silently dropped. */
|
|
194
|
+
function prepareMaintenanceState(mode) {
|
|
195
|
+
// Re-derive from BOTH a prior crashed maintenance's durable obligation and the current on-disk state.
|
|
196
|
+
const prior = (() => {
|
|
197
|
+
try {
|
|
198
|
+
return readRecovery();
|
|
199
|
+
}
|
|
200
|
+
catch {
|
|
201
|
+
return { rebuildFromDisk: true, repairAllSeeded: true }; // corrupt marker ⇒ recover conservatively
|
|
202
|
+
}
|
|
203
|
+
})();
|
|
204
|
+
let manifestRebuilt = prior?.rebuildFromDisk ?? false;
|
|
205
|
+
let repairAllSeeded = prior?.repairAllSeeded ?? false;
|
|
206
|
+
const manifestCorrupt = (() => {
|
|
207
|
+
try {
|
|
208
|
+
loadExtensionsManifest();
|
|
209
|
+
return false;
|
|
210
|
+
}
|
|
211
|
+
catch {
|
|
212
|
+
return true;
|
|
213
|
+
}
|
|
214
|
+
})();
|
|
215
|
+
const cursorCorrupt = (() => {
|
|
216
|
+
try {
|
|
217
|
+
readCursor();
|
|
218
|
+
return false;
|
|
219
|
+
}
|
|
220
|
+
catch {
|
|
221
|
+
return true;
|
|
222
|
+
}
|
|
223
|
+
})();
|
|
224
|
+
manifestRebuilt = manifestRebuilt || manifestCorrupt;
|
|
225
|
+
repairAllSeeded = repairAllSeeded || cursorCorrupt;
|
|
226
|
+
// Persist the obligation BEFORE any destructive quarantine below, so a crash in between still leaves
|
|
227
|
+
// a durable record the next run honors.
|
|
228
|
+
if (manifestRebuilt || repairAllSeeded)
|
|
229
|
+
writeRecovery({ rebuildFromDisk: manifestRebuilt, repairAllSeeded });
|
|
230
|
+
if (manifestCorrupt) {
|
|
231
|
+
const aside = quarantineExtensionsManifest();
|
|
232
|
+
if (aside)
|
|
233
|
+
console.error(c.red(`quarantined a corrupt extensions manifest → ${aside}`) +
|
|
234
|
+
c.dim(" (any third-party extensions it recorded must be `cotal ext add`ed again)"));
|
|
235
|
+
}
|
|
236
|
+
for (const aside of sanitizeCorruptCrashState())
|
|
237
|
+
console.error(c.dim(`quarantined a corrupt seed cursor → ${aside}`));
|
|
238
|
+
// A stamp that is corrupt JSON, OR parses but is not valid semver (e.g. `0.bad.0`), makes the refresh
|
|
239
|
+
// comparison throw — an auto boot then prescribes `--repair` and `--repair`/`--reset` re-throw the
|
|
240
|
+
// SAME error forever (readStamp itself throws on corrupt JSON). Detect BOTH here, BEFORE any semver
|
|
241
|
+
// use, and move the stamp aside so repair treats the prior generation as unknown (older), refreshes
|
|
242
|
+
// and verifies, and writes a fresh valid stamp.
|
|
243
|
+
let stampBad = false;
|
|
244
|
+
try {
|
|
245
|
+
const stamp = readStamp();
|
|
246
|
+
stampBad = stamp !== undefined && !isValidSemver(stamp.generation);
|
|
247
|
+
}
|
|
248
|
+
catch {
|
|
249
|
+
stampBad = true; // corrupt JSON
|
|
250
|
+
}
|
|
251
|
+
if (stampBad && existsSync(stampPath())) {
|
|
252
|
+
const aside = `${stampPath()}.corrupt.${randomBytes(4).toString("hex")}`;
|
|
253
|
+
renameSync(stampPath(), aside);
|
|
254
|
+
console.error(c.dim(`quarantined an invalid version stamp → ${aside}`));
|
|
255
|
+
}
|
|
256
|
+
if (mode === "reset") {
|
|
257
|
+
for (const aside of quarantineCorruptSeedState())
|
|
258
|
+
console.error(c.dim(`quarantined corrupt seed state → ${aside}`));
|
|
259
|
+
}
|
|
260
|
+
return { manifestRebuilt, repairAllSeeded };
|
|
261
|
+
}
|
|
262
|
+
/** True iff `v` parses as a numeric-core semver (the only thing the refresh comparison can order). */
|
|
263
|
+
function isValidSemver(v) {
|
|
264
|
+
try {
|
|
265
|
+
parseSemver(v);
|
|
266
|
+
return true;
|
|
267
|
+
}
|
|
268
|
+
catch {
|
|
269
|
+
return false;
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
/**
|
|
273
|
+
* The ever-seeded set to reconcile against, per the prefix state and the mode. Pristine/legacy
|
|
274
|
+
* prefixes initialize it; a witnessed prefix with a lost authority is fail-loud in auto/force,
|
|
275
|
+
* recoverable via `--repair`, and reset-to-defaults via `--reset`.
|
|
276
|
+
*/
|
|
277
|
+
function resolveEverSeeded(mode, generation) {
|
|
278
|
+
if (mode === "reset")
|
|
279
|
+
return new Set(); // recreate defaults: every built-in becomes never-seeded
|
|
280
|
+
const witness = readWitness();
|
|
281
|
+
if (!witness) {
|
|
282
|
+
// No witness: a pristine prefix (nothing installed) or a legacy one (extensions predating the
|
|
283
|
+
// seeder). Mark any OFFICIAL connector already in the manifest as seeded so a manually-added one
|
|
284
|
+
// is not re-seeded; a static-import-era prefix has none, so all four seed fresh.
|
|
285
|
+
return new Set(loadExtensionsManifest()
|
|
286
|
+
.extensions.map((e) => officialNameOfPkg(e.pkg))
|
|
287
|
+
.filter((n) => !!n));
|
|
288
|
+
}
|
|
289
|
+
// Union the live authority with its monotonic backup: a live set that lost ids (a truncated write
|
|
290
|
+
// that still parsed) can only shrink, and the backup is a superset, so a removed connector is never
|
|
291
|
+
// resurrected by such a loss.
|
|
292
|
+
let merged;
|
|
293
|
+
try {
|
|
294
|
+
merged = everSeededUnion();
|
|
295
|
+
}
|
|
296
|
+
catch {
|
|
297
|
+
merged = undefined; // corrupt → treated as lost below
|
|
298
|
+
}
|
|
299
|
+
if (merged)
|
|
300
|
+
return merged;
|
|
301
|
+
// Witness present but authority (and backup) lost.
|
|
302
|
+
if (mode === "repair") {
|
|
303
|
+
const recovered = recoverAuthorityFromBackup();
|
|
304
|
+
if (!recovered)
|
|
305
|
+
throw new Error("connector seed authority is lost and no backup remains - removed-vs-never-seeded is unrecoverable; `cotal ext seed --reset` recreates defaults (this resurrects any deliberately-removed connector)");
|
|
306
|
+
console.error(c.dim("recovered the seed authority from its backup"));
|
|
307
|
+
return recovered;
|
|
308
|
+
}
|
|
309
|
+
throw new Error("connector seed authority is missing or corrupt - `cotal ext seed --repair` recovers it from the durable backup, or `--reset` recreates defaults (resurrecting removed connectors)");
|
|
310
|
+
}
|
|
311
|
+
/** Stage the payload and `ext add` it as a seed child, journaling the crash cursor around each step.
|
|
312
|
+
* The child is authenticated: it carries the live reconcile lock's nonce + this parent's PID so a
|
|
313
|
+
* forged `COTAL_EXT_SEEDING` can't skip the mutation lock for an arbitrary `ext add`. */
|
|
314
|
+
function seedOne(name, generation, nonce, force) {
|
|
315
|
+
writeCursor({ nonce, package: name, phase: "copy" });
|
|
316
|
+
const storePath = stageSeedPayload(generation, name, { force });
|
|
317
|
+
writeCursor({ nonce, package: name, phase: "add" });
|
|
318
|
+
// Record intent to spawn BEFORE the spawn, so the orphan window never opens ownerless: a repair
|
|
319
|
+
// after a parent SIGKILL sees this pending marker and fails loud rather than racing the installer.
|
|
320
|
+
writePendingChildMarker(nonce);
|
|
321
|
+
const [bin, ...argv] = selfArgv();
|
|
322
|
+
const r = spawnSync(bin, [...argv, "ext", "add", storePath], {
|
|
323
|
+
encoding: "utf8",
|
|
324
|
+
env: { ...process.env, COTAL_EXT_SEEDING: nonce, COTAL_EXT_SEEDING_PARENT: String(process.pid) },
|
|
325
|
+
});
|
|
326
|
+
clearChildMarker(); // parent survived the child: the marker's job is done (child also clears its own)
|
|
327
|
+
if (r.stdout)
|
|
328
|
+
process.stdout.write(r.stdout);
|
|
329
|
+
if (r.status !== 0) {
|
|
330
|
+
const tail = `${r.stderr ?? ""}`.trim().split("\n").slice(-8).join("\n");
|
|
331
|
+
throw new Error(`failed to seed connector "${name}" from ${storePath}:\n${tail}`);
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
/** Confirm a connector the reconcile claims to have (re)installed is recorded AND on disk with its
|
|
335
|
+
* entry file resolvable — so `--repair` can never clear the cursor and stamp success over a
|
|
336
|
+
* half-installed prefix (a surviving package.json with a missing main is still broken). */
|
|
337
|
+
function verifyInstalled(name) {
|
|
338
|
+
const pkg = OFFICIAL_CONNECTORS[name];
|
|
339
|
+
const entry = installedEntry(name);
|
|
340
|
+
if (!entry)
|
|
341
|
+
throw new Error(`connector "${name}" (${pkg}) was expected in the manifest after seeding but is absent - rerun \`cotal ext seed --repair\``);
|
|
342
|
+
if (!installedExtensionVersion(pkg))
|
|
343
|
+
throw new Error(`connector "${name}" (${pkg}) is recorded but not installed on disk - rerun \`cotal ext seed --repair\``);
|
|
344
|
+
if (!mainEntryPresent(pkg))
|
|
345
|
+
throw new Error(`connector "${name}" (${pkg}) is installed but its entry file is missing (a torn install) - rerun \`cotal ext seed --repair\``);
|
|
346
|
+
}
|
|
347
|
+
/** The package's declared main entry file exists on disk (`main`, else the CommonJS default). Used to
|
|
348
|
+
* detect a torn install where package.json survived a partial npm copy but the built dist did not. */
|
|
349
|
+
function mainEntryPresent(pkg) {
|
|
350
|
+
const dir = extensionPackageDir(pkg);
|
|
351
|
+
let main = "index.js";
|
|
352
|
+
try {
|
|
353
|
+
const declared = JSON.parse(readFileSync(join(dir, "package.json"), "utf8")).main;
|
|
354
|
+
if (typeof declared === "string" && declared)
|
|
355
|
+
main = declared;
|
|
356
|
+
}
|
|
357
|
+
catch {
|
|
358
|
+
return false; // package.json unreadable ⇒ not intact
|
|
359
|
+
}
|
|
360
|
+
return existsSync(join(dir, main));
|
|
361
|
+
}
|
|
362
|
+
/** A seeded built-in is fully intact: recorded on disk (package.json + version) AND its main entry
|
|
363
|
+
* file present. A partial tear (main gone, package.json kept) is NOT intact. */
|
|
364
|
+
function isIntact(name) {
|
|
365
|
+
const pkg = OFFICIAL_CONNECTORS[name];
|
|
366
|
+
return installedExtensionVersion(pkg) !== undefined && mainEntryPresent(pkg);
|
|
367
|
+
}
|
|
368
|
+
function installedEntry(name) {
|
|
369
|
+
const pkg = OFFICIAL_CONNECTORS[name];
|
|
370
|
+
return loadExtensionsManifest().extensions.find((e) => e.pkg === pkg);
|
|
371
|
+
}
|
|
372
|
+
function officialNameOfPkg(pkg) {
|
|
373
|
+
return SEED_BUILTINS.find((name) => OFFICIAL_CONNECTORS[name] === pkg);
|
|
374
|
+
}
|
|
375
|
+
/** A DOWNGRADE never rewrites installed connector code without `--force`; an absent prior stamp counts
|
|
376
|
+
* as older, so an upgrade from an un-stamped prefix refreshes. Semver 2.0 precedence (prerelease
|
|
377
|
+
* ordering included), so `1.0.0-rc.1` < `1.0.0` and `1.0.10` > `1.0.9`. */
|
|
378
|
+
function isStrictlyNewer(a, b) {
|
|
379
|
+
return compareSemver(a, b ?? "0.0.0") > 0;
|
|
380
|
+
}
|
|
381
|
+
function parseSemver(v) {
|
|
382
|
+
const core = v.split("+")[0];
|
|
383
|
+
const dash = core.indexOf("-");
|
|
384
|
+
const pre = dash >= 0 ? core.slice(dash + 1).split(".") : [];
|
|
385
|
+
// Fail loud on a non-numeric release segment rather than coercing it to 0 (which would silently
|
|
386
|
+
// mis-order versions). The generation is a real package.json version and the stamp is one we wrote,
|
|
387
|
+
// so a non-semver core here means corrupt state → `cotal ext seed --repair`/`--reset`.
|
|
388
|
+
const release = (dash >= 0 ? core.slice(0, dash) : core).split(".").map((s) => {
|
|
389
|
+
if (!/^\d+$/.test(s))
|
|
390
|
+
throw new Error(`invalid version "${v}" (release segment "${s}" is not numeric) - repair with \`cotal ext seed --repair\` (or --reset)`);
|
|
391
|
+
return Number(s);
|
|
392
|
+
});
|
|
393
|
+
return { rel: [release[0] ?? 0, release[1] ?? 0, release[2] ?? 0], pre };
|
|
394
|
+
}
|
|
395
|
+
function compareSemver(a, b) {
|
|
396
|
+
const pa = parseSemver(a);
|
|
397
|
+
const pb = parseSemver(b);
|
|
398
|
+
for (let i = 0; i < 3; i++) {
|
|
399
|
+
if (pa.rel[i] !== pb.rel[i])
|
|
400
|
+
return pa.rel[i] > pb.rel[i] ? 1 : -1;
|
|
401
|
+
}
|
|
402
|
+
// A release (no prerelease) outranks a prerelease of the same core version.
|
|
403
|
+
if (!pa.pre.length && pb.pre.length)
|
|
404
|
+
return 1;
|
|
405
|
+
if (pa.pre.length && !pb.pre.length)
|
|
406
|
+
return -1;
|
|
407
|
+
const n = Math.max(pa.pre.length, pb.pre.length);
|
|
408
|
+
for (let i = 0; i < n; i++) {
|
|
409
|
+
const x = pa.pre[i];
|
|
410
|
+
const y = pb.pre[i];
|
|
411
|
+
if (x === undefined)
|
|
412
|
+
return -1; // fewer prerelease fields ⇒ lower precedence
|
|
413
|
+
if (y === undefined)
|
|
414
|
+
return 1;
|
|
415
|
+
const xn = /^\d+$/.test(x);
|
|
416
|
+
const yn = /^\d+$/.test(y);
|
|
417
|
+
if (xn && yn) {
|
|
418
|
+
const d = Number(x) - Number(y);
|
|
419
|
+
if (d !== 0)
|
|
420
|
+
return d > 0 ? 1 : -1;
|
|
421
|
+
}
|
|
422
|
+
else if (xn)
|
|
423
|
+
return -1; // numeric identifiers rank below alphanumeric
|
|
424
|
+
else if (yn)
|
|
425
|
+
return 1;
|
|
426
|
+
else if (x !== y)
|
|
427
|
+
return x < y ? -1 : 1;
|
|
428
|
+
}
|
|
429
|
+
return 0;
|
|
430
|
+
}
|
|
431
|
+
//# sourceMappingURL=reconcile.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"reconcile.js","sourceRoot":"","sources":["../../src/seed/reconcile.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Stage a built-in connector's shipped payload into `store/<generation>/<name>` and return that
|
|
3
|
+
* stable path (the spec `ext add` installs from). Idempotent: an intact prior copy is reused unless
|
|
4
|
+
* `force` re-materializes it (a `--force`/`--reset` repair). The copy is staged into a sibling temp
|
|
5
|
+
* dir and renamed into place, so a crash mid-copy never leaves a half-written payload at the final
|
|
6
|
+
* path for a later run to `ext add` from.
|
|
7
|
+
*/
|
|
8
|
+
export declare function stageSeedPayload(generation: string, name: string, opts?: {
|
|
9
|
+
force?: boolean;
|
|
10
|
+
}): string;
|
|
11
|
+
/**
|
|
12
|
+
* GC seed-store generations other than `keepGeneration`, but ONLY those no live manifest entry still
|
|
13
|
+
* installs from (its normalized `file:` spec points under the generation dir). This is the commit
|
|
14
|
+
* predicate: a prior generation is removed only after every seeded entry has been re-added from the
|
|
15
|
+
* new one, so a running manager never loses the bytes its connectors resolve.
|
|
16
|
+
*/
|
|
17
|
+
export declare function gcSeedStore(keepGeneration: string, referencedSpecs: readonly string[]): void;
|
|
18
|
+
//# sourceMappingURL=store.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"store.d.ts","sourceRoot":"","sources":["../../src/seed/store.ts"],"names":[],"mappings":"AAqBA;;;;;;GAMG;AACH,wBAAgB,gBAAgB,CAAC,UAAU,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,GAAE;IAAE,KAAK,CAAC,EAAE,OAAO,CAAA;CAAO,GAAG,MAAM,CAWzG;AAED;;;;;GAKG;AACH,wBAAgB,WAAW,CAAC,cAAc,EAAE,MAAM,EAAE,eAAe,EAAE,SAAS,MAAM,EAAE,GAAG,IAAI,CAS5F"}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { cpSync, existsSync, mkdirSync, readdirSync, renameSync, rmSync } from "node:fs";
|
|
2
|
+
import { dirname, join, relative, sep } from "node:path";
|
|
3
|
+
import { seedStoreDir, seedStorePath, shippedSourceDir } from "./paths.js";
|
|
4
|
+
/**
|
|
5
|
+
* The durable seed store: a stable, per-generation copy of each shipped connector payload that
|
|
6
|
+
* `ext add --install-links` can normalize a `file:` dep against (a volatile `npx` source would later
|
|
7
|
+
* fail to reify). One directory per generation keeps an in-flight refresh from clobbering the bytes a
|
|
8
|
+
* running manager's connectors still resolve; the old generation is GC'd only once nothing references
|
|
9
|
+
* it.
|
|
10
|
+
*/
|
|
11
|
+
/** Everything except a nested `node_modules` (npm resolves deps fresh; peers are junction-linked by
|
|
12
|
+
* the `ext add` path) and VCS metadata. The exclusion is RELATIVE to the payload root — a published
|
|
13
|
+
* connector lives UNDER `.../node_modules/cotal-ai/seeded-connectors/<name>`, so matching
|
|
14
|
+
* `node_modules` anywhere in the absolute path would reject the root itself and copy nothing. */
|
|
15
|
+
function payloadFilter(root, from) {
|
|
16
|
+
const segments = relative(root, from).split(sep);
|
|
17
|
+
return !segments.includes("node_modules") && !segments.includes(".git");
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Stage a built-in connector's shipped payload into `store/<generation>/<name>` and return that
|
|
21
|
+
* stable path (the spec `ext add` installs from). Idempotent: an intact prior copy is reused unless
|
|
22
|
+
* `force` re-materializes it (a `--force`/`--reset` repair). The copy is staged into a sibling temp
|
|
23
|
+
* dir and renamed into place, so a crash mid-copy never leaves a half-written payload at the final
|
|
24
|
+
* path for a later run to `ext add` from.
|
|
25
|
+
*/
|
|
26
|
+
export function stageSeedPayload(generation, name, opts = {}) {
|
|
27
|
+
const dest = seedStorePath(generation, name);
|
|
28
|
+
if (!opts.force && existsSync(join(dest, "package.json")))
|
|
29
|
+
return dest;
|
|
30
|
+
const src = shippedSourceDir(name);
|
|
31
|
+
const staging = `${dest}.staging`;
|
|
32
|
+
rmSync(staging, { recursive: true, force: true });
|
|
33
|
+
rmSync(dest, { recursive: true, force: true });
|
|
34
|
+
mkdirSync(dirname(dest), { recursive: true });
|
|
35
|
+
cpSync(src, staging, { recursive: true, filter: (from) => payloadFilter(src, from) });
|
|
36
|
+
renameSync(staging, dest); // atomic within the store: the final path only ever holds a complete payload
|
|
37
|
+
return dest;
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* GC seed-store generations other than `keepGeneration`, but ONLY those no live manifest entry still
|
|
41
|
+
* installs from (its normalized `file:` spec points under the generation dir). This is the commit
|
|
42
|
+
* predicate: a prior generation is removed only after every seeded entry has been re-added from the
|
|
43
|
+
* new one, so a running manager never loses the bytes its connectors resolve.
|
|
44
|
+
*/
|
|
45
|
+
export function gcSeedStore(keepGeneration, referencedSpecs) {
|
|
46
|
+
const root = seedStoreDir();
|
|
47
|
+
if (!existsSync(root))
|
|
48
|
+
return;
|
|
49
|
+
for (const gen of readdirSync(root)) {
|
|
50
|
+
if (gen === keepGeneration)
|
|
51
|
+
continue;
|
|
52
|
+
const genDir = join(root, gen);
|
|
53
|
+
const referenced = referencedSpecs.some((spec) => spec === genDir || spec.startsWith(genDir + sep));
|
|
54
|
+
if (!referenced)
|
|
55
|
+
rmSync(genDir, { recursive: true, force: true });
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
//# sourceMappingURL=store.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"store.js","sourceRoot":"","sources":["../../src/seed/store.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,SAAS,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AACzF,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,GAAG,EAAE,MAAM,WAAW,CAAC;AACzD,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAE3E;;;;;;GAMG;AAEH;;;kGAGkG;AAClG,SAAS,aAAa,CAAC,IAAY,EAAE,IAAY;IAC/C,MAAM,QAAQ,GAAG,QAAQ,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IACjD,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAC,cAAc,CAAC,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;AAC1E,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,gBAAgB,CAAC,UAAkB,EAAE,IAAY,EAAE,OAA4B,EAAE;IAC/F,MAAM,IAAI,GAAG,aAAa,CAAC,UAAU,EAAE,IAAI,CAAC,CAAC;IAC7C,IAAI,CAAC,IAAI,CAAC,KAAK,IAAI,UAAU,CAAC,IAAI,CAAC,IAAI,EAAE,cAAc,CAAC,CAAC;QAAE,OAAO,IAAI,CAAC;IACvE,MAAM,GAAG,GAAG,gBAAgB,CAAC,IAAI,CAAC,CAAC;IACnC,MAAM,OAAO,GAAG,GAAG,IAAI,UAAU,CAAC;IAClC,MAAM,CAAC,OAAO,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;IAClD,MAAM,CAAC,IAAI,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;IAC/C,SAAS,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAC9C,MAAM,CAAC,GAAG,EAAE,OAAO,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,aAAa,CAAC,GAAG,EAAE,IAAI,CAAC,EAAE,CAAC,CAAC;IACtF,UAAU,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC,CAAC,6EAA6E;IACxG,OAAO,IAAI,CAAC;AACd,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,WAAW,CAAC,cAAsB,EAAE,eAAkC;IACpF,MAAM,IAAI,GAAG,YAAY,EAAE,CAAC;IAC5B,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC;QAAE,OAAO;IAC9B,KAAK,MAAM,GAAG,IAAI,WAAW,CAAC,IAAI,CAAC,EAAE,CAAC;QACpC,IAAI,GAAG,KAAK,cAAc;YAAE,SAAS;QACrC,MAAM,MAAM,GAAG,IAAI,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC;QAC/B,MAAM,UAAU,GAAG,eAAe,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,KAAK,MAAM,IAAI,IAAI,CAAC,UAAU,CAAC,MAAM,GAAG,GAAG,CAAC,CAAC,CAAC;QACpG,IAAI,CAAC,UAAU;YAAE,MAAM,CAAC,MAAM,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;IACpE,CAAC;AACH,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cotal-ai/cli",
|
|
3
3
|
"description": "Cotal mesh CLI: up, join, watch, console, spawn, mint, channels, history, ext.",
|
|
4
|
-
"version": "0.11.
|
|
4
|
+
"version": "0.11.4",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"repository": {
|
|
7
7
|
"type": "git",
|
|
@@ -24,8 +24,8 @@
|
|
|
24
24
|
"yaml": "^2.9.0",
|
|
25
25
|
"zod": "^4.4.3",
|
|
26
26
|
"ws": "^8.21.0",
|
|
27
|
-
"@cotal-ai/
|
|
28
|
-
"@cotal-ai/
|
|
27
|
+
"@cotal-ai/core": "0.11.4",
|
|
28
|
+
"@cotal-ai/workspace": "0.11.4"
|
|
29
29
|
},
|
|
30
30
|
"optionalDependencies": {
|
|
31
31
|
"@eplightning/nats-server-darwin-arm64": "^2.14.0",
|