akm-opencode-v2 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 +56 -60
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -45,7 +45,8 @@ function readPluginVersion(moduleUrl, packageName) {
|
|
|
45
45
|
// ../claude/shared/ref-extraction.ts
|
|
46
46
|
import { existsSync, statSync } from "fs";
|
|
47
47
|
import path2 from "path";
|
|
48
|
-
var AKM_REF_STRICT = /^(?:[A-Za-z0-9@._+-]+\/\/)?(
|
|
48
|
+
var AKM_REF_STRICT = /^(?:[A-Za-z0-9@._+-]+\/\/)?[A-Za-z0-9@._+-]+(?:\/[A-Za-z0-9._+@-]+)*(?:#[A-Za-z0-9._~!$&'()*+,;=:@%/?-]+)?$/;
|
|
49
|
+
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._~!$&'()*+,;=:@%/?-]+)?$/;
|
|
49
50
|
var EDGE_PUNCTUATION = new Set([".", ",", ";", ":", "!", "?", "(", ")", "[", "]", "{", "}", "'", '"', "`"]);
|
|
50
51
|
function normalizeToken(token) {
|
|
51
52
|
let start = 0;
|
|
@@ -60,14 +61,39 @@ function extractAkmRefsFromString(text) {
|
|
|
60
61
|
const refs = new Set;
|
|
61
62
|
for (const token of text.split(/\s+/)) {
|
|
62
63
|
const normalized = normalizeToken(token);
|
|
63
|
-
if (normalized &&
|
|
64
|
+
if (normalized && CONCEPT_ROOT_REF.test(normalized))
|
|
64
65
|
refs.add(normalized);
|
|
65
66
|
}
|
|
66
67
|
return [...refs];
|
|
67
68
|
}
|
|
69
|
+
function akmRefFromValue(value) {
|
|
70
|
+
if (typeof value !== "string")
|
|
71
|
+
return;
|
|
72
|
+
const ref = value.trim();
|
|
73
|
+
return AKM_REF_STRICT.test(ref) && !ref.split("#", 1)[0].split("//").pop().split("/").some((s) => s === "." || s === "..") ? ref : undefined;
|
|
74
|
+
}
|
|
75
|
+
function refsOfAkmResult(result) {
|
|
76
|
+
if (!result || typeof result !== "object")
|
|
77
|
+
return [];
|
|
78
|
+
const r = result;
|
|
79
|
+
const entries = [r, ...Array.isArray(r.hits) ? r.hits : [], ...Array.isArray(r.items) ? r.items : []];
|
|
80
|
+
const refs = entries.map((e) => e && typeof e === "object" ? akmRefFromValue(e.ref) : undefined);
|
|
81
|
+
return [...new Set(refs.filter((ref) => !!ref))];
|
|
82
|
+
}
|
|
83
|
+
function extractRefsFromAkmOutput(text) {
|
|
84
|
+
let parsed;
|
|
85
|
+
try {
|
|
86
|
+
parsed = JSON.parse(text);
|
|
87
|
+
} catch {
|
|
88
|
+
parsed = undefined;
|
|
89
|
+
}
|
|
90
|
+
const refLines = [...text.matchAll(/^\s*ref:\s*(\S+)\s*$/gm)].map((m) => akmRefFromValue(m[1]));
|
|
91
|
+
return [...new Set([...refsOfAkmResult(parsed), ...refLines.filter((r) => !!r), ...extractAkmRefsFromString(text)])];
|
|
92
|
+
}
|
|
68
93
|
function normalizeCandidate(candidate) {
|
|
69
94
|
const canonical = normalizeToken(candidate);
|
|
70
|
-
|
|
95
|
+
const ref = akmRefFromValue(canonical);
|
|
96
|
+
if (!ref)
|
|
71
97
|
return null;
|
|
72
98
|
const withoutFragment = canonical.split("#", 1)[0] ?? "";
|
|
73
99
|
const separator = withoutFragment.indexOf("//");
|
|
@@ -103,39 +129,35 @@ var SCRIPT_EXTENSIONS = new Set([
|
|
|
103
129
|
".kts"
|
|
104
130
|
]);
|
|
105
131
|
function markdownFile(directPath) {
|
|
132
|
+
if (path2.basename(directPath).replace(/\.md$/, "") === "SKILL")
|
|
133
|
+
return false;
|
|
106
134
|
return isFile(`${directPath}.md`) || directPath.endsWith(".md") && isFile(directPath);
|
|
107
135
|
}
|
|
108
|
-
function isAsset(
|
|
109
|
-
if (
|
|
110
|
-
return
|
|
111
|
-
if (
|
|
112
|
-
return
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
136
|
+
function isAsset(directPath, ref) {
|
|
137
|
+
if (isFile(path2.join(directPath, "SKILL.md")) || markdownFile(directPath))
|
|
138
|
+
return true;
|
|
139
|
+
if (SCRIPT_EXTENSIONS.has(path2.extname(directPath).toLowerCase()) && isFile(directPath))
|
|
140
|
+
return true;
|
|
141
|
+
const folders = ref.split("/").slice(0, -1);
|
|
142
|
+
if (folders.includes("env")) {
|
|
143
|
+
if (isFile(`${directPath}.env`))
|
|
144
|
+
return true;
|
|
145
|
+
if (path2.basename(directPath) === "default" && isFile(path2.join(path2.dirname(directPath), ".env")))
|
|
146
|
+
return true;
|
|
147
|
+
}
|
|
148
|
+
if (folders.includes("tasks") && isFile(`${directPath}.yml`))
|
|
149
|
+
return true;
|
|
150
|
+
return folders.includes("secrets") && !/\.(lock|sensitive)$/.test(directPath) && isFile(directPath);
|
|
151
|
+
}
|
|
123
152
|
function conceptExistsInAnyBundle(conceptId, bundleRoots) {
|
|
124
|
-
const type = conceptId.split("/", 1)[0];
|
|
125
|
-
const rest = conceptId.slice(type.length + 1);
|
|
126
153
|
for (const root of bundleRoots) {
|
|
127
154
|
if (!root)
|
|
128
155
|
continue;
|
|
129
156
|
const resolvedRoot = path2.resolve(root);
|
|
157
|
+
const inside = (file) => file !== resolvedRoot && file.startsWith(`${resolvedRoot}${path2.sep}`);
|
|
130
158
|
const directPath = path2.resolve(resolvedRoot, conceptId);
|
|
131
|
-
if (directPath
|
|
132
|
-
continue;
|
|
133
|
-
if (isAsset(type, directPath))
|
|
159
|
+
if (inside(directPath) && isAsset(directPath, conceptId))
|
|
134
160
|
return true;
|
|
135
|
-
if (OUTSIDE_THEIR_DIRECTORY.has(type) && rest.includes("/") && !rest.startsWith(`${type}/`)) {
|
|
136
|
-
if (isAsset(type, path2.resolve(resolvedRoot, rest)))
|
|
137
|
-
return true;
|
|
138
|
-
}
|
|
139
161
|
}
|
|
140
162
|
return false;
|
|
141
163
|
}
|
|
@@ -802,35 +824,9 @@ function classifyToolFeedback(value) {
|
|
|
802
824
|
return "positive";
|
|
803
825
|
return;
|
|
804
826
|
}
|
|
805
|
-
function extractToolRefs(
|
|
806
|
-
const
|
|
807
|
-
|
|
808
|
-
if (typeof value !== "string")
|
|
809
|
-
return;
|
|
810
|
-
for (const ref of extractAkmRefsFromString(value))
|
|
811
|
-
refs.add(ref);
|
|
812
|
-
};
|
|
813
|
-
for (const key of ["ref", "package_ref"])
|
|
814
|
-
addMatches(args[key]);
|
|
815
|
-
if (output && typeof output === "object") {
|
|
816
|
-
const o = output;
|
|
817
|
-
addMatches(o.ref);
|
|
818
|
-
if (Array.isArray(o.hits)) {
|
|
819
|
-
for (const hit of o.hits) {
|
|
820
|
-
if (hit && typeof hit === "object")
|
|
821
|
-
addMatches(hit.ref);
|
|
822
|
-
}
|
|
823
|
-
}
|
|
824
|
-
if (Array.isArray(o.items)) {
|
|
825
|
-
for (const item of o.items) {
|
|
826
|
-
if (item && typeof item === "object")
|
|
827
|
-
addMatches(item.ref);
|
|
828
|
-
}
|
|
829
|
-
}
|
|
830
|
-
if (toolName === "akm_remember" && typeof o.ref === "string")
|
|
831
|
-
addMatches(o.ref);
|
|
832
|
-
}
|
|
833
|
-
return [...refs];
|
|
827
|
+
function extractToolRefs(args, output) {
|
|
828
|
+
const named = [args.ref, args.package_ref].map(akmRefFromValue).filter((ref) => !!ref);
|
|
829
|
+
return [...new Set([...named, ...refsOfAkmResult(output)])];
|
|
834
830
|
}
|
|
835
831
|
function extractAkmRefsFromAllArgs(args) {
|
|
836
832
|
if (!args || typeof args !== "object")
|
|
@@ -909,7 +905,7 @@ function createFeedbackTracker(options) {
|
|
|
909
905
|
const isAkmTool = input.tool.startsWith("akm_");
|
|
910
906
|
const candidateRefs = [...new Set([...extractAkmRefsFromAllArgs(input.args), ...extractAkmRefsFromString(input.outputText)])];
|
|
911
907
|
const parsed = isAkmTool ? parseToolOutput(input.outputText) : null;
|
|
912
|
-
const refs = isAkmTool && parsed ? extractToolRefs(input.
|
|
908
|
+
const refs = isAkmTool && parsed ? extractToolRefs(input.args, parsed) : validateRefCandidates(candidateRefs, [await input.getBundleDir() ?? ""]);
|
|
913
909
|
const failedCall = classifyToolFeedback(parsed) === "negative";
|
|
914
910
|
if (refs.length > 0) {
|
|
915
911
|
input.writeEvent({
|
|
@@ -929,7 +925,7 @@ function createFeedbackTracker(options) {
|
|
|
929
925
|
}
|
|
930
926
|
function observeAkmToolResult(input) {
|
|
931
927
|
const outcome = classifyToolFeedback(input.parsed);
|
|
932
|
-
const refs = extractToolRefs(input.
|
|
928
|
+
const refs = extractToolRefs(input.args, input.parsed);
|
|
933
929
|
const failedCall = outcome === "negative";
|
|
934
930
|
if (!failedCall)
|
|
935
931
|
noteRecentRefs(input.sessionID, refs);
|
|
@@ -3017,7 +3013,7 @@ ${NEED_MORE_CONTEXT_HINT}` : NEED_MORE_CONTEXT_HINT;
|
|
|
3017
3013
|
sessionID,
|
|
3018
3014
|
query: truncateLogText(decision.query, 200),
|
|
3019
3015
|
reason: decision.reason,
|
|
3020
|
-
refs:
|
|
3016
|
+
refs: extractRefsFromAkmOutput(curated ?? ""),
|
|
3021
3017
|
outcome: curated ? "ok" : "skipped"
|
|
3022
3018
|
});
|
|
3023
3019
|
});
|
|
@@ -3223,7 +3219,7 @@ ${st.hints}` : AKM_HINTS_PREFIX,
|
|
|
3223
3219
|
log(outcome.ok ? "info" : "error", outcome.ok ? "AKM tool call completed" : "AKM tool call failed", {
|
|
3224
3220
|
toolName: spec,
|
|
3225
3221
|
sessionID: context.sessionID,
|
|
3226
|
-
refs:
|
|
3222
|
+
refs: extractRefsFromAkmOutput(outcome.text),
|
|
3227
3223
|
...outcome.ok ? {} : { error: failureMessage(outcome.text) }
|
|
3228
3224
|
});
|
|
3229
3225
|
return outcome;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "akm-opencode-v2",
|
|
3
|
-
"version": "0.10.
|
|
3
|
+
"version": "0.10.261107-beta",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "OpenCode 2 plugin for AKM: the five AKM tools, automatic recall, and automatic session extraction. For OpenCode 1, use akm-opencode.",
|
|
6
6
|
"keywords": [
|
|
@@ -39,7 +39,7 @@
|
|
|
39
39
|
"typecheck": "tsc -p tsconfig.json"
|
|
40
40
|
},
|
|
41
41
|
"dependencies": {
|
|
42
|
-
"akm-cli": "0.10.
|
|
42
|
+
"akm-cli": "0.10.261107-beta"
|
|
43
43
|
},
|
|
44
44
|
"peerDependencies": {
|
|
45
45
|
"@opencode/plugin": "2.1.4",
|