akm-opencode-v2 0.10.261012-beta → 0.10.261013-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/README.md +10 -8
- package/dist/index.js +8 -3
- package/package.json +6 -6
package/README.md
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
# akm-opencode-v2
|
|
2
2
|
|
|
3
|
-
OpenCode **2.x** plugin for [AKM](https://github.com/itlackey/akm) `0.10.
|
|
3
|
+
OpenCode **2.x** plugin for [AKM](https://github.com/itlackey/akm) `0.10.261015-beta`. It registers the five public AKM tools, brings relevant AKM context into the model request automatically, records feedback and learning proposals from what you tell the model, and hands finished turns to AKM's session extraction.
|
|
4
4
|
|
|
5
5
|
Using OpenCode 1.x? Install [`akm-opencode`](../opencode/README.md) instead. Install only the plugin that matches your OpenCode major: each is built against its host's plugin API and neither works in the other.
|
|
6
6
|
|
|
7
7
|
| | `akm-opencode` | `akm-opencode-v2` |
|
|
8
8
|
| --- | --- | --- |
|
|
9
|
-
| OpenCode | 1.x (tested 1.18.34) | 2.x (built
|
|
10
|
-
| Plugin API | `@opencode-ai/plugin` 1.x | `@opencode/plugin` 2.
|
|
11
|
-
| `akm-cli` | `0.10.
|
|
9
|
+
| OpenCode | 1.x (tested 1.18.34) | 2.x (built against 2.1.4; loaded against 2.0.26 and 2.1.4) |
|
|
10
|
+
| Plugin API | `@opencode-ai/plugin` 1.x | `@opencode/plugin` 2.1.4 (Effect entrypoint) |
|
|
11
|
+
| `akm-cli` | `0.10.261015-beta`, exact | `0.10.261015-beta`, exact |
|
|
12
12
|
| Config key | `"plugin": ["akm-opencode"]` | `"plugins": ["akm-opencode-v2@next"]` |
|
|
13
13
|
|
|
14
14
|
This package depends on neither `opencode-ai` nor `@opencode/cli`. Installing it never installs or replaces your `opencode` binary.
|
|
@@ -25,7 +25,7 @@ Add the plugin to your OpenCode 2 configuration (the `plugins` array in `opencod
|
|
|
25
25
|
|
|
26
26
|
Use `@next` (the prerelease channel) or an exact version such as `akm-opencode-v2@0.10.261002-beta`, not the bare name. OpenCode 2 resolves a bare name to `*`, which excludes prereleases, and every published `akm-opencode-v2` version is a prerelease, so `akm-opencode-v2` alone fails with `No matching version found for akm-opencode-v2@*`.
|
|
27
27
|
|
|
28
|
-
`akm-cli@0.10.
|
|
28
|
+
`akm-cli@0.10.261015-beta` is installed with the plugin and is the `akm` it runs (set `AKM_OPENCODE_CLI` to an absolute path to use another executable). `@opencode/plugin` and `effect` are peer dependencies: OpenCode supplies its own copies at load time, so they are external to the published bundle.
|
|
29
29
|
|
|
30
30
|
## Tools
|
|
31
31
|
|
|
@@ -33,7 +33,7 @@ The same five tools, with the same descriptions and argument schemas, as the V1
|
|
|
33
33
|
|
|
34
34
|
## Hook mapping
|
|
35
35
|
|
|
36
|
-
How each V1 responsibility maps onto the OpenCode 2
|
|
36
|
+
How each V1 responsibility maps onto the OpenCode 2 plugin API (built against 2.1.4), as implemented:
|
|
37
37
|
|
|
38
38
|
| V1 responsibility | V2 native mechanism | Behavior |
|
|
39
39
|
| --- | --- | --- |
|
|
@@ -59,7 +59,7 @@ Automatic recall (the `prompt` hook and the session-start curation) calls `curat
|
|
|
59
59
|
|
|
60
60
|
### Write gate
|
|
61
61
|
|
|
62
|
-
OpenCode 2
|
|
62
|
+
OpenCode 2 **does** have a native pre-tool hook that can block: `tool.hook("execute.before")` runs before every tool, may mutate `input`, and a failure with a `Tool.Error` becomes the tool's error result, which the model reads. (Verified against the 2.0.26 binary: an error tagged `_tag: "Tool.Error"` reaches the model with its message intact; an untagged error is reported as a declined call, so the plugin builds the tagged error itself because `@opencode/schema` cannot be imported from a plugin.) The gate is therefore ported with the V1 policy ([`opencode-shared/write-gate.ts`](../opencode-shared/write-gate.ts)): when a file the session **read** declares a format (`apiVersion`, `$schema`, a yaml-language-server pragma, an XML default namespace) that the bundle documents, and the session has not opened that asset, the first `edit`/`write` to the file is blocked once with a message naming the asset; repeating it proceeds. Same as V1, the default mode is `observe` (ledger only, nothing blocked); `AKM_WRITE_GATE=enforce` blocks and `off` disables it, and every watched call writes exactly one `write_gate` event with a named reason.
|
|
63
63
|
|
|
64
64
|
Differences from V1: the tools are `edit {path, oldString, newString}`, `write {path, content}` and, on `gpt-*` models, `patch {patchText}` (V1: `filePath` and `apply_patch`). As in V1 the gate cannot resolve a file from a patch envelope, so `patch` is a typed skip with one warning. A `read` result carries the file's raw text as structured `output.content`, which the gate scans directly instead of V1's numbered `<content>` rendering.
|
|
65
65
|
|
|
@@ -104,7 +104,9 @@ Round 1, with recall still going through the CLI: verified against the real bina
|
|
|
104
104
|
|
|
105
105
|
Round 2 (same binary, built `dist/` loaded through a re-exporting plugin directory, mock model, stub `akm`): the shell hook exports `AKM_PROJECT`, `AKM_BUNDLE_DIR` and `AKM_PLUGIN_VERSION` to a model-issued `shell` call; `edit` before an opened asset is blocked in `enforce` and the model receives the gate message; a prompt of "Remember that ..." runs `akm proposal new` and logs `AKM learning proposal submitted`; `akm_show` followed by "thanks, that worked" runs `akm feedback knowledge/inkwell --positive`; the pending count is requested. **In-process recall cannot be exercised for real yet** because no published `akm-cli` provides `akm-cli/api`: against the real binary the plugin logged `AKM recall failed` and carried on, and recall through the API is covered by tests against a fake that follows the contract.
|
|
106
106
|
|
|
107
|
-
|
|
107
|
+
A subagent's child session (`session.created` with a `parentID`) is part of its parent's work and its prompt is model-written, so the plugin runs no session-start curation, recall, learning signals or extraction for it; the parent's extraction covers it.
|
|
108
|
+
|
|
109
|
+
Not verified against the real binary: a real model's use of the tools, compaction and retry behaviour, `session.deleted` cleanup, and installing the package from the npm registry (it is not published; the plugin was loaded from a directory that re-exports the installed `dist/`). `tests/opencode-v2-plugin.test.ts` covers these paths with a fake host context and a fake `akm`.
|
|
108
110
|
|
|
109
111
|
## Locking down destructive commands
|
|
110
112
|
|
package/dist/index.js
CHANGED
|
@@ -2822,6 +2822,7 @@ function createCore(options) {
|
|
|
2822
2822
|
const now = options.now ?? Date.now;
|
|
2823
2823
|
const recallWaitMs = options.recallWaitMs ?? Math.max(0, Number(process.env.AKM_RECALL_WAIT_MS ?? "3000") || 0);
|
|
2824
2824
|
const sessions = new Map;
|
|
2825
|
+
const childSessions = new Set;
|
|
2825
2826
|
const resolveCommand = options.resolveCommand ?? (() => resolveAkmCommand(options.moduleUrl, PACKAGE_NAME));
|
|
2826
2827
|
const extractSession = options.extract ?? spawnSessionExtract;
|
|
2827
2828
|
let disposed = false;
|
|
@@ -2883,6 +2884,7 @@ function createCore(options) {
|
|
|
2883
2884
|
return existing;
|
|
2884
2885
|
}
|
|
2885
2886
|
function dropSession(sessionID) {
|
|
2887
|
+
childSessions.delete(sessionID);
|
|
2886
2888
|
const existing = sessions.get(sessionID);
|
|
2887
2889
|
clearGateSession(sessionID);
|
|
2888
2890
|
tracker.clear(sessionID);
|
|
@@ -2981,7 +2983,7 @@ function createCore(options) {
|
|
|
2981
2983
|
}
|
|
2982
2984
|
async function onPrompt(sessionID, promptText) {
|
|
2983
2985
|
try {
|
|
2984
|
-
if (disposed)
|
|
2986
|
+
if (disposed || childSessions.has(sessionID))
|
|
2985
2987
|
return;
|
|
2986
2988
|
const text = unwrapJsonStringPrompt(promptText);
|
|
2987
2989
|
if (!text)
|
|
@@ -3075,7 +3077,7 @@ ${st.hints}` : AKM_HINTS_PREFIX,
|
|
|
3075
3077
|
st.workflow = workflowRaw && summarizeActiveWorkflows(workflowRaw) || undefined;
|
|
3076
3078
|
}
|
|
3077
3079
|
function maybeExtract(sessionID) {
|
|
3078
|
-
if (disposed || !autoMemoryEnabled())
|
|
3080
|
+
if (disposed || !autoMemoryEnabled() || childSessions.has(sessionID))
|
|
3079
3081
|
return;
|
|
3080
3082
|
const st = state(sessionID);
|
|
3081
3083
|
const at = now();
|
|
@@ -3169,7 +3171,10 @@ ${st.hints}` : AKM_HINTS_PREFIX,
|
|
|
3169
3171
|
return;
|
|
3170
3172
|
switch (event.type) {
|
|
3171
3173
|
case "session.created":
|
|
3172
|
-
|
|
3174
|
+
if (typeof data.parentID === "string")
|
|
3175
|
+
childSessions.add(sessionID);
|
|
3176
|
+
else
|
|
3177
|
+
await onSessionCreated(sessionID);
|
|
3173
3178
|
break;
|
|
3174
3179
|
case "session.execution.succeeded":
|
|
3175
3180
|
maybeExtract(sessionID);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "akm-opencode-v2",
|
|
3
|
-
"version": "0.10.
|
|
3
|
+
"version": "0.10.261013-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,16 +39,16 @@
|
|
|
39
39
|
"typecheck": "tsc -p tsconfig.json"
|
|
40
40
|
},
|
|
41
41
|
"dependencies": {
|
|
42
|
-
"akm-cli": "0.10.
|
|
42
|
+
"akm-cli": "0.10.261015-beta"
|
|
43
43
|
},
|
|
44
44
|
"peerDependencies": {
|
|
45
|
-
"@opencode/plugin": "2.
|
|
46
|
-
"effect": "4.0.
|
|
45
|
+
"@opencode/plugin": "2.1.4",
|
|
46
|
+
"effect": "4.0.1"
|
|
47
47
|
},
|
|
48
48
|
"devDependencies": {
|
|
49
|
-
"@opencode/plugin": "2.
|
|
49
|
+
"@opencode/plugin": "2.1.4",
|
|
50
50
|
"@types/node": "^26.1.1",
|
|
51
|
-
"effect": "4.0.
|
|
51
|
+
"effect": "4.0.1",
|
|
52
52
|
"typescript": "^5.8.3"
|
|
53
53
|
}
|
|
54
54
|
}
|