@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
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { opendir } from 'node:fs/promises';
|
|
2
2
|
import { basename, dirname, extname, 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 { readBoundedText, streamBoundedJsonLines, } from '../readers.js';
|
|
6
6
|
export const CURSOR_ADAPTER_VERSION = '1.0.0';
|
|
7
7
|
export const CURSOR_SOURCE_SCHEMA_VERSION = '1.0.0';
|
|
8
8
|
const CliEventSchema = z.object({
|
|
@@ -82,7 +82,7 @@ export class CursorSessionAdapter {
|
|
|
82
82
|
for (const root of [...scope.allowedRoots].sort()) {
|
|
83
83
|
for await (const locator of discoverJsonl(resolve(root), this.discoveryLimits.maxDepth)) {
|
|
84
84
|
if (++emitted > this.discoveryLimits.maxFiles) {
|
|
85
|
-
throw new SessionContractError('RESOURCE_LIMIT_EXCEEDED', 'Cursor source discovery exceeded the authorized file limit');
|
|
85
|
+
throw new SessionContractError('RESOURCE_LIMIT_EXCEEDED', 'Cursor source discovery exceeded the authorized file limit', { limit: 'maxFiles', configured: this.discoveryLimits.maxFiles, observed: emitted });
|
|
86
86
|
}
|
|
87
87
|
yield {
|
|
88
88
|
provider: 'cursor',
|
|
@@ -93,6 +93,16 @@ export class CursorSessionAdapter {
|
|
|
93
93
|
}
|
|
94
94
|
}
|
|
95
95
|
async inspect(source) {
|
|
96
|
+
if (source.locatorClass === 'cursor-cli-stream-json'
|
|
97
|
+
|| source.locatorClass === 'cursor-cloud-events-jsonl'
|
|
98
|
+
|| source.locatorClass === 'cursor-agent-transcript-jsonl') {
|
|
99
|
+
const records = this.stream(source);
|
|
100
|
+
let result = await records.next();
|
|
101
|
+
while (!result.done)
|
|
102
|
+
result = await records.next();
|
|
103
|
+
if (result.value)
|
|
104
|
+
return result.value;
|
|
105
|
+
}
|
|
96
106
|
const parsed = await this.readSource(source);
|
|
97
107
|
return {
|
|
98
108
|
sourceSchemaVersion: parsed.schemaVersion,
|
|
@@ -102,7 +112,8 @@ export class CursorSessionAdapter {
|
|
|
102
112
|
}
|
|
103
113
|
async *stream(source, cursor) {
|
|
104
114
|
if (source.locatorClass === 'cursor-cli-stream-json'
|
|
105
|
-
|| source.locatorClass === 'cursor-cloud-events-jsonl'
|
|
115
|
+
|| source.locatorClass === 'cursor-cloud-events-jsonl'
|
|
116
|
+
|| source.locatorClass === 'cursor-agent-transcript-jsonl') {
|
|
106
117
|
const input = await streamBoundedJsonLines({
|
|
107
118
|
selectedPath: source.locator,
|
|
108
119
|
allowedRoots: source.authorizedScope.allowedRoots,
|
|
@@ -114,13 +125,14 @@ export class CursorSessionAdapter {
|
|
|
114
125
|
let agentId;
|
|
115
126
|
let runId;
|
|
116
127
|
let sawRecord = false;
|
|
128
|
+
let complete = false;
|
|
117
129
|
for await (const line of input) {
|
|
118
130
|
sawRecord = true;
|
|
119
131
|
const raw = asObject(line.value);
|
|
120
132
|
const currentSchema = typeof raw.schemaVersion === 'string'
|
|
121
133
|
? raw.schemaVersion : CURSOR_SOURCE_SCHEMA_VERSION;
|
|
122
134
|
if (schemaVersion && schemaVersion !== currentSchema) {
|
|
123
|
-
throw new SessionContractError('SCHEMA_DRIFT', 'Cursor source declares mixed schema versions');
|
|
135
|
+
throw new SessionContractError('SCHEMA_DRIFT', 'Cursor source declares mixed schema versions', schemaIssueDetail('schemaVersion'));
|
|
124
136
|
}
|
|
125
137
|
schemaVersion = currentSchema;
|
|
126
138
|
assertSupportedSchemaMajor(schemaVersion);
|
|
@@ -128,7 +140,7 @@ export class CursorSessionAdapter {
|
|
|
128
140
|
if (source.locatorClass === 'cursor-cli-stream-json') {
|
|
129
141
|
const parsed = CliEventSchema.safeParse(line.value);
|
|
130
142
|
if (!parsed.success) {
|
|
131
|
-
throw new SessionContractError('MALFORMED_SOURCE', 'Cursor CLI event is malformed');
|
|
143
|
+
throw new SessionContractError('MALFORMED_SOURCE', 'Cursor CLI event is malformed', schemaRejectionDetail(parsed.error));
|
|
132
144
|
}
|
|
133
145
|
const event = parsed.data;
|
|
134
146
|
if (cliSessionId && cliSessionId !== event.session_id) {
|
|
@@ -137,10 +149,10 @@ export class CursorSessionAdapter {
|
|
|
137
149
|
cliSessionId = event.session_id;
|
|
138
150
|
record = normalizeCli([line]).records[0];
|
|
139
151
|
}
|
|
140
|
-
else {
|
|
152
|
+
else if (source.locatorClass === 'cursor-cloud-events-jsonl') {
|
|
141
153
|
const parsed = CloudEventSchema.safeParse(line.value);
|
|
142
154
|
if (!parsed.success) {
|
|
143
|
-
throw new SessionContractError('MALFORMED_SOURCE', 'Cursor Cloud Agent event is malformed');
|
|
155
|
+
throw new SessionContractError('MALFORMED_SOURCE', 'Cursor Cloud Agent event is malformed', schemaRejectionDetail(parsed.error));
|
|
144
156
|
}
|
|
145
157
|
const event = parsed.data;
|
|
146
158
|
const nextAgentId = event.agent?.id ?? agentId;
|
|
@@ -153,27 +165,38 @@ export class CursorSessionAdapter {
|
|
|
153
165
|
}
|
|
154
166
|
agentId = nextAgentId;
|
|
155
167
|
runId = nextRunId;
|
|
156
|
-
|
|
168
|
+
const normalized = normalizeCloud([{
|
|
157
169
|
...line,
|
|
158
170
|
value: {
|
|
159
171
|
...event,
|
|
160
172
|
agent: event.agent ?? (agentId ? { id: agentId } : undefined),
|
|
161
173
|
run: event.run ?? (runId ? { id: runId } : undefined),
|
|
162
174
|
},
|
|
163
|
-
}])
|
|
175
|
+
}]);
|
|
176
|
+
complete ||= normalized.complete;
|
|
177
|
+
record = normalized.records[0];
|
|
178
|
+
}
|
|
179
|
+
else {
|
|
180
|
+
record = normalizeAgentTranscript([line], source.locator).records[0];
|
|
164
181
|
}
|
|
182
|
+
complete ||= record.extensions?.lifecycle === 'complete';
|
|
165
183
|
if (outputIndex++ >= start)
|
|
166
184
|
yield record;
|
|
167
185
|
}
|
|
168
186
|
if (!sawRecord && !input.incompleteTail) {
|
|
169
|
-
throw new SessionContractError('MALFORMED_SOURCE', 'Cursor structured source is empty');
|
|
187
|
+
throw new SessionContractError('MALFORMED_SOURCE', 'Cursor structured source is empty', schemaIssueDetail('<root>'));
|
|
170
188
|
}
|
|
171
|
-
return
|
|
189
|
+
return {
|
|
190
|
+
sourceSchemaVersion: schemaVersion ?? CURSOR_SOURCE_SCHEMA_VERSION,
|
|
191
|
+
consistency: complete && !input.incompleteTail ? 'complete' : 'provisional',
|
|
192
|
+
operationalState: 'available',
|
|
193
|
+
};
|
|
172
194
|
}
|
|
173
195
|
const parsed = await this.readSource(source);
|
|
174
196
|
const start = parseCursor(cursor?.value);
|
|
175
197
|
for (const record of parsed.records.slice(start))
|
|
176
198
|
yield record;
|
|
199
|
+
return undefined;
|
|
177
200
|
}
|
|
178
201
|
async readSource(source) {
|
|
179
202
|
const authorization = {
|
|
@@ -191,36 +214,6 @@ export class CursorSessionAdapter {
|
|
|
191
214
|
records: normalizeMarkdown(input.value, source.locator),
|
|
192
215
|
};
|
|
193
216
|
}
|
|
194
|
-
const input = await readBoundedJsonLines(authorization, { consistency: 'provisional', limits: this.limits });
|
|
195
|
-
if (input.records.length === 0 && !input.incompleteTail) {
|
|
196
|
-
throw new SessionContractError('MALFORMED_SOURCE', 'Cursor structured source is empty');
|
|
197
|
-
}
|
|
198
|
-
const schemaVersion = declaredVersion(input.records);
|
|
199
|
-
assertSupportedSchemaMajor(schemaVersion);
|
|
200
|
-
if (source.locatorClass === 'cursor-cli-stream-json') {
|
|
201
|
-
const normalized = normalizeCli(input.records);
|
|
202
|
-
return {
|
|
203
|
-
schemaVersion,
|
|
204
|
-
consistency: normalized.complete && !input.incompleteTail ? 'complete' : 'provisional',
|
|
205
|
-
records: normalized.records,
|
|
206
|
-
};
|
|
207
|
-
}
|
|
208
|
-
if (source.locatorClass === 'cursor-cloud-events-jsonl') {
|
|
209
|
-
const normalized = normalizeCloud(input.records);
|
|
210
|
-
return {
|
|
211
|
-
schemaVersion,
|
|
212
|
-
consistency: normalized.complete && !input.incompleteTail ? 'complete' : 'provisional',
|
|
213
|
-
records: normalized.records,
|
|
214
|
-
};
|
|
215
|
-
}
|
|
216
|
-
if (source.locatorClass === 'cursor-agent-transcript-jsonl') {
|
|
217
|
-
const normalized = normalizeAgentTranscript(input.records, source.locator);
|
|
218
|
-
return {
|
|
219
|
-
schemaVersion,
|
|
220
|
-
consistency: normalized.complete && !input.incompleteTail ? 'complete' : 'provisional',
|
|
221
|
-
records: normalized.records,
|
|
222
|
-
};
|
|
223
|
-
}
|
|
224
217
|
throw new SessionContractError('UNSUPPORTED_OPERATION', 'unsupported Cursor source class');
|
|
225
218
|
}
|
|
226
219
|
}
|
|
@@ -257,7 +250,7 @@ function normalizeCli(input) {
|
|
|
257
250
|
for (const line of input) {
|
|
258
251
|
const parsed = CliEventSchema.safeParse(line.value);
|
|
259
252
|
if (!parsed.success) {
|
|
260
|
-
throw new SessionContractError('MALFORMED_SOURCE', 'Cursor CLI event is malformed');
|
|
253
|
+
throw new SessionContractError('MALFORMED_SOURCE', 'Cursor CLI event is malformed', schemaRejectionDetail(parsed.error));
|
|
261
254
|
}
|
|
262
255
|
const event = parsed.data;
|
|
263
256
|
if (sessionId && sessionId !== event.session_id) {
|
|
@@ -307,7 +300,7 @@ function normalizeCloud(input) {
|
|
|
307
300
|
for (const line of input) {
|
|
308
301
|
const parsed = CloudEventSchema.safeParse(line.value);
|
|
309
302
|
if (!parsed.success) {
|
|
310
|
-
throw new SessionContractError('MALFORMED_SOURCE', 'Cursor Cloud Agent event is malformed');
|
|
303
|
+
throw new SessionContractError('MALFORMED_SOURCE', 'Cursor Cloud Agent event is malformed', schemaRejectionDetail(parsed.error));
|
|
311
304
|
}
|
|
312
305
|
const event = parsed.data;
|
|
313
306
|
const nextAgentId = event.agent?.id ?? agentId;
|
|
@@ -371,7 +364,7 @@ function normalizeAgentTranscript(input, locator) {
|
|
|
371
364
|
for (const line of input) {
|
|
372
365
|
const parsed = AgentTranscriptEventSchema.safeParse(line.value);
|
|
373
366
|
if (!parsed.success) {
|
|
374
|
-
throw new SessionContractError('MALFORMED_SOURCE', 'Cursor agent transcript event is malformed');
|
|
367
|
+
throw new SessionContractError('MALFORMED_SOURCE', 'Cursor agent transcript event is malformed', schemaRejectionDetail(parsed.error));
|
|
375
368
|
}
|
|
376
369
|
const event = parsed.data;
|
|
377
370
|
const terminal = event.type === 'turn_ended' && event.status === 'success';
|
|
@@ -411,7 +404,7 @@ function normalizeMarkdown(value, locator) {
|
|
|
411
404
|
const heading = /^#{1,3}\s+(User|Assistant|Cursor)\s*$/gim;
|
|
412
405
|
const matches = [...value.matchAll(heading)];
|
|
413
406
|
if (matches.length === 0) {
|
|
414
|
-
throw new SessionContractError('MALFORMED_SOURCE', 'Cursor Markdown export has no role headings');
|
|
407
|
+
throw new SessionContractError('MALFORMED_SOURCE', 'Cursor Markdown export has no role headings', schemaIssueDetail('headings'));
|
|
415
408
|
}
|
|
416
409
|
const nativeSessionId = basename(locator, extname(locator));
|
|
417
410
|
return matches.map((match, index) => {
|
|
@@ -462,16 +455,6 @@ function messageText(value) {
|
|
|
462
455
|
return '';
|
|
463
456
|
}).filter(Boolean).join('\n');
|
|
464
457
|
}
|
|
465
|
-
function declaredVersion(records) {
|
|
466
|
-
const versions = new Set(records.map((line) => {
|
|
467
|
-
const value = asObject(line.value);
|
|
468
|
-
return typeof value.schemaVersion === 'string' ? value.schemaVersion : CURSOR_SOURCE_SCHEMA_VERSION;
|
|
469
|
-
}));
|
|
470
|
-
if (versions.size !== 1) {
|
|
471
|
-
throw new SessionContractError('SCHEMA_DRIFT', 'Cursor source declares mixed schema versions');
|
|
472
|
-
}
|
|
473
|
-
return [...versions][0];
|
|
474
|
-
}
|
|
475
458
|
function declaredEventVersion(event) {
|
|
476
459
|
return event.schemaVersion ?? CURSOR_SOURCE_SCHEMA_VERSION;
|
|
477
460
|
}
|
|
@@ -511,7 +494,7 @@ function parseCursor(value) {
|
|
|
511
494
|
if (!value)
|
|
512
495
|
return 0;
|
|
513
496
|
if (!/^\d+$/.test(value)) {
|
|
514
|
-
throw new SessionContractError('SCHEMA_DRIFT', 'invalid Cursor record cursor');
|
|
497
|
+
throw new SessionContractError('SCHEMA_DRIFT', 'invalid Cursor record cursor', schemaIssueDetail('cursor'));
|
|
515
498
|
}
|
|
516
499
|
return Number(value);
|
|
517
500
|
}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { opendir } from 'node:fs/promises';
|
|
2
2
|
import { resolve } from 'node:path';
|
|
3
3
|
import { z } from 'zod';
|
|
4
|
-
import { SessionContractError, } from '../contracts.js';
|
|
5
|
-
import {
|
|
4
|
+
import { schemaRejectionDetail, schemaIssueDetail, SessionContractError, } from '../contracts.js';
|
|
5
|
+
import { streamBoundedJsonLines } from '../readers.js';
|
|
6
6
|
export const DEEPSEEK_HARNESS_ADAPTER_VERSION = '1.0.0';
|
|
7
7
|
export const DEEPSEEK_HARNESS_SOURCE_SCHEMA_VERSION = '2.0.0';
|
|
8
8
|
const Header = z.object({
|
|
@@ -39,7 +39,7 @@ export class DeepSeekHarnessSessionAdapter {
|
|
|
39
39
|
for (const root of [...scope.allowedRoots].sort()) {
|
|
40
40
|
for await (const locator of jsonlFiles(resolve(root))) {
|
|
41
41
|
if (++count > this.maxFiles)
|
|
42
|
-
throw new SessionContractError('RESOURCE_LIMIT_EXCEEDED', 'DeepSeek Harness discovery file limit exceeded');
|
|
42
|
+
throw new SessionContractError('RESOURCE_LIMIT_EXCEEDED', 'DeepSeek Harness discovery file limit exceeded', { limit: 'maxFiles', configured: this.maxFiles, observed: count });
|
|
43
43
|
yield { provider: this.provider, locator, locatorClass: 'deepseek-harness-session-v2-jsonl' };
|
|
44
44
|
}
|
|
45
45
|
}
|
|
@@ -47,12 +47,15 @@ export class DeepSeekHarnessSessionAdapter {
|
|
|
47
47
|
async inspect(source) {
|
|
48
48
|
let input;
|
|
49
49
|
try {
|
|
50
|
-
input = await
|
|
50
|
+
input = await streamBoundedJsonLines({ selectedPath: source.locator, allowedRoots: source.authorizedScope.allowedRoots }, { consistency: 'provisional', limits: this.limits });
|
|
51
51
|
}
|
|
52
52
|
catch (error) {
|
|
53
53
|
throw normalizeAuthorizationError(error);
|
|
54
54
|
}
|
|
55
|
-
|
|
55
|
+
let header;
|
|
56
|
+
for await (const line of input)
|
|
57
|
+
header ??= parseHeader(line.value);
|
|
58
|
+
header ??= parseHeader(undefined);
|
|
56
59
|
if (input.incompleteTail)
|
|
57
60
|
throw new SessionContractError('TRUNCATED_SOURCE', 'DeepSeek Harness session has a truncated JSONL tail');
|
|
58
61
|
return { sourceSchemaVersion: `${header.version}.0.0`, consistency: 'complete', operationalState: 'available' };
|
|
@@ -67,24 +70,24 @@ export class DeepSeekHarnessSessionAdapter {
|
|
|
67
70
|
}
|
|
68
71
|
const start = cursor?.value.replace(/^byte:/, '') ?? '0';
|
|
69
72
|
if (!/^\d+$/.test(start))
|
|
70
|
-
throw new SessionContractError('SCHEMA_DRIFT', 'invalid DeepSeek Harness cursor');
|
|
73
|
+
throw new SessionContractError('SCHEMA_DRIFT', 'invalid DeepSeek Harness cursor', schemaIssueDetail('cursor'));
|
|
71
74
|
let header;
|
|
72
75
|
let expectedSeq = 0;
|
|
73
76
|
let end = 0;
|
|
74
77
|
for await (const line of input) {
|
|
75
78
|
end = line.byteOffset + line.byteLength;
|
|
76
79
|
if (Number(start) > line.byteOffset && Number(start) < end)
|
|
77
|
-
throw new SessionContractError('SCHEMA_DRIFT', 'DeepSeek Harness cursor is not a record boundary');
|
|
80
|
+
throw new SessionContractError('SCHEMA_DRIFT', 'DeepSeek Harness cursor is not a record boundary', schemaIssueDetail('cursor'));
|
|
78
81
|
if (!header) {
|
|
79
82
|
header = parseHeader(line.value);
|
|
80
83
|
continue;
|
|
81
84
|
}
|
|
82
85
|
const parsed = Event.safeParse(line.value);
|
|
83
86
|
if (!parsed.success)
|
|
84
|
-
throw new SessionContractError('MALFORMED_SOURCE', 'DeepSeek Harness session event is malformed');
|
|
87
|
+
throw new SessionContractError('MALFORMED_SOURCE', 'DeepSeek Harness session event is malformed', schemaRejectionDetail(parsed.error));
|
|
85
88
|
const event = parsed.data;
|
|
86
89
|
if (event.seq !== expectedSeq)
|
|
87
|
-
throw new SessionContractError(event.seq < expectedSeq ? 'DUPLICATE_NATIVE_ID' : 'SCHEMA_DRIFT', `DeepSeek Harness sequence expected ${expectedSeq}, received ${event.seq}
|
|
90
|
+
throw new SessionContractError(event.seq < expectedSeq ? 'DUPLICATE_NATIVE_ID' : 'SCHEMA_DRIFT', `DeepSeek Harness sequence expected ${expectedSeq}, received ${event.seq}`, schemaIssueDetail('seq'));
|
|
88
91
|
expectedSeq++;
|
|
89
92
|
if (end <= Number(start))
|
|
90
93
|
continue;
|
|
@@ -121,9 +124,9 @@ export class DeepSeekHarnessSessionAdapter {
|
|
|
121
124
|
};
|
|
122
125
|
}
|
|
123
126
|
if (!header)
|
|
124
|
-
throw new SessionContractError('MALFORMED_SOURCE', 'DeepSeek Harness session header is missing');
|
|
127
|
+
throw new SessionContractError('MALFORMED_SOURCE', 'DeepSeek Harness session header is missing', schemaIssueDetail('header'));
|
|
125
128
|
if (Number(start) > end)
|
|
126
|
-
throw new SessionContractError('SCHEMA_DRIFT', 'DeepSeek Harness cursor exceeds source size');
|
|
129
|
+
throw new SessionContractError('SCHEMA_DRIFT', 'DeepSeek Harness cursor exceeds source size', schemaIssueDetail('cursor'));
|
|
127
130
|
if (input.incompleteTail)
|
|
128
131
|
throw new SessionContractError('TRUNCATED_SOURCE', 'DeepSeek Harness session has a truncated JSONL tail');
|
|
129
132
|
}
|
|
@@ -131,7 +134,7 @@ export class DeepSeekHarnessSessionAdapter {
|
|
|
131
134
|
function parseHeader(value) {
|
|
132
135
|
const parsed = Header.safeParse(value);
|
|
133
136
|
if (!parsed.success)
|
|
134
|
-
throw new SessionContractError('MALFORMED_SOURCE', 'DeepSeek Harness session header is malformed');
|
|
137
|
+
throw new SessionContractError('MALFORMED_SOURCE', 'DeepSeek Harness session header is malformed', schemaRejectionDetail(parsed.error));
|
|
135
138
|
if (parsed.data.version !== 2)
|
|
136
139
|
throw new SessionContractError('UNKNOWN_SCHEMA_MAJOR', `unsupported DeepSeek Harness session version: ${parsed.data.version}`);
|
|
137
140
|
return parsed.data;
|
|
@@ -1,8 +1,8 @@
|
|
|
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, } from '../contracts.js';
|
|
5
|
-
import {
|
|
4
|
+
import { schemaRejectionDetail, schemaIssueDetail, SessionContractError, assertSupportedSchemaMajor, } from '../contracts.js';
|
|
5
|
+
import { streamBoundedJsonLines, } from '../readers.js';
|
|
6
6
|
export const FACTORY_ADAPTER_VERSION = '1.0.0';
|
|
7
7
|
export const FACTORY_SOURCE_SCHEMA_VERSION = '1.0.0';
|
|
8
8
|
const FactoryRecordSchema = z.object({
|
|
@@ -51,13 +51,21 @@ export class FactorySessionAdapter {
|
|
|
51
51
|
for (const root of [...scope.allowedRoots].sort()) {
|
|
52
52
|
for await (const locator of discoverJsonl(resolve(root), this.discoveryLimits.maxDepth)) {
|
|
53
53
|
if (++emitted > this.discoveryLimits.maxFiles) {
|
|
54
|
-
throw new SessionContractError('RESOURCE_LIMIT_EXCEEDED', 'Factory source discovery exceeded the authorized file limit');
|
|
54
|
+
throw new SessionContractError('RESOURCE_LIMIT_EXCEEDED', 'Factory source discovery exceeded the authorized file limit', { limit: 'maxFiles', configured: this.discoveryLimits.maxFiles, observed: emitted });
|
|
55
55
|
}
|
|
56
56
|
yield { provider: 'factory', locator, locatorClass: 'factory-droid-jsonl' };
|
|
57
57
|
}
|
|
58
58
|
}
|
|
59
59
|
}
|
|
60
60
|
async inspect(source) {
|
|
61
|
+
if (source.locatorClass === 'factory-droid-jsonl') {
|
|
62
|
+
const records = this.stream(source);
|
|
63
|
+
let result = await records.next();
|
|
64
|
+
while (!result.done)
|
|
65
|
+
result = await records.next();
|
|
66
|
+
if (result.value)
|
|
67
|
+
return result.value;
|
|
68
|
+
}
|
|
61
69
|
const parsed = await this.readSource(source);
|
|
62
70
|
return {
|
|
63
71
|
sourceSchemaVersion: parsed.schemaVersion,
|
|
@@ -76,6 +84,7 @@ export class FactorySessionAdapter {
|
|
|
76
84
|
let establishedId;
|
|
77
85
|
let schemaVersion = null;
|
|
78
86
|
let sawRecord = false;
|
|
87
|
+
let complete = false;
|
|
79
88
|
for await (const line of input) {
|
|
80
89
|
sawRecord = true;
|
|
81
90
|
const parsed = FactoryRecordSchema.safeParse(line.value);
|
|
@@ -85,7 +94,7 @@ export class FactorySessionAdapter {
|
|
|
85
94
|
const value = parsed.data;
|
|
86
95
|
const currentSchema = value.schemaVersion ?? FACTORY_SOURCE_SCHEMA_VERSION;
|
|
87
96
|
if (schemaVersion && schemaVersion !== currentSchema) {
|
|
88
|
-
throw new SessionContractError('SCHEMA_DRIFT', 'mixed Factory source schemas');
|
|
97
|
+
throw new SessionContractError('SCHEMA_DRIFT', 'mixed Factory source schemas', schemaIssueDetail('schemaVersion'));
|
|
89
98
|
}
|
|
90
99
|
schemaVersion = currentSchema;
|
|
91
100
|
assertSupportedSchemaMajor(schemaVersion);
|
|
@@ -95,44 +104,39 @@ export class FactorySessionAdapter {
|
|
|
95
104
|
throw new SessionContractError('DUPLICATE_NATIVE_ID', 'Factory source changes session identity');
|
|
96
105
|
}
|
|
97
106
|
establishedId = currentId;
|
|
98
|
-
|
|
107
|
+
const normalized = normalize([line], source, establishedId);
|
|
108
|
+
complete ||= normalized.complete;
|
|
109
|
+
for (const record of normalized.records) {
|
|
99
110
|
if (outputIndex++ >= start)
|
|
100
111
|
yield record;
|
|
101
112
|
}
|
|
102
113
|
}
|
|
103
114
|
if (!sawRecord && !input.incompleteTail) {
|
|
104
|
-
throw new SessionContractError('MALFORMED_SOURCE', 'Factory session source is empty');
|
|
115
|
+
throw new SessionContractError('MALFORMED_SOURCE', 'Factory session source is empty', schemaIssueDetail('<root>'));
|
|
105
116
|
}
|
|
106
|
-
return
|
|
117
|
+
return {
|
|
118
|
+
sourceSchemaVersion: schemaVersion ?? FACTORY_SOURCE_SCHEMA_VERSION,
|
|
119
|
+
consistency: complete && !input.incompleteTail ? 'complete' : 'provisional',
|
|
120
|
+
operationalState: 'available',
|
|
121
|
+
};
|
|
107
122
|
}
|
|
108
123
|
const parsed = await this.readSource(source);
|
|
109
124
|
const start = parseCursor(cursor?.value);
|
|
110
125
|
for (const record of parsed.records.slice(start))
|
|
111
126
|
yield record;
|
|
127
|
+
return undefined;
|
|
112
128
|
}
|
|
113
129
|
async readSource(source) {
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
const result = await readBoundedJsonLines({
|
|
118
|
-
selectedPath: source.locator,
|
|
119
|
-
allowedRoots: source.authorizedScope.allowedRoots,
|
|
120
|
-
}, { consistency: 'provisional', limits: this.limits });
|
|
121
|
-
input = result.records;
|
|
122
|
-
incompleteTail = result.incompleteTail;
|
|
123
|
-
}
|
|
124
|
-
else {
|
|
125
|
-
input = await this.remoteRecords(source);
|
|
126
|
-
}
|
|
127
|
-
if (input.length === 0 && !incompleteTail) {
|
|
128
|
-
throw new SessionContractError('MALFORMED_SOURCE', 'Factory session source is empty');
|
|
130
|
+
const input = await this.remoteRecords(source);
|
|
131
|
+
if (input.length === 0) {
|
|
132
|
+
throw new SessionContractError('MALFORMED_SOURCE', 'Factory session source is empty', schemaIssueDetail('<root>'));
|
|
129
133
|
}
|
|
130
134
|
const schemaVersion = declaredVersion(input);
|
|
131
135
|
assertSupportedSchemaMajor(schemaVersion);
|
|
132
136
|
const normalized = normalize(input, source);
|
|
133
137
|
return {
|
|
134
138
|
schemaVersion,
|
|
135
|
-
consistency: normalized.complete
|
|
139
|
+
consistency: normalized.complete ? 'complete' : 'provisional',
|
|
136
140
|
records: normalized.records,
|
|
137
141
|
};
|
|
138
142
|
}
|
|
@@ -155,7 +159,7 @@ export class FactorySessionAdapter {
|
|
|
155
159
|
}
|
|
156
160
|
const values = await transport.snapshot(source);
|
|
157
161
|
if (values.length > (this.limits?.maxRecords ?? 1_000_000)) {
|
|
158
|
-
throw new SessionContractError('RESOURCE_LIMIT_EXCEEDED', 'Factory remote record limit exceeded');
|
|
162
|
+
throw new SessionContractError('RESOURCE_LIMIT_EXCEEDED', 'Factory remote record limit exceeded', { limit: 'maxRecords', configured: this.limits?.maxRecords ?? 1_000_000, observed: values.length });
|
|
159
163
|
}
|
|
160
164
|
return values.map((value, sequence) => ({
|
|
161
165
|
value, sequence, byteOffset: sequence, byteLength: Buffer.byteLength(JSON.stringify(value)),
|
|
@@ -330,7 +334,7 @@ function factoryMalformedRecord(source, record, error) {
|
|
|
330
334
|
? issue.path.map(String).join('.')
|
|
331
335
|
: 'record';
|
|
332
336
|
return new SessionContractError('MALFORMED_SOURCE', `Factory source ${basename(source.locator)} record ${record.sequence + 1} `
|
|
333
|
-
+ `type ${type} failed requirement ${requirement} (${issue?.code ?? 'invalid_type'})
|
|
337
|
+
+ `type ${type} failed requirement ${requirement} (${issue?.code ?? 'invalid_type'})`, schemaRejectionDetail(error));
|
|
334
338
|
}
|
|
335
339
|
function declaredVersion(records) {
|
|
336
340
|
const versions = new Set(records.flatMap((record) => {
|
|
@@ -338,7 +342,7 @@ function declaredVersion(records) {
|
|
|
338
342
|
return typeof value.schemaVersion === 'string' ? [value.schemaVersion] : [];
|
|
339
343
|
}));
|
|
340
344
|
if (versions.size > 1)
|
|
341
|
-
throw new SessionContractError('SCHEMA_DRIFT', 'mixed Factory schema versions');
|
|
345
|
+
throw new SessionContractError('SCHEMA_DRIFT', 'mixed Factory schema versions', schemaIssueDetail('schemaVersion'));
|
|
342
346
|
return [...versions][0] ?? FACTORY_SOURCE_SCHEMA_VERSION;
|
|
343
347
|
}
|
|
344
348
|
function timestamp(value) {
|
|
@@ -375,7 +379,7 @@ function parseCursor(value) {
|
|
|
375
379
|
if (!value)
|
|
376
380
|
return 0;
|
|
377
381
|
if (!/^\d+$/.test(value))
|
|
378
|
-
throw new SessionContractError('SCHEMA_DRIFT', 'invalid Factory cursor');
|
|
382
|
+
throw new SessionContractError('SCHEMA_DRIFT', 'invalid Factory cursor', schemaIssueDetail('cursor'));
|
|
379
383
|
return Number(value);
|
|
380
384
|
}
|
|
381
385
|
const RECORD_KEYS = new Set([
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
|
-
import { SessionContractError, assertSupportedSchemaMajor, } from '../contracts.js';
|
|
2
|
+
import { schemaRejectionDetail, schemaIssueDetail, SessionContractError, assertSupportedSchemaMajor, } from '../contracts.js';
|
|
3
3
|
import { streamBoundedJsonLines } from '../readers.js';
|
|
4
4
|
export const GENERIC_INTERCHANGE_KIND = 'aiwg.session-interchange';
|
|
5
5
|
export const GENERIC_ADAPTER_VERSION = '1.0.0';
|
|
@@ -80,7 +80,7 @@ export class GenericSessionInterchangeAdapter {
|
|
|
80
80
|
sessionSequences.add(sequenceKey);
|
|
81
81
|
}
|
|
82
82
|
if (!header)
|
|
83
|
-
throw new SessionContractError('MALFORMED_SOURCE', 'generic interchange is empty');
|
|
83
|
+
throw new SessionContractError('MALFORMED_SOURCE', 'generic interchange is empty', schemaIssueDetail('<root>'));
|
|
84
84
|
if (input.incompleteTail) {
|
|
85
85
|
throw new SessionContractError('TRUNCATED_SOURCE', 'generic interchange contains a truncated record');
|
|
86
86
|
}
|
|
@@ -88,6 +88,7 @@ export class GenericSessionInterchangeAdapter {
|
|
|
88
88
|
sourceSchemaVersion: header.schemaVersion,
|
|
89
89
|
consistency: header.consistency,
|
|
90
90
|
operationalState: 'available',
|
|
91
|
+
declaredWorkspaceId: header.workspace.id,
|
|
91
92
|
};
|
|
92
93
|
}
|
|
93
94
|
async *stream(source, cursor) {
|
|
@@ -99,7 +100,7 @@ export class GenericSessionInterchangeAdapter {
|
|
|
99
100
|
const first = await iterator.next();
|
|
100
101
|
await iterator.return?.();
|
|
101
102
|
if (first.done)
|
|
102
|
-
throw new SessionContractError('MALFORMED_SOURCE', 'generic interchange is empty');
|
|
103
|
+
throw new SessionContractError('MALFORMED_SOURCE', 'generic interchange is empty', schemaIssueDetail('<root>'));
|
|
103
104
|
header = this.validateHeader(first.value.value, source);
|
|
104
105
|
}
|
|
105
106
|
const input = await this.openStream(source, byteCursor ?? undefined);
|
|
@@ -159,7 +160,7 @@ export class GenericSessionInterchangeAdapter {
|
|
|
159
160
|
};
|
|
160
161
|
}
|
|
161
162
|
if (!header) {
|
|
162
|
-
throw new SessionContractError('MALFORMED_SOURCE', 'generic interchange is empty');
|
|
163
|
+
throw new SessionContractError('MALFORMED_SOURCE', 'generic interchange is empty', schemaIssueDetail('<root>'));
|
|
163
164
|
}
|
|
164
165
|
if (input.incompleteTail) {
|
|
165
166
|
throw new SessionContractError('TRUNCATED_SOURCE', 'generic interchange contains a truncated record');
|
|
@@ -179,7 +180,10 @@ export class GenericSessionInterchangeAdapter {
|
|
|
179
180
|
const header = parseHeader(value);
|
|
180
181
|
assertSupportedSchemaMajor(header.schemaVersion);
|
|
181
182
|
if (header.sourceId !== source.sourceId) {
|
|
182
|
-
|
|
183
|
+
// SCHEMA_DRIFT: the selected identity no longer describes this file's
|
|
184
|
+
// declared source, so importing it would attach events to the wrong source.
|
|
185
|
+
throw new SessionContractError('SCHEMA_DRIFT', `selected source identity does not match interchange header: --source-id ${quoteValue(source.sourceId)} `
|
|
186
|
+
+ `but header sourceId is ${quoteValue(header.sourceId)}; pass --source-id ${quoteValue(header.sourceId)}`, schemaIssueDetail('sourceId'));
|
|
183
187
|
}
|
|
184
188
|
return header;
|
|
185
189
|
}
|
|
@@ -189,7 +193,7 @@ function parseByteCursor(value) {
|
|
|
189
193
|
return null;
|
|
190
194
|
const position = value.slice(5);
|
|
191
195
|
if (!/^\d+$/.test(position)) {
|
|
192
|
-
throw new SessionContractError('SCHEMA_DRIFT', 'invalid generic byte cursor');
|
|
196
|
+
throw new SessionContractError('SCHEMA_DRIFT', 'invalid generic byte cursor', schemaIssueDetail('cursor'));
|
|
193
197
|
}
|
|
194
198
|
return Number(position);
|
|
195
199
|
}
|
|
@@ -200,7 +204,10 @@ function parseHeader(value) {
|
|
|
200
204
|
if (hasAmbiguousTimestamp(result.error)) {
|
|
201
205
|
throw new SessionContractError('AMBIGUOUS_TIMESTAMP', 'generic interchange header has an ambiguous timestamp');
|
|
202
206
|
}
|
|
203
|
-
|
|
207
|
+
if (!isDeclaredInterchange(value)) {
|
|
208
|
+
throw new SessionContractError('MALFORMED_SOURCE', 'input is not a declared AIWG generic session interchange', schemaRejectionDetail(result.error));
|
|
209
|
+
}
|
|
210
|
+
throw new SessionContractError('MALFORMED_SOURCE', `generic interchange header ${describeIssue(result.error, true)}`, schemaRejectionDetail(result.error));
|
|
204
211
|
}
|
|
205
212
|
function parseEvent(value) {
|
|
206
213
|
const result = GenericInterchangeEventSchema.safeParse(value);
|
|
@@ -209,7 +216,34 @@ function parseEvent(value) {
|
|
|
209
216
|
if (hasAmbiguousTimestamp(result.error)) {
|
|
210
217
|
throw new SessionContractError('AMBIGUOUS_TIMESTAMP', 'generic interchange event has an ambiguous timestamp');
|
|
211
218
|
}
|
|
212
|
-
|
|
219
|
+
// Event values can carry transcript content, so name the field and the
|
|
220
|
+
// expected shape without echoing the received value.
|
|
221
|
+
throw new SessionContractError('MALFORMED_SOURCE', `generic interchange event is malformed: ${describeIssue(result.error, false)}`, schemaRejectionDetail(result.error));
|
|
222
|
+
}
|
|
223
|
+
function isDeclaredInterchange(value) {
|
|
224
|
+
return typeof value === 'object' && value !== null
|
|
225
|
+
&& value.type === GENERIC_INTERCHANGE_KIND;
|
|
226
|
+
}
|
|
227
|
+
function quoteValue(value) {
|
|
228
|
+
const text = typeof value === 'string' ? value : JSON.stringify(value) ?? String(value);
|
|
229
|
+
return JSON.stringify(text.length > 64 ? `${text.slice(0, 64)}…` : text);
|
|
230
|
+
}
|
|
231
|
+
function describeIssue(error, echoReceived) {
|
|
232
|
+
const issue = error.issues[0];
|
|
233
|
+
const field = issue.path.length > 0 ? `field "${issue.path.join('.')}"` : 'record';
|
|
234
|
+
if (issue.code === z.ZodIssueCode.invalid_enum_value) {
|
|
235
|
+
const received = echoReceived ? ` (got ${quoteValue(issue.received)})` : '';
|
|
236
|
+
return `${field} must be one of ${issue.options.join('|')}${received}`;
|
|
237
|
+
}
|
|
238
|
+
if (issue.code === z.ZodIssueCode.invalid_type) {
|
|
239
|
+
return issue.received === 'undefined'
|
|
240
|
+
? `${field} is required (${issue.expected})`
|
|
241
|
+
: `${field} must be ${issue.expected} (got ${issue.received})`;
|
|
242
|
+
}
|
|
243
|
+
if (issue.code === z.ZodIssueCode.invalid_literal) {
|
|
244
|
+
return `${field} must be ${quoteValue(issue.expected)}`;
|
|
245
|
+
}
|
|
246
|
+
return `${field} is invalid: ${issue.message}`;
|
|
213
247
|
}
|
|
214
248
|
function hasAmbiguousTimestamp(error) {
|
|
215
249
|
return error.issues.some((issue) => issue.code === z.ZodIssueCode.custom
|
|
@@ -219,7 +253,7 @@ function parseEventCursor(value) {
|
|
|
219
253
|
if (value === undefined || value === '')
|
|
220
254
|
return 0;
|
|
221
255
|
if (!/^\d+$/.test(value))
|
|
222
|
-
throw new SessionContractError('SCHEMA_DRIFT', 'generic event cursor is invalid');
|
|
256
|
+
throw new SessionContractError('SCHEMA_DRIFT', 'generic event cursor is invalid', schemaIssueDetail('cursor'));
|
|
223
257
|
return Number(value);
|
|
224
258
|
}
|
|
225
259
|
//# sourceMappingURL=generic.js.map
|