akm-cli 0.9.18 → 0.9.19-alpha.2

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 (52) hide show
  1. package/CHANGELOG.md +156 -0
  2. package/STABILITY.md +2 -1
  3. package/dist/assets/hints/cli-hints-full.md +4 -2
  4. package/dist/assets/hints/cli-hints-short.md +5 -3
  5. package/dist/assets/prompts/reflect-feedback-framing.md +1 -1
  6. package/dist/commands/feedback-cli.js +1 -1
  7. package/dist/commands/improve/consolidate/coverage.js +132 -0
  8. package/dist/commands/improve/consolidate/pair-pass.js +30 -20
  9. package/dist/commands/improve/consolidate.js +43 -10
  10. package/dist/commands/improve/distill.js +7 -3
  11. package/dist/commands/improve/eligibility.js +39 -9
  12. package/dist/commands/improve/improve-cli.js +9 -6
  13. package/dist/commands/improve/improve.js +13 -4
  14. package/dist/commands/improve/ledger.js +2 -2
  15. package/dist/commands/improve/loop-stages.js +2 -0
  16. package/dist/commands/improve/preparation.js +1 -1
  17. package/dist/commands/improve/reflect.js +1 -1
  18. package/dist/commands/improve/stage.js +61 -9
  19. package/dist/commands/proposal/diff-format.js +21 -0
  20. package/dist/commands/proposal/proposal-cli.js +48 -10
  21. package/dist/commands/proposal/proposal-types.js +11 -0
  22. package/dist/commands/proposal/proposal.js +60 -5
  23. package/dist/commands/proposal/repository.js +245 -17
  24. package/dist/commands/read/knowledge.js +13 -11
  25. package/dist/commands/read/remember-cli.js +7 -3
  26. package/dist/commands/sources/source-clone.js +1 -1
  27. package/dist/commands/tasks/tasks-cli.js +1 -1
  28. package/dist/commands/tasks/tasks.js +10 -3
  29. package/dist/core/mutation-target.js +8 -3
  30. package/dist/core/write-source.js +3 -2
  31. package/dist/indexer/usage/usage-events.js +2 -1
  32. package/dist/output/shapes/helpers.js +7 -0
  33. package/dist/output/shapes/passthrough.js +1 -0
  34. package/dist/output/shapes/proposal/reopen.js +14 -0
  35. package/dist/output/shapes.js +2 -0
  36. package/dist/output/text/helpers.js +1 -1
  37. package/dist/output/text/proposal/proposal.js +3 -1
  38. package/dist/output/text/proposal-format.js +87 -32
  39. package/dist/scripts/akm-migrate-node.js +79 -23
  40. package/dist/scripts/akm-migrate.js +79 -23
  41. package/dist/storage/repositories/improve-ledger-repository.js +65 -6
  42. package/dist/storage/repositories/index-vec-repository.js +13 -8
  43. package/dist/storage/repositories/proposals-repository.js +23 -0
  44. package/dist/tasks/run/load-task.js +5 -1
  45. package/docs/migration/README.md +1 -0
  46. package/docs/migration/release-notes/0.9.19.md +137 -0
  47. package/docs/migration/release-notes/README.md +5 -0
  48. package/docs/migration/v0.8-to-v0.9.md +5 -1
  49. package/docs/reference/cli.md +190 -28
  50. package/docs/reference/configuration.md +9 -8
  51. package/docs/reference/data-and-telemetry.md +19 -14
  52. package/package.json +1 -1
@@ -29,6 +29,7 @@ import { proposalDiffShapes } from "./shapes/proposal/diff.js";
29
29
  import { proposalListShapes } from "./shapes/proposal/list.js";
30
30
  import { proposalProducerShapes } from "./shapes/proposal/producer.js";
31
31
  import { proposalRejectShapes } from "./shapes/proposal/reject.js";
32
+ import { proposalReopenShapes } from "./shapes/proposal/reopen.js";
32
33
  import { proposalShowShapes } from "./shapes/proposal/show.js";
33
34
  import { getOutputShapeHandler, registerOutputShapes } from "./shapes/registry.js";
34
35
  import { registrySearchShapes } from "./shapes/registry-search.js";
