@skillstate/core 2.0.7 → 2.2.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/dist/adapter-shared.d.ts +61 -0
- package/dist/adapter-shared.d.ts.map +1 -0
- package/dist/adapter-shared.js +96 -0
- package/dist/adapter-shared.js.map +1 -0
- package/dist/atomic-write.d.ts +17 -0
- package/dist/atomic-write.d.ts.map +1 -1
- package/dist/atomic-write.js +47 -0
- package/dist/atomic-write.js.map +1 -1
- package/dist/hook-runtime.d.ts +163 -0
- package/dist/hook-runtime.d.ts.map +1 -0
- package/dist/hook-runtime.js +364 -0
- package/dist/hook-runtime.js.map +1 -0
- package/dist/host-state.d.ts +3 -2
- package/dist/host-state.d.ts.map +1 -1
- package/dist/host-state.js +24 -11
- package/dist/host-state.js.map +1 -1
- package/dist/index.d.ts +4 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +10 -0
- package/dist/index.js.map +1 -1
- package/dist/prompt-contract.d.ts +82 -0
- package/dist/prompt-contract.d.ts.map +1 -0
- package/dist/prompt-contract.js +129 -0
- package/dist/prompt-contract.js.map +1 -0
- package/dist/prompt-transformer.d.ts +0 -4
- package/dist/prompt-transformer.d.ts.map +1 -1
- package/dist/prompt-transformer.js +8 -43
- package/dist/prompt-transformer.js.map +1 -1
- package/dist/session-meta.d.ts +58 -0
- package/dist/session-meta.d.ts.map +1 -0
- package/dist/session-meta.js +101 -0
- package/dist/session-meta.js.map +1 -0
- package/dist/state-manager.d.ts.map +1 -1
- package/dist/state-manager.js +6 -30
- package/dist/state-manager.js.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,364 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @non-paper Wave-5 hook runtime — the SINGLE SOURCE OF TRUTH for every
|
|
3
|
+
* piece of logic embedded into self-contained generated hook scripts
|
|
4
|
+
* (Claude Code `.cjs` hooks, Codex `.cjs` hooks) and reused directly by
|
|
5
|
+
* the OpenCode plugin.
|
|
6
|
+
*
|
|
7
|
+
* CONSTRAINT: the generated scripts cannot import `@skillstate/*`, so the
|
|
8
|
+
* adapters inline these functions into the emitted `.cjs` via
|
|
9
|
+
* `fn.toString()` (see {@link hookRuntimeSnippet}). That means every
|
|
10
|
+
* function body below must be PLAIN JavaScript:
|
|
11
|
+
*
|
|
12
|
+
* - no imports and no `require` — dependencies are passed as parameters
|
|
13
|
+
* (`readFile`, `writeFile`, `home`), so the caller wires the real
|
|
14
|
+
* `node:fs`/`node:os`/`node:path` (or test mocks) at the call site;
|
|
15
|
+
* - type annotations live ONLY in the signatures — both `tsc` (dist) and
|
|
16
|
+
* the vitest/esbuild transform erase them, so `fn.toString()` yields a
|
|
17
|
+
* valid CJS snippet;
|
|
18
|
+
* - no references to module-scope helpers — each function is either fully
|
|
19
|
+
* self-contained or calls only its sibling functions from this module
|
|
20
|
+
* (which the snippet inlines together).
|
|
21
|
+
*
|
|
22
|
+
* The parity suite (`tests/core/hook-runtime-parity.test.ts`) evals the
|
|
23
|
+
* snippets extracted from the generated scripts and asserts byte-identical
|
|
24
|
+
* behavior against these originals, so the "embedded copy" can no longer
|
|
25
|
+
* drift from the source of truth.
|
|
26
|
+
*/
|
|
27
|
+
/** True for plain (non-null, non-array) objects. */
|
|
28
|
+
export function isPlainObject(value) {
|
|
29
|
+
return typeof value === 'object' && value !== null && !Array.isArray(value);
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Agent-id sanitization: keep `[A-Za-z0-9_-]` runs, collapse everything
|
|
33
|
+
* else into single `-`, trim edge dashes, cap at 64 chars. Garbage input
|
|
34
|
+
* sanitizes to `''` — callers treat that as "no agent" (the main state).
|
|
35
|
+
*/
|
|
36
|
+
export function sanitizeAgentId(agentId) {
|
|
37
|
+
return agentId
|
|
38
|
+
.replace(/[^A-Za-z0-9_-]+/g, '-')
|
|
39
|
+
.replace(/^-+|-+$/g, '')
|
|
40
|
+
.slice(0, 64);
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Agent id from a host session id (Claude Code / Codex hook stdin carry
|
|
44
|
+
* `session_id`; opencode hooks carry `sessionID`): the short prefix — the
|
|
45
|
+
* first 8 characters — keeps agent directories bounded while remaining
|
|
46
|
+
* unique enough per session. Non-string/empty input yields `''`.
|
|
47
|
+
*/
|
|
48
|
+
export function resolveAgentIdFromSession(sessionId) {
|
|
49
|
+
if (typeof sessionId !== 'string' || sessionId.length === 0)
|
|
50
|
+
return '';
|
|
51
|
+
return sessionId.slice(0, 8);
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Resolve the per-project state file for a working directory — the pure,
|
|
55
|
+
* dependency-free mirror of `resolveHostStateForCwd`
|
|
56
|
+
* (`<cwd>/.skillstate/skillstate.json`; the global bucket
|
|
57
|
+
* `<home>/.skillstate/global/skillstate.json` when cwd equals home).
|
|
58
|
+
*
|
|
59
|
+
* AGENT-SCOPED STATE: a non-empty `agentId` (sanitized via
|
|
60
|
+
* {@link sanitizeAgentId}) scopes the file under an isolated
|
|
61
|
+
* `agents/<agentId>/` copy — parallel sub-agents (hook sessions) never
|
|
62
|
+
* share the main state file.
|
|
63
|
+
*
|
|
64
|
+
* String arithmetic only (POSIX): absolute paths are normalized like
|
|
65
|
+
* `path.resolve` (empty/`.` segments dropped, `..` popped, trailing
|
|
66
|
+
* slashes trimmed); relative inputs stay relative because there is no
|
|
67
|
+
* `process` access. Callers that may see relative paths resolve them
|
|
68
|
+
* first (`path.resolve(cwd)`) — the generated hook scripts do exactly
|
|
69
|
+
* that. `home` must be provided to detect the global bucket; when it is
|
|
70
|
+
* omitted the project path is returned.
|
|
71
|
+
*/
|
|
72
|
+
export function resolveStatePathForCwd(cwd, home, agentId) {
|
|
73
|
+
const normalize = (p) => {
|
|
74
|
+
const isAbsolute = p.startsWith('/');
|
|
75
|
+
const segments = [];
|
|
76
|
+
for (const segment of p.split('/')) {
|
|
77
|
+
if (segment === '' || segment === '.')
|
|
78
|
+
continue;
|
|
79
|
+
if (segment === '..') {
|
|
80
|
+
if (segments.length > 0 && segments[segments.length - 1] !== '..') {
|
|
81
|
+
segments.pop();
|
|
82
|
+
}
|
|
83
|
+
else if (!isAbsolute) {
|
|
84
|
+
segments.push('..');
|
|
85
|
+
}
|
|
86
|
+
continue;
|
|
87
|
+
}
|
|
88
|
+
segments.push(segment);
|
|
89
|
+
}
|
|
90
|
+
return (isAbsolute ? '/' : '') + segments.join('/');
|
|
91
|
+
};
|
|
92
|
+
const rootless = (p) => (p === '/' ? '' : p);
|
|
93
|
+
const resolvedCwd = normalize(cwd);
|
|
94
|
+
const resolvedHome = home === undefined || home === null ? '' : normalize(home);
|
|
95
|
+
const agent = typeof agentId === 'string' && agentId.length > 0 ? sanitizeAgentId(agentId) : '';
|
|
96
|
+
const base = resolvedCwd === resolvedHome
|
|
97
|
+
? `${rootless(resolvedHome)}/.skillstate/global`
|
|
98
|
+
: `${rootless(resolvedCwd)}/.skillstate`;
|
|
99
|
+
if (agent.length > 0) {
|
|
100
|
+
return `${base}/agents/${agent}/skillstate.json`;
|
|
101
|
+
}
|
|
102
|
+
return `${base}/skillstate.json`;
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* Read the state file through the injected `readFile` (real `fs` in
|
|
106
|
+
* generated scripts, mocks in tests). The on-disk envelope is
|
|
107
|
+
* `{ version: 1, state }`; a bare object is tolerated and treated as the
|
|
108
|
+
* state itself; anything else (missing file, corrupt JSON, arrays,
|
|
109
|
+
* scalars) yields `{}` — best-effort, never throws.
|
|
110
|
+
*/
|
|
111
|
+
export function readStateEnvelope(statePath, readFile) {
|
|
112
|
+
try {
|
|
113
|
+
const parsed = JSON.parse(readFile(statePath));
|
|
114
|
+
if (isPlainObject(parsed)) {
|
|
115
|
+
if (isPlainObject(parsed.state)) {
|
|
116
|
+
return parsed.state;
|
|
117
|
+
}
|
|
118
|
+
return parsed;
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
catch {
|
|
122
|
+
// Missing or corrupt state file — fall back to the empty state.
|
|
123
|
+
}
|
|
124
|
+
return {};
|
|
125
|
+
}
|
|
126
|
+
/**
|
|
127
|
+
* Persist the state through the injected `writeFile` as the
|
|
128
|
+
* `{ version: 1, state }` envelope (pretty-printed, newline-terminated).
|
|
129
|
+
* Throws on failure — the caller decides whether to swallow it (OpenCode
|
|
130
|
+
* plugin) or surface a `systemMessage` (PostToolUse hooks).
|
|
131
|
+
*/
|
|
132
|
+
export function saveStateEnvelope(statePath, state, writeFile) {
|
|
133
|
+
writeFile(statePath, `${JSON.stringify({ version: 1, state }, null, 2)}\n`);
|
|
134
|
+
}
|
|
135
|
+
/**
|
|
136
|
+
* Block the current thread for `ms` milliseconds — the sync sleep for the
|
|
137
|
+
* {@link lockStateWrite} retry loop. Prefers `Atomics.wait` on a shared
|
|
138
|
+
* integer (a real sleep); falls back to a busy spin when the primitive is
|
|
139
|
+
* unavailable. Plain JS — survives `fn.toString()` inlining.
|
|
140
|
+
*/
|
|
141
|
+
export function sleepSync(ms) {
|
|
142
|
+
try {
|
|
143
|
+
Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, ms);
|
|
144
|
+
return;
|
|
145
|
+
}
|
|
146
|
+
catch (error) {
|
|
147
|
+
// Atomics.wait unavailable in this host — spin below.
|
|
148
|
+
}
|
|
149
|
+
const end = Date.now() + ms;
|
|
150
|
+
while (Date.now() < end) {
|
|
151
|
+
// Spin — hook scripts must stay synchronous.
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
/**
|
|
155
|
+
* Cross-process state lock for the SELF-CONTAINED hook scripts (sync,
|
|
156
|
+
* no imports): exclusive `O_EXCL` lockfile at `statePath + '.lock'`,
|
|
157
|
+
* stale-TTL takeover (10s — crashed hook holders), and a retry loop
|
|
158
|
+
* (50ms × 40 ≈ 2s) while a live holder runs its critical section. The
|
|
159
|
+
* injected `fs` (real `node:fs` in generated scripts and the plugin,
|
|
160
|
+
* mocks in tests) performs the lockfile I/O and creates the parent
|
|
161
|
+
* directory. The injected `fn` runs inside the lock; the lockfile is
|
|
162
|
+
* ALWAYS removed in the `finally` block. `fn` failures propagate AFTER
|
|
163
|
+
* the release; lock exhaustion throws.
|
|
164
|
+
*/
|
|
165
|
+
export function lockStateWrite(statePath, fs, fn) {
|
|
166
|
+
const lockPath = `${statePath}.lock`;
|
|
167
|
+
const ttl = 10_000;
|
|
168
|
+
const retries = 40;
|
|
169
|
+
const dir = lockPath.replace(/\/[^/]+$/, '');
|
|
170
|
+
try {
|
|
171
|
+
fs.mkdirSync(dir);
|
|
172
|
+
}
|
|
173
|
+
catch (error) {
|
|
174
|
+
// Exists already — only the lockfile itself must be exclusive.
|
|
175
|
+
}
|
|
176
|
+
let acquired = false;
|
|
177
|
+
for (let attempt = 0; attempt < retries; attempt++) {
|
|
178
|
+
try {
|
|
179
|
+
fs.closeSync(fs.openSync(lockPath, 'wx'));
|
|
180
|
+
acquired = true;
|
|
181
|
+
break;
|
|
182
|
+
}
|
|
183
|
+
catch (error) {
|
|
184
|
+
let mtimeMs = 0;
|
|
185
|
+
try {
|
|
186
|
+
mtimeMs = fs.statSync(lockPath).mtimeMs;
|
|
187
|
+
}
|
|
188
|
+
catch (error) {
|
|
189
|
+
// Vanished between the failed create and the stat — retry at once.
|
|
190
|
+
}
|
|
191
|
+
if (Date.now() - mtimeMs > ttl) {
|
|
192
|
+
try {
|
|
193
|
+
fs.unlinkSync(lockPath);
|
|
194
|
+
}
|
|
195
|
+
catch (error) {
|
|
196
|
+
// Another waiter removed it first — retry from the top.
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
else {
|
|
200
|
+
sleepSync(50);
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
if (!acquired) {
|
|
205
|
+
throw new Error(`skillstate: could not acquire the state lock: ${lockPath}`);
|
|
206
|
+
}
|
|
207
|
+
try {
|
|
208
|
+
return fn();
|
|
209
|
+
}
|
|
210
|
+
finally {
|
|
211
|
+
try {
|
|
212
|
+
fs.unlinkSync(lockPath);
|
|
213
|
+
}
|
|
214
|
+
catch (error) {
|
|
215
|
+
// Lock already removed (stale takeover raced us) — nothing to release.
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
/**
|
|
220
|
+
* Paper ⊕ merge: `null` deletes a key, nested plain objects merge
|
|
221
|
+
* recursively, everything else replaces. Pure — neither `state` nor
|
|
222
|
+
* `patch` is mutated.
|
|
223
|
+
*/
|
|
224
|
+
export function mergePatch(state, patch) {
|
|
225
|
+
const result = { ...state };
|
|
226
|
+
for (const key of Object.keys(patch)) {
|
|
227
|
+
const value = patch[key];
|
|
228
|
+
if (value === null) {
|
|
229
|
+
delete result[key];
|
|
230
|
+
}
|
|
231
|
+
else if (isPlainObject(value) && isPlainObject(result[key])) {
|
|
232
|
+
result[key] = mergePatch(result[key], value);
|
|
233
|
+
}
|
|
234
|
+
else {
|
|
235
|
+
result[key] = value;
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
return result;
|
|
239
|
+
}
|
|
240
|
+
/**
|
|
241
|
+
* Coerce a tool response into text: strings pass through, plain objects
|
|
242
|
+
* expose their `content` then `text` string field, other objects are
|
|
243
|
+
* JSON-stringified, null/undefined becomes `""`, everything else is
|
|
244
|
+
* `String()`-ed.
|
|
245
|
+
*/
|
|
246
|
+
export function readResponseText(response) {
|
|
247
|
+
if (typeof response === 'string')
|
|
248
|
+
return response;
|
|
249
|
+
if (isPlainObject(response)) {
|
|
250
|
+
if (typeof response['content'] === 'string')
|
|
251
|
+
return response['content'];
|
|
252
|
+
if (typeof response['text'] === 'string')
|
|
253
|
+
return response['text'];
|
|
254
|
+
return JSON.stringify(response);
|
|
255
|
+
}
|
|
256
|
+
return response === null || response === undefined ? '' : String(response);
|
|
257
|
+
}
|
|
258
|
+
/**
|
|
259
|
+
* Look for a fenced ```json block: `{ patch }` when it parses and carries
|
|
260
|
+
* an object-shaped `state_patch`, `{ invalid: true }` when a block exists
|
|
261
|
+
* but is malformed (an open fence that never closes — truncated output —
|
|
262
|
+
* is still a patch attempt and classifies as invalid), `{ absent: true }`
|
|
263
|
+
* when there is no block at all.
|
|
264
|
+
*/
|
|
265
|
+
export function findFencedPatch(text) {
|
|
266
|
+
const match = text.match(/```json\s*\n?([\s\S]*?)\n?\s*```/) ||
|
|
267
|
+
text.match(/```json\s*\n?([\s\S]+)$/);
|
|
268
|
+
if (!match)
|
|
269
|
+
return { absent: true };
|
|
270
|
+
try {
|
|
271
|
+
const parsed = JSON.parse(match[1]);
|
|
272
|
+
if (isPlainObject(parsed) && isPlainObject(parsed['state_patch'])) {
|
|
273
|
+
return { patch: parsed['state_patch'] };
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
catch {
|
|
277
|
+
// Malformed fenced JSON — report an invalid patch attempt.
|
|
278
|
+
}
|
|
279
|
+
return { invalid: true };
|
|
280
|
+
}
|
|
281
|
+
/**
|
|
282
|
+
* Fallback: a raw JSON object with `state_patch` anywhere in the text
|
|
283
|
+
* (first `{` … last `}`). Ordinary JSON output without a `state_patch`
|
|
284
|
+
* key is simply not a patch (`{ absent: true }`); a `state_patch` key
|
|
285
|
+
* holding a non-object is an invalid attempt.
|
|
286
|
+
*/
|
|
287
|
+
export function findRawPatch(text) {
|
|
288
|
+
const trimmed = text.trim();
|
|
289
|
+
const candidates = [];
|
|
290
|
+
try {
|
|
291
|
+
candidates.push(JSON.parse(trimmed));
|
|
292
|
+
}
|
|
293
|
+
catch {
|
|
294
|
+
// Not a whole-text JSON object — try the braced slice below.
|
|
295
|
+
}
|
|
296
|
+
const first = trimmed.indexOf('{');
|
|
297
|
+
const last = trimmed.lastIndexOf('}');
|
|
298
|
+
if (first !== -1 && last > first) {
|
|
299
|
+
try {
|
|
300
|
+
candidates.push(JSON.parse(trimmed.slice(first, last + 1)));
|
|
301
|
+
}
|
|
302
|
+
catch {
|
|
303
|
+
// The braced slice is not JSON either — no candidates left.
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
for (const candidate of candidates) {
|
|
307
|
+
if (isPlainObject(candidate)) {
|
|
308
|
+
if (isPlainObject(candidate['state_patch'])) {
|
|
309
|
+
return { patch: candidate['state_patch'] };
|
|
310
|
+
}
|
|
311
|
+
if (Object.prototype.hasOwnProperty.call(candidate, 'state_patch')) {
|
|
312
|
+
return { invalid: true };
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
return { absent: true };
|
|
317
|
+
}
|
|
318
|
+
/**
|
|
319
|
+
* Read the session-meta sidecar's status (`<dir>/.session-meta.json`,
|
|
320
|
+
* sibling of the state file). Plain JS — inlined into the generated
|
|
321
|
+
* SessionStart hooks via `fn.toString()`. Returns the `status` string for
|
|
322
|
+
* a readable object-shaped sidecar, else `null` (missing/corrupt/other
|
|
323
|
+
* shape — no lifecycle marker). The `readFile` dependency is injected at
|
|
324
|
+
* the call site (real `node:fs` in hooks, mocks in tests).
|
|
325
|
+
*/
|
|
326
|
+
export function readSessionMetaStatus(metaPath, readFile) {
|
|
327
|
+
try {
|
|
328
|
+
const parsed = JSON.parse(readFile(metaPath));
|
|
329
|
+
if (isPlainObject(parsed) && typeof parsed.status === 'string') {
|
|
330
|
+
return parsed.status;
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
catch (error) {
|
|
334
|
+
// Missing or corrupt sidecar — no lifecycle marker.
|
|
335
|
+
}
|
|
336
|
+
return null;
|
|
337
|
+
}
|
|
338
|
+
/**
|
|
339
|
+
* Assemble the CJS snippet embedded into every generated hook script:
|
|
340
|
+
* all sibling functions of this module, source-verbatim via
|
|
341
|
+
* `fn.toString()`. The adapters splice this block after their `require`
|
|
342
|
+
* preamble, which keeps the embedded logic byte-identical across hosts
|
|
343
|
+
* and impossible to drift from this module.
|
|
344
|
+
*/
|
|
345
|
+
export function hookRuntimeSnippet() {
|
|
346
|
+
return [
|
|
347
|
+
isPlainObject,
|
|
348
|
+
resolveAgentIdFromSession,
|
|
349
|
+
sanitizeAgentId,
|
|
350
|
+
resolveStatePathForCwd,
|
|
351
|
+
readStateEnvelope,
|
|
352
|
+
saveStateEnvelope,
|
|
353
|
+
mergePatch,
|
|
354
|
+
readResponseText,
|
|
355
|
+
findFencedPatch,
|
|
356
|
+
findRawPatch,
|
|
357
|
+
sleepSync,
|
|
358
|
+
lockStateWrite,
|
|
359
|
+
readSessionMetaStatus,
|
|
360
|
+
]
|
|
361
|
+
.map((fn) => fn.toString())
|
|
362
|
+
.join('\n\n');
|
|
363
|
+
}
|
|
364
|
+
//# sourceMappingURL=hook-runtime.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hook-runtime.js","sourceRoot":"","sources":["../src/hook-runtime.ts"],"names":[],"mappings":"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"}
|
package/dist/host-state.d.ts
CHANGED
|
@@ -2,7 +2,8 @@
|
|
|
2
2
|
* Resolve the per-project state file for a working directory —
|
|
3
3
|
* `<cwd>/.skillstate/skillstate.json`, or the global bucket
|
|
4
4
|
* `<home>/.skillstate/global/skillstate.json` when cwd equals home
|
|
5
|
-
* (`home` defaults to `os.homedir()`).
|
|
5
|
+
* (`home` defaults to `os.homedir()`). A non-empty `agentId` scopes the
|
|
6
|
+
* file under `<bucket>/agents/<sanitized agentId>/skillstate.json`.
|
|
6
7
|
*/
|
|
7
|
-
export declare function resolveHostStateForCwd(cwd: string, home?: string): string;
|
|
8
|
+
export declare function resolveHostStateForCwd(cwd: string, home?: string, agentId?: string): string;
|
|
8
9
|
//# sourceMappingURL=host-state.d.ts.map
|
package/dist/host-state.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"host-state.d.ts","sourceRoot":"","sources":["../src/host-state.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"host-state.d.ts","sourceRoot":"","sources":["../src/host-state.ts"],"names":[],"mappings":"AAyBA;;;;;;GAMG;AACH,wBAAgB,sBAAsB,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,GAAG,MAAM,CAa3F"}
|
package/dist/host-state.js
CHANGED
|
@@ -1,31 +1,44 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @non-paper Wave-4 DX helper — the canonical per-project state resolver
|
|
3
3
|
* shared by every host adapter (OpenCode plugin, Codex hooks/fork-trim,
|
|
4
|
-
* Claude Code hooks).
|
|
4
|
+
* Claude Code hooks, MCP).
|
|
5
5
|
*
|
|
6
6
|
* Semantics: the state file for a working directory is
|
|
7
7
|
* `<cwd>/.skillstate/skillstate.json`; a session opened directly in the
|
|
8
8
|
* user's home resolves to the global bucket
|
|
9
|
-
* `<home>/.skillstate/global/skillstate.json`.
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
* the
|
|
9
|
+
* `<home>/.skillstate/global/skillstate.json`. AGENT-SCOPED STATE: a
|
|
10
|
+
* non-empty `agentId` (sanitized `[A-Za-z0-9_-]`, ≤64 chars) scopes the
|
|
11
|
+
* file under an isolated copy — `agents/<agentId>/skillstate.json` inside
|
|
12
|
+
* the same bucket — so 2-3 parallel sub-agents (hook sessions) never
|
|
13
|
+
* last-writer-win over each other; the main agent keeps the unscoped
|
|
14
|
+
* path and merges sub-agent copies explicitly (MCP `agent.merge`).
|
|
15
|
+
*
|
|
16
|
+
* Pure path arithmetic — no filesystem access. Host-embedded hook scripts
|
|
17
|
+
* (self-contained `.cjs`) keep a behavior-equivalent copy of this logic in
|
|
18
|
+
* the hook-runtime `resolveStatePathForCwd` because they must run without
|
|
19
|
+
* importing `@skillstate/*`; that function is the parity mirror. The agent
|
|
20
|
+
* id sanitizer is shared verbatim from the hook-runtime module.
|
|
14
21
|
*/
|
|
15
22
|
import * as os from 'node:os';
|
|
16
23
|
import * as path from 'node:path';
|
|
24
|
+
import { sanitizeAgentId } from './hook-runtime.js';
|
|
17
25
|
/**
|
|
18
26
|
* Resolve the per-project state file for a working directory —
|
|
19
27
|
* `<cwd>/.skillstate/skillstate.json`, or the global bucket
|
|
20
28
|
* `<home>/.skillstate/global/skillstate.json` when cwd equals home
|
|
21
|
-
* (`home` defaults to `os.homedir()`).
|
|
29
|
+
* (`home` defaults to `os.homedir()`). A non-empty `agentId` scopes the
|
|
30
|
+
* file under `<bucket>/agents/<sanitized agentId>/skillstate.json`.
|
|
22
31
|
*/
|
|
23
|
-
export function resolveHostStateForCwd(cwd, home) {
|
|
32
|
+
export function resolveHostStateForCwd(cwd, home, agentId) {
|
|
24
33
|
const resolvedCwd = path.resolve(cwd);
|
|
25
34
|
const resolvedHome = path.resolve(home ?? os.homedir());
|
|
26
|
-
|
|
27
|
-
|
|
35
|
+
const bucket = resolvedCwd === resolvedHome
|
|
36
|
+
? path.join(resolvedHome, '.skillstate', 'global')
|
|
37
|
+
: path.join(resolvedCwd, '.skillstate');
|
|
38
|
+
const agent = typeof agentId === 'string' && agentId.length > 0 ? sanitizeAgentId(agentId) : '';
|
|
39
|
+
if (agent.length > 0) {
|
|
40
|
+
return path.join(bucket, 'agents', agent, 'skillstate.json');
|
|
28
41
|
}
|
|
29
|
-
return path.join(
|
|
42
|
+
return path.join(bucket, 'skillstate.json');
|
|
30
43
|
}
|
|
31
44
|
//# sourceMappingURL=host-state.js.map
|
package/dist/host-state.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"host-state.js","sourceRoot":"","sources":["../src/host-state.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"host-state.js","sourceRoot":"","sources":["../src/host-state.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,OAAO,KAAK,EAAE,MAAM,SAAS,CAAC;AAC9B,OAAO,KAAK,IAAI,MAAM,WAAW,CAAC;AAClC,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAEpD;;;;;;GAMG;AACH,MAAM,UAAU,sBAAsB,CAAC,GAAW,EAAE,IAAa,EAAE,OAAgB;IACjF,MAAM,WAAW,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;IACtC,MAAM,YAAY,GAAG,IAAI,CAAC,OAAO,CAAC,IAAI,IAAI,EAAE,CAAC,OAAO,EAAE,CAAC,CAAC;IACxD,MAAM,MAAM,GACV,WAAW,KAAK,YAAY;QAC1B,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,YAAY,EAAE,aAAa,EAAE,QAAQ,CAAC;QAClD,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,aAAa,CAAC,CAAC;IAC5C,MAAM,KAAK,GACT,OAAO,OAAO,KAAK,QAAQ,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,eAAe,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;IACpF,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACrB,OAAO,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,QAAQ,EAAE,KAAK,EAAE,iBAAiB,CAAC,CAAC;IAC/D,CAAC;IACD,OAAO,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,iBAAiB,CAAC,CAAC;AAC9C,CAAC"}
|
package/dist/index.d.ts
CHANGED
|
@@ -16,6 +16,10 @@ export * from './logger.js';
|
|
|
16
16
|
export * from './provider.js';
|
|
17
17
|
export * from './config.js';
|
|
18
18
|
export * from './host-state.js';
|
|
19
|
+
export * from './hook-runtime.js';
|
|
20
|
+
export * from './adapter-shared.js';
|
|
21
|
+
export * from './prompt-contract.js';
|
|
19
22
|
export * from './shutdown.js';
|
|
23
|
+
export * from './session-meta.js';
|
|
20
24
|
export * from './schemas/index.js';
|
|
21
25
|
//# 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":"AAKA,cAAc,YAAY,CAAC;AAC3B,cAAc,oBAAoB,CAAC;AACnC,cAAc,yBAAyB,CAAC;AACxC,cAAc,oBAAoB,CAAC;AACnC,cAAc,cAAc,CAAC;AAC7B,cAAc,sBAAsB,CAAC;AAErC,cAAc,iBAAiB,CAAC;AAChC,cAAc,eAAe,CAAC;AAC9B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,mBAAmB,CAAC;AAElC,cAAc,YAAY,CAAC;AAC3B,cAAc,iBAAiB,CAAC;AAChC,cAAc,kBAAkB,CAAC;AACjC,cAAc,aAAa,CAAC;AAC5B,cAAc,aAAa,CAAC;AAE5B,cAAc,eAAe,CAAC;AAC9B,cAAc,aAAa,CAAC;AAC5B,cAAc,iBAAiB,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAKA,cAAc,YAAY,CAAC;AAC3B,cAAc,oBAAoB,CAAC;AACnC,cAAc,yBAAyB,CAAC;AACxC,cAAc,oBAAoB,CAAC;AACnC,cAAc,cAAc,CAAC;AAC7B,cAAc,sBAAsB,CAAC;AAErC,cAAc,iBAAiB,CAAC;AAChC,cAAc,eAAe,CAAC;AAC9B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,mBAAmB,CAAC;AAElC,cAAc,YAAY,CAAC;AAC3B,cAAc,iBAAiB,CAAC;AAChC,cAAc,kBAAkB,CAAC;AACjC,cAAc,aAAa,CAAC;AAC5B,cAAc,aAAa,CAAC;AAE5B,cAAc,eAAe,CAAC;AAC9B,cAAc,aAAa,CAAC;AAC5B,cAAc,iBAAiB,CAAC;AAGhC,cAAc,mBAAmB,CAAC;AAGlC,cAAc,qBAAqB,CAAC;AAEpC,cAAc,sBAAsB,CAAC;AACrC,cAAc,eAAe,CAAC;AAE9B,cAAc,mBAAmB,CAAC;AAClC,cAAc,oBAAoB,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -24,6 +24,16 @@ export * from './logger.js';
|
|
|
24
24
|
export * from './provider.js';
|
|
25
25
|
export * from './config.js';
|
|
26
26
|
export * from './host-state.js';
|
|
27
|
+
// @non-paper Wave-5 hook runtime (single source of truth for generated
|
|
28
|
+
// hook scripts and the OpenCode plugin).
|
|
29
|
+
export * from './hook-runtime.js';
|
|
30
|
+
// @non-paper Wave-5 shared adapter plumbing (resolve/save/merge helpers
|
|
31
|
+
// reused by the claude/codex adapters).
|
|
32
|
+
export * from './adapter-shared.js';
|
|
33
|
+
// @non-paper Wave-5 deduplicated prompt texts (shared adapter vocabulary).
|
|
34
|
+
export * from './prompt-contract.js';
|
|
27
35
|
export * from './shutdown.js';
|
|
36
|
+
// @non-paper release-2.3.0 session lifecycle marker (orchestration meta).
|
|
37
|
+
export * from './session-meta.js';
|
|
28
38
|
export * from './schemas/index.js';
|
|
29
39
|
//# 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,qCAAqC;AACrC,EAAE;AACF,0EAA0E;AAC1E,6EAA6E;AAC7E,qDAAqD;AACrD,cAAc,YAAY,CAAC;AAC3B,cAAc,oBAAoB,CAAC;AACnC,cAAc,yBAAyB,CAAC;AACxC,cAAc,oBAAoB,CAAC;AACnC,cAAc,cAAc,CAAC;AAC7B,cAAc,sBAAsB,CAAC;AACrC,qEAAqE;AACrE,cAAc,iBAAiB,CAAC;AAChC,cAAc,eAAe,CAAC;AAC9B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,mBAAmB,CAAC;AAClC,0EAA0E;AAC1E,cAAc,YAAY,CAAC;AAC3B,cAAc,iBAAiB,CAAC;AAChC,cAAc,kBAAkB,CAAC;AACjC,cAAc,aAAa,CAAC;AAC5B,cAAc,aAAa,CAAC;AAC5B,mDAAmD;AACnD,cAAc,eAAe,CAAC;AAC9B,cAAc,aAAa,CAAC;AAC5B,cAAc,iBAAiB,CAAC;AAChC,cAAc,eAAe,CAAC;AAC9B,cAAc,oBAAoB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,qCAAqC;AACrC,EAAE;AACF,0EAA0E;AAC1E,6EAA6E;AAC7E,qDAAqD;AACrD,cAAc,YAAY,CAAC;AAC3B,cAAc,oBAAoB,CAAC;AACnC,cAAc,yBAAyB,CAAC;AACxC,cAAc,oBAAoB,CAAC;AACnC,cAAc,cAAc,CAAC;AAC7B,cAAc,sBAAsB,CAAC;AACrC,qEAAqE;AACrE,cAAc,iBAAiB,CAAC;AAChC,cAAc,eAAe,CAAC;AAC9B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,mBAAmB,CAAC;AAClC,0EAA0E;AAC1E,cAAc,YAAY,CAAC;AAC3B,cAAc,iBAAiB,CAAC;AAChC,cAAc,kBAAkB,CAAC;AACjC,cAAc,aAAa,CAAC;AAC5B,cAAc,aAAa,CAAC;AAC5B,mDAAmD;AACnD,cAAc,eAAe,CAAC;AAC9B,cAAc,aAAa,CAAC;AAC5B,cAAc,iBAAiB,CAAC;AAChC,uEAAuE;AACvE,yCAAyC;AACzC,cAAc,mBAAmB,CAAC;AAClC,wEAAwE;AACxE,wCAAwC;AACxC,cAAc,qBAAqB,CAAC;AACpC,2EAA2E;AAC3E,cAAc,sBAAsB,CAAC;AACrC,cAAc,eAAe,CAAC;AAC9B,0EAA0E;AAC1E,cAAc,mBAAmB,CAAC;AAClC,cAAc,oBAAoB,CAAC"}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @non-paper Canonical prompt texts — the SINGLE SOURCE OF TRUTH for the
|
|
3
|
+
* {state_patch, action} JSON contract, the history-unreliability hint, the
|
|
4
|
+
* schema renderer, and the SKILL.md body shared by every platform adapter.
|
|
5
|
+
*
|
|
6
|
+
* PROMPT-FIDELITY BOUNDARY: `PromptTransformer.formatPaper` (Appendix A.4)
|
|
7
|
+
* is byte-verbatim paper text and deliberately does NOT use these
|
|
8
|
+
* constants — its inline `{ "state_patch": { <dict: ...> }, "action": ... }`
|
|
9
|
+
* directive differs from the fenced example below by design. Everything
|
|
10
|
+
* here is the @non-paper adapter vocabulary, deduplicated across
|
|
11
|
+
* claude/codex/opencode adapters and the prompt transformer.
|
|
12
|
+
*/
|
|
13
|
+
import type { ProceduralSpec, StateSchema } from './types.js';
|
|
14
|
+
/**
|
|
15
|
+
* The two-key response directive (without the fenced example). Adapters
|
|
16
|
+
* prepend their own lead-in ("Based on your current state, provide your
|
|
17
|
+
* response with:" etc.) and append the numbered items via
|
|
18
|
+
* {@link STATE_PATCH_CONTRACT}.
|
|
19
|
+
*/
|
|
20
|
+
export declare const STATE_PATCH_CONTRACT_HEADER = "A JSON block containing both your State Patch and your Action. The JSON block MUST have exactly these two keys:";
|
|
21
|
+
/** Canonical fenced ```json example block for the two-key contract. */
|
|
22
|
+
export declare const STATE_PATCH_EXAMPLE_JSON: string;
|
|
23
|
+
/** Canonical sparse-patch rules: null deletes, omissions leave state unchanged. */
|
|
24
|
+
export declare const STATE_PATCH_RULES = "In `state_patch`, set keys to null to delete them. Only include fields you want to change. Omit fields to leave them unchanged.";
|
|
25
|
+
/**
|
|
26
|
+
* The reasoning-is-discarded persistence bullet (paper §3.2, §4): any fact
|
|
27
|
+
* that must survive belongs in `state_patch`, never in the conversation.
|
|
28
|
+
*/
|
|
29
|
+
export declare const REASONING_DISCARDED_NOTE = "Reasoning is discarded after execution \u2014 put anything you need to persist into `state_patch`.";
|
|
30
|
+
/**
|
|
31
|
+
* The full numbered response contract: reasoning is discarded (paper §3.2),
|
|
32
|
+
* the JSON block carries exactly the two keys, and the patch follows the
|
|
33
|
+
* sparse ⊕ semantics. Includes the example block and the rules — no lead-in.
|
|
34
|
+
*/
|
|
35
|
+
export declare const STATE_PATCH_CONTRACT: string;
|
|
36
|
+
/**
|
|
37
|
+
* The single history-unreliability hint appended to the additionalContext
|
|
38
|
+
* of every inject-style hook script (claude + codex alike). Names the MCP
|
|
39
|
+
* tools AND the fenced ```json state_patch channel — one text for all
|
|
40
|
+
* hosts, so the Bash-carried patch option can no longer drift away.
|
|
41
|
+
*/
|
|
42
|
+
export declare const HISTORY_UNRELIABLE_NOTE = "\nHistory is not reliable. Persist anything you need via the skillstate MCP tools (state.summary / state.patch) or a fenced ```json state_patch block.";
|
|
43
|
+
/**
|
|
44
|
+
* The interrupted-session hint injected by the SessionStart hooks
|
|
45
|
+
* (claude + codex alike) when the session-meta sidecar carries
|
|
46
|
+
* `status: "interrupted"` — a previous run of this session was killed
|
|
47
|
+
* (SIGINT/SIGTERM) mid-procedure. The hook appends the preserved state
|
|
48
|
+
* path so the agent can review progress/blockers before continuing.
|
|
49
|
+
* A fresh launch overwrites the status back to `running`.
|
|
50
|
+
*/
|
|
51
|
+
export declare const INTERRUPTED_SESSION_NOTE = "\nPrevious session was interrupted; state preserved at <path>; review progress/blockers before continuing.";
|
|
52
|
+
/**
|
|
53
|
+
* Render a state schema as the shared `## Schema` markdown block used by
|
|
54
|
+
* every prompt formatter and adapter `injectState`. Fields without a
|
|
55
|
+
* description fall back to "no description".
|
|
56
|
+
*/
|
|
57
|
+
export declare function describeSchema(schema: StateSchema): string;
|
|
58
|
+
/** Options for {@link skillMdBody}. */
|
|
59
|
+
export interface SkillMdBodyOptions {
|
|
60
|
+
/** Brand label woven into the hooks intro ("Claude Code", "Codex"). */
|
|
61
|
+
hostLabel: string;
|
|
62
|
+
/**
|
|
63
|
+
* How the injected state reaches the model, as a predicate:
|
|
64
|
+
* "injected into your context via hooks" (claude) /
|
|
65
|
+
* "provided as developer context" (codex).
|
|
66
|
+
*/
|
|
67
|
+
injectionPhrase: string;
|
|
68
|
+
/** The skill spec — name/instructions/version fill the frontmatter. */
|
|
69
|
+
spec: ProceduralSpec;
|
|
70
|
+
/** State path written into the frontmatter and the body (default `./.skillstate/skillstate.json`). */
|
|
71
|
+
statePath?: string;
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Generate the whole SKILL.md document shared by the hook-wiring adapters
|
|
75
|
+
* (claude, codex): identical frontmatter, Execution Context, and Process
|
|
76
|
+
* sections; the ONLY brand-specific parts are `hostLabel` (hooks intro)
|
|
77
|
+
* and `injectionPhrase` (how the state reaches the model). OpenCode keeps
|
|
78
|
+
* its own body — its history is trimmed by the plugin, not by hooks, so
|
|
79
|
+
* its Execution Context and Process genuinely differ.
|
|
80
|
+
*/
|
|
81
|
+
export declare function skillMdBody(options: SkillMdBodyOptions): string;
|
|
82
|
+
//# sourceMappingURL=prompt-contract.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"prompt-contract.d.ts","sourceRoot":"","sources":["../src/prompt-contract.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AACH,OAAO,KAAK,EAAE,cAAc,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAE9D;;;;;GAKG;AACH,eAAO,MAAM,2BAA2B,oHAC2E,CAAC;AAEpH,uEAAuE;AACvE,eAAO,MAAM,wBAAwB,QAOzB,CAAC;AAEb,mFAAmF;AACnF,eAAO,MAAM,iBAAiB,oIACqG,CAAC;AAEpI;;;GAGG;AACH,eAAO,MAAM,wBAAwB,uGAC4D,CAAC;AAElG;;;;GAIG;AACH,eAAO,MAAM,oBAAoB,QAOrB,CAAC;AAEb;;;;;GAKG;AACH,eAAO,MAAM,uBAAuB,2JACsH,CAAC;AAE3J;;;;;;;GAOG;AACH,eAAO,MAAM,wBAAwB,+GACyE,CAAC;AAE/G;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,WAAW,GAAG,MAAM,CAQ1D;AAED,uCAAuC;AACvC,MAAM,WAAW,kBAAkB;IACjC,uEAAuE;IACvE,SAAS,EAAE,MAAM,CAAC;IAClB;;;;OAIG;IACH,eAAe,EAAE,MAAM,CAAC;IACxB,uEAAuE;IACvE,IAAI,EAAE,cAAc,CAAC;IACrB,sGAAsG;IACtG,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED;;;;;;;GAOG;AACH,wBAAgB,WAAW,CAAC,OAAO,EAAE,kBAAkB,GAAG,MAAM,CAwD/D"}
|