@dharma-ai-labs/agent-fabric 0.2.96 → 0.2.98

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.
@@ -7,7 +7,7 @@ import { join } from 'node:path';
7
7
  import test from 'node:test';
8
8
  import { fileURLToPath, pathToFileURL } from 'node:url';
9
9
  import { promisify } from 'node:util';
10
- import { acceptedTrajectoryHead, activateAgyPlugin, attestAgySkillActivation, attestHermesSkillBundleActivation, actionDecisionCapabilityFreshUntil, canonicalFilesystemPath, controlAgentDecisionUrl, installAvailableNativeAgentFabricBootstraps, assertCapsuleAuthorizedByCurrentPolicy, assertRecoveredTaskWorkspacePolicy, assertTaskWorkspacePolicy, assertTaskSkillPin, installNativeAgentFabricBootstrap, installClaudeReadOnlyProjectPermissions, installRepositoryAgentFabricSkill, isDirectExecution, isTransientBootstrapError, loadAgentFabricOnboardingContract, loadOrCreateInstallationId, materializeWorkspacePolicy, applyServerEvidencePolicy, materializeInlineSkillFiles, validateSkillBundleSources, nativeSkillDirectory, nativeSkillDirectoryForWorkspace, nativeSkillRootMatchingAuthorization, normalizeGitRemoteIdentity, postTaskOutcome, parseCliOptions, parseSelectedProviderIds, pathExistsOrThrow, portalUrl, providerHintFromEnvironment, providerHintFromProcessArgv, probeRelayConnection, preflightBootstrapWorkspaceIdentity, rawLocalRetentionDays, syncPendingRetentionCapsules, requireCompletedBootstrapEvidence, retryBootstrapOnboarding, synchronizeBootstrapEvidence, deferUnavailableRelayRetention, recoverLegacySkillBundleIdAfterAuthorizationFailure, installedBundleIdForSkillPollAfterAuthorizationFailure, recoveredTaskPolicyWasSuperseded, relayProcessState, releaseDailyContentUpload, reserveDailyContentUpload, run, runAssistantCommand, sourceRepositoryFingerprint, stableRepositoryLauncherContents, summarizeBootstrapOrganizationApi, ensureAgyReadOnlyAttestationPermission, attestAgySkillBundleActivation, responseTextFromEvent, taskResponsePreview, taskReceiptSession, taskSkillPinFailureCode, verifyAgentFabricSkillInstallation, waitForRelayReadiness, withWorkspacePolicyRefreshLock, withWorkspaceSkillActivationLock, } from './index.js';
10
+ import { acceptedTrajectoryHead, activateAgyPlugin, attestAgySkillActivation, attestHermesSkillBundleActivation, actionDecisionCapabilityFreshUntil, canonicalFilesystemPath, controlAgentDecisionUrl, installAvailableNativeAgentFabricBootstraps, assertCapsuleAuthorizedByCurrentPolicy, assertRecoveredTaskWorkspacePolicy, assertTaskWorkspacePolicy, assertTaskSkillPin, installNativeAgentFabricBootstrap, installClaudeReadOnlyProjectPermissions, installRepositoryAgentFabricSkill, isDirectExecution, isTransientBootstrapError, loadAgentFabricOnboardingContract, loadOrCreateInstallationId, materializeWorkspacePolicy, applyServerEvidencePolicy, materializeInlineSkillFiles, validateSkillBundleSources, nativeSkillDirectory, nativeSkillDirectoryForWorkspace, nativeSkillRootMatchingAuthorization, normalizeGitRemoteIdentity, postTaskOutcome, parseCliOptions, parseSelectedProviderIds, pathExistsOrThrow, portalUrl, providerHintFromEnvironment, providerHintFromProcessArgv, probeRelayConnection, preflightBootstrapWorkspaceIdentity, rawLocalRetentionDays, syncPendingRetentionCapsules, requireCompletedBootstrapEvidence, retryBootstrapOnboarding, synchronizeBootstrapEvidence, deferUnavailableRelayRetention, recoverLegacySkillBundleIdAfterAuthorizationFailure, installedBundleIdForSkillPollAfterAuthorizationFailure, recoveredTaskPolicyWasSuperseded, acquireRelayProcessLease, relayProcessState, releaseDailyContentUpload, reserveDailyContentUpload, run, runAssistantCommand, sourceRepositoryFingerprint, stableRepositoryLauncherContents, summarizeBootstrapOrganizationApi, ensureAgyReadOnlyAttestationPermission, attestAgySkillBundleActivation, responseTextFromEvent, taskResponsePreview, taskReceiptSession, taskSkillPinFailureCode, verifyAgentFabricSkillInstallation, waitForRelayReadiness, withWorkspacePolicyRefreshLock, withWorkspaceSkillActivationLock, } from './index.js';
11
11
  import { canonicalize, signCanonicalObject } from '@dharma-ai-labs/agent-fabric-contracts';
