@dharma-ai-labs/agent-fabric 0.2.210 → 0.2.212

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 (66) hide show
  1. package/dist/codexSetupSessionHandoff.test.js +46 -5
  2. package/dist/codexSetupSessionHandoff.test.js.map +1 -1
  3. package/dist/containerRelayLifecycle.d.ts +16 -0
  4. package/dist/containerRelayLifecycle.d.ts.map +1 -1
  5. package/dist/containerRelayLifecycle.js +55 -5
  6. package/dist/containerRelayLifecycle.js.map +1 -1
  7. package/dist/containerRelayLifecycle.test.js +38 -6
  8. package/dist/containerRelayLifecycle.test.js.map +1 -1
  9. package/dist/containerRelayPublicCommand.test.js +17 -0
  10. package/dist/containerRelayPublicCommand.test.js.map +1 -1
  11. package/dist/containerRelayRuntimeTrust.test.js +10 -0
  12. package/dist/containerRelayRuntimeTrust.test.js.map +1 -1
  13. package/dist/containerRelaySchema.test.js +13 -0
  14. package/dist/containerRelaySchema.test.js.map +1 -1
  15. package/dist/containerStartupInspection.test.d.ts +2 -0
  16. package/dist/containerStartupInspection.test.d.ts.map +1 -0
  17. package/dist/containerStartupInspection.test.js +175 -0
  18. package/dist/containerStartupInspection.test.js.map +1 -0
  19. package/dist/index.d.ts.map +1 -1
  20. package/dist/index.js +124 -9
  21. package/dist/index.js.map +1 -1
  22. package/dist/maintenanceControlCaller.test.d.ts +2 -0
  23. package/dist/maintenanceControlCaller.test.d.ts.map +1 -0
  24. package/dist/maintenanceControlCaller.test.js +119 -0
  25. package/dist/maintenanceControlCaller.test.js.map +1 -0
  26. package/dist/namedSessionStoppedLock.d.ts +34 -0
  27. package/dist/namedSessionStoppedLock.d.ts.map +1 -0
  28. package/dist/namedSessionStoppedLock.js +108 -0
  29. package/dist/namedSessionStoppedLock.js.map +1 -0
  30. package/dist/namedSessionStoppedLock.test.d.ts +2 -0
  31. package/dist/namedSessionStoppedLock.test.d.ts.map +1 -0
  32. package/dist/namedSessionStoppedLock.test.js +104 -0
  33. package/dist/namedSessionStoppedLock.test.js.map +1 -0
  34. package/dist/relayAutostart.d.ts +3 -0
  35. package/dist/relayAutostart.d.ts.map +1 -1
  36. package/dist/relayAutostart.js +45 -6
  37. package/dist/relayAutostart.js.map +1 -1
  38. package/dist/relayAutostart.test.js +49 -1
  39. package/dist/relayAutostart.test.js.map +1 -1
  40. package/dist/relayRuntimeUpgrade.d.ts +1 -0
  41. package/dist/relayRuntimeUpgrade.d.ts.map +1 -1
  42. package/dist/relayRuntimeUpgrade.js +3 -3
  43. package/dist/relayRuntimeUpgrade.js.map +1 -1
  44. package/dist/relayRuntimeUpgradeCaller.test.js +76 -0
  45. package/dist/relayRuntimeUpgradeCaller.test.js.map +1 -1
  46. package/dist/relaySigningMaintenanceUpgrade.d.ts +44 -0
  47. package/dist/relaySigningMaintenanceUpgrade.d.ts.map +1 -0
  48. package/dist/relaySigningMaintenanceUpgrade.js +249 -0
  49. package/dist/relaySigningMaintenanceUpgrade.js.map +1 -0
  50. package/dist/relaySigningMaintenanceUpgrade.test.d.ts +2 -0
  51. package/dist/relaySigningMaintenanceUpgrade.test.d.ts.map +1 -0
  52. package/dist/relaySigningMaintenanceUpgrade.test.js +230 -0
  53. package/dist/relaySigningMaintenanceUpgrade.test.js.map +1 -0
  54. package/dist/schemas/container-startup-inspection.v1.schema.json +27 -0
  55. package/dist/schemas/local-signing-maintenance-upgrade-journal.schema.json +34 -0
  56. package/dist/schemas/local-signing-maintenance-upgrade.schema.json +33 -0
  57. package/dist/usage.d.ts.map +1 -1
  58. package/dist/usage.js +3 -2
  59. package/dist/usage.js.map +1 -1
  60. package/dist/wslRelayHost.d.ts +2 -0
  61. package/dist/wslRelayHost.d.ts.map +1 -1
  62. package/dist/wslRelayHost.js +35 -0
  63. package/dist/wslRelayHost.js.map +1 -1
  64. package/dist/wslRelayHost.test.js +81 -4
  65. package/dist/wslRelayHost.test.js.map +1 -1
  66. package/package.json +5 -5
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=maintenanceControlCaller.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"maintenanceControlCaller.test.d.ts","sourceRoot":"","sources":["../src/maintenanceControlCaller.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,119 @@
1
+ import assert from 'node:assert/strict';
2
+ import { readFile } from 'node:fs/promises';
3
+ import { resolve } from 'node:path';
4
+ import { fileURLToPath } from 'node:url';
5
+ import { runInNewContext } from 'node:vm';
6
+ import test from 'node:test';
7
+ import ts from 'typescript';
8
+ async function source() { return ts.createSourceFile('index.ts', await readFile(fileURLToPath(new URL('../src/index.ts', import.meta.url)), 'utf8'), ts.ScriptTarget.Latest, true); }
9
+ function compile(text) {
10
+ return ts.transpileModule(text.replaceAll('import.meta.url', JSON.stringify(import.meta.url)), { compilerOptions: { target: ts.ScriptTarget.ES2023, module: ts.ModuleKind.None } }).outputText;
11
+ }
12
+ async function namedFixture() {
13
+ const ast = await source(), node = ast.statements.find(n => ts.isFunctionDeclaration(n) && n.name?.text === 'namedSessionCommand');
14
+ assert(node);
15
+ const events = [], workspaceId = '33333333-3333-4333-8333-333333333333';
16
+ const registration = { name: 'codex-fixture', enabled: false, bindingId: 'binding', identity: { workspaceId, organizationId: 'org_fixture', deviceId: 'device',
17
+ endpointId: 'endpoint', repositoryBindingId: 'repository' } };
18
+ class TransportFailure extends Error {
19
+ diagnostic = { phase: 'connect', osCode: 'ENOENT' };
20
+ }
21
+ const globals = {
22
+ namedSessionReadinessDiagnosticRequested: () => false, currentBootstrapHostScope: () => undefined, currentAcceptedSetupSessionScope: () => undefined,
23
+ currentNamedSessionChildOwner: () => undefined, process: { platform: 'linux', kill: () => { throw Object.assign(Error('absent'), { code: 'ESRCH' }); } },
24
+ namedSessionPaths: () => ({ root: '/owned/sessions/codex-fixture' }), dharmaHome: () => '/owned',
25
+ required: (flags, key) => { if (!flags.has(key))
26
+ throw Error('required'); return String(flags.get(key)); },
27
+ acquireNamedSessionStartupAdmission: async () => { events.push('admitted'); return async () => { events.push('released'); }; },
28
+ registry: async () => [{ workspaceId, organizationId: 'org_fixture', path: '/checkout' }], readDeviceConfig: async () => ({ organizationId: 'org_fixture', deviceId: 'device' }),
29
+ assertBootstrapHostSource: async () => { }, repositoryRoleScope: () => ({ endpointId: 'endpoint', repositoryBindingId: 'repository' }),
30
+ readNamedSession: async () => registration, assertRelayAutostartPaused: async () => { events.push('paused-proof'); },
31
+ relayProcessState: async () => 'stopped', relaySupervisorProcessState: async () => 'stopped',
32
+ NamedSessionTransportFailure: TransportFailure, namedSessionRequest: async () => { throw new TransportFailure(); },
33
+ reconcileStoppedNamedSessionLock: async () => ({ ok: true }), resolve,
34
+ };
35
+ const run = runInNewContext(compile(node.getText(ast)) + '\nnamedSessionCommand', globals);
36
+ const flags = new Map([['name', registration.name], ['workspace-id', workspaceId], ['registration-sha256', 'a'.repeat(64)], ['lock-sha256', 'b'.repeat(64)], ['apply', true]]);
37
+ return { run, flags, events, globals };
38
+ }
39
+ test('actual stopped-lock caller holds home-wide startup admission until reconciliation settles', { timeout: 5000 }, async () => {
40
+ const f = await namedFixture();
41
+ let complete;
42
+ f.globals.reconcileStoppedNamedSessionLock = async (_input, deps) => {
43
+ await deps.assertTopology();
44
+ assert.equal(await deps.processState(987654), 'stopped');
45
+ await new Promise(r => { complete = r; });
46
+ return { ok: true };
47
+ };
48
+ const result = f.run('reconcile-stopped-lock', f.flags);
49
+ let failure;
50
+ void result.catch(error => { failure = error; });
51
+ for (let n = 0; n < 1000 && !complete && !failure; n++)
52
+ await new Promise(r => setTimeout(r, 1));
53
+ if (failure)
54
+ throw failure;
55
+ assert(complete, 'bounded fixture admission did not settle');
56
+ assert.deepEqual(f.events, ['admitted', 'paused-proof']);
57
+ complete();
58
+ await result;
59
+ assert.deepEqual(f.events, ['admitted', 'paused-proof', 'released']);
60
+ });
61
+ test('actual stopped-lock caller refuses setup/peer contexts and malformed mutation options before admission', async () => {
62
+ for (const kind of ['host', 'peer', 'accepted', 'false-apply', 'unknown', 'conflict']) {
63
+ const f = await namedFixture();
64
+ if (kind === 'host')
65
+ f.globals.currentBootstrapHostScope = () => ({});
66
+ if (kind === 'peer')
67
+ f.globals.currentNamedSessionChildOwner = () => ({});
68
+ if (kind === 'accepted')
69
+ f.globals.currentAcceptedSetupSessionScope = () => ({});
70
+ if (kind === 'false-apply')
71
+ f.flags.set('apply', 'false');
72
+ if (kind === 'unknown')
73
+ f.flags.set('force', true);
74
+ if (kind === 'conflict')
75
+ f.flags.set('dry-run', true);
76
+ await assert.rejects(f.run('reconcile-stopped-lock', f.flags), /named_session_stopped_lock_options_invalid/);
77
+ assert.deepEqual(f.events, []);
78
+ }
79
+ });
80
+ test('actual stopped-lock caller rejects a listening owner and unknown or denied socket failures', async () => {
81
+ for (const kind of ['live', 'denied', 'unknown']) {
82
+ const f = await namedFixture();
83
+ f.globals.namedSessionRequest = kind === 'live' ? async () => ({ ok: true }) : async () => { throw Object.assign(Error('unconfirmed'), { code: kind === 'denied' ? 'EACCES' : 'ECONNRESET' }); };
84
+ f.globals.reconcileStoppedNamedSessionLock = async (_input, deps) => { await deps.assertTopology(); throw Error('must not mutate'); };
85
+ await assert.rejects(f.run('reconcile-stopped-lock', f.flags), /named_session_stopped_lock_unconfirmed/);
86
+ assert.deepEqual(f.events, ['admitted', 'paused-proof', 'released']);
87
+ }
88
+ });
89
+ test('actual autostart pause is plan-first, container-only and preserves the owning mutation admission', async () => {
90
+ const ast = await source(), nodes = [];
91
+ const visit = (n) => { if (ts.isIfStatement(n) && n.expression.getText(ast) === "command === 'relay' && subcommand === 'autostart'")
92
+ nodes.push(n); ts.forEachChild(n, visit); };
93
+ visit(ast);
94
+ assert.equal(nodes.length, 1);
95
+ for (const mode of ['plan', 'apply', 'foreign', 'false-apply']) {
96
+ const events = [], flags = new Map();
97
+ if (mode !== 'plan')
98
+ flags.set('apply', mode === 'false-apply' ? 'false' : true);
99
+ const globals = { command: 'relay', subcommand: 'autostart', positional: ['relay', 'autostart', 'pause'], flags, dharmaHome: () => '/owned',
100
+ withRelayStartupMutation: async (f) => { events.push('lock'); try {
101
+ return await f();
102
+ }
103
+ finally {
104
+ events.push('unlock');
105
+ } },
106
+ inspectOwnedRelayAutostart: async () => ({ backend: mode === 'foreign' ? 'systemd-user' : 'container-entrypoint' }),
107
+ stopRelayAutostart: async () => { events.push('pause'); }, assertRelayAutostartPaused: async () => { events.push('proof'); } };
108
+ const run = runInNewContext(compile('async function run(){' + nodes[0].getText(ast) + '}') + '\nrun', globals);
109
+ if (mode === 'foreign' || mode === 'false-apply') {
110
+ await assert.rejects(run());
111
+ assert(!events.includes('pause'));
112
+ }
113
+ else {
114
+ await run();
115
+ assert.deepEqual(events, mode === 'plan' ? ['lock', 'unlock'] : ['lock', 'pause', 'proof', 'unlock']);
116
+ }
117
+ }
118
+ });
119
+ //# sourceMappingURL=maintenanceControlCaller.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"maintenanceControlCaller.test.js","sourceRoot":"","sources":["../src/maintenanceControlCaller.test.ts"],"names":[],"mappings":"AAAA,OAAO,MAAM,MAAM,oBAAoB,CAAC;AACxC,OAAO,EAAC,QAAQ,EAAC,MAAM,kBAAkB,CAAC;AAC1C,OAAO,EAAC,OAAO,EAAC,MAAM,WAAW,CAAC;AAClC,OAAO,EAAC,aAAa,EAAC,MAAM,UAAU,CAAC;AACvC,OAAO,EAAC,eAAe,EAAC,MAAM,SAAS,CAAC;AACxC,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,MAAM,YAAY,CAAC;AAE5B,KAAK,UAAU,MAAM,KAAG,OAAO,EAAE,CAAC,gBAAgB,CAAC,UAAU,EAAC,MAAM,QAAQ,CAAC,aAAa,CAAC,IAAI,GAAG,CAAC,iBAAiB,EAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAC,MAAM,CAAC,EAAC,EAAE,CAAC,YAAY,CAAC,MAAM,EAAC,IAAI,CAAC,CAAC,CAAA,CAAC;AAC7K,SAAS,OAAO,CAAC,IAAW;IAAE,OAAO,EAAE,CAAC,eAAe,CAAC,IAAI,CAAC,UAAU,CAAC,iBAAiB,EAAC,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EACxH,EAAC,eAAe,EAAC,EAAC,MAAM,EAAC,EAAE,CAAC,YAAY,CAAC,MAAM,EAAC,MAAM,EAAC,EAAE,CAAC,UAAU,CAAC,IAAI,EAAC,EAAC,CAAC,CAAC,UAAU,CAAC;AAAA,CAAC;AAC3F,KAAK,UAAU,YAAY;IACzB,MAAM,GAAG,GAAC,MAAM,MAAM,EAAE,EAAC,IAAI,GAAC,GAAG,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,CAAA,EAAE,CAAA,EAAE,CAAC,qBAAqB,CAAC,CAAC,CAAC,IAAE,CAAC,CAAC,IAAI,EAAE,IAAI,KAAG,qBAAqB,CAAC,CAAC;IAAA,MAAM,CAAC,IAAI,CAAC,CAAC;IACrI,MAAM,MAAM,GAAU,EAAE,EAAC,WAAW,GAAC,sCAAsC,CAAC;IAC5E,MAAM,YAAY,GAAC,EAAC,IAAI,EAAC,eAAe,EAAC,OAAO,EAAC,KAAK,EAAC,SAAS,EAAC,SAAS,EAAC,QAAQ,EAAC,EAAC,WAAW,EAAC,cAAc,EAAC,aAAa,EAAC,QAAQ,EAAC,QAAQ;YAC7I,UAAU,EAAC,UAAU,EAAC,mBAAmB,EAAC,YAAY,EAAC,EAAC,CAAC;IAC3D,MAAM,gBAAiB,SAAQ,KAAK;QAAE,UAAU,GAAC,EAAC,KAAK,EAAC,SAAS,EAAC,MAAM,EAAC,QAAQ,EAAC,CAAC;KAAC;IACpF,MAAM,OAAO,GAAwB;QACnC,wCAAwC,EAAC,GAAE,EAAE,CAAA,KAAK,EAAC,yBAAyB,EAAC,GAAE,EAAE,CAAA,SAAS,EAAC,gCAAgC,EAAC,GAAE,EAAE,CAAA,SAAS;QACzI,6BAA6B,EAAC,GAAE,EAAE,CAAA,SAAS,EAAC,OAAO,EAAC,EAAC,QAAQ,EAAC,OAAO,EAAC,IAAI,EAAC,GAAE,EAAE,GAAC,MAAM,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,QAAQ,CAAC,EAAC,EAAC,IAAI,EAAC,OAAO,EAAC,CAAC,CAAC,CAAA,CAAC,EAAC;QACtI,iBAAiB,EAAC,GAAE,EAAE,CAAA,CAAC,EAAC,IAAI,EAAC,+BAA+B,EAAC,CAAC,EAAC,UAAU,EAAC,GAAE,EAAE,CAAA,QAAQ;QACtF,QAAQ,EAAC,CAAC,KAAgC,EAAC,GAAU,EAAC,EAAE,GAAC,IAAG,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC;YAAC,MAAM,KAAK,CAAC,UAAU,CAAC,CAAC,CAAA,OAAO,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,CAAA,CAAC;QACnI,mCAAmC,EAAC,KAAK,IAAE,EAAE,GAAC,MAAM,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,CAAA,OAAO,KAAK,IAAE,EAAE,GAAC,MAAM,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,CAAA,CAAC,CAAC,CAAA,CAAC;QAClH,QAAQ,EAAC,KAAK,IAAE,EAAE,CAAA,CAAC,EAAC,WAAW,EAAC,cAAc,EAAC,aAAa,EAAC,IAAI,EAAC,WAAW,EAAC,CAAC,EAAC,gBAAgB,EAAC,KAAK,IAAE,EAAE,CAAA,CAAC,EAAC,cAAc,EAAC,aAAa,EAAC,QAAQ,EAAC,QAAQ,EAAC,CAAC;QAC5J,yBAAyB,EAAC,KAAK,IAAE,EAAE,GAAC,CAAC,EAAC,mBAAmB,EAAC,GAAE,EAAE,CAAA,CAAC,EAAC,UAAU,EAAC,UAAU,EAAC,mBAAmB,EAAC,YAAY,EAAC,CAAC;QACxH,gBAAgB,EAAC,KAAK,IAAE,EAAE,CAAA,YAAY,EAAC,0BAA0B,EAAC,KAAK,IAAE,EAAE,GAAC,MAAM,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC,CAAA,CAAC;QACzG,iBAAiB,EAAC,KAAK,IAAE,EAAE,CAAA,SAAS,EAAC,2BAA2B,EAAC,KAAK,IAAE,EAAE,CAAA,SAAS;QACnF,4BAA4B,EAAC,gBAAgB,EAAC,mBAAmB,EAAC,KAAK,IAAE,EAAE,GAAC,MAAM,IAAI,gBAAgB,EAAE,CAAC,CAAA,CAAC;QAC1G,gCAAgC,EAAC,KAAK,IAAE,EAAE,CAAA,CAAC,EAAC,EAAE,EAAC,IAAI,EAAC,CAAC,EAAC,OAAO;KAC9D,CAAC;IACF,MAAM,GAAG,GAAC,eAAe,CAAC,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,GAAC,uBAAuB,EAAC,OAAO,CAAuE,CAAC;IAC5J,MAAM,KAAK,GAAC,IAAI,GAAG,CAAwB,CAAC,CAAC,MAAM,EAAC,YAAY,CAAC,IAAI,CAAC,EAAC,CAAC,cAAc,EAAC,WAAW,CAAC,EAAC,CAAC,qBAAqB,EAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,EAAC,CAAC,aAAa,EAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,EAAC,CAAC,OAAO,EAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAC3L,OAAM,EAAC,GAAG,EAAC,KAAK,EAAC,MAAM,EAAC,OAAO,EAAC,CAAC;AACnC,CAAC;AAED,IAAI,CAAC,2FAA2F,EAAC,EAAC,OAAO,EAAC,IAAI,EAAC,EAAC,KAAK,IAAE,EAAE;IACvH,MAAM,CAAC,GAAC,MAAM,YAAY,EAAE,CAAC;IAAA,IAAI,QAA6B,CAAC;IAC/D,CAAC,CAAC,OAAO,CAAC,gCAAgC,GAAC,KAAK,EAAC,MAAc,EAAC,IAA8E,EAAC,EAAE;QAC/I,MAAM,IAAI,CAAC,cAAc,EAAE,CAAC;QAAA,MAAM,CAAC,KAAK,CAAC,MAAM,IAAI,CAAC,YAAY,CAAC,MAAM,CAAC,EAAC,SAAS,CAAC,CAAC;QACpF,MAAM,IAAI,OAAO,CAAO,CAAC,CAAA,EAAE,GAAC,QAAQ,GAAC,CAAC,CAAC,CAAA,CAAC,CAAC,CAAC;QAAA,OAAM,EAAC,EAAE,EAAC,IAAI,EAAC,CAAC;IAC5D,CAAC,CAAC;IACF,MAAM,MAAM,GAAC,CAAC,CAAC,GAAG,CAAC,wBAAwB,EAAC,CAAC,CAAC,KAAK,CAAC,CAAC;IAAA,IAAI,OAAe,CAAC;IACzE,KAAK,MAAM,CAAC,KAAK,CAAC,KAAK,CAAA,EAAE,GAAC,OAAO,GAAC,KAAK,CAAC,CAAA,CAAC,CAAC,CAAC;IAC3C,KAAI,IAAI,CAAC,GAAC,CAAC,EAAC,CAAC,GAAC,IAAI,IAAE,CAAC,QAAQ,IAAE,CAAC,OAAO,EAAC,CAAC,EAAE;QAAC,MAAM,IAAI,OAAO,CAAC,CAAC,CAAA,EAAE,CAAA,UAAU,CAAC,CAAC,EAAC,CAAC,CAAC,CAAC,CAAC;IAClF,IAAG,OAAO;QAAC,MAAM,OAAO,CAAC;IAAA,MAAM,CAAC,QAAQ,EAAC,0CAA0C,CAAC,CAAC;IACrF,MAAM,CAAC,SAAS,CAAC,CAAC,CAAC,MAAM,EAAC,CAAC,UAAU,EAAC,cAAc,CAAC,CAAC,CAAC;IAAA,QAAQ,EAAE,CAAC;IAAA,MAAM,MAAM,CAAC;IAC/E,MAAM,CAAC,SAAS,CAAC,CAAC,CAAC,MAAM,EAAC,CAAC,UAAU,EAAC,cAAc,EAAC,UAAU,CAAC,CAAC,CAAC;AACpE,CAAC,CAAC,CAAC;AAEH,IAAI,CAAC,wGAAwG,EAAC,KAAK,IAAE,EAAE;IACrH,KAAI,MAAM,IAAI,IAAI,CAAC,MAAM,EAAC,MAAM,EAAC,UAAU,EAAC,aAAa,EAAC,SAAS,EAAC,UAAU,CAAC,EAAC,CAAC;QAC/E,MAAM,CAAC,GAAC,MAAM,YAAY,EAAE,CAAC;QAC7B,IAAG,IAAI,KAAG,MAAM;YAAC,CAAC,CAAC,OAAO,CAAC,yBAAyB,GAAC,GAAE,EAAE,CAAA,CAAC,EAAE,CAAC,CAAC;QAC9D,IAAG,IAAI,KAAG,MAAM;YAAC,CAAC,CAAC,OAAO,CAAC,6BAA6B,GAAC,GAAE,EAAE,CAAA,CAAC,EAAE,CAAC,CAAC;QAClE,IAAG,IAAI,KAAG,UAAU;YAAC,CAAC,CAAC,OAAO,CAAC,gCAAgC,GAAC,GAAE,EAAE,CAAA,CAAC,EAAE,CAAC,CAAC;QACzE,IAAG,IAAI,KAAG,aAAa;YAAC,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,OAAO,EAAC,OAAO,CAAC,CAAC;QACrD,IAAG,IAAI,KAAG,SAAS;YAAC,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,OAAO,EAAC,IAAI,CAAC,CAAC;QAC9C,IAAG,IAAI,KAAG,UAAU;YAAC,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,SAAS,EAAC,IAAI,CAAC,CAAC;QACjD,MAAM,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,wBAAwB,EAAC,CAAC,CAAC,KAAK,CAAC,EAAC,4CAA4C,CAAC,CAAC;QAAA,MAAM,CAAC,SAAS,CAAC,CAAC,CAAC,MAAM,EAAC,EAAE,CAAC,CAAC;IAC3I,CAAC;AACH,CAAC,CAAC,CAAC;AAEH,IAAI,CAAC,4FAA4F,EAAC,KAAK,IAAE,EAAE;IACzG,KAAI,MAAM,IAAI,IAAI,CAAC,MAAM,EAAC,QAAQ,EAAC,SAAS,CAAC,EAAC,CAAC;QAC7C,MAAM,CAAC,GAAC,MAAM,YAAY,EAAE,CAAC;QAC7B,CAAC,CAAC,OAAO,CAAC,mBAAmB,GAAC,IAAI,KAAG,MAAM,CAAA,CAAC,CAAA,KAAK,IAAE,EAAE,CAAA,CAAC,EAAC,EAAE,EAAC,IAAI,EAAC,CAAC,CAAA,CAAC,CAAA,KAAK,IAAE,EAAE,GAAC,MAAM,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,aAAa,CAAC,EAAC,EAAC,IAAI,EAAC,IAAI,KAAG,QAAQ,CAAA,CAAC,CAAA,QAAQ,CAAA,CAAC,CAAA,YAAY,EAAC,CAAC,CAAC,CAAA,CAAC,CAAC;QACpK,CAAC,CAAC,OAAO,CAAC,gCAAgC,GAAC,KAAK,EAAC,MAAc,EAAC,IAAqC,EAAC,EAAE,GAAC,MAAM,IAAI,CAAC,cAAc,EAAE,CAAC,CAAA,MAAM,KAAK,CAAC,iBAAiB,CAAC,CAAC,CAAA,CAAC,CAAC;QACtK,MAAM,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,wBAAwB,EAAC,CAAC,CAAC,KAAK,CAAC,EAAC,wCAAwC,CAAC,CAAC;QACvG,MAAM,CAAC,SAAS,CAAC,CAAC,CAAC,MAAM,EAAC,CAAC,UAAU,EAAC,cAAc,EAAC,UAAU,CAAC,CAAC,CAAC;IACpE,CAAC;AACH,CAAC,CAAC,CAAC;AAEH,IAAI,CAAC,kGAAkG,EAAC,KAAK,IAAE,EAAE;IAC/G,MAAM,GAAG,GAAC,MAAM,MAAM,EAAE,EAAC,KAAK,GAAkB,EAAE,CAAC;IACnD,MAAM,KAAK,GAAC,CAAC,CAAS,EAAC,EAAE,GAAC,IAAG,EAAE,CAAC,aAAa,CAAC,CAAC,CAAC,IAAE,CAAC,CAAC,UAAU,CAAC,OAAO,CAAC,GAAG,CAAC,KAAG,mDAAmD;QAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAA,EAAE,CAAC,YAAY,CAAC,CAAC,EAAC,KAAK,CAAC,CAAC,CAAA,CAAC,CAAC;IAAA,KAAK,CAAC,GAAG,CAAC,CAAC;IACtL,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,MAAM,EAAC,CAAC,CAAC,CAAC;IAC7B,KAAI,MAAM,IAAI,IAAI,CAAC,MAAM,EAAC,OAAO,EAAC,SAAS,EAAC,aAAa,CAAC,EAAC,CAAC;QAC1D,MAAM,MAAM,GAAU,EAAE,EAAC,KAAK,GAAC,IAAI,GAAG,EAAyB,CAAC;QAAA,IAAG,IAAI,KAAG,MAAM;YAAC,KAAK,CAAC,GAAG,CAAC,OAAO,EAAC,IAAI,KAAG,aAAa,CAAA,CAAC,CAAA,OAAO,CAAA,CAAC,CAAA,IAAI,CAAC,CAAC;QACtI,MAAM,OAAO,GAAC,EAAC,OAAO,EAAC,OAAO,EAAC,UAAU,EAAC,WAAW,EAAC,UAAU,EAAC,CAAC,OAAO,EAAC,WAAW,EAAC,OAAO,CAAC,EAAC,KAAK,EAAC,UAAU,EAAC,GAAE,EAAE,CAAA,QAAQ;YAC1H,wBAAwB,EAAC,KAAK,EAAC,CAAsB,EAAC,EAAE,GAAC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAA,IAAG,CAAC;gBAAA,OAAO,MAAM,CAAC,EAAE,CAAC;YAAA,CAAC;oBAAO,CAAC;gBAAA,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;YAAA,CAAC,CAAA,CAAC;YACnI,0BAA0B,EAAC,KAAK,IAAE,EAAE,CAAA,CAAC,EAAC,OAAO,EAAC,IAAI,KAAG,SAAS,CAAA,CAAC,CAAA,cAAc,CAAA,CAAC,CAAA,sBAAsB,EAAC,CAAC;YACtG,kBAAkB,EAAC,KAAK,IAAE,EAAE,GAAC,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAA,CAAC,EAAC,0BAA0B,EAAC,KAAK,IAAE,EAAE,GAAC,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAA,CAAC,EAAC,CAAC;QACnH,MAAM,GAAG,GAAC,eAAe,CAAC,OAAO,CAAC,uBAAuB,GAAC,KAAK,CAAC,CAAC,CAAE,CAAC,OAAO,CAAC,GAAG,CAAC,GAAC,GAAG,CAAC,GAAC,OAAO,EAAC,OAAO,CAAwB,CAAC;QAC9H,IAAG,IAAI,KAAG,SAAS,IAAE,IAAI,KAAG,aAAa,EAAC,CAAC;YAAA,MAAM,MAAM,CAAC,OAAO,CAAC,GAAG,EAAE,CAAC,CAAC;YAAA,MAAM,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC;QAAA,CAAC;aACtG,CAAC;YAAA,MAAM,GAAG,EAAE,CAAC;YAAA,MAAM,CAAC,SAAS,CAAC,MAAM,EAAC,IAAI,KAAG,MAAM,CAAA,CAAC,CAAA,CAAC,MAAM,EAAC,QAAQ,CAAC,CAAA,CAAC,CAAA,CAAC,MAAM,EAAC,OAAO,EAAC,OAAO,EAAC,QAAQ,CAAC,CAAC,CAAC;QAAA,CAAC;IAC/G,CAAC;AACH,CAAC,CAAC,CAAC"}
@@ -0,0 +1,34 @@
1
+ import type { NamedSessionRegistration } from './namedSessionService.js';
2
+ interface Input {
3
+ home: string;
4
+ name: string;
5
+ registration: NamedSessionRegistration;
6
+ registrationSha256: string;
7
+ lockSha256: string;
8
+ apply: boolean;
9
+ }
10
+ interface Dependencies {
11
+ assertTopology(): Promise<void>;
12
+ processState(pid: number): Promise<'stopped' | 'running' | 'unknown'>;
13
+ }
14
+ /** Called only under the owning CLI's home-wide startup mutation admission. */
15
+ export declare function reconcileStoppedNamedSessionLock(input: Input, deps: Dependencies): Promise<{
16
+ state: string;
17
+ ok: boolean;
18
+ planned: boolean;
19
+ name: string;
20
+ workspaceId: string;
21
+ bindingId: string;
22
+ registrationSha256: string;
23
+ lockSha256: string;
24
+ archive: string;
25
+ previousPid: number;
26
+ registrationChanged: boolean;
27
+ budgetChanged: boolean;
28
+ providerStarted: boolean;
29
+ protectedStoreRead: boolean;
30
+ ready: boolean;
31
+ nativeContinuationAuthorized: boolean;
32
+ }>;
33
+ export {};
34
+ //# sourceMappingURL=namedSessionStoppedLock.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"namedSessionStoppedLock.d.ts","sourceRoot":"","sources":["../src/namedSessionStoppedLock.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAC,wBAAwB,EAAC,MAAM,0BAA0B,CAAC;AAIvE,UAAU,KAAK;IACb,IAAI,EAAC,MAAM,CAAC;IAAC,IAAI,EAAC,MAAM,CAAC;IAAC,YAAY,EAAC,wBAAwB,CAAC;IAChE,kBAAkB,EAAC,MAAM,CAAC;IAAC,UAAU,EAAC,MAAM,CAAC;IAAC,KAAK,EAAC,OAAO,CAAC;CAC7D;AACD,UAAU,YAAY;IACpB,cAAc,IAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC/B,YAAY,CAAC,GAAG,EAAC,MAAM,GAAE,OAAO,CAAC,SAAS,GAAC,SAAS,GAAC,SAAS,CAAC,CAAC;CACjE;AAYD,+EAA+E;AAC/E,wBAAsB,gCAAgC,CAAC,KAAK,EAAC,KAAK,EAAC,IAAI,EAAC,YAAY;;;;;;;;;;;;;;;;;GA+CnF"}
@@ -0,0 +1,108 @@
1
+ import { createHash } from 'node:crypto';
2
+ import { constants } from 'node:fs';
3
+ import { link, lstat, open, realpath, unlink } from 'node:fs/promises';
4
+ import { join, resolve } from 'node:path';
5
+ const digest = (bytes) => createHash('sha256').update(bytes).digest('hex');
6
+ const unavailable = () => new Error('named_session_stopped_lock_unconfirmed');
7
+ async function privateFile(path, uid, limit) {
8
+ const file = await open(path, constants.O_RDONLY | constants.O_NOFOLLOW | constants.O_NONBLOCK);
9
+ try {
10
+ const stat = await file.stat({ bigint: true });
11
+ if (!stat.isFile() || Number(stat.uid) !== uid || (Number(stat.mode) & 0o077) !== 0 || stat.size > BigInt(limit))
12
+ throw unavailable();
13
+ const bytes = await file.readFile();
14
+ if (bytes.length > limit)
15
+ throw unavailable();
16
+ return { bytes, dev: stat.dev, ino: stat.ino };
17
+ }
18
+ finally {
19
+ await file.close();
20
+ }
21
+ }
22
+ /** Called only under the owning CLI's home-wide startup mutation admission. */
23
+ export async function reconcileStoppedNamedSessionLock(input, deps) {
24
+ const uid = process.getuid?.() ?? -1;
25
+ if (process.platform !== 'linux' || uid <= 0 || resolve(input.home) !== input.home
26
+ || !/^[a-z][a-z0-9-]{0,47}$/.test(input.name) || input.registration.name !== input.name
27
+ || input.registration.enabled || input.registration.maintenanceFence
28
+ || ![input.registrationSha256, input.lockSha256].every(v => /^[a-f0-9]{64}$/.test(v)))
29
+ throw unavailable();
30
+ const root = join(input.home, 'sessions', input.name), registrationPath = join(root, 'registration.json'), lockPath = join(root, 'service.lock');
31
+ for (const path of [input.home, join(input.home, 'sessions'), root]) {
32
+ const stat = await lstat(path);
33
+ if (!stat.isDirectory() || stat.isSymbolicLink() || stat.uid !== uid || (stat.mode & 0o077) !== 0 || await realpath(path) !== path)
34
+ throw unavailable();
35
+ }
36
+ const verify = async () => {
37
+ await deps.assertTopology();
38
+ const registration = await privateFile(registrationPath, uid, 4096);
39
+ if (digest(registration.bytes) !== input.registrationSha256
40
+ || JSON.stringify(JSON.parse(registration.bytes.toString('utf8'))) !== JSON.stringify(input.registration))
41
+ throw unavailable();
42
+ const lock = await privateFile(lockPath, uid, 64), text = lock.bytes.toString('utf8');
43
+ if (digest(lock.bytes) !== input.lockSha256 || !/^([1-9][0-9]*)\n?$/.test(text))
44
+ throw unavailable();
45
+ const pid = Number(text.trim());
46
+ if (!Number.isSafeInteger(pid) || pid <= 1 || await deps.processState(pid) !== 'stopped')
47
+ throw unavailable();
48
+ return { ...lock, pid };
49
+ };
50
+ const before = await verify(), archiveName = 'service.lock.stopped.' + input.lockSha256;
51
+ const receipt = { ok: true, planned: !input.apply, name: input.name, workspaceId: input.registration.identity.workspaceId,
52
+ bindingId: input.registration.bindingId, registrationSha256: input.registrationSha256, lockSha256: input.lockSha256,
53
+ archive: archiveName, previousPid: before.pid, registrationChanged: false, budgetChanged: false, providerStarted: false, protectedStoreRead: false,
54
+ ready: false, nativeContinuationAuthorized: false };
55
+ if (!input.apply)
56
+ return { ...receipt, state: 'stopped_lock_reconciliation_planned' };
57
+ const current = await verify();
58
+ if (current.dev !== before.dev || current.ino !== before.ino)
59
+ throw unavailable();
60
+ const archive = join(root, archiveName);
61
+ try {
62
+ await link(lockPath, archive);
63
+ }
64
+ catch (error) {
65
+ if (error.code !== 'EEXIST')
66
+ throw error;
67
+ }
68
+ const retained = await privateFile(archive, uid, 64);
69
+ if (retained.dev !== before.dev || retained.ino !== before.ino || digest(retained.bytes) !== input.lockSha256)
70
+ throw unavailable();
71
+ const archiveFile = await open(archive, constants.O_RDONLY | constants.O_NOFOLLOW);
72
+ try {
73
+ await archiveFile.sync();
74
+ }
75
+ finally {
76
+ await archiveFile.close();
77
+ }
78
+ const directory = await open(root, constants.O_RDONLY | constants.O_DIRECTORY | constants.O_NOFOLLOW);
79
+ try {
80
+ await directory.sync();
81
+ }
82
+ finally {
83
+ await directory.close();
84
+ }
85
+ const final = await verify();
86
+ if (final.dev !== before.dev || final.ino !== before.ino)
87
+ throw unavailable();
88
+ await unlink(lockPath);
89
+ const completedDirectory = await open(root, constants.O_RDONLY | constants.O_DIRECTORY | constants.O_NOFOLLOW);
90
+ try {
91
+ await completedDirectory.sync();
92
+ }
93
+ finally {
94
+ await completedDirectory.close();
95
+ }
96
+ try {
97
+ await lstat(lockPath);
98
+ throw unavailable();
99
+ }
100
+ catch (error) {
101
+ if (error.code !== 'ENOENT')
102
+ throw error;
103
+ }
104
+ if (digest((await privateFile(registrationPath, uid, 4096)).bytes) !== input.registrationSha256)
105
+ throw unavailable();
106
+ return { ...receipt, state: 'stopped_lock_reconciled', planned: false };
107
+ }
108
+ //# sourceMappingURL=namedSessionStoppedLock.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"namedSessionStoppedLock.js","sourceRoot":"","sources":["../src/namedSessionStoppedLock.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=namedSessionStoppedLock.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"namedSessionStoppedLock.test.d.ts","sourceRoot":"","sources":["../src/namedSessionStoppedLock.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,104 @@
1
+ import assert from 'node:assert/strict';
2
+ import { createHash } from 'node:crypto';
3
+ import { chmod, lstat, mkdir, mkdtemp, readFile, realpath, rename, symlink, writeFile } from 'node:fs/promises';
4
+ import { tmpdir } from 'node:os';
5
+ import { join } from 'node:path';
6
+ import test from 'node:test';
7
+ import { reconcileStoppedNamedSessionLock } from './namedSessionStoppedLock.js';
8
+ const linux = { skip: process.platform !== 'linux' }, sha = (v) => createHash('sha256').update(v).digest('hex');
9
+ async function fixture() {
10
+ const home = await realpath(await mkdtemp(join(tmpdir(), 'dharma-stopped-lock-')));
11
+ await chmod(home, 0o700);
12
+ const name = 'codex-fixture', root = join(home, 'sessions', name);
13
+ await mkdir(root, { recursive: true, mode: 0o700 });
14
+ await chmod(join(home, 'sessions'), 0o700);
15
+ const registration = { schema: 'dharma.named-session/v1', name, bindingId: '11111111-1111-4111-8111-111111111111', enabled: false,
16
+ maximumCostCents: 1000, maximumTurnCostCents: 25, identity: { organizationId: 'org_fixture', provider: 'codex',
17
+ repositoryBindingId: '22222222-2222-4222-8222-222222222222', workspaceId: '33333333-3333-4333-8333-333333333333',
18
+ endpointId: '44444444-4444-4444-8444-444444444444', membershipId: '55555555-5555-4555-8555-555555555555', deviceId: '66666666-6666-4666-8666-666666666666' } };
19
+ await writeFile(join(root, 'registration.json'), JSON.stringify(registration) + '\n', { mode: 0o600 });
20
+ const lock = join(root, 'service.lock');
21
+ await writeFile(lock, '987654\n', { mode: 0o600 });
22
+ const input = { home, name, registration, registrationSha256: sha(await readFile(join(root, 'registration.json'))), lockSha256: sha(await readFile(lock)), apply: false };
23
+ const deps = { assertTopology: async () => { }, processState: async () => 'stopped' };
24
+ return { home, root, lock, input, deps };
25
+ }
26
+ test('stopped-lock plan is inert and apply retains the exact original lock inode and registration', linux, async () => {
27
+ const f = await fixture(), before = await lstat(f.lock);
28
+ const plan = await reconcileStoppedNamedSessionLock(f.input, f.deps);
29
+ assert.equal(plan.state, 'stopped_lock_reconciliation_planned');
30
+ assert.equal((await lstat(f.lock)).ino, before.ino);
31
+ await assert.rejects(lstat(join(f.root, plan.archive)), { code: 'ENOENT' });
32
+ const result = await reconcileStoppedNamedSessionLock({ ...f.input, apply: true }, f.deps);
33
+ assert.equal(result.state, 'stopped_lock_reconciled');
34
+ assert.equal((await lstat(join(f.root, result.archive))).ino, before.ino);
35
+ assert.equal(result.registrationChanged, false);
36
+ assert.equal(result.budgetChanged, false);
37
+ assert.equal(result.protectedStoreRead, false);
38
+ await assert.rejects(lstat(f.lock), { code: 'ENOENT' });
39
+ });
40
+ for (const cause of ['enabled', 'wrong-registration', 'wrong-lock', 'running', 'unknown', 'unsafe-parent', 'foreign-topology', 'symlink', 'malformed']) {
41
+ test('stopped-lock reconciliation refuses ' + cause + ' without removing the lock', linux, async () => {
42
+ const f = await fixture();
43
+ if (cause === 'enabled')
44
+ f.input.registration.enabled = true;
45
+ if (cause === 'wrong-registration')
46
+ f.input.registrationSha256 = '0'.repeat(64);
47
+ if (cause === 'wrong-lock')
48
+ f.input.lockSha256 = '0'.repeat(64);
49
+ if (cause === 'running' || cause === 'unknown')
50
+ f.deps.processState = async () => cause;
51
+ if (cause === 'unsafe-parent')
52
+ await chmod(f.root, 0o755);
53
+ if (cause === 'foreign-topology')
54
+ f.deps.assertTopology = async () => { throw Error('foreign controller'); };
55
+ if (cause === 'symlink') {
56
+ await writeFile(join(f.root, 'foreign'), '987654\n', { mode: 0o600 });
57
+ f.input.name = 'linked';
58
+ f.input.registration = { ...f.input.registration, name: 'linked' };
59
+ await symlink(f.root, join(f.home, 'sessions', 'linked'));
60
+ }
61
+ if (cause === 'malformed') {
62
+ await writeFile(f.lock, 'not-a-pid\n');
63
+ f.input.lockSha256 = sha(await readFile(f.lock));
64
+ }
65
+ await assert.rejects(reconcileStoppedNamedSessionLock({ ...f.input, apply: true }, f.deps));
66
+ assert.equal((await lstat(f.lock)).isFile(), true);
67
+ });
68
+ }
69
+ test('a topology change after archive creation leaves the active lock intact', linux, async () => {
70
+ const f = await fixture();
71
+ let checks = 0;
72
+ f.deps.assertTopology = async () => { if (++checks === 3)
73
+ throw Error('topology changed'); };
74
+ await assert.rejects(reconcileStoppedNamedSessionLock({ ...f.input, apply: true }, f.deps));
75
+ assert.equal((await lstat(f.lock)).isFile(), true);
76
+ assert.equal(sha(await readFile(join(f.root, 'service.lock.stopped.' + f.input.lockSha256))), f.input.lockSha256);
77
+ });
78
+ test('a symbolic service lock and an existing foreign archive never admit reconciliation', linux, async () => {
79
+ for (const cause of ['symlink', 'archive']) {
80
+ const f = await fixture();
81
+ if (cause === 'symlink') {
82
+ await rename(f.lock, join(f.root, 'original'));
83
+ await symlink(join(f.root, 'original'), f.lock);
84
+ }
85
+ else
86
+ await writeFile(join(f.root, 'service.lock.stopped.' + f.input.lockSha256), 'foreign\n', { mode: 0o600 });
87
+ await assert.rejects(reconcileStoppedNamedSessionLock({ ...f.input, apply: true }, f.deps));
88
+ assert.equal(Boolean(await lstat(f.lock)), true);
89
+ }
90
+ });
91
+ test('registration replacement or a newly live PID after planning cannot remove the active lock', linux, async () => {
92
+ for (const cause of ['registration', 'pid']) {
93
+ const f = await fixture();
94
+ let n = 0;
95
+ f.deps.assertTopology = async () => { if (++n === 2 && cause === 'registration')
96
+ await writeFile(join(f.root, 'registration.json'), '{}\n'); };
97
+ let pidChecks = 0;
98
+ if (cause === 'pid')
99
+ f.deps.processState = async () => ++pidChecks === 1 ? 'stopped' : 'running';
100
+ await assert.rejects(reconcileStoppedNamedSessionLock({ ...f.input, apply: true }, f.deps));
101
+ assert.equal((await lstat(f.lock)).isFile(), true);
102
+ }
103
+ });
104
+ //# sourceMappingURL=namedSessionStoppedLock.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"namedSessionStoppedLock.test.js","sourceRoot":"","sources":["../src/namedSessionStoppedLock.test.ts"],"names":[],"mappings":"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"}
@@ -62,6 +62,8 @@ export declare function enableRelayAutostart(options: RelayAutostartOptions & {
62
62
  policy: string | null;
63
63
  version: string;
64
64
  preserveStandardAnchor?: boolean;
65
+ /** Existing Linux registration only; keep its controller paused during a signing-maintenance upgrade. */
66
+ pauseForSigningMaintenance?: boolean;
65
67
  }): Promise<RelayAutostartState>;
66
68
  export declare function disableRelayAutostart(options: RelayAutostartOptions): Promise<RelayAutostartState>;
67
69
  export declare function startRelayAutostart(options: RelayAutostartOptions): Promise<{
@@ -72,6 +74,7 @@ export declare function startRelayAutostart(options: RelayAutostartOptions): Pro
72
74
  export declare function inspectOwnedRelayAutostart(options: RelayAutostartOptions, inspection?: {
73
75
  allowLegacy?: boolean;
74
76
  }): Promise<RelayAutostartRegistration>;
77
+ export declare function assertRelayAutostartPaused(options: RelayAutostartOptions): Promise<void>;
75
78
  export declare function stopRelayAutostart(options: RelayAutostartOptions): Promise<{
76
79
  state: "stop_requested";
77
80
  backend: "container-entrypoint" | "systemd-user" | "windows-task" | "launchd-user";
@@ -1 +1 @@
1
- {"version":3,"file":"relayAutostart.d.ts","sourceRoot":"","sources":["../src/relayAutostart.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"relayAutostart.d.ts","sourceRoot":"","sources":["../src/relayAutostart.ts"],"names":[],"mappings":"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"}
@@ -4,9 +4,9 @@ import { lstat, mkdir, readFile, rm, writeFile } from 'node:fs/promises';
4
4
  import { homedir } from 'node:os';
5
5
  import { dirname, isAbsolute, join, posix } from 'node:path';
6
6
  import { promisify } from 'node:util';
7
- import { assertContainerStartupOwnership, containerEntrypointAvailable, containerStartupControl, containerStartupState, ownsContainerStartup, writeContainerRegistration, readContainerRegistration } from './containerRelayLifecycle.js';
7
+ import { assertContainerStartupOwnership, containerEntrypointAvailable, containerStartupControl, containerStartupState, ownsContainerStartup, containerStartupPaused, writeContainerRegistration, readContainerRegistration } from './containerRelayLifecycle.js';
8
8
  import { currentBootstrapHostScope } from './bootstrapHostScope.js';
9
- import { assertWslHostPreflight, disableWslRelayHost, enableWslRelayHost, startWslRelayHost, wslRelayHostStatus } from './wslRelayHost.js';
9
+ import { assertWslHostPreflight, assertWslRelayHostPaused, pauseWslRelayHost, disableWslRelayHost, enableWslRelayHost, startWslRelayHost, wslRelayHostStatus } from './wslRelayHost.js';
10
10
  const execFileAsync = promisify(execFile);
11
11
  const UNIT_NAME = 'dharma-agent-fabric.service';
12
12
  const MAC_LABEL = 'io.dharma.agent-fabric.relay';
@@ -341,6 +341,9 @@ export async function relayAutostartStatus(options) {
341
341
  }
342
342
  export async function enableRelayAutostart(options) {
343
343
  const platform = options.platform || process.platform;
344
+ if (options.pauseForSigningMaintenance && (platform !== 'linux' || options.preserveStandardAnchor)) {
345
+ throw new Error('relay_signing_maintenance_startup_scope_invalid');
346
+ }
344
347
  if (platform !== 'linux' && platform !== 'win32' && platform !== 'darwin') {
345
348
  throw new Error(`Relay autostart is unsupported on ${platform}.`);
346
349
  }
@@ -349,6 +352,8 @@ export async function enableRelayAutostart(options) {
349
352
  const userHome = options.userHome || homedir();
350
353
  const run = options.run || defaultRunner;
351
354
  const previous = await readRegistration(options);
355
+ if (options.pauseForSigningMaintenance && !previous)
356
+ throw new Error('relay_signing_maintenance_startup_scope_invalid');
352
357
  const backend = platform === 'linux'
353
358
  ? await containerEntrypointAvailable(options) ? 'container-entrypoint' : 'systemd-user'
354
359
  : platform === 'darwin' ? 'launchd-user' : 'windows-task';
@@ -393,7 +398,7 @@ export async function enableRelayAutostart(options) {
393
398
  if (previous && !await ownsStartupFile(options, previous))
394
399
  throw new Error('autostart_conflict: container startup is not owned.');
395
400
  await writeContainerRegistration(options, registration);
396
- await containerStartupControl(options, registration, true);
401
+ await containerStartupControl(options, registration, !options.pauseForSigningMaintenance);
397
402
  return containerStartupState(options, registration);
398
403
  }
399
404
  if (platform === 'win32' && !previous) {
@@ -451,8 +456,11 @@ export async function enableRelayAutostart(options) {
451
456
  await writeFile(registrationPath(options.home), `${JSON.stringify(registration, null, 2)}\n`, { mode: 0o600 });
452
457
  if (platform === 'linux') {
453
458
  await run('systemctl', ['--user', 'daemon-reload']);
454
- await run('systemctl', ['--user', 'enable', UNIT_NAME]);
455
- await enableWslRelayHost(options);
459
+ await run('systemctl', ['--user', options.pauseForSigningMaintenance ? 'disable' : 'enable', UNIT_NAME]);
460
+ if (options.pauseForSigningMaintenance)
461
+ await pauseWslRelayHost(options);
462
+ else
463
+ await enableWslRelayHost(options);
456
464
  }
457
465
  else if (platform === 'darwin') {
458
466
  await run('/usr/bin/plutil', ['-lint', destination]);
@@ -474,7 +482,7 @@ export async function enableRelayAutostart(options) {
474
482
  await run('powershell.exe', encodedPowerShell(command));
475
483
  }
476
484
  const status = await relayAutostartStatus(options);
477
- if (status.state !== 'enabled')
485
+ if (status.state !== (options.pauseForSigningMaintenance ? 'disabled' : 'enabled'))
478
486
  throw new Error(`Relay autostart registration was not verified (${status.state}).`);
479
487
  return status;
480
488
  }
@@ -561,6 +569,37 @@ export async function inspectOwnedRelayAutostart(options, inspection = {}) {
561
569
  await macLoaded(options, registration);
562
570
  return registration;
563
571
  }
572
+ export async function assertRelayAutostartPaused(options) {
573
+ const registration = await inspectOwnedRelayAutostart(options);
574
+ if (registration.backend === 'container-entrypoint') {
575
+ // Only a valid paused control awaiting its new matching heartbeat is polled.
576
+ // Identity, permission, malformed metadata and other failures stop immediately.
577
+ for (let attempt = 0; attempt < 50; attempt++) {
578
+ if (await containerStartupPaused(options, registration))
579
+ return;
580
+ if (attempt < 49)
581
+ await new Promise(resolve => setTimeout(resolve, 100));
582
+ }
583
+ throw Error('relay_startup_pause_unconfirmed');
584
+ }
585
+ if (registration.backend !== 'systemd-user' || (await relayAutostartStatus(options)).state !== 'disabled') {
586
+ throw Error('relay_startup_pause_unconfirmed');
587
+ }
588
+ const run = options.run || defaultRunner;
589
+ let active;
590
+ try {
591
+ active = (await run('systemctl', ['--user', 'is-active', UNIT_NAME])).stdout.trim();
592
+ }
593
+ catch (error) {
594
+ const e = error;
595
+ if (e.code !== 3 || typeof e.stdout !== 'string' || e.stdout.trim() !== 'inactive')
596
+ throw error;
597
+ active = 'inactive';
598
+ }
599
+ if (active !== 'inactive')
600
+ throw Error('relay_startup_pause_unconfirmed');
601
+ await assertWslRelayHostPaused(options);
602
+ }
564
603
  export async function stopRelayAutostart(options) {
565
604
  const registration = await inspectOwnedRelayAutostart(options);
566
605
  const run = options.run || defaultRunner;