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

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 (55) hide show
  1. package/dist/containerRelayLifecycle.d.ts +1 -0
  2. package/dist/containerRelayLifecycle.d.ts.map +1 -1
  3. package/dist/containerRelayLifecycle.js +12 -0
  4. package/dist/containerRelayLifecycle.js.map +1 -1
  5. package/dist/containerRelayLifecycle.test.js +38 -6
  6. package/dist/containerRelayLifecycle.test.js.map +1 -1
  7. package/dist/containerRelayRuntimeTrust.test.js +10 -0
  8. package/dist/containerRelayRuntimeTrust.test.js.map +1 -1
  9. package/dist/index.d.ts.map +1 -1
  10. package/dist/index.js +117 -7
  11. package/dist/index.js.map +1 -1
  12. package/dist/maintenanceControlCaller.test.d.ts +2 -0
  13. package/dist/maintenanceControlCaller.test.d.ts.map +1 -0
  14. package/dist/maintenanceControlCaller.test.js +119 -0
  15. package/dist/maintenanceControlCaller.test.js.map +1 -0
  16. package/dist/namedSessionStoppedLock.d.ts +34 -0
  17. package/dist/namedSessionStoppedLock.d.ts.map +1 -0
  18. package/dist/namedSessionStoppedLock.js +108 -0
  19. package/dist/namedSessionStoppedLock.js.map +1 -0
  20. package/dist/namedSessionStoppedLock.test.d.ts +2 -0
  21. package/dist/namedSessionStoppedLock.test.d.ts.map +1 -0
  22. package/dist/namedSessionStoppedLock.test.js +104 -0
  23. package/dist/namedSessionStoppedLock.test.js.map +1 -0
  24. package/dist/relayAutostart.d.ts +3 -0
  25. package/dist/relayAutostart.d.ts.map +1 -1
  26. package/dist/relayAutostart.js +45 -6
  27. package/dist/relayAutostart.js.map +1 -1
  28. package/dist/relayAutostart.test.js +49 -1
  29. package/dist/relayAutostart.test.js.map +1 -1
  30. package/dist/relayRuntimeUpgrade.d.ts +1 -0
  31. package/dist/relayRuntimeUpgrade.d.ts.map +1 -1
  32. package/dist/relayRuntimeUpgrade.js +3 -3
  33. package/dist/relayRuntimeUpgrade.js.map +1 -1
  34. package/dist/relayRuntimeUpgradeCaller.test.js +76 -0
  35. package/dist/relayRuntimeUpgradeCaller.test.js.map +1 -1
  36. package/dist/relaySigningMaintenanceUpgrade.d.ts +44 -0
  37. package/dist/relaySigningMaintenanceUpgrade.d.ts.map +1 -0
  38. package/dist/relaySigningMaintenanceUpgrade.js +249 -0
  39. package/dist/relaySigningMaintenanceUpgrade.js.map +1 -0
  40. package/dist/relaySigningMaintenanceUpgrade.test.d.ts +2 -0
  41. package/dist/relaySigningMaintenanceUpgrade.test.d.ts.map +1 -0
  42. package/dist/relaySigningMaintenanceUpgrade.test.js +230 -0
  43. package/dist/relaySigningMaintenanceUpgrade.test.js.map +1 -0
  44. package/dist/schemas/local-signing-maintenance-upgrade-journal.schema.json +34 -0
  45. package/dist/schemas/local-signing-maintenance-upgrade.schema.json +33 -0
  46. package/dist/usage.d.ts.map +1 -1
  47. package/dist/usage.js +3 -2
  48. package/dist/usage.js.map +1 -1
  49. package/dist/wslRelayHost.d.ts +2 -0
  50. package/dist/wslRelayHost.d.ts.map +1 -1
  51. package/dist/wslRelayHost.js +35 -0
  52. package/dist/wslRelayHost.js.map +1 -1
  53. package/dist/wslRelayHost.test.js +81 -4
  54. package/dist/wslRelayHost.test.js.map +1 -1
  55. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -21,11 +21,13 @@ import { runDeviceSigningMaintenanceController } from './deviceSigningMaintenanc
