ilse-design 0.3.0-beta.7 → 0.3.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/LICENSE +21 -0
- package/README.md +67 -74
- package/dist/agent/executor.d.ts.map +1 -1
- package/dist/agent/executor.js +137 -46
- package/dist/agent/executor.js.map +1 -1
- package/dist/bridge/augment.d.ts +1 -0
- package/dist/bridge/augment.d.ts.map +1 -1
- package/dist/bridge/augment.js +52 -3
- package/dist/bridge/augment.js.map +1 -1
- package/dist/bridge/ws-server.d.ts +6 -0
- package/dist/bridge/ws-server.d.ts.map +1 -1
- package/dist/bridge/ws-server.js +10 -2
- package/dist/bridge/ws-server.js.map +1 -1
- package/dist/cli/default.d.ts.map +1 -1
- package/dist/cli/default.js +66 -40
- package/dist/cli/default.js.map +1 -1
- package/dist/cli/index.js +24 -16
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/listen.d.ts.map +1 -1
- package/dist/cli/listen.js +9 -8
- package/dist/cli/listen.js.map +1 -1
- package/dist/cli/login.d.ts.map +1 -1
- package/dist/cli/login.js +41 -26
- package/dist/cli/login.js.map +1 -1
- package/dist/config/user-config.d.ts +1 -0
- package/dist/config/user-config.d.ts.map +1 -1
- package/dist/config/user-config.js.map +1 -1
- package/dist/i18n/index.d.ts +23 -0
- package/dist/i18n/index.d.ts.map +1 -0
- package/dist/i18n/index.js +53 -0
- package/dist/i18n/index.js.map +1 -0
- package/dist/i18n/messages.d.ts +483 -0
- package/dist/i18n/messages.d.ts.map +1 -0
- package/dist/i18n/messages.js +490 -0
- package/dist/i18n/messages.js.map +1 -0
- package/dist/mcp/server.js +4 -1
- package/dist/mcp/server.js.map +1 -1
- package/dist/react/analyze.d.ts +46 -0
- package/dist/react/analyze.d.ts.map +1 -0
- package/dist/react/analyze.js +421 -0
- package/dist/react/analyze.js.map +1 -0
- package/dist/react/image-input.d.ts +13 -5
- package/dist/react/image-input.d.ts.map +1 -1
- package/dist/react/image-input.js +47 -39
- package/dist/react/image-input.js.map +1 -1
- package/dist/react/toolbar.d.ts.map +1 -1
- package/dist/react/toolbar.js +899 -71
- package/dist/react/toolbar.js.map +1 -1
- package/dist/setup/token-detect.d.ts +17 -0
- package/dist/setup/token-detect.d.ts.map +1 -0
- package/dist/setup/token-detect.js +169 -0
- package/dist/setup/token-detect.js.map +1 -0
- package/dist/types.d.ts +2 -1
- package/dist/types.d.ts.map +1 -1
- package/package.json +1 -1
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Iverson Dantas
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
# Ilse
|
|
2
2
|
|
|
3
|
-
**
|
|
3
|
+
**The designer's eye inside the code agent.**
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
Point at what's wrong in the UI. Your agent fixes it.
|
|
6
6
|
|
|
7
7
|
```bash
|
|
8
|
-
npm install
|
|
8
|
+
npm install ilse-design
|
|
9
9
|
```
|
|
10
10
|
|
|
11
11
|
```tsx
|
|
12
12
|
// app/layout.tsx
|
|
13
|
-
import { Ilse } from "
|
|
13
|
+
import { Ilse } from "ilse-design/react";
|
|
14
14
|
|
|
15
15
|
export default function Layout({ children }) {
|
|
16
16
|
return (
|
|
@@ -24,24 +24,24 @@ export default function Layout({ children }) {
|
|
|
24
24
|
}
|
|
25
25
|
```
|
|
26
26
|
|
|
27
|
-
|
|
27
|
+
In dev, a floating toolbar appears. In production, it disappears automatically.
|
|
28
28
|
|
|
29
29
|
---
|
|
30
30
|
|
|
31
|
-
## Setup
|
|
31
|
+
## Setup (3 steps)
|
|
32
32
|
|
|
33
|
-
### 1.
|
|
33
|
+
### 1. Install
|
|
34
34
|
|
|
35
35
|
```bash
|
|
36
|
-
npm install
|
|
36
|
+
npm install ilse-design
|
|
37
37
|
```
|
|
38
38
|
|
|
39
|
-
### 2.
|
|
39
|
+
### 2. Add the component to your layout
|
|
40
40
|
|
|
41
41
|
**Next.js (App Router):**
|
|
42
42
|
```tsx
|
|
43
43
|
// app/layout.tsx
|
|
44
|
-
import { Ilse } from "
|
|
44
|
+
import { Ilse } from "ilse-design/react";
|
|
45
45
|
|
|
46
46
|
export default function RootLayout({ children }) {
|
|
47
47
|
return (
|
|
@@ -57,8 +57,8 @@ export default function RootLayout({ children }) {
|
|
|
57
57
|
|
|
58
58
|
**Vite / CRA / Remix / Astro:**
|
|
59
59
|
```tsx
|
|
60
|
-
// App.tsx
|
|
61
|
-
import { Ilse } from "
|
|
60
|
+
// App.tsx or equivalent
|
|
61
|
+
import { Ilse } from "ilse-design/react";
|
|
62
62
|
|
|
63
63
|
function App() {
|
|
64
64
|
return (
|
|
@@ -70,115 +70,108 @@ function App() {
|
|
|
70
70
|
}
|
|
71
71
|
```
|
|
72
72
|
|
|
73
|
-
### 3.
|
|
73
|
+
### 3. Start the CLI
|
|
74
74
|
|
|
75
|
-
Para o Claude Code corrigir automaticamente:
|
|
76
75
|
```bash
|
|
77
|
-
npx
|
|
76
|
+
npx ilse
|
|
78
77
|
```
|
|
79
78
|
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
Para outros agentes (Cursor, VS Code, Codex, ChatGPT): funciona via clipboard automaticamente. Sem setup.
|
|
79
|
+
First run: choose automatic mode (recommended) or clipboard. The CLI detects your agent (Claude, Codex, Cursor, Gemini) and connects automatically.
|
|
83
80
|
|
|
84
81
|
---
|
|
85
82
|
|
|
86
|
-
##
|
|
83
|
+
## How it works
|
|
87
84
|
|
|
88
|
-
1.
|
|
89
|
-
2.
|
|
90
|
-
3.
|
|
91
|
-
4.
|
|
92
|
-
5.
|
|
93
|
-
6.
|
|
85
|
+
1. Run your project (`npm run dev`)
|
|
86
|
+
2. Open in browser — you'll see a small toolbar at the bottom
|
|
87
|
+
3. Click the toolbar → selection mode activates
|
|
88
|
+
4. Click any element, select text, or draw an area
|
|
89
|
+
5. Describe what needs to change
|
|
90
|
+
6. Attach reference images (paste with Ctrl+V or click +)
|
|
91
|
+
7. Send
|
|
94
92
|
|
|
95
|
-
**
|
|
96
|
-
**Se não está:** copia automático pro clipboard. Cola no chat do agente (Cmd+V).
|
|
93
|
+
**Automatic mode:** the annotation goes straight to your agent, which reads the code, fixes it, and resolves.
|
|
97
94
|
|
|
98
|
-
|
|
99
|
-
```
|
|
100
|
-
/ilse
|
|
101
|
-
```
|
|
102
|
-
Uma palavra. O agente lê todas as anotações pendentes, corrige cada uma, e marca como resolvido.
|
|
95
|
+
**Clipboard mode:** copies to clipboard. Paste in your agent's chat (Cmd+V).
|
|
103
96
|
|
|
104
97
|
---
|
|
105
98
|
|
|
106
|
-
##
|
|
99
|
+
## What Ilse captures
|
|
107
100
|
|
|
108
|
-
|
|
101
|
+
When you annotate an element, the agent receives:
|
|
109
102
|
|
|
110
|
-
- **
|
|
111
|
-
- **
|
|
112
|
-
- **
|
|
113
|
-
- **
|
|
114
|
-
- **
|
|
115
|
-
- **
|
|
116
|
-
- **Parent context**
|
|
117
|
-
- **
|
|
118
|
-
- **
|
|
103
|
+
- **Contextual label** — `button: "Submit"`, `heading: "Product Designer..."`
|
|
104
|
+
- **CSS selector** — `button.cta-primary`
|
|
105
|
+
- **React component name** — via React fiber (dev mode)
|
|
106
|
+
- **Component stack** — parent hierarchy
|
|
107
|
+
- **Grep pattern** — to find it in code
|
|
108
|
+
- **Relevant styles** — filtered by intent (if you said "wrong color", only sends colors)
|
|
109
|
+
- **Parent context** — flex, gap, layout
|
|
110
|
+
- **Reference images** — paste from Figma, screenshot, or upload
|
|
111
|
+
- **Viewport, URL, DPR** — page context
|
|
119
112
|
|
|
120
|
-
|
|
113
|
+
The agent doesn't guess — it has everything it needs to act.
|
|
121
114
|
|
|
122
115
|
---
|
|
123
116
|
|
|
124
117
|
## Features
|
|
125
118
|
|
|
126
|
-
- **3
|
|
127
|
-
- **
|
|
128
|
-
- **
|
|
129
|
-
- **
|
|
130
|
-
- **
|
|
131
|
-
- **
|
|
132
|
-
- **
|
|
119
|
+
- **3 capture modes** — click element, select text, draw area
|
|
120
|
+
- **Reference images** — paste screenshots or upload. Inline badges with hover preview
|
|
121
|
+
- **Suggestions** — static analysis (contrast, a11y, touch targets, DS tokens) + AI analysis on demand
|
|
122
|
+
- **Design intelligence** — auto-detects design tokens from tailwind.config, tokens.json, CSS variables
|
|
123
|
+
- **Chat mode** — free-text instructions without selecting an element
|
|
124
|
+
- **Page scan** — full-page design audit with categorized issues
|
|
125
|
+
- **Resize & snap** — drag handles with snap-to-grid (8px default, configurable)
|
|
126
|
+
- **Animation freeze** — pause animations to annotate tooltips, toasts, dropdowns
|
|
127
|
+
- **Batch send** — annotate multiple elements, send all at once
|
|
128
|
+
- **Smart augmentation** — filters styles by intent (layout, color, spacing, typography)
|
|
129
|
+
- **Session resume** — agent keeps context between annotations
|
|
130
|
+
- **Stream progress** — see each fix resolve in real-time
|
|
131
|
+
- **i18n** — auto-detects system language (English / Portuguese), switchable in settings
|
|
133
132
|
|
|
134
133
|
---
|
|
135
134
|
|
|
136
135
|
## CLI
|
|
137
136
|
|
|
138
|
-
A Ilse também tem CLI pra análise estática:
|
|
139
|
-
|
|
140
137
|
```bash
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
138
|
+
ilse # start (first-run setup + listen mode)
|
|
139
|
+
ilse listen # manual mode (no auto-execute)
|
|
140
|
+
ilse annotations # list annotations
|
|
141
|
+
ilse resolve <id> # resolve an annotation
|
|
142
|
+
ilse setup # register MCP server in Claude Code
|
|
143
|
+
ilse --reset # reset setup
|
|
144
144
|
```
|
|
145
145
|
|
|
146
146
|
---
|
|
147
147
|
|
|
148
|
-
##
|
|
149
|
-
|
|
150
|
-
IA liberou designers do gargalo de execução, mas craft ainda exige esforço humano.
|
|
151
|
-
|
|
152
|
-
A Ilse existe para potencializar o uso de IA no craft. Não é craft vs. IA — pelo contrário. O designer aponta o que o olho vê. O agente faz o que a mão faria.
|
|
153
|
-
|
|
154
|
-
> "Design é uma ferramenta para melhorar a humanidade." — Ilse Crawford
|
|
155
|
-
|
|
156
|
-
---
|
|
157
|
-
|
|
158
|
-
## Compatibilidade
|
|
148
|
+
## Agent compatibility
|
|
159
149
|
|
|
160
150
|
| Framework | Status |
|
|
161
151
|
|---|---|
|
|
162
|
-
| Next.js 13+ | ✓ |
|
|
152
|
+
| Next.js 13+ (App & Pages Router) | ✓ |
|
|
163
153
|
| Vite + React | ✓ |
|
|
164
154
|
| Create React App | ✓ |
|
|
165
155
|
| Remix | ✓ |
|
|
166
156
|
| Astro + React | ✓ |
|
|
167
157
|
|
|
168
|
-
|
|
|
158
|
+
| Agent | Integration |
|
|
169
159
|
|---|---|
|
|
170
|
-
| Claude Code | MCP
|
|
160
|
+
| Claude Code | MCP native + auto-execute |
|
|
171
161
|
| Cursor | MCP |
|
|
172
162
|
| VS Code (Copilot/Continue) | MCP |
|
|
173
|
-
| Codex,
|
|
163
|
+
| Codex, Gemini | Auto-execute via CLI |
|
|
164
|
+
| Any other | Clipboard fallback |
|
|
174
165
|
|
|
175
166
|
---
|
|
176
167
|
|
|
177
|
-
##
|
|
168
|
+
## Philosophy
|
|
169
|
+
|
|
170
|
+
AI freed designers from the execution bottleneck, but craft still demands human judgment.
|
|
178
171
|
|
|
179
|
-
|
|
172
|
+
Ilse is the designer's eye inside the agent: you point at what's wrong, the agent fixes it, you approve. Magic — but in control.
|
|
180
173
|
|
|
181
|
-
|
|
174
|
+
> "Design is a tool for improving humanity." — Ilse Crawford
|
|
182
175
|
|
|
183
176
|
---
|
|
184
177
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"executor.d.ts","sourceRoot":"","sources":["../../src/agent/executor.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAM9C,wBAAgB,sBAAsB,IAAI,IAAI,CAK7C;AAED,MAAM,MAAM,SAAS,GAAG,QAAQ,GAAG,OAAO,GAAG,cAAc,GAAG,QAAQ,GAAG,MAAM,CAAC;AAEhF,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,SAAS,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAqBD,wBAAgB,WAAW,IAAI,cAAc,CAM5C;
|
|
1
|
+
{"version":3,"file":"executor.d.ts","sourceRoot":"","sources":["../../src/agent/executor.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAM9C,wBAAgB,sBAAsB,IAAI,IAAI,CAK7C;AAED,MAAM,MAAM,SAAS,GAAG,QAAQ,GAAG,OAAO,GAAG,cAAc,GAAG,QAAQ,GAAG,MAAM,CAAC;AAEhF,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,SAAS,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAqBD,wBAAgB,WAAW,IAAI,cAAc,CAM5C;AAwHD,wBAAgB,gBAAgB,CAAC,WAAW,EAAE,UAAU,EAAE,EAAE,IAAI,CAAC,EAAE;IAAE,QAAQ,CAAC,EAAE,OAAO,CAAA;CAAE,GAAG,MAAM,CAwGjG;AAID,MAAM,WAAW,eAAe;IAC9B,EAAE,EAAE,OAAO,CAAC;IACZ,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,wBAAsB,iBAAiB,CACrC,UAAU,EAAE,UAAU,EACtB,KAAK,EAAE,cAAc,EACrB,OAAO,GAAE;IAAE,GAAG,CAAC,EAAE,MAAM,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,CAAA;CAAO,GACjD,OAAO,CAAC,eAAe,CAAC,CA8E1B;AAED,MAAM,WAAW,oBAAoB;IACnC,EAAE,EAAE,OAAO,CAAC;IACZ,SAAS,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC/B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED;;;;;;;;;GASG;AACH,wBAAsB,YAAY,CAChC,WAAW,EAAE,UAAU,EAAE,EACzB,KAAK,EAAE,cAAc,EACrB,OAAO,GAAE;IACP,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,UAAU,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;IACnD,UAAU,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IACpC,SAAS,CAAC,EAAE,MAAM,CAAC;CACf,GACL,OAAO,CAAC,oBAAoB,CAAC,CAgL/B"}
|
package/dist/agent/executor.js
CHANGED
|
@@ -41,44 +41,61 @@ export function detectAgent() {
|
|
|
41
41
|
// ── Prompt formatting ───────────────────────────────────────────────────────
|
|
42
42
|
function buildPrompt(annotation) {
|
|
43
43
|
const augmented = augmentAnnotation(annotation);
|
|
44
|
+
const isChat = annotation.intent === 'chat';
|
|
44
45
|
const isMove = annotation.intent === 'move' && annotation.rearrangeData;
|
|
45
46
|
const isCreate = annotation.intent === 'create';
|
|
46
47
|
const instructions = [];
|
|
47
|
-
|
|
48
|
+
const isAnalyze = annotation.intent === 'analyze';
|
|
49
|
+
if (isAnalyze) {
|
|
50
|
+
instructions.push('Ilse detected issues on this element. Perform a design review.', '', 'Element context:', augmented.context, '', 'INSTRUCTIONS:', '1. Read the component source file (use the grep pattern or component name)', '2. Check REUSE: is there a reusable component in the project (e.g. components/ui/Button) that should be used instead of inline classes? List the path.', '3. Check CONSISTENCY: does this element follow the same pattern as similar ones? (font-weight, padding, colors)', '4. Check DS: if there are design tokens in the project (tailwind.config, tokens.json, theme), does the element use the correct tokens?', '5. List issues in 1-3 short, direct bullet points.', '6. Do NOT make edits. Only analyze and report.');
|
|
51
|
+
}
|
|
52
|
+
else if (annotation.intent === 'resize') {
|
|
53
|
+
const orig = annotation.rearrangeData?.originalRect;
|
|
54
|
+
const curr = annotation.rearrangeData?.currentRect;
|
|
55
|
+
instructions.push('The designer RESIZED this element. You must change the size in the code.', '', ...(orig && curr ? [
|
|
56
|
+
`Original size: ${orig.width}×${orig.height}px`,
|
|
57
|
+
`Desired size: ${curr.width}×${curr.height}px`,
|
|
58
|
+
`Delta: Δw=${curr.width - orig.width}px, Δh=${curr.height - orig.height}px`,
|
|
59
|
+
] : []), '', 'HOW TO RESIZE:', '1. Find the element in the code using the grep pattern or selector', '2. Analyze how the size is defined (width/height, padding, min/max, flex)', '3. Apply the appropriate change for the context:', ' - If it has explicit width/height: adjust the values', ' - If padding/margin defines the size: adjust the padding', ' - If flex/grid: adjust flex-basis, min-width, or content', '4. Respect the existing layout — do not break responsiveness');
|
|
60
|
+
}
|
|
61
|
+
else if (isChat) {
|
|
62
|
+
instructions.push('The designer sent a direct instruction. EXECUTE — do not analyze, do not ask, do not request confirmation.', '', 'Instruction:', '"""', augmented.note, '"""', '', 'RULES:', '- APPLY the requested change. Read the files, edit, save.', '- If it is a question: answer in 1-2 direct sentences.', '- Do NOT analyze. Do NOT ask "confirm?". Do NOT say "this annotation is of type X". Just do it.', '- Be surgical — edit only what is necessary.');
|
|
63
|
+
}
|
|
64
|
+
else if (isMove) {
|
|
48
65
|
const { originalRect: o, currentRect: c } = annotation.rearrangeData;
|
|
49
66
|
const dx = c.x - o.x;
|
|
50
67
|
const dy = c.y - o.y;
|
|
51
|
-
instructions.push('
|
|
68
|
+
instructions.push('The designer DRAGGED this element to a new position. You must move the element in the code.', '', `Movement direction: ${dx > 0 ? 'right' : dx < 0 ? 'left' : 'no horizontal displacement'} (${dx}px), ${dy > 0 ? 'down' : dy < 0 ? 'up' : 'no vertical displacement'} (${dy}px)`, '', 'HOW TO MOVE:', '1. Find the element in the code using the grep pattern or selector', '2. Analyze the current layout (flex, grid, static, absolute)', '3. Apply the appropriate change for the context:', ' - Flexbox/Grid: change order, reorder the element in JSX, or adjust align-self/justify-self', ' - If you need to change ORDER among siblings: reorder elements in JSX/HTML', ' - Position absolute/fixed: adjust top/left/right/bottom', ' - Static: use margin or change position in DOM', '4. Do NOT add position:absolute just to move — respect the existing layout', '5. If delta is small (< 20px), it may be a margin/padding adjustment', '6. If delta is large, it may mean element reordering');
|
|
52
69
|
}
|
|
53
70
|
else if (isCreate) {
|
|
54
|
-
instructions.push('
|
|
71
|
+
instructions.push('The designer marked an EMPTY AREA where you should CREATE new content.', '', 'HOW TO CREATE:', '1. Find the nearest container using the selector or parent', '2. Create the element described in the designer\'s note', '3. Position it inside the existing container, in the most logical spot', '4. Follow the visual and code patterns of neighboring components');
|
|
55
72
|
}
|
|
56
73
|
else {
|
|
57
|
-
instructions.push('1.
|
|
74
|
+
instructions.push('1. Analyze whether the issue is in the component DEFINITION or the specific INSTANCE', '2. If it is a default style issue, fix it in the base component', '3. If it is specific to this instance, fix only the usage', '4. If the same issue may exist in other occurrences, search with the grep pattern and fix all', '5. Be surgical — edit only what is necessary');
|
|
58
75
|
}
|
|
59
76
|
return [
|
|
60
|
-
'
|
|
77
|
+
'You received a visual annotation from the designer via Ilse (visual feedback tool).',
|
|
61
78
|
'',
|
|
62
|
-
'
|
|
79
|
+
'Element context:',
|
|
63
80
|
augmented.context,
|
|
64
81
|
'',
|
|
65
|
-
'
|
|
82
|
+
'INSTRUCTIONS:',
|
|
66
83
|
...instructions,
|
|
67
84
|
'',
|
|
68
|
-
'
|
|
69
|
-
'
|
|
85
|
+
'After applying changes, respond in ONE line (max 15 words) describing what you changed.',
|
|
86
|
+
'Example: "Adjusted align-items on Button in components/Button.tsx"',
|
|
70
87
|
].join('\n');
|
|
71
88
|
}
|
|
72
89
|
export function buildBatchPrompt(annotations, opts) {
|
|
73
90
|
const sections = annotations.map((ann, i) => {
|
|
74
91
|
const augmented = augmentAnnotation(ann);
|
|
75
|
-
return `###
|
|
92
|
+
return `### Annotation #${i + 1} (id: ${ann.id})\n${augmented.context}`;
|
|
76
93
|
});
|
|
77
94
|
// Resumed session: agent already has instructions, just send the new annotation(s)
|
|
78
95
|
if (opts?.isResume) {
|
|
79
96
|
const count = annotations.length;
|
|
80
97
|
return [
|
|
81
|
-
`
|
|
98
|
+
`New ${count === 1 ? 'annotation' : `${count} annotations`} from the designer. Same rules as before.`,
|
|
82
99
|
'',
|
|
83
100
|
...sections,
|
|
84
101
|
].join('\n');
|
|
@@ -86,45 +103,86 @@ export function buildBatchPrompt(annotations, opts) {
|
|
|
86
103
|
// First invocation: full instructions
|
|
87
104
|
const hasMove = annotations.some(a => a.intent === 'move' && a.rearrangeData);
|
|
88
105
|
const hasCreate = annotations.some(a => a.intent === 'create');
|
|
106
|
+
const hasChat = annotations.some(a => a.intent === 'chat');
|
|
107
|
+
const allChat = annotations.every(a => a.intent === 'chat');
|
|
108
|
+
const allAnalyze = annotations.every(a => a.intent === 'analyze');
|
|
89
109
|
const count = annotations.length;
|
|
110
|
+
// Pure analyze batch — design review mode
|
|
111
|
+
if (allAnalyze) {
|
|
112
|
+
return [
|
|
113
|
+
`Analyze ${count === 1 ? 'this element' : `these ${count} elements`} from a design perspective.`,
|
|
114
|
+
'',
|
|
115
|
+
'RULES:',
|
|
116
|
+
'- Read the source code of each element (use grep pattern or component name)',
|
|
117
|
+
'- Check REUSE: is there a reusable component (e.g. components/ui/Button) that should be used?',
|
|
118
|
+
'- Check CONSISTENCY: does the element follow the same pattern as similar ones in the project?',
|
|
119
|
+
'- Check DS: if there are tokens (tailwind.config, tokens.json, theme), does the element use the correct ones?',
|
|
120
|
+
'- Do NOT make edits. Only analyze and report in short bullet points.',
|
|
121
|
+
'',
|
|
122
|
+
...sections,
|
|
123
|
+
'',
|
|
124
|
+
'OUTPUT BEHAVIOR:',
|
|
125
|
+
'- For each element, print one line:',
|
|
126
|
+
' #<id>: <analysis in max 20 words>',
|
|
127
|
+
].join('\n');
|
|
128
|
+
}
|
|
129
|
+
// Pure chat batch — simplified preamble
|
|
130
|
+
if (allChat) {
|
|
131
|
+
return [
|
|
132
|
+
`Direct instruction from the designer. EXECUTE — do not analyze, do not ask for confirmation.`,
|
|
133
|
+
'',
|
|
134
|
+
'RULES:',
|
|
135
|
+
'- APPLY the requested change. Read the files, edit, save.',
|
|
136
|
+
'- If it is a question: answer in 1-2 direct sentences.',
|
|
137
|
+
'- Do NOT analyze. Do NOT ask "confirm?". Just do it.',
|
|
138
|
+
'- Be surgical — edit only what is necessary.',
|
|
139
|
+
'',
|
|
140
|
+
...sections,
|
|
141
|
+
'',
|
|
142
|
+
'OUTPUT BEHAVIOR:',
|
|
143
|
+
'- Before each action, briefly state (1 short sentence) what you are doing.',
|
|
144
|
+
'- After finishing EACH message individually, IMMEDIATELY print a line in this format:',
|
|
145
|
+
' #<id>: <what you did in max 15 words>',
|
|
146
|
+
].join('\n');
|
|
147
|
+
}
|
|
90
148
|
return [
|
|
91
|
-
`
|
|
149
|
+
`You received ${count} visual ${count === 1 ? 'annotation' : 'annotations'} from the designer via Ilse (visual feedback tool).`,
|
|
92
150
|
...(count > 1 ? [
|
|
93
|
-
'
|
|
151
|
+
'Fix ALL in a single pass. Analyze the set before acting:',
|
|
94
152
|
] : [
|
|
95
|
-
'
|
|
153
|
+
'Fix this annotation:',
|
|
96
154
|
]),
|
|
97
|
-
'-
|
|
98
|
-
'-
|
|
99
|
-
'-
|
|
100
|
-
'-
|
|
155
|
+
'- If two annotations are on the same element, consolidate',
|
|
156
|
+
'- If the same pattern appears in several, fix it in the base component',
|
|
157
|
+
'- If the same issue may exist in other occurrences outside the annotations, search with grep and fix all',
|
|
158
|
+
'- Be surgical — edit only what is necessary',
|
|
101
159
|
...(hasMove ? [
|
|
102
160
|
'',
|
|
103
|
-
'
|
|
104
|
-
'-
|
|
105
|
-
'-
|
|
106
|
-
' flexbox/grid →
|
|
107
|
-
' position absolute →
|
|
108
|
-
' static →
|
|
109
|
-
'-
|
|
110
|
-
'-
|
|
161
|
+
'MOVE ANNOTATIONS (intent: move):',
|
|
162
|
+
'- The designer DRAGGED elements to new positions. The **Move** field shows the delta in pixels.',
|
|
163
|
+
'- To move: analyze the layout (flex/grid/static) and apply the appropriate change:',
|
|
164
|
+
' flexbox/grid → change order, reorder JSX, or adjust align-self',
|
|
165
|
+
' position absolute → adjust top/left',
|
|
166
|
+
' static → adjust margin or reorder in DOM',
|
|
167
|
+
'- Do NOT add position:absolute just to move — respect the existing layout',
|
|
168
|
+
'- Small delta (< 20px) = margin/padding adjustment. Large delta = element reordering.',
|
|
111
169
|
] : []),
|
|
112
170
|
...(hasCreate ? [
|
|
113
171
|
'',
|
|
114
|
-
'
|
|
115
|
-
'-
|
|
116
|
-
'-
|
|
117
|
-
'-
|
|
172
|
+
'CREATE ANNOTATIONS (intent: create):',
|
|
173
|
+
'- The designer marked empty areas where new content is needed.',
|
|
174
|
+
'- Create the element described in the note, inside the nearest container.',
|
|
175
|
+
'- Follow the visual and code patterns of neighboring components.',
|
|
118
176
|
] : []),
|
|
119
177
|
'',
|
|
120
178
|
...sections,
|
|
121
179
|
'',
|
|
122
|
-
'
|
|
123
|
-
'-
|
|
124
|
-
'
|
|
125
|
-
'-
|
|
126
|
-
' #<id>: <
|
|
127
|
-
'-
|
|
180
|
+
'OUTPUT BEHAVIOR:',
|
|
181
|
+
'- Before each action, briefly state (1 short sentence) what you are doing.',
|
|
182
|
+
' E.g.: "Reading the Header to understand the layout", "Searching for the Button component", "Adjusting alignment".',
|
|
183
|
+
'- After finishing EACH annotation individually (not at the end), IMMEDIATELY print a line in this format:',
|
|
184
|
+
' #<id>: <what you did in max 15 words>',
|
|
185
|
+
'- Do not accumulate summaries for the end. Report one by one, in order, as soon as you finish each edit.',
|
|
128
186
|
].join('\n');
|
|
129
187
|
}
|
|
130
188
|
export async function executeAnnotation(annotation, agent, options = {}) {
|
|
@@ -228,7 +286,8 @@ export async function executeBatch(annotations, agent, options = {}) {
|
|
|
228
286
|
let timedOut = false;
|
|
229
287
|
let sessionId;
|
|
230
288
|
const summaries = new Map();
|
|
231
|
-
let resolvedIndex = 0; //
|
|
289
|
+
let resolvedIndex = 0; // fallback: resolve by order when file_path matching fails
|
|
290
|
+
const resolvedIds = new Set(); // track which annotations have been resolved
|
|
232
291
|
const proc = spawn(agent.command, args, {
|
|
233
292
|
cwd,
|
|
234
293
|
env: process.env,
|
|
@@ -263,13 +322,44 @@ export async function executeBatch(annotations, agent, options = {}) {
|
|
|
263
322
|
// Parse stream-json events
|
|
264
323
|
try {
|
|
265
324
|
const event = JSON.parse(trimmed);
|
|
266
|
-
handleStreamEvent(event, annotations, summaries, () => {
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
325
|
+
handleStreamEvent(event, annotations, summaries, (filePath) => {
|
|
326
|
+
// Try to match by file_path first
|
|
327
|
+
let matched = false;
|
|
328
|
+
if (filePath) {
|
|
329
|
+
const basename = filePath.split('/').pop() ?? '';
|
|
330
|
+
for (const ann of annotations) {
|
|
331
|
+
if (resolvedIds.has(ann.id))
|
|
332
|
+
continue;
|
|
333
|
+
// Match if grepPattern contains the filename or component name
|
|
334
|
+
const grep = ann.grepPattern ?? '';
|
|
335
|
+
const comp = ann.component ?? '';
|
|
336
|
+
if ((grep && filePath.includes(grep.split(/[:\s]/)[0])) ||
|
|
337
|
+
(comp && basename.toLowerCase().includes(comp.toLowerCase())) ||
|
|
338
|
+
(basename && grep.toLowerCase().includes(basename.toLowerCase()))) {
|
|
339
|
+
resolvedIds.add(ann.id);
|
|
340
|
+
const summary = `Editando ${basename}`;
|
|
341
|
+
if (!summaries.has(ann.id)) {
|
|
342
|
+
summaries.set(ann.id, summary);
|
|
343
|
+
options.onProgress?.(ann.id, summary);
|
|
344
|
+
}
|
|
345
|
+
matched = true;
|
|
346
|
+
break;
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
// Fallback: resolve by order
|
|
351
|
+
if (!matched) {
|
|
352
|
+
while (resolvedIndex < annotations.length && resolvedIds.has(annotations[resolvedIndex].id)) {
|
|
353
|
+
resolvedIndex++;
|
|
354
|
+
}
|
|
355
|
+
if (resolvedIndex < annotations.length) {
|
|
356
|
+
const ann = annotations[resolvedIndex++];
|
|
357
|
+
resolvedIds.add(ann.id);
|
|
358
|
+
const summary = `Editando ${ann.component ?? ann.element}`;
|
|
359
|
+
if (!summaries.has(ann.id)) {
|
|
360
|
+
summaries.set(ann.id, summary);
|
|
361
|
+
options.onProgress?.(ann.id, summary);
|
|
362
|
+
}
|
|
273
363
|
}
|
|
274
364
|
}
|
|
275
365
|
}, (id) => { sessionId = id; }, (thinking) => options.onThinking?.(thinking));
|
|
@@ -356,7 +446,8 @@ function handleStreamEvent(event, annotations, summaries, onToolUse, onSessionId
|
|
|
356
446
|
if (thinking)
|
|
357
447
|
onThinking(thinking);
|
|
358
448
|
if (toolName && ['Edit', 'Write', 'MultiEdit', 'Update'].includes(toolName)) {
|
|
359
|
-
|
|
449
|
+
const filePath = typeof input?.file_path === 'string' ? input.file_path : undefined;
|
|
450
|
+
onToolUse(filePath);
|
|
360
451
|
}
|
|
361
452
|
}
|
|
362
453
|
// Text blocks: emit as thinking (cleaned up), also parse "#<id>:" summary pattern
|
|
@@ -432,7 +523,7 @@ function parseBatchSummaries(stdout, annotations) {
|
|
|
432
523
|
result.set(match[1], match[2].trim());
|
|
433
524
|
}
|
|
434
525
|
}
|
|
435
|
-
// Fill missing summaries with fallback
|
|
526
|
+
// Fill missing summaries with fallback (skip analyze — those should have real analysis)
|
|
436
527
|
for (const ann of annotations) {
|
|
437
528
|
if (!result.has(ann.id)) {
|
|
438
529
|
result.set(ann.id, 'Corrigido');
|