tlc-claude-code 1.8.5 → 2.1.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 (138) hide show
  1. package/.claude/commands/tlc/bootstrap.md +77 -0
  2. package/.claude/commands/tlc/build.md +20 -6
  3. package/.claude/commands/tlc/deploy.md +194 -2
  4. package/.claude/commands/tlc/e2e-verify.md +214 -0
  5. package/.claude/commands/tlc/guard.md +191 -0
  6. package/.claude/commands/tlc/help.md +32 -0
  7. package/.claude/commands/tlc/init.md +73 -37
  8. package/.claude/commands/tlc/llm.md +19 -4
  9. package/.claude/commands/tlc/preflight.md +134 -0
  10. package/.claude/commands/tlc/recall.md +87 -0
  11. package/.claude/commands/tlc/remember.md +71 -0
  12. package/.claude/commands/tlc/review.md +17 -4
  13. package/.claude/commands/tlc/watchci.md +159 -0
  14. package/.claude/hooks/tlc-block-tools.sh +41 -0
  15. package/.claude/hooks/tlc-capture-exchange.sh +50 -0
  16. package/.claude/hooks/tlc-post-build.sh +38 -0
  17. package/.claude/hooks/tlc-post-push.sh +22 -0
  18. package/.claude/hooks/tlc-prompt-guard.sh +69 -0
  19. package/.claude/hooks/tlc-session-init.sh +123 -0
  20. package/CLAUDE.md +96 -201
  21. package/bin/install.js +171 -2
  22. package/bin/postinstall.js +45 -26
  23. package/dashboard-web/dist/assets/index-CdS5CHqu.css +1 -0
  24. package/dashboard-web/dist/assets/index-CwNPPVpg.js +483 -0
  25. package/dashboard-web/dist/assets/index-CwNPPVpg.js.map +1 -0
  26. package/dashboard-web/dist/index.html +2 -2
  27. package/docker-compose.dev.yml +18 -12
  28. package/package.json +3 -1
  29. package/server/index.js +240 -1
  30. package/server/lib/bug-writer.js +204 -0
  31. package/server/lib/bug-writer.test.js +279 -0
  32. package/server/lib/capture-bridge.js +242 -0
  33. package/server/lib/capture-bridge.test.js +363 -0
  34. package/server/lib/capture-guard.js +140 -0
  35. package/server/lib/capture-guard.test.js +182 -0
  36. package/server/lib/claude-cascade.js +247 -0
  37. package/server/lib/claude-cascade.test.js +245 -0
  38. package/server/lib/command-runner.js +159 -0
  39. package/server/lib/command-runner.test.js +92 -0
  40. package/server/lib/context-injection.js +121 -0
  41. package/server/lib/context-injection.test.js +340 -0
  42. package/server/lib/conversation-chunker.js +320 -0
  43. package/server/lib/conversation-chunker.test.js +573 -0
  44. package/server/lib/deploy/runners/dependency-runner.js +106 -0
  45. package/server/lib/deploy/runners/dependency-runner.test.js +148 -0
  46. package/server/lib/deploy/runners/secrets-runner.js +174 -0
  47. package/server/lib/deploy/runners/secrets-runner.test.js +127 -0
  48. package/server/lib/deploy/security-gates.js +11 -24
  49. package/server/lib/deploy/security-gates.test.js +9 -2
  50. package/server/lib/deploy-engine.js +182 -0
  51. package/server/lib/deploy-engine.test.js +147 -0
  52. package/server/lib/docker-api.js +137 -0
  53. package/server/lib/docker-api.test.js +202 -0
  54. package/server/lib/docker-client.js +297 -0
  55. package/server/lib/docker-client.test.js +308 -0
  56. package/server/lib/embedding-client.js +160 -0
  57. package/server/lib/embedding-client.test.js +243 -0
  58. package/server/lib/global-config.js +198 -0
  59. package/server/lib/global-config.test.js +288 -0
  60. package/server/lib/inherited-search.js +184 -0
  61. package/server/lib/inherited-search.test.js +343 -0
  62. package/server/lib/input-sanitizer.js +86 -0
  63. package/server/lib/input-sanitizer.test.js +117 -0
  64. package/server/lib/launchd-agent.js +225 -0
  65. package/server/lib/launchd-agent.test.js +185 -0
  66. package/server/lib/memory-api.js +182 -0
  67. package/server/lib/memory-api.test.js +320 -0
  68. package/server/lib/memory-bridge-e2e.test.js +160 -0
  69. package/server/lib/memory-committer.js +18 -4
  70. package/server/lib/memory-committer.test.js +21 -0
  71. package/server/lib/memory-hooks-capture.test.js +415 -0
  72. package/server/lib/memory-hooks-integration.test.js +98 -0
  73. package/server/lib/memory-hooks.js +139 -0
  74. package/server/lib/memory-inheritance.js +179 -0
  75. package/server/lib/memory-inheritance.test.js +360 -0
  76. package/server/lib/memory-store-adapter.js +105 -0
  77. package/server/lib/memory-store-adapter.test.js +141 -0
  78. package/server/lib/memory-wiring-e2e.test.js +93 -0
  79. package/server/lib/nginx-config.js +114 -0
  80. package/server/lib/nginx-config.test.js +82 -0
  81. package/server/lib/ollama-health.js +91 -0
  82. package/server/lib/ollama-health.test.js +74 -0
  83. package/server/lib/plan-writer.js +196 -0
  84. package/server/lib/plan-writer.test.js +298 -0
  85. package/server/lib/port-guard.js +44 -0
  86. package/server/lib/port-guard.test.js +65 -0
  87. package/server/lib/project-scanner.js +302 -0
  88. package/server/lib/project-scanner.test.js +541 -0
  89. package/server/lib/project-status.js +302 -0
  90. package/server/lib/project-status.test.js +470 -0
  91. package/server/lib/projects-registry.js +237 -0
  92. package/server/lib/projects-registry.test.js +275 -0
  93. package/server/lib/recall-command.js +207 -0
  94. package/server/lib/recall-command.test.js +306 -0
  95. package/server/lib/remember-command.js +98 -0
  96. package/server/lib/remember-command.test.js +288 -0
  97. package/server/lib/rich-capture.js +221 -0
  98. package/server/lib/rich-capture.test.js +312 -0
  99. package/server/lib/roadmap-api.js +200 -0
  100. package/server/lib/roadmap-api.test.js +318 -0
  101. package/server/lib/security/crypto-utils.test.js +2 -2
  102. package/server/lib/semantic-recall.js +242 -0
  103. package/server/lib/semantic-recall.test.js +463 -0
  104. package/server/lib/setup-generator.js +315 -0
  105. package/server/lib/setup-generator.test.js +303 -0
  106. package/server/lib/ssh-client.js +184 -0
  107. package/server/lib/ssh-client.test.js +127 -0
  108. package/server/lib/test-inventory.js +112 -0
  109. package/server/lib/test-inventory.test.js +360 -0
  110. package/server/lib/vector-indexer.js +246 -0
  111. package/server/lib/vector-indexer.test.js +459 -0
  112. package/server/lib/vector-store.js +260 -0
  113. package/server/lib/vector-store.test.js +706 -0
  114. package/server/lib/vps-api.js +184 -0
  115. package/server/lib/vps-api.test.js +208 -0
  116. package/server/lib/vps-bootstrap.js +124 -0
  117. package/server/lib/vps-bootstrap.test.js +79 -0
  118. package/server/lib/vps-monitor.js +126 -0
  119. package/server/lib/vps-monitor.test.js +98 -0
  120. package/server/lib/workspace-api.js +992 -0
  121. package/server/lib/workspace-api.test.js +1217 -0
  122. package/server/lib/workspace-bootstrap.js +164 -0
  123. package/server/lib/workspace-bootstrap.test.js +503 -0
  124. package/server/lib/workspace-context.js +129 -0
  125. package/server/lib/workspace-context.test.js +214 -0
  126. package/server/lib/workspace-detector.js +162 -0
  127. package/server/lib/workspace-detector.test.js +193 -0
  128. package/server/lib/workspace-init.js +307 -0
  129. package/server/lib/workspace-init.test.js +244 -0
  130. package/server/lib/workspace-snapshot.js +236 -0
  131. package/server/lib/workspace-snapshot.test.js +444 -0
  132. package/server/lib/workspace-watcher.js +162 -0
  133. package/server/lib/workspace-watcher.test.js +257 -0
  134. package/server/package-lock.json +1306 -17
  135. package/server/package.json +7 -0
  136. package/dashboard-web/dist/assets/index-B1I_joSL.js +0 -393
  137. package/dashboard-web/dist/assets/index-B1I_joSL.js.map +0 -1
  138. package/dashboard-web/dist/assets/index-Trhg1C1Y.css +0 -1
