akm-cli 0.9.0-beta.55 → 0.9.0-beta.57
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/dist/indexer/db/db.js
CHANGED
|
@@ -1278,9 +1278,8 @@ export function applyFeedbackToUtilityScore(db, entryId, positiveCount, negative
|
|
|
1278
1278
|
/**
|
|
1279
1279
|
* Re-link detached usage_events to their current entry_ids via entry_ref.
|
|
1280
1280
|
*
|
|
1281
|
-
* After a full rebuild, entry IDs change. This
|
|
1282
|
-
*
|
|
1283
|
-
* history survives a full reindex.
|
|
1281
|
+
* After a full rebuild, entry IDs change. This restores each event's link
|
|
1282
|
+
* using the stable `entry_ref` column so usage history survives a reindex.
|
|
1284
1283
|
*/
|
|
1285
1284
|
export function relinkUsageEvents(db) {
|
|
1286
1285
|
bestEffort(() => {
|
|
@@ -1297,17 +1296,34 @@ export function relinkUsageEvents(db) {
|
|
|
1297
1296
|
WHERE entry_id IS NOT NULL
|
|
1298
1297
|
AND entry_id NOT IN (SELECT id FROM entries)
|
|
1299
1298
|
`);
|
|
1300
|
-
// Step 2: re-resolve any null entry_id from entry_ref against the
|
|
1301
|
-
//
|
|
1302
|
-
//
|
|
1303
|
-
|
|
1304
|
-
|
|
1305
|
-
|
|
1306
|
-
|
|
1307
|
-
|
|
1308
|
-
|
|
1309
|
-
|
|
1310
|
-
|
|
1299
|
+
// Step 2: re-resolve any null entry_id from entry_ref against the current
|
|
1300
|
+
// entries table, reusing the SAME canonical resolver the read path uses at
|
|
1301
|
+
// insert time (`findEntryIdByRef` → `parseAssetRef`). Resolving per DISTINCT
|
|
1302
|
+
// ref keeps this O(distinct-refs) indexed lookups instead of the previous
|
|
1303
|
+
// O(events × entries) non-indexable `substr(entry_key, …)` scan. It also
|
|
1304
|
+
// fixes a silent correctness bug: the old suffix match compared the RAW
|
|
1305
|
+
// `entry_ref`, so origin-qualified refs ("source//type:name") never matched
|
|
1306
|
+
// an `entry_key` and lost their usage history on every full rebuild.
|
|
1307
|
+
const refs = db
|
|
1308
|
+
.prepare("SELECT DISTINCT entry_ref AS ref FROM usage_events WHERE entry_id IS NULL AND entry_ref IS NOT NULL")
|
|
1309
|
+
.all();
|
|
1310
|
+
const update = db.prepare("UPDATE usage_events SET entry_id = ? WHERE entry_ref = ? AND entry_id IS NULL");
|
|
1311
|
+
const relinkTx = db.transaction(() => {
|
|
1312
|
+
for (const { ref } of refs) {
|
|
1313
|
+
let id;
|
|
1314
|
+
try {
|
|
1315
|
+
id = findEntryIdByRef(db, ref);
|
|
1316
|
+
}
|
|
1317
|
+
catch (err) {
|
|
1318
|
+
if (err instanceof Error && err.name === "UsageError")
|
|
1319
|
+
continue;
|
|
1320
|
+
throw err;
|
|
1321
|
+
}
|
|
1322
|
+
if (id !== undefined)
|
|
1323
|
+
update.run(id, ref);
|
|
1324
|
+
}
|
|
1325
|
+
});
|
|
1326
|
+
relinkTx();
|
|
1311
1327
|
}, "usage_events table may not exist yet during entry_id re-resolution");
|
|
1312
1328
|
}
|
|
1313
1329
|
// ── registry_index_cache helpers ─────────────────────────────────────────────
|
|
@@ -29,16 +29,6 @@ const FEEDBACK_REWARD_POSITIVE = 1.0;
|
|
|
29
29
|
* Reward 0.0 means "not helpful" (lowest MemRL signal).
|
|
30
30
|
*/
|
|
31
31
|
const FEEDBACK_REWARD_NEGATIVE = 0.0;
|
|
32
|
-
/**
|
|
33
|
-
* Maximum total negative utility delta allowed in a single
|
|
34
|
-
* `applyFeedbackToUtilityScore` call regardless of negativeCount.
|
|
35
|
-
*
|
|
36
|
-
* This caps the per-day negative impact (the function is called once per
|
|
37
|
-
* feedback event — spamming 10 negatives in one session can move utility
|
|
38
|
-
* at most `MAX_NEG_DELTA_PER_CALL`). The cap prevents a noisy negative-
|
|
39
|
-
* feedback stream from silently destroying a high-utility asset's ranking.
|
|
40
|
-
*/
|
|
41
|
-
export const MAX_NEG_DELTA_PER_CALL = 0.15;
|
|
42
32
|
/**
|
|
43
33
|
* Utility threshold below which a review-needed escalation is triggered.
|
|
44
34
|
* When a previously high-utility asset (≥ HIGH_UTILITY_THRESHOLD) drops
|
|
@@ -57,8 +47,12 @@ export const HIGH_UTILITY_THRESHOLD = 0.5;
|
|
|
57
47
|
* reward = weighted average of positive and negative signals
|
|
58
48
|
* nextUtil = clamp(currentUtil + lr × (reward − currentUtil), 0, 1)
|
|
59
49
|
*
|
|
60
|
-
* The
|
|
61
|
-
*
|
|
50
|
+
* The step is inherently bounded: reward ∈ [0, 1] and currentUtil ∈ [0, 1], so
|
|
51
|
+
* a single call moves utility by at most {@link FEEDBACK_LR} in either
|
|
52
|
+
* direction. `reward` is a proportion of the counts, not their magnitude, so
|
|
53
|
+
* with no positive signals the number of negatives is irrelevant (reward is 0
|
|
54
|
+
* whether there is 1 negative or 100). Mixing in positives shifts reward and so
|
|
55
|
+
* the step, but never past the learning-rate bound.
|
|
62
56
|
*
|
|
63
57
|
* Pure: no DB access. When both counts are zero, utility is unchanged.
|
|
64
58
|
*/
|
|
@@ -73,12 +67,8 @@ export function computeNextUtility(previousUtility, positiveCount, negativeCount
|
|
|
73
67
|
: negativeCount > 0 && positiveCount === 0
|
|
74
68
|
? FEEDBACK_REWARD_NEGATIVE
|
|
75
69
|
: (positiveCount * FEEDBACK_REWARD_POSITIVE + negativeCount * FEEDBACK_REWARD_NEGATIVE) / total;
|
|
76
|
-
// MemRL bounded-step EMA: lr × (reward − current)
|
|
77
|
-
|
|
78
|
-
// Per-call negative cap: if delta is negative (net negative feedback), cap it.
|
|
79
|
-
if (delta < 0) {
|
|
80
|
-
delta = Math.max(delta, -MAX_NEG_DELTA_PER_CALL);
|
|
81
|
-
}
|
|
70
|
+
// MemRL bounded-step EMA: lr × (reward − current). |delta| ≤ FEEDBACK_LR.
|
|
71
|
+
const delta = FEEDBACK_LR * (reward - previousUtility);
|
|
82
72
|
const nextUtility = Math.max(0, Math.min(1, previousUtility + delta));
|
|
83
73
|
const crossedReviewThreshold = previousUtility >= HIGH_UTILITY_THRESHOLD && nextUtility < UTILITY_REVIEW_THRESHOLD;
|
|
84
74
|
return { previousUtility, nextUtility, crossedReviewThreshold };
|
|
@@ -1,7 +1,13 @@
|
|
|
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
|
+
// AKM_EVENT_SOURCE carries usage-event provenance (improve/task) so that akm
|
|
5
|
+
// invocations a spawned agent makes are recorded as machine traffic, not user
|
|
6
|
+
// demand (DRIFT-6). Without it in the passthrough whitelist, buildChildEnv drops
|
|
7
|
+
// the stamp at the agent boundary — e.g. `akm wiki ingest` spawns an agent whose
|
|
8
|
+
// `akm curate/show/search` tool-calls then log source='user', silently inflating
|
|
9
|
+
// every lane's read-back (GRR). It is a provenance tag, never a secret.
|
|
10
|
+
const COMMON_PASSTHROUGH = ["HOME", "PATH", "USER", "LANG", "LC_ALL", "TERM", "TMPDIR", "AKM_EVENT_SOURCE"];
|
|
5
11
|
/**
|
|
6
12
|
* Built-in profiles for the five agent CLIs the v1 spec calls out
|
|
7
13
|
* explicitly. The fields here are conservative defaults — every value is
|
|
@@ -25,7 +25,9 @@ export function getCachedEmbedding(key) {
|
|
|
25
25
|
return cached;
|
|
26
26
|
}
|
|
27
27
|
export function setCachedEmbedding(key, value) {
|
|
28
|
-
//
|
|
28
|
+
// Delete first so an overwrite refreshes LRU recency AND is not counted as a
|
|
29
|
+
// new insert: only a genuinely new key at capacity should evict the oldest.
|
|
30
|
+
embedCache.delete(key);
|
|
29
31
|
if (embedCache.size >= EMBED_CACHE_MAX) {
|
|
30
32
|
const oldest = embedCache.keys().next().value;
|
|
31
33
|
if (oldest !== undefined) {
|
package/dist/registry/resolve.js
CHANGED
|
@@ -238,6 +238,11 @@ function tryParseLocalRef(rawRef, explicitPath) {
|
|
|
238
238
|
};
|
|
239
239
|
}
|
|
240
240
|
function isPathLikeRef(ref) {
|
|
241
|
+
// A leading `@` marks an npm scope (`@scope/pkg`), never a filesystem path —
|
|
242
|
+
// treat it as non-path so it falls through to the npm branch instead of
|
|
243
|
+
// being resolved (and rejected) as an explicit local path.
|
|
244
|
+
if (ref.startsWith("@"))
|
|
245
|
+
return false;
|
|
241
246
|
if (ref === "." || ref === "..")
|
|
242
247
|
return true;
|
|
243
248
|
if (path.isAbsolute(ref))
|
|
@@ -9715,15 +9715,12 @@ function computeNextUtility(previousUtility, positiveCount, negativeCount) {
|
|
|
9715
9715
|
}
|
|
9716
9716
|
const total = positiveCount + negativeCount;
|
|
9717
9717
|
const reward = positiveCount > 0 && negativeCount === 0 ? FEEDBACK_REWARD_POSITIVE : negativeCount > 0 && positiveCount === 0 ? FEEDBACK_REWARD_NEGATIVE : (positiveCount * FEEDBACK_REWARD_POSITIVE + negativeCount * FEEDBACK_REWARD_NEGATIVE) / total;
|
|
9718
|
-
|
|
9719
|
-
if (delta < 0) {
|
|
9720
|
-
delta = Math.max(delta, -MAX_NEG_DELTA_PER_CALL);
|
|
9721
|
-
}
|
|
9718
|
+
const delta = FEEDBACK_LR * (reward - previousUtility);
|
|
9722
9719
|
const nextUtility = Math.max(0, Math.min(1, previousUtility + delta));
|
|
9723
9720
|
const crossedReviewThreshold = previousUtility >= HIGH_UTILITY_THRESHOLD && nextUtility < UTILITY_REVIEW_THRESHOLD;
|
|
9724
9721
|
return { previousUtility, nextUtility, crossedReviewThreshold };
|
|
9725
9722
|
}
|
|
9726
|
-
var FEEDBACK_LR = 0.1, FEEDBACK_REWARD_POSITIVE = 1, FEEDBACK_REWARD_NEGATIVE = 0,
|
|
9723
|
+
var FEEDBACK_LR = 0.1, FEEDBACK_REWARD_POSITIVE = 1, FEEDBACK_REWARD_NEGATIVE = 0, UTILITY_REVIEW_THRESHOLD = 0.5, HIGH_UTILITY_THRESHOLD = 0.5;
|
|
9727
9724
|
|
|
9728
9725
|
// src/indexer/search/fts-query.ts
|
|
9729
9726
|
function sanitizeFtsQuery(query) {
|
|
@@ -11182,7 +11179,7 @@ var init_opencode = __esm(() => {
|
|
|
11182
11179
|
// src/integrations/agent/profiles.ts
|
|
11183
11180
|
var COMMON_PASSTHROUGH, BUILTINS, HEADLESS_BUILTINS, BUILTIN_AGENT_PROFILE_NAMES;
|
|
11184
11181
|
var init_profiles = __esm(() => {
|
|
11185
|
-
COMMON_PASSTHROUGH = ["HOME", "PATH", "USER", "LANG", "LC_ALL", "TERM", "TMPDIR"];
|
|
11182
|
+
COMMON_PASSTHROUGH = ["HOME", "PATH", "USER", "LANG", "LC_ALL", "TERM", "TMPDIR", "AKM_EVENT_SOURCE"];
|
|
11186
11183
|
BUILTINS = {
|
|
11187
11184
|
opencode: {
|
|
11188
11185
|
name: "opencode",
|
|
@@ -17572,14 +17569,23 @@ function relinkUsageEvents(db) {
|
|
|
17572
17569
|
WHERE entry_id IS NOT NULL
|
|
17573
17570
|
AND entry_id NOT IN (SELECT id FROM entries)
|
|
17574
17571
|
`);
|
|
17575
|
-
db.
|
|
17576
|
-
|
|
17577
|
-
|
|
17578
|
-
|
|
17579
|
-
|
|
17580
|
-
|
|
17581
|
-
|
|
17582
|
-
|
|
17572
|
+
const refs = db.prepare("SELECT DISTINCT entry_ref AS ref FROM usage_events WHERE entry_id IS NULL AND entry_ref IS NOT NULL").all();
|
|
17573
|
+
const update = db.prepare("UPDATE usage_events SET entry_id = ? WHERE entry_ref = ? AND entry_id IS NULL");
|
|
17574
|
+
const relinkTx = db.transaction(() => {
|
|
17575
|
+
for (const { ref } of refs) {
|
|
17576
|
+
let id;
|
|
17577
|
+
try {
|
|
17578
|
+
id = findEntryIdByRef(db, ref);
|
|
17579
|
+
} catch (err) {
|
|
17580
|
+
if (err instanceof Error && err.name === "UsageError")
|
|
17581
|
+
continue;
|
|
17582
|
+
throw err;
|
|
17583
|
+
}
|
|
17584
|
+
if (id !== undefined)
|
|
17585
|
+
update.run(id, ref);
|
|
17586
|
+
}
|
|
17587
|
+
});
|
|
17588
|
+
relinkTx();
|
|
17583
17589
|
}, "usage_events table may not exist yet during entry_id re-resolution");
|
|
17584
17590
|
}
|
|
17585
17591
|
function upsertRegistryIndexCache(db, registryUrl, indexJson, opts) {
|
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.57",
|
|
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": [
|