21
21
  import { withLegacySigningMaintenanceBoundary } from './legacySigningMaintenanceBoundary.js';
22
22
  import { superviseRelay } from './relaySupervisor.js';
23
23
  import { currentRepositoryRelayFailure, repositoryRelayObservationReady, runRegisteredRepositoryRelays, selectRepositoryRelayRegistrations, serializeRelayWork, waitForRelayRefresh, withRepositoryRelayStage } from './repositoryRelaySupervisor.js';
24
- import { assertRelayStartupOwnership, disableRelayAutostart, enableRelayAutostart, inspectOwnedRelayAutostart, relayAutostartStatus, startRelayAutostart, stopRelayAutostart } from './relayAutostart.js';
24
+ import { assertRelayStartupOwnership, assertRelayAutostartPaused, disableRelayAutostart, enableRelayAutostart, inspectOwnedRelayAutostart, relayAutostartStatus, startRelayAutostart, stopRelayAutostart } from './relayAutostart.js';
25
25
  import { runOwnedContainerEntrypoint, readContainerProcessIdentity } from './containerRelayLifecycle.js';
26
26
  import { readWorkspaceRegistry } from './workspaceRegistry.js';
27
27
  import { appendRecoveredWorkspace, applyRegistryRecoveryFile, inspectRegistryRecoveryFile, resolveRegistryRecoveryProjection } from './workspaceRegistryRecovery.js';
28
28
  import { relayRuntimeObservationReady, upgradeRelayRuntime } from './relayRuntimeUpgrade.js';
29
+ import { reconcileStoppedNamedSessionLock } from './namedSessionStoppedLock.js';
30
+ import { upgradeRelayForSigningMaintenance } from './relaySigningMaintenanceUpgrade.js';
29
31
  import { activateMaintenanceRestart, maintainNamedSession, recoverStoppedNamedSession } from './namedSessionMaintenance.js';
30
32
  import { assertNamedSessionStartupRegistration } from './namedSessionAdmission.js';
31
33
  import { recoverableContainerJournal } from './containerRelayRecovery.js';
@@ -112,7 +114,7 @@ import { parseLocalCodexSetupReadiness } from '@dharma-ai-labs/agent-fabric-loca
112
114
  import { writeBootstrapHostJson, writeBootstrapHostText } from './bootstrapHostFiles.js';
113
115
  export { openCooperativeInboxSession } from './cooperativeInboxSession.js';
114
116
  import { inspectNamedCodexRecoveryToolDeclaration } from './codexSigningRecoveryTool.js';
115
- const VERSION = '0.2.210';
117
+ const VERSION = '0.2.211';
116
118
  const USAGE = CLI_USAGE;
117
119
  const execFileAsync = promisify(execFile);
118
120
  const LOCAL_PROVIDER_IDS = ['codex', 'claude', 'agy', 'hermes'];
@@ -177,6 +179,18 @@ export function formatCommandOutput(value) {
177
179
  }
