the-frame-ai 0.9.6 → 0.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "the-frame-ai",
3
- "version": "0.9.6",
3
+ "version": "0.10.1",
4
4
  "description": "FRAME — Framework for AI-Assisted Solo Development",
5
5
  "type": "module",
6
6
  "bin": {
package/src/init.js CHANGED
@@ -10,8 +10,10 @@ import {
10
10
  writeFile,
11
11
  applyVars,
12
12
  mergeVscodeSettings,
13
+ mergeClaudeSettings,
14
+ mergeVscodeMcp,
13
15
  } from './utils.js';
14
- import { LANGUAGES, getLanguageInstruction, promptLanguage, promptConfig, promptCopilot } from './languages.js';
16
+ import { LANGUAGES, getLanguageInstruction, promptLanguage, promptConfig, promptCopilot, promptFrontend } from './languages.js';
15
17
  import { doctor } from './doctor.js';
16
18
 
17
19
  const PLANNING_DIRS = [
@@ -85,7 +87,14 @@ export async function init(target, flags = {}) {
85
87
  const commandCount = readdirSync(commandsSrc).filter((f) => f.endsWith('.md')).length;
86
88
  logSuccess(`${commandCount} commands → .claude/commands/`);
87
89
 
88
- // 2b. Copilot Chat support
90
+ // 2b. Frontend: Playwright MCP
91
+ const frontend = await promptFrontend(flags.yes);
92
+ if (frontend) {
93
+ mergeClaudeSettings(join(target, '.claude', 'settings.json'));
94
+ logSuccess(`Playwright MCP → .claude/settings.json`);
95
+ }
96
+
97
+ // 2c. Copilot Chat support
89
98
  const copilot = await promptCopilot(flags.yes);
90
99
  if (copilot) {
91
100
  const promptsDest = join(target, '.github', 'prompts');
@@ -96,7 +105,9 @@ export async function init(target, flags = {}) {
96
105
  const vscodeDest = join(target, '.vscode');
97
106
  ensureDir(vscodeDest);
98
107
  mergeVscodeSettings(join(vscodeDest, 'settings.json'));
108
+ if (frontend) mergeVscodeMcp(join(vscodeDest, 'mcp.json'));
99
109
  logSuccess(`${commandCount} Copilot prompts → .github/prompts/`);
110
+ if (frontend) logSuccess(`Playwright MCP → .vscode/mcp.json`);
100
111
  }
101
112
 
102
113
  // 3. Copy agents and apply quality.commands substitution
@@ -163,6 +174,7 @@ export async function init(target, flags = {}) {
163
174
  if (fileExists(configPath)) {
164
175
  resolvedConfig.language = language;
165
176
  resolvedConfig.copilot = copilot;
177
+ resolvedConfig.frontend = frontend;
166
178
  writeFile(configPath, JSON.stringify(resolvedConfig, null, 2));
167
179
  }
168
180
 
@@ -184,6 +196,7 @@ export async function init(target, flags = {}) {
184
196
  log(` Planning: files in .planning/`);
185
197
  log(` Config: .frame/config.json`);
186
198
  if (copilot) log(` Copilot: ${commandCount} prompts in .vscode/`);
199
+ if (frontend) log(` Playwright MCP: .claude/settings.json${copilot ? ' + .vscode/mcp.json' : ''}`);
187
200
  log('');
188
201
 
189
202
  // 11. Auto-run doctor
package/src/languages.js CHANGED
@@ -140,3 +140,14 @@ export async function promptCopilot(yes = false) {
140
140
  });
141
141
  });
142
142
  }
143
+
144
+ export async function promptFrontend(yes = false) {
145
+ if (!process.stdin.isTTY || yes) return false;
146
+ const rl = createInterface({ input: process.stdin, output: process.stdout });
147
+ return new Promise((resolve) => {
148
+ rl.question('\n? Is this a frontend project? Adds Playwright MCP for UI verification (y/N): ', (answer) => {
149
+ rl.close();
150
+ resolve(answer.trim().toLowerCase() === 'y');
151
+ });
152
+ });
153
+ }
package/src/update.js CHANGED
@@ -1,7 +1,8 @@
1
1
  import { join } from 'node:path';
2
2
  import { readdirSync, writeFileSync, readFileSync } from 'node:fs';
3
3
  import { TEMPLATES_DIR, VERSION, log, logSuccess } from './manifest.js';
4
- import { copyDir, makeExecutable, fileExists, applyVars, writeFile, ensureDir, mergeVscodeSettings } from './utils.js';
4
+ import { copyDir, makeExecutable, fileExists, applyVars, writeFile, ensureDir, mergeVscodeSettings, mergeClaudeSettings, mergeVscodeMcp } from './utils.js';
5
+ import { promptFrontend } from './languages.js';
5
6
 
6
7
 
7
8
  export async function update(target, flags = {}) {
@@ -99,6 +100,19 @@ export async function update(target, flags = {}) {
99
100
  }
100
101
  }
101
102
 
103
+ // 5. Update Playwright MCP (frontend projects)
104
+ if (config.frontend === undefined || config.frontend === false) {
105
+ if (process.stdin.isTTY && !flags.yes) {
106
+ const frontend = await promptFrontend(false);
107
+ config.frontend = frontend;
108
+ writeFileSync(join(target, '.frame', 'config.json'), JSON.stringify(config, null, 2), 'utf-8');
109
+ }
110
+ }
111
+ if (config.frontend) {
112
+ mergeClaudeSettings(join(target, '.claude', 'settings.json'));
113
+ if (config.copilot) mergeVscodeMcp(join(target, '.vscode', 'mcp.json'));
114
+ }
115
+
102
116
  // 5. Write new version
103
117
  writeFileSync(join(target, '.frame', '.frame-version'), VERSION, 'utf-8');
104
118
 
package/src/utils.js CHANGED
@@ -63,3 +63,28 @@ export function mergeVscodeSettings(settingsPath) {
63
63
  settings['chat.promptFiles'] = true;
64
64
  writeFileSync(settingsPath, JSON.stringify(settings, null, 2), 'utf-8');
65
65
  }
66
+
67
+ const PLAYWRIGHT_MCP = {
68
+ command: 'npx',
69
+ args: ['@playwright/mcp@latest'],
70
+ };
71
+
72
+ export function mergeClaudeSettings(settingsPath) {
73
+ let settings = {};
74
+ if (existsSync(settingsPath)) {
75
+ try { settings = JSON.parse(readFileSync(settingsPath, 'utf-8')); } catch {}
76
+ }
77
+ settings.mcpServers = settings.mcpServers ?? {};
78
+ settings.mcpServers.playwright = PLAYWRIGHT_MCP;
79
+ writeFileSync(settingsPath, JSON.stringify(settings, null, 2), 'utf-8');
80
+ }
81
+
82
+ export function mergeVscodeMcp(mcpPath) {
83
+ let config = {};
84
+ if (existsSync(mcpPath)) {
85
+ try { config = JSON.parse(readFileSync(mcpPath, 'utf-8')); } catch {}
86
+ }
87
+ config.servers = config.servers ?? {};
88
+ config.servers.playwright = PLAYWRIGHT_MCP;
89
+ writeFileSync(mcpPath, JSON.stringify(config, null, 2), 'utf-8');
90
+ }
@@ -140,6 +140,19 @@ If unclosed tasks exist — return and complete them or report to user.
140
140
 
141
141
  **D-step**: All checks must pass.
142
142
 
143
+ ### Step 6.5: UI Verification (if UI tasks present)
144
+
145
+ **Detect UI tasks**: any task changed files with `.tsx`, `.vue`, `.css`, `component`, `page`, `layout`, `style`.
146
+
147
+ If UI tasks exist AND Playwright MCP is available:
148
+ 1. `browser_navigate: {dev server URL}`
149
+ 2. `browser_screenshot`
150
+ 3. Compare with spec from `docs/specs/{feature}/spec.md`
151
+ 4. **PASS** → proceed to Step 7
152
+ 5. **FAIL** → describe problem, fix, re-run quality gates, re-verify
153
+
154
+ If Playwright MCP is not available — skip and note: "UI not verified (no browser tool)".
155
+
143
156
  ### Step 7: Update STATE.md (COMPLETE)
144
157
 
145
158
  ```markdown
@@ -91,6 +91,7 @@ Update STATE.md: `Current Phase: 3/4`
91
91
  - **D-step**: Regression test must PASS
92
92
  - Run all tests: `{quality.commands.test}`
93
93
  - Type check: `{quality.commands.typecheck}`
94
+ - **If UI bug** (visual, layout, component): open browser via Playwright MCP → `browser_navigate` → `browser_screenshot` → confirm the bug is gone visually
94
95
 
95
96
  ### Phase 4: Review and Knowledge Capture
96
97
 
@@ -45,6 +45,19 @@ Execute:
45
45
  4. Run quality gates: `{quality.commands.typecheck} && {quality.commands.test} && {quality.commands.lint}`
46
46
  5. Git commit: `git add {files} && git commit -m "{type}({scope}): {description}"`
47
47
 
48
+ ### Step 3.5: UI Verification (if UI task)
49
+
50
+ **Detect UI task**: task description or changed files contain `.tsx`, `.vue`, `.css`, `component`, `page`, `layout`, `style`, `UI`, or `interface`.
51
+
52
+ If this is a UI task AND Playwright MCP is available (`browser_navigate` tool exists):
53
+ 1. `browser_navigate: {dev server URL from .frame/config.json or ask user}`
54
+ 2. `browser_screenshot`
55
+ 3. Compare screenshot with task description
56
+ 4. **PASS** → continue to Step 4
57
+ 5. **FAIL** → describe the problem, return to Step 3 and fix, then re-verify
58
+
59
+ If Playwright MCP is not available — skip this step and note: "UI not verified (no browser tool)".
60
+
48
61
  ### Step 4: Update STATE.md and wins
49
62
 
50
63
  Update `.planning/STATE.md`:
@@ -0,0 +1,101 @@
1
+ # /frame:verify -- Browser UI Verification
2
+
3
+ Verifies UI result in a real browser via Playwright MCP. Use when the agent claims "done" but the interface looks wrong.
4
+
5
+ ## Instructions
6
+
7
+ Verify the UI for: **$ARGUMENTS** (if empty — verify the last completed task from STATE.md)
8
+
9
+ ### Step 1: Determine what to verify
10
+
11
+ If `$ARGUMENTS` is provided — use it as the verification target.
12
+ Otherwise read `.planning/STATE.md` → find the last completed task/feature.
13
+
14
+ ### Step 2: Determine the URL
15
+
16
+ Check in order:
17
+ 1. `$ARGUMENTS` contains a URL → use it
18
+ 2. `.frame/config.json` → `devServer.url` field
19
+ 3. Ask the user: "What URL should I open to verify? (e.g. http://localhost:3000)"
20
+
21
+ ### Step 3: Open browser and take screenshot
22
+
23
+ ```
24
+ browser_navigate: {url}
25
+ browser_screenshot
26
+ ```
27
+
28
+ Describe what you see: layout, content, interactive elements.
29
+
30
+ ### Step 4: Compare with expected result
31
+
32
+ Compare the screenshot with:
33
+ - The task description from `$ARGUMENTS` or STATE.md
34
+ - The spec from `docs/specs/{feature}/spec.md` (if exists)
35
+
36
+ **Verdict:**
37
+ - **PASS** — the interface matches the expected result → report success
38
+ - **FAIL** — something is wrong → describe exactly what is wrong and what was expected
39
+
40
+ ### Step 5: On FAIL — interact to dig deeper
41
+
42
+ If the initial screenshot shows a problem, try to reproduce it:
43
+ ```
44
+ browser_click: {element} # click buttons, links
45
+ browser_type: {selector} {text} # fill forms
46
+ browser_screenshot # screenshot after interaction
47
+ ```
48
+
49
+ Describe the exact problem: what element, what behavior, what was expected.
50
+
51
+ ### Step 6: Report
52
+
53
+ **On PASS:**
54
+ ```
55
+ ✅ UI verified: {what was checked}
56
+ - URL: {url}
57
+ - Result: matches expected behavior
58
+ ```
59
+
60
+ **On FAIL:**
61
+ ```
62
+ ❌ UI verification failed: {what was checked}
63
+ - URL: {url}
64
+ - Problem: {exact description}
65
+ - Expected: {what should be}
66
+ - Actual: {what is}
67
+ - Suggested fix: {where to look}
68
+ ```
69
+
70
+ On FAIL — do NOT auto-fix. Report to the user and wait for a decision:
71
+ - Fix and re-verify → run `/frame:fast {fix description}`, then `/frame:verify` again
72
+ - It's acceptable → mark as known issue
73
+
74
+ ## Rules
75
+
76
+ - **Never auto-fix** — verify only, report problems
77
+ - **Be specific** — describe exact elements, not "looks wrong"
78
+ - **Screenshot first** — always take a screenshot before interacting
79
+ - **Check mobile too** — if the project has responsive design, mention it
80
+
81
+ ## When to Use
82
+
83
+ - After `/frame:fast`, `/frame:build`, `/frame:wave` on UI tasks
84
+ - When the agent says "done" but visually something is off
85
+ - Before `/frame:ship` for frontend features
86
+ - When debugging visual regressions
87
+
88
+ ## Playwright MCP Setup
89
+
90
+ If `browser_navigate` is not available, Playwright MCP is not configured.
91
+ Add to `.claude/settings.json`:
92
+ ```json
93
+ {
94
+ "mcpServers": {
95
+ "playwright": {
96
+ "command": "npx",
97
+ "args": ["@playwright/mcp@latest"]
98
+ }
99
+ }
100
+ }
101
+ ```
@@ -141,6 +141,13 @@ Repeat Steps 5-6 for each wave until all waves are complete.
141
141
  git log --oneline -10
142
142
  ```
143
143
 
144
+ **UI Verification** (if any wave contained UI tasks — files with `.tsx`, `.vue`, `.css`, `component`, `page`, `layout`):
145
+
146
+ If Playwright MCP is available:
147
+ 1. `browser_navigate: {dev server URL}`
148
+ 2. `browser_screenshot`
149
+ 3. Compare with spec — PASS → continue, FAIL → report to user with exact description, do NOT auto-fix
150
+
144
151
  Check completeness:
145
152
  ```bash
146
153
  TOTAL=$(grep -c "^### Task" plan.md)