@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,128 @@
|
|
|
1
|
+
import { open } from 'node:fs/promises';
|
|
2
|
+
import { schemaIssueDetail, SessionContractError } from '../contracts.js';
|
|
3
|
+
import { authorizeSourceFile } from '../policy.js';
|
|
4
|
+
// Discovery inspects metadata, not an entire import. Bound allocation before
|
|
5
|
+
// assembling a line (readline would buffer an arbitrarily large single line).
|
|
6
|
+
export const MUSE_WORKSPACE_SCAN_LIMITS = Object.freeze({
|
|
7
|
+
maxRecords: 10_000,
|
|
8
|
+
maxRecordBytes: 8 * 1024 * 1024,
|
|
9
|
+
maxTotalBytes: 32 * 1024 * 1024,
|
|
10
|
+
maxNestingDepth: 64,
|
|
11
|
+
});
|
|
12
|
+
export const MUSE_WORKSPACE_TAIL_BYTES = 1024 * 1024;
|
|
13
|
+
export class MuseWorkspaceLimitError extends SessionContractError {
|
|
14
|
+
limitName;
|
|
15
|
+
limitValue;
|
|
16
|
+
constructor(limitName, limitValue, observed) {
|
|
17
|
+
super('RESOURCE_LIMIT_EXCEEDED', `Muse workspace inspection exceeded ${limitName}=${limitValue}`, { limit: limitName, configured: limitValue, observed });
|
|
18
|
+
this.limitName = limitName;
|
|
19
|
+
this.limitValue = limitValue;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
export async function* museWorkspaceScanLines(authorization, limits, progress, tailBytes) {
|
|
23
|
+
const allowed = await authorizeSourceFile(authorization);
|
|
24
|
+
const handle = await open(allowed.canonicalPath, 'r');
|
|
25
|
+
try {
|
|
26
|
+
const buffer = Buffer.allocUnsafe(64 * 1024);
|
|
27
|
+
let position = tailBytes === undefined ? 0 : Math.max(0, allowed.size - tailBytes);
|
|
28
|
+
// A tail window may start inside a record (or a UTF-8 code point).
|
|
29
|
+
// Discard that fragment before parsing any complete JSONL records.
|
|
30
|
+
let skipPartialLine = position > 0;
|
|
31
|
+
let parts = [];
|
|
32
|
+
let length = 0;
|
|
33
|
+
while (position < allowed.size) {
|
|
34
|
+
const remaining = limits.maxTotalBytes - progress.bytesInspected;
|
|
35
|
+
if (remaining <= 0)
|
|
36
|
+
throw scanLimit('maxTotalBytes', limits.maxTotalBytes, allowed.size);
|
|
37
|
+
const { bytesRead } = await handle.read(buffer, 0, Math.min(buffer.length, allowed.size - position, remaining), position);
|
|
38
|
+
if (bytesRead === 0) {
|
|
39
|
+
throw new SessionContractError('TRUNCATED_SOURCE', 'Muse source changed during inspection');
|
|
40
|
+
}
|
|
41
|
+
position += bytesRead;
|
|
42
|
+
let start = 0;
|
|
43
|
+
while (start < bytesRead) {
|
|
44
|
+
const newline = buffer.indexOf(10, start);
|
|
45
|
+
const end = newline >= 0 && newline < bytesRead ? newline + 1 : bytesRead;
|
|
46
|
+
const segment = buffer.subarray(start, end);
|
|
47
|
+
if (skipPartialLine) {
|
|
48
|
+
progress.bytesInspected += segment.length;
|
|
49
|
+
start = end;
|
|
50
|
+
if (newline >= 0 && newline < bytesRead)
|
|
51
|
+
skipPartialLine = false;
|
|
52
|
+
continue;
|
|
53
|
+
}
|
|
54
|
+
if (length + segment.length > limits.maxRecordBytes)
|
|
55
|
+
throw scanLimit('maxRecordBytes', limits.maxRecordBytes, length + segment.length);
|
|
56
|
+
parts.push(Buffer.from(segment));
|
|
57
|
+
length += segment.length;
|
|
58
|
+
progress.bytesInspected += segment.length;
|
|
59
|
+
start = end;
|
|
60
|
+
if (newline >= 0 && newline < bytesRead) {
|
|
61
|
+
const line = Buffer.concat(parts, length).toString('utf8');
|
|
62
|
+
parts = [];
|
|
63
|
+
length = 0;
|
|
64
|
+
if (line.trim() !== '') {
|
|
65
|
+
if (progress.recordsInspected >= limits.maxRecords)
|
|
66
|
+
throw scanLimit('maxRecords', limits.maxRecords, progress.recordsInspected + 1);
|
|
67
|
+
const value = parseMuseScanJson(line, limits.maxNestingDepth);
|
|
68
|
+
progress.recordsInspected += 1;
|
|
69
|
+
yield value;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
if (length > 0) {
|
|
75
|
+
const line = Buffer.concat(parts, length).toString('utf8');
|
|
76
|
+
if (line.trim() !== '') {
|
|
77
|
+
if (progress.recordsInspected >= limits.maxRecords)
|
|
78
|
+
throw scanLimit('maxRecords', limits.maxRecords, progress.recordsInspected + 1);
|
|
79
|
+
let value;
|
|
80
|
+
try {
|
|
81
|
+
value = parseMuseScanJson(line, limits.maxNestingDepth);
|
|
82
|
+
}
|
|
83
|
+
catch (error) {
|
|
84
|
+
if (error instanceof SessionContractError && error.code === 'MALFORMED_SOURCE') {
|
|
85
|
+
throw new SessionContractError('TRUNCATED_SOURCE', 'Muse source has an incomplete JSONL tail');
|
|
86
|
+
}
|
|
87
|
+
throw error;
|
|
88
|
+
}
|
|
89
|
+
progress.recordsInspected += 1;
|
|
90
|
+
yield value;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
const after = await handle.stat();
|
|
94
|
+
if (after.size !== allowed.size || after.mtimeMs !== allowed.mtimeMs) {
|
|
95
|
+
throw new SessionContractError('TRUNCATED_SOURCE', 'Muse source changed during inspection');
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
finally {
|
|
99
|
+
await handle.close();
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
export function parseMuseScanJson(line, maxDepth) {
|
|
103
|
+
let value;
|
|
104
|
+
try {
|
|
105
|
+
value = JSON.parse(line);
|
|
106
|
+
}
|
|
107
|
+
catch {
|
|
108
|
+
throw new SessionContractError('MALFORMED_SOURCE', 'Muse inspection encountered malformed JSON', schemaIssueDetail('<root>', 'invalid_json'));
|
|
109
|
+
}
|
|
110
|
+
// Check depth iteratively, including decoded retained children, before zod
|
|
111
|
+
// validation. Deep input must produce a limit diagnostic, not stack overflow.
|
|
112
|
+
const pending = [{ value, depth: 0 }];
|
|
113
|
+
while (pending.length > 0) {
|
|
114
|
+
const current = pending.pop();
|
|
115
|
+
if (current.depth > maxDepth)
|
|
116
|
+
throw scanLimit('maxNestingDepth', maxDepth, current.depth);
|
|
117
|
+
if (current.value !== null && typeof current.value === 'object') {
|
|
118
|
+
for (const child of Object.values(current.value)) {
|
|
119
|
+
pending.push({ value: child, depth: current.depth + 1 });
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
return value;
|
|
124
|
+
}
|
|
125
|
+
function scanLimit(limit, configured, observed) {
|
|
126
|
+
return new MuseWorkspaceLimitError(limit, configured, observed);
|
|
127
|
+
}
|
|
128
|
+
//# sourceMappingURL=muse-workspace-scan.js.map
|
|
@@ -42,8 +42,10 @@
|
|
|
42
42
|
import { opendir } from 'node:fs/promises';
|
|
43
43
|
import { resolve } from 'node:path';
|
|
44
44
|
import { z } from 'zod';
|
|
45
|
-
import {
|
|
46
|
-
import {
|
|
45
|
+
import { matchSessionWorkspace, WORKSPACE_MATCH_KINDS } from '../workspace-matching.js';
|
|
46
|
+
import { schemaRejectionDetail, schemaIssueDetail, SessionContractError, SessionErrorCodeSchema, SessionRejectionDetailSchema, assertSupportedSchemaMajor, } from '../contracts.js';
|
|
47
|
+
import { readBoundedJson, streamBoundedJsonLines, } from '../readers.js';
|
|
48
|
+
import { MUSE_WORKSPACE_SCAN_LIMITS, MUSE_WORKSPACE_TAIL_BYTES, MuseWorkspaceLimitError, museWorkspaceScanLines, parseMuseScanJson, } from './muse-workspace-scan.js';
|
|
47
49
|
export const MUSE_ADAPTER_VERSION = '1.0.0';
|
|
48
50
|
export const MUSE_EXPORT_SCHEMA_VERSION = '1.0.0';
|
|
49
51
|
export const MUSE_EXPORT_SCHEMA_MAJOR = 1;
|
|
@@ -79,7 +81,9 @@ const MuseEnvelopeSchema = z.object({
|
|
|
79
81
|
durability: z.string().optional(),
|
|
80
82
|
payload_type: z.string().optional(),
|
|
81
83
|
payload: z.object({
|
|
82
|
-
|
|
84
|
+
// Muse Code 1.4.3 runtime.session mode records carry an event without a
|
|
85
|
+
// kind; eventKindOf() falls back to payload_type for those.
|
|
86
|
+
event: z.object({ kind: z.string().min(1).optional() }).passthrough().optional(),
|
|
83
87
|
}).passthrough().optional(),
|
|
84
88
|
}).passthrough();
|
|
85
89
|
/**
|
|
@@ -170,7 +174,7 @@ export class MuseSessionAdapter {
|
|
|
170
174
|
for (const root of [...scope.allowedRoots].sort()) {
|
|
171
175
|
for await (const locator of museNativeSessionLogs(resolve(root))) {
|
|
172
176
|
if (++count > this.maxFiles) {
|
|
173
|
-
throw new SessionContractError('RESOURCE_LIMIT_EXCEEDED', 'Muse native session discovery exceeded the authorized file limit');
|
|
177
|
+
throw new SessionContractError('RESOURCE_LIMIT_EXCEEDED', 'Muse native session discovery exceeded the authorized file limit', { limit: 'maxFiles', configured: this.maxFiles, observed: count });
|
|
174
178
|
}
|
|
175
179
|
yield { provider: 'muse', locator, locatorClass: MUSE_NATIVE_LOCATOR_CLASS };
|
|
176
180
|
}
|
|
@@ -200,7 +204,7 @@ export class MuseSessionAdapter {
|
|
|
200
204
|
const native = await this.readNative(source);
|
|
201
205
|
const start = parseEventCursor(cursor?.value);
|
|
202
206
|
let outputIndex = 0;
|
|
203
|
-
for (const record of
|
|
207
|
+
for await (const record of this.readNativeRecords(source)) {
|
|
204
208
|
const position = outputIndex;
|
|
205
209
|
outputIndex += 1;
|
|
206
210
|
if (position < start)
|
|
@@ -251,13 +255,13 @@ export class MuseSessionAdapter {
|
|
|
251
255
|
}
|
|
252
256
|
catch (error) {
|
|
253
257
|
if (error instanceof SessionContractError && error.code === 'SCHEMA_DRIFT') {
|
|
254
|
-
throw new SessionContractError('MALFORMED_SOURCE', 'muse export document is not valid JSON');
|
|
258
|
+
throw new SessionContractError('MALFORMED_SOURCE', 'muse export document is not valid JSON', error.detail);
|
|
255
259
|
}
|
|
256
260
|
throw error;
|
|
257
261
|
}
|
|
258
262
|
const parsed = MuseTrajectorySchema.safeParse(value);
|
|
259
263
|
if (!parsed.success) {
|
|
260
|
-
throw new SessionContractError('MALFORMED_SOURCE', 'input is not a declared muse export trajectory document');
|
|
264
|
+
throw new SessionContractError('MALFORMED_SOURCE', 'input is not a declared muse export trajectory document', schemaRejectionDetail(parsed.error));
|
|
261
265
|
}
|
|
262
266
|
assertSupportedSchemaMajor(`${parsed.data.export_schema_version}.0.0`, MUSE_EXPORT_SCHEMA_MAJOR);
|
|
263
267
|
return { trajectory: parsed.data, bytesRead };
|
|
@@ -330,80 +334,89 @@ export class MuseSessionAdapter {
|
|
|
330
334
|
};
|
|
331
335
|
}
|
|
332
336
|
async readNative(source) {
|
|
333
|
-
this.
|
|
334
|
-
let
|
|
337
|
+
const records = this.readNativeRecords(source);
|
|
338
|
+
let result = await records.next();
|
|
339
|
+
while (!result.done)
|
|
340
|
+
result = await records.next();
|
|
341
|
+
return result.value;
|
|
342
|
+
}
|
|
343
|
+
async *readNativeRecords(source) {
|
|
335
344
|
try {
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
for (const line of input.records) {
|
|
349
|
-
const value = line.value;
|
|
350
|
-
if (isOmissionMarker(value)) {
|
|
351
|
-
diagnostics.omitted_records = (diagnostics.omitted_records ?? 0) + 1;
|
|
352
|
-
if (asObject(value).retained_marker === 'omitted_live_only') {
|
|
353
|
-
diagnostics.omitted_live_only = (diagnostics.omitted_live_only ?? 0) + 1;
|
|
354
|
-
}
|
|
355
|
-
continue;
|
|
356
|
-
}
|
|
357
|
-
const retained = MuseRetainedFrameSchema.safeParse(value);
|
|
358
|
-
if (retained.success) {
|
|
359
|
-
diagnostics.retained_frames = (diagnostics.retained_frames ?? 0) + 1;
|
|
360
|
-
for (const child of retained.data.children) {
|
|
361
|
-
let decoded;
|
|
362
|
-
try {
|
|
363
|
-
decoded = JSON.parse(child.record_json);
|
|
345
|
+
this.assertSupportedLocator(source);
|
|
346
|
+
const input = await streamBoundedJsonLines({ selectedPath: source.locator, allowedRoots: source.authorizedScope.allowedRoots }, { consistency: 'complete', limits: this.limits });
|
|
347
|
+
const diagnostics = {};
|
|
348
|
+
let records = 0;
|
|
349
|
+
let fallbackSessionId = nativeSessionIdFromLocator(source.locator) ?? source.sourceId;
|
|
350
|
+
let complete = false;
|
|
351
|
+
for await (const line of input) {
|
|
352
|
+
const value = line.value;
|
|
353
|
+
if (isOmissionMarker(value)) {
|
|
354
|
+
diagnostics.omitted_records = (diagnostics.omitted_records ?? 0) + 1;
|
|
355
|
+
if (asObject(value).retained_marker === 'omitted_live_only') {
|
|
356
|
+
diagnostics.omitted_live_only = (diagnostics.omitted_live_only ?? 0) + 1;
|
|
364
357
|
}
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
358
|
+
continue;
|
|
359
|
+
}
|
|
360
|
+
const retained = MuseRetainedFrameSchema.safeParse(value);
|
|
361
|
+
if (retained.success) {
|
|
362
|
+
diagnostics.retained_frames = (diagnostics.retained_frames ?? 0) + 1;
|
|
363
|
+
for (const child of retained.data.children) {
|
|
364
|
+
let decoded;
|
|
365
|
+
try {
|
|
366
|
+
decoded = JSON.parse(child.record_json);
|
|
367
|
+
}
|
|
368
|
+
catch {
|
|
369
|
+
throw new SessionContractError('MALFORMED_SOURCE', 'Muse retained frame child record is malformed JSON', schemaIssueDetail('children.record_json', 'invalid_json'));
|
|
370
|
+
}
|
|
371
|
+
const envelope = MuseEnvelopeSchema.safeParse(decoded);
|
|
372
|
+
if (!envelope.success) {
|
|
373
|
+
throw new SessionContractError('MALFORMED_SOURCE', 'Muse retained frame child record is malformed', schemaRejectionDetail(envelope.error));
|
|
374
|
+
}
|
|
375
|
+
const event = { kind: 'record', envelope: envelope.data };
|
|
376
|
+
fallbackSessionId = streamSessionIdOf(event.envelope) ?? fallbackSessionId;
|
|
377
|
+
complete ||= event.envelope.payload_type === 'session.end';
|
|
378
|
+
diagnostics.retained_frame_children = (diagnostics.retained_frame_children ?? 0) + 1;
|
|
379
|
+
records += 1;
|
|
380
|
+
yield {
|
|
381
|
+
event,
|
|
382
|
+
line,
|
|
383
|
+
retainedFrame: retained.data.retained_frame,
|
|
384
|
+
retainedChildIndex: child.child_index,
|
|
385
|
+
};
|
|
371
386
|
}
|
|
372
|
-
|
|
373
|
-
complete ||= event.envelope.payload_type === 'session.end';
|
|
374
|
-
diagnostics.retained_frame_children = (diagnostics.retained_frame_children ?? 0) + 1;
|
|
375
|
-
records.push({
|
|
376
|
-
event,
|
|
377
|
-
line,
|
|
378
|
-
retainedFrame: retained.data.retained_frame,
|
|
379
|
-
retainedChildIndex: child.child_index,
|
|
380
|
-
});
|
|
387
|
+
continue;
|
|
381
388
|
}
|
|
382
|
-
|
|
389
|
+
const envelope = MuseEnvelopeSchema.safeParse(value);
|
|
390
|
+
if (!envelope.success) {
|
|
391
|
+
throw new SessionContractError('MALFORMED_SOURCE', 'Muse native session log line is not a supported record shape', schemaRejectionDetail('retained_frame' in asObject(value) ? retained.error : envelope.error));
|
|
392
|
+
}
|
|
393
|
+
const event = { kind: 'record', envelope: envelope.data };
|
|
394
|
+
fallbackSessionId = streamSessionIdOf(event.envelope) ?? fallbackSessionId;
|
|
395
|
+
complete ||= event.envelope.payload_type === 'session.end';
|
|
396
|
+
records += 1;
|
|
397
|
+
yield { event, line };
|
|
383
398
|
}
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
throw new SessionContractError('MALFORMED_SOURCE', 'Muse native session log line is not a supported record shape');
|
|
399
|
+
if (records === 0) {
|
|
400
|
+
throw new SessionContractError('MALFORMED_SOURCE', 'Muse native session log contains no record envelopes', schemaIssueDetail('<root>'));
|
|
387
401
|
}
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
402
|
+
return {
|
|
403
|
+
complete,
|
|
404
|
+
context: {
|
|
405
|
+
locatorClass: MUSE_NATIVE_LOCATOR_CLASS,
|
|
406
|
+
sourceLabel: 'muse native session log',
|
|
407
|
+
bytesRead: input.bytesRead,
|
|
408
|
+
fallbackSessionId,
|
|
409
|
+
spawns: new Map(),
|
|
410
|
+
diagnostics,
|
|
411
|
+
},
|
|
412
|
+
};
|
|
391
413
|
}
|
|
392
|
-
|
|
393
|
-
|
|
414
|
+
catch (error) {
|
|
415
|
+
if (error instanceof SessionContractError && error.code === 'SCHEMA_DRIFT') {
|
|
416
|
+
throw new SessionContractError('MALFORMED_SOURCE', 'Muse native session log contains malformed JSONL', error.detail);
|
|
417
|
+
}
|
|
418
|
+
throw error;
|
|
394
419
|
}
|
|
395
|
-
return {
|
|
396
|
-
records,
|
|
397
|
-
complete,
|
|
398
|
-
context: {
|
|
399
|
-
locatorClass: MUSE_NATIVE_LOCATOR_CLASS,
|
|
400
|
-
sourceLabel: 'muse native session log',
|
|
401
|
-
bytesRead: input.bytesRead,
|
|
402
|
-
fallbackSessionId,
|
|
403
|
-
spawns: new Map(),
|
|
404
|
-
diagnostics,
|
|
405
|
-
},
|
|
406
|
-
};
|
|
407
420
|
}
|
|
408
421
|
assertSupportedLocator(source) {
|
|
409
422
|
if (source.locatorClass !== MUSE_LOCATOR_CLASS && source.locatorClass !== MUSE_NATIVE_LOCATOR_CLASS) {
|
|
@@ -495,44 +508,130 @@ async function* museNativeSessionLogs(root) {
|
|
|
495
508
|
}
|
|
496
509
|
}
|
|
497
510
|
}
|
|
498
|
-
export
|
|
499
|
-
|
|
511
|
+
export const MuseWorkspaceInspectionSchema = z.object({
|
|
512
|
+
outcome: z.enum(['matched', 'mismatch', 'inconclusive']),
|
|
513
|
+
attribution: z.enum(['matched', 'mismatch', 'unattributed']),
|
|
514
|
+
matchKind: z.enum(WORKSPACE_MATCH_KINDS).optional(),
|
|
515
|
+
reasonCode: z.string().nullable(),
|
|
516
|
+
recordsInspected: z.number().int().nonnegative(),
|
|
517
|
+
bytesInspected: z.number().int().nonnegative(),
|
|
518
|
+
completeInspection: z.boolean(),
|
|
519
|
+
limit: z.object({
|
|
520
|
+
name: z.enum(['maxRecords', 'maxRecordBytes', 'maxTotalBytes', 'maxNestingDepth']),
|
|
521
|
+
value: z.number().int().positive(),
|
|
522
|
+
}).optional(),
|
|
523
|
+
fallback: z.literal('bounded-tail').optional(),
|
|
524
|
+
detail: SessionRejectionDetailSchema.optional(),
|
|
525
|
+
});
|
|
526
|
+
/** Positive metadata evidence selects a source; import validates its full history. */
|
|
527
|
+
export async function inspectMuseNativeWorkspace(source, workspacePath, limitsInput) {
|
|
528
|
+
const limits = { ...MUSE_WORKSPACE_SCAN_LIMITS, ...limitsInput };
|
|
529
|
+
const progress = { recordsInspected: 0, bytesInspected: 0 };
|
|
530
|
+
let sawWorkspaceEvidence = false;
|
|
531
|
+
let retainedChildren = 0;
|
|
532
|
+
let limit;
|
|
533
|
+
let fallback;
|
|
534
|
+
const authorization = { selectedPath: source.locator, allowedRoots: source.authorizedScope.allowedRoots };
|
|
535
|
+
const receipt = (outcome, reasonCode, completeInspection = false) => ({
|
|
536
|
+
outcome, attribution: outcome === 'inconclusive' ? 'unattributed' : outcome,
|
|
537
|
+
reasonCode, ...progress, completeInspection,
|
|
538
|
+
...(limit ? { limit } : {}), ...(fallback ? { fallback } : {}),
|
|
539
|
+
});
|
|
540
|
+
const envelopesFromLine = (value) => nativeEnvelopesFromLine(value, limits, (count) => {
|
|
541
|
+
retainedChildren += count;
|
|
542
|
+
if (retainedChildren > limits.maxRecords) {
|
|
543
|
+
throw new MuseWorkspaceLimitError('maxRecords', limits.maxRecords, retainedChildren);
|
|
544
|
+
}
|
|
545
|
+
});
|
|
500
546
|
try {
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
547
|
+
if ([limits.maxRecords, limits.maxRecordBytes, limits.maxTotalBytes, limits.maxNestingDepth]
|
|
548
|
+
.some((limit) => !Number.isSafeInteger(limit) || limit <= 0)) {
|
|
549
|
+
throw new SessionContractError('INVALID_ARGUMENT', 'Muse inspection limits must be positive safe integers');
|
|
550
|
+
}
|
|
551
|
+
for await (const value of museWorkspaceScanLines(authorization, limits, progress)) {
|
|
552
|
+
const envelopes = envelopesFromLine(value);
|
|
553
|
+
for (const envelope of envelopes) {
|
|
554
|
+
const candidate = workspaceEvidenceOf(envelope);
|
|
555
|
+
if (!candidate)
|
|
556
|
+
continue;
|
|
557
|
+
sawWorkspaceEvidence = true;
|
|
558
|
+
const matchKind = await matchSessionWorkspace(candidate, workspacePath);
|
|
559
|
+
if (matchKind)
|
|
560
|
+
return { ...receipt('matched', null), matchKind };
|
|
561
|
+
}
|
|
562
|
+
}
|
|
563
|
+
return sawWorkspaceEvidence
|
|
564
|
+
? receipt('mismatch', 'MUSE_WORKSPACE_MISMATCH', true)
|
|
565
|
+
: receipt('inconclusive', 'MUSE_WORKSPACE_EVIDENCE_ABSENT', true);
|
|
505
566
|
}
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
567
|
+
catch (error) {
|
|
568
|
+
if (error instanceof MuseWorkspaceLimitError) {
|
|
569
|
+
limit = { name: error.limitName, value: error.limitValue };
|
|
570
|
+
fallback = 'bounded-tail';
|
|
571
|
+
const tailProgress = { recordsInspected: 0, bytesInspected: 0 };
|
|
572
|
+
const tailBytes = Math.min(MUSE_WORKSPACE_TAIL_BYTES, limits.maxTotalBytes);
|
|
573
|
+
retainedChildren = 0;
|
|
574
|
+
let matchKind;
|
|
575
|
+
try {
|
|
576
|
+
for await (const value of museWorkspaceScanLines(authorization, { ...limits, maxTotalBytes: tailBytes }, tailProgress, tailBytes)) {
|
|
577
|
+
for (const envelope of envelopesFromLine(value)) {
|
|
578
|
+
const candidate = workspaceEvidenceOf(envelope);
|
|
579
|
+
if (!candidate)
|
|
580
|
+
continue;
|
|
581
|
+
matchKind = await matchSessionWorkspace(candidate, workspacePath);
|
|
582
|
+
if (matchKind)
|
|
583
|
+
break;
|
|
584
|
+
}
|
|
585
|
+
if (matchKind)
|
|
586
|
+
break;
|
|
587
|
+
}
|
|
588
|
+
}
|
|
589
|
+
catch {
|
|
590
|
+
// Preserve the original limit receipt when the fallback cannot attribute.
|
|
591
|
+
}
|
|
592
|
+
progress.recordsInspected += tailProgress.recordsInspected;
|
|
593
|
+
progress.bytesInspected += tailProgress.bytesInspected;
|
|
594
|
+
if (matchKind)
|
|
595
|
+
return { ...receipt('matched', null), matchKind };
|
|
513
596
|
}
|
|
597
|
+
return {
|
|
598
|
+
...receipt('inconclusive', error instanceof SessionContractError
|
|
599
|
+
? error.code : 'MUSE_SOURCE_UNREADABLE'),
|
|
600
|
+
...(error instanceof SessionContractError && error.detail ? { detail: error.detail } : {}),
|
|
601
|
+
};
|
|
602
|
+
}
|
|
603
|
+
}
|
|
604
|
+
export async function museNativeSourceMatchesWorkspace(source, workspacePath) {
|
|
605
|
+
const result = await inspectMuseNativeWorkspace(source, workspacePath);
|
|
606
|
+
if (result.outcome === 'inconclusive') {
|
|
607
|
+
const code = SessionErrorCodeSchema.safeParse(result.reasonCode);
|
|
608
|
+
throw new SessionContractError(code.success ? code.data : 'SCHEMA_DRIFT', `Muse workspace inspection inconclusive: ${result.reasonCode}`, result.detail);
|
|
514
609
|
}
|
|
515
|
-
return
|
|
610
|
+
return result.outcome === 'matched';
|
|
516
611
|
}
|
|
517
|
-
function nativeEnvelopesFromLine(value) {
|
|
612
|
+
function nativeEnvelopesFromLine(value, limits, countChildren) {
|
|
518
613
|
if (isOmissionMarker(value))
|
|
519
614
|
return [];
|
|
520
|
-
const event = recordEventFromEnvelope(value);
|
|
521
|
-
if (event)
|
|
522
|
-
return [event.envelope];
|
|
523
615
|
const retained = MuseRetainedFrameSchema.safeParse(value);
|
|
524
|
-
if (!retained.success)
|
|
525
|
-
|
|
616
|
+
if (!retained.success) {
|
|
617
|
+
if (value === null || typeof value !== 'object' || Array.isArray(value)) {
|
|
618
|
+
throw new SessionContractError('MALFORMED_SOURCE', 'Muse inspection encountered a non-object native record', schemaIssueDetail('<root>'));
|
|
619
|
+
}
|
|
620
|
+
// Native logs carry record kinds the envelope schema does not model (for
|
|
621
|
+
// example runtime.session mode changes without payload.event.kind). They
|
|
622
|
+
// hold no workspace evidence, so skip them rather than fail the source.
|
|
623
|
+
const event = recordEventFromEnvelope(value);
|
|
624
|
+
return event ? [event.envelope] : [];
|
|
625
|
+
}
|
|
626
|
+
countChildren(retained.data.children.length);
|
|
526
627
|
const envelopes = [];
|
|
527
628
|
for (const child of retained.data.children) {
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
if (childEvent)
|
|
531
|
-
envelopes.push(childEvent.envelope);
|
|
532
|
-
}
|
|
533
|
-
catch {
|
|
534
|
-
return [];
|
|
629
|
+
if (Buffer.byteLength(child.record_json) > limits.maxRecordBytes) {
|
|
630
|
+
throw new MuseWorkspaceLimitError('maxRecordBytes', limits.maxRecordBytes, Buffer.byteLength(child.record_json));
|
|
535
631
|
}
|
|
632
|
+
const childEvent = recordEventFromEnvelope(parseMuseScanJson(child.record_json, limits.maxNestingDepth));
|
|
633
|
+
if (childEvent)
|
|
634
|
+
envelopes.push(childEvent.envelope);
|
|
536
635
|
}
|
|
537
636
|
return envelopes;
|
|
538
637
|
}
|
|
@@ -554,9 +653,6 @@ function workspaceEvidenceOf(envelope) {
|
|
|
554
653
|
}
|
|
555
654
|
return null;
|
|
556
655
|
}
|
|
557
|
-
function workspacePathEquals(candidate, workspacePath) {
|
|
558
|
-
return resolve(candidate) === workspacePath;
|
|
559
|
-
}
|
|
560
656
|
function nativeSessionIdFromLocator(locator) {
|
|
561
657
|
const parts = locator.replaceAll('\\', '/').split('/');
|
|
562
658
|
const leaf = parts.at(-1);
|
|
@@ -703,7 +799,7 @@ function parseEventCursor(value) {
|
|
|
703
799
|
if (value === undefined || value === '')
|
|
704
800
|
return 0;
|
|
705
801
|
if (!/^\d+$/.test(value))
|
|
706
|
-
throw new SessionContractError('SCHEMA_DRIFT', 'muse event cursor is invalid');
|
|
802
|
+
throw new SessionContractError('SCHEMA_DRIFT', 'muse event cursor is invalid', schemaIssueDetail('cursor'));
|
|
707
803
|
return Number(value);
|
|
708
804
|
}
|
|
709
805
|
//# sourceMappingURL=muse.js.map
|
|
@@ -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 OMP_ADAPTER_VERSION = '1.0.0';
|
|
7
7
|
export const OMP_SOURCE_SCHEMA_VERSION = '3.0.0';
|
|
8
8
|
const Title = z.object({ type: z.literal('title'), v: z.literal(1), title: z.string(), source: z.enum(['auto', 'user']).optional(), updatedAt: z.string(), pad: z.string() });
|
|
@@ -30,7 +30,7 @@ export class OmpSessionAdapter {
|
|
|
30
30
|
for (const root of [...scope.allowedRoots].sort()) {
|
|
31
31
|
for await (const locator of jsonlFiles(resolve(root))) {
|
|
32
32
|
if (++count > this.maxFiles)
|
|
33
|
-
throw new SessionContractError('RESOURCE_LIMIT_EXCEEDED', 'OMP discovery file limit exceeded');
|
|
33
|
+
throw new SessionContractError('RESOURCE_LIMIT_EXCEEDED', 'OMP discovery file limit exceeded', { limit: 'maxFiles', configured: this.maxFiles, observed: count });
|
|
34
34
|
yield { provider: 'omp', locator, locatorClass: 'omp-session-v3-jsonl' };
|
|
35
35
|
}
|
|
36
36
|
}
|
|
@@ -38,13 +38,23 @@ export class OmpSessionAdapter {
|
|
|
38
38
|
async inspect(source) {
|
|
39
39
|
let input;
|
|
40
40
|
try {
|
|
41
|
-
input = await
|
|
41
|
+
input = await streamBoundedJsonLines({ selectedPath: source.locator,
|
|
42
42
|
allowedRoots: source.authorizedScope.allowedRoots }, { consistency: 'provisional', limits: this.limits });
|
|
43
43
|
}
|
|
44
44
|
catch (error) {
|
|
45
45
|
throw normalizeAuthorizationError(error);
|
|
46
46
|
}
|
|
47
|
-
|
|
47
|
+
let header;
|
|
48
|
+
let prefix = true;
|
|
49
|
+
for await (const line of input) {
|
|
50
|
+
if (prefix) {
|
|
51
|
+
prefix = false;
|
|
52
|
+
if (titleOffset(line))
|
|
53
|
+
continue;
|
|
54
|
+
}
|
|
55
|
+
header ??= parseHeader(line.value);
|
|
56
|
+
}
|
|
57
|
+
header ??= parseHeader(undefined);
|
|
48
58
|
if (input.incompleteTail)
|
|
49
59
|
throw new SessionContractError('TRUNCATED_SOURCE', 'OMP session has a truncated JSONL tail');
|
|
50
60
|
return { sourceSchemaVersion: `${header.version}.0.0`, consistency: 'complete', operationalState: 'available' };
|
|
@@ -63,13 +73,13 @@ export class OmpSessionAdapter {
|
|
|
63
73
|
let prefix = true;
|
|
64
74
|
const start = cursor?.value.replace(/^byte:/, '') ?? '0';
|
|
65
75
|
if (!/^\d+$/.test(start))
|
|
66
|
-
throw new SessionContractError('SCHEMA_DRIFT', 'invalid OMP cursor');
|
|
76
|
+
throw new SessionContractError('SCHEMA_DRIFT', 'invalid OMP cursor', schemaIssueDetail('cursor'));
|
|
67
77
|
let end = 0;
|
|
68
78
|
const ids = new Set();
|
|
69
79
|
for await (const line of input) {
|
|
70
80
|
end = line.byteOffset + line.byteLength;
|
|
71
81
|
if (Number(start) > line.byteOffset && Number(start) < end) {
|
|
72
|
-
throw new SessionContractError('SCHEMA_DRIFT', 'OMP cursor is not a record boundary');
|
|
82
|
+
throw new SessionContractError('SCHEMA_DRIFT', 'OMP cursor is not a record boundary', schemaIssueDetail('cursor'));
|
|
73
83
|
}
|
|
74
84
|
if (prefix) {
|
|
75
85
|
prefix = false;
|
|
@@ -83,7 +93,7 @@ export class OmpSessionAdapter {
|
|
|
83
93
|
}
|
|
84
94
|
const parsed = Entry.safeParse(line.value);
|
|
85
95
|
if (!parsed.success)
|
|
86
|
-
throw new SessionContractError('MALFORMED_SOURCE', 'OMP session entry is malformed');
|
|
96
|
+
throw new SessionContractError('MALFORMED_SOURCE', 'OMP session entry is malformed', schemaRejectionDetail(parsed.error));
|
|
87
97
|
const entry = parsed.data;
|
|
88
98
|
if (ids.has(entry.id))
|
|
89
99
|
throw new SessionContractError('DUPLICATE_NATIVE_ID', 'OMP session contains a duplicate entry id');
|
|
@@ -107,9 +117,9 @@ export class OmpSessionAdapter {
|
|
|
107
117
|
nativeType: entry.type, parentId: entry.parentId, ...metadata(entry, message) } };
|
|
108
118
|
}
|
|
109
119
|
if (!sessionId)
|
|
110
|
-
throw new SessionContractError('MALFORMED_SOURCE', 'OMP session header is missing');
|
|
120
|
+
throw new SessionContractError('MALFORMED_SOURCE', 'OMP session header is missing', schemaIssueDetail('header'));
|
|
111
121
|
if (Number(start) > end)
|
|
112
|
-
throw new SessionContractError('SCHEMA_DRIFT', 'OMP cursor exceeds source size');
|
|
122
|
+
throw new SessionContractError('SCHEMA_DRIFT', 'OMP cursor exceeds source size', schemaIssueDetail('cursor'));
|
|
113
123
|
if (input.incompleteTail)
|
|
114
124
|
throw new SessionContractError('TRUNCATED_SOURCE', 'OMP session has a truncated JSONL tail');
|
|
115
125
|
}
|
|
@@ -125,7 +135,7 @@ const KNOWN = new Set(['message', 'thinking_level_change', 'model_change', 'comp
|
|
|
125
135
|
function parseHeader(value) {
|
|
126
136
|
const parsed = Header.safeParse(value);
|
|
127
137
|
if (!parsed.success)
|
|
128
|
-
throw new SessionContractError('MALFORMED_SOURCE', 'OMP session header is malformed');
|
|
138
|
+
throw new SessionContractError('MALFORMED_SOURCE', 'OMP session header is malformed', schemaRejectionDetail(parsed.error));
|
|
129
139
|
if (parsed.data.version !== 3)
|
|
130
140
|
throw new SessionContractError('UNKNOWN_SCHEMA_MAJOR', `unsupported OMP session version: ${parsed.data.version}`);
|
|
131
141
|
return parsed.data;
|
|
@@ -168,8 +178,12 @@ function normalizeAuthorizationError(error) {
|
|
|
168
178
|
function titleOffset(line) {
|
|
169
179
|
if (object(line?.value).type !== 'title')
|
|
170
180
|
return 0;
|
|
171
|
-
|
|
172
|
-
|
|
181
|
+
const parsed = Title.safeParse(line?.value);
|
|
182
|
+
if (!parsed.success) {
|
|
183
|
+
throw new SessionContractError('MALFORMED_SOURCE', 'OMP title slot is malformed', schemaRejectionDetail(parsed.error));
|
|
184
|
+
}
|
|
185
|
+
if (line?.byteLength !== 256) {
|
|
186
|
+
throw new SessionContractError('MALFORMED_SOURCE', 'OMP title slot is malformed', schemaIssueDetail('title'));
|
|
173
187
|
}
|
|
174
188
|
return 256;
|
|
175
189
|
}
|
|
@@ -198,6 +212,6 @@ export async function readOmpSessionHeader(source) {
|
|
|
198
212
|
}
|
|
199
213
|
return parseHeader(line.value);
|
|
200
214
|
}
|
|
201
|
-
throw new SessionContractError('MALFORMED_SOURCE', 'OMP header is missing');
|
|
215
|
+
throw new SessionContractError('MALFORMED_SOURCE', 'OMP header is missing', schemaIssueDetail('header'));
|
|
202
216
|
}
|
|
203
217
|
//# sourceMappingURL=omp.js.map
|