akm-cli 0.9.0-rc.0 → 0.9.0-rc.13
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 +1283 -22
- package/README.md +62 -37
- package/SECURITY.md +46 -31
- package/dist/akm +162 -38
- package/dist/akm-migrate +44 -0
- package/dist/assets/backends/schtasks-template.xml +2 -1
- package/dist/assets/hints/cli-hints-full.md +268 -118
- package/dist/assets/hints/cli-hints-short.md +87 -24
- package/dist/assets/{profiles → improve-strategies}/catchup.json +3 -1
- package/dist/assets/{profiles → improve-strategies}/consolidate.json +3 -1
- package/dist/assets/{profiles → improve-strategies}/default.json +6 -7
- package/dist/assets/improve-strategies/frequent.json +15 -0
- package/dist/assets/{profiles → improve-strategies}/graph-refresh.json +4 -2
- package/dist/assets/{profiles → improve-strategies}/memory-focus.json +4 -1
- package/dist/assets/{profiles → improve-strategies}/proactive-maintenance.json +5 -5
- package/dist/assets/{profiles → improve-strategies}/quick.json +4 -2
- package/dist/assets/improve-strategies/reflect-distill.json +30 -0
- package/dist/assets/{profiles → improve-strategies}/thorough.json +1 -1
- package/dist/assets/prompts/consolidate-system.md +5 -5
- package/dist/assets/prompts/extract-session.md +2 -6
- package/dist/assets/prompts/memory-infer-user.md +2 -3
- package/dist/assets/prompts/reflect-llm-framed-contract.md +11 -0
- package/dist/assets/prompts/reflect-llm-schema-contract.md +3 -0
- package/dist/assets/prompts/reflect-output-repair.md +3 -0
- package/dist/assets/prompts/workflow-unit-preamble.md +26 -0
- package/dist/assets/stash-skeleton/README.md +38 -10
- package/dist/assets/stash-skeleton/facts/conventions/assets/agent.md +8 -0
- package/dist/assets/stash-skeleton/facts/conventions/assets/command.md +8 -0
- package/dist/assets/stash-skeleton/facts/conventions/assets/fact.md +14 -1
- package/dist/assets/stash-skeleton/facts/conventions/assets/knowledge.md +13 -1
- package/dist/assets/stash-skeleton/facts/conventions/assets/lesson.md +9 -1
- package/dist/assets/stash-skeleton/facts/conventions/assets/memory.md +11 -0
- package/dist/assets/stash-skeleton/facts/conventions/assets/script.md +9 -0
- package/dist/assets/stash-skeleton/facts/conventions/assets/skill.md +9 -0
- package/dist/assets/stash-skeleton/facts/conventions/assets/workflow.md +8 -0
- package/dist/assets/stash-skeleton/facts/conventions/backlinks.md +100 -0
- package/dist/assets/stash-skeleton/facts/conventions/domains.md +64 -0
- package/dist/assets/stash-skeleton/facts/conventions/organization.md +136 -0
- package/dist/assets/tasks/core/extract.yml +3 -2
- package/dist/assets/tasks/core/improve.yml +2 -1
- package/dist/assets/tasks/core/index-refresh.yml +1 -0
- package/dist/assets/tasks/core/sync.yml +1 -0
- package/dist/assets/tasks/core/version-check.yml +2 -1
- package/dist/assets/tasks/improve/akm-graph-refresh-weekly.yml +5 -0
- package/dist/assets/tasks/improve/akm-improve-catchup.yml +8 -0
- package/dist/assets/tasks/improve/akm-improve-consolidate.yml +5 -0
- package/dist/assets/tasks/improve/akm-improve-frequent.yml +5 -0
- package/dist/assets/tasks/improve/akm-improve-nightly.yml +5 -0
- package/dist/assets/templates/html/health.html +5 -4
- package/dist/assets/workflows/workflow-template.md +31 -15
- package/dist/cli/invocation.js +279 -0
- package/dist/cli/parse-args.js +5 -90
- package/dist/cli/retired-commands.js +78 -0
- package/dist/cli/shared.js +158 -48
- package/dist/cli-node.mjs +2 -1
- package/dist/cli.js +747 -293
- package/dist/commands/agent/agent-dispatch.js +19 -18
- package/dist/commands/agent/agent-support.js +0 -24
- package/dist/commands/agent/contribute-cli.js +43 -97
- package/dist/commands/completions.js +80 -23
- package/dist/commands/config-cli.js +44 -281
- package/dist/commands/env/env-binding.js +99 -0
- package/dist/commands/env/env-cli.js +84 -224
- package/dist/commands/env/env.js +12 -163
- package/dist/commands/env/marker-path.js +6 -0
- package/dist/commands/env/secret-cli.js +45 -61
- package/dist/commands/env/secret.js +32 -62
- package/dist/commands/feedback-cli.js +179 -85
- package/dist/commands/health/accept-rate.js +58 -0
- package/dist/commands/health/advisories.js +7 -8
- package/dist/commands/health/checks.js +279 -94
- package/dist/commands/health/html-report.js +197 -578
- package/dist/commands/health/improve-metrics.js +277 -246
- package/dist/commands/health/llm-usage.js +19 -19
- package/dist/commands/health/md-report.js +16 -7
- package/dist/commands/health/metrics.js +67 -32
- package/dist/commands/health/renderers.js +47 -0
- package/dist/commands/health/report-view-model.js +508 -0
- package/dist/commands/health/stash-exposure.js +1 -1
- package/dist/commands/health/surfaces.js +16 -56
- package/dist/commands/health/task-runs.js +3 -67
- package/dist/{migrate-storage-node.mjs → commands/health/types-checks.js} +1 -5
- package/dist/commands/health/types-improve.js +29 -0
- package/dist/{output/text/save.js → commands/health/types-metrics.js} +1 -2
- package/dist/commands/health/types-result.js +7 -0
- package/dist/commands/health/types-runs.js +4 -0
- package/dist/commands/health/types-session-log.js +4 -0
- package/dist/commands/health/types-windows.js +4 -0
- package/dist/commands/health/types.js +26 -21
- package/dist/commands/health/windows.js +2 -3
- package/dist/commands/health.js +296 -167
- package/dist/commands/improve/anti-collapse.js +5 -5
- package/dist/commands/improve/autonomy-gate.js +68 -0
- package/dist/commands/improve/collapse-detector.js +65 -52
- package/dist/commands/improve/consolidate/chunking.js +9 -7
- package/dist/commands/improve/consolidate/eligibility.js +1 -23
- package/dist/commands/improve/consolidate/merge.js +4 -0
- package/dist/commands/improve/consolidate.js +454 -1354
- package/dist/commands/improve/content-hash.js +39 -0
- package/dist/commands/improve/distill/content-repair.js +4 -10
- package/dist/commands/improve/distill/promote-memory.js +89 -64
- package/dist/commands/improve/distill/quality-gate.js +118 -42
- package/dist/commands/improve/distill-guards.js +1 -1
- package/dist/commands/improve/distill-promotion-policy.js +33 -888
- package/dist/commands/improve/distill.js +607 -363
- package/dist/commands/improve/eligibility.js +165 -79
- package/dist/commands/improve/extract-cli.js +35 -126
- package/dist/commands/improve/extract-prompt.js +6 -35
- package/dist/commands/improve/extract.js +640 -391
- package/dist/commands/improve/feedback-valence.js +2 -12
- package/dist/commands/improve/improve-cli.js +134 -135
- package/dist/commands/improve/improve-result-file.js +30 -50
- package/dist/commands/improve/improve-run-types.js +4 -0
- package/dist/commands/improve/improve-strategies.js +135 -0
- package/dist/commands/improve/improve.js +904 -701
- package/dist/commands/improve/locks.js +64 -111
- package/dist/commands/improve/loop-stages.js +1110 -923
- package/dist/commands/improve/memory/derived-ref.js +124 -0
- package/dist/commands/improve/memory/memory-belief.js +79 -7
- package/dist/commands/improve/memory/memory-contradiction-detect.js +49 -52
- package/dist/commands/improve/memory/memory-improve.js +25 -37
- package/dist/commands/improve/outcome-loop.js +25 -88
- package/dist/commands/improve/preparation.js +1034 -813
- package/dist/commands/improve/proactive-maintenance.js +34 -9
- package/dist/commands/improve/proposal-envelope.js +31 -0
- package/dist/commands/improve/reflect.js +983 -794
- package/dist/commands/improve/run-context.js +119 -0
- package/dist/commands/improve/salience.js +24 -127
- package/dist/commands/improve/session-asset.js +7 -3
- package/dist/commands/improve/shared.js +14 -34
- package/dist/commands/improve/source-identity.js +28 -0
- package/dist/commands/improve/triage.js +20 -17
- package/dist/commands/lint/base-linter.js +340 -313
- package/dist/commands/lint/env-key-rules.js +31 -47
- package/dist/commands/lint/index.js +185 -30
- package/dist/commands/{events.js → log.js} +28 -38
- package/dist/commands/migrate-cli.js +54 -0
- package/dist/commands/migration-tool.js +55 -0
- package/dist/commands/observability-cli.js +70 -208
- package/dist/commands/proposal/diff-format.js +50 -0
- package/dist/commands/proposal/drain-policies.js +0 -6
- package/dist/commands/proposal/drain.js +91 -40
- package/dist/commands/proposal/proposal-cli.js +134 -132
- package/dist/commands/proposal/proposal-types.js +56 -0
- package/dist/commands/proposal/proposal.js +83 -65
- package/dist/commands/proposal/propose-cli.js +88 -0
- package/dist/commands/proposal/propose.js +105 -88
- package/dist/commands/proposal/repository.js +1303 -278
- package/dist/commands/proposal/validators/proposal-quality-validators.js +16 -6
- package/dist/commands/proposal/validators/proposal-validators.js +61 -12
- package/dist/commands/proposal/validators/proposals.js +6 -8
- package/dist/commands/read/curate.js +78 -73
- package/dist/commands/read/knowledge.js +510 -13
- package/dist/commands/read/registry-search.js +2 -2
- package/dist/commands/read/remember-cli.js +84 -15
- package/dist/commands/read/search-cli.js +203 -96
- package/dist/commands/read/search.js +126 -94
- package/dist/commands/read/show.js +226 -250
- package/dist/commands/registry-cli.js +34 -60
- package/dist/commands/remember.js +18 -57
- package/dist/commands/sources/add-cli.js +104 -49
- package/dist/commands/sources/bundle-cli.js +166 -0
- package/dist/commands/sources/bundle-config-ops.js +63 -0
- package/dist/commands/sources/info.js +27 -15
- package/dist/commands/sources/init.js +30 -40
- package/dist/commands/sources/installed-stashes.js +469 -172
- package/dist/commands/sources/migration-help.js +7 -4
- package/dist/commands/sources/schema-repair.js +10 -9
- package/dist/commands/sources/self-update.js +182 -121
- package/dist/commands/sources/source-add.js +169 -178
- package/dist/commands/sources/source-clone.js +144 -41
- package/dist/commands/sources/source-manage.js +94 -59
- package/dist/commands/sources/sources-cli.js +64 -205
- package/dist/commands/sources/stash-cli.js +91 -54
- package/dist/commands/sources/stash-skeleton.js +1 -1
- package/dist/commands/tasks/tasks-cli.js +106 -104
- package/dist/commands/tasks/tasks.js +445 -262
- package/dist/commands/workflow-cli.js +232 -121
- package/dist/core/action-contributors.js +1 -1
- package/dist/core/activation-policy.js +49 -0
- package/dist/core/adapter/adapters/agent-skills-adapter.js +181 -0
- package/dist/core/adapter/adapters/akm-adapter.js +528 -0
- package/dist/core/adapter/adapters/akm-lint.js +392 -0
- package/dist/core/adapter/adapters/akm-metadata.js +387 -0
- package/dist/core/adapter/adapters/akm-task-adapter.js +149 -0
- package/dist/core/adapter/adapters/akm-workflow-adapter.js +180 -0
- package/dist/core/adapter/adapters/claude-adapter.js +61 -0
- package/dist/core/adapter/adapters/dotenv-adapter.js +187 -0
- package/dist/core/adapter/adapters/generic-files-adapter.js +119 -0
- package/dist/core/adapter/adapters/index.js +80 -0
- package/dist/core/adapter/adapters/llm-wiki-adapter.js +419 -0
- package/dist/core/adapter/adapters/okf-adapter.js +391 -0
- package/dist/core/adapter/adapters/opencode-adapter.js +68 -0
- package/dist/core/adapter/adapters/shared.js +286 -0
- package/dist/core/adapter/adapters/tool-dir-shared.js +217 -0
- package/dist/core/adapter/adapters/website-snapshot-adapter.js +155 -0
- package/dist/core/adapter/bundle-adapter.js +4 -0
- package/dist/core/adapter/detect-adapter.js +17 -0
- package/dist/core/adapter/recognize-match.js +44 -0
- package/dist/core/adapter/registry.js +56 -0
- package/dist/core/adapter/types.js +4 -0
- package/dist/core/asset/akm-markdown.js +30 -0
- package/dist/core/asset/asset-placement.js +243 -0
- package/dist/core/asset/asset-ref.js +110 -79
- package/dist/core/asset/asset-serialize.js +20 -0
- package/dist/core/asset/frontmatter.js +28 -12
- package/dist/core/asset/markdown.js +40 -51
- package/dist/core/asset/resolve-ref.js +274 -0
- package/dist/core/asset/stash-meta.js +2 -2
- package/dist/core/bundle-id.js +51 -0
- package/dist/core/common.js +281 -86
- package/dist/core/config/config-io.js +42 -128
- package/dist/core/config/config-schema.js +233 -834
- package/dist/core/config/config-sources.js +162 -39
- package/dist/core/config/config-types.js +16 -11
- package/dist/core/config/config-version.js +29 -0
- package/dist/core/config/config-walker.js +126 -37
- package/dist/core/config/config.js +154 -331
- package/dist/core/config/deep-merge.js +41 -0
- package/dist/core/config/engine-semantics.js +28 -0
- package/dist/core/config/experimental.js +21 -0
- package/dist/core/config/schema/embedding.js +38 -0
- package/dist/core/config/schema/engines.js +116 -0
- package/dist/core/config/schema/experimental.js +47 -0
- package/dist/core/config/schema/feedback.js +31 -0
- package/dist/core/config/schema/improve-processes.js +389 -0
- package/dist/core/config/schema/improve.js +94 -0
- package/dist/core/config/schema/index-config.js +176 -0
- package/dist/core/config/schema/output.js +18 -0
- package/dist/core/config/schema/primitives.js +94 -0
- package/dist/core/config/schema/search.js +30 -0
- package/dist/core/config/schema/setup.js +18 -0
- package/dist/core/config/schema/sources-bundles.js +169 -0
- package/dist/core/config/schema/workflow.js +29 -0
- package/dist/core/env-secret-ref.js +155 -20
- package/dist/core/errors.js +17 -15
- package/dist/core/events-types.js +4 -0
- package/dist/core/events.js +46 -128
- package/dist/core/extra-params.js +62 -0
- package/dist/core/file-change.js +17 -0
- package/dist/core/file-lock.js +202 -57
- package/dist/core/fs-txn.js +392 -0
- package/dist/core/git-message.js +59 -0
- package/dist/core/improve-result.js +167 -0
- package/dist/core/json-schema.js +142 -0
- package/dist/core/lesson-lint.js +1 -17
- package/dist/core/logs-db.js +1 -1
- package/dist/core/maintenance-barrier.js +135 -0
- package/dist/core/migration-operation.js +44 -0
- package/dist/core/mutation-target.js +78 -0
- package/dist/core/paths.js +22 -25
- package/dist/core/platform.js +10 -0
- package/dist/core/recognition-util.js +128 -0
- package/dist/core/redaction.js +392 -0
- package/dist/core/standards/resolve-standards-context.js +36 -65
- package/dist/core/standards/resolve-stash-standards.js +2 -2
- package/dist/core/standards/resolve-type-conventions.js +5 -5
- package/dist/core/state/migrations.js +242 -11
- package/dist/core/state-db.js +98 -10
- package/dist/core/structured.js +1 -1
- package/dist/core/subprocess.js +303 -0
- package/dist/core/text-truncation.js +9 -5
- package/dist/core/time.js +20 -0
- package/dist/core/type-presentation.js +130 -0
- package/dist/core/warn.js +0 -3
- package/dist/core/write-source.js +834 -118
- package/dist/indexer/bundle-identity-guard.js +92 -0
- package/dist/indexer/db/graph-db.js +1 -25
- package/dist/indexer/db/llm-cache.js +1 -1
- package/dist/indexer/ensure-index.js +30 -9
- package/dist/indexer/graph/graph-boost.js +9 -30
- package/dist/indexer/graph/graph-extraction.js +41 -27
- package/dist/indexer/graph/graph-types.js +4 -0
- package/dist/indexer/index-writer-lock.js +93 -49
- package/dist/indexer/index-written-assets.js +100 -53
- package/dist/indexer/indexer.js +746 -329
- package/dist/indexer/init.js +18 -25
- package/dist/indexer/installations.js +142 -0
- package/dist/indexer/passes/dir-staleness.js +18 -10
- package/dist/indexer/passes/memory-inference.js +25 -15
- package/dist/indexer/passes/metadata.js +412 -243
- package/dist/indexer/scan/doc-to-entry.js +160 -0
- package/dist/indexer/scan/drain-dir.js +134 -0
- package/dist/indexer/search/db-search.js +292 -108
- package/dist/indexer/search/fts-query.js +64 -0
- package/dist/indexer/search/ranking-contributors.js +145 -25
- package/dist/indexer/search/ranking-types.js +4 -0
- package/dist/indexer/search/ranking.js +28 -71
- package/dist/indexer/search/search-attribution.js +67 -0
- package/dist/indexer/search/search-fields.js +18 -3
- package/dist/indexer/search/search-hit-enrichers.js +30 -40
- package/dist/indexer/search/search-source.js +157 -111
- package/dist/indexer/search/semantic-status.js +4 -1
- package/dist/indexer/usage/usage-events.js +10 -30
- package/dist/indexer/walk/file-context.js +3 -45
- package/dist/indexer/walk/matchers.js +42 -34
- package/dist/indexer/walk/path-resolver.js +11 -5
- package/dist/indexer/walk/walker.js +42 -14
- package/dist/integrations/agent/builder-shared.js +7 -0
- package/dist/integrations/agent/builders.js +5 -56
- package/dist/integrations/agent/config.js +3 -143
- package/dist/integrations/agent/detect.js +17 -2
- package/dist/integrations/agent/engine-resolution.js +231 -0
- package/dist/integrations/agent/index.js +1 -2
- package/dist/integrations/agent/model-aliases.js +16 -2
- package/dist/integrations/agent/profiles.js +36 -62
- package/dist/integrations/agent/prompts.js +46 -18
- package/dist/integrations/agent/runner-dispatch.js +93 -4
- package/dist/integrations/agent/runner.js +76 -208
- package/dist/integrations/agent/spawn.js +88 -196
- package/dist/integrations/harnesses/aider/agent-builder.js +114 -0
- package/dist/integrations/harnesses/aider/index.js +48 -0
- package/dist/integrations/harnesses/aider/result-extractor.js +53 -0
- package/dist/integrations/harnesses/amazonq/agent-builder.js +147 -0
- package/dist/integrations/harnesses/amazonq/index.js +45 -0
- package/dist/integrations/harnesses/amazonq/result-extractor.js +48 -0
- package/dist/integrations/harnesses/claude/agent-builder.js +46 -8
- package/dist/integrations/harnesses/claude/config-import.js +1 -3
- package/dist/integrations/harnesses/claude/index.js +24 -35
- package/dist/integrations/harnesses/claude/result-extractor.js +52 -0
- package/dist/integrations/harnesses/claude/session-log.js +27 -75
- package/dist/integrations/harnesses/codex/agent-builder.js +138 -0
- package/dist/integrations/harnesses/codex/index.js +52 -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 +48 -0
- package/dist/integrations/harnesses/copilot/result-extractor.js +151 -0
- package/dist/integrations/harnesses/gemini/agent-builder.js +120 -0
- package/dist/integrations/harnesses/gemini/index.js +48 -0
- package/dist/integrations/harnesses/gemini/result-extractor.js +121 -0
- package/dist/integrations/harnesses/ids.js +24 -0
- package/dist/integrations/harnesses/index.js +54 -34
- package/dist/integrations/harnesses/opencode/agent-builder.js +23 -5
- package/dist/integrations/harnesses/opencode/config-import.js +1 -3
- package/dist/integrations/harnesses/opencode/index.js +14 -32
- package/dist/integrations/harnesses/opencode/session-log.js +67 -125
- package/dist/integrations/harnesses/opencode-sdk/harness.js +51 -0
- package/dist/integrations/harnesses/opencode-sdk/sdk-runner.js +681 -108
- package/dist/integrations/harnesses/openhands/agent-builder.js +128 -0
- package/dist/integrations/harnesses/openhands/index.js +48 -0
- package/dist/integrations/harnesses/openhands/result-extractor.js +103 -0
- package/dist/integrations/harnesses/pi/agent-builder.js +97 -0
- package/dist/integrations/harnesses/pi/index.js +45 -0
- package/dist/integrations/harnesses/pi/result-extractor.js +135 -0
- package/dist/integrations/harnesses/shared.js +17 -0
- package/dist/integrations/harnesses/types.js +43 -32
- package/dist/integrations/lockfile.js +211 -24
- package/dist/integrations/session-logs/index.js +36 -39
- package/dist/integrations/session-logs/provider-base.js +113 -0
- package/dist/llm/client.js +182 -110
- package/dist/llm/embedders/deterministic.js +2 -2
- package/dist/llm/embedders/remote.js +21 -9
- package/dist/llm/feature-gate.js +17 -57
- package/dist/llm/graph-extract.js +12 -13
- package/dist/llm/index-passes.js +8 -42
- package/dist/llm/memory-infer.js +144 -1
- package/dist/llm/metadata-enhance.js +45 -30
- package/dist/llm/structured-call.js +16 -8
- package/dist/llm/usage-persist.js +30 -5
- package/dist/llm/usage-telemetry.js +59 -6
- package/dist/output/cli-hints.js +1 -2
- package/dist/output/command-registry.js +27 -0
- package/dist/output/context.js +22 -7
- package/dist/output/format-exempt.js +80 -0
- package/dist/output/generic-render.js +251 -0
- package/dist/output/html-render.js +11 -16
- package/dist/output/render-registry.js +57 -0
- package/dist/output/renderers.js +14 -279
- package/dist/output/shapes/curate.js +10 -1
- package/dist/output/shapes/events.js +12 -7
- package/dist/output/shapes/helpers.js +58 -84
- package/dist/output/shapes/passthrough.js +11 -39
- package/dist/output/shapes/proposal/producer.js +15 -7
- package/dist/output/shapes/registry.js +12 -6
- package/dist/output/shapes.js +0 -9
- package/dist/output/text/{init.js → bundle-create.js} +3 -1
- package/dist/output/text/bundle-show.js +7 -0
- package/dist/output/text/command-format.js +562 -0
- package/dist/output/text/env.js +1 -3
- package/dist/output/text/events.js +8 -7
- package/dist/output/text/helpers.js +15 -1164
- package/dist/output/text/proposal/producer.js +4 -2
- package/dist/output/text/proposal-format.js +202 -0
- package/dist/output/text/registry-commands.js +1 -2
- package/dist/output/text/registry.js +12 -6
- package/dist/output/text/show-directives.js +117 -0
- package/dist/output/text/show-format.js +103 -0
- package/dist/output/text/sync.js +5 -0
- package/dist/output/text/workflow-format.js +332 -0
- package/dist/output/text/workflow.js +3 -2
- package/dist/output/text.js +10 -19
- package/dist/registry/factory.js +4 -6
- package/dist/registry/origin-resolve.js +16 -27
- package/dist/registry/providers/skills-sh.js +3 -3
- package/dist/registry/providers/static-index.js +15 -25
- package/dist/registry/resolve.js +43 -94
- package/dist/registry/semver.js +43 -0
- package/dist/runtime.js +81 -12
- package/dist/scripts/akm-migrate.js +35529 -0
- package/dist/setup/detect.js +5 -7
- package/dist/setup/detected-engines.js +136 -0
- package/dist/setup/engine-config.js +100 -0
- package/dist/setup/registry-stash-loader.js +3 -3
- package/dist/setup/semantic-assets.js +12 -9
- package/dist/setup/setup.js +444 -208
- package/dist/setup/steps/connection-shared.js +120 -0
- package/dist/setup/steps/connection.js +108 -305
- package/dist/setup/steps/platforms.js +13 -12
- package/dist/setup/steps/semantic.js +15 -3
- package/dist/setup/steps/sources.js +21 -15
- package/dist/setup/steps/stashdir.js +6 -4
- package/dist/setup/steps/tasks.js +236 -119
- package/dist/setup/steps.js +3 -2
- package/dist/sources/freshness.js +39 -0
- package/dist/sources/provider-factory.js +11 -17
- package/dist/sources/providers/filesystem.js +2 -3
- package/dist/sources/providers/git-install.js +278 -34
- package/dist/sources/providers/git-provider.js +54 -56
- package/dist/sources/providers/git-stash.js +420 -91
- package/dist/sources/providers/git.js +2 -2
- package/dist/sources/providers/npm.js +16 -19
- package/dist/sources/providers/provider-utils.js +47 -22
- package/dist/sources/providers/sync-from-ref.js +3 -9
- package/dist/sources/providers/website.js +2 -2
- package/dist/sources/resolve.js +11 -10
- package/dist/sources/snapshot-fetchers/types.js +4 -0
- package/dist/sources/{website-ingest.js → snapshot-fetchers/website-ingest.js} +110 -41
- package/dist/storage/database.js +60 -4
- package/dist/storage/engines/sqlite-migrations.js +156 -5
- package/dist/storage/locations.js +1 -2
- package/dist/storage/repositories/canaries-repository.js +1 -1
- package/dist/storage/repositories/events-repository.js +51 -11
- package/dist/storage/repositories/improve-runs-repository.js +6 -32
- package/dist/storage/repositories/index-connection.js +79 -0
- package/dist/storage/repositories/index-db.js +4 -3
- package/dist/storage/repositories/index-entries-repository.js +863 -0
- package/dist/{indexer/db/entry-mapper.js → storage/repositories/index-entry-mapper.js} +19 -2
- package/dist/storage/repositories/index-entry-types.js +4 -0
- package/dist/storage/repositories/index-fts-repository.js +167 -0
- package/dist/storage/repositories/index-llm-cache-repository.js +108 -0
- package/dist/storage/repositories/index-meta-repository.js +49 -0
- package/dist/{indexer/db/schema.js → storage/repositories/index-schema.js} +226 -100
- package/dist/storage/repositories/index-sql.js +12 -0
- package/dist/storage/repositories/index-utility-repository.js +356 -0
- package/dist/storage/repositories/index-vec-repository.js +250 -0
- package/dist/storage/repositories/outcome-repository.js +119 -0
- package/dist/storage/repositories/proposals-repository.js +317 -75
- package/dist/storage/repositories/registry-cache.js +1 -1
- package/dist/storage/repositories/salience-repository.js +172 -0
- package/dist/storage/repositories/task-history-repository.js +110 -3
- package/dist/storage/repositories/workflow-runs-repository.js +240 -19
- package/dist/tasks/backends/cron.js +169 -46
- package/dist/tasks/backends/exec-utils.js +76 -3
- package/dist/tasks/backends/index.js +6 -9
- package/dist/tasks/backends/launchd.js +292 -55
- package/dist/tasks/backends/schtasks.js +557 -70
- package/dist/tasks/backends/types.js +4 -0
- package/dist/tasks/command-executable.js +93 -0
- package/dist/tasks/embedded.js +56 -38
- package/dist/tasks/parser.js +156 -64
- package/dist/tasks/resolve-akm-bin.js +144 -51
- package/dist/tasks/runner.js +377 -209
- package/dist/tasks/schedule.js +108 -19
- package/dist/tasks/scheduler-invocation.js +296 -0
- package/dist/tasks/schema.js +1 -1
- package/dist/tasks/task-id.js +35 -0
- package/dist/tasks/validator.js +30 -16
- package/dist/text-import-hook.mjs +1 -1
- package/dist/workflows/authoring/authoring.js +104 -43
- package/dist/workflows/authoring/scope-key.js +1 -1
- package/dist/workflows/cli.js +0 -16
- package/dist/workflows/concurrency-policy.js +15 -0
- package/dist/workflows/exec/brief.js +450 -0
- package/dist/workflows/exec/frozen-judge.js +47 -0
- package/dist/workflows/exec/native-executor.js +1038 -0
- package/dist/workflows/exec/param-secrets.js +115 -0
- package/dist/workflows/exec/report.js +1460 -0
- package/dist/workflows/exec/run-workflow.js +602 -0
- package/dist/workflows/exec/scheduler.js +71 -0
- package/dist/workflows/exec/step-work.js +1190 -0
- package/dist/workflows/exec/unit-writer.js +23 -0
- package/dist/workflows/exec/workflow-engine-gate.js +67 -0
- package/dist/workflows/exec/worktree.js +171 -0
- package/dist/workflows/ir/compile.js +246 -0
- package/dist/workflows/ir/freeze.js +233 -0
- package/dist/workflows/ir/params.js +54 -0
- package/dist/workflows/ir/plan-hash.js +68 -0
- package/dist/workflows/ir/schema.js +540 -0
- package/dist/workflows/parser.js +878 -304
- package/dist/workflows/program/expressions.js +181 -0
- package/dist/workflows/program/schema.js +51 -0
- package/dist/workflows/renderer.js +100 -45
- package/dist/workflows/resource-limits.js +22 -0
- package/dist/workflows/runtime/agent-identity.js +59 -14
- package/dist/workflows/runtime/checkin.js +1 -1
- package/dist/workflows/runtime/plan-classifier.js +131 -0
- package/dist/workflows/runtime/runs.js +376 -119
- package/dist/workflows/runtime/unit-checkin.js +45 -0
- package/dist/workflows/runtime/unit-phases.js +20 -0
- package/dist/workflows/runtime/workflow-asset-loader.js +241 -40
- package/dist/workflows/schema.js +1 -11
- package/dist/workflows/validate-summary.js +2 -3
- package/dist/workflows/validator.js +52 -30
- package/docs/README.md +42 -78
- package/docs/migration/README.md +8 -0
- package/docs/migration/release-notes/0.6.0.md +1 -1
- package/docs/migration/release-notes/0.7.0.md +9 -8
- package/docs/migration/release-notes/0.9.0.md +158 -14
- package/docs/migration/v0.7-to-v0.8.md +46 -47
- package/docs/migration/v0.8-to-v0.9.md +844 -0
- package/docs/reference/README.md +12 -0
- package/docs/reference/data-and-telemetry.md +333 -0
- package/package.json +21 -17
- package/schemas/akm-asset-envelope.json +93 -0
- package/schemas/akm-config.json +4636 -0
- package/schemas/akm-task.json +87 -0
- package/schemas/akm-workflow.json +373 -0
- package/dist/akm-migrate-storage +0 -38
- package/dist/assets/help/help-accept.md +0 -12
- package/dist/assets/help/help-improve.md +0 -84
- package/dist/assets/help/help-proposals.md +0 -17
- package/dist/assets/help/help-propose.md +0 -17
- package/dist/assets/help/help-reject.md +0 -11
- package/dist/assets/profiles/frequent.json +0 -13
- package/dist/assets/profiles/recombine-only.json +0 -21
- package/dist/assets/profiles/reflect-distill.json +0 -30
- package/dist/assets/profiles/synthesize.json +0 -15
- package/dist/assets/prompts/procedural-system.md +0 -44
- package/dist/assets/prompts/recombine-system.md +0 -40
- package/dist/assets/prompts/staleness-detect-system.md +0 -6
- package/dist/assets/tasks/core/backup.yml +0 -4
- package/dist/assets/tasks/graph-refresh-weekly.yml +0 -10
- package/dist/assets/templates/html/default.html +0 -78
- package/dist/assets/templates/html/vendor/echarts.min.js +0 -45
- package/dist/assets/wiki/index-template.md +0 -12
- package/dist/assets/wiki/ingest-workflow-template.md +0 -83
- package/dist/assets/wiki/log-template.md +0 -8
- package/dist/assets/wiki/schema-template.md +0 -61
- package/dist/cli/config-migrate.js +0 -150
- package/dist/cli/config-validate.js +0 -39
- package/dist/commands/graph/graph-cli.js +0 -124
- package/dist/commands/graph/graph.js +0 -487
- package/dist/commands/improve/calibration.js +0 -161
- package/dist/commands/improve/dedup.js +0 -482
- package/dist/commands/improve/extract-watch.js +0 -140
- package/dist/commands/improve/hot-probation.js +0 -45
- package/dist/commands/improve/improve-auto-accept.js +0 -276
- package/dist/commands/improve/improve-profiles.js +0 -168
- package/dist/commands/improve/procedural.js +0 -398
- package/dist/commands/improve/recombine.js +0 -818
- package/dist/commands/improve/schema-similarity-gate.js +0 -168
- package/dist/commands/lint/agent-linter.js +0 -44
- package/dist/commands/lint/command-linter.js +0 -44
- package/dist/commands/lint/default-linter.js +0 -16
- package/dist/commands/lint/fact-linter.js +0 -39
- package/dist/commands/lint/knowledge-linter.js +0 -16
- package/dist/commands/lint/memory-linter.js +0 -61
- package/dist/commands/lint/registry.js +0 -41
- package/dist/commands/lint/skill-linter.js +0 -45
- package/dist/commands/lint/task-linter.js +0 -50
- package/dist/commands/lint/workflow-linter.js +0 -81
- package/dist/commands/proposal/legacy-import.js +0 -115
- package/dist/commands/sources/history.js +0 -196
- package/dist/commands/tasks/default-tasks.js +0 -186
- package/dist/commands/wiki-cli.js +0 -292
- package/dist/core/asset/asset-registry.js +0 -76
- package/dist/core/asset/asset-spec.js +0 -259
- package/dist/core/config/config-migration.js +0 -602
- package/dist/core/deep-merge.js +0 -38
- package/dist/core/eval/rank-metrics.js +0 -113
- package/dist/core/ripgrep/install.js +0 -163
- package/dist/core/ripgrep/resolve.js +0 -81
- package/dist/indexer/db/db.js +0 -1413
- package/dist/indexer/manifest.js +0 -170
- package/dist/indexer/passes/metadata-contributors.js +0 -31
- package/dist/indexer/usage/unmigrated-vaults-guard.js +0 -94
- package/dist/integrations/harnesses/opencode-sdk/index.js +0 -49
- package/dist/llm/call-ai.js +0 -62
- package/dist/llm/memory-infer-impl.js +0 -138
- package/dist/output/shapes/distill.js +0 -14
- package/dist/output/shapes/history.js +0 -11
- package/dist/output/text/distill.js +0 -6
- package/dist/output/text/enable-disable.js +0 -8
- package/dist/output/text/history.js +0 -6
- package/dist/output/text/wiki.js +0 -16
- package/dist/registry/build-index.js +0 -386
- package/dist/scripts/migrate-storage.js +0 -19108
- package/dist/scripts/migrations/import-fs-improve-runs-to-db.js +0 -9411
- package/dist/scripts/migrations/v16-to-v17.js +0 -141
- package/dist/setup/legacy-config.js +0 -106
- package/dist/storage/repositories/consolidation-repository.js +0 -38
- package/dist/storage/repositories/recombine-repository.js +0 -213
- package/dist/wiki/wiki-templates.js +0 -15
- package/dist/wiki/wiki.js +0 -1012
- package/dist/workflows/db.js +0 -215
- package/docs/data-and-telemetry.md +0 -226
- /package/dist/sources/{wiki-fetchers → snapshot-fetchers}/registry.js +0 -0
- /package/dist/sources/{wiki-fetchers → snapshot-fetchers}/youtube.js +0 -0
|
@@ -2,24 +2,100 @@
|
|
|
2
2
|
// License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
3
3
|
// file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
|
4
4
|
import { randomUUID } from "node:crypto";
|
|
5
|
-
import {
|
|
5
|
+
import { parseBundleRef } from "../../core/asset/asset-ref.js";
|
|
6
6
|
import { loadConfig } from "../../core/config/config.js";
|
|
7
7
|
import { NotFoundError, UsageError } from "../../core/errors.js";
|
|
8
8
|
import { appendEvent } from "../../core/events.js";
|
|
9
|
+
import { warn } from "../../core/warn.js";
|
|
10
|
+
import { insertEventOnce } from "../../storage/repositories/events-repository.js";
|
|
9
11
|
import { withWorkflowRunsRepo, } from "../../storage/repositories/workflow-runs-repository.js";
|
|
10
12
|
import { getCurrentWorkflowScopeKey } from "../authoring/scope-key.js";
|
|
13
|
+
import { frozenSummaryJudge } from "../exec/frozen-judge.js";
|
|
14
|
+
import { detectSecretShapedParams } from "../exec/param-secrets.js";
|
|
15
|
+
import { collectWorkflowWarnings } from "../ir/compile.js";
|
|
16
|
+
import { compileResolveFreezeWorkflow } from "../ir/freeze.js";
|
|
17
|
+
import { validateWorkflowParams } from "../ir/params.js";
|
|
18
|
+
import { canonicalPlanJson, computePlanHash } from "../ir/plan-hash.js";
|
|
19
|
+
import { decodeWorkflowPlanV3, WORKFLOW_IR_VERSION } from "../ir/schema.js";
|
|
11
20
|
import { validateStepSummary } from "../validate-summary.js";
|
|
12
21
|
import { resolveAgentIdentity } from "./agent-identity.js";
|
|
13
22
|
import { evaluateCheckin } from "./checkin.js";
|
|
14
|
-
import {
|
|
23
|
+
import { assertWorkflowSpineMatchesPlan, classifyWorkflowRunPlan, frozenStepRows, requireExecutableWorkflowPlan, } from "./plan-classifier.js";
|
|
24
|
+
import { evaluateStaleUnits } from "./unit-checkin.js";
|
|
25
|
+
import { canonicalizeWorkflowRefInput, loadWorkflowAsset, resolveWorkflowEntryId } from "./workflow-asset-loader.js";
|
|
26
|
+
/** Clip bound for a unit's `result_json` on the `--units` diagnostic surface. */
|
|
27
|
+
const UNIT_DIAGNOSTIC_CLIP = 2000;
|
|
28
|
+
function toUnitDiagnostic(row, stale, plannedEngine) {
|
|
29
|
+
let diagnostic = null;
|
|
30
|
+
if (row.result_json !== null) {
|
|
31
|
+
// `result_json` is a JSON-encoded value: a bare JSON string for a free-text
|
|
32
|
+
// unit, an object/array for a schema unit. Render the decoded string as-is
|
|
33
|
+
// (no surrounding quotes) and other shapes as compact JSON, then clip so a
|
|
34
|
+
// large artifact can't flood the diagnostic surface.
|
|
35
|
+
let text = row.result_json;
|
|
36
|
+
try {
|
|
37
|
+
const parsed = JSON.parse(row.result_json);
|
|
38
|
+
text = typeof parsed === "string" ? parsed : JSON.stringify(parsed);
|
|
39
|
+
}
|
|
40
|
+
catch {
|
|
41
|
+
/* leave the raw journaled text */
|
|
42
|
+
}
|
|
43
|
+
diagnostic = text.length > UNIT_DIAGNOSTIC_CLIP ? `${text.slice(0, UNIT_DIAGNOSTIC_CLIP)}…` : text;
|
|
44
|
+
}
|
|
45
|
+
return {
|
|
46
|
+
unitId: row.unit_id,
|
|
47
|
+
nodeId: row.node_id,
|
|
48
|
+
stepId: row.step_id,
|
|
49
|
+
phase: row.phase,
|
|
50
|
+
status: row.status,
|
|
51
|
+
attempts: row.attempts,
|
|
52
|
+
tokens: row.tokens,
|
|
53
|
+
failureReason: row.failure_reason,
|
|
54
|
+
sessionId: row.session_id,
|
|
55
|
+
diagnostic,
|
|
56
|
+
startedAt: row.started_at,
|
|
57
|
+
finishedAt: row.finished_at,
|
|
58
|
+
stale: stale !== undefined,
|
|
59
|
+
staleIdleMs: stale ? (Number.isFinite(stale.idleMs) ? stale.idleMs : null) : null,
|
|
60
|
+
claimHolder: row.claim_holder,
|
|
61
|
+
claimExpiresAt: row.claim_expires_at,
|
|
62
|
+
engine: row.engine ?? null,
|
|
63
|
+
runtimeKind: row.engine && (row.runner === "llm" || row.runner === "agent" || row.runner === "sdk") ? row.runner : null,
|
|
64
|
+
platform: plannedEngine?.kind === "agent" ? plannedEngine.platform : null,
|
|
65
|
+
};
|
|
66
|
+
}
|
|
15
67
|
export async function startWorkflowRun(ref, params = {}, options) {
|
|
16
68
|
const asset = await loadWorkflowAsset(ref);
|
|
69
|
+
// Frozen plan (redesign addendum, R1): compile the plan ONCE at start and
|
|
70
|
+
// persist it on the run row in the same transaction as the insert. Every
|
|
71
|
+
// later invocation executes this snapshot — the asset file is never re-read
|
|
72
|
+
// for an in-flight run; re-planning is an explicit new run.
|
|
73
|
+
const plan = decodeWorkflowPlanV3(compileResolveFreezeWorkflow(asset, loadConfig()).plan);
|
|
74
|
+
// Non-fatal WARNINGS: untyped-step and undeclared-param advisories surface
|
|
75
|
+
// as `warn()` lines at start (stderr, consistent with the repo's other
|
|
76
|
+
// author-facing warnings) without blocking the run.
|
|
77
|
+
for (const w of collectWorkflowWarnings(asset.document)) {
|
|
78
|
+
warn(`workflow start: ${asset.path}:${w.line} — ${w.message}`);
|
|
79
|
+
}
|
|
80
|
+
// Reviewer #12: validate supplied `--params` against the frozen param
|
|
81
|
+
// schemas BEFORE creating the run, so a type-mismatched param (e.g. a string
|
|
82
|
+
// for a `{ type: array }` param) is rejected with actionable errors instead
|
|
83
|
+
// of flowing silently into a unit prompt. Programs without declared param
|
|
84
|
+
// schemas (and every Markdown workflow) validate trivially.
|
|
85
|
+
const paramErrors = validateWorkflowParams(plan, params);
|
|
86
|
+
if (paramErrors.length > 0) {
|
|
87
|
+
throw new UsageError(`Cannot start ${asset.ref}: the supplied --params do not satisfy the workflow's declared parameter schemas:\n` +
|
|
88
|
+
paramErrors.map((e) => ` - ${e}`).join("\n"), "INVALID_JSON_ARGUMENT");
|
|
89
|
+
}
|
|
90
|
+
const planJson = canonicalPlanJson(plan);
|
|
91
|
+
const planHash = computePlanHash(plan);
|
|
92
|
+
const workflowRefs = await workflowRunRefSet(asset.ref, ref);
|
|
17
93
|
return withWorkflowRunsRepo(async (repo) => {
|
|
18
94
|
const now = new Date().toISOString();
|
|
19
95
|
const runId = randomUUID();
|
|
20
96
|
const scopeKey = getCurrentWorkflowScopeKey();
|
|
21
|
-
const currentStepId =
|
|
22
|
-
const workflowEntryId = resolveWorkflowEntryId(asset.sourcePath, asset.ref);
|
|
97
|
+
const currentStepId = plan.steps[0]?.stepId ?? null;
|
|
98
|
+
const workflowEntryId = resolveWorkflowEntryId(asset.sourcePath, asset.ref, asset.adapterId);
|
|
23
99
|
// Capture the agent harness + session driving this run. Explicit options
|
|
24
100
|
// win; otherwise fall back to best-effort environment detection. This is
|
|
25
101
|
// identity-only — no background thread or timer is started here.
|
|
@@ -30,19 +106,20 @@ export async function startWorkflowRun(ref, params = {}, options) {
|
|
|
30
106
|
// (workflow_ref, scope_key) pair, refuse to create a parallel run unless
|
|
31
107
|
// `force: true` is set. Previously every call inserted unconditionally,
|
|
32
108
|
// so two terminals running `akm workflow start <ref>` left two runs
|
|
33
|
-
// racing; `akm workflow next` then non-deterministically picked one.
|
|
34
|
-
|
|
35
|
-
const existing = repo.findActiveRunForScope(asset.ref, scopeKey);
|
|
36
|
-
if (existing) {
|
|
37
|
-
throw new UsageError(`Workflow ${asset.ref} already has an active run in this scope (id=${existing.id}, step=${existing.current_step_id ?? "—"}). ` +
|
|
38
|
-
`Use 'akm workflow next ${asset.ref}' to resume it, 'akm workflow abandon ${existing.id}' to give up on it, or pass --force to start a parallel run.`, "RESOURCE_ALREADY_EXISTS");
|
|
39
|
-
}
|
|
40
|
-
}
|
|
109
|
+
// racing; `akm workflow next` then non-deterministically picked one. The
|
|
110
|
+
// active-alias query and all inserts now share this immediate transaction.
|
|
41
111
|
// #506: arm a file-signal check-in (a timestamp, NOT a background thread —
|
|
42
|
-
//
|
|
112
|
+
// per the workflow-agent check-in ADR) so a stalled run can be
|
|
43
113
|
// re-targeted with a `continue` directive. The agent harness + session id
|
|
44
114
|
// are already resolved above (agentHarness/agentSessionId, from #501).
|
|
45
|
-
repo.
|
|
115
|
+
repo.immediateTransaction(() => {
|
|
116
|
+
if (!options?.force) {
|
|
117
|
+
const existing = repo.findActiveRunForScope(workflowRefs, scopeKey);
|
|
118
|
+
if (existing) {
|
|
119
|
+
throw new UsageError(`Workflow ${asset.ref} already has an active run in this scope (id=${existing.id}, step=${existing.current_step_id ?? "—"}). ` +
|
|
120
|
+
`Use 'akm workflow next ${asset.ref}' to resume it, 'akm workflow abandon ${existing.id}' to give up on it, or pass --force to start a parallel run.`, "RESOURCE_ALREADY_EXISTS");
|
|
121
|
+
}
|
|
122
|
+
}
|
|
46
123
|
repo.insertRun({
|
|
47
124
|
id: runId,
|
|
48
125
|
workflowRef: asset.ref,
|
|
@@ -57,16 +134,26 @@ export async function startWorkflowRun(ref, params = {}, options) {
|
|
|
57
134
|
agentSessionId,
|
|
58
135
|
checkinArmedAt: now,
|
|
59
136
|
});
|
|
60
|
-
repo.insertSteps(
|
|
137
|
+
repo.insertSteps(frozenStepRows(plan).map((step) => ({
|
|
61
138
|
runId,
|
|
62
|
-
stepId: step.
|
|
63
|
-
stepTitle: step.
|
|
139
|
+
stepId: step.stepId,
|
|
140
|
+
stepTitle: step.stepTitle,
|
|
64
141
|
instructions: step.instructions,
|
|
65
|
-
completionJson: step.
|
|
66
|
-
sequenceIndex: step.sequenceIndex
|
|
142
|
+
completionJson: step.completionJson,
|
|
143
|
+
sequenceIndex: step.sequenceIndex,
|
|
67
144
|
})));
|
|
145
|
+
// Same transaction as the insert: a run row never exists without its frozen plan.
|
|
146
|
+
repo.setRunPlan(runId, planJson, planHash, WORKFLOW_IR_VERSION);
|
|
68
147
|
});
|
|
69
148
|
const result = await getWorkflowStatus(runId);
|
|
149
|
+
// #13: params are declared non-secret (they are copied verbatim into every
|
|
150
|
+
// unit prompt and hashed into the unit identity, so they cannot be redacted
|
|
151
|
+
// without breaking the driver protocol). Surface a loud, best-effort warning
|
|
152
|
+
// when a param LOOKS like a credential so the author moves it to an env
|
|
153
|
+
// binding. Advisory only — never blocks the start.
|
|
154
|
+
const secretWarnings = detectSecretShapedParams(params);
|
|
155
|
+
if (secretWarnings.length > 0)
|
|
156
|
+
result.warnings = [...(result.warnings ?? []), ...secretWarnings];
|
|
70
157
|
// 07 P1-B: emit only the run id + status — NOT the raw workflowTitle (which
|
|
71
158
|
// comes verbatim from the workflow asset's frontmatter and is therefore
|
|
72
159
|
// attacker-influenceable). Keeping raw titles out of the events stream
|
|
@@ -74,78 +161,145 @@ export async function startWorkflowRun(ref, params = {}, options) {
|
|
|
74
161
|
// into agent context.
|
|
75
162
|
appendEvent({
|
|
76
163
|
eventType: "workflow_started",
|
|
77
|
-
ref: ref,
|
|
164
|
+
ref: asset.ref,
|
|
78
165
|
metadata: { runId: result.run.id, status: result.run.status },
|
|
79
166
|
});
|
|
80
167
|
return result;
|
|
81
168
|
});
|
|
82
169
|
}
|
|
83
|
-
export async function getWorkflowStatus(runId) {
|
|
170
|
+
export async function getWorkflowStatus(runId, opts) {
|
|
84
171
|
return withWorkflowRunsRepo((repo) => {
|
|
85
172
|
const run = readWorkflowRun(repo, runId);
|
|
86
173
|
const steps = readWorkflowRunSteps(repo, run.id);
|
|
87
|
-
|
|
174
|
+
const detail = buildWorkflowRunDetail(run, steps);
|
|
175
|
+
if (opts?.includeUnits) {
|
|
176
|
+
// The honest diagnostic surface (#22): read the unit journal straight and
|
|
177
|
+
// project each row, INCLUDING failures whose diagnostic text the
|
|
178
|
+
// deterministic evidence graph drops. Read-only; never mutates the run.
|
|
179
|
+
const rows = repo.getUnitsForRun(run.id);
|
|
180
|
+
// Codex round-3 finding B: run the SAME pure stale-claim evaluator `brief`
|
|
181
|
+
// uses (`now` injected for deterministic tests) so a dead driver's claimed
|
|
182
|
+
// `running` unit surfaces as stale here too, not just as raw `running`.
|
|
183
|
+
const staleById = new Map(evaluateStaleUnits(rows, opts.now ?? Date.now()).map((u) => [u.unitId, u]));
|
|
184
|
+
const classified = classifyWorkflowRunPlan(run);
|
|
185
|
+
const engines = classified.support === "supported" ? classified.plan.execution?.engines : undefined;
|
|
186
|
+
detail.units = rows.map((row) => toUnitDiagnostic(row, staleById.get(row.unit_id), row.engine ? engines?.[row.engine] : undefined));
|
|
187
|
+
}
|
|
188
|
+
return detail;
|
|
88
189
|
});
|
|
89
190
|
}
|
|
90
191
|
export async function hasWorkflowRun(runId) {
|
|
91
192
|
return withWorkflowRunsRepo((repo) => repo.hasRun(runId));
|
|
92
193
|
}
|
|
93
194
|
export async function listWorkflowRuns(input) {
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
195
|
+
const scopeKey = getCurrentWorkflowScopeKey();
|
|
196
|
+
const activeOnly = input?.activeOnly === true;
|
|
197
|
+
if (input?.workflowRef === undefined) {
|
|
198
|
+
return withWorkflowRunsRepo((repo) => ({
|
|
199
|
+
runs: repo.listRuns({ scopeKey, ...(activeOnly ? { activeOnly: true } : {}) }).map(toWorkflowRunSummary),
|
|
200
|
+
}));
|
|
201
|
+
}
|
|
202
|
+
const exactRef = input.workflowRef.trim();
|
|
203
|
+
if (!exactRef) {
|
|
204
|
+
throw new UsageError("Workflow ref filter cannot be empty.", "INVALID_FLAG_VALUE");
|
|
205
|
+
}
|
|
206
|
+
const parsedExactRef = parseBundleRef(exactRef);
|
|
207
|
+
if (parsedExactRef.fragment !== undefined) {
|
|
208
|
+
throw new UsageError("Workflow ref filters do not accept fragments.", "INVALID_FLAG_VALUE");
|
|
209
|
+
}
|
|
210
|
+
let workflowRefs = [exactRef];
|
|
211
|
+
try {
|
|
212
|
+
const canonicalRef = await canonicalizeWorkflowSpecifier(exactRef);
|
|
213
|
+
workflowRefs = await workflowRunRefSet(canonicalRef, exactRef);
|
|
214
|
+
}
|
|
215
|
+
catch (error) {
|
|
216
|
+
if (parsedExactRef.bundle !== undefined) {
|
|
217
|
+
const exactRows = await withWorkflowRunsRepo((repo) => repo.listRuns({ scopeKey, workflowRef: exactRef }));
|
|
218
|
+
if (exactRows.length === 0)
|
|
219
|
+
throw error;
|
|
220
|
+
return {
|
|
221
|
+
runs: exactRows.filter((row) => !activeOnly || row.status === "active").map(toWorkflowRunSummary),
|
|
222
|
+
};
|
|
103
223
|
}
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
224
|
+
if (!(error instanceof NotFoundError))
|
|
225
|
+
throw error;
|
|
226
|
+
}
|
|
227
|
+
return withWorkflowRunsRepo((repo) => ({
|
|
228
|
+
runs: repo
|
|
229
|
+
.listRuns({ scopeKey, workflowRefs, ...(activeOnly ? { activeOnly: true } : {}) })
|
|
230
|
+
.map(toWorkflowRunSummary),
|
|
231
|
+
}));
|
|
111
232
|
}
|
|
112
233
|
export async function getNextWorkflowStep(specifier, params) {
|
|
113
234
|
return withWorkflowRunsRepo(async (repo) => {
|
|
114
235
|
const { run, autoStarted } = await resolveRunSpecifier(repo, specifier, params);
|
|
115
236
|
const steps = readWorkflowRunSteps(repo, run.id);
|
|
116
|
-
const
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
// the run looks stalled. Pure timestamp evaluation — no background thread.
|
|
120
|
-
const checkin = evaluateCheckin({
|
|
121
|
-
status: run.status,
|
|
122
|
-
updatedAt: run.updated_at,
|
|
123
|
-
checkinArmedAt: run.checkin_armed_at,
|
|
124
|
-
agentHarness: run.agent_harness,
|
|
125
|
-
agentSessionId: run.agent_session_id,
|
|
126
|
-
}) ?? undefined;
|
|
127
|
-
return {
|
|
128
|
-
run: toWorkflowRunSummary(run),
|
|
129
|
-
workflow: {
|
|
130
|
-
ref: run.workflow_ref,
|
|
131
|
-
title: run.workflow_title,
|
|
132
|
-
steps: steps.map(toWorkflowRunStepState),
|
|
133
|
-
},
|
|
134
|
-
step: currentStep ? toWorkflowRunStepState(currentStep) : null,
|
|
135
|
-
...(done ? { done } : {}),
|
|
136
|
-
...(autoStarted ? { autoStarted } : {}),
|
|
137
|
-
...(checkin ? { checkin } : {}),
|
|
138
|
-
};
|
|
237
|
+
const plan = requireExecutableWorkflowPlan(run);
|
|
238
|
+
assertWorkflowSpineMatchesPlan(plan, run, steps);
|
|
239
|
+
return { ...projectNextResult(run, steps), ...(autoStarted ? { autoStarted: true } : {}) };
|
|
139
240
|
});
|
|
140
241
|
}
|
|
242
|
+
/**
|
|
243
|
+
* Project a run row + its step rows into a {@link WorkflowNextResult}. The pure
|
|
244
|
+
* read-shaping half of {@link getNextWorkflowStep}, extracted so the driver
|
|
245
|
+
* snapshot below reproduces the exact same projection without re-running the
|
|
246
|
+
* auto-start-capable {@link resolveRunSpecifier}.
|
|
247
|
+
*/
|
|
248
|
+
function projectNextResult(run, steps) {
|
|
249
|
+
const currentStep = resolveCurrentStep(run, steps);
|
|
250
|
+
const done = run.status === "completed" ? true : undefined;
|
|
251
|
+
// #506: surface a check-in directive through the normal command output when
|
|
252
|
+
// the run looks stalled. Pure timestamp evaluation — no background thread.
|
|
253
|
+
const checkin = evaluateCheckin({
|
|
254
|
+
status: run.status,
|
|
255
|
+
updatedAt: run.updated_at,
|
|
256
|
+
checkinArmedAt: run.checkin_armed_at,
|
|
257
|
+
agentHarness: run.agent_harness,
|
|
258
|
+
agentSessionId: run.agent_session_id,
|
|
259
|
+
}) ?? undefined;
|
|
260
|
+
return {
|
|
261
|
+
run: toWorkflowRunSummary(run),
|
|
262
|
+
workflow: {
|
|
263
|
+
ref: run.workflow_ref,
|
|
264
|
+
title: run.workflow_title,
|
|
265
|
+
steps: steps.map(toWorkflowRunStepState),
|
|
266
|
+
},
|
|
267
|
+
step: currentStep ? toWorkflowRunStepState(currentStep) : null,
|
|
268
|
+
...(done ? { done } : {}),
|
|
269
|
+
...(checkin ? { checkin } : {}),
|
|
270
|
+
};
|
|
271
|
+
}
|
|
272
|
+
/**
|
|
273
|
+
* A consistent point-in-time snapshot of a run for the harness-neutral driver
|
|
274
|
+
* protocol (PR #714 review round 2, #14). `brief`/`report` previously read the
|
|
275
|
+
* spine (`getNextWorkflowStep`) and then, in a SEPARATE connection, the run row
|
|
276
|
+
* + unit journal — so a concurrent `report`/`run`/manual completion could change
|
|
277
|
+
* the active step BETWEEN the two reads, leaving the described work-list
|
|
278
|
+
* inconsistent with the run row it was stamped against. This reads the run row,
|
|
279
|
+
* its steps, AND its unit rows inside ONE transaction (one connection, one
|
|
280
|
+
* snapshot) so all three agree. It never auto-starts — `runId` must already
|
|
281
|
+
* resolve to a concrete run — because the driver protocol never mutates on read.
|
|
282
|
+
*/
|
|
283
|
+
export async function snapshotRunForDriver(runId) {
|
|
284
|
+
return withWorkflowRunsRepo((repo) => repo.transaction(() => {
|
|
285
|
+
const run = readWorkflowRun(repo, runId);
|
|
286
|
+
const steps = readWorkflowRunSteps(repo, run.id);
|
|
287
|
+
const plan = requireExecutableWorkflowPlan(run);
|
|
288
|
+
assertWorkflowSpineMatchesPlan(plan, run, steps);
|
|
289
|
+
const units = repo.getUnitsForRun(run.id);
|
|
290
|
+
return { next: projectNextResult(run, steps), run, units };
|
|
291
|
+
}));
|
|
292
|
+
}
|
|
141
293
|
export async function resumeWorkflowRun(runId) {
|
|
142
294
|
return withWorkflowRunsRepo((repo) => {
|
|
143
295
|
const run = readWorkflowRun(repo, runId);
|
|
296
|
+
const plan = requireExecutableWorkflowPlan(run);
|
|
297
|
+
const steps = readWorkflowRunSteps(repo, run.id);
|
|
298
|
+
assertWorkflowSpineMatchesPlan(plan, run, steps);
|
|
144
299
|
if (run.status === "completed") {
|
|
145
300
|
throw new UsageError(`Workflow run ${run.id} is already completed and cannot be resumed.`);
|
|
146
301
|
}
|
|
147
302
|
if (run.status === "active") {
|
|
148
|
-
const steps = readWorkflowRunSteps(repo, run.id);
|
|
149
303
|
return buildWorkflowRunDetail(run, steps);
|
|
150
304
|
}
|
|
151
305
|
// blocked or failed → flip back to active and re-open the current step so
|
|
@@ -158,8 +312,8 @@ export async function resumeWorkflowRun(runId) {
|
|
|
158
312
|
repo.markRunActive(run.id, now);
|
|
159
313
|
});
|
|
160
314
|
const updated = { ...run, status: "active", updated_at: now };
|
|
161
|
-
const
|
|
162
|
-
return buildWorkflowRunDetail(updated,
|
|
315
|
+
const refreshedSteps = readWorkflowRunSteps(repo, run.id);
|
|
316
|
+
return buildWorkflowRunDetail(updated, refreshedSteps);
|
|
163
317
|
});
|
|
164
318
|
}
|
|
165
319
|
/**
|
|
@@ -170,18 +324,24 @@ export async function resumeWorkflowRun(runId) {
|
|
|
170
324
|
*/
|
|
171
325
|
export async function abandonWorkflowRun(runId) {
|
|
172
326
|
return withWorkflowRunsRepo((repo) => {
|
|
173
|
-
const run = readWorkflowRun(repo, runId);
|
|
174
|
-
if (run.status === "completed" || run.status === "failed") {
|
|
175
|
-
throw new UsageError(`Workflow run ${run.id} is already ${run.status}.`);
|
|
176
|
-
}
|
|
177
327
|
const now = new Date().toISOString();
|
|
178
|
-
repo.
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
328
|
+
const run = repo.immediateTransaction((db) => {
|
|
329
|
+
const current = readWorkflowRun(repo, runId);
|
|
330
|
+
if (current.status === "completed" || current.status === "failed") {
|
|
331
|
+
throw new UsageError(`Workflow run ${current.id} is already ${current.status}.`);
|
|
332
|
+
}
|
|
333
|
+
if (!repo.markRunAbandoned(current.id, now)) {
|
|
334
|
+
throw new UsageError(`Workflow run ${current.id} is ${current.status} and cannot be abandoned.`);
|
|
335
|
+
}
|
|
336
|
+
insertEventOnce(db, {
|
|
337
|
+
eventType: "workflow_abandoned",
|
|
338
|
+
ts: now,
|
|
339
|
+
ref: current.workflow_ref,
|
|
340
|
+
metadata: { runId: current.id },
|
|
341
|
+
idempotencyKey: current.id,
|
|
342
|
+
idempotencyMetadataKey: "runId",
|
|
343
|
+
});
|
|
344
|
+
return current;
|
|
185
345
|
});
|
|
186
346
|
const updated = {
|
|
187
347
|
...run,
|
|
@@ -192,9 +352,6 @@ export async function abandonWorkflowRun(runId) {
|
|
|
192
352
|
};
|
|
193
353
|
const steps = readWorkflowRunSteps(repo, run.id);
|
|
194
354
|
const detail = buildWorkflowRunDetail(updated, steps);
|
|
195
|
-
// Same injectable-footprint rule as workflow_started (07 P1-B): ids and
|
|
196
|
-
// status only, never the frontmatter-derived title.
|
|
197
|
-
appendEvent({ eventType: "workflow_abandoned", ref: run.workflow_ref, metadata: { runId: run.id } });
|
|
198
355
|
return detail;
|
|
199
356
|
});
|
|
200
357
|
}
|
|
@@ -203,9 +360,13 @@ export async function completeWorkflowStep(input) {
|
|
|
203
360
|
// the write transaction — a slow/hung LLM must never hold a db write lock.
|
|
204
361
|
const preflight = await withWorkflowRunsRepo((repo) => {
|
|
205
362
|
const run = readWorkflowRun(repo, input.runId);
|
|
363
|
+
const plan = requireExecutableWorkflowPlan(run);
|
|
364
|
+
const steps = readWorkflowRunSteps(repo, run.id);
|
|
365
|
+
assertWorkflowSpineMatchesPlan(plan, run, steps);
|
|
206
366
|
if (run.status !== "active") {
|
|
207
367
|
throw new UsageError(`Workflow run ${run.id} is ${run.status} and cannot be updated.`);
|
|
208
368
|
}
|
|
369
|
+
assertLeaseAllowsSpineAdvance(run, input.leaseHolder);
|
|
209
370
|
const existing = repo.getStep(run.id, input.stepId);
|
|
210
371
|
if (!existing) {
|
|
211
372
|
throw new NotFoundError(`Step "${input.stepId}" was not found in workflow run ${run.id}.`);
|
|
@@ -216,7 +377,10 @@ export async function completeWorkflowStep(input) {
|
|
|
216
377
|
if (run.current_step_id !== existing.step_id) {
|
|
217
378
|
throw new UsageError(`Step "${input.stepId}" is not the current step for workflow run ${run.id}. Complete "${run.current_step_id}" first.`);
|
|
218
379
|
}
|
|
219
|
-
|
|
380
|
+
const stepPlan = plan.steps.find((step) => step.stepId === input.stepId);
|
|
381
|
+
if (!stepPlan)
|
|
382
|
+
throw new NotFoundError(`Step "${input.stepId}" was not found in workflow run ${run.id}.`);
|
|
383
|
+
return { existing, plan, stepPlan };
|
|
220
384
|
});
|
|
221
385
|
const summary = input.summary?.trim();
|
|
222
386
|
// #506: completing a step requires a summary of the work done.
|
|
@@ -227,9 +391,11 @@ export async function completeWorkflowStep(input) {
|
|
|
227
391
|
// completionCriteria via the configured LLM. Fail-open when no criteria or no
|
|
228
392
|
// judge. Only a well-formed `complete: false` blocks completion.
|
|
229
393
|
if (input.status === "completed" && summary) {
|
|
230
|
-
const criteria =
|
|
231
|
-
const judge = input.summaryJudge === undefined
|
|
232
|
-
|
|
394
|
+
const criteria = preflight.stepPlan.gate.criteria;
|
|
395
|
+
const judge = input.summaryJudge === undefined
|
|
396
|
+
? frozenSummaryJudge(preflight.plan, preflight.stepPlan.gate.judge)
|
|
397
|
+
: input.summaryJudge;
|
|
398
|
+
const verdict = await validateStepSummary({ stepTitle: preflight.stepPlan.title, completionCriteria: criteria, summary }, judge ?? undefined);
|
|
233
399
|
if (!verdict.complete) {
|
|
234
400
|
// Re-arm the check-in so a subsequent stall is still nudged, but leave the
|
|
235
401
|
// step pending and return corrective feedback instead of completing.
|
|
@@ -250,9 +416,16 @@ export async function completeWorkflowStep(input) {
|
|
|
250
416
|
let refreshedSteps = [];
|
|
251
417
|
repo.transaction(() => {
|
|
252
418
|
const run = readWorkflowRun(repo, input.runId);
|
|
419
|
+
const plan = requireExecutableWorkflowPlan(run);
|
|
420
|
+
const spine = readWorkflowRunSteps(repo, run.id);
|
|
421
|
+
assertWorkflowSpineMatchesPlan(plan, run, spine);
|
|
253
422
|
if (run.status !== "active") {
|
|
254
423
|
throw new UsageError(`Workflow run ${run.id} is ${run.status} and cannot be updated.`);
|
|
255
424
|
}
|
|
425
|
+
// Re-checked inside the write transaction (like every other preflight
|
|
426
|
+
// condition): an engine may have claimed the run while the summary gate
|
|
427
|
+
// above was awaiting its LLM judge.
|
|
428
|
+
assertLeaseAllowsSpineAdvance(run, input.leaseHolder);
|
|
256
429
|
const existing = repo.getStep(run.id, input.stepId);
|
|
257
430
|
if (!existing) {
|
|
258
431
|
throw new NotFoundError(`Step "${input.stepId}" was not found in workflow run ${run.id}.`);
|
|
@@ -295,10 +468,16 @@ export async function completeWorkflowStep(input) {
|
|
|
295
468
|
};
|
|
296
469
|
});
|
|
297
470
|
const detail = buildWorkflowRunDetail(updatedRun, refreshedSteps);
|
|
471
|
+
// #11: emit `workflow_step_completed` ONLY for a genuine `completed`
|
|
472
|
+
// transition; every other non-pending status (failed/skipped/blocked)
|
|
473
|
+
// carries the honest `workflow_step_updated` name. The status is ALWAYS
|
|
474
|
+
// in metadata so consumers never infer it from the event name. Raw `notes`
|
|
475
|
+
// are workflow/model-authored content — an event-stream prompt-injection
|
|
476
|
+
// surface — and never enter the events log; they live on the step row only.
|
|
298
477
|
appendEvent({
|
|
299
|
-
eventType: "workflow_step_completed",
|
|
478
|
+
eventType: input.status === "completed" ? "workflow_step_completed" : "workflow_step_updated",
|
|
300
479
|
ref: detail.run.workflowRef,
|
|
301
|
-
metadata: { runId: input.runId, stepId: input.stepId,
|
|
480
|
+
metadata: { runId: input.runId, stepId: input.stepId, status: input.status },
|
|
302
481
|
});
|
|
303
482
|
if (detail.run.status === "completed") {
|
|
304
483
|
appendEvent({ eventType: "workflow_finished", ref: detail.run.workflowRef, metadata: { runId: input.runId } });
|
|
@@ -314,16 +493,28 @@ async function resolveRunSpecifier(repo, specifier, params) {
|
|
|
314
493
|
}
|
|
315
494
|
return { run: explicitRun, autoStarted: false };
|
|
316
495
|
}
|
|
317
|
-
|
|
318
|
-
|
|
496
|
+
const scopeKey = getCurrentWorkflowScopeKey();
|
|
497
|
+
const exactRef = specifier.trim();
|
|
498
|
+
const parsedExact = parseBundleRef(exactRef);
|
|
499
|
+
const qualifiedExact = parsedExact.bundle !== undefined && parsedExact.fragment === undefined;
|
|
500
|
+
const detached = qualifiedExact ? repo.getActiveRunRowForScope(exactRef, scopeKey) : undefined;
|
|
501
|
+
let ref;
|
|
502
|
+
try {
|
|
503
|
+
ref = await canonicalizeWorkflowSpecifier(specifier);
|
|
319
504
|
}
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
505
|
+
catch (error) {
|
|
506
|
+
if (detached) {
|
|
507
|
+
if (params && Object.keys(params).length > 0) {
|
|
508
|
+
throw new UsageError(`--params can only be set on a new run; ${specifier} already has an active run`);
|
|
509
|
+
}
|
|
510
|
+
return { run: detached, autoStarted: false };
|
|
511
|
+
}
|
|
512
|
+
if (error instanceof NotFoundError && !specifier.includes(":") && !specifier.includes("/")) {
|
|
513
|
+
throw new NotFoundError(`Workflow run or workflow "${specifier}" not found.`, "WORKFLOW_NOT_FOUND");
|
|
514
|
+
}
|
|
515
|
+
throw error;
|
|
323
516
|
}
|
|
324
|
-
const
|
|
325
|
-
const scopeKey = getCurrentWorkflowScopeKey();
|
|
326
|
-
const active = repo.getActiveRunRowForScope(ref, scopeKey);
|
|
517
|
+
const active = repo.getActiveRunRowForScope(await workflowRunRefSet(ref, exactRef), scopeKey);
|
|
327
518
|
if (active) {
|
|
328
519
|
if (params && Object.keys(params).length > 0) {
|
|
329
520
|
throw new UsageError(`--params can only be set on a new run; ${ref} already has an active run`);
|
|
@@ -333,6 +524,62 @@ async function resolveRunSpecifier(repo, specifier, params) {
|
|
|
333
524
|
const started = await startWorkflowRun(ref, params ?? {});
|
|
334
525
|
return { run: readWorkflowRun(repo, started.run.id), autoStarted: true };
|
|
335
526
|
}
|
|
527
|
+
async function canonicalizeWorkflowSpecifier(specifier) {
|
|
528
|
+
return canonicalizeWorkflowRefInput(specifier);
|
|
529
|
+
}
|
|
530
|
+
async function workflowRunRefSet(canonicalRef, exactRef) {
|
|
531
|
+
const parsed = parseBundleRef(canonicalRef);
|
|
532
|
+
const refs = new Set([canonicalRef, exactRef.trim()]);
|
|
533
|
+
const exact = parseBundleRef(exactRef.trim());
|
|
534
|
+
if (exact.bundle === undefined) {
|
|
535
|
+
refs.add(parsed.conceptId);
|
|
536
|
+
}
|
|
537
|
+
else {
|
|
538
|
+
try {
|
|
539
|
+
if ((await canonicalizeWorkflowSpecifier(parsed.conceptId)) === canonicalRef)
|
|
540
|
+
refs.add(parsed.conceptId);
|
|
541
|
+
}
|
|
542
|
+
catch (error) {
|
|
543
|
+
if (!(error instanceof NotFoundError))
|
|
544
|
+
throw error;
|
|
545
|
+
}
|
|
546
|
+
}
|
|
547
|
+
return [...refs];
|
|
548
|
+
}
|
|
549
|
+
/** Resolve an existing active run without auto-starting or rebinding a detached short ref. */
|
|
550
|
+
export async function resolveExistingWorkflowRunId(target) {
|
|
551
|
+
return withWorkflowRunsRepo(async (repo) => {
|
|
552
|
+
const byId = repo.getRunById(target);
|
|
553
|
+
if (byId)
|
|
554
|
+
return byId.id;
|
|
555
|
+
const scopeKey = getCurrentWorkflowScopeKey();
|
|
556
|
+
const exactRef = target.trim();
|
|
557
|
+
if (!exactRef.includes(":") && !exactRef.includes("/")) {
|
|
558
|
+
throw new NotFoundError(`Workflow run or workflow "${target}" not found.`, "WORKFLOW_NOT_FOUND");
|
|
559
|
+
}
|
|
560
|
+
const parsedExact = parseBundleRef(exactRef);
|
|
561
|
+
const detached = parsedExact.bundle && parsedExact.fragment === undefined
|
|
562
|
+
? repo.getActiveRunRowForScope(exactRef, scopeKey)
|
|
563
|
+
: undefined;
|
|
564
|
+
let canonicalRef;
|
|
565
|
+
try {
|
|
566
|
+
canonicalRef = await canonicalizeWorkflowSpecifier(exactRef);
|
|
567
|
+
}
|
|
568
|
+
catch (error) {
|
|
569
|
+
if (detached)
|
|
570
|
+
return detached.id;
|
|
571
|
+
if (error instanceof NotFoundError) {
|
|
572
|
+
throw new NotFoundError(`Workflow run or workflow "${target}" not found.`, "WORKFLOW_NOT_FOUND");
|
|
573
|
+
}
|
|
574
|
+
throw error;
|
|
575
|
+
}
|
|
576
|
+
const active = repo.getActiveRunRowForScope(await workflowRunRefSet(canonicalRef, exactRef), scopeKey);
|
|
577
|
+
if (!active) {
|
|
578
|
+
throw new NotFoundError(`No active workflow run for ${canonicalRef} in this scope.`, "WORKFLOW_NOT_FOUND");
|
|
579
|
+
}
|
|
580
|
+
return active.id;
|
|
581
|
+
});
|
|
582
|
+
}
|
|
336
583
|
function readWorkflowRun(repo, runId) {
|
|
337
584
|
const run = repo.getRunById(runId);
|
|
338
585
|
if (!run) {
|
|
@@ -344,6 +591,16 @@ function readWorkflowRunSteps(repo, runId) {
|
|
|
344
591
|
return repo.getStepsForRun(runId);
|
|
345
592
|
}
|
|
346
593
|
function buildWorkflowRunDetail(run, steps) {
|
|
594
|
+
// Review M1: `workflow status` (and every other detail-shaped response) now
|
|
595
|
+
// evaluates the check-in, not just `workflow next`. Pure timestamp check —
|
|
596
|
+
// no background thread (see checkin.ts).
|
|
597
|
+
const checkin = evaluateCheckin({
|
|
598
|
+
status: run.status,
|
|
599
|
+
updatedAt: run.updated_at,
|
|
600
|
+
checkinArmedAt: run.checkin_armed_at,
|
|
601
|
+
agentHarness: run.agent_harness,
|
|
602
|
+
agentSessionId: run.agent_session_id,
|
|
603
|
+
});
|
|
347
604
|
return {
|
|
348
605
|
run: toWorkflowRunSummary(run),
|
|
349
606
|
workflow: {
|
|
@@ -351,9 +608,11 @@ function buildWorkflowRunDetail(run, steps) {
|
|
|
351
608
|
title: run.workflow_title,
|
|
352
609
|
steps: steps.map(toWorkflowRunStepState),
|
|
353
610
|
},
|
|
611
|
+
...(checkin ? { checkin } : {}),
|
|
354
612
|
};
|
|
355
613
|
}
|
|
356
614
|
function toWorkflowRunSummary(run) {
|
|
615
|
+
const plan = classifyWorkflowRunPlan(run);
|
|
357
616
|
return {
|
|
358
617
|
id: run.id,
|
|
359
618
|
workflowRef: run.workflow_ref,
|
|
@@ -368,8 +627,33 @@ function toWorkflowRunSummary(run) {
|
|
|
368
627
|
params: parseJsonObject(run.params_json),
|
|
369
628
|
agentHarness: run.agent_harness ?? null,
|
|
370
629
|
agentSessionId: run.agent_session_id ?? null,
|
|
630
|
+
planIrVersion: plan.irVersion,
|
|
631
|
+
executionSupport: plan.support,
|
|
632
|
+
// Surface the engine lease (holder id + expiry — never workflow-authored
|
|
633
|
+
// content) so `workflow next`/`status` show who is driving the run.
|
|
634
|
+
...(run.engine_lease_holder && run.engine_lease_until
|
|
635
|
+
? { engineLease: { holder: run.engine_lease_holder, until: run.engine_lease_until } }
|
|
636
|
+
: {}),
|
|
371
637
|
};
|
|
372
638
|
}
|
|
639
|
+
/**
|
|
640
|
+
* Single-driver enforcement (R2 run lease): while a LIVE (unexpired) engine
|
|
641
|
+
* lease is held, only the holding engine may advance the gate spine. Manual
|
|
642
|
+
* `akm workflow complete` (no `leaseHolder`) — or a stale engine invocation
|
|
643
|
+
* whose lease was claimed by another — is refused with the holder + expiry.
|
|
644
|
+
* An EXPIRED lease never blocks: the engine that held it is presumed dead.
|
|
645
|
+
*/
|
|
646
|
+
function assertLeaseAllowsSpineAdvance(run, leaseHolder) {
|
|
647
|
+
if (!run.engine_lease_holder || !run.engine_lease_until)
|
|
648
|
+
return;
|
|
649
|
+
if (leaseHolder === run.engine_lease_holder)
|
|
650
|
+
return;
|
|
651
|
+
if (run.engine_lease_until < new Date().toISOString())
|
|
652
|
+
return; // expired ⇒ claimable, not live
|
|
653
|
+
throw new UsageError(`Workflow run ${run.id} is being driven by engine ${run.engine_lease_holder} ` +
|
|
654
|
+
`(run lease expires ${run.engine_lease_until}). The engine owns the step spine while it runs — ` +
|
|
655
|
+
`wait for it to finish or for the lease to expire before advancing steps manually.`);
|
|
656
|
+
}
|
|
373
657
|
function toWorkflowRunStepState(step) {
|
|
374
658
|
return {
|
|
375
659
|
id: step.step_id,
|
|
@@ -410,33 +694,6 @@ function deriveRunState(steps) {
|
|
|
410
694
|
.at(-1);
|
|
411
695
|
return { status: "completed", currentStepId: null, completedAt: completedAt ?? null };
|
|
412
696
|
}
|
|
413
|
-
/**
|
|
414
|
-
/**
|
|
415
|
-
* Build the default summary-validation judge from the configured LLM, or return
|
|
416
|
-
* `null` when no LLM is configured (gate is then skipped — fail-open). Lazily
|
|
417
|
-
* imports the client/config so the workflow engine has no hard LLM dependency.
|
|
418
|
-
*/
|
|
419
|
-
function buildDefaultSummaryJudge() {
|
|
420
|
-
let llm;
|
|
421
|
-
try {
|
|
422
|
-
const config = loadConfig();
|
|
423
|
-
const { getDefaultLlmConfig } = require("../../core/config/config");
|
|
424
|
-
llm = getDefaultLlmConfig(config);
|
|
425
|
-
}
|
|
426
|
-
catch {
|
|
427
|
-
return null;
|
|
428
|
-
}
|
|
429
|
-
if (!llm)
|
|
430
|
-
return null;
|
|
431
|
-
const resolved = llm;
|
|
432
|
-
return async ({ system, user }) => {
|
|
433
|
-
const { chatCompletion } = require("../../llm/client");
|
|
434
|
-
return chatCompletion(resolved, [
|
|
435
|
-
{ role: "system", content: system },
|
|
436
|
-
{ role: "user", content: user },
|
|
437
|
-
]);
|
|
438
|
-
};
|
|
439
|
-
}
|
|
440
697
|
function parseJsonObject(value) {
|
|
441
698
|
if (!value)
|
|
442
699
|
return undefined;
|