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,50 @@
|
|
|
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
|
+
* Where the user's OpenCode keeps its files: the XDG base directories on every
|
|
6
|
+
* platform (OpenCode's own `global-roots` does not special-case macOS or
|
|
7
|
+
* Windows), each with an `opencode` folder. The one place akm computes them.
|
|
8
|
+
*/
|
|
9
|
+
import os from "node:os";
|
|
10
|
+
import path from "node:path";
|
|
11
|
+
import { getDataDir } from "../../../core/paths.js";
|
|
12
|
+
function xdgRoot(name, fallback, env) {
|
|
13
|
+
const set = env[name]?.trim();
|
|
14
|
+
if (set)
|
|
15
|
+
return path.join(set, "opencode");
|
|
16
|
+
const home = env.HOME?.trim() || env.USERPROFILE?.trim() || os.homedir();
|
|
17
|
+
return path.join(home, ...fallback, "opencode");
|
|
18
|
+
}
|
|
19
|
+
/** `$XDG_DATA_HOME/opencode`: the user's `opencode.db`. */
|
|
20
|
+
function opencodeDataDir(env = process.env) {
|
|
21
|
+
return xdgRoot("XDG_DATA_HOME", [".local", "share"], env);
|
|
22
|
+
}
|
|
23
|
+
/** `$XDG_CACHE_HOME/opencode`: the plugin packages it installed. */
|
|
24
|
+
export function opencodeCacheDir(env = process.env) {
|
|
25
|
+
return xdgRoot("XDG_CACHE_HOME", [".cache"], env);
|
|
26
|
+
}
|
|
27
|
+
/** `$OPENCODE_CONFIG_DIR`, else `$XDG_CONFIG_HOME/opencode`: `opencode.json`, agents and plugins. */
|
|
28
|
+
export function opencodeConfigDir(env = process.env) {
|
|
29
|
+
return env.OPENCODE_CONFIG_DIR?.trim() || xdgRoot("XDG_CONFIG_HOME", [".config"], env);
|
|
30
|
+
}
|
|
31
|
+
/** OpenCode's SQLite session store, in OpenCode's data directory and in akm's. */
|
|
32
|
+
export function databaseIn(directory) {
|
|
33
|
+
return path.join(directory, "opencode.db");
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Everything akm's own OpenCode runtime keeps, under akm's data directory: the
|
|
37
|
+
* four XDG roots it is started with (`config`, `data`, `cache`, `state`) and its
|
|
38
|
+
* `tmp`. Nothing of the user's OpenCode is in it.
|
|
39
|
+
*/
|
|
40
|
+
export function akmRuntimeDir() {
|
|
41
|
+
return path.join(getDataDir(), "opencode-runtime");
|
|
42
|
+
}
|
|
43
|
+
/** The user's OpenCode database. */
|
|
44
|
+
export function opencodeDatabasePath(env = process.env) {
|
|
45
|
+
return databaseIn(opencodeDataDir(env));
|
|
46
|
+
}
|
|
47
|
+
/** Where akm's own runtime keeps its sessions: the `opencode/opencode.db` OpenCode makes under the runtime's `XDG_DATA_HOME`. */
|
|
48
|
+
export function akmOpencodeDatabasePath() {
|
|
49
|
+
return databaseIn(path.join(akmRuntimeDir(), "data", "opencode"));
|
|
50
|
+
}
|
|
@@ -0,0 +1,206 @@
|
|
|
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
|
+
* The OpenCode binary akm's own agent runtime runs, fetched on first use.
|
|
6
|
+
*
|
|
7
|
+
* OpenCode 2 is published as a prebuilt binary on npm: `@opencode/cli`, whose
|
|
8
|
+
* platform packages each hold one executable. akm does not depend on that
|
|
9
|
+
* package: the package manager would install every platform package that matches
|
|
10
|
+
* the OS and CPU (four, for Linux x64, about 900 MB), because none of them
|
|
11
|
+
* declares its libc or CPU features. akm fetches the one that matches this
|
|
12
|
+
* machine from the npm registry the first time its runtime is used, checks it
|
|
13
|
+
* against the registry's integrity hash, and keeps the executable under
|
|
14
|
+
* `<akm cache dir>/opencode/<version>/`. Package selection mirrors the
|
|
15
|
+
* `postinstall.mjs` of `@opencode/cli`.
|
|
16
|
+
*/
|
|
17
|
+
import { spawnSync } from "node:child_process";
|
|
18
|
+
import { createHash } from "node:crypto";
|
|
19
|
+
import fs from "node:fs";
|
|
20
|
+
import path from "node:path";
|
|
21
|
+
import { fetchWithRetry, isRecord, toErrorMessage } from "../../../../core/common.js";
|
|
22
|
+
import { getCacheDir } from "../../../../core/paths.js";
|
|
23
|
+
import { info } from "../../../../core/warn.js";
|
|
24
|
+
import { writeResponseToFileCapped } from "../../../../runtime.js";
|
|
25
|
+
import { extractTarGzMember } from "./tar.js";
|
|
26
|
+
/**
|
|
27
|
+
* The OpenCode release akm's own runtime runs. It is pinned because the runtime depends on things no OpenCode release
|
|
28
|
+
* promises: the inline config's shape, the `--standalone` flag, the plugin API, the text `run` prints, and the
|
|
29
|
+
* `opencode.db` tables that `../session-log-v2.ts` reads. To move it, change this version and `PACKAGES` if the release
|
|
30
|
+
* adds or drops a platform package, then run `tests/integration/opencode-runtime-sessions.test.ts` against the new
|
|
31
|
+
* binary (it fetches it) and read `docs/reference/configuration.md` ("Without a harness") for what the version changes.
|
|
32
|
+
*/
|
|
33
|
+
export const OPENCODE_RUNTIME_VERSION = "2.1.4";
|
|
34
|
+
const REGISTRY = "https://registry.npmjs.org";
|
|
35
|
+
/** The platform packages of `@opencode/cli` at {@link OPENCODE_RUNTIME_VERSION}. */
|
|
36
|
+
const PACKAGES = new Set([
|
|
37
|
+
"@opencode/cli-linux-x64",
|
|
38
|
+
"@opencode/cli-linux-x64-baseline",
|
|
39
|
+
"@opencode/cli-linux-x64-musl",
|
|
40
|
+
"@opencode/cli-linux-x64-baseline-musl",
|
|
41
|
+
"@opencode/cli-linux-arm64",
|
|
42
|
+
"@opencode/cli-linux-arm64-musl",
|
|
43
|
+
"@opencode/cli-darwin-x64",
|
|
44
|
+
"@opencode/cli-darwin-x64-baseline",
|
|
45
|
+
"@opencode/cli-darwin-arm64",
|
|
46
|
+
"@opencode/cli-windows-x64",
|
|
47
|
+
"@opencode/cli-windows-x64-baseline",
|
|
48
|
+
"@opencode/cli-windows-arm64",
|
|
49
|
+
]);
|
|
50
|
+
/** The package for a machine: `@opencode/cli-<platform>-<arch>`, with `-baseline` for an x64 CPU without AVX2 and `-musl` for musl. */
|
|
51
|
+
export function opencodePackage({ platform, arch, musl, avx2 }) {
|
|
52
|
+
const name = [
|
|
53
|
+
`@opencode/cli-${platform}-${arch}`,
|
|
54
|
+
...(arch === "x64" && !avx2 ? ["baseline"] : []),
|
|
55
|
+
...(platform === "linux" && musl ? ["musl"] : []),
|
|
56
|
+
].join("-");
|
|
57
|
+
if (!PACKAGES.has(name)) {
|
|
58
|
+
throw new Error(`OpenCode ${OPENCODE_RUNTIME_VERSION} publishes no binary for ${platform} ${arch} (${name}).`);
|
|
59
|
+
}
|
|
60
|
+
return name;
|
|
61
|
+
}
|
|
62
|
+
function run(command, args, timeout) {
|
|
63
|
+
return spawnSync(command, args, { encoding: "utf8", timeout, windowsHide: true });
|
|
64
|
+
}
|
|
65
|
+
const AVX2_WINDOWS_PROBE = '(Add-Type -MemberDefinition "[DllImport(""kernel32.dll"")] public static extern bool IsProcessorFeaturePresent(int ProcessorFeature);" -Name Kernel32 -Namespace Win32 -PassThru)::IsProcessorFeaturePresent(40)';
|
|
66
|
+
/** Whether an x64 CPU has AVX2, asked the way OpenCode's own installer asks it. */
|
|
67
|
+
function hasAvx2(platform) {
|
|
68
|
+
try {
|
|
69
|
+
if (platform === "linux")
|
|
70
|
+
return /(^|\s)avx2(\s|$)/i.test(fs.readFileSync("/proc/cpuinfo", "utf8"));
|
|
71
|
+
if (platform === "darwin") {
|
|
72
|
+
const probe = run("sysctl", ["-n", "hw.optional.avx2_0"], 1500);
|
|
73
|
+
return probe.status === 0 && probe.stdout.trim() === "1";
|
|
74
|
+
}
|
|
75
|
+
for (const shell of ["powershell.exe", "pwsh.exe", "pwsh", "powershell"]) {
|
|
76
|
+
const probe = run(shell, ["-NoProfile", "-NonInteractive", "-Command", AVX2_WINDOWS_PROBE], 3000);
|
|
77
|
+
if (probe.status !== 0)
|
|
78
|
+
continue;
|
|
79
|
+
const answer = probe.stdout.trim().toLowerCase();
|
|
80
|
+
if (answer === "true" || answer === "1")
|
|
81
|
+
return true;
|
|
82
|
+
if (answer === "false" || answer === "0")
|
|
83
|
+
return false;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
catch {
|
|
87
|
+
// Not knowing is the baseline build, which runs everywhere.
|
|
88
|
+
}
|
|
89
|
+
return false;
|
|
90
|
+
}
|
|
91
|
+
/** Whether this Linux uses musl libc. */
|
|
92
|
+
function isMusl() {
|
|
93
|
+
if (fs.existsSync("/etc/alpine-release"))
|
|
94
|
+
return true;
|
|
95
|
+
const probe = run("ldd", ["--version"], 5000);
|
|
96
|
+
return `${probe.stdout ?? ""}${probe.stderr ?? ""}`.toLowerCase().includes("musl");
|
|
97
|
+
}
|
|
98
|
+
/** This machine, as the package choice sees it. */
|
|
99
|
+
export function detectHost(env = process.env, operatingSystem = process.platform, processArch = process.arch) {
|
|
100
|
+
const platform = { darwin: "darwin", linux: "linux", win32: "windows" }[operatingSystem];
|
|
101
|
+
const nodeArch = { x64: "x64", arm64: "arm64" }[processArch];
|
|
102
|
+
if (!platform || !nodeArch)
|
|
103
|
+
throw new Error(`OpenCode publishes no binary for ${operatingSystem} ${processArch}.`);
|
|
104
|
+
// An x64 process on Windows for ARM still names the host CPU in PROCESSOR_IDENTIFIER, and the arm64 build is the one to run.
|
|
105
|
+
const arch = platform === "windows" && nodeArch === "x64" && env.PROCESSOR_IDENTIFIER?.startsWith("ARM") ? "arm64" : nodeArch;
|
|
106
|
+
return { platform, arch, musl: platform === "linux" && isMusl(), avx2: arch === "x64" && hasAvx2(platform) };
|
|
107
|
+
}
|
|
108
|
+
/** Where the OpenCode binary is kept once fetched. */
|
|
109
|
+
export function runtimeBinaryPath(platform = process.platform) {
|
|
110
|
+
return path.join(getCacheDir(), "opencode", OPENCODE_RUNTIME_VERSION, platform === "win32" ? "opencode.exe" : "opencode");
|
|
111
|
+
}
|
|
112
|
+
/** The `sha512-<base64>` integrity npm records for a tarball. */
|
|
113
|
+
function sha512Integrity(file) {
|
|
114
|
+
return new Promise((resolve, reject) => {
|
|
115
|
+
const hash = createHash("sha512");
|
|
116
|
+
fs.createReadStream(file)
|
|
117
|
+
.on("data", (chunk) => hash.update(chunk))
|
|
118
|
+
.on("error", reject)
|
|
119
|
+
.on("end", () => resolve(`sha512-${hash.digest("base64")}`));
|
|
120
|
+
});
|
|
121
|
+
}
|
|
122
|
+
/** Throws unless the tarball at `file` has the integrity the registry lists for it. */
|
|
123
|
+
export async function verifyIntegrity(file, expected) {
|
|
124
|
+
const listed = expected.split(/\s+/).filter((integrity) => integrity.startsWith("sha512-"));
|
|
125
|
+
if (listed.length === 0)
|
|
126
|
+
throw new Error(`the registry lists no sha512 integrity for it (${expected || "none"})`);
|
|
127
|
+
const actual = await sha512Integrity(file);
|
|
128
|
+
if (!listed.includes(actual))
|
|
129
|
+
throw new Error(`its sha512 integrity is ${actual}, not the ${listed.join(" or ")} the registry lists`);
|
|
130
|
+
}
|
|
131
|
+
async function registryDocument(url) {
|
|
132
|
+
const response = await fetchWithRetry(url, { headers: { accept: "application/json" } }, { timeout: 30_000 });
|
|
133
|
+
if (!response.ok) {
|
|
134
|
+
await response.body?.cancel().catch(() => undefined);
|
|
135
|
+
throw new Error(`the registry answered HTTP ${response.status}`);
|
|
136
|
+
}
|
|
137
|
+
const dist = (await response.json()).dist;
|
|
138
|
+
if (!isRecord(dist) || typeof dist.tarball !== "string" || typeof dist.integrity !== "string") {
|
|
139
|
+
throw new Error("the registry document has no dist.tarball and dist.integrity");
|
|
140
|
+
}
|
|
141
|
+
return { tarball: dist.tarball, integrity: dist.integrity };
|
|
142
|
+
}
|
|
143
|
+
/**
|
|
144
|
+
* Fetch the binary of the package `name` into `binary`: the registry document of that one package, its tarball, the
|
|
145
|
+
* integrity check before anything is extracted, then the executable by temp file and rename. Two akm processes fetching
|
|
146
|
+
* at once both finish: a rename that loses to the other leaves the file the other made.
|
|
147
|
+
*/
|
|
148
|
+
async function fetchBinary(name, binary) {
|
|
149
|
+
const directory = path.dirname(binary);
|
|
150
|
+
fs.mkdirSync(directory, { recursive: true });
|
|
151
|
+
const download = path.join(directory, `.download-${process.pid}.tgz`);
|
|
152
|
+
const partial = path.join(directory, `.opencode-${process.pid}.tmp`);
|
|
153
|
+
try {
|
|
154
|
+
const { tarball, integrity } = await registryDocument(`${REGISTRY}/${name}/${OPENCODE_RUNTIME_VERSION}`);
|
|
155
|
+
info(`Fetching OpenCode ${OPENCODE_RUNTIME_VERSION} for akm's own agent runtime (about 114 MB, once) into ${directory}.`);
|
|
156
|
+
const response = await fetchWithRetry(tarball, undefined, { timeout: 60_000 });
|
|
157
|
+
if (!response.ok) {
|
|
158
|
+
await response.body?.cancel().catch(() => undefined);
|
|
159
|
+
throw new Error(`${tarball} answered HTTP ${response.status}`);
|
|
160
|
+
}
|
|
161
|
+
// No overall deadline for a 114 MB file on a slow link: only 60 s without bytes fails it.
|
|
162
|
+
await writeResponseToFileCapped(download, response, { stallTimeoutMs: 60_000 });
|
|
163
|
+
await verifyIntegrity(download, integrity);
|
|
164
|
+
const size = await extractTarGzMember(download, `package/bin/${path.basename(binary)}`, partial);
|
|
165
|
+
fs.chmodSync(partial, 0o755);
|
|
166
|
+
try {
|
|
167
|
+
fs.renameSync(partial, binary);
|
|
168
|
+
}
|
|
169
|
+
catch (error) {
|
|
170
|
+
// Where an open executable cannot be replaced, the other process's file stands.
|
|
171
|
+
if (!fs.existsSync(binary) || fs.statSync(binary).size !== size)
|
|
172
|
+
throw error;
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
finally {
|
|
176
|
+
fs.rmSync(download, { force: true });
|
|
177
|
+
fs.rmSync(partial, { force: true });
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
/** Fetch the binary for this machine, naming the package, its URL and the cache path when it cannot. */
|
|
181
|
+
async function fetchForThisMachine(binary) {
|
|
182
|
+
let name = "an @opencode/cli platform package";
|
|
183
|
+
try {
|
|
184
|
+
name = opencodePackage(detectHost());
|
|
185
|
+
await fetchBinary(name, binary);
|
|
186
|
+
return binary;
|
|
187
|
+
}
|
|
188
|
+
catch (error) {
|
|
189
|
+
throw new Error(`Could not fetch OpenCode ${OPENCODE_RUNTIME_VERSION}, which akm's own agent runtime runs: package ${name} from ${REGISTRY}/${name}/${OPENCODE_RUNTIME_VERSION} into ${path.dirname(binary)}: ${toErrorMessage(error)}. ` +
|
|
190
|
+
"Without network access for this step, enable the opencode harness with an installed OpenCode 2 instead (see docs/reference/configuration.md).");
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
let fetching;
|
|
194
|
+
/**
|
|
195
|
+
* The path of the OpenCode binary akm's runtime runs, fetched first if it is not in the cache. A process fetches once,
|
|
196
|
+
* however many runs ask meanwhile.
|
|
197
|
+
*/
|
|
198
|
+
export function ensureRuntimeBinary() {
|
|
199
|
+
const binary = runtimeBinaryPath();
|
|
200
|
+
if (fs.existsSync(binary))
|
|
201
|
+
return Promise.resolve(binary);
|
|
202
|
+
fetching ??= fetchForThisMachine(binary).finally(() => {
|
|
203
|
+
fetching = undefined;
|
|
204
|
+
});
|
|
205
|
+
return fetching;
|
|
206
|
+
}
|
|
@@ -0,0 +1,152 @@
|
|
|
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
|
+
* The OpenCode 2 process akm's own runtime starts for one run, built the way the
|
|
6
|
+
* opencode harness builds model work on the user's OpenCode 2
|
|
7
|
+
* (`../agent-builder.ts`): `run --standalone --title akm`, the prompt on stdin,
|
|
8
|
+
* the inline config in `OPENCODE_CONFIG_CONTENT`. What differs is that the
|
|
9
|
+
* process is akm's own, so akm sets what a user's OpenCode keeps for itself:
|
|
10
|
+
*
|
|
11
|
+
* - **The connection is the only provider.** `@ai-sdk/openai-compatible` (which
|
|
12
|
+
* the binary bundles) at the connection's endpoint, with its key, and the one
|
|
13
|
+
* model the run was dispatched with, with the context window and output cap the
|
|
14
|
+
* connection states. The key is not in the config: the config names a 0600
|
|
15
|
+
* file under akm's runtime directory that holds it (`{file:…}`), so no process
|
|
16
|
+
* environment holds the key.
|
|
17
|
+
* - **akm's roots.** OpenCode's config, data, cache and state directories and its
|
|
18
|
+
* temp directory are akm's (`../roots.ts`), so nothing of the user's OpenCode
|
|
19
|
+
* is read or written and the sessions land where akm's reader looks. The
|
|
20
|
+
* inherited `OPENCODE_*` variables are dropped for the same reason.
|
|
21
|
+
* - **Nothing from outside.** No hosted free models and no model catalog fetch
|
|
22
|
+
* (a run with no usable provider fails instead of sending its prompt to
|
|
23
|
+
* OpenCode's service), no project config (`AGENTS.md`, `opencode.json`) and no
|
|
24
|
+
* Claude Code files (`~/.claude/skills`).
|
|
25
|
+
* - **The resume sweep is off** because `--standalone` keeps the run to one
|
|
26
|
+
* process that ends with it and replays nobody's killed sessions.
|
|
27
|
+
* - **The agent's commands do not see any of this.** The plugin puts the
|
|
28
|
+
* variables this module sets back to what akm runs in, or removes them, in the
|
|
29
|
+
* environment of the commands the agent runs: they get the user's directories,
|
|
30
|
+
* not the runtime's, and no OpenCode setting of akm's (an `opencode` they run
|
|
31
|
+
* would otherwise load akm's provider and its key file).
|
|
32
|
+
*
|
|
33
|
+
* The run is OpenCode's default agent (or the native agent the request names) with
|
|
34
|
+
* its normal tools, akm's three read tools and the connection's request fields
|
|
35
|
+
* from the plugin (`../../../../assets/opencode/akm-plugin.js`).
|
|
36
|
+
*/
|
|
37
|
+
import path from "node:path";
|
|
38
|
+
import { openAiBaseUrl } from "../../../../core/endpoint-url.js";
|
|
39
|
+
import { effectiveRequestFields } from "../../../../core/llm-inference.js";
|
|
40
|
+
/** The provider the connection is declared as; a process runs one connection, so the name is fixed. */
|
|
41
|
+
const PROVIDER = "akm";
|
|
42
|
+
const positiveInteger = (value) => typeof value === "number" && Number.isInteger(value) && value > 0 ? value : undefined;
|
|
43
|
+
/**
|
|
44
|
+
* A path as a `{file:…}` reference. OpenCode replaces the reference in the config's text before it parses it, so the
|
|
45
|
+
* path is read with the text's JSON escapes in it (measured on 2.1.4: a path holding a backslash or a quote is not
|
|
46
|
+
* found, and the request goes out with no key). Windows takes forward slashes, so its paths are written with them.
|
|
47
|
+
*/
|
|
48
|
+
function fileReference(file) {
|
|
49
|
+
return process.platform === "win32" ? file.replaceAll("\\", "/") : file;
|
|
50
|
+
}
|
|
51
|
+
/** What OpenCode assumes of a model that states no limit. It refuses a model whose limit states only one of the two. */
|
|
52
|
+
const DEFAULT_LIMIT = { context: 200_000, output: 32_000 };
|
|
53
|
+
/**
|
|
54
|
+
* The inline OpenCode config of a run. `keyFile` is where the connection's key is written for the run, when it has
|
|
55
|
+
* one. `ambient` is the environment the process is started over: the plugin gives the commands the agent runs these
|
|
56
|
+
* values back for the variables the run sets, and removes them where there is none.
|
|
57
|
+
*/
|
|
58
|
+
export function runtimeConfig(connection, pluginDirectory, keyFile, ambient = {}) {
|
|
59
|
+
const requestFields = effectiveRequestFields(connection.request, connection.inference);
|
|
60
|
+
const context = positiveInteger(connection.contextLength);
|
|
61
|
+
const output = positiveInteger(requestFields.max_tokens);
|
|
62
|
+
const limit = context === undefined && output === undefined
|
|
63
|
+
? undefined
|
|
64
|
+
: { context: context ?? DEFAULT_LIMIT.context, output: output ?? DEFAULT_LIMIT.output };
|
|
65
|
+
return {
|
|
66
|
+
plugins: [
|
|
67
|
+
{
|
|
68
|
+
package: pluginDirectory,
|
|
69
|
+
options: {
|
|
70
|
+
requestFields,
|
|
71
|
+
shellEnv: Object.fromEntries(RUNTIME_VARIABLES.map((name) => [name, ambient[name] ?? null])),
|
|
72
|
+
},
|
|
73
|
+
},
|
|
74
|
+
],
|
|
75
|
+
provider: {
|
|
76
|
+
[PROVIDER]: {
|
|
77
|
+
npm: "@ai-sdk/openai-compatible",
|
|
78
|
+
name: PROVIDER,
|
|
79
|
+
options: {
|
|
80
|
+
baseURL: openAiBaseUrl(connection.endpoint),
|
|
81
|
+
...(connection.apiKey ? { apiKey: `{file:${fileReference(keyFile)}}` } : {}),
|
|
82
|
+
},
|
|
83
|
+
models: {
|
|
84
|
+
[connection.model]: {
|
|
85
|
+
name: connection.model,
|
|
86
|
+
...(limit ? { limit } : {}),
|
|
87
|
+
},
|
|
88
|
+
},
|
|
89
|
+
},
|
|
90
|
+
},
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* The variables {@link runtimeEnv} sets that the commands the agent runs must not see as set: the runtime's roots (a
|
|
95
|
+
* command would read and write akm's directories instead of the user's) and akm's OpenCode settings (an `opencode` a
|
|
96
|
+
* command runs would load akm's provider and its key file). `AKM_OPENCODE_CLI`, between akm and its plugin, is
|
|
97
|
+
* harmless to a command and is left.
|
|
98
|
+
*/
|
|
99
|
+
const RUNTIME_VARIABLES = [
|
|
100
|
+
"XDG_CONFIG_HOME",
|
|
101
|
+
"XDG_DATA_HOME",
|
|
102
|
+
"XDG_CACHE_HOME",
|
|
103
|
+
"XDG_STATE_HOME",
|
|
104
|
+
"TMPDIR",
|
|
105
|
+
"OPENCODE_DISABLE_FREE_MODELS",
|
|
106
|
+
"OPENCODE_DISABLE_MODELS_FETCH",
|
|
107
|
+
"OPENCODE_DISABLE_PROJECT_CONFIG",
|
|
108
|
+
"OPENCODE_DISABLE_CLAUDE_CODE",
|
|
109
|
+
"OPENCODE_CONFIG_CONTENT",
|
|
110
|
+
];
|
|
111
|
+
/** What a run sets in the process's environment, over the one akm and the caller give every child. */
|
|
112
|
+
export function runtimeEnv(config, where) {
|
|
113
|
+
const at = (...parts) => path.join(where.directory, ...parts);
|
|
114
|
+
return {
|
|
115
|
+
XDG_CONFIG_HOME: at("config"),
|
|
116
|
+
XDG_DATA_HOME: at("data"),
|
|
117
|
+
XDG_CACHE_HOME: at("cache"),
|
|
118
|
+
XDG_STATE_HOME: at("state"),
|
|
119
|
+
TMPDIR: at("tmp"),
|
|
120
|
+
OPENCODE_DISABLE_FREE_MODELS: "1",
|
|
121
|
+
OPENCODE_DISABLE_MODELS_FETCH: "1",
|
|
122
|
+
OPENCODE_DISABLE_PROJECT_CONFIG: "1",
|
|
123
|
+
OPENCODE_DISABLE_CLAUDE_CODE: "1",
|
|
124
|
+
OPENCODE_CONFIG_CONTENT: JSON.stringify(config),
|
|
125
|
+
AKM_OPENCODE_CLI: JSON.stringify(where.akm),
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
/**
|
|
129
|
+
* A command that makes and migrates OpenCode's database and does nothing else (it lists the sessions, with no model and
|
|
130
|
+
* no background service), for the first start of a database.
|
|
131
|
+
*/
|
|
132
|
+
export function runtimePrepareArgv(binary) {
|
|
133
|
+
return [binary, "session", "list", "--standalone"];
|
|
134
|
+
}
|
|
135
|
+
/**
|
|
136
|
+
* The command line of a run; the prompt is not on it, it goes on stdin. `session` is the id the run's session is made
|
|
137
|
+
* with (`--session` makes a session of that id when none has it), so akm finds the session the run left.
|
|
138
|
+
*/
|
|
139
|
+
export function runtimeArgv(connection, dispatch, binary, session) {
|
|
140
|
+
return [
|
|
141
|
+
binary,
|
|
142
|
+
"run",
|
|
143
|
+
"--standalone",
|
|
144
|
+
"--title",
|
|
145
|
+
"akm",
|
|
146
|
+
"--session",
|
|
147
|
+
session,
|
|
148
|
+
...(dispatch.agent ? ["--agent", dispatch.agent] : []),
|
|
149
|
+
"--model",
|
|
150
|
+
`${PROVIDER}/${connection.model}`,
|
|
151
|
+
];
|
|
152
|
+
}
|
|
@@ -0,0 +1,177 @@
|
|
|
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
|
+
* akm's own agent runtime: a pinned OpenCode 2 binary run as a process over a
|
|
6
|
+
* connection (`./command.ts`), for agent work when no harness is enabled. It is
|
|
7
|
+
* what the application's port (`integrations/agent/runtime-port.ts`) asks for.
|
|
8
|
+
*
|
|
9
|
+
* The binary is fetched on first use (`./binary.ts`). Each run is its own process,
|
|
10
|
+
* run through the same spawn path as a harness's, so the deadline, the caller's
|
|
11
|
+
* signal and the capture of its output are the ones every agent run has. The
|
|
12
|
+
* process keeps nothing between runs but akm's runtime directory, where its
|
|
13
|
+
* sessions are (`../roots.ts`); nothing here reads config.
|
|
14
|
+
*/
|
|
15
|
+
import { randomUUID } from "node:crypto";
|
|
16
|
+
import fs from "node:fs";
|
|
17
|
+
import path from "node:path";
|
|
18
|
+
import akmPlugin from "../../../../assets/opencode/akm-plugin.js" with { type: "text" };
|
|
19
|
+
import { toErrorMessage, writeFileAtomic } from "../../../../core/common.js";
|
|
20
|
+
import { createLockPayload, probeLock, reclaimStaleLock, releaseLock, tryAcquireLockSync, } from "../../../../core/file-lock.js";
|
|
21
|
+
import { PORTABLE_INFERENCE_KEYS } from "../../../../core/llm-inference.js";
|
|
22
|
+
import { openDatabase } from "../../../../storage/database.js";
|
|
23
|
+
import { resolveAkmInvocation } from "../../../../tasks/resolve-akm-bin.js";
|
|
24
|
+
import { buildChildEnv, runBuiltCommand, } from "../../../agent/spawn.js";
|
|
25
|
+
import { akmOpencodeDatabasePath, akmRuntimeDir } from "../roots.js";
|
|
26
|
+
import { v2SessionTokens } from "../session-log-v2.js";
|
|
27
|
+
import { ensureRuntimeBinary, OPENCODE_RUNTIME_VERSION } from "./binary.js";
|
|
28
|
+
import { runtimeArgv, runtimeConfig, runtimeEnv, runtimePrepareArgv } from "./command.js";
|
|
29
|
+
/**
|
|
30
|
+
* What a request is lowered for when it runs here. The persona goes in the prompt, as for the opencode harness
|
|
31
|
+
* (`opencode run` has no system prompt flag); every portable setting is carried, as request fields the plugin lays over
|
|
32
|
+
* the model requests.
|
|
33
|
+
*/
|
|
34
|
+
const runtimeLowerer = {
|
|
35
|
+
id: "akm-runtime",
|
|
36
|
+
systemPrompt: false,
|
|
37
|
+
nativeAgent: true,
|
|
38
|
+
// Model work on a connection is a chat call (`buildExecution`), so no run here is confined; if one were lowered here, say so.
|
|
39
|
+
confinable: false,
|
|
40
|
+
inference: PORTABLE_INFERENCE_KEYS,
|
|
41
|
+
};
|
|
42
|
+
/** How long preparing the database may take: it is a few milliseconds of work and a process start. */
|
|
43
|
+
const PREPARE_TIMEOUT_MS = 60_000;
|
|
44
|
+
/** The connection's key, for the one run that reads it, kept as `credentials.json` is: 0600, in a 0700 directory. */
|
|
45
|
+
function writeKeyFile(file, key) {
|
|
46
|
+
fs.mkdirSync(path.dirname(file), { recursive: true, mode: 0o700 });
|
|
47
|
+
writeFileAtomic(file, key, 0o600);
|
|
48
|
+
}
|
|
49
|
+
/** Write the plugin where OpenCode loads it from (a directory, whose `index.mjs` is the module), when it is not already there. */
|
|
50
|
+
function installPlugin(directory) {
|
|
51
|
+
const pluginDirectory = path.join(directory, "config", "akm-plugin");
|
|
52
|
+
const file = path.join(pluginDirectory, "index.mjs");
|
|
53
|
+
if (!fs.existsSync(file) || fs.readFileSync(file, "utf8") !== akmPlugin) {
|
|
54
|
+
fs.mkdirSync(pluginDirectory, { recursive: true });
|
|
55
|
+
const partial = `${file}.${process.pid}.tmp`;
|
|
56
|
+
fs.writeFileSync(partial, akmPlugin);
|
|
57
|
+
fs.renameSync(partial, file);
|
|
58
|
+
}
|
|
59
|
+
return pluginDirectory;
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* OpenCode makes and migrates its database when a process starts, and two processes doing that to one database break
|
|
63
|
+
* each other (one fails with "Standalone server exited before reporting readiness"; on 2.1.4 two runs started together
|
|
64
|
+
* on a fresh directory lose one of them every time). So the first start of this OpenCode version is a preparing run of
|
|
65
|
+
* its own, under a lock file in the runtime directory that every run, of this akm process or another, waits on, and it
|
|
66
|
+
* leaves a marker naming the version; a run that finds the marker and the database starts at once. A dead holder's
|
|
67
|
+
* lock is reclaimed. The run itself reports anything the preparation does not.
|
|
68
|
+
*/
|
|
69
|
+
async function prepareDatabase(directory, command, opts) {
|
|
70
|
+
const marker = path.join(directory, `prepared-${OPENCODE_RUNTIME_VERSION}`);
|
|
71
|
+
const lock = path.join(directory, "prepare.lock");
|
|
72
|
+
const prepared = () => fs.existsSync(marker) && fs.existsSync(akmOpencodeDatabasePath());
|
|
73
|
+
const deadline = Date.now() + PREPARE_TIMEOUT_MS;
|
|
74
|
+
while (!prepared() && !opts.signal?.aborted) {
|
|
75
|
+
const ownership = tryAcquireLockSync(lock, createLockPayload());
|
|
76
|
+
if (ownership) {
|
|
77
|
+
try {
|
|
78
|
+
if (prepared())
|
|
79
|
+
return;
|
|
80
|
+
const result = await runBuiltCommand("akm's runtime preparing its database", command, {
|
|
81
|
+
...(opts.cwd ? { cwd: opts.cwd } : {}),
|
|
82
|
+
...(opts.signal ? { signal: opts.signal } : {}),
|
|
83
|
+
timeoutMs: PREPARE_TIMEOUT_MS,
|
|
84
|
+
});
|
|
85
|
+
if (result.ok)
|
|
86
|
+
fs.writeFileSync(marker, "");
|
|
87
|
+
return;
|
|
88
|
+
}
|
|
89
|
+
finally {
|
|
90
|
+
releaseLock(ownership);
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
const probe = probeLock(lock);
|
|
94
|
+
if (probe.state === "stale" && reclaimStaleLock(lock, probe))
|
|
95
|
+
continue;
|
|
96
|
+
if (Date.now() >= deadline) {
|
|
97
|
+
throw new Error(`Another akm process is still preparing the database of akm's runtime (lock ${lock}).`);
|
|
98
|
+
}
|
|
99
|
+
await new Promise((resolve) => setTimeout(resolve, 100));
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* The run's session as OpenCode recorded it, read once the process has ended: its id and the tokens its turn used,
|
|
104
|
+
* which a workflow's `budget.max_tokens` and the unit journal count. Nothing when the run made no session. Accounting
|
|
105
|
+
* is best-effort: a database that cannot be read leaves the run's result as it is.
|
|
106
|
+
*/
|
|
107
|
+
function sessionRecord(sessionId) {
|
|
108
|
+
try {
|
|
109
|
+
const db = openDatabase(akmOpencodeDatabasePath(), { readonly: true, create: false });
|
|
110
|
+
try {
|
|
111
|
+
const tokens = v2SessionTokens(db, sessionId);
|
|
112
|
+
if (!tokens)
|
|
113
|
+
return {};
|
|
114
|
+
return {
|
|
115
|
+
sessionId,
|
|
116
|
+
usage: { inputTokens: tokens.input, outputTokens: tokens.output, reasoningTokens: tokens.reasoning },
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
finally {
|
|
120
|
+
db.close();
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
catch {
|
|
124
|
+
return {};
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
export const opencodeRuntime = {
|
|
128
|
+
lowering: runtimeLowerer,
|
|
129
|
+
async run(profile, opts, connection) {
|
|
130
|
+
const label = `akm's runtime on connection "${profile.name}"`;
|
|
131
|
+
const dispatch = opts.dispatch;
|
|
132
|
+
if (dispatch?.prompt === undefined)
|
|
133
|
+
throw new TypeError("A run on akm's runtime is given a prompt.");
|
|
134
|
+
const start = Date.now();
|
|
135
|
+
try {
|
|
136
|
+
const binary = await ensureRuntimeBinary();
|
|
137
|
+
const directory = akmRuntimeDir();
|
|
138
|
+
for (const name of ["config", "data", "cache", "state", "tmp"]) {
|
|
139
|
+
fs.mkdirSync(path.join(directory, name), { recursive: true });
|
|
140
|
+
}
|
|
141
|
+
const where = {
|
|
142
|
+
binary,
|
|
143
|
+
directory,
|
|
144
|
+
pluginDirectory: installPlugin(directory),
|
|
145
|
+
akm: resolveAkmInvocation().argv,
|
|
146
|
+
};
|
|
147
|
+
// The user's own OPENCODE_* variables configure their OpenCode, not this one.
|
|
148
|
+
const ambient = Object.fromEntries(Object.entries(buildChildEnv(opts)).filter(([name]) => !name.startsWith("OPENCODE_")));
|
|
149
|
+
// OpenCode's own ids start with `ses_`, which it requires of one it is given.
|
|
150
|
+
const session = `ses_akm${randomUUID().replaceAll("-", "")}`;
|
|
151
|
+
const keyFile = path.join(directory, "keys", session);
|
|
152
|
+
const config = runtimeConfig(connection, where.pluginDirectory, keyFile, ambient);
|
|
153
|
+
const env = { ...ambient, ...runtimeEnv(config, where) };
|
|
154
|
+
try {
|
|
155
|
+
if (connection.apiKey)
|
|
156
|
+
writeKeyFile(keyFile, connection.apiKey);
|
|
157
|
+
await prepareDatabase(directory, { argv: runtimePrepareArgv(binary), env }, opts);
|
|
158
|
+
const result = await runBuiltCommand(label, { argv: runtimeArgv(connection, dispatch, binary, session), env, stdin: dispatch.prompt }, opts, "captured");
|
|
159
|
+
return { ...result, ...sessionRecord(session) };
|
|
160
|
+
}
|
|
161
|
+
finally {
|
|
162
|
+
fs.rmSync(keyFile, { force: true });
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
catch (error) {
|
|
166
|
+
return {
|
|
167
|
+
ok: false,
|
|
168
|
+
exitCode: null,
|
|
169
|
+
stdout: "",
|
|
170
|
+
stderr: toErrorMessage(error),
|
|
171
|
+
durationMs: Date.now() - start,
|
|
172
|
+
reason: "spawn_failed",
|
|
173
|
+
error: toErrorMessage(error),
|
|
174
|
+
};
|
|
175
|
+
}
|
|
176
|
+
},
|
|
177
|
+
};
|