@cotal-ai/workspace 0.35.0 → 0.37.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.
Files changed (48) hide show
  1. package/dist/agent-secrets.d.ts +206 -0
  2. package/dist/agent-secrets.d.ts.map +1 -0
  3. package/dist/agent-secrets.js +468 -0
  4. package/dist/agent-secrets.js.map +1 -0
  5. package/dist/auth-paths.d.ts +10 -53
  6. package/dist/auth-paths.d.ts.map +1 -1
  7. package/dist/auth-paths.js +18 -134
  8. package/dist/auth-paths.js.map +1 -1
  9. package/dist/bin-path.d.ts.map +1 -1
  10. package/dist/bin-path.js +4 -1
  11. package/dist/bin-path.js.map +1 -1
  12. package/dist/extensions.d.ts +13 -1
  13. package/dist/extensions.d.ts.map +1 -1
  14. package/dist/extensions.js +16 -0
  15. package/dist/extensions.js.map +1 -1
  16. package/dist/index.d.ts +3 -0
  17. package/dist/index.d.ts.map +1 -1
  18. package/dist/index.js +3 -0
  19. package/dist/index.js.map +1 -1
  20. package/dist/local-process.d.ts +111 -1
  21. package/dist/local-process.d.ts.map +1 -1
  22. package/dist/local-process.js +204 -23
  23. package/dist/local-process.js.map +1 -1
  24. package/dist/pid.d.ts +0 -9
  25. package/dist/pid.d.ts.map +1 -1
  26. package/dist/pid.js +0 -10
  27. package/dist/pid.js.map +1 -1
  28. package/dist/progress.d.ts +18 -0
  29. package/dist/progress.d.ts.map +1 -0
  30. package/dist/progress.js +9 -0
  31. package/dist/progress.js.map +1 -0
  32. package/dist/renewal.d.ts +22 -15
  33. package/dist/renewal.d.ts.map +1 -1
  34. package/dist/renewal.js +27 -21
  35. package/dist/renewal.js.map +1 -1
  36. package/dist/space-segmentation.d.ts +260 -0
  37. package/dist/space-segmentation.d.ts.map +1 -0
  38. package/dist/space-segmentation.js +428 -0
  39. package/dist/space-segmentation.js.map +1 -0
  40. package/dist/space.d.ts +19 -0
  41. package/dist/space.d.ts.map +1 -1
  42. package/dist/space.js +31 -0
  43. package/dist/space.js.map +1 -1
  44. package/dist/system-rotation.d.ts +7 -6
  45. package/dist/system-rotation.d.ts.map +1 -1
  46. package/dist/system-rotation.js +25 -10
  47. package/dist/system-rotation.js.map +1 -1
  48. package/package.json +2 -2
@@ -34,7 +34,117 @@ export interface LocalProcess extends Extension {
34
34
  * cwd-only stop would miss the live process. Bare whole-stack sweeps stay folder-scoped. */
35
35
  readonly rootedAt?: "target";
36
36
  }
37
- /** Resolve a declarative local-process path, rejecting absolute/traversal templates. */
37
+ /** `.cotal/manager.<spaceKey>.pid` the running manager's record, KEYED BY SPACE.
38
+ *
39
+ * The NAME lives in this tier because both the CLI (which reads it to decide whether to start one)
40
+ * and the manager daemon (which writes it on start) already depend on it, and a file written under
41
+ * one constant and read under another is the same defect as no record at all.
42
+ *
43
+ * It is a `{space}` TEMPLATE rather than a bare name because the record is per-tenant in meaning: a
44
+ * root-scoped `manager.pid` gave one workspace root exactly one manager BY FILENAME, so a second
45
+ * space booting in that root overwrote the first space's record and every reader then answered
46
+ * about the wrong process. `auth-service.{space}.pid` was already templated; these were not. */
47
+ export declare const MANAGER_PIDFILE = "manager.{space}.pid";
48
+ /** `.cotal/manager.<spaceKey>.log` — where a detached manager's output goes. Per-space for the same
49
+ * reason the pidfile is: two spaces' managers sharing one log interleave two meshes' console URLs
50
+ * (each a standing credential) into one 0600 file that neither tenant alone owns. */
51
+ export declare const MANAGER_LOGFILE = "manager.{space}.log";
52
+ /** `.cotal/manager.<spaceKey>.delivery-aware` — the sibling marker proving the live manager is a
53
+ * build that does NOT host Plane-3. Written and removed with the pidfile; it carries the pid it was
54
+ * written for, so a stale marker cannot be paired with a different manager. Per-space because the
55
+ * pid it names is, and a marker that could be paired with ANOTHER space's manager would answer the
56
+ * delivery cutover preflight about the wrong process. */
57
+ export declare const MANAGER_DELIVERY_AWARE_MARKER = "manager.{space}.delivery-aware";
58
+ /** `.cotal/delivery.<spaceKey>.pid` — the Plane-3 delivery daemon's record. Per-space: the daemon is
59
+ * minted a space-scoped cred and binds that space's durables, so two spaces need two daemons. */
60
+ export declare const DELIVERY_PIDFILE = "delivery.{space}.pid";
61
+ /** `.cotal/delivery.<spaceKey>.log` — the delivery daemon's output. See {@link MANAGER_LOGFILE}. */
62
+ export declare const DELIVERY_LOGFILE = "delivery.{space}.log";
63
+ /**
64
+ * The ROOT-SCOPED name each per-space RECORD was written under before segmentation — the one place
65
+ * that history is spelled.
66
+ *
67
+ * WHY A READ SHIM AND NOT A MIGRATION. `space-segmentation.ts` moves legacy material on first touch
68
+ * because those kinds have absent-means-mint writers, so a canonical read on an unmigrated root
69
+ * would mint a SECOND live credential. A pidfile has no such writer: it fronts a process that is
70
+ * either running or not. What an upgrade must not do is stop FINDING that process — a `cotal down`
71
+ * that skips a pre-upgrade record exits 0 leaving a live manager and a live delivery daemon behind,
72
+ * which is the customer-update-path invariant AGENTS.md calls load-bearing. So the pre-upgrade name
73
+ * is ADMITTED for reading; nothing is moved, and the start paths always WRITE the canonical name
74
+ * (a degraded write mode would keep minting the very records this ends).
75
+ *
76
+ * RECORDS ONLY — no logs. A log holds text, not a pid, so a pre-upgrade `manager.log` sitting beside
77
+ * the new `manager.<hex>.log` is an ordinary state rather than a contradiction, and the ambiguity
78
+ * rule below must never fire on it. Nothing sweeps the old log, which is what `clean` already did
79
+ * with logs before this change.
80
+ */
81
+ export declare const PRE_SEGMENTATION_RUNTIME_RECORDS: ReadonlyMap<string, string>;
82
+ /** The location a start WRITES: the canonical, space-keyed path, whatever else is on disk. Rejects
83
+ * absolute/traversal templates. Every writer takes this; readers take {@link localProcessPath}. */
84
+ export declare function canonicalLocalProcessPath(template: string, context: LocalProcessContext): string;
85
+ /**
86
+ * Every name this record has been written under, CANONICAL FIRST, whether or not each exists.
87
+ *
88
+ * Two pre-upgrade spellings are possible and both are historical fact rather than guesswork:
89
+ * - the PRE-HEX one, for a `{space}` template written before the hex re-key
90
+ * (`auth-service.<encodeURIComponent(space)>.pid`);
91
+ * - the PRE-SEGMENTATION root-scoped one, for the runtime records above.
92
+ *
93
+ * Exported for the SWEEPERS (`clean`, the `down` inventory), which must name every spelling they are
94
+ * about to remove and must NOT go through {@link localProcessPath} — a deleter that resolved through
95
+ * the ambiguity rule would refuse on exactly the half-upgraded root it exists to tidy.
96
+ */
97
+ export declare function localProcessPathCandidates(template: string, context: LocalProcessContext): string[];
98
+ /**
99
+ * The record to READ: the canonical space-keyed path, or a pre-upgrade one when that is the only
100
+ * spelling present.
101
+ *
102
+ * `down`/`status`/`up` read this to FIND and stop a live process, so a pre-upgrade record must stay
103
+ * findable across the upgrade or the daemon behind it is silently orphaned. BYTE-EXACT (a bare
104
+ * `existsSync` case-folds on macOS/Windows and would match another space's file); both spellings
105
+ * present is ambiguous and fails LOUD rather than picking one, mirroring the state-dir and registry
106
+ * legacy shims. The start paths reclaim a provably dead pre-upgrade record before writing the
107
+ * canonical one, so an ordinary upgrade never reaches that refusal.
108
+ */
38
109
  export declare function localProcessPath(template: string, context: LocalProcessContext): string;
