codetrap 0.1.8 → 0.1.9

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
@@ -64,50 +64,21 @@ npm install -g codetrap
64
64
 
65
65
  # Initialize pitfall memory in the target project
66
66
  cd /path/to/project
67
- codetrap init
67
+ codetrap setup codex
68
68
  codetrap doctor
69
69
  ```
70
70
 
71
- Add the packaged agent guidance to `AGENTS.md` for Codex, or to `CLAUDE.md` for Claude Code:
72
-
73
- ```bash
74
- cat "$(npm root -g)/codetrap/plugins/codetrap-agent/templates/AGENTS.codetrap.md" >> AGENTS.md
75
- # or:
76
- cat "$(npm root -g)/codetrap/plugins/codetrap-agent/templates/AGENTS.codetrap.md" >> CLAUDE.md
77
- ```
78
-
79
- Then have the agent run this before non-trivial edits:
80
-
81
- ```bash
82
- codetrap search "<task keywords>" --mode hybrid --json
83
- ```
71
+ `codetrap setup codex` installs the bundled Codex skills into `~/.codex/skills`, initializes `.codetrap/` when needed, and writes `AGENTS.md`. It does not configure MCP by default.
84
72
 
85
- Review the top 3 returned action cards, or all returned cards if fewer than 3, before deciding whether any trap applies. Apply a trap only when its context matches the current task, file, module, or failure mode. Severity alone is not enough to apply a trap. Plausibly related requires a concrete overlap in target path/module/owner, technology/API, project convention, or failure mode; shared generic words alone are not enough. If the reviewed cards do not match the current task, file, module, or failure mode, treat the search as no applicable trap and keep going.
86
-
87
- After a user correction, repeated test failure, or review finding, have the agent draft a candidate instead of writing confirmed memory:
73
+ To also configure Codex MCP, opt in explicitly:
88
74
 
89
75
  ```bash
90
- cat <<'EOF' | codetrap session capture --trap-markdown - --kind review --json
91
- Title: <durable pitfall>
92
- Context: <when it triggers>
93
- Mistake: <what the agent did wrong>
94
- Fix: <what to do instead>
95
- EOF
76
+ codetrap setup codex --mcp
96
77
  ```
97
78
 
98
- Review pending candidates with `codetrap session status`, `codetrap session list`, `codetrap doctor`, or `codetrap web`; accepting a candidate remains an explicit human decision.
79
+ The packaged template is the source of truth for exact agent behavior. It tells agents to run CLI JSON checks before non-trivial edits, inspect only relevant action cards, keep post-flight lessons in the session candidate inbox, and require explicit human approval before accepting a candidate into `traps.db`.
99
80
 
100
- Use the returned `candidate_id` and `session_id` to inspect and resolve the candidate:
101
-
102
- ```bash
103
- codetrap session candidate <candidate-id> --session <session-id> --json
104
-
105
- # Only after explicit human approval:
106
- codetrap session accept <candidate-id> --session <session-id>
107
-
108
- # Or reject instead:
109
- codetrap session reject <candidate-id> --session <session-id> --reason "<reason>"
110
- ```
81
+ For a quick manual check, agents can run `codetrap search "<task keywords>" --mode hybrid --json` from the project cwd.
111
82
 
112
83
  ## Features
113
84
 
@@ -227,6 +198,7 @@ codetrap/
227
198
  | `import` | Import traps from JSON (--json) |
228
199
  | `stats` | Show database statistics (--json includes embedding health) |
229
200
  | `doctor` | Diagnose cwd, scope, database paths, trap counts, and embedding health (--json) |
201
+ | `setup codex` | Install Codex skills and project guidance; MCP is opt-in with `--mcp` |
230
202
  | `repair-scope` | Move legacy mis-scoped project traps into the current project (dry-run by default, `--apply` to mutate, `--json`) |
231
203
  | `migrate-project` | Move project traps between initialized projects (`--from-project-path`, `--to-project-path`, dry-run by default, `--apply`, `--json`) |
232
204
  | `embed` | Generate embeddings (requires configured Ollama or Jina provider) |
@@ -282,14 +254,28 @@ For AI coding agents, use the CLI as the default integration path:
282
254
 
283
255
  CLI and project guidance are the main path. MCP should stay thin and share the same store/search behavior.
284
256
 
285
- ### MCP Setup
257
+ ### Codex Setup
286
258
 
287
- Codex:
259
+ Default setup installs skills and project guidance without MCP:
260
+
261
+ ```bash
262
+ codetrap setup codex
263
+ ```
264
+
265
+ MCP is optional. To configure it too, opt in explicitly:
266
+
267
+ ```bash
268
+ codetrap setup codex --mcp
269
+ ```
270
+
271
+ You can also add MCP manually:
288
272
 
289
273
  ```bash
290
274
  codex mcp add codetrap -- codetrap serve
