sneakoscope 0.5.0 → 0.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -10,11 +10,187 @@ Sneakoscope Codex is a zero-runtime-dependency Node.js harness for running Codex
10
10
  npm i -g sneakoscope
11
11
  ```
12
12
 
13
- The npm package name is `sneakoscope`; the command is branded as SKS and exposed as lowercase `sks` for shell portability.
14
- Global installation is the default and recommended setup. For a project-only install, use `npm i -D sneakoscope` and initialize hooks with `npx sks init --install-scope project`; this writes hook commands that call the local `node_modules/sneakoscope` binary instead of global `sks`.
13
+ The npm package name is `sneakoscope`; the command is branded as SKS and exposed as lowercase `sks` for shell portability. The package also exposes a `sneakoscope` command alias, so `sks setup` and `sneakoscope setup` are equivalent.
14
+ Global installation is the default and recommended setup. During `sks setup` or `sks init`, SKS resolves the global binary when possible and writes that absolute path into `.codex/hooks.json`, which avoids PATH issues in GUI or hook execution environments. For a project-only install, use `npm i -D sneakoscope` and initialize hooks with `npx sks setup --install-scope project`; this writes hook commands that call the local `node_modules/sneakoscope` binary.
15
15
 
16
16
  `@openai/codex` is intentionally not bundled. Install Codex separately, or set `SKS_CODEX_BIN` to the Codex executable you want Sneakoscope Codex to supervise.
17
17
 
18
+ ## One-Prompt LLM Install
19
+
20
+ If you are using Codex App, ChatGPT, Claude Code, Cursor, or another coding agent, copy this prompt into the agent from your target project directory:
21
+
22
+ ````text
23
+ You are installing Sneakoscope Codex in the current project. Do the setup end to end without asking follow-up questions unless a command needs user approval.
24
+
25
+ Repository:
26
+ https://github.com/mandarange/Sneakoscope-Codex.git
27
+
28
+ Requirements:
29
+ - Node.js must be >=20.11.
30
+ - Codex CLI is installed separately; if missing, report that @openai/codex must be installed or SKS_CODEX_BIN must be set.
31
+ - Prefer safe, local verification. Do not modify application source files unless needed for SKS setup.
32
+
33
+ Run:
34
+ ```bash
35
+ npm i -g git+https://github.com/mandarange/Sneakoscope-Codex.git
36
+ sks setup
37
+ sks doctor --fix
38
+ sks selftest --mock
39
+ sks commands
40
+ ```
41
+
42
+ If the global command is not on PATH, use:
43
+ ```bash
44
+ npx -y -p git+https://github.com/mandarange/Sneakoscope-Codex.git sks setup
45
+ npx -y -p git+https://github.com/mandarange/Sneakoscope-Codex.git sks doctor --fix
46
+ ```
47
+
48
+ After setup, explain these outputs to the user:
49
+ - `.sneakoscope/` mission state and policy
50
+ - `.codex/config.toml` Codex App profiles
51
+ - `.codex/hooks.json` SKS hook integration
52
+ - `.codex/skills/` local Codex App skills
53
+ - `.codex/SNEAKOSCOPE.md` Codex App quick reference
54
+ - `AGENTS.md` repository rules
55
+
56
+ Show the user how to discover commands:
57
+ ```bash
58
+ sks help
59
+ sks commands
60
+ sks usage ralph
61
+ sks quickstart
62
+ sks codex-app
63
+ sks dollar-commands
64
+ ```
65
+
66
+ Tell the user they can use these prompt commands inside Codex App:
67
+ ```text
68
+ $DF 글자 색 바꿔줘
69
+ $DF 내용을 영어로 바꿔줘
70
+ $SKS show me available workflows
71
+ $Ralph implement this with mandatory clarification
72
+ $Research investigate this idea
73
+ $DB check this migration safely
74
+ ```
75
+ ````
76
+
77
+ After SKS is installed, you can print this prompt again from the CLI:
78
+
79
+ ```bash
80
+ sks install-prompt
81
+ sks install-prompt --project
82
+ ```
83
+
84
+ ## Repository
85
+
86
+ ```bash
87
+ npm i -g git+https://github.com/mandarange/Sneakoscope-Codex.git
88
+ ```
89
+
90
+ Source repository: <https://github.com/mandarange/Sneakoscope-Codex.git>
91
+
92
+ Local development checkout:
93
+
94
+ ```bash
95
+ git clone https://github.com/mandarange/Sneakoscope-Codex.git
96
+ cd Sneakoscope-Codex
97
+ npm i
98
+ ```
99
+
100
+ ## Installed Commands
101
+
102
+ Installing the package exposes two equivalent shell commands:
103
+
104
+ ```bash
105
+ sks <command>
106
+ sneakoscope <command>
107
+ ```
108
+
109
+ Use `sks --help` or `sneakoscope --help` to inspect the installed CLI. The user-facing subcommands are listed in [Commands](#commands).
110
+
111
+ Useful discovery commands:
112
+
113
+ ```bash
114
+ sks commands
115
+ sks usage install
116
+ sks usage ralph
117
+ sks quickstart
118
+ sks install-prompt
119
+ sks codex-app
120
+ sks dollar-commands
121
+ sks df
122
+ sks aliases
123
+ ```
124
+
125
+ ## Prompt Pipeline and $ Commands
126
+
127
+ SKS installs a Codex App `UserPromptSubmit` hook that adds a lightweight prompt-optimization context to every user request. You do not need to type a command for basic routing: SKS will infer the lightest path before work starts.
128
+
129
+ Use `$` prompt commands inside Codex App or another coding agent when you want to force a route:
130
+
131
+ ```text
132
+ $DF fast design/content fix
133
+ $SKS general Sneakoscope workflow/help
134
+ $Ralph clarification-gated Ralph mission
135
+ $Research frontier research mission
136
+ $DB database/Supabase safety check
137
+ $GX deterministic visual context
138
+ $Help command and workflow help
139
+ ```
140
+
141
+ `$DF` is intentionally small and fast. Use it for changes like text color, visible copy, labels, spacing, button text, or translation:
142
+
143
+ ```text
144
+ $DF 글자 색 파란색으로 바꿔줘
145
+ $DF 내용을 영어로 바꿔줘
146
+ $DF Change the CTA label to "Start"
147
+ ```
148
+
149
+ DF should not start Ralph, Research, evaluation, or a broad redesign unless you explicitly ask for that.
150
+
151
+ ## Codex App
152
+
153
+ Sneakoscope Codex can also be used from Codex App when the repository is opened in the app. Run setup once in the project:
154
+
155
+ ```bash
156
+ sks setup
157
+ ```
158
+
159
+ This creates the app-facing control surface:
160
+
161
+ ```text
162
+ .codex/config.toml Codex App profiles for SKS Ralph, research, and default work
163
+ .codex/hooks.json Codex App hook entrypoints routed through SKS guards
164
+ .codex/skills/ local project skills for Ralph, DB safety, GX, research, and design work
165
+ .codex/SNEAKOSCOPE.md quick reference for using SKS inside Codex App
166
+ AGENTS.md repository rules loaded by Codex agents
167
+ .sneakoscope/ mission state, gates, logs, policy, GX cartridges, and reports
168
+ ```
169
+
170
+ Inside Codex App, you can ask the agent to use the local SKS control surface, for example:
171
+
172
+ ```text
173
+ $DF 글자 색 바꿔줘
174
+ $DF 내용을 영어로 바꿔줘
175
+ Use Sneakoscope Ralph mode to prepare this task.
176
+ Run the latest Ralph mission with the sealed decision contract.
177
+ Use SKS DB safety before touching database or Supabase files.
178
+ Use SKS research mode for this investigation.
179
+ ```
180
+
181
+ If Codex App cannot find `sks` from hooks, run:
182
+
183
+ ```bash
184
+ sks fix-path
185
+ ```
186
+
187
+ For a project-only install, use:
188
+
189
+ ```bash
190
+ npm i -D sneakoscope
191
+ npx sks setup --install-scope project
192
+ ```
193
+
18
194
  ## Requirements
19
195
 
20
196
  - Node.js `>=20.11`
@@ -25,8 +201,7 @@ Global installation is the default and recommended setup. For a project-only ins
25
201
  ## Quick Start
26
202
 
27
203
  ```bash
28
- sks doctor --fix
29
- sks init
204
+ sks setup
30
205
  sks selftest --mock
31
206
  ```
32
207
 
@@ -34,8 +209,19 @@ Project-only setup:
34
209
 
35
210
  ```bash
36
211
  npm i -D sneakoscope
