akm-cli 0.9.6 → 0.9.8-beta.1
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 +408 -0
- package/dist/assets/hints/cli-hints-full.md +3 -3
- package/dist/assets/improve-strategies/catchup.json +40 -11
- package/dist/assets/improve-strategies/thorough.json +45 -7
- package/dist/assets/tasks/improve/akm-improve-frequent.yml +2 -2
- package/dist/commands/agent/contribute-cli.js +11 -0
- package/dist/commands/env/env.js +2 -21
- package/dist/commands/health/checks.js +0 -25
- package/dist/commands/health/improve-metrics.js +8 -34
- package/dist/commands/health/windows.js +0 -4
- package/dist/commands/health.js +1 -35
- package/dist/commands/improve/consolidate/eligibility.js +11 -5
- package/dist/commands/improve/extract.js +36 -32
- package/dist/commands/improve/improve-cli.js +1 -1
- package/dist/commands/improve/improve-strategies.js +0 -4
- package/dist/commands/improve/memory/memory-belief.js +15 -5
- package/dist/commands/improve/memory/memory-contradiction-detect.js +16 -25
- package/dist/commands/improve/memory/memory-improve.js +9 -20
- package/dist/commands/improve/preparation.js +53 -37
- package/dist/commands/improve/reflect.js +14 -18
- package/dist/commands/lint/base-linter.js +182 -19
- package/dist/commands/lint/index.js +21 -9
- package/dist/commands/migrate/config-extra-params.js +61 -0
- package/dist/commands/migrate/dead-residue.js +113 -0
- package/dist/commands/migrate/stale-txn.js +49 -0
- package/dist/commands/migrate-cli.js +42 -1
- package/dist/commands/proposal/proposal.js +1 -21
- package/dist/commands/proposal/repository.js +0 -4
- package/dist/commands/proposal/validators/proposal-quality-validators.js +0 -6
- package/dist/commands/read/curate.js +51 -18
- package/dist/commands/read/search-cli.js +24 -1
- package/dist/commands/read/show.js +2 -1
- package/dist/commands/sources/installed-stashes.js +5 -1
- package/dist/commands/sources/self-update.js +38 -1
- package/dist/commands/sources/sources-cli.js +17 -1
- package/dist/commands/tasks/tasks.js +0 -8
- package/dist/commands/url-checker.js +20 -28
- package/dist/core/adapter/adapters/agent-skills-adapter.js +2 -6
- package/dist/core/adapter/adapters/akm-adapter.js +2 -3
- package/dist/core/adapter/adapters/akm-lint.js +2 -20
- package/dist/core/adapter/adapters/akm-task-adapter.js +2 -6
- package/dist/core/adapter/adapters/akm-workflow-adapter.js +2 -6
- package/dist/core/adapter/adapters/dotenv-adapter.js +2 -22
- package/dist/core/adapter/adapters/generic-files-adapter.js +3 -9
- package/dist/core/adapter/adapters/llm-wiki-adapter.js +2 -6
- package/dist/core/adapter/adapters/okf-adapter.js +7 -18
- package/dist/core/adapter/adapters/shared.js +2 -0
- package/dist/core/adapter/adapters/tool-dir-shared.js +3 -9
- package/dist/core/adapter/adapters/website-snapshot-adapter.js +2 -6
- package/dist/core/adapter/validate-context.js +1 -3
- package/dist/core/asset/asset-placement.js +14 -5
- package/dist/core/asset/frontmatter.js +212 -0
- package/dist/core/asset/memory-archive.js +97 -0
- package/dist/core/common.js +66 -2
- package/dist/core/config/config-walker.js +6 -10
- package/dist/core/config/config.js +11 -8
- package/dist/core/config/engine-semantics.js +0 -2
- package/dist/core/extra-params.js +17 -13
- package/dist/core/improve-result.js +1 -3
- package/dist/core/json-schema.js +9 -11
- package/dist/core/state/migrations.js +52 -2
- package/dist/core/state-db.js +2 -1
- package/dist/execution/executable-identity.js +1 -3
- package/dist/execution/guarded-source.js +1 -6
- package/dist/indexer/bundle-identity-guard.js +6 -1
- package/dist/indexer/db/graph-db.js +139 -154
- package/dist/indexer/ensure-index.js +11 -19
- package/dist/indexer/graph/graph-boost.js +23 -34
- package/dist/indexer/graph/graph-extraction.js +12 -2
- package/dist/indexer/indexer.js +1 -1
- package/dist/indexer/lookup/adapter-concept-owner.js +12 -9
- package/dist/indexer/passes/memory-inference.js +7 -2
- package/dist/indexer/scan/drain-dir.js +2 -4
- package/dist/indexer/search/db-search.js +3 -3
- package/dist/indexer/search/fts-query.js +10 -15
- package/dist/indexer/search/search-source.js +0 -13
- package/dist/indexer/usage/usage-events.js +9 -1
- package/dist/indexer/walk/walker.js +11 -6
- package/dist/integrations/harnesses/claude/result-extractor.js +30 -15
- package/dist/integrations/harnesses/codex/result-extractor.js +43 -6
- package/dist/integrations/harnesses/copilot/result-extractor.js +39 -12
- package/dist/integrations/harnesses/gemini/result-extractor.js +40 -12
- package/dist/integrations/harnesses/index.js +0 -4
- package/dist/integrations/harnesses/openhands/result-extractor.js +51 -19
- package/dist/integrations/harnesses/pi/result-extractor.js +45 -12
- package/dist/integrations/lockfile.js +0 -14
- package/dist/integrations/session-logs/index.js +0 -81
- package/dist/llm/client.js +0 -12
- package/dist/llm/memory-infer.js +1 -3
- package/dist/llm/usage-telemetry.js +1 -3
- package/dist/registry/create-provider-registry.js +4 -0
- package/dist/registry/factory.js +4 -0
- package/dist/registry/resolve.js +23 -8
- package/dist/runtime.js +0 -12
- package/dist/scripts/akm-migrate-node.js +155 -251
- package/dist/scripts/akm-migrate.js +155 -251
- package/dist/setup/setup.js +6 -12
- package/dist/sources/providers/git-install.js +7 -2
- package/dist/sources/providers/tar-utils.js +1 -7
- package/dist/sources/snapshot-fetchers/content-extract.js +0 -17
- package/dist/sources/snapshot-fetchers/website-ingest.js +126 -0
- package/dist/storage/managed-db.js +20 -7
- package/dist/storage/repositories/events-repository.js +0 -81
- package/dist/storage/repositories/index-connection.js +45 -3
- package/dist/storage/repositories/index-entries-repository.js +0 -17
- package/dist/storage/repositories/index-fts-repository.js +24 -30
- package/dist/storage/repositories/index-utility-repository.js +0 -57
- package/dist/storage/repositories/index-vec-repository.js +25 -27
- package/dist/storage/repositories/task-history-repository.js +9 -3
- package/dist/tasks/backends/cron.js +49 -9
- package/dist/tasks/backends/launchd.js +8 -18
- package/dist/tasks/resolve-akm-bin.js +17 -2
- package/dist/tasks/run/task-history.js +21 -31
- package/dist/tasks/scheduler-invocation.js +8 -1
- package/dist/tasks/scheduler-sync.js +1 -6
- package/dist/tasks/source/bounded-document.js +1 -14
- package/dist/tasks/source/parse-task-source.js +23 -9
- package/dist/workflows/exec/child-workflow.js +1 -1
- package/dist/workflows/exec/native-executor.js +2 -2
- package/dist/workflows/exec/step-work.js +5 -17
- package/dist/workflows/exec/worktree.js +40 -6
- package/dist/workflows/freeze/task-bindings.js +2 -4
- package/dist/workflows/ir/compile.js +3 -14
- package/dist/workflows/ir/schema-v4.js +4 -6
- package/dist/workflows/ir/schema.js +2 -5
- package/dist/workflows/parser.js +23 -26
- package/dist/workflows/source-files.js +8 -13
- package/dist/workflows/source-ir/schema.js +1 -19
- package/docs/migration/v0.9.0-troubleshooting.md +12 -2
- package/docs/reference/cli.md +7 -1
- package/docs/reference/workflow-schema.md +24 -0
- package/package.json +2 -5
- package/dist/assets/improve-strategies/frequent.json +0 -15
- package/dist/assets/improve-strategies/memory-focus.json +0 -15
- package/dist/workflows/source-ir/compare.js +0 -17
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,414 @@ All notable changes to this project will be documented in this file.
|
|
|
4
4
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
|
|
6
6
|
|
|
7
|
+
## [0.9.8-beta.1] - 2026-09-01
|
|
8
|
+
|
|
9
|
+
A cleanup and stabilization release: deletion of machinery that policed the
|
|
10
|
+
codebase's shape rather than its behaviour, and — because auditing for that
|
|
11
|
+
machinery meant reading the code closely — a run of real defects it had been
|
|
12
|
+
sitting on top of.
|
|
13
|
+
|
|
14
|
+
Two security holes, two search-correctness bugs, a locale-dependent hash, a
|
|
15
|
+
deletion shield that failed open, and sixteen places that answered a failure
|
|
16
|
+
with a confident wrong answer instead of an error.
|
|
17
|
+
|
|
18
|
+
### Fixed
|
|
19
|
+
|
|
20
|
+
- **Historical state migrations are reachable where akm cannot reinstall
|
|
21
|
+
itself** (#895). A migration flagged `historical-destructive` is refused
|
|
22
|
+
during an ordinary open — it needs a verified safety copy, taken under the
|
|
23
|
+
migration writer lock, so an unattended `akm index` can never quietly drop
|
|
24
|
+
operator state. That guard is correct and unchanged. Its *remedy* was not:
|
|
25
|
+
the only code path that admitted the migration ran as a post-install step of
|
|
26
|
+
`akm upgrade`, behind an npm install. Where akm is installed globally by a
|
|
27
|
+
container image and the runtime user is unprivileged, that install fails
|
|
28
|
+
`EACCES` and throws long before the migration is reached, so `akm index
|
|
29
|
+
--full` was blocked with no supported way out — and the two obvious
|
|
30
|
+
workarounds are both wrong (upgrading as root installs a *newer* akm than the
|
|
31
|
+
image ships, which `config-version-shim` then fails closed against; deleting
|
|
32
|
+
`state.db` destroys task history, proposals, and lessons metadata, none of
|
|
33
|
+
which is derived). New `akm upgrade --state-only` applies pending state
|
|
34
|
+
migrations and installs nothing. Nothing about the migration needed the
|
|
35
|
+
network, root, or a new binary; coupling it to one was the bug. The safety
|
|
36
|
+
copy is still taken — this changes who may request the migration, not what it
|
|
37
|
+
does.
|
|
38
|
+
|
|
39
|
+
- **Two security holes closed.** A failed `git ls-remote` made
|
|
40
|
+
`verifyClonedRevision` a no-op, silently skipping the R-011 post-clone
|
|
41
|
+
revision-integrity check — the guard against a compromised mirror — so any
|
|
42
|
+
network blip disabled it without a word. And `scanExtractedFiles`, the
|
|
43
|
+
post-extraction TOCTOU path-traversal rescan, returned silently when a
|
|
44
|
+
directory could not be read: it passed clean in exactly the race it exists
|
|
45
|
+
to catch. Both now fail loudly.
|
|
46
|
+
|
|
47
|
+
- **`akm curate --type` ignored the type filter.** A set `--type` bypassed
|
|
48
|
+
`selectCuratedStashHits` entirely and did a raw slice of the hits as
|
|
49
|
+
received, which neither filtered by type nor ranked by score — so
|
|
50
|
+
`--type command` could return a skill, in arbitrary order. It now narrows
|
|
51
|
+
the candidate pool and runs the full curation pipeline over it. The test
|
|
52
|
+
that should have caught this passed by accident, because the off-type hit
|
|
53
|
+
happened to sit past the result limit.
|
|
54
|
+
|
|
55
|
+
- **Curate silently dropped relevant results.** An undocumented floor excluded
|
|
56
|
+
any hit scoring below `max(0.35, leader * 0.7)`. Measured against a real
|
|
57
|
+
3,265-memory bundle, one query went from one result to four once it was
|
|
58
|
+
removed — the suppressed hits were the ones actually matching. Ordering is
|
|
59
|
+
unchanged: results were already sorted before the floor ran, so it could
|
|
60
|
+
only ever hide the tail.
|
|
61
|
+
|
|
62
|
+
- **A bundle-audit hash depended on the machine's locale.** `canonicalJson`
|
|
63
|
+
in `installed-stashes.ts` sorted keys with `localeCompare` — ICU-dependent —
|
|
64
|
+
and fed the result to `sha256Hex`, so the same object could hash differently
|
|
65
|
+
on two machines. Now codepoint order, matching the other implementations.
|
|
66
|
+
|
|
67
|
+
- **A deletion shield failed open.** `isHotCapturedMemory` returned false when
|
|
68
|
+
it could not read or parse a memory, marking exactly the memories it failed
|
|
69
|
+
to inspect as fair game for consolidate to merge or delete. It now fails
|
|
70
|
+
closed.
|
|
71
|
+
|
|
72
|
+
- **Sixteen places returned a confident wrong answer instead of an error.**
|
|
73
|
+
The pattern (#791) recurred across search, graph, indexing, and scheduling:
|
|
74
|
+
a corrupt or locked index reported "no matches"; a failed inline rebuild
|
|
75
|
+
surfaced as "Index is empty. Run 'akm index'" at exit 0; `akm show` reported
|
|
76
|
+
"0 related files" for an unreadable index; a DB failure in
|
|
77
|
+
`listProposalsReadOnly` returned `[]`, so dedup could not tell "no prior
|
|
78
|
+
proposal" from "database unreadable" and could re-mint an already-rejected
|
|
79
|
+
one; a permission fault on the bundle directory told the user to run
|
|
80
|
+
`akm bundle create`; and `launchd`'s `list()` returned `[]` when the
|
|
81
|
+
LaunchAgents directory could not be read, so task reconciliation concluded
|
|
82
|
+
there was nothing to manage. In each case the failure now surfaces.
|
|
83
|
+
|
|
84
|
+
- **Drifted copies of shared helpers.** `asNonEmptyString` trimmed in two
|
|
85
|
+
places and not in four others, so a whitespace-only session id decoded to
|
|
86
|
+
`" "` in some subsystems and `undefined` in others. `isPlainObject` had two
|
|
87
|
+
incompatible definitions under one name; the loose form would accept a
|
|
88
|
+
`Date` or class instance as a plain record. Both consolidated, along with
|
|
89
|
+
`toPosix` (15 copies, whose "avoid an import cycle" justification was false
|
|
90
|
+
in every case), `isRecord` (11), `compareCodePoints` (8), and five more
|
|
91
|
+
families.
|
|
92
|
+
|
|
93
|
+
- **Pruning a memory no longer leaves dangling belief edges (#885).**
|
|
94
|
+
`writeContradictEdge` — the hardened, test-covered `contradictedBy` writer —
|
|
95
|
+
had no production caller; its docstring named three that did not exist. The
|
|
96
|
+
live pass used a private near-copy that had drifted on exactly the two
|
|
97
|
+
behaviours the original was hardened for: it read the key with
|
|
98
|
+
`Array.isArray` only, so a SCALAR edge (live data the indexer accepts and
|
|
99
|
+
lint never flags) read as "no edges" and was overwritten out of existence;
|
|
100
|
+
and it set `beliefState: "contradicted"` unconditionally, promoting an
|
|
101
|
+
`archived` memory back up the ranking. The tests for both behaviours were
|
|
102
|
+
guarding dead code. The copy is gone.
|
|
103
|
+
|
|
104
|
+
`persistBeliefStateTransition` is deliberately NOT routed through the shared
|
|
105
|
+
primitive: it is a state-transition writer that replaces the edge list
|
|
106
|
+
wholesale and can clear it, which an append-only, never-weaken primitive
|
|
107
|
+
cannot express.
|
|
108
|
+
|
|
109
|
+
- **`git worktree` operations no longer fail on a busy machine (#891).** The
|
|
110
|
+
module's internal `GIT_TIMEOUT_MS` was a flat 30s with no margin, so a
|
|
111
|
+
healthy `git worktree remove` on a loaded host returned
|
|
112
|
+
`{ removed: false, error: "timed out after 30000ms" }`. Anyone running a
|
|
113
|
+
workflow with `isolation: worktree` alongside other git activity could hit
|
|
114
|
+
spurious create failures, or have a clean worktree wrongly retained as
|
|
115
|
+
unremovable. Raised to 120s, matching the existing `GIT_PUSH_TIMEOUT_MS`
|
|
116
|
+
precedent. Note `scripts/test-integration.sh` had already raised *bun's*
|
|
117
|
+
per-test timeout for this reason, but that never touched the production
|
|
118
|
+
subprocess timeout, which fires first.
|
|
119
|
+
|
|
120
|
+
- **`akm health`'s dead-link check no longer reports an unearned all-clear
|
|
121
|
+
(#892).** `checkDeadUrls` capped at 20 URLs across the whole bundle, plus an
|
|
122
|
+
undocumented `slice(0, 3)` per entry, then the caller logged "URL check
|
|
123
|
+
complete (0 dead)". A bundle with thousands of links got a clean bill of
|
|
124
|
+
health after twenty were examined. Both caps removed; every URL is checked
|
|
125
|
+
and a failed request surfaces instead of being swallowed.
|
|
126
|
+
|
|
127
|
+
- **`akm lint --fix` no longer breaks on gitignored drafts (#887).** The doc
|
|
128
|
+
linter walked `docs/` with no gitignore awareness, so unpublished drafts
|
|
129
|
+
under `docs/.pending/` were held to the published-docs contract —
|
|
130
|
+
`bun run lint` failed locally while CI, which never has those files, stayed
|
|
131
|
+
green.
|
|
132
|
+
|
|
133
|
+
### Changed
|
|
134
|
+
|
|
135
|
+
- **Search no longer truncates long queries (#892).** `MAX_LEXICAL_QUERY_TOKENS
|
|
136
|
+
= 16` silently dropped every token past the sixteenth, and tokens are
|
|
137
|
+
collected in order, so the discarded half was the tail — for
|
|
138
|
+
natural-language input, usually where the discriminating words are. It also
|
|
139
|
+
fed ranking, so token-overlap scoring ran on the truncated set too. It was
|
|
140
|
+
unexplained in the code and in the commit that introduced it, and unreachable
|
|
141
|
+
from any flag, config key, or environment variable. Removed: the planner
|
|
142
|
+
handles 10,000 tokens in 9ms, so no performance cliff was being protected.
|
|
143
|
+
|
|
144
|
+
- **Content and memory bodies are no longer silently truncated.**
|
|
145
|
+
`MAX_CONTENT_CHARS` (100k, duplicated across 8 adapters) cut indexed content
|
|
146
|
+
so the tail of a long document was unsearchable; `MAX_BODY_CHARS` (4000) cut
|
|
147
|
+
the text sent for memory inference, so on a large-context engine the model
|
|
148
|
+
saw a fraction of the input while the derived memory looked complete. Both
|
|
149
|
+
removed.
|
|
150
|
+
|
|
151
|
+
- **GitHub Actions are pinned to commit SHAs (#768).** All 29 `uses:` steps
|
|
152
|
+
across every workflow, with the tag preserved in a trailing comment.
|
|
153
|
+
|
|
154
|
+
- **Gated CI runs on schedule, dispatch, and candidate tags only.** The
|
|
155
|
+
`detect-changes` job that selected suites by regex-matching a PR diff is
|
|
156
|
+
gone — its path patterns had gone stale and still named test files this
|
|
157
|
+
release moved or deleted, so it was silently under-selecting suites. Release
|
|
158
|
+
evidence is unchanged; the checklist always required an exact-SHA dispatch.
|
|
159
|
+
|
|
160
|
+
- **`akm-eval` in CI is now a determinism check only.** Its score gates are
|
|
161
|
+
removed. Measured before cutting: the baseline scored a perfect 1.0 against
|
|
162
|
+
a 0.75 gate, and seven of nine case types never ran — CI has no LLM and no
|
|
163
|
+
run history, so everything the eval exists to measure was skipped while the
|
|
164
|
+
job reported green. The harness itself is unchanged and remains a genuine
|
|
165
|
+
quality signal when run against a real bundle.
|
|
166
|
+
|
|
167
|
+
### Removed
|
|
168
|
+
|
|
169
|
+
- **`akm health --clean-dead-residue` and every other compensating shim.**
|
|
170
|
+
A special-purpose flag on `health` that deleted files existed because
|
|
171
|
+
migrations had not finished their own job. Removing a superseded layout IS
|
|
172
|
+
migration, so `akm migrate status` now reports it and `akm migrate apply`
|
|
173
|
+
removes it. Four more of the same class went the same way: the D8
|
|
174
|
+
`task_history` vocabulary is rewritten once by a state migration instead of
|
|
175
|
+
re-decided at three read sites; the legacy `extraParams` config lift happens
|
|
176
|
+
once in `migrate apply` instead of silently on every load forever (an
|
|
177
|
+
unmigrated config now fails closed, naming the command to run); retired
|
|
178
|
+
`type:slug` xrefs are rewritten by `lint --fix`; and stale transaction
|
|
179
|
+
journals are recovered by `migrate apply` rather than reported by an
|
|
180
|
+
advisory that pointed at documentation while the recovery function it needed
|
|
181
|
+
sat with zero callers.
|
|
182
|
+
|
|
183
|
+
- **Dead code with no consumers.** An empty `{}` type threaded through two
|
|
184
|
+
functions as a parameter neither read, with a `{}` placeholder at the call
|
|
185
|
+
site; unused helpers, imports, and parameters throughout.
|
|
186
|
+
|
|
187
|
+
- **14 architecture ratchets, 15 golden/snapshot suites, 12 characterization
|
|
188
|
+
suites.** Function-size and import-cycle ratchets that failed on refactors
|
|
189
|
+
harming nothing; byte-for-byte snapshots "fixed" by regenerating; tests that
|
|
190
|
+
pinned "what the code does today" by definition.
|
|
191
|
+
- **11 of 14 lint scripts (-3,988 lines).** `lint-tests-isolation` alone was
|
|
192
|
+
717 lines standing in front of `src/core/paths.ts`, which already throws
|
|
193
|
+
`TEST_ISOLATION_MISSING` at runtime. Also removed: the `gen-config-schema
|
|
194
|
+
--check` gate (`build` regenerates the schema anyway, so what ships is always
|
|
195
|
+
current), and `lint-devto-posts` (322 lines that were wired to nothing and
|
|
196
|
+
duplicated checks `devto-cli` performs itself). The three kept catch
|
|
197
|
+
user-visible problems: secrets must route through the resolver, no dead refs
|
|
198
|
+
in shipped assets, no docs teaching commands that do not exist.
|
|
199
|
+
- **Both `MIN_TESTS` floors** — arbitrary numbers whose only job was to fail
|
|
200
|
+
the suite when test count dropped.
|
|
201
|
+
- **`release-workflow-syntax.yml`** — a workflow that ran actionlint over the
|
|
202
|
+
other workflows. A broken workflow file already fails at GitHub.
|
|
203
|
+
- **Dead `$STASH/.akm` residue is now reportable (#889).** `akm health` gains a
|
|
204
|
+
read-only `stash-dead-residue` advisory naming each stale path and its size;
|
|
205
|
+
deletion is gated behind an explicit `akm health --clean-dead-residue`. On a
|
|
206
|
+
real bundle 82% of `.akm` (135 MB) was pre-0.9.0 leftovers no code reads.
|
|
207
|
+
|
|
208
|
+
### Testing
|
|
209
|
+
|
|
210
|
+
- Test isolation grandfather list drained 58 -> 2 (#785); the two retained
|
|
211
|
+
entries are the helper-definitions file and a meta-test of the guard itself.
|
|
212
|
+
- The test tree now has a stated unit/integration rule and ~250 files were
|
|
213
|
+
reclassified by evidence — real DB, network, or process spawn — rather than
|
|
214
|
+
by filename (#786).
|
|
215
|
+
- 31 status-only `not.toBe(0)` assertions replaced with exact exit codes and
|
|
216
|
+
machine-readable error codes, every value observed rather than inferred
|
|
217
|
+
(#787).
|
|
218
|
+
- Near-duplicate clusters drained (#788); real-server timing flakes removed or
|
|
219
|
+
made deterministic (#789).
|
|
220
|
+
- Kept deliberately: `registry-network-boundary.test.ts`, which enforces that
|
|
221
|
+
only `pinned-transport.ts` may import `node:http`/`node:https` — the control
|
|
222
|
+
that stops a raw request bypassing address-pinned fetching. No lint script
|
|
223
|
+
covers that boundary.
|
|
224
|
+
|
|
225
|
+
## [0.9.7] - 2026-08-31
|
|
226
|
+
|
|
227
|
+
### Added
|
|
228
|
+
|
|
229
|
+
- **`akm curate --pack <tokens>` (#746).** Packs the ranked stash hits' full
|
|
230
|
+
content into a single token-budgeted blob instead of returning refs the
|
|
231
|
+
caller has to follow up on with N separate `akm show` calls. Content is
|
|
232
|
+
resolved through the same path `akm show` uses, so a `ref#fragment` hit
|
|
233
|
+
packs just that section. Drops whole assets from the tail of the ranked
|
|
234
|
+
list first; only a single highest-rank hit that alone exceeds the budget
|
|
235
|
+
is truncated. Registry hits are never packed — that separation stays
|
|
236
|
+
opt-in and there is no flag to override it. Named `--pack` rather than
|
|
237
|
+
`--budget` because the workflow asset schema already uses `budget` for
|
|
238
|
+
run-cost caps.
|
|
239
|
+
|
|
240
|
+
- **`llms.txt`-aware website ingestion (#749).** `akm bundle add` against an
|
|
241
|
+
origin root now probes `<origin>/llms.txt` first and, when present, uses
|
|
242
|
+
that author-curated link list as the crawl frontier instead of discovering
|
|
243
|
+
links by parsing HTML. Each linked page still flows through the same
|
|
244
|
+
robots-compliant, host-guarded, content-extracting fetch as before, so
|
|
245
|
+
ingested pages stay individually addressable. Off-origin manifest entries
|
|
246
|
+
are dropped. The probe is restricted to origin-root URLs, so adding a
|
|
247
|
+
specific page still fetches that page. Sites without the file fall through
|
|
248
|
+
to the existing crawler unchanged. `llms-full.txt` is deliberately not
|
|
249
|
+
read: its `## <path>` separators are ambiguous against real page content.
|
|
250
|
+
|
|
251
|
+
### Changed
|
|
252
|
+
|
|
253
|
+
- **The improve-strategy presets were reviewed as a set (#878).** The
|
|
254
|
+
investigation first believed `thorough` silently ran without validation;
|
|
255
|
+
that was wrong — every strategy deep-merges onto `default` before
|
|
256
|
+
resolving, so the old asset behaved correctly. What was real: `thorough`
|
|
257
|
+
was the only preset of ten relying on that invisible inheritance instead
|
|
258
|
+
of an explicit process matrix, and its triage used `applyMode: "queue"`
|
|
259
|
+
while its description promised to "drain the backlog" — queue mode never
|
|
260
|
+
promotes, so nothing drained. `catchup` had the same inertness:
|
|
261
|
+
`maxAcceptsPerRun: 100` under queue mode, a key the promote loop never
|
|
262
|
+
reads.
|
|
263
|
+
|
|
264
|
+
Both now use the same judged-promotion pattern as `reflect-distill` and
|
|
265
|
+
`proactive-maintenance`: `applyMode: "promote"`, `judgment: true`, a
|
|
266
|
+
per-run accept cap (`thorough` 25, `catchup` 100), and `maxDiffLines:
|
|
267
|
+
200`. The autonomy gate demotes promote back to queue unless
|
|
268
|
+
`experimental.improveAutonomy` is enabled, so by default both still
|
|
269
|
+
review-only; with autonomy on, they actually drain. `thorough` now
|
|
270
|
+
carries default's full explicit matrix, and a regression test pins
|
|
271
|
+
"everything default enables, thorough enables identically, plus triage."
|
|
272
|
+
|
|
273
|
+
### Fixed
|
|
274
|
+
|
|
275
|
+
- **Pruning a memory no longer leaves dangling belief edges (#884).**
|
|
276
|
+
`analyzeMemoryCleanup` archives a pruned memory rather than deleting it —
|
|
277
|
+
the file moves under `.akm/memory-cleanup/archive/` beside a `cleanup.md`
|
|
278
|
+
audit record naming its `ref` and `originalPath`. Ref resolution only ever
|
|
279
|
+
looked at the memory's original location, so once #882 made
|
|
280
|
+
`contradictedBy`/`supersededBy` validatable, every memory pointing at a
|
|
281
|
+
pruned one began reporting `missing-ref`. `refExistsInAnyStash` now resolves
|
|
282
|
+
the archive tombstone, so a belief edge to an archived memory is satisfied
|
|
283
|
+
instead of dangling. Existence only: `resolveRefPathInStash` still ignores
|
|
284
|
+
the archive, because it returns a path callers mutate (`--supersedes`
|
|
285
|
+
demotion) and an archived file must never be written to. The contradiction
|
|
286
|
+
an edge records is preserved rather than erased, which a bare edge-scrub
|
|
287
|
+
would have destroyed.
|
|
288
|
+
|
|
289
|
+
A ref whose target has neither a file nor a tombstone was removed by
|
|
290
|
+
something other than prune — a hand `git rm`, or a pre-fix release — and is
|
|
291
|
+
genuinely dangling. Clearing those deletes user assertions, so it is opt-in
|
|
292
|
+
behind `akm lint --prune-dangling-edges` and is deliberately NOT folded into
|
|
293
|
+
`--fix`: every other auto-fix repairs a malformed file, whereas this one
|
|
294
|
+
edits well-formed files to drop a claim about the belief graph. The repair
|
|
295
|
+
is scoped to the `supersededBy`/`contradictedBy` channels — a stale `xrefs`
|
|
296
|
+
entry is an ordinary broken link that the author may want to re-target, not
|
|
297
|
+
delete — and preserves comments, key order, and surviving list entries. It
|
|
298
|
+
clears the same `writable: false` gate `--fix` does.
|
|
299
|
+
|
|
300
|
+
Known limitation: if a memory's only edge on a channel is dropped, a
|
|
301
|
+
`beliefState:` naming that channel is left without a supporting edge.
|
|
302
|
+
Choosing a demotion target is a belief-semantics decision this fix does not
|
|
303
|
+
make. No occurrences existed in the stash that surfaced #884.
|
|
304
|
+
|
|
305
|
+
- **A corrupt `index.db` now rebuilds instead of failing the command
|
|
306
|
+
(#865).** `src/core/state-db.ts` documented that "a corrupt index is
|
|
307
|
+
recovered by deleting it and re-running `akm index`" — that recovery was
|
|
308
|
+
never implemented. Real on-disk corruption surfaced a raw `SQLITE_CORRUPT`
|
|
309
|
+
and exited 70, and the existing inline-reindex fallback could not help
|
|
310
|
+
because it reopened the same corrupt file. `openIndexDatabase` now detects
|
|
311
|
+
corruption, removes the file and its `-wal`/`-shm` sidecars, and retries
|
|
312
|
+
the open once. Scoped to `index.db`, which is fully regenerable from the
|
|
313
|
+
stash; `state.db` is never touched.
|
|
314
|
+
|
|
315
|
+
- **`akm task sync` accepts an immutable package-local install (#868).** An
|
|
316
|
+
image-baked akm pinned at a path outside the npm global root was refused
|
|
317
|
+
outright, and `--rebind` then warned on every sync that the pinned binary
|
|
318
|
+
was "mutable, unproven" — the opposite of true, training operators to
|
|
319
|
+
ignore a recurring warning. The npm-global check was only ever a proxy for
|
|
320
|
+
"this binary won't change out from under the scheduler"; that property is
|
|
321
|
+
now tested directly, so a launcher this process cannot write to (a
|
|
322
|
+
read-only mount) is eligible without `--rebind` and without the warning.
|
|
323
|
+
Writable `npx`/project-`node_modules` installs remain ineligible, which is
|
|
324
|
+
the case the original check existed for. No new config knob.
|
|
325
|
+
|
|
326
|
+
- **`TASK_SCHEMA_VERSION_UNSUPPORTED` names the actual blocker (#869).** For
|
|
327
|
+
a v2/v3 file the message is only reached after the read-time shim has
|
|
328
|
+
already tried and failed to convert it — meaning a human decision is
|
|
329
|
+
required — yet it pointed at `akm migrate apply`, which would report the
|
|
330
|
+
identical block for that same file. The blocked `reason`/`detail` were
|
|
331
|
+
already computed and then discarded; they are now surfaced, so the error
|
|
332
|
+
names the specific reason (e.g.
|
|
333
|
+
`shell-command-resolution-changes-v2-literal-argv-semantics`) and says a
|
|
334
|
+
decision is needed rather than sending the operator to a command that
|
|
335
|
+
cannot help.
|
|
336
|
+
|
|
337
|
+
Also verified as already fixed and left alone: cross-bundle scoping (a
|
|
338
|
+
blocked file in one bundle does not prevent conversion in another —
|
|
339
|
+
resolved by #866) and `env`-prefixed command conversion (resolved by
|
|
340
|
+
#867).
|
|
341
|
+
|
|
342
|
+
- **`akm task sync` no longer dead-ends on pre-0.9.2 crontab rows (#881).**
|
|
343
|
+
Rows written by v0.9.0/v0.9.1 carry no `--scheduler-context` marker, so
|
|
344
|
+
`extractCronInvocation` could not parse them. Sync therefore saw the task
|
|
345
|
+
as absent, tried to install it, and collided with the row that was still
|
|
346
|
+
physically present — permanently blocking sync for every task on any
|
|
347
|
+
install upgrading past v0.9.2. Such a row is now recognized and
|
|
348
|
+
reconciled. The fallback fires only when the marker is entirely absent
|
|
349
|
+
and only inside akm's own `# akm:task … BEGIN/END` sentinels, so a row
|
|
350
|
+
carrying the marker that fails to parse for any other reason is never
|
|
351
|
+
reinterpreted, and no ownership or cardinality assertion changed.
|
|
352
|
+
|
|
353
|
+
- **`akm lint` validates `type:slug` xrefs instead of silently skipping
|
|
354
|
+
them (#882).** `typeNameFromConceptId` returns `undefined` for the colon
|
|
355
|
+
grammar, so `classifyConceptRef` treated those refs as "not a local ref"
|
|
356
|
+
and dropped them before validation — roughly half the xref channel on a
|
|
357
|
+
real corpus. Zero `missing-ref` findings read as "every reference is
|
|
358
|
+
healthy" when half had never been examined. akm still writes this
|
|
359
|
+
grammar today (`memory-contradiction-detect.ts` emits `contradictedBy:`
|
|
360
|
+
as `memory:<name>`), so it is a live channel, not legacy residue; it is
|
|
361
|
+
now accepted as a fallback in lint only, leaving the parser and write
|
|
362
|
+
paths on the single conceptId grammar.
|
|
363
|
+
|
|
364
|
+
- **Refs to derived memories resolve (#882).** `assetPathCandidatesForName`
|
|
365
|
+
only ever offered `<name>.md`, so any ref to a memory stored as
|
|
366
|
+
`<name>.derived.md` failed to resolve — affecting the conceptId grammar
|
|
367
|
+
equally, and invisible until the above fix made these refs validatable.
|
|
368
|
+
`.derived` is a provenance marker on the same identity, not part of the
|
|
369
|
+
name, so `<name>.derived.md` is now a secondary candidate with plain
|
|
370
|
+
`<name>.md` still taking precedence when both exist. Fixed at the
|
|
371
|
+
resolution primitive, so write-time `--xref`/`--supersedes` validation
|
|
372
|
+
benefits as well.
|
|
373
|
+
|
|
374
|
+
### Removed
|
|
375
|
+
|
|
376
|
+
- **The `frequent` and `memory-focus` improve strategies.** Zero recorded
|
|
377
|
+
invocations, and both were mid-points of other presets (`frequent` ≈
|
|
378
|
+
`reflect-distill` without distill or triage; `memory-focus` a subset of
|
|
379
|
+
`frequent`). The shipped hourly task template now uses `reflect-distill`
|
|
380
|
+
— matching what real deployments had already switched to by hand. Any
|
|
381
|
+
removed combination remains expressible via `improve.strategies` in
|
|
382
|
+
config. One caveat: a user-config strategy *named* `frequent` or
|
|
383
|
+
`memory-focus` previously merged over the built-in of the same name; it
|
|
384
|
+
now merges over `default` only, so a partial override that relied on the
|
|
385
|
+
built-in's values will resolve differently and should be made explicit.
|
|
386
|
+
|
|
387
|
+
### Testing
|
|
388
|
+
|
|
389
|
+
- **The previous-release corpus covers more than task sources (#880).**
|
|
390
|
+
Added fixtures for the synthesized `AKM_BUNDLE_DIR` duplicate-`stash`
|
|
391
|
+
bundle shape that caused #870, the retired 0.8 `stashDir`/`sources[]`/
|
|
392
|
+
`installed[]` config keys, and a downstream consumer's `config.json` plus
|
|
393
|
+
four task-source-v4 files. The 0.8 fixture deliberately asserts the
|
|
394
|
+
opposite of the others: those keys are hard-rejected by design, so it
|
|
395
|
+
guards that the rejection stays loud and actionable rather than silently
|
|
396
|
+
loading. Every fixture was proven to catch a regression by breaking the
|
|
397
|
+
guarantee, observing the failure, and reverting.
|
|
398
|
+
|
|
399
|
+
- Pinned current handling of truncated LLM responses (`finishReason:
|
|
400
|
+
"length"`) as a regression test (#865). No distinct classification or
|
|
401
|
+
retry was added: the underlying truncation was already resolved by
|
|
402
|
+
`reasoningEffort`, and threading the finish reason through four layers to
|
|
403
|
+
earn one diagnostic label was not justified.
|
|
404
|
+
|
|
405
|
+
### Not shipped
|
|
406
|
+
|
|
407
|
+
- **Orphan-asset detection for `akm health` (#750)** was implemented and
|
|
408
|
+
then backed out after measurement. Against a live 23,859-entry index it
|
|
409
|
+
flagged 16,609 of 16,615 in-scope assets (99.96%) and took 135 s. The
|
|
410
|
+
corpus is not densely cross-linked — 1,591 distinct xref tokens exist in
|
|
411
|
+
total — so the check has no signal to give. The broken-ref half of #750
|
|
412
|
+
had already shipped previously. Moved to Backlog; see #882 for the
|
|
413
|
+
resolver defect the investigation exposed.
|
|
414
|
+
|
|
7
415
|
## [0.9.6] - 2026-08-31
|
|
8
416
|
|
|
9
417
|
The deletion release: **net −2,100 lines**, almost all of it machinery that
|
|
@@ -245,8 +245,8 @@ akm improve --no-push # commit but skip push for this ru
|
|
|
245
245
|
akm improve --sync # force sync even on strategies that disable it
|
|
246
246
|
```
|
|
247
247
|
|
|
248
|
-
Strategy sync defaults: `catchup`, `consolidate`, `default`,
|
|
249
|
-
`graph-refresh`, `
|
|
248
|
+
Strategy sync defaults: `catchup`, `consolidate`, `default`,
|
|
249
|
+
`graph-refresh`, `quick`, and `thorough` auto-commit + push;
|
|
250
250
|
`proactive-maintenance` and `reflect-distill` skip sync entirely. Override
|
|
251
251
|
with `--sync` / `--no-sync` flags.
|
|
252
252
|
|
|
@@ -355,7 +355,7 @@ scheduler (cron / launchd / schtasks). The file is the source of truth:
|
|
|
355
355
|
file plus one `sync` is a complete workflow.
|
|
356
356
|
|
|
357
357
|
```sh
|
|
358
|
-
akm task add nightly-improve --schedule "@daily" --command "akm improve --strategy
|
|
358
|
+
akm task add nightly-improve --schedule "@daily" --command "akm improve --strategy default"
|
|
359
359
|
akm task add briefing --schedule "0 9 * * *" --prompt "Draft the morning briefing" # Inline command task
|
|
360
360
|
akm task sync # Reconcile task files with the OS scheduler
|
|
361
361
|
akm task sync --rebind # Also re-pin the scheduler's akm binary/spelling
|
|
@@ -1,15 +1,44 @@
|
|
|
1
1
|
{
|
|
2
|
-
"description": "Manual catch-up
|
|
2
|
+
"description": "Manual catch-up \u2014 consolidation plus a judged triage drain (up to 100 accepts) with no interval minimum. Auto-accepts only when improve autonomy is enabled; otherwise proposals queue for review.",
|
|
3
3
|
"processes": {
|
|
4
|
-
"reflect": {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
"
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
"
|
|
11
|
-
|
|
12
|
-
|
|
4
|
+
"reflect": {
|
|
5
|
+
"enabled": false
|
|
6
|
+
},
|
|
7
|
+
"distill": {
|
|
8
|
+
"enabled": false
|
|
9
|
+
},
|
|
10
|
+
"consolidate": {
|
|
11
|
+
"enabled": true,
|
|
12
|
+
"allowedTypes": ["memory"],
|
|
13
|
+
"maxChunkSize": 50,
|
|
14
|
+
"minPoolSize": 0
|
|
15
|
+
},
|
|
16
|
+
"memoryInference": {
|
|
17
|
+
"enabled": false
|
|
18
|
+
},
|
|
19
|
+
"graphExtraction": {
|
|
20
|
+
"enabled": false
|
|
21
|
+
},
|
|
22
|
+
"extract": {
|
|
23
|
+
"enabled": false
|
|
24
|
+
},
|
|
25
|
+
"triage": {
|
|
26
|
+
"enabled": true,
|
|
27
|
+
"applyMode": "promote",
|
|
28
|
+
"policy": "personal-stash",
|
|
29
|
+
"maxAcceptsPerRun": 100,
|
|
30
|
+
"judgment": true,
|
|
31
|
+
"maxDiffLines": 200
|
|
32
|
+
},
|
|
33
|
+
"validation": {
|
|
34
|
+
"enabled": false
|
|
35
|
+
},
|
|
36
|
+
"proactiveMaintenance": {
|
|
37
|
+
"enabled": false
|
|
38
|
+
}
|
|
13
39
|
},
|
|
14
|
-
"sync": {
|
|
40
|
+
"sync": {
|
|
41
|
+
"enabled": true,
|
|
42
|
+
"push": true
|
|
43
|
+
}
|
|
15
44
|
}
|
|
@@ -1,15 +1,53 @@
|
|
|
1
1
|
{
|
|
2
|
-
"description": "
|
|
2
|
+
"description": "Everything default runs, plus a judged triage drain of the pending-proposal backlog (up to 25 accepts per run). Auto-accepts only when improve autonomy is enabled; otherwise proposals queue for review. Identical tuning to default; improve-stage extract and proactive maintenance stay off.",
|
|
3
3
|
"processes": {
|
|
4
4
|
"reflect": {
|
|
5
5
|
"enabled": true,
|
|
6
|
+
"limit": 25,
|
|
6
7
|
"allowedTypes": ["agent", "command", "knowledge", "lesson", "memory", "skill", "workflow"]
|
|
7
8
|
},
|
|
8
|
-
"distill": {
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
9
|
+
"distill": {
|
|
10
|
+
"enabled": true,
|
|
11
|
+
"allowedTypes": ["memory"],
|
|
12
|
+
"requirePlannedRefs": true
|
|
13
|
+
},
|
|
14
|
+
"consolidate": {
|
|
15
|
+
"enabled": true,
|
|
16
|
+
"allowedTypes": ["memory"],
|
|
17
|
+
"minPoolSize": 500
|
|
18
|
+
},
|
|
19
|
+
"memoryInference": {
|
|
20
|
+
"enabled": true
|
|
21
|
+
},
|
|
22
|
+
"graphExtraction": {
|
|
23
|
+
"enabled": true
|
|
24
|
+
},
|
|
25
|
+
"extract": {
|
|
26
|
+
"enabled": false,
|
|
27
|
+
"triage": {
|
|
28
|
+
"enabled": true,
|
|
29
|
+
"minScore": 2
|
|
30
|
+
}
|
|
31
|
+
},
|
|
32
|
+
"validation": {
|
|
33
|
+
"enabled": true
|
|
34
|
+
},
|
|
35
|
+
"proactiveMaintenance": {
|
|
36
|
+
"enabled": false,
|
|
37
|
+
"dueDays": 30,
|
|
38
|
+
"maxPerRun": 15
|
|
39
|
+
},
|
|
40
|
+
"triage": {
|
|
41
|
+
"enabled": true,
|
|
42
|
+
"applyMode": "promote",
|
|
43
|
+
"policy": "personal-stash",
|
|
44
|
+
"maxAcceptsPerRun": 25,
|
|
45
|
+
"maxDiffLines": 200,
|
|
46
|
+
"judgment": true
|
|
47
|
+
}
|
|
13
48
|
},
|
|
14
|
-
"sync": {
|
|
49
|
+
"sync": {
|
|
50
|
+
"enabled": true,
|
|
51
|
+
"push": true
|
|
52
|
+
}
|
|
15
53
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
version: 4
|
|
2
|
-
run: akm improve --strategy
|
|
3
|
-
description: Frequent
|
|
2
|
+
run: akm improve --strategy reflect-distill --skip-if-locked
|
|
3
|
+
description: Frequent learning pass (hourly at :40) — reflect, distill, memory inference, judged triage
|
|
4
4
|
schedule: "40 * * * *"
|
|
@@ -139,6 +139,16 @@ export const lintCommand = defineCommand({
|
|
|
139
139
|
description: "Exit non-zero when summary.flagged > 0 (CI-friendly). Default: exit 0 regardless of findings.",
|
|
140
140
|
default: false,
|
|
141
141
|
},
|
|
142
|
+
// #884: NOT folded into `--fix`. Every other auto-fix repairs a structural
|
|
143
|
+
// defect in the file it edits; this one DELETES an assertion the user (or
|
|
144
|
+
// the improve pipeline) made about the belief graph, and it does so in
|
|
145
|
+
// files that are themselves perfectly well-formed. That is a data decision,
|
|
146
|
+
// so it stays opt-in behind its own flag even when `--fix` is present.
|
|
147
|
+
"prune-dangling-edges": {
|
|
148
|
+
type: "boolean",
|
|
149
|
+
description: "Opt-in repair: drop supersededBy/contradictedBy entries whose target has neither a file nor a prune tombstone. Modifies memories — review the plain `akm lint` report first.",
|
|
150
|
+
default: false,
|
|
151
|
+
},
|
|
142
152
|
type: {
|
|
143
153
|
type: "string",
|
|
144
154
|
description: "Only lint assets of this type (e.g. workflows, tasks, memories). akm bundles only — every other adapter validates the whole bundle and warns that the flag had no effect.",
|
|
@@ -151,6 +161,7 @@ export const lintCommand = defineCommand({
|
|
|
151
161
|
fix: args.fix === true || getHyphenatedBoolean(args, "auto-fix"),
|
|
152
162
|
dir: getStringArg(args, "dir"),
|
|
153
163
|
typeFilter: getStringArg(args, "type"),
|
|
164
|
+
pruneDanglingEdges: getHyphenatedBoolean(args, "prune-dangling-edges"),
|
|
154
165
|
});
|
|
155
166
|
output("lint", result);
|
|
156
167
|
if (args["fail-on-flagged"] && result.summary.flagged > 0) {
|
package/dist/commands/env/env.js
CHANGED
|
@@ -48,28 +48,9 @@
|
|
|
48
48
|
import fs from "node:fs";
|
|
49
49
|
import path from "node:path";
|
|
50
50
|
import dotenv from "dotenv";
|
|
51
|
-
import { writeFileAtomic } from "../../core/common.js";
|
|
51
|
+
import { scanEnvKeyNames, writeFileAtomic } from "../../core/common.js";
|
|
52
52
|
import { sensitiveMarkerPath } from "./marker-path.js";
|
|
53
|
-
|
|
54
|
-
const ASSIGN_RE = /^\s*(?:export\s+)?([A-Za-z_][A-Za-z0-9_]*)\s*=/;
|
|
55
|
-
/** Scan lines and return KEY names in file order, without duplicates. */
|
|
56
|
-
export function scanEnvKeyNames(text) {
|
|
57
|
-
const keys = [];
|
|
58
|
-
const seen = new Set();
|
|
59
|
-
for (const line of text.split(/\r?\n/)) {
|
|
60
|
-
const m = line.match(ASSIGN_RE);
|
|
61
|
-
if (!m)
|
|
62
|
-
continue;
|
|
63
|
-
const key = m[1];
|
|
64
|
-
if (!key)
|
|
65
|
-
continue;
|
|
66
|
-
if (seen.has(key))
|
|
67
|
-
continue;
|
|
68
|
-
seen.add(key);
|
|
69
|
-
keys.push(key);
|
|
70
|
-
}
|
|
71
|
-
return keys;
|
|
72
|
-
}
|
|
53
|
+
export { scanEnvKeyNames };
|
|
73
54
|
/**
|
|
74
55
|
* Read and return ONLY non-secret metadata: key names.
|
|
75
56
|
*
|
|
@@ -706,29 +706,4 @@ export const HEALTH_CHECKS = [
|
|
|
706
706
|
};
|
|
707
707
|
},
|
|
708
708
|
},
|
|
709
|
-
{
|
|
710
|
-
// Item 4: stale durable-transaction journals under $DATA/txn (stranded
|
|
711
|
-
// recovery state seen twice in a real 0.9 migration) had zero health
|
|
712
|
-
// visibility. `count`/`unreadable` already exclude journals younger than
|
|
713
|
-
// the sweeper's grace period (a currently-running operation), so any
|
|
714
|
-
// nonzero count here is a real leftover.
|
|
715
|
-
name: "stale-txn-journals",
|
|
716
|
-
channel: "advisory",
|
|
717
|
-
run: (ctx) => {
|
|
718
|
-
const s = ctx.staleTxnJournals;
|
|
719
|
-
const warn = s.count > 0;
|
|
720
|
-
const unreadablePart = s.unreadable > 0 ? `, ${s.unreadable} unreadable` : "";
|
|
721
|
-
const agePart = s.oldestAgeMs !== null ? `, oldest ${Math.round(s.oldestAgeMs / 60000)}m old` : "";
|
|
722
|
-
return {
|
|
723
|
-
name: "stale-txn-journals",
|
|
724
|
-
kind: "deterministic",
|
|
725
|
-
status: warn ? "warn" : "pass",
|
|
726
|
-
confidence: "high",
|
|
727
|
-
message: warn
|
|
728
|
-
? `${s.count} stale transaction journal(s) found under ${s.dir}${unreadablePart}${agePart} — see docs/migration/v0.9.0-troubleshooting.md for journal reconciliation steps.`
|
|
729
|
-
: "No stale transaction journals found.",
|
|
730
|
-
evidence: { dir: s.dir, count: s.count, unreadable: s.unreadable, oldestAgeMs: s.oldestAgeMs },
|
|
731
|
-
};
|
|
732
|
-
},
|
|
733
|
-
},
|
|
734
709
|
];
|