@aiwg/cli 2026.10.1 → 2026.10.3

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.
Files changed (166) hide show
  1. package/agentic/code/providers/capability-matrix.yaml +270 -0
  2. package/agentic/code/providers/model-capabilities.v1.json +3091 -24
  3. package/bin/aiwg.mjs +86 -21
  4. package/dist/src/a2a/codecs.js +9 -0
  5. package/dist/src/artifacts/corpus-tools/vision-extract.js +105 -15
  6. package/dist/src/artifacts/repair.js +9 -4
  7. package/dist/src/channel/manager.mjs +59 -10
  8. package/dist/src/cli/child-process-result.js +40 -0
  9. package/dist/src/cli/env.js +38 -16
  10. package/dist/src/cli/flag-parsing.js +236 -0
  11. package/dist/src/cli/handlers/decision.js +210 -4
  12. package/dist/src/cli/handlers/diagnose.js +9 -2
  13. package/dist/src/cli/handlers/feedback.js +14 -5
  14. package/dist/src/cli/handlers/init.js +245 -30
  15. package/dist/src/cli/handlers/mc.js +23 -0
  16. package/dist/src/cli/handlers/models.js +69 -6
  17. package/dist/src/cli/handlers/ralph.js +3 -0
  18. package/dist/src/cli/handlers/refresh.js +16 -0
  19. package/dist/src/cli/handlers/regenerate.js +14 -0
  20. package/dist/src/cli/handlers/runtime-info.js +24 -9
  21. package/dist/src/cli/handlers/script-runner.js +16 -6
  22. package/dist/src/cli/handlers/session.js +396 -62
  23. package/dist/src/cli/handlers/sessions.js +146 -40
  24. package/dist/src/cli/handlers/setup-manifest.js +439 -39
  25. package/dist/src/cli/handlers/setup.js +139 -39
  26. package/dist/src/cli/handlers/subcommands.js +3 -1
  27. package/dist/src/cli/handlers/team.js +18 -8
  28. package/dist/src/cli/handlers/use.js +13 -0
  29. package/dist/src/cli/handlers/utilities.js +106 -23
  30. package/dist/src/cli/prompt-utils.js +72 -0
  31. package/dist/src/cli/provider-resolution.js +11 -0
  32. package/dist/src/config/aiwg-config.js +268 -4
  33. package/dist/src/config/cli.js +146 -19
  34. package/dist/src/config/dispatch-thresholds-runtime.mjs +38 -0
  35. package/dist/src/config/project-artifacts-health.mjs +14 -3
  36. package/dist/src/config/user-config.js +36 -10
  37. package/dist/src/decision/adapters/jev.js +75 -27
  38. package/dist/src/decision/driver.js +3 -1
  39. package/dist/src/decision/entry.js +38 -6
  40. package/dist/src/decision/heldout/collector.js +10 -1
  41. package/dist/src/decision/index.js +1 -0
  42. package/dist/src/decision/interop.js +60 -8
  43. package/dist/src/decision/ledger.js +839 -0
  44. package/dist/src/decision/validate.js +6 -3
  45. package/dist/src/effects/dispatch-verifier.js +252 -0
  46. package/dist/src/effects/index.js +1 -0
  47. package/dist/src/features/installer.js +2 -2
  48. package/dist/src/flow/graph-metadata.js +5 -0
  49. package/dist/src/gates/providers/loader.js +3 -1
  50. package/dist/src/installation/manager-command.mjs +1 -1
  51. package/dist/src/installation/manager.mjs +17 -2
  52. package/dist/src/lint/runner.js +2 -2
  53. package/dist/src/mcp/adapters/codex-runtime.js +360 -56
  54. package/dist/src/mcp/cli.mjs +587 -77
  55. package/dist/src/mcp/config-file.mjs +279 -0
  56. package/dist/src/mcp/config-layers.mjs +348 -0
  57. package/dist/src/mcp/credentials.mjs +484 -0
  58. package/dist/src/mcp/grok-build-config.mjs +16 -26
  59. package/dist/src/mcp/helpers.mjs +106 -2
  60. package/dist/src/mcp/omp-config.mjs +50 -29
  61. package/dist/src/mcp/profiles.js +97 -23
  62. package/dist/src/mcp/profiles.mjs +99 -27
  63. package/dist/src/mcp/registry.js +264 -57
  64. package/dist/src/mcp/registry.mjs +198 -45
  65. package/dist/src/mcp/server.mjs +403 -20
  66. package/dist/src/mcp/toml-string.mjs +9 -0
  67. package/dist/src/mcp/toml-strip-mcp.mjs +135 -0
  68. package/dist/src/mcp/tool-filters.mjs +357 -0
  69. package/dist/src/mcp/tools/agentic-sandbox.mjs +3 -1
  70. package/dist/src/mcp/tools/decision.mjs +21 -3
  71. package/dist/src/mcp/tools/orchestration.mjs +38 -0
  72. package/dist/src/mcp/tools/subsystems.mjs +39 -8
  73. package/dist/src/mcp/tools/worker-invoke.mjs +1539 -0
  74. package/dist/src/mcp/tools/worker-shell-control.mjs +258 -0
  75. package/dist/src/mcp/tools/worker-stdin-runtime.mjs +79 -0
  76. package/dist/src/memory/project-registry.js +2 -2
  77. package/dist/src/mission-protocol/codecs.js +639 -1
  78. package/dist/src/mission-protocol/types.js +110 -0
  79. package/dist/src/mission-protocol/worker-status.js +2 -0
  80. package/dist/src/models/config-loader.js +70 -13
  81. package/dist/src/models/grok-build-models.js +93 -41
  82. package/dist/src/models/model-capabilities.v1.json +3091 -24
  83. package/dist/src/models/model-discovery.js +862 -63
  84. package/dist/src/models/provider-policy.js +625 -11
  85. package/dist/src/models/qualification-digest.mjs +17 -0
  86. package/dist/src/models/resolver.js +259 -0
  87. package/dist/src/models/worker-direct-readiness.js +529 -0
  88. package/dist/src/models/worker-dispatch-offer.js +169 -0
  89. package/dist/src/models/worker-health-readiness.js +131 -0
  90. package/dist/src/models/worker-installation.mjs +879 -0
  91. package/dist/src/models/wrapper-route.js +18 -0
  92. package/dist/src/ops/registry.js +9 -14
  93. package/dist/src/plugins/standalone-packager.js +4 -3
  94. package/dist/src/process/bounded-child-process.mjs +387 -0
  95. package/dist/src/process/cli-command.mjs +75 -0
  96. package/dist/src/providers/capability-matrix.js +8 -0
  97. package/dist/src/providers/capability-matrix.yaml +270 -0
  98. package/dist/src/providers/grok-build-headless.js +43 -21
  99. package/dist/src/providers/provider-definitions.js +9 -1
  100. package/dist/src/providers/provider-definitions.mjs +9 -2
  101. package/dist/src/serve/executor-registry.js +16 -24
  102. package/dist/src/serve/fleet-mission-conductor.js +9 -0
  103. package/dist/src/serve/mission-conductor.js +9 -0
  104. package/dist/src/serve/shared-host-scheduler.js +2 -0
  105. package/dist/src/serve/worker-invocation.js +538 -0
  106. package/dist/src/serve/worker-stdin-frame.mjs +107 -0
  107. package/dist/src/sessions/adapter-registry.js +45 -0
  108. package/dist/src/sessions/adapters/generic.js +37 -3
  109. package/dist/src/sessions/adapters/grokbot-locator.js +111 -0
  110. package/dist/src/sessions/adapters/grokbot.js +423 -24
  111. package/dist/src/sessions/adapters/muse-workspace-scan.js +108 -0
  112. package/dist/src/sessions/adapters/muse.js +68 -29
  113. package/dist/src/sessions/adapters/pi.js +1 -0
  114. package/dist/src/sessions/batch-contracts.js +13 -1
  115. package/dist/src/sessions/batch-import.js +23 -42
  116. package/dist/src/sessions/candidates.js +47 -11
  117. package/dist/src/sessions/contracts.js +35 -0
  118. package/dist/src/sessions/coverage-preflight.js +134 -0
  119. package/dist/src/sessions/discovery.js +3 -0
  120. package/dist/src/sessions/grok-build-cli.js +67 -5
  121. package/dist/src/sessions/importer.js +24 -8
  122. package/dist/src/sessions/index.js +2 -0
  123. package/dist/src/sessions/repository.js +54 -13
  124. package/dist/src/sessions/workspace-discovery.js +99 -37
  125. package/dist/src/skills/adapters/clawhub.js +10 -8
  126. package/dist/src/skills/adapters/openclaw.js +10 -7
  127. package/dist/src/smiths/context-pipeline/parallelism-section.js +192 -3
  128. package/dist/src/smiths/context-pipeline/workspace-context.js +116 -9
  129. package/dist/src/smiths/hook-bridge/codex-translator.js +6 -5
  130. package/dist/src/smiths/mcpsmith/example.js +1 -1
  131. package/dist/src/smiths/toolsmith/runtime-discovery.mjs +10 -14
  132. package/dist/src/storage/backends/logseq.js +68 -7
  133. package/dist/src/storage/fortemi-qualification-receipt.js +2 -2
  134. package/dist/src/testing/generators/test-code-generator.js +57 -30
  135. package/dist/src/uhp/client.js +11 -1
  136. package/dist/src/uhp/mission.js +5 -0
  137. package/dist/src/update/checker.mjs +5 -5
  138. package/dist/src/update/notifier.mjs +54 -2
  139. package/dist/src/writing/fidelity.js +18 -1
  140. package/package.json +18 -1
  141. package/schemas/mission-v1.schema.json +2429 -0
  142. package/schemas/models/model-catalog.v1.schema.json +301 -0
  143. package/schemas/models/model-config-compatibility.v1.schema.json +281 -0
  144. package/schemas/models/model-policy.v1.schema.json +14 -0
  145. package/schemas/models/provider-model-capabilities.v1.schema.json +1066 -0
  146. package/tools/_resolve-impl.mjs +39 -0
  147. package/tools/agents/deploy-agents.mjs +15 -2
  148. package/tools/agents/providers/base.mjs +49 -32
  149. package/tools/agents/providers/grokbot.mjs +11 -12
  150. package/tools/agents/providers/hermes.mjs +6 -3
  151. package/tools/agents/providers/omp.mjs +5 -2
  152. package/tools/agents/providers/openclaw-translator.mjs +19 -5
  153. package/tools/providers/deepseek-harness-transport.mjs +358 -0
  154. package/tools/providers/omp-transport.mjs +192 -0
  155. package/tools/ralph-external/lib/claude-adapter.mjs +389 -0
  156. package/tools/ralph-external/lib/codex-adapter.mjs +432 -0
  157. package/tools/ralph-external/lib/deepseek-harness-adapter.mjs +397 -0
  158. package/tools/ralph-external/lib/factory-adapter.mjs +503 -0
  159. package/tools/ralph-external/lib/muse-adapter.mjs +364 -0
  160. package/tools/ralph-external/lib/omp-adapter.mjs +315 -0
  161. package/tools/ralph-external/lib/opencode-adapter.mjs +575 -0
  162. package/tools/ralph-external/lib/openhuman-adapter.mjs +75 -0
  163. package/tools/ralph-external/lib/pi-adapter.mjs +333 -0
  164. package/tools/ralph-external/lib/provider-adapter.mjs +690 -0
  165. package/tools/ralph-external/lib/worker-health.mjs +439 -0
  166. package/vscode-extension/schemas/aiwg.config.v1.json +1953 -0