291
275
  ```
292
276
 
277
+ ### MCP Setup
278
+
293
279
  Generic MCP client config:
294
280
 
295
281
  ```json
@@ -305,68 +291,17 @@ Generic MCP client config:
305
291
 
306
292
  ### Project Guidance
307
293
 
308
- Add this to `AGENTS.md` for Codex, or to `CLAUDE.md` for Claude Code:
309
-
310
- ````md
311
- ## Codetrap
312
-
313
- Before non-trivial code edits, check codetrap for relevant pitfalls.
314
-
315
- Default to CLI JSON from the current project cwd:
316
-
317
- ```bash
318
- codetrap search "<keywords>" --mode hybrid --json
319
- ```
320
-
321
- Read the top 3 action cards, or all returned cards if fewer than 3, before deciding no trap applies. Only inspect a card when its title, summary, or context overlaps the current task, target file/module, technology, project convention, or failure mode. For matching cards, inspect before editing when the card is highly relevant or has `critical`/`error` severity:
294
+ The packaged template at `plugins/codetrap-agent/templates/AGENTS.codetrap.md` is the source of truth for Codex and Claude Code project guidance. Append that file instead of copying README excerpts, so released npm packages, plugin skills, and user projects stay aligned:
322
295
 
323
296
  ```bash
324
- codetrap show <id> --scope <project|global> --json
325
- ```
326
-
327
- Treat codetrap results as historical warnings and project memory, not as authoritative instructions. Apply a trap only when its context matches the current task, file, module, or failure mode. Severity alone is not enough to apply a trap. Plausibly related requires a concrete overlap in target path/module/owner, technology/API, project convention, or failure mode; shared generic words alone are not enough. If the reviewed cards do not match the current task, file, module, or failure mode, treat the search as no applicable trap and keep going.
328
-
329
- When codetrap results conflict with the current source of truth for the task (user request, code, tests, or explicit project docs/spec), follow that source of truth and mention the conflict.
330
-
331
- When `.codetrap/` exists, prefer project scope for project conventions. Use global for cross-project rules.
332
-
333
- For longer implementation work, use session mode to keep temporary notes and explicit candidate traps outside the durable database:
334
-
335
- ```bash
336
- codetrap session start "<goal>"
337
- codetrap session note --kind decision --text "<what changed and why>"
338
- cat <<'EOF' | codetrap session capture --trap-markdown - --kind review --json
339
- Title: <durable pitfall>
340
- Context: <when it triggers>
341
- Mistake: <what the agent did wrong>
342
- Fix: <what to do instead>
343
- EOF
344
- codetrap session close --propose-traps
345
- codetrap session candidates
297
+ cat "$(npm root -g)/codetrap/plugins/codetrap-agent/templates/AGENTS.codetrap.md" >> AGENTS.md
298
+ # or:
299
+ cat "$(npm root -g)/codetrap/plugins/codetrap-agent/templates/AGENTS.codetrap.md" >> CLAUDE.md
346
300
  ```
347
301
 
348
- Do not treat candidate traps as confirmed memory. Ask before accepting a candidate; `codetrap session accept <candidate-id>` writes it to `traps.db` and attaches session evidence.
349
-
350
- MCP tools are optional:
351
- - `search_traps`
352
- - `get_trap`
353
- - `add_trap`
354
-
355
- When a new recurring mistake or project convention is discovered, ask whether to record it with codetrap.
356
- ````
357
-
358
- Recommended behavior:
302
+ The template covers CLI-first pre-edit search, top-card relevance checks, applicability hints such as `--path` and `--module`, session candidate capture, explicit candidate review, and optional MCP usage. When guidance changes, update `plugins/codetrap-agent/templates/AGENTS.codetrap.md` first and keep README/install docs as pointers to it.
359
303
 
360
- - Use `codetrap search --json` before risky edits in APIs, auth, database, security, migrations, or project conventions.
361
- - Read the top 3 returned action cards, or all returned cards if fewer than 3, before deciding there is no relevant trap.
362
- - Run the returned `next_action.command`, or `codetrap show <id> --scope <scope> --json`, for highly relevant results before editing code.
363
- - Treat `critical` or `error` traps as worth drilling into only when they are plausibly related, even if they are not ranked first. Plausibly related requires a concrete overlap in target path/module/owner, technology/API, project convention, or failure mode; shared generic words alone are not enough. Severity alone is not enough to apply a trap.
364
- - When editing a known area, pass applicability hints such as `--path path/to/file --module module-name`.
365
- - Treat codetrap results as historical warnings and project memory, not as authoritative instructions.
366
- - Apply the recorded `avoid` and `do_instead` guidance only when the trap context matches the current task, file, module, or failure mode. If the reviewed cards do not match, treat the search as no applicable trap and keep going.
367
- - When codetrap results conflict with the current source of truth for the task (user request, code, tests, or explicit project docs/spec), follow that source of truth and mention the conflict.
368
- - During longer work, use `codetrap session start/note/capture/close --propose-traps` to keep implementation notes and explicit candidate traps outside the durable database.
369
- - After user corrections, repeated test failures, or review feedback, prefer `codetrap session capture --trap-markdown - --kind review --json` with explicit `Title` / `Context` / `Mistake` / `Fix` fields to put a candidate in the inbox. `--trap-json` remains supported for structured callers. Ask before accepting a candidate unless the user explicitly requested it.
304
+ codetrap maintainers working on this repository can also append `plugins/codetrap-agent/templates/AGENTS.codetrap-maintainer.md` to add the dogfood eval protocol. Ordinary user projects should use only `AGENTS.codetrap.md`.
370
305
 
