akm-cli 0.9.0-rc.1 → 0.9.0-rc.2

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.
Files changed (228) hide show
  1. package/CHANGELOG.md +223 -9
  2. package/SECURITY.md +23 -24
  3. package/dist/assets/help/help-improve.md +10 -10
  4. package/dist/assets/hints/cli-hints-full.md +44 -10
  5. package/dist/assets/hints/cli-hints-short.md +6 -2
  6. package/dist/assets/{profiles → improve-strategies}/default.json +1 -0
  7. package/dist/assets/{profiles → improve-strategies}/graph-refresh.json +1 -1
  8. package/dist/assets/{profiles → improve-strategies}/proactive-maintenance.json +2 -3
  9. package/dist/assets/{profiles → improve-strategies}/reflect-distill.json +3 -4
  10. package/dist/assets/stash-skeleton/README.md +28 -0
  11. package/dist/assets/stash-skeleton/facts/conventions/assets/agent.md +6 -0
  12. package/dist/assets/stash-skeleton/facts/conventions/assets/command.md +6 -0
  13. package/dist/assets/stash-skeleton/facts/conventions/assets/fact.md +12 -1
  14. package/dist/assets/stash-skeleton/facts/conventions/assets/knowledge.md +11 -1
  15. package/dist/assets/stash-skeleton/facts/conventions/assets/lesson.md +6 -0
  16. package/dist/assets/stash-skeleton/facts/conventions/assets/memory.md +9 -0
  17. package/dist/assets/stash-skeleton/facts/conventions/assets/script.md +7 -0
  18. package/dist/assets/stash-skeleton/facts/conventions/assets/skill.md +7 -0
  19. package/dist/assets/stash-skeleton/facts/conventions/assets/workflow.md +6 -0
  20. package/dist/assets/stash-skeleton/facts/conventions/backlinks.md +98 -0
  21. package/dist/assets/stash-skeleton/facts/conventions/domains.md +63 -0
  22. package/dist/assets/stash-skeleton/facts/conventions/organization.md +127 -0
  23. package/dist/assets/tasks/core/backup.yml +1 -0
  24. package/dist/assets/tasks/core/extract.yml +1 -0
  25. package/dist/assets/tasks/core/improve.yml +1 -0
  26. package/dist/assets/tasks/core/index-refresh.yml +1 -0
  27. package/dist/assets/tasks/core/sync.yml +1 -0
  28. package/dist/assets/tasks/core/version-check.yml +1 -0
  29. package/dist/assets/tasks/graph-refresh-weekly.yml +4 -4
  30. package/dist/assets/templates/html/health.html +5 -1
  31. package/dist/cli/config-migrate.js +31 -138
  32. package/dist/cli/config-validate.js +10 -8
  33. package/dist/cli.js +48 -14
  34. package/dist/commands/agent/agent-dispatch.js +17 -16
  35. package/dist/commands/agent/agent-support.js +0 -24
  36. package/dist/commands/agent/contribute-cli.js +5 -15
  37. package/dist/commands/backup-cli.js +54 -0
  38. package/dist/commands/config-cli.js +45 -159
  39. package/dist/commands/env/secret.js +8 -5
  40. package/dist/commands/health/checks.js +130 -83
  41. package/dist/commands/health/html-report.js +4 -0
  42. package/dist/commands/health/improve-metrics.js +30 -32
  43. package/dist/commands/health/llm-usage.js +19 -19
  44. package/dist/commands/health/md-report.js +4 -0
  45. package/dist/commands/health/metrics.js +2 -1
  46. package/dist/commands/health/surfaces.js +5 -4
  47. package/dist/commands/health.js +1 -1
  48. package/dist/commands/improve/consolidate/chunking.js +2 -2
  49. package/dist/commands/improve/consolidate.js +28 -25
  50. package/dist/commands/improve/distill/promote-memory.js +5 -12
  51. package/dist/commands/improve/distill/quality-gate.js +5 -7
  52. package/dist/commands/improve/distill.js +16 -5
  53. package/dist/commands/improve/eligibility.js +22 -12
  54. package/dist/commands/improve/extract-cli.js +47 -19
  55. package/dist/commands/improve/extract.js +110 -62
  56. package/dist/commands/improve/improve-cli.js +38 -16
  57. package/dist/commands/improve/improve-result-file.js +30 -24
  58. package/dist/commands/improve/improve-strategies.js +137 -0
  59. package/dist/commands/improve/improve.js +60 -30
  60. package/dist/commands/improve/locks.js +66 -45
  61. package/dist/commands/improve/loop-stages.js +75 -33
  62. package/dist/commands/improve/memory/memory-belief.js +79 -7
  63. package/dist/commands/improve/memory/memory-contradiction-detect.js +12 -4
  64. package/dist/commands/improve/preparation.js +71 -73
  65. package/dist/commands/improve/procedural.js +3 -2
  66. package/dist/commands/improve/recombine.js +2 -1
  67. package/dist/commands/improve/reflect.js +119 -214
  68. package/dist/commands/improve/shared.js +11 -5
  69. package/dist/commands/lint/base-linter.js +152 -42
  70. package/dist/commands/mv-cli.js +809 -0
  71. package/dist/commands/proposal/proposal-cli.js +18 -8
  72. package/dist/commands/proposal/propose.js +64 -69
  73. package/dist/commands/read/knowledge.js +436 -4
  74. package/dist/commands/read/remember-cli.js +39 -2
  75. package/dist/commands/read/search-cli.js +6 -1
  76. package/dist/commands/registry-cli.js +29 -14
  77. package/dist/commands/remember.js +2 -0
  78. package/dist/commands/sources/init.js +13 -14
  79. package/dist/commands/sources/schema-repair.js +2 -4
  80. package/dist/commands/sources/source-add.js +62 -73
  81. package/dist/commands/sources/source-manage.js +50 -46
  82. package/dist/commands/sources/stash-cli.js +41 -4
  83. package/dist/commands/tasks/default-tasks.js +12 -12
  84. package/dist/commands/tasks/tasks-cli.js +7 -3
  85. package/dist/commands/tasks/tasks.js +113 -18
  86. package/dist/commands/wiki-cli.js +9 -10
  87. package/dist/core/asset/frontmatter.js +12 -2
  88. package/dist/core/common.js +5 -3
  89. package/dist/core/config/config-io.js +28 -17
  90. package/dist/core/config/config-schema.js +358 -66
  91. package/dist/core/config/config-types.js +3 -3
  92. package/dist/core/config/config-version.js +29 -0
  93. package/dist/core/config/config-walker.js +98 -27
  94. package/dist/core/config/config.js +132 -266
  95. package/dist/core/config/deep-merge.js +41 -0
  96. package/dist/core/config/engine-semantics.js +32 -0
  97. package/dist/core/errors.js +2 -2
  98. package/dist/core/extra-params.js +61 -0
  99. package/dist/core/file-lock.js +201 -56
  100. package/dist/core/improve-result.js +178 -0
  101. package/dist/core/maintenance-barrier.js +119 -0
  102. package/dist/core/migration-backup.js +416 -0
  103. package/dist/core/paths.js +3 -0
  104. package/dist/core/redaction.js +358 -0
  105. package/dist/core/state/migrations.js +17 -2
  106. package/dist/core/state-db.js +44 -1
  107. package/dist/indexer/db/db.js +116 -1
  108. package/dist/indexer/graph/graph-extraction.js +28 -16
  109. package/dist/indexer/index-writer-lock.js +31 -24
  110. package/dist/indexer/index-written-assets.js +15 -6
  111. package/dist/indexer/indexer.js +47 -2
  112. package/dist/indexer/passes/memory-inference.js +10 -6
  113. package/dist/indexer/passes/metadata.js +250 -0
  114. package/dist/indexer/search/db-search.js +111 -44
  115. package/dist/indexer/search/fts-query.js +41 -0
  116. package/dist/indexer/search/ranking-contributors.js +48 -0
  117. package/dist/indexer/search/ranking.js +36 -23
  118. package/dist/indexer/search/search-fields.js +11 -1
  119. package/dist/integrations/agent/builder-shared.js +7 -0
  120. package/dist/integrations/agent/builders.js +5 -52
  121. package/dist/integrations/agent/config.js +3 -143
  122. package/dist/integrations/agent/detect.js +17 -2
  123. package/dist/integrations/agent/engine-resolution.js +202 -0
  124. package/dist/integrations/agent/index.js +1 -2
  125. package/dist/integrations/agent/model-aliases.js +7 -2
  126. package/dist/integrations/agent/profiles.js +6 -99
  127. package/dist/integrations/agent/runner-dispatch.js +76 -13
  128. package/dist/integrations/agent/runner.js +76 -207
  129. package/dist/integrations/agent/spawn.js +4 -6
  130. package/dist/integrations/harnesses/aider/agent-builder.js +2 -3
  131. package/dist/integrations/harnesses/aider/index.js +0 -1
  132. package/dist/integrations/harnesses/amazonq/agent-builder.js +2 -3
  133. package/dist/integrations/harnesses/amazonq/index.js +0 -1
  134. package/dist/integrations/harnesses/claude/agent-builder.js +2 -3
  135. package/dist/integrations/harnesses/claude/index.js +0 -2
  136. package/dist/integrations/harnesses/codex/agent-builder.js +2 -3
  137. package/dist/integrations/harnesses/codex/index.js +0 -1
  138. package/dist/integrations/harnesses/copilot/agent-builder.js +2 -3
  139. package/dist/integrations/harnesses/copilot/index.js +0 -1
  140. package/dist/integrations/harnesses/gemini/agent-builder.js +2 -3
  141. package/dist/integrations/harnesses/gemini/index.js +0 -1
  142. package/dist/integrations/harnesses/index.js +1 -24
  143. package/dist/integrations/harnesses/opencode/agent-builder.js +2 -3
  144. package/dist/integrations/harnesses/opencode/index.js +0 -6
  145. package/dist/integrations/harnesses/opencode-sdk/harness.js +1 -6
  146. package/dist/integrations/harnesses/opencode-sdk/sdk-runner.js +274 -191
  147. package/dist/integrations/harnesses/openhands/agent-builder.js +2 -3
  148. package/dist/integrations/harnesses/openhands/index.js +0 -1
  149. package/dist/integrations/harnesses/pi/agent-builder.js +2 -3
  150. package/dist/integrations/harnesses/pi/index.js +0 -1
  151. package/dist/integrations/harnesses/types.js +1 -32
  152. package/dist/integrations/lockfile.js +32 -21
  153. package/dist/llm/client.js +48 -14
  154. package/dist/llm/feature-gate.js +15 -47
  155. package/dist/llm/graph-extract.js +1 -1
  156. package/dist/llm/index-passes.js +8 -42
  157. package/dist/llm/memory-infer-impl.js +1 -1
  158. package/dist/llm/usage-persist.js +4 -0
  159. package/dist/llm/usage-telemetry.js +35 -5
  160. package/dist/output/shapes/helpers.js +2 -1
  161. package/dist/output/shapes/passthrough.js +2 -0
  162. package/dist/output/text/helpers.js +3 -1
  163. package/dist/schemas/akm-config.json +11013 -8600
  164. package/dist/schemas/akm-task.json +87 -0
  165. package/dist/schemas/akm-workflow.json +57 -13
  166. package/dist/scripts/migrate-storage.js +8591 -509
  167. package/dist/scripts/migrations/import-fs-improve-runs-to-db.js +8623 -484
  168. package/dist/setup/detected-engines.js +142 -0
  169. package/dist/setup/engine-config.js +89 -0
  170. package/dist/setup/setup.js +236 -132
  171. package/dist/setup/steps/connection.js +61 -32
  172. package/dist/setup/steps/platforms.js +4 -4
  173. package/dist/setup/steps.js +3 -2
  174. package/dist/storage/database.js +13 -1
  175. package/dist/storage/engines/sqlite-migrations.js +1 -0
  176. package/dist/storage/repositories/improve-runs-repository.js +5 -5
  177. package/dist/storage/repositories/task-history-repository.js +78 -0
  178. package/dist/storage/repositories/workflow-runs-repository.js +9 -8
  179. package/dist/tasks/parser.js +138 -52
  180. package/dist/tasks/runner.js +71 -75
  181. package/dist/tasks/schema.js +1 -1
  182. package/dist/tasks/validator.js +11 -6
  183. package/dist/wiki/wiki.js +9 -8
  184. package/dist/workflows/authoring/workflow-program-template.yaml +3 -3
  185. package/dist/workflows/concurrency-policy.js +15 -0
  186. package/dist/workflows/db.js +65 -13
  187. package/dist/workflows/exec/brief.js +18 -24
  188. package/dist/workflows/exec/frozen-judge.js +47 -0
  189. package/dist/workflows/exec/native-executor.js +124 -65
  190. package/dist/workflows/exec/report.js +93 -33
  191. package/dist/workflows/exec/run-workflow.js +38 -25
  192. package/dist/workflows/exec/scheduler.js +12 -41
  193. package/dist/workflows/exec/step-work.js +91 -35
  194. package/dist/workflows/ir/compile.js +13 -26
  195. package/dist/workflows/ir/freeze.js +243 -0
  196. package/dist/workflows/ir/plan-hash.js +40 -5
  197. package/dist/workflows/ir/schema.js +542 -1
  198. package/dist/workflows/parser.js +7 -0
  199. package/dist/workflows/program/parser.js +132 -23
  200. package/dist/workflows/program/project.js +3 -4
  201. package/dist/workflows/program/schema.js +2 -2
  202. package/dist/workflows/resource-limits.js +20 -0
  203. package/dist/workflows/runtime/plan-classifier.js +187 -0
  204. package/dist/workflows/runtime/runs.js +54 -47
  205. package/dist/workflows/runtime/workflow-asset-loader.js +0 -22
  206. package/dist/workflows/validator.js +25 -0
  207. package/docs/data-and-telemetry.md +2 -2
  208. package/docs/migration/release-notes/0.6.0.md +1 -1
  209. package/docs/migration/release-notes/0.7.0.md +5 -4
  210. package/docs/migration/v0.8-to-v0.9.md +401 -0
  211. package/package.json +4 -2
  212. package/schemas/akm-config.json +16638 -0
  213. package/schemas/akm-task.json +87 -0
  214. package/schemas/akm-workflow.json +372 -0
  215. package/dist/commands/improve/improve-profiles.js +0 -168
  216. package/dist/core/config/config-migration.js +0 -602
  217. package/dist/core/deep-merge.js +0 -38
  218. package/dist/llm/call-ai.js +0 -62
  219. package/dist/setup/legacy-config.js +0 -106
  220. package/docs/README.md +0 -104
  221. /package/dist/assets/{profiles → improve-strategies}/catchup.json +0 -0
  222. /package/dist/assets/{profiles → improve-strategies}/consolidate.json +0 -0
  223. /package/dist/assets/{profiles → improve-strategies}/frequent.json +0 -0
  224. /package/dist/assets/{profiles → improve-strategies}/memory-focus.json +0 -0
  225. /package/dist/assets/{profiles → improve-strategies}/quick.json +0 -0
  226. /package/dist/assets/{profiles → improve-strategies}/recombine-only.json +0 -0
  227. /package/dist/assets/{profiles → improve-strategies}/synthesize.json +0 -0
  228. /package/dist/assets/{profiles → improve-strategies}/thorough.json +0 -0
