@skillstate/opencode 2.0.1 → 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.
- package/README.md +103 -0
- package/package.json +1 -1
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
|
+
[](https://www.npmjs.com/package/@skillstate/opencode)
|
|
8
|
+
[](https://www.npmjs.com/package/@skillstate/opencode)
|
|
9
|
+
[](https://github.com/vitalykuzyaev/skillstate)
|
|
10
|
+
[](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
|