akm-cli 0.8.7 → 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 +428 -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} +48 -36
  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
@@ -0,0 +1,307 @@
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
+ * `akm wiki` command family. Extracted verbatim from src/cli.ts (WS6) so the
6
+ * God Module shrinks; the `main.subCommands.wiki` key and every subcommand's
7
+ * args/output shape are byte-identical. Handlers whose body is a plain
8
+ * `runWithJsonErrors(...) + output(...)` are migrated to `defineJsonCommand`,
9
+ * which emits the same JSON envelope (stdout/stderr/exit-code) as the inline
10
+ * form. `wiki lint` keeps an explicit `runWithJsonErrors` because it calls
11
+ * `process.exit(1)` after the wrapper when findings exist.
12
+ */
13
+ import { defineCommand } from "citty";
14
+ import { getStringArg, hasSubcommand, parsePositiveIntFlag } from "../cli/parse-args.js";
15
+ import { defineJsonCommand, output, runWithJsonErrors } from "../cli/shared.js";
16
+ import { isHttpUrl, resolveStashDir } from "../core/common.js";
17
+ import { loadConfig, resolveConfiguredSources } from "../core/config/config.js";
18
+ import { ConfigError, UsageError } from "../core/errors.js";
19
+ import { getHyphenatedArg, getHyphenatedBoolean } from "../output/context.js";
20
+ import { akmAgentDispatch } from "./agent/agent-dispatch.js";
21
+ import { readKnowledgeInput } from "./read/knowledge.js";
22
+ import { buildWebsiteOptions } from "./sources/add-cli.js";
23
+ const wikiCreateCommand = defineJsonCommand({
24
+ meta: { name: "create", description: "Scaffold a new wiki under <stashDir>/wikis/<name>/" },
25
+ args: {
26
+ name: { type: "positional", description: "Wiki name (lowercase, digits, hyphens)", required: true },
27
+ },
28
+ async run({ args }) {
29
+ const { createWiki } = await import("../wiki/wiki.js");
30
+ const stashDir = resolveStashDir();
31
+ const result = createWiki(stashDir, args.name);
32
+ output("wiki-create", result);
33
+ },
34
+ });
35
+ const wikiRegisterCommand = defineJsonCommand({
36
+ meta: {
37
+ name: "register",
38
+ description: "Register an existing directory or repo as a first-class wiki without copying or mutating it; refreshes source and wiki search state immediately",
39
+ },
40
+ args: {
41
+ name: { type: "positional", description: "Wiki name (lowercase, digits, hyphens)", required: true },
42
+ ref: { type: "positional", description: "Path or repo ref for the external wiki source", required: true },
43
+ writable: {
44
+ type: "boolean",
45
+ description: "Mark a git-backed source as writable so changes can be pushed back",
46
+ default: false,
47
+ },
48
+ "max-pages": { type: "string", description: "Maximum pages to crawl for website sources (default: 50)" },
49
+ "max-depth": { type: "string", description: "Maximum crawl depth for website sources (default: 3)" },
50
+ },
51
+ async run({ args }) {
52
+ const { registerWikiSource } = await import("./sources/source-add.js");
53
+ const result = await registerWikiSource({
54
+ ref: args.ref.trim(),
55
+ name: args.name,
56
+ options: Object.keys(buildWebsiteOptions(args)).length > 0 ? buildWebsiteOptions(args) : undefined,
57
+ writable: args.writable,
58
+ });
59
+ output("wiki-register", result);
60
+ },
61
+ });
62
+ const wikiListCommand = defineJsonCommand({
63
+ meta: { name: "list", description: "List wikis with page/raw counts and last-modified timestamps" },
64
+ async run() {
65
+ const { listWikis } = await import("../wiki/wiki.js");
66
+ const stashDir = resolveStashDir();
67
+ const wikis = listWikis(stashDir);
68
+ output("wiki-list", { wikis });
69
+ },
70
+ });
71
+ const wikiShowCommand = defineJsonCommand({
72
+ meta: { name: "show", description: "Show a wiki's path, description, counts, and last 3 log entries" },
73
+ args: {
74
+ name: { type: "positional", description: "Wiki name", required: true },
75
+ },
76
+ async run({ args }) {
77
+ const { showWiki } = await import("../wiki/wiki.js");
78
+ const stashDir = resolveStashDir();
79
+ const result = showWiki(stashDir, args.name);
80
+ output("wiki-show", result);
81
+ },
82
+ });
83
+ const wikiRemoveCommand = defineJsonCommand({
84
+ meta: {
85
+ name: "remove",
86
+ description: "Remove a wiki and refresh the index. Preserves raw/ by default; pass --with-sources to also delete raw/",
87
+ },
88
+ args: {
89
+ name: { type: "positional", description: "Wiki name", required: true },
90
+ yes: {
91
+ type: "boolean",
92
+ alias: "y",
93
+ description: "Skip confirmation prompt (required in non-interactive shells)",
94
+ default: false,
95
+ },
96
+ "with-sources": {
97
+ type: "boolean",
98
+ description: "Also delete the raw/ directory (immutable ingested sources)",
99
+ default: false,
100
+ },
101
+ },
102
+ async run({ args }) {
103
+ const { confirmDestructive } = await import("../cli/confirm.js");
104
+ const confirmed = await confirmDestructive(`Remove wiki "${args.name}"? This cannot be undone.`, {
105
+ yes: args.yes === true,
106
+ });
107
+ if (!confirmed) {
108
+ process.stderr.write("Aborted.\n");
109
+ return;
110
+ }
111
+ const withSources = getHyphenatedBoolean(args, "with-sources");
112
+ const { removeWiki } = await import("../wiki/wiki.js");
113
+ const { akmIndex } = await import("../indexer/indexer.js");
114
+ const stashDir = resolveStashDir();
115
+ const result = removeWiki(stashDir, args.name, { withSources });
116
+ await akmIndex({ stashDir });
117
+ output("wiki-remove", result);
118
+ },
119
+ });
120
+ const wikiPagesCommand = defineJsonCommand({
121
+ meta: {
122
+ name: "pages",
123
+ description: "List wiki pages (ref + frontmatter description), excluding schema/index/log/raw",
124
+ },
125
+ args: {
126
+ name: { type: "positional", description: "Wiki name", required: true },
127
+ },
128
+ async run({ args }) {
129
+ const { listPages } = await import("../wiki/wiki.js");
130
+ const stashDir = resolveStashDir();
131
+ const pages = listPages(stashDir, args.name);
132
+ output("wiki-pages", { wiki: args.name, pages });
133
+ },
134
+ });
135
+ const wikiSearchCommand = defineJsonCommand({
136
+ meta: {
137
+ name: "search",
138
+ description: "Search wiki pages within a single wiki (scoped wrapper over `akm search --type wiki`; excludes raw/schema/index/log and returns canonical wiki refs)",
139
+ },
140
+ args: {
141
+ name: { type: "positional", description: "Wiki name", required: true },
142
+ query: { type: "positional", description: "Search query", required: true },
143
+ limit: { type: "string", description: "Max hits (default 20)", required: false },
144
+ },
145
+ async run({ args }) {
146
+ const { resolveWikiSource, searchInWiki } = await import("../wiki/wiki.js");
147
+ const stashDir = resolveStashDir();
148
+ resolveWikiSource(stashDir, args.name);
149
+ const parsedLimit = args.limit ? Number(args.limit) : undefined;
150
+ const limit = typeof parsedLimit === "number" && Number.isFinite(parsedLimit) && parsedLimit > 0 ? parsedLimit : undefined;
151
+ const response = await searchInWiki({ stashDir, wikiName: args.name, query: args.query, limit });
152
+ output("search", response);
153
+ },
154
+ });
155
+ const wikiStashCommand = defineJsonCommand({
156
+ meta: {
157
+ name: "stash",
158
+ description: "Copy a source into wikis/<name>/raw/<slug>.md with frontmatter. Source may be a file path, URL, or '-' for stdin.",
159
+ },
160
+ args: {
161
+ name: { type: "positional", description: "Wiki name", required: true },
162
+ source: { type: "positional", description: "Source file path, URL, or '-' to read from stdin", required: true },
163
+ as: { type: "string", description: "Preferred slug base (defaults to source filename or first-line slug)" },
164
+ target: {
165
+ type: "string",
166
+ description: "Name of a writable stash source to write into instead of the default stash. Must match a configured source name (run `akm list` to see sources).",
167
+ },
168
+ },
169
+ async run({ args }) {
170
+ const { stashRaw } = await import("../wiki/wiki.js");
171
+ const { content, preferredName } = await (async () => {
172
+ if (!isHttpUrl(args.source))
173
+ return readKnowledgeInput(args.source);
174
+ const { fetchWebsiteMarkdownSnapshot } = await import("../sources/website-ingest.js");
175
+ const snapshot = await fetchWebsiteMarkdownSnapshot(args.source);
176
+ return { content: snapshot.content, preferredName: args.as ?? snapshot.preferredName };
177
+ })();
178
+ let stashDir;
179
+ if (args.target) {
180
+ // Resolve the named source to its filesystem path.
181
+ const cfg = loadConfig();
182
+ const sources = resolveConfiguredSources(cfg);
183
+ const match = sources.find((s) => s.name === args.target);
184
+ if (!match) {
185
+ throw new UsageError(`--target must reference a configured source name. No source named "${args.target}" found. Run \`akm list\` to see available sources.`, "INVALID_FLAG_VALUE");
186
+ }
187
+ const spec = match.source;
188
+ if (spec.type !== "filesystem" && spec.type !== "local") {
189
+ throw new ConfigError(`Source "${args.target}" is not a filesystem source and cannot be used as a wiki stash target.`, "INVALID_CONFIG_FILE", `Use a source with type "filesystem" or "local", or omit --target to use the default stash.`);
190
+ }
191
+ stashDir = spec.path;
192
+ }
193
+ else {
194
+ stashDir = resolveStashDir();
195
+ }
196
+ const result = stashRaw({
197
+ stashDir,
198
+ wikiName: args.name,
199
+ content,
200
+ preferredName: args.as ?? preferredName,
201
+ explicitSlug: args.as !== undefined,
202
+ });
203
+ output("wiki-stash", { ok: true, wiki: args.name, source: args.source, ...result });
204
+ },
205
+ });
206
+ const wikiLintCommand = defineCommand({
207
+ meta: {
208
+ name: "lint",
209
+ description: "Structural lint for a wiki: orphans, broken xrefs, missing descriptions, uncited raws, stale index",
210
+ },
211
+ args: {
212
+ name: { type: "positional", description: "Wiki name", required: true },
213
+ },
214
+ async run({ args }) {
215
+ let findingCount = 0;
216
+ await runWithJsonErrors(async () => {
217
+ const { lintWiki } = await import("../wiki/wiki.js");
218
+ const stashDir = resolveStashDir();
219
+ const report = lintWiki(stashDir, args.name);
220
+ output("wiki-lint", report);
221
+ findingCount = report.findings.length;
222
+ });
223
+ if (findingCount > 0)
224
+ process.exit(1); // EXIT_GENERAL
225
+ },
226
+ });
227
+ const wikiIngestCommand = defineJsonCommand({
228
+ meta: {
229
+ name: "ingest",
230
+ description: "Dispatch an agent to execute the ingest workflow for this wiki. Uses --profile or config.defaults.agent.",
231
+ },
232
+ args: {
233
+ name: { type: "positional", description: "Wiki name", required: true },
234
+ profile: {
235
+ type: "string",
236
+ description: "Agent profile to use (default: config.defaults.agent).",
237
+ },
238
+ model: {
239
+ type: "string",
240
+ description: "Model override — accepts aliases (opus, sonnet, haiku) or exact platform model IDs.",
241
+ },
242
+ "timeout-ms": { type: "string", description: "Override the agent CLI timeout in milliseconds." },
243
+ },
244
+ async run({ args }) {
245
+ const { buildIngestWorkflow } = await import("../wiki/wiki.js");
246
+ const stashDir = resolveStashDir();
247
+ const built = buildIngestWorkflow(stashDir, args.name);
248
+ const config = loadConfig();
249
+ const profileName = getStringArg(args, "profile") ?? config.defaults?.agent;
250
+ if (!profileName) {
251
+ throw new UsageError("akm wiki ingest requires an agent profile. Pass --profile <name> or set defaults.agent in config.", "MISSING_REQUIRED_ARGUMENT", "Available profiles are listed under profiles.agent in your config. Run `akm config get profiles.agent` to inspect.");
252
+ }
253
+ const timeoutMs = parsePositiveIntFlag(getHyphenatedArg(args, "timeout-ms"), "--timeout-ms");
254
+ const model = getStringArg(args, "model");
255
+ const { getDefaultLlmConfig } = await import("../core/config/config.js");
256
+ const dispatchResult = await akmAgentDispatch({
257
+ profileName,
258
+ agentConfig: config,
259
+ llmConfig: getDefaultLlmConfig(config),
260
+ prompt: built.workflow,
261
+ dispatch: {
262
+ prompt: built.workflow,
263
+ ...(model !== undefined ? { model } : {}),
264
+ },
265
+ ...(timeoutMs !== undefined && Number.isFinite(timeoutMs) ? { timeoutMs } : {}),
266
+ });
267
+ output("wiki-ingest", {
268
+ wiki: built.wiki,
269
+ path: built.path,
270
+ schemaPath: built.schemaPath,
271
+ dispatched: true,
272
+ profile: profileName,
273
+ agentResult: dispatchResult,
274
+ });
275
+ },
276
+ });
277
+ // Single source of truth: the routing set is derived from the subCommands keys
278
+ // (M10) so adding a subcommand can never silently desync from `hasSubcommand`.
279
+ const wikiSubCommands = {
280
+ create: wikiCreateCommand,
281
+ register: wikiRegisterCommand,
282
+ list: wikiListCommand,
283
+ show: wikiShowCommand,
284
+ remove: wikiRemoveCommand,
285
+ pages: wikiPagesCommand,
286
+ search: wikiSearchCommand,
287
+ stash: wikiStashCommand,
288
+ lint: wikiLintCommand,
289
+ ingest: wikiIngestCommand,
290
+ };
291
+ const WIKI_SUBCOMMAND_SET = new Set(Object.keys(wikiSubCommands));
292
+ export const wikiCommand = defineCommand({
293
+ meta: {
294
+ name: "wiki",
295
+ description: "Manage multiple markdown wikis (Karpathy-style). akm surfaces (lifecycle, raw/, lint, index); the agent writes pages.",
296
+ },
297
+ subCommands: wikiSubCommands,
298
+ run({ args }) {
299
+ return runWithJsonErrors(async () => {
300
+ if (hasSubcommand(args, WIKI_SUBCOMMAND_SET))
301
+ return;
302
+ // Default action: list wikis
303
+ const { listWikis } = await import("../wiki/wiki.js");
304
+ output("wiki-list", { wikis: listWikis(resolveStashDir()) });
305
+ });
306
+ },
307
+ });
@@ -0,0 +1,329 @@
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
+ * `akm workflow` command family. Extracted verbatim from src/cli.ts (WS6) so the
6
+ * God Module shrinks; the `main.subCommands.workflow` key and every subcommand's
7
+ * args/output shape are byte-identical. Handlers whose body is a plain
8
+ * `runWithJsonErrors(...) + output(...)` are migrated to `defineJsonCommand`,
9
+ * which emits the same JSON envelope (stdout/stderr/exit-code) as the inline
10
+ * form. `workflow template` keeps a plain `defineCommand` because it writes the
11
+ * template straight to stdout with no JSON envelope. The private helpers
12
+ * `looksLikeWorkflowRunId` and `resolveWorkflowFilePath` move with the family.
13
+ */
14
+ import { defineCommand } from "citty";
15
+ import { defineJsonCommand, output, runWithJsonErrors } from "../cli/shared.js";
16
+ import { assertFlatAssetName, combineCreatePath, normalizeCreateSubPath } from "../core/asset/asset-create.js";
17
+ import { parseAssetRef } from "../core/asset/asset-ref.js";
18
+ import { loadConfig } from "../core/config/config.js";
19
+ import { NotFoundError, UsageError } from "../core/errors.js";
20
+ import { akmIndex } from "../indexer/indexer.js";
21
+ import { resolveSourceEntries } from "../indexer/search/search-source.js";
22
+ import { hasBooleanFlag } from "../output/context.js";
23
+ import { resolveSourcesForOrigin } from "../registry/origin-resolve.js";
24
+ import { resolveAssetPath } from "../sources/resolve.js";
25
+ import { createWorkflowAsset, formatWorkflowErrors, getWorkflowTemplate, validateWorkflowSource, } from "../workflows/authoring/authoring.js";
26
+ import { hasWorkflowSubcommand, parseWorkflowJsonObject, parseWorkflowStepState, WORKFLOW_STEP_STATES, } from "../workflows/cli.js";
27
+ import { completeWorkflowStep, getNextWorkflowStep, getWorkflowStatus, listWorkflowRuns, resumeWorkflowRun, startWorkflowRun, } from "../workflows/runtime/runs.js";
28
+ const workflowStartCommand = defineJsonCommand({
29
+ meta: {
30
+ name: "start",
31
+ description: "Start a new workflow run in the current working scope",
32
+ },
33
+ args: {
34
+ ref: { type: "positional", description: "Workflow ref (workflow:<name>)", required: true },
35
+ params: { type: "string", description: "Workflow parameters as a JSON object" },
36
+ force: {
37
+ type: "boolean",
38
+ description: "Allow a parallel run when an active run already exists in this scope (#485)",
39
+ default: false,
40
+ },
41
+ },
42
+ async run({ args }) {
43
+ const result = await startWorkflowRun(args.ref, parseWorkflowJsonObject(args.params, "--params"), {
44
+ force: args.force === true,
45
+ });
46
+ output("workflow-start", result);
47
+ },
48
+ });
49
+ const workflowNextCommand = defineJsonCommand({
50
+ meta: {
51
+ name: "next",
52
+ description: "Show the next actionable workflow step in the current scope, auto-starting a run when passed a workflow ref",
53
+ },
54
+ args: {
55
+ target: { type: "positional", description: "Workflow run id or workflow ref", required: true },
56
+ params: { type: "string", description: "Workflow parameters as a JSON object (only for auto-started runs)" },
57
+ },
58
+ async run({ args }) {
59
+ // `--dry-run` is intentionally NOT a declared arg (so it stays out of
60
+ // --help). The guard reads it straight from process.argv so existing
61
+ // callers still get a clear, actionable error instead of a generic
62
+ // "unknown flag" from citty.
63
+ if (hasBooleanFlag(process.argv, "--dry-run")) {
64
+ throw new UsageError("`akm workflow next` does not support --dry-run. Remove the flag to start or resume a run.", "INVALID_FLAG_VALUE");
65
+ }
66
+ const parsedParams = args.params ? parseWorkflowJsonObject(args.params, "--params") : undefined;
67
+ // If the target looks like a UUID-style run id (no `:` and matches the
68
+ // run-id shape), short-circuit with a structured WORKFLOW_NOT_FOUND
69
+ // error before parseAssetRef gets to throw an unhelpful ref-parse error.
70
+ if (looksLikeWorkflowRunId(args.target)) {
71
+ const { hasWorkflowRun } = await import("../workflows/runtime/runs.js");
72
+ if (!(await hasWorkflowRun(args.target))) {
73
+ throw new NotFoundError(`Workflow run "${args.target}" not found.`, "WORKFLOW_NOT_FOUND", "Run `akm workflow list --active` to see runs.");
74
+ }
75
+ }
76
+ const result = await getNextWorkflowStep(args.target, parsedParams);
77
+ output("workflow-next", result);
78
+ },
79
+ });
80
+ /**
81
+ * Heuristic: a workflow run id is a UUID-shaped or hex-id-shaped string with
82
+ * no `:` separator (refs always contain a colon: `workflow:<name>` or
83
+ * `<origin>//workflow:<name>`). When this matches we can give a much better
84
+ * error than parseAssetRef's "Invalid asset type" failure.
85
+ */
86
+ function looksLikeWorkflowRunId(target) {
87
+ if (target.includes(":"))
88
+ return false;
89
+ if (target.includes("/"))
90
+ return false;
91
+ // UUID v4-ish: 8-4-4-4-12 hex digits separated by dashes.
92
+ if (/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(target))
93
+ return true;
94
+ // Bare hex/alphanumeric run ids of >=8 chars (covers shortened ids).
95
+ if (/^[0-9a-z][0-9a-z_-]{7,}$/i.test(target) && /[0-9]/.test(target))
96
+ return true;
97
+ return false;
98
+ }
99
+ const workflowCompleteCommand = defineJsonCommand({
100
+ meta: {
101
+ name: "complete",
102
+ description: "Update a workflow step state and persist notes/evidence",
103
+ },
104
+ args: {
105
+ runId: { type: "positional", description: "Workflow run id", required: true },
106
+ step: { type: "string", description: "Workflow step id", required: true },
107
+ state: {
108
+ type: "string",
109
+ description: `Step state (default: completed). One of: ${WORKFLOW_STEP_STATES.join(", ")}.`,
110
+ },
111
+ notes: { type: "string", description: "Notes for the completed step" },
112
+ summary: {
113
+ type: "string",
114
+ description: "Summary of work done (required when completing a step); validated against completion criteria",
115
+ },
116
+ evidence: { type: "string", description: "Evidence JSON object for the step" },
117
+ },
118
+ async run({ args }) {
119
+ const result = await completeWorkflowStep({
120
+ runId: args.runId,
121
+ stepId: args.step,
122
+ status: parseWorkflowStepState(args.state),
123
+ notes: args.notes,
124
+ summary: args.summary,
125
+ evidence: args.evidence ? parseWorkflowJsonObject(args.evidence, "--evidence") : undefined,
126
+ });
127
+ if ("ok" in result && result.ok === false) {
128
+ // Summary failed the completion-criteria validation gate (#506): the
129
+ // step stays pending and the agent receives corrective feedback.
130
+ output("workflow-complete-rejected", result);
131
+ return;
132
+ }
133
+ output("workflow-complete", result);
134
+ },
135
+ });
136
+ const workflowStatusCommand = defineJsonCommand({
137
+ meta: {
138
+ name: "status",
139
+ description: "Show full workflow run state for review or resume; workflow refs resolve within the current scope",
140
+ },
141
+ args: {
142
+ target: { type: "positional", description: "Workflow run id or workflow ref (workflow:<name>)", required: true },
143
+ },
144
+ async run({ args }) {
145
+ const target = args.target;
146
+ // Check if target looks like a workflow ref
147
+ const parsed = (() => {
148
+ try {
149
+ return parseAssetRef(target);
150
+ }
151
+ catch {
152
+ return null;
153
+ }
154
+ })();
155
+ if (parsed?.type === "workflow") {
156
+ const ref = `${parsed.origin ? `${parsed.origin}//` : ""}workflow:${parsed.name}`;
157
+ const { runs } = await listWorkflowRuns({ workflowRef: ref });
158
+ if (runs.length === 0) {
159
+ throw new NotFoundError(`No workflow runs found for ${ref}`, "WORKFLOW_NOT_FOUND");
160
+ }
161
+ const mostRecent = runs[0];
162
+ if (!mostRecent)
163
+ throw new NotFoundError(`No workflow runs found for ${ref}`, "WORKFLOW_NOT_FOUND");
164
+ const result = await getWorkflowStatus(mostRecent.id);
165
+ output("workflow-status", result);
166
+ }
167
+ else {
168
+ const result = await getWorkflowStatus(target);
169
+ output("workflow-status", result);
170
+ }
171
+ },
172
+ });
173
+ const workflowListCommand = defineJsonCommand({
174
+ meta: {
175
+ name: "list",
176
+ description: "List workflow runs in the current working scope",
177
+ },
178
+ args: {
179
+ ref: { type: "string", description: "Filter to one workflow ref" },
180
+ active: { type: "boolean", description: "Only show active runs", default: false },
181
+ },
182
+ async run({ args }) {
183
+ const result = await listWorkflowRuns({ workflowRef: args.ref, activeOnly: args.active });
184
+ output("workflow-list", result);
185
+ },
186
+ });
187
+ const workflowCreateCommand = defineJsonCommand({
188
+ meta: {
189
+ name: "create",
190
+ description: "Create a workflow markdown document in the working stash",
191
+ },
192
+ args: {
193
+ name: {
194
+ type: "positional",
195
+ description: "Workflow name (flat, no '/'; use --path for a subdirectory)",
196
+ required: true,
197
+ },
198
+ path: {
199
+ type: "string",
200
+ description: "Relative subdirectory under workflows/ to place the workflow in (e.g. 'release'). The filename comes from the name.",
201
+ },
202
+ from: { type: "string", description: "Import and validate markdown from an existing file" },
203
+ force: {
204
+ type: "boolean",
205
+ description: "Overwrite an existing workflow (requires --from or --reset)",
206
+ default: false,
207
+ },
208
+ reset: {
209
+ type: "boolean",
210
+ description: "Explicitly replace an existing workflow with a fresh template (use with --force)",
211
+ default: false,
212
+ },
213
+ },
214
+ async run({ args }) {
215
+ // `name` is flat; subdirectory placement is `--path`'s job.
216
+ assertFlatAssetName(args.name);
217
+ const effectiveName = combineCreatePath(normalizeCreateSubPath(args.path), args.name);
218
+ const namePattern = /^[a-z0-9][a-z0-9._/-]*$/;
219
+ if (!namePattern.test(effectiveName)) {
220
+ throw new UsageError("Workflow name must start with a lowercase letter or digit and contain only lowercase letters, digits, hyphens, dots, underscores, and slashes.");
221
+ }
222
+ if (args.force && !args.from && !args.reset) {
223
+ throw new UsageError("Refusing to overwrite with template: pass --from <file> to replace content, or --reset to explicitly replace with a fresh template.");
224
+ }
225
+ const result = createWorkflowAsset({
226
+ name: effectiveName,
227
+ from: args.from,
228
+ force: args.force,
229
+ });
230
+ // Index the newly-written workflow so `akm workflow start` can resolve
231
+ // a workflowEntryId without requiring an explicit `akm index` call
232
+ // first. Uses the same incremental index path that `akm add` uses.
233
+ await akmIndex({ stashDir: result.stashDir });
234
+ output("workflow-create", { ok: true, ...result });
235
+ },
236
+ });
237
+ const workflowTemplateCommand = defineCommand({
238
+ meta: {
239
+ name: "template",
240
+ description: "Print a valid workflow markdown template",
241
+ },
242
+ run() {
243
+ process.stdout.write(getWorkflowTemplate());
244
+ },
245
+ });
246
+ const workflowValidateCommand = defineJsonCommand({
247
+ meta: {
248
+ name: "validate",
249
+ description: "Validate a workflow markdown file or ref and print any errors",
250
+ },
251
+ args: {
252
+ target: {
253
+ type: "positional",
254
+ description: "Workflow ref (workflow:<name>) or filesystem path to a workflow .md",
255
+ required: true,
256
+ },
257
+ },
258
+ async run({ args }) {
259
+ const filePath = await resolveWorkflowFilePath(args.target);
260
+ const { parse } = validateWorkflowSource(filePath);
261
+ if (parse.ok) {
262
+ output("workflow-validate", {
263
+ ok: true,
264
+ path: filePath,
265
+ title: parse.document.title,
266
+ stepCount: parse.document.steps.length,
267
+ });
268
+ return;
269
+ }
270
+ throw new UsageError(formatWorkflowErrors(filePath, parse.errors));
271
+ },
272
+ });
273
+ async function resolveWorkflowFilePath(target) {
274
+ if (!target.startsWith("workflow:"))
275
+ return target;
276
+ const parsed = parseAssetRef(target);
277
+ if (parsed.type !== "workflow") {
278
+ throw new UsageError(`Expected a workflow ref (workflow:<name>), got "${target}".`);
279
+ }
280
+ const config = loadConfig();
281
+ const allSources = resolveSourceEntries(undefined, config);
282
+ const searchSources = resolveSourcesForOrigin(parsed.origin, allSources);
283
+ for (const source of searchSources) {
284
+ try {
285
+ return await resolveAssetPath(source.path, "workflow", parsed.name);
286
+ }
287
+ catch {
288
+ /* try next source */
289
+ }
290
+ }
291
+ throw new UsageError(`Workflow not found for ref: workflow:${parsed.name}`);
292
+ }
293
+ const workflowResumeCommand = defineJsonCommand({
294
+ meta: {
295
+ name: "resume",
296
+ description: "Resume a blocked or failed workflow run, flipping it back to active",
297
+ },
298
+ args: {
299
+ runId: { type: "positional", description: "Workflow run id", required: true },
300
+ },
301
+ async run({ args }) {
302
+ const result = await resumeWorkflowRun(args.runId);
303
+ output("workflow-resume", result);
304
+ },
305
+ });
306
+ export const workflowCommand = defineCommand({
307
+ meta: {
308
+ name: "workflow",
309
+ description: "Author, inspect, and execute step-by-step workflow assets",
310
+ },
311
+ subCommands: {
312
+ start: workflowStartCommand,
313
+ next: workflowNextCommand,
314
+ complete: workflowCompleteCommand,
315
+ status: workflowStatusCommand,
316
+ list: workflowListCommand,
317
+ create: workflowCreateCommand,
318
+ template: workflowTemplateCommand,
319
+ resume: workflowResumeCommand,
320
+ validate: workflowValidateCommand,
321
+ },
322
+ run({ args }) {
323
+ return runWithJsonErrors(async () => {
324
+ if (hasWorkflowSubcommand(args))
325
+ return;
326
+ output("workflow-list", await listWorkflowRuns({ activeOnly: true }));
327
+ });
328
+ },
329
+ });
@@ -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 { defaultRendererRegistry } from "./asset-registry";
4
+ import { defaultRendererRegistry } from "./asset/asset-registry.js";
5
5
  function registryActionContributor(registry) {
6
6
  return {
7
7
  name: "registry-action-contributor",