akm-cli 0.9.0-beta.6 → 0.9.0-beta.9
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 +71 -0
- package/dist/cli.js +7 -0
- package/dist/commands/feedback-cli.js +42 -37
- package/dist/commands/graph/graph.js +75 -71
- package/dist/commands/health.js +10 -2
- package/dist/commands/improve/consolidate.js +18 -1
- package/dist/commands/improve/distill.js +26 -5
- package/dist/commands/improve/extract-prompt.js +1 -1
- package/dist/commands/improve/improve-auto-accept.js +6 -0
- package/dist/commands/improve/improve-profiles.js +4 -0
- package/dist/commands/improve/improve.js +720 -468
- package/dist/commands/improve/proactive-maintenance.js +113 -0
- package/dist/commands/improve/reflect.js +6 -0
- package/dist/commands/proposal/proposal.js +5 -0
- package/dist/commands/proposal/validators/proposals.js +67 -54
- package/dist/commands/read/curate.js +17 -0
- package/dist/commands/sources/stash-cli.js +10 -2
- package/dist/core/config/config-schema.js +11 -0
- package/dist/core/paths.js +3 -0
- package/dist/core/state-db.js +46 -1
- package/dist/indexer/db/db.js +97 -11
- package/dist/indexer/ensure-index.js +152 -17
- package/dist/indexer/index-writer-lock.js +99 -0
- package/dist/indexer/indexer.js +114 -111
- package/dist/integrations/harnesses/claude/session-log.js +1 -1
- package/dist/llm/client.js +23 -4
- package/dist/scripts/migrate-storage.js +85 -13
- package/dist/scripts/migrations/import-fs-improve-runs-to-db.js +8 -1
- package/dist/sources/providers/tar-utils.js +16 -8
- package/package.json +1 -1
|
@@ -8882,6 +8882,7 @@ var init_improve_types = () => {};
|
|
|
8882
8882
|
// src/core/state-db.ts
|
|
8883
8883
|
var exports_state_db = {};
|
|
8884
8884
|
__export(exports_state_db, {
|
|
8885
|
+
withImmediateTransaction: () => withImmediateTransaction,
|
|
8885
8886
|
upsertTaskHistory: () => upsertTaskHistory,
|
|
8886
8887
|
upsertProposal: () => upsertProposal,
|
|
8887
8888
|
upsertExtractedSession: () => upsertExtractedSession,
|
|
@@ -8979,7 +8980,8 @@ function proposalRowToProposal(row) {
|
|
|
8979
8980
|
...meta.review !== undefined ? { review: meta.review } : {},
|
|
8980
8981
|
...typeof meta.confidence === "number" ? { confidence: meta.confidence } : {},
|
|
8981
8982
|
...meta.gateDecision !== undefined ? { gateDecision: meta.gateDecision } : {},
|
|
8982
|
-
...typeof meta.backupContent === "string" ? { backupContent: meta.backupContent } : {}
|
|
8983
|
+
...typeof meta.backupContent === "string" ? { backupContent: meta.backupContent } : {},
|
|
8984
|
+
...typeof meta.eligibilitySource === "string" ? { eligibilitySource: meta.eligibilitySource } : {}
|
|
8983
8985
|
};
|
|
8984
8986
|
}
|
|
8985
8987
|
function proposalToRowValues(proposal, stashDir) {
|
|
@@ -8994,6 +8996,8 @@ function proposalToRowValues(proposal, stashDir) {
|
|
|
8994
8996
|
metaObj.gateDecision = proposal.gateDecision;
|
|
8995
8997
|
if (proposal.backupContent !== undefined)
|
|
8996
8998
|
metaObj.backupContent = proposal.backupContent;
|
|
8999
|
+
if (proposal.eligibilitySource !== undefined)
|
|
9000
|
+
metaObj.eligibilitySource = proposal.eligibilitySource;
|
|
8997
9001
|
return {
|
|
8998
9002
|
id: proposal.id,
|
|
8999
9003
|
stash_dir: stashDir,
|
|
@@ -9120,6 +9124,19 @@ function insertProposalIfAbsent(db, proposal, stashDir) {
|
|
|
9120
9124
|
const changes = result.changes ?? 0;
|
|
9121
9125
|
return Number(changes) > 0;
|
|
9122
9126
|
}
|
|
9127
|
+
function withImmediateTransaction(db, fn) {
|
|
9128
|
+
db.exec("BEGIN IMMEDIATE");
|
|
9129
|
+
try {
|
|
9130
|
+
const result = fn();
|
|
9131
|
+
db.exec("COMMIT");
|
|
9132
|
+
return result;
|
|
9133
|
+
} catch (err) {
|
|
9134
|
+
try {
|
|
9135
|
+
db.exec("ROLLBACK");
|
|
9136
|
+
} catch {}
|
|
9137
|
+
throw err;
|
|
9138
|
+
}
|
|
9139
|
+
}
|
|
9123
9140
|
function upsertTaskHistory(db, row) {
|
|
9124
9141
|
db.prepare(`
|
|
9125
9142
|
INSERT OR IGNORE INTO task_history
|
|
@@ -9402,7 +9419,7 @@ var init_state_db = __esm(() => {
|
|
|
9402
9419
|
-- metadata_json TEXT \u2014 JSON object for future proposal fields.
|
|
9403
9420
|
-- Current fields stored here: sourceRun,
|
|
9404
9421
|
-- review, confidence, gateDecision (#577),
|
|
9405
|
-
-- backupContent.
|
|
9422
|
+
-- backupContent, eligibilitySource.
|
|
9406
9423
|
--
|
|
9407
9424
|
-- ADD COLUMN extension points (future migrations):
|
|
9408
9425
|
-- ALTER TABLE proposals ADD COLUMN source_run TEXT DEFAULT NULL;
|
|
@@ -9599,6 +9616,13 @@ var init_state_db = __esm(() => {
|
|
|
9599
9616
|
imported_count INTEGER NOT NULL DEFAULT 0
|
|
9600
9617
|
);
|
|
9601
9618
|
`
|
|
9619
|
+
},
|
|
9620
|
+
{
|
|
9621
|
+
id: "006-proposals-pending-ref-source",
|
|
9622
|
+
up: `
|
|
9623
|
+
CREATE INDEX IF NOT EXISTS idx_proposals_stash_status_ref_source
|
|
9624
|
+
ON proposals(stash_dir, status, ref, source);
|
|
9625
|
+
`
|
|
9602
9626
|
}
|
|
9603
9627
|
];
|
|
9604
9628
|
});
|
|
@@ -10512,7 +10536,7 @@ class ClaudeCodeProvider {
|
|
|
10512
10536
|
const full = path8.join(dir, entry.name);
|
|
10513
10537
|
if (entry.isDirectory())
|
|
10514
10538
|
yield* this.#walkJsonl(full);
|
|
10515
|
-
else if (entry.name.endsWith(".jsonl"))
|
|
10539
|
+
else if (entry.name.endsWith(".jsonl") && entry.name !== "journal.jsonl")
|
|
10516
10540
|
yield full;
|
|
10517
10541
|
}
|
|
10518
10542
|
} catch {}
|
|
@@ -15514,6 +15538,9 @@ var init_config_schema = __esm(() => {
|
|
|
15514
15538
|
limit: positiveInt.optional(),
|
|
15515
15539
|
neighborsPerChanged: exports_external.number().int().min(1).optional(),
|
|
15516
15540
|
requirePlannedRefs: exports_external.boolean().optional(),
|
|
15541
|
+
dueDays: exports_external.number().int().min(0).optional(),
|
|
15542
|
+
maxPerRun: positiveInt.optional(),
|
|
15543
|
+
importanceWeights: exports_external.record(exports_external.string().min(1), exports_external.number()).optional(),
|
|
15517
15544
|
minPendingCount: exports_external.number().int().min(0).optional(),
|
|
15518
15545
|
minNewSessions: exports_external.number().int().min(0).optional(),
|
|
15519
15546
|
indexSessions: exports_external.boolean().optional(),
|
|
@@ -15536,7 +15563,8 @@ var init_config_schema = __esm(() => {
|
|
|
15536
15563
|
memoryInference: ImproveProcessConfigSchema.optional(),
|
|
15537
15564
|
graphExtraction: ImproveProcessConfigSchema.optional(),
|
|
15538
15565
|
validation: ImproveProcessConfigSchema.optional(),
|
|
15539
|
-
triage: ImproveProcessConfigSchema.optional()
|
|
15566
|
+
triage: ImproveProcessConfigSchema.optional(),
|
|
15567
|
+
proactiveMaintenance: ImproveProcessConfigSchema.optional()
|
|
15540
15568
|
}).passthrough().superRefine((val, ctx) => {
|
|
15541
15569
|
const raw = val;
|
|
15542
15570
|
if ("feedbackDistillation" in raw) {
|
|
@@ -15554,7 +15582,8 @@ var init_config_schema = __esm(() => {
|
|
|
15554
15582
|
"graphExtraction",
|
|
15555
15583
|
"validation",
|
|
15556
15584
|
"extract",
|
|
15557
|
-
"triage"
|
|
15585
|
+
"triage",
|
|
15586
|
+
"proactiveMaintenance"
|
|
15558
15587
|
]);
|
|
15559
15588
|
for (const k of Object.keys(raw)) {
|
|
15560
15589
|
if (!allowed.has(k)) {
|
|
@@ -16293,6 +16322,7 @@ __export(exports_db, {
|
|
|
16293
16322
|
getMeta: () => getMeta,
|
|
16294
16323
|
getLlmCacheEntry: () => getLlmCacheEntry,
|
|
16295
16324
|
getLlmCacheEntriesByRefs: () => getLlmCacheEntriesByRefs,
|
|
16325
|
+
getIndexedFilePaths: () => getIndexedFilePaths,
|
|
16296
16326
|
getIndexDirState: () => getIndexDirState,
|
|
16297
16327
|
getEntryRefRowsForStashRoot: () => getEntryRefRowsForStashRoot,
|
|
16298
16328
|
getEntryIdByFilePath: () => getEntryIdByFilePath,
|
|
@@ -17192,6 +17222,10 @@ function getEntryIdByFilePath(db, filePath) {
|
|
|
17192
17222
|
const row = db.prepare("SELECT id FROM entries WHERE file_path = ? LIMIT 1").get(filePath);
|
|
17193
17223
|
return row?.id;
|
|
17194
17224
|
}
|
|
17225
|
+
function getIndexedFilePaths(db) {
|
|
17226
|
+
const rows = db.prepare("SELECT DISTINCT file_path FROM entries WHERE file_path IS NOT NULL AND file_path <> ''").all();
|
|
17227
|
+
return new Set(rows.map((r) => r.file_path));
|
|
17228
|
+
}
|
|
17195
17229
|
function getEntryFilePathById(db, id) {
|
|
17196
17230
|
const row = db.prepare("SELECT file_path FROM entries WHERE id = ?").get(id);
|
|
17197
17231
|
return row?.file_path;
|
|
@@ -17319,18 +17353,56 @@ function clearStaleCacheEntries(db) {
|
|
|
17319
17353
|
function computeBodyHash(body) {
|
|
17320
17354
|
return sha256Hex(body);
|
|
17321
17355
|
}
|
|
17356
|
+
function bareRef(ref) {
|
|
17357
|
+
try {
|
|
17358
|
+
const parsed = parseAssetRef(ref);
|
|
17359
|
+
return `${parsed.type}:${parsed.name}`;
|
|
17360
|
+
} catch {
|
|
17361
|
+
return ref;
|
|
17362
|
+
}
|
|
17363
|
+
}
|
|
17322
17364
|
function getRetrievalCounts(db, refs) {
|
|
17323
17365
|
if (refs.length === 0)
|
|
17324
17366
|
return new Map;
|
|
17325
|
-
const
|
|
17326
|
-
for (
|
|
17327
|
-
const
|
|
17367
|
+
const bareToInputs = new Map;
|
|
17368
|
+
for (const ref of refs) {
|
|
17369
|
+
const bare = bareRef(ref);
|
|
17370
|
+
const existing = bareToInputs.get(bare);
|
|
17371
|
+
if (existing)
|
|
17372
|
+
existing.push(ref);
|
|
17373
|
+
else
|
|
17374
|
+
bareToInputs.set(bare, [ref]);
|
|
17375
|
+
}
|
|
17376
|
+
const bareForms = [...bareToInputs.keys()];
|
|
17377
|
+
const countsByBare = new Map;
|
|
17378
|
+
for (let i = 0;i < bareForms.length; i += SQLITE_CHUNK_SIZE) {
|
|
17379
|
+
const chunk = bareForms.slice(i, i + SQLITE_CHUNK_SIZE);
|
|
17328
17380
|
const placeholders = chunk.map(() => "?").join(", ");
|
|
17329
|
-
const rows = db.prepare(`SELECT
|
|
17330
|
-
|
|
17331
|
-
|
|
17332
|
-
|
|
17333
|
-
|
|
17381
|
+
const rows = db.prepare(`SELECT
|
|
17382
|
+
CASE
|
|
17383
|
+
WHEN instr(entry_ref, '//') > 0
|
|
17384
|
+
THEN substr(entry_ref, instr(entry_ref, '//') + 2)
|
|
17385
|
+
ELSE entry_ref
|
|
17386
|
+
END AS bare_ref,
|
|
17387
|
+
COUNT(*) AS cnt
|
|
17388
|
+
FROM usage_events
|
|
17389
|
+
WHERE event_type IN ('search','show','curate')
|
|
17390
|
+
AND entry_ref IS NOT NULL
|
|
17391
|
+
AND CASE
|
|
17392
|
+
WHEN instr(entry_ref, '//') > 0
|
|
17393
|
+
THEN substr(entry_ref, instr(entry_ref, '//') + 2)
|
|
17394
|
+
ELSE entry_ref
|
|
17395
|
+
END IN (${placeholders})
|
|
17396
|
+
GROUP BY bare_ref`).all(...chunk);
|
|
17397
|
+
for (const r of rows) {
|
|
17398
|
+
countsByBare.set(r.bare_ref, (countsByBare.get(r.bare_ref) ?? 0) + r.cnt);
|
|
17399
|
+
}
|
|
17400
|
+
}
|
|
17401
|
+
const result = new Map;
|
|
17402
|
+
for (const [bare, count] of countsByBare) {
|
|
17403
|
+
for (const input of bareToInputs.get(bare) ?? []) {
|
|
17404
|
+
result.set(input, count);
|
|
17405
|
+
}
|
|
17334
17406
|
}
|
|
17335
17407
|
return result;
|
|
17336
17408
|
}
|
|
@@ -8708,7 +8708,7 @@ var MIGRATIONS = [
|
|
|
8708
8708
|
-- metadata_json TEXT \u2014 JSON object for future proposal fields.
|
|
8709
8709
|
-- Current fields stored here: sourceRun,
|
|
8710
8710
|
-- review, confidence, gateDecision (#577),
|
|
8711
|
-
-- backupContent.
|
|
8711
|
+
-- backupContent, eligibilitySource.
|
|
8712
8712
|
--
|
|
8713
8713
|
-- ADD COLUMN extension points (future migrations):
|
|
8714
8714
|
-- ALTER TABLE proposals ADD COLUMN source_run TEXT DEFAULT NULL;
|
|
@@ -8905,6 +8905,13 @@ var MIGRATIONS = [
|
|
|
8905
8905
|
imported_count INTEGER NOT NULL DEFAULT 0
|
|
8906
8906
|
);
|
|
8907
8907
|
`
|
|
8908
|
+
},
|
|
8909
|
+
{
|
|
8910
|
+
id: "006-proposals-pending-ref-source",
|
|
8911
|
+
up: `
|
|
8912
|
+
CREATE INDEX IF NOT EXISTS idx_proposals_stash_status_ref_source
|
|
8913
|
+
ON proposals(stash_dir, status, ref, source);
|
|
8914
|
+
`
|
|
8908
8915
|
}
|
|
8909
8916
|
];
|
|
8910
8917
|
function runMigrations2(db) {
|
|
@@ -12,12 +12,12 @@
|
|
|
12
12
|
* providers that fetch tarballs (currently `NpmSourceProvider` and the
|
|
13
13
|
* registry index builder).
|
|
14
14
|
*/
|
|
15
|
-
import { spawnSync } from "node:child_process";
|
|
16
15
|
import { createHash } from "node:crypto";
|
|
17
16
|
import fs from "node:fs";
|
|
18
17
|
import path from "node:path";
|
|
19
18
|
import { isWithin } from "../../core/common.js";
|
|
20
19
|
import { warn } from "../../core/warn.js";
|
|
20
|
+
import { spawnSync } from "../../runtime.js";
|
|
21
21
|
/**
|
|
22
22
|
* Verify an archive's integrity against a known hash. Throws and removes
|
|
23
23
|
* the archive when verification fails.
|
|
@@ -65,17 +65,25 @@ export function verifyArchiveIntegrity(archivePath, expected, source) {
|
|
|
65
65
|
* tree for symlinks that would escape the destination.
|
|
66
66
|
*/
|
|
67
67
|
export function extractTarGzSecure(archivePath, destinationDir) {
|
|
68
|
-
const listResult = spawnSync("tar",
|
|
69
|
-
if (listResult.
|
|
70
|
-
const err = listResult.stderr?.trim() ||
|
|
68
|
+
const listResult = spawnSync(["tar", "tzf", archivePath]);
|
|
69
|
+
if (!listResult.success) {
|
|
70
|
+
const err = listResult.stderr?.toString().trim() || "unknown error";
|
|
71
71
|
throw new Error(`Failed to inspect archive ${archivePath}: ${err}`);
|
|
72
72
|
}
|
|
73
|
-
validateTarEntries(listResult.stdout);
|
|
73
|
+
validateTarEntries(listResult.stdout.toString());
|
|
74
74
|
fs.rmSync(destinationDir, { recursive: true, force: true });
|
|
75
75
|
fs.mkdirSync(destinationDir, { recursive: true });
|
|
76
|
-
const extractResult = spawnSync(
|
|
77
|
-
|
|
78
|
-
|
|
76
|
+
const extractResult = spawnSync([
|
|
77
|
+
"tar",
|
|
78
|
+
"xzf",
|
|
79
|
+
archivePath,
|
|
80
|
+
"--no-same-owner",
|
|
81
|
+
"--strip-components=1",
|
|
82
|
+
"-C",
|
|
83
|
+
destinationDir,
|
|
84
|
+
]);
|
|
85
|
+
if (!extractResult.success) {
|
|
86
|
+
const err = extractResult.stderr?.toString().trim() || "unknown error";
|
|
79
87
|
throw new Error(`Failed to extract archive ${archivePath}: ${err}`);
|
|
80
88
|
}
|
|
81
89
|
// Post-extraction scan: verify all extracted files are within destinationDir
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "akm-cli",
|
|
3
|
-
"version": "0.9.0-beta.
|
|
3
|
+
"version": "0.9.0-beta.9",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "akm (Agent Knowledge Management) — A package manager for AI agent skills, commands, tools, and knowledge. Works with Claude Code, OpenCode, Cursor, and any AI coding assistant.",
|
|
6
6
|
"keywords": [
|