specrails-desktop 2.7.0 → 2.9.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 +23 -19
- package/client/dist/assets/{ActivityFeedPage-LKqd18-G.js → ActivityFeedPage-DNqnf1fZ.js} +1 -1
- package/client/dist/assets/{AgentsPage-Cb-b-6Ot.js → AgentsPage-vmNIEbGM.js} +1 -1
- package/client/dist/assets/{AnalyticsPage-HVxQQ1wy.js → AnalyticsPage-CdfN0ofZ.js} +1 -1
- package/client/dist/assets/{BarChart-BOyHB0dw.js → BarChart-CIkopHjl.js} +1 -1
- package/client/dist/assets/{CodePage-DnOnwKGB.js → CodePage-DDRNU5FN.js} +1 -1
- package/client/dist/assets/{DesktopAnalyticsPage-D2auU39x.js → DesktopAnalyticsPage-Cl3sKKSG.js} +1 -1
- package/client/dist/assets/{DocsDialog-CTuDX3GK.js → DocsDialog-BGrBOfUr.js} +2 -2
- package/client/dist/assets/{DocsPage-DRyMmu0Z.js → DocsPage-CY-2SSzw.js} +2 -2
- package/client/dist/assets/{ExportDropdown-DO-GGiMh.js → ExportDropdown-BRHcvP0r.js} +1 -1
- package/client/dist/assets/{IntegrationsPage-BhbO4jFT.js → IntegrationsPage-nKdLB4Ub.js} +1 -1
- package/client/dist/assets/{JobDetailPage-DJooEg1s.js → JobDetailPage-Bf0A6WWQ.js} +1 -1
- package/client/dist/assets/{JobsPage-BbaC-YOg.js → JobsPage-Vg4nXPdL.js} +1 -1
- package/client/dist/assets/{dist-js-CiIVMsx3.js → dist-js-0i_klubI.js} +1 -1
- package/client/dist/assets/{dist-js-Xc2lRKp2.js → dist-js-CUs5GjwA.js} +1 -1
- package/client/dist/assets/{index-DK214dak.js → index-BXoHFtfG.js} +8 -8
- package/client/dist/assets/index-D6BaYRRU.css +2 -0
- package/client/dist/assets/{integrations-2C7MkGT0.js → integrations-7YyTBuU9.js} +1 -1
- package/client/dist/assets/{integrations-CX4p_bij.js → integrations-B9CEpNF0.js} +1 -1
- package/client/dist/assets/{integrations-C2jQtv-s.js → integrations-BlvAdewo.js} +1 -1
- package/client/dist/assets/{integrations-eQPHAYsE.js → integrations-Bw8UM9Xd.js} +1 -1
- package/client/dist/assets/{integrations-BDC670cg.js → integrations-C5SxNKnG.js} +1 -1
- package/client/dist/assets/{integrations-BqUmRUef.js → integrations-CJQKMmdW.js} +1 -1
- package/client/dist/assets/{integrations-CB98NeH5.js → integrations-DWz1eU_K.js} +1 -1
- package/client/dist/assets/{integrations-_SuVeQIG.js → integrations-DiPR8Fzp.js} +1 -1
- package/client/dist/assets/{lib-Bo5s6xpe.js → lib-D6M_MvoC.js} +1 -1
- package/client/dist/assets/setup-B6egeeTM.js +1 -0
- package/client/dist/assets/setup-BHroXlke.js +1 -0
- package/client/dist/assets/setup-BIXsWUp1.js +1 -0
- package/client/dist/assets/setup-BJRdg1iE.js +1 -0
- package/client/dist/assets/setup-C0rVGnCy.js +1 -0
- package/client/dist/assets/setup-Cpu17hJv.js +1 -0
- package/client/dist/assets/setup-D-1r0uSx.js +1 -0
- package/client/dist/assets/setup-Dn2-veYO.js +1 -0
- package/client/dist/assets/{useProjectCache-DVNypkmR.js → useProjectCache-BeyBSNpD.js} +1 -1
- package/client/dist/index.html +4 -4
- package/docs/README.md +5 -2
- package/docs/agy-cli-provider-study.md +78 -0
- package/docs/cli.md +23 -4
- package/docs/codex.md +116 -58
- package/docs/creating-specs.md +19 -5
- package/docs/customizing.md +27 -6
- package/docs/gemini.md +225 -73
- package/docs/getting-started.md +18 -9
- package/docs/guide/de/agents/1-meet-the-agents.md +38 -0
- package/docs/guide/de/agents/2-profiles-and-the-balanced-default.md +45 -0
- package/docs/guide/de/agents/3-customizing-models-per-agent.md +60 -0
- package/docs/guide/de/agents/4-custom-agents-catalog.md +43 -0
- package/docs/guide/de/getting-started/1-what-is-specrails.md +49 -0
- package/docs/guide/de/getting-started/2-installing-and-first-run.md +42 -0
- package/docs/guide/de/getting-started/3-adding-your-first-project.md +58 -0
- package/docs/guide/de/getting-started/4-the-dashboard-tour.md +53 -0
- package/docs/guide/de/insights/1-analytics-and-cost-tracking.md +78 -0
- package/docs/guide/de/insights/2-the-integrated-terminal.md +46 -0
- package/docs/guide/de/insights/3-code-explorer.md +50 -0
- package/docs/guide/de/integrations/1-ai-providers.md +64 -0
- package/docs/guide/de/integrations/2-plugins.md +44 -0
- package/docs/guide/de/integrations/3-jira-integration.md +71 -0
- package/docs/guide/de/integrations/4-mobile-companion.md +38 -0
- package/docs/guide/de/pipeline/1-rails-and-jobs.md +94 -0
- package/docs/guide/de/pipeline/2-the-job-detail-view.md +90 -0
- package/docs/guide/de/pipeline/3-batch-implement-and-multi-feature.md +78 -0
- package/docs/guide/de/pipeline/4-picking-an-engine-per-rail.md +60 -0
- package/docs/guide/de/settings/1-themes.md +37 -0
- package/docs/guide/de/settings/2-language.md +39 -0
- package/docs/guide/de/settings/3-pipeline-telemetry-and-diagnostics.md +46 -0
- package/docs/guide/de/settings/4-where-your-data-lives.md +48 -0
- package/docs/guide/de/specs/1-specs-and-the-backlog.md +52 -0
- package/docs/guide/de/specs/2-add-spec-quick-mode.md +45 -0
- package/docs/guide/de/specs/3-add-spec-explore-mode.md +68 -0
- package/docs/guide/de/specs/4-drafts-and-contract-layer.md +81 -0
- package/docs/guide/en/agents/1-meet-the-agents.md +38 -0
- package/docs/guide/en/agents/2-profiles-and-the-balanced-default.md +45 -0
- package/docs/guide/en/agents/3-customizing-models-per-agent.md +60 -0
- package/docs/guide/en/agents/4-custom-agents-catalog.md +43 -0
- package/docs/guide/en/getting-started/1-what-is-specrails.md +49 -0
- package/docs/guide/en/getting-started/2-installing-and-first-run.md +42 -0
- package/docs/guide/en/getting-started/3-adding-your-first-project.md +58 -0
- package/docs/guide/en/getting-started/4-the-dashboard-tour.md +53 -0
- package/docs/guide/en/insights/1-analytics-and-cost-tracking.md +78 -0
- package/docs/guide/en/insights/2-the-integrated-terminal.md +46 -0
- package/docs/guide/en/insights/3-code-explorer.md +50 -0
- package/docs/guide/en/integrations/1-ai-providers.md +64 -0
- package/docs/guide/en/integrations/2-plugins.md +44 -0
- package/docs/guide/en/integrations/3-jira-integration.md +71 -0
- package/docs/guide/en/integrations/4-mobile-companion.md +38 -0
- package/docs/guide/en/pipeline/1-rails-and-jobs.md +94 -0
- package/docs/guide/en/pipeline/2-the-job-detail-view.md +90 -0
- package/docs/guide/en/pipeline/3-batch-implement-and-multi-feature.md +78 -0
- package/docs/guide/en/pipeline/4-picking-an-engine-per-rail.md +60 -0
- package/docs/guide/en/settings/1-themes.md +37 -0
- package/docs/guide/en/settings/2-language.md +39 -0
- package/docs/guide/en/settings/3-pipeline-telemetry-and-diagnostics.md +46 -0
- package/docs/guide/en/settings/4-where-your-data-lives.md +48 -0
- package/docs/guide/en/specs/1-specs-and-the-backlog.md +52 -0
- package/docs/guide/en/specs/2-add-spec-quick-mode.md +45 -0
- package/docs/guide/en/specs/3-add-spec-explore-mode.md +68 -0
- package/docs/guide/en/specs/4-drafts-and-contract-layer.md +81 -0
- package/docs/guide/es/agents/1-meet-the-agents.md +38 -0
- package/docs/guide/es/agents/2-profiles-and-the-balanced-default.md +45 -0
- package/docs/guide/es/agents/3-customizing-models-per-agent.md +60 -0
- package/docs/guide/es/agents/4-custom-agents-catalog.md +43 -0
- package/docs/guide/es/getting-started/1-what-is-specrails.md +49 -0
- package/docs/guide/es/getting-started/2-installing-and-first-run.md +42 -0
- package/docs/guide/es/getting-started/3-adding-your-first-project.md +58 -0
- package/docs/guide/es/getting-started/4-the-dashboard-tour.md +53 -0
- package/docs/guide/es/insights/1-analytics-and-cost-tracking.md +78 -0
- package/docs/guide/es/insights/2-the-integrated-terminal.md +46 -0
- package/docs/guide/es/insights/3-code-explorer.md +50 -0
- package/docs/guide/es/integrations/1-ai-providers.md +64 -0
- package/docs/guide/es/integrations/2-plugins.md +44 -0
- package/docs/guide/es/integrations/3-jira-integration.md +71 -0
- package/docs/guide/es/integrations/4-mobile-companion.md +38 -0
- package/docs/guide/es/pipeline/1-rails-and-jobs.md +94 -0
- package/docs/guide/es/pipeline/2-the-job-detail-view.md +90 -0
- package/docs/guide/es/pipeline/3-batch-implement-and-multi-feature.md +78 -0
- package/docs/guide/es/pipeline/4-picking-an-engine-per-rail.md +60 -0
- package/docs/guide/es/settings/1-themes.md +37 -0
- package/docs/guide/es/settings/2-language.md +39 -0
- package/docs/guide/es/settings/3-pipeline-telemetry-and-diagnostics.md +46 -0
- package/docs/guide/es/settings/4-where-your-data-lives.md +48 -0
- package/docs/guide/es/specs/1-specs-and-the-backlog.md +52 -0
- package/docs/guide/es/specs/2-add-spec-quick-mode.md +45 -0
- package/docs/guide/es/specs/3-add-spec-explore-mode.md +68 -0
- package/docs/guide/es/specs/4-drafts-and-contract-layer.md +81 -0
- package/docs/guide/fr/agents/1-meet-the-agents.md +38 -0
- package/docs/guide/fr/agents/2-profiles-and-the-balanced-default.md +45 -0
- package/docs/guide/fr/agents/3-customizing-models-per-agent.md +60 -0
- package/docs/guide/fr/agents/4-custom-agents-catalog.md +43 -0
- package/docs/guide/fr/getting-started/1-what-is-specrails.md +49 -0
- package/docs/guide/fr/getting-started/2-installing-and-first-run.md +42 -0
- package/docs/guide/fr/getting-started/3-adding-your-first-project.md +58 -0
- package/docs/guide/fr/getting-started/4-the-dashboard-tour.md +53 -0
- package/docs/guide/fr/insights/1-analytics-and-cost-tracking.md +78 -0
- package/docs/guide/fr/insights/2-the-integrated-terminal.md +46 -0
- package/docs/guide/fr/insights/3-code-explorer.md +50 -0
- package/docs/guide/fr/integrations/1-ai-providers.md +64 -0
- package/docs/guide/fr/integrations/2-plugins.md +44 -0
- package/docs/guide/fr/integrations/3-jira-integration.md +71 -0
- package/docs/guide/fr/integrations/4-mobile-companion.md +38 -0
- package/docs/guide/fr/pipeline/1-rails-and-jobs.md +94 -0
- package/docs/guide/fr/pipeline/2-the-job-detail-view.md +90 -0
- package/docs/guide/fr/pipeline/3-batch-implement-and-multi-feature.md +78 -0
- package/docs/guide/fr/pipeline/4-picking-an-engine-per-rail.md +60 -0
- package/docs/guide/fr/settings/1-themes.md +37 -0
- package/docs/guide/fr/settings/2-language.md +39 -0
- package/docs/guide/fr/settings/3-pipeline-telemetry-and-diagnostics.md +46 -0
- package/docs/guide/fr/settings/4-where-your-data-lives.md +48 -0
- package/docs/guide/fr/specs/1-specs-and-the-backlog.md +52 -0
- package/docs/guide/fr/specs/2-add-spec-quick-mode.md +45 -0
- package/docs/guide/fr/specs/3-add-spec-explore-mode.md +68 -0
- package/docs/guide/fr/specs/4-drafts-and-contract-layer.md +81 -0
- package/docs/guide/it/agents/1-meet-the-agents.md +38 -0
- package/docs/guide/it/agents/2-profiles-and-the-balanced-default.md +45 -0
- package/docs/guide/it/agents/3-customizing-models-per-agent.md +60 -0
- package/docs/guide/it/agents/4-custom-agents-catalog.md +43 -0
- package/docs/guide/it/getting-started/1-what-is-specrails.md +49 -0
- package/docs/guide/it/getting-started/2-installing-and-first-run.md +42 -0
- package/docs/guide/it/getting-started/3-adding-your-first-project.md +58 -0
- package/docs/guide/it/getting-started/4-the-dashboard-tour.md +53 -0
- package/docs/guide/it/insights/1-analytics-and-cost-tracking.md +78 -0
- package/docs/guide/it/insights/2-the-integrated-terminal.md +46 -0
- package/docs/guide/it/insights/3-code-explorer.md +50 -0
- package/docs/guide/it/integrations/1-ai-providers.md +64 -0
- package/docs/guide/it/integrations/2-plugins.md +44 -0
- package/docs/guide/it/integrations/3-jira-integration.md +71 -0
- package/docs/guide/it/integrations/4-mobile-companion.md +38 -0
- package/docs/guide/it/pipeline/1-rails-and-jobs.md +94 -0
- package/docs/guide/it/pipeline/2-the-job-detail-view.md +90 -0
- package/docs/guide/it/pipeline/3-batch-implement-and-multi-feature.md +78 -0
- package/docs/guide/it/pipeline/4-picking-an-engine-per-rail.md +60 -0
- package/docs/guide/it/settings/1-themes.md +37 -0
- package/docs/guide/it/settings/2-language.md +39 -0
- package/docs/guide/it/settings/3-pipeline-telemetry-and-diagnostics.md +46 -0
- package/docs/guide/it/settings/4-where-your-data-lives.md +48 -0
- package/docs/guide/it/specs/1-specs-and-the-backlog.md +52 -0
- package/docs/guide/it/specs/2-add-spec-quick-mode.md +45 -0
- package/docs/guide/it/specs/3-add-spec-explore-mode.md +68 -0
- package/docs/guide/it/specs/4-drafts-and-contract-layer.md +81 -0
- package/docs/guide/ja/agents/1-meet-the-agents.md +38 -0
- package/docs/guide/ja/agents/2-profiles-and-the-balanced-default.md +45 -0
- package/docs/guide/ja/agents/3-customizing-models-per-agent.md +60 -0
- package/docs/guide/ja/agents/4-custom-agents-catalog.md +43 -0
- package/docs/guide/ja/getting-started/1-what-is-specrails.md +49 -0
- package/docs/guide/ja/getting-started/2-installing-and-first-run.md +42 -0
- package/docs/guide/ja/getting-started/3-adding-your-first-project.md +58 -0
- package/docs/guide/ja/getting-started/4-the-dashboard-tour.md +53 -0
- package/docs/guide/ja/insights/1-analytics-and-cost-tracking.md +78 -0
- package/docs/guide/ja/insights/2-the-integrated-terminal.md +46 -0
- package/docs/guide/ja/insights/3-code-explorer.md +50 -0
- package/docs/guide/ja/integrations/1-ai-providers.md +64 -0
- package/docs/guide/ja/integrations/2-plugins.md +44 -0
- package/docs/guide/ja/integrations/3-jira-integration.md +71 -0
- package/docs/guide/ja/integrations/4-mobile-companion.md +38 -0
- package/docs/guide/ja/pipeline/1-rails-and-jobs.md +94 -0
- package/docs/guide/ja/pipeline/2-the-job-detail-view.md +90 -0
- package/docs/guide/ja/pipeline/3-batch-implement-and-multi-feature.md +78 -0
- package/docs/guide/ja/pipeline/4-picking-an-engine-per-rail.md +60 -0
- package/docs/guide/ja/settings/1-themes.md +37 -0
- package/docs/guide/ja/settings/2-language.md +39 -0
- package/docs/guide/ja/settings/3-pipeline-telemetry-and-diagnostics.md +46 -0
- package/docs/guide/ja/settings/4-where-your-data-lives.md +48 -0
- package/docs/guide/ja/specs/1-specs-and-the-backlog.md +52 -0
- package/docs/guide/ja/specs/2-add-spec-quick-mode.md +45 -0
- package/docs/guide/ja/specs/3-add-spec-explore-mode.md +68 -0
- package/docs/guide/ja/specs/4-drafts-and-contract-layer.md +81 -0
- package/docs/guide/pt/agents/1-meet-the-agents.md +38 -0
- package/docs/guide/pt/agents/2-profiles-and-the-balanced-default.md +45 -0
- package/docs/guide/pt/agents/3-customizing-models-per-agent.md +60 -0
- package/docs/guide/pt/agents/4-custom-agents-catalog.md +43 -0
- package/docs/guide/pt/getting-started/1-what-is-specrails.md +49 -0
- package/docs/guide/pt/getting-started/2-installing-and-first-run.md +42 -0
- package/docs/guide/pt/getting-started/3-adding-your-first-project.md +58 -0
- package/docs/guide/pt/getting-started/4-the-dashboard-tour.md +53 -0
- package/docs/guide/pt/insights/1-analytics-and-cost-tracking.md +78 -0
- package/docs/guide/pt/insights/2-the-integrated-terminal.md +46 -0
- package/docs/guide/pt/insights/3-code-explorer.md +50 -0
- package/docs/guide/pt/integrations/1-ai-providers.md +64 -0
- package/docs/guide/pt/integrations/2-plugins.md +44 -0
- package/docs/guide/pt/integrations/3-jira-integration.md +71 -0
- package/docs/guide/pt/integrations/4-mobile-companion.md +38 -0
- package/docs/guide/pt/pipeline/1-rails-and-jobs.md +94 -0
- package/docs/guide/pt/pipeline/2-the-job-detail-view.md +90 -0
- package/docs/guide/pt/pipeline/3-batch-implement-and-multi-feature.md +78 -0
- package/docs/guide/pt/pipeline/4-picking-an-engine-per-rail.md +60 -0
- package/docs/guide/pt/settings/1-themes.md +37 -0
- package/docs/guide/pt/settings/2-language.md +39 -0
- package/docs/guide/pt/settings/3-pipeline-telemetry-and-diagnostics.md +46 -0
- package/docs/guide/pt/settings/4-where-your-data-lives.md +48 -0
- package/docs/guide/pt/specs/1-specs-and-the-backlog.md +52 -0
- package/docs/guide/pt/specs/2-add-spec-quick-mode.md +45 -0
- package/docs/guide/pt/specs/3-add-spec-explore-mode.md +68 -0
- package/docs/guide/pt/specs/4-drafts-and-contract-layer.md +81 -0
- package/docs/guide/zh/agents/1-meet-the-agents.md +38 -0
- package/docs/guide/zh/agents/2-profiles-and-the-balanced-default.md +45 -0
- package/docs/guide/zh/agents/3-customizing-models-per-agent.md +60 -0
- package/docs/guide/zh/agents/4-custom-agents-catalog.md +43 -0
- package/docs/guide/zh/getting-started/1-what-is-specrails.md +49 -0
- package/docs/guide/zh/getting-started/2-installing-and-first-run.md +42 -0
- package/docs/guide/zh/getting-started/3-adding-your-first-project.md +58 -0
- package/docs/guide/zh/getting-started/4-the-dashboard-tour.md +53 -0
- package/docs/guide/zh/insights/1-analytics-and-cost-tracking.md +78 -0
- package/docs/guide/zh/insights/2-the-integrated-terminal.md +46 -0
- package/docs/guide/zh/insights/3-code-explorer.md +50 -0
- package/docs/guide/zh/integrations/1-ai-providers.md +64 -0
- package/docs/guide/zh/integrations/2-plugins.md +44 -0
- package/docs/guide/zh/integrations/3-jira-integration.md +71 -0
- package/docs/guide/zh/integrations/4-mobile-companion.md +38 -0
- package/docs/guide/zh/pipeline/1-rails-and-jobs.md +94 -0
- package/docs/guide/zh/pipeline/2-the-job-detail-view.md +90 -0
- package/docs/guide/zh/pipeline/3-batch-implement-and-multi-feature.md +78 -0
- package/docs/guide/zh/pipeline/4-picking-an-engine-per-rail.md +60 -0
- package/docs/guide/zh/settings/1-themes.md +37 -0
- package/docs/guide/zh/settings/2-language.md +39 -0
- package/docs/guide/zh/settings/3-pipeline-telemetry-and-diagnostics.md +46 -0
- package/docs/guide/zh/settings/4-where-your-data-lives.md +48 -0
- package/docs/guide/zh/specs/1-specs-and-the-backlog.md +52 -0
- package/docs/guide/zh/specs/2-add-spec-quick-mode.md +45 -0
- package/docs/guide/zh/specs/3-add-spec-explore-mode.md +68 -0
- package/docs/guide/zh/specs/4-drafts-and-contract-layer.md +81 -0
- package/docs/internals/README.md +1 -1
- package/docs/internals/adding-a-provider.md +192 -59
- package/docs/internals/api-reference.md +130 -21
- package/docs/internals/architecture.md +22 -9
- package/docs/internals/bundled-framework-build-plan.md +264 -0
- package/docs/internals/configuration.md +33 -8
- package/docs/internals/global-artifacts-alignment-contract.md +486 -0
- package/docs/internals/global-artifacts-relocation-evaluation.md +294 -0
- package/docs/internals/operations-runbook.md +16 -5
- package/docs/internals/profiles.md +42 -14
- package/docs/platforms/macos.md +27 -8
- package/docs/platforms/windows.md +20 -6
- package/docs/running-pipelines.md +17 -9
- package/docs/terminal.md +9 -3
- package/docs/tracking-cost.md +17 -11
- package/package.json +1 -1
- package/server/dist/agent-refine-manager.js +20 -5
- package/server/dist/artifact-registry.js +468 -0
- package/server/dist/attachment-manager.js +5 -8
- package/server/dist/browser-capture-manager.js +4 -4
- package/server/dist/bundled-core.js +72 -0
- package/server/dist/bundled-openspec.js +58 -0
- package/server/dist/chat-manager.js +42 -5
- package/server/dist/code-explorer-router.js +10 -7
- package/server/dist/config.js +7 -2
- package/server/dist/context-budget.js +17 -6
- package/server/dist/context-scope.js +6 -2
- package/server/dist/contract-refine-runner.js +31 -9
- package/server/dist/desktop-router.js +39 -14
- package/server/dist/docs-router.js +210 -132
- package/server/dist/file-summary-manager.js +41 -16
- package/server/dist/framework-manager.js +248 -0
- package/server/dist/framework-migration.js +308 -0
- package/server/dist/index.js +30 -0
- package/server/dist/install-config-path.js +73 -0
- package/server/dist/jira/jira-sync-manager.js +23 -11
- package/server/dist/openspec-shim.js +153 -0
- package/server/dist/plugins-router.js +19 -8
- package/server/dist/profiles-router.js +38 -16
- package/server/dist/project-registry.js +101 -3
- package/server/dist/project-router-chat.js +1 -1
- package/server/dist/project-router-helpers.js +25 -12
- package/server/dist/project-router-jobs.js +3 -3
- package/server/dist/project-router-settings.js +8 -6
- package/server/dist/project-router-setup.js +27 -10
- package/server/dist/project-router-spending.js +6 -1
- package/server/dist/project-router-tickets.js +30 -10
- package/server/dist/project-router.js +16 -1
- package/server/dist/providers/gemini-adapter.js +4 -0
- package/server/dist/providers/gemini-agent-ack.js +65 -0
- package/server/dist/queue-manager.js +156 -12
- package/server/dist/setup-manager.js +131 -29
- package/server/dist/smash-runner.js +21 -6
- package/server/dist/ticket-store.js +6 -2
- package/server/dist/ticket-watcher.js +5 -1
- package/server/dist/util/stream-display.js +18 -3
- package/server/dist/vitest-setup.js +25 -0
- package/server/dist/workspace-manager.js +199 -0
- package/server/dist/workspace-resolution.js +147 -0
- package/client/dist/assets/index-DgKfQFcf.css +0 -2
- package/client/dist/assets/setup-BIIkb-_K.js +0 -1
- package/client/dist/assets/setup-BeQxu9kD.js +0 -1
- package/client/dist/assets/setup-CPa6GnlI.js +0 -1
- package/client/dist/assets/setup-CZl4OEJx.js +0 -1
- package/client/dist/assets/setup-ChpodNfn.js +0 -1
- package/client/dist/assets/setup-D_fjJH6u.js +0 -1
- package/client/dist/assets/setup-YzD8DX4O.js +0 -1
- package/client/dist/assets/setup-fRpDozmq.js +0 -1
- package/docs/adding-a-provider.md +0 -107
|
@@ -2,6 +2,10 @@
|
|
|
2
2
|
|
|
3
3
|
REST and WebSocket endpoints exposed by the app server. The server binds to `127.0.0.1` only (loopback); the default port is `4200` but it can be overridden with `--port <n>` on the server command line.
|
|
4
4
|
|
|
5
|
+
> **New here?** This page is the contract the desktop UI, the CLI, and the mobile gateway all speak to the local server. **You normally never call these endpoints directly — the app does it for you.** Read on only if you are scripting against the server, writing an integration, or debugging. Everything is local-only: there is no cloud API.
|
|
6
|
+
|
|
7
|
+
The app speaks to three interchangeable AI provider CLIs — **Claude, Codex, and Gemini** — all enabled by default. Endpoints that accept a provider value (`provider` / `aiEngine`) take any of `claude`, `codex`, or `gemini`, validated against the providers the project actually installed. See the [Codex guide](../codex.md) and the [Gemini guide](../gemini.md) for provider specifics.
|
|
8
|
+
|
|
5
9
|
## Authentication
|
|
6
10
|
|
|
7
11
|
An app token is **auto-generated on first run** (two concatenated UUIDs) and persisted to `~/.specrails/desktop.token` with mode `0600`. It is **mandatory**, not optional. Every `/api/*` route is protected by it, with two exceptions that are mounted before the auth middleware: `/api/health` and `/api/token`.
|
|
@@ -17,7 +21,7 @@ The CLI and the desktop client read the token automatically. The browser client
|
|
|
17
21
|
|
|
18
22
|
There is no UI to set or clear the token, and it is not an app setting.
|
|
19
23
|
|
|
20
|
-
This page is hand-maintained against the route declarations in `server/*-router.ts`. If you spot a discrepancy, please file an issue.
|
|
24
|
+
This page is hand-maintained against the route declarations in `server/*-router.ts`, the per-domain `server/project-router-{jobs,spending,settings,terminals,tickets,chat,setup}.ts` family, `server/code-explorer-router.ts`, and `server/jira-router.ts`. If you spot a discrepancy, please file an issue.
|
|
21
25
|
|
|
22
26
|
---
|
|
23
27
|
|
|
@@ -27,14 +31,15 @@ This page is hand-maintained against the route declarations in `server/*-router.
|
|
|
27
31
|
|--------|--------|------|-------|
|
|
28
32
|
| `/api/health` | direct | none | Liveness probe (`{ status, version, uptime, projects, mode }`) |
|
|
29
33
|
| `/api/token` | direct | none | Returns the auth token for local bootstrapping (loopback-only) |
|
|
30
|
-
| `/api/docs` | `docs-router` |
|
|
34
|
+
| `/api/docs` | `docs-router` | loopback-only (mounted before token auth) | Bundled documentation portal |
|
|
31
35
|
| `/api/mobile/*` | `mobile-admin-router` | Bearer / X-Desktop-Token + loopback | Mobile Gateway admin (enable/pair/devices) |
|
|
32
36
|
| `/api/*` | `desktop-router` | Bearer / X-Desktop-Token | Cross-project operations |
|
|
33
37
|
| `/api/projects/:projectId/*` | `project-router` | Bearer / X-Desktop-Token | Project-scoped operations |
|
|
34
|
-
| `/api/projects/:projectId/code/*` | `code-explorer-router` | Bearer / X-Desktop-Token |
|
|
38
|
+
| `/api/projects/:projectId/code/*` | `code-explorer-router` | Bearer / X-Desktop-Token | Code explorer (read + in-app file editing; 404 when the gate is off) |
|
|
35
39
|
| `/api/projects/:projectId/rails/*` | `rails-router` | Bearer / X-Desktop-Token | Rails (execution lanes) |
|
|
36
40
|
| `/api/projects/:projectId/profiles/*` | `profiles-router` | Bearer / X-Desktop-Token | Agent profiles + catalog studio |
|
|
37
41
|
| `/api/projects/:projectId/plugins/*` | `plugins-router` | Bearer / X-Desktop-Token | Plugin marketplace |
|
|
42
|
+
| `/api/projects/:projectId/jira/*` | `jira-router` | Bearer / X-Desktop-Token | Jira integration (404 when `SPECRAILS_JIRA_SECTION=false`) |
|
|
38
43
|
| `/otlp/v1/{traces,metrics,logs}` | `telemetry-receiver` | none (gated by job id) | OTLP/JSON receiver |
|
|
39
44
|
| `/ws` | WebSocket | token in query | Project + app event stream |
|
|
40
45
|
| `/ws/terminal/:id` | WebSocket | token in query | PTY traffic for the terminal panel |
|
|
@@ -54,17 +59,29 @@ A non-localhost `Origin` header is rejected by the CORS middleware with `403 For
|
|
|
54
59
|
| Method | Path | Notes |
|
|
55
60
|
|--------|------|-------|
|
|
56
61
|
| `GET` | `/projects` | List registered projects |
|
|
57
|
-
| `POST` | `/projects` | Register a project. Body `{ path, name?, provider?, providers? }`. `providers: string[]` enables a multi-provider project (first entry = primary/default); legacy single `provider` still honoured; omit both to default to `["claude"]`. 409 if the path is already registered |
|
|
62
|
+
| `POST` | `/projects` | Register a project. Body `{ path, name?, provider?, providers? }`. Each provider value is one of `claude`, `codex`, `gemini` (registry-validated). `providers: string[]` enables a multi-provider project (first entry = primary/default); legacy single `provider` still honoured; omit both to default to `["claude"]`. 409 if the path is already registered. 400 if a provider is unknown, or if a disabled provider is selected: `codex` when `SPECRAILS_CODEX_BETA=0`, `gemini` when `SPECRAILS_GEMINI_BETA=0` (both default-enabled) |
|
|
58
63
|
| `DELETE` | `/projects/:id` | Unregister (does not delete the project directory) |
|
|
59
64
|
| `GET` | `/resolve?path=…` | Find a project by **exact** canonical filesystem path. No parent-directory walking — a subdirectory returns 404 |
|
|
60
65
|
|
|
66
|
+
Example — register a project that uses both Claude and Gemini:
|
|
67
|
+
|
|
68
|
+
```json
|
|
69
|
+
// POST /api/projects
|
|
70
|
+
{
|
|
71
|
+
"path": "/Users/me/code/my-app",
|
|
72
|
+
"name": "My App",
|
|
73
|
+
"providers": ["claude", "gemini"]
|
|
74
|
+
}
|
|
75
|
+
// → 201 { "project": { "id": "my-app", "name": "My App", "provider": "claude", "providers": ["claude", "gemini"], ... } }
|
|
76
|
+
```
|
|
77
|
+
|
|
61
78
|
### App state
|
|
62
79
|
|
|
63
80
|
| Method | Path | Notes |
|
|
64
81
|
|--------|------|-------|
|
|
65
82
|
| `GET` | `/state` | `{ projects, projectCount, …todayStats }` (today's cross-project cost/run aggregates spread into the response) |
|
|
66
|
-
| `GET` | `/cli-status` | Detected AI CLI provider + version (`{ provider, version }`), e.g. claude or
|
|
67
|
-
| `GET` | `/available-providers` | Provider catalogue (
|
|
83
|
+
| `GET` | `/cli-status` | Detected AI CLI provider + version (`{ provider, version }`), e.g. `claude`, `codex`, or `gemini` — runs `<binary> --version`. Registry-driven |
|
|
84
|
+
| `GET` | `/available-providers` | Provider catalogue used by the setup wizard. Registry-driven map (`{ claude, codex, gemini, tiers }`) reporting which CLIs are installed. Codex/Gemini are surfaced unless forced off by `SPECRAILS_CODEX_BETA=0` / `SPECRAILS_GEMINI_BETA=0` (both enabled by default) |
|
|
68
85
|
| `GET` | `/core-compat` | specrails-core version compatibility probe |
|
|
69
86
|
| `GET` | `/setup-prerequisites` | Tool checks (`node`/`npm`/`npx`/`git`, optionally `uv`). Add `?diagnostic=1` to nest a `diagnostic` object: `{ pathSegments, pathSources, loginShellStatus, whichResults, nodeEnv, platform }` |
|
|
70
87
|
|
|
@@ -155,6 +172,14 @@ All routes below are prefixed with `/api/projects/:projectId/`. In the client, u
|
|
|
155
172
|
| `POST` | `/config` | Force re-discovery |
|
|
156
173
|
| `GET` | `/default-spec-model?provider=` | Resolve the Quick-spec model for an engine. Returns `{ model, provider, allowed, providers }`; `provider` falls back to the primary if omitted/invalid |
|
|
157
174
|
|
|
175
|
+
Example — queue a command on a specific provider:
|
|
176
|
+
|
|
177
|
+
```json
|
|
178
|
+
// POST /api/projects/my-app/spawn
|
|
179
|
+
{ "command": "/specrails:implement #42 --yes", "aiEngine": "gemini" }
|
|
180
|
+
// → 202 { "jobId": "j_01H...", "position": 0 }
|
|
181
|
+
```
|
|
182
|
+
|
|
158
183
|
### Pipelines and jobs
|
|
159
184
|
|
|
160
185
|
| Method | Path | Notes |
|
|
@@ -170,8 +195,32 @@ All routes below are prefixed with `/api/projects/:projectId/`. In the client, u
|
|
|
170
195
|
| `DELETE` | `/jobs/:id` | Cancel a running or queued job |
|
|
171
196
|
| `DELETE` | `/jobs` | Purge completed jobs (optional `{ from, to }` window) |
|
|
172
197
|
| `PATCH` | `/jobs/:id/priority` | Re-rank a queued job |
|
|
198
|
+
| `POST` | `/jobs/:id/messages` | Send one more user turn to a running **interactive** ultracode job. Body `{ text }`. `202` accepted, `400` missing text, `403` interactive jobs disabled, `409` the job is not an active interactive session |
|
|
199
|
+
| `POST` | `/jobs/:id/finalize` | Finalize a running interactive job (SIGTERM the resident child; final totals + `completed` status are stamped when it closes). `202` scheduled, `403` interactive jobs disabled, `409` not an active interactive session |
|
|
173
200
|
| `GET` | `/jobs/:jobId/diagnostic` | Stream a diagnostic ZIP (telemetry + profile + plugins snapshots) |
|
|
174
201
|
|
|
202
|
+
The two interactive endpoints back the in-job chat for **Interactive Ultracode** rails (Claude-only). They both 403 when the server has `SPECRAILS_INTERACTIVE_JOBS=false`.
|
|
203
|
+
|
|
204
|
+
Example — fetch one job:
|
|
205
|
+
|
|
206
|
+
```json
|
|
207
|
+
// GET /api/projects/my-app/jobs/j_01H...
|
|
208
|
+
{
|
|
209
|
+
"job": {
|
|
210
|
+
"id": "j_01H...",
|
|
211
|
+
"command": "/specrails:implement #42 --yes",
|
|
212
|
+
"status": "completed",
|
|
213
|
+
"total_cost_usd": 0.83,
|
|
214
|
+
"num_turns": 14,
|
|
215
|
+
"model": "sonnet",
|
|
216
|
+
"hasTelemetry": true,
|
|
217
|
+
"tickets": [{ "id": 42, "title": "Add CSV export" }]
|
|
218
|
+
},
|
|
219
|
+
"events": [ /* streamed job events */ ],
|
|
220
|
+
"phaseDefinitions": [ /* architect → developer → reviewer → ship */ ]
|
|
221
|
+
}
|
|
222
|
+
```
|
|
223
|
+
|
|
175
224
|
### Queue
|
|
176
225
|
|
|
177
226
|
Jobs within a project run **strictly one at a time** (serialized) — a single queue per project. Parallelism is across projects only.
|
|
@@ -196,6 +245,21 @@ Spending is tracked across six surfaces: `job`, `quick-spec`, `explore-spec`, `a
|
|
|
196
245
|
| `GET` | `/tickets/:id/spending-summary` | Per-ticket cross-surface aggregate (powers `TicketSpendingLine`) |
|
|
197
246
|
| `GET` | `/analytics/export?format=csv\|json&mode=summary\|raw&…` | Multi-section summary CSV/JSON, or raw rows (10 000 cap) |
|
|
198
247
|
|
|
248
|
+
Example — the Analytics dashboard payload (abridged):
|
|
249
|
+
|
|
250
|
+
```json
|
|
251
|
+
// GET /api/projects/my-app/spending?period=30d
|
|
252
|
+
{
|
|
253
|
+
"summary": { "totalCostUsd": 12.40, "totalRuns": 58, "prevPeriodDeltaPct": -8.2, "trackingStartedAt": "2026-05-01" },
|
|
254
|
+
"bySurface": [{ "surface": "job", "costUsd": 9.10 }, { "surface": "explore-spec", "costUsd": 2.30 }],
|
|
255
|
+
"byModel": [{ "model": "sonnet", "costUsd": 8.00 }, { "model": "gemini-3.5-flash", "costUsd": 1.20 }],
|
|
256
|
+
"dailyTimeline": [ /* zero-filled, stacked by surface */ ],
|
|
257
|
+
"topTickets": [ /* top 10 cross-surface */ ]
|
|
258
|
+
}
|
|
259
|
+
```
|
|
260
|
+
|
|
261
|
+
Cost is **provider-billed and exact for Claude**; for Codex and Gemini it is **estimated from a rate card** (those CLIs do not report a native cost).
|
|
262
|
+
|
|
199
263
|
### Budget
|
|
200
264
|
|
|
201
265
|
| Method | Path | Notes |
|
|
@@ -216,7 +280,7 @@ Spending is tracked across six surfaces: `job`, `quick-spec`, `explore-spec`, `a
|
|
|
216
280
|
| `POST` | `/tickets/save-as-draft` | Persist an Explore conversation as a draft (idempotent on `conversationId`) |
|
|
217
281
|
| `POST` | `/tickets/from-draft` | Commit a draft (flip-in-place) or insert a new ticket |
|
|
218
282
|
| `POST` | `/tickets/from-prompt` | Create a ticket directly from a prompt |
|
|
219
|
-
| `POST` | `/tickets/:id/contract-refine` | Retry Contract Refine for an existing ticket
|
|
283
|
+
| `POST` | `/tickets/:id/contract-refine` | Retry Contract Refine for an existing ticket. `202` scheduled, `404` unknown ticket, `409` when: the project is Codex (`contract_refine_unsupported_for_codex` — Contract Refine is Claude-only), the kill switch is active (`feature_disabled_by_env`), or the ticket has no origin conversation |
|
|
220
284
|
| `POST` | `/tickets/:id/smash` | SMASH an epic into sub-specs |
|
|
221
285
|
| `POST` | `/tickets/:id/smash/undo` | Undo a SMASH operation |
|
|
222
286
|
| `DELETE` | `/tickets/:id/children` | Delete all children of an epic |
|
|
@@ -251,7 +315,7 @@ The setup wizard is a three-step flow (Configure / Install / Done). The `enrich/
|
|
|
251
315
|
| Method | Path | Notes |
|
|
252
316
|
|--------|------|-------|
|
|
253
317
|
| `POST` | `/setup/install-config` | Write `.specrails/install-config.yaml` to the project |
|
|
254
|
-
| `POST` | `/setup/install` | Run `npx
|
|
318
|
+
| `POST` | `/setup/install` | Run `npx specrails-core init --from-config <file>` (the pinned core release — currently `specrails-core@^4.8.0` — is resolved by SetupManager, overridable via `SPECRAILS_CORE_BIN`) |
|
|
255
319
|
| `POST` | `/setup/start` | Legacy setup-chat session start |
|
|
256
320
|
| `POST` | `/setup/message` | Legacy setup-chat turn |
|
|
257
321
|
| `POST` | `/enrich/start` | Legacy AI-enrich session start |
|
|
@@ -348,12 +412,13 @@ Gated by `requireBrowserCaptureEnabled` — returns 404 when the feature is disa
|
|
|
348
412
|
|
|
349
413
|
## `/api/projects/:projectId/code/*`
|
|
350
414
|
|
|
351
|
-
|
|
415
|
+
A non-developer-friendly file tree + Monaco viewer with plain-language AI summaries and *touched-by-AI* provenance chips, plus opt-in in-app editing of existing files (overwrite-only). Mounted via `code-explorer-router`; 404 when the server gate is off.
|
|
352
416
|
|
|
353
417
|
| Method | Path | Notes |
|
|
354
418
|
|--------|------|-------|
|
|
355
419
|
| `GET` | `/tree?withProvenance=1&filter=touched-by-ai\|all&cursor=…` | Virtualised file tree (pagination cap 2000, `.gitignore`-aware) |
|
|
356
420
|
| `GET` | `/file?path=…` | File contents (binary refusal, 2 MB cap, path-traversal guard) |
|
|
421
|
+
| `PUT` | `/file` | In-app edit: overwrite an **existing** text file. Body `{ path, content }`. Overwrite-only (no create, no rename); same traversal / deny-list / `.gitignore` guards as the read path. `404` if the path does not exist, `413` over the 2 MB cap, `415` for binary content/files |
|
|
357
422
|
| `GET` | `/summary?path=…` | Plain-language AI summary for a file |
|
|
358
423
|
| `POST` | `/file/regenerate-summary?path=…` | Enqueue a summary regeneration. Body `{ overrideBudget? }` → `202 { enqueued: true }` |
|
|
359
424
|
| `GET` | `/provenance?ticketId=…` | Files touched by a ticket |
|
|
@@ -368,15 +433,18 @@ Read-only Code explorer (mounted via `code-explorer-router`; 404 when the server
|
|
|
368
433
|
| `GET` | `/` | List rails |
|
|
369
434
|
| `PUT` | `/:railIndex/tickets` | Assign tickets to a rail. Body `{ ticketIds: number[] }` |
|
|
370
435
|
| `PUT` | `/:railIndex/profile` | Set the rail's default profile |
|
|
371
|
-
| `PUT` | `/:railIndex/engine` | Set the rail's AI engine override. Body `{ aiEngine }` (string or `null` to clear) |
|
|
372
|
-
| `
|
|
373
|
-
| `POST` | `/:railIndex/
|
|
436
|
+
| `PUT` | `/:railIndex/engine` | Set the rail's AI engine override. Body `{ aiEngine }` (string — one of the project's providers — or `null` to clear) |
|
|
437
|
+
| `PUT` | `/:railIndex/name` | Set the rail's display name. Body `{ name }` (string or `null` to clear back to the default label); 400 if longer than 60 characters |
|
|
438
|
+
| `POST` | `/:railIndex/launch` | Launch the rail. Body `{ mode?, profileName?, aiEngine?, model?, interactive? }`. `mode` is `implement` / `batch-implement` / `ultracode`; `model` (haiku/sonnet/opus) applies to ultracode only; `interactive: true` opens an in-job chat and is **ultracode-only** (400 for any other mode, 403 when interactive jobs are disabled). Returns `202 { jobId, railIndex, mode }`; **`503`** when the Claude or Codex CLI binary is not found (a missing Gemini/other binary surfaces as `500`) |
|
|
439
|
+
| `POST` | `/:railIndex/stop` | Stop the rail's running job (cancels every job the rail registered) |
|
|
374
440
|
|
|
375
441
|
---
|
|
376
442
|
|
|
377
443
|
## `/api/projects/:projectId/profiles/*`
|
|
378
444
|
|
|
379
|
-
Gated by `SPECRAILS_AGENTS_SECTION !== 'false'`.
|
|
445
|
+
Gated by `SPECRAILS_AGENTS_SECTION !== 'false'`. Rails force legacy (no-profile) mode whenever the chosen engine is not Claude, and the Agents section is hidden in multi-provider projects; profile env-injection itself works for any provider whose adapter advertises `profileEnvSupport`.
|
|
446
|
+
|
|
447
|
+
> **Provider capability notes.** A few behaviours are not the same across all three providers: **Contract Refine** is Claude-only; **rails force legacy (no-profile) mode** for any non-Claude engine; **Ultracode rails** are Claude-only; the **Serena plugin** (and other `project-json` plugins) work for Claude and Gemini but are filtered out for Codex; and **cost is exact only for Claude** (estimated from a rate card for Codex and Gemini). See the [Codex guide](../codex.md) and [Gemini guide](../gemini.md).
|
|
380
448
|
|
|
381
449
|
### Profile CRUD
|
|
382
450
|
|
|
@@ -387,8 +455,8 @@ Gated by `SPECRAILS_AGENTS_SECTION !== 'false'`. Profiles are effectively Claude
|
|
|
387
455
|
| `GET` | `/:name` | One profile |
|
|
388
456
|
| `PATCH` | `/:name` | Update |
|
|
389
457
|
| `DELETE` | `/:name` | Delete |
|
|
390
|
-
| `POST` | `/:name/duplicate` | Duplicate. Body `{
|
|
391
|
-
| `POST` | `/:name/rename` | Rename. Body `{
|
|
458
|
+
| `POST` | `/:name/duplicate` | Duplicate. Body `{ name }` (the new profile name) |
|
|
459
|
+
| `POST` | `/:name/rename` | Rename. Body `{ name }` (the new profile name) |
|
|
392
460
|
| `GET` | `/resolve?profile=…` | Preview which profile would run given a selection |
|
|
393
461
|
|
|
394
462
|
### Bootstrap and analytics
|
|
@@ -445,9 +513,32 @@ Gated by `SPECRAILS_PLUGINS_SECTION !== 'false'`.
|
|
|
445
513
|
|
|
446
514
|
---
|
|
447
515
|
|
|
516
|
+
## `/api/projects/:projectId/jira/*`
|
|
517
|
+
|
|
518
|
+
Optional per-project Jira integration: a project's specs can be backed by a Jira board instead of the local store. Mounted via `jira-router` and gated by `SPECRAILS_JIRA_SECTION` — **every route 404s when the flag is `false`**. Inert until a connection is configured. The Jira token is never returned to the client (connection responses carry `hasToken` only). The first six endpoints back the step-by-step connect wizard (test → pick project → optional status map → connect).
|
|
519
|
+
|
|
520
|
+
| Method | Path | Notes |
|
|
521
|
+
|--------|------|-------|
|
|
522
|
+
| `GET` | `/connection` | Current connection (token redacted) or `{ connected: false }` |
|
|
523
|
+
| `PATCH` | `/connection` | Toggle `enabled` (hot-swap local ↔ Jira) and/or update the discard status / status map. `404` if no connection |
|
|
524
|
+
| `DELETE` | `/connection` | Disconnect and restore the local backlog config |
|
|
525
|
+
| `POST` | `/test` | Wizard step 1: validate credentials without saving. Body `{ baseUrl, accountEmail?, token }`. `401` on bad credentials |
|
|
526
|
+
| `POST` | `/discover-projects` | Wizard step 2: list visible Jira projects. Body `{ baseUrl, accountEmail?, token, query? }` |
|
|
527
|
+
| `POST` | `/discover-statuses` | Wizard step 3 (optional): list a project's statuses. Body `{ baseUrl, accountEmail?, token, projectKey }` |
|
|
528
|
+
| `POST` | `/connect` | Wizard final step: validate + persist + start sync. Body `{ baseUrl, accountEmail?, token, jiraProjectKey, statusMap?, discardStatus? }`. `201` on success |
|
|
529
|
+
| `GET` | `/statuses` | The connected project's real statuses (post-connect picker), using stored credentials |
|
|
530
|
+
| `POST` | `/resume` | Re-paste a fresh token after a `401` and drain the parked outbox |
|
|
531
|
+
| `POST` | `/sync` | Manual "Sync now" — a full re-fetch ignoring the high-water mark |
|
|
532
|
+
| `GET` | `/outbox?state=` | List durable write-back ops (optional `state=pending\|inflight\|done\|dead`) + counts |
|
|
533
|
+
| `POST` | `/outbox/:id/retry` | Re-queue a dead-lettered op. `404` if the op is missing or not dead |
|
|
534
|
+
| `POST` | `/specs` | Add Spec when the project source is Jira: create the issue in Jira and materialize it locally. Body `{ title, description?, labels?, priority?, issueType? }` → `201 { localId, jiraKey }` |
|
|
535
|
+
| `POST` | `/specs/:localId/discard` | Move the linked issue to the configured discard status (instead of deleting). Body `{ comment? }`. `404` if unlinked, `409` otherwise |
|
|
536
|
+
| `GET` | `/specs/:localId/details` | Read-only Jira details + development payload for the spec detail modal |
|
|
537
|
+
| `GET` | `/links` | The spec ↔ Jira issue map (drives the badge and diagnostics) |
|
|
538
|
+
|
|
448
539
|
## `/api/docs/*`
|
|
449
540
|
|
|
450
|
-
The bundled documentation portal (served by `docs-router`,
|
|
541
|
+
The bundled documentation portal (served by `docs-router`, loopback-only — mounted before token auth).
|
|
451
542
|
|
|
452
543
|
| Method | Path | Notes |
|
|
453
544
|
|--------|------|-------|
|
|
@@ -476,17 +567,21 @@ A single connection at `ws://127.0.0.1:4200/ws?token=<authToken>` multiplexes ev
|
|
|
476
567
|
|
|
477
568
|
Every project-scoped message includes a `projectId` field. App-level messages have no `projectId` and reach every handler.
|
|
478
569
|
|
|
570
|
+
**On connect**, the current Super-mode server sends exactly **one** frame: `desktop.projects` (the project list). There is **no live `init` frame** — the `init` type still exists in `server/types.ts` and is consumed by `usePipeline`, but only demo-mode emits it; per-project initial state is fetched via REST (e.g. `GET /jobs`, `GET /queue`).
|
|
571
|
+
|
|
479
572
|
### Job, queue & pipeline
|
|
480
573
|
|
|
481
574
|
| Type | Scope | Notes |
|
|
482
575
|
|------|-------|-------|
|
|
483
|
-
| `init` | project | Per-connection dashboard snapshot sent on (re)connect: `{ projectName, phases, phaseDefinitions, logBuffer, recentJobs, queue }` |
|
|
484
576
|
| `log` | project | Streaming log line |
|
|
485
577
|
| `event` | project | Structured job event |
|
|
486
578
|
| `phase` | project | Pipeline phase transition |
|
|
487
579
|
| `queue` | project | Queue snapshot (`{ jobs, activeJobId, paused, timestamp }`) — job-exit state changes reach the client here |
|
|
488
580
|
| `pipeline_status` | project | Pipeline finished (`completed` / `failed`) |
|
|
489
581
|
| `exit` | both | Replay of a process exit (`{ code, signal, early }`); also emitted on the terminal stream |
|
|
582
|
+
| `job.turn_user` | project | Interactive job: a user prompt was accepted (echoed so the in-job chat can render the bubble immediately; `queued` is true when a turn is already streaming) |
|
|
583
|
+
| `job.turn_done` | project | Interactive job: a turn finished streaming, carrying the running sum of real token/cost totals |
|
|
584
|
+
| `job.finalized` | project | Interactive job finalized (or crashed): final authoritative totals + terminal status |
|
|
490
585
|
|
|
491
586
|
### Budget & cost
|
|
492
587
|
|
|
@@ -540,6 +635,7 @@ Every project-scoped message includes a `projectId` field. App-level messages ha
|
|
|
540
635
|
| Type | Scope | Notes |
|
|
541
636
|
|------|-------|-------|
|
|
542
637
|
| `rail.job_started` / `rail.job_completed` / `rail.job_stopped` | project | Rail job lifecycle |
|
|
638
|
+
| `rail.updated` | project | A non-launch rail change (tickets reassigned, renamed, mode/profile/engine edited) — carries the full post-mutation rail snapshot |
|
|
543
639
|
|
|
544
640
|
### Plugins
|
|
545
641
|
|
|
@@ -557,6 +653,16 @@ Every project-scoped message includes a `projectId` field. App-level messages ha
|
|
|
557
653
|
| `file.provenance_updated` | project | A job touched files |
|
|
558
654
|
| `file.summary_updated` / `file.summary_failed` / `file.summary_skipped` | project | Summary lifecycle |
|
|
559
655
|
|
|
656
|
+
### Jira
|
|
657
|
+
|
|
658
|
+
| Type | Scope | Notes |
|
|
659
|
+
|------|-------|-------|
|
|
660
|
+
| `jira.synced` | project | Inbound poll materialized issues into the local cache |
|
|
661
|
+
| `jira.sync_error` | project | A sync attempt failed |
|
|
662
|
+
| `jira.auth_expired` | project | A `401` paused the project; the user must re-paste a token (then `POST /jira/resume`) |
|
|
663
|
+
| `jira.outbox_changed` | project | The durable write-back outbox changed (op enqueued/drained/dead-lettered) |
|
|
664
|
+
| `jira.degraded` | project | A write-back op was dead-lettered or a path is blocked; sync continues |
|
|
665
|
+
|
|
560
666
|
### Setup wizard
|
|
561
667
|
|
|
562
668
|
| Type | Scope | Notes |
|
|
@@ -616,10 +722,13 @@ The app uses standard HTTP status codes. Notable conventions:
|
|
|
616
722
|
|
|
617
723
|
- `400` — malformed body / invalid params
|
|
618
724
|
- `401` — missing or invalid token (Bearer or `X-Desktop-Token`)
|
|
619
|
-
- `403` — cross-origin request (a non-localhost `Origin` header)
|
|
620
|
-
- `404` — resource not found (including a project resolved from an unregistered path)
|
|
621
|
-
- `409` — write conflict (file-lock contention on tickets, plugin name collision, project path already registered)
|
|
725
|
+
- `403` — cross-origin request (a non-localhost `Origin` header), or a feature gated off (interactive jobs disabled, code-explorer deny-list/gitignore)
|
|
726
|
+
- `404` — resource not found (including a project resolved from an unregistered path, or any route under a disabled section gate such as Jira / Code explorer)
|
|
727
|
+
- `409` — write conflict (file-lock contention on tickets, plugin/profile name collision, project path already registered) or a state conflict (e.g. not an active interactive job, Contract Refine unsupported)
|
|
728
|
+
- `413` — payload too large (code-explorer edit over the 2 MB cap)
|
|
729
|
+
- `415` — unsupported media type (code-explorer edit of binary content)
|
|
622
730
|
- `500` — unhandled exception (logged to stdout)
|
|
731
|
+
- `503` — the Claude or Codex CLI binary was not found when launching a rail job (a missing Gemini/other-provider binary falls through to `500`)
|
|
623
732
|
|
|
624
733
|
Error responses are `{ "error": "<message>" }`.
|
|
625
734
|
|
|
@@ -627,5 +736,5 @@ Error responses are `{ "error": "<message>" }`.
|
|
|
627
736
|
|
|
628
737
|
## Caveats
|
|
629
738
|
|
|
630
|
-
- **Surface drift**: this file is hand-maintained against the route declarations in `server/*-router.ts`
|
|
739
|
+
- **Surface drift**: this file is hand-maintained against the route declarations in `server/*-router.ts`, the per-domain `server/project-router-{jobs,spending,settings,terminals,tickets,chat,setup}.ts` family, `server/code-explorer-router.ts`, and `server/jira-router.ts`. The app adds endpoints regularly; if a route exists in code but not here, please open an issue.
|
|
631
740
|
- **Stability**: routes under `/api/*` and `/api/projects/:projectId/*` are considered stable. A few legacy setup endpoints (`setup/start`, `setup/message`, `enrich/*`) back a flow the UI does not expose and remain only for forward compatibility.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Architecture
|
|
2
2
|
|
|
3
|
-
This document describes the technical architecture of specrails-desktop
|
|
3
|
+
This document describes the technical architecture of specrails-desktop: its layers, data layout, request flow, authentication, and the subsystems that make up the app. It is the entry point to the other internals docs — see the [See also](#see-also) block at the bottom. (The authoritative version lives in `package.json`; this doc is verified against `main`.)
|
|
4
4
|
|
|
5
5
|
---
|
|
6
6
|
|
|
@@ -39,16 +39,22 @@ Tests use vitest with `:memory:` SQLite databases.
|
|
|
39
39
|
~/.specrails/
|
|
40
40
|
desktop.sqlite # project registry (id, name, path, slug, provider…)
|
|
41
41
|
desktop.token # auth token, mode 0600 (auto-generated on first run)
|
|
42
|
+
registry.json # repo-realpath → workspace map shared with specrails-core (artifact relocation)
|
|
42
43
|
manager.pid # server PID for clean shutdown
|
|
44
|
+
framework/<version>/<provider>/ # bundled specrails-core framework, materialized once
|
|
45
|
+
framework/current # symlink → active framework version (atomic swap on app update)
|
|
43
46
|
projects/
|
|
44
47
|
<slug>/
|
|
45
48
|
jobs.sqlite # per-project: jobs, rails, tickets, invocations, …
|
|
46
49
|
jobs/<jobId>/ # per-job snapshots (profile.json, plugins.json, …)
|
|
50
|
+
workspace/ # relocated spawn cwd (artifactRoot); ./project link → repo
|
|
47
51
|
telemetry/ # OTEL blobs (compacted after 7 days)
|
|
48
52
|
explore-cwd/ # app-managed Explore spawn cwd (CLAUDE.md + ./project link)
|
|
49
53
|
terminals/ # per-session shell-integration shims
|
|
50
54
|
```
|
|
51
55
|
|
|
56
|
+
> **Artifact relocation + bundled framework (pre-release, branch `feat/relocate-artifacts-to-home`).** Relocated projects spawn AI-CLIs from `projects/<slug>/workspace` (with `SPECRAILS_REPO_DIR` pointing at the repo) instead of the repo, so imported repos stay pristine; the framework is bundled and symlinked instead of installed per-project via `npx`. See the **Artifact relocation + bundled framework** section in `CLAUDE.md` and the three internal docs: `global-artifacts-relocation-evaluation.md`, `global-artifacts-alignment-contract.md`, `bundled-framework-build-plan.md`.
|
|
57
|
+
|
|
52
58
|
The app SQLite (`desktop.sqlite`) stores only project metadata. All per-project data lives in an isolated `jobs.sqlite` under the project's slug directory — not just jobs and chat, but rails, tickets, agent profiles/versions, AI invocations (cost analytics), telemetry pointers, file provenance, terminal settings/marks, and more (see the `MIGRATIONS` array in `server/db.ts`). Projects can be removed and re-added without losing history, and the registry can be wiped without touching project data.
|
|
53
59
|
|
|
54
60
|
> The data root is hardcoded to `os.homedir()/.specrails`. There is no environment override for the data directory.
|
|
@@ -153,7 +159,7 @@ client/src/
|
|
|
153
159
|
│ ├── AnalyticsPage.tsx # Per-project cost analytics
|
|
154
160
|
│ ├── DesktopAnalyticsPage.tsx # Cross-project spending roll-up
|
|
155
161
|
│ ├── AgentsPage.tsx # Agent profiles + catalog
|
|
156
|
-
│ ├── CodePage.tsx #
|
|
162
|
+
│ ├── CodePage.tsx # Code explorer: file tree + Monaco viewer + edit (flag-gated)
|
|
157
163
|
│ ├── SettingsPage.tsx # Per-project settings
|
|
158
164
|
│ ├── GlobalSettingsPage.tsx # App settings
|
|
159
165
|
│ └── JobDetailPage.tsx # Full log viewer for a single job
|
|
@@ -202,20 +208,25 @@ A single WebSocket connection at `ws://127.0.0.1:4200/ws` multiplexes all applic
|
|
|
202
208
|
|
|
203
209
|
Every project-scoped message includes a `projectId` field; app-level messages (`desktop.project_added`, `desktop.project_removed`, `desktop.projects`) have none.
|
|
204
210
|
|
|
211
|
+
### Connect handshake
|
|
212
|
+
|
|
213
|
+
The **only** frame the server sends on connect is `desktop.projects` (the full project registry) — `server/index.ts` pushes it inside `wss.on('connection', …)`. There is no rich per-connection dashboard snapshot pushed automatically. After connecting, a client subscribes to a project (sends a subscribe frame with `projectId`); per-project state then arrives as the project broadcasts it — notably the `queue` snapshot and per-job `exit` replay. A new client should code against `desktop.projects`, not against an `init` frame.
|
|
214
|
+
|
|
215
|
+
> **`init` is defined-but-unused.** A `type:'init'` shape exists as a TypeScript interface in `server/types.ts`, but no code path emits it in Super mode — it is a legacy shape, not a live frame. Do not wire a client to receive it.
|
|
216
|
+
|
|
205
217
|
### Representative message types
|
|
206
218
|
|
|
207
219
|
Canonical shapes live in `server/types.ts`. The core dashboard messages:
|
|
208
220
|
|
|
209
221
|
| Type | Scope | Payload (key fields) |
|
|
210
222
|
|------|-------|----------------------|
|
|
211
|
-
| `
|
|
223
|
+
| `desktop.projects` | app | `{ projects }` — full registry, the **on-connect** frame |
|
|
212
224
|
| `queue` | project | `{ jobs, activeJobId, paused, timestamp, projectId }` — full queue snapshot |
|
|
213
225
|
| `log` | project | `{ source: 'stdout'\|'stderr', line, timestamp, processId, projectId }` |
|
|
214
226
|
| `phase` | project | `{ phase, state, timestamp, projectId }` |
|
|
215
227
|
| `exit` | project | `{ code, signal, early }` — process exit replay on the WS upgrade |
|
|
216
228
|
| `desktop.project_added` | app | `{ project }` |
|
|
217
229
|
| `desktop.project_removed` | app | `{ projectId }` |
|
|
218
|
-
| `desktop.projects` | app | `{ projects }` |
|
|
219
230
|
|
|
220
231
|
Job lifecycle is reported by the message types `job_started`, `job_completed`, `job_failed`, and `job_canceled`. Feature subsystems add many more (`spending.invalidated`, `plugin.*`, `file.*`, `rail.job_started/completed/stopped`, `explore.contract_refine_failed`, chat/refine/SMASH/proposal streams). See [`api-reference.md`](api-reference.md) for the full outbound-event catalogue.
|
|
221
232
|
|
|
@@ -237,7 +248,7 @@ App-level messages (no `projectId`) are processed by all handlers.
|
|
|
237
248
|
|
|
238
249
|
## Process spawning and concurrency
|
|
239
250
|
|
|
240
|
-
`QueueManager` and `ChatManager` spawn the provider CLI (`claude` or `
|
|
251
|
+
`QueueManager` and `ChatManager` spawn the project's provider CLI (`claude`, `codex`, or `gemini`) as subprocesses, always with `cwd` set so the process runs in the correct directory. The exact binary and argv are chosen by the resolved `ProviderAdapter` — managers never branch on the provider id (see [Multi-provider adapters](#feature-subsystems)).
|
|
241
252
|
|
|
242
253
|
- **Within a project, jobs run strictly one at a time.** Each `ProjectContext` has exactly one `QueueManager` with a single `_activeJobId`; `_drainQueue()` early-returns while a job is active, so the next rail job queues behind the current one.
|
|
243
254
|
- **Parallelism is across projects only** — each project has its own `QueueManager`, so jobs in different projects run simultaneously. There is no "max concurrent jobs" setting; the only automatic queue-pause is budget-based (daily budget / per-job cost alert).
|
|
@@ -253,15 +264,16 @@ The app is more than the job pipeline. Each subsystem owns its modules; this is
|
|
|
253
264
|
|
|
254
265
|
| Subsystem | Server modules | Notes |
|
|
255
266
|
|-----------|---------------|-------|
|
|
256
|
-
| **Multi-provider adapters** | `server/providers/{types,claude-adapter,codex-adapter,registry,index}.ts`, `server/provider-selection.ts` | Claude
|
|
267
|
+
| **Multi-provider adapters** | `server/providers/{types,claude-adapter,codex-adapter,gemini-adapter,registry,index}.ts`, `server/provider-selection.ts` | **Three first-class providers — Claude, Codex, and Gemini — all enabled by default** behind a `ProviderAdapter` contract. Claude has full native support (native cost + native OTEL + `--system-prompt`); Codex (`≥ 0.128.0`) has estimated cost and OTEL synthesized by the app; Gemini (`≥ 0.11.0`) has estimated cost but **native OTEL** (it honours the standard `OTEL_*` env vars QueueManager injects — no synthetic bridge), folds its system prompt into `GEMINI.md`, uses `project-json` MCP registration, defaults to `gemini-3.5-flash`, and uniquely implements the optional `prepareHeadlessSpawn()` hook to pre-acknowledge subagents for headless rail spawns. A project can install any subset; `providers[]` is a JSON column, the first entry is primary. Per-invocation provider is late-bound. Provider availability is gated by `SPECRAILS_CODEX_BETA` / `SPECRAILS_GEMINI_BETA` (set either to `0` to disable; both default-enabled, see [`configuration.md`](configuration.md)). See [`adding-a-provider.md`](adding-a-provider.md), [`../codex.md`](../codex.md), and [`../gemini.md`](../gemini.md). |
|
|
257
268
|
| **Spending analytics** | `server/spending.ts`, `server/ai-invocations.ts`, `server/pricing.ts` | `recordInvocation` writes an `ai_invocations` row per AI CLI call across six surfaces (`job`, `quick-spec`, `explore-spec`, `ai-edit`, `smash`, `file-summary`); powers the Analytics page and `spending.invalidated`. |
|
|
258
|
-
| **Agent profiles** | `server/profile-manager.ts`, `server/profiles-router.ts` | Declarative JSON in `.specrails/profiles/*.json`, snapshot-per-job, `SPECRAILS_PROFILE_PATH` env injection. Requires `specrails-core ≥ 4.1.0
|
|
269
|
+
| **Agent profiles** | `server/profile-manager.ts`, `server/profiles-router.ts` | Declarative JSON in `.specrails/profiles/*.json`, snapshot-per-job, `SPECRAILS_PROFILE_PATH` env injection. Requires `specrails-core ≥ 4.1.0` **in the project** (distinct from the app-wide install floor of `^4.8.0` — see [Setup wizard flow](#setup-wizard-flow)). Claude-only: the rails router force-nulls the profile for any non-Claude engine. |
|
|
259
270
|
| **Plugins (Integrations)** | `server/plugin-manager.ts`, `server/plugins/` | Bundled-only, MCP-based, additivity invariant, surgical `.mcp.json` merge, `plugin.*` WS events. Serena ships today. |
|
|
260
271
|
| **Terminal panel** | `server/terminal-manager.ts` | `node-pty` sessions over the dedicated `/ws/terminal/:id` socket, OSC shell-integration marks. See [`../terminal.md`](../terminal.md). |
|
|
261
|
-
| **Code explorer** | `server/code-explorer-router.ts`, `server/file-provenance.ts`, `server/file-summary-manager.ts` |
|
|
272
|
+
| **Code explorer** | `server/code-explorer-router.ts`, `server/file-provenance.ts`, `server/file-summary-manager.ts` | A non-developer-friendly file tree + Monaco viewer with plain-language AI summaries and *touched-by-AI* provenance chips per ticket/job, plus opt-in in-app editing of existing files (overwrite-only via `PUT /file` — no create/rename; refuses binaries `415`, enforces a 2 MB cap `413`, `404` on a missing path, respects deny-list/`.gitignore`). |
|
|
262
273
|
| **Pipeline telemetry** | `server/telemetry-receiver.ts` + QueueManager OTEL injection | Opt-in OTLP/JSON signals to `POST /otlp/v1/{traces,metrics,logs}`; blobs compacted after 7 days; diagnostic ZIP export. |
|
|
263
274
|
| **Explore acceleration + Contract Refine** | `server/explore-cwd-manager.ts`, `server/contract-refine-runner.ts` | App-managed Explore spawn cwd for fast first-token; optional post-commit Contract Layer enrichment. Kill switches: `SPECRAILS_EXPLORE_CONTRACT_REFINE`, `SPECRAILS_EXPLORE_LEGACY_CWD`. |
|
|
264
275
|
| **Tickets / drafts** | `server/ticket-store.ts` | Spec tickets (incl. `draft` status) backing the Specs board and Save-as-Draft flow. |
|
|
276
|
+
| **Jira integration** | `server/jira/*` (`jira-sync-manager`, `jira-client`, `jira-materializer`, `jira-status-resolver`, `jira-db`, `jira-credential-store`), `server/jira-router.ts` | Optional per-project sync that backs a project's specs with a Jira board (Cloud or Data Center). Desktop is the sync layer — specrails-core reads the materialized cache unchanged and stays read-only. Inbound polling + a durable outbox handle write-back; the encrypted token lives on-device. Routes under `/api/projects/:id/jira/*` (gated by `SPECRAILS_JIRA_SECTION`, 404 when off); project-scoped WS events `jira.synced`, `jira.sync_error`, `jira.auth_expired`, `jira.outbox_changed`, `jira.degraded`. See [`../jira-integration-plan.md`](../jira-integration-plan.md). |
|
|
265
277
|
| **Theme system** | `server/desktop-router.ts` (`GET/PATCH /api/theme`) | Five built-in themes (`dracula`, `aurora-light`, `obsidian-dark`, `matrix`, `specrails`), default `specrails`, persisted app-wide with an anti-FOUC inline script. |
|
|
266
278
|
|
|
267
279
|
Most client feature sections are gated by VITE flags, and they share one polarity: `VITE_FEATURE_TERMINAL_PANEL`, `VITE_FEATURE_AGENTS_SECTION`, `VITE_FEATURE_EXPLORE_PREMIUM_UX`, and `VITE_FEATURE_CODE_EXPLORER` are all **opt-out** — default ON, set the flag to `false` to hide that section. See [`configuration.md`](configuration.md) for the full flag and settings reference.
|
|
@@ -273,7 +285,7 @@ Most client feature sections are gated by VITE flags, and they share one polarit
|
|
|
273
285
|
When a project is added without specrails-core, the setup wizard runs. The client renders a **3-step** indicator: **Configure → Install → Done**.
|
|
274
286
|
|
|
275
287
|
1. **Configure** — confirm path and pick provider(s) and model presets. (Multi-provider projects get one Configure step per provider.)
|
|
276
|
-
2. **Install** — the app writes `.specrails/install-config.yaml` and runs `npx --yes --prefer-online specrails-core
|
|
288
|
+
2. **Install** — the app writes `.specrails/install-config.yaml` and runs `npx --yes --prefer-online specrails-core@^4.8.0 init --yes --from-config <tempPath>`, streaming the log. The package spec is the constant `CORE_PACKAGE_SPEC` — a deliberately pinned major range (the floor is `4.8.0`, the release that ships the Gemini provider target), so a future core `5.x` doesn't auto-land. Override the binary locally with `SPECRAILS_CORE_BIN`. For multi-provider projects each provider's install runs sequentially.
|
|
277
289
|
3. **Done** — per-provider completion summary.
|
|
278
290
|
|
|
279
291
|
`SetupManager` (server) owns wizard state; `DesktopProvider` (client) tracks which projects are in setup via `setupProjectIds`. The wizard does spawn a real AI CLI for the `/setup` chat, but that spawn is deliberately left uninstrumented (it writes no `ai_invocations` row).
|
|
@@ -328,5 +340,6 @@ macOS desktop builds are signed + notarized. Windows builds (x64 and arm64) ship
|
|
|
328
340
|
- [Configuration](configuration.md) — env vars, feature flags, app/project settings
|
|
329
341
|
- [Agent profiles](profiles.md) — profile schema, resolution order, snapshot-per-job
|
|
330
342
|
- [Adding a provider](adding-a-provider.md) — the `ProviderAdapter` contract
|
|
343
|
+
- [Codex](../codex.md) / [Gemini](../gemini.md) — per-provider user guides
|
|
331
344
|
- [OpenSpec workflow](openspec-workflow.md) — the spec-driven change lifecycle
|
|
332
345
|
- [Operations runbook](operations-runbook.md) — running, upgrading, and recovering the app
|