akm-opencode-v2 0.10.261011-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 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.26101002-alpha`. 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.
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 and loaded against 2.0.26) |
10
- | Plugin API | `@opencode-ai/plugin` 1.x | `@opencode/plugin` 2.0.26 (Effect entrypoint) |
11
- | `akm-cli` | `0.10.26101002-alpha`, exact | `0.10.26101002-alpha`, exact |
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.26101002-alpha` 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.
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.0.26 plugin API, as implemented:
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.0.26 **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.
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
- Not verified against the real binary: a real model's use of the tools, compaction and retry behaviour, subagent sessions, `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`.
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
- await onSessionCreated(sessionID);
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.261011-beta",
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.261012-beta"
42
+ "akm-cli": "0.10.261015-beta"
43
43
  },
44
44
  "peerDependencies": {
45
- "@opencode/plugin": "2.0.26",
46
- "effect": "4.0.0-rc.112"
45
+ "@opencode/plugin": "2.1.4",
46
+ "effect": "4.0.1"
47
47
  },
48
48
  "devDependencies": {
49
- "@opencode/plugin": "2.0.26",
49
+ "@opencode/plugin": "2.1.4",
50
50
  "@types/node": "^26.1.1",
51
- "effect": "4.0.0-rc.112",
51
+ "effect": "4.0.1",
52
52
  "typescript": "^5.8.3"
53
53
  }
54
54
  }