@@ -42,8 +42,9 @@
42
42
  import { opendir } from 'node:fs/promises';
43
43
  import { resolve } from 'node:path';
44
44
  import { z } from 'zod';
45
- import { SessionContractError, assertSupportedSchemaMajor, } from '../contracts.js';
45
+ import { SessionContractError, SessionErrorCodeSchema, assertSupportedSchemaMajor, } from '../contracts.js';
46
46
  import { readBoundedJson, readBoundedJsonLines, } from '../readers.js';
47
+ import { MUSE_WORKSPACE_SCAN_LIMITS, museWorkspaceScanLines, parseMuseScanJson, } from './muse-workspace-scan.js';
47
48
  export const MUSE_ADAPTER_VERSION = '1.0.0';
48
49
  export const MUSE_EXPORT_SCHEMA_VERSION = '1.0.0';
49
50
  export const MUSE_EXPORT_SCHEMA_MAJOR = 1;
@@ -79,7 +80,9 @@ const MuseEnvelopeSchema = z.object({
79
80
  durability: z.string().optional(),
80
81
  payload_type: z.string().optional(),
81
82
  payload: z.object({
82
- event: z.object({ kind: z.string().min(1) }).passthrough().optional(),
83
+ // Muse Code 1.4.3 runtime.session mode records carry an event without a
84
+ // kind; eventKindOf() falls back to payload_type for those.
85
+ event: z.object({ kind: z.string().min(1).optional() }).passthrough().optional(),
83
86
  }).passthrough().optional(),
84
87
  }).passthrough();
