@skillstate/opencode 2.2.2 → 3.0.1

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 (62) hide show
  1. package/README.md +194 -142
  2. package/dist/feedback.d.ts +178 -0
  3. package/dist/feedback.d.ts.map +1 -0
  4. package/dist/feedback.js +235 -0
  5. package/dist/feedback.js.map +1 -0
  6. package/dist/index.d.ts +58 -2
  7. package/dist/index.d.ts.map +1 -1
  8. package/dist/index.js +48 -3
  9. package/dist/index.js.map +1 -1
  10. package/dist/mode.d.ts +97 -0
  11. package/dist/mode.d.ts.map +1 -0
  12. package/dist/mode.js +111 -0
  13. package/dist/mode.js.map +1 -0
  14. package/dist/opencode-adapter.d.ts +10 -46
  15. package/dist/opencode-adapter.d.ts.map +1 -1
  16. package/dist/opencode-adapter.js +1 -64
  17. package/dist/opencode-adapter.js.map +1 -1
  18. package/dist/paper-mode.d.ts +421 -0
  19. package/dist/paper-mode.d.ts.map +1 -0
  20. package/dist/paper-mode.js +445 -0
  21. package/dist/paper-mode.js.map +1 -0
  22. package/dist/plugin.d.ts +218 -76
  23. package/dist/plugin.d.ts.map +1 -1
  24. package/dist/plugin.js +867 -232
  25. package/dist/plugin.js.map +1 -1
  26. package/dist/response-sink.d.ts +208 -0
  27. package/dist/response-sink.d.ts.map +1 -0
  28. package/dist/response-sink.js +243 -0
  29. package/dist/response-sink.js.map +1 -0
  30. package/dist/runtime.d.ts +203 -0
  31. package/dist/runtime.d.ts.map +1 -0
  32. package/dist/runtime.js +332 -0
  33. package/dist/runtime.js.map +1 -0
  34. package/dist/session-registry.d.ts +148 -0
  35. package/dist/session-registry.d.ts.map +1 -0
  36. package/dist/session-registry.js +236 -0
  37. package/dist/session-registry.js.map +1 -0
  38. package/dist/spec-loader.d.ts +81 -0
  39. package/dist/spec-loader.d.ts.map +1 -0
  40. package/dist/spec-loader.js +163 -0
  41. package/dist/spec-loader.js.map +1 -0
  42. package/dist/state-store.d.ts +126 -0
  43. package/dist/state-store.d.ts.map +1 -0
  44. package/dist/state-store.js +186 -0
  45. package/dist/state-store.js.map +1 -0
  46. package/dist/step-boundary.d.ts +91 -0
  47. package/dist/step-boundary.d.ts.map +1 -0
  48. package/dist/step-boundary.js +109 -0
  49. package/dist/step-boundary.js.map +1 -0
  50. package/dist/system-hint.d.ts +129 -0
  51. package/dist/system-hint.d.ts.map +1 -0
  52. package/dist/system-hint.js +166 -0
  53. package/dist/system-hint.js.map +1 -0
  54. package/dist/tools.d.ts +148 -0
  55. package/dist/tools.d.ts.map +1 -0
  56. package/dist/tools.js +350 -0
  57. package/dist/tools.js.map +1 -0
  58. package/package.json +3 -2
  59. package/dist/plugin-types.d.ts +0 -71
  60. package/dist/plugin-types.d.ts.map +0 -1
  61. package/dist/plugin-types.js +0 -8
  62. package/dist/plugin-types.js.map +0 -1