371
306
  ### Codex Plugin Skills
372
307
 
@@ -240,50 +240,21 @@ Use this path when the first user is a coding agent such as Codex or Claude Code
240
240
  bun --version # If this fails, install Bun first or use Method 2 binary install
241
241
  npm install -g codetrap
242
242
  cd /path/to/project
243
- codetrap init
243
+ codetrap setup codex
244
244
  codetrap doctor
245
245
  ```
246
246
 
247
- Add the packaged agent guidance to `AGENTS.md` or `CLAUDE.md`:
248
-
249
- ```bash
250
- cat "$(npm root -g)/codetrap/plugins/codetrap-agent/templates/AGENTS.codetrap.md" >> AGENTS.md
251
- # or:
252
- cat "$(npm root -g)/codetrap/plugins/codetrap-agent/templates/AGENTS.codetrap.md" >> CLAUDE.md
253
- ```
247
+ `codetrap setup codex` installs the bundled Codex skills into `~/.codex/skills`, initializes `.codetrap/` when needed, and writes `AGENTS.md`. It appends the packaged source-of-truth template at `plugins/codetrap-agent/templates/AGENTS.codetrap.md`. It does not configure MCP by default.
254
248
 
255
- Then have the agent run a pre-edit check from the project cwd:
249
+ To also configure Codex MCP, opt in explicitly:
256
250
 
257
251
  ```bash
258
- codetrap search "<task keywords>" --mode hybrid --json
252
+ codetrap setup codex --mcp
259
253
  ```
260
254
 
261
- Review the top 3 returned action cards, or all returned cards if fewer than 3, before deciding whether any trap applies. Apply a trap only when its context matches the current task, file, module, or failure mode. Severity alone is not enough to apply a trap. Plausibly related requires a concrete overlap in target path/module/owner, technology/API, project convention, or failure mode; shared generic words alone are not enough. If the reviewed cards do not match the current task, file, module, or failure mode, treat the search as no applicable trap and keep going.
262
-
263
- After user corrections, repeated test failures, or review feedback, have the agent write a candidate into the review inbox:
264
-
265
- ```bash
266
- cat <<'EOF' | codetrap session capture --trap-markdown - --kind review --json
267
- Title: <durable pitfall>
268
- Context: <when it triggers>
269
- Mistake: <what the agent did wrong>
270
- Fix: <what to do instead>
271
- EOF
272
- ```
273
-
274
- Use `codetrap session status`, `codetrap session list`, `codetrap doctor`, or `codetrap web` to review pending candidates. Do not accept candidates automatically.
275
-
276
- Use the returned `candidate_id` and `session_id` to inspect and resolve the candidate:
277
-
278
- ```bash
279
- codetrap session candidate <candidate-id> --session <session-id> --json
280
-
281
- # Only after explicit human approval:
282
- codetrap session accept <candidate-id> --session <session-id>
255
+ The packaged template is the source of truth for exact agent behavior. It tells agents to run CLI JSON checks before non-trivial edits, inspect only relevant action cards, keep post-flight lessons in the session candidate inbox, and require explicit human approval before accepting a candidate into `traps.db`.
283
256
 
284
- # Or reject instead:
285
- codetrap session reject <candidate-id> --session <session-id> --reason "<reason>"
286
- ```
257
+ For a quick manual check, agents can run `codetrap search "<task keywords>" --mode hybrid --json` from the project cwd.
287
258
 
288
259
  ## Optional: Local Ollama Embeddings
289
260
 
@@ -342,79 +313,22 @@ If no embedding provider is configured:
342
313
 
343
314
  ## Optional: Codex MCP
344
315
 
345
- If the `codetrap` command is on your `PATH`, add it to Codex as an MCP server:
316
+ MCP is optional. `codetrap setup codex` does not configure MCP unless you pass `--mcp`:
346
317
 
347
318
  ```bash
348
- codex mcp add codetrap -- codetrap serve
319
+ codetrap setup codex --mcp
349
320
  ```
350
321
 
351
- If your MCP client does not inherit your shell `PATH`, use the absolute path:
322
+ You can also add MCP manually if the `codetrap` command is on your `PATH`:
352
323
 
353
324
  ```bash
