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.
- package/CHANGELOG.md +277 -1694
- package/STABILITY.md +9 -8
- package/dist/assets/hints/cli-hints-full.md +6 -7
- package/dist/assets/improve-strategies/catchup.json +0 -3
- package/dist/assets/improve-strategies/consolidate.json +0 -1
- package/dist/assets/improve-strategies/default.json +1 -2
- package/dist/assets/improve-strategies/proactive-maintenance.json +1 -2
- package/dist/assets/improve-strategies/quick.json +1 -2
- package/dist/assets/improve-strategies/reflect-distill.json +1 -2
- package/dist/assets/improve-strategies/thorough.json +0 -3
- package/dist/assets/prompts/consolidate-pair.md +20 -0
- package/dist/assets/stash-skeleton/facts/conventions/backlinks.md +17 -19
- package/dist/assets/stash-skeleton/facts/conventions/domains.md +2 -2
- package/dist/assets/templates/html/health.html +3 -5
- package/dist/cli/retired-commands.js +1 -1
- package/dist/cli/unknown-flags.js +24 -1
- package/dist/cli.js +46 -1
- package/dist/commands/health/archive-usage.js +92 -0
- package/dist/commands/health/data-dir-usage.js +25 -13
- package/dist/commands/health/html-report.js +1 -4
- package/dist/commands/health/improve-metrics.js +25 -37
- package/dist/commands/health/md-report.js +1 -6
- package/dist/commands/health/report-view-model.js +4 -14
- package/dist/commands/health/windows.js +0 -1
- package/dist/commands/health.js +13 -0
- package/dist/commands/improve/consolidate/continuity-check.js +137 -0
- package/dist/commands/improve/consolidate/pair-pass.js +791 -0
- package/dist/commands/improve/consolidate.js +38 -63
- package/dist/commands/improve/extract-prompt.js +1 -2
- package/dist/commands/improve/improve-cli.js +1 -1
- package/dist/commands/improve/improve-strategies.js +23 -5
- package/dist/commands/improve/improve.js +19 -30
- package/dist/commands/improve/ledger.js +3 -2
- package/dist/commands/improve/loop-stages.js +5 -85
- package/dist/commands/improve/memory/memory-belief.js +3 -1
- package/dist/commands/improve/memory/memory-improve.js +262 -11
- package/dist/commands/improve/planner.js +0 -5
- package/dist/commands/improve/preparation.js +20 -135
- package/dist/commands/improve/retrieval-scope.js +19 -4
- package/dist/commands/improve/salience.js +1 -14
- package/dist/commands/improve/stage.js +0 -1
- package/dist/commands/lint/base-linter.js +19 -11
- package/dist/commands/proposal/drain.js +8 -1
- package/dist/commands/proposal/proposal-cli.js +16 -2
- package/dist/commands/proposal/proposal-types.js +7 -0
- package/dist/commands/proposal/proposal.js +37 -6
- package/dist/commands/proposal/repository.js +613 -4
- package/dist/commands/proposal/validators/proposals.js +9 -0
- package/dist/commands/read/knowledge.js +3 -2
- package/dist/commands/read/show.js +0 -14
- package/dist/commands/sources/info.js +122 -18
- package/dist/commands/sources/stash-cli.js +23 -3
- package/dist/core/bundle-rename.js +1 -7
- package/dist/core/config/config-schema.js +8 -1
- package/dist/core/config/config.js +23 -48
- package/dist/core/config/engine-semantics.js +0 -2
- package/dist/core/config/schema/improve-processes.js +17 -42
- package/dist/core/config/schema/index-config.js +5 -25
- package/dist/core/file-change.js +13 -5
- package/dist/core/improve-result.js +22 -6
- package/dist/core/improve-types.js +0 -1
- package/dist/core/loopback.js +7 -12
- package/dist/core/parse.js +13 -16
- package/dist/core/state/migrations.js +15 -0
- package/dist/core/time.js +0 -20
- package/dist/indexer/db/llm-cache.js +2 -2
- package/dist/indexer/ensure-index.js +2 -2
- package/dist/indexer/index-written-assets.js +2 -3
- package/dist/indexer/indexer.js +18 -418
- package/dist/indexer/passes/metadata.js +0 -19
- package/dist/indexer/walk/walker.js +3 -4
- package/dist/llm/client.js +8 -10
- package/dist/llm/embedders/remote.js +1 -2
- package/dist/llm/feature-gate.js +0 -5
- package/dist/output/shapes/helpers.js +20 -4
- package/dist/output/text/command-format.js +9 -8
- package/dist/output/text/proposal-format.js +47 -1
- package/dist/output/text/show-format.js +0 -20
- package/dist/scripts/akm-migrate-node.js +923 -950
- package/dist/scripts/akm-migrate.js +923 -950
- package/dist/setup/steps/connection.js +5 -6
- package/dist/setup/steps/platforms.js +2 -2
- package/dist/sources/providers/git-stash.js +83 -4
- package/dist/storage/repositories/improve-ledger-repository.js +48 -7
- package/dist/storage/repositories/index-connection.js +5 -2
- package/dist/storage/repositories/index-entries-repository.js +4 -7
- package/dist/storage/repositories/index-entry-schema.js +4 -2
- package/dist/storage/repositories/index-llm-cache-repository.js +7 -26
- package/dist/storage/repositories/index-schema.js +55 -104
- package/dist/storage/repositories/proposals-repository.js +61 -0
- package/dist/storage/repositories/salience-repository.js +1 -19
- package/docs/migration/README.md +1 -1
- package/docs/migration/release-notes/0.9.17.md +130 -41
- package/docs/migration/release-notes/README.md +7 -0
- package/docs/reference/cli.md +27 -21
- package/docs/reference/configuration.md +21 -12
- package/docs/reference/data-and-telemetry.md +0 -1
- package/package.json +1 -1
- package/schemas/akm-config.json +0 -342
- package/dist/assets/improve-strategies/graph-refresh.json +0 -15
- package/dist/assets/prompts/contradiction-judge.md +0 -33
- package/dist/assets/prompts/graph-extract-system.md +0 -1
- package/dist/assets/prompts/graph-extract-user-prompt.md +0 -35
- package/dist/assets/prompts/metadata-enhance-system.md +0 -1
- package/dist/assets/tasks/improve/akm-graph-refresh-weekly.yml +0 -4
- package/dist/indexer/db/graph-db.js +0 -399
- package/dist/indexer/graph/graph-extraction.js +0 -809
- package/dist/indexer/graph/graph-related.js +0 -131
- package/dist/indexer/graph/graph-types.js +0 -4
- package/dist/llm/graph-extract.js +0 -892
- package/dist/llm/metadata-enhance.js +0 -95
|
@@ -204,12 +204,14 @@ export function refExistsInAnyStash(relPath, refType, refName, stashRoots) {
|
|
|
204
204
|
if (resolveRefPathInStash(relPath, refType, refName, root) !== null)
|
|
205
205
|
return true;
|
|
206
206
|
}
|
|
207
|
-
// #884:
|
|
208
|
-
//
|
|
209
|
-
//
|
|
210
|
-
//
|
|
211
|
-
//
|
|
212
|
-
//
|
|
207
|
+
// #884: an asset `analyzeMemoryCleanup` pruned, or (alpha.9) a consolidate
|
|
208
|
+
// pair-pass `retire` proposal or a promotion's source memory retired, was
|
|
209
|
+
// ARCHIVED, not deleted — its bytes and identity live on under
|
|
210
|
+
// `.akm/memory-cleanup/archive`. Inbound refs to it are satisfied, not
|
|
211
|
+
// dangling, so resolve the tombstone rather than reporting `missing-ref`.
|
|
212
|
+
// Checked only after every live location misses: a tombstone must never
|
|
213
|
+
// shadow a real file, and the scan then costs one directory read per root
|
|
214
|
+
// instead of one per ref.
|
|
213
215
|
//
|
|
214
216
|
// Existence ONLY. `resolveRefPathInStash` deliberately does NOT consult the
|
|
215
217
|
// archive: it hands back a path callers MUTATE (SPEC-5 `--supersedes`
|
|
@@ -231,13 +233,19 @@ function refPathCandidates(refType, typeDir, refName) {
|
|
|
231
233
|
return [...candidates, assetPathForName(refType, typeDir, `${refName}${DERIVED_SUFFIX}`)];
|
|
232
234
|
}
|
|
233
235
|
/**
|
|
234
|
-
* True when `(refType, refName)` names
|
|
235
|
-
* root. Mirrors `resolveRefPathInStash`'s candidate set
|
|
236
|
-
* through the `.derived.md` child (#882) still
|
|
236
|
+
* True when `(refType, refName)` names an asset the cleanup archive holds a
|
|
237
|
+
* tombstone for, in any root. Mirrors `resolveRefPathInStash`'s candidate set
|
|
238
|
+
* so a memory ref that resolved through the `.derived.md` child (#882) still
|
|
239
|
+
* resolves once archived.
|
|
240
|
+
*
|
|
241
|
+
* Originally memory-only (#884: only `.derived` memories were ever pruned).
|
|
242
|
+
* 0.9.17-alpha.9 generalized `archiveCleanupCandidate` to any memory,
|
|
243
|
+
* knowledge or lesson file (a consolidate pair-pass `retire` proposal, or an
|
|
244
|
+
* accepted promotion's source memory), so this must check every type, not
|
|
245
|
+
* just `memory` — otherwise an xref to a retired knowledge or lesson asset
|
|
246
|
+
* reports `missing-ref` even though it resolves fine through the tombstone.
|
|
237
247
|
*/
|
|
238
248
|
function memoryArchiveHasRef(refType, refName, stashRoots) {
|
|
239
|
-
if (refType !== "memory")
|
|
240
|
-
return false; // only memories are ever archived
|
|
241
249
|
const typeDir = stashDirFor(refType);
|
|
242
250
|
if (typeDir === undefined)
|
|
243
251
|
return false;
|
|
@@ -29,7 +29,7 @@ import { buildExecution, resolveExecution } from "../../integrations/agent/execu
|
|
|
29
29
|
import { assertRunnerCredentials, runExecution, } from "../../integrations/agent/runner-dispatch.js";
|
|
30
30
|
import { errMessage, noticeSet } from "../improve/stage.js";
|
|
31
31
|
import { akmProposalAccept, akmProposalReject } from "./proposal.js";
|
|
32
|
-
import { STALE_TARGET_GATE_REASON } from "./proposal-types.js";
|
|
32
|
+
import { isRetireProposal, STALE_TARGET_GATE_REASON } from "./proposal-types.js";
|
|
33
33
|
import { listProposals, listProposalsReadOnly, preflightProposalPromotion, proposalContent, proposalContentHash, readFreshProposalTarget, recordGateDecision, } from "./repository.js";
|
|
34
34
|
/** The gate label on every decision the drain records. */
|
|
35
35
|
const DRAIN_GATE = "triage";
|
|
@@ -305,6 +305,13 @@ export async function drainProposals(opts, promoteFn = akmProposalAccept, reject
|
|
|
305
305
|
const accepts = [];
|
|
306
306
|
const empties = [];
|
|
307
307
|
for (const proposal of pending) {
|
|
308
|
+
// A consolidate pair-pass `retire` proposal is never auto-decided here,
|
|
309
|
+
// whatever `applyMode` says (alpha.9 brief §A "Review"; spec §25.6):
|
|
310
|
+
// untouched, still pending, waiting for a direct `akm proposal accept`.
|
|
311
|
+
// Checked before isEmptyDiff, which reads proposalContent() and has
|
|
312
|
+
// nothing meaningful to read on a delete-primary change anyway.
|
|
313
|
+
if (isRetireProposal(proposal))
|
|
314
|
+
continue;
|
|
308
315
|
const decision = proposal.gateDecision;
|
|
309
316
|
// Another gate's rejection stands; a human-review deferral from the distill
|
|
310
317
|
// quality gate is left for that human.
|
|
@@ -89,6 +89,10 @@ const proposalListCommand = defineJsonCommand({
|
|
|
89
89
|
},
|
|
90
90
|
ref: { type: "string", description: "Filter by asset ref ([bundle//]conceptId, e.g. knowledge/guide.md)" },
|
|
91
91
|
type: { type: "string", description: "Filter by asset type" },
|
|
92
|
+
generator: {
|
|
93
|
+
type: "string",
|
|
94
|
+
description: "Filter by generator/source (e.g. reflect, distill, consolidate-pair) — same value accept/reject --generator take.",
|
|
95
|
+
},
|
|
92
96
|
},
|
|
93
97
|
run({ args }) {
|
|
94
98
|
const status = parseProposalStatus(args.status);
|
|
@@ -97,6 +101,7 @@ const proposalListCommand = defineJsonCommand({
|
|
|
97
101
|
status,
|
|
98
102
|
ref: args.ref,
|
|
99
103
|
type: args.type,
|
|
104
|
+
generator: args.generator,
|
|
100
105
|
includeArchive: status === "accepted" || status === "rejected" || status === "reverted",
|
|
101
106
|
});
|
|
102
107
|
output("proposal-list", result);
|
|
@@ -149,7 +154,7 @@ const proposalAcceptCommand = defineJsonCommand({
|
|
|
149
154
|
return;
|
|
150
155
|
}
|
|
151
156
|
const { maxDiffLines, olderThanMs } = parseBulkFilterFlags(args);
|
|
152
|
-
const { count, results } = await bulkAdjudicateProposals({
|
|
157
|
+
const { count, results, skippedForContinuityRisk } = await bulkAdjudicateProposals({
|
|
153
158
|
action: "accept",
|
|
154
159
|
generator,
|
|
155
160
|
maxDiffLines,
|
|
@@ -158,7 +163,16 @@ const proposalAcceptCommand = defineJsonCommand({
|
|
|
158
163
|
queue: args.queue,
|
|
159
164
|
target: args.target,
|
|
160
165
|
});
|
|
161
|
-
output("proposal-accept-batch", {
|
|
166
|
+
output("proposal-accept-batch", {
|
|
167
|
+
accepted: count,
|
|
168
|
+
results,
|
|
169
|
+
// S4: how many otherwise-matching proposals were skipped specifically
|
|
170
|
+
// because they carry retirement.continuityRisk — visible under
|
|
171
|
+
// --dry-run and on a real run alike, distinct from an ordinary
|
|
172
|
+
// --max-diff-lines/--older-than miss.
|
|
173
|
+
skippedForContinuityRisk,
|
|
174
|
+
dryRun: args["dry-run"],
|
|
175
|
+
});
|
|
162
176
|
return;
|
|
163
177
|
}
|
|
164
178
|
if (!args.id) {
|
|
@@ -9,6 +9,8 @@ export const PROPOSAL_SOURCES = [
|
|
|
9
9
|
"reflect",
|
|
10
10
|
"distill",
|
|
11
11
|
"consolidate",
|
|
12
|
+
/** The consolidate pair pass's own retire proposals (alpha.9, S6) — kept apart from `consolidate`'s promotions so a bulk `accept --generator consolidate` never sweeps a retirement, and the reverse. */
|
|
13
|
+
"consolidate-pair",
|
|
12
14
|
"extract",
|
|
13
15
|
"improve",
|
|
14
16
|
"feedback",
|
|
@@ -23,6 +25,7 @@ export const AUTOMATED_PROPOSAL_SOURCES = [
|
|
|
23
25
|
"reflect",
|
|
24
26
|
"distill",
|
|
25
27
|
"consolidate",
|
|
28
|
+
"consolidate-pair",
|
|
26
29
|
"extract",
|
|
27
30
|
"improve",
|
|
28
31
|
"schema-repair",
|
|
@@ -33,6 +36,10 @@ export function isValidProposalSource(source) {
|
|
|
33
36
|
export function isAutomatedProposalSource(source) {
|
|
34
37
|
return AUTOMATED_PROPOSAL_SOURCES.includes(source);
|
|
35
38
|
}
|
|
39
|
+
/** A pending or accepted proposal whose primary change deletes its target (a consolidate retire proposal, alpha.9). */
|
|
40
|
+
export function isRetireProposal(proposal) {
|
|
41
|
+
return proposal.changes[0]?.op === "delete";
|
|
42
|
+
}
|
|
36
43
|
/** A promote refused because the target changed after mint (STALE, R20) — not a merit judgement. */
|
|
37
44
|
export const STALE_TARGET_GATE_REASON = "stale-target";
|
|
38
45
|
export const EXPIRED_GATE_REASON = "expired";
|
|
@@ -15,6 +15,7 @@ import { resolveStashDir } from "../../core/common.js";
|
|
|
15
15
|
import { loadConfig } from "../../core/config/config.js";
|
|
16
16
|
import { resolveWriteTarget } from "../../core/write-source.js";
|
|
17
17
|
import { withAssetMutationLease } from "../../indexer/index-writer-lock.js";
|
|
18
|
+
import { isRetireProposal } from "./proposal-types.js";
|
|
18
19
|
import { diffProposal, listProposals, preflightProposalPromotion, promoteProposal, proposalContent, rejectProposalDurably, resolveProposalId, revertProposal, } from "./repository.js";
|
|
19
20
|
import { validateProposal } from "./validators/proposals.js";
|
|
20
21
|
// ── Shared helpers ──────────────────────────────────────────────────────────
|
|
@@ -55,7 +56,7 @@ export function akmProposalList(options = {}) {
|
|
|
55
56
|
status: options.status,
|
|
56
57
|
ref: options.ref,
|
|
57
58
|
type: options.type,
|
|
58
|
-
});
|
|
59
|
+
}).filter((p) => options.generator === undefined || p.source === options.generator);
|
|
59
60
|
return { schemaVersion: 1, totalCount: proposals.length, proposals };
|
|
60
61
|
}
|
|
61
62
|
export function akmProposalShow(options) {
|
|
@@ -64,9 +65,13 @@ export function akmProposalShow(options) {
|
|
|
64
65
|
const proposal = resolveProposalId(stash, options.id);
|
|
65
66
|
let validation = validateProposal(proposal);
|
|
66
67
|
// An explicit stashDir without config is an in-process storage test seam; it
|
|
67
|
-
// has no authenticated write-target context to preflight against.
|
|
68
|
+
// has no authenticated write-target context to preflight against. A retire
|
|
69
|
+
// proposal writes no content — preflightProposalPromotion's stamp/lint
|
|
70
|
+
// machinery is create/update-shaped and has nothing meaningful to check
|
|
71
|
+
// here; `diff` already shows the body being retired.
|
|
68
72
|
if (validation.ok &&
|
|
69
73
|
proposal.status === "pending" &&
|
|
74
|
+
!isRetireProposal(proposal) &&
|
|
70
75
|
(options.config !== undefined || options.stashDir === undefined)) {
|
|
71
76
|
try {
|
|
72
77
|
preflightProposalPromotion(options.config ?? loadConfig(), proposal, { queueTarget: queue.target });
|
|
@@ -161,6 +166,16 @@ export async function akmProposalRevert(options) {
|
|
|
161
166
|
proposal: result.proposal,
|
|
162
167
|
};
|
|
163
168
|
}
|
|
169
|
+
/** The retired file's current line count for `--max-diff-lines` (S6); unresolvable is never size-filtered here — the real accept/reject attempt fails cleanly on a genuinely stale target. */
|
|
170
|
+
function retiredTargetLineCount(stashDir, config, proposal, queueTarget) {
|
|
171
|
+
try {
|
|
172
|
+
const existing = diffProposal(stashDir, config, proposal.id, { queueTarget }).existing;
|
|
173
|
+
return existing === null ? 0 : existing.split("\n").length;
|
|
174
|
+
}
|
|
175
|
+
catch {
|
|
176
|
+
return 0;
|
|
177
|
+
}
|
|
178
|
+
}
|
|
164
179
|
/**
|
|
165
180
|
* Bulk accept/reject every pending proposal from one generator, applying the
|
|
166
181
|
* shared `--max-diff-lines` / `--older-than` filters. Consolidates the two
|
|
@@ -170,12 +185,21 @@ export async function akmProposalRevert(options) {
|
|
|
170
185
|
*/
|
|
171
186
|
export async function bulkAdjudicateProposals(options) {
|
|
172
187
|
const config = options.config ?? loadConfig();
|
|
173
|
-
const { stashDir } = resolveProposalQueue(options.stashDir, options.queue, config);
|
|
174
|
-
|
|
188
|
+
const { stashDir, target: queueTarget } = resolveProposalQueue(options.stashDir, options.queue, config);
|
|
189
|
+
// Every filter EXCEPT the continuityRisk exclusion below — matched against
|
|
190
|
+
// separately so its own count (S4) can be reported apart from an ordinary
|
|
191
|
+
// --max-diff-lines/--older-than miss.
|
|
192
|
+
const matched = listProposals(stashDir, { status: "pending" }).filter((p) => {
|
|
175
193
|
if (p.source !== options.generator)
|
|
176
194
|
return false;
|
|
177
195
|
if (options.maxDiffLines !== undefined) {
|
|
178
|
-
|
|
196
|
+
// S6: a retire proposal's own payload is empty (it deletes its
|
|
197
|
+
// target) — proposalContent() would always read as 1 line, so
|
|
198
|
+
// --max-diff-lines could never filter one out. Count the retired
|
|
199
|
+
// file's own current line count instead.
|
|
200
|
+
const lines = isRetireProposal(p)
|
|
201
|
+
? retiredTargetLineCount(stashDir, config, p, queueTarget)
|
|
202
|
+
: proposalContent(p).split("\n").length;
|
|
179
203
|
if (lines > options.maxDiffLines)
|
|
180
204
|
return false;
|
|
181
205
|
}
|
|
@@ -186,6 +210,13 @@ export async function bulkAdjudicateProposals(options) {
|
|
|
186
210
|
}
|
|
187
211
|
return true;
|
|
188
212
|
});
|
|
213
|
+
// Item 1 (continuity check, alpha.9 plan §5.4, rule R3): a retire proposal
|
|
214
|
+
// the check flagged is never bulk-accepted, by generator or any other
|
|
215
|
+
// sweep — only a person accepting it by id can. Bulk reject is unaffected:
|
|
216
|
+
// declining a risky proposal is never the unsafe direction.
|
|
217
|
+
const isContinuityExcluded = (p) => options.action === "accept" && Boolean(p.retirement?.continuityRisk);
|
|
218
|
+
const skippedForContinuityRisk = matched.filter(isContinuityExcluded).length;
|
|
219
|
+
const pending = matched.filter((p) => !isContinuityExcluded(p));
|
|
189
220
|
const results = [];
|
|
190
221
|
for (const proposal of pending) {
|
|
191
222
|
if (options.dryRun) {
|
|
@@ -198,5 +229,5 @@ export async function bulkAdjudicateProposals(options) {
|
|
|
198
229
|
results.push(await akmProposalReject({ stashDir, id: proposal.id, queue: options.queue, reason: options.reason, config }));
|
|
199
230
|
}
|
|
200
231
|
}
|
|
201
|
-
return { count: results.length, results };
|
|
232
|
+
return { count: results.length, results, skippedForContinuityRisk };
|
|
202
233
|
}
|