@cleocode/adapters 2026.10.4 → 2026.10.5-rc.ci.672

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.
Files changed (37) hide show
  1. package/dist/index.js +1608 -1380
  2. package/dist/index.js.map +3 -3
  3. package/dist/providers/claude-code/adapter.d.ts.map +1 -1
  4. package/dist/providers/claude-code/hooks.d.ts +43 -17
  5. package/dist/providers/claude-code/hooks.d.ts.map +1 -1
  6. package/dist/providers/claude-code/install.d.ts +42 -14
  7. package/dist/providers/claude-code/install.d.ts.map +1 -1
  8. package/dist/providers/claude-code/paths.d.ts +77 -0
  9. package/dist/providers/claude-code/paths.d.ts.map +1 -1
  10. package/dist/providers/codex/install.d.ts.map +1 -1
  11. package/dist/providers/cursor/install.d.ts.map +1 -1
  12. package/dist/providers/gemini-cli/install.d.ts.map +1 -1
  13. package/dist/providers/kimi/install.d.ts.map +1 -1
  14. package/dist/providers/openai-sdk/install.d.ts.map +1 -1
  15. package/dist/providers/opencode/install.d.ts.map +1 -1
  16. package/dist/providers/pi/install.d.ts.map +1 -1
  17. package/dist/providers/shared/heavy-command-hook-install.d.ts.map +1 -1
  18. package/dist/providers/shared/project-instruction-file.d.ts +30 -0
  19. package/dist/providers/shared/project-instruction-file.d.ts.map +1 -0
  20. package/package.json +5 -5
  21. package/src/__tests__/claude-code-adapter.test.ts +11 -6
  22. package/src/providers/claude-code/__tests__/hooks-install.test.ts +20 -17
  23. package/src/providers/claude-code/__tests__/no-user-global-write.test.ts +293 -0
  24. package/src/providers/claude-code/adapter.ts +3 -1
  25. package/src/providers/claude-code/hooks.ts +138 -51
  26. package/src/providers/claude-code/install.ts +123 -52
  27. package/src/providers/claude-code/paths.ts +159 -1
  28. package/src/providers/codex/install.ts +4 -2
  29. package/src/providers/cursor/install.ts +26 -12
  30. package/src/providers/gemini-cli/install.ts +4 -2
  31. package/src/providers/kimi/install.ts +4 -2
  32. package/src/providers/openai-sdk/install.ts +5 -2
  33. package/src/providers/opencode/install.ts +4 -2
  34. package/src/providers/pi/install.ts +4 -2
  35. package/src/providers/shared/__tests__/heavy-command-hook-install.test.ts +20 -0
  36. package/src/providers/shared/heavy-command-hook-install.ts +6 -1
  37. package/src/providers/shared/project-instruction-file.ts +47 -0