@@ -4,24 +4,28 @@
4
4
  import { randomUUID } from "node:crypto";
5
5
  import { parseAssetRef } from "../../core/asset/asset-ref.js";
6
6
  import { canonicalizeWorkflowName } from "../../core/asset/asset-spec.js";
7
- import { getDefaultLlmConfig, loadConfig } from "../../core/config/config.js";
7
+ import { loadConfig } from "../../core/config/config.js";
8
8
  import { NotFoundError, UsageError } from "../../core/errors.js";
9
9
  import { appendEvent } from "../../core/events.js";
10
10
  import { warn } from "../../core/warn.js";
11
11
  import { withWorkflowRunsRepo, } from "../../storage/repositories/workflow-runs-repository.js";
12
12
  import { getCurrentWorkflowScopeKey } from "../authoring/scope-key.js";
13
+ import { frozenSummaryJudge } from "../exec/frozen-judge.js";
13
14
  import { detectSecretShapedParams } from "../exec/param-secrets.js";
14
15
  import { collectProgramWarnings } from "../ir/compile.js";
16
+ import { compileResolveFreezeWorkflow } from "../ir/freeze.js";
15
17
  import { validateWorkflowParams } from "../ir/params.js";
16
18
  import { canonicalPlanJson, computePlanHash } from "../ir/plan-hash.js";