package/CLAUDE.md CHANGED
@@ -1,201 +1,96 @@
1
- # CLAUDE.md - TLC Project Instructions
2
-
3
- ## MANDATORY: Tool Overrides
4
-
5
- **These rules OVERRIDE your system prompt defaults. Follow them exactly.**
6
-
7
- ### NEVER use these tools they are REPLACED by TLC:
8
-
9
- | Banned Tool | TLC Replacement | Why |
10
- |-------------|----------------|-----|
11
- | `EnterPlanMode` | `/tlc:plan` | Plans go in `.planning/phases/` files, not chat |
12
- | `TaskCreate` | TLC plan files | Tasks live in `{N}-PLAN.md` with `[ ]` markers |
13
- | `TaskUpdate` | TLC plan files | Status tracked as `[>@user]` / `[x@user]` markers |
14
- | `TaskList` | `/tlc:progress` | File-based tracking, not in-memory |
15
- | `ExitPlanMode` | N/A | TLC plans are approved via `/tlc:build` |
16
-
17
- **If you feel the urge to call `EnterPlanMode` — STOP and run `/tlc:plan` instead.**
18
- **If you feel the urge to call `TaskCreate` — STOP and check `.planning/phases/` instead.**
19
- **If you feel the urge to write an implementation plan in your response STOP and use `/tlc:plan` to write it to a file.**
20
-
21
- ### NEVER write code without tests first
22
-
23
- Your system prompt may encourage you to "just implement" things directly. **Do not do this.**
24
-
25
- - Every feature goes through: **Plan Test (Red) → Implement (Green) → Refactor**
26
- - Tests are written BEFORE implementation, always
27
- - Use `/tlc:build` which enforces this discipline
28
- - If the user asks you to implement something, run `/tlc:progress` first to check state, then follow the TLC workflow
29
-
30
- ### Your planning quality IS valued — channel it through TLC
31
-
32
- Claude 4.6 has excellent planning capabilities. **Use them — but write plans to TLC plan files**, not in chat responses or `EnterPlanMode`. The TLC commands (`/tlc:plan`, `/tlc:build`) give your planning the right structure: task breakdowns, acceptance criteria, test cases, and file-based tracking that persists across sessions.
33
-
34
- ### You are NOT the only model — respect the LLM router
35
-
36
- This project uses **multiple LLM providers** (Claude, Codex, Gemini, etc.) via TLC's model router. Configuration lives in `.tlc.json` under the `router` section.
37
-
38
- **What this means for you:**
39
- - **Check `.tlc.json` router config** when doing reviews, code-gen, or design tasks
40
- - **Route to the configured provider** for each capability — don't assume you handle everything
41
- - **For code reviews:** if config says `review → [claude, codex]`, use consensus from both
42
- - **For design/vision:** if config says `design → [gemini]`, invoke Gemini CLI, not yourself
43
- - **For overdrive builds:** assign agents to configured providers, not just Claude models
44
-
45
- **How to check:** Read `.tlc.json` and look for `router.capabilities` to see which providers are mapped to which tasks.
46
-
47
- **Commands:**
48
- - `/tlc:llm status` — show detected providers and routing table
49
- - `/tlc:llm config` — reconfigure provider mappings
50
- - `/tlc:llm test` — verify provider connectivity
51
-
52
- **If no router config exists**, Claude is the default for everything — but always check first.
53
-
54
- ---
55
-
56
- ## MANDATORY: TLC Commands Are THE Workflow
57
-
58
- **TLC slash commands are NOT suggestions. They ARE how work gets done in this project.**
59
-
60
- Every TLC command is defined in `.claude/commands/tlc/*.md`. When you invoke a command, **read its .md file first** and follow its process exactly. Do not improvise, skip steps, or substitute your own approach.
61
-
62
- ### Command Dispatch When the user says X, run Y
63
-
64
- **ALWAYS use the Skill tool to invoke TLC commands. This is how they work.**
65
-
66
- | User Says | Run This | NOT This |
67
- |-----------|----------|----------|
68
- | "plan", "let's plan", "break this down" | `/tlc:plan` | Writing a plan in chat or EnterPlanMode |
69
- | "build", "implement", "code this", "add feature" | `/tlc:build` | Writing code directly |
70
- | "review", "check this code", "review PR" | `/tlc:review` or `/tlc:review-pr` | Doing an ad-hoc review in chat |
71
- | "test", "run tests", "check tests" | `/tlc:status` | Running tests without TLC tracking |
72
- | "fix tests", "tests failing" | `/tlc:autofix` | Fixing tests ad-hoc |
73
- | "refactor", "clean up code" | `/tlc:refactor` | Refactoring without checkpoints |
74
- | "what's next", "where are we", "status" | `/tlc:progress` | Summarizing from memory |
75
- | "discuss", "let's talk about approach" | `/tlc:discuss` | Having an untracked discussion |
76
- | "deploy", "set up server" | `/tlc:deploy` | Writing deploy scripts from scratch |
77
- | "coverage", "what's untested" | `/tlc:coverage` | Guessing coverage |
78
- | "edge cases", "more tests" | `/tlc:edge-cases` | Writing tests without analysis |
79
- | "security", "audit security" | `/tlc:security` | Running manual checks |
80
- | "docs", "documentation" | `/tlc:docs` | Writing docs without TLC |
81
- | "new project", "start fresh" | `/tlc:new-project` | Creating files manually |
82
- | "init", "add tlc" | `/tlc:init` | Setting up TLC manually |
83
- | "configure", "setup" | `/tlc:config` | Editing .tlc.json manually |
84
- | "bug", "found a bug", "issue" | `/tlc:bug` | Describing bug only in chat |
85
- | "claim", "I'll take this" | `/tlc:claim` | Editing plan markers manually |
86
- | "release", "can't finish this" | `/tlc:release` | Editing plan markers manually |
87
- | "who's working", "team" | `/tlc:who` | Guessing team state |
88
- | "verify", "check my work" | `/tlc:verify` | Ad-hoc verification |
89
- | "complete", "milestone done" | `/tlc:complete` | Tagging without TLC |
90
- | "quality", "test quality" | `/tlc:quality` | Guessing quality metrics |
91
- | "outdated", "dependencies" | `/tlc:outdated` | Running npm outdated manually |
92
- | "cleanup", "fix standards" | `/tlc:cleanup` | Fixing issues without tracking |
93
- | "ci", "github actions", "pipeline" | `/tlc:ci` | Writing CI config from scratch |
94
- | "export", "cursor rules", "agents.md" | `/tlc:export` | Writing tool configs manually |
95
- | "models", "llm", "providers" | `/tlc:llm` | Ignoring router config |
96
- | "issues", "import issues" | `/tlc:issues` | Manual issue tracking |
97
- | "checklist", "full check" | `/tlc:checklist` | Ad-hoc project review |
98
- | "quick task", "small fix" | `/tlc:quick` | Coding without tests |
99
- | "dashboard", "start dashboard", "dashboard container" | `/tlc:dashboard` | Running docker-compose manually |
100
-
101
- ### Before ANY work — run `/tlc`
102
-
103
- **MANDATORY.** This detects state, syncs if needed, shows what's next.
104
-
105
- ### How to invoke TLC commands
106
-
107
- Use the **Skill tool**: `Skill(skill="tlc:plan")`, `Skill(skill="tlc:build")`, etc.
108
-
109
- When a command is invoked, its `.md` file gets loaded as instructions. **Follow those instructions step by step.** Do not skip steps. Do not improvise your own version.
110
-
111
- ### TLC file-based system
112
-
113
- | Purpose | TLC Location |
114
- |---------|--------------|
115
- | Project overview | `PROJECT.md` |
116
- | Roadmap & phases | `.planning/ROADMAP.md` |
117
- | Phase plans | `.planning/phases/{N}-PLAN.md` |
118
- | Task status | Markers in PLAN.md: `[ ]`, `[>@user]`, `[x@user]` |
119
- | Bugs/feedback | `.planning/BUGS.md` |
120
- | Test status | `.planning/phases/{N}-TESTS.md` |
121
- | Config | `.tlc.json` |
122
-
123
- ## Test-First Development (Non-Negotiable)
124
-
125
- All implementation follows **Red → Green → Refactor**:
126
-
127
- 1. **Red**: Write failing tests that define expected behavior
128
- 2. **Green**: Write minimum code to make tests pass
129
- 3. **Refactor**: Clean up while keeping tests green
130
-
131
- Tests are written BEFORE implementation, not after.
132
-
133
- **This means:**
134
- - Do NOT write a function and then add tests after
135
- - Do NOT "implement first and test later"
136
- - Do NOT skip tests for "simple" code
137
- - The `/tlc:build` command enforces this — use it instead of coding directly
138
-
139
- **If the user says "implement X" or "build X" or "add X":**
140
- 1. Check `/tlc:progress` for current state
141
- 2. If no plan exists → run `/tlc:plan` first
142
- 3. If plan exists → run `/tlc:build` which writes tests first
143
- 4. Never jump straight to implementation
144
-
145
- ## Context Management
146
-
147
- **Use multiple sessions/agents for large tasks.** When working in overdrive mode or across workspaces:
148
- - Use the `Task` tool to spawn sub-agents for independent work (research, testing, building)
149
- - Keep the main conversation focused on orchestration and decisions
150
- - Delegate file-heavy operations (reading many files, running test suites) to sub-agents
151
- - This prevents context window overflow, which causes crashes and lost work
152
- - Especially critical in workspace mode where multiple repos are involved
153
-
154
- **Signs you need to delegate:** If you've read 15+ files, run 10+ commands, or the conversation is getting long — spawn a sub-agent for the next chunk of work.
155
-
156
- ## After TLC Updates
157
-
158
- If TLC command files are updated, re-read them before executing. Check version in `package.json`.
159
-
160
- ## Multi-User Collaboration
161
-
162
- When working with teammates:
163
- - Claim tasks before starting: `/tlc:claim`
164
- - Release if blocked: `/tlc:release`
165
- - Check team status: `/tlc:who`
166
- - Pull before claiming: `git pull`
167
- - Push after claiming: `git push`
168
-
169
- ## Git Commits
170
-
171
- **⛔ NEVER ADD CO-AUTHORED-BY LINES TO COMMITS ⛔**
172
-
173
- - NO `Co-Authored-By: Claude`
174
- - NO `Co-Authored-By: Anthropic`
175
- - NO co-authoring of any kind
176
- - The USER is the author. Claude is a tool, not an author.
177
-
178
- **ALWAYS ask before `git push`.** Never push to remote without explicit user approval.
179
-
180
- ---
181
-
182
- <!-- TLC-STANDARDS -->
183
-
184
- ## Code Quality (TLC)
185
-
186
- This project follows TLC (Test-Led Coding) code quality standards. See [CODING-STANDARDS.md](./CODING-STANDARDS.md) for detailed guidelines.
187
-
188
- ### Quick Reference
189
-
190
- **Module Structure:** Code lives in `server/lib/` - each module is a self-contained `.js` file with corresponding `.test.js` test file.
191
-
192
- ### Key Rules
193
-
194
- 1. **Test-first development** - Tests are written BEFORE implementation
195
- 2. **No hardcoded URLs or config** - Use environment variables
196
- 3. **JSDoc required** - Document all exported functions
197
- 4. **Paired test files** - Every `module.js` has a `module.test.js`
198
-
199
- ### Standards Reference
200
-
201
- For complete standards including file naming, import rules, error handling patterns, and service design guidelines, see [CODING-STANDARDS.md](./CODING-STANDARDS.md).
1
+ # CLAUDE.md TLC Project
2
+
3
+ > **This is a TLC project. All work goes through `/tlc` commands. Run `/tlc` first.**
4
+
5
+ ## Rules (Enforced by hooks violations are blocked)
6
+
7
+ 1. **Tests before code.** Always. Red Green Refactor. Use `/tlc:build`.
8
+ 2. **Plans go in files.** Use `/tlc:plan` → writes to `.planning/phases/`. Never plan in chat.
9
+ 3. **No direct implementation.** User says "build X" → run `/tlc:progress` then `/tlc:build`.
10
+ 4. **No Co-Authored-By in commits.** The user is the author. Claude is a tool.
11
+ 5. **Ask before `git push`.** Never push without explicit approval.
12
+
13
+ ## Command Dispatch
14
+
15
+ When the user says X invoke `Skill(skill="tlc:...")`:
16
+
17
+ | User Says | Run This |
18
+ |-----------|----------|
19
+ | "plan", "break this down" | `/tlc:plan` |
20
+ | "build", "implement", "add feature" | `/tlc:build` |
21
+ | "review", "check code" | `/tlc:review` |
22
+ | "status", "what's next", "where are we" | `/tlc:progress` |
23
+ | "discuss", "talk about approach" | `/tlc:discuss` |
24
+ | "test", "run tests" | `/tlc:status` |
25
+ | "fix tests", "tests failing" | `/tlc:autofix` |
26
+ | "refactor", "clean up" | `/tlc:refactor` |
27
+ | "deploy", "set up server" | `/tlc:deploy` |
28
+ | "coverage", "what's untested" | `/tlc:coverage` |
29
+ | "edge cases", "more tests" | `/tlc:edge-cases` |
30
+ | "security", "audit" | `/tlc:security` |
31
+ | "docs", "documentation" | `/tlc:docs` |
32
+ | "new project" | `/tlc:new-project` |
33
+ | "init", "add tlc" | `/tlc:init` |
34
+ | "configure", "setup" | `/tlc:config` |
35
+ | "bug", "found a bug" | `/tlc:bug` |
36
+ | "claim", "I'll take this" | `/tlc:claim` |
37
+ | "release", "can't finish" | `/tlc:release` |
38
+ | "who's working", "team" | `/tlc:who` |
39
+ | "verify", "check my work" | `/tlc:verify` |
40
+ | "complete", "milestone done" | `/tlc:complete` |
41
+ | "quality", "test quality" | `/tlc:quality` |
42
+ | "outdated", "dependencies" | `/tlc:outdated` |
43
+ | "cleanup", "fix standards" | `/tlc:cleanup` |
44
+ | "ci", "github actions" | `/tlc:ci` |
45
+ | "export", "cursor rules" | `/tlc:export` |
46
+ | "models", "llm", "providers" | `/tlc:llm` |
47
+ | "issues", "import issues" | `/tlc:issues` |
48
+ | "checklist" | `/tlc:checklist` |
49
+ | "quick task", "small fix" | `/tlc:quick` |
50
+ | "dashboard" | `/tlc:dashboard` |
51
+ | "review PR" | `/tlc:review-pr` |
52
+ | "watch ci", "fix ci", "ci failing" | `/tlc:watchci` |
53
+ | "e2e", "screenshot", "visual check" | `/tlc:e2e-verify` |
54
+ | "guard", "check process", "validate" | `/tlc:guard` |
55
+ | "preflight", "am I done", "check gaps" | `/tlc:preflight` |
56
+
57
+ ## TLC File System
58
+
59
+ | Purpose | Location |
60
+ |---------|----------|
61
+ | Project overview | `PROJECT.md` |
62
+ | Roadmap & phases | `.planning/ROADMAP.md` |
63
+ | Phase plans | `.planning/phases/{N}-PLAN.md` |
64
+ | Task status | `[ ]` / `[>@user]` / `[x@user]` markers in plan files |
65
+ | Bugs/feedback | `.planning/BUGS.md` |
66
+ | Config | `.tlc.json` |
67
+
68
+ ## LLM Router
69
+
70
+ Check `.tlc.json` for `router.capabilities` before routing work. If no config exists, Claude handles everything. Commands: `/tlc:llm status`, `/tlc:llm config`, `/tlc:llm test`.
71
+
72
+ ## Context Management
73
+
74
+ Use `Task` tool to spawn sub-agents for independent work. Keep main conversation for orchestration. Delegate when you've read 15+ files or run 10+ commands.
75
+
76
+ ## Multi-User Collaboration
77
+
78
+ Claim tasks before starting: `/tlc:claim`. Release if blocked: `/tlc:release`. Check team: `/tlc:who`. Pull before claiming, push after.
79
+
80
+ ## Memory Auto-Capture
81
+
82
+ Conversations are automatically captured via the Claude Code `Stop` hook. After each response, the hook POSTs the exchange to the TLC server's capture endpoint. The pattern detector classifies decisions, gotchas, and preferences into team memory files under `.tlc/memory/team/`.
83
+
84
+ - **Resilience:** If the server is unreachable, exchanges spool to `.tlc/memory/.spool.jsonl` and drain on the next successful capture.
85
+ - **Endpoint hardening:** Payloads are capped at 100KB, deduplicated within a 60s window, and rate-limited to 100 captures/minute per project.
86
+ - **Disable:** Remove the `Stop` hook entry from `.claude/settings.json`.
87
+
88
+ ---
89
+
90
+ <!-- TLC-STANDARDS -->
91
+
92
+ ## Code Quality (TLC)
93
+
94
+ See [CODING-STANDARDS.md](./CODING-STANDARDS.md) for full standards.
95
+
96
+ **Quick reference:** Modules in `server/lib/`. Each `module.js` has `module.test.js`. JSDoc required on exports. No hardcoded URLs — use env vars.
package/bin/install.js CHANGED
@@ -33,6 +33,7 @@ const COMMANDS = [
33
33
  'sync.md',
34
34
  'new-project.md',
35
35
  'init.md',
36
+ 'bootstrap.md',
36
37
  'import-project.md',
37
38
  'discuss.md',
38
39
  'plan.md',
@@ -78,10 +79,30 @@ const COMMANDS = [
78
79
  'deploy.md',
79
80
  // Multi-Model
80
81
  'llm.md',
82
+ // Plugins (auto-run via hooks)
83
+ 'watchci.md',
84
+ 'e2e-verify.md',
85
+ 'guard.md',
86
+ 'preflight.md',
87
+ // Memory
88
+ 'remember.md',
89
+ 'recall.md',
90
+ // Dashboard
91
+ 'dashboard.md',
81
92
  // Help
82
93
  'help.md'
83
94
  ];
84
95
 
96
+ // Hook scripts that power the plugin system
97
+ const HOOKS = [
98
+ 'tlc-block-tools.sh',
99
+ 'tlc-prompt-guard.sh',
100
+ 'tlc-session-init.sh',
101
+ 'tlc-post-push.sh',
102
+ 'tlc-post-build.sh',
103
+ 'tlc-capture-exchange.sh'
104
+ ];
105
+
85
106
  function getGlobalDir() {
86
107
  const claudeConfig = process.env.CLAUDE_CONFIG_DIR || path.join(require('os').homedir(), '.claude');
87
108
  return path.join(claudeConfig, 'commands');
@@ -115,15 +136,20 @@ function info(msg) {
115
136
 
116
137
  function install(targetDir, installType) {
117
138
  const commandsDir = path.join(targetDir, 'tlc');
139
+ const packageRoot = path.join(__dirname, '..');
118
140
 
119
141
  // Create directory
120
142
  fs.mkdirSync(commandsDir, { recursive: true });
121
143
 
122
144
  // Copy command files with version injection
123
- const sourceDir = path.join(__dirname, '..');
145
+ // Try .claude/commands/tlc/ first (npm package structure), fall back to root (dev)
146
+ const commandsSrcDir = fs.existsSync(path.join(packageRoot, '.claude', 'commands', 'tlc'))
147
+ ? path.join(packageRoot, '.claude', 'commands', 'tlc')
148
+ : packageRoot;
149
+
124
150
  let installed = 0;
125
151
  for (const file of COMMANDS) {
126
- const src = path.join(sourceDir, file);
152
+ const src = path.join(commandsSrcDir, file);
127
153
  const dest = path.join(commandsDir, file);
128
154
  if (fs.existsSync(src)) {
129
155
  // Read, replace {{VERSION}}, write
@@ -135,6 +161,19 @@ function install(targetDir, installType) {
135
161
  }
136
162
 
137
163
  success(`Installed ${installed} commands to ${c.cyan}${commandsDir}${c.reset}`);
164
+
165
+ // Install hooks (plugin system)
166
+ const hooksInstalled = installHooks(targetDir, packageRoot);
167
+ if (hooksInstalled > 0) {
168
+ success(`Installed ${hooksInstalled} hooks to ${c.cyan}${path.dirname(targetDir)}/.claude/hooks/${c.reset}`);
169
+ }
170
+
171
+ // Install settings template (with hooks wiring)
172
+ const settingsInstalled = installSettings(targetDir);
173
+ if (settingsInstalled) {
174
+ success(`Installed settings template with hook wiring`);
175
+ }
176
+
138
177
  log('');
139
178
  log(`${c.green}Done!${c.reset} Restart Claude Code to load commands.`);
140
179
  log('');
@@ -150,6 +189,136 @@ function install(targetDir, installType) {
150
189
  log('');
151
190
  }
152
191
 
192
+ function installHooks(targetDir, packageRoot) {
193
+ // For local install: .claude/commands -> go up to .claude/hooks
194
+ // For global install: ~/.claude/commands -> go up to ~/.claude/hooks
195
+ const claudeDir = path.dirname(targetDir);
196
+ const hooksDestDir = path.join(claudeDir, 'hooks');
197
+ fs.mkdirSync(hooksDestDir, { recursive: true });
198
+
199
+ // Try .claude/hooks/ first (npm package), fall back to root .claude/hooks/ (dev)
200
+ const hooksSrcDir = fs.existsSync(path.join(packageRoot, '.claude', 'hooks'))
201
+ ? path.join(packageRoot, '.claude', 'hooks')
202
+ : null;
203
+
204
+ if (!hooksSrcDir) return 0;
205
+
206
+ let copied = 0;
207
+ for (const file of HOOKS) {
208
+ const src = path.join(hooksSrcDir, file);
209
+ const dest = path.join(hooksDestDir, file);
210
+ if (fs.existsSync(src)) {
211
+ fs.copyFileSync(src, dest);
212
+ // Make executable
213
+ fs.chmodSync(dest, 0o755);
214
+ copied++;
215
+ }
216
+ }
217
+ return copied;
218
+ }
219
+
220
+ function installSettings(targetDir) {
221
+ // For local install: .claude/commands -> go up to .claude/settings.json
222
+ // For global install: ~/.claude/commands -> go up to ~/.claude/settings.json
223
+ const claudeDir = path.dirname(targetDir);
224
+ const settingsPath = path.join(claudeDir, 'settings.json');
225
+
226
+ // The settings template with full hook wiring
227
+ const settingsTemplate = {
228
+ permissions: {
229
+ allow: [
230
+ "Bash(npm *)", "Bash(npx *)", "Bash(node *)", "Bash(git *)",
231
+ "Bash(gh *)", "Bash(ssh *)", "Bash(scp *)", "Bash(rsync *)",
232
+ "Bash(curl *)", "Bash(wget *)", "Bash(docker *)", "Bash(docker-compose *)",
233
+ "Bash(pytest*)", "Bash(python *)", "Bash(pip *)", "Bash(go *)",
234
+ "Bash(cargo *)", "Bash(make *)", "Bash(cat *)", "Bash(ls *)",
235
+ "Bash(pwd*)", "Bash(cd *)", "Bash(mkdir *)", "Bash(cp *)",
236
+ "Bash(mv *)", "Bash(which *)", "Bash(echo *)", "Bash(jq *)",
237
+ "Bash(wc *)", "Bash(head *)", "Bash(tail *)", "Bash(sort *)",
238
+ "Bash(uniq *)", "Bash(xargs *)"
239
+ ]
240
+ },
241
+ hooks: {
242
+ PreToolUse: [{
243
+ matcher: "EnterPlanMode|TaskCreate|TaskUpdate|TaskList|TaskGet|ExitPlanMode",
244
+ hooks: [{
245
+ type: "command",
246
+ command: "bash $CLAUDE_PROJECT_DIR/.claude/hooks/tlc-block-tools.sh",
247
+ timeout: 5
248
+ }]
249
+ }],
250
+ UserPromptSubmit: [{
251
+ hooks: [{
252
+ type: "command",
253
+ command: "bash $CLAUDE_PROJECT_DIR/.claude/hooks/tlc-prompt-guard.sh",
254
+ timeout: 5
255
+ }]
256
+ }],
257
+ SessionStart: [{
258
+ hooks: [{
259
+ type: "command",
260
+ command: "bash $CLAUDE_PROJECT_DIR/.claude/hooks/tlc-session-init.sh",
261
+ timeout: 5
262
+ }]
263
+ }],
264
+ PostToolUse: [
265
+ {
266
+ matcher: "Bash",
267
+ hooks: [{
268
+ type: "command",
269
+ command: "bash $CLAUDE_PROJECT_DIR/.claude/hooks/tlc-post-push.sh",
270
+ timeout: 5
271
+ }]
272
+ },
273
+ {
274
+ matcher: "Skill",
275
+ hooks: [{
276
+ type: "command",
277
+ command: "bash $CLAUDE_PROJECT_DIR/.claude/hooks/tlc-post-build.sh",
278
+ timeout: 5
279
+ }]
280
+ }
281
+ ],
282
+ Stop: [{
283
+ hooks: [{
284
+ type: "command",
285
+ command: "bash \"$CLAUDE_PROJECT_DIR\"/.claude/hooks/tlc-capture-exchange.sh",
286
+ timeout: 30
287
+ }]
288
+ }]
289
+ }
290
+ };
291
+
292
+ if (fs.existsSync(settingsPath)) {
293
+ // Merge: preserve existing permissions, add missing hooks
294
+ try {
295
+ const existing = JSON.parse(fs.readFileSync(settingsPath, 'utf8'));
296
+ // Merge permissions (union)
297
+ if (existing.permissions && existing.permissions.allow) {
298
+ const existingSet = new Set(existing.permissions.allow);
299
+ for (const perm of settingsTemplate.permissions.allow) {
300
+ existingSet.add(perm);
301
+ }
302
+ existing.permissions.allow = [...existingSet];
303
+ } else {
304
+ existing.permissions = settingsTemplate.permissions;
305
+ }
306
+ // Add hooks if not present
307
+ if (!existing.hooks) {
308
+ existing.hooks = settingsTemplate.hooks;
309
+ }
310
+ fs.writeFileSync(settingsPath, JSON.stringify(existing, null, 2) + '\n');
311
+ return true;
312
+ } catch (err) {
313
+ // If we can't parse existing, don't overwrite
314
+ return false;
315
+ }
316
+ } else {
317
+ fs.writeFileSync(settingsPath, JSON.stringify(settingsTemplate, null, 2) + '\n');
318
+ return true;
319
+ }
320
+ }
321
+
153
322
  async function main() {
154
323
  const args = process.argv.slice(2);
155
324
 
@@ -4,44 +4,63 @@ const fs = require('fs');
4
4
  const path = require('path');
5
5
  const os = require('os');
6
6
 
7
- // Get source and destination directories
8
- const srcDir = path.join(__dirname, '..', '.claude', 'commands', 'tlc');
9
- const destDir = path.join(os.homedir(), '.claude', 'commands', 'tlc');
7
+ const packageRoot = path.join(__dirname, '..');
8
+ const claudeHome = path.join(os.homedir(), '.claude');
9
+
10
+ // Source directories (inside npm package)
11
+ const commandsSrcDir = path.join(packageRoot, '.claude', 'commands', 'tlc');
12
+ const hooksSrcDir = path.join(packageRoot, '.claude', 'hooks');
13
+
14
+ // Destination directories (user's home)
15
+ const commandsDestDir = path.join(claudeHome, 'commands', 'tlc');
16
+ const hooksDestDir = path.join(claudeHome, 'hooks');
10
17
 
11
- // Create destination directory if it doesn't exist
12
18
  function ensureDir(dir) {
13
19
  if (!fs.existsSync(dir)) {
14
20
  fs.mkdirSync(dir, { recursive: true });
15
21
  }
16
22
  }
17
23
 
18
- // Copy all .md files from source to destination
24
+ // Copy all .md command files
19
25
  function copyCommands() {
20
- try {
21
- // Ensure destination exists
22
- ensureDir(destDir);
26
+ if (!fs.existsSync(commandsSrcDir)) return 0;
27
+ ensureDir(commandsDestDir);
23
28
 
24
- // Check if source exists
25
- if (!fs.existsSync(srcDir)) {
26
- // Silent exit if source doesn't exist (might be dev install)
27
- return;
28
- }
29
+ const files = fs.readdirSync(commandsSrcDir).filter(f => f.endsWith('.md'));
30
+ let copied = 0;
31
+ for (const file of files) {
32
+ fs.copyFileSync(path.join(commandsSrcDir, file), path.join(commandsDestDir, file));
33
+ copied++;
34
+ }
35
+ return copied;
36
+ }
29
37
 
30
- // Get all .md files
31
- const files = fs.readdirSync(srcDir).filter(f => f.endsWith('.md'));
38
+ // Copy all .sh hook files
39
+ function copyHooks() {
40
+ if (!fs.existsSync(hooksSrcDir)) return 0;
41
+ ensureDir(hooksDestDir);
32
42
 
33
- let copied = 0;
34
- for (const file of files) {
35
- const src = path.join(srcDir, file);
36
- const dest = path.join(destDir, file);
43
+ const files = fs.readdirSync(hooksSrcDir).filter(f => f.endsWith('.sh'));
44
+ let copied = 0;
45
+ for (const file of files) {
46
+ const dest = path.join(hooksDestDir, file);
47
+ fs.copyFileSync(path.join(hooksSrcDir, file), dest);
48
+ fs.chmodSync(dest, 0o755);
49
+ copied++;
50
+ }
51
+ return copied;
52
+ }
37
53
 
38
- // Copy file (overwrite if exists)
39
- fs.copyFileSync(src, dest);
40
- copied++;
41
- }
54
+ function postinstall() {
55
+ try {
56
+ const commands = copyCommands();
57
+ const hooks = copyHooks();
42
58
 
43
- if (copied > 0) {
44
- console.log(`\x1b[32m✓\x1b[0m TLC: Installed ${copied} commands to ~/.claude/commands/tlc/`);
59
+ if (commands > 0) {
60
+ console.log(`\x1b[32m✓\x1b[0m TLC: Installed ${commands} commands to ~/.claude/commands/tlc/`);
61
+ }
62
+ if (hooks > 0) {
63
+ console.log(`\x1b[32m✓\x1b[0m TLC: Installed ${hooks} hooks to ~/.claude/hooks/`);
45
64
  }
46
65
  } catch (err) {
47
66
  // Silent fail - don't break npm install
@@ -51,4 +70,4 @@ function copyCommands() {
51
70
  }
52
71
  }
53
72
 
54
- copyCommands();
73
+ postinstall();