@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/README.md
CHANGED
|
@@ -20,6 +20,7 @@ dharma repositories connect \
|
|
|
20
20
|
--repo "$PWD" \
|
|
21
21
|
--provider codex \
|
|
22
22
|
--provider claude \
|
|
23
|
+
--provider hermes \
|
|
23
24
|
--organization-id <organization-id> \
|
|
24
25
|
--policy-revision <dashboard-policy-revision>
|
|
25
26
|
dharma repositories status --repo "$PWD" --json
|
|
@@ -36,10 +37,18 @@ the same agent. The CLI derives repository identity from a credential-free
|
|
|
36
37
|
normalized Git remote. Repositories without a remote require an explicit stable
|
|
37
38
|
`--repository-key`; absolute paths are never identity.
|
|
38
39
|
|
|
39
|
-
Current provider adapters are Codex, Claude Code, and
|
|
40
|
+
Current provider adapters are Codex, Claude Code, Agy, and Hermes Agent. Run
|
|
40
41
|
`dharma providers list` because evidence, task, continuation, Skill installation,
|
|
41
42
|
activation, and usage capabilities are reported independently.
|
|
42
43
|
|
|
44
|
+
Agy 1.1.15 Skill activation uses only its supported plugin and sandboxed print
|
|
45
|
+
interfaces. During onboarding, Dharma adds the narrow read-only
|
|
46
|
+
`command(git status)` preflight to Agy's permission allowlist. It never uses
|
|
47
|
+
`--dangerously-skip-permissions`. A signed remediation Skill contains a
|
|
48
|
+
content-bound activation token; Agy must return that token with a fresh nonce
|
|
49
|
+
before the device signs an active installation receipt. A mismatch restores the
|
|
50
|
+
previous bundle before the receipt is posted.
|
|
51
|
+
|
|
43
52
|
Signed workspace registration returns the organization-admin-approved evidence
|
|
44
53
|
policy from Dharma HQ. The CLI applies that server revision to
|
|
45
54
|
`.dharma/approved-policy.json` automatically. Without an active content grant,
|
|
@@ -73,7 +82,7 @@ rejects trajectories that do not carry the installed candidate bundle ID:
|
|
|
73
82
|
```bash
|
|
74
83
|
dharma skills sync \
|
|
75
84
|
--workspace-id <workspace-id> \
|
|
76
|
-
--provider <codex|claude|agy> \
|
|
85
|
+
--provider <codex|claude|agy|hermes> \
|
|
77
86
|
--policy .dharma/approved-policy.json \
|
|
78
87
|
--approval-id <evaluation-authorization-id>
|
|
79
88
|
|
package/dist/index.d.ts
CHANGED
|
@@ -115,6 +115,21 @@ export declare function postTaskOutcome(input: {
|
|
|
115
115
|
postEvent: (taskId: string, eventType: TaskReceipt['status'], payload: Record<string, unknown>) => Promise<unknown>;
|
|
116
116
|
}): Promise<unknown>;
|
|
117
117
|
export declare function nativeSkillDirectory(provider: ProviderId, env?: NodeJS.ProcessEnv, home?: string): string;
|
|
118
|
+
type HermesSkillExecutor = (executable: string, argv: string[], options: {
|
|
119
|
+
timeout: number;
|
|
120
|
+
env: NodeJS.ProcessEnv;
|
|
121
|
+
cwd: string;
|
|
122
|
+
}) => Promise<{
|
|
123
|
+
stdout?: string | Buffer;
|
|
124
|
+
}>;
|
|
125
|
+
export declare function trustHermesProject(input: {
|
|
126
|
+
workspace: string;
|
|
127
|
+
env?: NodeJS.ProcessEnv;
|
|
128
|
+
execute?: HermesSkillExecutor;
|
|
129
|
+
}): Promise<{
|
|
130
|
+
workspace: string;
|
|
131
|
+
trusted: boolean;
|
|
132
|
+
}>;
|
|
118
133
|
export declare function installNativeAgentFabricBootstrap(input: {
|
|
119
134
|
provider: ProviderId;
|
|
120
135
|
workspace: string;
|
|
@@ -123,6 +138,7 @@ export declare function installNativeAgentFabricBootstrap(input: {
|
|
|
123
138
|
hqUrl: string;
|
|
124
139
|
env?: NodeJS.ProcessEnv;
|
|
125
140
|
home?: string;
|
|
141
|
+
executeHermes?: HermesSkillExecutor;
|
|
126
142
|
}): Promise<{
|
|
127
143
|
provider: ProviderId;
|
|
128
144
|
nativeSkillDirectory: string;
|
|
@@ -167,6 +183,7 @@ export declare function verifyAgentFabricSkillInstallation(input: {
|
|
|
167
183
|
}) => Promise<{
|
|
168
184
|
stdout: string | Buffer;
|
|
169
185
|
}>;
|
|
186
|
+
listHermesSkills?: HermesSkillExecutor;
|
|
170
187
|
}): Promise<{
|
|
171
188
|
provider: ProviderId;
|
|
172
189
|
ready: boolean;
|
|
@@ -186,6 +203,24 @@ export declare function verifyAgentFabricSkillInstallation(input: {
|
|
|
186
203
|
activation: string;
|
|
187
204
|
nextAction: string;
|
|
188
205
|
}>;
|
|
206
|
+
export declare function attestHermesSkillBundleActivation(input: {
|
|
207
|
+
bundle: SkillBundle;
|
|
208
|
+
workspace: string;
|
|
209
|
+
env?: NodeJS.ProcessEnv;
|
|
210
|
+
execute?: HermesSkillExecutor;
|
|
211
|
+
}): Promise<{
|
|
212
|
+
name: string;
|
|
213
|
+
status: "unavailable";
|
|
214
|
+
details: string;
|
|
215
|
+
} | {
|
|
216
|
+
name: string;
|
|
217
|
+
status: "fail";
|
|
218
|
+
details: string;
|
|
219
|
+
} | {
|
|
220
|
+
name: string;
|
|
221
|
+
status: "pass";
|
|
222
|
+
details: string;
|
|
223
|
+
}>;
|
|
189
224
|
type AgyPluginExecutor = (executable: string, argv: string[], options: {
|
|
190
225
|
timeout: number;
|
|
191
226
|
env: NodeJS.ProcessEnv;
|
|
@@ -195,6 +230,58 @@ export declare function activateAgyPlugin(input?: {
|
|
|
195
230
|
home?: string;
|
|
196
231
|
execute?: AgyPluginExecutor;
|
|
197
232
|
}): Promise<void>;
|
|
233
|
+
export declare function ensureAgyReadOnlyAttestationPermission(input?: {
|
|
234
|
+
env?: NodeJS.ProcessEnv;
|
|
235
|
+
home?: string;
|
|
236
|
+
}): Promise<{
|
|
237
|
+
changed: boolean;
|
|
238
|
+
settingsPath: string;
|
|
239
|
+
permission: string;
|
|
240
|
+
}>;
|
|
241
|
+
type AgyAttestationExecutor = (executable: string, argv: string[], options: {
|
|
242
|
+
timeout: number;
|
|
243
|
+
env: NodeJS.ProcessEnv;
|
|
244
|
+
cwd: string;
|
|
245
|
+
}) => Promise<{
|
|
246
|
+
stdout: string | Buffer;
|
|
247
|
+
}>;
|
|
248
|
+
export declare function attestAgySkillActivation(input: {
|
|
249
|
+
skillId: string;
|
|
250
|
+
skillPath: string;
|
|
251
|
+
workspace: string;
|
|
252
|
+
challenge?: string;
|
|
253
|
+
env?: NodeJS.ProcessEnv;
|
|
254
|
+
execute?: AgyAttestationExecutor;
|
|
255
|
+
}): Promise<{
|
|
256
|
+
name: string;
|
|
257
|
+
status: "unavailable";
|
|
258
|
+
details: string;
|
|
259
|
+
} | {
|
|
260
|
+
name: string;
|
|
261
|
+
status: "fail";
|
|
262
|
+
details: string;
|
|
263
|
+
} | {
|
|
264
|
+
name: string;
|
|
265
|
+
status: "pass";
|
|
266
|
+
details: string;
|
|
267
|
+
}>;
|
|
268
|
+
export declare function attestAgySkillBundleActivation(input: {
|
|
269
|
+
bundle: SkillBundle;
|
|
270
|
+
nativeSkillDirectory: string;
|
|
271
|
+
workspace: string;
|
|
272
|
+
}): Promise<{
|
|
273
|
+
name: string;
|
|
274
|
+
status: "unavailable";
|
|
275
|
+
details: string;
|
|
276
|
+
} | {
|
|
277
|
+
name: string;
|
|
278
|
+
status: "fail";
|
|
279
|
+
details: string;
|
|
280
|
+
} | {
|
|
281
|
+
name: string;
|
|
282
|
+
status: "pass";
|
|
283
|
+
details: string;
|
|
284
|
+
}>;
|
|
198
285
|
export declare function materializeInlineSkillFiles(bundle: SkillBundle, sourceRoot: string): Promise<boolean>;
|
|
199
286
|
export declare function recoverLegacySkillBundleIdAfterAuthorizationFailure(input: {
|
|
200
287
|
nativeSkillDirectory: string;
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AASA,OAAO,EAGL,KAAK,kBAAkB,EAAE,KAAK,UAAU,EAAE,KAAK,0BAA0B,EAC1E,MAAM,wCAAwC,CAAC;AAChD,OAAO,EAA2G,KAAK,iBAAiB,EAAE,MAAM,iDAAiD,CAAC;AAClM,OAAO,EAAsE,KAAK,kBAAkB,EAAE,MAAM,qCAAqC,CAAC;AAClJ,OAAO,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/dist/index.js
CHANGED
|
@@ -10,15 +10,19 @@ import { promisify } from 'node:util';
|
|
|
10
10
|
import { canonicalize, createActionDecisionPublicKeyResolver, sha256, validateContract, validateTrustedServerSigningKeysetContract, verifyCanonicalObject, verifyInitialServerSigningKeyset, } from '@dharma-ai-labs/agent-fabric-contracts';
|
|
11
11
|
import { buildTrajectoryCapsule, redactValue, referencesExcludedPath, trajectoryCapsuleHash } from '@dharma-ai-labs/agent-fabric-evidence-reduction';
|
|
12
12
|
import { assertPolicy, loadOrganizationPolicy, verifyServerAuthorizedPolicy } from '@dharma-ai-labs/agent-fabric-policy';
|
|
13
|
-
import { agyAdapter, claudeAdapter, codexAdapter, providerAdapters, providerExecutionRecords, providerProcessEnvironment } from '@dharma-ai-labs/agent-fabric-provider-adapters';
|
|
13
|
+
import { agyAdapter, claudeAdapter, codexAdapter, hermesAdapter, providerAdapters, providerExecutionRecords, providerProcessEnvironment } from '@dharma-ai-labs/agent-fabric-provider-adapters';
|
|
14
14
|
import { AgentFabricClient, beginEnrollment, loadOrCreateDeviceIdentity, normalizeHqUrl, pollEnrollment, deleteActiveSkillAuthorizationAnchor, loadActiveSkillAuthorizationAnchor, loadDeviceEnrollmentAnchor, saveActiveSkillAuthorizationAnchor, isDefinitiveAgentFabricRejection, recoverDeviceEnrollmentConsistency, saveDeviceConfig, saveDeviceEnrollmentAnchor, } from '@dharma-ai-labs/agent-fabric-relay-client';
|
|
15
15
|
import { AgentFabricClient as AgentFabricApiClient } from '@dharma-ai-labs/agent-fabric-sdk';
|
|
16
16
|
import { getActiveSkillBundleAuthorization, getExpiredSkillBundleAuthorizationForReplacement, getLegacySkillBundleIdForUpgrade, installSkillBundle, rollbackUnconfirmedSkillBundle, verifySkillBundle } from '@dharma-ai-labs/agent-fabric-skill-manager';
|
|
17
17
|
import { executeTask, FileActionExecutionJournal, FileTaskReceiptStore, providerInstructionsForTask, } from '@dharma-ai-labs/agent-fabric-task-runner';
|
|
18
18
|
import { CLI_USAGE } from './usage.js';
|
|
19
|
-
const VERSION = '0.2.
|
|
19
|
+
const VERSION = '0.2.17';
|
|
20
20
|
const USAGE = CLI_USAGE;
|
|
21
21
|
const execFileAsync = promisify(execFile);
|
|
22
|
+
const LOCAL_PROVIDER_IDS = ['codex', 'claude', 'agy', 'hermes'];
|
|
23
|
+
function isLocalProviderId(value) {
|
|
24
|
+
return LOCAL_PROVIDER_IDS.includes(value);
|
|
25
|
+
}
|
|
22
26
|
export function parseCliOptions(args) {
|
|
23
27
|
const positional = [];
|
|
24
28
|
const flags = new Map();
|
|
@@ -319,7 +323,7 @@ export function assertCapsuleAuthorizedByCurrentPolicy(capsule, policy) {
|
|
|
319
323
|
&& captureProvenance.sourceClass === 'signed_task_execution';
|
|
320
324
|
const signedTaskBundleIds = [...new Set(events.map((event) => (event && typeof event === 'object' && !Array.isArray(event)
|
|
321
325
|
? String(event.skillBundleId || '') : '')).filter(Boolean))];
|
|
322
|
-
if (!
|
|
326
|
+
if (!isLocalProviderId(provider)
|
|
323
327
|
|| !digest.test(String(capsule.sessionId || ''))
|
|
324
328
|
|| (signedTaskCapture
|
|
325
329
|
? !uuid.test(String(capsule.taskId || ''))
|
|
@@ -740,7 +744,7 @@ export async function withWorkspacePolicyRefreshLock(workspaceId, operation) {
|
|
|
740
744
|
return withFileLock(`${workspaceAuthorizationStatePath(workspaceId)}.refresh.lock`, operation, 'Timed out waiting for the workspace policy refresh lock.');
|
|
741
745
|
}
|
|
742
746
|
export async function withWorkspaceSkillActivationLock(workspaceId, provider, operation) {
|
|
743
|
-
if (!workspaceId || !
|
|
747
|
+
if (!workspaceId || !isLocalProviderId(provider)) {
|
|
744
748
|
throw new Error('Skill activation lock requires a registered workspace and supported provider.');
|
|
745
749
|
}
|
|
746
750
|
const key = createHash('sha256').update(`${workspaceId}:${provider}`).digest('hex');
|
|
@@ -895,6 +899,8 @@ function providerAdapter(provider) {
|
|
|
895
899
|
return claudeAdapter;
|
|
896
900
|
if (provider === 'agy')
|
|
897
901
|
return agyAdapter;
|
|
902
|
+
if (provider === 'hermes')
|
|
903
|
+
return hermesAdapter;
|
|
898
904
|
return null;
|
|
899
905
|
}
|
|
900
906
|
function deterministicUuid(value) {
|
|
@@ -1763,8 +1769,8 @@ export function parseSelectedProviderIds(values) {
|
|
|
1763
1769
|
.filter(Boolean))];
|
|
1764
1770
|
if (selected.length === 0)
|
|
1765
1771
|
return null;
|
|
1766
|
-
if (selected.some((value) => !
|
|
1767
|
-
throw new Error('Repository providers must be codex, claude, or
|
|
1772
|
+
if (selected.some((value) => !isLocalProviderId(value))) {
|
|
1773
|
+
throw new Error('Repository providers must be codex, claude, agy, or hermes. Repeat --provider to select more than one.');
|
|
1768
1774
|
}
|
|
1769
1775
|
return selected;
|
|
1770
1776
|
}
|
|
@@ -2058,7 +2064,7 @@ Use the installed \`dharma\` CLI for organization-scoped agent work. Never print
|
|
|
2058
2064
|
Do not substitute a placeholder or shell variable. Stop unless the result reports \`ready: true\`. Restart the provider after the first installation so it discovers the native skill.
|
|
2059
2065
|
2. Run \`dharma providers list\` to confirm the provider's independently tested evidence, task, continuation, skill, activation, and rollback capabilities.
|
|
2060
2066
|
3. Keep \`dharma relay start --policy .dharma/approved-policy.json\` running for signed task, evidence, and skill delivery.
|
|
2061
|
-
4. Preview the exact automatic disclosure with \`dharma evidence preview --workspace . --provider codex --policy .dharma/approved-policy.json --maximum-sessions 20\` for Codex, replacing only the literal provider value with \`claude\` or \`
|
|
2067
|
+
4. Preview the exact automatic disclosure with \`dharma evidence preview --workspace . --provider codex --policy .dharma/approved-policy.json --maximum-sessions 20\` for Codex, replacing only the literal provider value with \`claude\`, \`agy\`, or \`hermes\` when that is the current agent. Confirm the policy mode and consent receipt before syncing.
|
|
2062
2068
|
5. Run local deterministic self-analysis during capture. Deliver event counts, timing, coverage, failure signals, tool-discipline results, reason codes, and content availability metadata. Do not invent a semantic judgment from metadata. Sessions flagged \`semanticReviewRecommended\` require a policy-authorized evidence request or customer-authorized content mode before server judging.
|
|
2063
2069
|
6. Use only signed tasks whose organization, device, workspace, authority, budget, and skill pin pass local validation.
|
|
2064
2070
|
7. For cross-agent help, ask the control plane for a structured, task-bound handoff. Do not open arbitrary chat, shell, file, merge, deploy, or secret authority.
|
|
@@ -2903,8 +2909,20 @@ export function nativeSkillDirectory(provider, env = process.env, home = homedir
|
|
|
2903
2909
|
return resolve(env.CODEX_HOME || resolve(home, '.codex'), 'skills');
|
|
2904
2910
|
if (provider === 'claude')
|
|
2905
2911
|
return resolve(env.CLAUDE_CONFIG_DIR || resolve(home, '.claude'), 'skills');
|
|
2912
|
+
if (provider === 'hermes')
|
|
2913
|
+
return resolve(env.HERMES_HOME || resolve(home, '.hermes'), 'skills');
|
|
2906
2914
|
return resolve(env.AGY_CONFIG_DIR || resolve(home, '.gemini', 'antigravity-cli'), 'plugins', 'dharma-agent-fabric', 'skills');
|
|
2907
2915
|
}
|
|
2916
|
+
export async function trustHermesProject(input) {
|
|
2917
|
+
const workspace = await realpath(input.workspace);
|
|
2918
|
+
const execute = input.execute || ((executable, argv, options) => execFileAsync(executable, argv, options));
|
|
2919
|
+
await execute('hermes', ['skills', 'trust', workspace], {
|
|
2920
|
+
timeout: 30_000,
|
|
2921
|
+
env: providerProcessEnvironment(input.env),
|
|
2922
|
+
cwd: workspace,
|
|
2923
|
+
});
|
|
2924
|
+
return { workspace, trusted: true };
|
|
2925
|
+
}
|
|
2908
2926
|
export async function installNativeAgentFabricBootstrap(input) {
|
|
2909
2927
|
const root = nativeSkillDirectory(input.provider, input.env, input.home);
|
|
2910
2928
|
const skillRoot = resolve(root, 'dharma-agent-fabric');
|
|
@@ -2940,6 +2958,13 @@ The repository-local skill and connection manifest are authoritative for the act
|
|
|
2940
2958
|
}, null, 2)}\n`, { mode: 0o600 });
|
|
2941
2959
|
if (input.provider === 'agy')
|
|
2942
2960
|
await activateAgyPlugin({ env: input.env, home: input.home });
|
|
2961
|
+
if (input.provider === 'hermes') {
|
|
2962
|
+
await trustHermesProject({
|
|
2963
|
+
workspace: input.workspace,
|
|
2964
|
+
env: input.env,
|
|
2965
|
+
execute: input.executeHermes,
|
|
2966
|
+
});
|
|
2967
|
+
}
|
|
2943
2968
|
return {
|
|
2944
2969
|
provider: input.provider,
|
|
2945
2970
|
nativeSkillDirectory: root,
|
|
@@ -2993,7 +3018,7 @@ export async function verifyAgentFabricSkillInstallation(input) {
|
|
|
2993
3018
|
catch { }
|
|
2994
3019
|
}
|
|
2995
3020
|
const nativeInstalled = nativeManaged;
|
|
2996
|
-
let nativeDiscovered = input.provider
|
|
3021
|
+
let nativeDiscovered = ['agy', 'hermes'].includes(input.provider) ? false : nativeInstalled;
|
|
2997
3022
|
if (input.provider === 'agy' && nativeInstalled) {
|
|
2998
3023
|
try {
|
|
2999
3024
|
const listAgyPlugins = input.listAgyPlugins
|
|
@@ -3014,9 +3039,20 @@ export async function verifyAgentFabricSkillInstallation(input) {
|
|
|
3014
3039
|
}
|
|
3015
3040
|
catch { }
|
|
3016
3041
|
}
|
|
3017
|
-
|
|
3042
|
+
if (input.provider === 'hermes' && nativeInstalled) {
|
|
3043
|
+
try {
|
|
3044
|
+
const listHermesSkills = input.listHermesSkills
|
|
3045
|
+
|| ((executable, argv, options) => (execFileAsync(executable, argv, options)));
|
|
3046
|
+
const { stdout } = await listHermesSkills('hermes', ['skills', 'list', '--source', 'local', '--enabled-only'], {
|
|
3047
|
+
timeout: 30_000,
|
|
3048
|
+
env: providerProcessEnvironment(input.env),
|
|
3049
|
+
cwd: workspace,
|
|
3050
|
+
});
|
|
3051
|
+
nativeDiscovered = /\bdharma-agent-fabric\b/.test(String(stdout || ''));
|
|
3052
|
+
}
|
|
3053
|
+
catch { }
|
|
3054
|
+
}
|
|
3018
3055
|
const bootstrapReady = repositoryInstalled && nativeInstalled && nativeDiscovered;
|
|
3019
|
-
const signedLifecycleReady = bootstrapReady && activationAttested;
|
|
3020
3056
|
let workspaceId;
|
|
3021
3057
|
let organizationAgentId;
|
|
3022
3058
|
try {
|
|
@@ -3031,6 +3067,17 @@ export async function verifyAgentFabricSkillInstallation(input) {
|
|
|
3031
3067
|
const activeBundleId = workspaceId && organizationAgentId && config
|
|
3032
3068
|
? (await activeSkillAuthorization(input.provider, workspaceId, organizationAgentId, config))?.bundleId ?? null
|
|
3033
3069
|
: null;
|
|
3070
|
+
let activationAttested = !['agy', 'hermes'].includes(input.provider) ? nativeInstalled : false;
|
|
3071
|
+
if (['agy', 'hermes'].includes(input.provider) && activeBundleId && workspaceId) {
|
|
3072
|
+
try {
|
|
3073
|
+
const receipt = JSON.parse(await readFile(resolve(nativeRoot, '.dharma-managed', 'workspaces', workspaceId, 'active', 'INSTALL_RECEIPT.json'), 'utf8'));
|
|
3074
|
+
activationAttested = Array.isArray(receipt.checks) && receipt.checks.some((item) => (item && typeof item === 'object'
|
|
3075
|
+
&& item.name === `provider:${input.provider}:activation`
|
|
3076
|
+
&& item.status === 'pass'));
|
|
3077
|
+
}
|
|
3078
|
+
catch { }
|
|
3079
|
+
}
|
|
3080
|
+
const signedLifecycleReady = bootstrapReady && activationAttested && Boolean(activeBundleId);
|
|
3034
3081
|
return {
|
|
3035
3082
|
provider: input.provider,
|
|
3036
3083
|
ready: bootstrapReady,
|
|
@@ -3047,15 +3094,61 @@ export async function verifyAgentFabricSkillInstallation(input) {
|
|
|
3047
3094
|
nativeSkillPath,
|
|
3048
3095
|
workspaceId: workspaceId || null,
|
|
3049
3096
|
activeBundleId,
|
|
3050
|
-
activation: input.provider === 'agy' ? '
|
|
3051
|
-
nextAction: input.provider === 'agy' && bootstrapReady
|
|
3052
|
-
? 'The Agy bootstrap is installed and discoverable.
|
|
3053
|
-
: bootstrapReady
|
|
3054
|
-
?
|
|
3055
|
-
:
|
|
3097
|
+
activation: input.provider === 'agy' ? (activationAttested ? 'attested' : 'manual_invocation_required') : 'next_session',
|
|
3098
|
+
nextAction: input.provider === 'agy' && bootstrapReady && !activationAttested
|
|
3099
|
+
? 'The Agy bootstrap is installed and discoverable. A signed remediation bundle must include and pass the content-bound activation challenge before full lifecycle support is reported.'
|
|
3100
|
+
: input.provider === 'hermes' && bootstrapReady && !activationAttested
|
|
3101
|
+
? 'The Hermes bootstrap is installed, the project is trusted, and the skill is discoverable. A signed remediation bundle must pass Hermes discovery before full lifecycle support is reported.'
|
|
3102
|
+
: bootstrapReady
|
|
3103
|
+
? `Start a new ${input.provider} session from ${workspace} and invoke the dharma-agent-fabric skill.`
|
|
3104
|
+
: 'Run dharma onboard again from the repository root.',
|
|
3105
|
+
};
|
|
3106
|
+
}
|
|
3107
|
+
export async function attestHermesSkillBundleActivation(input) {
|
|
3108
|
+
if (input.bundle.skills.length === 0) {
|
|
3109
|
+
return {
|
|
3110
|
+
name: 'provider:hermes:activation',
|
|
3111
|
+
status: 'unavailable',
|
|
3112
|
+
details: 'The signed bundle contains no Hermes skill content to discover.',
|
|
3113
|
+
};
|
|
3114
|
+
}
|
|
3115
|
+
const workspace = await realpath(input.workspace);
|
|
3116
|
+
const execute = input.execute || ((executable, argv, options) => execFileAsync(executable, argv, options));
|
|
3117
|
+
await trustHermesProject({ workspace, env: input.env, execute });
|
|
3118
|
+
let stdout;
|
|
3119
|
+
try {
|
|
3120
|
+
({ stdout } = await execute('hermes', ['skills', 'list', '--source', 'local', '--enabled-only'], {
|
|
3121
|
+
timeout: 30_000,
|
|
3122
|
+
env: providerProcessEnvironment(input.env),
|
|
3123
|
+
cwd: workspace,
|
|
3124
|
+
}));
|
|
3125
|
+
}
|
|
3126
|
+
catch (error) {
|
|
3127
|
+
return {
|
|
3128
|
+
name: 'provider:hermes:activation',
|
|
3129
|
+
status: 'fail',
|
|
3130
|
+
details: error instanceof Error ? `Hermes skill discovery failed: ${error.message}`.slice(0, 1_000) : 'Hermes skill discovery failed.',
|
|
3131
|
+
};
|
|
3132
|
+
}
|
|
3133
|
+
const listing = String(stdout || '');
|
|
3134
|
+
const missing = input.bundle.skills
|
|
3135
|
+
.map((skill) => skill.skillId)
|
|
3136
|
+
.filter((skillId) => !listing.includes(skillId));
|
|
3137
|
+
if (missing.length) {
|
|
3138
|
+
return {
|
|
3139
|
+
name: 'provider:hermes:activation',
|
|
3140
|
+
status: 'fail',
|
|
3141
|
+
details: `Hermes did not discover the installed signed skill${missing.length === 1 ? '' : 's'}: ${missing.join(', ')}`,
|
|
3142
|
+
};
|
|
3143
|
+
}
|
|
3144
|
+
return {
|
|
3145
|
+
name: 'provider:hermes:activation',
|
|
3146
|
+
status: 'pass',
|
|
3147
|
+
details: `Hermes discovered ${input.bundle.skills.length} installed signed skill${input.bundle.skills.length === 1 ? '' : 's'} in the trusted workspace.`,
|
|
3056
3148
|
};
|
|
3057
3149
|
}
|
|
3058
3150
|
export async function activateAgyPlugin(input = {}) {
|
|
3151
|
+
await ensureAgyReadOnlyAttestationPermission({ env: input.env, home: input.home });
|
|
3059
3152
|
const root = resolve(nativeSkillDirectory('agy', input.env, input.home), '..');
|
|
3060
3153
|
const execute = input.execute || ((executable, argv, options) => execFileAsync(executable, argv, options));
|
|
3061
3154
|
const options = { timeout: 30_000, env: providerProcessEnvironment(input.env) };
|
|
@@ -3071,6 +3164,148 @@ export async function activateAgyPlugin(input = {}) {
|
|
|
3071
3164
|
await execute('agy', ['plugin', 'install', root], options);
|
|
3072
3165
|
await execute('agy', ['plugin', 'enable', 'dharma-agent-fabric'], options);
|
|
3073
3166
|
}
|
|
3167
|
+
const AGY_ATTESTATION_PERMISSION = 'command(git status)';
|
|
3168
|
+
const AGY_ACTIVATION_TOKEN = /^Dharma activation token: `(sha256:[a-f0-9]{64})`$/m;
|
|
3169
|
+
export async function ensureAgyReadOnlyAttestationPermission(input = {}) {
|
|
3170
|
+
const configRoot = resolve(input.env?.AGY_CONFIG_DIR || resolve(input.home || homedir(), '.gemini', 'antigravity-cli'));
|
|
3171
|
+
const settingsPath = resolve(configRoot, 'settings.json');
|
|
3172
|
+
await mkdir(configRoot, { recursive: true, mode: 0o700 });
|
|
3173
|
+
let settings = {};
|
|
3174
|
+
if (await pathExists(settingsPath)) {
|
|
3175
|
+
const parsed = JSON.parse(await readFile(settingsPath, 'utf8'));
|
|
3176
|
+
if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) {
|
|
3177
|
+
throw new Error('Agy settings must be a JSON object before Dharma can add its read-only preflight permission.');
|
|
3178
|
+
}
|
|
3179
|
+
settings = parsed;
|
|
3180
|
+
}
|
|
3181
|
+
const permissions = settings.permissions && typeof settings.permissions === 'object' && !Array.isArray(settings.permissions)
|
|
3182
|
+
? settings.permissions
|
|
3183
|
+
: {};
|
|
3184
|
+
const current = permissions.allow;
|
|
3185
|
+
if (current !== undefined && (!Array.isArray(current) || current.some((item) => typeof item !== 'string'))) {
|
|
3186
|
+
throw new Error('Agy permissions.allow must be a string array.');
|
|
3187
|
+
}
|
|
3188
|
+
const allow = [...new Set([...(Array.isArray(current) ? current : []), AGY_ATTESTATION_PERMISSION])];
|
|
3189
|
+
if (Array.isArray(current) && current.length === allow.length) {
|
|
3190
|
+
return { changed: false, settingsPath, permission: AGY_ATTESTATION_PERMISSION };
|
|
3191
|
+
}
|
|
3192
|
+
const updated = { ...settings, permissions: { ...permissions, allow } };
|
|
3193
|
+
const temporary = resolve(configRoot, `.settings.${randomUUID()}.tmp`);
|
|
3194
|
+
await writeFile(temporary, `${JSON.stringify(updated, null, 2)}\n`, { mode: 0o600 });
|
|
3195
|
+
await rename(temporary, settingsPath);
|
|
3196
|
+
return { changed: true, settingsPath, permission: AGY_ATTESTATION_PERMISSION };
|
|
3197
|
+
}
|
|
3198
|
+
function parseAgyStructuredResponse(stdout) {
|
|
3199
|
+
try {
|
|
3200
|
+
const outer = JSON.parse(String(stdout));
|
|
3201
|
+
if (outer.status !== 'SUCCESS' || typeof outer.response !== 'string')
|
|
3202
|
+
return null;
|
|
3203
|
+
const match = outer.response.match(/\{[\s\S]*\}/);
|
|
3204
|
+
if (!match)
|
|
3205
|
+
return null;
|
|
3206
|
+
const value = JSON.parse(match[0]);
|
|
3207
|
+
return value && typeof value === 'object' && !Array.isArray(value) ? value : null;
|
|
3208
|
+
}
|
|
3209
|
+
catch {
|
|
3210
|
+
return null;
|
|
3211
|
+
}
|
|
3212
|
+
}
|
|
3213
|
+
export async function attestAgySkillActivation(input) {
|
|
3214
|
+
if (!/^[A-Za-z0-9][A-Za-z0-9._-]{0,127}$/.test(input.skillId)) {
|
|
3215
|
+
throw new Error('Agy activation skill identifier is invalid.');
|
|
3216
|
+
}
|
|
3217
|
+
const skill = await readFile(input.skillPath, 'utf8');
|
|
3218
|
+
const token = skill.match(AGY_ACTIVATION_TOKEN)?.[1];
|
|
3219
|
+
if (!token) {
|
|
3220
|
+
return {
|
|
3221
|
+
name: 'provider:agy:activation',
|
|
3222
|
+
status: 'unavailable',
|
|
3223
|
+
details: `Signed skill ${input.skillId} does not contain a Dharma activation token.`,
|
|
3224
|
+
};
|
|
3225
|
+
}
|
|
3226
|
+
const challenge = input.challenge || randomUUID();
|
|
3227
|
+
if (!/^[A-Za-z0-9_-]{8,128}$/.test(challenge))
|
|
3228
|
+
throw new Error('Agy activation challenge is invalid.');
|
|
3229
|
+
const schema = JSON.stringify({
|
|
3230
|
+
type: 'object',
|
|
3231
|
+
additionalProperties: false,
|
|
3232
|
+
required: ['challenge', 'activationToken'],
|
|
3233
|
+
properties: {
|
|
3234
|
+
challenge: { type: 'string' },
|
|
3235
|
+
activationToken: { type: 'string' },
|
|
3236
|
+
},
|
|
3237
|
+
});
|
|
3238
|
+
const prompt = `/${input.skillId}\nDharma activation attestation. Do not use tools or inspect files. Return only JSON with fields challenge and activationToken. Challenge: ${challenge}`;
|
|
3239
|
+
const execute = input.execute || ((executable, argv, options) => execFileAsync(executable, argv, options));
|
|
3240
|
+
let stdout;
|
|
3241
|
+
try {
|
|
3242
|
+
({ stdout } = await execute('agy', [
|
|
3243
|
+
'--new-project',
|
|
3244
|
+
'--print', prompt,
|
|
3245
|
+
'--output-format', 'json',
|
|
3246
|
+
'--json-schema', schema,
|
|
3247
|
+
'--model', input.env?.DHARMA_AGY_ATTEST_MODEL || 'gemini-3.7-flash-low',
|
|
3248
|
+
'--mode', 'plan',
|
|
3249
|
+
'--sandbox',
|
|
3250
|
+
'--print-timeout', '90s',
|
|
3251
|
+
], {
|
|
3252
|
+
timeout: 120_000,
|
|
3253
|
+
env: providerProcessEnvironment(input.env),
|
|
3254
|
+
cwd: await realpath(input.workspace),
|
|
3255
|
+
}));
|
|
3256
|
+
}
|
|
3257
|
+
catch (error) {
|
|
3258
|
+
return {
|
|
3259
|
+
name: 'provider:agy:activation',
|
|
3260
|
+
status: 'fail',
|
|
3261
|
+
details: error instanceof Error ? `Agy activation process failed: ${error.message}`.slice(0, 1_000) : 'Agy activation process failed.',
|
|
3262
|
+
};
|
|
3263
|
+
}
|
|
3264
|
+
const response = parseAgyStructuredResponse(stdout);
|
|
3265
|
+
if (!response || response.challenge !== challenge) {
|
|
3266
|
+
return {
|
|
3267
|
+
name: 'provider:agy:activation',
|
|
3268
|
+
status: 'fail',
|
|
3269
|
+
details: 'Agy did not return the fresh activation challenge.',
|
|
3270
|
+
};
|
|
3271
|
+
}
|
|
3272
|
+
if (response.activationToken !== token) {
|
|
3273
|
+
return {
|
|
3274
|
+
name: 'provider:agy:activation',
|
|
3275
|
+
status: 'fail',
|
|
3276
|
+
details: 'Agy returned an activation token that does not match the installed signed skill.',
|
|
3277
|
+
};
|
|
3278
|
+
}
|
|
3279
|
+
return {
|
|
3280
|
+
name: 'provider:agy:activation',
|
|
3281
|
+
status: 'pass',
|
|
3282
|
+
details: `Agy expanded ${input.skillId} and returned a fresh content-bound challenge.`,
|
|
3283
|
+
};
|
|
3284
|
+
}
|
|
3285
|
+
export async function attestAgySkillBundleActivation(input) {
|
|
3286
|
+
if (input.bundle.skills.length === 0) {
|
|
3287
|
+
return {
|
|
3288
|
+
name: 'provider:agy:activation',
|
|
3289
|
+
status: 'unavailable',
|
|
3290
|
+
details: 'The signed bundle contains no Agy skill content to attest.',
|
|
3291
|
+
};
|
|
3292
|
+
}
|
|
3293
|
+
await activateAgyPlugin();
|
|
3294
|
+
for (const skill of input.bundle.skills) {
|
|
3295
|
+
const check = await attestAgySkillActivation({
|
|
3296
|
+
skillId: skill.skillId,
|
|
3297
|
+
skillPath: resolve(input.nativeSkillDirectory, skill.skillId, 'SKILL.md'),
|
|
3298
|
+
workspace: input.workspace,
|
|
3299
|
+
});
|
|
3300
|
+
if (check.status !== 'pass')
|
|
3301
|
+
return check;
|
|
3302
|
+
}
|
|
3303
|
+
return {
|
|
3304
|
+
name: 'provider:agy:activation',
|
|
3305
|
+
status: 'pass',
|
|
3306
|
+
details: `Agy expanded ${input.bundle.skills.length} signed skill${input.bundle.skills.length === 1 ? '' : 's'} with fresh content-bound challenges.`,
|
|
3307
|
+
};
|
|
3308
|
+
}
|
|
3074
3309
|
function containedInlinePath(root, value) {
|
|
3075
3310
|
if (!value || value.includes('\\') || isAbsolute(value))
|
|
3076
3311
|
throw new Error('Inline skill file path is invalid.');
|
|
@@ -3136,8 +3371,8 @@ export async function installedBundleIdForSkillPollAfterAuthorizationFailure(inp
|
|
|
3136
3371
|
async function skillSync(flags) {
|
|
3137
3372
|
const workspaceId = required(flags, 'workspace-id');
|
|
3138
3373
|
const providerValue = required(flags, 'provider');
|
|
3139
|
-
if (!
|
|
3140
|
-
throw new Error('Skill provider must be codex, claude, or
|
|
3374
|
+
if (!isLocalProviderId(providerValue))
|
|
3375
|
+
throw new Error('Skill provider must be codex, claude, agy, or hermes.');
|
|
3141
3376
|
const provider = providerValue;
|
|
3142
3377
|
return withWorkspaceSkillActivationLock(workspaceId, provider, async () => {
|
|
3143
3378
|
const workspace = (await registry()).find((item) => item.workspaceId === workspaceId);
|
|
@@ -3224,6 +3459,18 @@ async function skillSync(flags) {
|
|
|
3224
3459
|
provider,
|
|
3225
3460
|
smokeCommandId: typeof flags.get('smoke-command') === 'string' ? String(flags.get('smoke-command')) : undefined,
|
|
3226
3461
|
organizationApprovalId: typeof flags.get('approval-id') === 'string' ? String(flags.get('approval-id')) : undefined,
|
|
3462
|
+
...(provider === 'agy' ? {
|
|
3463
|
+
providerActivationCheck: () => attestAgySkillBundleActivation({
|
|
3464
|
+
bundle,
|
|
3465
|
+
nativeSkillDirectory: destination,
|
|
3466
|
+
workspace: workspace.path,
|
|
3467
|
+
}),
|
|
3468
|
+
} : provider === 'hermes' ? {
|
|
3469
|
+
providerActivationCheck: () => attestHermesSkillBundleActivation({
|
|
3470
|
+
bundle,
|
|
3471
|
+
workspace: workspace.path,
|
|
3472
|
+
}),
|
|
3473
|
+
} : {}),
|
|
3227
3474
|
});
|
|
3228
3475
|
const restoreAnchor = async () => {
|
|
3229
3476
|
if (previousAnchor) {
|
|
@@ -3277,8 +3524,6 @@ async function skillSync(flags) {
|
|
|
3277
3524
|
activatedAt: receipt.completedAt,
|
|
3278
3525
|
expiresAt: bundle.expiresAt ?? null,
|
|
3279
3526
|
});
|
|
3280
|
-
if (provider === 'agy')
|
|
3281
|
-
await activateAgyPlugin();
|
|
3282
3527
|
}
|
|
3283
3528
|
}
|
|
3284
3529
|
catch (error) {
|
|
@@ -3449,8 +3694,8 @@ export async function run(argv) {
|
|
|
3449
3694
|
return skillSync(flags);
|
|
3450
3695
|
if (command === 'skills' && subcommand === 'status') {
|
|
3451
3696
|
const providerValue = required(flags, 'provider');
|
|
3452
|
-
if (!
|
|
3453
|
-
throw new Error('Skill provider must be codex, claude, or
|
|
3697
|
+
if (!isLocalProviderId(providerValue))
|
|
3698
|
+
throw new Error('Skill provider must be codex, claude, agy, or hermes.');
|
|
3454
3699
|
const root = nativeSkillDirectory(providerValue);
|
|
3455
3700
|
const workspaceId = required(flags, 'workspace-id');
|
|
3456
3701
|
const config = JSON.parse(await readFile(configPath(), 'utf8'));
|
|
@@ -3466,8 +3711,8 @@ export async function run(argv) {
|
|
|
3466
3711
|
}
|
|
3467
3712
|
if (command === 'skills' && subcommand === 'verify') {
|
|
3468
3713
|
const providerValue = required(flags, 'provider');
|
|
3469
|
-
if (!
|
|
3470
|
-
throw new Error('Skill provider must be codex, claude, or
|
|
3714
|
+
if (!isLocalProviderId(providerValue))
|
|
3715
|
+
throw new Error('Skill provider must be codex, claude, agy, or hermes.');
|
|
3471
3716
|
const result = await verifyAgentFabricSkillInstallation({
|
|
3472
3717
|
provider: providerValue,
|
|
3473
3718
|
workspace: String(flags.get('workspace') || '.'),
|