85
88
  /**
@@ -495,44 +498,80 @@ async function* museNativeSessionLogs(root) {
495
498
  }
496
499
  }
497
500
  }
498
- export async function museNativeSourceMatchesWorkspace(source, workspacePath) {
499
- let input;
501
+ export const MuseWorkspaceInspectionSchema = z.object({
502
+ outcome: z.enum(['matched', 'mismatch', 'inconclusive']),
503
+ reasonCode: z.string().nullable(),
504
+ recordsInspected: z.number().int().nonnegative(),
505
+ bytesInspected: z.number().int().nonnegative(),
506
+ completeInspection: z.boolean(),
507
+ });
508
+ /** Positive metadata evidence selects a source; import validates its full history. */
509
+ export async function inspectMuseNativeWorkspace(source, workspacePath, limitsInput) {
510
+ const limits = { ...MUSE_WORKSPACE_SCAN_LIMITS, ...limitsInput };
511
+ const progress = { recordsInspected: 0, bytesInspected: 0 };
512
+ let sawWorkspaceEvidence = false;
513
+ let retainedChildren = 0;
514
+ const receipt = (outcome, reasonCode, completeInspection = false) => ({ outcome, reasonCode, ...progress, completeInspection });
500
515
  try {
501
- input = await readBoundedJsonLines({ selectedPath: source.locator, allowedRoots: source.authorizedScope.allowedRoots }, { consistency: 'complete', limits: { maxRecords: 100, maxRecordBytes: 8 * 1024 * 1024 } });
516
+ if (Object.values(limits).some((limit) => !Number.isSafeInteger(limit) || limit <= 0)) {
517
+ throw new SessionContractError('INVALID_ARGUMENT', 'Muse inspection limits must be positive safe integers');
518
+ }
519
+ for await (const value of museWorkspaceScanLines({ selectedPath: source.locator, allowedRoots: source.authorizedScope.allowedRoots }, limits, progress)) {
520
+ const envelopes = nativeEnvelopesFromLine(value, limits, (count) => {
521
+ retainedChildren += count;
522
+ if (retainedChildren > limits.maxRecords) {
523
+ throw new SessionContractError('RESOURCE_LIMIT_EXCEEDED', 'Muse retained child inspection limit exceeded');
524
+ }
525
+ });
526
+ for (const envelope of envelopes) {
527
+ const candidate = workspaceEvidenceOf(envelope);
528
+ if (!candidate)
529
+ continue;
530
+ sawWorkspaceEvidence = true;
531
+ if (workspacePathEquals(candidate, workspacePath))
532
+ return receipt('matched', null);
533
+ }
534
+ }
535
+ return sawWorkspaceEvidence
536
+ ? receipt('mismatch', 'MUSE_WORKSPACE_MISMATCH', true)
537
+ : receipt('inconclusive', 'MUSE_WORKSPACE_EVIDENCE_ABSENT', true);
502
538
  }
503
- catch {
504
- return false;
539
+ catch (error) {
540
+ return receipt('inconclusive', error instanceof SessionContractError
541
+ ? error.code : 'MUSE_SOURCE_UNREADABLE');
505
542
  }
506
- for (const line of input.records) {
507
- for (const envelope of nativeEnvelopesFromLine(line.value)) {
508
- const candidate = workspaceEvidenceOf(envelope);
509
- if (!candidate)
510
- continue;
511
- if (workspacePathEquals(candidate, workspacePath))
512
- return true;
513
- }
543
+ }
544
+ export async function museNativeSourceMatchesWorkspace(source, workspacePath) {
545
+ const result = await inspectMuseNativeWorkspace(source, workspacePath);
546
+ if (result.outcome === 'inconclusive') {
547
+ const code = SessionErrorCodeSchema.safeParse(result.reasonCode);
548
+ throw new SessionContractError(code.success ? code.data : 'SCHEMA_DRIFT', `Muse workspace inspection inconclusive: ${result.reasonCode}`);
514
549
  }
515
- return false;
550
+ return result.outcome === 'matched';
516
551
  }
517
- function nativeEnvelopesFromLine(value) {
552
+ function nativeEnvelopesFromLine(value, limits, countChildren) {
518
553
  if (isOmissionMarker(value))
519
554
  return [];
520
- const event = recordEventFromEnvelope(value);
521
- if (event)
522
- return [event.envelope];
523
555
  const retained = MuseRetainedFrameSchema.safeParse(value);
524
- if (!retained.success)
525
- return [];
556
+ if (!retained.success) {
557
+ if (value === null || typeof value !== 'object' || Array.isArray(value)) {
558
+ throw new SessionContractError('MALFORMED_SOURCE', 'Muse inspection encountered a non-object native record');
559
+ }
560
+ // Native logs carry record kinds the envelope schema does not model (for
561
+ // example runtime.session mode changes without payload.event.kind). They
562
+ // hold no workspace evidence, so skip them rather than fail the source.
563
+ const event = recordEventFromEnvelope(value);
564
+ return event ? [event.envelope] : [];
565
+ }
566
+ countChildren(retained.data.children.length);
526
567
  const envelopes = [];
527
568
  for (const child of retained.data.children) {
528
- try {
529
- const childEvent = recordEventFromEnvelope(JSON.parse(child.record_json));
530
- if (childEvent)
531
- envelopes.push(childEvent.envelope);
532
- }
533
- catch {
534
- return [];
569
+ if (Buffer.byteLength(child.record_json) > limits.maxRecordBytes) {
570
+ throw new SessionContractError('RESOURCE_LIMIT_EXCEEDED', 'Muse retained child inspection byte limit exceeded');
535
571
  }
572
+ const childEvent = recordEventFromEnvelope(parseMuseScanJson(child.record_json, limits.maxNestingDepth));
573
+ if (childEvent)
574
+ envelopes.push(childEvent.envelope);
536
575
  }
537
576
  return envelopes;
538
577
  }
@@ -13,6 +13,7 @@ export class PiSessionAdapter {
13
13
  limits;
14
14
  maxFiles;
15
15
  provider = 'pi';
16
+ sourceSchemaMajor = 3;
16
17
  adapterVersion = PI_ADAPTER_VERSION;
17
18
  disposition = 'implemented';
18
19
  supportedOperations = ['discover', 'inspect', 'stream'];
@@ -1,3 +1,4 @@
1
+ import { reconcileCoveragePreflight } from './coverage-preflight.js';
1
2
  export const BATCH_IMPORT_VERSION = '1.0.0';
2
3
  export const COVERAGE_VERSION = '1.0.0';
3
4
  export function coverageFromBatchRun(run, now = new Date(), staleAfterMs = 24 * 60 * 60 * 1_000) {
@@ -18,7 +19,10 @@ export function coverageFromBatchRun(run, now = new Date(), staleAfterMs = 24 *
18
19
  const notChecked = providerNames(run, 'not-checked');
19
20
  const manifestAgeMs = Math.max(0, now.getTime() - Date.parse(run.manifestCreatedAt));
20
21
  const isStale = manifestAgeMs > staleAfterMs;
21
- const incomplete = rejected > 0 || pending > 0 || skipped > 0
22
+ const preflight = run.preflight ? reconcileCoveragePreflight(run.preflight, run.sources) : undefined;
23
+ const incomplete = !preflight || preflight.status !== 'complete'
24
+ || unavailable.length > 0 || accepted + duplicated + previouslyCommitted === 0
25
+ || rejected > 0 || pending > 0 || skipped > 0
22
26
  || exportRequired.length > 0 || notChecked.length > 0;
23
27
  const rejectionCounts = {};
24
28
  for (const source of run.sources) {
@@ -36,6 +40,9 @@ export function coverageFromBatchRun(run, now = new Date(), staleAfterMs = 24 *
36
40
  .map((source) => source.updatedAt)
37
41
  .sort();
38
42
  const remediation = [
43
+ ...(preflight?.ledger.flatMap((entry) => entry.remediation ? [entry.remediation] : []) ?? ['Legacy receipt lacks provider/runtime preflight; rediscover with --expected-providers.']),
44
+ ...(preflight && ['mismatch', 'stale', 'unknown'].includes(preflight.runtime.installationState)
45
+ ? ['Inspect the recorded runtime identity and deliberately select a compatible installation; then rediscover. No automatic switch is performed.'] : []),
39
46
  ...(rejected > 0
40
47
  ? ['Run `aiwg sessions import-discovered --resume --confirm` after correcting rejected sources.']
41
48
  : []),
@@ -47,6 +54,9 @@ export function coverageFromBatchRun(run, now = new Date(), staleAfterMs = 24 *
47
54
  return {
48
55
  schemaVersion: COVERAGE_VERSION,
49
56
  status: isStale ? 'stale' : incomplete ? 'partial' : 'complete',
57
+ acquisitionStatus: incomplete ? 'partial' : 'complete',
58
+ preflight,
59
+ semanticReview: 'not-assessed',
50
60
  workspaceId: run.workspaceId,
51
61
  manifestId: run.manifestId,
52
62
  batchRunId: run.runId,
@@ -89,6 +99,8 @@ function unknownCoverage() {
89
99
  return {
90
100
  schemaVersion: COVERAGE_VERSION,
91
101
  status: 'unknown',
102
+ acquisitionStatus: 'unknown',
103
+ semanticReview: 'not-assessed',
92
104
  workspaceId: '',
93
105
  manifestId: null,
94
106
  batchRunId: null,
@@ -1,11 +1,6 @@
1
- import { OmpSessionAdapter, OMP_ADAPTER_VERSION } from './adapters/omp.js';
2
- import { DeepSeekHarnessSessionAdapter, DEEPSEEK_HARNESS_ADAPTER_VERSION } from './adapters/deepseek-harness.js';
3
1
  import { stat } from 'node:fs/promises';
4
- import { CLAUDE_ADAPTER_VERSION, ClaudeSessionAdapter, } from './adapters/claude.js';
5
- import { CODEX_ADAPTER_VERSION, CodexSessionAdapter, } from './adapters/codex.js';
6
- import { CURSOR_ADAPTER_VERSION, CursorSessionAdapter, } from './adapters/cursor.js';
7
- import { FACTORY_ADAPTER_VERSION, FactorySessionAdapter, } from './adapters/factory.js';
8
- import { MUSE_ADAPTER_VERSION, MuseSessionAdapter, } from './adapters/muse.js';
2
+ import { createSessionAdapterRegistry } from './adapter-registry.js';
3
+ import { coveragePreflight, sessionRuntimeIdentity } from './coverage-preflight.js';
9
4
  import { SESSION_CONTRACT_VERSION, SessionContractError, SessionSourceSchema, sha256, } from './contracts.js';
10
5
  import { BATCH_IMPORT_VERSION, coverageFromBatchRun, } from './batch-contracts.js';
11
6
  import { IncrementalSessionImporter, SessionImportFailure } from './importer.js';
@@ -22,6 +17,12 @@ export async function importDiscoveryManifest(options) {
22
17
  if (run.runId !== runId) {
23
18
  throw new SessionContractError('IMPORT_CONFLICT', 'discovery manifest is already associated with a different batch run');
24
19
  }
20
+ run.preflight = coveragePreflight({
21
+ expectedProviders: options.manifest.preflight?.expectedProviders,
22
+ expectedProviderBasis: options.manifest.preflight?.expectedProviderBasis ?? 'legacy',
23
+ runtime: options.runtime ?? sessionRuntimeIdentity(),
24
+ reports: options.manifest.providers,
25
+ });
25
26
  run.status = 'running';
26
27
  run.updatedAt = now().toISOString();
27
28
  run.completedAt = null;
@@ -100,7 +101,7 @@ export async function importDiscoveryManifest(options) {
100
101
  }
101
102
  const rejected = run.sources.some((source) => source.status === 'rejected');
102
103
  const pending = run.sources.some((source) => source.status === 'pending' || source.status === 'running');
103
- const providerGap = run.providers.some((provider) => provider.status === 'export-required' || provider.status === 'not-checked');
104
+ const providerGap = coverageFromBatchRun(run, now()).acquisitionStatus !== 'complete';
104
105
  const publishable = run.sources
105
106
  .filter((source) => isAccepted(source.status))
106
107
  .map((source) => source.sourceId);
@@ -129,7 +130,14 @@ function injectFault(options, run, boundary, sourceId) {
129
130
  }
130
131
  export function previewDiscoveryImport(manifest, existing, now = new Date()) {
131
132
  const run = existing ?? newBatchRun(manifest, sha256(['workspace-import-v1', manifest.manifestId, manifest.workspaceId].join('\0')), now);
132
- return receiptFor(run, now);
133
+ return receiptFor({
134
+ ...run,
135
+ preflight: coveragePreflight({
136
+ expectedProviders: manifest.preflight?.expectedProviders,
137
+ expectedProviderBasis: manifest.preflight?.expectedProviderBasis ?? 'legacy',
138
+ reports: manifest.providers,
139
+ }),
140
+ }, now);
133
141
  }
134
142
  function newBatchRun(manifest, runId, now) {
135
143
  const timestamp = now.toISOString();
@@ -143,6 +151,8 @@ function newBatchRun(manifest, runId, now) {
143
151
  startedAt: timestamp,
144
152
  updatedAt: timestamp,
145
153
  completedAt: null,
154
+ preflight: manifest.preflight,
155
+ discoveryRuntime: manifest.preflight?.runtime,
146
156
  providers: manifest.providers,
147
157
  sources: manifest.sources.map((source) => ({
148
158
  sourceId: source.sourceId,
@@ -200,21 +210,7 @@ async function assertManifestSourceUnchanged(source) {
200
210
  }
201
211
  }
202
212
  function adapterFor(provider) {
203
- if (provider === 'deepseek-harness')
204
- return new DeepSeekHarnessSessionAdapter();
205
- if (provider === 'omp')
206
- return new OmpSessionAdapter();
207
- if (provider === 'claude')
208
- return new ClaudeSessionAdapter();
209
- if (provider === 'codex')
210
- return new CodexSessionAdapter();
211
- if (provider === 'cursor')
212
- return new CursorSessionAdapter();
213
- if (provider === 'factory')
214
- return new FactorySessionAdapter();
215
- if (provider === 'muse')
216
- return new MuseSessionAdapter();
217
- throw new SessionContractError('UNSUPPORTED_OPERATION', `batch discovery import is not implemented for ${provider}`);
213
+ return createSessionAdapterRegistry().get(provider);
218
214
  }
219
215
  async function sessionSource(selected, adapter) {
220
216
  const probe = await adapter.inspect(selected);
@@ -225,7 +221,7 @@ async function sessionSource(selected, adapter) {
225
221
  providerProfile: providerProfile(selected.provider, selected.locatorClass),
226
222
  locatorClass: selected.locatorClass,
227
223
  redactedLocator: '<discovered-session-source>',
228
- adapterVersion: adapterVersion(selected.provider),
224
+ adapterVersion: adapter.adapterVersion,
229
225
  sourceSchemaVersion: probe.sourceSchemaVersion,
230
226
  disposition: 'implemented',
231
227
  operationalState: probe.operationalState,
@@ -234,23 +230,6 @@ async function sessionSource(selected, adapter) {
234
230
  extensions: { [`native.${selected.provider}`]: {} },
235
231
  });
236
232
  }
237
- function adapterVersion(provider) {
238
- if (provider === 'deepseek-harness')
239
- return DEEPSEEK_HARNESS_ADAPTER_VERSION;
240
- if (provider === 'omp')
241
- return OMP_ADAPTER_VERSION;
242
- if (provider === 'claude')
243
- return CLAUDE_ADAPTER_VERSION;
244
- if (provider === 'codex')
245
- return CODEX_ADAPTER_VERSION;
246
- if (provider === 'cursor')
247
- return CURSOR_ADAPTER_VERSION;
248
- if (provider === 'factory')
249
- return FACTORY_ADAPTER_VERSION;
250
- if (provider === 'muse')
251
- return MUSE_ADAPTER_VERSION;
252
- return '1.0.0';
253
- }
254
233
  function providerProfile(provider, locatorClass) {
255
234
  if (provider === 'deepseek-harness')
256
235
  return 'native-session-v2-jsonl';
@@ -269,6 +248,8 @@ function providerProfile(provider, locatorClass) {
269
248
  return 'documented-project-jsonl';
270
249
  if (provider === 'muse')
271
250
  return 'muse-native-session-log-v1';
251
+ if (provider === 'grokbot')
252
+ return 'grokbot-native-transcript-replica-v1';
272
253
  return 'manual-interchange';
273
254
  }
274
255
  function importErrorCode(error) {
@@ -103,17 +103,21 @@ export class StructuralCandidateExtractor {
103
103
  const drafts = [];
104
104
  for (const item of evidence) {
105
105
  let offset = 0;
106
- for (const line of item.text.split(/\n/)) {
107
- const match = STRUCTURAL_PATTERN.exec(line);
108
- if (match) {
109
- const label = match[1].toLowerCase();
110
- const assertion = match[2].trim();
111
- const start = offset + line.indexOf(assertion);
106
+ for (const rawLine of item.text.split(/\n/)) {
107
+ const line = rawLine.endsWith('\r') ? rawLine.slice(0, -1) : rawLine;
108
+ const separator = line.indexOf(':');
109
+ const label = line.slice(0, separator).normalize('NFKC').toLowerCase();
110
+ const remainder = line.slice(separator + 1);
111
+ const content = remainder.trimStart();
112
+ if (separator >= 0 && Object.hasOwn(STRUCTURAL_TYPES, label)
113
+ && remainder.length > 0 && !/[\r\u2028\u2029]/u.test(content || remainder.slice(-1))) {
114
+ const assertion = content.trim();
115
+ const start = offset + separator + 1 + remainder.length - content.length;
112
116
  const type = STRUCTURAL_TYPES[label];
113
117
  const relationship = type === 'relationship'
114
118
  ? parseRelationship(assertion)
115
119
  : { subject: null, predicate: null, object: null };
116
- if (type && (type !== 'relationship' || relationship.subject)) {
120
+ if (type && assertion && (type !== 'relationship' || relationship.subject)) {
117
121
  drafts.push({
118
122
  type,
119
123
  assertion,
@@ -125,7 +129,7 @@ export class StructuralCandidateExtractor {
125
129
  });
126
130
  }
127
131
  }
128
- offset += line.length + 1;
132
+ offset += rawLine.length + 1;
129
133
  }
130
134
  }
131
135
  return drafts;
@@ -134,7 +138,6 @@ export class StructuralCandidateExtractor {
134
138
  const SECURITY_POLICY_VERSION = '1.0.0';
135
139
  const INSTRUCTION_PATTERN = /\b(?:ignore|override|disregard)\b.{0,40}\b(?:instruction|prompt|policy|rule)s?\b|\b(?:system|developer)\s+(?:message|instruction|prompt)\b|\b(?:execute|invoke|run)\b.{0,30}\b(?:tool|command|shell|script)\b/i;
136
140
  const SECRET_PATTERN = /\b(?:api[_-]?key|access[_-]?token|password|passwd|private[_-]?key|authorization|cookie|secret)\b\s*(?:[:=]|\bis\b)/i;
137
- const STRUCTURE_PATTERN = /(?:^|\n)\s*(?:---|\.\.\.)\s*(?:\n|$)|```|~~~|<[/!?A-Za-z]|!\[[^\]]*\]\(|\[[^\]]+\]\([^)]*\)|\{\{|\{%/;
138
141
  const CONTROL_PATTERN = /[\u0000-\u0008\u000b\u000c\u000e-\u001f\u007f-\u009f]/;
139
142
  const BIDI_PATTERN = /[\u061c\u200e\u200f\u202a-\u202e\u2066-\u2069]/u;
140
143
  const LATIN_PATTERN = /\p{Script=Latin}/u;
@@ -146,7 +149,7 @@ export function classifyCandidateSecurity(input) {
146
149
  const warnings = [];
147
150
  if (INSTRUCTION_PATTERN.test(text))
148
151
  warnings.push('instruction-like');
149
- if (STRUCTURE_PATTERN.test(text))
152
+ if (hasStructureBreakingContent(text))
150
153
  warnings.push('structure-breaking');
151
154
  if (CONTROL_PATTERN.test(text))
152
155
  warnings.push('control-character');
@@ -175,7 +178,40 @@ function evidenceSupportsAssertion(assertion, quote) {
175
178
  const quoteTokens = tokens(quote);
176
179
  return [...assertionTokens].some((token) => quoteTokens.has(token));
177
180
  }
178
- const STRUCTURAL_PATTERN = /^(Decision|Requirement|Constraint|Preference|Task|Discovery|Fix|Failed approach|Procedure|Risk|Contradiction|Question|Entity|Relationship):\s*(.+)$/i;
181
+ function hasStructureBreakingContent(text) {
182
+ if (/```|~~~|<[/!?A-Za-z]|\{\{|\{%/.test(text))
183
+ return true;
184
+ for (const line of text.split('\n')) {
185
+ const trimmed = line.trim();
186
+ if (trimmed === '---' || trimmed === '...')
187
+ return true;
188
+ }
189
+ let bracket = -1;
190
+ let image = false;
191
+ let link = false;
192
+ for (let index = 0; index < text.length; index++) {
193
+ if (text[index] === '[') {
194
+ if (bracket < 0)
195
+ bracket = index;
196
+ if (index > 0 && text[index - 1] === '!')
197
+ image = true;
198
+ }
199
+ else if (text[index] === ']') {
200
+ if (text[index + 1] === '(') {
201
+ if (image)
202
+ return true;
203
+ if (bracket >= 0 && index > bracket + 1)
204
+ link = true;
205
+ }
206
+ bracket = -1;
207
+ image = false;
208
+ }
209
+ else if (text[index] === ')' && link) {
210
+ return true;
211
+ }
212
+ }
213
+ return false;
214
+ }
179
215
  const STRUCTURAL_TYPES = {
180
216
  decision: 'decision',
181
217
  requirement: 'requirement',
@@ -6,6 +6,41 @@ export const SESSION_PROVIDER_IDS = [
6
6
  'opencode', 'openclaw', 'openhuman', 'grokbot', 'grok-build', 'pi', 'omp', 'deepseek-harness', 'warp', 'devin-desktop', 'muse', 'generic',
7
7
  ];
8
8
  export const SessionProviderIdSchema = z.enum(SESSION_PROVIDER_IDS);
9
+ // Expected scope must also represent providers unknown to this runtime.
10
+ export const ExpectedSessionProviderSchema = z.string().regex(/^[a-z][a-z0-9-]*$/);
11
+ export const SessionRuntimeIdentitySchema = z.object({
12
+ packageName: z.string(),
13
+ version: z.string(),
14
+ packageRoot: z.string(),
15
+ executable: z.string(),
16
+ nodeVersion: z.string(),
17
+ installationMethod: z.string(),
18
+ installationState: z.enum(['aligned', 'mismatch', 'stale', 'unrecorded', 'unknown']),
19
+ canonicalRoot: z.string().nullable(),
20
+ diagnostics: z.array(z.string()),
21
+ });
22
+ export const SessionCoveragePreflightSchema = z.object({
23
+ expectedProviders: z.array(ExpectedSessionProviderSchema).min(1),
24
+ expectedProviderBasis: z.enum(['explicit', 'declared-default', 'legacy']),
25
+ supportedProviders: z.array(ExpectedSessionProviderSchema),
26
+ runtime: SessionRuntimeIdentitySchema,
27
+ status: z.enum(['partial', 'complete']),
28
+ unresolvedProviders: z.array(ExpectedSessionProviderSchema),
29
+ ledger: z.array(z.object({
30
+ provider: ExpectedSessionProviderSchema,
31
+ disposition: z.enum([
32
+ 'missing-adapter', 'unsupported', 'authorization-required', 'export-required',
33
+ 'unavailable', 'no-sources', 'not-checked', 'pending-import', 'import-incomplete',
34
+ 'scope-incomplete', 'acquired',
35
+ ]),
36
+ adapterVersion: z.string().nullable(),
37
+ supportedOperations: z.array(z.string()),
38
+ acquisitionModes: z.array(z.string()),
39
+ sourceCount: z.number().int().nonnegative(),
40
+ boundaries: z.array(z.string()),
41
+ remediation: z.string().nullable(),
42
+ })),
43
+ });
9
44
  export const SESSION_PROVIDER_ALIASES = Object.freeze({
10
45
  windsurf: 'devin-desktop',
11
46
  dsh: 'deepseek-harness',
@@ -0,0 +1,134 @@
1
+ import { readFileSync, realpathSync } from 'node:fs';
2
+ import { dirname, join } from 'node:path';
3
+ import { fileURLToPath } from 'node:url';
4
+ import { findPackageRoot } from '../cli/find-package-root.js';
5
+ import { inspectInstallation } from '../installation/manager.mjs';
6
+ import { ExpectedSessionProviderSchema, SESSION_PROVIDER_ALIASES, SESSION_PROVIDER_IDS, SessionContractError, SessionCoveragePreflightSchema, SessionRuntimeIdentitySchema, } from './contracts.js';
7
+ import { createSessionAdapterRegistry } from './adapter-registry.js';
8
+ export function expectedSessionProviders(values) {
9
+ const providers = values.map((value) => {
10
+ const canonical = SESSION_PROVIDER_ALIASES[value.trim()]
11
+ ?? value.trim();
12
+ if (!ExpectedSessionProviderSchema.safeParse(canonical).success) {
13
+ throw new SessionContractError('INVALID_ARGUMENT', `invalid expected provider: ${value}`);
14
+ }
15
+ return canonical;
16
+ });
17
+ if (providers.length === 0) {
18
+ throw new SessionContractError('INVALID_ARGUMENT', 'expected providers must not be empty');
19
+ }
20
+ return [...new Set(providers)].sort();
21
+ }
22
+ /** Resolve the code actually loaded, independently of cwd, AIWG_ROOT and corpus redirects. */
23
+ export function sessionRuntimeIdentity() {
24
+ const packageRoot = findPackageRoot(dirname(fileURLToPath(import.meta.url)));
25
+ if (!packageRoot)
26
+ throw new SessionContractError('INVALID_ARGUMENT', 'cannot locate the running AIWG package');
27
+ const pkg = JSON.parse(readFileSync(join(packageRoot, 'package.json'), 'utf8'));
28
+ const executable = process.argv[1] ?? process.execPath;
29
+ const base = {
30
+ packageName: pkg.name, version: pkg.version, packageRoot: realpathSync(packageRoot),
31
+ executable, nodeVersion: process.version,
32
+ };
33
+ try {
34
+ const installation = inspectInstallation({ actualRoot: packageRoot, createIfMissing: false });
35
+ return SessionRuntimeIdentitySchema.parse({
36
+ ...base,
37
+ installationMethod: installation.actualMethod,
38
+ installationState: installation.state,
39
+ canonicalRoot: installation.identity?.root ?? null,
40
+ diagnostics: [
41
+ ...installation.drift,
42
+ ...(['mismatch', 'stale'].includes(installation.state)
43
+ ? ['Deliberately select a compatible runtime, inspect `aiwg installation show`, and rediscover. No automatic upgrade or installation switch is performed.'] : []),
44
+ ],
45
+ });
46
+ }
47
+ catch (error) {
48
+ return SessionRuntimeIdentitySchema.parse({
49
+ ...base, installationMethod: 'unknown', installationState: 'unknown', canonicalRoot: null,
50
+ diagnostics: [
51
+ error instanceof Error ? error.message : String(error),
52
+ 'Inspect `aiwg installation show` and deliberately select a compatible runtime before claiming complete coverage.',
53
+ ],
54
+ });
55
+ }
56
+ }
57
+ export function coveragePreflight(options = {}) {
58
+ const expectedProviders = expectedSessionProviders(options.expectedProviders ?? SESSION_PROVIDER_IDS);
59
+ const adapters = (options.registry ?? createSessionAdapterRegistry()).list();
60
+ const runtime = options.runtime ?? sessionRuntimeIdentity();
61
+ const ledger = expectedProviders.map((provider) => {
62
+ const adapter = adapters.find((item) => item.provider === provider);
63
+ const report = options.reports?.find((item) => item.provider === provider);
64
+ const entry = {
65
+ provider, disposition: 'not-checked', adapterVersion: adapter?.adapterVersion ?? null,
66
+ supportedOperations: [...(adapter?.supportedOperations ?? [])],
67
+ acquisitionModes: [...(adapter?.acquisitionModes ?? [])],
68
+ sourceCount: report?.sourceCount ?? 0, boundaries: [],
69
+ remediation: report?.remediation ?? 'Run authorized workspace discovery or select a supported export.',
70
+ };
71
+ if (!adapter) {
72
+ entry.disposition = 'missing-adapter';
73
+ entry.remediation = `Running ${runtime.packageName} ${runtime.version} at ${runtime.packageRoot} has no ${provider} adapter. Deliberately select a compatible runtime or use an explicitly authorized supported export; no installation is switched automatically.`;
74
+ }
75
+ else if (adapter.disposition === 'unsupported' || !adapter.supportedOperations.includes('stream')) {
76
+ entry.disposition = 'unsupported';
77
+ }
78
+ else if (report?.reasonCode === 'SHARED_ROOT_AUTHORIZATION_REQUIRED') {
79
+ entry.disposition = 'authorization-required';
80
+ }
81
+ else if (report?.status === 'export-required' || !adapter.supportedOperations.includes('discover')) {
82
+ entry.disposition = 'export-required';
83
+ }
84
+ else if (report?.status === 'unavailable') {
85
+ entry.disposition = 'unavailable';
86
+ }
87
+ else if (report?.reasonCode === 'MUSE_SOURCE_INSPECTION_INCOMPLETE') {
88
+ entry.disposition = report.sourceCount > 0 ? 'pending-import' : 'not-checked';
89
+ entry.boundaries.push('Some Muse sources could not be fully inspected; see museSourceInspections in the discovery manifest.');
90
+ entry.remediation = report.remediation;
91
+ }
92
+ else if (report?.status === 'checked') {
93
+ entry.disposition = report.sourceCount > 0 ? 'pending-import' : 'no-sources';
94
+ entry.remediation = report.sourceCount > 0
95
+ ? 'Import the exact authorized manifest and inspect source dispositions.'
96
+ : 'Zero matching sources does not establish no activity; verify scope, authorization and export availability.';
97
+ }
98
+ if (provider === 'muse') {
99
+ entry.boundaries.push('Native discovery includes parent session.jsonl logs only; nested subagent logs and approval-review scope are not established.');
100
+ }
101
+ return entry;
102
+ });
103
+ return SessionCoveragePreflightSchema.parse({
104
+ expectedProviders,
105
+ expectedProviderBasis: options.expectedProviderBasis ?? (options.expectedProviders ? 'explicit' : 'declared-default'),
106
+ supportedProviders: adapters.map((adapter) => adapter.provider), runtime,
107
+ status: 'partial', unresolvedProviders: expectedProviders, ledger,
108
+ });
109
+ }
110
+ export function reconcileCoveragePreflight(preflight, sources) {
111
+ const accepted = new Set(['committed', 'duplicate', 'previously-committed']);
112
+ const ledger = preflight.ledger.map((entry) => {
113
+ if (!['pending-import', 'import-incomplete', 'scope-incomplete', 'acquired'].includes(entry.disposition))
114
+ return entry;
115
+ const selected = sources.filter((source) => source.provider === entry.provider);
116
+ const imported = selected.length === entry.sourceCount && selected.length > 0
117
+ && selected.every((source) => accepted.has(source.status) && source.eventsAccepted > 0);
118
+ return {
119
+ ...entry,
120
+ disposition: !imported ? 'import-incomplete'
121
+ : entry.boundaries.length > 0 ? 'scope-incomplete' : 'acquired',
122
+ remediation: !imported ? 'Resolve pending, rejected, skipped or empty imports before claiming acquisition coverage.'
123
+ : entry.boundaries.length > 0 ? 'Declare the parent-only boundary and separately authorize supported exports for omitted scope.' : null,
124
+ };
125
+ });
126
+ const unresolvedProviders = ledger.filter((entry) => entry.disposition !== 'acquired').map((entry) => entry.provider);
127
+ const runtimeGap = ['mismatch', 'stale', 'unknown'].includes(preflight.runtime.installationState);
128
+ return {
129
+ ...preflight, ledger, unresolvedProviders,
130
+ status: unresolvedProviders.length > 0 || runtimeGap || preflight.expectedProviderBasis !== 'explicit'
131
+ ? 'partial' : 'complete',
132
+ };
133
+ }
134
+ //# sourceMappingURL=coverage-preflight.js.map
@@ -1,6 +1,9 @@
1
1
  import { SessionContractError, assertSessionProviderId, } from './contracts.js';
2
2
  export class SessionSourceAdapterRegistry {
3
3
  adapters = new Map();
4
+ list() {
5
+ return [...this.adapters.values()].sort((a, b) => a.provider.localeCompare(b.provider));
6
+ }
4
7
  register(adapter) {
5
8
  const provider = assertSessionProviderId(adapter.provider);
6
9
  if (this.adapters.has(provider))