tlc-claude-code 2.9.1 → 2.10.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.
|
@@ -106,14 +106,14 @@ process.stdout.write(JSON.stringify(result));" 2>/dev/null
|
|
|
106
106
|
After `resolveRouting` returns, immediately write `.tlc/.build-routing-active` with the active provider name from `models[0]` before doing any other build work. Remove `.tlc/.build-routing-active` on completion, cancellation, or failure cleanup.
|
|
107
107
|
|
|
108
108
|
**Routing decision:**
|
|
109
|
-
-
|
|
110
|
-
- If
|
|
109
|
+
- **ALWAYS use Orchestrator Mode.** Claude never writes code inline. The routing config determines which provider the orchestrator dispatches TO (codex, claude session, gemini), but Claude in this conversation is always the PM.
|
|
110
|
+
- If the orchestrator is unreachable, auto-recover it (restart container, deploy latest code). If recovery fails, STOP — do not fall back to inline code.
|
|
111
111
|
|
|
112
|
-
## ORCHESTRATOR MODE
|
|
112
|
+
## ORCHESTRATOR MODE (ALWAYS)
|
|
113
113
|
|
|
114
|
-
|
|
114
|
+
Claude is the **project manager**. Claude reads the plan, breaks tasks into small prompts, and dispatches each to the tlc-core orchestrator. Claude does NOT write code. This is not conditional on routing — it is always the mode.
|
|
115
115
|
|
|
116
|
-
|
|
116
|
+
The `models[0]` value from routing determines which provider the orchestrator uses (`codex`, `claude`, `gemini`), not whether Claude writes code inline.
|
|
117
117
|
|
|
118
118
|
### Step O1: Read the Plan
|
|
119
119
|
|
|
@@ -254,11 +254,9 @@ After PR is created (or phase completes):
|
|
|
254
254
|
- Mark completed tasks `[x]` in PLAN.md
|
|
255
255
|
- Report final summary
|
|
256
256
|
|
|
257
|
-
##
|
|
257
|
+
## AGENT INSTRUCTIONS (Reference for Dispatched Sessions)
|
|
258
258
|
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
The existing build instructions below are the Inline Mode instructions and should be followed unchanged.
|
|
259
|
+
**These instructions are NOT for Claude in the main conversation.** They are the reference for what the dispatched orchestrator agent (Codex, Claude session, or Gemini) should do inside its tmux session. Claude packages these into the dispatch prompt — Claude does not execute them inline.
|
|
262
260
|
|
|
263
261
|
## Engineering Standards
|
|
264
262
|
|
|
@@ -19,9 +19,62 @@ For brand new projects with no code, use `/tlc:new-project` instead.
|
|
|
19
19
|
|
|
20
20
|
## Process
|
|
21
21
|
|
|
22
|
-
### 0.
|
|
22
|
+
### 0. Orchestrator Enforcement (runs first, always)
|
|
23
23
|
|
|
24
|
-
**Before anything else**,
|
|
24
|
+
**Before anything else**, verify the orchestrator is available. All code execution goes through it — no exceptions.
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
# Check orchestrator health
|
|
28
|
+
if curl -sf --max-time 2 http://localhost:3100/health > /dev/null 2>&1; then
|
|
29
|
+
echo "Orchestrator: ✅ healthy"
|
|
30
|
+
else
|
|
31
|
+
echo "Orchestrator: ❌ not running — attempting recovery..."
|
|
32
|
+
# Try to find and restart the orchestrator container
|
|
33
|
+
ORCH_CONTAINER=$(docker ps -a --format '{{.Names}}' 2>/dev/null | grep "orchestrator" | head -1)
|
|
34
|
+
if [ -n "$ORCH_CONTAINER" ]; then
|
|
35
|
+
docker start "$ORCH_CONTAINER" 2>/dev/null
|
|
36
|
+
sleep 3
|
|
37
|
+
fi
|
|
38
|
+
# If still down and tlc-core source exists, deploy and start
|
|
39
|
+
if ! curl -sf --max-time 2 http://localhost:3100/health > /dev/null 2>&1; then
|
|
40
|
+
if command -v tlc-core >/dev/null 2>&1; then
|
|
41
|
+
tlc-core start &
|
|
42
|
+
sleep 5
|
|
43
|
+
fi
|
|
44
|
+
fi
|
|
45
|
+
# Final check
|
|
46
|
+
if curl -sf --max-time 2 http://localhost:3100/health > /dev/null 2>&1; then
|
|
47
|
+
echo "Orchestrator: ✅ recovered"
|
|
48
|
+
else
|
|
49
|
+
echo "Orchestrator: ❌ FAILED — code execution will not work"
|
|
50
|
+
echo "Install tlc-core: git clone git@github.com:TwentyTwoLabs22/tlc-core.git && cd cli && npm i && npm link"
|
|
51
|
+
echo "Then run: tlc-core start"
|
|
52
|
+
fi
|
|
53
|
+
fi
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
Also verify CodeDB and agent runner:
|
|
57
|
+
|
|
58
|
+
```bash
|
|
59
|
+
# CodeDB
|
|
60
|
+
if ! curl -sf --max-time 1 http://localhost:7719/health > /dev/null 2>&1; then
|
|
61
|
+
if command -v codedb >/dev/null 2>&1; then
|
|
62
|
+
codedb serve . &
|
|
63
|
+
echo "CodeDB: ✅ started"
|
|
64
|
+
else
|
|
65
|
+
echo "CodeDB: ❌ not installed — run: npx tlc-claude-code"
|
|
66
|
+
fi
|
|
67
|
+
fi
|
|
68
|
+
|
|
69
|
+
# Agent runner container
|
|
70
|
+
if ! docker ps --format '{{.Names}}' 2>/dev/null | grep -q "tlc-agent-runner"; then
|
|
71
|
+
docker start tlc-agent-runner 2>/dev/null && echo "Agent Runner: ✅ started" || echo "Agent Runner: ❌ not available"
|
|
72
|
+
fi
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
### 0b. Upgrade Check
|
|
76
|
+
|
|
77
|
+
**After orchestrator is verified**, check if this is already a TLC project:
|
|
25
78
|
|
|
26
79
|
```bash
|
|
27
80
|
# Check for existing TLC markers
|
|
@@ -100,14 +100,12 @@ process.stdout.write(JSON.stringify(result));" 2>/dev/null
|
|
|
100
100
|
After `resolveRouting` returns, immediately write `.tlc/.quick-routing-active` with the active provider name from `models[0]` before doing any other quick work. Remove `.tlc/.quick-routing-active` on completion, cancellation, or failure cleanup.
|
|
101
101
|
|
|
102
102
|
**Routing decision:**
|
|
103
|
-
-
|
|
104
|
-
- If
|
|
103
|
+
- **ALWAYS use Orchestrator Mode.** Claude never writes code inline. Routing determines which provider the orchestrator dispatches to.
|
|
104
|
+
- If orchestrator is down, auto-recover. If recovery fails, STOP — do not fall back to inline.
|
|
105
105
|
|
|
106
|
-
## ORCHESTRATOR MODE
|
|
106
|
+
## ORCHESTRATOR MODE (ALWAYS)
|
|
107
107
|
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
Claude does not execute the quick-task instructions inline in this path. Claude acts as the orchestrator for the routed provider run:
|
|
108
|
+
Claude acts as the orchestrator — dispatches the quick task to the orchestrator, monitors completion, verifies result. Claude does NOT write code.
|
|
111
109
|
|
|
112
110
|
1. Treat Claude as the orchestrator for a small, test-first routed task rather than executing the work inline.
|
|
113
111
|
2. Gather the minimal project context needed for the quick task, then package a focused prompt with the task request, expected failing test, implementation scope, and verification target.
|
|
@@ -123,12 +121,9 @@ Claude does not execute the quick-task instructions inline in this path. Claude
|
|
|
123
121
|
- If the provider returns incomplete code or missing tests, issue a targeted retry for the missing part.
|
|
124
122
|
7. When finished, display the routed provider result, persist any captured memory, remove `.tlc/.quick-routing-active`, and stop. Do **not** execute Inline Mode afterward.
|
|
125
123
|
|
|
126
|
-
##
|
|
127
|
-
|
|
128
|
-
Use this mode only when `models[0]` **IS** `claude`.
|
|
129
|
-
|
|
130
|
-
The existing quick-task instructions below are the Inline Mode instructions and should be followed unchanged.
|
|
124
|
+
## AGENT INSTRUCTIONS (Reference for Dispatched Sessions)
|
|
131
125
|
|
|
126
|
+
**These instructions are NOT for Claude in the main conversation.** They are packaged into the dispatch prompt for the orchestrator agent.
|
|
132
127
|
|
|
133
128
|
## Engineering Standards
|
|
134
129
|
|
|
@@ -181,6 +181,31 @@ Only mention upgrade details in `--verbose` mode.
|
|
|
181
181
|
|
|
182
182
|
## One-Pass Detection
|
|
183
183
|
|
|
184
|
+
### Step 0: Quick Health Check
|
|
185
|
+
|
|
186
|
+
Before phase detection, run a fast health check (no auto-recovery — that's the SessionStart hook's job). Just report status in one line:
|
|
187
|
+
|
|
188
|
+
```bash
|
|
189
|
+
# Check key systems in parallel (each with 1s timeout)
|
|
190
|
+
CODEDB=$(curl -sf --max-time 1 http://localhost:7719/health > /dev/null 2>&1 && echo "✅" || echo "❌")
|
|
191
|
+
ORCH=$(curl -sf --max-time 1 http://localhost:3100/health > /dev/null 2>&1 && echo "✅" || echo "❌")
|
|
192
|
+
RUNNER=$(docker ps --format '{{.Names}}' 2>/dev/null | grep -q "tlc-agent-runner" && echo "✅" || echo "❌")
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
Print one compact line:
|
|
196
|
+
|
|
197
|
+
```
|
|
198
|
+
Systems: CodeDB ${CODEDB} | Orchestrator ${ORCH} | Agent Runner ${RUNNER}
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
If any system is ❌, **auto-recover immediately** before continuing:
|
|
202
|
+
|
|
203
|
+
1. CodeDB ❌ → run `codedb serve . &` (or `npx tlc-claude-code` if binary missing), wait 2s, re-check
|
|
204
|
+
2. Orchestrator ❌ → find orchestrator container (`docker ps | grep orchestrator`), deploy latest code from `../tlc-core/orchestrator/`, restart container, wait 3s, re-check
|
|
205
|
+
3. Agent Runner ❌ → `docker start tlc-agent-runner` if stopped, report if container doesn't exist
|
|
206
|
+
|
|
207
|
+
After recovery attempts, print updated status. Only continue to phase detection after all recoverable systems are up. If recovery fails, print the failure and continue anyway — don't block indefinitely.
|
|
208
|
+
|
|
184
209
|
### Step 1: Load Core Context
|
|
185
210
|
|
|
186
211
|
Read, in this order:
|
|
@@ -256,11 +281,22 @@ Backward compatibility:
|
|
|
256
281
|
|
|
257
282
|
## Output Format
|
|
258
283
|
|
|
259
|
-
Normal output must stay
|
|
284
|
+
Normal output must stay compact — health line + phase status + action.
|
|
260
285
|
|
|
261
286
|
Use this pattern:
|
|
262
287
|
|
|
263
288
|
```text
|
|
289
|
+
Systems: CodeDB ✅ | Orchestrator ✅ | Agent Runner ✅
|
|
290
|
+
TLC v{version} | Phase {PHASE_ID}: {Name} | {done}/{total} tasks done
|
|
291
|
+
Next: {action summary}
|
|
292
|
+
Running /tlc:{command} {PHASE_ID}...
|
|
293
|
+
```
|
|
294
|
+
|
|
295
|
+
If any system is down:
|
|
296
|
+
|
|
297
|
+
```text
|
|
298
|
+
Systems: CodeDB ✅ | Orchestrator ❌ | Agent Runner ✅
|
|
299
|
+
⚠️ Orchestrator down — run /tlc:init to recover
|
|
264
300
|
TLC v{version} | Phase {PHASE_ID}: {Name} | {done}/{total} tasks done
|
|
265
301
|
Next: {action summary}
|
|
266
302
|
Running /tlc:{command} {PHASE_ID}...
|
|
@@ -269,6 +305,7 @@ Running /tlc:{command} {PHASE_ID}...
|
|
|
269
305
|
If there is nothing safe to auto-run:
|
|
270
306
|
|
|
271
307
|
```text
|
|
308
|
+
Systems: CodeDB ✅ | Orchestrator ✅ | Agent Runner ✅
|
|
272
309
|
TLC v{version} | All phases complete
|
|
273
310
|
Next: release or start the next milestone
|
|
274
311
|
Run /tlc:complete or /tlc:new-milestone
|
|
@@ -338,7 +375,8 @@ Run /tlc:complete or /tlc:new-milestone
|
|
|
338
375
|
## Example
|
|
339
376
|
|
|
340
377
|
```text
|
|
341
|
-
|
|
378
|
+
Systems: CodeDB ✅ | Orchestrator ✅ | Agent Runner ✅
|
|
379
|
+
TLC v2.9.2 | Phase TLC-8: Auth System | 3/5 tasks done
|
|
342
380
|
Next: build task 4 (JWT middleware)
|
|
343
381
|
Running /tlc:build TLC-8...
|
|
344
382
|
```
|
|
@@ -1,86 +1,98 @@
|
|
|
1
1
|
#!/bin/bash
|
|
2
|
-
# TLC
|
|
3
|
-
#
|
|
4
|
-
#
|
|
5
|
-
# 3. Probe LLM providers and write persistent router state
|
|
2
|
+
# TLC Session Init — Comprehensive Health Check
|
|
3
|
+
# Verifies ALL systems and reports status clearly.
|
|
4
|
+
# No silent failures. No partial checks.
|
|
6
5
|
|
|
7
6
|
if [ ! -f ".tlc.json" ]; then
|
|
8
7
|
exit 0
|
|
9
8
|
fi
|
|
10
9
|
|
|
10
|
+
PROJECT_DIR="${CLAUDE_PROJECT_DIR:-$(pwd)}"
|
|
11
|
+
TLC_PORT="${TLC_PORT:-3147}"
|
|
12
|
+
TLC_CORE_PORT="${TLC_CORE_PORT:-3100}"
|
|
13
|
+
ERRORS=0
|
|
14
|
+
WARNINGS=0
|
|
15
|
+
|
|
11
16
|
echo "TLC project detected. All work goes through /tlc commands. Run /tlc for current status and next action."
|
|
17
|
+
echo ""
|
|
18
|
+
echo "── System Health Check ──────────────────────────────"
|
|
19
|
+
|
|
20
|
+
# ─── 1. TLC Package Version ──────────────────────────────
|
|
21
|
+
INSTALLED_VER=$(node -e "try{console.log(require('tlc-claude-code/package.json').version)}catch{try{console.log(require('$PROJECT_DIR/package.json').version)}catch{console.log('not-installed')}}" 2>/dev/null)
|
|
22
|
+
LATEST_VER=$(npm view tlc-claude-code version 2>/dev/null || echo "unknown")
|
|
23
|
+
PROJECT_VER=$(node -e "try{console.log(require('./.tlc.json').tlcVersion||'unknown')}catch{console.log('unknown')}" 2>/dev/null)
|
|
12
24
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
25
|
+
if [ "$INSTALLED_VER" = "not-installed" ]; then
|
|
26
|
+
echo " TLC Package: ❌ not installed (run: npm i -g tlc-claude-code)"
|
|
27
|
+
ERRORS=$((ERRORS + 1))
|
|
28
|
+
elif [ "$INSTALLED_VER" != "$LATEST_VER" ] && [ "$LATEST_VER" != "unknown" ]; then
|
|
29
|
+
echo " TLC Package: ⏳ ${INSTALLED_VER} → ${LATEST_VER} — auto-updating..."
|
|
30
|
+
npm i -g tlc-claude-code@latest > /dev/null 2>&1
|
|
31
|
+
NEW_VER=$(node -e "try{console.log(require('tlc-claude-code/package.json').version)}catch{console.log('?')}" 2>/dev/null)
|
|
32
|
+
if [ "$NEW_VER" = "$LATEST_VER" ]; then
|
|
33
|
+
echo " TLC Package: ✅ updated to v${NEW_VER}"
|
|
34
|
+
else
|
|
35
|
+
echo " TLC Package: ⚠️ update failed — still on v${INSTALLED_VER}"
|
|
36
|
+
WARNINGS=$((WARNINGS + 1))
|
|
21
37
|
fi
|
|
38
|
+
else
|
|
39
|
+
echo " TLC Package: ✅ v${INSTALLED_VER} (latest)"
|
|
22
40
|
fi
|
|
23
41
|
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
42
|
+
# ─── 2. TLC Memory System ────────────────────────────────
|
|
43
|
+
mkdir -p "$PROJECT_DIR/.tlc/memory/team/decisions" \
|
|
44
|
+
"$PROJECT_DIR/.tlc/memory/team/gotchas" \
|
|
45
|
+
"$PROJECT_DIR/.tlc/memory/.local/sessions" 2>/dev/null
|
|
27
46
|
|
|
28
|
-
TLC_PORT="${TLC_PORT:-3147}"
|
|
29
47
|
if curl -sf --max-time 1 "http://localhost:${TLC_PORT}/api/health" > /dev/null 2>&1; then
|
|
30
|
-
|
|
48
|
+
echo " TLC Server: ✅ running (:${TLC_PORT})"
|
|
49
|
+
# Drain spool
|
|
50
|
+
SPOOL_DRAIN=""
|
|
51
|
+
if node -e "require('tlc-claude-code/server/lib/capture/spool-processor')" 2>/dev/null; then
|
|
52
|
+
SPOOL_DRAIN="require('tlc-claude-code/server/lib/capture/spool-processor').processSpool('$PROJECT_DIR')"
|
|
53
|
+
elif [ -f "$PROJECT_DIR/server/lib/capture/spool-processor.js" ]; then
|
|
54
|
+
SPOOL_DRAIN="require('$PROJECT_DIR/server/lib/capture/spool-processor').processSpool('$PROJECT_DIR')"
|
|
55
|
+
fi
|
|
56
|
+
[ -n "$SPOOL_DRAIN" ] && node -e "$SPOOL_DRAIN" 2>/dev/null
|
|
31
57
|
else
|
|
32
58
|
PLIST="$HOME/Library/LaunchAgents/com.tlc.server.plist"
|
|
33
|
-
|
|
34
59
|
if [ -f "$PLIST" ]; then
|
|
35
60
|
launchctl kickstart -k "gui/$(id -u)/com.tlc.server" 2>/dev/null
|
|
36
61
|
elif [ -f "$PROJECT_DIR/server/index.js" ]; then
|
|
37
62
|
nohup node "$PROJECT_DIR/server/index.js" > "$HOME/.tlc/logs/server.log" 2>&1 &
|
|
38
63
|
fi
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
64
|
+
sleep 2
|
|
65
|
+
if curl -sf --max-time 1 "http://localhost:${TLC_PORT}/api/health" > /dev/null 2>&1; then
|
|
66
|
+
echo " TLC Server: ✅ started (:${TLC_PORT})"
|
|
67
|
+
else
|
|
68
|
+
echo " TLC Server: ❌ failed to start"
|
|
69
|
+
ERRORS=$((ERRORS + 1))
|
|
70
|
+
fi
|
|
44
71
|
fi
|
|
45
72
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
echo "
|
|
73
|
+
SPOOL_FILE="$PROJECT_DIR/.tlc/memory/.spool.jsonl"
|
|
74
|
+
SPOOL_COUNT=0
|
|
75
|
+
if [ -f "$SPOOL_FILE" ]; then
|
|
76
|
+
SPOOL_COUNT=$(wc -l < "$SPOOL_FILE" 2>/dev/null || echo "0")
|
|
77
|
+
fi
|
|
78
|
+
SPOOL_COUNT=$(echo "$SPOOL_COUNT" | tr -d ' ')
|
|
79
|
+
if [ "$SPOOL_COUNT" -gt 0 ] 2>/dev/null; then
|
|
80
|
+
echo " Memory Spool: ⚠️ ${SPOOL_COUNT} entries pending drain"
|
|
81
|
+
WARNINGS=$((WARNINGS + 1))
|
|
54
82
|
else
|
|
55
|
-
|
|
56
|
-
if command -v tlc-core >/dev/null 2>&1; then
|
|
57
|
-
echo "tlc-core orchestrator: not running — starting..."
|
|
58
|
-
tlc-core start > /dev/null 2>&1 &
|
|
59
|
-
# Wait up to 15s for health
|
|
60
|
-
for i in 1 2 3 4 5; do
|
|
61
|
-
sleep 3
|
|
62
|
-
if curl -sf --max-time 1 "http://localhost:${TLC_CORE_PORT}/health" > /dev/null 2>&1; then
|
|
63
|
-
echo "tlc-core orchestrator: started successfully"
|
|
64
|
-
break
|
|
65
|
-
fi
|
|
66
|
-
done
|
|
67
|
-
if ! curl -sf --max-time 1 "http://localhost:${TLC_CORE_PORT}/health" > /dev/null 2>&1; then
|
|
68
|
-
echo "tlc-core orchestrator: failed to start. Run 'tlc-core start' manually."
|
|
69
|
-
fi
|
|
70
|
-
else
|
|
71
|
-
echo "tlc-core orchestrator: not installed. Run: git clone git@github.com:TwentyTwoLabs22/tlc-core.git && cd cli && npm install && npm link"
|
|
72
|
-
fi
|
|
83
|
+
echo " Memory: ✅ ready (spool empty)"
|
|
73
84
|
fi
|
|
74
85
|
|
|
75
|
-
# ─── CodeDB
|
|
86
|
+
# ─── 3. CodeDB ───────────────────────────────────────────
|
|
76
87
|
if command -v codedb >/dev/null 2>&1; then
|
|
77
88
|
if curl -sf --max-time 1 "http://localhost:7719/health" > /dev/null 2>&1; then
|
|
78
|
-
|
|
89
|
+
CODEDB_FILES=$(curl -sf --max-time 1 "http://localhost:7719/status" 2>/dev/null | node -e "try{const d=JSON.parse(require('fs').readFileSync('/dev/stdin','utf8'));console.log(d.files||'?')}catch{console.log('?')}" 2>/dev/null || echo "?")
|
|
90
|
+
echo " CodeDB: ✅ running (${CODEDB_FILES} files indexed)"
|
|
79
91
|
else
|
|
80
92
|
codedb serve "$PROJECT_DIR" > /dev/null 2>&1 &
|
|
81
|
-
echo "
|
|
93
|
+
echo " CodeDB: ✅ started indexing"
|
|
82
94
|
fi
|
|
83
|
-
# Ensure .mcp.json
|
|
95
|
+
# Ensure .mcp.json
|
|
84
96
|
if [ ! -f "$PROJECT_DIR/.mcp.json" ]; then
|
|
85
97
|
cat > "$PROJECT_DIR/.mcp.json" <<'MCPEOF'
|
|
86
98
|
{
|
|
@@ -92,126 +104,269 @@ if command -v codedb >/dev/null 2>&1; then
|
|
|
92
104
|
}
|
|
93
105
|
}
|
|
94
106
|
MCPEOF
|
|
95
|
-
echo "
|
|
107
|
+
echo " CodeDB MCP: ✅ created .mcp.json"
|
|
108
|
+
fi
|
|
109
|
+
else
|
|
110
|
+
# Auto-install CodeDB binary
|
|
111
|
+
echo " CodeDB: ⏳ not installed — auto-installing..."
|
|
112
|
+
if npx -y tlc-claude-code 2>/dev/null | tail -1; then
|
|
113
|
+
if command -v codedb >/dev/null 2>&1; then
|
|
114
|
+
codedb serve "$PROJECT_DIR" > /dev/null 2>&1 &
|
|
115
|
+
echo " CodeDB: ✅ installed and started"
|
|
116
|
+
else
|
|
117
|
+
echo " CodeDB: ❌ install failed"
|
|
118
|
+
ERRORS=$((ERRORS + 1))
|
|
119
|
+
fi
|
|
120
|
+
else
|
|
121
|
+
echo " CodeDB: ❌ install failed"
|
|
122
|
+
ERRORS=$((ERRORS + 1))
|
|
96
123
|
fi
|
|
97
124
|
fi
|
|
98
125
|
|
|
99
|
-
# ───
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
126
|
+
# ─── 4. tlc-core Orchestrator + Containers ────────────────
|
|
127
|
+
if [ "${TLC_CORE_AUTOSTART}" = "false" ]; then
|
|
128
|
+
echo " Orchestrator: ⏸ disabled (TLC_CORE_AUTOSTART=false)"
|
|
129
|
+
elif curl -sf --max-time 2 "http://localhost:${TLC_CORE_PORT}/health" > /dev/null 2>&1; then
|
|
130
|
+
ORCH_HEALTH=$(curl -sf --max-time 2 "http://localhost:${TLC_CORE_PORT}/health" 2>/dev/null)
|
|
131
|
+
PG_STATUS=$(echo "$ORCH_HEALTH" | node -e "try{console.log(JSON.parse(require('fs').readFileSync('/dev/stdin','utf8')).postgres)}catch{console.log('?')}" 2>/dev/null)
|
|
132
|
+
DOCKER_STATUS=$(echo "$ORCH_HEALTH" | node -e "try{console.log(JSON.parse(require('fs').readFileSync('/dev/stdin','utf8')).docker)}catch{console.log('?')}" 2>/dev/null)
|
|
133
|
+
RUNNING_SESSIONS=$(curl -sf --max-time 2 "http://localhost:${TLC_CORE_PORT}/sessions" 2>/dev/null | node -e "try{const d=JSON.parse(require('fs').readFileSync('/dev/stdin','utf8'));const r=d.filter(s=>s.status==='running');console.log(r.length+'/'+d.length)}catch{console.log('?')}" 2>/dev/null)
|
|
134
|
+
echo " Orchestrator: ✅ healthy (pg:${PG_STATUS}, docker:${DOCKER_STATUS}, sessions:${RUNNING_SESSIONS})"
|
|
135
|
+
|
|
136
|
+
# Check agent-runner container
|
|
137
|
+
if docker ps --format '{{.Names}}' 2>/dev/null | grep -q "tlc-agent-runner"; then
|
|
138
|
+
TMUX_COUNT=$(docker exec tlc-agent-runner tmux list-sessions 2>/dev/null | wc -l | tr -d ' ')
|
|
139
|
+
echo " Agent Runner: ✅ running (${TMUX_COUNT} tmux sessions)"
|
|
140
|
+
else
|
|
141
|
+
echo " Agent Runner: ❌ container not running"
|
|
142
|
+
ERRORS=$((ERRORS + 1))
|
|
143
|
+
fi
|
|
144
|
+
|
|
145
|
+
# Check session monitor + watchdog
|
|
146
|
+
ORCH_LOGS=$(docker logs tlc-core-orchestrator-1 --tail 50 2>&1)
|
|
147
|
+
MONITOR_OK=false
|
|
148
|
+
WATCHDOG_OK=false
|
|
149
|
+
if echo "$ORCH_LOGS" | grep -q "Session monitor started"; then
|
|
150
|
+
MONITOR_OK=true
|
|
151
|
+
echo " Session Monitor: ✅ active (10s interval)"
|
|
152
|
+
fi
|
|
153
|
+
if echo "$ORCH_LOGS" | grep -q "Watchdog started\|watchdog.*Started"; then
|
|
154
|
+
WATCHDOG_OK=true
|
|
155
|
+
echo " Watchdog: ✅ active (60s interval)"
|
|
156
|
+
fi
|
|
157
|
+
|
|
158
|
+
# Auto-recover: if monitor or watchdog missing, deploy latest code and restart
|
|
159
|
+
if [ "$MONITOR_OK" = false ] || [ "$WATCHDOG_OK" = false ]; then
|
|
160
|
+
echo " Monitor/Watchdog: ⏳ missing — deploying latest code and restarting..."
|
|
161
|
+
# Find orchestrator source
|
|
162
|
+
ORCH_SRC=""
|
|
163
|
+
if [ -d "$PROJECT_DIR/../tlc-core/orchestrator" ]; then
|
|
164
|
+
ORCH_SRC="$PROJECT_DIR/../tlc-core/orchestrator"
|
|
165
|
+
elif [ -d "$(dirname "$PROJECT_DIR")/tlc-core/orchestrator" ]; then
|
|
166
|
+
ORCH_SRC="$(dirname "$PROJECT_DIR")/tlc-core/orchestrator"
|
|
167
|
+
fi
|
|
168
|
+
if [ -n "$ORCH_SRC" ]; then
|
|
169
|
+
ORCH_CONTAINER=$(docker ps --format '{{.Names}}' 2>/dev/null | grep "orchestrator" | head -1)
|
|
170
|
+
if [ -n "$ORCH_CONTAINER" ]; then
|
|
171
|
+
docker cp "$ORCH_SRC/lib/." "$ORCH_CONTAINER:/app/lib/" 2>/dev/null
|
|
172
|
+
docker cp "$ORCH_SRC/index.js" "$ORCH_CONTAINER:/app/index.js" 2>/dev/null
|
|
173
|
+
docker cp "$ORCH_SRC/migrations/." "$ORCH_CONTAINER:/app/migrations/" 2>/dev/null
|
|
174
|
+
docker restart "$ORCH_CONTAINER" > /dev/null 2>&1
|
|
175
|
+
sleep 3
|
|
176
|
+
if curl -sf --max-time 2 "http://localhost:${TLC_CORE_PORT}/health" > /dev/null 2>&1; then
|
|
177
|
+
echo " Monitor/Watchdog: ✅ restarted with latest code"
|
|
178
|
+
else
|
|
179
|
+
echo " Monitor/Watchdog: ❌ restart failed"
|
|
180
|
+
ERRORS=$((ERRORS + 1))
|
|
181
|
+
fi
|
|
182
|
+
else
|
|
183
|
+
echo " Monitor/Watchdog: ❌ orchestrator container not found"
|
|
184
|
+
ERRORS=$((ERRORS + 1))
|
|
185
|
+
fi
|
|
186
|
+
else
|
|
187
|
+
[ "$MONITOR_OK" = false ] && echo " Session Monitor: ❌ not running (tlc-core source not found)" && ERRORS=$((ERRORS + 1))
|
|
188
|
+
[ "$WATCHDOG_OK" = false ] && echo " Watchdog: ⚠️ not detected" && WARNINGS=$((WARNINGS + 1))
|
|
189
|
+
fi
|
|
190
|
+
fi
|
|
191
|
+
else
|
|
192
|
+
if command -v tlc-core >/dev/null 2>&1; then
|
|
193
|
+
echo " Orchestrator: ❌ not running — starting..."
|
|
194
|
+
tlc-core start > /dev/null 2>&1 &
|
|
195
|
+
for i in 1 2 3 4 5; do
|
|
196
|
+
sleep 3
|
|
197
|
+
curl -sf --max-time 1 "http://localhost:${TLC_CORE_PORT}/health" > /dev/null 2>&1 && break
|
|
198
|
+
done
|
|
199
|
+
if curl -sf --max-time 1 "http://localhost:${TLC_CORE_PORT}/health" > /dev/null 2>&1; then
|
|
200
|
+
echo " Orchestrator: ✅ started"
|
|
201
|
+
else
|
|
202
|
+
echo " Orchestrator: ❌ failed to start. Run 'tlc-core start' manually."
|
|
203
|
+
ERRORS=$((ERRORS + 1))
|
|
204
|
+
fi
|
|
205
|
+
else
|
|
206
|
+
echo " Orchestrator: ❌ not installed"
|
|
207
|
+
ERRORS=$((ERRORS + 1))
|
|
208
|
+
fi
|
|
209
|
+
fi
|
|
210
|
+
|
|
211
|
+
# ─── 5. LLM CLI Versions ─────────────────────────────────
|
|
212
|
+
CLAUDE_VER=$(claude --version 2>/dev/null | head -1 || echo "not installed")
|
|
213
|
+
CODEX_VER=$(codex --version 2>/dev/null | head -1 || echo "not installed")
|
|
214
|
+
GEMINI_VER=$(gemini --version 2>/dev/null | head -1 || echo "not installed")
|
|
215
|
+
|
|
216
|
+
PROVIDER_COUNT=0
|
|
217
|
+
PROVIDER_LIST=""
|
|
218
|
+
if [ "$CLAUDE_VER" != "not installed" ]; then
|
|
219
|
+
PROVIDER_COUNT=$((PROVIDER_COUNT + 1))
|
|
220
|
+
PROVIDER_LIST="${PROVIDER_LIST}claude(${CLAUDE_VER}), "
|
|
111
221
|
fi
|
|
112
|
-
if [
|
|
113
|
-
|
|
222
|
+
if [ "$CODEX_VER" != "not installed" ]; then
|
|
223
|
+
PROVIDER_COUNT=$((PROVIDER_COUNT + 1))
|
|
224
|
+
PROVIDER_LIST="${PROVIDER_LIST}codex(${CODEX_VER}), "
|
|
114
225
|
fi
|
|
226
|
+
if [ "$GEMINI_VER" != "not installed" ]; then
|
|
227
|
+
PROVIDER_COUNT=$((PROVIDER_COUNT + 1))
|
|
228
|
+
PROVIDER_LIST="${PROVIDER_LIST}gemini(${GEMINI_VER}), "
|
|
229
|
+
fi
|
|
230
|
+
PROVIDER_LIST=$(echo "$PROVIDER_LIST" | sed 's/, $//')
|
|
115
231
|
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
#
|
|
119
|
-
|
|
120
|
-
|
|
232
|
+
if [ "$PROVIDER_COUNT" -gt 0 ]; then
|
|
233
|
+
echo " LLM Providers: ✅ ${PROVIDER_COUNT} available — ${PROVIDER_LIST}"
|
|
234
|
+
# Check for updates (non-blocking, just warn)
|
|
235
|
+
if [ "$CODEX_VER" != "not installed" ]; then
|
|
236
|
+
CODEX_LATEST=$(npm view @openai/codex version 2>/dev/null || echo "")
|
|
237
|
+
if [ -n "$CODEX_LATEST" ] && [ "$CODEX_VER" != *"$CODEX_LATEST"* ] 2>/dev/null; then
|
|
238
|
+
echo " Codex Update: ⚠️ latest: ${CODEX_LATEST} — run: npm i -g @openai/codex"
|
|
239
|
+
WARNINGS=$((WARNINGS + 1))
|
|
240
|
+
fi
|
|
241
|
+
fi
|
|
242
|
+
else
|
|
243
|
+
echo " LLM Providers: ❌ none found"
|
|
244
|
+
ERRORS=$((ERRORS + 1))
|
|
245
|
+
fi
|
|
121
246
|
|
|
247
|
+
# Write router state
|
|
122
248
|
STATE_DIR="$PROJECT_DIR/.tlc"
|
|
123
249
|
STATE_FILE="$STATE_DIR/.router-state.json"
|
|
124
250
|
mkdir -p "$STATE_DIR"
|
|
125
251
|
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
if [ "$STATE_AGE" -lt 3600 ]; then
|
|
131
|
-
STALE=false
|
|
132
|
-
fi
|
|
133
|
-
fi
|
|
134
|
-
|
|
135
|
-
if [ "$STALE" = true ]; then
|
|
136
|
-
# Probe each provider
|
|
137
|
-
CLAUDE_PATH=$(command -v claude 2>/dev/null || echo "")
|
|
138
|
-
CODEX_PATH=$(command -v codex 2>/dev/null || echo "")
|
|
139
|
-
GEMINI_PATH=$(command -v gemini 2>/dev/null || echo "")
|
|
140
|
-
|
|
141
|
-
CLAUDE_OK="false"
|
|
142
|
-
CODEX_OK="false"
|
|
143
|
-
GEMINI_OK="false"
|
|
144
|
-
|
|
145
|
-
[ -n "$CLAUDE_PATH" ] && CLAUDE_OK="true"
|
|
146
|
-
[ -n "$CODEX_PATH" ] && CODEX_OK="true"
|
|
147
|
-
[ -n "$GEMINI_PATH" ] && GEMINI_OK="true"
|
|
148
|
-
|
|
149
|
-
# Count available
|
|
150
|
-
AVAILABLE=0
|
|
151
|
-
[ "$CLAUDE_OK" = "true" ] && AVAILABLE=$((AVAILABLE + 1))
|
|
152
|
-
[ "$CODEX_OK" = "true" ] && AVAILABLE=$((AVAILABLE + 1))
|
|
153
|
-
[ "$GEMINI_OK" = "true" ] && AVAILABLE=$((AVAILABLE + 1))
|
|
154
|
-
|
|
155
|
-
# Read configured providers from .tlc.json
|
|
156
|
-
CONFIGURED_PROVIDERS=""
|
|
157
|
-
if command -v jq >/dev/null 2>&1; then
|
|
158
|
-
CONFIGURED_PROVIDERS=$(jq -r '.router.providers // {} | keys[]' .tlc.json 2>/dev/null | tr '\n' ',' | sed 's/,$//')
|
|
159
|
-
fi
|
|
252
|
+
CLAUDE_OK="false"; CODEX_OK="false"; GEMINI_OK="false"
|
|
253
|
+
[ "$CLAUDE_VER" != "not installed" ] && CLAUDE_OK="true"
|
|
254
|
+
[ "$CODEX_VER" != "not installed" ] && CODEX_OK="true"
|
|
255
|
+
[ "$GEMINI_VER" != "not installed" ] && GEMINI_OK="true"
|
|
160
256
|
|
|
161
|
-
|
|
162
|
-
cat > "$STATE_FILE" <<STATEEOF
|
|
257
|
+
cat > "$STATE_FILE" <<STATEEOF
|
|
163
258
|
{
|
|
164
259
|
"probed_at": "$(date -u +%Y-%m-%dT%H:%M:%SZ)",
|
|
165
260
|
"ttl_seconds": 3600,
|
|
166
261
|
"providers": {
|
|
167
|
-
"claude": {
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
},
|
|
171
|
-
"codex": {
|
|
172
|
-
"available": $CODEX_OK,
|
|
173
|
-
"path": "$CODEX_PATH"
|
|
174
|
-
},
|
|
175
|
-
"gemini": {
|
|
176
|
-
"available": $GEMINI_OK,
|
|
177
|
-
"path": "$GEMINI_PATH"
|
|
178
|
-
}
|
|
262
|
+
"claude": { "available": $CLAUDE_OK, "version": "$CLAUDE_VER" },
|
|
263
|
+
"codex": { "available": $CODEX_OK, "version": "$CODEX_VER" },
|
|
264
|
+
"gemini": { "available": $GEMINI_OK, "version": "$GEMINI_VER" }
|
|
179
265
|
},
|
|
180
|
-
"summary": {
|
|
181
|
-
"available_count": $AVAILABLE,
|
|
182
|
-
"configured": "$CONFIGURED_PROVIDERS"
|
|
183
|
-
}
|
|
266
|
+
"summary": { "available_count": $PROVIDER_COUNT }
|
|
184
267
|
}
|
|
185
268
|
STATEEOF
|
|
186
269
|
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
270
|
+
# ─── 6. Git + Remote Sync ────────────────────────────────
|
|
271
|
+
# Fetch remote to get accurate ahead/behind counts
|
|
272
|
+
git fetch --quiet 2>/dev/null
|
|
273
|
+
CURRENT_BRANCH=$(git branch --show-current 2>/dev/null)
|
|
274
|
+
BEHIND=$(git rev-list --count HEAD..@{u} 2>/dev/null || echo "?")
|
|
275
|
+
AHEAD=$(git rev-list --count @{u}..HEAD 2>/dev/null || echo "?")
|
|
276
|
+
|
|
277
|
+
if [ "$BEHIND" = "0" ] && [ "$AHEAD" = "0" ]; then
|
|
278
|
+
echo " Git (${CURRENT_BRANCH}): ✅ in sync with remote"
|
|
279
|
+
elif [ "$BEHIND" != "?" ] && [ "$BEHIND" -gt 0 ] 2>/dev/null; then
|
|
280
|
+
echo " Git (${CURRENT_BRANCH}): ⚠️ ${BEHIND} commits behind remote — run: git pull"
|
|
281
|
+
WARNINGS=$((WARNINGS + 1))
|
|
282
|
+
elif [ "$AHEAD" != "?" ] && [ "$AHEAD" -gt 0 ] 2>/dev/null; then
|
|
283
|
+
echo " Git (${CURRENT_BRANCH}): ⚠️ ${AHEAD} commits ahead — push pending"
|
|
284
|
+
WARNINGS=$((WARNINGS + 1))
|
|
198
285
|
else
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
286
|
+
echo " Git (${CURRENT_BRANCH}): ⚠️ remote tracking unknown"
|
|
287
|
+
WARNINGS=$((WARNINGS + 1))
|
|
288
|
+
fi
|
|
289
|
+
|
|
290
|
+
# ─── 7. Workspace Awareness ──────────────────────────────
|
|
291
|
+
WORKSPACE_FILE=""
|
|
292
|
+
CHECK_DIR="$PROJECT_DIR"
|
|
293
|
+
while [ "$CHECK_DIR" != "/" ]; do
|
|
294
|
+
if [ -f "$CHECK_DIR/.tlc-workspace.json" ]; then
|
|
295
|
+
WORKSPACE_FILE="$CHECK_DIR/.tlc-workspace.json"
|
|
296
|
+
break
|
|
203
297
|
fi
|
|
298
|
+
CHECK_DIR=$(dirname "$CHECK_DIR")
|
|
299
|
+
done
|
|
300
|
+
|
|
301
|
+
if [ -n "$WORKSPACE_FILE" ]; then
|
|
302
|
+
WORKSPACE_NAME=$(node -e "try{console.log(JSON.parse(require('fs').readFileSync('$WORKSPACE_FILE','utf8')).workspace)}catch{console.log('?')}" 2>/dev/null)
|
|
303
|
+
REPO_COUNT=$(node -e "try{console.log(Object.keys(JSON.parse(require('fs').readFileSync('$WORKSPACE_FILE','utf8')).repos).length)}catch{console.log('?')}" 2>/dev/null)
|
|
304
|
+
echo " Workspace: ✅ ${WORKSPACE_NAME} (${REPO_COUNT} repos)"
|
|
305
|
+
|
|
306
|
+
# Check each repo's sync status
|
|
307
|
+
WORKSPACE_ROOT=$(dirname "$WORKSPACE_FILE")
|
|
308
|
+
node -e "
|
|
309
|
+
const fs = require('fs');
|
|
310
|
+
const path = require('path');
|
|
311
|
+
const { execSync } = require('child_process');
|
|
312
|
+
const wsRoot = process.argv[1];
|
|
313
|
+
const ws = JSON.parse(fs.readFileSync(process.argv[2], 'utf8'));
|
|
314
|
+
for (const [name, repo] of Object.entries(ws.repos)) {
|
|
315
|
+
const rp = path.resolve(wsRoot, repo.path);
|
|
316
|
+
try {
|
|
317
|
+
fs.accessSync(rp);
|
|
318
|
+
// Fetch remote for accurate state
|
|
319
|
+
try { execSync('git -C ' + JSON.stringify(rp) + ' fetch --quiet', { stdio: ['pipe','pipe','pipe'], timeout: 10000 }); } catch {}
|
|
320
|
+
const branch = execSync('git -C ' + JSON.stringify(rp) + ' branch --show-current', { encoding: 'utf8', stdio: ['pipe','pipe','pipe'] }).trim();
|
|
321
|
+
let status = 'unknown';
|
|
322
|
+
try {
|
|
323
|
+
const behind = execSync('git -C ' + JSON.stringify(rp) + ' rev-list --count HEAD..@{u}', { encoding: 'utf8', stdio: ['pipe','pipe','pipe'] }).trim();
|
|
324
|
+
const ahead = execSync('git -C ' + JSON.stringify(rp) + ' rev-list --count @{u}..HEAD', { encoding: 'utf8', stdio: ['pipe','pipe','pipe'] }).trim();
|
|
325
|
+
if (behind === '0' && ahead === '0') status = 'in sync';
|
|
326
|
+
else if (behind !== '0') status = behind + ' behind — needs pull';
|
|
327
|
+
else status = ahead + ' ahead — push pending';
|
|
328
|
+
} catch { status = 'no remote tracking'; }
|
|
329
|
+
console.log(' [' + repo.prefix + '] ' + branch + ': ' + status);
|
|
330
|
+
} catch {
|
|
331
|
+
console.log(' [' + repo.prefix + '] not cloned');
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
" "$WORKSPACE_ROOT" "$WORKSPACE_FILE" 2>/dev/null
|
|
335
|
+
else
|
|
336
|
+
echo " Workspace: ⚠️ no .tlc-workspace.json found (single-repo mode)"
|
|
337
|
+
WARNINGS=$((WARNINGS + 1))
|
|
204
338
|
fi
|
|
205
339
|
|
|
206
|
-
# ───
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
340
|
+
# ─── 8. CI/CD Status ─────────────────────────────────────
|
|
341
|
+
if command -v gh >/dev/null 2>&1; then
|
|
342
|
+
LAST_RUN=$(gh run list --limit 1 --json conclusion,status,name -q '.[0]' 2>/dev/null)
|
|
343
|
+
if [ -n "$LAST_RUN" ]; then
|
|
344
|
+
RUN_STATUS=$(echo "$LAST_RUN" | node -e "try{const d=JSON.parse(require('fs').readFileSync('/dev/stdin','utf8'));console.log(d.conclusion||d.status)}catch{console.log('?')}" 2>/dev/null)
|
|
345
|
+
RUN_NAME=$(echo "$LAST_RUN" | node -e "try{const d=JSON.parse(require('fs').readFileSync('/dev/stdin','utf8'));console.log(d.name)}catch{console.log('?')}" 2>/dev/null)
|
|
346
|
+
if [ "$RUN_STATUS" = "success" ]; then
|
|
347
|
+
echo " CI/CD: ✅ last run passed (${RUN_NAME})"
|
|
348
|
+
elif [ "$RUN_STATUS" = "failure" ]; then
|
|
349
|
+
echo " CI/CD: ❌ last run FAILED (${RUN_NAME})"
|
|
350
|
+
ERRORS=$((ERRORS + 1))
|
|
351
|
+
else
|
|
352
|
+
echo " CI/CD: ⏳ ${RUN_STATUS} (${RUN_NAME})"
|
|
353
|
+
fi
|
|
354
|
+
else
|
|
355
|
+
echo " CI/CD: ⚠️ no recent runs"
|
|
356
|
+
fi
|
|
357
|
+
else
|
|
358
|
+
echo " CI/CD: ⚠️ gh CLI not installed"
|
|
359
|
+
WARNINGS=$((WARNINGS + 1))
|
|
212
360
|
fi
|
|
213
|
-
|
|
214
|
-
|
|
361
|
+
|
|
362
|
+
# ─── Summary ─────────────────────────────────────────────
|
|
363
|
+
echo "────────────────────────────────────────────────────"
|
|
364
|
+
if [ "$ERRORS" -eq 0 ] && [ "$WARNINGS" -eq 0 ]; then
|
|
365
|
+
echo "All systems healthy. ✅"
|
|
366
|
+
elif [ "$ERRORS" -eq 0 ]; then
|
|
367
|
+
echo "${WARNINGS} warning(s), 0 errors. Systems operational."
|
|
368
|
+
else
|
|
369
|
+
echo "⚠️ ${ERRORS} error(s), ${WARNINGS} warning(s). Check above."
|
|
215
370
|
fi
|
|
216
371
|
|
|
217
372
|
exit 0
|
package/CLAUDE.md
CHANGED
|
@@ -10,6 +10,7 @@
|
|
|
10
10
|
4. **No direct implementation.** User says "build X" → run `/tlc:progress` then `/tlc:build`.
|
|
11
11
|
5. **No Co-Authored-By in commits.** The user is the author. Claude is a tool.
|
|
12
12
|
6. **Ask before `git push`.** Never push without explicit approval.
|
|
13
|
+
7. **Claude NEVER writes code.** All code execution goes through the orchestrator (tlc-core :3100). Claude is PM — read, plan, dispatch, review. Sub-agents writing code is a bug. If the orchestrator is down, recover it first — never fall back to inline code.
|
|
13
14
|
|
|
14
15
|
## CodeDB
|
|
15
16
|
|