specrails-desktop 2.47.0 → 2.48.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -0
- package/client/dist/assets/{ActivityFeedPage-DSCpSOGV.js → ActivityFeedPage-CGq6QhP5.js} +1 -1
- package/client/dist/assets/AgentBrowserCapture-C4GZ-kdf.js +1 -0
- package/client/dist/assets/AgentModeAnalyticsPane-_IPmL0ZS.js +2 -0
- package/client/dist/assets/AgentModeCodePane-B5WG5DOP.js +2 -0
- package/client/dist/assets/{AgentModeJobsPane-Dw3DNFkh.js → AgentModeJobsPane-w1N_HIXh.js} +1 -1
- package/client/dist/assets/AgentsPage-CmwnnT46.js +87 -0
- package/client/dist/assets/AnalyticsPage-BUMsKtsJ.js +1 -0
- package/client/dist/assets/CodePage-PjgywJPS.js +3 -0
- package/client/dist/assets/DesktopAnalyticsPage-BXY1pH4y.js +1 -0
- package/client/dist/assets/DocsDialog-ccQETHKB.js +11 -0
- package/client/dist/assets/DocsPage-DzEgplB3.js +11 -0
- package/client/dist/assets/{ExportDropdown-BwuvqS2Y.js → ExportDropdown-B8bBGopr.js} +1 -1
- package/client/dist/assets/InteractiveJobComposer-CEwGkJ8F.js +19 -0
- package/client/dist/assets/JobDetailModal-BYXmuTDe.js +1 -0
- package/client/dist/assets/JobDetailPage-CWp6MwJj.js +1 -0
- package/client/dist/assets/JobsPage-D1O1uyG8.js +1 -0
- package/client/dist/assets/{LoopBuilderPage-Byvq8Oqx.js → LoopBuilderPage-DQE-7Vby.js} +2 -2
- package/client/dist/assets/{LoopPreviewModal-BMC9Mgj1.js → LoopPreviewModal-Bk7zIXD5.js} +1 -1
- package/client/dist/assets/LoopsPage-CqG7mx56.js +1 -0
- package/client/dist/assets/MinimizedChatsContext-UpnqccPx.js +1 -0
- package/client/dist/assets/PluginsPage-CjgVvmpW.js +2 -0
- package/client/dist/assets/{ProjectSettingsDialog-nspqxH-M.js → ProjectSettingsDialog-D6vBCoay.js} +1 -1
- package/client/dist/assets/{RepositoryDeliveries-Dq9NJOWi.js → RepositoryDeliveries-C36ipKp_.js} +1 -1
- package/client/dist/assets/{RepositoryScopeSelector-C3jKG2z0.js → RepositoryScopeSelector-0Gz_fR1E.js} +1 -1
- package/client/dist/assets/ReviewPacketPage-Dr9RYs7q.js +1 -0
- package/client/dist/assets/TemplatePreviewModal-sCMHYFJo.js +1 -0
- package/client/dist/assets/TicketDetailModalContext-C5GgJlEt.js +14 -0
- package/client/dist/assets/{Trans-C0KyPo2O.js → Trans-9pHTy2fH.js} +1 -1
- package/client/dist/assets/{addspec-D2YIQ0GU.js → addspec-BOvgmcgk.js} +1 -1
- package/client/dist/assets/{addspec-B_TPJt-R.js → addspec-Clmyfn_R.js} +1 -1
- package/client/dist/assets/{addspec-A1lDQa4M.js → addspec-CsNaBpHp.js} +1 -1
- package/client/dist/assets/{addspec-CQBjzt24.js → addspec-D2tvWmmV.js} +1 -1
- package/client/dist/assets/{addspec-CLYLvaVP.js → addspec-D3nFwvD0.js} +1 -1
- package/client/dist/assets/{addspec-BPpZ_olp.js → addspec-DVLEhK3w.js} +1 -1
- package/client/dist/assets/{addspec-iFdQ6D99.js → addspec-DXbK-tb0.js} +1 -1
- package/client/dist/assets/{addspec-BHZd0N5F.js → addspec-OHG8DFEn.js} +1 -1
- package/client/dist/assets/agentRuntime-BUimiX__.js +1 -0
- package/client/dist/assets/agentRuntime-BcN97sAB.js +1 -0
- package/client/dist/assets/agentRuntime-Ckyg-ahT.js +1 -0
- package/client/dist/assets/agentRuntime-DJCwyX4t.js +1 -0
- package/client/dist/assets/agentRuntime-DVzPJOl0.js +1 -0
- package/client/dist/assets/agentRuntime-V9AZTG3c.js +1 -0
- package/client/dist/assets/agentRuntime-bAAjw1vw.js +1 -0
- package/client/dist/assets/agentRuntime-v4qKAYH-.js +1 -0
- package/client/dist/assets/{agents-DyI4rbHa.js → agents-CA5eT1d0.js} +1 -1
- package/client/dist/assets/{agents-_5mJMkAE.js → agents-CAgy-5uS.js} +1 -1
- package/client/dist/assets/{agents-BIT1UdTy.js → agents-CNm6Qzlv.js} +1 -1
- package/client/dist/assets/{agents-CST-lpYX.js → agents-CTwbx-fb.js} +1 -1
- package/client/dist/assets/{agents-C7fKfvm8.js → agents-DEGV1Vao.js} +1 -1
- package/client/dist/assets/{agents-DsgGMGwU.js → agents-HsDF1aQU.js} +1 -1
- package/client/dist/assets/{agents-Cm2JYrAa.js → agents-IQjdA-z9.js} +1 -1
- package/client/dist/assets/{agents-H6tVQUNP.js → agents-RkGoteXh.js} +1 -1
- package/client/dist/assets/analytics-BNgZ1Nj7.js +1 -0
- package/client/dist/assets/analytics-BlypLLR6.js +1 -0
- package/client/dist/assets/analytics-CoEzWPx4.js +1 -0
- package/client/dist/assets/analytics-DFh5lSOl.js +1 -0
- package/client/dist/assets/analytics-DZp-DS2U.js +1 -0
- package/client/dist/assets/analytics-DjLlE7jS.js +1 -0
- package/client/dist/assets/analytics-jzCkOec3.js +1 -0
- package/client/dist/assets/analytics-nZIjjtCc.js +1 -0
- package/client/dist/assets/{dashboard-BK_mez-z.js → dashboard-C29Qwa-L.js} +1 -1
- package/client/dist/assets/{dashboard-BwkjxI6H.js → dashboard-CSJzf5OT.js} +1 -1
- package/client/dist/assets/{dashboard-C3bDKf7s.js → dashboard-CTfEtkqX.js} +1 -1
- package/client/dist/assets/{dashboard-Bt0cCzeG.js → dashboard-Cr4D8oMn.js} +1 -1
- package/client/dist/assets/{dashboard-fRrP0Kv0.js → dashboard-Csf1yGSN.js} +1 -1
- package/client/dist/assets/{dashboard-CdvjGfog.js → dashboard-D40HP2ks.js} +1 -1
- package/client/dist/assets/dashboard-DBAP2_SQ.js +1 -0
- package/client/dist/assets/{dashboard-B14uYXkG.js → dashboard-DMklepmz.js} +1 -1
- package/client/dist/assets/file-text-CFT-xXKN.js +1 -0
- package/client/dist/assets/{formatDistanceToNow-D44phX1J.js → formatDistanceToNow-w_2U5pm0.js} +1 -1
- package/client/dist/assets/{getTimezoneOffsetInMilliseconds-EAh9LFSx.js → getTimezoneOffsetInMilliseconds-BRymg1Kk.js} +1 -1
- package/client/dist/assets/index-D0ScFZvR.css +2 -0
- package/client/dist/assets/index-DORCrgbI.js +77 -0
- package/client/dist/assets/jira-api-BqHbSdxK.js +1 -0
- package/client/dist/assets/jobs-C6qmvUAi.js +1 -0
- package/client/dist/assets/jobs-C9j2PuwW.js +1 -0
- package/client/dist/assets/jobs-DLHdDkHc.js +1 -0
- package/client/dist/assets/jobs-DSp9DoD_.js +1 -0
- package/client/dist/assets/jobs-DTQO08nJ.js +1 -0
- package/client/dist/assets/jobs-DoFaEl9g.js +1 -0
- package/client/dist/assets/jobs-Dpw6AEOP.js +1 -0
- package/client/dist/assets/jobs-DrF8Do8s.js +1 -0
- package/client/dist/assets/{narration-UWi_xIZ-.js → narration--hUhjM5v.js} +1 -1
- package/client/dist/assets/{narration-DiPyj06T.js → narration-CHI06czm.js} +1 -1
- package/client/dist/assets/{narration-DrBAf8uv.js → narration-DjKB3pQZ.js} +1 -1
- package/client/dist/assets/{narration-CqNvgRi9.js → narration-DtCYvRLM.js} +1 -1
- package/client/dist/assets/{narration-B1uGfofH.js → narration-DvLQBW9U.js} +1 -1
- package/client/dist/assets/{narration-BKcL4Srl.js → narration-eSx3gR0W.js} +1 -1
- package/client/dist/assets/{narration-OyujFouL.js → narration-n3hOA7LY.js} +1 -1
- package/client/dist/assets/{narration-BtjKyHVM.js → narration-thJOeT2-.js} +1 -1
- package/client/dist/assets/packet-BNW8ODQw.js +1 -0
- package/client/dist/assets/packet-CXYvfdjy.js +1 -0
- package/client/dist/assets/packet-CtIlB8YE.js +1 -0
- package/client/dist/assets/packet-DA1SJkMH.js +1 -0
- package/client/dist/assets/packet-DYcWfBip.js +1 -0
- package/client/dist/assets/packet-DseX9yKC.js +1 -0
- package/client/dist/assets/packet-_m5aOy_d.js +1 -0
- package/client/dist/assets/packet-qOemUAm3.js +1 -0
- package/client/dist/assets/{project-repositories-GRYdjlKB.js → project-repositories-BsCs1PPA.js} +1 -1
- package/client/dist/assets/provider-capabilities-Vi1ZGvAK.js +1 -0
- package/client/dist/assets/settings-BsehKpty.js +1 -0
- package/client/dist/assets/settings-CQWob3SB.js +1 -0
- package/client/dist/assets/settings-CgCl0hzy.js +1 -0
- package/client/dist/assets/settings-DLRLd22L.js +1 -0
- package/client/dist/assets/settings-Dn5prAFl.js +1 -0
- package/client/dist/assets/settings-HZSu-K4l.js +1 -0
- package/client/dist/assets/{settings-DEgcA0jd.js → settings-p4OVIyRh.js} +1 -1
- package/client/dist/assets/settings-rddaldUp.js +1 -0
- package/client/dist/assets/setup-B5FHuxvB.js +1 -0
- package/client/dist/assets/setup-BihzXadx.js +1 -0
- package/client/dist/assets/setup-BtC6Hg4K.js +1 -0
- package/client/dist/assets/setup-C9Fy9PKQ.js +1 -0
- package/client/dist/assets/setup-CROyqD5N.js +1 -0
- package/client/dist/assets/setup-DpqzaEEA.js +1 -0
- package/client/dist/assets/setup-Dwzt5nO1.js +1 -0
- package/client/dist/assets/setup-zLEDnG7N.js +1 -0
- package/client/dist/assets/{spending-CN9PHM65.js → spending-hcgxHP4O.js} +1 -1
- package/client/dist/assets/{useDesktop-iius_s5d.js → useDesktop-CAisjKWC.js} +1 -1
- package/client/dist/assets/{useSharedWebSocket-D7hkZ3Ka.js → useSharedWebSocket-BHIfW4QT.js} +2 -2
- package/client/dist/assets/wrench-BfmNO9Vw.js +1 -0
- package/client/dist/index.html +27 -26
- package/docs/guide/de/integrations/7-local-engines.md +37 -0
- package/docs/guide/en/integrations/7-local-engines.md +37 -0
- package/docs/guide/es/integrations/7-local-engines.md +37 -0
- package/docs/guide/fr/integrations/7-local-engines.md +37 -0
- package/docs/guide/it/integrations/7-local-engines.md +37 -0
- package/docs/guide/ja/integrations/7-local-engines.md +37 -0
- package/docs/guide/pt/integrations/7-local-engines.md +37 -0
- package/docs/guide/zh/integrations/7-local-engines.md +37 -0
- package/docs/internals/adding-a-provider.md +12 -0
- package/docs/internals/local-agent-runner.md +153 -0
- package/docs/internals/review-packet.md +8 -0
- package/docs/local-providers.md +215 -0
- package/local-runner/dist/specrails-local-runner.js +15815 -0
- package/package.json +7 -5
- package/server/dist/agent-chat-manager.js +8 -1
- package/server/dist/agent-chat-router.js +5 -2
- package/server/dist/agent-fence-promotion.js +53 -0
- package/server/dist/agent-mcp-config.js +4 -1
- package/server/dist/agent-runtime-bridge.js +7 -2
- package/server/dist/agent-runtime-controls-router.js +12 -1
- package/server/dist/agent-runtime-controls.js +37 -2
- package/server/dist/agent-runtime-effective-config.js +28 -7
- package/server/dist/agent-runtime-metrics.js +1 -1
- package/server/dist/agent-runtime-settings-router.js +76 -6
- package/server/dist/agent-runtime-settings.js +137 -7
- package/server/dist/agent-spec-framing.js +10 -4
- package/server/dist/binary-probe.js +12 -0
- package/server/dist/blueprint-router.js +3 -2
- package/server/dist/chat-manager.js +5 -1
- package/server/dist/desktop-router.js +87 -4
- package/server/dist/index.js +13 -0
- package/server/dist/interactive-job-session.js +3 -1
- package/server/dist/local-engine-detection.js +118 -0
- package/server/dist/loop-executors.js +2 -1
- package/server/dist/loop-role-engines.js +129 -0
- package/server/dist/loop-run-manager.js +4 -4
- package/server/dist/mcp/tools/app-settings.js +30 -4
- package/server/dist/mcp/tools/rails.js +1 -1
- package/server/dist/pr-body.js +11 -2
- package/server/dist/pricing.js +15 -0
- package/server/dist/provider-detection.js +63 -1
- package/server/dist/provider-selection.js +26 -1
- package/server/dist/providers/index.js +4 -1
- package/server/dist/providers/local-adapter-registry.js +56 -0
- package/server/dist/providers/local-adapter.js +426 -0
- package/server/dist/providers/registry.js +39 -4
- package/server/dist/rail-isolated-launch.js +3 -3
- package/server/dist/rails-router.js +66 -10
- package/server/dist/result-event.js +17 -0
- package/server/dist/review-packet.js +1 -0
- package/server/dist/schemas/agent-runtime.schema.json +10 -2
- package/server/dist/setup-manager.js +5 -1
- package/server/dist/spec-models.js +14 -2
- package/server/dist/worktree-node-modules.js +97 -65
- package/client/dist/assets/AgentBrowserCapture-mc1c5pgS.js +0 -1
- package/client/dist/assets/AgentModeAnalyticsPane--UkamBTm.js +0 -2
- package/client/dist/assets/AgentModeCodePane-DJCswsvU.js +0 -2
- package/client/dist/assets/AgentsPage-ChElPUL9.js +0 -87
- package/client/dist/assets/AnalyticsPage-BGtkFHBp.js +0 -1
- package/client/dist/assets/CodePage-BBnw3VGn.js +0 -3
- package/client/dist/assets/DesktopAnalyticsPage-B85tNScc.js +0 -1
- package/client/dist/assets/DocsDialog-D4cXrOMl.js +0 -11
- package/client/dist/assets/DocsPage-BCAbC6qy.js +0 -11
- package/client/dist/assets/InteractiveJobComposer-Coq-Zhk0.js +0 -19
- package/client/dist/assets/JobDetailModal--Mjam0Nc.js +0 -1
- package/client/dist/assets/JobDetailPage-B6ShWSBh.js +0 -1
- package/client/dist/assets/JobsPage-DHU_ep_B.js +0 -1
- package/client/dist/assets/LoopsPage-CFGl-Nw8.js +0 -1
- package/client/dist/assets/MinimizedChatsContext-DHjHBYqa.js +0 -1
- package/client/dist/assets/PluginsPage-BHygRnW6.js +0 -2
- package/client/dist/assets/ReviewPacketPage-C9mqhi65.js +0 -1
- package/client/dist/assets/TemplatePreviewModal-BmwoAjOr.js +0 -1
- package/client/dist/assets/TicketDetailModalContext-lYmoONrd.js +0 -14
- package/client/dist/assets/agentRuntime-62GWdc26.js +0 -1
- package/client/dist/assets/agentRuntime-BN1mKAuY.js +0 -1
- package/client/dist/assets/agentRuntime-BNBCzQLM.js +0 -1
- package/client/dist/assets/agentRuntime-BQE_K1GG.js +0 -1
- package/client/dist/assets/agentRuntime-CCU3HCtS.js +0 -1
- package/client/dist/assets/agentRuntime-DT72Bpdv.js +0 -1
- package/client/dist/assets/agentRuntime-ZfMPeeiP.js +0 -1
- package/client/dist/assets/agentRuntime-g3W8Ry4d.js +0 -1
- package/client/dist/assets/analytics-47pYygtV.js +0 -1
- package/client/dist/assets/analytics-B0vt1g5U.js +0 -1
- package/client/dist/assets/analytics-BMzCvrCU.js +0 -1
- package/client/dist/assets/analytics-BlFN3Zwx.js +0 -1
- package/client/dist/assets/analytics-CZYzL-nR.js +0 -1
- package/client/dist/assets/analytics-DAsb9MJ8.js +0 -1
- package/client/dist/assets/analytics-FXQlQ2Yt.js +0 -1
- package/client/dist/assets/analytics-RnFCNkah.js +0 -1
- package/client/dist/assets/dashboard-BfBir_6o.js +0 -1
- package/client/dist/assets/file-text-BcLCfcWZ.js +0 -1
- package/client/dist/assets/index-Cfh9aaep.css +0 -2
- package/client/dist/assets/index-DgMBighL.js +0 -76
- package/client/dist/assets/jira-api-BQR6G0YY.js +0 -1
- package/client/dist/assets/jobs-5PQJbdOf.js +0 -1
- package/client/dist/assets/jobs-B2B08Oy9.js +0 -1
- package/client/dist/assets/jobs-BJZtBbwb.js +0 -1
- package/client/dist/assets/jobs-BlWEsQb7.js +0 -1
- package/client/dist/assets/jobs-ConfD8xD.js +0 -1
- package/client/dist/assets/jobs-DMPU64ms.js +0 -1
- package/client/dist/assets/jobs-DojASiTp.js +0 -1
- package/client/dist/assets/jobs-kVHkNpB-.js +0 -1
- package/client/dist/assets/packet-BQ2tXfJI.js +0 -1
- package/client/dist/assets/packet-BdpOJ1Cy.js +0 -1
- package/client/dist/assets/packet-C3Ievb9R.js +0 -1
- package/client/dist/assets/packet-C4zJIG0Y.js +0 -1
- package/client/dist/assets/packet-Cx-zRuWn.js +0 -1
- package/client/dist/assets/packet-DUTGX52M.js +0 -1
- package/client/dist/assets/packet-DhsKtUPB.js +0 -1
- package/client/dist/assets/packet-z3LJ8Zyy.js +0 -1
- package/client/dist/assets/provider-capabilities-CXipwrXJ.js +0 -1
- package/client/dist/assets/settings-B3rWEwOx.js +0 -1
- package/client/dist/assets/settings-BcVoiMyw.js +0 -1
- package/client/dist/assets/settings-BlYvaQ7w.js +0 -1
- package/client/dist/assets/settings-CD5uEBiL.js +0 -1
- package/client/dist/assets/settings-CyhS0DLJ.js +0 -1
- package/client/dist/assets/settings-DCMFUGDs.js +0 -1
- package/client/dist/assets/settings-DmbYKyMJ.js +0 -1
- package/client/dist/assets/setup-2xGgu4Sk.js +0 -1
- package/client/dist/assets/setup-Ba11l2JA.js +0 -1
- package/client/dist/assets/setup-BzW4kMok.js +0 -1
- package/client/dist/assets/setup-COzwYhkJ.js +0 -1
- package/client/dist/assets/setup-CRVULhtF.js +0 -1
- package/client/dist/assets/setup-DgvlxwpE.js +0 -1
- package/client/dist/assets/setup-Dw_wYeEY.js +0 -1
- package/client/dist/assets/setup-ZPtEeJPW.js +0 -1
|
@@ -12,7 +12,9 @@ const file_provenance_1 = require("./file-provenance");
|
|
|
12
12
|
const file_story_1 = require("./file-story");
|
|
13
13
|
const loops_store_1 = require("./loops-store");
|
|
14
14
|
const loop_runs_store_1 = require("./loop-runs-store");
|
|
15
|
+
const registry_1 = require("./providers/registry");
|
|
15
16
|
const providers_1 = require("./providers");
|
|
17
|
+
const loop_role_engines_1 = require("./loop-role-engines");
|
|
16
18
|
const runtime_1 = require("./providers/runtime");
|
|
17
19
|
const agent_defaults_1 = require("./agent-defaults");
|
|
18
20
|
const profile_manager_1 = require("./profile-manager");
|
|
@@ -374,8 +376,9 @@ function createRailsRouter() {
|
|
|
374
376
|
}
|
|
375
377
|
const value = body.aiEngine;
|
|
376
378
|
const c = ctx(req);
|
|
377
|
-
// null clears the override; a string must be one of the project's providers
|
|
378
|
-
|
|
379
|
+
// null clears the override; a string must be one of the project's providers
|
|
380
|
+
// — or the `roles` sentinel (per-role engines from Settings ▸ Specrails Agents).
|
|
381
|
+
if (value !== null && value !== loop_role_engines_1.ROLES_ENGINE) {
|
|
379
382
|
const check = (0, provider_selection_1.validateRequestedProvider)(c.project, value);
|
|
380
383
|
if (!check.ok) {
|
|
381
384
|
res.status(400).json({ error: check.error });
|
|
@@ -635,7 +638,21 @@ function createRailsRouter() {
|
|
|
635
638
|
}
|
|
636
639
|
// AI engine precedence: explicit body param > stored rail engine > primary.
|
|
637
640
|
// `undefined`/empty in both means "run on the project's primary provider".
|
|
638
|
-
const
|
|
641
|
+
const requestedEngineRaw = aiEngine === undefined ? (rail.aiEngine ?? undefined) : aiEngine;
|
|
642
|
+
// `roles` (hybrid-role-engines): the pipeline roles keep the project's
|
|
643
|
+
// per-role runtime settings (no flattening override) and the loop's own
|
|
644
|
+
// steps come from the stored loop-role engines — verifier for every
|
|
645
|
+
// non-core ai-step, decider for the Loop Decider. The rail's "engine" for
|
|
646
|
+
// the non-core path is therefore the verifier's provider.
|
|
647
|
+
const rolesMode = requestedEngineRaw === loop_role_engines_1.ROLES_ENGINE;
|
|
648
|
+
if (rolesMode && mode === 'freestyle') {
|
|
649
|
+
res.status(400).json({ error: 'roles_engine_unsupported_mode', detail: 'Freestyle has no roles; pick a concrete engine' });
|
|
650
|
+
return;
|
|
651
|
+
}
|
|
652
|
+
const loopRoleEngines = rolesMode ? (0, loop_role_engines_1.loadLoopRoleEngines)(c.project) : {};
|
|
653
|
+
const requestedEngine = rolesMode
|
|
654
|
+
? (loopRoleEngines.verifier?.provider && (0, provider_selection_1.validateRequestedProvider)(c.project, loopRoleEngines.verifier.provider).ok ? loopRoleEngines.verifier.provider : undefined)
|
|
655
|
+
: requestedEngineRaw;
|
|
639
656
|
const engineCheck = (0, provider_selection_1.validateRequestedProvider)(c.project, requestedEngine);
|
|
640
657
|
if (!engineCheck.ok) {
|
|
641
658
|
res.status(400).json({ error: engineCheck.error });
|
|
@@ -646,9 +663,18 @@ function createRailsRouter() {
|
|
|
646
663
|
const railProvider = requestedEngine ? engineCheck.provider : undefined;
|
|
647
664
|
// Mission/MCP and Launch-all submit aiEngine or use the saved rail engine.
|
|
648
665
|
// Resolve this at the shared boundary, not only in the Dashboard payload.
|
|
649
|
-
|
|
666
|
+
// Local (OpenAI-compatible) engines: the override carries provider + model
|
|
667
|
+
// only — OpenAI endpoints have no effort knob, so effort is DROPPED (never
|
|
668
|
+
// forwarded to Core's executor), and cost caps are refused (a local run has
|
|
669
|
+
// no billable cost to cap against).
|
|
670
|
+
const localEngine = (0, registry_1.isLocalAdapterId)(engineCheck.provider);
|
|
671
|
+
if (rolesMode && runtimeProviderOverride) {
|
|
672
|
+
res.status(400).json({ error: 'runtime_provider_mismatch', detail: 'A roles launch carries no provider override' });
|
|
673
|
+
return;
|
|
674
|
+
}
|
|
675
|
+
if (!runtimeProviderOverride && requestedEngine && !rolesMode) {
|
|
650
676
|
try {
|
|
651
|
-
runtimeProviderOverride = (0, agent_runtime_settings_1.validateRuntimeProviderOverride)({ provider: engineCheck.provider, ...(model ? { model } : {}), ...(reasoning_effort ? { effort: reasoning_effort } : {}) });
|
|
677
|
+
runtimeProviderOverride = (0, agent_runtime_settings_1.validateRuntimeProviderOverride)({ provider: engineCheck.provider, ...(model ? { model } : {}), ...(reasoning_effort && !localEngine ? { effort: reasoning_effort } : {}) });
|
|
652
678
|
}
|
|
653
679
|
catch {
|
|
654
680
|
res.status(400).json({ error: 'invalid_runtime_provider_override' });
|
|
@@ -659,6 +685,13 @@ function createRailsRouter() {
|
|
|
659
685
|
res.status(400).json({ error: 'runtime_provider_mismatch' });
|
|
660
686
|
return;
|
|
661
687
|
}
|
|
688
|
+
if (localEngine && runtimeProviderOverride?.effort !== undefined) {
|
|
689
|
+
runtimeProviderOverride = { provider: runtimeProviderOverride.provider, ...(runtimeProviderOverride.model !== undefined ? { model: runtimeProviderOverride.model } : {}) };
|
|
690
|
+
}
|
|
691
|
+
if (localEngine && req.body?.maxCostUsd !== undefined && req.body?.maxCostUsd !== null) {
|
|
692
|
+
res.status(400).json({ error: 'local_engine_no_cost_cap' });
|
|
693
|
+
return;
|
|
694
|
+
}
|
|
662
695
|
// Freestyle bypasses the OpenSpec pipeline and hands the raw spec to a
|
|
663
696
|
// provider that explicitly advertises autonomous freestyle support.
|
|
664
697
|
if (mode === 'freestyle' && (0, providers_1.getAdapter)(engineCheck.provider).capabilities.freestyle !== true) {
|
|
@@ -779,26 +812,40 @@ function createRailsRouter() {
|
|
|
779
812
|
return;
|
|
780
813
|
}
|
|
781
814
|
}
|
|
815
|
+
const verifierEngine = rolesMode ? (0, loop_role_engines_1.resolveLoopRoleEngine)(c.project, 'verifier', { provider: loopProvider, model: loopAdapter.defaultModel() }, loopRoleEngines) : undefined;
|
|
782
816
|
const loopModel = typeof model === 'string' && model
|
|
783
817
|
? model
|
|
784
|
-
: (profileModel ?? globalAgentDefaults?.pipelineModel ?? loopAdapter.defaultModel());
|
|
818
|
+
: (verifierEngine?.model ?? profileModel ?? globalAgentDefaults?.pipelineModel ?? loopAdapter.defaultModel());
|
|
785
819
|
let effort;
|
|
786
|
-
|
|
820
|
+
// Local (OpenAI-compatible) engines have no per-invocation effort knob
|
|
821
|
+
// unless the connection opts in; a requested effort is DROPPED, not a
|
|
822
|
+
// 400 — the engine selectors send the last-used effort blindly.
|
|
823
|
+
const effortRequested = localEngine && !loopAdapter.capabilities.supportsReasoningEffort ? undefined : (reasoning_effort ?? verifierEngine?.effort);
|
|
824
|
+
if (effortRequested !== undefined && effortRequested !== null) {
|
|
787
825
|
const allowed = (0, providers_1.reasoningEffortsForModel)(loopAdapter, loopModel);
|
|
788
|
-
if (typeof
|
|
789
|
-
!allowed.includes(
|
|
826
|
+
if (typeof effortRequested !== 'string' ||
|
|
827
|
+
!allowed.includes(effortRequested)) {
|
|
790
828
|
res.status(400).json({
|
|
791
829
|
error: `reasoning_effort is not valid for provider "${loopProvider}" and model "${loopModel}"`,
|
|
792
830
|
allowed,
|
|
793
831
|
});
|
|
794
832
|
return;
|
|
795
833
|
}
|
|
796
|
-
effort =
|
|
834
|
+
effort = effortRequested;
|
|
797
835
|
}
|
|
798
836
|
else if (globalAgentDefaults?.pipelineEffort
|
|
799
837
|
&& (0, runtime_1.isReasoningEffortValidForModel)(loopAdapter, loopModel, globalAgentDefaults.pipelineEffort)) {
|
|
800
838
|
effort = globalAgentDefaults.pipelineEffort;
|
|
801
839
|
}
|
|
840
|
+
// Loop Decider engine under roles mode (else the rail's engine, as before).
|
|
841
|
+
// Its provider must enforce a read-only tool policy like the rail's.
|
|
842
|
+
const deciderEngine = rolesMode && loopGraph.nodes.some((node) => node.type === 'decider')
|
|
843
|
+
? (0, loop_role_engines_1.resolveLoopRoleEngine)(c.project, 'decider', { provider: loopProvider, model: loopModel, ...(effort ? { effort } : {}) }, loopRoleEngines)
|
|
844
|
+
: undefined;
|
|
845
|
+
if (deciderEngine && !(0, providers_1.supportsToolPolicy)((0, providers_1.getAdapter)(deciderEngine.provider), 'read-only')) {
|
|
846
|
+
res.status(409).json({ code: 'provider_tool_policy_unsupported', provider: deciderEngine.provider, requiredPolicy: 'read-only', error: `Provider '${deciderEngine.provider}' cannot run Loop Deciders because its headless CLI does not enforce a read-only tool policy.` });
|
|
847
|
+
return;
|
|
848
|
+
}
|
|
802
849
|
// The loop's command(s) declare ticket scope + required capabilities.
|
|
803
850
|
const promptsText = loopGraph.nodes
|
|
804
851
|
.filter((n) => n.type === 'ai-step')
|
|
@@ -934,6 +981,7 @@ function createRailsRouter() {
|
|
|
934
981
|
runtimeProviderOverride,
|
|
935
982
|
ctx: c, railIndex, ticketIds: [...rail.ticketIds], repositoryIds, ...repositoryBases, loopId, loopName, loopGraph,
|
|
936
983
|
provider: loopProvider, model: loopModel, effort, scope,
|
|
984
|
+
...(deciderEngine ? { deciderEngine } : {}),
|
|
937
985
|
profileName: resolvedProfile,
|
|
938
986
|
originSurface: originSurface ?? 'dashboard',
|
|
939
987
|
originConversationId: originConversationId ?? null,
|
|
@@ -1066,6 +1114,7 @@ function createRailsRouter() {
|
|
|
1066
1114
|
provider: loopProvider,
|
|
1067
1115
|
model: loopModel,
|
|
1068
1116
|
effort,
|
|
1117
|
+
...(deciderEngine ? { deciderEngine } : {}),
|
|
1069
1118
|
profileName: resolvedProfile,
|
|
1070
1119
|
})
|
|
1071
1120
|
.then((r) => {
|
|
@@ -1244,6 +1293,13 @@ function createRailsRouter() {
|
|
|
1244
1293
|
catch (err) {
|
|
1245
1294
|
console.warn(`[rails-router] stop: loop cancel(${runId}) failed: ${err.message}`);
|
|
1246
1295
|
}
|
|
1296
|
+
// A run the engine no longer owns (reconciled as an orphan by a context
|
|
1297
|
+
// reload while still alive) never settles through onLoopRunFinished, so
|
|
1298
|
+
// its rail entry would pin the tickets "in flight" forever. When the
|
|
1299
|
+
// durable row is already terminal, release the entry here.
|
|
1300
|
+
const row = (0, loop_runs_store_1.getLoopRun)(c.db, runId);
|
|
1301
|
+
if (!row || row.status === 'completed')
|
|
1302
|
+
c.railLoopRuns.delete(runId);
|
|
1247
1303
|
const stopMsg = {
|
|
1248
1304
|
type: 'loop.run_stopped',
|
|
1249
1305
|
projectId: c.project.id,
|
|
@@ -23,6 +23,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
23
23
|
exports.finaliseInvocationResult = finaliseInvocationResult;
|
|
24
24
|
exports.normaliseResultEvent = normaliseResultEvent;
|
|
25
25
|
const pricing_1 = require("./pricing");
|
|
26
|
+
const local_adapter_1 = require("./providers/local-adapter");
|
|
26
27
|
/**
|
|
27
28
|
* Finalise an AI invocation by walking the adapter's parsed events, stamping
|
|
28
29
|
* the model when the adapter does not report one, and applying the local
|
|
@@ -68,6 +69,22 @@ function finaliseInvocationResult(adapter, events, opts = {}) {
|
|
|
68
69
|
// (COST-ACCOUNTING-AUDIT CRIT-1). A genuine native cost — including a
|
|
69
70
|
// numeric 0 — still passes through untouched with estimated=false.
|
|
70
71
|
const nativeCostAbsent = cloned.total_cost_usd === null || cloned.total_cost_usd === undefined;
|
|
72
|
+
// Local (OpenAI-compatible) engines are NEVER rate-card guessed: cost is the
|
|
73
|
+
// connection's optional user-supplied rates (flagged estimated) or NULL —
|
|
74
|
+
// honest "cost unknown", never $0 (design D9).
|
|
75
|
+
if ((0, local_adapter_1.isLocalAdapter)(adapter)) {
|
|
76
|
+
if (nativeCostAbsent && hasBillableUsage) {
|
|
77
|
+
const computed = (0, pricing_1.estimateLocalCostUsd)(adapter.localConnection.rates, {
|
|
78
|
+
tokens_in: cloned.tokens_in,
|
|
79
|
+
tokens_out: cloned.tokens_out,
|
|
80
|
+
});
|
|
81
|
+
if (computed !== null) {
|
|
82
|
+
cloned.total_cost_usd = computed;
|
|
83
|
+
estimated = true;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
return { result: cloned, estimated };
|
|
87
|
+
}
|
|
71
88
|
if (nativeCostAbsent && hasBillableUsage) {
|
|
72
89
|
const estimator = opts.estimator ?? pricing_1.estimateCostUsd;
|
|
73
90
|
const computed = estimator(adapter.id, cloned.model, {
|
|
@@ -240,6 +240,7 @@ function composeReviewPacket({ db, row, repositoryId = row.repository_id ?? unde
|
|
|
240
240
|
title: snap?.title ?? null,
|
|
241
241
|
problem: narrative.problem,
|
|
242
242
|
solution: narrative.solution,
|
|
243
|
+
solutionOverflow: narrative.overflow,
|
|
243
244
|
labels: snap?.labels ?? [],
|
|
244
245
|
implementationOutcome: unitRows[0]?.implementationOutcome ?? null,
|
|
245
246
|
deliveryOutcome: unitRows[0]?.deliveryOutcome ?? null,
|
|
@@ -12,10 +12,12 @@
|
|
|
12
12
|
"planning": { "enum": ["full", "proportional"] }, "acceptDeveloperChecks": { "type": "boolean" },
|
|
13
13
|
"verification": { "type": "object", "additionalProperties": false, "properties": { "maxConcurrency": { "type": "integer", "minimum": 1, "maximum": 4 } } }
|
|
14
14
|
} },
|
|
15
|
+
"guardrails": { "type": "object", "additionalProperties": false, "properties": { "plan-validation": { "type": "boolean" }, "genuine-blocking-question": { "type": "boolean" }, "plan-language-hint": { "type": "boolean" }, "frozen-plan-writes": { "type": "boolean" }, "primary-language": { "type": "boolean" }, "duplicate-sibling": { "type": "boolean" }, "one-test-per-module": { "type": "boolean" }, "empty-write": { "type": "boolean" }, "evidence-gated-ticking": { "type": "boolean" }, "inventory-retry": { "type": "boolean" }, "synthetic-corrections": { "type": "boolean" }, "silent-group-closure": { "type": "boolean" }, "verify-per-group": { "type": "boolean" }, "test-reachability": { "type": "boolean" }, "exit-code-honesty": { "type": "boolean" }, "environment-repair": { "type": "boolean" }, "lockfile-repair": { "type": "boolean" }, "verify-idle-timeout": { "type": "boolean" } } },
|
|
15
16
|
"rolePrompts": { "type": "object", "additionalProperties": false, "properties": {
|
|
16
17
|
"architect": { "type": "string", "minLength": 1, "maxLength": 20000, "pattern": "\\S" },
|
|
17
18
|
"developer": { "type": "string", "minLength": 1, "maxLength": 20000, "pattern": "\\S" },
|
|
18
|
-
"reviewer": { "type": "string", "minLength": 1, "maxLength": 20000, "pattern": "\\S" }
|
|
19
|
+
"reviewer": { "type": "string", "minLength": 1, "maxLength": 20000, "pattern": "\\S" },
|
|
20
|
+
"fixer": { "type": "string", "minLength": 1, "maxLength": 20000, "pattern": "\\S" }
|
|
19
21
|
} },
|
|
20
22
|
"enabled": { "type": "boolean", "deprecated": true, "description": "Accepted for saved configuration compatibility; implementation always uses the agent runtime." },
|
|
21
23
|
"providers": { "type": "array", "items": { "oneOf": [
|
|
@@ -25,9 +27,14 @@
|
|
|
25
27
|
{ "type": "object", "additionalProperties": false, "required": ["id", "kind", "baseUrl"], "properties": {
|
|
26
28
|
"id": { "$ref": "#/definitions/id" }, "kind": { "const": "openai-compatible" },
|
|
27
29
|
"baseUrl": { "type": "string", "pattern": "^https?://[^/?#@]+(?:/[^?#]*)?$" },
|
|
28
|
-
"apiKeyEnv": { "type": "string", "pattern": "^[A-Za-z_][A-Za-z0-9_]*$" }
|
|
30
|
+
"apiKeyEnv": { "type": "string", "pattern": "^[A-Za-z_][A-Za-z0-9_]*$" },
|
|
31
|
+
"supportsReasoningEffort": { "type": "boolean", "description": "The endpoint honours the OpenAI reasoning_effort request field (low|medium|high)." },
|
|
32
|
+
"agentLoop": { "enum": ["compact", "free"], "description": "compact (default): host-driven pipelines of small structured calls for small local models; free: one agentic loop per role with guardrails." },
|
|
33
|
+
"contextWindowTokens": { "type": "integer", "minimum": 4096, "description": "Context window used for the compaction budget (chars/4 estimate). Default 32768." },
|
|
34
|
+
"maxOutputTokens": { "type": "integer", "minimum": 1024, "description": "Output budget (max_tokens) of one tool turn; retried once at twice this when cut off, always bounded by the remaining context window. Default 8192." }
|
|
29
35
|
} }
|
|
30
36
|
] } },
|
|
37
|
+
"fixer": { "$ref": "#/definitions/agent" },
|
|
31
38
|
"agents": { "type": "object", "additionalProperties": false, "required": ["architect", "developer", "reviewer"], "properties": {
|
|
32
39
|
"architect": { "$ref": "#/definitions/agent" }, "developer": { "$ref": "#/definitions/agent" }, "reviewer": { "$ref": "#/definitions/agent" }
|
|
33
40
|
} },
|
|
@@ -67,6 +74,7 @@
|
|
|
67
74
|
"score": { "type": "number", "minimum": 0, "maximum": 100 },
|
|
68
75
|
"agent": { "type": "object", "additionalProperties": false, "required": ["provider"], "dependencies": { "escalation": ["model"] }, "properties": {
|
|
69
76
|
"effort": { "$ref": "#/definitions/effort" },
|
|
77
|
+
"thinking": { "type": "string", "enum": ["on", "off"], "description": "OpenAI-compatible engines only: private thinking (chat_template_kwargs.enable_thinking). Default off." },
|
|
70
78
|
"escalation": { "type": "object", "additionalProperties": false, "required": ["model"], "properties": {
|
|
71
79
|
"model": { "type": "string", "minLength": 1, "maxLength": 256, "pattern": "^[^-\\r\\n\\u0000][^\\r\\n\\u0000]*$" }, "effort": { "$ref": "#/definitions/effort" }
|
|
72
80
|
} },
|
|
@@ -20,6 +20,7 @@ const win_spawn_1 = require("./util/win-spawn");
|
|
|
20
20
|
const setup_prerequisites_1 = require("./setup-prerequisites");
|
|
21
21
|
const core_package_1 = require("./core-package");
|
|
22
22
|
const providers_1 = require("./providers");
|
|
23
|
+
const registry_1 = require("./providers/registry");
|
|
23
24
|
const runtime_1 = require("./providers/runtime");
|
|
24
25
|
const result_event_1 = require("./result-event");
|
|
25
26
|
const ai_invocations_1 = require("./ai-invocations");
|
|
@@ -752,7 +753,10 @@ class SetupManager {
|
|
|
752
753
|
const state = this.silentAssembleState(projectId);
|
|
753
754
|
if (state.running)
|
|
754
755
|
return;
|
|
755
|
-
|
|
756
|
+
// Local (OpenAI-compatible) engines have no core framework target: core
|
|
757
|
+
// `init` rejects them (`unsupported provider 'local'`), so they never enter
|
|
758
|
+
// the assemble list whatever door (add, detection, retry) supplied them.
|
|
759
|
+
const list = (opts?.providersFilter ?? providers).filter((p) => (0, providers_1.hasAdapter)(p) && !(0, registry_1.isLocalAdapterId)(p));
|
|
756
760
|
if (list.length === 0)
|
|
757
761
|
return;
|
|
758
762
|
this._silentAssembles.set(projectId, { running: true, failed: [] });
|
|
@@ -48,7 +48,14 @@ exports.PROVIDER_DEFAULT_MODEL = {
|
|
|
48
48
|
kimi: 'k3',
|
|
49
49
|
};
|
|
50
50
|
function getModelsForProvider(provider) {
|
|
51
|
-
|
|
51
|
+
const fixed = PROVIDER_MODELS[provider];
|
|
52
|
+
if (fixed)
|
|
53
|
+
return fixed;
|
|
54
|
+
// Dynamically registered adapters (local OpenAI-compatible engines) own a
|
|
55
|
+
// live catalog — the discovered `GET /v1/models` ids, or the stored default.
|
|
56
|
+
if ((0, providers_1.hasAdapter)(provider))
|
|
57
|
+
return (0, providers_1.getAdapter)(provider).modelCatalog().map(({ value, label }) => ({ value, label }));
|
|
58
|
+
return [];
|
|
52
59
|
}
|
|
53
60
|
function isValidModelForProvider(model, provider) {
|
|
54
61
|
if (!(0, providers_1.hasAdapter)(provider))
|
|
@@ -56,5 +63,10 @@ function isValidModelForProvider(model, provider) {
|
|
|
56
63
|
return (0, providers_1.isModelAvailableForAdapter)((0, providers_1.getAdapter)(provider), model);
|
|
57
64
|
}
|
|
58
65
|
function getProviderDefault(provider) {
|
|
59
|
-
|
|
66
|
+
const fixed = exports.PROVIDER_DEFAULT_MODEL[provider];
|
|
67
|
+
if (fixed)
|
|
68
|
+
return fixed;
|
|
69
|
+
if ((0, providers_1.hasAdapter)(provider))
|
|
70
|
+
return (0, providers_1.getAdapter)(provider).defaultModel();
|
|
71
|
+
return '';
|
|
60
72
|
}
|
|
@@ -33,59 +33,21 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
33
33
|
};
|
|
34
34
|
})();
|
|
35
35
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.WORKTREE_DEPENDENCY_CACHES = void 0;
|
|
36
37
|
exports.isWorktreeNodeModulesEnabled = isWorktreeNodeModulesEnabled;
|
|
38
|
+
exports.discoverPackageDirs = discoverPackageDirs;
|
|
37
39
|
exports.authenticateWarmNodeModulesLinks = authenticateWarmNodeModulesLinks;
|
|
38
40
|
exports.linkNodeModulesIntoWorktree = linkNodeModulesIntoWorktree;
|
|
39
41
|
/**
|
|
40
|
-
*
|
|
42
|
+
* Reuse installed packages without sharing tool caches with the base checkout.
|
|
43
|
+
* Each worktree owns its node_modules directory; package entries remain links,
|
|
44
|
+
* while .vite, .vite-temp and .cache are local writable directories. No install,
|
|
45
|
+
* dependency copy or permission broadening is performed. Legacy whole-directory
|
|
46
|
+
* links are migrated only after their exact source has been authenticated.
|
|
41
47
|
*
|
|
42
|
-
*
|
|
43
|
-
*
|
|
44
|
-
*
|
|
45
|
-
* This module links the base checkout's existing install into the worktree so
|
|
46
|
-
* the run starts warm.
|
|
47
|
-
*
|
|
48
|
-
* Mechanics:
|
|
49
|
-
* - DISCOVER: every directory that holds a `package.json` in the base repo at
|
|
50
|
-
* depth ≤ `MAX_DEPTH` (root plus shallow sub-packages like `client/`),
|
|
51
|
-
* skipping dot-dirs and anything inside a `node_modules` tree.
|
|
52
|
-
* - LINK: for each discovered package dir whose base checkout actually has a
|
|
53
|
-
* `node_modules`, create the same relative path in the worktree as a
|
|
54
|
-
* SYMLINK (junction on Windows). No copy fallback on purpose — copying a
|
|
55
|
-
* multi-GB dependency tree would be slower than the `npm install` it
|
|
56
|
-
* replaces; a failed link simply degrades to the legacy cold start.
|
|
57
|
-
* - NEVER overwrite: an existing entry at the destination (a real dir, a
|
|
58
|
-
* prior link, anything) is left untouched, so resume passes are idempotent
|
|
59
|
-
* and an agent-made install is never clobbered.
|
|
60
|
-
*
|
|
61
|
-
* The returned `authenticated` paths are appended to the launch's overlay-
|
|
62
|
-
* exclusion list, so a linked `node_modules` inherits the same commit-time
|
|
63
|
-
* guarantees as overlay scaffolding (excluded pathspecs + index audit) even if
|
|
64
|
-
* the repo's `.gitignore` were ever missing the entry.
|
|
65
|
-
*
|
|
66
|
-
* Release safety (why `authenticated` exists next to `linked`): a repo whose
|
|
67
|
-
* `.gitignore` carries the ordinary `node_modules/` DIRECTORY pattern does not
|
|
68
|
-
* ignore a SYMLINK named `node_modules`, so the link surfaces as an untracked
|
|
69
|
-
* entry in `git status`. Without evidence authorizing it, worktree release read
|
|
70
|
-
* that as "the worktree contains changes made after settlement", parked the row
|
|
71
|
-
* at `needs-review` forever and permanently blocked checkout of the branch. The
|
|
72
|
-
* links therefore also carry `OverlayCleanupEvidence`, and a link created by an
|
|
73
|
-
* EARLIER pass (resume) is re-authenticated instead of being ignored — the old
|
|
74
|
-
* `linked`-only contract silently dropped both guarantees on resume.
|
|
75
|
-
*
|
|
76
|
-
* Authentication is deliberately narrow and source-anchored, never name-based:
|
|
77
|
-
* the worktree entry must be a symlink whose resolved target is exactly the base
|
|
78
|
-
* checkout's identically-named dependency directory. A real directory, a copy,
|
|
79
|
-
* or a link pointing anywhere else stays unauthorized and preserves the
|
|
80
|
-
* worktree, as `Recoverable work is never removed automatically` requires.
|
|
81
|
-
*
|
|
82
|
-
* Honest caveat (documented, accepted): the link SHARES the dependency tree
|
|
83
|
-
* with the base checkout. Reads (tests, builds) are safe under concurrency; an
|
|
84
|
-
* in-worktree `npm install` would write through to the shared tree — the same
|
|
85
|
-
* mutation it would make in the user's checkout after merge.
|
|
86
|
-
*
|
|
87
|
-
* Kill switch: `SPECRAILS_WORKTREE_NODE_MODULES=false` restores the byte-
|
|
88
|
-
* identical cold-worktree behaviour.
|
|
48
|
+
* Cleanup authority covers individual source-anchored links, never the entire
|
|
49
|
+
* writable directory. Replaced packages and newly created files therefore keep
|
|
50
|
+
* the existing ignored-artifact / recoverable-work settlement guarantees.
|
|
89
51
|
*/
|
|
90
52
|
const fs = __importStar(require("fs"));
|
|
91
53
|
const path = __importStar(require("path"));
|
|
@@ -94,6 +56,7 @@ const worktree_overlay_1 = require("./worktree-overlay");
|
|
|
94
56
|
const MAX_DEPTH = 2;
|
|
95
57
|
/** Name of the dependency directory this module links. */
|
|
96
58
|
const DEPS_DIR = 'node_modules';
|
|
59
|
+
exports.WORKTREE_DEPENDENCY_CACHES = ['.vite', '.vite-temp', '.cache'];
|
|
97
60
|
function isWorktreeNodeModulesEnabled() {
|
|
98
61
|
return (process.env.SPECRAILS_WORKTREE_NODE_MODULES ?? '').toLowerCase() !== 'false';
|
|
99
62
|
}
|
|
@@ -139,7 +102,8 @@ function discoverPackageDirs(baseRepo) {
|
|
|
139
102
|
if (name.startsWith('.') || name === 'node_modules')
|
|
140
103
|
continue;
|
|
141
104
|
const childAbs = path.join(abs, name);
|
|
142
|
-
|
|
105
|
+
// A first-party symlink can escape the checkout or form a discovery cycle.
|
|
106
|
+
if (!fs.lstatSync(childAbs).isDirectory())
|
|
143
107
|
continue;
|
|
144
108
|
walk(rel === '' ? name : `${rel}/${name}`, depth + 1);
|
|
145
109
|
}
|
|
@@ -176,7 +140,7 @@ function authenticateWarmLink(baseRepo, worktreePath, rel) {
|
|
|
176
140
|
return null;
|
|
177
141
|
// A link to something that is not a live directory proves nothing about the
|
|
178
142
|
// base checkout's dependency tree.
|
|
179
|
-
if (!
|
|
143
|
+
if (!exists(target))
|
|
180
144
|
return null;
|
|
181
145
|
}
|
|
182
146
|
catch {
|
|
@@ -233,12 +197,60 @@ function discoverWorktreeDependencyPaths(worktreePath) {
|
|
|
233
197
|
function authenticateWarmNodeModulesLinks(baseRepo, worktreePath) {
|
|
234
198
|
const evidence = [];
|
|
235
199
|
for (const rel of discoverWorktreeDependencyPaths(worktreePath)) {
|
|
236
|
-
const
|
|
237
|
-
if (
|
|
238
|
-
evidence.push(
|
|
200
|
+
const legacy = authenticateWarmLink(baseRepo, worktreePath, rel);
|
|
201
|
+
if (legacy) {
|
|
202
|
+
evidence.push(legacy);
|
|
203
|
+
continue;
|
|
204
|
+
}
|
|
205
|
+
const dest = path.join(worktreePath, rel);
|
|
206
|
+
try {
|
|
207
|
+
if (!fs.lstatSync(dest).isDirectory())
|
|
208
|
+
continue;
|
|
209
|
+
for (const name of fs.readdirSync(dest)) {
|
|
210
|
+
if (exports.WORKTREE_DEPENDENCY_CACHES.includes(name))
|
|
211
|
+
continue;
|
|
212
|
+
const entryRel = `${rel}/${name}`;
|
|
213
|
+
const entry = authenticateWarmLink(baseRepo, worktreePath, entryRel);
|
|
214
|
+
if (entry) {
|
|
215
|
+
evidence.push(entry);
|
|
216
|
+
continue;
|
|
217
|
+
}
|
|
218
|
+
// Scoped package parents are local too; never follow foreign symlinks.
|
|
219
|
+
if (name.startsWith('@') && fs.lstatSync(path.join(dest, name)).isDirectory()) {
|
|
220
|
+
for (const scoped of fs.readdirSync(path.join(dest, name))) {
|
|
221
|
+
const child = authenticateWarmLink(baseRepo, worktreePath, `${entryRel}/${scoped}`);
|
|
222
|
+
if (child)
|
|
223
|
+
evidence.push(child);
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
catch { /* Unreadable or concurrently removed entries confer no authority. */ }
|
|
239
229
|
}
|
|
240
230
|
return evidence;
|
|
241
231
|
}
|
|
232
|
+
function linkDependencyEntry(source, destination) {
|
|
233
|
+
fs.symlinkSync(source, destination, process.platform === 'win32'
|
|
234
|
+
? (isDir(source) ? 'junction' : 'file') : undefined);
|
|
235
|
+
}
|
|
236
|
+
function createLocalDependencyTree(source, destination) {
|
|
237
|
+
fs.mkdirSync(destination);
|
|
238
|
+
for (const name of fs.readdirSync(source)) {
|
|
239
|
+
if (exports.WORKTREE_DEPENDENCY_CACHES.includes(name))
|
|
240
|
+
continue;
|
|
241
|
+
const src = path.join(source, name);
|
|
242
|
+
const dest = path.join(destination, name);
|
|
243
|
+
if (name.startsWith('@') && isDir(src)) {
|
|
244
|
+
fs.mkdirSync(dest);
|
|
245
|
+
for (const scoped of fs.readdirSync(src))
|
|
246
|
+
linkDependencyEntry(path.join(src, scoped), path.join(dest, scoped));
|
|
247
|
+
}
|
|
248
|
+
else
|
|
249
|
+
linkDependencyEntry(src, dest);
|
|
250
|
+
}
|
|
251
|
+
for (const cache of exports.WORKTREE_DEPENDENCY_CACHES)
|
|
252
|
+
fs.mkdirSync(path.join(destination, cache));
|
|
253
|
+
}
|
|
242
254
|
/**
|
|
243
255
|
* Link the base checkout's installed `node_modules` trees into a fresh
|
|
244
256
|
* worktree. Best-effort and side-effect-transparent: never throws, never
|
|
@@ -256,25 +268,45 @@ function linkNodeModulesIntoWorktree(baseRepo, worktreePath) {
|
|
|
256
268
|
if (!isDir(src))
|
|
257
269
|
continue;
|
|
258
270
|
const dest = path.join(worktreePath, ...rel.split('/'));
|
|
259
|
-
|
|
271
|
+
const legacy = authenticateWarmLink(baseRepo, worktreePath, rel);
|
|
272
|
+
if (!exists(dest) || legacy) {
|
|
273
|
+
let staging;
|
|
274
|
+
let removedLegacy = false;
|
|
260
275
|
try {
|
|
261
276
|
fs.mkdirSync(path.dirname(dest), { recursive: true });
|
|
262
|
-
fs.
|
|
277
|
+
staging = fs.mkdtempSync(path.join(path.dirname(dest), '.specrails-dependencies-'));
|
|
278
|
+
const prepared = path.join(staging, DEPS_DIR);
|
|
279
|
+
createLocalDependencyTree(src, prepared);
|
|
280
|
+
if (legacy) {
|
|
281
|
+
// Recheck immediately before removing the old link. Never unlink a
|
|
282
|
+
// directory or a replacement another actor installed in the meantime.
|
|
283
|
+
const current = authenticateWarmLink(baseRepo, worktreePath, rel);
|
|
284
|
+
if (!current || current.digest !== legacy.digest)
|
|
285
|
+
throw new Error('dependency link changed during preparation');
|
|
286
|
+
fs.unlinkSync(dest);
|
|
287
|
+
removedLegacy = true;
|
|
288
|
+
}
|
|
289
|
+
fs.renameSync(prepared, dest);
|
|
263
290
|
result.linked.push(rel);
|
|
264
291
|
}
|
|
265
292
|
catch (err) {
|
|
266
|
-
|
|
267
|
-
|
|
293
|
+
if (removedLegacy && !exists(dest)) {
|
|
294
|
+
try {
|
|
295
|
+
linkDependencyEntry(src, dest);
|
|
296
|
+
}
|
|
297
|
+
catch (restoreError) {
|
|
298
|
+
result.warnings.push(`failed to restore ${rel}: ${errMsg(restoreError)}`);
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
result.warnings.push(`failed to prepare ${rel}: ${errMsg(err)}`);
|
|
302
|
+
}
|
|
303
|
+
finally {
|
|
304
|
+
if (staging)
|
|
305
|
+
fs.rmSync(staging, { recursive: true, force: true });
|
|
268
306
|
}
|
|
269
|
-
}
|
|
270
|
-
// Authenticate what is actually on disk NOW — a link we just made, or one a
|
|
271
|
-
// previous pass made. An entry that cannot prove itself (a real dir, an
|
|
272
|
-
// agent-made install) is deliberately left unauthorized.
|
|
273
|
-
const entry = authenticateWarmLink(baseRepo, worktreePath, rel);
|
|
274
|
-
if (entry) {
|
|
275
|
-
result.authenticated.push(rel);
|
|
276
|
-
result.evidence.push(entry);
|
|
277
307
|
}
|
|
278
308
|
}
|
|
309
|
+
result.evidence = authenticateWarmNodeModulesLinks(baseRepo, worktreePath);
|
|
310
|
+
result.authenticated = result.evidence.map(entry => entry.path);
|
|
279
311
|
return result;
|
|
280
312
|
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{a as e}from"./rolldown-runtime-CNC7AqOf.js";import{n as t,t as n}from"./jsx-runtime-zu2_FqZY.js";import{d as r,f as i,m as a,u as o}from"./TicketDetailModalContext-lYmoONrd.js";import{n as s}from"./createLucideIcon-Bjbbp_KS.js";import{s as c}from"./useDesktop-iius_s5d.js";import{Ht as l,I as u,K as d,Q as f,Wt as p,b as m,tt as h}from"./index-DgMBighL.js";var g=e(t(),1),_=n();function v({projectId:e,conversationId:t}){let{t:n}=s(`agent`),{error:v}=p(),y=h(t??`__new-mission__`),{closeBrowser:b,queueCapture:x,browserOwnerId:S,browserUrl:C,setBrowserUrl:w}=d(),{materializeDraftConversation:T}=u(),[E,D]=(0,g.useState)(!1),[O,k]=(0,g.useState)(!1),[A,j]=(0,g.useState)(`probing`);(0,g.useEffect)(()=>{if(t&&(E||O||A===`screencast`))return f(t)},[t,E,O,A]);let M=(0,g.useMemo)(()=>{if(C)return C;try{return i(localStorage.getItem(`specrails-desktop:agent-browser-url:${e}`)??``)??`about:blank`}catch{return`about:blank`}},[e]);(0,g.useEffect)(()=>{let e=!0;return r().then(t=>{e&&j(t?`native`:`screencast`)}),()=>{e=!1}},[]);let N=(0,g.useMemo)(()=>`agent-${t??`home`}-${Math.round(performance.now())}`,[t]),P=async e=>{k(!0);try{let r=await l(t??(await T()).id,a(e.screenshotDataUrl,`capture-${Date.now()}.png`));x(r),c.success(n(`workspace.browserCaptured`)),b()}catch(e){throw c.error(n(`workspace.uploadFailed`),{description:e instanceof Error?e.message:void 0}),e}finally{k(!1)}};return A===`probing`?null:A===`native`?(0,_.jsx)(o,{ownerId:S??void 0,leaseRevision:y,onBusyChange:D,transferError:v,url:M,onClose:b,onFallback:()=>j(`screencast`),onUrlChange:t=>{if(w(t),i(t)&&t!==`about:blank`)try{localStorage.setItem(`specrails-desktop:agent-browser-url:${e}`,t)}catch{}},confirmLabel:n(`workspace.browserConfirm`),selectLabel:n(`workspace.browserSelectStart`),onCaptured:P}):(0,_.jsx)(m,{open:!0,onClose:b,projectId:e,pendingSpecId:N,confirmLabel:n(`workspace.browserConfirm`),selectLabel:n(`workspace.browserSelectStart`),onCaptured:P})}export{v as AgentBrowserCapture};
|
|
@@ -1,2 +0,0 @@
|
|
|
1
|
-
const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["assets/AnalyticsPage-BGtkFHBp.js","assets/rolldown-runtime-CNC7AqOf.js","assets/jsx-runtime-zu2_FqZY.js","assets/chunk-KS7C4IRE-DEKu087k.js","assets/preload-helper-Czpn1I53.js","assets/useSharedWebSocket-D7hkZ3Ka.js","assets/activity-DiyjsgQV.js","assets/addspec-D2YIQ0GU.js","assets/agent-Bh9K7iEt.js","assets/agentRuntime-BNBCzQLM.js","assets/agents-CST-lpYX.js","assets/agentstudio-CN2pokQu.js","assets/aiedit-iIjz2_Qk.js","assets/analytics-BMzCvrCU.js","assets/attachments-B53PG733.js","assets/browser-CG0PE1j_.js","assets/builder-BTiGnPT0.js","assets/chat-BGD7MXAy.js","assets/code-DaZ-ZwCT.js","assets/commands-BAWSYHjQ.js","assets/common-BrlwEnL7.js","assets/dashboard-BfBir_6o.js","assets/explore-DgBACn39.js","assets/integrations-mB-7zoyT.js","assets/jira-CKJg3HZd.js","assets/jobs-DMPU64ms.js","assets/loops-B7YpGizO.js","assets/mcp-CUAN6ORK.js","assets/narration-OyujFouL.js","assets/nav-Ch-zHBG5.js","assets/packet-Cx-zRuWn.js","assets/settings-BlYvaQ7w.js","assets/setup-Ba11l2JA.js","assets/specs-DII0C8gw.js","assets/terminal-BAzpHtpY.js","assets/tickets-W6pBmbrX.js","assets/createLucideIcon-Bjbbp_KS.js","assets/Trans-C0KyPo2O.js","assets/useDesktop-iius_s5d.js","assets/react-dom-DiWzBDP9.js","assets/spending-CN9PHM65.js","assets/clsx-CjueKrWZ.js","assets/formatDistanceToNow-D44phX1J.js","assets/getTimezoneOffsetInMilliseconds-EAh9LFSx.js","assets/provider-capabilities-CXipwrXJ.js","assets/index-DgMBighL.js","assets/TicketDetailModalContext-lYmoONrd.js","assets/save-B6wGWwBR.js","assets/MinimizedChatsContext-DHjHBYqa.js","assets/sparkles-DrY8hb0X.js","assets/x-CBMI9ejn.js","assets/file-text-BcLCfcWZ.js","assets/circle-x-CMYsN4ZH.js","assets/download-CFHyyHcw.js","assets/git-branch-BRM0F5GN.js","assets/loader-circle-DcygOQpC.js","assets/pencil-C9RkrIPZ.js","assets/square-Ci-PFcFe.js","assets/plus-CsnjfkmX.js","assets/search-Cq_gE3Ik.js","assets/trash-2-BOU3WdZZ.js","assets/triangle-alert-H9T4jAmh.js","assets/jira-api-BQR6G0YY.js","assets/zap-CHo3aCD1.js","assets/dialog-xXB2q5HJ.js","assets/utils-BC4DHlz2.js","assets/lib-CGdyxIWg.js","assets/button-Ccc9Dc-D.js","assets/RepositoryScopeSelector-C3jKG2z0.js","assets/project-repositories-GRYdjlKB.js","assets/core-B3mKBIh5.js","assets/RepositoryDeliveries-Dq9NJOWi.js","assets/format-duration-NJVPOPBG.js","assets/event-Bt7f3wXe.js","assets/index-Cfh9aaep.css","assets/ExportDropdown-BwuvqS2Y.js","assets/BarChart-nBOMNfiy.js","assets/value-s-gzBeyF.js"])))=>i.map(i=>d[i]);
|
|
2
|
-
import{a as e}from"./rolldown-runtime-CNC7AqOf.js";import{n as t,t as n}from"./jsx-runtime-zu2_FqZY.js";import{t as r}from"./preload-helper-Czpn1I53.js";import{n as i}from"./createLucideIcon-Bjbbp_KS.js";import{t as a}from"./loader-circle-DcygOQpC.js";import{t as o}from"./x-CBMI9ejn.js";import{t as s}from"./utils-BC4DHlz2.js";import{K as c,vt as l,yt as u}from"./index-DgMBighL.js";var d=e(t(),1),f=n(),p=(0,d.lazy)(()=>r(()=>import(`./AnalyticsPage-BGtkFHBp.js`),__vite__mapDeps([0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77]))),m=420,h=560;function g(){let{t:e}=i(`agent`),{closeAnalyticsPane:t}=c(),[n,r]=(0,d.useState)(h),[g,_]=(0,d.useState)(!1),v=(0,d.useCallback)(e=>{let t=e.clientX,i=n,a=window.innerWidth-m;try{e.currentTarget.setPointerCapture(e.pointerId)}catch{}let o=e=>{let n=Math.min(Math.max(i+(t-e.clientX),m),a);r(n)},s=()=>{window.removeEventListener(`pointermove`,o),window.removeEventListener(`pointerup`,s),window.removeEventListener(`pointercancel`,s)};window.addEventListener(`pointermove`,o),window.addEventListener(`pointerup`,s),window.addEventListener(`pointercancel`,s)},[n]);return(0,f.jsxs)(`div`,{className:s(`flex h-full flex-col overflow-hidden border-l border-border bg-background`,g&&`absolute inset-0 z-30 border-l-0`),style:g?void 0:{width:n,flexShrink:0},"data-testid":`agent-analytics-pane`,children:[(0,f.jsx)(`div`,{className:`relative flex items-center`,children:!g&&(0,f.jsx)(`div`,{role:`separator`,"aria-orientation":`vertical`,onPointerDown:v,className:`absolute left-0 top-0 h-full w-1.5 -translate-x-full cursor-col-resize select-none touch-none hover:bg-accent-primary/20`,title:e(`workspace.resizeAnalytics`)})}),(0,f.jsxs)(`div`,{className:`flex items-center gap-2 border-b border-border/60 bg-surface/40 px-3 py-1.5`,children:[(0,f.jsx)(`span`,{className:`text-xs font-medium text-foreground/70`,children:e(`workspace.analytics`)}),(0,f.jsxs)(`div`,{className:`ml-auto flex items-center gap-1`,children:[(0,f.jsx)(`button`,{type:`button`,onClick:()=>_(e=>!e),"aria-label":e(g?`restore`:`maximize`),title:e(g?`restore`:`maximize`),className:`rounded-md p-1 text-foreground/60 hover:bg-surface hover:text-foreground`,children:g?(0,f.jsx)(l,{className:`h-4 w-4`}):(0,f.jsx)(u,{className:`h-4 w-4`})}),(0,f.jsx)(`button`,{type:`button`,onClick:t,"aria-label":e(`workspace.closeAnalytics`),title:e(`workspace.closeAnalytics`),className:`rounded-md p-1 text-foreground/60 hover:bg-surface hover:text-foreground`,children:(0,f.jsx)(o,{className:`h-4 w-4`})})]})]}),(0,f.jsx)(`div`,{className:`min-h-0 flex-1 overflow-y-auto`,children:(0,f.jsx)(d.Suspense,{fallback:(0,f.jsx)(`div`,{className:`flex h-24 items-center justify-center text-muted-foreground`,children:(0,f.jsx)(a,{className:`h-4 w-4 animate-spin`})}),children:(0,f.jsx)(p,{})})})]})}export{g as AgentModeAnalyticsPane};
|
|
@@ -1,2 +0,0 @@
|
|
|
1
|
-
const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["assets/CodePage-BBnw3VGn.js","assets/rolldown-runtime-CNC7AqOf.js","assets/jsx-runtime-zu2_FqZY.js","assets/react-dom-DiWzBDP9.js","assets/preload-helper-Czpn1I53.js","assets/chunk-KS7C4IRE-DEKu087k.js","assets/TicketDetailModalContext-lYmoONrd.js","assets/useSharedWebSocket-D7hkZ3Ka.js","assets/activity-DiyjsgQV.js","assets/addspec-D2YIQ0GU.js","assets/agent-Bh9K7iEt.js","assets/agentRuntime-BNBCzQLM.js","assets/agents-CST-lpYX.js","assets/agentstudio-CN2pokQu.js","assets/aiedit-iIjz2_Qk.js","assets/analytics-BMzCvrCU.js","assets/attachments-B53PG733.js","assets/browser-CG0PE1j_.js","assets/builder-BTiGnPT0.js","assets/chat-BGD7MXAy.js","assets/code-DaZ-ZwCT.js","assets/commands-BAWSYHjQ.js","assets/common-BrlwEnL7.js","assets/dashboard-BfBir_6o.js","assets/explore-DgBACn39.js","assets/integrations-mB-7zoyT.js","assets/jira-CKJg3HZd.js","assets/jobs-DMPU64ms.js","assets/loops-B7YpGizO.js","assets/mcp-CUAN6ORK.js","assets/narration-OyujFouL.js","assets/nav-Ch-zHBG5.js","assets/packet-Cx-zRuWn.js","assets/settings-BlYvaQ7w.js","assets/setup-Ba11l2JA.js","assets/specs-DII0C8gw.js","assets/terminal-BAzpHtpY.js","assets/tickets-W6pBmbrX.js","assets/createLucideIcon-Bjbbp_KS.js","assets/Trans-C0KyPo2O.js","assets/useDesktop-iius_s5d.js","assets/save-B6wGWwBR.js","assets/spending-CN9PHM65.js","assets/MinimizedChatsContext-DHjHBYqa.js","assets/sparkles-DrY8hb0X.js","assets/x-CBMI9ejn.js","assets/file-text-BcLCfcWZ.js","assets/circle-x-CMYsN4ZH.js","assets/download-CFHyyHcw.js","assets/git-branch-BRM0F5GN.js","assets/loader-circle-DcygOQpC.js","assets/pencil-C9RkrIPZ.js","assets/square-Ci-PFcFe.js","assets/plus-CsnjfkmX.js","assets/search-Cq_gE3Ik.js","assets/trash-2-BOU3WdZZ.js","assets/triangle-alert-H9T4jAmh.js","assets/jira-api-BQR6G0YY.js","assets/zap-CHo3aCD1.js","assets/dialog-xXB2q5HJ.js","assets/utils-BC4DHlz2.js","assets/clsx-CjueKrWZ.js","assets/lib-CGdyxIWg.js","assets/formatDistanceToNow-D44phX1J.js","assets/getTimezoneOffsetInMilliseconds-EAh9LFSx.js","assets/button-Ccc9Dc-D.js","assets/RepositoryScopeSelector-C3jKG2z0.js","assets/project-repositories-GRYdjlKB.js","assets/provider-capabilities-CXipwrXJ.js","assets/index-DgMBighL.js","assets/core-B3mKBIh5.js","assets/RepositoryDeliveries-Dq9NJOWi.js","assets/format-duration-NJVPOPBG.js","assets/event-Bt7f3wXe.js","assets/index-Cfh9aaep.css"])))=>i.map(i=>d[i]);
|
|
2
|
-
import{a as e}from"./rolldown-runtime-CNC7AqOf.js";import{n as t,t as n}from"./jsx-runtime-zu2_FqZY.js";import{t as r}from"./preload-helper-Czpn1I53.js";import{n as i}from"./createLucideIcon-Bjbbp_KS.js";import{t as a}from"./x-CBMI9ejn.js";import{$ as o,K as s,et as c,vt as l,yt as u}from"./index-DgMBighL.js";var d=e(t(),1),f=n(),p=(0,d.lazy)(()=>r(()=>import(`./CodePage-BBnw3VGn.js`),__vite__mapDeps([0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74]))),m=420,h=560;function g({projectId:e,conversationId:t}){let{t:n}=i(`agent`),{closeCodePane:r}=s(),[g,_]=(0,d.useState)(h),[v,y]=(0,d.useState)(()=>window.innerWidth),[b,x]=(0,d.useState)(!1),S=(0,d.useRef)(null),C=(0,d.useRef)(null),w=Math.max(0,v-Math.min(m,v/2)),T=Math.min(m,w),E=Math.min(w,Math.max(T,g)),D=(0,d.useCallback)(e=>Math.min(w,Math.max(T,e)),[w,T]),O=`${e}:${t}`,k=(0,d.useCallback)(n=>{c(e,t,{path:n})},[e,t]);(0,d.useLayoutEffect)(()=>{let e=S.current,t=e?.parentElement;if(!e||!t)return;let n=()=>{let n=t.getBoundingClientRect().width||t.clientWidth||window.innerWidth,r=0;for(let n of t.children){if(n===e||!(n instanceof HTMLElement))continue;let t=getComputedStyle(n);t.display===`none`||t.position===`absolute`||t.position===`fixed`||Number(t.flexGrow)>0||(r+=n.getBoundingClientRect().width)}y(Math.max(0,n-r))},r=new ResizeObserver(n),i=()=>{r.disconnect(),r.observe(t);for(let n of t.children)n!==e&&r.observe(n);n()},a=new MutationObserver(i);return a.observe(t,{childList:!0}),i(),window.addEventListener(`resize`,n),()=>{r.disconnect(),a.disconnect(),window.removeEventListener(`resize`,n)}},[O]),(0,d.useEffect)(()=>()=>{C.current?.()},[O,b,w]);let A=(0,d.useCallback)(e=>{if(e.button!==0)return;e.preventDefault(),C.current?.();let t=e.clientX,n=E,r=e.pointerId,i=e.currentTarget;try{i.setPointerCapture(r)}catch{}let a=e=>{e.pointerId===r&&_(D(n+t-e.clientX))},o=()=>{window.removeEventListener(`pointermove`,a),window.removeEventListener(`pointerup`,s),window.removeEventListener(`pointercancel`,s),window.removeEventListener(`blur`,o),i.removeEventListener(`lostpointercapture`,o);try{i.hasPointerCapture(r)&&i.releasePointerCapture(r)}catch{}C.current=null},s=e=>{e.pointerId===r&&o()};C.current=o,window.addEventListener(`pointermove`,a),window.addEventListener(`pointerup`,s),window.addEventListener(`pointercancel`,s),window.addEventListener(`blur`,o),i.addEventListener(`lostpointercapture`,o)},[E,D]);return(0,f.jsxs)(`div`,{ref:S,className:`flex h-full min-w-0 flex-col overflow-hidden border-l border-border bg-background${b?` absolute inset-0 z-30 border-l-0`:` relative`}`,style:b?void 0:{width:E,maxWidth:`100%`,flexShrink:0},"data-testid":`agent-code-pane`,children:[!b&&(0,f.jsx)(`div`,{role:`separator`,"aria-orientation":`vertical`,onPointerDown:A,tabIndex:0,"aria-label":n(`workspace.resizeCode`),"aria-valuemin":Math.round(T),"aria-valuemax":Math.round(w),"aria-valuenow":Math.round(E),onKeyDown:e=>{let t=e.key===`ArrowLeft`?E+32:e.key===`ArrowRight`?E-32:e.key===`Home`?T:e.key===`End`?w:null;t!==null&&(e.preventDefault(),_(D(t)))},className:`absolute inset-y-0 left-0 z-20 w-1.5 cursor-col-resize select-none touch-none hover:bg-accent-primary/20 focus-visible:bg-accent-primary/30 focus-visible:outline-none`,title:n(`workspace.resizeCode`)}),(0,f.jsxs)(`div`,{className:`flex items-center gap-2 border-b border-border/60 bg-surface/40 px-3 py-1.5`,children:[(0,f.jsx)(`span`,{className:`text-xs font-medium text-foreground/70`,children:n(`workspace.files`)}),(0,f.jsxs)(`div`,{className:`ml-auto flex items-center gap-1`,children:[(0,f.jsx)(`button`,{type:`button`,onClick:()=>{C.current?.(),x(e=>!e)},"aria-label":n(b?`restore`:`maximize`),title:n(b?`restore`:`maximize`),className:`rounded-md p-1 text-foreground/60 hover:bg-surface hover:text-foreground`,children:b?(0,f.jsx)(l,{className:`h-4 w-4`}):(0,f.jsx)(u,{className:`h-4 w-4`})}),(0,f.jsx)(`button`,{type:`button`,onClick:()=>{C.current?.(),r()},"aria-label":n(`workspace.closeFiles`),title:n(`workspace.closeFiles`),className:`rounded-md p-1 text-foreground/60 hover:bg-surface hover:text-foreground`,children:(0,f.jsx)(a,{className:`h-4 w-4`})})]})]}),(0,f.jsx)(`div`,{className:`min-h-0 flex-1 overflow-hidden`,children:(0,f.jsx)(d.Suspense,{fallback:(0,f.jsx)(`div`,{className:`flex h-full items-center justify-center text-sm text-muted-foreground`,children:`…`}),children:(0,f.jsx)(p,{embedded:!0,initialRepositoryId:o(e,t).repositoryId,onRepositoryChange:n=>c(e,t,{repositoryId:n}),initialPath:o(e,t).path,onSelectedPathChange:k},O)})})]},O)}export{g as AgentModeCodePane};
|