akm-cli 0.9.0-beta.32 → 0.9.0-beta.33
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 +16 -0
- package/dist/commands/improve/extract.js +15 -9
- package/dist/llm/feature-gate.js +8 -4
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -6,6 +6,22 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
|
|
|
6
6
|
|
|
7
7
|
## [Unreleased]
|
|
8
8
|
|
|
9
|
+
## [0.9.0-beta.33] — 2026-06-21
|
|
10
|
+
|
|
11
|
+
### Fixed
|
|
12
|
+
|
|
13
|
+
- **`akm extract` decoupled from the improve-stage toggle.** `processes.extract.enabled`
|
|
14
|
+
now gates extract only as a STAGE of `akm improve` (the active improve profile, per
|
|
15
|
+
#593/#594); an explicit `akm extract` command always runs. Previously dropping extract
|
|
16
|
+
from the daily improve profile silently disabled the standalone command (and its LLM
|
|
17
|
+
calls, via the shared `session_extraction` feature gate).
|
|
18
|
+
- **`extract --session-id` now respects the content-hash ledger; `--force` overrides.**
|
|
19
|
+
Explicit single-session extraction previously bypassed the #602 already-extracted skip
|
|
20
|
+
unconditionally — re-paying the LLM on every call and risking double-extraction against
|
|
21
|
+
the cron. Now a targeted `extract --session-id <id>` is idempotent (skips an unchanged,
|
|
22
|
+
already-extracted session with zero LLM calls) and only `--force` re-extracts. This
|
|
23
|
+
makes a session-end hook firing `extract --session-id <id>` precise AND idempotent.
|
|
24
|
+
|
|
9
25
|
## [0.9.0-beta.32] — 2026-06-21
|
|
10
26
|
|
|
11
27
|
### Added
|
|
@@ -37,7 +37,7 @@ import { getAvailableHarnesses } from "../../integrations/session-logs/index.js"
|
|
|
37
37
|
import { preFilterSession } from "../../integrations/session-logs/pre-filter.js";
|
|
38
38
|
import { chatCompletion } from "../../llm/client.js";
|
|
39
39
|
import { embed } from "../../llm/embedder.js";
|
|
40
|
-
import {
|
|
40
|
+
import { tryLlmFeature } from "../../llm/feature-gate.js";
|
|
41
41
|
import { sha256Hex } from "../../runtime.js";
|
|
42
42
|
import { createProposal, isProposalSkipped } from "../proposal/validators/proposals.js";
|
|
43
43
|
import { buildExtractPrompt, EXTRACT_JSON_SCHEMA, parseExtractPayload } from "./extract-prompt.js";
|
|
@@ -180,7 +180,7 @@ triage, sessionIndexing, schemaSimilarityCtx,
|
|
|
180
180
|
// prior row + bypass flags are threaded in from the caller. Skipping here still
|
|
181
181
|
// costs ZERO LLM calls (the expensive resource #602 protects); only the cheap
|
|
182
182
|
// file read is incurred.
|
|
183
|
-
prior, force
|
|
183
|
+
prior, force) {
|
|
184
184
|
const warnings = [];
|
|
185
185
|
let data;
|
|
186
186
|
try {
|
|
@@ -201,10 +201,12 @@ prior, force, singleSession) {
|
|
|
201
201
|
// #602 — content-hash skip. Computed on the RAW event stream immediately after
|
|
202
202
|
// a successful read, BEFORE the pre-filter / minContentChars / triage gates, so
|
|
203
203
|
// an unchanged session never reaches the LLM. Hash-based ⇒ clock-independent
|
|
204
|
-
// (immune to the Jun 11-12 timestamp double-extract/over-throttle bug).
|
|
205
|
-
//
|
|
204
|
+
// (immune to the Jun 11-12 timestamp double-extract/over-throttle bug). The skip
|
|
205
|
+
// applies UNIFORMLY — including explicit `--session-id` targeting (so a
|
|
206
|
+
// session-end hook firing `extract --session-id <id>` is idempotent). ONLY
|
|
207
|
+
// `--force` overrides it to re-extract a previously-extracted session.
|
|
206
208
|
const contentHash = hashSessionContent(data);
|
|
207
|
-
if (!force &&
|
|
209
|
+
if (!force && shouldSkipAlreadyExtractedSession(prior, contentHash)) {
|
|
208
210
|
return {
|
|
209
211
|
sessionId: sessionRef.sessionId,
|
|
210
212
|
harness: harness.name,
|
|
@@ -470,9 +472,13 @@ export async function akmExtract(options) {
|
|
|
470
472
|
const extractProcess = activeProfile
|
|
471
473
|
? activeProfile.processes?.extract
|
|
472
474
|
: config.profiles?.improve?.default?.processes?.extract;
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
475
|
+
// The `extract.enabled` process toggle gates extract as a STAGE of `akm improve`
|
|
476
|
+
// (the activeProfile path) — consistent with #593/#594 where the active profile,
|
|
477
|
+
// not `default`, is the source of truth. An EXPLICIT `akm extract` invocation
|
|
478
|
+
// (no activeProfile) is a direct user/cron action and always runs; gating it on
|
|
479
|
+
// the default improve profile's stage toggle was a footgun — dropping extract
|
|
480
|
+
// from the daily improve profile would silently disable the standalone command.
|
|
481
|
+
const extractEnabled = activeProfile ? resolveProcessEnabled("extract", activeProfile) : true;
|
|
476
482
|
// Feature-gate early so we get a clean "skipped because disabled" envelope.
|
|
477
483
|
if (!extractEnabled) {
|
|
478
484
|
return {
|
|
@@ -685,7 +691,7 @@ export async function akmExtract(options) {
|
|
|
685
691
|
break;
|
|
686
692
|
}
|
|
687
693
|
try {
|
|
688
|
-
const result = await processSession(harness, summary, stashDir, config, llmConfig, chat, options.ctx, sourceRun, dryRun, timeoutMs, maxTotalChars, minContentChars, triage, sessionIndexing, schemaSimilarityCtx, prior, options.force === true
|
|
694
|
+
const result = await processSession(harness, summary, stashDir, config, llmConfig, chat, options.ctx, sourceRun, dryRun, timeoutMs, maxTotalChars, minContentChars, triage, sessionIndexing, schemaSimilarityCtx, prior, options.force === true);
|
|
689
695
|
sessions.push(result);
|
|
690
696
|
// #626 — triage aggregation. A session reached the triage gate only when it
|
|
691
697
|
// was NOT already preempted by an earlier skip (read_failed / too_short /
|
package/dist/llm/feature-gate.js
CHANGED
|
@@ -30,10 +30,14 @@ const FEATURE_LOCATION = {
|
|
|
30
30
|
proposal_quality_gate: (cfg) => cfg.profiles?.improve?.default?.processes?.reflect?.qualityGate?.enabled ?? false,
|
|
31
31
|
// Legacy default: false
|
|
32
32
|
memory_contradiction_detection: (cfg) => cfg.profiles?.improve?.default?.processes?.consolidate?.contradictionDetection?.enabled ?? false,
|
|
33
|
-
//
|
|
34
|
-
//
|
|
35
|
-
//
|
|
36
|
-
|
|
33
|
+
// Always on at the LLM-wrapper level. Enablement is decided ONCE at the
|
|
34
|
+
// extract entry point (`akmExtract`): the `extract.enabled` process toggle
|
|
35
|
+
// gates extract as a STAGE of `akm improve` (the active improve profile, per
|
|
36
|
+
// #593/#594), while an explicit `akm extract` command always runs. Gating the
|
|
37
|
+
// inner LLM calls on `default.processes.extract.enabled` here was a footgun —
|
|
38
|
+
// dropping extract from the daily improve profile silently disabled the
|
|
39
|
+
// standalone `akm extract` command. (cfg unused — kept for resolver signature.)
|
|
40
|
+
session_extraction: (_cfg) => true,
|
|
37
41
|
};
|
|
38
42
|
/**
|
|
39
43
|
* Pure predicate: is the named feature gate enabled in `config`?
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "akm-cli",
|
|
3
|
-
"version": "0.9.0-beta.
|
|
3
|
+
"version": "0.9.0-beta.33",
|
|
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": [
|