akm-cli 0.9.0-beta.5 → 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 +119 -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 +24 -4
- 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 +753 -465
- 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 +25 -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 +90 -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 +2 -2
|
@@ -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 {}
|
|
@@ -15510,6 +15534,14 @@ var init_config_schema = __esm(() => {
|
|
|
15510
15534
|
maxTotalChars: positiveInt.optional(),
|
|
15511
15535
|
minContentChars: exports_external.number().int().min(0).optional(),
|
|
15512
15536
|
maxChunkSize: exports_external.number().int().min(1).max(50).optional(),
|
|
15537
|
+
incrementalSince: exports_external.string().optional(),
|
|
15538
|
+
limit: positiveInt.optional(),
|
|
15539
|
+
neighborsPerChanged: exports_external.number().int().min(1).optional(),
|
|
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(),
|
|
15544
|
+
minPendingCount: exports_external.number().int().min(0).optional(),
|
|
15513
15545
|
minNewSessions: exports_external.number().int().min(0).optional(),
|
|
15514
15546
|
indexSessions: exports_external.boolean().optional(),
|
|
15515
15547
|
minSessionDuration: exports_external.number().min(0).optional(),
|
|
@@ -15531,7 +15563,8 @@ var init_config_schema = __esm(() => {
|
|
|
15531
15563
|
memoryInference: ImproveProcessConfigSchema.optional(),
|
|
15532
15564
|
graphExtraction: ImproveProcessConfigSchema.optional(),
|
|
15533
15565
|
validation: ImproveProcessConfigSchema.optional(),
|
|
15534
|
-
triage: ImproveProcessConfigSchema.optional()
|
|
15566
|
+
triage: ImproveProcessConfigSchema.optional(),
|
|
15567
|
+
proactiveMaintenance: ImproveProcessConfigSchema.optional()
|
|
15535
15568
|
}).passthrough().superRefine((val, ctx) => {
|
|
15536
15569
|
const raw = val;
|
|
15537
15570
|
if ("feedbackDistillation" in raw) {
|
|
@@ -15549,7 +15582,8 @@ var init_config_schema = __esm(() => {
|
|
|
15549
15582
|
"graphExtraction",
|
|
15550
15583
|
"validation",
|
|
15551
15584
|
"extract",
|
|
15552
|
-
"triage"
|
|
15585
|
+
"triage",
|
|
15586
|
+
"proactiveMaintenance"
|
|
15553
15587
|
]);
|
|
15554
15588
|
for (const k of Object.keys(raw)) {
|
|
15555
15589
|
if (!allowed.has(k)) {
|
|
@@ -16288,6 +16322,7 @@ __export(exports_db, {
|
|
|
16288
16322
|
getMeta: () => getMeta,
|
|
16289
16323
|
getLlmCacheEntry: () => getLlmCacheEntry,
|
|
16290
16324
|
getLlmCacheEntriesByRefs: () => getLlmCacheEntriesByRefs,
|
|
16325
|
+
getIndexedFilePaths: () => getIndexedFilePaths,
|
|
16291
16326
|
getIndexDirState: () => getIndexDirState,
|
|
16292
16327
|
getEntryRefRowsForStashRoot: () => getEntryRefRowsForStashRoot,
|
|
16293
16328
|
getEntryIdByFilePath: () => getEntryIdByFilePath,
|
|
@@ -17187,6 +17222,10 @@ function getEntryIdByFilePath(db, filePath) {
|
|
|
17187
17222
|
const row = db.prepare("SELECT id FROM entries WHERE file_path = ? LIMIT 1").get(filePath);
|
|
17188
17223
|
return row?.id;
|
|
17189
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
|
+
}
|
|
17190
17229
|
function getEntryFilePathById(db, id) {
|
|
17191
17230
|
const row = db.prepare("SELECT file_path FROM entries WHERE id = ?").get(id);
|
|
17192
17231
|
return row?.file_path;
|
|
@@ -17314,18 +17353,56 @@ function clearStaleCacheEntries(db) {
|
|
|
17314
17353
|
function computeBodyHash(body) {
|
|
17315
17354
|
return sha256Hex(body);
|
|
17316
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
|
+
}
|
|
17317
17364
|
function getRetrievalCounts(db, refs) {
|
|
17318
17365
|
if (refs.length === 0)
|
|
17319
17366
|
return new Map;
|
|
17320
|
-
const
|
|
17321
|
-
for (
|
|
17322
|
-
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);
|
|
17323
17380
|
const placeholders = chunk.map(() => "?").join(", ");
|
|
17324
|
-
const rows = db.prepare(`SELECT
|
|
17325
|
-
|
|
17326
|
-
|
|
17327
|
-
|
|
17328
|
-
|
|
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
|
+
}
|
|
17329
17406
|
}
|
|
17330
17407
|
return result;
|
|
17331
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": [
|
|
@@ -51,7 +51,7 @@
|
|
|
51
51
|
},
|
|
52
52
|
"scripts": {
|
|
53
53
|
"preinstall": "node -e \"var ua=process.env.npm_config_user_agent||'';var major=parseInt((process.versions.node||'0').split('.')[0],10);if(process.versions.bun||ua.startsWith('bun/')||process.env.BUN_INSTALL||major>=20){process.exit(0)}console.error('\\n ERROR: akm-cli requires the Bun runtime (https://bun.sh), Node.js >= 20, or the prebuilt binary.\\n Install options:\\n 1. Bun: curl -fsSL https://bun.sh/install | bash && bun install -g akm-cli\\n 2. Binary: curl -fsSL https://github.com/itlackey/akm/releases/latest/download/install.sh | bash\\n');process.exit(1)\"",
|
|
54
|
-
"build": "rm -rf dist && bun run tsc --project ./tsconfig.build.json && bun scripts/copy-assets.ts && bun scripts/fix-esm-extensions.ts",
|
|
54
|
+
"build": "rm -rf dist && bun scripts/gen-config-schema.ts &&bun run tsc --project ./tsconfig.build.json && bun scripts/copy-assets.ts && bun scripts/fix-esm-extensions.ts",
|
|
55
55
|
"check": "bun run lint && bunx tsc --noEmit && bun run test:unit && bun run test:integration",
|
|
56
56
|
"check:fast": "bun run lint && bunx tsc --noEmit && bun run test:unit",
|
|
57
57
|
"check:changed": "bun test tests/output-baseline.test.ts tests/integration/e2e.test.ts tests/stash-search.test.ts && bun run lint && bunx tsc --noEmit",
|