akm-cli 0.9.0-rc.8 → 0.9.0
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 +1063 -44
- package/README.md +51 -25
- package/SECURITY.md +14 -1
- package/STABILITY.md +497 -0
- package/dist/akm +148 -35
- package/dist/{akm-migrate-storage → akm-migrate} +6 -9
- package/dist/assets/hints/cli-hints-full.md +223 -95
- package/dist/assets/hints/cli-hints-short.md +85 -22
- package/dist/assets/improve-strategies/default.json +1 -1
- package/dist/assets/improve-strategies/reflect-distill.json +1 -1
- package/dist/assets/prompts/memory-infer-user.md +2 -3
- package/dist/assets/stash-skeleton/README.md +6 -5
- package/dist/assets/stash-skeleton/facts/conventions/assets/agent.md +2 -0
- package/dist/assets/stash-skeleton/facts/conventions/assets/command.md +2 -0
- package/dist/assets/stash-skeleton/facts/conventions/assets/fact.md +2 -0
- package/dist/assets/stash-skeleton/facts/conventions/assets/knowledge.md +2 -0
- package/dist/assets/stash-skeleton/facts/conventions/assets/lesson.md +2 -0
- package/dist/assets/stash-skeleton/facts/conventions/assets/memory.md +2 -0
- package/dist/assets/stash-skeleton/facts/conventions/assets/script.md +2 -0
- package/dist/assets/stash-skeleton/facts/conventions/assets/skill.md +2 -0
- package/dist/assets/stash-skeleton/facts/conventions/assets/workflow.md +2 -0
- package/dist/assets/stash-skeleton/facts/conventions/backlinks.md +2 -0
- package/dist/assets/stash-skeleton/facts/conventions/domains.md +2 -0
- package/dist/assets/stash-skeleton/facts/conventions/organization.md +20 -9
- package/dist/assets/tasks/core/extract.yml +1 -1
- package/dist/assets/tasks/core/version-check.yml +1 -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 +1 -3
- package/dist/assets/workflows/workflow-template.md +32 -15
- package/dist/cli/invocation.js +40 -15
- package/dist/cli/parse-args.js +0 -22
- package/dist/cli/retired-commands.js +121 -0
- package/dist/cli/shared.js +154 -22
- package/dist/cli/unknown-flags.js +236 -0
- package/dist/cli-node.mjs +2 -1
- package/dist/cli.js +696 -258
- package/dist/commands/agent/agent-dispatch.js +14 -3
- package/dist/commands/agent/contribute-cli.js +73 -88
- package/dist/commands/completions.js +79 -22
- package/dist/commands/config-cli.js +17 -150
- package/dist/commands/env/env-cli.js +59 -143
- package/dist/commands/env/env.js +12 -163
- package/dist/commands/env/marker-path.js +6 -0
- package/dist/commands/env/secret-cli.js +36 -66
- package/dist/commands/env/secret.js +24 -57
- package/dist/commands/feedback-cli.js +141 -87
- package/dist/commands/health/accept-rate.js +58 -0
- package/dist/commands/health/advisories.js +3 -4
- package/dist/commands/health/checks.js +85 -23
- package/dist/commands/health/html-report.js +7 -10
- package/dist/commands/health/improve-metrics.js +25 -83
- package/dist/commands/health/md-report.js +5 -9
- package/dist/commands/health/metrics.js +62 -20
- package/dist/commands/health/renderers.js +47 -0
- package/dist/commands/health/report-view-model.js +4 -5
- package/dist/commands/health/stash-exposure.js +1 -1
- package/dist/commands/health/surfaces.js +3 -48
- package/dist/commands/health/task-runs.js +3 -67
- package/dist/commands/health/types-improve.js +7 -0
- package/dist/commands/health.js +99 -28
- package/dist/commands/improve/anti-collapse.js +2 -2
- package/dist/commands/improve/autonomy-gate.js +68 -0
- package/dist/commands/improve/collapse-detector.js +41 -40
- package/dist/commands/improve/consolidate/eligibility.js +1 -23
- package/dist/commands/improve/consolidate/merge.js +4 -0
- package/dist/commands/improve/consolidate.js +140 -1000
- package/dist/commands/improve/distill/promote-memory.js +12 -12
- package/dist/commands/improve/distill/quality-gate.js +6 -6
- package/dist/commands/improve/distill.js +58 -69
- package/dist/commands/improve/eligibility.js +105 -57
- package/dist/commands/improve/extract-cli.js +14 -133
- package/dist/commands/improve/improve-cli.js +98 -114
- package/dist/commands/improve/improve-result-file.js +1 -28
- package/dist/commands/improve/improve-strategies.js +8 -5
- package/dist/commands/improve/improve.js +128 -91
- package/dist/commands/improve/loop-stages.js +182 -20
- package/dist/commands/improve/memory/derived-ref.js +45 -43
- package/dist/commands/improve/memory/memory-belief.js +1 -1
- package/dist/commands/improve/memory/memory-contradiction-detect.js +4 -12
- package/dist/commands/improve/memory/memory-improve.js +6 -5
- package/dist/commands/improve/outcome-loop.js +22 -65
- package/dist/commands/improve/preparation.js +114 -123
- package/dist/commands/improve/proactive-maintenance.js +2 -5
- package/dist/commands/improve/reflect.js +56 -160
- package/dist/commands/improve/salience.js +11 -122
- package/dist/commands/improve/source-identity.js +10 -38
- package/dist/commands/lint/base-linter.js +20 -124
- package/dist/commands/lint/env-key-rules.js +31 -47
- package/dist/commands/lint/index.js +249 -43
- package/dist/commands/{events.js → log.js} +33 -38
- package/dist/commands/migrate-cli.js +92 -12
- package/dist/commands/migration-tool.js +46 -0
- package/dist/commands/observability-cli.js +70 -209
- package/dist/commands/proposal/drain.js +101 -29
- package/dist/commands/proposal/proposal-cli.js +76 -48
- package/dist/commands/proposal/proposal.js +54 -18
- package/dist/commands/proposal/propose-cli.js +88 -0
- package/dist/commands/proposal/propose.js +23 -15
- package/dist/commands/proposal/repository.js +701 -278
- package/dist/commands/proposal/validators/proposal-quality-validators.js +2 -8
- package/dist/commands/proposal/validators/proposal-validators.js +55 -7
- package/dist/commands/proposal/validators/proposals.js +4 -7
- package/dist/commands/read/curate.js +34 -53
- package/dist/commands/read/knowledge.js +150 -95
- package/dist/commands/read/registry-search.js +2 -2
- package/dist/commands/read/remember-cli.js +42 -15
- package/dist/commands/read/search-cli.js +180 -78
- package/dist/commands/read/search.js +58 -43
- package/dist/commands/read/show.js +197 -141
- package/dist/commands/registry-cli.js +12 -51
- package/dist/commands/remember.js +14 -57
- package/dist/commands/sources/add-cli.js +100 -31
- package/dist/commands/sources/bundle-cli.js +166 -0
- package/dist/commands/sources/bundle-config-ops.js +7 -2
- package/dist/commands/sources/info.js +18 -5
- package/dist/commands/sources/init.js +12 -12
- package/dist/commands/sources/installed-stashes.js +382 -98
- package/dist/commands/sources/schema-repair.js +3 -2
- package/dist/commands/sources/self-update.js +131 -38
- package/dist/commands/sources/source-add.js +72 -17
- package/dist/commands/sources/source-clone.js +129 -45
- package/dist/commands/sources/source-manage.js +43 -23
- package/dist/commands/sources/sources-cli.js +57 -208
- package/dist/commands/sources/stash-cli.js +46 -53
- package/dist/commands/tasks/tasks-cli.js +91 -97
- package/dist/commands/tasks/tasks.js +276 -421
- package/dist/commands/workflow-cli.js +175 -450
- package/dist/core/adapter/adapters/akm-adapter.js +47 -28
- package/dist/core/adapter/adapters/akm-lint.js +42 -27
- package/dist/core/adapter/adapters/akm-metadata.js +15 -44
- package/dist/core/adapter/adapters/akm-task-adapter.js +15 -13
- package/dist/core/adapter/adapters/akm-workflow-adapter.js +55 -71
- package/dist/core/adapter/adapters/dotenv-adapter.js +1 -1
- package/dist/core/adapter/adapters/generic-files-adapter.js +2 -0
- package/dist/core/adapter/adapters/index.js +6 -6
- package/dist/core/adapter/adapters/llm-wiki-adapter.js +14 -8
- package/dist/core/adapter/adapters/okf-adapter.js +187 -19
- package/dist/core/adapter/adapters/shared.js +3 -19
- package/dist/core/adapter/adapters/tool-dir-shared.js +8 -3
- package/dist/core/adapter/adapters/website-snapshot-adapter.js +1 -0
- package/dist/core/adapter/detect-adapter.js +17 -0
- package/dist/core/adapter/recognize-match.js +6 -4
- package/dist/core/adapter/validate-context.js +214 -0
- package/dist/core/asset/akm-markdown.js +63 -0
- package/dist/core/asset/asset-placement.js +20 -6
- package/dist/core/asset/asset-ref.js +11 -9
- package/dist/core/asset/frontmatter-lint.js +30 -0
- package/dist/core/asset/frontmatter.js +37 -9
- package/dist/core/asset/markdown.js +40 -51
- package/dist/core/asset/resolve-ref.js +89 -18
- package/dist/core/asset/stash-meta.js +1 -1
- package/dist/core/bundle-id.js +51 -0
- package/dist/core/common.js +152 -38
- package/dist/core/config/config-io.js +12 -1
- package/dist/core/config/config-schema.js +35 -8
- package/dist/core/config/config-sources.js +55 -11
- package/dist/core/config/config-walker.js +25 -9
- package/dist/core/config/config.js +9 -48
- package/dist/core/config/experimental.js +21 -0
- package/dist/core/config/schema/embedding.js +5 -1
- package/dist/core/config/schema/experimental.js +30 -0
- package/dist/core/config/schema/improve-processes.js +0 -6
- package/dist/core/config/schema/improve.js +21 -3
- package/dist/core/config/schema/index-config.js +8 -15
- package/dist/core/config/schema/output.js +4 -1
- package/dist/core/config/schema/setup.js +9 -18
- package/dist/core/config/schema/sources-bundles.js +49 -33
- package/dist/core/config/schema/workflow.js +3 -3
- package/dist/core/env-secret-ref.js +76 -46
- package/dist/core/errors.js +18 -12
- package/dist/core/events.js +46 -128
- package/dist/core/file-change.js +6 -5
- package/dist/core/fs-txn.js +83 -7
- package/dist/core/git-message.js +2 -2
- package/dist/core/improve-result.js +1 -100
- package/dist/core/lesson-lint.js +1 -17
- package/dist/core/logs-db.js +2 -1
- package/dist/core/migration-operation.js +16 -0
- package/dist/core/mutation-target.js +78 -0
- package/dist/core/parse.js +4 -1
- package/dist/core/paths.js +17 -20
- package/dist/core/recognition-util.js +12 -14
- package/dist/core/redaction.js +34 -0
- package/dist/core/standards/resolve-standards-context.js +2 -14
- package/dist/core/standards/resolve-stash-standards.js +2 -2
- package/dist/core/standards/resolve-type-conventions.js +2 -2
- package/dist/core/state/migrations.js +41 -18
- package/dist/core/state-db.js +5 -14
- package/dist/core/structured.js +1 -1
- package/dist/core/subprocess.js +6 -4
- package/dist/core/text-truncation.js +9 -5
- package/dist/core/type-presentation.js +3 -3
- package/dist/core/warn.js +0 -3
- package/dist/core/write-source.js +771 -95
- package/dist/indexer/bundle-identity-guard.js +3 -2
- package/dist/indexer/db/graph-db.js +0 -24
- package/dist/indexer/ensure-index.js +1 -0
- package/dist/indexer/graph/graph-boost.js +9 -34
- package/dist/indexer/graph/graph-extraction.js +8 -5
- package/dist/indexer/index-writer-lock.js +53 -17
- package/dist/indexer/index-written-assets.js +16 -22
- package/dist/indexer/indexer.js +497 -239
- package/dist/indexer/installations.js +14 -96
- package/dist/indexer/passes/dir-staleness.js +16 -9
- package/dist/indexer/passes/memory-inference.js +11 -9
- package/dist/indexer/passes/metadata.js +113 -47
- package/dist/indexer/scan/doc-to-entry.js +38 -1
- package/dist/indexer/scan/drain-dir.js +13 -23
- package/dist/indexer/search/db-search.js +99 -54
- package/dist/indexer/search/fts-query.js +47 -24
- package/dist/indexer/search/ranking-contributors.js +42 -20
- package/dist/indexer/search/ranking.js +18 -99
- package/dist/indexer/search/search-fields.js +7 -2
- package/dist/indexer/search/search-source.js +82 -93
- package/dist/indexer/usage/usage-events.js +0 -89
- package/dist/indexer/walk/file-context.js +2 -1
- package/dist/indexer/walk/matchers.js +30 -43
- package/dist/indexer/walk/path-resolver.js +7 -2
- package/dist/indexer/walk/walker.js +38 -12
- package/dist/integrations/agent/builders.js +0 -6
- package/dist/integrations/agent/config.js +2 -2
- package/dist/integrations/agent/detect.js +49 -19
- package/dist/integrations/agent/engine-fallback.js +76 -0
- package/dist/integrations/agent/profiles.js +14 -0
- package/dist/integrations/agent/prompts.js +12 -8
- package/dist/integrations/agent/runner-dispatch.js +4 -2
- package/dist/integrations/agent/runner.js +0 -1
- package/dist/integrations/agent/spawn.js +5 -6
- package/dist/integrations/github.js +1 -1
- package/dist/integrations/harnesses/aider/agent-builder.js +6 -4
- package/dist/integrations/harnesses/amazonq/agent-builder.js +7 -4
- package/dist/integrations/harnesses/claude/session-log.js +0 -10
- package/dist/integrations/harnesses/codex/agent-builder.js +5 -2
- package/dist/integrations/harnesses/copilot/agent-builder.js +5 -3
- package/dist/integrations/harnesses/gemini/agent-builder.js +5 -3
- package/dist/integrations/harnesses/index.js +3 -7
- package/dist/integrations/harnesses/opencode/agent-builder.js +21 -2
- package/dist/integrations/harnesses/opencode/session-log.js +0 -15
- package/dist/integrations/harnesses/opencode-sdk/sdk-runner.js +13 -4
- package/dist/integrations/harnesses/openhands/agent-builder.js +9 -6
- package/dist/integrations/harnesses/pi/agent-builder.js +6 -4
- package/dist/integrations/lockfile.js +101 -6
- package/dist/integrations/session-logs/index.js +3 -28
- package/dist/llm/client.js +136 -100
- package/dist/llm/embedders/remote.js +13 -5
- package/dist/llm/feature-gate.js +4 -12
- package/dist/llm/graph-extract.js +5 -11
- package/dist/llm/memory-infer.js +144 -1
- package/dist/llm/metadata-enhance.js +5 -7
- package/dist/llm/structured-call.js +1 -1
- package/dist/llm/usage-persist.js +26 -5
- package/dist/llm/usage-telemetry.js +25 -2
- package/dist/output/cli-hints.js +1 -2
- package/dist/output/context.js +22 -7
- package/dist/output/format-exempt.js +80 -0
- package/dist/output/generic-render.js +259 -0
- package/dist/output/render-registry.js +57 -0
- package/dist/output/renderers.js +14 -36
- package/dist/output/shapes/curate.js +10 -1
- package/dist/output/shapes/events.js +12 -7
- package/dist/output/shapes/helpers.js +56 -83
- package/dist/output/shapes/migrate.js +8 -0
- package/dist/output/shapes/passthrough.js +7 -41
- package/dist/output/shapes/proposal/producer.js +15 -7
- package/dist/output/shapes.js +2 -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 +164 -96
- package/dist/output/text/env.js +1 -3
- package/dist/output/text/events.js +8 -7
- package/dist/output/text/health-format.js +103 -0
- package/dist/output/text/health.js +7 -0
- package/dist/output/text/helpers.js +10 -8
- package/dist/output/text/lint-format.js +43 -0
- package/dist/output/text/{save.js → lint.js} +2 -2
- package/dist/output/text/migrate.js +88 -0
- package/dist/output/text/proposal/producer.js +4 -2
- package/dist/output/text/proposal-format.js +44 -72
- package/dist/output/text/registry-commands.js +1 -2
- package/dist/output/text/show-directives.js +15 -7
- package/dist/output/text/status-list.js +32 -0
- package/dist/output/text/sync.js +5 -0
- package/dist/output/text/workflow-format.js +24 -203
- package/dist/output/text/workflow.js +1 -7
- package/dist/output/text.js +16 -17
- 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 +13 -23
- package/dist/registry/resolve.js +42 -7
- package/dist/registry/semver.js +34 -84
- package/dist/runtime.js +2 -23
- package/dist/scripts/akm-migrate-node.js +60290 -0
- package/dist/scripts/akm-migrate.js +59628 -0
- package/dist/setup/detect.js +42 -15
- package/dist/setup/registry-stash-loader.js +2 -2
- package/dist/setup/setup.js +236 -136
- package/dist/setup/steps/connection.js +7 -9
- package/dist/setup/steps/platforms.js +9 -9
- package/dist/setup/steps/semantic.js +15 -3
- package/dist/setup/steps/sources.js +12 -13
- package/dist/setup/steps/stashdir.js +2 -3
- package/dist/setup/steps/tasks.js +237 -120
- package/dist/sources/freshness.js +1 -1
- 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 +25 -23
- package/dist/sources/providers/git-stash.js +395 -106
- package/dist/sources/providers/git.js +2 -2
- package/dist/sources/providers/npm.js +16 -19
- package/dist/sources/providers/provider-utils.js +7 -4
- package/dist/sources/providers/sync-from-ref.js +3 -9
- package/dist/sources/providers/website.js +6 -1
- package/dist/sources/resolve.js +6 -5
- package/dist/sources/snapshot-fetchers/bluesky.js +146 -0
- package/dist/sources/snapshot-fetchers/content-extract.js +566 -0
- package/dist/sources/snapshot-fetchers/fetcher-util.js +41 -0
- package/dist/sources/snapshot-fetchers/github.js +100 -0
- package/dist/sources/snapshot-fetchers/host-guard.js +291 -0
- package/dist/sources/snapshot-fetchers/registry.js +17 -1
- package/dist/sources/snapshot-fetchers/robots.js +348 -0
- package/dist/sources/snapshot-fetchers/rss.js +282 -0
- package/dist/sources/snapshot-fetchers/secret-seam.js +42 -0
- package/dist/sources/snapshot-fetchers/website-ingest.js +566 -268
- package/dist/sources/snapshot-fetchers/x.js +910 -0
- package/dist/storage/database.js +7 -0
- package/dist/storage/engines/sqlite-migrations.js +23 -111
- package/dist/storage/managed-db.js +2 -2
- package/dist/storage/repositories/canaries-repository.js +1 -1
- package/dist/storage/repositories/events-repository.js +27 -11
- package/dist/storage/repositories/improve-runs-repository.js +6 -12
- package/dist/storage/repositories/index-connection.js +17 -6
- package/dist/storage/repositories/index-entries-repository.js +151 -240
- package/dist/storage/repositories/index-entry-mapper.js +15 -11
- package/dist/storage/repositories/index-fts-repository.js +5 -2
- package/dist/storage/repositories/index-llm-cache-repository.js +0 -1
- package/dist/storage/repositories/index-meta-repository.js +2 -3
- package/dist/storage/repositories/index-schema.js +10 -25
- package/dist/storage/repositories/index-utility-repository.js +15 -28
- package/dist/storage/repositories/index-vec-repository.js +6 -1
- package/dist/storage/repositories/outcome-repository.js +119 -0
- package/dist/storage/repositories/proposals-repository.js +296 -59
- package/dist/storage/repositories/registry-cache.js +19 -0
- package/dist/storage/repositories/salience-repository.js +172 -0
- package/dist/storage/repositories/task-history-repository.js +15 -13
- package/dist/storage/repositories/workflow-runs-repository.js +52 -40
- package/dist/tasks/backends/cron.js +105 -15
- package/dist/tasks/backends/index.js +1 -1
- package/dist/tasks/backends/launchd.js +85 -38
- package/dist/tasks/backends/schtasks.js +135 -15
- package/dist/tasks/embedded.js +56 -40
- package/dist/tasks/parser.js +7 -157
- package/dist/tasks/resolve-akm-bin.js +137 -59
- package/dist/tasks/runner.js +79 -42
- package/dist/tasks/scheduler-invocation.js +220 -10
- package/dist/tasks/schema.js +24 -1
- package/dist/tasks/task-id.js +1 -3
- package/dist/tasks/validator.js +20 -6
- package/dist/workflows/authoring/authoring.js +94 -143
- package/dist/workflows/authoring/scope-key.js +1 -1
- package/dist/workflows/exec/frozen-judge.js +28 -2
- package/dist/workflows/exec/native-executor.js +77 -57
- package/dist/workflows/exec/param-secrets.js +9 -9
- package/dist/workflows/exec/run-workflow.js +133 -79
- package/dist/workflows/exec/step-work.js +219 -346
- package/dist/{migrate-storage-node.mjs → workflows/exec/unit-dispatch.js} +1 -5
- package/dist/workflows/ir/compile.js +141 -270
- package/dist/workflows/ir/freeze.js +40 -30
- package/dist/workflows/ir/params.js +135 -11
- package/dist/workflows/ir/plan-hash.js +1 -1
- package/dist/workflows/ir/schema.js +25 -26
- package/dist/workflows/parser.js +872 -307
- package/dist/workflows/program/expressions.js +20 -208
- package/dist/workflows/program/schema.js +7 -10
- package/dist/workflows/renderer.js +95 -68
- package/dist/workflows/resource-limits.js +2 -0
- package/dist/workflows/runtime/checkin.js +3 -3
- package/dist/workflows/runtime/plan-classifier.js +16 -75
- package/dist/workflows/runtime/runs.js +186 -127
- package/dist/workflows/runtime/unit-checkin.js +1 -1
- package/dist/workflows/runtime/unit-phases.js +2 -2
- package/dist/workflows/runtime/workflow-asset-loader.js +232 -83
- package/dist/workflows/schema.js +1 -11
- package/dist/workflows/validate-summary.js +30 -36
- package/dist/workflows/validator.js +21 -62
- package/docs/README.md +68 -0
- package/docs/migration/README.md +8 -0
- package/docs/migration/release-notes/0.7.0.md +11 -11
- package/docs/migration/release-notes/0.9.0.md +208 -27
- package/docs/migration/v0.7-to-v0.8.md +46 -47
- package/docs/migration/v0.8-to-v0.9.md +564 -208
- package/docs/migration/v0.9.0-troubleshooting.md +561 -0
- package/docs/reference/README.md +12 -0
- package/docs/reference/cli.md +2253 -0
- package/docs/reference/configuration.md +358 -0
- package/docs/reference/data-and-telemetry.md +105 -42
- package/docs/reference/workflows.md +647 -0
- package/package.json +22 -11
- package/schemas/akm-asset-envelope.json +93 -0
- package/schemas/akm-config.json +81 -128
- package/schemas/akm-workflow.json +74 -73
- package/dist/assets/tasks/core/backup.yml +0 -5
- package/dist/assets/tasks/graph-refresh-weekly.yml +0 -10
- package/dist/cli/config-migrate.js +0 -1806
- package/dist/cli/config-validate.js +0 -41
- package/dist/commands/backup-cli.js +0 -56
- package/dist/commands/bundle/bundle-cli.js +0 -68
- package/dist/commands/bundle/bundle.js +0 -219
- package/dist/commands/graph/graph-cli.js +0 -124
- package/dist/commands/graph/graph.js +0 -489
- package/dist/commands/improve/extract-watch.js +0 -140
- package/dist/commands/mv-cli.js +0 -1221
- package/dist/commands/sources/history.js +0 -201
- package/dist/commands/tasks/default-tasks.js +0 -186
- package/dist/core/migration-backup.js +0 -1234
- package/dist/indexer/usage/unmigrated-vaults-guard.js +0 -95
- package/dist/llm/memory-infer-impl.js +0 -138
- package/dist/migrate/legacy/config-source-migration.js +0 -223
- package/dist/migrate/legacy/content-migration.js +0 -305
- package/dist/migrate/legacy/legacy-layout.js +0 -779
- package/dist/migrate/legacy/legacy-paths.js +0 -25
- package/dist/migrate/legacy/legacy-stash-json.js +0 -72
- package/dist/migrate/legacy/proposal-fs-import.js +0 -168
- package/dist/migrate/legacy/task-target-ref-migration.js +0 -272
- package/dist/migrate/legacy/three-db-cutover.js +0 -841
- package/dist/migrate/legacy/workflow-migrations-bodies.js +0 -52
- package/dist/migrate/legacy/workflow-migrations-frozen.js +0 -21
- package/dist/migrate/legacy-ref-grammar.js +0 -214
- 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/registry/build-index.js +0 -382
- package/dist/schemas/akm-config.json +0 -4704
- package/dist/schemas/akm-task.json +0 -87
- package/dist/schemas/akm-workflow.json +0 -372
- package/dist/scripts/migrate-storage.js +0 -3816
- package/dist/workflows/authoring/workflow-program-template.yaml +0 -31
- package/dist/workflows/cli.js +0 -53
- package/dist/workflows/exec/brief.js +0 -481
- package/dist/workflows/exec/report.js +0 -1460
- package/dist/workflows/exec/watch.js +0 -116
- package/dist/workflows/program/parser.js +0 -813
- package/dist/workflows/program/project.js +0 -104
|
@@ -4,109 +4,78 @@
|
|
|
4
4
|
import fs from "node:fs";
|
|
5
5
|
import path from "node:path";
|
|
6
6
|
import workflowTemplate from "../../assets/workflows/workflow-template.md" with { type: "text" };
|
|
7
|
-
import {
|
|
7
|
+
import { ensureAkmMarkdownType } from "../../core/asset/akm-markdown.js";
|
|
8
|
+
import { makeBundleRef } from "../../core/asset/asset-ref.js";
|
|
9
|
+
import { isWithin, writeFileAtomic } from "../../core/common.js";
|
|
10
|
+
import { loadConfig } from "../../core/config/config.js";
|
|
8
11
|
import { UsageError } from "../../core/errors.js";
|
|
12
|
+
import { defaultBundleForTarget } from "../../core/mutation-target.js";
|
|
9
13
|
import { canonicalizeWorkflowName, WORKFLOW_EXTENSIONS } from "../../core/recognition-util.js";
|
|
10
14
|
import { warn } from "../../core/warn.js";
|
|
11
|
-
import {
|
|
15
|
+
import { prepareWriteTargetForMutation, resolveWriteTarget, withWriteTargetMutation } from "../../core/write-source.js";
|
|
16
|
+
import { compileWorkflowPlan } from "../ir/compile.js";
|
|
12
17
|
import { parseWorkflow } from "../parser.js";
|
|
13
|
-
|
|
14
|
-
import workflowProgramTemplate from "./workflow-program-template.yaml" with { type: "text" };
|
|
15
|
-
const DEFAULT_WORKFLOW_TEMPLATE = renderWorkflowTemplate({
|
|
16
|
-
title: "Example Workflow",
|
|
17
|
-
firstStepTitle: "First Step",
|
|
18
|
-
firstStepId: "first-step",
|
|
19
|
-
});
|
|
18
|
+
const DEFAULT_WORKFLOW_TEMPLATE = renderWorkflowTemplate("New Workflow");
|
|
20
19
|
export function getWorkflowTemplate() {
|
|
21
20
|
return DEFAULT_WORKFLOW_TEMPLATE;
|
|
22
21
|
}
|
|
23
|
-
/**
|
|
24
|
-
* Minimal valid YAML workflow *program* (redesign addendum, R1), printed by
|
|
25
|
-
* `akm workflow template --yaml`. Kept as an external asset file per the repo
|
|
26
|
-
* convention (see `workflow-program-template.yaml` next to this module);
|
|
27
|
-
* `tests/workflows/program-assets.test.ts` pins that it parses AND compiles.
|
|
28
|
-
*/
|
|
29
|
-
export function getWorkflowProgramTemplate() {
|
|
30
|
-
return workflowProgramTemplate;
|
|
31
|
-
}
|
|
32
22
|
export function buildWorkflowTemplate(name) {
|
|
33
23
|
if (!name)
|
|
34
24
|
return DEFAULT_WORKFLOW_TEMPLATE;
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
});
|
|
42
|
-
const result = parseWorkflow(customized, { path: `<template:${name}>` });
|
|
43
|
-
if (!result.ok) {
|
|
44
|
-
throw new UsageError(formatWorkflowErrors(`<template:${name}>`, result.errors));
|
|
45
|
-
}
|
|
25
|
+
// Only the H1 is customized. Step ids are STRUCTURAL under the unified format
|
|
26
|
+
// — each appears in `steps[].id`, as a body `## <id>` heading, and possibly in
|
|
27
|
+
// another step's `inputs:` — so rewriting them from a name would have to patch
|
|
28
|
+
// three places consistently to stay parseable. Generic `first-step`/
|
|
29
|
+
// `second-step` are the author's to rename.
|
|
30
|
+
const customized = renderWorkflowTemplate(humanizeWorkflowName(name));
|
|
31
|
+
validateWorkflowContent(customized, `<template:${name}>`);
|
|
46
32
|
return customized;
|
|
47
33
|
}
|
|
48
|
-
/**
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
* {@link buildWorkflowTemplate} — so a create never writes an asset that
|
|
54
|
-
* `show`/`start`/`validate` would then reject.
|
|
55
|
-
*/
|
|
56
|
-
export function buildWorkflowProgramTemplate(name) {
|
|
57
|
-
if (!name)
|
|
58
|
-
return workflowProgramTemplate;
|
|
59
|
-
const programName = slugifyWorkflowStepId(name);
|
|
60
|
-
const customized = workflowProgramTemplate.replace(/^name:.*$/m, `name: ${programName}`);
|
|
61
|
-
const parsed = parseWorkflowProgram(customized, { path: `<template:${name}>` });
|
|
62
|
-
if (!parsed.ok) {
|
|
63
|
-
throw new UsageError(formatWorkflowErrors(`<template:${name}>`, parsed.errors));
|
|
34
|
+
/** Parse AND compile `content`, so a create never writes an asset that `show`/`start`/`validate` would then reject. */
|
|
35
|
+
function validateWorkflowContent(content, sourcePath) {
|
|
36
|
+
const result = parseWorkflow(content, { path: sourcePath });
|
|
37
|
+
if (!result.ok) {
|
|
38
|
+
throw new UsageError(formatWorkflowErrors(sourcePath, result.errors));
|
|
64
39
|
}
|
|
65
|
-
const compiled =
|
|
40
|
+
const compiled = compileWorkflowPlan(result.document, slugifyWorkflowStepId(sourcePath));
|
|
66
41
|
if (!compiled.ok) {
|
|
67
|
-
throw new UsageError(formatWorkflowErrors(
|
|
42
|
+
throw new UsageError(formatWorkflowErrors(sourcePath, compiled.errors));
|
|
68
43
|
}
|
|
69
|
-
return customized;
|
|
70
44
|
}
|
|
71
|
-
/** Recognized
|
|
72
|
-
const
|
|
45
|
+
/** Recognized workflow-program suffixes — creating one is a lint-time usage error (workflow-format-unification). */
|
|
46
|
+
const YAML_SUFFIX_RE = /\.ya?ml$/i;
|
|
47
|
+
export function assertWorkflowMarkdownName(name) {
|
|
48
|
+
if (!YAML_SUFFIX_RE.test(name.trim()))
|
|
49
|
+
return;
|
|
50
|
+
throw new UsageError(`Workflows are markdown-only now (workflow-format-unification) — "${name}" cannot be created. ` +
|
|
51
|
+
`Use a plain name (no ".yaml"/".yml" suffix); the orchestration graph lives in the ".md" file's frontmatter.`);
|
|
52
|
+
}
|
|
73
53
|
export function createWorkflowAsset(input) {
|
|
74
|
-
|
|
75
|
-
const
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
const
|
|
81
|
-
const programSuffix = suffixMatch ? suffixMatch[0].toLowerCase() : undefined;
|
|
82
|
-
const isProgram = programSuffix !== undefined;
|
|
54
|
+
assertWorkflowMarkdownName(input.name);
|
|
55
|
+
const config = loadConfig();
|
|
56
|
+
const resolvedTarget = resolveWriteTarget(config);
|
|
57
|
+
const target = prepareWriteTargetForMutation(resolvedTarget, { allowedAdapters: ["akm", "akm-workflow"] });
|
|
58
|
+
const stashDir = target.source.path;
|
|
59
|
+
const standaloneWorkflowBundle = target.source.adapterId === "akm-workflow";
|
|
60
|
+
const typeRoot = standaloneWorkflowBundle ? stashDir : path.join(stashDir, "workflows");
|
|
83
61
|
const normalizedName = normalizeWorkflowName(input.name);
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
//
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
// the same canonical name, naming the existing file. A same-extension collision
|
|
102
|
-
// (the target path itself exists) keeps the classic `--force` overwrite escape;
|
|
103
|
-
// a DIFFERENT-extension collision cannot be force-overwritten (writing a new
|
|
104
|
-
// file would leave the old one shadowing it) — remove the existing file first.
|
|
105
|
-
const existingPaths = WORKFLOW_EXTENSIONS.map((ext) => path.join(typeRoot, `${normalizedName}${ext}`)).filter((candidate) => fs.existsSync(candidate));
|
|
106
|
-
const conflicting = existingPaths.find((p) => p !== assetPath);
|
|
107
|
-
if (conflicting !== undefined) {
|
|
108
|
-
throw new UsageError(`Workflow "${normalizedName}" already exists as ${path.relative(stashDir, conflicting)} — the ` +
|
|
109
|
-
`\`workflows/${normalizedName}\` ref resolves to that file, so creating this one would shadow it. ` +
|
|
62
|
+
const conceptId = standaloneWorkflowBundle ? normalizedName : `workflows/${normalizedName}`;
|
|
63
|
+
const assetPath = path.join(typeRoot, `${normalizedName}.md`);
|
|
64
|
+
const relativeAssetPath = path.relative(path.resolve(typeRoot), path.resolve(assetPath));
|
|
65
|
+
if (relativeAssetPath === ".." ||
|
|
66
|
+
relativeAssetPath.startsWith(`..${path.sep}`) ||
|
|
67
|
+
path.isAbsolute(relativeAssetPath)) {
|
|
68
|
+
throw new UsageError(`Resolved workflow path escapes the bundle: "${normalizedName}"`, "PATH_ESCAPE_VIOLATION");
|
|
69
|
+
}
|
|
70
|
+
// A file whose canonical name matches but whose PATH differs can only be a
|
|
71
|
+
// case variant now (`upper.MD` vs `upper.md`) — the cross-EXTENSION case this
|
|
72
|
+
// guard also covered is gone with the unified `.md`-only format. It still
|
|
73
|
+
// matters: on a case-insensitive filesystem the two spellings are one file,
|
|
74
|
+
// so writing the target would silently clobber or shadow the existing asset.
|
|
75
|
+
const shadowing = findExistingWorkflowPaths(typeRoot, normalizedName).find((p) => p !== assetPath);
|
|
76
|
+
if (shadowing !== undefined) {
|
|
77
|
+
throw new UsageError(`Workflow "${normalizedName}" already exists as ${path.relative(stashDir, shadowing)} — the ` +
|
|
78
|
+
`\`${conceptId}\` ref resolves to that file, so creating this one would shadow it. ` +
|
|
110
79
|
`Remove or rename the existing file first, or create the workflow under a different name.`, "RESOURCE_ALREADY_EXISTS");
|
|
111
80
|
}
|
|
112
81
|
if (fs.existsSync(assetPath) && !input.force) {
|
|
@@ -114,33 +83,19 @@ export function createWorkflowAsset(input) {
|
|
|
114
83
|
}
|
|
115
84
|
const content = input.from
|
|
116
85
|
? readWorkflowSource(input.from, stashDir)
|
|
117
|
-
: (input.content ??
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
}
|
|
129
|
-
const compiled = compileWorkflowProgram(parsed.program);
|
|
130
|
-
if (!compiled.ok) {
|
|
131
|
-
throw new UsageError(formatWorkflowErrors(sourcePath, compiled.errors));
|
|
132
|
-
}
|
|
133
|
-
}
|
|
134
|
-
else {
|
|
135
|
-
const result = parseWorkflow(content, { path: sourcePath });
|
|
136
|
-
if (!result.ok) {
|
|
137
|
-
throw new UsageError(formatWorkflowErrors(sourcePath, result.errors));
|
|
138
|
-
}
|
|
139
|
-
}
|
|
140
|
-
fs.mkdirSync(path.dirname(assetPath), { recursive: true });
|
|
141
|
-
fs.writeFileSync(assetPath, content.endsWith("\n") ? content : `${content}\n`, "utf8");
|
|
86
|
+
: (input.content ?? buildWorkflowTemplate(normalizedName));
|
|
87
|
+
const sourcePath = input.from ?? `workflows/${normalizedName}.md`;
|
|
88
|
+
validateWorkflowContent(content, sourcePath);
|
|
89
|
+
const authoredContent = ensureAkmMarkdownType(content, "workflow");
|
|
90
|
+
const mode = fs.existsSync(assetPath) ? fs.lstatSync(assetPath).mode & 0o777 : 0o644;
|
|
91
|
+
const defaultBundle = defaultBundleForTarget(config);
|
|
92
|
+
const ref = makeBundleRef(target.source.name === defaultBundle ? undefined : target.source.name, conceptId);
|
|
93
|
+
withWriteTargetMutation(target, [assetPath], { ignored: "reject", purpose: "workflow-authoring", message: `Create ${ref}` }, () => {
|
|
94
|
+
fs.mkdirSync(path.dirname(assetPath), { recursive: true });
|
|
95
|
+
writeFileAtomic(assetPath, authoredContent.endsWith("\n") ? authoredContent : `${authoredContent}\n`, mode);
|
|
96
|
+
});
|
|
142
97
|
return {
|
|
143
|
-
ref
|
|
98
|
+
ref,
|
|
144
99
|
path: assetPath,
|
|
145
100
|
stashDir,
|
|
146
101
|
};
|
|
@@ -167,10 +122,9 @@ function readWorkflowSource(source, stashDir) {
|
|
|
167
122
|
return fs.readFileSync(resolved, "utf8");
|
|
168
123
|
}
|
|
169
124
|
function normalizeWorkflowName(name) {
|
|
170
|
-
// Strip
|
|
171
|
-
//
|
|
172
|
-
//
|
|
173
|
-
// by the caller (createWorkflowAsset).
|
|
125
|
+
// Strip a recognized workflow extension (.md) so the canonical name — and
|
|
126
|
+
// thus the `workflows/<name>` ref — is extension-free regardless of how the
|
|
127
|
+
// user spelled it.
|
|
174
128
|
const normalized = canonicalizeWorkflowName(name
|
|
175
129
|
.trim()
|
|
176
130
|
.replace(/\\/g, "/")
|
|
@@ -190,7 +144,7 @@ function humanizeWorkflowName(name) {
|
|
|
190
144
|
.pop()
|
|
191
145
|
?.replace(/[-_]+/g, " ")
|
|
192
146
|
.replace(/\b\w/g, (match) => match.toUpperCase())
|
|
193
|
-
.trim() || "
|
|
147
|
+
.trim() || "New Workflow");
|
|
194
148
|
}
|
|
195
149
|
function slugifyWorkflowStepId(name) {
|
|
196
150
|
return (name
|
|
@@ -222,34 +176,31 @@ export function validateWorkflowSource(target) {
|
|
|
222
176
|
return { path: target, parse: parseWorkflow(content, { path: target }) };
|
|
223
177
|
}
|
|
224
178
|
/**
|
|
225
|
-
*
|
|
226
|
-
* `
|
|
227
|
-
* `
|
|
228
|
-
*
|
|
229
|
-
* `WorkflowError[]` shape, ready for `formatWorkflowErrors`. Throws
|
|
230
|
-
* `UsageError` only when the target cannot be located on disk.
|
|
179
|
+
* Every file under `typeRoot` whose canonical workflow name equals
|
|
180
|
+
* `normalizedName`. Extension matching is case-INSENSITIVE, so `foo.MD` and
|
|
181
|
+
* `foo.md` both match — the case-variant collision the create path must refuse
|
|
182
|
+
* rather than silently clobber on a case-insensitive filesystem.
|
|
231
183
|
*/
|
|
232
|
-
|
|
233
|
-
const
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
const content = fs.readFileSync(resolved, "utf8");
|
|
238
|
-
const parse = parseWorkflowProgram(content, { path: target });
|
|
239
|
-
if (!parse.ok) {
|
|
240
|
-
return { path: target, result: { ok: false, errors: parse.errors } };
|
|
241
|
-
}
|
|
242
|
-
const compiled = compileWorkflowProgram(parse.program);
|
|
243
|
-
if (!compiled.ok) {
|
|
244
|
-
return { path: target, result: { ok: false, errors: compiled.errors } };
|
|
184
|
+
function findExistingWorkflowPaths(typeRoot, normalizedName) {
|
|
185
|
+
const parent = path.join(typeRoot, path.dirname(normalizedName));
|
|
186
|
+
let entries;
|
|
187
|
+
try {
|
|
188
|
+
entries = fs.readdirSync(parent, { withFileTypes: true });
|
|
245
189
|
}
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
190
|
+
catch {
|
|
191
|
+
return [];
|
|
192
|
+
}
|
|
193
|
+
const basename = path.basename(normalizedName);
|
|
194
|
+
return WORKFLOW_EXTENSIONS.flatMap((extension) => entries
|
|
195
|
+
.filter((entry) => {
|
|
196
|
+
if (!entry.isFile() && !entry.isSymbolicLink())
|
|
197
|
+
return false;
|
|
198
|
+
const entryExtension = path.extname(entry.name);
|
|
199
|
+
return entryExtension.toLowerCase() === extension && entry.name.slice(0, -entryExtension.length) === basename;
|
|
200
|
+
})
|
|
201
|
+
.sort((a, b) => a.name.localeCompare(b.name))
|
|
202
|
+
.map((entry) => path.join(parent, entry.name)));
|
|
249
203
|
}
|
|
250
|
-
function renderWorkflowTemplate(
|
|
251
|
-
return workflowTemplate
|
|
252
|
-
.replace("{{TITLE}}", input.title)
|
|
253
|
-
.replace("{{FIRST_STEP_TITLE}}", input.firstStepTitle)
|
|
254
|
-
.replace("{{FIRST_STEP_ID}}", input.firstStepId);
|
|
204
|
+
function renderWorkflowTemplate(title) {
|
|
205
|
+
return workflowTemplate.replace("{{TITLE}}", title);
|
|
255
206
|
}
|
|
@@ -21,7 +21,7 @@ export function resolveWorkflowScopeAnchor(startDir) {
|
|
|
21
21
|
if (gitRoot)
|
|
22
22
|
return gitRoot;
|
|
23
23
|
try {
|
|
24
|
-
const stashDir = safeRealpath(resolveStashDir(
|
|
24
|
+
const stashDir = safeRealpath(resolveStashDir());
|
|
25
25
|
if (isWithin(cwd, stashDir))
|
|
26
26
|
return stashDir;
|
|
27
27
|
}
|
|
@@ -4,12 +4,37 @@
|
|
|
4
4
|
import { deepMergeConfig } from "../../core/config/deep-merge.js";
|
|
5
5
|
import { ConfigError } from "../../core/errors.js";
|
|
6
6
|
/** Build a gate judge from a v3 catalog entry without consulting live config. */
|
|
7
|
-
export function frozenSummaryJudge(plan, invocation) {
|
|
7
|
+
export function frozenSummaryJudge(plan, invocation, signal, dispatcher) {
|
|
8
8
|
if (!invocation)
|
|
9
9
|
return null;
|
|
10
10
|
const engine = plan.execution?.engines[invocation.engine];
|
|
11
|
-
if (!engine
|
|
11
|
+
if (!engine)
|
|
12
12
|
throw new ConfigError(`Frozen gate engine "${invocation.engine}" is unavailable.`, "INVALID_CONFIG_FILE");
|
|
13
|
+
if (engine.kind === "agent") {
|
|
14
|
+
if (!dispatcher) {
|
|
15
|
+
throw new ConfigError(`Frozen agent gate engine "${invocation.engine}" has no unit dispatcher.`, "INVALID_CONFIG_FILE");
|
|
16
|
+
}
|
|
17
|
+
return async ({ system, user }) => {
|
|
18
|
+
const fallbackEngine = engine.fallbackLlmEngine ? plan.execution.engines[engine.fallbackLlmEngine] : undefined;
|
|
19
|
+
const result = await dispatcher({
|
|
20
|
+
runId: "gate",
|
|
21
|
+
stepId: "gate",
|
|
22
|
+
unitId: "gate",
|
|
23
|
+
nodeId: "gate",
|
|
24
|
+
prompt: user,
|
|
25
|
+
systemPrompt: system,
|
|
26
|
+
engine,
|
|
27
|
+
...(fallbackEngine?.kind === "llm" ? { fallbackEngine } : {}),
|
|
28
|
+
invocation,
|
|
29
|
+
timeoutMs: invocation.timeoutMs,
|
|
30
|
+
...(signal ? { signal } : {}),
|
|
31
|
+
});
|
|
32
|
+
if (!result.ok) {
|
|
33
|
+
throw new Error(result.error || `Verification engine "${invocation.engine}" failed.`);
|
|
34
|
+
}
|
|
35
|
+
return result.text;
|
|
36
|
+
};
|
|
37
|
+
}
|
|
13
38
|
return async ({ system, user }) => {
|
|
14
39
|
const { chatCompletion } = await import("../../llm/client.js");
|
|
15
40
|
return chatCompletion(materialize(engine, invocation), [
|
|
@@ -17,6 +42,7 @@ export function frozenSummaryJudge(plan, invocation) {
|
|
|
17
42
|
{ role: "user", content: user },
|
|
18
43
|
], {
|
|
19
44
|
timeoutMs: invocation.timeoutMs,
|
|
45
|
+
...(signal ? { signal } : {}),
|
|
20
46
|
});
|
|
21
47
|
};
|
|
22
48
|
}
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
// License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
3
3
|
// file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
|
4
4
|
/**
|
|
5
|
-
* Native executor — executes
|
|
5
|
+
* Native executor — executes one frozen step subgraph (`IrStepPlan.root`) on
|
|
6
6
|
* the local machine: fan-out through the scheduler, schema-validated
|
|
7
7
|
* structured output through `runStructured` (core/structured.ts), per-unit
|
|
8
8
|
* persistence through the serialized writer queue, and `workflow_unit_*`
|
|
@@ -33,12 +33,11 @@
|
|
|
33
33
|
*
|
|
34
34
|
* Empty free-text outputs (peer review): a SUCCESSFUL schemaless unit that
|
|
35
35
|
* returns the empty string is normalized to "no output" — {@link dispatchUnit}
|
|
36
|
-
* drops the falsy `text`, `finishUnit` journals `result_json = NULL`, and
|
|
37
|
-
* durable-row reuse
|
|
38
|
-
*
|
|
39
|
-
*
|
|
40
|
-
*
|
|
41
|
-
* `EMPTY_OUTPUT` driver-parity golden pins it). Consequences that follow from
|
|
36
|
+
* drops the falsy `text`, `finishUnit` journals `result_json = NULL`, and
|
|
37
|
+
* durable-row reuse rehydrates the same absence (`unitOutcomeFromRow`). This is
|
|
38
|
+
* the ONLY empty-output resolution: `''` never survives into the journal, so the
|
|
39
|
+
* live artifact cannot diverge from the artifact a resume rebuilds from the same
|
|
40
|
+
* rows (the byte-identical-graph cardinal rule). Consequences that follow from
|
|
42
41
|
* "empty == absent", not special-cased anywhere:
|
|
43
42
|
* - a SOLO empty step promotes `output = null` (the unit's absent text ??
|
|
44
43
|
* null); a `collect` fan-out promotes `null` in that item's slot.
|
|
@@ -74,9 +73,7 @@
|
|
|
74
73
|
* never a silent re-dispatch — under a frozen plan the same identity must
|
|
75
74
|
* reproduce the same inputs, so a mismatch means the journal (or params
|
|
76
75
|
* row) was tampered with. Failed/running/missing rows dispatch live.
|
|
77
|
-
* -
|
|
78
|
-
* no back-compat shim: those rows simply never match a content-derived id
|
|
79
|
-
* and are ignored (the step re-runs cleanly on top of them).
|
|
76
|
+
* - Rows with unrelated ids never match a content-derived id and are ignored.
|
|
80
77
|
*
|
|
81
78
|
* Gate loops (addendum, R2 `gate.max_loops`): when the engine re-executes a
|
|
82
79
|
* step subgraph after a gate rejection, it threads the judge's feedback in as
|
|
@@ -136,17 +133,15 @@ import { validateJsonSchemaSubset } from "../../core/json-schema.js";
|
|
|
136
133
|
import { collectSensitiveValues, isEnvPassthroughValueSafeToExpose, redactSensitiveValue } from "../../core/redaction.js";
|
|
137
134
|
import { runStructured } from "../../core/structured.js";
|
|
138
135
|
import { warn } from "../../core/warn.js";
|
|
136
|
+
import { insertEventStrict } from "../../storage/repositories/events-repository.js";
|
|
139
137
|
import { withWorkflowRunsRepo } from "../../storage/repositories/workflow-runs-repository.js";
|
|
140
138
|
import { LIFETIME_UNIT_CAP, scheduleUnits, UnitCapExceededError } from "./scheduler.js";
|
|
141
|
-
// Shared step semantics — the ONE implementation consumed by
|
|
142
|
-
// (this module + run-workflow.ts)
|
|
143
|
-
//
|
|
144
|
-
import {
|
|
139
|
+
// Shared step semantics — the ONE implementation consumed by the engine
|
|
140
|
+
// (this module + run-workflow.ts) on both the fresh-execution and the resume
|
|
141
|
+
// path. This module dispatches; step-work.ts owns the pure decisions.
|
|
142
|
+
import { computeStepWorkList, reduceEmptyStep, reduceStepOutcomes, stepOutputsFromEvidence, unitOutcomeFromRow, } from "./step-work.js";
|
|
145
143
|
import { enqueueUnitWrite } from "./unit-writer.js";
|
|
146
144
|
import { assertGitWorkTree, cleanupUnitWorktree, createUnitWorktree } from "./worktree.js";
|
|
147
|
-
// Re-exported for existing consumers (run-workflow.ts, tests) that import these
|
|
148
|
-
// from native-executor; they now live in the shared step-work module.
|
|
149
|
-
export { buildArtifactSummary, DEFAULT_UNIT_TIMEOUT_MS, projectStepOutput };
|
|
150
145
|
/**
|
|
151
146
|
* Mutable per-step dispatch budget: the lifetime unit cap PLUS the declared
|
|
152
147
|
* run-level budget ceilings (`budget.max_units` / `budget.max_tokens`,
|
|
@@ -248,10 +243,11 @@ export async function executeStepPlan(plan, ctx) {
|
|
|
248
243
|
const dispatched = ctx.unitsDispatched ?? 0;
|
|
249
244
|
// Work-list computation is the SHARED, PURE decision (step-work.ts): resolve
|
|
250
245
|
// the fan-out list, derive content-derived unit ids, assemble each unit's
|
|
251
|
-
// prompt, and hash its resolved input.
|
|
252
|
-
//
|
|
253
|
-
//
|
|
254
|
-
//
|
|
246
|
+
// prompt, and hash its resolved input. A resume recomputes the identical list
|
|
247
|
+
// from the same frozen plan — that shared pure implementation is what lets
|
|
248
|
+
// journaled rows be matched instead of re-executed. This module owns only the
|
|
249
|
+
// impure remainder: env/worktree preflight, durable-row reuse, dispatch,
|
|
250
|
+
// journaling, budget.
|
|
255
251
|
const workList = computeStepWorkList(plan, {
|
|
256
252
|
runId: ctx.runId,
|
|
257
253
|
params: ctx.params,
|
|
@@ -266,10 +262,9 @@ export async function executeStepPlan(plan, ctx) {
|
|
|
266
262
|
const { template, reducer, isFanOut, items, units: workUnits } = workList.list;
|
|
267
263
|
if (items.length === 0) {
|
|
268
264
|
// Empty fan-out: the promoted artifact is the degenerate empty value, honored
|
|
269
|
-
// against the step's declared output schema. `reduceEmptyStep`
|
|
270
|
-
// decision
|
|
271
|
-
//
|
|
272
|
-
// artifact + schema verdict.
|
|
265
|
+
// against the step's declared output schema. `reduceEmptyStep` (step-work.ts)
|
|
266
|
+
// owns that decision so a zero-unit step promotes the identical artifact +
|
|
267
|
+
// schema verdict every time the spine reaches it.
|
|
273
268
|
return { ...reduceEmptyStep(plan, reducer), unitsDispatched: dispatched };
|
|
274
269
|
}
|
|
275
270
|
const dispatcher = ctx.dispatcher ?? defaultUnitDispatcher;
|
|
@@ -466,7 +461,7 @@ async function runUnit(input) {
|
|
|
466
461
|
...(sensitiveValues.length > 0 ? { sensitiveValues } : {}),
|
|
467
462
|
...(input.signal ? { signal: input.signal } : {}),
|
|
468
463
|
};
|
|
469
|
-
// Bounded retry
|
|
464
|
+
// Bounded retry: attempt 0 journals under the base
|
|
470
465
|
// journal id (`<unitId>`, or `<unitId>~l<loop>` in a gate loop — computed by
|
|
471
466
|
// the shared work-list), retry attempt N under `<baseId>~r<N>`. Every attempt
|
|
472
467
|
// keeps its own row. Retries only fire when the failure reason is in
|
|
@@ -489,8 +484,8 @@ async function runUnit(input) {
|
|
|
489
484
|
const reuse = classifyUnitReuse(workUnit, input.existingUnits, gateLoop);
|
|
490
485
|
if (reuse.kind === "reuse") {
|
|
491
486
|
// Identity in the durable step evidence is the CONTENT-derived base id, not
|
|
492
|
-
// the `~r<n>` attempt row it was reused from — the
|
|
493
|
-
//
|
|
487
|
+
// the `~r<n>` attempt row it was reused from — the work list only ever knows
|
|
488
|
+
// base ids, so evidence.units[].unitId stays stable across retries+resumes.
|
|
494
489
|
return reuseCompletedUnit(unitId, reuse.row, workUnit.schema !== undefined);
|
|
495
490
|
}
|
|
496
491
|
if (reuse.kind === "diverge") {
|
|
@@ -504,6 +499,14 @@ async function runUnit(input) {
|
|
|
504
499
|
}
|
|
505
500
|
let outcome;
|
|
506
501
|
for (let attempt = 0; attempt < maxAttempts; attempt++) {
|
|
502
|
+
if (input.signal?.aborted) {
|
|
503
|
+
return (outcome ?? {
|
|
504
|
+
unitId,
|
|
505
|
+
ok: false,
|
|
506
|
+
failureReason: "aborted",
|
|
507
|
+
error: "unit was not dispatched because the workflow invocation was interrupted",
|
|
508
|
+
});
|
|
509
|
+
}
|
|
507
510
|
const attemptId = attemptIdFor(attempt);
|
|
508
511
|
// Lifetime cap + declared budget ceilings, consumed per ACTUAL dispatch
|
|
509
512
|
// (reuses above returned before reaching here). Refusal fails this unit
|
|
@@ -542,6 +545,8 @@ async function runUnit(input) {
|
|
|
542
545
|
input.budget.addTokens(outcome.tokens);
|
|
543
546
|
if (outcome.ok)
|
|
544
547
|
return outcome;
|
|
548
|
+
if (input.signal?.aborted)
|
|
549
|
+
return outcome;
|
|
545
550
|
const reason = outcome.failureReason;
|
|
546
551
|
if (!retry || reason === undefined || !retry.on.includes(reason))
|
|
547
552
|
return outcome;
|
|
@@ -596,8 +601,14 @@ async function dispatchJournaledAttempt(input) {
|
|
|
596
601
|
metadata: { runId: ctx.runId, stepId: plan.stepId, unitId: attemptId },
|
|
597
602
|
});
|
|
598
603
|
const outcome = redactUnitOutcome(await dispatchUnit(request, dispatcher), request.sensitiveValues ?? []);
|
|
599
|
-
|
|
600
|
-
|
|
604
|
+
const finishedAt = new Date().toISOString();
|
|
605
|
+
await enqueueUnitWrite(() => withWorkflowRunsRepo((repo) => repo.immediateTransaction((db) => {
|
|
606
|
+
const run = repo.getRunById(ctx.runId);
|
|
607
|
+
if (run?.status !== "active")
|
|
608
|
+
return;
|
|
609
|
+
if (ctx.leaseHolder !== undefined && run.engine_lease_holder !== ctx.leaseHolder)
|
|
610
|
+
return;
|
|
611
|
+
repo.finishUnit({
|
|
601
612
|
runId: ctx.runId,
|
|
602
613
|
unitId: attemptId,
|
|
603
614
|
status: outcome.ok ? "completed" : "failed",
|
|
@@ -611,21 +622,22 @@ async function dispatchJournaledAttempt(input) {
|
|
|
611
622
|
// Harness-native session id (P2): journaled so resume can replay the
|
|
612
623
|
// harness's own context cache (e.g. `codex exec resume <id>`).
|
|
613
624
|
sessionId: outcome.sessionId ?? null,
|
|
614
|
-
finishedAt
|
|
615
|
-
})
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
625
|
+
finishedAt,
|
|
626
|
+
});
|
|
627
|
+
insertEventStrict(db, {
|
|
628
|
+
eventType: "workflow_unit_finished",
|
|
629
|
+
ts: finishedAt,
|
|
630
|
+
ref: ctx.workflowRef,
|
|
631
|
+
metadata: {
|
|
632
|
+
runId: ctx.runId,
|
|
633
|
+
stepId: plan.stepId,
|
|
634
|
+
unitId: attemptId,
|
|
635
|
+
status: outcome.ok ? "completed" : "failed",
|
|
636
|
+
...(outcome.failureReason ? { failureReason: outcome.failureReason } : {}),
|
|
637
|
+
...(outcome.tokens !== undefined ? { tokens: outcome.tokens } : {}),
|
|
638
|
+
},
|
|
639
|
+
});
|
|
640
|
+
})));
|
|
629
641
|
// Worktree lifecycle epilogue: a CLEAN worktree (`git status --porcelain`
|
|
630
642
|
// empty) is removed; a DIRTY one is retained and logged — the unit left
|
|
631
643
|
// uncollected work, and its journaled worktree_path says where. Cleanup is
|
|
@@ -701,12 +713,12 @@ async function dispatchUnit(request, dispatcher) {
|
|
|
701
713
|
}
|
|
702
714
|
const text = await dispatchOnce();
|
|
703
715
|
// Normalize an EMPTY successful output to "no text". `finishUnit` journals
|
|
704
|
-
// result_json = NULL for a falsy text, so durable-reuse
|
|
705
|
-
//
|
|
706
|
-
//
|
|
707
|
-
//
|
|
708
|
-
//
|
|
709
|
-
//
|
|
716
|
+
// result_json = NULL for a falsy text, so durable-reuse rehydrates NO text
|
|
717
|
+
// from the row (unitOutcomeFromRow). Preserving `text: ""` only in this live
|
|
718
|
+
// outcome would make the LIVE step artifact ("") diverge from the artifact a
|
|
719
|
+
// resume rebuilds from the row (null) — the exact byte-identical-graph
|
|
720
|
+
// violation the cardinal rule forbids. Treating empty as absent keeps live
|
|
721
|
+
// dispatch and engine resume identical.
|
|
710
722
|
return { unitId: request.unitId, ok: true, ...(text ? { text } : {}), ...captured() };
|
|
711
723
|
}
|
|
712
724
|
catch (err) {
|
|
@@ -778,6 +790,7 @@ async function resolveEnvBindings(refs) {
|
|
|
778
790
|
export function buildAgentDispatchRequest(request, prompt) {
|
|
779
791
|
return {
|
|
780
792
|
prompt,
|
|
793
|
+
...(request.systemPrompt ? { systemPrompt: request.systemPrompt } : {}),
|
|
781
794
|
...(request.invocation.model ? { model: request.invocation.model } : {}),
|
|
782
795
|
...(request.invocation.model ? { modelIsExact: true } : {}),
|
|
783
796
|
...(request.schema ? { schema: request.schema } : {}),
|
|
@@ -817,7 +830,13 @@ export const defaultUnitDispatcher = async (request, feedback) => {
|
|
|
817
830
|
const { chatCompletion, LlmCallError } = await import("../../llm/client.js");
|
|
818
831
|
const connection = resolved.connection;
|
|
819
832
|
try {
|
|
820
|
-
const
|
|
833
|
+
const messages = request.systemPrompt
|
|
834
|
+
? [
|
|
835
|
+
{ role: "system", content: request.systemPrompt },
|
|
836
|
+
{ role: "user", content: prompt },
|
|
837
|
+
]
|
|
838
|
+
: [{ role: "user", content: prompt }];
|
|
839
|
+
const text = await chatCompletion(connection, messages, {
|
|
821
840
|
timeoutMs: request.timeoutMs,
|
|
822
841
|
...(request.signal ? { signal: request.signal } : {}),
|
|
823
842
|
// Native structured output where the connection supports it; the
|
|
@@ -923,9 +942,8 @@ function redactUnitOutcome(outcome, sensitiveValues) {
|
|
|
923
942
|
* vocabulary `retry.on` accepts and the journal's `failure_reason` column
|
|
924
943
|
* carries. Exhaustive over the code union (typecheck fails on drift):
|
|
925
944
|
*
|
|
926
|
-
* - `timeout` → `timeout` (wall-clock expiry
|
|
927
|
-
*
|
|
928
|
-
* folds into its timeout code)
|
|
945
|
+
* - `timeout` → `timeout` (wall-clock expiry)
|
|
946
|
+
* - `aborted` → `aborted` (caller/budget cancellation)
|
|
929
947
|
* - `rate_limited` → `llm_rate_limit` (HTTP 429 — the canonical transient)
|
|
930
948
|
* - `parse_error` / `provider_html_error`
|
|
931
949
|
* → `parse_error` (a response arrived but was not the
|
|
@@ -938,6 +956,8 @@ function redactUnitOutcome(outcome, sensitiveValues) {
|
|
|
938
956
|
*/
|
|
939
957
|
export function llmFailureReasonFor(code) {
|
|
940
958
|
switch (code) {
|
|
959
|
+
case "aborted":
|
|
960
|
+
return "aborted";
|
|
941
961
|
case "timeout":
|
|
942
962
|
return "timeout";
|
|
943
963
|
case "rate_limited":
|
|
@@ -1014,8 +1034,8 @@ function materializeFrozenLlm(snapshot, invocation) {
|
|
|
1014
1034
|
* Rehydrate a journaled completed unit row into a UnitOutcome (durable-row
|
|
1015
1035
|
* reuse). Delegates to the shared {@link unitOutcomeFromRow} — the reuse path
|
|
1016
1036
|
* only reaches here for completed rows (the caller guards `status ===
|
|
1017
|
-
* "completed"`), so
|
|
1018
|
-
*
|
|
1037
|
+
* "completed"`), so a reused unit contributes exactly what its original
|
|
1038
|
+
* dispatch did.
|
|
1019
1039
|
*/
|
|
1020
1040
|
function reuseCompletedUnit(unitId, row, hasSchema) {
|
|
1021
1041
|
return unitOutcomeFromRow(unitId, row, hasSchema);
|