akm-cli 0.9.0-beta.11 → 0.9.0-beta.26
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 +163 -0
- package/dist/assets/prompts/consolidate-system.md +23 -0
- package/dist/assets/prompts/contradiction-judge.md +33 -0
- package/dist/assets/prompts/distill-knowledge-system.md +22 -0
- package/dist/assets/prompts/distill-lesson-system.md +36 -0
- package/dist/assets/prompts/extract-session.md +5 -1
- package/dist/assets/prompts/graph-extract-system.md +1 -0
- package/dist/assets/prompts/memory-infer-system.md +1 -0
- package/dist/assets/prompts/memory-infer-user.md +5 -0
- package/dist/assets/prompts/metadata-enhance-system.md +1 -0
- package/dist/assets/prompts/procedural-system.md +44 -0
- package/dist/assets/prompts/recombine-system.md +40 -0
- package/dist/assets/prompts/staleness-detect-system.md +6 -0
- package/dist/assets/prompts/validate-summary-judge.md +1 -0
- package/dist/assets/templates/html/health.html +25 -27
- package/dist/cli.js +2 -2
- package/dist/commands/agent/contribute-cli.js +16 -3
- package/dist/commands/feedback-cli.js +48 -44
- package/dist/commands/health/html-report.js +140 -16
- package/dist/commands/health.js +277 -1
- package/dist/commands/improve/calibration.js +161 -0
- package/dist/commands/improve/consolidate.js +595 -105
- package/dist/commands/improve/dedup.js +482 -0
- package/dist/commands/improve/distill.js +119 -64
- package/dist/commands/improve/encoding-salience.js +205 -0
- package/dist/commands/improve/extract-cli.js +115 -1
- package/dist/commands/improve/extract-prompt.js +32 -1
- package/dist/commands/improve/extract-watch.js +140 -0
- package/dist/commands/improve/extract.js +210 -30
- package/dist/commands/improve/feedback-valence.js +54 -0
- package/dist/commands/improve/homeostatic.js +467 -0
- package/dist/commands/improve/improve-auto-accept.js +80 -7
- package/dist/commands/improve/improve-profiles.js +8 -0
- package/dist/commands/improve/improve.js +991 -61
- package/dist/commands/improve/memory/memory-contradiction-detect.js +23 -28
- package/dist/commands/improve/outcome-loop.js +256 -0
- package/dist/commands/improve/proactive-maintenance.js +9 -35
- package/dist/commands/improve/procedural.js +409 -0
- package/dist/commands/improve/recombine.js +488 -0
- package/dist/commands/improve/reflect.js +20 -1
- package/dist/commands/improve/related-sessions.js +120 -0
- package/dist/commands/improve/salience.js +386 -0
- package/dist/commands/improve/triage.js +95 -0
- package/dist/commands/lint/agent-linter.js +19 -24
- package/dist/commands/lint/base-linter.js +173 -60
- package/dist/commands/lint/command-linter.js +19 -24
- package/dist/commands/lint/env-key-rules.js +34 -1
- package/dist/commands/lint/index.js +30 -13
- package/dist/commands/lint/memory-linter.js +1 -1
- package/dist/commands/lint/registry.js +5 -2
- package/dist/commands/lint/task-linter.js +3 -3
- package/dist/commands/lint/workflow-linter.js +26 -1
- package/dist/commands/proposal/validators/proposals.js +4 -0
- package/dist/commands/read/curate.js +284 -86
- package/dist/commands/read/search-cli.js +7 -0
- package/dist/commands/read/search.js +1 -0
- package/dist/commands/sources/installed-stashes.js +5 -1
- package/dist/core/asset/frontmatter.js +166 -167
- package/dist/core/asset/markdown.js +8 -0
- package/dist/core/config/config-schema.js +211 -3
- package/dist/core/config/config.js +2 -2
- package/dist/core/logs-db.js +4 -3
- package/dist/core/state-db.js +555 -29
- package/dist/indexer/db/db.js +250 -27
- package/dist/indexer/db/graph-db.js +81 -86
- package/dist/indexer/graph/graph-boost.js +51 -41
- package/dist/indexer/passes/memory-inference.js +10 -3
- package/dist/indexer/passes/staleness-detect.js +2 -5
- package/dist/indexer/search/db-search.js +15 -4
- package/dist/indexer/search/ranking.js +4 -0
- package/dist/integrations/harnesses/claude/session-log.js +10 -0
- package/dist/integrations/harnesses/opencode/session-log.js +9 -0
- package/dist/integrations/session-logs/index.js +16 -0
- package/dist/llm/embedder.js +27 -3
- package/dist/llm/embedders/local.js +66 -2
- package/dist/llm/graph-extract.js +2 -1
- package/dist/llm/memory-infer.js +4 -8
- package/dist/llm/metadata-enhance.js +9 -1
- package/dist/output/shapes/curate.js +14 -2
- package/dist/output/text/helpers.js +9 -0
- package/dist/runtime.js +25 -1
- package/dist/scripts/migrate-storage.js +1025 -567
- package/dist/scripts/migrations/import-fs-improve-runs-to-db.js +435 -269
- package/dist/storage/sqlite-pragmas.js +146 -0
- package/dist/workflows/db.js +3 -4
- package/dist/workflows/validate-summary.js +2 -7
- package/docs/data-and-telemetry.md +1 -0
- package/package.json +5 -4
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
// This Source Code Form is subject to the terms of the Mozilla Public
|
|
2
|
+
// License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
3
|
+
// file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
|
4
|
+
/**
|
|
5
|
+
* Shared SQLite PRAGMA application + journal-mode resolution (#628).
|
|
6
|
+
*
|
|
7
|
+
* Every AKM SQLite opener applies the same opening PRAGMAs: a journal mode, a
|
|
8
|
+
* 30 s busy_timeout, and (for most) foreign_keys = ON. Historically each opener
|
|
9
|
+
* hard-coded `PRAGMA journal_mode = WAL`. WAL is impossible on network
|
|
10
|
+
* filesystems (NFS/SMB) because its `-shm` shared-memory wal-index cannot be
|
|
11
|
+
* mmap'd over a network mount, so AKM could not run with its data dir on a
|
|
12
|
+
* network share.
|
|
13
|
+
*
|
|
14
|
+
* This module centralises that PRAGMA block behind {@link applyStandardPragmas}
|
|
15
|
+
* and makes the journal mode configurable via the `AKM_SQLITE_JOURNAL_MODE`
|
|
16
|
+
* env var (WAL | DELETE | TRUNCATE; default WAL = unchanged behaviour). When the
|
|
17
|
+
* mode is the WAL default and the data directory is detected to live on a
|
|
18
|
+
* network filesystem, it auto-falls-back to DELETE with a one-line warning.
|
|
19
|
+
*
|
|
20
|
+
* Boundary note: this is a PLAIN module, not a runtime-boundary file. It only
|
|
21
|
+
* does pure string work plus `db.exec()` (allowed everywhere). The single
|
|
22
|
+
* runtime primitive it needs — a filesystem-type probe (statfs) — lives in
|
|
23
|
+
* src/runtime.ts and is injected here, keeping the network-FS classifier a
|
|
24
|
+
* pure, unit-testable function.
|
|
25
|
+
*
|
|
26
|
+
* @module storage/sqlite-pragmas
|
|
27
|
+
*/
|
|
28
|
+
import { warn } from "../core/warn.js";
|
|
29
|
+
import { statfsType } from "../runtime.js";
|
|
30
|
+
const VALID_MODES = new Set(["WAL", "DELETE", "TRUNCATE"]);
|
|
31
|
+
// One-shot warning guards so a misconfigured env var or a network-FS fallback
|
|
32
|
+
// each emit AT MOST ONCE per process rather than on every db open.
|
|
33
|
+
let warnedInvalid = false;
|
|
34
|
+
let warnedNetworkFallback = false;
|
|
35
|
+
/**
|
|
36
|
+
* Resolve a raw `AKM_SQLITE_JOURNAL_MODE` value to a canonical {@link JournalMode}.
|
|
37
|
+
*
|
|
38
|
+
* PURE and unit-testable: the raw string is passed in (not read from
|
|
39
|
+
* `process.env` here). Trims + uppercases; an empty/undefined value yields the
|
|
40
|
+
* WAL default; a recognised value yields its canonical form; any other
|
|
41
|
+
* non-empty value warns once and falls back to WAL. Never throws.
|
|
42
|
+
*/
|
|
43
|
+
export function resolveJournalMode(raw) {
|
|
44
|
+
if (raw === undefined)
|
|
45
|
+
return "WAL";
|
|
46
|
+
const normalized = raw.trim().toUpperCase();
|
|
47
|
+
if (normalized === "")
|
|
48
|
+
return "WAL";
|
|
49
|
+
if (VALID_MODES.has(normalized)) {
|
|
50
|
+
return normalized;
|
|
51
|
+
}
|
|
52
|
+
warnInvalidJournalModeOnce(raw);
|
|
53
|
+
return "WAL";
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* The single env-reading seam: resolve the configured journal mode from
|
|
57
|
+
* `process.env.AKM_SQLITE_JOURNAL_MODE`. Read at call time (per open) so tests
|
|
58
|
+
* that set the env per-case see the right value and we avoid stale-env flakes.
|
|
59
|
+
*/
|
|
60
|
+
export function resolveConfiguredJournalMode() {
|
|
61
|
+
return resolveJournalMode(process.env.AKM_SQLITE_JOURNAL_MODE);
|
|
62
|
+
}
|
|
63
|
+
function warnInvalidJournalModeOnce(raw) {
|
|
64
|
+
if (warnedInvalid)
|
|
65
|
+
return;
|
|
66
|
+
warnedInvalid = true;
|
|
67
|
+
warn(`[akm] invalid AKM_SQLITE_JOURNAL_MODE=${JSON.stringify(raw)} — using WAL (valid: WAL, DELETE, TRUNCATE)`);
|
|
68
|
+
}
|
|
69
|
+
// Known Linux f_type magic numbers for network filesystems. node's statfs
|
|
70
|
+
// normalises `type` to this numeric f_type magic on all platforms.
|
|
71
|
+
const FS_MAGIC_NFS = 0x6969; // 26985 — NFS
|
|
72
|
+
const FS_MAGIC_SMB = 0x517b; // 20859 — older SMB_SUPER_MAGIC
|
|
73
|
+
const FS_MAGIC_CIFS = 0xff534d42; // 4283649346 — SMB/CIFS
|
|
74
|
+
const FS_MAGIC_SMB2 = 0xfe534d42; // 4267272514 — SMB2
|
|
75
|
+
const FS_MAGIC_FUSE = 0x65735546; // 1702057286 — FUSE (sshfs + many network FUSE mounts)
|
|
76
|
+
const NETWORK_FS_MAGICS = new Set([
|
|
77
|
+
FS_MAGIC_NFS,
|
|
78
|
+
FS_MAGIC_SMB,
|
|
79
|
+
FS_MAGIC_CIFS,
|
|
80
|
+
FS_MAGIC_SMB2,
|
|
81
|
+
// FUSE is a judgment call: it backs BOTH network mounts (sshfs) and local
|
|
82
|
+
// mounts (some encrypted/overlay FS). Treating it as network falls back to
|
|
83
|
+
// DELETE — conservative-but-safe (DELETE works everywhere; the only cost is
|
|
84
|
+
// losing WAL concurrency). An operator can always force WAL via the env var.
|
|
85
|
+
FS_MAGIC_FUSE,
|
|
86
|
+
]);
|
|
87
|
+
/**
|
|
88
|
+
* PURE classifier: is `fsType` a known network-filesystem magic number?
|
|
89
|
+
* Returns false for `undefined` (probe failed/unsupported) and for local
|
|
90
|
+
* magics (ext4 0xEF53, btrfs, xfs, tmpfs, apfs, …). Unit-testable with
|
|
91
|
+
* injected magic numbers — no real mount required.
|
|
92
|
+
*/
|
|
93
|
+
export function isNetworkFilesystem(fsType) {
|
|
94
|
+
if (fsType === undefined)
|
|
95
|
+
return false;
|
|
96
|
+
return NETWORK_FS_MAGICS.has(fsType);
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* Apply AKM's standard opening PRAGMAs to `db`, in order:
|
|
100
|
+
* 1. `journal_mode` = the configured mode (with WAL→DELETE network-FS fallback)
|
|
101
|
+
* 2. `busy_timeout = 30000`
|
|
102
|
+
* 3. `foreign_keys = ON` (unless `opts.foreignKeys === false`)
|
|
103
|
+
* 4. `synchronous = FULL` (only in a rollback-journal mode — DELETE/TRUNCATE)
|
|
104
|
+
*
|
|
105
|
+
* Returns the effective {@link JournalMode} so callers/tests can assert it.
|
|
106
|
+
*
|
|
107
|
+
* `synchronous = FULL` is set explicitly only in DELETE/TRUNCATE so durability
|
|
108
|
+
* intent is clear: rollback journals need FULL for crash-durability across
|
|
109
|
+
* power loss, whereas WAL is durable at NORMAL. SQLite's default synchronous is
|
|
110
|
+
* already FULL when unset, so this never changes WAL-default behaviour — the
|
|
111
|
+
* WAL path emits no `synchronous` pragma, exactly as before.
|
|
112
|
+
*/
|
|
113
|
+
export function applyStandardPragmas(db, opts = {}) {
|
|
114
|
+
let mode = resolveConfiguredJournalMode();
|
|
115
|
+
// Network-FS fallback only fires for the WAL default and only when we have a
|
|
116
|
+
// directory to probe. An explicitly-requested DELETE/TRUNCATE is never
|
|
117
|
+
// overridden, and a failed/unsupported probe (undefined) keeps WAL.
|
|
118
|
+
if (mode === "WAL" && opts.dataDir) {
|
|
119
|
+
const probe = opts.fsTypeProbe ?? statfsType;
|
|
120
|
+
if (isNetworkFilesystem(probe(opts.dataDir))) {
|
|
121
|
+
mode = "DELETE";
|
|
122
|
+
warnNetworkFallbackOnce(opts.dataDir);
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
// PRAGMAs must run before any DDL or DML. busy_timeout is applied FIRST so a
|
|
126
|
+
// journal-mode change that must reclaim a leftover `-wal` file (WAL→DELETE on
|
|
127
|
+
// reopen of an unclean WAL db, e.g. after a crash) can wait out a transient
|
|
128
|
+
// lock instead of failing immediately with SQLITE_BUSY. For the WAL default
|
|
129
|
+
// this is a no-op (WAL→WAL changes nothing), so byte-identical behaviour is
|
|
130
|
+
// preserved.
|
|
131
|
+
db.exec("PRAGMA busy_timeout = 30000");
|
|
132
|
+
db.exec(`PRAGMA journal_mode = ${mode}`);
|
|
133
|
+
if (opts.foreignKeys !== false) {
|
|
134
|
+
db.exec("PRAGMA foreign_keys = ON");
|
|
135
|
+
}
|
|
136
|
+
if (mode !== "WAL") {
|
|
137
|
+
db.exec("PRAGMA synchronous = FULL");
|
|
138
|
+
}
|
|
139
|
+
return mode;
|
|
140
|
+
}
|
|
141
|
+
function warnNetworkFallbackOnce(dataDir) {
|
|
142
|
+
if (warnedNetworkFallback)
|
|
143
|
+
return;
|
|
144
|
+
warnedNetworkFallback = true;
|
|
145
|
+
warn(`[akm] network filesystem detected at ${dataDir} — WAL unsupported, using DELETE journal mode`);
|
|
146
|
+
}
|
package/dist/workflows/db.js
CHANGED
|
@@ -6,6 +6,7 @@ import path from "node:path";
|
|
|
6
6
|
import { getWorkflowDbPath } from "../core/paths.js";
|
|
7
7
|
import { openDatabase } from "../storage/database.js";
|
|
8
8
|
import { runMigrations as runSqliteMigrations } from "../storage/engines/sqlite-migrations.js";
|
|
9
|
+
import { applyStandardPragmas } from "../storage/sqlite-pragmas.js";
|
|
9
10
|
/**
|
|
10
11
|
* workflow.db — Durable SQLite database for workflow run state.
|
|
11
12
|
*
|
|
@@ -46,12 +47,10 @@ export function openWorkflowDatabase(dbPath = getWorkflowDbPath()) {
|
|
|
46
47
|
fs.mkdirSync(dir, { recursive: true });
|
|
47
48
|
}
|
|
48
49
|
const db = openDatabase(dbPath);
|
|
49
|
-
db.exec("PRAGMA journal_mode = WAL");
|
|
50
50
|
// #589: 30 s busy timeout, matching index.db / state.db. Without it the
|
|
51
51
|
// default is 0 ms, so any concurrent writer fails immediately with
|
|
52
|
-
// SQLITE_BUSY.
|
|
53
|
-
db
|
|
54
|
-
db.exec("PRAGMA foreign_keys = ON");
|
|
52
|
+
// SQLITE_BUSY. #628: journal_mode is configurable via AKM_SQLITE_JOURNAL_MODE.
|
|
53
|
+
applyStandardPragmas(db, { dataDir: dir });
|
|
55
54
|
ensureBaseSchema(db);
|
|
56
55
|
runMigrations(db);
|
|
57
56
|
return db;
|
|
@@ -16,14 +16,9 @@
|
|
|
16
16
|
*
|
|
17
17
|
* @module workflows/validate-summary
|
|
18
18
|
*/
|
|
19
|
+
import validateSummaryJudgePrompt from "../assets/prompts/validate-summary-judge.md" with { type: "text" };
|
|
19
20
|
import { parseJsonResponse } from "../core/parse.js";
|
|
20
|
-
const JUDGE_SYSTEM =
|
|
21
|
-
"Given a step's completion criteria and a summary of the work an agent claims to have done, " +
|
|
22
|
-
"judge whether the summary provides concrete evidence that EVERY criterion is satisfied. " +
|
|
23
|
-
"Be skeptical: vague, hand-wavy, or unsubstantiated claims do NOT satisfy a criterion. " +
|
|
24
|
-
'Respond with ONLY a JSON object: {"complete": boolean, "missing": string[], "feedback": string}. ' +
|
|
25
|
-
'"missing" lists the exact criteria that are not yet satisfied; "feedback" is a short directive ' +
|
|
26
|
-
"telling the agent what to finish or fix. No prose, no markdown fences.";
|
|
21
|
+
const JUDGE_SYSTEM = validateSummaryJudgePrompt;
|
|
27
22
|
function buildUserPrompt(input) {
|
|
28
23
|
const criteria = input.completionCriteria.map((c, i) => `${i + 1}. ${c}`).join("\n");
|
|
29
24
|
return [
|
|
@@ -216,6 +216,7 @@ You can redirect any AKM directory to a custom path:
|
|
|
216
216
|
|---|---|
|
|
217
217
|
| `AKM_CONFIG_DIR` | Config directory (`~/.config/akm/`) |
|
|
218
218
|
| `AKM_DATA_DIR` | Data directory (`~/.local/share/akm/`) |
|
|
219
|
+
| `AKM_SQLITE_JOURNAL_MODE` | SQLite journal mode: `WAL` (default), `DELETE`, or `TRUNCATE`. Use `DELETE`/`TRUNCATE` on network filesystems (NFS/SMB) where WAL is impossible. When left at the `WAL` default, akm auto-detects a network FS for the data dir and falls back to `DELETE`. |
|
|
219
220
|
| `AKM_STATE_DIR` | State directory (`~/.local/state/akm/`) |
|
|
220
221
|
| `AKM_CACHE_DIR` | Cache directory (`~/.cache/akm/`) |
|
|
221
222
|
| `AKM_STASH_DIR` | Default stash directory (`~/akm/`) |
|
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.26",
|
|
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": [
|
|
@@ -55,9 +55,10 @@
|
|
|
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",
|
|
58
|
-
"
|
|
59
|
-
"test
|
|
60
|
-
"test:
|
|
58
|
+
"sweep:tmp": "bun scripts/sweep-test-tmp.ts",
|
|
59
|
+
"test": "bun run sweep:tmp && bun test --parallel=${TEST_PARALLEL:-12} --timeout=30000 ./tests --path-ignore-patterns=tests/integration",
|
|
60
|
+
"test:unit": "bun run sweep:tmp && bun test --parallel=${TEST_PARALLEL:-12} --timeout=30000 ./tests --path-ignore-patterns=tests/integration",
|
|
61
|
+
"test:integration": "bun run sweep:tmp && bun test --parallel=${TEST_PARALLEL:-12} --timeout=30000 ./tests/integration ./tests/commands ./tests/workflows",
|
|
61
62
|
"test:node-smoke": "bun scripts/node-smoke.ts",
|
|
62
63
|
"test:node-compat": "AKM_NODE_COMPAT_TESTS=1 bun test --timeout=120000 tests/integration/node-compat.test.ts",
|
|
63
64
|
"test:sharded": "bun test ./tests --shard=1/4 & bun test ./tests --shard=2/4 & bun test ./tests --shard=3/4 & bun test ./tests --shard=4/4 & wait",
|