@skillstate/codex 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/codex-adapter.d.ts +40 -14
- package/dist/codex-adapter.d.ts.map +1 -1
- package/dist/codex-adapter.js +104 -257
- package/dist/codex-adapter.js.map +1 -1
- package/package.json +1 -1
package/dist/codex-adapter.d.ts
CHANGED
|
@@ -38,6 +38,15 @@ export interface CodexHooksConfigOptions {
|
|
|
38
38
|
* embedded copy because they cannot import `@skillstate/*`).
|
|
39
39
|
*/
|
|
40
40
|
export declare const resolveStateForCwd: typeof resolveHostStateForCwd;
|
|
41
|
+
/**
|
|
42
|
+
* OpenAI Codex platform adapter (@non-paper; see module doc).
|
|
43
|
+
*
|
|
44
|
+
* Every generated hook script is a SELF-CONTAINED CommonJS file (Node
|
|
45
|
+
* builtins only, no `@skillstate/*` import): Codex executes them directly
|
|
46
|
+
* via `node <script> <event>` with the hook JSON on stdin, and each script
|
|
47
|
+
* resolves the per-project state from `input.cwd` at runtime — so one
|
|
48
|
+
* global `hooks.json` + one script directory serve every project.
|
|
49
|
+
*/
|
|
41
50
|
export declare class CodexAdapter {
|
|
42
51
|
readonly name = "codex";
|
|
43
52
|
/**
|
|
@@ -73,50 +82,67 @@ export declare class CodexAdapter {
|
|
|
73
82
|
* `hookEventName: "SessionStart"` (state survives compaction);
|
|
74
83
|
* - `post-tool-use`: extracts a `state_patch` from the tool_response
|
|
75
84
|
* (fenced ```json block or raw JSON), applies the ⊕ null-deletion merge
|
|
76
|
-
* and writes the state file
|
|
77
|
-
* the patch is invalid.
|
|
85
|
+
* and writes the state file (under the built-in cross-process lock);
|
|
86
|
+
* stdout is `{}` or a `systemMessage` when the patch is invalid.
|
|
87
|
+
*
|
|
88
|
+
* AGENT-SCOPED STATE: the hook stdin's `session_id` scopes the state to
|
|
89
|
+
* `<cwd>/.skillstate/agents/<session-prefix>/skillstate.json`, so
|
|
90
|
+
* parallel Codex sessions never last-writer-win over each other.
|
|
78
91
|
*
|
|
79
92
|
* `statePath` is accepted for `{ root, name }` confinement (traversal
|
|
80
93
|
* refs throw) and documented in the script header; the content itself is
|
|
81
94
|
* cwd-resolving and never bakes an absolute state path in.
|
|
82
95
|
*/
|
|
83
96
|
generateHookScript(event: CodexHookEvent, statePath?: string | StatePathRef): string;
|
|
97
|
+
/**
|
|
98
|
+
* Inject-script template (`UserPromptSubmit` / `SessionStart`): brand
|
|
99
|
+
* header + the shared hook-runtime snippet ({@link hookRuntimeSnippet}
|
|
100
|
+
* inlined via `fn.toString()`) + a stdin loop that emits
|
|
101
|
+
* `{ hookSpecificOutput: { hookEventName, additionalContext } }` with the
|
|
102
|
+
* current state JSON read from the SESSION cwd. Brand specifics stay in
|
|
103
|
+
* the adapter (comment lines only); the `contextSuffix` is the shared
|
|
104
|
+
* {@link HISTORY_UNRELIABLE_NOTE} from `@skillstate/core`.
|
|
105
|
+
*/
|
|
106
|
+
private buildInjectScriptTemplate;
|
|
84
107
|
/**
|
|
85
108
|
* Generate a SKILL.md for Codex's skill directory
|
|
86
109
|
* (`~/.codex/skills/<name>/SKILL.md`). The body instructs the agent to
|
|
87
110
|
* treat the hook-injected state as authoritative (history is not
|
|
88
|
-
* reliable), to
|
|
89
|
-
* to persist via `state.patch` — the PostToolUse hook also merges any
|
|
111
|
+
* reliable), to orient via `state.summary` (full dump via `state.get`),
|
|
112
|
+
* and to persist via `state.patch` — the PostToolUse hook also merges any
|
|
90
113
|
* fenced ```json `state_patch` block printed by a Bash tool call.
|
|
91
114
|
*/
|
|
92
115
|
generateSkillMd(spec: ProceduralSpec, statePath?: string): string;
|
|
93
116
|
/**
|
|
94
|
-
* Generate the hooks.json document and persist it via
|
|
95
|
-
* Both the destination and the embedded state path
|
|
96
|
-
* `{ root, name }` refs confined by
|
|
97
|
-
* absolute destination path.
|
|
117
|
+
* Generate the hooks.json document and persist it via the shared
|
|
118
|
+
* `saveGenerated`. Both the destination and the embedded state path
|
|
119
|
+
* accept raw strings or `{ root, name }` refs confined by
|
|
120
|
+
* `resolveStatePath`. Returns the absolute destination path.
|
|
98
121
|
*/
|
|
99
122
|
saveHooksConfig(target: string | StatePathRef, statePath: string | StatePathRef, options?: CodexHooksConfigOptions): Promise<string>;
|
|
100
123
|
/**
|
|
101
124
|
* Merge the skillstate hook groups into an existing `hooks.json` text.
|
|
102
125
|
* Idempotent: if any skillstate command is already wired, the document is
|
|
103
126
|
* returned unchanged. Existing (non-skillstate) hooks are preserved.
|
|
127
|
+
*
|
|
128
|
+
* The mechanics live in the shared {@link mergeHookGroups}; this method
|
|
129
|
+
* supplies only the format specifics (generated hooks.json groups —
|
|
130
|
+
* with the codex `description`/`statusMessage`/`additionalContextLimit`
|
|
131
|
+
* fields — and the `node <script> <event>` skillstate commands).
|
|
104
132
|
*/
|
|
105
133
|
mergeHooksConfig(existingJson: string, options?: CodexHooksConfigOptions): string;
|
|
106
134
|
/**
|
|
107
|
-
* Generate a hook script and persist it via
|
|
108
|
-
* is the script destination (usually
|
|
135
|
+
* Generate a hook script and persist it via the shared `saveGenerated`
|
|
136
|
+
* (atomic temp-rename write). `target` is the script destination (usually
|
|
109
137
|
* {@link CodexAdapter.codexHookScriptPath}); `statePath` is forwarded to
|
|
110
138
|
* {@link generateHookScript}. Returns the absolute destination path.
|
|
111
139
|
*/
|
|
112
140
|
saveHookScript(event: CodexHookEvent, target: string | StatePathRef, statePath?: string | StatePathRef): Promise<string>;
|
|
113
141
|
/**
|
|
114
|
-
* Generate a SKILL.md and persist it via `
|
|
115
|
-
* absolute destination path.
|
|
142
|
+
* Generate a SKILL.md and persist it via the shared `saveGenerated`.
|
|
143
|
+
* Returns the absolute destination path.
|
|
116
144
|
*/
|
|
117
145
|
saveSkillMd(target: string | StatePathRef, spec: ProceduralSpec, statePath?: string): Promise<string>;
|
|
118
|
-
/** Resolve a `string | StatePathRef` via `resolveStatePath` (throws on `..`). */
|
|
119
|
-
private resolve;
|
|
120
146
|
/** PostToolUse script: extract state_patch, ⊕ merge, persist. */
|
|
121
147
|
private buildPostToolUseScript;
|
|
122
148
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"codex-adapter.d.ts","sourceRoot":"","sources":["../src/codex-adapter.ts"],"names":[],"mappings":"AA4BA,OAAO,
|
|
1
|
+
{"version":3,"file":"codex-adapter.d.ts","sourceRoot":"","sources":["../src/codex-adapter.ts"],"names":[],"mappings":"AA4BA,OAAO,EAKL,sBAAsB,EAIvB,MAAM,kBAAkB,CAAC;AAC1B,OAAO,KAAK,EAAE,cAAc,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAErE,+EAA+E;AAC/E,MAAM,MAAM,cAAc,GACtB,oBAAoB,GACpB,uBAAuB,GACvB,eAAe,CAAC;AAEpB,6DAA6D;AAC7D,eAAO,MAAM,iBAAiB,2EAIgB,CAAC;AAE/C,6EAA6E;AAC7E,eAAO,MAAM,2BAA2B,cAAc,CAAC;AAEvD,2DAA2D;AAC3D,eAAO,MAAM,2BAA2B,WAAW,CAAC;AAEpD;;;GAGG;AACH,eAAO,MAAM,8BAA8B,OAAO,CAAC;AAEnD,gFAAgF;AAChF,eAAO,MAAM,0BAA0B,KAAK,CAAC;AAE7C,4DAA4D;AAC5D,MAAM,WAAW,uBAAuB;IACtC;;;OAGG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,2EAA2E;IAC3E,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,mFAAmF;IACnF,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,8EAA8E;IAC9E,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAED;;;;;;;GAOG;AACH,eAAO,MAAM,kBAAkB,+BAAyB,CAAC;AAEzD;;;;;;;;GAQG;AAEH,qBAAa,YAAY;IACvB,QAAQ,CAAC,IAAI,WAAW;IAExB;;;;;OAKG;IACH,mBAAmB,CAAC,SAAS,EAAE,MAAM,EAAE,KAAK,EAAE,cAAc,GAAG,MAAM,CAEpE;IAED;;;;;;;;;;;OAWG;IACH,mBAAmB,CACjB,SAAS,EAAE,MAAM,GAAG,YAAY,EAChC,OAAO,CAAC,EAAE,uBAAuB,GAChC,MAAM,CA6CR;IAED;;;;;;;;;;;;;;;;;;;;;;;OAuBG;IACH,kBAAkB,CAChB,KAAK,EAAE,cAAc,EACrB,SAAS,CAAC,EAAE,MAAM,GAAG,YAAY,GAChC,MAAM,CAiBR;IAED;;;;;;;;OAQG;IACH,OAAO,CAAC,yBAAyB;IA2EjC;;;;;;;OAOG;IACH,eAAe,CAAC,IAAI,EAAE,cAAc,EAAE,SAAS,CAAC,EAAE,MAAM,GAAG,MAAM,CAOhE;IAED;;;;;OAKG;IACG,eAAe,CACnB,MAAM,EAAE,MAAM,GAAG,YAAY,EAC7B,SAAS,EAAE,MAAM,GAAG,YAAY,EAChC,OAAO,CAAC,EAAE,uBAAuB,GAChC,OAAO,CAAC,MAAM,CAAC,CAEjB;IAED;;;;;;;;;OASG;IACH,gBAAgB,CAAC,YAAY,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,uBAAuB,GAAG,MAAM,CAahF;IAED;;;;;OAKG;IACG,cAAc,CAClB,KAAK,EAAE,cAAc,EACrB,MAAM,EAAE,MAAM,GAAG,YAAY,EAC7B,SAAS,CAAC,EAAE,MAAM,GAAG,YAAY,GAChC,OAAO,CAAC,MAAM,CAAC,CAEjB;IAED;;;OAGG;IACG,WAAW,CACf,MAAM,EAAE,MAAM,GAAG,YAAY,EAC7B,IAAI,EAAE,cAAc,EACpB,SAAS,CAAC,EAAE,MAAM,GACjB,OAAO,CAAC,MAAM,CAAC,CAEjB;IAMD,iEAAiE;IACjE,OAAO,CAAC,sBAAsB;CAwE/B"}
|
package/dist/codex-adapter.js
CHANGED
|
@@ -26,7 +26,7 @@
|
|
|
26
26
|
* @non-paper — no adapters exist in arXiv 2608.26263v3.
|
|
27
27
|
*/
|
|
28
28
|
import * as path from 'node:path';
|
|
29
|
-
import {
|
|
29
|
+
import { HISTORY_UNRELIABLE_NOTE, hookRuntimeSnippet, INTERRUPTED_SESSION_NOTE, mergeHookGroups, resolveHostStateForCwd, resolveTarget, saveGenerated, skillMdBody, } from '@skillstate/core';
|
|
30
30
|
/** All {@link CodexHookEvent} values in generation order. */
|
|
31
31
|
export const CODEX_HOOK_EVENTS = [
|
|
32
32
|
'user-prompt-submit',
|
|
@@ -62,10 +62,6 @@ export const resolveStateForCwd = resolveHostStateForCwd;
|
|
|
62
62
|
* resolves the per-project state from `input.cwd` at runtime — so one
|
|
63
63
|
* global `hooks.json` + one script directory serve every project.
|
|
64
64
|
*/
|
|
65
|
-
/** Narrow record check for hooks.json documents (module scope). */
|
|
66
|
-
function isPlainObjectDoc(value) {
|
|
67
|
-
return typeof value === 'object' && value !== null && !Array.isArray(value);
|
|
68
|
-
}
|
|
69
65
|
export class CodexAdapter {
|
|
70
66
|
name = 'codex';
|
|
71
67
|
/**
|
|
@@ -90,7 +86,7 @@ export class CodexAdapter {
|
|
|
90
86
|
* file's directory).
|
|
91
87
|
*/
|
|
92
88
|
generateHooksConfig(statePath, options) {
|
|
93
|
-
const resolved =
|
|
89
|
+
const resolved = resolveTarget(statePath);
|
|
94
90
|
const scriptDir = options?.scriptDir ?? path.dirname(resolved);
|
|
95
91
|
const command = (event) => options?.command ?? `node ${JSON.stringify(this.codexHookScriptPath(scriptDir, event))} ${event}`;
|
|
96
92
|
const timeout = options?.timeoutSeconds ?? CODEX_HOOK_TIMEOUT_SECONDS;
|
|
@@ -140,75 +136,104 @@ export class CodexAdapter {
|
|
|
140
136
|
* `hookEventName: "SessionStart"` (state survives compaction);
|
|
141
137
|
* - `post-tool-use`: extracts a `state_patch` from the tool_response
|
|
142
138
|
* (fenced ```json block or raw JSON), applies the ⊕ null-deletion merge
|
|
143
|
-
* and writes the state file
|
|
144
|
-
* the patch is invalid.
|
|
139
|
+
* and writes the state file (under the built-in cross-process lock);
|
|
140
|
+
* stdout is `{}` or a `systemMessage` when the patch is invalid.
|
|
141
|
+
*
|
|
142
|
+
* AGENT-SCOPED STATE: the hook stdin's `session_id` scopes the state to
|
|
143
|
+
* `<cwd>/.skillstate/agents/<session-prefix>/skillstate.json`, so
|
|
144
|
+
* parallel Codex sessions never last-writer-win over each other.
|
|
145
145
|
*
|
|
146
146
|
* `statePath` is accepted for `{ root, name }` confinement (traversal
|
|
147
147
|
* refs throw) and documented in the script header; the content itself is
|
|
148
148
|
* cwd-resolving and never bakes an absolute state path in.
|
|
149
149
|
*/
|
|
150
150
|
generateHookScript(event, statePath) {
|
|
151
|
-
const resolved = statePath === undefined ? undefined :
|
|
151
|
+
const resolved = statePath === undefined ? undefined : resolveTarget(statePath);
|
|
152
152
|
const header = `// State file (per-project resolver): ${resolved ?? '<cwd>/.skillstate/skillstate.json (global bucket when cwd === home)'}`;
|
|
153
153
|
if (event === 'post-tool-use') {
|
|
154
154
|
return this.buildPostToolUseScript(header);
|
|
155
155
|
}
|
|
156
156
|
const hookEventName = event === 'session-start-compact' ? 'SessionStart' : 'UserPromptSubmit';
|
|
157
|
+
// A1 text is shared: both hosts append the SAME HISTORY_UNRELIABLE_NOTE
|
|
158
|
+
// (MCP tools + fenced state_patch channel) after the state JSON.
|
|
159
|
+
return this.buildInjectScriptTemplate({
|
|
160
|
+
header,
|
|
161
|
+
hookEventName,
|
|
162
|
+
contextSuffix: HISTORY_UNRELIABLE_NOTE,
|
|
163
|
+
});
|
|
164
|
+
}
|
|
165
|
+
/**
|
|
166
|
+
* Inject-script template (`UserPromptSubmit` / `SessionStart`): brand
|
|
167
|
+
* header + the shared hook-runtime snippet ({@link hookRuntimeSnippet}
|
|
168
|
+
* inlined via `fn.toString()`) + a stdin loop that emits
|
|
169
|
+
* `{ hookSpecificOutput: { hookEventName, additionalContext } }` with the
|
|
170
|
+
* current state JSON read from the SESSION cwd. Brand specifics stay in
|
|
171
|
+
* the adapter (comment lines only); the `contextSuffix` is the shared
|
|
172
|
+
* {@link HISTORY_UNRELIABLE_NOTE} from `@skillstate/core`.
|
|
173
|
+
*/
|
|
174
|
+
buildInjectScriptTemplate(options) {
|
|
175
|
+
// SessionStart is a real session boundary: when the session-meta
|
|
176
|
+
// sidecar still carries `status: "interrupted"` (the previous run of
|
|
177
|
+
// this session was killed before it could finalize), the hook appends
|
|
178
|
+
// the shared INTERRUPTED_SESSION_NOTE — with the preserved state path
|
|
179
|
+
// substituted — so the model reviews progress/blockers first. A fresh
|
|
180
|
+
// MCP launch overwrites the status back to `running`.
|
|
181
|
+
const interruptedCheck = options.hookEventName === 'SessionStart';
|
|
157
182
|
return [
|
|
158
183
|
'#!/usr/bin/env node',
|
|
159
|
-
`// skillstate Codex hook — ${hookEventName} (generated by @skillstate/codex).`,
|
|
184
|
+
`// skillstate Codex hook — ${options.hookEventName} (generated by @skillstate/codex).`,
|
|
160
185
|
'// Self-contained CommonJS: reads one hook JSON document on stdin,',
|
|
161
186
|
'// resolves the state from the SESSION cwd, and emits',
|
|
162
187
|
'// { hookSpecificOutput: { hookEventName, additionalContext } }.',
|
|
163
|
-
header,
|
|
188
|
+
options.header,
|
|
164
189
|
"'use strict';",
|
|
165
190
|
'const fs = require("fs");',
|
|
166
191
|
'const os = require("os");',
|
|
167
192
|
'const path = require("path");',
|
|
168
193
|
'',
|
|
169
|
-
`const HOOK_EVENT_NAME = ${JSON.stringify(hookEventName)};`,
|
|
194
|
+
`const HOOK_EVENT_NAME = ${JSON.stringify(options.hookEventName)};`,
|
|
195
|
+
`const INTERRUPTED_SESSION_NOTE = ${JSON.stringify(INTERRUPTED_SESSION_NOTE)};`,
|
|
170
196
|
'',
|
|
171
|
-
|
|
172
|
-
' const resolvedCwd = path.resolve(cwd);',
|
|
173
|
-
' const resolvedHome = path.resolve(os.homedir());',
|
|
174
|
-
' if (resolvedCwd === resolvedHome) {',
|
|
175
|
-
' return path.join(resolvedHome, ".skillstate", "global", "skillstate.json");',
|
|
176
|
-
' }',
|
|
177
|
-
' return path.join(resolvedCwd, ".skillstate", "skillstate.json");',
|
|
178
|
-
'}',
|
|
179
|
-
'',
|
|
180
|
-
'function readState(statePath) {',
|
|
181
|
-
' try {',
|
|
182
|
-
' if (fs.existsSync(statePath)) {',
|
|
183
|
-
' const parsed = JSON.parse(fs.readFileSync(statePath, "utf-8"));',
|
|
184
|
-
' if (parsed !== null && typeof parsed === "object" && !Array.isArray(parsed)) {',
|
|
185
|
-
' if (parsed.state !== null && typeof parsed.state === "object" && !Array.isArray(parsed.state)) {',
|
|
186
|
-
' return parsed.state;',
|
|
187
|
-
' }',
|
|
188
|
-
' return parsed;',
|
|
189
|
-
' }',
|
|
190
|
-
' }',
|
|
191
|
-
' } catch (error) {}',
|
|
192
|
-
' return {};',
|
|
193
|
-
'}',
|
|
197
|
+
hookRuntimeSnippet(),
|
|
194
198
|
'',
|
|
195
199
|
'let raw = "";',
|
|
196
200
|
'process.stdin.setEncoding("utf-8");',
|
|
197
201
|
'process.stdin.on("data", (chunk) => { raw += chunk; });',
|
|
198
202
|
'process.stdin.on("end", () => {',
|
|
199
203
|
' let cwd = process.cwd();',
|
|
204
|
+
' let agentId = "";',
|
|
200
205
|
' try {',
|
|
201
206
|
' const input = JSON.parse(raw);',
|
|
202
207
|
' if (typeof input.cwd === "string" && input.cwd.length > 0) {',
|
|
203
208
|
' cwd = input.cwd;',
|
|
204
209
|
' }',
|
|
210
|
+
' agentId = resolveAgentIdFromSession(input.session_id);',
|
|
205
211
|
' } catch (error) {}',
|
|
206
|
-
' const
|
|
212
|
+
' const statePath = resolveStatePathForCwd(',
|
|
213
|
+
' path.resolve(cwd),',
|
|
214
|
+
' path.resolve(os.homedir()),',
|
|
215
|
+
' agentId,',
|
|
216
|
+
' );',
|
|
217
|
+
' const state = readStateEnvelope(statePath, (p) => fs.readFileSync(p, "utf-8"));',
|
|
218
|
+
' let contextSuffix = ' + JSON.stringify(options.contextSuffix) + ';',
|
|
219
|
+
...(interruptedCheck
|
|
220
|
+
? [
|
|
221
|
+
' const metaStatus = readSessionMetaStatus(',
|
|
222
|
+
' statePath.replace(/\\/+[^/]*$/, "") + "/.session-meta.json",',
|
|
223
|
+
' (p) => fs.readFileSync(p, "utf-8"),',
|
|
224
|
+
' );',
|
|
225
|
+
' if (metaStatus === "interrupted") {',
|
|
226
|
+
' contextSuffix += INTERRUPTED_SESSION_NOTE.replace("<path>", function () {',
|
|
227
|
+
' return statePath;',
|
|
228
|
+
' });',
|
|
229
|
+
' }',
|
|
230
|
+
]
|
|
231
|
+
: []),
|
|
207
232
|
' const output = {',
|
|
208
233
|
' hookSpecificOutput: {',
|
|
209
234
|
' hookEventName: HOOK_EVENT_NAME,',
|
|
210
235
|
' additionalContext: "Current skill state (JSON): " + JSON.stringify(state)',
|
|
211
|
-
' +
|
|
236
|
+
' + contextSuffix,',
|
|
212
237
|
' },',
|
|
213
238
|
' };',
|
|
214
239
|
' process.stdout.write(JSON.stringify(output));',
|
|
@@ -220,154 +245,67 @@ export class CodexAdapter {
|
|
|
220
245
|
* Generate a SKILL.md for Codex's skill directory
|
|
221
246
|
* (`~/.codex/skills/<name>/SKILL.md`). The body instructs the agent to
|
|
222
247
|
* treat the hook-injected state as authoritative (history is not
|
|
223
|
-
* reliable), to
|
|
224
|
-
* to persist via `state.patch` — the PostToolUse hook also merges any
|
|
248
|
+
* reliable), to orient via `state.summary` (full dump via `state.get`),
|
|
249
|
+
* and to persist via `state.patch` — the PostToolUse hook also merges any
|
|
225
250
|
* fenced ```json `state_patch` block printed by a Bash tool call.
|
|
226
251
|
*/
|
|
227
252
|
generateSkillMd(spec, statePath) {
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
`version: ${spec.version}`,
|
|
235
|
-
'execution_context:',
|
|
236
|
-
` state_path: ${resolvedStatePath}`,
|
|
237
|
-
' format: json',
|
|
238
|
-
'---',
|
|
239
|
-
'',
|
|
240
|
-
`# ${spec.name}`,
|
|
241
|
-
'',
|
|
242
|
-
spec.instructions,
|
|
243
|
-
'',
|
|
244
|
-
'## Execution Context',
|
|
245
|
-
'',
|
|
246
|
-
`Your execution state lives at \`${resolvedStatePath}\` (per project; a`,
|
|
247
|
-
'session started in $HOME uses `~/.skillstate/global/skillstate.json`).',
|
|
248
|
-
'The skillstate Codex hooks:',
|
|
249
|
-
'',
|
|
250
|
-
'- inject the CURRENT state as developer context on every prompt submit',
|
|
251
|
-
' (`UserPromptSubmit`) and re-inject it after compaction',
|
|
252
|
-
' (`SessionStart` matcher `^compact$`);',
|
|
253
|
-
'- watch every Bash tool result and merge a fenced ```json block carrying',
|
|
254
|
-
' a `state_patch` into the state file (`PostToolUse`).',
|
|
255
|
-
'',
|
|
256
|
-
'The injected state is authoritative — history is not reliable. Never',
|
|
257
|
-
'reconstruct execution context from the conversation.',
|
|
258
|
-
'',
|
|
259
|
-
'## Process',
|
|
260
|
-
'',
|
|
261
|
-
'1. Read the current state from the injected context, or fetch it with',
|
|
262
|
-
' the skillstate MCP tool `state.get`.',
|
|
263
|
-
'2. Observe the result of your last action.',
|
|
264
|
-
'3. Reason about what to do next, given the state and the observation.',
|
|
265
|
-
'4. Persist progress with the skillstate MCP tool `state.patch` (sparse',
|
|
266
|
-
' patch; set a key to `null` to delete it), and/or emit a fenced JSON',
|
|
267
|
-
' block with exactly two keys inside a Bash tool call so the',
|
|
268
|
-
' `PostToolUse` hook merges it:',
|
|
269
|
-
'',
|
|
270
|
-
`${fence}json`,
|
|
271
|
-
'{',
|
|
272
|
-
' "state_patch": { "key": "new_value", "obsolete_key": null },',
|
|
273
|
-
' "action": "next_action_name"',
|
|
274
|
-
'}',
|
|
275
|
-
fence,
|
|
276
|
-
'',
|
|
277
|
-
'- In `state_patch`, set keys to `null` to delete them. Only include',
|
|
278
|
-
' fields you want to change. Omit fields to leave them unchanged.',
|
|
279
|
-
'- Put anything you need to survive into `state_patch`; never rely on',
|
|
280
|
-
' the conversation remembering it.',
|
|
281
|
-
'- `action` names what you will do next (e.g. "continue", "done").',
|
|
282
|
-
'',
|
|
283
|
-
].join('\n');
|
|
253
|
+
return skillMdBody({
|
|
254
|
+
hostLabel: 'Codex',
|
|
255
|
+
injectionPhrase: 'provided as developer context',
|
|
256
|
+
spec,
|
|
257
|
+
statePath,
|
|
258
|
+
});
|
|
284
259
|
}
|
|
285
260
|
/**
|
|
286
|
-
* Generate the hooks.json document and persist it via
|
|
287
|
-
* Both the destination and the embedded state path
|
|
288
|
-
* `{ root, name }` refs confined by
|
|
289
|
-
* absolute destination path.
|
|
261
|
+
* Generate the hooks.json document and persist it via the shared
|
|
262
|
+
* `saveGenerated`. Both the destination and the embedded state path
|
|
263
|
+
* accept raw strings or `{ root, name }` refs confined by
|
|
264
|
+
* `resolveStatePath`. Returns the absolute destination path.
|
|
290
265
|
*/
|
|
291
266
|
async saveHooksConfig(target, statePath, options) {
|
|
292
|
-
|
|
293
|
-
await atomicWriteFile(dest, this.generateHooksConfig(statePath, options));
|
|
294
|
-
return dest;
|
|
267
|
+
return saveGenerated(target, this.generateHooksConfig(statePath, options));
|
|
295
268
|
}
|
|
296
269
|
/**
|
|
297
270
|
* Merge the skillstate hook groups into an existing `hooks.json` text.
|
|
298
271
|
* Idempotent: if any skillstate command is already wired, the document is
|
|
299
272
|
* returned unchanged. Existing (non-skillstate) hooks are preserved.
|
|
273
|
+
*
|
|
274
|
+
* The mechanics live in the shared {@link mergeHookGroups}; this method
|
|
275
|
+
* supplies only the format specifics (generated hooks.json groups —
|
|
276
|
+
* with the codex `description`/`statusMessage`/`additionalContextLimit`
|
|
277
|
+
* fields — and the `node <script> <event>` skillstate commands).
|
|
300
278
|
*/
|
|
301
279
|
mergeHooksConfig(existingJson, options) {
|
|
302
|
-
let doc = {};
|
|
303
|
-
try {
|
|
304
|
-
doc = JSON.parse(existingJson);
|
|
305
|
-
}
|
|
306
|
-
catch {
|
|
307
|
-
// Missing or malformed user file: start from a fresh document.
|
|
308
|
-
}
|
|
309
|
-
if (!isPlainObjectDoc(doc.hooks)) {
|
|
310
|
-
doc.hooks = {};
|
|
311
|
-
}
|
|
312
280
|
const scriptDir = options?.scriptDir ?? '<stateDir>/hooks';
|
|
313
281
|
const command = (event) => `node ${JSON.stringify(this.codexHookScriptPath(scriptDir, event))} ${event}`;
|
|
314
|
-
const skillstateCommands = new Set(CODEX_HOOK_EVENTS.map((event) => JSON.stringify(command(event))));
|
|
315
|
-
let alreadyWired = false;
|
|
316
|
-
for (const groups of Object.values(doc.hooks)) {
|
|
317
|
-
if (!Array.isArray(groups))
|
|
318
|
-
continue;
|
|
319
|
-
for (const group of groups) {
|
|
320
|
-
if (!isPlainObjectDoc(group) || !Array.isArray(group['hooks']))
|
|
321
|
-
continue;
|
|
322
|
-
for (const handler of group['hooks']) {
|
|
323
|
-
if (isPlainObjectDoc(handler) && skillstateCommands.has(JSON.stringify(handler['command']))) {
|
|
324
|
-
alreadyWired = true;
|
|
325
|
-
}
|
|
326
|
-
}
|
|
327
|
-
}
|
|
328
|
-
}
|
|
329
|
-
if (alreadyWired) {
|
|
330
|
-
return `${JSON.stringify(doc, null, 2)}\n`;
|
|
331
|
-
}
|
|
332
282
|
const statePathRef = { root: path.dirname(options?.scriptDir ?? '.'), name: 'skillstate.json' };
|
|
333
283
|
const generated = JSON.parse(this.generateHooksConfig(statePathRef, { ...options, scriptDir }));
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
}
|
|
340
|
-
return `${JSON.stringify(doc, null, 2)}\n`;
|
|
284
|
+
return mergeHookGroups({
|
|
285
|
+
existingJson,
|
|
286
|
+
generatedGroups: generated.hooks,
|
|
287
|
+
commandsOf: new Set(CODEX_HOOK_EVENTS.map((event) => JSON.stringify(command(event)))),
|
|
288
|
+
});
|
|
341
289
|
}
|
|
342
290
|
/**
|
|
343
|
-
* Generate a hook script and persist it via
|
|
344
|
-
* is the script destination (usually
|
|
291
|
+
* Generate a hook script and persist it via the shared `saveGenerated`
|
|
292
|
+
* (atomic temp-rename write). `target` is the script destination (usually
|
|
345
293
|
* {@link CodexAdapter.codexHookScriptPath}); `statePath` is forwarded to
|
|
346
294
|
* {@link generateHookScript}. Returns the absolute destination path.
|
|
347
295
|
*/
|
|
348
296
|
async saveHookScript(event, target, statePath) {
|
|
349
|
-
|
|
350
|
-
await atomicWriteFile(dest, this.generateHookScript(event, statePath));
|
|
351
|
-
return dest;
|
|
297
|
+
return saveGenerated(target, this.generateHookScript(event, statePath));
|
|
352
298
|
}
|
|
353
299
|
/**
|
|
354
|
-
* Generate a SKILL.md and persist it via `
|
|
355
|
-
* absolute destination path.
|
|
300
|
+
* Generate a SKILL.md and persist it via the shared `saveGenerated`.
|
|
301
|
+
* Returns the absolute destination path.
|
|
356
302
|
*/
|
|
357
303
|
async saveSkillMd(target, spec, statePath) {
|
|
358
|
-
|
|
359
|
-
await atomicWriteFile(dest, this.generateSkillMd(spec, statePath));
|
|
360
|
-
return dest;
|
|
304
|
+
return saveGenerated(target, this.generateSkillMd(spec, statePath));
|
|
361
305
|
}
|
|
362
306
|
/* ------------------------------------------------------------------ */
|
|
363
307
|
/* Internal helpers */
|
|
364
308
|
/* ------------------------------------------------------------------ */
|
|
365
|
-
/** Resolve a `string | StatePathRef` via `resolveStatePath` (throws on `..`). */
|
|
366
|
-
resolve(target) {
|
|
367
|
-
return typeof target === 'string'
|
|
368
|
-
? target
|
|
369
|
-
: resolveStatePath(target.root, target.name);
|
|
370
|
-
}
|
|
371
309
|
/** PostToolUse script: extract state_patch, ⊕ merge, persist. */
|
|
372
310
|
buildPostToolUseScript(header) {
|
|
373
311
|
const fence = '```';
|
|
@@ -384,109 +322,9 @@ export class CodexAdapter {
|
|
|
384
322
|
'const os = require("os");',
|
|
385
323
|
'const path = require("path");',
|
|
386
324
|
'',
|
|
387
|
-
'function isPlainObject(value) {',
|
|
388
|
-
' return typeof value === "object" && value !== null && !Array.isArray(value);',
|
|
389
|
-
'}',
|
|
390
|
-
'',
|
|
391
|
-
'function resolveStatePathForCwd(cwd) {',
|
|
392
|
-
' const resolvedCwd = path.resolve(cwd);',
|
|
393
|
-
' const resolvedHome = path.resolve(os.homedir());',
|
|
394
|
-
' if (resolvedCwd === resolvedHome) {',
|
|
395
|
-
' return path.join(resolvedHome, ".skillstate", "global", "skillstate.json");',
|
|
396
|
-
' }',
|
|
397
|
-
' return path.join(resolvedCwd, ".skillstate", "skillstate.json");',
|
|
398
|
-
'}',
|
|
399
|
-
'',
|
|
400
|
-
'function readState(statePath) {',
|
|
401
|
-
' try {',
|
|
402
|
-
' if (fs.existsSync(statePath)) {',
|
|
403
|
-
' const parsed = JSON.parse(fs.readFileSync(statePath, "utf-8"));',
|
|
404
|
-
' if (parsed !== null && typeof parsed === "object" && !Array.isArray(parsed)) {',
|
|
405
|
-
' if (parsed.state !== null && typeof parsed.state === "object" && !Array.isArray(parsed.state)) {',
|
|
406
|
-
' return parsed.state;',
|
|
407
|
-
' }',
|
|
408
|
-
' return parsed;',
|
|
409
|
-
' }',
|
|
410
|
-
' }',
|
|
411
|
-
' } catch (error) {}',
|
|
412
|
-
' return {};',
|
|
413
|
-
'}',
|
|
414
|
-
'',
|
|
415
|
-
'// Paper ⊕ merge: null deletes a key, nested plain objects merge',
|
|
416
|
-
'// recursively, everything else replaces.',
|
|
417
|
-
'function mergePatch(base, patch) {',
|
|
418
|
-
' const result = { ...base };',
|
|
419
|
-
' for (const key of Object.keys(patch)) {',
|
|
420
|
-
' const value = patch[key];',
|
|
421
|
-
' if (value === null) {',
|
|
422
|
-
' delete result[key];',
|
|
423
|
-
' } else if (isPlainObject(value) && isPlainObject(result[key])) {',
|
|
424
|
-
' result[key] = mergePatch(result[key], value);',
|
|
425
|
-
' } else {',
|
|
426
|
-
' result[key] = value;',
|
|
427
|
-
' }',
|
|
428
|
-
' }',
|
|
429
|
-
' return result;',
|
|
430
|
-
'}',
|
|
431
|
-
'',
|
|
432
|
-
'function readResponseText(response) {',
|
|
433
|
-
' if (typeof response === "string") return response;',
|
|
434
|
-
' if (isPlainObject(response)) {',
|
|
435
|
-
' if (typeof response.content === "string") return response.content;',
|
|
436
|
-
' if (typeof response.text === "string") return response.text;',
|
|
437
|
-
' return JSON.stringify(response);',
|
|
438
|
-
' }',
|
|
439
|
-
' return response === null || response === undefined ? "" : String(response);',
|
|
440
|
-
'}',
|
|
441
|
-
'',
|
|
442
325
|
`const FENCE = ${JSON.stringify(fence)};`,
|
|
443
|
-
'const FENCE_RE = /' + '```' + 'json\\s*\\n?([\\s\\S]*?)\\n?\\s*' + '```' + '/;',
|
|
444
|
-
'// An open fence that never closes (truncated output) is still a patch',
|
|
445
|
-
'// attempt: match from ```json to end-of-text so it classifies as invalid.',
|
|
446
|
-
'const OPEN_FENCE_RE = /' + '```' + 'json\\s*\\n?([\\s\\S]+)$/',
|
|
447
|
-
'',
|
|
448
|
-
'// Look for a fenced ```json block: { patch } when it parses and carries',
|
|
449
|
-
'// an object state_patch, { invalid: true } when a block exists but is',
|
|
450
|
-
'// malformed, { absent: true } when there is no block at all.',
|
|
451
|
-
'function findFencedPatch(text) {',
|
|
452
|
-
' const match = text.match(FENCE_RE) || text.match(OPEN_FENCE_RE);',
|
|
453
|
-
' if (!match) return { absent: true };',
|
|
454
|
-
' try {',
|
|
455
|
-
' const parsed = JSON.parse(match[1]);',
|
|
456
|
-
' if (isPlainObject(parsed) && isPlainObject(parsed.state_patch)) {',
|
|
457
|
-
' return { patch: parsed.state_patch };',
|
|
458
|
-
' }',
|
|
459
|
-
' } catch (error) {}',
|
|
460
|
-
' return { invalid: true };',
|
|
461
|
-
'}',
|
|
462
326
|
'',
|
|
463
|
-
|
|
464
|
-
'// Ordinary JSON output without a state_patch key is simply not a patch.',
|
|
465
|
-
'function findRawPatch(text) {',
|
|
466
|
-
' const trimmed = text.trim();',
|
|
467
|
-
' const candidates = [];',
|
|
468
|
-
' try {',
|
|
469
|
-
' candidates.push(JSON.parse(trimmed));',
|
|
470
|
-
' } catch (error) {}',
|
|
471
|
-
' const first = trimmed.indexOf("{");',
|
|
472
|
-
' const last = trimmed.lastIndexOf("}");',
|
|
473
|
-
' if (first !== -1 && last > first) {',
|
|
474
|
-
' try {',
|
|
475
|
-
' candidates.push(JSON.parse(trimmed.slice(first, last + 1)));',
|
|
476
|
-
' } catch (error) {}',
|
|
477
|
-
' }',
|
|
478
|
-
' for (const candidate of candidates) {',
|
|
479
|
-
' if (isPlainObject(candidate)) {',
|
|
480
|
-
' if (isPlainObject(candidate.state_patch)) {',
|
|
481
|
-
' return { patch: candidate.state_patch };',
|
|
482
|
-
' }',
|
|
483
|
-
' if (Object.prototype.hasOwnProperty.call(candidate, "state_patch")) {',
|
|
484
|
-
' return { invalid: true };',
|
|
485
|
-
' }',
|
|
486
|
-
' }',
|
|
487
|
-
' }',
|
|
488
|
-
' return { absent: true };',
|
|
489
|
-
'}',
|
|
327
|
+
hookRuntimeSnippet(),
|
|
490
328
|
'',
|
|
491
329
|
'let raw = "";',
|
|
492
330
|
'process.stdin.setEncoding("utf-8");',
|
|
@@ -499,7 +337,11 @@ export class CodexAdapter {
|
|
|
499
337
|
' if (typeof input.cwd === "string" && input.cwd.length > 0) {',
|
|
500
338
|
' cwd = input.cwd;',
|
|
501
339
|
' }',
|
|
502
|
-
' const statePath = resolveStatePathForCwd(
|
|
340
|
+
' const statePath = resolveStatePathForCwd(',
|
|
341
|
+
' path.resolve(cwd),',
|
|
342
|
+
' path.resolve(os.homedir()),',
|
|
343
|
+
' resolveAgentIdFromSession(input.session_id),',
|
|
344
|
+
' );',
|
|
503
345
|
' const response = input.tool_response;',
|
|
504
346
|
' let result;',
|
|
505
347
|
' if (isPlainObject(response) && isPlainObject(response.state_patch)) {',
|
|
@@ -510,10 +352,15 @@ export class CodexAdapter {
|
|
|
510
352
|
' if (result.absent) result = findRawPatch(text);',
|
|
511
353
|
' }',
|
|
512
354
|
' if (result.patch !== undefined) {',
|
|
513
|
-
' const merged = mergePatch(readState(statePath), result.patch);',
|
|
514
355
|
' try {',
|
|
515
356
|
' fs.mkdirSync(path.dirname(statePath), { recursive: true });',
|
|
516
|
-
'
|
|
357
|
+
' lockStateWrite(statePath, fs, () => {',
|
|
358
|
+
' const merged = mergePatch(',
|
|
359
|
+
' readStateEnvelope(statePath, (p) => fs.readFileSync(p, "utf-8")),',
|
|
360
|
+
' result.patch,',
|
|
361
|
+
' );',
|
|
362
|
+
' saveStateEnvelope(statePath, merged, (p, data) => fs.writeFileSync(p, data));',
|
|
363
|
+
' });',
|
|
517
364
|
' } catch (writeError) {',
|
|
518
365
|
" output.systemMessage = 'skillstate: failed to persist state (' + writeError.message + ')';",
|
|
519
366
|
' }',
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"codex-adapter.js","sourceRoot":"","sources":["../src/codex-adapter.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,OAAO,KAAK,IAAI,MAAM,WAAW,CAAC;AAClC,OAAO,
|
|
1
|
+
{"version":3,"file":"codex-adapter.js","sourceRoot":"","sources":["../src/codex-adapter.ts"],"names":[],"mappings":"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"}
|