@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,49 +1,459 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Grok Bot session adapter — manual-export
|
|
3
|
-
* for
|
|
2
|
+
* Grok Bot session adapter — manual-export interchange plus an evidence-gated
|
|
3
|
+
* native locator for the Grok Bot desktop app's local transcript cache.
|
|
4
4
|
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
5
|
+
* Native discovery (#2970) is Linux-only and requires an explicitly
|
|
6
|
+
* authorized `sand-client-persistence` root (`--grokbot-root`); there is no
|
|
7
|
+
* default path and nothing is guessed for macOS/Windows, where the layout is
|
|
8
|
+
* unverified. The store is one JSON document per key, named `<base32
|
|
9
|
+
* key>.blob` (RFC 4648 section 6, lowercase, unpadded). Discovery decodes
|
|
10
|
+
* ONLY filenames to classify them; it never opens a file whose decoded key
|
|
11
|
+
* is outside the allowlist below, and it never recurses or follows symlinks.
|
|
7
12
|
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
13
|
+
* Allowlisted keys (see grokbot-locator.ts):
|
|
14
|
+
* - `...transcript.replicas.<conversation-uuid>` — one conversation; the
|
|
15
|
+
* only key class ever selected as an importable source.
|
|
16
|
+
* - `...roster.last-roster` — account conversation index; never opened by
|
|
17
|
+
* this adapter (no session content), kept out of discover() results.
|
|
18
|
+
* Every other key (composer-drafts, send-journal, experiments, ui-layout,
|
|
19
|
+
* sand-secrets, box-secrets, cookies, local/session storage, etc.) is never
|
|
20
|
+
* decoded content, never opened, and `~/.grokbot` (daemon credentials) is
|
|
21
|
+
* never referenced.
|
|
22
|
+
*
|
|
23
|
+
* Grok Bot conversations carry no workspace/cwd field — there is no native
|
|
24
|
+
* evidence linking a conversation to a project directory. Following the
|
|
25
|
+
* established precedent for other account-scoped, non-workspace-scoped
|
|
26
|
+
* native locators (`pi`, `deepseek-harness`: no per-source workspace
|
|
27
|
+
* filtering in workspace-discovery.ts), every authorized conversation under
|
|
28
|
+
* `--grokbot-root` surfaces to whichever workspace runs discovery; this
|
|
29
|
+
* adapter never guesses a workspace link and `inspect()` never sets
|
|
30
|
+
* `declaredWorkspaceId` for native sources.
|
|
31
|
+
*
|
|
32
|
+
* The replica is a bounded client-side cache (~200 entries) that can evict
|
|
33
|
+
* its oldest entries as new ones arrive, so a re-read is not append-only —
|
|
34
|
+
* the file may shrink, and Grok Bot may rewrite it via a rename-swap that
|
|
35
|
+
* changes its inode. This adapter declares `sourceContinuity: 'snapshot'`
|
|
36
|
+
* (contracts.ts), which tells the shared importer to skip its generic
|
|
37
|
+
* size-shrink / file-identity / prefix-rewrite checks (those assume
|
|
38
|
+
* append-only growth) for this source. Idempotent, non-duplicating re-import
|
|
39
|
+
* across the sliding window then relies on two things instead: (1)
|
|
40
|
+
* `workspace-discovery.ts` assigns a conversation-id–derived,
|
|
41
|
+
* content-independent `sourceId` for native sources (mirroring the existing
|
|
42
|
+
* OMP convention), so the importer's checkpoint continuity survives content
|
|
43
|
+
* changes; (2) `stream()` resumes from the native, monotonic `seq` carried
|
|
44
|
+
* by each entry (not a position/byte offset, which the sliding window would
|
|
45
|
+
* invalidate) and tags every record's `sourceCursor` as `native:<seq>` — an
|
|
46
|
+
* opaque provider-native resume token the importer stores verbatim
|
|
47
|
+
* (`positionKind: 'provider-native'`), never reinterpreted as a byte offset.
|
|
48
|
+
* Combined with the catalog's identity-keyed `INSERT OR IGNORE`, re-importing
|
|
49
|
+
* after the window has slid can only add genuinely new entries, never
|
|
50
|
+
* duplicate ones.
|
|
10
51
|
*
|
|
11
52
|
* @see docs/providers/grokbot-sessions.md
|
|
12
|
-
* @issue #215
|
|
53
|
+
* @issue #215, #2970
|
|
13
54
|
*/
|
|
14
|
-
import {
|
|
55
|
+
import { opendir } from 'node:fs/promises';
|
|
56
|
+
import { resolve } from 'node:path';
|
|
57
|
+
import { z } from 'zod';
|
|
58
|
+
import { schemaRejectionDetail, schemaIssueDetail, SessionContractError, assertSupportedSchemaMajor, } from '../contracts.js';
|
|
59
|
+
import { readBoundedJson } from '../readers.js';
|
|
15
60
|
import { GenericSessionInterchangeAdapter, } from './generic.js';
|
|
61
|
+
import { classifyGrokbotBlobName, grokbotConversationIdFromLocator, } from './grokbot-locator.js';
|
|
16
62
|
export const GROKBOT_ADAPTER_VERSION = '1.0.0';
|
|
17
63
|
export const GROKBOT_EXPORT_SCHEMA_VERSION = '1.0.0';
|
|
64
|
+
export const GROKBOT_NATIVE_SCHEMA_VERSION = '1.0.0';
|
|
65
|
+
export const GROKBOT_NATIVE_SCHEMA_MAJOR = 1;
|
|
18
66
|
export const GROKBOT_LOCATOR_CLASS = 'manual-export';
|
|
67
|
+
export const GROKBOT_NATIVE_REPLICA_LOCATOR_CLASS = 'grokbot-native-transcript-replica';
|
|
68
|
+
const GrokbotEntryBaseSchema = z.object({
|
|
69
|
+
kind: z.string().min(1),
|
|
70
|
+
id: z.string().min(1),
|
|
71
|
+
timestampMs: z.number().int().nonnegative(),
|
|
72
|
+
requestId: z.string().optional(),
|
|
73
|
+
seq: z.number().int().nonnegative(),
|
|
74
|
+
}).passthrough();
|
|
75
|
+
const SendMessageEntrySchema = GrokbotEntryBaseSchema.extend({
|
|
76
|
+
kind: z.literal('send-message'),
|
|
77
|
+
respondedValue: z.unknown().optional(),
|
|
78
|
+
secretProvided: z.boolean().optional(),
|
|
79
|
+
message: z.discriminatedUnion('type', [
|
|
80
|
+
z.object({ type: z.literal('text'), content: z.string() }).passthrough(),
|
|
81
|
+
z.object({
|
|
82
|
+
type: z.literal('widget'),
|
|
83
|
+
widget: z.object({ prompt: z.string() }).passthrough(),
|
|
84
|
+
}).passthrough(),
|
|
85
|
+
z.object({
|
|
86
|
+
type: z.literal('email-draft'),
|
|
87
|
+
draft: z.object({ subject: z.string().optional(), body: z.string() }).passthrough(),
|
|
88
|
+
}).passthrough(),
|
|
89
|
+
z.object({
|
|
90
|
+
type: z.literal('slack-draft'),
|
|
91
|
+
draft: z.object({ target: z.string().optional(), body: z.string() }).passthrough(),
|
|
92
|
+
}).passthrough(),
|
|
93
|
+
z.object({
|
|
94
|
+
type: z.literal('attachment'),
|
|
95
|
+
url: z.string(),
|
|
96
|
+
file_name: z.string(),
|
|
97
|
+
}).passthrough(),
|
|
98
|
+
z.object({
|
|
99
|
+
type: z.literal('user-form'),
|
|
100
|
+
formRequest: z.object({ title: z.string() }).passthrough(),
|
|
101
|
+
}).passthrough(),
|
|
102
|
+
z.object({
|
|
103
|
+
type: z.literal('secret-request'),
|
|
104
|
+
secretRequest: z.object({ label: z.string() }).passthrough(),
|
|
105
|
+
}).passthrough(),
|
|
106
|
+
]),
|
|
107
|
+
});
|
|
108
|
+
const MessageEntrySchema = GrokbotEntryBaseSchema.extend({
|
|
109
|
+
kind: z.literal('message'),
|
|
110
|
+
role: z.enum(['user', 'assistant']),
|
|
111
|
+
content: z.string(),
|
|
112
|
+
fromAgent: z.object({ id: z.string().optional(), name: z.string().optional() })
|
|
113
|
+
.passthrough().optional(),
|
|
114
|
+
});
|
|
115
|
+
const UserAttachmentEntrySchema = GrokbotEntryBaseSchema.extend({
|
|
116
|
+
kind: z.literal('user-attachment'),
|
|
117
|
+
file_name: z.string(),
|
|
118
|
+
file_path: z.string().optional(),
|
|
119
|
+
width: z.number().optional(),
|
|
120
|
+
height: z.number().optional(),
|
|
121
|
+
byteSize: z.number().optional(),
|
|
122
|
+
});
|
|
123
|
+
const EventEntrySchema = GrokbotEntryBaseSchema.extend({
|
|
124
|
+
kind: z.literal('event'),
|
|
125
|
+
event: z.record(z.string(), z.unknown()),
|
|
126
|
+
});
|
|
127
|
+
const NoticeEntrySchema = GrokbotEntryBaseSchema.extend({
|
|
128
|
+
kind: z.literal('notice'),
|
|
129
|
+
text: z.string(),
|
|
130
|
+
});
|
|
131
|
+
const GrokbotReplicaValueSchema = z.object({
|
|
132
|
+
entries: z.array(GrokbotEntryBaseSchema),
|
|
133
|
+
epochHint: z.string().nullish(),
|
|
134
|
+
acceptedSequenceHint: z.number().int().nonnegative().nullish(),
|
|
135
|
+
persistedAt: z.number().int().nonnegative().nullish(),
|
|
136
|
+
precedingTimestampMs: z.number().int().nonnegative().nullish(),
|
|
137
|
+
}).passthrough();
|
|
138
|
+
const GrokbotReplicaDocumentSchema = z.object({
|
|
139
|
+
schemaVersion: z.number().int().nonnegative(),
|
|
140
|
+
value: GrokbotReplicaValueSchema,
|
|
141
|
+
}).passthrough();
|
|
19
142
|
export class GrokbotSessionAdapter {
|
|
143
|
+
limits;
|
|
144
|
+
maxFiles;
|
|
20
145
|
provider = 'grokbot';
|
|
21
146
|
adapterVersion = GROKBOT_ADAPTER_VERSION;
|
|
22
|
-
disposition = '
|
|
23
|
-
supportedOperations = ['inspect', 'stream'];
|
|
24
|
-
acquisitionModes = ['manual-export'];
|
|
147
|
+
disposition = 'implemented';
|
|
148
|
+
supportedOperations = ['discover', 'inspect', 'stream'];
|
|
149
|
+
acquisitionModes = ['manual-export', 'jsonl'];
|
|
150
|
+
/**
|
|
151
|
+
* The replica is rewritten wholesale (sliding window, possible
|
|
152
|
+
* rename-swap), not appended to. See the class-level doc comment.
|
|
153
|
+
*/
|
|
154
|
+
sourceContinuity = 'snapshot';
|
|
25
155
|
interchange;
|
|
26
|
-
constructor(limits) {
|
|
156
|
+
constructor(limits, maxFiles = 10_000) {
|
|
157
|
+
this.limits = limits;
|
|
158
|
+
this.maxFiles = maxFiles;
|
|
27
159
|
this.interchange = new GenericSessionInterchangeAdapter(limits);
|
|
28
160
|
}
|
|
29
|
-
async *discover(
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
161
|
+
async *discover(scope) {
|
|
162
|
+
if (scope.allowedRoots.length === 0) {
|
|
163
|
+
throw new SessionContractError('SOURCE_NOT_AUTHORIZED', 'Grok Bot native discovery requires an explicitly authorized sand-client-persistence root; '
|
|
164
|
+
+ 'pass --grokbot-root. There is no default root and nothing is guessed for macOS or Windows.');
|
|
165
|
+
}
|
|
166
|
+
let count = 0;
|
|
167
|
+
for (const root of [...scope.allowedRoots].sort()) {
|
|
168
|
+
let directory;
|
|
169
|
+
try {
|
|
170
|
+
directory = await opendir(resolve(root));
|
|
171
|
+
}
|
|
172
|
+
catch {
|
|
173
|
+
continue;
|
|
174
|
+
}
|
|
175
|
+
for await (const dirent of directory) {
|
|
176
|
+
// Never recurse, never follow symlinks: only plain files directly
|
|
177
|
+
// under the authorized root are even filename-classified.
|
|
178
|
+
if (!dirent.isFile())
|
|
179
|
+
continue;
|
|
180
|
+
const classification = classifyGrokbotBlobName(dirent.name);
|
|
181
|
+
if (classification?.kind !== 'transcript-replica')
|
|
182
|
+
continue;
|
|
183
|
+
if (++count > this.maxFiles) {
|
|
184
|
+
throw new SessionContractError('RESOURCE_LIMIT_EXCEEDED', 'Grok Bot native discovery exceeded the authorized file limit', { limit: 'maxFiles', configured: this.maxFiles, observed: count });
|
|
185
|
+
}
|
|
186
|
+
yield {
|
|
187
|
+
provider: 'grokbot',
|
|
188
|
+
locator: resolve(root, dirent.name),
|
|
189
|
+
locatorClass: GROKBOT_NATIVE_REPLICA_LOCATOR_CLASS,
|
|
190
|
+
};
|
|
191
|
+
}
|
|
192
|
+
}
|
|
33
193
|
}
|
|
34
194
|
async inspect(source) {
|
|
35
|
-
|
|
36
|
-
|
|
195
|
+
if (source.locatorClass === GROKBOT_LOCATOR_CLASS) {
|
|
196
|
+
return this.interchange.inspect(source);
|
|
197
|
+
}
|
|
198
|
+
this.assertNativeReplica(source);
|
|
199
|
+
const native = await this.readReplica(source);
|
|
200
|
+
return {
|
|
201
|
+
sourceSchemaVersion: GROKBOT_NATIVE_SCHEMA_VERSION,
|
|
202
|
+
consistency: native.truncated ? 'provisional' : 'complete',
|
|
203
|
+
operationalState: 'available',
|
|
204
|
+
// No native evidence links a conversation to a workspace/cwd; never
|
|
205
|
+
// fabricate one.
|
|
206
|
+
};
|
|
37
207
|
}
|
|
38
208
|
async *stream(source, cursor) {
|
|
39
|
-
|
|
40
|
-
|
|
209
|
+
if (source.locatorClass === GROKBOT_LOCATOR_CLASS) {
|
|
210
|
+
yield* this.interchange.stream(source, cursor);
|
|
211
|
+
return;
|
|
212
|
+
}
|
|
213
|
+
this.assertNativeReplica(source);
|
|
214
|
+
const native = await this.readReplica(source);
|
|
215
|
+
const conversationId = grokbotConversationIdFromLocator(source.locator);
|
|
216
|
+
if (!conversationId) {
|
|
217
|
+
throw new SessionContractError('SOURCE_NOT_AUTHORIZED', 'Grok Bot native locator does not decode to an authorized transcript-replica key');
|
|
218
|
+
}
|
|
219
|
+
const lastSeq = parseNativeCursor(cursor?.value);
|
|
220
|
+
const seen = new Set();
|
|
221
|
+
for (const entry of native.entries) {
|
|
222
|
+
if (seen.has(entry.seq)) {
|
|
223
|
+
throw new SessionContractError('DUPLICATE_NATIVE_ID', 'Grok Bot transcript replica contains a duplicate entry sequence');
|
|
224
|
+
}
|
|
225
|
+
seen.add(entry.seq);
|
|
226
|
+
if (entry.seq <= lastSeq)
|
|
227
|
+
continue;
|
|
228
|
+
const mapped = mapGrokbotEntry(entry);
|
|
229
|
+
if (!mapped)
|
|
230
|
+
continue; // Unrecognized entry kind: skipped, never fabricated.
|
|
231
|
+
yield {
|
|
232
|
+
nativeSessionId: conversationId,
|
|
233
|
+
nativeEventId: mapped.nativeEventId,
|
|
234
|
+
sequence: mapped.sequence,
|
|
235
|
+
kind: mapped.kind,
|
|
236
|
+
role: mapped.role,
|
|
237
|
+
participant: mapped.participant,
|
|
238
|
+
text: mapped.text,
|
|
239
|
+
occurredAt: mapped.occurredAt,
|
|
240
|
+
// Opaque provider-native resume token: the importer stores this
|
|
241
|
+
// verbatim (positionKind: 'provider-native') and never reinterprets
|
|
242
|
+
// it as a byte offset. It encodes the last imported native `seq`,
|
|
243
|
+
// which is monotonic and stable across the bounded cache evicting
|
|
244
|
+
// old entries. See the class-level doc comment for the full
|
|
245
|
+
// rationale.
|
|
246
|
+
sourceCursor: `native:${entry.seq}`,
|
|
247
|
+
rawReference: { locatorClass: GROKBOT_NATIVE_REPLICA_LOCATOR_CLASS, sequence: entry.seq },
|
|
248
|
+
extensions: mapped.extensions,
|
|
249
|
+
};
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
assertNativeReplica(source) {
|
|
253
|
+
if (source.locatorClass !== GROKBOT_NATIVE_REPLICA_LOCATOR_CLASS) {
|
|
254
|
+
throw new SessionContractError('UNSUPPORTED_OPERATION', `Grok Bot supports only locatorClass "${GROKBOT_LOCATOR_CLASS}" or `
|
|
255
|
+
+ `"${GROKBOT_NATIVE_REPLICA_LOCATOR_CLASS}" (got "${source.locatorClass}"). `
|
|
256
|
+
+ 'Do not reuse Cursor or other provider locators.');
|
|
257
|
+
}
|
|
258
|
+
// Enforce the filename allowlist before any read, not only in discover():
|
|
259
|
+
// a caller can hand inspect()/stream() any path with the native class.
|
|
260
|
+
if (!grokbotConversationIdFromLocator(source.locator)) {
|
|
261
|
+
throw new SessionContractError('SOURCE_NOT_AUTHORIZED', 'Grok Bot native locator does not decode to an authorized transcript-replica key');
|
|
262
|
+
}
|
|
41
263
|
}
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
264
|
+
async readReplica(source) {
|
|
265
|
+
const { value } = await readBoundedJson({
|
|
266
|
+
selectedPath: source.locator,
|
|
267
|
+
allowedRoots: source.authorizedScope.allowedRoots,
|
|
268
|
+
}, this.limits);
|
|
269
|
+
const parsed = GrokbotReplicaDocumentSchema.safeParse(value);
|
|
270
|
+
if (!parsed.success) {
|
|
271
|
+
throw malformedGrokbotSource('transcript replica', parsed.error);
|
|
46
272
|
}
|
|
273
|
+
assertSupportedSchemaMajor(`${parsed.data.schemaVersion}.0.0`, GROKBOT_NATIVE_SCHEMA_MAJOR);
|
|
274
|
+
const { entries, precedingTimestampMs } = parsed.data.value;
|
|
275
|
+
// The resume cursor is the last yielded seq, so stream in seq order even
|
|
276
|
+
// if the cache stores entries out of order.
|
|
277
|
+
entries.sort((left, right) => left.seq - right.seq);
|
|
278
|
+
// A window that no longer starts at seq 1 has evicted history, whether or
|
|
279
|
+
// not the optional precedingTimestampMs hint is present.
|
|
280
|
+
const truncated = entries.length > 0
|
|
281
|
+
&& (entries[0].seq > 1 || (precedingTimestampMs ?? 0) > 0);
|
|
282
|
+
return { entries, truncated };
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
function parseNativeCursor(value) {
|
|
286
|
+
if (!value)
|
|
287
|
+
return 0;
|
|
288
|
+
const raw = value.startsWith('native:') ? value.slice('native:'.length) : value;
|
|
289
|
+
if (!/^\d+$/.test(raw))
|
|
290
|
+
throw new SessionContractError('SCHEMA_DRIFT', 'invalid Grok Bot native cursor', schemaIssueDetail('cursor'));
|
|
291
|
+
return Number(raw);
|
|
292
|
+
}
|
|
293
|
+
function mapGrokbotEntry(entry) {
|
|
294
|
+
const occurredAt = new Date(entry.timestampMs).toISOString();
|
|
295
|
+
switch (entry.kind) {
|
|
296
|
+
case 'send-message':
|
|
297
|
+
return mapSendMessage(entry, occurredAt);
|
|
298
|
+
case 'message':
|
|
299
|
+
return mapMessage(entry, occurredAt);
|
|
300
|
+
case 'user-attachment':
|
|
301
|
+
return mapUserAttachment(entry, occurredAt);
|
|
302
|
+
case 'event':
|
|
303
|
+
return mapEvent(entry, occurredAt);
|
|
304
|
+
case 'notice':
|
|
305
|
+
return mapNotice(entry, occurredAt);
|
|
306
|
+
default:
|
|
307
|
+
// Unrecognized entry kind: safely skipped, never fabricated into a record.
|
|
308
|
+
return null;
|
|
47
309
|
}
|
|
48
310
|
}
|
|
311
|
+
function malformedGrokbotSource(subject, error) {
|
|
312
|
+
// Include only schema paths and codes, never Zod messages or input values.
|
|
313
|
+
const issues = error.issues.map((issue) => `${issue.path.join('.') || '<root>'} (${issue.code})`);
|
|
314
|
+
return new SessionContractError('MALFORMED_SOURCE', `Grok Bot ${subject} is malformed at ${issues.join(', ')}`, schemaRejectionDetail(error));
|
|
315
|
+
}
|
|
316
|
+
function mapSendMessage(raw, occurredAt) {
|
|
317
|
+
const messageType = z.object({ type: z.string().min(1) }).safeParse(raw.message);
|
|
318
|
+
if (messageType.success && !SendMessageEntrySchema.shape.message.options.some((option) => option.shape.type.value === messageType.data.type)) {
|
|
319
|
+
// Like unknown entry kinds, unknown message types are skipped without inventing content.
|
|
320
|
+
// Known types still go through their full schema validation below.
|
|
321
|
+
return null;
|
|
322
|
+
}
|
|
323
|
+
const parsed = SendMessageEntrySchema.safeParse(raw);
|
|
324
|
+
if (!parsed.success) {
|
|
325
|
+
throw malformedGrokbotSource('send-message entry', parsed.error);
|
|
326
|
+
}
|
|
327
|
+
const entry = parsed.data;
|
|
328
|
+
const { message } = entry;
|
|
329
|
+
let text;
|
|
330
|
+
switch (message.type) {
|
|
331
|
+
case 'text':
|
|
332
|
+
text = message.content;
|
|
333
|
+
break;
|
|
334
|
+
case 'widget':
|
|
335
|
+
text = `[widget] ${message.widget.prompt} -> ${stringOrEmpty(entry.respondedValue)}`;
|
|
336
|
+
break;
|
|
337
|
+
case 'email-draft':
|
|
338
|
+
text = `[email-draft] ${message.draft.subject ?? ''}\n${message.draft.body}`;
|
|
339
|
+
break;
|
|
340
|
+
case 'slack-draft':
|
|
341
|
+
text = `[slack-draft] ${message.draft.target ?? ''}\n${message.draft.body}`;
|
|
342
|
+
break;
|
|
343
|
+
case 'attachment':
|
|
344
|
+
text = `[attachment] ${message.file_name} (${message.url})`;
|
|
345
|
+
break;
|
|
346
|
+
case 'user-form':
|
|
347
|
+
text = `[user-form] ${message.formRequest.title}`;
|
|
348
|
+
break;
|
|
349
|
+
case 'secret-request':
|
|
350
|
+
text = `[secret-request] ${message.secretRequest.label} (value not exported)`;
|
|
351
|
+
break;
|
|
352
|
+
default:
|
|
353
|
+
text = '';
|
|
354
|
+
}
|
|
355
|
+
return {
|
|
356
|
+
nativeEventId: entry.id,
|
|
357
|
+
sequence: entry.seq,
|
|
358
|
+
kind: `grokbot.send-message.${message.type}`,
|
|
359
|
+
role: 'assistant',
|
|
360
|
+
text,
|
|
361
|
+
occurredAt,
|
|
362
|
+
extensions: {
|
|
363
|
+
nativeKind: 'send-message',
|
|
364
|
+
messageType: message.type,
|
|
365
|
+
secretProvided: entry.secretProvided,
|
|
366
|
+
provenance: { acquisition: GROKBOT_NATIVE_REPLICA_LOCATOR_CLASS },
|
|
367
|
+
},
|
|
368
|
+
};
|
|
369
|
+
}
|
|
370
|
+
function mapMessage(raw, occurredAt) {
|
|
371
|
+
const parsed = MessageEntrySchema.safeParse(raw);
|
|
372
|
+
if (!parsed.success) {
|
|
373
|
+
throw malformedGrokbotSource('message entry', parsed.error);
|
|
374
|
+
}
|
|
375
|
+
const entry = parsed.data;
|
|
376
|
+
return {
|
|
377
|
+
nativeEventId: entry.id,
|
|
378
|
+
sequence: entry.seq,
|
|
379
|
+
kind: 'grokbot.message',
|
|
380
|
+
role: entry.role,
|
|
381
|
+
participant: entry.fromAgent?.name ?? entry.fromAgent?.id,
|
|
382
|
+
text: entry.content,
|
|
383
|
+
occurredAt,
|
|
384
|
+
extensions: {
|
|
385
|
+
nativeKind: 'message',
|
|
386
|
+
fromAgent: entry.fromAgent,
|
|
387
|
+
provenance: { acquisition: GROKBOT_NATIVE_REPLICA_LOCATOR_CLASS },
|
|
388
|
+
},
|
|
389
|
+
};
|
|
390
|
+
}
|
|
391
|
+
function mapUserAttachment(raw, occurredAt) {
|
|
392
|
+
const parsed = UserAttachmentEntrySchema.safeParse(raw);
|
|
393
|
+
if (!parsed.success) {
|
|
394
|
+
throw malformedGrokbotSource('user-attachment entry', parsed.error);
|
|
395
|
+
}
|
|
396
|
+
const entry = parsed.data;
|
|
397
|
+
return {
|
|
398
|
+
nativeEventId: entry.id,
|
|
399
|
+
sequence: entry.seq,
|
|
400
|
+
kind: 'grokbot.user-attachment',
|
|
401
|
+
role: 'user',
|
|
402
|
+
text: `[user-attachment] ${entry.file_name} `
|
|
403
|
+
+ `(${entry.width ?? '?'}x${entry.height ?? '?'}, ${entry.byteSize ?? '?'} bytes)`,
|
|
404
|
+
occurredAt,
|
|
405
|
+
extensions: {
|
|
406
|
+
nativeKind: 'user-attachment',
|
|
407
|
+
fileName: entry.file_name,
|
|
408
|
+
filePath: entry.file_path,
|
|
409
|
+
width: entry.width,
|
|
410
|
+
height: entry.height,
|
|
411
|
+
byteSize: entry.byteSize,
|
|
412
|
+
provenance: { acquisition: GROKBOT_NATIVE_REPLICA_LOCATOR_CLASS },
|
|
413
|
+
},
|
|
414
|
+
};
|
|
415
|
+
}
|
|
416
|
+
function mapEvent(raw, occurredAt) {
|
|
417
|
+
const parsed = EventEntrySchema.safeParse(raw);
|
|
418
|
+
if (!parsed.success) {
|
|
419
|
+
throw malformedGrokbotSource('event entry', parsed.error);
|
|
420
|
+
}
|
|
421
|
+
const entry = parsed.data;
|
|
422
|
+
const label = stringOrEmpty(entry.event.kind) || stringOrEmpty(entry.event.type) || 'event';
|
|
423
|
+
return {
|
|
424
|
+
nativeEventId: entry.id,
|
|
425
|
+
sequence: entry.seq,
|
|
426
|
+
kind: 'grokbot.event',
|
|
427
|
+
role: 'system',
|
|
428
|
+
text: `[event] ${label}`,
|
|
429
|
+
occurredAt,
|
|
430
|
+
extensions: {
|
|
431
|
+
nativeKind: 'event',
|
|
432
|
+
event: entry.event,
|
|
433
|
+
provenance: { acquisition: GROKBOT_NATIVE_REPLICA_LOCATOR_CLASS },
|
|
434
|
+
},
|
|
435
|
+
};
|
|
436
|
+
}
|
|
437
|
+
function mapNotice(raw, occurredAt) {
|
|
438
|
+
const parsed = NoticeEntrySchema.safeParse(raw);
|
|
439
|
+
if (!parsed.success) {
|
|
440
|
+
throw malformedGrokbotSource('notice entry', parsed.error);
|
|
441
|
+
}
|
|
442
|
+
const entry = parsed.data;
|
|
443
|
+
return {
|
|
444
|
+
nativeEventId: entry.id,
|
|
445
|
+
sequence: entry.seq,
|
|
446
|
+
kind: 'grokbot.notice',
|
|
447
|
+
role: 'system',
|
|
448
|
+
text: entry.text,
|
|
449
|
+
occurredAt,
|
|
450
|
+
extensions: {
|
|
451
|
+
nativeKind: 'notice',
|
|
452
|
+
provenance: { acquisition: GROKBOT_NATIVE_REPLICA_LOCATOR_CLASS },
|
|
453
|
+
},
|
|
454
|
+
};
|
|
455
|
+
}
|
|
456
|
+
function stringOrEmpty(value) {
|
|
457
|
+
return typeof value === 'string' ? value : '';
|
|
458
|
+
}
|
|
49
459
|
//# sourceMappingURL=grokbot.js.map
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
|
-
import { SessionContractError, assertSupportedSchemaMajor, } from '../contracts.js';
|
|
3
|
-
import {
|
|
2
|
+
import { schemaRejectionDetail, schemaIssueDetail, SessionContractError, assertSupportedSchemaMajor, } from '../contracts.js';
|
|
3
|
+
import { streamBoundedJsonLines, } from '../readers.js';
|
|
4
4
|
export const HERMES_ADAPTER_VERSION = '1.0.0';
|
|
5
5
|
export const HERMES_EXPORT_SCHEMA_VERSION = '1.0.0';
|
|
6
6
|
export const HERMES_NATIVE_SCHEMA_VERSION = '23.0.0';
|
|
@@ -73,6 +73,15 @@ export class HermesSessionAdapter {
|
|
|
73
73
|
// Native exports and consistent snapshots require explicit selection.
|
|
74
74
|
}
|
|
75
75
|
async inspect(source) {
|
|
76
|
+
if (source.locatorClass === 'hermes-export-jsonl'
|
|
77
|
+
|| source.locatorClass === 'hermes-consistent-snapshot-jsonl') {
|
|
78
|
+
const records = this.stream(source);
|
|
79
|
+
let result = await records.next();
|
|
80
|
+
while (!result.done)
|
|
81
|
+
result = await records.next();
|
|
82
|
+
if (result.value)
|
|
83
|
+
return result.value;
|
|
84
|
+
}
|
|
76
85
|
const parsed = await this.readSource(source);
|
|
77
86
|
return {
|
|
78
87
|
sourceSchemaVersion: parsed.schemaVersion,
|
|
@@ -94,21 +103,23 @@ export class HermesSessionAdapter {
|
|
|
94
103
|
let outputIndex = 0;
|
|
95
104
|
let schema = null;
|
|
96
105
|
let sawRecord = false;
|
|
106
|
+
let complete = true;
|
|
97
107
|
for await (const line of input) {
|
|
98
108
|
sawRecord = true;
|
|
99
109
|
const parsed = ExportSchema.safeParse(line.value);
|
|
100
110
|
if (!parsed.success) {
|
|
101
|
-
throw new SessionContractError('MALFORMED_SOURCE', 'Hermes export is malformed');
|
|
111
|
+
throw new SessionContractError('MALFORMED_SOURCE', 'Hermes export is malformed', schemaRejectionDetail(parsed.error));
|
|
102
112
|
}
|
|
113
|
+
complete &&= ended(parsed.data);
|
|
103
114
|
const currentSchema = declaredSchema(parsed.data);
|
|
104
115
|
if (schema && schema !== currentSchema) {
|
|
105
|
-
throw new SessionContractError('SCHEMA_DRIFT', 'mixed Hermes export schemas');
|
|
116
|
+
throw new SessionContractError('SCHEMA_DRIFT', 'mixed Hermes export schemas', schemaIssueDetail('schemaVersion'));
|
|
106
117
|
}
|
|
107
118
|
schema = currentSchema;
|
|
108
119
|
assertSupportedSchemaMajor(schema, 23);
|
|
109
120
|
if (source.locatorClass === 'hermes-consistent-snapshot-jsonl'
|
|
110
121
|
&& parsed.data.snapshotConsistency !== 'sqlite-backup') {
|
|
111
|
-
throw new SessionContractError('SCHEMA_DRIFT', 'Hermes snapshot lacks sqlite3.backup() consistency evidence');
|
|
122
|
+
throw new SessionContractError('SCHEMA_DRIFT', 'Hermes snapshot lacks sqlite3.backup() consistency evidence', schemaIssueDetail('snapshotConsistency'));
|
|
112
123
|
}
|
|
113
124
|
for (const record of normalizeSession(parsed.data, line, source.locatorClass)) {
|
|
114
125
|
if (outputIndex++ >= start)
|
|
@@ -116,16 +127,21 @@ export class HermesSessionAdapter {
|
|
|
116
127
|
}
|
|
117
128
|
}
|
|
118
129
|
if (!sawRecord)
|
|
119
|
-
throw new SessionContractError('MALFORMED_SOURCE', 'Hermes source is empty');
|
|
130
|
+
throw new SessionContractError('MALFORMED_SOURCE', 'Hermes source is empty', schemaIssueDetail('<root>'));
|
|
120
131
|
if (input.incompleteTail && source.locatorClass !== 'hermes-export-jsonl') {
|
|
121
132
|
throw new SessionContractError('TRUNCATED_SOURCE', 'Hermes consistent snapshot is truncated');
|
|
122
133
|
}
|
|
123
|
-
return
|
|
134
|
+
return {
|
|
135
|
+
sourceSchemaVersion: HERMES_EXPORT_SCHEMA_VERSION,
|
|
136
|
+
consistency: complete ? 'complete' : 'provisional',
|
|
137
|
+
operationalState: 'available',
|
|
138
|
+
};
|
|
124
139
|
}
|
|
125
140
|
const parsed = await this.readSource(source);
|
|
126
141
|
const start = parseCursor(cursor?.value);
|
|
127
142
|
for (const record of parsed.records.slice(start))
|
|
128
143
|
yield record;
|
|
144
|
+
return undefined;
|
|
129
145
|
}
|
|
130
146
|
async readSource(source) {
|
|
131
147
|
if (source.locatorClass === 'hermes-state-db') {
|
|
@@ -143,37 +159,19 @@ export class HermesSessionAdapter {
|
|
|
143
159
|
value, sequence, byteOffset: sequence, byteLength: Buffer.byteLength(JSON.stringify(value)),
|
|
144
160
|
}));
|
|
145
161
|
}
|
|
146
|
-
else if (source.locatorClass === 'hermes-export-jsonl'
|
|
147
|
-
|| source.locatorClass === 'hermes-consistent-snapshot-jsonl') {
|
|
148
|
-
const result = await readBoundedJsonLines({
|
|
149
|
-
selectedPath: source.locator,
|
|
150
|
-
allowedRoots: source.authorizedScope.allowedRoots,
|
|
151
|
-
}, {
|
|
152
|
-
consistency: source.locatorClass === 'hermes-export-jsonl' ? 'provisional' : 'complete',
|
|
153
|
-
limits: this.limits,
|
|
154
|
-
});
|
|
155
|
-
input = result.records;
|
|
156
|
-
if (result.incompleteTail && source.locatorClass !== 'hermes-export-jsonl') {
|
|
157
|
-
throw new SessionContractError('TRUNCATED_SOURCE', 'Hermes consistent snapshot is truncated');
|
|
158
|
-
}
|
|
159
|
-
}
|
|
160
162
|
else {
|
|
161
163
|
throw new SessionContractError('UNSUPPORTED_OPERATION', 'unsupported Hermes source class');
|
|
162
164
|
}
|
|
163
165
|
if (input.length === 0)
|
|
164
|
-
throw new SessionContractError('MALFORMED_SOURCE', 'Hermes source is empty');
|
|
166
|
+
throw new SessionContractError('MALFORMED_SOURCE', 'Hermes source is empty', schemaIssueDetail('<root>'));
|
|
165
167
|
const parsed = input.map((line) => {
|
|
166
168
|
const result = ExportSchema.safeParse(line.value);
|
|
167
169
|
if (!result.success)
|
|
168
|
-
throw new SessionContractError('MALFORMED_SOURCE', 'Hermes export is malformed');
|
|
170
|
+
throw new SessionContractError('MALFORMED_SOURCE', 'Hermes export is malformed', schemaRejectionDetail(result.error));
|
|
169
171
|
return { line, value: result.data };
|
|
170
172
|
});
|
|
171
173
|
const schemaVersion = declaredVersion(parsed.map(({ value }) => value));
|
|
172
174
|
assertSupportedSchemaMajor(schemaVersion, 23);
|
|
173
|
-
if (source.locatorClass === 'hermes-consistent-snapshot-jsonl'
|
|
174
|
-
&& parsed.some(({ value }) => value.snapshotConsistency !== 'sqlite-backup')) {
|
|
175
|
-
throw new SessionContractError('SCHEMA_DRIFT', 'Hermes snapshot lacks sqlite3.backup() consistency evidence');
|
|
176
|
-
}
|
|
177
175
|
return {
|
|
178
176
|
schemaVersion: HERMES_EXPORT_SCHEMA_VERSION,
|
|
179
177
|
consistency: parsed.every(({ value }) => ended(value)) ? 'complete' : 'provisional',
|
|
@@ -291,7 +289,7 @@ function ended(value) {
|
|
|
291
289
|
function declaredVersion(values) {
|
|
292
290
|
const versions = new Set(values.map(declaredSchema));
|
|
293
291
|
if (versions.size !== 1)
|
|
294
|
-
throw new SessionContractError('SCHEMA_DRIFT', 'mixed Hermes export schemas');
|
|
292
|
+
throw new SessionContractError('SCHEMA_DRIFT', 'mixed Hermes export schemas', schemaIssueDetail('schemaVersion'));
|
|
295
293
|
return [...versions][0];
|
|
296
294
|
}
|
|
297
295
|
function declaredSchema(value) {
|
|
@@ -330,7 +328,7 @@ function parseCursor(value) {
|
|
|
330
328
|
if (!value)
|
|
331
329
|
return 0;
|
|
332
330
|
if (!/^\d+$/.test(value))
|
|
333
|
-
throw new SessionContractError('SCHEMA_DRIFT', 'invalid Hermes cursor');
|
|
331
|
+
throw new SessionContractError('SCHEMA_DRIFT', 'invalid Hermes cursor', schemaIssueDetail('cursor'));
|
|
334
332
|
return Number(value);
|
|
335
333
|
}
|
|
336
334
|
const SESSION_KEYS = new Set([
|