37
- npx sks doctor --fix --install-scope project
38
- npx sks init --install-scope project
212
+ npx sks setup --install-scope project
213
+ ```
214
+
215
+ If a GUI hook, Codex session, or another project cannot find `sks`, refresh the hook command with the resolved binary path:
216
+
217
+ ```bash
218
+ sks fix-path
219
+ ```
220
+
221
+ If your shell cannot find the global command yet, run through npm without relying on PATH:
222
+
223
+ ```bash
224
+ npx -y -p sneakoscope sks setup
39
225
  ```
40
226
 
41
227
  Create a Ralph mission:
@@ -73,6 +259,8 @@ sks research run latest --max-cycles 3
73
259
  - **Sealed decision contract**: `ralph answer` validates answers and writes `decision-contract.json`.
74
260
  - **No-question Ralph loop**: after `ralph run` starts, Ralph must resolve ambiguity with the sealed contract instead of asking the user.
75
261
  - **Research mode**: `research` runs a frontier-discovery loop for non-obvious hypotheses, falsification, novelty ledgers, and testable experiments.
262
+ - **Prompt pipeline and `$` routes**: user prompts are lightly optimized by default, and Codex App users can force routes such as `$DF`, `$Ralph`, `$Research`, `$DB`, and `$GX`.
263
+ - **Fast DF mode**: `$DF` handles small design/content edits like color, copy, labels, spacing, and translation without unnecessary Ralph, Research, or evaluation loops.
76
264
  - **Database guard**: destructive DB operations, production writes, unsafe Supabase MCP configuration, and direct live SQL mutations are blocked or warned on.
77
265
  - **H-Proof done gate**: completion requires supported critical claims, reviewed DB safety state, acceptable visual/wiki drift, and required test evidence.
78
266
  - **Performance evaluation**: `sks eval` produces deterministic token, accuracy-proxy, recall, support, and runtime metrics for before/after evidence.
@@ -110,7 +298,24 @@ Core invariants:
110
298
 
111
299
  ## Commands
112
300
 
301
+ All examples below use `sks`, but the same commands can be run with the `sneakoscope` alias.
302
+
113
303
  ```bash
304
+ sks help [topic]
305
+ sks commands [--json]
306
+ sks usage [install|setup|ralph|research|db|codex-app|df|dollar|eval|gx]
307
+ sks quickstart
308
+ sks install-prompt [--project]
309
+ sks codex-app
310
+ sks dollar-commands [--json]
311
+ sks df
312
+ sks aliases
313
+
314
+ sks --help
315
+ sneakoscope --help
316
+
317
+ sks setup [--install-scope global|project] [--force] [--json]
318
+ sks fix-path [--install-scope global|project] [--json]
114
319
  sks doctor [--fix] [--json] [--install-scope global|project]
115
320
  sks init [--force] [--install-scope global|project]
116
321
  sks selftest [--mock]
@@ -138,6 +343,7 @@ sks eval compare --baseline old.json --candidate new.json [--json]
138
343
  sks eval thresholds
139
344
 
140
345
  sks hproof check [mission-id|latest]
346
+ sks team "task"
141
347
  sks gx init [name]
142
348
  sks gx render [name] [--format svg|html|all]
143
349
  sks gx validate [name]
@@ -146,6 +352,7 @@ sks gx snapshot [name]
146
352
  sks profile show
147
353
  sks profile set <model>
148
354
  sks gc [--dry-run] [--json]
355
+ sks memory [--dry-run] [--json]
149
356
  sks stats [--json]
150
357
  ```
151
358
 
@@ -272,6 +479,8 @@ sks hproof check latest
272
479
  .sneakoscope/ mission state, policy, retention, logs, GX cartridges
273
480
  .codex/config.toml Codex profiles used by Sneakoscope Codex
274
481
  .codex/hooks.json hook entrypoints
482
+ .codex/skills/ Codex App local project skills
483
+ .codex/SNEAKOSCOPE.md Codex App quick reference
275
484
  .agents/skills/ Sneakoscope Codex helper skills
276
485
  AGENTS.md managed repository rules block
277
486
  ```
@@ -279,7 +488,7 @@ AGENTS.md managed repository rules block
279
488
  Install scope controls `.codex/hooks.json`:
280
489
 
281
490
  ```text
282
- global -> sks hook ...
491
+ global -> /absolute/path/to/sks hook ... when resolvable, otherwise sks hook ...
283
492
  project -> node ./node_modules/sneakoscope/bin/sks.mjs hook ...
284
493
  ```
285
494
 
@@ -362,12 +571,32 @@ The published npm package is allowlisted to `bin`, `src`, `docs`, `README.md`, a
362
571
  ## Development
363
572
 
364
573
  ```bash
574
+ npm run repo-audit
365
575
  npm run packcheck
366
576
  npm run selftest
367
577
  npm run sizecheck
368
578
  npm run doctor
369
579
  ```
370
580
 
581
+ `npm run repo-audit` checks tracked files for risky local paths and high-confidence secret material such as private keys, npm/GitHub/OpenAI-style tokens, local MCP configs, DB dumps, and credential files. It is included in `prepack` and `prepublishOnly`.
582
+
371
583
  `npm run sizecheck` blocks accidental package bloat before `npm pack` or `npm publish`. Defaults: packed tarball `<=96 KiB`, unpacked package `<=320 KiB`, package files `<=40`, and each tracked file `<=256 KiB`. Override only for an intentional release with `SKS_MAX_PACK_BYTES`, `SKS_MAX_UNPACKED_BYTES`, `SKS_MAX_PACK_FILES`, or `SKS_MAX_TRACKED_FILE_BYTES`.
372
584
 
373
585
  `npm run selftest` uses the mock path and does not call a model. Live Ralph runs require a working Codex CLI installation and authentication.
586
+
587
+ ## Publishing
588
+
589
+ The npm package is published as public package `sneakoscope`. You must be logged in as an npm owner for that package before publishing.
590
+
591
+ ```bash
592
+ npm whoami
593
+ npm owner ls sneakoscope
594
+ npm run publish:dry
595
+ npm run publish:npm
596
+ ```
597
+
598
+ If `npm whoami` returns `E401 Unauthorized`, run `npm login` with an owner account or ask an existing owner to add your npm username:
599
+
600
+ ```bash
601
+ npm owner add <your-npm-username> sneakoscope
602
+ ```
@@ -1,6 +1,6 @@
1
1
  # Sneakoscope Codex performance and leak policy
2
2
 
3
- Sneakoscope Codex v0.5 is designed to keep runtime, package size, RAM, and storage bounded.
3
+ Sneakoscope Codex v0.6 is designed to keep runtime, package size, RAM, and storage bounded.
4
4
 
5
5
  ## Speed
6
6
 
