tlc-claude-code 2.0.1 → 2.2.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 (109) hide show
  1. package/.claude/agents/builder.md +144 -0
  2. package/.claude/agents/planner.md +143 -0
  3. package/.claude/agents/reviewer.md +160 -0
  4. package/.claude/commands/tlc/build.md +4 -0
  5. package/.claude/commands/tlc/deploy.md +194 -2
  6. package/.claude/commands/tlc/e2e-verify.md +214 -0
  7. package/.claude/commands/tlc/guard.md +191 -0
  8. package/.claude/commands/tlc/help.md +32 -0
  9. package/.claude/commands/tlc/init.md +73 -37
  10. package/.claude/commands/tlc/llm.md +19 -4
  11. package/.claude/commands/tlc/preflight.md +134 -0
  12. package/.claude/commands/tlc/review-plan.md +363 -0
  13. package/.claude/commands/tlc/review.md +172 -57
  14. package/.claude/commands/tlc/watchci.md +159 -0
  15. package/.claude/hooks/tlc-block-tools.sh +41 -0
  16. package/.claude/hooks/tlc-capture-exchange.sh +50 -0
  17. package/.claude/hooks/tlc-post-build.sh +38 -0
  18. package/.claude/hooks/tlc-post-push.sh +22 -0
  19. package/.claude/hooks/tlc-prompt-guard.sh +69 -0
  20. package/.claude/hooks/tlc-session-init.sh +123 -0
  21. package/CLAUDE.md +13 -0
  22. package/bin/install.js +268 -2
  23. package/bin/postinstall.js +102 -24
  24. package/bin/setup-autoupdate.js +206 -0
  25. package/bin/setup-autoupdate.test.js +124 -0
  26. package/bin/tlc.js +0 -0
  27. package/dashboard-web/dist/assets/index-CdS5CHqu.css +1 -0
  28. package/dashboard-web/dist/assets/index-CwNPPVpg.js +483 -0
  29. package/dashboard-web/dist/assets/index-CwNPPVpg.js.map +1 -0
  30. package/dashboard-web/dist/index.html +2 -2
  31. package/docker-compose.dev.yml +18 -12
  32. package/package.json +4 -2
  33. package/scripts/project-docs.js +1 -1
  34. package/server/index.js +228 -2
  35. package/server/lib/capture-bridge.js +242 -0
  36. package/server/lib/capture-bridge.test.js +363 -0
  37. package/server/lib/capture-guard.js +140 -0
  38. package/server/lib/capture-guard.test.js +182 -0
  39. package/server/lib/command-runner.js +159 -0
  40. package/server/lib/command-runner.test.js +92 -0
  41. package/server/lib/cost-tracker.test.js +49 -12
  42. package/server/lib/deploy/runners/dependency-runner.js +106 -0
  43. package/server/lib/deploy/runners/dependency-runner.test.js +148 -0
  44. package/server/lib/deploy/runners/secrets-runner.js +174 -0
  45. package/server/lib/deploy/runners/secrets-runner.test.js +127 -0
  46. package/server/lib/deploy/security-gates.js +11 -24
  47. package/server/lib/deploy/security-gates.test.js +9 -2
  48. package/server/lib/deploy-engine.js +182 -0
  49. package/server/lib/deploy-engine.test.js +147 -0
  50. package/server/lib/docker-api.js +137 -0
  51. package/server/lib/docker-api.test.js +202 -0
  52. package/server/lib/docker-client.js +297 -0
  53. package/server/lib/docker-client.test.js +308 -0
  54. package/server/lib/input-sanitizer.js +86 -0
  55. package/server/lib/input-sanitizer.test.js +117 -0
  56. package/server/lib/launchd-agent.js +225 -0
  57. package/server/lib/launchd-agent.test.js +185 -0
  58. package/server/lib/memory-api.js +3 -1
  59. package/server/lib/memory-api.test.js +3 -5
  60. package/server/lib/memory-bridge-e2e.test.js +160 -0
  61. package/server/lib/memory-committer.js +18 -4
  62. package/server/lib/memory-committer.test.js +21 -0
  63. package/server/lib/memory-hooks-capture.test.js +69 -4
  64. package/server/lib/memory-hooks-integration.test.js +98 -0
  65. package/server/lib/memory-hooks.js +42 -4
  66. package/server/lib/memory-store-adapter.js +105 -0
  67. package/server/lib/memory-store-adapter.test.js +141 -0
  68. package/server/lib/memory-wiring-e2e.test.js +93 -0
  69. package/server/lib/nginx-config.js +114 -0
  70. package/server/lib/nginx-config.test.js +82 -0
  71. package/server/lib/ollama-health.js +91 -0
  72. package/server/lib/ollama-health.test.js +74 -0
  73. package/server/lib/orchestration/agent-dispatcher.js +114 -0
  74. package/server/lib/orchestration/agent-dispatcher.test.js +110 -0
  75. package/server/lib/orchestration/orchestrator.js +130 -0
  76. package/server/lib/orchestration/orchestrator.test.js +192 -0
  77. package/server/lib/orchestration/tmux-manager.js +101 -0
  78. package/server/lib/orchestration/tmux-manager.test.js +109 -0
  79. package/server/lib/orchestration/worktree-manager.js +132 -0
  80. package/server/lib/orchestration/worktree-manager.test.js +129 -0
  81. package/server/lib/port-guard.js +44 -0
  82. package/server/lib/port-guard.test.js +65 -0
  83. package/server/lib/project-scanner.js +37 -2
  84. package/server/lib/project-scanner.test.js +152 -0
  85. package/server/lib/remember-command.js +2 -0
  86. package/server/lib/remember-command.test.js +23 -0
  87. package/server/lib/review/plan-reviewer.js +260 -0
  88. package/server/lib/review/plan-reviewer.test.js +269 -0
  89. package/server/lib/review/review-schemas.js +173 -0
  90. package/server/lib/review/review-schemas.test.js +152 -0
  91. package/server/lib/security/crypto-utils.test.js +2 -2
  92. package/server/lib/semantic-recall.js +1 -1
  93. package/server/lib/semantic-recall.test.js +17 -0
  94. package/server/lib/ssh-client.js +184 -0
  95. package/server/lib/ssh-client.test.js +127 -0
  96. package/server/lib/vps-api.js +184 -0
  97. package/server/lib/vps-api.test.js +208 -0
  98. package/server/lib/vps-bootstrap.js +124 -0
  99. package/server/lib/vps-bootstrap.test.js +79 -0
  100. package/server/lib/vps-monitor.js +126 -0
  101. package/server/lib/vps-monitor.test.js +98 -0
  102. package/server/lib/workspace-api.js +182 -1
  103. package/server/lib/workspace-api.test.js +474 -0
  104. package/server/package-lock.json +737 -0
  105. package/server/package.json +3 -0
  106. package/server/setup.sh +271 -271
  107. package/dashboard-web/dist/assets/index-Uhc49PE-.css +0 -1
  108. package/dashboard-web/dist/assets/index-W36XHPC5.js +0 -431
  109. package/dashboard-web/dist/assets/index-W36XHPC5.js.map +0 -1
