@dharma-ai-labs/agent-fabric 0.2.15 → 0.2.17
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/README.md +11 -2
- package/dist/index.d.ts +87 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +269 -24
- package/dist/index.js.map +1 -1
- package/dist/index.test.js +175 -5
- package/dist/index.test.js.map +1 -1
- package/dist/schemas/skill-bundle.schema.json +1 -1
- package/dist/schemas/task-envelope.schema.json +1 -1
- package/package.json +9 -9
package/dist/index.test.js
CHANGED
|
@@ -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 { activateAgyPlugin, actionDecisionCapabilityFreshUntil, canonicalFilesystemPath, controlAgentDecisionUrl, installAvailableNativeAgentFabricBootstraps, assertCapsuleAuthorizedByCurrentPolicy, assertRecoveredTaskWorkspacePolicy, assertTaskWorkspacePolicy, assertTaskSkillPin, installNativeAgentFabricBootstrap, installRepositoryAgentFabricSkill, isDirectExecution, materializeWorkspacePolicy, applyServerEvidencePolicy, materializeInlineSkillFiles, nativeSkillDirectory, normalizeGitRemoteIdentity, postTaskOutcome, parseCliOptions, parseSelectedProviderIds, pathExistsOrThrow, portalUrl, rawLocalRetentionDays, recoverLegacySkillBundleIdAfterAuthorizationFailure, installedBundleIdForSkillPollAfterAuthorizationFailure, recoveredTaskPolicyWasSuperseded, relayProcessState, releaseDailyContentUpload, reserveDailyContentUpload, run, runAssistantCommand, sourceRepositoryFingerprint, responseTextFromEvent, taskResponsePreview, taskReceiptSession, taskSkillPinFailureCode, verifyAgentFabricSkillInstallation, withWorkspacePolicyRefreshLock, withWorkspaceSkillActivationLock, } from './index.js';
|
|
10
|
+
import { activateAgyPlugin, attestAgySkillActivation, attestHermesSkillBundleActivation, actionDecisionCapabilityFreshUntil, canonicalFilesystemPath, controlAgentDecisionUrl, installAvailableNativeAgentFabricBootstraps, assertCapsuleAuthorizedByCurrentPolicy, assertRecoveredTaskWorkspacePolicy, assertTaskWorkspacePolicy, assertTaskSkillPin, installNativeAgentFabricBootstrap, installRepositoryAgentFabricSkill, isDirectExecution, materializeWorkspacePolicy, applyServerEvidencePolicy, materializeInlineSkillFiles, nativeSkillDirectory, normalizeGitRemoteIdentity, postTaskOutcome, parseCliOptions, parseSelectedProviderIds, pathExistsOrThrow, portalUrl, rawLocalRetentionDays, recoverLegacySkillBundleIdAfterAuthorizationFailure, installedBundleIdForSkillPollAfterAuthorizationFailure, recoveredTaskPolicyWasSuperseded, relayProcessState, releaseDailyContentUpload, reserveDailyContentUpload, run, runAssistantCommand, sourceRepositoryFingerprint, ensureAgyReadOnlyAttestationPermission, attestAgySkillBundleActivation, responseTextFromEvent, taskResponsePreview, taskReceiptSession, taskSkillPinFailureCode, verifyAgentFabricSkillInstallation, withWorkspacePolicyRefreshLock, withWorkspaceSkillActivationLock, } from './index.js';
|
|
11
11
|
import { canonicalize, signCanonicalObject } from '@dharma-ai-labs/agent-fabric-contracts';
|
|
12
12
|
import { buildTrajectoryCapsule } from '@dharma-ai-labs/agent-fabric-evidence-reduction';
|
|
13
13
|
import { CLI_USAGE } from './usage.js';
|
|
@@ -401,7 +401,8 @@ test('CLI parser preserves repeated repository, key, and provider selections', (
|
|
|
401
401
|
assert.equal(parsed.flags.get('non-interactive'), true);
|
|
402
402
|
assert.deepEqual(parseSelectedProviderIds(parsed.repeated.get('provider') || []), ['codex', 'claude']);
|
|
403
403
|
assert.deepEqual(parseSelectedProviderIds(['agy,codex', 'agy']), ['agy', 'codex']);
|
|
404
|
-
assert.
|
|
404
|
+
assert.deepEqual(parseSelectedProviderIds(['hermes,codex', 'hermes']), ['hermes', 'codex']);
|
|
405
|
+
assert.throws(() => parseSelectedProviderIds(['unsupported']), /codex, claude, agy, or hermes/);
|
|
405
406
|
});
|
|
406
407
|
test('workspace registration reuses a normalized repository identity across local paths', async () => {
|
|
407
408
|
const root = await mkdtemp(join(tmpdir(), 'dharma-repository-identity-'));
|
|
@@ -590,12 +591,15 @@ test('workspace policy refreshes serialize before requesting a new signed author
|
|
|
590
591
|
process.env.DHARMA_HOME = home;
|
|
591
592
|
const events = [];
|
|
592
593
|
try {
|
|
594
|
+
let firstEntered;
|
|
595
|
+
const firstStarted = new Promise((resolve) => { firstEntered = resolve; });
|
|
593
596
|
const first = withWorkspacePolicyRefreshLock('workspace-concurrent', async () => {
|
|
594
597
|
events.push('first-start');
|
|
598
|
+
firstEntered();
|
|
595
599
|
await new Promise((accept) => setTimeout(accept, 40));
|
|
596
600
|
events.push('first-end');
|
|
597
601
|
});
|
|
598
|
-
await
|
|
602
|
+
await firstStarted;
|
|
599
603
|
const second = withWorkspacePolicyRefreshLock('workspace-concurrent', async () => {
|
|
600
604
|
events.push('second-start');
|
|
601
605
|
events.push('second-end');
|
|
@@ -616,12 +620,15 @@ test('task execution and skill synchronization share one workspace-provider acti
|
|
|
616
620
|
process.env.DHARMA_HOME = home;
|
|
617
621
|
const events = [];
|
|
618
622
|
try {
|
|
623
|
+
let taskEntered;
|
|
624
|
+
const taskStarted = new Promise((resolve) => { taskEntered = resolve; });
|
|
619
625
|
const task = withWorkspaceSkillActivationLock('workspace-concurrent', 'codex', async () => {
|
|
620
626
|
events.push('task-start');
|
|
627
|
+
taskEntered();
|
|
621
628
|
await new Promise((accept) => setTimeout(accept, 40));
|
|
622
629
|
events.push('task-end');
|
|
623
630
|
});
|
|
624
|
-
await
|
|
631
|
+
await taskStarted;
|
|
625
632
|
const sync = withWorkspaceSkillActivationLock('workspace-concurrent', 'codex', async () => {
|
|
626
633
|
events.push('sync-start');
|
|
627
634
|
events.push('sync-end');
|
|
@@ -1132,9 +1139,73 @@ test('provider skill roots map to each host native discovery directory', async (
|
|
|
1132
1139
|
assert.equal(nativeSkillDirectory('codex', {}, home), join(home, '.codex', 'skills'));
|
|
1133
1140
|
assert.equal(nativeSkillDirectory('claude', {}, home), join(home, '.claude', 'skills'));
|
|
1134
1141
|
assert.equal(nativeSkillDirectory('agy', {}, home), join(home, '.gemini', 'antigravity-cli', 'plugins', 'dharma-agent-fabric', 'skills'));
|
|
1142
|
+
assert.equal(nativeSkillDirectory('hermes', {}, home), join(home, '.hermes', 'skills'));
|
|
1135
1143
|
assert.equal(nativeSkillDirectory('codex', { CODEX_HOME: join(home, 'custom-codex') }, home), join(home, 'custom-codex', 'skills'));
|
|
1136
1144
|
assert.equal(nativeSkillDirectory('claude', { CLAUDE_CONFIG_DIR: join(home, 'custom-claude') }, home), join(home, 'custom-claude', 'skills'));
|
|
1137
1145
|
assert.equal(nativeSkillDirectory('agy', { AGY_CONFIG_DIR: join(home, 'custom-agy') }, home), join(home, 'custom-agy', 'plugins', 'dharma-agent-fabric', 'skills'));
|
|
1146
|
+
assert.equal(nativeSkillDirectory('hermes', { HERMES_HOME: join(home, 'custom-hermes') }, home), join(home, 'custom-hermes', 'skills'));
|
|
1147
|
+
});
|
|
1148
|
+
test('Hermes bootstrap trusts the repository and verifies native discovery', async () => {
|
|
1149
|
+
const root = await mkdtemp(join(tmpdir(), 'dharma-hermes-skill-'));
|
|
1150
|
+
const home = join(root, 'home');
|
|
1151
|
+
const workspace = join(root, 'repo');
|
|
1152
|
+
const calls = [];
|
|
1153
|
+
await mkdir(workspace, { recursive: true });
|
|
1154
|
+
const canonicalWorkspace = await realpath(workspace);
|
|
1155
|
+
await installRepositoryAgentFabricSkill({
|
|
1156
|
+
workspace,
|
|
1157
|
+
hqUrl: 'https://www.dharma-ai.io',
|
|
1158
|
+
organizationId: 'org_test',
|
|
1159
|
+
workspaceId: 'workspace_test',
|
|
1160
|
+
policyRevision: 'agent-fabric-policy-v1',
|
|
1161
|
+
});
|
|
1162
|
+
const installed = await installNativeAgentFabricBootstrap({
|
|
1163
|
+
provider: 'hermes', workspace, workspaceId: 'workspace_test', organizationId: 'org_test',
|
|
1164
|
+
hqUrl: 'https://www.dharma-ai.io', home, env: { HOME: home, PATH: '/usr/bin:/bin' },
|
|
1165
|
+
executeHermes: async (executable, argv, options) => {
|
|
1166
|
+
calls.push({ executable, argv, cwd: options.cwd });
|
|
1167
|
+
return { stdout: '' };
|
|
1168
|
+
},
|
|
1169
|
+
});
|
|
1170
|
+
assert.equal(installed.verified, true);
|
|
1171
|
+
assert.deepEqual(calls[0], {
|
|
1172
|
+
executable: 'hermes',
|
|
1173
|
+
argv: ['skills', 'trust', canonicalWorkspace],
|
|
1174
|
+
cwd: canonicalWorkspace,
|
|
1175
|
+
});
|
|
1176
|
+
const verified = await verifyAgentFabricSkillInstallation({
|
|
1177
|
+
provider: 'hermes', workspace, home, env: { HOME: home, PATH: '/usr/bin:/bin' },
|
|
1178
|
+
listHermesSkills: async () => ({ stdout: 'dharma-agent-fabric local trusted enabled' }),
|
|
1179
|
+
});
|
|
1180
|
+
assert.equal(verified.ready, true);
|
|
1181
|
+
assert.equal(verified.nativeDiscovered, true);
|
|
1182
|
+
assert.equal(verified.activationAttested, false);
|
|
1183
|
+
assert.match(verified.nextAction, /signed remediation bundle/);
|
|
1184
|
+
});
|
|
1185
|
+
test('Hermes signed activation requires every installed bundle skill to be discovered', async () => {
|
|
1186
|
+
const workspace = await mkdtemp(join(tmpdir(), 'dharma-hermes-activation-'));
|
|
1187
|
+
const canonicalWorkspace = await realpath(workspace);
|
|
1188
|
+
const bundle = {
|
|
1189
|
+
operation: 'install',
|
|
1190
|
+
skills: [{ skillId: 'price-boundary' }, { skillId: 'handoff-authority' }],
|
|
1191
|
+
};
|
|
1192
|
+
const calls = [];
|
|
1193
|
+
const passed = await attestHermesSkillBundleActivation({
|
|
1194
|
+
bundle, workspace,
|
|
1195
|
+
execute: async (_executable, argv) => {
|
|
1196
|
+
calls.push(argv);
|
|
1197
|
+
return { stdout: argv[1] === 'list' ? 'price-boundary\nhandoff-authority\n' : '' };
|
|
1198
|
+
},
|
|
1199
|
+
});
|
|
1200
|
+
assert.equal(passed.status, 'pass');
|
|
1201
|
+
assert.deepEqual(calls[0], ['skills', 'trust', canonicalWorkspace]);
|
|
1202
|
+
assert.deepEqual(calls[1], ['skills', 'list', '--source', 'local', '--enabled-only']);
|
|
1203
|
+
const failed = await attestHermesSkillBundleActivation({
|
|
1204
|
+
bundle, workspace,
|
|
1205
|
+
execute: async (_executable, argv) => ({ stdout: argv[1] === 'list' ? 'price-boundary\n' : '' }),
|
|
1206
|
+
});
|
|
1207
|
+
assert.equal(failed.status, 'fail');
|
|
1208
|
+
assert.match(failed.details, /handoff-authority/);
|
|
1138
1209
|
});
|
|
1139
1210
|
test('native bootstrap installation makes the repository skill verifiable by Codex', async () => {
|
|
1140
1211
|
const root = await mkdtemp(join(tmpdir(), 'dharma-native-skill-'));
|
|
@@ -1207,7 +1278,7 @@ test('Agy skill verification requires the native plugin to be discoverable by th
|
|
|
1207
1278
|
assert.equal(discovered.signedLifecycleReady, false);
|
|
1208
1279
|
assert.equal(discovered.ready, true);
|
|
1209
1280
|
assert.equal(discovered.verificationScope, 'generic_bootstrap');
|
|
1210
|
-
assert.match(discovered.nextAction, /
|
|
1281
|
+
assert.match(discovered.nextAction, /content-bound activation challenge/);
|
|
1211
1282
|
});
|
|
1212
1283
|
test('native bootstrap installation refuses to overwrite an unmanaged provider skill', async () => {
|
|
1213
1284
|
const root = await mkdtemp(join(tmpdir(), 'dharma-native-skill-unmanaged-'));
|
|
@@ -1242,6 +1313,105 @@ test('Agy activation validates and registers the generated plugin before enablin
|
|
|
1242
1313
|
{ executable: 'agy', argv: ['plugin', 'enable', 'dharma-agent-fabric'] },
|
|
1243
1314
|
]);
|
|
1244
1315
|
});
|
|
1316
|
+
test('Agy attestation permission adds only the supported read-only Git preflight', async () => {
|
|
1317
|
+
const home = await mkdtemp(join(tmpdir(), 'dharma-agy-permission-'));
|
|
1318
|
+
const root = join(home, '.gemini', 'antigravity-cli');
|
|
1319
|
+
await mkdir(root, { recursive: true });
|
|
1320
|
+
await writeFile(join(root, 'settings.json'), `${JSON.stringify({
|
|
1321
|
+
enableTelemetry: false,
|
|
1322
|
+
permissions: { allow: ['command(ls)'] },
|
|
1323
|
+
}, null, 2)}\n`);
|
|
1324
|
+
const first = await ensureAgyReadOnlyAttestationPermission({ home, env: {} });
|
|
1325
|
+
const second = await ensureAgyReadOnlyAttestationPermission({ home, env: {} });
|
|
1326
|
+
const settings = JSON.parse(await readFile(join(root, 'settings.json'), 'utf8'));
|
|
1327
|
+
assert.equal(first.changed, true);
|
|
1328
|
+
assert.equal(second.changed, false);
|
|
1329
|
+
assert.deepEqual(settings.permissions.allow, ['command(ls)', 'command(git status)']);
|
|
1330
|
+
assert.equal(settings.enableTelemetry, false);
|
|
1331
|
+
});
|
|
1332
|
+
test('Agy activation attestation proves the invoked skill token without unsafe permission bypasses', async () => {
|
|
1333
|
+
const root = await mkdtemp(join(tmpdir(), 'dharma-agy-attestation-'));
|
|
1334
|
+
const workspace = join(root, 'repo');
|
|
1335
|
+
const skillPath = join(root, 'SKILL.md');
|
|
1336
|
+
await mkdir(workspace, { recursive: true });
|
|
1337
|
+
await writeFile(skillPath, [
|
|
1338
|
+
'# Signed remediation',
|
|
1339
|
+
'',
|
|
1340
|
+
'Dharma activation token: `sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa`',
|
|
1341
|
+
'',
|
|
1342
|
+
].join('\n'));
|
|
1343
|
+
let observed = {};
|
|
1344
|
+
const result = await attestAgySkillActivation({
|
|
1345
|
+
skillId: 'dharma-remediation',
|
|
1346
|
+
skillPath,
|
|
1347
|
+
workspace,
|
|
1348
|
+
challenge: 'agy-test-challenge',
|
|
1349
|
+
execute: async (executable, argv, options) => {
|
|
1350
|
+
observed = { executable, argv, cwd: options.cwd };
|
|
1351
|
+
return { stdout: JSON.stringify({
|
|
1352
|
+
status: 'SUCCESS',
|
|
1353
|
+
response: '```json\\n{"challenge":"agy-test-challenge","activationToken":"sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"}\\n```',
|
|
1354
|
+
}) };
|
|
1355
|
+
},
|
|
1356
|
+
});
|
|
1357
|
+
assert.equal(result.status, 'pass');
|
|
1358
|
+
assert.equal(observed.executable, 'agy');
|
|
1359
|
+
assert.equal(observed.cwd, await realpath(workspace));
|
|
1360
|
+
assert.ok(observed.argv?.includes('--sandbox'));
|
|
1361
|
+
assert.ok(observed.argv?.includes('plan'));
|
|
1362
|
+
assert.ok(observed.argv?.includes('gemini-3.7-flash-low'));
|
|
1363
|
+
assert.equal(observed.argv?.includes('--dangerously-skip-permissions'), false);
|
|
1364
|
+
assert.match(String(observed.argv?.[2]), /^\/dharma-remediation/);
|
|
1365
|
+
assert.doesNotMatch(String(observed.argv?.[2]), /sha256:aaaaaaaa/);
|
|
1366
|
+
});
|
|
1367
|
+
test('Agy activation attestation fails closed on a mismatched content token', async () => {
|
|
1368
|
+
const root = await mkdtemp(join(tmpdir(), 'dharma-agy-attestation-mismatch-'));
|
|
1369
|
+
const skillPath = join(root, 'SKILL.md');
|
|
1370
|
+
await writeFile(skillPath, 'Dharma activation token: `sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa`\n');
|
|
1371
|
+
const result = await attestAgySkillActivation({
|
|
1372
|
+
skillId: 'dharma-remediation',
|
|
1373
|
+
skillPath,
|
|
1374
|
+
workspace: root,
|
|
1375
|
+
challenge: 'agy-test-challenge',
|
|
1376
|
+
execute: async () => ({ stdout: JSON.stringify({
|
|
1377
|
+
status: 'SUCCESS',
|
|
1378
|
+
response: '{"challenge":"agy-test-challenge","activationToken":"sha256:bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb"}',
|
|
1379
|
+
}) }),
|
|
1380
|
+
});
|
|
1381
|
+
assert.equal(result.status, 'fail');
|
|
1382
|
+
assert.equal(result.details, 'Agy returned an activation token that does not match the installed signed skill.');
|
|
1383
|
+
});
|
|
1384
|
+
test('Agy does not report content attestation for an empty clear bundle', async () => {
|
|
1385
|
+
const root = await mkdtemp(join(tmpdir(), 'dharma-agy-empty-attestation-'));
|
|
1386
|
+
const result = await attestAgySkillBundleActivation({
|
|
1387
|
+
bundle: {
|
|
1388
|
+
schema: 'dharma.skill-bundle/v2',
|
|
1389
|
+
bundleId: 'bundle_clear',
|
|
1390
|
+
organizationId: 'org_test',
|
|
1391
|
+
version: '0.0.0',
|
|
1392
|
+
operation: 'clear',
|
|
1393
|
+
riskClass: 'R0',
|
|
1394
|
+
targetSelectors: {
|
|
1395
|
+
organizationAgentIds: [],
|
|
1396
|
+
deviceIds: [],
|
|
1397
|
+
workspaceIds: [],
|
|
1398
|
+
providers: ['agy'],
|
|
1399
|
+
},
|
|
1400
|
+
activationPolicy: 'next_session',
|
|
1401
|
+
rollbackBundleId: null,
|
|
1402
|
+
evaluationReceiptId: 'evaluation_clear',
|
|
1403
|
+
bundleHash: 'unused-by-attestation',
|
|
1404
|
+
createdAt: new Date().toISOString(),
|
|
1405
|
+
expiresAt: new Date(Date.now() + 60_000).toISOString(),
|
|
1406
|
+
skills: [],
|
|
1407
|
+
signature: 'unused-by-attestation',
|
|
1408
|
+
},
|
|
1409
|
+
nativeSkillDirectory: root,
|
|
1410
|
+
workspace: root,
|
|
1411
|
+
});
|
|
1412
|
+
assert.equal(result.status, 'unavailable');
|
|
1413
|
+
assert.equal(result.details, 'The signed bundle contains no Agy skill content to attest.');
|
|
1414
|
+
});
|
|
1245
1415
|
test('native bootstrap installation isolates provider failures during onboarding', async () => {
|
|
1246
1416
|
const result = await installAvailableNativeAgentFabricBootstraps({
|
|
1247
1417
|
providers: [
|