354
- codex mcp add codetrap -- "$(bun pm bin -g)/codetrap" serve
355
- ```
356
-
357
- Agents can also use the CLI directly from `AGENTS.md`:
358
-
359
- ````md
360
- Before non-trivial code edits, check codetrap from the current project cwd:
361
-
362
- codetrap search "<keywords>" --mode hybrid --json
363
-
364
- Review the top 3 action cards, or all returned cards if fewer than 3, before deciding no trap applies. Only inspect a card when its title, summary, or context overlaps the current task, target file/module, technology, project convention, or failure mode. For matching critical/error results, inspect before editing:
365
-
366
- codetrap show <id> --scope <project|global> --json
367
-
368
- Apply a trap only when its context matches the current task, file, module, or failure mode. Severity alone is not enough to apply a trap. Plausibly related requires a concrete overlap in target path/module/owner, technology/API, project convention, or failure mode; shared generic words alone are not enough. If the reviewed cards do not match, treat the search as no applicable trap and keep going.
369
-
370
- When editing a known area, pass applicability hints:
371
-
372
- codetrap search "<keywords>" --path path/to/file --module module-name --json
373
-
374
- To capture a post-flight lesson from agent work:
375
-
376
- ```bash
377
- cat <<'EOF' | codetrap session capture --trap-markdown - --kind review --json
378
- Title: <durable pitfall>
379
- Context: <when it triggers>
380
- Mistake: <what the agent did wrong>
381
- Fix: <what to do instead>
382
- EOF
383
- ```
384
-
385
- `--trap-json` remains available for callers that already have a structured object:
386
-
387
- ```bash
388
- codetrap session capture --trap-json '{...}' --kind review --json
389
- ```
390
-
391
- For longer implementation work, keep temporary notes and explicit candidate traps in session files first:
392
-
393
- ```bash
394
- codetrap session start "<goal>"
395
- codetrap session note --kind decision --text "<what changed and why>"
396
- cat <<'EOF' | codetrap session capture --trap-markdown - --kind review --json
397
- Title: <durable pitfall>
398
- Context: <when it triggers>
399
- Mistake: <what the agent did wrong>
400
- Fix: <what to do instead>
401
- EOF
402
- codetrap session close --propose-traps
403
- codetrap session candidates
325
+ codex mcp add codetrap -- codetrap serve
404
326
  ```
405
327
 
406
- Pending candidates are visible from `codetrap session status`, `codetrap session list`, `codetrap doctor`, and `codetrap web`.
407
-
408
- Only accepted candidates are written to `traps.db`:
328
+ If your MCP client does not inherit your shell `PATH`, use the absolute path:
409
329
 
410
330
  ```bash