@@ -51,6 +52,7 @@ const BUILT_IN_OUTPUT_SHAPES = [
51
52
  ...proposalShowShapes,
52
53
  ...proposalAcceptShapes,
53
54
  ...proposalRejectShapes,
55
+ ...proposalReopenShapes,
54
56
  ...proposalDiffShapes,
55
57
  ...proposalProducerShapes,
56
58
  ...envListShapes,
@@ -18,6 +18,6 @@
18
18
  export { formatAddPlain, formatBundleRenamePlain, formatBundleShowPlain, formatClonePlain, formatConfigPlain, formatCuratePlain, formatEnvCreatePlain, formatEnvExportPlain, formatEnvListPlain, formatEnvRemovePlain, formatEventLine, formatEventsPlain, formatFeedbackPlain, formatImportPlain, formatIndexPlain, formatInfoPlain, formatInitPlain, formatListPlain, formatModelsListPlain, formatRegistryAddPlain, formatRegistryListPlain, formatRegistryRemovePlain, formatRegistrySearchPlain, formatRememberPlain, formatRemovePlain, formatSearchPlain, formatSyncPlain, formatUpdatePlain, formatUpgradePlain, } from "./command-format.js";
19
19
  export { formatHealthPlain } from "./health-format.js";
20
20
  export { formatLintPlain } from "./lint-format.js";
21
- export { formatGateDecisionSummary, formatProposalAcceptPlain, formatProposalDiffPlain, formatProposalDrainPlain, formatProposalListPlain, formatProposalProducerPlain, formatProposalRejectPlain, formatProposalShowPlain, } from "./proposal-format.js";
21
+ export { formatGateDecisionSummary, formatProposalAcceptPlain, formatProposalDiffPlain, formatProposalDrainPlain, formatProposalListPlain, formatProposalProducerPlain, formatProposalRejectPlain, formatProposalReopenBatchPlain, formatProposalReopenPlain, formatProposalShowPlain, } from "./proposal-format.js";
22
22
  export { formatShowPlain } from "./show-format.js";
23
23
  export { formatWorkflowCreatePlain, formatWorkflowListPlain, formatWorkflowPlanPlain, formatWorkflowResumePlain, formatWorkflowRunPlain, formatWorkflowStatusPlain, } from "./workflow-format.js";
@@ -2,12 +2,14 @@
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
4
  // Output text formatters for `akm proposal *` (#225).
5
- import { formatProposalAcceptPlain, formatProposalDiffPlain, formatProposalDrainPlain, formatProposalListPlain, formatProposalRejectPlain, formatProposalShowPlain, } from "../helpers.js";
5
+ import { formatProposalAcceptPlain, formatProposalDiffPlain, formatProposalDrainPlain, formatProposalListPlain, formatProposalRejectPlain, formatProposalReopenBatchPlain, formatProposalReopenPlain, formatProposalShowPlain, } from "../helpers.js";
6
6
  export const proposalFormatters = [
7
7
  { command: "proposal-list", handler: (r) => formatProposalListPlain(r) },
8
8
  { command: "proposal-show", handler: (r) => formatProposalShowPlain(r) },
9
9
  { command: "proposal-accept", handler: (r) => formatProposalAcceptPlain(r) },
10
10
  { command: "proposal-reject", handler: (r) => formatProposalRejectPlain(r) },
11
+ { command: "proposal-reopen", handler: (r) => formatProposalReopenPlain(r) },
12
+ { command: "proposal-reopen-batch", handler: (r) => formatProposalReopenBatchPlain(r) },
11
13
  { command: "proposal-diff", handler: (r) => formatProposalDiffPlain(r) },
12
14
  { command: "proposal-drain", handler: (r) => formatProposalDrainPlain(r) },
13
15
  ];
@@ -113,6 +113,47 @@ export function formatProposalListPlain(r) {
113
113
  }
114
114
  return lines.join("\n").trimEnd();
115
115
  }