@@ -1,6 +1,6 @@
1
1
  # /tlc:review - Review Current Branch
2
2
 
3
- Review changes on current branch before pushing.
3
+ Review changes on current branch before pushing. **Runs in a loop until clean.**
4
4
 
5
5
  ## What This Does
6
6
 
@@ -9,7 +9,10 @@ Review changes on current branch before pushing.
9
9
  3. Checks test coverage for all changed files
10
10
  4. Analyzes commit order for TDD compliance
11
11
  5. Scans for security issues
12
- 6. Generates verdict: APPROVED or CHANGES_REQUESTED
12
+ 6. If issues found **fix them automatically, then re-review**
13
+ 7. **Repeats until both Claude and Codex approve** — no arbitrary limit, runs until clean
14
+
15
+ **This is an iterative review loop, not a single pass.** Think of it as RL-mode: keep fixing and re-checking until the code is foolproof.
13
16
 
14
17
  **This runs automatically at the end of `/tlc:build`.**
15
18
 
@@ -41,19 +44,32 @@ TLC automatically uses ALL providers configured for the `review` capability in `
41
44
 
42
45
  ## Process
43
46
 
44
- ### Step 1: Load Router Configuration
47
+ ### Step 1: Load Router State (Persistent)
45
48
 
46
- Read `.tlc.json` to get configured review providers:
49
+ **Always read from the router state file first**, then fall back to config:
47
50
 
48
51
  ```javascript
52
+ // 1. Read persistent router state (written by session-init hook)
53
+ const routerState = JSON.parse(fs.readFileSync('.tlc/.router-state.json', 'utf-8'));
54
+
55
+ // 2. Read config for capability mappings
49
56
  const config = JSON.parse(fs.readFileSync('.tlc.json', 'utf-8'));
50
57
  const reviewProviders = config.router?.capabilities?.review?.providers || ['claude'];
51
58
  const providers = config.router?.providers || {};
59
+
60
+ // 3. Filter to only AVAILABLE providers (from state file)
61
+ const availableReviewers = reviewProviders.filter(p =>
62
+ routerState.providers[p]?.available === true
63
+ );
52
64
  ```
53
65
 
54
- **Default providers for review:** `['claude', 'codex']`
66
+ **The state file (`.tlc/.router-state.json`) is authoritative for availability.** It's written by the `SessionStart` hook, re-probed every hour, and persists across skill invocations. Never run `which codex` yourself — read the state file.
67
+
68
+ If the state file is missing or stale (>1 hour), probe manually and write a fresh one.
55
69
 
56
- If Codex is configured and available, it WILL be invoked automatically.
70
+ **Default providers for review:** `['claude', 'codex']` but only invoked if the state file confirms they're available.
71
+
72
+ If Codex is configured AND available in state, it WILL be invoked automatically.
57
73
 
58
74
  ### Step 2: Identify Changes
59
75
 
@@ -179,52 +195,38 @@ For each provider in `reviewProviders` (except `claude` which is the current ses
179
195
 
180
196
  **How to invoke:**
181
197
 
182
- 1. **Save diff to temporary file with size limit** (max 500 lines per chunk):
198
+ **Codex** use its built-in `review` subcommand. It reads the git diff natively, no need to pipe files:
199
+
183
200
  ```bash
