ctx-cc 4.1.2 → 4.1.3
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 +4 -4
- package/hooks/pre-tool-use.js +4 -2
- package/package.json +3 -3
- package/plugin.json +1 -1
- package/src/install.js +37 -20
package/README.md
CHANGED
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
|
|
14
14
|
[](https://www.npmjs.com/package/ctx-cc)
|
|
15
15
|
[](https://opensource.org/licenses/MIT)
|
|
16
|
-
[](#testing)
|
|
17
17
|
[](#)
|
|
18
18
|
|
|
19
19
|
```bash
|
|
@@ -493,7 +493,7 @@ Options:
|
|
|
493
493
|
```bash
|
|
494
494
|
git clone https://github.com/jufjuf/CTX.git
|
|
495
495
|
cd CTX
|
|
496
|
-
npm test #
|
|
496
|
+
npm test # 154 tests, node:test runner
|
|
497
497
|
```
|
|
498
498
|
|
|
499
499
|
**Project structure:**
|
|
@@ -505,7 +505,7 @@ ctx-cc/
|
|
|
505
505
|
├── commands/ 26 slash command definitions (.md)
|
|
506
506
|
├── hooks/ 3 enforcement hook scripts (.js)
|
|
507
507
|
├── src/ 5 source modules (.js)
|
|
508
|
-
├── test/
|
|
508
|
+
├── test/ 9 test files (.test.js)
|
|
509
509
|
├── templates/ config.json, PRD.json, state templates
|
|
510
510
|
├── bin/ctx.js CLI entry point (installer only)
|
|
511
511
|
├── plugin.json Marketplace manifest
|
|
@@ -518,7 +518,7 @@ ctx-cc/
|
|
|
518
518
|
|
|
519
519
|
```bash
|
|
520
520
|
npm test
|
|
521
|
-
#
|
|
521
|
+
# 154 tests, 0 failures, ~1s
|
|
522
522
|
```
|
|
523
523
|
|
|
524
524
|
**Coverage:**
|
package/hooks/pre-tool-use.js
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
* Enforces TDD mode and capability restrictions.
|
|
6
6
|
* Installed to .claude/hooks/ctx-pre-tool-use.js
|
|
7
7
|
*
|
|
8
|
-
* Reads hook input from stdin (JSON with tool_name, tool_input,
|
|
8
|
+
* Reads hook input from stdin (JSON with tool_name, tool_input, agent_type).
|
|
9
9
|
* Exit 0 = allow, Exit 2 = block.
|
|
10
10
|
*/
|
|
11
11
|
|
|
@@ -28,7 +28,9 @@ try {
|
|
|
28
28
|
|
|
29
29
|
const toolName = input.tool_name || '';
|
|
30
30
|
const toolInput = input.tool_input || '';
|
|
31
|
-
|
|
31
|
+
// Claude Code identifies the spawning subagent as `agent_type` (e.g. "ctx-reviewer").
|
|
32
|
+
// Fall back to `agent_name` for forward/back compatibility across CLI versions.
|
|
33
|
+
const agentName = input.agent_type || input.agent_name || '';
|
|
32
34
|
|
|
33
35
|
// --- TDD Enforcement ---
|
|
34
36
|
if (toolName === 'Bash' && /git commit/.test(toolInput)) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ctx-cc",
|
|
3
|
-
"version": "4.1.
|
|
3
|
+
"version": "4.1.3",
|
|
4
4
|
"description": "CTX 4.0 — Intelligent workflow orchestration for Claude Code. 26 subagents, 7 skills, deterministic hooks. Phase-based lifecycle with autonomous execution.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"claude",
|
|
@@ -15,14 +15,14 @@
|
|
|
15
15
|
"license": "MIT",
|
|
16
16
|
"repository": {
|
|
17
17
|
"type": "git",
|
|
18
|
-
"url": "https://github.com/jufjuf/CTX.git"
|
|
18
|
+
"url": "git+https://github.com/jufjuf/CTX.git"
|
|
19
19
|
},
|
|
20
20
|
"homepage": "https://github.com/jufjuf/CTX",
|
|
21
21
|
"bugs": {
|
|
22
22
|
"url": "https://github.com/jufjuf/CTX/issues"
|
|
23
23
|
},
|
|
24
24
|
"bin": {
|
|
25
|
-
"ctx-cc": "
|
|
25
|
+
"ctx-cc": "bin/ctx.js"
|
|
26
26
|
},
|
|
27
27
|
"files": [
|
|
28
28
|
"bin/",
|
package/plugin.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ctx",
|
|
3
|
-
"version": "4.1.
|
|
3
|
+
"version": "4.1.3",
|
|
4
4
|
"description": "CTX — Intelligent workflow orchestration for Claude Code. Specialized agents, phase-based lifecycle, three-stage review gate with OpenAI Codex cross-model review, autonomous execution.",
|
|
5
5
|
"author": "jufjuf",
|
|
6
6
|
"license": "MIT",
|
package/src/install.js
CHANGED
|
@@ -212,7 +212,19 @@ function cleanupPrefixed(dir, prefix) {
|
|
|
212
212
|
}
|
|
213
213
|
}
|
|
214
214
|
|
|
215
|
-
|
|
215
|
+
/**
|
|
216
|
+
* Merge CTX's three enforcement hooks into settings.json using Claude Code's
|
|
217
|
+
* current nested hook schema: { matcher, hooks: [{ type: 'command', command }] }.
|
|
218
|
+
* The empty matcher ("") fires on every tool call / subagent stop.
|
|
219
|
+
*
|
|
220
|
+
* The flat `{ command }` shape CTX shipped before is NOT recognized by current
|
|
221
|
+
* Claude Code — it is silently ignored, so the hooks never run. This writes the
|
|
222
|
+
* supported shape and removes any prior CTX entry (flat or nested) so reinstall
|
|
223
|
+
* stays idempotent. Non-CTX hooks are preserved verbatim.
|
|
224
|
+
*
|
|
225
|
+
* Exported for unit testing.
|
|
226
|
+
*/
|
|
227
|
+
export function mergeHooksIntoSettings(targetBase, hooksDir) {
|
|
216
228
|
const settingsPath = path.join(targetBase, 'settings.json');
|
|
217
229
|
let settings = {};
|
|
218
230
|
|
|
@@ -221,34 +233,39 @@ function mergeHooksIntoSettings(targetBase, hooksDir) {
|
|
|
221
233
|
settings = JSON.parse(fs.readFileSync(settingsPath, 'utf-8'));
|
|
222
234
|
} catch {}
|
|
223
235
|
|
|
224
|
-
//
|
|
236
|
+
// True if a hook entry points at one of our ctx-* scripts. Handles the
|
|
237
|
+
// current nested shape and tolerates the legacy flat shape so upgrades
|
|
238
|
+
// don't leave a stale duplicate behind.
|
|
239
|
+
const isCtxEntry = (entry) => {
|
|
240
|
+
const handlers = Array.isArray(entry?.hooks) ? entry.hooks : [];
|
|
241
|
+
return handlers.some(h => typeof h?.command === 'string' && h.command.includes('ctx-'))
|
|
242
|
+
|| (typeof entry?.command === 'string' && entry.command.includes('ctx-'));
|
|
243
|
+
};
|
|
244
|
+
|
|
245
|
+
// Preserve every non-CTX hook entry as-is.
|
|
225
246
|
const existingHooks = settings.hooks || {};
|
|
226
247
|
const userHooks = {};
|
|
227
|
-
for (const [event,
|
|
228
|
-
if (Array.isArray(
|
|
229
|
-
userHooks[event] =
|
|
248
|
+
for (const [event, entries] of Object.entries(existingHooks)) {
|
|
249
|
+
if (Array.isArray(entries)) {
|
|
250
|
+
userHooks[event] = entries.filter(e => !isCtxEntry(e));
|
|
230
251
|
}
|
|
231
252
|
}
|
|
232
253
|
|
|
233
|
-
//
|
|
254
|
+
// CTX hooks in the supported nested schema.
|
|
255
|
+
const ctxEntry = (script) => ({
|
|
256
|
+
matcher: '',
|
|
257
|
+
hooks: [{ type: 'command', command: `node ${path.join(hooksDir, script)}` }],
|
|
258
|
+
});
|
|
234
259
|
const ctxHooks = {
|
|
235
|
-
SubagentStop: [
|
|
236
|
-
|
|
237
|
-
],
|
|
238
|
-
PreToolUse: [
|
|
239
|
-
{ command: `node ${path.join(hooksDir, 'ctx-pre-tool-use.js')}` }
|
|
240
|
-
],
|
|
241
|
-
PostToolUse: [
|
|
242
|
-
{ command: `node ${path.join(hooksDir, 'ctx-post-tool-use.js')}` }
|
|
243
|
-
],
|
|
260
|
+
SubagentStop: [ctxEntry('ctx-subagent-stop.js')],
|
|
261
|
+
PreToolUse: [ctxEntry('ctx-pre-tool-use.js')],
|
|
262
|
+
PostToolUse: [ctxEntry('ctx-post-tool-use.js')],
|
|
244
263
|
};
|
|
245
264
|
|
|
246
|
-
// Merge
|
|
265
|
+
// Merge: preserved user hooks first, CTX hooks appended.
|
|
247
266
|
const merged = {};
|
|
248
|
-
for (const
|
|
249
|
-
|
|
250
|
-
const ctxList = ctxHooks[event] || [];
|
|
251
|
-
merged[event] = [...userList, ...ctxList];
|
|
267
|
+
for (const event of new Set([...Object.keys(userHooks), ...Object.keys(ctxHooks)])) {
|
|
268
|
+
merged[event] = [...(userHooks[event] || []), ...(ctxHooks[event] || [])];
|
|
252
269
|
}
|
|
253
270
|
|
|
254
271
|
settings.hooks = merged;
|