akm-cli 0.9.0-beta.9 → 0.9.0-rc.1
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 +715 -0
- package/README.md +12 -4
- package/dist/akm +38 -0
- package/dist/akm-migrate-storage +38 -0
- package/dist/assets/help/help-improve.md +9 -6
- package/dist/assets/hints/cli-hints-full.md +6 -5
- package/dist/assets/profiles/default.json +9 -4
- package/dist/assets/profiles/frequent.json +1 -1
- package/dist/assets/profiles/memory-focus.json +1 -1
- package/dist/assets/profiles/proactive-maintenance.json +25 -0
- package/dist/assets/profiles/quick.json +1 -1
- package/dist/assets/profiles/recombine-only.json +21 -0
- package/dist/assets/profiles/reflect-distill.json +30 -0
- package/dist/assets/profiles/synthesize.json +15 -0
- package/dist/assets/profiles/thorough.json +1 -1
- package/dist/assets/prompts/consolidate-system.md +23 -0
- package/dist/assets/prompts/contradiction-judge.md +33 -0
- package/dist/assets/prompts/distill-knowledge-system.md +22 -0
- package/dist/assets/prompts/distill-lesson-system.md +36 -0
- package/dist/assets/prompts/extract-session.md +11 -3
- package/dist/assets/prompts/graph-extract-system.md +1 -0
- package/dist/assets/prompts/graph-extract-user-prompt.md +1 -1
- package/dist/assets/prompts/memory-infer-system.md +1 -0
- package/dist/assets/prompts/memory-infer-user.md +5 -0
- package/dist/assets/prompts/metadata-enhance-system.md +1 -0
- package/dist/assets/prompts/procedural-system.md +44 -0
- package/dist/assets/prompts/recombine-system.md +40 -0
- package/dist/assets/prompts/staleness-detect-system.md +6 -0
- package/dist/assets/prompts/validate-summary-judge.md +1 -0
- package/dist/assets/prompts/workflow-unit-preamble.md +26 -0
- package/dist/assets/stash-skeleton/facts/conventions/assets/agent.md +38 -0
- package/dist/assets/stash-skeleton/facts/conventions/assets/command.md +38 -0
- package/dist/assets/stash-skeleton/facts/conventions/assets/fact.md +39 -0
- package/dist/assets/stash-skeleton/facts/conventions/assets/knowledge.md +40 -0
- package/dist/assets/stash-skeleton/facts/conventions/assets/lesson.md +43 -0
- package/dist/assets/stash-skeleton/facts/conventions/assets/memory.md +38 -0
- package/dist/assets/stash-skeleton/facts/conventions/assets/script.md +43 -0
- package/dist/assets/stash-skeleton/facts/conventions/assets/skill.md +40 -0
- package/dist/assets/stash-skeleton/facts/conventions/assets/workflow.md +43 -0
- package/dist/assets/templates/html/health.html +281 -111
- package/dist/assets/wiki/ingest-workflow-template.md +45 -16
- package/dist/assets/wiki/schema-template.md +4 -4
- package/dist/cli/clack.js +56 -0
- package/dist/cli/config-migrate.js +7 -1
- package/dist/cli/confirm.js +1 -1
- package/dist/cli/parse-args.js +46 -1
- package/dist/cli/shared.js +28 -0
- package/dist/cli.js +25 -21
- package/dist/commands/agent/agent-dispatch.js +3 -2
- package/dist/commands/agent/agent-support.js +0 -7
- package/dist/commands/agent/contribute-cli.js +26 -7
- package/dist/commands/config-cli.js +26 -13
- package/dist/commands/env/child-env.js +47 -0
- package/dist/commands/env/env-binding.js +95 -0
- package/dist/commands/env/env-cli.js +228 -292
- package/dist/commands/env/env.js +14 -67
- package/dist/commands/env/secret-cli.js +140 -138
- package/dist/commands/feedback-cli.js +156 -155
- package/dist/commands/graph/graph-cli.js +5 -13
- package/dist/commands/graph/graph.js +3 -3
- package/dist/commands/health/advisories.js +151 -0
- package/dist/commands/health/checks.js +103 -16
- package/dist/commands/health/html-report.js +447 -81
- package/dist/commands/health/improve-metrics.js +771 -0
- package/dist/commands/health/llm-usage.js +65 -0
- package/dist/commands/health/md-report.js +103 -0
- package/dist/commands/health/metrics.js +278 -0
- package/dist/commands/health/stash-exposure.js +46 -0
- package/dist/commands/health/surfaces.js +216 -0
- package/dist/commands/health/task-runs.js +135 -0
- package/dist/commands/health/types.js +26 -0
- package/dist/commands/health/windows.js +195 -0
- package/dist/commands/health.js +91 -1091
- package/dist/commands/improve/anti-collapse.js +170 -0
- package/dist/commands/improve/calibration.js +161 -0
- package/dist/commands/improve/collapse-detector.js +421 -0
- package/dist/commands/improve/consolidate/chunking.js +141 -0
- package/dist/commands/improve/consolidate/eligibility.js +64 -0
- package/dist/commands/improve/consolidate/merge.js +145 -0
- package/dist/commands/improve/consolidate/sanitize.js +231 -0
- package/dist/commands/{lint.js → improve/consolidate/types.js} +1 -1
- package/dist/commands/improve/consolidate.js +1295 -1277
- package/dist/commands/improve/dedup.js +482 -0
- package/dist/commands/improve/distill/content-repair.js +202 -0
- package/dist/commands/improve/distill/promote-memory.js +229 -0
- package/dist/commands/improve/distill/quality-gate.js +236 -0
- package/dist/commands/improve/distill-guards.js +127 -0
- package/dist/commands/improve/distill-promotion-policy.js +826 -167
- package/dist/commands/improve/distill.js +228 -605
- package/dist/commands/improve/eligibility.js +434 -0
- package/dist/commands/improve/encoding-salience.js +205 -0
- package/dist/commands/improve/extract-cli.js +179 -59
- package/dist/commands/improve/extract-prompt.js +54 -3
- package/dist/commands/improve/extract-watch.js +140 -0
- package/dist/commands/improve/extract.js +409 -43
- package/dist/commands/improve/feedback-valence.js +54 -0
- package/dist/commands/improve/hot-probation.js +45 -0
- package/dist/commands/improve/improve-auto-accept.js +157 -10
- package/dist/commands/improve/improve-cli.js +115 -73
- package/dist/commands/improve/improve-profiles.js +28 -8
- package/dist/commands/improve/improve-result-file.js +15 -25
- package/dist/commands/improve/improve-session.js +58 -0
- package/dist/commands/improve/improve.js +485 -2764
- package/dist/commands/improve/locks.js +154 -0
- package/dist/commands/improve/loop-stages.js +1100 -0
- package/dist/commands/improve/memory/memory-belief.js +14 -15
- package/dist/commands/improve/memory/memory-contradiction-detect.js +83 -60
- package/dist/commands/improve/memory/memory-improve.js +27 -27
- package/dist/commands/improve/outcome-loop.js +270 -0
- package/dist/commands/improve/preparation.js +2002 -0
- package/dist/commands/improve/proactive-maintenance.js +37 -35
- package/dist/commands/improve/procedural.js +398 -0
- package/dist/commands/improve/recombine.js +818 -0
- package/dist/commands/improve/reflect-noise.js +0 -0
- package/dist/commands/improve/reflect.js +206 -45
- package/dist/commands/improve/salience.js +455 -0
- package/dist/commands/improve/schema-similarity-gate.js +168 -0
- package/dist/commands/improve/shared.js +51 -0
- package/dist/commands/improve/triage.js +93 -0
- package/dist/commands/lint/agent-linter.js +19 -24
- package/dist/commands/lint/base-linter.js +173 -60
- package/dist/commands/lint/command-linter.js +19 -24
- package/dist/commands/lint/env-key-rules.js +38 -1
- package/dist/commands/lint/fact-linter.js +39 -0
- package/dist/commands/lint/index.js +31 -13
- package/dist/commands/lint/memory-linter.js +1 -1
- package/dist/commands/lint/registry.js +7 -2
- package/dist/commands/lint/task-linter.js +3 -3
- package/dist/commands/lint/workflow-linter.js +26 -1
- package/dist/commands/observability-cli.js +4 -4
- package/dist/commands/proposal/drain-policies.js +13 -4
- package/dist/commands/proposal/drain.js +45 -51
- package/dist/commands/proposal/legacy-import.js +115 -0
- package/dist/commands/proposal/proposal-cli.js +24 -34
- package/dist/commands/proposal/proposal.js +2 -1
- package/dist/commands/proposal/propose.js +8 -3
- package/dist/commands/proposal/repository.js +829 -0
- package/dist/commands/proposal/validators/proposal-quality-validators.js +9 -8
- package/dist/commands/proposal/validators/proposals.js +93 -895
- package/dist/commands/read/curate.js +410 -111
- package/dist/commands/read/knowledge.js +10 -3
- package/dist/commands/read/remember-cli.js +133 -138
- package/dist/commands/read/search-cli.js +15 -8
- package/dist/commands/read/search.js +22 -11
- package/dist/commands/read/show.js +106 -14
- package/dist/commands/registry-cli.js +76 -87
- package/dist/commands/remember.js +11 -12
- package/dist/commands/sources/add-cli.js +91 -95
- package/dist/commands/sources/history.js +1 -1
- package/dist/commands/sources/init.js +66 -18
- package/dist/commands/sources/installed-stashes.js +11 -3
- package/dist/commands/sources/migration-help.js +7 -4
- package/dist/commands/sources/schema-repair.js +44 -46
- package/dist/commands/sources/self-update.js +2 -2
- package/dist/commands/sources/source-add.js +7 -3
- package/dist/commands/sources/sources-cli.js +3 -3
- package/dist/commands/sources/stash-cli.js +19 -39
- package/dist/commands/sources/stash-skeleton.js +57 -8
- package/dist/commands/tasks/default-tasks.js +15 -2
- package/dist/commands/tasks/tasks-cli.js +20 -29
- package/dist/commands/tasks/tasks.js +39 -11
- package/dist/commands/wiki-cli.js +23 -38
- package/dist/commands/workflow-cli.js +291 -13
- package/dist/core/asset/asset-registry.js +3 -1
- package/dist/core/asset/asset-spec.js +79 -5
- package/dist/core/asset/frontmatter.js +188 -167
- package/dist/core/asset/markdown.js +8 -0
- package/dist/core/authoring-rules.js +92 -0
- package/dist/core/common.js +4 -23
- package/dist/core/concurrent.js +10 -1
- package/dist/core/config/config-io.js +10 -1
- package/dist/core/config/config-migration.js +18 -40
- package/dist/core/config/config-schema.js +403 -62
- package/dist/core/config/config-types.js +3 -3
- package/dist/core/config/config.js +67 -22
- package/dist/core/deep-merge.js +38 -0
- package/dist/core/errors.js +1 -0
- package/dist/core/eval/rank-metrics.js +113 -0
- package/dist/core/events.js +4 -7
- package/dist/core/improve-types.js +47 -8
- package/dist/core/json-schema.js +142 -0
- package/dist/core/logs-db.js +14 -75
- package/dist/core/parse.js +36 -16
- package/dist/core/paths.js +18 -18
- package/dist/core/standards/resolve-standards-context.js +87 -0
- package/dist/core/standards/resolve-stash-standards.js +99 -0
- package/dist/core/standards/resolve-type-conventions.js +66 -0
- package/dist/core/state/migrations.js +770 -0
- package/dist/core/state-db.js +132 -1126
- package/dist/core/structured.js +69 -0
- package/dist/core/time.js +53 -0
- package/dist/core/warn.js +21 -0
- package/dist/core/write-source.js +37 -0
- package/dist/indexer/db/db.js +261 -770
- package/dist/indexer/db/entry-mapper.js +41 -0
- package/dist/indexer/db/graph-db.js +129 -86
- package/dist/indexer/db/llm-cache.js +2 -2
- package/dist/indexer/db/schema.js +516 -0
- package/dist/indexer/ensure-index.js +36 -92
- package/dist/indexer/feedback/utility-policy.js +75 -0
- package/dist/indexer/graph/graph-boost.js +51 -41
- package/dist/indexer/graph/graph-extraction.js +207 -4
- package/dist/indexer/index-writer-lock.js +18 -11
- package/dist/indexer/index-written-assets.js +105 -0
- package/dist/indexer/indexer.js +182 -204
- package/dist/indexer/passes/dir-staleness.js +114 -0
- package/dist/indexer/passes/memory-inference.js +13 -5
- package/dist/indexer/passes/metadata.js +20 -0
- package/dist/indexer/read-preflight.js +23 -0
- package/dist/indexer/search/db-search.js +89 -13
- package/dist/indexer/search/fts-query.js +51 -0
- package/dist/indexer/search/ranking-contributors.js +95 -9
- package/dist/indexer/search/ranking.js +79 -3
- package/dist/indexer/search/search-fields.js +6 -0
- package/dist/indexer/search/search-source.js +32 -21
- package/dist/indexer/search/semantic-status.js +4 -0
- package/dist/indexer/walk/matchers.js +48 -0
- package/dist/indexer/walk/walker.js +21 -13
- package/dist/integrations/agent/builders.js +41 -13
- package/dist/integrations/agent/config.js +20 -59
- package/dist/integrations/agent/detect.js +9 -0
- package/dist/integrations/agent/index.js +3 -19
- package/dist/integrations/agent/model-aliases.js +16 -2
- package/dist/integrations/agent/profiles.js +79 -6
- package/dist/integrations/agent/prompts.js +75 -9
- package/dist/integrations/agent/runner-dispatch.js +83 -0
- package/dist/integrations/agent/runner.js +13 -9
- package/dist/integrations/agent/spawn.js +206 -81
- package/dist/integrations/harnesses/aider/agent-builder.js +113 -0
- package/dist/integrations/harnesses/aider/index.js +58 -0
- package/dist/integrations/harnesses/aider/result-extractor.js +53 -0
- package/dist/integrations/harnesses/amazonq/agent-builder.js +153 -0
- package/dist/integrations/harnesses/amazonq/index.js +59 -0
- package/dist/integrations/harnesses/amazonq/result-extractor.js +48 -0
- package/dist/integrations/harnesses/claude/agent-builder.js +46 -7
- package/dist/integrations/harnesses/claude/index.js +27 -23
- package/dist/integrations/harnesses/claude/result-extractor.js +52 -0
- package/dist/integrations/harnesses/claude/session-log.js +10 -0
- package/dist/integrations/harnesses/codex/agent-builder.js +137 -0
- package/dist/integrations/harnesses/codex/index.js +63 -0
- package/dist/integrations/harnesses/codex/result-extractor.js +73 -0
- package/dist/integrations/harnesses/copilot/agent-builder.js +122 -0
- package/dist/integrations/harnesses/copilot/index.js +60 -0
- package/dist/integrations/harnesses/copilot/result-extractor.js +151 -0
- package/dist/integrations/harnesses/gemini/agent-builder.js +121 -0
- package/dist/integrations/harnesses/gemini/index.js +60 -0
- package/dist/integrations/harnesses/gemini/result-extractor.js +121 -0
- package/dist/integrations/harnesses/index.js +28 -7
- package/dist/integrations/harnesses/opencode/agent-builder.js +1 -1
- package/dist/integrations/harnesses/opencode/index.js +17 -16
- package/dist/integrations/harnesses/opencode/session-log.js +173 -3
- package/dist/integrations/harnesses/opencode-sdk/harness.js +65 -0
- package/dist/integrations/harnesses/opencode-sdk/index.js +10 -34
- package/dist/integrations/harnesses/opencode-sdk/sdk-runner.js +642 -71
- package/dist/integrations/harnesses/openhands/agent-builder.js +126 -0
- package/dist/integrations/harnesses/openhands/index.js +58 -0
- package/dist/integrations/harnesses/openhands/result-extractor.js +103 -0
- package/dist/integrations/harnesses/pi/agent-builder.js +104 -0
- package/dist/integrations/harnesses/pi/index.js +58 -0
- package/dist/integrations/harnesses/pi/result-extractor.js +135 -0
- package/dist/integrations/harnesses/types.js +8 -0
- package/dist/integrations/session-logs/index.js +40 -11
- package/dist/llm/call-ai.js +2 -2
- package/dist/llm/client.js +34 -11
- package/dist/llm/embedder.js +67 -4
- package/dist/llm/embedders/cache.js +3 -1
- package/dist/llm/embedders/deterministic.js +66 -0
- package/dist/llm/embedders/local.js +73 -3
- package/dist/llm/feature-gate.js +16 -15
- package/dist/llm/graph-extract.js +67 -44
- package/dist/llm/memory-infer-impl.js +138 -0
- package/dist/llm/memory-infer.js +1 -127
- package/dist/llm/metadata-enhance.js +44 -31
- package/dist/llm/structured-call.js +49 -0
- package/dist/migrate-storage-node.mjs +8 -0
- package/dist/output/context.js +5 -5
- package/dist/output/renderers.js +87 -15
- package/dist/output/shapes/curate.js +14 -2
- package/dist/output/shapes/helpers.js +0 -3
- package/dist/output/shapes/passthrough.js +6 -1
- package/dist/output/text/helpers.js +241 -2
- package/dist/output/text/workflow.js +4 -1
- package/dist/registry/providers/skills-sh.js +21 -147
- package/dist/registry/providers/static-index.js +15 -157
- package/dist/registry/resolve.js +27 -9
- package/dist/runtime.js +25 -1
- package/dist/schemas/akm-config.json +14225 -0
- package/dist/schemas/akm-workflow.json +328 -0
- package/dist/scripts/migrate-storage.js +2743 -8390
- package/dist/scripts/migrations/import-fs-improve-runs-to-db.js +1652 -607
- package/dist/setup/detect.js +9 -0
- package/dist/setup/legacy-config.js +106 -0
- package/dist/setup/prompt.js +57 -0
- package/dist/setup/providers.js +14 -0
- package/dist/setup/registry-stash-loader.js +12 -0
- package/dist/setup/semantic-assets.js +124 -0
- package/dist/setup/setup.js +52 -1614
- package/dist/setup/steps/connection.js +734 -0
- package/dist/setup/steps/output.js +31 -0
- package/dist/setup/steps/platforms.js +124 -0
- package/dist/setup/steps/semantic.js +27 -0
- package/dist/setup/steps/sources.js +222 -0
- package/dist/setup/steps/stashdir.js +42 -0
- package/dist/setup/steps/tasks.js +152 -0
- package/dist/sources/include.js +6 -2
- package/dist/sources/providers/filesystem.js +0 -1
- package/dist/sources/providers/git-install.js +210 -0
- package/dist/sources/providers/git-provider.js +234 -0
- package/dist/sources/providers/git-stash.js +248 -0
- package/dist/sources/providers/git.js +10 -661
- package/dist/sources/providers/npm.js +2 -6
- package/dist/sources/providers/provider-utils.js +13 -7
- package/dist/sources/providers/sync-from-ref.js +9 -1
- package/dist/sources/providers/website.js +9 -5
- package/dist/sources/website-ingest.js +187 -29
- package/dist/sources/wiki-fetchers/registry.js +53 -0
- package/dist/sources/wiki-fetchers/youtube.js +239 -0
- package/dist/storage/database.js +45 -10
- package/dist/storage/managed-db.js +82 -0
- package/dist/storage/repositories/canaries-repository.js +107 -0
- package/dist/storage/repositories/consolidation-repository.js +38 -0
- package/dist/storage/repositories/embeddings-repository.js +72 -0
- package/dist/storage/repositories/events-repository.js +187 -0
- package/dist/storage/repositories/extract-sessions-repository.js +96 -0
- package/dist/storage/repositories/improve-runs-repository.js +146 -0
- package/dist/storage/repositories/index-db.js +14 -8
- package/dist/storage/repositories/proposals-repository.js +220 -0
- package/dist/storage/repositories/recombine-repository.js +213 -0
- package/dist/storage/repositories/registry-cache.js +93 -0
- package/dist/storage/repositories/registry-index-cache-repository.js +46 -0
- package/dist/storage/repositories/task-history-repository.js +93 -0
- package/dist/storage/repositories/workflow-runs-repository.js +189 -1
- package/dist/storage/sqlite-pragmas.js +146 -0
- package/dist/tasks/backends/cron.js +1 -1
- package/dist/tasks/backends/index.js +9 -0
- package/dist/tasks/backends/launchd.js +1 -1
- package/dist/tasks/backends/schtasks.js +1 -1
- package/dist/tasks/{resolveAkmBin.js → resolve-akm-bin.js} +2 -2
- package/dist/tasks/runner.js +15 -13
- package/dist/text-import-hook.mjs +1 -1
- package/dist/wiki/wiki.js +52 -11
- package/dist/workflows/authoring/authoring.js +123 -10
- package/dist/workflows/authoring/workflow-program-template.yaml +31 -0
- package/dist/workflows/cli.js +5 -0
- package/dist/workflows/db.js +138 -4
- package/dist/workflows/exec/brief.js +484 -0
- package/dist/workflows/exec/native-executor.js +975 -0
- package/dist/workflows/exec/param-secrets.js +115 -0
- package/dist/workflows/exec/report.js +1295 -0
- package/dist/workflows/exec/run-workflow.js +596 -0
- package/dist/workflows/exec/scheduler.js +100 -0
- package/dist/workflows/exec/step-work.js +1156 -0
- package/dist/workflows/exec/unit-writer.js +23 -0
- package/dist/workflows/exec/watch.js +116 -0
- package/dist/workflows/exec/worktree.js +171 -0
- package/dist/workflows/ir/compile.js +388 -0
- package/dist/workflows/ir/params.js +54 -0
- package/dist/workflows/ir/plan-hash.js +33 -0
- package/dist/workflows/ir/schema.js +4 -0
- package/dist/workflows/parser.js +3 -1
- package/dist/workflows/program/expressions.js +369 -0
- package/dist/workflows/program/parser.js +760 -0
- package/dist/workflows/program/project.js +105 -0
- package/dist/workflows/program/schema.js +54 -0
- package/dist/workflows/renderer.js +82 -5
- package/dist/workflows/runtime/agent-identity.js +59 -14
- package/dist/workflows/runtime/runs.js +248 -153
- package/dist/workflows/runtime/unit-checkin.js +45 -0
- package/dist/workflows/runtime/workflow-asset-loader.js +188 -0
- package/dist/workflows/validate-summary.js +26 -10
- package/dist/workflows/validator.js +1 -1
- package/docs/README.md +69 -18
- package/docs/data-and-telemetry.md +7 -5
- package/docs/migration/release-notes/0.7.0.md +1 -1
- package/docs/migration/release-notes/0.9.0-beta.60.md +19 -0
- package/docs/migration/release-notes/0.9.0.md +39 -0
- package/package.json +10 -10
- package/dist/assets/tasks/core/update-stashes.yml +0 -4
- package/dist/commands/db-cli.js +0 -23
- package/dist/indexer/db/db-backup.js +0 -376
- package/dist/indexer/passes/staleness-detect.js +0 -488
|
@@ -0,0 +1,121 @@
|
|
|
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
|
+
function isRecord(value) {
|
|
5
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* Keys that may carry the final answer, in precedence order. `response` is
|
|
9
|
+
* Gemini's documented `--output-format json` envelope key.
|
|
10
|
+
*/
|
|
11
|
+
const TEXT_KEYS = ["response", "result", "text", "output", "content", "message"];
|
|
12
|
+
/** Keys that may carry the harness-native session id, in precedence order. */
|
|
13
|
+
const SESSION_KEYS = ["session_id", "sessionId", "conversation_id", "conversationId", "chat_id", "chatId"];
|
|
14
|
+
/**
|
|
15
|
+
* Coerce a candidate value into text. Handles the shapes Gemini nests
|
|
16
|
+
* answers in: bare strings, `{content|text}` wrappers (assistant message
|
|
17
|
+
* objects), and arrays of `{type:"text",text}` content blocks (Gemini API
|
|
18
|
+
* `parts`-style lists). Depth-bounded: JSON.parse output is acyclic, but
|
|
19
|
+
* nesting is capped anyway so a pathological envelope cannot recurse
|
|
20
|
+
* unboundedly.
|
|
21
|
+
*/
|
|
22
|
+
function textOf(value, depth = 0) {
|
|
23
|
+
if (depth > 4)
|
|
24
|
+
return undefined;
|
|
25
|
+
if (typeof value === "string")
|
|
26
|
+
return value;
|
|
27
|
+
if (Array.isArray(value)) {
|
|
28
|
+
const parts = [];
|
|
29
|
+
for (const block of value) {
|
|
30
|
+
const t = textOf(block, depth + 1);
|
|
31
|
+
if (t)
|
|
32
|
+
parts.push(t);
|
|
33
|
+
}
|
|
34
|
+
return parts.length > 0 ? parts.join("\n") : undefined;
|
|
35
|
+
}
|
|
36
|
+
if (isRecord(value)) {
|
|
37
|
+
return textOf(value.content ?? value.text, depth + 1);
|
|
38
|
+
}
|
|
39
|
+
return undefined;
|
|
40
|
+
}
|
|
41
|
+
/** Extract the final-answer text from one parsed JSON value, if any. */
|
|
42
|
+
function extractText(value) {
|
|
43
|
+
if (typeof value === "string")
|
|
44
|
+
return value;
|
|
45
|
+
if (!isRecord(value))
|
|
46
|
+
return undefined;
|
|
47
|
+
for (const key of TEXT_KEYS) {
|
|
48
|
+
if (!(key in value))
|
|
49
|
+
continue;
|
|
50
|
+
const text = textOf(value[key]);
|
|
51
|
+
if (text !== undefined)
|
|
52
|
+
return text;
|
|
53
|
+
}
|
|
54
|
+
return undefined;
|
|
55
|
+
}
|
|
56
|
+
/** Extract a harness-native session id from one parsed JSON value, if any. */
|
|
57
|
+
function extractSessionId(value) {
|
|
58
|
+
if (!isRecord(value))
|
|
59
|
+
return undefined;
|
|
60
|
+
for (const key of SESSION_KEYS) {
|
|
61
|
+
const candidate = value[key];
|
|
62
|
+
if (typeof candidate === "string" && candidate.length > 0)
|
|
63
|
+
return candidate;
|
|
64
|
+
}
|
|
65
|
+
return undefined;
|
|
66
|
+
}
|
|
67
|
+
/** JSON.parse that returns undefined instead of throwing. */
|
|
68
|
+
function tryParseJson(raw) {
|
|
69
|
+
try {
|
|
70
|
+
return JSON.parse(raw);
|
|
71
|
+
}
|
|
72
|
+
catch {
|
|
73
|
+
return undefined;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Normalize a raw gemini run result into `{ text, sessionId? }`.
|
|
78
|
+
* See the module doc for the three stdout shapes handled.
|
|
79
|
+
*/
|
|
80
|
+
export const geminiResultExtractor = (result) => {
|
|
81
|
+
// The raw result's own sessionId (SDK-style paths) is the fallback; an id
|
|
82
|
+
// found in the output stream wins because it is fresher.
|
|
83
|
+
const fallbackSessionId = result.sessionId;
|
|
84
|
+
const raw = result.stdout.trim();
|
|
85
|
+
// Shape 1 — whole stdout is one JSON document (spawn may have pre-parsed
|
|
86
|
+
// it when the profile requested parseOutput: "json").
|
|
87
|
+
const whole = result.parsed !== undefined ? result.parsed : raw.length > 0 ? tryParseJson(raw) : undefined;
|
|
88
|
+
if (whole !== undefined) {
|
|
89
|
+
const sessionId = extractSessionId(whole) ?? fallbackSessionId;
|
|
90
|
+
// Unknown envelope (no recognized text key — includes the error-only
|
|
91
|
+
// variant): fall back to raw stdout so downstream embedded-JSON parsing
|
|
92
|
+
// and failure handling still have the full material to work with.
|
|
93
|
+
const text = extractText(whole) ?? raw;
|
|
94
|
+
return { text, ...(sessionId ? { sessionId } : {}) };
|
|
95
|
+
}
|
|
96
|
+
// Shape 2 — JSONL event stream: last text-bearing event wins; first
|
|
97
|
+
// session-id-bearing event supplies the id. Non-JSON lines are banner
|
|
98
|
+
// noise and are skipped.
|
|
99
|
+
let lastText;
|
|
100
|
+
let streamSessionId;
|
|
101
|
+
let sawJsonLine = false;
|
|
102
|
+
for (const line of raw.split("\n")) {
|
|
103
|
+
const trimmed = line.trim();
|
|
104
|
+
if (trimmed.length === 0)
|
|
105
|
+
continue;
|
|
106
|
+
const event = tryParseJson(trimmed);
|
|
107
|
+
if (event === undefined)
|
|
108
|
+
continue;
|
|
109
|
+
sawJsonLine = true;
|
|
110
|
+
streamSessionId ??= extractSessionId(event);
|
|
111
|
+
const text = extractText(event);
|
|
112
|
+
if (text !== undefined)
|
|
113
|
+
lastText = text;
|
|
114
|
+
}
|
|
115
|
+
if (sawJsonLine) {
|
|
116
|
+
const sessionId = streamSessionId ?? fallbackSessionId;
|
|
117
|
+
return { text: lastText ?? raw, ...(sessionId ? { sessionId } : {}) };
|
|
118
|
+
}
|
|
119
|
+
// Shape 3 — plain text passthrough.
|
|
120
|
+
return { text: raw, ...(fallbackSessionId ? { sessionId: fallbackSessionId } : {}) };
|
|
121
|
+
};
|
|
@@ -17,9 +17,22 @@
|
|
|
17
17
|
* harness in #563/#564; this step only owns ids + capability membership and
|
|
18
18
|
* wires the existing call sites to consult it (behaviour-preserving).
|
|
19
19
|
*/
|
|
20
|
+
import { AiderHarness } from "./aider/index.js";
|
|
21
|
+
import { AmazonqHarness } from "./amazonq/index.js";
|
|
20
22
|
import { ClaudeHarness } from "./claude/index.js";
|
|
23
|
+
import { CodexHarness } from "./codex/index.js";
|
|
24
|
+
import { CopilotHarness } from "./copilot/index.js";
|
|
25
|
+
import { GeminiHarness } from "./gemini/index.js";
|
|
21
26
|
import { OpencodeHarness } from "./opencode/index.js";
|
|
22
|
-
|
|
27
|
+
// Import the descriptor from its LEAF module, not the per-harness barrel: the
|
|
28
|
+
// barrel re-exports `./sdk-runner` (which imports `core/config`, and
|
|
29
|
+
// `core/config/config-types` derives `VALID_HARNESS_IDS` back from this file).
|
|
30
|
+
// Importing the class through the barrel would form an initialization cycle
|
|
31
|
+
// that throws a TDZ error when the barrel is the first module loaded in a fresh
|
|
32
|
+
// graph (see ./opencode-sdk/harness.ts). This keeps the registry a config-leaf.
|
|
33
|
+
import { OpencodeSdkHarness } from "./opencode-sdk/harness.js";
|
|
34
|
+
import { OpenhandsHarness } from "./openhands/index.js";
|
|
35
|
+
import { PiHarness } from "./pi/index.js";
|
|
23
36
|
// Each harness descriptor (ClaudeHarness, OpencodeHarness, OpencodeSdkHarness)
|
|
24
37
|
// lives in its own per-harness directory alongside that harness's session-log
|
|
25
38
|
// reader, agent builder, config importer, and/or SDK runner (#563/#564). They
|
|
@@ -33,13 +46,22 @@ import { OpencodeSdkHarness } from "./opencode-sdk/index.js";
|
|
|
33
46
|
* `z.enum(...)`, and the `platform` union all need the literal types.
|
|
34
47
|
*/
|
|
35
48
|
// Order is significant: VALID_HARNESS_IDS derives from this array and feeds the
|
|
36
|
-
// committed JSON-schema enum order.
|
|
37
|
-
//
|
|
38
|
-
//
|
|
49
|
+
// committed JSON-schema enum order. The original [opencode, claude,
|
|
50
|
+
// opencode-sdk] prefix is preserved so the pre-unification portion of the
|
|
51
|
+
// generated schema enum does not reorder (#562); the seven P2 harness adapters
|
|
52
|
+
// (plan §"Capability matrix") are appended after it, which extends the enum
|
|
53
|
+
// additively (schemas/akm-config.json is regenerated in lockstep).
|
|
39
54
|
export const HARNESS_REGISTRY = Object.freeze([
|
|
40
55
|
new OpencodeHarness(),
|
|
41
56
|
new ClaudeHarness(),
|
|
42
57
|
new OpencodeSdkHarness(),
|
|
58
|
+
new CodexHarness(),
|
|
59
|
+
new CopilotHarness(),
|
|
60
|
+
new PiHarness(),
|
|
61
|
+
new GeminiHarness(),
|
|
62
|
+
new AiderHarness(),
|
|
63
|
+
new AmazonqHarness(),
|
|
64
|
+
new OpenhandsHarness(),
|
|
43
65
|
]);
|
|
44
66
|
/** Lookup by canonical id. */
|
|
45
67
|
export const HARNESS_BY_ID = new Map(HARNESS_REGISTRY.map((h) => [h.id, h]));
|
|
@@ -60,9 +82,8 @@ const HARNESS_BY_ANY_ID = (() => {
|
|
|
60
82
|
})();
|
|
61
83
|
/**
|
|
62
84
|
* Canonical, ordered list of valid harness / platform ids. The Zod
|
|
63
|
-
* `AgentPlatformSchema` enum, the `
|
|
64
|
-
*
|
|
65
|
-
* union all derive from this so they cannot drift.
|
|
85
|
+
* `AgentPlatformSchema` enum, the `AgentProfileConfig` platform union, and
|
|
86
|
+
* setup's `DetectedHarness` union all derive from this so they cannot drift.
|
|
66
87
|
*/
|
|
67
88
|
export const VALID_HARNESS_IDS = Object.freeze(HARNESS_REGISTRY.map((h) => h.id));
|
|
68
89
|
/** Harnesses that expose readable native session logs. */
|
|
@@ -33,7 +33,7 @@ export const opencodeBuilder = {
|
|
|
33
33
|
args.push("--system-prompt", req.systemPrompt);
|
|
34
34
|
}
|
|
35
35
|
if (req.model) {
|
|
36
|
-
const resolved = resolveModel(req.model, "opencode", profile.modelAliases);
|
|
36
|
+
const resolved = resolveModel(req.model, "opencode", profile.modelAliases, profile.globalModelAliases);
|
|
37
37
|
args.push("--model", resolved);
|
|
38
38
|
}
|
|
39
39
|
args.push("--");
|
|
@@ -1,23 +1,9 @@
|
|
|
1
1
|
// This Source Code Form is subject to the terms of the Mozilla Public
|
|
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
|
-
/**
|
|
5
|
-
* OpenCode harness (#564).
|
|
6
|
-
*
|
|
7
|
-
* Per-harness barrel that gathers the OpenCode integration surfaces previously
|
|
8
|
-
* scattered across the codebase:
|
|
9
|
-
* - session-log reader → ./session-log.ts (OpenCodeProvider)
|
|
10
|
-
* - agent command builder → ./agent-builder.ts (opencodeBuilder)
|
|
11
|
-
* - config importer → ./config-import.ts (openCodeImporter)
|
|
12
|
-
*
|
|
13
|
-
* It also defines {@link OpencodeHarness}, the {@link AkmHarness} descriptor
|
|
14
|
-
* that `HARNESS_REGISTRY` registers.
|
|
15
|
-
*
|
|
16
|
-
* id normalization: OpenCode's canonical id (`'opencode'`) is also its runtime
|
|
17
|
-
* identity and session-log provider name — there is no historical split (unlike
|
|
18
|
-
* Claude Code's 'claude' vs 'claude-code'), so no alias bridge is needed.
|
|
19
|
-
*/
|
|
20
4
|
import { BaseHarness } from "../types.js";
|
|
5
|
+
import { opencodeBuilder } from "./agent-builder.js";
|
|
6
|
+
import { OpenCodeProvider } from "./session-log.js";
|
|
21
7
|
export { opencodeBuilder } from "./agent-builder.js";
|
|
22
8
|
export { openCodeImporter } from "./config-import.js";
|
|
23
9
|
export { OpenCodeProvider } from "./session-log.js";
|
|
@@ -48,6 +34,21 @@ export class OpencodeHarness extends BaseHarness {
|
|
|
48
34
|
// `v1ProfilePlatform()` resolves most-specific-id-first, so "opencode-sdk-*"
|
|
49
35
|
// is claimed by OpencodeSdkHarness before this prefix can over-match it.
|
|
50
36
|
v1ProfilePrefixes = ["opencode"];
|
|
37
|
+
agentBuilder = opencodeBuilder;
|
|
38
|
+
// ── Workflow-engine descriptor (plan §"Capability matrix", P2) ────────────
|
|
39
|
+
// This entry is the CLI spawn path (`opencode run …`): akm launches the
|
|
40
|
+
// harness locally per unit ⇒ local-runner. (The SDK path is the separate
|
|
41
|
+
// `opencode-sdk` harness.)
|
|
42
|
+
pattern = "local-runner";
|
|
43
|
+
// The CLI path emits plain text — no JSON stream akm consumes — so the
|
|
44
|
+
// engine uses the prompt-injected schema + embedded-JSON extraction tier
|
|
45
|
+
// (the matrix's "via prompt+validate"). The SDK entry is native-json.
|
|
46
|
+
structuredOutput = "none";
|
|
47
|
+
// `opencode run --session <id>` continues a previous session.
|
|
48
|
+
resume = { flag: "--session", takesSessionId: true };
|
|
49
|
+
// Session-id env marker for run attribution.
|
|
50
|
+
identityEnv = ["OPENCODE_SESSION_ID"];
|
|
51
|
+
sessionLogProvider = () => new OpenCodeProvider();
|
|
51
52
|
capabilities = caps({
|
|
52
53
|
sessionLogs: true,
|
|
53
54
|
agentDispatch: true,
|
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
import fs from "node:fs";
|
|
5
5
|
import os from "node:os";
|
|
6
6
|
import path from "node:path";
|
|
7
|
+
import { openDatabase } from "../../../storage/database.js";
|
|
7
8
|
import { extractInlineRefMentions } from "../../session-logs/inline-refs.js";
|
|
8
9
|
function getOpenCodeBaseDir() {
|
|
9
10
|
if (process.platform === "darwin") {
|
|
@@ -12,20 +13,49 @@ function getOpenCodeBaseDir() {
|
|
|
12
13
|
return path.join(os.homedir(), ".local", "share", "opencode");
|
|
13
14
|
}
|
|
14
15
|
/**
|
|
15
|
-
* Opencode storage
|
|
16
|
-
*
|
|
17
|
-
*
|
|
16
|
+
* Opencode storage layouts:
|
|
17
|
+
*
|
|
18
|
+
* SQLite (current, observed 2026-06): `<base>/opencode.db` — a Drizzle-managed
|
|
19
|
+
* database with `session` / `message` / `part` tables. Message text lives in
|
|
20
|
+
* `part` rows (`data` JSON, `type: "text"`); `message.data` holds role/timing.
|
|
21
|
+
* This is the layout current opencode builds write; it is preferred whenever
|
|
22
|
+
* `opencode.db` exists.
|
|
23
|
+
*
|
|
24
|
+
* JSON files (legacy, observed 2026-05): `<base>/storage/session/<projectId>/
|
|
25
|
+
* <sessionId>.json` (metadata) + `<base>/storage/message/<sessionId>/
|
|
26
|
+
* <messageId>.json` (one per message). Read only when `opencode.db` is absent.
|
|
18
27
|
*
|
|
19
28
|
* Older builds wrote logs directly into `<base>/log/` and `<base>/*.log`;
|
|
20
29
|
* those are still scanned by {@link OpenCodeProvider.readEvents} for
|
|
21
30
|
* backward compatibility with the existing failure-pattern aggregator.
|
|
22
31
|
*/
|
|
32
|
+
/** Filename of opencode's SQLite session store, relative to its base dir. */
|
|
33
|
+
const OPENCODE_DB_FILENAME = "opencode.db";
|
|
23
34
|
export class OpenCodeProvider {
|
|
24
35
|
name = "opencode";
|
|
25
36
|
#baseDir = getOpenCodeBaseDir();
|
|
26
37
|
isAvailable() {
|
|
27
38
|
return fs.existsSync(this.#baseDir);
|
|
28
39
|
}
|
|
40
|
+
/** Absolute path to opencode's SQLite store under `base`. */
|
|
41
|
+
#dbPath(base) {
|
|
42
|
+
return path.join(base, OPENCODE_DB_FILENAME);
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Directories/files opencode writes session data under. Returns the base dir
|
|
46
|
+
* when the SQLite store (`opencode.db`) exists, the legacy JSON session root
|
|
47
|
+
* (`<base>/storage/session`) when present, or both during a migration overlap.
|
|
48
|
+
* Empty when neither exists. See {@link SessionLogHarness.watchRoots}.
|
|
49
|
+
*/
|
|
50
|
+
watchRoots() {
|
|
51
|
+
const roots = [];
|
|
52
|
+
if (fs.existsSync(this.#dbPath(this.#baseDir)))
|
|
53
|
+
roots.push(this.#baseDir);
|
|
54
|
+
const sessionRoot = path.join(this.#baseDir, "storage", "session");
|
|
55
|
+
if (fs.existsSync(sessionRoot))
|
|
56
|
+
roots.push(sessionRoot);
|
|
57
|
+
return roots;
|
|
58
|
+
}
|
|
29
59
|
*readEvents(input) {
|
|
30
60
|
// Legacy behavior: stream raw log lines from the top-level dir and `log/`
|
|
31
61
|
// subdirectory. Kept to keep `getExecutionLogCandidates` working without
|
|
@@ -82,6 +112,9 @@ export class OpenCodeProvider {
|
|
|
82
112
|
listSessions(input = {}) {
|
|
83
113
|
const base = input.location ?? this.#baseDir;
|
|
84
114
|
const sinceMs = input.sinceMs ?? 0;
|
|
115
|
+
const dbPath = this.#dbPath(base);
|
|
116
|
+
if (fs.existsSync(dbPath))
|
|
117
|
+
return this.#listSessionsFromDb(dbPath, sinceMs);
|
|
85
118
|
const sessionRoot = path.join(base, "storage", "session");
|
|
86
119
|
if (!fs.existsSync(sessionRoot))
|
|
87
120
|
return [];
|
|
@@ -142,6 +175,8 @@ export class OpenCodeProvider {
|
|
|
142
175
|
return summaries.sort((a, b) => (b.endedAt ?? 0) - (a.endedAt ?? 0));
|
|
143
176
|
}
|
|
144
177
|
readSession(ref) {
|
|
178
|
+
if (path.basename(ref.filePath) === OPENCODE_DB_FILENAME)
|
|
179
|
+
return this.#readSessionFromDb(ref);
|
|
145
180
|
let meta = {};
|
|
146
181
|
try {
|
|
147
182
|
meta = JSON.parse(fs.readFileSync(ref.filePath, "utf8"));
|
|
@@ -199,6 +234,141 @@ export class OpenCodeProvider {
|
|
|
199
234
|
inlineRefs,
|
|
200
235
|
};
|
|
201
236
|
}
|
|
237
|
+
/**
|
|
238
|
+
* List sessions from the SQLite store. `filePath` on each summary is the
|
|
239
|
+
* `opencode.db` path so {@link readSession} can route back to the DB reader.
|
|
240
|
+
* Returns `[]` (never throws) when the DB is unreadable or lacks the expected
|
|
241
|
+
* schema — callers treat a missing harness as "no sessions".
|
|
242
|
+
*/
|
|
243
|
+
#listSessionsFromDb(dbPath, sinceMs) {
|
|
244
|
+
let db;
|
|
245
|
+
try {
|
|
246
|
+
db = openDatabase(dbPath, { readonly: true, create: false });
|
|
247
|
+
}
|
|
248
|
+
catch {
|
|
249
|
+
return [];
|
|
250
|
+
}
|
|
251
|
+
try {
|
|
252
|
+
const rows = db
|
|
253
|
+
.prepare("SELECT id, title, directory, time_created, time_updated FROM session WHERE time_updated >= ? ORDER BY time_updated DESC")
|
|
254
|
+
.all(sinceMs);
|
|
255
|
+
return rows.map((r) => {
|
|
256
|
+
const startedAt = typeof r.time_created === "number" ? r.time_created : undefined;
|
|
257
|
+
const endedAt = typeof r.time_updated === "number" ? r.time_updated : undefined;
|
|
258
|
+
const title = typeof r.title === "string" && r.title.length > 0 ? r.title : undefined;
|
|
259
|
+
const projectHint = typeof r.directory === "string" && r.directory.length > 0 ? r.directory : undefined;
|
|
260
|
+
return {
|
|
261
|
+
harness: this.name,
|
|
262
|
+
sessionId: r.id,
|
|
263
|
+
filePath: dbPath,
|
|
264
|
+
...(startedAt !== undefined ? { startedAt } : {}),
|
|
265
|
+
...(endedAt !== undefined ? { endedAt } : {}),
|
|
266
|
+
...(projectHint ? { projectHint } : {}),
|
|
267
|
+
...(title ? { title } : {}),
|
|
268
|
+
};
|
|
269
|
+
});
|
|
270
|
+
}
|
|
271
|
+
catch {
|
|
272
|
+
// Missing `session` table / unexpected schema — treat as no sessions.
|
|
273
|
+
return [];
|
|
274
|
+
}
|
|
275
|
+
finally {
|
|
276
|
+
db.close();
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
/**
|
|
280
|
+
* Read one session from the SQLite store. Message text lives in `part` rows
|
|
281
|
+
* (`type: "text"`); `message.data` carries role + timing. One event per
|
|
282
|
+
* message, text-parts concatenated in time order. Returns empty events
|
|
283
|
+
* (never throws) when the DB is unreadable.
|
|
284
|
+
*/
|
|
285
|
+
#readSessionFromDb(ref) {
|
|
286
|
+
const emptyRef = { harness: this.name, sessionId: ref.sessionId, filePath: ref.filePath };
|
|
287
|
+
let db;
|
|
288
|
+
try {
|
|
289
|
+
db = openDatabase(ref.filePath, { readonly: true, create: false });
|
|
290
|
+
}
|
|
291
|
+
catch {
|
|
292
|
+
return { ref: emptyRef, events: [], inlineRefs: [] };
|
|
293
|
+
}
|
|
294
|
+
try {
|
|
295
|
+
const meta = db
|
|
296
|
+
.prepare("SELECT title, directory, time_created, time_updated FROM session WHERE id = ?")
|
|
297
|
+
.get(ref.sessionId);
|
|
298
|
+
const startedAt = typeof meta?.time_created === "number" ? meta.time_created : undefined;
|
|
299
|
+
const endedAt = typeof meta?.time_updated === "number" ? meta.time_updated : undefined;
|
|
300
|
+
const title = typeof meta?.title === "string" && meta.title.length > 0 ? meta.title : undefined;
|
|
301
|
+
const projectHint = typeof meta?.directory === "string" && meta.directory.length > 0 ? meta.directory : undefined;
|
|
302
|
+
const messages = db
|
|
303
|
+
.prepare("SELECT id, data, time_created FROM message WHERE session_id = ? ORDER BY time_created ASC, id ASC")
|
|
304
|
+
.all(ref.sessionId);
|
|
305
|
+
const parts = db
|
|
306
|
+
.prepare("SELECT message_id, data FROM part WHERE session_id = ? ORDER BY time_created ASC, id ASC")
|
|
307
|
+
.all(ref.sessionId);
|
|
308
|
+
// Group text-part bodies by their parent message.
|
|
309
|
+
const textByMessage = new Map();
|
|
310
|
+
for (const part of parts) {
|
|
311
|
+
let parsed;
|
|
312
|
+
try {
|
|
313
|
+
parsed = JSON.parse(part.data);
|
|
314
|
+
}
|
|
315
|
+
catch {
|
|
316
|
+
continue;
|
|
317
|
+
}
|
|
318
|
+
if (parsed?.type !== "text")
|
|
319
|
+
continue;
|
|
320
|
+
const text = parsed.text;
|
|
321
|
+
if (typeof text !== "string" || text.length < 1)
|
|
322
|
+
continue;
|
|
323
|
+
const bucket = textByMessage.get(part.message_id) ?? [];
|
|
324
|
+
bucket.push(text);
|
|
325
|
+
textByMessage.set(part.message_id, bucket);
|
|
326
|
+
}
|
|
327
|
+
const events = [];
|
|
328
|
+
const inlineRefs = [];
|
|
329
|
+
for (const message of messages) {
|
|
330
|
+
let mdata = {};
|
|
331
|
+
try {
|
|
332
|
+
mdata = JSON.parse(message.data);
|
|
333
|
+
}
|
|
334
|
+
catch {
|
|
335
|
+
// role/timing unavailable — fall through with defaults
|
|
336
|
+
}
|
|
337
|
+
const role = typeof mdata.role === "string" ? mdata.role : "unknown";
|
|
338
|
+
const mtime = mdata.time?.created;
|
|
339
|
+
const ts = typeof mtime === "number"
|
|
340
|
+
? mtime
|
|
341
|
+
: typeof message.time_created === "number"
|
|
342
|
+
? message.time_created
|
|
343
|
+
: undefined;
|
|
344
|
+
const text = (textByMessage.get(message.id) ?? []).join("\n").trim();
|
|
345
|
+
if (text.length < 1)
|
|
346
|
+
continue;
|
|
347
|
+
events.push({ harness: this.name, text, ts, sessionId: ref.sessionId, role, filePath: ref.filePath });
|
|
348
|
+
inlineRefs.push(...extractInlineRefMentions(text, ts));
|
|
349
|
+
}
|
|
350
|
+
events.sort((a, b) => (a.ts ?? 0) - (b.ts ?? 0));
|
|
351
|
+
return {
|
|
352
|
+
ref: {
|
|
353
|
+
harness: this.name,
|
|
354
|
+
sessionId: ref.sessionId,
|
|
355
|
+
filePath: ref.filePath,
|
|
356
|
+
...(startedAt !== undefined ? { startedAt } : {}),
|
|
357
|
+
...(endedAt !== undefined ? { endedAt } : {}),
|
|
358
|
+
...(projectHint ? { projectHint } : {}),
|
|
359
|
+
...(title ? { title } : {}),
|
|
360
|
+
},
|
|
361
|
+
events,
|
|
362
|
+
inlineRefs,
|
|
363
|
+
};
|
|
364
|
+
}
|
|
365
|
+
catch {
|
|
366
|
+
return { ref: emptyRef, events: [], inlineRefs: [] };
|
|
367
|
+
}
|
|
368
|
+
finally {
|
|
369
|
+
db.close();
|
|
370
|
+
}
|
|
371
|
+
}
|
|
202
372
|
/**
|
|
203
373
|
* Derive opencode base dir from a session metadata file path so a caller
|
|
204
374
|
* passing a custom `--location` can still find the message dir.
|
|
@@ -0,0 +1,65 @@
|
|
|
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
|
+
* OpenCode SDK harness DESCRIPTOR (#564).
|
|
6
|
+
*
|
|
7
|
+
* This module is a dependency-graph LEAF: it imports only the harness base
|
|
8
|
+
* types (`../types`) and nothing from `core/config` or the SDK runner. Keeping
|
|
9
|
+
* the descriptor separate from the runtime runner (`./sdk-runner`, which pulls
|
|
10
|
+
* `core/config`) is load-bearing: `HARNESS_REGISTRY` in `../index.ts` imports
|
|
11
|
+
* this class from HERE, not from the per-harness barrel (`./index.ts`). The
|
|
12
|
+
* barrel additionally re-exports `runOpencodeSdk`/`closeServer` from
|
|
13
|
+
* `./sdk-runner`; that re-export makes the barrel transitively depend on
|
|
14
|
+
* `core/config`, and `core/config/config-types` derives `VALID_HARNESS_IDS`
|
|
15
|
+
* back from `../index.ts`. If the registry imported the class through the
|
|
16
|
+
* barrel, that cycle would evaluate `../index.ts` (and `new
|
|
17
|
+
* OpencodeSdkHarness()`) while the barrel — and hence this class binding — was
|
|
18
|
+
* still initializing, throwing a temporal-dead-zone "Cannot access
|
|
19
|
+
* 'OpencodeSdkHarness' before initialization" whenever the barrel is the first
|
|
20
|
+
* module loaded in a fresh graph (e.g. the workflow-exec subprocess entry).
|
|
21
|
+
* Importing the descriptor from this leaf keeps the registry a config-leaf and
|
|
22
|
+
* breaks the cycle.
|
|
23
|
+
*/
|
|
24
|
+
import { BaseHarness } from "../types.js";
|
|
25
|
+
function caps(c) {
|
|
26
|
+
return {
|
|
27
|
+
sessionLogs: false,
|
|
28
|
+
agentDispatch: false,
|
|
29
|
+
detection: false,
|
|
30
|
+
configImport: false,
|
|
31
|
+
runtimeIdentity: false,
|
|
32
|
+
v1Migration: false,
|
|
33
|
+
...c,
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* OpenCode SDK (embedded-SDK dispatch path).
|
|
38
|
+
*
|
|
39
|
+
* Dispatch-only: no native session logs, but detected at setup and migrated
|
|
40
|
+
* from v1 profile names.
|
|
41
|
+
*/
|
|
42
|
+
export class OpencodeSdkHarness extends BaseHarness {
|
|
43
|
+
id = "opencode-sdk";
|
|
44
|
+
displayName = "OpenCode SDK";
|
|
45
|
+
aliases = [];
|
|
46
|
+
// Decorated v1 profile names like "opencode-sdk-fast" belong to the SDK path.
|
|
47
|
+
v1ProfilePrefixes = ["opencode-sdk"];
|
|
48
|
+
// ── Workflow-engine descriptor (plan §"Capability matrix", P2) ────────────
|
|
49
|
+
// Embedded-SDK dispatch on this machine ⇒ local-runner (the matrix's
|
|
50
|
+
// "local (sdk/cli)" row, SDK half).
|
|
51
|
+
pattern = "local-runner";
|
|
52
|
+
// `session.prompt` returns structured SDK events/messages; akm extracts the
|
|
53
|
+
// final message then validates against the node schema ⇒ native-json tier.
|
|
54
|
+
structuredOutput = "native-json";
|
|
55
|
+
// No `resume` flag: session reuse is programmatic — the SDK session id is
|
|
56
|
+
// stored opportunistically on the unit row and passed back to
|
|
57
|
+
// `session.prompt`, not replayed via a CLI flag.
|
|
58
|
+
// No `identityEnv`: the SDK runs in-process; it does not mark a child
|
|
59
|
+
// process environment with a session id of its own.
|
|
60
|
+
capabilities = caps({
|
|
61
|
+
agentDispatch: true,
|
|
62
|
+
detection: true,
|
|
63
|
+
v1Migration: true,
|
|
64
|
+
});
|
|
65
|
+
}
|
|
@@ -5,10 +5,15 @@
|
|
|
5
5
|
* OpenCode SDK harness (#564).
|
|
6
6
|
*
|
|
7
7
|
* Per-harness barrel for the SDK-mode dispatch path:
|
|
8
|
-
* -
|
|
8
|
+
* - descriptor → ./harness.ts ({@link OpencodeSdkHarness}, the
|
|
9
|
+
* {@link AkmHarness} that `HARNESS_REGISTRY` registers)
|
|
10
|
+
* - agent runner → ./sdk-runner.ts (runOpencodeSdk)
|
|
9
11
|
*
|
|
10
|
-
*
|
|
11
|
-
* that
|
|
12
|
+
* The descriptor lives in its own leaf module (`./harness.ts`) rather than
|
|
13
|
+
* here so that the registry can import the class WITHOUT pulling in
|
|
14
|
+
* `./sdk-runner` (and its `core/config` dependency) — see the header of
|
|
15
|
+
* `./harness.ts` for the temporal-dead-zone cycle this avoids. This barrel is
|
|
16
|
+
* the runtime entry point that re-exports both.
|
|
12
17
|
*
|
|
13
18
|
* Unlike the CLI harnesses, the SDK path has no native session logs of its own
|
|
14
19
|
* (`capabilities.sessionLogs = false`): it dispatches via the embedded
|
|
@@ -16,34 +21,5 @@
|
|
|
16
21
|
* session files. It is still detected at setup and migrated from v1 profile
|
|
17
22
|
* names. Canonical id is `'opencode-sdk'` with no alias.
|
|
18
23
|
*/
|
|
19
|
-
|
|
20
|
-
export { closeServer,
|
|
21
|
-
function caps(c) {
|
|
22
|
-
return {
|
|
23
|
-
sessionLogs: false,
|
|
24
|
-
agentDispatch: false,
|
|
25
|
-
detection: false,
|
|
26
|
-
configImport: false,
|
|
27
|
-
runtimeIdentity: false,
|
|
28
|
-
v1Migration: false,
|
|
29
|
-
...c,
|
|
30
|
-
};
|
|
31
|
-
}
|
|
32
|
-
/**
|
|
33
|
-
* OpenCode SDK (embedded-SDK dispatch path).
|
|
34
|
-
*
|
|
35
|
-
* Dispatch-only: no native session logs, but detected at setup and migrated
|
|
36
|
-
* from v1 profile names.
|
|
37
|
-
*/
|
|
38
|
-
export class OpencodeSdkHarness extends BaseHarness {
|
|
39
|
-
id = "opencode-sdk";
|
|
40
|
-
displayName = "OpenCode SDK";
|
|
41
|
-
aliases = [];
|
|
42
|
-
// Decorated v1 profile names like "opencode-sdk-fast" belong to the SDK path.
|
|
43
|
-
v1ProfilePrefixes = ["opencode-sdk"];
|
|
44
|
-
capabilities = caps({
|
|
45
|
-
agentDispatch: true,
|
|
46
|
-
detection: true,
|
|
47
|
-
v1Migration: true,
|
|
48
|
-
});
|
|
49
|
-
}
|
|
24
|
+
export { OpencodeSdkHarness } from "./harness.js";
|
|
25
|
+
export { closeServer, runOpencodeSdk } from "./sdk-runner.js";
|