akm-cli 0.8.6 → 0.8.14

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 (324) hide show
  1. package/CHANGELOG.md +442 -0
  2. package/dist/assets/help/help-proposals.md +1 -2
  3. package/dist/assets/hints/cli-hints-full.md +34 -19
  4. package/dist/assets/hints/cli-hints-short.md +1 -1
  5. package/dist/assets/profiles/catchup.json +13 -0
  6. package/dist/assets/profiles/consolidate.json +13 -0
  7. package/dist/assets/profiles/frequent.json +13 -0
  8. package/dist/assets/tasks/core/backup.yml +4 -0
  9. package/dist/assets/tasks/core/extract.yml +4 -0
  10. package/dist/assets/tasks/core/improve.yml +4 -0
  11. package/dist/assets/tasks/core/index-refresh.yml +4 -0
  12. package/dist/assets/tasks/core/sync.yml +4 -0
  13. package/dist/assets/tasks/core/update-stashes.yml +4 -0
  14. package/dist/assets/tasks/core/version-check.yml +4 -0
  15. package/dist/assets/templates/html/default.html +78 -0
  16. package/dist/assets/templates/html/health.html +560 -0
  17. package/dist/assets/templates/html/vendor/echarts.min.js +45 -0
  18. package/dist/cli/config-migrate.js +6 -6
  19. package/dist/cli/config-validate.js +4 -4
  20. package/dist/cli/confirm.js +3 -3
  21. package/dist/cli/parse-args.js +1 -1
  22. package/dist/cli/shared.js +72 -19
  23. package/dist/cli-node.mjs +26 -0
  24. package/dist/cli.js +206 -3866
  25. package/dist/commands/{agent-dispatch.js → agent/agent-dispatch.js} +6 -6
  26. package/dist/commands/{agent-support.js → agent/agent-support.js} +2 -2
  27. package/dist/commands/agent/contribute-cli.js +200 -0
  28. package/dist/commands/completions.js +1 -1
  29. package/dist/commands/config-cli.js +230 -3
  30. package/dist/commands/db-cli.js +2 -2
  31. package/dist/commands/env/env-cli.js +529 -0
  32. package/dist/commands/env/env.js +410 -0
  33. package/dist/commands/env/secret-cli.js +259 -0
  34. package/dist/commands/{secret.js → env/secret.js} +6 -47
  35. package/dist/commands/events.js +4 -4
  36. package/dist/commands/feedback-cli.js +18 -34
  37. package/dist/commands/graph/graph-cli.js +132 -0
  38. package/dist/commands/{graph.js → graph/graph.js} +22 -16
  39. package/dist/commands/health/checks.js +279 -0
  40. package/dist/commands/health/html-report.js +448 -0
  41. package/dist/commands/health.js +189 -266
  42. package/dist/commands/{consolidate.js → improve/consolidate.js} +63 -38
  43. package/dist/commands/{distill-promotion-policy.js → improve/distill-promotion-policy.js} +3 -3
  44. package/dist/commands/{distill.js → improve/distill.js} +39 -18
  45. package/dist/commands/{eval-cases.js → improve/eval-cases.js} +1 -1
  46. package/dist/commands/{extract-cli.js → improve/extract-cli.js} +4 -4
  47. package/dist/commands/{extract-prompt.js → improve/extract-prompt.js} +2 -2
  48. package/dist/commands/{extract.js → improve/extract.js} +221 -26
  49. package/dist/commands/{improve-auto-accept.js → improve/improve-auto-accept.js} +30 -4
  50. package/dist/commands/{improve-cli.js → improve/improve-cli.js} +44 -22
  51. package/dist/commands/{improve-profiles.js → improve/improve-profiles.js} +13 -7
  52. package/dist/commands/{improve-result-file.js → improve/improve-result-file.js} +1 -1
  53. package/dist/commands/{improve.js → improve/improve.js} +672 -292
  54. package/dist/{core → commands/improve/memory}/memory-belief.js +2 -2
  55. package/dist/{core → commands/improve/memory}/memory-contradiction-detect.js +5 -5
  56. package/dist/{core → commands/improve/memory}/memory-improve.js +4 -4
  57. package/dist/commands/improve/reflect-noise.js +0 -0
  58. package/dist/commands/{reflect.js → improve/reflect.js} +58 -28
  59. package/dist/commands/improve/session-asset.js +248 -0
  60. package/dist/commands/lint/agent-linter.js +1 -1
  61. package/dist/commands/lint/base-linter.js +55 -37
  62. package/dist/commands/lint/command-linter.js +1 -1
  63. package/dist/commands/lint/default-linter.js +1 -1
  64. package/dist/commands/lint/env-key-rules.js +1 -1
  65. package/dist/commands/lint/index.js +19 -25
  66. package/dist/commands/lint/knowledge-linter.js +1 -1
  67. package/dist/commands/lint/memory-linter.js +1 -1
  68. package/dist/commands/lint/registry.js +8 -8
  69. package/dist/commands/lint/skill-linter.js +1 -1
  70. package/dist/commands/lint/task-linter.js +1 -1
  71. package/dist/commands/lint/workflow-linter.js +1 -1
  72. package/dist/commands/lint.js +1 -1
  73. package/dist/commands/observability-cli.js +244 -0
  74. package/dist/commands/proposal/drain-policies.js +3 -3
  75. package/dist/commands/proposal/drain.js +87 -15
  76. package/dist/commands/proposal/proposal-cli.js +490 -0
  77. package/dist/commands/{proposal.js → proposal/proposal.js} +17 -6
  78. package/dist/commands/{propose.js → proposal/propose.js} +11 -11
  79. package/dist/{core → commands/proposal/validators}/proposal-quality-validators.js +8 -3
  80. package/dist/{core → commands/proposal/validators}/proposal-validators.js +5 -5
  81. package/dist/{core → commands/proposal/validators}/proposals.js +374 -345
  82. package/dist/commands/{curate.js → read/curate.js} +7 -7
  83. package/dist/commands/{knowledge.js → read/knowledge.js} +22 -9
  84. package/dist/commands/{registry-search.js → read/registry-search.js} +5 -5
  85. package/dist/commands/{remember-cli.js → read/remember-cli.js} +15 -7
  86. package/dist/commands/read/search-cli.js +207 -0
  87. package/dist/commands/{search.js → read/search.js} +22 -27
  88. package/dist/commands/{show.js → read/show.js} +31 -45
  89. package/dist/commands/registry-cli.js +8 -8
  90. package/dist/commands/remember.js +14 -10
  91. package/dist/commands/sources/add-cli.js +293 -0
  92. package/dist/commands/{history.js → sources/history.js} +27 -25
  93. package/dist/commands/{info.js → sources/info.js} +6 -6
  94. package/dist/commands/{init.js → sources/init.js} +6 -6
  95. package/dist/commands/{installed-stashes.js → sources/installed-stashes.js} +12 -12
  96. package/dist/commands/{migration-help.js → sources/migration-help.js} +3 -2
  97. package/dist/commands/{schema-repair.js → sources/schema-repair.js} +8 -8
  98. package/dist/commands/{self-update.js → sources/self-update.js} +10 -9
  99. package/dist/commands/{source-add.js → sources/source-add.js} +10 -10
  100. package/dist/commands/{source-clone.js → sources/source-clone.js} +7 -7
  101. package/dist/commands/{source-manage.js → sources/source-manage.js} +4 -4
  102. package/dist/commands/sources/sources-cli.js +305 -0
  103. package/dist/commands/sources/stash-cli.js +219 -0
  104. package/dist/commands/{stash-skeleton.js → sources/stash-skeleton.js} +2 -1
  105. package/dist/commands/tasks/default-tasks.js +173 -0
  106. package/dist/commands/tasks/tasks-cli.js +210 -0
  107. package/dist/commands/{tasks.js → tasks/tasks.js} +14 -14
  108. package/dist/commands/wiki-cli.js +307 -0
  109. package/dist/commands/workflow-cli.js +329 -0
  110. package/dist/core/action-contributors.js +1 -1
  111. package/dist/core/assert.js +40 -0
  112. package/dist/core/asset/asset-create.js +54 -0
  113. package/dist/core/{asset-ref.js → asset/asset-ref.js} +21 -4
  114. package/dist/core/{asset-registry.js → asset/asset-registry.js} +3 -3
  115. package/dist/core/{asset-spec.js → asset/asset-spec.js} +17 -31
  116. package/dist/core/{markdown.js → asset/markdown.js} +1 -1
  117. package/dist/core/{stash-meta.js → asset/stash-meta.js} +1 -1
  118. package/dist/core/best-effort.js +64 -0
  119. package/dist/core/common.js +32 -18
  120. package/dist/core/{config-io.js → config/config-io.js} +29 -19
  121. package/dist/core/{config-migration.js → config/config-migration.js} +11 -9
  122. package/dist/core/{config-schema.js → config/config-schema.js} +50 -7
  123. package/dist/core/config/config-types.js +16 -0
  124. package/dist/core/{config-walker.js → config/config-walker.js} +2 -2
  125. package/dist/core/{config.js → config/config.js} +10 -8
  126. package/dist/core/env-secret-ref.js +90 -0
  127. package/dist/core/errors.js +13 -3
  128. package/dist/core/events.js +27 -4
  129. package/dist/core/file-lock.js +1 -1
  130. package/dist/core/improve-types.js +48 -0
  131. package/dist/core/lesson-lint.js +2 -2
  132. package/dist/core/logs-db.js +304 -0
  133. package/dist/core/paths.js +2 -2
  134. package/dist/core/ripgrep/install.js +2 -2
  135. package/dist/core/ripgrep/resolve.js +2 -2
  136. package/dist/core/state-db.js +195 -60
  137. package/dist/core/text-truncation.js +148 -0
  138. package/dist/core/time.js +1 -1
  139. package/dist/core/write-source.js +98 -85
  140. package/dist/indexer/{db-backup.js → db/db-backup.js} +9 -24
  141. package/dist/indexer/{db.js → db/db.js} +128 -118
  142. package/dist/indexer/{graph-db.js → db/graph-db.js} +9 -4
  143. package/dist/indexer/{llm-cache.js → db/llm-cache.js} +15 -12
  144. package/dist/indexer/ensure-index.js +4 -4
  145. package/dist/indexer/{graph-boost.js → graph/graph-boost.js} +1 -1
  146. package/dist/indexer/{graph-extraction.js → graph/graph-extraction.js} +55 -13
  147. package/dist/indexer/indexer.js +37 -30
  148. package/dist/indexer/init.js +54 -0
  149. package/dist/indexer/manifest.js +10 -10
  150. package/dist/indexer/{memory-inference.js → passes/memory-inference.js} +141 -33
  151. package/dist/indexer/{metadata-contributors.js → passes/metadata-contributors.js} +10 -8
  152. package/dist/indexer/{metadata.js → passes/metadata.js} +15 -19
  153. package/dist/indexer/{staleness-detect.js → passes/staleness-detect.js} +53 -12
  154. package/dist/indexer/{db-search.js → search/db-search.js} +28 -16
  155. package/dist/indexer/{ranking-contributors.js → search/ranking-contributors.js} +1 -1
  156. package/dist/indexer/{ranking.js → search/ranking.js} +2 -2
  157. package/dist/indexer/{search-hit-enrichers.js → search/search-hit-enrichers.js} +3 -3
  158. package/dist/indexer/{search-source.js → search/search-source.js} +8 -8
  159. package/dist/indexer/{semantic-status.js → search/semantic-status.js} +3 -3
  160. package/dist/indexer/usage/unmigrated-vaults-guard.js +94 -0
  161. package/dist/indexer/{usage-events.js → usage/usage-events.js} +32 -0
  162. package/dist/indexer/{file-context.js → walk/file-context.js} +10 -15
  163. package/dist/indexer/{matchers.js → walk/matchers.js} +13 -9
  164. package/dist/indexer/{path-resolver.js → walk/path-resolver.js} +6 -6
  165. package/dist/indexer/{project-context.js → walk/project-context.js} +1 -1
  166. package/dist/indexer/{walker.js → walk/walker.js} +4 -3
  167. package/dist/integrations/agent/builder-shared.js +39 -0
  168. package/dist/integrations/agent/builders.js +14 -81
  169. package/dist/integrations/agent/config.js +6 -4
  170. package/dist/integrations/agent/detect.js +1 -1
  171. package/dist/integrations/agent/index.js +23 -8
  172. package/dist/integrations/agent/prompts.js +2 -3
  173. package/dist/integrations/agent/runner.js +22 -3
  174. package/dist/integrations/agent/spawn.js +9 -10
  175. package/dist/integrations/harnesses/claude/agent-builder.js +48 -0
  176. package/dist/integrations/harnesses/claude/config-import.js +70 -0
  177. package/dist/integrations/harnesses/claude/index.js +64 -0
  178. package/dist/integrations/{session-logs/providers/claude-code.js → harnesses/claude/session-log.js} +32 -5
  179. package/dist/integrations/harnesses/index.js +144 -0
  180. package/dist/integrations/harnesses/opencode/agent-builder.js +43 -0
  181. package/dist/integrations/harnesses/opencode/config-import.js +82 -0
  182. package/dist/integrations/harnesses/opencode/index.js +59 -0
  183. package/dist/integrations/{session-logs/providers/opencode.js → harnesses/opencode/session-log.js} +1 -1
  184. package/dist/integrations/harnesses/opencode-sdk/index.js +49 -0
  185. package/dist/integrations/harnesses/opencode-sdk/sdk-runner.js +234 -0
  186. package/dist/integrations/harnesses/types.js +43 -0
  187. package/dist/integrations/lockfile.js +7 -16
  188. package/dist/integrations/session-logs/index.js +82 -9
  189. package/dist/llm/call-ai.js +4 -4
  190. package/dist/llm/client.js +146 -6
  191. package/dist/llm/embedder.js +6 -6
  192. package/dist/llm/embedders/local.js +9 -22
  193. package/dist/llm/embedders/remote.js +2 -2
  194. package/dist/llm/embedders/types.js +1 -1
  195. package/dist/llm/graph-extract.js +31 -12
  196. package/dist/llm/index-passes.js +1 -1
  197. package/dist/llm/memory-infer.js +12 -5
  198. package/dist/llm/metadata-enhance.js +2 -2
  199. package/dist/llm/usage-persist.js +77 -0
  200. package/dist/llm/usage-telemetry.js +103 -0
  201. package/dist/output/context.js +9 -46
  202. package/dist/output/html-render.js +73 -0
  203. package/dist/output/renderers.js +88 -58
  204. package/dist/output/shapes/curate.js +7 -3
  205. package/dist/output/shapes/distill.js +7 -3
  206. package/dist/output/shapes/env-list.js +18 -16
  207. package/dist/output/shapes/events.js +5 -4
  208. package/dist/output/shapes/helpers.js +19 -5
  209. package/dist/output/shapes/history.js +7 -3
  210. package/dist/output/shapes/passthrough.js +8 -11
  211. package/dist/output/shapes/{proposal-accept.js → proposal/accept.js} +7 -3
  212. package/dist/output/shapes/{proposal-diff.js → proposal/diff.js} +7 -3
  213. package/dist/output/shapes/{proposal-list.js → proposal/list.js} +7 -3
  214. package/dist/output/shapes/{proposal-producer.js → proposal/producer.js} +5 -4
  215. package/dist/output/shapes/{proposal-reject.js → proposal/reject.js} +7 -3
  216. package/dist/output/shapes/{proposal-show.js → proposal/show.js} +7 -3
  217. package/dist/output/shapes/registry-search.js +7 -3
  218. package/dist/output/shapes/registry.js +12 -0
  219. package/dist/output/shapes/search.js +7 -3
  220. package/dist/output/shapes/secret-list.js +18 -16
  221. package/dist/output/shapes/show.js +7 -3
  222. package/dist/output/shapes.js +55 -30
  223. package/dist/output/text/add.js +2 -3
  224. package/dist/output/text/clone.js +2 -3
  225. package/dist/output/text/config.js +2 -3
  226. package/dist/output/text/curate.js +4 -3
  227. package/dist/output/text/distill.js +2 -3
  228. package/dist/output/text/enable-disable.js +5 -4
  229. package/dist/output/text/env.js +13 -0
  230. package/dist/output/text/events.js +5 -4
  231. package/dist/output/text/feedback.js +4 -3
  232. package/dist/output/text/helpers.js +123 -40
  233. package/dist/output/text/history.js +2 -3
  234. package/dist/output/text/import.js +2 -3
  235. package/dist/output/text/index.js +2 -3
  236. package/dist/output/text/info.js +2 -3
  237. package/dist/output/text/init.js +2 -3
  238. package/dist/output/text/list.js +2 -3
  239. package/dist/output/text/proposal/producer.js +9 -0
  240. package/dist/output/text/proposal/proposal.js +13 -0
  241. package/dist/output/text/registry-commands.js +8 -7
  242. package/dist/output/text/registry.js +12 -0
  243. package/dist/output/text/remember.js +4 -3
  244. package/dist/output/text/remove.js +2 -3
  245. package/dist/output/text/save.js +2 -3
  246. package/dist/output/text/search.js +4 -3
  247. package/dist/output/text/show.js +4 -3
  248. package/dist/output/text/update.js +2 -3
  249. package/dist/output/text/upgrade.js +2 -3
  250. package/dist/output/text/wiki.js +12 -11
  251. package/dist/output/text/workflow.js +12 -10
  252. package/dist/output/text.js +66 -32
  253. package/dist/registry/build-index.js +11 -10
  254. package/dist/registry/factory.js +1 -1
  255. package/dist/registry/origin-resolve.js +1 -1
  256. package/dist/registry/providers/index.js +2 -2
  257. package/dist/registry/providers/skills-sh.js +91 -72
  258. package/dist/registry/providers/static-index.js +75 -52
  259. package/dist/registry/resolve.js +3 -3
  260. package/dist/runtime.js +242 -0
  261. package/dist/scripts/migrate-storage.js +1654 -683
  262. package/dist/scripts/migrations/import-fs-improve-runs-to-db.js +254 -168
  263. package/dist/setup/detect.js +311 -9
  264. package/dist/setup/harness-config-import.js +6 -120
  265. package/dist/setup/setup.js +454 -43
  266. package/dist/sources/include.js +1 -1
  267. package/dist/sources/provider-factory.js +2 -2
  268. package/dist/sources/providers/filesystem.js +3 -3
  269. package/dist/sources/providers/git.js +9 -9
  270. package/dist/sources/providers/index.js +4 -4
  271. package/dist/sources/providers/npm.js +6 -6
  272. package/dist/sources/providers/provider-utils.js +13 -20
  273. package/dist/sources/providers/sync-from-ref.js +5 -5
  274. package/dist/sources/providers/tar-utils.js +2 -2
  275. package/dist/sources/providers/website.js +2 -2
  276. package/dist/sources/resolve.js +5 -5
  277. package/dist/sources/website-ingest.js +5 -5
  278. package/dist/storage/database.js +102 -0
  279. package/dist/storage/engines/sqlite-migrations.js +42 -0
  280. package/dist/storage/locations.js +25 -0
  281. package/dist/storage/repositories/index-db.js +43 -0
  282. package/dist/storage/repositories/workflow-runs-repository.js +141 -0
  283. package/dist/tasks/backends/cron.js +4 -4
  284. package/dist/tasks/backends/exec-utils.js +32 -0
  285. package/dist/tasks/backends/index.js +3 -3
  286. package/dist/tasks/backends/launchd.js +7 -14
  287. package/dist/tasks/backends/schtasks.js +7 -16
  288. package/dist/tasks/embedded.js +71 -0
  289. package/dist/tasks/parser.js +2 -2
  290. package/dist/tasks/resolveAkmBin.js +1 -1
  291. package/dist/tasks/runner.js +127 -31
  292. package/dist/tasks/schedule.js +1 -1
  293. package/dist/tasks/validator.js +7 -7
  294. package/dist/text-import-hook.mjs +51 -0
  295. package/dist/version.js +2 -1
  296. package/dist/wiki/wiki.js +7 -7
  297. package/dist/workflows/{authoring.js → authoring/authoring.js} +6 -6
  298. package/dist/workflows/{scope-key.js → authoring/scope-key.js} +1 -1
  299. package/dist/workflows/cli.js +1 -1
  300. package/dist/workflows/db.js +54 -32
  301. package/dist/workflows/parser.js +4 -4
  302. package/dist/workflows/renderer.js +5 -5
  303. package/dist/workflows/runtime/agent-identity.js +56 -0
  304. package/dist/workflows/runtime/checkin.js +57 -0
  305. package/dist/workflows/{runs.js → runtime/runs.js} +197 -101
  306. package/dist/workflows/validate-summary.js +82 -0
  307. package/docs/README.md +1 -1
  308. package/docs/data-and-telemetry.md +6 -6
  309. package/package.json +17 -8
  310. package/dist/commands/add-cli.js +0 -279
  311. package/dist/commands/env.js +0 -213
  312. package/dist/integrations/agent/sdk-runner.js +0 -126
  313. package/dist/output/shapes/vault-list.js +0 -19
  314. package/dist/output/text/proposal-producer.js +0 -8
  315. package/dist/output/text/proposal.js +0 -12
  316. package/dist/output/text/vault.js +0 -16
  317. /package/dist/core/{asset-serialize.js → asset/asset-serialize.js} +0 -0
  318. /package/dist/core/{frontmatter.js → asset/frontmatter.js} +0 -0
  319. /package/dist/core/{config-sources.js → config/config-sources.js} +0 -0
  320. /package/dist/indexer/{graph-dedup.js → graph/graph-dedup.js} +0 -0
  321. /package/dist/{core/config-types.js → indexer/passes/pass-context.js} +0 -0
  322. /package/dist/indexer/{search-fields.js → search/search-fields.js} +0 -0
  323. /package/dist/indexer/{index-context.js → walk/index-context.js} +0 -0
  324. /package/dist/workflows/{document-cache.js → runtime/document-cache.js} +0 -0