184
- # Get diff and check size
185
- git diff main...HEAD > /tmp/review-diff-full.patch
186
- line_count=$(wc -l < /tmp/review-diff-full.patch)
201
+ # Review current branch against main (default)
202
+ codex review --base main "Focus on: bugs, security issues, missing edge cases, test coverage gaps. End with APPROVED or CHANGES_REQUESTED."
187
203
 
188
- if [ "$line_count" -gt 500 ]; then
189
- echo "⚠️ Large diff ($line_count lines) - chunking for review..."
190
-
191
- # Split by file for targeted review
192
- git diff --name-only main...HEAD | while read file; do
193
- git diff main...HEAD -- "$file" > "/tmp/review-chunk-${file//\//_}.patch"
194
- done
195
-
196
- # Or truncate with warning
197
- head -500 /tmp/review-diff-full.patch > /tmp/review-diff.patch
198
- echo "... truncated (showing first 500 of $line_count lines)" >> /tmp/review-diff.patch
199
- else
200
- cp /tmp/review-diff-full.patch /tmp/review-diff.patch
201
- fi
202
- ```
204
+ # Review uncommitted changes only
205
+ codex review --uncommitted
203
206
 
204
- 2. **Invoke each configured provider** (one chunk at a time if split):
207
+ # Review a specific commit
208
+ codex review --commit <sha>
205
209
 
206
- ```bash
207
- # For Codex (GPT-5.2) - detailed review prompt
208
- codex --print "You are a senior code reviewer. Analyze this diff thoroughly:
210
+ # Custom instructions via prompt
211
+ codex review --base main "Check for TDD compliance: were tests written before implementation? Flag any implementation without corresponding test files."
212
+ ```
209
213
 
210
- 1. **Line-by-line Analysis**: Comment on specific lines with issues
211
- 2. **Bugs**: Identify potential bugs, edge cases, null checks
212
- 3. **Security**: SQL injection, XSS, command injection, auth issues
213
- 4. **Performance**: N+1 queries, unnecessary loops, memory leaks
214
- 5. **Code Quality**: Naming, duplication, complexity, SOLID principles
215
- 6. **Test Coverage**: Are the changes properly tested?
214
+ `codex review` outputs a structured review to stdout. No `--print` flag needed it's already non-interactive.
216
215
 
217
- For each issue found:
218
- - File and line number
219
- - Severity (critical/high/medium/low)
220
- - What's wrong
221
- - How to fix it
216
+ **Gemini** no built-in review command, so save diff and invoke:
222
217
 
223
- End with: APPROVED (no critical/high issues) or CHANGES_REQUESTED (has critical/high issues)
218
+ ```bash
219
+ # Save diff for Gemini
220
+ git diff main...HEAD > /tmp/review-diff.patch
221
+ line_count=$(wc -l < /tmp/review-diff.patch)
224
222
 
225
- File: /tmp/review-diff.patch"
223
+ # Truncate if too large
224
+ if [ "$line_count" -gt 500 ]; then
225
+ head -500 /tmp/review-diff.patch > /tmp/review-diff-truncated.patch
226
+ echo "... truncated (showing first 500 of $line_count lines)" >> /tmp/review-diff-truncated.patch
227
+ mv /tmp/review-diff-truncated.patch /tmp/review-diff.patch
228
+ fi
226
229
 
227
- # For Gemini - detailed review prompt
228
230
  gemini --print "Review this code diff as a senior engineer. Provide:
229
231
  - Specific line-by-line feedback
230
232
  - Security vulnerabilities with file:line references
@@ -232,14 +234,10 @@ gemini --print "Review this code diff as a senior engineer. Provide:
232
234
  - Code quality issues
233
235
  - Missing test coverage
234
236
 
235
- Be thorough and specific. File: /tmp/review-diff.patch"
236
- ```
237
+ Be thorough and specific. End with APPROVED or CHANGES_REQUESTED.
237
238
 
238
- **Large Diff Handling:**
239
- - Diffs over 500 lines are automatically chunked by file
240
- - Each file's changes reviewed separately
241
- - Results aggregated across all chunks
242
- - Alternative: truncate with warning (shows first 500 lines)
239
+ $(cat /tmp/review-diff.patch)"
240
+ ```
243
241
 
244
242
  **Note:** Each CLI has its own syntax. Check `codex --help` and `gemini --help` for exact flags. The `--print` flag outputs the response without interactive mode.
245
243
 
@@ -264,7 +262,124 @@ Invoking Codex (GPT-5.2) for review...
264
262
  - Any CHANGES_REQUESTED = overall CHANGES_REQUESTED