116
+ /**
117
+ * A retire proposal's verdict lines — the pair judge's label and reason, and
118
+ * the continuity check's failing queries — as `proposal show` and `proposal
119
+ * diff` both print them. `retirement` is the stored block, which `proposal
120
+ * diff` reports under the same keys.
121
+ */
122
+ function retireVerdictLines(retirement) {
123
+ const lines = [
124
+ `retire.label: ${String(retirement.judgeLabel)} (cosine=${String(retirement.cosine)})`,
125
+ `retire.reason: ${String(retirement.judgeReason)}`,
126
+ ];
127
+ // Item 1 (continuity check): flagged, but still minted — never swept by a
128
+ // bulk accept, only acceptable by id, so a reviewer must see it.
129
+ const continuityRisk = retirement.continuityRisk;
130
+ if (continuityRisk) {
131
+ const failingQueries = typeof continuityRisk.failingQueries === "number" ? continuityRisk.failingQueries : 0;
132
+ const unverifiedQueries = typeof continuityRisk.unverifiedQueries === "number" ? continuityRisk.unverifiedQueries : 0;
133
+ const summary = [];
134
+ if (failingQueries > 0) {
135
+ summary.push(`${failingQueries} of the retired asset's own quer${failingQueries === 1 ? "y" : "ies"} would not have found the successor top 10`);
136
+ }
137
+ // S2: a query the search call never ran, or that fell back to
138
+ // keyword-only ranking, is never silently trusted OR silently
139
+ // dropped — it excludes the proposal from bulk accept on its own.
140
+ if (unverifiedQueries > 0) {
141
+ summary.push(`${unverifiedQueries} quer${unverifiedQueries === 1 ? "y" : "ies"} unverified (search failed or used the keyword-only fallback)`);
142
+ }
143
+ lines.push(`retire.continuityRisk: ${summary.join("; ")} — excluded from bulk accept`);
144
+ // N3 / S4: the actual failing query text, not just the count — a
145
+ // reviewer deciding whether to accept by id needs to see what would
146
+ // stop resolving, not just how many queries.
147
+ const ranks = Array.isArray(continuityRisk.ranks) ? continuityRisk.ranks : [];
148
+ for (const rank of ranks) {
149
+ const successorRank = rank.successorRank === null || rank.successorRank === undefined
150
+ ? "absent from top 10"
151
+ : `#${String(rank.successorRank)}`;
152
+ lines.push(` - "${String(rank.query)}": retired #${String(rank.retiredRank)}, successor ${successorRank}`);
153
+ }
154
+ }
155
+ return lines;
156
+ }
116
157
  export function formatProposalShowPlain(r) {
117
158
  const p = r.proposal;
118
159
  const lines = [];
@@ -150,42 +191,24 @@ export function formatProposalShowPlain(r) {
150
191
  if (review.decidedAt)
151
192
  lines.push(`review.decidedAt: ${String(review.decidedAt)}`);
152
193
  }
194
+ // `akm proposal reopen` (#997): the rejection each reopen undid, so a
195
+ // pending proposal that was once rejected says so.
196
+ const history = Array.isArray(p.reviewHistory) ? p.reviewHistory : [];
197
+ for (const entry of history) {
198
+ const undone = entry.review;
199
+ const was = undone
200
+ ? `${String(undone.outcome ?? "?")}${undone.reason ? `: ${String(undone.reason)}` : ""} (${String(undone.decidedAt ?? "?")})`
201
+ : "an unrecorded review";
202
+ const why = entry.reopenReason ? ` (${String(entry.reopenReason)})` : "";
203
+ lines.push(`reopened: ${String(entry.reopenedAt)}${why}, undoing ${was}`);
204
+ }
153
205
  // alpha.9: a consolidate retire proposal writes no content (`payload.content`
154
206
  // is empty by design) — this is the reason a reviewer needs instead. `diff`
155
207
  // shows the body being retired.
156
208
  const retirement = p.retirement;
157
209
  if (retirement) {
158
210
  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
- }
211
+ lines.push(...retireVerdictLines(retirement));
189
212
  }
190
213
  const validation = r.validation;
191
214
  if (validation) {
@@ -215,7 +238,10 @@ export function formatProposalShowPlain(r) {
215
238
  }
216
239
  }
217
240
  const payload = p.payload;
