akm-cli 0.8.1 → 0.9.0-beta.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.
Files changed (318) hide show
  1. package/CHANGELOG.md +258 -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/stash-skeleton/README.md +76 -0
  9. package/dist/assets/tasks/core/backup.yml +4 -0
  10. package/dist/assets/tasks/core/extract.yml +4 -0
  11. package/dist/assets/tasks/core/improve.yml +4 -0
  12. package/dist/assets/tasks/core/index-refresh.yml +4 -0
  13. package/dist/assets/tasks/core/sync.yml +4 -0
  14. package/dist/assets/tasks/core/update-stashes.yml +4 -0
  15. package/dist/assets/tasks/core/version-check.yml +4 -0
  16. package/dist/cli/config-migrate.js +6 -6
  17. package/dist/cli/config-validate.js +4 -4
  18. package/dist/cli/confirm.js +3 -3
  19. package/dist/cli/parse-args.js +1 -1
  20. package/dist/cli/shared.js +51 -14
  21. package/dist/cli-node.mjs +26 -0
  22. package/dist/cli.js +171 -3857
  23. package/dist/commands/{agent-dispatch.js → agent/agent-dispatch.js} +6 -6
  24. package/dist/commands/{agent-support.js → agent/agent-support.js} +2 -2
  25. package/dist/commands/agent/contribute-cli.js +200 -0
  26. package/dist/commands/completions.js +1 -1
  27. package/dist/commands/config-cli.js +240 -3
  28. package/dist/commands/config-edit.js +344 -0
  29. package/dist/commands/db-cli.js +2 -2
  30. package/dist/commands/env/env-cli.js +529 -0
  31. package/dist/commands/env/env.js +410 -0
  32. package/dist/commands/env/secret-cli.js +259 -0
  33. package/dist/commands/{secret.js → env/secret.js} +6 -47
  34. package/dist/commands/events.js +4 -4
  35. package/dist/commands/feedback-cli.js +18 -34
  36. package/dist/commands/graph/graph-cli.js +132 -0
  37. package/dist/commands/{graph.js → graph/graph.js} +22 -16
  38. package/dist/commands/health/checks.js +279 -0
  39. package/dist/commands/health.js +101 -249
  40. package/dist/commands/{consolidate.js → improve/consolidate.js} +52 -40
  41. package/dist/commands/{distill-promotion-policy.js → improve/distill-promotion-policy.js} +3 -3
  42. package/dist/commands/{distill.js → improve/distill.js} +39 -18
  43. package/dist/commands/{eval-cases.js → improve/eval-cases.js} +1 -1
  44. package/dist/commands/{extract-cli.js → improve/extract-cli.js} +4 -4
  45. package/dist/commands/{extract-prompt.js → improve/extract-prompt.js} +2 -2
  46. package/dist/commands/{extract.js → improve/extract.js} +185 -26
  47. package/dist/commands/{improve-auto-accept.js → improve/improve-auto-accept.js} +4 -4
  48. package/dist/commands/{improve-cli.js → improve/improve-cli.js} +45 -23
  49. package/dist/commands/{improve-profiles.js → improve/improve-profiles.js} +13 -7
  50. package/dist/commands/{improve-result-file.js → improve/improve-result-file.js} +10 -5
  51. package/dist/commands/{improve.js → improve/improve.js} +536 -248
  52. package/dist/{core → commands/improve/memory}/memory-belief.js +2 -2
  53. package/dist/{core → commands/improve/memory}/memory-contradiction-detect.js +5 -5
  54. package/dist/{core → commands/improve/memory}/memory-improve.js +4 -4
  55. package/dist/commands/{reflect.js → improve/reflect.js} +33 -28
  56. package/dist/commands/improve/session-asset.js +248 -0
  57. package/dist/commands/lint/agent-linter.js +1 -1
  58. package/dist/commands/lint/base-linter.js +55 -37
  59. package/dist/commands/lint/command-linter.js +1 -1
  60. package/dist/commands/lint/default-linter.js +1 -1
  61. package/dist/commands/lint/env-key-rules.js +1 -1
  62. package/dist/commands/lint/index.js +19 -25
  63. package/dist/commands/lint/knowledge-linter.js +1 -1
  64. package/dist/commands/lint/memory-linter.js +1 -1
  65. package/dist/commands/lint/registry.js +8 -8
  66. package/dist/commands/lint/skill-linter.js +1 -1
  67. package/dist/commands/lint/task-linter.js +1 -1
  68. package/dist/commands/lint/workflow-linter.js +1 -1
  69. package/dist/commands/lint.js +1 -1
  70. package/dist/commands/observability-cli.js +244 -0
  71. package/dist/commands/{proposal-drain-policies.js → proposal/drain-policies.js} +3 -3
  72. package/dist/commands/{proposal-drain.js → proposal/drain.js} +15 -10
  73. package/dist/commands/proposal/proposal-cli.js +478 -0
  74. package/dist/commands/{proposal.js → proposal/proposal.js} +5 -5
  75. package/dist/commands/{propose.js → proposal/propose.js} +11 -11
  76. package/dist/{core → commands/proposal/validators}/proposal-quality-validators.js +8 -3
  77. package/dist/{core → commands/proposal/validators}/proposal-validators.js +5 -5
  78. package/dist/{core → commands/proposal/validators}/proposals.js +13 -7
  79. package/dist/commands/{curate.js → read/curate.js} +7 -7
  80. package/dist/commands/{knowledge.js → read/knowledge.js} +22 -9
  81. package/dist/commands/{registry-search.js → read/registry-search.js} +5 -5
  82. package/dist/commands/{remember-cli.js → read/remember-cli.js} +15 -7
  83. package/dist/commands/read/search-cli.js +207 -0
  84. package/dist/commands/{search.js → read/search.js} +22 -27
  85. package/dist/commands/{show.js → read/show.js} +77 -44
  86. package/dist/commands/registry-cli.js +8 -8
  87. package/dist/commands/remember.js +8 -8
  88. package/dist/commands/sources/add-cli.js +293 -0
  89. package/dist/commands/{history.js → sources/history.js} +27 -25
  90. package/dist/commands/{info.js → sources/info.js} +6 -6
  91. package/dist/commands/{init.js → sources/init.js} +10 -5
  92. package/dist/commands/{installed-stashes.js → sources/installed-stashes.js} +12 -12
  93. package/dist/commands/{migration-help.js → sources/migration-help.js} +3 -2
  94. package/dist/commands/{schema-repair.js → sources/schema-repair.js} +8 -8
  95. package/dist/commands/{self-update.js → sources/self-update.js} +10 -9
  96. package/dist/commands/{source-add.js → sources/source-add.js} +10 -10
  97. package/dist/commands/{source-clone.js → sources/source-clone.js} +7 -7
  98. package/dist/commands/{source-manage.js → sources/source-manage.js} +4 -4
  99. package/dist/commands/sources/sources-cli.js +305 -0
  100. package/dist/commands/sources/stash-cli.js +219 -0
  101. package/dist/commands/sources/stash-skeleton.js +79 -0
  102. package/dist/commands/tasks/default-tasks.js +173 -0
  103. package/dist/commands/tasks/tasks-cli.js +210 -0
  104. package/dist/commands/{tasks.js → tasks/tasks.js} +14 -14
  105. package/dist/commands/wiki-cli.js +307 -0
  106. package/dist/commands/workflow-cli.js +329 -0
  107. package/dist/core/action-contributors.js +1 -1
  108. package/dist/core/assert.js +40 -0
  109. package/dist/core/asset/asset-create.js +54 -0
  110. package/dist/core/{asset-ref.js → asset/asset-ref.js} +21 -4
  111. package/dist/core/{asset-registry.js → asset/asset-registry.js} +3 -3
  112. package/dist/core/{asset-spec.js → asset/asset-spec.js} +17 -31
  113. package/dist/core/{markdown.js → asset/markdown.js} +1 -1
  114. package/dist/core/asset/stash-meta.js +110 -0
  115. package/dist/core/best-effort.js +64 -0
  116. package/dist/core/common.js +32 -18
  117. package/dist/core/{config-io.js → config/config-io.js} +29 -19
  118. package/dist/core/{config-migration.js → config/config-migration.js} +11 -9
  119. package/dist/core/{config-schema.js → config/config-schema.js} +45 -1
  120. package/dist/core/config/config-types.js +16 -0
  121. package/dist/core/{config-walker.js → config/config-walker.js} +2 -2
  122. package/dist/core/{config.js → config/config.js} +10 -8
  123. package/dist/core/env-secret-ref.js +90 -0
  124. package/dist/core/errors.js +13 -3
  125. package/dist/core/events.js +27 -4
  126. package/dist/core/file-lock.js +1 -1
  127. package/dist/core/improve-types.js +48 -0
  128. package/dist/core/lesson-lint.js +2 -2
  129. package/dist/core/paths.js +2 -2
  130. package/dist/{setup/ripgrep-install.js → core/ripgrep/install.js} +2 -2
  131. package/dist/{setup/ripgrep-resolve.js → core/ripgrep/resolve.js} +2 -2
  132. package/dist/core/state-db.js +88 -46
  133. package/dist/core/text-truncation.js +148 -0
  134. package/dist/core/time.js +1 -1
  135. package/dist/core/write-source.js +98 -85
  136. package/dist/indexer/{db-backup.js → db/db-backup.js} +9 -24
  137. package/dist/indexer/{db.js → db/db.js} +126 -116
  138. package/dist/indexer/{graph-db.js → db/graph-db.js} +9 -4
  139. package/dist/indexer/{llm-cache.js → db/llm-cache.js} +15 -12
  140. package/dist/indexer/ensure-index.js +4 -4
  141. package/dist/indexer/{graph-boost.js → graph/graph-boost.js} +1 -1
  142. package/dist/indexer/{graph-extraction.js → graph/graph-extraction.js} +55 -13
  143. package/dist/indexer/indexer.js +37 -30
  144. package/dist/indexer/init.js +54 -0
  145. package/dist/indexer/manifest.js +10 -10
  146. package/dist/indexer/{memory-inference.js → passes/memory-inference.js} +92 -23
  147. package/dist/indexer/{metadata-contributors.js → passes/metadata-contributors.js} +10 -8
  148. package/dist/indexer/{metadata.js → passes/metadata.js} +15 -19
  149. package/dist/indexer/{staleness-detect.js → passes/staleness-detect.js} +53 -12
  150. package/dist/indexer/{db-search.js → search/db-search.js} +28 -16
  151. package/dist/indexer/{ranking-contributors.js → search/ranking-contributors.js} +1 -1
  152. package/dist/indexer/{ranking.js → search/ranking.js} +2 -2
  153. package/dist/indexer/{search-hit-enrichers.js → search/search-hit-enrichers.js} +3 -3
  154. package/dist/indexer/{search-source.js → search/search-source.js} +8 -8
  155. package/dist/indexer/{semantic-status.js → search/semantic-status.js} +3 -3
  156. package/dist/indexer/usage/unmigrated-vaults-guard.js +94 -0
  157. package/dist/indexer/{usage-events.js → usage/usage-events.js} +32 -0
  158. package/dist/indexer/{file-context.js → walk/file-context.js} +10 -15
  159. package/dist/indexer/{matchers.js → walk/matchers.js} +13 -9
  160. package/dist/indexer/{path-resolver.js → walk/path-resolver.js} +6 -6
  161. package/dist/indexer/{project-context.js → walk/project-context.js} +1 -1
  162. package/dist/indexer/{walker.js → walk/walker.js} +4 -3
  163. package/dist/integrations/agent/builder-shared.js +39 -0
  164. package/dist/integrations/agent/builders.js +14 -81
  165. package/dist/integrations/agent/config.js +6 -4
  166. package/dist/integrations/agent/detect.js +1 -1
  167. package/dist/integrations/agent/index.js +23 -8
  168. package/dist/integrations/agent/prompts.js +2 -3
  169. package/dist/integrations/agent/runner.js +22 -3
  170. package/dist/integrations/agent/spawn.js +9 -10
  171. package/dist/integrations/harnesses/claude/agent-builder.js +48 -0
  172. package/dist/integrations/harnesses/claude/config-import.js +70 -0
  173. package/dist/integrations/harnesses/claude/index.js +64 -0
  174. package/dist/integrations/{session-logs/providers/claude-code.js → harnesses/claude/session-log.js} +16 -1
  175. package/dist/integrations/harnesses/index.js +144 -0
  176. package/dist/integrations/harnesses/opencode/agent-builder.js +43 -0
  177. package/dist/integrations/harnesses/opencode/config-import.js +82 -0
  178. package/dist/integrations/harnesses/opencode/index.js +59 -0
  179. package/dist/integrations/{session-logs/providers/opencode.js → harnesses/opencode/session-log.js} +1 -1
  180. package/dist/integrations/harnesses/opencode-sdk/index.js +49 -0
  181. package/dist/integrations/harnesses/opencode-sdk/sdk-runner.js +234 -0
  182. package/dist/integrations/harnesses/types.js +43 -0
  183. package/dist/integrations/lockfile.js +7 -16
  184. package/dist/integrations/session-logs/index.js +82 -9
  185. package/dist/llm/call-ai.js +4 -4
  186. package/dist/llm/client.js +131 -6
  187. package/dist/llm/embedder.js +6 -6
  188. package/dist/llm/embedders/local.js +9 -22
  189. package/dist/llm/embedders/remote.js +2 -2
  190. package/dist/llm/embedders/types.js +1 -1
  191. package/dist/llm/graph-extract.js +31 -12
  192. package/dist/llm/index-passes.js +1 -1
  193. package/dist/llm/memory-infer.js +12 -5
  194. package/dist/llm/metadata-enhance.js +2 -2
  195. package/dist/output/context.js +6 -44
  196. package/dist/output/renderers.js +88 -58
  197. package/dist/output/shapes/curate.js +7 -3
  198. package/dist/output/shapes/distill.js +7 -3
  199. package/dist/output/shapes/env-list.js +18 -16
  200. package/dist/output/shapes/events.js +5 -4
  201. package/dist/output/shapes/helpers.js +2 -4
  202. package/dist/output/shapes/history.js +7 -3
  203. package/dist/output/shapes/passthrough.js +8 -11
  204. package/dist/output/shapes/{proposal-accept.js → proposal/accept.js} +7 -3
  205. package/dist/output/shapes/{proposal-diff.js → proposal/diff.js} +7 -3
  206. package/dist/output/shapes/{proposal-list.js → proposal/list.js} +7 -3
  207. package/dist/output/shapes/{proposal-producer.js → proposal/producer.js} +5 -4
  208. package/dist/output/shapes/{proposal-reject.js → proposal/reject.js} +7 -3
  209. package/dist/output/shapes/{proposal-show.js → proposal/show.js} +7 -3
  210. package/dist/output/shapes/registry-search.js +7 -3
  211. package/dist/output/shapes/registry.js +12 -0
  212. package/dist/output/shapes/search.js +7 -3
  213. package/dist/output/shapes/secret-list.js +18 -16
  214. package/dist/output/shapes/show.js +7 -3
  215. package/dist/output/shapes.js +55 -30
  216. package/dist/output/text/add.js +2 -3
  217. package/dist/output/text/clone.js +2 -3
  218. package/dist/output/text/config.js +2 -3
  219. package/dist/output/text/curate.js +4 -3
  220. package/dist/output/text/distill.js +2 -3
  221. package/dist/output/text/enable-disable.js +5 -4
  222. package/dist/output/text/env.js +13 -0
  223. package/dist/output/text/events.js +5 -4
  224. package/dist/output/text/feedback.js +4 -3
  225. package/dist/output/text/helpers.js +54 -39
  226. package/dist/output/text/history.js +2 -3
  227. package/dist/output/text/import.js +2 -3
  228. package/dist/output/text/index.js +2 -3
  229. package/dist/output/text/info.js +2 -3
  230. package/dist/output/text/init.js +2 -3
  231. package/dist/output/text/list.js +2 -3
  232. package/dist/output/text/proposal/producer.js +9 -0
  233. package/dist/output/text/proposal/proposal.js +13 -0
  234. package/dist/output/text/registry-commands.js +8 -7
  235. package/dist/output/text/registry.js +12 -0
  236. package/dist/output/text/remember.js +4 -3
  237. package/dist/output/text/remove.js +2 -3
  238. package/dist/output/text/save.js +2 -3
  239. package/dist/output/text/search.js +4 -3
  240. package/dist/output/text/show.js +4 -3
  241. package/dist/output/text/update.js +2 -3
  242. package/dist/output/text/upgrade.js +2 -3
  243. package/dist/output/text/wiki.js +12 -11
  244. package/dist/output/text/workflow.js +12 -10
  245. package/dist/output/text.js +66 -32
  246. package/dist/registry/build-index.js +11 -10
  247. package/dist/registry/factory.js +1 -1
  248. package/dist/registry/origin-resolve.js +1 -1
  249. package/dist/registry/providers/index.js +2 -2
  250. package/dist/registry/providers/skills-sh.js +91 -72
  251. package/dist/registry/providers/static-index.js +75 -52
  252. package/dist/registry/resolve.js +3 -3
  253. package/dist/runtime.js +242 -0
  254. package/dist/scripts/migrate-storage.js +1594 -673
  255. package/dist/scripts/migrations/import-fs-improve-runs-to-db.js +240 -166
  256. package/dist/setup/detect.js +338 -9
  257. package/dist/setup/harness-config-import.js +56 -0
  258. package/dist/setup/registry-stash-loader.js +99 -0
  259. package/dist/setup/setup.js +664 -96
  260. package/dist/sources/include.js +1 -1
  261. package/dist/sources/provider-factory.js +2 -2
  262. package/dist/sources/providers/filesystem.js +3 -3
  263. package/dist/sources/providers/git.js +9 -9
  264. package/dist/sources/providers/index.js +4 -4
  265. package/dist/sources/providers/npm.js +6 -6
  266. package/dist/sources/providers/provider-utils.js +13 -20
  267. package/dist/sources/providers/sync-from-ref.js +5 -5
  268. package/dist/sources/providers/tar-utils.js +2 -2
  269. package/dist/sources/providers/website.js +2 -2
  270. package/dist/sources/resolve.js +5 -5
  271. package/dist/sources/website-ingest.js +5 -5
  272. package/dist/storage/database.js +102 -0
  273. package/dist/storage/engines/sqlite-migrations.js +42 -0
  274. package/dist/storage/locations.js +25 -0
  275. package/dist/storage/repositories/index-db.js +43 -0
  276. package/dist/storage/repositories/workflow-runs-repository.js +141 -0
  277. package/dist/tasks/backends/cron.js +4 -4
  278. package/dist/tasks/backends/exec-utils.js +32 -0
  279. package/dist/tasks/backends/index.js +3 -3
  280. package/dist/tasks/backends/launchd.js +7 -14
  281. package/dist/tasks/backends/schtasks.js +7 -16
  282. package/dist/tasks/embedded.js +71 -0
  283. package/dist/tasks/parser.js +2 -2
  284. package/dist/tasks/resolveAkmBin.js +1 -1
  285. package/dist/tasks/runner.js +28 -15
  286. package/dist/tasks/schedule.js +1 -1
  287. package/dist/tasks/validator.js +7 -7
  288. package/dist/text-import-hook.mjs +51 -0
  289. package/dist/version.js +2 -1
  290. package/dist/wiki/wiki.js +7 -7
  291. package/dist/workflows/{authoring.js → authoring/authoring.js} +6 -6
  292. package/dist/workflows/{scope-key.js → authoring/scope-key.js} +1 -1
  293. package/dist/workflows/cli.js +1 -1
  294. package/dist/workflows/db.js +50 -32
  295. package/dist/workflows/parser.js +4 -4
  296. package/dist/workflows/renderer.js +5 -5
  297. package/dist/workflows/runtime/agent-identity.js +56 -0
  298. package/dist/workflows/runtime/checkin.js +57 -0
  299. package/dist/workflows/{runs.js → runtime/runs.js} +197 -101
  300. package/dist/workflows/validate-summary.js +82 -0
  301. package/docs/README.md +1 -1
  302. package/docs/data-and-telemetry.md +6 -6
  303. package/package.json +16 -8
  304. package/dist/commands/add-cli.js +0 -279
  305. package/dist/commands/env.js +0 -213
  306. package/dist/integrations/agent/sdk-runner.js +0 -126
  307. package/dist/output/shapes/vault-list.js +0 -19
  308. package/dist/output/text/proposal-producer.js +0 -8
  309. package/dist/output/text/proposal.js +0 -12
  310. package/dist/output/text/vault.js +0 -16
  311. /package/dist/core/{asset-serialize.js → asset/asset-serialize.js} +0 -0
  312. /package/dist/core/{frontmatter.js → asset/frontmatter.js} +0 -0
  313. /package/dist/core/{config-sources.js → config/config-sources.js} +0 -0
  314. /package/dist/indexer/{graph-dedup.js → graph/graph-dedup.js} +0 -0
  315. /package/dist/{core/config-types.js → indexer/passes/pass-context.js} +0 -0
  316. /package/dist/indexer/{search-fields.js → search/search-fields.js} +0 -0
  317. /package/dist/indexer/{index-context.js → walk/index-context.js} +0 -0
  318. /package/dist/workflows/{document-cache.js → runtime/document-cache.js} +0 -0
