akm-cli 0.9.17-alpha.9 → 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.
@@ -180,9 +180,12 @@ export function openReadonlyExistingDatabase(dbPath, options) {
180
180
  // never block — but in the DELETE/TRUNCATE modes the network-FS fallback and
181
181
  // AKM_SQLITE_JOURNAL_MODE can select, a concurrent writer makes every read
182
182
  // fail instantly with SQLITE_BUSY. busy_timeout is legal on a read-only
183
- // connection, so apply just that one.
183
+ // connection, so apply just that one. `busyTimeoutMs` defaults to the
184
+ // shared 30s constant; a caller that must never sit behind another akm
185
+ // process's write lock for long (e.g. `akm info`) can pass a much shorter
186
+ // bound instead.
184
187
  try {
185
- db.exec(`PRAGMA busy_timeout = ${SQLITE_BUSY_TIMEOUT_MS}`);
188
+ db.exec(`PRAGMA busy_timeout = ${options?.busyTimeoutMs ?? SQLITE_BUSY_TIMEOUT_MS}`);
186
189
  checkIndexLayout(db, resolvedPath);
187
190
  return db;
188
191
  }
@@ -5,7 +5,7 @@ Upgrade guides and per-release migration notes.
5
5
  - [v0.9.1 -> v0.9.2 migration guide](v0.9.1-to-v0.9.2.md) -- Task-v2/task-v3 to task source v4 conversion, the durable-v4-family workflow boundary at executable `irVersion: 5`, and release behavior changes
6
6
  - [v0.9.2 release note](release-notes/0.9.2.md) -- Self-contained terminal upgrade summary shipped for `akm help migrate 0.9.2`
7
7
  - [v0.9.16 release note](release-notes/0.9.16.md) -- Source-bound scheduler grants, local execution authority, and split unsafe overrides
8
- - [v0.9.17 release note](release-notes/0.9.17.md) -- Tolerant readers, one config migration step, a plain scheduler list, less machinery, and the upgrade rehearsal gate
8
+ - [v0.9.17 release note](release-notes/0.9.17.md) -- Consolidate's retire proposals and index layout 26, replacing the LLM entity graph with declared links, and `akm improve` scoped to what retrieval actually returns
9
9
  - [v0.8 -> current v0.9 migration guide](v0.8-to-v0.9.md) -- Package upgrade with fresh current config/state and explicit task conversion
10
10
  - [v0.7 -> v0.8 migration guide](v0.7-to-v0.8.md) -- Task schema and 0.8-era changes
11
11
  - [v0.5 -> v0.6 migration guide](https://github.com/itlackey/akm/blob/main/docs/migration/v0.5-to-v0.6.md) -- Terminology cut, registry schema v3, publisher changes
@@ -1,43 +1,132 @@
1
1
  Migration notes for akm v0.9.17
2
2
 
3
- Upgrading no longer needs a manual step to keep working, and there is less
4
- machinery to break.
5
-
6
- Readers tolerate what older releases wrote, except task sources. A
7
- `version: 2` or `version: 3` task source fails on its own with
8
- `TASK_SCHEMA_VERSION_UNSUPPORTED`, naming `akm migrate apply`, which converts
9
- it to `version: 4` once; the other tasks keep running. A config key this
10
- release does not know -- retired, misspelled, or written by a newer release --
11
- is kept in memory and named once, never a reason to refuse the config;
12
- ordinary writes round-trip it, and `akm migrate apply` drops it.
13
- `akm migrate apply` has one config step (`configFile`): read config.json
14
- through the same pipeline every load runs and write the current shape back,
15
- under a backup.
16
-
17
- Scheduling is one list. `scheduler.enabled` in config.json holds the
18
- fully-qualified refs this host schedules (`bundle//tasks/x`). The
19
- 0.9.17-alpha `{kind, ref, sourceId}` grant objects are read as their ref. A
20
- config with no list at all -- every release before 0.9.17 -- means "keep
21
- what is installed": the first `akm task sync` (or `setup`, `task enable`,
22
- `task disable`, `task add`) after the upgrade takes the akm-written rows
23
- already in the native scheduler as the host's choice, writes the list, and
24
- says so. An explicit list, empty or not, is never second-guessed. There are
25
- no grants, no source identities, no carry-forward and no fire-time gate.
26
-
27
- Removed machinery: filesystem transaction journals for proposal accept/revert
28
- (the asset is written, then the proposal row and its event are recorded in
29
- one state.db transaction; a crash in between leaves a re-acceptable pending
30
- proposal); the maintenance barrier, its per-process activity registry (the
31
- source of the lock-sidecar leak) and the SQLite lock-operation mutex (a lock
32
- file is one `O_EXCL` create); startup version reconciliation and
33
- `--host-local`; the akm-install enumerator and `akm upgrade --version/--tag`;
34
- the upgrade and transaction health advisories; the `akm info` compat
35
- manifest. `akm migrate apply` removes the files those left under `$DATA`,
36
- `$STATE` and `$CONFIG`.
37
-
38
- Every historical shape akm has written is exercised by the upgrade rehearsal
39
- (`tests/integration/upgrade-rehearsal/`) before each release: a real previous
40
- release builds a home, the candidate installs over it in place, and the
41
- rehearsal drives migrate, bundle list, search, show, task sync, health and a
42
- scheduled task's generated cron command, then confirms the previous release
43
- still runs against the candidate-written home.
3
+ Run this after upgrading:
4
+
5
+ ```sh
6
+ akm migrate apply
7
+ akm task sync
8
+ ```
9
+
10
+ akm migrate apply reads config.json through the normal load pipeline and
11
+ writes its current shape back under a backup, dropping every retired key it
12
+ finds -- run it with --dry-run first to see the exact list for your config.
13
+ From 0.9.16, that includes index.graph.*, index.metadataEnhance,
14
+ search.minScore, search.graphBoost.*, improve.utilityDecay.*, and a dozen
15
+ smaller ones. None of them do anything any more -- leaving them in
16
+ config.json is harmless until you run migrate apply, which drops them for
17
+ good. It also deletes files nothing reads any more: 0.9.16's transaction
18
+ journals ($DATA/txn/ and $DATA/txn-quarantine/), its maintenance barrier
19
+ lock, and the maintenance-activities/ registry, which leaked an entry per
20
+ process and reached 927 MB on one host. It also drops a leftover
21
+ improve.strategies["graph-refresh"] override block, but not
22
+ defaults.improveStrategy: "graph-refresh" itself -- if you set that, change
23
+ it to a different strategy by hand, since graph-refresh now refuses
24
+ outright, naming the retirement, rather than quietly running as a no-op. The
25
+ shipped akm-graph-refresh-weekly task template is gone; remove or repoint
26
+ any task that used it. Separately, akm search --no-project-context and akm
27
+ proposal drain --policy/--max-diff-lines now fail as unknown flags; drop
28
+ them from any script or task that still passes them.
29
+
30
+ The first akm index after upgrading migrates index.db to layout 26 in
31
+ place -- for a 0.9.16 index this includes a one-time full-text rebuild it
32
+ was already due for, so budget a few seconds for a 24k-entry index rather
33
+ than a fraction of one. This also drops the LLM entity-graph tables -- the
34
+ per-file entity/relation extraction that fed akm show's old related list is
35
+ retired -- and ends with a VACUUM that reclaims the space both steps free;
36
+ akm index has never VACUUMed index.db before, so this is the first time it
37
+ happens at all, not a repeat of something 0.9.16 already did. Nothing is
38
+ re-embedded by this migration.
39
+
40
+ Embeddings are a separate matter if you use a nomic-embed or E5 model:
41
+ akm index now sends the model's own document template (nomic:
42
+ "search_document: ", E5: "passage: ") instead of the raw text, which changes
43
+ what gets embedded, so every entry re-embeds once on the next akm index.
44
+ Qwen3, the BGE/mxbai/arctic family, and the default local model have no
45
+ document template and keep their stored vectors untouched. Set
46
+ embedding.documentTemplate: "" if you'd rather keep the old vectors than pay
47
+ for a full re-embed. If you had index.metadataEnhance on before upgrading
48
+ (it defaulted off), run akm index --full once afterward to replace the
49
+ LLM-written descriptions it left behind with the plain deterministic ones --
50
+ an ordinary incremental akm index does not touch them.
51
+
52
+ The first akm task sync after upgrading rewrites every akm-managed
53
+ scheduler row once, in place. Each row now sets its own AKM_BUNDLE_DIR
54
+ (plus any AKM_CONFIG_DIR/AKM_DATA_DIR/AKM_CACHE_DIR/AKM_STATE_DIR the
55
+ syncing shell had set explicitly) inline, instead of pointing at a
56
+ --scheduler-context <file> descriptor, and a crontab's PATH moves the same
57
+ way, into a # akm:env block next to the task rows. The rewrite keeps each
58
+ row's existing launcher and schedule -- it is reported as an update, never
59
+ an add or a remove -- and rows written by 0.9.0 through 0.9.16 keep firing
60
+ normally until that sync runs. Once akm task doctor lists no binding still
61
+ pointing at a descriptor file, the old $DATA/tasks/context/ files can be
62
+ deleted.
63
+
64
+ akm improve now reworks only what retrieval actually returned -- an asset a
65
+ real search, curate, show, or feedback touched in the last 90 days -- plus
66
+ material no improve stage has processed yet. The proactive-maintenance and
67
+ high-salience lanes, and the memory consolidation judge, no longer reach
68
+ into the unread tail of a stash; an asset left out this way shows up under a
69
+ new retrieval gate in akm improve --dry-run and under akm health's
70
+ not_retrieved skip reason, not silently.
71
+
72
+ Consolidation gets a second pass. It compares each new-or-changed memory,
73
+ flat knowledge/ file, or lesson against its nearest neighbours, and where an
74
+ LLM judge calls a pair duplicate, subsumed, or superseding, it mints a
75
+ reviewed retire proposal for the losing side -- nothing is retired
76
+ automatically. Review these like any other proposal: akm proposal list
77
+ --generator consolidate-pair (or just akm proposal list, which flags one
78
+ carrying continuity risk inline), show, diff, then accept or reject.
79
+ Accepting one archives the losing file instead of deleting it, and akm
80
+ proposal revert restores it exactly; archived files are only deleted 30 days
81
+ after retirement, and only once git holds them clean and unmodified.
82
+ Accepting a promotion (a consolidate promote proposal, by a person or by
83
+ triage auto-promotion) now also archives the source memory it was promoted
84
+ from, so a promotion no longer leaves a duplicate sitting next to the
85
+ knowledge doc it produced.
86
+
87
+ akm proposal drain, and improve's own triage pre-pass, no longer take a
88
+ policy. Both now accept only a proposal the quality judge passed on its
89
+ exact content and reject an empty diff; everything else goes to
90
+ processes.triage.judgment or waits for review -- including extract and
91
+ consolidate proposals, which used to be auto-accepted on size alone under
92
+ the personal-stash default.
93
+
94
+ akm show no longer has a related field. It lists an asset's links instead:
95
+ the relations a bundle already declares -- cross-references, supersededBy,
96
+ a .derived memory's parent, a wiki's citations, resolved page links, a
97
+ workflow's or task's target -- grouped outgoing/incoming/unresolved,
98
+ computed with no LLM call. Curate's support refs are drawn from the same
99
+ links now, not from the retired entity graph.
100
+
101
+ akm info always exits 0 and always prints a report, even when something is
102
+ wrong: an invalid config.json, a missing or unreadable bundle directory, or
103
+ a locked/newer/corrupt index.db is named in the report (configError,
104
+ bundleDirError, indexStats.unavailable) instead of failing the command or
105
+ showing unexplained zeros. It also reports link counts per kind, including
106
+ how many are unresolved.
107
+
108
+ Decide every pending retire proposal -- akm proposal accept or reject --
109
+ before downgrading to 0.9.16. Older releases predate the retire proposal
110
+ shape entirely: akm proposal show/diff/drain exits 70 on one it doesn't
111
+ recognize, and drain's own nightly pre-pass failing on the first pending
112
+ retire proposal it meets stops that run's auto-promotion for the whole
113
+ stash, not just for the one proposal.
114
+
115
+ 0.9.16 already refuses to open a newer-layout index.db outright
116
+ (INDEX_SCHEMA_INCOMPATIBLE, naming the upgrade) and leaves the file
117
+ untouched, so downgrading needs a fresh index: move index.db aside and run
118
+ akm index --full under 0.9.16, which re-embeds everything from scratch.
119
+
120
+ A workflow run started under 0.9.17 freezes its plan as irVersion 6,
121
+ which 0.9.16 does not understand and refuses to resume
122
+ (WORKFLOW_IR_VERSION_UNSUPPORTED) -- let any in-flight workflow runs finish
123
+ before downgrading, or plan to restart them fresh under 0.9.16.
124
+
125
+ The state.db migration that adds the improve ledger
126
+ (028-improve-ledger) drops six tables 0.9.16 and earlier used
127
+ (proposal_fingerprints and friends). Because it drops schema, the akm that
128
+ runs it first copies the database to state.db.pre-028-improve-ledger.bak
129
+ before making the change. That backup is a snapshot from the moment of
130
+ upgrade -- restoring it to downgrade discards every proposal, event, and run
131
+ state.db has recorded since, not just the ledger's own six tables, so treat
132
+ it as a last resort rather than routine.
@@ -7,6 +7,13 @@ live one level up in `docs/migration/`.
7
7
 