265
263
  - Issues from all providers are combined in the report
266
264
 
267
- ### Step 7: Generate Report
265
+ ### Step 7: Fix-and-Recheck Loop (RL Mode)
266
+
267
+ **This is the core innovation. Reviews are not one-shot — they loop until clean.**
268
+
269
+ After Steps 2-6 complete, if ANY issues were found:
270
+
271
+ ```
272
+ ┌─────────────────────────────────────────────┐
273
+ │ REVIEW LOOP (runs until clean) │
274
+ │ │
275
+ │ 1. Collect all issues from Claude + Codex │
276
+ │ 2. Fix each issue: │
277
+ │ - Missing tests → write them │
278
+ │ - Security issues → patch the code │
279
+ │ - Coding standards → refactor │
280
+ │ - Codex feedback → apply fixes │
281
+ │ 3. Run tests to verify fixes don't break │
282
+ │ 4. Commit fixes │
283
+ │ 5. Re-run Steps 2-6 (full review again) │
284
+ │ 6. If new issues → loop back to 1 │
285
+ │ 7. If clean → exit loop, generate report │
286
+ └─────────────────────────────────────────────┘
287
+ ```
288
+
289
+ **Iteration rules:**
290
+
291
+ 1. **No arbitrary limit** — keep looping until BOTH providers return APPROVED. The code isn't done until it's clean.
292
+ 2. **Each iteration runs the FULL check** — don't skip steps. Fresh eyes each time.
293
+ 3. **Re-invoke Codex each iteration** — `codex review --base main` sees the latest fixes
294
+ 4. **Commit after each fix round** — `git commit -m "fix: address review feedback (round N)"`
295
+ 5. **Track what was fixed** — maintain a running list for the final report
296
+ 6. **Stuck detection** — if the SAME issue appears 3 times after being "fixed", stop and escalate to the user with context on what was tried. This is the only exit condition besides clean.
297
+
298
+ **Fix priority order:**
299
+ 1. Security issues (HIGH severity) — fix these first, they block everything
300
+ 2. Missing tests — write them before touching implementation
301
+ 3. Implementation bugs flagged by Codex — apply fixes
302
+ 4. Coding standards (file size, `any` types, return types) — refactor
303
+ 5. Style/naming/docs — lowest priority, fix if time permits
304
+
305
+ **What gets auto-fixed vs flagged for human:**
306
+
307
+ | Issue Type | Auto-Fix | Human Review |
308
+ |-----------|----------|--------------|
309
+ | Missing test file | Write it | - |
310
+ | Hardcoded secret | Replace with env var | If unclear what var to use |
311
+ | `any` type | Replace with proper interface | If domain type unclear |
312
+ | File >1000 lines | Split into sub-modules | If split strategy unclear |
313
+ | Security vulnerability | Patch it | If fix might break behavior |
314
+ | Codex-flagged bug | Apply suggestion | If suggestion conflicts with Claude |
315
+ | Merge conflict | - | Always human |
316
+
317
+ **Example iteration:**
318
+
319
+ ```
320
+ ───────────────────────────────────────
321
+ Review Round 1/5
322
+ ───────────────────────────────────────
323
+ Claude: CHANGES_REQUESTED
324
+ - Missing test for src/utils.js
325
+ - Hardcoded API key in src/config.js
326
+ Codex: CHANGES_REQUESTED
327
+ - Missing null check in src/parser.js:42
328
+ - No error handling in src/api.js:88
329
+
330
+ Fixing 4 issues...
331
+ ✅ Created src/utils.test.js (3 tests)
332
+ ✅ Replaced hardcoded key with process.env.API_KEY
333
+ ✅ Added null check in parser.js:42
334
+ ✅ Added try/catch in api.js:88
335
+ ✅ All tests pass
336
+ ✅ Committed: fix: address review feedback (round 1)
337
+
338
+ ───────────────────────────────────────
339
+ Review Round 2/5
340
+ ───────────────────────────────────────
341
+ Claude: CHANGES_REQUESTED
342
+ - src/utils.test.js missing edge case for empty input
343
+ Codex: APPROVED
344
+
345
+ Fixing 1 issue...
346
+ ✅ Added empty input edge case test
347
+ ✅ All tests pass
348
+ ✅ Committed: fix: address review feedback (round 2)
349
+
350
+ ───────────────────────────────────────
351
+ Review Round 3/5
352
+ ───────────────────────────────────────
353
+ Claude: APPROVED
354
+ Codex: APPROVED
355
+
356
+ ✅ All providers agree — exiting loop.
357
+ ───────────────────────────────────────
358
+ ```
359
+
360
+ **Stuck detection (only exit besides clean):**
361
+
362
+ ```
363
+ ───────────────────────────────────────
364
+ Review Round 7
365
+ ───────────────────────────────────────
366
+ Claude: APPROVED
367
+ Codex: CHANGES_REQUESTED
368
+ - Complex refactor needed in src/legacy.js ← appeared 3 times
369
+
370
+ ⚠️ STUCK: This issue has reappeared 3 times after being fixed.
371
+ Escalating to human review.
372
+
373
+ Attempts made:
374
+ Round 3: Extracted helper function → Codex still flagged
375
+ Round 5: Split into two modules → Codex still flagged
376
+ Round 7: Added interface layer → Codex still flagged
377
+
378
+ This needs human judgment. Run /tlc:review again after manual fix.
379
+ ───────────────────────────────────────
380
+ ```
381
+
382
+ ### Step 8: Generate Report
268
383
 
