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
@@ -52,7 +52,7 @@ import { appendEvent } from "../../core/events.js";
52
52
  import { proposalContent } from "../../core/file-change.js";
53
53
  import { _setTxnMutationHookForTests, advanceTxn, beginTxn, canonicalTxnRoot, cleanupTxn, fsyncTxnDir, fsyncTxnFile, listTxnJournals, mintTxnId, registerTxnKind, sweepJournallessTxnDir, txnDirFor, txnMutationHook, txnNamespaceDir, } from "../../core/fs-txn.js";
54
54
  import { canonicalBundleIdForTarget, resolveBundleWriteTarget } from "../../core/mutation-target.js";
55
- import { withImmediateTransaction, withStateDb } from "../../core/state-db.js";
55
+ import { getStateDbPath, withImmediateTransaction, withStateDb } from "../../core/state-db.js";
56
56
  import { warn } from "../../core/warn.js";
57
57
  import { recordWrittenPath } from "../../core/write-provenance.js";
58
58
  import { assertAkmAssetWrite, assertWriteTargetPathsClean, captureGitPublication, captureWriteTargetPathSnapshot, prepareWriteTargetForMutation, publishWriteTargetTransaction, resolveWriteTarget, } from "../../core/write-source.js";
@@ -61,7 +61,8 @@ import { indexWrittenAssets } from "../../indexer/index-written-assets.js";
61
61
  import { deriveInstallations } from "../../indexer/installations.js";
62
62
  import { resolveSourceEntries } from "../../indexer/search/search-source.js";
63
63
  import { insertEventOnce } from "../../storage/repositories/events-repository.js";
64
- import { getStateProposal, getStateProposalLenient, listStateProposalIdsByPrefix, listStateProposals, upsertProposal, } from "../../storage/repositories/proposals-repository.js";
64
+ import { getStateProposal, listStateProposalIdsByPrefix, listStateProposals, upsertProposal, } from "../../storage/repositories/proposals-repository.js";
65
+ import { openSqliteReadSnapshot } from "../../storage/sqlite-read-snapshot.js";
65
66
  import { pkgVersion } from "../../version.js";
66
67
  import { runBaseChecks } from "../lint/base-linter.js";
67
68
  import { formatNewAssetDiff, formatUnifiedDiff } from "./diff-format.js";
@@ -153,46 +154,6 @@ function newId(ctx) {
153
154
  function withProposalsDb(_stashDir, ctx, fn) {
154
155
  return withStateDb(fn, { path: ctx?.dbPath });
155
156
  }
156
- function persistProposalUpdate(db, proposal, stashDir) {
157
- // Only take the full re-serialize (upsertProposal -> proposalToRowValues)
158
- // path when `changes` is well-formed enough to survive it — a non-empty
159
- // path on every entry, matching proposalToRowValues' own validation. A
160
- // legacy row with a present `proposedTarget` but an empty/missing
161
- // `changes[].path` (e.g. a malformed 0.8-era row) would otherwise die in
162
- // proposalToRowValues; falling through to the targeted UPDATE below keeps
163
- // `changes`/`proposedTarget` untouched in metadata_json and only flips the
164
- // status/review/etc. fields the terminal transition actually needs.
165
- const changesAreWellFormed = proposal.changes.length > 0 && proposal.changes.every((change) => change.path.length > 0);
166
- if (changesAreWellFormed && proposal.proposedTarget) {
167
- upsertProposal(db, proposal, stashDir);
168
- return;
169
- }
170
- const row = db
171
- .prepare("SELECT metadata_json FROM proposals WHERE id = ? AND stash_dir = ?")
172
- .get(proposal.id, stashDir);
173
- if (!row)
174
- throw new NotFoundError(`Proposal "${proposal.id}" not found.`, "PROPOSAL_NOT_FOUND");
175
- const metadata = JSON.parse(row.metadata_json);
176
- for (const field of [
177
- "sourceRun",
178
- "beforeHash",
179
- "review",
180
- "confidence",
181
- "gateDecision",
182
- "backupContent",
183
- "acceptedTarget",
184
- "eligibilitySource",
185
- ]) {
186
- const value = proposal[field];
187
- if (value === undefined)
188
- delete metadata[field];
189
- else
190
- metadata[field] = value;
191
- }
192
- db.prepare(`UPDATE proposals
193
- SET ref = ?, status = ?, source = ?, updated_at = ?, content = ?, frontmatter_json = ?, metadata_json = ?
194
- WHERE id = ? AND stash_dir = ?`).run(proposal.ref, proposal.status, proposal.source, proposal.updatedAt, proposal.payload.content, proposal.payload.frontmatter ? JSON.stringify(proposal.payload.frontmatter) : null, JSON.stringify(metadata), proposal.id, stashDir);
195
- }
196
157
  function proposalRefIdentity(ref) {
197
158
  try {
198
159
  const parsed = parseBundleRef(ref);
@@ -565,6 +526,50 @@ export function listProposals(stashDir, options = {}, ctx) {
565
526
  });
566
527
  });
