@aiwg/cli 2026.10.1 → 2026.10.4
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/capability-matrix.yaml +270 -0
- package/agentic/code/providers/model-capabilities.v1.json +3183 -24
- package/bin/aiwg.mjs +135 -47
- package/dist/src/a2a/codecs.js +9 -0
- 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 +57 -18
- package/dist/src/artifacts/corpus-tools/snapshot.js +1 -1
- package/dist/src/artifacts/corpus-tools/vision-extract.js +107 -15
- 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 +285 -131
- package/dist/src/artifacts/index-files.js +132 -18
- package/dist/src/artifacts/index-preparation.js +65 -0
- package/dist/src/artifacts/index-refresh.js +576 -0
- package/dist/src/artifacts/index-worker.mjs +9 -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/repair.js +9 -4
- 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 +78 -12
- package/dist/src/cli/child-process-result.js +40 -0
- package/dist/src/cli/command-log.js +2 -3
- package/dist/src/cli/env.js +38 -16
- package/dist/src/cli/flag-parsing.js +236 -0
- 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 +218 -5
- package/dist/src/cli/handlers/diagnose.js +13 -5
- package/dist/src/cli/handlers/effect.js +4 -2
- package/dist/src/cli/handlers/evidence.js +3 -0
- package/dist/src/cli/handlers/feedback.js +14 -5
- 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 +248 -30
- package/dist/src/cli/handlers/lint.js +5 -0
- package/dist/src/cli/handlers/mc.js +23 -0
- package/dist/src/cli/handlers/models.js +169 -10
- package/dist/src/cli/handlers/ralph-launcher.js +2 -0
- package/dist/src/cli/handlers/ralph.js +3 -0
- package/dist/src/cli/handlers/refresh.js +28 -0
- package/dist/src/cli/handlers/regenerate.js +14 -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 +25 -11
- package/dist/src/cli/handlers/script-runner.js +19 -8
- package/dist/src/cli/handlers/session.js +406 -62
- package/dist/src/cli/handlers/sessions.js +243 -76
- package/dist/src/cli/handlers/setup-manifest.js +474 -79
- package/dist/src/cli/handlers/setup.js +180 -39
- package/dist/src/cli/handlers/steward.js +11 -0
- package/dist/src/cli/handlers/subcommands.js +60 -3
- package/dist/src/cli/handlers/team.js +18 -8
- package/dist/src/cli/handlers/uhp.js +3 -0
- package/dist/src/cli/handlers/use.js +307 -55
- package/dist/src/cli/handlers/utilities.js +125 -26
- package/dist/src/cli/handlers/version.js +8 -0
- package/dist/src/cli/prompt-utils.js +72 -0
- package/dist/src/cli/provider-resolution.js +11 -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 +349 -35
- package/dist/src/config/cli.js +256 -23
- package/dist/src/config/decision-config.js +106 -0
- package/dist/src/config/dispatch-thresholds-runtime.d.mts +8 -0
- package/dist/src/config/dispatch-thresholds-runtime.mjs +38 -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-health.mjs +14 -3
- 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 +38 -11
- package/dist/src/config/user-registry.js +23 -15
- package/dist/src/config/user-state.js +7 -0
- package/dist/src/decision/adapters/jev.js +75 -27
- package/dist/src/decision/ask.js +203 -43
- package/dist/src/decision/context-live-qualification.js +2 -2
- package/dist/src/decision/driver.js +14 -7
- 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 +25 -6
- 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 +15 -14
- package/dist/src/decision/heldout/contract.js +30 -7
- package/dist/src/decision/index.js +1 -0
- package/dist/src/decision/interop.js +60 -8
- package/dist/src/decision/jev-credentials.js +15 -1
- package/dist/src/decision/ledger.js +942 -0
- 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/decision/validate.js +6 -3
- package/dist/src/effects/dispatch-verifier.js +252 -0
- package/dist/src/effects/index.js +1 -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/features/installer.js +2 -2
- package/dist/src/flow/graph-metadata.js +5 -0
- package/dist/src/gates/providers/loader.js +64 -18
- package/dist/src/installation/manager-command.d.mts +18 -0
- package/dist/src/installation/manager-command.mjs +15 -3
- package/dist/src/installation/manager.d.mts +49 -0
- package/dist/src/installation/manager.mjs +95 -5
- 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 +366 -56
- 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 +620 -85
- package/dist/src/mcp/config-file.d.mts +28 -0
- package/dist/src/mcp/config-file.mjs +279 -0
- package/dist/src/mcp/config-layers.d.mts +36 -0
- package/dist/src/mcp/config-layers.mjs +348 -0
- package/dist/src/mcp/credentials.d.mts +51 -0
- package/dist/src/mcp/credentials.mjs +484 -0
- package/dist/src/mcp/grok-build-config.d.mts +6 -0
- package/dist/src/mcp/grok-build-config.mjs +17 -27
- package/dist/src/mcp/helpers.mjs +109 -4
- 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/omp-config.mjs +50 -29
- package/dist/src/mcp/profiles.js +97 -23
- package/dist/src/mcp/profiles.mjs +99 -27
- package/dist/src/mcp/registry.js +248 -131
- package/dist/src/mcp/registry.mjs +169 -100
- 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 +127 -82
- 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-string.mjs +9 -0
- package/dist/src/mcp/toml-strip-mcp.d.mts +1 -0
- package/dist/src/mcp/toml-strip-mcp.mjs +135 -0
- package/dist/src/mcp/tool-filters.d.mts +46 -0
- package/dist/src/mcp/tool-filters.mjs +357 -0
- package/dist/src/mcp/tools/agentic-sandbox.mjs +3 -1
- package/dist/src/mcp/tools/decision.mjs +22 -3
- package/dist/src/mcp/tools/discovery.mjs +62 -55
- package/dist/src/mcp/tools/orchestration.mjs +50 -2
- package/dist/src/mcp/tools/subsystems.mjs +39 -8
- package/dist/src/mcp/tools/worker-invoke.mjs +2856 -0
- package/dist/src/mcp/tools/worker-shell-control.mjs +289 -0
- package/dist/src/mcp/tools/worker-stdin-runtime.mjs +79 -0
- package/dist/src/memory/project-registry.js +2 -2
- package/dist/src/mission-protocol/codecs.js +647 -1
- package/dist/src/mission-protocol/types.js +110 -0
- package/dist/src/mission-protocol/worker-status.js +2 -0
- package/dist/src/models/config-loader.js +76 -14
- package/dist/src/models/grok-build-models.js +93 -41
- package/dist/src/models/model-capabilities.v1.json +3183 -24
- package/dist/src/models/model-discovery.js +931 -67
- package/dist/src/models/provider-policy.js +719 -11
- package/dist/src/models/qualification-digest.d.mts +2 -0
- package/dist/src/models/qualification-digest.mjs +17 -0
- package/dist/src/models/resolver.js +261 -0
- package/dist/src/models/worker-direct-readiness.js +550 -0
- package/dist/src/models/worker-dispatch-offer.js +169 -0
- package/dist/src/models/worker-health-readiness.js +144 -0
- package/dist/src/models/worker-installation.d.mts +39 -0
- package/dist/src/models/worker-installation.mjs +986 -0
- package/dist/src/models/wrapper-route.js +18 -0
- package/dist/src/ops/registry.js +9 -14
- package/dist/src/plugins/standalone-packager.js +4 -3
- package/dist/src/process/bounded-child-process.d.mts +84 -0
- package/dist/src/process/bounded-child-process.mjs +430 -0
- package/dist/src/process/cli-command.d.mts +16 -0
- package/dist/src/process/cli-command.mjs +75 -0
- package/dist/src/process/signal-child.d.mts +6 -0
- package/dist/src/process/signal-child.mjs +7 -0
- package/dist/src/providers/capability-matrix.js +8 -0
- package/dist/src/providers/capability-matrix.yaml +270 -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 +53 -23
- 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/provider-definitions.js +9 -1
- package/dist/src/providers/provider-definitions.mjs +9 -2
- 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/executor-registry.js +16 -24
- package/dist/src/serve/fleet-mission-conductor.js +9 -0
- package/dist/src/serve/mission-conductor.js +47 -12
- package/dist/src/serve/shared-host-scheduler.js +2 -0
- package/dist/src/serve/worker-invocation.js +558 -0
- package/dist/src/serve/worker-stdin-frame.d.mts +10 -0
- package/dist/src/serve/worker-stdin-frame.mjs +107 -0
- package/dist/src/sessions/adapter-registry.js +49 -0
- package/dist/src/sessions/adapters/claude.js +39 -54
- package/dist/src/sessions/adapters/codex.js +82 -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 +43 -9
- package/dist/src/sessions/adapters/grok-build.js +11 -11
- package/dist/src/sessions/adapters/grokbot-locator.js +111 -0
- package/dist/src/sessions/adapters/grokbot.js +434 -24
- package/dist/src/sessions/adapters/hermes.js +27 -29
- package/dist/src/sessions/adapters/muse-workspace-scan.js +128 -0
- package/dist/src/sessions/adapters/muse.js +200 -104
- 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 +30 -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 +25 -5
- package/dist/src/sessions/batch-import.js +72 -51
- package/dist/src/sessions/candidates.js +47 -11
- package/dist/src/sessions/contracts.js +75 -2
- package/dist/src/sessions/coverage-preflight.js +134 -0
- package/dist/src/sessions/discovery.js +3 -0
- package/dist/src/sessions/export-plan.js +4 -3
- package/dist/src/sessions/grok-build-cli.js +67 -5
- 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 +84 -46
- package/dist/src/sessions/index.js +2 -0
- package/dist/src/sessions/lifecycle.js +45 -0
- package/dist/src/sessions/policy.js +133 -25
- package/dist/src/sessions/readers.js +106 -53
- package/dist/src/sessions/refresh.js +106 -0
- package/dist/src/sessions/repository.js +199 -63
- package/dist/src/sessions/workspace-discovery.js +315 -88
- package/dist/src/sessions/workspace-matching.js +107 -0
- package/dist/src/skills/adapters/clawhub.js +10 -8
- package/dist/src/skills/adapters/openclaw.js +10 -7
- 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 +195 -14
- package/dist/src/smiths/context-pipeline/workspace-context.js +116 -9
- package/dist/src/smiths/hook-bridge/codex-translator.js +6 -5
- package/dist/src/smiths/mcpsmith/example.js +1 -1
- 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 +85 -31
- package/dist/src/storage/backends/fs.js +18 -76
- package/dist/src/storage/backends/logseq.js +68 -7
- package/dist/src/storage/backends/obsidian.js +1 -0
- package/dist/src/storage/fortemi-qualification-receipt.js +2 -2
- package/dist/src/testing/generators/test-code-generator.js +57 -30
- package/dist/src/tracker/forge-http.js +2 -1
- package/dist/src/uhp/client.js +11 -1
- package/dist/src/uhp/mission.js +5 -0
- package/dist/src/update/checker.d.mts +2 -0
- package/dist/src/update/checker.mjs +5 -5
- package/dist/src/update/notifier.mjs +54 -2
- 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/dist/src/writing/fidelity.js +18 -1
- package/package.json +32 -2
- package/schemas/mission-v1.schema.json +2429 -0
- package/schemas/models/model-catalog.v1.schema.json +301 -0
- package/schemas/models/model-config-compatibility.v1.schema.json +281 -0
- package/schemas/models/model-policy.v1.schema.json +14 -0
- package/schemas/models/provider-model-capabilities.v1.schema.json +1072 -0
- package/tools/_resolve-impl.mjs +39 -2
- package/tools/agents/deploy-agents.mjs +64 -23
- package/tools/agents/providers/base.mjs +153 -166
- 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/grokbot.mjs +11 -12
- package/tools/agents/providers/hermes.mjs +62 -49
- package/tools/agents/providers/omp.mjs +5 -2
- package/tools/agents/providers/openclaw-translator.mjs +19 -5
- 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 +360 -0
- package/tools/providers/omp-transport.mjs +194 -0
- package/tools/ralph-external/lib/claude-adapter.mjs +389 -0
- package/tools/ralph-external/lib/codex-adapter.mjs +432 -0
- package/tools/ralph-external/lib/consecutive-failure-circuit-breaker.mjs +1748 -0
- package/tools/ralph-external/lib/deepseek-harness-adapter.mjs +397 -0
- package/tools/ralph-external/lib/factory-adapter.mjs +503 -0
- package/tools/ralph-external/lib/launcher-recovery-evidence.mjs +55 -0
- package/tools/ralph-external/lib/muse-adapter.mjs +364 -0
- package/tools/ralph-external/lib/omp-adapter.mjs +315 -0
- package/tools/ralph-external/lib/opencode-adapter.mjs +575 -0
- package/tools/ralph-external/lib/openhuman-adapter.mjs +75 -0
- package/tools/ralph-external/lib/pi-adapter.mjs +329 -0
- package/tools/ralph-external/lib/provider-adapter.mjs +748 -0
- 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 +439 -0
- 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 +2916 -0
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Conductor-side stdin framing for resolved worker invocations (#2911).
|
|
3
|
+
*
|
|
4
|
+
* `stdin: 'brief-json'` means the worker reads one JSON params document on
|
|
5
|
+
* stdin, built by the conductor from the brief file and closed at EOF. The
|
|
6
|
+
* brief stays the source of truth and is never copied into argv, so prompt
|
|
7
|
+
* text cannot surface in /proc/<pid>/cmdline, unit properties or argv logs.
|
|
8
|
+
* The document is the OpenHuman agent.chat params shape (`message`,
|
|
9
|
+
* `model_override`, `cwd`; tinyhumansai/openhuman@216ea32
|
|
10
|
+
* crates/openhuman-core/src/agent/schemas.rs:97-105), consumed by
|
|
11
|
+
* `call --params-stdin`, which reads stdin to EOF (core/cli.rs:445-468).
|
|
12
|
+
*
|
|
13
|
+
* Shared by the #2887 shell renderer (as a pipeline stage) and the attached
|
|
14
|
+
* one-shot launcher (written to the child's stdin pipe).
|
|
15
|
+
*/
|
|
16
|
+
import { open } from 'node:fs/promises';
|
|
17
|
+
import { createHash } from 'node:crypto';
|
|
18
|
+
import { pathToFileURL } from 'node:url';
|
|
19
|
+
|
|
20
|
+
export const WORKER_STDIN_FRAME_MAX_BRIEF_BYTES = 262144;
|
|
21
|
+
export const WORKER_STDIN_FRAME_MAX_BYTES = 1048576;
|
|
22
|
+
|
|
23
|
+
/** @returns {string} the exact JSON document delivered on stdin. */
|
|
24
|
+
export function workerStdinDocument({ brief, model, cwd }) {
|
|
25
|
+
const text = Buffer.isBuffer(brief) ? new TextDecoder('utf-8', { fatal: true }).decode(brief) : brief;
|
|
26
|
+
if (typeof text !== 'string') throw new Error('brief-json framing requires brief text');
|
|
27
|
+
if (typeof model !== 'string' || !model || model.includes('\0')) throw new Error('brief-json framing requires an explicit model');
|
|
28
|
+
if (typeof cwd !== 'string' || !cwd.startsWith('/') || cwd.includes('\0')) throw new Error('brief-json framing requires an absolute workspace');
|
|
29
|
+
return JSON.stringify({ message: text, model_override: model, cwd });
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/** Stdin bytes for a resolved invocation: null (closed), the raw brief, or the framed document. */
|
|
33
|
+
export function workerStdinBytes(invocation, brief, adapter) {
|
|
34
|
+
if (invocation.stdin === 'closed') return null;
|
|
35
|
+
if (invocation.stdin === 'brief-text') return Buffer.isBuffer(brief) ? brief : Buffer.from(brief);
|
|
36
|
+
if (invocation.stdin === 'brief-json') {
|
|
37
|
+
return Buffer.from(workerStdinDocument({ brief, model: invocation.selected?.model, cwd: invocation.cwd }));
|
|
38
|
+
}
|
|
39
|
+
if (invocation.stdin === 'adapter-frame') {
|
|
40
|
+
if (typeof adapter?.buildWorkerStdinFrame !== 'function') throw new Error('Installed adapter stdin framer is required');
|
|
41
|
+
if (Buffer.byteLength(brief) > WORKER_STDIN_FRAME_MAX_BRIEF_BYTES) throw new Error('Brief exceeds the framing bound');
|
|
42
|
+
const frame = adapter.buildWorkerStdinFrame(brief);
|
|
43
|
+
if (typeof frame !== 'string' && !(frame instanceof Uint8Array)) throw new Error('Adapter stdin frame must be bytes or text');
|
|
44
|
+
if (Buffer.byteLength(frame) === 0) throw new Error('Adapter stdin frame must not be empty');
|
|
45
|
+
if (Buffer.byteLength(frame) > WORKER_STDIN_FRAME_MAX_BYTES) throw new Error('Adapter stdin frame exceeds byte bound');
|
|
46
|
+
return Buffer.from(frame);
|
|
47
|
+
}
|
|
48
|
+
throw new Error(`Unsupported worker stdin mode: ${invocation.stdin}`);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
async function readBounded(filename) {
|
|
52
|
+
const handle = await open(filename, 'r');
|
|
53
|
+
try {
|
|
54
|
+
const stat = await handle.stat();
|
|
55
|
+
if (!stat.isFile() || stat.size > WORKER_STDIN_FRAME_MAX_BRIEF_BYTES) throw new Error('Brief must be a bounded regular file');
|
|
56
|
+
const bytes = Buffer.alloc(WORKER_STDIN_FRAME_MAX_BRIEF_BYTES + 1);
|
|
57
|
+
let length = 0;
|
|
58
|
+
while (length < bytes.length) {
|
|
59
|
+
const { bytesRead } = await handle.read(bytes, length, bytes.length - length, null);
|
|
60
|
+
if (!bytesRead) break;
|
|
61
|
+
length += bytesRead;
|
|
62
|
+
}
|
|
63
|
+
if (length > WORKER_STDIN_FRAME_MAX_BRIEF_BYTES) throw new Error('Brief exceeds the framing bound');
|
|
64
|
+
return bytes.subarray(0, length);
|
|
65
|
+
} finally { await handle.close(); }
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/** Bound host authority only; workspace is an execution scope, never a config source. */
|
|
69
|
+
export async function recordedWorkerStdinBytes({ filename, workspace, cli, adapterId, scopeDigest, briefDigest,
|
|
70
|
+
storePath, storeDigest, policy }) {
|
|
71
|
+
if (!filename?.startsWith('/') || !storePath?.startsWith('/')
|
|
72
|
+
|| !/^sha256:[a-f0-9]{64}$/.test(storeDigest ?? '')) throw new Error('Invalid adapter stdin framing request');
|
|
73
|
+
const { loadRecordedWorkerInstallations } = await import('../models/worker-installation.mjs');
|
|
74
|
+
const { loadProviderModelCapabilities } = await import('../models/provider-policy.js');
|
|
75
|
+
const { drivers } = await loadRecordedWorkerInstallations({ registry: loadProviderModelCapabilities(),
|
|
76
|
+
cwd: workspace, policy, storePath, storeDigest });
|
|
77
|
+
const driver = drivers[cli];
|
|
78
|
+
if (!driver || driver.qualification.adapterId !== adapterId
|
|
79
|
+
|| driver.qualification.adapter.invocation.stdin !== 'adapter-frame'
|
|
80
|
+
|| driver.qualification.installation?.evidence?.scopeDigest !== scopeDigest) throw new Error('Adapter stdin binding changed');
|
|
81
|
+
const brief = await readBounded(filename);
|
|
82
|
+
if (`sha256:${createHash('sha256').update(brief).digest('hex')}` !== briefDigest) throw new Error('Adapter stdin brief changed');
|
|
83
|
+
return workerStdinBytes({ stdin: 'adapter-frame' }, brief, driver);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
// Pipeline stage: `worker-stdin-frame.mjs BRIEF_PATH MODEL CWD`. Only the
|
|
87
|
+
// brief path, never its content, appears on this command line.
|
|
88
|
+
if (process.argv[1] && import.meta.url === pathToFileURL(process.argv[1]).href) {
|
|
89
|
+
const [briefPath, model, cwd] = process.argv.slice(2);
|
|
90
|
+
try {
|
|
91
|
+
if (briefPath === '--adapter-frame') {
|
|
92
|
+
const [filename, workspace, cli, adapterId, scopeDigest, briefDigest, storePath, storeDigest, policyJson] = process.argv.slice(3);
|
|
93
|
+
if (process.argv.length !== 12) throw new Error('Invalid adapter stdin framing request');
|
|
94
|
+
// Reuse the recorded-installation loader; no module path or code supplied
|
|
95
|
+
// by a brief is ever imported. The conductor binds store bytes and policy;
|
|
96
|
+
// never resolve configuration from the worker-writable workspace.
|
|
97
|
+
process.stdout.write(await recordedWorkerStdinBytes({ filename, workspace, cli, adapterId, scopeDigest, briefDigest,
|
|
98
|
+
storePath, storeDigest, policy: JSON.parse(policyJson) ?? undefined }));
|
|
99
|
+
} else {
|
|
100
|
+
if (process.argv.length !== 5 || !briefPath?.startsWith('/')) throw new Error('usage: worker-stdin-frame.mjs BRIEF_PATH MODEL CWD');
|
|
101
|
+
process.stdout.write(workerStdinDocument({ brief: await readBounded(briefPath), model, cwd }));
|
|
102
|
+
}
|
|
103
|
+
} catch (error) {
|
|
104
|
+
process.stderr.write(`worker-stdin-frame: ${error?.message ?? error}\n`);
|
|
105
|
+
process.exitCode = 2;
|
|
106
|
+
}
|
|
107
|
+
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { resolveImportLimits } from './import-limits.js';
|
|
2
|
+
import { ClaudeSessionAdapter } from './adapters/claude.js';
|
|
3
|
+
import { CodexSessionAdapter } from './adapters/codex.js';
|
|
4
|
+
import { CopilotSessionAdapter } from './adapters/copilot.js';
|
|
5
|
+
import { CursorSessionAdapter } from './adapters/cursor.js';
|
|
6
|
+
import { FactorySessionAdapter } from './adapters/factory.js';
|
|
7
|
+
import { HermesSessionAdapter } from './adapters/hermes.js';
|
|
8
|
+
import { OpenCodeSessionAdapter } from './adapters/opencode.js';
|
|
9
|
+
import { OpenClawSessionAdapter } from './adapters/openclaw.js';
|
|
10
|
+
import { OpenHumanSessionAdapter } from './adapters/openhuman.js';
|
|
11
|
+
import { GrokbotSessionAdapter } from './adapters/grokbot.js';
|
|
12
|
+
import { GrokBuildSessionAdapter } from './adapters/grok-build.js';
|
|
13
|
+
import { MuseSessionAdapter } from './adapters/muse.js';
|
|
14
|
+
import { PiSessionAdapter } from './adapters/pi.js';
|
|
15
|
+
import { OmpSessionAdapter } from './adapters/omp.js';
|
|
16
|
+
import { DeepSeekHarnessSessionAdapter } from './adapters/deepseek-harness.js';
|
|
17
|
+
import { WarpSessionAdapter } from './adapters/warp.js';
|
|
18
|
+
import { DevinDesktopSessionAdapter } from './adapters/windsurf.js';
|
|
19
|
+
import { GenericSessionInterchangeAdapter } from './adapters/generic.js';
|
|
20
|
+
import { SessionSourceAdapterRegistry } from './discovery.js';
|
|
21
|
+
export function createSessionAdapterRegistry(limits) {
|
|
22
|
+
limits = { ...resolveImportLimits(undefined, {
|
|
23
|
+
maxRecordBytes: limits?.maxRecordBytes, maxSourceBytes: limits?.maxTotalBytes,
|
|
24
|
+
}), ...limits };
|
|
25
|
+
const registry = new SessionSourceAdapterRegistry();
|
|
26
|
+
for (const adapter of [
|
|
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),
|
|
45
|
+
])
|
|
46
|
+
registry.register(adapter);
|
|
47
|
+
return registry;
|
|
48
|
+
}
|
|
49
|
+
//# sourceMappingURL=adapter-registry.js.map
|
|
@@ -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) {
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { opendir } from 'node:fs/promises';
|
|
2
2
|
import { basename, resolve } from 'node:path';
|
|
3
3
|
import { z } from 'zod';
|
|
4
|
-
import { SessionContractError, assertSupportedSchemaMajor, } from '../contracts.js';
|
|
5
|
-
import {
|
|
4
|
+
import { schemaRejectionDetail, schemaIssueDetail, SessionContractError, assertSupportedSchemaMajor, } from '../contracts.js';
|
|
5
|
+
import { streamBoundedJsonLines, } from '../readers.js';
|
|
6
6
|
export const CODEX_ADAPTER_VERSION = '1.0.0';
|
|
7
7
|
export const CODEX_SOURCE_SCHEMA_VERSION = '1.0.0';
|
|
8
8
|
const AppServerEnvelopeSchema = z.object({
|
|
@@ -57,7 +57,7 @@ export class CodexSessionAdapter {
|
|
|
57
57
|
for (const root of [...scope.allowedRoots].sort()) {
|
|
58
58
|
for await (const locator of discoverJsonl(resolve(root), this.discoveryLimits.maxDepth)) {
|
|
59
59
|
if (++emitted > this.discoveryLimits.maxFiles) {
|
|
60
|
-
throw new SessionContractError('RESOURCE_LIMIT_EXCEEDED', 'Codex source discovery exceeded the authorized file limit');
|
|
60
|
+
throw new SessionContractError('RESOURCE_LIMIT_EXCEEDED', 'Codex source discovery exceeded the authorized file limit', { limit: 'maxFiles', configured: this.discoveryLimits.maxFiles, observed: emitted });
|
|
61
61
|
}
|
|
62
62
|
yield {
|
|
63
63
|
provider: 'codex',
|
|
@@ -70,30 +70,34 @@ export class CodexSessionAdapter {
|
|
|
70
70
|
}
|
|
71
71
|
}
|
|
72
72
|
async inspect(source) {
|
|
73
|
-
const
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
};
|
|
73
|
+
const records = this.readSource(source);
|
|
74
|
+
let result = await records.next();
|
|
75
|
+
while (!result.done)
|
|
76
|
+
result = await records.next();
|
|
77
|
+
return result.value;
|
|
79
78
|
}
|
|
80
79
|
async *stream(source, cursor) {
|
|
80
|
+
yield* this.readSource(source, cursor);
|
|
81
|
+
}
|
|
82
|
+
async *readSource(source, cursor) {
|
|
81
83
|
const start = parseCursor(cursor?.value);
|
|
82
84
|
const input = await streamBoundedJsonLines({ selectedPath: source.locator, allowedRoots: source.authorizedScope.allowedRoots }, { consistency: 'provisional', limits: this.limits });
|
|
83
85
|
let mode = isAppServerLocator(source.locator)
|
|
84
86
|
? 'app-server' : null;
|
|
85
87
|
let schemaVersion = null;
|
|
86
88
|
const sourceArtifactSessionId = rolloutIdFromFilename(source.locator);
|
|
87
|
-
|
|
89
|
+
const rolloutState = { nativeSessionId: sourceArtifactSessionId };
|
|
88
90
|
const identities = new Map();
|
|
89
91
|
let outputIndex = 0;
|
|
90
92
|
let sawRecord = false;
|
|
93
|
+
let complete = false;
|
|
94
|
+
let sawActive = false;
|
|
91
95
|
for await (const line of input) {
|
|
92
96
|
sawRecord = true;
|
|
93
97
|
mode ??= isAppServerRecord(line.value) ? 'app-server' : 'rollout';
|
|
94
98
|
const currentSchema = declaredSchemaVersion([line]);
|
|
95
99
|
if (schemaVersion && schemaVersion !== currentSchema) {
|
|
96
|
-
throw new SessionContractError('SCHEMA_DRIFT', 'Codex source declares mixed schema versions');
|
|
100
|
+
throw new SessionContractError('SCHEMA_DRIFT', 'Codex source declares mixed schema versions', schemaIssueDetail('schemaVersion'));
|
|
97
101
|
}
|
|
98
102
|
schemaVersion = currentSchema;
|
|
99
103
|
assertSupportedSchemaMajor(schemaVersion);
|
|
@@ -101,30 +105,22 @@ export class CodexSessionAdapter {
|
|
|
101
105
|
if (mode === 'app-server') {
|
|
102
106
|
const parsed = AppServerEnvelopeSchema.safeParse(line.value);
|
|
103
107
|
if (!parsed.success) {
|
|
104
|
-
throw new SessionContractError('MALFORMED_SOURCE', 'Codex App Server record is malformed');
|
|
108
|
+
throw new SessionContractError('MALFORMED_SOURCE', 'Codex App Server record is malformed', schemaRejectionDetail(parsed.error));
|
|
105
109
|
}
|
|
106
110
|
for (const thread of extractThreads(parsed.data)) {
|
|
107
111
|
validateThreadIdentity(thread, identities);
|
|
112
|
+
sawActive ||= statusType(thread.status) === 'active';
|
|
108
113
|
}
|
|
109
|
-
|
|
114
|
+
const appServer = normalizeAppServer([line]);
|
|
115
|
+
complete ||= appServer.complete;
|
|
116
|
+
normalized = appServer.records;
|
|
110
117
|
}
|
|
111
118
|
else {
|
|
112
119
|
const parsed = RolloutEnvelopeSchema.safeParse(line.value);
|
|
113
120
|
if (!parsed.success) {
|
|
114
|
-
throw new SessionContractError('MALFORMED_SOURCE', 'Codex rollout record is malformed');
|
|
115
|
-
}
|
|
116
|
-
const payload = asObject(parsed.data.payload);
|
|
117
|
-
if (parsed.data.type === 'session_meta') {
|
|
118
|
-
const declaredId = stringValue(payload.id);
|
|
119
|
-
if (!declaredId) {
|
|
120
|
-
throw new SessionContractError('MALFORMED_SOURCE', 'Codex session metadata is missing its id');
|
|
121
|
-
}
|
|
122
|
-
nativeSessionId = declaredId;
|
|
121
|
+
throw new SessionContractError('MALFORMED_SOURCE', 'Codex rollout record is malformed', schemaRejectionDetail(parsed.error));
|
|
123
122
|
}
|
|
124
|
-
|
|
125
|
-
throw new SessionContractError('MALFORMED_SOURCE', 'Codex rollout has no session identity before content records');
|
|
126
|
-
}
|
|
127
|
-
normalized = [rolloutRecord(nativeSessionId, parsed.data, payload, line, sourceArtifactSessionId)];
|
|
123
|
+
normalized = [normalizeRolloutRecord(rolloutState, parsed.data, line, sourceArtifactSessionId)];
|
|
128
124
|
}
|
|
129
125
|
for (const record of normalized) {
|
|
130
126
|
if (outputIndex++ >= start)
|
|
@@ -132,25 +128,12 @@ export class CodexSessionAdapter {
|
|
|
132
128
|
}
|
|
133
129
|
}
|
|
134
130
|
if (!sawRecord && !input.incompleteTail) {
|
|
135
|
-
throw new SessionContractError('MALFORMED_SOURCE', 'Codex JSONL source is empty');
|
|
136
|
-
}
|
|
137
|
-
}
|
|
138
|
-
async readSource(source) {
|
|
139
|
-
const input = await readBoundedJsonLines({ selectedPath: source.locator, allowedRoots: source.authorizedScope.allowedRoots }, { consistency: 'provisional', limits: this.limits });
|
|
140
|
-
if (input.records.length === 0 && !input.incompleteTail) {
|
|
141
|
-
throw new SessionContractError('MALFORMED_SOURCE', 'Codex JSONL source is empty');
|
|
131
|
+
throw new SessionContractError('MALFORMED_SOURCE', 'Codex JSONL source is empty', schemaIssueDetail('<root>'));
|
|
142
132
|
}
|
|
143
|
-
const appServer = isAppServerLocator(source.locator)
|
|
144
|
-
|| input.records.some((record) => isAppServerRecord(record.value));
|
|
145
|
-
const schemaVersion = declaredSchemaVersion(input.records);
|
|
146
|
-
assertSupportedSchemaMajor(schemaVersion);
|
|
147
|
-
const normalized = appServer
|
|
148
|
-
? normalizeAppServer(input.records)
|
|
149
|
-
: normalizeRollout(input.records, source.locator);
|
|
150
133
|
return {
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
134
|
+
sourceSchemaVersion: schemaVersion ?? CODEX_SOURCE_SCHEMA_VERSION,
|
|
135
|
+
consistency: complete && !sawActive ? 'complete' : 'provisional',
|
|
136
|
+
operationalState: 'available',
|
|
154
137
|
};
|
|
155
138
|
}
|
|
156
139
|
}
|
|
@@ -162,7 +145,7 @@ function normalizeAppServer(input) {
|
|
|
162
145
|
for (const line of input) {
|
|
163
146
|
const parsed = AppServerEnvelopeSchema.safeParse(line.value);
|
|
164
147
|
if (!parsed.success) {
|
|
165
|
-
throw new SessionContractError('MALFORMED_SOURCE', 'Codex App Server record is malformed');
|
|
148
|
+
throw new SessionContractError('MALFORMED_SOURCE', 'Codex App Server record is malformed', schemaRejectionDetail(parsed.error));
|
|
166
149
|
}
|
|
167
150
|
const envelope = parsed.data;
|
|
168
151
|
const threads = extractThreads(envelope);
|
|
@@ -207,30 +190,62 @@ function normalizeAppServer(input) {
|
|
|
207
190
|
}
|
|
208
191
|
return { records, complete: complete && !sawActive };
|
|
209
192
|
}
|
|
210
|
-
function
|
|
211
|
-
const
|
|
212
|
-
let
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
throw new SessionContractError('MALFORMED_SOURCE', 'Codex rollout record is malformed');
|
|
193
|
+
function normalizeRolloutRecord(state, envelope, line, sourceArtifactSessionId) {
|
|
194
|
+
const payload = asObject(envelope.payload);
|
|
195
|
+
let firstMetadata = false;
|
|
196
|
+
if (envelope.type === 'session_meta') {
|
|
197
|
+
const declaredId = stringValue(payload.id);
|
|
198
|
+
if (!declaredId) {
|
|
199
|
+
throw new SessionContractError('MALFORMED_SOURCE', 'Codex session metadata is missing its id', schemaIssueDetail('payload.id'));
|
|
218
200
|
}
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
201
|
+
if (!state.metadataId) {
|
|
202
|
+
firstMetadata = true;
|
|
203
|
+
state.metadataId = declaredId;
|
|
204
|
+
state.nativeSessionId = declaredId;
|
|
205
|
+
const spawn = asObject(asObject(asObject(payload.source).subagent).thread_spawn);
|
|
206
|
+
const lineage = Object.fromEntries(Object.entries({
|
|
207
|
+
forkedFromId: stringValue(payload.forked_from_id),
|
|
208
|
+
parentThreadId: stringValue(spawn.parent_thread_id),
|
|
209
|
+
depth: nonnegativeInteger(spawn.depth ?? payload.depth),
|
|
210
|
+
agentPath: stringValue(payload.agent_path ?? spawn.agent_path),
|
|
211
|
+
agentNickname: stringValue(payload.agent_nickname ?? spawn.agent_nickname),
|
|
212
|
+
subagentHistoryStartOrdinal: nonnegativeInteger(payload.subagent_history_start_ordinal),
|
|
213
|
+
threadSource: stringValue(payload.thread_source),
|
|
214
|
+
}).filter(([, value]) => value !== undefined));
|
|
215
|
+
if (Object.keys(lineage).length > 0)
|
|
216
|
+
state.lineage = lineage;
|
|
227
217
|
}
|
|
228
|
-
if (
|
|
229
|
-
|
|
218
|
+
else if (declaredId !== state.metadataId) {
|
|
219
|
+
state.replayParentId ??= declaredId;
|
|
230
220
|
}
|
|
231
|
-
records.push(rolloutRecord(nativeSessionId, envelope, payload, line, sourceArtifactSessionId));
|
|
232
221
|
}
|
|
233
|
-
|
|
222
|
+
if (!state.nativeSessionId) {
|
|
223
|
+
throw new SessionContractError('MALFORMED_SOURCE', 'Codex rollout has no session identity before content records', schemaIssueDetail('payload.id'));
|
|
224
|
+
}
|
|
225
|
+
const historyStart = state.lineage?.subagentHistoryStartOrdinal;
|
|
226
|
+
// Legacy rollouts have no ordinal boundary; a new turn ends the replay prefix.
|
|
227
|
+
if (historyStart === undefined && (envelope.type === 'turn_context'
|
|
228
|
+
|| (envelope.type === 'event_msg' && payload.type === 'task_started'))) {
|
|
229
|
+
state.replayParentId = undefined;
|
|
230
|
+
}
|
|
231
|
+
const parentId = stringValue(state.lineage?.parentThreadId)
|
|
232
|
+
?? stringValue(state.lineage?.forkedFromId)
|
|
233
|
+
?? state.replayParentId;
|
|
234
|
+
const inherited = !firstMetadata && parentId && (typeof historyStart === 'number'
|
|
235
|
+
? (nonnegativeInteger(envelope.ordinal) ?? line.sequence) < historyStart
|
|
236
|
+
: state.replayParentId !== undefined);
|
|
237
|
+
const record = rolloutRecord(state.nativeSessionId, envelope, payload, line, sourceArtifactSessionId);
|
|
238
|
+
if (state.lineage)
|
|
239
|
+
record.extensions.lineage = state.lineage;
|
|
240
|
+
if (inherited) {
|
|
241
|
+
record.extensions.inheritedFromId = parentId;
|
|
242
|
+
record.extensions.replayed = true;
|
|
243
|
+
}
|
|
244
|
+
return record;
|
|
245
|
+
}
|
|
246
|
+
function nonnegativeInteger(value) {
|
|
247
|
+
return typeof value === 'number' && Number.isSafeInteger(value) && value >= 0
|
|
248
|
+
? value : undefined;
|
|
234
249
|
}
|
|
235
250
|
function threadEvidence(thread, envelope, line) {
|
|
236
251
|
const status = statusType(thread.status);
|
|
@@ -350,7 +365,7 @@ function extractThreads(envelope) {
|
|
|
350
365
|
return candidates.map((candidate) => {
|
|
351
366
|
const parsed = ThreadSchema.safeParse(candidate);
|
|
352
367
|
if (!parsed.success) {
|
|
353
|
-
throw new SessionContractError('MALFORMED_SOURCE', 'Codex App Server thread is malformed');
|
|
368
|
+
throw new SessionContractError('MALFORMED_SOURCE', 'Codex App Server thread is malformed', schemaRejectionDetail(parsed.error));
|
|
354
369
|
}
|
|
355
370
|
return parsed.data;
|
|
356
371
|
});
|
|
@@ -359,7 +374,7 @@ function validateThreadIdentity(thread, identities) {
|
|
|
359
374
|
const sessionTree = thread.sessionId ?? thread.id;
|
|
360
375
|
const previous = identities.get(thread.id);
|
|
361
376
|
if (previous && previous !== sessionTree) {
|
|
362
|
-
throw new SessionContractError('SCHEMA_DRIFT', 'Codex thread session-tree identity changed');
|
|
377
|
+
throw new SessionContractError('SCHEMA_DRIFT', 'Codex thread session-tree identity changed', schemaIssueDetail('sessionId'));
|
|
363
378
|
}
|
|
364
379
|
identities.set(thread.id, sessionTree);
|
|
365
380
|
}
|
|
@@ -514,7 +529,7 @@ function parseCursor(value) {
|
|
|
514
529
|
if (value === undefined || value === '')
|
|
515
530
|
return 0;
|
|
516
531
|
if (!/^\d+$/.test(value))
|
|
517
|
-
throw new SessionContractError('SCHEMA_DRIFT', 'Codex record cursor is invalid');
|
|
532
|
+
throw new SessionContractError('SCHEMA_DRIFT', 'Codex record cursor is invalid', schemaIssueDetail('cursor'));
|
|
518
533
|
return Number(value);
|
|
519
534
|
}
|
|
520
535
|
function unixTimestamp(value) {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { basename, extname } from 'node:path';
|
|
2
2
|
import { z } from 'zod';
|
|
3
|
-
import { SessionContractError, assertSupportedSchemaMajor, } from '../contracts.js';
|
|
3
|
+
import { schemaRejectionDetail, schemaIssueDetail, SessionContractError, assertSupportedSchemaMajor, } from '../contracts.js';
|
|
4
4
|
import { readBoundedJson } from '../readers.js';
|
|
5
5
|
export const COPILOT_ADAPTER_VERSION = '1.0.0';
|
|
6
6
|
export const COPILOT_EXPORT_SCHEMA_VERSION = '1.0.0';
|
|
@@ -76,7 +76,7 @@ export class CopilotSessionAdapter {
|
|
|
76
76
|
}, this.limits);
|
|
77
77
|
const parsed = ExportSchema.safeParse(value);
|
|
78
78
|
if (!parsed.success) {
|
|
79
|
-
throw new SessionContractError('MALFORMED_SOURCE', 'Copilot chat export is malformed');
|
|
79
|
+
throw new SessionContractError('MALFORMED_SOURCE', 'Copilot chat export is malformed', schemaRejectionDetail(parsed.error));
|
|
80
80
|
}
|
|
81
81
|
const schemaVersion = declaredSchemaVersion(parsed.data);
|
|
82
82
|
assertSupportedSchemaMajor(schemaVersion);
|
|
@@ -193,7 +193,7 @@ function declaredSchemaVersion(value) {
|
|
|
193
193
|
? value.version
|
|
194
194
|
: Number(String(value.version).split('.')[0]);
|
|
195
195
|
if (!Number.isInteger(major) || major < 1) {
|
|
196
|
-
throw new SessionContractError('SCHEMA_DRIFT', 'invalid Copilot export version');
|
|
196
|
+
throw new SessionContractError('SCHEMA_DRIFT', 'invalid Copilot export version', schemaIssueDetail('version'));
|
|
197
197
|
}
|
|
198
198
|
return `${major}.0.0`;
|
|
199
199
|
}
|
|
@@ -210,7 +210,7 @@ function parseCursor(value) {
|
|
|
210
210
|
if (!value)
|
|
211
211
|
return 0;
|
|
212
212
|
if (!/^\d+$/.test(value)) {
|
|
213
|
-
throw new SessionContractError('SCHEMA_DRIFT', 'invalid Copilot record cursor');
|
|
213
|
+
throw new SessionContractError('SCHEMA_DRIFT', 'invalid Copilot record cursor', schemaIssueDetail('cursor'));
|
|
214
214
|
}
|
|
215
215
|
return Number(value);
|
|
216
216
|
}
|