@@ -3,61 +3,76 @@
3
3
  // file, You can obtain one at https://mozilla.org/MPL/2.0/.
4
4
  import { randomUUID } from "node:crypto";
5
5
  import fs from "node:fs";
6
- import { parseAssetRef } from "../core/asset-ref";
7
- import { loadConfig } from "../core/config";
8
- import { NotFoundError, UsageError } from "../core/errors";
9
- import { appendEvent } from "../core/events";
10
- import { getDbPath } from "../core/paths";
11
- import { closeDatabase, openExistingDatabase } from "../indexer/db";
12
- import { resolveSourceEntries } from "../indexer/search-source";
13
- import { resolveSourcesForOrigin } from "../registry/origin-resolve";
14
- import { resolveAssetPath } from "../sources/resolve";
15
- import { formatWorkflowErrors } from "./authoring";
16
- import { closeWorkflowDatabase, openWorkflowDatabase } from "./db";
17
- import { parseWorkflow } from "./parser";
18
- import { getCurrentWorkflowScopeKey } from "./scope-key";
19
- async function withWorkflowDb(fn) {
20
- const db = openWorkflowDatabase();
21
- try {
22
- return await Promise.resolve(fn(db));
23
- }
24
- finally {
25
- closeWorkflowDatabase(db);
26
- }
27
- }
6
+ import { parseAssetRef } from "../../core/asset/asset-ref.js";
7
+ import { loadConfig } from "../../core/config/config.js";
8
+ import { NotFoundError, UsageError } from "../../core/errors.js";
9
+ import { appendEvent } from "../../core/events.js";
10
+ import { getDbPath } from "../../core/paths.js";
11
+ import { closeDatabase, openExistingDatabase } from "../../indexer/db/db.js";
12
+ import { resolveSourceEntries } from "../../indexer/search/search-source.js";
13
+ import { resolveSourcesForOrigin } from "../../registry/origin-resolve.js";
14
+ import { resolveAssetPath } from "../../sources/resolve.js";
15
+ import { withWorkflowRunsRepo, } from "../../storage/repositories/workflow-runs-repository.js";
16
+ import { formatWorkflowErrors } from "../authoring/authoring.js";
17
+ import { getCurrentWorkflowScopeKey } from "../authoring/scope-key.js";
18
+ import { parseWorkflow } from "../parser.js";
19
+ import { validateStepSummary } from "../validate-summary.js";
20
+ import { resolveAgentIdentity } from "./agent-identity.js";
21
+ import { evaluateCheckin } from "./checkin.js";
28
22
  export async function startWorkflowRun(ref, params = {}, options) {
29
23
  const asset = await loadWorkflowAsset(ref);
30
- return withWorkflowDb(async (db) => {
24
+ return withWorkflowRunsRepo(async (repo) => {
31
25
  const now = new Date().toISOString();
32
26
  const runId = randomUUID();
33
27
  const scopeKey = getCurrentWorkflowScopeKey();
34
28
  const currentStepId = asset.steps[0]?.id ?? null;
35
29
  const workflowEntryId = resolveWorkflowEntryId(asset.sourcePath, asset.ref);
30
+ // Capture the agent harness + session driving this run. Explicit options
31
+ // win; otherwise fall back to best-effort environment detection. This is
32
+ // identity-only — no background thread or timer is started here.
33
+ const detected = resolveAgentIdentity();
34
+ const agentHarness = options?.agentHarness !== undefined ? options.agentHarness : detected.harness;
35
+ const agentSessionId = options?.agentSessionId !== undefined ? options.agentSessionId : detected.sessionId;
36
36
  // Concurrency guard (#485): if an active run already exists in this
37
37
  // (workflow_ref, scope_key) pair, refuse to create a parallel run unless
38
38
  // `force: true` is set. Previously every call inserted unconditionally,
39
39
  // so two terminals running `akm workflow start <ref>` left two runs
40
40
  // racing; `akm workflow next` then non-deterministically picked one.
41
41
  if (!options?.force) {
42
- const existing = db
43
- .prepare("SELECT id, current_step_id FROM workflow_runs WHERE workflow_ref = ? AND scope_key = ? AND status = 'active' ORDER BY updated_at DESC LIMIT 1")
44
- .get(asset.ref, scopeKey);
42
+ const existing = repo.findActiveRunForScope(asset.ref, scopeKey);
45
43
  if (existing) {
46
44
  throw new UsageError(`Workflow ${asset.ref} already has an active run in this scope (id=${existing.id}, step=${existing.current_step_id ?? "—"}). ` +
47
45
  `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");
48
46
  }
49
47
  }
50
- db.transaction(() => {
51
- db.prepare(`INSERT INTO workflow_runs (
52
- id, workflow_ref, scope_key, workflow_entry_id, workflow_title, status, params_json, current_step_id, created_at, updated_at
53
- ) VALUES (?, ?, ?, ?, ?, 'active', ?, ?, ?, ?)`).run(runId, asset.ref, scopeKey, workflowEntryId, asset.title, JSON.stringify(params), currentStepId, now, now);
54
- const insertStep = db.prepare(`INSERT INTO workflow_run_steps (
55
- run_id, step_id, step_title, instructions, completion_json, sequence_index, status
56
- ) VALUES (?, ?, ?, ?, ?, ?, 'pending')`);
57
- for (const step of asset.steps) {
58
- insertStep.run(runId, step.id, step.title, step.instructions, step.completionCriteria ? JSON.stringify(step.completionCriteria) : null, step.sequenceIndex ?? 0);
59
- }
60
- })();
48
+ // #506: arm a file-signal check-in (a timestamp, NOT a background thread —
49
+ // see docs/technical/workflow-agent-checkin-adr.md) so a stalled run can be
50
+ // re-targeted with a `continue` directive. The agent harness + session id
51
+ // are already resolved above (agentHarness/agentSessionId, from #501).
52
+ repo.transaction(() => {
53
+ repo.insertRun({
54
+ id: runId,
55
+ workflowRef: asset.ref,
56
+ scopeKey,
57
+ workflowEntryId,
58
+ workflowTitle: asset.title,
59
+ paramsJson: JSON.stringify(params),
60
+ currentStepId,
61
+ createdAt: now,
62
+ updatedAt: now,
63
+ agentHarness,
64
+ agentSessionId,
65
+ checkinArmedAt: now,
66
+ });
67
+ repo.insertSteps(asset.steps.map((step) => ({
68
+ runId,
69
+ stepId: step.id,
70
+ stepTitle: step.title,
71
+ instructions: step.instructions,
72
+ completionJson: step.completionCriteria ? JSON.stringify(step.completionCriteria) : null,
73
+ sequenceIndex: step.sequenceIndex ?? 0,
74
+ })));
75
+ });
61
76
  const result = await getWorkflowStatus(runId);
62
77
  appendEvent({
63
78
  eventType: "workflow_started",
@@ -68,49 +83,49 @@ export async function startWorkflowRun(ref, params = {}, options) {
68
83
  });
69
84
  }
70
85
  export async function getWorkflowStatus(runId) {
71
- return withWorkflowDb((db) => {
72
- const run = readWorkflowRun(db, runId);
73
- const steps = readWorkflowRunSteps(db, run.id);
86
+ return withWorkflowRunsRepo((repo) => {
87
+ const run = readWorkflowRun(repo, runId);
88
+ const steps = readWorkflowRunSteps(repo, run.id);
74
89
  return buildWorkflowRunDetail(run, steps);
75
90
  });
76
91
  }
77
92
  export async function hasWorkflowRun(runId) {
78
- return withWorkflowDb((db) => {
79
- const row = db.prepare("SELECT 1 FROM workflow_runs WHERE id = ? LIMIT 1").get(runId);
80
- return !!row;
81
- });
93
+ return withWorkflowRunsRepo((repo) => repo.hasRun(runId));
82
94
  }
83
95
  export async function listWorkflowRuns(input) {
84
- return withWorkflowDb((db) => {
85
- const filters = [];
86
- const params = [];
96
+ return withWorkflowRunsRepo((repo) => {
87
97
  const scopeKey = getCurrentWorkflowScopeKey();
88
- filters.push("scope_key = ?");
89
- params.push(scopeKey);
98
+ let workflowRef;
90
99
  if (input?.workflowRef) {
91
100
  const parsed = parseAssetRef(input.workflowRef);
92
101
  if (parsed.type !== "workflow") {
93
102
  throw new UsageError(`Expected a workflow ref (workflow:<name>), got "${input.workflowRef}".`);
94
103
  }
95
- filters.push("workflow_ref = ?");
96
- params.push(`${parsed.origin ? `${parsed.origin}//` : ""}workflow:${parsed.name}`);
104
+ workflowRef = `${parsed.origin ? `${parsed.origin}//` : ""}workflow:${parsed.name}`;
97
105
  }
98
- if (input?.activeOnly) {
99
- filters.push("status IN ('active', 'blocked')");
100
- }
101
- const where = filters.length > 0 ? `WHERE ${filters.join(" AND ")}` : "";
102
- const rows = db
103
- .prepare(`SELECT * FROM workflow_runs ${where} ORDER BY updated_at DESC, created_at DESC`)
104
- .all(...params);
106
+ const rows = repo.listRuns({
107
+ scopeKey,
108
+ ...(workflowRef ? { workflowRef } : {}),
109
+ ...(input?.activeOnly ? { activeOnly: true } : {}),
110
+ });
105
111
  return { runs: rows.map(toWorkflowRunSummary) };
106
112
  });
107
113
  }
108
114
  export async function getNextWorkflowStep(specifier, params) {
109
- return withWorkflowDb(async (db) => {
110
- const { run, autoStarted } = await resolveRunSpecifier(db, specifier, params);
111
- const steps = readWorkflowRunSteps(db, run.id);
115
+ return withWorkflowRunsRepo(async (repo) => {
116
+ const { run, autoStarted } = await resolveRunSpecifier(repo, specifier, params);
117
+ const steps = readWorkflowRunSteps(repo, run.id);
112
118
  const currentStep = resolveCurrentStep(run, steps);
113
119
  const done = run.status === "completed" ? true : undefined;
120
+ // #506: surface a check-in directive through the normal command output when
121
+ // the run looks stalled. Pure timestamp evaluation — no background thread.
122
+ const checkin = evaluateCheckin({
123
+ status: run.status,
124
+ updatedAt: run.updated_at,
125
+ checkinArmedAt: run.checkin_armed_at,
126
+ agentHarness: run.agent_harness,
127
+ agentSessionId: run.agent_session_id,
128
+ }) ?? undefined;
114
129
  return {
115
130
  run: toWorkflowRunSummary(run),
116
131
  workflow: {
@@ -121,47 +136,90 @@ export async function getNextWorkflowStep(specifier, params) {
121
136
  step: currentStep ? toWorkflowRunStepState(currentStep) : null,
122
137
  ...(done ? { done } : {}),
123
138
  ...(autoStarted ? { autoStarted } : {}),
139
+ ...(checkin ? { checkin } : {}),
124
140
  };
125
141
  });
126
142
  }
127
143
  export async function resumeWorkflowRun(runId) {
128
- return withWorkflowDb((db) => {
129
- const run = readWorkflowRun(db, runId);
144
+ return withWorkflowRunsRepo((repo) => {
145
+ const run = readWorkflowRun(repo, runId);
130
146
  if (run.status === "completed") {
131
147
  throw new UsageError(`Workflow run ${run.id} is already completed and cannot be resumed.`);
132
148
  }
133
149
  if (run.status === "active") {
134
- const steps = readWorkflowRunSteps(db, run.id);
150
+ const steps = readWorkflowRunSteps(repo, run.id);
135
151
  return buildWorkflowRunDetail(run, steps);
136
152
  }
137
153
  // blocked or failed → flip back to active and re-open the current step so
138
154
  // it can be reclassified (completed, failed, skipped) after resuming.
139
155
  const now = new Date().toISOString();
140
- db.transaction(() => {
156
+ repo.transaction(() => {
141
157
  if (run.current_step_id) {
142
- db.prepare(`UPDATE workflow_run_steps
143
- SET status = 'pending', notes = NULL, evidence_json = NULL, completed_at = NULL
144
- WHERE run_id = ? AND step_id = ? AND status IN ('blocked', 'failed')`).run(run.id, run.current_step_id);
158
+ repo.reopenStepsForResume(run.id, run.current_step_id);
145
159
  }
146
- db.prepare("UPDATE workflow_runs SET status = 'active', updated_at = ? WHERE id = ?").run(now, run.id);
147
- })();
160
+ repo.markRunActive(run.id, now);
161
+ });
148
162
  const updated = { ...run, status: "active", updated_at: now };
149
- const steps = readWorkflowRunSteps(db, run.id);
163
+ const steps = readWorkflowRunSteps(repo, run.id);
150
164
  return buildWorkflowRunDetail(updated, steps);
151
165
  });
152
166
  }
153
167
  export async function completeWorkflowStep(input) {
154
- return withWorkflowDb((db) => {
168
+ // Read the step (read-only) up front so the LLM validation gate runs OUTSIDE
169
+ // the write transaction — a slow/hung LLM must never hold a db write lock.
170
+ const preflight = await withWorkflowRunsRepo((repo) => {
171
+ const run = readWorkflowRun(repo, input.runId);
172
+ if (run.status !== "active") {
173
+ throw new UsageError(`Workflow run ${run.id} is ${run.status} and cannot be updated.`);
174
+ }
175
+ const existing = repo.getStep(run.id, input.stepId);
176
+ if (!existing) {
177
+ throw new NotFoundError(`Step "${input.stepId}" was not found in workflow run ${run.id}.`);
178
+ }
179
+ if (existing.status !== "pending") {
180
+ throw new UsageError(`Step "${input.stepId}" is already ${existing.status} in workflow run ${run.id}.`);
181
+ }
182
+ if (run.current_step_id !== existing.step_id) {
183
+ throw new UsageError(`Step "${input.stepId}" is not the current step for workflow run ${run.id}. Complete "${run.current_step_id}" first.`);
184
+ }
185
+ return { existing };
186
+ });
187
+ const summary = input.summary?.trim();
188
+ // #506: completing a step requires a summary of the work done.
189
+ if (input.status === "completed" && !summary) {
190
+ throw new UsageError(`Completing step "${input.stepId}" requires a --summary describing the work done.`, "MISSING_REQUIRED_ARGUMENT");
191
+ }
192
+ // #506: validation gate — judge the summary against the step's
193
+ // completionCriteria via the configured LLM. Fail-open when no criteria or no
194
+ // judge. Only a well-formed `complete: false` blocks completion.
195
+ if (input.status === "completed" && summary) {
196
+ const criteria = parseJsonArray(preflight.existing.completion_json) ?? [];
197
+ const judge = input.summaryJudge === undefined ? buildDefaultSummaryJudge() : input.summaryJudge;
198
+ const verdict = await validateStepSummary({ stepTitle: preflight.existing.step_title, completionCriteria: criteria, summary }, judge ?? undefined);
199
+ if (!verdict.complete) {
200
+ // Re-arm the check-in so a subsequent stall is still nudged, but leave the
201
+ // step pending and return corrective feedback instead of completing.
202
+ await withWorkflowRunsRepo((repo) => {
203
+ repo.rearmCheckin(input.runId, new Date().toISOString());
204
+ });
205
+ return {
206
+ ok: false,
207
+ runId: input.runId,
208
+ stepId: input.stepId,
209
+ missing: verdict.missing,
210
+ feedback: verdict.feedback ?? "The summary does not satisfy the step's completion criteria.",
211
+ };
212
+ }
213
+ }
214
+ return withWorkflowRunsRepo((repo) => {
155
215
  let updatedRun;
156
216
  let refreshedSteps = [];
157
- db.transaction(() => {
158
- const run = readWorkflowRun(db, input.runId);
217
+ repo.transaction(() => {
218
+ const run = readWorkflowRun(repo, input.runId);
159
219
  if (run.status !== "active") {
160
220
  throw new UsageError(`Workflow run ${run.id} is ${run.status} and cannot be updated.`);
161
221
  }
162
- const existing = db
163
- .prepare("SELECT * FROM workflow_run_steps WHERE run_id = ? AND step_id = ?")
164
- .get(run.id, input.stepId);
222
+ const existing = repo.getStep(run.id, input.stepId);
165
223
  if (!existing) {
166
224
  throw new NotFoundError(`Step "${input.stepId}" was not found in workflow run ${run.id}.`);
167
225
  }
@@ -172,22 +230,36 @@ export async function completeWorkflowStep(input) {
172
230
  throw new UsageError(`Step "${input.stepId}" is not the current step for workflow run ${run.id}. Complete "${run.current_step_id}" first.`);
173
231
  }
174
232
  const completedAt = new Date().toISOString();
175
- db.prepare(`UPDATE workflow_run_steps
176
- SET status = ?, notes = ?, evidence_json = ?, completed_at = ?
177
- WHERE run_id = ? AND step_id = ?`).run(input.status, input.notes?.trim() || null, input.evidence ? JSON.stringify(input.evidence) : null, completedAt, run.id, input.stepId);
178
- refreshedSteps = readWorkflowRunSteps(db, run.id);
233
+ repo.updateStepCompletion({
234
+ status: input.status,
235
+ notes: input.notes?.trim() || null,
236
+ evidenceJson: input.evidence ? JSON.stringify(input.evidence) : null,
237
+ summary: summary || null,
238
+ completedAt,
239
+ runId: run.id,
240
+ stepId: input.stepId,
241
+ });
242
+ refreshedSteps = readWorkflowRunSteps(repo, run.id);
179
243
  const state = deriveRunState(refreshedSteps);
180
- db.prepare(`UPDATE workflow_runs
181
- SET status = ?, current_step_id = ?, updated_at = ?, completed_at = ?
182
- WHERE id = ?`).run(state.status, state.currentStepId, completedAt, state.completedAt, run.id);
244
+ // Re-arm the check-in on every state change: a healthy, progressing run
245
+ // keeps pushing the stall window forward so the directive never fires.
246
+ repo.updateRunState({
247
+ status: state.status,
248
+ currentStepId: state.currentStepId,
249
+ updatedAt: completedAt,
250
+ completedAt: state.completedAt,
251
+ checkinArmedAt: completedAt,
252
+ runId: run.id,
253
+ });
183
254
  updatedRun = {
184
255
  ...run,
185
256
  status: state.status,
186
257
  current_step_id: state.currentStepId,
187
258
  updated_at: completedAt,
188
259
  completed_at: state.completedAt,
260
+ checkin_armed_at: completedAt,
189
261
  };
190
- })();
262
+ });
191
263
  const detail = buildWorkflowRunDetail(updatedRun, refreshedSteps);
192
264
  appendEvent({
193
265
  eventType: "workflow_step_completed",
@@ -200,8 +272,8 @@ export async function completeWorkflowStep(input) {
200
272
  return detail;
201
273
  });
202
274
  }
203
- async function resolveRunSpecifier(db, specifier, params) {
204
- const explicitRun = db.prepare("SELECT * FROM workflow_runs WHERE id = ?").get(specifier);
275
+ async function resolveRunSpecifier(repo, specifier, params) {
276
+ const explicitRun = repo.getRunById(specifier);
205
277
  if (explicitRun) {
206
278
  if (params && Object.keys(params).length > 0) {
207
279
  throw new UsageError(`--params can only be used when starting a new run from a workflow ref, not with an existing run id ("${specifier}")`);
@@ -217,9 +289,7 @@ async function resolveRunSpecifier(db, specifier, params) {
217
289
  }
218
290
  const ref = `${parsed.origin ? `${parsed.origin}//` : ""}workflow:${parsed.name}`;
219
291
  const scopeKey = getCurrentWorkflowScopeKey();
220
- const active = db
221
- .prepare("SELECT * FROM workflow_runs WHERE workflow_ref = ? AND scope_key = ? AND status = 'active' ORDER BY updated_at DESC LIMIT 1")
222
- .get(ref, scopeKey);
292
+ const active = repo.getActiveRunRowForScope(ref, scopeKey);
223
293
  if (active) {
224
294
  if (params && Object.keys(params).length > 0) {
225
295
  throw new UsageError(`--params can only be set on a new run; ${ref} already has an active run`);
@@ -227,7 +297,7 @@ async function resolveRunSpecifier(db, specifier, params) {
227
297
  return { run: active, autoStarted: false };
228
298
  }
229
299
  const started = await startWorkflowRun(ref, params ?? {});
230
- return { run: readWorkflowRun(db, started.run.id), autoStarted: true };
300
+ return { run: readWorkflowRun(repo, started.run.id), autoStarted: true };
231
301
  }
232
302
  async function loadWorkflowAsset(ref) {
233
303
  const parsed = parseAssetRef(ref);
@@ -338,17 +408,15 @@ function resolveWorkflowEntryId(sourcePath, ref) {
338
408
  closeDatabase(db);
339
409
  }
340
410
  }
341
- function readWorkflowRun(db, runId) {
342
- const run = db.prepare("SELECT * FROM workflow_runs WHERE id = ?").get(runId);
411
+ function readWorkflowRun(repo, runId) {
412
+ const run = repo.getRunById(runId);
343
413
  if (!run) {
344
414
  throw new NotFoundError(`Workflow run "${runId}" not found.`, "WORKFLOW_NOT_FOUND");
345
415
  }
346
416
  return run;
347
417
  }
348
- function readWorkflowRunSteps(db, runId) {
349
- return db
350
- .prepare("SELECT * FROM workflow_run_steps WHERE run_id = ? ORDER BY sequence_index ASC")
351
- .all(runId);
418
+ function readWorkflowRunSteps(repo, runId) {
419
+ return repo.getStepsForRun(runId);
352
420
  }
353
421
  function buildWorkflowRunDetail(run, steps) {
354
422
  return {
@@ -373,6 +441,8 @@ function toWorkflowRunSummary(run) {
373
441
  updatedAt: run.updated_at,
374
442
  completedAt: run.completed_at,
375
443
  params: parseJsonObject(run.params_json),
444
+ agentHarness: run.agent_harness ?? null,
445
+ agentSessionId: run.agent_session_id ?? null,
376
446
  };
377
447
  }
378
448
  function toWorkflowRunStepState(step) {
@@ -385,6 +455,7 @@ function toWorkflowRunStepState(step) {
385
455
  status: step.status,
386
456
  notes: step.notes ?? undefined,
387
457
  evidence: parseJsonObject(step.evidence_json),
458
+ summary: step.summary ?? undefined,
388
459
  completedAt: step.completed_at,
389
460
  };
390
461
  }
@@ -414,6 +485,33 @@ function deriveRunState(steps) {
414
485
  .at(-1);
415
486
  return { status: "completed", currentStepId: null, completedAt: completedAt ?? null };
416
487
  }
488
+ /**
489
+ /**
490
+ * Build the default summary-validation judge from the configured LLM, or return
491
+ * `null` when no LLM is configured (gate is then skipped — fail-open). Lazily
492
+ * imports the client/config so the workflow engine has no hard LLM dependency.
493
+ */
494
+ function buildDefaultSummaryJudge() {
495
+ let llm;
496
+ try {
497
+ const config = loadConfig();
498
+ const { getDefaultLlmConfig } = require("../../core/config/config");
499
+ llm = getDefaultLlmConfig(config);
500
+ }
501
+ catch {
502
+ return null;
503
+ }
504
+ if (!llm)
505
+ return null;
506
+ const resolved = llm;
507
+ return async ({ system, user }) => {
508
+ const { chatCompletion } = require("../../llm/client");
509
+ return chatCompletion(resolved, [
510
+ { role: "system", content: system },
511
+ { role: "user", content: user },
512
+ ]);
513
+ };
514
+ }
417
515
  function parseJsonObject(value) {
418
516
  if (!value)
419
517
  return undefined;
@@ -443,10 +541,8 @@ function parseJsonArray(value) {
443
541
  return undefined;
444
542
  }
445
543
  export async function getActiveWorkflowRun(scopeKey = getCurrentWorkflowScopeKey()) {
446
- return withWorkflowDb((db) => {
447
- const row = db
448
- .query("SELECT id, current_step_id, workflow_ref FROM workflow_runs WHERE scope_key = ? AND status IN ('active', 'blocked') ORDER BY updated_at DESC LIMIT 1")
449
- .get(scopeKey);
544
+ return withWorkflowRunsRepo((repo) => {
545
+ const row = repo.findActiveOrBlockedRunForScope(scopeKey);
450
546
  if (!row)
451
547
  return null;
452
548
  return { runId: row.id, stepId: row.current_step_id, workflowRef: row.workflow_ref };
@@ -0,0 +1,82 @@
1
+ // This Source Code Form is subject to the terms of the Mozilla Public
2
+ // License, v. 2.0. If a copy of the MPL was not distributed with this
3
+ // file, You can obtain one at https://mozilla.org/MPL/2.0/.
4
+ /**
5
+ * Summary-validation gate for workflow step/workflow completion (#506).
6
+ *
7
+ * Takes a step's `completionCriteria` and the summary of work the agent claims
8
+ * to have done, asks the configured LLM to judge whether the summary
9
+ * demonstrates each criterion is met, and returns either a pass or structured
10
+ * corrective feedback steering the agent on what to finish/fix.
11
+ *
12
+ * The LLM call is injected (`judge`) so the gate is unit-testable without a
13
+ * live endpoint, and the whole gate is fail-open: when no criteria exist or no
14
+ * judge is available the step completes as before. See
15
+ * docs/technical/workflow-agent-checkin-adr.md.
16
+ *
17
+ * @module workflows/validate-summary
18
+ */
19
+ import { parseJsonResponse } from "../core/parse.js";
20
+ const JUDGE_SYSTEM = "You are a strict completion auditor for a software workflow engine. " +
21
+ "Given a step's completion criteria and a summary of the work an agent claims to have done, " +
22
+ "judge whether the summary provides concrete evidence that EVERY criterion is satisfied. " +
23
+ "Be skeptical: vague, hand-wavy, or unsubstantiated claims do NOT satisfy a criterion. " +
24
+ 'Respond with ONLY a JSON object: {"complete": boolean, "missing": string[], "feedback": string}. ' +
25
+ '"missing" lists the exact criteria that are not yet satisfied; "feedback" is a short directive ' +
26
+ "telling the agent what to finish or fix. No prose, no markdown fences.";
27
+ function buildUserPrompt(input) {
28
+ const criteria = input.completionCriteria.map((c, i) => `${i + 1}. ${c}`).join("\n");
29
+ return [
30
+ `Step: ${input.stepTitle}`,
31
+ "",
32
+ "Completion criteria:",
33
+ criteria,
34
+ "",
35
+ "Agent's summary of work done:",
36
+ input.summary.trim(),
37
+ "",
38
+ "Return the JSON verdict now.",
39
+ ].join("\n");
40
+ }
41
+ /**
42
+ * Run the summary-validation gate.
43
+ *
44
+ * Fail-open contract:
45
+ * - no criteria → `{ complete: true, skipped: true }`
46
+ * - no judge → `{ complete: true, skipped: true }`
47
+ * - judge throws / returns unparseable → `{ complete: true, skipped: true }`
48
+ *
49
+ * Only a well-formed `complete: false` verdict blocks completion.
50
+ */
51
+ export async function validateStepSummary(input, judge) {
52
+ const criteria = input.completionCriteria.filter((c) => c.trim().length > 0);
53
+ if (criteria.length === 0) {
54
+ return { complete: true, missing: [], skipped: true };
55
+ }
56
+ if (!judge) {
57
+ return { complete: true, missing: [], skipped: true };
58
+ }
59
+ let raw;
60
+ try {
61
+ raw = await judge({ system: JUDGE_SYSTEM, user: buildUserPrompt({ ...input, completionCriteria: criteria }) });
62
+ }
63
+ catch {
64
+ // LLM unreachable / errored — fail open so offline use keeps working.
65
+ return { complete: true, missing: [], skipped: true };
66
+ }
67
+ const parsed = parseJsonResponse(raw);
68
+ if (!parsed || typeof parsed.complete !== "boolean") {
69
+ return { complete: true, missing: [], skipped: true };
70
+ }
71
+ if (parsed.complete) {
72
+ return { complete: true, missing: [] };
73
+ }
74
+ const missing = Array.isArray(parsed.missing)
75
+ ? parsed.missing.filter((m) => typeof m === "string" && m.trim().length > 0)
76
+ : [];
77
+ const feedback = typeof parsed.feedback === "string" && parsed.feedback.trim().length > 0
78
+ ? parsed.feedback.trim()
79
+ : "The summary does not yet demonstrate every completion criterion is met. " +
80
+ "Finish the outstanding work and resubmit with a summary that addresses each criterion.";
81
+ return { complete: false, missing, feedback };
82
+ }
package/docs/README.md CHANGED
@@ -31,7 +31,7 @@
31
31
 
32
32
  ## Operations
33
33
 
34
- - Analyzing `akm improve` runs -- use [`akm health`](../src/commands/health.ts) (0.8.0+): `--since`, `--detail per-run`, `--window-compare`, `--windows`. See [health-command-enhancements.md](technical/health-command-enhancements.md).
34
+ - Analyzing `akm improve` runs -- use [`akm health`](../src/commands/health.ts) (0.8.0+): `--since`, `--group-by run`, `--window-compare`, `--windows`. See [health-command-enhancements.md](technical/health-command-enhancements.md).
35
35
 
36
36
  ## Internals
37
37
 
@@ -76,7 +76,7 @@ Override: set `AKM_STASH_DIR` (or configure `stashDir` in `config.json`).
76
76
 
77
77
  ### 1. Events Table
78
78
 
79
- An append-only log of every mutating action you perform with AKM. Events are stored locally for self-improvement (the improve loop uses them to surface usage patterns) and for inspection via `akm events`.
79
+ An append-only log of every mutating action you perform with AKM. Events are stored locally for self-improvement (the improve loop uses them to surface usage patterns) and for inspection via `akm log`.
80
80
 
81
81
  **What is recorded:**
82
82
  - `event_type` — what action was taken (see full list below)
@@ -101,7 +101,7 @@ An append-only log of every mutating action you perform with AKM. Events are sto
101
101
  | `update` | `akm update [source]` | `ref` |
102
102
  | `remember` | `akm remember <text>` | `ref` |
103
103
  | `import` | `akm import <file>` | `ref` |
104
- | `save` | `akm save <ref>` | `ref` |
104
+ | `save` | `akm sync` | `ref` |
105
105
  | `feedback` | `akm feedback <ref>` | `signal` (positive/negative) |
106
106
  | `search` | `akm search <query>` | `query`, `source`, `signal` |
107
107
  | `curate` | `akm curate <prompt>` | `query`, `source` |
@@ -154,16 +154,16 @@ A record of scheduled task runs (from `akm tasks`):
154
154
 
155
155
  ```sh
156
156
  # List recent events
157
- akm events list
157
+ akm log list
158
158
 
159
159
  # Stream live events (tail)
160
- akm events tail
160
+ akm log tail
161
161
 
162
162
  # Filter by type
163
- akm events list --type search --limit 20
163
+ akm log list --type search --limit 20
164
164
 
165
165
  # Filter by asset ref
166
- akm events list --ref skill:code-review
166
+ akm log list --ref skill:code-review
167
167
  ```
168
168
 
169
169
  ### Inspect proposals