@yeison.restrepo.r/code-conductor 1.23.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (43) hide show
  1. package/LICENSE +185 -0
  2. package/README.md +314 -0
  3. package/bin/code-conductor.mjs +133 -0
  4. package/global/CLAUDE.md +93 -0
  5. package/global/commands/cc-checkpoint.md +50 -0
  6. package/global/commands/cc-compact.md +49 -0
  7. package/global/commands/cc-lang.md +32 -0
  8. package/global/commands/cc-stack.md +69 -0
  9. package/global/hooks/graphify-ast-refresh.py +81 -0
  10. package/global/hooks/verbosity-remind.sh +372 -0
  11. package/global/memory/personal.md +24 -0
  12. package/global/memory/verbosity.md +7 -0
  13. package/global/settings.json +24 -0
  14. package/lib/installer/config.mjs +51 -0
  15. package/lib/installer/deploy.mjs +76 -0
  16. package/lib/installer/env.mjs +35 -0
  17. package/lib/installer/settings.mjs +77 -0
  18. package/package.json +34 -0
  19. package/project-template/.claude/commands/cc-debug.md +42 -0
  20. package/project-template/.claude/commands/cc-docs.md +49 -0
  21. package/project-template/.claude/commands/cc-implement.md +164 -0
  22. package/project-template/.claude/commands/cc-init.md +84 -0
  23. package/project-template/.claude/commands/cc-plan.md +114 -0
  24. package/project-template/.claude/commands/cc-refactor.md +42 -0
  25. package/project-template/.claude/commands/cc-resume.md +142 -0
  26. package/project-template/.claude/commands/cc-review.md +77 -0
  27. package/project-template/.claude/commands/cc-spec.md +138 -0
  28. package/project-template/.claude/commands/cc-test.md +56 -0
  29. package/project-template/.claude/hooks/context-guard.ps1 +55 -0
  30. package/project-template/.claude/hooks/context-guard.sh +43 -0
  31. package/project-template/.claude/hooks/post-compact.ps1 +41 -0
  32. package/project-template/.claude/hooks/post-compact.sh +36 -0
  33. package/project-template/.claude/hooks/pre-tool-use.sh +81 -0
  34. package/project-template/.claude/hooks/verbosity-remind.sh +168 -0
  35. package/project-template/.claude/memory/context-threshold.txt +1 -0
  36. package/project-template/.claude/memory/project.md +48 -0
  37. package/project-template/.claude/settings.json +52 -0
  38. package/project-template/CLAUDE.md +104 -0
  39. package/skills/agent-delegation.md +44 -0
  40. package/skills/code-simplifier.md +124 -0
  41. package/skills/critical-review.md +75 -0
  42. package/skills/memory-first.md +50 -0
  43. package/skills/verbosity.md +30 -0
