akm-cli 0.9.1 → 0.9.2-alpha.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (350) hide show
  1. package/CHANGELOG.md +103 -28
  2. package/README.md +3 -1
  3. package/SECURITY.md +1 -1
  4. package/STABILITY.md +1 -1
  5. package/dist/akm +2 -2
  6. package/dist/akm-migrate +2 -2
  7. package/dist/assets/hints/cli-hints-full.md +14 -9
  8. package/dist/assets/improve-strategies/proactive-maintenance.json +1 -1
  9. package/dist/assets/improve-strategies/reflect-distill.json +1 -1
  10. package/dist/assets/models.json +35 -0
  11. package/dist/assets/stash-skeleton/facts/conventions/backlinks.md +3 -4
  12. package/dist/assets/stash-skeleton/facts/conventions/organization.md +1 -3
  13. package/dist/assets/tasks/core/extract.yml +6 -5
  14. package/dist/assets/tasks/core/improve.yml +6 -5
  15. package/dist/assets/tasks/core/index-refresh.yml +6 -5
  16. package/dist/assets/tasks/core/sync.yml +6 -5
  17. package/dist/assets/tasks/core/version-check.yml +6 -5
  18. package/dist/assets/tasks/improve/akm-graph-refresh-weekly.yml +6 -5
  19. package/dist/assets/tasks/improve/akm-improve-catchup.yml +6 -5
  20. package/dist/assets/tasks/improve/akm-improve-consolidate.yml +6 -5
  21. package/dist/assets/tasks/improve/akm-improve-frequent.yml +6 -5
  22. package/dist/assets/tasks/improve/akm-improve-nightly.yml +6 -5
  23. package/dist/cli/confirm.js +2 -2
  24. package/dist/cli/parse-args.js +3 -24
  25. package/dist/cli/retired-commands.js +1 -1
  26. package/dist/cli/shared.js +2 -2
  27. package/dist/cli.js +11 -9
  28. package/dist/commands/agent/agent-dispatch.js +55 -89
  29. package/dist/commands/agent/contribute-cli.js +12 -45
  30. package/dist/commands/command/builtin-action.js +32 -0
  31. package/dist/commands/command/command-cli.js +99 -0
  32. package/dist/commands/command/command-execution.js +308 -0
  33. package/dist/commands/command/execution-source-loader.js +176 -0
  34. package/dist/commands/command/portable-template.js +60 -0
  35. package/dist/commands/config-cli.js +10 -4
  36. package/dist/commands/env/env.js +4 -2
  37. package/dist/commands/feedback-cli.js +1 -1
  38. package/dist/commands/health/checks.js +241 -29
  39. package/dist/commands/health/html-report.js +0 -14
  40. package/dist/commands/health/report-view-model.js +0 -1
  41. package/dist/commands/health/surfaces.js +6 -7
  42. package/dist/commands/health/types.js +0 -2
  43. package/dist/commands/health.js +63 -18
  44. package/dist/commands/improve/collapse-detector.js +5 -6
  45. package/dist/commands/improve/consolidate.js +251 -214
  46. package/dist/commands/improve/distill/promote-memory.js +71 -34
  47. package/dist/commands/improve/distill/quality-gate.js +17 -5
  48. package/dist/commands/improve/distill.js +232 -155
  49. package/dist/commands/improve/eligibility.js +112 -79
  50. package/dist/commands/improve/execution.js +57 -0
  51. package/dist/commands/improve/extract-cli.js +5 -5
  52. package/dist/commands/improve/extract-prompt.js +64 -22
  53. package/dist/commands/improve/extract.js +608 -360
  54. package/dist/commands/improve/improve-strategies.js +43 -14
  55. package/dist/commands/improve/improve.js +249 -29
  56. package/dist/commands/improve/loop-stages.js +11 -17
  57. package/dist/commands/improve/memory/memory-contradiction-detect.js +90 -66
  58. package/dist/commands/improve/outcome-loop.js +22 -38
  59. package/dist/commands/improve/planner.js +134 -0
  60. package/dist/commands/improve/preparation.js +730 -409
  61. package/dist/commands/improve/reflect.js +386 -223
  62. package/dist/commands/improve/run-context.js +3 -4
  63. package/dist/commands/improve/salience.js +6 -58
  64. package/dist/commands/improve/session-asset.js +12 -12
  65. package/dist/commands/lint/index.js +101 -29
  66. package/dist/commands/migrate-cli.js +11 -69
  67. package/dist/commands/migration-tool.js +6 -9
  68. package/dist/commands/models-cli.js +27 -0
  69. package/dist/commands/proposal/drain.js +258 -186
  70. package/dist/commands/proposal/proposal-cli.js +32 -10
  71. package/dist/commands/proposal/proposal.js +2 -5
  72. package/dist/commands/proposal/propose.js +192 -172
  73. package/dist/commands/proposal/repository.js +54 -91
  74. package/dist/commands/proposal/validators/proposal-validators.js +9 -7
  75. package/dist/commands/read/curate.js +53 -22
  76. package/dist/commands/read/registry-search.js +25 -9
  77. package/dist/commands/read/remember-cli.js +14 -2
  78. package/dist/commands/read/search.js +10 -4
  79. package/dist/commands/read/show.js +139 -153
  80. package/dist/commands/registry-cli.js +16 -7
  81. package/dist/commands/remember.js +33 -18
  82. package/dist/commands/sources/add-cli.js +19 -178
  83. package/dist/commands/sources/bundle-cli.js +15 -3
  84. package/dist/commands/sources/dangerous-env-audit.js +135 -0
  85. package/dist/commands/sources/info.js +2 -1
  86. package/dist/commands/sources/installed-stashes.js +901 -177
  87. package/dist/commands/sources/schema-repair.js +174 -95
  88. package/dist/commands/sources/self-update.js +30 -74
  89. package/dist/commands/sources/source-add.js +3 -5
  90. package/dist/commands/sources/sources-cli.js +2 -15
  91. package/dist/commands/sources/update-transaction.js +220 -0
  92. package/dist/commands/tasks/tasks-cli.js +3 -3
  93. package/dist/commands/tasks/tasks.js +736 -317
  94. package/dist/commands/workflow-cli.js +2 -2
  95. package/dist/core/adapter/adapters/agent-skills-adapter.js +3 -0
  96. package/dist/core/adapter/adapters/akm-adapter.js +85 -35
  97. package/dist/core/adapter/adapters/akm-lint.js +54 -39
  98. package/dist/core/adapter/adapters/akm-metadata.js +45 -45
  99. package/dist/core/adapter/adapters/akm-task-adapter.js +32 -49
  100. package/dist/core/adapter/adapters/akm-workflow-adapter.js +38 -23
  101. package/dist/core/adapter/adapters/dotenv-adapter.js +30 -1
  102. package/dist/core/adapter/adapters/generic-files-adapter.js +11 -0
  103. package/dist/core/adapter/adapters/index.js +0 -9
  104. package/dist/core/adapter/adapters/llm-wiki-adapter.js +4 -0
  105. package/dist/core/adapter/adapters/okf-adapter.js +4 -0
  106. package/dist/core/adapter/adapters/opencode-adapter.js +5 -8
  107. package/dist/core/adapter/adapters/tool-dir-shared.js +63 -6
  108. package/dist/core/adapter/adapters/website-snapshot-adapter.js +4 -0
  109. package/dist/core/adapter/execution-source.js +308 -0
  110. package/dist/core/adapter/recognize-match.js +36 -13
  111. package/dist/core/adapter/registry.js +0 -9
  112. package/dist/core/asset/stash-meta.js +94 -4
  113. package/dist/core/common.js +6 -11
  114. package/dist/core/config/config-io.js +3 -3
  115. package/dist/core/config/config-schema.js +18 -40
  116. package/dist/core/config/config-sources.js +11 -21
  117. package/dist/core/config/config-walker.js +31 -13
  118. package/dist/core/config/config.js +23 -26
  119. package/dist/core/config/schema/engines.js +8 -7
  120. package/dist/core/config/schema/improve-processes.js +29 -5
  121. package/dist/core/config/schema/index-config.js +0 -27
  122. package/dist/core/config/schema/primitives.js +1 -23
  123. package/dist/core/config/schema/sources-bundles.js +13 -16
  124. package/dist/core/errors.js +2 -0
  125. package/dist/core/events.js +68 -32
  126. package/dist/core/extra-params.js +1 -0
  127. package/dist/core/improve-result.js +315 -0
  128. package/dist/core/lesson-lint.js +0 -6
  129. package/dist/core/maintenance-barrier.js +4 -4
  130. package/dist/core/network-policy.js +152 -0
  131. package/dist/core/paths.js +1 -1
  132. package/dist/core/recognition-util.js +4 -4
  133. package/dist/core/registry-url.js +456 -0
  134. package/dist/core/state/migrations.js +161 -47
  135. package/dist/core/state-db.js +453 -80
  136. package/dist/core/system-error.js +32 -0
  137. package/dist/core/time.js +2 -12
  138. package/dist/core/write-source.js +0 -18
  139. package/dist/execution/directory-identity.js +52 -0
  140. package/dist/execution/executable-identity.js +107 -0
  141. package/dist/execution/guarded-source.js +398 -0
  142. package/dist/execution/json.js +95 -0
  143. package/dist/{commands/health/types-session-log.js → execution/limits.js} +2 -1
  144. package/dist/execution/record.js +55 -0
  145. package/dist/execution/resolved-request.js +730 -0
  146. package/dist/execution/source.js +320 -0
  147. package/dist/indexer/bundle-identity-guard.js +5 -4
  148. package/dist/indexer/db/graph-db.js +33 -0
  149. package/dist/indexer/graph/graph-boost.js +3 -4
  150. package/dist/indexer/graph/graph-extraction.js +562 -373
  151. package/dist/indexer/index-written-assets.js +78 -39
  152. package/dist/indexer/indexer.js +471 -432
  153. package/dist/indexer/installations.js +6 -0
  154. package/dist/indexer/lookup/adapter-concept-owner.js +283 -0
  155. package/dist/indexer/materialize-embeddings.js +155 -0
  156. package/dist/indexer/passes/memory-inference.js +227 -174
  157. package/dist/indexer/passes/metadata.js +263 -118
  158. package/dist/indexer/scan/doc-to-entry.js +7 -10
  159. package/dist/indexer/scan/drain-dir.js +51 -23
  160. package/dist/indexer/search/db-search.js +156 -50
  161. package/dist/indexer/search/fts-query.js +40 -40
  162. package/dist/indexer/search/ranking.js +36 -1
  163. package/dist/indexer/search/search-attribution.js +3 -1
  164. package/dist/indexer/search/search-fields.js +23 -14
  165. package/dist/indexer/search/search-hit-enrichers.js +1 -1
  166. package/dist/indexer/search/search-source.js +7 -16
  167. package/dist/indexer/search/semantic-status.js +10 -1
  168. package/dist/indexer/usage/show-usage.js +105 -0
  169. package/dist/indexer/usage/usage-events.js +7 -2
  170. package/dist/indexer/walk/matchers.js +40 -10
  171. package/dist/indexer/walk/path-resolver.js +5 -2
  172. package/dist/indexer/walk/walker.js +20 -2
  173. package/dist/integrations/agent/builder-shared.js +3 -6
  174. package/dist/integrations/agent/conversation-fallback.js +16 -0
  175. package/dist/integrations/agent/engine-resolution.js +87 -87
  176. package/dist/integrations/agent/execution-cascade.js +566 -0
  177. package/dist/integrations/agent/execution-definitions.js +211 -0
  178. package/dist/integrations/agent/execution-lowering.js +811 -0
  179. package/dist/integrations/agent/execution-preparation.js +67 -0
  180. package/dist/integrations/agent/index.js +0 -2
  181. package/dist/integrations/agent/inline-execution.js +74 -0
  182. package/dist/integrations/agent/model-map.js +515 -0
  183. package/dist/integrations/agent/persona-fallback.js +30 -0
  184. package/dist/integrations/agent/request-lowering.js +186 -0
  185. package/dist/integrations/agent/runner-dispatch.js +230 -37
  186. package/dist/integrations/agent/runner.js +12 -83
  187. package/dist/integrations/harnesses/aider/agent-builder.js +8 -0
  188. package/dist/integrations/harnesses/aider/index.js +0 -1
  189. package/dist/integrations/harnesses/amazonq/agent-builder.js +8 -0
  190. package/dist/integrations/harnesses/amazonq/index.js +0 -1
  191. package/dist/integrations/harnesses/claude/agent-builder.js +14 -1
  192. package/dist/integrations/harnesses/claude/index.js +1 -5
  193. package/dist/integrations/harnesses/claude/session-log.js +3 -33
  194. package/dist/integrations/harnesses/codex/agent-builder.js +8 -0
  195. package/dist/integrations/harnesses/codex/index.js +0 -1
  196. package/dist/integrations/harnesses/copilot/agent-builder.js +8 -0
  197. package/dist/integrations/harnesses/copilot/index.js +0 -1
  198. package/dist/integrations/harnesses/gemini/agent-builder.js +8 -0
  199. package/dist/integrations/harnesses/gemini/index.js +0 -1
  200. package/dist/integrations/harnesses/index.js +4 -44
  201. package/dist/integrations/harnesses/opencode/agent-builder.js +16 -9
  202. package/dist/integrations/harnesses/opencode/index.js +0 -2
  203. package/dist/integrations/harnesses/opencode/session-log.js +14 -204
  204. package/dist/integrations/harnesses/opencode-sdk/harness.js +12 -1
  205. package/dist/integrations/harnesses/opencode-sdk/sdk-runner.js +40 -42
  206. package/dist/integrations/harnesses/openhands/agent-builder.js +8 -0
  207. package/dist/integrations/harnesses/openhands/index.js +0 -1
  208. package/dist/integrations/harnesses/pi/agent-builder.js +8 -0
  209. package/dist/integrations/harnesses/pi/index.js +0 -1
  210. package/dist/integrations/harnesses/shared.js +0 -1
  211. package/dist/integrations/harnesses/types.js +1 -3
  212. package/dist/integrations/lockfile.js +82 -79
  213. package/dist/integrations/session-logs/index.js +6 -17
  214. package/dist/integrations/session-logs/provider-base.js +1 -29
  215. package/dist/llm/client.js +10 -5
  216. package/dist/llm/embedder.js +6 -7
  217. package/dist/llm/embedders/local.js +37 -88
  218. package/dist/llm/embedders/types.js +1 -1
  219. package/dist/llm/graph-extract.js +75 -50
  220. package/dist/llm/index-passes.js +43 -5
  221. package/dist/llm/memory-infer.js +8 -6
  222. package/dist/llm/metadata-enhance.js +5 -3
  223. package/dist/llm/structured-call.js +122 -25
  224. package/dist/output/format-exempt.js +1 -1
  225. package/dist/output/render-registry.js +0 -16
  226. package/dist/output/renderers.js +12 -7
  227. package/dist/output/shapes/curate.js +1 -0
  228. package/dist/output/shapes/helpers.js +10 -2
  229. package/dist/output/shapes/passthrough.js +2 -0
  230. package/dist/output/text/command-format.js +31 -33
  231. package/dist/output/text/health-format.js +1 -29
  232. package/dist/output/text/migrate.js +6 -56
  233. package/dist/output/text/proposal-format.js +16 -1
  234. package/dist/output/text/workflow-format.js +16 -0
  235. package/dist/registry/network.js +279 -0
  236. package/dist/registry/pinned-request-helper.js +247 -0
  237. package/dist/registry/pinned-transport.js +717 -0
  238. package/dist/registry/providers/skills-sh.js +18 -6
  239. package/dist/registry/providers/static-index.js +20 -7
  240. package/dist/registry/resolve.js +53 -28
  241. package/dist/scripts/akm-migrate-node.js +19334 -52269
  242. package/dist/scripts/akm-migrate.js +19270 -51612
  243. package/dist/setup/registry-stash-loader.js +64 -20
  244. package/dist/setup/semantic-assets.js +9 -34
  245. package/dist/setup/setup.js +12 -30
  246. package/dist/setup/source-identity.js +17 -0
  247. package/dist/setup/steps/sources.js +36 -15
  248. package/dist/setup/steps/tasks.js +39 -11
  249. package/dist/sources/providers/git-provider.js +3 -3
  250. package/dist/sources/providers/npm.js +2 -2
  251. package/dist/sources/providers/provider-utils.js +4 -3
  252. package/dist/sources/providers/website.js +11 -7
  253. package/dist/sources/snapshot-fetchers/host-guard.js +9 -136
  254. package/dist/sources/snapshot-fetchers/website-ingest.js +25 -109
  255. package/dist/sources/website-url.js +73 -0
  256. package/dist/storage/engines/sqlite-migrations.js +81 -26
  257. package/dist/storage/managed-db.js +27 -24
  258. package/dist/storage/repositories/events-repository.js +3 -0
  259. package/dist/storage/repositories/index-connection.js +42 -10
  260. package/dist/storage/repositories/index-entries-repository.js +203 -229
  261. package/dist/storage/repositories/index-entry-mapper.js +8 -12
  262. package/dist/storage/repositories/index-entry-schema.js +255 -0
  263. package/dist/storage/repositories/index-fts-repository.js +64 -71
  264. package/dist/storage/repositories/index-llm-cache-repository.js +8 -13
  265. package/dist/storage/repositories/index-meta-repository.js +0 -11
  266. package/dist/storage/repositories/index-schema.js +74 -350
  267. package/dist/storage/repositories/index-utility-repository.js +12 -17
  268. package/dist/storage/repositories/index-vec-repository.js +56 -7
  269. package/dist/storage/repositories/proposals-repository.js +4 -127
  270. package/dist/storage/repositories/registry-cache.js +2 -1
  271. package/dist/storage/repositories/task-history-repository.js +20 -40
  272. package/dist/storage/repositories/workflow-runs-repository.js +228 -129
  273. package/dist/storage/sqlite-read-snapshot.js +148 -0
  274. package/dist/tasks/backends/cron.js +170 -42
  275. package/dist/tasks/backends/index.js +1 -1
  276. package/dist/tasks/backends/launchd.js +787 -202
  277. package/dist/tasks/backends/schtasks.js +282 -83
  278. package/dist/tasks/embedded.js +7 -7
  279. package/dist/tasks/frozen-script.js +50 -0
  280. package/dist/tasks/resolve-akm-bin.js +5 -1
  281. package/dist/tasks/runner.js +239 -251
  282. package/dist/tasks/runtime-v3.js +281 -0
  283. package/dist/tasks/scheduler-binding.js +272 -0
  284. package/dist/tasks/scheduler-invocation.js +57 -43
  285. package/dist/tasks/scheduler-sync.js +654 -0
  286. package/dist/tasks/source-v3.js +752 -0
  287. package/dist/tasks/standalone-script-entry.js +5 -0
  288. package/dist/tasks/task-id.js +29 -0
  289. package/dist/workflows/authoring/authoring.js +15 -32
  290. package/dist/workflows/exec/dispatch-redaction.js +14 -8
  291. package/dist/workflows/exec/exec-unit.js +7 -28
  292. package/dist/workflows/exec/frozen-judge.js +57 -89
  293. package/dist/workflows/exec/lowering-notices.js +23 -0
  294. package/dist/workflows/exec/native-executor.js +301 -458
  295. package/dist/workflows/exec/param-secrets.js +4 -3
  296. package/dist/workflows/exec/run-workflow.js +26 -32
  297. package/dist/workflows/exec/step-work.js +105 -109
  298. package/dist/workflows/exec/unit-dispatch.js +103 -27
  299. package/dist/workflows/exec/unit-writer.js +3 -3
  300. package/dist/workflows/exec/worktree.js +2 -2
  301. package/dist/workflows/ir/compile.js +86 -72
  302. package/dist/workflows/ir/environment-v4.js +328 -0
  303. package/dist/workflows/ir/freeze-v4.js +122 -0
  304. package/dist/workflows/ir/plan-hash.js +13 -7
  305. package/dist/workflows/ir/schema-v4.js +525 -0
  306. package/dist/workflows/ir/schema.js +25 -284
  307. package/dist/workflows/ir/source-freeze-v4.js +506 -0
  308. package/dist/workflows/parser.js +27 -24
  309. package/dist/workflows/program/schema.js +1 -2
  310. package/dist/workflows/renderer.js +42 -29
  311. package/dist/workflows/resource-limits.js +4 -5
  312. package/dist/workflows/runtime/agent-identity.js +11 -13
  313. package/dist/workflows/runtime/plan-classifier.js +8 -8
  314. package/dist/workflows/runtime/runs.js +27 -43
  315. package/dist/workflows/runtime/workflow-asset-loader.js +45 -205
  316. package/dist/workflows/source-files.js +373 -0
  317. package/dist/workflows/source-ir/compile.js +196 -0
  318. package/dist/workflows/source-ir/github-yaml.js +577 -0
  319. package/dist/workflows/source-ir/ordering.js +38 -0
  320. package/dist/workflows/source-ir/program.js +50 -0
  321. package/dist/workflows/source-ir/result.js +26 -0
  322. package/dist/workflows/source-ir/schema.js +772 -0
  323. package/dist/workflows/source-ir/semantics.js +242 -0
  324. package/dist/workflows/source-ir/uses.js +14 -0
  325. package/docs/README.md +2 -0
  326. package/docs/migration/README.md +3 -1
  327. package/docs/migration/release-notes/0.9.2.md +55 -0
  328. package/docs/migration/release-notes/README.md +5 -0
  329. package/docs/migration/v0.8-to-v0.9.md +76 -1077
  330. package/docs/migration/v0.9.0-troubleshooting.md +104 -516
  331. package/docs/migration/v0.9.1-to-v0.9.2.md +150 -0
  332. package/docs/reference/README.md +1 -0
  333. package/docs/reference/cli.md +230 -98
  334. package/docs/reference/configuration.md +159 -36
  335. package/docs/reference/data-and-telemetry.md +19 -1
  336. package/docs/reference/supported-formats.md +23 -3
  337. package/docs/reference/tasks.md +182 -0
  338. package/docs/reference/workflow-schema.md +91 -40
  339. package/docs/reference/workflows.md +33 -6
  340. package/package.json +10 -6
  341. package/schemas/akm-config.json +372 -224
  342. package/schemas/akm-task.json +324 -80
  343. package/schemas/akm-workflow.json +6 -9
  344. package/dist/core/migration-operation.js +0 -75
  345. package/dist/integrations/agent/model-aliases.js +0 -74
  346. package/dist/tasks/parser.js +0 -380
  347. package/dist/tasks/schema.js +0 -123
  348. package/dist/tasks/validator.js +0 -80
  349. package/dist/workflows/ir/freeze.js +0 -320
  350. package/dist/workflows/runtime/document-cache.js +0 -13
