@skillstate/claude 2.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/dist/claude-adapter.d.ts +77 -0
- package/dist/claude-adapter.d.ts.map +1 -0
- package/dist/claude-adapter.js +323 -0
- package/dist/claude-adapter.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +3 -0
- package/dist/index.js.map +1 -0
- package/package.json +24 -0
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @non-paper adapter — no adapters exist in arXiv 2608.26263v3.
|
|
3
|
+
*
|
|
4
|
+
* This file bridges the paper-exact core (Algorithm 1 prompt, ⊕ merge,
|
|
5
|
+
* §7 rollback-retry rejection) into Claude Code sessions via hook scripts
|
|
6
|
+
* and prompt boilerplate.
|
|
7
|
+
*
|
|
8
|
+
* LIMITATION: Claude Code hooks are append-only — history cannot be trimmed
|
|
9
|
+
* from hooks. The best strategy is: PreCompact injects state into the
|
|
10
|
+
* compaction summary, SessionStart(source:compact) re-injects state after
|
|
11
|
+
* compaction. True O(1) is not possible without host-side trimming.
|
|
12
|
+
*/
|
|
13
|
+
import type { SkillState, StatePatch, ProceduralSpec, Observation, PlatformAdapter } from '@skillstate/core';
|
|
14
|
+
import type { StatePathRef } from '@skillstate/core';
|
|
15
|
+
export declare class ClaudeAdapter implements PlatformAdapter {
|
|
16
|
+
readonly name = "claude";
|
|
17
|
+
private transformer;
|
|
18
|
+
injectState(state: SkillState, spec: ProceduralSpec): string;
|
|
19
|
+
extractPatch(response: string): StatePatch | null;
|
|
20
|
+
extractAction(response: string): string | null;
|
|
21
|
+
/**
|
|
22
|
+
* @non-paper — adapter convenience (delegates to the transformer).
|
|
23
|
+
* Paper-exact callers use `PromptTransformer.formatPaper` (Appendix A.4).
|
|
24
|
+
*/
|
|
25
|
+
formatPrompt(state: SkillState, observation: Observation, spec: ProceduralSpec): string;
|
|
26
|
+
generateHookScript(eventType: 'PreToolUse' | 'PostToolUse', statePath: string, schema?: ProceduralSpec['schema']): string;
|
|
27
|
+
/**
|
|
28
|
+
* @non-paper additive overload: accept a `{ root, name }` ref confined
|
|
29
|
+
* via `resolveStatePath` — `..` escapes throw instead of embedding an
|
|
30
|
+
* unsafe path into the generated script. The string overload above is
|
|
31
|
+
* byte-identical to the pre-wave-2 codegen.
|
|
32
|
+
*/
|
|
33
|
+
generateHookScript(eventType: 'PreToolUse' | 'PostToolUse', stateRef: StatePathRef, schema?: ProceduralSpec['schema']): string;
|
|
34
|
+
/**
|
|
35
|
+
* @non-paper additive helper: generate a hook script and persist it via
|
|
36
|
+
* `atomicWriteFile` (tmp + fsync + rename). Both the destination and the
|
|
37
|
+
* embedded state path accept raw strings (legacy behavior) or
|
|
38
|
+
* `{ root, name }` refs confined by `resolveStatePath`. Returns the
|
|
39
|
+
* absolute destination path.
|
|
40
|
+
*/
|
|
41
|
+
saveHookScript(target: string | StatePathRef, eventType: 'PreToolUse' | 'PostToolUse', statePath: string | StatePathRef, schema?: ProceduralSpec['schema']): Promise<string>;
|
|
42
|
+
/**
|
|
43
|
+
* Generate a PreCompact hook script that injects the current skill state
|
|
44
|
+
* into the compaction summary. Also tracks what changed since the last
|
|
45
|
+
* compact to provide a diff in additionalContext.
|
|
46
|
+
*
|
|
47
|
+
* The script reads `.skillstate.json`, reads the previous compact snapshot
|
|
48
|
+
* from `.skillstate.last-compact.json` (if it exists), computes a diff,
|
|
49
|
+
* and injects the current state + diff into additionalContext. After
|
|
50
|
+
* injection it saves the current state as the new compact snapshot.
|
|
51
|
+
*/
|
|
52
|
+
generateCompactHookScript(statePath: string, schema?: ProceduralSpec['schema']): string;
|
|
53
|
+
generateCompactHookScript(stateRef: StatePathRef, schema?: ProceduralSpec['schema']): string;
|
|
54
|
+
/**
|
|
55
|
+
* Generate a SessionStart hook script that re-injects state after
|
|
56
|
+
* compaction. The hook uses a matcher for `source: "compact"` so it
|
|
57
|
+
* only fires when the session was resumed from a compacted state.
|
|
58
|
+
*/
|
|
59
|
+
generateSessionStartHookScript(statePath: string): string;
|
|
60
|
+
generateSessionStartHookScript(stateRef: StatePathRef): string;
|
|
61
|
+
/**
|
|
62
|
+
* Convenience: generate both compact-related hooks at once.
|
|
63
|
+
* Returns `{ preCompact, sessionStartCompact }` — write each to a
|
|
64
|
+
* `.cjs` file and register in Claude Code settings.
|
|
65
|
+
*/
|
|
66
|
+
generateAllHooksScripts(statePath: string, schema?: ProceduralSpec['schema']): {
|
|
67
|
+
preCompact: string;
|
|
68
|
+
sessionStartCompact: string;
|
|
69
|
+
};
|
|
70
|
+
generateAllHooksScripts(stateRef: StatePathRef, schema?: ProceduralSpec['schema']): {
|
|
71
|
+
preCompact: string;
|
|
72
|
+
sessionStartCompact: string;
|
|
73
|
+
};
|
|
74
|
+
generateAppendPrompt(): string;
|
|
75
|
+
private describeSchema;
|
|
76
|
+
}
|
|
77
|
+
//# sourceMappingURL=claude-adapter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"claude-adapter.d.ts","sourceRoot":"","sources":["../src/claude-adapter.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AACH,OAAO,KAAK,EACV,UAAU,EACV,UAAU,EACV,cAAc,EACd,WAAW,EACX,eAAe,EAChB,MAAM,kBAAkB,CAAC;AAM1B,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAErD,qBAAa,aAAc,YAAW,eAAe;IACnD,QAAQ,CAAC,IAAI,YAAY;IAEzB,OAAO,CAAC,WAAW,CAAiD;IAEpE,WAAW,CAAC,KAAK,EAAE,UAAU,EAAE,IAAI,EAAE,cAAc,GAAG,MAAM,CA+B3D;IAED,YAAY,CAAC,QAAQ,EAAE,MAAM,GAAG,UAAU,GAAG,IAAI,CAEhD;IAED,aAAa,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAE7C;IAED;;;OAGG;IACH,YAAY,CACV,KAAK,EAAE,UAAU,EACjB,WAAW,EAAE,WAAW,EACxB,IAAI,EAAE,cAAc,GACnB,MAAM,CAER;IAED,kBAAkB,CAChB,SAAS,EAAE,YAAY,GAAG,aAAa,EACvC,SAAS,EAAE,MAAM,EACjB,MAAM,CAAC,EAAE,cAAc,CAAC,QAAQ,CAAC,GAChC,MAAM,CAAC;IACV;;;;;OAKG;IACH,kBAAkB,CAChB,SAAS,EAAE,YAAY,GAAG,aAAa,EACvC,QAAQ,EAAE,YAAY,EACtB,MAAM,CAAC,EAAE,cAAc,CAAC,QAAQ,CAAC,GAChC,MAAM,CAAC;IAmJV;;;;;;OAMG;IACG,cAAc,CAClB,MAAM,EAAE,MAAM,GAAG,YAAY,EAC7B,SAAS,EAAE,YAAY,GAAG,aAAa,EACvC,SAAS,EAAE,MAAM,GAAG,YAAY,EAChC,MAAM,CAAC,EAAE,cAAc,CAAC,QAAQ,CAAC,GAChC,OAAO,CAAC,MAAM,CAAC,CAYjB;IAED;;;;;;;;;OASG;IACH,yBAAyB,CAAC,SAAS,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,cAAc,CAAC,QAAQ,CAAC,GAAG,MAAM,CAAC;IACxF,yBAAyB,CAAC,QAAQ,EAAE,YAAY,EAAE,MAAM,CAAC,EAAE,cAAc,CAAC,QAAQ,CAAC,GAAG,MAAM,CAAC;IAuE7F;;;;OAIG;IACH,8BAA8B,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAAC;IAC1D,8BAA8B,CAAC,QAAQ,EAAE,YAAY,GAAG,MAAM,CAAC;IA6B/D;;;;OAIG;IACH,uBAAuB,CACrB,SAAS,EAAE,MAAM,EACjB,MAAM,CAAC,EAAE,cAAc,CAAC,QAAQ,CAAC,GAChC;QAAE,UAAU,EAAE,MAAM,CAAC;QAAC,mBAAmB,EAAE,MAAM,CAAA;KAAE,CAAC;IACvD,uBAAuB,CACrB,QAAQ,EAAE,YAAY,EACtB,MAAM,CAAC,EAAE,cAAc,CAAC,QAAQ,CAAC,GAChC;QAAE,UAAU,EAAE,MAAM,CAAC;QAAC,mBAAmB,EAAE,MAAM,CAAA;KAAE,CAAC;IAWvD,oBAAoB,IAAI,MAAM,CAe7B;IAED,OAAO,CAAC,cAAc;CASvB"}
|
|
@@ -0,0 +1,323 @@
|
|
|
1
|
+
import { PromptTransformer } from '@skillstate/core';
|
|
2
|
+
import { atomicWriteFile, resolveStatePath, } from '@skillstate/core';
|
|
3
|
+
export class ClaudeAdapter {
|
|
4
|
+
name = 'claude';
|
|
5
|
+
transformer = new PromptTransformer({ platform: 'claude' });
|
|
6
|
+
injectState(state, spec) {
|
|
7
|
+
const stateJson = JSON.stringify(state);
|
|
8
|
+
const schemaDesc = this.describeSchema(spec.schema);
|
|
9
|
+
return `# System
|
|
10
|
+
|
|
11
|
+
You are ${spec.name}. ${spec.instructions}
|
|
12
|
+
|
|
13
|
+
${schemaDesc}
|
|
14
|
+
|
|
15
|
+
# Current State
|
|
16
|
+
|
|
17
|
+
\`\`\`json
|
|
18
|
+
${stateJson}
|
|
19
|
+
\`\`\`
|
|
20
|
+
|
|
21
|
+
# Instructions
|
|
22
|
+
|
|
23
|
+
Based on your current state, provide your response with:
|
|
24
|
+
|
|
25
|
+
1. Step-by-step reasoning (will be discarded after execution)
|
|
26
|
+
2. A JSON block containing both your State Patch and your Action. The JSON block MUST have exactly these two keys:
|
|
27
|
+
|
|
28
|
+
\`\`\`json
|
|
29
|
+
{
|
|
30
|
+
"state_patch": { "key": "new_value", "obsolete_key": null },
|
|
31
|
+
"action": "your_action_here"
|
|
32
|
+
}
|
|
33
|
+
\`\`\`
|
|
34
|
+
|
|
35
|
+
In \`state_patch\`, set keys to null to delete them. Only include fields you want to change. Omit fields to leave them unchanged.`;
|
|
36
|
+
}
|
|
37
|
+
extractPatch(response) {
|
|
38
|
+
return this.transformer.extractStatePatch(response);
|
|
39
|
+
}
|
|
40
|
+
extractAction(response) {
|
|
41
|
+
return this.transformer.extractAction(response);
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* @non-paper — adapter convenience (delegates to the transformer).
|
|
45
|
+
* Paper-exact callers use `PromptTransformer.formatPaper` (Appendix A.4).
|
|
46
|
+
*/
|
|
47
|
+
formatPrompt(state, observation, spec) {
|
|
48
|
+
return this.transformer.formatForClaude(spec, state, observation);
|
|
49
|
+
}
|
|
50
|
+
generateHookScript(eventType, statePathOrRef, schema) {
|
|
51
|
+
const statePath = typeof statePathOrRef === 'string'
|
|
52
|
+
? statePathOrRef
|
|
53
|
+
: resolveStatePath(statePathOrRef.root, statePathOrRef.name);
|
|
54
|
+
const sp = JSON.stringify(statePath);
|
|
55
|
+
if (eventType === 'PreToolUse') {
|
|
56
|
+
return [
|
|
57
|
+
'// Claude hook: PreToolUse',
|
|
58
|
+
'// Reads skill state and injects it into the tool\'s additionalContext.',
|
|
59
|
+
'// ADDITIVE: the host history is left untouched, so this alone does not',
|
|
60
|
+
'// reproduce the paper O(1) footprint (see module doc).',
|
|
61
|
+
'const fs = require("fs");',
|
|
62
|
+
'const stateFilePath = ' + sp + ';',
|
|
63
|
+
'let state = {};',
|
|
64
|
+
'try {',
|
|
65
|
+
' if (fs.existsSync(stateFilePath)) {',
|
|
66
|
+
' state = JSON.parse(fs.readFileSync(stateFilePath, "utf-8"));',
|
|
67
|
+
' }',
|
|
68
|
+
'} catch (e) { state = {}; }',
|
|
69
|
+
'const stateJson = JSON.stringify(state);',
|
|
70
|
+
'const output = {',
|
|
71
|
+
' hookSpecificOutput: {',
|
|
72
|
+
' additionalContext: "Current skill state (JSON): " + stateJson',
|
|
73
|
+
' }',
|
|
74
|
+
'};',
|
|
75
|
+
'process.stdout.write(JSON.stringify(output));',
|
|
76
|
+
].join('\n');
|
|
77
|
+
}
|
|
78
|
+
// PostToolUse — schema-validated null-deletion merge. Malformed outputs
|
|
79
|
+
// are rejected and never persisted (paper Limitations: malformed outputs
|
|
80
|
+
// cannot corrupt Σt). Self-contained CommonJS (hook scripts run via
|
|
81
|
+
// `node script.cjs`). The schema is embedded so unknown keys / wrong
|
|
82
|
+
// types are rejected here instead of corrupting the persisted state.
|
|
83
|
+
const fence = '`' + '`' + '`';
|
|
84
|
+
const schemaJson = JSON.stringify(schema ?? {});
|
|
85
|
+
return [
|
|
86
|
+
'// Claude hook: PostToolUse',
|
|
87
|
+
'// Extracts state_patch from the assistant\'s response, validates it against',
|
|
88
|
+
'// the embedded schema, applies the null-deletion merge, and saves.',
|
|
89
|
+
'const fs = require("fs");',
|
|
90
|
+
'const stateFilePath = ' + sp + ';',
|
|
91
|
+
'const schema = ' + schemaJson + ';',
|
|
92
|
+
'',
|
|
93
|
+
'function isPlainObject(v) {',
|
|
94
|
+
' return typeof v === "object" && v !== null && !Array.isArray(v);',
|
|
95
|
+
'}',
|
|
96
|
+
'',
|
|
97
|
+
'// ⊕ merge from the paper: null deletes a key, plain objects merge',
|
|
98
|
+
'// recursively, everything else overwrites. Never mutates `base` —',
|
|
99
|
+
'// builds and returns a copy.',
|
|
100
|
+
'function mergePatch(base, patch) {',
|
|
101
|
+
' function mergeInto(result, patchObj) {',
|
|
102
|
+
' for (const key of Object.keys(patchObj)) {',
|
|
103
|
+
' const value = patchObj[key];',
|
|
104
|
+
' if (value === null) {',
|
|
105
|
+
' delete result[key];',
|
|
106
|
+
' } else if (isPlainObject(value) && isPlainObject(result[key])) {',
|
|
107
|
+
' result[key] = mergeInto({ ...result[key] }, value);',
|
|
108
|
+
' } else {',
|
|
109
|
+
' result[key] = value;',
|
|
110
|
+
' }',
|
|
111
|
+
' }',
|
|
112
|
+
' return result;',
|
|
113
|
+
' }',
|
|
114
|
+
' return mergeInto({ ...base }, patch);',
|
|
115
|
+
'}',
|
|
116
|
+
'',
|
|
117
|
+
'// Schema validation: unknown keys rejected; null is always valid (deletion).',
|
|
118
|
+
'function validatePatchAgainstSchema(patch) {',
|
|
119
|
+
' for (const key of Object.keys(patch)) {',
|
|
120
|
+
' const field = schema[key];',
|
|
121
|
+
' if (!field) {',
|
|
122
|
+
' return "Unknown key: " + key;',
|
|
123
|
+
' }',
|
|
124
|
+
' const value = patch[key];',
|
|
125
|
+
' if (value === null) continue;',
|
|
126
|
+
' const expected = field.type;',
|
|
127
|
+
' let ok = false;',
|
|
128
|
+
' if (expected === "string") ok = typeof value === "string";',
|
|
129
|
+
' else if (expected === "number") ok = typeof value === "number";',
|
|
130
|
+
' else if (expected === "boolean") ok = typeof value === "boolean";',
|
|
131
|
+
' else if (expected === "array") ok = Array.isArray(value);',
|
|
132
|
+
' else if (expected === "object") ok = isPlainObject(value);',
|
|
133
|
+
' if (!ok) {',
|
|
134
|
+
' return "Invalid type for field \'" + key + "\': expected " + expected +',
|
|
135
|
+
' ", got " + (Array.isArray(value) ? "array" : typeof value);',
|
|
136
|
+
' }',
|
|
137
|
+
' }',
|
|
138
|
+
' return null;',
|
|
139
|
+
'}',
|
|
140
|
+
'',
|
|
141
|
+
'let state = {};',
|
|
142
|
+
'try {',
|
|
143
|
+
' if (fs.existsSync(stateFilePath)) {',
|
|
144
|
+
' state = JSON.parse(fs.readFileSync(stateFilePath, "utf-8"));',
|
|
145
|
+
' }',
|
|
146
|
+
'} catch (e) { state = {}; }',
|
|
147
|
+
'let input = "";',
|
|
148
|
+
'process.stdin.setEncoding("utf-8");',
|
|
149
|
+
'process.stdin.on("data", (chunk) => { input += chunk; });',
|
|
150
|
+
'process.stdin.on("end", () => {',
|
|
151
|
+
' const output = {};',
|
|
152
|
+
' try {',
|
|
153
|
+
' const parsed = JSON.parse(input);',
|
|
154
|
+
' const content = parsed.tool_response || parsed.content || "";',
|
|
155
|
+
' const re = /' + fence + 'json\\s*\\n?([\\s\\S]*?)\\n?\\s*' + fence + '/;',
|
|
156
|
+
' const match = content.match(re);',
|
|
157
|
+
' if (match) {',
|
|
158
|
+
' // Guarded parse: malformed JSON inside the fence leaves state untouched.',
|
|
159
|
+
' let json;',
|
|
160
|
+
' try {',
|
|
161
|
+
' json = JSON.parse(match[1]);',
|
|
162
|
+
' } catch (parseError) {',
|
|
163
|
+
' output.error = "Malformed JSON in state patch block: " + parseError.message;',
|
|
164
|
+
' process.stdout.write(JSON.stringify(output));',
|
|
165
|
+
' return;',
|
|
166
|
+
' }',
|
|
167
|
+
' if (json.state_patch && typeof json.state_patch === "object" && !Array.isArray(json.state_patch)) {',
|
|
168
|
+
' const validationError = validatePatchAgainstSchema(json.state_patch);',
|
|
169
|
+
' if (validationError) {',
|
|
170
|
+
' // Reject: report the error, never write state.',
|
|
171
|
+
' output.error = validationError;',
|
|
172
|
+
' process.stdout.write(JSON.stringify(output));',
|
|
173
|
+
' return;',
|
|
174
|
+
' }',
|
|
175
|
+
' state = mergePatch(state, json.state_patch);',
|
|
176
|
+
' fs.writeFileSync(stateFilePath, JSON.stringify(state, null, 2));',
|
|
177
|
+
' }',
|
|
178
|
+
' }',
|
|
179
|
+
' } catch (e) {',
|
|
180
|
+
' // Malformed stdin JSON or unexpected failure: state stays untouched.',
|
|
181
|
+
' output.error = "Failed to process PostToolUse input: " + e.message;',
|
|
182
|
+
' }',
|
|
183
|
+
' process.stdout.write(JSON.stringify(output));',
|
|
184
|
+
'});',
|
|
185
|
+
].join('\n');
|
|
186
|
+
}
|
|
187
|
+
/**
|
|
188
|
+
* @non-paper additive helper: generate a hook script and persist it via
|
|
189
|
+
* `atomicWriteFile` (tmp + fsync + rename). Both the destination and the
|
|
190
|
+
* embedded state path accept raw strings (legacy behavior) or
|
|
191
|
+
* `{ root, name }` refs confined by `resolveStatePath`. Returns the
|
|
192
|
+
* absolute destination path.
|
|
193
|
+
*/
|
|
194
|
+
async saveHookScript(target, eventType, statePath, schema) {
|
|
195
|
+
const dest = typeof target === 'string'
|
|
196
|
+
? target
|
|
197
|
+
: resolveStatePath(target.root, target.name);
|
|
198
|
+
const resolvedState = typeof statePath === 'string'
|
|
199
|
+
? statePath
|
|
200
|
+
: resolveStatePath(statePath.root, statePath.name);
|
|
201
|
+
const script = this.generateHookScript(eventType, resolvedState, schema);
|
|
202
|
+
await atomicWriteFile(dest, script);
|
|
203
|
+
return dest;
|
|
204
|
+
}
|
|
205
|
+
generateCompactHookScript(statePathOrRef, schema) {
|
|
206
|
+
const statePath = typeof statePathOrRef === 'string'
|
|
207
|
+
? statePathOrRef
|
|
208
|
+
: resolveStatePath(statePathOrRef.root, statePathOrRef.name);
|
|
209
|
+
const sp = JSON.stringify(statePath);
|
|
210
|
+
const schemaJson = JSON.stringify(schema ?? {});
|
|
211
|
+
const lastCompactPath = JSON.stringify(statePath + '.last-compact.json');
|
|
212
|
+
return [
|
|
213
|
+
'// Claude hook: PreCompact',
|
|
214
|
+
'// Injects the current skill state into the compaction summary.',
|
|
215
|
+
'// Tracks diff since last compact for incremental context.',
|
|
216
|
+
'const fs = require("fs");',
|
|
217
|
+
'const stateFilePath = ' + sp + ';',
|
|
218
|
+
'const lastCompactFilePath = ' + lastCompactPath + ';',
|
|
219
|
+
'const schema = ' + schemaJson + ';',
|
|
220
|
+
'',
|
|
221
|
+
'function readJsonSafe(filePath) {',
|
|
222
|
+
' try {',
|
|
223
|
+
' if (fs.existsSync(filePath)) {',
|
|
224
|
+
' return JSON.parse(fs.readFileSync(filePath, "utf-8"));',
|
|
225
|
+
' }',
|
|
226
|
+
' } catch {}',
|
|
227
|
+
' return {};',
|
|
228
|
+
'}',
|
|
229
|
+
'',
|
|
230
|
+
'const current = readJsonSafe(stateFilePath);',
|
|
231
|
+
'const lastCompact = readJsonSafe(lastCompactFilePath);',
|
|
232
|
+
'',
|
|
233
|
+
'// Compute diff: keys added, changed, or deleted since last compact.',
|
|
234
|
+
'const diff = {};',
|
|
235
|
+
'const allKeys = new Set([...Object.keys(current), ...Object.keys(lastCompact)]);',
|
|
236
|
+
'for (const key of allKeys) {',
|
|
237
|
+
' const cur = current[key];',
|
|
238
|
+
' const prev = lastCompact[key];',
|
|
239
|
+
' if (cur === undefined) {',
|
|
240
|
+
' diff[key] = "(deleted)";',
|
|
241
|
+
' } else if (prev === undefined) {',
|
|
242
|
+
' diff[key] = cur;',
|
|
243
|
+
' } else if (JSON.stringify(cur) !== JSON.stringify(prev)) {',
|
|
244
|
+
' diff[key] = { from: prev, to: cur };',
|
|
245
|
+
' }',
|
|
246
|
+
'}',
|
|
247
|
+
'',
|
|
248
|
+
'const contextParts = [',
|
|
249
|
+
' "Current skill state (JSON): " + JSON.stringify(current),',
|
|
250
|
+
'];',
|
|
251
|
+
'if (Object.keys(diff).length > 0) {',
|
|
252
|
+
' contextParts.push("Changes since last compact: " + JSON.stringify(diff));',
|
|
253
|
+
'}',
|
|
254
|
+
'',
|
|
255
|
+
'const output = {',
|
|
256
|
+
' hookSpecificOutput: {',
|
|
257
|
+
' additionalContext: contextParts.join("\\n")',
|
|
258
|
+
' }',
|
|
259
|
+
'};',
|
|
260
|
+
'',
|
|
261
|
+
'// Save current state as the new compact snapshot.',
|
|
262
|
+
'try {',
|
|
263
|
+
' fs.writeFileSync(lastCompactFilePath, JSON.stringify(current, null, 2));',
|
|
264
|
+
'} catch {}',
|
|
265
|
+
'',
|
|
266
|
+
'process.stdout.write(JSON.stringify(output));',
|
|
267
|
+
].join('\n');
|
|
268
|
+
}
|
|
269
|
+
generateSessionStartHookScript(statePathOrRef) {
|
|
270
|
+
const statePath = typeof statePathOrRef === 'string'
|
|
271
|
+
? statePathOrRef
|
|
272
|
+
: resolveStatePath(statePathOrRef.root, statePathOrRef.name);
|
|
273
|
+
const sp = JSON.stringify(statePath);
|
|
274
|
+
return [
|
|
275
|
+
'// Claude hook: SessionStart (source: compact)',
|
|
276
|
+
'// Re-injects skill state after compaction so the model retains',
|
|
277
|
+
'// execution context even though history was compressed.',
|
|
278
|
+
'const fs = require("fs");',
|
|
279
|
+
'const stateFilePath = ' + sp + ';',
|
|
280
|
+
'let state = {};',
|
|
281
|
+
'try {',
|
|
282
|
+
' if (fs.existsSync(stateFilePath)) {',
|
|
283
|
+
' state = JSON.parse(fs.readFileSync(stateFilePath, "utf-8"));',
|
|
284
|
+
' }',
|
|
285
|
+
'} catch {}',
|
|
286
|
+
'const output = {',
|
|
287
|
+
' hookSpecificOutput: {',
|
|
288
|
+
' additionalContext: "Skill state restored after compaction: " + JSON.stringify(state)',
|
|
289
|
+
' }',
|
|
290
|
+
'};',
|
|
291
|
+
'process.stdout.write(JSON.stringify(output));',
|
|
292
|
+
].join('\n');
|
|
293
|
+
}
|
|
294
|
+
generateAllHooksScripts(statePathOrRef, schema) {
|
|
295
|
+
return {
|
|
296
|
+
preCompact: this.generateCompactHookScript(statePathOrRef, schema),
|
|
297
|
+
sessionStartCompact: this.generateSessionStartHookScript(statePathOrRef),
|
|
298
|
+
};
|
|
299
|
+
}
|
|
300
|
+
generateAppendPrompt() {
|
|
301
|
+
return `You are operating in state-based execution mode. Your state is maintained across steps.
|
|
302
|
+
|
|
303
|
+
After each step, you MUST respond with a JSON block containing your State Patch and your Action. The JSON block MUST have exactly these two keys:
|
|
304
|
+
|
|
305
|
+
\`\`\`json
|
|
306
|
+
{
|
|
307
|
+
"state_patch": { "field_to_update": "new_value", "obsolete_field": null },
|
|
308
|
+
"action": "next_action_name"
|
|
309
|
+
}
|
|
310
|
+
\`\`\`
|
|
311
|
+
|
|
312
|
+
- In \`state_patch\`, set keys to null to delete them. Only include fields you want to change. Omit fields to leave them unchanged.
|
|
313
|
+
- \`action\` indicates what you want to do next (e.g., "continue", "done", "deploy").
|
|
314
|
+
- Reasoning is discarded after execution — put anything you need to persist into \`state_patch\`.`;
|
|
315
|
+
}
|
|
316
|
+
describeSchema(schema) {
|
|
317
|
+
const fields = Object.entries(schema)
|
|
318
|
+
.map(([name, field]) => `- ${name} (${field.type}): ${field.description ?? 'no description'}`)
|
|
319
|
+
.join('\n');
|
|
320
|
+
return `## Schema\n${fields}`;
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
//# sourceMappingURL=claude-adapter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"claude-adapter.js","sourceRoot":"","sources":["../src/claude-adapter.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,cAAc,qBAAqB,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,qDAAqD;AACrD,cAAc,qBAAqB,CAAC"}
|
package/package.json
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@skillstate/claude",
|
|
3
|
+
"version": "2.0.0",
|
|
4
|
+
"description": "Claude Code platform adapter for the skillstate runtime.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "dist/index.js",
|
|
7
|
+
"types": "dist/index.d.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"types": "./dist/index.d.ts",
|
|
11
|
+
"default": "./dist/index.js"
|
|
12
|
+
},
|
|
13
|
+
"./package.json": "./package.json"
|
|
14
|
+
},
|
|
15
|
+
"files": ["dist"],
|
|
16
|
+
"sideEffects": false,
|
|
17
|
+
"engines": {
|
|
18
|
+
"node": ">=20"
|
|
19
|
+
},
|
|
20
|
+
"license": "MIT",
|
|
21
|
+
"dependencies": {
|
|
22
|
+
"@skillstate/core": "^2.0.0"
|
|
23
|
+
}
|
|
24
|
+
}
|