@@ -1 +1 @@
1
- {"version":3,"file":"adapter.d.ts","sourceRoot":"","sources":["../../../src/providers/claude-code/adapter.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAKH,OAAO,KAAK,EACV,mBAAmB,EACnB,mBAAmB,EACnB,oBAAoB,EACpB,mBAAmB,EACpB,MAAM,qBAAqB,CAAC;AAG7B,OAAO,EAAE,gCAAgC,EAAE,MAAM,sBAAsB,CAAC;AACxE,OAAO,EAAE,sBAAsB,EAAE,MAAM,YAAY,CAAC;AACpD,OAAO,EAAE,yBAAyB,EAAE,MAAM,cAAc,CAAC;AACzD,OAAO,EAAE,sBAAsB,EAAE,MAAM,YAAY,CAAC;AAEpD,OAAO,EAAE,0BAA0B,EAAE,MAAM,gBAAgB,CAAC;AAC5D,OAAO,EAAE,2BAA2B,EAAE,MAAM,gBAAgB,CAAC;AAE7D;;;;;;;;;;;;;;GAcG;AACH,qBAAa,iBAAkB,YAAW,mBAAmB;IAC3D,kCAAkC;IAClC,QAAQ,CAAC,EAAE,iBAAiB;IAC5B,oCAAoC;IACpC,QAAQ,CAAC,IAAI,iBAAiB;IAC9B,8BAA8B;IAC9B,QAAQ,CAAC,OAAO,WAAW;IAE3B,+CAA+C;IAC/C,YAAY,EAAE,mBAAmB,CA6B/B;IAEF,8DAA8D;IAC9D,KAAK,EAAE,sBAAsB,CAAC;IAC9B;;;;;;OAMG;IACH,KAAK,EAAE,oBAAoB,CAAC;IAC5B,+EAA+E;IAC/E,OAAO,EAAE,yBAAyB,CAAC;IACnC,mEAAmE;IACnE,KAAK,EAAE,sBAAsB,CAAC;IAC9B,+EAA+E;IAC/E,cAAc,EAAE,gCAAgC,CAAC;IACjD,wDAAwD;IACxD,SAAS,EAAE,2BAA2B,CAAC;IACvC,2EAA2E;IAC3E,QAAQ,EAAE,0BAA0B,CAAC;IAErC,oEAAoE;IACpE,OAAO,CAAC,UAAU,CAAuB;IACzC,kDAAkD;IAClD,OAAO,CAAC,WAAW,CAAS;;IAY5B;;;;;;;;OAQG;IACG,UAAU,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAqCnD;;;;OAIG;IACG,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IAQ9B;;;;;;;;;OASG;IACG,WAAW,IAAI,OAAO,CAAC,mBAAmB,CAAC;IAuCjD;;OAEG;IACH,aAAa,IAAI,OAAO;IAIxB;;OAEG;IACH,aAAa,IAAI,MAAM,GAAG,IAAI;CAG/B"}
1
+ {"version":3,"file":"adapter.d.ts","sourceRoot":"","sources":["../../../src/providers/claude-code/adapter.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAKH,OAAO,KAAK,EACV,mBAAmB,EACnB,mBAAmB,EACnB,oBAAoB,EACpB,mBAAmB,EACpB,MAAM,qBAAqB,CAAC;AAG7B,OAAO,EAAE,gCAAgC,EAAE,MAAM,sBAAsB,CAAC;AACxE,OAAO,EAAE,sBAAsB,EAAE,MAAM,YAAY,CAAC;AACpD,OAAO,EAAE,yBAAyB,EAAE,MAAM,cAAc,CAAC;AACzD,OAAO,EAAE,sBAAsB,EAAE,MAAM,YAAY,CAAC;AAEpD,OAAO,EAAE,0BAA0B,EAAE,MAAM,gBAAgB,CAAC;AAC5D,OAAO,EAAE,2BAA2B,EAAE,MAAM,gBAAgB,CAAC;AAE7D;;;;;;;;;;;;;;GAcG;AACH,qBAAa,iBAAkB,YAAW,mBAAmB;IAC3D,kCAAkC;IAClC,QAAQ,CAAC,EAAE,iBAAiB;IAC5B,oCAAoC;IACpC,QAAQ,CAAC,IAAI,iBAAiB;IAC9B,8BAA8B;IAC9B,QAAQ,CAAC,OAAO,WAAW;IAE3B,+CAA+C;IAC/C,YAAY,EAAE,mBAAmB,CA6B/B;IAEF,8DAA8D;IAC9D,KAAK,EAAE,sBAAsB,CAAC;IAC9B;;;;;;OAMG;IACH,KAAK,EAAE,oBAAoB,CAAC;IAC5B,+EAA+E;IAC/E,OAAO,EAAE,yBAAyB,CAAC;IACnC,mEAAmE;IACnE,KAAK,EAAE,sBAAsB,CAAC;IAC9B,+EAA+E;IAC/E,cAAc,EAAE,gCAAgC,CAAC;IACjD,wDAAwD;IACxD,SAAS,EAAE,2BAA2B,CAAC;IACvC,2EAA2E;IAC3E,QAAQ,EAAE,0BAA0B,CAAC;IAErC,oEAAoE;IACpE,OAAO,CAAC,UAAU,CAAuB;IACzC,kDAAkD;IAClD,OAAO,CAAC,WAAW,CAAS;;IAY5B;;;;;;;;OAQG;IACG,UAAU,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAuCnD;;;;OAIG;IACG,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IAQ9B;;;;;;;;;OASG;IACG,WAAW,IAAI,OAAO,CAAC,mBAAmB,CAAC;IAuCjD;;OAEG;IACH,aAAa,IAAI,OAAO;IAIxB;;OAEG;IACH,aAAa,IAAI,MAAM,GAAG,IAAI;CAG/B"}
@@ -16,11 +16,23 @@
16
16
  * @epic T134
17
17
  */
18
18
  import type { AdapterHookProvider } from '@cleocode/contracts';
19
+ /** The `Stop` hook command: end the CLEO session when Claude Code stops. */
20
+ export declare const NATIVE_STOP_HOOK_COMMAND = "cleo session end --quiet # cleo-hook";
21
+ /** The `PostToolUse` (`Write|Edit`) hook command: a brain observation per file write. */
22
+ export declare const NATIVE_OBSERVE_HOOK_COMMAND = "cleo observe \"File modified via $TOOL_NAME\" --title \"tool-use\" --quiet # cleo-hook";
23
+ /**
24
+ * The `PostToolUse` (`Write|Edit`) NEXUS post-check: re-index changed files and
25
+ * flag regressions. `$TOOL_INPUT_file_path` is populated by Claude Code for
26
+ * Write/Edit events.
27
+ */
28
+ export declare const NATIVE_NEXUS_HOOK_COMMAND = "cleo nexus analyze --incremental --json > /dev/null 2>&1 && cleo observe \"NEXUS re-indexed after $TOOL_NAME on $TOOL_INPUT_file_path\" --title \"nexus-post-check\" --quiet # cleo-hook";
19
29
  /**
20
30
  * Hook provider for Claude Code.
21
31
  *
22
- * Claude Code registers hooks via its global config at `~/.claude/settings.json`.
23
- * Supported handler types: command, http, prompt, agent.
32
+ * CLEO registers its Claude Code hooks in the project's per-machine
33
+ * `<project>/.claude/settings.local.json`, never in the user-global
34
+ * `~/.claude/settings.json` (T13227). Supported handler types: command, http,
35
+ * prompt, agent.
24
36
  *
25
37
  * Event mapping is based on `getProviderHookProfile('claude-code')` from
26
38
  * CAAMP 1.9.1. Async accessors (`getSupportedCanonicalEvents`,
@@ -60,45 +72,59 @@ export declare class ClaudeCodeHookProvider implements AdapterHookProvider {
60
72
  /**
61
73
  * Register native hooks for a project.
62
74
  *
63
- * Writes CLEO hook entries to `~/.claude/settings.json` so that Claude Code's
64
- * native event system calls cleo CLI commands when events fire. This bridges
65
- * Claude Code's event loop to CLEO's internal hook dispatch.
75
+ * Writes CLEO hook entries to the project's per-machine
76
+ * `<project>/.claude/settings.local.json` so that Claude Code's native event
77
+ * system calls cleo CLI commands when events fire in this project. This
78
+ * bridges Claude Code's event loop to CLEO's internal hook dispatch.
79
+ * CLEO never writes the user-global `~/.claude/settings.json` (T13227): a
80
+ * project that is the home directory, or whose settings file resolves into
81
+ * the user-global Claude config, is refused and nothing is written. When
82
+ * git does not ignore `settings.local.json` yet, a marked `info/exclude`
83
+ * block keeps it out of git (the T12983 heavy-command rule).
66
84
  *
67
- * Idempotent: skips writing if CLEO hooks already exist in settings.json.
85
+ * Idempotent: skips writing if the native hooks are already present.
68
86
  *
69
87
  * Hook entries registered:
70
88
  * - `Stop` → `cleo session end --quiet` (triggers LLM extraction, reflector, consolidation)
71
89
  * - `PostToolUse` (Write|Edit) → brain observation for file modifications
72
- * - `SubagentStop` → brain observation for agent completion
90
+ * and the NEXUS post-check
73
91
  *
74
- * @param projectDir - Project directory for context-scoped hook commands
75
- * @task T164 @task T555
92
+ * @param projectDir - Project whose Claude Code settings receive the hooks
93
+ * @task T164 @task T555 @task T13227
76
94
  */
77
95
  registerNativeHooks(projectDir: string): Promise<void>;
78
96
  /**
79
97
  * Unregister native hooks.
80
98
  *
81
- * Removes CLEO hook entries from Claude Code's `settings.json` by filtering
82
- * out entries containing the `# cleo-hook` marker. Same locking, atomicity
83
- * and parse-error rules as {@link registerNativeHooks}.
99
+ * Removes the hook objects {@link registerNativeHooks} wrote from the
100
+ * project's `settings.local.json`, and nothing else: the heavy-command hook
101
+ * and the user's own hooks stay, and an entry or event is dropped only when
102
+ * left empty. Same locking, atomicity, parse-error and project-scope rules
103
+ * as {@link registerNativeHooks}.
84
104
  *
85
- * @task T164 @task T555
105
+ * @task T164 @task T555 @task T13227
86
106
  */
87
107
  unregisterNativeHooks(): Promise<void>;
88
108
  /** The last settings.json failure, or `null` when the last update succeeded. */
89
109
  private settingsError;
90
110
  /**
91
- * Why the last settings.json update did not happen, or `null`.
111
+ * Why the last settings update did not happen, or `null`.
92
112
  *
93
113
  * @remarks
94
114
  * Hook registration stays non-fatal for adapter initialisation, so a
95
- * refused write (malformed settings.json, lock timeout) is surfaced here and
96
- * on stderr instead of being swallowed (T12385).
115
+ * refused write (malformed settings file, lock timeout, a user-global
116
+ * target) is surfaced here and on stderr instead of being swallowed
117
+ * (T12385, T13227).
97
118
  *
98
119
  * @returns The failure message, or `null`
99
120
  */
100
121
  getSettingsError(): string | null;
101
- /** Apply `mutate` to settings.json via CAAMP's locked, atomic JSON writer. */
122
+ /**
123
+ * Apply `mutate` to the project's `settings.local.json` via CAAMP's locked,
124
+ * atomic JSON writer.
125
+ *
126
+ * @returns whether the file was written.
127
+ */
102
128
  private updateSettings;
103
129
  /**
104
130
  * Check whether hooks have been registered via `registerNativeHooks`.
@@ -1 +1 @@
1
- {"version":3,"file":"hooks.d.ts","sourceRoot":"","sources":["../../../src/providers/claude-code/hooks.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAMH,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAC;AAqD/D;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,qBAAa,sBAAuB,YAAW,mBAAmB;IAChE,kEAAkE;IAClE,OAAO,CAAC,UAAU,CAAS;IAE3B;;;;;;;;;;;OAWG;IACH,gBAAgB,CAAC,aAAa,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI;IAItD,+DAA+D;IAC/D,OAAO,CAAC,UAAU,CAAuB;IAEzC;;;;;;;;;;;;;;;;OAgBG;IACG,mBAAmB,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAuC5D;;;;;;;;OAQG;IACG,qBAAqB,IAAI,OAAO,CAAC,IAAI,CAAC;IAW5C,gFAAgF;IAChF,OAAO,CAAC,aAAa,CAAuB;IAE5C;;;;;;;;;OASG;IACH,gBAAgB,IAAI,MAAM,GAAG,IAAI;IAIjC,8EAA8E;YAChE,cAAc;IAe5B;;OAEG;IACH,YAAY,IAAI,OAAO;IAIvB;;;;OAIG;IACH,aAAa,IAAI,MAAM,GAAG,IAAI;IAI9B;;;;;;;;OAQG;IACH,WAAW,IAAI,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAI/C;;;;;;;;;;OAUG;IACG,2BAA2B,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC;IAStD;;;;;;;;;;OAUG;IACG,kBAAkB,IAAI,OAAO,CAAC,OAAO,GAAG,IAAI,CAAC;IASnD;;;;;;;;;;OAUG;IACG,aAAa,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;IAW9D;;;;;;;;;;;;;;;;OAgBG;IACG,aAAa,CAAC,SAAS,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;CA4FpF"}
1
+ {"version":3,"file":"hooks.d.ts","sourceRoot":"","sources":["../../../src/providers/claude-code/hooks.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAMH,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAC;AAI/D,4EAA4E;AAC5E,eAAO,MAAM,wBAAwB,yCAAyC,CAAC;AAE/E,yFAAyF;AACzF,eAAO,MAAM,2BAA2B,2FAC8C,CAAC;AAEvF;;;;GAIG;AACH,eAAO,MAAM,yBAAyB,6LACkJ,CAAC;AA4GzL;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,qBAAa,sBAAuB,YAAW,mBAAmB;IAChE,kEAAkE;IAClE,OAAO,CAAC,UAAU,CAAS;IAE3B;;;;;;;;;;;OAWG;IACH,gBAAgB,CAAC,aAAa,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI;IAItD,+DAA+D;IAC/D,OAAO,CAAC,UAAU,CAAuB;IAEzC;;;;;;;;;;;;;;;;;;;;;;OAsBG;IACG,mBAAmB,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IA0B5D;;;;;;;;;;OAUG;IACG,qBAAqB,IAAI,OAAO,CAAC,IAAI,CAAC;IAmB5C,gFAAgF;IAChF,OAAO,CAAC,aAAa,CAAuB;IAE5C;;;;;;;;;;OAUG;IACH,gBAAgB,IAAI,MAAM,GAAG,IAAI;IAIjC;;;;;OAKG;YACW,cAAc;IAmB5B;;OAEG;IACH,YAAY,IAAI,OAAO;IAIvB;;;;OAIG;IACH,aAAa,IAAI,MAAM,GAAG,IAAI;IAI9B;;;;;;;;OAQG;IACH,WAAW,IAAI,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAI/C;;;;;;;;;;OAUG;IACG,2BAA2B,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC;IAStD;;;;;;;;;;OAUG;IACG,kBAAkB,IAAI,OAAO,CAAC,OAAO,GAAG,IAAI,CAAC;IASnD;;;;;;;;;;OAUG;IACG,aAAa,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;IAW9D;;;;;;;;;;;;;;;;OAgBG;IACG,aAAa,CAAC,SAAS,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;CA4FpF"}
@@ -3,14 +3,22 @@
3
3
  *
4
4
  * Handles CLEO installation into Claude Code environments:
5
5
  * - Ensures CLAUDE.md has CLEO @-references
6
- * - Manages plugin registration in ~/.claude/settings.json
6
+ * - Manages plugin registration in the PROJECT's `.claude/settings.local.json`
7
+ * - Installs the PreCompact hook templates in the PROJECT's `.claude/hooks/`
7
8
  * - Installs the heavy-command `PreToolUse` hook in the PROJECT's
8
9
  * `.claude/settings.local.json` (T12983)
9
10
  *
11
+ * Project-level only (T13227): CLEO never writes the user-global
12
+ * `~/.claude/settings.json` or `~/.claude/hooks/` (`CLAUDE_HOME`,
13
+ * `CLAUDE_SETTINGS`). A project that is the home directory, or whose
14
+ * `.claude/` resolves into the user-global Claude config, gets those steps
15
+ * reported as `skipped` and nothing is written there.
16
+ *
10
17
  * Migrated from src/core/install/claude-plugin.ts
11
18
  *
12
19
  * @task T5240
13
20
  * @task T12983
21
+ * @task T13227
14
22
  */
15
23
  import type { AdapterInstallProvider, InstallOptions, InstallResult } from '@cleocode/contracts';
16
24
  /**
@@ -18,19 +26,24 @@ import type { AdapterInstallProvider, InstallOptions, InstallResult } from '@cle
18
26
  *
19
27
  * Manages CLEO's integration with Claude Code by:
20
28
  * 1. Ensuring CLAUDE.md contains @-references to CLEO instruction files
21
- * 2. Installing adapter-provided commands to .claude/commands/
22
- * 3. Registering the brain observation plugin in ~/.claude/settings.json
23
- * 4. Installing PreCompact hook templates
29
+ * 2. Installing adapter-provided commands to the project's .claude/commands/
30
+ * 3. Registering the brain observation plugin in the project's
31
+ * `.claude/settings.local.json`
32
+ * 4. Installing PreCompact hook templates in the project's `.claude/hooks/`
33
+ * and wiring them into the project's `.claude/settings.local.json`
24
34
  * 5. Installing the heavy-command `PreToolUse` hook in the project's
25
35
  * `.claude/settings.local.json`, when `options.heavyCommandHook` is set
26
36
  *
27
37
  * @remarks
28
38
  * Installation is idempotent -- running install multiple times on the same
29
39
  * project produces the same result. The provider disables the legacy
30
- * `claude-mem\@thedotmack` plugin if present and enables the unified
31
- * `cleo\@cleocode` plugin instead.
40
+ * `claude-mem\@thedotmack` plugin for the project if present and enables the
41
+ * unified `cleo\@cleocode` plugin instead. Nothing is written to the
42
+ * user-global Claude config (T13227).
32
43
  */
33
44
  export declare class ClaudeCodeInstallProvider implements AdapterInstallProvider {
45
+ /** The project the last {@link install} ran for; {@link isInstalled} reads its settings. */
46
+ private projectDir;
34
47
  /**
35
48
  * Install CLEO into a Claude Code project.
36
49
  *
@@ -47,7 +60,9 @@ export declare class ClaudeCodeInstallProvider implements AdapterInstallProvider
47
60
  /**
48
61
  * Check whether CLEO is installed in the current environment.
49
62
  *
50
- * Checks for plugin enabled in ~/.claude/settings.json.
63
+ * Checks for the plugin enabled in the project's
64
+ * `.claude/settings.local.json` — the project of the last {@link install},
65
+ * else the working directory (T13227).
51
66
  */
52
67
  isInstalled(): Promise<boolean>;
53
68
  /**
@@ -57,6 +72,8 @@ export declare class ClaudeCodeInstallProvider implements AdapterInstallProvider
57
72
  * and default references from the provider registry (T1919).
58
73
  *
59
74
  * @param projectDir - Project root directory
75
+ * @throws {@link UserGlobalClaudeConfigError} when the project root is inside
76
+ * the user-global Claude config dir (T13227); nothing is written.
60
77
  */
61
78
  ensureInstructionReferences(projectDir: string): Promise<void>;
62
79
  /**
@@ -67,43 +84,54 @@ export declare class ClaudeCodeInstallProvider implements AdapterInstallProvider
67
84
  *
68
85
  * @param projectDir - Project root directory
69
86
  * @returns Array of installed command filenames
87
+ * @throws {@link UserGlobalClaudeConfigError} when the target is user-global
70
88
  */
71
89
  private installCommands;
72
90
  /**
73
- * Register the CLEO brain plugin in ~/.claude/settings.json.
91
+ * Register the CLEO brain plugin in the project's
92
+ * `.claude/settings.local.json` (T13227: never the user-global settings).
74
93
  *
94
+ * @param projectDir - Project root directory
75
95
  * @returns Description of what was registered, or null if no change needed
96
+ * @throws {@link UserGlobalClaudeConfigError} when the target is user-global
76
97
  */
77
98
  private registerPlugin;
78
99
  /**
79
100
  * Install the CLEO PreCompact hook templates for Claude Code (T1013).
80
101
  *
81
- * Writes two files to `~/.claude/hooks/`:
102
+ * Writes two files to the project's `.claude/hooks/`:
82
103
  * 1. `cleo-precompact-core.sh` — universal CLEO safestop helper (shared
83
104
  * across all providers; sourced by the provider-specific shim).
84
105
  * 2. `precompact-safestop.sh` — Claude-Code-flavoured wrapper that invokes
85
106
  * `cleo memory precompact-flush` and `cleo safestop`.
86
107
  *
87
- * Also registers a `PreCompact` entry in `~/.claude/settings.json` so Claude
88
- * Code runs the hook when auto-compact fires (at 95% context).
108
+ * Also registers a `PreCompact` entry in the project's
109
+ * `.claude/settings.local.json` so Claude Code runs the hook when
110
+ * auto-compact fires (at 95% context). Files git does not ignore yet are
111
+ * kept out of it with a marked `info/exclude` block. Nothing is written to
112
+ * the user-global Claude config (T13227).
89
113
  *
90
114
  * Idempotent: subsequent installs skip unchanged files and do not duplicate
91
- * the settings.json hook entry.
115
+ * the settings hook entry.
92
116
  *
117
+ * @param projectDir - Project root directory
93
118
  * @returns Install summary (paths written + config change description), or
94
119
  * `null` when no change was required.
120
+ * @throws {@link UserGlobalClaudeConfigError} when the target is user-global
95
121
  *
96
- * @task T1013
122
+ * @task T1013 @task T13227
97
123
  */
98
124
  private installHookTemplates;
99
125
  /**
100
- * Register the PreCompact hook command in `~/.claude/settings.json`.
126
+ * Register the PreCompact hook command in the project's
127
+ * `.claude/settings.local.json`.
101
128
  *
102
129
  * The Claude Code native event name for the canonical `PreCompact` event is
103
130
  * `PreCompact` (identity mapping — see `hook-mappings.json`). The entry is
104
131
  * tagged with `# cleo-hook` so the uninstall flow can identify and remove
105
132
  * our additions without touching user-authored hooks.
106
133
  *
134
+ * @param settingsPath - The project settings file (already scope-checked).
107
135
  * @param shimPath - Absolute path to the installed `precompact-safestop.sh`.
108
136
  * @returns `true` when a new hook entry was written, `false` when an
109
137
  * equivalent entry was already present.
@@ -1 +1 @@
1
- {"version":3,"file":"install.d.ts","sourceRoot":"","sources":["../../../src/providers/claude-code/install.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAOH,OAAO,KAAK,EAAE,sBAAsB,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AA6BjG;;;;;;;;;;;;;;;;GAgBG;AACH,qBAAa,yBAA0B,YAAW,sBAAsB;IACtE;;;;;OAKG;IACG,OAAO,CAAC,OAAO,EAAE,cAAc,GAAG,OAAO,CAAC,aAAa,CAAC;IA0E9D;;;;OAIG;IACG,SAAS,IAAI,OAAO,CAAC,IAAI,CAAC;IAEhC;;;;OAIG;IACG,WAAW,IAAI,OAAO,CAAC,OAAO,CAAC;IAkBrC;;;;;;;OAOG;IACG,2BAA2B,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAIpE;;;;;;;;OAQG;IACH,OAAO,CAAC,eAAe;IAsBvB;;;;OAIG;YACW,cAAc;IAwB5B;;;;;;;;;;;;;;;;;;;OAmBG;YACW,oBAAoB;IAgClC;;;;;;;;;;;;;OAaG;YACW,sBAAsB;CAmBrC"}
1
+ {"version":3,"file":"install.d.ts","sourceRoot":"","sources":["../../../src/providers/claude-code/install.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAMH,OAAO,KAAK,EAAE,sBAAsB,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAwCjG;;;;;;;;;;;;;;;;;;;GAmBG;AACH,qBAAa,yBAA0B,YAAW,sBAAsB;IACtE,4FAA4F;IAC5F,OAAO,CAAC,UAAU,CAAuB;IAEzC;;;;;OAKG;IACG,OAAO,CAAC,OAAO,EAAE,cAAc,GAAG,OAAO,CAAC,aAAa,CAAC;IA4F9D;;;;OAIG;IACG,SAAS,IAAI,OAAO,CAAC,IAAI,CAAC;IAEhC;;;;;;OAMG;IACG,WAAW,IAAI,OAAO,CAAC,OAAO,CAAC;IAwBrC;;;;;;;;;OASG;IACG,2BAA2B,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAKpE;;;;;;;;;OASG;IACH,OAAO,CAAC,eAAe;IAsBvB;;;;;;;OAOG;YACW,cAAc;IA2B5B;;;;;;;;;;;;;;;;;;;;;;;;OAwBG;YACW,oBAAoB;IAoClC;;;;;;;;;;;;;;;OAeG;YACW,sBAAsB;CAmBrC"}
@@ -47,5 +47,82 @@ export declare class ClaudeCodePathProvider implements AdapterPathProvider {
47
47
  * ```
48
48
  */
49
49
  export declare function claudeSettingsPath(): string;
50
+ /**
51
+ * The adapter was asked to write somewhere that is, or lies inside, the
52
+ * user-global Claude Code config (T13227). CLEO never writes there — adding
53
+ * and removing entries alike — so nothing is written and the caller reports
54
+ * the step as skipped.
55
+ */
56
+ export declare class UserGlobalClaudeConfigError extends Error {
57
+ /** The path that was refused. */
58
+ readonly path: string;
59
+ /**
60
+ * @param path - the refused target.
61
+ * @param why - which user-global location it hits.
62
+ */
63
+ constructor(path: string, why: string);
64
+ }
65
+ /**
66
+ * The project's per-machine Claude Code settings file,
67
+ * `<project>/.claude/settings.local.json` — the only settings file the
68
+ * adapter's hook and plugin writers touch (T13227, the T12983/T13124 rule:
69
+ * project-level only, never the user-global `~/.claude/settings.json`).
70
+ *
71
+ * @param projectDir - the project root.
72
+ * @returns the absolute settings path.
73
+ * @throws {@link UserGlobalClaudeConfigError} when it would be user-global.
74
+ *
75
+ * @example
76
+ * ```typescript
77
+ * const target = projectClaudeSettingsPath('/repo'); // /repo/.claude/settings.local.json
78
+ * ```
79
+ */
80
+ export declare function projectClaudeSettingsPath(projectDir: string): string;
81
+ /**
82
+ * The project's Claude Code hook-script dir, `<project>/.claude/hooks`, where
83
+ * the PreCompact templates are copied (T13227).
84
+ *
85
+ * @param projectDir - the project root.
86
+ * @returns the absolute hooks dir.
87
+ * @throws {@link UserGlobalClaudeConfigError} when it would be user-global.
88
+ *
89
+ * @example
90
+ * ```typescript
91
+ * const dir = projectClaudeHooksDir('/repo'); // /repo/.claude/hooks
92
+ * ```
93
+ */
94
+ export declare function projectClaudeHooksDir(projectDir: string): string;
95
+ /**
96
+ * Refuse a project whose `CLAUDE.md` would be user-global in effect (T13227
97
+ * review): a root inside the user-global Claude config dir (in any spelling),
98
+ * where it is Claude Code's user-global memory file `~/.claude/CLAUDE.md`, or
99
+ * the home directory itself — Claude Code loads `CLAUDE.md` from the working
100
+ * directory up through every ancestor, so `~/CLAUDE.md` reaches every session
101
+ * under `$HOME`.
102
+ *
103
+ * @param projectDir - the project root.
104
+ * @throws {@link UserGlobalClaudeConfigError} when the project root is the
105
+ * home directory or inside the user-global Claude config dir.
106
+ *
107
+ * @example
108
+ * ```typescript
109
+ * assertProjectInstructionScope('/repo'); // ok
110
+ * ```
111
+ */
112
+ export declare function assertProjectInstructionScope(projectDir: string): void;
113
+ /**
114
+ * The project's Claude Code commands dir, `<project>/.claude/commands`, where
115
+ * the adapter's slash commands are copied (T13227).
116
+ *
117
+ * @param projectDir - the project root.
118
+ * @returns the absolute commands dir.
119
+ * @throws {@link UserGlobalClaudeConfigError} when it would be user-global.
120
+ *
121
+ * @example
122
+ * ```typescript
123
+ * const dir = projectClaudeCommandsDir('/repo'); // /repo/.claude/commands
124
+ * ```
125
+ */
126
+ export declare function projectClaudeCommandsDir(projectDir: string): string;
50
127
  export { appendHookEntry, CLEO_HOOK_MARKER, hasCleoHook, hookMap, isCleoHookEntry, isPlainObject, removeCleoHookEntries, } from '../shared/hook-config.js';
51
128
  //# sourceMappingURL=paths.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"paths.d.ts","sourceRoot":"","sources":["../../../src/providers/claude-code/paths.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAIH,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAC;AAE/D;;;;;;;;;;;;GAYG;AACH,qBAAa,sBAAuB,YAAW,mBAAmB;IAChE,uDAAuD;IACvD,cAAc,IAAI,MAAM;IAIxB,4EAA4E;IAC5E,eAAe,IAAI,MAAM,GAAG,IAAI;IAIhC,4EAA4E;IAC5E,kBAAkB,IAAI,MAAM,GAAG,IAAI;IAInC,8EAA8E;IAC9E,eAAe,IAAI,MAAM,GAAG,IAAI;CAGjC;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,kBAAkB,IAAI,MAAM,CAI3C;AAED,OAAO,EACL,eAAe,EACf,gBAAgB,EAChB,WAAW,EACX,OAAO,EACP,eAAe,EACf,aAAa,EACb,qBAAqB,GACtB,MAAM,0BAA0B,CAAC"}
1
+ {"version":3,"file":"paths.d.ts","sourceRoot":"","sources":["../../../src/providers/claude-code/paths.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAKH,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAC;AAG/D;;;;;;;;;;;;GAYG;AACH,qBAAa,sBAAuB,YAAW,mBAAmB;IAChE,uDAAuD;IACvD,cAAc,IAAI,MAAM;IAIxB,4EAA4E;IAC5E,eAAe,IAAI,MAAM,GAAG,IAAI;IAIhC,4EAA4E;IAC5E,kBAAkB,IAAI,MAAM,GAAG,IAAI;IAInC,8EAA8E;IAC9E,eAAe,IAAI,MAAM,GAAG,IAAI;CAGjC;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,kBAAkB,IAAI,MAAM,CAI3C;AAoCD;;;;;GAKG;AACH,qBAAa,2BAA4B,SAAQ,KAAK;IACpD,iCAAiC;IACjC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IAEtB;;;OAGG;gBACS,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM;CAKtC;AA6BD;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,yBAAyB,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,CAEpE;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,qBAAqB,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,CAEhE;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,6BAA6B,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI,CAEtE;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,wBAAwB,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,CAEnE;AAED,OAAO,EACL,eAAe,EACf,gBAAgB,EAChB,WAAW,EACX,OAAO,EACP,eAAe,EACf,aAAa,EACb,qBAAqB,GACtB,MAAM,0BAA0B,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"install.d.ts","sourceRoot":"","sources":["../../../src/providers/codex/install.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAIH,OAAO,KAAK,EAAE,sBAAsB,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAIjG;;;;;;;;;;;;;;;;;GAiBG;AACH,qBAAa,oBAAqB,YAAW,sBAAsB;IACjE;;;;;;OAMG;IACG,OAAO,CAAC,OAAO,EAAE,cAAc,GAAG,OAAO,CAAC,aAAa,CAAC;IAwC9D;;;;;OAKG;IACG,SAAS,IAAI,OAAO,CAAC,IAAI,CAAC;IAIhC;;;;;OAKG;IACG,WAAW,IAAI,OAAO,CAAC,OAAO,CAAC;IAerC;;;;;;;OAOG;IACG,2BAA2B,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;CAMrE"}
1
+ {"version":3,"file":"install.d.ts","sourceRoot":"","sources":["../../../src/providers/codex/install.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAIH,OAAO,KAAK,EAAE,sBAAsB,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAKjG;;;;;;;;;;;;;;;;;GAiBG;AACH,qBAAa,oBAAqB,YAAW,sBAAsB;IACjE;;;;;;OAMG;IACG,OAAO,CAAC,OAAO,EAAE,cAAc,GAAG,OAAO,CAAC,aAAa,CAAC;IAyC9D;;;;;OAKG;IACG,SAAS,IAAI,OAAO,CAAC,IAAI,CAAC;IAIhC;;;;;OAKG;IACG,WAAW,IAAI,OAAO,CAAC,OAAO,CAAC;IAerC;;;;;;;OAOG;IACG,2BAA2B,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;CAMrE"}
@@ -1 +1 @@
1
- {"version":3,"file":"install.d.ts","sourceRoot":"","sources":["../../../src/providers/cursor/install.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAUH,OAAO,KAAK,EAAE,sBAAsB,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAsBjG;;;;;;;;;;;;;GAaG;AACH,qBAAa,qBAAsB,YAAW,sBAAsB;IAClE;;;;;OAKG;IACG,OAAO,CAAC,OAAO,EAAE,cAAc,GAAG,OAAO,CAAC,aAAa,CAAC;IAuC9D;;;;OAIG;IACG,SAAS,IAAI,OAAO,CAAC,IAAI,CAAC;IAEhC;;;;OAIG;IACG,WAAW,IAAI,OAAO,CAAC,OAAO,CAAC;IA2BrC;;;;;;;OAOG;IACG,2BAA2B,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAKpE;;;;;;;;;;;;;;;OAeG;YACW,sBAAsB;IAcpC;;OAEG;IACH,OAAO,CAAC,kBAAkB;IAS1B;;;;;;;;;;;;;;;;;OAiBG;YACW,oBAAoB;IA8BlC;;;;;;;;;;;;OAYG;YACW,sBAAsB;CA+BrC"}
1
+ {"version":3,"file":"install.d.ts","sourceRoot":"","sources":["../../../src/providers/cursor/install.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAUH,OAAO,KAAK,EAAE,sBAAsB,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAwBjG;;;;;;;;;;;;;GAaG;AACH,qBAAa,qBAAsB,YAAW,sBAAsB;IAClE;;;;;OAKG;IACG,OAAO,CAAC,OAAO,EAAE,cAAc,GAAG,OAAO,CAAC,aAAa,CAAC;IAmD9D;;;;OAIG;IACG,SAAS,IAAI,OAAO,CAAC,IAAI,CAAC;IAEhC;;;;OAIG;IACG,WAAW,IAAI,OAAO,CAAC,OAAO,CAAC;IA2BrC;;;;;;;OAOG;IACG,2BAA2B,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAKpE;;;;;;;;;;;;;;;OAeG;YACW,sBAAsB;IAcpC;;OAEG;IACH,OAAO,CAAC,kBAAkB;IAS1B;;;;;;;;;;;;;;;;;OAiBG;YACW,oBAAoB;IA8BlC;;;;;;;;;;;;OAYG;YACW,sBAAsB;CA+BrC"}
@@ -1 +1 @@
1
- {"version":3,"file":"install.d.ts","sourceRoot":"","sources":["../../../src/providers/gemini-cli/install.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAKH,OAAO,KAAK,EAAE,sBAAsB,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAGjG;;;;;;;;;;;;;;GAcG;AACH,qBAAa,wBAAyB,YAAW,sBAAsB;IACrE;;;;;;OAMG;IACG,OAAO,CAAC,OAAO,EAAE,cAAc,GAAG,OAAO,CAAC,aAAa,CAAC;IAuB9D;;;;;OAKG;IACG,SAAS,IAAI,OAAO,CAAC,IAAI,CAAC;IAIhC;;;;;OAKG;IACG,WAAW,IAAI,OAAO,CAAC,OAAO,CAAC;IAiBrC;;;;;;;OAOG;IACG,2BAA2B,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;CAMrE"}
1
+ {"version":3,"file":"install.d.ts","sourceRoot":"","sources":["../../../src/providers/gemini-cli/install.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAKH,OAAO,KAAK,EAAE,sBAAsB,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAIjG;;;;;;;;;;;;;;GAcG;AACH,qBAAa,wBAAyB,YAAW,sBAAsB;IACrE;;;;;;OAMG;IACG,OAAO,CAAC,OAAO,EAAE,cAAc,GAAG,OAAO,CAAC,aAAa,CAAC;IAwB9D;;;;;OAKG;IACG,SAAS,IAAI,OAAO,CAAC,IAAI,CAAC;IAIhC;;;;;OAKG;IACG,WAAW,IAAI,OAAO,CAAC,OAAO,CAAC;IAiBrC;;;;;;;OAOG;IACG,2BAA2B,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;CAMrE"}
@@ -1 +1 @@
1
- {"version":3,"file":"install.d.ts","sourceRoot":"","sources":["../../../src/providers/kimi/install.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAKH,OAAO,KAAK,EAAE,sBAAsB,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAGjG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AACH,qBAAa,mBAAoB,YAAW,sBAAsB;IAChE;;;;;;OAMG;IACG,OAAO,CAAC,OAAO,EAAE,cAAc,GAAG,OAAO,CAAC,aAAa,CAAC;IAuB9D;;;;;OAKG;IACG,SAAS,IAAI,OAAO,CAAC,IAAI,CAAC;IAIhC;;;;;OAKG;IACG,WAAW,IAAI,OAAO,CAAC,OAAO,CAAC;IAiBrC;;;;;;;OAOG;IACG,2BAA2B,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;CAMrE"}
1
+ {"version":3,"file":"install.d.ts","sourceRoot":"","sources":["../../../src/providers/kimi/install.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAKH,OAAO,KAAK,EAAE,sBAAsB,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAIjG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AACH,qBAAa,mBAAoB,YAAW,sBAAsB;IAChE;;;;;;OAMG;IACG,OAAO,CAAC,OAAO,EAAE,cAAc,GAAG,OAAO,CAAC,aAAa,CAAC;IAwB9D;;;;;OAKG;IACG,SAAS,IAAI,OAAO,CAAC,IAAI,CAAC;IAIhC;;;;;OAKG;IACG,WAAW,IAAI,OAAO,CAAC,OAAO,CAAC;IAiBrC;;;;;;;OAOG;IACG,2BAA2B,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;CAMrE"}
@@ -1 +1 @@
1
- {"version":3,"file":"install.d.ts","sourceRoot":"","sources":["../../../src/providers/openai-sdk/install.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAKH,OAAO,KAAK,EAAE,sBAAsB,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAGjG;;;;;;;;;;;GAWG;AACH,qBAAa,wBAAyB,YAAW,sBAAsB;IACrE;;;;;OAKG;IACG,OAAO,CAAC,OAAO,EAAE,cAAc,GAAG,OAAO,CAAC,aAAa,CAAC;IA8B9D;;;;OAIG;IACG,SAAS,IAAI,OAAO,CAAC,IAAI,CAAC;IAEhC;;;;OAIG;IACG,WAAW,IAAI,OAAO,CAAC,OAAO,CAAC;IAMrC;;;;OAIG;IACG,2BAA2B,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAWpE;;;;OAIG;IACH,OAAO,CAAC,eAAe;CAOxB"}
1
+ {"version":3,"file":"install.d.ts","sourceRoot":"","sources":["../../../src/providers/openai-sdk/install.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAKH,OAAO,KAAK,EAAE,sBAAsB,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAIjG;;;;;;;;;;;GAWG;AACH,qBAAa,wBAAyB,YAAW,sBAAsB;IACrE;;;;;OAKG;IACG,OAAO,CAAC,OAAO,EAAE,cAAc,GAAG,OAAO,CAAC,aAAa,CAAC;IAgC9D;;;;OAIG;IACG,SAAS,IAAI,OAAO,CAAC,IAAI,CAAC;IAEhC;;;;OAIG;IACG,WAAW,IAAI,OAAO,CAAC,OAAO,CAAC;IAMrC;;;;OAIG;IACG,2BAA2B,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAWpE;;;;OAIG;IACH,OAAO,CAAC,eAAe;CAOxB"}
@@ -1 +1 @@
1
- {"version":3,"file":"install.d.ts","sourceRoot":"","sources":["../../../src/providers/opencode/install.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAKH,OAAO,KAAK,EAAE,sBAAsB,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAWjG;;;;;;;;;;;;;;;;;GAiBG;AACH,qBAAa,uBAAwB,YAAW,sBAAsB;IACpE;;;;;OAKG;IACG,OAAO,CAAC,OAAO,EAAE,cAAc,GAAG,OAAO,CAAC,aAAa,CAAC;IAiD9D;;;;OAIG;IACG,SAAS,IAAI,OAAO,CAAC,IAAI,CAAC;IAEhC;;;;OAIG;IACG,WAAW,IAAI,OAAO,CAAC,OAAO,CAAC;IAerC;;;;;;OAMG;IACG,2BAA2B,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAOpE;;;;;;;;;;;;;;;;;;;OAmBG;IACH,OAAO,CAAC,oBAAoB;IAiC5B;;;;;;;;;;;;;;OAcG;IACH,OAAO,CAAC,qBAAqB;CA0C9B"}
1
+ {"version":3,"file":"install.d.ts","sourceRoot":"","sources":["../../../src/providers/opencode/install.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAKH,OAAO,KAAK,EAAE,sBAAsB,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAYjG;;;;;;;;;;;;;;;;;GAiBG;AACH,qBAAa,uBAAwB,YAAW,sBAAsB;IACpE;;;;;OAKG;IACG,OAAO,CAAC,OAAO,EAAE,cAAc,GAAG,OAAO,CAAC,aAAa,CAAC;IAkD9D;;;;OAIG;IACG,SAAS,IAAI,OAAO,CAAC,IAAI,CAAC;IAEhC;;;;OAIG;IACG,WAAW,IAAI,OAAO,CAAC,OAAO,CAAC;IAerC;;;;;;OAMG;IACG,2BAA2B,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAOpE;;;;;;;;;;;;;;;;;;;OAmBG;IACH,OAAO,CAAC,oBAAoB;IAiC5B;;;;;;;;;;;;;;OAcG;IACH,OAAO,CAAC,qBAAqB;CA0C9B"}
@@ -1 +1 @@
1
- {"version":3,"file":"install.d.ts","sourceRoot":"","sources":["../../../src/providers/pi/install.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAIH,OAAO,KAAK,EAAE,sBAAsB,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAWjG;;;;;;;;;;;;;GAaG;AACH,qBAAa,iBAAkB,YAAW,sBAAsB;IAC9D;;;;;OAKG;IACG,OAAO,CAAC,OAAO,EAAE,cAAc,GAAG,OAAO,CAAC,aAAa,CAAC;IA0C9D;;;;OAIG;IACG,SAAS,IAAI,OAAO,CAAC,IAAI,CAAC;IAEhC;;;;OAIG;IACG,WAAW,IAAI,OAAO,CAAC,OAAO,CAAC;IA0BrC;;;;;;OAMG;IACG,2BAA2B,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;CAMrE"}
1
+ {"version":3,"file":"install.d.ts","sourceRoot":"","sources":["../../../src/providers/pi/install.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAIH,OAAO,KAAK,EAAE,sBAAsB,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAYjG;;;;;;;;;;;;;GAaG;AACH,qBAAa,iBAAkB,YAAW,sBAAsB;IAC9D;;;;;OAKG;IACG,OAAO,CAAC,OAAO,EAAE,cAAc,GAAG,OAAO,CAAC,aAAa,CAAC;IA2C9D;;;;OAIG;IACG,SAAS,IAAI,OAAO,CAAC,IAAI,CAAC;IAEhC;;;;OAIG;IACG,WAAW,IAAI,OAAO,CAAC,OAAO,CAAC;IA0BrC;;;;;;OAMG;IACG,2BAA2B,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;CAMrE"}
@@ -1 +1 @@
1
- {"version":3,"file":"heavy-command-hook-install.d.ts","sourceRoot":"","sources":["../../../src/providers/shared/heavy-command-hook-install.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"heavy-command-hook-install.d.ts","sourceRoot":"","sources":["../../../src/providers/shared/heavy-command-hook-install.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,30 @@
1
+ /**
2
+ * A provider's PROJECT instruction file, skipped (not failed) at a project
3
+ * rooted at the home directory (T13227).
4
+ *
5
+ * Providers load CLAUDE.md / AGENTS.md / GEMINI.md from the working directory
6
+ * up through every ancestor, so a file at `$HOME` reaches every session under
7
+ * it: CAAMP refuses it with `HomeInstructionFileError`. An adapter's install
8
+ * reports that step as `skipped` and carries on with the rest, the way the
9
+ * heavy-command hook already skips the home directory (T12983).
10
+ *
11
+ * @task T13227
12
+ */
13
+ import { type EnsureProviderInstructionFileOptions, type EnsureProviderInstructionFileResult } from '@cleocode/caamp';
14
+ /**
15
+ * Ensure a provider's project instruction file, or `null` when the project is
16
+ * the home directory and the file was refused (nothing written).
17
+ *
18
+ * @param providerId - CAAMP provider id.
19
+ * @param projectDir - the project root.
20
+ * @param options - references, content, scope.
21
+ * @returns the CAAMP result, or `null` when skipped at `$HOME`.
22
+ *
23
+ * @example
24
+ * ```typescript
25
+ * const r = await ensureProjectInstructionFile('codex', projectDir, { scope: 'project' });
26
+ * if (r === null) details.instructionFile = 'skipped';
27
+ * ```
28
+ */
29
+ export declare function ensureProjectInstructionFile(providerId: string, projectDir: string, options: EnsureProviderInstructionFileOptions): Promise<EnsureProviderInstructionFileResult | null>;
30
+ //# sourceMappingURL=project-instruction-file.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"project-instruction-file.d.ts","sourceRoot":"","sources":["../../../src/providers/shared/project-instruction-file.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,EACL,KAAK,oCAAoC,EACzC,KAAK,mCAAmC,EAGzC,MAAM,iBAAiB,CAAC;AAEzB;;;;;;;;;;;;;;GAcG;AACH,wBAAsB,4BAA4B,CAChD,UAAU,EAAE,MAAM,EAClB,UAAU,EAAE,MAAM,EAClB,OAAO,EAAE,oCAAoC,GAC5C,OAAO,CAAC,mCAAmC,GAAG,IAAI,CAAC,CAOrD"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cleocode/adapters",
3
- "version": "2026.10.4",
3
+ "version": "2026.10.5-rc.ci.672",
4
4
  "description": "Unified provider adapters for CLEO (Claude Code, OpenCode, Cursor)",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -19,9 +19,9 @@
19
19
  "@ai-sdk/anthropic": "^3.0.69",
20
20
  "@ai-sdk/openai": "^2.0.53",
21
21
  "ai": "^6.0.168",
22
- "@cleocode/caamp": "2026.10.4",
23
- "@cleocode/paths": "2026.10.4",
24
- "@cleocode/contracts": "2026.10.4"
22
+ "@cleocode/caamp": "2026.10.5-rc.ci.672",
23
+ "@cleocode/contracts": "2026.10.5-rc.ci.672",
24
+ "@cleocode/paths": "2026.10.5-rc.ci.672"
25
25
  },
26
26
  "license": "MIT",
27
27
  "engines": {
@@ -34,7 +34,7 @@
34
34
  "devDependencies": {
35
35
  "@types/node": "^24.3.0",
36
36
  "vitest": "^4.1.4",
37
- "@cleocode/playbooks": "2026.10.4"
37
+ "@cleocode/playbooks": "2026.10.5-rc.ci.672"
38
38
  },
39
39
  "repository": {
40
40
  "type": "git",
@@ -7,7 +7,7 @@
7
7
  * @task T5240
8
8
  */
9
9
 
10
- import { mkdirSync, readFileSync, rmSync, writeFileSync } from 'node:fs';
10
+ import { mkdirSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from 'node:fs';
11
11
  import { tmpdir } from 'node:os';
12
12
  import { join } from 'node:path';
13
13
  import {
@@ -108,11 +108,16 @@ describe('ClaudeCodeHookProvider — integration', () => {
108
108
  });
109
109
 
110
110
  it('tracks registration state', async () => {
111
- expect(hooks.isRegistered()).toBe(false);
112
- await hooks.registerNativeHooks('/tmp/test');
113
- expect(hooks.isRegistered()).toBe(true);
114
- await hooks.unregisterNativeHooks();
115
- expect(hooks.isRegistered()).toBe(false);
111
+ const projectDir = mkdtempSync(join(tmpdir(), 'cleo-claude-hooks-'));
112
+ try {
113
+ expect(hooks.isRegistered()).toBe(false);
114
+ await hooks.registerNativeHooks(projectDir);
115
+ expect(hooks.isRegistered()).toBe(true);
116
+ await hooks.unregisterNativeHooks();
117
+ expect(hooks.isRegistered()).toBe(false);
118
+ } finally {
119
+ rmSync(projectDir, { recursive: true, force: true });
120
+ }
116
121
  });
117
122
 
118
123
  it('exposes event map for introspection', () => {
@@ -3,9 +3,10 @@
3
3
  *
4
4
  * Validates that:
5
5
  * - Shared `cleo-precompact-core.sh` and provider-specific
6
- * `precompact-safestop.sh` are copied into `~/.claude/hooks/`.
7
- * - `~/.claude/settings.json` gains a `PreCompact` entry pointing at the
8
- * installed shim, tagged with the `# cleo-hook` sentinel for clean uninstall.
6
+ * `precompact-safestop.sh` are copied into the PROJECT's `.claude/hooks/`.
7
+ * - The project's `.claude/settings.local.json` gains a `PreCompact` entry
8
+ * pointing at the installed shim, tagged with the `# cleo-hook` sentinel.
9
+ * - The user-global `$CLAUDE_HOME` is never written (T13227).
9
10
  * - Repeat invocations are idempotent (no duplicate settings entries).
10
11
  * - The source templates contain the universal CLEO CLI invocations so the
11
12
  * bash contract remains DRY across providers.
@@ -14,6 +15,7 @@
14
15
  * impersonates `$HOME` via the `HOME` env var, so no user config is touched.
15
16
  *
16
17
  * @task T1013
18
+ * @task T13227
17
19
  * @epic T1000
18
20
  */
19
21
 
@@ -67,7 +69,7 @@ describe('ClaudeCodeInstallProvider — PreCompact hook templates', () => {
67
69
  rmSync(projectDir, { recursive: true, force: true });
68
70
  });
69
71
 
70
- it('installs both bash templates into $HOME/.claude/hooks/', async () => {
72
+ it('installs both bash templates into the project .claude/hooks/', async () => {
71
73
  const provider = new ClaudeCodeInstallProvider();
72
74
 
73
75
  const result = await provider.install({ projectDir });
@@ -79,20 +81,21 @@ describe('ClaudeCodeInstallProvider — PreCompact hook templates', () => {
79
81
  } | null;
80
82
 
81
83
  expect(hookTemplates).not.toBeNull();
82
- expect(hookTemplates?.templates.targetDir).toBe(join(fakeHome, '.claude', 'hooks'));
84
+ expect(hookTemplates?.templates.targetDir).toBe(join(projectDir, '.claude', 'hooks'));
85
+ expect(existsSync(join(fakeHome, '.claude'))).toBe(false);
83
86
  const installed = hookTemplates?.templates.installedFiles ?? [];
84
87
  expect(installed.some((p) => p.endsWith('cleo-precompact-core.sh'))).toBe(true);
85
88
  expect(installed.some((p) => p.endsWith('precompact-safestop.sh'))).toBe(true);
86
89
 
87
90
  // Installed shim sources the shared helper.
88
91
  const shim = readFileSync(
89
- join(fakeHome, '.claude', 'hooks', 'precompact-safestop.sh'),
92
+ join(projectDir, '.claude', 'hooks', 'precompact-safestop.sh'),
90
93
  'utf-8',
91
94
  );
92
95
  expect(shim).toContain('cleo-precompact-core.sh');
93
96
  // Shared helper invokes the universal CLEO CLI.
94
97
  const core = readFileSync(
95
- join(fakeHome, '.claude', 'hooks', 'cleo-precompact-core.sh'),
98
+ join(projectDir, '.claude', 'hooks', 'cleo-precompact-core.sh'),
96
99
  'utf-8',
97
100
  );
98
101
  expect(core).toContain('cleo memory precompact-flush');
@@ -100,11 +103,11 @@ describe('ClaudeCodeInstallProvider — PreCompact hook templates', () => {
100
103
  expect(core).toMatch(/cleo_cmd.*safestop/);
101
104
  });
102
105
 
103
- it('writes a PreCompact entry into $HOME/.claude/settings.json tagged # cleo-hook', async () => {
106
+ it('writes a PreCompact entry into the project settings.local.json tagged # cleo-hook', async () => {
104
107
  const provider = new ClaudeCodeInstallProvider();
105
108
  await provider.install({ projectDir });
106
109
 
107
- const settingsPath = join(fakeHome, '.claude', 'settings.json');
110
+ const settingsPath = join(projectDir, '.claude', 'settings.local.json');
108
111
  const settings = JSON.parse(readFileSync(settingsPath, 'utf-8')) as {
109
112
  hooks?: Record<string, Array<{ hooks?: Array<{ command?: string; type?: string }> }>>;
110
113
  };
@@ -124,7 +127,7 @@ describe('ClaudeCodeInstallProvider — PreCompact hook templates', () => {
124
127
  await provider.install({ projectDir });
125
128
  await provider.install({ projectDir });
126
129
 
127
- const settingsPath = join(fakeHome, '.claude', 'settings.json');
130
+ const settingsPath = join(projectDir, '.claude', 'settings.local.json');
128
131
  const settings = JSON.parse(readFileSync(settingsPath, 'utf-8')) as {
129
132
  hooks?: { PreCompact?: unknown[] };
130
133
  };
@@ -134,12 +137,12 @@ describe('ClaudeCodeInstallProvider — PreCompact hook templates', () => {
134
137
  // T12385 — a malformed settings.json used to be replaced with an object
135
138
  // holding only CLEO's entries (the parse error was caught and the writer
136
139
  // "started fresh"). It must now be reported and left byte-identical.
137
- describe('T12385 — malformed settings.json is never rewritten', () => {
140
+ describe('T12385 — malformed settings file is never rewritten', () => {
138
141
  const malformed = '{\n "permissions": { "allow": ["Bash(ls)"] },\n "model": "opus",\n';
139
142
 
140
143
  it('install reports the parse error and leaves the file byte-identical', async () => {
141
- const settingsPath = join(fakeHome, '.claude', 'settings.json');
142
- mkdirSync(join(fakeHome, '.claude'), { recursive: true });
144
+ const settingsPath = join(projectDir, '.claude', 'settings.local.json');
145
+ mkdirSync(join(projectDir, '.claude'), { recursive: true });
143
146
  writeFileSync(settingsPath, malformed, 'utf-8');
144
147
 
145
148
  const result = await new ClaudeCodeInstallProvider().install({ projectDir });
@@ -153,8 +156,8 @@ describe('ClaudeCodeInstallProvider — PreCompact hook templates', () => {
153
156
  });
154
157
 
155
158
  it('hook registration reports the parse error and leaves the file byte-identical', async () => {
156
- const settingsPath = join(fakeHome, '.claude', 'settings.json');
157
- mkdirSync(join(fakeHome, '.claude'), { recursive: true });
159
+ const settingsPath = join(projectDir, '.claude', 'settings.local.json');
160
+ mkdirSync(join(projectDir, '.claude'), { recursive: true });
158
161
  writeFileSync(settingsPath, malformed, 'utf-8');
159
162
  const stderr = vi.spyOn(process.stderr, 'write').mockImplementation(() => true);
160
163
 
@@ -168,8 +171,8 @@ describe('ClaudeCodeInstallProvider — PreCompact hook templates', () => {
168
171
  });
169
172
 
170
173
  it('preserves unrelated user settings when it does write', async () => {
171
- const settingsPath = join(fakeHome, '.claude', 'settings.json');
172
- mkdirSync(join(fakeHome, '.claude'), { recursive: true });
174
+ const settingsPath = join(projectDir, '.claude', 'settings.local.json');
175
+ mkdirSync(join(projectDir, '.claude'), { recursive: true });
173
176
  writeFileSync(
174
177
  settingsPath,
175
178
  JSON.stringify({ model: 'opus', hooks: { Stop: [{ matcher: 'x', hooks: [] }] } }),