110
+ /**
111
+ * Reclaim a provably DEAD pre-upgrade record before a start claims the canonical slot.
112
+ *
113
+ * Without this an ordinary upgrade wedges the root: a pre-segmentation crash leaves `manager.pid`,
114
+ * the next start writes `manager.<hex>.pid`, BOTH then exist, and {@link localProcessPath} correctly
115
+ * refuses every later status/down as ambiguous.
116
+ *
117
+ * It reclaims ONLY what a canonical claim would: an empty slot (a pre-protocol crash) or a pid
118
+ * proven dead by ESRCH. It NEVER deletes an unattributable record, a still-LIVE holder, or one whose
119
+ * liveness the kernel would not answer — those are precisely the live pre-upgrade daemon this path
120
+ * exists not to orphan, so they THROW and the start aborts loud rather than deleting the record and
121
+ * launching a competitor. Byte-exact, no case-fold. RECORDS only: a log holds text, not a pid.
122
+ */
123
+ export declare function reclaimDeadPreUpgradeRecord(template: string, context: LocalProcessContext): void;
124
+ /** A space this root holds a runtime record for, with the one fact a caller has to act on. */
125
+ export interface RecordedRuntimeSpace {
126
+ readonly space: string;
127
+ /** False only when EVERY record for this space is provably not a process (empty husk, or a pid
128
+ * ESRCH-proven dead). An unparsable record or a pid the kernel will not answer for counts as
129
+ * possibly running: the same fail-closed direction `down`'s dependant guard takes, because the
130
+ * cost of the other reading is walking past a live daemon. */
131
+ readonly mayBeRunning: boolean;
132
+ }
133
+ /**
134
+ * The spaces whose runtime daemons THIS ROOT has recorded, read off the record filenames.
135
+ *
136
+ * A root's space is otherwise derived from its `.cotal/auth` account records, and an OPEN mesh
137
+ * (`broker: { auth: false }`) has none — so that derivation answers with the default space while the
138
+ * mesh runs under its own name. A root-scoped `manager.pid` was space-blind and hid that; a
139
+ * per-space record does not, and a `cotal down` that cannot name the space walks past a live manager
140
+ * and exits 0. The records themselves are the one source that always knows: `spaceKey` is injective
141
+ * UTF-8 hex, so the name a start wrote decodes back to the space it wrote it for.
142
+ *
143
+ * THE PID RECORDS ONLY. They are what "a daemon is running here" means; the log and the
144
+ * delivery-aware marker are siblings of a record rather than evidence of their own. A
145
+ * PRE-SEGMENTATION root-scoped record names no space and contributes none — the folder's own space
146
+ * still resolves it, through the candidate list in {@link localProcessPath}.
147
+ */
148
+ export declare function recordedRuntimeSpaces(root: string): RecordedRuntimeSpace[];
39
149
  export declare function localProcessVisible(process: LocalProcess, context: LocalProcessContext): boolean;
40
150
  //# sourceMappingURL=local-process.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"local-process.d.ts","sourceRoot":"","sources":["../src/local-process.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAGhD,uGAAuG;AACvG,MAAM,WAAW,mBAAmB;IAClC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,QAAQ,CAAC,EAAE,OAAO,CAAC;CAC7B;AAED;;;;4FAI4F;AAC5F,MAAM,WAAW,YAAa,SAAQ,SAAS;IAC7C,QAAQ,CAAC,IAAI,EAAE,eAAe,CAAC;IAC/B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,kGAAkG;IAClG,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IACxB;iGAC6F;IAC7F,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,gGAAgG;IAChG,QAAQ,CAAC,SAAS,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IACvC,uFAAuF;IACvF,QAAQ,CAAC,QAAQ,CAAC,EAAE,OAAO,CAAC;IAC5B,iGAAiG;IACjG,QAAQ,CAAC,UAAU,CAAC,EAAE,OAAO,CAAC;IAC9B,iFAAiF;IACjF,QAAQ,CAAC,WAAW,CAAC,EAAE,WAAW,CAAC;IACnC;;;;iGAI6F;IAC7F,QAAQ,CAAC,QAAQ,CAAC,EAAE,QAAQ,CAAC;CAC9B;AAED,wFAAwF;AACxF,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,mBAAmB,GAAG,MAAM,CA2BvF;AAaD,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,YAAY,EAAE,OAAO,EAAE,mBAAmB,GAAG,OAAO,CAEhG"}