269
384
  ```markdown
270
385
  # Code Review Report
@@ -292,14 +407,11 @@ Invoking Codex (GPT-5.2) for review...
292
407
  - TDD Score: 75%
293
408
  ```
294
409
 
295
- ### Step 8: Return Verdict
410
+ ### Step 9: Return Verdict
296
411
 
297
- **APPROVED** - All checks pass. Ready to push/merge.
412
+ **APPROVED** - All providers agree after N iterations. Ready to push/merge.
298
413
 
299
- **CHANGES_REQUESTED** - Issues found:
300
- - Missing tests → Add tests for flagged files
301
- - Low TDD score → Consider reordering commits or adding test commits
302
- - Security issues → Fix flagged patterns
414
+ **CHANGES_REQUESTED** - Max iterations reached with remaining issues. Needs human review.
303
415
 
304
416
  ## Example Output
305
417
 
@@ -420,6 +532,9 @@ Action required:
420
532
  | `--providers <list>` | Override providers (e.g., `--providers codex,gemini`) |
421
533
  | `--codex-only` | Use only Codex for review |
422
534
  | `--no-external` | Skip external providers, use Claude only |
535
+ | `--stuck-threshold <N>` | How many times the same issue reappears before escalating to human (default: 3) |
536
+ | `--no-fix` | Single-pass review only — report issues but don't auto-fix |
537
+ | `--fix-all` | Fix even low-priority style issues (default: skip style) |
423
538
 
424
539
  ## Integration
425
540
 
