akm-cli 0.8.0 → 0.8.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 +47 -0
- package/dist/assets/profiles/default.json +15 -0
- package/dist/assets/profiles/graph-refresh.json +13 -0
- package/dist/assets/profiles/memory-focus.json +12 -0
- package/dist/assets/profiles/quick.json +15 -0
- package/dist/assets/profiles/thorough.json +15 -0
- package/dist/assets/tasks/graph-refresh-weekly.yml +10 -0
- package/dist/commands/consolidate.js +32 -11
- package/dist/commands/extract-prompt.js +14 -1
- package/dist/commands/health.js +69 -8
- package/dist/commands/improve-cli.js +1 -1
- package/dist/commands/improve-profiles.js +13 -59
- package/dist/commands/improve.js +38 -41
- package/dist/commands/info.js +23 -28
- package/dist/indexer/indexer.js +2 -2
- package/dist/llm/graph-extract.js +1 -1
- package/dist/output/cli-hints.js +2 -2
- package/dist/tasks/backends/launchd.js +1 -1
- package/dist/tasks/backends/schtasks.js +1 -1
- package/dist/wiki/wiki-templates.js +3 -3
- package/dist/wiki/wiki.js +1 -1
- package/dist/workflows/authoring.js +1 -1
- package/package.json +1 -1
- /package/dist/{tasks → assets}/backends/launchd-template.xml +0 -0
- /package/dist/{tasks → assets}/backends/schtasks-template.xml +0 -0
- /package/dist/{commands → assets}/help/help-accept.md +0 -0
- /package/dist/{commands → assets}/help/help-improve.md +0 -0
- /package/dist/{commands → assets}/help/help-proposals.md +0 -0
- /package/dist/{commands → assets}/help/help-propose.md +0 -0
- /package/dist/{commands → assets}/help/help-reject.md +0 -0
- /package/dist/{output → assets/hints}/cli-hints-full.md +0 -0
- /package/dist/{output → assets/hints}/cli-hints-short.md +0 -0
- /package/dist/{llm → assets}/prompts/extract-session.md +0 -0
- /package/dist/{llm → assets}/prompts/graph-extract-user-prompt.md +0 -0
- /package/dist/{wiki → assets/wiki}/index-template.md +0 -0
- /package/dist/{wiki → assets/wiki}/ingest-workflow-template.md +0 -0
- /package/dist/{wiki → assets/wiki}/log-template.md +0 -0
- /package/dist/{wiki → assets/wiki}/schema-template.md +0 -0
- /package/dist/{workflows → assets/workflows}/workflow-template.md +0 -0
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,53 @@ 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.8.1] - 2026-06-05
|
|
8
|
+
|
|
9
|
+
### Added
|
|
10
|
+
|
|
11
|
+
- **`graph-refresh` improve profile** — new built-in profile that runs a full-corpus
|
|
12
|
+
graph extraction pass across all stash files (all other improve processes disabled).
|
|
13
|
+
Use `akm improve --profile graph-refresh` for a weekly relationship rebuild.
|
|
14
|
+
Pairs with the new `graph-refresh-weekly` task template (`akm tasks add --template graph-refresh-weekly`).
|
|
15
|
+
- **`session-extraction` health advisory** — new heuristic advisory backed by real
|
|
16
|
+
`akmExtract` outcomes: warns when the session-extraction process ran but produced
|
|
17
|
+
zero proposals across ≥ 5 sessions, or recorded warnings. Replaces the vestigial
|
|
18
|
+
`session-log-failures` warn signal.
|
|
19
|
+
- **`improve.sessionExtraction` health metrics** — `sessionsScanned`, `sessionsExtracted`,
|
|
20
|
+
`sessionsSkipped`, `proposalsCreated`, `warnings`, `durationMs` now tracked and
|
|
21
|
+
visible in `akm health` reports.
|
|
22
|
+
|
|
23
|
+
### Fixed
|
|
24
|
+
|
|
25
|
+
- **`akm info` indexStats** — `readIndexStats` errors are now surfaced and the resolved
|
|
26
|
+
DB path is passed correctly; `entryCount`, `hasEmbeddings`, and related fields are
|
|
27
|
+
no longer silently empty (#510).
|
|
28
|
+
- **Indexer timing fields** — `embedMs` and `ftsMs` in timing output had their
|
|
29
|
+
operands swapped, producing negative durations. Fixed (#516).
|
|
30
|
+
- **Incremental consolidation gate** — the `volumeTriggered` path bypassed the
|
|
31
|
+
incremental gate introduced in 0.8.0, causing consolidation to run on chunks it
|
|
32
|
+
had already processed in the same run. Fixed.
|
|
33
|
+
- **Improve budget exhaustion** — `improve.lock` was not released after budget
|
|
34
|
+
exhaustion, blocking subsequent runs until the lock TTL expired.
|
|
35
|
+
- **Consolidation chunk retry** — failed chunks are now retried once with a 2 s
|
|
36
|
+
backoff before being recorded as lost, reducing transient LLM errors from
|
|
37
|
+
propagating to `chunksFailed`.
|
|
38
|
+
- **`yieldRate` health metric** — `skippedAborted` refs were incorrectly counted in
|
|
39
|
+
`freshAttempts`, inflating the denominator and underreporting yield rate.
|
|
40
|
+
- **`session-log-failures` advisory** — demoted from `warn` to always `pass`
|
|
41
|
+
(informational only); the advisory was a raw regex counter with no LLM signal,
|
|
42
|
+
producing false positives on normal session content.
|
|
43
|
+
|
|
44
|
+
### Refactored
|
|
45
|
+
|
|
46
|
+
- All runtime assets consolidated under `src/assets/` with `dist/assets/` mirroring
|
|
47
|
+
the layout exactly. Built-in improve profiles moved from in-source object literals
|
|
48
|
+
to embedded JSON files (`src/assets/profiles/*.json`). The `copy-assets.ts` build
|
|
49
|
+
step now uses a precise `src/assets/**/*` glob instead of a broad catch-all.
|
|
50
|
+
- Vestigial Phase 0 (`getExecutionLogCandidates` / `ERROR_PATTERNS`) removed from
|
|
51
|
+
the improve pipeline. This regex scan collected a metric count but never fed an
|
|
52
|
+
LLM; `akmExtract` (Phase 0.4) is the real session extraction pipeline.
|
|
53
|
+
|
|
7
54
|
## [0.8.0] - 2026-05-28
|
|
8
55
|
|
|
9
56
|
### Performance
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
{
|
|
2
|
+
"description": "Standard improve pass — all sub-processes, markdown asset types.",
|
|
3
|
+
"processes": {
|
|
4
|
+
"reflect": {
|
|
5
|
+
"enabled": true,
|
|
6
|
+
"allowedTypes": ["agent", "command", "knowledge", "lesson", "memory", "skill", "wiki", "workflow"]
|
|
7
|
+
},
|
|
8
|
+
"distill": { "enabled": true, "allowedTypes": ["memory"] },
|
|
9
|
+
"consolidate": { "enabled": true, "allowedTypes": ["memory"] },
|
|
10
|
+
"memoryInference": { "enabled": true },
|
|
11
|
+
"graphExtraction": { "enabled": true },
|
|
12
|
+
"triage": { "enabled": false, "applyMode": "queue", "policy": "personal-stash" }
|
|
13
|
+
},
|
|
14
|
+
"sync": { "enabled": true, "push": true }
|
|
15
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
{
|
|
2
|
+
"description": "Full-corpus graph extraction pass — rebuilds graph relationships across all stash files. Disables all other sub-processes. Use via `akm improve --profile graph-refresh` or the embedded `graph-refresh-weekly` task.",
|
|
3
|
+
"processes": {
|
|
4
|
+
"reflect": { "enabled": false },
|
|
5
|
+
"distill": { "enabled": false },
|
|
6
|
+
"consolidate": { "enabled": false },
|
|
7
|
+
"memoryInference": { "enabled": false },
|
|
8
|
+
"graphExtraction": { "enabled": true, "fullScan": true },
|
|
9
|
+
"extract": { "enabled": false },
|
|
10
|
+
"triage": { "enabled": false }
|
|
11
|
+
},
|
|
12
|
+
"sync": { "enabled": true, "push": true }
|
|
13
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
{
|
|
2
|
+
"description": "Memory and lesson improvement only — no distill, consolidate, or graphExtraction.",
|
|
3
|
+
"processes": {
|
|
4
|
+
"reflect": { "enabled": true, "allowedTypes": ["memory", "lesson"] },
|
|
5
|
+
"distill": { "enabled": false },
|
|
6
|
+
"consolidate": { "enabled": false },
|
|
7
|
+
"memoryInference": { "enabled": true },
|
|
8
|
+
"graphExtraction": { "enabled": false },
|
|
9
|
+
"triage": { "enabled": false }
|
|
10
|
+
},
|
|
11
|
+
"sync": { "enabled": false }
|
|
12
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
{
|
|
2
|
+
"description": "Reflect-only pass — no distill, consolidate, memoryInference, or graphExtraction.",
|
|
3
|
+
"processes": {
|
|
4
|
+
"reflect": {
|
|
5
|
+
"enabled": true,
|
|
6
|
+
"allowedTypes": ["agent", "command", "knowledge", "lesson", "memory", "skill", "wiki", "workflow"]
|
|
7
|
+
},
|
|
8
|
+
"distill": { "enabled": false },
|
|
9
|
+
"consolidate": { "enabled": false },
|
|
10
|
+
"memoryInference": { "enabled": false },
|
|
11
|
+
"graphExtraction": { "enabled": false },
|
|
12
|
+
"triage": { "enabled": false }
|
|
13
|
+
},
|
|
14
|
+
"sync": { "enabled": false }
|
|
15
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
{
|
|
2
|
+
"description": "All sub-processes enabled (currently identical to default; reserved for future divergence).",
|
|
3
|
+
"processes": {
|
|
4
|
+
"reflect": {
|
|
5
|
+
"enabled": true,
|
|
6
|
+
"allowedTypes": ["agent", "command", "knowledge", "lesson", "memory", "skill", "wiki", "workflow"]
|
|
7
|
+
},
|
|
8
|
+
"distill": { "enabled": true, "allowedTypes": ["memory"] },
|
|
9
|
+
"consolidate": { "enabled": true, "allowedTypes": ["memory"] },
|
|
10
|
+
"memoryInference": { "enabled": true },
|
|
11
|
+
"graphExtraction": { "enabled": true },
|
|
12
|
+
"triage": { "enabled": true, "applyMode": "queue" }
|
|
13
|
+
},
|
|
14
|
+
"sync": { "enabled": true, "push": true }
|
|
15
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
id: graph-refresh-weekly
|
|
2
|
+
description: >
|
|
3
|
+
Weekly full-corpus graph extraction pass. Rebuilds entity and relation
|
|
4
|
+
indexes across all stash files using the graph-refresh improve profile.
|
|
5
|
+
Complements the per-run improve pipeline which only extracts graph data
|
|
6
|
+
for files touched by actionable refs.
|
|
7
|
+
command: akm improve --profile graph-refresh
|
|
8
|
+
schedule: "0 3 * * 0"
|
|
9
|
+
enabled: false
|
|
10
|
+
timeout: 3600000
|
|
@@ -965,7 +965,7 @@ export async function akmConsolidate(opts = {}) {
|
|
|
965
965
|
}
|
|
966
966
|
warn(`[consolidate] chunk ${chunkIdx + 1}/${chunks.length} (${chunk.length} memories) …`);
|
|
967
967
|
const userPrompt = buildChunkPrompt(sourceName, chunk, chunkIdx, chunks.length, bodyTruncation, pendingProposalBodyHashes);
|
|
968
|
-
|
|
968
|
+
let raw = await tryLlmFeature("memory_consolidation", config, async () => {
|
|
969
969
|
if (!llmConfig)
|
|
970
970
|
return { ok: false, error: "No LLM configured for consolidation" };
|
|
971
971
|
try {
|
|
@@ -985,16 +985,37 @@ export async function akmConsolidate(opts = {}) {
|
|
|
985
985
|
}
|
|
986
986
|
}, { ok: false, error: `chunk ${chunkIdx + 1} failed` });
|
|
987
987
|
if (!raw.ok) {
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
988
|
+
// Single retry with 2s backoff before recording chunk as lost.
|
|
989
|
+
// Recovers transient Shredder LM Studio timeouts without significantly
|
|
990
|
+
// extending run time. Only marks failed if both attempts fail.
|
|
991
|
+
await new Promise((r) => setTimeout(r, 2_000));
|
|
992
|
+
const retry = await tryLlmFeature("memory_consolidation", config, async () => {
|
|
993
|
+
if (!llmConfig)
|
|
994
|
+
return { ok: false, error: "No LLM configured for consolidation" };
|
|
995
|
+
try {
|
|
996
|
+
const content = await chatCompletion(llmConfig, [
|
|
997
|
+
{ role: "system", content: CONSOLIDATE_SYSTEM_PROMPT },
|
|
998
|
+
{ role: "user", content: userPrompt },
|
|
999
|
+
], { responseSchema: CONSOLIDATE_PLAN_JSON_SCHEMA, enableThinking: false });
|
|
1000
|
+
return { ok: true, content };
|
|
1001
|
+
}
|
|
1002
|
+
catch (e) {
|
|
1003
|
+
return { ok: false, error: String(e) };
|
|
1004
|
+
}
|
|
1005
|
+
}, { ok: false, error: `chunk ${chunkIdx + 1} retry failed` });
|
|
1006
|
+
if (!retry.ok) {
|
|
1007
|
+
warn(retry.error ?? `chunk ${chunkIdx + 1} failed after retry`);
|
|
1008
|
+
warnings.push(retry.error ?? `chunk ${chunkIdx + 1} failed after retry`);
|
|
1009
|
+
totalChunksProcessed++;
|
|
1010
|
+
totalChunksFailed++;
|
|
1011
|
+
// Account for the chunk's memories under the failed-chunk bucket.
|
|
1012
|
+
// judgedNoAction does NOT run on this path (it's after the success
|
|
1013
|
+
// guards) so without this the accounting invariant breaks on every
|
|
1014
|
+
// chunk-level transport/parse failure.
|
|
1015
|
+
failedChunkMemories += chunk.length;
|
|
1016
|
+
continue;
|
|
1017
|
+
}
|
|
1018
|
+
raw = retry;
|
|
998
1019
|
}
|
|
999
1020
|
if (process.env.AKM_DEBUG_LLM) {
|
|
1000
1021
|
const preview = (raw.content ?? "").slice(0, 500);
|
|
@@ -1,7 +1,20 @@
|
|
|
1
1
|
// This Source Code Form is subject to the terms of the Mozilla Public
|
|
2
2
|
// License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
3
3
|
// file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
|
4
|
-
|
|
4
|
+
/**
|
|
5
|
+
* Prompt + schema for `akm extract <session>`.
|
|
6
|
+
*
|
|
7
|
+
* Mirrors the REFLECT_JSON_SCHEMA pattern: a strict JSON Schema describing
|
|
8
|
+
* the LLM output, plus a {@link buildExtractPrompt} helper that interpolates
|
|
9
|
+
* session data into the markdown template loaded from
|
|
10
|
+
* `src/assets/prompts/extract-session.md`.
|
|
11
|
+
*
|
|
12
|
+
* The schema is intentionally strict — providers with `supportsJsonSchema:
|
|
13
|
+
* true` enforce shape upstream, so the parser only has to handle the
|
|
14
|
+
* happy path. `additionalProperties: false` means any hallucinated keys
|
|
15
|
+
* the model emits get dropped before we parse.
|
|
16
|
+
*/
|
|
17
|
+
import promptTemplate from "../assets/prompts/extract-session.md" with { type: "text" };
|
|
5
18
|
/**
|
|
6
19
|
* JSON Schema for the structured extract output. Passed to `chatCompletion`
|
|
7
20
|
* when the configured LLM connection has `supportsJsonSchema: true`.
|
package/dist/commands/health.js
CHANGED
|
@@ -73,7 +73,6 @@ function createUnknownImproveMetrics() {
|
|
|
73
73
|
},
|
|
74
74
|
reflectsWithErrorContext: 0,
|
|
75
75
|
coverageGapCount: 0,
|
|
76
|
-
executionLogCandidateCount: 0,
|
|
77
76
|
evalCasesWritten: 0,
|
|
78
77
|
deadUrlCount: 0,
|
|
79
78
|
memorySummary: { eligible: 0, derived: 0 },
|
|
@@ -130,6 +129,15 @@ function createUnknownImproveMetrics() {
|
|
|
130
129
|
failures: 0,
|
|
131
130
|
durationMs: 0,
|
|
132
131
|
},
|
|
132
|
+
sessionExtraction: {
|
|
133
|
+
ran: false,
|
|
134
|
+
sessionsScanned: 0,
|
|
135
|
+
sessionsExtracted: 0,
|
|
136
|
+
sessionsSkipped: 0,
|
|
137
|
+
proposalsCreated: 0,
|
|
138
|
+
warnings: 0,
|
|
139
|
+
durationMs: 0,
|
|
140
|
+
},
|
|
133
141
|
wallTime: {
|
|
134
142
|
count: 0,
|
|
135
143
|
medianMs: 0,
|
|
@@ -288,8 +296,6 @@ function projectRunMetrics(result) {
|
|
|
288
296
|
metrics.reflectsWithErrorContext += toFiniteNumber(result.reflectsWithErrorContext);
|
|
289
297
|
if (Array.isArray(result.coverageGaps))
|
|
290
298
|
metrics.coverageGapCount += result.coverageGaps.length;
|
|
291
|
-
if (Array.isArray(result.executionLogCandidates))
|
|
292
|
-
metrics.executionLogCandidateCount += result.executionLogCandidates.length;
|
|
293
299
|
metrics.evalCasesWritten += toFiniteNumber(result.evalCasesWritten);
|
|
294
300
|
if (Array.isArray(result.deadUrls))
|
|
295
301
|
metrics.deadUrlCount += result.deadUrls.length;
|
|
@@ -385,6 +391,18 @@ function projectRunMetrics(result) {
|
|
|
385
391
|
}
|
|
386
392
|
}
|
|
387
393
|
metrics.graphExtraction.durationMs += toFiniteNumber(result.graphExtractionDurationMs);
|
|
394
|
+
if (Array.isArray(result.extract)) {
|
|
395
|
+
for (const e of result.extract) {
|
|
396
|
+
metrics.sessionExtraction.sessionsScanned += toFiniteNumber(e.sessionsProcessed);
|
|
397
|
+
metrics.sessionExtraction.sessionsSkipped += toFiniteNumber(e.sessionsSkipped);
|
|
398
|
+
if (Array.isArray(e.sessions)) {
|
|
399
|
+
metrics.sessionExtraction.sessionsExtracted += e.sessions.filter((s) => Array.isArray(s.proposalIds) && s.proposalIds.length > 0).length;
|
|
400
|
+
}
|
|
401
|
+
metrics.sessionExtraction.proposalsCreated += Array.isArray(e.proposals) ? e.proposals.length : 0;
|
|
402
|
+
metrics.sessionExtraction.warnings += Array.isArray(e.warnings) ? e.warnings.length : 0;
|
|
403
|
+
metrics.sessionExtraction.durationMs += toFiniteNumber(e.durationMs);
|
|
404
|
+
}
|
|
405
|
+
}
|
|
388
406
|
return metrics;
|
|
389
407
|
}
|
|
390
408
|
/**
|
|
@@ -412,7 +430,9 @@ function finalizeImproveMetrics(metrics) {
|
|
|
412
430
|
// `considered`/`written` for totals but are excluded from the rate so
|
|
413
431
|
// they cannot drag it down. See ImproveHealthMetrics.memoryInference
|
|
414
432
|
// jsdoc for the rationale.
|
|
415
|
-
metrics.memoryInference.freshAttempts = Math.max(0, metrics.memoryInference.yieldEligibleConsidered -
|
|
433
|
+
metrics.memoryInference.freshAttempts = Math.max(0, metrics.memoryInference.yieldEligibleConsidered -
|
|
434
|
+
metrics.memoryInference.cacheHits -
|
|
435
|
+
metrics.memoryInference.skippedAborted);
|
|
416
436
|
metrics.memoryInference.yieldRate =
|
|
417
437
|
metrics.memoryInference.freshAttempts > 0
|
|
418
438
|
? roundRate(metrics.memoryInference.yieldEligibleWritten / metrics.memoryInference.freshAttempts)
|
|
@@ -423,6 +443,10 @@ function finalizeImproveMetrics(metrics) {
|
|
|
423
443
|
metrics.graphExtraction.durationMs > 0;
|
|
424
444
|
const cacheTotal = metrics.graphExtraction.cacheHits + metrics.graphExtraction.cacheMisses;
|
|
425
445
|
metrics.graphExtraction.cacheHitRate = cacheTotal > 0 ? roundRate(metrics.graphExtraction.cacheHits / cacheTotal) : 0;
|
|
446
|
+
metrics.sessionExtraction.ran =
|
|
447
|
+
metrics.sessionExtraction.sessionsScanned > 0 ||
|
|
448
|
+
metrics.sessionExtraction.proposalsCreated > 0 ||
|
|
449
|
+
metrics.sessionExtraction.durationMs > 0;
|
|
426
450
|
}
|
|
427
451
|
/**
|
|
428
452
|
* Merge per-row metrics from `src` into accumulator `dst`. All numeric fields
|
|
@@ -459,7 +483,6 @@ function mergeImproveMetrics(dst, src) {
|
|
|
459
483
|
dst.actions.error += src.actions.error;
|
|
460
484
|
dst.reflectsWithErrorContext += src.reflectsWithErrorContext;
|
|
461
485
|
dst.coverageGapCount += src.coverageGapCount;
|
|
462
|
-
dst.executionLogCandidateCount += src.executionLogCandidateCount;
|
|
463
486
|
dst.evalCasesWritten += src.evalCasesWritten;
|
|
464
487
|
dst.deadUrlCount += src.deadUrlCount;
|
|
465
488
|
dst.memorySummary.eligible += src.memorySummary.eligible;
|
|
@@ -504,6 +527,12 @@ function mergeImproveMetrics(dst, src) {
|
|
|
504
527
|
dst.graphExtraction.truncations += src.graphExtraction.truncations;
|
|
505
528
|
dst.graphExtraction.failures += src.graphExtraction.failures;
|
|
506
529
|
dst.graphExtraction.durationMs += src.graphExtraction.durationMs;
|
|
530
|
+
dst.sessionExtraction.sessionsScanned += src.sessionExtraction.sessionsScanned;
|
|
531
|
+
dst.sessionExtraction.sessionsExtracted += src.sessionExtraction.sessionsExtracted;
|
|
532
|
+
dst.sessionExtraction.sessionsSkipped += src.sessionExtraction.sessionsSkipped;
|
|
533
|
+
dst.sessionExtraction.proposalsCreated += src.sessionExtraction.proposalsCreated;
|
|
534
|
+
dst.sessionExtraction.warnings += src.sessionExtraction.warnings;
|
|
535
|
+
dst.sessionExtraction.durationMs += src.sessionExtraction.durationMs;
|
|
507
536
|
}
|
|
508
537
|
function loadImproveRunRows(db, since, until) {
|
|
509
538
|
const sql = until
|
|
@@ -892,6 +921,8 @@ const INTERESTING_DELTA_PATHS = [
|
|
|
892
921
|
"improve.memoryInference.skippedNoFacts",
|
|
893
922
|
"improve.graphExtraction.cacheHitRate",
|
|
894
923
|
"improve.graphExtraction.failures",
|
|
924
|
+
"improve.sessionExtraction.sessionsScanned",
|
|
925
|
+
"improve.sessionExtraction.proposalsCreated",
|
|
895
926
|
"improve.wallTime.medianMs",
|
|
896
927
|
"improve.wallTime.p95Ms",
|
|
897
928
|
];
|
|
@@ -1112,16 +1143,46 @@ export function akmHealth(options = {}) {
|
|
|
1112
1143
|
catch {
|
|
1113
1144
|
sessionLogEntries = [];
|
|
1114
1145
|
}
|
|
1146
|
+
// session-log-failures: demoted to informational — the ERROR_PATTERNS regex
|
|
1147
|
+
// scans pre-LLM session text and produces false positives on diagnostic
|
|
1148
|
+
// conversation. It does not gate the real extraction pipeline (akmExtract).
|
|
1149
|
+
// Never triggers warn; kept for backward-compat visibility only.
|
|
1115
1150
|
advisories.push({
|
|
1116
1151
|
name: "session-log-failures",
|
|
1117
1152
|
kind: "heuristic",
|
|
1118
|
-
status:
|
|
1119
|
-
confidence:
|
|
1153
|
+
status: "pass",
|
|
1154
|
+
confidence: "low",
|
|
1120
1155
|
message: sessionLogEntries.length === 0
|
|
1121
1156
|
? "No repeated external session-log failure patterns were detected."
|
|
1122
|
-
: `${sessionLogEntries.length}
|
|
1157
|
+
: `${sessionLogEntries.length} raw session-log keyword match(es) detected (pre-LLM, informational only).`,
|
|
1123
1158
|
evidence: { candidates: sessionLogEntries.slice(0, 5) },
|
|
1124
1159
|
});
|
|
1160
|
+
const sx = improveSummary.sessionExtraction;
|
|
1161
|
+
const sxWarnReasons = [];
|
|
1162
|
+
if (sx.warnings > 0)
|
|
1163
|
+
sxWarnReasons.push(`${sx.warnings} harness error(s)`);
|
|
1164
|
+
if (sx.ran && sx.sessionsScanned >= 5 && sx.proposalsCreated === 0)
|
|
1165
|
+
sxWarnReasons.push("no proposals generated across scanned sessions");
|
|
1166
|
+
advisories.push({
|
|
1167
|
+
name: "session-extraction",
|
|
1168
|
+
kind: "heuristic",
|
|
1169
|
+
status: sxWarnReasons.length > 0 ? "warn" : "pass",
|
|
1170
|
+
confidence: sx.ran ? "medium" : "low",
|
|
1171
|
+
message: sx.ran
|
|
1172
|
+
? sxWarnReasons.length > 0
|
|
1173
|
+
? `Session extraction degraded: ${sxWarnReasons.join("; ")}.`
|
|
1174
|
+
: `Session extraction healthy: ${sx.sessionsScanned} scanned, ${sx.sessionsExtracted} extracted, ${sx.proposalsCreated} proposal(s) created.`
|
|
1175
|
+
: "Session extraction not active (feature disabled or no harness available).",
|
|
1176
|
+
evidence: {
|
|
1177
|
+
ran: sx.ran,
|
|
1178
|
+
sessionsScanned: sx.sessionsScanned,
|
|
1179
|
+
sessionsExtracted: sx.sessionsExtracted,
|
|
1180
|
+
sessionsSkipped: sx.sessionsSkipped,
|
|
1181
|
+
proposalsCreated: sx.proposalsCreated,
|
|
1182
|
+
warnings: sx.warnings,
|
|
1183
|
+
durationMs: sx.durationMs,
|
|
1184
|
+
},
|
|
1185
|
+
});
|
|
1125
1186
|
const metrics = {
|
|
1126
1187
|
taskFailRate: roundRate(taskFailRate),
|
|
1127
1188
|
agentFailureRate: roundRate(agentFailureRate),
|
|
@@ -56,7 +56,7 @@ export const improveCommand = defineCommand({
|
|
|
56
56
|
},
|
|
57
57
|
profile: {
|
|
58
58
|
type: "string",
|
|
59
|
-
description: "Named improve profile from profiles.improve or built-in profiles (default, quick, thorough, memory-focus). Controls which sub-processes run and which asset types are processed.",
|
|
59
|
+
description: "Named improve profile from profiles.improve or built-in profiles (default, quick, thorough, memory-focus, graph-refresh). Controls which sub-processes run and which asset types are processed.",
|
|
60
60
|
},
|
|
61
61
|
sync: {
|
|
62
62
|
type: "boolean",
|
|
@@ -1,6 +1,11 @@
|
|
|
1
1
|
// This Source Code Form is subject to the terms of the Mozilla Public
|
|
2
2
|
// License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
3
3
|
// file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
|
4
|
+
import profileDefault from "../assets/profiles/default.json" with { type: "json" };
|
|
5
|
+
import profileGraphRefresh from "../assets/profiles/graph-refresh.json" with { type: "json" };
|
|
6
|
+
import profileMemoryFocus from "../assets/profiles/memory-focus.json" with { type: "json" };
|
|
7
|
+
import profileQuick from "../assets/profiles/quick.json" with { type: "json" };
|
|
8
|
+
import profileThorough from "../assets/profiles/thorough.json" with { type: "json" };
|
|
4
9
|
import { parseAssetRef } from "../core/asset-ref";
|
|
5
10
|
import { warn } from "../core/warn";
|
|
6
11
|
/** Profile name used as the final fallback when nothing else resolves. */
|
|
@@ -11,66 +16,15 @@ export const DEFAULT_ALLOWED_TYPES = {
|
|
|
11
16
|
distill: ["memory"],
|
|
12
17
|
consolidate: ["memory"],
|
|
13
18
|
};
|
|
19
|
+
// Built-in profiles are loaded from embedded JSON files in src/assets/profiles/.
|
|
20
|
+
// To add a new profile: create a new .json file there, import it above, and add
|
|
21
|
+
// it to this map. No code change needed beyond those two steps.
|
|
14
22
|
const BUILTIN_PROFILES = {
|
|
15
|
-
default:
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
consolidate: { enabled: true, allowedTypes: DEFAULT_ALLOWED_TYPES.consolidate },
|
|
21
|
-
memoryInference: { enabled: true },
|
|
22
|
-
graphExtraction: { enabled: true },
|
|
23
|
-
// validation: deliberately undefined — third-tier classifier is opt-in.
|
|
24
|
-
triage: { enabled: false, applyMode: "queue", policy: "personal-stash" },
|
|
25
|
-
},
|
|
26
|
-
sync: { enabled: true, push: true },
|
|
27
|
-
},
|
|
28
|
-
quick: {
|
|
29
|
-
description: "Reflect-only pass — no distill, consolidate, memoryInference, or graphExtraction.",
|
|
30
|
-
processes: {
|
|
31
|
-
reflect: { enabled: true, allowedTypes: DEFAULT_ALLOWED_TYPES.reflect },
|
|
32
|
-
distill: { enabled: false },
|
|
33
|
-
consolidate: { enabled: false },
|
|
34
|
-
memoryInference: { enabled: false },
|
|
35
|
-
graphExtraction: { enabled: false },
|
|
36
|
-
triage: { enabled: false },
|
|
37
|
-
},
|
|
38
|
-
// Lightweight passes opt out of end-of-run sync: a reflect-only `quick`
|
|
39
|
-
// run should not auto-commit/push the git-backed stash to its remote.
|
|
40
|
-
// (The auto-sync gate in improve.ts treats an absent sync block as
|
|
41
|
-
// ENABLED + push, so we set this explicitly to avoid a surprise push.)
|
|
42
|
-
sync: { enabled: false },
|
|
43
|
-
},
|
|
44
|
-
thorough: {
|
|
45
|
-
// Reserved for future divergence; for now behaviorally identical to
|
|
46
|
-
// `default`. Documented here so callers picking `--profile thorough` do
|
|
47
|
-
// not expect a different code path until we wire stricter limits in.
|
|
48
|
-
description: "All sub-processes enabled (currently identical to default; reserved for future divergence).",
|
|
49
|
-
processes: {
|
|
50
|
-
reflect: { enabled: true, allowedTypes: DEFAULT_ALLOWED_TYPES.reflect },
|
|
51
|
-
distill: { enabled: true, allowedTypes: DEFAULT_ALLOWED_TYPES.distill },
|
|
52
|
-
consolidate: { enabled: true, allowedTypes: DEFAULT_ALLOWED_TYPES.consolidate },
|
|
53
|
-
memoryInference: { enabled: true },
|
|
54
|
-
graphExtraction: { enabled: true },
|
|
55
|
-
triage: { enabled: true, applyMode: "queue" },
|
|
56
|
-
},
|
|
57
|
-
sync: { enabled: true, push: true },
|
|
58
|
-
},
|
|
59
|
-
"memory-focus": {
|
|
60
|
-
description: "Memory and lesson improvement only — no distill or consolidate.",
|
|
61
|
-
processes: {
|
|
62
|
-
reflect: { enabled: true, allowedTypes: ["memory", "lesson"] },
|
|
63
|
-
distill: { enabled: false },
|
|
64
|
-
consolidate: { enabled: false },
|
|
65
|
-
memoryInference: { enabled: true },
|
|
66
|
-
graphExtraction: { enabled: false },
|
|
67
|
-
triage: { enabled: false },
|
|
68
|
-
},
|
|
69
|
-
// Limited pass opts out of end-of-run sync for the same reason as `quick`:
|
|
70
|
-
// a memory/lesson-only run should not auto-commit/push the stash. Explicit
|
|
71
|
-
// here because improve.ts treats an absent sync block as ENABLED + push.
|
|
72
|
-
sync: { enabled: false },
|
|
73
|
-
},
|
|
23
|
+
default: profileDefault,
|
|
24
|
+
quick: profileQuick,
|
|
25
|
+
thorough: profileThorough,
|
|
26
|
+
"memory-focus": profileMemoryFocus,
|
|
27
|
+
"graph-refresh": profileGraphRefresh,
|
|
74
28
|
};
|
|
75
29
|
/**
|
|
76
30
|
* Default enabled-state for known improve processes when neither the user
|
package/dist/commands/improve.js
CHANGED
|
@@ -25,7 +25,7 @@ import { resolveAssetPath } from "../indexer/path-resolver";
|
|
|
25
25
|
import { getWritableStashDirs, resolveSourceEntries } from "../indexer/search-source";
|
|
26
26
|
import { runStalenessDetectionPass } from "../indexer/staleness-detect";
|
|
27
27
|
import { resolveImproveProcessRunnerFromProfile, resolveTriageJudgmentRunner } from "../integrations/agent/runner";
|
|
28
|
-
import { getAvailableHarnesses
|
|
28
|
+
import { getAvailableHarnesses } from "../integrations/session-logs";
|
|
29
29
|
import { isLlmFeatureEnabled, isProcessEnabled } from "../llm/feature-gate";
|
|
30
30
|
import { isGitBackedStash, resolveWritableOverride, saveGitStash } from "../sources/providers/git";
|
|
31
31
|
import { akmConsolidate } from "./consolidate";
|
|
@@ -674,7 +674,12 @@ export async function akmImprove(options = {}) {
|
|
|
674
674
|
// lives in the outer scope. It is always assigned at the top of the try.
|
|
675
675
|
let eventsCtx = {};
|
|
676
676
|
try {
|
|
677
|
-
const budgetTimer = setTimeout(() =>
|
|
677
|
+
const budgetTimer = setTimeout(() => {
|
|
678
|
+
budgetAbortController.abort("improve budget exhausted");
|
|
679
|
+
// Grace period: let finally run to release improve.lock, then hard-exit
|
|
680
|
+
// to prevent the process outliving the task timeout window (lock-cascade fix).
|
|
681
|
+
setTimeout(() => process.exit(1), 5_000);
|
|
682
|
+
}, budgetMs);
|
|
678
683
|
// Clear the timer when the run ends to avoid keeping the event loop alive.
|
|
679
684
|
clearBudgetTimer = () => clearTimeout(budgetTimer);
|
|
680
685
|
try {
|
|
@@ -798,9 +803,6 @@ export async function akmImprove(options = {}) {
|
|
|
798
803
|
...(preparation.lintSummary !== undefined ? { lintSummary: preparation.lintSummary } : {}),
|
|
799
804
|
...(preparation.memoryIndexHealth !== undefined ? { memoryIndexHealth: preparation.memoryIndexHealth } : {}),
|
|
800
805
|
...(preparation.coverageGaps.length > 0 ? { coverageGaps: preparation.coverageGaps } : {}),
|
|
801
|
-
...(preparation.executionLogCandidates.length > 0
|
|
802
|
-
? { executionLogCandidates: preparation.executionLogCandidates }
|
|
803
|
-
: {}),
|
|
804
806
|
...(preparation.extract && preparation.extract.length > 0 ? { extract: preparation.extract } : {}),
|
|
805
807
|
...(primaryStashDir !== undefined ? { evalCasesWritten: countEvalCases(primaryStashDir) } : {}),
|
|
806
808
|
...(deadUrls !== undefined && deadUrls.length > 0 ? { deadUrls } : {}),
|
|
@@ -990,7 +992,6 @@ function emitImproveCompletedEvent(result, durations, eventsCtx) {
|
|
|
990
992
|
reflectSkippedActions: actionCounts.reflectSkipped,
|
|
991
993
|
reflectsWithErrorContext: result.reflectsWithErrorContext ?? 0,
|
|
992
994
|
coverageGapCount: result.coverageGaps?.length ?? 0,
|
|
993
|
-
executionLogCandidateCount: result.executionLogCandidates?.length ?? 0,
|
|
994
995
|
evalCasesWritten: result.evalCasesWritten ?? 0,
|
|
995
996
|
deadUrlCount: result.deadUrls?.length ?? 0,
|
|
996
997
|
memoryEligible: result.memorySummary.eligible,
|
|
@@ -1047,15 +1048,6 @@ async function runImprovePreparationStage(args) {
|
|
|
1047
1048
|
}
|
|
1048
1049
|
}
|
|
1049
1050
|
}
|
|
1050
|
-
// Phase 0 — execution log synthesis
|
|
1051
|
-
let executionLogCandidates = [];
|
|
1052
|
-
try {
|
|
1053
|
-
const logEntries = getExecutionLogCandidates(7);
|
|
1054
|
-
executionLogCandidates = logEntries.filter((e) => e.isFailurePattern).map((e) => e.topic);
|
|
1055
|
-
}
|
|
1056
|
-
catch {
|
|
1057
|
-
// best-effort
|
|
1058
|
-
}
|
|
1059
1051
|
// Phase 0.4 — session-extract pass.
|
|
1060
1052
|
//
|
|
1061
1053
|
// Reads native session files (claude-code JSONL, opencode storage tree)
|
|
@@ -1539,7 +1531,6 @@ async function runImprovePreparationStage(args) {
|
|
|
1539
1531
|
cleanupWarnings,
|
|
1540
1532
|
appliedCleanup,
|
|
1541
1533
|
memoryIndexHealth,
|
|
1542
|
-
executionLogCandidates,
|
|
1543
1534
|
extract: extractResults,
|
|
1544
1535
|
actionableRefs,
|
|
1545
1536
|
signalBearingSet,
|
|
@@ -2111,13 +2102,16 @@ async function runImprovePostLoopStage(args) {
|
|
|
2111
2102
|
// Tie consolidate proposals back to this improve invocation so
|
|
2112
2103
|
// accept-rate-per-run aggregation works. Mirrors reflect/propose/extract.
|
|
2113
2104
|
sourceRun: `consolidate-${Date.now()}`,
|
|
2114
|
-
// Incremental consolidation:
|
|
2115
|
-
//
|
|
2116
|
-
//
|
|
2117
|
-
//
|
|
2118
|
-
//
|
|
2119
|
-
//
|
|
2120
|
-
incrementalSince
|
|
2105
|
+
// Incremental consolidation: pass the last-consolidation timestamp so
|
|
2106
|
+
// akmConsolidate skips chunks with no memory changed since then. Converts
|
|
2107
|
+
// consolidation cost from O(pool) to O(changed clusters) — the fix for
|
|
2108
|
+
// the rising p95 tail where full-pool re-judging produced 5–10 min runs
|
|
2109
|
+
// that promoted ~0. undefined → full pass on first-ever run (bootstrap).
|
|
2110
|
+
// volumeTriggered correctly forces the run past cooldown but must NOT
|
|
2111
|
+
// override incrementalSince — the stash has ~1400 eligible memories so
|
|
2112
|
+
// volumeTriggered=true on every run, permanently forcing full 12-chunk
|
|
2113
|
+
// scans (~264s) instead of the intended 1-2 chunk incremental path (~44s).
|
|
2114
|
+
incrementalSince: lastConsolidateTs,
|
|
2121
2115
|
maxChunkSize: improveProfile?.processes?.consolidate?.maxChunkSize,
|
|
2122
2116
|
// Honor profile.autoAccept (already merged into options.autoAccept at the
|
|
2123
2117
|
// top of akmImprove). The CLI parser always supplies 90 when --auto-accept
|
|
@@ -2287,25 +2281,25 @@ async function runImproveMaintenancePasses(args) {
|
|
|
2287
2281
|
}
|
|
2288
2282
|
const graphEnabled = isProcessEnabled("index", "graph_extraction", config);
|
|
2289
2283
|
const graphExtractionDisabledByProfile = improveProfile?.processes?.graphExtraction?.enabled === false;
|
|
2284
|
+
const graphExtractionFullScan = improveProfile?.processes?.graphExtraction?.fullScan === true;
|
|
2290
2285
|
// Build the set of refs actually touched this run.
|
|
2291
2286
|
const touchedRefs = new Set();
|
|
2292
2287
|
for (const r of args.actionableRefs)
|
|
2293
2288
|
touchedRefs.add(r.ref);
|
|
2294
2289
|
for (const r of memoryRefsForInference)
|
|
2295
2290
|
touchedRefs.add(r);
|
|
2296
|
-
// INVARIANT: graph extraction
|
|
2297
|
-
//
|
|
2298
|
-
//
|
|
2299
|
-
//
|
|
2300
|
-
//
|
|
2301
|
-
//
|
|
2302
|
-
//
|
|
2303
|
-
// mock injection (graphExtractionFn) used by tests stays exercised.
|
|
2291
|
+
// INVARIANT: graph extraction normally runs only on files touched by
|
|
2292
|
+
// actionable refs (candidatePaths). Full-corpus scans are opt-in via
|
|
2293
|
+
// profile.processes.graphExtraction.fullScan = true (used by the
|
|
2294
|
+
// `graph-refresh` built-in profile and its weekly scheduled task).
|
|
2295
|
+
// The empty-Set fallback is intentional when no refs were touched —
|
|
2296
|
+
// the extractor's filter rejects every file and returns empty, keeping
|
|
2297
|
+
// the pass invoked so the action is recorded and tests stay exercised.
|
|
2304
2298
|
if (graphExtractionDisabledByProfile) {
|
|
2305
2299
|
info("[improve] graph extraction skipped (disabled by improve profile)");
|
|
2306
2300
|
}
|
|
2307
2301
|
else if (sources.length > 0 && graphEnabled) {
|
|
2308
|
-
info(
|
|
2302
|
+
info(`[improve] graph extraction starting${graphExtractionFullScan ? " (full-corpus scan)" : ""}`);
|
|
2309
2303
|
const extractionStart = Date.now();
|
|
2310
2304
|
try {
|
|
2311
2305
|
// D9: if consolidation ran but memory inference did not reindex, force a reindex
|
|
@@ -2325,15 +2319,18 @@ async function runImproveMaintenancePasses(args) {
|
|
|
2325
2319
|
closeDatabase(db);
|
|
2326
2320
|
db = openDatabase(getDbPath(), config.embedding?.dimension ? { embeddingDim: config.embedding.dimension } : undefined);
|
|
2327
2321
|
}
|
|
2328
|
-
// Resolve touched refs to absolute file paths.
|
|
2329
|
-
//
|
|
2330
|
-
|
|
2331
|
-
if (
|
|
2332
|
-
|
|
2333
|
-
|
|
2334
|
-
|
|
2335
|
-
|
|
2336
|
-
|
|
2322
|
+
// Resolve touched refs to absolute file paths. Skipped for fullScan
|
|
2323
|
+
// (candidatePaths stays undefined → extractor processes all files).
|
|
2324
|
+
let candidatePaths;
|
|
2325
|
+
if (!graphExtractionFullScan) {
|
|
2326
|
+
candidatePaths = new Set();
|
|
2327
|
+
if (primaryStashDir && touchedRefs.size > 0) {
|
|
2328
|
+
const writableDirSet = new Set(getWritableStashDirs(primaryStashDir).map((d) => path.resolve(d)));
|
|
2329
|
+
const resolved = await Promise.all([...touchedRefs].map((ref) => findAssetFilePath(ref, primaryStashDir, writableDirSet).catch(() => null)));
|
|
2330
|
+
for (const p of resolved) {
|
|
2331
|
+
if (typeof p === "string" && p.length > 0)
|
|
2332
|
+
candidatePaths.add(p);
|
|
2333
|
+
}
|
|
2337
2334
|
}
|
|
2338
2335
|
}
|
|
2339
2336
|
const progressHandler = (event) => {
|
package/dist/commands/info.js
CHANGED
|
@@ -46,8 +46,11 @@ export function assembleInfo(options) {
|
|
|
46
46
|
...(s.url ? { url: s.url } : {}),
|
|
47
47
|
...(s.enabled !== undefined ? { enabled: s.enabled } : {}),
|
|
48
48
|
}));
|
|
49
|
-
// Index stats
|
|
50
|
-
|
|
49
|
+
// Index stats — resolve the DB path from config so info reads the same
|
|
50
|
+
// database that health and search use, rather than a bare getDbPath() call
|
|
51
|
+
// that ignores XDG_DATA_HOME or per-config overrides.
|
|
52
|
+
const resolvedDbPath = options?.dbPath ?? getDbPath();
|
|
53
|
+
const indexStats = readIndexStats(resolvedDbPath);
|
|
51
54
|
return {
|
|
52
55
|
schemaVersion: 1,
|
|
53
56
|
version: pkgVersion,
|
|
@@ -64,38 +67,30 @@ export function assembleInfo(options) {
|
|
|
64
67
|
indexStats,
|
|
65
68
|
};
|
|
66
69
|
}
|
|
67
|
-
function readIndexStats(
|
|
68
|
-
const
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
};
|
|
77
|
-
}
|
|
70
|
+
function readIndexStats(resolvedPath) {
|
|
71
|
+
const EMPTY = {
|
|
72
|
+
entryCount: 0,
|
|
73
|
+
lastBuiltAt: null,
|
|
74
|
+
hasEmbeddings: false,
|
|
75
|
+
vecAvailable: false,
|
|
76
|
+
};
|
|
77
|
+
if (!fs.existsSync(resolvedPath))
|
|
78
|
+
return EMPTY;
|
|
78
79
|
let db;
|
|
79
80
|
try {
|
|
80
81
|
db = openExistingDatabase(resolvedPath);
|
|
81
|
-
const entryCount = getEntryCount(db);
|
|
82
|
-
const lastBuiltAt = getMeta(db, "builtAt") ?? null;
|
|
83
|
-
const vecAvailable = isVecAvailable(db);
|
|
84
|
-
const hasEmbeddings = getMeta(db, "hasEmbeddings") === "1";
|
|
85
82
|
return {
|
|
86
|
-
entryCount,
|
|
87
|
-
lastBuiltAt,
|
|
88
|
-
hasEmbeddings,
|
|
89
|
-
vecAvailable,
|
|
83
|
+
entryCount: getEntryCount(db),
|
|
84
|
+
lastBuiltAt: getMeta(db, "builtAt") ?? null,
|
|
85
|
+
hasEmbeddings: getMeta(db, "hasEmbeddings") === "1",
|
|
86
|
+
vecAvailable: isVecAvailable(db),
|
|
90
87
|
};
|
|
91
88
|
}
|
|
92
|
-
catch {
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
vecAvailable: false,
|
|
98
|
-
};
|
|
89
|
+
catch (err) {
|
|
90
|
+
// Surface the error so operators can diagnose mismatches between
|
|
91
|
+
// `akm info` and `akm health` rather than silently returning zeros.
|
|
92
|
+
process.stderr.write(`[akm info] failed to read index stats from ${resolvedPath}: ${String(err)}\n`);
|
|
93
|
+
return EMPTY;
|
|
99
94
|
}
|
|
100
95
|
finally {
|
|
101
96
|
if (db) {
|
package/dist/indexer/indexer.js
CHANGED
|
@@ -322,8 +322,8 @@ export async function akmIndex(options) {
|
|
|
322
322
|
totalMs: Date.now() - timing.t0,
|
|
323
323
|
walkMs: timing.tWalkEnd - timing.tWalkStart,
|
|
324
324
|
llmMs: timing.tLlmEnd - timing.tWalkEnd,
|
|
325
|
-
embedMs: timing.tEmbedEnd - timing.
|
|
326
|
-
ftsMs: timing.tFtsEnd - timing.
|
|
325
|
+
embedMs: timing.tEmbedEnd - timing.tLlmEnd,
|
|
326
|
+
ftsMs: timing.tFtsEnd - timing.tEmbedEnd,
|
|
327
327
|
},
|
|
328
328
|
...(cleanResult !== undefined ? { clean: cleanResult } : {}),
|
|
329
329
|
};
|
|
@@ -20,11 +20,11 @@
|
|
|
20
20
|
* the connection via `resolveIndexPassLLM("graph", config)` and pass it
|
|
21
21
|
* straight through.
|
|
22
22
|
*/
|
|
23
|
+
import userPromptTemplate from "../assets/prompts/graph-extract-user-prompt.md" with { type: "text" };
|
|
23
24
|
import { toErrorMessage } from "../core/common";
|
|
24
25
|
import { warn, warnVerbose } from "../core/warn";
|
|
25
26
|
import { chatCompletion, parseEmbeddedJsonResponse } from "./client";
|
|
26
27
|
import { tryLlmFeature } from "./feature-gate";
|
|
27
|
-
import userPromptTemplate from "./prompts/graph-extract-user-prompt.md" with { type: "text" };
|
|
28
28
|
/**
|
|
29
29
|
* Separator token used between assets in a batch prompt.
|
|
30
30
|
* Chosen to be visually clear and unlikely to appear verbatim in asset bodies.
|
package/dist/output/cli-hints.js
CHANGED
|
@@ -10,6 +10,6 @@
|
|
|
10
10
|
* `EMBEDDED_HINTS` (`--detail brief`, short reference, ~40 lines) and
|
|
11
11
|
* `EMBEDDED_HINTS_FULL` (`--detail normal|full`, ~250 lines).
|
|
12
12
|
*/
|
|
13
|
-
import EMBEDDED_HINTS_FULL from "
|
|
14
|
-
import EMBEDDED_HINTS from "
|
|
13
|
+
import EMBEDDED_HINTS_FULL from "../assets/hints/cli-hints-full.md" with { type: "text" };
|
|
14
|
+
import EMBEDDED_HINTS from "../assets/hints/cli-hints-short.md" with { type: "text" };
|
|
15
15
|
export { EMBEDDED_HINTS, EMBEDDED_HINTS_FULL };
|
|
@@ -24,12 +24,12 @@
|
|
|
24
24
|
import fs from "node:fs";
|
|
25
25
|
import os from "node:os";
|
|
26
26
|
import path from "node:path";
|
|
27
|
+
import launchdTemplate from "../../assets/backends/launchd-template.xml" with { type: "text" };
|
|
27
28
|
import { ConfigError } from "../../core/errors";
|
|
28
29
|
import { getTaskLogDir } from "../../core/paths";
|
|
29
30
|
import { resolveAkmInvocation } from "../resolveAkmBin";
|
|
30
31
|
import { parseSchedule, translateToLaunchd } from "../schedule";
|
|
31
32
|
import { escapeXml, spawnCommand } from "./exec-utils";
|
|
32
|
-
import launchdTemplate from "./launchd-template.xml" with { type: "text" };
|
|
33
33
|
export const LAUNCHD_LABEL_PREFIX = "com.akm.task.";
|
|
34
34
|
export function LAUNCHD_BACKEND(options = {}) {
|
|
35
35
|
const exec = options.exec ?? defaultLaunchdExec();
|
|
@@ -32,12 +32,12 @@
|
|
|
32
32
|
import fs from "node:fs";
|
|
33
33
|
import os from "node:os";
|
|
34
34
|
import path from "node:path";
|
|
35
|
+
import schtasksTemplate from "../../assets/backends/schtasks-template.xml" with { type: "text" };
|
|
35
36
|
import { ConfigError } from "../../core/errors";
|
|
36
37
|
import { getTaskLogDir } from "../../core/paths";
|
|
37
38
|
import { resolveAkmInvocation } from "../resolveAkmBin";
|
|
38
39
|
import { parseSchedule, translateToSchtasks } from "../schedule";
|
|
39
40
|
import { escapeXml, spawnCommand } from "./exec-utils";
|
|
40
|
-
import schtasksTemplate from "./schtasks-template.xml" with { type: "text" };
|
|
41
41
|
export const DEFAULT_FOLDER_PREFIX = "\\akm\\";
|
|
42
42
|
export function SCHTASKS_BACKEND(options = {}) {
|
|
43
43
|
const exec = options.exec ?? defaultSchtasksExec();
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
// This Source Code Form is subject to the terms of the Mozilla Public
|
|
2
2
|
// License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
3
3
|
// file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
|
4
|
-
import indexTemplate from "
|
|
5
|
-
import logTemplate from "
|
|
6
|
-
import schemaTemplate from "
|
|
4
|
+
import indexTemplate from "../assets/wiki/index-template.md" with { type: "text" };
|
|
5
|
+
import logTemplate from "../assets/wiki/log-template.md" with { type: "text" };
|
|
6
|
+
import schemaTemplate from "../assets/wiki/schema-template.md" with { type: "text" };
|
|
7
7
|
export function buildSchemaMd(wikiName) {
|
|
8
8
|
return schemaTemplate.replaceAll("{{WIKI_NAME}}", wikiName);
|
|
9
9
|
}
|
package/dist/wiki/wiki.js
CHANGED
|
@@ -44,13 +44,13 @@
|
|
|
44
44
|
import fs from "node:fs";
|
|
45
45
|
import path from "node:path";
|
|
46
46
|
import { parse as yamlParse } from "yaml";
|
|
47
|
+
import ingestWorkflowTemplate from "../assets/wiki/ingest-workflow-template.md" with { type: "text" };
|
|
47
48
|
import { akmSearch } from "../commands/search";
|
|
48
49
|
import { isWithin, todayIso } from "../core/common";
|
|
49
50
|
import { getSources, loadUserConfig, saveConfig } from "../core/config";
|
|
50
51
|
import { NotFoundError, UsageError } from "../core/errors";
|
|
51
52
|
import { parseFrontmatter, parseFrontmatterBlock } from "../core/frontmatter";
|
|
52
53
|
import { resolveSourceEntries } from "../indexer/search-source";
|
|
53
|
-
import ingestWorkflowTemplate from "./ingest-workflow-template.md" with { type: "text" };
|
|
54
54
|
import { buildIndexMd, buildLogMd, buildSchemaMd } from "./wiki-templates";
|
|
55
55
|
// ── Constants ───────────────────────────────────────────────────────────────
|
|
56
56
|
export const WIKIS_SUBDIR = "wikis";
|
|
@@ -3,12 +3,12 @@
|
|
|
3
3
|
// file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
|
4
4
|
import fs from "node:fs";
|
|
5
5
|
import path from "node:path";
|
|
6
|
+
import workflowTemplate from "../assets/workflows/workflow-template.md" with { type: "text" };
|
|
6
7
|
import { resolveAssetPathFromName } from "../core/asset-spec";
|
|
7
8
|
import { isWithin, resolveStashDir } from "../core/common";
|
|
8
9
|
import { UsageError } from "../core/errors";
|
|
9
10
|
import { warn } from "../core/warn";
|
|
10
11
|
import { parseWorkflow } from "./parser";
|
|
11
|
-
import workflowTemplate from "./workflow-template.md" with { type: "text" };
|
|
12
12
|
const DEFAULT_WORKFLOW_TEMPLATE = renderWorkflowTemplate({
|
|
13
13
|
title: "Example Workflow",
|
|
14
14
|
firstStepTitle: "First Step",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "akm-cli",
|
|
3
|
-
"version": "0.8.
|
|
3
|
+
"version": "0.8.1",
|
|
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": [
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|