@dharma-ai-labs/agent-fabric 0.2.124 → 0.2.126
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/AGENT_FABRIC_ONBOARDING.md +3 -3
- package/README.md +18 -7
- package/dist/bin.js +2 -1
- package/dist/bin.js.map +1 -1
- package/dist/bootstrapRepositorySelection.d.ts +17 -0
- package/dist/bootstrapRepositorySelection.d.ts.map +1 -0
- package/dist/bootstrapRepositorySelection.js +145 -0
- package/dist/bootstrapRepositorySelection.js.map +1 -0
- package/dist/bootstrapRepositorySelection.test.d.ts +2 -0
- package/dist/bootstrapRepositorySelection.test.d.ts.map +1 -0
- package/dist/bootstrapRepositorySelection.test.js +145 -0
- package/dist/bootstrapRepositorySelection.test.js.map +1 -0
- package/dist/bootstrapResume.test.js +14 -1
- package/dist/bootstrapResume.test.js.map +1 -1
- package/dist/index.d.ts +6 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +116 -35
- package/dist/index.js.map +1 -1
- package/dist/index.test.js +90 -7
- package/dist/index.test.js.map +1 -1
- package/dist/namedSessionService.d.ts.map +1 -1
- package/dist/namedSessionService.js +50 -10
- package/dist/namedSessionService.js.map +1 -1
- package/dist/namedSessionService.test.js +10 -0
- package/dist/namedSessionService.test.js.map +1 -1
- package/dist/onboardingContract.test.js +2 -0
- package/dist/onboardingContract.test.js.map +1 -1
- package/dist/repositoryOnboardingCaller.test.js +66 -2
- package/dist/repositoryOnboardingCaller.test.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -30,6 +30,7 @@ import { advanceRepositorySourceBaseline, BlockedRepositorySourceRetry, fetchRep
|
|
|
30
30
|
import { assertRepositoryInstallerOwnership, writeRepositoryInstallerFile } from './repositoryInstallerFiles.js';
|
|
31
31
|
import { recoverLegacyRepositoryInstaller, selectLegacyInstallerRecoveryWorkspace } from './legacyInstallerRecovery.js';
|
|
32
32
|
import { onboardingResumeCommand, selectDeviceWorkspace, workspaceIdForDevice } from './onboardingWorkspace.js';
|
|
33
|
+
import { resolveBootstrapRepositoryWorkspace } from './bootstrapRepositorySelection.js';
|
|
33
34
|
import { receiveRepositoryPackageDelivery } from './repositoryPackageDelivery.js';
|
|
34
35
|
import { selectInstalledRepositoryKnowledge } from './repositoryInstalledKnowledge.js';
|
|
35
36
|
import { prepareProvidersIndependently, startSkillPreparationPump } from './skillPreparationPump.js';
|
|
@@ -60,7 +61,7 @@ import { openCodexAppServerTransport } from '@dharma-ai-labs/agent-fabric-provid
|
|
|
60
61
|
import { createNamedSessionTrust, isNamedSessionOwnerReceipt, renewNamedSessionLifetime } from './namedSessionTrust.js';
|
|
61
62
|
import { startNamedCodexThread } from './namedCodexThread.js';
|
|
62
63
|
export { openCooperativeInboxSession } from './cooperativeInboxSession.js';
|
|
63
|
-
const VERSION = '0.2.
|
|
64
|
+
const VERSION = '0.2.126';
|
|
64
65
|
const USAGE = CLI_USAGE;
|
|
65
66
|
const execFileAsync = promisify(execFile);
|
|
66
67
|
const LOCAL_PROVIDER_IDS = ['codex', 'claude', 'agy', 'hermes'];
|
|
@@ -116,6 +117,17 @@ export function portalUrl(flags, fallback = 'https://www.dharma-ai.io') {
|
|
|
116
117
|
function print(value) {
|
|
117
118
|
process.stdout.write(typeof value === 'string' ? `${value}\n` : `${JSON.stringify(value, null, 2)}\n`);
|
|
118
119
|
}
|
|
120
|
+
export function commandExitCode(argv, value) {
|
|
121
|
+
const { positional, flags } = parseCliOptions(argv);
|
|
122
|
+
if (positional[0] !== 'bootstrap' || flags.has('help') || flags.has('version'))
|
|
123
|
+
return 0;
|
|
124
|
+
if (!value || typeof value !== 'object' || Array.isArray(value))
|
|
125
|
+
return 1;
|
|
126
|
+
const receipt = value;
|
|
127
|
+
if (receipt.ok !== true)
|
|
128
|
+
return 1;
|
|
129
|
+
return flags.has('complete') && (receipt.stage !== 'complete' || receipt.sharedRepositoryReady !== true) ? 1 : 0;
|
|
130
|
+
}
|
|
119
131
|
async function loadVaultModule() {
|
|
120
132
|
const original = process.emitWarning;
|
|
121
133
|
process.emitWarning = ((warning, ...args) => {
|
|
@@ -350,8 +362,16 @@ export async function syncPendingRetentionCapsules(vault, fabric, policy, worksp
|
|
|
350
362
|
: 'An unsent oversized trajectory capsule was retired from the upload queue. Encrypted raw evidence remains local and eligible sessions can be recaptured under the current policy.\n');
|
|
351
363
|
continue;
|
|
352
364
|
}
|
|
353
|
-
|
|
354
|
-
|
|
365
|
+
try {
|
|
366
|
+
await reserveDailyContentUpload(item.capsule, policy);
|
|
367
|
+
await fabric.syncTrajectory(item.capsule);
|
|
368
|
+
}
|
|
369
|
+
catch (error) {
|
|
370
|
+
if (!isDefinitiveSecretDisclosureRejection(error))
|
|
371
|
+
throw error;
|
|
372
|
+
vault.discardPendingCapsuleSync(item.trajectoryId, item.revision, 'secret_disclosure_forbidden');
|
|
373
|
+
continue;
|
|
374
|
+
}
|
|
355
375
|
vault.markCapsuleSynced(item.trajectoryId, item.revision);
|
|
356
376
|
synced += 1;
|
|
357
377
|
}
|
|
@@ -1398,10 +1418,30 @@ export async function retryBootstrapOnboarding(operation, options = {}) {
|
|
|
1398
1418
|
}
|
|
1399
1419
|
}
|
|
1400
1420
|
function bootstrapEvidenceErrorCode(error) {
|
|
1421
|
+
if (isDefinitiveSecretDisclosureRejection(error))
|
|
1422
|
+
return 'secret_disclosure_forbidden';
|
|
1401
1423
|
const message = String(error?.message || error || '');
|
|
1402
1424
|
const candidate = message.match(/(?:^|\n)([a-z][a-z0-9_]{2,80})(?=:)/)?.[1];
|
|
1403
1425
|
return candidate || 'evidence_capture_failed';
|
|
1404
1426
|
}
|
|
1427
|
+
function isDefinitiveSecretDisclosureRejection(error) {
|
|
1428
|
+
return isDefinitiveAgentFabricRejection(error)
|
|
1429
|
+
&& /^policy_boundary:\s*secret_disclosure_forbidden(?:\s|\.|$)/.test(String(error.message));
|
|
1430
|
+
}
|
|
1431
|
+
export function publishedPackageCanDeferSecretEvidence(evidence, repositoryPackage, sourcePolicyGenerationId) {
|
|
1432
|
+
return evidence.state === 'deferred' && evidence.errorCode === 'secret_disclosure_forbidden'
|
|
1433
|
+
&& repositoryPackage.state === 'published' && Boolean(repositoryPackage.releaseId)
|
|
1434
|
+
&& repositoryPackage.sourcePolicyGenerationId === sourcePolicyGenerationId;
|
|
1435
|
+
}
|
|
1436
|
+
export function initialBootstrapEvidenceDisposition(discovered, disclosureReady) {
|
|
1437
|
+
if (!Number.isSafeInteger(discovered) || discovered < 0) {
|
|
1438
|
+
throw new Error('Evidence preview returned an invalid trajectory count.');
|
|
1439
|
+
}
|
|
1440
|
+
return discovered > 0 && !disclosureReady
|
|
1441
|
+
? { state: 'denied_disclosure', captured: 0, synced: 0,
|
|
1442
|
+
reason: 'policy_boundary', errorCode: 'automatic_disclosure_not_ready' }
|
|
1443
|
+
: { state: 'synchronized', captured: 0, synced: 0 };
|
|
1444
|
+
}
|
|
1405
1445
|
export async function synchronizeBootstrapEvidence(operation) {
|
|
1406
1446
|
try {
|
|
1407
1447
|
const result = await operation();
|
|
@@ -1413,8 +1453,8 @@ export async function synchronizeBootstrapEvidence(operation) {
|
|
|
1413
1453
|
const retentionNotReady = errorCode === 'agent_fabric_retention_not_ready';
|
|
1414
1454
|
return {
|
|
1415
1455
|
state: 'deferred',
|
|
1416
|
-
captured:
|
|
1417
|
-
synced:
|
|
1456
|
+
captured: null,
|
|
1457
|
+
synced: null,
|
|
1418
1458
|
reason: retentionNotReady ? 'retention_not_ready' : policyBoundary ? 'policy_boundary' : 'capture_unavailable',
|
|
1419
1459
|
errorCode,
|
|
1420
1460
|
};
|
|
@@ -2006,7 +2046,38 @@ async function bootstrap(flags) {
|
|
|
2006
2046
|
const organizationId = required(flags, 'organization-id');
|
|
2007
2047
|
const resuming = flags.has('resume');
|
|
2008
2048
|
const bootstrapToken = resuming ? null : required(flags, 'grant');
|
|
2009
|
-
const
|
|
2049
|
+
const selectedRemote = flags.get('repository-url-base64url');
|
|
2050
|
+
let repositorySelection;
|
|
2051
|
+
try {
|
|
2052
|
+
if (flags.has('repository-url-base64url') && typeof selectedRemote !== 'string') {
|
|
2053
|
+
throw new Error('repository_selection_invalid_url: selected repository URL is missing.');
|
|
2054
|
+
}
|
|
2055
|
+
if (selectedRemote && flags.has('repository-key')) {
|
|
2056
|
+
throw new Error('repository_selection_invalid_url: selected remote cannot be combined with a repository key.');
|
|
2057
|
+
}
|
|
2058
|
+
repositorySelection = typeof selectedRemote === 'string'
|
|
2059
|
+
? await resolveBootstrapRepositoryWorkspace({
|
|
2060
|
+
workspace: String(flags.get('workspace') || '.'),
|
|
2061
|
+
selectedRemoteBase64url: selectedRemote,
|
|
2062
|
+
organizationId,
|
|
2063
|
+
home: dharmaHome(),
|
|
2064
|
+
normalizeRemote: normalizeGitRemoteIdentity,
|
|
2065
|
+
withLock: (path) => acquirePidLock(path, 30_000, 'repository_checkout_busy: another setup is selecting this repository; retry after it finishes.'),
|
|
2066
|
+
})
|
|
2067
|
+
: { workspace: await realpath(String(flags.get('workspace') || '.')), selection: 'provided' };
|
|
2068
|
+
}
|
|
2069
|
+
catch (error) {
|
|
2070
|
+
const message = error && typeof error === 'object' && 'message' in error && typeof error.message === 'string'
|
|
2071
|
+
? error.message : '';
|
|
2072
|
+
const code = /^repository_[a-z_]+:/.exec(message)?.[0].slice(0, -1) || 'repository_selection_failed';
|
|
2073
|
+
return { ok: false, stage: 'repository_selection', code, grantRedeemed: false,
|
|
2074
|
+
message: code === 'repository_checkout_failed'
|
|
2075
|
+
? 'Git could not clone the selected repository with this device\'s existing access. Confirm repository access or use a matching checkout; the grant was not redeemed.'
|
|
2076
|
+
: message.startsWith('repository_') ? message : 'Selected repository could not be verified; the grant was not redeemed.' };
|
|
2077
|
+
}
|
|
2078
|
+
const workspace = repositorySelection.workspace;
|
|
2079
|
+
if (selectedRemote)
|
|
2080
|
+
process.stderr.write(`Agent Fabric repository checkout: ${workspace}\n`);
|
|
2010
2081
|
const policyRevision = required(flags, 'policy-revision');
|
|
2011
2082
|
const repositoryIdentity = await preflightBootstrapWorkspaceIdentity(workspace, typeof flags.get('repository-key') === 'string' ? String(flags.get('repository-key')) : null);
|
|
2012
2083
|
const requestedProvider = String(flags.get('provider') || 'auto').trim().toLowerCase();
|
|
@@ -2116,6 +2187,7 @@ async function bootstrap(flags) {
|
|
|
2116
2187
|
return {
|
|
2117
2188
|
ok: false,
|
|
2118
2189
|
stage: 'organization_api_credentials',
|
|
2190
|
+
repositorySelection,
|
|
2119
2191
|
code: credentialFailure,
|
|
2120
2192
|
message: 'The enrolled device is preserved, but its organization API credential is unavailable. Contact Dharma support for device-bound credential recovery; do not repeat enrollment or use another member\'s token.',
|
|
2121
2193
|
sharedRepositoryReady: false,
|
|
@@ -2137,6 +2209,7 @@ async function bootstrap(flags) {
|
|
|
2137
2209
|
return {
|
|
2138
2210
|
ok: onboarded.ok === true,
|
|
2139
2211
|
stage: onboarded.stage,
|
|
2212
|
+
repositorySelection,
|
|
2140
2213
|
code: onboarded.code,
|
|
2141
2214
|
sharedRepositoryReady: false,
|
|
2142
2215
|
enrollment: {
|
|
@@ -2190,6 +2263,7 @@ async function bootstrap(flags) {
|
|
|
2190
2263
|
return {
|
|
2191
2264
|
ok: true,
|
|
2192
2265
|
stage: sharedRepositoryReady ? onboarded.stage : 'shared_repository_pending',
|
|
2266
|
+
repositorySelection,
|
|
2193
2267
|
localStage: onboarded.localStage ?? onboarded.stage,
|
|
2194
2268
|
sharedRepositoryReady,
|
|
2195
2269
|
enrollment: {
|
|
@@ -2210,16 +2284,8 @@ async function bootstrap(flags) {
|
|
|
2210
2284
|
if (!skill.ready)
|
|
2211
2285
|
throw new Error(`Provider skill did not become ready: ${JSON.stringify(skill)}`);
|
|
2212
2286
|
const policyPath = resolve(workspace, '.dharma', 'approved-policy.json');
|
|
2213
|
-
const
|
|
2214
|
-
|
|
2215
|
-
]);
|
|
2216
|
-
const preview = await evidencePreview(evidenceFlags);
|
|
2217
|
-
let synchronized = { state: 'synchronized', captured: 0, synced: 0 };
|
|
2218
|
-
if (Number(preview.trajectoryCount || 0) > 0
|
|
2219
|
-
&& preview.automaticDisclosure?.ready === true) {
|
|
2220
|
-
evidenceFlags.set('sync', true);
|
|
2221
|
-
synchronized = await synchronizeBootstrapEvidence(async () => await retryBootstrapOnboarding(async () => await capture(evidenceFlags, true)));
|
|
2222
|
-
}
|
|
2287
|
+
const firstLearning = onboarded.firstLearningEvidence;
|
|
2288
|
+
const firstLearningReady = firstLearning?.state === 'synchronized' || firstLearning?.state === 'denied_disclosure';
|
|
2223
2289
|
const relay = flags.has('no-relay-daemon')
|
|
2224
2290
|
? { started: false, ...(await waitForRelayReadiness()) }
|
|
2225
2291
|
: await startRelayDaemon(policyPath);
|
|
@@ -2252,7 +2318,6 @@ async function bootstrap(flags) {
|
|
|
2252
2318
|
runOrganizationCommand('skills', 'list', apiFlags),
|
|
2253
2319
|
runOrganizationCommand('usage', 'list', apiFlags),
|
|
2254
2320
|
]);
|
|
2255
|
-
requireCompletedBootstrapEvidence(synchronized, Number(preview.trajectoryCount || 0));
|
|
2256
2321
|
const organizationApi = summarizeBootstrapOrganizationApi({
|
|
2257
2322
|
organizationId,
|
|
2258
2323
|
organization,
|
|
@@ -2275,12 +2340,12 @@ async function bootstrap(flags) {
|
|
|
2275
2340
|
const repositoryReceipt = onboarded;
|
|
2276
2341
|
const namedSessionReady = provider !== 'codex' || process.platform !== 'linux'
|
|
2277
2342
|
|| Boolean(namedSession?.ok === true && ['running', 'executing'].includes(String(namedSession.state)));
|
|
2278
|
-
const firstLearning = repositoryReceipt.firstLearningEvidence;
|
|
2279
2343
|
const role = repositoryReceipt.repositoryRole;
|
|
2280
2344
|
return {
|
|
2281
|
-
ok:
|
|
2282
|
-
stage: sharedRepositoryReady ? namedSessionReady ? 'complete' : 'named_session_pending'
|
|
2345
|
+
ok: sharedRepositoryReady && namedSessionReady && firstLearningReady,
|
|
2346
|
+
stage: sharedRepositoryReady ? namedSessionReady ? firstLearningReady ? 'complete' : 'first_learning_pending' : 'named_session_pending'
|
|
2283
2347
|
: repositoryReadiness?.outcome === 'blocked' ? 'shared_repository_blocked' : 'shared_repository_pending',
|
|
2348
|
+
repositorySelection,
|
|
2284
2349
|
localStage: 'complete',
|
|
2285
2350
|
sharedRepositoryReady,
|
|
2286
2351
|
enrollment: {
|
|
@@ -2298,9 +2363,9 @@ async function bootstrap(flags) {
|
|
|
2298
2363
|
provider,
|
|
2299
2364
|
skill,
|
|
2300
2365
|
evidence: {
|
|
2301
|
-
discovered: Number(
|
|
2302
|
-
synchronized,
|
|
2303
|
-
automaticDisclosure:
|
|
2366
|
+
discovered: Number(firstLearning?.discovered || 0),
|
|
2367
|
+
synchronized: firstLearning,
|
|
2368
|
+
automaticDisclosure: { ready: firstLearning?.disclosureReady === true },
|
|
2304
2369
|
},
|
|
2305
2370
|
relayProbe: relay.probe,
|
|
2306
2371
|
relay,
|
|
@@ -2880,10 +2945,18 @@ async function capture(flags, batch = false) {
|
|
|
2880
2945
|
capsules.push(capsule);
|
|
2881
2946
|
if (fabric) {
|
|
2882
2947
|
vault.queueCapsuleSync(capsule.trajectoryId, capsule.revision);
|
|
2883
|
-
|
|
2884
|
-
|
|
2885
|
-
|
|
2886
|
-
|
|
2948
|
+
try {
|
|
2949
|
+
await reserveDailyContentUpload(capsule, policy);
|
|
2950
|
+
// An unknown delivery outcome retains the local advisory reservation.
|
|
2951
|
+
// HQ performs the authoritative, idempotent organization/day charge.
|
|
2952
|
+
syncResults.push(await fabric.syncTrajectory(capsule));
|
|
2953
|
+
}
|
|
2954
|
+
catch (error) {
|
|
2955
|
+
if (isDefinitiveSecretDisclosureRejection(error)) {
|
|
2956
|
+
vault.discardPendingCapsuleSync(capsule.trajectoryId, capsule.revision, 'secret_disclosure_forbidden');
|
|
2957
|
+
}
|
|
2958
|
+
throw error;
|
|
2959
|
+
}
|
|
2887
2960
|
vault.markCapsuleSynced(capsule.trajectoryId, capsule.revision);
|
|
2888
2961
|
}
|
|
2889
2962
|
}
|
|
@@ -4179,19 +4252,24 @@ async function onboard(flags) {
|
|
|
4179
4252
|
controlBranch: boundRepository.controlBranch,
|
|
4180
4253
|
policyRevision: authoritativeRevision,
|
|
4181
4254
|
}));
|
|
4255
|
+
const canonicalPackage = registered.repositoryPackage;
|
|
4182
4256
|
const onboardingProvider = providerIds?.[0] || 'codex';
|
|
4183
4257
|
const onboardingEvidenceFlags = new Map([
|
|
4184
4258
|
['workspace', workspace], ['provider', onboardingProvider],
|
|
4185
4259
|
['policy', resolve(workspace, '.dharma', 'approved-policy.json')], ['maximum-sessions', '20'],
|
|
4186
4260
|
]);
|
|
4187
4261
|
const onboardingEvidencePreview = await staged('first_learning_preview', async () => evidencePreview(onboardingEvidenceFlags));
|
|
4188
|
-
|
|
4189
|
-
|
|
4190
|
-
|
|
4262
|
+
const discoveredTrajectories = Number(onboardingEvidencePreview.trajectoryCount || 0);
|
|
4263
|
+
const disclosureReady = onboardingEvidencePreview.automaticDisclosure?.ready === true;
|
|
4264
|
+
let onboardingEvidence = initialBootstrapEvidenceDisposition(discoveredTrajectories, disclosureReady);
|
|
4265
|
+
if (discoveredTrajectories > 0 && disclosureReady) {
|
|
4191
4266
|
onboardingEvidenceFlags.set('sync', true);
|
|
4192
4267
|
onboardingEvidence = await staged('first_learning_sync', async () => {
|
|
4193
4268
|
const result = await synchronizeBootstrapEvidence(async () => await retryBootstrapOnboarding(async () => await capture(onboardingEvidenceFlags, true)));
|
|
4194
|
-
|
|
4269
|
+
if (publishedPackageCanDeferSecretEvidence(result, canonicalPackage, sourceAuthorization.generationId)) {
|
|
4270
|
+
return { ...result, state: 'denied_disclosure' };
|
|
4271
|
+
}
|
|
4272
|
+
requireCompletedBootstrapEvidence(result, discoveredTrajectories);
|
|
4195
4273
|
return result;
|
|
4196
4274
|
});
|
|
4197
4275
|
}
|
|
@@ -4203,7 +4281,6 @@ async function onboard(flags) {
|
|
|
4203
4281
|
const candidateScope = { organizationId, workspaceId: registered.workspaceId,
|
|
4204
4282
|
repositoryBindingId: registered.repositoryBindingId, repositoryAgentId: registered.repositoryAgentId };
|
|
4205
4283
|
const outboxRoot = resolve(dharmaHome(), 'relay', 'repository-candidates');
|
|
4206
|
-
const canonicalPackage = registered.repositoryPackage;
|
|
4207
4284
|
const refreshPolicy = repositoryPackageNeedsPolicyRefresh(canonicalPackage, sourceAuthorization.generationId);
|
|
4208
4285
|
const retryBlockedInitial = canonicalPackage.state === 'blocked' && canonicalPackage.generation === 0
|
|
4209
4286
|
&& canonicalPackage.consolidationMode === 'initial_repository';
|
|
@@ -4309,8 +4386,8 @@ async function onboard(flags) {
|
|
|
4309
4386
|
repositorySkill: installed,
|
|
4310
4387
|
repositoryCandidate: candidate,
|
|
4311
4388
|
firstLearningEvidence: {
|
|
4312
|
-
discovered:
|
|
4313
|
-
disclosureReady
|
|
4389
|
+
discovered: discoveredTrajectories,
|
|
4390
|
+
disclosureReady,
|
|
4314
4391
|
...onboardingEvidence,
|
|
4315
4392
|
},
|
|
4316
4393
|
repositoryRole: role,
|
|
@@ -6961,7 +7038,11 @@ export async function run(argv) {
|
|
|
6961
7038
|
throw new Error(USAGE);
|
|
6962
7039
|
}
|
|
6963
7040
|
if (isDirectExecution(process.argv[1], import.meta.url)) {
|
|
6964
|
-
|
|
7041
|
+
const argv = process.argv.slice(2);
|
|
7042
|
+
run(argv).then((value) => {
|
|
7043
|
+
print(value);
|
|
7044
|
+
process.exitCode = commandExitCode(argv, value);
|
|
7045
|
+
}).catch((error) => {
|
|
6965
7046
|
const message = error instanceof Error ? error.message : String(error);
|
|
6966
7047
|
process.stderr.write(`${message}\n`);
|
|
6967
7048
|
process.exitCode = 2;
|