akm-cli 0.9.17-alpha.8 → 0.9.17

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 (111) hide show
  1. package/CHANGELOG.md +277 -1694
  2. package/STABILITY.md +9 -8
  3. package/dist/assets/hints/cli-hints-full.md +6 -7
  4. package/dist/assets/improve-strategies/catchup.json +0 -3
  5. package/dist/assets/improve-strategies/consolidate.json +0 -1
  6. package/dist/assets/improve-strategies/default.json +1 -2
  7. package/dist/assets/improve-strategies/proactive-maintenance.json +1 -2
  8. package/dist/assets/improve-strategies/quick.json +1 -2
  9. package/dist/assets/improve-strategies/reflect-distill.json +1 -2
  10. package/dist/assets/improve-strategies/thorough.json +0 -3
  11. package/dist/assets/prompts/consolidate-pair.md +20 -0
  12. package/dist/assets/stash-skeleton/facts/conventions/backlinks.md +17 -19
  13. package/dist/assets/stash-skeleton/facts/conventions/domains.md +2 -2
  14. package/dist/assets/templates/html/health.html +3 -5
  15. package/dist/cli/retired-commands.js +1 -1
  16. package/dist/cli/unknown-flags.js +24 -1
  17. package/dist/cli.js +46 -1
  18. package/dist/commands/health/archive-usage.js +92 -0
  19. package/dist/commands/health/data-dir-usage.js +25 -13
  20. package/dist/commands/health/html-report.js +1 -4
  21. package/dist/commands/health/improve-metrics.js +25 -37
  22. package/dist/commands/health/md-report.js +1 -6
  23. package/dist/commands/health/report-view-model.js +4 -14
  24. package/dist/commands/health/windows.js +0 -1
  25. package/dist/commands/health.js +13 -0
  26. package/dist/commands/improve/consolidate/continuity-check.js +137 -0
  27. package/dist/commands/improve/consolidate/pair-pass.js +791 -0
  28. package/dist/commands/improve/consolidate.js +38 -63
  29. package/dist/commands/improve/extract-prompt.js +1 -2
  30. package/dist/commands/improve/improve-cli.js +1 -1
  31. package/dist/commands/improve/improve-strategies.js +23 -5
  32. package/dist/commands/improve/improve.js +19 -30
  33. package/dist/commands/improve/ledger.js +3 -2
  34. package/dist/commands/improve/loop-stages.js +5 -85
  35. package/dist/commands/improve/memory/memory-belief.js +3 -1
  36. package/dist/commands/improve/memory/memory-improve.js +262 -11
  37. package/dist/commands/improve/planner.js +0 -5
  38. package/dist/commands/improve/preparation.js +20 -135
  39. package/dist/commands/improve/retrieval-scope.js +19 -4
  40. package/dist/commands/improve/salience.js +1 -14
  41. package/dist/commands/improve/stage.js +0 -1
  42. package/dist/commands/lint/base-linter.js +19 -11
  43. package/dist/commands/proposal/drain.js +8 -1
  44. package/dist/commands/proposal/proposal-cli.js +16 -2
  45. package/dist/commands/proposal/proposal-types.js +7 -0
  46. package/dist/commands/proposal/proposal.js +37 -6
  47. package/dist/commands/proposal/repository.js +613 -4
  48. package/dist/commands/proposal/validators/proposals.js +9 -0
  49. package/dist/commands/read/knowledge.js +3 -2
  50. package/dist/commands/read/show.js +0 -14
  51. package/dist/commands/sources/info.js +122 -18
  52. package/dist/commands/sources/stash-cli.js +23 -3
  53. package/dist/core/bundle-rename.js +1 -7
  54. package/dist/core/config/config-schema.js +8 -1
  55. package/dist/core/config/config.js +23 -48
  56. package/dist/core/config/engine-semantics.js +0 -2
  57. package/dist/core/config/schema/improve-processes.js +17 -42
  58. package/dist/core/config/schema/index-config.js +5 -25
  59. package/dist/core/file-change.js +13 -5
  60. package/dist/core/improve-result.js +22 -6
  61. package/dist/core/improve-types.js +0 -1
  62. package/dist/core/loopback.js +7 -12
  63. package/dist/core/parse.js +13 -16
  64. package/dist/core/state/migrations.js +15 -0
  65. package/dist/core/time.js +0 -20
  66. package/dist/indexer/db/llm-cache.js +2 -2
  67. package/dist/indexer/ensure-index.js +2 -2
  68. package/dist/indexer/index-written-assets.js +2 -3
  69. package/dist/indexer/indexer.js +18 -418
  70. package/dist/indexer/passes/metadata.js +0 -19
  71. package/dist/indexer/walk/walker.js +3 -4
  72. package/dist/llm/client.js +8 -10
  73. package/dist/llm/embedders/remote.js +1 -2
  74. package/dist/llm/feature-gate.js +0 -5
  75. package/dist/output/shapes/helpers.js +20 -4
  76. package/dist/output/text/command-format.js +9 -8
  77. package/dist/output/text/proposal-format.js +47 -1
  78. package/dist/output/text/show-format.js +0 -20
  79. package/dist/scripts/akm-migrate-node.js +923 -950
  80. package/dist/scripts/akm-migrate.js +923 -950
  81. package/dist/setup/steps/connection.js +5 -6
  82. package/dist/setup/steps/platforms.js +2 -2
  83. package/dist/sources/providers/git-stash.js +83 -4
  84. package/dist/storage/repositories/improve-ledger-repository.js +48 -7
  85. package/dist/storage/repositories/index-connection.js +5 -2
  86. package/dist/storage/repositories/index-entries-repository.js +4 -7
  87. package/dist/storage/repositories/index-entry-schema.js +4 -2
  88. package/dist/storage/repositories/index-llm-cache-repository.js +7 -26
  89. package/dist/storage/repositories/index-schema.js +55 -104
  90. package/dist/storage/repositories/proposals-repository.js +61 -0
  91. package/dist/storage/repositories/salience-repository.js +1 -19
  92. package/docs/migration/README.md +1 -1
  93. package/docs/migration/release-notes/0.9.17.md +130 -41
  94. package/docs/migration/release-notes/README.md +7 -0
  95. package/docs/reference/cli.md +27 -21
  96. package/docs/reference/configuration.md +21 -12
  97. package/docs/reference/data-and-telemetry.md +0 -1
  98. package/package.json +1 -1
  99. package/schemas/akm-config.json +0 -342
  100. package/dist/assets/improve-strategies/graph-refresh.json +0 -15
  101. package/dist/assets/prompts/contradiction-judge.md +0 -33
  102. package/dist/assets/prompts/graph-extract-system.md +0 -1
  103. package/dist/assets/prompts/graph-extract-user-prompt.md +0 -35
  104. package/dist/assets/prompts/metadata-enhance-system.md +0 -1
  105. package/dist/assets/tasks/improve/akm-graph-refresh-weekly.yml +0 -4
  106. package/dist/indexer/db/graph-db.js +0 -399
  107. package/dist/indexer/graph/graph-extraction.js +0 -809
  108. package/dist/indexer/graph/graph-related.js +0 -131
  109. package/dist/indexer/graph/graph-types.js +0 -4
  110. package/dist/llm/graph-extract.js +0 -892
  111. package/dist/llm/metadata-enhance.js +0 -95