@@ -2,6 +2,38 @@
2
2
  // License, v. 2.0. If a copy of the MPL was not distributed with this
3
3
  // file, You can obtain one at https://mozilla.org/MPL/2.0/.
4
4
  import { spawnSync } from "node:child_process";
5
+ import fs from "node:fs";
6
+ /**
7
+ * Default exec strategy: run commands synchronously via {@link spawnCommand}.
8
+ *
9
+ * This is the shared default for every task backend's `exec` seam. Backends
10
+ * that need extra fields (e.g. launchd's `uid()`) spread this and add them.
11
+ */
12
+ export function nodeExec() {
13
+ return {
14
+ run(args) {
15
+ return spawnCommand(args);
16
+ },
17
+ };
18
+ }
19
+ /**
20
+ * Default filesystem strategy for the shared subset of the backend `fs` seam
21
+ * (`writeFile` + `ensureDir`), backed by `node:fs`.
22
+ *
23
+ * Backends spread this and add their own members. Note `removeFile` is NOT
24
+ * shared here: the launchd and schtasks defaults differ observably (schtasks
25
+ * swallows errors; launchd does not), so each keeps its own.
26
+ */
27
+ export function nodeFs() {
28
+ return {
29
+ writeFile(file, content) {
30
+ fs.writeFileSync(file, content, { encoding: "utf8" });
31
+ },
32
+ ensureDir(dir) {
33
+ fs.mkdirSync(dir, { recursive: true });
34
+ },
35
+ };
36
+ }
5
37
  /**
6
38
  * Run a command synchronously, normalizing null results to safe defaults.
7
39
  * args[0] is the binary; args[1..] are its arguments.
@@ -1,9 +1,9 @@
1
1
  // This Source Code Form is subject to the terms of the Mozilla Public
2
2
  // License, v. 2.0. If a copy of the MPL was not distributed with this
3
3
  // file, You can obtain one at https://mozilla.org/MPL/2.0/.
4
- import { CRON_BACKEND } from "./cron";
5
- import { LAUNCHD_BACKEND } from "./launchd";
6
- import { SCHTASKS_BACKEND } from "./schtasks";
4
+ import { CRON_BACKEND } from "./cron.js";
5
+ import { LAUNCHD_BACKEND } from "./launchd.js";
6
+ import { SCHTASKS_BACKEND } from "./schtasks.js";
7
7
  export function selectBackend(options = {}) {
8
8
  const platform = options.platform ?? process.platform;
9
9
  switch (platform) {
@@ -25,11 +25,11 @@ import fs from "node:fs";
25
25
  import os from "node:os";
26
26
  import path from "node:path";
27
27
  import launchdTemplate from "../../assets/backends/launchd-template.xml" with { type: "text" };
28
- import { ConfigError } from "../../core/errors";
29
- import { getTaskLogDir } from "../../core/paths";
30
- import { resolveAkmInvocation } from "../resolveAkmBin";
31
- import { parseSchedule, translateToLaunchd } from "../schedule";
32
- import { escapeXml, spawnCommand } from "./exec-utils";
28
+ import { ConfigError } from "../../core/errors.js";
29
+ import { getTaskLogDir } from "../../core/paths.js";
30
+ import { resolveAkmInvocation } from "../resolveAkmBin.js";
31
+ import { parseSchedule, translateToLaunchd } from "../schedule.js";
32
+ import { escapeXml, nodeExec, nodeFs } from "./exec-utils.js";
33
33
  export const LAUNCHD_LABEL_PREFIX = "com.akm.task.";
34
34
  export function LAUNCHD_BACKEND(options = {}) {
35
35
  const exec = options.exec ?? defaultLaunchdExec();
@@ -152,9 +152,7 @@ function defaultAgentsDir() {
152
152
  }
153
153
  function defaultLaunchdExec() {
154
154
  return {
155
- run(args) {
156
- return spawnCommand(args);
157
- },
155
+ ...nodeExec(),
158
156
  uid() {
159
157
  const fn = process.getuid;
160
158
  return typeof fn === "function" ? fn.call(process) : 0;
@@ -163,15 +161,10 @@ function defaultLaunchdExec() {
163
161
  }
164
162
  function defaultLaunchdFs() {
165
163
  return {
166
- writeFile(file, content) {
167
- fs.writeFileSync(file, content, { encoding: "utf8" });
168
- },
164
+ ...nodeFs(),
169
165
  removeFile(file) {
170
166
  fs.rmSync(file, { force: true });
171
167
  },
172
- ensureDir(dir) {
173
- fs.mkdirSync(dir, { recursive: true });
174
- },
175
168
  list(dir) {
176
169
  try {
177
170
  return fs.readdirSync(dir);
@@ -33,11 +33,11 @@ import fs from "node:fs";
33
33
  import os from "node:os";
34
34
  import path from "node:path";
35
35
  import schtasksTemplate from "../../assets/backends/schtasks-template.xml" with { type: "text" };
36
- import { ConfigError } from "../../core/errors";
37
- import { getTaskLogDir } from "../../core/paths";
38
- import { resolveAkmInvocation } from "../resolveAkmBin";
39
- import { parseSchedule, translateToSchtasks } from "../schedule";
40
- import { escapeXml, spawnCommand } from "./exec-utils";
36
+ import { ConfigError } from "../../core/errors.js";
37
+ import { getTaskLogDir } from "../../core/paths.js";
38
+ import { resolveAkmInvocation } from "../resolveAkmBin.js";
39
+ import { parseSchedule, translateToSchtasks } from "../schedule.js";
40
+ import { escapeXml, nodeExec, nodeFs } from "./exec-utils.js";
41
41
  export const DEFAULT_FOLDER_PREFIX = "\\akm\\";
42
42
  export function SCHTASKS_BACKEND(options = {}) {
43
43
  const exec = options.exec ?? defaultSchtasksExec();
@@ -186,17 +186,11 @@ function quoteArg(s) {
186
186
  return `"${s.replace(/"/g, '\\"')}"`;
187
187
  }
188
188
  function defaultSchtasksExec() {
189
- return {
190
- run(args) {
191
- return spawnCommand(args);
192
- },
193
- };
189
+ return nodeExec();
194
190
  }
195
191
  function defaultSchtasksFs() {
196
192
  return {
197
- writeFile(file, content) {
198
- fs.writeFileSync(file, content, { encoding: "utf8" });
199
- },
193
+ ...nodeFs(),
200
194
  removeFile(file) {
201
195
  try {
202
196
  fs.rmSync(file, { force: true });
@@ -205,9 +199,6 @@ function defaultSchtasksFs() {
205
199
  /* ignore */