8
8
  ## Available notes
9
9
 
10
+ - [0.9.17](0.9.17.md) — consolidate's retire proposals and continuity check,
11
+ promotions archiving their source memory, declared links replacing the LLM
12
+ entity graph, index layout 26, scheduler rows carrying their own context,
13
+ and `akm improve` scoped to what retrieval actually returns
14
+ - [0.9.16](0.9.16.md) — source-bound scheduler grants, local execution
15
+ authority, config inheritance's portable-data boundary, and split unsafe
16
+ overrides
10
17
  - [0.9.15](0.9.15.md) — exit-code 75 for lease/state.db contention,
11
18
  `--require-engines` scheduled task templates, `--no-probe` cli-version
12
19
  skip, thinking-control wire forms, embedding re-embed safety and
@@ -318,8 +318,10 @@ Returns a JSON object with:
318
318
  | Field | Description |
319
319
  | --- | --- |
320
320
  | `version` | Current akm version |
321
- | `bundleDir` | Primary bundle directory — same resolution `akm bundle list` uses |
321
+ | `bundleDir` | Primary bundle directory — same resolution `akm bundle list` uses. Falls back to the platform-default location when no bundle resolves. |
322
322
  | `defaultBundle` | Name of the primary bundle from config, or `null` when none is configured |