@@ -15,7 +15,7 @@ import { resolveStashDir } from "../../core/common.js";
15
15
  import { loadConfig } from "../../core/config/config.js";
16
16
  import { resolveWriteTarget } from "../../core/write-source.js";
17
17
  import { withAssetMutationLease } from "../../indexer/index-writer-lock.js";
18
- import { createProposal, diffProposal, isProposalSkipped, listProposals, preflightProposalPromotion, promoteProposal, proposalContent, recoverProposalTransactionsForStash, rejectProposalDurably, resolveProposalId, resolveProposalIdForReject, revertProposal, } from "./repository.js";
18
+ import { createProposal, diffProposal, isProposalSkipped, listProposals, preflightProposalPromotion, promoteProposal, proposalContent, recoverProposalTransactionsForStash, rejectProposalDurably, resolveProposalId, revertProposal, } from "./repository.js";
19
19
  import { validateProposal } from "./validators/proposals.js";
20
20
  // ── Shared helpers ──────────────────────────────────────────────────────────
21
21
  function resolveStash(stashDir) {
@@ -103,10 +103,7 @@ export async function akmProposalReject(options) {
103
103
  return withAssetMutationLease("proposal-reject", async () => {
104
104
  const config = options.config ?? loadConfig();
105
105
  const { stashDir: stash } = resolveProposalQueue(options.stashDir, options.queue, config);
106
- // resolveProposalIdForReject tolerates a legacy row whose metadata fails
107
- // strict decoding — resolveProposalId's exact-UUID match would otherwise
108
- // throw here, before the terminal-status machinery even runs.
109
- const proposalId = resolveProposalIdForReject(stash, options.id, options.ctx);
106
+ const proposalId = resolveProposalId(stash, options.id, options.ctx).id;
110
107
  await recoverProposalTransactionsForStash(stash, config, options.ctx, proposalId);
111
108
  const updated = rejectProposalDurably(stash, proposalId, options.reason, options.ctx, options.gateDecision);
112
109
  return {
@@ -16,27 +16,81 @@ import fs from "node:fs";
16
16
  import { placementTypes, stashDirFor } from "../../core/asset/asset-placement.js";
17
17
  import { parseRefInput } from "../../core/asset/resolve-ref.js";
18
18
  import { resolveStashDir } from "../../core/common.js";
19
- import { ConfigError, UsageError } from "../../core/errors.js";
19
+ import { UsageError } from "../../core/errors.js";
20
20
  import { appendEvent } from "../../core/events.js";
21
- import { redactSensitiveText } from "../../core/redaction.js";
22
21
  import { resolveStandardsContext } from "../../core/standards/resolve-standards-context.js";
23
22
  import { warn } from "../../core/warn.js";
24
23
  import { deriveEntryProvenance } from "../../indexer/installations.js";
25
- import { fallbackAnnouncement, NO_ENGINE_MESSAGE_SUFFIX, NO_ENGINE_REMEDY, withEngineFallback, } from "../../integrations/agent/engine-fallback.js";
26
- import { resolveEngine } from "../../integrations/agent/engine-resolution.js";
24
+ import { fallbackAnnouncement } from "../../integrations/agent/engine-fallback.js";
25
+ import { acquireLoweredExecutionDispatchLease, dispatchLoweredExecutionRequest, disposeLoweredExecutionDispatchLease, lowerResolvedExecutionRequest, redactWithLoweredExecutionDispatchLease, } from "../../integrations/agent/execution-lowering.js";
26
+ import { prepareInlineExecution } from "../../integrations/agent/inline-execution.js";
27
27
  import { buildProposePrompt, parseAgentProposalPayload } from "../../integrations/agent/prompts.js";
28
- import { collectDispatchSensitiveValues, executeRunner } from "../../integrations/agent/runner-dispatch.js";
29
28
  import { baseFailureFields, enoentHintMessage, isEnoentFailure } from "../agent/agent-support.js";
30
29
  import { createProposal, isProposalSkipped, resolveProposalQueueTarget, } from "./repository.js";
31
- function failureEnvelope(result, type, name, engine, fallbackReason = "non_zero_exit") {
30
+ function failureEnvelope(result, type, name, engine, notices, fallbackReason = "non_zero_exit") {
32
31
  return {
33
32
  ...baseFailureFields(result, fallbackReason),
34
33
  schemaVersion: 2,
35
34
  type,
36
35
  name,
37
36
  engine,
37
+ ...(notices.length > 0 ? { notices } : {}),
38
38
  };
39
39
  }
40
+ function noticeFields(notices) {
41
+ return notices.length > 0 ? { notices } : {};
42
+ }
43
+ /** Materialize required credentials through the real runner boundary, without provider I/O. */
44
+ async function preflightProposalDispatch(lowered, runOptions) {
45
+ return acquireLoweredExecutionDispatchLease(lowered, {
46
+ ...(runOptions.envSource ? { envSource: runOptions.envSource } : {}),
47
+ });
48
+ }
49
+ /** Resolve, lower, and dispatch the already-rendered proposal prompt. */
50
+ async function dispatchProposalPrompt(prompt, config, options, onDispatchReady) {
51
+ const current = {
52
+ ...(options.engine !== undefined ? { engine: options.engine } : {}),
53
+ ...(options.timeoutMs !== undefined ? { timeout: options.timeoutMs } : {}),
54
+ };
55
+ const prepared = prepareInlineExecution({
56
+ content: prompt,
57
+ config,
58
+ invocationKind: "direct",
59
+ ...(Object.keys(current).length > 0 ? { current } : {}),
60
+ });
61
+ const engineName = prepared.request.engine.name;
62
+ const announcement = fallbackAnnouncement(prepared.fallbackEngineName, engineName);
63
+ if (announcement)
64
+ warn(announcement);
65
+ const lowered = lowerResolvedExecutionRequest(prepared.request, prepared.config);
66
+ const interactive = !options.runAgentOptions?.spawn;
67
+ const runOptions = {
68
+ stdio: interactive ? "interactive" : "captured",
69
+ parseOutput: "text",
70
+ ...(options.runAgentOptions ?? {}),
71
+ };
72
+ const lease = await preflightProposalDispatch(lowered, runOptions);
73
+ // Materialize/validate every required symbolic credential before the entry
74
+ // event opens durable state. Provider/runtime failures still occur after the
75
+ // event, preserving the command-attempt observability contract.
76
+ try {
77
+ onDispatchReady();
78
+ options.onDispatchReady?.();
79
+ const result = await dispatchLoweredExecutionRequest(lowered, { runOptions, lease });
80
+ return {
81
+ result,
82
+ engineName,
83
+ ...(lowered.runner.kind === "llm" ? {} : { engineBin: lowered.runner.profile.bin }),
84
+ notices: lowered.notices,
85
+ lease,
86
+ interactive,
87
+ };
88
+ }
89
+ catch (error) {
90
+ disposeLoweredExecutionDispatchLease(lease);
91
+ throw error;
92
+ }
93
+ }
40
94
  /**
41
95
  * WI-8.5a — the fully-qualified `bundle//conceptId` item_ref for a proposal
42
96
  * target in `stashDir`. The conceptId is BUILT from the D-R2 static table
@@ -80,23 +134,11 @@ export async function akmPropose(options) {
80
134
  throw new UsageError(`propose: unknown asset type "${options.type}". Known types: ${[...placementTypes()].sort().join(", ")}.`, "INVALID_FLAG_VALUE");
81
135
  }
82
136
  const stash = options.stashDir ?? resolveStashDir();
83
- // 1. Resolve the selected engine and write target exactly once.
84
- // the LLM arm uses the caller-specific plain-chat handler below.
137
+ // 1. Resolve the write target. Engine/model/inference resolution happens
138
+ // exactly once below through the shared execution cascade.
85
139
  const config = options.agentConfig ?? (await import("../../core/config/config.js")).loadConfig();
86
140
  const target = resolveProposalQueueTarget(stash, config);
87
- emitProposeInvoked(target.source, options);
88
- const { config: engineConfig, fallbackEngineName } = withEngineFallback(config);
89
- const engineName = options.engine ?? engineConfig.defaults?.engine;
90
- // Announced, never silent: `options.engine` outranks the default, so the
91
- // fallback is only reportable when it is the engine actually selected.
92
- const engineAnnouncement = fallbackAnnouncement(fallbackEngineName, engineName);
93
- if (engineAnnouncement)
94
- warn(engineAnnouncement);
95
- if (!engineName)
96
- throw new ConfigError(`propose ${NO_ENGINE_MESSAGE_SUFFIX} ${NO_ENGINE_REMEDY}`, "INVALID_CONFIG_FILE");
97
- const runner = resolveEngine(engineName, engineConfig);
98
- const profile = runner.kind === "llm" ? undefined : runner.profile;
99
- // 3. Build prompt.
141
+ // 2. Build terminal user content.
100
142
  // Synthesize a temp draft path so opencode can write the asset content
101
143
  // directly using its file tools rather than returning JSON via stdout.
102
144
  const draftFilePath = import("node:os").then((os) => import("node:path").then((path) => path.join(os.tmpdir(), `akm-propose-${options.type}-${options.name.replace(/[^a-z0-9_-]/gi, "_")}-${Date.now()}.md`)));
@@ -111,166 +153,144 @@ export async function akmPropose(options) {
111
153
  ...(standardsContext.trim() ? { standardsContext } : {}),
112
154
  draftFilePath: resolvedDraftPath,
113
155
  });
114
- // 4. Dispatch the selected engine.
115
- // Real agent runs use interactive mode so file tools can write the draft.
116
- // Injected/custom spawns still need captured stdout for JSON payload tests.
117
- // All kinds cross the unified RunnerSpec dispatch boundary.
118
- const useCustomSpawn = Boolean(options.runAgentOptions?.spawn);
119
- let result;
120
- const runOptions = {
121
- stdio: useCustomSpawn ? "captured" : "interactive",
122
- parseOutput: "text",
123
- ...(options.timeoutMs !== undefined ? { timeoutMs: options.timeoutMs } : {}),
124
- ...(options.runAgentOptions ?? {}),
125
- };
126
- const sensitiveValues = collectDispatchSensitiveValues(runner, runOptions);
127
- result = await executeRunner(runner, prompt, runOptions, {
128
- llm: async (spec, llmPrompt, opts) => {
129
- const { chatCompletion } = await import("../../llm/client.js");
130
- const started = Date.now();
131
- try {
132
- const stdout = await chatCompletion(spec.connection, [{ role: "user", content: llmPrompt }], {
133
- ...(Object.hasOwn(opts, "timeoutMs") ? { timeoutMs: opts.timeoutMs } : {}),
134
- });
135
- return { ok: true, exitCode: 0, stdout, stderr: "", durationMs: Date.now() - started };
136
- }
137
- catch (error) {
156
+ // 3. Preserve the fully-authored prompt as the terminal user content;
157
+ // no synthetic persona, conversation turn, schema, or tool selection is
158
+ // introduced while it crosses the shared resolved/lowered boundary.
159
+ const dispatch = await dispatchProposalPrompt(prompt, config, options, () => emitProposeInvoked(target.source, options));
160
+ const { result, engineName, notices, lease } = dispatch;
161
+ try {
162
+ if (!result.ok) {
163
+ // B3: ENOENT / not-found gives an actionable hint.
164
+ if (isEnoentFailure(result)) {
138
165
  return {
139
- ok: false,
140
- exitCode: null,
141
- stdout: "",
142
- stderr: "",
143
- durationMs: Date.now() - started,
144
- error: String(error),
145
- reason: "spawn_failed",
166
+ ...failureEnvelope(result, options.type, options.name, engineName, notices),
167
+ error: enoentHintMessage(dispatch.engineBin ?? engineName),
146
168
  };
147
169
  }
148
- },
149
- });
150
- if (!result.ok) {
151
- // B3: ENOENT / not-found gives an actionable hint.
152
- if (isEnoentFailure(result)) {
153
- return {
154
- ...failureEnvelope(result, options.type, options.name, engineName),
155
- error: enoentHintMessage(profile?.bin ?? engineName),
156
- };
170
+ return failureEnvelope(result, options.type, options.name, engineName, notices);
157
171
  }
158
- return failureEnvelope(result, options.type, options.name, engineName);
159
- }
160
- // 5. Resolve the proposal content.
161
- // Path A: opencode wrote the draft file — read it directly (no stdout parse).
162
- // Path B: fallback to stdout JSON parse for non-file-writing agents.
163
- let payload;
164
- if (fs.existsSync(resolvedDraftPath)) {
165
- const draftContent = fs.readFileSync(resolvedDraftPath, "utf8");
166
- fs.unlinkSync(resolvedDraftPath);
167
- payload = {
168
- ref: proposeItemRef(target.source, options.type, options.name),
169
- content: draftContent,
170
- };
171
- }
172
- else {
173
- // B1: When interactive mode was used and stdout is empty, the agent did not
174
- // write the draft file and stdout was not captured — surface an actionable error.
175
- const stdioWasInteractive = !useCustomSpawn;
176
- if (stdioWasInteractive && (result.stdout ?? "") === "") {
177
- return {
178
- schemaVersion: 2,
179
- ok: false,
180
- reason: "parse_error",
181
- error: "Agent did not write draft file and stdout was not captured (interactive mode). Check that the agent CLI understood the file-write instruction, or configure a headless profile with stdio: 'captured'.",
182
- type: options.type,
183
- name: options.name,
184
- engine: engineName,
185
- exitCode: result.exitCode,
186
- ...(result.stderr ? { stderr: result.stderr } : {}),
172
+ // 5. Resolve the proposal content.
173
+ // Path A: opencode wrote the draft file — read it directly (no stdout parse).
174
+ // Path B: fallback to stdout JSON parse for non-file-writing agents.
175
+ let payload;
176
+ if (fs.existsSync(resolvedDraftPath)) {
177
+ const draftContent = fs.readFileSync(resolvedDraftPath, "utf8");
178
+ fs.unlinkSync(resolvedDraftPath);
179
+ payload = {
180
+ ref: proposeItemRef(target.source, options.type, options.name),
181
+ content: draftContent,
187
182
  };
188
183
  }
189
- try {
190
- payload = parseAgentProposalPayload(result.stdout ?? "");
191
- }
192
- catch (err) {
193
- return {
194
- schemaVersion: 2,
195
- ok: false,
196
- reason: "parse_error",
197
- error: err instanceof Error ? err.message : String(err),
198
- type: options.type,
199
- name: options.name,
200
- engine: engineName,
201
- exitCode: result.exitCode,
202
- stdout: result.stdout,
203
- ...(result.stderr ? { stderr: result.stderr } : {}),
204
- };
205
- }
206
- }
207
- payload = { ...payload, content: redactSensitiveText(payload.content, sensitiveValues) };
208
- // 6. Insert the proposal. Note: we allow the agent's `ref` to normalise the
209
- // asset name (e.g. path-cleanup), but only after validating that the ref is
210
- // well-formed and the type still matches the requested type.
211
- const expectedRef = proposeItemRef(target.source, options.type, options.name);
212
- let ref = expectedRef;
213
- if (payload.ref) {
214
- let parsedRef;
215
- try {
216
- parsedRef = parseRefInput(payload.ref);
184
+ else {
185
+ // B1: When interactive mode was used and stdout is empty, the agent did not
186
+ // write the draft file and stdout was not captured — surface an actionable error.
187
+ if (dispatch.interactive && (result.stdout ?? "") === "") {
188
+ return {
189
+ schemaVersion: 2,
190
+ ok: false,
191
+ reason: "parse_error",
192
+ error: "Agent did not write draft file and stdout was not captured (interactive mode). Check that the agent CLI understood the file-write instruction, or configure a headless profile with stdio: 'captured'.",
193
+ type: options.type,
194
+ name: options.name,
195
+ engine: engineName,
196
+ exitCode: result.exitCode,
197
+ ...(result.stderr ? { stderr: result.stderr } : {}),
198
+ ...noticeFields(notices),
199
+ };
200
+ }
201
+ try {
202
+ payload = parseAgentProposalPayload(result.stdout ?? "");
203
+ }
204
+ catch (err) {
205
+ return {
206
+ schemaVersion: 2,
207
+ ok: false,
208
+ reason: "parse_error",
209
+ error: err instanceof Error ? err.message : String(err),
210
+ type: options.type,
211
+ name: options.name,
212
+ engine: engineName,
213
+ exitCode: result.exitCode,
214
+ stdout: result.stdout,
215
+ ...(result.stderr ? { stderr: result.stderr } : {}),
216
+ ...noticeFields(notices),
217
+ };
218
+ }
217
219
  }
218
- catch (err) {
219
- return {
220
- schemaVersion: 2,
221
- ok: false,
222
- reason: "parse_error",
223
- error: err instanceof Error ? err.message : String(err),
224
- type: options.type,
225
- name: options.name,
226
- engine: engineName,
227
- exitCode: result.exitCode,
228
- stdout: result.stdout,
229
- ...(result.stderr ? { stderr: result.stderr } : {}),
230
- };
220
+ payload = { ...payload, content: redactWithLoweredExecutionDispatchLease(lease, payload.content) };
221
+ // 6. Insert the proposal. Note: we allow the agent's `ref` to normalise the
222
+ // asset name (e.g. path-cleanup), but only after validating that the ref is
223
+ // well-formed and the type still matches the requested type.
224
+ const expectedRef = proposeItemRef(target.source, options.type, options.name);
225
+ let ref = expectedRef;
226
+ if (payload.ref) {
227
+ let parsedRef;
228
+ try {
229
+ parsedRef = parseRefInput(payload.ref);
230
+ }
231
+ catch (err) {
232
+ return {
233
+ schemaVersion: 2,
234
+ ok: false,
235
+ reason: "parse_error",
236
+ error: err instanceof Error ? err.message : String(err),
237
+ type: options.type,
238
+ name: options.name,
239
+ engine: engineName,
240
+ exitCode: result.exitCode,
241
+ stdout: result.stdout,
242
+ ...(result.stderr ? { stderr: result.stderr } : {}),
243
+ ...noticeFields(notices),
244
+ };
245
+ }
246
+ if (parsedRef.type !== options.type) {
247
+ return {
248
+ schemaVersion: 2,
249
+ ok: false,
250
+ reason: "parse_error",
251
+ error: `Agent returned ref type ${parsedRef.type} but expected ${options.type}`,
252
+ type: options.type,
253
+ name: options.name,
254
+ engine: engineName,
255
+ exitCode: result.exitCode,
256
+ stdout: result.stdout,
257
+ ...(result.stderr ? { stderr: result.stderr } : {}),
258
+ ...noticeFields(notices),
259
+ };
260
+ }
261
+ ref = proposeItemRef(target.source, parsedRef.type, parsedRef.name);
231
262
  }
232
- if (parsedRef.type !== options.type) {
233
- return {
234
- schemaVersion: 2,
235
- ok: false,
236
- reason: "parse_error",
237
- error: `Agent returned ref type ${parsedRef.type} but expected ${options.type}`,
238
- type: options.type,
239
- name: options.name,
240
- engine: engineName,
241
- exitCode: result.exitCode,
242
- stdout: result.stdout,
243
- ...(result.stderr ? { stderr: result.stderr } : {}),
244
- };
263
+ const createInput = {
264
+ ref,
265
+ source: "propose",
266
+ sourceRun: `propose-${Date.now()}`,
267
+ target,
268
+ // User-initiated proposals always bypass dedup/cooldown guards the
269
+ // operator is explicitly asking for a new proposal.
270
+ force: true,
271
+ payload: {
272
+ content: payload.content,
273
+ ...(payload.frontmatter ? { frontmatter: payload.frontmatter } : {}),
274
+ },
275
+ };
276
+ const proposalResult = createProposal(stash, createInput, options.ctx);
277
+ // With force:true, the result is always a Proposal (never skipped).
278
+ if (isProposalSkipped(proposalResult)) {
279
+ // Should never happen when force:true, but be defensive.
280
+ throw new Error(`Unexpected skip in propose command: ${proposalResult.message}`);
245
281
  }
246
- ref = proposeItemRef(target.source, parsedRef.type, parsedRef.name);
282
+ const proposal = proposalResult;
283
+ return {
284
+ schemaVersion: 2,
285
+ ok: true,
286
+ proposal,
287
+ ref: proposal.ref,
288
+ engine: engineName,
289
+ durationMs: result.durationMs,
290
+ ...noticeFields(notices),
291
+ };
247
292
  }
248
- const createInput = {
249
- ref,
250
- source: "propose",
251
- sourceRun: `propose-${Date.now()}`,
252
- target,
253
- // User-initiated proposals always bypass dedup/cooldown guards — the
254
- // operator is explicitly asking for a new proposal.
255
- force: true,
256
- payload: {
257
- content: payload.content,
258
- ...(payload.frontmatter ? { frontmatter: payload.frontmatter } : {}),
259
- },
260
- };
261
- const proposalResult = createProposal(stash, createInput, options.ctx);
262
- // With force:true, the result is always a Proposal (never skipped).
263
- if (isProposalSkipped(proposalResult)) {
264
- // Should never happen when force:true, but be defensive.
265
- throw new Error(`Unexpected skip in propose command: ${proposalResult.message}`);
293
+ finally {
294
+ disposeLoweredExecutionDispatchLease(lease);
266
295
  }
267
- const proposal = proposalResult;
268
- return {
269
- schemaVersion: 2,
270
- ok: true,
271
- proposal,
272
- ref: proposal.ref,
273
- engine: engineName,
274
- durationMs: result.durationMs,
275
- };
276
296
  }