1
+ {"version":3,"file":"local-process.d.ts","sourceRoot":"","sources":["../src/local-process.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAIhD,uGAAuG;AACvG,MAAM,WAAW,mBAAmB;IAClC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,QAAQ,CAAC,EAAE,OAAO,CAAC;CAC7B;AAED;;;;4FAI4F;AAC5F,MAAM,WAAW,YAAa,SAAQ,SAAS;IAC7C,QAAQ,CAAC,IAAI,EAAE,eAAe,CAAC;IAC/B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,kGAAkG;IAClG,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IACxB;iGAC6F;IAC7F,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,gGAAgG;IAChG,QAAQ,CAAC,SAAS,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IACvC,uFAAuF;IACvF,QAAQ,CAAC,QAAQ,CAAC,EAAE,OAAO,CAAC;IAC5B,iGAAiG;IACjG,QAAQ,CAAC,UAAU,CAAC,EAAE,OAAO,CAAC;IAC9B,iFAAiF;IACjF,QAAQ,CAAC,WAAW,CAAC,EAAE,WAAW,CAAC;IACnC;;;;iGAI6F;IAC7F,QAAQ,CAAC,QAAQ,CAAC,EAAE,QAAQ,CAAC;CAC9B;AAID;;;;;;;;;iGASiG;AACjG,eAAO,MAAM,eAAe,wBAAwB,CAAC;AAErD;;sFAEsF;AACtF,eAAO,MAAM,eAAe,wBAAwB,CAAC;AAErD;;;;0DAI0D;AAC1D,eAAO,MAAM,6BAA6B,mCAAmC,CAAC;AAE9E;kGACkG;AAClG,eAAO,MAAM,gBAAgB,yBAAyB,CAAC;AAEvD,oGAAoG;AACpG,eAAO,MAAM,gBAAgB,yBAAyB,CAAC;AAEvD;;;;;;;;;;;;;;;;;GAiBG;AACH,eAAO,MAAM,gCAAgC,EAAE,WAAW,CAAC,MAAM,EAAE,MAAM,CAIvE,CAAC;AAEH;oGACoG;AACpG,wBAAgB,yBAAyB,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,mBAAmB,GAAG,MAAM,CAOhG;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,0BAA0B,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,mBAAmB,GAAG,MAAM,EAAE,CAUnG;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,mBAAmB,GAAG,MAAM,CAavF;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,2BAA2B,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,mBAAmB,GAAG,IAAI,CAyBhG;AAED,8FAA8F;AAC9F,MAAM,WAAW,oBAAoB;IACnC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB;;;mEAG+D;IAC/D,QAAQ,CAAC,YAAY,EAAE,OAAO,CAAC;CAChC;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,MAAM,GAAG,oBAAoB,EAAE,CAgB1E;AA2CD,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,YAAY,EAAE,OAAO,EAAE,mBAAmB,GAAG,OAAO,CAEhG"}
@@ -1,36 +1,217 @@
1
- import { readdirSync } from "node:fs";
1
+ import { readdirSync, readFileSync, rmSync } from "node:fs";
2
2
  import { isAbsolute, join, normalize, dirname, basename } from "node:path";
3
3
  import { spaceKey } from "./auth-paths.js";
4
- /** Resolve a declarative local-process path, rejecting absolute/traversal templates. */
5
- export function localProcessPath(template, context) {
4
+ import { parsePid, probeLiveness } from "./pid.js";
5
+ // ---- the runtime records, per space -------------------------------------------------------------
6
+ /** `.cotal/manager.<spaceKey>.pid` — the running manager's record, KEYED BY SPACE.
7
+ *
8
+ * The NAME lives in this tier because both the CLI (which reads it to decide whether to start one)
9
+ * and the manager daemon (which writes it on start) already depend on it, and a file written under
10
+ * one constant and read under another is the same defect as no record at all.
11
+ *
12
+ * It is a `{space}` TEMPLATE rather than a bare name because the record is per-tenant in meaning: a
13
+ * root-scoped `manager.pid` gave one workspace root exactly one manager BY FILENAME, so a second
14
+ * space booting in that root overwrote the first space's record and every reader then answered
15
+ * about the wrong process. `auth-service.{space}.pid` was already templated; these were not. */
16
+ export const MANAGER_PIDFILE = "manager.{space}.pid";
17
+ /** `.cotal/manager.<spaceKey>.log` — where a detached manager's output goes. Per-space for the same
18
+ * reason the pidfile is: two spaces' managers sharing one log interleave two meshes' console URLs
19
+ * (each a standing credential) into one 0600 file that neither tenant alone owns. */
20
+ export const MANAGER_LOGFILE = "manager.{space}.log";
21
+ /** `.cotal/manager.<spaceKey>.delivery-aware` — the sibling marker proving the live manager is a
22
+ * build that does NOT host Plane-3. Written and removed with the pidfile; it carries the pid it was
23
+ * written for, so a stale marker cannot be paired with a different manager. Per-space because the
24
+ * pid it names is, and a marker that could be paired with ANOTHER space's manager would answer the
25
+ * delivery cutover preflight about the wrong process. */
26
+ export const MANAGER_DELIVERY_AWARE_MARKER = "manager.{space}.delivery-aware";
27
+ /** `.cotal/delivery.<spaceKey>.pid` — the Plane-3 delivery daemon's record. Per-space: the daemon is
28
+ * minted a space-scoped cred and binds that space's durables, so two spaces need two daemons. */
29
+ export const DELIVERY_PIDFILE = "delivery.{space}.pid";
30
+ /** `.cotal/delivery.<spaceKey>.log` — the delivery daemon's output. See {@link MANAGER_LOGFILE}. */
31
+ export const DELIVERY_LOGFILE = "delivery.{space}.log";
32
+ /**
33
+ * The ROOT-SCOPED name each per-space RECORD was written under before segmentation — the one place
34
+ * that history is spelled.
35
+ *
36
+ * WHY A READ SHIM AND NOT A MIGRATION. `space-segmentation.ts` moves legacy material on first touch
37
+ * because those kinds have absent-means-mint writers, so a canonical read on an unmigrated root
38
+ * would mint a SECOND live credential. A pidfile has no such writer: it fronts a process that is
39
+ * either running or not. What an upgrade must not do is stop FINDING that process — a `cotal down`
40
+ * that skips a pre-upgrade record exits 0 leaving a live manager and a live delivery daemon behind,
41
+ * which is the customer-update-path invariant AGENTS.md calls load-bearing. So the pre-upgrade name
42
+ * is ADMITTED for reading; nothing is moved, and the start paths always WRITE the canonical name
43
+ * (a degraded write mode would keep minting the very records this ends).
44
+ *
45
+ * RECORDS ONLY — no logs. A log holds text, not a pid, so a pre-upgrade `manager.log` sitting beside
46
+ * the new `manager.<hex>.log` is an ordinary state rather than a contradiction, and the ambiguity
47
+ * rule below must never fire on it. Nothing sweeps the old log, which is what `clean` already did
48
+ * with logs before this change.
49
+ */
50
+ export const PRE_SEGMENTATION_RUNTIME_RECORDS = new Map([
51
+ [MANAGER_PIDFILE, "manager.pid"],
52
+ [MANAGER_DELIVERY_AWARE_MARKER, "manager.delivery-aware"],
53
+ [DELIVERY_PIDFILE, "delivery.pid"],
54
+ ]);
55
+ /** The location a start WRITES: the canonical, space-keyed path, whatever else is on disk. Rejects
56
+ * absolute/traversal templates. Every writer takes this; readers take {@link localProcessPath}. */
57
+ export function canonicalLocalProcessPath(template, context) {
6
58
  if (!template.trim())
7
59
  throw new Error("local-process path must not be empty");
8
60
  const expanded = template.replaceAll("{space}", spaceKey(context.space));
9
61
  const normalized = normalize(expanded);
10
62
  if (normalized === "." || isAbsolute(expanded) || normalized === ".." || normalized.startsWith(`..${process.platform === "win32" ? "\\" : "/"}`))
11
63
  throw new Error(`local-process path must stay under .cotal: ${JSON.stringify(template)}`);
12
- const canonical = join(context.root, ".cotal", normalized);
13
- // A `{space}`-keyed file (the user-auth service pid/log) was written `auth-service.<encoded>.pid`
14
- // before the hex re-key. `down`/`status` READ this path to find and stop the process; if only the
15
- // canonical hex name is checked, a pre-upgrade auth-service - a callout SIGNER - is a live process
16
- // whose legacy pidfile is skipped, so `down` exits 0 leaving it running (the customer-update-path
17
- // invariant AGENTS.md calls load-bearing: an upgrade must never silently orphan a signer). Admit
18
- // the legacy name too, BYTE-EXACT (a bare `existsSync` would case-fold on macOS/Windows and match
19
- // another space's legacy file); both present is ambiguous and fails loud, mirroring the state-dir
20
- // and registry legacy shims.
21
- if (template.includes("{space}")) {
22
- const legacy = join(context.root, ".cotal", normalize(template.replaceAll("{space}", encodeURIComponent(context.space))));
23
- if (legacy !== canonical) {
24
- const has = (p) => existsByteExact(p);
25
- const canonicalExists = has(canonical);
26
- const legacyExists = has(legacy);
27
- if (legacyExists && canonicalExists)
28
- throw new Error(`both ${canonical} and the pre-hex ${legacy} exist for space "${context.space}" - ambiguous process record; remove the stale one`);
29
- if (legacyExists)
30
- return legacy;
64
+ return join(context.root, ".cotal", normalized);
65
+ }
66
+ /**
67
+ * Every name this record has been written under, CANONICAL FIRST, whether or not each exists.
68
+ *
69
+ * Two pre-upgrade spellings are possible and both are historical fact rather than guesswork:
70
+ * - the PRE-HEX one, for a `{space}` template written before the hex re-key
71
+ * (`auth-service.<encodeURIComponent(space)>.pid`);
72
+ * - the PRE-SEGMENTATION root-scoped one, for the runtime records above.
73
+ *
74
+ * Exported for the SWEEPERS (`clean`, the `down` inventory), which must name every spelling they are
75
+ * about to remove and must NOT go through {@link localProcessPath} — a deleter that resolved through
76
+ * the ambiguity rule would refuse on exactly the half-upgraded root it exists to tidy.
77
+ */
78
+ export function localProcessPathCandidates(template, context) {
79
+ const paths = [canonicalLocalProcessPath(template, context)];
80
+ const add = (name) => {
81
+ const p = join(context.root, ".cotal", normalize(name));
82
+ if (!paths.includes(p))
83
+ paths.push(p);
84
+ };
85
+ if (template.includes("{space}"))
86
+ add(template.replaceAll("{space}", encodeURIComponent(context.space)));
87
+ const preSegmentation = PRE_SEGMENTATION_RUNTIME_RECORDS.get(template);
88
+ if (preSegmentation !== undefined)
89
+ add(preSegmentation);
90
+ return paths;
91
+ }
92
+ /**
93
+ * The record to READ: the canonical space-keyed path, or a pre-upgrade one when that is the only
94
+ * spelling present.
95
+ *
96
+ * `down`/`status`/`up` read this to FIND and stop a live process, so a pre-upgrade record must stay
97
+ * findable across the upgrade or the daemon behind it is silently orphaned. BYTE-EXACT (a bare
98
+ * `existsSync` case-folds on macOS/Windows and would match another space's file); both spellings
99
+ * present is ambiguous and fails LOUD rather than picking one, mirroring the state-dir and registry
100
+ * legacy shims. The start paths reclaim a provably dead pre-upgrade record before writing the
101
+ * canonical one, so an ordinary upgrade never reaches that refusal.
102
+ */
103
+ export function localProcessPath(template, context) {
104
+ const [canonical, ...legacy] = localProcessPathCandidates(template, context);
105
+ const present = legacy.filter(existsByteExact);
106
+ if (present.length === 0)
107
+ return canonical;
108
+ if (existsByteExact(canonical))
109
+ throw new Error(`both ${canonical} and the pre-upgrade ${present.join(" and ")} exist for space "${context.space}" - ambiguous process record; remove the stale one`);
110
+ if (present.length > 1)
111
+ throw new Error(`several pre-upgrade records (${present.join(", ")}) exist for space "${context.space}" - ambiguous process record; remove the stale one`);
112
+ return present[0];
113
+ }
114
+ /**
115
+ * Reclaim a provably DEAD pre-upgrade record before a start claims the canonical slot.
116
+ *
117
+ * Without this an ordinary upgrade wedges the root: a pre-segmentation crash leaves `manager.pid`,
118
+ * the next start writes `manager.<hex>.pid`, BOTH then exist, and {@link localProcessPath} correctly
119
+ * refuses every later status/down as ambiguous.
120
+ *
121
+ * It reclaims ONLY what a canonical claim would: an empty slot (a pre-protocol crash) or a pid
122
+ * proven dead by ESRCH. It NEVER deletes an unattributable record, a still-LIVE holder, or one whose
123
+ * liveness the kernel would not answer — those are precisely the live pre-upgrade daemon this path
124
+ * exists not to orphan, so they THROW and the start aborts loud rather than deleting the record and
125
+ * launching a competitor. Byte-exact, no case-fold. RECORDS only: a log holds text, not a pid.
126
+ */
127
+ export function reclaimDeadPreUpgradeRecord(template, context) {
128
+ const [, ...legacy] = localProcessPathCandidates(template, context);
129
+ for (const path of legacy) {
130
+ if (!existsByteExact(path))
131
+ continue;
132
+ const raw = readFileSync(path, "utf8").trim();
133
+ if (raw === "") {
134
+ rmSync(path, { force: true }); // empty husk: nothing is behind it, as the canonical claim treats it
135
+ continue;
31
136
  }
137
+ const pid = parsePid(raw);
138
+ if (pid === undefined)
139
+ throw new Error(`the pre-upgrade record ${path} holds unattributable content ${JSON.stringify(raw)} - refusing to reclaim it or start a competing process; inspect or remove it manually`);
140
+ const state = probeLiveness(pid);
141
+ if (state === "alive")
142
+ throw new Error(`a pre-upgrade process is already running (pid ${pid}) at ${path} - refusing to start a second; run \`cotal down\` to stop it, then retry`);
143
+ if (state === "unknown")
144
+ throw new Error(`cannot determine whether pid ${pid} in ${path} is alive - refusing to reclaim an unattributable record or start a competing process; inspect or remove it manually`);
145
+ rmSync(path, { force: true }); // ESRCH-proven dead
146
+ }
147
+ }
148
+ /**
149
+ * The spaces whose runtime daemons THIS ROOT has recorded, read off the record filenames.
150
+ *
151
+ * A root's space is otherwise derived from its `.cotal/auth` account records, and an OPEN mesh
152
+ * (`broker: { auth: false }`) has none — so that derivation answers with the default space while the
153
+ * mesh runs under its own name. A root-scoped `manager.pid` was space-blind and hid that; a
154
+ * per-space record does not, and a `cotal down` that cannot name the space walks past a live manager
155
+ * and exits 0. The records themselves are the one source that always knows: `spaceKey` is injective
156
+ * UTF-8 hex, so the name a start wrote decodes back to the space it wrote it for.
157
+ *
158
+ * THE PID RECORDS ONLY. They are what "a daemon is running here" means; the log and the
159
+ * delivery-aware marker are siblings of a record rather than evidence of their own. A
160
+ * PRE-SEGMENTATION root-scoped record names no space and contributes none — the folder's own space
161
+ * still resolves it, through the candidate list in {@link localProcessPath}.
162
+ */
163
+ export function recordedRuntimeSpaces(root) {
164
+ const dir = join(root, ".cotal");
165
+ let names;
166
+ try {
167
+ names = readdirSync(dir);
168
+ }
169
+ catch {
170
+ return []; // no `.cotal` → nothing is recorded here
171
+ }
172
+ const found = new Map();
173
+ for (const name of names)
174
+ for (const template of [MANAGER_PIDFILE, DELIVERY_PIDFILE]) {
175
+ const space = spaceFromRecordName(template, name);
176
+ if (space === undefined)
177
+ continue;
178
+ found.set(space, (found.get(space) ?? false) || recordMayBeRunning(join(dir, name)));
179
+ }
180
+ return [...found].map(([space, mayBeRunning]) => ({ space, mayBeRunning })).sort((a, b) => a.space.localeCompare(b.space));
181
+ }
182
+ /** The space a canonical record filename encodes, or undefined when the name is not one
183
+ * {@link canonicalLocalProcessPath} wrote for this template (wrong fixed parts, non-hex body, or a
184
+ * body that does not round-trip back to the same name). Same predicate as the account-file and
185
+ * path-segment decoders: enumeration must never read a stray as a tenant. */
186
+ function spaceFromRecordName(template, name) {
187
+ const at = template.indexOf("{space}");
188
+ if (at < 0)
189
+ return undefined;
190
+ const prefix = template.slice(0, at), suffix = template.slice(at + "{space}".length);
191
+ if (!name.startsWith(prefix) || !name.endsWith(suffix) || name.length <= prefix.length + suffix.length)
192
+ return undefined;
193
+ const key = name.slice(prefix.length, name.length - suffix.length);
194
+ if (key.length % 2 !== 0 || !/^[0-9a-f]+$/.test(key))
195
+ return undefined;
196
+ const space = Buffer.from(key, "hex").toString("utf8");
197
+ return space.length > 0 && spaceKey(space) === key ? space : undefined;
198
+ }
199
+ /** Whether a record file might still front a process. See {@link RecordedRuntimeSpace.mayBeRunning}
200
+ * for the direction and why it is that one. */
201
+ function recordMayBeRunning(path) {
202
+ let raw;
203
+ try {
204
+ raw = readFileSync(path, "utf8").trim();
205
+ }
206
+ catch {
207
+ return false; // removed under us → nothing to address
32
208
  }
33
- return canonical;
209
+ if (raw === "")
210
+ return false; // pre-protocol husk: no process behind it
211
+ const pid = parsePid(raw);
212
+ if (pid === undefined)
213
+ return true; // unattributable: cannot prove it gone
214
+ return probeLiveness(pid) !== "dead"; // alive OR unknown; only ESRCH clears it
34
215
  }
35
216
  /** Byte-exact existence: an entry named exactly `basename(p)` in its parent dir. `existsSync` on a
36
217
  * case-insensitive filesystem reports a case-folded sibling as present, which for a legacy pidfile
@@ -1 +1 @@
1
- {"version":3,"file":"local-process.js","sourceRoot":"","sources":["../src/local-process.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AACtC,OAAO,EAAE,UAAU,EAAE,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAC;AAE3E,OAAO,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAuC3C,wFAAwF;AACxF,MAAM,UAAU,gBAAgB,CAAC,QAAgB,EAAE,OAA4B;IAC7E,IAAI,CAAC,QAAQ,CAAC,IAAI,EAAE;QAAE,MAAM,IAAI,KAAK,CAAC,sCAAsC,CAAC,CAAC;IAC9E,MAAM,QAAQ,GAAG,QAAQ,CAAC,UAAU,CAAC,SAAS,EAAE,QAAQ,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC;IACzE,MAAM,UAAU,GAAG,SAAS,CAAC,QAAQ,CAAC,CAAC;IACvC,IAAI,UAAU,KAAK,GAAG,IAAI,UAAU,CAAC,QAAQ,CAAC,IAAI,UAAU,KAAK,IAAI,IAAI,UAAU,CAAC,UAAU,CAAC,KAAK,OAAO,CAAC,QAAQ,KAAK,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC;QAC9I,MAAM,IAAI,KAAK,CAAC,8CAA8C,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;IAC5F,MAAM,SAAS,GAAG,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,QAAQ,EAAE,UAAU,CAAC,CAAC;IAC3D,kGAAkG;IAClG,kGAAkG;IAClG,mGAAmG;IACnG,kGAAkG;IAClG,iGAAiG;IACjG,kGAAkG;IAClG,kGAAkG;IAClG,6BAA6B;IAC7B,IAAI,QAAQ,CAAC,QAAQ,CAAC,SAAS,CAAC,EAAE,CAAC;QACjC,MAAM,MAAM,GAAG,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,QAAQ,EAAE,SAAS,CAAC,QAAQ,CAAC,UAAU,CAAC,SAAS,EAAE,kBAAkB,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;QAC1H,IAAI,MAAM,KAAK,SAAS,EAAE,CAAC;YACzB,MAAM,GAAG,GAAG,CAAC,CAAS,EAAE,EAAE,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC;YAC9C,MAAM,eAAe,GAAG,GAAG,CAAC,SAAS,CAAC,CAAC;YACvC,MAAM,YAAY,GAAG,GAAG,CAAC,MAAM,CAAC,CAAC;YACjC,IAAI,YAAY,IAAI,eAAe;gBACjC,MAAM,IAAI,KAAK,CAAC,QAAQ,SAAS,oBAAoB,MAAM,qBAAqB,OAAO,CAAC,KAAK,oDAAoD,CAAC,CAAC;YACrJ,IAAI,YAAY;gBAAE,OAAO,MAAM,CAAC;QAClC,CAAC;IACH,CAAC;IACD,OAAO,SAAS,CAAC;AACnB,CAAC;AAED;;qFAEqF;AACrF,SAAS,eAAe,CAAC,CAAS;IAChC,IAAI,CAAC;QACH,OAAO,WAAW,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC;IACvD,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC,CAAC,8BAA8B;IAC9C,CAAC;AACH,CAAC;AAED,MAAM,UAAU,mBAAmB,CAAC,OAAqB,EAAE,OAA4B;IACrF,OAAO,OAAO,CAAC,WAAW,KAAK,WAAW,IAAI,OAAO,CAAC,QAAQ,KAAK,IAAI,CAAC;AAC1E,CAAC"}
1
+ {"version":3,"file":"local-process.js","sourceRoot":"","sources":["../src/local-process.ts"],"names":[],"mappings":"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"}
package/dist/pid.d.ts CHANGED
@@ -46,15 +46,6 @@ export declare function livenessFromErrno(code: string | undefined): "alive" | "
46
46
  * this so that branch can be driven directly. Production passes nothing and gets the real one. */
47
47
  export type LivenessProbe = (pid: number) => "alive" | "dead" | "unknown";
48
48
  export declare function probeLiveness(pid: number): "alive" | "dead" | "unknown";
49
- /** `.cotal/manager.pid` — the running manager's pid. The NAME lives here, in the tier both the CLI
50
- * (which reads it to decide whether to start one) and the manager daemon (which writes it on
51
- * start) already depend on, because a file written under one constant and read under another is
52
- * the same defect as no record at all. */
53
- export declare const MANAGER_PIDFILE = "manager.pid";
54
- /** `.cotal/manager.delivery-aware` — the sibling marker proving the live manager is a build that
55
- * does NOT host Plane-3. Written and removed with the pidfile; it carries the pid it was written
56
- * for, so a stale marker cannot be paired with a different manager. */
57
- export declare const MANAGER_DELIVERY_AWARE_MARKER = "manager.delivery-aware";
58
49
  /** What was read about ONE pid's command line, three-valued for the same reason liveness is:
59
50
  * "it is something else" and "I could not look" are different facts and only the first may be
60
51
  * acted on. */
package/dist/pid.d.ts.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"pid.d.ts","sourceRoot":"","sources":["../src/pid.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAKH;;;wCAGwC;AACxC,wBAAgB,QAAQ,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAGxD;AAED;;;;;;;;sDAQsD;AACtD,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,GAAG,OAAO,GAAG,MAAM,GAAG,SAAS,CAIxF;AAED;;;;;;;2BAO2B;AAC3B;;;mGAGmG;AACnG,MAAM,MAAM,aAAa,GAAG,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,GAAG,MAAM,GAAG,SAAS,CAAC;AAE1E,wBAAgB,aAAa,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,GAAG,MAAM,GAAG,SAAS,CAOvE;AAID;;;2CAG2C;AAC3C,eAAO,MAAM,eAAe,gBAAgB,CAAC;AAE7C;;wEAEwE;AACxE,eAAO,MAAM,6BAA6B,2BAA2B,CAAC;AAItE;;gBAEgB;AAChB,MAAM,MAAM,cAAc;AACxB,gDAAgD;AAC9C;IAAE,IAAI,EAAE,SAAS,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE;AACtC,iGAAiG;GAC/F;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE;AAClB,oFAAoF;GAClF;IAAE,IAAI,EAAE,YAAY,CAAC;IAAC,GAAG,EAAE,MAAM,CAAA;CAAE,CAAC;AAExC;;6CAE6C;AAC7C,MAAM,MAAM,aAAa,GAAG,CAAC,GAAG,EAAE,MAAM,KAAK,cAAc,CAAC;AAE5D;;;;;;;;GAQG;AACH,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,MAAM,GAAG,cAAc,CAkB9D;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,wBAAwB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAEjE"}
1
+ {"version":3,"file":"pid.d.ts","sourceRoot":"","sources":["../src/pid.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAKH;;;wCAGwC;AACxC,wBAAgB,QAAQ,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAGxD;AAED;;;;;;;;sDAQsD;AACtD,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,GAAG,OAAO,GAAG,MAAM,GAAG,SAAS,CAIxF;AAED;;;;;;;2BAO2B;AAC3B;;;mGAGmG;AACnG,MAAM,MAAM,aAAa,GAAG,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,GAAG,MAAM,GAAG,SAAS,CAAC;AAE1E,wBAAgB,aAAa,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,GAAG,MAAM,GAAG,SAAS,CAOvE;AAWD;;gBAEgB;AAChB,MAAM,MAAM,cAAc;AACxB,gDAAgD;AAC9C;IAAE,IAAI,EAAE,SAAS,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE;AACtC,iGAAiG;GAC/F;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE;AAClB,oFAAoF;GAClF;IAAE,IAAI,EAAE,YAAY,CAAC;IAAC,GAAG,EAAE,MAAM,CAAA;CAAE,CAAC;AAExC;;6CAE6C;AAC7C,MAAM,MAAM,aAAa,GAAG,CAAC,GAAG,EAAE,MAAM,KAAK,cAAc,CAAC;AAE5D;;;;;;;;GAQG;AACH,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,MAAM,GAAG,cAAc,CAkB9D;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,wBAAwB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAEjE"}
package/dist/pid.js CHANGED
@@ -52,16 +52,6 @@ export function probeLiveness(pid) {
52
52
  return livenessFromErrno(e.code);
53
53
  }
54
54
  }
55
- // ---- the manager's own record ------------------------------------------------------------------
56
- /** `.cotal/manager.pid` — the running manager's pid. The NAME lives here, in the tier both the CLI
57
- * (which reads it to decide whether to start one) and the manager daemon (which writes it on
58
- * start) already depend on, because a file written under one constant and read under another is
59
- * the same defect as no record at all. */
60
- export const MANAGER_PIDFILE = "manager.pid";
61
- /** `.cotal/manager.delivery-aware` — the sibling marker proving the live manager is a build that
62
- * does NOT host Plane-3. Written and removed with the pidfile; it carries the pid it was written
63
- * for, so a stale marker cannot be paired with a different manager. */
64
- export const MANAGER_DELIVERY_AWARE_MARKER = "manager.delivery-aware";
65
55
  /**
66
56
  * Read one pid's command line.
67
57
  *
package/dist/pid.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"pid.js","sourceRoot":"","sources":["../src/pid.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"pid.js","sourceRoot":"","sources":["../src/pid.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,18 @@
1
+ /** Progress is an outside observation of work product, not the seat's presence heartbeat. */
2
+ export declare const PROGRESS_STALL_MS: number;
3
+ export interface ProgressObservation {
4
+ /** Epoch ms of the last assistant message in the seat's session store. */
5
+ lastAssistantTs: number;
6
+ }
7
+ /** Render-agnostic operator signal. Human wording belongs to each presentation surface. */
8
+ export type ProgressSignal = {
9
+ kind: "unknown";
10
+ } | {
11
+ kind: "fresh";
12
+ ageMs: number;
13
+ } | {
14
+ kind: "stalled";
15
+ ageMs: number;
16
+ };
17
+ export declare function progressSignal(observation: ProgressObservation | undefined, now: number, stallMs?: number): ProgressSignal;
18
+ //# sourceMappingURL=progress.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"progress.d.ts","sourceRoot":"","sources":["../src/progress.ts"],"names":[],"mappings":"AAAA,6FAA6F;AAC7F,eAAO,MAAM,iBAAiB,QAAa,CAAC;AAE5C,MAAM,WAAW,mBAAmB;IAClC,0EAA0E;IAC1E,eAAe,EAAE,MAAM,CAAC;CACzB;AAED,2FAA2F;AAC3F,MAAM,MAAM,cAAc,GACtB;IAAE,IAAI,EAAE,SAAS,CAAA;CAAE,GACnB;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GAChC;IAAE,IAAI,EAAE,SAAS,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC;AAEvC,wBAAgB,cAAc,CAC5B,WAAW,EAAE,mBAAmB,GAAG,SAAS,EAC5C,GAAG,EAAE,MAAM,EACX,OAAO,SAAoB,GAC1B,cAAc,CAIhB"}
@@ -0,0 +1,9 @@
1
+ /** Progress is an outside observation of work product, not the seat's presence heartbeat. */
2
+ export const PROGRESS_STALL_MS = 5 * 60_000;
3
+ export function progressSignal(observation, now, stallMs = PROGRESS_STALL_MS) {
4
+ if (observation === undefined)
5
+ return { kind: "unknown" };
6
+ const ageMs = Math.max(0, now - observation.lastAssistantTs);
7
+ return ageMs > stallMs ? { kind: "stalled", ageMs } : { kind: "fresh", ageMs };
8
+ }
9
+ //# sourceMappingURL=progress.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"progress.js","sourceRoot":"","sources":["../src/progress.ts"],"names":[],"mappings":"AAAA,6FAA6F;AAC7F,MAAM,CAAC,MAAM,iBAAiB,GAAG,CAAC,GAAG,MAAM,CAAC;AAa5C,MAAM,UAAU,cAAc,CAC5B,WAA4C,EAC5C,GAAW,EACX,OAAO,GAAG,iBAAiB;IAE3B,IAAI,WAAW,KAAK,SAAS;QAAE,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,CAAC;IAC1D,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,GAAG,GAAG,WAAW,CAAC,eAAe,CAAC,CAAC;IAC7D,OAAO,KAAK,GAAG,OAAO,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,SAAS,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC;AACjF,CAAC"}
package/dist/renewal.d.ts CHANGED
@@ -7,24 +7,28 @@ import { type Profile, type SecretStore } from "@cotal-ai/core";
7
7
  * preflight-proves each candidate). Machine-local file work lives here in the workspace layer:
8
8
  * implementations never import each other.
9
9
  */
10
- /** The canonical secret-store key of the delivery daemon's scoped cred by the FS convention the
11
- * key IS the filename under `.cotal/`. The single source for every tier (the CLI writer, the
12
- * delivery daemon reader, this renewal owner): a hand-copied drifted literal would silently split
13
- * the kind across two store entries with no compile error. Lives in workspace because the
14
- * key↔filename convention is the workspace layout's; implementations never import each other. */
15
- export declare const DELIVERY_CREDS_KEY = "delivery.creds";
16
- /** The membership feed's data-account rw cred key the same key↔filename discipline as
17
- * {@link DELIVERY_CREDS_KEY}. Named (not a bare literal) so the renewal owner can map a remint
18
- * result back to the daemon's `membership` component without a hand-copied string. */
19
- export declare const MEMBERSHIP_RW_CREDS_KEY = "membership-rw.creds";
20
- /** The seed-less daemon creds files a renewal owner re-signs. The $SYS files
21
- * (membership-observer, connection-evictor) are deliberately ABSENT: they are rotation-renewed —
22
- * no persisted seed can re-sign them, by design. */
10
+ /** The seed-less daemon creds a renewal owner re-signs. The $SYS kinds (membership-observer,
11
+ * connection-evictor) are deliberately ABSENT: they are rotation-renewed no persisted seed can
12
+ * re-sign them, by design. Their keys are {@link membershipObserverCredsKey} /
13
+ * {@link connectionEvictorCredsKey} injectable, but never re-signable from a persisted seed.
14
+ *
15
+ * `key` is a `(space) => key` BUILDER, not a literal, because these kinds are now per-space (§3.1):
16
+ * one entry no longer names one location. `kind` stays beside it because that is what a
17
+ * {@link RemintResult} reports and what an operator reads see {@link RemintResult.file}.
18
+ *
19
+ * The builders are {@link segmentedKey}, NOT the migrating per-kind resolvers: see that function for
20
+ * why the renewal owner is one of the two owners that must not move material. */
23
21
  export declare const REMINTABLE_DAEMON_CREDS: ReadonlyArray<{
24
- file: string;
22
+ kind: string;
23
+ key: (space: string) => string;
25
24
  profile: Profile;
26
25
  }>;
27
26
  export interface RemintResult {
27
+ /** THE KIND, never the segmented key. A remint result is mapped back to a daemon component by
28
+ * literal comparison against the kind (`manager.ts:1147` attributes a fingerprint to
29
+ * `expected.delivery` that way), so a `file` carrying a `space.<hex>/` prefix would match nothing
30
+ * and the manager would silently stop attributing renewals. It is also what `doctor auth` prints,
31
+ * which would otherwise start showing an operator hex. */
28
32
  file: string;
29
33
  /** true = re-signed; false = failed (see error); undefined ok with `skipped` = file absent. */
30
34
  ok: boolean;
@@ -42,7 +46,10 @@ export interface RemintResult {
42
46
  * The manager — the D5 standing-renewal owner, and a hosted-path caller (manager.ts calls this
43
47
  * unconditionally) — passes the SAME store it gives the daemon (its `ManagerOptions.secretStore`),
44
48
  * so a hosted composition re-signs into the store the daemon renews from, never a divergent one; no
45
- * store means the local workspace FS composition (keys = the filenames under `.cotal/`).
49
+ * store means the local workspace FS composition (keys = the paths under `.cotal/`).
50
+ *
51
+ * The creds are PER-SPACE as of P7, so every store op is addressed by the entry's
52
+ * `key(expectedSpace)` builder (§3.1) while every RESULT still reports the entry's `kind`.
46
53
  *
47
54
  * `expectedSpace` (the caller's known space — the manager's `this.space`, doctor's resolved space) is
48
55
  * a REQUIRED positional and is validated against the store's signer: the daemon creds are SPACE-SCOPED,
@@ -1 +1 @@
1
- {"version":3,"file":"renewal.d.ts","sourceRoot":"","sources":["../src/renewal.ts"],"names":[],"mappings":"AAEA,OAAO,EAML,KAAK,OAAO,EACZ,KAAK,WAAW,EAEjB,MAAM,gBAAgB,CAAC;AAIxB;;;;;;;GAOG;AAEH;;;;kGAIkG;AAClG,eAAO,MAAM,kBAAkB,mBAAmB,CAAC;AAEnD;;uFAEuF;AACvF,eAAO,MAAM,uBAAuB,wBAAwB,CAAC;AAE7D;;qDAEqD;AACrD,eAAO,MAAM,uBAAuB,EAAE,aAAa,CAAC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,OAAO,CAAA;CAAE,CAGrF,CAAC;AAEF,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,+FAA+F;IAC/F,EAAE,EAAE,OAAO,CAAC;IACZ,OAAO,CAAC,EAAE,cAAc,GAAG,SAAS,CAAC;IACrC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf;;;4FAGwF;IACxF,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;8DA8B8D;AAC9D,wBAAsB,iBAAiB,CACrC,IAAI,EAAE,MAAM,EACZ,aAAa,EAAE,MAAM,EACrB,KAAK,CAAC,EAAE,WAAW,EACnB,IAAI,CAAC,EAAE;IAAE,SAAS,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,CAAC,CAAA;CAAE,GACzD,OAAO,CAAC,YAAY,EAAE,CAAC,CAsDzB;AAED;;uFAEuF;AACvF,MAAM,WAAW,aAAa;IAC5B,yCAAyC;IACzC,EAAE,EAAE,MAAM,CAAC;IACX,yDAAyD;IACzD,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,YAAY,EAAE,CAAC;IACxB,6FAA6F;IAC7F,QAAQ,CAAC,EAAE;QAAE,EAAE,EAAE,OAAO,CAAC;QAAC,MAAM,CAAC,EAAE,OAAO,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;CAC9D;AAED,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAEtD;AAED,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,aAAa,GAAG,IAAI,CAM5E;AAED,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,GAAG,aAAa,GAAG,SAAS,CAQzE"}
1
+ {"version":3,"file":"renewal.d.ts","sourceRoot":"","sources":["../src/renewal.ts"],"names":[],"mappings":"AAEA,OAAO,EAML,KAAK,OAAO,EACZ,KAAK,WAAW,EAEjB,MAAM,gBAAgB,CAAC;AAKxB;;;;;;;GAOG;AAEH;;;;;;;;;;kFAUkF;AAClF,eAAO,MAAM,uBAAuB,EAAE,aAAa,CAAC;IAClD,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,MAAM,CAAC;IAC/B,OAAO,EAAE,OAAO,CAAC;CAClB,CAGA,CAAC;AAEF,MAAM,WAAW,YAAY;IAC3B;;;;+DAI2D;IAC3D,IAAI,EAAE,MAAM,CAAC;IACb,+FAA+F;IAC/F,EAAE,EAAE,OAAO,CAAC;IACZ,OAAO,CAAC,EAAE,cAAc,GAAG,SAAS,CAAC;IACrC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf;;;4FAGwF;IACxF,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;8DAiC8D;AAC9D,wBAAsB,iBAAiB,CACrC,IAAI,EAAE,MAAM,EACZ,aAAa,EAAE,MAAM,EACrB,KAAK,CAAC,EAAE,WAAW,EACnB,IAAI,CAAC,EAAE;IAAE,SAAS,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,CAAC,CAAA;CAAE,GACzD,OAAO,CAAC,YAAY,EAAE,CAAC,CA0DzB;AAED;;uFAEuF;AACvF,MAAM,WAAW,aAAa;IAC5B,yCAAyC;IACzC,EAAE,EAAE,MAAM,CAAC;IACX,yDAAyD;IACzD,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,YAAY,EAAE,CAAC;IACxB,6FAA6F;IAC7F,QAAQ,CAAC,EAAE;QAAE,EAAE,EAAE,OAAO,CAAC;QAAC,MAAM,CAAC,EAAE,OAAO,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;CAC9D;AAED,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAEtD;AAED,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,aAAa,GAAG,IAAI,CAM5E;AAED,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,GAAG,aAAa,GAAG,SAAS,CAQzE"}