akm-cli 0.9.1 → 0.9.2-alpha.1

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 (341) hide show
  1. package/CHANGELOG.md +88 -0
  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/tasks/core/extract.yml +6 -5
  12. package/dist/assets/tasks/core/improve.yml +6 -5
  13. package/dist/assets/tasks/core/index-refresh.yml +6 -5
  14. package/dist/assets/tasks/core/sync.yml +6 -5
  15. package/dist/assets/tasks/core/version-check.yml +6 -5
  16. package/dist/assets/tasks/improve/akm-graph-refresh-weekly.yml +6 -5
  17. package/dist/assets/tasks/improve/akm-improve-catchup.yml +6 -5
  18. package/dist/assets/tasks/improve/akm-improve-consolidate.yml +6 -5
  19. package/dist/assets/tasks/improve/akm-improve-frequent.yml +6 -5
  20. package/dist/assets/tasks/improve/akm-improve-nightly.yml +6 -5
  21. package/dist/cli/confirm.js +2 -2
  22. package/dist/cli/parse-args.js +3 -24
  23. package/dist/cli/retired-commands.js +1 -1
  24. package/dist/cli/shared.js +2 -2
  25. package/dist/cli.js +11 -9
  26. package/dist/commands/agent/agent-dispatch.js +55 -89
  27. package/dist/commands/agent/contribute-cli.js +12 -45
  28. package/dist/commands/command/builtin-action.js +32 -0
  29. package/dist/commands/command/command-cli.js +99 -0
  30. package/dist/commands/command/command-execution.js +308 -0
  31. package/dist/commands/command/execution-source-loader.js +176 -0
  32. package/dist/commands/command/portable-template.js +60 -0
  33. package/dist/commands/config-cli.js +10 -4
  34. package/dist/commands/env/env.js +4 -2
  35. package/dist/commands/feedback-cli.js +1 -1
  36. package/dist/commands/health/checks.js +241 -29
  37. package/dist/commands/health/html-report.js +0 -14
  38. package/dist/commands/health/report-view-model.js +0 -1
  39. package/dist/commands/health/surfaces.js +6 -7
  40. package/dist/commands/health/types.js +0 -2
  41. package/dist/commands/health.js +63 -18
  42. package/dist/commands/improve/collapse-detector.js +2 -2
  43. package/dist/commands/improve/consolidate.js +251 -214
  44. package/dist/commands/improve/distill/promote-memory.js +71 -34
  45. package/dist/commands/improve/distill/quality-gate.js +17 -5
  46. package/dist/commands/improve/distill.js +232 -155
  47. package/dist/commands/improve/eligibility.js +112 -79
  48. package/dist/commands/improve/execution.js +57 -0
  49. package/dist/commands/improve/extract-cli.js +5 -5
  50. package/dist/commands/improve/extract.js +521 -342
  51. package/dist/commands/improve/improve-strategies.js +43 -14
  52. package/dist/commands/improve/improve.js +249 -29
  53. package/dist/commands/improve/loop-stages.js +11 -17
  54. package/dist/commands/improve/memory/memory-contradiction-detect.js +90 -66
  55. package/dist/commands/improve/outcome-loop.js +22 -38
  56. package/dist/commands/improve/planner.js +134 -0
  57. package/dist/commands/improve/preparation.js +730 -409
  58. package/dist/commands/improve/reflect.js +386 -223
  59. package/dist/commands/improve/run-context.js +3 -4
  60. package/dist/commands/improve/salience.js +6 -58
  61. package/dist/commands/improve/session-asset.js +12 -12
  62. package/dist/commands/lint/index.js +101 -29
  63. package/dist/commands/migrate-cli.js +11 -69
  64. package/dist/commands/migration-tool.js +6 -9
  65. package/dist/commands/models-cli.js +27 -0
  66. package/dist/commands/proposal/drain.js +258 -186
  67. package/dist/commands/proposal/proposal-cli.js +32 -10
  68. package/dist/commands/proposal/proposal.js +2 -5
  69. package/dist/commands/proposal/propose.js +192 -172
  70. package/dist/commands/proposal/repository.js +54 -91
  71. package/dist/commands/proposal/validators/proposal-validators.js +9 -7
  72. package/dist/commands/read/curate.js +10 -0
  73. package/dist/commands/read/registry-search.js +25 -9
  74. package/dist/commands/read/remember-cli.js +14 -2
  75. package/dist/commands/read/search.js +10 -4
  76. package/dist/commands/read/show.js +139 -153
  77. package/dist/commands/registry-cli.js +16 -7
  78. package/dist/commands/remember.js +33 -18
  79. package/dist/commands/sources/add-cli.js +19 -178
  80. package/dist/commands/sources/bundle-cli.js +15 -3
  81. package/dist/commands/sources/dangerous-env-audit.js +135 -0
  82. package/dist/commands/sources/info.js +2 -1
  83. package/dist/commands/sources/installed-stashes.js +835 -152
  84. package/dist/commands/sources/schema-repair.js +174 -95
  85. package/dist/commands/sources/self-update.js +30 -74
  86. package/dist/commands/sources/source-add.js +3 -5
  87. package/dist/commands/sources/sources-cli.js +2 -15
  88. package/dist/commands/sources/update-transaction.js +220 -0
  89. package/dist/commands/tasks/tasks-cli.js +3 -3
  90. package/dist/commands/tasks/tasks.js +736 -317
  91. package/dist/commands/workflow-cli.js +2 -2
  92. package/dist/core/adapter/adapters/agent-skills-adapter.js +3 -0
  93. package/dist/core/adapter/adapters/akm-adapter.js +83 -34
  94. package/dist/core/adapter/adapters/akm-lint.js +54 -39
  95. package/dist/core/adapter/adapters/akm-metadata.js +45 -45
  96. package/dist/core/adapter/adapters/akm-task-adapter.js +32 -49
  97. package/dist/core/adapter/adapters/akm-workflow-adapter.js +38 -23
  98. package/dist/core/adapter/adapters/dotenv-adapter.js +30 -1
  99. package/dist/core/adapter/adapters/generic-files-adapter.js +11 -0
  100. package/dist/core/adapter/adapters/index.js +0 -9
  101. package/dist/core/adapter/adapters/llm-wiki-adapter.js +4 -0
  102. package/dist/core/adapter/adapters/okf-adapter.js +4 -0
  103. package/dist/core/adapter/adapters/opencode-adapter.js +5 -8
  104. package/dist/core/adapter/adapters/tool-dir-shared.js +63 -6
  105. package/dist/core/adapter/adapters/website-snapshot-adapter.js +4 -0
  106. package/dist/core/adapter/execution-source.js +308 -0
  107. package/dist/core/adapter/recognize-match.js +36 -13
  108. package/dist/core/adapter/registry.js +0 -9
  109. package/dist/core/asset/stash-meta.js +94 -4
  110. package/dist/core/common.js +6 -11
  111. package/dist/core/config/config-io.js +3 -3
  112. package/dist/core/config/config-schema.js +18 -40
  113. package/dist/core/config/config-sources.js +11 -21
  114. package/dist/core/config/config-walker.js +31 -13
  115. package/dist/core/config/config.js +21 -20
  116. package/dist/core/config/schema/engines.js +8 -7
  117. package/dist/core/config/schema/improve-processes.js +29 -5
  118. package/dist/core/config/schema/primitives.js +1 -23
  119. package/dist/core/config/schema/sources-bundles.js +13 -16
  120. package/dist/core/errors.js +2 -0
  121. package/dist/core/events.js +68 -32
  122. package/dist/core/extra-params.js +1 -0
  123. package/dist/core/improve-result.js +315 -0
  124. package/dist/core/lesson-lint.js +0 -6
  125. package/dist/core/maintenance-barrier.js +4 -4
  126. package/dist/core/network-policy.js +152 -0
  127. package/dist/core/paths.js +1 -1
  128. package/dist/core/recognition-util.js +4 -4
  129. package/dist/core/registry-url.js +456 -0
  130. package/dist/core/state/migrations.js +161 -47
  131. package/dist/core/state-db.js +453 -80
  132. package/dist/core/system-error.js +32 -0
  133. package/dist/core/time.js +2 -12
  134. package/dist/core/write-source.js +0 -18
  135. package/dist/execution/directory-identity.js +52 -0
  136. package/dist/execution/executable-identity.js +107 -0
  137. package/dist/execution/guarded-source.js +398 -0
  138. package/dist/execution/json.js +95 -0
  139. package/dist/{commands/health/types-session-log.js → execution/limits.js} +2 -1
  140. package/dist/execution/record.js +55 -0
  141. package/dist/execution/resolved-request.js +730 -0
  142. package/dist/execution/source.js +320 -0
  143. package/dist/indexer/bundle-identity-guard.js +5 -4
  144. package/dist/indexer/db/graph-db.js +33 -0
  145. package/dist/indexer/graph/graph-boost.js +3 -4
  146. package/dist/indexer/graph/graph-extraction.js +562 -373
  147. package/dist/indexer/index-written-assets.js +65 -34
  148. package/dist/indexer/indexer.js +443 -222
  149. package/dist/indexer/installations.js +6 -0
  150. package/dist/indexer/lookup/adapter-concept-owner.js +283 -0
  151. package/dist/indexer/passes/memory-inference.js +227 -174
  152. package/dist/indexer/scan/doc-to-entry.js +7 -9
  153. package/dist/indexer/scan/drain-dir.js +51 -23
  154. package/dist/indexer/search/db-search.js +98 -22
  155. package/dist/indexer/search/search-fields.js +1 -1
  156. package/dist/indexer/search/search-hit-enrichers.js +1 -1
  157. package/dist/indexer/search/search-source.js +7 -16
  158. package/dist/indexer/search/semantic-status.js +10 -1
  159. package/dist/indexer/usage/show-usage.js +105 -0
  160. package/dist/indexer/usage/usage-events.js +7 -2
  161. package/dist/indexer/walk/matchers.js +40 -10
  162. package/dist/indexer/walk/path-resolver.js +5 -2
  163. package/dist/indexer/walk/walker.js +20 -2
  164. package/dist/integrations/agent/builder-shared.js +3 -6
  165. package/dist/integrations/agent/conversation-fallback.js +16 -0
  166. package/dist/integrations/agent/engine-resolution.js +87 -87
  167. package/dist/integrations/agent/execution-cascade.js +566 -0
  168. package/dist/integrations/agent/execution-definitions.js +211 -0
  169. package/dist/integrations/agent/execution-lowering.js +811 -0
  170. package/dist/integrations/agent/execution-preparation.js +67 -0
  171. package/dist/integrations/agent/index.js +0 -2
  172. package/dist/integrations/agent/inline-execution.js +74 -0
  173. package/dist/integrations/agent/model-map.js +515 -0
  174. package/dist/integrations/agent/persona-fallback.js +30 -0
  175. package/dist/integrations/agent/request-lowering.js +186 -0
  176. package/dist/integrations/agent/runner-dispatch.js +230 -37
  177. package/dist/integrations/agent/runner.js +12 -83
  178. package/dist/integrations/harnesses/aider/agent-builder.js +8 -0
  179. package/dist/integrations/harnesses/aider/index.js +0 -1
  180. package/dist/integrations/harnesses/amazonq/agent-builder.js +8 -0
  181. package/dist/integrations/harnesses/amazonq/index.js +0 -1
  182. package/dist/integrations/harnesses/claude/agent-builder.js +14 -1
  183. package/dist/integrations/harnesses/claude/index.js +1 -5
  184. package/dist/integrations/harnesses/claude/session-log.js +3 -33
  185. package/dist/integrations/harnesses/codex/agent-builder.js +8 -0
  186. package/dist/integrations/harnesses/codex/index.js +0 -1
  187. package/dist/integrations/harnesses/copilot/agent-builder.js +8 -0
  188. package/dist/integrations/harnesses/copilot/index.js +0 -1
  189. package/dist/integrations/harnesses/gemini/agent-builder.js +8 -0
  190. package/dist/integrations/harnesses/gemini/index.js +0 -1
  191. package/dist/integrations/harnesses/index.js +4 -44
  192. package/dist/integrations/harnesses/opencode/agent-builder.js +16 -9
  193. package/dist/integrations/harnesses/opencode/index.js +0 -2
  194. package/dist/integrations/harnesses/opencode/session-log.js +14 -204
  195. package/dist/integrations/harnesses/opencode-sdk/harness.js +12 -1
  196. package/dist/integrations/harnesses/opencode-sdk/sdk-runner.js +40 -42
  197. package/dist/integrations/harnesses/openhands/agent-builder.js +8 -0
  198. package/dist/integrations/harnesses/openhands/index.js +0 -1
  199. package/dist/integrations/harnesses/pi/agent-builder.js +8 -0
  200. package/dist/integrations/harnesses/pi/index.js +0 -1
  201. package/dist/integrations/harnesses/shared.js +0 -1
  202. package/dist/integrations/harnesses/types.js +1 -3
  203. package/dist/integrations/lockfile.js +82 -79
  204. package/dist/integrations/session-logs/index.js +6 -17
  205. package/dist/integrations/session-logs/provider-base.js +1 -29
  206. package/dist/llm/client.js +10 -5
  207. package/dist/llm/embedder.js +6 -7
  208. package/dist/llm/embedders/local.js +37 -88
  209. package/dist/llm/embedders/types.js +1 -1
  210. package/dist/llm/graph-extract.js +75 -50
  211. package/dist/llm/index-passes.js +43 -5
  212. package/dist/llm/memory-infer.js +8 -6
  213. package/dist/llm/metadata-enhance.js +5 -3
  214. package/dist/llm/structured-call.js +122 -25
  215. package/dist/output/format-exempt.js +1 -1
  216. package/dist/output/render-registry.js +0 -16
  217. package/dist/output/renderers.js +12 -7
  218. package/dist/output/shapes/curate.js +1 -0
  219. package/dist/output/shapes/helpers.js +10 -2
  220. package/dist/output/shapes/passthrough.js +2 -0
  221. package/dist/output/text/command-format.js +28 -32
  222. package/dist/output/text/health-format.js +1 -29
  223. package/dist/output/text/migrate.js +6 -56
  224. package/dist/output/text/proposal-format.js +16 -1
  225. package/dist/output/text/workflow-format.js +16 -0
  226. package/dist/registry/network.js +279 -0
  227. package/dist/registry/pinned-request-helper.js +247 -0
  228. package/dist/registry/pinned-transport.js +717 -0
  229. package/dist/registry/providers/skills-sh.js +18 -6
  230. package/dist/registry/providers/static-index.js +20 -7
  231. package/dist/registry/resolve.js +53 -28
  232. package/dist/scripts/akm-migrate-node.js +19122 -52218
  233. package/dist/scripts/akm-migrate.js +19064 -51567
  234. package/dist/setup/registry-stash-loader.js +64 -20
  235. package/dist/setup/semantic-assets.js +9 -34
  236. package/dist/setup/setup.js +12 -30
  237. package/dist/setup/source-identity.js +17 -0
  238. package/dist/setup/steps/sources.js +36 -15
  239. package/dist/setup/steps/tasks.js +39 -11
  240. package/dist/sources/providers/git-provider.js +3 -3
  241. package/dist/sources/providers/npm.js +2 -2
  242. package/dist/sources/providers/provider-utils.js +4 -3
  243. package/dist/sources/providers/website.js +11 -7
  244. package/dist/sources/snapshot-fetchers/host-guard.js +9 -136
  245. package/dist/sources/snapshot-fetchers/website-ingest.js +25 -109
  246. package/dist/sources/website-url.js +73 -0
  247. package/dist/storage/engines/sqlite-migrations.js +81 -26
  248. package/dist/storage/managed-db.js +27 -24
  249. package/dist/storage/repositories/events-repository.js +3 -0
  250. package/dist/storage/repositories/index-connection.js +42 -10
  251. package/dist/storage/repositories/index-entries-repository.js +167 -207
  252. package/dist/storage/repositories/index-entry-mapper.js +8 -12
  253. package/dist/storage/repositories/index-entry-schema.js +255 -0
  254. package/dist/storage/repositories/index-fts-repository.js +10 -10
  255. package/dist/storage/repositories/index-llm-cache-repository.js +8 -13
  256. package/dist/storage/repositories/index-meta-repository.js +0 -11
  257. package/dist/storage/repositories/index-schema.js +71 -342
  258. package/dist/storage/repositories/index-utility-repository.js +12 -17
  259. package/dist/storage/repositories/index-vec-repository.js +1 -1
  260. package/dist/storage/repositories/proposals-repository.js +4 -127
  261. package/dist/storage/repositories/registry-cache.js +2 -1
  262. package/dist/storage/repositories/task-history-repository.js +20 -40
  263. package/dist/storage/repositories/workflow-runs-repository.js +228 -129
  264. package/dist/storage/sqlite-read-snapshot.js +148 -0
  265. package/dist/tasks/backends/cron.js +170 -42
  266. package/dist/tasks/backends/index.js +1 -1
  267. package/dist/tasks/backends/launchd.js +787 -202
  268. package/dist/tasks/backends/schtasks.js +282 -83
  269. package/dist/tasks/embedded.js +7 -7
  270. package/dist/tasks/frozen-script.js +50 -0
  271. package/dist/tasks/resolve-akm-bin.js +5 -1
  272. package/dist/tasks/runner.js +239 -251
  273. package/dist/tasks/runtime-v3.js +281 -0
  274. package/dist/tasks/scheduler-binding.js +272 -0
  275. package/dist/tasks/scheduler-invocation.js +57 -43
  276. package/dist/tasks/scheduler-sync.js +654 -0
  277. package/dist/tasks/source-v3.js +752 -0
  278. package/dist/tasks/standalone-script-entry.js +5 -0
  279. package/dist/tasks/task-id.js +29 -0
  280. package/dist/workflows/authoring/authoring.js +15 -32
  281. package/dist/workflows/exec/dispatch-redaction.js +14 -8
  282. package/dist/workflows/exec/exec-unit.js +7 -28
  283. package/dist/workflows/exec/frozen-judge.js +57 -89
  284. package/dist/workflows/exec/lowering-notices.js +23 -0
  285. package/dist/workflows/exec/native-executor.js +301 -458
  286. package/dist/workflows/exec/param-secrets.js +4 -3
  287. package/dist/workflows/exec/run-workflow.js +26 -32
  288. package/dist/workflows/exec/step-work.js +105 -109
  289. package/dist/workflows/exec/unit-dispatch.js +103 -27
  290. package/dist/workflows/exec/unit-writer.js +3 -3
  291. package/dist/workflows/exec/worktree.js +2 -2
  292. package/dist/workflows/ir/compile.js +86 -72
  293. package/dist/workflows/ir/environment-v4.js +328 -0
  294. package/dist/workflows/ir/freeze-v4.js +122 -0
  295. package/dist/workflows/ir/plan-hash.js +13 -7
  296. package/dist/workflows/ir/schema-v4.js +525 -0
  297. package/dist/workflows/ir/schema.js +25 -284
  298. package/dist/workflows/ir/source-freeze-v4.js +506 -0
  299. package/dist/workflows/parser.js +27 -24
  300. package/dist/workflows/program/schema.js +1 -2
  301. package/dist/workflows/renderer.js +42 -29
  302. package/dist/workflows/resource-limits.js +4 -5
  303. package/dist/workflows/runtime/agent-identity.js +11 -13
  304. package/dist/workflows/runtime/plan-classifier.js +8 -8
  305. package/dist/workflows/runtime/runs.js +27 -43
  306. package/dist/workflows/runtime/workflow-asset-loader.js +45 -205
  307. package/dist/workflows/source-files.js +373 -0
  308. package/dist/workflows/source-ir/compile.js +196 -0
  309. package/dist/workflows/source-ir/github-yaml.js +577 -0
  310. package/dist/workflows/source-ir/ordering.js +38 -0
  311. package/dist/workflows/source-ir/program.js +50 -0
  312. package/dist/workflows/source-ir/result.js +26 -0
  313. package/dist/workflows/source-ir/schema.js +772 -0
  314. package/dist/workflows/source-ir/semantics.js +242 -0
  315. package/dist/workflows/source-ir/uses.js +14 -0
  316. package/docs/README.md +2 -0
  317. package/docs/migration/README.md +3 -1
  318. package/docs/migration/release-notes/0.9.2.md +55 -0
  319. package/docs/migration/release-notes/README.md +5 -0
  320. package/docs/migration/v0.8-to-v0.9.md +76 -1077
  321. package/docs/migration/v0.9.0-troubleshooting.md +104 -516
  322. package/docs/migration/v0.9.1-to-v0.9.2.md +150 -0
  323. package/docs/reference/README.md +1 -0
  324. package/docs/reference/cli.md +230 -98
  325. package/docs/reference/configuration.md +153 -27
  326. package/docs/reference/data-and-telemetry.md +19 -1
  327. package/docs/reference/supported-formats.md +23 -3
  328. package/docs/reference/tasks.md +182 -0
  329. package/docs/reference/workflow-schema.md +91 -40
  330. package/docs/reference/workflows.md +33 -6
  331. package/package.json +10 -6
  332. package/schemas/akm-config.json +372 -216
  333. package/schemas/akm-task.json +324 -80
  334. package/schemas/akm-workflow.json +6 -9
  335. package/dist/core/migration-operation.js +0 -75
  336. package/dist/integrations/agent/model-aliases.js +0 -74
  337. package/dist/tasks/parser.js +0 -380
  338. package/dist/tasks/schema.js +0 -123
  339. package/dist/tasks/validator.js +0 -80
  340. package/dist/workflows/ir/freeze.js +0 -320
  341. 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
  }