@skillstate/opencode 2.2.1 → 3.0.0
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 +86 -91
- package/dist/index.d.ts +28 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +24 -3
- package/dist/index.js.map +1 -1
- package/dist/opencode-adapter.d.ts +9 -46
- package/dist/opencode-adapter.d.ts.map +1 -1
- package/dist/opencode-adapter.js +1 -64
- package/dist/opencode-adapter.js.map +1 -1
- package/dist/plugin.d.ts +82 -72
- package/dist/plugin.d.ts.map +1 -1
- package/dist/plugin.js +138 -201
- package/dist/plugin.js.map +1 -1
- package/dist/session-registry.d.ts +148 -0
- package/dist/session-registry.d.ts.map +1 -0
- package/dist/session-registry.js +236 -0
- package/dist/session-registry.js.map +1 -0
- package/dist/state-store.d.ts +126 -0
- package/dist/state-store.d.ts.map +1 -0
- package/dist/state-store.js +186 -0
- package/dist/state-store.js.map +1 -0
- package/dist/system-hint.d.ts +62 -0
- package/dist/system-hint.d.ts.map +1 -0
- package/dist/system-hint.js +87 -0
- package/dist/system-hint.js.map +1 -0
- package/dist/tools.d.ts +114 -0
- package/dist/tools.d.ts.map +1 -0
- package/dist/tools.js +334 -0
- package/dist/tools.js.map +1 -0
- package/package.json +3 -2
- package/dist/plugin-types.d.ts +0 -64
- package/dist/plugin-types.d.ts.map +0 -1
- package/dist/plugin-types.js +0 -8
- package/dist/plugin-types.js.map +0 -1
package/README.md
CHANGED
|
@@ -14,11 +14,15 @@
|
|
|
14
14
|
---
|
|
15
15
|
|
|
16
16
|
`@skillstate/opencode` integrates the paper-exact runtime
|
|
17
|
-
([`@skillstate/core`](../core)) into **OpenCode**.
|
|
18
|
-
|
|
17
|
+
([`@skillstate/core`](../core)) into **OpenCode**. The integration is the
|
|
18
|
+
npm plugin `SkillStatePlugin` itself, loaded directly from the PROJECT
|
|
19
|
+
`opencode.json(c)` (`"plugin": ["@skillstate/opencode"]`): it hooks
|
|
19
20
|
`experimental.chat.messages.transform` to **trim history before every LLM
|
|
20
21
|
call** — dropping old messages and injecting only the state, which is genuine
|
|
21
|
-
**O(1)** prompt footprint.
|
|
22
|
+
**O(1)** prompt footprint. The plugin is project-local and inert when the
|
|
23
|
+
project has no `.skillstate/` state, and OpenCode reads the shared project
|
|
24
|
+
`.claude/skills/skillstate/SKILL.md` too (Claude-compatible skill discovery),
|
|
25
|
+
so one host-neutral skill file serves both hosts.
|
|
22
26
|
|
|
23
27
|
> **@non-paper** — no adapters exist in arXiv 2608.26263v3. This adapter is an
|
|
24
28
|
> additive integration, not part of the paper.
|
|
@@ -34,89 +38,77 @@ Requires Node.js >= 20. TypeScript types are bundled.
|
|
|
34
38
|
## Quick start
|
|
35
39
|
|
|
36
40
|
```ts
|
|
37
|
-
import { OpenCodeAdapter } from '@skillstate/opencode';
|
|
38
|
-
import { INTERCODE_CTF_SPEC } from '@skillstate/core/schemas';
|
|
41
|
+
import { OpenCodeAdapter, SkillStatePlugin, createSkillStatePlugin } from '@skillstate/opencode';
|
|
39
42
|
|
|
40
43
|
const adapter = new OpenCodeAdapter();
|
|
41
44
|
|
|
42
|
-
//
|
|
43
|
-
//
|
|
44
|
-
const
|
|
45
|
-
|
|
46
|
-
//
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
//
|
|
52
|
-
//
|
|
53
|
-
|
|
54
|
-
maxHistoryMessages: 5, // keep last 5 non-system messages
|
|
55
|
-
});
|
|
56
|
-
|
|
57
|
-
// Persist the plugin to disk atomically:
|
|
58
|
-
const saved = await adapter.savePluginCode(
|
|
59
|
-
'./skillstate.plugin.ts',
|
|
60
|
-
{ maxHistoryMessages: 5 },
|
|
61
|
-
);
|
|
45
|
+
// The plugin OpenCode loads from "plugin": ["@skillstate/opencode"] —
|
|
46
|
+
// the ready-made instance (the default export carries the same function):
|
|
47
|
+
const plugin = SkillStatePlugin;
|
|
48
|
+
|
|
49
|
+
// Need a custom configuration? Build your own instance:
|
|
50
|
+
const configured = createSkillStatePlugin({ maxHistoryMessages: 5 });
|
|
51
|
+
|
|
52
|
+
// Real O(1) history trimming via experimental.chat.messages.transform,
|
|
53
|
+
// compaction context injection via experimental.session.compacting, and
|
|
54
|
+
// state persistence via tool.execute.after. The state path is resolved per
|
|
55
|
+
// session from the host cwd inside the plugin — no baked path, and every
|
|
56
|
+
// state-touching hook returns early when the project has no state file.
|
|
62
57
|
```
|
|
63
58
|
|
|
64
59
|
## Install into OpenCode (host)
|
|
65
60
|
|
|
66
61
|
Tested end-to-end against OpenCode ≥ 1.17 (`@opencode-ai/plugin` 1.15.x
|
|
67
|
-
hook contracts).
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
```ts
|
|
72
|
-
// scripts/gen-plugin.mjs (run with: node scripts/gen-plugin.mjs)
|
|
73
|
-
import { OpenCodeAdapter } from '@skillstate/opencode';
|
|
74
|
-
import { writeFileSync } from 'node:fs';
|
|
75
|
-
|
|
76
|
-
const adapter = new OpenCodeAdapter();
|
|
77
|
-
const code = adapter.generatePluginCode({ maxHistoryMessages: 3 });
|
|
78
|
-
writeFileSync('/abs/path/to/skillstate.plugin.ts', code);
|
|
79
|
-
```
|
|
80
|
-
|
|
81
|
-
Put the generated `skillstate.plugin.ts` anywhere stable (absolute path is
|
|
82
|
-
safest), e.g. `<project>/.opencode-runtime/skillstate.plugin.ts`. The plugin
|
|
83
|
-
must be able to resolve `@skillstate/opencode` at load time (install it in
|
|
84
|
-
the project or globally) — hook logic lives in that package.
|
|
62
|
+
hook contracts). Everything below is PROJECT-LOCAL — nothing is written
|
|
63
|
+
into `~/.config/opencode`. The one-command path is
|
|
64
|
+
`npm i -g @skillstate/cli && skillstate init` in the project (it performs
|
|
65
|
+
steps 1–3 for every detected host); the manual equivalent:
|
|
85
66
|
|
|
86
|
-
**
|
|
87
|
-
|
|
67
|
+
**1. Register the npm plugin in the project `opencode.jsonc|json`** — add
|
|
68
|
+
`"@skillstate/opencode"` to the `plugin` array (npm entries are
|
|
69
|
+
auto-installed by OpenCode via Bun; no generated plugin file exists):
|
|
88
70
|
|
|
89
|
-
```
|
|
71
|
+
```jsonc
|
|
90
72
|
{
|
|
91
|
-
"
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
"cmd_summary": "initialized"
|
|
73
|
+
"plugin": [
|
|
74
|
+
"@ai-sdk/anthropic",
|
|
75
|
+
"@skillstate/opencode"
|
|
76
|
+
]
|
|
96
77
|
}
|
|
97
78
|
```
|
|
98
79
|
|
|
99
|
-
**
|
|
100
|
-
`
|
|
101
|
-
TypeScript is supported because plugins load under Bun):
|
|
80
|
+
**2. Register the MCP server** in the same config's `mcp` object —
|
|
81
|
+
`skillstate init` writes exactly this entry (`npx -y @skillstate/mcp@^3`):
|
|
102
82
|
|
|
103
83
|
```jsonc
|
|
104
84
|
{
|
|
105
|
-
"
|
|
106
|
-
"
|
|
107
|
-
|
|
108
|
-
|
|
85
|
+
"mcp": {
|
|
86
|
+
"skillstate": {
|
|
87
|
+
"type": "local",
|
|
88
|
+
"command": ["npx", "-y", "@skillstate/mcp@^3"],
|
|
89
|
+
"enabled": true
|
|
90
|
+
}
|
|
91
|
+
}
|
|
109
92
|
}
|
|
110
93
|
```
|
|
111
94
|
|
|
112
|
-
**
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
95
|
+
**3. Share the project skill** — one host-neutral
|
|
96
|
+
`.claude/skills/skillstate/SKILL.md` (written by `skillstate init`) serves
|
|
97
|
+
both OpenCode and Claude Code: OpenCode reads project `.claude/skills/` via
|
|
98
|
+
Claude-compatible discovery. The skill's frontmatter is exactly `name` +
|
|
99
|
+
`description`; the body describes the state-based execution protocol and
|
|
100
|
+
names no host-specific hook/plugin events — the npm plugin injects the
|
|
101
|
+
current state into context every turn, and everything else goes through the
|
|
102
|
+
host-agnostic skillstate MCP tools.
|
|
103
|
+
|
|
104
|
+
**4. Run `skillstate init` in the project** (or let it do all of the above
|
|
105
|
+
at once) to create the state envelope `./.skillstate/skillstate.json` —
|
|
106
|
+
the plugin resolves it from the session cwd and stays inert until it
|
|
107
|
+
exists.
|
|
108
|
+
|
|
109
|
+
Verify with `opencode debug config` (the plugin entry shows under `plugin`,
|
|
110
|
+
`mcp.skillstate` under `mcp`) and `opencode debug skill` (your skill is
|
|
111
|
+
listed). Hook notes for OpenCode ≥ 1.17:
|
|
120
112
|
`messages.transform` receives `{ info: Message, parts: Part[] }` entries and
|
|
121
113
|
must mutate `output.messages` **in place**; the plugin injects state as a
|
|
122
114
|
synthetic `{ info, parts }` message.
|
|
@@ -125,30 +117,29 @@ synthetic `{ info, parts }` message.
|
|
|
125
117
|
|
|
126
118
|
Root path `@skillstate/opencode` exports the adapter and the static plugin:
|
|
127
119
|
|
|
128
|
-
- `new OpenCodeAdapter()` — implements `PlatformAdapter` (`name = 'opencode'`)
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
`experimental.chat.messages.transform` (real history trimming),
|
|
136
|
-
`experimental.session.compacting` (inject state into compaction context),
|
|
137
|
-
`tool.execute.after` (persist `state_patch` to disk).
|
|
120
|
+
- `new OpenCodeAdapter()` — implements `PlatformAdapter` (`name = 'opencode'`);
|
|
121
|
+
a pure prompt/parse surface (`injectState`, `extractPatch`,
|
|
122
|
+
`extractAction`, `formatPrompt`) — host glue is the npm plugin itself,
|
|
123
|
+
not generated code.
|
|
124
|
+
- `SkillStatePlugin` (+ default export) — the ready-made plugin instance
|
|
125
|
+
OpenCode loads from `"plugin": ["@skillstate/opencode"]`; identical to
|
|
126
|
+
`createSkillStatePlugin()`.
|
|
138
127
|
- `createSkillStatePlugin({ maxHistoryMessages? })` — the static plugin
|
|
139
128
|
factory (single source of truth for the hook logic); state is resolved from
|
|
140
129
|
the session cwd on every hook call via
|
|
141
|
-
`resolveStatePathForCwd(process.cwd(), os.homedir())
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
130
|
+
`resolveStatePathForCwd(process.cwd(), os.homedir(), agentId)`, and every
|
|
131
|
+
state-touching hook returns early when the state file does not exist
|
|
132
|
+
(hooks never create state files). Hooks:
|
|
133
|
+
`experimental.chat.messages.transform` (real history trimming),
|
|
134
|
+
`experimental.session.compacting` (inject state into compaction context),
|
|
135
|
+
`tool.execute.after` (persist `state_patch` to disk).
|
|
136
|
+
- `resolveStatePathForCwd(cwd, home?, agentId?): string` — the per-project
|
|
137
|
+
state path resolution (pure path arithmetic, no filesystem access).
|
|
138
|
+
- `pluginAgentId(input, messages?)` / `scopedAgentId(agentId)` /
|
|
139
|
+
`registerSessionParent(sessionId, parentId)` / `resetSessionParents()` —
|
|
140
|
+
the agent-scope plumbing (session id → `agents/` directory name).
|
|
147
141
|
- `readSkillState` / `saveSkillState` / `mergePatch` / `extractPatch` — the
|
|
148
142
|
plugin's state helpers, shared by the static plugin.
|
|
149
|
-
- `savePluginCode(target, options?): Promise<string>` — writes the plugin
|
|
150
|
-
atomically and returns the destination. `target` accepts a raw path or a
|
|
151
|
-
`{ root, name }` ref confined by `resolveStatePath` (`..` escapes throw).
|
|
152
143
|
- `injectState(state, spec): string` / `formatPrompt(state, observation, spec): string`.
|
|
153
144
|
- `extractPatch(response): StatePatch | null` / `extractAction(response): string | null`.
|
|
154
145
|
|
|
@@ -159,12 +150,16 @@ Root path `@skillstate/opencode` exports the adapter and the static plugin:
|
|
|
159
150
|
`experimental.chat.messages.transform`, so the plugin drops old messages
|
|
160
151
|
instead of just hiding them — only the last N non-system messages plus an
|
|
161
152
|
injected state message reach the LLM.
|
|
162
|
-
- The
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
session cwd
|
|
153
|
+
- **The plugin is the npm package, not generated code.** Hook logic lives
|
|
154
|
+
only in `src/plugin.ts` — nothing is emitted to disk by an installer, so
|
|
155
|
+
there are no generated files to edit. **WHERE STATE LIVES** (each opencode
|
|
156
|
+
session reads AND writes the same path within its cwd — no cross-file
|
|
157
|
+
surprises):
|
|
158
|
+
- main session: `<cwd>/.skillstate/skillstate.json`
|
|
159
|
+
- sub-agent session (Task sub-agents carry `parentID` on the session):
|
|
160
|
+
`<cwd>/.skillstate/agents/<parentPrefix>-<sessionPrefix>/skillstate.json`
|
|
161
|
+
- a session started in `$HOME`: the global bucket
|
|
162
|
+
`~/.skillstate/global/...` with the same main/sub split.
|
|
168
163
|
- Depends on [`@skillstate/core`](../core) for `PromptTransformer`,
|
|
169
164
|
`atomicWriteFile`, and `resolveStatePath`.
|
|
170
165
|
|
package/dist/index.d.ts
CHANGED
|
@@ -1,3 +1,29 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
/**
|
|
2
|
+
* `@skillstate/opencode` — the OpenCode v2 plugin package.
|
|
3
|
+
*
|
|
4
|
+
* The default export IS the plugin definition: OpenCode loads
|
|
5
|
+
* `opencode.json` → `"plugins": ["@skillstate/opencode"]`, imports this
|
|
6
|
+
* module and calls `setup(ctx)`. Everything else is exported for tests and
|
|
7
|
+
* for embedders that want the pieces without the plugin lifecycle.
|
|
8
|
+
*
|
|
9
|
+
* See `plugin.ts` for the design contract, in particular the rule that this
|
|
10
|
+
* package never mutates `event.messages`.
|
|
11
|
+
*/
|
|
12
|
+
export { SkillStatePlugin, PLUGIN_ID, default } from './plugin.js';
|
|
13
|
+
/**
|
|
14
|
+
* The paper-exact `PlatformAdapter` (arXiv 2608.26263v3 A.4 prompt format).
|
|
15
|
+
* Kept as the research surface used by the benchmark; it is NOT the host
|
|
16
|
+
* integration and nothing in the plugin path calls it. In particular its
|
|
17
|
+
* `injectState` still emits the paper's `STATE_PATCH_CONTRACT`, which is
|
|
18
|
+
* exactly the instruction pattern the v2 plugin avoids.
|
|
19
|
+
*/
|
|
20
|
+
export { OpenCodeAdapter } from './opencode-adapter.js';
|
|
21
|
+
export { SessionRegistry, stateScopeFor, DEFAULT_SESSION_TTL_MS, } from './session-registry.js';
|
|
22
|
+
export type { SessionRecord, SessionRegistryOptions } from './session-registry.js';
|
|
23
|
+
export { ProjectStateStore, diffDocuments, mergeDocuments, statePathFor, } from './state-store.js';
|
|
24
|
+
export type { StateChanges, StateDocument, ProjectStateStoreOptions, } from './state-store.js';
|
|
25
|
+
export { buildStateHint, renderStateForHint, ADVERTISED_TOOLS, MAX_INLINE_STATE_CHARS, } from './system-hint.js';
|
|
26
|
+
export type { StateHintOptions } from './system-hint.js';
|
|
27
|
+
export { registerTools, normalizePatch, MAX_PATCH_BYTES } from './tools.js';
|
|
28
|
+
export type { MergeValue, ReadValue, ToolDeps, ToolError, ToolOk, ToolResult, UpdateValue, } from './tools.js';
|
|
3
29
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,EAAE,gBAAgB,EAAE,SAAS,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AACnE;;;;;;GAMG;AACH,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AACxD,OAAO,EACL,eAAe,EACf,aAAa,EACb,sBAAsB,GACvB,MAAM,uBAAuB,CAAC;AAC/B,YAAY,EAAE,aAAa,EAAE,sBAAsB,EAAE,MAAM,uBAAuB,CAAC;AACnF,OAAO,EACL,iBAAiB,EACjB,aAAa,EACb,cAAc,EACd,YAAY,GACb,MAAM,kBAAkB,CAAC;AAC1B,YAAY,EACV,YAAY,EACZ,aAAa,EACb,wBAAwB,GACzB,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EACL,cAAc,EACd,kBAAkB,EAClB,gBAAgB,EAChB,sBAAsB,GACvB,MAAM,kBAAkB,CAAC;AAC1B,YAAY,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AACzD,OAAO,EAAE,aAAa,EAAE,cAAc,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAC5E,YAAY,EACV,UAAU,EACV,SAAS,EACT,QAAQ,EACR,SAAS,EACT,MAAM,EACN,UAAU,EACV,WAAW,GACZ,MAAM,YAAY,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -1,4 +1,25 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
/**
|
|
2
|
+
* `@skillstate/opencode` — the OpenCode v2 plugin package.
|
|
3
|
+
*
|
|
4
|
+
* The default export IS the plugin definition: OpenCode loads
|
|
5
|
+
* `opencode.json` → `"plugins": ["@skillstate/opencode"]`, imports this
|
|
6
|
+
* module and calls `setup(ctx)`. Everything else is exported for tests and
|
|
7
|
+
* for embedders that want the pieces without the plugin lifecycle.
|
|
8
|
+
*
|
|
9
|
+
* See `plugin.ts` for the design contract, in particular the rule that this
|
|
10
|
+
* package never mutates `event.messages`.
|
|
11
|
+
*/
|
|
12
|
+
export { SkillStatePlugin, PLUGIN_ID, default } from './plugin.js';
|
|
13
|
+
/**
|
|
14
|
+
* The paper-exact `PlatformAdapter` (arXiv 2608.26263v3 A.4 prompt format).
|
|
15
|
+
* Kept as the research surface used by the benchmark; it is NOT the host
|
|
16
|
+
* integration and nothing in the plugin path calls it. In particular its
|
|
17
|
+
* `injectState` still emits the paper's `STATE_PATCH_CONTRACT`, which is
|
|
18
|
+
* exactly the instruction pattern the v2 plugin avoids.
|
|
19
|
+
*/
|
|
20
|
+
export { OpenCodeAdapter } from './opencode-adapter.js';
|
|
21
|
+
export { SessionRegistry, stateScopeFor, DEFAULT_SESSION_TTL_MS, } from './session-registry.js';
|
|
22
|
+
export { ProjectStateStore, diffDocuments, mergeDocuments, statePathFor, } from './state-store.js';
|
|
23
|
+
export { buildStateHint, renderStateForHint, ADVERTISED_TOOLS, MAX_INLINE_STATE_CHARS, } from './system-hint.js';
|
|
24
|
+
export { registerTools, normalizePatch, MAX_PATCH_BYTES } from './tools.js';
|
|
4
25
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,EAAE,gBAAgB,EAAE,SAAS,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AACnE;;;;;;GAMG;AACH,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AACxD,OAAO,EACL,eAAe,EACf,aAAa,EACb,sBAAsB,GACvB,MAAM,uBAAuB,CAAC;AAE/B,OAAO,EACL,iBAAiB,EACjB,aAAa,EACb,cAAc,EACd,YAAY,GACb,MAAM,kBAAkB,CAAC;AAM1B,OAAO,EACL,cAAc,EACd,kBAAkB,EAClB,gBAAgB,EAChB,sBAAsB,GACvB,MAAM,kBAAkB,CAAC;AAE1B,OAAO,EAAE,aAAa,EAAE,cAAc,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC"}
|
|
@@ -4,21 +4,17 @@
|
|
|
4
4
|
* Bridges the skillstate runtime into OpenCode via:
|
|
5
5
|
* - Prompts formatted with the skillstate XML-style skill envelope
|
|
6
6
|
* (delegates to PromptTransformer.formatForOpenCode).
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
* -
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
7
|
+
*
|
|
8
|
+
* Host glue is NO LONGER GENERATED by this adapter:
|
|
9
|
+
* - the plugin is the npm package `@skillstate/opencode` itself, loaded
|
|
10
|
+
* directly from the project `opencode.json`
|
|
11
|
+
* `"plugin": ["@skillstate/opencode"]` (see `SkillStatePlugin` /
|
|
12
|
+
* `createSkillStatePlugin` in `src/plugin.ts` — project-local and inert
|
|
13
|
+
* when the project has no skillstate state);
|
|
14
|
+
* - skill markdown (SKILL.md) generation is host-neutral and lives in the
|
|
15
|
+
* CLI, not in the platform adapters.
|
|
14
16
|
*/
|
|
15
17
|
import type { SkillState, StatePatch, ProceduralSpec, Observation, PlatformAdapter } from '@skillstate/core';
|
|
16
|
-
import type { StatePathRef } from '@skillstate/core';
|
|
17
|
-
/** Options for {@link OpenCodeAdapter.generatePluginCode}. */
|
|
18
|
-
export interface GeneratePluginOptions {
|
|
19
|
-
/** Non-system messages kept by the plugin (default 3). */
|
|
20
|
-
maxHistoryMessages?: number;
|
|
21
|
-
}
|
|
22
18
|
/**
|
|
23
19
|
* OpenCode platform adapter (@non-paper; see module doc).
|
|
24
20
|
*/
|
|
@@ -46,38 +42,5 @@ export declare class OpenCodeAdapter implements PlatformAdapter {
|
|
|
46
42
|
* Paper-exact callers use `PromptTransformer.formatPaper` (Appendix A.4).
|
|
47
43
|
*/
|
|
48
44
|
formatPrompt(state: SkillState, observation: Observation, spec: ProceduralSpec): string;
|
|
49
|
-
/**
|
|
50
|
-
* Generate a SKILL.md suitable for OpenCode's skill system.
|
|
51
|
-
*
|
|
52
|
-
* The frontmatter carries the skill name/description plus an
|
|
53
|
-
* execution_context block pointing at the persisted state file; the body
|
|
54
|
-
* describes the state-based execution process. History is discarded by
|
|
55
|
-
* the plugin's `messages.transform` hook — the LLM sees only the state.
|
|
56
|
-
*/
|
|
57
|
-
generateSkillMd(spec: ProceduralSpec, statePath?: string): string;
|
|
58
|
-
/**
|
|
59
|
-
* Generate an OpenCode plugin file.
|
|
60
|
-
*
|
|
61
|
-
* The plugin is ALWAYS a thin loader in per-project resolver mode: the
|
|
62
|
-
* state path is computed from the session cwd on every hook call inside
|
|
63
|
-
* the static plugin (`resolveStatePathForCwd(process.cwd(),
|
|
64
|
-
* os.homedir())`), so each project gets its own
|
|
65
|
-
* `<cwd>/.skillstate/skillstate.json` and a session opened anywhere
|
|
66
|
-
* resolves the same state for the same project.
|
|
67
|
-
*
|
|
68
|
-
* Hooks (see `src/plugin.ts`): `experimental.chat.messages.transform`
|
|
69
|
-
* (real O(1) history trimming, `{ info, parts }` entries, in-place
|
|
70
|
-
* mutation), `experimental.session.compacting` (state into compaction
|
|
71
|
-
* context), `tool.execute.after` (persist `state_patch` from
|
|
72
|
-
* `output.output`).
|
|
73
|
-
*/
|
|
74
|
-
generatePluginCode(options?: GeneratePluginOptions): string;
|
|
75
|
-
/**
|
|
76
|
-
* @non-paper additive helper: generate the plugin and persist it via
|
|
77
|
-
* `atomicWriteFile` (tmp + fsync + rename). The destination accepts a raw
|
|
78
|
-
* string or a `{ root, name }` ref confined by `resolveStatePath`.
|
|
79
|
-
* Returns the absolute destination path.
|
|
80
|
-
*/
|
|
81
|
-
savePluginCode(target: string | StatePathRef, options?: GeneratePluginOptions): Promise<string>;
|
|
82
45
|
}
|
|
83
46
|
//# sourceMappingURL=opencode-adapter.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"opencode-adapter.d.ts","sourceRoot":"","sources":["../src/opencode-adapter.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"opencode-adapter.d.ts","sourceRoot":"","sources":["../src/opencode-adapter.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AACH,OAAO,KAAK,EACV,UAAU,EACV,UAAU,EACV,cAAc,EACd,WAAW,EACX,eAAe,EAChB,MAAM,kBAAkB,CAAC;AAI1B;;GAEG;AACH,qBAAa,eAAgB,YAAW,eAAe;IACrD,QAAQ,CAAC,IAAI,cAAc;IAE3B,OAAO,CAAC,WAAW,CAAmD;IAEtE;;;;OAIG;IACH,WAAW,CAAC,KAAK,EAAE,UAAU,EAAE,IAAI,EAAE,cAAc,GAAG,MAAM,CAe3D;IAED;;OAEG;IACH,YAAY,CAAC,QAAQ,EAAE,MAAM,GAAG,UAAU,GAAG,IAAI,CAEhD;IAED;;OAEG;IACH,aAAa,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAE7C;IAED;;;;;OAKG;IACH,YAAY,CACV,KAAK,EAAE,UAAU,EACjB,WAAW,EAAE,WAAW,EACxB,IAAI,EAAE,cAAc,GACnB,MAAM,CAER;CAOF"}
|
package/dist/opencode-adapter.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { PromptTransformer } from '@skillstate/core';
|
|
2
|
-
import {
|
|
2
|
+
import { describeSchema, STATE_PATCH_CONTRACT } from '@skillstate/core';
|
|
3
3
|
/**
|
|
4
4
|
* OpenCode platform adapter (@non-paper; see module doc).
|
|
5
5
|
*/
|
|
@@ -47,68 +47,5 @@ ${STATE_PATCH_CONTRACT}`;
|
|
|
47
47
|
formatPrompt(state, observation, spec) {
|
|
48
48
|
return this.transformer.formatForOpenCode(spec, state, observation);
|
|
49
49
|
}
|
|
50
|
-
/**
|
|
51
|
-
* Generate a SKILL.md suitable for OpenCode's skill system.
|
|
52
|
-
*
|
|
53
|
-
* The frontmatter carries the skill name/description plus an
|
|
54
|
-
* execution_context block pointing at the persisted state file; the body
|
|
55
|
-
* describes the state-based execution process. History is discarded by
|
|
56
|
-
* the plugin's `messages.transform` hook — the LLM sees only the state.
|
|
57
|
-
*/
|
|
58
|
-
generateSkillMd(spec, statePath) {
|
|
59
|
-
return skillMdBody({
|
|
60
|
-
hostLabel: 'OpenCode',
|
|
61
|
-
injectionPhrase: 'injected into the message list before every model call',
|
|
62
|
-
hooks: {
|
|
63
|
-
inject: 'messages.transform',
|
|
64
|
-
reInject: 'session.compacting',
|
|
65
|
-
},
|
|
66
|
-
spec,
|
|
67
|
-
statePath: statePath ?? './.skillstate/skillstate.json',
|
|
68
|
-
});
|
|
69
|
-
}
|
|
70
|
-
/**
|
|
71
|
-
* Generate an OpenCode plugin file.
|
|
72
|
-
*
|
|
73
|
-
* The plugin is ALWAYS a thin loader in per-project resolver mode: the
|
|
74
|
-
* state path is computed from the session cwd on every hook call inside
|
|
75
|
-
* the static plugin (`resolveStatePathForCwd(process.cwd(),
|
|
76
|
-
* os.homedir())`), so each project gets its own
|
|
77
|
-
* `<cwd>/.skillstate/skillstate.json` and a session opened anywhere
|
|
78
|
-
* resolves the same state for the same project.
|
|
79
|
-
*
|
|
80
|
-
* Hooks (see `src/plugin.ts`): `experimental.chat.messages.transform`
|
|
81
|
-
* (real O(1) history trimming, `{ info, parts }` entries, in-place
|
|
82
|
-
* mutation), `experimental.session.compacting` (state into compaction
|
|
83
|
-
* context), `tool.execute.after` (persist `state_patch` from
|
|
84
|
-
* `output.output`).
|
|
85
|
-
*/
|
|
86
|
-
generatePluginCode(options) {
|
|
87
|
-
const maxHistory = options?.maxHistoryMessages ?? 3;
|
|
88
|
-
return `// OpenCode plugin (thin loader) generated by skillstate.
|
|
89
|
-
// Hook logic lives in the static plugin — the single source of truth —
|
|
90
|
-
// shipped in the @skillstate/opencode package. PER-PROJECT state is
|
|
91
|
-
// resolved from the session cwd on every hook call —
|
|
92
|
-
// <cwd>/.skillstate/skillstate.json (global bucket when cwd === home).
|
|
93
|
-
import { createSkillStatePlugin } from '@skillstate/opencode';
|
|
94
|
-
|
|
95
|
-
export default createSkillStatePlugin({
|
|
96
|
-
maxHistoryMessages: ${maxHistory},
|
|
97
|
-
});
|
|
98
|
-
`;
|
|
99
|
-
}
|
|
100
|
-
/**
|
|
101
|
-
* @non-paper additive helper: generate the plugin and persist it via
|
|
102
|
-
* `atomicWriteFile` (tmp + fsync + rename). The destination accepts a raw
|
|
103
|
-
* string or a `{ root, name }` ref confined by `resolveStatePath`.
|
|
104
|
-
* Returns the absolute destination path.
|
|
105
|
-
*/
|
|
106
|
-
async savePluginCode(target, options) {
|
|
107
|
-
const dest = typeof target === 'string'
|
|
108
|
-
? target
|
|
109
|
-
: resolveStatePath(target.root, target.name);
|
|
110
|
-
await atomicWriteFile(dest, this.generatePluginCode(options));
|
|
111
|
-
return dest;
|
|
112
|
-
}
|
|
113
50
|
}
|
|
114
51
|
//# sourceMappingURL=opencode-adapter.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"opencode-adapter.js","sourceRoot":"","sources":["../src/opencode-adapter.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"opencode-adapter.js","sourceRoot":"","sources":["../src/opencode-adapter.ts"],"names":[],"mappings":"AAuBA,OAAO,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AACrD,OAAO,EAAE,cAAc,EAAE,oBAAoB,EAAE,MAAM,kBAAkB,CAAC;AAExE;;GAEG;AACH,MAAM,OAAO,eAAe;IACjB,IAAI,GAAG,UAAU,CAAC;IAEnB,WAAW,GAAG,IAAI,iBAAiB,CAAC,EAAE,QAAQ,EAAE,UAAU,EAAE,CAAC,CAAC;IAEtE;;;;OAIG;IACH,WAAW,CAAC,KAAiB,EAAE,IAAoB;QACjD,MAAM,SAAS,GAAG,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC;QACxC,MAAM,UAAU,GAAG,cAAc,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QAE/C,OAAO,gBAAgB,IAAI,CAAC,EAAE;gBAClB,IAAI,CAAC,YAAY;EAC/B,UAAU;;EAEV,SAAS;;;;;;EAMT,oBAAoB,EAAE,CAAC;IACvB,CAAC;IAED;;OAEG;IACH,YAAY,CAAC,QAAgB;QAC3B,OAAO,IAAI,CAAC,WAAW,CAAC,iBAAiB,CAAC,QAAQ,CAAC,CAAC;IACtD,CAAC;IAED;;OAEG;IACH,aAAa,CAAC,QAAgB;QAC5B,OAAO,IAAI,CAAC,WAAW,CAAC,aAAa,CAAC,QAAQ,CAAC,CAAC;IAClD,CAAC;IAED;;;;;OAKG;IACH,YAAY,CACV,KAAiB,EACjB,WAAwB,EACxB,IAAoB;QAEpB,OAAO,IAAI,CAAC,WAAW,CAAC,iBAAiB,CAAC,IAAI,EAAE,KAAK,EAAE,WAAW,CAAC,CAAC;IACtE,CAAC;CAOF"}
|