@@ -0,0 +1,148 @@
1
+ /**
2
+ * Sub-agent session registry for the OpenCode v2 plugin.
3
+ *
4
+ * OpenCode spawns a CHILD SESSION for every sub-agent (the `task` tool and
5
+ * every custom agent). Those child sessions are first-class: they run the
6
+ * agent loop, call tools, and would otherwise all write to the SAME project
7
+ * state file — the last writer wins and the main agent's notes are silently
8
+ * clobbered mid-task.
9
+ *
10
+ * The v1 plugin inferred this from an in-process `Map` fed by an `event`
11
+ * hook. v2 exposes a real event stream (`ctx.event.subscribe()`), so the
12
+ * registry is an explicit, testable value object instead of module-level
13
+ * mutable state shared by tests and a single plugin instance.
14
+ *
15
+ * PARENT EDGES come from the server's own event stream. In OpenCode v2 the
16
+ * relevant payloads are:
17
+ *
18
+ * ```ts
19
+ * { type: "session.created", data: { sessionID: string, parentID?: string } }
20
+ * { type: "session.forked", data: { sessionID: string, parentID: string } }
21
+ * { type: "session.deleted", data: { sessionID: string } }
22
+ * ```
23
+ *
24
+ * There is no `session.updated` event in v2, and the parent lives on
25
+ * `data.parentID` — not on a `properties.info` envelope as it did in v1.
26
+ * A session with a non-empty `parentID` is a sub-agent; a session with an
27
+ * absent or empty `parentID` is a root session. The registry never guesses
28
+ * from the id shape — a session that has not been observed on the stream
29
+ * yet is treated as a ROOT session (the safe default: it gets the shared
30
+ * project file, which is what a plain single-session user expects).
31
+ *
32
+ * LIFECYCLE: entries are refreshed on every event and evicted after
33
+ * {@link DEFAULT_SESSION_TTL_MS} of silence, so a long-lived OpenCode
34
+ * process does not accumulate one entry per session it has ever seen.
35
+ */
36
+ /** How long a session stays registered after its last event. */
37
+ export declare const DEFAULT_SESSION_TTL_MS: number;
38
+ /** A session as observed on the OpenCode event stream. */
39
+ export interface SessionRecord {
40
+ /** The host session id, verbatim. */
41
+ readonly id: string;
42
+ /** The parent session id, or `null` for a root session. */
43
+ readonly parentID: string | null;
44
+ /** Event receive time (epoch ms) — drives TTL eviction. */
45
+ readonly seenAt: number;
46
+ }
47
+ /**
48
+ * Options for {@link SessionRegistry}. Tests inject a clock and a TTL so
49
+ * eviction is deterministic.
50
+ */
51
+ export interface SessionRegistryOptions {
52
+ /** Clock in epoch milliseconds. Defaults to `Date.now`. */
53
+ now?: () => number;
54
+ /** Idle time after which a session is evicted. Defaults to 6h. */
55
+ ttlMs?: number;
56
+ /** Cap on retained sessions; the oldest are evicted first. */
57
+ maxSessions?: number;
58
+ }
59
+ /**
60
+ * Tracks the session→parent forest reported by the OpenCode event stream.
61
+ *
62
+ * Every method is pure with respect to the plugin's other state: the
63
+ * registry only ever answers questions about the shape of the session tree.
64
+ */
65
+ export declare class SessionRegistry {
66
+ private readonly sessions;
67
+ private readonly now;
68
+ private readonly ttlMs;
69
+ private readonly maxSessions;
70
+ constructor(options?: SessionRegistryOptions);
71
+ /**
72
+ * Fold one server event into the registry.
73
+ *
74
+ * `session.created` and `session.forked` register (or re-parent) a
75
+ * session; `session.deleted` forgets it. Any other event, and any
76
+ * malformed payload, is ignored — the stream carries far more than
77
+ * sessions and one odd record must never break the subscription loop.
78
+ *
79
+ * Returns the {@link SessionRecord} it wrote, or `null` when nothing was
80
+ * registered (including a deletion).
81
+ */
82
+ ingestEvent(event: unknown): SessionRecord | null;
83
+ /** The recorded session, or `undefined` when it was never observed. */
84
+ get(sessionID: string): SessionRecord | undefined;
85
+ /**
86
+ * Whether `sessionID` is a sub-agent session (a session with a parent).
87
+ *
88
+ * An UNOBSERVED session answers `false`: the plugin then treats it as a
89
+ * root session, which is the behaviour a single-session user expects and
90
+ * never creates a surprise `agents/` directory.
91
+ */
92
+ isSubAgent(sessionID: string): boolean;
93
+ /**
94
+ * The topmost ancestor of `sessionID` (itself when it is a root
95
+ * session). Follows parent edges with a visited set so a cycle — which a
96
+ * buggy or hostile event stream could produce — terminates instead of
97
+ * hanging the agent loop.
98
+ */
99
+ rootOf(sessionID: string): string;
100
+ /**
101
+ * Every session below `sessionID` in the tree - i.e. every session whose
102
+ * parent chain passes through `sessionID`, excluding `sessionID` itself.
103
+ *
104
+ * "Root ancestor" would be the wrong definition here: asked about a
105
+ * sub-agent it would also return that sub-agent, because the sub-agent's
106
+ * root is further up. Walking up to the queried session instead answers
107
+ * both cases uniformly, and a root session still gets every sub-agent.
108
+ *
109
+ * Sorted by id for a stable, testable result.
110
+ */
111
+ descendantsOf(sessionID: string): string[];
112
+ /**
113
+ * Whether `candidate` sits somewhere below `ancestor`. Cycle-safe: a
114
+ * parent chain that loops back on itself terminates instead of hanging
115
+ * the agent loop.
116
+ */
117
+ private isDescendantOf;
118
+ /** Every registered session, oldest-observed first. */
119
+ list(): readonly SessionRecord[];
120
+ /** How many sessions are currently registered. */
121
+ get size(): number;
122
+ /** Forget every session (test isolation, and a clean reload). */
123
+ clear(): void;
124
+ /**
125
+ * Drop sessions idle for longer than the TTL, then enforce the size cap
126
+ * by dropping the least-recently-seen entries. Called after every
127
+ * ingest; also exposed for tests.
128
+ */
129
+ evict(): void;
130
+ }
131
+ /**
132
+ * The on-disk scope name for a session: a stable, filesystem-safe id that
133
+ * keeps SUB-AGENT sessions in their own directory and root sessions on the
134
+ * shared project file.
135
+ *
136
+ * Returns `''` for a root session (the shared project state) and a
137
+ * sanitized `<parent>-<session>` id for a sub-agent.
138
+ *
139
+ * The child part is the FULL sanitized session id, not a short prefix. The
140
+ * v1 code truncated to 8 characters, which silently collapses two sibling
141
+ * sub-agents into one state file whenever their ids share a prefix — they
142
+ * overwrite each other's notes with no error. `sanitizeAgentId` caps the
143
+ * result at 64 characters, so the directory name stays bounded. The parent
144
+ * part is truncated to 8 characters because it only has to disambiguate
145
+ * which root a sub-agent belongs to.
146
+ */
147
+ export declare function stateScopeFor(registry: SessionRegistry, sessionID: string): string;
148
+ //# sourceMappingURL=session-registry.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"session-registry.d.ts","sourceRoot":"","sources":["../src/session-registry.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AAIH,gEAAgE;AAChE,eAAO,MAAM,sBAAsB,QAAqB,CAAC;AAEzD,0DAA0D;AAC1D,MAAM,WAAW,aAAa;IAC5B,qCAAqC;IACrC,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,2DAA2D;IAC3D,QAAQ,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACjC,2DAA2D;IAC3D,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;CACzB;AAED;;;GAGG;AACH,MAAM,WAAW,sBAAsB;IACrC,2DAA2D;IAC3D,GAAG,CAAC,EAAE,MAAM,MAAM,CAAC;IACnB,kEAAkE;IAClE,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,8DAA8D;IAC9D,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAkCD;;;;;GAKG;AACH,qBAAa,eAAe;IAC1B,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAoC;IAC7D,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAe;IACnC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAS;IAC/B,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAS;IAErC,YAAY,OAAO,GAAE,sBAA2B,EAI/C;IAED;;;;;;;;;;OAUG;IACH,WAAW,CAAC,KAAK,EAAE,OAAO,GAAG,aAAa,GAAG,IAAI,CAehD;IAED,uEAAuE;IACvE,GAAG,CAAC,SAAS,EAAE,MAAM,GAAG,aAAa,GAAG,SAAS,CAEhD;IAED;;;;;;OAMG;IACH,UAAU,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAErC;IAED;;;;;OAKG;IACH,MAAM,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAUhC;IAED;;;;;;;;;;OAUG;IACH,aAAa,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,EAAE,CAQzC;IAED;;;;OAIG;IACH,OAAO,CAAC,cAAc;IActB,uDAAuD;IACvD,IAAI,IAAI,SAAS,aAAa,EAAE,CAE/B;IAED,kDAAkD;IAClD,IAAI,IAAI,IAAI,MAAM,CAEjB;IAED,iEAAiE;IACjE,KAAK,IAAI,IAAI,CAEZ;IAED;;;;OAIG;IACH,KAAK,IAAI,IAAI,CAYZ;CACF;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,aAAa,CAC3B,QAAQ,EAAE,eAAe,EACzB,SAAS,EAAE,MAAM,GAChB,MAAM,CAQR"}
@@ -0,0 +1,236 @@
1
+ /**
2
+ * Sub-agent session registry for the OpenCode v2 plugin.
3
+ *
4
+ * OpenCode spawns a CHILD SESSION for every sub-agent (the `task` tool and
5
+ * every custom agent). Those child sessions are first-class: they run the
6
+ * agent loop, call tools, and would otherwise all write to the SAME project
7
+ * state file — the last writer wins and the main agent's notes are silently
8
+ * clobbered mid-task.
9
+ *
10
+ * The v1 plugin inferred this from an in-process `Map` fed by an `event`
11
+ * hook. v2 exposes a real event stream (`ctx.event.subscribe()`), so the
12
+ * registry is an explicit, testable value object instead of module-level
13
+ * mutable state shared by tests and a single plugin instance.
14
+ *
15
+ * PARENT EDGES come from the server's own event stream. In OpenCode v2 the
16
+ * relevant payloads are:
17
+ *
18
+ * ```ts
19
+ * { type: "session.created", data: { sessionID: string, parentID?: string } }
20
+ * { type: "session.forked", data: { sessionID: string, parentID: string } }
21
+ * { type: "session.deleted", data: { sessionID: string } }
22
+ * ```
23
+ *
24
+ * There is no `session.updated` event in v2, and the parent lives on
25
+ * `data.parentID` — not on a `properties.info` envelope as it did in v1.
26
+ * A session with a non-empty `parentID` is a sub-agent; a session with an
27
+ * absent or empty `parentID` is a root session. The registry never guesses
28
+ * from the id shape — a session that has not been observed on the stream
29
+ * yet is treated as a ROOT session (the safe default: it gets the shared
30
+ * project file, which is what a plain single-session user expects).
31
+ *
32
+ * LIFECYCLE: entries are refreshed on every event and evicted after
33
+ * {@link DEFAULT_SESSION_TTL_MS} of silence, so a long-lived OpenCode
34
+ * process does not accumulate one entry per session it has ever seen.
35
+ */
36
+ import { sanitizeAgentId } from '@skillstate/core';
37
+ /** How long a session stays registered after its last event. */
38
+ export const DEFAULT_SESSION_TTL_MS = 6 * 60 * 60 * 1000;
39
+ const DEFAULT_MAX_SESSIONS = 512;
40
+ function readSessionEvent(event) {
41
+ if (typeof event !== 'object' || event === null)
42
+ return null;
43
+ const type = event.type;
44
+ if (typeof type !== 'string')
45
+ return null;
46
+ if (type !== 'session.created' && type !== 'session.forked' && type !== 'session.deleted') {
47
+ return null;
48
+ }
49
+ const data = event.data;
50
+ if (typeof data !== 'object' || data === null)
51
+ return null;
52
+ const record = data;
53
+ if (typeof record.sessionID !== 'string' || record.sessionID.length === 0)
54
+ return null;
55
+ if (type === 'session.deleted')
56
+ return { kind: 'delete', id: record.sessionID };
57
+ const parent = typeof record.parentID === 'string' && record.parentID.length > 0 ? record.parentID : null;
58
+ return { kind: 'upsert', id: record.sessionID, parentID: parent };
59
+ }
60
+ /**
61
+ * Tracks the session→parent forest reported by the OpenCode event stream.
62
+ *
63
+ * Every method is pure with respect to the plugin's other state: the
64
+ * registry only ever answers questions about the shape of the session tree.
65
+ */
66
+ export class SessionRegistry {
67
+ sessions = new Map();
68
+ now;
69
+ ttlMs;
70
+ maxSessions;
71
+ constructor(options = {}) {
72
+ this.now = options.now ?? Date.now;
73
+ this.ttlMs = options.ttlMs ?? DEFAULT_SESSION_TTL_MS;
74
+ this.maxSessions = options.maxSessions ?? DEFAULT_MAX_SESSIONS;
75
+ }
76
+ /**
77
+ * Fold one server event into the registry.
78
+ *
79
+ * `session.created` and `session.forked` register (or re-parent) a
80
+ * session; `session.deleted` forgets it. Any other event, and any
81
+ * malformed payload, is ignored — the stream carries far more than
82
+ * sessions and one odd record must never break the subscription loop.
83
+ *
84
+ * Returns the {@link SessionRecord} it wrote, or `null` when nothing was
85
+ * registered (including a deletion).
86
+ */
87
+ ingestEvent(event) {
88
+ const parsed = readSessionEvent(event);
89
+ if (parsed === null)
90
+ return null;
91
+ if (parsed.kind === 'delete') {
92
+ this.sessions.delete(parsed.id);
93
+ return null;
94
+ }
95
+ const record = {
96
+ id: parsed.id,
97
+ parentID: parsed.parentID,
98
+ seenAt: this.now(),
99
+ };
100
+ this.sessions.set(record.id, record);
101
+ this.evict();
102
+ return record;
103
+ }
104
+ /** The recorded session, or `undefined` when it was never observed. */
105
+ get(sessionID) {
106
+ return this.sessions.get(sessionID);
107
+ }
108
+ /**
109
+ * Whether `sessionID` is a sub-agent session (a session with a parent).
110
+ *
111
+ * An UNOBSERVED session answers `false`: the plugin then treats it as a
112
+ * root session, which is the behaviour a single-session user expects and
113
+ * never creates a surprise `agents/` directory.
114
+ */
115
+ isSubAgent(sessionID) {
116
+ return this.sessions.get(sessionID)?.parentID != null;
117
+ }
118
+ /**
119
+ * The topmost ancestor of `sessionID` (itself when it is a root
120
+ * session). Follows parent edges with a visited set so a cycle — which a
121
+ * buggy or hostile event stream could produce — terminates instead of
122
+ * hanging the agent loop.
123
+ */
124
+ rootOf(sessionID) {
125
+ let current = sessionID;
126
+ const visited = new Set([sessionID]);
127
+ for (;;) {
128
+ const record = this.sessions.get(current);
129
+ const parent = record?.parentID;
130
+ if (parent === undefined || parent === null || visited.has(parent))
131
+ return current;
132
+ visited.add(parent);
133
+ current = parent;
134
+ }
135
+ }
136
+ /**
137
+ * Every session below `sessionID` in the tree - i.e. every session whose
138
+ * parent chain passes through `sessionID`, excluding `sessionID` itself.
139
+ *
140
+ * "Root ancestor" would be the wrong definition here: asked about a
141
+ * sub-agent it would also return that sub-agent, because the sub-agent's
142
+ * root is further up. Walking up to the queried session instead answers
143
+ * both cases uniformly, and a root session still gets every sub-agent.
144
+ *
145
+ * Sorted by id for a stable, testable result.
146
+ */
147
+ descendantsOf(sessionID) {
148
+ const result = [];
149
+ for (const record of this.sessions.values()) {
150
+ if (record.id !== sessionID && this.isDescendantOf(record.id, sessionID)) {
151
+ result.push(record.id);
152
+ }
153
+ }
154
+ return result.sort();
155
+ }
156
+ /**
157
+ * Whether `candidate` sits somewhere below `ancestor`. Cycle-safe: a
158
+ * parent chain that loops back on itself terminates instead of hanging
159
+ * the agent loop.
160
+ */
161
+ isDescendantOf(candidate, ancestor) {
162
+ let current = candidate;
163
+ const visited = new Set([candidate]);
164
+ for (;;) {
165
+ const record = this.sessions.get(current);
166
+ const parent = record?.parentID ?? null;
167
+ if (parent === null)
168
+ return false;
169
+ if (parent === ancestor)
170
+ return true;
171
+ if (visited.has(parent))
172
+ return false;
173
+ visited.add(parent);
174
+ current = parent;
175
+ }
176
+ }
177
+ /** Every registered session, oldest-observed first. */
178
+ list() {
179
+ return [...this.sessions.values()].sort((a, b) => a.seenAt - b.seenAt || a.id.localeCompare(b.id));
180
+ }
181
+ /** How many sessions are currently registered. */
182
+ get size() {
183
+ return this.sessions.size;
184
+ }
185
+ /** Forget every session (test isolation, and a clean reload). */
186
+ clear() {
187
+ this.sessions.clear();
188
+ }
189
+ /**
190
+ * Drop sessions idle for longer than the TTL, then enforce the size cap
191
+ * by dropping the least-recently-seen entries. Called after every
192
+ * ingest; also exposed for tests.
193
+ */
194
+ evict() {
195
+ const cutoff = this.now() - this.ttlMs;
196
+ for (const [id, record] of this.sessions) {
197
+ if (record.seenAt < cutoff)
198
+ this.sessions.delete(id);
199
+ }
200
+ if (this.sessions.size <= this.maxSessions)
201
+ return;
202
+ const ordered = [...this.sessions.entries()].sort((a, b) => a[1].seenAt - b[1].seenAt || a[0].localeCompare(b[0]));
203
+ for (const [id] of ordered.slice(0, this.sessions.size - this.maxSessions)) {
204
+ this.sessions.delete(id);
205
+ }
206
+ }
207
+ }
208
+ /**
209
+ * The on-disk scope name for a session: a stable, filesystem-safe id that
210
+ * keeps SUB-AGENT sessions in their own directory and root sessions on the
211
+ * shared project file.
212
+ *
213
+ * Returns `''` for a root session (the shared project state) and a
214
+ * sanitized `<parent>-<session>` id for a sub-agent.
215
+ *
216
+ * The child part is the FULL sanitized session id, not a short prefix. The
217
+ * v1 code truncated to 8 characters, which silently collapses two sibling
218
+ * sub-agents into one state file whenever their ids share a prefix — they
219
+ * overwrite each other's notes with no error. `sanitizeAgentId` caps the
220
+ * result at 64 characters, so the directory name stays bounded. The parent
221
+ * part is truncated to 8 characters because it only has to disambiguate
222
+ * which root a sub-agent belongs to.
223
+ */
224
+ export function stateScopeFor(registry, sessionID) {
225
+ const record = registry.get(sessionID);
226
+ if (record === undefined || record.parentID === null)
227
+ return '';
228
+ const child = sanitizeAgentId(sessionID);
229
+ const parentPrefix = sanitizeAgentId(record.parentID).slice(0, 8);
230
+ if (child.length === 0)
231
+ return parentPrefix;
232
+ if (parentPrefix.length === 0)
233
+ return child;
234
+ return `${parentPrefix}-${child}`;
235
+ }
236
+ //# sourceMappingURL=session-registry.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"session-registry.js","sourceRoot":"","sources":["../src/session-registry.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,81 @@
1
+ /**
2
+ * Resolving P — the procedural specification the paper's prompt is built on.
3
+ *
4
+ * ── Why the plugin needs a spec at all ────────────────────────────────────
5
+ *
6
+ * A.4 is `Format(P, Σₜ, Oₜ)`, and P is the first argument. Paper mode
7
+ * therefore cannot assemble a paper-conformant prompt without one, even
8
+ * though the store ({@link ProjectStateStore}) is deliberately schema-free:
9
+ * notes mode never shows the model a schema, so it never needs P.
10
+ *
11
+ * ── Resolution order ─────────────────────────────────────────────────────
12
+ *
13
+ * 1. `<project>/skill-spec.json` — the file `skillstate init` writes and the
14
+ * one the CLI's `--spec` already points at (`config.ts` default
15
+ * `specPath: './skill-spec.json'`). A project that has customised its
16
+ * procedure gets that procedure.
17
+ * 2. {@link GENERIC_PROCEDURE_SPEC} — the built-in, domain-neutral default.
18
+ *
19
+ * ── A malformed spec file must not reach the model ────────────────────────
20
+ *
21
+ * A half-written or hand-mangled `skill-spec.json` is exactly the kind of
22
+ * input that produced the v1 failure, where the spec's own instructions
23
+ * ("You are an autonomous CTF agent … find the flag") overrode the user. So
24
+ * the file is VALIDATED before it is trusted, field by field, and anything
25
+ * that does not typecheck falls back to the built-in spec with the reason
26
+ * recorded. There is no code path that feeds an unvalidated P to the model.
27
+ *
28
+ * Reads are cached per directory for the lifetime of the resolver: the
29
+ * `context` hook runs on every model request, and re-reading and re-validating
30
+ * a file that cannot change without the user editing it is pure overhead on
31
+ * the agent loop's hot path. {@link SpecResolver.invalidate} drops the cache
32
+ * for callers that do edit it.
33
+ */
34
+ import type { ProceduralSpec } from '@skillstate/core';
35
+ /** The file a project keeps its procedural spec in. */
36
+ export declare const SPEC_FILE_NAME = "skill-spec.json";
37
+ /** Where the resolved spec came from. */
38
+ export type SpecSource = 'builtin' | 'file';
39
+ /** The outcome of {@link SpecResolver.resolve}. */
40
+ export interface SpecResolution {
41
+ /** The spec to build the prompt from. Always valid. */
42
+ readonly spec: ProceduralSpec;
43
+ /** `builtin` when the file was absent or rejected. */
44
+ readonly source: SpecSource;
45
+ /** Absolute path of the file that was read, when one existed. */
46
+ readonly path?: string;
47
+ /**
48
+ * Why a file was rejected, verbatim. Present only alongside
49
+ * `source: 'builtin'` when a file existed and did not validate.
50
+ */
51
+ readonly rejected?: string;
52
+ }
53
+ /**
54
+ * Validate a parsed spec document. Returns the spec, or a sentence naming
55
+ * the first field that failed. Pure.
56
+ *
57
+ * The checks are deliberately structural only — they reject a document that
58
+ * could not be rendered or that would misdescribe Σₜ, and nothing subtler.
59
+ * Semantic review of an instructions string is not something a type check can
60
+ * do, and pretending otherwise would be worse than not checking.
61
+ */
62
+ export declare function parseSpec(value: unknown): ProceduralSpec | string;
63
+ /**
64
+ * Per-project spec resolution with a cache.
65
+ *
66
+ * One instance per plugin setup. The cache key is the resolved project
67
+ * directory, so a single OpenCode server serving several checkouts gets a
68
+ * different spec per checkout without the caller managing that.
69
+ */
70
+ export declare class SpecResolver {
71
+ private readonly cache;
72
+ /**
73
+ * The spec for `directory`, reading and validating the file at most once
74
+ * per {@link invalidate}.
75
+ */
76
+ resolve(directory: string): SpecResolution;
77
+ /** Drop the cached spec for `directory` (or for every directory). */
78
+ invalidate(directory?: string): void;
79
+ private load;
80
+ }
81
+ //# sourceMappingURL=spec-loader.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"spec-loader.d.ts","sourceRoot":"","sources":["../src/spec-loader.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AAKH,OAAO,KAAK,EAAE,cAAc,EAA4B,MAAM,kBAAkB,CAAC;AAEjF,uDAAuD;AACvD,eAAO,MAAM,cAAc,oBAAoB,CAAC;AAEhD,yCAAyC;AACzC,MAAM,MAAM,UAAU,GAAG,SAAS,GAAG,MAAM,CAAC;AAE5C,mDAAmD;AACnD,MAAM,WAAW,cAAc;IAC7B,uDAAuD;IACvD,QAAQ,CAAC,IAAI,EAAE,cAAc,CAAC;IAC9B,sDAAsD;IACtD,QAAQ,CAAC,MAAM,EAAE,UAAU,CAAC;IAC5B,iEAAiE;IACjE,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IACvB;;;OAGG;IACH,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;CAC5B;AA+BD;;;;;;;;GAQG;AACH,wBAAgB,SAAS,CAAC,KAAK,EAAE,OAAO,GAAG,cAAc,GAAG,MAAM,CAiBjE;AAED;;;;;;GAMG;AACH,qBAAa,YAAY;IACvB,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAqC;IAE3D;;;OAGG;IACH,OAAO,CAAC,SAAS,EAAE,MAAM,GAAG,cAAc,CAOzC;IAED,qEAAqE;IACrE,UAAU,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAGnC;IAED,OAAO,CAAC,IAAI;CA8Bb"}
@@ -0,0 +1,163 @@
1
+ /**
2
+ * Resolving P — the procedural specification the paper's prompt is built on.
3
+ *
4
+ * ── Why the plugin needs a spec at all ────────────────────────────────────
5
+ *
6
+ * A.4 is `Format(P, Σₜ, Oₜ)`, and P is the first argument. Paper mode
7
+ * therefore cannot assemble a paper-conformant prompt without one, even
8
+ * though the store ({@link ProjectStateStore}) is deliberately schema-free:
9
+ * notes mode never shows the model a schema, so it never needs P.
10
+ *
11
+ * ── Resolution order ─────────────────────────────────────────────────────
12
+ *
13
+ * 1. `<project>/skill-spec.json` — the file `skillstate init` writes and the
14
+ * one the CLI's `--spec` already points at (`config.ts` default
15
+ * `specPath: './skill-spec.json'`). A project that has customised its
16
+ * procedure gets that procedure.
17
+ * 2. {@link GENERIC_PROCEDURE_SPEC} — the built-in, domain-neutral default.
18
+ *
19
+ * ── A malformed spec file must not reach the model ────────────────────────
20
+ *
21
+ * A half-written or hand-mangled `skill-spec.json` is exactly the kind of
22
+ * input that produced the v1 failure, where the spec's own instructions
23
+ * ("You are an autonomous CTF agent … find the flag") overrode the user. So
24
+ * the file is VALIDATED before it is trusted, field by field, and anything
25
+ * that does not typecheck falls back to the built-in spec with the reason
26
+ * recorded. There is no code path that feeds an unvalidated P to the model.
27
+ *
28
+ * Reads are cached per directory for the lifetime of the resolver: the
29
+ * `context` hook runs on every model request, and re-reading and re-validating
30
+ * a file that cannot change without the user editing it is pure overhead on
31
+ * the agent loop's hot path. {@link SpecResolver.invalidate} drops the cache
32
+ * for callers that do edit it.
33
+ */
34
+ import * as fs from 'node:fs';
35
+ import * as path from 'node:path';
36
+ import { GENERIC_PROCEDURE_SPEC, isPlainObject } from '@skillstate/core';
37
+ /** The file a project keeps its procedural spec in. */
38
+ export const SPEC_FILE_NAME = 'skill-spec.json';
39
+ const SCHEMA_TYPES = new Set([
40
+ 'string',
41
+ 'number',
42
+ 'boolean',
43
+ 'array',
44
+ 'object',
45
+ ]);
46
+ function validateSchema(value, at) {
47
+ if (!isPlainObject(value))
48
+ return `${at} is not an object`;
49
+ const schema = {};
50
+ for (const [key, raw] of Object.entries(value)) {
51
+ if (!isPlainObject(raw))
52
+ return `${at}.${key} is not an object`;
53
+ const type = raw['type'];
54
+ if (typeof type !== 'string' || !SCHEMA_TYPES.has(type)) {
55
+ return `${at}.${key}.type must be one of ${[...SCHEMA_TYPES].join(', ')}`;
56
+ }
57
+ if (!('default' in raw))
58
+ return `${at}.${key}.default is required`;
59
+ const description = raw['description'];
60
+ if (description !== undefined && typeof description !== 'string') {
61
+ return `${at}.${key}.description must be a string`;
62
+ }
63
+ const field = { type: type, default: raw['default'] };
64
+ if (typeof description === 'string')
65
+ field.description = description;
66
+ schema[key] = field;
67
+ }
68
+ return schema;
69
+ }
70
+ /**
71
+ * Validate a parsed spec document. Returns the spec, or a sentence naming
72
+ * the first field that failed. Pure.
73
+ *
74
+ * The checks are deliberately structural only — they reject a document that
75
+ * could not be rendered or that would misdescribe Σₜ, and nothing subtler.
76
+ * Semantic review of an instructions string is not something a type check can
77
+ * do, and pretending otherwise would be worse than not checking.
78
+ */
79
+ export function parseSpec(value) {
80
+ if (!isPlainObject(value))
81
+ return 'spec is not an object';
82
+ const id = value['id'];
83
+ if (typeof id !== 'string' || id.trim() === '')
84
+ return 'id must be a non-empty string';
85
+ const name = value['name'];
86
+ if (typeof name !== 'string' || name.trim() === '')
87
+ return 'name must be a non-empty string';
88
+ const version = value['version'];
89
+ if (typeof version !== 'string' || version.trim() === '') {
90
+ return 'version must be a non-empty string';
91
+ }
92
+ const instructions = value['instructions'];
93
+ if (typeof instructions !== 'string' || instructions.trim() === '') {
94
+ return 'instructions must be a non-empty string';
95
+ }
96
+ const schema = validateSchema(value['schema'], 'schema');
97
+ if (typeof schema === 'string')
98
+ return schema;
99
+ return { id, name, version, instructions, schema };
100
+ }
101
+ /**
102
+ * Per-project spec resolution with a cache.
103
+ *
104
+ * One instance per plugin setup. The cache key is the resolved project
105
+ * directory, so a single OpenCode server serving several checkouts gets a
106
+ * different spec per checkout without the caller managing that.
107
+ */
108
+ export class SpecResolver {
109
+ cache = new Map();
110
+ /**
111
+ * The spec for `directory`, reading and validating the file at most once
112
+ * per {@link invalidate}.
113
+ */
114
+ resolve(directory) {
115
+ const key = path.resolve(directory);
116
+ const cached = this.cache.get(key);
117
+ if (cached !== undefined)
118
+ return cached;
119
+ const resolution = this.load(key);
120
+ this.cache.set(key, resolution);
121
+ return resolution;
122
+ }
123
+ /** Drop the cached spec for `directory` (or for every directory). */
124
+ invalidate(directory) {
125
+ if (directory === undefined)
126
+ this.cache.clear();
127
+ else
128
+ this.cache.delete(path.resolve(directory));
129
+ }
130
+ load(directory) {
131
+ const file = path.join(directory, SPEC_FILE_NAME);
132
+ let raw;
133
+ try {
134
+ raw = fs.readFileSync(file, 'utf-8');
135
+ }
136
+ catch {
137
+ return { spec: GENERIC_PROCEDURE_SPEC, source: 'builtin' };
138
+ }
139
+ let parsed;
140
+ try {
141
+ parsed = JSON.parse(raw);
142
+ }
143
+ catch (error) {
144
+ return {
145
+ spec: GENERIC_PROCEDURE_SPEC,
146
+ source: 'builtin',
147
+ path: file,
148
+ rejected: `invalid JSON: ${String(error)}`,
149
+ };
150
+ }
151
+ const validated = parseSpec(parsed);
152
+ if (typeof validated === 'string') {
153
+ return {
154
+ spec: GENERIC_PROCEDURE_SPEC,
155
+ source: 'builtin',
156
+ path: file,
157
+ rejected: validated,
158
+ };
159
+ }
160
+ return { spec: validated, source: 'file', path: file };
161
+ }
162
+ }
163
+ //# sourceMappingURL=spec-loader.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"spec-loader.js","sourceRoot":"","sources":["../src/spec-loader.ts"],"names":[],"mappings":"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"}