206
200
  }
207
201
  },
208
- ensureDir(dir) {
209
- fs.mkdirSync(dir, { recursive: true });
210
- },
211
202
  tmpdir() {
212
203
  return os.tmpdir();
213
204
  },
@@ -0,0 +1,71 @@
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
+ * Embedded core task templates.
6
+ *
7
+ * A curated set of read-only YAML task templates ships inside the akm binary
8
+ * under `src/assets/tasks/core/`. They are resolved at runtime via
9
+ * `import.meta.dir` (mirroring `SKELETON_DIR` in
10
+ * src/commands/stash-skeleton.ts) and are NOT written to any stash at
11
+ * install/init time — the `akm setup` wizard copies a template into the
12
+ * primary stash only when the user opts in (copy-on-enable).
13
+ *
14
+ * Each entry exposes the parsed `command`, `schedule`, and `description`
15
+ * alongside the raw `yaml`, so the wizard can both render a choice and write
16
+ * the file verbatim (with an optional schedule edit applied).
17
+ */
18
+ import fs from "node:fs";
19
+ import path from "node:path";
20
+ import { parse as yamlParse } from "yaml";
21
+ import { getDirname } from "../runtime.js";
22
+ /** Directory holding the bundled core task templates. */
23
+ const CORE_TASKS_DIR = path.join(getDirname(import.meta.url), "../assets/tasks/core");
24
+ /**
25
+ * Enumerate the embedded core task templates from the bundled assets
26
+ * directory. Sorted by id for deterministic ordering. Returns an empty array
27
+ * if the directory is missing (defensive — a build without assets should not
28
+ * crash the wizard).
29
+ */
30
+ export function listEmbeddedTasks() {
31
+ let entries;
32
+ try {
33
+ entries = fs.readdirSync(CORE_TASKS_DIR);
34
+ }
35
+ catch {
36
+ return [];
37
+ }
38
+ const tasks = [];
39
+ for (const entry of entries.sort()) {
40
+ if (!entry.endsWith(".yml"))
41
+ continue;
42
+ const id = entry.slice(0, -4);
43
+ const filePath = path.join(CORE_TASKS_DIR, entry);
44
+ let yaml;
45
+ try {
46
+ yaml = fs.readFileSync(filePath, "utf8");
47
+ }
48
+ catch {
49
+ continue;
50
+ }
51
+ let doc;
52
+ try {
53
+ doc = yamlParse(yaml) ?? {};
54
+ }
55
+ catch {
56
+ continue;
57
+ }
58
+ const command = typeof doc.command === "string" ? doc.command : "";
59
+ const schedule = typeof doc.schedule === "string" ? doc.schedule : "";
60
+ const description = typeof doc.description === "string" ? doc.description : "";
61
+ tasks.push({
62
+ id,
63
+ label: `core/${id}`,
64
+ command,
65
+ schedule,
66
+ description,
67
+ yaml,
68
+ });
69
+ }
70
+ return tasks;
71
+ }
@@ -35,8 +35,8 @@
35
35
  */
