@aiwg/cli 2026.10.3 → 2026.10.5
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 +2 -2
- package/agentic/code/providers/model-capabilities.v1.json +96 -4
- package/bin/aiwg.mjs +50 -27
- package/dist/src/agents/grounding/knowledge-base.js +54 -6
- package/dist/src/artifacts/browser-export.js +6 -0
- package/dist/src/artifacts/checksum-manifest.js +1 -0
- package/dist/src/artifacts/citation-parser.js +173 -92
- package/dist/src/artifacts/citation-table-schema.js +59 -0
- package/dist/src/artifacts/cli.js +69 -18
- package/dist/src/artifacts/corpus-tools/snapshot.js +1 -1
- package/dist/src/artifacts/corpus-tools/vision-extract.js +2 -0
- package/dist/src/artifacts/corpus-views/ref-parser.js +3 -1
- package/dist/src/artifacts/corpus-views/renderers.js +3 -3
- package/dist/src/artifacts/discovery-eval.js +6 -4
- package/dist/src/artifacts/fortemi-core-query-adapter.js +36 -3
- package/dist/src/artifacts/fortemi-core-sync.js +166 -40
- package/dist/src/artifacts/framework-capabilities.js +171 -0
- package/dist/src/artifacts/framework-index-paths.js +73 -0
- package/dist/src/artifacts/framework-source-digest.js +75 -0
- package/dist/src/artifacts/index-builder.js +286 -131
- package/dist/src/artifacts/index-files.js +132 -18
- package/dist/src/artifacts/index-preparation.js +130 -0
- package/dist/src/artifacts/index-refresh.js +591 -0
- package/dist/src/artifacts/index-worker.mjs +11 -0
- package/dist/src/artifacts/prebuilt-build-lock.js +47 -4
- package/dist/src/artifacts/prebuilt-deployment.js +46 -0
- package/dist/src/artifacts/prebuilt-relations.js +80 -0
- package/dist/src/artifacts/query-engine.js +410 -88
- package/dist/src/artifacts/relations-builder.js +168 -0
- package/dist/src/artifacts/relations.js +148 -0
- package/dist/src/artifacts/stats.js +5 -2
- package/dist/src/artifacts/types.js +30 -10
- package/dist/src/artifacts/watcher.js +1 -1
- package/dist/src/auth/credential-store.js +2 -1
- package/dist/src/catalog/cli.d.mts +5 -0
- package/dist/src/channel/manager.d.mts +20 -0
- package/dist/src/channel/manager.mjs +19 -2
- package/dist/src/cli/command-log.js +2 -3
- package/dist/src/cli/handlers/artifacts.js +3 -0
- package/dist/src/cli/handlers/auth.js +3 -0
- package/dist/src/cli/handlers/decision.js +19 -12
- package/dist/src/cli/handlers/diagnose.js +4 -3
- package/dist/src/cli/handlers/effect.js +4 -2
- package/dist/src/cli/handlers/evidence.js +3 -0
- package/dist/src/cli/handlers/help.js +1 -0
- package/dist/src/cli/handlers/index.js +3 -1
- package/dist/src/cli/handlers/init.js +4 -1
- package/dist/src/cli/handlers/lint.js +5 -0
- package/dist/src/cli/handlers/models.js +104 -8
- package/dist/src/cli/handlers/ralph-launcher.js +2 -0
- package/dist/src/cli/handlers/refresh.js +12 -0
- package/dist/src/cli/handlers/resource-versions.js +3 -0
- package/dist/src/cli/handlers/rules.js +195 -0
- package/dist/src/cli/handlers/run.js +4 -0
- package/dist/src/cli/handlers/runtime-info.js +1 -2
- package/dist/src/cli/handlers/script-runner.js +3 -2
- package/dist/src/cli/handlers/session.js +19 -9
- package/dist/src/cli/handlers/sessions.js +137 -43
- package/dist/src/cli/handlers/setup-manifest.js +39 -44
- package/dist/src/cli/handlers/setup.js +41 -0
- package/dist/src/cli/handlers/steward.js +11 -0
- package/dist/src/cli/handlers/subcommands.js +57 -2
- package/dist/src/cli/handlers/uhp.js +3 -0
- package/dist/src/cli/handlers/use.js +294 -55
- package/dist/src/cli/handlers/utilities.js +26 -10
- package/dist/src/cli/handlers/version.js +8 -0
- package/dist/src/cli/router.js +15 -1
- package/dist/src/cli/services/deployment-verification.js +19 -9
- package/dist/src/cli/services/provider-prepare-coordinator.js +24 -0
- package/dist/src/cli/skill-usage.js +2 -3
- package/dist/src/config/aiwg-config.js +87 -37
- package/dist/src/config/cli.js +111 -5
- package/dist/src/config/decision-config.js +106 -0
- package/dist/src/config/dispatch-thresholds-runtime.d.mts +8 -0
- package/dist/src/config/gitignore.js +50 -0
- package/dist/src/config/index-graph-overrides.js +36 -0
- package/dist/src/config/project-artifacts-health.d.mts +37 -0
- package/dist/src/config/project-artifacts-runtime.d.mts +16 -0
- package/dist/src/config/user-config-dir.d.mts +9 -0
- package/dist/src/config/user-config.js +2 -1
- package/dist/src/config/user-registry.js +23 -15
- package/dist/src/config/user-state.js +7 -0
- package/dist/src/decision/ask.js +203 -43
- package/dist/src/decision/context-live-qualification.js +2 -2
- package/dist/src/decision/driver.js +13 -8
- package/dist/src/decision/ensemble/aggregate.js +23 -10
- package/dist/src/decision/ensemble-study/multifact-study.js +6 -2
- package/dist/src/decision/entry.js +2 -15
- package/dist/src/decision/graph-live-qualification.js +1 -1
- package/dist/src/decision/graph-run.js +9 -0
- package/dist/src/decision/heldout/collector.js +5 -13
- package/dist/src/decision/heldout/contract.js +30 -7
- package/dist/src/decision/jev-credentials.js +15 -1
- package/dist/src/decision/ledger.js +131 -28
- package/dist/src/decision/offload-activation.js +137 -0
- package/dist/src/decision/offload.js +550 -0
- package/dist/src/decision/qualification/load.js +4 -6
- package/dist/src/decision/savings.js +28 -0
- package/dist/src/effects/types.js +5 -1
- package/dist/src/effects/verifiers/git.js +2 -1
- package/dist/src/effects/verifiers/tracker.js +26 -14
- package/dist/src/extensions/commands/definitions.js +19 -0
- package/dist/src/extensions/project-local-remove.js +36 -1
- package/dist/src/gates/providers/loader.js +61 -17
- package/dist/src/installation/manager-command.d.mts +18 -0
- package/dist/src/installation/manager-command.mjs +14 -2
- package/dist/src/installation/manager.d.mts +49 -0
- package/dist/src/installation/manager.mjs +78 -3
- package/dist/src/issues/cli.js +4 -4
- package/dist/src/issues/local.js +24 -5
- package/dist/src/jobs/runner.js +1 -1
- package/dist/src/lint/cli.js +27 -1
- package/dist/src/lint/loader.js +2 -1
- package/dist/src/lint/reporters.js +25 -1
- package/dist/src/lint/rule-activation.js +43 -0
- package/dist/src/lint/runner.js +137 -62
- package/dist/src/mcp/adapters/codex-runtime.js +7 -1
- package/dist/src/mcp/claude-install.d.mts +4 -0
- package/dist/src/mcp/claude-install.mjs +41 -0
- package/dist/src/mcp/cli.d.mts +1 -0
- package/dist/src/mcp/cli.mjs +36 -11
- package/dist/src/mcp/config-file.d.mts +28 -0
- package/dist/src/mcp/config-layers.d.mts +36 -0
- package/dist/src/mcp/credentials.d.mts +51 -0
- package/dist/src/mcp/grok-build-config.d.mts +6 -0
- package/dist/src/mcp/grok-build-config.mjs +1 -1
- package/dist/src/mcp/helpers.mjs +3 -2
- package/dist/src/mcp/muse-native-config.d.mts +13 -0
- package/dist/src/mcp/muse-native-config.mjs +1 -0
- package/dist/src/mcp/omp-config.d.mts +4 -0
- package/dist/src/mcp/registry.js +3 -93
- package/dist/src/mcp/registry.mjs +3 -87
- package/dist/src/mcp/server-config.d.mts +3 -0
- package/dist/src/mcp/server-config.mjs +89 -0
- package/dist/src/mcp/server.mjs +37 -375
- package/dist/src/mcp/test-simple.mjs +2 -1
- package/dist/src/mcp/toml-editor.d.mts +4 -0
- package/dist/src/mcp/toml-string.d.mts +1 -0
- package/dist/src/mcp/toml-strip-mcp.d.mts +1 -0
- package/dist/src/mcp/tool-filters.d.mts +46 -0
- package/dist/src/mcp/tools/decision.mjs +12 -11
- package/dist/src/mcp/tools/discovery.mjs +62 -55
- package/dist/src/mcp/tools/orchestration.mjs +12 -2
- package/dist/src/mcp/tools/worker-invoke.mjs +1340 -23
- package/dist/src/mcp/tools/worker-shell-control.mjs +52 -21
- package/dist/src/mcp/tools/worker-stdin-runtime.mjs +3 -3
- package/dist/src/mission-protocol/codecs.js +8 -0
- package/dist/src/models/config-loader.js +7 -2
- package/dist/src/models/model-capabilities.v1.json +96 -4
- package/dist/src/models/model-discovery.js +76 -11
- package/dist/src/models/provider-policy.js +101 -7
- package/dist/src/models/qualification-digest.d.mts +2 -0
- package/dist/src/models/resolver.js +12 -10
- package/dist/src/models/worker-direct-readiness.js +65 -44
- package/dist/src/models/worker-dispatch-offer.js +3 -3
- package/dist/src/models/worker-health-readiness.js +16 -3
- package/dist/src/models/worker-installation.d.mts +39 -0
- package/dist/src/models/worker-installation.mjs +135 -28
- package/dist/src/process/bounded-child-process.d.mts +84 -0
- package/dist/src/process/bounded-child-process.mjs +43 -0
- package/dist/src/process/cli-command.d.mts +16 -0
- package/dist/src/process/signal-child.d.mts +6 -0
- package/dist/src/process/signal-child.mjs +7 -0
- package/dist/src/providers/deployed-skill-roots.js +20 -0
- package/dist/src/providers/grok-build-acp.js +3 -2
- package/dist/src/providers/grok-build-headless.js +12 -4
- package/dist/src/providers/grok-build-inspect.js +1 -0
- package/dist/src/providers/omp-agent.d.mts +8 -0
- package/dist/src/providers/omp-diagnostics.d.mts +1 -0
- package/dist/src/providers/omp-paths.d.mts +13 -0
- package/dist/src/providers/skill-ownership.d.mts +9 -0
- package/dist/src/providers/skill-ownership.mjs +88 -0
- package/dist/src/rules/activation.d.mts +21 -0
- package/dist/src/rules/activation.mjs +62 -0
- package/dist/src/rules/inline-budget.d.mts +26 -0
- package/dist/src/rules/inline-budget.mjs +66 -0
- package/dist/src/rules/inventory.js +129 -0
- package/dist/src/rules/pin-state.js +73 -0
- package/dist/src/rules/pins.d.mts +14 -0
- package/dist/src/rules/pins.mjs +112 -0
- package/dist/src/rules/rule-frontmatter.schema.json +197 -0
- package/dist/src/serve/mission-conductor.js +38 -12
- package/dist/src/serve/worker-invocation.js +30 -10
- package/dist/src/serve/worker-stdin-frame.d.mts +10 -0
- package/dist/src/sessions/adapter-registry.js +23 -19
- package/dist/src/sessions/adapters/claude.js +39 -54
- package/dist/src/sessions/adapters/codex.js +95 -67
- package/dist/src/sessions/adapters/copilot.js +4 -4
- package/dist/src/sessions/adapters/cursor.js +40 -57
- package/dist/src/sessions/adapters/deepseek-harness.js +15 -12
- package/dist/src/sessions/adapters/factory.js +31 -27
- package/dist/src/sessions/adapters/generic.js +10 -10
- package/dist/src/sessions/adapters/grok-build.js +11 -11
- package/dist/src/sessions/adapters/grokbot.js +24 -13
- package/dist/src/sessions/adapters/hermes.js +27 -29
- package/dist/src/sessions/adapters/muse-workspace-scan.js +31 -11
- package/dist/src/sessions/adapters/muse.js +150 -93
- package/dist/src/sessions/adapters/omp.js +28 -14
- package/dist/src/sessions/adapters/openclaw.js +89 -79
- package/dist/src/sessions/adapters/opencode.js +27 -24
- package/dist/src/sessions/adapters/openhuman.js +18 -60
- package/dist/src/sessions/adapters/pi.js +29 -14
- package/dist/src/sessions/adapters/warp.js +3 -3
- package/dist/src/sessions/adapters/windsurf.js +19 -48
- package/dist/src/sessions/batch-contracts.js +16 -8
- package/dist/src/sessions/batch-import.js +252 -12
- package/dist/src/sessions/contracts.js +50 -3
- package/dist/src/sessions/coverage-preflight.js +27 -2
- package/dist/src/sessions/export-plan.js +4 -3
- package/dist/src/sessions/import-exclusions.js +72 -0
- package/dist/src/sessions/import-lease.js +34 -18
- package/dist/src/sessions/import-limits.js +37 -0
- package/dist/src/sessions/importer.js +60 -38
- package/dist/src/sessions/lifecycle.js +45 -0
- package/dist/src/sessions/policy.js +145 -26
- package/dist/src/sessions/readers.js +106 -53
- package/dist/src/sessions/refresh.js +105 -0
- package/dist/src/sessions/repository.js +151 -54
- package/dist/src/sessions/workspace-discovery.js +292 -60
- package/dist/src/sessions/workspace-matching.js +107 -0
- package/dist/src/skills/importer.js +1 -0
- package/dist/src/smiths/context-pipeline/aiwg-md.js +11 -0
- package/dist/src/smiths/context-pipeline/claude-hook.js +3 -26
- package/dist/src/smiths/context-pipeline/finalization.js +6 -5
- package/dist/src/smiths/context-pipeline/generator.js +21 -4
- package/dist/src/smiths/context-pipeline/parallelism-section.js +7 -15
- package/dist/src/smiths/mcpsmith/generator.js +1 -1
- package/dist/src/smiths/toolsmith/runtime-discovery.d.mts +10 -0
- package/dist/src/smiths/toolsmith/runtime-discovery.mjs +76 -18
- package/dist/src/storage/backends/fs.js +18 -76
- package/dist/src/storage/backends/obsidian.js +1 -0
- package/dist/src/tracker/forge-http.js +2 -1
- package/dist/src/update/checker.d.mts +2 -0
- package/dist/src/update/service.d.mts +22 -0
- package/dist/src/utils/contained-filesystem.d.mts +37 -0
- package/dist/src/utils/contained-filesystem.mjs +683 -0
- package/dist/src/utils/temporary-directory.js +36 -0
- package/dist/src/writing/example-generator.js +1 -1
- package/package.json +15 -2
- package/schemas/models/model-catalog.v1.schema.json +1 -1
- package/schemas/models/provider-model-capabilities.v1.schema.json +6 -0
- package/tools/_resolve-impl.mjs +13 -15
- package/tools/agents/deploy-agents.mjs +49 -21
- package/tools/agents/providers/base.mjs +104 -134
- package/tools/agents/providers/claude.mjs +8 -24
- package/tools/agents/providers/codex.mjs +18 -11
- package/tools/agents/providers/cursor.mjs +19 -18
- package/tools/agents/providers/grok-build.mjs +3 -1
- package/tools/agents/providers/hermes.mjs +57 -47
- package/tools/agents/providers/openclaw.mjs +9 -4
- package/tools/agents/providers/pi.mjs +5 -0
- package/tools/agents/providers/provider-prepare-channel.mjs +5 -0
- package/tools/agents/providers/provider-prepare-coordinator.mjs +247 -0
- package/tools/agents/providers/provider-prepare-worker.mjs +84 -0
- package/tools/agents/providers/rule-delivery.mjs +1270 -0
- package/tools/agents/providers/warp.mjs +20 -26
- package/tools/cli/decision-offload-report.mjs +40 -0
- package/tools/cli/workspace-status.mjs +862 -0
- package/tools/plugin/package-plugins.mjs +186 -8
- package/tools/plugin/plugin-links.mjs +114 -0
- package/tools/providers/antigravity-transport.mjs +3 -1
- package/tools/providers/deepseek-harness-transport.mjs +6 -4
- package/tools/providers/omp-transport.mjs +4 -2
- package/tools/ralph-external/lib/consecutive-failure-circuit-breaker.mjs +1748 -0
- package/tools/ralph-external/lib/launcher-recovery-evidence.mjs +55 -0
- package/tools/ralph-external/lib/omp-adapter.mjs +1 -1
- package/tools/ralph-external/lib/pi-adapter.mjs +0 -4
- package/tools/ralph-external/lib/provider-adapter.mjs +59 -1
- package/tools/ralph-external/lib/recovery-probe.mjs +72 -0
- package/tools/ralph-external/lib/session-environment.mjs +28 -0
- package/tools/ralph-external/lib/systemd-client.mjs +49 -0
- package/tools/ralph-external/lib/worker-health.mjs +1 -1
- package/tools/ralph-external/lib/worker-isolation.mjs +717 -0
- package/tools/ralph-external/lib/worker-overflow.mjs +50 -0
- package/tools/ralph-external/process-monitor.mjs +1017 -0
- package/tools/ralph-external/session-launcher.mjs +5057 -0
- package/tools/scripts/resource-preflight.mjs +541 -0
- package/tools/skills/deploy-skills-codex.mjs +2 -1
- package/vscode-extension/schemas/aiwg.config.v1.json +1194 -231
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "http://json-schema.org/draft-07/schema#",
|
|
3
|
+
"$id": "https://aiwg.io/schemas/rules/rule-frontmatter.v1.schema.json",
|
|
4
|
+
"title": "Rule activation frontmatter",
|
|
5
|
+
"description": "ADR rule activation contract. Other existing discovery metadata is preserved. Missing activation is permitted only by the migration parser, which warns and infers tier delivery.",
|
|
6
|
+
"type": "object",
|
|
7
|
+
"required": [
|
|
8
|
+
"activation"
|
|
9
|
+
],
|
|
10
|
+
"additionalProperties": true,
|
|
11
|
+
"properties": {
|
|
12
|
+
"activation": {
|
|
13
|
+
"type": "string",
|
|
14
|
+
"enum": [
|
|
15
|
+
"kernel",
|
|
16
|
+
"summary",
|
|
17
|
+
"bound",
|
|
18
|
+
"paths",
|
|
19
|
+
"on-demand"
|
|
20
|
+
]
|
|
21
|
+
},
|
|
22
|
+
"summary": {
|
|
23
|
+
"type": "string",
|
|
24
|
+
"pattern": "^[^\\r\\n\\u0085\\u2028\\u2029]*\\S[^\\r\\n\\u0085\\u2028\\u2029]*$",
|
|
25
|
+
"description": "A nonempty single-line imperative, <=240 Unicode code points after trimming. Imperative mood is reviewed by authors.",
|
|
26
|
+
"allOf": [
|
|
27
|
+
{
|
|
28
|
+
"pattern": "^\\s*\\S(?:[^\\r\\n\\u0085\\u2028\\u2029]{0,238}\\S)?\\s*$"
|
|
29
|
+
}
|
|
30
|
+
]
|
|
31
|
+
},
|
|
32
|
+
"bound_to": {
|
|
33
|
+
"type": "object",
|
|
34
|
+
"additionalProperties": false,
|
|
35
|
+
"properties": {
|
|
36
|
+
"skills": {
|
|
37
|
+
"type": "array",
|
|
38
|
+
"items": {
|
|
39
|
+
"type": "string",
|
|
40
|
+
"pattern": "^(?!.*(?:^|/)\\.\\.?(/|$))[A-Za-z0-9_][A-Za-z0-9_.:-]*(?:/[A-Za-z0-9_][A-Za-z0-9_.:-]*)*$"
|
|
41
|
+
}
|
|
42
|
+
},
|
|
43
|
+
"agents": {
|
|
44
|
+
"type": "array",
|
|
45
|
+
"items": {
|
|
46
|
+
"type": "string",
|
|
47
|
+
"pattern": "^(?!.*(?:^|/)\\.\\.?(/|$))[A-Za-z0-9_][A-Za-z0-9_.:-]*(?:/[A-Za-z0-9_][A-Za-z0-9_.:-]*)*$"
|
|
48
|
+
}
|
|
49
|
+
},
|
|
50
|
+
"flows": {
|
|
51
|
+
"type": "array",
|
|
52
|
+
"items": {
|
|
53
|
+
"type": "string",
|
|
54
|
+
"pattern": "^(?!.*(?:^|/)\\.\\.?(/|$))[A-Za-z0-9_][A-Za-z0-9_.:-]*(?:/[A-Za-z0-9_][A-Za-z0-9_.:-]*)*$"
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
},
|
|
59
|
+
"paths": {
|
|
60
|
+
"type": "array",
|
|
61
|
+
"minItems": 1,
|
|
62
|
+
"items": {
|
|
63
|
+
"type": "string",
|
|
64
|
+
"pattern": "^(?![A-Za-z]:)(?!/)(?!.*\\\\)(?!.*(?:^|/)\\.\\.(?:/|$))(?=.*\\S)[^\\r\\n]+$"
|
|
65
|
+
}
|
|
66
|
+
},
|
|
67
|
+
"enforcedBy": {
|
|
68
|
+
"description": "Opaque reserved metadata for #2839. Has no activation or runtime enforcement effect."
|
|
69
|
+
}
|
|
70
|
+
},
|
|
71
|
+
"allOf": [
|
|
72
|
+
{
|
|
73
|
+
"if": {
|
|
74
|
+
"properties": {
|
|
75
|
+
"activation": {
|
|
76
|
+
"enum": [
|
|
77
|
+
"summary",
|
|
78
|
+
"bound",
|
|
79
|
+
"paths"
|
|
80
|
+
]
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
},
|
|
84
|
+
"then": {
|
|
85
|
+
"required": [
|
|
86
|
+
"summary"
|
|
87
|
+
],
|
|
88
|
+
"properties": {
|
|
89
|
+
"summary": {}
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
},
|
|
93
|
+
{
|
|
94
|
+
"if": {
|
|
95
|
+
"properties": {
|
|
96
|
+
"activation": {
|
|
97
|
+
"enum": [
|
|
98
|
+
"kernel",
|
|
99
|
+
"on-demand"
|
|
100
|
+
]
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
},
|
|
104
|
+
"then": {
|
|
105
|
+
"not": {
|
|
106
|
+
"required": [
|
|
107
|
+
"bound_to"
|
|
108
|
+
],
|
|
109
|
+
"properties": {
|
|
110
|
+
"bound_to": {}
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
},
|
|
115
|
+
{
|
|
116
|
+
"if": {
|
|
117
|
+
"properties": {
|
|
118
|
+
"activation": {
|
|
119
|
+
"const": "paths"
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
},
|
|
123
|
+
"then": {
|
|
124
|
+
"required": [
|
|
125
|
+
"paths"
|
|
126
|
+
],
|
|
127
|
+
"properties": {
|
|
128
|
+
"paths": {}
|
|
129
|
+
}
|
|
130
|
+
},
|
|
131
|
+
"else": {
|
|
132
|
+
"not": {
|
|
133
|
+
"required": [
|
|
134
|
+
"paths"
|
|
135
|
+
],
|
|
136
|
+
"properties": {
|
|
137
|
+
"paths": {}
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
},
|
|
142
|
+
{
|
|
143
|
+
"if": {
|
|
144
|
+
"properties": {
|
|
145
|
+
"activation": {
|
|
146
|
+
"const": "bound"
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
},
|
|
150
|
+
"then": {
|
|
151
|
+
"required": [
|
|
152
|
+
"bound_to"
|
|
153
|
+
],
|
|
154
|
+
"properties": {
|
|
155
|
+
"bound_to": {
|
|
156
|
+
"type": "object",
|
|
157
|
+
"anyOf": [
|
|
158
|
+
{
|
|
159
|
+
"required": [
|
|
160
|
+
"skills"
|
|
161
|
+
],
|
|
162
|
+
"properties": {
|
|
163
|
+
"skills": {
|
|
164
|
+
"type": "array",
|
|
165
|
+
"minItems": 1
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
},
|
|
169
|
+
{
|
|
170
|
+
"required": [
|
|
171
|
+
"agents"
|
|
172
|
+
],
|
|
173
|
+
"properties": {
|
|
174
|
+
"agents": {
|
|
175
|
+
"type": "array",
|
|
176
|
+
"minItems": 1
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
},
|
|
180
|
+
{
|
|
181
|
+
"required": [
|
|
182
|
+
"flows"
|
|
183
|
+
],
|
|
184
|
+
"properties": {
|
|
185
|
+
"flows": {
|
|
186
|
+
"type": "array",
|
|
187
|
+
"minItems": 1
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
]
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
]
|
|
197
|
+
}
|
|
@@ -25,8 +25,6 @@
|
|
|
25
25
|
import { routeMission } from './agent-router.js';
|
|
26
26
|
import { StackAdapterRegistry } from './stack-adapters.js';
|
|
27
27
|
import { assertMissionWorkerHandoff } from '../mission-protocol/codecs.js';
|
|
28
|
-
const defaultRunWorker = () => ({ output: undefined, cost: 0 });
|
|
29
|
-
const defaultScore = (r) => (r.output ? r.output.length : 0);
|
|
30
28
|
/**
|
|
31
29
|
* The cross-stack Mission conductor. Decomposes a Mission into worker cycles,
|
|
32
30
|
* dispatches each to an executor of the chosen runtime via `routeMission`, and
|
|
@@ -36,10 +34,12 @@ export class MissionConductor {
|
|
|
36
34
|
adapters;
|
|
37
35
|
runWorker;
|
|
38
36
|
scoreOutput;
|
|
37
|
+
scorerId;
|
|
39
38
|
constructor(opts = {}) {
|
|
40
39
|
this.adapters = opts.adapters ?? new StackAdapterRegistry();
|
|
41
|
-
this.runWorker = opts.runWorker
|
|
42
|
-
this.scoreOutput = opts.scoreOutput
|
|
40
|
+
this.runWorker = opts.runWorker;
|
|
41
|
+
this.scoreOutput = opts.scoreOutput;
|
|
42
|
+
this.scorerId = opts.scoreOutput ? (opts.scorerId ?? 'custom') : null;
|
|
43
43
|
}
|
|
44
44
|
/**
|
|
45
45
|
* Conduct a Mission across the given executor pool. Returns the ledger.
|
|
@@ -69,6 +69,8 @@ export class MissionConductor {
|
|
|
69
69
|
missionId: plan.missionId,
|
|
70
70
|
goal: plan.goal,
|
|
71
71
|
completionCriterion: plan.completionCriterion,
|
|
72
|
+
executionMode: this.runWorker ? 'executed' : 'plan-only',
|
|
73
|
+
scorerId: this.scorerId,
|
|
72
74
|
activityLog: [],
|
|
73
75
|
cycles: [],
|
|
74
76
|
totalCost: 0,
|
|
@@ -77,6 +79,7 @@ export class MissionConductor {
|
|
|
77
79
|
...(plan.graph ? { graph: structuredClone(plan.graph) } : {}),
|
|
78
80
|
};
|
|
79
81
|
ledger.activityLog.push(`mission ${plan.missionId} start — goal: ${plan.goal} — ${plan.cycles.length} cycle(s)` +
|
|
82
|
+
` — mode: ${ledger.executionMode}, scorer: ${ledger.scorerId ?? '(none)'}` +
|
|
80
83
|
(resumeFrom ? ` (resume: ${carried.size} carried)` : ''));
|
|
81
84
|
for (const cycle of plan.cycles) {
|
|
82
85
|
const graph = plan.graph && cycle.graph ? {
|
|
@@ -134,6 +137,20 @@ export class MissionConductor {
|
|
|
134
137
|
const executor = routing.selected.executor;
|
|
135
138
|
const invocation = adapter.invoke(cycle.prompt, graph);
|
|
136
139
|
ledger.activityLog.push(`cycle ${cycle.id} → executor ${executor.name} (${executor.executorId}) on ${cycle.runtime}: ${invocation.describe}`);
|
|
140
|
+
if (!this.runWorker) {
|
|
141
|
+
ledger.cycles.push({
|
|
142
|
+
cycleId: cycle.id,
|
|
143
|
+
runtime: cycle.runtime,
|
|
144
|
+
primitive: adapter.primitive,
|
|
145
|
+
executorId: executor.executorId,
|
|
146
|
+
routed: true,
|
|
147
|
+
reason: 'plan-only: worker not configured; execution pending',
|
|
148
|
+
cost: 0,
|
|
149
|
+
...(graph ? { graph } : {}),
|
|
150
|
+
});
|
|
151
|
+
ledger.activityLog.push(`cycle ${cycle.id} PLANNED on ${cycle.runtime} — execution pending`);
|
|
152
|
+
continue;
|
|
153
|
+
}
|
|
137
154
|
let output;
|
|
138
155
|
let cost = 0;
|
|
139
156
|
try {
|
|
@@ -173,23 +190,32 @@ export class MissionConductor {
|
|
|
173
190
|
ledger.totalCost += cost;
|
|
174
191
|
ledger.activityLog.push(`cycle ${cycle.id} done on ${cycle.runtime} (cost ${cost})`);
|
|
175
192
|
}
|
|
176
|
-
//
|
|
193
|
+
// Planned cycles remain pending until a worker executes them.
|
|
177
194
|
const accounted = new Set([...ledger.checkpoint.completed, ...ledger.checkpoint.failed]);
|
|
178
195
|
ledger.checkpoint.pending = plan.cycles.map((c) => c.id).filter((id) => !accounted.has(id));
|
|
179
196
|
// Cross-stack aggregation: distinct runtimes that actually ran a worker.
|
|
180
197
|
ledger.runtimesUsed = [
|
|
181
|
-
...new Set(ledger.cycles.filter((c) => c.routed).map((c) => c.runtime)),
|
|
198
|
+
...new Set(ledger.cycles.filter((c) => c.routed && accounted.has(c.cycleId)).map((c) => c.runtime)),
|
|
182
199
|
];
|
|
183
200
|
// Best-output selection (REF-015) — conductor-side, across stacks.
|
|
184
201
|
let best;
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
202
|
+
if (this.scoreOutput) {
|
|
203
|
+
for (const c of ledger.cycles) {
|
|
204
|
+
if (c.output === undefined)
|
|
205
|
+
continue;
|
|
206
|
+
const score = this.scoreOutput(c);
|
|
207
|
+
if (!Number.isFinite(score)) {
|
|
208
|
+
ledger.activityLog.push(`cycle ${c.cycleId} UNSCORED — scorer ${this.scorerId} returned a non-finite score`);
|
|
209
|
+
continue;
|
|
210
|
+
}
|
|
211
|
+
if (!best || score > best.score) {
|
|
212
|
+
best = { cycleId: c.cycleId, runtime: c.runtime, output: c.output, score };
|
|
213
|
+
}
|
|
191
214
|
}
|
|
192
215
|
}
|
|
216
|
+
else {
|
|
217
|
+
ledger.activityLog.push('best-output unavailable: no scorer configured');
|
|
218
|
+
}
|
|
193
219
|
ledger.bestOutput = best;
|
|
194
220
|
ledger.activityLog.push(`mission ${plan.missionId} end — completed ${ledger.checkpoint.completed.length}, ` +
|
|
195
221
|
`failed ${ledger.checkpoint.failed.length}, runtimes [${ledger.runtimesUsed.join(', ')}], ` +
|
|
@@ -8,7 +8,7 @@ import { resolveWorkerPlan } from '../models/resolver.js';
|
|
|
8
8
|
import { workerConfigDigest, validateWorkerHealthConfig } from '../config/aiwg-config.js';
|
|
9
9
|
import { assertValidWorkerPayload } from '../mission-protocol/codecs.js';
|
|
10
10
|
import { qualificationDigest } from '../models/qualification-digest.mjs';
|
|
11
|
-
import { qualifyWorkerInvocationProfile, assertWorkerSelectionAllowed, requiredWorkerControls, requiresWorkerExternalBoundary, isCanonicalWorkerModelKey, assertWorkerHealthQualification, WorkerPolicyError, DEFAULT_WORKER_SELECTION } from '../models/provider-policy.js';
|
|
11
|
+
import { qualifyWorkerInvocationProfile, isOperatorQualifiedWorkerAdapter, assertOperatorWorkerNativeArgv, assertWorkerSelectionAllowed, requiredWorkerControls, requiresWorkerExternalBoundary, isCanonicalWorkerModelKey, assertWorkerHealthQualification, WorkerPolicyError, DEFAULT_WORKER_SELECTION } from '../models/provider-policy.js';
|
|
12
12
|
/** Frozen per-attempt windows; parent/transport ceilings include time already spent. */
|
|
13
13
|
export function resolveWorkerEffectiveHealth(config, input) {
|
|
14
14
|
const roleDefaults = { efficiency: 1, coding: 1, reasoning: 2 };
|
|
@@ -149,6 +149,7 @@ export async function prepareWorkerInvocation(invocation, qualification) {
|
|
|
149
149
|
throw new Error('Worker invocation input/output paths must be distinct');
|
|
150
150
|
}
|
|
151
151
|
if (result.transport === 'shell') {
|
|
152
|
+
assertOperatorWorkerNativeArgv(qualification.adapter, result.argv, result.selected, qualification.permissions);
|
|
152
153
|
if (!absolute(result.argv[0]) || result.argv[0].includes('=') || result.argv.some(value => value.includes('\0'))) {
|
|
153
154
|
throw new WorkerPolicyError('OG_CONFIG_REFERENCE', 'Worker invocation requires an absolute binary without equals and NUL-free argv');
|
|
154
155
|
}
|
|
@@ -230,8 +231,15 @@ export function parseWorkerCommandArgs(args) {
|
|
|
230
231
|
workdir: 'workdir', 'final-output': 'final_output', transport: 'transport', format: 'format' };
|
|
231
232
|
const result = {};
|
|
232
233
|
let json = false;
|
|
234
|
+
let premiumAuthorized = false;
|
|
233
235
|
for (let i = 0; i < args.length; i++) {
|
|
234
236
|
const token = args[i];
|
|
237
|
+
if (token === '--authorize-premium') {
|
|
238
|
+
if (premiumAuthorized)
|
|
239
|
+
throw new Error('Duplicate --authorize-premium');
|
|
240
|
+
premiumAuthorized = true;
|
|
241
|
+
continue;
|
|
242
|
+
}
|
|
235
243
|
if (token === '--json') {
|
|
236
244
|
if (json)
|
|
237
245
|
throw new Error('Duplicate --json');
|
|
@@ -266,7 +274,7 @@ export function parseWorkerCommandArgs(args) {
|
|
|
266
274
|
throw new Error('Unsupported transport');
|
|
267
275
|
if (result.format && !['shell', 'json'].includes(result.format))
|
|
268
276
|
throw new Error('Unsupported renderer; use POSIX shell or JSON');
|
|
269
|
-
return result;
|
|
277
|
+
return { ...result, ...(premiumAuthorized ? { authority: { premiumAuthorized: true, maxAutoTier: 3 } } : {}) };
|
|
270
278
|
}
|
|
271
279
|
const bytesDigest = (bytes) => `sha256:${createHash('sha256').update(bytes).digest('hex')}`;
|
|
272
280
|
export async function inspectWorkerPath(filename, kind) {
|
|
@@ -324,6 +332,14 @@ async function readBrief(filename) {
|
|
|
324
332
|
await handle.close();
|
|
325
333
|
}
|
|
326
334
|
}
|
|
335
|
+
/** Structured root-check failure; only these explicit path details are public. */
|
|
336
|
+
export class WorkerPathScopeError extends WorkerPolicyError {
|
|
337
|
+
pointer;
|
|
338
|
+
constructor(key, filename, roots) {
|
|
339
|
+
super('OG_CONFIG_REFERENCE', `${filename} must be inside the worker-writable ${roots.length === 1 ? 'root' : 'roots'} ${roots.join(', ')}.`);
|
|
340
|
+
this.pointer = key === 'briefPath' ? '/request/brief' : '/request/finalOutput';
|
|
341
|
+
}
|
|
342
|
+
}
|
|
327
343
|
/** Re-resolve saved JSON through the same trusted owners; saved argv is never authority. */
|
|
328
344
|
export async function revalidateWorkerInvocationPlan(saved, snapshot, drivers, now = new Date().toISOString()) {
|
|
329
345
|
if (!saved.request || saved.mode !== 'direct' || saved.status !== 'eligible'
|
|
@@ -350,6 +366,8 @@ export async function resolveWorkerInvocation(snapshot, request, drivers, now =
|
|
|
350
366
|
let failureCode = 'OG_CONFIG_REFERENCE';
|
|
351
367
|
let plan;
|
|
352
368
|
try {
|
|
369
|
+
if (!path.isAbsolute(request.brief))
|
|
370
|
+
throw new WorkerPolicyError('OG_CONFIG_REFERENCE', '--brief must be an absolute path; relative paths are not resolved against cwd or --workdir.');
|
|
353
371
|
const bytes = await readBrief(request.brief);
|
|
354
372
|
const briefDigest = bytes === null ? null : bytesDigest(bytes);
|
|
355
373
|
if (expected && expected.briefDigest !== briefDigest)
|
|
@@ -364,7 +382,7 @@ export async function resolveWorkerInvocation(snapshot, request, drivers, now =
|
|
|
364
382
|
}
|
|
365
383
|
}
|
|
366
384
|
plan = resolveWorkerPlan(snapshot, { role: request.role, taskClass: request.task, group: request.group,
|
|
367
|
-
transport: request.transport, now, expectedDigests: expected?.digests,
|
|
385
|
+
transport: request.transport, authority: request.authority, now, expectedDigests: expected?.digests,
|
|
368
386
|
...(brief ? { dataClass: brief.intent.dataClass, member: brief.intent.pins.member,
|
|
369
387
|
model: brief.intent.pins.model, effort: brief.intent.pins.effort?.value, ceilings: {
|
|
370
388
|
...brief.intent.limits, costUsd: brief.intent.limits.costUsd ?? undefined
|
|
@@ -442,7 +460,7 @@ export async function resolveWorkerInvocation(snapshot, request, drivers, now =
|
|
|
442
460
|
throw new Error('MCP server/tool is not registered and allowed by the current MCP profile');
|
|
443
461
|
}
|
|
444
462
|
}
|
|
445
|
-
const controls = requiredWorkerControls({ policy: plan.policy, permissions: tuple.permissions, effort: tuple.effort,
|
|
463
|
+
const controls = isOperatorQualifiedWorkerAdapter(adapter) ? (healthConfig?.requireStepCap ? ['stepCap'] : []) : requiredWorkerControls({ policy: plan.policy, permissions: tuple.permissions, effort: tuple.effort,
|
|
446
464
|
requiredControls: healthConfig?.requireStepCap ? ['stepCap'] : [] });
|
|
447
465
|
pointer = `/parallelism/clis/${tuple.cli}/invocationProfile`;
|
|
448
466
|
failureCode = 'OG_ADAPTER_UNQUALIFIED';
|
|
@@ -469,9 +487,8 @@ export async function resolveWorkerInvocation(snapshot, request, drivers, now =
|
|
|
469
487
|
readiness: bytes !== null && workspaceExists && outputParentsExist ? 'launchable' : 'preparatory', briefDigest,
|
|
470
488
|
limits, maxOutputBytes: adapter.invocation.maxOutputBytes ?? 10485760,
|
|
471
489
|
effectiveCaps: tuple.effectiveMaxParallel === null ? {} : { parallel: tuple.effectiveMaxParallel },
|
|
472
|
-
controlEvidence: controls.map(name => profile.controls[name].evidence),
|
|
473
|
-
health: effectiveHealth,
|
|
474
|
-
};
|
|
490
|
+
controlEvidence: isOperatorQualifiedWorkerAdapter(adapter) ? [adapter.qualification.evidenceRef, ...controls.map(name => profile.controls[name].evidence)] : controls.map(name => profile.controls[name].evidence),
|
|
491
|
+
health: effectiveHealth, };
|
|
475
492
|
const invocationQualification = { ...qualification, now: Date.parse(now),
|
|
476
493
|
policy: plan.policy, permissions: tuple.permissions, role: request.role, modelObservation: observation,
|
|
477
494
|
expectedDigests: { policyDigest, catalogDigest: plan.digests.catalogDigest, profileDigest: plan.digests.profileDigest, briefDigest },
|
|
@@ -520,8 +537,10 @@ export async function resolveWorkerInvocation(snapshot, request, drivers, now =
|
|
|
520
537
|
return plan;
|
|
521
538
|
}
|
|
522
539
|
}
|
|
523
|
-
/** Public diagnostics contain fixed summaries
|
|
540
|
+
/** Public diagnostics contain fixed summaries or explicit typed request-path details. */
|
|
524
541
|
export function workerInvocationDiagnostic(error, pointer, fallback = 'OG_CONFIG_REFERENCE') {
|
|
542
|
+
if (error instanceof WorkerPathScopeError)
|
|
543
|
+
return { code: error.code, pointer: error.pointer, message: error.message };
|
|
525
544
|
const code = error instanceof WorkerPolicyError ? error.code : fallback;
|
|
526
545
|
const messages = {
|
|
527
546
|
OG_CONFIG_REFERENCE: 'Invalid request or configuration reference; check the paths and settings.',
|
|
@@ -529,10 +548,11 @@ export function workerInvocationDiagnostic(error, pointer, fallback = 'OG_CONFIG
|
|
|
529
548
|
OG_MODEL_UNAPPROVED: 'The selected model lacks current approved observation evidence.',
|
|
530
549
|
OG_EFFORT_DENIED: 'The selected effort is denied by the resolved worker policy.',
|
|
531
550
|
OG_DATA_POLICY: 'The selected model does not satisfy the resolved data policy.',
|
|
532
|
-
OG_ADAPTER_UNQUALIFIED: 'The installation or invocation could not be revalidated.
|
|
551
|
+
OG_ADAPTER_UNQUALIFIED: 'The installation or invocation could not be revalidated. Run aiwg doctor --probe-workers --qualify to qualify this workspace.',
|
|
533
552
|
OG_POLICY_RELAXATION: 'The request would relax the resolved worker policy.',
|
|
534
553
|
OG_BUDGET_UNMEASURABLE: 'The requested worker budget cannot be enforced.',
|
|
535
554
|
};
|
|
536
|
-
return { code, pointer, message:
|
|
555
|
+
return { code, pointer, message: error instanceof WorkerPolicyError && error.message === '--brief must be an absolute path; relative paths are not resolved against cwd or --workdir.'
|
|
556
|
+
? error.message : messages[code] };
|
|
537
557
|
}
|
|
538
558
|
//# sourceMappingURL=worker-invocation.js.map
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/** Conductor-side stdin framing shared by the shell renderer and the one-shot launcher. */
|
|
2
|
+
export const WORKER_STDIN_FRAME_MAX_BRIEF_BYTES: number;
|
|
3
|
+
export const WORKER_STDIN_FRAME_MAX_BYTES: number;
|
|
4
|
+
export function recordedWorkerStdinBytes(input: {
|
|
5
|
+
filename: string; workspace: string; cli: string; adapterId: string; scopeDigest: string; briefDigest: string;
|
|
6
|
+
storePath: string; storeDigest: string; policy?: import('../models/types.js').WorkerSelectionPolicy;
|
|
7
|
+
}): Promise<Buffer | null>;
|
|
8
|
+
export function workerStdinDocument(input: { brief: string | Buffer; model: string; cwd: string }): string;
|
|
9
|
+
export function workerStdinBytes(invocation: { stdin: 'closed' | 'brief-text' | 'brief-json' | 'adapter-frame'; cwd?: string;
|
|
10
|
+
selected?: { model?: string } }, brief: string | Buffer, adapter?: { buildWorkerStdinFrame?(brief: string | Buffer): string | Uint8Array }): Buffer | null;
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { resolveImportLimits } from './import-limits.js';
|
|
1
2
|
import { ClaudeSessionAdapter } from './adapters/claude.js';
|
|
2
3
|
import { CodexSessionAdapter } from './adapters/codex.js';
|
|
3
4
|
import { CopilotSessionAdapter } from './adapters/copilot.js';
|
|
@@ -17,27 +18,30 @@ import { WarpSessionAdapter } from './adapters/warp.js';
|
|
|
17
18
|
import { DevinDesktopSessionAdapter } from './adapters/windsurf.js';
|
|
18
19
|
import { GenericSessionInterchangeAdapter } from './adapters/generic.js';
|
|
19
20
|
import { SessionSourceAdapterRegistry } from './discovery.js';
|
|
20
|
-
export function createSessionAdapterRegistry() {
|
|
21
|
+
export function createSessionAdapterRegistry(limits) {
|
|
22
|
+
limits = { ...resolveImportLimits(undefined, {
|
|
23
|
+
maxRecordBytes: limits?.maxRecordBytes, maxSourceBytes: limits?.maxTotalBytes,
|
|
24
|
+
}), ...limits };
|
|
21
25
|
const registry = new SessionSourceAdapterRegistry();
|
|
22
26
|
for (const adapter of [
|
|
23
|
-
new ClaudeSessionAdapter(),
|
|
24
|
-
new CodexSessionAdapter(),
|
|
25
|
-
new CopilotSessionAdapter(),
|
|
26
|
-
new CursorSessionAdapter(),
|
|
27
|
-
new FactorySessionAdapter(),
|
|
28
|
-
new HermesSessionAdapter(),
|
|
29
|
-
new OpenCodeSessionAdapter(),
|
|
30
|
-
new OpenClawSessionAdapter(),
|
|
31
|
-
new OpenHumanSessionAdapter(),
|
|
32
|
-
new GrokbotSessionAdapter(),
|
|
33
|
-
new GrokBuildSessionAdapter(),
|
|
34
|
-
new MuseSessionAdapter(),
|
|
35
|
-
new PiSessionAdapter(),
|
|
36
|
-
new OmpSessionAdapter(),
|
|
37
|
-
new DeepSeekHarnessSessionAdapter(),
|
|
38
|
-
new WarpSessionAdapter(),
|
|
39
|
-
new DevinDesktopSessionAdapter(),
|
|
40
|
-
new GenericSessionInterchangeAdapter(),
|
|
27
|
+
new ClaudeSessionAdapter(limits),
|
|
28
|
+
new CodexSessionAdapter(limits),
|
|
29
|
+
new CopilotSessionAdapter(limits),
|
|
30
|
+
new CursorSessionAdapter(limits),
|
|
31
|
+
new FactorySessionAdapter(limits),
|
|
32
|
+
new HermesSessionAdapter(limits),
|
|
33
|
+
new OpenCodeSessionAdapter(limits),
|
|
34
|
+
new OpenClawSessionAdapter(limits),
|
|
35
|
+
new OpenHumanSessionAdapter(limits),
|
|
36
|
+
new GrokbotSessionAdapter(limits),
|
|
37
|
+
new GrokBuildSessionAdapter(limits),
|
|
38
|
+
new MuseSessionAdapter(limits),
|
|
39
|
+
new PiSessionAdapter(limits),
|
|
40
|
+
new OmpSessionAdapter(limits),
|
|
41
|
+
new DeepSeekHarnessSessionAdapter(limits),
|
|
42
|
+
new WarpSessionAdapter(limits),
|
|
43
|
+
new DevinDesktopSessionAdapter(limits),
|
|
44
|
+
new GenericSessionInterchangeAdapter(limits),
|
|
41
45
|
])
|
|
42
46
|
registry.register(adapter);
|
|
43
47
|
return registry;
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { opendir } from 'node:fs/promises';
|
|
2
2
|
import { basename, extname, resolve } from 'node:path';
|
|
3
3
|
import { z } from 'zod';
|
|
4
|
-
import { SessionContractError, assertSupportedSchemaMajor, sha256, } from '../contracts.js';
|
|
4
|
+
import { schemaRejectionDetail, schemaIssueDetail, SessionContractError, assertSupportedSchemaMajor, sha256, } from '../contracts.js';
|
|
5
5
|
import { redactSourceLocator } from '../discovery.js';
|
|
6
|
-
import { readBoundedJson,
|
|
6
|
+
import { readBoundedJson, streamBoundedJsonLines, } from '../readers.js';
|
|
7
7
|
export const CLAUDE_ADAPTER_VERSION = '1.1.0';
|
|
8
8
|
export const CLAUDE_TRANSCRIPT_SCHEMA_VERSION = '1.0.0';
|
|
9
9
|
/** AIWG's own understanding of the layout it supports; Claude web/account
|
|
@@ -101,7 +101,7 @@ export class ClaudeSessionAdapter {
|
|
|
101
101
|
for await (const locator of discoverJsonl(resolve(root), this.discoveryLimits.maxDepth)) {
|
|
102
102
|
emitted += 1;
|
|
103
103
|
if (emitted > this.discoveryLimits.maxFiles) {
|
|
104
|
-
throw new SessionContractError('RESOURCE_LIMIT_EXCEEDED', 'Claude source discovery exceeded the authorized file limit');
|
|
104
|
+
throw new SessionContractError('RESOURCE_LIMIT_EXCEEDED', 'Claude source discovery exceeded the authorized file limit', { limit: 'maxFiles', configured: this.discoveryLimits.maxFiles, observed: emitted });
|
|
105
105
|
}
|
|
106
106
|
yield {
|
|
107
107
|
provider: 'claude',
|
|
@@ -112,12 +112,19 @@ export class ClaudeSessionAdapter {
|
|
|
112
112
|
}
|
|
113
113
|
}
|
|
114
114
|
async inspect(source) {
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
115
|
+
if (source.locatorClass === 'claude-web-export-json') {
|
|
116
|
+
const parsed = await this.readWebExportSource(source);
|
|
117
|
+
return {
|
|
118
|
+
sourceSchemaVersion: parsed.schemaVersion,
|
|
119
|
+
consistency: parsed.consistency,
|
|
120
|
+
operationalState: 'available',
|
|
121
|
+
};
|
|
122
|
+
}
|
|
123
|
+
const records = this.readSource(source);
|
|
124
|
+
let result = await records.next();
|
|
125
|
+
while (!result.done)
|
|
126
|
+
result = await records.next();
|
|
127
|
+
return result.value;
|
|
121
128
|
}
|
|
122
129
|
async *stream(source, cursor) {
|
|
123
130
|
if (source.locatorClass === 'claude-web-export-json') {
|
|
@@ -127,69 +134,57 @@ export class ClaudeSessionAdapter {
|
|
|
127
134
|
yield record;
|
|
128
135
|
return;
|
|
129
136
|
}
|
|
137
|
+
yield* this.readSource(source, cursor);
|
|
138
|
+
}
|
|
139
|
+
async *readSource(source, cursor) {
|
|
130
140
|
const start = parseRecordCursor(cursor?.value);
|
|
131
141
|
const input = await streamBoundedJsonLines({
|
|
132
142
|
selectedPath: source.locator,
|
|
133
143
|
allowedRoots: source.authorizedScope.allowedRoots,
|
|
134
144
|
}, { consistency: 'provisional', limits: this.limits });
|
|
135
|
-
|
|
145
|
+
let hookSource = isHookLocator(source.locator) ? true : undefined;
|
|
136
146
|
let outputIndex = 0;
|
|
137
147
|
let sawRecord = false;
|
|
148
|
+
let complete = false;
|
|
138
149
|
let schemaVersion = null;
|
|
139
150
|
for await (const line of input) {
|
|
140
151
|
sawRecord = true;
|
|
141
|
-
const value = line.value
|
|
152
|
+
const value = line.value && typeof line.value === 'object'
|
|
153
|
+
? line.value : {};
|
|
142
154
|
const currentSchema = typeof value.schemaVersion === 'string'
|
|
143
155
|
? value.schemaVersion : CLAUDE_TRANSCRIPT_SCHEMA_VERSION;
|
|
144
156
|
if (schemaVersion && currentSchema !== schemaVersion) {
|
|
145
|
-
throw new SessionContractError('SCHEMA_DRIFT', 'Claude source declares mixed schema versions');
|
|
157
|
+
throw new SessionContractError('SCHEMA_DRIFT', 'Claude source declares mixed schema versions', schemaIssueDetail('schemaVersion'));
|
|
146
158
|
}
|
|
147
159
|
schemaVersion = currentSchema;
|
|
148
160
|
assertSupportedSchemaMajor(schemaVersion);
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
161
|
+
hookSource ??= isHookRecord(line.value);
|
|
162
|
+
const normalized = hookSource
|
|
163
|
+
? normalizeHooks([line])
|
|
164
|
+
: normalizeTranscript([line], source.locator);
|
|
165
|
+
complete ||= normalized.complete;
|
|
166
|
+
for (const record of normalized.records) {
|
|
153
167
|
if (outputIndex++ >= start)
|
|
154
168
|
yield record;
|
|
155
169
|
}
|
|
156
170
|
}
|
|
157
171
|
if (!sawRecord && !input.incompleteTail) {
|
|
158
|
-
throw new SessionContractError('MALFORMED_SOURCE', 'Claude JSONL source is empty');
|
|
172
|
+
throw new SessionContractError('MALFORMED_SOURCE', 'Claude JSONL source is empty', schemaIssueDetail('<root>'));
|
|
159
173
|
}
|
|
160
|
-
}
|
|
161
|
-
async readSource(source) {
|
|
162
|
-
if (source.locatorClass === 'claude-web-export-json') {
|
|
163
|
-
return this.readWebExportSource(source);
|
|
164
|
-
}
|
|
165
|
-
const result = await readBoundedJsonLines({
|
|
166
|
-
selectedPath: source.locator,
|
|
167
|
-
allowedRoots: source.authorizedScope.allowedRoots,
|
|
168
|
-
}, { consistency: 'provisional', limits: this.limits });
|
|
169
|
-
if (result.records.length === 0 && !result.incompleteTail) {
|
|
170
|
-
throw new SessionContractError('MALFORMED_SOURCE', 'Claude JSONL source is empty');
|
|
171
|
-
}
|
|
172
|
-
const hookSource = isHookLocator(source.locator)
|
|
173
|
-
|| result.records.some((record) => isHookRecord(record.value));
|
|
174
|
-
const normalized = hookSource
|
|
175
|
-
? normalizeHooks(result.records)
|
|
176
|
-
: normalizeTranscript(result.records, source.locator);
|
|
177
|
-
const schemaVersion = declaredSchemaVersion(result.records);
|
|
178
|
-
assertSupportedSchemaMajor(schemaVersion);
|
|
179
174
|
return {
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
175
|
+
sourceSchemaVersion: schemaVersion ?? CLAUDE_TRANSCRIPT_SCHEMA_VERSION,
|
|
176
|
+
consistency: complete ? 'complete' : 'provisional',
|
|
177
|
+
operationalState: 'available',
|
|
183
178
|
};
|
|
184
179
|
}
|
|
185
180
|
async readWebExportSource(source) {
|
|
186
181
|
const { value } = await readBoundedJson({ selectedPath: source.locator, allowedRoots: source.authorizedScope.allowedRoots }, this.limits);
|
|
187
182
|
const parsed = ClaudeWebExportSchema.safeParse(value);
|
|
188
183
|
if (!parsed.success) {
|
|
189
|
-
throw new SessionContractError('MALFORMED_SOURCE', 'Claude web/account export is not a recognized conversations.json layout');
|
|
184
|
+
throw new SessionContractError('MALFORMED_SOURCE', 'Claude web/account export is not a recognized conversations.json layout', schemaRejectionDetail(parsed.error));
|
|
190
185
|
}
|
|
191
186
|
if (parsed.data.length === 0) {
|
|
192
|
-
throw new SessionContractError('MALFORMED_SOURCE', 'Claude web/account export is empty');
|
|
187
|
+
throw new SessionContractError('MALFORMED_SOURCE', 'Claude web/account export is empty', schemaIssueDetail('<root>'));
|
|
193
188
|
}
|
|
194
189
|
return {
|
|
195
190
|
records: normalizeWebExport(parsed.data),
|
|
@@ -263,7 +258,7 @@ function normalizeTranscript(records, locator) {
|
|
|
263
258
|
for (const record of records) {
|
|
264
259
|
const parsed = ClaudeRecordSchema.safeParse(record.value);
|
|
265
260
|
if (!parsed.success) {
|
|
266
|
-
throw new SessionContractError('MALFORMED_SOURCE', 'Claude transcript record is malformed');
|
|
261
|
+
throw new SessionContractError('MALFORMED_SOURCE', 'Claude transcript record is malformed', schemaRejectionDetail(parsed.error));
|
|
267
262
|
}
|
|
268
263
|
const value = parsed.data;
|
|
269
264
|
const embeddedSessionId = value.sessionId ?? value.session_id;
|
|
@@ -297,7 +292,7 @@ function normalizeHooks(records) {
|
|
|
297
292
|
for (const record of records) {
|
|
298
293
|
const parsed = ClaudeHookSchema.safeParse(record.value);
|
|
299
294
|
if (!parsed.success) {
|
|
300
|
-
throw new SessionContractError('MALFORMED_SOURCE', 'Claude lifecycle hook record is malformed');
|
|
295
|
+
throw new SessionContractError('MALFORMED_SOURCE', 'Claude lifecycle hook record is malformed', schemaRejectionDetail(parsed.error));
|
|
301
296
|
}
|
|
302
297
|
const hook = parsed.data;
|
|
303
298
|
complete ||= hook.hook_event_name === 'SessionEnd';
|
|
@@ -464,21 +459,11 @@ async function* discoverJsonl(root, maxDepth) {
|
|
|
464
459
|
pending.push({ path, depth: current.depth + 1 });
|
|
465
460
|
}
|
|
466
461
|
}
|
|
467
|
-
function declaredSchemaVersion(records) {
|
|
468
|
-
const declared = records
|
|
469
|
-
.map((record) => {
|
|
470
|
-
if (!record.value || typeof record.value !== 'object' || Array.isArray(record.value))
|
|
471
|
-
return undefined;
|
|
472
|
-
return record.value.schemaVersion;
|
|
473
|
-
})
|
|
474
|
-
.find((value) => typeof value === 'string');
|
|
475
|
-
return declared ?? CLAUDE_TRANSCRIPT_SCHEMA_VERSION;
|
|
476
|
-
}
|
|
477
462
|
function parseRecordCursor(value) {
|
|
478
463
|
if (value === undefined || value === '')
|
|
479
464
|
return 0;
|
|
480
465
|
if (!/^\d+$/.test(value))
|
|
481
|
-
throw new SessionContractError('SCHEMA_DRIFT', 'Claude record cursor is invalid');
|
|
466
|
+
throw new SessionContractError('SCHEMA_DRIFT', 'Claude record cursor is invalid', schemaIssueDetail('cursor'));
|
|
482
467
|
return Number(value);
|
|
483
468
|
}
|
|
484
469
|
function hookNativeId(hook, sequence) {
|