akm-opencode 0.10.261106-beta → 0.10.261108-beta
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/index.js +63 -60
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -964,7 +964,8 @@ function shouldSubmitAutomaticFeedback(signal) {
|
|
|
964
964
|
// ../claude/shared/ref-extraction.ts
|
|
965
965
|
import { existsSync as existsSync3, statSync as statSync3 } from "fs";
|
|
966
966
|
import path4 from "path";
|
|
967
|
-
var AKM_REF_STRICT = /^(?:[A-Za-z0-9@._+-]+\/\/)?(
|
|
967
|
+
var AKM_REF_STRICT = /^(?:[A-Za-z0-9@._+-]+\/\/)?[A-Za-z0-9@._+-]+(?:\/[A-Za-z0-9._+@-]+)*(?:#[A-Za-z0-9._~!$&'()*+,;=:@%/?-]+)?$/;
|
|
968
|
+
var CONCEPT_ROOT_REF = /^(?:[A-Za-z0-9@._+-]+\/\/)?(?:agents|commands|env|facts|instructions|knowledge|lessons|memories|scripts|secrets|sessions|skills|tasks|workflows)\/[A-Za-z0-9._/-]+(?:#[A-Za-z0-9._~!$&'()*+,;=:@%/?-]+)?$/;
|
|
968
969
|
var EDGE_PUNCTUATION = new Set([".", ",", ";", ":", "!", "?", "(", ")", "[", "]", "{", "}", "'", '"', "`"]);
|
|
969
970
|
function normalizeToken(token) {
|
|
970
971
|
let start = 0;
|
|
@@ -979,14 +980,39 @@ function extractAkmRefsFromString(text) {
|
|
|
979
980
|
const refs = new Set;
|
|
980
981
|
for (const token of text.split(/\s+/)) {
|
|
981
982
|
const normalized = normalizeToken(token);
|
|
982
|
-
if (normalized &&
|
|
983
|
+
if (normalized && CONCEPT_ROOT_REF.test(normalized))
|
|
983
984
|
refs.add(normalized);
|
|
984
985
|
}
|
|
985
986
|
return [...refs];
|
|
986
987
|
}
|
|
988
|
+
function akmRefFromValue(value) {
|
|
989
|
+
if (typeof value !== "string")
|
|
990
|
+
return;
|
|
991
|
+
const ref = value.trim();
|
|
992
|
+
return AKM_REF_STRICT.test(ref) && !ref.split("#", 1)[0].split("//").pop().split("/").some((s) => s === "." || s === "..") ? ref : undefined;
|
|
993
|
+
}
|
|
994
|
+
function refsOfAkmResult(result) {
|
|
995
|
+
if (!result || typeof result !== "object")
|
|
996
|
+
return [];
|
|
997
|
+
const r = result;
|
|
998
|
+
const entries = [r, ...Array.isArray(r.hits) ? r.hits : [], ...Array.isArray(r.items) ? r.items : []];
|
|
999
|
+
const refs = entries.map((e) => e && typeof e === "object" ? akmRefFromValue(e.ref) : undefined);
|
|
1000
|
+
return [...new Set(refs.filter((ref) => !!ref))];
|
|
1001
|
+
}
|
|
1002
|
+
function extractRefsFromAkmOutput(text) {
|
|
1003
|
+
let parsed;
|
|
1004
|
+
try {
|
|
1005
|
+
parsed = JSON.parse(text);
|
|
1006
|
+
} catch {
|
|
1007
|
+
parsed = undefined;
|
|
1008
|
+
}
|
|
1009
|
+
const refLines = [...text.matchAll(/^\s*ref:\s*(\S+)\s*$/gm)].map((m) => akmRefFromValue(m[1]));
|
|
1010
|
+
return [...new Set([...refsOfAkmResult(parsed), ...refLines.filter((r) => !!r), ...extractAkmRefsFromString(text)])];
|
|
1011
|
+
}
|
|
987
1012
|
function normalizeCandidate(candidate) {
|
|
988
1013
|
const canonical = normalizeToken(candidate);
|
|
989
|
-
|
|
1014
|
+
const ref = akmRefFromValue(canonical);
|
|
1015
|
+
if (!ref)
|
|
990
1016
|
return null;
|
|
991
1017
|
const withoutFragment = canonical.split("#", 1)[0] ?? "";
|
|
992
1018
|
const separator = withoutFragment.indexOf("//");
|
|
@@ -1022,37 +1048,41 @@ var SCRIPT_EXTENSIONS = new Set([
|
|
|
1022
1048
|
".kts"
|
|
1023
1049
|
]);
|
|
1024
1050
|
function markdownFile(directPath) {
|
|
1051
|
+
if (path4.basename(directPath).replace(/\.md$/, "") === "SKILL")
|
|
1052
|
+
return false;
|
|
1025
1053
|
return isFile(`${directPath}.md`) || directPath.endsWith(".md") && isFile(directPath);
|
|
1026
1054
|
}
|
|
1027
|
-
function isAsset(
|
|
1028
|
-
if (
|
|
1029
|
-
return
|
|
1030
|
-
if (
|
|
1031
|
-
return
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
}
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1055
|
+
function isAsset(directPath, ref) {
|
|
1056
|
+
if (isFile(path4.join(directPath, "SKILL.md")) || markdownFile(directPath))
|
|
1057
|
+
return true;
|
|
1058
|
+
if (SCRIPT_EXTENSIONS.has(path4.extname(directPath).toLowerCase()) && isFile(directPath))
|
|
1059
|
+
return true;
|
|
1060
|
+
const folders = ref.split("/").slice(0, -1);
|
|
1061
|
+
if (folders.includes("env")) {
|
|
1062
|
+
if (isFile(`${directPath}.env`))
|
|
1063
|
+
return true;
|
|
1064
|
+
if (path4.basename(directPath) === "default" && isFile(path4.join(path4.dirname(directPath), ".env")))
|
|
1065
|
+
return true;
|
|
1066
|
+
}
|
|
1067
|
+
if (folders.includes("tasks") && isFile(`${directPath}.yml`))
|
|
1068
|
+
return true;
|
|
1069
|
+
return folders.includes("secrets") && !/\.(lock|sensitive)$/.test(directPath) && isFile(directPath);
|
|
1070
|
+
}
|
|
1071
|
+
var LEGACY_PREFIXES = new Set(["scripts", "agents", "commands", "facts", "instructions", "knowledge", "lessons", "memories", "sessions"]);
|
|
1042
1072
|
function conceptExistsInAnyBundle(conceptId, bundleRoots) {
|
|
1043
|
-
const
|
|
1044
|
-
const rest = conceptId.slice(
|
|
1073
|
+
const head = conceptId.split("/", 1)[0];
|
|
1074
|
+
const rest = conceptId.slice(head.length + 1);
|
|
1045
1075
|
for (const root of bundleRoots) {
|
|
1046
1076
|
if (!root)
|
|
1047
1077
|
continue;
|
|
1048
1078
|
const resolvedRoot = path4.resolve(root);
|
|
1079
|
+
const inside = (file) => file !== resolvedRoot && file.startsWith(`${resolvedRoot}${path4.sep}`);
|
|
1049
1080
|
const directPath = path4.resolve(resolvedRoot, conceptId);
|
|
1050
|
-
if (directPath
|
|
1051
|
-
continue;
|
|
1052
|
-
if (isAsset(type, directPath))
|
|
1081
|
+
if (inside(directPath) && isAsset(directPath, conceptId))
|
|
1053
1082
|
return true;
|
|
1054
|
-
if (
|
|
1055
|
-
|
|
1083
|
+
if (LEGACY_PREFIXES.has(head) && rest.includes("/")) {
|
|
1084
|
+
const legacyPath = path4.resolve(resolvedRoot, rest);
|
|
1085
|
+
if (inside(legacyPath) && isAsset(legacyPath, rest))
|
|
1056
1086
|
return true;
|
|
1057
1087
|
}
|
|
1058
1088
|
}
|
|
@@ -1101,35 +1131,9 @@ function classifyToolFeedback(value) {
|
|
|
1101
1131
|
return "positive";
|
|
1102
1132
|
return;
|
|
1103
1133
|
}
|
|
1104
|
-
function extractToolRefs(
|
|
1105
|
-
const
|
|
1106
|
-
|
|
1107
|
-
if (typeof value !== "string")
|
|
1108
|
-
return;
|
|
1109
|
-
for (const ref of extractAkmRefsFromString(value))
|
|
1110
|
-
refs.add(ref);
|
|
1111
|
-
};
|
|
1112
|
-
for (const key of ["ref", "package_ref"])
|
|
1113
|
-
addMatches(args[key]);
|
|
1114
|
-
if (output && typeof output === "object") {
|
|
1115
|
-
const o = output;
|
|
1116
|
-
addMatches(o.ref);
|
|
1117
|
-
if (Array.isArray(o.hits)) {
|
|
1118
|
-
for (const hit of o.hits) {
|
|
1119
|
-
if (hit && typeof hit === "object")
|
|
1120
|
-
addMatches(hit.ref);
|
|
1121
|
-
}
|
|
1122
|
-
}
|
|
1123
|
-
if (Array.isArray(o.items)) {
|
|
1124
|
-
for (const item of o.items) {
|
|
1125
|
-
if (item && typeof item === "object")
|
|
1126
|
-
addMatches(item.ref);
|
|
1127
|
-
}
|
|
1128
|
-
}
|
|
1129
|
-
if (toolName === "akm_remember" && typeof o.ref === "string")
|
|
1130
|
-
addMatches(o.ref);
|
|
1131
|
-
}
|
|
1132
|
-
return [...refs];
|
|
1134
|
+
function extractToolRefs(args, output) {
|
|
1135
|
+
const named = [args.ref, args.package_ref].map(akmRefFromValue).filter((ref) => !!ref);
|
|
1136
|
+
return [...new Set([...named, ...refsOfAkmResult(output)])];
|
|
1133
1137
|
}
|
|
1134
1138
|
function extractAkmRefsFromAllArgs(args) {
|
|
1135
1139
|
if (!args || typeof args !== "object")
|
|
@@ -1208,7 +1212,7 @@ function createFeedbackTracker(options) {
|
|
|
1208
1212
|
const isAkmTool = input.tool.startsWith("akm_");
|
|
1209
1213
|
const candidateRefs = [...new Set([...extractAkmRefsFromAllArgs(input.args), ...extractAkmRefsFromString(input.outputText)])];
|
|
1210
1214
|
const parsed = isAkmTool ? parseToolOutput(input.outputText) : null;
|
|
1211
|
-
const refs = isAkmTool && parsed ? extractToolRefs(input.
|
|
1215
|
+
const refs = isAkmTool && parsed ? extractToolRefs(input.args, parsed) : validateRefCandidates(candidateRefs, [await input.getBundleDir() ?? ""]);
|
|
1212
1216
|
const failedCall = classifyToolFeedback(parsed) === "negative";
|
|
1213
1217
|
if (refs.length > 0) {
|
|
1214
1218
|
input.writeEvent({
|
|
@@ -1228,7 +1232,7 @@ function createFeedbackTracker(options) {
|
|
|
1228
1232
|
}
|
|
1229
1233
|
function observeAkmToolResult(input) {
|
|
1230
1234
|
const outcome = classifyToolFeedback(input.parsed);
|
|
1231
|
-
const refs = extractToolRefs(input.
|
|
1235
|
+
const refs = extractToolRefs(input.args, input.parsed);
|
|
1232
1236
|
const failedCall = outcome === "negative";
|
|
1233
1237
|
if (!failedCall)
|
|
1234
1238
|
noteRecentRefs(input.sessionID, refs);
|
|
@@ -3233,8 +3237,7 @@ async function runCli(client, args, meta) {
|
|
|
3233
3237
|
stdout,
|
|
3234
3238
|
stderr: ""
|
|
3235
3239
|
});
|
|
3236
|
-
const
|
|
3237
|
-
const refs = args[0] === "search" || args[0] === "curate" ? [...new Set([...parsed?.hits?.flatMap((hit) => hit.ref ? [hit.ref] : []) ?? [], ...extractAkmRefsFromString(stdout)])] : extractAkmRefsFromString(stdout);
|
|
3240
|
+
const refs = extractRefsFromAkmOutput(stdout);
|
|
3238
3241
|
feedbackTracker.noteRecentRefs(meta.sessionID, refs);
|
|
3239
3242
|
if (meta.toolName === "akm_search") {
|
|
3240
3243
|
await emitWorkflowTelemetry(client, "info", "akm.search.invoked", {
|
|
@@ -3346,7 +3349,7 @@ async function runInProcess(client, operation, input, meta) {
|
|
|
3346
3349
|
return result.output;
|
|
3347
3350
|
}
|
|
3348
3351
|
const output = result.output;
|
|
3349
|
-
const refs =
|
|
3352
|
+
const refs = extractRefsFromAkmOutput(output);
|
|
3350
3353
|
feedbackTracker.noteRecentRefs(meta.sessionID, refs);
|
|
3351
3354
|
await writePluginLog(client, "info", "AKM read call completed", {
|
|
3352
3355
|
subsystem: "akm",
|
|
@@ -3617,7 +3620,7 @@ ${block}`;
|
|
|
3617
3620
|
(async () => {
|
|
3618
3621
|
try {
|
|
3619
3622
|
const curated = await runCurateForPrompt(logClient, decision.query, sessionID, directorySnapshot);
|
|
3620
|
-
const refs =
|
|
3623
|
+
const refs = extractRefsFromAkmOutput(curated ?? "");
|
|
3621
3624
|
writeStructuredEvent({
|
|
3622
3625
|
event: "prompt_recall",
|
|
3623
3626
|
sessionId: sessionID,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "akm-opencode",
|
|
3
|
-
"version": "0.10.
|
|
3
|
+
"version": "0.10.261108-beta",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "OpenCode plugin for AKM with discovery tools, feedback, memory, and automatic learning proposals from corrections and recurring workflows.",
|
|
6
6
|
"keywords": [
|
|
@@ -38,7 +38,7 @@
|
|
|
38
38
|
},
|
|
39
39
|
"dependencies": {
|
|
40
40
|
"@opencode-ai/plugin": "^1.18.14",
|
|
41
|
-
"akm-cli": "0.10.
|
|
41
|
+
"akm-cli": "0.10.261108-beta"
|
|
42
42
|
},
|
|
43
43
|
"devDependencies": {
|
|
44
44
|
"@types/node": "^26.1.1",
|