sinapse-ai 1.14.0 → 1.16.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.
@@ -0,0 +1,374 @@
1
+ # Spec Pipeline: Clarify Specification
2
+
3
+ > **Phase:** 4b - Clarify
4
+ > **Owner Agent:** @project-lead
5
+ > **Pipeline:** spec-pipeline
6
+
7
+ ---
8
+
9
+ ## Purpose
10
+
11
+ Desambiguar a especificação ANTES do QA gate e do plano. Roda DEPOIS de `write` (spec escrita)
12
+ e ANTES de `critique`. Varre o `spec.md` por uma taxonomia de 9 categorias de cobertura, faz no
13
+ máximo 5 perguntas guiadas por (Impacto × Incerteza) — uma de cada vez — e integra cada resposta
14
+ atomicamente no `spec.md`. Sub-especificação descoberta tarde é o retrabalho mais caro do pipeline;
15
+ o clarify ataca isso cedo, perguntando apenas o que muda decisão downstream.
16
+
17
+ ---
18
+
19
+ ## autoClaude
20
+
21
+ ```yaml
22
+ autoClaude:
23
+ version: '3.0'
24
+ pipelinePhase: spec-clarify
25
+
26
+ elicit: true # Interactive - asks the user clarifying questions
27
+ deterministic: false # Output depends on user answers
28
+ composable: true
29
+
30
+ selfCritique:
31
+ required: false
32
+
33
+ inputs:
34
+ - name: storyId
35
+ type: string
36
+ required: true
37
+
38
+ - name: spec
39
+ type: file
40
+ path: docs/stories/{storyId}/spec/spec.md
41
+ required: true
42
+
43
+ - name: requirements
44
+ type: file
45
+ path: docs/stories/{storyId}/spec/requirements.json
46
+ required: false
47
+
48
+ outputs:
49
+ - name: spec.md
50
+ type: file
51
+ path: docs/stories/{storyId}/spec/spec.md
52
+ mutation: append # Adds/updates the `## Clarifications` section + target sections
53
+
54
+ verification:
55
+ type: gate
56
+ blocking: false # Skippable with explicit rework-risk warning
57
+ completion_field: clarificationComplete
58
+
59
+ contextRequirements:
60
+ projectContext: true
61
+ filesContext: true
62
+ implementationPlan: false
63
+ spec: true
64
+ ```
65
+
66
+ ---
67
+
68
+ ## Coverage Taxonomy (9 categories)
69
+
70
+ Varra o `spec.md` e marque cada categoria como **Clear / Partial / Missing**. Perguntas só nascem
71
+ de categorias `Partial` ou `Missing` cujo esclarecimento muda uma decisão downstream.
72
+
73
+ ```yaml
74
+ taxonomy:
75
+ - id: tax-1
76
+ name: 'Functional Scope & Behavior'
77
+ looks_for: 'Core actions, in/out of scope, behavioral edges'
78
+
79
+ - id: tax-2
80
+ name: 'Domain & Data Model'
81
+ looks_for: 'Entities, attributes, relationships, identity, lifecycle/state'
82
+
83
+ - id: tax-3
84
+ name: 'Interaction & UX Flow'
85
+ looks_for: 'Steps, states, error/empty states, accessibility intent'
86
+
87
+ - id: tax-4
88
+ name: 'Non-Functional Quality Attributes'
89
+ looks_for: 'Performance, scale, latency, availability, security targets (quantified)'
90
+
91
+ - id: tax-5
92
+ name: 'Integration & External Dependencies'
93
+ looks_for: 'External services, APIs, contracts, failure modes of integrations'
94
+
95
+ - id: tax-6
96
+ name: 'Edge Cases & Failure Handling'
97
+ looks_for: 'Boundary conditions, invalid input, partial failure, recovery'
98
+
99
+ - id: tax-7
100
+ name: 'Constraints & Tradeoffs'
101
+ looks_for: 'Hard constraints, rejected alternatives, explicit tradeoffs'
102
+
103
+ - id: tax-8
104
+ name: 'Terminology & Consistency'
105
+ looks_for: 'Consistent naming, no synonym drift, defined glossary terms'
106
+
107
+ - id: tax-9
108
+ name: 'Completion Signals'
109
+ looks_for: 'Measurable done criteria, acceptance signals, Success Criteria present'
110
+
111
+ - id: tax-misc
112
+ name: 'Misc / Signals'
113
+ looks_for: 'TODO / ??? placeholders, unquantified adjectives (fast/scalable/secure), [NEEDS CLARIFICATION] markers'
114
+ ```
115
+
116
+ ---
117
+
118
+ ## Question Selection (Impact × Uncertainty)
119
+
120
+ ```yaml
121
+ selection:
122
+ heuristic: 'Impact × Uncertainty'
123
+
124
+ rule: |
125
+ Only include questions whose answers materially impact architecture, data modeling,
126
+ task decomposition, test design, UX behavior, operational readiness, or compliance
127
+ validation. Discard cosmetic questions that do not change a downstream decision.
128
+
129
+ prioritize:
130
+ - High impact + high uncertainty (ask first)
131
+ - High impact + medium uncertainty
132
+ discard:
133
+ - Low impact (any uncertainty)
134
+ - Already Clear in the taxonomy scan
135
+ ```
136
+
137
+ ---
138
+
139
+ ## Question Format
140
+
141
+ ```yaml
142
+ question_format:
143
+ max_questions: 5
144
+ one_at_a_time: true # Ask, wait for answer, integrate, then next
145
+
146
+ styles:
147
+ - type: multiple_choice
148
+ options: '2 to 5 mutually exclusive options'
149
+ include_recommendation: true # Mark the recommended option
150
+ - type: short_answer
151
+ constraint: 'answer in <= 5 words'
152
+ ```
153
+
154
+ ---
155
+
156
+ ## Integration (atomic)
157
+
158
+ Cada resposta é integrada IMEDIATAMENTE antes da próxima pergunta — registro + aplicação na seção-alvo.
159
+
160
+ ```yaml
161
+ integration:
162
+ log_section:
163
+ create_if_missing: '## Clarifications'
164
+ subsection: '### Session {YYYY-MM-DD}'
165
+ entry_format: '- Q: {question} -> A: {answer}'
166
+
167
+ apply_change:
168
+ description: 'Apply the answer to the target section of the spec'
169
+ targets:
170
+ - Functional Requirements (FR-*)
171
+ - Key Entities / Data Model
172
+ - Success Criteria (SC-*)
173
+ - Edge Cases
174
+ - Constraints (CON-*)
175
+ rule: 'Never log an answer without applying it to the target section'
176
+ ```
177
+
178
+ ---
179
+
180
+ ## Stop Criteria
181
+
182
+ ```yaml
183
+ stop_when:
184
+ any_of:
185
+ - 'All critical ambiguities resolved'
186
+ - 'User says proceed / done / skip'
187
+ - 'Reached 5 questions'
188
+ - 'No critical ambiguity detected in the taxonomy scan (zero questions is valid)'
189
+ ```
190
+
191
+ ---
192
+
193
+ ## Gate
194
+
195
+ ```yaml
196
+ gate:
197
+ order: 'Run (and complete) clarify BEFORE the plan phase'
198
+ blocking: false
199
+
200
+ on_skip:
201
+ allowed: true
202
+ required_action: |
203
+ Warn explicitly: downstream rework risk increases when clarification is skipped.
204
+ message: |
205
+ ⚠️ Skipping clarification. Ambiguities in the spec may surface during plan/implement,
206
+ increasing rework cost. Proceeding at user request.
207
+ ```
208
+
209
+ ---
210
+
211
+ ## Execution Flow
212
+
213
+ ### Step 1: Scan Coverage
214
+
215
+ ```yaml
216
+ scan:
217
+ action: scan_spec_against_taxonomy
218
+ for_each: category in taxonomy
219
+ process: |
220
+ 1. Read spec.md
221
+ 2. Mark category Clear / Partial / Missing
222
+ 3. Note specific gap location (section)
223
+ ```
224
+
225
+ ### Step 2: Select Questions
226
+
227
+ ```yaml
228
+ select:
229
+ action: rank_by_impact_uncertainty
230
+ process: |
231
+ 1. Build candidate questions from Partial/Missing categories
232
+ 2. Apply the materially-impacts filter (discard cosmetic)
233
+ 3. Rank by Impact x Uncertainty
234
+ 4. Cap the queue at 5
235
+ ```
236
+
237
+ ### Step 3: Ask & Integrate Loop
238
+
239
+ ```yaml
240
+ ask_loop:
241
+ for_each: question in selected (max 5)
242
+ process: |
243
+ 1. Ask ONE question (multiple-choice 2-5 opts w/ recommendation, OR short answer <=5 words)
244
+ 2. Wait for the answer
245
+ 3. Append `- Q: ... -> A: ...` under `## Clarifications` / `### Session {date}`
246
+ 4. Apply the answer to the target spec section
247
+ 5. Re-check stop criteria; break if met
248
+ ```
249
+
250
+ ### Step 4: Finalize
251
+
252
+ ```yaml
253
+ finalize:
254
+ action: confirm_clarification_complete
255
+ process: |
256
+ 1. Ensure every asked question was both logged AND applied
257
+ 2. Set clarificationComplete = true
258
+ 3. Hand off to critique
259
+ ```
260
+
261
+ ---
262
+
263
+ ## Integration
264
+
265
+ ### Command Integration (@project-lead)
266
+
267
+ ```yaml
268
+ command:
269
+ name: '*clarify-spec'
270
+ syntax: '*clarify-spec {story-id}'
271
+ agent: pm
272
+
273
+ examples:
274
+ - '*clarify-spec STORY-42'
275
+ ```
276
+
277
+ ### Pipeline Integration
278
+
279
+ ```yaml
280
+ pipeline:
281
+ phase: clarify
282
+ previous_phase: spec
283
+ next_phase: critique
284
+
285
+ requires:
286
+ - spec.md
287
+
288
+ optional:
289
+ - requirements.json
290
+
291
+ gate: true # Order gate: complete before plan
292
+ blocking: false # Skippable with rework-risk warning
293
+
294
+ pass_to_next:
295
+ - spec.md
296
+ ```
297
+
298
+ ---
299
+
300
+ ## Error Handling
301
+
302
+ ```yaml
303
+ errors:
304
+ - id: missing-spec
305
+ condition: 'spec.md not found'
306
+ action: 'Halt - cannot clarify without a spec'
307
+ blocking: true
308
+
309
+ - id: no-ambiguity
310
+ condition: 'Taxonomy scan finds zero critical ambiguities'
311
+ action: 'Skip questions, set clarificationComplete=true, proceed to critique'
312
+ blocking: false
313
+
314
+ - id: user-defers
315
+ condition: 'User declines to answer / says proceed'
316
+ action: 'Warn of rework risk, set clarificationComplete=false, proceed'
317
+ blocking: false
318
+ ```
319
+
320
+ ---
321
+
322
+ ## Examples
323
+
324
+ ### Example: Clarify a vague NFR
325
+
326
+ **Input:** spec.md says "the endpoint should be fast" (tax-4 = Partial, unquantified adjective)
327
+
328
+ **Interaction:**
329
+
330
+ ```
331
+ Q: What is the acceptable p95 latency for the endpoint?
332
+ A) < 100ms B) < 300ms (recommended) C) < 1s D) No target needed
333
+ A: B
334
+ ```
335
+
336
+ **Spec mutation:**
337
+
338
+ ```markdown
339
+ ## Clarifications
340
+
341
+ ### Session 2026-06-24
342
+
343
+ - Q: What is the acceptable p95 latency for the endpoint? → A: < 300ms (p95)
344
+
345
+ <!-- and NFR section updated: -->
346
+ | Category | Requirement | Target |
347
+ | ----------- | ------------------------ | ------------- |
348
+ | Performance | Endpoint response (p95) | < 300ms |
349
+ ```
350
+
351
+ ---
352
+
353
+ ## Metadata
354
+
355
+ ```yaml
356
+ metadata:
357
+ story: '3.4b'
358
+ epic: 'Epic 3 - Spec Pipeline'
359
+ created: '2026-06-24'
360
+ author: '@project-lead (Axis)'
361
+ version: '1.0.0'
362
+ source: 'GitHub Spec Kit — templates/commands/clarify.md'
363
+ tags:
364
+ - spec-pipeline
365
+ - clarify
366
+ - ambiguity
367
+ - elicitation
368
+ - product-lead
369
+ ```
370
+
371
+ ## Handoff
372
+ next_agent: @quality-gate
373
+ next_command: *critique-spec {story-id}
374
+ condition: Clarification complete (no critical ambiguities open) OR user proceeds with rework-risk warning
@@ -21,6 +21,10 @@ When the user's prompt matches ANY of these patterns, Chrome Brain is active:
21
21
  4. Track screenshot count — max 15 per session
22
22
  5. Handoff results to domain squad when applicable
23
23
 
24
+ ## Janela fixa & login (uma vez)
25
+
26
+ A automação roda numa **janela de Chrome dedicada e fixa** (perfil `~/.chrome-debug-profile`), separada do Chrome pessoal do usuário. Ela é lançada **só quando uma tarefa de browser precisa** e **nunca é morta enquanto saudável** (o `chrome-ensure` só relança se a porta estiver realmente fora do ar). Na primeira vez que uma tarefa acessar um site que exige login, o usuário loga **uma vez** nessa janela — o perfil persiste, então não precisa logar de novo. Para logar proativamente em todas as contas de uma vez: `sinapse chrome-brain login`.
27
+
24
28
  ## Auto-Learning — MANDATORY
25
29
 
26
30
  After completing ANY browser automation task, evaluate:
@@ -0,0 +1,78 @@
1
+ #!/usr/bin/env node
2
+ 'use strict';
3
+
4
+ /*
5
+ * Chrome Brain — chrome-brain-log (Node, cross-platform).
6
+ *
7
+ * Called by the PostToolUse hook after every browser MCP tool. Appends a usage
8
+ * line and warns when the per-session screenshot count gets risky (the API has
9
+ * a ~20MB response cap). Node version of the old bash logger so it runs hidden
10
+ * on Windows (no console window) and needs no date/awk/grep.
11
+ *
12
+ * FAIL-SOFT: never throws, always exits 0.
13
+ */
14
+
15
+ const fs = require('fs');
16
+ const os = require('os');
17
+ const path = require('path');
18
+
19
+ function toolName() {
20
+ // Claude Code passes a JSON payload on stdin; fall back to env then 'unknown'.
21
+ try {
22
+ const raw = fs.readFileSync(0, 'utf8');
23
+ if (raw) {
24
+ const j = JSON.parse(raw);
25
+ return j.tool_name || j.toolName || process.env.HOOK_TOOL_NAME || 'unknown';
26
+ }
27
+ } catch {
28
+ /* no stdin / not JSON */
29
+ }
30
+ return process.env.HOOK_TOOL_NAME || 'unknown';
31
+ }
32
+
33
+ try {
34
+ const dir = path.join(os.homedir(), '.chrome-brain');
35
+ fs.mkdirSync(dir, { recursive: true });
36
+
37
+ const now = new Date();
38
+ const today = now.toISOString().slice(0, 10).replace(/-/g, ''); // YYYYMMDD
39
+ const time = now.toTimeString().slice(0, 8); // HH:MM:SS
40
+ const tool = toolName();
41
+
42
+ fs.appendFileSync(path.join(dir, `session-${today}.log`), `${time} ${tool}\n`);
43
+
44
+ if (/take_screenshot|take_snapshot/.test(tool)) {
45
+ const countFile = path.join(dir, '.screenshot-count');
46
+ const dateFile = path.join(dir, '.screenshot-date');
47
+
48
+ let lastDate = '';
49
+ try {
50
+ lastDate = fs.readFileSync(dateFile, 'utf8').trim();
51
+ } catch {
52
+ /* first run */
53
+ }
54
+ if (lastDate !== today) {
55
+ fs.writeFileSync(dateFile, today);
56
+ fs.writeFileSync(countFile, '0');
57
+ }
58
+
59
+ let count = 0;
60
+ try {
61
+ count = parseInt(fs.readFileSync(countFile, 'utf8'), 10) || 0;
62
+ } catch {
63
+ /* default 0 */
64
+ }
65
+ count += 1;
66
+ fs.writeFileSync(countFile, String(count));
67
+
68
+ if (count === 12) {
69
+ process.stderr.write('WARNING: 12 screenshots this session. Consider saving state and rotating.\n');
70
+ } else if (count >= 15) {
71
+ process.stderr.write('CRITICAL: 15+ screenshots. Session at risk of the API size cap. Save state NOW.\n');
72
+ }
73
+ }
74
+ } catch {
75
+ /* fail-soft */
76
+ }
77
+
78
+ process.exit(0);
@@ -0,0 +1,108 @@
1
+ #!/usr/bin/env node
2
+ 'use strict';
3
+
4
+ /*
5
+ * Chrome Brain — chrome-ensure (Node, cross-platform).
6
+ *
7
+ * Called by the PreToolUse hook before any browser MCP tool. Guarantees the
8
+ * SINGLE fixed-profile debug Chrome is up on the CDP port — and crucially:
9
+ * - NEVER kills a healthy instance (the old bash script force-killed on a
10
+ * flaky check, which dropped the live DevTools connection).
11
+ * - Launches detached + windowsHide so NO console (CMD/PowerShell) window
12
+ * ever pops (the old `#!/bin/bash` script spawned a console on Windows).
13
+ * - Uses one fixed profile so the user logs in ONCE and stays logged in.
14
+ *
15
+ * Reads config from ~/.sinapse/chrome-brain.json (written at install time):
16
+ * { "chromePath": "...", "port": 9222, "profile": "~/.chrome-debug-profile" }
17
+ *
18
+ * FAIL-SOFT: any error -> exit 0. A browser helper is never worth blocking a
19
+ * tool call (the MCP itself will surface a clear error if Chrome is truly down).
20
+ *
21
+ * Pass `--visible` (or run via `chrome-brain login`) to force a launch even when
22
+ * an instance is already up — used to open the window for first-time login.
23
+ */
24
+
25
+ const fs = require('fs');
26
+ const os = require('os');
27
+ const path = require('path');
28
+ const http = require('http');
29
+ const { spawn } = require('child_process');
30
+
31
+ const CONFIG_PATH = path.join(os.homedir(), '.sinapse', 'chrome-brain.json');
32
+
33
+ function readConfig() {
34
+ try {
35
+ const c = JSON.parse(fs.readFileSync(CONFIG_PATH, 'utf8'));
36
+ if (!c || !c.chromePath) return null;
37
+ return {
38
+ chromePath: c.chromePath,
39
+ port: Number(c.port) || 9222,
40
+ profile: c.profile || path.join(os.homedir(), '.chrome-debug-profile'),
41
+ };
42
+ } catch {
43
+ return null;
44
+ }
45
+ }
46
+
47
+ // True iff a debug Chrome is already answering CDP on the port. Short timeout so
48
+ // the hook never stalls a tool call.
49
+ function isAlive(port) {
50
+ return new Promise((resolve) => {
51
+ const req = http.get(
52
+ { host: '127.0.0.1', port, path: '/json/version', timeout: 1200 },
53
+ (res) => {
54
+ res.resume();
55
+ resolve(res.statusCode === 200);
56
+ }
57
+ );
58
+ req.on('error', () => resolve(false));
59
+ req.on('timeout', () => {
60
+ req.destroy();
61
+ resolve(false);
62
+ });
63
+ });
64
+ }
65
+
66
+ function launch(cfg) {
67
+ const args = [
68
+ `--remote-debugging-port=${cfg.port}`,
69
+ `--user-data-dir=${cfg.profile}`,
70
+ '--no-first-run',
71
+ '--no-default-browser-check',
72
+ ];
73
+ // detached + ignored stdio + unref: Chrome survives this short-lived hook
74
+ // process and keeps the fixed profile alive across the whole session.
75
+ // windowsHide hides any console wrapper (chrome.exe itself is a GUI app, so
76
+ // its own window still shows — that is intentional, the user logs in there).
77
+ const child = spawn(cfg.chromePath, args, {
78
+ detached: true,
79
+ stdio: 'ignore',
80
+ windowsHide: true,
81
+ });
82
+ child.unref();
83
+ }
84
+
85
+ async function main() {
86
+ const force = process.argv.includes('--visible') || process.argv.includes('--force');
87
+ const cfg = readConfig();
88
+ if (!cfg) process.exit(0); // not configured -> do nothing, never block
89
+
90
+ const alive = await isAlive(cfg.port);
91
+ if (alive && !force) process.exit(0); // healthy -> NEVER touch it, just return
92
+
93
+ try {
94
+ launch(cfg);
95
+ } catch {
96
+ process.exit(0);
97
+ }
98
+
99
+ // Poll until ready (~10s max). We never kill anything; if it does not come up
100
+ // we exit quietly and let the MCP report the connection error.
101
+ for (let i = 0; i < 20; i++) {
102
+ await new Promise((r) => setTimeout(r, 500));
103
+ if (await isAlive(cfg.port)) process.exit(0);
104
+ }
105
+ process.exit(0);
106
+ }
107
+
108
+ main().catch(() => process.exit(0));