@dharma-ai-labs/agent-fabric 0.2.112 → 0.2.114

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.js CHANGED
@@ -18,11 +18,13 @@ import { executeTask, FileActionExecutionJournal, FileTaskReceiptStore, provider
18
18
  import { CLI_USAGE } from './usage.js';
19
19
  import { superviseRelay } from './relaySupervisor.js';
20
20
  import { disableRelayAutostart, enableRelayAutostart, relayAutostartStatus, startRelayAutostart } from './relayAutostart.js';
21
+ import { assertStudyExactPoll, studyTaskIdFromFlags } from './studyExactTaskSelector.js';
21
22
  import { initializeRepositoryKnowledge, readRepositoryKnowledgeSource } from './repositoryKnowledge.js';
22
23
  import { inventoryRepositoryPackage, readRepositoryPackageSnapshot, readRepositorySourceBaselineSnapshot, writeRepositoryPackageSnapshot } from './repositoryPackage.js';
23
24
  import { validateRepositorySourceAuthorization } from './repositorySourceAuthorization.js';
24
25
  import { advanceRepositorySourceBaseline, BlockedRepositorySourceRetry, fetchRepositorySourceAuthorization, recoverPublishedLocalSourceBaseline, RepositorySourceWatcher, scanRepositorySourceChanges, seedRepositorySourceWatcher } from './repositorySourceSync.js';
25
26
  import { assertRepositoryInstallerOwnership, writeRepositoryInstallerFile } from './repositoryInstallerFiles.js';
27
+ import { onboardingResumeCommand, selectDeviceWorkspace, workspaceIdForDevice } from './onboardingWorkspace.js';
26
28
  import { receiveRepositoryPackageDelivery } from './repositoryPackageDelivery.js';
27
29
  import { selectInstalledRepositoryKnowledge } from './repositoryInstalledKnowledge.js';
28
30
  import { prepareProvidersIndependently, startSkillPreparationPump } from './skillPreparationPump.js';
@@ -52,7 +54,7 @@ import { openCodexAppServerTransport } from '@dharma-ai-labs/agent-fabric-provid
52
54
  import { createNamedSessionTrust, isNamedSessionOwnerReceipt, renewNamedSessionLifetime } from './namedSessionTrust.js';
53
55
  import { startNamedCodexThread } from './namedCodexThread.js';
54
56
  export { openCooperativeInboxSession } from './cooperativeInboxSession.js';
55
- const VERSION = '0.2.112';
57
+ const VERSION = '0.2.114';
56
58
  const USAGE = CLI_USAGE;
57
59
  const execFileAsync = promisify(execFile);
58
60
  const LOCAL_PROVIDER_IDS = ['codex', 'claude', 'agy', 'hermes'];
@@ -1133,13 +1135,6 @@ function providerAdapter(provider) {
1133
1135
  return hermesAdapter;
1134
1136
  return null;
1135
1137
  }
1136
- function deterministicUuid(value) {
1137
- const bytes = createHash('sha256').update(value).digest().subarray(0, 16);
1138
- bytes[6] = ((bytes[6] ?? 0) & 0x0f) | 0x50;
1139
- bytes[8] = ((bytes[8] ?? 0) & 0x3f) | 0x80;
1140
- const hex = bytes.toString('hex');
1141
- return `${hex.slice(0, 8)}-${hex.slice(8, 12)}-${hex.slice(12, 16)}-${hex.slice(16, 20)}-${hex.slice(20)}`;
1142
- }
1143
1138
  export function normalizeGitRemoteIdentity(value) {
1144
1139
  const raw = value.trim();
1145
1140
  if (!raw || /[\u0000-\u001f\u007f]/.test(raw))
@@ -1627,13 +1622,20 @@ async function relaySupervise(flags) {
1627
1622
  if (demoOnly && flags.has('policy'))
1628
1623
  throw new Error('Demo-only supervision cannot select a standard policy.');
1629
1624
  const policyPath = demoOnly ? null : resolve(required(flags, 'policy'));
1630
- const selectedWorkspace = policyPath
1631
- ? (await registry()).find((item) => resolve(item.path, '.dharma', 'approved-policy.json') === policyPath) : null;
1625
+ const config = policyPath ? await readDeviceConfig() : null;
1626
+ const policyWorkspace = policyPath ? dirname(dirname(policyPath)) : null;
1627
+ const selectedWorkspace = policyPath && config && policyWorkspace
1628
+ ? selectDeviceWorkspace(await registry(), {
1629
+ organizationId: config.organizationId, deviceId: config.deviceId, path: policyWorkspace,
1630
+ }) : null;
1632
1631
  if (policyPath) {
1633
- if (!await readDeviceConfig())
1632
+ if (!config)
1634
1633
  throw new Error('Relay supervision requires an enrolled device.');
1635
1634
  if (!selectedWorkspace)
1636
1635
  throw new Error('Relay policy must be the canonical policy of one registered workspace.');
1636
+ if (resolve(selectedWorkspace.path, '.dharma', 'approved-policy.json') !== policyPath) {
1637
+ throw new Error('Relay policy must be the canonical policy of one registered workspace.');
1638
+ }
1637
1639
  }
1638
1640
  else if (!(await listDemoWatchRegistrations(dharmaHome())).length) {
1639
1641
  throw new Error('Relay supervision requires at least one registered Demo repository.');
@@ -2601,7 +2603,9 @@ async function capture(flags, batch = false) {
2601
2603
  }
2602
2604
  const session = sessions.at(-1);
2603
2605
  const device = JSON.parse(await readFile(configPath(), 'utf8'));
2604
- const registered = (await registry()).find((item) => item.path === workspace);
2606
+ const registered = selectDeviceWorkspace(await registry(), {
2607
+ organizationId: device.organizationId, deviceId: device.deviceId, path: workspace,
2608
+ });
2605
2609
  if (!registered)
2606
2610
  throw new Error('Workspace is not registered locally. Run dharma workspace add.');
2607
2611
  const captureProvenance = (collectedAt) => ({
@@ -2758,7 +2762,9 @@ async function evidencePreview(flags) {
2758
2762
  const policyPath = flags.get('policy');
2759
2763
  if (typeof policyPath === 'string') {
2760
2764
  const device = JSON.parse(await readFile(configPath(), 'utf8'));
2761
- const registered = (await registry()).find((item) => item.path === workspace);
2765
+ const registered = selectDeviceWorkspace(await registry(), {
2766
+ organizationId: device.organizationId, deviceId: device.deviceId, path: workspace,
2767
+ });
2762
2768
  if (!registered)
2763
2769
  throw new Error('Workspace is not registered locally. Run dharma workspace add.');
2764
2770
  const policy = await loadVerifiedWorkspacePolicy(policyPath, registered?.workspaceId);
@@ -2836,7 +2842,7 @@ async function workspaceAdd(flags, positional) {
2836
2842
  const organizationId = String(flags.get('organization-id') || device.organizationId);
2837
2843
  if (organizationId !== device.organizationId)
2838
2844
  throw new Error('Workspace organization must match the enrolled device.');
2839
- const workspaceId = deterministicUuid(`${organizationId}:${device.deviceId}:${path}`);
2845
+ const workspaceId = workspaceIdForDevice({ organizationId, deviceId: device.deviceId, path });
2840
2846
  const remote = await gitValue(path, ['config', '--get', 'remote.origin.url']);
2841
2847
  const identity = sourceRepositoryFingerprint(remote, typeof flags.get('repository-key') === 'string' ? String(flags.get('repository-key')) : null);
2842
2848
  const entry = {
@@ -3769,17 +3775,29 @@ async function onboard(flags) {
3769
3775
  const providerIds = parseSelectedProviderIds(typeof flags.get('providers') === 'string'
3770
3776
  ? [String(flags.get('providers'))]
3771
3777
  : typeof flags.get('provider') === 'string' ? [String(flags.get('provider'))] : []);
3772
- let registered = (await registry()).find((item) => item.path === workspace);
3773
- if (!registered || (!registered.repositoryRemoteHash && typeof flags.get('repository-key') === 'string')) {
3778
+ const repositoryKey = typeof flags.get('repository-key') === 'string' ? String(flags.get('repository-key')) : null;
3779
+ const repositoryIdentity = await preflightBootstrapWorkspaceIdentity(workspace, repositoryKey);
3780
+ let registered = selectDeviceWorkspace(await registry(), {
3781
+ organizationId,
3782
+ deviceId: config.deviceId,
3783
+ path: workspace,
3784
+ repositoryRemoteHash: repositoryIdentity.fingerprint,
3785
+ });
3786
+ if (!registered) {
3774
3787
  const addFlags = new Map([
3775
3788
  ['organization-id', organizationId],
3776
3789
  ['path', workspace],
3777
3790
  ['name', String(flags.get('name') || basename(workspace))],
3778
3791
  ]);
3779
- if (typeof flags.get('repository-key') === 'string')
3780
- addFlags.set('repository-key', String(flags.get('repository-key')));
3792
+ if (repositoryKey)
3793
+ addFlags.set('repository-key', repositoryKey);
3781
3794
  await workspaceAdd(addFlags, [workspace]);
3782
- registered = (await registry()).find((item) => item.path === workspace);
3795
+ registered = selectDeviceWorkspace(await registry(), {
3796
+ organizationId,
3797
+ deviceId: config.deviceId,
3798
+ path: workspace,
3799
+ repositoryRemoteHash: repositoryIdentity.fingerprint,
3800
+ });
3783
3801
  }
3784
3802
  if (!registered)
3785
3803
  throw new Error('Workspace registration failed.');
@@ -3807,8 +3825,12 @@ async function onboard(flags) {
3807
3825
  }
3808
3826
  const boundRepository = registered;
3809
3827
  const onboardWorkspaceId = registered.workspaceId;
3810
- const providerOption = providerIds?.length ? ` --providers ${providerIds.join(',')}` : '';
3811
- const resumeCommand = `dharma onboard --resume --organization-id ${organizationId} --workspace . --policy-revision ${authoritativeRevision}${providerOption}`;
3828
+ const resumeCommand = onboardingResumeCommand({
3829
+ organizationId,
3830
+ policyRevision: authoritativeRevision,
3831
+ repositoryKey,
3832
+ providerIds,
3833
+ });
3812
3834
  const staged = (stage, operation) => withOnboardingStage(stage, onboardWorkspaceId, resumeCommand, operation);
3813
3835
  const installed = await staged('local_skill_inventory', async () => installRepositoryAgentFabricSkill({
3814
3836
  workspace,
@@ -4507,8 +4529,10 @@ async function finalizeRecoveredSignedTaskTrajectories(fabric, vaultPolicy, only
4507
4529
  }
4508
4530
  return finalized;
4509
4531
  }
4510
- async function executeOneTask(fabric, leaseSeconds) {
4511
- const polled = await fabric.pollTask(leaseSeconds);
4532
+ async function executeOneTask(fabric, leaseSeconds, exactStudyTask) {
4533
+ const polled = await fabric.pollTask(leaseSeconds, exactStudyTask?.taskId);
4534
+ if (exactStudyTask)
4535
+ assertStudyExactPoll(polled, exactStudyTask.taskId, exactStudyTask.workspaceId);
4512
4536
  const taskRow = polled.task;
4513
4537
  if (!taskRow?.envelope)
4514
4538
  return { ok: true, task: null };
@@ -4641,14 +4665,23 @@ async function executeOneTask(fabric, leaseSeconds) {
4641
4665
  async function runOneTask(flags) {
4642
4666
  const policyPath = resolve(required(flags, 'policy'));
4643
4667
  const requestedWorkspaceId = typeof flags.get('workspace-id') === 'string' ? String(flags.get('workspace-id')) : undefined;
4644
- const selectedWorkspace = (await registry()).find((item) => (resolve(item.path, '.dharma', 'approved-policy.json') === policyPath
4645
- && (!requestedWorkspaceId || item.workspaceId === requestedWorkspaceId)));
4668
+ const records = await registry();
4669
+ const config = await readDeviceConfig();
4670
+ const selectedWorkspace = requestedWorkspaceId
4671
+ ? records.find(item => item.workspaceId === requestedWorkspaceId
4672
+ && resolve(item.path, '.dharma', 'approved-policy.json') === policyPath)
4673
+ : config
4674
+ ? selectDeviceWorkspace(records, {
4675
+ organizationId: config.organizationId, deviceId: config.deviceId, path: dirname(dirname(policyPath)),
4676
+ })
4677
+ : null;
4646
4678
  if (!selectedWorkspace)
4647
4679
  throw new Error('Task policy must be the canonical policy of one registered workspace.');
4680
+ const studyTaskId = studyTaskIdFromFlags(flags, selectedWorkspace.workspaceId);
4648
4681
  const policy = await loadVerifiedWorkspacePolicy(policyPath, selectedWorkspace.workspaceId);
4649
4682
  const fabric = await client();
4650
- const recoveredTaskTrajectories = await finalizeRecoveredSignedTaskTrajectories(fabric, policy);
4651
- const result = await executeOneTask(fabric, Number(flags.get('lease-seconds') || 120));
4683
+ const recoveredTaskTrajectories = studyTaskId ? [] : await finalizeRecoveredSignedTaskTrajectories(fabric, policy);
4684
+ const result = await executeOneTask(fabric, Number(flags.get('lease-seconds') || 120), studyTaskId ? { taskId: studyTaskId, workspaceId: selectedWorkspace.workspaceId } : undefined);
4652
4685
  return recoveredTaskTrajectories.length ? { ...result, recoveredTaskTrajectories } : result;
4653
4686
  }
4654
4687
  export function nativeSkillDirectory(provider, env = process.env, home = homedir()) {
@@ -5753,9 +5786,17 @@ async function takeCachedSkillUpdate(input) {
5753
5786
  }
5754
5787
  async function relayStart(flags) {
5755
5788
  const policyPath = resolve(required(flags, 'policy'));
5756
- const selectedWorkspace = (await registry()).find((item) => resolve(item.path, '.dharma', 'approved-policy.json') === policyPath);
5789
+ const declaredPolicy = await loadOrganizationPolicy(policyPath);
5790
+ const declaredWorkspaceId = declaredPolicy.serverAuthorization?.workspaceId;
5791
+ const selectedWorkspace = declaredWorkspaceId
5792
+ ? (await registry()).find(item => item.workspaceId === declaredWorkspaceId
5793
+ && item.organizationId === declaredPolicy.organizationId)
5794
+ : null;
5757
5795
  if (!selectedWorkspace)
5758
5796
  throw new Error('Relay policy must be the canonical policy of one registered workspace.');
5797
+ if (resolve(selectedWorkspace.path, '.dharma', 'approved-policy.json') !== policyPath) {
5798
+ throw new Error('Relay policy must be the canonical policy of one registered workspace.');
5799
+ }
5759
5800
  let canonicalWorkspace = selectedWorkspace;
5760
5801
  let policy = await loadVerifiedWorkspacePolicy(policyPath, canonicalWorkspace.workspaceId);
5761
5802
  const fabric = await client();