@sentropic/h2a 0.97.2 → 0.97.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/.claude-plugin/plugin.json +1 -1
- package/.codex-plugin/plugin.json +1 -1
- package/dist/bin.js +13 -0
- package/dist/bin.js.map +1 -1
- package/dist/cli.d.ts +13 -0
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +94 -37
- package/dist/cli.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/mcp.d.ts +1 -1
- package/dist/mcp.d.ts.map +1 -1
- package/dist/mcp.js +2 -0
- package/dist/mcp.js.map +1 -1
- package/dist/runtime/identity/bindings.d.ts +33 -0
- package/dist/runtime/identity/bindings.d.ts.map +1 -1
- package/dist/runtime/identity/bindings.js +65 -2
- package/dist/runtime/identity/bindings.js.map +1 -1
- package/dist/runtime/identity/index.d.ts +4 -4
- package/dist/runtime/identity/index.d.ts.map +1 -1
- package/dist/runtime/identity/index.js +2 -2
- package/dist/runtime/identity/index.js.map +1 -1
- package/dist/runtime/identity/live.d.ts +63 -0
- package/dist/runtime/identity/live.d.ts.map +1 -1
- package/dist/runtime/identity/live.js +346 -65
- package/dist/runtime/identity/live.js.map +1 -1
- package/dist/runtime/identity/worker.d.ts +19 -0
- package/dist/runtime/identity/worker.d.ts.map +1 -0
- package/dist/runtime/identity/worker.js +189 -0
- package/dist/runtime/identity/worker.js.map +1 -0
- package/dist/runtime/local-files/locks.d.ts +34 -0
- package/dist/runtime/local-files/locks.d.ts.map +1 -1
- package/dist/runtime/local-files/locks.js +55 -2
- package/dist/runtime/local-files/locks.js.map +1 -1
- package/dist/runtime/local-files/store.d.ts +21 -0
- package/dist/runtime/local-files/store.d.ts.map +1 -1
- package/dist/runtime/local-files/store.js +79 -10
- package/dist/runtime/local-files/store.js.map +1 -1
- package/dist/runtime/mcp/discovery-pagination.d.ts +73 -0
- package/dist/runtime/mcp/discovery-pagination.d.ts.map +1 -0
- package/dist/runtime/mcp/discovery-pagination.js +446 -0
- package/dist/runtime/mcp/discovery-pagination.js.map +1 -0
- package/dist/runtime/mcp/frame-budget.d.ts +149 -0
- package/dist/runtime/mcp/frame-budget.d.ts.map +1 -0
- package/dist/runtime/mcp/frame-budget.js +275 -0
- package/dist/runtime/mcp/frame-budget.js.map +1 -0
- package/dist/runtime/mcp/handlers.d.ts +14 -3
- package/dist/runtime/mcp/handlers.d.ts.map +1 -1
- package/dist/runtime/mcp/handlers.js +22 -1
- package/dist/runtime/mcp/handlers.js.map +1 -1
- package/dist/runtime/mcp/identity-state.d.ts +131 -0
- package/dist/runtime/mcp/identity-state.d.ts.map +1 -0
- package/dist/runtime/mcp/identity-state.js +288 -0
- package/dist/runtime/mcp/identity-state.js.map +1 -0
- package/dist/runtime/mcp/index.d.ts +2 -0
- package/dist/runtime/mcp/index.d.ts.map +1 -1
- package/dist/runtime/mcp/index.js +2 -0
- package/dist/runtime/mcp/index.js.map +1 -1
- package/dist/runtime/mcp/notifications.d.ts +13 -1
- package/dist/runtime/mcp/notifications.d.ts.map +1 -1
- package/dist/runtime/mcp/notifications.js +36 -20
- package/dist/runtime/mcp/notifications.js.map +1 -1
- package/dist/runtime/mcp/payload-store.d.ts +67 -0
- package/dist/runtime/mcp/payload-store.d.ts.map +1 -0
- package/dist/runtime/mcp/payload-store.js +242 -0
- package/dist/runtime/mcp/payload-store.js.map +1 -0
- package/dist/runtime/mcp/phase-trace.d.ts +98 -0
- package/dist/runtime/mcp/phase-trace.d.ts.map +1 -0
- package/dist/runtime/mcp/phase-trace.js +179 -0
- package/dist/runtime/mcp/phase-trace.js.map +1 -0
- package/dist/runtime/mcp/server.d.ts +36 -1
- package/dist/runtime/mcp/server.d.ts.map +1 -1
- package/dist/runtime/mcp/server.js +162 -5
- package/dist/runtime/mcp/server.js.map +1 -1
- package/dist/runtime/mcp/sessions.d.ts +12 -2
- package/dist/runtime/mcp/sessions.d.ts.map +1 -1
- package/dist/runtime/mcp/sessions.js +15 -3
- package/dist/runtime/mcp/sessions.js.map +1 -1
- package/dist/runtime/mcp/stdio.d.ts +21 -0
- package/dist/runtime/mcp/stdio.d.ts.map +1 -1
- package/dist/runtime/mcp/stdio.js +378 -98
- package/dist/runtime/mcp/stdio.js.map +1 -1
- package/dist/runtime/mcp/tools.d.ts.map +1 -1
- package/dist/runtime/mcp/tools.js +47 -4
- package/dist/runtime/mcp/tools.js.map +1 -1
- package/dist/runtime/mcp-central.d.ts.map +1 -1
- package/dist/runtime/mcp-central.js +17 -7
- package/dist/runtime/mcp-central.js.map +1 -1
- package/dist/runtime/mcp-http/hosted-mcp-server.d.ts.map +1 -1
- package/dist/runtime/mcp-http/hosted-mcp-server.js +16 -6
- package/dist/runtime/mcp-http/hosted-mcp-server.js.map +1 -1
- package/dist/runtime/mcp-http/readonly-allowlist.d.ts.map +1 -1
- package/dist/runtime/mcp-http/readonly-allowlist.js +6 -0
- package/dist/runtime/mcp-http/readonly-allowlist.js.map +1 -1
- package/package.json +3 -3
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* L2 identity worker — the dedicated, non-detached child that resolves the
|
|
3
|
+
* shared identity OFF the parent's MCP event loop.
|
|
4
|
+
*
|
|
5
|
+
* It receives ONE typed request over IPC, runs the canonical async resolution
|
|
6
|
+
* (the same writer path as the CLI — `resolveLiveIdentityAsync`, whose only
|
|
7
|
+
* append of a binding row is `reclaimOrMint*`), and returns ONE response. It
|
|
8
|
+
* publishes NO presence, NO tool signature, NO wake, NO readiness ACK; those are
|
|
9
|
+
* the parent's job after it validates the result. No PEM ever crosses IPC — only
|
|
10
|
+
* paths, which the parent re-validates against the canonical key layout.
|
|
11
|
+
*
|
|
12
|
+
* It is argv-only (the request arrives over IPC), stdout is ignored (it must
|
|
13
|
+
* never emit protocol traffic), and diagnostics go to stderr. A cancel makes it
|
|
14
|
+
* stop starting any NEW transaction (cooperative); a transaction already entered
|
|
15
|
+
* under a lock finishes so no half-written binding is left, and the lock is
|
|
16
|
+
* released in the resolver's `finally`.
|
|
17
|
+
*/
|
|
18
|
+
import { resolveLiveIdentityAsync } from "./live.js";
|
|
19
|
+
import { LockCancelledError, LockTimeoutError } from "../local-files/locks.js";
|
|
20
|
+
import { createMcpTrace, setActiveMcpTrace } from "../mcp/phase-trace.js";
|
|
21
|
+
function classify(err) {
|
|
22
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
23
|
+
if (err instanceof LockCancelledError) {
|
|
24
|
+
return { cause: "identity_timeout", message };
|
|
25
|
+
}
|
|
26
|
+
const code = err?.code;
|
|
27
|
+
if (code === "EROFS")
|
|
28
|
+
return { cause: "storage_readonly", message };
|
|
29
|
+
if (code === "EACCES" || code === "EPERM")
|
|
30
|
+
return { cause: "storage_permission_denied", message };
|
|
31
|
+
if (err instanceof Error && err.name === "LockTimeoutError") {
|
|
32
|
+
return { cause: "identity_timeout", message };
|
|
33
|
+
}
|
|
34
|
+
// A generic durable-store write failure vs. an unexpected worker fault.
|
|
35
|
+
if (code === "ENOSPC" || code === "EIO")
|
|
36
|
+
return { cause: "identity_storage_failed", message };
|
|
37
|
+
return { cause: "identity_worker_failed", message };
|
|
38
|
+
}
|
|
39
|
+
function send(message) {
|
|
40
|
+
try {
|
|
41
|
+
process.send?.(message);
|
|
42
|
+
}
|
|
43
|
+
catch {
|
|
44
|
+
/* the parent may have closed the channel; nothing more we can do */
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
const abort = new AbortController();
|
|
48
|
+
let handled = false;
|
|
49
|
+
process.on("message", (raw) => {
|
|
50
|
+
const msg = raw;
|
|
51
|
+
if (!msg || typeof msg !== "object")
|
|
52
|
+
return;
|
|
53
|
+
if (msg.kind === "cancel") {
|
|
54
|
+
// Cooperative: stop before any NEW transaction. A transaction already under a
|
|
55
|
+
// lock finishes; its `finally` releases the lock.
|
|
56
|
+
abort.abort(msg.reason ?? "cancel");
|
|
57
|
+
send({ kind: "cancel_ack", v: 1 });
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
if (msg.kind !== "resolve_identity" || handled)
|
|
61
|
+
return;
|
|
62
|
+
handled = true;
|
|
63
|
+
const req = msg;
|
|
64
|
+
// L0 (#249): relocate the identity/lock/registry instrumentation that used to
|
|
65
|
+
// run on the parent. Installing a correlated `identity-child` trace (same
|
|
66
|
+
// attemptId as the parent) makes resolveLiveIdentityAsync's provider/keys/
|
|
67
|
+
// register/alias spans, the registry_read span, and the binding-lock spans
|
|
68
|
+
// fire HERE (on the worker's stderr, which the parent forwards line by line),
|
|
69
|
+
// instead of being silently lost when resolution moved off the parent loop.
|
|
70
|
+
setActiveMcpTrace(createMcpTrace({
|
|
71
|
+
role: "identity-child",
|
|
72
|
+
...(req.traceAttemptId !== undefined ? { attemptId: req.traceAttemptId } : {}),
|
|
73
|
+
pid: process.pid
|
|
74
|
+
}));
|
|
75
|
+
const input = {
|
|
76
|
+
root: req.request.root,
|
|
77
|
+
host: req.request.host,
|
|
78
|
+
cwd: req.request.cwd,
|
|
79
|
+
...(req.request.explicitInstance !== undefined
|
|
80
|
+
? { explicitInstance: req.request.explicitInstance }
|
|
81
|
+
: {}),
|
|
82
|
+
...(req.request.name !== undefined ? { name: req.request.name } : {}),
|
|
83
|
+
...(req.request.scopes !== undefined ? { scopes: req.request.scopes } : {}),
|
|
84
|
+
...(req.request.declaredCapabilities !== undefined
|
|
85
|
+
? { declaredCapabilities: req.request.declaredCapabilities }
|
|
86
|
+
: {})
|
|
87
|
+
};
|
|
88
|
+
const budgetMs = Number.isFinite(req.budgetMs) && req.budgetMs > 0 ? req.budgetMs : 20_000;
|
|
89
|
+
const startNs = process.hrtime.bigint();
|
|
90
|
+
const remainingMs = () => budgetMs - Number((process.hrtime.bigint() - startNs) / 1000000n);
|
|
91
|
+
const cancellableDelay = (ms) => new Promise((resolve) => {
|
|
92
|
+
if (abort.signal.aborted)
|
|
93
|
+
return resolve();
|
|
94
|
+
const timer = setTimeout(resolve, ms);
|
|
95
|
+
const onAbort = () => {
|
|
96
|
+
clearTimeout(timer);
|
|
97
|
+
resolve();
|
|
98
|
+
};
|
|
99
|
+
abort.signal.addEventListener("abort", onAbort, { once: true });
|
|
100
|
+
});
|
|
101
|
+
// Retry on CONTENTION (a live lock holder) until the budget, ceding the event
|
|
102
|
+
// loop between attempts so an IPC cancel is honored; the parent's 20 s deadline
|
|
103
|
+
// is authoritative. A PERMANENT error (EROFS / EACCES / …) is NOT retried — it
|
|
104
|
+
// is the failure. `reclaimOrMint*` stays the unique binding writer across
|
|
105
|
+
// attempts; a contended attempt writes no binding (it releases the lock first).
|
|
106
|
+
// Shared across attempts: the mint candidate is generated once (no keypair
|
|
107
|
+
// leak) and the expensive OUTSIDE-lock reads are parsed once (no re-parse of
|
|
108
|
+
// the ~17 MB registry per retry under contention).
|
|
109
|
+
const mintMemo = {};
|
|
110
|
+
const prepCache = {};
|
|
111
|
+
let attempt = 0;
|
|
112
|
+
const resolveWithRetry = async () => {
|
|
113
|
+
while (!abort.signal.aborted) {
|
|
114
|
+
const budget = remainingMs();
|
|
115
|
+
if (budget <= 0)
|
|
116
|
+
throw new LockTimeoutError("identity", undefined, budgetMs);
|
|
117
|
+
try {
|
|
118
|
+
return await resolveLiveIdentityAsync(input, {
|
|
119
|
+
signal: abort.signal,
|
|
120
|
+
deadlineMs: budget,
|
|
121
|
+
// Fail a contended registration fast so the identity lock is not held
|
|
122
|
+
// through a long registry wait; the loop retries outside the section.
|
|
123
|
+
registryLockTimeoutMs: 250,
|
|
124
|
+
mintMemo,
|
|
125
|
+
prepCache,
|
|
126
|
+
attempt
|
|
127
|
+
});
|
|
128
|
+
}
|
|
129
|
+
catch (err) {
|
|
130
|
+
attempt += 1;
|
|
131
|
+
if (abort.signal.aborted)
|
|
132
|
+
throw err;
|
|
133
|
+
if (err instanceof LockTimeoutError && remainingMs() > 0) {
|
|
134
|
+
await cancellableDelay(200);
|
|
135
|
+
continue;
|
|
136
|
+
}
|
|
137
|
+
throw err;
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
throw new LockCancelledError("identity", "cancelled");
|
|
141
|
+
};
|
|
142
|
+
void resolveWithRetry()
|
|
143
|
+
.then((identity) => {
|
|
144
|
+
send({
|
|
145
|
+
kind: "identity_resolved",
|
|
146
|
+
v: 1,
|
|
147
|
+
identity: {
|
|
148
|
+
instance: identity.instance,
|
|
149
|
+
host: identity.host,
|
|
150
|
+
...(identity.workspace !== undefined ? { workspace: identity.workspace } : {}),
|
|
151
|
+
...(identity.name !== undefined ? { name: identity.name } : {}),
|
|
152
|
+
action: identity.action,
|
|
153
|
+
...(identity.providerSessionId !== undefined
|
|
154
|
+
? { providerSessionId: identity.providerSessionId }
|
|
155
|
+
: {}),
|
|
156
|
+
...(identity.providerSessionSource !== undefined
|
|
157
|
+
? { providerSessionSource: identity.providerSessionSource }
|
|
158
|
+
: {}),
|
|
159
|
+
// Paths only — the parent re-validates them against identityKeyPaths.
|
|
160
|
+
privateKeyPath: identity.privateKeyPath ?? "",
|
|
161
|
+
publicKeyPath: identity.publicKeyPath ?? "",
|
|
162
|
+
...(identity.migrationNotice !== undefined
|
|
163
|
+
? { migrationNotice: identity.migrationNotice }
|
|
164
|
+
: {}),
|
|
165
|
+
...(identity.legacyInstance !== undefined
|
|
166
|
+
? { legacyInstance: identity.legacyInstance }
|
|
167
|
+
: {}),
|
|
168
|
+
// Only a locally-derived identity (no explicit --instance) may attest a
|
|
169
|
+
// delegation; an explicit label never becomes an ownership attestation.
|
|
170
|
+
delegationEligible: req.request.explicitInstance === undefined
|
|
171
|
+
}
|
|
172
|
+
});
|
|
173
|
+
})
|
|
174
|
+
.catch((err) => {
|
|
175
|
+
const { cause, message } = classify(err);
|
|
176
|
+
send({ kind: "identity_error", v: 1, cause, message });
|
|
177
|
+
})
|
|
178
|
+
.finally(() => {
|
|
179
|
+
// The worker's whole job is one resolution; exit so no orphan lingers to
|
|
180
|
+
// start another transaction. Give the IPC a tick to flush.
|
|
181
|
+
setTimeout(() => process.exit(0), 10).unref?.();
|
|
182
|
+
});
|
|
183
|
+
});
|
|
184
|
+
// If the parent's channel closes before a result, exit rather than linger.
|
|
185
|
+
process.on("disconnect", () => {
|
|
186
|
+
abort.abort("disconnect");
|
|
187
|
+
setTimeout(() => process.exit(0), 50).unref?.();
|
|
188
|
+
});
|
|
189
|
+
//# sourceMappingURL=worker.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"worker.js","sourceRoot":"","sources":["../../../src/runtime/identity/worker.ts"],"names":[],"mappings":"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"}
|
|
@@ -24,6 +24,20 @@
|
|
|
24
24
|
* unlinking and retrying. Otherwise we poll up to `timeoutMs` and throw
|
|
25
25
|
* `LockTimeoutError`.
|
|
26
26
|
*/
|
|
27
|
+
/**
|
|
28
|
+
* A passive observation of a lock critical section, for the L0 phase trace.
|
|
29
|
+
* `lock` is a LOGICAL id (the lock's parent directory name, e.g. `registry` /
|
|
30
|
+
* `identity`) — never the lock owner payload or any binding content. Emitting
|
|
31
|
+
* an observation never changes the lock's timeout, poll or reclaim policy, and
|
|
32
|
+
* a throwing observer can never break the critical section.
|
|
33
|
+
*/
|
|
34
|
+
export interface LockObservation {
|
|
35
|
+
readonly lock: string;
|
|
36
|
+
readonly event: "wait" | "acquired" | "released" | "timeout";
|
|
37
|
+
readonly waitMs?: number;
|
|
38
|
+
readonly holdMs?: number;
|
|
39
|
+
readonly attempts?: number;
|
|
40
|
+
}
|
|
27
41
|
export interface LockOwner {
|
|
28
42
|
readonly pid: number;
|
|
29
43
|
readonly hostname: string;
|
|
@@ -47,6 +61,26 @@ export interface WithLockOptions {
|
|
|
47
61
|
* reason to silently continue.
|
|
48
62
|
*/
|
|
49
63
|
readonly reclaimStale?: boolean;
|
|
64
|
+
/**
|
|
65
|
+
* Passive instrumentation hook (L0). Called on `wait` (once, before the first
|
|
66
|
+
* acquire attempt), `acquired` (with `waitMs`/`attempts`), `released` (with
|
|
67
|
+
* `holdMs`) and `timeout` (with `waitMs`). It cannot change locking behaviour.
|
|
68
|
+
*/
|
|
69
|
+
readonly observe?: (event: LockObservation) => void;
|
|
70
|
+
/**
|
|
71
|
+
* L2 cooperative cancellation (async `withLock` only). When aborted while
|
|
72
|
+
* WAITING for the lock, the wait stops and `withLock` rejects with a
|
|
73
|
+
* `LockCancelledError` — the worker then stops before entering a new critical
|
|
74
|
+
* section. Once the lock is HELD, `fn` runs to completion (a transaction
|
|
75
|
+
* already entered finishes cleanly); the signal never interrupts a held
|
|
76
|
+
* section, so no half-written state is left behind.
|
|
77
|
+
*/
|
|
78
|
+
readonly signal?: AbortSignal;
|
|
79
|
+
}
|
|
80
|
+
/** Thrown by the async `withLock` when its signal aborts DURING the wait. */
|
|
81
|
+
export declare class LockCancelledError extends Error {
|
|
82
|
+
readonly lockPath: string;
|
|
83
|
+
constructor(lockPath: string, reason?: string);
|
|
50
84
|
}
|
|
51
85
|
export declare class LockTimeoutError extends Error {
|
|
52
86
|
readonly lockPath: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"locks.d.ts","sourceRoot":"","sources":["../../../src/runtime/local-files/locks.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;
|
|
1
|
+
{"version":3,"file":"locks.d.ts","sourceRoot":"","sources":["../../../src/runtime/local-files/locks.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AAMH;;;;;;GAMG;AACH,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,UAAU,GAAG,UAAU,GAAG,SAAS,CAAC;IAC7D,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;CAC5B;AAuBD,MAAM,WAAW,SAAS;IACxB,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,4EAA4E;IAC5E,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAC3B,8DAA8D;IAC9D,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;CAC9B;AAED,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IACzB;;;OAGG;IACH,QAAQ,CAAC,aAAa,CAAC,EAAE,QAAQ,CAAC,IAAI,CAAC,SAAS,EAAE,UAAU,GAAG,YAAY,CAAC,CAAC,CAAC;IAC9E;;;;OAIG;IACH,QAAQ,CAAC,YAAY,CAAC,EAAE,OAAO,CAAC;IAChC;;;;OAIG;IACH,QAAQ,CAAC,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,eAAe,KAAK,IAAI,CAAC;IACpD;;;;;;;OAOG;IACH,QAAQ,CAAC,MAAM,CAAC,EAAE,WAAW,CAAC;CAC/B;AAED,6EAA6E;AAC7E,qBAAa,kBAAmB,SAAQ,KAAK;IAC3C,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;gBACd,QAAQ,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM;CAK9C;AAED,qBAAa,gBAAiB,SAAQ,KAAK;IACzC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,aAAa,CAAC,EAAE,SAAS,CAAC;gBAEvB,QAAQ,EAAE,MAAM,EAAE,aAAa,EAAE,SAAS,GAAG,SAAS,EAAE,SAAS,EAAE,MAAM;CAWtF;AAgHD,wBAAsB,QAAQ,CAAC,CAAC,EAC9B,QAAQ,EAAE,MAAM,EAChB,EAAE,EAAE,MAAM,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,EACxB,OAAO,GAAE,eAAoB,GAC5B,OAAO,CAAC,CAAC,CAAC,CAwCZ;AAED,wBAAgB,YAAY,CAAC,CAAC,EAC5B,QAAQ,EAAE,MAAM,EAChB,EAAE,EAAE,MAAM,CAAC,EACX,OAAO,GAAE,eAAoB,GAC5B,CAAC,CAoCH"}
|
|
@@ -26,6 +26,35 @@
|
|
|
26
26
|
*/
|
|
27
27
|
import { closeSync, openSync, readFileSync, unlinkSync, writeFileSync } from "node:fs";
|
|
28
28
|
import { hostname } from "node:os";
|
|
29
|
+
import { basename, dirname } from "node:path";
|
|
30
|
+
function logicalLockId(lockPath) {
|
|
31
|
+
try {
|
|
32
|
+
const label = basename(dirname(lockPath)) || basename(lockPath);
|
|
33
|
+
return label.length > 64 ? label.slice(0, 64) : label;
|
|
34
|
+
}
|
|
35
|
+
catch {
|
|
36
|
+
return "lock";
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
function notifyObserver(observe, event) {
|
|
40
|
+
if (!observe)
|
|
41
|
+
return;
|
|
42
|
+
try {
|
|
43
|
+
observe(event);
|
|
44
|
+
}
|
|
45
|
+
catch {
|
|
46
|
+
/* a passive observer must never disturb the critical section */
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
/** Thrown by the async `withLock` when its signal aborts DURING the wait. */
|
|
50
|
+
export class LockCancelledError extends Error {
|
|
51
|
+
lockPath;
|
|
52
|
+
constructor(lockPath, reason) {
|
|
53
|
+
super(`LockCancelledError: acquisition of ${lockPath} was cancelled${reason ? ` (${reason})` : ""}`);
|
|
54
|
+
this.name = "LockCancelledError";
|
|
55
|
+
this.lockPath = lockPath;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
29
58
|
export class LockTimeoutError extends Error {
|
|
30
59
|
lockPath;
|
|
31
60
|
lastSeenOwner;
|
|
@@ -149,22 +178,36 @@ export async function withLock(lockPath, fn, options = {}) {
|
|
|
149
178
|
const timeoutMs = options.timeoutMs ?? DEFAULT_TIMEOUT_MS;
|
|
150
179
|
const pollMs = options.pollMs ?? DEFAULT_POLL_MS;
|
|
151
180
|
const selfHostname = hostname();
|
|
152
|
-
const
|
|
181
|
+
const observe = options.observe;
|
|
182
|
+
const lock = observe ? logicalLockId(lockPath) : "";
|
|
183
|
+
const startedAt = Date.now();
|
|
184
|
+
const deadline = startedAt + timeoutMs;
|
|
153
185
|
let lastSeen;
|
|
186
|
+
let attempts = 0;
|
|
187
|
+
notifyObserver(observe, { lock, event: "wait" });
|
|
154
188
|
while (true) {
|
|
189
|
+
if (options.signal?.aborted) {
|
|
190
|
+
notifyObserver(observe, { lock, event: "timeout", waitMs: Date.now() - startedAt, attempts });
|
|
191
|
+
throw new LockCancelledError(lockPath, String(options.signal.reason ?? "aborted"));
|
|
192
|
+
}
|
|
193
|
+
attempts++;
|
|
155
194
|
const attempt = acquire(lockPath, selfHostname, options);
|
|
156
195
|
if (attempt.ok)
|
|
157
196
|
break;
|
|
158
197
|
lastSeen = attempt.lastSeen ?? lastSeen;
|
|
159
198
|
if (Date.now() >= deadline) {
|
|
199
|
+
notifyObserver(observe, { lock, event: "timeout", waitMs: Date.now() - startedAt, attempts });
|
|
160
200
|
throw new LockTimeoutError(lockPath, lastSeen, timeoutMs);
|
|
161
201
|
}
|
|
162
202
|
await delay(pollMs);
|
|
163
203
|
}
|
|
204
|
+
const acquiredAt = Date.now();
|
|
205
|
+
notifyObserver(observe, { lock, event: "acquired", waitMs: acquiredAt - startedAt, attempts });
|
|
164
206
|
try {
|
|
165
207
|
return await fn();
|
|
166
208
|
}
|
|
167
209
|
finally {
|
|
210
|
+
notifyObserver(observe, { lock, event: "released", holdMs: Date.now() - acquiredAt });
|
|
168
211
|
try {
|
|
169
212
|
unlinkSync(lockPath);
|
|
170
213
|
}
|
|
@@ -177,22 +220,32 @@ export function withLockSync(lockPath, fn, options = {}) {
|
|
|
177
220
|
const timeoutMs = options.timeoutMs ?? DEFAULT_TIMEOUT_MS;
|
|
178
221
|
const pollMs = options.pollMs ?? DEFAULT_POLL_MS;
|
|
179
222
|
const selfHostname = hostname();
|
|
180
|
-
const
|
|
223
|
+
const observe = options.observe;
|
|
224
|
+
const lock = observe ? logicalLockId(lockPath) : "";
|
|
225
|
+
const startedAt = Date.now();
|
|
226
|
+
const deadline = startedAt + timeoutMs;
|
|
181
227
|
let lastSeen;
|
|
228
|
+
let attempts = 0;
|
|
229
|
+
notifyObserver(observe, { lock, event: "wait" });
|
|
182
230
|
while (true) {
|
|
231
|
+
attempts++;
|
|
183
232
|
const attempt = acquire(lockPath, selfHostname, options);
|
|
184
233
|
if (attempt.ok)
|
|
185
234
|
break;
|
|
186
235
|
lastSeen = attempt.lastSeen ?? lastSeen;
|
|
187
236
|
if (Date.now() >= deadline) {
|
|
237
|
+
notifyObserver(observe, { lock, event: "timeout", waitMs: Date.now() - startedAt, attempts });
|
|
188
238
|
throw new LockTimeoutError(lockPath, lastSeen, timeoutMs);
|
|
189
239
|
}
|
|
190
240
|
busyWaitSync(pollMs);
|
|
191
241
|
}
|
|
242
|
+
const acquiredAt = Date.now();
|
|
243
|
+
notifyObserver(observe, { lock, event: "acquired", waitMs: acquiredAt - startedAt, attempts });
|
|
192
244
|
try {
|
|
193
245
|
return fn();
|
|
194
246
|
}
|
|
195
247
|
finally {
|
|
248
|
+
notifyObserver(observe, { lock, event: "released", holdMs: Date.now() - acquiredAt });
|
|
196
249
|
try {
|
|
197
250
|
unlinkSync(lockPath);
|
|
198
251
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"locks.js","sourceRoot":"","sources":["../../../src/runtime/local-files/locks.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AAEH,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,YAAY,EAAE,UAAU,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AACvF,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;
|
|
1
|
+
{"version":3,"file":"locks.js","sourceRoot":"","sources":["../../../src/runtime/local-files/locks.ts"],"names":[],"mappings":"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"}
|
|
@@ -28,6 +28,27 @@ export interface CreateLocalStoreOptions {
|
|
|
28
28
|
* critical section plus inter-host clock skew. Default 30000.
|
|
29
29
|
*/
|
|
30
30
|
leaseMs?: number;
|
|
31
|
+
/**
|
|
32
|
+
* L2: when `false`, DO NOT create the store layout — no directory, no schema
|
|
33
|
+
* sentinel, no empty `instances.jsonl`. An existing sentinel is still read and
|
|
34
|
+
* validated; an absent root simply yields empty reads (a genuinely unreadable
|
|
35
|
+
* file is NOT flattened to an empty list). Used by the MCP transport so
|
|
36
|
+
* `initialize` / `tools/list` / `h2a_identity_status` and every read-only tool
|
|
37
|
+
* answer on a read-only or not-yet-created root, before identity is ready.
|
|
38
|
+
* Default `true` (unchanged behavior for every existing caller).
|
|
39
|
+
*/
|
|
40
|
+
initialize?: boolean;
|
|
41
|
+
/**
|
|
42
|
+
* L2: when `true`, every mutating method refuses with a typed
|
|
43
|
+
* `StorageReadonlyError` ("storage_readonly") instead of attempting a write.
|
|
44
|
+
* Read paths are unaffected. Default `false`.
|
|
45
|
+
*/
|
|
46
|
+
readOnly?: boolean;
|
|
47
|
+
}
|
|
48
|
+
/** L2: a mutator refused because the store was opened read-only. */
|
|
49
|
+
export declare class StorageReadonlyError extends Error {
|
|
50
|
+
readonly code = "storage_readonly";
|
|
51
|
+
constructor(operation: string);
|
|
31
52
|
}
|
|
32
53
|
/**
|
|
33
54
|
* An append-only audit event for a subagent (DEC-071). Distinct from the
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"store.d.ts","sourceRoot":"","sources":["../../../src/runtime/local-files/store.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"store.d.ts","sourceRoot":"","sources":["../../../src/runtime/local-files/store.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,11 +1,20 @@
|
|
|
1
|
-
import { appendFileSync, existsSync, mkdirSync, readFileSync, readdirSync, unlinkSync, writeFileSync } from "node:fs";
|
|
1
|
+
import { appendFileSync, existsSync, mkdirSync, readFileSync, readdirSync, statSync, unlinkSync, writeFileSync } from "node:fs";
|
|
2
2
|
import { dirname, join } from "node:path";
|
|
3
3
|
import { H2A_ARTIFACT_KINDS, H2A_AUTHORITY_MATRIX, H2A_DECLARATION_INTERET_BODY_KIND, appendJournalEntry, assertValidNegotiationState, canSignArtifactKind, computeHash, createJournalEntry, deriveDecisionDossier as deriveDecisionDossierCore, derivePostureConflit, derivePostureConfiance as derivePostureConfianceCore, evaluatePresenterBias, isH2AEnvelope, validateH2AEnvelope, isH2ADeclarationInteret, validateSubagentBinding, verifyCanonical, verifyJournalChain } from "@sentropic/h2a";
|
|
4
4
|
import { withLockSync } from "./locks.js";
|
|
5
5
|
import { withLeaseSync } from "./lease.js";
|
|
6
|
+
import { getActiveMcpTrace } from "../mcp/phase-trace.js";
|
|
6
7
|
import { inboxDir, inboxDirRaw, localStorePaths, negotiationDir, negotiationJournalFile, outboxDir, outboxDirRaw, safePathSegment } from "./paths.js";
|
|
7
8
|
import { H2A_STORE_SCHEMA_FILE, H2A_STORE_SCHEMA_VERSION, StoreSchemaMismatchError, readCliPackageVersion } from "./schema.js";
|
|
8
9
|
import { listIdentityAliases, mergeInboxDedup } from "../identity/migration.js";
|
|
10
|
+
/** L2: a mutator refused because the store was opened read-only. */
|
|
11
|
+
export class StorageReadonlyError extends Error {
|
|
12
|
+
code = "storage_readonly";
|
|
13
|
+
constructor(operation) {
|
|
14
|
+
super(`storage_readonly: ${operation} refused on a read-only store`);
|
|
15
|
+
this.name = "StorageReadonlyError";
|
|
16
|
+
}
|
|
17
|
+
}
|
|
9
18
|
function ensureDir(path) {
|
|
10
19
|
mkdirSync(path, { recursive: true });
|
|
11
20
|
}
|
|
@@ -122,12 +131,32 @@ function envLeaseMs() {
|
|
|
122
131
|
}
|
|
123
132
|
export function createLocalStore(options) {
|
|
124
133
|
const paths = localStorePaths(options.root);
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
134
|
+
const initialize = options.initialize !== false;
|
|
135
|
+
const readOnly = options.readOnly === true;
|
|
136
|
+
if (initialize) {
|
|
137
|
+
ensureLayout(paths);
|
|
138
|
+
ensureSchemaSentinel(paths.root, {
|
|
139
|
+
allowVersionMismatch: options.allowVersionMismatch === true
|
|
140
|
+
});
|
|
141
|
+
if (!existsSync(paths.instances)) {
|
|
142
|
+
writeFileSync(paths.instances, "", { encoding: "utf8" });
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
else {
|
|
146
|
+
// Non-initializing open (L2): create nothing. Only VALIDATE a sentinel that
|
|
147
|
+
// already exists — an incompatible one still fails closed (an unsupported
|
|
148
|
+
// schema is a refusal, never a silent write); an absent one is left absent.
|
|
149
|
+
if (existsSync(join(paths.root, H2A_STORE_SCHEMA_FILE))) {
|
|
150
|
+
ensureSchemaSentinel(paths.root, {
|
|
151
|
+
allowVersionMismatch: options.allowVersionMismatch === true
|
|
152
|
+
});
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
// L2 defense-in-depth: a mutator on a read-only store refuses with a typed
|
|
156
|
+
// error rather than surfacing a raw EROFS from deep in an append.
|
|
157
|
+
function assertWritable(operation) {
|
|
158
|
+
if (readOnly)
|
|
159
|
+
throw new StorageReadonlyError(operation);
|
|
131
160
|
}
|
|
132
161
|
const lockTimeoutMs = options.lockTimeoutMs ?? 5000;
|
|
133
162
|
const lockMode = resolveLockMode(options.lockMode);
|
|
@@ -139,10 +168,28 @@ export function createLocalStore(options) {
|
|
|
139
168
|
// is the same-machine default (DEC-036); `lease` is the cross-host primitive
|
|
140
169
|
// (DEC-065) for a shared RWX store. Both share the `(path, fn, opts)` shape;
|
|
141
170
|
// the lease handle arg is simply ignored by the store's sync sections.
|
|
171
|
+
// L0 passive lock instrumentation: forward the primitive's observations to
|
|
172
|
+
// the ambient MCP trace (logical lock id only — never the owner payload).
|
|
173
|
+
// Undefined trace → no observe callback is attached and behaviour is byte-for
|
|
174
|
+
// -byte identical to before. Detailed-gated so a normal CLI run adds nothing.
|
|
175
|
+
function lockObserver() {
|
|
176
|
+
const trace = getActiveMcpTrace();
|
|
177
|
+
if (!trace?.detailed)
|
|
178
|
+
return undefined;
|
|
179
|
+
return (event) => {
|
|
180
|
+
trace.phase(`lock_${event.event}`, {
|
|
181
|
+
tool: event.lock,
|
|
182
|
+
...(event.waitMs !== undefined ? { waitMs: event.waitMs } : {}),
|
|
183
|
+
...(event.holdMs !== undefined ? { holdMs: event.holdMs } : {})
|
|
184
|
+
});
|
|
185
|
+
};
|
|
186
|
+
}
|
|
142
187
|
function lock(lockPath, fn, opts) {
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
188
|
+
if (lockMode === "lease") {
|
|
189
|
+
return withLeaseSync(lockPath, fn, opts);
|
|
190
|
+
}
|
|
191
|
+
const observe = lockObserver();
|
|
192
|
+
return withLockSync(lockPath, fn, observe ? { ...opts, observe } : opts);
|
|
146
193
|
}
|
|
147
194
|
const registryLock = join(paths.registry, ".lock");
|
|
148
195
|
const negotiationLock = (id) => join(negotiationDir(paths, id), ".lock");
|
|
@@ -160,6 +207,25 @@ export function createLocalStore(options) {
|
|
|
160
207
|
return Array.isArray(value) ? value : [value];
|
|
161
208
|
}
|
|
162
209
|
function listInstances() {
|
|
210
|
+
// L0 registry-read measurement (detailed-gated so the hot path is untouched
|
|
211
|
+
// when not tracing): the registry file size in bytes, recorded SEPARATELY
|
|
212
|
+
// from any lock hold. This is the read the identity-resolution boot performs
|
|
213
|
+
// against a large `instances.jsonl` — the candidate cause surface for T8.
|
|
214
|
+
const trace = getActiveMcpTrace();
|
|
215
|
+
if (trace?.detailed) {
|
|
216
|
+
let bytes = 0;
|
|
217
|
+
try {
|
|
218
|
+
bytes = statSync(paths.instances).size;
|
|
219
|
+
}
|
|
220
|
+
catch {
|
|
221
|
+
/* a missing/rotating registry is not a measurement failure */
|
|
222
|
+
}
|
|
223
|
+
return trace.span("registry_read", () => readJsonl(paths.instances).map((reg) => ({
|
|
224
|
+
...reg,
|
|
225
|
+
roles: toArray(reg.roles),
|
|
226
|
+
scopes: toArray(reg.scopes)
|
|
227
|
+
})), { bytes });
|
|
228
|
+
}
|
|
163
229
|
return readJsonl(paths.instances).map((reg) => ({
|
|
164
230
|
...reg,
|
|
165
231
|
roles: toArray(reg.roles),
|
|
@@ -170,6 +236,7 @@ export function createLocalStore(options) {
|
|
|
170
236
|
return listInstances().find((entry) => entry.id === id);
|
|
171
237
|
}
|
|
172
238
|
function registerInstance(reg) {
|
|
239
|
+
assertWritable("registerInstance");
|
|
173
240
|
lock(registryLock, () => {
|
|
174
241
|
if (findInstance(reg.id)) {
|
|
175
242
|
return;
|
|
@@ -201,6 +268,7 @@ export function createLocalStore(options) {
|
|
|
201
268
|
return readJsonl(paths.keys);
|
|
202
269
|
}
|
|
203
270
|
function addInstanceKey(instanceId, publicKeyPem) {
|
|
271
|
+
assertWritable("addInstanceKey");
|
|
204
272
|
lock(registryLock, () => {
|
|
205
273
|
if (!findInstance(instanceId)) {
|
|
206
274
|
throw new Error(`Instance not registered: ${instanceId}`);
|
|
@@ -857,6 +925,7 @@ export function createLocalStore(options) {
|
|
|
857
925
|
return out;
|
|
858
926
|
}
|
|
859
927
|
function putInboxMessage(actor, envelope) {
|
|
928
|
+
assertWritable("putInboxMessage");
|
|
860
929
|
const validation = validateH2AEnvelope(envelope);
|
|
861
930
|
if (!validation.ok) {
|
|
862
931
|
throw new Error("putInboxMessage: invalid H2A envelope — " + validation.errors.join("; "));
|