akm-opencode 0.10.261105-beta → 0.10.261107-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 +57 -62
- 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,39 +1048,35 @@ 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
|
+
}
|
|
1042
1071
|
function conceptExistsInAnyBundle(conceptId, bundleRoots) {
|
|
1043
|
-
const type = conceptId.split("/", 1)[0];
|
|
1044
|
-
const rest = conceptId.slice(type.length + 1);
|
|
1045
1072
|
for (const root of bundleRoots) {
|
|
1046
1073
|
if (!root)
|
|
1047
1074
|
continue;
|
|
1048
1075
|
const resolvedRoot = path4.resolve(root);
|
|
1076
|
+
const inside = (file) => file !== resolvedRoot && file.startsWith(`${resolvedRoot}${path4.sep}`);
|
|
1049
1077
|
const directPath = path4.resolve(resolvedRoot, conceptId);
|
|
1050
|
-
if (directPath
|
|
1051
|
-
continue;
|
|
1052
|
-
if (isAsset(type, directPath))
|
|
1078
|
+
if (inside(directPath) && isAsset(directPath, conceptId))
|
|
1053
1079
|
return true;
|
|
1054
|
-
if (OUTSIDE_THEIR_DIRECTORY.has(type) && rest.includes("/") && !rest.startsWith(`${type}/`)) {
|
|
1055
|
-
if (isAsset(type, path4.resolve(resolvedRoot, rest)))
|
|
1056
|
-
return true;
|
|
1057
|
-
}
|
|
1058
1080
|
}
|
|
1059
1081
|
return false;
|
|
1060
1082
|
}
|
|
@@ -1101,35 +1123,9 @@ function classifyToolFeedback(value) {
|
|
|
1101
1123
|
return "positive";
|
|
1102
1124
|
return;
|
|
1103
1125
|
}
|
|
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];
|
|
1126
|
+
function extractToolRefs(args, output) {
|
|
1127
|
+
const named = [args.ref, args.package_ref].map(akmRefFromValue).filter((ref) => !!ref);
|
|
1128
|
+
return [...new Set([...named, ...refsOfAkmResult(output)])];
|
|
1133
1129
|
}
|
|
1134
1130
|
function extractAkmRefsFromAllArgs(args) {
|
|
1135
1131
|
if (!args || typeof args !== "object")
|
|
@@ -1208,7 +1204,7 @@ function createFeedbackTracker(options) {
|
|
|
1208
1204
|
const isAkmTool = input.tool.startsWith("akm_");
|
|
1209
1205
|
const candidateRefs = [...new Set([...extractAkmRefsFromAllArgs(input.args), ...extractAkmRefsFromString(input.outputText)])];
|
|
1210
1206
|
const parsed = isAkmTool ? parseToolOutput(input.outputText) : null;
|
|
1211
|
-
const refs = isAkmTool && parsed ? extractToolRefs(input.
|
|
1207
|
+
const refs = isAkmTool && parsed ? extractToolRefs(input.args, parsed) : validateRefCandidates(candidateRefs, [await input.getBundleDir() ?? ""]);
|
|
1212
1208
|
const failedCall = classifyToolFeedback(parsed) === "negative";
|
|
1213
1209
|
if (refs.length > 0) {
|
|
1214
1210
|
input.writeEvent({
|
|
@@ -1228,7 +1224,7 @@ function createFeedbackTracker(options) {
|
|
|
1228
1224
|
}
|
|
1229
1225
|
function observeAkmToolResult(input) {
|
|
1230
1226
|
const outcome = classifyToolFeedback(input.parsed);
|
|
1231
|
-
const refs = extractToolRefs(input.
|
|
1227
|
+
const refs = extractToolRefs(input.args, input.parsed);
|
|
1232
1228
|
const failedCall = outcome === "negative";
|
|
1233
1229
|
if (!failedCall)
|
|
1234
1230
|
noteRecentRefs(input.sessionID, refs);
|
|
@@ -3233,8 +3229,7 @@ async function runCli(client, args, meta) {
|
|
|
3233
3229
|
stdout,
|
|
3234
3230
|
stderr: ""
|
|
3235
3231
|
});
|
|
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);
|
|
3232
|
+
const refs = extractRefsFromAkmOutput(stdout);
|
|
3238
3233
|
feedbackTracker.noteRecentRefs(meta.sessionID, refs);
|
|
3239
3234
|
if (meta.toolName === "akm_search") {
|
|
3240
3235
|
await emitWorkflowTelemetry(client, "info", "akm.search.invoked", {
|
|
@@ -3346,7 +3341,7 @@ async function runInProcess(client, operation, input, meta) {
|
|
|
3346
3341
|
return result.output;
|
|
3347
3342
|
}
|
|
3348
3343
|
const output = result.output;
|
|
3349
|
-
const refs =
|
|
3344
|
+
const refs = extractRefsFromAkmOutput(output);
|
|
3350
3345
|
feedbackTracker.noteRecentRefs(meta.sessionID, refs);
|
|
3351
3346
|
await writePluginLog(client, "info", "AKM read call completed", {
|
|
3352
3347
|
subsystem: "akm",
|
|
@@ -3617,7 +3612,7 @@ ${block}`;
|
|
|
3617
3612
|
(async () => {
|
|
3618
3613
|
try {
|
|
3619
3614
|
const curated = await runCurateForPrompt(logClient, decision.query, sessionID, directorySnapshot);
|
|
3620
|
-
const refs =
|
|
3615
|
+
const refs = extractRefsFromAkmOutput(curated ?? "");
|
|
3621
3616
|
writeStructuredEvent({
|
|
3622
3617
|
event: "prompt_recall",
|
|
3623
3618
|
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.261107-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.261107-beta"
|
|
42
42
|
},
|
|
43
43
|
"devDependencies": {
|
|
44
44
|
"@types/node": "^26.1.1",
|