@skillstate/opencode 2.0.0 → 2.0.2

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.
Files changed (2) hide show
  1. package/README.md +103 -0
  2. package/package.json +4 -2
package/README.md ADDED
@@ -0,0 +1,103 @@
1
+ <div align="center">
2
+
3
+ # @skillstate/opencode
4
+
5
+ **OpenCode platform adapter for the @skillstate/core runtime — the only case with real O(1) prompt economy via history trimming.**
6
+
7
+ [![npm version](https://img.shields.io/npm/v/@skillstate/opencode)](https://www.npmjs.com/package/@skillstate/opencode)
8
+ [![node](https://img.shields.io/node/v/@skillstate/opencode)](https://www.npmjs.com/package/@skillstate/opencode)
9
+ [![Tests](https://img.shields.io/badge/tests-755%20passing-brightgreen)](https://github.com/vitalykuzyaev/skillstate)
10
+ [![License: MIT](https://img.shields.io/badge/license-MIT-blue)](https://github.com/vitalykuzyaev/skillstate/blob/main/LICENSE)
11
+
12
+ </div>
13
+
14
+ ---
15
+
16
+ `@skillstate/opencode` integrates the paper-exact runtime
17
+ ([`@skillstate/core`](../core)) into **OpenCode**. It emits a `SKILL.md` so the
18
+ host discovers the skill, and a plugin that hooks
19
+ `experimental.chat.messages.transform` to **trim history before every LLM
20
+ call** — dropping old messages and injecting only the state, which is genuine
21
+ **O(1)** prompt footprint.
22
+
23
+ > **@non-paper** — no adapters exist in arXiv 2608.26263v3. This adapter is an
24
+ > additive integration, not part of the paper.
25
+
26
+ ## Installation
27
+
28
+ ```bash
29
+ npm i @skillstate/core @skillstate/opencode
30
+ ```
31
+
32
+ Requires Node.js >= 20. TypeScript types are bundled.
33
+
34
+ ## Quick start
35
+
36
+ ```ts
37
+ import { OpenCodeAdapter } from '@skillstate/opencode';
38
+ import { INTERCODE_CTF_SPEC } from '@skillstate/core/schemas';
39
+
40
+ const adapter = new OpenCodeAdapter();
41
+
42
+ // SKILL.md with frontmatter (name/description/version) + an
43
+ // execution_context block pointing at the persisted state file:
44
+ const skillMd = adapter.generateSkillMd(INTERCODE_CTF_SPEC, './.skillstate.json');
45
+
46
+ // Plugin with real O(1) history trimming via experimental.chat.messages.transform:
47
+ const plugin = adapter.generatePluginCode('./.skillstate.json');
48
+
49
+ // Default keeps the last 3 non-system messages + state injection.
50
+ // Configure history depth:
51
+ const plugin2 = adapter.generatePluginCode('./.skillstate.json', {
52
+ maxHistoryMessages: 5, // keep last 5 non-system messages
53
+ });
54
+
55
+ // Persist the plugin to disk atomically:
56
+ const saved = await adapter.savePluginCode(
57
+ './skillstate.plugin.ts',
58
+ './.skillstate.json',
59
+ { maxHistoryMessages: 5 },
60
+ );
61
+ ```
62
+
63
+ ## API / Exports
64
+
65
+ Root path `@skillstate/opencode` exports one thing: `OpenCodeAdapter`.
66
+
67
+ - `new OpenCodeAdapter()` — implements `PlatformAdapter` (`name = 'opencode'`).
68
+ - `generateSkillMd(spec, statePath?): string` — a `SKILL.md` body with
69
+ frontmatter and a state-based process description.
70
+ - `generatePluginCode(statePath, options?): string` — an OpenCode plugin
71
+ (`options.maxHistoryMessages`, default 3). Hooks:
72
+ `experimental.chat.messages.transform` (real history trimming),
73
+ `experimental.session.compacting` (inject state into compaction context),
74
+ `tool.execute.after` (persist `state_patch` to disk).
75
+ - `savePluginCode(target, statePath, options?): Promise<string>` — writes the
76
+ plugin atomically and returns the destination.
77
+ - `injectState(state, spec): string` / `formatPrompt(state, observation, spec): string`.
78
+ - `extractPatch(response): StatePatch | null` / `extractAction(response): string | null`.
79
+
80
+ Both `generatePluginCode`/`savePluginCode` accept a raw path (legacy) or a
81
+ `{ root, name }` ref confined by `resolveStatePath` (`..` escapes throw).
82
+
83
+ ## Notes
84
+
85
+ - **Real O(1).** Unlike Claude Code and Codex, OpenCode exposes
86
+ `experimental.chat.messages.transform`, so the plugin drops old messages
87
+ instead of just hiding them — only the last N non-system messages plus an
88
+ injected state message reach the LLM.
89
+ - The generated plugin is a self-contained ESM/TS module; it reads and writes
90
+ the state file directly and applies the paper ⊕ null-deletion merge.
91
+ - Depends on [`@skillstate/core`](../core) for `PromptTransformer`,
92
+ `atomicWriteFile`, and `resolveStatePath`.
93
+
94
+ ## Related
95
+
96
+ - Paper: [arXiv:2608.26263](https://arxiv.org/abs/2608.26263).
97
+ - Core runtime: [`@skillstate/core`](../core).
98
+ - [`state.md`](../../state.md) — design notes.
99
+ - Other adapters: `@skillstate/claude`, `@skillstate/codex`, `@skillstate/mcp`.
100
+
101
+ ## License
102
+
103
+ [MIT](LICENSE) © 2026 Vitaly Kuzyaev
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@skillstate/opencode",
3
- "version": "2.0.0",
3
+ "version": "2.0.2",
4
4
  "description": "OpenCode platform adapter for the skillstate runtime.",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -12,7 +12,9 @@
12
12
  },
13
13
  "./package.json": "./package.json"
14
14
  },
15
- "files": ["dist"],
15
+ "files": [
16
+ "dist"
17
+ ],
16
18
  "sideEffects": false,
17
19
  "engines": {
18
20
  "node": ">=20"