36
36
  import path from "node:path";
37
37
  import { parse as parseYaml } from "yaml";
38
- import { UsageError } from "../core/errors";
39
- import { TASK_SCHEMA_VERSION } from "./schema";
38
+ import { UsageError } from "../core/errors.js";
39
+ import { TASK_SCHEMA_VERSION } from "./schema.js";
40
40
  export function parseTaskDocument(input) {
41
41
  const { yaml, filePath, id } = input;
42
42
  let data;
@@ -24,7 +24,7 @@ import { spawnSync } from "node:child_process";
24
24
  import fs from "node:fs";
25
25
  import path from "node:path";
26
26
  import { fileURLToPath } from "node:url";
27
- import { ConfigError } from "../core/errors";
27
+ import { ConfigError } from "../core/errors.js";
28
28
  export function resolveAkmInvocation(options = {}) {
29
29
  const env = options.env ?? process.env;
30
30
  const override = env.AKM_BIN?.trim();
@@ -24,19 +24,21 @@
24
24
  */
25
25
  import fs from "node:fs";
26
26
  import path from "node:path";
27
- import { parseAssetRef } from "../core/asset-ref";
28
- import { resolveStashDir } from "../core/common";
29
- import { loadConfig } from "../core/config";
30
- import { NotFoundError, rethrowIfTestIsolationError } from "../core/errors";
31
- import { getTaskLogDir } from "../core/paths";
32
- import { getTaskHistory, openStateDatabase, queryTaskHistory, upsertTaskHistory } from "../core/state-db";
33
- import { error } from "../core/warn";
34
- import { requireAgentProfile, runAgent } from "../integrations/agent";
35
- import { resolveProcessAgentProfile } from "../integrations/agent/config";
36
- import { resolveRunner } from "../integrations/agent/runner";
37
- import { resolveAssetPath } from "../sources/resolve";
38
- import { startWorkflowRun } from "../workflows/runs";
39
- import { parseTaskDocument } from "./parser";
27
+ import { assertNever } from "../core/assert.js";
28
+ import { parseAssetRef } from "../core/asset/asset-ref.js";
29
+ import { resolveStashDir } from "../core/common.js";
30
+ import { loadConfig } from "../core/config/config.js";
31
+ import { NotFoundError, rethrowIfTestIsolationError } from "../core/errors.js";
32
+ import { getTaskLogDir } from "../core/paths.js";
33
+ import { getTaskHistory, openStateDatabase, queryTaskHistory, upsertTaskHistory } from "../core/state-db.js";
34
+ import { error } from "../core/warn.js";
35
+ import { requireAgentProfile, runAgent } from "../integrations/agent/index.js";
36
+ import { resolveProcessAgentProfile } from "../integrations/agent/config.js";
37
+ import { resolveRunner } from "../integrations/agent/runner.js";
38
+ import { spawn } from "../runtime.js";
39
+ import { resolveAssetPath } from "../sources/resolve.js";
40
+ import { startWorkflowRun } from "../workflows/runtime/runs.js";
41
+ import { parseTaskDocument } from "./parser.js";
40
42
  export async function runTask(id, options = {}) {
41
43
  const stashDir = options.stashDir ?? resolveStashDir();
42
44
  const runAgentImpl = options.runAgentImpl ?? runAgent;
@@ -111,7 +113,7 @@ async function runCommandTask(input) {
111
113
  let stderr = "";
112
114
  let exitCode = null;
113
115
  try {
114
- const proc = Bun.spawn(cmd, {
116
+ const proc = spawn(cmd, {
115
117
  stdin: "ignore",
116
118
  stdout: "pipe",
117
119
  stderr: "pipe",
@@ -222,8 +224,19 @@ async function runWorkflowTask(input) {
222
224
  * returns (multi-step workflows pause for user input); recording them as
223
225
  * "completed" would be misleading. We preserve "active" as a first-class
224
226
  * task status with exit code 0 — the OS scheduler treats it as success.
227
+ *
228
+ * The parameter is typed as the runtime's `WorkflowRunStatus` union (plus the
229
+ * `undefined` that `detail?.run.status` can produce when no detail is present).
230
+ * Every union member is handled explicitly and the `default` arm calls
231
+ * `assertNever`, so adding a new `WorkflowRunStatus` variant without mapping it
232
+ * here is a *compile* error rather than silently collapsing to "completed".
233
+ * The previous silent `default: "completed"` is preserved only for the
234
+ * `undefined` (no-detail) case, which is handled up front.
225
235
  */
226
236
  function mapWorkflowStatus(status) {
237
+ // No run detail → treat as completed (unchanged from the prior silent default).
238
+ if (status === undefined)
239
+ return "completed";
227
240
  switch (status) {
228
241
  case "completed":
229
242
  case "blocked":
@@ -231,7 +244,7 @@ function mapWorkflowStatus(status) {
231
244
  case "active":
232
245
  return status;
233
246
  default:
234
- return "completed";
247
+ return assertNever(status, "mapWorkflowStatus");
235
248
  }
236
249
  }
237
250
  function renderWorkflowLog(input) {
@@ -26,7 +26,7 @@
26
26
  * Linux may fail to translate when copied to macOS/Windows. `tasks sync`
27
27
  * re-validates against the local backend and surfaces any incompatibility.
28
28
  */
29
- import { UsageError } from "../core/errors";
29
+ import { UsageError } from "../core/errors.js";
30
30
  const ALIAS_TO_CRON = {
31
31
  "@hourly": "0 * * * *",
32
32
  "@daily": "0 0 * * *",
@@ -16,13 +16,13 @@
16
16
  */
17
17
  import fs from "node:fs";
18
18
  import path from "node:path";
19
- import { parseAssetRef } from "../core/asset-ref";
20
- import { resolveStashDir } from "../core/common";
21
- import { loadConfig } from "../core/config";
22
- import { NotFoundError } from "../core/errors";
23
- import { requireAgentProfile } from "../integrations/agent";
24
- import { resolveAssetPath } from "../sources/resolve";
25
- import { parseSchedule } from "./schedule";
19
+ import { parseAssetRef } from "../core/asset/asset-ref.js";
20
+ import { resolveStashDir } from "../core/common.js";
21
+ import { loadConfig } from "../core/config/config.js";
22
+ import { NotFoundError } from "../core/errors.js";
23
+ import { requireAgentProfile } from "../integrations/agent/index.js";
24
+ import { resolveAssetPath } from "../sources/resolve.js";
25
+ import { parseSchedule } from "./schedule.js";
26
26
  export async function validateTaskDocument(task, options) {
27
27
  // Schedule must parse and translate.
28
28
  parseSchedule(task.schedule, options.backend);
@@ -0,0 +1,51 @@
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
+ // Node ESM loader hook: support `import x from "./foo.md" with { type: "text" }`.
6
+ //
7
+ // Bun has a built-in text loader; Node does not (it only understands
8
+ // `type: "json"`). akm embeds prompt/template assets via `with { type: "text" }`
9
+ // imports that are statically hoisted into the module graph, so Node fails at
10
+ // load time with ERR_UNKNOWN_FILE_EXTENSION / unsupported import attribute
11
+ // before any command runs. This hook makes Node treat those imports as a module
12
+ // whose default export is the file's UTF-8 contents — byte-identical to Bun's
13
+ // text loader. It is ONLY registered on the Node entry path (see cli-node.mjs);
14
+ // Bun never loads it, so the Bun runtime is untouched.
15
+
16
+ import { readFile } from "node:fs/promises";
17
+ import { fileURLToPath } from "node:url";
18
+
19
+ const TEXT_EXTENSIONS = new Set([".md", ".xml", ".txt", ".sql"]);
20
+
21
+ function isTextImport(url, importAttributes) {
22
+ if (importAttributes && importAttributes.type === "text") return true;
23
+ const i = url.lastIndexOf(".");
24
+ if (i === -1) return false;
25
+ return TEXT_EXTENSIONS.has(url.slice(i).toLowerCase().split("?")[0]);
26
+ }
27
+
28
+ export async function load(url, context, nextLoad) {
29
+ if (url.startsWith("file:") && isTextImport(url, context.importAttributes)) {
30
+ const text = await readFile(fileURLToPath(url), "utf8");
31
+ return {
32
+ format: "module",
33
+ shortCircuit: true,
34
+ source: `export default ${JSON.stringify(text)};`,
35
+ };
36
+ }
37
+ return nextLoad(url, context);
38
+ }
39
+
40
+ // Node validates import attributes against the resolved format and rejects an
41
+ // unknown `type: "text"` during resolution. Strip the attribute here so our
42
+ // `load` hook (above) can take over; the assertion has already served its
43
+ // purpose of routing to text handling.
44
+ export async function resolve(specifier, context, nextResolve) {
45
+ const result = await nextResolve(specifier, context);
46
+ if (result.importAttributes && result.importAttributes.type === "text") {
47
+ const { type, ...rest } = result.importAttributes;
48
+ return { ...result, importAttributes: rest };
49
+ }
50
+ return result;
51
+ }
package/dist/version.js CHANGED
@@ -3,13 +3,14 @@
3
3
  // file, You can obtain one at https://mozilla.org/MPL/2.0/.
4
4
  import fs from "node:fs";
5
5
  import path from "node:path";
6
+ import { getDirname } from "./runtime.js";
6
7
  // Version: prefer compile-time define, then package.json, then fallback
7
8
  export const pkgVersion = (() => {
8
9
  // Injected at compile time via `bun build --define`
9
10
  if (typeof AKM_VERSION !== "undefined")
10
11
  return AKM_VERSION;
11
12
  try {
12
- const pkgPath = path.resolve(import.meta.dir ?? __dirname, "../package.json");
13
+ const pkgPath = path.resolve(getDirname(import.meta.url), "../package.json");
13
14
  if (fs.existsSync(pkgPath)) {
14
15
  const pkg = JSON.parse(fs.readFileSync(pkgPath, "utf-8"));
15
16
  if (typeof pkg.version === "string")
package/dist/wiki/wiki.js CHANGED
@@ -45,13 +45,13 @@ import fs from "node:fs";
45
45
  import path from "node:path";
46
46
  import { parse as yamlParse } from "yaml";
47
47
  import ingestWorkflowTemplate from "../assets/wiki/ingest-workflow-template.md" with { type: "text" };
48
- import { akmSearch } from "../commands/search";
49
- import { isWithin, todayIso } from "../core/common";
50
- import { getSources, loadUserConfig, saveConfig } from "../core/config";
51
- import { NotFoundError, UsageError } from "../core/errors";
52
- import { parseFrontmatter, parseFrontmatterBlock } from "../core/frontmatter";
53
- import { resolveSourceEntries } from "../indexer/search-source";
54
- import { buildIndexMd, buildLogMd, buildSchemaMd } from "./wiki-templates";
48
+ import { akmSearch } from "../commands/read/search.js";
49
+ import { parseFrontmatter, parseFrontmatterBlock } from "../core/asset/frontmatter.js";
50
+ import { isWithin, todayIso } from "../core/common.js";
51
+ import { getSources, loadUserConfig, saveConfig } from "../core/config/config.js";
52
+ import { NotFoundError, UsageError } from "../core/errors.js";
53
+ import { resolveSourceEntries } from "../indexer/search/search-source.js";
54
+ import { buildIndexMd, buildLogMd, buildSchemaMd } from "./wiki-templates.js";
55
55
  // ── Constants ───────────────────────────────────────────────────────────────
56
56
  export const WIKIS_SUBDIR = "wikis";
57
57
  export const SCHEMA_MD = "schema.md";
@@ -3,12 +3,12 @@
3
3
  // file, You can obtain one at https://mozilla.org/MPL/2.0/.
4
4
  import fs from "node:fs";
5
5
  import path from "node:path";
6
- import workflowTemplate from "../assets/workflows/workflow-template.md" with { type: "text" };
7
- import { resolveAssetPathFromName } from "../core/asset-spec";
8
- import { isWithin, resolveStashDir } from "../core/common";
9
- import { UsageError } from "../core/errors";
10
- import { warn } from "../core/warn";
11
- import { parseWorkflow } from "./parser";
6
+ import workflowTemplate from "../../assets/workflows/workflow-template.md" with { type: "text" };
7
+ import { resolveAssetPathFromName } from "../../core/asset/asset-spec.js";
8
+ import { isWithin, resolveStashDir } from "../../core/common.js";
9
+ import { UsageError } from "../../core/errors.js";
10
+ import { warn } from "../../core/warn.js";
11
+ import { parseWorkflow } from "../parser.js";
12
12
  const DEFAULT_WORKFLOW_TEMPLATE = renderWorkflowTemplate({
13
13
  title: "Example Workflow",
14
14
  firstStepTitle: "First Step",
@@ -4,7 +4,7 @@
4
4
  import { createHash } from "node:crypto";
5
5
  import fs from "node:fs";
6
6
  import path from "node:path";
7
- import { isWithin, resolveStashDir, safeRealpath, toPosix } from "../core/common";
7
+ import { isWithin, resolveStashDir, safeRealpath, toPosix } from "../../core/common.js";
8
8
  const PROJECT_CONFIG_RELATIVE_PATH = path.join(".akm", "config.json");
9
9
  export function getCurrentWorkflowScopeKey() {
10
10
  const anchor = resolveWorkflowScopeAnchor(process.cwd());
@@ -1,7 +1,7 @@
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
- import { UsageError } from "../core/errors";
4
+ import { UsageError } from "../core/errors.js";
5
5
  export const WORKFLOW_STEP_STATES = [
6
6
  "completed",
7
7
  "blocked",
@@ -1,10 +1,11 @@
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
- import { Database } from "bun:sqlite";
5
4
  import fs from "node:fs";
6
5
  import path from "node:path";
7
- import { getWorkflowDbPath } from "../core/paths";
6
+ import { getWorkflowDbPath } from "../core/paths.js";
7
+ import { openDatabase } from "../storage/database.js";
8
+ import { runMigrations as runSqliteMigrations } from "../storage/engines/sqlite-migrations.js";
8
9
  /**
9
10
  * workflow.db — Durable SQLite database for workflow run state.
10
11
  *
@@ -44,7 +45,7 @@ export function openWorkflowDatabase(dbPath = getWorkflowDbPath()) {
44
45
  if (!fs.existsSync(dir)) {
45
46
  fs.mkdirSync(dir, { recursive: true });
46
47
  }
47
- const db = new Database(dbPath);
48
+ const db = openDatabase(dbPath);
48
49
  db.exec("PRAGMA journal_mode = WAL");
49
50
  db.exec("PRAGMA foreign_keys = ON");
50
51
  ensureBaseSchema(db);
@@ -102,6 +103,13 @@ function ensureBaseSchema(db) {
102
103
  ON workflow_run_steps(run_id, sequence_index);
103
104
  `);
104
105
  }
106
+ // ── Migration engine ─────────────────────────────────────────────────────────
107
+ //
108
+ // The runner itself (ensureMigrationsTable + runMigrations) lives in the shared
109
+ // engine at src/storage/engines/sqlite-migrations.ts. This module owns its own
110
+ // MIGRATIONS array plus the pre-versioning `bootstrap` hook, and delegates
111
+ // application to that shared runner. The {@link Migration} interface is imported
112
+ // from there.
105
113
  /**
106
114
  * All workflow.db migrations in application order. New migrations are
107
115
  * APPENDED — never inserted in the middle or reordered.
@@ -121,29 +129,50 @@ const MIGRATIONS = [
121
129
  ON workflow_runs(scope_key, workflow_ref, status);
122
130
  `,
123
131
  },
132
+ // ── Migration 002 — record agent harness + session identity ──────────────────
133
+ //
134
+ // Persists the agent harness identifier (e.g. "claude-code", "opencode") and
135
+ // the platform-native session id that owns each workflow run. This is the
136
+ // first concrete slice of #501 / #506: capturing *who* is driving a run so a
137
+ // future (separately-approved) monitor can correlate workflow runs with
138
+ // session activity. Both columns are nullable — runs started outside an agent
139
+ // harness, and all pre-existing runs, simply have NULL identity.
140
+ {
141
+ id: "002-add-agent-identity",
142
+ up: `
143
+ ALTER TABLE workflow_runs ADD COLUMN agent_harness TEXT;
144
+ ALTER TABLE workflow_runs ADD COLUMN agent_session_id TEXT;
145
+
146
+ CREATE INDEX IF NOT EXISTS idx_workflow_runs_agent_session
147
+ ON workflow_runs(agent_harness, agent_session_id);
148
+ `,
149
+ },
150
+ // ── Migration 003 — check-in arming + per-step summary (#506) ────────────────
151
+ //
152
+ // Builds on the agent identity recorded by migration 002. Arms a file-signal
153
+ // check-in (a timestamp, NOT a background thread — see
154
+ // docs/technical/workflow-agent-checkin-adr.md) so a stalled run can be
155
+ // re-targeted with a `continue` directive, and adds a per-step `summary`
156
+ // column so step/workflow completion can capture and validate a required
157
+ // summary of work done. Both columns are nullable.
158
+ {
159
+ id: "003-checkin-and-step-summary",
160
+ up: `
161
+ ALTER TABLE workflow_runs ADD COLUMN checkin_armed_at TEXT;
162
+ ALTER TABLE workflow_run_steps ADD COLUMN summary TEXT;
163
+ `,
164
+ },
124
165
  ];
125
166
  /**
126
167
  * Stable id of the scope_key migration. Exported for bootstrap detection and
127
168
  * tests.
128
169
  */
129
170
  const SCOPE_KEY_MIGRATION_ID = "001-add-scope-key";
130
- /**
131
- * Create the migrations table if it does not exist. Called unconditionally on
132
- * every open so a fresh database bootstraps correctly.
133
- */
134
- function ensureMigrationsTable(db) {
135
- db.exec(`
136
- CREATE TABLE IF NOT EXISTS schema_migrations (
137
- id TEXT PRIMARY KEY,
138
- applied_at TEXT NOT NULL DEFAULT (datetime('now'))
139
- );
140
- `);
141
- }
142
171
  /**
143
172
  * Detect whether a column exists on a given table.
144
173
  */
145
174
  function hasColumn(db, table, column) {
146
- const rows = db.query(`PRAGMA table_info(${table})`).all();
175
+ const rows = db.prepare(`PRAGMA table_info(${table})`).all();
147
176
  return rows.some((r) => r.name === column);
148
177
  }
149
178
  /**
@@ -171,24 +200,13 @@ function bootstrapPreVersioningDb(db) {
171
200
  /**
172
201
  * Apply every pending migration in a single transaction per migration.
173
202
  *
174
- * Each migration is applied in its own transaction so a failure in migration N
175
- * does not roll back already-applied migrations 1..N-1. The migration row is
176
- * inserted AFTER the DDL succeeds a crash mid-migration leaves no row and
177
- * the migration is retried on next open.
203
+ * Delegates to the shared SQLite migration engine, passing the
204
+ * `bootstrapPreVersioningDb` hook so databases created before this file gained
205
+ * migration tracking back-fill their scope_key row instead of re-running the
206
+ * ALTER.
178
207
  *
179
208
  * Called automatically by {@link openWorkflowDatabase}.
180
209
  */
181
210
  export function runMigrations(db) {
182
- ensureMigrationsTable(db);
183
- bootstrapPreVersioningDb(db);
184
- const appliedRows = db.prepare("SELECT id FROM schema_migrations").all();
185
- const applied = new Set(appliedRows.map((r) => r.id));
186
- for (const migration of MIGRATIONS) {
187
- if (applied.has(migration.id))
188
- continue;
189
- db.transaction(() => {
190
- db.exec(migration.up);
191
- db.prepare("INSERT INTO schema_migrations (id) VALUES (?)").run(migration.id);
192
- })();
193
- }
211
+ runSqliteMigrations(db, MIGRATIONS, { bootstrap: bootstrapPreVersioningDb });
194
212
  }
@@ -11,10 +11,10 @@
11
11
  * line spans, accumulating `WorkflowError`s rather than throwing.
12
12
  */
13
13
  import { parse as yamlParse } from "yaml";
14
- import { parseFrontmatterBlock } from "../core/frontmatter";
15
- import { parseMarkdownToc } from "../core/markdown";
16
- import { WORKFLOW_SCHEMA_VERSION, } from "./schema";
17
- import { runSemanticChecks } from "./validator";
14
+ import { parseFrontmatterBlock } from "../core/asset/frontmatter.js";
15
+ import { parseMarkdownToc } from "../core/asset/markdown.js";
16
+ import { WORKFLOW_SCHEMA_VERSION, } from "./schema.js";
17
+ import { runSemanticChecks } from "./validator.js";
18
18
  const WORKFLOW_TITLE_PREFIX = "Workflow:";
19
19
  const STEP_PREFIX = "Step:";
20
20
  const STEP_ID_LINE = /^Step ID:\s+(.+?)\s*$/;
@@ -9,11 +9,11 @@
9
9
  * uses the flat `WorkflowStepDefinition` type for backwards compatibility)
10
10
  * and into search hints for the indexer.
11
11
  */
12
- import { makeAssetRef } from "../core/asset-ref";
13
- import { UsageError } from "../core/errors";
14
- import { registerMetadataContributor } from "../indexer/metadata-contributors";
15
- import { cacheWorkflowDocument } from "./document-cache";
16
- import { parseWorkflow } from "./parser";
12
+ import { makeAssetRef } from "../core/asset/asset-ref.js";
13
+ import { UsageError } from "../core/errors.js";
14
+ import { registerMetadataContributor } from "../indexer/passes/metadata-contributors.js";
15
+ import { parseWorkflow } from "./parser.js";
16
+ import { cacheWorkflowDocument } from "./runtime/document-cache.js";
17
17
  function shellQuote(value) {
18
18
  return `'${value.replace(/'/g, `'\\''`)}'`;
19
19
  }