akm-cli 0.7.5 → 0.8.0-rc.6

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 (236) hide show
  1. package/{.github/CHANGELOG.md → CHANGELOG.md} +113 -2
  2. package/README.md +20 -4
  3. package/SECURITY.md +93 -0
  4. package/dist/cli/config-migrate.js +144 -0
  5. package/dist/cli/config-validate.js +39 -0
  6. package/dist/cli/confirm.js +73 -0
  7. package/dist/cli/parse-args.js +133 -0
  8. package/dist/cli.js +1995 -551
  9. package/dist/commands/agent-dispatch.js +110 -0
  10. package/dist/commands/agent-support.js +68 -0
  11. package/dist/commands/completions.js +3 -0
  12. package/dist/commands/config-cli.js +130 -534
  13. package/dist/commands/consolidate.js +1531 -0
  14. package/dist/commands/curate.js +44 -3
  15. package/dist/commands/db-cli.js +23 -0
  16. package/dist/commands/distill-promotion-policy.js +660 -0
  17. package/dist/commands/distill.js +990 -75
  18. package/dist/commands/eval-cases.js +43 -0
  19. package/dist/commands/events.js +5 -23
  20. package/dist/commands/graph.js +477 -0
  21. package/dist/commands/health.js +400 -0
  22. package/dist/commands/help/help-accept.md +9 -0
  23. package/dist/commands/help/help-improve.md +77 -0
  24. package/dist/commands/help/help-proposals.md +15 -0
  25. package/dist/commands/help/help-propose.md +17 -0
  26. package/dist/commands/help/help-reject.md +8 -0
  27. package/dist/commands/history.js +54 -46
  28. package/dist/commands/improve-profiles.js +146 -0
  29. package/dist/commands/improve-result-file.js +103 -0
  30. package/dist/commands/improve.js +2175 -0
  31. package/dist/commands/info.js +5 -2
  32. package/dist/commands/init.js +50 -2
  33. package/dist/commands/installed-stashes.js +102 -139
  34. package/dist/commands/knowledge.js +136 -0
  35. package/dist/commands/lint/agent-linter.js +49 -0
  36. package/dist/commands/lint/base-linter.js +479 -0
  37. package/dist/commands/lint/command-linter.js +49 -0
  38. package/dist/commands/lint/default-linter.js +16 -0
  39. package/dist/commands/lint/index.js +183 -0
  40. package/dist/commands/lint/knowledge-linter.js +16 -0
  41. package/dist/commands/lint/markdown-insertion.js +343 -0
  42. package/dist/commands/lint/memory-linter.js +61 -0
  43. package/dist/commands/lint/registry.js +36 -0
  44. package/dist/commands/lint/skill-linter.js +45 -0
  45. package/dist/commands/lint/task-linter.js +50 -0
  46. package/dist/commands/lint/types.js +4 -0
  47. package/dist/commands/lint/vault-key-rules.js +139 -0
  48. package/dist/commands/lint/workflow-linter.js +56 -0
  49. package/dist/commands/lint.js +4 -0
  50. package/dist/commands/migration-help.js +5 -2
  51. package/dist/commands/proposal.js +66 -12
  52. package/dist/commands/propose.js +86 -31
  53. package/dist/commands/reflect.js +1119 -73
  54. package/dist/commands/registry-search.js +5 -2
  55. package/dist/commands/remember.js +69 -6
  56. package/dist/commands/schema-repair.js +203 -0
  57. package/dist/commands/search.js +115 -14
  58. package/dist/commands/self-update.js +3 -0
  59. package/dist/commands/show.js +144 -25
  60. package/dist/commands/source-add.js +17 -45
  61. package/dist/commands/source-clone.js +3 -0
  62. package/dist/commands/source-manage.js +14 -19
  63. package/dist/commands/tasks.js +438 -0
  64. package/dist/commands/url-checker.js +42 -0
  65. package/dist/commands/vault.js +130 -77
  66. package/dist/core/action-contributors.js +28 -0
  67. package/dist/core/asset-ref.js +7 -0
  68. package/dist/core/asset-registry.js +7 -16
  69. package/dist/core/asset-serialize.js +88 -0
  70. package/dist/core/asset-spec.js +22 -0
  71. package/dist/core/common.js +157 -0
  72. package/dist/core/concurrent.js +25 -0
  73. package/dist/core/config-io.js +347 -0
  74. package/dist/core/config-migration.js +625 -0
  75. package/dist/core/config-schema.js +501 -0
  76. package/dist/core/config-sources.js +108 -0
  77. package/dist/core/config-types.js +4 -0
  78. package/dist/core/config-walker.js +337 -0
  79. package/dist/core/config.js +327 -987
  80. package/dist/core/errors.js +40 -19
  81. package/dist/core/events.js +91 -138
  82. package/dist/core/file-lock.js +104 -0
  83. package/dist/core/frontmatter.js +3 -6
  84. package/dist/core/lesson-lint.js +3 -0
  85. package/dist/core/markdown.js +20 -0
  86. package/dist/core/memory-belief.js +62 -0
  87. package/dist/core/memory-contradiction-detect.js +274 -0
  88. package/dist/core/memory-improve.js +806 -0
  89. package/dist/core/parse.js +158 -0
  90. package/dist/core/paths.js +326 -14
  91. package/dist/core/proposal-quality-validators.js +364 -0
  92. package/dist/core/proposal-validators.js +69 -0
  93. package/dist/core/proposals.js +498 -42
  94. package/dist/core/state-db.js +927 -0
  95. package/dist/core/text-truncation.js +107 -0
  96. package/dist/core/time.js +54 -0
  97. package/dist/core/warn.js +62 -1
  98. package/dist/core/write-source.js +3 -0
  99. package/dist/indexer/db-backup.js +391 -0
  100. package/dist/indexer/db-search.js +152 -253
  101. package/dist/indexer/db.js +933 -103
  102. package/dist/indexer/ensure-index.js +64 -0
  103. package/dist/indexer/file-context.js +3 -0
  104. package/dist/indexer/graph-boost.js +376 -101
  105. package/dist/indexer/graph-db.js +391 -0
  106. package/dist/indexer/graph-dedup.js +95 -0
  107. package/dist/indexer/graph-extraction.js +550 -124
  108. package/dist/indexer/index-context.js +4 -0
  109. package/dist/indexer/indexer.js +506 -291
  110. package/dist/indexer/llm-cache.js +47 -0
  111. package/dist/indexer/manifest.js +3 -0
  112. package/dist/indexer/matchers.js +148 -160
  113. package/dist/indexer/memory-inference.js +99 -74
  114. package/dist/indexer/metadata-contributors.js +29 -0
  115. package/dist/indexer/metadata.js +255 -196
  116. package/dist/indexer/path-resolver.js +92 -0
  117. package/dist/indexer/project-context.js +192 -0
  118. package/dist/indexer/ranking-contributors.js +331 -0
  119. package/dist/indexer/ranking.js +81 -0
  120. package/dist/indexer/search-fields.js +5 -9
  121. package/dist/indexer/search-hit-enrichers.js +111 -0
  122. package/dist/indexer/search-source.js +44 -10
  123. package/dist/indexer/semantic-status.js +5 -16
  124. package/dist/indexer/staleness-detect.js +447 -0
  125. package/dist/indexer/usage-events.js +12 -9
  126. package/dist/indexer/walker.js +28 -0
  127. package/dist/integrations/agent/builders.js +135 -0
  128. package/dist/integrations/agent/config.js +122 -230
  129. package/dist/integrations/agent/detect.js +3 -0
  130. package/dist/integrations/agent/index.js +7 -13
  131. package/dist/integrations/agent/model-aliases.js +55 -0
  132. package/dist/integrations/agent/profiles.js +70 -5
  133. package/dist/integrations/agent/prompts.js +150 -74
  134. package/dist/integrations/agent/runner.js +151 -0
  135. package/dist/integrations/agent/sdk-runner.js +126 -0
  136. package/dist/integrations/agent/spawn.js +118 -23
  137. package/dist/integrations/github.js +3 -0
  138. package/dist/integrations/lockfile.js +32 -69
  139. package/dist/integrations/session-logs/index.js +68 -0
  140. package/dist/integrations/session-logs/providers/claude-code.js +59 -0
  141. package/dist/integrations/session-logs/providers/opencode.js +55 -0
  142. package/dist/integrations/session-logs/types.js +4 -0
  143. package/dist/llm/call-ai.js +62 -0
  144. package/dist/llm/client.js +72 -124
  145. package/dist/llm/embedder.js +3 -19
  146. package/dist/llm/embedders/cache.js +3 -7
  147. package/dist/llm/embedders/local.js +3 -0
  148. package/dist/llm/embedders/remote.js +20 -8
  149. package/dist/llm/embedders/types.js +3 -7
  150. package/dist/llm/feature-gate.js +89 -48
  151. package/dist/llm/graph-extract.js +676 -70
  152. package/dist/llm/index-passes.js +9 -23
  153. package/dist/llm/memory-infer.js +52 -71
  154. package/dist/llm/metadata-enhance.js +42 -29
  155. package/dist/llm/prompts/graph-extract-user-prompt.md +35 -0
  156. package/dist/output/cli-hints-full.md +281 -0
  157. package/dist/output/cli-hints-short.md +65 -0
  158. package/dist/output/cli-hints.js +5 -318
  159. package/dist/output/context.js +3 -0
  160. package/dist/output/renderers.js +223 -256
  161. package/dist/output/shapes.js +150 -105
  162. package/dist/output/text.js +318 -30
  163. package/dist/registry/build-index.js +3 -0
  164. package/dist/registry/create-provider-registry.js +3 -0
  165. package/dist/registry/factory.js +3 -0
  166. package/dist/registry/origin-resolve.js +3 -0
  167. package/dist/registry/providers/index.js +3 -0
  168. package/dist/registry/providers/skills-sh.js +70 -49
  169. package/dist/registry/providers/static-index.js +53 -48
  170. package/dist/registry/providers/types.js +3 -24
  171. package/dist/registry/resolve.js +11 -16
  172. package/dist/registry/types.js +3 -0
  173. package/dist/scripts/migrate-storage.js +17307 -0
  174. package/dist/scripts/migrations/import-fs-improve-runs-to-db.js +8900 -0
  175. package/dist/scripts/migrations/v16-to-v17.js +141 -0
  176. package/dist/setup/detect.js +3 -0
  177. package/dist/setup/ripgrep-install.js +3 -0
  178. package/dist/setup/ripgrep-resolve.js +3 -0
  179. package/dist/setup/setup.js +775 -37
  180. package/dist/setup/steps.js +3 -15
  181. package/dist/sources/include.js +3 -0
  182. package/dist/sources/provider-factory.js +5 -12
  183. package/dist/sources/provider.js +3 -20
  184. package/dist/sources/providers/filesystem.js +19 -23
  185. package/dist/sources/providers/git.js +7 -5
  186. package/dist/sources/providers/index.js +3 -0
  187. package/dist/sources/providers/install-types.js +3 -13
  188. package/dist/sources/providers/npm.js +3 -4
  189. package/dist/sources/providers/provider-utils.js +3 -0
  190. package/dist/sources/providers/sync-from-ref.js +3 -11
  191. package/dist/sources/providers/tar-utils.js +3 -0
  192. package/dist/sources/providers/website.js +18 -22
  193. package/dist/sources/resolve.js +3 -0
  194. package/dist/sources/types.js +3 -0
  195. package/dist/sources/website-ingest.js +7 -0
  196. package/dist/tasks/backends/cron.js +203 -0
  197. package/dist/tasks/backends/exec-utils.js +28 -0
  198. package/dist/tasks/backends/index.js +24 -0
  199. package/dist/tasks/backends/launchd-template.xml +19 -0
  200. package/dist/tasks/backends/launchd.js +187 -0
  201. package/dist/tasks/backends/schtasks-template.xml +29 -0
  202. package/dist/tasks/backends/schtasks.js +215 -0
  203. package/dist/tasks/parser.js +211 -0
  204. package/dist/tasks/resolveAkmBin.js +87 -0
  205. package/dist/tasks/runner.js +458 -0
  206. package/dist/tasks/schedule.js +211 -0
  207. package/dist/tasks/schema.js +15 -0
  208. package/dist/tasks/validator.js +62 -0
  209. package/dist/version.js +3 -0
  210. package/dist/wiki/index-template.md +12 -0
  211. package/dist/wiki/ingest-workflow-template.md +54 -0
  212. package/dist/wiki/log-template.md +8 -0
  213. package/dist/wiki/schema-template.md +61 -0
  214. package/dist/wiki/wiki-templates.js +15 -0
  215. package/dist/wiki/wiki.js +13 -61
  216. package/dist/workflows/authoring.js +8 -25
  217. package/dist/workflows/cli.js +3 -0
  218. package/dist/workflows/db.js +140 -10
  219. package/dist/workflows/document-cache.js +3 -10
  220. package/dist/workflows/parser.js +3 -0
  221. package/dist/workflows/renderer.js +11 -3
  222. package/dist/workflows/runs.js +62 -91
  223. package/dist/workflows/schema.js +3 -0
  224. package/dist/workflows/scope-key.js +3 -0
  225. package/dist/workflows/validator.js +4 -8
  226. package/dist/workflows/workflow-template.md +24 -0
  227. package/docs/README.md +9 -2
  228. package/docs/data-and-telemetry.md +225 -0
  229. package/docs/migration/release-notes/0.7.0.md +1 -1
  230. package/docs/migration/release-notes/0.7.5.md +2 -2
  231. package/docs/migration/release-notes/0.8.0.md +48 -0
  232. package/docs/migration/v0.7-to-v0.8.md +1307 -0
  233. package/package.json +20 -8
  234. package/.github/LICENSE +0 -374
  235. package/dist/commands/install-audit.js +0 -381
  236. package/dist/templates/wiki-templates.js +0 -100
