specrails-desktop 2.29.4 → 2.30.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/client/dist/assets/{ActivityFeedPage-CDMzpGXd.js → ActivityFeedPage-AQgpr9qG.js} +1 -1
- package/client/dist/assets/{AgentBrowserCapture-BVTacapZ.js → AgentBrowserCapture-I7a0usG7.js} +1 -1
- package/client/dist/assets/AgentModeCodePane-BqOVg15n.js +2 -0
- package/client/dist/assets/{AgentModeJobsPane-DAjN8Au5.js → AgentModeJobsPane-4SG6FF27.js} +1 -1
- package/client/dist/assets/{AgentsPage-CebykajE.js → AgentsPage-C3FgYlEi.js} +1 -1
- package/client/dist/assets/{AnalyticsPage-BiPrVvgv.js → AnalyticsPage-BcMNByW5.js} +1 -1
- package/client/dist/assets/{CodePage-Dw9eQFRS.js → CodePage-CgdDkXp-.js} +1 -1
- package/client/dist/assets/{DesktopAnalyticsPage-cCG_JAEi.js → DesktopAnalyticsPage-DPMcS88n.js} +1 -1
- package/client/dist/assets/{DocsDialog-C1kZ_mRP.js → DocsDialog-BC7574Zi.js} +1 -1
- package/client/dist/assets/{DocsPage-3GivxWJm.js → DocsPage-Dd9yilUg.js} +1 -1
- package/client/dist/assets/{InteractiveJobComposer-KuZXGdr8.js → InteractiveJobComposer-CqC_0VQL.js} +1 -1
- package/client/dist/assets/{JobDetailModal-DWpRALkB.js → JobDetailModal-BFNXOhk1.js} +1 -1
- package/client/dist/assets/{JobDetailPage-mrXDKafj.js → JobDetailPage-DM-6zYpA.js} +1 -1
- package/client/dist/assets/{JobsPage-CUYXjcoc.js → JobsPage-1dkjPk1k.js} +1 -1
- package/client/dist/assets/{LoopBuilderPage-CwjBD5Gm.js → LoopBuilderPage-BPeqz6cG.js} +1 -1
- package/client/dist/assets/{LoopPreviewModal-CO9ton0-.js → LoopPreviewModal-EdkyYaGN.js} +1 -1
- package/client/dist/assets/{LoopsPage-CLL5UuvN.js → LoopsPage-nZfgiaK8.js} +1 -1
- package/client/dist/assets/{MinimizedChatsContext-DJAkRYps.js → MinimizedChatsContext-Cs34FPTz.js} +1 -1
- package/client/dist/assets/{PluginsPage-DZvCC5Ri.js → PluginsPage-CwFfFBzW.js} +1 -1
- package/client/dist/assets/{ProjectSettingsDialog-C7Hesadg.js → ProjectSettingsDialog-DHsxLFMT.js} +1 -1
- package/client/dist/assets/{TemplatePreviewModal-DczCzUzP.js → TemplatePreviewModal-wcI3nGNr.js} +1 -1
- package/client/dist/assets/TicketDetailModal-7EloKP1C.js +14 -0
- package/client/dist/assets/{Trans-Cm9rhdnG.js → Trans-CPISVji8.js} +1 -1
- package/client/dist/assets/agent-BABjRt0P.js +1 -0
- package/client/dist/assets/agent-BuUpgqVx.js +1 -0
- package/client/dist/assets/agent-CCDZesgU.js +1 -0
- package/client/dist/assets/agent-CVn64zWH.js +1 -0
- package/client/dist/assets/agent-CWeOny0E.js +1 -0
- package/client/dist/assets/agent-DOysmad_.js +1 -0
- package/client/dist/assets/agent-DSsjTBhn.js +1 -0
- package/client/dist/assets/agent-DlZMxfM9.js +1 -0
- package/client/dist/assets/builder-BH8Fua-g.js +1 -0
- package/client/dist/assets/builder-BoV7DgKd.js +1 -0
- package/client/dist/assets/builder-Cc_Lf79C.js +1 -0
- package/client/dist/assets/builder-CwA4T7gP.js +1 -0
- package/client/dist/assets/builder-CwZ7Bme2.js +1 -0
- package/client/dist/assets/builder-CxW-JFsR.js +1 -0
- package/client/dist/assets/builder-D94lrV7x.js +1 -0
- package/client/dist/assets/builder-cqHpCyGa.js +1 -0
- package/client/dist/assets/{dist-js-BERxOT0X.js → dist-js-Bt2zW2YG.js} +1 -1
- package/client/dist/assets/{dist-js-Di8lflPo.js → dist-js-zvt5ap3o.js} +1 -1
- package/client/dist/assets/{formatDistanceToNow-BAXZRbEO.js → formatDistanceToNow-ByKli7Q_.js} +1 -1
- package/client/dist/assets/{getTimezoneOffsetInMilliseconds-DwzZXHtg.js → getTimezoneOffsetInMilliseconds-qrcBaLW1.js} +1 -1
- package/client/dist/assets/i18n-Bf9Ckd10.js +2 -0
- package/client/dist/assets/index-Dh9i4CnN.css +2 -0
- package/client/dist/assets/index-xkzK3E5i.js +76 -0
- package/client/dist/assets/setup-3832BJCo.js +1 -0
- package/client/dist/assets/setup-B8J-gECe.js +1 -0
- package/client/dist/assets/setup-BCIOxVsc.js +1 -0
- package/client/dist/assets/setup-BciLj_tU.js +1 -0
- package/client/dist/assets/setup-CITtPjed.js +1 -0
- package/client/dist/assets/setup-CTkE3cfh.js +1 -0
- package/client/dist/assets/setup-ajB4rYm-.js +1 -0
- package/client/dist/assets/setup-xFO1wNl0.js +1 -0
- package/client/dist/assets/{spending-BLb5pj6G.js → spending-DMnCXy84.js} +1 -1
- package/client/dist/assets/{useBrowserCaptureSession-DR1_jL56.js → useBrowserCaptureSession-CkBJShUw.js} +1 -1
- package/client/dist/assets/{useDesktop-D4DxBGPU.js → useDesktop-B4pSBIDd.js} +1 -1
- package/client/dist/index.html +14 -13
- package/docs/codex.md +2 -1
- package/docs/customizing.md +1 -1
- package/docs/internals/gemini-mcp-registration.md +1 -1
- package/docs/internals/global-artifacts-alignment-contract.md +4 -4
- package/docs/internals/project-builder.md +306 -0
- package/docs/internals/safe-pr-review-flow.md +29 -19
- package/package.json +1 -1
- package/server/dist/agent-operator-prompt.js +7 -1
- package/server/dist/blueprint-chat-manager.js +335 -0
- package/server/dist/blueprint-commit.js +335 -0
- package/server/dist/blueprint-draft-parser.js +168 -0
- package/server/dist/blueprint-operator-prompt.js +149 -0
- package/server/dist/blueprint-render.js +105 -0
- package/server/dist/blueprint-router.js +173 -0
- package/server/dist/blueprint-spec-quality.js +167 -0
- package/server/dist/blueprint-store.js +49 -0
- package/server/dist/blueprint-types.js +29 -0
- package/server/dist/builder-cwd-manager.js +57 -0
- package/server/dist/chat-manager.js +435 -23
- package/server/dist/context-scope.js +6 -3
- package/server/dist/contract-refine-runner.js +143 -72
- package/server/dist/desktop-db.js +27 -0
- package/server/dist/index.js +15 -0
- package/server/dist/offline-assemble.js +203 -0
- package/server/dist/pricing.js +5 -0
- package/server/dist/project-router-chat.js +14 -2
- package/server/dist/project-router.js +130 -7
- package/server/dist/providers/claude-adapter.js +8 -2
- package/server/dist/providers/codex-adapter.js +23 -10
- package/server/dist/providers/gemini-adapter.js +16 -7
- package/server/dist/rail-isolated-launch.js +11 -1
- package/server/dist/setup-manager.js +6 -54
- package/server/dist/spec-models.js +3 -0
- package/server/dist/workspace-manager.js +3 -1
- package/server/dist/worktree-overlay.js +233 -51
- package/client/dist/assets/AgentModeCodePane-D9bhFyuy.js +0 -2
- package/client/dist/assets/TicketDetailModal-CFh7GOv5.js +0 -14
- package/client/dist/assets/agent-BXc59ARK2.js +0 -1
- package/client/dist/assets/agent-BbIFXdDq.js +0 -1
- package/client/dist/assets/agent-BqEfA5u5.js +0 -1
- package/client/dist/assets/agent-BtGzgTC4.js +0 -1
- package/client/dist/assets/agent-CIhys_5d.js +0 -1
- package/client/dist/assets/agent-CJPaqsVR.js +0 -1
- package/client/dist/assets/agent-n-hY4GuL.js +0 -1
- package/client/dist/assets/agent-tJ-efa3_2.js +0 -1
- package/client/dist/assets/i18n-cK5pPbj8.js +0 -2
- package/client/dist/assets/index-BT6xDQjB.css +0 -2
- package/client/dist/assets/index-CCq_kIrF.js +0 -76
- package/client/dist/assets/setup-CGZjy2IF2.js +0 -1
- package/client/dist/assets/setup-CXa0Sx16.js +0 -1
- package/client/dist/assets/setup-CmK87LuS.js +0 -1
- package/client/dist/assets/setup-D2ktKKMF2.js +0 -1
- package/client/dist/assets/setup-DG2H7ha5.js +0 -1
- package/client/dist/assets/setup-DK5bHDUq2.js +0 -1
- package/client/dist/assets/setup-DrWlIQTZ.js +0 -1
- package/client/dist/assets/setup-rzHUVgAu.js +0 -1
- /package/client/dist/assets/{activity-C6kJpm9q2.js → activity-C6kJpm9q.js} +0 -0
- /package/client/dist/assets/{activity-DAyekdlt2.js → activity-DAyekdlt.js} +0 -0
- /package/client/dist/assets/{addspec-DbNBbrha2.js → addspec-DbNBbrha.js} +0 -0
- /package/client/dist/assets/{addspec-htHGZHOe2.js → addspec-htHGZHOe.js} +0 -0
- /package/client/dist/assets/{agents-6ZOJXWVk2.js → agents-6ZOJXWVk.js} +0 -0
- /package/client/dist/assets/{agents-Bz-thHkB2.js → agents-Bz-thHkB.js} +0 -0
- /package/client/dist/assets/{agentstudio-BLGvxWBx2.js → agentstudio-BLGvxWBx.js} +0 -0
- /package/client/dist/assets/{agentstudio-D9UKiWTj2.js → agentstudio-D9UKiWTj.js} +0 -0
- /package/client/dist/assets/{aiedit-BoG24nlg2.js → aiedit-BoG24nlg.js} +0 -0
- /package/client/dist/assets/{aiedit-olnv3QSt2.js → aiedit-olnv3QSt.js} +0 -0
- /package/client/dist/assets/{analytics-CdsAPAwZ2.js → analytics-CdsAPAwZ.js} +0 -0
- /package/client/dist/assets/{analytics-IEsKZvpW2.js → analytics-IEsKZvpW.js} +0 -0
- /package/client/dist/assets/{attachments-D0wXXt9T2.js → attachments-D0wXXt9T.js} +0 -0
- /package/client/dist/assets/{attachments-V_WZAYXx2.js → attachments-V_WZAYXx.js} +0 -0
- /package/client/dist/assets/{browser-CyR1Kp3m2.js → browser-CyR1Kp3m.js} +0 -0
- /package/client/dist/assets/{browser-DwZljcRh2.js → browser-DwZljcRh.js} +0 -0
- /package/client/dist/assets/{chat-BR8oe53x2.js → chat-BR8oe53x.js} +0 -0
- /package/client/dist/assets/{chat-DZyu3ImY2.js → chat-DZyu3ImY.js} +0 -0
- /package/client/dist/assets/{code-D20ef9Cf2.js → code-D20ef9Cf.js} +0 -0
- /package/client/dist/assets/{code-geHmknB92.js → code-geHmknB9.js} +0 -0
- /package/client/dist/assets/{commands-BEwbAjtD2.js → commands-BEwbAjtD.js} +0 -0
- /package/client/dist/assets/{commands-DTQBF_q52.js → commands-DTQBF_q5.js} +0 -0
- /package/client/dist/assets/{common-BNbnv8cE2.js → common-BNbnv8cE.js} +0 -0
- /package/client/dist/assets/{common-DBtTzeYm2.js → common-DBtTzeYm.js} +0 -0
- /package/client/dist/assets/{dashboard-Cqmmbh3l2.js → dashboard-Cqmmbh3l.js} +0 -0
- /package/client/dist/assets/{dashboard-Dy2Um-US2.js → dashboard-Dy2Um-US.js} +0 -0
- /package/client/dist/assets/{explore-C0TjprJW2.js → explore-C0TjprJW.js} +0 -0
- /package/client/dist/assets/{explore-DsXAgnmJ2.js → explore-DsXAgnmJ.js} +0 -0
- /package/client/dist/assets/{integrations-CH0zy1Mw2.js → integrations-CH0zy1Mw.js} +0 -0
- /package/client/dist/assets/{integrations-b8pH-vfl2.js → integrations-b8pH-vfl.js} +0 -0
- /package/client/dist/assets/{jira-CNeYi06w2.js → jira-CNeYi06w.js} +0 -0
- /package/client/dist/assets/{jira-pRaL7JQo2.js → jira-pRaL7JQo.js} +0 -0
- /package/client/dist/assets/{jobs-B-sDHEay2.js → jobs-B-sDHEay.js} +0 -0
- /package/client/dist/assets/{jobs-DzSIR8V62.js → jobs-DzSIR8V6.js} +0 -0
- /package/client/dist/assets/{loops-Crc9It8o2.js → loops-Crc9It8o.js} +0 -0
- /package/client/dist/assets/{loops-DH2hZcbK2.js → loops-DH2hZcbK.js} +0 -0
- /package/client/dist/assets/{loops-DS5TmvIU2.js → loops-DS5TmvIU.js} +0 -0
- /package/client/dist/assets/{mcp-Czd_iyp02.js → mcp-Czd_iyp0.js} +0 -0
- /package/client/dist/assets/{mcp-D4ZjtIx32.js → mcp-D4ZjtIx3.js} +0 -0
- /package/client/dist/assets/{mcp-DIfBUv2D2.js → mcp-DIfBUv2D.js} +0 -0
- /package/client/dist/assets/{nav-BRJBxaGt2.js → nav-BRJBxaGt.js} +0 -0
- /package/client/dist/assets/{nav-CNskRJKQ2.js → nav-CNskRJKQ.js} +0 -0
- /package/client/dist/assets/{nav-TvumAFD22.js → nav-TvumAFD2.js} +0 -0
- /package/client/dist/assets/{settings-DAZqjX2a2.js → settings-DAZqjX2a.js} +0 -0
- /package/client/dist/assets/{settings-DRh39v1S2.js → settings-DRh39v1S.js} +0 -0
- /package/client/dist/assets/{settings-Mj1OJbfd2.js → settings-Mj1OJbfd.js} +0 -0
- /package/client/dist/assets/{specs-BcyxaCwf2.js → specs-BcyxaCwf.js} +0 -0
- /package/client/dist/assets/{specs-CLZKysq-2.js → specs-CLZKysq-.js} +0 -0
- /package/client/dist/assets/{specs-dV3Mq5Mu2.js → specs-dV3Mq5Mu.js} +0 -0
- /package/client/dist/assets/{terminal-C2NAd7BW2.js → terminal-C2NAd7BW.js} +0 -0
- /package/client/dist/assets/{terminal-IahE4LW92.js → terminal-IahE4LW9.js} +0 -0
- /package/client/dist/assets/{terminal-QpXZU2Bn2.js → terminal-QpXZU2Bn.js} +0 -0
- /package/client/dist/assets/{tickets-Bs37scwY2.js → tickets-Bs37scwY.js} +0 -0
- /package/client/dist/assets/{tickets-DQp7JS2R2.js → tickets-DQp7JS2R.js} +0 -0
- /package/client/dist/assets/{tickets-DpmdE8tv2.js → tickets-DpmdE8tv.js} +0 -0
package/client/dist/index.html
CHANGED
|
@@ -204,7 +204,7 @@
|
|
|
204
204
|
.specrails-splash__mark .pill { opacity: 1; }
|
|
205
205
|
}
|
|
206
206
|
</style>
|
|
207
|
-
<script type="module" crossorigin src="/assets/index-
|
|
207
|
+
<script type="module" crossorigin src="/assets/index-xkzK3E5i.js"></script>
|
|
208
208
|
<link rel="modulepreload" crossorigin href="/assets/rolldown-runtime-CNC7AqOf.js">
|
|
209
209
|
<link rel="modulepreload" crossorigin href="/assets/jsx-runtime-zu2_FqZY.js">
|
|
210
210
|
<link rel="modulepreload" crossorigin href="/assets/react-dom-DiWzBDP9.js">
|
|
@@ -213,13 +213,14 @@
|
|
|
213
213
|
<link rel="modulepreload" crossorigin href="/assets/createLucideIcon-Bjbbp_KS.js">
|
|
214
214
|
<link rel="modulepreload" crossorigin href="/assets/activity-DiyjsgQV.js">
|
|
215
215
|
<link rel="modulepreload" crossorigin href="/assets/addspec-Rw8uVBC1.js">
|
|
216
|
-
<link rel="modulepreload" crossorigin href="/assets/agent-
|
|
216
|
+
<link rel="modulepreload" crossorigin href="/assets/agent-BuUpgqVx.js">
|
|
217
217
|
<link rel="modulepreload" crossorigin href="/assets/agents-DhG7mg6-.js">
|
|
218
218
|
<link rel="modulepreload" crossorigin href="/assets/agentstudio-BIUe1Im2.js">
|
|
219
219
|
<link rel="modulepreload" crossorigin href="/assets/aiedit-iIjz2_Qk.js">
|
|
220
220
|
<link rel="modulepreload" crossorigin href="/assets/analytics-DZ8Aoq3I.js">
|
|
221
221
|
<link rel="modulepreload" crossorigin href="/assets/attachments-B53PG733.js">
|
|
222
222
|
<link rel="modulepreload" crossorigin href="/assets/browser-CXUcnTMI.js">
|
|
223
|
+
<link rel="modulepreload" crossorigin href="/assets/builder-Cc_Lf79C.js">
|
|
223
224
|
<link rel="modulepreload" crossorigin href="/assets/chat-BGD7MXAy.js">
|
|
224
225
|
<link rel="modulepreload" crossorigin href="/assets/code-BDXEM4ml.js">
|
|
225
226
|
<link rel="modulepreload" crossorigin href="/assets/commands-DyUZQ1FI.js">
|
|
@@ -233,23 +234,23 @@
|
|
|
233
234
|
<link rel="modulepreload" crossorigin href="/assets/mcp-uDkXYu4L.js">
|
|
234
235
|
<link rel="modulepreload" crossorigin href="/assets/nav-myFaXRHD.js">
|
|
235
236
|
<link rel="modulepreload" crossorigin href="/assets/settings-B0ypw9uw.js">
|
|
236
|
-
<link rel="modulepreload" crossorigin href="/assets/setup-
|
|
237
|
+
<link rel="modulepreload" crossorigin href="/assets/setup-ajB4rYm-.js">
|
|
237
238
|
<link rel="modulepreload" crossorigin href="/assets/specs-DII0C8gw.js">
|
|
238
239
|
<link rel="modulepreload" crossorigin href="/assets/terminal-BFRZnMPP.js">
|
|
239
240
|
<link rel="modulepreload" crossorigin href="/assets/tickets-D_yDquEw.js">
|
|
240
|
-
<link rel="modulepreload" crossorigin href="/assets/i18n-
|
|
241
|
-
<link rel="modulepreload" crossorigin href="/assets/Trans-
|
|
241
|
+
<link rel="modulepreload" crossorigin href="/assets/i18n-Bf9Ckd10.js">
|
|
242
|
+
<link rel="modulepreload" crossorigin href="/assets/Trans-CPISVji8.js">
|
|
242
243
|
<link rel="modulepreload" crossorigin href="/assets/dist-bVqfYmby.js">
|
|
243
244
|
<link rel="modulepreload" crossorigin href="/assets/arrow-left-CpIR4j7G.js">
|
|
244
245
|
<link rel="modulepreload" crossorigin href="/assets/auth-D_5bQv5W.js">
|
|
245
246
|
<link rel="modulepreload" crossorigin href="/assets/api-B2M7CtDw.js">
|
|
246
|
-
<link rel="modulepreload" crossorigin href="/assets/useBrowserCaptureSession-
|
|
247
|
+
<link rel="modulepreload" crossorigin href="/assets/useBrowserCaptureSession-CkBJShUw.js">
|
|
247
248
|
<link rel="modulepreload" crossorigin href="/assets/arrow-up-right-9DoMn7fD.js">
|
|
248
249
|
<link rel="modulepreload" crossorigin href="/assets/sparkles-DrY8hb0X.js">
|
|
249
250
|
<link rel="modulepreload" crossorigin href="/assets/x-CBMI9ejn.js">
|
|
250
251
|
<link rel="modulepreload" crossorigin href="/assets/useSharedWebSocket-DaPh7QBL.js">
|
|
251
|
-
<link rel="modulepreload" crossorigin href="/assets/useDesktop-
|
|
252
|
-
<link rel="modulepreload" crossorigin href="/assets/MinimizedChatsContext-
|
|
252
|
+
<link rel="modulepreload" crossorigin href="/assets/useDesktop-B4pSBIDd.js">
|
|
253
|
+
<link rel="modulepreload" crossorigin href="/assets/MinimizedChatsContext-Cs34FPTz.js">
|
|
253
254
|
<link rel="modulepreload" crossorigin href="/assets/external-link-BcU5EWZp.js">
|
|
254
255
|
<link rel="modulepreload" crossorigin href="/assets/chevron-right-CViMxucY.js">
|
|
255
256
|
<link rel="modulepreload" crossorigin href="/assets/circle-x-CMYsN4ZH.js">
|
|
@@ -272,11 +273,11 @@
|
|
|
272
273
|
<link rel="modulepreload" crossorigin href="/assets/dialog-CzIekCw0.js">
|
|
273
274
|
<link rel="modulepreload" crossorigin href="/assets/jira-api-BgFIr8eD.js">
|
|
274
275
|
<link rel="modulepreload" crossorigin href="/assets/lib-CGdyxIWg.js">
|
|
275
|
-
<link rel="modulepreload" crossorigin href="/assets/getTimezoneOffsetInMilliseconds-
|
|
276
|
-
<link rel="modulepreload" crossorigin href="/assets/formatDistanceToNow-
|
|
277
|
-
<link rel="modulepreload" crossorigin href="/assets/spending-
|
|
278
|
-
<link rel="modulepreload" crossorigin href="/assets/TicketDetailModal-
|
|
279
|
-
<link rel="stylesheet" crossorigin href="/assets/index-
|
|
276
|
+
<link rel="modulepreload" crossorigin href="/assets/getTimezoneOffsetInMilliseconds-qrcBaLW1.js">
|
|
277
|
+
<link rel="modulepreload" crossorigin href="/assets/formatDistanceToNow-ByKli7Q_.js">
|
|
278
|
+
<link rel="modulepreload" crossorigin href="/assets/spending-DMnCXy84.js">
|
|
279
|
+
<link rel="modulepreload" crossorigin href="/assets/TicketDetailModal-7EloKP1C.js">
|
|
280
|
+
<link rel="stylesheet" crossorigin href="/assets/index-Dh9i4CnN.css">
|
|
280
281
|
</head>
|
|
281
282
|
<body>
|
|
282
283
|
<div id="specrails-splash" aria-hidden="false" role="status" aria-label="Loading Specrails">
|
package/docs/codex.md
CHANGED
|
@@ -116,7 +116,8 @@ the [Gemini guide](gemini.md).)
|
|
|
116
116
|
| **Min CLI version** | none pinned | `0.128.0` | `0.11.0` |
|
|
117
117
|
| **Project dir** | `.claude/` | `.codex/` | `.gemini/` |
|
|
118
118
|
| **Instructions file** | `CLAUDE.md` | `AGENTS.md` | `GEMINI.md` |
|
|
119
|
-
| **Default model** | `sonnet` | `gpt-5.5` | `gemini-3.5-flash` |
|
|
119
|
+
| **Default model** | `sonnet` | `gpt-5.5` (catalog includes the GPT-5.6 family: `gpt-5.6-sol` / `gpt-5.6-terra` / `gpt-5.6-luna`) | `gemini-3.5-flash` |
|
|
120
|
+
| **Reasoning efforts** | `low`–`xhigh` | `minimal`–`ultra` (`xhigh`/`max`/`ultra` ship with GPT-5.6; `ultra` is Sol-only upstream) | none |
|
|
120
121
|
| **Agent format** | `.claude/agents/<id>.md` with `model:` frontmatter | `.codex/skills/<id>/SKILL.md` Skill format | `.gemini/` command + agent target |
|
|
121
122
|
| **Agent profiles** | Full support (rail `RailProfileSelector`) | **None** — rails force the profile to `null` | **None** — rails force the profile to `null` |
|
|
122
123
|
| **Pipeline rails** | ✅ all rail types | ✅ (except Freestyle) | ✅ (except Freestyle) |
|
package/docs/customizing.md
CHANGED
|
@@ -161,7 +161,7 @@ Most settings live in the UI. A few app-level switches are env-only because they
|
|
|
161
161
|
| `SPECRAILS_GEMINI_BETA=0` | Emergency rollback — disable the Gemini provider (default unset = enabled; only the exact string `0` disables; **no legacy fallback name**) |
|
|
162
162
|
| `SPECRAILS_SMASH=0` | Kill switch for SMASH spec decomposition (`0` / `false` / `off`; endpoints return 409) |
|
|
163
163
|
| `SPECRAILS_EXPLORE_CONTRACT_REFINE=0` | App-wide kill switch for Contract Refine (auto-fire + retry endpoint; accepts `0` / `false` / `off`) |
|
|
164
|
-
| `SPECRAILS_EXPLORE_LEGACY_CWD=1` | Force Explore
|
|
164
|
+
| `SPECRAILS_EXPLORE_LEGACY_CWD=1` | Force every Explore spawn to use the project root instead of the app-managed `explore-cwd/` or a relocated workspace |
|
|
165
165
|
| `SPECRAILS_FILE_SUMMARY_MODEL` | Override the model used for Code-section file summaries. Per-provider overrides take precedence: `SPECRAILS_FILE_SUMMARY_MODEL_CLAUDE` (Claude) and `SPECRAILS_FILE_SUMMARY_MODEL_CODEX` (Codex); the generic var is the fallback |
|
|
166
166
|
| `SPECRAILS_ALLOW_LOCAL_WEBHOOKS=1` | Allow outbound webhooks to target loopback / private-network addresses |
|
|
167
167
|
|
|
@@ -38,7 +38,7 @@ loads** for gemini:
|
|
|
38
38
|
|---|---|---|
|
|
39
39
|
| Plugins on rails (`server/plugin-manager.ts`, e.g. Serena) | surgical merge into `<project>/.mcp.json` for `project-json` providers | plugin installs "successfully", MCP server never loads in gemini rail spawns |
|
|
40
40
|
| Workspace MCP (`server/agent-mcp-config.ts` `mergeSpecrailsIntoWorkspaceMcp`, via `workspace-manager.ts`) | writes `<workspace>/.mcp.json` | not read by gemini |
|
|
41
|
-
| Explore `context_scope.mcp` (`server/chat-manager.ts`) | spawns from `<project.path>` so `.mcp.json` loads | loads nothing on gemini |
|
|
41
|
+
| Explore `context_scope.mcp` (`server/chat-manager.ts`) | spawns from the relocation-aware artifact cwd (workspace when relocated, `<project.path>` when legacy) so `.mcp.json` loads | loads nothing on gemini |
|
|
42
42
|
|
|
43
43
|
Fixing these means writing into the repo's / workspace's `.gemini/settings.json`, which
|
|
44
44
|
intersects the **pristine-repo / artifact-relocation policy** (the app must not mutate the
|
|
@@ -239,7 +239,7 @@ $HOME/.specrails/
|
|
|
239
239
|
├── jira-secret.key # keyfile AES-256-GCM (0600), desktop-only
|
|
240
240
|
├── doctor.log # log append-only, core-only (única lectura $HOME de core hoy)
|
|
241
241
|
└── projects/<slug>/
|
|
242
|
-
├── workspace/ # = artifactRoot. cwd de
|
|
242
|
+
├── workspace/ # = artifactRoot. cwd de jobs y Explore mcp=true relocalizados
|
|
243
243
|
│ ├── .specrails/
|
|
244
244
|
│ │ ├── local-tickets.json (+ .lock) ← SPECRAILS_TICKETS_PATH [core escribe/lee · desktop escribe]
|
|
245
245
|
│ │ ├── backlog-config.json ← SPECRAILS_BACKLOG_CONFIG_PATH [desktop escribe · core lee]
|
|
@@ -365,9 +365,9 @@ El lado desktop ya tiene el precedente load-bearing en producción (`explore-cwd
|
|
|
365
365
|
|
|
366
366
|
### 6.1 cwd de spawn + env por provider
|
|
367
367
|
|
|
368
|
-
`ExploreCwdManager` se generaliza a un `WorkspaceManager` que materializa `~/.specrails/projects/<slug>/workspace/` con `./project -> <project.path>` (symlink/junction, fallback `project-path.txt` — la lógica existente `ensureProjectLink`). **
|
|
368
|
+
`ExploreCwdManager` se generaliza a un `WorkspaceManager` que materializa `~/.specrails/projects/<slug>/workspace/` con `./project -> <project.path>` (symlink/junction, fallback `project-path.txt` — la lógica existente `ensureProjectLink`). **Las AI-CLI relocalizadas usan el workspace salvo los procesos deliberadamente repo-bound y Explore con `mcp=false`, que conserva su `explore-cwd`.**
|
|
369
369
|
|
|
370
|
-
**Managers que MUEVEN cwd → workspace:** `QueueManager._startJob` (rails — el grande), `ChatManager` (
|
|
370
|
+
**Managers que MUEVEN cwd → workspace:** `QueueManager._startJob` (rails — el grande), `ChatManager` (sidebar + Explore con `mcp=true`), `AgentRefineManager` (ai-edit), `ContractRefineRunner` cuando refleja un Explore `mcp=true`, `project-router /tickets/generate-spec` (quick-spec), `FileSummaryManager`, `SetupManager.startInstall` (corre `npx specrails-core init --root-dir <project.path> --workspace-dir <workspace>`). Explore y Contract Refine con `mcp=false` permanecen en el app-managed `explore-cwd`.
|
|
371
371
|
|
|
372
372
|
**Managers que CONSERVAN cwd = `project.path`:** `TerminalManager` (shell repo-bound), `file-provenance.ts` (git repo-bound), `code-explorer-router` (lee fuente), lecturas de fuente de `FileSummaryManager`, `metrics.ts` (coverage).
|
|
373
373
|
|
|
@@ -380,7 +380,7 @@ El lado desktop ya tiene el precedente load-bearing en producción (`explore-cwd
|
|
|
380
380
|
- **Smoke check (manual):** en un proyecto relocalizado con provider=codex, lanzar un loop "Implement" cuyo paso de fix deba editar una fuente del repo; confirmar en el transcript que (a) `apply_patch`/edit a `<repoDir>/...` **NO** devuelve `Operation not permitted`, y (b) `npm run build`/`tsc -b` puede escribir `node_modules/.tmp/*.tsbuildinfo`. Reproducción del fallo: revertir el `extraArgs` de codex → la edición del repo en la iteración ≥2 vuelve a fallar con `Operation not permitted`. Cubierto por `server/loop-executors.test.ts` (assert del arg `writable_roots`).
|
|
381
381
|
- **gemini**: inyecta `GEMINI_CLI_TRUST_WORKSPACE=true` (ancla el root confiable al workspace). **Re-keya** `~/.gemini/acknowledgments/agents.json` al workspace.
|
|
382
382
|
- Los tres: el workspace **estrictamente fuera del repo** y el discovery no debe seguir `./project` (mitiga la fuga por ancestor-walk de codex/gemini).
|
|
383
|
-
- **Caso especial Explore `mcp=true
|
|
383
|
+
- **Caso especial Explore `mcp=true` (implementado):** `ChatManager` resuelve el cwd mediante la misma puerta de relocalización: workspace cuando el proyecto está relocalizado, `project.path` en legacy. Las rutas persistent-stdin, crash-respawn y Contract Refine conservan esa misma pareja cwd/env. Una sesión anterior creada bajo el cwd del repo que devuelve exactamente `No conversation found with session ID` se invalida y reintenta fresh una sola vez desde el workspace (transcript persistido acotado para Explore; ticket sembrado y tools deshabilitadas para Contract Refine), nunca volviendo al repo. `SPECRAILS_EXPLORE_LEGACY_CWD=1` sigue forzando `project.path`.
|
|
384
384
|
|
|
385
385
|
### 6.2 Sitios de re-apuntado de path (`project.path` → workspace)
|
|
386
386
|
|
|
@@ -0,0 +1,306 @@
|
|
|
1
|
+
# Project Builder — as-built internals
|
|
2
|
+
|
|
3
|
+
> OpenSpec change `add-project-builder`. Greenfield project creation from an
|
|
4
|
+
> idea: a day-0 blueprint conversation, an orchestrated bootstrap commit, and a
|
|
5
|
+
> milestone lifecycle (Launch M1 batch rail, sidebar re-entry, Generate M2+).
|
|
6
|
+
|
|
7
|
+
## Entry + builder mode (reskin)
|
|
8
|
+
|
|
9
|
+
"+ Add Project" shows an **Existing | New** pre-screen (`AddProjectDialog`,
|
|
10
|
+
`chooser-existing` / `chooser-new` cards) when both `FEATURE_PROJECT_BUILDER`
|
|
11
|
+
(client) and the parent-wired `onOpenBuilder` callback are present. *Existing*
|
|
12
|
+
continues into the unchanged AddProjectDialog/setup-wizard flow; *New* calls
|
|
13
|
+
`AgentChatContext.builderMode.enter()` — the AGENT transforms into the Builder
|
|
14
|
+
(change `reskin-project-builder-into-agent-panel`; the original full-screen
|
|
15
|
+
`ProjectBuilderShell` overlay is deleted). Flags:
|
|
16
|
+
`VITE_FEATURE_PROJECT_BUILDER` (client) / `SPECRAILS_PROJECT_BUILDER` (server),
|
|
17
|
+
both default ON, `"false"` opts out (server flag 404s every `/api/blueprint/*`
|
|
18
|
+
route).
|
|
19
|
+
|
|
20
|
+
**Builder mode (client architecture):**
|
|
21
|
+
|
|
22
|
+
- `builderMode` slice on `AgentChatContext`: `{ active, enter, exit, session }`.
|
|
23
|
+
`enter()` also opens the floating panel outside Agent Mode; `exit()` aborts
|
|
24
|
+
the in-flight builder turn (`POST /abort`) and resets every session slice.
|
|
25
|
+
The agent's own chrome (project/mission selectors, conversation, queue,
|
|
26
|
+
pinned cards) is hidden while active but NEVER unmounted.
|
|
27
|
+
- Session logic in `client/src/hooks/useBuilderSession.ts` (extracted from the
|
|
28
|
+
retired shell): bootstrap, `blueprint.*` WS handling with NULL-SAFE identity
|
|
29
|
+
checks (a pre-bootstrap/pre-commit null ref must never match a null/absent
|
|
30
|
+
message id), phases, snapshot, send/commit/launch actions, `dirty` flag.
|
|
31
|
+
- `BuilderConversation` (`client/src/components/project-builder/`): the four
|
|
32
|
+
phases in the MISSION format — chat renders a centered message column with
|
|
33
|
+
the `BuilderComposer` docked at the bottom (centered card while empty,
|
|
34
|
+
mission-style); in Agent Mode the hero and docked cards share a `layoutId`,
|
|
35
|
+
so the first send morphs the agent smoothly down. Then commit
|
|
36
|
+
(`BlueprintCommitForm`), progress step list, done (Launch M1 / Open project).
|
|
37
|
+
Esc: commit→chat, chat→exit (confirm-gated when dirty).
|
|
38
|
+
- `BuilderComposer`: mirrors the mission composer's visual language — the SAME
|
|
39
|
+
provider/model/effort selectors (provider/model bind to the blueprint
|
|
40
|
+
conversation; reasoning effort is validated against the selected provider
|
|
41
|
+
and rides each send), surprise-me chip, native `resize-y` textarea, and the
|
|
42
|
+
same `SendHorizontal` action. Models and effort levels come from
|
|
43
|
+
`GET /api/blueprint/models?provider=`.
|
|
44
|
+
- `BuilderHalo`: orbiting ring — CSS `builder-halo-spin` keyframes over an
|
|
45
|
+
XOR-masked conic-gradient border band (follows ANY radius: circular on the
|
|
46
|
+
bubble/panel-header icon, card radius on the composer; no per-frame JS),
|
|
47
|
+
`motion` enter/exit, `prefers-reduced-motion` ⇒ static glow. It is strictly
|
|
48
|
+
an ENTRY flourish: shown on the fresh empty composer and the matching
|
|
49
|
+
bubble/panel-header identity, then removed as soon as the first work message
|
|
50
|
+
begins. Builder mode itself continues without a halo; there is no wind-down.
|
|
51
|
+
- Per UI mode: **board** — `AgentChatPanel` widens (860px) and gains an
|
|
52
|
+
attached blueprint side pane; **Agent Mode** — `AgentModeSurface` renders
|
|
53
|
+
the builder conversation and `AgentWorkspaceSidebar` swaps (AnimatePresence)
|
|
54
|
+
to `BlueprintPanel` + the Create-specs CTA, forced-expanded for the duration.
|
|
55
|
+
- The builder conversation stays on `blueprint_conversations` / `blueprint.*`
|
|
56
|
+
— never mixed into `agent_conversations` or the mission selector.
|
|
57
|
+
- `BlueprintPanel` M1 spec cards are clickable → `BlueprintSpecModal`
|
|
58
|
+
(hand-rolled body portal at z-[65], same tier as `LoopPreviewModal`; Esc +
|
|
59
|
+
backdrop close). At day 0 the specs are NOT tickets yet (only in the
|
|
60
|
+
snapshot), so this is a lightweight read-only preview — NOT the heavy
|
|
61
|
+
`TicketDetailModal`. Cards expose `shortSummary`, priority, and acceptance-
|
|
62
|
+
criteria count; the modal exposes the summary, priority, canonical five-
|
|
63
|
+
section description, and every separate acceptance criterion. The same panel
|
|
64
|
+
(and therefore the modal) is reused in the M2+ `MilestoneGenerateShell`, so
|
|
65
|
+
the user reviews the content that will become the authoritative tickets
|
|
66
|
+
(apart from the deterministic criteria fold). The detailed M2+ preview is
|
|
67
|
+
transient; the blueprint has no per-milestone detailed-spec collection.
|
|
68
|
+
|
|
69
|
+
## Day-0 chat (no project exists)
|
|
70
|
+
|
|
71
|
+
- **Manager**: `server/blueprint-chat-manager.ts` `BlueprintChatManager` — an
|
|
72
|
+
app-level sibling of `AgentChatManager` reusing `runAiCliInvocation`. Spawns
|
|
73
|
+
from `~/.specrails/builder-cwd/` (`server/builder-cwd-manager.ts`: always
|
|
74
|
+
re-written instruction files from `server/blueprint-operator-prompt.ts`, NO
|
|
75
|
+
`./project` symlink, NO MCP). Auto-heal: a resume that yields no text retries
|
|
76
|
+
fresh once. Abort keeps partial text and records `aborted`.
|
|
77
|
+
- **Persistence**: `blueprint_conversations` / `blueprint_messages` in
|
|
78
|
+
`desktop.sqlite` (migration 22; CRUD in `server/blueprint-store.ts`).
|
|
79
|
+
- **WS**: app-global `blueprint.stream` / `blueprint.done` / `blueprint.error`
|
|
80
|
+
(no `projectId`; NOT in the mobile-ws translation layer). `blueprint.done`
|
|
81
|
+
carries the STRIPPED `fullText` plus the last valid `blueprint` snapshot.
|
|
82
|
+
- **Accounting**: one `agent_invocations` row per settled turn with
|
|
83
|
+
`project_id NULL` (the Home-turn precedent). No backfill after creation.
|
|
84
|
+
- **REST**: `/api/blueprint/*` (`server/blueprint-router.ts`) — conversations
|
|
85
|
+
CRUD, `/send` (202, 409 while streaming), `/abort`, `/models`, `/commit`.
|
|
86
|
+
`/models` returns the provider's `efforts` catalog; `/send` accepts only a
|
|
87
|
+
catalog-valid `reasoning_effort`, and providers without the capability omit
|
|
88
|
+
the field when spawning.
|
|
89
|
+
- **Generation boundary**: interview turns and Surprise Me may complete the
|
|
90
|
+
product/flow/platform/stack/assumption/milestone proposal, but MUST keep
|
|
91
|
+
`m1Specs: []` and `specsComplete: false`. Detailed M1 generation starts only
|
|
92
|
+
after explicit user approval or a direct request to generate the backlog.
|
|
93
|
+
That next assistant turn emits the entire self-validated 5–10-spec M1 set in
|
|
94
|
+
ONE response containing ONE complete fenced snapshot. It never publishes a
|
|
95
|
+
partial subset as the latest draft; `specsComplete: true` appears only on the
|
|
96
|
+
complete set. If generation cannot finish, the prior non-complete proposal
|
|
97
|
+
remains the last valid state and cannot be committed.
|
|
98
|
+
|
|
99
|
+
## blueprint-draft protocol
|
|
100
|
+
|
|
101
|
+
Fenced ` ```blueprint-draft ` JSON blocks. FULL snapshots, LAST syntactically
|
|
102
|
+
valid block wins, streaming tail cut (unterminated trailing fence never
|
|
103
|
+
parsed/shown — `cutUnterminatedBlock`). Unknown keys dropped; missing or
|
|
104
|
+
non-integer `blueprintVersion` rejects the block. Parser pair:
|
|
105
|
+
`server/blueprint-draft-parser.ts` ⇄ `client/src/lib/blueprint-draft.ts` (keep
|
|
106
|
+
coercion rules in sync). Schema types in `server/blueprint-types.ts`:
|
|
107
|
+
`product{name,pitch,audience}`, `coreFlow`, `platform`,
|
|
108
|
+
`stack{language,framework,db,notes?}`, `assumptions[]`,
|
|
109
|
+
`milestones[]{id,title,goal,status: planned|committed|done, plannedSpecs[],
|
|
110
|
+
ticketIds?}` (ticketIds ADVISORY only), `specsComplete`, and detailed
|
|
111
|
+
`m1Specs[]{kind,title,shortSummary,description,acceptanceCriteria[],priority,
|
|
112
|
+
labels[],dependsOnIndex?}`. `kind` is `scaffold|feature|verification`; priority
|
|
113
|
+
is `low|medium|high|critical`. After approval, detailed M1 generation arrives
|
|
114
|
+
as one complete 5–10-spec snapshot with an explicit scaffold first. M2+
|
|
115
|
+
milestones carry `plannedSpecs` titles only until that milestone is explicitly
|
|
116
|
+
generated, at which point the target milestone's entire detailed set likewise
|
|
117
|
+
arrives in one assistant response/snapshot. The version stays 1: legacy
|
|
118
|
+
snapshots default missing `specsComplete=false`, `kind='feature'`,
|
|
119
|
+
`shortSummary=''`, criteria to `[]`, and missing/invalid priority to `medium`
|
|
120
|
+
on read. Those defaults preserve readability only; newly committed batches
|
|
121
|
+
must pass the strict quality gate.
|
|
122
|
+
|
|
123
|
+
Parsing deliberately retains two representations of the LAST valid block:
|
|
124
|
+
`blueprint` is the compatibility-normalized `Blueprint` used by preview/read
|
|
125
|
+
surfaces, while `rawBlueprint` is the exact parsed JSON before enum defaults,
|
|
126
|
+
dependency drops, or missing-field defaults. `blueprint.done` carries both;
|
|
127
|
+
the client mirrors the pair, derives readiness from the raw value, and sends
|
|
128
|
+
that raw value to M1/M2+ commit. Therefore an invalid `kind`, `priority`,
|
|
129
|
+
`dependsOnIndex`, or required field cannot disappear/default during rendering
|
|
130
|
+
and then pass the mutation gate. Persisted legacy files are a different read
|
|
131
|
+
boundary: `readBlueprint()` calls `coerceBlueprint()` server-side so old v1
|
|
132
|
+
files remain readable (and returns null for missing/corrupt input).
|
|
133
|
+
|
|
134
|
+
## Canonical rich-spec contract (M1 and generated M2+)
|
|
135
|
+
|
|
136
|
+
There is no Builder-specific “lite spec” format. Every detailed Builder spec
|
|
137
|
+
uses the normal Specrails contract:
|
|
138
|
+
|
|
139
|
+
1. `kind`: `scaffold`, `feature`, or `verification`
|
|
140
|
+
2. an English, action-oriented, unique `title`
|
|
141
|
+
3. a one-sentence `shortSummary` no longer than 240 characters
|
|
142
|
+
4. `description` with exactly these `##` headings, once and in this order:
|
|
143
|
+
`Problem Statement`, `Proposed Solution`, `Out of Scope`,
|
|
144
|
+
`Technical Considerations`, `Estimated Complexity`
|
|
145
|
+
5. a separate `acceptanceCriteria[]` containing 4–10 non-empty, independently
|
|
146
|
+
testable outcomes; `description` MUST NOT contain `## Acceptance Criteria`
|
|
147
|
+
6. a catalog-valid `priority`, non-empty domain labels, and an optional
|
|
148
|
+
`dependsOnIndex` that points strictly backward (the M1 scaffold omits it)
|
|
149
|
+
|
|
150
|
+
Every named description section has a non-empty body. `Out of Scope` and
|
|
151
|
+
`Technical Considerations` each contain at least 2 bullets; Estimated
|
|
152
|
+
Complexity includes a reasoned estimate. Day-0 technical considerations name
|
|
153
|
+
the selected stack, planned components/contracts, risks, and inter-spec
|
|
154
|
+
dependencies but never fabricate repository paths. Generated M2+ specs first
|
|
155
|
+
inspect the real project and may name only verified existing paths and
|
|
156
|
+
identifiers; their criteria cover behavior, failure/edge cases, and tests.
|
|
157
|
+
|
|
158
|
+
`server/blueprint-spec-quality.ts` is the shared deterministic authority. It
|
|
159
|
+
validates `specsComplete=true`, the complete-set size, all fields/sections
|
|
160
|
+
above (including both 2-bullet minima), unique titles, the M1 first-item
|
|
161
|
+
`kind='scaffold'` rule, and backward-only dependencies. Both commit paths run
|
|
162
|
+
it before any filesystem, registry, blueprint, milestone, or ticket-store
|
|
163
|
+
mutation and return a stable spec/field-oriented detail when it rejects. A
|
|
164
|
+
prompt is a generation aid, never the integrity boundary. Validation receives
|
|
165
|
+
the exact raw generated payload; normalized compatibility views are not
|
|
166
|
+
commit evidence.
|
|
167
|
+
|
|
168
|
+
## Orchestrated commit (register-project-LAST)
|
|
169
|
+
|
|
170
|
+
`POST /api/blueprint/commit` → sync validation (named errors: `invalid_name`,
|
|
171
|
+
`invalid_location`, `providers_required`, `unknown_provider`,
|
|
172
|
+
`invalid_blueprint`, `m1_specs_required`, `m1_specs_over_cap`,
|
|
173
|
+
`bundled_framework_missing`, `location_not_empty`,
|
|
174
|
+
`location_already_registered`; rich-spec failures include actionable spec/field
|
|
175
|
+
detail) → 202 `{commitId}` → per-step
|
|
176
|
+
`blueprint.commit_progress` → terminal `blueprint.commit_done{projectId}` /
|
|
177
|
+
`commit_failed{step,error}`. Orchestrator: `server/blueprint-commit.ts`
|
|
178
|
+
`createBlueprintCommitRunner` (DI IO bag — every step fail-injectable in
|
|
179
|
+
tests). Step order:
|
|
180
|
+
|
|
181
|
+
1. `create-dir` — mkdir target
|
|
182
|
+
2. `git-init` — `git init -b main` + deterministic README (no AI call,
|
|
183
|
+
`renderReadme`) + initial commit (pinned committer identity)
|
|
184
|
+
3. `assemble` — registry mirror + framework materialize + one core
|
|
185
|
+
`init --from-config` per provider (`server/offline-assemble.ts`
|
|
186
|
+
`assembleProjectOffline`, extracted from `SetupManager`): PREFERS the
|
|
187
|
+
bundled core (offline `node <bundled-cli> init`, `spawnBundledCoreInit`),
|
|
188
|
+
falls back to `npx specrails-core` (`spawnNpxCoreInit`) when no bundle —
|
|
189
|
+
so `npm run dev` and runtimes-less builds work. `canAssembleProject()` is
|
|
190
|
+
the validation gate: true when the bundle is present OR
|
|
191
|
+
`SPECRAILS_IS_DESKTOP !== '1'`; only a packaged desktop build with a
|
|
192
|
+
missing/corrupted bundle returns false → `bundled_framework_missing`
|
|
193
|
+
("reinstall the app"). Verifies the workspace exists afterwards.
|
|
194
|
+
4. `blueprint` — `writeBlueprintPair` into `<workspace>/.specrails/`
|
|
195
|
+
(`blueprint.json` source of truth + deterministic `blueprint.md`,
|
|
196
|
+
`server/blueprint-render.ts`; repo stays pristine)
|
|
197
|
+
5. `tickets` — `mutateStore` on the workspace `local-tickets.json`: `todo`,
|
|
198
|
+
label `M1`, `source='project-builder'`, `created_by='project-builder'`, spec
|
|
199
|
+
order preserved, generated priority/short summary/domain labels retained,
|
|
200
|
+
structured criteria folded once via the normal
|
|
201
|
+
`formatDescriptionWithCriteria` helper, `dependsOnIndex` → `prerequisites`,
|
|
202
|
+
advisory ids written back to milestone m1 (+ `status='committed'`) and the
|
|
203
|
+
pair re-rendered
|
|
204
|
+
6. `register` — `ProjectRegistry.addProject` with the pre-generated id/slug
|
|
205
|
+
(LAST mutation; broadcast `desktop.project_added`)
|
|
206
|
+
7. `github` — best-effort, never aborts. A server-side pre-flight
|
|
207
|
+
(`gh auth token`) runs first as defence against a stale client cache: a
|
|
208
|
+
spawn error (gh not on PATH) → warning `gh_not_installed`; a non-zero exit
|
|
209
|
+
→ warning `gh_not_authenticated`, both WITHOUT spawning the create. Then
|
|
210
|
+
`gh repo create <slug> --private --source . --push`; a failure is
|
|
211
|
+
classified by `classifyGhCreateError` (`gh_scope` for 403/scope,
|
|
212
|
+
`gh_repo_exists`, `gh_network`, else `gh_failed`). Every warning rides the
|
|
213
|
+
`blueprint.commit_progress` payload's additive `code` field so the client
|
|
214
|
+
renders an i18n message (`builder:progress.githubErrors.*` ×8, raw stderr
|
|
215
|
+
tail kept as tooltip) and fires ONE non-blocking `toast.warning` per commit
|
|
216
|
+
attempt (`useBuilderSession` `ghWarnedRef`).
|
|
217
|
+
|
|
218
|
+
**Checkbox gating** (`BlueprintCommitForm`): the "Create private GitHub
|
|
219
|
+
repository" option renders ONLY when gh is installed+executable
|
|
220
|
+
(`usePrerequisites()` gh entry); installed-but-unauthenticated shows it
|
|
221
|
+
disabled with the actionable `commit.githubAuthHint` («gh auth login»). gh
|
|
222
|
+
absent ⇒ the checkbox does not exist. Submit force-clears the flag unless gh
|
|
223
|
+
is fully ready (installed + authenticated).
|
|
224
|
+
|
|
225
|
+
**Crash posture**: a crash before step 6 leaves an orphan dir + registry entry
|
|
226
|
+
but NO project row (invisible; re-run rejects `location_not_empty`). After
|
|
227
|
+
step 6 it is an ordinary project missing only the remote.
|
|
228
|
+
|
|
229
|
+
## Milestone lifecycle
|
|
230
|
+
|
|
231
|
+
- **Launch Milestone 1** (`client/src/lib/milestone-launch.ts`
|
|
232
|
+
`launchMilestone`): gather `M1`-labeled `todo` tickets → `POST /rails`
|
|
233
|
+
(server allocates the lowest free index) → `PUT /rails/:i/tickets` → `POST
|
|
234
|
+
/rails/:i/launch {mode:'batch-implement'}` (the server maps the bare mode to
|
|
235
|
+
the batch factory loop: worktree isolation + ask-first PR). Offered on the
|
|
236
|
+
Builder done screen and the sidebar entry; existing 409 guards surface as
|
|
237
|
+
toasts.
|
|
238
|
+
- **Sidebar re-entry** (`BuilderSidebarEntry`, mounted in
|
|
239
|
+
`ProjectRightSidebar` + `AgentWorkspaceSidebar`): visible iff
|
|
240
|
+
`GET /api/projects/:id/blueprint` (project-router) returns a blueprint
|
|
241
|
+
(404 = hidden). Progress derives LIVE from board tickets by `M<n>` label —
|
|
242
|
+
never from stored ticket ids. Actions: Launch M1 (while launchable) +
|
|
243
|
+
Generate M<next> (first `planned` milestone > 1).
|
|
244
|
+
- **Board classification**: new Builder tickets use
|
|
245
|
+
`source='project-builder'` + `created_by='project-builder'`. For projects
|
|
246
|
+
created before that source existed, `DashboardPage` also treats
|
|
247
|
+
`source='manual'` + `created_by='project-builder'` as specs; existing tickets
|
|
248
|
+
appear after reload without rewriting the user's ticket store.
|
|
249
|
+
- **Generate M2+** (`MilestoneGenerateShell`): PROJECT-level conversation
|
|
250
|
+
`kind='milestone'` through the existing ChatManager. The milestone id rides
|
|
251
|
+
`context_scope` as `{milestone:'m2'}` (`POST /chat/conversations` body
|
|
252
|
+
`{kind:'milestone', milestone}`); `ChatManager._buildMilestoneSystemPrompt`
|
|
253
|
+
seeds the prompt with the workspace `blueprint.json`, the target
|
|
254
|
+
`plannedSpecs`, the complete canonical rich-spec/quality contract, and the
|
|
255
|
+
code-grounding rules. It instructs the agent to return every detailed spec
|
|
256
|
+
for the target milestone in one assistant response and one complete snapshot,
|
|
257
|
+
never an incrementally committable subset. Claude receives it through the
|
|
258
|
+
system prompt; adapters without that argument receive the same dynamic
|
|
259
|
+
instructions and blueprint context in the effective user turn, so Claude,
|
|
260
|
+
Codex, and Gemini receive equivalent authoring/context instructions.
|
|
261
|
+
Generation itself is read-only: the prompt forbids repository/workspace/
|
|
262
|
+
ticket/config/git mutation, write-capable shell/tool actions, builds, and
|
|
263
|
+
tests. `toolPolicy='read-only'` maps Claude to `--permission-mode plan`
|
|
264
|
+
+ `--safe-mode` + only `Read,Grep,Glob`; Codex fresh turns use
|
|
265
|
+
`--sandbox read-only` and resumes carry `sandbox_mode="read-only"`; Gemini
|
|
266
|
+
uses `--approval-mode plan` and never `--yolo`. Gemini CLI does not expose a
|
|
267
|
+
selectable filesystem sandbox comparable to Codex, so its protection is the
|
|
268
|
+
native plan/policy layer plus the prompt—not an OS/filesystem sandbox. If a
|
|
269
|
+
CLI version rejects an incompatible safety flag, the turn fails closed; it
|
|
270
|
+
is never retried with a mutating/yolo policy. For relocated projects the
|
|
271
|
+
prompt identifies the absolute real repo, its `./project` mount, and
|
|
272
|
+
`SPECRAILS_REPO_DIR`; it explicitly warns Read/Grep/Glob not to receive
|
|
273
|
+
literal shell-variable expressions, preventing grounding against the empty
|
|
274
|
+
workspace. Grounded specs name only verified paths/identifiers and require
|
|
275
|
+
behavioral, failure/edge-case, and testing criteria. Accounting records
|
|
276
|
+
`surface='explore-spec'` (no new surface value). Committing calls
|
|
277
|
+
`POST /api/projects/:id/blueprint/commit-milestone {milestoneId, specs[]}` —
|
|
278
|
+
atomically validates the complete batch before any write, then inserts
|
|
279
|
+
`M<n>`-labeled `todo` tickets with Builder source/provenance and the same
|
|
280
|
+
priority/summary/criteria/labels/prerequisite ticket-materialization rules as M1
|
|
281
|
+
(broadcasting `ticket_created` per row), flips the milestone to `committed`,
|
|
282
|
+
and re-renders the pair. These tickets are the authoritative detailed M2+
|
|
283
|
+
representation: their descriptions contain the folded criteria and they
|
|
284
|
+
retain priority, short summary, domain + `M<n>` labels, and prerequisites.
|
|
285
|
+
`blueprint.json` deliberately stores only the existing milestone skeleton
|
|
286
|
+
with `status='committed'` and advisory `ticketIds`; it has no detailed-M2-
|
|
287
|
+
per-milestone schema. On 201 the shell calls `onCommitted`, increments the
|
|
288
|
+
sidebar blueprint refresh key (no-store refetch), closes, and the next CTA
|
|
289
|
+
resolves to the first later milestone still `planned`. Jira-connected
|
|
290
|
+
projects ride the existing machinery on the store mutation.
|
|
291
|
+
|
|
292
|
+
## Tests
|
|
293
|
+
|
|
294
|
+
`server/blueprint-{draft-parser,render,store,chat-manager,commit,router}.test.ts`,
|
|
295
|
+
`server/offline-assemble.test.ts`, `server/project-router.test.ts`; client
|
|
296
|
+
`src/lib/__tests__/{blueprint-draft,milestone-launch}.test.ts`,
|
|
297
|
+
`src/hooks/__tests__/useBuilderSession.test.ts`,
|
|
298
|
+
`src/components/__tests__/{ProjectBuilder,BuilderSidebarEntry}.test.tsx`, and
|
|
299
|
+
`src/pages/__tests__/DashboardPage.test.tsx`.
|
|
300
|
+
Locale parity covers the `builder` namespace ×8.
|
|
301
|
+
|
|
302
|
+
## Deferred (v2)
|
|
303
|
+
|
|
304
|
+
Resume/minimize for Builder conversations (no dock chip — no `projectId` to
|
|
305
|
+
tag), an orphan-dir startup sweeper, non-GitHub remotes, editing an existing
|
|
306
|
+
blueprint via the day-0 Builder, a live side-panel draft during M2 generation.
|
|
@@ -193,25 +193,35 @@ seeded instruction file), which lives in `~/.specrails/projects/<slug>/workspace
|
|
|
193
193
|
absent from the worktree: the claude CLI reported `Unknown command: /specrails:implement`
|
|
194
194
|
and the loop "succeeded" through verify/fix without implementing (live evidence: run
|
|
195
195
|
01f41203). Legacy projects have the sibling gap for their UNTRACKED on-disk `.claude`
|
|
196
|
-
entries.
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
196
|
+
entries. Relocated projects also need repo-resident carve-outs that are intentionally not
|
|
197
|
+
part of the workspace framework, notably OpenSpec's untracked `/opsx:*` commands and
|
|
198
|
+
`openspec-*` skills. Each allocated worktree therefore gets `applyWorktreeOverlay(...)`
|
|
199
|
+
at launch:
|
|
200
|
+
|
|
201
|
+
- **Ordered source roots** are resolved once per launch. The primary root is the effective
|
|
202
|
+
artifact root (`resolveProjectExecution`: workspace when relocated, repo when legacy).
|
|
203
|
+
A relocated launch additionally passes the repo as a lower-priority fallback so its
|
|
204
|
+
untracked provider entries reach the worktree. Earlier roots win per entry; legacy stays
|
|
205
|
+
on its byte-identical single-root path.
|
|
206
|
+
- **Merge-only links/copies** under `<worktree>/<providerDir>/`: one contributing directory
|
|
207
|
+
stays a whole-dir link; when several roots contribute children, the destination is a REAL
|
|
208
|
+
directory of per-child links. Checkout content is NEVER overwritten, including source
|
|
209
|
+
file/directory type conflicts. On resume, only an authenticated prior-manifest whole-dir
|
|
210
|
+
link/copy may be rebuilt into recorded leaves; a foreign symlink is untouched even when it
|
|
211
|
+
targets a configured source. Converted parents are revoked from the manifest. `agent-memory`
|
|
212
|
+
remains linked (shared pre-isolation semantics). The providerDir root and every source's
|
|
213
|
+
`worktrees/` entry are never linked. `.mcp.json` and the provider instruction file are COPIED
|
|
214
|
+
from the first root containing them when checkout lacks them. Windows: junction →
|
|
215
|
+
dereferencing-copy fallback.
|
|
216
|
+
- **Never on the PR**: the resume-safe manifest records authenticated overlay leaves against
|
|
217
|
+
any configured root; settlement persists immutable fingerprints. Commit delivery deliberately
|
|
218
|
+
runs plain `git add -A`, audits the index, resets forbidden literal top-level paths, re-audits,
|
|
219
|
+
and makes those exclusions authoritative with `git commit --only`. The writable manifest alone
|
|
220
|
+
never grants cleanup authority. Cleanup atomically renames each authenticated root into a unique
|
|
221
|
+
sibling quarantine, revalidates it after the move, discloses raced content there, and never
|
|
222
|
+
deletes or restores quarantined paths automatically over a possibly recreated source. A modified
|
|
223
|
+
or concurrently extended overlay is preserved as user data, while a no-op overlay keeps the
|
|
224
|
+
byte-identical ordinary staging behavior.
|
|
215
225
|
Successful quarantine batches deliberately remain beside the former worktree; automatic GC is
|
|
216
226
|
out of scope because deleting a path still writable through an open descriptor would reintroduce
|
|
217
227
|
the data-loss race. A future cleanup flow must be explicit and inspectable.
|
package/package.json
CHANGED
|
@@ -366,6 +366,12 @@ summary later.
|
|
|
366
366
|
invariants. Use **SDD Quick (OpenSpec)** for small OpenSpec-governed work that
|
|
367
367
|
should move faster than the full Implement pipeline while keeping OpenSpec
|
|
368
368
|
artifacts authoritative.
|
|
369
|
+
- **Batch sizing: at most 3 specs per rail.** When recommending or configuring
|
|
370
|
+
a \`batch-implement\` launch, never propose more than 3 specs on one rail —
|
|
371
|
+
larger batches dilute the pipeline's context and review quality. Split
|
|
372
|
+
bigger sets across multiple rails (worktree isolation makes parallel rails
|
|
373
|
+
safe; create rails as needed) or into sequential launches. Exceed 3 only
|
|
374
|
+
when the user explicitly insists after you have stated this recommendation.
|
|
369
375
|
- **Never offer direct code edits as the implementation path.** Even if the
|
|
370
376
|
change is "just one or two lines", keep Specrails as the wrapper: update or
|
|
371
377
|
create a local ticket, classify the work, then propose the appropriate rail
|
|
@@ -529,4 +535,4 @@ When the user has no projects yet, or asks to add one:
|
|
|
529
535
|
Setup is QUICK-only (fast, offline). Do NOT offer, mention, or attempt a "full"
|
|
530
536
|
or "enrich" install — that flow is deprecated and not available through you.
|
|
531
537
|
`;
|
|
532
|
-
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; run long-lived server/watch/tail shell commands with specrails_jobs background_start and confirmed:true only at Autonomous level after explicit user confirmation, not a raw shell runner, so the app can show the killable background chip in this chat; if a background chip exits/fails, use specrails_jobs background_logs for its pid before asking to relaunch; if a job/loop is still running, pass allowWhileBusy:true only after explicit concurrent confirmation; 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. Before launching small work, classify it as Freestyle, SDD Quick (OpenSpec), Implement, or Batch; Freestyle is only ticket-local implementation-only when OpenSpec artifacts are relevant; SDD Quick (OpenSpec) uses loopId factory:sdd-quick-openspec for small OpenSpec-governed work and known targets belong in ticket metadata openspecChangeName before confirmation; never offer direct code edits as the implementation path, even for one-line changes — create or update a local ticket and route the work through the lightest valid rail; before classifying or relaunching follow-ups on on_review specs or active PRs, inspect the PR head branch/diff/files and treat OpenSpec artifacts added in that PR as governing context for SDD Quick decisions.`;
|
|
538
|
+
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; run long-lived server/watch/tail shell commands with specrails_jobs background_start and confirmed:true only at Autonomous level after explicit user confirmation, not a raw shell runner, so the app can show the killable background chip in this chat; if a background chip exits/fails, use specrails_jobs background_logs for its pid before asking to relaunch; if a job/loop is still running, pass allowWhileBusy:true only after explicit concurrent confirmation; 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. Before launching small work, classify it as Freestyle, SDD Quick (OpenSpec), Implement, or Batch; Freestyle is only ticket-local implementation-only when OpenSpec artifacts are relevant; SDD Quick (OpenSpec) uses loopId factory:sdd-quick-openspec for small OpenSpec-governed work and known targets belong in ticket metadata openspecChangeName before confirmation; never offer direct code edits as the implementation path, even for one-line changes — create or update a local ticket and route the work through the lightest valid rail; when proposing batch-implement work never recommend more than 3 specs per rail — split larger sets across multiple rails or sequential launches, exceeding 3 only on explicit user insistence; before classifying or relaunching follow-ups on on_review specs or active PRs, inspect the PR head branch/diff/files and treat OpenSpec artifacts added in that PR as governing context for SDD Quick decisions.`;
|