178
180
  export function commandExitCode(argv, value) {
179
181
  const { positional, flags } = parseCliOptions(argv);
182
+ if (positional[0] === 'relay' && positional[1] === 'upgrade'
183
+ && (flags.has('stage-signing-maintenance') || flags.has('finish-signing-maintenance'))) {
184
+ if (!value || typeof value !== 'object' || Array.isArray(value))
185
+ return 2;
186
+ const receipt = value;
187
+ if (receipt.schema !== 'dharma.local-signing-maintenance-upgrade/v1' || receipt.ready !== false
188
+ || receipt.nativeContinuationAuthorized !== false)
189
+ return 2;
190
+ return flags.get('apply') !== true ? receipt.state === 'planned' ? 0 : 2
191
+ : flags.has('finish-signing-maintenance') ? receipt.state === 'completed' && receipt.upgradeComplete === true ? 0 : 2
192
+ : receipt.state === 'staged' && receipt.upgradeComplete === false ? 0 : 2;
193
+ }
180
194
  if (positional[0] === 'signing-recovery') {
181
195
  if (!value || typeof value !== 'object' || Array.isArray(value))
182
196
  return 2;
@@ -2014,6 +2028,15 @@ async function installStableRepositoryLauncher(workspace) {
2014
2028
  return { shell: '.dharma/bin/dharma', windows: '.dharma/bin/dharma.cmd' };
2015
2029
  }
2016
2030
  async function relayUpgrade(flags) {
2031
+ const stageMaintenance = flags.has('stage-signing-maintenance'), finishMaintenance = flags.has('finish-signing-maintenance');
2032
+ const maintenance = stageMaintenance || finishMaintenance;
2033
+ if (maintenance && process.platform !== 'linux')
2034
+ throw new Error('relay_signing_maintenance_linux_required');
2035
+ if (stageMaintenance && finishMaintenance || maintenance && flags.has('rollback')
2036
+ || ['stage-signing-maintenance', 'finish-signing-maintenance'].some(key => flags.has(key) && flags.get(key) !== true)
2037
+ || maintenance && ['apply', 'dry-run'].some(key => flags.has(key) && flags.get(key) !== true)
2038
+ || flags.has('previous-upgrade-sha256') && !stageMaintenance)
2039
+ throw new Error('relay_signing_maintenance_options_invalid');
2017
2040
  const config = await readDeviceConfig();
2018
2041
  if (!config)
2019
2042
  throw new Error('relay_upgrade_enrollment_required');
@@ -2057,10 +2080,46 @@ async function relayUpgrade(flags) {
2057
2080
  const npmCliPath = process.platform === 'linux' && !flags.has('rollback') ? await resolveRepositoryNpmCli() : undefined;
2058
2081
  const codexDirectory = !flags.has('rollback')
2059
2082
  ? await resolveRepositoryCodexDirectory({ searchPath: providerProcessEnvironment(process.env).PATH }) : undefined;
2060
- const receipt = await upgradeRelayRuntime({ home, workspace, version: VERSION,
2083
+ const upgrade = maintenance ? upgradeRelayForSigningMaintenance : upgradeRelayRuntime;
2084
+ const receipt = await upgrade({ home, workspace, version: VERSION,
2061
2085
  organizationId: config.organizationId, deviceId: config.deviceId, workspaceId: selected.workspaceId,
2062
- dryRun: !flags.has('apply'), rollback: flags.has('rollback') }, {
2086
+ dryRun: !flags.has('apply'), rollback: flags.has('rollback'),
2087
+ trustGeneration: config.serverSigningKeyset?.generation ?? 0, finish: finishMaintenance,
2088
+ ...(flags.has('previous-upgrade-sha256') ? { previousUpgradeSha256: String(flags.get('previous-upgrade-sha256')) } : {}) }, {
2063
2089
  assertStopped,
2090
+ assertStartupPaused: () => assertRelayAutostartPaused(startupOptions),
2091
+ stageStartup: (version, restore) => enableRelayAutostart({ ...startupOptions, workspace,
2092
+ launcher: startup.launcher, policy: startup.policy, version, restoreCodexHome: restore.codexHome, pauseForSigningMaintenance: true }),
2093
+ assertNamedDisabled: async () => {
2094
+ const entries = await readdir(resolve(home, 'sessions'), { withFileTypes: true });
2095
+ const names = entries.filter(entry => entry.isDirectory() && /^[a-z][a-z0-9-]{0,47}$/.test(entry.name));
2096
+ if (names.length !== 1)
2097
+ throw Error('relay_signing_maintenance_session_scope_unavailable');
2098
+ const registration = await readNamedSession(home, names[0].name);
2099
+ if (!registration || registration.enabled || registration.identity.organizationId !== config.organizationId
2100
+ || registration.identity.deviceId !== config.deviceId || registration.identity.workspaceId !== selected.workspaceId)
2101
+ throw Error('relay_signing_maintenance_session_scope_unavailable');
2102
+ try {
2103
+ await lstat(resolve(home, 'sessions', names[0].name, 'service.lock'));
2104
+ throw Error('relay_signing_maintenance_session_lock_requires_reconciliation');
2105
+ }
2106
+ catch (error) {
2107
+ if (error.code !== 'ENOENT')
2108
+ throw error;
2109
+ }
2110
+ },
2111
+ assertRecoveredTrust: async (previousGeneration) => {
2112
+ const current = await readDeviceConfig(), keyset = current?.serverSigningKeyset;
2113
+ if (!current || current.organizationId !== config.organizationId || current.deviceId !== config.deviceId
2114
+ || current.hqUrl !== config.hqUrl || current.relayUrl !== config.relayUrl || current.enrolledAt !== config.enrolledAt
2115
+ || current.connectionMode !== config.connectionMode
2116
+ || current.installationId !== config.installationId || current.publicKeyEd25519 !== config.publicKeyEd25519
2117
+ || current.setupClaimReference !== config.setupClaimReference || current.setupClaimRepositoryFingerprint !== config.setupClaimRepositoryFingerprint
2118
+ || !keyset || keyset.generation <= previousGeneration || !validateTrustedServerSigningKeysetContract(keyset).ok
2119
+ || !verifyInitialServerSigningKeyset(keyset, createPublicKey({ key: { kty: 'OKP', crv: 'Ed25519', x: current.serverPublicKeyEd25519 }, format: 'jwk' }), current.organizationId).ok)
2120
+ throw Error('relay_signing_maintenance_trust_not_recovered');
2121
+ await loadDeviceEnrollmentAnchor({ config: current, readOnly: true });
2122
+ },
2064
2123
  recoverableJournal: startup.backend === 'container-entrypoint' ? recoverableContainerJournal : undefined,
2065
2124
  inspectStartup: async () => {
2066
2125
  const current = await inspectOwnedRelayAutostart(startupOptions);
@@ -2120,7 +2179,8 @@ async function relayUpgrade(flags) {
2120
2179
  throw new Error('relay_upgrade_receiver_unconfirmed');
2121
2180
  },
2122
2181
  });
2123
- const validation = await validateContract(resolve(fileURLToPath(new URL('.', import.meta.url)), 'schemas'), 'https://schemas.dharma-ai.io/local-relay-upgrade/v1', receipt);
2182
+ const validation = await validateContract(resolve(fileURLToPath(new URL('.', import.meta.url)), 'schemas'), maintenance ? 'https://schemas.dharma-ai.io/local-signing-maintenance-upgrade/v1'
2183
+ : 'https://schemas.dharma-ai.io/local-relay-upgrade/v1', receipt);
2124
2184
  if (!validation.ok)
2125
2185
  throw new Error('relay_upgrade_receipt_invalid');
2126
2186
  return receipt;
@@ -5316,6 +5376,11 @@ async function namedSessionCommand(action, flags) {
5316
5376
  const hostScope = currentBootstrapHostScope();
5317
5377
  const setupSessionScope = currentAcceptedSetupSessionScope();
5318
5378
  const supervisorOwner = currentNamedSessionChildOwner();
5379
+ if (action === 'reconcile-stopped-lock' && (hostScope || setupSessionScope || supervisorOwner
5380
+ || [...flags.keys()].some(k => !['name', 'workspace-id', 'registration-sha256', 'lock-sha256', 'apply', 'dry-run', 'json'].includes(k))
5381
+ || ['apply', 'dry-run', 'json'].some(k => flags.has(k) && flags.get(k) !== true)
5382
+ || flags.has('apply') && flags.has('dry-run')))
5383
+ throw Error('named_session_stopped_lock_options_invalid');
5319
5384
  if (hostScope && (supervisorOwner || setupSessionScope))
5320
5385
  throw new Error('named_session_child_owner_conflict');
5321
5386
  if (setupSessionScope && !['start', 'status', 'readiness'].includes(action))
@@ -5338,7 +5403,7 @@ async function namedSessionCommand(action, flags) {
5338
5403
  await release?.();
5339
5404
  };
5340
5405
  try {
5341
- if (['start', 'serve'].includes(action) && flags.has('apply')) {
5406
+ if (['start', 'serve'].includes(action) && flags.has('apply') || action === 'reconcile-stopped-lock') {
5342
5407
  startupAdmission = await step(() => acquireNamedSessionStartupAdmission());
5343
5408
  }
5344
5409
  let childMessage;
@@ -5373,6 +5438,36 @@ async function namedSessionCommand(action, flags) {
5373
5438
  bindingId: existing?.bindingId ?? null };
5374
5439
  }
5375
5440
  }
5441
+ if (action === 'reconcile-stopped-lock') {
5442
+ if (!existing)
5443
+ throw Error('named_session_stopped_lock_unconfirmed');
5444
+ return await reconcileStoppedNamedSessionLock({ home: dharmaHome(), name, registration: existing,
5445
+ registrationSha256: required(flags, 'registration-sha256'), lockSha256: required(flags, 'lock-sha256'), apply: flags.has('apply') }, {
5446
+ assertTopology: async () => {
5447
+ await assertRelayAutostartPaused({ home: dharmaHome() });
5448
+ if (await relayProcessState(dharmaHome()) !== 'stopped' || await relaySupervisorProcessState(dharmaHome()) !== 'stopped')
5449
+ throw Error('named_session_stopped_lock_unconfirmed');
5450
+ try {
5451
+ await namedSessionRequest(dharmaHome(), name, { action: 'status' }, { diagnostic: true });
5452
+ throw Error('named_session_stopped_lock_unconfirmed');
5453
+ }
5454
+ catch (error) {
5455
+ if (!(error instanceof NamedSessionTransportFailure) || error.diagnostic.phase !== 'connect'
5456
+ || !['ENOENT', 'ECONNREFUSED'].includes(String(error.diagnostic.osCode)))
5457
+ throw Error('named_session_stopped_lock_unconfirmed');
5458
+ }
5459
+ },
5460
+ processState: async (pid) => {
5461
+ try {
5462
+ process.kill(pid, 0);
5463
+ return 'running';
5464
+ }
5465
+ catch (error) {
5466
+ return error.code === 'ESRCH' ? 'stopped' : 'unknown';
5467
+ }
5468
+ },
5469
+ });
5470
+ }
5376
5471
  if (action === 'readiness') {
5377
5472
  if (!existing?.enabled)
5378
5473
  throw new Error('named_session_readiness_unavailable');
@@ -9649,9 +9744,24 @@ export async function run(argv) {
9649
9744
  if (command === 'relay' && subcommand === 'autostart') {
9650
9745
  if (positional[2] === 'status')
9651
9746
  return relayAutostartStatus({ home: dharmaHome() });
9747
+ if (positional[2] === 'pause') {
9748
+ if ([...flags.keys()].some(k => !['apply', 'dry-run', 'json'].includes(k))
9749
+ || [...flags.values()].some(v => v !== true) || flags.has('apply') && flags.has('dry-run'))
9750
+ throw Error('relay_pause_options_invalid');
9751
+ return withRelayStartupMutation(async () => {
9752
+ const registration = await inspectOwnedRelayAutostart({ home: dharmaHome() });
9753
+ if (registration.backend !== 'container-entrypoint')
9754
+ throw Error('relay_pause_container_required');
9755
+ if (!flags.has('apply'))
9756
+ return { ok: true, planned: true, state: 'pause_planned', backend: registration.backend };
9757
+ await stopRelayAutostart({ home: dharmaHome() });
9758
+ await assertRelayAutostartPaused({ home: dharmaHome() });
9759
+ return { ok: true, planned: false, state: 'paused', backend: registration.backend, registrationPreserved: true };
9760
+ });
9761
+ }
9652
9762
  if (positional[2] === 'disable')
9653
9763
  return withRelayStartupMutation(() => disableRelayAutostart({ home: dharmaHome() }));
9654
- throw new Error('Use dharma relay autostart status or dharma relay autostart disable.');
9764
+ throw new Error('Use dharma relay autostart status, pause or disable.');
9655
9765
  }
9656
9766
  if (command === 'relay' && subcommand === 'supervise')
9657
9767
  return relaySupervise(flags);