@cleocode/adapters 2026.10.1 → 2026.10.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +1073 -262
- package/dist/index.js.map +3 -3
- package/dist/providers/claude-code/install.d.ts +6 -0
- package/dist/providers/claude-code/install.d.ts.map +1 -1
- package/dist/providers/claude-code/paths.d.ts +1 -78
- package/dist/providers/claude-code/paths.d.ts.map +1 -1
- package/dist/providers/codex/install.d.ts +8 -2
- package/dist/providers/codex/install.d.ts.map +1 -1
- package/dist/providers/kimi/install.d.ts +15 -0
- package/dist/providers/kimi/install.d.ts.map +1 -1
- package/dist/providers/opencode/install.d.ts +2 -0
- package/dist/providers/opencode/install.d.ts.map +1 -1
- package/dist/providers/shared/heavy-command-hook-install.d.ts +173 -0
- package/dist/providers/shared/heavy-command-hook-install.d.ts.map +1 -0
- package/dist/providers/shared/hook-config.d.ts +94 -0
- package/dist/providers/shared/hook-config.d.ts.map +1 -0
- package/package.json +5 -5
- package/src/providers/claude-code/install.ts +29 -1
- package/src/providers/claude-code/paths.ts +9 -131
- package/src/providers/codex/install.ts +27 -3
- package/src/providers/kimi/install.ts +15 -0
- package/src/providers/opencode/install.ts +24 -1
- package/src/providers/shared/__tests__/heavy-command-hook-install.test.ts +621 -0
- package/src/providers/shared/heavy-command-hook-install.ts +562 -0
- package/src/providers/shared/hook-config.ts +145 -0
|
@@ -4,10 +4,13 @@
|
|
|
4
4
|
* Handles CLEO installation into Claude Code environments:
|
|
5
5
|
* - Ensures CLAUDE.md has CLEO @-references
|
|
6
6
|
* - Manages plugin registration in ~/.claude/settings.json
|
|
7
|
+
* - Installs the heavy-command `PreToolUse` hook in the PROJECT's
|
|
8
|
+
* `.claude/settings.local.json` (T12983)
|
|
7
9
|
*
|
|
8
10
|
* Migrated from src/core/install/claude-plugin.ts
|
|
9
11
|
*
|
|
10
12
|
* @task T5240
|
|
13
|
+
* @task T12983
|
|
11
14
|
*/
|
|
12
15
|
import type { AdapterInstallProvider, InstallOptions, InstallResult } from '@cleocode/contracts';
|
|
13
16
|
/**
|
|
@@ -17,6 +20,9 @@ import type { AdapterInstallProvider, InstallOptions, InstallResult } from '@cle
|
|
|
17
20
|
* 1. Ensuring CLAUDE.md contains @-references to CLEO instruction files
|
|
18
21
|
* 2. Installing adapter-provided commands to .claude/commands/
|
|
19
22
|
* 3. Registering the brain observation plugin in ~/.claude/settings.json
|
|
23
|
+
* 4. Installing PreCompact hook templates
|
|
24
|
+
* 5. Installing the heavy-command `PreToolUse` hook in the project's
|
|
25
|
+
* `.claude/settings.local.json`, when `options.heavyCommandHook` is set
|
|
20
26
|
*
|
|
21
27
|
* @remarks
|
|
22
28
|
* Installation is idempotent -- running install multiple times on the same
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"install.d.ts","sourceRoot":"","sources":["../../../src/providers/claude-code/install.ts"],"names":[],"mappings":"AAAA
|
|
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"}
|
|
@@ -47,82 +47,5 @@ export declare class ClaudeCodePathProvider implements AdapterPathProvider {
|
|
|
47
47
|
* ```
|
|
48
48
|
*/
|
|
49
49
|
export declare function claudeSettingsPath(): string;
|
|
50
|
-
|
|
51
|
-
* Whether a parsed settings value is a plain JSON object.
|
|
52
|
-
*
|
|
53
|
-
* @param value - Any parsed JSON value
|
|
54
|
-
* @returns `true` for a non-null, non-array object
|
|
55
|
-
*
|
|
56
|
-
* @example
|
|
57
|
-
* ```typescript
|
|
58
|
-
* isPlainObject(settings.enabledPlugins);
|
|
59
|
-
* ```
|
|
60
|
-
*/
|
|
61
|
-
export declare function isPlainObject(value: unknown): value is Record<string, unknown>;
|
|
62
|
-
/**
|
|
63
|
-
* Whether a settings.json hook entry carries a CLEO-owned command.
|
|
64
|
-
*
|
|
65
|
-
* @param entry - One element of a `hooks.<Event>` array
|
|
66
|
-
* @param commandIncludes - Extra substring the CLEO command must contain
|
|
67
|
-
* @returns `true` when one of the entry's commands has the `# cleo-hook` marker
|
|
68
|
-
*
|
|
69
|
-
* @example
|
|
70
|
-
* ```typescript
|
|
71
|
-
* isCleoHookEntry({ hooks: [{ type: "command", command: "x # cleo-hook" }] }); // true
|
|
72
|
-
* ```
|
|
73
|
-
*/
|
|
74
|
-
export declare function isCleoHookEntry(entry: unknown, commandIncludes?: string): boolean;
|
|
75
|
-
/**
|
|
76
|
-
* Whether a `hooks.<Event>` value holds a CLEO-owned entry.
|
|
77
|
-
*
|
|
78
|
-
* @param entries - The event's value (non-arrays hold none)
|
|
79
|
-
* @param commandIncludes - Extra substring the CLEO command must contain
|
|
80
|
-
* @returns `true` when a CLEO entry is present
|
|
81
|
-
*
|
|
82
|
-
* @example
|
|
83
|
-
* ```typescript
|
|
84
|
-
* hasCleoHook(hookMap(settings).Stop);
|
|
85
|
-
* ```
|
|
86
|
-
*/
|
|
87
|
-
export declare function hasCleoHook(entries: unknown, commandIncludes?: string): boolean;
|
|
88
|
-
/**
|
|
89
|
-
* Return the settings object's `hooks` map, creating an empty one if absent.
|
|
90
|
-
*
|
|
91
|
-
* @param settings - Parsed settings.json
|
|
92
|
-
* @returns The live `hooks` object (mutations apply to `settings`)
|
|
93
|
-
* @throws Error when `hooks` exists but is not an object — the caller's write
|
|
94
|
-
* is aborted and the file left untouched
|
|
95
|
-
*
|
|
96
|
-
* @example
|
|
97
|
-
* ```typescript
|
|
98
|
-
* const hooks = hookMap(settings);
|
|
99
|
-
* ```
|
|
100
|
-
*/
|
|
101
|
-
export declare function hookMap(settings: Record<string, unknown>): Record<string, unknown>;
|
|
102
|
-
/**
|
|
103
|
-
* Append a hook entry to `hooks[event]`, preserving existing entries.
|
|
104
|
-
*
|
|
105
|
-
* @param hooks - The settings `hooks` map
|
|
106
|
-
* @param event - Native event name (e.g. `Stop`, `PreCompact`)
|
|
107
|
-
* @param entry - Entry to append
|
|
108
|
-
* @throws Error when `hooks[event]` exists but is not an array
|
|
109
|
-
*
|
|
110
|
-
* @example
|
|
111
|
-
* ```typescript
|
|
112
|
-
* appendHookEntry(hookMap(settings), "Stop", { matcher: "", hooks: [] });
|
|
113
|
-
* ```
|
|
114
|
-
*/
|
|
115
|
-
export declare function appendHookEntry(hooks: Record<string, unknown>, event: string, entry: Record<string, unknown>): void;
|
|
116
|
-
/**
|
|
117
|
-
* Remove every CLEO-owned entry from every event array in `hooks`.
|
|
118
|
-
*
|
|
119
|
-
* @param hooks - The settings `hooks` map
|
|
120
|
-
* @returns Whether anything was removed
|
|
121
|
-
*
|
|
122
|
-
* @example
|
|
123
|
-
* ```typescript
|
|
124
|
-
* const changed = removeCleoHookEntries(hookMap(settings));
|
|
125
|
-
* ```
|
|
126
|
-
*/
|
|
127
|
-
export declare function removeCleoHookEntries(hooks: Record<string, unknown>): boolean;
|
|
50
|
+
export { appendHookEntry, CLEO_HOOK_MARKER, hasCleoHook, hookMap, isCleoHookEntry, isPlainObject, removeCleoHookEntries, } from '../shared/hook-config.js';
|
|
128
51
|
//# 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;
|
|
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"}
|
|
@@ -3,9 +3,12 @@
|
|
|
3
3
|
*
|
|
4
4
|
* Handles CLEO installation into Codex CLI environments:
|
|
5
5
|
* - Ensures AGENTS.md has CLEO @-references via CAAMP
|
|
6
|
+
* - Installs the heavy-command `PreToolUse` hook in the project's
|
|
7
|
+
* `.codex/hooks.json` (T12983)
|
|
6
8
|
*
|
|
7
9
|
* @task T162
|
|
8
10
|
* @task T9019
|
|
11
|
+
* @task T12983
|
|
9
12
|
* @epic T134
|
|
10
13
|
*/
|
|
11
14
|
import type { AdapterInstallProvider, InstallOptions, InstallResult } from '@cleocode/contracts';
|
|
@@ -15,11 +18,14 @@ import type { AdapterInstallProvider, InstallOptions, InstallResult } from '@cle
|
|
|
15
18
|
* Manages CLEO's integration with Codex CLI by:
|
|
16
19
|
* 1. Ensuring AGENTS.md contains @-references to CLEO instruction files
|
|
17
20
|
* (delegated to CAAMP's canonical {@link ensureProviderInstructionFile}).
|
|
21
|
+
* 2. Installing the heavy-command `PreToolUse` hook (matcher `Bash`) in the
|
|
22
|
+
* project's `.codex/hooks.json`, when `options.heavyCommandHook` is set.
|
|
23
|
+
* Codex asks the user to review and trust a new project hook (`/hooks`)
|
|
24
|
+
* before it runs it.
|
|
18
25
|
*
|
|
19
26
|
* @remarks
|
|
20
27
|
* Installation is idempotent — running install multiple times on the same
|
|
21
|
-
* project produces the same result.
|
|
22
|
-
* does not have an MCP or plugin registration mechanism.
|
|
28
|
+
* project produces the same result.
|
|
23
29
|
*
|
|
24
30
|
* @task T162
|
|
25
31
|
* @epic T134
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"install.d.ts","sourceRoot":"","sources":["../../../src/providers/codex/install.ts"],"names":[],"mappings":"AAAA
|
|
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;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"}
|
|
@@ -21,6 +21,21 @@ import type { AdapterInstallProvider, InstallOptions, InstallResult } from '@cle
|
|
|
21
21
|
* project produces the same result. Only AGENTS.md is managed; Kimi does
|
|
22
22
|
* not have an MCP or plugin registration mechanism.
|
|
23
23
|
*
|
|
24
|
+
* The heavy-command hook (T12983) is NOT installed for Kimi: Kimi reads
|
|
25
|
+
* `[[hooks]]` only from the user-global `~/.kimi/config.toml` (no project
|
|
26
|
+
* config, and CLEO installs this hook per project only), and its
|
|
27
|
+
* `PreToolUse` answer cannot rewrite the command. `cleo hook heavy-command
|
|
28
|
+
* --provider kimi` speaks Kimi's protocol (deny with the governed command as
|
|
29
|
+
* the reason) for a manual entry:
|
|
30
|
+
*
|
|
31
|
+
* ```toml
|
|
32
|
+
* [[hooks]]
|
|
33
|
+
* event = "PreToolUse"
|
|
34
|
+
* matcher = "Shell"
|
|
35
|
+
* command = "cleo hook heavy-command --provider kimi"
|
|
36
|
+
* timeout = 20
|
|
37
|
+
* ```
|
|
38
|
+
*
|
|
24
39
|
* @task T163
|
|
25
40
|
* @epic T134
|
|
26
41
|
*/
|
|
@@ -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
|
|
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"}
|
|
@@ -4,10 +4,12 @@
|
|
|
4
4
|
* Handles CLEO installation into OpenCode environments:
|
|
5
5
|
* - Ensures AGENTS.md has CLEO @-references via CAAMP
|
|
6
6
|
* - Installs PreCompact hook shell shims + a JS plugin wrapper (T1013)
|
|
7
|
+
* - Installs the heavy-command `tool.execute.before` plugin (T12983)
|
|
7
8
|
*
|
|
8
9
|
* @task T5240
|
|
9
10
|
* @task T1013
|
|
10
11
|
* @task T9019
|
|
12
|
+
* @task T12983
|
|
11
13
|
*/
|
|
12
14
|
import type { AdapterInstallProvider, InstallOptions, InstallResult } from '@cleocode/contracts';
|
|
13
15
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"install.d.ts","sourceRoot":"","sources":["../../../src/providers/opencode/install.ts"],"names":[],"mappings":"AAAA
|
|
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"}
|
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Install CLEO's heavy-command hook into a project's provider configs (T12983).
|
|
3
|
+
*
|
|
4
|
+
* The hook (`cleo hook heavy-command`, in `@cleocode/cleo`) runs before every
|
|
5
|
+
* shell command an agent issues and routes heavy work (tests, builds,
|
|
6
|
+
* typechecks, installs) through `cleo run`, the machine-wide resource budget.
|
|
7
|
+
* Delivery per provider:
|
|
8
|
+
*
|
|
9
|
+
* - Claude Code: a `PreToolUse` / `Bash` hook in
|
|
10
|
+
* `<project>/.claude/settings.local.json`: project-level but per machine,
|
|
11
|
+
* which fits a per-machine budget. When git does not ignore that file yet,
|
|
12
|
+
* a marked block in the repository's `info/exclude` keeps it out of git.
|
|
13
|
+
* - Codex: the same hook in `<project>/.codex/hooks.json` (Codex asks the
|
|
14
|
+
* user to review and trust a new project hook in `/hooks` before it runs).
|
|
15
|
+
* - opencode: a `tool.execute.before` / `tool.execute.after` plugin at
|
|
16
|
+
* `<project>/.opencode/plugins/cleo-heavy-command.js`.
|
|
17
|
+
* - Kimi: not installed. Kimi reads hooks only from the global
|
|
18
|
+
* `~/.kimi/config.toml` and cannot rewrite input; `cleo hook heavy-command
|
|
19
|
+
* --provider kimi` speaks its protocol for a manual `[[hooks]]` entry.
|
|
20
|
+
*
|
|
21
|
+
* Project-level only: CLEO never writes this hook into a user-global config,
|
|
22
|
+
* and never into the home directory's provider configs. The hook command
|
|
23
|
+
* decides cheaply before it starts `cleo` (a tool name must appear as a whole
|
|
24
|
+
* word), guards against a missing or older `cleo`, and always exits 0. Only
|
|
25
|
+
* CLEO's own hook object is ever added, replaced or removed: a user hook that
|
|
26
|
+
* shares its matcher group stays. Mode `off` removes it again.
|
|
27
|
+
*
|
|
28
|
+
* @task T12983
|
|
29
|
+
* @epic T12978
|
|
30
|
+
*/
|
|
31
|
+
import type { HeavyCommandHookMode } from '@cleocode/contracts';
|
|
32
|
+
/** Identifies the heavy-command hook among CLEO's hook commands. */
|
|
33
|
+
export declare const HEAVY_COMMAND_HOOK_ID = "cleo hook heavy-command";
|
|
34
|
+
/** Seconds a harness waits for the hook before it runs the command unchanged. */
|
|
35
|
+
export declare const HEAVY_COMMAND_HOOK_TIMEOUT_SEC = 20;
|
|
36
|
+
/** File name of the generated opencode plugin. */
|
|
37
|
+
export declare const OPENCODE_HEAVY_COMMAND_PLUGIN = "cleo-heavy-command.js";
|
|
38
|
+
/**
|
|
39
|
+
* Tool names that send a shell call on to `cleo hook`: a superset of the
|
|
40
|
+
* command words `run-class` treats as heavy (test runners, compilers,
|
|
41
|
+
* bundlers, linters, package managers and their exec runners, cargo, go).
|
|
42
|
+
* Matched as whole words only, so `cat test-notes.md` never starts `cleo`;
|
|
43
|
+
* recognition proper stays in `run-class` inside `cleo hook`.
|
|
44
|
+
*/
|
|
45
|
+
export declare const HEAVY_TOOL_WORDS: readonly string[];
|
|
46
|
+
/**
|
|
47
|
+
* What a sync did to one config file. `skipped`: the project is the user's
|
|
48
|
+
* home directory, whose provider configs are the user-global ones.
|
|
49
|
+
*/
|
|
50
|
+
export type HeavyHookSyncResult = 'installed' | 'updated' | 'removed' | 'unchanged' | 'skipped';
|
|
51
|
+
/**
|
|
52
|
+
* Whether `projectDir` is the user's home directory. There,
|
|
53
|
+
* `<home>/.claude/settings.local.json`, `<home>/.codex/hooks.json` and
|
|
54
|
+
* `<home>/.opencode/` act as user-global configs, and CLEO installs this
|
|
55
|
+
* hook per project only, so the installers skip it.
|
|
56
|
+
*
|
|
57
|
+
* @param projectDir - the project root an installer was given.
|
|
58
|
+
* @param home - the home directory (injectable for tests).
|
|
59
|
+
*/
|
|
60
|
+
export declare function isUserHomeDir(projectDir: string, home?: string): boolean;
|
|
61
|
+
/**
|
|
62
|
+
* The context line an older CLEO gets: its `cleo` has no `cleo hook` (and so
|
|
63
|
+
* no `cleo run`), so the command runs unchanged and ungoverned. A
|
|
64
|
+
* Claude-style `PreToolUse` answer; no single quotes (it is inlined into a
|
|
65
|
+
* single-quoted `sh` word).
|
|
66
|
+
*/
|
|
67
|
+
export declare const OLDER_CLEO_HOOK_ANSWER: string;
|
|
68
|
+
/** File-name prefix of the "this cleo has no `cleo hook`" markers in `$TMPDIR`. */
|
|
69
|
+
export declare const OLDER_CLEO_MARKER_PREFIX = "cleo-hook-unsupported-";
|
|
70
|
+
/**
|
|
71
|
+
* Delete this user's older-CLEO markers, so a CLEO that has just installed the
|
|
72
|
+
* hook is asked again at once instead of after the marker lapses.
|
|
73
|
+
*
|
|
74
|
+
* @param dir - the directory the hook command keeps markers in
|
|
75
|
+
* (`$XDG_RUNTIME_DIR`, else `$TMPDIR`).
|
|
76
|
+
* @returns how many markers were removed.
|
|
77
|
+
*/
|
|
78
|
+
export declare function clearOlderCleoMarkers(dir?: string): number;
|
|
79
|
+
/**
|
|
80
|
+
* The hook command line for a JSON hook config, ending in the `# cleo-hook`
|
|
81
|
+
* marker. Claude Code runs hook commands through `sh -c`, so its line is the
|
|
82
|
+
* guard script itself. Codex runs them through the user's login shell
|
|
83
|
+
* (`$SHELL -lc`, which may be fish), so its line hands the script to
|
|
84
|
+
* `/bin/sh -c` as one quoted word.
|
|
85
|
+
*
|
|
86
|
+
* @param provider - the harness protocol to answer in.
|
|
87
|
+
* @returns the command line for the provider's config.
|
|
88
|
+
*
|
|
89
|
+
* @example
|
|
90
|
+
* ```ts
|
|
91
|
+
* heavyCommandHookCommand('claude-code');
|
|
92
|
+
* // command -v cleo >/dev/null 2>&1 || exit 0; in="$(cat)"; set -f; …; exit 0 # cleo-hook
|
|
93
|
+
* heavyCommandHookCommand('codex');
|
|
94
|
+
* // /bin/sh -c 'command -v cleo >/dev/null 2>&1 || exit 0; …' # cleo-hook
|
|
95
|
+
* ```
|
|
96
|
+
*/
|
|
97
|
+
export declare function heavyCommandHookCommand(provider: 'claude-code' | 'codex'): string;
|
|
98
|
+
/**
|
|
99
|
+
* CLEO's hook object (one element of a matcher group's `hooks` array).
|
|
100
|
+
*
|
|
101
|
+
* @param provider - `claude-code` or `codex`.
|
|
102
|
+
*/
|
|
103
|
+
export declare function heavyCommandHookObject(provider: 'claude-code' | 'codex'): Record<string, unknown>;
|
|
104
|
+
/**
|
|
105
|
+
* The `hooks.PreToolUse` matcher group CLEO adds when none of the user's
|
|
106
|
+
* groups holds its hook yet (Claude Code and Codex both match `Bash`).
|
|
107
|
+
*
|
|
108
|
+
* @param provider - `claude-code` or `codex`.
|
|
109
|
+
*/
|
|
110
|
+
export declare function heavyCommandHookEntry(provider: 'claude-code' | 'codex'): Record<string, unknown>;
|
|
111
|
+
/**
|
|
112
|
+
* Add, refresh or (mode `off`) remove CLEO's heavy-command hook in a JSON hook
|
|
113
|
+
* config, through CAAMP's locked atomic writer. Only CLEO's own hook object is
|
|
114
|
+
* touched; a malformed file throws and is left as it is.
|
|
115
|
+
*
|
|
116
|
+
* @param configPath - the config file (created when missing, unless `off`).
|
|
117
|
+
* @param provider - `claude-code` or `codex`.
|
|
118
|
+
* @param mode - the resolved hook mode.
|
|
119
|
+
* @returns what changed.
|
|
120
|
+
*/
|
|
121
|
+
export declare function syncJsonHeavyCommandHook(configPath: string, provider: 'claude-code' | 'codex', mode: HeavyCommandHookMode): Promise<HeavyHookSyncResult>;
|
|
122
|
+
/** First line of the `info/exclude` block CLEO adds (and alone may remove). */
|
|
123
|
+
export declare const LOCAL_SETTINGS_EXCLUDE_MARKER = "# cleo-hook: keep the per-machine heavy-command hook settings out of git (T12983)";
|
|
124
|
+
/**
|
|
125
|
+
* Keep `.claude/settings.local.json` out of git when nothing ignores it yet
|
|
126
|
+
* (Claude Code ignores the file only when it creates it itself). Adds a marked
|
|
127
|
+
* block naming this project's file to the repository's `info/exclude`, never
|
|
128
|
+
* to a tracked `.gitignore`. Keyed on the exact path line, so a second CLEO
|
|
129
|
+
* project in a subdirectory of the same repository gets its own line.
|
|
130
|
+
* Idempotent; does nothing outside a git work tree.
|
|
131
|
+
*
|
|
132
|
+
* @param projectDir - the project root.
|
|
133
|
+
* @returns whether a block was added.
|
|
134
|
+
*/
|
|
135
|
+
export declare function excludeLocalSettingsFromGit(projectDir: string): boolean;
|
|
136
|
+
/**
|
|
137
|
+
* Remove the block {@link excludeLocalSettingsFromGit} added for this
|
|
138
|
+
* project, and only that: the exact path line and the marker right above it.
|
|
139
|
+
*
|
|
140
|
+
* @param projectDir - the project root.
|
|
141
|
+
* @returns whether a block was removed.
|
|
142
|
+
*/
|
|
143
|
+
export declare function unexcludeLocalSettingsFromGit(projectDir: string): boolean;
|
|
144
|
+
/**
|
|
145
|
+
* Claude Code: sync the hook in `<project>/.claude/settings.local.json`, keep
|
|
146
|
+
* that file out of git, and remove a hook an earlier build put in the shared
|
|
147
|
+
* `<project>/.claude/settings.json`.
|
|
148
|
+
*
|
|
149
|
+
* @param projectDir - the project root.
|
|
150
|
+
* @param mode - the resolved hook mode.
|
|
151
|
+
* @returns what changed in `settings.local.json`.
|
|
152
|
+
*/
|
|
153
|
+
export declare function syncClaudeCodeHeavyCommandHook(projectDir: string, mode: HeavyCommandHookMode): Promise<HeavyHookSyncResult>;
|
|
154
|
+
/**
|
|
155
|
+
* Source of the opencode plugin. opencode runs plugins in-process:
|
|
156
|
+
* `tool.execute.before` may replace `output.args`, and
|
|
157
|
+
* `tool.execute.after` may extend the tool's output. The plugin skips calls
|
|
158
|
+
* with no {@link HEAVY_TOOL_WORDS} word, asks
|
|
159
|
+
* `cleo hook heavy-command --provider opencode` for the rest, applies a
|
|
160
|
+
* rewrite and its longer timeout, and appends the hook's context line to the
|
|
161
|
+
* tool's output (opencode has no other channel back to the agent).
|
|
162
|
+
*/
|
|
163
|
+
export declare function opencodeHeavyCommandPluginSource(): string;
|
|
164
|
+
/**
|
|
165
|
+
* Write (or, mode `off`, delete) the opencode plugin in
|
|
166
|
+
* `<projectDir>/.opencode/plugins/`. Rewritten only when its content changed.
|
|
167
|
+
*
|
|
168
|
+
* @param projectDir - the project root.
|
|
169
|
+
* @param mode - the resolved hook mode.
|
|
170
|
+
* @returns what changed.
|
|
171
|
+
*/
|
|
172
|
+
export declare function syncOpencodeHeavyCommandPlugin(projectDir: string, mode: HeavyCommandHookMode): HeavyHookSyncResult;
|
|
173
|
+
//# sourceMappingURL=heavy-command-hook-install.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"heavy-command-hook-install.d.ts","sourceRoot":"","sources":["../../../src/providers/shared/heavy-command-hook-install.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AAeH,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,qBAAqB,CAAC;AAGhE,oEAAoE;AACpE,eAAO,MAAM,qBAAqB,4BAA4B,CAAC;AAE/D,iFAAiF;AACjF,eAAO,MAAM,8BAA8B,KAAK,CAAC;AAEjD,kDAAkD;AAClD,eAAO,MAAM,6BAA6B,0BAA0B,CAAC;AAErE;;;;;;GAMG;AACH,eAAO,MAAM,gBAAgB,EAAE,SAAS,MAAM,EA+B5C,CAAC;AAEH;;;GAGG;AACH,MAAM,MAAM,mBAAmB,GAAG,WAAW,GAAG,SAAS,GAAG,SAAS,GAAG,WAAW,GAAG,SAAS,CAAC;AAUhG;;;;;;;;GAQG;AACH,wBAAgB,aAAa,CAAC,UAAU,EAAE,MAAM,EAAE,IAAI,GAAE,MAAkB,GAAG,OAAO,CAEnF;AAED;;;;;GAKG;AACH,eAAO,MAAM,sBAAsB,QAOjC,CAAC;AAEH,mFAAmF;AACnF,eAAO,MAAM,wBAAwB,2BAA2B,CAAC;AAEjE;;;;;;;GAOG;AACH,wBAAgB,qBAAqB,CACnC,GAAG,GAAE,MAAgD,GACpD,MAAM,CAkBR;AAqDD;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,uBAAuB,CAAC,QAAQ,EAAE,aAAa,GAAG,OAAO,GAAG,MAAM,CAIjF;AAED;;;;GAIG;AACH,wBAAgB,sBAAsB,CAAC,QAAQ,EAAE,aAAa,GAAG,OAAO,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAMjG;AAED;;;;;GAKG;AACH,wBAAgB,qBAAqB,CAAC,QAAQ,EAAE,aAAa,GAAG,OAAO,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAEhG;AA4DD;;;;;;;;;GASG;AACH,wBAAsB,wBAAwB,CAC5C,UAAU,EAAE,MAAM,EAClB,QAAQ,EAAE,aAAa,GAAG,OAAO,EACjC,IAAI,EAAE,oBAAoB,GACzB,OAAO,CAAC,mBAAmB,CAAC,CA4B9B;AAKD,+EAA+E;AAC/E,eAAO,MAAM,6BAA6B,sFAC2C,CAAC;AA6BtF;;;;;;;;;;GAUG;AACH,wBAAgB,2BAA2B,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAWvE;AAED;;;;;;GAMG;AACH,wBAAgB,6BAA6B,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CASzE;AAED;;;;;;;;GAQG;AACH,wBAAsB,8BAA8B,CAClD,UAAU,EAAE,MAAM,EAClB,IAAI,EAAE,oBAAoB,GACzB,OAAO,CAAC,mBAAmB,CAAC,CAc9B;AAED;;;;;;;;GAQG;AACH,wBAAgB,gCAAgC,IAAI,MAAM,CAmDzD;AAED;;;;;;;GAOG;AACH,wBAAgB,8BAA8B,CAC5C,UAAU,EAAE,MAAM,EAClB,IAAI,EAAE,oBAAoB,GACzB,mBAAmB,CAarB"}
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Helpers for JSON hook configs shaped like Claude Code's `settings.json`
|
|
3
|
+
* `hooks` map: `{ "<Event>": [{ "matcher": "...", "hooks": [{ "type":
|
|
4
|
+
* "command", "command": "..." }] }] }`. Codex's `hooks.json` uses the same
|
|
5
|
+
* shape. Every command CLEO owns carries the `# cleo-hook` marker so CLEO can
|
|
6
|
+
* find (and remove) its own entries without touching user-authored ones.
|
|
7
|
+
*
|
|
8
|
+
* Moved from `claude-code/paths.ts` (T12385) so the Codex installer can share
|
|
9
|
+
* them (T12983); `claude-code/paths.ts` re-exports them.
|
|
10
|
+
*
|
|
11
|
+
* @task T12385
|
|
12
|
+
* @task T12983
|
|
13
|
+
*/
|
|
14
|
+
/** Marker CLEO puts in every hook command it owns. */
|
|
15
|
+
export declare const CLEO_HOOK_MARKER = "# cleo-hook";
|
|
16
|
+
/**
|
|
17
|
+
* Whether a parsed settings value is a plain JSON object.
|
|
18
|
+
*
|
|
19
|
+
* @param value - Any parsed JSON value
|
|
20
|
+
* @returns `true` for a non-null, non-array object
|
|
21
|
+
*
|
|
22
|
+
* @example
|
|
23
|
+
* ```typescript
|
|
24
|
+
* isPlainObject(settings.enabledPlugins);
|
|
25
|
+
* ```
|
|
26
|
+
*/
|
|
27
|
+
export declare function isPlainObject(value: unknown): value is Record<string, unknown>;
|
|
28
|
+
/**
|
|
29
|
+
* Whether a settings.json hook entry carries a CLEO-owned command.
|
|
30
|
+
*
|
|
31
|
+
* @param entry - One element of a `hooks.<Event>` array
|
|
32
|
+
* @param commandIncludes - Extra substring the CLEO command must contain
|
|
33
|
+
* @returns `true` when one of the entry's commands has the `# cleo-hook` marker
|
|
34
|
+
*
|
|
35
|
+
* @example
|
|
36
|
+
* ```typescript
|
|
37
|
+
* isCleoHookEntry({ hooks: [{ type: "command", command: "x # cleo-hook" }] }); // true
|
|
38
|
+
* ```
|
|
39
|
+
*/
|
|
40
|
+
export declare function isCleoHookEntry(entry: unknown, commandIncludes?: string): boolean;
|
|
41
|
+
/**
|
|
42
|
+
* Whether a `hooks.<Event>` value holds a CLEO-owned entry.
|
|
43
|
+
*
|
|
44
|
+
* @param entries - The event's value (non-arrays hold none)
|
|
45
|
+
* @param commandIncludes - Extra substring the CLEO command must contain
|
|
46
|
+
* @returns `true` when a CLEO entry is present
|
|
47
|
+
*
|
|
48
|
+
* @example
|
|
49
|
+
* ```typescript
|
|
50
|
+
* hasCleoHook(hookMap(settings).Stop);
|
|
51
|
+
* ```
|
|
52
|
+
*/
|
|
53
|
+
export declare function hasCleoHook(entries: unknown, commandIncludes?: string): boolean;
|
|
54
|
+
/**
|
|
55
|
+
* Return the settings object's `hooks` map, creating an empty one if absent.
|
|
56
|
+
*
|
|
57
|
+
* @param settings - Parsed settings.json
|
|
58
|
+
* @returns The live `hooks` object (mutations apply to `settings`)
|
|
59
|
+
* @throws Error when `hooks` exists but is not an object — the caller's write
|
|
60
|
+
* is aborted and the file left untouched
|
|
61
|
+
*
|
|
62
|
+
* @example
|
|
63
|
+
* ```typescript
|
|
64
|
+
* const hooks = hookMap(settings);
|
|
65
|
+
* ```
|
|
66
|
+
*/
|
|
67
|
+
export declare function hookMap(settings: Record<string, unknown>): Record<string, unknown>;
|
|
68
|
+
/**
|
|
69
|
+
* Append a hook entry to `hooks[event]`, preserving existing entries.
|
|
70
|
+
*
|
|
71
|
+
* @param hooks - The settings `hooks` map
|
|
72
|
+
* @param event - Native event name (e.g. `Stop`, `PreCompact`)
|
|
73
|
+
* @param entry - Entry to append
|
|
74
|
+
* @throws Error when `hooks[event]` exists but is not an array
|
|
75
|
+
*
|
|
76
|
+
* @example
|
|
77
|
+
* ```typescript
|
|
78
|
+
* appendHookEntry(hookMap(settings), "Stop", { matcher: "", hooks: [] });
|
|
79
|
+
* ```
|
|
80
|
+
*/
|
|
81
|
+
export declare function appendHookEntry(hooks: Record<string, unknown>, event: string, entry: Record<string, unknown>): void;
|
|
82
|
+
/**
|
|
83
|
+
* Remove every CLEO-owned entry from every event array in `hooks`.
|
|
84
|
+
*
|
|
85
|
+
* @param hooks - The settings `hooks` map
|
|
86
|
+
* @returns Whether anything was removed
|
|
87
|
+
*
|
|
88
|
+
* @example
|
|
89
|
+
* ```typescript
|
|
90
|
+
* const changed = removeCleoHookEntries(hookMap(settings));
|
|
91
|
+
* ```
|
|
92
|
+
*/
|
|
93
|
+
export declare function removeCleoHookEntries(hooks: Record<string, unknown>): boolean;
|
|
94
|
+
//# sourceMappingURL=hook-config.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hook-config.d.ts","sourceRoot":"","sources":["../../../src/providers/shared/hook-config.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,sDAAsD;AACtD,eAAO,MAAM,gBAAgB,gBAAgB,CAAC;AAE9C;;;;;;;;;;GAUG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAE9E;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,eAAe,CAAC,KAAK,EAAE,OAAO,EAAE,eAAe,CAAC,EAAE,MAAM,GAAG,OAAO,CASjF;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,WAAW,CAAC,OAAO,EAAE,OAAO,EAAE,eAAe,CAAC,EAAE,MAAM,GAAG,OAAO,CAE/E;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,OAAO,CAAC,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAWlF;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,eAAe,CAC7B,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC9B,KAAK,EAAE,MAAM,EACb,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC7B,IAAI,CAMN;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO,CAW7E"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cleocode/adapters",
|
|
3
|
-
"version": "2026.10.
|
|
3
|
+
"version": "2026.10.2",
|
|
4
4
|
"description": "Unified provider adapters for CLEO (Claude Code, OpenCode, Cursor)",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -15,9 +15,9 @@
|
|
|
15
15
|
"@ai-sdk/anthropic": "^3.0.69",
|
|
16
16
|
"@ai-sdk/openai": "^2.0.53",
|
|
17
17
|
"ai": "^6.0.168",
|
|
18
|
-
"@cleocode/caamp": "2026.10.
|
|
19
|
-
"@cleocode/
|
|
20
|
-
"@cleocode/
|
|
18
|
+
"@cleocode/caamp": "2026.10.2",
|
|
19
|
+
"@cleocode/paths": "2026.10.2",
|
|
20
|
+
"@cleocode/contracts": "2026.10.2"
|
|
21
21
|
},
|
|
22
22
|
"license": "MIT",
|
|
23
23
|
"engines": {
|
|
@@ -30,7 +30,7 @@
|
|
|
30
30
|
"devDependencies": {
|
|
31
31
|
"@types/node": "^24.3.0",
|
|
32
32
|
"vitest": "^4.1.4",
|
|
33
|
-
"@cleocode/playbooks": "2026.10.
|
|
33
|
+
"@cleocode/playbooks": "2026.10.2"
|
|
34
34
|
},
|
|
35
35
|
"repository": {
|
|
36
36
|
"type": "git",
|
|
@@ -4,18 +4,25 @@
|
|
|
4
4
|
* Handles CLEO installation into Claude Code environments:
|
|
5
5
|
* - Ensures CLAUDE.md has CLEO @-references
|
|
6
6
|
* - Manages plugin registration in ~/.claude/settings.json
|
|
7
|
+
* - Installs the heavy-command `PreToolUse` hook in the PROJECT's
|
|
8
|
+
* `.claude/settings.local.json` (T12983)
|
|
7
9
|
*
|
|
8
10
|
* Migrated from src/core/install/claude-plugin.ts
|
|
9
11
|
*
|
|
10
12
|
* @task T5240
|
|
13
|
+
* @task T12983
|
|
11
14
|
*/
|
|
12
15
|
|
|
13
16
|
import { copyFileSync, existsSync, mkdirSync, readdirSync, readFileSync } from 'node:fs';
|
|
14
17
|
import { homedir } from 'node:os';
|
|
15
|
-
import { dirname, join } from 'node:path';
|
|
18
|
+
import { dirname, join, resolve } from 'node:path';
|
|
16
19
|
import { fileURLToPath } from 'node:url';
|
|
17
20
|
import { ensureProviderInstructionFile, updateJsonConfigFile } from '@cleocode/caamp';
|
|
18
21
|
import type { AdapterInstallProvider, InstallOptions, InstallResult } from '@cleocode/contracts';
|
|
22
|
+
import {
|
|
23
|
+
isUserHomeDir,
|
|
24
|
+
syncClaudeCodeHeavyCommandHook,
|
|
25
|
+
} from '../shared/heavy-command-hook-install.js';
|
|
19
26
|
import {
|
|
20
27
|
type InstallHookTemplatesResult,
|
|
21
28
|
installProviderHookTemplates,
|
|
@@ -47,6 +54,9 @@ function getAdapterCommandsDir(): string {
|
|
|
47
54
|
* 1. Ensuring CLAUDE.md contains @-references to CLEO instruction files
|
|
48
55
|
* 2. Installing adapter-provided commands to .claude/commands/
|
|
49
56
|
* 3. Registering the brain observation plugin in ~/.claude/settings.json
|
|
57
|
+
* 4. Installing PreCompact hook templates
|
|
58
|
+
* 5. Installing the heavy-command `PreToolUse` hook in the project's
|
|
59
|
+
* `.claude/settings.local.json`, when `options.heavyCommandHook` is set
|
|
50
60
|
*
|
|
51
61
|
* @remarks
|
|
52
62
|
* Installation is idempotent -- running install multiple times on the same
|
|
@@ -105,6 +115,24 @@ export class ClaudeCodeInstallProvider implements AdapterInstallProvider {
|
|
|
105
115
|
settingsErrors.push(err instanceof Error ? err.message : String(err));
|
|
106
116
|
}
|
|
107
117
|
|
|
118
|
+
// Step 5 (T12983): route heavy shell commands through `cleo run`.
|
|
119
|
+
// Project-level settings only; the user's ~/.claude is never touched.
|
|
120
|
+
if (options.heavyCommandHook !== undefined) {
|
|
121
|
+
const projectSettings = join(projectDir, '.claude', 'settings.json');
|
|
122
|
+
if (isUserHomeDir(projectDir) || resolve(projectSettings) === resolve(claudeSettingsPath())) {
|
|
123
|
+
details.heavyCommandHook = 'skipped';
|
|
124
|
+
} else {
|
|
125
|
+
try {
|
|
126
|
+
details.heavyCommandHook = await syncClaudeCodeHeavyCommandHook(
|
|
127
|
+
projectDir,
|
|
128
|
+
options.heavyCommandHook,
|
|
129
|
+
);
|
|
130
|
+
} catch (err) {
|
|
131
|
+
settingsErrors.push(err instanceof Error ? err.message : String(err));
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
|
|
108
136
|
if (settingsErrors.length > 0) {
|
|
109
137
|
details.settingsErrors = settingsErrors;
|
|
110
138
|
}
|