@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,143 +1,268 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { access, mkdir, readFile, realpath, rename, stat, writeFile, } from 'node:fs/promises';
|
|
1
|
+
import { access, mkdir, readFile, readdir, realpath, rename, stat, writeFile, } from 'node:fs/promises';
|
|
3
2
|
import { homedir, userInfo } from 'node:os';
|
|
4
3
|
import { basename, dirname, join, resolve } from 'node:path';
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import { CursorSessionAdapter } from './adapters/cursor.js';
|
|
9
|
-
import { FactorySessionAdapter } from './adapters/factory.js';
|
|
10
|
-
import { MuseSessionAdapter, museNativeSourceMatchesWorkspace } from './adapters/muse.js';
|
|
11
|
-
import { OmpSessionAdapter, readOmpSessionHeader } from './adapters/omp.js';
|
|
4
|
+
import { inspectMuseNativeWorkspace } from './adapters/muse.js';
|
|
5
|
+
import { readOmpSessionHeader } from './adapters/omp.js';
|
|
6
|
+
import { grokbotConversationIdFromLocator } from './adapters/grokbot-locator.js';
|
|
12
7
|
import { resolveOmpPaths } from '../providers/omp-paths.mjs';
|
|
13
|
-
import {
|
|
14
|
-
import { DeepSeekHarnessSessionAdapter } from './adapters/deepseek-harness.js';
|
|
15
|
-
import { SESSION_PROVIDER_IDS, sha256, } from './contracts.js';
|
|
8
|
+
import { SESSION_PROVIDER_IDS, SessionCoveragePreflightSchema, SessionContractError, sha256, } from './contracts.js';
|
|
16
9
|
import { redactSourceLocator } from './discovery.js';
|
|
17
|
-
import {
|
|
10
|
+
import { createSessionAdapterRegistry } from './adapter-registry.js';
|
|
11
|
+
import { coveragePreflight, expectedSessionProviders } from './coverage-preflight.js';
|
|
12
|
+
import { fingerprintSourceFile, streamJsonLines } from './readers.js';
|
|
13
|
+
import { matchSessionWorkspace } from './workspace-matching.js';
|
|
14
|
+
import { matchImportExclusion, nativeSessionIdFromLocator, resolveImportExclusions } from './import-exclusions.js';
|
|
18
15
|
export const DISCOVERY_MANIFEST_VERSION = '1.0.0';
|
|
19
16
|
const MANUAL_EXPORT_PROVIDERS = new Set([
|
|
20
|
-
'copilot', 'hermes', 'opencode', 'openclaw', 'openhuman', '
|
|
17
|
+
'copilot', 'hermes', 'opencode', 'openclaw', 'openhuman', 'grok-build',
|
|
21
18
|
'warp', 'devin-desktop', 'generic',
|
|
22
19
|
]);
|
|
23
20
|
export async function discoverWorkspaceHistories(options) {
|
|
21
|
+
const registry = options.registry ?? createSessionAdapterRegistry();
|
|
22
|
+
const exclusions = resolveImportExclusions(undefined, options.exclude);
|
|
23
|
+
const expectedProviders = expectedSessionProviders(options.expectedProviders ?? SESSION_PROVIDER_IDS);
|
|
24
|
+
const supportedProviders = new Set(registry.list().map((adapter) => adapter.provider));
|
|
24
25
|
const workspacePath = await canonicalPath(options.workspace);
|
|
25
26
|
const workspaceId = workspacePath;
|
|
27
|
+
const workspacePaths = [...new Set([workspacePath, resolve(options.workspace),
|
|
28
|
+
...(options.workspaceAliases ?? []).map((alias) => resolve(alias))])];
|
|
29
|
+
for (const alias of workspacePaths) {
|
|
30
|
+
if (await canonicalPath(alias) !== workspacePath) {
|
|
31
|
+
throw new SessionContractError('INVALID_ARGUMENT', 'workspace alias resolves to a different workspace');
|
|
32
|
+
}
|
|
33
|
+
}
|
|
26
34
|
const providerHomes = providerHomeCandidates(options.providerHome, options.operatorHome);
|
|
27
|
-
const keyWithLeadingDash = workspaceKey(workspacePath, true);
|
|
28
|
-
const keyWithoutLeadingDash = workspaceKey(workspacePath, false);
|
|
29
35
|
const discoverable = [
|
|
30
|
-
{ provider: 'deepseek-harness',
|
|
36
|
+
{ provider: 'deepseek-harness', roots: options.dshRoot
|
|
31
37
|
? [resolve(options.dshRoot)] : options.providerHome
|
|
32
38
|
? [join(resolve(options.providerHome), '.dsh', 'sessions')] : [] },
|
|
33
|
-
{ provider: 'omp',
|
|
39
|
+
{ provider: 'omp', roots: options.ompRoot
|
|
34
40
|
? [resolve(options.ompRoot)] : options.providerHome
|
|
35
41
|
? [resolveOmpPaths({ home: resolve(options.providerHome), cwd: workspacePath }).sessionsDir] : [] },
|
|
36
|
-
{ provider: 'muse',
|
|
42
|
+
{ provider: 'muse', roots: options.museRoot
|
|
37
43
|
? [resolve(options.museRoot)] : [] },
|
|
44
|
+
// Grok Bot conversations carry no workspace/cwd field, so unlike
|
|
45
|
+
// claude/cursor/factory there is no per-workspace default path to derive
|
|
46
|
+
// from providerHome. Native discovery requires an explicit
|
|
47
|
+
// --grokbot-root (same shared-root authorization model as
|
|
48
|
+
// codex/omp/deepseek-harness/muse below), and every authorized
|
|
49
|
+
// conversation surfaces to whichever workspace runs discovery (same
|
|
50
|
+
// no-filtering behavior already used for `pi`/`deepseek-harness`).
|
|
51
|
+
{ provider: 'grokbot', roots: options.grokbotRoot
|
|
52
|
+
? [resolve(options.grokbotRoot)] : [] },
|
|
38
53
|
{
|
|
39
54
|
provider: 'claude',
|
|
40
|
-
|
|
41
|
-
roots: providerHomes.map((providerHome) => join(providerHome, '.claude', 'projects', keyWithLeadingDash)),
|
|
55
|
+
roots: providerHomes.flatMap((providerHome) => workspacePaths.map((workspace) => join(providerHome, '.claude', 'projects', claudeProjectKey(workspace)))),
|
|
42
56
|
},
|
|
43
57
|
{
|
|
44
58
|
provider: 'codex',
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
? [resolve(options.codexRoot)]
|
|
48
|
-
: options.providerHome
|
|
49
|
-
? [join(resolve(options.providerHome), '.codex', 'sessions')]
|
|
50
|
-
: [],
|
|
59
|
+
roots: options.authorizedRoots || !expectedProviders.includes('codex')
|
|
60
|
+
? [] : await codexDiscoveryRoots(options),
|
|
51
61
|
},
|
|
52
62
|
{
|
|
53
63
|
provider: 'cursor',
|
|
54
|
-
|
|
55
|
-
roots: providerHomes.map((providerHome) => join(providerHome, '.cursor', 'projects', keyWithoutLeadingDash, 'agent-transcripts')),
|
|
64
|
+
roots: providerHomes.flatMap((providerHome) => workspacePaths.map((workspace) => join(providerHome, '.cursor', 'projects', workspaceKey(workspace, false), 'agent-transcripts'))),
|
|
56
65
|
},
|
|
57
66
|
{
|
|
58
67
|
provider: 'factory',
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
join(providerHome, '.factory', '
|
|
62
|
-
|
|
63
|
-
]),
|
|
68
|
+
roots: providerHomes.flatMap((providerHome) => workspacePaths.flatMap((workspace) => [
|
|
69
|
+
join(providerHome, '.factory', 'projects', workspaceKey(workspace, true)),
|
|
70
|
+
join(providerHome, '.factory', 'sessions', workspaceKey(workspace, true)),
|
|
71
|
+
])),
|
|
64
72
|
},
|
|
65
73
|
{
|
|
74
|
+
// Pi stores every working directory's sessions in its own
|
|
75
|
+
// subdirectory of the sessions root, named `--<path>--` where
|
|
76
|
+
// `<path>` has its leading separator removed and `/`, `\`, and `:`
|
|
77
|
+
// replaced with `-` (https://pi.dev/docs/latest/session-format,
|
|
78
|
+
// "File Location", verified 2026-10-12) — the same transform
|
|
79
|
+
// `workspaceKey(path, false)` already applies for Cursor below.
|
|
80
|
+
// Scanning the whole sessions root (as before) would import every
|
|
81
|
+
// other workspace's history into this one's catalog (#2656).
|
|
66
82
|
provider: 'pi',
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
? resolve(process.env.PI_CODING_AGENT_SESSION_DIR)
|
|
71
|
-
: join(resolve(options.providerHome), '.pi', 'agent', 'sessions')]
|
|
72
|
-
: [],
|
|
83
|
+
roots: (process.env.PI_CODING_AGENT_SESSION_DIR
|
|
84
|
+
? [resolve(process.env.PI_CODING_AGENT_SESSION_DIR)]
|
|
85
|
+
: providerHomes.map((providerHome) => join(providerHome, '.pi', 'agent', 'sessions'))).flatMap((sessionsRoot) => workspacePaths.map((workspace) => join(sessionsRoot, `--${workspaceKey(workspace, false)}--`))),
|
|
73
86
|
},
|
|
74
87
|
];
|
|
88
|
+
const authorizedRoots = { ...options.authorizedRoots };
|
|
75
89
|
const reports = new Map();
|
|
76
90
|
const candidates = [];
|
|
77
91
|
const seen = new Set();
|
|
78
92
|
for (const entry of discoverable) {
|
|
93
|
+
if (!expectedProviders.includes(entry.provider) || !supportedProviders.has(entry.provider))
|
|
94
|
+
continue;
|
|
95
|
+
const adapter = registry.get(entry.provider);
|
|
96
|
+
if (adapter.disposition === 'unsupported' || !adapter.supportedOperations.includes('discover'))
|
|
97
|
+
continue;
|
|
79
98
|
const availableRoots = [];
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
99
|
+
const rootCounts = new Map();
|
|
100
|
+
for (const root of options.authorizedRoots ? options.authorizedRoots[entry.provider] ?? [] : entry.roots) {
|
|
101
|
+
if (await pathExists(root)) {
|
|
102
|
+
const canonical = await canonicalPath(root);
|
|
103
|
+
if (options.authorizedRoots && canonical !== root) {
|
|
104
|
+
throw new SessionContractError('INVALID_ARGUMENT', 'previously authorized provider root changed; rediscover with explicit authorization');
|
|
105
|
+
}
|
|
106
|
+
if (!availableRoots.includes(canonical)) {
|
|
107
|
+
availableRoots.push(canonical);
|
|
108
|
+
rootCounts.set(canonical, {
|
|
109
|
+
root: redactSourceLocator(canonical), rootId: sha256(canonical),
|
|
110
|
+
status: 'checked', sourceCount: 0, duplicateCount: 0,
|
|
111
|
+
});
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
else {
|
|
115
|
+
rootCounts.set(root, {
|
|
116
|
+
root: redactSourceLocator(root), rootId: sha256(root),
|
|
117
|
+
status: 'unavailable', sourceCount: 0, duplicateCount: 0,
|
|
118
|
+
});
|
|
119
|
+
}
|
|
83
120
|
}
|
|
84
121
|
if (availableRoots.length === 0) {
|
|
85
122
|
const codexNeedsAuthorization = (entry.provider === 'codex' || entry.provider === 'omp'
|
|
86
|
-
|| entry.provider === 'deepseek-harness' || entry.provider === 'muse'
|
|
123
|
+
|| entry.provider === 'deepseek-harness' || entry.provider === 'muse'
|
|
124
|
+
|| entry.provider === 'grokbot')
|
|
87
125
|
&& entry.roots.length === 0;
|
|
88
126
|
reports.set(entry.provider, providerReport(entry.provider, codexNeedsAuthorization ? 'export-required' : 'unavailable', codexNeedsAuthorization ? 'manual-export' : 'discoverable', [], codexNeedsAuthorization
|
|
89
127
|
? 'SHARED_ROOT_AUTHORIZATION_REQUIRED'
|
|
90
128
|
: 'PROVIDER_ROOT_UNAVAILABLE', codexNeedsAuthorization
|
|
91
|
-
? `Pass --${entry.provider}-root with an explicitly authorized sessions root.`
|
|
129
|
+
? `Pass --${entry.provider === 'deepseek-harness' ? 'dsh' : entry.provider}-root with an explicitly authorized sessions root.`
|
|
92
130
|
: `No authorized ${entry.provider} workspace history root was found.`));
|
|
131
|
+
if (entry.provider === 'codex')
|
|
132
|
+
reports.get(entry.provider).rootCounts = [...rootCounts.values()];
|
|
93
133
|
continue;
|
|
94
134
|
}
|
|
135
|
+
authorizedRoots[entry.provider] = availableRoots;
|
|
95
136
|
const scope = {
|
|
96
137
|
workspaceId,
|
|
97
138
|
allowedRoots: availableRoots,
|
|
98
139
|
};
|
|
99
140
|
const providerSources = [];
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
141
|
+
let matchedBySubfolder = 0;
|
|
142
|
+
let matchedByWorktree = 0;
|
|
143
|
+
const museSourceInspections = [];
|
|
144
|
+
for await (const descriptor of adapter.discover(scope)) {
|
|
145
|
+
const known = options.knownSources?.find(source => source.provider === descriptor.provider && source.locator === descriptor.locator);
|
|
146
|
+
const nativeSessionId = known?.nativeSessionId ?? descriptor.nativeSessionId ?? nativeSessionIdFromLocator(descriptor);
|
|
147
|
+
const exclusion = matchImportExclusion({ ...descriptor, nativeSessionId }, exclusions);
|
|
148
|
+
if (exclusion) {
|
|
149
|
+
const locator = resolve(descriptor.locator);
|
|
150
|
+
const authorizedRoot = scope.allowedRoots.find(root => locator === root || locator.startsWith(`${root}/`));
|
|
151
|
+
if (!authorizedRoot)
|
|
152
|
+
continue;
|
|
153
|
+
const key = `excluded\0${entry.provider}\0${locator}`;
|
|
154
|
+
if (seen.has(key))
|
|
155
|
+
continue;
|
|
156
|
+
seen.add(key);
|
|
157
|
+
const source = {
|
|
158
|
+
sourceId: known?.sourceId ?? sha256(key), provider: entry.provider,
|
|
159
|
+
locator, redactedLocator: redactSourceLocator(locator), locatorClass: descriptor.locatorClass,
|
|
160
|
+
authorizedRoot, modifiedAt: '', sizeBytes: 0, digest: '', nativeSessionId,
|
|
161
|
+
status: 'excluded', exclusion,
|
|
162
|
+
};
|
|
163
|
+
rootCounts.get(authorizedRoot).sourceCount += 1;
|
|
164
|
+
providerSources.push(source);
|
|
165
|
+
candidates.push(source);
|
|
104
166
|
continue;
|
|
105
|
-
|
|
106
|
-
|
|
167
|
+
}
|
|
168
|
+
let workspaceMatch = null;
|
|
169
|
+
if (entry.provider === 'muse') {
|
|
170
|
+
const inspection = await inspectMuseNativeWorkspace({
|
|
107
171
|
...descriptor,
|
|
108
172
|
sourceId: 'discovery',
|
|
109
173
|
authorizedScope: scope,
|
|
110
|
-
}, workspacePath)
|
|
111
|
-
|
|
174
|
+
}, workspacePath);
|
|
175
|
+
museSourceInspections.push({
|
|
176
|
+
sourceKey: sha256(['muse-workspace-inspection-v1', descriptor.locator].join('\0')),
|
|
177
|
+
redactedLocator: redactSourceLocator(descriptor.locator),
|
|
178
|
+
nativeSessionId: basename(dirname(descriptor.locator)),
|
|
179
|
+
...inspection,
|
|
180
|
+
});
|
|
181
|
+
if (inspection.outcome !== 'matched')
|
|
182
|
+
continue;
|
|
183
|
+
workspaceMatch = inspection.matchKind ?? null;
|
|
184
|
+
}
|
|
185
|
+
const locator = await canonicalPath(descriptor.locator);
|
|
186
|
+
if (entry.provider === 'codex') {
|
|
187
|
+
workspaceMatch = await codexSourceWorkspaceMatch(locator, workspacePath);
|
|
188
|
+
if (!workspaceMatch)
|
|
189
|
+
continue;
|
|
190
|
+
}
|
|
112
191
|
const ompHeader = entry.provider === 'omp' ? await readOmpSessionHeader({ ...descriptor, sourceId: 'discovery', authorizedScope: scope }) : undefined;
|
|
113
|
-
if (ompHeader
|
|
114
|
-
|
|
192
|
+
if (ompHeader) {
|
|
193
|
+
workspaceMatch = await matchSessionWorkspace(ompHeader.cwd, workspacePath);
|
|
194
|
+
if (!workspaceMatch)
|
|
195
|
+
continue;
|
|
196
|
+
}
|
|
115
197
|
const details = await stat(locator);
|
|
116
198
|
const authorizedRoot = scope.allowedRoots.find((root) => locator === root || locator.startsWith(`${root}/`));
|
|
117
199
|
if (!authorizedRoot)
|
|
118
200
|
continue;
|
|
201
|
+
if (entry.provider === 'claude'
|
|
202
|
+
&& !await claudeSourceMatchesWorkspace(locator, workspacePath))
|
|
203
|
+
continue;
|
|
119
204
|
const fingerprint = await fingerprintSourceFile({
|
|
120
205
|
selectedPath: locator,
|
|
121
206
|
allowedRoots: [authorizedRoot],
|
|
122
207
|
});
|
|
123
|
-
const
|
|
124
|
-
|
|
208
|
+
const rolloutId = entry.provider === 'codex' && descriptor.locatorClass === 'codex-rollout-jsonl'
|
|
209
|
+
? await codexRolloutId(locator) : undefined;
|
|
210
|
+
const dedupeKey = rolloutId
|
|
211
|
+
? `codex\0rollout\0${rolloutId}`
|
|
212
|
+
: `${entry.provider}\0${fingerprint.digest}\0${fingerprint.size}`;
|
|
213
|
+
const rootCount = rootCounts.get(authorizedRoot);
|
|
214
|
+
if (seen.has(dedupeKey)) {
|
|
215
|
+
rootCount.duplicateCount += 1;
|
|
125
216
|
continue;
|
|
217
|
+
}
|
|
126
218
|
seen.add(dedupeKey);
|
|
219
|
+
if (workspaceMatch === 'subfolder')
|
|
220
|
+
matchedBySubfolder += 1;
|
|
221
|
+
if (workspaceMatch === 'worktree')
|
|
222
|
+
matchedByWorktree += 1;
|
|
223
|
+
rootCount.sourceCount += 1;
|
|
127
224
|
const source = sourceFromDescriptor(descriptor, locator, authorizedRoot, details, fingerprint.digest);
|
|
225
|
+
source.nativeSessionId = rolloutId ?? ompHeader?.id ?? nativeSessionId;
|
|
128
226
|
if (ompHeader)
|
|
129
227
|
source.sourceId = sha256(['omp-native-source-v1', workspaceId, ompHeader.id].join('\0'));
|
|
228
|
+
if (entry.provider === 'grokbot') {
|
|
229
|
+
// The replica is rewritten wholesale as its sliding window evicts
|
|
230
|
+
// old entries, so a content-digest sourceId (the default above)
|
|
231
|
+
// would churn every re-discovery and break checkpoint continuity.
|
|
232
|
+
// Key it on the conversation id instead, same rationale as the OMP
|
|
233
|
+
// override above.
|
|
234
|
+
const conversationId = grokbotConversationIdFromLocator(locator);
|
|
235
|
+
if (conversationId) {
|
|
236
|
+
source.sourceId = sha256(['grokbot-native-source-v1', workspaceId, conversationId].join('\0'));
|
|
237
|
+
}
|
|
238
|
+
}
|
|
130
239
|
providerSources.push(source);
|
|
131
240
|
candidates.push(source);
|
|
132
241
|
}
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
: null
|
|
242
|
+
const incompleteMuseInspection = museSourceInspections.some((inspection) => inspection.outcome === 'inconclusive');
|
|
243
|
+
const report = providerReport(entry.provider, incompleteMuseInspection ? 'not-checked' : 'checked', 'discoverable', providerSources, incompleteMuseInspection ? 'MUSE_SOURCE_INSPECTION_INCOMPLETE'
|
|
244
|
+
: providerSources.length === 0 ? 'NO_WORKSPACE_SOURCES' : null, incompleteMuseInspection
|
|
245
|
+
? 'Review unattributed museSourceInspections and their limit name/value; authorize a supported Muse export for unresolved sources before claiming workspace coverage.'
|
|
246
|
+
: providerSources.length === 0
|
|
247
|
+
? `The ${entry.provider} root was checked, but no source matched the authorized workspace.`
|
|
248
|
+
: null);
|
|
249
|
+
if (entry.provider === 'muse') {
|
|
250
|
+
report.museSourceInspections = museSourceInspections.sort((a, b) => a.sourceKey.localeCompare(b.sourceKey));
|
|
251
|
+
}
|
|
252
|
+
report.matchedBySubfolder = matchedBySubfolder;
|
|
253
|
+
report.matchedByWorktree = matchedByWorktree;
|
|
254
|
+
if (entry.provider === 'codex')
|
|
255
|
+
report.rootCounts = [...rootCounts.values()];
|
|
256
|
+
reports.set(entry.provider, report);
|
|
136
257
|
}
|
|
137
|
-
for (const provider of
|
|
258
|
+
for (const provider of expectedProviders) {
|
|
138
259
|
if (reports.has(provider))
|
|
139
260
|
continue;
|
|
140
261
|
const manual = MANUAL_EXPORT_PROVIDERS.has(provider);
|
|
262
|
+
if (!supportedProviders.has(provider)) {
|
|
263
|
+
reports.set(provider, providerReport(provider, 'not-checked', 'unsupported', [], 'MISSING_ADAPTER', 'Deliberately select a compatible runtime or an authorized supported export.'));
|
|
264
|
+
continue;
|
|
265
|
+
}
|
|
141
266
|
const grokBuild = provider === 'grok-build';
|
|
142
267
|
reports.set(provider, providerReport(provider, manual ? 'export-required' : 'not-checked', manual ? 'manual-export' : 'unsupported', [], grokBuild ? 'CLI_EXPORT_REQUIRED'
|
|
143
268
|
: manual ? 'EXPLICIT_EXPORT_REQUIRED' : 'PROVIDER_NOT_CHECKED', grokBuild
|
|
@@ -148,9 +273,15 @@ export async function discoverWorkspaceHistories(options) {
|
|
|
148
273
|
}
|
|
149
274
|
const sources = candidates.sort(compareSources);
|
|
150
275
|
const providers = [...reports.values()].sort((a, b) => a.provider.localeCompare(b.provider));
|
|
276
|
+
const preflight = coveragePreflight({
|
|
277
|
+
expectedProviders, expectedProviderBasis: options.expectedProviders ? 'explicit' : 'declared-default',
|
|
278
|
+
registry, runtime: options.runtime, reports: providers,
|
|
279
|
+
});
|
|
151
280
|
const identity = {
|
|
152
281
|
schemaVersion: DISCOVERY_MANIFEST_VERSION,
|
|
153
282
|
workspaceId,
|
|
283
|
+
preflight,
|
|
284
|
+
authorizedRoots,
|
|
154
285
|
sources: sources.map((source) => ({
|
|
155
286
|
sourceId: source.sourceId,
|
|
156
287
|
provider: source.provider,
|
|
@@ -159,11 +290,17 @@ export async function discoverWorkspaceHistories(options) {
|
|
|
159
290
|
modifiedAt: source.modifiedAt,
|
|
160
291
|
sizeBytes: source.sizeBytes,
|
|
161
292
|
digest: source.digest,
|
|
293
|
+
...(source.nativeSessionId ? { nativeSessionId: source.nativeSessionId } : {}),
|
|
294
|
+
...(source.status ? { status: source.status, exclusion: source.exclusion } : {}),
|
|
162
295
|
})),
|
|
163
296
|
providers: providers.map((provider) => ({
|
|
164
297
|
provider: provider.provider,
|
|
165
298
|
status: provider.status,
|
|
166
299
|
reasonCode: provider.reasonCode,
|
|
300
|
+
...(provider.matchedBySubfolder !== undefined ? { matchedBySubfolder: provider.matchedBySubfolder } : {}),
|
|
301
|
+
...(provider.matchedByWorktree !== undefined ? { matchedByWorktree: provider.matchedByWorktree } : {}),
|
|
302
|
+
...(provider.rootCounts ? { rootCounts: provider.rootCounts } : {}),
|
|
303
|
+
...(provider.museSourceInspections ? { museSourceInspections: provider.museSourceInspections } : {}),
|
|
167
304
|
})),
|
|
168
305
|
};
|
|
169
306
|
return {
|
|
@@ -172,6 +309,8 @@ export async function discoverWorkspaceHistories(options) {
|
|
|
172
309
|
createdAt: options.createdAt ?? new Date().toISOString(),
|
|
173
310
|
workspaceId,
|
|
174
311
|
workspacePath,
|
|
312
|
+
preflight,
|
|
313
|
+
authorizedRoots,
|
|
175
314
|
providers,
|
|
176
315
|
sources,
|
|
177
316
|
};
|
|
@@ -194,6 +333,11 @@ export async function readDiscoveryManifest(path) {
|
|
|
194
333
|
|| !Array.isArray(value.sources)) {
|
|
195
334
|
throw new Error('session discovery manifest is malformed or unsupported');
|
|
196
335
|
}
|
|
336
|
+
if (value.preflight) {
|
|
337
|
+
const parsed = SessionCoveragePreflightSchema.safeParse(value.preflight);
|
|
338
|
+
if (!parsed.success)
|
|
339
|
+
throw new SessionContractError('INVALID_ARGUMENT', 'invalid discovery coverage preflight');
|
|
340
|
+
}
|
|
197
341
|
const expected = await rediscoverManifestIdentity(value);
|
|
198
342
|
if (expected !== value.manifestId) {
|
|
199
343
|
throw new Error('session discovery manifest identity does not match its contents');
|
|
@@ -207,11 +351,15 @@ export function publicDiscoveryManifest(manifest) {
|
|
|
207
351
|
createdAt: manifest.createdAt,
|
|
208
352
|
workspaceId: manifest.workspaceId,
|
|
209
353
|
workspacePath: manifest.workspacePath,
|
|
354
|
+
preflight: manifest.preflight,
|
|
210
355
|
providers: manifest.providers,
|
|
211
356
|
sources: manifest.sources.map(({ locator: _locator, authorizedRoot: _root, ...source }) => source),
|
|
212
357
|
totals: {
|
|
213
358
|
providers: manifest.providers.length,
|
|
214
359
|
sources: manifest.sources.length,
|
|
360
|
+
excluded: manifest.sources.filter(source => source.status === 'excluded').length,
|
|
361
|
+
matchedBySubfolder: manifest.providers.reduce((sum, provider) => sum + (provider.matchedBySubfolder ?? 0), 0),
|
|
362
|
+
matchedByWorktree: manifest.providers.reduce((sum, provider) => sum + (provider.matchedByWorktree ?? 0), 0),
|
|
215
363
|
},
|
|
216
364
|
};
|
|
217
365
|
}
|
|
@@ -231,12 +379,14 @@ function sourceFromDescriptor(descriptor, locator, authorizedRoot, details, dige
|
|
|
231
379
|
};
|
|
232
380
|
}
|
|
233
381
|
function providerReport(provider, status, disposition, sources, reasonCode, remediation) {
|
|
234
|
-
const timestamps = sources.map((source) => source.modifiedAt).sort();
|
|
382
|
+
const timestamps = sources.map((source) => source.modifiedAt).filter(Boolean).sort();
|
|
235
383
|
return {
|
|
236
384
|
provider,
|
|
237
385
|
status,
|
|
238
386
|
disposition,
|
|
239
387
|
sourceCount: sources.length,
|
|
388
|
+
matchedBySubfolder: 0,
|
|
389
|
+
matchedByWorktree: 0,
|
|
240
390
|
dateRange: {
|
|
241
391
|
earliest: timestamps.at(0) ?? null,
|
|
242
392
|
latest: timestamps.at(-1) ?? null,
|
|
@@ -250,6 +400,8 @@ async function rediscoverManifestIdentity(manifest) {
|
|
|
250
400
|
const identity = {
|
|
251
401
|
schemaVersion: manifest.schemaVersion,
|
|
252
402
|
workspaceId: manifest.workspaceId,
|
|
403
|
+
...(manifest.preflight ? { preflight: manifest.preflight } : {}),
|
|
404
|
+
...(manifest.authorizedRoots ? { authorizedRoots: manifest.authorizedRoots } : {}),
|
|
253
405
|
sources: manifest.sources.map((source) => ({
|
|
254
406
|
sourceId: source.sourceId,
|
|
255
407
|
provider: source.provider,
|
|
@@ -258,46 +410,84 @@ async function rediscoverManifestIdentity(manifest) {
|
|
|
258
410
|
modifiedAt: source.modifiedAt,
|
|
259
411
|
sizeBytes: source.sizeBytes,
|
|
260
412
|
digest: source.digest,
|
|
413
|
+
...(source.nativeSessionId ? { nativeSessionId: source.nativeSessionId } : {}),
|
|
414
|
+
...(source.status ? { status: source.status, exclusion: source.exclusion } : {}),
|
|
261
415
|
})),
|
|
262
416
|
providers: manifest.providers.map((provider) => ({
|
|
263
417
|
provider: provider.provider,
|
|
264
418
|
status: provider.status,
|
|
265
419
|
reasonCode: provider.reasonCode,
|
|
420
|
+
...(provider.matchedBySubfolder !== undefined ? { matchedBySubfolder: provider.matchedBySubfolder } : {}),
|
|
421
|
+
...(provider.matchedByWorktree !== undefined ? { matchedByWorktree: provider.matchedByWorktree } : {}),
|
|
422
|
+
...(provider.rootCounts ? { rootCounts: provider.rootCounts } : {}),
|
|
423
|
+
...(provider.museSourceInspections ? { museSourceInspections: provider.museSourceInspections } : {}),
|
|
266
424
|
})),
|
|
267
425
|
};
|
|
268
426
|
return sha256(JSON.stringify(identity));
|
|
269
427
|
}
|
|
270
|
-
async function
|
|
271
|
-
const
|
|
272
|
-
|
|
273
|
-
|
|
428
|
+
async function codexDiscoveryRoots(options) {
|
|
429
|
+
const explicit = [...(options.codexRoots ?? []), ...(options.codexRoot ? [options.codexRoot] : [])];
|
|
430
|
+
if (explicit.length > 0)
|
|
431
|
+
return [...new Set(explicit.map((root) => resolve(root)))];
|
|
432
|
+
// Shared stores require the same explicit provider-home authorization as the default root.
|
|
433
|
+
if (!options.providerHome)
|
|
434
|
+
return [];
|
|
435
|
+
const codexHome = join(resolve(options.providerHome), '.codex');
|
|
436
|
+
const roots = [join(codexHome, 'sessions')];
|
|
437
|
+
if (process.env.CODEX_HOME)
|
|
438
|
+
roots.push(resolve(process.env.CODEX_HOME, 'sessions'));
|
|
274
439
|
try {
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
try {
|
|
280
|
-
value = JSON.parse(line);
|
|
281
|
-
}
|
|
282
|
-
catch {
|
|
283
|
-
continue;
|
|
284
|
-
}
|
|
285
|
-
const cwd = codexWorkspaceField(value);
|
|
286
|
-
if (!cwd)
|
|
287
|
-
continue;
|
|
288
|
-
try {
|
|
289
|
-
return await canonicalPath(cwd) === workspacePath;
|
|
290
|
-
}
|
|
291
|
-
catch {
|
|
292
|
-
return resolve(cwd) === workspacePath;
|
|
440
|
+
const roles = await readdir(join(codexHome, 'roles-runtime'), { withFileTypes: true });
|
|
441
|
+
for (const role of roles.sort((a, b) => a.name.localeCompare(b.name))) {
|
|
442
|
+
if (role.isDirectory() || role.isSymbolicLink()) {
|
|
443
|
+
roots.push(join(codexHome, 'roles-runtime', role.name, '.codex', 'sessions'));
|
|
293
444
|
}
|
|
294
445
|
}
|
|
295
|
-
return false;
|
|
296
446
|
}
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
447
|
+
catch (error) {
|
|
448
|
+
if (!['ENOENT', 'ENOTDIR'].includes(error.code ?? ''))
|
|
449
|
+
throw error;
|
|
300
450
|
}
|
|
451
|
+
return [...new Set(roots)];
|
|
452
|
+
}
|
|
453
|
+
async function codexRolloutId(locator) {
|
|
454
|
+
let count = 0;
|
|
455
|
+
for await (const { line } of streamJsonLines(locator)) {
|
|
456
|
+
if (++count > 50)
|
|
457
|
+
break;
|
|
458
|
+
let value;
|
|
459
|
+
try {
|
|
460
|
+
value = JSON.parse(line);
|
|
461
|
+
}
|
|
462
|
+
catch {
|
|
463
|
+
continue;
|
|
464
|
+
}
|
|
465
|
+
const record = asObject(value);
|
|
466
|
+
const id = asObject(record.payload).id;
|
|
467
|
+
if (record.type === 'session_meta' && typeof id === 'string' && id.length > 0)
|
|
468
|
+
return id;
|
|
469
|
+
}
|
|
470
|
+
return /([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})\.jsonl$/i
|
|
471
|
+
.exec(basename(locator))?.[1];
|
|
472
|
+
}
|
|
473
|
+
async function codexSourceWorkspaceMatch(locator, workspacePath) {
|
|
474
|
+
let count = 0;
|
|
475
|
+
for await (const { line } of streamJsonLines(locator)) {
|
|
476
|
+
if (++count > 50)
|
|
477
|
+
break;
|
|
478
|
+
let value;
|
|
479
|
+
try {
|
|
480
|
+
value = JSON.parse(line);
|
|
481
|
+
}
|
|
482
|
+
catch {
|
|
483
|
+
continue;
|
|
484
|
+
}
|
|
485
|
+
const cwd = codexWorkspaceField(value);
|
|
486
|
+
if (!cwd)
|
|
487
|
+
continue;
|
|
488
|
+
return await matchSessionWorkspace(cwd, workspacePath);
|
|
489
|
+
}
|
|
490
|
+
return null;
|
|
301
491
|
}
|
|
302
492
|
function codexWorkspaceField(value) {
|
|
303
493
|
const root = asObject(value);
|
|
@@ -322,6 +512,43 @@ function asObject(value) {
|
|
|
322
512
|
async function canonicalPath(path) {
|
|
323
513
|
return realpath(resolve(path));
|
|
324
514
|
}
|
|
515
|
+
async function claudeSourceMatchesWorkspace(locator, workspacePath) {
|
|
516
|
+
let count = 0;
|
|
517
|
+
for await (const { line } of streamJsonLines(locator, { end: 1024 * 1024 - 1 })) {
|
|
518
|
+
if (++count > 50)
|
|
519
|
+
break;
|
|
520
|
+
let value;
|
|
521
|
+
try {
|
|
522
|
+
value = JSON.parse(line);
|
|
523
|
+
}
|
|
524
|
+
catch {
|
|
525
|
+
continue;
|
|
526
|
+
}
|
|
527
|
+
const cwd = asObject(value).cwd;
|
|
528
|
+
if (typeof cwd !== 'string' || cwd.length === 0)
|
|
529
|
+
continue;
|
|
530
|
+
try {
|
|
531
|
+
return await canonicalPath(cwd) === workspacePath;
|
|
532
|
+
}
|
|
533
|
+
catch {
|
|
534
|
+
return resolve(cwd) === workspacePath;
|
|
535
|
+
}
|
|
536
|
+
}
|
|
537
|
+
// Older transcripts without cwd still use the selected project folder.
|
|
538
|
+
return true;
|
|
539
|
+
}
|
|
540
|
+
export function claudeProjectKey(path) {
|
|
541
|
+
// Claude Code 2.1.302 replaces each character, then caps keys at 200
|
|
542
|
+
// characters with a base-36 suffix from the original path's 32-bit hash.
|
|
543
|
+
const key = path.replace(/[^A-Za-z0-9-]/g, '-');
|
|
544
|
+
if (key.length <= 200)
|
|
545
|
+
return key;
|
|
546
|
+
let hash = 0;
|
|
547
|
+
for (let index = 0; index < path.length; index += 1) {
|
|
548
|
+
hash = ((hash << 5) - hash + path.charCodeAt(index)) | 0;
|
|
549
|
+
}
|
|
550
|
+
return `${key.slice(0, 200)}-${Math.abs(hash).toString(36)}`;
|
|
551
|
+
}
|
|
325
552
|
function workspaceKey(path, retainLeadingSeparator) {
|
|
326
553
|
const normalized = path.replace(/\\/g, '/');
|
|
327
554
|
const input = retainLeadingSeparator ? normalized : normalized.replace(/^\/+/, '');
|