tlc-claude-code 2.5.0 → 2.6.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.
- package/.claude/commands/tlc/autofix.md +34 -1
- package/.claude/commands/tlc/build.md +89 -6
- package/.claude/commands/tlc/ci.md +178 -414
- package/.claude/commands/tlc/coverage.md +34 -0
- package/.claude/commands/tlc/deploy.md +19 -6
- package/.claude/commands/tlc/discuss.md +34 -0
- package/.claude/commands/tlc/docs.md +35 -1
- package/.claude/commands/tlc/e2e.md +300 -0
- package/.claude/commands/tlc/edge-cases.md +35 -1
- package/.claude/commands/tlc/init.md +38 -8
- package/.claude/commands/tlc/new-project.md +46 -4
- package/.claude/commands/tlc/plan.md +33 -0
- package/.claude/commands/tlc/quick.md +33 -0
- package/.claude/commands/tlc/release.md +85 -135
- package/.claude/commands/tlc/restore.md +14 -0
- package/.claude/commands/tlc/review.md +76 -1
- package/.claude/commands/tlc/tlc.md +134 -0
- package/.claude/commands/tlc/verify.md +64 -65
- package/.claude/commands/tlc/watchci.md +10 -0
- package/.claude/hooks/tlc-block-tools.sh +13 -0
- package/.claude/hooks/tlc-session-init.sh +9 -0
- package/CODING-STANDARDS.md +35 -10
- package/package.json +1 -1
- package/server/lib/block-tools-hook.js +23 -0
- package/server/lib/e2e/acceptance-parser.js +132 -0
- package/server/lib/e2e/acceptance-parser.test.js +110 -0
- package/server/lib/e2e/framework-detector.js +47 -0
- package/server/lib/e2e/framework-detector.test.js +94 -0
- package/server/lib/e2e/log-assertions.js +107 -0
- package/server/lib/e2e/log-assertions.test.js +68 -0
- package/server/lib/e2e/test-generator.js +159 -0
- package/server/lib/e2e/test-generator.test.js +121 -0
- package/server/lib/e2e/verify-runner.js +191 -0
- package/server/lib/e2e/verify-runner.test.js +167 -0
- package/server/lib/hooks/block-tools-hook.test.js +54 -0
- package/server/lib/orchestration/cli-dispatch.js +16 -1
- package/server/lib/orchestration/cli-dispatch.test.js +94 -8
- package/server/lib/orchestration/completion-checker.js +101 -0
- package/server/lib/orchestration/completion-checker.test.js +177 -0
- package/server/lib/orchestration/result-verifier.js +143 -0
- package/server/lib/orchestration/result-verifier.test.js +291 -0
- package/server/lib/orchestration/session-dispatcher.js +99 -0
- package/server/lib/orchestration/session-dispatcher.test.js +215 -0
- package/server/lib/orchestration/session-status.js +147 -0
- package/server/lib/orchestration/session-status.test.js +130 -0
- package/server/lib/release/agent-runner-updates.js +24 -0
- package/server/lib/release/agent-runner-updates.test.js +22 -0
- package/server/lib/release/changelog-generator.js +142 -0
- package/server/lib/release/changelog-generator.test.js +113 -0
- package/server/lib/release/ci-watcher.js +83 -0
- package/server/lib/release/ci-watcher.test.js +81 -0
- package/server/lib/release/health-checker.js +111 -0
- package/server/lib/release/health-checker.test.js +121 -0
- package/server/lib/release/release-pipeline.js +187 -0
- package/server/lib/release/release-pipeline.test.js +262 -0
- package/server/lib/release/version-bumper.js +183 -0
- package/server/lib/release/version-bumper.test.js +142 -0
- package/server/lib/routing-preamble.integration.test.js +12 -0
- package/server/lib/routing-preamble.js +13 -2
- package/server/lib/routing-preamble.test.js +49 -0
- package/server/lib/scaffolding/ci-detector.js +139 -0
- package/server/lib/scaffolding/ci-detector.test.js +198 -0
- package/server/lib/scaffolding/ci-scaffolder.js +347 -0
- package/server/lib/scaffolding/ci-scaffolder.test.js +157 -0
- package/server/lib/scaffolding/deploy-detector.js +135 -0
- package/server/lib/scaffolding/deploy-detector.test.js +106 -0
- package/server/lib/scaffolding/health-scaffold.js +374 -0
- package/server/lib/scaffolding/health-scaffold.test.js +99 -0
- package/server/lib/scaffolding/logger-scaffold.js +196 -0
- package/server/lib/scaffolding/logger-scaffold.test.js +146 -0
- package/server/lib/scaffolding/migration-detector.js +78 -0
- package/server/lib/scaffolding/migration-detector.test.js +127 -0
- package/server/lib/scaffolding/snapshot-manager.js +142 -0
- package/server/lib/scaffolding/snapshot-manager.test.js +225 -0
- package/server/lib/task-router-config.js +50 -20
- package/server/lib/task-router-config.test.js +29 -15
|
@@ -97,6 +97,40 @@ process.stdout.write(JSON.stringify(result));" 2>/dev/null
|
|
|
97
97
|
|
|
98
98
|
**Override:** Pass `--model <name>` to route this specific run to a different model.
|
|
99
99
|
|
|
100
|
+
After `resolveRouting` returns, immediately write `.tlc/.discuss-routing-active` with the active provider name from `models[0]` before doing any other discuss work. Remove `.tlc/.discuss-routing-active` on completion, cancellation, or failure cleanup.
|
|
101
|
+
|
|
102
|
+
**Routing decision:**
|
|
103
|
+
- If routing says external provider (`models[0] !== 'claude'`), follow **ONLY ORCHESTRATOR MODE** below.
|
|
104
|
+
- If routing says Claude (`models[0] === 'claude'`), follow **INLINE MODE** below.
|
|
105
|
+
|
|
106
|
+
## ORCHESTRATOR MODE
|
|
107
|
+
|
|
108
|
+
Use this mode only when `models[0]` is **NOT** `claude`.
|
|
109
|
+
|
|
110
|
+
Claude does not execute the discussion instructions inline in this path. Claude acts as the orchestrator for the routed provider run:
|
|
111
|
+
|
|
112
|
+
1. Claude acts as the orchestrator for the routed implementation discussion instead of running the interview inline.
|
|
113
|
+
2. Scan the roadmap, discussion history, relevant code, recent changes, and project conventions before dispatching discussion work.
|
|
114
|
+
3. Package a prompt that asks the routed provider to propose a concrete implementation approach first, then surface only the highest-value confirm-or-correct questions.
|
|
115
|
+
4. Dispatch through the provider CLI path, using `codex exec` for Codex-style providers or `gemini -p` for Gemini-style providers, preferably via the shared dispatch layer when available.
|
|
116
|
+
5. Verify the routed discussion output before accepting it:
|
|
117
|
+
- Confirm it reflects the actual repo context instead of asking the user to restate known facts.
|
|
118
|
+
- Confirm it leads with a recommendation, then asks only material decision questions.
|
|
119
|
+
- Reject vague brainstorming output or question lists that do not advance the phase.
|
|
120
|
+
6. If the routed response misses key architectural context or asks low-value questions, issue a focused follow-up dispatch to tighten the discussion.
|
|
121
|
+
7. Handle failures explicitly:
|
|
122
|
+
- If dispatch fails because of model mismatch, auth, or missing CLI, check `.tlc/.router-state.json` for the provider's actual available model and retry once with the corrected model.
|
|
123
|
+
- If retry still fails, stop and report the exact failure to the user. Do not silently fall back to Claude inline execution.
|
|
124
|
+
- If the provider returns weak discovery output, reject it and rerun with explicit context and decision targets.
|
|
125
|
+
8. When finished, display the routed discussion result, persist any captured memory, remove `.tlc/.discuss-routing-active`, and stop. Do **not** execute Inline Mode afterward.
|
|
126
|
+
|
|
127
|
+
## INLINE MODE
|
|
128
|
+
|
|
129
|
+
Use this mode only when `models[0]` **IS** `claude`.
|
|
130
|
+
|
|
131
|
+
The existing discussion instructions below are the Inline Mode instructions and should be followed unchanged.
|
|
132
|
+
|
|
133
|
+
|
|
100
134
|
## What This Does
|
|
101
135
|
|
|
102
136
|
Runs a short implementation interview for the current phase using a silent expansion workflow:
|
|
@@ -95,7 +95,41 @@ process.stdout.write(JSON.stringify(result));" 2>/dev/null
|
|
|
95
95
|
- Execute inline (Claude) AND dispatch to CLI models simultaneously
|
|
96
96
|
- Collect and merge results
|
|
97
97
|
|
|
98
|
-
**Override:** Pass `--model <name>` to route this specific run to a different model.
|
|
98
|
+
**Override:** Pass `--model <name>` to route this specific run to a different model.
|
|
99
|
+
|
|
100
|
+
After `resolveRouting` returns, immediately write `.tlc/.docs-routing-active` with the active provider name from `models[0]` before doing any other docs work. Remove `.tlc/.docs-routing-active` on completion, cancellation, or failure cleanup.
|
|
101
|
+
|
|
102
|
+
**Routing decision:**
|
|
103
|
+
- If routing says external provider (`models[0] !== 'claude'`), follow **ONLY ORCHESTRATOR MODE** below.
|
|
104
|
+
- If routing says Claude (`models[0] === 'claude'`), follow **INLINE MODE** below.
|
|
105
|
+
|
|
106
|
+
## ORCHESTRATOR MODE
|
|
107
|
+
|
|
108
|
+
Use this mode only when `models[0]` is **NOT** `claude`.
|
|
109
|
+
|
|
110
|
+
Claude does not execute the documentation instructions inline in this path. Claude acts as the orchestrator for the routed provider run:
|
|
111
|
+
|
|
112
|
+
1. Claude acts as the orchestrator for routed documentation work instead of maintaining docs inline.
|
|
113
|
+
2. Gather the relevant repository context, documentation targets, configured docs settings, and any screenshot or API-doc generation expectations before dispatch.
|
|
114
|
+
3. Break the docs work into focused slices when useful, such as README updates, API docs generation, screenshot capture guidance, or automation setup.
|
|
115
|
+
4. Dispatch through the provider CLI path, using `codex exec` for Codex-style providers or `gemini -p` for Gemini-style providers, preferably via the shared dispatch layer when available.
|
|
116
|
+
5. Verify the routed result before accepting it:
|
|
117
|
+
- Confirm the documentation changes match the current codebase and command intent.
|
|
118
|
+
- Confirm generated instructions or automation steps are specific enough to execute in this repo.
|
|
119
|
+
- Reject stale, generic, or obviously hallucinated documentation output.
|
|
120
|
+
6. If the routed work comes back incomplete, dispatch follow-up tasks for the missing documentation slices rather than declaring success.
|
|
121
|
+
7. Handle failures explicitly:
|
|
122
|
+
- If dispatch fails because of model mismatch, auth, or missing CLI, check `.tlc/.router-state.json` for the provider's actual available model and retry once with the corrected model.
|
|
123
|
+
- If retry still fails, stop and report the exact failure to the user. Do not silently fall back to Claude inline execution.
|
|
124
|
+
- If the provider returns low-confidence docs or broken setup steps, request a targeted correction before continuing.
|
|
125
|
+
8. When finished, display the routed documentation result, persist any captured memory, remove `.tlc/.docs-routing-active`, and stop. Do **not** execute Inline Mode afterward.
|
|
126
|
+
|
|
127
|
+
## INLINE MODE
|
|
128
|
+
|
|
129
|
+
Use this mode only when `models[0]` **IS** `claude`.
|
|
130
|
+
|
|
131
|
+
The existing documentation instructions below are the Inline Mode instructions and should be followed unchanged.
|
|
132
|
+
|
|
99
133
|
|
|
100
134
|
## Usage
|
|
101
135
|
|
|
@@ -0,0 +1,300 @@
|
|
|
1
|
+
# /tlc:e2e - Generate Phase E2E Tests
|
|
2
|
+
|
|
3
|
+
Parse acceptance criteria from a phase `PLAN.md`, generate matching E2E test files, scaffold an E2E framework if missing, run the generated tests to verify they execute, and commit the result.
|
|
4
|
+
|
|
5
|
+
## Routing
|
|
6
|
+
|
|
7
|
+
This command supports multi-model routing via `~/.tlc/config.json`.
|
|
8
|
+
|
|
9
|
+
**Before executing this command:**
|
|
10
|
+
|
|
11
|
+
1. Read routing config:
|
|
12
|
+
```bash
|
|
13
|
+
node -e "const fs = require('fs');
|
|
14
|
+
const path = require('path');
|
|
15
|
+
const os = require('os');
|
|
16
|
+
function readJson(filePath, fileSystem) {
|
|
17
|
+
try {
|
|
18
|
+
return JSON.parse(fileSystem.readFileSync(filePath, 'utf8'));
|
|
19
|
+
} catch {
|
|
20
|
+
return null;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
function loadPersonalConfig(options) {
|
|
24
|
+
const configPath = path.join(options.homeDir, '.tlc', 'config.json');
|
|
25
|
+
return readJson(configPath, options.fs);
|
|
26
|
+
}
|
|
27
|
+
function loadProjectOverride(options) {
|
|
28
|
+
const configPath = path.join(options.projectDir, '.tlc.json');
|
|
29
|
+
const data = readJson(configPath, options.fs);
|
|
30
|
+
return data && data.task_routing_override ? data.task_routing_override : null;
|
|
31
|
+
}
|
|
32
|
+
function resolveRouting(options) {
|
|
33
|
+
let models = ['claude'];
|
|
34
|
+
let strategy = 'single';
|
|
35
|
+
let source = 'shipped-defaults';
|
|
36
|
+
let providers;
|
|
37
|
+
const personal = loadPersonalConfig({ homeDir: options.homeDir, fs: options.fs });
|
|
38
|
+
if (personal) {
|
|
39
|
+
if (personal.model_providers) {
|
|
40
|
+
providers = personal.model_providers;
|
|
41
|
+
}
|
|
42
|
+
const personalRouting = personal.task_routing && personal.task_routing[options.command];
|
|
43
|
+
if (personalRouting) {
|
|
44
|
+
if (Array.isArray(personalRouting.models)) {
|
|
45
|
+
models = personalRouting.models.slice();
|
|
46
|
+
} else if (typeof personalRouting.model === 'string') {
|
|
47
|
+
models = [personalRouting.model];
|
|
48
|
+
}
|
|
49
|
+
if (personalRouting.strategy) {
|
|
50
|
+
strategy = personalRouting.strategy;
|
|
51
|
+
}
|
|
52
|
+
source = 'personal-config';
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
const projectOverride = loadProjectOverride({ projectDir: options.projectDir, fs: options.fs });
|
|
56
|
+
if (projectOverride) {
|
|
57
|
+
const overrideEntry = projectOverride[options.command];
|
|
58
|
+
if (overrideEntry) {
|
|
59
|
+
if (Array.isArray(overrideEntry.models)) {
|
|
60
|
+
models = overrideEntry.models.slice();
|
|
61
|
+
} else if (typeof overrideEntry.model === 'string') {
|
|
62
|
+
models = [overrideEntry.model];
|
|
63
|
+
}
|
|
64
|
+
if (overrideEntry.strategy) {
|
|
65
|
+
strategy = overrideEntry.strategy;
|
|
66
|
+
}
|
|
67
|
+
source = 'project-override';
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
if (options.flagModel) {
|
|
71
|
+
models = [options.flagModel];
|
|
72
|
+
strategy = 'single';
|
|
73
|
+
source = 'flag-override';
|
|
74
|
+
}
|
|
75
|
+
const result = { models, strategy, source };
|
|
76
|
+
if (providers) {
|
|
77
|
+
result.providers = providers;
|
|
78
|
+
}
|
|
79
|
+
return result;
|
|
80
|
+
}
|
|
81
|
+
const result = resolveRouting({ command: \"e2e\", flagModel: process.argv[1], projectDir: process.cwd(), homeDir: process.env.HOME || os.homedir(), fs });
|
|
82
|
+
process.stdout.write(JSON.stringify(result));" 2>/dev/null
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
2. If `models[0]` is NOT `claude`:
|
|
86
|
+
- Read `PROJECT.md`, the target phase `PLAN.md`, and `.tlc.json`
|
|
87
|
+
- Package the agent prompt below with project context
|
|
88
|
+
- Dispatch to the routed CLI
|
|
89
|
+
- Display the CLI output and stop
|
|
90
|
+
|
|
91
|
+
3. If `models[0]` IS `claude`:
|
|
92
|
+
- Execute the agent prompt below as normal
|
|
93
|
+
|
|
94
|
+
4. If `strategy` is `parallel`:
|
|
95
|
+
- Execute inline and dispatch to external providers simultaneously
|
|
96
|
+
- Collect and merge results
|
|
97
|
+
|
|
98
|
+
**Override:** Pass `--model <name>` to route this specific run to a different model.
|
|
99
|
+
|
|
100
|
+
After `resolveRouting` returns, immediately write `.tlc/.e2e-routing-active` with the active provider name from `models[0]` before doing any other e2e work. Remove `.tlc/.e2e-routing-active` on completion, cancellation, or failure cleanup.
|
|
101
|
+
|
|
102
|
+
## What This Does
|
|
103
|
+
|
|
104
|
+
1. Resolves the target phase
|
|
105
|
+
2. Reads the phase `PLAN.md`
|
|
106
|
+
3. Parses task acceptance criteria into automatable E2E scenarios
|
|
107
|
+
4. Detects or scaffolds an E2E framework
|
|
108
|
+
5. Generates E2E test files
|
|
109
|
+
6. Runs only the generated tests to verify they execute
|
|
110
|
+
7. Reports `N generated, M skipped (manual)`
|
|
111
|
+
8. Commits the generated files and framework scaffolding
|
|
112
|
+
|
|
113
|
+
## Usage
|
|
114
|
+
|
|
115
|
+
```text
|
|
116
|
+
/tlc:e2e
|
|
117
|
+
/tlc:e2e 7
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
If no phase is provided, auto-detect the active phase from `ROADMAP.md` or fall back to the latest incomplete phase plan.
|
|
121
|
+
|
|
122
|
+
## Process
|
|
123
|
+
|
|
124
|
+
### Step 1: Resolve the Target Phase
|
|
125
|
+
|
|
126
|
+
Determine the phase in this order:
|
|
127
|
+
|
|
128
|
+
1. Explicit `[phase]` argument
|
|
129
|
+
2. Active/current/in-progress phase in `ROADMAP.md`
|
|
130
|
+
3. Highest-numbered `.planning/phases/*-PLAN.md` without a matching `*-VERIFIED.md`
|
|
131
|
+
|
|
132
|
+
Target file:
|
|
133
|
+
|
|
134
|
+
```text
|
|
135
|
+
.planning/phases/{N}-PLAN.md
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
If the plan file does not exist, stop and report the missing path.
|
|
139
|
+
|
|
140
|
+
### Step 2: Load Plan Context
|
|
141
|
+
|
|
142
|
+
Read:
|
|
143
|
+
- `.planning/phases/{N}-PLAN.md`
|
|
144
|
+
- `.planning/phases/{N}-DISCUSSION.md` if present
|
|
145
|
+
- `PROJECT.md` if present
|
|
146
|
+
- `.tlc.json` if present
|
|
147
|
+
|
|
148
|
+
Extract each task block and its acceptance criteria. Use the acceptance criteria as the source of truth for E2E generation.
|
|
149
|
+
|
|
150
|
+
### Step 3: Parse Acceptance Criteria
|
|
151
|
+
|
|
152
|
+
Use `server/lib/e2e/acceptance-parser.js` to normalize acceptance criteria for each task.
|
|
153
|
+
|
|
154
|
+
Rules:
|
|
155
|
+
- Parse task-by-task, not as one giant phase blob
|
|
156
|
+
- Preserve the task title as the scenario name
|
|
157
|
+
- Treat parser items with `type: 'manual'` as manual verification only
|
|
158
|
+
- Do not generate automated tests for manual-only criteria
|
|
159
|
+
- If a task has both automatable and manual criteria, generate tests for the automatable criteria and count the manual criteria as skipped
|
|
160
|
+
|
|
161
|
+
Summary counters:
|
|
162
|
+
- `generated`: number of generated E2E files written
|
|
163
|
+
- `skipped (manual)`: number of acceptance criteria skipped because they require manual verification
|
|
164
|
+
|
|
165
|
+
### Step 4: Detect or Scaffold the E2E Framework
|
|
166
|
+
|
|
167
|
+
Use `server/lib/e2e/framework-detector.js`.
|
|
168
|
+
|
|
169
|
+
Framework selection rules:
|
|
170
|
+
- If Playwright is already configured, use Playwright
|
|
171
|
+
- Else if the repo already uses `supertest` for API-level E2E coverage, use Supertest
|
|
172
|
+
- Else scaffold Playwright by default
|
|
173
|
+
|
|
174
|
+
When scaffolding Playwright:
|
|
175
|
+
- Add `playwright.config.ts` if missing
|
|
176
|
+
- Create `tests/e2e/` if no E2E directory exists
|
|
177
|
+
- Add `@playwright/test` to `devDependencies` if missing
|
|
178
|
+
- Add or update package scripts so generated tests can run cleanly
|
|
179
|
+
|
|
180
|
+
When scaffolding Supertest:
|
|
181
|
+
- Only choose this path for service-only repos with an existing Vitest/Jest-style API test setup
|
|
182
|
+
- Reuse the project's current test runner instead of inventing a new one
|
|
183
|
+
|
|
184
|
+
Do not replace an established framework just because another one is available.
|
|
185
|
+
|
|
186
|
+
### Step 5: Generate Test Files
|
|
187
|
+
|
|
188
|
+
Use `server/lib/e2e/test-generator.js` to generate the file bodies, then write the files into the detected E2E directory.
|
|
189
|
+
|
|
190
|
+
Generation rules:
|
|
191
|
+
- One generated file per task/scenario
|
|
192
|
+
- Generated files must map directly to that task's acceptance criteria
|
|
193
|
+
- Add a short generated header comment at the top of each file:
|
|
194
|
+
`Generated by /tlc:e2e from .planning/phases/{N}-PLAN.md`
|
|
195
|
+
- Prefer stable filenames derived from the task title slug
|
|
196
|
+
- Keep generated files idempotent: if the command is run again, update previously generated files in place
|
|
197
|
+
- Never overwrite clearly hand-written E2E files that do not contain the generated header comment
|
|
198
|
+
|
|
199
|
+
If a target file already exists and appears hand-written:
|
|
200
|
+
- Skip it
|
|
201
|
+
- Report it separately as a preserved manual file
|
|
202
|
+
- Do not include it in `skipped (manual)` unless the acceptance criteria were also classified as manual
|
|
203
|
+
|
|
204
|
+
### Step 6: Run the Generated Tests
|
|
205
|
+
|
|
206
|
+
Run only the generated files.
|
|
207
|
+
|
|
208
|
+
Playwright:
|
|
209
|
+
```bash
|
|
210
|
+
npx playwright test <generated-files> --reporter=list
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
Supertest with Vitest:
|
|
214
|
+
```bash
|
|
215
|
+
npx vitest run <generated-files>
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
Verification rules:
|
|
219
|
+
- The generated tests must be discovered by the runner
|
|
220
|
+
- They must execute without syntax errors, import errors, or framework bootstrapping failures
|
|
221
|
+
- If the framework was scaffolded, verify the scaffolding in the same run
|
|
222
|
+
- If execution fails because the repo is missing dependencies, install the minimum required dependencies and rerun
|
|
223
|
+
- If execution still fails, stop and report the exact failure instead of committing broken scaffolding
|
|
224
|
+
|
|
225
|
+
### Step 7: Commit
|
|
226
|
+
|
|
227
|
+
Commit when done. This is mandatory if generation and execution verification succeed.
|
|
228
|
+
|
|
229
|
+
Stage only the files created or updated for this command:
|
|
230
|
+
- Generated E2E files
|
|
231
|
+
- Framework config or package manifest changes required for E2E
|
|
232
|
+
- Lockfile updates if dependencies were installed
|
|
233
|
+
|
|
234
|
+
Commit message:
|
|
235
|
+
|
|
236
|
+
```bash
|
|
237
|
+
git commit -m "test(e2e): generate phase {N} coverage"
|
|
238
|
+
```
|
|
239
|
+
|
|
240
|
+
### Step 8: Report
|
|
241
|
+
|
|
242
|
+
Return a compact summary:
|
|
243
|
+
|
|
244
|
+
```text
|
|
245
|
+
Phase {N} E2E generation complete
|
|
246
|
+
Framework: playwright | supertest
|
|
247
|
+
Generated: {N}
|
|
248
|
+
Skipped (manual): {M}
|
|
249
|
+
Preserved manual files: {K}
|
|
250
|
+
Verification: passed
|
|
251
|
+
Commit: {sha}
|
|
252
|
+
```
|
|
253
|
+
|
|
254
|
+
If verification failed, report:
|
|
255
|
+
- framework used
|
|
256
|
+
- generated file count
|
|
257
|
+
- skipped manual count
|
|
258
|
+
- exact command run
|
|
259
|
+
- exact error
|
|
260
|
+
- whether files were left uncommitted
|
|
261
|
+
|
|
262
|
+
## Guard Rails
|
|
263
|
+
|
|
264
|
+
- Do not invent scenarios not grounded in acceptance criteria
|
|
265
|
+
- Do not overwrite hand-written E2E tests
|
|
266
|
+
- Do not claim success if the generated tests were not actually executed
|
|
267
|
+
- Do not commit if execution verification failed
|
|
268
|
+
- Keep generation scoped to the requested phase
|
|
269
|
+
- Prefer preserving existing repo conventions over TLC defaults
|
|
270
|
+
|
|
271
|
+
## Example
|
|
272
|
+
|
|
273
|
+
```text
|
|
274
|
+
> /tlc:e2e 7
|
|
275
|
+
|
|
276
|
+
Loading .planning/phases/7-PLAN.md...
|
|
277
|
+
Parsing acceptance criteria...
|
|
278
|
+
|
|
279
|
+
Detected framework: none
|
|
280
|
+
Scaffolding Playwright...
|
|
281
|
+
|
|
282
|
+
Generating E2E files...
|
|
283
|
+
Created tests/e2e/user-login.test.ts
|
|
284
|
+
Created tests/e2e/reset-password.test.ts
|
|
285
|
+
Created tests/e2e/session-timeout.test.ts
|
|
286
|
+
|
|
287
|
+
Running generated tests...
|
|
288
|
+
3 files discovered
|
|
289
|
+
3 files executed successfully
|
|
290
|
+
|
|
291
|
+
Committed: test(e2e): generate phase 7 coverage
|
|
292
|
+
|
|
293
|
+
Phase 7 E2E generation complete
|
|
294
|
+
Framework: playwright
|
|
295
|
+
Generated: 3
|
|
296
|
+
Skipped (manual): 2
|
|
297
|
+
Preserved manual files: 0
|
|
298
|
+
Verification: passed
|
|
299
|
+
Commit: abc1234
|
|
300
|
+
```
|
|
@@ -95,7 +95,41 @@ process.stdout.write(JSON.stringify(result));" 2>/dev/null
|
|
|
95
95
|
- Execute inline (Claude) AND dispatch to CLI models simultaneously
|
|
96
96
|
- Collect and merge results
|
|
97
97
|
|
|
98
|
-
**Override:** Pass `--model <name>` to route this specific run to a different model.
|
|
98
|
+
**Override:** Pass `--model <name>` to route this specific run to a different model.
|
|
99
|
+
|
|
100
|
+
After `resolveRouting` returns, immediately write `.tlc/.edge-cases-routing-active` with the active provider name from `models[0]` before doing any other edge-cases work. Remove `.tlc/.edge-cases-routing-active` on completion, cancellation, or failure cleanup.
|
|
101
|
+
|
|
102
|
+
**Routing decision:**
|
|
103
|
+
- If routing says external provider (`models[0] !== 'claude'`), follow **ONLY ORCHESTRATOR MODE** below.
|
|
104
|
+
- If routing says Claude (`models[0] === 'claude'`), follow **INLINE MODE** below.
|
|
105
|
+
|
|
106
|
+
## ORCHESTRATOR MODE
|
|
107
|
+
|
|
108
|
+
Use this mode only when `models[0]` is **NOT** `claude`.
|
|
109
|
+
|
|
110
|
+
Claude does not execute the edge-case generation instructions inline in this path. Claude acts as the orchestrator for the routed provider run:
|
|
111
|
+
|
|
112
|
+
1. Claude acts as the orchestrator for routed edge-case analysis and test generation instead of doing that analysis inline.
|
|
113
|
+
2. Read the target file or function context, current test setup, and project conventions before dispatching the request.
|
|
114
|
+
3. Package a prompt that asks the routed provider to identify meaningful edge cases, generate test coverage for them, and keep the output aligned with the project's existing test patterns.
|
|
115
|
+
4. Dispatch through the provider CLI path, using `codex exec` for Codex-style providers or `gemini -p` for Gemini-style providers, preferably via the shared dispatch layer when available.
|
|
116
|
+
5. Verify the routed result before accepting it:
|
|
117
|
+
- Confirm the generated edge cases are grounded in the actual target behavior and parameter surface.
|
|
118
|
+
- Confirm the tests are non-duplicative and materially improve coverage.
|
|
119
|
+
- Reject generic or mechanically generated cases that do not map to the real code.
|
|
120
|
+
6. If the routed output misses important boundary conditions or produces weak tests, dispatch a focused follow-up for the missing scenarios.
|
|
121
|
+
7. Handle failures explicitly:
|
|
122
|
+
- If dispatch fails because of model mismatch, auth, or missing CLI, check `.tlc/.router-state.json` for the provider's actual available model and retry once with the corrected model.
|
|
123
|
+
- If retry still fails, stop and report the exact failure to the user. Do not silently fall back to Claude inline execution.
|
|
124
|
+
- If the provider returns malformed or low-value test output, reject it and request a constrained retry.
|
|
125
|
+
8. When finished, display the routed edge-case result, persist any captured memory, remove `.tlc/.edge-cases-routing-active`, and stop. Do **not** execute Inline Mode afterward.
|
|
126
|
+
|
|
127
|
+
## INLINE MODE
|
|
128
|
+
|
|
129
|
+
Use this mode only when `models[0]` **IS** `claude`.
|
|
130
|
+
|
|
131
|
+
The existing edge-case generation instructions below are the Inline Mode instructions and should be followed unchanged.
|
|
132
|
+
|
|
99
133
|
|
|
100
134
|
## What This Does
|
|
101
135
|
|
|
@@ -136,7 +136,37 @@ Add test scripts to package.json:
|
|
|
136
136
|
}
|
|
137
137
|
```
|
|
138
138
|
|
|
139
|
-
### 5.
|
|
139
|
+
### 5. Scaffold Observability
|
|
140
|
+
|
|
141
|
+
1. Detect deploy target: run `server/lib/scaffolding/deploy-detector.js` `detectDeployTarget({ projectDir })`
|
|
142
|
+
- If result is `"unknown"`, ask user: `"Deploy target? 1) Docker Compose 2) Kubernetes/k3s 3) VPS 4) Not sure"`
|
|
143
|
+
- Store result in `.tlc.json` under `deploy.target`
|
|
144
|
+
2. Scaffold logger: run `server/lib/scaffolding/logger-scaffold.js` `scaffoldLogger({ projectDir, language })`
|
|
145
|
+
- If skipped (existing logger found), report: `"Existing logger detected — skipping"`
|
|
146
|
+
- If generated, report files created and dependencies to install
|
|
147
|
+
3. Scaffold health endpoint: run `server/lib/scaffolding/health-scaffold.js` `scaffoldHealth({ projectDir, deployTarget, framework })`
|
|
148
|
+
- Report endpoint(s) created
|
|
149
|
+
4. Enable snapshots: add to `.tlc.json`: `{ snapshots: { enabled: true, maxRetention: 10 } }`
|
|
150
|
+
|
|
151
|
+
### 6. Detect CI/CD
|
|
152
|
+
|
|
153
|
+
After observability scaffolding, inspect the project's CI/CD posture:
|
|
154
|
+
|
|
155
|
+
1. Detect CI: run `server/lib/scaffolding/ci-detector.js` `detectCI({ projectDir, fs })`
|
|
156
|
+
- Use the detector result fields: `platform`, `workflows`, and `gaps`
|
|
157
|
+
- Recognize `no-ci`, `missing-test-step`, `missing-deploy-step`, and `missing-coverage-upload`
|
|
158
|
+
2. If no CI is found (`platform === "none"` or `gaps` includes `no-ci`):
|
|
159
|
+
- Scaffold GitHub Actions using `server/lib/scaffolding/ci-scaffolder.js`
|
|
160
|
+
- Report the workflow files created and any required secrets or environment variables
|
|
161
|
+
3. If CI exists but has gaps:
|
|
162
|
+
- Report the existing CI platform and workflow files detected
|
|
163
|
+
- Report the missing capabilities from `gaps`
|
|
164
|
+
- Offer to fill the gaps instead of replacing the existing CI
|
|
165
|
+
4. If CI is complete (`gaps.length === 0`):
|
|
166
|
+
- Report: `"CI/CD OK"`
|
|
167
|
+
- Include detected platform and workflow file paths in the summary
|
|
168
|
+
|
|
169
|
+
### 7. If Tests Already Exist
|
|
140
170
|
|
|
141
171
|
- Skip framework setup
|
|
142
172
|
- Note existing test patterns for consistency
|
|
@@ -170,7 +200,7 @@ If option 2 selected, create multi-framework config:
|
|
|
170
200
|
}
|
|
171
201
|
```
|
|
172
202
|
|
|
173
|
-
###
|
|
203
|
+
### 8. Analyze Existing Code Structure
|
|
174
204
|
|
|
175
205
|
Scan the codebase and generate summary:
|
|
176
206
|
- Main directories and their purpose
|
|
@@ -178,7 +208,7 @@ Scan the codebase and generate summary:
|
|
|
178
208
|
- Entry points (main files, API routes, etc.)
|
|
179
209
|
- Dependencies and their roles
|
|
180
210
|
|
|
181
|
-
###
|
|
211
|
+
### 9. Identify Untested Code
|
|
182
212
|
|
|
183
213
|
Compare source files against test files to identify:
|
|
184
214
|
- Modules/components with no corresponding tests
|
|
@@ -201,7 +231,7 @@ Untested:
|
|
|
201
231
|
Critical paths without tests: 2 (auth, payments)
|
|
202
232
|
```
|
|
203
233
|
|
|
204
|
-
###
|
|
234
|
+
### 10. Offer Retrospective Test Writing
|
|
205
235
|
|
|
206
236
|
Ask the user:
|
|
207
237
|
|
|
@@ -406,7 +436,7 @@ Create `.claude/settings.json`:
|
|
|
406
436
|
|
|
407
437
|
If `.claude/settings.json` already exists, merge: preserve existing permissions (union), add hooks section if missing (don't overwrite existing hooks).
|
|
408
438
|
|
|
409
|
-
###
|
|
439
|
+
### 11. Create or Update PROJECT.md
|
|
410
440
|
|
|
411
441
|
If PROJECT.md doesn't exist, create it with:
|
|
412
442
|
|
|
@@ -441,7 +471,7 @@ Tests are written BEFORE implementation, not after.
|
|
|
441
471
|
|
|
442
472
|
If PROJECT.md exists, append the TLC section only.
|
|
443
473
|
|
|
444
|
-
###
|
|
474
|
+
### 12. Set Up Documentation (Optional)
|
|
445
475
|
|
|
446
476
|
If the project doesn't have docs automation:
|
|
447
477
|
|
|
@@ -459,7 +489,7 @@ Set up documentation automation? (Y/n)
|
|
|
459
489
|
|
|
460
490
|
If yes, run `/tlc:docs setup`.
|
|
461
491
|
|
|
462
|
-
###
|
|
492
|
+
### 13. Enterprise Features (Optional)
|
|
463
493
|
|
|
464
494
|
After basic setup, offer enterprise features:
|
|
465
495
|
|
|
@@ -505,7 +535,7 @@ Commands available:
|
|
|
505
535
|
/tlc:compliance - SOC 2 compliance dashboard
|
|
506
536
|
```
|
|
507
537
|
|
|
508
|
-
###
|
|
538
|
+
### 14. Report Summary
|
|
509
539
|
|
|
510
540
|
```
|
|
511
541
|
TLC initialized for [project name]
|
|
@@ -8,6 +8,7 @@ Initialize a new project with test-led development.
|
|
|
8
8
|
2. Suggest tech stack based on your needs
|
|
9
9
|
3. Create roadmap
|
|
10
10
|
4. Set up test infrastructure
|
|
11
|
+
5. Set up baseline CI workflow
|
|
11
12
|
|
|
12
13
|
## Process
|
|
13
14
|
|
|
@@ -146,6 +147,7 @@ Create PROJECT.md with tech decisions:
|
|
|
146
147
|
| Database | PostgreSQL | Relational data needs |
|
|
147
148
|
| Architecture | Modular monolith | Start simple |
|
|
148
149
|
| Hosting | Docker + Railway | Easy CI/CD |
|
|
150
|
+
| CI/CD | GitHub Actions | Baseline test and deploy workflow |
|
|
149
151
|
|
|
150
152
|
## Constraints
|
|
151
153
|
- Timeline: MVP in 4 weeks
|
|
@@ -272,6 +274,9 @@ Scaffold based on chosen stack:
|
|
|
272
274
|
project/
|
|
273
275
|
├── src/
|
|
274
276
|
├── test/
|
|
277
|
+
├── .github/
|
|
278
|
+
│ └── workflows/
|
|
279
|
+
│ └── ci.yml
|
|
275
280
|
├── .env.example
|
|
276
281
|
├── .tlc.json
|
|
277
282
|
├── .mocharc.json
|
|
@@ -309,7 +314,43 @@ Add to `package.json`:
|
|
|
309
314
|
}
|
|
310
315
|
```
|
|
311
316
|
|
|
312
|
-
### Step 9:
|
|
317
|
+
### Step 9: Scaffold Observability
|
|
318
|
+
|
|
319
|
+
During project template generation, scaffold observability alongside the rest of the project setup:
|
|
320
|
+
|
|
321
|
+
1. Detect deploy target: run `server/lib/scaffolding/deploy-detector.js` `detectDeployTarget({ projectDir })`
|
|
322
|
+
- If result is `"unknown"`, ask user: `"Deploy target? 1) Docker Compose 2) Kubernetes/k3s 3) VPS 4) Not sure"`
|
|
323
|
+
- Store result in `.tlc.json` under `deploy.target`
|
|
324
|
+
2. Scaffold logger: run `server/lib/scaffolding/logger-scaffold.js` `scaffoldLogger({ projectDir, language })`
|
|
325
|
+
- If skipped (existing logger found), report: `"Existing logger detected — skipping"`
|
|
326
|
+
- If generated, report files created and dependencies to install
|
|
327
|
+
3. Scaffold health endpoint: run `server/lib/scaffolding/health-scaffold.js` `scaffoldHealth({ projectDir, deployTarget, framework })`
|
|
328
|
+
- Report endpoint(s) created
|
|
329
|
+
4. Enable snapshots: add to `.tlc.json`: `{ snapshots: { enabled: true, maxRetention: 10 } }`
|
|
330
|
+
|
|
331
|
+
### Step 10: Detect and Scaffold CI Workflow
|
|
332
|
+
|
|
333
|
+
During project template generation, add CI/CD setup after observability:
|
|
334
|
+
|
|
335
|
+
1. Detect CI: run `server/lib/scaffolding/ci-detector.js` `detectCI({ projectDir, fs })`
|
|
336
|
+
- Inspect `platform`, `workflows`, and `gaps`
|
|
337
|
+
2. If no CI is found (`platform === "none"` or `gaps` includes `no-ci`):
|
|
338
|
+
- Scaffold GitHub Actions using `server/lib/scaffolding/ci-scaffolder.js`
|
|
339
|
+
- Include at least one workflow in `.github/workflows/` for tests, coverage, and deploy handoff where appropriate
|
|
340
|
+
- Report files created plus any secrets or variables still required
|
|
341
|
+
3. If CI already exists but has gaps:
|
|
342
|
+
- Report the existing platform and workflow files
|
|
343
|
+
- Report the gaps found by the detector
|
|
344
|
+
- Offer to fill the gaps without replacing the current CI setup
|
|
345
|
+
4. If CI is complete (`gaps.length === 0`):
|
|
346
|
+
- Report: `"CI/CD OK"`
|
|
347
|
+
|
|
348
|
+
Add CI metadata to the generated project template where applicable:
|
|
349
|
+
- CI platform: `[github-actions|jenkins|gitlab|circleci|none]`
|
|
350
|
+
- CI workflows: `[paths created or detected]`
|
|
351
|
+
- CI gaps: `[none|gap list]`
|
|
352
|
+
|
|
353
|
+
### Step 11: Set Up Documentation (Optional)
|
|
313
354
|
|
|
314
355
|
Offer to set up documentation automation:
|
|
315
356
|
|
|
@@ -330,7 +371,7 @@ If yes, run the docs setup:
|
|
|
330
371
|
- Add `.github/workflows/docs-sync.yml`
|
|
331
372
|
- Add npm scripts for docs maintenance
|
|
332
373
|
|
|
333
|
-
### Step
|
|
374
|
+
### Step 12: Enterprise Features (Optional)
|
|
334
375
|
|
|
335
376
|
If compliance requirements were mentioned in Step 1, or for enterprise projects:
|
|
336
377
|
|
|
@@ -395,5 +436,6 @@ Interactive flow that:
|
|
|
395
436
|
3. Lets you adjust
|
|
396
437
|
4. Creates roadmap
|
|
397
438
|
5. Sets up tests
|
|
398
|
-
6.
|
|
399
|
-
7.
|
|
439
|
+
6. Scaffolds observability
|
|
440
|
+
7. Sets up documentation automation
|
|
441
|
+
8. Optionally enables enterprise features
|
|
@@ -97,6 +97,39 @@ process.stdout.write(JSON.stringify(result));" 2>/dev/null
|
|
|
97
97
|
|
|
98
98
|
**Override:** Pass `--model <name>` to route this specific run to a different model.
|
|
99
99
|
|
|
100
|
+
After `resolveRouting` returns, immediately write `.tlc/.plan-routing-active` with the active provider name from `models[0]` before doing any other plan work. Remove `.tlc/.plan-routing-active` on completion, cancellation, or failure cleanup.
|
|
101
|
+
|
|
102
|
+
**Routing decision:**
|
|
103
|
+
- If routing says external provider (`models[0] !== 'claude'`), follow **ONLY ORCHESTRATOR MODE** below.
|
|
104
|
+
- If routing says Claude (`models[0] === 'claude'`), follow **INLINE MODE** below.
|
|
105
|
+
|
|
106
|
+
## ORCHESTRATOR MODE
|
|
107
|
+
|
|
108
|
+
Use this mode only when `models[0]` is **NOT** `claude`.
|
|
109
|
+
|
|
110
|
+
Claude does not execute the planning instructions inline in this path. Claude acts as the orchestrator for the routed provider run:
|
|
111
|
+
|
|
112
|
+
1. Read the roadmap, current phase context, discussion artifacts, project constraints, and any existing research before dispatching planning work.
|
|
113
|
+
2. Prepare a full planning prompt that asks the routed provider to research, decompose, and sequence the phase using the project's architectural and task-quality standards.
|
|
114
|
+
3. Dispatch through the provider CLI path, using `codex exec` for Codex-style providers or `gemini -p` for Gemini-style providers, preferably via the shared dispatch layer when available.
|
|
115
|
+
4. Verify the returned plan before accepting it:
|
|
116
|
+
- Confirm it addresses the correct phase and reflects the actual roadmap goal.
|
|
117
|
+
- Confirm tasks are actionable, testable, dependency-aware, and aligned with file/folder sizing constraints.
|
|
118
|
+
- Confirm the plan contains real implementation thinking rather than generic project-management filler.
|
|
119
|
+
5. If the first routed result is incomplete, contradictory, or too vague to execute, send a focused follow-up planning dispatch that requests the missing structure instead of accepting it.
|
|
120
|
+
6. Handle failures explicitly:
|
|
121
|
+
- If dispatch fails because of model mismatch, auth, or missing CLI, check `.tlc/.router-state.json` for the provider's actual available model and retry once with the corrected model.
|
|
122
|
+
- If retry still fails, stop and report the exact failure to the user. Do not silently fall back to Claude inline execution.
|
|
123
|
+
- If the provider produces a weak plan, reject it and re-dispatch with tighter scope and success criteria.
|
|
124
|
+
7. When finished, display the routed planning result, persist any captured memory, remove `.tlc/.plan-routing-active`, and stop. Do **not** execute Inline Mode afterward.
|
|
125
|
+
|
|
126
|
+
## INLINE MODE
|
|
127
|
+
|
|
128
|
+
Use this mode only when `models[0]` **IS** `claude`.
|
|
129
|
+
|
|
130
|
+
The existing planning instructions below are the Inline Mode instructions and should be followed unchanged.
|
|
131
|
+
|
|
132
|
+
|
|
100
133
|
## Architectural Standards
|
|
101
134
|
|
|
102
135
|
**Plan like a principal engineer designing for scale:**
|