specrails-desktop 2.26.0 → 2.26.2
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/client/dist/assets/{ActivityFeedPage-1eXnoNAo.js → ActivityFeedPage-bDe4VitF.js} +1 -1
- package/client/dist/assets/{AgentBrowserCapture-BHW_6Vm0.js → AgentBrowserCapture-DQyeEm2V.js} +1 -1
- package/client/dist/assets/{AgentModeCodePane-C89SAJzI.js → AgentModeCodePane-Ci39DcOo.js} +2 -2
- package/client/dist/assets/{AgentModeJobsPane-BG_4r4Dm.js → AgentModeJobsPane-C-g1WNVG.js} +1 -1
- package/client/dist/assets/{AgentsPage-BrkWfc9s.js → AgentsPage-BWgglK7V.js} +3 -3
- package/client/dist/assets/{AnalyticsPage-CMZRUPrT.js → AnalyticsPage-Da21wWWw.js} +1 -1
- package/client/dist/assets/{BarChart-BtF3zJHa.js → BarChart-BiLTq3uC.js} +1 -1
- package/client/dist/assets/{CodePage-Cime5FRs.js → CodePage-BUcAp7SC.js} +1 -1
- package/client/dist/assets/{DesktopAnalyticsPage-CSKHSBBF.js → DesktopAnalyticsPage-COkzgMmd.js} +1 -1
- package/client/dist/assets/{DocsDialog-ClTq6Fzj.js → DocsDialog-PZHMN18B.js} +1 -1
- package/client/dist/assets/{DocsPage-DTxfOpTu.js → DocsPage-D3fChfkj.js} +1 -1
- package/client/dist/assets/{ExportDropdown-Ho9zdPvK.js → ExportDropdown-DDhJH-Jr.js} +1 -1
- package/client/dist/assets/{IntegrationsPage-DWNyo6jk.js → IntegrationsPage-F87uxxVH.js} +1 -1
- package/client/dist/assets/{InteractiveJobComposer-CYxXOKld.js → InteractiveJobComposer-DqDCiCa0.js} +5 -5
- package/client/dist/assets/{JobDetailModal-DrNafHY5.js → JobDetailModal-BWJR60fi.js} +1 -1
- package/client/dist/assets/{JobDetailPage-4VKw33GW.js → JobDetailPage-CjWE_jyd.js} +1 -1
- package/client/dist/assets/{JobsPage-cFr6wWaH.js → JobsPage-LmnXkyCa.js} +1 -1
- package/client/dist/assets/{LoopBuilderPage-Bk8zVvEX.js → LoopBuilderPage-DsLLrtHa.js} +2 -2
- package/client/dist/assets/{LoopPreviewModal-XFSO2Vcs.js → LoopPreviewModal-C-fDEgnu.js} +1 -1
- package/client/dist/assets/{LoopsPage-DWMwDj9g.js → LoopsPage-DDNO9h9T.js} +1 -1
- package/client/dist/assets/{ProjectSettingsDialog-DnSe_yWm.js → ProjectSettingsDialog-CX854C8e.js} +1 -1
- package/client/dist/assets/{TemplatePreviewModal-B30-TY_v.js → TemplatePreviewModal-DcHFbLA8.js} +1 -1
- package/client/dist/assets/agent-BI6vr-To.js +1 -0
- package/client/dist/assets/{agent-D5QNn9np2.js → agent-BUGXI3Ok2.js} +1 -1
- package/client/dist/assets/agent-Bph_-xt7.js +1 -0
- package/client/dist/assets/agent-Bvy2Csyd.js +1 -0
- package/client/dist/assets/{agent-DgFoLgrF2.js → agent-Bwkyg2oX2.js} +1 -1
- package/client/dist/assets/agent-CLCyDaZh.js +1 -0
- package/client/dist/assets/{agent-6mhkV25_2.js → agent-Cqs14QMr2.js} +1 -1
- package/client/dist/assets/{agent-CRYdi9-t.js → agent-DJ0EBUuP.js} +1 -1
- package/client/dist/assets/{brain-DcXkQwzO.js → brain-BBNUUrUI.js} +1 -1
- package/client/dist/assets/dashboard-BjjS1OrL.js +1 -0
- package/client/dist/assets/dashboard-Bk6oSk1H2.js +1 -0
- package/client/dist/assets/dashboard-BrH-GdOg2.js +1 -0
- package/client/dist/assets/dashboard-BurhUI8_.js +1 -0
- package/client/dist/assets/dashboard-C6w0rICe.js +1 -0
- package/client/dist/assets/dashboard-CAUnfDQL2.js +1 -0
- package/client/dist/assets/dashboard-C_ljpeYO.js +1 -0
- package/client/dist/assets/dashboard-D6OqDdj6.js +1 -0
- package/client/dist/assets/{dist-js-BAWwLSIj.js → dist-js-BxjTIvdT.js} +1 -1
- package/client/dist/assets/{dist-js-6U6hyD6z.js → dist-js-DdP_Gl3p.js} +1 -1
- package/client/dist/assets/{index-cvOunQkD.css → index-C695aPdV.css} +1 -1
- package/client/dist/assets/index-Dw1N2-ci.js +156 -0
- package/client/dist/assets/{lib-Bsny0zZp.js → lib-BviHZ_gK.js} +1 -1
- package/client/dist/assets/{settings-DHd1lQ1k.js → settings-BHdPchJP.js} +1 -1
- package/client/dist/assets/{settings-FJXpJ3k92.js → settings-BeCczBFS2.js} +1 -1
- package/client/dist/assets/{settings-BWIf3vv4.js → settings-BlLi719f.js} +1 -1
- package/client/dist/assets/{settings-DTYQ5COE.js → settings-C_nY14Yz.js} +1 -1
- package/client/dist/assets/{settings-DE8t6aYv.js → settings-CaZ26a0S.js} +1 -1
- package/client/dist/assets/{settings-Dgv_q4qf2.js → settings-D54_cgl12.js} +1 -1
- package/client/dist/assets/{settings-DXgPh9-k.js → settings-D9bDDe2O.js} +1 -1
- package/client/dist/assets/{settings-BhuXe7ek2.js → settings-cn0tbve62.js} +1 -1
- package/client/dist/assets/{setup-iY8vH8pB.js → setup-7J8TjG4O.js} +1 -1
- package/client/dist/assets/{setup-D674kWQH.js → setup-BXpw07r-.js} +1 -1
- package/client/dist/assets/{setup-B590KsTX.js → setup-BiduSX9d.js} +1 -1
- package/client/dist/assets/{setup-cnqZsQSX2.js → setup-BuQNKztt2.js} +1 -1
- package/client/dist/assets/{setup-CEj6uY3-2.js → setup-BwMovM9z2.js} +1 -1
- package/client/dist/assets/{setup-BkyGoby6.js → setup-D84y3wx-.js} +1 -1
- package/client/dist/assets/{setup-CbIerFGf2.js → setup-DU0ULX8q2.js} +1 -1
- package/client/dist/assets/{setup-VNqXyB6Y.js → setup-RiUHzq7E.js} +1 -1
- package/client/dist/assets/{upload-49vX83IZ.js → upload-CRuuzzvp.js} +1 -1
- package/client/dist/assets/{value-Bo8EiTZE.js → value-CIr5hDMt.js} +1 -1
- package/client/dist/index.html +21 -8
- package/package.json +1 -1
- package/server/dist/agent-operator-prompt.js +45 -5
- package/server/dist/desktop-router.js +9 -2
- package/server/dist/mcp/guide.js +33 -4
- package/server/dist/mcp/tools/app-settings.js +18 -2
- package/server/dist/mcp/tools/catalog.js +2 -0
- package/server/dist/mcp/tools/rails.js +27 -6
- package/server/dist/mcp/tools/support.js +324 -0
- package/server/dist/pr-publisher.js +17 -15
- package/server/dist/project-git.js +57 -0
- package/server/dist/rail-isolated-launch.js +27 -3
- package/server/dist/rail-pr-decision.js +69 -1
- package/server/dist/rail-worktree-release.js +25 -0
- package/server/dist/rail-worktrees-store.js +2 -2
- package/server/dist/rails-router.js +136 -7
- package/client/dist/assets/agent-BZqfQhI_.js +0 -1
- package/client/dist/assets/agent-Bjy1SlT5.js +0 -1
- package/client/dist/assets/agent-Bn6ZmjHj.js +0 -1
- package/client/dist/assets/agent-DgwPsxWQ.js +0 -1
- package/client/dist/assets/dashboard-CuGuy2__2.js +0 -1
- package/client/dist/assets/dashboard-CxP3TZ3I2.js +0 -1
- package/client/dist/assets/dashboard-DWHVfP7U.js +0 -1
- package/client/dist/assets/dashboard-D_Pgs6QH2.js +0 -1
- package/client/dist/assets/dashboard-Dwnssayh.js +0 -1
- package/client/dist/assets/dashboard-S_pT1yxN.js +0 -1
- package/client/dist/assets/dashboard-tCxOFOxx.js +0 -1
- package/client/dist/assets/dashboard-zefbBNyG.js +0 -1
- package/client/dist/assets/index-DnkfABxY.js +0 -156
package/client/dist/index.html
CHANGED
|
@@ -47,8 +47,14 @@
|
|
|
47
47
|
} catch (_) { /* storage unavailable — nothing to migrate */ }
|
|
48
48
|
try {
|
|
49
49
|
var k = 'specrails-desktop:ui-theme'
|
|
50
|
-
var
|
|
50
|
+
var legacyThemeIds = { 'star-wars': 'galaxy', matrix: 'code-rain' }
|
|
51
|
+
var allowed = ['dracula', 'aurora-light', 'obsidian-dark', 'code-rain', 'specrails', 'galaxy']
|
|
51
52
|
var v = localStorage.getItem(k)
|
|
53
|
+
var migrated = legacyThemeIds[v]
|
|
54
|
+
if (migrated) {
|
|
55
|
+
v = migrated
|
|
56
|
+
localStorage.setItem(k, migrated)
|
|
57
|
+
}
|
|
52
58
|
document.documentElement.dataset.theme =
|
|
53
59
|
v && allowed.indexOf(v) !== -1 ? v : 'specrails'
|
|
54
60
|
} catch (_) {
|
|
@@ -85,7 +91,7 @@
|
|
|
85
91
|
--splash-secondary: #f48fc7;
|
|
86
92
|
--splash-muted: #8b8fa3;
|
|
87
93
|
}
|
|
88
|
-
html[data-theme="
|
|
94
|
+
html[data-theme="code-rain"] {
|
|
89
95
|
--splash-bg: #08120e;
|
|
90
96
|
--splash-fg: #b8ffd9;
|
|
91
97
|
--splash-primary: #00ff66;
|
|
@@ -99,6 +105,13 @@
|
|
|
99
105
|
--splash-secondary: #9a6fce;
|
|
100
106
|
--splash-muted: #6b6f8c;
|
|
101
107
|
}
|
|
108
|
+
html[data-theme="galaxy"] {
|
|
109
|
+
--splash-bg: hsl(220 20% 4%);
|
|
110
|
+
--splash-fg: hsl(210 30% 94%);
|
|
111
|
+
--splash-primary: hsl(212 100% 62%);
|
|
112
|
+
--splash-secondary: hsl(210 12% 65%);
|
|
113
|
+
--splash-muted: hsl(215 15% 60%);
|
|
114
|
+
}
|
|
102
115
|
html, body {
|
|
103
116
|
margin: 0;
|
|
104
117
|
background: var(--splash-bg);
|
|
@@ -191,14 +204,14 @@
|
|
|
191
204
|
.specrails-splash__mark .pill { opacity: 1; }
|
|
192
205
|
}
|
|
193
206
|
</style>
|
|
194
|
-
<script type="module" crossorigin src="/assets/index-
|
|
207
|
+
<script type="module" crossorigin src="/assets/index-Dw1N2-ci.js"></script>
|
|
195
208
|
<link rel="modulepreload" crossorigin href="/assets/chunk-BNv3lrIs.js">
|
|
196
209
|
<link rel="modulepreload" crossorigin href="/assets/preload-helper-DSXbuxSR.js">
|
|
197
210
|
<link rel="modulepreload" crossorigin href="/assets/clsx-CNmW0Nip.js">
|
|
198
211
|
<link rel="modulepreload" crossorigin href="/assets/auth-Cvsb7-Ek.js">
|
|
199
212
|
<link rel="modulepreload" crossorigin href="/assets/activity-D8vQJrpW.js">
|
|
200
213
|
<link rel="modulepreload" crossorigin href="/assets/addspec-DxW6oPsk.js">
|
|
201
|
-
<link rel="modulepreload" crossorigin href="/assets/agent-
|
|
214
|
+
<link rel="modulepreload" crossorigin href="/assets/agent-CLCyDaZh.js">
|
|
202
215
|
<link rel="modulepreload" crossorigin href="/assets/agents-Cev2oFfX.js">
|
|
203
216
|
<link rel="modulepreload" crossorigin href="/assets/agentstudio-CZm2rOzt.js">
|
|
204
217
|
<link rel="modulepreload" crossorigin href="/assets/aiedit-DYtnZU9H.js">
|
|
@@ -209,7 +222,7 @@
|
|
|
209
222
|
<link rel="modulepreload" crossorigin href="/assets/code-thSEptMx.js">
|
|
210
223
|
<link rel="modulepreload" crossorigin href="/assets/commands-CckaBWdV.js">
|
|
211
224
|
<link rel="modulepreload" crossorigin href="/assets/common-CYaT2yHp.js">
|
|
212
|
-
<link rel="modulepreload" crossorigin href="/assets/dashboard-
|
|
225
|
+
<link rel="modulepreload" crossorigin href="/assets/dashboard-BurhUI8_.js">
|
|
213
226
|
<link rel="modulepreload" crossorigin href="/assets/explore-BKVV5JSu.js">
|
|
214
227
|
<link rel="modulepreload" crossorigin href="/assets/integrations-CuWnMR5L.js">
|
|
215
228
|
<link rel="modulepreload" crossorigin href="/assets/jira-B3613-gj.js">
|
|
@@ -217,12 +230,12 @@
|
|
|
217
230
|
<link rel="modulepreload" crossorigin href="/assets/loops-Brnx4Fji.js">
|
|
218
231
|
<link rel="modulepreload" crossorigin href="/assets/mcp-CIH0pH1K.js">
|
|
219
232
|
<link rel="modulepreload" crossorigin href="/assets/nav-CzKzuwH8.js">
|
|
220
|
-
<link rel="modulepreload" crossorigin href="/assets/settings-
|
|
221
|
-
<link rel="modulepreload" crossorigin href="/assets/setup-
|
|
233
|
+
<link rel="modulepreload" crossorigin href="/assets/settings-D9bDDe2O.js">
|
|
234
|
+
<link rel="modulepreload" crossorigin href="/assets/setup-RiUHzq7E.js">
|
|
222
235
|
<link rel="modulepreload" crossorigin href="/assets/specs-CmEZY57v.js">
|
|
223
236
|
<link rel="modulepreload" crossorigin href="/assets/terminal-DFPNRLKp.js">
|
|
224
237
|
<link rel="modulepreload" crossorigin href="/assets/tickets-CkfbISuK.js">
|
|
225
|
-
<link rel="stylesheet" crossorigin href="/assets/index-
|
|
238
|
+
<link rel="stylesheet" crossorigin href="/assets/index-C695aPdV.css">
|
|
226
239
|
</head>
|
|
227
240
|
<body>
|
|
228
241
|
<div id="specrails-splash" aria-hidden="false" role="status" aria-label="Loading Specrails">
|
package/package.json
CHANGED
|
@@ -118,6 +118,39 @@ tool for exactly that, and never refuse or push this back to the user's terminal
|
|
|
118
118
|
(\`rm -rf\`, force-push, branch deletion, history rewrite) to "make something
|
|
119
119
|
work" — surface the blocker instead.
|
|
120
120
|
|
|
121
|
+
## Support & troubleshooting
|
|
122
|
+
|
|
123
|
+
When the user asks for help installing or using Specrails, asks "how do I...?",
|
|
124
|
+
reports a broken setup, provider CLI/auth issue, MCP/Agent Chat issue, failed
|
|
125
|
+
job, missing agents/skills/slash commands, PR-delivery confusion, costs, or
|
|
126
|
+
plugin trouble, this is SUPPORT — not backlog work. Call
|
|
127
|
+
\`specrails_support(action:'triage', question, projectId?)\` first and answer
|
|
128
|
+
from its diagnostics/playbook. Do NOT create or propose a spec unless the user
|
|
129
|
+
explicitly pivots from troubleshooting to product work.
|
|
130
|
+
|
|
131
|
+
For job failures that mention missing agents, missing skills, missing
|
|
132
|
+
\`/specrails:*\` commands, \`/opsx:*\` commands, "baseline agents", or a
|
|
133
|
+
command not installed, explain the storage model correctly: upstream agents,
|
|
134
|
+
skills and slash commands live in the app-global specrails-core framework, NOT
|
|
135
|
+
inside the selected project. Give the user the repair path:
|
|
136
|
+
|
|
137
|
+
- If global core may be stale, offer
|
|
138
|
+
\`specrails_support(action:'core_update_check')\`, then with confirmation
|
|
139
|
+
\`specrails_support(action:'core_update_apply')\`.
|
|
140
|
+
- If global core is current and there is no concrete failing job/error, say the
|
|
141
|
+
core installation looks healthy. Do NOT infer a MyProject problem from
|
|
142
|
+
\`setup/checkpoints\`.
|
|
143
|
+
- A setup checkpoint summary showing pending checkpoints, 0 agents, or
|
|
144
|
+
0 \`specrails:*\` commands is NOT a specrails-core health signal and is NOT a
|
|
145
|
+
reason to run \`specrails_setup(install)\`. Do not say they "live in
|
|
146
|
+
MyProject", and do not claim MyProject's projection is broken from that alone.
|
|
147
|
+
- If a real job still reports missing core definitions while global core is
|
|
148
|
+
current, ask for/read \`specrails_jobs(get)\` or \`specrails_jobs(diagnostic)\`
|
|
149
|
+
and report it as a framework-loading/job diagnostic issue, not a project setup
|
|
150
|
+
checkpoint issue.
|
|
151
|
+
- Manual fallback for standalone/legacy core installs: from the project root run
|
|
152
|
+
\`npx specrails-core@latest update\`, then retry the job.
|
|
153
|
+
|
|
121
154
|
## Permission ladder & confirmation rules
|
|
122
155
|
|
|
123
156
|
Your actions are gated by a cumulative level the user steers live with
|
|
@@ -147,7 +180,9 @@ above the current level, say so up front.
|
|
|
147
180
|
|
|
148
181
|
## Think in specs (default stance)
|
|
149
182
|
|
|
150
|
-
When the user describes work to be done, the natural unit is a
|
|
183
|
+
When the user describes product/code work to be done, the natural unit is a
|
|
184
|
+
SPEC. This default does NOT apply to support/troubleshooting questions; route
|
|
185
|
+
those through \`specrails_support\` instead.
|
|
151
186
|
|
|
152
187
|
1. Check the backlog for duplicates first: \`specrails_specs(list)\`.
|
|
153
188
|
2. Capture the work as a spec — pick the right creation path (next section).
|
|
@@ -337,6 +372,11 @@ summary later.
|
|
|
337
372
|
is explicit, covering Jira projects whose Review status has not been mapped to
|
|
338
373
|
Specrails \`on_review\`. You do NOT need to know or pass the branch name. If
|
|
339
374
|
there is no confident open PR match, the normal new-work flow is preserved.
|
|
375
|
+
- A published PR card (\`decision:'pr_ready'\`) is STILL an open PR continuation
|
|
376
|
+
target, not a blocker. If the user asks for modifications on that PR, assign
|
|
377
|
+
the same spec(s) to a rail and launch again; do NOT tell them they must publish,
|
|
378
|
+
discard, or merge first. \`pr_decision_pending\` should only block unresolved
|
|
379
|
+
deliveries with no continuable PR head yet.
|
|
340
380
|
- Launch proposal shape: tickets (ids + titles), rail number, mode, engine and
|
|
341
381
|
model/profile, plus "runs for minutes and costs money". If the API mode is
|
|
342
382
|
\`freestyle\`, write "Freestyle" to the user. Wait for yes.
|
|
@@ -350,9 +390,9 @@ summary later.
|
|
|
350
390
|
tickets to the returned \`railIndex\`, and launch. Never wedge waiting for a
|
|
351
391
|
slot and never steal a configured rail's tickets to free one.
|
|
352
392
|
- **Launching many rails**: \`specrails_rails(launch_all)\` launches every rail
|
|
353
|
-
that has tickets and no active run / pending PR decision in ONE
|
|
354
|
-
with its own stored mode/engine/profile, and returns per-rail
|
|
355
|
-
(launched / skipped with reason / failed) — report them per rail. It is
|
|
393
|
+
that has tickets and no active run / uncontinuable pending PR decision in ONE
|
|
394
|
+
call, each with its own stored mode/engine/profile, and returns per-rail
|
|
395
|
+
outcomes (launched / skipped with reason / failed) — report them per rail. It is
|
|
356
396
|
ai-spawn: propose it with the total rail + spec count and cost framing
|
|
357
397
|
first. One yes covers the whole batch when the user asked for the batch
|
|
358
398
|
("launch everything") — do not re-ask per rail.
|
|
@@ -431,4 +471,4 @@ When the user has no projects yet, or asks to add one:
|
|
|
431
471
|
Setup is QUICK-only (fast, offline). Do NOT offer, mention, or attempt a "full"
|
|
432
472
|
or "enrich" install — that flow is deprecated and not available through you.
|
|
433
473
|
`;
|
|
434
|
-
exports.OPERATOR_SYSTEM_PROMPT = `You are the Specrails operator agent, embedded inside the Specrails Desktop app; drive it on the user's behalf using the specrails_* MCP tools. Your full operator manual is the CLAUDE.md auto-loaded from your working directory — follow it. Non-negotiables: target a project with specrails_select_project or the projectId argument, and ask rather than guess when none is pinned; short async 202 ops (spec generation, ai-edit) may be awaited with specrails_watch (projectId required), but after a rail/job LAUNCH is accepted end your reply immediately — progress streams live in the conversation's run card and the app; watch a launched run only when the user explicitly asks you to wait, with a bounded untilMs; never claim success from a 202 acceptance alone — verify from a terminal event or a domain read (e.g. specrails_jobs get); call the free-form autonomous rail mode Freestyle in prose — freestyle/factory:freestyle/{{cmd:freestyle}} are canonical API/id/token values for that same capability; respect the cumulative permission ladder observe / edit / operate / autonomous — if a tool is refused, name the level the user must Shift+Tab to, never work around it; when refining a spec, ground it in the real codebase FIRST (specrails_code tree/read_file/summary + specrails_specs list) and show the evolving draft as one fenced spec-draft JSON block (title, description, labels, priority, acceptanceCriteria) at the end of each turn that changed it — the app renders it as a live card; persist the refined spec with specrails_specs commit_draft (no conversationId) — never route it through create/generate, which regenerate the content with AI; commit_draft appends a Contract Layer by default via one short background AI pass — pass contractRefine false when the user declines it; report tool outputs faithfully, including failures. Format replies for easy reading: short paragraphs separated by blank lines, bullet lists for enumerations. When asking the user to pick between concrete choices, end the reply with a fenced options code block containing a JSON array of the 2-6 choice labels (rendered as clickable chips); never use that block otherwise.`;
|
|
474
|
+
exports.OPERATOR_SYSTEM_PROMPT = `You are the Specrails operator agent, embedded inside the Specrails Desktop app; drive it on the user's behalf using the specrails_* MCP tools. Your full operator manual is the CLAUDE.md auto-loaded from your working directory — follow it. Non-negotiables: target a project with specrails_select_project or the projectId argument, and ask rather than guess when none is pinned; support/troubleshooting/install/usage/job-failure questions use specrails_support first and never become specs unless the user pivots to product work; missing agents/skills/slash commands concern the app-global specrails-core framework, never project-owned files — never say agents/skills/commands live inside the project; project setup checkpoints are not a core health signal, so pending/0 agents/0 commands must not trigger specrails_setup(install) or a project repair recommendation; offer core_update_check/core_update_apply only for global core updates, and if global core is current ask for the concrete job error/diagnostic; an on_review spec with an open PR, including a published pr_ready card, can be relaunched to continue that PR branch — do not require publish/discard/merge first; short async 202 ops (spec generation, ai-edit) may be awaited with specrails_watch (projectId required), but after a rail/job LAUNCH is accepted end your reply immediately — progress streams live in the conversation's run card and the app; watch a launched run only when the user explicitly asks you to wait, with a bounded untilMs; never claim success from a 202 acceptance alone — verify from a terminal event or a domain read (e.g. specrails_jobs get); call the free-form autonomous rail mode Freestyle in prose — freestyle/factory:freestyle/{{cmd:freestyle}} are canonical API/id/token values for that same capability; respect the cumulative permission ladder observe / edit / operate / autonomous — if a tool is refused, name the level the user must Shift+Tab to, never work around it; when refining a spec, ground it in the real codebase FIRST (specrails_code tree/read_file/summary + specrails_specs list) and show the evolving draft as one fenced spec-draft JSON block (title, description, labels, priority, acceptanceCriteria) at the end of each turn that changed it — the app renders it as a live card; persist the refined spec with specrails_specs commit_draft (no conversationId) — never route it through create/generate, which regenerate the content with AI; commit_draft appends a Contract Layer by default via one short background AI pass — pass contractRefine false when the user declines it; report tool outputs faithfully, including failures. Format replies for easy reading: short paragraphs separated by blank lines, bullet lists for enumerations. When asking the user to pick between concrete choices, end the reply with a fenced options code block containing a JSON array of the 2-6 choice labels (rendered as clickable chips); never use that block otherwise.`;
|
|
@@ -64,7 +64,11 @@ function isGeminiBetaDisabled() {
|
|
|
64
64
|
}
|
|
65
65
|
// Theme allow-list. Mirror of THEME_IDS in `client/src/lib/themes.ts` —
|
|
66
66
|
// kept duplicated to avoid pulling client code into the server bundle.
|
|
67
|
-
const THEME_ID_ALLOWLIST = new Set(['dracula', 'aurora-light', 'obsidian-dark', '
|
|
67
|
+
const THEME_ID_ALLOWLIST = new Set(['dracula', 'aurora-light', 'obsidian-dark', 'code-rain', 'specrails', 'galaxy']);
|
|
68
|
+
const LEGACY_THEME_ID_MAP = {
|
|
69
|
+
'star-wars': 'galaxy',
|
|
70
|
+
matrix: 'code-rain',
|
|
71
|
+
};
|
|
68
72
|
// Language allow-list. Mirror of LANGUAGE_IDS in `client/src/lib/i18n.ts` —
|
|
69
73
|
// kept duplicated to avoid pulling client code into the server bundle.
|
|
70
74
|
const LANGUAGE_ID_ALLOWLIST = new Set(['en', 'es', 'fr', 'de', 'pt', 'it', 'zh', 'ja']);
|
|
@@ -840,7 +844,10 @@ function createDesktopRouter(registry, broadcast) {
|
|
|
840
844
|
// Persisted under desktop_settings key `ui_theme`. Default seeded by migration 8.
|
|
841
845
|
router.get('/theme', (_req, res) => {
|
|
842
846
|
const stored = (0, desktop_db_1.getDesktopSetting)(registry.desktopDb, 'ui_theme');
|
|
843
|
-
const
|
|
847
|
+
const migrated = stored ? LEGACY_THEME_ID_MAP[stored] : undefined;
|
|
848
|
+
const theme = migrated ?? (stored && THEME_ID_ALLOWLIST.has(stored) ? stored : 'specrails');
|
|
849
|
+
if (migrated)
|
|
850
|
+
(0, desktop_db_1.setDesktopSetting)(registry.desktopDb, 'ui_theme', migrated);
|
|
844
851
|
res.json({ theme });
|
|
845
852
|
});
|
|
846
853
|
router.patch('/theme', (req, res) => {
|
package/server/dist/mcp/guide.js
CHANGED
|
@@ -53,6 +53,13 @@ Codex, Gemini) to implement specs.
|
|
|
53
53
|
|
|
54
54
|
## Creating specs — three paths, one decision rule
|
|
55
55
|
|
|
56
|
+
Before creating a spec, classify the user's intent. If they are asking for
|
|
57
|
+
help using Specrails, installation/setup, a failed job, missing agents/skills,
|
|
58
|
+
MCP connection, provider auth, GitHub/PR delivery, costs, or "how do I...?"
|
|
59
|
+
support, DO NOT create a spec. Call \`specrails_support(action:'triage')\`
|
|
60
|
+
and solve it conversationally first. Only move to spec creation when the user
|
|
61
|
+
explicitly asks for product/backlog work.
|
|
62
|
+
|
|
56
63
|
1. **Quick (AI-generated)** — \`specrails_specs(action:'generate', idea, …)\`, or
|
|
57
64
|
the simpler \`create\` with title/description: routes through the app's Quick
|
|
58
65
|
Add Spec — an AI pass structures the request into a complete spec, so
|
|
@@ -105,15 +112,20 @@ heading inside the description); \`labels\`; \`priority\`. Spec content is Engli
|
|
|
105
112
|
other work, create one and proceed; never wait for a slot.
|
|
106
113
|
- Parallel launches are safe and normal: each launch isolates its work in
|
|
107
114
|
per-ticket git worktrees, so several rails can run at once. \`launch_all\`
|
|
108
|
-
(ai-spawn) launches EVERY rail that has tickets and no active run /
|
|
109
|
-
PR decision in one call, each with its stored
|
|
110
|
-
per-rail outcomes (launched / skipped with
|
|
115
|
+
(ai-spawn) launches EVERY rail that has tickets and no active run /
|
|
116
|
+
uncontinuable pending PR decision in one call, each with its stored
|
|
117
|
+
mode/engine/profile, returning per-rail outcomes (launched / skipped with
|
|
118
|
+
reason / failed).
|
|
111
119
|
- Relaunching an \`on_review\` ticket with a matching OPEN GitHub PR continues
|
|
112
120
|
that PR's head branch automatically. Jira-linked \`in_progress\` tickets can
|
|
113
121
|
also continue an open PR when the match is explicit, covering Jira projects
|
|
114
122
|
whose Review status has not been mapped to Specrails \`on_review\`. New
|
|
115
123
|
tickets, or tickets without a confident open-PR match, keep the normal
|
|
116
124
|
branch-from-integration flow.
|
|
125
|
+
- A published PR delivery (\`decision:'pr_ready'\`) is still an open PR
|
|
126
|
+
continuation target when it has a PR URL/head branch covering the rail's
|
|
127
|
+
tickets. Do not tell the user to Publish/Discard/Merge first when they ask for
|
|
128
|
+
more changes on that same PR; assign the spec(s) to a rail and launch again.
|
|
117
129
|
- Projects without Git cannot use isolated worktrees or PR continuation. A
|
|
118
130
|
launch degrades to shared-cwd execution and returns \`isolationUnavailable\`;
|
|
119
131
|
explain that it writes directly to files and no PR card/branch will appear.
|
|
@@ -171,7 +183,10 @@ Tools cannot raise their own permissions in either regime. Common tiers:
|
|
|
171
183
|
list/get/spending/watch = read; commit_draft, from_prompt, update, set_tickets,
|
|
172
184
|
create_rail, plugin install, Jira connect = write; spec create/generate, rail
|
|
173
185
|
launch/launch_all, chat send, job spawn = ai-spawn; spec delete, rail stop, job
|
|
174
|
-
purge, plugin uninstall, Jira disconnect, project unregister = destructive.
|
|
186
|
+
purge, plugin uninstall, Jira disconnect, project unregister = destructive.
|
|
187
|
+
\`specrails_support(triage/core_update_status/core_update_check)\` is read;
|
|
188
|
+
\`specrails_support(core_update_apply)\` is ai-spawn because it runs longer
|
|
189
|
+
global update work. Note the
|
|
175
190
|
embedded spec-refinement happy path (investigate + commit_draft) needs only
|
|
176
191
|
read + write — ai-spawn is required only to launch work or spawn a nested AI.
|
|
177
192
|
|
|
@@ -216,6 +231,20 @@ read + write — ai-spawn is required only to launch work or spawn a nested AI.
|
|
|
216
231
|
\`install_config\` per provider → ONE \`install\` (provisions all chosen
|
|
217
232
|
providers; quick-only, offline) → poll \`checkpoints\` until
|
|
218
233
|
\`isInstalling === false\`.
|
|
234
|
+
- **Support** (\`specrails_support\`): use FIRST for installation/usage help,
|
|
235
|
+
provider CLI/auth, MCP/Agent Chat issues, missing agents/skills/commands,
|
|
236
|
+
failed jobs, PR delivery confusion, costs, and plugin questions. It returns a
|
|
237
|
+
support playbook plus local diagnostics and never creates specs. When a job
|
|
238
|
+
says agents, skills, or slash commands are missing, explain that upstream
|
|
239
|
+
definitions live in the APP-GLOBAL specrails-core framework, not inside the
|
|
240
|
+
project. For specrails-core installation questions, project setup checkpoints
|
|
241
|
+
are NOT a health signal: pending checkpoints or 0 agents/commands do not prove
|
|
242
|
+
a core problem and must not trigger \`specrails_setup(install)\`. If global
|
|
243
|
+
core is stale, offer \`core_update_check\` + \`core_update_apply\`. If global
|
|
244
|
+
core is current but a real job still reports missing core definitions, ask for
|
|
245
|
+
the job error/diagnostic and give the manual fallback for standalone/legacy
|
|
246
|
+
core installs: from the project root, run \`npx specrails-core@latest update\`,
|
|
247
|
+
then retry the job.
|
|
219
248
|
- **Loops lifecycle** (\`specrails_loops\`): Draft → \`publish\` (graph-validated)
|
|
220
249
|
→ runnable; \`update\` reverts to Draft and returns 409 while running;
|
|
221
250
|
\`preview\` dry-runs token resolution without spawning; constants are shared
|
|
@@ -8,8 +8,12 @@ const mcp_tiers_1 = require("../mcp-tiers");
|
|
|
8
8
|
// permission-tier toggles are intentionally NOT writable here — an external LLM
|
|
9
9
|
// must never be able to escalate its own permissions. Those are user-only,
|
|
10
10
|
// changed in the Settings ▸ MCP panel.
|
|
11
|
-
const WRITABLE_THEMES = ['specrails', 'dracula', 'aurora-light', 'obsidian-dark', '
|
|
11
|
+
const WRITABLE_THEMES = ['specrails', 'dracula', 'aurora-light', 'obsidian-dark', 'code-rain', 'galaxy'];
|
|
12
12
|
const WRITABLE_LANGS = ['en', 'es', 'fr', 'de', 'pt', 'it', 'zh', 'ja'];
|
|
13
|
+
const LEGACY_THEME_ID_MAP = {
|
|
14
|
+
'star-wars': 'galaxy',
|
|
15
|
+
matrix: 'code-rain',
|
|
16
|
+
};
|
|
13
17
|
function appTools() {
|
|
14
18
|
return [
|
|
15
19
|
{
|
|
@@ -44,8 +48,9 @@ function appTools() {
|
|
|
44
48
|
handler: (ctx, args) => {
|
|
45
49
|
const db = ctx.desktopDb;
|
|
46
50
|
if (args.action === 'get') {
|
|
51
|
+
const theme = normalizeStoredTheme(db);
|
|
47
52
|
return {
|
|
48
|
-
theme
|
|
53
|
+
theme,
|
|
49
54
|
language: (0, desktop_db_1.getDesktopSetting)(db, 'ui_language') ?? null,
|
|
50
55
|
dailyBudgetUsd: num((0, desktop_db_1.getDesktopSetting)(db, 'desktop_daily_budget_usd')),
|
|
51
56
|
costAlertThresholdUsd: num((0, desktop_db_1.getDesktopSetting)(db, 'cost_alert_threshold_usd')),
|
|
@@ -102,6 +107,17 @@ function appTools() {
|
|
|
102
107
|
},
|
|
103
108
|
];
|
|
104
109
|
}
|
|
110
|
+
function normalizeStoredTheme(db) {
|
|
111
|
+
const stored = (0, desktop_db_1.getDesktopSetting)(db, 'ui_theme');
|
|
112
|
+
if (!stored)
|
|
113
|
+
return 'specrails';
|
|
114
|
+
const migrated = LEGACY_THEME_ID_MAP[stored];
|
|
115
|
+
if (migrated) {
|
|
116
|
+
(0, desktop_db_1.setDesktopSetting)(db, 'ui_theme', migrated);
|
|
117
|
+
return migrated;
|
|
118
|
+
}
|
|
119
|
+
return WRITABLE_THEMES.includes(stored) ? stored : 'specrails';
|
|
120
|
+
}
|
|
105
121
|
function num(v) {
|
|
106
122
|
if (v === undefined)
|
|
107
123
|
return null;
|
|
@@ -17,6 +17,7 @@ const code_1 = require("./code");
|
|
|
17
17
|
const setup_1 = require("./setup");
|
|
18
18
|
const analytics_1 = require("./analytics");
|
|
19
19
|
const git_1 = require("./git");
|
|
20
|
+
const support_1 = require("./support");
|
|
20
21
|
/**
|
|
21
22
|
* The full MCP tool catalog. Domain-facade tools each expose an `action` enum
|
|
22
23
|
* and call the app's REST API over loopback (see apiCall). Meta tools receive a
|
|
@@ -41,6 +42,7 @@ function buildToolSpecs() {
|
|
|
41
42
|
specs.push(...(0, setup_1.setupTools)());
|
|
42
43
|
specs.push(...(0, analytics_1.analyticsTools)());
|
|
43
44
|
specs.push(...(0, git_1.gitTools)());
|
|
45
|
+
specs.push(...(0, support_1.supportTools)());
|
|
44
46
|
// Meta last (needs the full list for search/describe)
|
|
45
47
|
specs.push(...(0, meta_1.metaTools)(() => specs));
|
|
46
48
|
return specs;
|
|
@@ -7,6 +7,26 @@ const types_1 = require("./types");
|
|
|
7
7
|
* efforts outside it (codex 'minimal', claude 'xhigh') are never defaulted —
|
|
8
8
|
* a default must not 400 a launch that would succeed without it. */
|
|
9
9
|
const RAIL_REASONING_EFFORTS = new Set(['low', 'medium', 'high']);
|
|
10
|
+
function isRecord(value) {
|
|
11
|
+
return typeof value === 'object' && value !== null && !Array.isArray(value);
|
|
12
|
+
}
|
|
13
|
+
function prDeliveryContinuesTickets(raw, ticketIds) {
|
|
14
|
+
if (!isRecord(raw))
|
|
15
|
+
return false;
|
|
16
|
+
const decision = raw.decision;
|
|
17
|
+
if (decision !== 'pr_draft' && decision !== 'pr_ready')
|
|
18
|
+
return false;
|
|
19
|
+
if (typeof raw.prUrl !== 'string' || !raw.prUrl)
|
|
20
|
+
return false;
|
|
21
|
+
if (typeof raw.branch !== 'string' || !raw.branch)
|
|
22
|
+
return false;
|
|
23
|
+
if (raw.prState !== 'pr-created')
|
|
24
|
+
return false;
|
|
25
|
+
if (!Array.isArray(raw.ticketIds))
|
|
26
|
+
return false;
|
|
27
|
+
const covered = new Set(raw.ticketIds.filter((id) => typeof id === 'number'));
|
|
28
|
+
return ticketIds.length > 0 && ticketIds.every((id) => covered.has(id));
|
|
29
|
+
}
|
|
10
30
|
/**
|
|
11
31
|
* Rails domain facade. A "rail" is a numbered launch slot per project: it holds
|
|
12
32
|
* a set of assigned ticket IDs plus a mode/profile/engine/name, and launching it
|
|
@@ -27,9 +47,9 @@ function railsTools() {
|
|
|
27
47
|
'Actions: list (rails + active jobs/loop runs), create_rail (add a new rail slot; returns its railIndex), set_tickets (assign ticket IDs), set_profile (default agent profile, null=legacy), ' +
|
|
28
48
|
'set_engine (provider override, null=primary), set_name (display label, null clears), ' +
|
|
29
49
|
'launch (ai-spawn — spawns claude/codex/gemini CLI job(s) that WRITE CODE, RUN TESTS, COMMIT, and INCUR TOKEN COST; returns 202 with jobId/jobIds/loopRunIds), ' +
|
|
30
|
-
'launch_all (ai-spawn — launches EVERY rail that has tickets and no active run/pending PR decision, in parallel, using each rail\'s stored mode/engine/profile; returns per-rail outcomes with skip reasons), ' +
|
|
50
|
+
'launch_all (ai-spawn — launches EVERY rail that has tickets and no active run/uncontinuable pending PR decision, in parallel, using each rail\'s stored mode/engine/profile; returns per-rail outcomes with skip reasons), ' +
|
|
31
51
|
'stop (destructive — kills all active jobs and loop runs for the rail). ' +
|
|
32
|
-
'For on_review tickets with an already-open GitHub PR, launch automatically tries to continue that PR head branch; Jira-linked in_progress tickets can do the same when the PR match is explicit; fresh tickets still start from the project integration branch. ' +
|
|
52
|
+
'For on_review tickets with an already-open GitHub PR (including a published pr_ready delivery), launch automatically tries to continue that PR head branch; Jira-linked in_progress tickets can do the same when the PR match is explicit; fresh tickets still start from the project integration branch. ' +
|
|
33
53
|
'When launched from the in-app agent chat without an explicit aiEngine, the engine defaults to your conversation\'s provider (pass aiEngine to override; launch_all always uses each rail\'s stored engine). ' +
|
|
34
54
|
'User-facing naming: call the free-form autonomous mode "Freestyle"; use "freestyle" as the canonical API enum value for that same capability. ' +
|
|
35
55
|
'NAMING: railIndex is the 0-BASED internal identity; the dashboard shows rails 1-based ("Rail N" = railIndex N-1). When talking to the user, ALWAYS say "Rail <railIndex + 1>" (or the rail\'s custom name) — results include railLabel with the correct user-facing label.',
|
|
@@ -236,7 +256,7 @@ function railsTools() {
|
|
|
236
256
|
return {
|
|
237
257
|
...r,
|
|
238
258
|
railLabel,
|
|
239
|
-
hint: `Launch accepted (202) on ${railLabel} (isolated worktree, PR flow active) — tell the user it runs on "${railLabel}" (UI labels are 1-based). If the assigned spec is on_review with a matching open PR, or is Jira-linked in_progress with an explicit PR match, Specrails continues that PR branch automatically; otherwise it starts a fresh branch from the integration branch. The PR-decision card will appear here and on the rail header when it settles. Use specrails_watch with the returned loopRunIds to await completion only if asked. Rails run for minutes; pass untilMs up to 600000 and re-watch on timeout.`,
|
|
259
|
+
hint: `Launch accepted (202) on ${railLabel} (isolated worktree, PR flow active) — tell the user it runs on "${railLabel}" (UI labels are 1-based). If the assigned spec is on_review with a matching open PR, including an already-published pr_ready PR, or is Jira-linked in_progress with an explicit PR match, Specrails continues that PR branch automatically; otherwise it starts a fresh branch from the integration branch. The PR-decision card will appear here and on the rail header when it settles. Use specrails_watch with the returned loopRunIds to await completion only if asked. Rails run for minutes; pass untilMs up to 600000 and re-watch on timeout.`,
|
|
240
260
|
};
|
|
241
261
|
}
|
|
242
262
|
case 'launch_all': {
|
|
@@ -244,8 +264,9 @@ function railsTools() {
|
|
|
244
264
|
// because each launch isolates its work in per-ticket git worktrees
|
|
245
265
|
// (allocation is serialized per repo by the launch path itself).
|
|
246
266
|
// Eligibility mirrors the dashboard's Launch-all control: the rail
|
|
247
|
-
// must hold tickets, have no active job/loop run, and no
|
|
248
|
-
// PR delivery.
|
|
267
|
+
// must hold tickets, have no active job/loop run, and no uncontinuable
|
|
268
|
+
// PR delivery. A draft/published PR covering the rail's tickets is
|
|
269
|
+
// intentionally continuable. Each rail launches with its OWN stored config
|
|
249
270
|
// (mode/engine/profile) — conversation-provider defaults do NOT
|
|
250
271
|
// apply here (they would clobber per-rail engines).
|
|
251
272
|
const snapshot = (await (0, types_1.apiCall)(ctx, 'GET', base));
|
|
@@ -267,7 +288,7 @@ function railsTools() {
|
|
|
267
288
|
results.push({ railIndex: idx, outcome: 'skipped', reason: 'already-running', ticketIds });
|
|
268
289
|
continue;
|
|
269
290
|
}
|
|
270
|
-
if (key in prDeliveries) {
|
|
291
|
+
if (key in prDeliveries && !prDeliveryContinuesTickets(prDeliveries[key], ticketIds)) {
|
|
271
292
|
results.push({ railIndex: idx, outcome: 'skipped', reason: 'pr-decision-pending', ticketIds });
|
|
272
293
|
continue;
|
|
273
294
|
}
|