tlc-claude-code 1.8.5 → 2.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude/commands/tlc/bootstrap.md +77 -0
- package/.claude/commands/tlc/build.md +20 -6
- package/.claude/commands/tlc/deploy.md +194 -2
- package/.claude/commands/tlc/e2e-verify.md +214 -0
- package/.claude/commands/tlc/guard.md +191 -0
- package/.claude/commands/tlc/help.md +32 -0
- package/.claude/commands/tlc/init.md +73 -37
- package/.claude/commands/tlc/llm.md +19 -4
- package/.claude/commands/tlc/preflight.md +134 -0
- package/.claude/commands/tlc/recall.md +87 -0
- package/.claude/commands/tlc/remember.md +71 -0
- package/.claude/commands/tlc/review.md +17 -4
- package/.claude/commands/tlc/watchci.md +159 -0
- package/.claude/hooks/tlc-block-tools.sh +41 -0
- package/.claude/hooks/tlc-capture-exchange.sh +50 -0
- package/.claude/hooks/tlc-post-build.sh +38 -0
- package/.claude/hooks/tlc-post-push.sh +22 -0
- package/.claude/hooks/tlc-prompt-guard.sh +69 -0
- package/.claude/hooks/tlc-session-init.sh +123 -0
- package/CLAUDE.md +96 -201
- package/bin/install.js +171 -2
- package/bin/postinstall.js +45 -26
- package/dashboard-web/dist/assets/index-CdS5CHqu.css +1 -0
- package/dashboard-web/dist/assets/index-CwNPPVpg.js +483 -0
- package/dashboard-web/dist/assets/index-CwNPPVpg.js.map +1 -0
- package/dashboard-web/dist/index.html +2 -2
- package/docker-compose.dev.yml +18 -12
- package/package.json +3 -1
- package/server/index.js +240 -1
- package/server/lib/bug-writer.js +204 -0
- package/server/lib/bug-writer.test.js +279 -0
- package/server/lib/capture-bridge.js +242 -0
- package/server/lib/capture-bridge.test.js +363 -0
- package/server/lib/capture-guard.js +140 -0
- package/server/lib/capture-guard.test.js +182 -0
- package/server/lib/claude-cascade.js +247 -0
- package/server/lib/claude-cascade.test.js +245 -0
- package/server/lib/command-runner.js +159 -0
- package/server/lib/command-runner.test.js +92 -0
- package/server/lib/context-injection.js +121 -0
- package/server/lib/context-injection.test.js +340 -0
- package/server/lib/conversation-chunker.js +320 -0
- package/server/lib/conversation-chunker.test.js +573 -0
- package/server/lib/deploy/runners/dependency-runner.js +106 -0
- package/server/lib/deploy/runners/dependency-runner.test.js +148 -0
- package/server/lib/deploy/runners/secrets-runner.js +174 -0
- package/server/lib/deploy/runners/secrets-runner.test.js +127 -0
- package/server/lib/deploy/security-gates.js +11 -24
- package/server/lib/deploy/security-gates.test.js +9 -2
- package/server/lib/deploy-engine.js +182 -0
- package/server/lib/deploy-engine.test.js +147 -0
- package/server/lib/docker-api.js +137 -0
- package/server/lib/docker-api.test.js +202 -0
- package/server/lib/docker-client.js +297 -0
- package/server/lib/docker-client.test.js +308 -0
- package/server/lib/embedding-client.js +160 -0
- package/server/lib/embedding-client.test.js +243 -0
- package/server/lib/global-config.js +198 -0
- package/server/lib/global-config.test.js +288 -0
- package/server/lib/inherited-search.js +184 -0
- package/server/lib/inherited-search.test.js +343 -0
- package/server/lib/input-sanitizer.js +86 -0
- package/server/lib/input-sanitizer.test.js +117 -0
- package/server/lib/launchd-agent.js +225 -0
- package/server/lib/launchd-agent.test.js +185 -0
- package/server/lib/memory-api.js +182 -0
- package/server/lib/memory-api.test.js +320 -0
- package/server/lib/memory-bridge-e2e.test.js +160 -0
- package/server/lib/memory-committer.js +18 -4
- package/server/lib/memory-committer.test.js +21 -0
- package/server/lib/memory-hooks-capture.test.js +415 -0
- package/server/lib/memory-hooks-integration.test.js +98 -0
- package/server/lib/memory-hooks.js +139 -0
- package/server/lib/memory-inheritance.js +179 -0
- package/server/lib/memory-inheritance.test.js +360 -0
- package/server/lib/memory-store-adapter.js +105 -0
- package/server/lib/memory-store-adapter.test.js +141 -0
- package/server/lib/memory-wiring-e2e.test.js +93 -0
- package/server/lib/nginx-config.js +114 -0
- package/server/lib/nginx-config.test.js +82 -0
- package/server/lib/ollama-health.js +91 -0
- package/server/lib/ollama-health.test.js +74 -0
- package/server/lib/plan-writer.js +196 -0
- package/server/lib/plan-writer.test.js +298 -0
- package/server/lib/port-guard.js +44 -0
- package/server/lib/port-guard.test.js +65 -0
- package/server/lib/project-scanner.js +302 -0
- package/server/lib/project-scanner.test.js +541 -0
- package/server/lib/project-status.js +302 -0
- package/server/lib/project-status.test.js +470 -0
- package/server/lib/projects-registry.js +237 -0
- package/server/lib/projects-registry.test.js +275 -0
- package/server/lib/recall-command.js +207 -0
- package/server/lib/recall-command.test.js +306 -0
- package/server/lib/remember-command.js +98 -0
- package/server/lib/remember-command.test.js +288 -0
- package/server/lib/rich-capture.js +221 -0
- package/server/lib/rich-capture.test.js +312 -0
- package/server/lib/roadmap-api.js +200 -0
- package/server/lib/roadmap-api.test.js +318 -0
- package/server/lib/security/crypto-utils.test.js +2 -2
- package/server/lib/semantic-recall.js +242 -0
- package/server/lib/semantic-recall.test.js +463 -0
- package/server/lib/setup-generator.js +315 -0
- package/server/lib/setup-generator.test.js +303 -0
- package/server/lib/ssh-client.js +184 -0
- package/server/lib/ssh-client.test.js +127 -0
- package/server/lib/test-inventory.js +112 -0
- package/server/lib/test-inventory.test.js +360 -0
- package/server/lib/vector-indexer.js +246 -0
- package/server/lib/vector-indexer.test.js +459 -0
- package/server/lib/vector-store.js +260 -0
- package/server/lib/vector-store.test.js +706 -0
- package/server/lib/vps-api.js +184 -0
- package/server/lib/vps-api.test.js +208 -0
- package/server/lib/vps-bootstrap.js +124 -0
- package/server/lib/vps-bootstrap.test.js +79 -0
- package/server/lib/vps-monitor.js +126 -0
- package/server/lib/vps-monitor.test.js +98 -0
- package/server/lib/workspace-api.js +992 -0
- package/server/lib/workspace-api.test.js +1217 -0
- package/server/lib/workspace-bootstrap.js +164 -0
- package/server/lib/workspace-bootstrap.test.js +503 -0
- package/server/lib/workspace-context.js +129 -0
- package/server/lib/workspace-context.test.js +214 -0
- package/server/lib/workspace-detector.js +162 -0
- package/server/lib/workspace-detector.test.js +193 -0
- package/server/lib/workspace-init.js +307 -0
- package/server/lib/workspace-init.test.js +244 -0
- package/server/lib/workspace-snapshot.js +236 -0
- package/server/lib/workspace-snapshot.test.js +444 -0
- package/server/lib/workspace-watcher.js +162 -0
- package/server/lib/workspace-watcher.test.js +257 -0
- package/server/package-lock.json +1306 -17
- package/server/package.json +7 -0
- package/dashboard-web/dist/assets/index-B1I_joSL.js +0 -393
- package/dashboard-web/dist/assets/index-B1I_joSL.js.map +0 -1
- package/dashboard-web/dist/assets/index-Trhg1C1Y.css +0 -1
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
# /tlc:bootstrap - Workspace Bootstrap
|
|
2
|
+
|
|
3
|
+
Clone all repos and set up a workspace on a new machine.
|
|
4
|
+
|
|
5
|
+
## Usage
|
|
6
|
+
|
|
7
|
+
```
|
|
8
|
+
/tlc:bootstrap
|
|
9
|
+
/tlc:bootstrap --dry-run
|
|
10
|
+
/tlc:bootstrap --skip-install
|
|
11
|
+
/tlc:bootstrap --parallel 5
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
## What This Does
|
|
15
|
+
|
|
16
|
+
1. Reads `projects.json` from the workspace root
|
|
17
|
+
2. Clones all repos that aren't already present
|
|
18
|
+
3. Checks out the correct branch per repo
|
|
19
|
+
4. Installs dependencies (npm install, pip install, etc.)
|
|
20
|
+
5. Rebuilds vector indexes from memory text files
|
|
21
|
+
6. Reports summary
|
|
22
|
+
|
|
23
|
+
## Options
|
|
24
|
+
|
|
25
|
+
| Flag | Default | Description |
|
|
26
|
+
|------|---------|-------------|
|
|
27
|
+
| `--dry-run` | false | Show what would be cloned without doing it |
|
|
28
|
+
| `--skip-install` | false | Skip dependency installation |
|
|
29
|
+
| `--parallel N` | 3 | Number of concurrent clones |
|
|
30
|
+
|
|
31
|
+
## Process
|
|
32
|
+
|
|
33
|
+
### Step 1: Read Registry
|
|
34
|
+
|
|
35
|
+
Load `projects.json` from workspace root. If it doesn't exist:
|
|
36
|
+
```
|
|
37
|
+
No projects.json found.
|
|
38
|
+
|
|
39
|
+
Run /tlc:init to initialize this workspace, or create projects.json manually.
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
### Step 2: Clone Repos
|
|
43
|
+
|
|
44
|
+
For each project in the registry:
|
|
45
|
+
- If directory already exists with `.git/` → skip
|
|
46
|
+
- Otherwise → `git clone <url> <path>`
|
|
47
|
+
- Checkout the `defaultBranch`
|
|
48
|
+
|
|
49
|
+
### Step 3: Install Dependencies
|
|
50
|
+
|
|
51
|
+
For each cloned repo (unless `--skip-install`):
|
|
52
|
+
- Node.js (`package.json`) → `npm install`
|
|
53
|
+
- Python (`requirements.txt`) → `pip install -r requirements.txt`
|
|
54
|
+
- Go (`go.mod`) → `go mod download`
|
|
55
|
+
|
|
56
|
+
### Step 4: Rebuild Vectors
|
|
57
|
+
|
|
58
|
+
If Ollama is available:
|
|
59
|
+
- Pull embedding model: `ollama pull mxbai-embed-large`
|
|
60
|
+
- Rebuild vector indexes from memory text files
|
|
61
|
+
|
|
62
|
+
### Step 5: Summary
|
|
63
|
+
|
|
64
|
+
```
|
|
65
|
+
Workspace bootstrap complete:
|
|
66
|
+
Cloned: 3 repos
|
|
67
|
+
Skipped: 1 (already present)
|
|
68
|
+
Failed: 0
|
|
69
|
+
|
|
70
|
+
All repos ready. Run /tlc:progress to see project status.
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
## Related Commands
|
|
74
|
+
|
|
75
|
+
- `/tlc:init` — Initialize TLC in an existing project
|
|
76
|
+
- `/tlc:recall` — Search workspace memory
|
|
77
|
+
- `/tlc:progress` — Check project status
|
|
@@ -636,21 +636,35 @@ git add src/auth/login.ts tests/auth/login.test.ts
|
|
|
636
636
|
git commit -m "feat: {task-title} - phase {N}"
|
|
637
637
|
```
|
|
638
638
|
|
|
639
|
-
#### 7e. Mark Task Complete (
|
|
639
|
+
#### 7e. Mark Task Complete in PLAN.md (MANDATORY)
|
|
640
640
|
|
|
641
|
-
|
|
641
|
+
**Always update the task marker in PLAN.md after tests pass.** This is not optional.
|
|
642
642
|
|
|
643
|
-
1.
|
|
644
|
-
2.
|
|
645
|
-
3.
|
|
643
|
+
1. Open `.planning/phases/{phase}-PLAN.md`
|
|
644
|
+
2. Find the task heading: `### Task {N}: {title} [ ]` (or `[>@{user}]`)
|
|
645
|
+
3. Update the marker:
|
|
646
|
+
- Single-user: `[ ]` → `[x]`
|
|
647
|
+
- Multi-user: `[>@{user}]` → `[x@{user}]`
|
|
648
|
+
4. Include the plan update in the same commit (step 7d) or commit separately
|
|
649
|
+
|
|
650
|
+
**Example:**
|
|
651
|
+
```
|
|
652
|
+
### Task 3: Tabbed Project Detail Page [ ] ← before
|
|
653
|
+
### Task 3: Tabbed Project Detail Page [x] ← after
|
|
654
|
+
```
|
|
655
|
+
|
|
656
|
+
This keeps the plan file as the single source of truth for task status. Do NOT wait until the end of the phase — mark each task done immediately after its tests pass.
|
|
657
|
+
|
|
658
|
+
If in multi-user mode, also push to share progress with team.
|
|
646
659
|
|
|
647
660
|
#### 7f. Move to next task
|
|
648
|
-
Repeat 7a-
|
|
661
|
+
Repeat 7a-7e for each task in the phase.
|
|
649
662
|
|
|
650
663
|
**Critical Rules:**
|
|
651
664
|
- Implement **one task at a time**
|
|
652
665
|
- Run tests **after each task**
|
|
653
666
|
- Commit **after each passing task**
|
|
667
|
+
- **Mark task `[x]` in PLAN.md after each passing task** — never defer this
|
|
654
668
|
- Do NOT batch — sequential execution catches issues early
|
|
655
669
|
|
|
656
670
|
### Step 8: Verify All Tests Pass (Green)
|
|
@@ -648,9 +648,199 @@ Add to GitHub deploy keys (read-only):
|
|
|
648
648
|
https://github.com/org/repo/settings/keys
|
|
649
649
|
```
|
|
650
650
|
|
|
651
|
-
###
|
|
651
|
+
### Secrets Management with HashiCorp Vault
|
|
652
652
|
|
|
653
|
-
|
|
653
|
+
**Never store secrets in `.env` files, code, or git.** All secrets go through HashiCorp Vault.
|
|
654
|
+
|
|
655
|
+
#### Setup Vault
|
|
656
|
+
|
|
657
|
+
```
|
|
658
|
+
> /tlc:deploy vault setup
|
|
659
|
+
|
|
660
|
+
HashiCorp Vault Setup
|
|
661
|
+
════════════════════════════════════════════════
|
|
662
|
+
|
|
663
|
+
Vault address: https://vault.example.com
|
|
664
|
+
Auth method: [token/approle/github] approle
|
|
665
|
+
|
|
666
|
+
Configuring AppRole auth for TLC...
|
|
667
|
+
✓ Created policy: tlc-deploy-policy
|
|
668
|
+
✓ Created AppRole: tlc-deploy
|
|
669
|
+
✓ Role ID: 7c8a9b2d-...
|
|
670
|
+
✓ Secret ID: (stored in CI secrets)
|
|
671
|
+
|
|
672
|
+
Secrets engine: kv-v2 at secret/tlc/{project}
|
|
673
|
+
|
|
674
|
+
Configuration saved to .tlc.json (no secrets stored)
|
|
675
|
+
```
|
|
676
|
+
|
|
677
|
+
#### Secret Paths
|
|
678
|
+
|
|
679
|
+
Secrets are organized by environment in Vault:
|
|
680
|
+
|
|
681
|
+
```
|
|
682
|
+
secret/tlc/{project}/
|
|
683
|
+
├── dev/
|
|
684
|
+
│ ├── database_url
|
|
685
|
+
│ ├── jwt_secret
|
|
686
|
+
│ ├── slack_webhook
|
|
687
|
+
│ └── github_webhook_secret
|
|
688
|
+
├── staging/
|
|
689
|
+
│ ├── database_url
|
|
690
|
+
│ ├── jwt_secret
|
|
691
|
+
│ └── api_keys
|
|
692
|
+
└── production/
|
|
693
|
+
├── database_url
|
|
694
|
+
├── jwt_secret
|
|
695
|
+
├── api_keys
|
|
696
|
+
└── ssl_certs
|
|
697
|
+
```
|
|
698
|
+
|
|
699
|
+
#### Vault Commands
|
|
700
|
+
|
|
701
|
+
```
|
|
702
|
+
> /tlc:deploy vault set dev/jwt_secret "new-secret-value"
|
|
703
|
+
✓ Secret stored at secret/tlc/my-app/dev/jwt_secret
|
|
704
|
+
|
|
705
|
+
> /tlc:deploy vault list dev
|
|
706
|
+
Secrets at secret/tlc/my-app/dev/:
|
|
707
|
+
database_url
|
|
708
|
+
jwt_secret
|
|
709
|
+
slack_webhook
|
|
710
|
+
github_webhook_secret
|
|
711
|
+
|
|
712
|
+
> /tlc:deploy vault get dev/jwt_secret
|
|
713
|
+
✓ Value copied to clipboard (not displayed)
|
|
714
|
+
|
|
715
|
+
> /tlc:deploy vault rotate dev/jwt_secret
|
|
716
|
+
✓ New secret generated and stored
|
|
717
|
+
✓ Containers using this secret will be restarted
|
|
718
|
+
```
|
|
719
|
+
|
|
720
|
+
#### How Containers Get Secrets
|
|
721
|
+
|
|
722
|
+
Secrets are injected at deploy time, never baked into images:
|
|
723
|
+
|
|
724
|
+
```yaml
|
|
725
|
+
# docker-compose.yml (generated per deployment)
|
|
726
|
+
services:
|
|
727
|
+
app:
|
|
728
|
+
build: ./deployments/${BRANCH}
|
|
729
|
+
environment:
|
|
730
|
+
- VAULT_ADDR=${VAULT_ADDR}
|
|
731
|
+
- VAULT_ROLE_ID=${VAULT_ROLE_ID}
|
|
732
|
+
# Secrets fetched at startup via vault-agent sidecar
|
|
733
|
+
# OR injected via envconsul/consul-template
|
|
734
|
+
```
|
|
735
|
+
|
|
736
|
+
**Option A: Vault Agent Sidecar (recommended)**
|
|
737
|
+
|
|
738
|
+
```yaml
|
|
739
|
+
services:
|
|
740
|
+
vault-agent:
|
|
741
|
+
image: hashicorp/vault
|
|
742
|
+
command: vault agent -config=/etc/vault/agent.hcl
|
|
743
|
+
volumes:
|
|
744
|
+
- shared-secrets:/secrets
|
|
745
|
+
|
|
746
|
+
app:
|
|
747
|
+
depends_on: [vault-agent]
|
|
748
|
+
volumes:
|
|
749
|
+
- shared-secrets:/secrets:ro
|
|
750
|
+
environment:
|
|
751
|
+
- ENV_FILE=/secrets/.env
|
|
752
|
+
```
|
|
753
|
+
|
|
754
|
+
**Option B: envconsul (simpler)**
|
|
755
|
+
|
|
756
|
+
```dockerfile
|
|
757
|
+
# In app Dockerfile
|
|
758
|
+
RUN curl -fsSL https://releases.hashicorp.com/envconsul/0.13.2/envconsul_0.13.2_linux_amd64.tgz | tar xz
|
|
759
|
+
ENTRYPOINT ["envconsul", "-vault-addr", "$VAULT_ADDR", "-secret", "secret/tlc/${PROJECT}/${ENV}", "npm", "start"]
|
|
760
|
+
```
|
|
761
|
+
|
|
762
|
+
**Option C: CI-time injection (simplest, for non-production)**
|
|
763
|
+
|
|
764
|
+
```yaml
|
|
765
|
+
# GitHub Actions
|
|
766
|
+
- name: Fetch secrets from Vault
|
|
767
|
+
uses: hashicorp/vault-action@v3
|
|
768
|
+
with:
|
|
769
|
+
url: ${{ secrets.VAULT_ADDR }}
|
|
770
|
+
method: approle
|
|
771
|
+
roleId: ${{ secrets.VAULT_ROLE_ID }}
|
|
772
|
+
secretId: ${{ secrets.VAULT_SECRET_ID }}
|
|
773
|
+
secrets: |
|
|
774
|
+
secret/data/tlc/${{ env.PROJECT }}/dev database_url | DATABASE_URL;
|
|
775
|
+
secret/data/tlc/${{ env.PROJECT }}/dev jwt_secret | JWT_SECRET;
|
|
776
|
+
```
|
|
777
|
+
|
|
778
|
+
#### Vault Configuration in .tlc.json
|
|
779
|
+
|
|
780
|
+
```json
|
|
781
|
+
{
|
|
782
|
+
"deploy": {
|
|
783
|
+
"domain": "project.example.com",
|
|
784
|
+
"vault": {
|
|
785
|
+
"enabled": true,
|
|
786
|
+
"addr": "https://vault.example.com",
|
|
787
|
+
"auth": "approle",
|
|
788
|
+
"secretPath": "secret/tlc/my-app",
|
|
789
|
+
"injection": "vault-agent",
|
|
790
|
+
"environments": ["dev", "staging", "production"]
|
|
791
|
+
}
|
|
792
|
+
}
|
|
793
|
+
}
|
|
794
|
+
```
|
|
795
|
+
|
|
796
|
+
**No secrets in `.tlc.json`.** Only the Vault address and paths. Role IDs and Secret IDs live in CI secrets or the deploy server's own Vault agent.
|
|
797
|
+
|
|
798
|
+
#### Secret Rotation
|
|
799
|
+
|
|
800
|
+
```
|
|
801
|
+
> /tlc:deploy vault rotate-all dev
|
|
802
|
+
|
|
803
|
+
Rotating all secrets for dev environment...
|
|
804
|
+
✓ database_url — rotated (new password generated)
|
|
805
|
+
✓ jwt_secret — rotated (32-byte random)
|
|
806
|
+
✓ slack_webhook — skipped (external, rotate manually)
|
|
807
|
+
✓ github_webhook_secret — rotated
|
|
808
|
+
|
|
809
|
+
Restarting affected containers...
|
|
810
|
+
✓ dev containers restarted with new secrets
|
|
811
|
+
|
|
812
|
+
Rotation complete. Old secrets invalidated.
|
|
813
|
+
```
|
|
814
|
+
|
|
815
|
+
#### Migration from .env Files
|
|
816
|
+
|
|
817
|
+
If you have existing `.env` files:
|
|
818
|
+
|
|
819
|
+
```
|
|
820
|
+
> /tlc:deploy vault migrate
|
|
821
|
+
|
|
822
|
+
Found .env files:
|
|
823
|
+
/opt/tlc-deploy/.env (4 secrets)
|
|
824
|
+
.env.local (2 secrets)
|
|
825
|
+
|
|
826
|
+
Migrating to Vault...
|
|
827
|
+
✓ JWT_SECRET → secret/tlc/my-app/dev/jwt_secret
|
|
828
|
+
✓ DATABASE_URL → secret/tlc/my-app/dev/database_url
|
|
829
|
+
✓ GITHUB_WEBHOOK_SECRET → secret/tlc/my-app/dev/github_webhook_secret
|
|
830
|
+
✓ SLACK_WEBHOOK_URL → secret/tlc/my-app/dev/slack_webhook
|
|
831
|
+
|
|
832
|
+
Securely deleting .env files...
|
|
833
|
+
✓ /opt/tlc-deploy/.env shredded
|
|
834
|
+
✓ .env.local shredded
|
|
835
|
+
|
|
836
|
+
Check .gitignore includes: .env* ✓
|
|
837
|
+
|
|
838
|
+
Migration complete. All secrets now in Vault.
|
|
839
|
+
```
|
|
840
|
+
|
|
841
|
+
### Environment Variables (Legacy / Non-Vault)
|
|
842
|
+
|
|
843
|
+
If Vault is not configured, secrets fall back to `.env` files on the deploy server. **This is not recommended for production.**
|
|
654
844
|
|
|
655
845
|
```bash
|
|
656
846
|
# /opt/tlc-deploy/.env
|
|
@@ -660,6 +850,8 @@ GITHUB_WEBHOOK_SECRET=webhook-secret
|
|
|
660
850
|
SLACK_WEBHOOK_URL=https://hooks.slack.com/...
|
|
661
851
|
```
|
|
662
852
|
|
|
853
|
+
**Warning:** TLC will flag `.env` files containing secrets during `/tlc:security` scans.
|
|
854
|
+
|
|
663
855
|
## Cleanup
|
|
664
856
|
|
|
665
857
|
### Remove old deployments
|
|
@@ -0,0 +1,214 @@
|
|
|
1
|
+
# /tlc:e2e-verify - E2E Visual Verification
|
|
2
|
+
|
|
3
|
+
When code is "done", verify it actually works by running e2e tests, taking screenshots, and checking logs. Trust but verify.
|
|
4
|
+
|
|
5
|
+
## What This Does
|
|
6
|
+
|
|
7
|
+
1. **Starts the dev server** (if not already running)
|
|
8
|
+
2. **Runs Playwright e2e tests** to exercise the application
|
|
9
|
+
3. **Takes screenshots** of key pages/states
|
|
10
|
+
4. **Reads screenshots visually** to verify UI correctness
|
|
11
|
+
5. **Checks server and browser console logs** for errors
|
|
12
|
+
6. **Reports findings** and fixes issues
|
|
13
|
+
|
|
14
|
+
This replaces the manual "let me check if it actually works" step.
|
|
15
|
+
|
|
16
|
+
## Usage
|
|
17
|
+
|
|
18
|
+
```
|
|
19
|
+
/tlc:e2e-verify
|
|
20
|
+
/tlc:e2e-verify dashboard # verify specific area
|
|
21
|
+
/tlc:e2e-verify --screenshots # screenshot-heavy mode
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
## Process
|
|
25
|
+
|
|
26
|
+
### Step 1: Ensure Dev Server is Running
|
|
27
|
+
|
|
28
|
+
Check if the server is already up:
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
curl -s http://localhost:3148/health || curl -s http://localhost:3148/ 2>/dev/null
|
|
32
|
+
curl -s http://localhost:4000/ 2>/dev/null
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
If not running:
|
|
36
|
+
- Start the TLC server: `node server/index.js &` (port from `.tlc.json`)
|
|
37
|
+
- Start the dashboard dev server if needed: `cd dashboard-web && npm run dev &`
|
|
38
|
+
- Wait for both to be ready (poll health endpoints)
|
|
39
|
+
|
|
40
|
+
### Step 2: Run Existing E2E Tests
|
|
41
|
+
|
|
42
|
+
Check which Playwright config applies:
|
|
43
|
+
- Root: `playwright.config.ts` (server e2e, baseURL `localhost:3147`)
|
|
44
|
+
- Dashboard: `dashboard-web/playwright.config.ts` (dashboard e2e, baseURL `localhost:4000`)
|
|
45
|
+
|
|
46
|
+
Run the relevant tests:
|
|
47
|
+
|
|
48
|
+
```bash
|
|
49
|
+
npx playwright test --reporter=list
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
- Capture stdout/stderr
|
|
53
|
+
- Note any failures
|
|
54
|
+
|
|
55
|
+
### Step 3: Take Screenshots
|
|
56
|
+
|
|
57
|
+
Use Playwright to screenshot key pages. Create a temporary test script if no existing screenshots cover the area:
|
|
58
|
+
|
|
59
|
+
```bash
|
|
60
|
+
npx playwright test --project=chromium --reporter=list
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
For targeted screenshots, use Playwright's screenshot API via a quick script:
|
|
64
|
+
|
|
65
|
+
```javascript
|
|
66
|
+
// Save to /tmp/tlc-screenshots/
|
|
67
|
+
const { chromium } = require('playwright');
|
|
68
|
+
const browser = await chromium.launch();
|
|
69
|
+
const page = await browser.newPage();
|
|
70
|
+
|
|
71
|
+
// Screenshot key pages
|
|
72
|
+
await page.goto('http://localhost:4000');
|
|
73
|
+
await page.screenshot({ path: '/tmp/tlc-screenshots/dashboard-home.png', fullPage: true });
|
|
74
|
+
|
|
75
|
+
// Login flow
|
|
76
|
+
await page.goto('http://localhost:4000/login');
|
|
77
|
+
await page.screenshot({ path: '/tmp/tlc-screenshots/login.png', fullPage: true });
|
|
78
|
+
|
|
79
|
+
// After login
|
|
80
|
+
await page.fill('[data-testid="email"]', 'user@local.com');
|
|
81
|
+
await page.fill('[data-testid="password"]', '2026rocks');
|
|
82
|
+
await page.click('[data-testid="login-btn"]');
|
|
83
|
+
await page.waitForURL('**/dashboard**');
|
|
84
|
+
await page.screenshot({ path: '/tmp/tlc-screenshots/after-login.png', fullPage: true });
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
Adapt the script based on what was changed — screenshot the areas affected by recent work.
|
|
88
|
+
|
|
89
|
+
### Step 4: Visual Inspection
|
|
90
|
+
|
|
91
|
+
**Read each screenshot using the Read tool** (Claude is multimodal and can see images).
|
|
92
|
+
|
|
93
|
+
For each screenshot, check:
|
|
94
|
+
- **Layout**: Is the page rendering correctly? No overlapping elements, broken grids?
|
|
95
|
+
- **Content**: Is text readable? Are labels correct? No "undefined" or "[object Object]"?
|
|
96
|
+
- **State**: Are loading states resolved? No spinners stuck? No empty states where data should be?
|
|
97
|
+
- **Errors**: Any visible error messages, red banners, or console error overlays?
|
|
98
|
+
- **Styling**: Does it look intentional? No broken CSS, missing icons, or unstyled elements?
|
|
99
|
+
|
|
100
|
+
### Step 5: Check Logs
|
|
101
|
+
|
|
102
|
+
**Server logs:**
|
|
103
|
+
```bash
|
|
104
|
+
# Check for errors in server output
|
|
105
|
+
# If server was started with output capture, read the log file
|
|
106
|
+
cat /tmp/tlc-server.log 2>/dev/null | grep -i "error\|warn\|fail" | tail -20
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
**Browser console:**
|
|
110
|
+
- Playwright captures console messages — check test output for console errors
|
|
111
|
+
- Look for: uncaught exceptions, failed network requests, React/Vue warnings
|
|
112
|
+
|
|
113
|
+
**Network requests:**
|
|
114
|
+
- Check for failed API calls (4xx, 5xx responses)
|
|
115
|
+
- Check for CORS errors
|
|
116
|
+
- Check for slow responses (>2s)
|
|
117
|
+
|
|
118
|
+
### Step 6: Report and Fix
|
|
119
|
+
|
|
120
|
+
**If everything looks good:**
|
|
121
|
+
```
|
|
122
|
+
✅ E2E Verification Complete
|
|
123
|
+
|
|
124
|
+
Screenshots reviewed:
|
|
125
|
+
- Dashboard home: ✅ Renders correctly
|
|
126
|
+
- Login page: ✅ Form visible, styled correctly
|
|
127
|
+
- After login: ✅ Dashboard loads with data
|
|
128
|
+
|
|
129
|
+
Logs: No errors found
|
|
130
|
+
Tests: 12/12 passing
|
|
131
|
+
|
|
132
|
+
Code is verified.
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
**If issues found:**
|
|
136
|
+
```
|
|
137
|
+
⚠️ E2E Verification Found Issues
|
|
138
|
+
|
|
139
|
+
1. Dashboard home: Table header misaligned on narrow viewport
|
|
140
|
+
2. Server log: "Warning: deprecated API endpoint /api/v1/stats called"
|
|
141
|
+
3. Console: "Failed to load resource: 404 /api/fonts/inter.woff2"
|
|
142
|
+
|
|
143
|
+
Fixing...
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
Then fix each issue:
|
|
147
|
+
- Read the relevant source files
|
|
148
|
+
- Apply fixes
|
|
149
|
+
- Re-run the verification for the fixed areas
|
|
150
|
+
- Loop until clean
|
|
151
|
+
|
|
152
|
+
### Step 7: Final Confirmation
|
|
153
|
+
|
|
154
|
+
After all fixes:
|
|
155
|
+
- Re-run full e2e suite
|
|
156
|
+
- Take fresh screenshots of fixed areas
|
|
157
|
+
- Confirm visually
|
|
158
|
+
- Report final status
|
|
159
|
+
|
|
160
|
+
## Screenshot Locations
|
|
161
|
+
|
|
162
|
+
Screenshots are saved to `/tmp/tlc-screenshots/` for the session. Clean up after verification.
|
|
163
|
+
|
|
164
|
+
## Guard Rails
|
|
165
|
+
|
|
166
|
+
- **Don't skip failures.** Every visual anomaly and log error gets investigated.
|
|
167
|
+
- **Don't change tests to match broken UI.** Fix the UI.
|
|
168
|
+
- **Clean up temp files.** Remove screenshot scripts and temp screenshots when done.
|
|
169
|
+
- **Respect server state.** Don't kill servers that were already running before verification.
|
|
170
|
+
|
|
171
|
+
## Example
|
|
172
|
+
|
|
173
|
+
```
|
|
174
|
+
> /tlc:e2e-verify
|
|
175
|
+
|
|
176
|
+
Checking servers...
|
|
177
|
+
Server (3148): ✅ running
|
|
178
|
+
Dashboard (4000): ✅ running
|
|
179
|
+
|
|
180
|
+
Running e2e tests...
|
|
181
|
+
12/12 passing ✅
|
|
182
|
+
|
|
183
|
+
Taking screenshots...
|
|
184
|
+
📸 /dashboard — captured
|
|
185
|
+
📸 /login — captured
|
|
186
|
+
📸 /settings — captured
|
|
187
|
+
📸 /phases — captured
|
|
188
|
+
|
|
189
|
+
Reviewing screenshots...
|
|
190
|
+
/dashboard: ✅ Layout correct, data loading, no errors
|
|
191
|
+
/login: ✅ Form renders, labels correct
|
|
192
|
+
/settings: ⚠️ Theme toggle shows "undefined" label
|
|
193
|
+
/phases: ✅ Phase list renders correctly
|
|
194
|
+
|
|
195
|
+
Checking logs...
|
|
196
|
+
Server: ✅ No errors
|
|
197
|
+
Console: ⚠️ "Cannot read property 'label' of undefined" on /settings
|
|
198
|
+
|
|
199
|
+
Found 1 issue: Theme toggle label is undefined.
|
|
200
|
+
Reading settings component...
|
|
201
|
+
|
|
202
|
+
Fixed: Added fallback label for theme toggle.
|
|
203
|
+
Re-verifying /settings... ✅ Label now shows "Dark Mode"
|
|
204
|
+
|
|
205
|
+
✅ E2E Verification Complete — all clear.
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
## When to Use
|
|
209
|
+
|
|
210
|
+
- After `/tlc:build` completes a phase
|
|
211
|
+
- After `/tlc:watchci` reports green
|
|
212
|
+
- Before marking a phase as verified (`/tlc:verify`)
|
|
213
|
+
- Any time you want visual proof that the app works
|
|
214
|
+
- Combine with `/tlc:watchci`: build → push → watchci → e2e-verify
|