@@ -0,0 +1,159 @@
1
+ # /tlc:watchci - Watch CI and Fix Until Green
2
+
3
+ After pushing code, monitor the GitHub Actions run and fix failures in a loop until CI passes.
4
+
5
+ ## What This Does
6
+
7
+ 1. **Identifies the GH Actions run** triggered by the latest push
8
+ 2. **Polls until complete** (or fails)
9
+ 3. **On failure**: reads the logs, identifies the issue, fixes it, commits, pushes again
10
+ 4. **Repeats** until green or max attempts reached
11
+ 5. **Reports** final status
12
+
13
+ This is the "I pushed, now babysit CI for me" command.
14
+
15
+ ## Usage
16
+
17
+ ```
18
+ /tlc:watchci
19
+ /tlc:watchci 3 # max 3 fix attempts (default: 5)
20
+ ```
21
+
22
+ ## Process
23
+
24
+ ### Step 1: Find the Active Run
25
+
26
+ ```bash
27
+ gh run list --limit 5 --json databaseId,status,conclusion,headBranch,event,name,createdAt
28
+ ```
29
+
30
+ - Find the most recent run on the current branch
31
+ - If no run is in progress or recently completed, tell the user and exit
32
+ - Show: workflow name, run ID, status
33
+
34
+ ### Step 2: Wait for Completion
35
+
36
+ Poll the run status every 30 seconds:
37
+
38
+ ```bash
39
+ gh run view <run_id> --json status,conclusion
40
+ ```
41
+
42
+ While status is `in_progress` or `queued`:
43
+ - Print a brief status update every 60 seconds (not every poll)
44
+ - Continue waiting
45
+
46
+ ### Step 3: Check Result
47
+
48
+ If `conclusion` is `success`:
49
+ - Report green and exit
50
+
51
+ If `conclusion` is `failure`:
52
+ - Move to Step 4
53
+
54
+ ### Step 4: Read Failure Logs
55
+
56
+ ```bash
57
+ gh run view <run_id> --log-failed
58
+ ```
59
+
60
+ - Parse the failed step(s) and their log output
61
+ - Identify the root cause:
62
+ - **Test failure**: Which test, what assertion, what file
63
+ - **Build failure**: Which compilation error, what file/line
64
+ - **Lint failure**: Which rule, what file/line
65
+ - **Dependency issue**: Which package, what version conflict
66
+ - **Other**: Extract the relevant error message
67
+
68
+ ### Step 5: Fix the Issue
69
+
70
+ Based on the failure type:
71
+
72
+ **Test failure:**
73
+ - Read the failing test file and the source file it tests
74
+ - Understand what broke
75
+ - Fix the source code (not the test, unless the test itself is wrong)
76
+ - Run the test locally first to verify: `npm test` or `npx vitest run <file>`
77
+
78
+ **Build failure:**
79
+ - Read the file with the compilation error
80
+ - Fix the type error, missing import, etc.
81
+ - Verify locally: `npm run build` or `npx tsc --noEmit`
82
+
83
+ **Lint failure:**
84
+ - Read the file and fix the lint issue
85
+ - Verify locally: `npm run lint`
86
+
87
+ **Dependency issue:**
88
+ - Fix package.json or lock file as needed
89
+ - Verify locally: `npm ci`
90
+
91
+ ### Step 6: Commit and Push
92
+
93
+ - Stage only the files you changed
94
+ - Commit with message: `fix: resolve CI failure - <brief description>`
95
+ - Push to the same branch
96
+ - **Ask user before pushing** (per TLC rules)
97
+
98
+ ### Step 7: Loop Back
99
+
100
+ - Return to Step 1 to watch the new run
101
+ - Track attempt count
102
+ - If max attempts (default 5) reached without green, stop and report:
103
+ - What was tried
104
+ - What's still failing
105
+ - Suggestion for manual investigation
106
+
107
+ ## Guard Rails
108
+
109
+ - **Never push without asking.** Even in a fix loop, confirm before each push.
110
+ - **Never modify tests to make CI pass** unless the test itself has a genuine bug (not a "make the assertion match the wrong output" fix).
111
+ - **Local verification first.** Always run the fix locally before pushing.
112
+ - **Max attempts.** Default 5. Don't loop forever.
113
+ - **Don't mask failures.** If a test is legitimately catching a bug, fix the bug. Don't skip the test.
114
+
115
+ ## Example
116
+
117
+ ```
118
+ > /tlc:watchci
119
+
120
+ Watching CI for branch: feature/auth-module
121
+ Run #4521 (CI) — in progress...
122
+
123
+ ⏳ Waiting... (2m elapsed)
124
+ ⏳ Waiting... (3m elapsed)
125
+
126
+ ❌ Run #4521 failed
127
+
128
+ Failed step: "Run tests"
129
+ Error: FAIL server/lib/auth/auth.test.js
130
+ ● validateToken › should reject expired tokens
131
+ Expected: "TOKEN_EXPIRED"
132
+ Received: "INVALID_TOKEN"
133
+
134
+ Reading auth.test.js and auth.service.js...
135
+
136
+ Found: validateToken returns generic "INVALID_TOKEN" for expired tokens
137
+ instead of the specific "TOKEN_EXPIRED" error code.
138
+
139
+ Fix: Update the expiry check in auth.service.js to return "TOKEN_EXPIRED"
140
+
141
+ Running locally... ✅ Test passes
142
+
143
+ Ready to commit and push fix? (Y/n)
144
+ > y
145
+
146
+ Pushed. Watching new run...
147
+
148
+ Run #4522 (CI) — in progress...
149
+ ⏳ Waiting... (2m elapsed)
150
+
151
+ ✅ Run #4522 passed! CI is green.
152
+ ```
153
+
154
+ ## When to Use
155
+
156
+ - After pushing and you want CI monitored automatically
157
+ - After `/tlc:build` when you've pushed your work
158
+ - When CI keeps failing and you want the fix loop automated
159
+ - Pair with `/tlc:e2e-verify` for full verification after CI is green
@@ -0,0 +1,41 @@
1
+ #!/bin/bash
2
+ # TLC Enforcement Layer 1: Hard-block non-TLC planning tools
3
+ # Fires on PreToolUse for banned tools and DENIES them.
4
+ # Claude cannot bypass this - the tool call never executes.
5
+
6
+ INPUT=$(cat)
7
+ TOOL=$(echo "$INPUT" | jq -r '.tool_name // empty')
8
+
9
+ case "$TOOL" in
10
+ EnterPlanMode)
11
+ REASON="BLOCKED by TLC. Use /tlc:plan instead. Plans go in .planning/phases/ files."
12
+ ;;
13
+ TaskCreate)
14
+ REASON="BLOCKED by TLC. Tasks live in .planning/phases/{N}-PLAN.md with [ ] markers."
15
+ ;;
16
+ TaskUpdate)
17
+ REASON="BLOCKED by TLC. Update task markers in .planning/phases/{N}-PLAN.md files."
18
+ ;;
19
+ TaskGet)
20
+ REASON="BLOCKED by TLC. Read tasks from .planning/phases/{N}-PLAN.md files."
21
+ ;;
22
+ TaskList)
23
+ REASON="BLOCKED by TLC. Use /tlc:progress to check task status."
24
+ ;;
25
+ ExitPlanMode)
26
+ REASON="BLOCKED by TLC. Plans are approved via /tlc:build, not ExitPlanMode."
27
+ ;;
28
+ *)
29
+ exit 0
30
+ ;;
31
+ esac
32
+
33
+ cat <<EOF
34
+ {
35
+ "hookSpecificOutput": {
36
+ "hookEventName": "PreToolUse",
37
+ "permissionDecision": "deny",
38
+ "permissionDecisionReason": "${REASON}"
39
+ }
40
+ }
41
+ EOF
@@ -0,0 +1,50 @@
1
+ #!/usr/bin/env bash
2
+ # TLC Memory Capture - Claude Code Stop Hook
3
+ #
4
+ # Reads Stop hook JSON from stdin, extracts the assistant response,
5
+ # and sends it to the TLC server for memory processing.
6
+ # Falls back to local spool when server is unreachable.
7
+ #
8
+ # This script MUST exit 0 always - capture failures never block Claude.
9
+
10
+ set -o pipefail
11
+
12
+ # Read stdin (Stop hook provides JSON)
13
+ INPUT=$(cat)
14
+
15
+ # Quick exit if no input
16
+ [ -z "$INPUT" ] && exit 0
17
+
18
+ # Use the capture-bridge Node.js module for reliable processing
19
+ PROJECT_DIR="${CLAUDE_PROJECT_DIR:-$(pwd)}"
20
+ BRIDGE_SCRIPT="$PROJECT_DIR/server/lib/capture-bridge.js"
21
+
22
+ if [ -f "$BRIDGE_SCRIPT" ]; then
23
+ echo "$INPUT" | node -e "
24
+ const bridge = require('$BRIDGE_SCRIPT');
25
+ let input = '';
26
+ process.stdin.on('data', d => input += d);
27
+ process.stdin.on('end', async () => {
28
+ const parsed = bridge.parseStopHookInput(input);
29
+ if (!parsed || !parsed.assistantMessage) process.exit(0);
30
+
31
+ const userMessage = parsed.transcriptPath
32
+ ? bridge.extractLastUserMessage(parsed.transcriptPath)
33
+ : null;
34
+
35
+ await bridge.captureExchange({
36
+ cwd: parsed.cwd || '$PROJECT_DIR',
37
+ assistantMessage: parsed.assistantMessage,
38
+ userMessage,
39
+ sessionId: parsed.sessionId,
40
+ });
41
+
42
+ const path = require('path');
43
+ const spoolDir = path.join(parsed.cwd || '$PROJECT_DIR', '.tlc', 'memory');
44
+ await bridge.drainSpool(spoolDir);
45
+ });
46
+ " 2>/dev/null
47
+ fi
48
+
49
+ # Always exit 0 - never block Claude
50
+ exit 0
@@ -0,0 +1,38 @@
1
+ #!/bin/bash
2
+ # TLC Plugin: Post-build and post-plan automation chain
3
+ # Fires on PostToolUse for Skill.
4
+ #
5
+ # After /tlc:build (code written):
6
+ # guard → preflight → review (Claude + Codex) → if APPROVED → offer push + PR
7
+ #
8
+ # After /tlc:plan:
9
+ # guard plan → validate structure
10
+ #
11
+ # After /tlc:quick:
12
+ # preflight → review → offer push
13
+
14
+ INPUT=$(cat)
15
+ TOOL=$(echo "$INPUT" | jq -r '.tool_name // empty')
16
+
17
+ # Only care about Skill tool
18
+ [ "$TOOL" != "Skill" ] && exit 0
19
+
20
+ SKILL=$(echo "$INPUT" | jq -r '.tool_input.skill // empty')
21
+
22
+ case "$SKILL" in
23
+ tlc:build)
24
+ echo "[TLC-PLUGIN] Build phase complete. Mandatory post-build chain:
25
+ (1) Run /tlc:guard to validate TLC process compliance (test-first, coverage, no skipped tests).
26
+ (2) Run /tlc:preflight to check for gaps (references, registries, configs, distribution).
27
+ (3) Run /tlc:review to invoke multi-LLM review — Claude reviews in-session, THEN invoke Codex CLI for second opinion. BOTH must APPROVE.
28
+ (4) If review APPROVED: ask user for permission to push to remote and create a PR for main.
29
+ (5) If review CHANGES_REQUESTED: fix the issues and re-run the review. Do NOT push.
30
+ Do NOT skip any step. Do NOT push without review approval."
31
+ ;;
32
+ tlc:plan)
33
+ echo "[TLC-PLUGIN] Plan created. Now automatically run /tlc:guard plan to validate the plan has proper task breakdown, acceptance criteria, and dependency ordering. Do NOT skip."
34
+ ;;
35
+ tlc:quick)
36
+ echo "[TLC-PLUGIN] Quick task complete. Run /tlc:preflight then /tlc:review (Claude + Codex). If APPROVED, ask user for permission to push and create PR."
37
+ ;;
38
+ esac
@@ -0,0 +1,22 @@
1
+ #!/bin/bash
2
+ # TLC Plugin: Post-push automation chain
3
+ # Fires on PostToolUse for Bash. Detects git push.
4
+ #
5
+ # After git push:
6
+ # watchci (monitor GH Actions) → if green → e2e-verify (screenshots + logs)
7
+
8
+ INPUT=$(cat)
9
+ TOOL=$(echo "$INPUT" | jq -r '.tool_name // empty')
10
+
11
+ # Only care about Bash tool
12
+ [ "$TOOL" != "Bash" ] && exit 0
13
+
14
+ # Check if the command was a git push
15
+ COMMAND=$(echo "$INPUT" | jq -r '.tool_input.command // empty')
16
+ if echo "$COMMAND" | grep -qE '^git push'; then
17
+ echo "[TLC-PLUGIN] git push detected. Mandatory post-push chain:
18
+ (1) Run /tlc:watchci — monitor the GitHub Actions run, read failure logs, fix issues, and push again until CI is green.
19
+ (2) Once CI is green, run /tlc:e2e-verify — start the app, take screenshots, read them visually, check server and console logs for errors.
20
+ (3) If e2e-verify finds issues, fix them and push again (which restarts this chain).
21
+ Do NOT skip any step."
22
+ fi
@@ -0,0 +1,69 @@
1
+ #!/bin/bash
2
+ # TLC Enforcement Layer 2: Smart intent detection + routing
3
+ # Fires on every UserPromptSubmit. Parses user message for intent and
4
+ # injects specific TLC command routing — not a generic reminder.
5
+ #
6
+ # Output appears as <user-prompt-submit-hook> and Claude treats it as user instruction.
7
+ # Survives context compaction because it is re-injected every turn.
8
+
9
+ # Only active in TLC projects
10
+ [ ! -f ".tlc.json" ] && exit 0
11
+
12
+ # Read user's message from stdin
13
+ INPUT=$(cat)
14
+ MSG=$(echo "$INPUT" | jq -r '.user_prompt // empty' 2>/dev/null)
15
+
16
+ # If we can't parse the message, fall back to generic reminder
17
+ if [ -z "$MSG" ]; then
18
+ echo "[TLC PROJECT] All work uses /tlc commands. Never write code without tests. Run /tlc if unsure."
19
+ exit 0
20
+ fi
21
+
22
+ # Lowercase for matching
23
+ MSG_LOWER=$(echo "$MSG" | tr '[:upper:]' '[:lower:]')
24
+
25
+ # Detect intent and inject specific routing
26
+ # Priority order: most specific first
27
+
28
+ # Plan intent
29
+ if echo "$MSG_LOWER" | grep -qE '\b(plan|break.*(down|into)|design|architect|roadmap)\b'; then
30
+ if ! echo "$MSG_LOWER" | grep -qE '/tlc'; then
31
+ echo "[TLC-ENFORCE] Planning detected. You MUST use /tlc:plan for this. Plans go in .planning/phases/ files, not in chat. Invoke Skill(skill=\"tlc:plan\") now."
32
+ exit 0
33
+ fi
34
+ fi
35
+
36
+ # Build/implement intent
37
+ if echo "$MSG_LOWER" | grep -qE '\b(build|implement|create|add|code|write|develop|make)\b.*(feature|function|module|component|endpoint|api|page|service|handler|route|model)'; then
38
+ if ! echo "$MSG_LOWER" | grep -qE '/tlc'; then
39
+ echo "[TLC-ENFORCE] Implementation detected. You MUST use /tlc:build for this. Tests before code — Red, Green, Refactor. Run /tlc:progress first, then invoke Skill(skill=\"tlc:build\"). Do NOT write code directly."
40
+ exit 0
41
+ fi
42
+ fi
43
+
44
+ # Fix/bug intent
45
+ if echo "$MSG_LOWER" | grep -qE '\b(fix|bug|broken|not working|failing|crash|error)\b'; then
46
+ if ! echo "$MSG_LOWER" | grep -qE '/tlc'; then
47
+ echo "[TLC-ENFORCE] Bug/fix detected. Use /tlc:quick for small fixes (still test-first) or /tlc:autofix if tests are failing. Do NOT write code directly without tests."
48
+ exit 0
49
+ fi
50
+ fi
51
+
52
+ # Refactor intent
53
+ if echo "$MSG_LOWER" | grep -qE '\b(refactor|clean.?up|restructure|reorganize|simplify)\b'; then
54
+ if ! echo "$MSG_LOWER" | grep -qE '/tlc'; then
55
+ echo "[TLC-ENFORCE] Refactoring detected. Use /tlc:refactor for step-by-step standards refactoring with tests. Invoke Skill(skill=\"tlc:refactor\")."
56
+ exit 0
57
+ fi
58
+ fi
59
+
60
+ # Deploy intent
61
+ if echo "$MSG_LOWER" | grep -qE '\b(deploy|ship|release|publish|push to prod|staging)\b'; then
62
+ if ! echo "$MSG_LOWER" | grep -qE '/tlc'; then
63
+ echo "[TLC-ENFORCE] Deployment detected. Use /tlc:deploy for deployment. Secrets must come from HashiCorp Vault or environment — never hardcode. Invoke Skill(skill=\"tlc:deploy\")."
64
+ exit 0
65
+ fi
66
+ fi
67
+
68
+ # Generic fallback for TLC projects
69
+ echo "[TLC PROJECT] All work uses /tlc commands. Never write code without tests. Run /tlc if unsure."