323
+ | `configError` | Present only when `config.json` exists but could not be loaded (parse or schema failure); every config-derived field falls back to the same defaults a fresh install reports |
324
+ | `bundleDirError` | Present when a bundle IS configured (an env override or `bundles.*` in config) but its path doesn't resolve, OR when the platform-default fallback itself can't resolve (e.g. `HOME` unset) — absent for the ordinary "no bundle created yet" state, where `bundleDir` needs no explanation |
323
325
  | `dataDir` | Resolved data directory (`getDataDir()`) |
324
326
  | `configDir` | Resolved config directory (`getConfigDir()`) |
325
327
  | `cacheDir` | Resolved cache directory (`getCacheDir()`) |
@@ -329,7 +331,14 @@ Returns a JSON object with:
329
331
  | `semanticSearch` | Semantic search status: `mode`, `status`, and optional `reason`/`message` |
330
332
  | `registries` | Configured registries |
331
333
  | `sourceProviders` | Configured sources (filesystem, git, website, npm) |
332
- | `indexStats` | Index stats: `entryCount`, `byType` (per-asset-type breakdown), `links` (declared links per kind with `total` and `unresolved`; absent when the index holds none), `lastBuiltAt`, `hasEmbeddings` |
334
+ | `indexStats` | Index stats: `entryCount`, `byType` (per-asset-type breakdown), `links` (declared links per kind with `total` and `unresolved`; absent when the index holds none), `lastBuiltAt`, `hasEmbeddings`, `unreadable` (index.db exists but the filesystem refuses to read it — a permissions problem), `unavailable` (index.db is readable but the SQLite-level read didn't complete: locked by another akm process, a newer layout this akm can't understand, or a corrupt file) |
335
+
336
+ `akm info` never refuses: an unreadable config, an unresolvable bundle
337
+ directory, or an index.db that's locked, newer, older, corrupt, missing, or
338
+ empty each degrade the relevant field(s) above instead of failing the
339
+ command. It also never waits more than about 1.5s on a locked index.db,
340
+ regardless of the shared 30s lock-wait every write command otherwise uses,
341
+ and warns rather than refusing on an unrecognized flag.
333
342
 
334
343
  `semanticSearch.status` values:
335
344
  - `"ready-js"` — every entry has a vector; semantic search is active (the name is historical: `"ready-vec"`, the sqlite-vec variant, is gone)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "akm-cli",
3
- "version": "0.9.17-alpha.9",
3
+ "version": "0.9.17",
4
4
  "type": "module",
5
5
  "description": "akm (Agent Knowledge Manager) — a portable, local-first capability library for AI agents. Discover, load, share, and improve reusable skills, scripts, workflows, and knowledge across any shell-capable coding agent, including Claude Code, OpenCode, and Cursor.",
6
6
  "keywords": [