specrails-desktop 2.8.0 → 2.9.1
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-DpQzYMBz.js} +1 -1
- package/client/dist/assets/{AgentsPage-Cb-b-6Ot.js → AgentsPage-29fCY8qV.js} +1 -1
- package/client/dist/assets/{AnalyticsPage-HVxQQ1wy.js → AnalyticsPage-BwGtS6Hf.js} +1 -1
- package/client/dist/assets/{BarChart-BOyHB0dw.js → BarChart-CTR97DVC.js} +1 -1
- package/client/dist/assets/{CodePage-DnOnwKGB.js → CodePage-yAAxKasA.js} +1 -1
- package/client/dist/assets/{DesktopAnalyticsPage-D2auU39x.js → DesktopAnalyticsPage-BdK_XpsD.js} +1 -1
- package/client/dist/assets/{DocsDialog-CTuDX3GK.js → DocsDialog-BaE0cLlL.js} +2 -2
- package/client/dist/assets/{DocsPage-DRyMmu0Z.js → DocsPage-c1FgZX8_.js} +2 -2
- package/client/dist/assets/{ExportDropdown-DO-GGiMh.js → ExportDropdown-lPv_yDen.js} +1 -1
- package/client/dist/assets/{IntegrationsPage-BhbO4jFT.js → IntegrationsPage-DOpxRe7G.js} +1 -1
- package/client/dist/assets/{JobDetailPage-DJooEg1s.js → JobDetailPage-5ExzXY-F.js} +1 -1
- package/client/dist/assets/{JobsPage-BbaC-YOg.js → JobsPage-iW7WuPAc.js} +1 -1
- package/client/dist/assets/{dist-js-Xc2lRKp2.js → dist-js-A8aSaLng.js} +1 -1
- package/client/dist/assets/{dist-js-CiIVMsx3.js → dist-js-CD_m3Xj5.js} +1 -1
- package/client/dist/assets/index-D6BaYRRU.css +2 -0
- package/client/dist/assets/{index-DK214dak.js → index-DRhFPNAv.js} +44 -44
- 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-1vkTuLY7.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/{tickets-9kdPXInd.js → tickets-CG_mo-Bg.js} +1 -1
- package/client/dist/assets/{tickets-n23kDqJT.js → tickets-CVJQ-vRm.js} +1 -1
- package/client/dist/assets/{tickets-tGx5AR5b.js → tickets-D5MSAPe_.js} +1 -1
- package/client/dist/assets/{tickets-1UIGf_oA.js → tickets-DBV3wgQZ.js} +1 -1
- package/client/dist/assets/{tickets-DNmXcAwu.js → tickets-Q0_pONEh.js} +1 -1
- package/client/dist/assets/{tickets-C6pwZwt4.js → tickets-RZ0LyeQe.js} +1 -1
- package/client/dist/assets/{tickets-DAjtxAVb.js → tickets-d1A6EOHa.js} +1 -1
- package/client/dist/assets/{tickets-0rM0lIXd.js → tickets-r4-oNV0R.js} +1 -1
- package/client/dist/assets/{useProjectCache-DVNypkmR.js → useProjectCache-CSi2xHri.js} +1 -1
- package/client/dist/index.html +5 -5
- 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 +24 -1
- 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/queue-manager.js +149 -18
- 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/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
|
@@ -340,11 +340,15 @@ function extractTicketIdsFromCommand(command) {
|
|
|
340
340
|
* resolve to `title: null`. Returns `[]` when the command has no ticket
|
|
341
341
|
* references.
|
|
342
342
|
*/
|
|
343
|
-
function resolveTicketsFromCommand(projectPath, command
|
|
343
|
+
function resolveTicketsFromCommand(projectPath, command,
|
|
344
|
+
/** Relocate-artifacts: when provided, read the store from this absolute path
|
|
345
|
+
* (the workspace ticket store) instead of `resolveTicketStoragePath(
|
|
346
|
+
* projectPath)`. Legacy callers omit it and behave byte-identically. */
|
|
347
|
+
ticketsPathOverride) {
|
|
344
348
|
const ids = extractTicketIdsFromCommand(command);
|
|
345
349
|
if (ids.length === 0)
|
|
346
350
|
return [];
|
|
347
|
-
const store = readStore(resolveTicketStoragePath(projectPath));
|
|
351
|
+
const store = readStore(ticketsPathOverride ?? resolveTicketStoragePath(projectPath));
|
|
348
352
|
return ids.map((id) => ({
|
|
349
353
|
id,
|
|
350
354
|
title: store.tickets[String(id)]?.title ?? null,
|
|
@@ -7,6 +7,7 @@ exports.TicketWatcher = void 0;
|
|
|
7
7
|
const path_1 = __importDefault(require("path"));
|
|
8
8
|
const fs_1 = __importDefault(require("fs"));
|
|
9
9
|
const chokidar_1 = require("chokidar");
|
|
10
|
+
const workspace_resolution_1 = require("./workspace-resolution");
|
|
10
11
|
const TICKET_FILE = '.specrails/local-tickets.json';
|
|
11
12
|
const DEBOUNCE_MS = 150;
|
|
12
13
|
/**
|
|
@@ -33,7 +34,10 @@ class TicketWatcher {
|
|
|
33
34
|
start() {
|
|
34
35
|
if (this._closed)
|
|
35
36
|
return;
|
|
36
|
-
|
|
37
|
+
// Relocate-artifacts gate: watch the workspace ticket file when relocated,
|
|
38
|
+
// else the repo-relative file (byte-identical for existing projects).
|
|
39
|
+
const exec = (0, workspace_resolution_1.resolveProjectExecution)({ path: this._projectPath });
|
|
40
|
+
const filePath = exec.relocated ? exec.ticketsPath : path_1.default.join(this._projectPath, TICKET_FILE);
|
|
37
41
|
// Seed initial revision so we can detect external changes
|
|
38
42
|
this._lastRevision = this._readRevision(filePath);
|
|
39
43
|
this._watcher = new chokidar_1.FSWatcher({
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
const fs_1 = require("fs");
|
|
7
|
+
const os_1 = __importDefault(require("os"));
|
|
8
|
+
const path_1 = __importDefault(require("path"));
|
|
9
|
+
/**
|
|
10
|
+
* Test safety net: NEVER let a test write the relocation registry into the
|
|
11
|
+
* developer's real `$HOME/.specrails/registry.json`.
|
|
12
|
+
*
|
|
13
|
+
* `ProjectRegistry.loadAll()` runs `reconcileFromProjects`, and `addProject`
|
|
14
|
+
* runs `mirrorProjectEntry`; both resolve the registry path from
|
|
15
|
+
* `resolveHome()`, which falls back to `os.homedir()` when neither a `home`
|
|
16
|
+
* arg nor `SPECRAILS_REGISTRY_HOME` is set. A test that constructs a
|
|
17
|
+
* `ProjectRegistry` without pinning a tmp home would then pollute the real
|
|
18
|
+
* registry. This setup file (run once per test file by vitest `setupFiles`)
|
|
19
|
+
* points `SPECRAILS_REGISTRY_HOME` at a throwaway tmp dir unless the test has
|
|
20
|
+
* already set its own, so the real home is unreachable from tests by
|
|
21
|
+
* construction. Tests that need a specific home still override it per-test.
|
|
22
|
+
*/
|
|
23
|
+
if (!process.env.SPECRAILS_REGISTRY_HOME) {
|
|
24
|
+
process.env.SPECRAILS_REGISTRY_HOME = (0, fs_1.mkdtempSync)(path_1.default.join(os_1.default.tmpdir(), 'specrails-desktop-test-home-'));
|
|
25
|
+
}
|
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.workspacePathFor = workspacePathFor;
|
|
7
|
+
exports.ensureWorkspace = ensureWorkspace;
|
|
8
|
+
exports.assembleWorkspaceFramework = assembleWorkspaceFramework;
|
|
9
|
+
exports.removeWorkspace = removeWorkspace;
|
|
10
|
+
const fs_1 = __importDefault(require("fs"));
|
|
11
|
+
const path_1 = __importDefault(require("path"));
|
|
12
|
+
const os_1 = __importDefault(require("os"));
|
|
13
|
+
const framework_manager_1 = require("./framework-manager");
|
|
14
|
+
const framework_migration_1 = require("./framework-migration");
|
|
15
|
+
/**
|
|
16
|
+
* WorkspaceManager — a reusable materializer for the per-project workspace dir
|
|
17
|
+
* under `~/.specrails/projects/<slug>/workspace`. This is the relocation target
|
|
18
|
+
* for a repo's artifacts (see `server/artifact-registry.ts` + the global-
|
|
19
|
+
* artifacts-alignment contract): the workspace holds the `./project` link back
|
|
20
|
+
* to the user's repo so tools spawned with the workspace as cwd can still reach
|
|
21
|
+
* the source.
|
|
22
|
+
*
|
|
23
|
+
* This generalizes the materialization logic of `explore-cwd-manager.ts`
|
|
24
|
+
* (the `ensureProjectLink` symlink/junction/fallback dance) without coupling to
|
|
25
|
+
* the Explore-specific embedded instructions file. Explore-cwd is intentionally
|
|
26
|
+
* left UNCHANGED (it keeps its own parallel copy); this module is the forward-
|
|
27
|
+
* looking home for workspace materialization.
|
|
28
|
+
*
|
|
29
|
+
* NOTE (this stage): nothing yet spawns from the workspace dir. This is the
|
|
30
|
+
* additive foundation — wiring spawn cwd/env to the workspace is a later stage.
|
|
31
|
+
*/
|
|
32
|
+
/** Base dir holding all per-project app data. Overridable for tests. */
|
|
33
|
+
function projectsBaseDir(home) {
|
|
34
|
+
return path_1.default.join(home ?? os_1.default.homedir(), '.specrails', 'projects');
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Compute the workspace path for a project without touching the filesystem.
|
|
38
|
+
* Mirrors `artifact-registry.workspaceLayout(...).workspaceDir`.
|
|
39
|
+
*/
|
|
40
|
+
function workspacePathFor(slug, home) {
|
|
41
|
+
return path_1.default.join(projectsBaseDir(home), slug, 'workspace');
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Create or refresh the workspace dir for a project. Idempotent and cheap when
|
|
45
|
+
* already up-to-date. Creates the workspace directory and a `./project`
|
|
46
|
+
* symlink (junction on Windows) pointing at `projectPath`, with a
|
|
47
|
+
* `project-path.txt` fallback when symlink/junction creation fails. Returns the
|
|
48
|
+
* absolute workspace path.
|
|
49
|
+
*/
|
|
50
|
+
function ensureWorkspace(slug, projectPath, home) {
|
|
51
|
+
const ws = workspacePathFor(slug, home);
|
|
52
|
+
fs_1.default.mkdirSync(ws, { recursive: true });
|
|
53
|
+
ensureProjectLink(ws, projectPath);
|
|
54
|
+
return ws;
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Ensure the workspace exists (with the `./project` link) AND assemble the
|
|
58
|
+
* framework into it by SYMLINK (offline) via the bundled specrails-core
|
|
59
|
+
* `assemble` subcommand. The providerDir static subtrees
|
|
60
|
+
* (`agents/`/`commands/`/`skills/`/`rules/`) become symlinks into
|
|
61
|
+
* `~/.specrails/framework/current/<provider>/`; `agent-memory/` stays a real
|
|
62
|
+
* writable dir (core's assemble handles that distinction).
|
|
63
|
+
*
|
|
64
|
+
* EXISTENCE-GATED: when no bundled core is present, `assembled` is false and the
|
|
65
|
+
* caller must fall back to the legacy `npx specrails-core init` assembly. The
|
|
66
|
+
* workspace + `./project` link are still ensured so the legacy path has a cwd.
|
|
67
|
+
*/
|
|
68
|
+
function assembleWorkspaceFramework(slug, projectPath, provider, opts = {}) {
|
|
69
|
+
const ws = ensureWorkspace(slug, projectPath, opts.home);
|
|
70
|
+
const fm = opts.framework ?? new framework_manager_1.FrameworkManager({ home: opts.home });
|
|
71
|
+
if (!fm.isAvailable()) {
|
|
72
|
+
return { assembled: false, workspace: ws };
|
|
73
|
+
}
|
|
74
|
+
// Lazy-on-first-touch migration: if this workspace still holds a per-workspace
|
|
75
|
+
// framework COPY (the pre-bundled relocate-core layout), convert it to symlinks
|
|
76
|
+
// into `framework/current` non-destructively BEFORE assembling. Idempotent +
|
|
77
|
+
// safe to run repeatedly; it no-ops once the workspace is symlinked. The
|
|
78
|
+
// migration re-enters this function with `_skipMigrate` to do the actual
|
|
79
|
+
// re-link, so we guard against infinite recursion here.
|
|
80
|
+
if (!opts._skipMigrate) {
|
|
81
|
+
try {
|
|
82
|
+
(0, framework_migration_1.migrateWorkspaceToSymlinks)(slug, projectPath, provider, {
|
|
83
|
+
home: opts.home,
|
|
84
|
+
framework: fm,
|
|
85
|
+
broadcast: opts.broadcast,
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
catch {
|
|
89
|
+
/* migration is best-effort; assemble below still produces a usable layout */
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
const res = fm.assembleWorkspace({
|
|
93
|
+
workspace: ws,
|
|
94
|
+
provider,
|
|
95
|
+
version: opts.version,
|
|
96
|
+
codeRoot: projectPath,
|
|
97
|
+
});
|
|
98
|
+
if (!res.ran)
|
|
99
|
+
return { assembled: false, workspace: ws };
|
|
100
|
+
return { assembled: true, workspace: ws, error: res.error };
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* Recursively remove the workspace dir for a project. The `project`
|
|
104
|
+
* symlink/junction is unlinked explicitly (never followed) so the user's repo
|
|
105
|
+
* is never touched. No-op when the dir does not exist.
|
|
106
|
+
*/
|
|
107
|
+
function removeWorkspace(slug, home) {
|
|
108
|
+
const ws = workspacePathFor(slug, home);
|
|
109
|
+
if (!fs_1.default.existsSync(ws))
|
|
110
|
+
return;
|
|
111
|
+
const linkPath = path_1.default.join(ws, 'project');
|
|
112
|
+
try {
|
|
113
|
+
const st = fs_1.default.lstatSync(linkPath);
|
|
114
|
+
if (st.isSymbolicLink() || (process.platform === 'win32' && st.isDirectory())) {
|
|
115
|
+
// unlink works on POSIX symlinks; rmdir on Windows junctions
|
|
116
|
+
try {
|
|
117
|
+
fs_1.default.unlinkSync(linkPath);
|
|
118
|
+
}
|
|
119
|
+
catch {
|
|
120
|
+
try {
|
|
121
|
+
fs_1.default.rmdirSync(linkPath);
|
|
122
|
+
}
|
|
123
|
+
catch { /* best-effort */ }
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
catch {
|
|
128
|
+
/* link may not exist */
|
|
129
|
+
}
|
|
130
|
+
fs_1.default.rmSync(ws, { recursive: true, force: true });
|
|
131
|
+
}
|
|
132
|
+
/**
|
|
133
|
+
* Ensure `<ws>/project` resolves to `<projectPath>` (symlink on POSIX, junction
|
|
134
|
+
* on Windows). Recreated when the existing target differs. On both symlink and
|
|
135
|
+
* junction failure, writes a `project-path.txt` fallback. This is the EXACT
|
|
136
|
+
* logic from `explore-cwd-manager.ts`'s private `ensureProjectLink`.
|
|
137
|
+
*/
|
|
138
|
+
function ensureProjectLink(cwd, projectPath) {
|
|
139
|
+
const linkPath = path_1.default.join(cwd, 'project');
|
|
140
|
+
const fallbackPath = path_1.default.join(cwd, 'project-path.txt');
|
|
141
|
+
let needsCreate = true;
|
|
142
|
+
try {
|
|
143
|
+
const st = fs_1.default.lstatSync(linkPath);
|
|
144
|
+
if (st.isSymbolicLink()) {
|
|
145
|
+
const current = fs_1.default.readlinkSync(linkPath);
|
|
146
|
+
if (path_1.default.resolve(cwd, current) === path_1.default.resolve(projectPath)) {
|
|
147
|
+
needsCreate = false;
|
|
148
|
+
}
|
|
149
|
+
else {
|
|
150
|
+
fs_1.default.unlinkSync(linkPath);
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
else {
|
|
154
|
+
// existing non-symlink (e.g. Windows junction or stale dir) — replace
|
|
155
|
+
try {
|
|
156
|
+
fs_1.default.unlinkSync(linkPath);
|
|
157
|
+
}
|
|
158
|
+
catch {
|
|
159
|
+
try {
|
|
160
|
+
fs_1.default.rmdirSync(linkPath);
|
|
161
|
+
}
|
|
162
|
+
catch { /* best-effort */ }
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
catch {
|
|
167
|
+
/* link does not exist — fall through to create */
|
|
168
|
+
}
|
|
169
|
+
if (needsCreate) {
|
|
170
|
+
let created = false;
|
|
171
|
+
if (process.platform === 'win32') {
|
|
172
|
+
try {
|
|
173
|
+
fs_1.default.symlinkSync(projectPath, linkPath, 'junction');
|
|
174
|
+
created = true;
|
|
175
|
+
}
|
|
176
|
+
catch { /* fall through to plain symlink */ }
|
|
177
|
+
}
|
|
178
|
+
if (!created) {
|
|
179
|
+
try {
|
|
180
|
+
fs_1.default.symlinkSync(projectPath, linkPath);
|
|
181
|
+
created = true;
|
|
182
|
+
}
|
|
183
|
+
catch { /* fall through to text fallback */ }
|
|
184
|
+
}
|
|
185
|
+
if (!created) {
|
|
186
|
+
// Final fallback: write the absolute path so the model can use it.
|
|
187
|
+
fs_1.default.writeFileSync(fallbackPath, projectPath, 'utf-8');
|
|
188
|
+
return;
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
// If we successfully created/verified the symlink, clean up any stale
|
|
192
|
+
// fallback file from a prior failed attempt.
|
|
193
|
+
if (fs_1.default.existsSync(fallbackPath)) {
|
|
194
|
+
try {
|
|
195
|
+
fs_1.default.unlinkSync(fallbackPath);
|
|
196
|
+
}
|
|
197
|
+
catch { /* ignore */ }
|
|
198
|
+
}
|
|
199
|
+
}
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* workspace-resolution — the SINGLE gate for the relocate-artifacts-to-home
|
|
4
|
+
* feature (DESKTOP STAGE 2). Every spawner cwd/env decision and every relocated
|
|
5
|
+
* artifact-read site funnels through `resolveProjectExecution(...)`.
|
|
6
|
+
*
|
|
7
|
+
* THE GATE — a project is "relocated" iff BOTH hold:
|
|
8
|
+
* 1. a registry entry exists for the repo (`resolveArtifacts(...).isLegacy ===
|
|
9
|
+
* false`), AND
|
|
10
|
+
* 2. the workspace is actually populated by core — detected by the presence of
|
|
11
|
+
* `<workspace>/.specrails/specrails-version` (core installed there).
|
|
12
|
+
*
|
|
13
|
+
* When NOT relocated (every existing in-repo project, or a relocated registry
|
|
14
|
+
* entry whose workspace core has not yet populated) the resolution is
|
|
15
|
+
* BYTE-IDENTICAL to pre-stage-2 behaviour: cwd = project.path, repo-relative
|
|
16
|
+
* artifact paths, empty env. This is what keeps stage 2 regression-safe for
|
|
17
|
+
* existing users — only relocated projects diverge.
|
|
18
|
+
*
|
|
19
|
+
* When relocated:
|
|
20
|
+
* - cwd = the workspace dir (core discovers sr-* agents there),
|
|
21
|
+
* - repoDir = project.path (the user's repo; source/git/openspec stay here),
|
|
22
|
+
* - env = { SPECRAILS_REPO_DIR: project.path, ... } so stage-3
|
|
23
|
+
* `${SPECRAILS_REPO_DIR:-.}` re-pointing drives source/openspec/
|
|
24
|
+
* git I/O back into the repo,
|
|
25
|
+
* - artifact paths point at the workspace (from the registry entry),
|
|
26
|
+
* - the `<workspace>/project` symlink is (re)created before returning so tools
|
|
27
|
+
* spawned from the workspace can still reach the repo by relative path.
|
|
28
|
+
*
|
|
29
|
+
* The workspace path is ALWAYS read from the registry entry (an adopted repo's
|
|
30
|
+
* registry slug may differ from the desktop.sqlite slug); never recompute it
|
|
31
|
+
* from a desktop slug.
|
|
32
|
+
*/
|
|
33
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
34
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
35
|
+
};
|
|
36
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
37
|
+
exports.isWorkspacePopulated = isWorkspacePopulated;
|
|
38
|
+
exports.resolveProjectExecution = resolveProjectExecution;
|
|
39
|
+
const fs_1 = __importDefault(require("fs"));
|
|
40
|
+
const path_1 = __importDefault(require("path"));
|
|
41
|
+
const artifact_registry_1 = require("./artifact-registry");
|
|
42
|
+
const workspace_manager_1 = require("./workspace-manager");
|
|
43
|
+
/** Marker file core writes into the workspace once it has installed there. The
|
|
44
|
+
* presence of this file is the "populated" half of the gate. */
|
|
45
|
+
const WORKSPACE_VERSION_MARKER = path_1.default.join('.specrails', 'specrails-version');
|
|
46
|
+
/** True when `<workspaceDir>/.specrails/specrails-version` exists (core has
|
|
47
|
+
* installed into the workspace). The legacy `.specrails-version` location is
|
|
48
|
+
* NOT a workspace marker (a bare workspace dir never has the dot-file form).
|
|
49
|
+
*
|
|
50
|
+
* Bundled-framework layout: `assemble` SYMLINKS the providerDir subtrees
|
|
51
|
+
* (`agents/` per-file, `commands/`/`skills/`/`rules/` whole-dir) into the
|
|
52
|
+
* workspace but writes the `.specrails/specrails-version` marker as a REAL file
|
|
53
|
+
* (via core's `writeManifestFiles`). So "populated" depends only on the real
|
|
54
|
+
* marker — it is agnostic to whether the providerDir is a real dir or a tree of
|
|
55
|
+
* symlinks into `framework/current/<provider>/`. `fs.existsSync` resolves the
|
|
56
|
+
* marker (and would also resolve it through a symlinked `.specrails`, though the
|
|
57
|
+
* manifest layer is never linked). */
|
|
58
|
+
function isWorkspacePopulated(workspaceDir) {
|
|
59
|
+
try {
|
|
60
|
+
return fs_1.default.existsSync(path_1.default.join(workspaceDir, WORKSPACE_VERSION_MARKER));
|
|
61
|
+
}
|
|
62
|
+
catch {
|
|
63
|
+
return false;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* THE GATE. Resolve how a project's AI CLIs should be spawned and where its
|
|
68
|
+
* relocated artifacts live. Read-only with respect to the registry; the only
|
|
69
|
+
* side effect (when relocated) is (re)creating the workspace `./project` symlink
|
|
70
|
+
* via `ensureWorkspace`.
|
|
71
|
+
*/
|
|
72
|
+
function resolveProjectExecution(project, home) {
|
|
73
|
+
const repoDir = project.path;
|
|
74
|
+
let art;
|
|
75
|
+
try {
|
|
76
|
+
art = (0, artifact_registry_1.resolveArtifacts)(project.path, { allocate: false }, home);
|
|
77
|
+
}
|
|
78
|
+
catch {
|
|
79
|
+
// A registry read failure must never break a spawn — fall back to legacy.
|
|
80
|
+
return legacyExecution(repoDir);
|
|
81
|
+
}
|
|
82
|
+
// Gate part 1: no registry entry ⇒ legacy.
|
|
83
|
+
if (art.isLegacy) {
|
|
84
|
+
return legacyExecution(repoDir);
|
|
85
|
+
}
|
|
86
|
+
// Gate part 2: registry entry exists but the workspace is NOT yet populated by
|
|
87
|
+
// core ⇒ stay legacy (existing project that has a registry entry but whose
|
|
88
|
+
// core install still lives in-repo). This is what keeps every existing
|
|
89
|
+
// assertion valid: a registry entry alone never flips a project to relocated.
|
|
90
|
+
if (!isWorkspacePopulated(art.workspaceDir)) {
|
|
91
|
+
return legacyExecution(repoDir);
|
|
92
|
+
}
|
|
93
|
+
// Relocated. (Re)create the workspace `./project` symlink so tools spawned from
|
|
94
|
+
// the workspace can still reach the repo. ALWAYS use the REGISTRY entry's slug
|
|
95
|
+
// (an adopted repo's registry slug may differ from the desktop slug) so the
|
|
96
|
+
// symlink lands in the same workspace dir core populated. Best-effort — a
|
|
97
|
+
// symlink failure must not abort the spawn (ensureWorkspace falls back to
|
|
98
|
+
// project-path.txt internally).
|
|
99
|
+
const workspaceSlug = art.entry?.slug ?? project.slug;
|
|
100
|
+
try {
|
|
101
|
+
if (workspaceSlug)
|
|
102
|
+
(0, workspace_manager_1.ensureWorkspace)(workspaceSlug, repoDir, home);
|
|
103
|
+
}
|
|
104
|
+
catch {
|
|
105
|
+
/* non-fatal — ensureWorkspace already has its own fallbacks */
|
|
106
|
+
}
|
|
107
|
+
const env = {
|
|
108
|
+
SPECRAILS_REPO_DIR: repoDir,
|
|
109
|
+
SPECRAILS_WORKSPACE_DIR: art.workspaceDir,
|
|
110
|
+
SPECRAILS_TICKETS_PATH: art.ticketsPath,
|
|
111
|
+
SPECRAILS_STATE_DIR: art.stateDir,
|
|
112
|
+
SPECRAILS_BACKLOG_CONFIG_PATH: art.backlogConfigPath,
|
|
113
|
+
SPECRAILS_PROFILES_DIR: art.profilesDir,
|
|
114
|
+
};
|
|
115
|
+
return {
|
|
116
|
+
relocated: true,
|
|
117
|
+
cwd: art.workspaceDir,
|
|
118
|
+
repoDir,
|
|
119
|
+
workspaceDir: art.workspaceDir,
|
|
120
|
+
ticketsPath: art.ticketsPath,
|
|
121
|
+
backlogConfigPath: art.backlogConfigPath,
|
|
122
|
+
profilesDir: art.profilesDir,
|
|
123
|
+
pluginsStateDir: art.pluginsStateDir,
|
|
124
|
+
fileSummariesDir: art.fileSummariesDir,
|
|
125
|
+
specrailsDir: art.specrailsDir,
|
|
126
|
+
stateDir: art.stateDir,
|
|
127
|
+
env,
|
|
128
|
+
};
|
|
129
|
+
}
|
|
130
|
+
/** Build the legacy (in-repo, byte-identical-to-today) execution. */
|
|
131
|
+
function legacyExecution(repoDir) {
|
|
132
|
+
const specrailsDir = path_1.default.join(repoDir, '.specrails');
|
|
133
|
+
return {
|
|
134
|
+
relocated: false,
|
|
135
|
+
cwd: repoDir,
|
|
136
|
+
repoDir,
|
|
137
|
+
workspaceDir: null,
|
|
138
|
+
ticketsPath: path_1.default.join(specrailsDir, 'local-tickets.json'),
|
|
139
|
+
backlogConfigPath: path_1.default.join(specrailsDir, 'backlog-config.json'),
|
|
140
|
+
profilesDir: path_1.default.join(specrailsDir, 'profiles'),
|
|
141
|
+
pluginsStateDir: path_1.default.join(specrailsDir, 'plugins'),
|
|
142
|
+
fileSummariesDir: path_1.default.join(specrailsDir, 'file-summaries'),
|
|
143
|
+
specrailsDir,
|
|
144
|
+
stateDir: path_1.default.join(repoDir, '.claude'),
|
|
145
|
+
env: {},
|
|
146
|
+
};
|
|
147
|
+
}
|