@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.
- package/dist/agent-secrets.d.ts +206 -0
- package/dist/agent-secrets.d.ts.map +1 -0
- package/dist/agent-secrets.js +468 -0
- package/dist/agent-secrets.js.map +1 -0
- package/dist/auth-paths.d.ts +10 -53
- package/dist/auth-paths.d.ts.map +1 -1
- package/dist/auth-paths.js +18 -134
- package/dist/auth-paths.js.map +1 -1
- package/dist/bin-path.d.ts.map +1 -1
- package/dist/bin-path.js +4 -1
- package/dist/bin-path.js.map +1 -1
- package/dist/extensions.d.ts +13 -1
- package/dist/extensions.d.ts.map +1 -1
- package/dist/extensions.js +16 -0
- package/dist/extensions.js.map +1 -1
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -0
- package/dist/index.js.map +1 -1
- package/dist/local-process.d.ts +111 -1
- package/dist/local-process.d.ts.map +1 -1
- package/dist/local-process.js +204 -23
- package/dist/local-process.js.map +1 -1
- package/dist/pid.d.ts +0 -9
- package/dist/pid.d.ts.map +1 -1
- package/dist/pid.js +0 -10
- package/dist/pid.js.map +1 -1
- package/dist/progress.d.ts +18 -0
- package/dist/progress.d.ts.map +1 -0
- package/dist/progress.js +9 -0
- package/dist/progress.js.map +1 -0
- package/dist/renewal.d.ts +22 -15
- package/dist/renewal.d.ts.map +1 -1
- package/dist/renewal.js +27 -21
- package/dist/renewal.js.map +1 -1
- package/dist/space-segmentation.d.ts +260 -0
- package/dist/space-segmentation.d.ts.map +1 -0
- package/dist/space-segmentation.js +428 -0
- package/dist/space-segmentation.js.map +1 -0
- package/dist/space.d.ts +19 -0
- package/dist/space.d.ts.map +1 -1
- package/dist/space.js +31 -0
- package/dist/space.js.map +1 -1
- package/dist/system-rotation.d.ts +7 -6
- package/dist/system-rotation.d.ts.map +1 -1
- package/dist/system-rotation.js +25 -10
- package/dist/system-rotation.js.map +1 -1
- package/package.json +2 -2
package/dist/local-process.d.ts
CHANGED
|
@@ -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
|
-
/**
|
|
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;
|
|
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"}
|
package/dist/local-process.js
CHANGED
|
@@ -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
|
-
|
|
5
|
-
|
|
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
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
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
|
-
|
|
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;
|
|
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;
|
|
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":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAEH,OAAO,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAC/C,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAEvC;;;wCAGwC;AACxC,MAAM,UAAU,QAAQ,CAAC,GAAW;IAClC,MAAM,CAAC,GAAG,MAAM,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC,CAAC;IAC7B,OAAO,MAAM,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;AACzE,CAAC;AAED;;;;;;;;sDAQsD;AACtD,MAAM,UAAU,iBAAiB,CAAC,IAAwB;IACxD,IAAI,IAAI,KAAK,OAAO;QAAE,OAAO,MAAM,CAAC;IACpC,IAAI,IAAI,KAAK,OAAO;QAAE,OAAO,OAAO,CAAC,CAAC,kCAAkC;IACxE,OAAO,SAAS,CAAC,CAAC,6EAA6E;AACjG,CAAC;AAgBD,MAAM,UAAU,aAAa,CAAC,GAAW;IACvC,IAAI,CAAC;QACH,OAAO,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC;QACrB,OAAO,OAAO,CAAC;IACjB,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC;QACX,OAAO,iBAAiB,CAAE,CAA2B,CAAC,IAAI,CAAC,CAAC;IAC9D,CAAC;AACH,CAAC;
|
|
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"}
|
package/dist/progress.js
ADDED
|
@@ -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
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
* {@link
|
|
18
|
-
*
|
|
19
|
-
|
|
20
|
-
|
|
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
|
-
|
|
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
|
|
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,
|
package/dist/renewal.d.ts.map
CHANGED
|
@@ -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;
|
|
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"}
|