specrails-desktop 2.61.0 → 2.63.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/cli/dist/specrails-desktop.js +39 -5
- package/client/dist/assets/ActivityFeedPage-Bn2MpG5M.js +1 -0
- package/client/dist/assets/{AgentBrowserCapture-CkNWDZT3.js → AgentBrowserCapture-CHlXWdXq.js} +1 -1
- package/client/dist/assets/AgentModeAnalyticsPane-yj-YCgrK.js +2 -0
- package/client/dist/assets/AgentModeCodePane-Xczcyghb.js +2 -0
- package/client/dist/assets/{AgentModeJobsPane-U1J6PaBo.js → AgentModeJobsPane-DtOW01ln.js} +1 -1
- package/client/dist/assets/AgentsPage-BMfJ4mzU.js +118 -0
- package/client/dist/assets/AnalyticsPage-CGn5cgtc.js +1 -0
- package/client/dist/assets/BarChart-BDMqVFJy.js +55 -0
- package/client/dist/assets/CodePage-C8NIginr.js +3 -0
- package/client/dist/assets/DesktopAnalyticsPage-C87r4y26.js +1 -0
- package/client/dist/assets/{DocsDialog-CSlMPemn.js → DocsDialog-Z50a_KPv.js} +1 -1
- package/client/dist/assets/{DocsPage-BKlYAvWq.js → DocsPage-DIArbEPl.js} +1 -1
- package/client/dist/assets/{ExportDropdown-CweP_1GP.js → ExportDropdown-CJdCqYd7.js} +1 -1
- package/client/dist/assets/IntegrationsPage-EAipiDWm.js +1 -0
- package/client/dist/assets/InteractiveJobComposer-BxLh4me-.js +19 -0
- package/client/dist/assets/{JobDetailModal-DYyGq1Vp.js → JobDetailModal-C7dWoRu6.js} +1 -1
- package/client/dist/assets/JobDetailPage-Ilu294WS.js +1 -0
- package/client/dist/assets/JobsPage-fPq1hefb.js +1 -0
- package/client/dist/assets/LoopBuilderPage-5M7IypEP.js +1 -0
- package/client/dist/assets/{LoopPreviewModal-DkLRfsYX.js → LoopPreviewModal-ChI3NQC7.js} +1 -1
- package/client/dist/assets/{LoopWindowSurface-CuACkXFV.js → LoopWindowSurface-D1WB9i-9.js} +1 -1
- package/client/dist/assets/LoopsPage-CCwc0Biu.js +2 -0
- package/client/dist/assets/MinimizedChatsContext-eH_KaAZ1.js +1 -0
- package/client/dist/assets/PluginsPage-DfDfEfbW.js +2 -0
- package/client/dist/assets/ProjectSettingsDialog-9NHnG8JQ.js +1 -0
- package/client/dist/assets/RepositoryDeliveries-DgzNnJmn.js +5 -0
- package/client/dist/assets/{RepositoryScopeSelector-CeCr6Jz-.js → RepositoryScopeSelector-BSgUqk_u.js} +1 -1
- package/client/dist/assets/ReviewPacketPage-D34bGpSA.js +4 -0
- package/client/dist/assets/{TemplatePreviewModal-B8yd1AGU.js → TemplatePreviewModal-CcfSxWQ7.js} +1 -1
- package/client/dist/assets/TicketDetailModalContext-BoafEcm4.js +16 -0
- package/client/dist/assets/Trans-CVSryAL1.js +1 -0
- package/client/dist/assets/agent-5bSixVzz.js +1 -0
- package/client/dist/assets/agent-BR4EHfhq.js +1 -0
- package/client/dist/assets/agent-C0IKkJP8.js +1 -0
- package/client/dist/assets/agent-C7li9ayC.js +1 -0
- package/client/dist/assets/agent-D0dRmEen.js +1 -0
- package/client/dist/assets/{agent-BjttZLIl.js → agent-DZVGHm7H.js} +1 -1
- package/client/dist/assets/agent-Dip4h2YE.js +1 -0
- package/client/dist/assets/agent-Pp-P-n1p.js +1 -0
- package/client/dist/assets/ban-wqfdzoXt.js +1 -0
- package/client/dist/assets/{button-D1xExSTF.js → button-4FS1ZDTp.js} +1 -1
- package/client/dist/assets/chevron-up-6EFqEHBj.js +1 -0
- package/client/dist/assets/chunk-OB3PAWPO-B1EMk45A.js +3 -0
- package/client/dist/assets/circle-x-D2ttKotB.js +1 -0
- package/client/dist/assets/createLucideIcon-DtODIU64.js +1 -0
- package/client/dist/assets/{dialog-CMgps2MY.js → dialog-DtdR05v1.js} +1 -1
- package/client/dist/assets/download-C9wP_42h.js +1 -0
- package/client/dist/assets/external-link-CZ6Q-v1-.js +1 -0
- package/client/dist/assets/file-text-C0blZHLh.js +1 -0
- package/client/dist/assets/{formatDistanceToNow-DZ3VWsHq.js → formatDistanceToNow-NVM6rK3i.js} +1 -1
- package/client/dist/assets/{getTimezoneOffsetInMilliseconds-9JiGlFrx.js → getTimezoneOffsetInMilliseconds-ZHg7WpdH.js} +1 -1
- package/client/dist/assets/git-branch-yf6LE1Bw.js +1 -0
- package/client/dist/assets/index-Culan6y7.js +83 -0
- package/client/dist/assets/index-D1v33giW.css +2 -0
- package/client/dist/assets/jira-api-Bl8xEIpk.js +1 -0
- package/client/dist/assets/jsx-runtime-BbYvbtY8.js +1 -0
- package/client/dist/assets/layers-BCLTgHXO.js +1 -0
- package/client/dist/assets/{lib-C7Mhm-gT.js → lib-CQJT8S6Q.js} +1 -1
- package/client/dist/assets/{lib-CGdyxIWg.js → lib-DWJfei6y.js} +1 -1
- package/client/dist/assets/loader-circle-BqV9xYGf.js +1 -0
- package/client/dist/assets/{loop-layout-BF8xMiNv.js → loop-layout-CyXj9223.js} +1 -1
- package/client/dist/assets/pencil-CxrRbDwb.js +1 -0
- package/client/dist/assets/plus-fHDdjBk1.js +1 -0
- package/client/dist/assets/{project-repositories-CadLZOnr.js → project-repositories-CvJf1a6H.js} +1 -1
- package/client/dist/assets/react-dom-DDD8FYaU.js +1 -0
- package/client/dist/assets/rotate-ccw-DalJAQQX.js +1 -0
- package/client/dist/assets/save-LmPSfsvZ.js +1 -0
- package/client/dist/assets/search-BDVp3fkH.js +1 -0
- package/client/dist/assets/{settings-Dn-pXukr.js → settings-BO2N-oPf.js} +1 -1
- package/client/dist/assets/{settings-ByVE7jdZ.js → settings-BQChAs_w.js} +1 -1
- package/client/dist/assets/{settings-BBj_kZaD.js → settings-BzmYlcQB.js} +1 -1
- package/client/dist/assets/{settings-COlH_P33.js → settings-CGjXb6TX.js} +1 -1
- package/client/dist/assets/{settings-D77mC_Lb.js → settings-CMxEWY46.js} +1 -1
- package/client/dist/assets/{settings-DZKy7MqN.js → settings-C_dRSgI2.js} +1 -1
- package/client/dist/assets/{settings-B5Hy_Kol.js → settings-Hw7av-B1.js} +1 -1
- package/client/dist/assets/settings-nryN6wuS.js +1 -0
- package/client/dist/assets/sparkles-CCfUdFGY.js +1 -0
- package/client/dist/assets/spending-BfjSJjBd.js +1 -0
- package/client/dist/assets/square-D0JTbRSR.js +1 -0
- package/client/dist/assets/trash-D8zYUmTg.js +1 -0
- package/client/dist/assets/triangle-alert-Cxpn8bqr.js +1 -0
- package/client/dist/assets/upload-CCHvUkRs.js +1 -0
- package/client/dist/assets/{useDesktop-DKNbOF0u.js → useDesktop-C5JVBeur.js} +1 -1
- package/client/dist/assets/{useRuntimeRuns-D3YMw9qx.js → useRuntimeRuns-DohBmeg8.js} +1 -1
- package/client/dist/assets/useSharedWebSocket-CNOvmgTr.js +2 -0
- package/client/dist/assets/{value-s-gzBeyF.js → value-DtOOK0wQ.js} +1 -1
- package/client/dist/assets/x-Bu7X_eR2.js +1 -0
- package/client/dist/assets/zap-bugHyWzQ.js +1 -0
- package/client/dist/index.html +44 -41
- package/docs/ci-cd.md +8 -1
- package/docs/customizing.md +1 -0
- package/docs/getting-started.md +1 -1
- package/docs/guide/de/integrations/6-agent-chat.md +11 -0
- package/docs/guide/de/settings/5-project-environment.md +27 -0
- package/docs/guide/en/integrations/6-agent-chat.md +11 -0
- package/docs/guide/en/settings/5-project-environment.md +27 -0
- package/docs/guide/es/integrations/6-agent-chat.md +11 -0
- package/docs/guide/es/settings/5-project-environment.md +27 -0
- package/docs/guide/fr/integrations/6-agent-chat.md +11 -0
- package/docs/guide/fr/settings/5-project-environment.md +27 -0
- package/docs/guide/it/integrations/6-agent-chat.md +11 -0
- package/docs/guide/it/settings/5-project-environment.md +27 -0
- package/docs/guide/ja/integrations/6-agent-chat.md +11 -0
- package/docs/guide/ja/settings/5-project-environment.md +27 -0
- package/docs/guide/pt/integrations/6-agent-chat.md +11 -0
- package/docs/guide/pt/settings/5-project-environment.md +27 -0
- package/docs/guide/zh/integrations/6-agent-chat.md +11 -0
- package/docs/guide/zh/settings/5-project-environment.md +27 -0
- package/docs/internals/README.md +1 -0
- package/docs/internals/agent-sessions.md +157 -0
- package/docs/internals/api-reference.md +35 -4
- package/docs/internals/configuration.md +80 -5
- package/docs/internals/core-runtime-updates.md +10 -3
- package/docs/internals/operations-runbook.md +11 -0
- package/docs/internals/programmatic-agent-runtime.md +1 -1
- package/docs/internals/safe-pr-review-flow.md +15 -0
- package/docs/internals/source-map.md +42 -1
- package/docs/mcp.md +1 -1
- package/docs/platforms/macos.md +2 -0
- package/docs/platforms/windows-parity.md +4 -4
- package/docs/platforms/windows.md +9 -9
- package/local-runner/dist/specrails-local-runner.js +1 -1
- package/mcp-bridge/dist/specrails-mcp.js +82 -15
- package/package.json +8 -9
- package/server/dist/agent-mcp-config.js +41 -0
- package/server/dist/core-compat.js +2 -0
- package/server/dist/desktop-db.js +101 -4
- package/server/dist/desktop-router.js +31 -2
- package/server/dist/index.js +58 -0
- package/server/dist/mcp/tools/app-settings.js +11 -0
- package/server/dist/mcp/tools/env.js +38 -3
- package/server/dist/mcp/tools/mission.js +45 -2
- package/server/dist/mcp/tools/specs.js +2 -2
- package/server/dist/modules/accounting/runtime/result-event.js +9 -1
- package/server/dist/modules/agent-runtime/runtime/agent-runtime-controls.js +25 -0
- package/server/dist/modules/agent-sessions/adapters/host-process.js +73 -0
- package/server/dist/modules/agent-sessions/adapters/http.js +31 -0
- package/server/dist/modules/agent-sessions/adapters/rpc-client.js +147 -0
- package/server/dist/modules/agent-sessions/application/session-event-pump.js +99 -0
- package/server/dist/modules/agent-sessions/domain/availability.js +25 -0
- package/server/dist/modules/agent-sessions/domain/errors.js +23 -0
- package/server/dist/modules/agent-sessions/domain/host-state.js +80 -0
- package/server/dist/modules/agent-sessions/domain/projection.js +147 -0
- package/server/dist/modules/agent-sessions/domain/protocol.js +59 -0
- package/server/dist/modules/agent-sessions/domain/subagent-policy.js +34 -0
- package/server/dist/modules/agent-sessions/index.js +31 -0
- package/server/dist/modules/agent-sessions/ports.js +2 -0
- package/server/dist/modules/agent-sessions/runtime/core-sessions-availability.js +43 -0
- package/server/dist/modules/agent-sessions/runtime/session-host-registry.js +226 -0
- package/server/dist/modules/agents/runtime/agent-store.js +3 -1
- package/server/dist/modules/execution/runtime/queue-manager.js +8 -0
- package/server/dist/modules/loops/runtime/loop-executors.js +1 -0
- package/server/dist/modules/loops/runtime/loop-implement-recipe.js +15 -4
- package/server/dist/modules/loops/runtime/loop-run-manager.js +11 -0
- package/server/dist/modules/missions/runtime/agent-chat-manager.js +137 -40
- package/server/dist/modules/missions/runtime/agent-chat-router.js +68 -0
- package/server/dist/modules/missions/runtime/agent-operator-prompt.js +8 -9
- package/server/dist/modules/missions/runtime/agent-session-store.js +133 -0
- package/server/dist/modules/missions/runtime/core-session-runner.js +204 -0
- package/server/dist/modules/missions/runtime/mission-core-sessions.js +286 -0
- package/server/dist/modules/missions/runtime/mission-session-projector.js +168 -0
- package/server/dist/modules/project-settings/adapters/http.js +38 -2
- package/server/dist/modules/project-settings/adapters/sqlite.js +30 -2
- package/server/dist/modules/project-settings/domain.js +24 -0
- package/server/dist/modules/project-settings/index.js +2 -1
- package/server/dist/modules/specs/runtime/spec-models.js +1 -1
- package/server/dist/path-resolver.js +135 -20
- package/server/dist/plugins/codex-spawn.js +15 -7
- package/server/dist/project-env.js +265 -17
- package/server/dist/project-registry.js +46 -0
- package/server/dist/project-router-settings.js +24 -1
- package/server/dist/providers/claude-adapter.js +6 -1
- package/server/dist/worktree-node-modules.js +95 -1
- package/client/dist/assets/ActivityFeedPage-Wi5XNgoG.js +0 -1
- package/client/dist/assets/AgentModeAnalyticsPane-CXz2j-Bt.js +0 -2
- package/client/dist/assets/AgentModeCodePane-DnsBPtpS.js +0 -2
- package/client/dist/assets/AgentsPage-CXrqu5vo.js +0 -118
- package/client/dist/assets/AnalyticsPage-Cvtt-LOO.js +0 -1
- package/client/dist/assets/BarChart-nBOMNfiy.js +0 -33
- package/client/dist/assets/CodePage-D35o-MFO.js +0 -3
- package/client/dist/assets/DesktopAnalyticsPage-CsDFy5rp.js +0 -1
- package/client/dist/assets/IntegrationsPage-Bhy58lnQ.js +0 -1
- package/client/dist/assets/InteractiveJobComposer-CFKvbQeJ.js +0 -19
- package/client/dist/assets/JobDetailPage-C6gpdYvj.js +0 -1
- package/client/dist/assets/JobsPage-CgS0pnKd.js +0 -1
- package/client/dist/assets/LoopBuilderPage-jUp20DSZ.js +0 -1
- package/client/dist/assets/LoopsPage-ClSrWzDd.js +0 -2
- package/client/dist/assets/MinimizedChatsContext-CroAs6Kh.js +0 -1
- package/client/dist/assets/PluginsPage-nCKQOwRL.js +0 -2
- package/client/dist/assets/ProjectSettingsDialog-BVDYwllU.js +0 -1
- package/client/dist/assets/RepositoryDeliveries-DJCm1pZr.js +0 -5
- package/client/dist/assets/ReviewPacketPage-kTErrEjx.js +0 -4
- package/client/dist/assets/TicketDetailModalContext-YBJX3RmP.js +0 -16
- package/client/dist/assets/Trans-D5eOjfvG.js +0 -1
- package/client/dist/assets/agent--8QAfoXL.js +0 -1
- package/client/dist/assets/agent-3HxXkIWX.js +0 -1
- package/client/dist/assets/agent-CpFCz32T.js +0 -1
- package/client/dist/assets/agent-DVnw6ybO.js +0 -1
- package/client/dist/assets/agent-Z5s_GTP0.js +0 -1
- package/client/dist/assets/agent-hv57-zyG.js +0 -1
- package/client/dist/assets/agent-xGrZ_aN1.js +0 -1
- package/client/dist/assets/chunk-KS7C4IRE-DEKu087k.js +0 -3
- package/client/dist/assets/circle-x-CMYsN4ZH.js +0 -1
- package/client/dist/assets/createLucideIcon-Bjbbp_KS.js +0 -1
- package/client/dist/assets/download-CFHyyHcw.js +0 -1
- package/client/dist/assets/external-link-D6XxC_Cu.js +0 -1
- package/client/dist/assets/file-text-BcLCfcWZ.js +0 -1
- package/client/dist/assets/git-branch-BRM0F5GN.js +0 -1
- package/client/dist/assets/index-Bfunvi6w.css +0 -2
- package/client/dist/assets/index-lTGJJTuk.js +0 -83
- package/client/dist/assets/jira-api-Bp0zXwjg.js +0 -1
- package/client/dist/assets/jsx-runtime-zu2_FqZY.js +0 -1
- package/client/dist/assets/loader-circle-DcygOQpC.js +0 -1
- package/client/dist/assets/pencil-C9RkrIPZ.js +0 -1
- package/client/dist/assets/plus-CsnjfkmX.js +0 -1
- package/client/dist/assets/react-dom-DiWzBDP9.js +0 -1
- package/client/dist/assets/rotate-ccw-Wh4id13q.js +0 -1
- package/client/dist/assets/save-OsUqVn99.js +0 -1
- package/client/dist/assets/search-Cq_gE3Ik.js +0 -1
- package/client/dist/assets/settings-Dbyd6gmj.js +0 -1
- package/client/dist/assets/sparkles-DrY8hb0X.js +0 -1
- package/client/dist/assets/spending-DQDNtM8q.js +0 -1
- package/client/dist/assets/square-Ci-PFcFe.js +0 -1
- package/client/dist/assets/trash-2-BOU3WdZZ.js +0 -1
- package/client/dist/assets/triangle-alert-H9T4jAmh.js +0 -1
- package/client/dist/assets/upload-DYMjAQ6M.js +0 -1
- package/client/dist/assets/useSharedWebSocket-DaWuiO0S.js +0 -2
- package/client/dist/assets/x-CBMI9ejn.js +0 -1
- package/client/dist/assets/zap-CUOlvtT1.js +0 -1
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
# Core agent sessions in Desktop
|
|
2
|
+
|
|
3
|
+
Specrails Core runs conversational agent work as **resident sessions**: one
|
|
4
|
+
provider process per conversation that survives between turns, owns its
|
|
5
|
+
sub-agents and records everything in a durable journal. Desktop hosts that
|
|
6
|
+
runtime, projects its events into its own tables and renders them. This page is
|
|
7
|
+
the map for that split. The OpenSpec change
|
|
8
|
+
[`core-agent-sessions-host`](../../openspec/changes/core-agent-sessions-host/design.md)
|
|
9
|
+
holds the decisions; Core's side is documented in Core's `docs/agent-sessions/`.
|
|
10
|
+
|
|
11
|
+
## Who owns what
|
|
12
|
+
|
|
13
|
+
| Concern | Owner |
|
|
14
|
+
| --- | --- |
|
|
15
|
+
| Provider processes, provider frames, sub-agent lifecycle, steering, interrupt | Core drivers (Claude stream-json, Codex app-server) |
|
|
16
|
+
| Usage normalisation (per-turn deltas, billed vs estimated cost) | Core |
|
|
17
|
+
| Durable journal `~/.specrails/sessions/<scope>/sessions.sqlite` | Core (single writer per scope) |
|
|
18
|
+
| Host supervision (one host per scope), protocol client, generic projection | Desktop [`server/modules/agent-sessions`](../../server/modules/agent-sessions/README.md) |
|
|
19
|
+
| Surface tables, accounting rows, WebSocket events, UI | Desktop surfaces (missions today) |
|
|
20
|
+
| Queue, receipts, MCP capability, tiers, titles, PR/rail cards | Desktop product rules (unchanged) |
|
|
21
|
+
|
|
22
|
+
Desktop never interprets provider frames and never branches on provider ids:
|
|
23
|
+
it relies on the driver capabilities Core declares in `initialize`.
|
|
24
|
+
|
|
25
|
+
## Scopes and hosts
|
|
26
|
+
|
|
27
|
+
A scope is a project slug, or `global` for missions without a pinned project.
|
|
28
|
+
Desktop starts `specrails-core runtime host --stdio --scope <scope>` lazily on
|
|
29
|
+
the first session of that scope ([`CoreHostLauncher`](../../server/modules/agent-sessions/adapters/host-process.ts))
|
|
30
|
+
and supervises it in the [`SessionHostRegistry`](../../server/modules/agent-sessions/runtime/session-host-registry.ts):
|
|
31
|
+
|
|
32
|
+
- pings with a timeout; unexpected exits restart with capped backoff;
|
|
33
|
+
- after a restart, tracked sessions are resumed and replayed from their cursors;
|
|
34
|
+
- repeated failures mark the scope `degraded`: new turns use the legacy
|
|
35
|
+
transport and the mission shows a notice with Retry;
|
|
36
|
+
- causes a restart cannot fix degrade at once: another host owns the journal
|
|
37
|
+
(`journal_locked`), the protocol does not match, or Core lacks the host;
|
|
38
|
+
- removing a project stops its host; app shutdown sends `host.shutdown`, then
|
|
39
|
+
tree-kills.
|
|
40
|
+
|
|
41
|
+
## Turns: the runner seam
|
|
42
|
+
|
|
43
|
+
Missions run turns through `nativeLiveSessionRunner(adapter) ?? runAiCliInvocation`.
|
|
44
|
+
[`createCoreSessionRunner`](../../server/modules/missions/runtime/core-session-runner.ts)
|
|
45
|
+
is a third implementation of that contract. [`MissionCoreSessions.prepareTurn`](../../server/modules/missions/runtime/mission-core-sessions.ts)
|
|
46
|
+
selects it when the scope is available and Core lists a driver for the
|
|
47
|
+
conversation's provider. The runner opens or resumes the session, sends the
|
|
48
|
+
prompt as one input, maps user-turn events to `AdapterEvent`s, delivers steer
|
|
49
|
+
through `session.send`, and returns Core's normalised usage. Stop goes through a
|
|
50
|
+
`TurnHandle` (`session.interrupt`); deleting a mission calls `session.close`.
|
|
51
|
+
|
|
52
|
+
MCP: each turn mints a capability and rewrites the conversation's capability
|
|
53
|
+
file; the bridge re-reads it per request, so a resident provider always presents
|
|
54
|
+
the current turn's capability. The capability outlives the turn while
|
|
55
|
+
background work may still call Specrails tools, until the next turn rotates it
|
|
56
|
+
or Core retires the process. Structured MCP specs include the Specrails bridge,
|
|
57
|
+
external servers and app-installed plugin servers.
|
|
58
|
+
|
|
59
|
+
## Projection
|
|
60
|
+
|
|
61
|
+
```
|
|
62
|
+
Core journal ──session.event──▶ SessionEventPump ──ProjectionOp[]──▶ ProjectionSink (surface)
|
|
63
|
+
(seq, dedupe, (domain/projection.ts, one transaction:
|
|
64
|
+
gap fill) pure reducer) rows + cursor, then WS
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
- [`SessionEventPump`](../../server/modules/agent-sessions/application/session-event-pump.ts)
|
|
68
|
+
applies each `(sessionId, seq)` once and in order; gaps and `session.lagged`
|
|
69
|
+
are filled from `session.events`. On attach it rebuilds in-memory state up to
|
|
70
|
+
the sink cursor without re-applying.
|
|
71
|
+
- [`MissionSessionProjector`](../../server/modules/missions/runtime/mission-session-projector.ts)
|
|
72
|
+
is the missions sink. It persists what happens outside user turns: sub-agents
|
|
73
|
+
(`agent_subagents`) and their output (`agent_subagent_events`), resident phase
|
|
74
|
+
and cursor (`agent_session_cursors`), and continuation turns as messages with
|
|
75
|
+
`turn_origin` `subagent`/`system` plus invocations with `origin`. User turns
|
|
76
|
+
are settled by the mission manager.
|
|
77
|
+
- Continuation turns get a deterministic invocation id, so replay never records
|
|
78
|
+
a turn twice. `POST /api/agent/conversations/:id/session/rebuild` resets the
|
|
79
|
+
derived rows and replays the journal silently (see the
|
|
80
|
+
[API reference](api-reference.md)).
|
|
81
|
+
|
|
82
|
+
## Sub-agent policy
|
|
83
|
+
|
|
84
|
+
[`resolveSubagentPolicy`](../../server/modules/agent-sessions/domain/subagent-policy.ts)
|
|
85
|
+
maps `(surface, project setting, app setting)` to `policy.subagents`. A
|
|
86
|
+
conversation with a project follows the project's "Allow sub-agents" setting.
|
|
87
|
+
A conversation without a project follows the app setting. Both default to off.
|
|
88
|
+
Implement pipelines are not a surface, so they never resolve a policy. The
|
|
89
|
+
composition root wires the resolver into `MissionCoreSessions`. Settings
|
|
90
|
+
routes call `ProjectRegistry.notifySettingsChanged`, and
|
|
91
|
+
`MissionCoreSessions.refreshSubagentPolicy` then sends the complete policy to
|
|
92
|
+
each open session of that scope. Core's `session.update` replaces the policy as
|
|
93
|
+
a whole and ignores unchanged configurations, so the resident process is not
|
|
94
|
+
restarted for nothing. A session with running sub-agents reports the change as
|
|
95
|
+
deferred, and the mission offers "Stop agents and apply now". If Core rejects
|
|
96
|
+
a policy with `policy_unenforceable`, the mission shows a localized error that
|
|
97
|
+
names the provider and the setting.
|
|
98
|
+
|
|
99
|
+
## Sub-agent runtime (who launches them)
|
|
100
|
+
|
|
101
|
+
The hybrid runtime decides who launches sub-agents once the policy allows them.
|
|
102
|
+
[`resolveSubagentRuntime`](../../server/modules/agent-sessions/domain/subagent-policy.ts)
|
|
103
|
+
maps the "Run sub-agents with" choice (project setting `subagentRuntime`, or the
|
|
104
|
+
app setting for missions without a project), the mission's provider and the
|
|
105
|
+
Core capabilities to `policy.subagentRuntime`:
|
|
106
|
+
|
|
107
|
+
| Choice | Mission provider | Runtime sent to Core |
|
|
108
|
+
| --- | --- | --- |
|
|
109
|
+
| `null` (same as the mission agent) | any | `{ mode: 'native' }` |
|
|
110
|
+
| provider P, model M, effort E | P | `{ mode: 'native', model?, effort? }`. Only overrides the driver declares through `capabilities.subagentModel` / `subagentEffort` are sent (Claude: model only, Codex: both) |
|
|
111
|
+
| provider P, model M, effort E | not P | `{ mode: 'delegated', driver: P, model: M, effort? }` |
|
|
112
|
+
|
|
113
|
+
When Core lacks `capabilities.delegation`, or P is not one of its drivers, the
|
|
114
|
+
mission stays native and receives an `agent_session_notice` with code
|
|
115
|
+
`subagents.delegation_unsupported` or `subagents.driver_unavailable` and the
|
|
116
|
+
`provider`. A setting change refreshes open sessions like the policy does.
|
|
117
|
+
|
|
118
|
+
In a delegated session Core disables the provider's own sub-agent tool and the
|
|
119
|
+
mission agent launches sub-agents through the Specrails MCP: `specrails_mission`
|
|
120
|
+
actions `subagent_start`, `subagent_wait`, `subagent_list` and `subagent_stop`
|
|
121
|
+
call `AgentChatManager.delegateSubagent` / `waitSubagents` / `stopSubagents`,
|
|
122
|
+
which map to Core's `session.delegate`, `session.waitSubagents` and
|
|
123
|
+
`session.stopSubagents`. `MissionCoreSessions` adds a short system prompt
|
|
124
|
+
addendum that tells the agent how to delegate. Each delegated sub-agent is a
|
|
125
|
+
Core child session (its own process, no shared prompt cache), mirrored into the
|
|
126
|
+
mission's tree with `delegated: { driver, model }`; results nobody waited for
|
|
127
|
+
arrive as a system continuation turn. Its usage is billed separately
|
|
128
|
+
(`subagent.usage` with `billing: 'separate'`): the projector records it as its
|
|
129
|
+
own invocation (`core-subagent:<conversation>:<subagent>:<seq>`, origin
|
|
130
|
+
`subagent`, the child's provider) on top of the parent's cost. Migration 34
|
|
131
|
+
adds `delegated_driver` / `delegated_model` to `agent_subagents`.
|
|
132
|
+
|
|
133
|
+
## UI
|
|
134
|
+
|
|
135
|
+
The client keeps session state in [`MissionSessionsContext`](../../client/src/features/missions/context/MissionSessionsContext.tsx)
|
|
136
|
+
over a pure reducer ([`mission-sessions.ts`](../../client/src/features/missions/lib/mission-sessions.ts)).
|
|
137
|
+
Each launch renders as a compact line under the message whose `core_turn_id`
|
|
138
|
+
started it. `agent_done` carries `coreTurnId`, so the anchor exists without a
|
|
139
|
+
reload. A launch whose reply has no text sits after the message that preceded
|
|
140
|
+
it. The line is expanded while agents work and folds once they finish. The
|
|
141
|
+
sidebar keeps a live dot for missions with background work. Details are in the
|
|
142
|
+
[missions feature guide](../../client/src/features/missions/README.md).
|
|
143
|
+
|
|
144
|
+
## Rollout
|
|
145
|
+
|
|
146
|
+
`SPECRAILS_CORE_SESSIONS` (`auto` by default, `on` or `off`, see
|
|
147
|
+
[configuration](configuration.md)) gates the Core path. It only takes effect
|
|
148
|
+
when the selected Core advertises `sessions` and its session contract matches
|
|
149
|
+
([`core-compat.ts`](../../server/core-compat.ts)). Otherwise, missions keep
|
|
150
|
+
their legacy transports.
|
|
151
|
+
|
|
152
|
+
## Verify
|
|
153
|
+
|
|
154
|
+
```bash
|
|
155
|
+
npx vitest run server/modules/agent-sessions server/modules/missions
|
|
156
|
+
npm run test --prefix client -- src/features/missions
|
|
157
|
+
```
|
|
@@ -93,8 +93,8 @@ Example — register a project that uses both Claude and Gemini:
|
|
|
93
93
|
|
|
94
94
|
| Method | Path | Notes |
|
|
95
95
|
|--------|------|-------|
|
|
96
|
-
| `GET` | `/settings` | App-wide settings |
|
|
97
|
-
| `PUT` | `/settings` | Update any subset of `{ port?, specrailsTechUrl?, costAlertThresholdUsd? }` |
|
|
96
|
+
| `GET` | `/settings` | App-wide settings, including `allowSubagents` (default `false`) and `subagentRuntime` (default `null`) |
|
|
97
|
+
| `PUT` | `/settings` | Update any subset of `{ port?, specrailsTechUrl?, costAlertThresholdUsd?, allowSubagents?, subagentRuntime? }`. `subagentRuntime` is `null` (same as the mission agent) or `{ provider, model, effort: string \| null }` for missions without a project; an invalid value returns `400`. `allowSubagents` is the app-wide "Allow sub-agents" setting for missions without a project. It must be a boolean (otherwise `400` and nothing is written), and a change refreshes the policy of open sessions |
|
|
98
98
|
| `GET` | `/budget` | App-wide budget config |
|
|
99
99
|
| `PATCH` | `/budget` | Update the app-wide daily budget |
|
|
100
100
|
| `GET` | `/theme` | Current UI theme (defaults to `specrails`) |
|
|
@@ -149,6 +149,35 @@ Proxies the external specrails-tech agents service (base URL from `desktop_setti
|
|
|
149
149
|
| `POST` | `/agents` | Create an agent entry |
|
|
150
150
|
| `PATCH` | `/agents/:id` | Update |
|
|
151
151
|
|
|
152
|
+
### Missions: Core agent session sub-agents (`/api/agent/*`)
|
|
153
|
+
|
|
154
|
+
These routes are available when a mission ran in a Core agent session (`SPECRAILS_CORE_SESSIONS`, see [agent sessions](../../server/modules/agent-sessions/README.md)). Rows are Desktop's rebuildable projection of Core's session journal.
|
|
155
|
+
|
|
156
|
+
| Method | Path | Notes |
|
|
157
|
+
|--------|------|-------|
|
|
158
|
+
| `GET` | `/agent/active-turns` | Reconnect snapshot. Besides `turns`, the response includes `sessions[]`: `{ conversationId, residentPhase, processAlive, liveSubagents, subagents }` for missions with background work. |
|
|
159
|
+
| `GET` | `/agent/conversations/:id` | Includes `session`: `{ residentPhase, processAlive, liveSubagents, subagents }`, or `null` when the mission never ran in Core. |
|
|
160
|
+
| `GET` | `/agent/conversations/:id/subagents` | `{ subagents, session }`. Each sub-agent has id, parent, kind, agent type, description, phase (`running`/`idle`/`failed`/`stopped`/`killed`/`interrupted`), reason, restarts, launching Core turn, timestamps, usage, tool uses, duration and result summary. Sub-agents Specrails launched on another provider carry `delegated: { driver, model }`; their usage is recorded as separate `subagent` invocations. |
|
|
161
|
+
| `GET` | `/agent/conversations/:id/subagents/:subagentId/events?after=&limit=` | Paged sub-agent transcript `{ events: [{ seq, channel, delta?, tool?, createdAt }], hasMore }`. `limit` is 1–1000. |
|
|
162
|
+
| `POST` | `/agent/conversations/:id/subagents/stop` | Body `{ subagentIds? }` (all when omitted). Returns `{ stopped }`; `502` when the session host is unavailable. |
|
|
163
|
+
| `POST` | `/agent/conversations/:id/session/rebuild` | Operator repair: replays the mission's Core journal into its sub-agent rows, events, resident state and cursor. Turns already recorded as messages/invocations are not duplicated; the replay is silent, then clients receive `agent_resident_state` and one `agent_subagent` per row. Returns `{ lastSeq, subagents }`; `409` while a turn runs or when the mission has no Core session; `502` when the host is unavailable. |
|
|
164
|
+
|
|
165
|
+
| `GET` | `/agent/session-hosts` | `{ hosts: [{ scope, status, detail, code }] }`: one entry per Core session host scope (project slug or `global`). `code` explains a degraded scope (`journal_locked`, `protocol_mismatch`, `driver_unavailable`). |
|
|
166
|
+
| `POST` | `/agent/session-hosts/:scope/retry` | Starts a degraded scope again. Returns `{ host }`, or `502` with `{ error, host }` when it is still unavailable. |
|
|
167
|
+
|
|
168
|
+
WebSocket events for these missions:
|
|
169
|
+
|
|
170
|
+
- `agent_resident_state`, `agent_subagent`, `agent_subagent_event`;
|
|
171
|
+
- `agent_turn_started` / `agent_turn_done` for turns Core starts after sub-agents finish (origin `subagent` or `system`);
|
|
172
|
+
- `agent_session_updated` (`applied` / `deferred`) and `agent_session_notice` (`level`, `code`, `message`, optional `scope`). The notice covers provider warnings such as `policy.subagent_blocked`, and a turn that fell back to the legacy transport (`host_degraded`, `journal_locked`);
|
|
173
|
+
- `agent_sessions_host` (app-level, no `projectId`): `{ scope, status, detail, code }` on every host status change.
|
|
174
|
+
|
|
175
|
+
Background turns also stream `agent_stream`, `agent_tool` and `agent_tool_result` with a `turnId`.
|
|
176
|
+
|
|
177
|
+
`agent_session_notice` with code `subagents.delegation_unsupported` or `subagents.driver_unavailable` (and `provider`) says a "Run sub-agents with" choice cannot be honoured, so the mission stays native. In delegated missions the agent uses the `specrails_mission` MCP actions `subagent_start`, `subagent_wait`, `subagent_list` and `subagent_stop`.
|
|
178
|
+
|
|
179
|
+
`agent_error` may carry `code` and `provider` for failures the client explains in the user's language. One example is `policy_unenforceable`, sent when a provider cannot honour "Allow sub-agents: off".
|
|
180
|
+
|
|
152
181
|
### Webhooks
|
|
153
182
|
|
|
154
183
|
| Method | Path | Notes |
|
|
@@ -405,8 +434,10 @@ Gated by `requireBrowserCaptureEnabled` — returns 404 when the feature is disa
|
|
|
405
434
|
|
|
406
435
|
| Method | Path | Notes |
|
|
407
436
|
|--------|------|-------|
|
|
408
|
-
| `GET` | `/settings` | Project settings |
|
|
409
|
-
| `PATCH` | `/settings` | Update |
|
|
437
|
+
| `GET` | `/settings` | Project settings, including `allowSubagents` (default `false`) and `subagentRuntime` (default `null`) |
|
|
438
|
+
| `PATCH` | `/settings` | Update. `allowSubagents` must be a boolean; `subagentRuntime` is `null` or `{ provider, model, effort: string \| null }` (strictly validated). A change to either refreshes the sub-agent policy of the project's open agent sessions. A change to `worktreeEnvPassthrough` (names only) re-warms the project's login-shell recovery |
|
|
439
|
+
| `GET` | `/env-passthrough/status` | Value-free resolution status of every configured `worktreeEnvPassthrough` name: `{ loginShellRecovery, timeoutMs, checking, names: [{ name, status, shell, checkedAt, exitCode }] }`. `status` is `inherited`, `recovered`, `not-defined`, `probe-timeout`, `probe-failed`, or `pending` for a name never checked. Probes first only when a missing name has no valid cached result. Never returns values |
|
|
440
|
+
| `POST` | `/env-passthrough/recheck` | Probe the login shell now (asynchronously, `SPECRAILS_LOGIN_SHELL_TIMEOUT_MS`, default 10 s), then return the same payload as the status route |
|
|
410
441
|
| `GET` | `/terminal-settings` | Per-project terminal overrides |
|
|
411
442
|
| `PATCH` | `/terminal-settings` | Update |
|
|
412
443
|
| `GET` | `/agent-models` | Per-agent model overrides |
|
|
@@ -175,17 +175,58 @@ shell when a GUI launch does not supply it. A zsh login shell reads `~/.zprofile
|
|
|
175
175
|
adding it to tracked repository files. Windows uses its inherited environment.
|
|
176
176
|
|
|
177
177
|
Recovered values stay in a project-owned in-memory overlay, not the server's global
|
|
178
|
-
environment, SQLite or runtime snapshots.
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
178
|
+
environment, SQLite or runtime snapshots. Removing a configured name drops its
|
|
179
|
+
recovered value and status immediately. A missing value remains absent: Desktop
|
|
180
|
+
never substitutes a dummy credential or treats a blocked package-manager command as passed.
|
|
181
|
+
|
|
182
|
+
#### Login-shell recovery and resolution status
|
|
183
|
+
|
|
184
|
+
The login-shell probe runs `$SHELL -l -i -c 'printf …'` and reads only the requested
|
|
185
|
+
names from a block bracketed by sentinels. Text a profile prints outside that block
|
|
186
|
+
(banners, instant prompts) is ignored. A complete block is accepted **whatever the
|
|
187
|
+
shell's exit status**; a non-zero exit is kept only as a diagnostic.
|
|
188
|
+
|
|
189
|
+
- **Asynchronous warm cache.** Desktop probes in the background when a project opens,
|
|
190
|
+
when its configured names change, and about a minute before a successful result
|
|
191
|
+
expires. The probe never blocks the server's event loop. Its budget is 10 seconds by
|
|
192
|
+
default; set `SPECRAILS_LOGIN_SHELL_TIMEOUT_MS` (milliseconds, capped at 120000) to
|
|
193
|
+
change it. The refresh stops when the project is removed.
|
|
194
|
+
- **Spawn-time reads.** Rail jobs, loop steps and retained runtime controls read the
|
|
195
|
+
warm cache synchronously. Only a name that was never checked (or whose success
|
|
196
|
+
expired) gets the short synchronous fallback, bounded at 1.5 seconds. When that
|
|
197
|
+
fallback fails, the asynchronous probe is started immediately so the next spawn can
|
|
198
|
+
use its result.
|
|
199
|
+
- **Lifetimes.** Recovered values stay valid for 10 minutes and are refreshed before
|
|
200
|
+
then; a failed refresh keeps a still-valid value. Failed or empty lookups are retried
|
|
201
|
+
after 30 seconds. Changing `SHELL`, `HOME` or `ZDOTDIR` discards cached results.
|
|
202
|
+
|
|
203
|
+
Each configured name has a value-free status, kept in the owning project's memory
|
|
204
|
+
together with the shell used and the time of the check:
|
|
205
|
+
|
|
206
|
+
| Status | Meaning |
|
|
207
|
+
|--------|---------|
|
|
208
|
+
| `inherited` | Present in the environment Desktop started with. |
|
|
209
|
+
| `recovered` | Read from the login shell. |
|
|
210
|
+
| `not-defined` | The probe succeeded but the shell does not export the name (also used on Windows, where there is no login-shell recovery). |
|
|
211
|
+
| `probe-timeout` | The shell did not print the block within the budget. |
|
|
212
|
+
| `probe-failed` | The shell could not be started, or its output had no complete sentinel block. |
|
|
213
|
+
|
|
214
|
+
`GET /api/projects/:projectId/env-passthrough/status` returns these statuses
|
|
215
|
+
(`pending` appears only for a name that has never been checked), and
|
|
216
|
+
`POST /api/projects/:projectId/env-passthrough/recheck` probes immediately. The
|
|
217
|
+
Project Settings environment card shows them as chips with a **Check again** action,
|
|
218
|
+
and the MCP `specrails_env` tool exposes them through `get`, `status` and `recheck`.
|
|
219
|
+
When a rail, loop or queued job starts with a configured name unresolved, its run log
|
|
220
|
+
receives one aggregated warning, for example
|
|
221
|
+
`[environment] NODE_AUTH_TOKEN not available (probe-timeout); configure it in the login shell or launch from a terminal`.
|
|
222
|
+
Statuses, logs and MCP output contain names and states only, never values.
|
|
183
223
|
|
|
184
224
|
A few env vars are read directly by the app. The two most useful operational ones:
|
|
185
225
|
|
|
186
226
|
| Variable | Description |
|
|
187
227
|
|----------|-------------|
|
|
188
228
|
| `SPECRAILS_TECH_URL` | Fallback specrails-tech base URL. Resolution order is the `specrails_tech_url` app setting **first**, then this env var, then `http://localhost:3000` — so a stored app setting takes precedence over this var. |
|
|
229
|
+
| `SPECRAILS_LOGIN_SHELL_TIMEOUT_MS` | Budget in milliseconds for the asynchronous login-shell probe that recovers configured project environment names (default `10000`, capped at `120000`). The synchronous cold fallback keeps its 1.5 s bound. See [Login-shell recovery](#login-shell-recovery-and-resolution-status). |
|
|
189
230
|
| `WM_ZOMBIE_TIMEOUT_MS` | Zombie-job detection timeout in milliseconds (default `1800000` = 30 min). This is a stuck-job watchdog, **not** a hard "kill after N minutes" cap. |
|
|
190
231
|
|
|
191
232
|
### Provider rollback gates
|
|
@@ -205,6 +246,40 @@ its native key/config, and Kimi via `kimi login` or user-managed
|
|
|
205
246
|
`~/.kimi-code/config.toml`. See [Kimi](../kimi.md), [Codex](../codex.md), and
|
|
206
247
|
[Gemini](../gemini.md).
|
|
207
248
|
|
|
249
|
+
### Core agent sessions (rollout)
|
|
250
|
+
|
|
251
|
+
| Variable | Effect |
|
|
252
|
+
|----------|--------|
|
|
253
|
+
| `SPECRAILS_CORE_SESSIONS` | `auto` (default) uses Core's agent session host (`specrails-core runtime host`) when the selected Core advertises the `sessions` capability and its session contract is compatible. `on` behaves like `auto` but is reported as forced. `off` keeps conversational features on their legacy transports. It cannot enable sessions on a Core that lacks them, and Desktop logs the reason. |
|
|
254
|
+
|
|
255
|
+
With sessions enabled, Desktop runs one Core host per project, plus one for
|
|
256
|
+
project-less missions. Session journals live in
|
|
257
|
+
`~/.specrails/sessions/<project>/sessions.sqlite`, owned by Core. Desktop
|
|
258
|
+
stores only a rebuildable projection. See
|
|
259
|
+
[agent sessions](../../server/modules/agent-sessions/README.md).
|
|
260
|
+
|
|
261
|
+
**Allow sub-agents** is a setting, not a flag, and it is off by default. The
|
|
262
|
+
project setting `allowSubagents` (`config.allow_subagents`) applies to that
|
|
263
|
+
project's conversational agents (missions, explore, refinements). The app
|
|
264
|
+
setting (`agent_allow_subagents` in `desktop_settings`) covers missions without
|
|
265
|
+
a project. Implement pipelines never read it. Desktop sends the resolved value
|
|
266
|
+
to Core as `policy.subagents`. Core enforces it through the provider switch, and
|
|
267
|
+
it also stops any sub-agent a provider starts anyway. A change reaches open
|
|
268
|
+
sessions immediately: idle sessions apply it, and sessions with running
|
|
269
|
+
sub-agents report it as deferred. The setting is read-only over the Specrails
|
|
270
|
+
MCP, so an agent cannot grant itself sub-agents.
|
|
271
|
+
|
|
272
|
+
**Run sub-agents with** chooses who launches them. The project setting
|
|
273
|
+
`subagentRuntime` (`config.subagent_runtime`, JSON) and the app setting
|
|
274
|
+
(`agent_subagent_runtime` in `desktop_settings`) hold `null` (the default: the
|
|
275
|
+
mission agent's own provider launches native sub-agents) or
|
|
276
|
+
`{ provider, model, effort }`. Missions on that provider keep native sub-agents
|
|
277
|
+
with that model and effort; missions on another provider get sub-agents that
|
|
278
|
+
Core launches on the chosen provider (delegated), at the cost of a cold start
|
|
279
|
+
and no shared prompt cache. The UI asks for confirmation before leaving the
|
|
280
|
+
default. The setting is read-only over the Specrails MCP. See
|
|
281
|
+
[agent sessions](agent-sessions.md#sub-agent-runtime-who-launches-them).
|
|
282
|
+
|
|
208
283
|
For the full catalogue of feature flags and kill switches (`SPECRAILS_*` server gates, `VITE_FEATURE_*` client flags, `SPECRAILS_CODEX_BETA`, `SPECRAILS_GEMINI_BETA`, `SPECRAILS_EXPLORE_*`), see [../customizing.md](../customizing.md#environment-variables).
|
|
209
284
|
|
|
210
285
|
---
|
|
@@ -13,15 +13,22 @@ framework is rejected rather than silently replacing an update.
|
|
|
13
13
|
|
|
14
14
|
## Persistence and publication
|
|
15
15
|
|
|
16
|
-
The release bundle pins Core 6.
|
|
16
|
+
The release bundle pins Core 6.5.0 in `desktop-release.yml` and
|
|
17
17
|
`scripts/assemble-bundled-core.lock.json`. Core 6 is the Desktop-only engine: it
|
|
18
18
|
publishes integration contract 5.1 (no standalone `update`) and ships only the
|
|
19
19
|
implement and retry workflows (Batch was folded into implement; Desktop no
|
|
20
20
|
longer requires `batch-implement` but stays compatible with Cores that still ship it). Update both pins together and check compatibility against
|
|
21
21
|
the staged published package; retained runs still use their original runtime.
|
|
22
22
|
|
|
23
|
-
|
|
24
|
-
|
|
23
|
+
`scripts/assemble-bundled-core.mjs` relocates any pnpm virtual store a
|
|
24
|
+
dependency leaks into its tarball (today `@langchain/langgraph-sdk` ships
|
|
25
|
+
`dist/node_modules/.pnpm/…` and imports it by relative path) to
|
|
26
|
+
`<dir>/_pnpm/<entry>`, rewriting the relative imports that cross it, so the
|
|
27
|
+
module still loads while every staged path stays inside the MSI budget
|
|
28
|
+
(`MAX_STAGED_RELATIVE_PATH`, 120 characters).
|
|
29
|
+
|
|
30
|
+
The paired CI checkout uses the immutable Core 6.5.0 release commit
|
|
31
|
+
`187f9d24533a99fb1f37c7805b3c5b1375040d25`. Bundle smoke checks use Node 22.22.3,
|
|
25
32
|
matching Core's minimum supported Node version and the Desktop release runtime.
|
|
26
33
|
|
|
27
34
|
Desktop updates retain the complete npm installation, including dependencies,
|
|
@@ -140,6 +140,17 @@ If a single provider or feature is breaking the app, you can turn it off with an
|
|
|
140
140
|
|
|
141
141
|
These are the most common ops escape hatches; see [Configuration → Environment variables](configuration.md#environment-variables) for the complete list of gates and flags.
|
|
142
142
|
|
|
143
|
+
### Missions on Core agent sessions
|
|
144
|
+
|
|
145
|
+
With `SPECRAILS_CORE_SESSIONS` at `auto` (the default) or `on`, missions run in a Core host
|
|
146
|
+
process per project scope (`specrails-core runtime host --stdio --scope …`).
|
|
147
|
+
The server log prefix is `[agent-sessions]`.
|
|
148
|
+
|
|
149
|
+
- **Status.** The server logs each scope's transitions: `starting`, `ready`, `restarting`, `degraded`. `GET /api/agent/session-hosts` lists them. A degraded scope sends new mission turns through the legacy transport, and the mission shows why, with a **Retry** button (`POST /api/agent/session-hosts/:scope/retry`). Crashes degrade a scope after repeated failures. Some causes degrade it at once, without restart attempts: another Desktop instance holding the journal (`journal_locked`), an incompatible Core (`protocol_mismatch`), or a Core without the host (`driver_unavailable`). Close the other instance or fix Core, then retry.
|
|
150
|
+
- **Session data.** Core owns the journals in `~/.specrails/sessions/<project>/sessions.sqlite`. Desktop's tables (`agent_session_cursors`, `agent_subagents`, `agent_subagent_events`) are a projection. If they look wrong, rebuild them for one mission with `POST /api/agent/conversations/:id/session/rebuild`. This never duplicates messages or spend.
|
|
151
|
+
- **Turn it off.** `SPECRAILS_CORE_SESSIONS=off` returns every mission to the legacy transports. Missions keep their history; sub-agent cards remain for past turns.
|
|
152
|
+
- **Live check (paid, opt-in).** `SPECRAILS_LIVE_PROVIDER_SMOKE=1 npx vitest run server/modules/missions/runtime/mission-core-sessions.live.test.ts` runs real Claude missions against the local `../specrails-core` build. Add `SPECRAILS_LIVE_PROVIDERS=claude,codex` to include Codex, and `SPECRAILS_LIVE_<PROVIDER>_MODEL` to pick a model the account can use.
|
|
153
|
+
|
|
143
154
|
### Per-project reset (keeps the registration)
|
|
144
155
|
|
|
145
156
|
To clear one project's job history, invocations, and telemetry pointers while keeping it registered, delete just that project's `jobs.sqlite` with the app stopped:
|
|
@@ -119,7 +119,7 @@ All routes are under `/api/projects/:projectId`:
|
|
|
119
119
|
| `POST /agent-runtime/runs/:runId/resume` | Accept `{}`, `{ "approve": ["archive"] }`, `{ "recover": ["developer"] }`, explicit `invalidate` phase IDs, or `{ "answer": "…" }` for a pending question (required while one is open) |
|
|
120
120
|
| `POST /agent-runtime/runs/:runId/cancel` | Cancel a continuation owned by this controller |
|
|
121
121
|
|
|
122
|
-
Host blockers (Core `hostBlockers: 1` / `setupCommands: 1`): the Implement recipe opts its `verify` nodes into host-owned environment repair and the `blocked` outcome. Core emits `[environment] <command> (<repository>)` and `Environment: installed …` lines on the `verification-output` channel, so they reach the readable job log through the same projection as checks. A precondition Core cannot satisfy (no network for a browser download, registry credentials, a failing `setup` command, a missing toolchain) ends the run at `host-blocked` with `completion.blocker = { kind, reason, command, args, cwd, requiredAction, evidenceId? }`; a fixer-declared `blocker` ends it at `fixer-blocked`. The bridge maps that completion (`ok: false`) to `runtimeStatus: 'blocked'`, the run row shows the blocked badge and the loop log renders "Blocked by the host environment" with the localized kind, the failing command and cwd, the required action and a copy button. Older Core packages receive the pre-blocker definition and no `setup` list.
|
|
122
|
+
Host blockers (Core `hostBlockers: 1` / `setupCommands: 1`): the Implement recipe opts its `verify` nodes into host-owned environment repair and the `blocked` outcome. Core emits `[environment] <command> (<repository>)` and `Environment: installed …` lines on the `verification-output` channel, so they reach the readable job log through the same projection as checks. A precondition Core cannot satisfy (no network for a browser download, registry credentials, a failing `setup` command, a missing toolchain) ends the run at `host-blocked` with `completion.blocker = { kind, reason, command, args, cwd, requiredAction, evidenceId? }`; a fixer-declared `blocker` ends it at `fixer-blocked`. A developer-declared `blocker` ends the run at `developer-blocked` only for kinds the person must provide (`credential`, `network`, `environment-variable`); any other kind goes to host verification first: a host precondition ends at `host-blocked`, a reproduced failure goes to the fixer as a correction, and passing checks reach the reviewer, whose rejection of unfinished tasks is corrected within the same budget. The developer loop is bounded like corrections: when `tasks` finds approved tasks still unchecked, the developer runs again only while its last turn changed the candidate (`implementation-progress`, otherwise `implementation-stalled`) and within `implementationLimit` = 3 attempts (`implementation-exhausted`); both ends report the developer's `incomplete` list and summary. The bridge maps that completion (`ok: false`) to `runtimeStatus: 'blocked'`, the run row shows the blocked badge and the loop log renders "Blocked by the host environment" with the localized kind, the failing command and cwd, the required action and a copy button. Older Core packages receive the pre-blocker definition and no `setup` list.
|
|
123
123
|
|
|
124
124
|
Resume responds `202` after admission and continues asynchronously. Legacy phase IDs are `architect`, `developer`, `fixer`, `verify`, `reviewer` and `archive`. For engine v2, use `POST /loop-runs/:runId/resume` instead. `recover` contains exact attempt IDs from `GET /loop-runs/:runId/recovery`; approval and answer controls use pending interrupt IDs. Node paths are display context, not recovery identities. The saved-execution panel and job header expose explicit per-attempt selection. Core's lease and Desktop's execution/mount claim jointly prevent competing writers. Resident human pauses keep their original settlement callback; restart recovery reconnects to the frozen delivery allocation and terminal outbox.
|
|
125
125
|
|
|
@@ -133,6 +133,21 @@ Both temporary checkouts use non-force cleanup, including after a Git runner exc
|
|
|
133
133
|
including proofs for historical misplaced links; symlinked destination ancestors confer no
|
|
134
134
|
authority. Registration paths, frozen manifests and Core scope remain unchanged. A failed run
|
|
135
135
|
keeps its old checkout; after updating Desktop, a fresh Relaunch receives the corrected layout.
|
|
136
|
+
- Warm reuse is gated by dependency freshness. Before preparing a new link for a package
|
|
137
|
+
directory, Desktop compares its dependency inputs in the base checkout and in the worktree: the
|
|
138
|
+
nearest lockfile found walking up to the Git top level (first of `pnpm-lock.yaml`, `yarn.lock`,
|
|
139
|
+
`package-lock.json`, `npm-shrinkwrap.json`, `bun.lock`, at the same relative position) and a
|
|
140
|
+
canonical digest of the `package.json` dependency, devDependency, optionalDependency and
|
|
141
|
+
peerDependency fields (scripts and other metadata are ignored). If either input differs, or one
|
|
142
|
+
cannot be read, the directory gets no `node_modules` and the run reports, on the
|
|
143
|
+
`rail.overlay_degraded` channel, for example
|
|
144
|
+
`apps/catalog: yarn.lock differs from the base checkout; dependencies will be installed in the worktree`.
|
|
145
|
+
Core's environment preparation then installs that directory cold from the worktree's own lockfile.
|
|
146
|
+
This prevents a base checkout on another branch, or behind the remote, from supplying packages
|
|
147
|
+
the run's code does not declare. Desktop never checks out, pulls or installs anything in the
|
|
148
|
+
user's checkout to make warm reuse possible. Links already present for a resumed run keep their
|
|
149
|
+
authentication; the guard only applies when a link is prepared. `SPECRAILS_WORKTREE_NODE_MODULES=false`
|
|
150
|
+
still disables warm reuse entirely.
|
|
136
151
|
- Per-unit settlement returns structured execution + delivery results. `onLoopRunFinished` receives
|
|
137
152
|
the engine outcome only; commit/status/ref/provenance/push failures cannot rewrite it.
|
|
138
153
|
- Before staging, settlement blocks active OpenSpec change directories introduced relative to
|
|
@@ -5,7 +5,7 @@ architectural dependency declaration. Search a heading or filename and read only
|
|
|
5
5
|
the relevant source and tests. Feature prefixes group the legacy server files;
|
|
6
6
|
new bounded modules live under `server/modules/`.
|
|
7
7
|
|
|
8
|
-
Includes
|
|
8
|
+
Includes 1044 source/build files. Nearby tests are linked where names
|
|
9
9
|
match; integration suites may live elsewhere. Use `rg` to find other consumers.
|
|
10
10
|
|
|
11
11
|
## cli
|
|
@@ -457,7 +457,9 @@ match; integration suites may live elsewhere. Use `rg` to find other consumers.
|
|
|
457
457
|
- [AgentRefChip.tsx](../../client/src/features/missions/components/AgentRefChip.tsx)
|
|
458
458
|
- [AgentRunFailureMarker.tsx](../../client/src/features/missions/components/AgentRunFailureMarker.tsx)
|
|
459
459
|
- [AgentRuntimeSelector.tsx](../../client/src/features/missions/components/AgentRuntimeSelector.tsx)
|
|
460
|
+
- [AgentSessionIndicators.tsx](../../client/src/features/missions/components/AgentSessionIndicators.tsx)
|
|
460
461
|
- [AgentSpecDraftCard.tsx](../../client/src/features/missions/components/AgentSpecDraftCard.tsx)
|
|
462
|
+
- [AgentSubagentsCard.tsx](../../client/src/features/missions/components/AgentSubagentsCard.tsx)
|
|
461
463
|
- [AgentThinkingHalo.tsx](../../client/src/features/missions/components/AgentThinkingHalo.tsx) · [test](../../client/src/features/missions/components/__tests__/AgentThinkingHalo.test.tsx)
|
|
462
464
|
- [AgentTierChip.tsx](../../client/src/features/missions/components/AgentTierChip.tsx)
|
|
463
465
|
- [AgentToolbarSelector.tsx](../../client/src/features/missions/components/AgentToolbarSelector.tsx)
|
|
@@ -486,6 +488,7 @@ match; integration suites may live elsewhere. Use `rg` to find other consumers.
|
|
|
486
488
|
- [AgentChatContext.tsx](../../client/src/features/missions/context/AgentChatContext.tsx) · [test](../../client/src/features/missions/context/AgentChatContext.test.tsx)
|
|
487
489
|
- [AgentWorkspaceContext.tsx](../../client/src/features/missions/context/AgentWorkspaceContext.tsx) · [test](../../client/src/features/missions/context/__tests__/AgentWorkspaceContext.test.tsx)
|
|
488
490
|
- [MinimizedChatsContext.tsx](../../client/src/features/missions/context/MinimizedChatsContext.tsx) · [test](../../client/src/features/missions/context/__tests__/MinimizedChatsContext.test.tsx)
|
|
491
|
+
- [MissionSessionsContext.tsx](../../client/src/features/missions/context/MissionSessionsContext.tsx) · [test](../../client/src/features/missions/context/__tests__/MissionSessionsContext.test.tsx)
|
|
489
492
|
- [MissionSplitViewsContext.tsx](../../client/src/features/missions/context/MissionSplitViewsContext.tsx)
|
|
490
493
|
- [MissionWindowsContext.tsx](../../client/src/features/missions/context/MissionWindowsContext.tsx) · [test](../../client/src/features/missions/context/__tests__/MissionWindowsContext.test.tsx)
|
|
491
494
|
|
|
@@ -500,10 +503,12 @@ match; integration suites may live elsewhere. Use `rg` to find other consumers.
|
|
|
500
503
|
- [agent-context-palette.ts](../../client/src/features/missions/lib/agent-context-palette.ts) · [test](../../client/src/features/missions/lib/__tests__/agent-context-palette.test.ts)
|
|
501
504
|
- [agent-refs.ts](../../client/src/features/missions/lib/agent-refs.ts) · [test](../../client/src/features/missions/lib/__tests__/agent-refs.test.ts)
|
|
502
505
|
- [mission-search.ts](../../client/src/features/missions/lib/mission-search.ts) · [test](../../client/src/features/missions/lib/__tests__/mission-search.test.ts)
|
|
506
|
+
- [mission-sessions.ts](../../client/src/features/missions/lib/mission-sessions.ts) · [test](../../client/src/features/missions/lib/__tests__/mission-sessions.test.ts)
|
|
503
507
|
- [mission-split-layout.ts](../../client/src/features/missions/lib/mission-split-layout.ts) · [test](../../client/src/features/missions/lib/__tests__/mission-split-layout.test.ts)
|
|
504
508
|
- [mission-view-state.ts](../../client/src/features/missions/lib/mission-view-state.ts)
|
|
505
509
|
- [mission-window-controller.ts](../../client/src/features/missions/lib/mission-window-controller.ts) · [test](../../client/src/features/missions/lib/__tests__/mission-window-controller.test.ts)
|
|
506
510
|
- [mission-windows.ts](../../client/src/features/missions/lib/mission-windows.ts) · [test](../../client/src/features/missions/lib/__tests__/mission-windows.test.ts)
|
|
511
|
+
- [subagent-result.ts](../../client/src/features/missions/lib/subagent-result.ts) · [test](../../client/src/features/missions/lib/__tests__/subagent-result.test.ts)
|
|
507
512
|
|
|
508
513
|
## client/src/features/plugins/lib
|
|
509
514
|
|
|
@@ -600,6 +605,7 @@ match; integration suites may live elsewhere. Use `rg` to find other consumers.
|
|
|
600
605
|
- [RuntimeRetention.tsx](../../client/src/features/settings/components/RuntimeRetention.tsx) · [test](../../client/src/features/settings/components/__tests__/RuntimeRetention.test.tsx)
|
|
601
606
|
- [RuntimeRolePrompts.tsx](../../client/src/features/settings/components/RuntimeRolePrompts.tsx) · [test](../../client/src/features/settings/components/__tests__/RuntimeRolePrompts.test.tsx)
|
|
602
607
|
- [RuntimeSteering.tsx](../../client/src/features/settings/components/RuntimeSteering.tsx) · [test](../../client/src/features/settings/components/__tests__/RuntimeSteering.test.tsx)
|
|
608
|
+
- [SubagentsSettingsSection.tsx](../../client/src/features/settings/components/SubagentsSettingsSection.tsx) · [test](../../client/src/features/settings/components/__tests__/SubagentsSettingsSection.test.tsx)
|
|
603
609
|
- [TerminalSettingsSection.tsx](../../client/src/features/settings/components/TerminalSettingsSection.tsx)
|
|
604
610
|
|
|
605
611
|
## client/src/features/settings/components/pickers
|
|
@@ -842,7 +848,9 @@ match; integration suites may live elsewhere. Use `rg` to find other consumers.
|
|
|
842
848
|
- [generate-icons.mjs](../../scripts/generate-icons.mjs)
|
|
843
849
|
- [generate-mobile-types.mjs](../../scripts/generate-mobile-types.mjs)
|
|
844
850
|
- [generate-source-map.mjs](../../scripts/generate-source-map.mjs) · [test](../../scripts/generate-source-map.test.mjs)
|
|
851
|
+
- [module-references.mjs](../../scripts/module-references.mjs) · [test](../../scripts/module-references.test.mjs)
|
|
845
852
|
- [obfuscate-chromium.mjs](../../scripts/obfuscate-chromium.mjs)
|
|
853
|
+
- [paired-core-shards.mjs](../../scripts/paired-core-shards.mjs) · [test](../../scripts/paired-core-shards.test.mjs)
|
|
846
854
|
- [patch-node-pty.mjs](../../scripts/patch-node-pty.mjs) · [test](../../scripts/patch-node-pty.test.mjs)
|
|
847
855
|
- [recover-desktop-channel.mjs](../../scripts/recover-desktop-channel.mjs) · [test](../../scripts/recover-desktop-channel.test.mjs)
|
|
848
856
|
- [release-policy.mjs](../../scripts/release-policy.mjs) · [test](../../scripts/release-policy.test.mjs)
|
|
@@ -1098,6 +1106,35 @@ match; integration suites may live elsewhere. Use `rg` to find other consumers.
|
|
|
1098
1106
|
- [agent-runtime-verification-log.ts](../../server/modules/agent-runtime/runtime/agent-runtime-verification-log.ts)
|
|
1099
1107
|
- [agent-runtime-verification-suggestions.ts](../../server/modules/agent-runtime/runtime/agent-runtime-verification-suggestions.ts) · [test](../../server/modules/agent-runtime/runtime/agent-runtime-verification-suggestions.test.ts)
|
|
1100
1108
|
|
|
1109
|
+
## server/modules/agent-sessions
|
|
1110
|
+
|
|
1111
|
+
- [index.ts](../../server/modules/agent-sessions/index.ts)
|
|
1112
|
+
- [ports.ts](../../server/modules/agent-sessions/ports.ts)
|
|
1113
|
+
|
|
1114
|
+
## server/modules/agent-sessions/adapters
|
|
1115
|
+
|
|
1116
|
+
- [host-process.ts](../../server/modules/agent-sessions/adapters/host-process.ts)
|
|
1117
|
+
- [http.ts](../../server/modules/agent-sessions/adapters/http.ts)
|
|
1118
|
+
- [rpc-client.ts](../../server/modules/agent-sessions/adapters/rpc-client.ts)
|
|
1119
|
+
|
|
1120
|
+
## server/modules/agent-sessions/application
|
|
1121
|
+
|
|
1122
|
+
- [session-event-pump.ts](../../server/modules/agent-sessions/application/session-event-pump.ts)
|
|
1123
|
+
|
|
1124
|
+
## server/modules/agent-sessions/domain
|
|
1125
|
+
|
|
1126
|
+
- [availability.ts](../../server/modules/agent-sessions/domain/availability.ts)
|
|
1127
|
+
- [errors.ts](../../server/modules/agent-sessions/domain/errors.ts)
|
|
1128
|
+
- [host-state.ts](../../server/modules/agent-sessions/domain/host-state.ts)
|
|
1129
|
+
- [projection.ts](../../server/modules/agent-sessions/domain/projection.ts)
|
|
1130
|
+
- [protocol.ts](../../server/modules/agent-sessions/domain/protocol.ts)
|
|
1131
|
+
- [subagent-policy.ts](../../server/modules/agent-sessions/domain/subagent-policy.ts)
|
|
1132
|
+
|
|
1133
|
+
## server/modules/agent-sessions/runtime
|
|
1134
|
+
|
|
1135
|
+
- [core-sessions-availability.ts](../../server/modules/agent-sessions/runtime/core-sessions-availability.ts)
|
|
1136
|
+
- [session-host-registry.ts](../../server/modules/agent-sessions/runtime/session-host-registry.ts)
|
|
1137
|
+
|
|
1101
1138
|
## server/modules/agents/runtime
|
|
1102
1139
|
|
|
1103
1140
|
- [agent-catalog.ts](../../server/modules/agents/runtime/agent-catalog.ts)
|
|
@@ -1309,10 +1346,14 @@ match; integration suites may live elsewhere. Use `rg` to find other consumers.
|
|
|
1309
1346
|
- [agent-fence-promotion.ts](../../server/modules/missions/runtime/agent-fence-promotion.ts)
|
|
1310
1347
|
- [agent-input-store.ts](../../server/modules/missions/runtime/agent-input-store.ts) · [test](../../server/modules/missions/runtime/agent-input-store.test.ts)
|
|
1311
1348
|
- [agent-operator-prompt.ts](../../server/modules/missions/runtime/agent-operator-prompt.ts) · [test](../../server/modules/missions/runtime/agent-operator-prompt.test.ts)
|
|
1349
|
+
- [agent-session-store.ts](../../server/modules/missions/runtime/agent-session-store.ts)
|
|
1312
1350
|
- [agent-spec-framing.ts](../../server/modules/missions/runtime/agent-spec-framing.ts) · [test](../../server/modules/missions/runtime/agent-spec-framing.test.ts)
|
|
1313
1351
|
- [agent-steering.ts](../../server/modules/missions/runtime/agent-steering.ts) · [test](../../server/modules/missions/runtime/agent-steering.test.ts)
|
|
1314
1352
|
- [agent-tier.ts](../../server/modules/missions/runtime/agent-tier.ts)
|
|
1353
|
+
- [core-session-runner.ts](../../server/modules/missions/runtime/core-session-runner.ts) · [test](../../server/modules/missions/runtime/core-session-runner.test.ts)
|
|
1354
|
+
- [mission-core-sessions.ts](../../server/modules/missions/runtime/mission-core-sessions.ts) · [test](../../server/modules/missions/runtime/mission-core-sessions.test.ts)
|
|
1315
1355
|
- [mission-run-notify.ts](../../server/modules/missions/runtime/mission-run-notify.ts) · [test](../../server/modules/missions/runtime/mission-run-notify.test.ts)
|
|
1356
|
+
- [mission-session-projector.ts](../../server/modules/missions/runtime/mission-session-projector.ts) · [test](../../server/modules/missions/runtime/mission-session-projector.test.ts)
|
|
1316
1357
|
|
|
1317
1358
|
## server/modules/project-settings
|
|
1318
1359
|
|
package/docs/mcp.md
CHANGED
|
@@ -48,7 +48,7 @@ reading one description. The tools are:
|
|
|
48
48
|
| `specrails_loops` | Saved loop workflows |
|
|
49
49
|
| `specrails_code` | File discovery, literal content search, bounded line reads, summaries and provenance; AI summary regeneration is capability-gated |
|
|
50
50
|
| `specrails_git` | Repository/branch/worktree information, status, diffs and PR lookup |
|
|
51
|
-
| `specrails_env` | Project environment readiness and environment-file management |
|
|
51
|
+
| `specrails_env` | Project environment readiness and environment-file management; `get`/`status`/`recheck` report each configured name's value-free resolution status |
|
|
52
52
|
| `specrails_support` | Support triage, local diagnostics and specrails-core update workflows |
|
|
53
53
|
| `specrails_setup` | Add-project setup wizard surface |
|
|
54
54
|
| `specrails_analytics` | Per-project spending analytics + budget |
|
package/docs/platforms/macos.md
CHANGED
|
@@ -77,6 +77,8 @@ When the app runs without an active bundle (a runtimes-less build, or `npm run d
|
|
|
77
77
|
|
|
78
78
|
2. **Login-shell merge (async)** — right after the HTTP server starts listening, `augmentPathFromLoginShell()` spawns `$SHELL -l -i` once (1500 ms timeout) and merges whatever `PATH` that login + interactive shell exposes. This recovers the segments that Volta, nvm, fnm, asdf, etc. add only inside your interactive shell — whatever your `$SHELL` produces, no specific rc file is assumed. On timeout or non-zero exit, the fast-path `PATH` stays in effect and a single warning is logged.
|
|
79
79
|
|
|
80
|
+
Project environment names configured in Project Settings (for example `NODE_AUTH_TOKEN`) use a separate, per-project login-shell probe with a 10 s budget (`SPECRAILS_LOGIN_SHELL_TIMEOUT_MS`). It runs in the background, never writes to `process.env`, and reports a status per name. See [configuration](../internals/configuration.md#login-shell-recovery-and-resolution-status).
|
|
81
|
+
|
|
80
82
|
The resolved `PATH` is stored on `process.env.PATH`, so every downstream spawn inherits it (`QueueManager` → provider CLI, `SetupManager` → `npx specrails-core`, `terminalManager` PTYs, etc.).
|
|
81
83
|
|
|
82
84
|
## Broken-symlink detection
|
|
@@ -6,8 +6,8 @@ This audit covers the `codex/multi-repo-projects` branch, including mission stee
|
|
|
6
6
|
|
|
7
7
|
| Feature | Windows implementation and checks |
|
|
8
8
|
| --- | --- |
|
|
9
|
-
| Installation, native runtimes | Native x64/ARM64 NSIS
|
|
10
|
-
| Desktop updates |
|
|
9
|
+
| Installation, native runtimes | Native x64/ARM64 NSIS builds; WebView2 provisioning through the embedded bootstrapper; bundled Node/Git/core/OpenSpec; staged SQLite and full ConPTY/WinPTY dependency validation. |
|
|
10
|
+
| Desktop updates | NSIS-specific and generic Tauri targets both reference the NSIS installer; earlier MSI installs fall back to the generic entry and the NSIS installer removes the WiX installation. Missing, empty or ambiguous artifact/signature pairs fail manifest generation. Publication is serialized, and previous download installers are retained until the remote manifest matches the new release. |
|
|
11
11
|
| Startup and project catalog | Recover the actual Windows profile rather than inventing `C:\Users\Default`; SQLite catalog/repository IDs reopen under the same Unicode/spaced profile. |
|
|
12
12
|
| Projects and multi-repo | Repository membership and canonical identity use real paths; junction and case aliases cannot add the same repository twice. Shared backlog and per-repository jobs retain their existing regression coverage. |
|
|
13
13
|
| Core setup and updates | Offline assembly from the shipped core; preserve and restore the previous active framework if Windows junction replacement fails. Installed-package smoke waits for the real workspace marker. |
|
|
@@ -28,7 +28,7 @@ This audit covers the `codex/multi-repo-projects` branch, including mission stee
|
|
|
28
28
|
|
|
29
29
|
`.github/workflows/windows-parity.yml` runs a `windows-parity` job on `windows-latest` (x64) for every pull request and push to `main`, adding `windows-11-arm` on the `main` pushes. It installs dependencies, checks TypeScript, runs release/PTY helper regression tests, native filesystem/process tests (retried once, they drive real processes), the application build, native host build/tests, and four real native fixtures: WebView2 capture/selection, authentication popups, mission window handoff, and browser multiwindow transfer/parking. It is deliberately a separate workflow from `ci.yml`: `release.yml` waits for CI only, so a slow or flaky Windows run never delays the release PR, while Desktop Release still builds and installs on Windows before publication. The jsdom client suite is not repeated on Windows; it runs on Linux in CI. The bundled-core matrix in `ci.yml` exercises Windows junction/copy relocation for providers.
|
|
30
30
|
|
|
31
|
-
`.github/workflows/desktop-release.yml` builds the real installers and runs `scripts/smoke-windows-installers.ps1` before publishing artifacts.
|
|
31
|
+
`.github/workflows/desktop-release.yml` builds the real installers and runs `scripts/smoke-windows-installers.ps1` before publishing artifacts. The script fails on any MSI bundle, then installs the NSIS package into a temporary path containing spaces and drives `scripts/smoke-installed-windows.mjs` with the installed Node runtime. The driver uses an isolated user profile and tests:
|
|
32
32
|
|
|
33
33
|
1. The installed pkg sidecar boots with bundled resources and authenticates API access.
|
|
34
34
|
2. A temporary Git repository is registered and core assembly completes offline.
|
|
@@ -53,7 +53,7 @@ The detachable-window implementation has passed native macOS fixtures locally, i
|
|
|
53
53
|
|
|
54
54
|
Before claiming complete Windows parity, record successful x64 and ARM64 CI/release runs and exercise the actual installed UI on supported Windows versions:
|
|
55
55
|
|
|
56
|
-
- Clean NSIS
|
|
56
|
+
- Clean NSIS installs, in-place upgrades from the previous release (including an MSI-installed release migrating through the updater), relaunch, tray quit and uninstall. Verify one installation entry and preserved projects/logs.
|
|
57
57
|
- Native browsing and capture at 100%, 150% and 200% display scaling; resize, maximize, multi-monitor movement, keyboard/clipboard, popup/self-close, and the relevant Okta/SSO tenant. Detach two active missions, minimize main independently, move them between monitors, and reattach into a window with its own open browser; verify both sessions and pending inputs remain intact.
|
|
58
58
|
- Provider authentication and one real mission/rail per enabled provider; steering during a tool call; cancellation; multi-repo integration/checkout with clean and conflicting working trees.
|
|
59
59
|
- Long-running frontend/backend processes, immediate startup failure, stopping nested processes, app quit/update during execution, and persisted logs after restart.
|