411
- # Only after explicit human approval:
412
- codetrap session accept <candidate-id>
331
+ codex mcp add codetrap -- "$(bun pm bin -g)/codetrap" serve
413
332
  ```
414
333
 
415
- `codetrap session accept --edit-json ...` applies the edit before conflict detection. If a possible active-trap conflict is found, the candidate remains proposed and records conflict diagnostics until you choose `--accept-anyway`, `--supersedes <trap-id>`, or reject it.
416
-
417
- To save a lesson from an external article or reference, let the agent read the source and attach the URL as evidence after the user confirms the trap:
418
-
419
- codetrap add_trap_evidence <id> --scope global --source_type article --source_ref "https://example.com/post" --output-json
420
- ````
334
+ Agents can also use the CLI directly when the project guidance tells them when to call it. `codetrap setup codex` installs that guidance in `AGENTS.md`.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "codetrap",
3
- "version": "0.1.8",
3
+ "version": "0.1.9",
4
4
  "description": "Capture and retrieve coding pitfalls so AI doesn't repeat mistakes",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "codetrap-agent",
3
- "version": "0.1.2",
3
+ "version": "0.1.9",
4
4
  "description": "CLI-first codetrap integration bundle for coding agents.",
5
5
  "author": {
6
6
  "name": "codetrap maintainers",
@@ -0,0 +1,15 @@
1
+ ## Codetrap Dogfood Eval
2
+
3
+ Use this add-on only for codetrap maintainers working on codetrap itself. For ordinary external projects, use `AGENTS.codetrap.md` without this dogfood section.
4
+
5
+ After each pre-edit codetrap search, record whether the search was:
6
+ - useful_hit
7
+ - miss
8
+ - noisy_hit
9
+ - no_relevant_trap
10
+
11
+ Record the observation in `dogfood-log.md` with the task, query, mode, top results, judgment, whether the result changed the next action, and the promotion lane.
12
+
13
+ When a real query should reliably find an existing trap, save it as a live eval case with query, mode, scope, and gold target.
14
+
15
+ Do not promote every observation. Only promote representative cases that protect search quality.
@@ -38,18 +38,3 @@ Use `--trap-json` only when the caller already has a structured object.
38
38
  Review the candidate with `codetrap session candidate <candidate-id> --session <session-id> --json`, then accept, edit, reject, or supersede it explicitly.
39
39
 
40
40
  Use `codetrap session status`, `codetrap session list`, `codetrap doctor`, or `codetrap web` to find pending candidates that still need review.
41
-
42
-
43
- ## Codetrap Dogfood Eval
44
-
45
- After each pre-edit codetrap search, record whether the search was:
46
- - useful_hit
47
- - miss
48
- - noisy_hit
49
- - no_relevant_trap
50
-
51
- Record the observation in `dogfood-log.md` with the task, query, mode, top results, judgment, whether the result changed the next action, and the promotion lane.
52
-
53
- When a real query should reliably find an existing trap, save it as a live eval case with query, mode, scope, and gold target.
54
-
55
- Do not promote every observation. Only promote representative cases that protect search quality.
@@ -1,5 +1,8 @@
1
1
  #!/usr/bin/env bun
2
2
 
3
+ import { tmpdir } from "node:os";
4
+ import { join } from "node:path";
5
+
3
6
  const tag = process.argv[2] ?? process.env.RELEASE_TAG;
4
7
  const packageJson = await Bun.file("package.json").json() as { name?: string; version?: string };
5
8
  const published = await packageVersionExists(packageJson.name, packageJson.version);
@@ -10,6 +13,18 @@ const commands: { name: string; cmd: string[]; optional?: boolean }[] = [
10
13
  { name: "build", cmd: ["bun", "run", "build"] },
11
14
  { name: "build release assets", cmd: ["bun", "run", "build:release"] },
12
15
  { name: "smoke test release binary", cmd: [hostBinaryPath(), "--help"] },
16
+ {
17
+ name: "smoke test release binary Codex setup",
18
+ cmd: [
19
+ hostBinaryPath(),
20
+ "setup",
21
+ "codex",
22
+ "--dry-run",
23
+ "--json",
24
+ "--codex-home",
25
+ join(tmpdir(), "codetrap-release-preflight-codex-home"),
26
+ ],
27
+ },
13
28
  { name: "npm pack dry-run", cmd: ["npm", "pack", "--dry-run"] },
14
29
  ...(!published ? [{ name: "npm publish dry-run", cmd: ["npm", "publish", "--dry-run", "--access", "public"] }] : []),
15
30
  ];
@@ -17,6 +17,7 @@ import {
17
17
  type EmbeddingsUseResult,
18
18
  } from "../lib/embedding-management";
19
19
  import { searchDefaultsFromConfig } from "../lib/config";
20
+ import { formatCodexSetupText, runCodexSetup } from "../lib/codex-setup";
20
21
  import { SessionStore } from "../lib/session-store";
21
22
  import { SessionOperations, type SessionConflictResult } from "../lib/session-operations";
22
23
  import {
@@ -110,6 +111,8 @@ export async function executeCommand(strip: string[], store: TrapStore): Promise
110
111
  return cmdStats(args, operations);
111
112
  case "doctor":
112
113
  return cmdDoctor(args, store, operations);
114
+ case "setup":
115
+ return cmdSetup(args);
113
116
  case "repair-scope":
114
117
  return cmdScopeMigration("repair-scope", args, operations);
115
118
  case "migrate-project":
@@ -123,7 +126,7 @@ export async function executeCommand(strip: string[], store: TrapStore): Promise
123
126
  default:
124
127
  return errorResult([
125
128
  `Unknown command: ${sub}`,
126
- "Commands: init, add, search, list, show, edit, delete, add_trap_evidence, archive_trap, supersede_trap, export, import, stats, doctor, repair-scope, migrate-project, embed, embeddings, session",
129
+ "Commands: init, add, search, list, show, edit, delete, add_trap_evidence, archive_trap, supersede_trap, export, import, stats, doctor, setup, repair-scope, migrate-project, embed, embeddings, session",
127
130
  ].join("\n"));
128
131
  }
129
132
  }
@@ -370,6 +373,31 @@ async function cmdDoctor(args: string[], store: TrapStore, operations: TrapOpera
370
373
  : textResult(formatDoctorText(report));
371
374
  }
372
375
 
376
+ function cmdSetup(args: string[]): CommandResult {
377
+ const sub = args[0];
378
+ const rest = args.slice(1);
379
+ if (sub !== "codex") {
380
+ return errorResult("Usage: codetrap setup codex [--mcp] [--no-agents] [--agents-file AGENTS.md] [--codex-home <path>] [--dry-run] [--json]");
381
+ }
382
+ const { opts } = parseArgs(rest);
383
+ try {
384
+ const result = runCodexSetup({
385
+ cwd: process.cwd(),
386
+ codexHome: opts["codex-home"],
387
+ agentsFile: opts["agents-file"],
388
+ installMcp: opts.mcp !== undefined,
389
+ skipAgents: opts["no-agents"] !== undefined,
390
+ dryRun: opts["dry-run"] !== undefined,
391
+ });
392
+ if (opts.json !== undefined) return jsonResult(result, result.success ? 0 : 1);
393
+ return result.success
394
+ ? textResult(formatCodexSetupText(result))
395
+ : errorResult(formatCodexSetupText(result));
396
+ } catch (error) {
397
+ return errorFrom(error);
398
+ }
399
+ }
400
+
373
401
  function cmdScopeMigration(
374
402
  command: ScopeMigrationCommand,
375
403
  args: string[],
package/src/index.ts CHANGED
@@ -61,6 +61,7 @@ function showHelp(): void {
61
61
  console.log(" import <file.json> Import traps from JSON");
62
62
  console.log(" stats Show statistics");
63
63
  console.log(" doctor Diagnose scope, database, and embedding health");
64
+ console.log(" setup codex Install Codex skills and project guidance (MCP opt-in)");
64
65
  console.log(" repair-scope Move mis-scoped project traps into the current project");
65
66
  console.log(" migrate-project Move project traps between initialized projects");
66
67
  console.log(" serve Start MCP server (for Claude Code)");
@@ -84,7 +85,11 @@ function showHelp(): void {
84
85
  console.log(" --output-json JSON output for add/edit when --json is used as input");
85
86
  console.log(" --from-project-path <path> Source project path for scope repair/migration");
86
87
  console.log(" --to-project-path <path> Destination project path for scope repair/migration");
87
- console.log(" --dry-run|--apply Preview or apply scope repair/migration");
88
+ console.log(" --dry-run|--apply Preview setup/scope migration, or apply scope migration");
89
+ console.log(" --mcp With setup codex, also run: codex mcp add codetrap -- codetrap serve");
90
+ console.log(" --codex-home <path> With setup codex, override CODEX_HOME/default ~/.codex");
91
+ console.log(" --agents-file <path> With setup codex, choose AGENTS.md target");
92
+ console.log(" --no-agents With setup codex, install skills without editing AGENTS.md");
88
93
  }
89
94
 
90
95
  function showWebHelp(): void {
@@ -0,0 +1,247 @@
1
+ import {
2
+ appendFileSync,
3
+ cpSync,
4
+ existsSync,
5
+ mkdirSync,
6
+ readdirSync,
7
+ readFileSync,
8
+ writeFileSync,
9
+ } from "node:fs";
10
+ import { homedir } from "node:os";
11
+ import { dirname, join, resolve } from "node:path";
12
+ import { fileURLToPath } from "node:url";
13
+ import { findProjectRoot } from "./scope";
14
+ import agentsTemplateAsset from "../../plugins/codetrap-agent/templates/AGENTS.codetrap.md" with { type: "text" };
15
+ import codetrapAddSkill from "../../plugins/codetrap-agent/skills/codetrap-add/SKILL.md" with { type: "text" };
16
+ import codetrapCaptureSkill from "../../plugins/codetrap-agent/skills/codetrap-capture/SKILL.md" with { type: "text" };
17
+ import codetrapCaptureExternalSkill from "../../plugins/codetrap-agent/skills/codetrap-capture-external/SKILL.md" with { type: "text" };
18
+ import codetrapCheckSkill from "../../plugins/codetrap-agent/skills/codetrap-check/SKILL.md" with { type: "text" };
19
+ import codetrapSearchSkill from "../../plugins/codetrap-agent/skills/codetrap-search/SKILL.md" with { type: "text" };
20
+
21
+ export type CodexSetupOptions = {
22
+ cwd: string;
23
+ codexHome?: string;
24
+ agentsFile?: string;
25
+ installMcp?: boolean;
26
+ skipAgents?: boolean;
27
+ dryRun?: boolean;
28
+ };
29
+
30
+ export type CodexSetupStatus =
31
+ | "already_present"
32
+ | "created"
33
+ | "appended"
34
+ | "installed"
35
+ | "updated"
36
+ | "unchanged"
37
+ | "skipped"
38
+ | "would_create"
39
+ | "would_append"
40
+ | "would_install"
41
+ | "would_update"
42
+ | "would_run"
43
+ | "failed";
44
+
45
+ export type CodexSetupResult = {
46
+ success: boolean;
47
+ project_root: string;
48
+ codex_home: string;
49
+ plugin_root: string;
50
+ dry_run: boolean;
51
+ project: {
52
+ codetrap_dir: string;
53
+ status: CodexSetupStatus;
54
+ };
55
+ skills: Array<{
56
+ name: string;
57
+ source: string;
58
+ destination: string;
59
+ status: CodexSetupStatus;
60
+ }>;
61
+ agents: {
62
+ path: string | null;
63
+ status: CodexSetupStatus;
64
+ };
65
+ mcp: {
66
+ requested: boolean;
67
+ command: string;
68
+ status: CodexSetupStatus;
69
+ exit_code?: number | null;
70
+ error?: string;
71
+ };
72
+ };
73
+
74
+ const AGENTS_TEMPLATE_PATH = "templates/AGENTS.codetrap.md";
75
+ const CODEX_MARKER = "codetrap search \"<keywords>\" --mode hybrid --json";
76
+ const MCP_COMMAND = ["codex", "mcp", "add", "codetrap", "--", "codetrap", "serve"];
77
+ const EMBEDDED_PLUGIN_ROOT = "embedded://plugins/codetrap-agent";
78
+ const EMBEDDED_SKILLS = [
79
+ { name: "codetrap-add", skill: codetrapAddSkill },
80
+ { name: "codetrap-capture", skill: codetrapCaptureSkill },
81
+ { name: "codetrap-capture-external", skill: codetrapCaptureExternalSkill },
82
+ { name: "codetrap-check", skill: codetrapCheckSkill },
83
+ { name: "codetrap-search", skill: codetrapSearchSkill },
84
+ ];
85
+
86
+ export function runCodexSetup(options: CodexSetupOptions): CodexSetupResult {
87
+ const cwd = resolve(options.cwd);
88
+ const projectRoot = findProjectRoot(cwd) ?? cwd;
89
+ const codexHome = resolveCodexHome(options.codexHome);
90
+ const pluginRoot = bundledPluginRoot();
91
+ const useEmbeddedAssets = !existsSync(pluginRoot);
92
+
93
+ const dryRun = options.dryRun === true;
94
+ const project = ensureProjectCodetrap(projectRoot, dryRun);
95
+ const skills = useEmbeddedAssets
96
+ ? installEmbeddedSkills(codexHome, dryRun)
97
+ : installSkills(pluginRoot, codexHome, dryRun);
98
+ const agents = options.skipAgents
99
+ ? { path: null, status: "skipped" as const }
100
+ : installAgentsTemplate(projectRoot, useEmbeddedAssets ? null : pluginRoot, options.agentsFile ?? "AGENTS.md", dryRun);
101
+ const mcp = setupMcp(options.installMcp === true, dryRun);
102
+ const success = mcp.status !== "failed";
103
+
104
+ return {
105
+ success,
106
+ project_root: projectRoot,
107
+ codex_home: codexHome,
108
+ plugin_root: useEmbeddedAssets ? EMBEDDED_PLUGIN_ROOT : pluginRoot,
109
+ dry_run: dryRun,
110
+ project,
111
+ skills,
112
+ agents,
113
+ mcp,
114
+ };
115
+ }
116
+
117
+ export function formatCodexSetupText(result: CodexSetupResult): string {
118
+ const installed = result.skills.filter((skill) =>
119
+ ["installed", "updated", "would_install", "would_update"].includes(skill.status)
120
+ ).length;
121
+ const unchanged = result.skills.filter((skill) => skill.status === "unchanged").length;
122
+ const lines = [
123
+ result.success ? "Codex setup complete." : "Codex setup completed with errors.",
124
+ `Project: ${result.project.status} (${result.project.codetrap_dir})`,
125
+ `Skills: ${installed} changed, ${unchanged} unchanged (${join(result.codex_home, "skills")})`,
126
+ `AGENTS: ${result.agents.status}${result.agents.path ? ` (${result.agents.path})` : ""}`,
127
+ ];
128
+ if (result.mcp.requested) {
129
+ lines.push(`MCP: ${result.mcp.status} (${result.mcp.command})`);
130
+ if (result.mcp.error) lines.push(`MCP error: ${result.mcp.error}`);
131
+ } else {
132
+ lines.push(`MCP: skipped; pass --mcp to run '${result.mcp.command}'.`);
133
+ }
134
+ if (result.dry_run) lines.unshift("Dry run; no files or Codex config were changed.");
135
+ return lines.join("\n");
136
+ }
137
+
138
+ function ensureProjectCodetrap(projectRoot: string, dryRun: boolean): CodexSetupResult["project"] {
139
+ const codetrapDir = join(projectRoot, ".codetrap");
140
+ if (existsSync(codetrapDir)) {
141
+ return { codetrap_dir: codetrapDir, status: "already_present" };
142
+ }
143
+ if (!dryRun) mkdirSync(codetrapDir, { recursive: true });
144
+ return { codetrap_dir: codetrapDir, status: dryRun ? "would_create" : "created" };
145
+ }
146
+
147
+ function installSkills(pluginRoot: string, codexHome: string, dryRun: boolean): CodexSetupResult["skills"] {
148
+ const sourceSkillsDir = join(pluginRoot, "skills");
149
+ const targetSkillsDir = join(codexHome, "skills");
150
+ if (!dryRun) mkdirSync(targetSkillsDir, { recursive: true });
151
+
152
+ return readdirSync(sourceSkillsDir, { withFileTypes: true })
153
+ .filter((entry) => entry.isDirectory())
154
+ .sort((left, right) => left.name.localeCompare(right.name))
155
+ .map((entry) => {
156
+ const source = join(sourceSkillsDir, entry.name);
157
+ const destination = join(targetSkillsDir, entry.name);
158
+ const sourceSkill = readFileSync(join(source, "SKILL.md"), "utf-8");
159
+ const destinationSkillPath = join(destination, "SKILL.md");
160
+ const exists = existsSync(destinationSkillPath);
161
+ const unchanged = exists && readFileSync(destinationSkillPath, "utf-8") === sourceSkill;
162
+ let status: CodexSetupStatus = unchanged ? "unchanged" : exists ? "updated" : "installed";
163
+ if (dryRun && status === "installed") status = "would_install";
164
+ if (dryRun && status === "updated") status = "would_update";
165
+ if (!dryRun && !unchanged) cpSync(source, destination, { recursive: true, force: true });
166
+ return { name: entry.name, source, destination, status };
167
+ });
168
+ }
169
+
170
+ function installEmbeddedSkills(codexHome: string, dryRun: boolean): CodexSetupResult["skills"] {
171
+ const targetSkillsDir = join(codexHome, "skills");
172
+ if (!dryRun) mkdirSync(targetSkillsDir, { recursive: true });
173
+
174
+ return EMBEDDED_SKILLS.map((entry) => {
175
+ const destination = join(targetSkillsDir, entry.name);
176
+ const destinationSkillPath = join(destination, "SKILL.md");
177
+ const exists = existsSync(destinationSkillPath);
178
+ const unchanged = exists && readFileSync(destinationSkillPath, "utf-8") === entry.skill;
179
+ let status: CodexSetupStatus = unchanged ? "unchanged" : exists ? "updated" : "installed";
180
+ if (dryRun && status === "installed") status = "would_install";
181
+ if (dryRun && status === "updated") status = "would_update";
182
+ if (!dryRun && !unchanged) {
183
+ mkdirSync(destination, { recursive: true });
184
+ writeFileSync(destinationSkillPath, entry.skill);
185
+ }
186
+ return {
187
+ name: entry.name,
188
+ source: `${EMBEDDED_PLUGIN_ROOT}/skills/${entry.name}`,
189
+ destination,
190
+ status,
191
+ };
192
+ });
193
+ }
194
+
195
+ function installAgentsTemplate(
196
+ projectRoot: string,
197
+ pluginRoot: string | null,
198
+ agentsFile: string,
199
+ dryRun: boolean
200
+ ): CodexSetupResult["agents"] {
201
+ const target = resolve(projectRoot, agentsFile);
202
+ const template = (pluginRoot
203
+ ? readFileSync(join(pluginRoot, AGENTS_TEMPLATE_PATH), "utf-8")
204
+ : agentsTemplateAsset
205
+ ).trimEnd();
206
+ if (existsSync(target)) {
207
+ const current = readFileSync(target, "utf-8");
208
+ if (current.includes(CODEX_MARKER)) {
209
+ return { path: target, status: "already_present" };
210
+ }
211
+ if (!dryRun) appendFileSync(target, `${current.endsWith("\n") ? "\n" : "\n\n"}${template}\n`);
212
+ return { path: target, status: dryRun ? "would_append" : "appended" };
213
+ }
214
+ if (!dryRun) writeFileSync(target, `${template}\n`);
215
+ return { path: target, status: dryRun ? "would_create" : "created" };
216
+ }
217
+
218
+ function setupMcp(requested: boolean, dryRun: boolean): CodexSetupResult["mcp"] {
219
+ const command = MCP_COMMAND.join(" ");
220
+ if (!requested) return { requested, command, status: "skipped" };
221
+ if (dryRun) return { requested, command, status: "would_run" };
222
+
223
+ const result = Bun.spawnSync({
224
+ cmd: MCP_COMMAND,
225
+ stdout: "pipe",
226
+ stderr: "pipe",
227
+ });
228
+ if (result.success) return { requested, command, status: "installed", exit_code: result.exitCode };
229
+
230
+ const stderr = new TextDecoder().decode(result.stderr).trim();
231
+ const stdout = new TextDecoder().decode(result.stdout).trim();
232
+ return {
233
+ requested,
234
+ command,
235
+ status: "failed",
236
+ exit_code: result.exitCode,
237
+ error: stderr || stdout || "codex mcp add failed",
238
+ };
239
+ }
240
+
241
+ function resolveCodexHome(codexHome?: string): string {
242
+ return resolve(codexHome ?? process.env.CODEX_HOME ?? join(process.env.HOME ?? process.env.USERPROFILE ?? homedir(), ".codex"));
243
+ }
244
+
245
+ function bundledPluginRoot(): string {
246
+ return join(dirname(dirname(dirname(fileURLToPath(import.meta.url)))), "plugins", "codetrap-agent");
247
+ }