package/package.json CHANGED
@@ -1,11 +1,16 @@
1
1
  {
2
2
  "name": "sneakoscope",
3
3
  "displayName": "Sneakoscope Codex",
4
- "version": "0.5.0",
4
+ "version": "0.6.0",
5
5
  "description": "Sneakoscope Codex: database-safe, performance-bounded Codex CLI harness with Ralph no-question loop, H-Proof gates, deterministic GX visual context, and TriWiki compression.",
6
6
  "type": "module",
7
7
  "bin": {
8
- "sks": "bin/sks.mjs"
8
+ "sks": "bin/sks.mjs",
9
+ "sneakoscope": "bin/sks.mjs"
10
+ },
11
+ "publishConfig": {
12
+ "access": "public",
13
+ "registry": "https://registry.npmjs.org/"
9
14
  },
10
15
  "files": [
11
16
  "bin",
@@ -18,12 +23,15 @@
18
23
  "node": ">=20.11"
19
24
  },
20
25
  "scripts": {
26
+ "repo-audit": "node ./scripts/repo-audit.mjs",
21
27
  "selftest": "node ./bin/sks.mjs selftest --mock",
22
28
  "doctor": "node ./bin/sks.mjs doctor",
23
29
  "packcheck": "find bin src scripts -name '*.mjs' -print0 | xargs -0 -n1 node --check",
24
30
  "sizecheck": "node ./scripts/sizecheck.mjs",
25
- "prepack": "npm run packcheck && npm run selftest && npm run sizecheck",
26
- "prepublishOnly": "npm run packcheck && npm run selftest && npm run sizecheck"
31
+ "publish:dry": "npm --cache /tmp/sks-npm-cache pack --dry-run",
32
+ "publish:npm": "npm --cache /tmp/sks-npm-cache publish --access public",
33
+ "prepack": "npm run repo-audit && npm run packcheck && npm run selftest && npm run sizecheck",
34
+ "prepublishOnly": "npm run repo-audit && npm run packcheck && npm run selftest && npm run sizecheck"
27
35
  },
28
36
  "keywords": [
29
37
  "sneakoscope",
package/src/cli/main.mjs CHANGED
@@ -18,6 +18,46 @@ import { buildResearchPrompt, evaluateResearchGate, writeMockResearchResult, wri
18
18
 
19
19
  const flag = (args, name) => args.includes(name);
20
20
  const promptOf = (args) => args.filter((x) => !String(x).startsWith('--')).join(' ').trim();
21
+ const REPOSITORY_URL = 'https://github.com/mandarange/Sneakoscope-Codex.git';
22
+ const USAGE_TOPICS = 'install|setup|ralph|research|db|codex-app|df|dollar|eval|gx';
23
+
24
+ const DOLLAR_COMMANDS = [
25
+ { command: '$DF', route: 'fast design/content fix', description: 'Small UI/content edits such as text color, copy, label, spacing, or translation. Avoids heavy loops.' },
26
+ { command: '$SKS', route: 'general SKS workflow', description: 'General Sneakoscope setup, help, status, and workflow routing.' },
27
+ { command: '$Ralph', route: 'Ralph mission', description: 'Mandatory clarification and no-question autonomous mission workflow.' },
28
+ { command: '$Research', route: 'research mission', description: 'Frontier discovery, hypotheses, falsification, and testable predictions.' },
29
+ { command: '$DB', route: 'database safety', description: 'Database, Supabase, migration, SQL, or MCP safety checks.' },
30
+ { command: '$GX', route: 'visual context', description: 'Deterministic GX visual context cartridges.' },
31
+ { command: '$Help', route: 'command help', description: 'Explain installed SKS commands and workflows.' }
32
+ ];
33
+
34
+ const COMMAND_CATALOG = [
35
+ { name: 'help', usage: 'sks help [topic]', description: 'Show CLI help or focused help for a topic.' },
36
+ { name: 'commands', usage: 'sks commands [--json]', description: 'List every user-facing command with a short description.' },
37
+ { name: 'usage', usage: `sks usage [${USAGE_TOPICS}]`, description: 'Print copy-ready workflows for common tasks.' },
38
+ { name: 'quickstart', usage: 'sks quickstart', description: 'Show the shortest safe setup and verification flow.' },
39
+ { name: 'install-prompt', usage: 'sks install-prompt [--project]', description: 'Print an LLM-ready prompt that installs and configures SKS automatically.' },
40
+ { name: 'codex-app', usage: 'sks codex-app', description: 'Show Codex App setup files and example prompts.' },
41
+ { name: 'dollar-commands', usage: 'sks dollar-commands [--json]', description: 'List Codex App $ commands such as $DF.' },
42
+ { name: 'df', usage: 'sks df', description: 'Explain $DF fast design/content fix mode.' },
43
+ { name: 'aliases', usage: 'sks aliases', description: 'Show command aliases and npm binary names.' },
44
+ { name: 'setup', usage: 'sks setup [--install-scope global|project] [--force] [--json]', description: 'Initialize SKS state, Codex App files, hooks, skills, and rules.' },
45
+ { name: 'fix-path', usage: 'sks fix-path [--install-scope global|project] [--json]', description: 'Refresh hook commands with the resolved SKS binary path.' },
46
+ { name: 'doctor', usage: 'sks doctor [--fix] [--json] [--install-scope global|project]', description: 'Check Node, Codex CLI, install scope, hooks, skills, DB guard, and Codex App files.' },
47
+ { name: 'init', usage: 'sks init [--force] [--install-scope global|project]', description: 'Initialize the local SKS control surface.' },
48
+ { name: 'selftest', usage: 'sks selftest [--mock]', description: 'Run local smoke tests without calling a model.' },
49
+ { name: 'ralph', usage: 'sks ralph prepare|answer|run|status ...', description: 'Run mandatory-clarification Ralph missions with a no-question execution loop.' },
50
+ { name: 'research', usage: 'sks research prepare|run|status ...', description: 'Run frontier-style research missions with novelty and falsification gates.' },
51
+ { name: 'db', usage: 'sks db policy|scan|mcp-config|classify|check ...', description: 'Inspect and enforce database/Supabase safety policy.' },
52
+ { name: 'eval', usage: 'sks eval run|compare|thresholds ...', description: 'Run deterministic context-quality and performance evidence checks.' },
53
+ { name: 'hproof', usage: 'sks hproof check [mission-id|latest]', description: 'Evaluate the H-Proof done gate for a mission.' },
54
+ { name: 'team', usage: 'sks team "task"', description: 'Create a clarification-gated team mission.' },
55
+ { name: 'gx', usage: 'sks gx init|render|validate|drift|snapshot [name]', description: 'Create and verify deterministic SVG/HTML visual context cartridges.' },
56
+ { name: 'profile', usage: 'sks profile show|set <model>', description: 'Inspect or set the current SKS model profile metadata.' },
57
+ { name: 'gc', usage: 'sks gc [--dry-run] [--json]', description: 'Compact oversized logs and prune stale runtime artifacts.' },
58
+ { name: 'memory', usage: 'sks memory [--dry-run] [--json]', description: 'Alias for SKS garbage collection and retention handling.' },
59
+ { name: 'stats', usage: 'sks stats [--json]', description: 'Show package and .sneakoscope storage size.' }
60
+ ];
21
61
 
22
62
  function installScopeFromArgs(args = [], fallback = 'global') {
23
63
  if (flag(args, '--project')) return 'project';
@@ -29,7 +69,18 @@ function installScopeFromArgs(args = [], fallback = 'global') {
29
69
  export async function main(args) {
30
70
  const [cmd, sub, ...rest] = args;
31
71
  const tail = sub === undefined ? [] : [sub, ...rest];
32
- if (!cmd || cmd === 'help' || cmd === '--help' || cmd === '-h') return help();
72
+ if (!cmd || cmd === '--help' || cmd === '-h') return help();
73
+ if (cmd === 'help') return help(tail);
74
+ if (cmd === 'commands') return commands(tail);
75
+ if (cmd === 'usage') return usage(tail);
76
+ if (cmd === 'quickstart') return quickstart();
77
+ if (cmd === 'install-prompt') return installPrompt(tail);
78
+ if (cmd === 'codex-app') return codexAppHelp();
79
+ if (cmd === 'dollar-commands' || cmd === 'dollars' || cmd === '$') return dollarCommands(tail);
80
+ if (String(cmd).toLowerCase() === 'df') return dfHelp();
81
+ if (cmd === 'aliases') return aliases();
82
+ if (cmd === 'setup') return setup(tail);
83
+ if (cmd === 'fix-path') return fixPath(tail);
33
84
  if (cmd === 'doctor') return doctor(tail);
34
85
  if (cmd === 'init') return init(tail);
35
86
  if (cmd === 'selftest') return selftest(tail);
@@ -49,10 +100,23 @@ export async function main(args) {
49
100
  process.exitCode = 1;
50
101
  }
51
102
 
52
- function help() {
103
+ function help(args = []) {
104
+ const topic = args[0];
105
+ if (topic) return usage([topic]);
53
106
  console.log(`Sneakoscope Codex
54
107
 
55
108
  Usage:
109
+ sks help [topic]
110
+ sks commands [--json]
111
+ sks usage [${USAGE_TOPICS}]
112
+ sks quickstart
113
+ sks install-prompt [--project]
114
+ sks codex-app
115
+ sks dollar-commands [--json]
116
+ sks df
117
+ sks aliases
118
+ sks setup [--install-scope global|project] [--force] [--json]
119
+ sks fix-path [--install-scope global|project] [--json]
56
120
  sks doctor [--fix] [--json] [--install-scope global|project]
57
121
  sks init [--install-scope global|project]
58
122
  sks selftest [--mock]
@@ -75,17 +139,441 @@ Usage:
75
139
  sks gx validate [name]
76
140
  sks gx drift [name]
77
141
  sks gx snapshot [name]
142
+ sks profile show
143
+ sks profile set <model>
78
144
  sks gc [--dry-run] [--json]
145
+ sks memory [--dry-run] [--json]
79
146
  sks stats [--json]
147
+
148
+ Discovery:
149
+ sks commands Full command list with descriptions
150
+ sks usage ralph Workflow examples for one topic
151
+ sks install-prompt Copy/paste prompt for an LLM installer
152
+ sks dollar-commands Codex App $ commands, including $DF
80
153
  `);
81
154
  }
82
155
 
156
+ function commands(args = []) {
157
+ if (flag(args, '--json')) return console.log(JSON.stringify({ aliases: ['sks', 'sneakoscope'], dollar_commands: DOLLAR_COMMANDS, commands: COMMAND_CATALOG }, null, 2));
158
+ console.log('Sneakoscope Codex Commands\n');
159
+ console.log('Aliases: sks, sneakoscope\n');
160
+ const width = Math.max(...COMMAND_CATALOG.map((c) => c.usage.length));
161
+ for (const c of COMMAND_CATALOG) console.log(`${c.usage.padEnd(width)} ${c.description}`);
162
+ }
163
+
164
+ function dollarCommands(args = []) {
165
+ if (flag(args, '--json')) return console.log(JSON.stringify({ dollar_commands: DOLLAR_COMMANDS }, null, 2));
166
+ console.log('Sneakoscope Codex $ Commands\n');
167
+ console.log('Use these inside Codex App or another agent prompt. Shells treat $ as variable syntax, so these are prompt commands, not terminal commands.\n');
168
+ const width = Math.max(...DOLLAR_COMMANDS.map((c) => c.command.length));
169
+ for (const c of DOLLAR_COMMANDS) console.log(`${c.command.padEnd(width)} ${c.route}: ${c.description}`);
170
+ console.log('\nDefault pipeline: even without a $ command, SKS optimizes the prompt and infers the lightest route. Simple design/content edits infer $DF.');
171
+ }
172
+
173
+ function dfHelp() {
174
+ console.log(`SKS DF Mode
175
+
176
+ Prompt command:
177
+ $DF <small design/content request>
178
+
179
+ Examples:
180
+ $DF 글자 색 파란색으로 바꿔줘
181
+ $DF 내용을 영어로 바꿔줘
182
+ $DF Change the CTA label to "Start"
183
+
184
+ Purpose:
185
+ Fast design/content fixes only. DF should prompt-engineer the user's request into the smallest implementation change.
186
+
187
+ Rules:
188
+ Do not run Ralph, Research, eval, or broad redesign.
189
+ Inspect only what is needed, edit only what is requested, and run cheap verification when useful.
190
+ `);
191
+ }
192
+
193
+ function quickstart() {
194
+ console.log(`Sneakoscope Codex Quickstart
195
+
196
+ Install from npm:
197
+ npm i -g sneakoscope
198
+
199
+ Install from GitHub:
200
+ npm i -g git+${REPOSITORY_URL}
201
+
202
+ Initialize this project for CLI and Codex App:
203
+ sks setup
204
+
205
+ Verify:
206
+ sks doctor --fix
207
+ sks selftest --mock
208
+ sks commands
209
+
210
+ If hooks cannot find the command:
211
+ sks fix-path
212
+
213
+ Project-only install:
214
+ npm i -D sneakoscope
215
+ npx sks setup --install-scope project
216
+ `);
217
+ }
218
+
219
+ function installPrompt(args = []) {
220
+ const projectOnly = flag(args, '--project');
221
+ const install = projectOnly
222
+ ? `npm i -D git+${REPOSITORY_URL}\nnpx sks setup --install-scope project`
223
+ : `npm i -g git+${REPOSITORY_URL}\nsks setup`;
224
+ console.log(`Copy this prompt into an LLM coding assistant:
225
+
226
+ You are installing Sneakoscope Codex in the current project. Do the setup end to end without asking follow-up questions unless a command needs user approval.
227
+
228
+ Repository:
229
+ ${REPOSITORY_URL}
230
+
231
+ Requirements:
232
+ - Node.js must be >=20.11.
233
+ - Codex CLI is installed separately; if missing, report that @openai/codex must be installed or SKS_CODEX_BIN must be set.
234
+ - Prefer safe, local verification. Do not modify application source files unless needed for SKS setup.
235
+
236
+ Run:
237
+ \`\`\`bash
238
+ ${install}
239
+ ${projectOnly ? 'npx sks doctor --fix --install-scope project\nnpx sks selftest --mock\nnpx sks commands' : 'sks doctor --fix\nsks selftest --mock\nsks commands'}
240
+ \`\`\`
241
+
242
+ If the global command is not on PATH, use:
243
+ \`\`\`bash
244
+ npx -y -p git+${REPOSITORY_URL} sks setup
245
+ npx -y -p git+${REPOSITORY_URL} sks doctor --fix
246
+ \`\`\`
247
+
248
+ After setup, explain these outputs to the user:
249
+ - \`.sneakoscope/\` mission state and policy
250
+ - \`.codex/config.toml\` Codex App profiles
251
+ - \`.codex/hooks.json\` SKS hook integration
252
+ - \`.codex/skills/\` local Codex App skills
253
+ - \`.codex/SNEAKOSCOPE.md\` Codex App quick reference
254
+ - \`AGENTS.md\` repository rules
255
+
256
+ Show the user how to discover commands:
257
+ \`\`\`bash
258
+ sks help
259
+ sks commands
260
+ sks usage ralph
261
+ sks quickstart
262
+ sks codex-app
263
+ sks dollar-commands
264
+ \`\`\`
265
+
266
+ Tell the user they can use these prompt commands inside Codex App:
267
+ \`\`\`text
268
+ $DF 글자 색 바꿔줘
269
+ $DF 내용을 영어로 바꿔줘
270
+ $Ralph implement this with mandatory clarification
271
+ $Research investigate this idea
272
+ $DB check this migration safely
273
+ \`\`\`
274
+ `);
275
+ }
276
+
277
+ function codexAppHelp() {
278
+ console.log(`Sneakoscope Codex App Usage
279
+
280
+ Run once in the project:
281
+ sks setup
282
+
283
+ Generated app files:
284
+ .codex/config.toml profiles for SKS Ralph, research, and default work
285
+ .codex/hooks.json hook events routed through SKS guards
286
+ .codex/skills/ local project skills
287
+ .codex/SNEAKOSCOPE.md app quick reference
288
+ AGENTS.md repository rules
289
+
290
+ Useful prompts inside Codex App:
291
+ $DF 글자 색 바꿔줘
292
+ $DF 내용을 영어로 바꿔줘
293
+ Use Sneakoscope Ralph mode to prepare this task.
294
+ Run the latest Ralph mission with the sealed decision contract.
295
+ Use SKS DB safety before touching database or Supabase files.
296
+ Use SKS research mode for this investigation.
297
+
298
+ Repair hook PATH issues:
299
+ sks fix-path
300
+
301
+ Discover usage:
302
+ sks commands
303
+ sks usage codex-app
304
+ sks dollar-commands
305
+ sks df
306
+ sks install-prompt
307
+ `);
308
+ }
309
+
310
+ function aliases() {
311
+ console.log(`Sneakoscope Codex Aliases
312
+
313
+ Binary aliases:
314
+ sks
315
+ sneakoscope
316
+
317
+ Command aliases:
318
+ sks memory -> sks gc
319
+ sks --help -> sks help
320
+ sks -h -> sks help
321
+
322
+ Codex App prompt commands:
323
+ $DF fast design/content fix
324
+ $SKS general Sneakoscope route
325
+ $Ralph Ralph mission route
326
+ $Research research mission route
327
+ $DB database safety route
328
+ $GX visual context route
329
+ $Help command help route
330
+
331
+ Examples:
332
+ sks setup
333
+ sneakoscope setup
334
+ sks commands
335
+ sneakoscope commands
336
+ `);
337
+ }
338
+
339
+ function usage(args = []) {
340
+ const topic = String(args[0] || 'overview').toLowerCase();
341
+ const blocks = {
342
+ overview: `Sneakoscope Codex Usage
343
+
344
+ Discovery:
345
+ sks help
346
+ sks commands
347
+ sks quickstart
348
+ sks install-prompt
349
+ sks codex-app
350
+ sks dollar-commands
351
+
352
+ Common workflows:
353
+ sks usage install
354
+ sks usage ralph
355
+ sks usage research
356
+ sks usage db
357
+ sks usage df
358
+ `,
359
+ install: `Install and Setup
360
+
361
+ Global install:
362
+ npm i -g sneakoscope
363
+ sks setup
364
+ sks doctor --fix
365
+ sks selftest --mock
366
+
367
+ GitHub install:
368
+ npm i -g git+${REPOSITORY_URL}
369
+ sks setup
370
+
371
+ Project-only install:
372
+ npm i -D sneakoscope
373
+ npx sks setup --install-scope project
374
+
375
+ LLM-assisted install:
376
+ sks install-prompt
377
+ `,
378
+ setup: `Setup Repair
379
+
380
+ Initialize:
381
+ sks setup
382
+
383
+ Refresh hook command paths:
384
+ sks fix-path
385
+
386
+ Inspect readiness:
387
+ sks doctor
388
+ sks doctor --fix
389
+ sks doctor --json
390
+ `,
391
+ ralph: `Ralph Workflow
392
+
393
+ Prepare:
394
+ sks ralph prepare "task"
395
+
396
+ Answer generated slots:
397
+ cat .sneakoscope/missions/<MISSION_ID>/questions.md
398
+ cp .sneakoscope/missions/<MISSION_ID>/required-answers.schema.json answers.json
399
+ sks ralph answer <MISSION_ID> answers.json
400
+
401
+ Run:
402
+ sks ralph run <MISSION_ID> --max-cycles 8
403
+ sks ralph status latest
404
+
405
+ Local smoke run:
406
+ sks ralph run latest --mock
407
+ `,
408
+ research: `Research Workflow
409
+
410
+ Prepare:
411
+ sks research prepare "topic" --depth frontier
412
+
413
+ Run:
414
+ sks research run latest --max-cycles 3
415
+
416
+ Inspect:
417
+ sks research status latest
418
+ `,
419
+ db: `Database Safety
420
+
421
+ Policy:
422
+ sks db policy
423
+
424
+ Scan project config:
425
+ sks db scan --migrations
426
+
427
+ Generate safe Supabase MCP config:
428
+ sks db mcp-config --project-ref <ref> --features database,docs
429
+
430
+ Classify/check operations:
431
+ sks db classify --sql "DROP TABLE users"
432
+ sks db check --command "supabase db reset"
433
+ sks db check --file ./migration.sql
434
+ `,
435
+ 'codex-app': `Codex App
436
+
437
+ Initialize app files:
438
+ sks setup
439
+
440
+ Inspect app guidance:
441
+ sks codex-app
442
+ sks dollar-commands
443
+ cat .codex/SNEAKOSCOPE.md
444
+
445
+ Use inside Codex App:
446
+ $DF 글자 색 바꿔줘
447
+ $DF 내용을 영어로 바꿔줘
448
+ Use Sneakoscope Ralph mode to prepare this task.
449
+ Use SKS DB safety before touching database or Supabase files.
450
+ `,
451
+ df: `DF Fast Design/Content Fix
452
+
453
+ Use inside Codex App:
454
+ $DF 글자 색 파란색으로 바꿔줘
455
+ $DF 내용을 영어로 바꿔줘
456
+ $DF Change the button label to "Start"
457
+
458
+ Behavior:
459
+ Prompt-engineer the request into the smallest design/content edit.
460
+ Do not start Ralph, Research, eval, or a broad redesign.
461
+ Inspect only relevant files and run only cheap verification when useful.
462
+
463
+ CLI help:
464
+ sks df
465
+ `,
466
+ dollar: `Dollar Commands
467
+
468
+ Use inside Codex App or an agent prompt:
469
+ $DF fast design/content fix
470
+ $SKS general Sneakoscope route
471
+ $Ralph Ralph mission route
472
+ $Research research mission route
473
+ $DB database safety route
474
+ $GX visual context route
475
+ $Help command help route
476
+
477
+ Terminal discovery:
478
+ sks dollar-commands
479
+ sks dollar-commands --json
480
+ `,
481
+ eval: `Evaluation
482
+
483
+ Run benchmark:
484
+ sks eval run
485
+ sks eval run --json --out report.json
486
+
487
+ Compare reports:
488
+ sks eval compare --baseline old.json --candidate new.json
489
+
490
+ Show thresholds:
491
+ sks eval thresholds
492
+ `,
493
+ gx: `GX Visual Context
494
+
495
+ Create:
496
+ sks gx init architecture-atlas
497
+
498
+ Render and verify:
499
+ sks gx render architecture-atlas --format all
500
+ sks gx validate architecture-atlas
501
+ sks gx drift architecture-atlas
502
+ sks gx snapshot architecture-atlas
503
+ `
504
+ };
505
+ const text = blocks[topic] || blocks.overview;
506
+ console.log(text);
507
+ }
508
+
509
+ async function setup(args) {
510
+ const root = await projectRoot();
511
+ const installScope = installScopeFromArgs(args);
512
+ const globalCommand = await globalSksCommand();
513
+ const res = await initProject(root, { force: flag(args, '--force'), installScope, globalCommand });
514
+ const install = await installStatus(root, installScope, { globalCommand });
515
+ const hooksPath = path.join(root, '.codex', 'hooks.json');
516
+ const result = {
517
+ root,
518
+ install,
519
+ hooks: hooksPath,
520
+ codex_app: {
521
+ config: path.join(root, '.codex', 'config.toml'),
522
+ hooks: hooksPath,
523
+ skills: path.join(root, '.codex', 'skills'),
524
+ quick_reference: path.join(root, '.codex', 'SNEAKOSCOPE.md'),
525
+ agents_rules: path.join(root, 'AGENTS.md')
526
+ },
527
+ created: res.created,
528
+ next: ['sks selftest --mock', 'sks doctor', 'sks commands']
529
+ };
530
+ if (flag(args, '--json')) return console.log(JSON.stringify(result, null, 2));
531
+ console.log('Sneakoscope Codex Setup\n');
532
+ console.log(`Project: ${root}`);
533
+ console.log(`Install: ${install.ok ? 'ok' : 'missing'} ${install.scope} (${install.command_prefix})`);
534
+ console.log(`Hooks: ${path.relative(root, hooksPath)}`);
535
+ console.log(`Codex App: .codex/config.toml, .codex/hooks.json, .codex/skills, .codex/SNEAKOSCOPE.md`);
536
+ console.log(`Prompt: default optimization pipeline, $DF fast design/content route`);
537
+ console.log(`Skills: .codex/skills, .agents/skills`);
538
+ console.log(`Next: sks selftest --mock; sks commands; sks dollar-commands`);
539
+ if (!install.ok && install.scope === 'global') console.log('\nGlobal command missing. Run: npm i -g sneakoscope');
540
+ if (!install.ok && install.scope === 'project') console.log('\nProject package missing. Run: npm i -D sneakoscope');
541
+ }
542
+
543
+ async function fixPath(args) {
544
+ const root = await projectRoot();
545
+ const manifest = await readJson(path.join(root, '.sneakoscope', 'manifest.json'), null);
546
+ const installScope = args.includes('--install-scope') || flag(args, '--project') || flag(args, '--global')
547
+ ? installScopeFromArgs(args)
548
+ : normalizeInstallScope(manifest?.installation?.scope || 'global');
549
+ const globalCommand = await globalSksCommand();
550
+ await initProject(root, { installScope, globalCommand });
551
+ const install = await installStatus(root, installScope, { globalCommand });
552
+ const result = {
553
+ root,
554
+ install_scope: installScope,
555
+ hook_command_prefix: sksCommandPrefix(installScope, { globalCommand }),
556
+ hooks: path.join(root, '.codex', 'hooks.json'),
557
+ install
558
+ };
559
+ if (flag(args, '--json')) return console.log(JSON.stringify(result, null, 2));
560
+ console.log('SKS hook path refreshed\n');
561
+ console.log(`Project: ${root}`);
562
+ console.log(`Install: ${install.ok ? 'ok' : 'missing'} ${install.scope} (${install.command_prefix})`);
563
+ console.log(`Hooks: .codex/hooks.json`);
564
+ if (!install.ok && install.scope === 'global') console.log('\nGlobal command missing. Run: npm i -g sneakoscope');
565
+ if (!install.ok && install.scope === 'project') console.log('\nProject package missing. Run: npm i -D sneakoscope');
566
+ }
567
+
83
568
  async function doctor(args) {
84
569
  const root = await projectRoot();
85
570
  const requestedScope = args.includes('--install-scope') || flag(args, '--project') || flag(args, '--global')
86
571
  ? installScopeFromArgs(args)
87
572
  : null;
88
- if (flag(args, '--fix')) await initProject(root, { installScope: requestedScope || 'global' });
573
+ if (flag(args, '--fix')) {
574
+ const fixScope = requestedScope || 'global';
575
+ await initProject(root, { installScope: fixScope, globalCommand: await globalSksCommand() });
576
+ }
89
577
  const codex = await getCodexInfo();
90
578
  const rust = await rustInfo();
91
579
  const nodeOk = Number(process.versions.node.split('.')[0]) >= 20;
@@ -96,16 +584,27 @@ async function doctor(args) {
96
584
  const install = await installStatus(root, installScope);
97
585
  const dbPolicyExists = await exists(path.join(root, '.sneakoscope', 'db-safety.json'));
98
586
  const dbScan = await scanDbSafety(root).catch((err) => ({ ok: false, findings: [{ id: 'db_safety_scan_failed', severity: 'high', reason: err.message }] }));
587
+ const codexApp = {
588
+ config: { ok: await exists(path.join(root, '.codex', 'config.toml')) },
589
+ hooks: { ok: await exists(path.join(root, '.codex', 'hooks.json')) },
590
+ skills: { ok: await exists(path.join(root, '.codex', 'skills')) },
591
+ quick_reference: { ok: await exists(path.join(root, '.codex', 'SNEAKOSCOPE.md')) },
592
+ agents_rules: { ok: await exists(path.join(root, 'AGENTS.md')) }
593
+ };
99
594
  const result = {
100
595
  node: { ok: nodeOk, version: process.version }, root, codex, rust,
101
596
  install,
102
597
  sneakoscope: { ok: await exists(path.join(root, '.sneakoscope')) },
103
598
  db_guard: { ok: dbPolicyExists && dbScan.ok, policy: dbPolicyExists ? await loadDbSafetyPolicy(root) : null, scan: dbScan },
104
599
  hooks: { ok: await exists(path.join(root, '.codex', 'hooks.json')) },
105
- skills: { ok: await exists(path.join(root, '.agents', 'skills')) },
600
+ skills: { ok: (await exists(path.join(root, '.codex', 'skills'))) && (await exists(path.join(root, '.agents', 'skills'))) },
601
+ codex_app: {
602
+ ...codexApp,
603
+ ok: codexApp.config.ok && codexApp.hooks.ok && codexApp.skills.ok && codexApp.quick_reference.ok && codexApp.agents_rules.ok
604
+ },
106
605
  package: { bytes: pkgBytes, human: formatBytes(pkgBytes) }, storage
107
606
  };
108
- result.ready = nodeOk && Boolean(codex.bin) && install.ok && result.sneakoscope.ok && result.db_guard.ok;
607
+ result.ready = nodeOk && Boolean(codex.bin) && install.ok && result.sneakoscope.ok && result.db_guard.ok && result.codex_app.ok;
109
608
  if (flag(args, '--json')) return console.log(JSON.stringify(result, null, 2));
110
609
  console.log('Sneakoscope Codex Doctor\n');
111
610
  console.log(`Node: ${nodeOk ? 'ok' : 'fail'} ${process.version}`);
@@ -116,7 +615,8 @@ async function doctor(args) {
116
615
  console.log(`State: ${result.sneakoscope.ok ? 'ok' : 'missing .sneakoscope'}`);
117
616
  console.log(`DB Guard: ${result.db_guard.ok ? 'ok' : 'blocked'} ${dbScan.findings?.length || 0} finding(s)`);
118
617
  console.log(`Hooks: ${result.hooks.ok ? 'ok' : 'missing .codex/hooks.json'}`);
119
- console.log(`Skills: ${result.skills.ok ? 'ok' : 'missing .agents/skills'}`);
618
+ console.log(`Codex App: ${result.codex_app.ok ? 'ok' : 'missing app files'} .codex/config.toml .codex/hooks.json .codex/skills .codex/SNEAKOSCOPE.md`);
619
+ console.log(`Skills: ${result.skills.ok ? 'ok' : 'missing .codex/skills or .agents/skills'}`);
120
620
  console.log(`Package: ${result.package.human}`);
121
621
  console.log(`Storage: ${storage.total_human || '0 B'}`);
122
622
  console.log(`Ready: ${result.ready ? 'yes' : 'no'}`);
@@ -129,15 +629,22 @@ async function doctor(args) {
129
629
  async function init(args) {
130
630
  const root = await projectRoot();
131
631
  const installScope = installScopeFromArgs(args);
132
- const res = await initProject(root, { force: flag(args, '--force'), installScope });
632
+ const globalCommand = await globalSksCommand();
633
+ const res = await initProject(root, { force: flag(args, '--force'), installScope, globalCommand });
133
634
  console.log(`Initialized Sneakoscope Codex in ${root}`);
134
- console.log(`Install scope: ${installScope} (${sksCommandPrefix(installScope)})`);
635
+ console.log(`Install scope: ${installScope} (${sksCommandPrefix(installScope, { globalCommand })})`);
135
636
  for (const x of res.created) console.log(`- ${x}`);
136
637
  }
137
638
 
138
- async function installStatus(root, scope) {
139
- const commandPrefix = sksCommandPrefix(scope);
140
- const globalBin = await which('sks').catch(() => null);
639
+ async function globalSksCommand() {
640
+ return process.env.SKS_BIN || await which('sks').catch(() => null) || 'sks';
641
+ }
642
+
643
+ async function installStatus(root, scope, opts = {}) {
644
+ const discoveredGlobalBin = await which('sks').catch(() => null);
645
+ const configuredGlobalBin = process.env.SKS_BIN || (opts.globalCommand && opts.globalCommand !== 'sks' ? opts.globalCommand : null);
646
+ const globalBin = configuredGlobalBin || discoveredGlobalBin;
647
+ const commandPrefix = sksCommandPrefix(scope, { globalCommand: globalBin || undefined });
141
648
  const projectBin = path.join(root, 'node_modules', 'sneakoscope', 'bin', 'sks.mjs');
142
649
  const projectBinExists = await exists(projectBin);
143
650
  return {
@@ -386,12 +893,24 @@ async function selftest() {
386
893
  await initProject(tmp, {});
387
894
  const defaultHooks = await readJson(path.join(tmp, '.codex', 'hooks.json'));
388
895
  if (defaultHooks.hooks.PreToolUse[0].hooks[0].command !== 'sks hook pre-tool') throw new Error('selftest failed: global install hook command changed');
896
+ const absoluteHookTmp = tmpdir();
897
+ await initProject(absoluteHookTmp, { globalCommand: '/usr/local/bin/sks' });
898
+ const absoluteHooks = await readJson(path.join(absoluteHookTmp, '.codex', 'hooks.json'));
899
+ if (absoluteHooks.hooks.PreToolUse[0].hooks[0].command !== '/usr/local/bin/sks hook pre-tool') throw new Error('selftest failed: absolute global hook command missing');
389
900
  const projectScopeTmp = tmpdir();
390
901
  await initProject(projectScopeTmp, { installScope: 'project' });
391
902
  const projectHooks = await readJson(path.join(projectScopeTmp, '.codex', 'hooks.json'));
392
903
  if (projectHooks.hooks.PreToolUse[0].hooks[0].command !== 'node ./node_modules/sneakoscope/bin/sks.mjs hook pre-tool') throw new Error('selftest failed: project install hook command missing');
393
904
  const researchSkillExists = await exists(path.join(tmp, '.agents', 'skills', 'research-discovery', 'SKILL.md'));
394
905
  if (!researchSkillExists) throw new Error('selftest failed: research skill not installed');
906
+ const codexAppSkillExists = await exists(path.join(tmp, '.codex', 'skills', 'research-discovery', 'SKILL.md'));
907
+ if (!codexAppSkillExists) throw new Error('selftest failed: Codex App skill not installed');
908
+ const dfSkillExists = await exists(path.join(tmp, '.codex', 'skills', 'DF', 'SKILL.md'));
909
+ if (!dfSkillExists) throw new Error('selftest failed: $DF skill not installed');
910
+ const promptPipelineSkillExists = await exists(path.join(tmp, '.codex', 'skills', 'prompt-pipeline', 'SKILL.md'));
911
+ if (!promptPipelineSkillExists) throw new Error('selftest failed: prompt pipeline skill not installed');
912
+ const codexAppQuickRefExists = await exists(path.join(tmp, '.codex', 'SNEAKOSCOPE.md'));
913
+ if (!codexAppQuickRefExists) throw new Error('selftest failed: Codex App quick reference missing');
395
914
  const { id, dir, mission } = await createMission(tmp, { mode: 'ralph', prompt: '로그인 세션 만료 UX 개선 supabase db' });
396
915
  const schema = buildQuestionSchema(mission.prompt);
397
916
  await writeQuestions(dir, schema);
package/src/core/fsx.mjs CHANGED
@@ -5,7 +5,7 @@ import os from 'node:os';
5
5
  import crypto from 'node:crypto';
6
6
  import { spawn } from 'node:child_process';
7
7
 
8
- export const PACKAGE_VERSION = '0.5.0';
8
+ export const PACKAGE_VERSION = '0.6.0';
9
9
  export const DEFAULT_PROCESS_TAIL_BYTES = 256 * 1024;
10
10
  export const DEFAULT_PROCESS_TIMEOUT_MS = 30 * 60 * 1000;
11
11
 
@@ -22,10 +22,43 @@ function extractLastMessage(payload) {
22
22
  return payload.last_assistant_message || payload.assistant_message || payload.message || payload.response || payload.raw || '';
23
23
  }
24
24
 
25
+ function extractUserPrompt(payload) {
26
+ return payload.prompt
27
+ || payload.user_prompt
28
+ || payload.userPrompt
29
+ || payload.message
30
+ || payload.input?.prompt
31
+ || payload.input?.message
32
+ || payload.raw
33
+ || '';
34
+ }
35
+
25
36
  function extractCommand(payload) {
26
37
  return payload.command || payload.tool_input?.command || payload.input?.command || payload.tool?.input?.command || '';
27
38
  }
28
39
 
40
+ function dollarCommand(prompt) {
41
+ const match = String(prompt || '').trim().match(/^\$([A-Za-z][A-Za-z0-9_-]*)(?:\s|:|$)/);
42
+ return match ? match[1].toUpperCase() : null;
43
+ }
44
+
45
+ function looksLikeFastDesignFix(prompt) {
46
+ const text = String(prompt || '');
47
+ const designCue = /(글자|텍스트|문구|내용|색|컬러|폰트|간격|여백|정렬|버튼|라벨|영어|한국어|번역|copy|text|color|font|spacing|padding|margin|align|label|button|translate)/i.test(text);
48
+ const changeCue = /(바꿔|변경|수정|교체|고쳐|영어로|한국어로|change|replace|update|make|turn|translate|fix)/i.test(text);
49
+ return designCue && changeCue;
50
+ }
51
+
52
+ function promptPipelineContext(prompt) {
53
+ const command = dollarCommand(prompt);
54
+ const fastDesign = command === 'DF' || looksLikeFastDesignFix(prompt);
55
+ const route = command ? `$${command}` : (fastDesign ? '$DF inferred' : 'default');
56
+ const dfLine = fastDesign
57
+ ? '\nFast design fix: treat this as $DF. Do the smallest relevant edit, avoid Ralph/research loops, avoid broad redesign, and run only cheap verification when useful.'
58
+ : '';
59
+ return `SKS prompt pipeline active. Route: ${route}. Optimize the user request before acting: extract intent, target files/surfaces, constraints, acceptance criteria, and the smallest safe execution path. Use explicit $ commands when present: $DF fast design/content edit, $Ralph clarification-gated mission, $Research discovery run, $DB database safety, $GX visual context, $SKS general SKS help. Without a command, infer the lightest matching route and avoid heavy loops unless the task requires them.${dfLine}`;
60
+ }
61
+
29
62
  export async function hookMain(name) {
30
63
  const payload = await loadHookPayload();
31
64
  const root = await projectRoot(payload.cwd || process.cwd());
@@ -40,7 +73,7 @@ export async function hookMain(name) {
40
73
  }
41
74
 
42
75
  async function hookUserPrompt(root, state, payload, noQuestion) {
43
- if (!noQuestion) return { continue: true };
76
+ if (!noQuestion) return { continue: true, additionalContext: promptPipelineContext(extractUserPrompt(payload)) };
44
77
  const id = state.mission_id;
45
78
  if (id) await appendJsonl(path.join(missionDir(root, id), 'user_queue.jsonl'), { ts: nowIso(), payload });
46
79
  return {
package/src/core/init.mjs CHANGED
@@ -9,14 +9,14 @@ export function normalizeInstallScope(scope = 'global') {
9
9
  throw new Error(`Invalid install scope: ${scope}. Use "global" or "project".`);
10
10
  }
11
11
 
12
- export function sksCommandPrefix(scope = 'global') {
12
+ export function sksCommandPrefix(scope = 'global', opts = {}) {
13
13
  return normalizeInstallScope(scope) === 'project'
14
14
  ? 'node ./node_modules/sneakoscope/bin/sks.mjs'
15
- : 'sks';
15
+ : (opts.globalCommand || 'sks');
16
16
  }
17
17
 
18
- function sksHookCommand(scope, hookName) {
19
- return `${sksCommandPrefix(scope)} hook ${hookName}`;
18
+ function sksHookCommand(commandPrefix, hookName) {
19
+ return `${commandPrefix} hook ${hookName}`;
20
20
  }
21
21
 
22
22
  const AGENTS_BLOCK = `
@@ -44,6 +44,18 @@ When the user asks for research, new discoveries, hypothesis generation, frontie
44
44
 
45
45
  When creating HTML, UI, prototype, deck-like, or visual artifacts, use the local design artifact skill. Gather design context first, build the actual usable experience rather than a marketing placeholder, expose variations when useful, and verify the rendered artifact before handoff.
46
46
 
47
+ ## Prompt Optimization Pipeline
48
+
49
+ Every user prompt enters the SKS prompt optimization pipeline even when the user does not type a command. Extract intent, target files or surfaces, constraints, acceptance criteria, risks, and the smallest safe execution path before acting. Choose the lightest matching route: fast edit, normal implementation, Ralph, Research, DB safety, GX, or evaluation. Do not run heavy Ralph/research/evaluation loops for simple direct edits.
50
+
51
+ ## Dollar Commands
52
+
53
+ Codex App users may invoke local SKS modes with skill-style dollar commands. \`$DF\` is the fast design/content fix route for small changes such as text color, copy edits, label changes, spacing tweaks, or translating visible text. \`$DF\` should avoid broad redesign, avoid unnecessary planning loops, and make the requested change directly with only cheap verification when useful.
54
+
55
+ ## Codex App Usage
56
+
57
+ When this repository is opened in Codex App, use the local Sneakoscope files as the app control surface. Read \`.codex/SNEAKOSCOPE.md\` for the quick reference, load project skills from \`.codex/skills\` when applicable, and use the generated \`.codex/hooks.json\` hooks for DB safety, no-question Ralph runs, retention, and done-gate enforcement.
58
+
47
59
  ## Source Priority
48
60
 
49
61
  1. Current code, tests, config
@@ -66,9 +78,10 @@ A task is not done until relevant tests are run or justified, unsupported critic
66
78
  export async function initProject(root, opts = {}) {
67
79
  const created = [];
68
80
  const installScope = normalizeInstallScope(opts.installScope || 'global');
81
+ const hookCommandPrefix = opts.hookCommandPrefix || sksCommandPrefix(installScope, { globalCommand: opts.globalCommand });
69
82
  const sine = path.join(root, '.sneakoscope');
70
83
  const dirs = [
71
- '.sneakoscope/state', '.sneakoscope/missions', '.sneakoscope/db', '.sneakoscope/bus', '.sneakoscope/hproof', '.sneakoscope/db', '.sneakoscope/memory/q0_raw', '.sneakoscope/memory/q1_evidence', '.sneakoscope/memory/q2_facts', '.sneakoscope/memory/q3_tags', '.sneakoscope/memory/q4_bits', '.sneakoscope/gx/cartridges', '.sneakoscope/model/fingerprints', '.sneakoscope/genome/candidates', '.sneakoscope/trajectories/raw', '.sneakoscope/locks', '.sneakoscope/tmp', '.sneakoscope/arenas', '.sneakoscope/reports', '.codex', '.agents/skills'
84
+ '.sneakoscope/state', '.sneakoscope/missions', '.sneakoscope/db', '.sneakoscope/bus', '.sneakoscope/hproof', '.sneakoscope/db', '.sneakoscope/memory/q0_raw', '.sneakoscope/memory/q1_evidence', '.sneakoscope/memory/q2_facts', '.sneakoscope/memory/q3_tags', '.sneakoscope/memory/q4_bits', '.sneakoscope/gx/cartridges', '.sneakoscope/model/fingerprints', '.sneakoscope/genome/candidates', '.sneakoscope/trajectories/raw', '.sneakoscope/locks', '.sneakoscope/tmp', '.sneakoscope/arenas', '.sneakoscope/reports', '.codex', '.codex/skills', '.agents/skills'
72
85
  ];
73
86
  for (const d of dirs) await ensureDir(path.join(root, d));
74
87
 
@@ -78,13 +91,27 @@ export async function initProject(root, opts = {}) {
78
91
  initialized_at: nowIso(),
79
92
  no_external_tools: true,
80
93
  codex_required: true,
94
+ codex_app_supported: true,
81
95
  native_runtime_dependencies: 0,
82
96
  installation: {
83
97
  scope: installScope,
84
98
  default_scope: 'global',
85
- global_command: 'sks',
99
+ hook_command_prefix: hookCommandPrefix,
100
+ global_command: opts.globalCommand || 'sks',
86
101
  project_command: 'node ./node_modules/sneakoscope/bin/sks.mjs'
87
102
  },
103
+ codex_app: {
104
+ config: '.codex/config.toml',
105
+ hooks: '.codex/hooks.json',
106
+ skills: '.codex/skills',
107
+ quick_reference: '.codex/SNEAKOSCOPE.md',
108
+ agents_rules: 'AGENTS.md'
109
+ },
110
+ prompt_pipeline: {
111
+ default_enabled: true,
112
+ dollar_commands: ['$DF', '$SKS', '$Ralph', '$Research', '$DB', '$GX', '$Help'],
113
+ fast_design_command: '$DF'
114
+ },
88
115
  database_safety: 'destructive_db_operations_denied_always',
89
116
  gx_renderer: 'deterministic_svg_html'
90
117
  });
@@ -98,20 +125,20 @@ export async function initProject(root, opts = {}) {
98
125
 
99
126
  const policyPath = path.join(sine, 'policy.json');
100
127
  if (!(await exists(policyPath)) || opts.force) {
101
- await writeJsonAtomic(policyPath, defaultPolicy(installScope));
128
+ await writeJsonAtomic(policyPath, defaultPolicy(installScope, hookCommandPrefix));
102
129
  created.push('.sneakoscope/policy.json');
103
130
  } else {
104
131
  const policy = await readJson(policyPath, {});
105
132
  await writeJsonAtomic(policyPath, {
106
133
  ...policy,
107
- installation: installPolicy(installScope)
134
+ installation: installPolicy(installScope, hookCommandPrefix)
108
135
  });
109
136
  }
110
137
 
111
- function defaultPolicy(scope) {
138
+ function defaultPolicy(scope, commandPrefix) {
112
139
  return {
113
140
  schema_version: 1,
114
- installation: installPolicy(scope),
141
+ installation: installPolicy(scope, commandPrefix),
115
142
  retention: DEFAULT_RETENTION_POLICY,
116
143
  database_safety: DEFAULT_DB_SAFETY_POLICY,
117
144
  performance: {
@@ -140,17 +167,31 @@ export async function initProject(root, opts = {}) {
140
167
  renderer: 'deterministic_svg_html',
141
168
  source_of_truth: 'vgraph.json',
142
169
  external_image_generation: false
170
+ },
171
+ codex_app: {
172
+ supported: true,
173
+ config: '.codex/config.toml',
174
+ hooks: '.codex/hooks.json',
175
+ skills: '.codex/skills',
176
+ quick_reference: '.codex/SNEAKOSCOPE.md',
177
+ agents_rules: 'AGENTS.md'
178
+ },
179
+ prompt_pipeline: {
180
+ default_enabled: true,
181
+ route_without_command: true,
182
+ dollar_commands: ['$DF', '$SKS', '$Ralph', '$Research', '$DB', '$GX', '$Help'],
183
+ fast_design_command: '$DF'
143
184
  }
144
185
  };
145
186
  }
146
187
 
147
- function installPolicy(scope) {
188
+ function installPolicy(scope, commandPrefix) {
148
189
  return {
149
190
  scope,
150
191
  default_scope: 'global',
151
- hook_command_prefix: sksCommandPrefix(scope),
192
+ hook_command_prefix: commandPrefix,
152
193
  global_install: 'npm i -g sneakoscope',
153
- project_install: 'npm i -D sneakoscope && npx sks init --install-scope project'
194
+ project_install: 'npm i -D sneakoscope && npx sks setup --install-scope project'
154
195
  };
155
196
  }
156
197
 
@@ -166,24 +207,106 @@ export async function initProject(root, opts = {}) {
166
207
  await writeTextAtomic(path.join(root, '.codex', 'config.toml'), `[features]\ncodex_hooks = true\n\n[profiles.sks-ralph]\nmodel = "gpt-5.5"\napproval_policy = "never"\nsandbox_mode = "workspace-write"\nmodel_reasoning_effort = "high"\n\n[profiles.sks-research]\nmodel = "gpt-5.5"\napproval_policy = "never"\nsandbox_mode = "workspace-write"\nmodel_reasoning_effort = "xhigh"\n\n[profiles.sks-default]\nmodel = "gpt-5.5"\napproval_policy = "on-request"\nsandbox_mode = "workspace-write"\nmodel_reasoning_effort = "medium"\n`);
167
208
  created.push('.codex/config.toml');
168
209
 
210
+ await writeTextAtomic(path.join(root, '.codex', 'SNEAKOSCOPE.md'), codexAppQuickReference(installScope, hookCommandPrefix));
211
+ created.push('.codex/SNEAKOSCOPE.md');
212
+
169
213
  await writeJsonAtomic(path.join(root, '.codex', 'hooks.json'), {
170
214
  hooks: {
171
- UserPromptSubmit: [{ hooks: [{ type: 'command', command: sksHookCommand(installScope, 'user-prompt-submit') }] }],
172
- PreToolUse: [{ matcher: '*', hooks: [{ type: 'command', command: sksHookCommand(installScope, 'pre-tool') }] }],
173
- PostToolUse: [{ matcher: '*', hooks: [{ type: 'command', command: sksHookCommand(installScope, 'post-tool') }] }],
174
- PermissionRequest: [{ matcher: '*', hooks: [{ type: 'command', command: sksHookCommand(installScope, 'permission-request') }] }],
175
- Stop: [{ hooks: [{ type: 'command', command: sksHookCommand(installScope, 'stop') }] }]
215
+ UserPromptSubmit: [{ hooks: [{ type: 'command', command: sksHookCommand(hookCommandPrefix, 'user-prompt-submit') }] }],
216
+ PreToolUse: [{ matcher: '*', hooks: [{ type: 'command', command: sksHookCommand(hookCommandPrefix, 'pre-tool') }] }],
217
+ PostToolUse: [{ matcher: '*', hooks: [{ type: 'command', command: sksHookCommand(hookCommandPrefix, 'post-tool') }] }],
218
+ PermissionRequest: [{ matcher: '*', hooks: [{ type: 'command', command: sksHookCommand(hookCommandPrefix, 'permission-request') }] }],
219
+ Stop: [{ hooks: [{ type: 'command', command: sksHookCommand(hookCommandPrefix, 'stop') }] }]
176
220
  }
177
221
  });
178
222
  created.push(`.codex/hooks.json (${installScope})`);
179
223
 
180
224
  await installSkills(root);
225
+ created.push('.codex/skills/*');
181
226
  created.push('.agents/skills/*');
182
227
  return { created };
183
228
  }
184
229
 
230
+ function codexAppQuickReference(scope, commandPrefix) {
231
+ return `# Sneakoscope Codex for Codex App
232
+
233
+ This project has been initialized for both the SKS CLI and Codex App.
234
+
235
+ ## App Control Surface
236
+
237
+ - Rules: \`AGENTS.md\`
238
+ - Hooks: \`.codex/hooks.json\`
239
+ - Profiles: \`.codex/config.toml\`
240
+ - App skills: \`.codex/skills/\`
241
+ - Mission state: \`.sneakoscope/missions/\`
242
+ - Current state: \`.sneakoscope/state/current.json\`
243
+
244
+ ## Installed Command
245
+
246
+ \`\`\`bash
247
+ ${commandPrefix} <command>
248
+ \`\`\`
249
+
250
+ Install scope: \`${scope}\`
251
+
252
+ ## Discovery Commands
253
+
254
+ \`\`\`bash
255
+ ${commandPrefix} help
256
+ ${commandPrefix} commands
257
+ ${commandPrefix} usage ralph
258
+ ${commandPrefix} quickstart
259
+ ${commandPrefix} install-prompt
260
+ ${commandPrefix} codex-app
261
+ \`\`\`
262
+
263
+ ## Dollar Commands
264
+
265
+ - \`$DF\`: fast design/content fix. Use for color, copy, label, spacing, translation, or small UI edits.
266
+ - \`$SKS\`: general Sneakoscope workflow/help route.
267
+ - \`$Ralph\`: clarification-gated autonomous mission route.
268
+ - \`$Research\`: frontier research route.
269
+ - \`$DB\`: database/Supabase safety route.
270
+ - \`$GX\`: deterministic visual context route.
271
+ - \`$Help\`: explain installed commands and workflows.
272
+
273
+ The prompt optimization pipeline also runs without a dollar command and infers the lightest route automatically.
274
+
275
+ ## Common App Prompts
276
+
277
+ - "Use Sneakoscope Ralph mode to prepare this task."
278
+ - "$DF change the button text to English."
279
+ - "Run the latest Ralph mission with the sealed decision contract."
280
+ - "Use SKS DB safety before touching database or Supabase files."
281
+ - "Use SKS research mode for this investigation."
282
+
283
+ ## CLI Bridge
284
+
285
+ Codex App can call the same project-local control surface through terminal commands:
286
+
287
+ \`\`\`bash
288
+ ${commandPrefix} setup
289
+ ${commandPrefix} doctor
290
+ ${commandPrefix} ralph prepare "task"
291
+ ${commandPrefix} ralph status latest
292
+ ${commandPrefix} research prepare "topic"
293
+ ${commandPrefix} db scan --migrations
294
+ \`\`\`
295
+
296
+ The hooks file routes Codex App tool events through SKS guards for no-question mode, DB safety, permission requests, and done-gate checks.
297
+ `;
298
+ }
299
+
185
300
  async function installSkills(root) {
186
301
  const skills = {
302
+ 'DF': `---\nname: DF\ndescription: Fast design/content fix mode for $DF requests and inferred simple edits such as text color, copy, labels, spacing, or translation.\n---\n\nYou are running SKS DF mode.\n\nPurpose:\n- Quickly convert a small design/content request into the exact implementation change.\n- Use for requests like 글자 색 바꿔줘, 내용을 영어로 바꿔줘, button label 수정, spacing 조정, copy replacement, simple style tweaks.\n\nRules:\n- Do not start Ralph, Research, eval, or broad redesign unless the user explicitly asks.\n- Do not ask for more requirements when the target can be inferred from local context.\n- Inspect only the files needed to locate the target.\n- Make the smallest scoped edit that satisfies the request.\n- Preserve the existing design system and component patterns.\n- Run only cheap verification when useful, such as syntax check, focused test, or local render check for visual risk.\n- Final response should be short: what changed and any verification.\n`,
303
+ 'SKS': `---\nname: SKS\ndescription: General Sneakoscope Codex command route for $SKS usage, setup, status, and workflow help.\n---\n\nUse the local SKS control surface. Prefer these discovery commands when the user asks what is available: sks commands, sks usage <topic>, sks quickstart, sks codex-app, sks install-prompt. If implementation is requested, route to the lightest matching SKS path.\n`,
304
+ 'Ralph': `---\nname: Ralph\ndescription: Dollar-command route for SKS Ralph mandatory clarification and no-question mission workflows.\n---\n\nUse when the user invokes $Ralph or requests a clarification-gated autonomous implementation mission. Prepare with sks ralph prepare, answer/seal required slots when answers are provided, then run only after decision-contract.json exists.\n`,
305
+ 'Research': `---\nname: Research\ndescription: Dollar-command route for SKS Research frontier discovery workflows.\n---\n\nUse when the user invokes $Research or asks for research, hypotheses, new mechanisms, falsification, or testable predictions. Prefer sks research prepare and sks research run. Do not use for ordinary code edits.\n`,
306
+ 'DB': `---\nname: DB\ndescription: Dollar-command route for database and Supabase safety checks.\n---\n\nUse when the user invokes $DB or the task touches SQL, Supabase, Postgres, migrations, Prisma, Drizzle, Knex, MCP database tools, or production data. Run or follow sks db policy, sks db scan, sks db classify, and sks db check. Destructive database operations remain forbidden.\n`,
307
+ 'GX': `---\nname: GX\ndescription: Dollar-command route for deterministic GX visual context cartridges.\n---\n\nUse when the user invokes $GX or asks for architecture/context visualization through SKS. Prefer sks gx init, render, validate, drift, and snapshot. vgraph.json remains the source of truth.\n`,
308
+ 'Help': `---\nname: Help\ndescription: Dollar-command route for explaining installed SKS commands and workflows.\n---\n\nUse when the user invokes $Help or asks what commands exist. Prefer concise output from sks commands, sks usage <topic>, sks quickstart, sks aliases, and sks codex-app.\n`,
309
+ 'prompt-pipeline': `---\nname: prompt-pipeline\ndescription: Default SKS prompt optimization pipeline that runs even without an explicit command.\n---\n\nFor every user request, silently extract intent, target surface, constraints, acceptance criteria, risk level, and the smallest safe route. Infer $DF for simple design/content edits. Use Ralph only for work that needs clarification gates, Research only for discovery work, DB only for database-risk work, GX only for visual context artifacts, and eval only when performance or context-quality claims need evidence.\n`,
187
310
  'ralph-supervisor': `---\nname: ralph-supervisor\ndescription: Run the Ralph no-question loop after a decision contract is sealed.\n---\n\nYou are the Ralph Supervisor.\n\nRules:\n- Never ask the user during Ralph run.\n- Use decision-contract.json and the decision ladder.\n- Continue until done-gate.json passes or safe scope is completed with explicit limitation.\n- Keep outputs bounded. Write raw logs to files and summarize only tails.\n- Database destructive operations are never allowed.\n- Write progress to .sneakoscope mission files.\n`,
188
311
  'ralph-resolver': `---\nname: ralph-resolver\ndescription: Resolve newly discovered ambiguity during Ralph using the sealed decision ladder, without asking the user.\n---\n\nResolve ambiguity in this order: seed contract, explicit answers, approved defaults, AGENTS.md, current code/tests, smallest reversible change, defer optional scope. Never ask the user. If database risk is involved, prefer read-only, no-op, local-only migration file, or safe limitation; never run destructive SQL.\n`,
189
312
  'hproof-claim-ledger': `---\nname: hproof-claim-ledger\ndescription: Extract atomic claims and classify support status.\n---\n\nEvery factual statement must become an atomic claim. Unsupported critical claims cannot be used for implementation or final answer. Database claims require DB safety evidence.\n`,
@@ -198,8 +321,10 @@ async function installSkills(root) {
198
321
  'design-artifact-expert': `---\nname: design-artifact-expert\ndescription: Create or revise high-fidelity HTML, UI, prototype, deck-like, or visual design artifacts using project design context, variations, and rendered verification.\n---\n\nUse when the user asks for design, UI, prototype, HTML artifact, landing page, deck-like visual work, interaction design, or visual refinement.\n\nWorkflow:\n1. Understand the artifact, audience, constraints, fidelity, variants, and existing brand/design system.\n2. Inspect local code, assets, screenshots, or design-system docs before inventing visuals. If context exists, follow its visual vocabulary.\n3. Build the actual usable screen or artifact first; avoid empty landing-page framing unless the task is explicitly marketing.\n4. Use descriptive HTML filenames. Keep large artifacts split into small support files when needed.\n5. For screens/slides, add data-screen-label attributes for comment context. Slide labels are 1-indexed.\n6. Preserve state for decks, videos, or multi-step prototypes with localStorage when refresh continuity matters.\n7. Expose a small Tweaks surface for useful variants such as layout, density, color, copy, or interaction options.\n8. Verify the artifact renders cleanly in a browser or preview. For design tasks, set done-gate.json design_verification_required/present fields and cite evidence.\n\nQuality bar:\n- Root design decisions in available assets and components.\n- Use restrained, domain-appropriate layout and typography.\n- Avoid text overlap, unreadable controls, decorative clutter, one-note palettes, and placeholder-only deliverables.\n- Prefer icons and familiar controls for tool actions, and make repeated UI dimensions stable.\n`
199
322
  };
200
323
  for (const [name, content] of Object.entries(skills)) {
201
- const dir = path.join(root, '.agents', 'skills', name);
202
- await ensureDir(dir);
203
- await writeTextAtomic(path.join(dir, 'SKILL.md'), `${content.trim()}\n`);
324
+ for (const base of ['.codex/skills', '.agents/skills']) {
325
+ const dir = path.join(root, base, name);
326
+ await ensureDir(dir);
327
+ await writeTextAtomic(path.join(dir, 'SKILL.md'), `${content.trim()}\n`);
328
+ }
204
329
  }
205
330
  }