akm-cli 0.10.261012-beta → 0.10.261014-beta
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/CHANGELOG.md +710 -3
- package/README.md +15 -0
- package/SECURITY.md +11 -10
- package/STABILITY.md +47 -51
- package/dist/assets/hints/cli-hints-full.md +21 -19
- package/dist/assets/hints/cli-hints-short.md +3 -4
- package/dist/assets/opencode/akm-plugin.js +177 -0
- package/dist/assets/stash-skeleton/README.md +1 -1
- package/dist/assets/tasks/core/improve.yml +1 -1
- package/dist/assets/tasks/improve/akm-improve-consolidate.yml +1 -1
- package/dist/assets/ui/config.js +27 -10
- package/dist/assets/workflows/workflow-template.md +2 -2
- package/dist/cli/clack.js +3 -1
- package/dist/cli/selection.js +33 -0
- package/dist/cli/shared.js +14 -1
- package/dist/cli/unknown-flags.js +6 -37
- package/dist/cli.js +69 -48
- package/dist/commands/agent/agent-dispatch.js +17 -25
- package/dist/commands/agent/contribute-cli.js +9 -8
- package/dist/commands/command/command-cli.js +4 -8
- package/dist/commands/command/command-execution.js +25 -39
- package/dist/commands/command/execution-source-loader.js +10 -14
- package/dist/commands/completions.js +1 -1
- package/dist/commands/config-cli.js +14 -5
- package/dist/commands/env/child-env.js +12 -14
- package/dist/commands/env/env-binding.js +47 -58
- package/dist/commands/env/env-cli.js +22 -24
- package/dist/commands/env/env.js +10 -58
- package/dist/commands/env/secret-cli.js +11 -29
- package/dist/commands/env/secret.js +3 -10
- package/dist/commands/health/checks.js +10 -849
- package/dist/commands/health/connections-and-harnesses-check.js +109 -0
- package/dist/commands/health/egress.js +3 -3
- package/dist/commands/health/html-report.js +9 -10
- package/dist/commands/health/plugin-staleness.js +18 -11
- package/dist/commands/health/report-view-model.js +16 -12
- package/dist/commands/health/scheduler-binary.js +1 -1
- package/dist/commands/health/semantic-search-check.js +85 -0
- package/dist/commands/health/type-directory-check.js +0 -3
- package/dist/commands/health.js +30 -42
- package/dist/commands/improve/consolidate/pair-pass.js +10 -25
- package/dist/commands/improve/consolidate.js +10 -15
- package/dist/commands/improve/distill.js +5 -17
- package/dist/commands/improve/eligibility.js +1 -3
- package/dist/commands/improve/execution.js +37 -40
- package/dist/commands/improve/extract-cli.js +6 -11
- package/dist/commands/improve/extract-prompt.js +2 -2
- package/dist/commands/improve/extract.js +67 -97
- package/dist/commands/improve/improve-cli.js +22 -128
- package/dist/commands/improve/improve-report.js +1 -1
- package/dist/commands/improve/improve-strategies.js +25 -108
- package/dist/commands/improve/improve.js +10 -14
- package/dist/commands/improve/loop-stages.js +3 -0
- package/dist/commands/improve/memory/memory-improve.js +1 -1
- package/dist/commands/improve/preparation.js +8 -13
- package/dist/commands/improve/reflect.js +203 -332
- package/dist/commands/improve/retrieval-scope.js +1 -1
- package/dist/commands/improve/session-asset.js +3 -2
- package/dist/commands/improve/stage.js +87 -115
- package/dist/commands/lint/base-linter.js +3 -3
- package/dist/commands/lint/env-key-rules.js +7 -6
- package/dist/commands/lint/index.js +3 -3
- package/dist/commands/models-cli.js +103 -63
- package/dist/commands/proposal/drain.js +26 -39
- package/dist/commands/proposal/proposal-cli.js +14 -18
- package/dist/commands/proposal/propose-cli.js +4 -2
- package/dist/commands/proposal/propose.js +37 -64
- package/dist/commands/proposal/repository.js +17 -17
- package/dist/commands/proposal/validators/proposal-validators.js +3 -6
- package/dist/commands/read/curate.js +10 -6
- package/dist/commands/read/registry-search.js +2 -48
- package/dist/commands/read/search-cli.js +1 -8
- package/dist/commands/read/search.js +5 -6
- package/dist/commands/read/show.js +6 -29
- package/dist/commands/remember.js +25 -40
- package/dist/commands/sources/add-cli.js +8 -63
- package/dist/commands/sources/bundle-cli.js +8 -9
- package/dist/commands/sources/bundle-config-ops.js +2 -2
- package/dist/commands/sources/info.js +12 -1
- package/dist/commands/sources/init.js +1 -1
- package/dist/commands/sources/installed-stashes.js +119 -63
- package/dist/commands/sources/migration-help.js +1 -1
- package/dist/commands/sources/plugin-upgrade.js +8 -15
- package/dist/commands/sources/schema-repair.js +4 -10
- package/dist/commands/sources/source-add.js +2 -2
- package/dist/commands/sources/source-clone.js +31 -7
- package/dist/commands/sources/source-manage.js +4 -4
- package/dist/commands/targets.js +175 -0
- package/dist/commands/tasks/explain.js +104 -69
- package/dist/commands/tasks/tasks-cli.js +9 -11
- package/dist/commands/tasks/tasks.js +75 -97
- package/dist/commands/ui/api.js +11 -3
- package/dist/commands/ui/redact.js +5 -31
- package/dist/commands/ui/workspace-actions.js +1 -1
- package/dist/commands/workflow/plan.js +48 -9
- package/dist/commands/workflow-cli.js +40 -45
- package/dist/core/adapter/adapters/agent-skills-adapter.js +10 -11
- package/dist/core/adapter/adapters/akm-adapter.js +36 -41
- package/dist/core/adapter/adapters/akm-lint.js +10 -12
- package/dist/core/adapter/adapters/akm-metadata.js +2 -2
- package/dist/core/adapter/adapters/akm-task-adapter.js +8 -9
- package/dist/core/adapter/adapters/akm-workflow-adapter.js +5 -5
- package/dist/core/adapter/adapters/claude-adapter.js +1 -1
- package/dist/core/adapter/adapters/dotenv-adapter.js +7 -6
- package/dist/core/adapter/adapters/generic-files-adapter.js +5 -5
- package/dist/core/adapter/adapters/index.js +3 -4
- package/dist/core/adapter/adapters/llm-wiki-adapter.js +12 -14
- package/dist/core/adapter/adapters/okf-adapter.js +8 -10
- package/dist/core/adapter/adapters/opencode-adapter.js +1 -1
- package/dist/core/adapter/adapters/shared.js +3 -3
- package/dist/core/adapter/adapters/tool-dir-shared.js +7 -25
- package/dist/core/adapter/adapters/website-snapshot-adapter.js +3 -3
- package/dist/core/adapter/detect-adapter.js +1 -1
- package/dist/core/adapter/execution-source.js +13 -35
- package/dist/core/adapter/registry.js +1 -1
- package/dist/core/adapter/validate-context.js +2 -4
- package/dist/core/asset/asset-placement.js +1 -1
- package/dist/core/asset/asset-ref.js +3 -3
- package/dist/core/asset/resolve-ref.js +5 -0
- package/dist/core/bundle-rename.js +12 -4
- package/dist/core/closest-match.js +37 -0
- package/dist/core/common.js +37 -57
- package/dist/core/config/config-io.js +26 -18
- package/dist/core/config/config-schema.js +19 -106
- package/dist/core/config/config-sources.js +3 -3
- package/dist/core/config/config-types.js +4 -4
- package/dist/core/config/config-walker.js +50 -77
- package/dist/core/config/config.js +438 -109
- package/dist/core/config/convert-engine-references.js +114 -0
- package/dist/core/config/convert-engines-shared.js +40 -0
- package/dist/core/config/convert-engines.js +300 -0
- package/dist/core/config/convert-models-overlay.js +137 -0
- package/dist/core/config/credentials.js +304 -0
- package/dist/core/config/engine-semantics.js +3 -3
- package/dist/core/config/migrate-keys.js +222 -0
- package/dist/core/config/model-aliases.js +37 -0
- package/dist/core/config/models-file.js +34 -0
- package/dist/core/config/retired-engines.js +53 -0
- package/dist/core/config/schema/connections.js +41 -0
- package/dist/core/config/schema/embedding.js +2 -2
- package/dist/core/config/schema/harnesses.js +41 -0
- package/dist/core/config/schema/improve-processes.js +9 -28
- package/dist/core/config/schema/improve.js +36 -1
- package/dist/core/config/schema/index-config.js +18 -20
- package/dist/core/config/schema/primitives.js +42 -17
- package/dist/core/config/schema/search.js +6 -11
- package/dist/core/config/schema/sources-bundles.js +9 -9
- package/dist/core/config/schema/workflow.js +2 -6
- package/dist/core/config/unusable-entries.js +66 -0
- package/dist/core/content-safety.js +3 -6
- package/dist/core/endpoint-url.js +47 -0
- package/dist/core/env-secret-ref.js +84 -73
- package/dist/core/errors.js +10 -16
- package/dist/core/extra-params.js +3 -3
- package/dist/core/improve-result.js +8 -9
- package/dist/core/json-schema.js +1 -1
- package/dist/core/lesson-lint.js +1 -1
- package/dist/core/llm-inference.js +80 -0
- package/dist/core/parse.js +2 -2
- package/dist/core/paths.js +33 -10
- package/dist/core/recognition-util.js +8 -10
- package/dist/core/redaction.js +94 -55
- package/dist/core/ref-token.js +82 -0
- package/dist/core/secret-value.js +14 -0
- package/dist/core/state/migrations.js +17 -22
- package/dist/core/structured.js +2 -68
- package/dist/core/subprocess.js +63 -22
- package/dist/core/type-presentation.js +10 -14
- package/dist/core/write-source.js +20 -4
- package/dist/execution/input-contract.js +3 -6
- package/dist/execution/notices.js +49 -0
- package/dist/execution/resolved-request.js +24 -40
- package/dist/execution/source.js +21 -45
- package/dist/execution/target-ref.js +2 -2
- package/dist/indexer/bundle-identity-guard.js +6 -5
- package/dist/indexer/ensure-index.js +1 -1
- package/dist/indexer/index-writer-lock.js +1 -1
- package/dist/indexer/indexer.js +46 -42
- package/dist/indexer/installations.js +12 -22
- package/dist/indexer/lookup/adapter-concept-owner.js +40 -14
- package/dist/indexer/materialize-embeddings.js +20 -16
- package/dist/indexer/passes/memory-inference.js +21 -50
- package/dist/indexer/passes/metadata.js +5 -5
- package/dist/indexer/scan/doc-to-entry.js +1 -1
- package/dist/indexer/scan/drain-dir.js +9 -11
- package/dist/indexer/search/db-search.js +9 -7
- package/dist/indexer/search/search-source.js +42 -22
- package/dist/indexer/usage/usage-events.js +2 -3
- package/dist/indexer/walk/index-context.js +2 -1
- package/dist/indexer/walk/matchers.js +3 -11
- package/dist/indexer/walk/path-resolver.js +13 -68
- package/dist/indexer/walk/walker.js +32 -26
- package/dist/integrations/agent/akm-read-tools.js +81 -0
- package/dist/integrations/agent/config.js +1 -1
- package/dist/integrations/agent/detect.js +32 -36
- package/dist/integrations/agent/execution.js +130 -428
- package/dist/integrations/agent/index.js +1 -1
- package/dist/integrations/agent/profiles.js +24 -28
- package/dist/integrations/agent/prompts.js +17 -30
- package/dist/integrations/agent/request-lowering.js +67 -101
- package/dist/integrations/agent/resolution.js +332 -0
- package/dist/integrations/agent/runner-dispatch.js +156 -181
- package/dist/integrations/agent/runner.js +20 -70
- package/dist/integrations/agent/runtime-port.js +4 -0
- package/dist/integrations/agent/runtime.js +10 -0
- package/dist/integrations/agent/spawn.js +65 -190
- package/dist/integrations/harnesses/aider/index.js +19 -39
- package/dist/integrations/harnesses/amazonq/index.js +17 -32
- package/dist/integrations/harnesses/claude/index.js +59 -28
- package/dist/integrations/harnesses/claude/session-log.js +7 -5
- package/dist/integrations/harnesses/codex/index.js +19 -31
- package/dist/integrations/harnesses/copilot/index.js +17 -35
- package/dist/integrations/harnesses/gemini/index.js +18 -34
- package/dist/integrations/harnesses/harness.js +36 -0
- package/dist/integrations/harnesses/index.js +20 -51
- package/dist/integrations/harnesses/opencode/agent-builder.js +132 -100
- package/dist/integrations/harnesses/opencode/index.js +11 -33
- package/dist/integrations/harnesses/opencode/roots.js +50 -0
- package/dist/integrations/harnesses/opencode/runtime/binary.js +206 -0
- package/dist/integrations/harnesses/opencode/runtime/command.js +152 -0
- package/dist/integrations/harnesses/opencode/runtime/index.js +177 -0
- package/dist/integrations/harnesses/opencode/runtime/tar.js +107 -0
- package/dist/integrations/harnesses/opencode/session-log-v1.js +15 -7
- package/dist/integrations/harnesses/opencode/session-log-v2.js +72 -48
- package/dist/integrations/harnesses/opencode/session-log.js +58 -137
- package/dist/integrations/harnesses/opencode/version.js +34 -53
- package/dist/integrations/harnesses/openhands/index.js +13 -37
- package/dist/integrations/harnesses/pi/index.js +21 -32
- package/dist/integrations/lockfile.js +1 -1
- package/dist/integrations/session-logs/index.js +11 -31
- package/dist/llm/client.js +93 -111
- package/dist/llm/embedder.js +19 -34
- package/dist/llm/embedders/connection.js +31 -0
- package/dist/llm/embedders/local-model-files.js +56 -0
- package/dist/llm/embedders/local.js +146 -115
- package/dist/llm/embedders/remote.js +26 -23
- package/dist/llm/embedders/types.js +1 -1
- package/dist/llm/index-passes.js +33 -39
- package/dist/llm/memory-infer.js +67 -77
- package/dist/llm/model-list.js +35 -0
- package/dist/llm/rerank-client.js +8 -14
- package/dist/llm/structured-call.js +45 -99
- package/dist/llm/structured.js +60 -0
- package/dist/output/renderers.js +2 -8
- package/dist/output/shapes/helpers.js +18 -44
- package/dist/output/shapes/passthrough.js +1 -0
- package/dist/output/shapes.js +1 -7
- package/dist/output/text/command-format.js +41 -39
- package/dist/output/text/health-format.js +8 -2
- package/dist/output/text/helpers.js +1 -1
- package/dist/output/text/migrate.js +12 -0
- package/dist/output/text/models.js +3 -2
- package/dist/output/text/registry-commands.js +1 -2
- package/dist/output/text/show-directives.js +16 -28
- package/dist/output/text/show-format.js +0 -2
- package/dist/output/text/targets-table.js +70 -0
- package/dist/output/text/workflow-format.js +44 -15
- package/dist/output/text.js +1 -1
- package/dist/registry/providers/skills-sh.js +1 -28
- package/dist/registry/providers/static-index.js +1 -71
- package/dist/runtime.js +6 -2
- package/dist/scripts/akm-migrate-node.js +47095 -44905
- package/dist/scripts/akm-migrate.js +46946 -44755
- package/dist/setup/detect.js +28 -273
- package/dist/setup/endpoint.js +36 -0
- package/dist/setup/semantic-assets.js +13 -19
- package/dist/setup/setup-flags.js +77 -0
- package/dist/setup/setup-plan.js +144 -0
- package/dist/setup/setup.js +134 -358
- package/dist/setup/steps/connection-shared.js +49 -101
- package/dist/setup/steps/connection.js +121 -524
- package/dist/setup/steps/embeddings.js +151 -0
- package/dist/setup/steps/harnesses.js +118 -0
- package/dist/setup/steps/platforms.js +2 -81
- package/dist/setup/steps/tasks.js +1 -2
- package/dist/setup/steps.js +10 -0
- package/dist/setup/summary.js +67 -0
- package/dist/sources/freshness.js +16 -21
- package/dist/sources/providers/git-provider.js +2 -9
- package/dist/sources/providers/provider-utils.js +13 -5
- package/dist/sources/resolve.js +12 -16
- package/dist/sources/snapshot-fetchers/robots.js +11 -12
- package/dist/sources/snapshot-fetchers/secret-seam.js +2 -4
- package/dist/sources/snapshot-fetchers/website-ingest.js +8 -15
- package/dist/sources/snapshot-fetchers/x.js +1 -1
- package/dist/standalone/onnxruntime-library.js +52 -0
- package/dist/storage/repositories/improve-ledger-repository.js +1 -1
- package/dist/storage/repositories/improve-runs-repository.js +0 -13
- package/dist/storage/repositories/index-entries-repository.js +2 -2
- package/dist/storage/repositories/proposals-repository.js +2 -2
- package/dist/storage/repositories/task-history-repository.js +2 -2
- package/dist/storage/repositories/workflow-runs-repository.js +44 -129
- package/dist/storage/sqlite-read-snapshot.js +33 -29
- package/dist/tasks/embedded.js +1 -1
- package/dist/tasks/log-redaction.js +7 -119
- package/dist/tasks/prepare/prepare-support.js +8 -7
- package/dist/tasks/prepare/prepare.js +8 -9
- package/dist/tasks/prepare/script-capture.js +9 -25
- package/dist/tasks/run/attempt-lifecycle.js +17 -35
- package/dist/tasks/run/load-task.js +54 -27
- package/dist/tasks/run/run-command-task.js +15 -10
- package/dist/tasks/run/run-native-task.js +8 -21
- package/dist/tasks/run/run-task.js +5 -8
- package/dist/tasks/run/run-workflow-task.js +14 -21
- package/dist/tasks/run/task-history.js +9 -17
- package/dist/tasks/run/task-log.js +1 -5
- package/dist/tasks/scheduler-invocation.js +13 -18
- package/dist/tasks/scheduler-sync.js +0 -1
- package/dist/tasks/source/bounded-document.js +31 -117
- package/dist/tasks/source/parse-task-source.js +0 -1
- package/dist/tasks/source/project-v4.js +5 -3
- package/dist/tasks/source/task-input-diagnostics.js +3 -4
- package/dist/tasks/source/task-source-v4.js +48 -72
- package/dist/tasks/source-v3.js +2 -5
- package/dist/tasks/task-run-reserved-flags.js +1 -2
- package/dist/workflows/authoring/authoring.js +2 -7
- package/dist/workflows/compile.js +1 -15
- package/dist/workflows/concurrency-policy.js +4 -4
- package/dist/workflows/exec/child-workflow.js +1 -4
- package/dist/workflows/exec/dispatch-redaction.js +35 -86
- package/dist/workflows/exec/environment.js +13 -77
- package/dist/workflows/exec/exec-unit.js +14 -55
- package/dist/workflows/exec/frozen-judge.js +26 -28
- package/dist/workflows/exec/native-executor.js +126 -71
- package/dist/workflows/exec/run-workflow.js +38 -42
- package/dist/workflows/exec/step-work.js +13 -17
- package/dist/workflows/exec/unit-dispatch.js +7 -21
- package/dist/workflows/freeze/environment.js +14 -119
- package/dist/workflows/freeze/freeze.js +14 -33
- package/dist/workflows/freeze/step-values.js +6 -13
- package/dist/workflows/freeze/targets/child-workflow.js +3 -5
- package/dist/workflows/freeze/targets/command.js +9 -15
- package/dist/workflows/freeze/targets/shell.js +0 -3
- package/dist/workflows/freeze/task-bindings.js +0 -1
- package/dist/workflows/parser.js +50 -59
- package/dist/workflows/plan.js +8 -2
- package/dist/workflows/renderer.js +83 -9
- package/dist/workflows/resource-limits.js +2 -2
- package/dist/workflows/runtime/run-plan.js +38 -23
- package/dist/workflows/runtime/runs.js +55 -93
- package/dist/workflows/runtime/workflow-asset-loader.js +55 -86
- package/dist/workflows/source-files.js +7 -19
- package/docs/README.md +10 -16
- package/docs/architecture/README.md +2 -37
- package/docs/architecture/adapters.md +2 -2
- package/docs/architecture/akm-core-principles.md +256 -118
- package/docs/architecture/architecture.md +283 -99
- package/docs/architecture/improvement.md +8 -2
- package/docs/architecture/internals/classification.md +1 -3
- package/docs/architecture/internals/fresh-host-rebuild-runbook.md +7 -6
- package/docs/architecture/internals/health-advisories.md +35 -74
- package/docs/architecture/internals/improve-workflow.md +27 -26
- package/docs/architecture/internals/indexing.md +3 -3
- package/docs/architecture/internals/storage-locations.md +48 -15
- package/docs/architecture/persisted-data-compat.md +10 -6
- package/docs/architecture/specs/okf-support.md +9 -11
- package/docs/architecture/specs/ref.md +7 -9
- package/docs/architecture/testing/testing-workflow.md +172 -52
- package/docs/architecture/workflow-engine.md +51 -34
- package/docs/guides/README.md +0 -1
- package/docs/guides/author-bundles.md +15 -20
- package/docs/guides/author-workflows.md +93 -71
- package/docs/guides/bundles.md +20 -16
- package/docs/guides/discover-and-load.md +1 -1
- package/docs/guides/getting-started.md +49 -3
- package/docs/guides/improve-the-library.md +10 -4
- package/docs/guides/recipes/headless-install.md +11 -16
- package/docs/guides/run-workflows.md +29 -20
- package/docs/guides/scheduling.md +2 -2
- package/docs/guides/use-with-any-agent.md +20 -22
- package/docs/integration/bundling-akm.md +19 -9
- package/docs/maintainers/README.md +2 -6
- package/docs/maintainers/release-checklist.md +73 -126
- package/docs/migration/README.md +10 -3
- package/docs/migration/release-notes/0.10.0.md +81 -16
- package/docs/migration/release-notes/0.6.0.md +1 -1
- package/docs/migration/release-notes/0.7.0.md +1 -1
- package/docs/migration/release-notes/0.9.0.md +1 -1
- package/docs/migration/release-notes/README.md +1 -1
- package/docs/migration/v0.9-to-v0.10.md +300 -60
- package/docs/migration/v0.9.1-to-v0.9.2.md +6 -5
- package/docs/posts/config-v2-lessons-16.md +1 -1
- package/docs/posts/llm-mode-reflect-13.md +1 -1
- package/docs/posts/release-0.6.0.md +11 -11
- package/docs/posts/release-0.8.0.md +4 -4
- package/docs/posts/workflows-vaults-09.md +1 -1
- package/docs/reference/README.md +1 -1
- package/docs/reference/asset-types.md +2 -2
- package/docs/reference/cli.md +477 -388
- package/docs/reference/configuration.md +569 -550
- package/docs/reference/data-and-telemetry.md +9 -6
- package/docs/reference/env-and-secrets.md +72 -15
- package/docs/reference/refs.md +3 -20
- package/docs/reference/registry.md +12 -38
- package/docs/reference/supported-formats.md +1 -1
- package/docs/reference/tasks.md +22 -11
- package/docs/reference/ui-api.md +14 -9
- package/docs/reference/workflow-schema.md +199 -154
- package/docs/reference/workflows.md +4 -6
- package/package.json +9 -11
- package/schemas/akm-config.json +1696 -2922
- package/schemas/akm-task.json +4 -4
- package/schemas/akm-workflow.json +36 -9
- package/ROADMAP.md +0 -112
- package/dist/assets/models.json +0 -35
- package/dist/commands/health/engine-usage.js +0 -45
- package/dist/commands/sources/dangerous-env-audit.js +0 -134
- package/dist/core/activation-policy.js +0 -67
- package/dist/core/config/schema/engines.js +0 -160
- package/dist/core/config/schema/execution.js +0 -23
- package/dist/core/spawn-env.js +0 -268
- package/dist/execution/directory-identity.js +0 -78
- package/dist/integrations/agent/builder-shared.js +0 -33
- package/dist/integrations/agent/builders.js +0 -43
- package/dist/integrations/agent/engine-fallback.js +0 -59
- package/dist/integrations/agent/engine-resolution.js +0 -333
- package/dist/integrations/agent/model-map.js +0 -475
- package/dist/integrations/harnesses/aider/agent-builder.js +0 -107
- package/dist/integrations/harnesses/aider/result-extractor.js +0 -53
- package/dist/integrations/harnesses/amazonq/agent-builder.js +0 -138
- package/dist/integrations/harnesses/amazonq/result-extractor.js +0 -48
- package/dist/integrations/harnesses/claude/agent-builder.js +0 -106
- package/dist/integrations/harnesses/claude/config-import.js +0 -67
- package/dist/integrations/harnesses/claude/result-extractor.js +0 -67
- package/dist/integrations/harnesses/codex/agent-builder.js +0 -150
- package/dist/integrations/harnesses/codex/result-extractor.js +0 -110
- package/dist/integrations/harnesses/copilot/agent-builder.js +0 -117
- package/dist/integrations/harnesses/copilot/result-extractor.js +0 -178
- package/dist/integrations/harnesses/gemini/agent-builder.js +0 -114
- package/dist/integrations/harnesses/gemini/result-extractor.js +0 -149
- package/dist/integrations/harnesses/opencode/config-import.js +0 -149
- package/dist/integrations/harnesses/opencode/model-config.js +0 -33
- package/dist/integrations/harnesses/opencode/model-work-agent.js +0 -115
- package/dist/integrations/harnesses/opencode/session-log-types.js +0 -12
- package/dist/integrations/harnesses/opencode-sdk/index.js +0 -44
- package/dist/integrations/harnesses/opencode-sdk/sdk-runner.js +0 -1052
- package/dist/integrations/harnesses/opencode-sdk/v1-adapter.js +0 -199
- package/dist/integrations/harnesses/opencode-sdk/v2-adapter.js +0 -254
- package/dist/integrations/harnesses/opencode-sdk/wire.js +0 -66
- package/dist/integrations/harnesses/openhands/agent-builder.js +0 -120
- package/dist/integrations/harnesses/openhands/result-extractor.js +0 -135
- package/dist/integrations/harnesses/pi/agent-builder.js +0 -89
- package/dist/integrations/harnesses/pi/result-extractor.js +0 -168
- package/dist/integrations/harnesses/shared.js +0 -18
- package/dist/integrations/harnesses/types.js +0 -55
- package/dist/llm/feature-gate.js +0 -115
- package/dist/output/shapes/models-list.js +0 -16
- package/dist/output/shapes/registry-search.js +0 -10
- package/dist/setup/detected-engines.js +0 -136
- package/dist/setup/engine-config.js +0 -97
- package/dist/setup/harness-config-import.js +0 -47
- package/dist/setup/providers.js +0 -14
- package/dist/setup/steps/semantic.js +0 -39
- package/dist/workflows/authoring/scope-key.js +0 -79
- package/dist/workflows/exec/lowering-notices.js +0 -23
- package/dist/workflows/source-semantics.js +0 -110
- package/docs/architecture/0.10-process-rules.md +0 -832
- package/docs/architecture/akm-architecture-decision-history.md +0 -2055
- package/docs/architecture/comparisons/claude-code-vs-akm-workflows-full.md +0 -550
- package/docs/architecture/decisions/0001-no-interpolation-attached-structured-context.md +0 -72
- package/docs/architecture/decisions/0002-unit-reuse-and-input-hash-scope.md +0 -142
- package/docs/architecture/decisions/0003-child-env-allowlist-and-provenance.md +0 -189
- package/docs/architecture/decisions/0004-task-input-contract-and-flag-coercion.md +0 -97
- package/docs/architecture/decisions/0005-task-result-vocabulary-and-legacy-read-mapping.md +0 -108
- package/docs/architecture/decisions/0006-task-source-version-routing.md +0 -124
- package/docs/architecture/decisions/0007-workflow-composition-bounds.md +0 -83
- package/docs/architecture/decisions/0008-task-binding-normalization.md +0 -88
- package/docs/architecture/decisions/0009-child-run-publication-column-parity.md +0 -80
- package/docs/architecture/decisions/0010-driver-protocol-cut.md +0 -36
- package/docs/architecture/decisions/0011-engine-run-loop-invariants.md +0 -125
- package/docs/architecture/decisions/README.md +0 -62
- package/docs/architecture/internals/functional-contract-patterns.md +0 -340
- package/docs/architecture/internals/registry-network-boundary.md +0 -57
- package/docs/architecture/internals/search.md +0 -248
- package/docs/architecture/reviews/env-secret-access.md +0 -319
- package/docs/architecture/runtime-boundary-design.md +0 -153
- package/docs/architecture/specs/0.9.0-close-out-plan.md +0 -361
- package/docs/architecture/specs/0.9.0-decisions.md +0 -532
- package/docs/architecture/specs/0.9.0-docs-code-drift-register.md +0 -745
- package/docs/architecture/specs/0.9.0-open-items-register.md +0 -135
- package/docs/architecture/specs/0.9.0-public-api-issue-backlog.md +0 -740
- package/docs/architecture/specs/0.9.0-release-surface-review.md +0 -636
- package/docs/architecture/specs/agent-command-engine-model-design.md +0 -513
- package/docs/architecture/specs/akm-0.9.0-bundle-adapter-spec.md +0 -501
- package/docs/architecture/specs/akm-0.9.0-ref-grammar-decision.md +0 -291
- package/docs/architecture/specs/akm-format-neutral-bundle-workspace-spec.md +0 -2059
- package/docs/architecture/specs/di-seams-plan.md +0 -539
- package/docs/architecture/specs/driver-protocol-keep-or-cut.md +0 -275
- package/docs/architecture/specs/fact-asset-type.md +0 -142
- package/docs/architecture/specs/improve-collapse-churn-detector-design.md +0 -634
- package/docs/architecture/specs/reviews/task-workflow-unification/README.md +0 -72
- package/docs/architecture/specs/reviews/task-workflow-unification/findings-consolidated.md +0 -152
- package/docs/architecture/specs/reviews/task-workflow-unification/library-eval-alternatives.md +0 -352
- package/docs/architecture/specs/reviews/task-workflow-unification/library-eval-bunqueue.md +0 -300
- package/docs/architecture/specs/reviews/task-workflow-unification/library-eval-openworkflow.md +0 -402
- package/docs/architecture/specs/reviews/task-workflow-unification/opus-review-1.md +0 -758
- package/docs/architecture/specs/reviews/task-workflow-unification/opus-review-2.md +0 -645
- package/docs/architecture/specs/reviews/task-workflow-unification/opus-review-3.md +0 -602
- package/docs/architecture/specs/reviews/task-workflow-unification/panel-r1-adversarial.md +0 -27
- package/docs/architecture/specs/reviews/task-workflow-unification/panel-r1-architecture.md +0 -27
- package/docs/architecture/specs/reviews/task-workflow-unification/panel-r1-coverage.md +0 -74
- package/docs/architecture/specs/reviews/task-workflow-unification/panel-r1-security.md +0 -15
- package/docs/architecture/specs/reviews/task-workflow-unification/panel-r2-adversarial.md +0 -132
- package/docs/architecture/specs/reviews/task-workflow-unification/panel-r2-verification.md +0 -147
- package/docs/architecture/specs/stash-conventions-code-spec.md +0 -275
- package/docs/architecture/specs/stash-organization-conventions.md +0 -377
- package/docs/architecture/specs/task-workflow-format-unification.md +0 -721
- package/docs/architecture/specs/workflow-engine-buy-vs-build.md +0 -231
- package/docs/architecture/specs/workflow-format-unification.md +0 -432
- package/docs/architecture/testing/manual-testing-checklist.md +0 -3411
- package/docs/architecture/testing/okf-v0.2-conformance-runbook.md +0 -924
- package/docs/architecture/testing/task-workflow-manual-tests.md +0 -1720
- package/docs/guides/claude-code-vs-akm-workflows.md +0 -29
- package/docs/guides/knowledge-management.md +0 -18
- package/docs/maintainers/curate-workmap.md +0 -335
- package/docs/migration/v0.5-to-v0.6.md +0 -759
- package/docs/migration/v0.7-to-v0.8.md +0 -1378
- package/docs/plans/0.9.2-agent-command-workflow-plan.md +0 -423
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
// This Source Code Form is subject to the terms of the Mozilla Public
|
|
2
|
+
// License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
3
|
+
// file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
|
4
|
+
/**
|
|
5
|
+
* One member of a gzip-compressed tar archive, streamed to a file. This is all
|
|
6
|
+
* akm needs of tar: the OpenCode binary is a single regular file of about 240 MB
|
|
7
|
+
* inside its package tarball, so it is never held in memory and no tar library
|
|
8
|
+
* is a dependency.
|
|
9
|
+
*/
|
|
10
|
+
import fs from "node:fs";
|
|
11
|
+
import { pipeline } from "node:stream";
|
|
12
|
+
import zlib from "node:zlib";
|
|
13
|
+
const BLOCK_BYTES = 512;
|
|
14
|
+
/** Exact reads from a stream of chunks. */
|
|
15
|
+
class ByteReader {
|
|
16
|
+
#chunks;
|
|
17
|
+
#pending = Buffer.alloc(0);
|
|
18
|
+
constructor(source) {
|
|
19
|
+
this.#chunks = source[Symbol.asyncIterator]();
|
|
20
|
+
}
|
|
21
|
+
/** Up to `max` bytes, at least one unless the stream has ended (`undefined`). */
|
|
22
|
+
async read(max) {
|
|
23
|
+
if (this.#pending.length === 0) {
|
|
24
|
+
const next = await this.#chunks.next();
|
|
25
|
+
if (next.done)
|
|
26
|
+
return undefined;
|
|
27
|
+
this.#pending = next.value;
|
|
28
|
+
}
|
|
29
|
+
const taken = this.#pending.subarray(0, max);
|
|
30
|
+
this.#pending = this.#pending.subarray(taken.length);
|
|
31
|
+
return taken;
|
|
32
|
+
}
|
|
33
|
+
async exact(count) {
|
|
34
|
+
const parts = [];
|
|
35
|
+
for (let left = count; left > 0;) {
|
|
36
|
+
const part = await this.read(left);
|
|
37
|
+
if (!part)
|
|
38
|
+
throw new Error("the archive ends inside an entry");
|
|
39
|
+
parts.push(part);
|
|
40
|
+
left -= part.length;
|
|
41
|
+
}
|
|
42
|
+
return Buffer.concat(parts);
|
|
43
|
+
}
|
|
44
|
+
async skip(count) {
|
|
45
|
+
for (let left = count; left > 0;) {
|
|
46
|
+
const part = await this.read(left);
|
|
47
|
+
if (!part)
|
|
48
|
+
throw new Error("the archive ends inside an entry");
|
|
49
|
+
left -= part.length;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
/** A header field of NUL-terminated text. */
|
|
54
|
+
const field = (header, start, end) => {
|
|
55
|
+
const bytes = header.subarray(start, end);
|
|
56
|
+
const stop = bytes.indexOf(0);
|
|
57
|
+
return bytes.subarray(0, stop < 0 ? bytes.length : stop).toString("utf8");
|
|
58
|
+
};
|
|
59
|
+
/**
|
|
60
|
+
* Write the regular file `member` of the `.tgz` at `archive` to `destination` (mode 0755) and return its size. Entries
|
|
61
|
+
* are matched by the header's name field alone, which holds up to 100 bytes; a longer name, which tar keeps in the
|
|
62
|
+
* ustar prefix field or a PAX `path` record, is not read, so such a member is never found. The one member akm reads,
|
|
63
|
+
* `package/bin/opencode`, is short. Extended headers are skipped like any other entry that is not the member.
|
|
64
|
+
*/
|
|
65
|
+
export async function extractTarGzMember(archive, member, destination) {
|
|
66
|
+
const gunzip = zlib.createGunzip();
|
|
67
|
+
pipeline(fs.createReadStream(archive), gunzip, () => { });
|
|
68
|
+
const reader = new ByteReader(gunzip);
|
|
69
|
+
try {
|
|
70
|
+
return await extractFrom(reader, archive, member, destination);
|
|
71
|
+
}
|
|
72
|
+
finally {
|
|
73
|
+
// The rest of the archive is not read: close it now rather than when the stream is collected.
|
|
74
|
+
gunzip.destroy();
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
async function extractFrom(reader, archive, member, destination) {
|
|
78
|
+
for (;;) {
|
|
79
|
+
const header = await reader.exact(BLOCK_BYTES);
|
|
80
|
+
if (header.every((byte) => byte === 0))
|
|
81
|
+
throw new Error(`${archive} has no ${member}`);
|
|
82
|
+
const name = field(header, 0, 100).replace(/^\.\//, "");
|
|
83
|
+
const typeflag = String.fromCharCode(header[156] ?? 0);
|
|
84
|
+
const size = Number.parseInt(field(header, 124, 136).trim() || "0", 8);
|
|
85
|
+
if (!Number.isSafeInteger(size))
|
|
86
|
+
throw new Error(`${archive} is not a tar archive this reader understands`);
|
|
87
|
+
const padding = (BLOCK_BYTES - (size % BLOCK_BYTES)) % BLOCK_BYTES;
|
|
88
|
+
if (name !== member || (typeflag !== "0" && typeflag !== "\0")) {
|
|
89
|
+
await reader.skip(size + padding);
|
|
90
|
+
continue;
|
|
91
|
+
}
|
|
92
|
+
const out = await fs.promises.open(destination, "w", 0o755);
|
|
93
|
+
try {
|
|
94
|
+
for (let left = size; left > 0;) {
|
|
95
|
+
const part = await reader.read(left);
|
|
96
|
+
if (!part)
|
|
97
|
+
throw new Error(`${archive} ends inside ${member}`);
|
|
98
|
+
await out.writeFile(part);
|
|
99
|
+
left -= part.length;
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
finally {
|
|
103
|
+
await out.close();
|
|
104
|
+
}
|
|
105
|
+
return size;
|
|
106
|
+
}
|
|
107
|
+
}
|
|
@@ -2,7 +2,16 @@
|
|
|
2
2
|
// License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
3
3
|
// file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
|
4
4
|
import { extractInlineRefMentions } from "../../session-logs/inline-refs.js";
|
|
5
|
-
|
|
5
|
+
/** The metadata of a row, with a column that is absent or empty left out. */
|
|
6
|
+
export function toMeta(r, sessionId) {
|
|
7
|
+
return {
|
|
8
|
+
sessionId,
|
|
9
|
+
startedAt: typeof r.time_created === "number" ? r.time_created : undefined,
|
|
10
|
+
endedAt: typeof r.time_updated === "number" ? r.time_updated : undefined,
|
|
11
|
+
projectHint: typeof r.directory === "string" && r.directory.length > 0 ? r.directory : undefined,
|
|
12
|
+
title: typeof r.title === "string" && r.title.length > 0 ? r.title : undefined,
|
|
13
|
+
};
|
|
14
|
+
}
|
|
6
15
|
/** Listing needs only `session`; reading a session needs `message` and `part`, and fails loudly without them. */
|
|
7
16
|
export const V1_TABLES = ["session"];
|
|
8
17
|
/** Every V1 session updated at or after `sinceMs`, newest first. Throws on an incompatible schema. */
|
|
@@ -12,18 +21,17 @@ export function listV1Sessions(db, sinceMs) {
|
|
|
12
21
|
.all(sinceMs);
|
|
13
22
|
return rows.map((r) => toMeta(r, r.id));
|
|
14
23
|
}
|
|
15
|
-
/** Whether a V1 `session` row exists for `sessionId`. */
|
|
16
|
-
export function hasV1Session(db, sessionId) {
|
|
17
|
-
return db.prepare("SELECT id FROM session WHERE id = ?").get(sessionId) !== undefined;
|
|
18
|
-
}
|
|
19
24
|
/**
|
|
20
25
|
* One event per message, text-parts concatenated in time order. Throws on an
|
|
21
|
-
* incompatible schema; individual unparsable
|
|
26
|
+
* incompatible schema or a session that is not in the file; individual unparsable
|
|
27
|
+
* rows are skipped.
|
|
22
28
|
*/
|
|
23
29
|
export function readV1Session(db, harness, sessionId, filePath) {
|
|
24
30
|
const meta = db
|
|
25
31
|
.prepare("SELECT title, directory, time_created, time_updated FROM session WHERE id = ?")
|
|
26
32
|
.get(sessionId);
|
|
33
|
+
if (!meta)
|
|
34
|
+
throw new Error(`session ${sessionId} is not in the file`);
|
|
27
35
|
const messages = db
|
|
28
36
|
.prepare("SELECT id, data, time_created FROM message WHERE session_id = ? ORDER BY time_created ASC, id ASC")
|
|
29
37
|
.all(sessionId);
|
|
@@ -68,5 +76,5 @@ export function readV1Session(db, harness, sessionId, filePath) {
|
|
|
68
76
|
inlineRefs.push(...extractInlineRefMentions(text, ts));
|
|
69
77
|
}
|
|
70
78
|
events.sort((a, b) => (a.ts ?? 0) - (b.ts ?? 0));
|
|
71
|
-
return { meta:
|
|
79
|
+
return { meta: toMeta(meta, sessionId), events, inlineRefs };
|
|
72
80
|
}
|
|
@@ -2,37 +2,25 @@
|
|
|
2
2
|
// License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
3
3
|
// file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
|
4
4
|
/**
|
|
5
|
-
* OpenCode 2 session
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
* Read-only: the database is never migrated; V1 rows a native upgrade copied
|
|
9
|
-
* here arrive as the same shapes under the same session id.
|
|
5
|
+
* OpenCode 2 session store: the `session_v2` and `session_message` tables, read
|
|
6
|
+
* with SQLite only. Nothing here starts OpenCode (which would migrate the file
|
|
7
|
+
* and resume its suspended sessions); it reads the rows as they are.
|
|
10
8
|
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
9
|
+
* A message row is `(id, type, data)`; OpenCode decodes it as `{ ...data, id, type }`,
|
|
10
|
+
* which is rebuilt here. Only top-level sessions are read, and akm's own
|
|
11
|
+
* model-work sessions are left out: OpenCode 2 stores the agent a session ran as,
|
|
12
|
+
* and akm runs model work as one agent (`./agent-builder.ts`).
|
|
13
|
+
*
|
|
14
|
+
* Mapping to events follows the Codex reader: user and assistant text become events of
|
|
15
|
+
* that role, a tool call becomes `[tool:<name>] <input>` and its outcome a
|
|
16
|
+
* `tool` event `[tool_result] <output>`, so the inline-ref scanner sees shell
|
|
17
|
+
* commands. Reasoning, compaction, synthetic/system and bookkeeping messages
|
|
18
|
+
* are skipped.
|
|
16
19
|
*/
|
|
17
20
|
import { asRecord, tryParseJson } from "../../../core/common.js";
|
|
18
|
-
import { warnOnce } from "../../../core/warn.js";
|
|
19
21
|
import { extractInlineRefMentions } from "../../session-logs/inline-refs.js";
|
|
20
|
-
import {
|
|
21
|
-
|
|
22
|
-
/** Every V2 session updated at or after `sinceMs`, newest first. Throws on an incompatible schema. */
|
|
23
|
-
export function listV2Sessions(db, sinceMs) {
|
|
24
|
-
const rows = db
|
|
25
|
-
.prepare("SELECT id, title, directory, time_created, time_updated FROM session_v2 WHERE time_updated >= ? ORDER BY time_updated DESC")
|
|
26
|
-
.all(sinceMs);
|
|
27
|
-
return rows.map((r) => toMeta(r, r.id));
|
|
28
|
-
}
|
|
29
|
-
/** Whether `sessionId` has a `session_v2` row, and how many `session_message` rows it owns. */
|
|
30
|
-
export function v2SessionState(db, sessionId) {
|
|
31
|
-
const row = db
|
|
32
|
-
.prepare("SELECT (SELECT COUNT(*) FROM session_message WHERE session_id = s.id) AS n FROM session_v2 s WHERE s.id = ?")
|
|
33
|
-
.get(sessionId);
|
|
34
|
-
return row ? { exists: true, messages: row.n } : { exists: false, messages: 0 };
|
|
35
|
-
}
|
|
22
|
+
import { MODEL_WORK_AGENT } from "./agent-builder.js";
|
|
23
|
+
import { toMeta } from "./session-log-v1.js";
|
|
36
24
|
const asObject = asRecord;
|
|
37
25
|
function asNumber(v) {
|
|
38
26
|
return typeof v === "number" ? v : undefined;
|
|
@@ -69,17 +57,8 @@ function structuredErrorText(err) {
|
|
|
69
57
|
return e.message;
|
|
70
58
|
return typeof e?.type === "string" ? e.type : "error";
|
|
71
59
|
}
|
|
72
|
-
/**
|
|
73
|
-
|
|
74
|
-
* schema; a message whose JSON cannot be read is skipped with one warning.
|
|
75
|
-
*/
|
|
76
|
-
export function readV2Session(db, harness, sessionId, filePath) {
|
|
77
|
-
const meta = db
|
|
78
|
-
.prepare("SELECT title, directory, time_created, time_updated FROM session_v2 WHERE id = ?")
|
|
79
|
-
.get(sessionId);
|
|
80
|
-
const rows = db
|
|
81
|
-
.prepare("SELECT id, type, data, time_created FROM session_message WHERE session_id = ? ORDER BY seq ASC, time_created ASC, id ASC")
|
|
82
|
-
.all(sessionId);
|
|
60
|
+
/** One session's events and inline refs, from its messages oldest first. A message that is not an object is skipped. */
|
|
61
|
+
export function opencodeMessageEvents(messages, harness, sessionId, filePath) {
|
|
83
62
|
const events = [];
|
|
84
63
|
const inlineRefs = [];
|
|
85
64
|
const push = (role, text, ts) => {
|
|
@@ -89,18 +68,16 @@ export function readV2Session(db, harness, sessionId, filePath) {
|
|
|
89
68
|
events.push({ harness, text: trimmed, ts, sessionId, role, filePath });
|
|
90
69
|
inlineRefs.push(...extractInlineRefMentions(trimmed, ts));
|
|
91
70
|
};
|
|
92
|
-
for (const
|
|
93
|
-
const data = asObject(
|
|
94
|
-
if (!data)
|
|
95
|
-
warnOnce(`opencode-v2-message:${filePath}:${row.id}`, `OpenCode 2 history: skipped unreadable message ${row.id} in session ${sessionId} (${filePath}).`);
|
|
71
|
+
for (const message of messages) {
|
|
72
|
+
const data = asObject(message);
|
|
73
|
+
if (!data)
|
|
96
74
|
continue;
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
if (row.type === "user") {
|
|
75
|
+
const ts = asNumber(asObject(data.time)?.created);
|
|
76
|
+
if (data.type === "user") {
|
|
100
77
|
if (typeof data.text === "string")
|
|
101
78
|
push("user", data.text, ts);
|
|
102
79
|
}
|
|
103
|
-
else if (
|
|
80
|
+
else if (data.type === "assistant") {
|
|
104
81
|
const content = Array.isArray(data.content) ? data.content : [];
|
|
105
82
|
const text = content
|
|
106
83
|
.map((c) => asObject(c))
|
|
@@ -128,7 +105,7 @@ export function readV2Session(db, harness, sessionId, filePath) {
|
|
|
128
105
|
}
|
|
129
106
|
}
|
|
130
107
|
}
|
|
131
|
-
else if (
|
|
108
|
+
else if (data.type === "shell") {
|
|
132
109
|
if (typeof data.command === "string")
|
|
133
110
|
push("assistant", `[tool:shell] ${data.command}`, ts);
|
|
134
111
|
const out = asObject(data.output)?.output;
|
|
@@ -136,5 +113,52 @@ export function readV2Session(db, harness, sessionId, filePath) {
|
|
|
136
113
|
push("tool", `[tool_result] ${out}`, ts);
|
|
137
114
|
}
|
|
138
115
|
}
|
|
139
|
-
return {
|
|
116
|
+
return { events, inlineRefs };
|
|
117
|
+
}
|
|
118
|
+
/** The columns of each table akm reads; a file lacking one is a schema akm does not support. */
|
|
119
|
+
const V2_COLUMNS = {
|
|
120
|
+
session_v2: ["id", "parent_id", "title", "directory", "agent", "time_created", "time_updated"],
|
|
121
|
+
session_message: ["id", "session_id", "type", "seq", "data"],
|
|
122
|
+
};
|
|
123
|
+
/** Whether `db` has the OpenCode 2 session tables with the columns akm reads. */
|
|
124
|
+
export function hasV2Tables(db) {
|
|
125
|
+
return Object.entries(V2_COLUMNS).every(([table, columns]) => {
|
|
126
|
+
const present = new Set(db
|
|
127
|
+
.prepare(`PRAGMA table_info(${table})`)
|
|
128
|
+
.all()
|
|
129
|
+
.map((c) => c.name));
|
|
130
|
+
return columns.every((column) => present.has(column));
|
|
131
|
+
});
|
|
132
|
+
}
|
|
133
|
+
/** Top-level sessions that are not akm's model work. */
|
|
134
|
+
const AKM_USER_SESSIONS = `parent_id IS NULL AND (agent IS NULL OR agent != '${MODEL_WORK_AGENT}')`;
|
|
135
|
+
/** Every top-level OpenCode 2 session updated at or after `sinceMs`, newest first. Throws on an incompatible schema. */
|
|
136
|
+
export function listV2Sessions(db, sinceMs) {
|
|
137
|
+
return db
|
|
138
|
+
.prepare(`SELECT id, title, directory, time_created, time_updated FROM session_v2 WHERE ${AKM_USER_SESSIONS} AND time_updated >= ? ORDER BY time_updated DESC`)
|
|
139
|
+
.all(sinceMs)
|
|
140
|
+
.map((row) => toMeta(row, row.id));
|
|
141
|
+
}
|
|
142
|
+
/**
|
|
143
|
+
* The tokens one session's turns used: OpenCode records them on each assistant message and keeps their sums on the
|
|
144
|
+
* session row (equal, measured on 2.1.4). Undefined when the session is not in the file.
|
|
145
|
+
*/
|
|
146
|
+
export function v2SessionTokens(db, sessionId) {
|
|
147
|
+
const row = db
|
|
148
|
+
.prepare("SELECT tokens_input, tokens_output, tokens_reasoning FROM session_v2 WHERE id = ?")
|
|
149
|
+
.get(sessionId);
|
|
150
|
+
return row ? { input: row.tokens_input, output: row.tokens_output, reasoning: row.tokens_reasoning } : undefined;
|
|
151
|
+
}
|
|
152
|
+
/** One session's events, from its messages in order. Throws when the session is not in the file. */
|
|
153
|
+
export function readV2Session(db, harness, sessionId, filePath) {
|
|
154
|
+
const row = db
|
|
155
|
+
.prepare("SELECT title, directory, time_created, time_updated FROM session_v2 WHERE id = ?")
|
|
156
|
+
.get(sessionId);
|
|
157
|
+
if (!row)
|
|
158
|
+
throw new Error(`session ${sessionId} is not in the file`);
|
|
159
|
+
const messages = db
|
|
160
|
+
.prepare("SELECT id, type, data FROM session_message WHERE session_id = ? ORDER BY seq ASC")
|
|
161
|
+
.all(sessionId)
|
|
162
|
+
.map((message) => ({ ...asRecord(tryParseJson(message.data)), id: message.id, type: message.type }));
|
|
163
|
+
return { meta: toMeta(row, sessionId), ...opencodeMessageEvents(messages, harness, sessionId, filePath) };
|
|
140
164
|
}
|
|
@@ -2,167 +2,88 @@
|
|
|
2
2
|
// License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
3
3
|
// file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
|
4
4
|
import fs from "node:fs";
|
|
5
|
-
import os from "node:os";
|
|
6
|
-
import path from "node:path";
|
|
7
5
|
import { toErrorMessage } from "../../../core/common.js";
|
|
8
6
|
import { warnOnce } from "../../../core/warn.js";
|
|
9
7
|
import { openDatabase } from "../../../storage/database.js";
|
|
10
8
|
import { openSqliteReadSnapshot } from "../../../storage/sqlite-read-snapshot.js";
|
|
11
9
|
import { AbstractSessionLogProvider } from "../../session-logs/provider-base.js";
|
|
12
|
-
import {
|
|
13
|
-
import {
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
return path.join(os.homedir(), "Library", "Application Support", "opencode");
|
|
17
|
-
}
|
|
18
|
-
return path.join(os.homedir(), ".local", "share", "opencode");
|
|
19
|
-
}
|
|
20
|
-
/**
|
|
21
|
-
* OpenCode session storage: one SQLite file, `<base>/opencode.db`, whose
|
|
22
|
-
* layout decides the reader, never the installed binary or its version:
|
|
23
|
-
*
|
|
24
|
-
* - V1: `session` table, with `message` / `part` for content (`session-log-v1.ts`).
|
|
25
|
-
* - V2: `session_v2` / `session_message` tables (`session-log-v2.ts`).
|
|
26
|
-
* - Both: a natively upgraded V1 file keeps its V1 tables and gains the V2
|
|
27
|
-
* ones. Sessions are merged by id, V2 winning, V1-only ones kept.
|
|
28
|
-
* - Neither: an unsupported layout, reported, never presented as empty.
|
|
29
|
-
*
|
|
30
|
-
* The file is opened read-only and never migrated or written.
|
|
31
|
-
*/
|
|
32
|
-
/** Filename of opencode's SQLite session store, relative to its base dir. */
|
|
33
|
-
const OPENCODE_DB_FILENAME = "opencode.db";
|
|
34
|
-
function tableNames(db) {
|
|
10
|
+
import { akmOpencodeDatabasePath, databaseIn, opencodeDatabasePath } from "./roots.js";
|
|
11
|
+
import { listV1Sessions, readV1Session, V1_TABLES } from "./session-log-v1.js";
|
|
12
|
+
import { hasV2Tables, listV2Sessions, readV2Session } from "./session-log-v2.js";
|
|
13
|
+
function layoutOf(db) {
|
|
35
14
|
const rows = db.prepare("SELECT name FROM sqlite_master WHERE type = 'table'").all();
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
const v2 = V2_TABLES.every((t) => tables.has(t));
|
|
41
|
-
return v1 || v2 ? { kind: "ok", v1, v2 } : { kind: "unsupported", tables: [...tables].sort() };
|
|
15
|
+
const tables = new Set(rows.map((r) => r.name));
|
|
16
|
+
if (tables.has("session_v2") && hasV2Tables(db))
|
|
17
|
+
return "v2";
|
|
18
|
+
return V1_TABLES.every((t) => tables.has(t)) && !tables.has("session_v2") ? "v1" : "unsupported";
|
|
42
19
|
}
|
|
43
20
|
export class OpenCodeProvider extends AbstractSessionLogProvider {
|
|
44
21
|
name = "opencode";
|
|
45
|
-
#
|
|
22
|
+
#userDatabase = opencodeDatabasePath();
|
|
46
23
|
availabilityRoot() {
|
|
47
|
-
return this.#
|
|
24
|
+
return this.#userDatabase;
|
|
48
25
|
}
|
|
49
|
-
/**
|
|
50
|
-
|
|
51
|
-
return
|
|
26
|
+
/** The user's OpenCode history, or akm's own. */
|
|
27
|
+
isAvailable() {
|
|
28
|
+
return super.isAvailable() || fs.existsSync(akmOpencodeDatabasePath());
|
|
52
29
|
}
|
|
53
|
-
/**
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
let db;
|
|
59
|
-
try {
|
|
60
|
-
db = openDatabase(dbPath, { readonly: true, create: false });
|
|
61
|
-
}
|
|
62
|
-
catch (error) {
|
|
63
|
-
return { kind: "unreadable", reason: toErrorMessage(error) };
|
|
64
|
-
}
|
|
65
|
-
try {
|
|
66
|
-
return classify(tableNames(db));
|
|
67
|
-
}
|
|
68
|
-
catch (error) {
|
|
69
|
-
return { kind: "unreadable", reason: toErrorMessage(error) };
|
|
70
|
-
}
|
|
71
|
-
finally {
|
|
72
|
-
db.close();
|
|
73
|
-
}
|
|
30
|
+
/** The stores to read: the one under `location`, else the user's and akm's. */
|
|
31
|
+
#stores(location) {
|
|
32
|
+
if (location)
|
|
33
|
+
return [databaseIn(location)];
|
|
34
|
+
return [this.#userDatabase, akmOpencodeDatabasePath()];
|
|
74
35
|
}
|
|
75
|
-
listSessions(input = {}) {
|
|
76
|
-
const
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
this.#warnUnavailable(dbPath, `cannot open it (${toErrorMessage(error)})`);
|
|
87
|
-
return [];
|
|
88
|
-
}
|
|
89
|
-
if (!db)
|
|
90
|
-
return [];
|
|
91
|
-
try {
|
|
92
|
-
const status = classify(tableNames(db));
|
|
93
|
-
if (status.kind !== "ok") {
|
|
94
|
-
this.#warnUnavailable(dbPath, `it has neither the OpenCode 1 (${V1_TABLES.join("/")}) nor the OpenCode 2 (${V2_TABLES.join("/")}) tables`);
|
|
95
|
-
return [];
|
|
36
|
+
async listSessions(input = {}) {
|
|
37
|
+
const sinceMs = input.sinceMs ?? 0;
|
|
38
|
+
const listed = [];
|
|
39
|
+
for (const dbPath of this.#stores(input.location)) {
|
|
40
|
+
if (!fs.existsSync(dbPath))
|
|
41
|
+
continue;
|
|
42
|
+
try {
|
|
43
|
+
listed.push(...this.#listStore(dbPath, sinceMs, input.isolatedSnapshot === true));
|
|
44
|
+
}
|
|
45
|
+
catch (error) {
|
|
46
|
+
this.#warnUnavailable(dbPath, `cannot list it (${toErrorMessage(error)})`);
|
|
96
47
|
}
|
|
97
|
-
return this.#listFromDb(db, dbPath, input.sinceMs ?? 0, status.v1, status.v2);
|
|
98
|
-
}
|
|
99
|
-
catch (error) {
|
|
100
|
-
this.#warnUnavailable(dbPath, `cannot query it (${toErrorMessage(error)})`);
|
|
101
|
-
return [];
|
|
102
|
-
}
|
|
103
|
-
finally {
|
|
104
|
-
db.close();
|
|
105
48
|
}
|
|
49
|
+
return listed.sort((a, b) => (b.endedAt ?? 0) - (a.endedAt ?? 0));
|
|
106
50
|
}
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
const
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
db = openDatabase(ref.filePath, { readonly: true, create: false });
|
|
51
|
+
/** One session's events. A file or session that cannot be read throws, so the caller records the failure. */
|
|
52
|
+
async readSession(ref) {
|
|
53
|
+
const layout = this.#withDb(ref.filePath, false, layoutOf);
|
|
54
|
+
if (layout === "unsupported") {
|
|
55
|
+
throw new Error(`${ref.filePath} has no supported OpenCode 1 or OpenCode 2 session tables`);
|
|
113
56
|
}
|
|
114
|
-
|
|
115
|
-
this
|
|
116
|
-
|
|
57
|
+
const read = this.#withDb(ref.filePath, false, (db) => layout === "v2"
|
|
58
|
+
? readV2Session(db, this.name, ref.sessionId, ref.filePath)
|
|
59
|
+
: readV1Session(db, this.name, ref.sessionId, ref.filePath));
|
|
60
|
+
return {
|
|
61
|
+
ref: this.sessionRef({ ...read.meta, filePath: ref.filePath }),
|
|
62
|
+
events: read.events,
|
|
63
|
+
inlineRefs: read.inlineRefs,
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
#listStore(dbPath, sinceMs, isolated) {
|
|
67
|
+
const layout = this.#withDb(dbPath, isolated, layoutOf);
|
|
68
|
+
if (layout === "unsupported") {
|
|
69
|
+
this.#warnUnavailable(dbPath, `it has neither the OpenCode 1 (${V1_TABLES.join("/")}) nor the OpenCode 2 tables`);
|
|
70
|
+
return [];
|
|
117
71
|
}
|
|
72
|
+
const metas = this.#withDb(dbPath, isolated, (db) => layout === "v2" ? listV2Sessions(db, sinceMs) : listV1Sessions(db, sinceMs));
|
|
73
|
+
return metas.map((meta) => this.sessionRef({ ...meta, filePath: dbPath }));
|
|
74
|
+
}
|
|
75
|
+
/** Run `use` on the SQLite file at `dbPath`, read-only (a private copy when `isolated`). */
|
|
76
|
+
#withDb(dbPath, isolated, use) {
|
|
77
|
+
const db = isolated ? openSqliteReadSnapshot(dbPath) : openDatabase(dbPath, { readonly: true, create: false });
|
|
78
|
+
if (!db)
|
|
79
|
+
throw new Error("the file disappeared");
|
|
118
80
|
try {
|
|
119
|
-
|
|
120
|
-
if (status.kind !== "ok") {
|
|
121
|
-
this.#warnUnavailable(ref.filePath, "it has no supported OpenCode 1 or OpenCode 2 session tables");
|
|
122
|
-
return empty;
|
|
123
|
-
}
|
|
124
|
-
// V2 owns a session that has messages there; otherwise a retained V1 copy (a
|
|
125
|
-
// session the upgrade has not copied, or copied without messages) is the history.
|
|
126
|
-
const v2 = status.v2 ? v2SessionState(db, ref.sessionId) : { exists: false, messages: 0 };
|
|
127
|
-
const useV2 = v2.exists && (v2.messages > 0 || !status.v1 || !hasV1Session(db, ref.sessionId));
|
|
128
|
-
const read = useV2
|
|
129
|
-
? readV2Session(db, this.name, ref.sessionId, ref.filePath)
|
|
130
|
-
: readV1Session(db, this.name, ref.sessionId, ref.filePath);
|
|
131
|
-
return {
|
|
132
|
-
ref: this.sessionRef({ ...read.meta, filePath: ref.filePath }),
|
|
133
|
-
events: read.events,
|
|
134
|
-
inlineRefs: read.inlineRefs,
|
|
135
|
-
};
|
|
136
|
-
}
|
|
137
|
-
catch (error) {
|
|
138
|
-
this.#warnUnavailable(ref.filePath, `cannot read session ${ref.sessionId} (${toErrorMessage(error)})`);
|
|
139
|
-
return empty;
|
|
81
|
+
return use(db);
|
|
140
82
|
}
|
|
141
83
|
finally {
|
|
142
84
|
db.close();
|
|
143
85
|
}
|
|
144
86
|
}
|
|
145
|
-
/** List each present layout; one failing layout is reported and the other still listed. */
|
|
146
|
-
#listFromDb(db, dbPath, sinceMs, v1, v2) {
|
|
147
|
-
const merged = new Map();
|
|
148
|
-
const attempt = (label, list) => {
|
|
149
|
-
try {
|
|
150
|
-
for (const meta of list())
|
|
151
|
-
if (!merged.has(meta.sessionId))
|
|
152
|
-
merged.set(meta.sessionId, meta);
|
|
153
|
-
}
|
|
154
|
-
catch (error) {
|
|
155
|
-
this.#warnUnavailable(dbPath, `its ${label} session tables cannot be queried (${toErrorMessage(error)})`);
|
|
156
|
-
}
|
|
157
|
-
};
|
|
158
|
-
if (v2)
|
|
159
|
-
attempt("OpenCode 2", () => listV2Sessions(db, sinceMs));
|
|
160
|
-
if (v1)
|
|
161
|
-
attempt("OpenCode 1", () => listV1Sessions(db, sinceMs));
|
|
162
|
-
return [...merged.values()]
|
|
163
|
-
.sort((a, b) => (b.endedAt ?? 0) - (a.endedAt ?? 0))
|
|
164
|
-
.map((meta) => this.sessionRef({ ...meta, filePath: dbPath }));
|
|
165
|
-
}
|
|
166
87
|
#warnUnavailable(dbPath, why) {
|
|
167
88
|
warnOnce(`opencode-history:${dbPath}:${why}`, `OpenCode session history at ${dbPath} was not read: ${why}. This is an unsupported or damaged store, not an empty history.`);
|
|
168
89
|
}
|