@slycode/slycode 0.2.21 → 0.2.23
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/dist/bridge/api.d.ts +2 -1
- package/dist/bridge/api.js +114 -1
- package/dist/bridge/api.js.map +1 -1
- package/dist/bridge/git-utils.d.ts +9 -0
- package/dist/bridge/git-utils.js +49 -0
- package/dist/bridge/git-utils.js.map +1 -0
- package/dist/bridge/index.js +8 -2
- package/dist/bridge/index.js.map +1 -1
- package/dist/bridge/provider-utils.d.ts +10 -0
- package/dist/bridge/provider-utils.js +5 -1
- package/dist/bridge/provider-utils.js.map +1 -1
- package/dist/bridge/response-store.d.ts +46 -0
- package/dist/bridge/response-store.js +95 -0
- package/dist/bridge/response-store.js.map +1 -0
- package/dist/bridge/session-manager.d.ts +33 -1
- package/dist/bridge/session-manager.js +191 -2
- package/dist/bridge/session-manager.js.map +1 -1
- package/dist/bridge/types.d.ts +41 -0
- package/dist/data/scaffold-templates/tutorial-project/documentation/kanban.json +1 -1
- package/dist/messaging/bridge-client.d.ts +7 -3
- package/dist/messaging/bridge-client.js +26 -5
- package/dist/messaging/bridge-client.js.map +1 -1
- package/dist/messaging/index.js +149 -30
- package/dist/messaging/index.js.map +1 -1
- package/dist/messaging/state.d.ts +3 -0
- package/dist/messaging/state.js +13 -0
- package/dist/messaging/state.js.map +1 -1
- package/dist/messaging/types.d.ts +3 -0
- package/dist/scripts/kanban.js +448 -2
- package/dist/store/actions/checkpoint.md +1 -1
- package/dist/store/actions/context.md +1 -1
- package/dist/store/actions/create-card.md +1 -1
- package/dist/store/actions/deep-design.md +13 -3
- package/dist/store/actions/design-requirements.md +11 -1
- package/dist/store/actions/explore.md +1 -1
- package/dist/store/actions/onboard.md +2 -4
- package/dist/store/actions/summarize.md +1 -1
- package/dist/store/skills/kanban/SKILL.md +77 -3
- package/dist/web/.next/BUILD_ID +1 -1
- package/dist/web/.next/app-path-routes-manifest.json +1 -0
- package/dist/web/.next/build-manifest.json +2 -2
- package/dist/web/.next/prerender-manifest.json +3 -3
- package/dist/web/.next/routes-manifest.json +6 -0
- package/dist/web/.next/server/app/_global-error.html +2 -2
- package/dist/web/.next/server/app/_global-error.rsc +1 -1
- package/dist/web/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +1 -1
- package/dist/web/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
- package/dist/web/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
- package/dist/web/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
- package/dist/web/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
- package/dist/web/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
- package/dist/web/.next/server/app/_not-found.html +1 -1
- package/dist/web/.next/server/app/_not-found.rsc +10 -10
- package/dist/web/.next/server/app/_not-found.segments/_full.segment.rsc +10 -10
- package/dist/web/.next/server/app/_not-found.segments/_head.segment.rsc +4 -4
- package/dist/web/.next/server/app/_not-found.segments/_index.segment.rsc +5 -5
- package/dist/web/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +2 -2
- package/dist/web/.next/server/app/_not-found.segments/_not-found.segment.rsc +3 -3
- package/dist/web/.next/server/app/_not-found.segments/_tree.segment.rsc +2 -2
- package/dist/web/.next/server/app/api/areas/route.js +1 -1
- package/dist/web/.next/server/app/api/areas/route.js.nft.json +1 -1
- package/dist/web/.next/server/app/api/bridge/[...path]/route.js +1 -1
- package/dist/web/.next/server/app/api/bridge/[...path]/route.js.nft.json +1 -1
- package/dist/web/.next/server/app/api/changelog/route/app-paths-manifest.json +3 -0
- package/dist/web/.next/server/app/api/changelog/route/build-manifest.json +11 -0
- package/dist/web/.next/server/app/api/changelog/route/server-reference-manifest.json +4 -0
- package/dist/web/.next/server/app/api/changelog/route.js +7 -0
- package/dist/web/.next/server/app/api/changelog/route.js.map +5 -0
- package/dist/web/.next/server/app/api/changelog/route.js.nft.json +1 -0
- package/dist/web/.next/server/app/api/changelog/route_client-reference-manifest.js +2 -0
- package/dist/web/.next/server/app/api/cli-assets/assistant/route.js +1 -1
- package/dist/web/.next/server/app/api/cli-assets/assistant/route.js.nft.json +1 -1
- package/dist/web/.next/server/app/api/cli-assets/fix/route.js +1 -1
- package/dist/web/.next/server/app/api/cli-assets/fix/route.js.nft.json +1 -1
- package/dist/web/.next/server/app/api/cli-assets/import/route.js +1 -1
- package/dist/web/.next/server/app/api/cli-assets/import/route.js.nft.json +1 -1
- package/dist/web/.next/server/app/api/cli-assets/route.js +2 -2
- package/dist/web/.next/server/app/api/cli-assets/route.js.nft.json +1 -1
- package/dist/web/.next/server/app/api/cli-assets/store/preview/route.js +1 -1
- package/dist/web/.next/server/app/api/cli-assets/store/preview/route.js.nft.json +1 -1
- package/dist/web/.next/server/app/api/cli-assets/store/route.js +2 -2
- package/dist/web/.next/server/app/api/cli-assets/store/route.js.nft.json +1 -1
- package/dist/web/.next/server/app/api/cli-assets/sync/route.js +1 -1
- package/dist/web/.next/server/app/api/cli-assets/sync/route.js.nft.json +1 -1
- package/dist/web/.next/server/app/api/cli-assets/updates/route.js +2 -2
- package/dist/web/.next/server/app/api/cli-assets/updates/route.js.nft.json +1 -1
- package/dist/web/.next/server/app/api/dashboard/route.js +2 -2
- package/dist/web/.next/server/app/api/dashboard/route.js.nft.json +1 -1
- package/dist/web/.next/server/app/api/events/route.js +1 -1
- package/dist/web/.next/server/app/api/events/route.js.nft.json +1 -1
- package/dist/web/.next/server/app/api/file/route.js +1 -1
- package/dist/web/.next/server/app/api/file/route.js.nft.json +1 -1
- package/dist/web/.next/server/app/api/git-status/route.js +1 -1
- package/dist/web/.next/server/app/api/git-status/route.js.nft.json +1 -1
- package/dist/web/.next/server/app/api/kanban/route.js +1 -1
- package/dist/web/.next/server/app/api/kanban/route.js.nft.json +1 -1
- package/dist/web/.next/server/app/api/kanban/stream/route.js +1 -1
- package/dist/web/.next/server/app/api/kanban/stream/route.js.nft.json +1 -1
- package/dist/web/.next/server/app/api/projects/[id]/route.js +2 -2
- package/dist/web/.next/server/app/api/projects/[id]/route.js.nft.json +1 -1
- package/dist/web/.next/server/app/api/projects/analyze/route.js +1 -1
- package/dist/web/.next/server/app/api/projects/analyze/route.js.nft.json +1 -1
- package/dist/web/.next/server/app/api/projects/reorder/route.js +2 -2
- package/dist/web/.next/server/app/api/projects/reorder/route.js.nft.json +1 -1
- package/dist/web/.next/server/app/api/projects/route.js +2 -2
- package/dist/web/.next/server/app/api/projects/route.js.nft.json +1 -1
- package/dist/web/.next/server/app/api/providers/route.js +1 -1
- package/dist/web/.next/server/app/api/providers/route.js.nft.json +1 -1
- package/dist/web/.next/server/app/api/scheduler/route.js +1 -1
- package/dist/web/.next/server/app/api/scheduler/route.js.nft.json +1 -1
- package/dist/web/.next/server/app/api/search/route.js +1 -1
- package/dist/web/.next/server/app/api/search/route.js.nft.json +1 -1
- package/dist/web/.next/server/app/api/settings/route.js +1 -1
- package/dist/web/.next/server/app/api/settings/route.js.nft.json +1 -1
- package/dist/web/.next/server/app/api/sly-actions/invalidate/route.js +1 -1
- package/dist/web/.next/server/app/api/sly-actions/invalidate/route.js.nft.json +1 -1
- package/dist/web/.next/server/app/api/sly-actions/route.js +1 -1
- package/dist/web/.next/server/app/api/sly-actions/route.js.nft.json +1 -1
- package/dist/web/.next/server/app/api/sly-actions/stream/route.js +1 -1
- package/dist/web/.next/server/app/api/sly-actions/stream/route.js.nft.json +1 -1
- package/dist/web/.next/server/app/api/system-stats/route.js +1 -1
- package/dist/web/.next/server/app/api/system-stats/route.js.nft.json +1 -1
- package/dist/web/.next/server/app/api/terminal-classes/route.js +1 -1
- package/dist/web/.next/server/app/api/terminal-classes/route.js.nft.json +1 -1
- package/dist/web/.next/server/app/api/transcribe/route.js +5 -5
- package/dist/web/.next/server/app/api/transcribe/route.js.nft.json +1 -1
- package/dist/web/.next/server/app/api/version-check/route.js +1 -1
- package/dist/web/.next/server/app/api/version-check/route.js.nft.json +1 -1
- package/dist/web/.next/server/app/page.js +1 -1
- package/dist/web/.next/server/app/page.js.nft.json +1 -1
- package/dist/web/.next/server/app/page_client-reference-manifest.js +1 -1
- package/dist/web/.next/server/app/project/[id]/page.js +2 -2
- package/dist/web/.next/server/app/project/[id]/page.js.nft.json +1 -1
- package/dist/web/.next/server/app/project/[id]/page_client-reference-manifest.js +1 -1
- package/dist/web/.next/server/app-paths-manifest.json +1 -0
- package/dist/web/.next/server/chunks/{[externals]__c6831f39._.js → [externals]__78e522ea._.js} +2 -2
- package/dist/web/.next/server/chunks/{[root-of-the-server]__1ec21ccc._.js → [root-of-the-server]__029203cd._.js} +3 -3
- package/dist/web/.next/server/chunks/{[root-of-the-server]__4297cb97._.js → [root-of-the-server]__0d6d4443._.js} +1 -1
- package/dist/web/.next/server/chunks/[root-of-the-server]__172ad0b1._.js +18 -0
- package/dist/web/.next/server/chunks/[root-of-the-server]__1c5f4ef9._.js +3 -0
- package/dist/web/.next/server/chunks/[root-of-the-server]__1cab11f0._.js +3 -0
- package/dist/web/.next/server/chunks/{[root-of-the-server]__0f69c28a._.js → [root-of-the-server]__1eb3f172._.js} +2 -2
- package/dist/web/.next/server/chunks/[root-of-the-server]__22cba275._.js +3 -0
- package/dist/web/.next/server/chunks/[root-of-the-server]__2543e413._.js +3 -0
- package/dist/web/.next/server/chunks/[root-of-the-server]__2c42a835._.js +3 -0
- package/dist/web/.next/server/chunks/[root-of-the-server]__2ed0ff47._.js +3 -0
- package/dist/web/.next/server/chunks/[root-of-the-server]__35454eea._.js +27 -0
- package/dist/web/.next/server/chunks/[root-of-the-server]__35768b56._.js +3 -0
- package/dist/web/.next/server/chunks/[root-of-the-server]__3880228a._.js +3 -0
- package/dist/web/.next/server/chunks/[root-of-the-server]__42322d88._.js +3 -0
- package/dist/web/.next/server/chunks/{[root-of-the-server]__d0f4efec._.js → [root-of-the-server]__5152eeff._.js} +3 -3
- package/dist/web/.next/server/chunks/[root-of-the-server]__527c7f57._.js +3 -0
- package/dist/web/.next/server/chunks/[root-of-the-server]__5c5dac4b._.js +3 -0
- package/dist/web/.next/server/chunks/[root-of-the-server]__5cb130f2._.js +3 -0
- package/dist/web/.next/server/chunks/[root-of-the-server]__68927e75._.js +3 -0
- package/dist/web/.next/server/chunks/[root-of-the-server]__719517c7._.js +3 -0
- package/dist/web/.next/server/chunks/[root-of-the-server]__73cf49c2._.js +3 -0
- package/dist/web/.next/server/chunks/{[root-of-the-server]__f5dae2ad._.js → [root-of-the-server]__7af4ab09._.js} +1 -1
- package/dist/web/.next/server/chunks/{[root-of-the-server]__4244617a._.js → [root-of-the-server]__7e6860e0._.js} +3 -3
- package/dist/web/.next/server/chunks/[root-of-the-server]__88bf5e22._.js +3 -0
- package/dist/web/.next/server/chunks/{[root-of-the-server]__f97e93fa._.js → [root-of-the-server]__8b4259cb._.js} +3 -3
- package/dist/web/.next/server/chunks/[root-of-the-server]__92f81907._.js +3 -0
- package/dist/web/.next/server/chunks/[root-of-the-server]__967603e9._.js +3 -0
- package/dist/web/.next/server/chunks/[root-of-the-server]__9e4bd28f._.js +3 -0
- package/dist/web/.next/server/chunks/[root-of-the-server]__a259539f._.js +3 -0
- package/dist/web/.next/server/chunks/[root-of-the-server]__ba1d2e56._.js +3 -0
- package/dist/web/.next/server/chunks/[root-of-the-server]__c942d872._.js +3 -0
- package/dist/web/.next/server/chunks/[root-of-the-server]__d7893622._.js +3 -0
- package/dist/web/.next/server/chunks/{[root-of-the-server]__3b9d3e43._.js → [root-of-the-server]__d843611b._.js} +6 -6
- package/dist/web/.next/server/chunks/[root-of-the-server]__f4d2627f._.js +3 -0
- package/dist/web/.next/server/chunks/[root-of-the-server]__f597835d._.js +3 -0
- package/dist/web/.next/server/chunks/{[root-of-the-server]__cf14e306._.js → [root-of-the-server]__fe8b9abd._.js} +1 -1
- package/dist/web/.next/server/chunks/_next-internal_server_app_api_changelog_route_actions_d6e239bf.js +3 -0
- package/dist/web/.next/server/chunks/node_modules_next_dist_esm_build_templates_app-route_18324462.js +1 -1
- package/dist/web/.next/server/chunks/src_677020aa._.js +1 -1
- package/dist/web/.next/server/chunks/src_lib_scheduler_ts_03988e3e._.js +1 -1
- package/dist/web/.next/server/chunks/src_lib_scheduler_ts_7120457c._.js +1 -1
- package/dist/web/.next/server/chunks/ssr/[root-of-the-server]__1f5fc489._.js +4 -3
- package/dist/web/.next/server/chunks/ssr/[root-of-the-server]__43d93717._.js +3 -0
- package/dist/web/.next/server/chunks/ssr/{[root-of-the-server]__077f472c._.js → [root-of-the-server]__6183d28c._.js} +1 -1
- package/dist/web/.next/server/chunks/ssr/[root-of-the-server]__90f82e6d._.js +3 -0
- package/dist/web/.next/server/chunks/ssr/[root-of-the-server]__bcbe4bf2._.js +4 -3
- package/dist/web/.next/server/chunks/ssr/src_components_Dashboard_tsx_efc4dc27._.js +1 -1
- package/dist/web/.next/server/chunks/ssr/src_components_c4135402._.js +1 -1
- package/dist/web/.next/server/chunks/ssr/src_contexts_VoiceContext_tsx_cfba7292._.js +1 -1
- package/dist/web/.next/server/chunks/ssr/src_lib_registry_ts_2fc87c9c._.js +1 -1
- package/dist/web/.next/server/pages/404.html +1 -1
- package/dist/web/.next/server/pages/500.html +2 -2
- package/dist/web/.next/server/server-reference-manifest.js +1 -1
- package/dist/web/.next/server/server-reference-manifest.json +1 -1
- package/dist/web/.next/static/chunks/293449b828207656.css +1 -0
- package/dist/web/.next/static/chunks/{f55f3c8c1a52f80c.js → 3859477038c381ad.js} +1 -1
- package/dist/web/.next/static/chunks/3a5721af09d1c753.js +5 -0
- package/dist/web/.next/static/chunks/{8fb2a99c64580de7.js → 98311243e9a5a0ec.js} +1 -1
- package/dist/web/.next/static/chunks/{b8e0c1aeea4a14bc.js → a47f36b030917d1f.js} +1 -1
- package/dist/web/.next/static/chunks/d60c422421920130.js +5 -0
- package/dist/web/.next/static/chunks/{4049cceee6a49323.js → fa78afe3ceed998b.js} +1 -1
- package/dist/web/src/app/api/changelog/route.ts +45 -0
- package/dist/web/src/app/api/kanban/route.ts +52 -12
- package/dist/web/src/app/api/projects/analyze/route.ts +12 -2
- package/dist/web/src/app/api/projects/route.ts +1 -11
- package/dist/web/src/app/api/providers/route.ts +4 -0
- package/dist/web/src/components/ActivityFeed.tsx +3 -0
- package/dist/web/src/components/BranchTab.tsx +115 -0
- package/dist/web/src/components/ChangelogModal.tsx +234 -0
- package/dist/web/src/components/ClaudeTerminalPanel.tsx +124 -70
- package/dist/web/src/components/Dashboard.tsx +11 -0
- package/dist/web/src/components/GlobalClaudePanel.tsx +6 -0
- package/dist/web/src/components/ProjectKanban.tsx +38 -8
- package/dist/web/src/components/VersionUpdateToast.tsx +6 -4
- package/dist/web/src/components/VoiceControlBar.tsx +1 -1
- package/dist/web/src/lib/paths.ts +14 -0
- package/dist/web/src/lib/scheduler.ts +2 -1
- package/dist/web/src/lib/types.ts +24 -0
- package/dist/web/tsconfig.tsbuildinfo +1 -1
- package/package.json +1 -1
- package/templates/changelog.json +242 -0
- package/templates/kanban-seed.json +1 -1
- package/templates/store/actions/checkpoint.md +1 -1
- package/templates/store/actions/context.md +1 -1
- package/templates/store/actions/create-card.md +1 -1
- package/templates/store/actions/deep-design.md +13 -3
- package/templates/store/actions/design-requirements.md +11 -1
- package/templates/store/actions/explore.md +1 -1
- package/templates/store/actions/onboard.md +2 -4
- package/templates/store/actions/summarize.md +1 -1
- package/templates/store/skills/kanban/SKILL.md +77 -3
- package/templates/tutorial-project/documentation/kanban.json +1 -1
- package/templates/updates/actions/checkpoint.md +1 -1
- package/templates/updates/actions/context.md +1 -1
- package/templates/updates/actions/create-card.md +1 -1
- package/templates/updates/actions/deep-design.md +13 -3
- package/templates/updates/actions/design-requirements.md +11 -1
- package/templates/updates/actions/explore.md +1 -1
- package/templates/updates/actions/onboard.md +2 -4
- package/templates/updates/actions/summarize.md +1 -1
- package/templates/updates/skills/kanban/SKILL.md +77 -3
- package/dist/web/.next/server/chunks/[root-of-the-server]__09aec55a._.js +0 -3
- package/dist/web/.next/server/chunks/[root-of-the-server]__12f6cd6f._.js +0 -3
- package/dist/web/.next/server/chunks/[root-of-the-server]__15fc9266._.js +0 -18
- package/dist/web/.next/server/chunks/[root-of-the-server]__198f01e0._.js +0 -3
- package/dist/web/.next/server/chunks/[root-of-the-server]__279e9bf3._.js +0 -3
- package/dist/web/.next/server/chunks/[root-of-the-server]__2b639eab._.js +0 -3
- package/dist/web/.next/server/chunks/[root-of-the-server]__2d1f0ed9._.js +0 -3
- package/dist/web/.next/server/chunks/[root-of-the-server]__3f239285._.js +0 -3
- package/dist/web/.next/server/chunks/[root-of-the-server]__47dd878e._.js +0 -3
- package/dist/web/.next/server/chunks/[root-of-the-server]__5b8c9374._.js +0 -3
- package/dist/web/.next/server/chunks/[root-of-the-server]__5e08b942._.js +0 -3
- package/dist/web/.next/server/chunks/[root-of-the-server]__6ffce934._.js +0 -3
- package/dist/web/.next/server/chunks/[root-of-the-server]__71bb3374._.js +0 -3
- package/dist/web/.next/server/chunks/[root-of-the-server]__7603305e._.js +0 -3
- package/dist/web/.next/server/chunks/[root-of-the-server]__7c476ad6._.js +0 -3
- package/dist/web/.next/server/chunks/[root-of-the-server]__846ca56f._.js +0 -3
- package/dist/web/.next/server/chunks/[root-of-the-server]__98d88050._.js +0 -3
- package/dist/web/.next/server/chunks/[root-of-the-server]__b273cc05._.js +0 -3
- package/dist/web/.next/server/chunks/[root-of-the-server]__b90bbd70._.js +0 -3
- package/dist/web/.next/server/chunks/[root-of-the-server]__d5272169._.js +0 -3
- package/dist/web/.next/server/chunks/[root-of-the-server]__d56e68cb._.js +0 -3
- package/dist/web/.next/server/chunks/[root-of-the-server]__d6362272._.js +0 -3
- package/dist/web/.next/server/chunks/[root-of-the-server]__de1277ee._.js +0 -27
- package/dist/web/.next/server/chunks/[root-of-the-server]__e88a19d2._.js +0 -3
- package/dist/web/.next/server/chunks/[root-of-the-server]__f3e501b6._.js +0 -3
- package/dist/web/.next/server/chunks/[root-of-the-server]__f59af2bc._.js +0 -3
- package/dist/web/.next/server/chunks/ssr/[root-of-the-server]__9ac6ea25._.js +0 -3
- package/dist/web/.next/server/chunks/ssr/[root-of-the-server]__dfe2728c._.js +0 -3
- package/dist/web/.next/static/chunks/3d5195b57fc05540.js +0 -4
- package/dist/web/.next/static/chunks/59fb302a5bfd2dc0.js +0 -4
- package/dist/web/.next/static/chunks/747f5e5f9dcf2621.css +0 -1
- /package/dist/web/.next/static/{0sPAbk-Qw-InZ0rdHjHnC → aN-jqftQVvSm0qVskLybH}/_buildManifest.js +0 -0
- /package/dist/web/.next/static/{0sPAbk-Qw-InZ0rdHjHnC → aN-jqftQVvSm0qVskLybH}/_clientMiddlewareManifest.json +0 -0
- /package/dist/web/.next/static/{0sPAbk-Qw-InZ0rdHjHnC → aN-jqftQVvSm0qVskLybH}/_ssgManifest.js +0 -0
|
@@ -13,11 +13,16 @@ interface ProviderConfig {
|
|
|
13
13
|
command: string;
|
|
14
14
|
permissions: { flag: string; label: string; default: boolean };
|
|
15
15
|
resume: { supported: boolean };
|
|
16
|
+
model?: {
|
|
17
|
+
flag: string;
|
|
18
|
+
available: Array<{ id: string; label: string; description?: string }>;
|
|
19
|
+
};
|
|
16
20
|
}
|
|
17
21
|
|
|
18
22
|
interface ProviderDefault {
|
|
19
23
|
provider: string;
|
|
20
24
|
skipPermissions: boolean;
|
|
25
|
+
model?: string;
|
|
21
26
|
}
|
|
22
27
|
|
|
23
28
|
interface ProvidersData {
|
|
@@ -45,6 +50,7 @@ interface SessionInfo {
|
|
|
45
50
|
claudeSessionId?: string | null;
|
|
46
51
|
provider?: string;
|
|
47
52
|
skipPermissions?: boolean;
|
|
53
|
+
model?: string;
|
|
48
54
|
}
|
|
49
55
|
|
|
50
56
|
export interface TerminalContext {
|
|
@@ -145,6 +151,13 @@ export function ClaudeTerminalPanel({
|
|
|
145
151
|
// Spawn error toast — shown when session creation fails (e.g. posix_spawnp failed)
|
|
146
152
|
const [spawnError, setSpawnError] = useState<string | null>(null);
|
|
147
153
|
|
|
154
|
+
// Model selection state
|
|
155
|
+
const [selectedModel, setSelectedModel] = useState(''); // '' = Default (no flag)
|
|
156
|
+
const prevProviderRef = useRef(selectedProvider);
|
|
157
|
+
const userSelectedModelRef = useRef(false);
|
|
158
|
+
const sessionInfoRef = useRef(sessionInfo);
|
|
159
|
+
sessionInfoRef.current = sessionInfo;
|
|
160
|
+
|
|
148
161
|
// Instruction file check state
|
|
149
162
|
const [instructionFileCheck, setInstructionFileCheck] = useState<{ needed: boolean; targetFile?: string; copySource?: string } | null>(null);
|
|
150
163
|
const [createInstructionFile, setCreateInstructionFile] = useState(true);
|
|
@@ -177,15 +190,53 @@ export function ClaudeTerminalPanel({
|
|
|
177
190
|
setSelectedProvider(def.provider);
|
|
178
191
|
}
|
|
179
192
|
setSkipPermissions(def.skipPermissions);
|
|
193
|
+
if (def.model) {
|
|
194
|
+
setSelectedModel(def.model);
|
|
195
|
+
}
|
|
180
196
|
}
|
|
181
197
|
}
|
|
182
198
|
})
|
|
183
199
|
.catch(() => { /* providers.json not available, use defaults */ });
|
|
184
200
|
}, [stage]);
|
|
185
201
|
|
|
202
|
+
// Pre-fill model when provider changes
|
|
203
|
+
useEffect(() => {
|
|
204
|
+
if (!providersData) return;
|
|
205
|
+
const providerChanged = prevProviderRef.current !== selectedProvider;
|
|
206
|
+
prevProviderRef.current = selectedProvider;
|
|
207
|
+
if (!providerChanged && userSelectedModelRef.current) return;
|
|
208
|
+
userSelectedModelRef.current = false;
|
|
209
|
+
// Priority: last-used from session > stage default > Default
|
|
210
|
+
const si = sessionInfoRef.current;
|
|
211
|
+
if (si?.model && si.provider === selectedProvider) {
|
|
212
|
+
const available = providersData.providers[selectedProvider]?.model?.available;
|
|
213
|
+
if (available?.some(m => m.id === si.model)) {
|
|
214
|
+
setSelectedModel(si.model);
|
|
215
|
+
return;
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
const stageDefault = stage ? providersData.defaults.stages[stage] : null;
|
|
219
|
+
const def = stageDefault || providersData.defaults.global;
|
|
220
|
+
if (def?.model && def.provider === selectedProvider) {
|
|
221
|
+
const available = providersData.providers[selectedProvider]?.model?.available;
|
|
222
|
+
if (available?.some(m => m.id === def.model)) {
|
|
223
|
+
setSelectedModel(def.model);
|
|
224
|
+
return;
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
setSelectedModel('');
|
|
228
|
+
}, [selectedProvider, providersData, stage]);
|
|
229
|
+
|
|
186
230
|
// Persist provider default to /api/providers (fire-and-forget)
|
|
187
231
|
const saveProviderDefault = useCallback((provider: string, skip: boolean) => {
|
|
188
|
-
|
|
232
|
+
// Preserve any existing model field in the stage default (stage model defaults are intentional config)
|
|
233
|
+
const existingDefault = stage
|
|
234
|
+
? providersData?.defaults.stages[stage]
|
|
235
|
+
: providersData?.defaults.global;
|
|
236
|
+
const defaultVal: Record<string, unknown> = { provider, skipPermissions: skip };
|
|
237
|
+
if (existingDefault?.model && existingDefault.provider === provider) {
|
|
238
|
+
defaultVal.model = existingDefault.model;
|
|
239
|
+
}
|
|
189
240
|
const defaults = stage
|
|
190
241
|
? { stages: { [stage]: defaultVal } }
|
|
191
242
|
: { global: defaultVal };
|
|
@@ -194,7 +245,7 @@ export function ClaudeTerminalPanel({
|
|
|
194
245
|
headers: { 'Content-Type': 'application/json' },
|
|
195
246
|
body: JSON.stringify({ defaults }),
|
|
196
247
|
}).catch(() => { /* preference save — ignore errors */ });
|
|
197
|
-
}, [stage]);
|
|
248
|
+
}, [stage, providersData]);
|
|
198
249
|
|
|
199
250
|
const isRunning = sessionInfo?.status === 'running' || sessionInfo?.status === 'detached';
|
|
200
251
|
const hasHistory = sessionInfo?.hasHistory;
|
|
@@ -288,6 +339,74 @@ export function ClaudeTerminalPanel({
|
|
|
288
339
|
</div>
|
|
289
340
|
) : null;
|
|
290
341
|
|
|
342
|
+
// Helper to render model label from provider config
|
|
343
|
+
const getModelLabel = (providerId: string, modelId?: string) => {
|
|
344
|
+
if (!modelId || !providersData) return null;
|
|
345
|
+
return providersData.providers[providerId]?.model?.available?.find(m => m.id === modelId)?.label || modelId;
|
|
346
|
+
};
|
|
347
|
+
|
|
348
|
+
// Shared provider selector (eliminates duplication between resume and fresh-start screens)
|
|
349
|
+
const renderProviderSelector = (options?: { showModel?: boolean }) => {
|
|
350
|
+
if (!providersData || Object.keys(providersData.providers).length <= 1) return null;
|
|
351
|
+
const currentProvider = providersData.providers[selectedProvider];
|
|
352
|
+
const models = currentProvider?.model?.available;
|
|
353
|
+
const showModel = options?.showModel !== false;
|
|
354
|
+
return (
|
|
355
|
+
<div className="flex flex-col items-center gap-2 mt-3 pt-3 border-t border-void-700/50">
|
|
356
|
+
<div className="flex gap-1">
|
|
357
|
+
{Object.values(providersData.providers).map(p => (
|
|
358
|
+
<button
|
|
359
|
+
key={p.id}
|
|
360
|
+
onClick={() => {
|
|
361
|
+
setSelectedProvider(p.id);
|
|
362
|
+
saveProviderDefault(p.id, skipPermissions);
|
|
363
|
+
onProviderChange?.(p.id);
|
|
364
|
+
}}
|
|
365
|
+
className={`rounded-md px-3 py-1 text-xs font-medium transition-all ${
|
|
366
|
+
selectedProvider === p.id
|
|
367
|
+
? 'border border-neon-blue-400/60 bg-neon-blue-400/15 text-neon-blue-400 shadow-[0_0_8px_rgba(0,191,255,0.2)]'
|
|
368
|
+
: 'border border-void-600 bg-void-800 text-void-400 hover:border-void-500 hover:text-void-300'
|
|
369
|
+
}`}
|
|
370
|
+
>
|
|
371
|
+
{p.displayName}
|
|
372
|
+
</button>
|
|
373
|
+
))}
|
|
374
|
+
</div>
|
|
375
|
+
<div className="flex items-center gap-3">
|
|
376
|
+
{showModel && models && models.length > 0 && (
|
|
377
|
+
<div className="flex items-center gap-1.5">
|
|
378
|
+
<span className="text-xs text-void-500">Model</span>
|
|
379
|
+
<select
|
|
380
|
+
value={selectedModel}
|
|
381
|
+
onChange={(e) => { setSelectedModel(e.target.value); userSelectedModelRef.current = true; }}
|
|
382
|
+
className={`max-w-[140px] truncate rounded border px-2 py-1 text-xs font-medium transition-all ${
|
|
383
|
+
selectedModel
|
|
384
|
+
? 'border-neon-blue-400/40 bg-neon-blue-400/10 text-neon-blue-400'
|
|
385
|
+
: 'border-void-600 bg-void-800 text-void-400'
|
|
386
|
+
}`}
|
|
387
|
+
>
|
|
388
|
+
<option value="">Default</option>
|
|
389
|
+
{models.map(m => (
|
|
390
|
+
<option key={m.id} value={m.id}>{m.label}</option>
|
|
391
|
+
))}
|
|
392
|
+
</select>
|
|
393
|
+
</div>
|
|
394
|
+
)}
|
|
395
|
+
<label className="flex items-center gap-1.5 text-xs text-void-500 cursor-pointer">
|
|
396
|
+
<input
|
|
397
|
+
type="checkbox"
|
|
398
|
+
checked={skipPermissions}
|
|
399
|
+
onChange={(e) => { setSkipPermissions(e.target.checked); saveProviderDefault(selectedProvider, e.target.checked); }}
|
|
400
|
+
className="rounded border-void-600"
|
|
401
|
+
/>
|
|
402
|
+
{providersData.providers[selectedProvider]?.permissions.label || 'Skip permissions'}
|
|
403
|
+
</label>
|
|
404
|
+
</div>
|
|
405
|
+
{instructionFileWarning}
|
|
406
|
+
</div>
|
|
407
|
+
);
|
|
408
|
+
};
|
|
409
|
+
|
|
291
410
|
// Derive startup and toolbar lists from placement
|
|
292
411
|
const startupActions = actions.filter(a => a.placement === 'startup' || a.placement === 'both');
|
|
293
412
|
const toolbarActions = actions.filter(a => a.placement === 'toolbar' || a.placement === 'both');
|
|
@@ -317,6 +436,7 @@ export function ClaudeTerminalPanel({
|
|
|
317
436
|
cwd,
|
|
318
437
|
fresh: !hasHistory,
|
|
319
438
|
prompt,
|
|
439
|
+
model: selectedModel || undefined,
|
|
320
440
|
createInstructionFile: instructionFileCheck?.needed ? createInstructionFile : undefined,
|
|
321
441
|
}),
|
|
322
442
|
});
|
|
@@ -619,40 +739,7 @@ export function ClaudeTerminalPanel({
|
|
|
619
739
|
Custom...
|
|
620
740
|
</button>
|
|
621
741
|
</div>
|
|
622
|
-
{
|
|
623
|
-
{providersData && Object.keys(providersData.providers).length > 1 && (
|
|
624
|
-
<div className="flex flex-col items-center gap-2 mt-3 pt-3 border-t border-void-700/50">
|
|
625
|
-
<div className="flex gap-1">
|
|
626
|
-
{Object.values(providersData.providers).map(p => (
|
|
627
|
-
<button
|
|
628
|
-
key={p.id}
|
|
629
|
-
onClick={() => {
|
|
630
|
-
setSelectedProvider(p.id);
|
|
631
|
-
saveProviderDefault(p.id, skipPermissions);
|
|
632
|
-
onProviderChange?.(p.id);
|
|
633
|
-
}}
|
|
634
|
-
className={`rounded-md px-3 py-1 text-xs font-medium transition-all ${
|
|
635
|
-
selectedProvider === p.id
|
|
636
|
-
? 'border border-neon-blue-400/60 bg-neon-blue-400/15 text-neon-blue-400 shadow-[0_0_8px_rgba(0,191,255,0.2)]'
|
|
637
|
-
: 'border border-void-600 bg-void-800 text-void-400 hover:border-void-500 hover:text-void-300'
|
|
638
|
-
}`}
|
|
639
|
-
>
|
|
640
|
-
{p.displayName}
|
|
641
|
-
</button>
|
|
642
|
-
))}
|
|
643
|
-
</div>
|
|
644
|
-
<label className="flex items-center gap-1.5 text-xs text-void-500 cursor-pointer">
|
|
645
|
-
<input
|
|
646
|
-
type="checkbox"
|
|
647
|
-
checked={skipPermissions}
|
|
648
|
-
onChange={(e) => { setSkipPermissions(e.target.checked); saveProviderDefault(selectedProvider, e.target.checked); }}
|
|
649
|
-
className="rounded border-void-600"
|
|
650
|
-
/>
|
|
651
|
-
{providersData.providers[selectedProvider]?.permissions.label || 'Skip permissions'}
|
|
652
|
-
</label>
|
|
653
|
-
{instructionFileWarning}
|
|
654
|
-
</div>
|
|
655
|
-
)}
|
|
742
|
+
{renderProviderSelector({ showModel: false })}
|
|
656
743
|
</>
|
|
657
744
|
) : (
|
|
658
745
|
<>
|
|
@@ -684,40 +771,7 @@ export function ClaudeTerminalPanel({
|
|
|
684
771
|
>
|
|
685
772
|
Start without prompt
|
|
686
773
|
</button>
|
|
687
|
-
{
|
|
688
|
-
{providersData && Object.keys(providersData.providers).length > 1 && (
|
|
689
|
-
<div className="flex flex-col items-center gap-2 mt-3 pt-3 border-t border-void-700/50">
|
|
690
|
-
<div className="flex gap-1">
|
|
691
|
-
{Object.values(providersData.providers).map(p => (
|
|
692
|
-
<button
|
|
693
|
-
key={p.id}
|
|
694
|
-
onClick={() => {
|
|
695
|
-
setSelectedProvider(p.id);
|
|
696
|
-
saveProviderDefault(p.id, skipPermissions);
|
|
697
|
-
onProviderChange?.(p.id);
|
|
698
|
-
}}
|
|
699
|
-
className={`rounded-md px-3 py-1 text-xs font-medium transition-all ${
|
|
700
|
-
selectedProvider === p.id
|
|
701
|
-
? 'border border-neon-blue-400/60 bg-neon-blue-400/15 text-neon-blue-400 shadow-[0_0_8px_rgba(0,191,255,0.2)]'
|
|
702
|
-
: 'border border-void-600 bg-void-800 text-void-400 hover:border-void-500 hover:text-void-300'
|
|
703
|
-
}`}
|
|
704
|
-
>
|
|
705
|
-
{p.displayName}
|
|
706
|
-
</button>
|
|
707
|
-
))}
|
|
708
|
-
</div>
|
|
709
|
-
<label className="flex items-center gap-1.5 text-xs text-void-500 cursor-pointer">
|
|
710
|
-
<input
|
|
711
|
-
type="checkbox"
|
|
712
|
-
checked={skipPermissions}
|
|
713
|
-
onChange={(e) => { setSkipPermissions(e.target.checked); saveProviderDefault(selectedProvider, e.target.checked); }}
|
|
714
|
-
className="rounded border-void-600"
|
|
715
|
-
/>
|
|
716
|
-
{providersData.providers[selectedProvider]?.permissions.label || 'Skip permissions'}
|
|
717
|
-
</label>
|
|
718
|
-
{instructionFileWarning}
|
|
719
|
-
</div>
|
|
720
|
-
)}
|
|
774
|
+
{renderProviderSelector()}
|
|
721
775
|
</>
|
|
722
776
|
)}
|
|
723
777
|
</div>
|
|
@@ -15,6 +15,7 @@ import { CliAssetsTab } from './CliAssetsTab';
|
|
|
15
15
|
import { ActivityFeed } from './ActivityFeed';
|
|
16
16
|
import { ThemeToggle } from './ThemeToggle';
|
|
17
17
|
import { VersionUpdateToast } from './VersionUpdateToast';
|
|
18
|
+
import { ChangelogModal } from './ChangelogModal';
|
|
18
19
|
import { useVoice } from '@/contexts/VoiceContext';
|
|
19
20
|
|
|
20
21
|
interface DashboardProps {
|
|
@@ -35,6 +36,7 @@ export function Dashboard({ data: initialData }: DashboardProps) {
|
|
|
35
36
|
const [dropIndex, setDropIndex] = useState<number | null>(null);
|
|
36
37
|
const gridRef = useRef<HTMLDivElement>(null);
|
|
37
38
|
const [slycodeVersion, setSlycodeVersion] = useState<string | null>(null);
|
|
39
|
+
const [showChangelog, setShowChangelog] = useState(false);
|
|
38
40
|
|
|
39
41
|
// Fetch SlyCode version on mount
|
|
40
42
|
useEffect(() => {
|
|
@@ -472,6 +474,13 @@ export function Dashboard({ data: initialData }: DashboardProps) {
|
|
|
472
474
|
<p className="mt-2 text-xs text-void-500 dark:text-void-400">
|
|
473
475
|
© 2026 SlyCode (<a href="https://slycode.ai" target="_blank" rel="noopener noreferrer" className="hover:text-neon-blue-500 dark:hover:text-neon-blue-400 transition-colors">slycode.ai</a>). All rights reserved.
|
|
474
476
|
{slycodeVersion && <span className="ml-2 text-void-400 dark:text-void-500">v{slycodeVersion}</span>}
|
|
477
|
+
<button
|
|
478
|
+
type="button"
|
|
479
|
+
onClick={() => setShowChangelog(true)}
|
|
480
|
+
className="ml-2 text-void-400 hover:text-neon-blue-500 dark:text-void-500 dark:hover:text-neon-blue-400 transition-colors underline-offset-2 hover:underline"
|
|
481
|
+
>
|
|
482
|
+
Changelog
|
|
483
|
+
</button>
|
|
475
484
|
</p>
|
|
476
485
|
</footer>
|
|
477
486
|
</main>
|
|
@@ -482,6 +491,8 @@ export function Dashboard({ data: initialData }: DashboardProps) {
|
|
|
482
491
|
onCreated={refreshData}
|
|
483
492
|
/>
|
|
484
493
|
|
|
494
|
+
{showChangelog && <ChangelogModal onClose={() => setShowChangelog(false)} />}
|
|
495
|
+
|
|
485
496
|
{/* Global Terminal */}
|
|
486
497
|
<GlobalClaudePanel
|
|
487
498
|
sessionNameOverride="global:global"
|
|
@@ -8,6 +8,7 @@ import {
|
|
|
8
8
|
import { useSlyActionsConfig } from '@/hooks/useSlyActionsConfig';
|
|
9
9
|
import { onTerminalPrompt } from '@/lib/terminal-events';
|
|
10
10
|
import { ClaudeTerminalPanel, type TerminalContext } from './ClaudeTerminalPanel';
|
|
11
|
+
import { BranchTab } from './BranchTab';
|
|
11
12
|
import { useVoice } from '@/contexts/VoiceContext';
|
|
12
13
|
|
|
13
14
|
interface SessionInfo {
|
|
@@ -264,6 +265,11 @@ export function GlobalClaudePanel({
|
|
|
264
265
|
/>
|
|
265
266
|
</div>
|
|
266
267
|
)}
|
|
268
|
+
|
|
269
|
+
{/* Git branch tab - positioned to the left of the panel */}
|
|
270
|
+
{cwd && (
|
|
271
|
+
<BranchTab projectPath={cwd} isTerminalExpanded={isExpanded} />
|
|
272
|
+
)}
|
|
267
273
|
</div>
|
|
268
274
|
);
|
|
269
275
|
}
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
import { useState, useEffect, useRef, useCallback, useMemo } from 'react';
|
|
4
4
|
import { useSearchParams, useRouter, usePathname } from 'next/navigation';
|
|
5
|
-
import type { ProjectWithBacklog, KanbanCard, KanbanStage, KanbanStages, BridgeStats, Priority } from '@/lib/types';
|
|
5
|
+
import type { ProjectWithBacklog, KanbanCard, KanbanStage, KanbanStages, BridgeStats, Priority, ChangedCard, CardChangeType } from '@/lib/types';
|
|
6
6
|
import { connectionManager } from '@/lib/connection-manager';
|
|
7
7
|
import { tabSync } from '@/lib/tab-sync';
|
|
8
8
|
import { usePolling } from '@/hooks/usePolling';
|
|
@@ -85,6 +85,8 @@ export function ProjectKanban({ project, projectPath, showArchived = false, show
|
|
|
85
85
|
const [activeCards, setActiveCards] = useState<Set<string>>(new Set());
|
|
86
86
|
const prevActiveCardsRef = useRef<Set<string>>(new Set());
|
|
87
87
|
const consumedCardParamRef = useRef<string | null>(null);
|
|
88
|
+
const editedCardIdsRef = useRef<Set<string>>(new Set());
|
|
89
|
+
const movedCardIdsRef = useRef<Set<string>>(new Set());
|
|
88
90
|
|
|
89
91
|
// Context menu state
|
|
90
92
|
const [contextMenu, setContextMenu] = useState<{ position: { x: number; y: number }; card: KanbanCard; stage: KanbanStage } | null>(null);
|
|
@@ -376,8 +378,8 @@ export function ProjectKanban({ project, projectPath, showArchived = false, show
|
|
|
376
378
|
setSaveStatus('saving');
|
|
377
379
|
isSavingRef.current = true;
|
|
378
380
|
try {
|
|
379
|
-
// Compute which cards actually changed vs the clean baseline
|
|
380
|
-
const
|
|
381
|
+
// Compute which cards actually changed vs the clean baseline, with typed changeset
|
|
382
|
+
const changedCards: ChangedCard[] = [];
|
|
381
383
|
const baselineCards = new Map<string, string>();
|
|
382
384
|
for (const stage of STAGE_ORDER) {
|
|
383
385
|
for (const card of cleanBaselineRef.current[stage] || []) {
|
|
@@ -389,29 +391,51 @@ export function ProjectKanban({ project, projectPath, showArchived = false, show
|
|
|
389
391
|
const baselineKey = baselineCards.get(card.id);
|
|
390
392
|
const currentKey = JSON.stringify(card) + '|' + stage;
|
|
391
393
|
if (baselineKey !== currentKey) {
|
|
392
|
-
|
|
394
|
+
if (editedCardIdsRef.current.has(card.id)) {
|
|
395
|
+
changedCards.push({ id: card.id, type: 'edit' }); // Edit wins over move
|
|
396
|
+
} else if (movedCardIdsRef.current.has(card.id)) {
|
|
397
|
+
changedCards.push({ id: card.id, type: 'move' });
|
|
398
|
+
}
|
|
399
|
+
// Untracked divergence (SSE timing, connection issues, normalizeOrder drift)
|
|
400
|
+
// — skip it. The server merge preserves disk truth for cards not in changedCards.
|
|
393
401
|
}
|
|
394
402
|
baselineCards.delete(card.id);
|
|
395
403
|
}
|
|
396
404
|
}
|
|
397
405
|
// Cards in baseline but not in current = deleted
|
|
398
406
|
for (const deletedId of baselineCards.keys()) {
|
|
399
|
-
|
|
407
|
+
changedCards.push({ id: deletedId, type: 'delete' });
|
|
400
408
|
}
|
|
401
409
|
|
|
410
|
+
// Clear tracking refs after building payload
|
|
411
|
+
editedCardIdsRef.current.clear();
|
|
412
|
+
movedCardIdsRef.current.clear();
|
|
413
|
+
|
|
402
414
|
const res = await fetch('/api/kanban', {
|
|
403
415
|
method: 'POST',
|
|
404
416
|
headers: { 'Content-Type': 'application/json' },
|
|
405
|
-
body: JSON.stringify({ projectId: project.id, stages: stagesToSave,
|
|
417
|
+
body: JSON.stringify({ projectId: project.id, stages: stagesToSave, changedCards }),
|
|
406
418
|
});
|
|
407
419
|
if (res.ok) {
|
|
408
420
|
const data = await res.json();
|
|
409
421
|
lastSaveTimestampRef.current = data.last_updated;
|
|
410
|
-
|
|
422
|
+
// Use server's merged+normalized stages as baseline (eliminates normalizeOrder drift)
|
|
423
|
+
const serverStages = data.stages;
|
|
424
|
+
if (serverStages) {
|
|
425
|
+
cleanBaselineRef.current = serverStages;
|
|
426
|
+
// Sync React state with server truth if no new user edits happened during save.
|
|
427
|
+
// Without this, baseline and stages diverge — cards the user never touched appear
|
|
428
|
+
// "changed" in the next save cycle and get reverted to stale frontend positions.
|
|
429
|
+
if (stagesEqual(stagesRef.current, stagesToSave)) {
|
|
430
|
+
setStages(serverStages);
|
|
431
|
+
}
|
|
432
|
+
} else {
|
|
433
|
+
cleanBaselineRef.current = stagesToSave;
|
|
434
|
+
}
|
|
411
435
|
// Only clear dirty if stages haven't changed during the save.
|
|
412
436
|
// If the user made edits while the save was in flight, stay dirty
|
|
413
437
|
// so SSE/polling won't overwrite their pending changes.
|
|
414
|
-
isDirtyRef.current = !stagesEqual(stagesRef.current,
|
|
438
|
+
isDirtyRef.current = !stagesEqual(stagesRef.current, cleanBaselineRef.current);
|
|
415
439
|
setSaveStatus('saved');
|
|
416
440
|
// Notify other tabs immediately
|
|
417
441
|
tabSync.broadcast('kanban-update', project.id);
|
|
@@ -544,6 +568,8 @@ export function ProjectKanban({ project, projectPath, showArchived = false, show
|
|
|
544
568
|
|
|
545
569
|
if (!selectedStage) return;
|
|
546
570
|
|
|
571
|
+
editedCardIdsRef.current.add(updatedCard.id);
|
|
572
|
+
|
|
547
573
|
// Update stages - selectedCard will be automatically derived from the updated stages
|
|
548
574
|
setStages((prev) => ({
|
|
549
575
|
...prev,
|
|
@@ -577,6 +603,7 @@ export function ProjectKanban({ project, projectPath, showArchived = false, show
|
|
|
577
603
|
};
|
|
578
604
|
|
|
579
605
|
const handleMoveCard = (cardId: string, newStage: KanbanStage, insertIndex?: number) => {
|
|
606
|
+
movedCardIdsRef.current.add(cardId);
|
|
580
607
|
setStages((prev) => {
|
|
581
608
|
// Find which stage the card is currently in
|
|
582
609
|
let sourceStage: KanbanStage | null = null;
|
|
@@ -695,6 +722,7 @@ export function ProjectKanban({ project, projectPath, showArchived = false, show
|
|
|
695
722
|
checked: p === card.priority,
|
|
696
723
|
disabled: p === card.priority,
|
|
697
724
|
onClick: () => {
|
|
725
|
+
editedCardIdsRef.current.add(card.id);
|
|
698
726
|
setStages((prev) => ({
|
|
699
727
|
...prev,
|
|
700
728
|
[stage]: prev[stage].map((c) =>
|
|
@@ -731,6 +759,7 @@ export function ProjectKanban({ project, projectPath, showArchived = false, show
|
|
|
731
759
|
disabled: !!card.automation,
|
|
732
760
|
onClick: () => {
|
|
733
761
|
if (card.automation) return;
|
|
762
|
+
editedCardIdsRef.current.add(card.id);
|
|
734
763
|
setStages((prev) => ({
|
|
735
764
|
...prev,
|
|
736
765
|
[stage]: prev[stage].map((c) =>
|
|
@@ -767,6 +796,7 @@ export function ProjectKanban({ project, projectPath, showArchived = false, show
|
|
|
767
796
|
checked: p === card.priority,
|
|
768
797
|
disabled: p === card.priority,
|
|
769
798
|
onClick: () => {
|
|
799
|
+
editedCardIdsRef.current.add(card.id);
|
|
770
800
|
setStages((prev) => ({
|
|
771
801
|
...prev,
|
|
772
802
|
[stage]: prev[stage].map((c) =>
|
|
@@ -53,12 +53,14 @@ export function VersionUpdateToast() {
|
|
|
53
53
|
/>
|
|
54
54
|
<span className="text-sm text-void-700 dark:text-void-300">
|
|
55
55
|
SlyCode <span className="font-medium text-neon-blue-500 dark:text-neon-blue-400">v{info.latest}</span> available
|
|
56
|
-
<span className="text-void-500 dark:text-void-400"> (current: v{info.current})</span>
|
|
57
56
|
</span>
|
|
58
57
|
</div>
|
|
59
|
-
<
|
|
60
|
-
|
|
61
|
-
|
|
58
|
+
<div className="flex items-center gap-1.5">
|
|
59
|
+
<span className="text-xs text-void-500 dark:text-void-400">run in terminal:</span>
|
|
60
|
+
<code className="rounded bg-void-100 px-1.5 py-0.5 text-xs text-void-600 dark:bg-void-800 dark:text-void-400">
|
|
61
|
+
slycode update
|
|
62
|
+
</code>
|
|
63
|
+
</div>
|
|
62
64
|
<button
|
|
63
65
|
onClick={handleDismiss}
|
|
64
66
|
className="ml-1 rounded p-0.5 text-void-400 transition-colors hover:bg-void-200 hover:text-void-600 dark:text-void-500 dark:hover:bg-void-800 dark:hover:text-void-300"
|
|
@@ -45,7 +45,7 @@ export function VoiceControlBar({
|
|
|
45
45
|
onClick={onRecord}
|
|
46
46
|
disabled={disabled}
|
|
47
47
|
className="rounded-md border border-void-400/30 bg-void-200/50 p-1.5 text-void-500 transition-all hover:border-red-400/40 hover:bg-red-400/10 hover:text-red-400 disabled:opacity-50 dark:border-void-500/25 dark:bg-void-700/50 dark:text-void-400 dark:hover:border-red-400/40 dark:hover:bg-red-400/10 dark:hover:text-red-400"
|
|
48
|
-
title="Start recording
|
|
48
|
+
title="Start recording [Ctrl+.]"
|
|
49
49
|
>
|
|
50
50
|
<svg className="h-4 w-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
51
51
|
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M19 11a7 7 0 01-7 7m0 0a7 7 0 01-7-7m7 7v4m0 0H8m4 0h4m-4-8a3 3 0 01-3-3V5a3 3 0 116 0v6a3 3 0 01-3 3z" />
|
|
@@ -7,6 +7,20 @@
|
|
|
7
7
|
|
|
8
8
|
import path from 'path';
|
|
9
9
|
import fs from 'fs';
|
|
10
|
+
import os from 'os';
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Expand tilde (~) in a path to the user's home directory.
|
|
14
|
+
* Also normalizes Unicode tildes (U+02DC, U+FF5E) that Mac browsers can produce.
|
|
15
|
+
*/
|
|
16
|
+
export function expandTilde(p: string): string {
|
|
17
|
+
// Normalize Unicode tildes (U+02DC small tilde, U+FF5E fullwidth tilde) to ASCII
|
|
18
|
+
p = p.replace(/^[\u02dc\uff5e]/, '~');
|
|
19
|
+
if (p.startsWith('~/') || p === '~') {
|
|
20
|
+
return p.replace(/^~/, os.homedir());
|
|
21
|
+
}
|
|
22
|
+
return p;
|
|
23
|
+
}
|
|
10
24
|
|
|
11
25
|
/**
|
|
12
26
|
* Resolve the SlyCode root directory (workspace).
|
|
@@ -666,7 +666,8 @@ async function checkAutomations(): Promise<void> {
|
|
|
666
666
|
result.error.includes('Session create failed') ||
|
|
667
667
|
result.error.includes('Session stopped') ||
|
|
668
668
|
result.error.includes('Input failed') ||
|
|
669
|
-
result.error.includes('No automation config')
|
|
669
|
+
result.error.includes('No automation config') ||
|
|
670
|
+
result.error.includes('No activity detected')
|
|
670
671
|
);
|
|
671
672
|
if (isHardFailure) {
|
|
672
673
|
await sendErrorNotification(card.title, result.error || 'Unknown error', result.sessionName);
|
|
@@ -128,6 +128,13 @@ export interface KanbanStages {
|
|
|
128
128
|
done: KanbanCard[];
|
|
129
129
|
}
|
|
130
130
|
|
|
131
|
+
export type CardChangeType = 'move' | 'edit' | 'create' | 'delete';
|
|
132
|
+
|
|
133
|
+
export interface ChangedCard {
|
|
134
|
+
id: string;
|
|
135
|
+
type: CardChangeType;
|
|
136
|
+
}
|
|
137
|
+
|
|
131
138
|
export interface KanbanBoard {
|
|
132
139
|
project_id: string;
|
|
133
140
|
stages: KanbanStages;
|
|
@@ -163,6 +170,23 @@ export interface FeatureEntry {
|
|
|
163
170
|
projectId?: string;
|
|
164
171
|
}
|
|
165
172
|
|
|
173
|
+
// ============================================================================
|
|
174
|
+
// Changelog Types
|
|
175
|
+
// ============================================================================
|
|
176
|
+
|
|
177
|
+
export type ChangelogChangeType = 'feature' | 'bugfix' | 'improvement' | 'chore';
|
|
178
|
+
|
|
179
|
+
export interface ChangelogChange {
|
|
180
|
+
type: ChangelogChangeType;
|
|
181
|
+
description: string;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
export interface ChangelogVersion {
|
|
185
|
+
version: string;
|
|
186
|
+
date: string; // YYYY-MM-DD
|
|
187
|
+
changes: ChangelogChange[];
|
|
188
|
+
}
|
|
189
|
+
|
|
166
190
|
// ============================================================================
|
|
167
191
|
// Questionnaire Types (per design doc section 3.3)
|
|
168
192
|
// ============================================================================
|