218
- if (payload && typeof payload.content === "string") {
241
+ // A retire proposal's payload is empty by design (it archives a file, it
242
+ // writes none): a bare `payload:` heading reads as "replaced by nothing" —
243
+ // the misreading #997 is about — so the retirement lines above stand alone.
244
+ if (!retirement && payload && typeof payload.content === "string") {
219
245
  lines.push("");
220
246
  lines.push("payload:");
221
247
  lines.push(payload.content);
@@ -229,6 +255,18 @@ export function formatProposalRejectPlain(r) {
229
255
  const reason = r.reason ? ` (${String(r.reason)})` : "";
230
256
  return `Rejected proposal ${String(r.id)} (${String(r.ref)})${reason}`;
231
257
  }
258
+ export function formatProposalReopenPlain(r) {
259
+ const reason = r.reason ? ` (${String(r.reason)})` : "";
260
+ return `Reopened proposal ${String(r.id)} (${String(r.ref)}) [pending]${reason}`;
261
+ }
262
+ export function formatProposalReopenBatchPlain(r) {
263
+ const results = Array.isArray(r.results) ? r.results : [];
264
+ const reason = results[0]?.reason ? ` (${String(results[0].reason)})` : "";
265
+ return [
266
+ `Reopened ${results.length} proposal(s) [pending]${reason}`,
267
+ ...results.map((result) => ` ${String(result.id)} ${String(result.ref)}`),
268
+ ].join("\n");
269
+ }
232
270
  export function formatProposalDrainPlain(r) {
233
271
  const applyMode = String(r.applyMode ?? "queue");
234
272
  const promoted = Array.isArray(r.promoted) ? r.promoted : [];
@@ -257,10 +295,27 @@ export function formatProposalDrainPlain(r) {
257
295
  return lines.join("\n").trimEnd();
258
296
  }
259
297
  export function formatProposalDiffPlain(r) {
298
+ const unified = typeof r.unified === "string" ? r.unified : "";
299
+ if (r.op === "delete") {
300
+ // #997: a retire proposal archives its target — it does not "update" it —
301
+ // so the header says so, and the pair verdict and the accept/revert note
302
+ // sit above the file that is leaving.
303
+ const retirement = r.retirement;
304
+ const subject = retirement
305
+ ? `${String(retirement.retiredRef)} -> ${String(retirement.successorRef)}`
306
+ : String(r.ref);
307
+ const lines = [`# proposal ${String(r.id)} (retire: ${subject})`];
308
+ if (retirement)
309
+ lines.push(...retireVerdictLines(retirement));
310
+ if (typeof r.note === "string")
311
+ lines.push(`note: ${r.note}`);
312
+ if (unified)
313
+ lines.push(unified);
314
+ return lines.join("\n");
315
+ }
260
316
  const header = r.isNew
261
317
  ? `# proposal ${String(r.id)} (new asset: ${String(r.ref)})`
262
318
  : `# proposal ${String(r.id)} (update: ${String(r.ref)})`;
263
- const unified = typeof r.unified === "string" ? r.unified : "";
264
319
  if (!unified)
265
320
  return `${header}\n(no changes)`;
266
321
  return `${header}\n${unified}`;
@@ -28540,6 +28540,7 @@ function shapeProposalEntry(entry, detail) {
28540
28540
  "confidence",
28541
28541
  "gateDecision",
28542
28542
  "review",
28543
+ "reviewHistory",
28543
28544
  "retirement"
28544
28545
  ]);
28545
28546
  }
@@ -28555,6 +28556,7 @@ function shapeProposalEntry(entry, detail) {
28555
28556
  "gateDecision",
28556
28557
  "payload",
28557
28558
  "review",
28559
+ "reviewHistory",
28558
28560
  "retirement",
28559
28561
  "retiredArchive",
28560
28562
  "promotionSource",
@@ -28619,7 +28621,10 @@ function shapeProposalDiffOutput(result, detail) {
28619
28621
  ref: result.ref,
28620
28622
  isNew: result.isNew,
28621
28623
  unified: result.unified,
28622
- ...result.targetPath !== undefined ? { targetPath: result.targetPath } : {}
28624
+ ...result.targetPath !== undefined ? { targetPath: result.targetPath } : {},
28625
+ ...result.op !== undefined ? { op: result.op } : {},
28626
+ ...result.retirement !== undefined ? { retirement: result.retirement } : {},
28627
+ ...result.note !== undefined ? { note: result.note } : {}
28623
28628
  };
28624
28629
  if (detail === "full") {
28625
28630
  return { schemaVersion: result.schemaVersion, ...base };
@@ -29041,6 +29046,7 @@ var PASSTHROUGH_COMMANDS = [
29041
29046
  "proposal-accept-batch",
29042
29047
  "proposal-drain",
29043
29048
  "proposal-reject-batch",
29049
+ "proposal-reopen-batch",
29044
29050
  "proposal-revert",
29045
29051
  "registry-add",
29046
29052
  "registry-list",
@@ -29112,6 +29118,14 @@ var proposalRejectShapes = [
29112
29118
  }
29113
29119
  ];
29114
29120
 
29121
+ // src/output/shapes/proposal/reopen.ts
29122
+ var proposalReopenShapes = [
29123
+ {
29124
+ command: "proposal-reopen",
29125
+ handler: (result, detail) => shapeProposalRejectOutput(result, detail)
29126
+ }
29127
+ ];
29128
+
29115
29129
  // src/output/shapes/proposal/show.ts
29116
29130
  var proposalShowShapes = [
29117
29131
  {
@@ -29202,6 +29216,7 @@ var BUILT_IN_OUTPUT_SHAPES = [
29202
29216
  ...proposalShowShapes,
29203
29217
  ...proposalAcceptShapes,
29204
29218
  ...proposalRejectShapes,
29219
+ ...proposalReopenShapes,
29205
29220
  ...proposalDiffShapes,
29206
29221
  ...proposalProducerShapes,
29207
29222
  ...envListShapes,
@@ -30423,6 +30438,31 @@ Generate one with \`akm improve <ref>\` or \`akm proposal new <type> <name> --ta
30423
30438
  return lines.join(`
30424
30439
  `).trimEnd();
30425
30440
  }
30441
+ function retireVerdictLines(retirement) {
30442
+ const lines = [
30443
+ `retire.label: ${String(retirement.judgeLabel)} (cosine=${String(retirement.cosine)})`,
30444
+ `retire.reason: ${String(retirement.judgeReason)}`
30445
+ ];
30446
+ const continuityRisk = retirement.continuityRisk;
30447
+ if (continuityRisk) {
30448
+ const failingQueries = typeof continuityRisk.failingQueries === "number" ? continuityRisk.failingQueries : 0;
30449
+ const unverifiedQueries = typeof continuityRisk.unverifiedQueries === "number" ? continuityRisk.unverifiedQueries : 0;
30450
+ const summary = [];
30451
+ if (failingQueries > 0) {
30452
+ summary.push(`${failingQueries} of the retired asset's own quer${failingQueries === 1 ? "y" : "ies"} would not have found the successor top 10`);
30453
+ }
30454
+ if (unverifiedQueries > 0) {
30455
+ summary.push(`${unverifiedQueries} quer${unverifiedQueries === 1 ? "y" : "ies"} unverified (search failed or used the keyword-only fallback)`);
30456
+ }
30457
+ lines.push(`retire.continuityRisk: ${summary.join("; ")} — excluded from bulk accept`);
30458
+ const ranks = Array.isArray(continuityRisk.ranks) ? continuityRisk.ranks : [];
30459
+ for (const rank of ranks) {
30460
+ const successorRank = rank.successorRank === null || rank.successorRank === undefined ? "absent from top 10" : `#${String(rank.successorRank)}`;
30461
+ lines.push(` - "${String(rank.query)}": retired #${String(rank.retiredRank)}, successor ${successorRank}`);
30462
+ }
30463
+ }
30464
+ return lines;
30465
+ }
30426
30466
  function formatProposalShowPlain(r) {
30427
30467
  const p = r.proposal;
30428
30468
  const lines = [];
@@ -30458,29 +30498,17 @@ function formatProposalShowPlain(r) {
30458
30498
  if (review.decidedAt)
30459
30499
  lines.push(`review.decidedAt: ${String(review.decidedAt)}`);
30460
30500
  }
30501
+ const history = Array.isArray(p.reviewHistory) ? p.reviewHistory : [];
30502
+ for (const entry of history) {
30503
+ const undone = entry.review;
30504
+ const was = undone ? `${String(undone.outcome ?? "?")}${undone.reason ? `: ${String(undone.reason)}` : ""} (${String(undone.decidedAt ?? "?")})` : "an unrecorded review";
30505
+ const why = entry.reopenReason ? ` (${String(entry.reopenReason)})` : "";
30506
+ lines.push(`reopened: ${String(entry.reopenedAt)}${why}, undoing ${was}`);
30507
+ }
30461
30508
  const retirement = p.retirement;
30462
30509
  if (retirement) {
30463
30510
  lines.push(`retire: ${String(retirement.retiredRef)} -> ${String(retirement.successorRef)}`);
30464
- lines.push(`retire.label: ${String(retirement.judgeLabel)} (cosine=${String(retirement.cosine)})`);
30465
- lines.push(`retire.reason: ${String(retirement.judgeReason)}`);
30466
- const continuityRisk = retirement.continuityRisk;
30467
- if (continuityRisk) {
30468
- const failingQueries = typeof continuityRisk.failingQueries === "number" ? continuityRisk.failingQueries : 0;
30469
- const unverifiedQueries = typeof continuityRisk.unverifiedQueries === "number" ? continuityRisk.unverifiedQueries : 0;
30470
- const summary = [];
30471
- if (failingQueries > 0) {
30472
- summary.push(`${failingQueries} of the retired asset's own quer${failingQueries === 1 ? "y" : "ies"} would not have found the successor top 10`);
30473
- }
30474
- if (unverifiedQueries > 0) {
30475
- summary.push(`${unverifiedQueries} quer${unverifiedQueries === 1 ? "y" : "ies"} unverified (search failed or used the keyword-only fallback)`);
30476
- }
30477
- lines.push(`retire.continuityRisk: ${summary.join("; ")} — excluded from bulk accept`);
30478
- const ranks = Array.isArray(continuityRisk.ranks) ? continuityRisk.ranks : [];
30479
- for (const rank of ranks) {
30480
- const successorRank = rank.successorRank === null || rank.successorRank === undefined ? "absent from top 10" : `#${String(rank.successorRank)}`;
30481
- lines.push(` - "${String(rank.query)}": retired #${String(rank.retiredRank)}, successor ${successorRank}`);
30482
- }
30483
- }
30511
+ lines.push(...retireVerdictLines(retirement));
30484
30512
  }
30485
30513
  const validation = r.validation;
30486
30514
  if (validation) {
@@ -30504,7 +30532,7 @@ function formatProposalShowPlain(r) {
30504
30532
  }
30505
30533
  }
30506
30534
  const payload = p.payload;
30507
- if (payload && typeof payload.content === "string") {
30535
+ if (!retirement && payload && typeof payload.content === "string") {
30508
30536
  lines.push("");
30509
30537
  lines.push("payload:");
30510
30538
  lines.push(payload.content);
@@ -30519,6 +30547,19 @@ function formatProposalRejectPlain(r) {
30519
30547
  const reason = r.reason ? ` (${String(r.reason)})` : "";
30520
30548
  return `Rejected proposal ${String(r.id)} (${String(r.ref)})${reason}`;
30521
30549
  }
30550
+ function formatProposalReopenPlain(r) {
30551
+ const reason = r.reason ? ` (${String(r.reason)})` : "";
30552
+ return `Reopened proposal ${String(r.id)} (${String(r.ref)}) [pending]${reason}`;
30553
+ }
30554
+ function formatProposalReopenBatchPlain(r) {
30555
+ const results = Array.isArray(r.results) ? r.results : [];
30556
+ const reason = results[0]?.reason ? ` (${String(results[0].reason)})` : "";
30557
+ return [
30558
+ `Reopened ${results.length} proposal(s) [pending]${reason}`,
30559
+ ...results.map((result) => ` ${String(result.id)} ${String(result.ref)}`)
30560
+ ].join(`
30561
+ `);
30562
+ }
30522
30563
  function formatProposalDrainPlain(r) {
30523
30564
  const applyMode = String(r.applyMode ?? "queue");
30524
30565
  const promoted = Array.isArray(r.promoted) ? r.promoted : [];
@@ -30548,8 +30589,21 @@ function formatProposalDrainPlain(r) {
30548
30589
  `).trimEnd();
30549
30590
  }
30550
30591
  function formatProposalDiffPlain(r) {
30551
- const header = r.isNew ? `# proposal ${String(r.id)} (new asset: ${String(r.ref)})` : `# proposal ${String(r.id)} (update: ${String(r.ref)})`;
30552
30592
  const unified = typeof r.unified === "string" ? r.unified : "";
30593
+ if (r.op === "delete") {
30594
+ const retirement = r.retirement;
30595
+ const subject = retirement ? `${String(retirement.retiredRef)} -> ${String(retirement.successorRef)}` : String(r.ref);
30596
+ const lines = [`# proposal ${String(r.id)} (retire: ${subject})`];
30597
+ if (retirement)
30598
+ lines.push(...retireVerdictLines(retirement));
30599
+ if (typeof r.note === "string")
30600
+ lines.push(`note: ${r.note}`);
30601
+ if (unified)
30602
+ lines.push(unified);
30603
+ return lines.join(`
30604
+ `);
30605
+ }
30606
+ const header = r.isNew ? `# proposal ${String(r.id)} (new asset: ${String(r.ref)})` : `# proposal ${String(r.id)} (update: ${String(r.ref)})`;
30553
30607
  if (!unified)
30554
30608
  return `${header}
30555
30609
  (no changes)`;
@@ -52915,6 +52969,8 @@ var proposalFormatters = [
52915
52969
  { command: "proposal-show", handler: (r) => formatProposalShowPlain(r) },
52916
52970
  { command: "proposal-accept", handler: (r) => formatProposalAcceptPlain(r) },
52917
52971
  { command: "proposal-reject", handler: (r) => formatProposalRejectPlain(r) },
52972
+ { command: "proposal-reopen", handler: (r) => formatProposalReopenPlain(r) },
52973
+ { command: "proposal-reopen-batch", handler: (r) => formatProposalReopenBatchPlain(r) },
52918
52974
  { command: "proposal-diff", handler: (r) => formatProposalDiffPlain(r) },
52919
52975
  { command: "proposal-drain", handler: (r) => formatProposalDrainPlain(r) }
52920
52976
  ];
@@ -27868,6 +27868,7 @@ function shapeProposalEntry(entry, detail) {
27868
27868
  "confidence",
27869
27869
  "gateDecision",
27870
27870
  "review",
27871
+ "reviewHistory",
27871
27872
  "retirement"
27872
27873
  ]);
27873
27874
  }
@@ -27883,6 +27884,7 @@ function shapeProposalEntry(entry, detail) {
27883
27884
  "gateDecision",
27884
27885
  "payload",
27885
27886
  "review",
27887
+ "reviewHistory",
27886
27888
  "retirement",
27887
27889
  "retiredArchive",
27888
27890
  "promotionSource",
@@ -27947,7 +27949,10 @@ function shapeProposalDiffOutput(result, detail) {
27947
27949
  ref: result.ref,
27948
27950
  isNew: result.isNew,
27949
27951
  unified: result.unified,
27950
- ...result.targetPath !== undefined ? { targetPath: result.targetPath } : {}
27952
+ ...result.targetPath !== undefined ? { targetPath: result.targetPath } : {},
27953
+ ...result.op !== undefined ? { op: result.op } : {},
27954
+ ...result.retirement !== undefined ? { retirement: result.retirement } : {},
27955
+ ...result.note !== undefined ? { note: result.note } : {}
27951
27956
  };
27952
27957
  if (detail === "full") {
27953
27958
  return { schemaVersion: result.schemaVersion, ...base };
@@ -28369,6 +28374,7 @@ var PASSTHROUGH_COMMANDS = [
28369
28374
  "proposal-accept-batch",
28370
28375
  "proposal-drain",
28371
28376
  "proposal-reject-batch",
28377
+ "proposal-reopen-batch",
28372
28378
  "proposal-revert",
28373
28379
  "registry-add",
28374
28380
  "registry-list",
@@ -28440,6 +28446,14 @@ var proposalRejectShapes = [
28440
28446
  }
28441
28447
  ];
28442
28448
 
28449
+ // src/output/shapes/proposal/reopen.ts
28450
+ var proposalReopenShapes = [
28451
+ {
28452
+ command: "proposal-reopen",
28453
+ handler: (result, detail) => shapeProposalRejectOutput(result, detail)
28454
+ }
28455
+ ];
28456
+
28443
28457
  // src/output/shapes/proposal/show.ts
28444
28458
  var proposalShowShapes = [
28445
28459
  {
@@ -28530,6 +28544,7 @@ var BUILT_IN_OUTPUT_SHAPES = [
28530
28544
  ...proposalShowShapes,
28531
28545
  ...proposalAcceptShapes,
28532
28546
  ...proposalRejectShapes,
28547
+ ...proposalReopenShapes,
28533
28548
  ...proposalDiffShapes,
28534
28549
  ...proposalProducerShapes,
28535
28550
  ...envListShapes,
@@ -29751,6 +29766,31 @@ Generate one with \`akm improve <ref>\` or \`akm proposal new <type> <name> --ta
29751
29766
  return lines.join(`
29752
29767
  `).trimEnd();
29753
29768
  }
29769
+ function retireVerdictLines(retirement) {
29770
+ const lines = [
29771
+ `retire.label: ${String(retirement.judgeLabel)} (cosine=${String(retirement.cosine)})`,
29772
+ `retire.reason: ${String(retirement.judgeReason)}`
29773
+ ];
29774
+ const continuityRisk = retirement.continuityRisk;
29775
+ if (continuityRisk) {
29776
+ const failingQueries = typeof continuityRisk.failingQueries === "number" ? continuityRisk.failingQueries : 0;
29777
+ const unverifiedQueries = typeof continuityRisk.unverifiedQueries === "number" ? continuityRisk.unverifiedQueries : 0;
29778
+ const summary = [];
29779
+ if (failingQueries > 0) {
29780
+ summary.push(`${failingQueries} of the retired asset's own quer${failingQueries === 1 ? "y" : "ies"} would not have found the successor top 10`);
29781
+ }
29782
+ if (unverifiedQueries > 0) {
29783
+ summary.push(`${unverifiedQueries} quer${unverifiedQueries === 1 ? "y" : "ies"} unverified (search failed or used the keyword-only fallback)`);
29784
+ }
29785
+ lines.push(`retire.continuityRisk: ${summary.join("; ")} \u2014 excluded from bulk accept`);
29786
+ const ranks = Array.isArray(continuityRisk.ranks) ? continuityRisk.ranks : [];
29787
+ for (const rank of ranks) {
29788
+ const successorRank = rank.successorRank === null || rank.successorRank === undefined ? "absent from top 10" : `#${String(rank.successorRank)}`;
29789
+ lines.push(` - "${String(rank.query)}": retired #${String(rank.retiredRank)}, successor ${successorRank}`);
29790
+ }
29791
+ }
29792
+ return lines;
29793
+ }
29754
29794
  function formatProposalShowPlain(r) {
29755
29795
  const p = r.proposal;
29756
29796
  const lines = [];
@@ -29786,29 +29826,17 @@ function formatProposalShowPlain(r) {
29786
29826
  if (review.decidedAt)
29787
29827
  lines.push(`review.decidedAt: ${String(review.decidedAt)}`);
29788
29828
  }
29829
+ const history = Array.isArray(p.reviewHistory) ? p.reviewHistory : [];
29830
+ for (const entry of history) {
29831
+ const undone = entry.review;
29832
+ const was = undone ? `${String(undone.outcome ?? "?")}${undone.reason ? `: ${String(undone.reason)}` : ""} (${String(undone.decidedAt ?? "?")})` : "an unrecorded review";
29833
+ const why = entry.reopenReason ? ` (${String(entry.reopenReason)})` : "";
29834
+ lines.push(`reopened: ${String(entry.reopenedAt)}${why}, undoing ${was}`);
29835
+ }
29789
29836
  const retirement = p.retirement;
29790
29837
  if (retirement) {
29791
29838
  lines.push(`retire: ${String(retirement.retiredRef)} -> ${String(retirement.successorRef)}`);
29792
- lines.push(`retire.label: ${String(retirement.judgeLabel)} (cosine=${String(retirement.cosine)})`);
29793
- lines.push(`retire.reason: ${String(retirement.judgeReason)}`);
29794
- const continuityRisk = retirement.continuityRisk;
29795
- if (continuityRisk) {
29796
- const failingQueries = typeof continuityRisk.failingQueries === "number" ? continuityRisk.failingQueries : 0;
29797
- const unverifiedQueries = typeof continuityRisk.unverifiedQueries === "number" ? continuityRisk.unverifiedQueries : 0;
29798
- const summary = [];
29799
- if (failingQueries > 0) {
29800
- summary.push(`${failingQueries} of the retired asset's own quer${failingQueries === 1 ? "y" : "ies"} would not have found the successor top 10`);
29801
- }
29802
- if (unverifiedQueries > 0) {
29803
- summary.push(`${unverifiedQueries} quer${unverifiedQueries === 1 ? "y" : "ies"} unverified (search failed or used the keyword-only fallback)`);
29804
- }
29805
- lines.push(`retire.continuityRisk: ${summary.join("; ")} \u2014 excluded from bulk accept`);
29806
- const ranks = Array.isArray(continuityRisk.ranks) ? continuityRisk.ranks : [];
29807
- for (const rank of ranks) {
29808
- const successorRank = rank.successorRank === null || rank.successorRank === undefined ? "absent from top 10" : `#${String(rank.successorRank)}`;
29809
- lines.push(` - "${String(rank.query)}": retired #${String(rank.retiredRank)}, successor ${successorRank}`);
29810
- }
29811
- }
29839
+ lines.push(...retireVerdictLines(retirement));
29812
29840
  }
29813
29841
  const validation = r.validation;
29814
29842
  if (validation) {
@@ -29832,7 +29860,7 @@ function formatProposalShowPlain(r) {
29832
29860
  }
29833
29861
  }
29834
29862
  const payload = p.payload;
29835
- if (payload && typeof payload.content === "string") {
29863
+ if (!retirement && payload && typeof payload.content === "string") {
29836
29864
  lines.push("");
29837
29865
  lines.push("payload:");
29838
29866
  lines.push(payload.content);
@@ -29847,6 +29875,19 @@ function formatProposalRejectPlain(r) {
29847
29875
  const reason = r.reason ? ` (${String(r.reason)})` : "";
29848
29876
  return `Rejected proposal ${String(r.id)} (${String(r.ref)})${reason}`;
29849
29877
  }
29878
+ function formatProposalReopenPlain(r) {
29879
+ const reason = r.reason ? ` (${String(r.reason)})` : "";
29880
+ return `Reopened proposal ${String(r.id)} (${String(r.ref)}) [pending]${reason}`;
29881
+ }
29882
+ function formatProposalReopenBatchPlain(r) {
29883
+ const results = Array.isArray(r.results) ? r.results : [];
29884
+ const reason = results[0]?.reason ? ` (${String(results[0].reason)})` : "";
29885
+ return [
29886
+ `Reopened ${results.length} proposal(s) [pending]${reason}`,
29887
+ ...results.map((result) => ` ${String(result.id)} ${String(result.ref)}`)
29888
+ ].join(`
29889
+ `);
29890
+ }
29850
29891
  function formatProposalDrainPlain(r) {
29851
29892
  const applyMode = String(r.applyMode ?? "queue");
29852
29893
  const promoted = Array.isArray(r.promoted) ? r.promoted : [];
@@ -29876,8 +29917,21 @@ function formatProposalDrainPlain(r) {
29876
29917
  `).trimEnd();
29877
29918
  }
29878
29919
  function formatProposalDiffPlain(r) {
29879
- const header = r.isNew ? `# proposal ${String(r.id)} (new asset: ${String(r.ref)})` : `# proposal ${String(r.id)} (update: ${String(r.ref)})`;
29880
29920
  const unified = typeof r.unified === "string" ? r.unified : "";
29921
+ if (r.op === "delete") {
29922
+ const retirement = r.retirement;
29923
+ const subject = retirement ? `${String(retirement.retiredRef)} -> ${String(retirement.successorRef)}` : String(r.ref);
29924
+ const lines = [`# proposal ${String(r.id)} (retire: ${subject})`];
29925
+ if (retirement)
29926
+ lines.push(...retireVerdictLines(retirement));
29927
+ if (typeof r.note === "string")
29928
+ lines.push(`note: ${r.note}`);
29929
+ if (unified)
29930
+ lines.push(unified);
29931
+ return lines.join(`
29932
+ `);
29933
+ }
29934
+ const header = r.isNew ? `# proposal ${String(r.id)} (new asset: ${String(r.ref)})` : `# proposal ${String(r.id)} (update: ${String(r.ref)})`;
29881
29935
  if (!unified)
29882
29936
  return `${header}
29883
29937
  (no changes)`;
@@ -52910,6 +52964,8 @@ var proposalFormatters = [
52910
52964
  { command: "proposal-show", handler: (r) => formatProposalShowPlain(r) },
52911
52965
  { command: "proposal-accept", handler: (r) => formatProposalAcceptPlain(r) },
52912
52966
  { command: "proposal-reject", handler: (r) => formatProposalRejectPlain(r) },
52967
+ { command: "proposal-reopen", handler: (r) => formatProposalReopenPlain(r) },
52968
+ { command: "proposal-reopen-batch", handler: (r) => formatProposalReopenBatchPlain(r) },
52913
52969
  { command: "proposal-diff", handler: (r) => formatProposalDiffPlain(r) },
52914
52970
  { command: "proposal-drain", handler: (r) => formatProposalDrainPlain(r) }
52915
52971
  ];