@@ -0,0 +1,142 @@
1
+ ---
2
+ description: "(Conductor) Restore full session context in a fresh Claude Code session"
3
+ ---
4
+
5
+ ## Step 1 — Verify project initialization
6
+
7
+ Check if `CLAUDE.md` exists in the current directory.
8
+
9
+ - If **absent**: stop immediately and output — `"Project not initialized. Run /cc-init first."`
10
+ - If **present but `## Project Identity` fields are all empty**: continue and include this warning at the top of the final report: `"⚠ Project identity incomplete — run /cc-init to fill it in."`
11
+
12
+ ## Step 2 — Read project identity
13
+
14
+ Read `CLAUDE.md`. Extract:
15
+ - **Name** (from `- **Name:**`)
16
+ - **Description** (from `- **Description:**`)
17
+ - **Stack** (from `- **Stack:**`)
18
+ - **Language** (from `- **Language:**`)
19
+
20
+ Use `—` for any missing fields.
21
+
22
+ **Auto-fill blank command fields (BUG-015):** After reading the identity fields, check if any of `Build`, `Test`, `Lint`, `Format`, `Setup` in CLAUDE.md are still `<command>` (any case) or blank after the colon. If at least one is blank AND `scripts/detect-stack.mjs` exists at `$PWD`:
23
+
24
+ 1. Run `node scripts/detect-stack.mjs "$PWD"` and capture the JSON output.
25
+ 2. For each blank/placeholder command field, if the JSON contains a matching key (`build`, `test`, `lint`, `format`, `setup`), replace the placeholder with the detected value using a single `Edit` call.
26
+ 3. Never overwrite a field that already contains a non-placeholder value.
27
+ 4. If all five fields are already populated, or if `scripts/detect-stack.mjs` does not exist, skip this step silently.
28
+ 5. If the JSON is `{}` or node exits non-zero, skip silently.
29
+
30
+ Re-read the updated CLAUDE.md fields after this step so the session resume report reflects the filled values.
31
+
32
+ ## Step 3 — Read project memory
33
+
34
+ Read `.claude/memory/project.md`.
35
+
36
+ Extract:
37
+ - The content of the most recent `## Checkpoint [...]` block (3 bullets max)
38
+ - Any entries under `## Active Conventions`
39
+ - Any entries under `## Technical Debt`
40
+
41
+ If the file is absent or has no `## Checkpoint` block, note `"No checkpoints yet"`.
42
+
43
+ ## Step 4 — Read personal preferences
44
+
45
+ Read `.claude/memory/personal.md`. Extract developer preferences (verbosity, shortcuts, habits).
46
+
47
+ If the file is absent, skip silently.
48
+
49
+ ## Step 5 — Find latest spec
50
+
51
+ List files in `docs/superpowers/specs/`. Select the file with the most recent modification time (`mtime`). Extract its first `#` heading as a one-line summary.
52
+
53
+ If the directory is absent or empty, use `none`.
54
+
55
+ ## Step 6 — Find latest plan
56
+
57
+ List files in `docs/superpowers/plans/`. Select the file with the most recent modification time (`mtime`). Extract its first `#` heading as a one-line summary.
58
+
59
+ If the directory is absent or empty, use `none`.
60
+
61
+ ## Step 6a: Scan active plan for in-progress and failed tasks
62
+
63
+ If a plan file was found in Step 6, scan it for active-state markers:
64
+
65
+ Run `Grep` with:
66
+ - `pattern`: `\[>\]|\[!\]`
67
+ - `path`: the plan file path found in Step 6
68
+ - `output_mode`: `content`
69
+
70
+ Collect results:
71
+ - Lines containing `[>]` are **in-progress tasks** (execution interrupted mid-flight)
72
+ - Lines containing `[!]` are **failed tasks** (execution halted; manual resolution required)
73
+
74
+ Extract the task ID (e.g. `[T-001-A]`) from each matching line. Store counts and IDs for the report.
75
+
76
+ If no `[>]` or `[!]` lines are found, skip these fields in the report.
77
+
78
+ ## Step 7 — Read git state
79
+
80
+ Run:
81
+
82
+ ```bash
83
+ git log --oneline -10
84
+ git status --short
85
+ git branch --show-current
86
+ ```
87
+
88
+ Count the lines in the `git status --short` output — each line represents one uncommitted file. If the output is empty, the count is `"none"`.
89
+
90
+ If not inside a git repository, skip silently.
91
+
92
+ ## Step 8 — Check for updates
93
+
94
+ Read the local installed version from `~/.claude/memory/conductor-version.md`.
95
+
96
+ Fetch the remote version:
97
+
98
+ ```bash
99
+ curl -fsSL --max-time 5 https://raw.githubusercontent.com/yeisonrestrepo/code-conductor/main/VERSION 2>/dev/null
100
+ ```
101
+
102
+ If the remote version differs from the local version, store this notice for the report:
103
+ `"⚡ code-conductor [remote version] available — run: bash install.sh to update"`
104
+
105
+ If the fetch fails or times out, skip silently. Do not stop the session.
106
+
107
+ ## Step 9 — Render report
108
+
109
+ Output this report, populating each field from the steps above:
110
+
111
+ ```
112
+ ## Session Resume — [Name] · [YYYY-MM-DD]
113
+
114
+ [⚠ Project identity incomplete — run /cc-init to fill it in.] ← include only if applicable
115
+ [⚡ code-conductor X.Y.Z available — run: bash install.sh to update] ← include only if applicable
116
+
117
+ ### Active Work
118
+ Spec: [spec filename] — [spec title]
119
+ Plan: [plan filename] — [plan title]
120
+ In-progress: [count] task(s) - [task IDs] (include only if [>] tasks were found in Step 6a)
121
+ Failed: [count] task(s) - [task IDs] (include only if [!] tasks were found in Step 6a)
122
+
123
+ ### Recent Commits
124
+ [git log --oneline -10 output]
125
+
126
+ ### Open Changes
127
+ Branch: [branch name] · Uncommitted: [count, or "none"]
128
+
129
+ ### Memory Highlights
130
+ [latest checkpoint block — 3 bullets max]
131
+
132
+ ### Session Preferences
133
+ [personal.md relevant lines]
134
+ ```
135
+
136
+ ## Step 10 — Load stack profile
137
+
138
+ Run `/cc-stack` to detect and load the matching stack profile.
139
+
140
+ If `/cc-stack` cannot detect a stack or reports an error, append this line to the report:
141
+ `"⚠ Stack could not be detected — run /cc-stack manually."`
142
+ Do not stop the session.
@@ -0,0 +1,77 @@
1
+ ---
2
+ description: "(Conductor) Review code changes against spec and standards"
3
+ ---
4
+
5
+ ## Phase entry - Handoff enforcement
6
+
7
+ Before doing anything else, perform this blocking check:
8
+
9
+ 1. Count the number of turns in the current conversation history.
10
+ 2. If turn count exceeds 5, halt immediately and output:
11
+
12
+ > "Phase boundary detected. Please execute /compact to clear history before proceeding."
13
+
14
+ Do not start any review tasks. Enter standby. Wait for the user to confirm `/compact` has been run before continuing.
15
+
16
+ 3. If turn count ≤ 5 AND `.claude/memory/session-snapshot.md` exists, proceed to the Destructive Read Invariant below.
17
+ 4. If turn count ≤ 5 AND `.claude/memory/session-snapshot.md` is absent, skip the Destructive Read Invariant and proceed directly - no snapshot context available (read-if-present fallback).
18
+
19
+ ## Phase entry - Destructive Read Invariant
20
+
21
+ Applies only when snapshot exists (step 3 above).
22
+
23
+ 1. Read `.claude/memory/session-snapshot.md` into context.
24
+ 2. Delete the file immediately.
25
+ 3. Use the snapshot contents as the starting context for this phase.
26
+
27
+ If the file cannot be deleted after reading, report the error and halt.
28
+
29
+ ---
30
+
31
+ ## Phase 0 — Skill activation
32
+
33
+ Before doing anything else, invoke both skills in order:
34
+
35
+ ```
36
+ Skill({ skill: "subagent-driven-development", args: "$ARGUMENTS" })
37
+ Skill({ skill: "critical-review" })
38
+ ```
39
+
40
+ `subagent-driven-development` spawns one `Explore` sub-agent per review layer (Critical / Important / Suggestions) — each returns findings, the main context aggregates only. `critical-review` then runs Phases 2–4: Adversarial Review (RESILIENCE / EFFICIENCY / FRICTION checks), Self-Correction Loop for any weakness found, and the mandatory `[VALIDATION]` section at the end.
41
+
42
+ ---
43
+
44
+ Determine what to review:
45
+ - No argument → `git diff HEAD`
46
+ - File path → review that file
47
+ - Directory → review all changed files in that directory
48
+
49
+ Review in three layers:
50
+
51
+ ### 🔴 Critical — Blocks merge
52
+ Issues that will cause bugs, security vulnerabilities, data loss, or breaking changes:
53
+ - Logic errors or incorrect algorithm
54
+ - SQL injection, XSS, hardcoded secrets, missing auth checks
55
+ - Mutations that bypass validation
56
+ - Breaking changes to public API without versioning
57
+
58
+ ### 🟡 Important — Must fix before shipping
59
+ Issues that degrade quality or create risk:
60
+ - Missing error handling for real failure cases
61
+ - Missing tests for new behavior
62
+ - Convention violations that will confuse future readers
63
+ - N+1 queries or obvious performance problems
64
+ - Missing input validation at system boundaries
65
+
66
+ ### 🟢 Suggestions — Optional improvements
67
+ Style, clarity, or minor improvements that would be nice but don't block the merge.
68
+
69
+ ---
70
+
71
+ **Verdict:**
72
+ - `APPROVED` — no critical or important issues
73
+ - `APPROVED WITH CHANGES` — important issues found, fix before shipping
74
+ - `BLOCKED` — critical issues found, do not merge
75
+
76
+ After showing the report, offer:
77
+ "Want me to auto-fix the critical and important issues?"
@@ -0,0 +1,138 @@
1
+ ---
2
+ description: "(Conductor) Define the problem and generate an approved spec"
3
+ ---
4
+
5
+ ## Phase entry - Resume Read
6
+
7
+ Before doing anything else, restore any stored context for the current commit by running `scripts/resume-read.mjs`. It resolves the current git hash, prefers a valid DB snapshot (`conductor-db get-snapshot`), falls back to the `.claude/memory/session-snapshot.json` handoff file, and prints a `RESUME_HIT` block on a hit / nothing on a miss. Capture its stdout **and** its exit code with the canonical per-platform form (each first probes for `node` and treats its absence as a clean miss, never an error):
8
+
9
+ - **Unix / Git Bash:**
10
+ ```sh
11
+ if command -v node >/dev/null 2>&1; then
12
+ resume_out="$(node scripts/resume-read.mjs 2>>.conductor/last-write.log)"; resume_rc=$?
13
+ else resume_rc=3; resume_out=""; fi
14
+ ```
15
+ - **PowerShell:**
16
+ ```powershell
17
+ if (Get-Command node -ErrorAction SilentlyContinue) {
18
+ $__eap = $ErrorActionPreference; $ErrorActionPreference = 'Continue'
19
+ if (Test-Path variable:PSNativeCommandUseErrorActionPreference) {
20
+ $__nap = $PSNativeCommandUseErrorActionPreference; $PSNativeCommandUseErrorActionPreference = $false
21
+ }
22
+ try {
23
+ $resume_out = node scripts/resume-read.mjs 2>> .conductor/last-write.log; $resume_rc = $LASTEXITCODE
24
+ } catch { $resume_rc = 3; $resume_out = "" }
25
+ finally {
26
+ $ErrorActionPreference = $__eap
27
+ if (Test-Path variable:__nap) { $PSNativeCommandUseErrorActionPreference = $__nap }
28
+ }
29
+ } else { $resume_rc = 3; $resume_out = "" }
30
+ ```
31
+
32
+ Branch on `resume_rc` - **only `0` and `4` are meaningful; every other code proceeds fresh:**
33
+
34
+ - **`0`** → parse the captured block and adopt it as this phase's starting context, then echo one banner to the user: `> Resumed from stored snapshot @ <commit> (phase: <phase>)`, appending ` (checkpoint prose available)` when the block reports `prose: available`. Parsing (the command owns normalization): split on `\n`; strip a trailing `\r` from every line; drop leading/trailing wholly-blank lines; require `lines[0].trim() === 'RESUME_HIT'` (anything else = miss); `key: value` lines split on the first `': '` (both sides trimmed); the `pending:` block is every subsequent `^\s*-\s+` line up to the first blank line or EOF, each item trimmed. Unknown keys are ignored. In PowerShell, `node …` binds `string[]` for multi-line output - normalize with `$lines = @($resume_out)`; a `$null`/empty capture with `resume_rc = 3` is a miss.
35
+ - **`4`** → **operational halt.** Do not run this phase's normal work. Emit exactly: `SNAP_INVALID: corrupt handoff at .claude/memory/session-snapshot.json - inspect or remove it, then re-run.` and enter standby awaiting user action. The corrupt file is left on disk (the script did not delete it).
36
+ - **`3` or any other code** → **proceed fresh** (clean miss, bypass, degrade, absent `node`, or any unexpected runtime code). Ignore the capture.
37
+
38
+ `resume-read.mjs` writes its own trace lines to `.conductor/last-write.log` via `appendFileSync`; the `2>>` redirect above only sinks the incidental exit-4 halt reason away from the UI - it is not the trace channel.
39
+
40
+ ---
41
+
42
+ ## Phase 0 — Skill activation
43
+
44
+ Before doing anything else, invoke both skills in order:
45
+
46
+ ```
47
+ Skill({ skill: "brainstorming", args: "$ARGUMENTS" })
48
+ Skill({ skill: "critical-review" })
49
+ ```
50
+
51
+ `brainstorming` explores the problem space and surfaces unknowns. `critical-review` Phase 1 then runs the Pre-Flight Analysis (Happy Path / Failure Points / Boundary Conditions) on the proposed solution before the spec is written. Do not write the spec until both have completed.
52
+
53
+ ---
54
+
55
+ ## Spec Read Budget
56
+
57
+ Before reading any file:
58
+ 1. Run Grep or Glob to locate relevant files. Skip this step only if the user's prompt names the exact file path.
59
+ 2. Apply the correct read rule based on file type:
60
+
61
+ **Capped source files** - read the first 30 lines only (`offset` omitted, `limit: 30`). Starting at any offset other than the beginning is forbidden; if the first 30 lines are insufficient, defer the file. Multiple reads of the same file at any offset are forbidden.
62
+ Extensions: `.ts` `.tsx` `.js` `.jsx` `.mjs` `.cjs` `.py` `.go` `.rs` `.java` `.rb` `.cs` `.cpp` `.c` `.h` `.swift` `.kt` `.php` `.sh` `.html` `.css` `.scss` `.sass` `.less` `.svelte` `.vue`
63
+
64
+ **Exempt files** - may be read in full:
65
+ Named manifests/config: `package.json` `package-lock.json` `yarn.lock` `pnpm-lock.yaml` `bun.lockb` `go.mod` `go.sum` `Cargo.toml` `Cargo.lock` `pyproject.toml` `requirements.txt` `Pipfile` `Gemfile` `Gemfile.lock` `tsconfig.json` `tsconfig.*.json` `.gitignore` `.eslintrc.*` `.prettierrc.*` `.env.example` `.nvmrc` `.node-version` `.python-version` `.tool-versions`
66
+ Patterns: `*.yaml` `*.yml` `*.toml` `*.json` (config/manifest root files only - do not apply to data or generated JSON) `*.md` `CLAUDE.md` `Makefile` `Dockerfile` `Dockerfile.*` `*.dockerfile` `Jenkinsfile` `Procfile` `Brewfile`
67
+ Note: `.env`, `.env.local`, `.env.*` (real values) are **not exempt** - the agent should not read them during spec phase.
68
+
69
+ **Extensionless files** - exempt only when the exact name appears in the Named manifests/config list or Patterns above. All other extensionless files (including unknown dotfiles) default to capped.
70
+
71
+ **Default** - any file not matched by the above rules defaults to capped.
72
+
73
+ **Deferred reads** - if a capped source file cannot be understood from 30 lines, record it in `### Files Requiring Full Read (deferred to /cc-plan)` and move on. Do not slice-read it.
74
+
75
+ ---
76
+
77
+ Search the codebase for existing code related to `$ARGUMENTS` before asking any questions.
78
+
79
+ Run: `grep -r "$ARGUMENTS" src/ --include="*.{ts,js,py,java,go,rs}" -l 2>/dev/null | head -20`
80
+
81
+ Then ask only for missing context. You need to understand:
82
+ 1. **Problem** — what is broken or missing?
83
+ 2. **User** — who is affected and what do they expect?
84
+ 3. **Constraints** — performance, security, backward compatibility?
85
+ 4. **Similar features** — anything in the codebase to stay consistent with?
86
+
87
+ Generate a spec with these sections:
88
+
89
+ ## Problem
90
+ [What is broken or missing, from the user's perspective]
91
+
92
+ ## Solution
93
+ [What will be built, one paragraph]
94
+
95
+ ## Behavior
96
+
97
+ ### Main path
98
+ [Step-by-step: what happens in the happy path]
99
+
100
+ ### Alternative paths
101
+ [Edge cases the user might hit]
102
+
103
+ ### Error cases
104
+ [What happens when things go wrong]
105
+
106
+ ## Acceptance Criteria
107
+ - [ ] [Testable criterion]
108
+ - [ ] [Testable criterion]
109
+
110
+ ## Out of Scope
111
+ [Explicitly list what this spec does NOT cover]
112
+
113
+ ## System Impact
114
+ [What existing code will be affected or needs to be reviewed]
115
+
116
+ ### Files Requiring Full Read (deferred to /cc-plan)
117
+
118
+ _None. List any source files that could not be understood within the 30-line cap. /cc-plan will perform full reads of these files before task breakdown._
119
+
120
+ ## Complexity Estimate
121
+ [S / M / L — with one sentence justification]
122
+
123
+ ---
124
+
125
+ Wait for explicit approval before proceeding to `/cc-plan`.
126
+
127
+ Once approved, append a summary to `.claude/memory/project.md` under:
128
+ `## Spec: [name] [YYYY-MM-DD]`
129
+
130
+ ---
131
+
132
+ ## Phase exit
133
+
134
+ Once the spec is approved and the summary has been appended to `.claude/memory/project.md`, instruct the user:
135
+
136
+ > "Spec complete. Run `/cc-compact` now before starting `/cc-plan`."
137
+
138
+ Do not proceed to plan phase without user confirmation that `/cc-compact` has been run.
@@ -0,0 +1,56 @@
1
+ ---
2
+ description: "(Conductor) Analyze coverage gaps and write missing tests"
3
+ ---
4
+
5
+ ## Phase 0 — Skill activation
6
+
7
+ Before doing anything else, invoke the `subagent-driven-development` Superpowers skill:
8
+
9
+ ```
10
+ Skill({ skill: "subagent-driven-development", args: "$ARGUMENTS" })
11
+ ```
12
+
13
+ Delegate coverage analysis to an `Explore` sub-agent. Delegate each test file to a separate sub-agent. The main context receives summaries and final file paths only.
14
+
15
+ ---
16
+
17
+ Analyze coverage gaps first. Run:
18
+ ```bash
19
+ # language-specific coverage command
20
+ # e.g.: pnpm test --coverage | tail -20
21
+ # e.g.: pytest --cov=src --cov-report=term-missing
22
+ ```
23
+
24
+ Identify what is untested. Prioritize:
25
+ 1. Public functions and API endpoints with no tests
26
+ 2. Error paths and edge cases in critical paths
27
+ 3. Integration points between modules
28
+
29
+ **Strategy:**
30
+ - Unit: logic with no I/O dependencies
31
+ - Integration: modules that talk to a database, API, or file system
32
+ - E2E: user-facing flows (use Playwright)
33
+
34
+ **All tests use AAA structure:**
35
+ ```
36
+ // Arrange
37
+ // Act
38
+ // Assert
39
+ ```
40
+
41
+ **Test names:** "should [expected behavior] when [condition]"
42
+
43
+ **For E2E with Playwright:**
44
+ 1. Confirm the app is running: `curl -f http://localhost:3000 || echo "App not running"`
45
+ 2. Navigate to the relevant page
46
+ 3. Interact with the UI to trigger the flow
47
+ 4. Capture a screenshot
48
+ 5. Generate the Playwright test
49
+
50
+ **Run tests after writing them.** Confirm before running.
51
+
52
+ **Report:**
53
+ - Passed: N
54
+ - Failed: N (with failure messages)
55
+ - Skipped: N
56
+ - Coverage delta: before → after (if available)
@@ -0,0 +1,55 @@
1
+ try {
2
+ $root = if ($env:CC_PROJECT_ROOT) { $env:CC_PROJECT_ROOT } else { '.' }
3
+ $mem = Join-Path $root '.claude\memory'
4
+ if ((Test-Path $mem) -and -not (Test-Path $mem -PathType Container)) { exit 0 }
5
+ New-Item -ItemType Directory -Force $mem -ErrorAction SilentlyContinue | Out-Null
6
+ if (-not (Test-Path $mem -PathType Container)) { exit 0 }
7
+
8
+ $critical = 25
9
+ $threshFile = Join-Path $mem 'context-threshold.txt'
10
+ try {
11
+ $raw = [System.IO.File]::ReadAllText($threshFile, [System.Text.Encoding]::UTF8)
12
+ $val = $raw.Split("`n")[0].TrimEnd("`r").Trim()
13
+ if ($val -match '^[1-9][0-9]*$') { $critical = [int]$val }
14
+ } catch { }
15
+
16
+ $count = 0
17
+ $countFile = Join-Path $mem 'turn-count.txt'
18
+ try {
19
+ $raw = [System.IO.File]::ReadAllText($countFile, [System.Text.Encoding]::UTF8)
20
+ $val = $raw.Split("`n")[0].TrimEnd("`r").Trim()
21
+ if ($val -match '^[0-9]+$') { $count = [int]$val }
22
+ } catch { }
23
+
24
+ $warning = [Math]::Truncate($critical * 80 / 100)
25
+ $newCount = [Math]::Min($count + 1, 99999)
26
+
27
+ $target = Join-Path $mem 'turn-count.txt'
28
+ $tmp = Join-Path $mem 'turn-count.txt.tmp'
29
+ $enc = [System.Text.UTF8Encoding]::new($false)
30
+ [System.IO.File]::WriteAllText($tmp, "$newCount`n", $enc)
31
+ try {
32
+ [System.IO.File]::Replace($tmp, $target, $null)
33
+ } catch [System.IO.FileNotFoundException] {
34
+ try {
35
+ [System.IO.File]::Move($tmp, $target)
36
+ } catch {
37
+ Remove-Item $tmp -Force -ErrorAction SilentlyContinue
38
+ exit 0
39
+ }
40
+ }
41
+
42
+ if ($env:CC_GUARD_DEBUG) {
43
+ Write-Host "[context-guard] root=$root count=$newCount critical=$critical warning=$warning"
44
+ }
45
+
46
+ if ($newCount -ge 99999) {
47
+ "[!!] CONTEXT CRITICAL: Turn 99999/$critical (counter saturated) -- run /cc-compact NOW."
48
+ } elseif ($newCount -ge $critical) {
49
+ "[!!] CONTEXT CRITICAL: Turn $newCount/$critical -- run /cc-compact NOW before context overflows."
50
+ } elseif ($warning -gt 0 -and $newCount -ge $warning) {
51
+ "[!] CONTEXT WARNING: Turn $newCount/$critical -- consider running /cc-compact soon."
52
+ }
53
+ } catch {
54
+ exit 0
55
+ }
@@ -0,0 +1,43 @@
1
+ #!/usr/bin/env bash
2
+ set +e
3
+ main() {
4
+ _mem="${CC_PROJECT_ROOT:-.}/.claude/memory"
5
+ if [ -e "$_mem" ] && [ ! -d "$_mem" ]; then exit 0; fi
6
+ mkdir -p "$_mem" 2>/dev/null || exit 0
7
+
8
+ # Read threshold
9
+ _thresh=""
10
+ IFS= read -r _thresh < "${_mem}/context-threshold.txt" 2>/dev/null || _thresh=""
11
+ _thresh="${_thresh%$'\r'}"
12
+ _thresh="${_thresh#$'\xef\xbb\xbf'}"
13
+ [[ "$_thresh" =~ ^[1-9][0-9]*$ ]] || _thresh=25
14
+ critical=$_thresh
15
+ warning=$(( (critical * 80) / 100 ))
16
+
17
+ # Read count
18
+ _c=""
19
+ IFS= read -r _c < "${_mem}/turn-count.txt" 2>/dev/null || _c=""
20
+ _c="${_c%$'\r'}"
21
+ _c="${_c#$'\xef\xbb\xbf'}"
22
+ [[ "$_c" =~ ^[0-9]+$ ]] || _c=0
23
+ count=$_c
24
+
25
+ new_count=$(( count < 99999 ? count + 1 : 99999 ))
26
+
27
+ _target="${_mem}/turn-count.txt"
28
+ _tmp="${_mem}/turn-count.txt.tmp"
29
+ printf '%d\n' "$new_count" > "$_tmp" && mv -f "$_tmp" "$_target" \
30
+ || { rm -f "$_tmp" 2>/dev/null; exit 0; }
31
+
32
+ [ -n "${CC_GUARD_DEBUG:-}" ] && printf '[context-guard] root=%s count=%d critical=%d warning=%d\n' \
33
+ "${CC_PROJECT_ROOT:-.}" "$new_count" "$critical" "$warning" >&2
34
+
35
+ if [ "$new_count" -ge 99999 ]; then
36
+ printf '🚨 CONTEXT CRITICAL: Turn 99999/%d (counter saturated) — run /cc-compact NOW.\n' "$critical"
37
+ elif [ "$new_count" -ge "$critical" ]; then
38
+ printf '🚨 CONTEXT CRITICAL: Turn %d/%d — run /cc-compact NOW before context overflows.\n' "$new_count" "$critical"
39
+ elif [ "$warning" -gt 0 ] && [ "$new_count" -ge "$warning" ]; then
40
+ printf '⚠ CONTEXT WARNING: Turn %d/%d — consider running /cc-compact soon.\n' "$new_count" "$critical"
41
+ fi
42
+ }
43
+ main || exit 0
@@ -0,0 +1,41 @@
1
+ try {
2
+ $root = if ($env:CC_PROJECT_ROOT) { $env:CC_PROJECT_ROOT } else { '.' }
3
+ $mem = Join-Path $root '.claude\memory'
4
+ if ((Test-Path $mem) -and -not (Test-Path $mem -PathType Container)) { exit 0 }
5
+ New-Item -ItemType Directory -Force $mem -ErrorAction SilentlyContinue | Out-Null
6
+ if (-not (Test-Path $mem -PathType Container)) { exit 0 }
7
+
8
+ $target = Join-Path $mem 'turn-count.txt'
9
+ $tmp = Join-Path $mem 'turn-count.txt.tmp'
10
+ $enc = [System.Text.UTF8Encoding]::new($false)
11
+ [System.IO.File]::WriteAllText($tmp, "0`n", $enc)
12
+ try {
13
+ [System.IO.File]::Replace($tmp, $target, $null)
14
+ } catch [System.IO.FileNotFoundException] {
15
+ try {
16
+ [System.IO.File]::Move($tmp, $target)
17
+ } catch {
18
+ Remove-Item $tmp -Force -ErrorAction SilentlyContinue
19
+ exit 0
20
+ }
21
+ }
22
+
23
+ ""
24
+ "[PKG] Conversation compacted. Context counter reset to 0."
25
+ $projMd = Join-Path $root '.claude\memory\project.md'
26
+ if (Test-Path $projMd) {
27
+ $lastMatch = Select-String '## Checkpoint' $projMd | Select-Object -Last 1
28
+ if ($lastMatch) { " Last checkpoint: $($lastMatch.Line)" } else { " No checkpoints recorded yet in project.md." }
29
+ } else { " No project.md found." }
30
+ ""
31
+ " [TIP] If this session had important decisions, run /checkpoint before continuing."
32
+
33
+ $cond = Join-Path $root '.conductor'
34
+ Remove-Item -Force -ErrorAction SilentlyContinue (Join-Path $cond 'session-id')
35
+ Remove-Item -Force -ErrorAction SilentlyContinue (Join-Path $cond 'session-id.*.tmp')
36
+ Remove-Item -Force -ErrorAction SilentlyContinue (Join-Path $cond 'resume-validate.*.tmp.json')
37
+
38
+ ""
39
+ } catch {
40
+ exit 0
41
+ }
@@ -0,0 +1,36 @@
1
+ #!/usr/bin/env bash
2
+ set +e
3
+ main() {
4
+ _mem="${CC_PROJECT_ROOT:-.}/.claude/memory"
5
+ if [ -e "$_mem" ] && [ ! -d "$_mem" ]; then exit 0; fi
6
+ mkdir -p "$_mem" 2>/dev/null || exit 0
7
+
8
+ _target="${_mem}/turn-count.txt"
9
+ _tmp="${_mem}/turn-count.txt.tmp"
10
+ printf '0\n' > "$_tmp" && mv -f "$_tmp" "$_target" \
11
+ || { rm -f "$_tmp" 2>/dev/null; exit 0; }
12
+
13
+ echo ""
14
+ echo "📦 Conversation compacted. Context counter reset to 0."
15
+
16
+ _mem_file="${CC_PROJECT_ROOT:-.}/.claude/memory/project.md"
17
+ if [ -f "$_mem_file" ]; then
18
+ _last=$(grep "## Checkpoint" "$_mem_file" | tail -1 || true)
19
+ [ -n "$_last" ] && echo " Last checkpoint: $_last" \
20
+ || echo " No checkpoints recorded yet in project.md."
21
+ else
22
+ echo " No project.md found."
23
+ fi
24
+
25
+ echo ""
26
+ echo " 💡 If this session had important decisions or conventions,"
27
+ echo " run /checkpoint before continuing."
28
+
29
+ _cond="${CC_PROJECT_ROOT:-.}/.conductor"
30
+ rm -f "${_cond}/session-id" 2>/dev/null
31
+ rm -f "${_cond}"/session-id.*.tmp 2>/dev/null
32
+ rm -f "${_cond}"/resume-validate.*.tmp.json 2>/dev/null
33
+
34
+ echo ""
35
+ }
36
+ main || exit 0
@@ -0,0 +1,81 @@
1
+ #!/usr/bin/env bash
2
+ # Guards: (1) large-file Read without limit, (2) duplicate file creation.
3
+
4
+ set -euo pipefail
5
+
6
+ # ── Guard 1: Large-file Read without limit ─────────────────────────────────────
7
+ if [ "${CLAUDE_TOOL_NAME:-}" = "Read" ]; then
8
+ READ_PATH=$(echo "${CLAUDE_TOOL_INPUT:-}" | grep -o '"file_path":"[^"]*"' | head -1 | sed 's/"file_path":"//;s/"//' || true)
9
+ if [ -n "$READ_PATH" ] && [ -f "$READ_PATH" ]; then
10
+ LINE_COUNT=$(wc -l < "$READ_PATH" 2>/dev/null || echo "0")
11
+ HAS_LIMIT=$(echo "${CLAUDE_TOOL_INPUT:-}" | grep -c '"limit"' || true)
12
+ if [ "$LINE_COUNT" -gt 150 ] && [ "$HAS_LIMIT" -eq 0 ]; then
13
+ echo ""
14
+ echo "⛔ LARGE FILE READ BLOCKED"
15
+ echo " File: $READ_PATH"
16
+ echo " Lines: $LINE_COUNT (>150 — no limit specified)"
17
+ echo ""
18
+ echo " Follow the orchestrator lookup chain:"
19
+ echo " 1. Check .claude/memory/project.md"
20
+ echo " 2. Query graphify for structural questions"
21
+ echo " 3. Use Grep/Glob for pattern searches"
22
+ echo " 4. Read with explicit offset + limit"
23
+ echo ""
24
+ exit 1
25
+ fi
26
+ fi
27
+ fi
28
+
29
+ # ── Guard 4 — block Read on graphify-out/ and node_modules/ (BUG-017) ─────────────────────
30
+ # To reset to GitHub upstream: delete .claude/hooks/pre-tool-use.sh, then re-run installer.
31
+ if [ "$CLAUDE_TOOL_NAME" = "Read" ]; then
32
+ _g4_result=$(printf '%s' "$CLAUDE_TOOL_INPUT" | python3 -c '
33
+ import json, sys, posixpath
34
+ raw = sys.stdin.buffer.read().decode("utf-8", errors="replace")
35
+ d = json.loads(raw)
36
+ fp = d.get("file_path", "").strip()
37
+ fp_n = posixpath.normpath(fp.replace("\\", "/"))
38
+ parts = [p.lower() for p in fp_n.split("/") if p and p != "."]
39
+ blocked = {"graphify-out", "node_modules"}
40
+ print("BLOCK" if any(p in blocked for p in parts) else "OK")
41
+ ' 2>/dev/null) || true
42
+ if [ "$_g4_result" = "BLOCK" ]; then
43
+ echo '{"decision":"block","reason":"Guard 4: direct reads of graphify-out/ and node_modules/ are forbidden. Use Glob for existence checks or the graphify skill: /graphify query \"<question>\"."}'
44
+ exit 1
45
+ fi
46
+ # Debug: set CC_GUARD4_DEBUG=1 to log fail-open events to stderr for diagnostics.
47
+ if [ -n "${CC_GUARD4_DEBUG:-}" ] && [ "$_g4_result" != "OK" ]; then
48
+ printf '[Guard 4 debug] fail-open: _g4_result="%s"\n' "$_g4_result" >&2
49
+ fi
50
+ fi
51
+
52
+ # ── Guard 2: Duplicate file creation ──────────────────────────────────────────
53
+ FILE_PATH=""
54
+ if [ -n "${CLAUDE_TOOL_INPUT:-}" ]; then
55
+ FILE_PATH=$(echo "$CLAUDE_TOOL_INPUT" | grep -o '"path":"[^"]*"' | head -1 | sed 's/"path":"//;s/"//' || true)
56
+ fi
57
+
58
+ if [ -z "$FILE_PATH" ]; then
59
+ exit 0
60
+ fi
61
+
62
+ if [ ! -f "$FILE_PATH" ]; then
63
+ exit 0
64
+ fi
65
+
66
+ LINE_COUNT=$(wc -l < "$FILE_PATH" 2>/dev/null || echo "?")
67
+ LAST_MODIFIED=$(date -r "$FILE_PATH" "+%Y-%m-%d %H:%M" 2>/dev/null || stat -c "%y" "$FILE_PATH" 2>/dev/null | cut -d. -f1 || echo "unknown")
68
+
69
+ echo ""
70
+ echo "⚠️ FILE ALREADY EXISTS"
71
+ echo " Path: $FILE_PATH"
72
+ echo " Lines: $LINE_COUNT"
73
+ echo " Last modified: $LAST_MODIFIED"
74
+ echo ""
75
+ echo " Choose an action:"
76
+ echo " 1. Edit the existing file instead of overwriting"
77
+ echo " 2. Confirm you want to overwrite (re-issue the command)"
78
+ echo " 3. Cancel"
79
+ echo ""
80
+
81
+ exit 1