12
12
  import { buildTrajectoryCapsule, trajectoryCapsuleHash } from '@dharma-ai-labs/agent-fabric-evidence-reduction';
13
13
  import { CLI_USAGE } from './usage.js';
@@ -88,6 +88,39 @@ test('bootstrap relay readiness fails closed when acknowledgement never arrives'
88
88
  wait: async () => undefined,
89
89
  }), /relay_session_unacknowledged/);
90
90
  });
91
+ test('bootstrap rejects a connected relay from an older CLI release', async () => {
92
+ await assert.rejects(() => waitForRelayReadiness({
93
+ processState: async () => 'running',
94
+ probe: async () => ({ ok: true, connected: true, organizationId: 'org_test',
95
+ deviceId: 'device_test', relayVersion: '0.2.80' }),
96
+ expectedVersion: '0.2.98',
97
+ attempts: 1,
98
+ }), /relay_version_mismatch:0\.2\.80:0\.2\.98/);
99
+ await assert.rejects(() => waitForRelayReadiness({
100
+ processState: async () => 'running',
101
+ probe: async () => ({ ok: true, connected: false, organizationId: 'org_test',
102
+ deviceId: 'device_test', relayVersion: '0.2.98' }),
103
+ expectedVersion: '0.2.98',
104
+ attempts: 1,
105
+ }), /relay_session_unacknowledged/);
106
+ });
107
+ test('relay process lease rejects concurrent starts and preserves a successor PID', async () => {
108
+ const home = await mkdtemp(join(tmpdir(), 'dharma-relay-lease-'));
109
+ const pidPath = join(home, 'relay', 'relay.pid');
110
+ await mkdir(join(home, 'relay'), { recursive: true });
111
+ await writeFile(pidPath, '99999999\n');
112
+ const release = await acquireRelayProcessLease(home);
113
+ assert.equal(await relayProcessState(home), 'running');
114
+ assert.equal((await readFile(pidPath, 'utf8')).trim(), String(process.pid));
115
+ await assert.rejects(() => acquireRelayProcessLease(home), /Another relay process is already running/);
116
+ await writeFile(pidPath, '424242\n');
117
+ await release();
118
+ assert.equal((await readFile(pidPath, 'utf8')).trim(), '424242');
119
+ await unlink(pidPath);
120
+ const nextRelease = await acquireRelayProcessLease(home);
121
+ await nextRelease();
122
+ assert.equal(await relayProcessState(home), 'stopped');
123
+ });
91
124
  test('bootstrap defers policy-rejected evidence without weakening the disclosure boundary', async () => {
92
125
  const result = await synchronizeBootstrapEvidence(async () => {
93
126
  throw new Error('local_path_disclosure_forbidden: capsule event contains a local path');
@@ -1752,13 +1785,13 @@ test('relay probe opens an authenticated session without polling or leasing work
1752
1785
  },
1753
1786
  openSession: async (version) => {
1754
1787
  sessions += 1;
1755
- assert.equal(version, '0.2.96');
1788
+ assert.equal(version, '0.2.98');
1756
1789
  return { ok: true };
1757
1790
  },
1758
1791
  }));
1759
1792
  assert.equal(sessions, 1);
1760
1793
  assert.deepEqual(result, {
1761
- ok: true, connected: true, organizationId: 'org_test', deviceId: 'device_test', relayVersion: '0.2.96',
1794
+ ok: true, connected: true, organizationId: 'org_test', deviceId: 'device_test', relayVersion: '0.2.98',
1762
1795
  });
1763
1796
  });
1764
1797
  test('relay probe fails closed when the server does not acknowledge the session', async () => {