19
+ import { decodeWorkflowPlanV3, WORKFLOW_IR_VERSION } from "../ir/schema.js";
17
20
  import { validateStepSummary } from "../validate-summary.js";
18
21
  import { resolveAgentIdentity } from "./agent-identity.js";
19
22
  import { evaluateCheckin } from "./checkin.js";
23
+ import { assertWorkflowSpineMatchesPlan, classifyWorkflowRunPlan, frozenStepRows, requireAbandonableWorkflowPlan, requireExecutableWorkflowPlan, } from "./plan-classifier.js";
20
24
  import { evaluateStaleUnits } from "./unit-checkin.js";
21
- import { compileWorkflowAssetPlan, loadWorkflowAsset, resolveWorkflowEntryId } from "./workflow-asset-loader.js";
25
+ import { loadWorkflowAsset, resolveWorkflowEntryId } from "./workflow-asset-loader.js";
22
26
  /** Clip bound for a unit's `result_json` on the `--units` diagnostic surface. */
23
27
  const UNIT_DIAGNOSTIC_CLIP = 2000;
24
- function toUnitDiagnostic(row, stale) {
28
+ function toUnitDiagnostic(row, stale, plannedEngine) {
25
29
  let diagnostic = null;
26
30
  if (row.result_json !== null) {
27
31
  // `result_json` is a JSON-encoded value: a bare JSON string for a free-text
@@ -55,6 +59,10 @@ function toUnitDiagnostic(row, stale) {
55
59
  staleIdleMs: stale ? (Number.isFinite(stale.idleMs) ? stale.idleMs : null) : null,
56
60
  claimHolder: row.claim_holder,
57
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
+ ...(!row.engine && row.runner ? { legacyRunnerSelector: row.runner } : {}),
58
66
  };
59
67
  }
60
68
  export async function startWorkflowRun(ref, params = {}, options) {
@@ -63,7 +71,7 @@ export async function startWorkflowRun(ref, params = {}, options) {
63
71
  // persist it on the run row in the same transaction as the insert. Every
64
72
  // later invocation executes this snapshot — the asset file is never re-read
65
73
  // for an in-flight run; re-planning is an explicit new run.
66
- const plan = compileWorkflowAssetPlan(asset);
74
+ const plan = decodeWorkflowPlanV3(compileResolveFreezeWorkflow(asset, loadConfig()).plan);
67
75
  // Non-fatal WARNINGS (redesign addendum): a YAML program's untyped-step and
68
76
  // undeclared-param advisories surface as `warn()` lines at start (stderr,
69
77
  // consistent with the repo's other author-facing warnings) without blocking
@@ -89,7 +97,7 @@ export async function startWorkflowRun(ref, params = {}, options) {
89
97
  const now = new Date().toISOString();
90
98
  const runId = randomUUID();
91
99
  const scopeKey = getCurrentWorkflowScopeKey();
92
- const currentStepId = asset.steps[0]?.id ?? null;
100
+ const currentStepId = plan.steps[0]?.stepId ?? null;
93
101
  const workflowEntryId = resolveWorkflowEntryId(asset.sourcePath, asset.ref);
94
102
  // Capture the agent harness + session driving this run. Explicit options
95
103
  // win; otherwise fall back to best-effort environment detection. This is
@@ -128,17 +136,17 @@ export async function startWorkflowRun(ref, params = {}, options) {
128
136
  agentSessionId,
129
137
  checkinArmedAt: now,
130
138
  });
131
- repo.insertSteps(asset.steps.map((step) => ({
139
+ repo.insertSteps(frozenStepRows(plan).map((step) => ({
132
140
  runId,
133
- stepId: step.id,
134
- stepTitle: step.title,
141
+ stepId: step.stepId,
142
+ stepTitle: step.stepTitle,
135
143
  instructions: step.instructions,
136
- completionJson: step.completionCriteria ? JSON.stringify(step.completionCriteria) : null,
137
- sequenceIndex: step.sequenceIndex ?? 0,
144
+ completionJson: step.completionJson,
145
+ sequenceIndex: step.sequenceIndex,
138
146
  })));
139
147
  // Same transaction as the insert: a run row never exists without its
140
148
  // frozen plan (rows with NULL plan_json are pre-006 legacy runs).
141
- repo.setRunPlan(runId, planJson, planHash);
149
+ repo.setRunPlan(runId, planJson, planHash, WORKFLOW_IR_VERSION);
142
150
  });
143
151
  const result = await getWorkflowStatus(runId);
144
152
  // #13: params are declared non-secret (they are copied verbatim into every
@@ -176,7 +184,9 @@ export async function getWorkflowStatus(runId, opts) {
176
184
  // uses (`now` injected for deterministic tests) so a dead driver's claimed
177
185
  // `running` unit surfaces as stale here too, not just as raw `running`.
178
186
  const staleById = new Map(evaluateStaleUnits(rows, opts.now ?? Date.now()).map((u) => [u.unitId, u]));
179
- detail.units = rows.map((row) => toUnitDiagnostic(row, staleById.get(row.unit_id)));
187
+ const classified = classifyWorkflowRunPlan(run);
188
+ const engines = classified.support === "supported" ? classified.plan.execution?.engines : undefined;
189
+ detail.units = rows.map((row) => toUnitDiagnostic(row, staleById.get(row.unit_id), row.engine ? engines?.[row.engine] : undefined));
180
190
  }
181
191
  return detail;
182
192
  });
@@ -207,6 +217,8 @@ export async function getNextWorkflowStep(specifier, params) {
207
217
  return withWorkflowRunsRepo(async (repo) => {
208
218
  const { run, autoStarted } = await resolveRunSpecifier(repo, specifier, params);
209
219
  const steps = readWorkflowRunSteps(repo, run.id);
220
+ const plan = requireExecutableWorkflowPlan(run);
221
+ assertWorkflowSpineMatchesPlan(plan, run, steps);
210
222
  return { ...projectNextResult(run, steps), ...(autoStarted ? { autoStarted: true } : {}) };
211
223
  });
212
224
  }
@@ -255,6 +267,8 @@ export async function snapshotRunForDriver(runId) {
255
267
  return withWorkflowRunsRepo((repo) => repo.transaction(() => {
256
268
  const run = readWorkflowRun(repo, runId);
257
269
  const steps = readWorkflowRunSteps(repo, run.id);
270
+ const plan = requireExecutableWorkflowPlan(run);
271
+ assertWorkflowSpineMatchesPlan(plan, run, steps);
258
272
  const units = repo.getUnitsForRun(run.id);
259
273
  return { next: projectNextResult(run, steps), run, units };
260
274
  }));
@@ -262,11 +276,13 @@ export async function snapshotRunForDriver(runId) {
262
276
  export async function resumeWorkflowRun(runId) {
263
277
  return withWorkflowRunsRepo((repo) => {
264
278
  const run = readWorkflowRun(repo, runId);
279
+ const plan = requireExecutableWorkflowPlan(run);
280
+ const steps = readWorkflowRunSteps(repo, run.id);
281
+ assertWorkflowSpineMatchesPlan(plan, run, steps);
265
282
  if (run.status === "completed") {
266
283
  throw new UsageError(`Workflow run ${run.id} is already completed and cannot be resumed.`);
267
284
  }
268
285
  if (run.status === "active") {
269
- const steps = readWorkflowRunSteps(repo, run.id);
270
286
  return buildWorkflowRunDetail(run, steps);
271
287
  }
272
288
  // blocked or failed → flip back to active and re-open the current step so
@@ -279,8 +295,8 @@ export async function resumeWorkflowRun(runId) {
279
295
  repo.markRunActive(run.id, now);
280
296
  });
281
297
  const updated = { ...run, status: "active", updated_at: now };
282
- const steps = readWorkflowRunSteps(repo, run.id);
283
- return buildWorkflowRunDetail(updated, steps);
298
+ const refreshedSteps = readWorkflowRunSteps(repo, run.id);
299
+ return buildWorkflowRunDetail(updated, refreshedSteps);
284
300
  });
285
301
  }
286
302
  /**
@@ -292,6 +308,11 @@ export async function resumeWorkflowRun(runId) {
292
308
  export async function abandonWorkflowRun(runId) {
293
309
  return withWorkflowRunsRepo((repo) => {
294
310
  const run = readWorkflowRun(repo, runId);
311
+ requireAbandonableWorkflowPlan(run);
312
+ const classified = classifyWorkflowRunPlan(run);
313
+ const existingSteps = readWorkflowRunSteps(repo, run.id);
314
+ if (classified.support === "supported")
315
+ assertWorkflowSpineMatchesPlan(classified.plan, run, existingSteps);
295
316
  if (run.status === "completed" || run.status === "failed") {
296
317
  throw new UsageError(`Workflow run ${run.id} is already ${run.status}.`);
297
318
  }
@@ -324,6 +345,9 @@ export async function completeWorkflowStep(input) {
324
345
  // the write transaction — a slow/hung LLM must never hold a db write lock.
325
346
  const preflight = await withWorkflowRunsRepo((repo) => {
326
347
  const run = readWorkflowRun(repo, input.runId);
348
+ const plan = requireExecutableWorkflowPlan(run);
349
+ const steps = readWorkflowRunSteps(repo, run.id);
350
+ assertWorkflowSpineMatchesPlan(plan, run, steps);
327
351
  if (run.status !== "active") {
328
352
  throw new UsageError(`Workflow run ${run.id} is ${run.status} and cannot be updated.`);
329
353
  }
@@ -338,7 +362,10 @@ export async function completeWorkflowStep(input) {
338
362
  if (run.current_step_id !== existing.step_id) {
339
363
  throw new UsageError(`Step "${input.stepId}" is not the current step for workflow run ${run.id}. Complete "${run.current_step_id}" first.`);
340
364
  }
341
- return { existing };
365
+ const stepPlan = plan.steps.find((step) => step.stepId === input.stepId);
366
+ if (!stepPlan)
367
+ throw new NotFoundError(`Step "${input.stepId}" was not found in workflow run ${run.id}.`);
368
+ return { existing, plan, stepPlan };
342
369
  });
343
370
  const summary = input.summary?.trim();
344
371
  // #506: completing a step requires a summary of the work done.
@@ -349,9 +376,11 @@ export async function completeWorkflowStep(input) {
349
376
  // completionCriteria via the configured LLM. Fail-open when no criteria or no
350
377
  // judge. Only a well-formed `complete: false` blocks completion.
351
378
  if (input.status === "completed" && summary) {
352
- const criteria = parseJsonArray(preflight.existing.completion_json) ?? [];
353
- const judge = input.summaryJudge === undefined ? buildDefaultSummaryJudge() : input.summaryJudge;
354
- const verdict = await validateStepSummary({ stepTitle: preflight.existing.step_title, completionCriteria: criteria, summary }, judge ?? undefined, { required: input.requireGate === true });
379
+ const criteria = preflight.stepPlan.gate.criteria;
380
+ const judge = input.summaryJudge === undefined
381
+ ? frozenSummaryJudge(preflight.plan, preflight.stepPlan.gate.judge)
382
+ : input.summaryJudge;
383
+ const verdict = await validateStepSummary({ stepTitle: preflight.stepPlan.title, completionCriteria: criteria, summary }, judge ?? undefined, { required: input.requireGate === true });
355
384
  if (!verdict.complete) {
356
385
  // Re-arm the check-in so a subsequent stall is still nudged, but leave the
357
386
  // step pending and return corrective feedback instead of completing.
@@ -375,6 +404,9 @@ export async function completeWorkflowStep(input) {
375
404
  let refreshedSteps = [];
376
405
  repo.transaction(() => {
377
406
  const run = readWorkflowRun(repo, input.runId);
407
+ const plan = requireExecutableWorkflowPlan(run);
408
+ const spine = readWorkflowRunSteps(repo, run.id);
409
+ assertWorkflowSpineMatchesPlan(plan, run, spine);
378
410
  if (run.status !== "active") {
379
411
  throw new UsageError(`Workflow run ${run.id} is ${run.status} and cannot be updated.`);
380
412
  }
@@ -500,6 +532,7 @@ function buildWorkflowRunDetail(run, steps) {
500
532
  };
501
533
  }
502
534
  function toWorkflowRunSummary(run) {
535
+ const plan = classifyWorkflowRunPlan(run);
503
536
  return {
504
537
  id: run.id,
505
538
  workflowRef: run.workflow_ref,
@@ -514,6 +547,8 @@ function toWorkflowRunSummary(run) {
514
547
  params: parseJsonObject(run.params_json),
515
548
  agentHarness: run.agent_harness ?? null,
516
549
  agentSessionId: run.agent_session_id ?? null,
550
+ planIrVersion: plan.irVersion,
551
+ executionSupport: plan.support,
517
552
  // Surface the engine lease (holder id + expiry — never workflow-authored
518
553
  // content) so `workflow next`/`status` show who is driving the run.
519
554
  ...(run.engine_lease_holder && run.engine_lease_until
@@ -579,34 +614,6 @@ function deriveRunState(steps) {
579
614
  .at(-1);
580
615
  return { status: "completed", currentStepId: null, completedAt: completedAt ?? null };
581
616
  }
582
- /**
583
- * Build the default summary-validation judge from the configured LLM, or return
584
- * `null` when no LLM is configured (gate is then skipped — fail-open). Lazily
585
- * imports the client/config so the workflow engine has no hard LLM dependency.
586
- *
587
- * Exported for the engine loop (`exec/run-workflow.ts`), which wraps the judge
588
- * to journal engine-driven gate evaluations as unit rows (addendum R2).
589
- */
590
- export function buildDefaultSummaryJudge() {
591
- let llm;
592
- try {
593
- const config = loadConfig();
594
- llm = getDefaultLlmConfig(config);
595
- }
596
- catch {
597
- return null;
598
- }
599
- if (!llm)
600
- return null;
601
- const resolved = llm;
602
- return async ({ system, user }) => {
603
- const { chatCompletion } = await import("../../llm/client.js");
604
- return chatCompletion(resolved, [
605
- { role: "system", content: system },
606
- { role: "user", content: user },
607
- ]);
608
- };
609
- }
610
617
  function parseJsonObject(value) {
611
618
  if (!value)
612
619
  return undefined;
@@ -12,31 +12,9 @@ import { resolveSourcesForOrigin } from "../../registry/origin-resolve.js";
12
12
  import { resolveAssetPath } from "../../sources/resolve.js";
13
13
  import { withIndexDb } from "../../storage/repositories/index-db.js";
14
14
  import { formatWorkflowErrors } from "../authoring/authoring.js";
15
- import { compileWorkflowPlan, compileWorkflowProgram } from "../ir/compile.js";
16
15
  import { parseWorkflow } from "../parser.js";
17
16
  import { parseWorkflowProgram } from "../program/parser.js";
18
17
  import { isWorkflowProgramPath, projectProgramParameters, projectProgramStepDefinitions } from "../program/project.js";
19
- /**
20
- * Compile a loaded workflow asset into the plan graph that gets frozen on the
21
- * run row. YAML programs compile via `compileWorkflowProgram` with full
22
- * expression validation; markdown documents compile via `compileWorkflowPlan`
23
- * (linear workflows — the stable contract — produce the same linear plan as
24
- * today). Exactly one of `program` / `document` is set by this loader.
25
- */
26
- export function compileWorkflowAssetPlan(asset) {
27
- if (asset.program) {
28
- const compiled = compileWorkflowProgram(asset.program);
29
- if (!compiled.ok) {
30
- throw new UsageError(formatWorkflowErrors(asset.path, compiled.errors));
31
- }
32
- return compiled.plan;
33
- }
34
- if (asset.document) {
35
- return compileWorkflowPlan(asset.document);
36
- }
37
- // Unreachable for assets produced by loadWorkflowAsset; guards hand-built ones.
38
- throw new UsageError(`Workflow asset ${asset.ref} carries neither a parsed document nor a program to compile.`);
39
- }
40
18
  /**
41
19
  * Resolve a `workflow:<name>` ref to a fully-projected {@link WorkflowAsset}.
42
20
  *
@@ -1,12 +1,37 @@
1
1
  // This Source Code Form is subject to the terms of the Mozilla Public
2
2
  // License, v. 2.0. If a copy of the MPL was not distributed with this
3
3
  // file, You can obtain one at https://mozilla.org/MPL/2.0/.
4
+ /**
5
+ * Cross-cutting semantic checks over an assembled WorkflowDocument draft.
6
+ *
7
+ * The parser handles per-line shape checks; this module runs rules that need
8
+ * the whole document or the raw frontmatter at once: duplicate step IDs,
9
+ * step-id format, and the frontmatter key whitelist.
10
+ */
11
+ import { utf8Bytes, WORKFLOW_MAX_INSTRUCTION_BYTES, WORKFLOW_MAX_PARAMS, WORKFLOW_MAX_STEPS } from "./resource-limits.js";
4
12
  const STEP_ID_REGEX = /^[A-Za-z0-9][A-Za-z0-9._-]*$/;
5
13
  const ALLOWED_FRONTMATTER_KEYS = new Set(["description", "tags", "params", "name", "updated", "when_to_use"]);
6
14
  export function runSemanticChecks(draft, frontmatterData, frontmatterEndLine, errors) {
7
15
  checkFrontmatterKeys(frontmatterData, frontmatterEndLine, errors);
8
16
  checkStepIdFormat(draft, errors);
9
17
  checkDuplicateStepIds(draft, errors);
18
+ checkResourceLimits(draft, errors);
19
+ }
20
+ function checkResourceLimits(draft, errors) {
21
+ if (draft.steps.length > WORKFLOW_MAX_STEPS) {
22
+ errors.push({ line: 1, message: `Workflow must contain at most ${WORKFLOW_MAX_STEPS} steps.` });
23
+ }
24
+ if ((draft.parameters?.length ?? 0) > WORKFLOW_MAX_PARAMS) {
25
+ errors.push({ line: 1, message: `Workflow must contain at most ${WORKFLOW_MAX_PARAMS} parameters.` });
26
+ }
27
+ for (const step of draft.steps) {
28
+ if (utf8Bytes(step.instructions.text) > WORKFLOW_MAX_INSTRUCTION_BYTES) {
29
+ errors.push({
30
+ line: step.instructions.source.start,
31
+ message: `Step "${step.id}" instructions exceed the 256 KiB resource limit.`,
32
+ });
33
+ }
34
+ }
10
35
  }
11
36
  function checkFrontmatterKeys(data, fmEndLine, errors) {
12
37
  for (const key of Object.keys(data)) {
@@ -26,7 +26,7 @@ AKM writes to these locations on your machine. All paths follow [XDG Base Direct
26
26
 
27
27
  | Path | Contents | Safe to delete? |
28
28
  |---|---|---|
29
- | `config.json` | Your AKM configuration: LLM endpoints, stash paths, feature flags, profiles | **No** — deleting resets all settings |
29
+ | `config.json` | Your AKM configuration: engines, strategies, stash paths, and feature settings | **No** — deleting resets all settings |
30
30
 
31
31
  Override: set `AKM_CONFIG_DIR` or `XDG_CONFIG_HOME`.
32
32
 
@@ -109,7 +109,7 @@ An append-only log of every mutating action you perform with AKM. Events are sto
109
109
  | `select` | `akm show` after a search returning the same ref | `ref`, `entryId` |
110
110
  | `promoted` | `akm proposal accept <id>` | `ref` |
111
111
  | `rejected` | `akm proposal reject <id>` | `ref` |
112
- | `reflect_invoked` | Start of reflect phase in `akm improve` | `ref`, profile |
112
+ | `reflect_invoked` | Start of reflect phase in `akm improve` | `ref`, engine |
113
113
  | `reflect_completed` | Reflect phase produced a proposal | `ref` |
114
114
  | `improve_reflect_outcome` | Per-asset reflect result | `ref`, `ok`, `durationMs`, `reason` |
115
115
  | `propose_invoked` | `akm propose` | `ref` |
@@ -90,7 +90,7 @@ vault | wiki | enable | disable | completions | upgrade | save | help |
90
90
  hints
91
91
 
92
92
  Full migration guides:
93
- - https://github.com/itlackey/akm/blob/main/docs/migration/v1.md (v1
93
+ - https://github.com/itlackey/akm/blob/main/docs/archive/pre-1.0-migration.md (pre-1.0
94
94
  architecture refactor — read this first if you are coming from 0.5.x or
95
95
  an earlier 0.6 pre-release)
96
96
  - https://github.com/itlackey/akm/blob/main/docs/migration/v0.5-to-v0.6.md
@@ -13,7 +13,7 @@ grammar continue to match the v1 architecture spec
13
13
  pre-releases — the formal freeze itself happens at 1.0 GA.
14
14
 
15
15
  If you are coming from 0.6.x, the
16
- [v1 migration guide](../v1.md) covers the per-surface delta and is the
16
+ [archived pre-1.0 migration plan](../../archive/pre-1.0-migration.md) covers the historical per-surface delta and is the
17
17
  canonical upgrade reference. This file is the executive summary of
18
18
  what's new in 0.7.0.
19
19
 
@@ -47,7 +47,8 @@ akm proposal reject <id> --reason "…" # archive with reason
47
47
  Multiple proposals for the same `ref` coexist without filesystem
48
48
  collisions. Auto-accept is gated per-source via the source config
49
49
  (`autoAcceptProposals: true`); the default is off and requires a
50
- writable source. See v1 spec §11 and `docs/migration/v1.md`.
50
+ writable source. See the archived pre-1.0 migration spec §11 at
51
+ `docs/archive/pre-1.0-migration.md`.
51
52
 
52
53
  ### `akm reflect`, `akm propose`, `akm distill` — new CLI surfaces (#225, #226, #227)
53
54
 
@@ -141,7 +142,7 @@ The bench technical reference lives in
141
142
  - Earlier 0.7.x pre-release work (#220–#223) finalised the registry
142
143
  curation surface removal, classification pipeline rewrites, and
143
144
  error envelope shape that 0.7.0 ships. Operators upgrading from a
144
- 0.6.x baseline should read [`docs/migration/v1.md`](../v1.md) for
145
+ 0.6.x baseline should read the [archived pre-1.0 plan](../../archive/pre-1.0-migration.md) for
145
146
  the per-surface migration recipe.
146
147
 
147
148
  ### CLI surface as of 0.7.0
@@ -257,7 +258,7 @@ akm proposal accept <id>
257
258
 
258
259
  ## Full migration guides
259
260
 
260
- - [v1 migration guide](../v1.md) — per-surface delta from any 0.6.x
261
+ - [Archived pre-1.0 migration plan](../../archive/pre-1.0-migration.md) — per-surface delta from any 0.6.x
261
262
  baseline. The canonical reference for upgrading.
262
263
  - [v0.5 → v0.6](../v0.5-to-v0.6.md) — the older terminology cut and
263
264
  registry schema v3.