spectoflow 0.20.0 → 0.21.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/README.md +47 -15
- package/bin/spectoflow.js +6 -4
- package/lib/adapters.js +108 -7
- package/package.json +1 -1
- package/templates/README.md +2 -0
- package/templates/dashboard/public/app.js +94 -13
- package/templates/dashboard/public/i18n.js +96 -6
- package/templates/dashboard/public/icons.js +2 -0
- package/templates/dashboard/public/index.html +22 -6
- package/templates/dashboard/public/styles.css +20 -11
- package/templates/dashboard/runner.js +14 -2
- package/templates/dashboard/server.js +5 -2
- package/templates/dashboard/summarize.js +2 -1
- package/templates/lib/agents-registry.js +20 -7
package/README.md
CHANGED
|
@@ -20,11 +20,39 @@ An **agent-agnostic** spec-driven development framework with a **real-time local
|
|
|
20
20
|
You speak in plain language; the framework classifies your intent and runs the right workflow. No
|
|
21
21
|
ceremonial command to start.
|
|
22
22
|
|
|
23
|
-
**Works with whichever coding agent you have
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
23
|
+
**Works with whichever coding agent you have.** `init` auto-detects what's installed; the dashboard's
|
|
24
|
+
topbar always shows the **active agent**, front and center, with a switcher — pick another and it's
|
|
25
|
+
verified as genuinely installed before activating (a red **"No agent found"** if none is), never
|
|
26
|
+
silently activating something that isn't there.
|
|
27
|
+
|
|
28
|
+
> Note the terminology: "agent" is overloaded here on purpose, matching how the ecosystem uses the
|
|
29
|
+
> word. The table below is about **coding-agent CLIs** — the tool you already run in your terminal
|
|
30
|
+
> (Claude Code, Copilot CLI, …). spectoflow's own **team personas** (developer, qa-engineer, …) are a
|
|
31
|
+
> different, unrelated use of "agent" — see [Agents vs skills](#agents-vs-skills) further down.
|
|
32
|
+
|
|
33
|
+
| Coding agent | Headless run | Docs |
|
|
34
|
+
|---|---|---|
|
|
35
|
+
| Claude Code | ✓ | [code.claude.com/docs/en/cli-reference](https://code.claude.com/docs/en/cli-reference) |
|
|
36
|
+
| Codex | ✓ | [developers.openai.com/codex/cli/reference](https://developers.openai.com/codex/cli/reference) |
|
|
37
|
+
| Cursor CLI | ✓ | [cursor.com/docs/cli/overview](https://cursor.com/docs/cli/overview) |
|
|
38
|
+
| Gemini CLI | ✓ | [github.com/google-gemini/gemini-cli](https://github.com/google-gemini/gemini-cli) |
|
|
39
|
+
| OpenCode | ✓ | [opencode.ai/docs/cli](https://opencode.ai/docs/cli/) |
|
|
40
|
+
| Kiro CLI | ✓ | [kiro.dev/docs/cli/headless](https://kiro.dev/docs/cli/headless/) |
|
|
41
|
+
| Antigravity | ✓ | [antigravity.google/docs/cli/headless](https://antigravity.google/docs/cli/headless/) |
|
|
42
|
+
| GitHub Copilot CLI | ✓ | [docs.github.com/copilot/…/about-copilot-cli](https://docs.github.com/copilot/concepts/agents/about-copilot-cli) |
|
|
43
|
+
| Amazon Q Developer CLI | ✓ | [docs.aws.amazon.com/amazonq/…/command-line-chat](https://docs.aws.amazon.com/amazonq/latest/qdeveloper-ug/command-line-chat.html) |
|
|
44
|
+
| Factory Droid CLI | ✓ | [docs.factory.ai/droid-exec/overview](https://docs.factory.ai/droid-exec/overview) |
|
|
45
|
+
| Auggie CLI (Augment Code) | ✓ | [docs.augmentcode.com/cli/overview](https://docs.augmentcode.com/cli/overview) |
|
|
46
|
+
| Goose CLI (Block) | ✓ | [block.github.io/goose](https://block.github.io/goose/) |
|
|
47
|
+
| Kimi CLI | detectable, manual only | [github.com/MoonshotAI/kimi-cli](https://github.com/MoonshotAI/kimi-cli) |
|
|
48
|
+
|
|
49
|
+
"Headless run" means spectoflow can actually spawn it non-interactively (`Run`/`Orchestrate`/
|
|
50
|
+
`Summarize` work). Kimi CLI has no confirmed one-shot mode as of this writing — spectoflow still
|
|
51
|
+
detects it and lets you set it as the active agent, it just won't try to spawn it (the pickers that
|
|
52
|
+
launch a run grey it out rather than hide it); drive it yourself in its own terminal meanwhile. The
|
|
53
|
+
same live table, with your own install status, is in the dashboard's **Documentation** tab. Missing
|
|
54
|
+
one you use? `config.json → runners` still takes any custom command by hand — see
|
|
55
|
+
[`templates/README.md`](templates/README.md) — or open an issue.
|
|
28
56
|
|
|
29
57
|
## Install
|
|
30
58
|
|
|
@@ -139,16 +167,19 @@ spectoflow dashboard # → http://localhost:4319 (or --port=
|
|
|
139
167
|
`spectoflow dashboard` is the simple way — it prints the URL and won't double-start (it detects a
|
|
140
168
|
dashboard already running on the port). `spectoflow status` tells you whether one is up. Running the
|
|
141
169
|
`server.js` directly still works for a manual/embedded setup. Zero dependencies, updates live via SSE +
|
|
142
|
-
file watching.
|
|
143
|
-
global-progress meter · a sync dot · a **Run** quick-action
|
|
144
|
-
control-room Overview — KPI cards, a status donut, a **scope-vs-delivered area curve**, a
|
|
170
|
+
file watching. Ten tabs behind a dense icon-tab header (brand logo · subtitle · **active agent** ·
|
|
171
|
+
autonomy mode · language · a slim global-progress meter · a sync dot · a **Run** quick-action): **Board**
|
|
172
|
+
(the control-room Overview — compact KPI cards, a status donut, a **scope-vs-delivered area curve**, a
|
|
145
173
|
workflow-at-a-glance strip, per-phase progress bars, filter chips + search — plus the phase board),
|
|
146
|
-
**
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
full-
|
|
174
|
+
**Chat** (a full-height group-chat panel with **Summarize**/**Clear**), **Requests** (tasks awaiting
|
|
175
|
+
you — `to_validate`/`to_analyze`), **Attention** (points the agent raised via a `::spectoflow attention
|
|
176
|
+
msg=…` sentinel or that you noted — edit/resolve/delete, or **validate → task**), **Backlog** (a flat
|
|
177
|
+
sortable/filterable, paginated table of every task, defaulting to open work), **Workflow** (the
|
|
178
|
+
pipeline as step cards — click one to enable/disable it, which edits `workflow.md`), **Agents &
|
|
179
|
+
Skills** (enriched cards that open a full-body markdown drawer), **Info** (a project-at-a-glance
|
|
180
|
+
summary), **Documentation** (the supported-agents table above, live with your own install status and
|
|
181
|
+
links, plus the CLI command reference), and **Personalize** (autonomy mode, language, design, the
|
|
182
|
+
active agent, and **Extend spectoflow** — described under *Customize* below). URLs are real routes
|
|
152
183
|
(`/board`, `/backlog/T-012`, …). Charts are zero-dep, hand-rolled SVG in `dashboard/public/charts.js`
|
|
153
184
|
(donut/area/bars/ring, animated, `prefers-reduced-motion`-aware), and every aggregate is computed
|
|
154
185
|
client-side.
|
|
@@ -173,7 +204,8 @@ read-only endpoint, `GET /api/agentfile?path=` (scoped to `.spectoflow/agents/**
|
|
|
173
204
|
`.spectoflow/skills/**`, path-traversal-safe) — the framework's only other server surface is
|
|
174
205
|
unchanged.
|
|
175
206
|
|
|
176
|
-
**Customize.**
|
|
207
|
+
**Customize.** Personalize → **Extend spectoflow** lets you extend the project's own spectoflow
|
|
208
|
+
install: add a
|
|
177
209
|
dashboard, a skill, or an agent by describing what you want (or hit **Auto** to have the agent survey
|
|
178
210
|
the project and propose candidates), and it clarifies first if the ask is ambiguous. Dashboards are
|
|
179
211
|
never raw HTML — they're a small **declarative block spec** (`markdown`, `kpi-row`, `chart-bars`,
|
package/bin/spectoflow.js
CHANGED
|
@@ -474,10 +474,12 @@ ${c.dim('Docs:')} https://github.com/georgesmomo/spectoflow`);
|
|
|
474
474
|
const HELP = {
|
|
475
475
|
init: `${c.bold('spectoflow init')} ${c.dim('[dir] [--agent=a,b]')}\n
|
|
476
476
|
Scaffold spectoflow into <dir> (default: current directory).
|
|
477
|
-
Auto-detects installed agents (${c.dim('claude, codex, cursor, gemini')}
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
${c.dim('
|
|
477
|
+
Auto-detects installed agents (${c.dim('claude, codex, cursor, gemini, opencode, kiro, antigravity,')}
|
|
478
|
+
${c.dim('copilot, amazon-q, droid, auggie, goose, kimi')}) and writes their entry shims; override
|
|
479
|
+
with ${c.g('--agent=claude,codex')}. Also wires ${c.bold('Playwright MCP')} into the project's
|
|
480
|
+
${c.dim('.mcp.json')} (idempotent — never touches an existing entry).
|
|
481
|
+
${c.dim('An existing CLAUDE.md is preserved as CLAUDE.md.tomerge for you to merge on first run.')}
|
|
482
|
+
${c.dim('Full list with docs links: the dashboard\'s Documentation tab, or the README.')}`,
|
|
481
483
|
update: `${c.bold('spectoflow update')} ${c.dim('[--dry-run] [--force|-f]')}\n
|
|
482
484
|
Refresh framework-owned files (engine, dashboard, default agents & skills, AGENTS.md, policy…)
|
|
483
485
|
to this CLI's version, ${c.bold('preserving your work')}: config.json, workflow.md, specs/, plans/
|
package/lib/adapters.js
CHANGED
|
@@ -68,56 +68,157 @@ Argument: \`$ARGUMENTS\`
|
|
|
68
68
|
|
|
69
69
|
// Priority order = which agent becomes the default when several are detected.
|
|
70
70
|
//
|
|
71
|
-
//
|
|
72
|
-
//
|
|
73
|
-
//
|
|
74
|
-
//
|
|
75
|
-
//
|
|
71
|
+
// `docsUrl` points at that agent's own official CLI docs — cited from the research pass that set
|
|
72
|
+
// `runner`/`headless`, never guessed; it's surfaced verbatim in the dashboard's Documentation tab so
|
|
73
|
+
// "which agent is this and where do I read about it" has a real answer, not just an id.
|
|
74
|
+
//
|
|
75
|
+
// `headless: false` marks an agent spectoflow can DETECT and let you set as active, but never spawn
|
|
76
|
+
// itself — no confirmed non-interactive one-shot mode (prompt as trailing arg → stdout → exit) as of
|
|
77
|
+
// this research pass, so `runner` is null on purpose (a fabricated command would just fail silently
|
|
78
|
+
// for real users). The dashboard still lists it and shows why Run/Orchestrate/Summarize are disabled
|
|
79
|
+
// for it, rather than hiding it — you can drive it yourself in its own terminal meanwhile, and
|
|
80
|
+
// `config.json → runners` is still yours to hand-wire a command into if one ships later.
|
|
81
|
+
//
|
|
82
|
+
// A runner string with more than one flag deliberately puts the trailing prompt right after whichever
|
|
83
|
+
// flag takes a value (e.g. `copilot -s --allow-all-tools -p`, not `copilot -p --allow-all-tools`) —
|
|
84
|
+
// runner.js spawns `[...parts.slice(1), prompt]`, appending the prompt as the LAST token, so a
|
|
85
|
+
// value-taking flag must be the last one in the string or the prompt lands on the wrong flag.
|
|
86
|
+
//
|
|
87
|
+
// Researched against both github.com/Fission-AI/OpenSpec/blob/main/docs/supported-tools.md and
|
|
88
|
+
// github.github.io/spec-kit/reference/integrations.html (broad agent-compatibility lists) — those
|
|
89
|
+
// pages document IDE/slash-command integration, not headless CLI support, so every entry below was
|
|
90
|
+
// independently verified against that tool's own primary docs regardless of appearing there.
|
|
91
|
+
//
|
|
92
|
+
// Left out of KNOWN_AGENTS entirely (not even headless:false) — researched, not re-added on a whim:
|
|
93
|
+
// DeepSeek Harness (deepseek-ai/deepseek-harness). It has no single installable binary to detect —
|
|
94
|
+
// it's invoked as `npx @deepseek-ai/dsh <subcommand>`, is explicitly a local WEB-APP framework (not a
|
|
95
|
+
// terminal chat/prompt tool like the others), and ships as an August-2026 "developer preview" whose
|
|
96
|
+
// APIs the project itself says will change. Detecting "is npx present" would not mean deepseek-harness
|
|
97
|
+
// is; it doesn't fit this registry's detection model. Revisit once it (or Kimi) publishes a real
|
|
98
|
+
// one-shot flag, or wire a custom command into config.json → runners by hand in the meantime.
|
|
76
99
|
const REGISTRY = [
|
|
77
100
|
{
|
|
78
101
|
id: 'claude',
|
|
102
|
+
label: 'Claude Code',
|
|
79
103
|
entries: [
|
|
80
104
|
{ path: 'CLAUDE.md', content: CLAUDE_MD },
|
|
81
105
|
{ path: '.claude/commands/spectoflow.md', content: SLASH_CMD },
|
|
82
106
|
],
|
|
83
107
|
runner: 'claude -p --permission-mode acceptEdits',
|
|
108
|
+
headless: true,
|
|
109
|
+
docsUrl: 'https://code.claude.com/docs/en/cli-reference',
|
|
84
110
|
detect: { bin: 'claude', dirs: ['.claude'] },
|
|
85
111
|
},
|
|
86
112
|
{
|
|
87
113
|
id: 'codex',
|
|
114
|
+
label: 'Codex',
|
|
88
115
|
entries: [{ path: 'AGENTS.md', content: ROOT_AGENTS_MD }],
|
|
89
116
|
runner: 'codex exec',
|
|
117
|
+
headless: true,
|
|
118
|
+
docsUrl: 'https://developers.openai.com/codex/cli/reference',
|
|
90
119
|
detect: { bin: 'codex', dirs: ['.codex'] },
|
|
91
120
|
},
|
|
92
121
|
{
|
|
93
122
|
id: 'cursor',
|
|
123
|
+
label: 'Cursor',
|
|
94
124
|
entries: [{ path: 'AGENTS.md', content: ROOT_AGENTS_MD }],
|
|
95
125
|
runner: 'cursor-agent -p',
|
|
126
|
+
headless: true,
|
|
127
|
+
docsUrl: 'https://cursor.com/docs/cli/overview',
|
|
96
128
|
detect: { bin: 'cursor-agent', dirs: ['.cursor'] },
|
|
97
129
|
},
|
|
98
130
|
{
|
|
99
131
|
id: 'gemini',
|
|
132
|
+
label: 'Gemini CLI',
|
|
100
133
|
entries: [{ path: 'GEMINI.md', content: GEMINI_MD }],
|
|
101
134
|
runner: 'gemini -p',
|
|
135
|
+
headless: true,
|
|
136
|
+
docsUrl: 'https://github.com/google-gemini/gemini-cli',
|
|
102
137
|
detect: { bin: 'gemini', dirs: ['.gemini'] },
|
|
103
138
|
},
|
|
104
139
|
{
|
|
105
140
|
id: 'opencode',
|
|
141
|
+
label: 'OpenCode',
|
|
106
142
|
entries: [{ path: 'AGENTS.md', content: ROOT_AGENTS_MD }],
|
|
107
143
|
runner: 'opencode run --quiet',
|
|
144
|
+
headless: true,
|
|
145
|
+
docsUrl: 'https://opencode.ai/docs/cli/',
|
|
108
146
|
detect: { bin: 'opencode', dirs: ['.opencode'] },
|
|
109
147
|
},
|
|
110
148
|
{
|
|
111
149
|
id: 'kiro',
|
|
150
|
+
label: 'Kiro CLI',
|
|
112
151
|
entries: [{ path: 'AGENTS.md', content: ROOT_AGENTS_MD }],
|
|
113
152
|
runner: 'kiro-cli chat --no-interactive --trust-all-tools',
|
|
153
|
+
headless: true,
|
|
154
|
+
docsUrl: 'https://kiro.dev/docs/cli/headless/',
|
|
114
155
|
detect: { bin: 'kiro-cli', dirs: ['.kiro'] },
|
|
115
156
|
},
|
|
116
157
|
{
|
|
117
158
|
id: 'antigravity',
|
|
159
|
+
label: 'Antigravity',
|
|
118
160
|
entries: [{ path: 'AGENTS.md', content: ROOT_AGENTS_MD }],
|
|
119
161
|
runner: 'agy -p',
|
|
120
|
-
|
|
162
|
+
headless: true,
|
|
163
|
+
docsUrl: 'https://antigravity.google/docs/cli/headless/',
|
|
164
|
+
detect: { bin: 'agy', dirs: [] },
|
|
165
|
+
},
|
|
166
|
+
{
|
|
167
|
+
id: 'kimi',
|
|
168
|
+
label: 'Kimi CLI',
|
|
169
|
+
entries: [{ path: 'AGENTS.md', content: ROOT_AGENTS_MD }],
|
|
170
|
+
runner: null, // no confirmed non-interactive one-shot mode — see the note above REGISTRY
|
|
171
|
+
headless: false,
|
|
172
|
+
docsUrl: 'https://github.com/MoonshotAI/kimi-cli',
|
|
173
|
+
detect: { bin: 'kimi', dirs: [] },
|
|
174
|
+
},
|
|
175
|
+
{
|
|
176
|
+
id: 'copilot',
|
|
177
|
+
label: 'GitHub Copilot CLI',
|
|
178
|
+
entries: [{ path: 'AGENTS.md', content: ROOT_AGENTS_MD }], // also reads CLAUDE.md/GEMINI.md and its own .github/copilot-instructions.md natively
|
|
179
|
+
runner: 'copilot -s --allow-all-tools -p',
|
|
180
|
+
headless: true,
|
|
181
|
+
docsUrl: 'https://docs.github.com/copilot/concepts/agents/about-copilot-cli',
|
|
182
|
+
// No detect.dirs on purpose: `.github/` is common on any project with GitHub Actions, whether or
|
|
183
|
+
// not Copilot CLI is set up — using it as a signal would falsely mark Copilot "installed" on
|
|
184
|
+
// countless unrelated projects. PATH detection (the bin) only.
|
|
185
|
+
detect: { bin: 'copilot', dirs: [] },
|
|
186
|
+
},
|
|
187
|
+
{
|
|
188
|
+
id: 'amazon-q',
|
|
189
|
+
label: 'Amazon Q Developer CLI',
|
|
190
|
+
entries: [{ path: 'AGENTS.md', content: ROOT_AGENTS_MD }], // NOT confirmed native — Q wires memory via `.amazonq/rules/**/*.md` referenced in its own agent config; this pointer is a harmless, forward-compatible default in the meantime
|
|
191
|
+
runner: 'q chat --no-interactive --trust-all-tools',
|
|
192
|
+
headless: true,
|
|
193
|
+
docsUrl: 'https://docs.aws.amazon.com/amazonq/latest/qdeveloper-ug/command-line-chat.html',
|
|
194
|
+
detect: { bin: 'q', dirs: ['.amazonq'] },
|
|
195
|
+
},
|
|
196
|
+
{
|
|
197
|
+
id: 'droid',
|
|
198
|
+
label: 'Factory Droid CLI',
|
|
199
|
+
entries: [{ path: 'AGENTS.md', content: ROOT_AGENTS_MD }],
|
|
200
|
+
runner: 'droid exec',
|
|
201
|
+
headless: true,
|
|
202
|
+
docsUrl: 'https://docs.factory.ai/droid-exec/overview',
|
|
203
|
+
detect: { bin: 'droid', dirs: ['.factory'] },
|
|
204
|
+
},
|
|
205
|
+
{
|
|
206
|
+
id: 'auggie',
|
|
207
|
+
label: 'Auggie CLI',
|
|
208
|
+
entries: [{ path: 'AGENTS.md', content: ROOT_AGENTS_MD }],
|
|
209
|
+
runner: 'auggie --quiet --print',
|
|
210
|
+
headless: true,
|
|
211
|
+
docsUrl: 'https://docs.augmentcode.com/cli/overview',
|
|
212
|
+
detect: { bin: 'auggie', dirs: ['.augment'] },
|
|
213
|
+
},
|
|
214
|
+
{
|
|
215
|
+
id: 'goose',
|
|
216
|
+
label: 'Goose CLI',
|
|
217
|
+
entries: [{ path: 'AGENTS.md', content: ROOT_AGENTS_MD }], // memory-file convention not confirmed AGENTS.md-native — same harmless-default treatment as amazon-q
|
|
218
|
+
runner: 'goose run -t',
|
|
219
|
+
headless: true,
|
|
220
|
+
docsUrl: 'https://block.github.io/goose/',
|
|
221
|
+
detect: { bin: 'goose', dirs: ['.goose'] },
|
|
121
222
|
},
|
|
122
223
|
];
|
|
123
224
|
|
|
@@ -148,7 +249,7 @@ function defaultRunners(agents) {
|
|
|
148
249
|
const out = {};
|
|
149
250
|
for (const id of agents) {
|
|
150
251
|
const a = byId(id);
|
|
151
|
-
if (a) out[id] = a.runner;
|
|
252
|
+
if (a && a.runner) out[id] = a.runner; // headless:false agents (e.g. kimi) have no runner to seed
|
|
152
253
|
}
|
|
153
254
|
return out;
|
|
154
255
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "spectoflow",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.21.0",
|
|
4
4
|
"description": "Agent-agnostic spec-driven development framework + real-time local control plane. Markdown artifacts, intent router, workflow-by-scope.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"spec-driven-development",
|
package/templates/README.md
CHANGED
|
@@ -28,6 +28,8 @@ sit at the project root and just point back here.
|
|
|
28
28
|
```
|
|
29
29
|
- **See what you got:** `spectoflow list` (agents, skills & workflow at a glance), or `spectoflow
|
|
30
30
|
agents` / `spectoflow skills` / `spectoflow workflow`. Append `-h` to any command for its help.
|
|
31
|
+
(These "agents" are spectoflow's own team personas below, not the coding-agent CLI you're typing
|
|
32
|
+
into — see the dashboard's **Documentation** tab for which coding-agent CLIs spectoflow can drive.)
|
|
31
33
|
- **Change how it runs** in the dashboard's **Personalize** tab (the **active agent**, always shown
|
|
32
34
|
in the topbar too — switching is verified against what's actually installed before it activates —
|
|
33
35
|
plus autonomy mode, output language, and the dashboard **design**), or by editing `config.json`.
|
|
@@ -95,7 +95,8 @@ function setChat(open){
|
|
|
95
95
|
$('#chat').setAttribute('aria-hidden', open?'false':'true');
|
|
96
96
|
$('#chatFab').classList.toggle('is-open',open);
|
|
97
97
|
try{ localStorage.setItem('spf-chat', open?'1':'0'); }catch{}
|
|
98
|
-
|
|
98
|
+
// Land where you can actually type, not wherever the log happened to be scrolled last.
|
|
99
|
+
if(open) setTimeout(()=>{ scrollChat($('#chatLog')); $('#runPrompt').focus(); },60);
|
|
99
100
|
}
|
|
100
101
|
// doRun/doOrchestrate default to the floating widget's textarea/select; the Chat tab has its own
|
|
101
102
|
// #tabRunPrompt/#tabRunAgent (an id can't be shared by two elements) and passes them explicitly —
|
|
@@ -139,11 +140,10 @@ function render(){
|
|
|
139
140
|
// in renderSettings() below (called on every render tick) and saved via saveSettings().
|
|
140
141
|
// agent select — widget (#runAgent) and Chat tab (#tabRunAgent) each get their own populated
|
|
141
142
|
// <select>, since an id can't be shared by two elements; same option list, same source of truth.
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
});
|
|
143
|
+
// Shows every known agent (not just ones already in config.json → runners — a freshly-installed
|
|
144
|
+
// agent works the first time, runner.js falls back to the registry default), disabling any that
|
|
145
|
+
// isn't genuinely installed or can't run headless (e.g. kimi).
|
|
146
|
+
[$('#runAgent'),$('#tabRunAgent')].forEach(sel=>fillAgentSelect(sel,P.knownAgents||[],runnableAgentIds(),c.agent));
|
|
147
147
|
const s=SpectoStats.stats(P);
|
|
148
148
|
const meterFill=$('#globalMeterFill');
|
|
149
149
|
if(meterFill) meterFill.style.width=(s.pct||0)+'%';
|
|
@@ -151,7 +151,7 @@ function render(){
|
|
|
151
151
|
if(meter) meter.title=`${t('kpi.globalProgress')}: ${s.pct}% (${s.done}/${s.total} ${t('kpi.tasksLabel')})`;
|
|
152
152
|
renderOverview(); renderBoard(); renderBacklog(); renderWorkflow(); renderTeam();
|
|
153
153
|
renderChatLog($('#chatLog')); renderChatLog($('#chatTabLog'));
|
|
154
|
-
renderSidebar(); renderRequests(); renderAttention(); renderInfo(); renderSettings();
|
|
154
|
+
renderSidebar(); renderRequests(); renderAttention(); renderInfo(); renderDocs(); renderSettings();
|
|
155
155
|
renderCustomDashboards(); // adds/removes nav tabs + panels before applyActiveTab() below reads them
|
|
156
156
|
applyActiveTab(); // re-apply the current tab so an SSE-driven re-render never resets to Board
|
|
157
157
|
applyI18nStatic(); // re-translate the static markup (nav, headers, placeholders…) for this tick's language
|
|
@@ -264,7 +264,7 @@ function renderOverview(){
|
|
|
264
264
|
|
|
265
265
|
// KPI row
|
|
266
266
|
const kpis=el('div','kpi-row');
|
|
267
|
-
kpis.append(kpiCard(t('kpi.globalProgress'), ring(s.pct,
|
|
267
|
+
kpis.append(kpiCard(t('kpi.globalProgress'), ring(s.pct,52), `${s.done}/${s.total} ${t('kpi.tasksLabel')}`, cssv('--s-done')));
|
|
268
268
|
kpis.append(kpiCard(t('status.in_progress'), numBlock(s.byStatus.in_progress||0,'var(--s-in_progress)'), t('kpi.tasksLabel'), cssv('--s-in_progress')));
|
|
269
269
|
kpis.append(kpiCard(t('status.to_validate'), numBlock(s.byStatus.to_validate||0,'var(--s-to_validate)'), t('kpi.awaitingReview'), cssv('--s-to_validate')));
|
|
270
270
|
const r=s.running||{};
|
|
@@ -717,6 +717,12 @@ function setModeSelects(mode){ [$('#setMode'),$('#topMode')].forEach(s=>{ if(s)
|
|
|
717
717
|
// the user activate an agent that isn't actually installed — options for a not-installed known agent
|
|
718
718
|
// are present but disabled, and P.installedAgents itself comes from the server testing each agent's
|
|
719
719
|
// real CLI (bin on PATH, or the project's own config dir), not a guess.
|
|
720
|
+
// ids that can actually be SPAWNED right now: installed AND headless-capable (a known agent like
|
|
721
|
+
// kimi can be "installed" and even the active agent, but nothing can run it non-interactively).
|
|
722
|
+
function runnableAgentIds(){
|
|
723
|
+
const installed=P.installedAgents||[];
|
|
724
|
+
return (P.knownAgents||[]).filter(a=>a.headless&&installed.includes(a.id)).map(a=>a.id);
|
|
725
|
+
}
|
|
720
726
|
function fillAgentSelect(sel,known,installed,active){
|
|
721
727
|
if(!sel) return;
|
|
722
728
|
const empty=!installed.length;
|
|
@@ -936,9 +942,7 @@ function renderCustomize(){
|
|
|
936
942
|
const form=el('div','cz-form');
|
|
937
943
|
const ta=el('textarea','chat-ta'); ta.placeholder=t('customize.describePh');
|
|
938
944
|
const sel=el('select','chat-agent');
|
|
939
|
-
|
|
940
|
-
runners.forEach((k)=>{ const o=document.createElement('option'); o.value=k; o.textContent=k; sel.append(o); });
|
|
941
|
-
if(P.config&&P.config.agent) sel.value=P.config.agent;
|
|
945
|
+
fillAgentSelect(sel,P.knownAgents||[],runnableAgentIds(),P.config&&P.config.agent);
|
|
942
946
|
const actions=el('div','cz-form-actions');
|
|
943
947
|
const autoBtn=el('button','btn',t('customize.auto'));
|
|
944
948
|
const goBtn=el('button','btn primary',t('customize.generate'));
|
|
@@ -963,7 +967,7 @@ async function czSubmit(kind,description,agent){
|
|
|
963
967
|
// A custom dashboard (Customize page) gets its own tab id "custom:<id>" and its own URL shape
|
|
964
968
|
// /custom/<id> — kept out of ROUTES (a fixed list) since the set of custom ids is dynamic; recognized
|
|
965
969
|
// by a dedicated branch in tabFromPath()/navigateTab() instead.
|
|
966
|
-
const ROUTES=['board','requests','attention','backlog','workflow','team','chat','info','settings'];
|
|
970
|
+
const ROUTES=['board','requests','attention','backlog','workflow','team','chat','info','docs','settings'];
|
|
967
971
|
function tabFromPath(){
|
|
968
972
|
const s=location.pathname.split('/').filter(Boolean);
|
|
969
973
|
if(s[0]==='custom'&&s[1]) return 'custom:'+decodeURIComponent(s[1]);
|
|
@@ -978,6 +982,10 @@ function navigateTab(tabId,push){
|
|
|
978
982
|
}
|
|
979
983
|
applyActiveTab();
|
|
980
984
|
closeNav(); // a tab pick closes the mobile menu
|
|
985
|
+
// Landing on Chat: go straight to where you can read the latest and type, not wherever the log
|
|
986
|
+
// was scrolled to last (only on an actual switch INTO the tab — applyActiveTab() alone runs on
|
|
987
|
+
// every SSE render tick too, and re-scrolling/re-focusing there would fight the user's typing).
|
|
988
|
+
if(tabId==='chat') setTimeout(()=>{ scrollChat($('#chatTabLog')); $('#tabRunPrompt').focus(); },60);
|
|
981
989
|
}
|
|
982
990
|
function closeNav(){ document.body.classList.remove('nav-open'); const nt=$('#navToggle'); if(nt) nt.setAttribute('aria-expanded','false'); }
|
|
983
991
|
|
|
@@ -1038,7 +1046,11 @@ function mdLite(raw){
|
|
|
1038
1046
|
// 2) escape HTML — everything below builds markup only from this escaped text
|
|
1039
1047
|
text=escHtml(text);
|
|
1040
1048
|
// 3) convert a small markdown subset to HTML
|
|
1041
|
-
const inline=s=> s
|
|
1049
|
+
const inline=s=> s
|
|
1050
|
+
.replace(/`([^`]+)`/g,'<code>$1</code>')
|
|
1051
|
+
.replace(/\*\*([^*]+)\*\*/g,'<strong>$1</strong>')
|
|
1052
|
+
.replace(/\[([^\]]+)\]\((https?:\/\/[^\s)]+)\)/g,'<a href="$2" target="_blank" rel="noopener">$1</a>') // [text](url)
|
|
1053
|
+
.replace(/(^|[^"'>])(https?:\/\/[^\s<]+)/g,'$1<a href="$2" target="_blank" rel="noopener">$2</a>'); // bare https://… URLs, skipping ones already inside an href/text we just built
|
|
1042
1054
|
const lines=text.split('\n');
|
|
1043
1055
|
let html='', inCode=false, codeBuf=[], listBuf=[], paraBuf=[];
|
|
1044
1056
|
const flushPara=()=>{ if(paraBuf.length){ html+='<p>'+paraBuf.join(' ')+'</p>'; paraBuf=[]; } };
|
|
@@ -1157,6 +1169,73 @@ function renderInfo(){
|
|
|
1157
1169
|
box.append(infoSection(t('info.workflowLabel'),'workflow',wfList));
|
|
1158
1170
|
}
|
|
1159
1171
|
|
|
1172
|
+
// ---- Documentation tab: which coding agents spectoflow can drive (with links to each one's own
|
|
1173
|
+
// docs, sourced from the same registry the topbar switcher reads) + the CLI command reference.
|
|
1174
|
+
// Never build this table from anything but P.knownAgents/P.installedAgents — that data comes from a
|
|
1175
|
+
// real PATH/config-dir test on the server, never a guess spectoflow hasn't verified. ----
|
|
1176
|
+
function linkEl(text,url){ const a=document.createElement('a'); a.href=url; a.target='_blank'; a.rel='noopener'; a.textContent=text; return a; }
|
|
1177
|
+
function docsAgentsTable(){
|
|
1178
|
+
const known=P.knownAgents||[], installed=P.installedAgents||[];
|
|
1179
|
+
const wrap=el('div','table-scroll'); const tbl=el('table','backlog-table');
|
|
1180
|
+
const thead=el('thead'); const htr=el('tr');
|
|
1181
|
+
[t('docs.colAgent'),t('docs.colStatus'),t('docs.colDocs')].forEach(c=>htr.append(el('th',null,c)));
|
|
1182
|
+
thead.append(htr); tbl.append(thead);
|
|
1183
|
+
const tbody=el('tbody');
|
|
1184
|
+
known.forEach(a=>{
|
|
1185
|
+
const tr=el('tr');
|
|
1186
|
+
tr.append(el('td',null,a.label));
|
|
1187
|
+
const statusTd=el('td');
|
|
1188
|
+
const isInstalled=installed.includes(a.id);
|
|
1189
|
+
const chip=el('span','chip s-'+(isInstalled?'done':'todo'), isInstalled?t('docs.installed'):t('docs.notInstalled'));
|
|
1190
|
+
statusTd.append(chip);
|
|
1191
|
+
if(!a.headless){ statusTd.append(document.createTextNode(' ')); statusTd.append(el('span','docs-manual-badge',t('docs.manualOnly'))); }
|
|
1192
|
+
tr.append(statusTd);
|
|
1193
|
+
const docsTd=el('td');
|
|
1194
|
+
if(a.docsUrl) docsTd.append(linkEl(t('docs.officialDocs'),a.docsUrl));
|
|
1195
|
+
tr.append(docsTd);
|
|
1196
|
+
tbody.append(tr);
|
|
1197
|
+
});
|
|
1198
|
+
tbl.append(tbody); wrap.append(tbl);
|
|
1199
|
+
return wrap;
|
|
1200
|
+
}
|
|
1201
|
+
function docsCommandsTable(){
|
|
1202
|
+
const rows=[
|
|
1203
|
+
['spectoflow init [dir] [--agent=a,b]', t('docs.cmd.init')],
|
|
1204
|
+
['spectoflow update [--dry-run] [--force|-f]', t('docs.cmd.update')],
|
|
1205
|
+
['spectoflow status', t('docs.cmd.status')],
|
|
1206
|
+
['spectoflow dashboard [--port=NNNN]', t('docs.cmd.dashboard')],
|
|
1207
|
+
['spectoflow dashboard status|stop|restart', t('docs.cmd.dashboardSub')],
|
|
1208
|
+
['spectoflow dashboard create "…" | --auto', t('docs.cmd.dashboardCreate')],
|
|
1209
|
+
['spectoflow skill create "…" | --auto', t('docs.cmd.skillCreate')],
|
|
1210
|
+
['spectoflow agent create "…" | --auto', t('docs.cmd.agentCreate')],
|
|
1211
|
+
['spectoflow list', t('docs.cmd.list')],
|
|
1212
|
+
['spectoflow agents · skills · workflow', t('docs.cmd.explore')],
|
|
1213
|
+
];
|
|
1214
|
+
const wrap=el('div','table-scroll'); const tbl=el('table','backlog-table');
|
|
1215
|
+
const thead=el('thead'); const htr=el('tr');
|
|
1216
|
+
[t('docs.colCommand'),t('docs.colWhatItDoes')].forEach(c=>htr.append(el('th',null,c)));
|
|
1217
|
+
thead.append(htr); tbl.append(thead);
|
|
1218
|
+
const tbody=el('tbody');
|
|
1219
|
+
rows.forEach(([cmd,desc])=>{
|
|
1220
|
+
const tr=el('tr');
|
|
1221
|
+
const cmdTd=el('td'); const code=el('code',null,cmd); cmdTd.append(code); tr.append(cmdTd);
|
|
1222
|
+
tr.append(el('td',null,desc));
|
|
1223
|
+
tbody.append(tr);
|
|
1224
|
+
});
|
|
1225
|
+
tbl.append(tbody); wrap.append(tbl);
|
|
1226
|
+
return wrap;
|
|
1227
|
+
}
|
|
1228
|
+
function renderDocs(){
|
|
1229
|
+
const box=$('#docsBody'); if(!box) return;
|
|
1230
|
+
box.innerHTML='';
|
|
1231
|
+
box.append(infoSection(t('docs.agentsTitle'),'agents',docsAgentsTable()));
|
|
1232
|
+
box.append(infoSection(t('docs.commandsTitle'),'run',docsCommandsTable()));
|
|
1233
|
+
const note=el('p','docs-note');
|
|
1234
|
+
note.append(document.createTextNode(t('docs.moreNote')+' '));
|
|
1235
|
+
note.append(linkEl('github.com/georgesmomo/spectoflow','https://github.com/georgesmomo/spectoflow'));
|
|
1236
|
+
box.append(note);
|
|
1237
|
+
}
|
|
1238
|
+
|
|
1160
1239
|
function openDrawer(id,keep){
|
|
1161
1240
|
// named `task`, not `t` — `t` is the global translation function (see i18n.js) and this whole
|
|
1162
1241
|
// function calls it repeatedly below; shadowing it with a task variable would break every call.
|
|
@@ -1297,6 +1376,8 @@ $('#chatClose').addEventListener('click',()=> setChat(false));
|
|
|
1297
1376
|
try{ if(localStorage.getItem('spf-chat')==='1') setChat(true); }catch{}
|
|
1298
1377
|
$('#runBtn').addEventListener('click',()=>doRun());
|
|
1299
1378
|
$('#orchBtn').addEventListener('click',()=>doOrchestrate());
|
|
1379
|
+
$('#widgetSummarizeBtn').addEventListener('click',()=>summarizeChat($('#runAgent')));
|
|
1380
|
+
$('#widgetClearBtn').addEventListener('click',clearChat);
|
|
1300
1381
|
$('#runPrompt').addEventListener('keydown',e=>{ if((e.metaKey||e.ctrlKey)&&e.key==='Enter')doRun(); });
|
|
1301
1382
|
// Chat tab — same doRun/doOrchestrate/approve, its own textarea/select (#tabRunPrompt/#tabRunAgent)
|
|
1302
1383
|
$('#tabRunBtn').addEventListener('click',()=>doRun($('#tabRunPrompt'),$('#tabRunAgent')));
|
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
const I18N = {
|
|
21
21
|
en: {
|
|
22
22
|
'nav.board':'Board','nav.requests':'Requests','nav.attention':'Attention','nav.backlog':'Backlog',
|
|
23
|
-
'nav.workflow':'Workflow','nav.team':'Agents & Skills','nav.chat':'Chat','nav.info':'Info','nav.settings':'Personalize',
|
|
23
|
+
'nav.workflow':'Workflow','nav.team':'Agents & Skills','nav.chat':'Chat','nav.info':'Info','nav.docs':'Documentation','nav.settings':'Personalize',
|
|
24
24
|
'status.todo':'To do','status.in_progress':'In progress','status.to_validate':'To validate',
|
|
25
25
|
'status.to_analyze':'To analyze','status.done':'Done','status.blocked':'Blocked',
|
|
26
26
|
'filter.all':'All','filter.open':'Open','filter.resolved':'Resolved',
|
|
@@ -114,10 +114,25 @@ en: {
|
|
|
114
114
|
'customize.add.dashboard':'Add dashboard','customize.add.skill':'Add skill','customize.add.agent':'Add agent',
|
|
115
115
|
'customize.empty.dashboard':'No custom dashboards yet.','customize.empty.skill':'No custom skills yet.','customize.empty.agent':'No custom agents yet.',
|
|
116
116
|
'customize.describePh':'Describe what you want…','customize.auto':'Auto','customize.generate':'Generate','customize.blocksSub':'block(s)',
|
|
117
|
+
'docs.title':'Documentation','docs.sub':'Which coding agents spectoflow can drive, and the commands that drive them.',
|
|
118
|
+
'docs.agentsTitle':'Supported agents','docs.commandsTitle':'Commands',
|
|
119
|
+
'docs.colAgent':'Agent','docs.colStatus':'Status','docs.colDocs':'Docs','docs.colCommand':'Command','docs.colWhatItDoes':'What it does',
|
|
120
|
+
'docs.installed':'Installed','docs.notInstalled':'Not installed','docs.manualOnly':'Manual only','docs.officialDocs':'Official docs ↗',
|
|
121
|
+
'docs.moreNote':'Full reference, source and license on GitHub:',
|
|
122
|
+
'docs.cmd.init':'Scaffold a project (auto-detects agents; wires Playwright MCP).',
|
|
123
|
+
'docs.cmd.update':'Refresh framework files to this kit version, preserving your work.',
|
|
124
|
+
'docs.cmd.status':'Progress + whether the dashboard is running.',
|
|
125
|
+
'docs.cmd.dashboard':'Start the control plane in the background.',
|
|
126
|
+
'docs.cmd.dashboardSub':'Check, stop, or restart the running dashboard.',
|
|
127
|
+
'docs.cmd.dashboardCreate':'Generate a custom dashboard from the terminal.',
|
|
128
|
+
'docs.cmd.skillCreate':'Generate a project-specific skill from the terminal.',
|
|
129
|
+
'docs.cmd.agentCreate':'Generate a project-specific agent persona from the terminal.',
|
|
130
|
+
'docs.cmd.list':'Agents, skills and the workflow at a glance.',
|
|
131
|
+
'docs.cmd.explore':'List the team personas, the procedures, or the pipeline steps.',
|
|
117
132
|
},
|
|
118
133
|
fr: {
|
|
119
134
|
'nav.board':'Tableau','nav.requests':'Demandes','nav.attention':'Attention','nav.backlog':'Backlog',
|
|
120
|
-
'nav.workflow':'Workflow','nav.team':'Agents et compétences','nav.chat':'Chat','nav.info':'Infos','nav.settings':'Personnalisation',
|
|
135
|
+
'nav.workflow':'Workflow','nav.team':'Agents et compétences','nav.chat':'Chat','nav.info':'Infos','nav.docs':'Documentation','nav.settings':'Personnalisation',
|
|
121
136
|
'status.todo':'À faire','status.in_progress':'En cours','status.to_validate':'À valider',
|
|
122
137
|
'status.to_analyze':'À analyser','status.done':'Terminé','status.blocked':'Bloqué',
|
|
123
138
|
'filter.all':'Tous','filter.open':'Ouverts','filter.resolved':'Résolus',
|
|
@@ -211,10 +226,25 @@ fr: {
|
|
|
211
226
|
'customize.add.dashboard':'Ajouter un dashboard','customize.add.skill':'Ajouter une compétence','customize.add.agent':'Ajouter un agent',
|
|
212
227
|
'customize.empty.dashboard':'Aucun dashboard personnalisé pour l’instant.','customize.empty.skill':'Aucune compétence personnalisée pour l’instant.','customize.empty.agent':'Aucun agent personnalisé pour l’instant.',
|
|
213
228
|
'customize.describePh':'Décrivez ce que vous voulez…','customize.auto':'Auto','customize.generate':'Générer','customize.blocksSub':'bloc(s)',
|
|
229
|
+
'docs.title':'Documentation','docs.sub':'Les agents de code que spectoflow peut piloter, et les commandes qui les pilotent.',
|
|
230
|
+
'docs.agentsTitle':'Agents pris en charge','docs.commandsTitle':'Commandes',
|
|
231
|
+
'docs.colAgent':'Agent','docs.colStatus':'Statut','docs.colDocs':'Docs','docs.colCommand':'Commande','docs.colWhatItDoes':'Ce que ça fait',
|
|
232
|
+
'docs.installed':'Installé','docs.notInstalled':'Non installé','docs.manualOnly':'Manuel uniquement','docs.officialDocs':'Doc officielle ↗',
|
|
233
|
+
'docs.moreNote':'Référence complète, source et licence sur GitHub :',
|
|
234
|
+
'docs.cmd.init':'Initialise un projet (détecte les agents automatiquement ; câble Playwright MCP).',
|
|
235
|
+
'docs.cmd.update':'Met à jour les fichiers du framework vers cette version, en préservant vos modifications.',
|
|
236
|
+
'docs.cmd.status':'Progression + si le dashboard tourne.',
|
|
237
|
+
'docs.cmd.dashboard':'Démarre le plan de contrôle en arrière-plan.',
|
|
238
|
+
'docs.cmd.dashboardSub':'Vérifie, arrête ou redémarre le dashboard en cours.',
|
|
239
|
+
'docs.cmd.dashboardCreate':'Génère un dashboard personnalisé depuis le terminal.',
|
|
240
|
+
'docs.cmd.skillCreate':'Génère une compétence propre au projet depuis le terminal.',
|
|
241
|
+
'docs.cmd.agentCreate':'Génère un agent (persona) propre au projet depuis le terminal.',
|
|
242
|
+
'docs.cmd.list':'Agents, compétences et workflow en un coup d’œil.',
|
|
243
|
+
'docs.cmd.explore':'Liste les personas de l’équipe, les procédures ou les étapes du pipeline.',
|
|
214
244
|
},
|
|
215
245
|
es: {
|
|
216
246
|
'nav.board':'Tablero','nav.requests':'Solicitudes','nav.attention':'Atención','nav.backlog':'Backlog',
|
|
217
|
-
'nav.workflow':'Workflow','nav.team':'Agentes y habilidades','nav.chat':'Chat','nav.info':'Info','nav.settings':'Personalizar',
|
|
247
|
+
'nav.workflow':'Workflow','nav.team':'Agentes y habilidades','nav.chat':'Chat','nav.info':'Info','nav.docs':'Documentación','nav.settings':'Personalizar',
|
|
218
248
|
'status.todo':'Por hacer','status.in_progress':'En curso','status.to_validate':'Por validar',
|
|
219
249
|
'status.to_analyze':'Por analizar','status.done':'Hecho','status.blocked':'Bloqueado',
|
|
220
250
|
'filter.all':'Todos','filter.open':'Abiertos','filter.resolved':'Resueltos',
|
|
@@ -308,10 +338,25 @@ es: {
|
|
|
308
338
|
'customize.add.dashboard':'Añadir dashboard','customize.add.skill':'Añadir habilidad','customize.add.agent':'Añadir agente',
|
|
309
339
|
'customize.empty.dashboard':'Aún no hay dashboards personalizados.','customize.empty.skill':'Aún no hay habilidades personalizadas.','customize.empty.agent':'Aún no hay agentes personalizados.',
|
|
310
340
|
'customize.describePh':'Describe lo que quieres…','customize.auto':'Auto','customize.generate':'Generar','customize.blocksSub':'bloque(s)',
|
|
341
|
+
'docs.title':'Documentación','docs.sub':'Qué agentes de código puede pilotar spectoflow, y los comandos que los pilotan.',
|
|
342
|
+
'docs.agentsTitle':'Agentes compatibles','docs.commandsTitle':'Comandos',
|
|
343
|
+
'docs.colAgent':'Agente','docs.colStatus':'Estado','docs.colDocs':'Docs','docs.colCommand':'Comando','docs.colWhatItDoes':'Qué hace',
|
|
344
|
+
'docs.installed':'Instalado','docs.notInstalled':'No instalado','docs.manualOnly':'Solo manual','docs.officialDocs':'Docs oficial ↗',
|
|
345
|
+
'docs.moreNote':'Referencia completa, código fuente y licencia en GitHub:',
|
|
346
|
+
'docs.cmd.init':'Crea un proyecto (detecta agentes automáticamente; conecta Playwright MCP).',
|
|
347
|
+
'docs.cmd.update':'Actualiza los archivos del framework a esta versión, preservando tu trabajo.',
|
|
348
|
+
'docs.cmd.status':'Progreso + si el dashboard está en ejecución.',
|
|
349
|
+
'docs.cmd.dashboard':'Inicia el panel de control en segundo plano.',
|
|
350
|
+
'docs.cmd.dashboardSub':'Consulta, detiene o reinicia el dashboard en ejecución.',
|
|
351
|
+
'docs.cmd.dashboardCreate':'Genera un dashboard personalizado desde la terminal.',
|
|
352
|
+
'docs.cmd.skillCreate':'Genera una habilidad propia del proyecto desde la terminal.',
|
|
353
|
+
'docs.cmd.agentCreate':'Genera un agente (persona) propio del proyecto desde la terminal.',
|
|
354
|
+
'docs.cmd.list':'Agentes, habilidades y workflow de un vistazo.',
|
|
355
|
+
'docs.cmd.explore':'Lista los personas del equipo, los procedimientos o los pasos del pipeline.',
|
|
311
356
|
},
|
|
312
357
|
de: {
|
|
313
358
|
'nav.board':'Board','nav.requests':'Anfragen','nav.attention':'Hinweise','nav.backlog':'Backlog',
|
|
314
|
-
'nav.workflow':'Workflow','nav.team':'Agenten & Skills','nav.chat':'Chat','nav.info':'Info','nav.settings':'Personalisieren',
|
|
359
|
+
'nav.workflow':'Workflow','nav.team':'Agenten & Skills','nav.chat':'Chat','nav.info':'Info','nav.docs':'Dokumentation','nav.settings':'Personalisieren',
|
|
315
360
|
'status.todo':'Offen','status.in_progress':'In Arbeit','status.to_validate':'Zu prüfen',
|
|
316
361
|
'status.to_analyze':'Zu analysieren','status.done':'Erledigt','status.blocked':'Blockiert',
|
|
317
362
|
'filter.all':'Alle','filter.open':'Offen','filter.resolved':'Erledigt',
|
|
@@ -405,10 +450,25 @@ de: {
|
|
|
405
450
|
'customize.add.dashboard':'Dashboard hinzufügen','customize.add.skill':'Skill hinzufügen','customize.add.agent':'Agent hinzufügen',
|
|
406
451
|
'customize.empty.dashboard':'Noch keine eigenen Dashboards.','customize.empty.skill':'Noch keine eigenen Skills.','customize.empty.agent':'Noch keine eigenen Agenten.',
|
|
407
452
|
'customize.describePh':'Beschreiben Sie, was Sie wollen…','customize.auto':'Auto','customize.generate':'Generieren','customize.blocksSub':'Block/Blöcke',
|
|
453
|
+
'docs.title':'Dokumentation','docs.sub':'Welche Coding-Agenten spectoflow steuern kann, und die Befehle dafür.',
|
|
454
|
+
'docs.agentsTitle':'Unterstützte Agenten','docs.commandsTitle':'Befehle',
|
|
455
|
+
'docs.colAgent':'Agent','docs.colStatus':'Status','docs.colDocs':'Docs','docs.colCommand':'Befehl','docs.colWhatItDoes':'Was er macht',
|
|
456
|
+
'docs.installed':'Installiert','docs.notInstalled':'Nicht installiert','docs.manualOnly':'Nur manuell','docs.officialDocs':'Offizielle Docs ↗',
|
|
457
|
+
'docs.moreNote':'Vollständige Referenz, Quellcode und Lizenz auf GitHub:',
|
|
458
|
+
'docs.cmd.init':'Projekt aufsetzen (erkennt Agenten automatisch; verdrahtet Playwright MCP).',
|
|
459
|
+
'docs.cmd.update':'Framework-Dateien auf diese Version aktualisieren, eigene Änderungen bleiben erhalten.',
|
|
460
|
+
'docs.cmd.status':'Fortschritt + ob das Dashboard läuft.',
|
|
461
|
+
'docs.cmd.dashboard':'Startet die Kontrollzentrale im Hintergrund.',
|
|
462
|
+
'docs.cmd.dashboardSub':'Prüft, stoppt oder startet das laufende Dashboard neu.',
|
|
463
|
+
'docs.cmd.dashboardCreate':'Erzeugt ein individuelles Dashboard über das Terminal.',
|
|
464
|
+
'docs.cmd.skillCreate':'Erzeugt einen projektspezifischen Skill über das Terminal.',
|
|
465
|
+
'docs.cmd.agentCreate':'Erzeugt eine projektspezifische Agenten-Persona über das Terminal.',
|
|
466
|
+
'docs.cmd.list':'Agenten, Skills und Workflow auf einen Blick.',
|
|
467
|
+
'docs.cmd.explore':'Listet die Team-Personas, die Verfahren oder die Pipeline-Schritte.',
|
|
408
468
|
},
|
|
409
469
|
pt: {
|
|
410
470
|
'nav.board':'Painel','nav.requests':'Pedidos','nav.attention':'Atenção','nav.backlog':'Backlog',
|
|
411
|
-
'nav.workflow':'Workflow','nav.team':'Agentes e habilidades','nav.chat':'Chat','nav.info':'Info','nav.settings':'Personalizar',
|
|
471
|
+
'nav.workflow':'Workflow','nav.team':'Agentes e habilidades','nav.chat':'Chat','nav.info':'Info','nav.docs':'Documentação','nav.settings':'Personalizar',
|
|
412
472
|
'status.todo':'A fazer','status.in_progress':'Em curso','status.to_validate':'Por validar',
|
|
413
473
|
'status.to_analyze':'Por analisar','status.done':'Concluído','status.blocked':'Bloqueado',
|
|
414
474
|
'filter.all':'Todos','filter.open':'Abertos','filter.resolved':'Resolvidos',
|
|
@@ -502,10 +562,25 @@ pt: {
|
|
|
502
562
|
'customize.add.dashboard':'Adicionar dashboard','customize.add.skill':'Adicionar habilidade','customize.add.agent':'Adicionar agente',
|
|
503
563
|
'customize.empty.dashboard':'Ainda sem dashboards personalizados.','customize.empty.skill':'Ainda sem habilidades personalizadas.','customize.empty.agent':'Ainda sem agentes personalizados.',
|
|
504
564
|
'customize.describePh':'Descreva o que quer…','customize.auto':'Auto','customize.generate':'Gerar','customize.blocksSub':'bloco(s)',
|
|
565
|
+
'docs.title':'Documentação','docs.sub':'Quais agentes de código o spectoflow consegue conduzir, e os comandos que os conduzem.',
|
|
566
|
+
'docs.agentsTitle':'Agentes suportados','docs.commandsTitle':'Comandos',
|
|
567
|
+
'docs.colAgent':'Agente','docs.colStatus':'Estado','docs.colDocs':'Docs','docs.colCommand':'Comando','docs.colWhatItDoes':'O que faz',
|
|
568
|
+
'docs.installed':'Instalado','docs.notInstalled':'Não instalado','docs.manualOnly':'Só manual','docs.officialDocs':'Docs oficial ↗',
|
|
569
|
+
'docs.moreNote':'Referência completa, código-fonte e licença no GitHub:',
|
|
570
|
+
'docs.cmd.init':'Cria um projeto (deteta agentes automaticamente; liga o Playwright MCP).',
|
|
571
|
+
'docs.cmd.update':'Atualiza os ficheiros do framework para esta versão, preservando o seu trabalho.',
|
|
572
|
+
'docs.cmd.status':'Progresso + se o dashboard está em execução.',
|
|
573
|
+
'docs.cmd.dashboard':'Inicia o painel de controlo em segundo plano.',
|
|
574
|
+
'docs.cmd.dashboardSub':'Verifica, para ou reinicia o dashboard em execução.',
|
|
575
|
+
'docs.cmd.dashboardCreate':'Gera um dashboard personalizado a partir do terminal.',
|
|
576
|
+
'docs.cmd.skillCreate':'Gera uma competência própria do projeto a partir do terminal.',
|
|
577
|
+
'docs.cmd.agentCreate':'Gera um agente (persona) próprio do projeto a partir do terminal.',
|
|
578
|
+
'docs.cmd.list':'Agentes, competências e workflow de relance.',
|
|
579
|
+
'docs.cmd.explore':'Lista os personas da equipa, os procedimentos ou os passos do pipeline.',
|
|
505
580
|
},
|
|
506
581
|
it: {
|
|
507
582
|
'nav.board':'Bacheca','nav.requests':'Richieste','nav.attention':'Attenzione','nav.backlog':'Backlog',
|
|
508
|
-
'nav.workflow':'Workflow','nav.team':'Agenti e competenze','nav.chat':'Chat','nav.info':'Info','nav.settings':'Personalizza',
|
|
583
|
+
'nav.workflow':'Workflow','nav.team':'Agenti e competenze','nav.chat':'Chat','nav.info':'Info','nav.docs':'Documentazione','nav.settings':'Personalizza',
|
|
509
584
|
'status.todo':'Da fare','status.in_progress':'In corso','status.to_validate':'Da convalidare',
|
|
510
585
|
'status.to_analyze':'Da analizzare','status.done':'Fatto','status.blocked':'Bloccato',
|
|
511
586
|
'filter.all':'Tutti','filter.open':'Aperti','filter.resolved':'Risolti',
|
|
@@ -599,6 +674,21 @@ it: {
|
|
|
599
674
|
'customize.add.dashboard':'Aggiungi dashboard','customize.add.skill':'Aggiungi skill','customize.add.agent':'Aggiungi agente',
|
|
600
675
|
'customize.empty.dashboard':'Ancora nessuna dashboard personalizzata.','customize.empty.skill':'Ancora nessuna skill personalizzata.','customize.empty.agent':'Ancora nessun agente personalizzato.',
|
|
601
676
|
'customize.describePh':'Descrivi cosa vuoi…','customize.auto':'Auto','customize.generate':'Genera','customize.blocksSub':'blocco/i',
|
|
677
|
+
'docs.title':'Documentazione','docs.sub':'Quali agenti di codice spectoflow può guidare, e i comandi che li guidano.',
|
|
678
|
+
'docs.agentsTitle':'Agenti supportati','docs.commandsTitle':'Comandi',
|
|
679
|
+
'docs.colAgent':'Agente','docs.colStatus':'Stato','docs.colDocs':'Docs','docs.colCommand':'Comando','docs.colWhatItDoes':'Cosa fa',
|
|
680
|
+
'docs.installed':'Installato','docs.notInstalled':'Non installato','docs.manualOnly':'Solo manuale','docs.officialDocs':'Docs ufficiale ↗',
|
|
681
|
+
'docs.moreNote':'Riferimento completo, codice sorgente e licenza su GitHub:',
|
|
682
|
+
'docs.cmd.init':'Crea un progetto (rileva gli agenti automaticamente; collega Playwright MCP).',
|
|
683
|
+
'docs.cmd.update':'Aggiorna i file del framework a questa versione, preservando il tuo lavoro.',
|
|
684
|
+
'docs.cmd.status':'Avanzamento + se il dashboard è in esecuzione.',
|
|
685
|
+
'docs.cmd.dashboard':'Avvia il pannello di controllo in background.',
|
|
686
|
+
'docs.cmd.dashboardSub':'Controlla, ferma o riavvia il dashboard in esecuzione.',
|
|
687
|
+
'docs.cmd.dashboardCreate':'Genera una dashboard personalizzata dal terminale.',
|
|
688
|
+
'docs.cmd.skillCreate':'Genera una skill specifica del progetto dal terminale.',
|
|
689
|
+
'docs.cmd.agentCreate':'Genera un agente (persona) specifico del progetto dal terminale.',
|
|
690
|
+
'docs.cmd.list':'Agenti, skill e workflow a colpo d’occhio.',
|
|
691
|
+
'docs.cmd.explore':'Elenca le persona del team, le procedure o i passaggi della pipeline.',
|
|
602
692
|
},
|
|
603
693
|
};
|
|
604
694
|
|
|
@@ -25,6 +25,8 @@
|
|
|
25
25
|
attention: wrap('<line x1="4.5" y1="2.4" x2="4.5" y2="15.6"/><path d="M4.5 3.4h8.2l-1.7 2.6 1.7 2.6H4.5z"/>'),
|
|
26
26
|
// gear — settings (proper cog with teeth)
|
|
27
27
|
settings: wrap('<circle cx="9" cy="9" r="2.4"/><path d="M9 1.6v2.2M9 14.2v2.2M16.4 9h-2.2M3.8 9H1.6M14.2 3.8l-1.55 1.55M5.35 12.65 3.8 14.2M14.2 14.2l-1.55-1.55M5.35 5.35 3.8 3.8"/>'),
|
|
28
|
+
// open book — documentation
|
|
29
|
+
docs: wrap('<path d="M9 5.4C7.4 4.2 5.2 3.7 2.8 4v9c2.4-.3 4.6.2 6.2 1.4 1.6-1.2 3.8-1.7 6.2-1.4V4c-2.4-.3-4.6.2-6.2 1.4z"/><line x1="9" y1="5.4" x2="9" y2="14.4"/>'),
|
|
28
30
|
// crescent moon — theme toggle
|
|
29
31
|
theme: wrap('<path d="M14.6 10.8A5.6 5.6 0 0 1 7.2 3.4 5.7 5.7 0 1 0 14.6 10.8z"/>'),
|
|
30
32
|
};
|
|
@@ -57,6 +57,7 @@
|
|
|
57
57
|
<button class="tab" data-tab="workflow" data-i18n-title="nav.workflow" title="Workflow"><span class="tab-ico" data-icon="workflow"></span><span class="tab-label" data-i18n="nav.workflow">Workflow</span></button>
|
|
58
58
|
<button class="tab" data-tab="team" data-i18n-title="nav.team" title="Agents & Skills"><span class="tab-ico" data-icon="agents"></span><span class="tab-label" data-i18n="nav.team">Agents & Skills</span></button>
|
|
59
59
|
<button class="tab" data-tab="info" data-i18n-title="nav.info" title="Info"><span class="tab-ico" data-icon="info"></span><span class="tab-label" data-i18n="nav.info">Info</span></button>
|
|
60
|
+
<button class="tab" data-tab="docs" data-i18n-title="nav.docs" title="Documentation"><span class="tab-ico" data-icon="docs"></span><span class="tab-label" data-i18n="nav.docs">Documentation</span></button>
|
|
60
61
|
<button class="tab" data-tab="settings" data-i18n-title="nav.settings" title="Personalize"><span class="tab-ico" data-icon="settings"></span><span class="tab-label" data-i18n="nav.settings">Personalize</span></button>
|
|
61
62
|
</nav>
|
|
62
63
|
<div class="top-right">
|
|
@@ -201,16 +202,18 @@
|
|
|
201
202
|
<h2 class="panel-title" data-i18n="nav.chat">Chat</h2>
|
|
202
203
|
<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>
|
|
203
204
|
</div>
|
|
204
|
-
<div class="chat-tab-head-actions">
|
|
205
|
-
<button id="tabSummarizeBtn" class="mini-btn" data-i18n-title="chat.summarizeTitle" data-i18n="action.summarize" title="Condense the recent activity into a summary">Summarize</button>
|
|
206
|
-
<button id="tabClearBtn" class="mini-btn" data-i18n-title="chat.clearTitle" data-i18n="action.clear" title="Clear the chat log">Clear</button>
|
|
207
|
-
<select id="tabRunAgent" class="chat-agent" title="Agent"></select>
|
|
208
|
-
</div>
|
|
209
205
|
</div>
|
|
210
206
|
<div class="chat-tab-log" id="chatTabLog">
|
|
211
207
|
<div class="chat-idle" data-i18n-html="chat.idle">Type a request — the agent runs headless in this project with full memory
|
|
212
208
|
(<code>CLAUDE.md → AGENTS.md</code>) and updates the board live.</div>
|
|
213
209
|
</div>
|
|
210
|
+
<!-- Toolbar right above the input, not up in the header — this is where you're looking
|
|
211
|
+
when you reach for Summarize/Clear or switch which agent the next message runs on. -->
|
|
212
|
+
<div class="chat-tab-toolbar">
|
|
213
|
+
<button id="tabSummarizeBtn" class="mini-btn" data-i18n-title="chat.summarizeTitle" data-i18n="action.summarize" title="Condense the recent activity into a summary">Summarize</button>
|
|
214
|
+
<button id="tabClearBtn" class="mini-btn" data-i18n-title="chat.clearTitle" data-i18n="action.clear" title="Clear the chat log">Clear</button>
|
|
215
|
+
<select id="tabRunAgent" class="chat-agent" title="Agent"></select>
|
|
216
|
+
</div>
|
|
214
217
|
<div class="chat-tab-input">
|
|
215
218
|
<textarea id="tabRunPrompt" class="chat-ta" data-i18n-ph="chat.inputPlaceholder" placeholder="e.g. Add a login feature with email + password"></textarea>
|
|
216
219
|
<div class="chat-tab-actions">
|
|
@@ -231,6 +234,15 @@
|
|
|
231
234
|
</div>
|
|
232
235
|
</section>
|
|
233
236
|
|
|
237
|
+
<!-- DOCUMENTATION (agent compatibility + CLI command reference — filled by renderDocs() in app.js) -->
|
|
238
|
+
<section class="panel" data-panel="docs">
|
|
239
|
+
<div class="info-wrap">
|
|
240
|
+
<h2 class="panel-title" data-i18n="docs.title">Documentation</h2>
|
|
241
|
+
<p class="panel-sub" data-i18n="docs.sub">Which coding agents spectoflow can drive, and the commands that drive them.</p>
|
|
242
|
+
<div class="info-grid docs-grid" id="docsBody"></div>
|
|
243
|
+
</div>
|
|
244
|
+
</section>
|
|
245
|
+
|
|
234
246
|
<!-- SETTINGS (change autonomy mode + output language → config.json) -->
|
|
235
247
|
<section class="panel" data-panel="settings">
|
|
236
248
|
<div class="settings-wrap">
|
|
@@ -306,13 +318,17 @@
|
|
|
306
318
|
<span class="chat-title" data-i18n="chat.widgetTitle">Run an agent</span>
|
|
307
319
|
<span class="chat-sub" data-i18n="chat.widgetSub">Quick access · full view in the Chat tab</span>
|
|
308
320
|
</div>
|
|
309
|
-
<select id="runAgent" class="chat-agent" title="Agent"></select>
|
|
310
321
|
<button class="chat-close" id="chatClose" aria-label="Close">×</button>
|
|
311
322
|
</div>
|
|
312
323
|
<div class="chat-log" id="chatLog">
|
|
313
324
|
<div class="chat-idle" data-i18n-html="chat.idle">Type a request — the agent runs headless in this project with full memory
|
|
314
325
|
(<code>CLAUDE.md → AGENTS.md</code>) and updates the board live.</div>
|
|
315
326
|
</div>
|
|
327
|
+
<div class="chat-toolbar">
|
|
328
|
+
<button id="widgetSummarizeBtn" class="mini-btn" data-i18n-title="chat.summarizeTitle" data-i18n="action.summarize" title="Condense the recent activity into a summary">Summarize</button>
|
|
329
|
+
<button id="widgetClearBtn" class="mini-btn" data-i18n-title="chat.clearTitle" data-i18n="action.clear" title="Clear the chat log">Clear</button>
|
|
330
|
+
<select id="runAgent" class="chat-agent" title="Agent"></select>
|
|
331
|
+
</div>
|
|
316
332
|
<div class="chat-input">
|
|
317
333
|
<textarea id="runPrompt" class="chat-ta" data-i18n-ph="chat.inputPlaceholder" placeholder="e.g. Add a login feature with email + password"></textarea>
|
|
318
334
|
<button id="runBtn" class="btn primary chat-send" data-i18n="action.send">Send</button>
|
|
@@ -97,17 +97,17 @@ body { background:var(--bg); color:var(--ink); font-family:var(--sans); font-siz
|
|
|
97
97
|
|
|
98
98
|
/* overview: KPI cards + status donut + workflow strip + phase bars */
|
|
99
99
|
.overview { padding:22px 24px 6px; display:flex; flex-direction:column; gap:14px; }
|
|
100
|
-
.kpi-row { display:grid; grid-template-columns:repeat(4,1fr); gap:
|
|
101
|
-
.kpi { background:var(--surface); border:1px solid var(--line); border-radius:var(--radius); padding:
|
|
100
|
+
.kpi-row { display:grid; grid-template-columns:repeat(4,1fr); gap:9px; }
|
|
101
|
+
.kpi { background:var(--surface); border:1px solid var(--line); border-radius:var(--radius); padding:10px 13px; display:flex; flex-direction:column; gap:4px; transition:box-shadow .15s; }
|
|
102
102
|
.kpi:hover { box-shadow:var(--shadow); }
|
|
103
|
-
.kpi-label { font-size:
|
|
103
|
+
.kpi-label { font-size:10px; text-transform:uppercase; letter-spacing:.07em; color:var(--faint); font-weight:700; }
|
|
104
104
|
.kpi-body { display:flex; align-items:center; }
|
|
105
|
-
.kpi-num { font-family:var(--mono); font-size:
|
|
106
|
-
.kpi-num.is-text { font-size:
|
|
107
|
-
.kpi-sub { font-size:
|
|
105
|
+
.kpi-num { font-family:var(--mono); font-size:23px; font-weight:700; line-height:1; color:var(--ink); }
|
|
106
|
+
.kpi-num.is-text { font-size:14px; text-transform:capitalize; }
|
|
107
|
+
.kpi-sub { font-size:10.5px; color:var(--muted); }
|
|
108
108
|
|
|
109
109
|
.ring-wrap { position:relative; display:inline-flex; align-items:center; justify-content:center; }
|
|
110
|
-
.ring-wrap .ring-label { position:absolute; font-family:var(--mono); font-size:
|
|
110
|
+
.ring-wrap .ring-label { position:absolute; font-family:var(--mono); font-size:10.5px; font-weight:700; color:var(--ink); }
|
|
111
111
|
.ring-svg circle { transition:stroke-dashoffset .5s ease; }
|
|
112
112
|
|
|
113
113
|
.ocard { background:var(--surface); border:1px solid var(--line); border-radius:var(--radius); padding:16px 18px; }
|
|
@@ -378,7 +378,8 @@ body { background:var(--bg); color:var(--ink); font-family:var(--sans); font-siz
|
|
|
378
378
|
.chat-title { font-weight:700; font-size:15px; }
|
|
379
379
|
.chat-sub { font-size:10px; color:var(--faint); text-transform:uppercase; letter-spacing:.04em; }
|
|
380
380
|
.chat-agent { margin-left:auto; flex-shrink:0; font:inherit; font-size:12px; background:var(--surface); color:var(--ink); border:1px solid var(--line); border-radius:7px; padding:5px 8px; }
|
|
381
|
-
.chat-
|
|
381
|
+
.chat-toolbar { display:flex; align-items:center; gap:8px; padding:8px 14px; border-top:1px solid var(--line); flex-wrap:wrap; }
|
|
382
|
+
.chat-close { width:28px; height:28px; flex-shrink:0; margin-left:auto; border:1px solid var(--line); background:var(--surface-2); color:var(--muted); border-radius:8px; font-size:17px; cursor:pointer; transition:border-color .15s,color .15s; }
|
|
382
383
|
.chat-close:hover { border-color:color-mix(in srgb,var(--s-blocked) 45%,var(--line)); color:var(--ink); }
|
|
383
384
|
.chat-log { flex:1; overflow-y:auto; padding:16px; display:flex; flex-direction:column; gap:11px; }
|
|
384
385
|
.chat-idle { color:var(--faint); font-style:italic; font-size:12.5px; }
|
|
@@ -414,10 +415,10 @@ body { background:var(--bg); color:var(--ink); font-family:var(--sans); font-siz
|
|
|
414
415
|
.chat-tab-head { display:flex; align-items:flex-start; gap:14px; margin-bottom:14px; }
|
|
415
416
|
.chat-tab-head .panel-title { margin:0; }
|
|
416
417
|
.chat-tab-head .panel-sub { margin:2px 0 0; }
|
|
417
|
-
.chat-tab-head-actions { display:flex; align-items:center; gap:8px; margin-left:auto; flex-shrink:0; flex-wrap:wrap; }
|
|
418
|
-
.chat-tab-head .chat-agent { flex-shrink:0; }
|
|
419
418
|
.chat-tab-log { flex:1; min-height:220px; overflow-y:auto; display:flex; flex-direction:column; gap:12px; background:var(--surface); border:1px solid var(--line); border-radius:var(--radius); padding:20px; box-shadow:var(--shadow); }
|
|
420
|
-
.chat-tab-
|
|
419
|
+
.chat-tab-toolbar { display:flex; align-items:center; gap:8px; margin-top:10px; flex-wrap:wrap; }
|
|
420
|
+
.chat-tab-toolbar .chat-agent { margin-left:auto; flex-shrink:0; }
|
|
421
|
+
.chat-tab-input { display:flex; gap:10px; margin-top:10px; }
|
|
421
422
|
.chat-tab-input .chat-ta { flex:1; min-height:56px; max-height:180px; }
|
|
422
423
|
.chat-tab-actions { display:flex; flex-direction:column; gap:8px; flex-shrink:0; }
|
|
423
424
|
.chat-tab-wrap .chat-warn { margin:8px 0 0; }
|
|
@@ -555,6 +556,14 @@ body.booting .ring-svg circle:last-of-type { transform-origin:center; animation:
|
|
|
555
556
|
.settings-select:focus { outline:2px solid var(--signal); outline-offset:1px; }
|
|
556
557
|
.settings-field-hint { font-size:12px; }
|
|
557
558
|
.settings-field-hint.is-empty { color:var(--s-blocked); }
|
|
559
|
+
.docs-grid { grid-template-columns:1fr; } /* the built-in tables are wide — full width beats 2-up */
|
|
560
|
+
.docs-grid .backlog-table a { color:var(--signal); text-decoration:none; }
|
|
561
|
+
.docs-grid .backlog-table a:hover { text-decoration:underline; }
|
|
562
|
+
.docs-grid .backlog-table code { font-family:var(--mono); font-size:12px; }
|
|
563
|
+
.docs-manual-badge { font-size:10px; text-transform:uppercase; letter-spacing:.05em; color:var(--muted); border:1px solid var(--line); border-radius:999px; padding:2px 7px; }
|
|
564
|
+
.docs-note { margin:14px 2px 0; font-size:12.5px; color:var(--muted); }
|
|
565
|
+
.docs-note a { color:var(--signal); text-decoration:none; }
|
|
566
|
+
.docs-note a:hover { text-decoration:underline; }
|
|
558
567
|
.settings-saved { align-self:flex-start; font-size:12px; color:var(--s-done); font-family:var(--mono); }
|
|
559
568
|
.settings-saved[hidden] { display:none; }
|
|
560
569
|
.settings-readonly { background:var(--surface); border:1px solid var(--line); border-radius:var(--radius); overflow:hidden; }
|
|
@@ -9,6 +9,18 @@
|
|
|
9
9
|
*/
|
|
10
10
|
const { spawn } = require('child_process');
|
|
11
11
|
const store = require('../lib/store');
|
|
12
|
+
const agentsRegistry = require('../lib/agents-registry');
|
|
13
|
+
|
|
14
|
+
// The command to run `which`: config.json's own runners map first (an explicit user choice always
|
|
15
|
+
// wins), falling back to the registry's default for a known, headless-capable, genuinely-installed
|
|
16
|
+
// agent — so picking one from a per-message agent list works the first time, before it's ever been
|
|
17
|
+
// the project's "active agent" and had a runner seeded into config.json for it.
|
|
18
|
+
function resolveRunnerCommand(root, cfg, which, opts) {
|
|
19
|
+
if (cfg.runners && cfg.runners[which]) return cfg.runners[which];
|
|
20
|
+
const known = agentsRegistry.KNOWN_AGENTS.find((a) => a.id === which);
|
|
21
|
+
if (known && known.runner && agentsRegistry.isAgentInstalled(which, root, opts)) return known.runner;
|
|
22
|
+
return null;
|
|
23
|
+
}
|
|
12
24
|
|
|
13
25
|
function runStart(root, run) {
|
|
14
26
|
const rt = store.readRuntime(root); rt.agents = rt.agents || []; rt.agents.push(run); store.writeRuntime(root, rt);
|
|
@@ -50,7 +62,7 @@ function pushAttention(root, text, by) {
|
|
|
50
62
|
function startRun(root, { prompt, agent, logPrompt = true }, emit) {
|
|
51
63
|
const cfg = store.readConfig(root);
|
|
52
64
|
const which = agent || cfg.agent || 'claude';
|
|
53
|
-
const cmdStr = cfg
|
|
65
|
+
const cmdStr = resolveRunnerCommand(root, cfg, which);
|
|
54
66
|
if (!cmdStr) return { error: `No runner configured for "${which}".` };
|
|
55
67
|
const parts = cmdStr.split(/\s+/).filter(Boolean);
|
|
56
68
|
const runId = 'r' + Date.now().toString(36);
|
|
@@ -97,4 +109,4 @@ function startRun(root, { prompt, agent, logPrompt = true }, emit) {
|
|
|
97
109
|
return { runId, child };
|
|
98
110
|
}
|
|
99
111
|
|
|
100
|
-
module.exports = { startRun };
|
|
112
|
+
module.exports = { startRun, resolveRunnerCommand };
|
|
@@ -35,7 +35,7 @@ function project(){
|
|
|
35
35
|
// Known vs. actually-installed agents — the topbar switcher needs both: the full list to offer,
|
|
36
36
|
// and which ones are real (bin on PATH, or the project already has that agent's config dir) so it
|
|
37
37
|
// can refuse to activate one that isn't there.
|
|
38
|
-
p.knownAgents = agentsRegistry.KNOWN_AGENTS.map((a) => ({ id: a.id, label: a.label }));
|
|
38
|
+
p.knownAgents = agentsRegistry.KNOWN_AGENTS.map((a) => ({ id: a.id, label: a.label, headless: a.headless, docsUrl: a.docsUrl }));
|
|
39
39
|
p.installedAgents = agentsRegistry.installedAgents(ROOT);
|
|
40
40
|
return p;
|
|
41
41
|
}
|
|
@@ -62,8 +62,11 @@ function writeConfig(patch){
|
|
|
62
62
|
}
|
|
63
63
|
cfg.agent = id;
|
|
64
64
|
// Seed a default runner if this agent was never configured (e.g. installed after init/update).
|
|
65
|
+
// A headless:false agent (e.g. kimi) has no runner to seed — it can still be the active agent,
|
|
66
|
+
// it just can't be spawned by Run/Orchestrate/Summarize (disabled client-side; runner.js and
|
|
67
|
+
// summarize.js also refuse server-side either way).
|
|
65
68
|
const known = agentsRegistry.KNOWN_AGENTS.find((a) => a.id === id);
|
|
66
|
-
if (known) { cfg.runners = cfg.runners || {}; if (!cfg.runners[id]) cfg.runners[id] = known.runner; }
|
|
69
|
+
if (known && known.runner) { cfg.runners = cfg.runners || {}; if (!cfg.runners[id]) cfg.runners[id] = known.runner; }
|
|
67
70
|
}
|
|
68
71
|
fs.writeFileSync(cp, JSON.stringify(cfg, null, 2) + '\n');
|
|
69
72
|
return cfg;
|
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
*/
|
|
7
7
|
const { spawn } = require('child_process');
|
|
8
8
|
const store = require('../lib/store');
|
|
9
|
+
const { resolveRunnerCommand } = require('./runner');
|
|
9
10
|
|
|
10
11
|
const DEFAULT_LIMIT = 40;
|
|
11
12
|
|
|
@@ -20,7 +21,7 @@ function formatLog(messages, limit = DEFAULT_LIMIT) {
|
|
|
20
21
|
function runSummarize(root, { agent } = {}, emit) {
|
|
21
22
|
const cfg = store.readConfig(root);
|
|
22
23
|
const which = agent || cfg.agent || 'claude';
|
|
23
|
-
const cmdStr = cfg
|
|
24
|
+
const cmdStr = resolveRunnerCommand(root, cfg, which);
|
|
24
25
|
if (!cmdStr) return { error: `No runner configured for "${which}".` };
|
|
25
26
|
|
|
26
27
|
const rt = store.readRuntime(root);
|
|
@@ -9,14 +9,27 @@
|
|
|
9
9
|
const fs = require('fs');
|
|
10
10
|
const path = require('path');
|
|
11
11
|
|
|
12
|
+
// headless:false = detectable and selectable as the active agent, but spectoflow never spawns it
|
|
13
|
+
// itself (no confirmed non-interactive one-shot mode) — Run/Orchestrate/Summarize stay disabled for
|
|
14
|
+
// it client-side; runner/summarize.js also refuse server-side (defense in depth). `docsUrl` is that
|
|
15
|
+
// agent's own official CLI docs, surfaced verbatim in the dashboard's Documentation tab. See the
|
|
16
|
+
// longer rationale above lib/adapters.js's REGISTRY, the richer install-time twin of this list —
|
|
17
|
+
// including why DeepSeek Harness isn't here at all, and why some runner strings order their flags
|
|
18
|
+
// the way they do (the trailing prompt must land right after whichever flag takes a value).
|
|
12
19
|
const KNOWN_AGENTS = [
|
|
13
|
-
{ id: 'claude', label: 'Claude Code', bin: 'claude', dirs: ['.claude'], runner: 'claude -p --permission-mode acceptEdits' },
|
|
14
|
-
{ id: 'codex', label: 'Codex', bin: 'codex', dirs: ['.codex'], runner: 'codex exec' },
|
|
15
|
-
{ id: 'cursor', label: 'Cursor', bin: 'cursor-agent', dirs: ['.cursor'], runner: 'cursor-agent -p' },
|
|
16
|
-
{ id: 'gemini', label: 'Gemini CLI', bin: 'gemini', dirs: ['.gemini'], runner: 'gemini -p' },
|
|
17
|
-
{ id: 'opencode', label: 'OpenCode', bin: 'opencode', dirs: ['.opencode'], runner: 'opencode run --quiet' },
|
|
18
|
-
{ id: 'kiro', label: 'Kiro CLI', bin: 'kiro-cli', dirs: ['.kiro'], runner: 'kiro-cli chat --no-interactive --trust-all-tools' },
|
|
19
|
-
{ id: 'antigravity', label: 'Antigravity', bin: 'agy', dirs: [], runner: 'agy -p' },
|
|
20
|
+
{ id: 'claude', label: 'Claude Code', bin: 'claude', dirs: ['.claude'], runner: 'claude -p --permission-mode acceptEdits', headless: true, docsUrl: 'https://code.claude.com/docs/en/cli-reference' },
|
|
21
|
+
{ id: 'codex', label: 'Codex', bin: 'codex', dirs: ['.codex'], runner: 'codex exec', headless: true, docsUrl: 'https://developers.openai.com/codex/cli/reference' },
|
|
22
|
+
{ id: 'cursor', label: 'Cursor', bin: 'cursor-agent', dirs: ['.cursor'], runner: 'cursor-agent -p', headless: true, docsUrl: 'https://cursor.com/docs/cli/overview' },
|
|
23
|
+
{ id: 'gemini', label: 'Gemini CLI', bin: 'gemini', dirs: ['.gemini'], runner: 'gemini -p', headless: true, docsUrl: 'https://github.com/google-gemini/gemini-cli' },
|
|
24
|
+
{ id: 'opencode', label: 'OpenCode', bin: 'opencode', dirs: ['.opencode'], runner: 'opencode run --quiet', headless: true, docsUrl: 'https://opencode.ai/docs/cli/' },
|
|
25
|
+
{ id: 'kiro', label: 'Kiro CLI', bin: 'kiro-cli', dirs: ['.kiro'], runner: 'kiro-cli chat --no-interactive --trust-all-tools', headless: true, docsUrl: 'https://kiro.dev/docs/cli/headless/' },
|
|
26
|
+
{ id: 'antigravity', label: 'Antigravity', bin: 'agy', dirs: [], runner: 'agy -p', headless: true, docsUrl: 'https://antigravity.google/docs/cli/headless/' },
|
|
27
|
+
{ id: 'kimi', label: 'Kimi CLI', bin: 'kimi', dirs: [], runner: null, headless: false, docsUrl: 'https://github.com/MoonshotAI/kimi-cli' },
|
|
28
|
+
{ id: 'copilot', label: 'GitHub Copilot CLI', bin: 'copilot', dirs: [], runner: 'copilot -s --allow-all-tools -p', headless: true, docsUrl: 'https://docs.github.com/copilot/concepts/agents/about-copilot-cli' },
|
|
29
|
+
{ id: 'amazon-q', label: 'Amazon Q Developer CLI', bin: 'q', dirs: ['.amazonq'], runner: 'q chat --no-interactive --trust-all-tools', headless: true, docsUrl: 'https://docs.aws.amazon.com/amazonq/latest/qdeveloper-ug/command-line-chat.html' },
|
|
30
|
+
{ id: 'droid', label: 'Factory Droid CLI', bin: 'droid', dirs: ['.factory'], runner: 'droid exec', headless: true, docsUrl: 'https://docs.factory.ai/droid-exec/overview' },
|
|
31
|
+
{ id: 'auggie', label: 'Auggie CLI', bin: 'auggie', dirs: ['.augment'], runner: 'auggie --quiet --print', headless: true, docsUrl: 'https://docs.augmentcode.com/cli/overview' },
|
|
32
|
+
{ id: 'goose', label: 'Goose CLI', bin: 'goose', dirs: ['.goose'], runner: 'goose run -t', headless: true, docsUrl: 'https://block.github.io/goose/' },
|
|
20
33
|
];
|
|
21
34
|
|
|
22
35
|
// Is `bin` an executable resolvable on PATH? On win32, an extension from PATHEXT is required, so we
|