567
528
  }
529
+ /**
530
+ * Read proposal context without creating or migrating state.db.
531
+ *
532
+ * Prompt-building consumers call this before their first model dispatch. A
533
+ * missing proposal store is therefore an empty snapshot, not a reason to
534
+ * create durable state before a required symbolic credential is validated at
535
+ * the dispatch boundary.
536
+ */
537
+ export function listProposalsReadOnly(stashDir, options = {}, ctx) {
538
+ const dbPath = ctx?.dbPath ?? getStateDbPath();
539
+ if (!fs.existsSync(dbPath))
540
+ return [];
541
+ let db;
542
+ try {
543
+ db = openSqliteReadSnapshot(dbPath);
544
+ if (!db)
545
+ return [];
546
+ if (!options.includeArchive && options.status !== undefined && options.status !== "pending")
547
+ return [];
548
+ const status = options.includeArchive ? options.status : "pending";
549
+ const wantRef = options.ref !== undefined ? filterRefIdentity(options.ref) : undefined;
550
+ return listStateProposals(db, {
551
+ stashDir,
552
+ ...(status !== undefined ? { status } : {}),
553
+ }).filter((proposal) => {
554
+ if (wantRef !== undefined && !proposalMatchesRef(proposal.ref, wantRef))
555
+ return false;
556
+ if (!options.type)
557
+ return true;
558
+ try {
559
+ return parseRefInput(proposal.ref).type === options.type;
560
+ }
561
+ catch {
562
+ return false;
563
+ }
564
+ });
565
+ }
566
+ catch {
567
+ return [];
568
+ }
569
+ finally {
570
+ db?.close();
571
+ }
572
+ }
568
573
  /**
569
574
  * Look up a proposal by id (live or archived).
570
575
  * Throws `NotFoundError` when no match exists in this stash.
@@ -579,25 +584,6 @@ function requireProposal(db, stashDir, id) {
579
584
  }
580
585
  return proposal;
581
586
  }
582
- /**
583
- * Lenient counterpart to {@link requireProposal} / {@link getProposal}, used
584
- * ONLY on the terminal-status (reject/archive) read paths — `archiveProposal`
585
- * and the reject-transaction machinery (`rejectProposalDurably`,
586
- * `finalizeRejectTransaction`). Those paths must succeed even when the row's
587
- * metadata fails strict decoding (see {@link proposalRowToProposalLenient});
588
- * every other reader (accept, revert, show, list's pending branch) keeps
589
- * strict decoding via `getProposal`/`requireProposal` unchanged.
590
- */
591
- function requireProposalLenient(db, stashDir, id) {
592
- const proposal = getStateProposalLenient(db, id, stashDir);
593
- if (!proposal) {
594
- throw new NotFoundError(`Proposal "${id}" not found.`, "PROPOSAL_NOT_FOUND");
595
- }
596
- return proposal;
597
- }
598
- function getProposalLenient(stashDir, id, ctx) {
599
- return withProposalsDb(stashDir, ctx, (db) => requireProposalLenient(db, stashDir, id));
600
- }
601
587
  /**
602
588
  * Resolve a proposal by full UUID, UUID prefix, or asset ref.
603
589
  *
@@ -638,22 +624,6 @@ export function resolveProposalId(stashDir, idOrRef, ctx) {
638
624
  throw new NotFoundError(`Proposal "${idOrRef}" not found.`, "PROPOSAL_NOT_FOUND");
639
625
  });
640
626
  }
641
- /**
642
- * Resolve a reject target's id, tolerating a legacy row whose metadata fails
643
- * strict decoding. `akm proposal reject` only needs the id — but
644
- * {@link resolveProposalId}'s exact-UUID fast path decodes the FULL proposal
645
- * just to hand it back, which throws on those rows before the
646
- * terminal-status machinery (which reads leniently — see
647
- * `requireProposalLenient`) ever runs. Falls back to `resolveProposalId`
648
- * unchanged for ref / uuid-prefix inputs, where existing resolution
649
- * (including its error semantics) is preserved.
650
- */
651
- export function resolveProposalIdForReject(stashDir, idOrRef, ctx) {
652
- const exact = withProposalsDb(stashDir, ctx, (db) => getStateProposalLenient(db, idOrRef, stashDir));
653
- if (exact)
654
- return exact.id;
655
- return resolveProposalId(stashDir, idOrRef, ctx).id;
656
- }
657
627
  /**
658
628
  * Archive a proposal: flip its status to `accepted` / `rejected`, bump
659
629
  * `updatedAt`, and record the review block. Used by both accept and reject
@@ -662,10 +632,7 @@ export function resolveProposalIdForReject(stashDir, idOrRef, ctx) {
662
632
  export function archiveProposal(stashDir, id, status, reason, ctx, gateDecision) {
663
633
  return withProposalsDb(stashDir, ctx, (db) => {
664
634
  return withImmediateTransaction(db, () => {
665
- // Lenient: archiving (accept OR reject) a legacy row with malformed
666
- // changes/proposedTarget metadata must still be able to flip status —
667
- // see requireProposalLenient.
668
- const existing = requireProposalLenient(db, stashDir, id);
635
+ const existing = requireProposal(db, stashDir, id);
669
636
  if (existing.status !== "pending") {
670
637
  throw new UsageError(`Proposal ${id} is not pending (current status: ${existing.status}). Only pending proposals can be ${status}.`, "INVALID_FLAG_VALUE");
671
638
  }
@@ -681,7 +648,7 @@ export function archiveProposal(stashDir, id, status, reason, ctx, gateDecision)
681
648
  },
682
649
  ...(gateDecision ? { gateDecision: { ...gateDecision, decidedAt: gateDecision.decidedAt ?? decidedAt } } : {}),
683
650
  };
684
- persistProposalUpdate(db, updated, stashDir);
651
+ upsertProposal(db, updated, stashDir);
685
652
  return updated;
686
653
  });
687
654
  });
@@ -711,7 +678,7 @@ export function recordGateDecision(stashDir, id, decision, ctx) {
711
678
  ...existing,
712
679
  gateDecision: { ...decision, decidedAt: decision.decidedAt ?? nowIso(ctx) },
713
680
  };
714
- persistProposalUpdate(db, updated, stashDir);
681
+ upsertProposal(db, updated, stashDir);
715
682
  return updated;
716
683
  });
717
684
  });
@@ -1182,9 +1149,7 @@ const REJECT_TXN_PHASES = ["prepared", "state-persisted", "event-finalized", "co
1182
1149
  function finalizeRejectTransaction(txn, ctx) {
1183
1150
  const p = txn.journal.payload;
1184
1151
  const decidedAt = txn.journal.decidedAt;
1185
- // Lenient: a reject transaction must run to completion even on a legacy
1186
- // row whose metadata fails strict decoding — see requireProposalLenient.
1187
- let proposal = getProposalLenient(p.stashDir, p.proposalId, ctx);
1152
+ let proposal = getProposal(p.stashDir, p.proposalId, ctx);
1188
1153
  if (txn.journal.phase === "prepared") {
1189
1154
  if (proposal.status === "pending") {
1190
1155
  proposal = archiveProposal(p.stashDir, p.proposalId, "rejected", p.reason, { ...ctx, now: () => Date.parse(decidedAt) }, p.gateDecision);
@@ -1196,7 +1161,7 @@ function finalizeRejectTransaction(txn, ctx) {
1196
1161
  txnMutationHook("reject-state-persisted");
1197
1162
  }
1198
1163
  if (txn.journal.phase === "state-persisted") {
1199
- proposal = getProposalLenient(p.stashDir, p.proposalId, ctx);
1164
+ proposal = getProposal(p.stashDir, p.proposalId, ctx);
1200
1165
  const eventRef = proposal.ref;
1201
1166
  const eventMeta = {
1202
1167
  proposalId: proposal.id,
@@ -1250,9 +1215,7 @@ export function rejectProposalDurably(stashDir, proposalId, reason, ctx, gateDec
1250
1215
  const recovered = recoverRejectTransaction(stashDir, proposalId, ctx);
1251
1216
  if (recovered)
1252
1217
  return recovered;
1253
- // Lenient: see requireProposalLenient the reject decision itself must not
1254
- // be blocked by a legacy row's malformed changes/proposedTarget metadata.
1255
- const proposal = getProposalLenient(stashDir, proposalId, ctx);
1218
+ const proposal = getProposal(stashDir, proposalId, ctx);
1256
1219
  if (proposal.status !== "pending") {
1257
1220
  throw new UsageError(`Proposal ${proposalId} is not pending (current status: ${proposal.status}). Only pending proposals can be rejected.`, "INVALID_FLAG_VALUE");
1258
1221
  }
@@ -1700,7 +1663,7 @@ async function promoteProposalWithLease(stashDir, config, id, options, ctx) {
1700
1663
  // final promoted payload (not the defective original).
1701
1664
  if (repairedContent !== proposalContent(proposal)) {
1702
1665
  withProposalsDb(stashDir, ctx, (db) => {
1703
- persistProposalUpdate(db, proposalToValidate, stashDir);
1666
+ upsertProposal(db, proposalToValidate, stashDir);
1704
1667
  });
1705
1668
  }
1706
1669
  await recoverProposalTransactionsForStash(stashDir, config, ctx, id);
@@ -5,8 +5,8 @@ import { parseFrontmatter } from "../../../core/asset/frontmatter.js";
5
5
  import { parseRefInput } from "../../../core/asset/resolve-ref.js";
6
6
  import { proposalContent } from "../../../core/file-change.js";
7
7
  import { lintLessonContent } from "../../../core/lesson-lint.js";
8
- import { parseTaskDocument } from "../../../tasks/parser.js";
9
- import { parseWorkflow } from "../../../workflows/parser.js";
8
+ import { parseTaskV3Yaml } from "../../../tasks/source-v3.js";
9
+ import { compileWorkflowSource } from "../../../workflows/source-ir/compile.js";
10
10
  import { defaultProposalQualityValidators } from "./proposal-quality-validators.js";
11
11
  const genericProposalValidator = {
12
12
  name: "generic-proposal-validator",
@@ -52,10 +52,9 @@ const canonicalProposalValidators = {
52
52
  const name = ctx.parsedRef?.name;
53
53
  if (!name)
54
54
  return [];
55
- parseTaskDocument({
55
+ parseTaskV3Yaml({
56
56
  yaml: proposalContent(proposal),
57
57
  filePath: proposal.changes[0]?.path || proposal.ref,
58
- id: name,
59
58
  });
60
59
  return [];
61
60
  },
@@ -63,13 +62,16 @@ const canonicalProposalValidators = {
63
62
  const content = proposalContent(proposal);
64
63
  if (!content.trim())
65
64
  return [];
66
- const changePath = proposal.changes[0]?.path ?? "";
67
- const result = parseWorkflow(content, { path: changePath || proposal.ref });
65
+ const sourcePath = proposal.changes[0]?.path || proposal.ref;
66
+ const result = compileWorkflowSource(content, {
67
+ path: sourcePath,
68
+ workspaceRoot: proposal.proposedTarget.root,
69
+ });
68
70
  if (result.ok)
69
71
  return [];
70
72
  return result.errors.map((error) => ({
71
73
  kind: "invalid-workflow-structure",
72
- message: `Workflow proposal ${proposal.id} (${proposal.ref}) is invalid at line ${error.line}: ${error.message}`,
74
+ message: `Workflow proposal ${proposal.id} (${proposal.ref}) is invalid [${error.code}] at ${error.path}:${error.line}: ${error.message}`,
73
75
  }));
74
76
  },
75
77
  };
@@ -159,6 +159,7 @@ export async function curateSearchResults(query, result, limit, selectedType, ev
159
159
  summary: buildCurateSummary(query, items),
160
160
  items,
161
161
  ...(result.warnings?.length ? { warnings: result.warnings } : {}),
162
+ ...(result.searchMode ? { searchMode: result.searchMode } : {}),
162
163
  ...(result.tip ? { tip: result.tip } : {}),
163
164
  };
164
165
  }
@@ -389,11 +390,20 @@ export function mergeCurateSearchResponses(base, extras) {
389
390
  ...baseReg,
390
391
  ...[...extraRegOnly.values()].sort((a, b) => (b.score ?? 0) - (a.score ?? 0)),
391
392
  ];
393
+ const modes = [base.searchMode, ...extras.map((result) => result.searchMode)].filter((mode) => mode !== undefined);
394
+ const searchMode = modes.includes("fts-fallback")
395
+ ? "fts-fallback"
396
+ : modes.includes("semantic")
397
+ ? "semantic"
398
+ : modes.includes("keyword")
399
+ ? "keyword"
400
+ : undefined;
392
401
  return {
393
402
  ...base,
394
403
  hits: mergedHits,
395
404
  ...(mergedRegistryHits.length > 0 ? { registryHits: mergedRegistryHits } : {}),
396
405
  ...(warnings.length > 0 ? { warnings } : {}),
406
+ ...(searchMode ? { searchMode } : {}),
397
407
  ...(mergedHits.length > 0 || mergedRegistryHits.length > 0 ? { tip: undefined } : {}),
398
408
  };
399
409
  }
@@ -1,8 +1,8 @@
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 { toErrorMessage } from "../../core/common.js";
5
4
  import { DEFAULT_CONFIG } from "../../core/config/config.js";
5
+ import { formatRegistryCredentialWarning, formatRegistryError, formatRegistryLabel, hasRegistryUrlCredentials, redactCredentialBearingUrls, } from "../../core/registry-url.js";
6
6
  import { warn } from "../../core/warn.js";
7
7
  import { resolveRegistryProviderFactory } from "../../registry/factory.js";
8
8
  // ── Eagerly import providers to trigger self-registration ───────────────────
@@ -16,8 +16,13 @@ export async function searchRegistry(query, options) {
16
16
  const limit = clampLimit(options?.limit);
17
17
  // resolveRegistries() already filters by enabled; explicit registries are filtered here
18
18
  const raw = options?.registries ?? resolveRegistries();
19
- const entries = options?.registries ? raw.filter((r) => r.enabled !== false) : raw;
20
19
  const warnings = [];
20
+ const entries = (options?.registries ? raw.filter((r) => r.enabled !== false) : raw).filter((entry) => {
21
+ if (!hasRegistryUrlCredentials(entry.url))
22
+ return true;
23
+ warnings.push(formatRegistryCredentialWarning(entry));
24
+ return false;
25
+ });
21
26
  // Resolve and search all providers concurrently
22
27
  const results = await Promise.allSettled(entries.map((entry) => {
23
28
  const provider = createProvider(entry, warnings);
@@ -34,13 +39,13 @@ export async function searchRegistry(query, options) {
34
39
  for (let i = 0; i < results.length; i++) {
35
40
  const result = results[i];
36
41
  if (result.status === "rejected") {
37
- warnings.push(toErrorMessage(result.reason));
42
+ warnings.push(`Registry ${formatRegistryLabel(entries[i])}: ${formatRegistryError(result.reason)}`);
38
43
  continue;
39
44
  }
40
45
  const value = result.value;
41
46
  if (!value)
42
47
  continue;
43
- const registryLabel = entries[i].name ? `"${entries[i].name}"` : entries[i].url;
48
+ const registryLabel = formatRegistryLabel(entries[i]);
44
49
  let dropped = 0;
45
50
  const validHits = [];
46
51
  for (const hit of value.hits) {
@@ -75,7 +80,7 @@ export async function searchRegistry(query, options) {
75
80
  warnings.push(`Registry ${registryLabel} returned ${dropped} incomplete hit(s); dropped from response.`);
76
81
  }
77
82
  if (value.warnings)
78
- warnings.push(...value.warnings);
83
+ warnings.push(...value.warnings.map(redactCredentialBearingUrls));
79
84
  }
80
85
  // Sort merged hits by normalized score descending, apply limit
81
86
  allHits.sort((a, b) => (b.score ?? 0) - (a.score ?? 0));
@@ -121,7 +126,7 @@ export function resolveRegistries(configRegistries) {
121
126
  provider = trimmed.slice(0, colonColonIdx).trim();
122
127
  url = trimmed.slice(colonColonIdx + 2).trim();
123
128
  if (!provider) {
124
- warn(`[akm] Ignoring AKM_REGISTRY_URL entry: empty provider type before "::" in "${trimmed}"`);
129
+ warn('[akm] Ignoring AKM_REGISTRY_URL entry: empty provider type before "::".');
125
130
  continue;
126
131
  }
127
132
  }
@@ -129,7 +134,11 @@ export function resolveRegistries(configRegistries) {
129
134
  url = trimmed;
130
135
  }
131
136
  if (!url.startsWith("http://") && !url.startsWith("https://")) {
132
- warn(`[akm] Ignoring AKM_REGISTRY_URL entry: must start with http:// or https://, got "${url}"`);
137
+ warn("[akm] Ignoring AKM_REGISTRY_URL entry: URL must start with http:// or https://.");
138
+ continue;
139
+ }
140
+ if (hasRegistryUrlCredentials(url)) {
141
+ warn(`[akm] ${formatRegistryCredentialWarning({ url })}`);
133
142
  continue;
134
143
  }
135
144
  entries.push(provider ? { url, provider } : { url });
@@ -137,14 +146,21 @@ export function resolveRegistries(configRegistries) {
137
146
  return entries;
138
147
  }
139
148
  const registries = configRegistries ?? DEFAULT_CONFIG.registries ?? [];
140
- return registries.filter((r) => r.enabled !== false);
149
+ return registries.filter((entry) => {
150
+ if (entry.enabled === false)
151
+ return false;
152
+ if (!hasRegistryUrlCredentials(entry.url))
153
+ return true;
154
+ warn(`[akm] ${formatRegistryCredentialWarning(entry)}`);
155
+ return false;
156
+ });
141
157
  }
142
158
  // ── Provider resolution ─────────────────────────────────────────────────────
143
159
  function createProvider(entry, warnings) {
144
160
  const providerType = entry.provider ?? "static-index";
145
161
  const factory = resolveRegistryProviderFactory(providerType);
146
162
  if (!factory) {
147
- const label = entry.name ? `${entry.name} (${entry.url})` : entry.url;
163
+ const label = formatRegistryLabel(entry);
148
164
  warnings.push(`Registry ${label}: unknown provider type "${providerType}"`);
149
165
  return null;
150
166
  }
@@ -230,6 +230,7 @@ export const rememberCommand = defineJsonCommand({
230
230
  let observed_at;
231
231
  let expires;
232
232
  let subjective;
233
+ let executionNotices;
233
234
  // Resolve --expires to an ISO date string
234
235
  if (args.expires) {
235
236
  const durationMs = parseDuration(args.expires);
@@ -261,6 +262,7 @@ export const rememberCommand = defineJsonCommand({
261
262
  description = enriched.description;
262
263
  if (!observed_at && enriched.observed_at)
263
264
  observed_at = enriched.observed_at;
265
+ executionNotices = enriched.notices;
264
266
  }
265
267
  // ── Required-field check (before any write) ───────────────────────────
266
268
  // Tags remain required when the user explicitly asked for tag-bearing
@@ -318,15 +320,25 @@ export const rememberCommand = defineJsonCommand({
318
320
  tagCount: tags.length,
319
321
  enriched: args.enrich === true,
320
322
  auto: args.auto === true,
323
+ ...(executionNotices && executionNotices.length > 0 ? { notices: executionNotices } : {}),
321
324
  ...(hasScope ? { scope: scopeFields } : {}),
322
325
  },
323
326
  });
324
327
  if (args.showSimilar) {
325
328
  const similar = await fetchSimilarMemories((body ?? args.content ?? "").slice(0, 500), result.ref, eventSource);
326
- output("remember", { ok: true, ...result, similar });
329
+ output("remember", {
330
+ ok: true,
331
+ ...result,
332
+ similar,
333
+ ...(executionNotices && executionNotices.length > 0 ? { notices: executionNotices } : {}),
334
+ });
327
335
  }
328
336
  else {
329
- output("remember", { ok: true, ...result });
337
+ output("remember", {
338
+ ok: true,
339
+ ...result,
340
+ ...(executionNotices && executionNotices.length > 0 ? { notices: executionNotices } : {}),
341
+ });
330
342
  }
331
343
  },
332
344
  });
@@ -127,9 +127,10 @@ export async function akmSearch(input) {
127
127
  hits: localHits,
128
128
  tip: hasResults ? undefined : localResult?.tip,
129
129
  warnings: localResult?.warnings?.length ? localResult.warnings : undefined,
130
+ searchMode: localResult?.mode ?? "keyword",
130
131
  timing: { totalMs: Date.now() - t0, rankMs: localResult?.rankMs, embedMs: localResult?.embedMs },
131
132
  };
132
- maybeLogSearchEvent(input, query, response, localResult?.mode ?? "keyword");
133
+ maybeLogSearchEvent(input, query, response, usageSearchMode(localResult?.mode));
133
134
  return response;
134
135
  }
135
136
  const registryHits = (registryResult?.hits ?? []).map((hit) => {
@@ -174,11 +175,16 @@ export async function akmSearch(input) {
174
175
  registryHits,
175
176
  tip: hasResults ? undefined : "No matching stash assets or registry entries were found.",
176
177
  warnings: warnings.length ? warnings : undefined,
178
+ searchMode: localResult?.mode ?? "keyword",
177
179
  timing: { totalMs: Date.now() - t0 },
178
180
  };
179
- maybeLogSearchEvent(input, query, response);
181
+ maybeLogSearchEvent(input, query, response, usageSearchMode(localResult?.mode));
180
182
  return response;
181
183
  }
184
+ /** Usage telemetry retains its historical semantic|keyword vocabulary. */
185
+ function usageSearchMode(mode) {
186
+ return mode === "semantic" ? "semantic" : "keyword";
187
+ }
182
188
  function maybeLogSearchEvent(input, query, response, mode) {
183
189
  if (input.skipLogging)
184
190
  return;
@@ -327,8 +333,8 @@ function normalizeLimit(limit) {
327
333
  * - `local` (default) — search the local stash index only
328
334
  * - `registry` — search remote registries only
329
335
  * - `all` — search local and registries
330
- * - Any named source from `config.sources[].name` — filters stash results to
331
- * that single source only. The named-source path is detected and resolved
336
+ * - Any named configured bundle — filters local results to that bundle only.
337
+ * The named-source path is detected and resolved
332
338
  * inside `akmSearch`; this function returns the raw name so the caller can
333
339
  * pass it through to `akmSearch` which accepts `SearchSource | string`.
334
340
  *