@@ -1,11 +1,75 @@
1
- /**
2
- * Pure shaping functions that select and trim fields from command result
3
- * objects according to the active detail level / agent mode.
4
- *
5
- * Every function in this module is side-effect free and operates on plain
6
- * `Record<string, unknown>` shapes, which makes them trivial to unit test.
7
- */
1
+ // This Source Code Form is subject to the terms of the Mozilla Public
2
+ // License, v. 2.0. If a copy of the MPL was not distributed with this
3
+ // file, You can obtain one at https://mozilla.org/MPL/2.0/.
8
4
  const NORMAL_DESCRIPTION_LIMIT = 250;
5
+ const PASSTHROUGH_COMMANDS = new Set([
6
+ "add",
7
+ "agent-result",
8
+ "clone",
9
+ "config",
10
+ "consolidate",
11
+ "curate",
12
+ "db-backups",
13
+ "disable",
14
+ "enable",
15
+ "feedback",
16
+ "graph-entities",
17
+ "graph-entity",
18
+ "graph-export",
19
+ "graph-orphans",
20
+ "graph-related",
21
+ "graph-relations",
22
+ "graph-summary",
23
+ "health",
24
+ "import",
25
+ "improve",
26
+ "index",
27
+ "info",
28
+ "init",
29
+ "lessons-coverage",
30
+ "lint",
31
+ "list",
32
+ "registry-add",
33
+ "registry-build-index",
34
+ "registry-list",
35
+ "registry-remove",
36
+ "remember",
37
+ "remove",
38
+ "save",
39
+ "setup",
40
+ "tasks-add",
41
+ "tasks-disable",
42
+ "tasks-doctor",
43
+ "tasks-enable",
44
+ "tasks-history",
45
+ "tasks-list",
46
+ "tasks-remove",
47
+ "tasks-run",
48
+ "tasks-show",
49
+ "tasks-sync",
50
+ "update",
51
+ "upgrade",
52
+ "vault-create",
53
+ "vault-set",
54
+ "vault-unset",
55
+ "wiki-create",
56
+ "wiki-ingest",
57
+ "wiki-lint",
58
+ "wiki-list",
59
+ "wiki-pages",
60
+ "wiki-register",
61
+ "wiki-remove",
62
+ "wiki-show",
63
+ "wiki-stash",
64
+ "workflow-complete",
65
+ "workflow-create",
66
+ "workflow-list",
67
+ "workflow-next",
68
+ "workflow-resume",
69
+ "workflow-start",
70
+ "workflow-status",
71
+ "workflow-validate",
72
+ ]);
9
73
  export function shapeForCommand(command, result, detail, forAgent = false) {
10
74
  switch (command) {
11
75
  case "search":
@@ -39,72 +103,40 @@ export function shapeForCommand(command, result, detail, forAgent = false) {
39
103
  return shapeProposalRejectOutput(result, detail);
40
104
  case "proposal-diff":
41
105
  return shapeProposalDiffOutput(result, detail);
106
+ // Phase 6C (Advantage D6c): revert envelope mirrors accept/reject.
107
+ case "proposal-revert":
108
+ return shapeProposalRevertOutput(result, detail);
42
109
  // Output shape registration for `akm reflect` and `akm propose` (#226).
43
110
  // Both share the proposal-producer envelope shape (success carries a
44
111
  // proposal entry; failure carries an AgentFailureReason discriminant).
45
112
  case "reflect":
46
113
  case "propose":
47
114
  return shapeProposalProducerOutput(result, detail);
48
- // Output shape registration for `akm distill <ref>` (#228). The shape is
49
- // simple — outcome + ids + optional payload — so `brief` strips the full
50
- // proposal blob, `normal` keeps the headline fields, and `full` projects
51
- // everything for downstream automation.
52
115
  case "distill":
53
116
  return shapeDistillOutput(result, detail);
54
- // Identity-passthrough commands — registered here so the registry stays
55
- // exhaustive (v1 spec §9). Each result object is already shaped at the
56
- // command boundary; the registry just confirms there's no surprise
57
- // command name slipping through.
58
- case "add":
59
- case "clone":
60
- case "config":
61
- case "curate":
62
- case "disable":
63
- case "enable":
64
- case "feedback":
65
- case "import":
66
- case "index":
67
- case "info":
68
- case "init":
69
- case "list":
70
- case "registry-add":
71
- case "registry-build-index":
72
- case "registry-list":
73
- case "registry-remove":
74
- case "remember":
75
- case "remove":
76
- case "save":
77
- case "update":
78
- case "upgrade":
79
- case "vault-create":
80
- case "vault-list":
81
- case "vault-set":
82
- case "vault-unset":
83
- case "wiki-create":
84
- case "wiki-ingest":
85
- case "wiki-lint":
86
- case "wiki-list":
87
- case "wiki-pages":
88
- case "wiki-register":
89
- case "wiki-remove":
90
- case "wiki-show":
91
- case "wiki-stash":
92
- case "workflow-complete":
93
- case "workflow-create":
94
- case "workflow-list":
95
- case "workflow-next":
96
- case "workflow-resume":
97
- case "workflow-start":
98
- case "workflow-status":
99
- case "workflow-validate":
100
- return result;
117
+ case "vault-list": {
118
+ const r = result;
119
+ const vaults = Array.isArray(r.vaults) ? r.vaults : [];
120
+ return {
121
+ ...r,
122
+ vaults: vaults.map((v) => {
123
+ const { path: _path, ...rest } = v;
124
+ return rest;
125
+ }),
126
+ };
127
+ }
101
128
  default:
102
- // v1 spec §9 (output-shape registry exhaustive): no silent JSON.stringify
103
- // fallback. A missing case here is a registration bug — fail loudly so
104
- // the caller (or its tests) sees the missing command name.
129
+ // v1 spec §9 (output-shape registry exhaustive): identity-passthrough
130
+ // commands are listed in PASSTHROUGH_COMMANDS; anything not in that set
131
+ // is a registration bug fail loudly.
132
+ if (PASSTHROUGH_COMMANDS.has(command))
133
+ return result;
105
134
  throw new Error(`output shape not registered for command: ${command}`);
106
135
  }
107
136
  }
137
+ function maybeAddSchema(base, detail, version) {
138
+ return detail === "full" ? { schemaVersion: version ?? 1, ...base } : base;
139
+ }
108
140
  /**
109
141
  * Shape the result of `akm reflect` / `akm propose`. On success we surface
110
142
  * the queued proposal entry (using the standard proposal-entry shaper so
@@ -141,17 +173,27 @@ export function shapeProposalProducerOutput(result, detail) {
141
173
  ...(typeof result.durationMs === "number" ? { durationMs: result.durationMs } : {}),
142
174
  proposal: shapeProposalEntry(proposal, detail === "brief" ? "normal" : detail),
143
175
  };
144
- if (detail === "full") {
145
- return { schemaVersion: result.schemaVersion ?? 1, ...base };
146
- }
147
- return base;
176
+ return maybeAddSchema(base, detail, result.schemaVersion);
148
177
  }
149
178
  export function shapeProposalEntry(entry, detail) {
150
179
  if (detail === "brief") {
151
- return pickFields(entry, ["id", "ref", "status", "source", "createdAt"]);
180
+ // Phase 6A: confidence is small + load-bearing for auto-accept telemetry,
181
+ // so include it even at brief detail.
182
+ return pickFields(entry, ["id", "ref", "status", "source", "createdAt", "confidence"]);
152
183
  }
153
184
  if (detail === "normal" || detail === "summary") {
154
- return pickFields(entry, ["id", "ref", "status", "source", "sourceRun", "createdAt", "updatedAt", "review"]);
185
+ return pickFields(entry, [
186
+ "id",
187
+ "ref",
188
+ "status",
189
+ "source",
190
+ "sourceRun",
191
+ "createdAt",
192
+ "updatedAt",
193
+ "review",
194
+ "confidence",
195
+ "backup",
196
+ ]);
155
197
  }
156
198
  // full / agent: project everything including the payload.
157
199
  return pickFields(entry, [
@@ -164,6 +206,8 @@ export function shapeProposalEntry(entry, detail) {
164
206
  "updatedAt",
165
207
  "payload",
166
208
  "review",
209
+ "confidence",
210
+ "backup",
167
211
  ]);
168
212
  }
169
213
  export function shapeProposalListOutput(result, detail) {
@@ -173,10 +217,7 @@ export function shapeProposalListOutput(result, detail) {
173
217
  totalCount: result.totalCount ?? shaped.length,
174
218
  proposals: shaped,
175
219
  };
176
- if (detail === "full") {
177
- return { schemaVersion: result.schemaVersion ?? 1, ...base };
178
- }
179
- return base;
220
+ return maybeAddSchema(base, detail, result.schemaVersion);
180
221
  }
181
222
  export function shapeProposalShowOutput(result, detail) {
182
223
  const proposal = result.proposal ?? {};
@@ -185,10 +226,7 @@ export function shapeProposalShowOutput(result, detail) {
185
226
  proposal: shapeProposalEntry(proposal, detail === "brief" ? "normal" : detail),
186
227
  ...(validation ? { validation } : {}),
187
228
  };
188
- if (detail === "full") {
189
- return { schemaVersion: result.schemaVersion ?? 1, ...base };
190
- }
191
- return base;
229
+ return maybeAddSchema(base, detail, result.schemaVersion);
192
230
  }
193
231
  export function shapeProposalAcceptOutput(result, detail) {
194
232
  const proposal = result.proposal ?? {};
@@ -199,10 +237,7 @@ export function shapeProposalAcceptOutput(result, detail) {
199
237
  assetPath: result.assetPath,
200
238
  proposal: shapeProposalEntry(proposal, detail === "brief" ? "normal" : detail),
201
239
  };
202
- if (detail === "full") {
203
- return { schemaVersion: result.schemaVersion ?? 1, ...base };
204
- }
205
- return base;
240
+ return maybeAddSchema(base, detail, result.schemaVersion);
206
241
  }
207
242
  export function shapeProposalRejectOutput(result, detail) {
208
243
  const proposal = result.proposal ?? {};
@@ -213,10 +248,26 @@ export function shapeProposalRejectOutput(result, detail) {
213
248
  ...(result.reason !== undefined ? { reason: result.reason } : {}),
214
249
  proposal: shapeProposalEntry(proposal, detail === "brief" ? "normal" : detail),
215
250
  };
216
- if (detail === "full") {
217
- return { schemaVersion: result.schemaVersion ?? 1, ...base };
218
- }
219
- return base;
251
+ return maybeAddSchema(base, detail, result.schemaVersion);
252
+ }
253
+ /**
254
+ * Shape the result of `akm proposal revert <id>` (Phase 6C / Advantage D6c).
255
+ *
256
+ * Mirrors {@link shapeProposalAcceptOutput} — the surface is intentionally
257
+ * symmetric with accept because the user-visible workflow is: accept restores
258
+ * the new content; revert restores the prior content; both should look the
259
+ * same in JSON output beyond the verb.
260
+ */
261
+ export function shapeProposalRevertOutput(result, detail) {
262
+ const proposal = result.proposal ?? {};
263
+ const base = {
264
+ ok: result.ok ?? true,
265
+ id: result.id,
266
+ ref: result.ref,
267
+ assetPath: result.assetPath,
268
+ proposal: shapeProposalEntry(proposal, detail === "brief" ? "normal" : detail),
269
+ };
270
+ return maybeAddSchema(base, detail, result.schemaVersion);
220
271
  }
221
272
  export function shapeDistillOutput(result, detail) {
222
273
  const proposal = result.proposal;
@@ -233,10 +284,7 @@ export function shapeDistillOutput(result, detail) {
233
284
  ...(Array.isArray(result.findings) && result.findings.length > 0 ? { findings: result.findings } : {}),
234
285
  ...(proposal ? { proposal: shapeProposalEntry(proposal, detail === "summary" ? "normal" : detail) } : {}),
235
286
  };
236
- if (detail === "full") {
237
- return { schemaVersion: result.schemaVersion ?? 1, ...base };
238
- }
239
- return base;
287
+ return maybeAddSchema(base, detail, result.schemaVersion);
240
288
  }
241
289
  export function shapeProposalDiffOutput(result, detail) {
242
290
  const base = {
@@ -246,10 +294,7 @@ export function shapeProposalDiffOutput(result, detail) {
246
294
  unified: result.unified,
247
295
  ...(result.targetPath !== undefined ? { targetPath: result.targetPath } : {}),
248
296
  };
249
- if (detail === "full") {
250
- return { schemaVersion: result.schemaVersion ?? 1, ...base };
251
- }
252
- return base;
297
+ return maybeAddSchema(base, detail, result.schemaVersion);
253
298
  }
254
299
  export function shapeEventsOutput(result, detail) {
255
300
  const events = Array.isArray(result.events) ? result.events : [];
@@ -268,16 +313,10 @@ export function shapeEventsOutput(result, detail) {
268
313
  if (typeof result.reason === "string") {
269
314
  base.reason = result.reason;
270
315
  }
271
- if (detail === "full") {
272
- return { schemaVersion: result.schemaVersion ?? 1, ...base };
273
- }
274
- return base;
316
+ return maybeAddSchema(base, detail, result.schemaVersion);
275
317
  }
276
318
  export function shapeEventEntry(entry, detail) {
277
- if (detail === "brief") {
278
- return pickFields(entry, ["eventType", "ref", "ts"]);
279
- }
280
- if (detail === "normal" || detail === "summary") {
319
+ if (detail === "brief" || detail === "normal" || detail === "summary") {
281
320
  return pickFields(entry, ["eventType", "ref", "ts"]);
282
321
  }
283
322
  // full / agent: project everything the reader emits.
@@ -313,13 +352,13 @@ export function shapeHistoryEntry(entry, detail) {
313
352
  if (detail === "brief") {
314
353
  // signal is load-bearing for feedback rows (positive/negative) so we
315
354
  // project it even at brief — without it the entry is ambiguous.
316
- return pickFields(entry, ["eventType", "ref", "signal", "createdAt"]);
355
+ return pickFields(entry, ["eventType", "ref", "signal", "source", "createdAt"]);
317
356
  }
318
357
  if (detail === "normal" || detail === "summary") {
319
- return pickFields(entry, ["eventType", "ref", "signal", "query", "createdAt"]);
358
+ return pickFields(entry, ["eventType", "ref", "signal", "query", "source", "createdAt"]);
320
359
  }
321
360
  // full / agent: return everything the reader emits.
322
- return pickFields(entry, ["id", "eventType", "ref", "entryId", "query", "signal", "metadata", "createdAt"]);
361
+ return pickFields(entry, ["id", "eventType", "ref", "entryId", "query", "signal", "source", "metadata", "createdAt"]);
323
362
  }
324
363
  export function shapeSearchOutput(result, detail, forAgent = false) {
325
364
  const hits = Array.isArray(result.hits) ? result.hits : [];
@@ -462,6 +501,7 @@ export function shapeShowOutput(result, detail, forAgent = false) {
462
501
  "steps",
463
502
  "keys",
464
503
  "comments",
504
+ "related",
465
505
  ]);
466
506
  }
467
507
  if (detail === "summary") {
@@ -477,9 +517,10 @@ export function shapeShowOutput(result, detail, forAgent = false) {
477
517
  "origin",
478
518
  "keys",
479
519
  "comments",
520
+ "related",
480
521
  ]);
481
522
  }
482
- const base = pickFields(result, [
523
+ const baseFields = [
483
524
  "type",
484
525
  "name",
485
526
  "origin",
@@ -502,11 +543,15 @@ export function shapeShowOutput(result, detail, forAgent = false) {
502
543
  "activeRun",
503
544
  "keys",
504
545
  "comments",
546
+ "related",
505
547
  // path and editable are always projected so JSON consumers can locate and
506
548
  // edit the asset without needing --detail full (QA #7).
507
- "path",
549
+ // Exception: vault assets omit path to avoid leaking absolute disk paths
550
+ // into structured JSON output (security fix M3).
551
+ ...(result.type === "vault" ? [] : ["path"]),
508
552
  "editable",
509
- ]);
553
+ ];
554
+ const base = pickFields(result, baseFields);
510
555
  if (detail !== "full") {
511
556
  return base;
512
557
  }