spectoflow 0.17.0 → 0.17.5
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/README.md +12 -6
- package/package.json +1 -1
- package/templates/README.md +4 -0
- package/templates/agents/qa-engineer.md +8 -5
- package/templates/dashboard/public/app.js +160 -124
- package/templates/dashboard/public/designs/console.css +15 -1
- package/templates/dashboard/public/designs/console.js +19 -0
- package/templates/dashboard/public/designs/orbit.css +42 -18
- package/templates/dashboard/public/designs/orbit.js +30 -5
- package/templates/dashboard/public/i18n.js +577 -0
- package/templates/dashboard/public/index.html +103 -86
- package/templates/dashboard/public/styles.css +15 -1
- package/templates/dashboard/server.js +1 -0
- package/templates/skills/write-e2e-tests/SKILL.md +72 -17
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
<body>
|
|
14
14
|
<header class="topbar">
|
|
15
15
|
<div class="brand">
|
|
16
|
-
<button class="nav-toggle" id="navToggle" aria-label="Toggle menu" aria-expanded="false"><span></span><span></span><span></span></button>
|
|
16
|
+
<button class="nav-toggle" id="navToggle" data-i18n-aria="topbar.navToggle" aria-label="Toggle menu" aria-expanded="false"><span></span><span></span><span></span></button>
|
|
17
17
|
<a class="brand-logo" href="/board" data-route="board" aria-label="spectoflow home">
|
|
18
18
|
<img class="brand-logo-img is-dark" src="logo-white.png" alt="spectoflow" />
|
|
19
19
|
<img class="brand-logo-img is-light" src="logo-dark.png" alt="spectoflow" />
|
|
@@ -25,27 +25,42 @@
|
|
|
25
25
|
<span class="brand-sep">/</span>
|
|
26
26
|
<span class="brand-project" id="projectName">—</span>
|
|
27
27
|
</div>
|
|
28
|
-
<div class="brand-sub" id="brandSub">
|
|
28
|
+
<div class="brand-sub" id="brandSub">
|
|
29
|
+
<select id="topMode" class="brand-mini-select" data-i18n-title="topbar.mode.title" data-i18n-aria="field.mode" aria-label="Autonomy mode" title="Autonomy mode — change from here or in Settings">
|
|
30
|
+
<option value="autopilot">autopilot</option>
|
|
31
|
+
<option value="semi">semi</option>
|
|
32
|
+
<option value="manual">manual</option>
|
|
33
|
+
</select>
|
|
34
|
+
<span class="brand-sub-sep">·</span>
|
|
35
|
+
<select id="topLang" class="brand-mini-select" data-i18n-title="topbar.lang.title" data-i18n-aria="field.lang" aria-label="Output language" title="Output language — change from here or in Settings">
|
|
36
|
+
<option value="en">en</option>
|
|
37
|
+
<option value="fr">fr</option>
|
|
38
|
+
<option value="es">es</option>
|
|
39
|
+
<option value="de">de</option>
|
|
40
|
+
<option value="pt">pt</option>
|
|
41
|
+
<option value="it">it</option>
|
|
42
|
+
</select>
|
|
43
|
+
</div>
|
|
29
44
|
</div>
|
|
30
45
|
<div class="progress-meter" id="globalMeter" title="Global progress">
|
|
31
46
|
<div class="progress-meter-fill" id="globalMeterFill"></div>
|
|
32
47
|
</div>
|
|
33
48
|
</div>
|
|
34
49
|
<nav class="tabs" id="tabs">
|
|
35
|
-
<button class="tab is-active" data-tab="board"><span class="tab-ico" data-icon="board"></span><span class="tab-label">Board</span></button>
|
|
36
|
-
<button class="tab" data-tab="
|
|
37
|
-
<button class="tab" data-tab="
|
|
38
|
-
<button class="tab" data-tab="
|
|
39
|
-
<button class="tab" data-tab="
|
|
40
|
-
<button class="tab" data-tab="
|
|
41
|
-
<button class="tab" data-tab="
|
|
42
|
-
<button class="tab" data-tab="info"><span class="tab-ico" data-icon="info"></span><span class="tab-label">Info</span></button>
|
|
43
|
-
<button class="tab" data-tab="settings"><span class="tab-ico" data-icon="settings"></span><span class="tab-label">Settings</span></button>
|
|
50
|
+
<button class="tab is-active" data-tab="board"><span class="tab-ico" data-icon="board"></span><span class="tab-label" data-i18n="nav.board">Board</span></button>
|
|
51
|
+
<button class="tab" data-tab="chat"><span class="tab-ico" data-icon="chat"></span><span class="tab-label" data-i18n="nav.chat">Chat</span></button>
|
|
52
|
+
<button class="tab" data-tab="requests"><span class="tab-ico" data-icon="requests"></span><span class="tab-label" data-i18n="nav.requests">Requests</span></button>
|
|
53
|
+
<button class="tab" data-tab="attention"><span class="tab-ico" data-icon="attention"></span><span class="tab-label" data-i18n="nav.attention">Attention</span><span class="tab-badge" id="attnBadge" hidden>0</span></button>
|
|
54
|
+
<button class="tab" data-tab="backlog"><span class="tab-ico" data-icon="backlog"></span><span class="tab-label" data-i18n="nav.backlog">Backlog</span></button>
|
|
55
|
+
<button class="tab" data-tab="workflow"><span class="tab-ico" data-icon="workflow"></span><span class="tab-label" data-i18n="nav.workflow">Workflow</span></button>
|
|
56
|
+
<button class="tab" data-tab="team"><span class="tab-ico" data-icon="agents"></span><span class="tab-label" data-i18n="nav.team">Agents & Skills</span></button>
|
|
57
|
+
<button class="tab" data-tab="info"><span class="tab-ico" data-icon="info"></span><span class="tab-label" data-i18n="nav.info">Info</span></button>
|
|
58
|
+
<button class="tab" data-tab="settings"><span class="tab-ico" data-icon="settings"></span><span class="tab-label" data-i18n="nav.settings">Settings</span></button>
|
|
44
59
|
</nav>
|
|
45
60
|
<div class="top-right">
|
|
46
61
|
<span class="sync" id="sync"><span class="sync-dot"></span><span id="syncLabel">live</span></span>
|
|
47
|
-
<button class="btn primary run-btn" id="runQuickBtn" title="Open the run chat"><span class="tab-ico" data-icon="run"></span><span>Run</span></button>
|
|
48
|
-
<button class="theme-toggle" id="themeToggle" aria-label="Toggle light / dark theme" title="Toggle light / dark"><span class="tab-ico" data-icon="theme"></span></button>
|
|
62
|
+
<button class="btn primary run-btn" id="runQuickBtn" data-i18n-title="topbar.run.title" title="Open the run chat"><span class="tab-ico" data-icon="run"></span><span data-i18n="action.run">Run</span></button>
|
|
63
|
+
<button class="theme-toggle" id="themeToggle" data-i18n-aria="topbar.theme.toggle" data-i18n-title="topbar.theme.toggle.title" aria-label="Toggle light / dark theme" title="Toggle light / dark"><span class="tab-ico" data-icon="theme"></span></button>
|
|
49
64
|
</div>
|
|
50
65
|
</header>
|
|
51
66
|
|
|
@@ -56,34 +71,35 @@
|
|
|
56
71
|
<div class="overview" id="overview"></div>
|
|
57
72
|
<div class="filters" id="filters">
|
|
58
73
|
<div class="chip-list" id="statusChips">
|
|
59
|
-
<button class="fchip active" data-status="all">All</button>
|
|
60
|
-
<button class="fchip" data-status="todo">To do</button>
|
|
61
|
-
<button class="fchip" data-status="in_progress">In progress</button>
|
|
62
|
-
<button class="fchip" data-status="to_validate">To validate</button>
|
|
63
|
-
<button class="fchip" data-status="to_analyze">To analyze</button>
|
|
64
|
-
<button class="fchip" data-status="done">Done</button>
|
|
65
|
-
<button class="fchip" data-status="blocked">Blocked</button>
|
|
74
|
+
<button class="fchip active" data-status="all" data-i18n="filter.all">All</button>
|
|
75
|
+
<button class="fchip" data-status="todo" data-i18n="status.todo">To do</button>
|
|
76
|
+
<button class="fchip" data-status="in_progress" data-i18n="status.in_progress">In progress</button>
|
|
77
|
+
<button class="fchip" data-status="to_validate" data-i18n="status.to_validate">To validate</button>
|
|
78
|
+
<button class="fchip" data-status="to_analyze" data-i18n="status.to_analyze">To analyze</button>
|
|
79
|
+
<button class="fchip" data-status="done" data-i18n="status.done">Done</button>
|
|
80
|
+
<button class="fchip" data-status="blocked" data-i18n="status.blocked">Blocked</button>
|
|
66
81
|
</div>
|
|
67
82
|
<div class="view-toggle" id="boardViewToggle" role="group" aria-label="Board view">
|
|
68
|
-
<button class="vt-btn active" data-view="list" title="Grouped by phase"><span class="tab-ico" data-icon="backlog"></span><span>List</span></button>
|
|
69
|
-
<button class="vt-btn" data-view="kanban" title="Columns by status"><span class="tab-ico" data-icon="board"></span><span>Kanban</span></button>
|
|
83
|
+
<button class="vt-btn active" data-view="list" data-i18n-title="board.viewList.title" title="Grouped by phase"><span class="tab-ico" data-icon="backlog"></span><span data-i18n="board.viewList">List</span></button>
|
|
84
|
+
<button class="vt-btn" data-view="kanban" data-i18n-title="board.viewKanban.title" title="Columns by status"><span class="tab-ico" data-icon="board"></span><span data-i18n="board.viewKanban">Kanban</span></button>
|
|
70
85
|
</div>
|
|
71
|
-
<button class="mini-btn" id="phaseToggleAll" title="Expand or collapse all phases">Expand all</button>
|
|
72
|
-
<input type="search" id="search" class="search" placeholder="Filter tasks…" autocomplete="off" />
|
|
86
|
+
<button class="mini-btn" id="phaseToggleAll" data-i18n-title="board.expandAllTitle" data-i18n="board.expandAll" title="Expand or collapse all phases">Expand all</button>
|
|
87
|
+
<input type="search" id="search" class="search" data-i18n-ph="board.filterPlaceholder" placeholder="Filter tasks…" autocomplete="off" />
|
|
73
88
|
</div>
|
|
74
89
|
<div class="board" id="board"></div>
|
|
75
90
|
</div>
|
|
76
91
|
<aside class="side" id="side">
|
|
77
92
|
<div class="rail-block rail-block-journal">
|
|
78
|
-
<h2 class="rail-title">Journal <span class="count" id="journalCount">0</span></h2>
|
|
93
|
+
<h2 class="rail-title"><span data-i18n="rail.journal">Journal</span> <span class="count" id="journalCount">0</span></h2>
|
|
79
94
|
<div class="journal" id="journal"></div>
|
|
95
|
+
<button class="mini-btn journal-more" id="journalMore" hidden></button>
|
|
80
96
|
</div>
|
|
81
97
|
<div class="rail-block">
|
|
82
|
-
<h2 class="rail-title">Specs <span class="count" id="specsCount">0</span></h2>
|
|
98
|
+
<h2 class="rail-title"><span data-i18n="rail.specs">Specs</span> <span class="count" id="specsCount">0</span></h2>
|
|
83
99
|
<ul class="flatlist" id="specs"></ul>
|
|
84
100
|
</div>
|
|
85
101
|
<div class="rail-block">
|
|
86
|
-
<h2 class="rail-title">Running <span class="count" id="runCount">0</span></h2>
|
|
102
|
+
<h2 class="rail-title"><span data-i18n="rail.running">Running</span> <span class="count" id="runCount">0</span></h2>
|
|
87
103
|
<ul class="flatlist" id="running"></ul>
|
|
88
104
|
</div>
|
|
89
105
|
</aside>
|
|
@@ -92,8 +108,8 @@
|
|
|
92
108
|
<!-- REQUESTS (tasks awaiting review: to_validate / to_analyze) -->
|
|
93
109
|
<section class="panel" data-panel="requests">
|
|
94
110
|
<div class="requests-wrap">
|
|
95
|
-
<h2 class="panel-title">Requests <span class="count" id="requestsCount">0</span></h2>
|
|
96
|
-
<p class="panel-sub">Tasks awaiting your input — status <em>to validate</em> or <em>to analyze</em>.</p>
|
|
111
|
+
<h2 class="panel-title"><span data-i18n="nav.requests">Requests</span> <span class="count" id="requestsCount">0</span></h2>
|
|
112
|
+
<p class="panel-sub" data-i18n-html="requests.sub">Tasks awaiting your input — status <em>to validate</em> or <em>to analyze</em>.</p>
|
|
97
113
|
<ul class="flatlist requests-list" id="requestsList"></ul>
|
|
98
114
|
</div>
|
|
99
115
|
</section>
|
|
@@ -101,16 +117,16 @@
|
|
|
101
117
|
<!-- ATTENTION (points raised by the agent or by you; validate → task) -->
|
|
102
118
|
<section class="panel" data-panel="attention">
|
|
103
119
|
<div class="attn-wrap">
|
|
104
|
-
<h2 class="panel-title">Points of attention <span class="count" id="attnCount">0</span></h2>
|
|
105
|
-
<p class="panel-sub">Things the agent flagged during work — or you noted — that deserve a look. <em>Validate</em> one to turn it into a task.</p>
|
|
120
|
+
<h2 class="panel-title"><span data-i18n="attn.title">Points of attention</span> <span class="count" id="attnCount">0</span></h2>
|
|
121
|
+
<p class="panel-sub" data-i18n-html="attn.sub">Things the agent flagged during work — or you noted — that deserve a look. <em>Validate</em> one to turn it into a task.</p>
|
|
106
122
|
<div class="attn-add">
|
|
107
|
-
<textarea id="attnInput" class="chat-ta" placeholder="Note something to keep an eye on…"></textarea>
|
|
108
|
-
<button id="attnAddBtn" class="btn primary">Add note</button>
|
|
123
|
+
<textarea id="attnInput" class="chat-ta" data-i18n-ph="attn.inputPlaceholder" placeholder="Note something to keep an eye on…"></textarea>
|
|
124
|
+
<button id="attnAddBtn" class="btn primary" data-i18n="attn.addNote">Add note</button>
|
|
109
125
|
</div>
|
|
110
126
|
<div class="attn-filters">
|
|
111
|
-
<button class="fchip active" data-attn="open">Open</button>
|
|
112
|
-
<button class="fchip" data-attn="all">All</button>
|
|
113
|
-
<button class="fchip" data-attn="resolved">Resolved</button>
|
|
127
|
+
<button class="fchip active" data-attn="open" data-i18n="filter.open">Open</button>
|
|
128
|
+
<button class="fchip" data-attn="all" data-i18n="filter.all">All</button>
|
|
129
|
+
<button class="fchip" data-attn="resolved" data-i18n="filter.resolved">Resolved</button>
|
|
114
130
|
</div>
|
|
115
131
|
<div class="attn-list" id="attnList"></div>
|
|
116
132
|
</div>
|
|
@@ -119,31 +135,31 @@
|
|
|
119
135
|
<!-- BACKLOG (flat, sortable, filterable table of every task) -->
|
|
120
136
|
<section class="panel" data-panel="backlog">
|
|
121
137
|
<div class="backlog-wrap">
|
|
122
|
-
<h2 class="panel-title">Backlog <span class="count" id="backlogCount">0</span></h2>
|
|
123
|
-
<p class="panel-sub">Every task, across every plan, in one flat table.</p>
|
|
138
|
+
<h2 class="panel-title"><span data-i18n="nav.backlog">Backlog</span> <span class="count" id="backlogCount">0</span></h2>
|
|
139
|
+
<p class="panel-sub" data-i18n="backlog.sub">Every task, across every plan, in one flat table.</p>
|
|
124
140
|
<div class="filters" id="backlogFilters">
|
|
125
141
|
<div class="chip-list" id="backlogStatusChips">
|
|
126
|
-
<button class="fchip active" data-status="open">Open</button>
|
|
127
|
-
<button class="fchip" data-status="all">All</button>
|
|
128
|
-
<button class="fchip" data-status="todo">To do</button>
|
|
129
|
-
<button class="fchip" data-status="in_progress">In progress</button>
|
|
130
|
-
<button class="fchip" data-status="to_validate">To validate</button>
|
|
131
|
-
<button class="fchip" data-status="to_analyze">To analyze</button>
|
|
132
|
-
<button class="fchip" data-status="done">Done</button>
|
|
133
|
-
<button class="fchip" data-status="blocked">Blocked</button>
|
|
142
|
+
<button class="fchip active" data-status="open" data-i18n="filter.open">Open</button>
|
|
143
|
+
<button class="fchip" data-status="all" data-i18n="filter.all">All</button>
|
|
144
|
+
<button class="fchip" data-status="todo" data-i18n="status.todo">To do</button>
|
|
145
|
+
<button class="fchip" data-status="in_progress" data-i18n="status.in_progress">In progress</button>
|
|
146
|
+
<button class="fchip" data-status="to_validate" data-i18n="status.to_validate">To validate</button>
|
|
147
|
+
<button class="fchip" data-status="to_analyze" data-i18n="status.to_analyze">To analyze</button>
|
|
148
|
+
<button class="fchip" data-status="done" data-i18n="status.done">Done</button>
|
|
149
|
+
<button class="fchip" data-status="blocked" data-i18n="status.blocked">Blocked</button>
|
|
134
150
|
</div>
|
|
135
|
-
<input type="search" id="backlogSearch" class="search" placeholder="Filter by id or title…" autocomplete="off" />
|
|
151
|
+
<input type="search" id="backlogSearch" class="search" data-i18n-ph="backlog.searchPlaceholder" placeholder="Filter by id or title…" autocomplete="off" />
|
|
136
152
|
</div>
|
|
137
153
|
<div class="table-scroll">
|
|
138
154
|
<table class="backlog-table" id="backlogTable">
|
|
139
155
|
<thead>
|
|
140
156
|
<tr>
|
|
141
|
-
<th data-col="id">ID</th>
|
|
142
|
-
<th data-col="title">Title</th>
|
|
143
|
-
<th data-col="phase">Phase</th>
|
|
144
|
-
<th data-col="status">Status</th>
|
|
145
|
-
<th data-col="owner">Owner</th>
|
|
146
|
-
<th data-col="level">Level</th>
|
|
157
|
+
<th data-col="id" data-i18n="col.id">ID</th>
|
|
158
|
+
<th data-col="title" data-i18n="col.title">Title</th>
|
|
159
|
+
<th data-col="phase" data-i18n="col.phase">Phase</th>
|
|
160
|
+
<th data-col="status" data-i18n="col.status">Status</th>
|
|
161
|
+
<th data-col="owner" data-i18n="col.owner">Owner</th>
|
|
162
|
+
<th data-col="level" data-i18n="col.level">Level</th>
|
|
147
163
|
<th data-col="comments">💬</th>
|
|
148
164
|
</tr>
|
|
149
165
|
</thead>
|
|
@@ -157,8 +173,8 @@
|
|
|
157
173
|
<!-- WORKFLOW -->
|
|
158
174
|
<section class="panel" data-panel="workflow">
|
|
159
175
|
<div class="wf-wrap">
|
|
160
|
-
<h2 class="panel-title">Active workflow</h2>
|
|
161
|
-
<p class="panel-sub">The pipeline your requests flow through — from idea to shipped, spec-driven. <strong>Click a step</strong> to see what it does and turn it on or off (this edits <code>.spectoflow/workflow.md</code>). Enabled steps run in order; the orchestrator gates each one by your <em>mode</em> and <em>policy</em>. Optional steps stay off until you switch them on.</p>
|
|
176
|
+
<h2 class="panel-title" data-i18n="workflow.title">Active workflow</h2>
|
|
177
|
+
<p class="panel-sub" data-i18n-html="workflow.sub">The pipeline your requests flow through — from idea to shipped, spec-driven. <strong>Click a step</strong> to see what it does and turn it on or off (this edits <code>.spectoflow/workflow.md</code>). Enabled steps run in order; the orchestrator gates each one by your <em>mode</em> and <em>policy</em>. Optional steps stay off until you switch them on.</p>
|
|
162
178
|
<div class="wf-diagram" id="wfDiagram"></div>
|
|
163
179
|
</div>
|
|
164
180
|
</section>
|
|
@@ -166,11 +182,11 @@
|
|
|
166
182
|
<!-- AGENTS & SKILLS -->
|
|
167
183
|
<section class="panel" data-panel="team">
|
|
168
184
|
<div class="team-wrap">
|
|
169
|
-
<h2 class="panel-title">Agents <span class="count" id="agentsCount">0</span></h2>
|
|
170
|
-
<p class="panel-sub">Stable team personas — the <em>who</em>.</p>
|
|
185
|
+
<h2 class="panel-title"><span data-i18n="team.agentsTitle">Agents</span> <span class="count" id="agentsCount">0</span></h2>
|
|
186
|
+
<p class="panel-sub" data-i18n-html="team.agentsSub">Stable team personas — the <em>who</em>.</p>
|
|
171
187
|
<div class="cards" id="agents"></div>
|
|
172
|
-
<h2 class="panel-title" style="margin-top:28px">Skills <span class="count" id="skillsCount">0</span></h2>
|
|
173
|
-
<p class="panel-sub">Evolving procedures — the <em>how</em>.</p>
|
|
188
|
+
<h2 class="panel-title" style="margin-top:28px"><span data-i18n="team.skillsTitle">Skills</span> <span class="count" id="skillsCount">0</span></h2>
|
|
189
|
+
<p class="panel-sub" data-i18n-html="team.skillsSub">Evolving procedures — the <em>how</em>.</p>
|
|
174
190
|
<div class="cards" id="skills"></div>
|
|
175
191
|
</div>
|
|
176
192
|
</section>
|
|
@@ -180,31 +196,31 @@
|
|
|
180
196
|
<div class="chat-tab-wrap">
|
|
181
197
|
<div class="chat-tab-head">
|
|
182
198
|
<div>
|
|
183
|
-
<h2 class="panel-title">Chat</h2>
|
|
184
|
-
<p class="panel-sub">Full conversation with the runner — the same run as the widget, more room to read it.</p>
|
|
199
|
+
<h2 class="panel-title" data-i18n="nav.chat">Chat</h2>
|
|
200
|
+
<p class="panel-sub" data-i18n="chat.tabSub">Full conversation with the runner — the same run as the widget, more room to read it.</p>
|
|
185
201
|
</div>
|
|
186
202
|
<select id="tabRunAgent" class="chat-agent" title="Agent"></select>
|
|
187
203
|
</div>
|
|
188
204
|
<div class="chat-tab-log" id="chatTabLog">
|
|
189
|
-
<div class="chat-idle">Type a request — the agent runs headless in this project with full memory
|
|
205
|
+
<div class="chat-idle" data-i18n-html="chat.idle">Type a request — the agent runs headless in this project with full memory
|
|
190
206
|
(<code>CLAUDE.md → AGENTS.md</code>) and updates the board live.</div>
|
|
191
207
|
</div>
|
|
192
208
|
<div class="chat-tab-input">
|
|
193
|
-
<textarea id="tabRunPrompt" class="chat-ta" placeholder="e.g. Add a login feature with email + password"></textarea>
|
|
209
|
+
<textarea id="tabRunPrompt" class="chat-ta" data-i18n-ph="chat.inputPlaceholder" placeholder="e.g. Add a login feature with email + password"></textarea>
|
|
194
210
|
<div class="chat-tab-actions">
|
|
195
|
-
<button id="tabRunBtn" class="btn primary chat-send">Send</button>
|
|
196
|
-
<button id="tabOrchBtn" class="btn chat-send" title="Walk the enabled workflow">Orchestrate</button>
|
|
211
|
+
<button id="tabRunBtn" class="btn primary chat-send" data-i18n="action.send">Send</button>
|
|
212
|
+
<button id="tabOrchBtn" class="btn chat-send" data-i18n-title="chat.orchestrateTitle" data-i18n="action.orchestrate" title="Walk the enabled workflow">Orchestrate</button>
|
|
197
213
|
</div>
|
|
198
214
|
</div>
|
|
199
|
-
<p class="chat-warn">⚠ Launches a real agent (<code>config.json → runners</code>) that can modify files & run commands.</p>
|
|
215
|
+
<p class="chat-warn" data-i18n-html="chat.warn">⚠ Launches a real agent (<code>config.json → runners</code>) that can modify files & run commands.</p>
|
|
200
216
|
</div>
|
|
201
217
|
</section>
|
|
202
218
|
|
|
203
219
|
<!-- INFO (project overview — filled by renderInfo() in app.js) -->
|
|
204
220
|
<section class="panel" data-panel="info">
|
|
205
221
|
<div class="info-wrap">
|
|
206
|
-
<h2 class="panel-title">Info</h2>
|
|
207
|
-
<p class="panel-sub">Project overview — configuration, counts, specs and active workflow.</p>
|
|
222
|
+
<h2 class="panel-title" data-i18n="info.title">Info</h2>
|
|
223
|
+
<p class="panel-sub" data-i18n="info.sub">Project overview — configuration, counts, specs and active workflow.</p>
|
|
208
224
|
<div class="info-grid" id="infoGrid"></div>
|
|
209
225
|
</div>
|
|
210
226
|
</section>
|
|
@@ -212,23 +228,23 @@
|
|
|
212
228
|
<!-- SETTINGS (change autonomy mode + output language → config.json) -->
|
|
213
229
|
<section class="panel" data-panel="settings">
|
|
214
230
|
<div class="settings-wrap">
|
|
215
|
-
<h2 class="panel-title">Settings</h2>
|
|
216
|
-
<p class="panel-sub">Change how spectoflow runs. Writes <code>.spectoflow/config.json</code> — the agent picks it up on its next run.</p>
|
|
231
|
+
<h2 class="panel-title" data-i18n="nav.settings">Settings</h2>
|
|
232
|
+
<p class="panel-sub" data-i18n-html="settings.sub">Change how spectoflow runs. Writes <code>.spectoflow/config.json</code> — the agent picks it up on its next run.</p>
|
|
217
233
|
<div class="settings-card">
|
|
218
234
|
<label class="settings-field">
|
|
219
|
-
<span class="settings-field-label">Dashboard design</span>
|
|
235
|
+
<span class="settings-field-label" data-i18n="field.design">Dashboard design</span>
|
|
220
236
|
<select id="setDesign" class="settings-select"></select>
|
|
221
237
|
</label>
|
|
222
238
|
<label class="settings-field">
|
|
223
|
-
<span class="settings-field-label">Autonomy mode</span>
|
|
239
|
+
<span class="settings-field-label" data-i18n="field.mode">Autonomy mode</span>
|
|
224
240
|
<select id="setMode" class="settings-select">
|
|
225
|
-
<option value="autopilot">autopilot — run freely, ask only on policy gates</option>
|
|
226
|
-
<option value="semi">semi — autopilot + policy approvals</option>
|
|
227
|
-
<option value="manual">manual — approve every step</option>
|
|
241
|
+
<option value="autopilot" data-i18n="mode.autopilot.desc">autopilot — run freely, ask only on policy gates</option>
|
|
242
|
+
<option value="semi" data-i18n="mode.semi.desc">semi — autopilot + policy approvals</option>
|
|
243
|
+
<option value="manual" data-i18n="mode.manual.desc">manual — approve every step</option>
|
|
228
244
|
</select>
|
|
229
245
|
</label>
|
|
230
246
|
<label class="settings-field">
|
|
231
|
-
<span class="settings-field-label">Output language</span>
|
|
247
|
+
<span class="settings-field-label" data-i18n="field.lang">Output language</span>
|
|
232
248
|
<select id="setLang" class="settings-select">
|
|
233
249
|
<option value="en">en · English</option>
|
|
234
250
|
<option value="fr">fr · Français</option>
|
|
@@ -238,7 +254,7 @@
|
|
|
238
254
|
<option value="it">it · Italiano</option>
|
|
239
255
|
</select>
|
|
240
256
|
</label>
|
|
241
|
-
<div class="settings-saved" id="settingsSaved" hidden>✓ saved</div>
|
|
257
|
+
<div class="settings-saved" id="settingsSaved" data-i18n="settings.saved" hidden>✓ saved</div>
|
|
242
258
|
</div>
|
|
243
259
|
<div class="settings-readonly" id="settingsReadonly"></div>
|
|
244
260
|
</div>
|
|
@@ -259,31 +275,31 @@
|
|
|
259
275
|
<div class="footer-right">
|
|
260
276
|
<a href="https://github.com/georgesmomo/spectoflow" target="_blank" rel="noopener">GitHub</a>
|
|
261
277
|
<a href="https://www.npmjs.com/package/spectoflow" target="_blank" rel="noopener">npm</a>
|
|
262
|
-
<button class="footer-link" id="footerSettings">Settings</button>
|
|
278
|
+
<button class="footer-link" id="footerSettings" data-i18n="nav.settings">Settings</button>
|
|
263
279
|
</div>
|
|
264
280
|
</footer>
|
|
265
281
|
|
|
266
282
|
<!-- CHAT WIDGET (floating agent runner; entry point to the group-chat) -->
|
|
267
|
-
<button class="chat-fab" id="chatFab" aria-label="Open run chat" title="Run an agent">💬</button>
|
|
283
|
+
<button class="chat-fab" id="chatFab" data-i18n-title="chat.widgetTitle" aria-label="Open run chat" title="Run an agent">💬</button>
|
|
268
284
|
<div class="chat" id="chat" aria-hidden="true" role="dialog" aria-label="Run an agent">
|
|
269
285
|
<div class="chat-head">
|
|
270
286
|
<div class="chat-head-text">
|
|
271
|
-
<span class="chat-title">Run an agent</span>
|
|
272
|
-
<span class="chat-sub">Quick access · full view in the Chat tab</span>
|
|
287
|
+
<span class="chat-title" data-i18n="chat.widgetTitle">Run an agent</span>
|
|
288
|
+
<span class="chat-sub" data-i18n="chat.widgetSub">Quick access · full view in the Chat tab</span>
|
|
273
289
|
</div>
|
|
274
290
|
<select id="runAgent" class="chat-agent" title="Agent"></select>
|
|
275
291
|
<button class="chat-close" id="chatClose" aria-label="Close">×</button>
|
|
276
292
|
</div>
|
|
277
293
|
<div class="chat-log" id="chatLog">
|
|
278
|
-
<div class="chat-idle">Type a request — the agent runs headless in this project with full memory
|
|
294
|
+
<div class="chat-idle" data-i18n-html="chat.idle">Type a request — the agent runs headless in this project with full memory
|
|
279
295
|
(<code>CLAUDE.md → AGENTS.md</code>) and updates the board live.</div>
|
|
280
296
|
</div>
|
|
281
297
|
<div class="chat-input">
|
|
282
|
-
<textarea id="runPrompt" class="chat-ta" placeholder="e.g. Add a login feature with email + password"></textarea>
|
|
283
|
-
<button id="runBtn" class="btn primary chat-send">Send</button>
|
|
284
|
-
<button id="orchBtn" class="btn chat-send" title="Walk the enabled workflow">Orchestrate</button>
|
|
298
|
+
<textarea id="runPrompt" class="chat-ta" data-i18n-ph="chat.inputPlaceholder" placeholder="e.g. Add a login feature with email + password"></textarea>
|
|
299
|
+
<button id="runBtn" class="btn primary chat-send" data-i18n="action.send">Send</button>
|
|
300
|
+
<button id="orchBtn" class="btn chat-send" data-i18n-title="chat.orchestrateTitle" data-i18n="action.orchestrate" title="Walk the enabled workflow">Orchestrate</button>
|
|
285
301
|
</div>
|
|
286
|
-
<p class="chat-warn">⚠ Launches a real agent (<code>config.json → runners</code>) that can modify files & run commands.</p>
|
|
302
|
+
<p class="chat-warn" data-i18n-html="chat.warn">⚠ Launches a real agent (<code>config.json → runners</code>) that can modify files & run commands.</p>
|
|
287
303
|
</div>
|
|
288
304
|
|
|
289
305
|
<div class="drawer" id="drawer" aria-hidden="true">
|
|
@@ -311,6 +327,7 @@
|
|
|
311
327
|
<script src="charts.js"></script>
|
|
312
328
|
<script src="icons.js"></script>
|
|
313
329
|
<script src="designs.js"></script>
|
|
330
|
+
<script src="i18n.js"></script>
|
|
314
331
|
<script src="app.js"></script>
|
|
315
332
|
<script src="designs/console.js"></script>
|
|
316
333
|
<script src="designs/orbit.js"></script>
|
|
@@ -26,7 +26,20 @@ body { background:var(--bg); color:var(--ink); font-family:var(--sans); font-siz
|
|
|
26
26
|
.brand-text { display:flex; flex-direction:column; gap:2px; min-width:0; }
|
|
27
27
|
.brand-line { display:flex; align-items:center; gap:7px; min-width:0; }
|
|
28
28
|
.brand-name { font-weight:700; } .brand-sep{ color:var(--faint); } .brand-project{ color:var(--muted); font-weight:500; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
|
|
29
|
-
.brand-sub { font-family:var(--mono); font-size:9.5px; text-transform:uppercase; letter-spacing:.08em; color:var(--faint); }
|
|
29
|
+
.brand-sub { display:flex; align-items:center; gap:4px; font-family:var(--mono); font-size:9.5px; text-transform:uppercase; letter-spacing:.08em; color:var(--faint); }
|
|
30
|
+
.brand-sub-sep { color:var(--faint); }
|
|
31
|
+
/* Quick mode/language switch, right on the bar — same source of truth as Settings (renderSettings()
|
|
32
|
+
keeps both pairs synced; a change here saves via the same /api/settings call). Kept visually quiet
|
|
33
|
+
(transparent, no border) until hovered/focused, so it reads as bar text until you reach for it. */
|
|
34
|
+
.brand-mini-select {
|
|
35
|
+
appearance:none; -webkit-appearance:none; border:1px solid transparent; border-radius:5px;
|
|
36
|
+
background:transparent; color:inherit; font:inherit; text-transform:inherit; letter-spacing:inherit;
|
|
37
|
+
padding:1px 14px 1px 3px; cursor:pointer;
|
|
38
|
+
background-image:linear-gradient(45deg,transparent 50%,currentColor 50%),linear-gradient(135deg,currentColor 50%,transparent 50%);
|
|
39
|
+
background-position:right 5px top 55%,right 2px top 55%; background-size:3px 3px,3px 3px; background-repeat:no-repeat;
|
|
40
|
+
}
|
|
41
|
+
.brand-mini-select:hover,.brand-mini-select:focus-visible { color:var(--ink); border-color:var(--line); background-color:var(--surface-2); outline:none; }
|
|
42
|
+
.brand-mini-select option { color:var(--ink); background:var(--surface); text-transform:none; }
|
|
30
43
|
.progress-meter { width:76px; height:5px; border-radius:999px; background:var(--surface-2); overflow:hidden; flex-shrink:0; margin-left:4px; }
|
|
31
44
|
.progress-meter-fill { height:100%; width:0%; background:linear-gradient(90deg,var(--cool),var(--signal)); border-radius:999px; transition:width .5s ease; }
|
|
32
45
|
.tabs { justify-self:center; display:flex; gap:2px; min-width:0; max-width:100%; overflow-x:auto; overflow-y:hidden; scrollbar-width:none; }
|
|
@@ -818,6 +831,7 @@ body.booting .wf-step2 { opacity:0; animation:rise .4s cubic-bezier(.2,.8,.2,1)
|
|
|
818
831
|
|
|
819
832
|
/* ---- board compactness: expand/collapse-all button + kanban column scroll (v0.13.5) ---- */
|
|
820
833
|
.mini-btn { font:inherit; font-size:11.5px; padding:5px 12px; border:1px solid var(--line); border-radius:999px; background:var(--surface); color:var(--muted); cursor:pointer; flex-shrink:0; }
|
|
834
|
+
.journal-more { display:block; width:100%; margin-top:8px; text-align:center; }
|
|
821
835
|
.mini-btn:hover { color:var(--ink); border-color:var(--cool); }
|
|
822
836
|
.main:has(.board.is-kanban) #phaseToggleAll { display:none; } /* phases are a List concept */
|
|
823
837
|
.kanban-col-body { max-height:64vh; overflow-y:auto; } /* keep columns compact on a big project */
|
|
@@ -29,6 +29,7 @@ function frameworkVersion(){
|
|
|
29
29
|
function project(){
|
|
30
30
|
const p = store.readProject(ROOT);
|
|
31
31
|
const v = frameworkVersion(); if (v) p.version = v;
|
|
32
|
+
p.projectName = path.basename(ROOT); // the actual project folder, always shown in the topbar
|
|
32
33
|
return p;
|
|
33
34
|
}
|
|
34
35
|
function sendJSON(res,code,obj){ res.writeHead(code,{'Content-Type':'application/json; charset=utf-8'}); res.end(JSON.stringify(obj)); }
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: write-e2e-tests
|
|
3
|
-
description: Author durable, CI-runnable end-to-end tests
|
|
3
|
+
description: Author durable, CI-runnable Playwright end-to-end tests — run headed, directly in the browser, by default; falls back to MCP, native browser tooling or headless, always telling the user why.
|
|
4
4
|
capability: testing
|
|
5
5
|
inputs: The user-visible flow(s) under test (spec acceptance criteria or a plan task), the running app under test, and its existing `tests/e2e/` suite and Playwright config if any.
|
|
6
6
|
outputs: Committed Playwright spec files under `tests/e2e/*.spec.ts`, runnable in CI.
|
|
@@ -44,22 +44,59 @@ Practices below are current Playwright guidance (see References for exact source
|
|
|
44
44
|
8. **Keep specs scoped to one flow each**, named for the behavior under test, and placed under
|
|
45
45
|
`tests/e2e/*.spec.ts` in the user's project.
|
|
46
46
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
**
|
|
61
|
-
|
|
62
|
-
|
|
47
|
+
## Running the tests — headed, in the real browser, by default
|
|
48
|
+
|
|
49
|
+
**Default: Playwright lib, headed.** When this skill's own agent runs the suite — while authoring it,
|
|
50
|
+
verifying a flow, or investigating a failure — run it **directly in a visible browser window**:
|
|
51
|
+
`npx playwright test --headed`. Watching the browser act out the flow, rather than reading a bare
|
|
52
|
+
pass/fail line, is the whole point: it is how you (and the user, if watching) catch a flow that
|
|
53
|
+
"passes" for the wrong reason. This is the default **local run mode** — not a suggestion to try once
|
|
54
|
+
in a while.
|
|
55
|
+
|
|
56
|
+
**`--ui` mode for authoring and debugging.** Reach for `npx playwright test --ui` when writing a new
|
|
57
|
+
flow or chasing a failure: it steps through each action with time-travel, showing the DOM/network at
|
|
58
|
+
every point, and is the fastest way to build a flow interactively before locking it into a spec.
|
|
59
|
+
|
|
60
|
+
**CI stays headless — that is not a fallback, it is a different job.** The committed suite still runs
|
|
61
|
+
`npx playwright test` (no `--headed`) in the project's CI pipeline, per the Quality bar below: most CI
|
|
62
|
+
runners have no real display, and headless is faster and the industry-standard way to gate a merge.
|
|
63
|
+
The headed-by-default rule governs *this skill's own local run loop*, not the CI config it authors.
|
|
64
|
+
|
|
65
|
+
**Switch away from headed only when:**
|
|
66
|
+
- **the user explicitly asked for something else** (headless, `--ui`, a specific project/browser) —
|
|
67
|
+
honor it, no need to justify; or
|
|
68
|
+
- **headed genuinely cannot run** (no display / sandboxed or remote environment / browsers not
|
|
69
|
+
installed) — then step down the ladder below.
|
|
70
|
+
|
|
71
|
+
Whenever you step down for the second reason, **say so** — don't silently swap to a quieter mode:
|
|
72
|
+
|
|
73
|
+
```
|
|
74
|
+
::spectoflow role=testing kind=progress msg=Running headless — no display available in this environment (would default to --headed)
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
or, if it blocks the task entirely, raise it as a `need` (see Output contract).
|
|
78
|
+
|
|
79
|
+
### The fallback ladder
|
|
80
|
+
1. **Playwright lib, headed** (default) — `npx playwright test --headed`. Needs `@playwright/test` as
|
|
81
|
+
the project's devDependency and `npx playwright install` for the browsers.
|
|
82
|
+
2. **Playwright lib, `--ui`** — for interactively authoring or debugging one flow before committing it.
|
|
83
|
+
3. **Playwright lib, headless** — same lib, just invisible: use when headed can't launch, or the user
|
|
84
|
+
asked for headless. Still the lib — nothing else changes.
|
|
85
|
+
4. **Playwright MCP** (`@playwright/mcp`, wired into the project's `.mcp.json` by `spectoflow init`):
|
|
86
|
+
the **agent-agnostic** way to drive a real browser and **generate** a spec from a recorded flow —
|
|
87
|
+
reach for this to explore an unfamiliar app or reproduce a bug, or when the project has no
|
|
88
|
+
Playwright lib set up yet. Works in any MCP client (Claude Code, Codex, Cursor, …); `npx` fetches
|
|
89
|
+
the server on first use — nothing to install; if it isn't wired, add it or re-run `spectoflow init`
|
|
90
|
+
(idempotent).
|
|
91
|
+
5. **The client's native browser tooling** (for Claude Code, the Chrome extension / `claude-in-chrome`)
|
|
92
|
+
for live/exploratory checks when neither the local lib nor MCP is usable.
|
|
93
|
+
6. **If no browser can run at all** (restricted CI, no browsers installed, nothing wired): still
|
|
94
|
+
**write the durable spec** (the artifact that lasts), then raise a `need` / Attention item with the
|
|
95
|
+
exact commands to enable it — never report a pass you couldn't actually observe.
|
|
96
|
+
|
|
97
|
+
**Live/exploratory verification is not this skill's output.** Whichever rung you're on, the durable,
|
|
98
|
+
CI-runnable artifact this skill produces is always the Playwright **spec file**, not the live session —
|
|
99
|
+
the live browser (headed, `--ui`, MCP, or the extension) is only the means to write and check it.
|
|
63
100
|
|
|
64
101
|
**Playwright is a dependency of the user's project, never of spectoflow.** This skill authors tests
|
|
65
102
|
against whatever Playwright version the target project has (or proposes adding `@playwright/test` as a
|
|
@@ -78,6 +115,14 @@ project devDependency when none exists) — spectoflow itself stays at zero runt
|
|
|
78
115
|
::spectoflow role=testing kind=result msg=<spec file> <pass|fail> (<n> tests)
|
|
79
116
|
::spectoflow role=testing kind=done msg=<flow name> e2e suite committed at tests/e2e/<file>
|
|
80
117
|
```
|
|
118
|
+
- Any step down the fallback ladder away from **Playwright lib, headed** (the default) is reported the
|
|
119
|
+
moment it happens, with the reason — never a silent switch:
|
|
120
|
+
|
|
121
|
+
```
|
|
122
|
+
::spectoflow role=testing kind=progress msg=Running headless — <reason> (would default to --headed)
|
|
123
|
+
::spectoflow role=testing kind=progress msg=Falling back to Playwright MCP — <reason>
|
|
124
|
+
::spectoflow role=testing kind=need msg=No browser can run here — spec written, needs <exact command> to verify
|
|
125
|
+
```
|
|
81
126
|
|
|
82
127
|
## Quality bar
|
|
83
128
|
- [ ] Each spec asserts user-visible behavior (text/role/state), not internal implementation.
|
|
@@ -90,6 +135,10 @@ project devDependency when none exists) — spectoflow itself stays at zero runt
|
|
|
90
135
|
- [ ] `trace: 'on-first-retry'` (or equivalent) is set so a CI failure is debuggable without tracing
|
|
91
136
|
every run.
|
|
92
137
|
- [ ] No spectoflow file declares Playwright as a dependency — only the user project's `package.json`.
|
|
138
|
+
- [ ] The local run defaulted to **Playwright lib, headed** (`--headed`), not headless, unless the user
|
|
139
|
+
asked otherwise or headed genuinely could not launch.
|
|
140
|
+
- [ ] Any step away from the headed default (headless, MCP, native browser tooling) was **announced**
|
|
141
|
+
with its reason via the `::spectoflow` sentinel — never a silent switch.
|
|
93
142
|
|
|
94
143
|
## References
|
|
95
144
|
- Playwright — Best Practices — https://playwright.dev/docs/best-practices (test user-visible behavior;
|
|
@@ -107,3 +156,9 @@ project devDependency when none exists) — spectoflow itself stays at zero runt
|
|
|
107
156
|
matching configuration).
|
|
108
157
|
- Playwright — Trace viewer — https://playwright.dev/docs/trace-viewer (`trace: 'on-first-retry'` for
|
|
109
158
|
CI).
|
|
159
|
+
- Playwright — Running and debugging tests — https://playwright.dev/docs/running-tests (headed mode is
|
|
160
|
+
the default way to watch a run locally).
|
|
161
|
+
- Playwright — UI Mode — https://playwright.dev/docs/test-ui-mode (`--ui`, time-travel debugging for
|
|
162
|
+
authoring and chasing failures).
|
|
163
|
+
- Playwright MCP — https://github.com/microsoft/playwright-mcp (agent-driven browser automation and
|
|
164
|
+
spec generation, agent-agnostic via MCP).
|