@@ -101,10 +101,9 @@ function retryBackoffMs() {
101
101
  * narrating about a document) does not get misclassified as a provider
102
102
  * context-limit error (#496).
103
103
  *
104
- * Canonical home: `graph-extract.ts` re-exports this so the index-pass
105
- * graph extractor and the retry classifier (`isRetryable`) share one
106
- * definition — retrying a context overflow cannot shrink the input, so it
107
- * must never be retried.
104
+ * Canonical home: `structured-call.ts`'s failure classifier and the retry
105
+ * classifier (`isRetryable`) here share one definition — retrying a context
106
+ * overflow cannot shrink the input, so it must never be retried.
108
107
  */
109
108
  export function isContextSizeError(message) {
110
109
  const lower = message.toLowerCase();
@@ -120,13 +119,12 @@ export function isContextSizeError(message) {
120
119
  /**
121
120
  * Codes describing a failure to reach or get a usable response from the
122
121
  * provider transport itself, as opposed to a malformed-but-received response
123
- * (`parse_error`) or a request-shape rejection (`rate_limited`). Shared by
124
- * {@link isRetryable} (which additionally requires evidence the failure is
125
- * transient) and the batch graph-extraction storm guard in `graph-extract.ts`
126
- * (which treats any of these as "the provider is down, stop retrying
127
- * per-asset") so the two classifications cannot drift apart.
122
+ * (`parse_error`) or a request-shape rejection (`rate_limited`). Used by
123
+ * {@link isRetryable}, which additionally requires evidence the failure is
124
+ * transient. Not exported — its one external caller (batched LLM
125
+ * entity-graph extraction) was retired in 0.9.17-alpha.9.
128
126
  */
129
- export function isTransportFailure(err) {
127
+ function isTransportFailure(err) {
130
128
  return err.code === "provider_error" || err.code === "network_error" || err.code === "provider_html_error";
131
129
  }
132
130
  /**
@@ -187,8 +187,7 @@ export function isContextExceededResponse(status, body) {
187
187
  * Resolve the effective in-flight request window for `RemoteEmbedder.embedBatch`.
188
188
  * Default (unset `embedding.concurrency`): 1 for a loopback endpoint, 2 for a
189
189
  * remote one, via the shared `defaultConcurrencyForEndpoint`
190
- * (`src/core/loopback.ts`), the same lowest-common-denominator rule
191
- * `getDefaultLlmConcurrency` (`src/indexer/indexer.ts`) uses.
190
+ * (`src/core/loopback.ts`).
192
191
  *
193
192
  * `embedding.concurrency` (#954) overrides this default in
194
193
  * either direction, bounded 1-16 at the config schema — added after field
@@ -7,8 +7,6 @@
7
7
  */
8
8
  const FEATURE_LOCATION = {
9
9
  memory_inference: (cfg) => cfg.index?.memory?.enabled ?? true,
10
- graph_extraction: (cfg) => cfg.index?.graph?.enabled ?? true,
11
- metadata_enhance: (cfg) => cfg.index?.metadataEnhance?.enabled ?? false,
12
10
  // #951: a real implementation of the dead `curate_rerank` key removed in
13
11
  // 0.8.0. Off by default — it requires a `search.curateRerank.endpoint` a
14
12
  // caller must explicitly configure.
@@ -82,9 +80,6 @@ export function isProcessEnabled(section, processName, config) {
82
80
  if (processName === "memory_inference" || processName === "memoryInference") {
83
81
  return isLlmFeatureEnabled(config, "memory_inference");
84
82
  }
85
- if (processName === "graph_extraction" || processName === "graphExtraction") {
86
- return isLlmFeatureEnabled(config, "graph_extraction");
87
- }
88
83
  }
89
84
  return false;
90
85
  }
@@ -56,11 +56,25 @@ export function shapeProposalProducerOutput(result, detail) {
56
56
  }
57
57
  export function shapeProposalEntry(entry, detail) {
58
58
  if (detail === "brief") {
59
- return pickFields(entry, ["id", "ref", "status", "source", "createdAt"]);
59
+ // `proposal list`'s default detail level IS "brief" (no `--detail` flag
60
+ // given projects here, not "normal") — `retirement` itself is not
61
+ // projected until "normal", so a flagged retire proposal's risk would
62
+ // otherwise be invisible by default. A minimal boolean marker, not the
63
+ // full risk object, keeps brief's shape small while still letting a
64
+ // reviewer see it without an extra flag.
65
+ const retirement = entry.retirement;
66
+ return {
67
+ ...pickFields(entry, ["id", "ref", "status", "source", "createdAt"]),
68
+ ...(retirement?.continuityRisk ? { continuityRisk: true } : {}),
69
+ };
60
70
  }
61
71
  if (detail === "normal") {
62
72
  // `confidence` and `gateDecision` (#577) explain why a proposal is pending,
63
73
  // so they are projected at `normal` for `akm proposal list/show` when present.
74
+ // `retirement` (alpha.9) is the same kind of field for a consolidate
75
+ // `retire` proposal: without it, "list/show" carries no reason a reviewer
76
+ // could act on (its `payload.content` is empty by design — a retire
77
+ // proposal deletes, it does not write).
64
78
  return pickFields(entry, [
65
79
  "id",
66
80
  "ref",
@@ -72,6 +86,7 @@ export function shapeProposalEntry(entry, detail) {
72
86
  "confidence",
73
87
  "gateDecision",
74
88
  "review",
89
+ "retirement",
75
90
  ]);
76
91
  }
77
92
  // full: project everything including the payload.
@@ -87,6 +102,10 @@ export function shapeProposalEntry(entry, detail) {
87
102
  "gateDecision",
88
103
  "payload",
89
104
  "review",
105
+ "retirement",
106
+ "retiredArchive",
107
+ "promotionSource",
108
+ "promotionSourceHash",
90
109
  ]);
91
110
  }
92
111
  export function shapeProposalListOutput(result, detail) {
@@ -357,7 +376,6 @@ export function shapeShowOutput(result, detail, shape = "human") {
357
376
  "workflowParameters",
358
377
  "steps",
359
378
  "keys",
360
- "related",
361
379
  "links",
362
380
  ...FRAGMENT_PROVENANCE_FIELDS,
363
381
  ...FRAGMENT_CONTEXT_FIELDS,
@@ -382,7 +400,6 @@ export function shapeShowOutput(result, detail, shape = "human") {
382
400
  "run",
383
401
  "origin",
384
402
  "keys",
385
- "related",
386
403
  "links",
387
404
  ...FRAGMENT_PROVENANCE_FIELDS,
388
405
  ...FRAGMENT_CONTEXT_FIELDS,
@@ -412,7 +429,6 @@ export function shapeShowOutput(result, detail, shape = "human") {
412
429
  "cwd",
413
430
  "activeRun",
414
431
  "keys",
415
- "related",
416
432
  "links",
417
433
  ...FRAGMENT_PROVENANCE_FIELDS,
418
434
  ...FRAGMENT_CONTEXT_FIELDS,
@@ -20,11 +20,20 @@ export function formatInfoPlain(r) {
20
20
  const lines = [];
21
21
  if (r.version)
22
22
  lines.push(`version: ${String(r.version)}`);
23
+ // Only present in infoCommand's own last-resort fallback (stash-cli.ts),
24
+ // when assembleInfo() itself threw — every field below it belongs to the
25
+ // normal shape and is absent there.
26
+ if (typeof r.error === "string")
27
+ lines.push(`error: ${r.error}`);
23
28
  if (r.bundleDir)
24
29
  lines.push(`bundleDir: ${String(r.bundleDir)}`);
25
30
  if (r.defaultBundle !== undefined) {
26
31
  lines.push(`defaultBundle: ${r.defaultBundle === null ? "(none)" : String(r.defaultBundle)}`);
27
32
  }
33
+ if (typeof r.configError === "string")
34
+ lines.push(`configError: ${r.configError}`);
35
+ if (typeof r.bundleDirError === "string")
36
+ lines.push(`bundleDirError: ${r.bundleDirError}`);
28
37
  if (Array.isArray(r.assetTypes) && r.assetTypes.length > 0) {
29
38
  lines.push(`assetTypes: ${r.assetTypes.join(", ")}`);
30
39
  }
@@ -407,14 +416,6 @@ export function formatIndexPlain(r) {
407
416
  for (const message of warnings)
408
417
  out += `\n - ${String(message)}`;
409
418
  }
410
- const notices = Array.isArray(indexResult.notices) ? indexResult.notices : [];
411
- for (const notice of notices) {
412
- const severity = notice.severity === "info" ? "info" : "warning";
413
- const field = typeof notice.field === "string" ? ` field=${notice.field}` : "";
414
- out +=
415
- `\n notice[${severity}] ${notice.code} adapter=${notice.adapter}${field}` +
416
- (notice.message ? `: ${notice.message}` : "");
417
- }
418
419
  const verification = indexResult.verification;
419
420
  if (verification?.ok === false && verification.message) {
420
421
  out += `\nVerification: ${String(verification.message)}`;
@@ -100,7 +100,16 @@ export function formatProposalListPlain(r) {
100
100
  // #577: surface the gate verdict inline so the queue explains itself.
101
101
  const gate = formatGateDecisionSummary(p.gateDecision);
102
102
  const gateSuffix = gate ? ` ${gate}` : "";
103
- lines.push(`${id} [${status}] ${ref} source=${source} ${created}${gateSuffix}`);
103
+ // A retire proposal's continuityRisk excludes it from bulk accept —
104
+ // visible in the default list, not just `proposal show`, since the owner
105
+ // reviews the backlog list-first. `list`'s default (brief) shape
106
+ // projects a `continuityRisk: true` marker instead of the full
107
+ // `retirement` object (only present from `--detail normal` up), so both
108
+ // shapes are checked here.
109
+ const retirement = p.retirement;
110
+ const flagged = p.continuityRisk === true || Boolean(retirement?.continuityRisk);
111
+ const continuitySuffix = flagged ? " ⚠ continuity-risk" : "";
112
+ lines.push(`${id} [${status}] ${ref} source=${source} ${created}${gateSuffix}${continuitySuffix}`);
104
113
  }
105
114
  return lines.join("\n").trimEnd();
106
115
  }
@@ -141,6 +150,43 @@ export function formatProposalShowPlain(r) {
141
150
  if (review.decidedAt)
142
151
  lines.push(`review.decidedAt: ${String(review.decidedAt)}`);
143
152
  }
153
+ // alpha.9: a consolidate retire proposal writes no content (`payload.content`
154
+ // is empty by design) — this is the reason a reviewer needs instead. `diff`
155
+ // shows the body being retired.
156
+ const retirement = p.retirement;
157
+ if (retirement) {
158
+ lines.push(`retire: ${String(retirement.retiredRef)} -> ${String(retirement.successorRef)}`);
159
+ lines.push(`retire.label: ${String(retirement.judgeLabel)} (cosine=${String(retirement.cosine)})`);
160
+ lines.push(`retire.reason: ${String(retirement.judgeReason)}`);
161
+ // Item 1 (continuity check): flagged, but still minted — never swept by a
162
+ // bulk accept, only acceptable by id, so a reviewer must see it here.
163
+ const continuityRisk = retirement.continuityRisk;
164
+ if (continuityRisk) {
165
+ const failingQueries = typeof continuityRisk.failingQueries === "number" ? continuityRisk.failingQueries : 0;
166
+ const unverifiedQueries = typeof continuityRisk.unverifiedQueries === "number" ? continuityRisk.unverifiedQueries : 0;
167
+ const summary = [];
168
+ if (failingQueries > 0) {
169
+ summary.push(`${failingQueries} of the retired asset's own quer${failingQueries === 1 ? "y" : "ies"} would not have found the successor top 10`);
170
+ }
171
+ // S2: a query the search call never ran, or that fell back to
172
+ // keyword-only ranking, is never silently trusted OR silently
173
+ // dropped — it excludes the proposal from bulk accept on its own.
174
+ if (unverifiedQueries > 0) {
175
+ summary.push(`${unverifiedQueries} quer${unverifiedQueries === 1 ? "y" : "ies"} unverified (search failed or used the keyword-only fallback)`);
176
+ }
177
+ lines.push(`retire.continuityRisk: ${summary.join("; ")} — excluded from bulk accept`);
178
+ // N3 / S4: the actual failing query text, not just the count — a
179
+ // reviewer deciding whether to accept by id needs to see what would
180
+ // stop resolving, not just how many queries.
181
+ const ranks = Array.isArray(continuityRisk.ranks) ? continuityRisk.ranks : [];
182
+ for (const rank of ranks) {
183
+ const successorRank = rank.successorRank === null || rank.successorRank === undefined
184
+ ? "absent from top 10"
185
+ : `#${String(rank.successorRank)}`;
186
+ lines.push(` - "${String(rank.query)}": retired #${String(rank.retiredRank)}, successor ${successorRank}`);
187
+ }
188
+ }
189
+ }
144
190
  const validation = r.validation;
145
191
  if (validation) {
146
192
  const findings = Array.isArray(validation.findings) ? validation.findings : [];
@@ -54,19 +54,6 @@ export function formatShowPlain(r, detail) {
54
54
  if (r.schemaVersion !== undefined)
55
55
  lines.push(`schemaVersion: ${String(r.schemaVersion)}`);
56
56
  }
57
- const related = typeof r.related === "object" && r.related !== null ? r.related : undefined;
58
- const relatedHits = related && Array.isArray(related.hits) ? related.hits : [];
59
- if (related) {
60
- lines.push("");
61
- lines.push(`related: ${String(related.total ?? relatedHits.length)}`);
62
- for (const hit of relatedHits) {
63
- lines.push(` - ${String(hit.type ?? "?")}: ${formatRelatedLabel(hit)}`);
64
- const shared = Array.isArray(hit.sharedEntities) ? hit.sharedEntities.map(String) : [];
65
- if (shared.length > 0)
66
- lines.push(` shared: ${shared.join(", ")}`);
67
- lines.push(` relationCount: ${String(hit.relationCount ?? 0)}`);
68
- }
69
- }
70
57
  const links = typeof r.links === "object" && r.links !== null ? r.links : undefined;
71
58
  if (links) {
72
59
  lines.push("");
@@ -114,10 +101,3 @@ export function formatShowPlain(r, detail) {
114
101
  appendShowDirectives(lines, r);
115
102
  return lines.length > 0 ? lines.join("\n") : null;
116
103
  }
117
- function formatRelatedLabel(hit) {
118
- const ref = typeof hit.ref === "string" ? hit.ref : undefined;
119
- if (ref)
120
- return ref;
121
- const pathValue = typeof hit.path === "string" ? hit.path : "?";
122
- return pathValue.split("/").pop() ?? pathValue;
123
- }