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,6 @@
1
- /**
2
- * Plain-text formatters for command output. Each top-level `formatPlain`
3
- * branch dispatches to a small per-command helper. Returning `null` means
4
- * "no plain rendering available — fall back to YAML".
5
- *
6
- * Pure functions — no IO.
7
- */
8
- import { formatInstallAuditSummary } from "../commands/install-audit";
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/.
9
4
  export function outputJsonl(command, shaped) {
10
5
  if (command === "search" || command === "registry-search") {
11
6
  const r = shaped;
@@ -38,6 +33,13 @@ export function formatPlain(command, result, detail) {
38
33
  case "index": {
39
34
  const indexResult = result;
40
35
  let out = `Indexed ${indexResult.totalEntries ?? 0} entries from ${indexResult.directoriesScanned ?? 0} directories (mode: ${indexResult.mode ?? "unknown"})`;
36
+ const graphQuality = indexResult.graphQuality;
37
+ if (graphQuality) {
38
+ const coverage = typeof graphQuality.extractionCoverage === "number"
39
+ ? `${Math.round(graphQuality.extractionCoverage * 100)}%`
40
+ : "n/a";
41
+ out += `\nGraph quality: entities ${graphQuality.entityCount ?? 0}, relations ${graphQuality.relationCount ?? 0}, coverage ${coverage}, density ${graphQuality.density ?? 0}`;
42
+ }
41
43
  const warnings = indexResult.warnings;
42
44
  if (Array.isArray(warnings) && warnings.length > 0) {
43
45
  out += `\nWarnings (${warnings.length}):`;
@@ -135,11 +137,6 @@ export function formatPlain(command, result, detail) {
135
137
  for (const message of warnings)
136
138
  lines.push(` - ${String(message)}`);
137
139
  }
138
- const installed = r.installed;
139
- const audit = installed?.audit;
140
- if (audit && typeof audit === "object") {
141
- lines.push(formatInstallAuditSummary(audit));
142
- }
143
140
  return lines.join("\n");
144
141
  }
145
142
  case "remove": {
@@ -211,6 +208,9 @@ export function formatPlain(command, result, detail) {
211
208
  case "proposal-diff": {
212
209
  return formatProposalDiffPlain(r);
213
210
  }
211
+ case "proposal-revert": {
212
+ return formatProposalRevertPlain(r);
213
+ }
214
214
  // Output shape registration for `akm reflect` / `akm propose` (#226).
215
215
  case "reflect":
216
216
  case "propose": {
@@ -221,6 +221,35 @@ export function formatPlain(command, result, detail) {
221
221
  case "distill": {
222
222
  return formatDistillPlain(r);
223
223
  }
224
+ case "graph-summary":
225
+ return formatGraphSummaryPlain(r);
226
+ case "graph-entities":
227
+ return formatGraphEntitiesPlain(r);
228
+ case "graph-entity":
229
+ return formatGraphEntityPlain(r);
230
+ case "graph-relations":
231
+ return formatGraphRelationsPlain(r);
232
+ case "graph-related":
233
+ return formatGraphRelatedPlain(r);
234
+ case "graph-orphans":
235
+ return formatGraphOrphansPlain(r);
236
+ case "graph-export":
237
+ return formatGraphExportPlain(r);
238
+ case "improve": {
239
+ return formatImprovePlain(r);
240
+ }
241
+ case "consolidate": {
242
+ return formatConsolidatePlain(r);
243
+ }
244
+ // Output shape registration for `akm agent <profile>` (#agent-dispatch).
245
+ // In interactive mode stdout/stderr are empty (they went to the TTY), so
246
+ // we print only the profile name and exit status. In captured mode we
247
+ // emit stdout first, then stderr, then the exit code summary.
248
+ case "agent-result": {
249
+ return formatAgentResultPlain(r);
250
+ }
251
+ case "health":
252
+ return formatHealthPlain(r);
224
253
  case "info":
225
254
  return formatInfoPlain(r);
226
255
  case "config":
@@ -249,7 +278,7 @@ export function formatPlain(command, result, detail) {
249
278
  case "vault-list":
250
279
  return formatVaultListPlain(r);
251
280
  case "vault-create":
252
- return `Created vault ${String(r.ref ?? "?")} at ${String(r.path ?? "?")}`;
281
+ return `Created vault ${String(r.ref ?? "?")}`;
253
282
  case "vault-set":
254
283
  return `Set ${String(r.key ?? "?")} in ${String(r.ref ?? "?")} (value not displayed)`;
255
284
  case "vault-unset": {
@@ -299,6 +328,50 @@ export function formatInfoPlain(r) {
299
328
  return JSON.stringify(r, null, 2);
300
329
  return lines.join("\n");
301
330
  }
331
+ export function formatHealthPlain(r) {
332
+ const lines = [];
333
+ lines.push(`health: ${String(r.status ?? "unknown")}`);
334
+ if (typeof r.since === "string")
335
+ lines.push(`since: ${r.since}`);
336
+ const metrics = typeof r.metrics === "object" && r.metrics !== null ? r.metrics : undefined;
337
+ if (metrics) {
338
+ lines.push("metrics:");
339
+ lines.push(` taskFailRate: ${String(metrics.taskFailRate ?? 0)}`);
340
+ lines.push(` agentFailureRate: ${String(metrics.agentFailureRate ?? 0)}`);
341
+ lines.push(` stuckActiveRuns: ${String(metrics.stuckActiveRuns ?? 0)}`);
342
+ lines.push(` logBackingRate: ${String(metrics.logBackingRate ?? 0)}`);
343
+ lines.push(` probeRoundTripMs: ${String(metrics.probeRoundTripMs ?? "null")}`);
344
+ }
345
+ const improve = typeof r.improve === "object" && r.improve !== null ? r.improve : undefined;
346
+ if (improve) {
347
+ const actions = typeof improve.actions === "object" && improve.actions !== null
348
+ ? improve.actions
349
+ : {};
350
+ lines.push("improve:");
351
+ lines.push(` invoked: ${String(improve.invoked ?? 0)}`);
352
+ lines.push(` completed: ${String(improve.completed ?? 0)}`);
353
+ lines.push(` skipped: ${String(improve.skipped ?? 0)}`);
354
+ lines.push(` plannedRefs: ${String(improve.plannedRefs ?? 0)}`);
355
+ lines.push(` actions: reflect=${String(actions.reflect ?? 0)} distill=${String(actions.distill ?? 0)} distillSkipped=${String(actions.distillSkipped ?? 0)} memoryPrune=${String(actions.memoryPrune ?? 0)} memoryInference=${String(actions.memoryInference ?? 0)} graphExtraction=${String(actions.graphExtraction ?? 0)} error=${String(actions.error ?? 0)}`);
356
+ lines.push(` coverageGapCount: ${String(improve.coverageGapCount ?? 0)}`);
357
+ lines.push(` executionLogCandidateCount: ${String(improve.executionLogCandidateCount ?? 0)}`);
358
+ lines.push(` deadUrlCount: ${String(improve.deadUrlCount ?? 0)}`);
359
+ }
360
+ const sections = [
361
+ ["hardChecks", r.hardChecks],
362
+ ["advisories", r.advisories],
363
+ ];
364
+ for (const [label, value] of sections) {
365
+ const checks = Array.isArray(value) ? value : [];
366
+ if (checks.length === 0)
367
+ continue;
368
+ lines.push(`${label}:`);
369
+ for (const check of checks) {
370
+ lines.push(` - [${String(check.status ?? "unknown")}] ${String(check.name ?? "check")}: ${String(check.message ?? "")}`);
371
+ }
372
+ }
373
+ return lines.join("\n");
374
+ }
302
375
  export function formatConfigPlain(r) {
303
376
  // Recursive flattener: prints `key=value` lines, and nested objects as
304
377
  // `parent.child=value`. Arrays render as JSON for compactness.
@@ -440,6 +513,96 @@ export function formatWorkflowValidatePlain(r) {
440
513
  const stepCount = typeof r.stepCount === "number" ? r.stepCount : 0;
441
514
  return `workflow validate: ok — ${title || pathValue} (${stepCount} step(s))`;
442
515
  }
516
+ export function formatGraphSummaryPlain(r) {
517
+ const lines = [
518
+ `Graph: ${String(r.graphPath ?? "?")}`,
519
+ `Generated: ${String(r.generatedAt ?? "?")}`,
520
+ `Files: ${String(r.fileCount ?? 0)} Entities: ${String(r.entityCount ?? 0)} Relations: ${String(r.relationCount ?? 0)}`,
521
+ ];
522
+ const quality = r.quality;
523
+ if (quality) {
524
+ const coverage = typeof quality.extractionCoverage === "number" ? `${Math.round(quality.extractionCoverage * 100)}%` : "n/a";
525
+ lines.push(`Coverage: ${coverage} Density: ${String(quality.density ?? 0)}`);
526
+ }
527
+ return lines.join("\n");
528
+ }
529
+ function formatConfidenceSuffix(value) {
530
+ if (typeof value !== "number" || !Number.isFinite(value) || value <= 0)
531
+ return "";
532
+ return ` (conf ${value.toFixed(2)})`;
533
+ }
534
+ export function formatGraphEntitiesPlain(r) {
535
+ const entities = Array.isArray(r.entities) ? r.entities : [];
536
+ if (entities.length === 0)
537
+ return "No entities found in graph.";
538
+ const lines = [`Entities (${String(r.total ?? entities.length)} total):`];
539
+ for (const entity of entities) {
540
+ const conf = formatConfidenceSuffix(entity.confidence);
541
+ lines.push(`- ${String(entity.name ?? "?")} (${String(entity.fileCount ?? 0)} files)${conf}`);
542
+ }
543
+ return lines.join("\n");
544
+ }
545
+ export function formatGraphRelationsPlain(r) {
546
+ const relations = Array.isArray(r.relations) ? r.relations : [];
547
+ if (relations.length === 0)
548
+ return "No relations found in graph.";
549
+ const lines = [`Relations (${String(r.total ?? relations.length)} total):`];
550
+ for (const relation of relations) {
551
+ const type = relation.type ? ` [${String(relation.type)}]` : "";
552
+ const conf = formatConfidenceSuffix(relation.confidence);
553
+ lines.push(`- ${String(relation.from ?? "?")} -> ${String(relation.to ?? "?")}${type} x${String(relation.count ?? 0)}${conf}`);
554
+ }
555
+ return lines.join("\n");
556
+ }
557
+ export function formatGraphEntityPlain(r) {
558
+ const matches = Array.isArray(r.matches) ? r.matches : [];
559
+ if (matches.length === 0)
560
+ return `No assets contain entity ${String(r.entity ?? "?")}.`;
561
+ const lines = [`Assets containing entity ${String(r.entity ?? "?")} (${String(r.total ?? matches.length)} total):`];
562
+ for (const match of matches) {
563
+ const label = typeof match.ref === "string" && match.ref ? match.ref : String(match.path ?? "?");
564
+ const conf = formatConfidenceSuffix(match.confidence);
565
+ lines.push(`- ${String(match.type ?? "?")}: ${label}${conf}`);
566
+ }
567
+ return lines.join("\n");
568
+ }
569
+ export function formatGraphOrphansPlain(r) {
570
+ const orphans = Array.isArray(r.orphans) ? r.orphans : [];
571
+ const considered = String(r.totalConsidered ?? "?");
572
+ if (orphans.length === 0) {
573
+ return `No orphan assets (0 of ${considered} have zero extracted entities).`;
574
+ }
575
+ const lines = [`Orphans (${String(r.total ?? orphans.length)} of ${considered} considered):`];
576
+ for (const orphan of orphans) {
577
+ const label = typeof orphan.ref === "string" && orphan.ref ? orphan.ref : String(orphan.path ?? "?");
578
+ lines.push(`- ${String(orphan.type ?? "?")}: ${label}`);
579
+ }
580
+ return lines.join("\n");
581
+ }
582
+ export function formatGraphRelatedPlain(r) {
583
+ const related = Array.isArray(r.related) ? r.related : [];
584
+ if (related.length === 0)
585
+ return String(r.tip ?? "No related graph neighbors were found.");
586
+ const lines = [`Related (${String(r.total ?? related.length)} total) for ${String(r.ref ?? "?")}:`];
587
+ for (const hit of related) {
588
+ const shared = Array.isArray(hit.sharedEntities) ? hit.sharedEntities.map(String).join(", ") : "";
589
+ lines.push(`- ${String(hit.type ?? "?")}: ${formatRelatedLabel(hit)}`);
590
+ if (shared)
591
+ lines.push(` shared: ${shared}`);
592
+ lines.push(` relationCount: ${String(hit.relationCount ?? 0)}`);
593
+ }
594
+ const topHit = related[0];
595
+ if (topHit) {
596
+ const target = typeof topHit.ref === "string" && topHit.ref ? topHit.ref : formatRelatedLabel(topHit);
597
+ if (target && target !== "?") {
598
+ lines.push(`Next: akm show '${target}'`);
599
+ }
600
+ }
601
+ return lines.join("\n");
602
+ }
603
+ export function formatGraphExportPlain(r) {
604
+ return `Exported graph (${String(r.format ?? "json")}, ${String(r.bytes ?? 0)} bytes) to ${String(r.outPath ?? "?")}`;
605
+ }
443
606
  export function formatProposalProducerPlain(command, r) {
444
607
  if (r.ok === false) {
445
608
  const reason = String(r.reason ?? "unknown");
@@ -464,7 +627,7 @@ export function formatProposalListPlain(r) {
464
627
  const proposals = Array.isArray(r.proposals) ? r.proposals : [];
465
628
  const total = typeof r.totalCount === "number" ? r.totalCount : proposals.length;
466
629
  if (proposals.length === 0) {
467
- return `${total} proposal(s).\nNo proposals.\nGenerate one with \`akm reflect <ref>\`, \`akm propose <type> <name> --task ...\`, or \`akm distill <ref>\`.`;
630
+ return `${total} proposal(s).\nNo proposals.\nGenerate one with \`akm improve\`, \`akm propose <type> <name> --task ...\`, or \`akm improve <ref>\`.`;
468
631
  }
469
632
  const lines = [`${total} proposal(s)`, ""];
470
633
  for (const p of proposals) {
@@ -490,6 +653,11 @@ export function formatProposalShowPlain(r) {
490
653
  lines.push(`createdAt: ${String(p.createdAt)}`);
491
654
  if (p.updatedAt)
492
655
  lines.push(`updatedAt: ${String(p.updatedAt)}`);
656
+ // Phase 6A / 6C: surface confidence and backup metadata.
657
+ if (typeof p.confidence === "number")
658
+ lines.push(`confidence: ${p.confidence.toFixed(2)}`);
659
+ if (typeof p.backup === "string" && p.backup.length > 0)
660
+ lines.push(`backup: ${String(p.backup)}`);
493
661
  const review = p.review;
494
662
  if (review) {
495
663
  lines.push(`review.outcome: ${String(review.outcome ?? "?")}`);
@@ -523,13 +691,18 @@ export function formatProposalRejectPlain(r) {
523
691
  const reason = r.reason ? ` (${String(r.reason)})` : "";
524
692
  return `Rejected proposal ${String(r.id ?? "?")} (${String(r.ref ?? "?")})${reason}`;
525
693
  }
694
+ export function formatProposalRevertPlain(r) {
695
+ // Phase 6C: mirror the accept-plain text — the user-facing message focuses
696
+ // on the destination path because that's what they need to verify.
697
+ return `Reverted proposal ${String(r.id ?? "?")} → restored prior content of ${String(r.ref ?? "?")} at ${String(r.assetPath ?? "?")}`;
698
+ }
526
699
  export function formatDistillPlain(r) {
527
700
  const outcome = String(r.outcome ?? "unknown");
528
701
  const inputRef = String(r.inputRef ?? "?");
529
702
  const lessonRef = String(r.lessonRef ?? "?");
530
703
  if (outcome === "queued") {
531
704
  const id = String(r.proposalId ?? "?");
532
- return `Distilled ${inputRef} → proposal ${id} (${lessonRef}). Run \`akm proposal show ${id}\` to review.`;
705
+ return `Distilled ${inputRef} → proposal ${id} (${lessonRef}). Run \`akm show proposal ${id}\` to review.`;
533
706
  }
534
707
  if (outcome === "validation_failed") {
535
708
  const findings = Array.isArray(r.findings) ? r.findings : [];
@@ -543,6 +716,50 @@ export function formatDistillPlain(r) {
543
716
  const message = typeof r.message === "string" ? r.message : "feature disabled or LLM unavailable";
544
717
  return `Distill skipped for ${inputRef}: ${message}`;
545
718
  }
719
+ export function formatConsolidatePlain(r) {
720
+ const processed = typeof r.processed === "number" ? r.processed : 0;
721
+ const merged = typeof r.merged === "number" ? r.merged : 0;
722
+ const deleted = typeof r.deleted === "number" ? r.deleted : 0;
723
+ const promoted = Array.isArray(r.promoted) ? r.promoted.length : 0;
724
+ const warnings = Array.isArray(r.warnings) ? r.warnings : [];
725
+ const lines = [];
726
+ if (r.dryRun === true) {
727
+ lines.push(`[consolidate] dry-run: ${processed} memories found, no AI call`);
728
+ }
729
+ else if (r.previewOnly === true) {
730
+ lines.push(`[consolidate] preview: processed=${processed}`);
731
+ const planned = Array.isArray(r.planned) ? r.planned : [];
732
+ for (const op of planned) {
733
+ if (op.op === "merge") {
734
+ lines.push(` merge: ${String(op.primary)} ← ${String(Array.isArray(op.secondaries) ? op.secondaries.join(", ") : "")}`);
735
+ }
736
+ else if (op.op === "delete") {
737
+ lines.push(` delete: ${String(op.ref)} (${String(op.reason ?? "")})`);
738
+ }
739
+ else if (op.op === "promote") {
740
+ lines.push(` promote: ${String(op.ref)} → ${String(op.knowledgeRef)}`);
741
+ }
742
+ }
743
+ }
744
+ else {
745
+ lines.push(`[consolidate] processed=${processed} merged=${merged} deleted=${deleted} promoted=${promoted}`);
746
+ }
747
+ for (const w of warnings) {
748
+ lines.push(` warning: ${w}`);
749
+ }
750
+ return lines.join("\n");
751
+ }
752
+ export function formatImprovePlain(r) {
753
+ const scope = r.scope ?? {};
754
+ const mode = String(scope.mode ?? "all");
755
+ const value = typeof scope.value === "string" ? ` ${scope.value}` : "";
756
+ const plannedRefs = Array.isArray(r.plannedRefs) ? r.plannedRefs.length : 0;
757
+ if (r.dryRun === true) {
758
+ return `Improve dry-run:${mode === "all" ? " all assets" : value} (${plannedRefs} planned ref(s))`;
759
+ }
760
+ const actions = Array.isArray(r.actions) ? r.actions.length : 0;
761
+ return `Improve:${mode === "all" ? " all assets" : value} queued ${actions} action(s) across ${plannedRefs} ref(s)`;
762
+ }
546
763
  export function formatProposalDiffPlain(r) {
547
764
  const header = r.isNew
548
765
  ? `# proposal ${String(r.id ?? "?")} (new asset: ${String(r.ref ?? "?")})`
@@ -552,18 +769,25 @@ export function formatProposalDiffPlain(r) {
552
769
  return `${header}\n(no changes)`;
553
770
  return `${header}\n${unified}`;
554
771
  }
555
- export function formatEventsPlain(r) {
556
- const events = Array.isArray(r.events) ? r.events : [];
557
- const headerParts = [];
772
+ /**
773
+ * Build the summary header line shared by formatEventsPlain and formatHistoryPlain.
774
+ * Accumulates ref/type/since label parts then appends the count label.
775
+ */
776
+ function buildEventHeader(r, countLabel, totalCount) {
777
+ const parts = [];
558
778
  if (typeof r.ref === "string" && r.ref)
559
- headerParts.push(`ref: ${r.ref}`);
779
+ parts.push(`ref: ${r.ref}`);
560
780
  if (typeof r.type === "string" && r.type)
561
- headerParts.push(`type: ${r.type}`);
781
+ parts.push(`type: ${r.type}`);
562
782
  if (typeof r.since === "string" && r.since)
563
- headerParts.push(`since: ${r.since}`);
783
+ parts.push(`since: ${r.since}`);
784
+ parts.push(`${totalCount} ${countLabel}`);
785
+ return parts.join(" ");
786
+ }
787
+ export function formatEventsPlain(r) {
788
+ const events = Array.isArray(r.events) ? r.events : [];
564
789
  const totalCount = typeof r.totalCount === "number" ? r.totalCount : events.length;
565
- headerParts.push(`${totalCount} event(s)`);
566
- const header = headerParts.join(" ");
790
+ const header = buildEventHeader(r, "event(s)", totalCount);
567
791
  if (events.length === 0) {
568
792
  return `${header}\nNo events.`;
569
793
  }
@@ -586,13 +810,8 @@ export function formatEventLine(event) {
586
810
  }
587
811
  export function formatHistoryPlain(r) {
588
812
  const entries = Array.isArray(r.entries) ? r.entries : [];
589
- const headerParts = [];
590
- if (typeof r.ref === "string" && r.ref)
591
- headerParts.push(`ref: ${r.ref}`);
592
- if (typeof r.since === "string" && r.since)
593
- headerParts.push(`since: ${r.since}`);
594
813
  const totalCount = typeof r.totalCount === "number" ? r.totalCount : entries.length;
595
- headerParts.push(`${totalCount} event(s)`);
814
+ const headerParts = [buildEventHeader(r, "event(s)", totalCount)];
596
815
  // Show active event sources so operators know which streams were consulted.
597
816
  if (Array.isArray(r.sources) && r.sources.length > 0) {
598
817
  headerParts.push(`sources: ${r.sources.join(", ")}`);
@@ -609,12 +828,15 @@ export function formatHistoryPlain(r) {
609
828
  const ref = entry.ref ? String(entry.ref) : null;
610
829
  const signal = entry.signal ? String(entry.signal) : null;
611
830
  const query = entry.query ? String(entry.query) : null;
831
+ const source = entry.source ? String(entry.source) : null;
612
832
  const head = ref ? `${created} [${eventType}] ${ref}` : `${created} [${eventType}]`;
613
833
  lines.push(head);
614
834
  if (signal)
615
835
  lines.push(` signal: ${signal}`);
616
836
  if (query)
617
837
  lines.push(` query: ${query}`);
838
+ if (source && source !== "user")
839
+ lines.push(` source: ${source}`);
618
840
  if (entry.metadata != null && entry.metadata !== "") {
619
841
  const meta = typeof entry.metadata === "string" ? entry.metadata : JSON.stringify(entry.metadata);
620
842
  lines.push(` metadata: ${meta}`);
@@ -670,6 +892,19 @@ function formatShowPlain(r, detail) {
670
892
  if (r.schemaVersion !== undefined)
671
893
  lines.push(`schemaVersion: ${String(r.schemaVersion)}`);
672
894
  }
895
+ const related = typeof r.related === "object" && r.related !== null ? r.related : undefined;
896
+ const relatedHits = related && Array.isArray(related.hits) ? related.hits : [];
897
+ if (related) {
898
+ lines.push("");
899
+ lines.push(`related: ${String(related.total ?? relatedHits.length)}`);
900
+ for (const hit of relatedHits) {
901
+ lines.push(` - ${String(hit.type ?? "?")}: ${formatRelatedLabel(hit)}`);
902
+ const shared = Array.isArray(hit.sharedEntities) ? hit.sharedEntities.map(String) : [];
903
+ if (shared.length > 0)
904
+ lines.push(` shared: ${shared.join(", ")}`);
905
+ lines.push(` relationCount: ${String(hit.relationCount ?? 0)}`);
906
+ }
907
+ }
673
908
  const payloads = [r.content, r.template, r.prompt].filter((value) => value != null).map(String);
674
909
  if (Array.isArray(r.steps) && r.steps.length > 0) {
675
910
  if (lines.length > 0)
@@ -786,6 +1021,13 @@ function isCommandOutputSkill(lines) {
786
1021
  const yamlCount = codeLines.filter((l) => yamlPattern.test(l)).length;
787
1022
  return cliCount > yamlCount && cliCount > 0;
788
1023
  }
1024
+ function formatRelatedLabel(hit) {
1025
+ const ref = typeof hit.ref === "string" ? hit.ref : undefined;
1026
+ if (ref)
1027
+ return ref;
1028
+ const pathValue = typeof hit.path === "string" ? hit.path : "?";
1029
+ return pathValue.split("/").pop() ?? pathValue;
1030
+ }
789
1031
  export function formatWorkflowListPlain(result) {
790
1032
  const runs = Array.isArray(result.runs) ? result.runs : [];
791
1033
  if (runs.length === 0) {
@@ -918,6 +1160,24 @@ export function formatSearchPlain(r, detail) {
918
1160
  if (Array.isArray(hit.warnings) && hit.warnings.length > 0) {
919
1161
  lines.push(` warnings: ${hit.warnings.join("; ")}`);
920
1162
  }
1163
+ const graph = typeof hit.graph === "object" && hit.graph !== null ? hit.graph : undefined;
1164
+ if (graph) {
1165
+ const entities = Array.isArray(graph.entities) ? graph.entities : [];
1166
+ if (entities.length > 0) {
1167
+ const matched = entities
1168
+ .filter((entity) => String(entity.kind ?? "") === "matched")
1169
+ .map((entity) => String(entity.name ?? "?"));
1170
+ const neighbors = entities
1171
+ .filter((entity) => String(entity.kind ?? "") !== "matched")
1172
+ .map((entity) => String(entity.name ?? "?"));
1173
+ lines.push(` graph: ${[
1174
+ matched.length > 0 ? `query match=${matched.join(", ")}` : undefined,
1175
+ neighbors.length > 0 ? `neighbors=${neighbors.join(", ")}` : undefined,
1176
+ ]
1177
+ .filter(Boolean)
1178
+ .join("; ")}`);
1179
+ }
1180
+ }
921
1181
  if (detail === "full") {
922
1182
  if (hit.path)
923
1183
  lines.push(` path: ${String(hit.path)}`);
@@ -1113,3 +1373,31 @@ export function formatCuratePlain(r, detail) {
1113
1373
  lines.push("To search further: akm search '<query>'");
1114
1374
  return lines.join("\n");
1115
1375
  }
1376
+ /**
1377
+ * Render the result of `akm agent <profile>`.
1378
+ *
1379
+ * Interactive mode: stdout and stderr are empty (output went to the TTY).
1380
+ * Print only the profile name and exit code so the caller knows the agent
1381
+ * finished.
1382
+ *
1383
+ * Captured mode: emit stdout (if non-empty), then stderr (if non-empty),
1384
+ * then the profile/exit-code summary line.
1385
+ */
1386
+ export function formatAgentResultPlain(r) {
1387
+ const profile = String(r.profileName ?? "agent");
1388
+ const exitCode = r.exitCode !== undefined && r.exitCode !== null ? Number(r.exitCode) : 0;
1389
+ const stdout = typeof r.stdout === "string" ? r.stdout : "";
1390
+ const stderr = typeof r.stderr === "string" ? r.stderr : "";
1391
+ // Interactive mode: both streams are empty.
1392
+ if (!stdout && !stderr) {
1393
+ return `[${profile}] agent exited with code ${exitCode}`;
1394
+ }
1395
+ // Captured mode: stream content + summary.
1396
+ const parts = [];
1397
+ if (stdout)
1398
+ parts.push(stdout.trimEnd());
1399
+ if (stderr)
1400
+ parts.push(stderr.trimEnd());
1401
+ parts.push(`[${profile}] agent exited with code ${exitCode}`);
1402
+ return parts.join("\n");
1403
+ }
@@ -1,3 +1,6 @@
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/.
1
4
  /**
2
5
  * Build the v2 JSON registry index consumed by the `static-index` registry
3
6
  * provider. This module emits artifacts that conform to the v2 schema; the
@@ -1,3 +1,6 @@
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/.
1
4
  /**
2
5
  * Generic factory-map utility.
3
6
  *
@@ -1,3 +1,6 @@
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/.
1
4
  /**
2
5
  * Registry provider factory map.
3
6
  *
@@ -1,3 +1,6 @@
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/.
1
4
  import path from "node:path";
2
5
  import { parseRegistryRef } from "./resolve";
3
6
  /**
@@ -1,3 +1,6 @@
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/.
1
4
  /**
2
5
  * Centralized registry provider registration.
3
6
  *