@dharma-ai-labs/agent-fabric 0.2.86 → 0.2.88
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +28 -2
- package/dist/index.js.map +1 -1
- package/dist/index.test.js +141 -3
- package/dist/index.test.js.map +1 -1
- package/package.json +2 -2
package/dist/index.test.js
CHANGED
|
@@ -9,7 +9,7 @@ import { fileURLToPath, pathToFileURL } from 'node:url';
|
|
|
9
9
|
import { promisify } from 'node:util';
|
|
10
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';
|
|
11
11
|
import { canonicalize, signCanonicalObject } from '@dharma-ai-labs/agent-fabric-contracts';
|
|
12
|
-
import { buildTrajectoryCapsule } from '@dharma-ai-labs/agent-fabric-evidence-reduction';
|
|
12
|
+
import { buildTrajectoryCapsule, trajectoryCapsuleHash } from '@dharma-ai-labs/agent-fabric-evidence-reduction';
|
|
13
13
|
import { CLI_USAGE } from './usage.js';
|
|
14
14
|
import { isSupportedNodeVersion, launchWithRuntime, nodeRuntimeCandidates, runtimeBootstrapHint, } from './runtime-bootstrap.js';
|
|
15
15
|
test('installation identity is durable per DHARMA_HOME and rejects corrupt state', async () => {
|
|
@@ -1334,6 +1334,144 @@ test('queued capsules from a replaced device are retained locally but never sent
|
|
|
1334
1334
|
assert.deepEqual(sent, [current.trajectoryId]);
|
|
1335
1335
|
assert.equal(old.deviceId, '11111111-1111-4111-8111-111111111111');
|
|
1336
1336
|
});
|
|
1337
|
+
test('oversized queued current-device revision is retired only after checking the accepted head', async () => {
|
|
1338
|
+
const base = await materializeWorkspacePolicy({
|
|
1339
|
+
workspace: await mkdtemp(join(tmpdir(), 'dharma-oversized-capsule-')),
|
|
1340
|
+
organizationId: 'org_northstar', revision: 'local',
|
|
1341
|
+
});
|
|
1342
|
+
const session = {
|
|
1343
|
+
provider: 'codex', sessionId: 'oversized-pending', sourcePath: '/private/codex.jsonl',
|
|
1344
|
+
workspace: '/repo', coverage: 'observed',
|
|
1345
|
+
startedAt: '2026-09-24T00:00:00.000Z', endedAt: '2026-09-24T00:00:01.000Z',
|
|
1346
|
+
records: [{ native: { type: 'message' }, sourcePath: '/private/codex.jsonl', line: 1,
|
|
1347
|
+
workspace: '/repo', timestamp: '2026-09-24T00:00:00.000Z', kind: 'metadata' }],
|
|
1348
|
+
};
|
|
1349
|
+
const previousRevisionHash = `sha256:${'a'.repeat(64)}`;
|
|
1350
|
+
const capsule = buildTrajectoryCapsule({
|
|
1351
|
+
organizationId: 'org_northstar', deviceId: '22222222-2222-4222-8222-222222222222',
|
|
1352
|
+
workspaceId: 'workspace-northstar', session, policy: base.policy,
|
|
1353
|
+
rawContentId: `sha256:${'b'.repeat(64)}`, rawBytes: 32,
|
|
1354
|
+
revision: 4, previousRevisionHash,
|
|
1355
|
+
});
|
|
1356
|
+
const capsuleBytes = Buffer.byteLength(canonicalize(capsule));
|
|
1357
|
+
const policyWithSmallerCap = {
|
|
1358
|
+
...base.policy,
|
|
1359
|
+
evidence: { ...base.policy.evidence, maximumCapsuleBytes: capsuleBytes - 1 },
|
|
1360
|
+
};
|
|
1361
|
+
const pending = [{ trajectoryId: capsule.trajectoryId, revision: 4, capsule }];
|
|
1362
|
+
const discarded = [];
|
|
1363
|
+
let synced = 0;
|
|
1364
|
+
let head = {
|
|
1365
|
+
revision: 3, capsuleHash: previousRevisionHash,
|
|
1366
|
+
};
|
|
1367
|
+
let headUnavailable = false;
|
|
1368
|
+
const vault = {
|
|
1369
|
+
listPendingCapsuleSyncs: async () => [...pending],
|
|
1370
|
+
markCapsuleSynced: () => { synced += 1; pending.length = 0; },
|
|
1371
|
+
discardPendingCapsuleSync: (_trajectoryId, _revision, reason) => {
|
|
1372
|
+
discarded.push(reason);
|
|
1373
|
+
pending.length = 0;
|
|
1374
|
+
},
|
|
1375
|
+
};
|
|
1376
|
+
const fabric = {
|
|
1377
|
+
config: { organizationId: 'org_northstar', deviceId: capsule.deviceId },
|
|
1378
|
+
getTrajectoryHead: async () => {
|
|
1379
|
+
if (headUnavailable)
|
|
1380
|
+
throw new Error('provider unavailable');
|
|
1381
|
+
return { trajectoryId: capsule.trajectoryId, head };
|
|
1382
|
+
},
|
|
1383
|
+
syncTrajectory: async () => { throw new Error('oversized capsule must not be uploaded'); },
|
|
1384
|
+
};
|
|
1385
|
+
assert.equal(await syncPendingRetentionCapsules(vault, fabric, policyWithSmallerCap, 'workspace-northstar'), 0);
|
|
1386
|
+
assert.deepEqual(discarded, ['capsule_size_limit_superseded']);
|
|
1387
|
+
assert.equal(synced, 0);
|
|
1388
|
+
assert.equal(capsule.capsuleHash, buildTrajectoryCapsule({
|
|
1389
|
+
organizationId: 'org_northstar', deviceId: capsule.deviceId, workspaceId: 'workspace-northstar',
|
|
1390
|
+
session, policy: base.policy, rawContentId: `sha256:${'b'.repeat(64)}`, rawBytes: 32,
|
|
1391
|
+
revision: 4, previousRevisionHash,
|
|
1392
|
+
}).capsuleHash);
|
|
1393
|
+
pending.push({ trajectoryId: capsule.trajectoryId, revision: 4, capsule });
|
|
1394
|
+
head = { revision: 4, capsuleHash: capsule.capsuleHash };
|
|
1395
|
+
assert.equal(await syncPendingRetentionCapsules(vault, fabric, policyWithSmallerCap, 'workspace-northstar'), 1);
|
|
1396
|
+
assert.equal(synced, 1);
|
|
1397
|
+
assert.deepEqual(discarded, ['capsule_size_limit_superseded']);
|
|
1398
|
+
pending.push({ trajectoryId: capsule.trajectoryId, revision: 4, capsule });
|
|
1399
|
+
headUnavailable = true;
|
|
1400
|
+
await assert.rejects(() => syncPendingRetentionCapsules(vault, fabric, policyWithSmallerCap, 'workspace-northstar'), /provider unavailable/);
|
|
1401
|
+
assert.equal(pending.length, 1);
|
|
1402
|
+
headUnavailable = false;
|
|
1403
|
+
head = { revision: 2, capsuleHash: previousRevisionHash };
|
|
1404
|
+
await assert.rejects(() => syncPendingRetentionCapsules(vault, fabric, policyWithSmallerCap, 'workspace-northstar'), /conflicts with the accepted server head/);
|
|
1405
|
+
assert.equal(pending.length, 1);
|
|
1406
|
+
});
|
|
1407
|
+
test('queued native recipient paths retire only an unsent revision without uploading it', async () => {
|
|
1408
|
+
const workspace = await mkdtemp(join(tmpdir(), 'dharma-recipient-path-capsule-'));
|
|
1409
|
+
const signed = signedPolicyAuthorization({
|
|
1410
|
+
revision: 'content-v1', evidence: {
|
|
1411
|
+
automaticDisclosure: { mode: 'customer_authorized_content', consentReceiptId: 'consent-recipient', allowedContentClasses: ['native_provider_payload'] },
|
|
1412
|
+
maximumCapsuleBytes: 500_000, maximumDailyUploadBytes: 50_000_000,
|
|
1413
|
+
},
|
|
1414
|
+
});
|
|
1415
|
+
const base = await materializeWorkspacePolicy({
|
|
1416
|
+
workspace, organizationId: 'org_northstar', revision: 'portal-bootstrap',
|
|
1417
|
+
serverPolicyAuthorization: signed.envelope, serverPublicKeyEd25519: signed.publicKeyEd25519,
|
|
1418
|
+
workspaceId: 'workspace-northstar', secureStore: memorySecureStore(),
|
|
1419
|
+
});
|
|
1420
|
+
const capsule = buildTrajectoryCapsule({
|
|
1421
|
+
organizationId: 'org_northstar', deviceId: '22222222-2222-4222-8222-222222222222',
|
|
1422
|
+
workspaceId: 'workspace-northstar', policy: base.policy,
|
|
1423
|
+
session: {
|
|
1424
|
+
provider: 'codex', sessionId: 'recipient-path-pending', sourcePath: '/private/codex.jsonl',
|
|
1425
|
+
workspace: '/repo', coverage: 'observed', startedAt: '2026-09-24T00:00:00.000Z',
|
|
1426
|
+
endedAt: '2026-09-24T00:00:01.000Z',
|
|
1427
|
+
records: [{ native: { type: 'tool_call', payload: { recipient: 'peer' } }, sourcePath: '/private/codex.jsonl',
|
|
1428
|
+
line: 1, workspace: '/repo', timestamp: '2026-09-24T00:00:00.000Z', kind: 'tool_call' }],
|
|
1429
|
+
},
|
|
1430
|
+
rawContentId: `sha256:${'b'.repeat(64)}`, rawBytes: 32,
|
|
1431
|
+
});
|
|
1432
|
+
const native = capsule.events[0].payload.nativeProviderPayload;
|
|
1433
|
+
native.payload.recipient = '/home';
|
|
1434
|
+
capsule.capsuleHash = trajectoryCapsuleHash(capsule);
|
|
1435
|
+
const pending = [{ trajectoryId: capsule.trajectoryId, revision: 1, capsule }];
|
|
1436
|
+
const discarded = [];
|
|
1437
|
+
let synced = 0;
|
|
1438
|
+
let head = null;
|
|
1439
|
+
let unavailable = false;
|
|
1440
|
+
const vault = {
|
|
1441
|
+
listPendingCapsuleSyncs: async () => [...pending],
|
|
1442
|
+
markCapsuleSynced: () => { synced += 1; pending.length = 0; },
|
|
1443
|
+
discardPendingCapsuleSync: (_trajectoryId, _revision, reason) => {
|
|
1444
|
+
discarded.push(reason);
|
|
1445
|
+
pending.length = 0;
|
|
1446
|
+
},
|
|
1447
|
+
};
|
|
1448
|
+
const fabric = {
|
|
1449
|
+
config: { organizationId: 'org_northstar', deviceId: capsule.deviceId },
|
|
1450
|
+
getTrajectoryHead: async () => {
|
|
1451
|
+
if (unavailable)
|
|
1452
|
+
throw new Error('provider unavailable');
|
|
1453
|
+
return { trajectoryId: capsule.trajectoryId, head };
|
|
1454
|
+
},
|
|
1455
|
+
syncTrajectory: async () => { throw new Error('path-bearing capsule must not be uploaded'); },
|
|
1456
|
+
};
|
|
1457
|
+
assert.equal(await syncPendingRetentionCapsules(vault, fabric, base.policy, 'workspace-northstar'), 0);
|
|
1458
|
+
assert.deepEqual(discarded, ['local_path_disclosure_superseded']);
|
|
1459
|
+
assert.equal(synced, 0);
|
|
1460
|
+
assert.equal(native.payload.recipient, '/home');
|
|
1461
|
+
pending.push({ trajectoryId: capsule.trajectoryId, revision: 1, capsule });
|
|
1462
|
+
head = { revision: 1, capsuleHash: capsule.capsuleHash };
|
|
1463
|
+
assert.equal(await syncPendingRetentionCapsules(vault, fabric, base.policy, 'workspace-northstar'), 1);
|
|
1464
|
+
assert.equal(synced, 1);
|
|
1465
|
+
assert.deepEqual(discarded, ['local_path_disclosure_superseded']);
|
|
1466
|
+
pending.push({ trajectoryId: capsule.trajectoryId, revision: 1, capsule });
|
|
1467
|
+
head = { revision: 2, capsuleHash: capsule.capsuleHash };
|
|
1468
|
+
await assert.rejects(() => syncPendingRetentionCapsules(vault, fabric, base.policy, 'workspace-northstar'), /conflicts with the accepted server head/);
|
|
1469
|
+
assert.equal(pending.length, 1);
|
|
1470
|
+
head = null;
|
|
1471
|
+
unavailable = true;
|
|
1472
|
+
await assert.rejects(() => syncPendingRetentionCapsules(vault, fabric, base.policy, 'workspace-northstar'), /provider unavailable/);
|
|
1473
|
+
assert.equal(pending.length, 1);
|
|
1474
|
+
});
|
|
1337
1475
|
test('recovered task evidence distinguishes a superseded policy from the current revision', () => {
|
|
1338
1476
|
const capsule = { redactionReceipt: { policyRevision: 'policy-v1' } };
|
|
1339
1477
|
assert.equal(recoveredTaskPolicyWasSuperseded(capsule, { revision: 'policy-v2' }), true);
|
|
@@ -1614,13 +1752,13 @@ test('relay probe opens an authenticated session without polling or leasing work
|
|
|
1614
1752
|
},
|
|
1615
1753
|
openSession: async (version) => {
|
|
1616
1754
|
sessions += 1;
|
|
1617
|
-
assert.equal(version, '0.2.
|
|
1755
|
+
assert.equal(version, '0.2.88');
|
|
1618
1756
|
return { ok: true };
|
|
1619
1757
|
},
|
|
1620
1758
|
}));
|
|
1621
1759
|
assert.equal(sessions, 1);
|
|
1622
1760
|
assert.deepEqual(result, {
|
|
1623
|
-
ok: true, connected: true, organizationId: 'org_test', deviceId: 'device_test', relayVersion: '0.2.
|
|
1761
|
+
ok: true, connected: true, organizationId: 'org_test', deviceId: 'device_test', relayVersion: '0.2.88',
|
|
1624
1762
|
});
|
|
1625
1763
|
});
|
|
1626
1764
|
test('relay probe fails closed when the server does not acknowledge the session', async () => {
|