tlc-claude-code 2.9.2 → 2.10.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude/commands/tlc/build.md +7 -9
- package/.claude/commands/tlc/init.md +55 -2
- package/.claude/commands/tlc/quick.md +6 -11
- package/.claude/commands/tlc/recall.md +37 -11
- package/.claude/commands/tlc/remember.md +41 -15
- package/.claude/commands/tlc/tlc.md +40 -2
- package/.claude/hooks/tlc-session-init.sh +86 -11
- package/CLAUDE.md +1 -0
- package/package.json +1 -1
- package/server/index.js +96 -66
- package/server/package-lock.json +26 -0
- package/server/package.json +1 -0
- package/server/setup.sh +271 -271
|
@@ -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
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# /tlc:recall - Team Memory Search
|
|
2
2
|
|
|
3
|
-
Search TLC team memory
|
|
3
|
+
Search TLC team memory through the context engine hybrid search pipeline. Use FTS5 plus vector search when the engine is available, and fall back to grep only when it is not.
|
|
4
4
|
|
|
5
5
|
## Usage
|
|
6
6
|
|
|
@@ -10,33 +10,58 @@ Search TLC team memory using plain grep. This is intentional: no vector search,
|
|
|
10
10
|
|
|
11
11
|
## What This Does
|
|
12
12
|
|
|
13
|
-
1.
|
|
14
|
-
2.
|
|
15
|
-
3.
|
|
16
|
-
4.
|
|
13
|
+
1. Opens `.tlc/context.sqlite` through `createContextEngine()`.
|
|
14
|
+
2. Builds a search pipeline with `createSearchPipeline` from `@tlc/context-engine/search-pipeline`.
|
|
15
|
+
3. Runs the context leg with the engine's hybrid FTS5 plus vector search.
|
|
16
|
+
4. Searches TLC memory under `.tlc/memory/team/`.
|
|
17
|
+
5. Falls back to recursive grep only when the context engine or database is unavailable.
|
|
17
18
|
|
|
18
19
|
## Search Rules
|
|
19
20
|
|
|
20
21
|
- Search both `decisions/` and `gotchas/`.
|
|
21
|
-
-
|
|
22
|
-
-
|
|
23
|
-
-
|
|
22
|
+
- Prefer context-engine hybrid search over grep.
|
|
23
|
+
- Use vector ranking when embeddings are available; FTS5-only results are acceptable when vectors are missing.
|
|
24
|
+
- Fall back to grep if `@tlc/context-engine` cannot be loaded or `.tlc/context.sqlite` does not exist yet.
|
|
24
25
|
|
|
25
26
|
## Process
|
|
26
27
|
|
|
27
|
-
### Step 1:
|
|
28
|
+
### Step 1: Try the context engine
|
|
29
|
+
|
|
30
|
+
```js
|
|
31
|
+
import { createContextEngine } from '@tlc/context-engine';
|
|
32
|
+
import { createSearch } from '@tlc/context-engine/retrieval/search';
|
|
33
|
+
import { createSearchPipeline } from '@tlc/context-engine/search-pipeline';
|
|
34
|
+
|
|
35
|
+
const engine = createContextEngine({ dbPath: '.tlc/context.sqlite' });
|
|
36
|
+
const hybridSearch = createSearch({
|
|
37
|
+
embeddingStore: {
|
|
38
|
+
findSimilar(db, queryVec, options) {
|
|
39
|
+
return engine.embeddings.findSimilar(queryVec, options);
|
|
40
|
+
},
|
|
41
|
+
},
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
const searchAll = createSearchPipeline({
|
|
45
|
+
search: (db, query, options) => hybridSearch(db, query, options),
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
const results = await searchAll(engine.db, query, { limit: 10 });
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
### Step 2: If the engine is unavailable, fall back to grep
|
|
28
52
|
|
|
29
53
|
```bash
|
|
30
|
-
grep -
|
|
54
|
+
grep -Ril "query" .tlc/memory/team/
|
|
31
55
|
```
|
|
32
56
|
|
|
33
|
-
### Step
|
|
57
|
+
### Step 3: Display matches
|
|
34
58
|
|
|
35
59
|
For each matching file, show:
|
|
36
60
|
|
|
37
61
|
- File path
|
|
38
62
|
- Date parsed from the filename prefix
|
|
39
63
|
- A short matching excerpt from the file body
|
|
64
|
+
- Search source: `context-engine` or `grep-fallback`
|
|
40
65
|
|
|
41
66
|
## Example Output
|
|
42
67
|
|
|
@@ -57,3 +82,4 @@ Excerpt: Local timezone conversion caused reporting drift in scheduled jobs.
|
|
|
57
82
|
- If there are no matches, say so directly.
|
|
58
83
|
- Keep excerpts short and relevant.
|
|
59
84
|
- Search TLC memory under `.tlc/memory/team/`, not Claude-managed memory.
|
|
85
|
+
- Close the context engine after the search when it was opened successfully.
|
|
@@ -17,31 +17,32 @@ Or without arguments:
|
|
|
17
17
|
## What This Does
|
|
18
18
|
|
|
19
19
|
1. Captures the provided decision text, or extracts decisions from the recent conversation context if no argument is given.
|
|
20
|
-
2.
|
|
21
|
-
3.
|
|
22
|
-
4.
|
|
20
|
+
2. Appends a JSONL event to `.tlc/events/memory.jsonl` through the context engine event log.
|
|
21
|
+
3. Replays the event into `.tlc/context.sqlite`.
|
|
22
|
+
4. Exports visible `.md` memory files for git visibility under `.tlc/memory/team/decisions/`.
|
|
23
|
+
5. Never writes to `~/.claude/projects/.../memory/` because that is Claude memory, not TLC memory.
|
|
23
24
|
|
|
24
25
|
## Write Format
|
|
25
26
|
|
|
26
|
-
Write the
|
|
27
|
+
Write the canonical record as a JSONL event first:
|
|
28
|
+
|
|
29
|
+
```json
|
|
30
|
+
{"type":"decision","category":"decision","scope":"team","subject":"use-utc-timestamps","body":"Always use UTC timestamps in the database and in exported logs."}
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
Then export the visible markdown file with YAML frontmatter:
|
|
27
34
|
|
|
28
35
|
```yaml
|
|
29
36
|
---
|
|
30
|
-
provider: claude
|
|
31
|
-
source: manual
|
|
32
37
|
timestamp: 2026-03-28T12:34:56Z
|
|
33
38
|
type: decision
|
|
34
39
|
scope: team
|
|
40
|
+
category: decision
|
|
41
|
+
subject: "use-utc-timestamps"
|
|
35
42
|
---
|
|
36
43
|
```
|
|
37
44
|
|
|
38
|
-
The filename must be:
|
|
39
|
-
|
|
40
|
-
```text
|
|
41
|
-
.tlc/memory/team/decisions/{date}-{slug}.md
|
|
42
|
-
```
|
|
43
|
-
|
|
44
|
-
Example:
|
|
45
|
+
The markdown filename must be:
|
|
45
46
|
|
|
46
47
|
```text
|
|
47
48
|
.tlc/memory/team/decisions/2026-03-28-use-utc-timestamps.md
|
|
@@ -53,19 +54,43 @@ Example:
|
|
|
53
54
|
|
|
54
55
|
- Use the argument as the decision content.
|
|
55
56
|
- Generate a short slug from the decision.
|
|
56
|
-
-
|
|
57
|
+
- Append the event with `engine.events.appendEvent('.tlc/events/memory.jsonl', event)`.
|
|
58
|
+
- Replay the log into the database.
|
|
59
|
+
- Export markdown back to `.tlc/memory/team/decisions/`.
|
|
57
60
|
|
|
58
61
|
### Without an argument
|
|
59
62
|
|
|
60
63
|
- Review the recent conversation context.
|
|
61
64
|
- Extract concrete decisions, conventions, or constraints worth preserving.
|
|
62
65
|
- Summarize them clearly.
|
|
63
|
-
-
|
|
66
|
+
- Append one JSONL event.
|
|
67
|
+
- Export one visible markdown file under `.tlc/memory/team/decisions/`.
|
|
68
|
+
|
|
69
|
+
## Implementation Sketch
|
|
70
|
+
|
|
71
|
+
```js
|
|
72
|
+
import { createContextEngine } from '@tlc/context-engine';
|
|
73
|
+
import { exportFactsToMarkdown } from '@tlc/context-engine/import/markdown-exporter';
|
|
74
|
+
|
|
75
|
+
const engine = createContextEngine({ dbPath: '.tlc/context.sqlite' });
|
|
76
|
+
const event = engine.events.appendEvent('.tlc/events/memory.jsonl', {
|
|
77
|
+
type: 'decision',
|
|
78
|
+
category: 'decision',
|
|
79
|
+
scope: 'team',
|
|
80
|
+
subject: slug,
|
|
81
|
+
body: decisionText,
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
engine.events.replayEvents([event]);
|
|
85
|
+
exportFactsToMarkdown(engine.db, '.tlc/memory/team/decisions');
|
|
86
|
+
engine.close();
|
|
87
|
+
```
|
|
64
88
|
|
|
65
89
|
## Confirmation
|
|
66
90
|
|
|
67
91
|
```text
|
|
68
92
|
Remembered: {summary}
|
|
93
|
+
Event: .tlc/events/memory.jsonl
|
|
69
94
|
File: .tlc/memory/team/decisions/2026-03-28-use-utc-timestamps.md
|
|
70
95
|
```
|
|
71
96
|
|
|
@@ -74,3 +99,4 @@ File: .tlc/memory/team/decisions/2026-03-28-use-utc-timestamps.md
|
|
|
74
99
|
- Prefer concise, durable statements over raw transcript dumps.
|
|
75
100
|
- Record decisions, not general chatter.
|
|
76
101
|
- Use `.tlc/memory/team/gotchas/` for gotchas, not this command.
|
|
102
|
+
- JSONL is the source of truth; markdown is the human-visible export.
|
|
@@ -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
|
```
|
|
@@ -26,8 +26,15 @@ if [ "$INSTALLED_VER" = "not-installed" ]; then
|
|
|
26
26
|
echo " TLC Package: ❌ not installed (run: npm i -g tlc-claude-code)"
|
|
27
27
|
ERRORS=$((ERRORS + 1))
|
|
28
28
|
elif [ "$INSTALLED_VER" != "$LATEST_VER" ] && [ "$LATEST_VER" != "unknown" ]; then
|
|
29
|
-
echo " TLC Package:
|
|
30
|
-
|
|
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))
|
|
37
|
+
fi
|
|
31
38
|
else
|
|
32
39
|
echo " TLC Package: ✅ v${INSTALLED_VER} (latest)"
|
|
33
40
|
fi
|
|
@@ -37,6 +44,15 @@ mkdir -p "$PROJECT_DIR/.tlc/memory/team/decisions" \
|
|
|
37
44
|
"$PROJECT_DIR/.tlc/memory/team/gotchas" \
|
|
38
45
|
"$PROJECT_DIR/.tlc/memory/.local/sessions" 2>/dev/null
|
|
39
46
|
|
|
47
|
+
# Bootstrap context engine on first run by importing visible markdown memory.
|
|
48
|
+
CONTEXT_BOOTSTRAP=""
|
|
49
|
+
if node -e "import('@tlc/context-engine/bootstrap').then(()=>process.exit(0)).catch(()=>process.exit(1))" >/dev/null 2>&1; then
|
|
50
|
+
CONTEXT_BOOTSTRAP="import('@tlc/context-engine').then(async ({ createContextEngine }) => { const { createBootstrap } = await import('@tlc/context-engine/bootstrap'); const { importMarkdownMemories } = await import('@tlc/context-engine/import/markdown-importer'); const { indexProject } = await import('@tlc/context-engine/retrieval/indexer'); const bootstrap = createBootstrap({ contextEngine: createContextEngine, markdownImporter: { importMarkdownMemories }, indexer: { indexProject } }); const result = await bootstrap(process.argv[1]); if ((result.imported || 0) > 0 || (result.indexed || 0) > 0) { console.log(' Context Engine: ✅ bootstrapped (' + result.imported + ' imported, ' + result.indexed + ' indexed)'); } }).catch(() => {})"
|
|
51
|
+
elif [ -d "$PROJECT_DIR/server/node_modules/@tlc/context-engine" ]; then
|
|
52
|
+
CONTEXT_BOOTSTRAP="(async () => { const [{ createContextEngine }, { createBootstrap }, { importMarkdownMemories }, { indexProject }] = await Promise.all([import('$PROJECT_DIR/server/node_modules/@tlc/context-engine/src/index.js'), import('$PROJECT_DIR/server/node_modules/@tlc/context-engine/src/bootstrap.js'), import('$PROJECT_DIR/server/node_modules/@tlc/context-engine/src/import/markdown-importer.js'), import('$PROJECT_DIR/server/node_modules/@tlc/context-engine/src/retrieval/indexer.js')]); const bootstrap = createBootstrap({ contextEngine: createContextEngine, markdownImporter: { importMarkdownMemories }, indexer: { indexProject } }); const result = await bootstrap(process.argv[1]); if ((result.imported || 0) > 0 || (result.indexed || 0) > 0) { console.log(' Context Engine: ✅ bootstrapped (' + result.imported + ' imported, ' + result.indexed + ' indexed)'); } })().catch(() => {})"
|
|
53
|
+
fi
|
|
54
|
+
[ -n "$CONTEXT_BOOTSTRAP" ] && node -e "$CONTEXT_BOOTSTRAP" "$PROJECT_DIR" 2>/dev/null
|
|
55
|
+
|
|
40
56
|
if curl -sf --max-time 1 "http://localhost:${TLC_PORT}/api/health" > /dev/null 2>&1; then
|
|
41
57
|
echo " TLC Server: ✅ running (:${TLC_PORT})"
|
|
42
58
|
# Drain spool
|
|
@@ -100,8 +116,20 @@ MCPEOF
|
|
|
100
116
|
echo " CodeDB MCP: ✅ created .mcp.json"
|
|
101
117
|
fi
|
|
102
118
|
else
|
|
103
|
-
|
|
104
|
-
|
|
119
|
+
# Auto-install CodeDB binary
|
|
120
|
+
echo " CodeDB: ⏳ not installed — auto-installing..."
|
|
121
|
+
if npx -y tlc-claude-code 2>/dev/null | tail -1; then
|
|
122
|
+
if command -v codedb >/dev/null 2>&1; then
|
|
123
|
+
codedb serve "$PROJECT_DIR" > /dev/null 2>&1 &
|
|
124
|
+
echo " CodeDB: ✅ installed and started"
|
|
125
|
+
else
|
|
126
|
+
echo " CodeDB: ❌ install failed"
|
|
127
|
+
ERRORS=$((ERRORS + 1))
|
|
128
|
+
fi
|
|
129
|
+
else
|
|
130
|
+
echo " CodeDB: ❌ install failed"
|
|
131
|
+
ERRORS=$((ERRORS + 1))
|
|
132
|
+
fi
|
|
105
133
|
fi
|
|
106
134
|
|
|
107
135
|
# ─── 4. tlc-core Orchestrator + Containers ────────────────
|
|
@@ -125,17 +153,49 @@ elif curl -sf --max-time 2 "http://localhost:${TLC_CORE_PORT}/health" > /dev/nul
|
|
|
125
153
|
|
|
126
154
|
# Check session monitor + watchdog
|
|
127
155
|
ORCH_LOGS=$(docker logs tlc-core-orchestrator-1 --tail 50 2>&1)
|
|
156
|
+
MONITOR_OK=false
|
|
157
|
+
WATCHDOG_OK=false
|
|
128
158
|
if echo "$ORCH_LOGS" | grep -q "Session monitor started"; then
|
|
159
|
+
MONITOR_OK=true
|
|
129
160
|
echo " Session Monitor: ✅ active (10s interval)"
|
|
130
|
-
else
|
|
131
|
-
echo " Session Monitor: ❌ not running — orchestrator needs restart"
|
|
132
|
-
ERRORS=$((ERRORS + 1))
|
|
133
161
|
fi
|
|
134
162
|
if echo "$ORCH_LOGS" | grep -q "Watchdog started\|watchdog.*Started"; then
|
|
163
|
+
WATCHDOG_OK=true
|
|
135
164
|
echo " Watchdog: ✅ active (60s interval)"
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
165
|
+
fi
|
|
166
|
+
|
|
167
|
+
# Auto-recover: if monitor or watchdog missing, deploy latest code and restart
|
|
168
|
+
if [ "$MONITOR_OK" = false ] || [ "$WATCHDOG_OK" = false ]; then
|
|
169
|
+
echo " Monitor/Watchdog: ⏳ missing — deploying latest code and restarting..."
|
|
170
|
+
# Find orchestrator source
|
|
171
|
+
ORCH_SRC=""
|
|
172
|
+
if [ -d "$PROJECT_DIR/../tlc-core/orchestrator" ]; then
|
|
173
|
+
ORCH_SRC="$PROJECT_DIR/../tlc-core/orchestrator"
|
|
174
|
+
elif [ -d "$(dirname "$PROJECT_DIR")/tlc-core/orchestrator" ]; then
|
|
175
|
+
ORCH_SRC="$(dirname "$PROJECT_DIR")/tlc-core/orchestrator"
|
|
176
|
+
fi
|
|
177
|
+
if [ -n "$ORCH_SRC" ]; then
|
|
178
|
+
ORCH_CONTAINER=$(docker ps --format '{{.Names}}' 2>/dev/null | grep "orchestrator" | head -1)
|
|
179
|
+
if [ -n "$ORCH_CONTAINER" ]; then
|
|
180
|
+
docker cp "$ORCH_SRC/lib/." "$ORCH_CONTAINER:/app/lib/" 2>/dev/null
|
|
181
|
+
docker cp "$ORCH_SRC/index.js" "$ORCH_CONTAINER:/app/index.js" 2>/dev/null
|
|
182
|
+
docker cp "$ORCH_SRC/migrations/." "$ORCH_CONTAINER:/app/migrations/" 2>/dev/null
|
|
183
|
+
docker restart "$ORCH_CONTAINER" > /dev/null 2>&1
|
|
184
|
+
sleep 3
|
|
185
|
+
if curl -sf --max-time 2 "http://localhost:${TLC_CORE_PORT}/health" > /dev/null 2>&1; then
|
|
186
|
+
echo " Monitor/Watchdog: ✅ restarted with latest code"
|
|
187
|
+
else
|
|
188
|
+
echo " Monitor/Watchdog: ❌ restart failed"
|
|
189
|
+
ERRORS=$((ERRORS + 1))
|
|
190
|
+
fi
|
|
191
|
+
else
|
|
192
|
+
echo " Monitor/Watchdog: ❌ orchestrator container not found"
|
|
193
|
+
ERRORS=$((ERRORS + 1))
|
|
194
|
+
fi
|
|
195
|
+
else
|
|
196
|
+
[ "$MONITOR_OK" = false ] && echo " Session Monitor: ❌ not running (tlc-core source not found)" && ERRORS=$((ERRORS + 1))
|
|
197
|
+
[ "$WATCHDOG_OK" = false ] && echo " Watchdog: ⚠️ not detected" && WARNINGS=$((WARNINGS + 1))
|
|
198
|
+
fi
|
|
139
199
|
fi
|
|
140
200
|
else
|
|
141
201
|
if command -v tlc-core >/dev/null 2>&1; then
|
|
@@ -180,6 +240,14 @@ PROVIDER_LIST=$(echo "$PROVIDER_LIST" | sed 's/, $//')
|
|
|
180
240
|
|
|
181
241
|
if [ "$PROVIDER_COUNT" -gt 0 ]; then
|
|
182
242
|
echo " LLM Providers: ✅ ${PROVIDER_COUNT} available — ${PROVIDER_LIST}"
|
|
243
|
+
# Check for updates (non-blocking, just warn)
|
|
244
|
+
if [ "$CODEX_VER" != "not installed" ]; then
|
|
245
|
+
CODEX_LATEST=$(npm view @openai/codex version 2>/dev/null || echo "")
|
|
246
|
+
if [ -n "$CODEX_LATEST" ] && [ "$CODEX_VER" != *"$CODEX_LATEST"* ] 2>/dev/null; then
|
|
247
|
+
echo " Codex Update: ⚠️ latest: ${CODEX_LATEST} — run: npm i -g @openai/codex"
|
|
248
|
+
WARNINGS=$((WARNINGS + 1))
|
|
249
|
+
fi
|
|
250
|
+
fi
|
|
183
251
|
else
|
|
184
252
|
echo " LLM Providers: ❌ none found"
|
|
185
253
|
ERRORS=$((ERRORS + 1))
|
|
@@ -209,6 +277,8 @@ cat > "$STATE_FILE" <<STATEEOF
|
|
|
209
277
|
STATEEOF
|
|
210
278
|
|
|
211
279
|
# ─── 6. Git + Remote Sync ────────────────────────────────
|
|
280
|
+
# Fetch remote to get accurate ahead/behind counts
|
|
281
|
+
git fetch --quiet 2>/dev/null
|
|
212
282
|
CURRENT_BRANCH=$(git branch --show-current 2>/dev/null)
|
|
213
283
|
BEHIND=$(git rev-list --count HEAD..@{u} 2>/dev/null || echo "?")
|
|
214
284
|
AHEAD=$(git rev-list --count @{u}..HEAD 2>/dev/null || echo "?")
|
|
@@ -254,11 +324,16 @@ if [ -n "$WORKSPACE_FILE" ]; then
|
|
|
254
324
|
const rp = path.resolve(wsRoot, repo.path);
|
|
255
325
|
try {
|
|
256
326
|
fs.accessSync(rp);
|
|
327
|
+
// Fetch remote for accurate state
|
|
328
|
+
try { execSync('git -C ' + JSON.stringify(rp) + ' fetch --quiet', { stdio: ['pipe','pipe','pipe'], timeout: 10000 }); } catch {}
|
|
257
329
|
const branch = execSync('git -C ' + JSON.stringify(rp) + ' branch --show-current', { encoding: 'utf8', stdio: ['pipe','pipe','pipe'] }).trim();
|
|
258
330
|
let status = 'unknown';
|
|
259
331
|
try {
|
|
260
332
|
const behind = execSync('git -C ' + JSON.stringify(rp) + ' rev-list --count HEAD..@{u}', { encoding: 'utf8', stdio: ['pipe','pipe','pipe'] }).trim();
|
|
261
|
-
|
|
333
|
+
const ahead = execSync('git -C ' + JSON.stringify(rp) + ' rev-list --count @{u}..HEAD', { encoding: 'utf8', stdio: ['pipe','pipe','pipe'] }).trim();
|
|
334
|
+
if (behind === '0' && ahead === '0') status = 'in sync';
|
|
335
|
+
else if (behind !== '0') status = behind + ' behind — needs pull';
|
|
336
|
+
else status = ahead + ' ahead — push pending';
|
|
262
337
|
} catch { status = 'no remote tracking'; }
|
|
263
338
|
console.log(' [' + repo.prefix + '] ' + branch + ': ' + status);
|
|
264
339
|
} catch {
|
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
|
|