@jiggai/kitchen 0.3.33 → 0.3.48
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/.next/BUILD_ID +1 -1
- package/.next/app-path-routes-manifest.json +4 -0
- package/.next/build-manifest.json +5 -5
- package/.next/prerender-manifest.json +3 -3
- package/.next/required-server-files.js +4 -4
- package/.next/required-server-files.json +4 -4
- package/.next/routes-manifest.json +24 -0
- package/.next/server/app/_global-error/page/build-manifest.json +3 -3
- package/.next/server/app/_global-error/page.js +2 -2
- package/.next/server/app/_global-error/page.js.nft.json +1 -1
- package/.next/server/app/_global-error.html +2 -2
- package/.next/server/app/_global-error.rsc +1 -1
- package/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +1 -1
- package/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
- package/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
- package/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
- package/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
- package/.next/server/app/_not-found/page/build-manifest.json +3 -3
- package/.next/server/app/_not-found/page.js +2 -2
- package/.next/server/app/_not-found/page.js.nft.json +1 -1
- package/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
- package/.next/server/app/_not-found.html +1 -1
- package/.next/server/app/_not-found.rsc +5 -5
- package/.next/server/app/_not-found.segments/_full.segment.rsc +5 -5
- package/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
- package/.next/server/app/_not-found.segments/_index.segment.rsc +3 -3
- package/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
- package/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
- package/.next/server/app/_not-found.segments/_tree.segment.rsc +2 -2
- package/.next/server/app/agents/[agentId]/page/build-manifest.json +3 -3
- package/.next/server/app/agents/[agentId]/page.js +2 -2
- package/.next/server/app/agents/[agentId]/page.js.nft.json +1 -1
- package/.next/server/app/agents/[agentId]/page_client-reference-manifest.js +1 -1
- package/.next/server/app/api/agents/[id]/route.js +1 -1
- package/.next/server/app/api/agents/[id]/route.js.nft.json +1 -1
- package/.next/server/app/api/agents/add/route.js.nft.json +1 -1
- package/.next/server/app/api/agents/file/route.js.nft.json +1 -1
- package/.next/server/app/api/agents/files/route.js.nft.json +1 -1
- package/.next/server/app/api/agents/route.js +1 -1
- package/.next/server/app/api/agents/route.js.nft.json +1 -1
- package/.next/server/app/api/agents/skills/install/route.js.nft.json +1 -1
- package/.next/server/app/api/agents/skills/route.js.nft.json +1 -1
- package/.next/server/app/api/agents/update/route.js.nft.json +1 -1
- package/.next/server/app/api/channels/bindings/route.js +1 -1
- package/.next/server/app/api/channels/bindings/route.js.nft.json +1 -1
- package/.next/server/app/api/cron/bulk/route/app-paths-manifest.json +3 -0
- package/.next/server/app/api/cron/bulk/route/build-manifest.json +11 -0
- package/.next/server/app/api/cron/bulk/route/server-reference-manifest.json +4 -0
- package/.next/server/app/api/cron/bulk/route.js +6 -0
- package/.next/server/app/api/cron/bulk/route.js.map +5 -0
- package/.next/server/app/api/cron/bulk/route.js.nft.json +1 -0
- package/.next/server/app/api/cron/bulk/route_client-reference-manifest.js +2 -0
- package/.next/server/app/api/cron/delete/route.js.nft.json +1 -1
- package/.next/server/app/api/cron/jobs/route.js.nft.json +1 -1
- package/.next/server/app/api/cron/recipe-installed/route.js.nft.json +1 -1
- package/.next/server/app/api/cron/worker/route.js +2 -1
- package/.next/server/app/api/cron/worker/route.js.nft.json +1 -1
- package/.next/server/app/api/goals/[id]/promote/route.js.nft.json +1 -1
- package/.next/server/app/api/goals/[id]/route.js.nft.json +1 -1
- package/.next/server/app/api/goals/route.js.nft.json +1 -1
- package/.next/server/app/api/ids/check/route.js.nft.json +1 -1
- package/.next/server/app/api/manifest/route/app-paths-manifest.json +3 -0
- package/.next/server/app/api/manifest/route/build-manifest.json +11 -0
- package/.next/server/app/api/manifest/route/server-reference-manifest.json +4 -0
- package/.next/server/app/api/manifest/route.js +6 -0
- package/.next/server/app/api/manifest/route.js.map +5 -0
- package/.next/server/app/api/manifest/route.js.nft.json +1 -0
- package/.next/server/app/api/manifest/route_client-reference-manifest.js +2 -0
- package/.next/server/app/api/marketplace/recipes/[slug]/route.js +1 -1
- package/.next/server/app/api/marketplace/recipes/[slug]/route.js.nft.json +1 -1
- package/.next/server/app/api/marketplace/recipes/route.js +1 -1
- package/.next/server/app/api/marketplace/recipes/route.js.nft.json +1 -1
- package/.next/server/app/api/plugins/[pluginId]/[...path]/route.js +2 -2
- package/.next/server/app/api/plugins/[pluginId]/[...path]/route.js.nft.json +1 -1
- package/.next/server/app/api/plugins/[pluginId]/tabs/[tabId]/route.js +1 -1
- package/.next/server/app/api/plugins/[pluginId]/tabs/[tabId]/route.js.nft.json +1 -1
- package/.next/server/app/api/plugins/route.js +1 -1
- package/.next/server/app/api/plugins/route.js.nft.json +1 -1
- package/.next/server/app/api/plugins/test/route.js +1 -1
- package/.next/server/app/api/plugins/test/route.js.nft.json +1 -1
- package/.next/server/app/api/recipes/[id]/route.js.nft.json +1 -1
- package/.next/server/app/api/recipes/clone/route.js.nft.json +1 -1
- package/.next/server/app/api/recipes/custom-team/route.js.nft.json +1 -1
- package/.next/server/app/api/recipes/delete/route.js.nft.json +1 -1
- package/.next/server/app/api/recipes/local-agent-catalog/route.js.nft.json +1 -1
- package/.next/server/app/api/recipes/route.js +1 -1
- package/.next/server/app/api/recipes/route.js.nft.json +1 -1
- package/.next/server/app/api/recipes/team-agents/route.js.nft.json +1 -1
- package/.next/server/app/api/scaffold/route.js.nft.json +1 -1
- package/.next/server/app/api/settings/cron-installation/route.js.nft.json +1 -1
- package/.next/server/app/api/settings/model-options/route.js +1 -1
- package/.next/server/app/api/settings/model-options/route.js.nft.json +1 -1
- package/.next/server/app/api/swarms/start/route.js +1 -1
- package/.next/server/app/api/swarms/start/route.js.nft.json +1 -1
- package/.next/server/app/api/swarms/status/route.js +1 -1
- package/.next/server/app/api/swarms/status/route.js.nft.json +1 -1
- package/.next/server/app/api/teams/[teamId]/media-providers/route.js +1 -1
- package/.next/server/app/api/teams/[teamId]/media-providers/route.js.nft.json +1 -1
- package/.next/server/app/api/teams/[teamId]/tickets/assign/route.js.nft.json +1 -1
- package/.next/server/app/api/teams/[teamId]/tickets/assignees/route.js.nft.json +1 -1
- package/.next/server/app/api/teams/[teamId]/tickets/comment/route.js.nft.json +1 -1
- package/.next/server/app/api/teams/[teamId]/tickets/delete/route.js.nft.json +1 -1
- package/.next/server/app/api/teams/[teamId]/tickets/move/route.js.nft.json +1 -1
- package/.next/server/app/api/teams/[teamId]/tickets/move-to-goals/route.js.nft.json +1 -1
- package/.next/server/app/api/teams/file/route.js.nft.json +1 -1
- package/.next/server/app/api/teams/files/route.js.nft.json +1 -1
- package/.next/server/app/api/teams/list/route/app-paths-manifest.json +3 -0
- package/.next/server/app/api/teams/list/route/build-manifest.json +11 -0
- package/.next/server/app/api/teams/list/route/server-reference-manifest.json +4 -0
- package/.next/server/app/api/teams/list/route.js +6 -0
- package/.next/server/app/api/teams/list/route.js.map +5 -0
- package/.next/server/app/api/teams/list/route.js.nft.json +1 -0
- package/.next/server/app/api/teams/list/route_client-reference-manifest.js +2 -0
- package/.next/server/app/api/teams/memory/route.js.nft.json +1 -1
- package/.next/server/app/api/teams/meta/route.js.nft.json +1 -1
- package/.next/server/app/api/teams/orchestrator/route.js +1 -1
- package/.next/server/app/api/teams/orchestrator/route.js.nft.json +1 -1
- package/.next/server/app/api/teams/remove-team/route.js.nft.json +1 -1
- package/.next/server/app/api/teams/skills/install/route.js.nft.json +1 -1
- package/.next/server/app/api/teams/skills/route.js.nft.json +1 -1
- package/.next/server/app/api/teams/workflow-deliverables/file/route.js +1 -1
- package/.next/server/app/api/teams/workflow-deliverables/file/route.js.nft.json +1 -1
- package/.next/server/app/api/teams/workflow-deliverables/route.js.nft.json +1 -1
- package/.next/server/app/api/teams/workflow-runs/route.js.nft.json +1 -1
- package/.next/server/app/api/teams/workflow-templates/route.js.nft.json +1 -1
- package/.next/server/app/api/teams/workflow-triggers/route/app-paths-manifest.json +3 -0
- package/.next/server/app/api/teams/workflow-triggers/route/build-manifest.json +11 -0
- package/.next/server/app/api/teams/workflow-triggers/route/server-reference-manifest.json +4 -0
- package/.next/server/app/api/teams/workflow-triggers/route.js +6 -0
- package/.next/server/app/api/teams/workflow-triggers/route.js.map +5 -0
- package/.next/server/app/api/teams/workflow-triggers/route.js.nft.json +1 -0
- package/.next/server/app/api/teams/workflow-triggers/route_client-reference-manifest.js +2 -0
- package/.next/server/app/api/teams/workflows/route.js.nft.json +1 -1
- package/.next/server/app/api/tickets/assign/route.js.nft.json +1 -1
- package/.next/server/app/api/tickets/assignees/route.js.nft.json +1 -1
- package/.next/server/app/api/tickets/move/route.js.nft.json +1 -1
- package/.next/server/app/channels/page/build-manifest.json +3 -3
- package/.next/server/app/channels/page.js +2 -2
- package/.next/server/app/channels/page.js.nft.json +1 -1
- package/.next/server/app/channels/page_client-reference-manifest.js +1 -1
- package/.next/server/app/channels.html +2 -2
- package/.next/server/app/channels.rsc +6 -6
- package/.next/server/app/channels.segments/_full.segment.rsc +6 -6
- package/.next/server/app/channels.segments/_head.segment.rsc +1 -1
- package/.next/server/app/channels.segments/_index.segment.rsc +3 -3
- package/.next/server/app/channels.segments/_tree.segment.rsc +2 -2
- package/.next/server/app/channels.segments/channels/__PAGE__.segment.rsc +2 -2
- package/.next/server/app/channels.segments/channels.segment.rsc +1 -1
- package/.next/server/app/cron-jobs/page/build-manifest.json +3 -3
- package/.next/server/app/cron-jobs/page.js +2 -2
- package/.next/server/app/cron-jobs/page.js.nft.json +1 -1
- package/.next/server/app/cron-jobs/page_client-reference-manifest.js +1 -1
- package/.next/server/app/goals/[id]/page/build-manifest.json +3 -3
- package/.next/server/app/goals/[id]/page.js +2 -2
- package/.next/server/app/goals/[id]/page.js.nft.json +1 -1
- package/.next/server/app/goals/[id]/page_client-reference-manifest.js +1 -1
- package/.next/server/app/goals/new/page/build-manifest.json +3 -3
- package/.next/server/app/goals/new/page.js +2 -2
- package/.next/server/app/goals/new/page.js.nft.json +1 -1
- package/.next/server/app/goals/new/page_client-reference-manifest.js +1 -1
- package/.next/server/app/goals/new.html +2 -2
- package/.next/server/app/goals/new.rsc +6 -6
- package/.next/server/app/goals/new.segments/_full.segment.rsc +6 -6
- package/.next/server/app/goals/new.segments/_head.segment.rsc +1 -1
- package/.next/server/app/goals/new.segments/_index.segment.rsc +3 -3
- package/.next/server/app/goals/new.segments/_tree.segment.rsc +2 -2
- package/.next/server/app/goals/new.segments/goals/new/__PAGE__.segment.rsc +2 -2
- package/.next/server/app/goals/new.segments/goals/new.segment.rsc +1 -1
- package/.next/server/app/goals/new.segments/goals.segment.rsc +1 -1
- package/.next/server/app/goals/page/build-manifest.json +3 -3
- package/.next/server/app/goals/page.js +2 -2
- package/.next/server/app/goals/page.js.nft.json +1 -1
- package/.next/server/app/goals/page_client-reference-manifest.js +1 -1
- package/.next/server/app/goals.html +1 -1
- package/.next/server/app/goals.rsc +6 -6
- package/.next/server/app/goals.segments/_full.segment.rsc +6 -6
- package/.next/server/app/goals.segments/_head.segment.rsc +1 -1
- package/.next/server/app/goals.segments/_index.segment.rsc +3 -3
- package/.next/server/app/goals.segments/_tree.segment.rsc +2 -2
- package/.next/server/app/goals.segments/goals/__PAGE__.segment.rsc +2 -2
- package/.next/server/app/goals.segments/goals.segment.rsc +1 -1
- package/.next/server/app/page/build-manifest.json +3 -3
- package/.next/server/app/page.js +4 -4
- package/.next/server/app/page.js.nft.json +1 -1
- package/.next/server/app/page_client-reference-manifest.js +1 -1
- package/.next/server/app/recipes/[id]/page/build-manifest.json +3 -3
- package/.next/server/app/recipes/[id]/page.js +4 -4
- package/.next/server/app/recipes/[id]/page.js.nft.json +1 -1
- package/.next/server/app/recipes/[id]/page_client-reference-manifest.js +1 -1
- package/.next/server/app/recipes/page/build-manifest.json +3 -3
- package/.next/server/app/recipes/page.js +4 -4
- package/.next/server/app/recipes/page.js.nft.json +1 -1
- package/.next/server/app/recipes/page_client-reference-manifest.js +1 -1
- package/.next/server/app/runs/page/build-manifest.json +3 -3
- package/.next/server/app/runs/page.js +5 -7
- package/.next/server/app/runs/page.js.nft.json +1 -1
- package/.next/server/app/runs/page_client-reference-manifest.js +1 -1
- package/.next/server/app/settings/page/build-manifest.json +3 -3
- package/.next/server/app/settings/page.js +2 -2
- package/.next/server/app/settings/page.js.nft.json +1 -1
- package/.next/server/app/settings/page_client-reference-manifest.js +1 -1
- package/.next/server/app/settings.html +1 -1
- package/.next/server/app/settings.rsc +6 -6
- package/.next/server/app/settings.segments/_full.segment.rsc +6 -6
- package/.next/server/app/settings.segments/_head.segment.rsc +1 -1
- package/.next/server/app/settings.segments/_index.segment.rsc +3 -3
- package/.next/server/app/settings.segments/_tree.segment.rsc +2 -2
- package/.next/server/app/settings.segments/settings/__PAGE__.segment.rsc +2 -2
- package/.next/server/app/settings.segments/settings.segment.rsc +1 -1
- package/.next/server/app/teams/[teamId]/deliverables/page/build-manifest.json +3 -3
- package/.next/server/app/teams/[teamId]/deliverables/page.js +5 -5
- package/.next/server/app/teams/[teamId]/deliverables/page.js.nft.json +1 -1
- package/.next/server/app/teams/[teamId]/deliverables/page_client-reference-manifest.js +1 -1
- package/.next/server/app/teams/[teamId]/page/build-manifest.json +3 -3
- package/.next/server/app/teams/[teamId]/page.js +5 -6
- package/.next/server/app/teams/[teamId]/page.js.nft.json +1 -1
- package/.next/server/app/teams/[teamId]/page_client-reference-manifest.js +1 -1
- package/.next/server/app/teams/[teamId]/runs/[workflowId]/[runId]/page/build-manifest.json +3 -3
- package/.next/server/app/teams/[teamId]/runs/[workflowId]/[runId]/page.js +5 -6
- package/.next/server/app/teams/[teamId]/runs/[workflowId]/[runId]/page.js.nft.json +1 -1
- package/.next/server/app/teams/[teamId]/runs/[workflowId]/[runId]/page_client-reference-manifest.js +1 -1
- package/.next/server/app/teams/[teamId]/runs/page/build-manifest.json +3 -3
- package/.next/server/app/teams/[teamId]/runs/page.js +2 -2
- package/.next/server/app/teams/[teamId]/runs/page.js.nft.json +1 -1
- package/.next/server/app/teams/[teamId]/runs/page_client-reference-manifest.js +1 -1
- package/.next/server/app/teams/[teamId]/tickets/[ticket]/page/build-manifest.json +3 -3
- package/.next/server/app/teams/[teamId]/tickets/[ticket]/page.js +2 -2
- package/.next/server/app/teams/[teamId]/tickets/[ticket]/page.js.nft.json +1 -1
- package/.next/server/app/teams/[teamId]/tickets/[ticket]/page_client-reference-manifest.js +1 -1
- package/.next/server/app/teams/[teamId]/tickets/page/build-manifest.json +3 -3
- package/.next/server/app/teams/[teamId]/tickets/page.js +2 -2
- package/.next/server/app/teams/[teamId]/tickets/page.js.nft.json +1 -1
- package/.next/server/app/teams/[teamId]/tickets/page_client-reference-manifest.js +1 -1
- package/.next/server/app/teams/[teamId]/workflows/[workflowId]/page/build-manifest.json +3 -3
- package/.next/server/app/teams/[teamId]/workflows/[workflowId]/page.js +5 -5
- package/.next/server/app/teams/[teamId]/workflows/[workflowId]/page.js.nft.json +1 -1
- package/.next/server/app/teams/[teamId]/workflows/[workflowId]/page_client-reference-manifest.js +1 -1
- package/.next/server/app/teams/[teamId]/workflows/page/build-manifest.json +3 -3
- package/.next/server/app/teams/[teamId]/workflows/page.js +5 -5
- package/.next/server/app/teams/[teamId]/workflows/page.js.nft.json +1 -1
- package/.next/server/app/teams/[teamId]/workflows/page_client-reference-manifest.js +1 -1
- package/.next/server/app/tickets/[ticket]/page/build-manifest.json +3 -3
- package/.next/server/app/tickets/[ticket]/page.js +2 -2
- package/.next/server/app/tickets/[ticket]/page.js.nft.json +1 -1
- package/.next/server/app/tickets/[ticket]/page_client-reference-manifest.js +1 -1
- package/.next/server/app/tickets/page/build-manifest.json +3 -3
- package/.next/server/app/tickets/page.js +2 -2
- package/.next/server/app/tickets/page.js.nft.json +1 -1
- package/.next/server/app/tickets/page_client-reference-manifest.js +1 -1
- package/.next/server/app-paths-manifest.json +4 -0
- package/.next/server/chunks/[externals]_node:fs_ddf6f167._.js +3 -0
- package/.next/server/chunks/[externals]_node:fs_ddf6f167._.js.map +1 -0
- package/.next/server/chunks/[root-of-the-server]__00a30f40._.js +1 -1
- package/.next/server/chunks/[root-of-the-server]__03c5f2a6._.js +3 -0
- package/.next/server/chunks/[root-of-the-server]__03c5f2a6._.js.map +1 -0
- package/.next/server/chunks/[root-of-the-server]__04f289da._.js +1 -1
- package/.next/server/chunks/[root-of-the-server]__08b4c8f2._.js +1 -1
- package/.next/server/chunks/[root-of-the-server]__0b2c557c._.js +3 -0
- package/.next/server/chunks/[root-of-the-server]__0b2c557c._.js.map +1 -0
- package/.next/server/chunks/[root-of-the-server]__0f55461f._.js +1 -1
- package/.next/server/chunks/[root-of-the-server]__1311d7a3._.js +1 -1
- package/.next/server/chunks/[root-of-the-server]__1480ffda._.js +1 -1
- package/.next/server/chunks/{[root-of-the-server]__be5f57b2._.js → [root-of-the-server]__17fa6089._.js} +2 -2
- package/.next/server/chunks/[root-of-the-server]__1873f417._.js +1 -1
- package/.next/server/chunks/[root-of-the-server]__1d4f6506._.js +3 -0
- package/.next/server/chunks/[root-of-the-server]__1d4f6506._.js.map +1 -0
- package/.next/server/chunks/[root-of-the-server]__1f18c0c4._.js +3 -0
- package/.next/server/chunks/[root-of-the-server]__1f18c0c4._.js.map +1 -0
- package/.next/server/chunks/[root-of-the-server]__1f1e62ac._.js +1 -1
- package/.next/server/chunks/[root-of-the-server]__20b1f42d._.js +1 -1
- package/.next/server/chunks/[root-of-the-server]__21ad9eeb._.js +1 -1
- package/.next/server/chunks/[root-of-the-server]__2c207e60._.js +1 -1
- package/.next/server/chunks/[root-of-the-server]__2dd1afff._.js +1 -1
- package/.next/server/chunks/[root-of-the-server]__3021a250._.js +1 -1
- package/.next/server/chunks/[root-of-the-server]__30cd38e9._.js +1 -1
- package/.next/server/chunks/[root-of-the-server]__392e585d._.js +2 -2
- package/.next/server/chunks/[root-of-the-server]__3bfad714._.js +1 -1
- package/.next/server/chunks/[root-of-the-server]__3d15e850._.js +1 -1
- package/.next/server/chunks/[root-of-the-server]__3f648b9b._.js +1 -1
- package/.next/server/chunks/[root-of-the-server]__482575d2._.js +1 -1
- package/.next/server/chunks/[root-of-the-server]__4898071c._.js +4 -4
- package/.next/server/chunks/[root-of-the-server]__497e7a9d._.js +22 -0
- package/.next/server/chunks/[root-of-the-server]__497e7a9d._.js.map +1 -0
- package/.next/server/chunks/[root-of-the-server]__4ee12514._.js +1 -1
- package/.next/server/chunks/[root-of-the-server]__55defc7c._.js +1 -1
- package/.next/server/chunks/{[root-of-the-server]__74b80ca4._.js → [root-of-the-server]__5792c29e._.js} +2 -2
- package/.next/server/chunks/[root-of-the-server]__5aa1dc93._.js +1 -1
- package/.next/server/chunks/[root-of-the-server]__5c5990a6._.js +1 -1
- package/.next/server/chunks/[root-of-the-server]__603cb0fa._.js +1 -1
- package/.next/server/chunks/[root-of-the-server]__6131b7e2._.js +1 -1
- package/.next/server/chunks/[root-of-the-server]__6131b7e2._.js.map +1 -1
- package/.next/server/chunks/[root-of-the-server]__636919a0._.js +1 -1
- package/.next/server/chunks/[root-of-the-server]__653d42f0._.js +3 -0
- package/.next/server/chunks/[root-of-the-server]__653d42f0._.js.map +1 -0
- package/.next/server/chunks/[root-of-the-server]__663e79ff._.js +1 -1
- package/.next/server/chunks/{[root-of-the-server]__0883634a._.js → [root-of-the-server]__68a21bb1._.js} +2 -2
- package/.next/server/chunks/{[root-of-the-server]__0883634a._.js.map → [root-of-the-server]__68a21bb1._.js.map} +1 -1
- package/.next/server/chunks/[root-of-the-server]__69c065ce._.js +1 -1
- package/.next/server/chunks/[root-of-the-server]__6e463e5f._.js +3 -0
- package/.next/server/chunks/[root-of-the-server]__6e463e5f._.js.map +1 -0
- package/.next/server/chunks/{[root-of-the-server]__c1b0d50e._.js → [root-of-the-server]__7194dfe2._.js} +3 -3
- package/.next/server/chunks/{[root-of-the-server]__f45ceefb._.js → [root-of-the-server]__7347e39f._.js} +2 -2
- package/.next/server/chunks/{[root-of-the-server]__f45ceefb._.js.map → [root-of-the-server]__7347e39f._.js.map} +1 -1
- package/.next/server/chunks/[root-of-the-server]__74e2a9ba._.js +1 -1
- package/.next/server/chunks/[root-of-the-server]__7bdf9f6e._.js +1 -1
- package/.next/server/chunks/[root-of-the-server]__7bdf9f6e._.js.map +1 -1
- package/.next/server/chunks/[root-of-the-server]__7e12b9f4._.js +1 -1
- package/.next/server/chunks/[root-of-the-server]__87875179._.js +1 -1
- package/.next/server/chunks/{[root-of-the-server]__17124952._.js → [root-of-the-server]__89f2190c._.js} +3 -3
- package/.next/server/chunks/[root-of-the-server]__8f8e110f._.js +1 -1
- package/.next/server/chunks/[root-of-the-server]__91d0cce1._.js +1 -1
- package/.next/server/chunks/[root-of-the-server]__91d0cce1._.js.map +1 -1
- package/.next/server/chunks/[root-of-the-server]__937b40e2._.js +3 -0
- package/.next/server/chunks/[root-of-the-server]__937b40e2._.js.map +1 -0
- package/.next/server/chunks/[root-of-the-server]__9853b72d._.js +1 -1
- package/.next/server/chunks/[root-of-the-server]__9dba20b3._.js +1 -1
- package/.next/server/chunks/[root-of-the-server]__9e96d37b._.js +1 -1
- package/.next/server/chunks/[root-of-the-server]__aba68368._.js +1 -1
- package/.next/server/chunks/[root-of-the-server]__aed4e4f2._.js +1 -1
- package/.next/server/chunks/[root-of-the-server]__b6cff26d._.js +1 -1
- package/.next/server/chunks/{[root-of-the-server]__0bea0f71._.js → [root-of-the-server]__b986660c._.js} +2 -2
- package/.next/server/chunks/{[root-of-the-server]__0bea0f71._.js.map → [root-of-the-server]__b986660c._.js.map} +1 -1
- package/.next/server/chunks/{[root-of-the-server]__343776df._.js → [root-of-the-server]__bbed0e46._.js} +2 -2
- package/.next/server/chunks/[root-of-the-server]__c15c5141._.js +1 -1
- package/.next/server/chunks/[root-of-the-server]__c50e4bc4._.js +1 -1
- package/.next/server/chunks/[root-of-the-server]__cc0860cb._.js +1 -1
- package/.next/server/chunks/[root-of-the-server]__cc3ea05b._.js +3 -0
- package/.next/server/chunks/[root-of-the-server]__cc3ea05b._.js.map +1 -0
- package/.next/server/chunks/[root-of-the-server]__d302afb4._.js +1 -1
- package/.next/server/chunks/[root-of-the-server]__d4a8660e._.js +1 -1
- package/.next/server/chunks/[root-of-the-server]__e1432bba._.js +3 -0
- package/.next/server/chunks/[root-of-the-server]__e1432bba._.js.map +1 -0
- package/.next/server/chunks/[root-of-the-server]__e478ef0d._.js +1 -1
- package/.next/server/chunks/[root-of-the-server]__e9acbabd._.js +1 -1
- package/.next/server/chunks/[root-of-the-server]__e9d9d570._.js +1 -1
- package/.next/server/chunks/[root-of-the-server]__f408c708._.js +2 -2
- package/.next/server/chunks/[root-of-the-server]__f4cbadf7._.js +1 -1
- package/.next/server/chunks/[root-of-the-server]__f5cd81f1._.js +1 -1
- package/.next/server/chunks/[root-of-the-server]__f85b5a70._.js +3 -0
- package/.next/server/chunks/[root-of-the-server]__f85b5a70._.js.map +1 -0
- package/.next/server/chunks/[root-of-the-server]__f994dc62._.js +1 -1
- package/.next/server/chunks/[root-of-the-server]__fb22e719._.js +3 -0
- package/.next/server/chunks/[root-of-the-server]__fb22e719._.js.map +1 -0
- package/.next/server/chunks/_next-internal_server_app_api_cron_bulk_route_actions_30f8adb9.js +3 -0
- package/.next/server/chunks/_next-internal_server_app_api_cron_bulk_route_actions_30f8adb9.js.map +1 -0
- package/.next/server/chunks/_next-internal_server_app_api_manifest_route_actions_7f7622ff.js +3 -0
- package/.next/server/chunks/_next-internal_server_app_api_manifest_route_actions_7f7622ff.js.map +1 -0
- package/.next/server/chunks/_next-internal_server_app_api_teams_list_route_actions_5aa8c937.js +3 -0
- package/.next/server/chunks/_next-internal_server_app_api_teams_list_route_actions_5aa8c937.js.map +1 -0
- package/.next/server/chunks/_next-internal_server_app_api_teams_workflow-triggers_route_actions_e86e3b38.js +3 -0
- package/.next/server/chunks/_next-internal_server_app_api_teams_workflow-triggers_route_actions_e86e3b38.js.map +1 -0
- package/.next/server/chunks/node_modules_next_dist_esm_build_templates_app-route_1fe98a49.js +1 -1
- package/.next/server/chunks/node_modules_next_dist_esm_build_templates_app-route_1fe98a49.js.map +1 -1
- package/.next/server/chunks/node_modules_next_dist_esm_build_templates_app-route_3a1b29e4.js +1 -1
- package/.next/server/chunks/node_modules_next_dist_esm_build_templates_app-route_cb6ddb24.js +13 -0
- package/.next/server/chunks/node_modules_next_dist_esm_build_templates_app-route_cb6ddb24.js.map +1 -0
- package/.next/server/chunks/node_modules_next_dist_esm_build_templates_app-route_f5680d9e.js +1 -1
- package/.next/server/chunks/node_modules_yaml_dist_49c13b35._.js +1 -1
- package/.next/server/chunks/node_modules_yaml_dist_49c13b35._.js.map +1 -1
- package/.next/server/chunks/ssr/[root-of-the-server]__195421b7._.js +2 -2
- package/.next/server/chunks/ssr/[root-of-the-server]__195421b7._.js.map +1 -1
- package/.next/server/chunks/ssr/[root-of-the-server]__2a657095._.js +3 -0
- package/.next/server/chunks/ssr/[root-of-the-server]__2a657095._.js.map +1 -0
- package/.next/server/chunks/ssr/[root-of-the-server]__3b880807._.js +1 -1
- package/.next/server/chunks/ssr/[root-of-the-server]__3b880807._.js.map +1 -1
- package/.next/server/chunks/ssr/[root-of-the-server]__3f55f975._.js +3 -0
- package/.next/server/chunks/ssr/[root-of-the-server]__3f55f975._.js.map +1 -0
- package/.next/server/chunks/ssr/[root-of-the-server]__471bc2e7._.js +1 -1
- package/.next/server/chunks/ssr/[root-of-the-server]__471bc2e7._.js.map +1 -1
- package/.next/server/chunks/ssr/[root-of-the-server]__4d24c088._.js +3 -0
- package/.next/server/chunks/ssr/[root-of-the-server]__4d24c088._.js.map +1 -0
- package/.next/server/chunks/ssr/[root-of-the-server]__6390ce9c._.js +3 -0
- package/.next/server/chunks/ssr/[root-of-the-server]__6390ce9c._.js.map +1 -0
- package/.next/server/chunks/ssr/[root-of-the-server]__7b8cdea5._.js +3 -0
- package/.next/server/chunks/ssr/[root-of-the-server]__7b8cdea5._.js.map +1 -0
- package/.next/server/chunks/ssr/[root-of-the-server]__7d21617d._.js +3 -0
- package/.next/server/chunks/ssr/[root-of-the-server]__7d21617d._.js.map +1 -0
- package/.next/server/chunks/ssr/[root-of-the-server]__8135c9d5._.js +3 -0
- package/.next/server/chunks/ssr/[root-of-the-server]__8135c9d5._.js.map +1 -0
- package/.next/server/chunks/ssr/{node_modules_next_dist_1038a5b9._.js → [root-of-the-server]__8e8f535b._.js} +2 -2
- package/.next/server/chunks/ssr/{node_modules_next_dist_1038a5b9._.js.map → [root-of-the-server]__8e8f535b._.js.map} +1 -1
- package/.next/server/chunks/ssr/[root-of-the-server]__92524828._.js +1 -1
- package/.next/server/chunks/ssr/[root-of-the-server]__92524828._.js.map +1 -1
- package/.next/server/chunks/ssr/[root-of-the-server]__997aa62c._.js +1 -1
- package/.next/server/chunks/ssr/[root-of-the-server]__997aa62c._.js.map +1 -1
- package/.next/server/chunks/ssr/[root-of-the-server]__9db1df87._.js +3 -0
- package/.next/server/chunks/ssr/[root-of-the-server]__9db1df87._.js.map +1 -0
- package/.next/server/chunks/ssr/[root-of-the-server]__9e1ab064._.js +1 -1
- package/.next/server/chunks/ssr/[root-of-the-server]__9e1ab064._.js.map +1 -1
- package/.next/server/chunks/ssr/[root-of-the-server]__a2e3966f._.js +3 -0
- package/.next/server/chunks/ssr/[root-of-the-server]__a2e3966f._.js.map +1 -0
- package/.next/server/chunks/ssr/[root-of-the-server]__af792402._.js +1 -1
- package/.next/server/chunks/ssr/[root-of-the-server]__af792402._.js.map +1 -1
- package/.next/server/chunks/ssr/[root-of-the-server]__b5f65083._.js +1 -1
- package/.next/server/chunks/ssr/[root-of-the-server]__b5f65083._.js.map +1 -1
- package/.next/server/chunks/ssr/[root-of-the-server]__becf14db._.js +3 -0
- package/.next/server/chunks/ssr/[root-of-the-server]__becf14db._.js.map +1 -0
- package/.next/server/chunks/ssr/[root-of-the-server]__c106a298._.js +3 -0
- package/.next/server/chunks/ssr/[root-of-the-server]__c106a298._.js.map +1 -0
- package/.next/server/chunks/ssr/[root-of-the-server]__cb91405c._.js +3 -0
- package/.next/server/chunks/ssr/[root-of-the-server]__cb91405c._.js.map +1 -0
- package/.next/server/chunks/ssr/[root-of-the-server]__f59c3144._.js +3 -0
- package/.next/server/chunks/ssr/[root-of-the-server]__f59c3144._.js.map +1 -0
- package/.next/server/chunks/ssr/[root-of-the-server]__fbe5ff69._.js +1 -1
- package/.next/server/chunks/ssr/[root-of-the-server]__fbe5ff69._.js.map +1 -1
- package/.next/server/chunks/ssr/_1ee3bd7b._.js +1 -1
- package/.next/server/chunks/ssr/_1ee3bd7b._.js.map +1 -1
- package/.next/server/chunks/ssr/{_deb7a691._.js → _2ab986a4._.js} +2 -2
- package/.next/server/chunks/ssr/_2ab986a4._.js.map +1 -0
- package/.next/server/chunks/ssr/_2d8d7232._.js +1 -1
- package/.next/server/chunks/ssr/_2d8d7232._.js.map +1 -1
- package/.next/server/chunks/ssr/_43a80c61._.js +1 -1
- package/.next/server/chunks/ssr/_43a80c61._.js.map +1 -1
- package/.next/server/chunks/ssr/_641f29bc._.js +3 -0
- package/.next/server/chunks/ssr/_641f29bc._.js.map +1 -0
- package/.next/server/chunks/ssr/_ac993243._.js +3 -0
- package/.next/server/chunks/ssr/_ac993243._.js.map +1 -0
- package/.next/server/chunks/ssr/_f636ce67._.js +3 -0
- package/.next/server/chunks/ssr/_f636ce67._.js.map +1 -0
- package/.next/server/chunks/ssr/b1a17_app_teams_[teamId]_workflows_[workflowId]_workflows-editor-client_tsx_5e714aa2._.js +7 -1
- package/.next/server/chunks/ssr/b1a17_app_teams_[teamId]_workflows_[workflowId]_workflows-editor-client_tsx_5e714aa2._.js.map +1 -1
- package/.next/server/chunks/ssr/{_7f9e89d2._.js → node_modules_next_10fb6ad9._.js} +3 -3
- package/.next/server/chunks/ssr/node_modules_next_10fb6ad9._.js.map +1 -0
- package/.next/server/chunks/ssr/node_modules_next_dist_25a30daf._.js +1 -1
- package/.next/server/chunks/ssr/node_modules_next_dist_compiled_bc6b8ddf._.js +1 -1
- package/.next/server/chunks/ssr/node_modules_yaml_dist_18db9ed7._.js +2 -2
- package/.next/server/chunks/ssr/src_13139e3d._.js +1 -1
- package/.next/server/chunks/ssr/src_13139e3d._.js.map +1 -1
- package/.next/server/chunks/ssr/src_2a73b867._.js +1 -1
- package/.next/server/chunks/ssr/src_2a73b867._.js.map +1 -1
- package/.next/server/chunks/ssr/src_2dbb3b7f._.js +1 -1
- package/.next/server/chunks/ssr/src_2dbb3b7f._.js.map +1 -1
- package/.next/server/chunks/ssr/src_417bc4a6._.js +1 -1
- package/.next/server/chunks/ssr/src_417bc4a6._.js.map +1 -1
- package/.next/server/chunks/ssr/src_59477309._.js +1 -1
- package/.next/server/chunks/ssr/src_59477309._.js.map +1 -1
- package/.next/server/chunks/ssr/src_79d55c05._.js +1 -1
- package/.next/server/chunks/ssr/src_79d55c05._.js.map +1 -1
- package/.next/server/chunks/ssr/src_app_HomeClient_tsx_f9f7568d._.js +1 -1
- package/.next/server/chunks/ssr/src_app_HomeClient_tsx_f9f7568d._.js.map +1 -1
- package/.next/server/chunks/ssr/src_app_agents_[agentId]_agent-editor_tsx_f85bbe65._.js +1 -1
- package/.next/server/chunks/ssr/src_app_agents_[agentId]_agent-editor_tsx_f85bbe65._.js.map +1 -1
- package/.next/server/chunks/ssr/src_app_cron-jobs_cron-jobs-client_tsx_ec91a73d._.js +1 -1
- package/.next/server/chunks/ssr/src_app_cron-jobs_cron-jobs-client_tsx_ec91a73d._.js.map +1 -1
- package/.next/server/chunks/ssr/src_app_recipes_[id]_RecipeEditor_index_tsx_98393217._.js +1 -1
- package/.next/server/chunks/ssr/src_app_recipes_[id]_RecipeEditor_index_tsx_98393217._.js.map +1 -1
- package/.next/server/chunks/ssr/src_app_recipes_recipes-client_tsx_8ed3ca94._.js +1 -1
- package/.next/server/chunks/ssr/src_app_recipes_recipes-client_tsx_8ed3ca94._.js.map +1 -1
- package/.next/server/chunks/ssr/src_app_teams_[teamId]_runs_[workflowId]_[runId]_run-detail-client_tsx_56f0cbd7._.js +3 -0
- package/.next/server/chunks/ssr/src_app_teams_[teamId]_runs_[workflowId]_[runId]_run-detail-client_tsx_56f0cbd7._.js.map +1 -0
- package/.next/server/chunks/ssr/src_app_teams_[teamId]_workflows_workflows-client_tsx_12742cc9._.js +1 -1
- package/.next/server/chunks/ssr/src_app_teams_[teamId]_workflows_workflows-client_tsx_12742cc9._.js.map +1 -1
- package/.next/server/chunks/ssr/src_app_tickets_TicketsBoardClient_tsx_5e156ef3._.js +1 -1
- package/.next/server/chunks/ssr/src_app_tickets_TicketsBoardClient_tsx_5e156ef3._.js.map +1 -1
- package/.next/server/middleware-build-manifest.js +3 -3
- package/.next/server/pages/404.html +1 -1
- package/.next/server/pages/500.html +2 -2
- package/.next/server/server-reference-manifest.js +1 -1
- package/.next/server/server-reference-manifest.json +1 -1
- package/.next/static/chunks/001f840e2d5598af.js +10 -0
- package/.next/static/chunks/212477db59154fa7.js +3 -0
- package/.next/static/chunks/242fee5849d79d1b.js +1 -0
- package/.next/static/chunks/26d8587a145bded7.js +1 -0
- package/.next/static/chunks/{b83c1ca03c3b8c6d.js → 372ac1d07db9969a.js} +1 -1
- package/.next/static/chunks/4a0d27f3023676a5.js +1 -0
- package/.next/static/chunks/4ad57cfc54e20abd.js +1 -0
- package/.next/static/chunks/4e8866ad8f1f6b2b.js +1 -0
- package/.next/static/chunks/7d9e7a36b92578fd.js +1 -0
- package/.next/static/chunks/87f63f654bc046a2.js +3 -0
- package/.next/static/chunks/8aac543d98940eb3.js +2 -0
- package/.next/static/chunks/8acd42df55d57556.js +1 -0
- package/.next/static/chunks/95b7564f2360e762.js +1 -0
- package/.next/static/chunks/9801fc48f532d076.js +1 -0
- package/.next/static/chunks/{d6e1b7307a9274ce.js → 9c627cb11f73ac4c.js} +1 -1
- package/.next/static/chunks/ad652e4b50e1fb17.js +1 -0
- package/.next/static/chunks/aff32612e6b9d901.js +1 -0
- package/.next/static/chunks/c6c561355e97baa8.js +7 -0
- package/.next/static/chunks/d4c855575c079ffc.js +3 -0
- package/.next/static/chunks/d593ea5e91e81b45.js +1 -0
- package/.next/static/chunks/{87879d67a1601ee0.js → e0984ec981f01c0d.js} +1 -1
- package/.next/static/chunks/f5039461b97678c7.js +1 -0
- package/.next/static/chunks/f51763a2aea0a4b6.js +1 -0
- package/.next/static/chunks/f7f157ba542e1ae5.js +1 -0
- package/.next/static/chunks/fb008837ba324b34.css +3 -0
- package/.next/static/chunks/{turbopack-dbf3078dbf5863bd.js → turbopack-bdd9478663f034d6.js} +1 -1
- package/LICENSE +192 -0
- package/README.md +19 -5
- package/openclaw/index.ts +144 -5
- package/openclaw.plugin.json +2 -8
- package/package.json +5 -2
- package/.next/server/chunks/[root-of-the-server]__18423bab._.js +0 -3
- package/.next/server/chunks/[root-of-the-server]__18423bab._.js.map +0 -1
- package/.next/server/chunks/[root-of-the-server]__35ec765d._.js +0 -13
- package/.next/server/chunks/[root-of-the-server]__35ec765d._.js.map +0 -1
- package/.next/server/chunks/[root-of-the-server]__3c92e5aa._.js +0 -3
- package/.next/server/chunks/[root-of-the-server]__3c92e5aa._.js.map +0 -1
- package/.next/server/chunks/[root-of-the-server]__813dd669._.js +0 -3
- package/.next/server/chunks/[root-of-the-server]__813dd669._.js.map +0 -1
- package/.next/server/chunks/[root-of-the-server]__b457b884._.js +0 -22
- package/.next/server/chunks/[root-of-the-server]__b457b884._.js.map +0 -1
- package/.next/server/chunks/[root-of-the-server]__c5e88cbb._.js +0 -3
- package/.next/server/chunks/[root-of-the-server]__c5e88cbb._.js.map +0 -1
- package/.next/server/chunks/[root-of-the-server]__da7df58d._.js +0 -3
- package/.next/server/chunks/[root-of-the-server]__da7df58d._.js.map +0 -1
- package/.next/server/chunks/ssr/[root-of-the-server]__0a5cb3ca._.js +0 -3
- package/.next/server/chunks/ssr/[root-of-the-server]__0a5cb3ca._.js.map +0 -1
- package/.next/server/chunks/ssr/[root-of-the-server]__177cec74._.js +0 -3
- package/.next/server/chunks/ssr/[root-of-the-server]__177cec74._.js.map +0 -1
- package/.next/server/chunks/ssr/[root-of-the-server]__4981f370._.js +0 -3
- package/.next/server/chunks/ssr/[root-of-the-server]__4981f370._.js.map +0 -1
- package/.next/server/chunks/ssr/[root-of-the-server]__51e26a01._.js +0 -3
- package/.next/server/chunks/ssr/[root-of-the-server]__51e26a01._.js.map +0 -1
- package/.next/server/chunks/ssr/[root-of-the-server]__6b6b7595._.js +0 -3
- package/.next/server/chunks/ssr/[root-of-the-server]__6b6b7595._.js.map +0 -1
- package/.next/server/chunks/ssr/[root-of-the-server]__8f9585b9._.js +0 -3
- package/.next/server/chunks/ssr/[root-of-the-server]__8f9585b9._.js.map +0 -1
- package/.next/server/chunks/ssr/[root-of-the-server]__9e400864._.js +0 -3
- package/.next/server/chunks/ssr/[root-of-the-server]__9e400864._.js.map +0 -1
- package/.next/server/chunks/ssr/[root-of-the-server]__a6348eaa._.js +0 -3
- package/.next/server/chunks/ssr/[root-of-the-server]__a6348eaa._.js.map +0 -1
- package/.next/server/chunks/ssr/[root-of-the-server]__ad4e8478._.js +0 -3
- package/.next/server/chunks/ssr/[root-of-the-server]__ad4e8478._.js.map +0 -1
- package/.next/server/chunks/ssr/[root-of-the-server]__b5aa14b8._.js +0 -3
- package/.next/server/chunks/ssr/[root-of-the-server]__b5aa14b8._.js.map +0 -1
- package/.next/server/chunks/ssr/[root-of-the-server]__b8998a21._.js +0 -3
- package/.next/server/chunks/ssr/[root-of-the-server]__b8998a21._.js.map +0 -1
- package/.next/server/chunks/ssr/[root-of-the-server]__e9bd9b71._.js +0 -3
- package/.next/server/chunks/ssr/[root-of-the-server]__e9bd9b71._.js.map +0 -1
- package/.next/server/chunks/ssr/_32beff4b._.js +0 -3
- package/.next/server/chunks/ssr/_32beff4b._.js.map +0 -1
- package/.next/server/chunks/ssr/_7f9e89d2._.js.map +0 -1
- package/.next/server/chunks/ssr/_8538617d._.js +0 -3
- package/.next/server/chunks/ssr/_8538617d._.js.map +0 -1
- package/.next/server/chunks/ssr/_a506fcf8._.js +0 -3
- package/.next/server/chunks/ssr/_a506fcf8._.js.map +0 -1
- package/.next/server/chunks/ssr/_deb7a691._.js.map +0 -1
- package/.next/server/chunks/ssr/d4b1c_modules_next_dist_server_route-modules_app-page_vendored_ssr_react-dom_6ef9314a.js +0 -3
- package/.next/server/chunks/ssr/d4b1c_modules_next_dist_server_route-modules_app-page_vendored_ssr_react-dom_6ef9314a.js.map +0 -1
- package/.next/server/chunks/ssr/src_app_21685f67._.js +0 -3
- package/.next/server/chunks/ssr/src_app_21685f67._.js.map +0 -1
- package/.next/static/chunks/0edab8a24d59a626.js +0 -2
- package/.next/static/chunks/410dc851d0e3033d.js +0 -1
- package/.next/static/chunks/4e38b3f280ced64c.js +0 -1
- package/.next/static/chunks/4f2b8a07ace7e02b.js +0 -1
- package/.next/static/chunks/57ad5290f7e92ffd.css +0 -3
- package/.next/static/chunks/8a919077b73862da.js +0 -1
- package/.next/static/chunks/9906444fb1191bb4.js +0 -1
- package/.next/static/chunks/a625725b4cd85ea3.js +0 -1
- package/.next/static/chunks/ac32974713c57cb3.js +0 -1
- package/.next/static/chunks/bdb7ebd88ea13111.js +0 -1
- package/.next/static/chunks/bfcfbe145220d365.js +0 -1
- package/.next/static/chunks/c0d9f53d91cc65c5.js +0 -10
- package/.next/static/chunks/c0e2f959abc4cc13.js +0 -1
- package/.next/static/chunks/c822e53f79a492c7.js +0 -1
- package/.next/static/chunks/ce6b2024d13b4333.js +0 -1
- package/.next/static/chunks/d13249af74d111cf.js +0 -3
- package/.next/static/chunks/d16f64ca3a8ed208.js +0 -1
- package/.next/static/chunks/d7541a171116ec9c.js +0 -1
- package/.next/static/chunks/e03137fd069b1514.js +0 -1
- package/.next/static/chunks/e10faa9296c8b246.js +0 -1
- package/.next/static/chunks/ec24877f7b7f82c5.js +0 -3
- package/.next/static/chunks/ff3bbb5df40b2cc4.js +0 -1
- /package/.next/server/chunks/{[root-of-the-server]__be5f57b2._.js.map → [root-of-the-server]__17fa6089._.js.map} +0 -0
- /package/.next/server/chunks/{[root-of-the-server]__74b80ca4._.js.map → [root-of-the-server]__5792c29e._.js.map} +0 -0
- /package/.next/server/chunks/{[root-of-the-server]__c1b0d50e._.js.map → [root-of-the-server]__7194dfe2._.js.map} +0 -0
- /package/.next/server/chunks/{[root-of-the-server]__17124952._.js.map → [root-of-the-server]__89f2190c._.js.map} +0 -0
- /package/.next/server/chunks/{[root-of-the-server]__343776df._.js.map → [root-of-the-server]__bbed0e46._.js.map} +0 -0
- /package/.next/static/{F0PhVXEIb3LrF9XQem5EQ → bTCL-c1-1vqxgA-ZN8TUy}/_buildManifest.js +0 -0
- /package/.next/static/{F0PhVXEIb3LrF9XQem5EQ → bTCL-c1-1vqxgA-ZN8TUy}/_clientMiddlewareManifest.json +0 -0
- /package/.next/static/{F0PhVXEIb3LrF9XQem5EQ → bTCL-c1-1vqxgA-ZN8TUy}/_ssgManifest.js +0 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../src/lib/errors.ts","../../../../src/lib/slugify.ts","../../../../src/components/GoalFormFields.tsx","../../../../src/lib/goals-client.ts","../../../../src/app/goals/new/page.tsx"],"sourcesContent":["/**\n * Extracts a string message from an unknown error value.\n * Used consistently across API routes and client components.\n */\nexport function errorMessage(e: unknown): string {\n return e instanceof Error ? e.message : String(e);\n}\n","/**\n * Slugify a string for use in ids, file names, or URLs.\n * Normalizes to lowercase, replaces non-alphanumeric sequences with hyphens, trims edges.\n * Uses character-by-character processing to avoid regex ReDoS.\n * @param maxLength - optional max length (default 80). Use 64 for goal ids.\n */\nexport function slugifyId(input: string, maxLength = 80): string {\n const s = String(input ?? \"\").toLowerCase().trim();\n const cap = Math.min(s.length, maxLength * 2);\n let result = \"\";\n let prevHyphen = false;\n for (let i = 0; i < cap; i++) {\n const c = s[i];\n if ((c >= \"a\" && c <= \"z\") || (c >= \"0\" && c <= \"9\")) {\n result += c;\n prevHyphen = false;\n } else if ((c === \" \" || c === \"-\" || c === \"_\") && !prevHyphen) {\n result += \"-\";\n prevHyphen = true;\n }\n }\n while (result.startsWith(\"-\")) result = result.slice(1);\n while (result.endsWith(\"-\")) result = result.slice(0, -1);\n return result.slice(0, maxLength);\n}\n","\"use client\";\n\nimport type { ReactNode } from \"react\";\nimport { useId } from \"react\";\nimport type { GoalFormState, GoalStatus } from \"@/lib/goals-client\";\n\nexport type { GoalFormState };\n\n/** Wraps goal form content with error display and action buttons. */\nexport function GoalFormCard({\n children,\n error,\n actions,\n}: {\n children: ReactNode;\n error: string | null;\n actions: ReactNode;\n}) {\n return (\n <div className=\"ck-glass p-6 space-y-4\">\n {children}\n {error ? <div className=\"text-sm text-red-300\">{error}</div> : null}\n {actions}\n </div>\n );\n}\n\nconst inputClass =\n \"mt-1 w-full rounded-[var(--ck-radius-sm)] border border-[color:var(--ck-border-subtle)] bg-transparent px-3 py-2 text-sm\";\n\ntype Props = {\n formState: GoalFormState;\n /** When provided, renders the ID field (for create flow). */\n idField?: { id: string; setId: (v: string) => void; suggestedId?: string };\n /** When provided, shows updated timestamp next to body label. */\n updatedAt?: string | null;\n /** Body textarea height override (e.g. 260 for new page). */\n bodyHeight?: string;\n};\n\nexport function GoalFormFields({\n formState,\n idField,\n updatedAt,\n bodyHeight = \"h-[320px]\",\n}: Props) {\n const { title, setTitle, status, setStatus, tagsRaw, setTagsRaw, teamsRaw, setTeamsRaw, body, setBody } = formState;\n const baseId = useId();\n const idInputId = `${baseId}-id`;\n const titleInputId = `${baseId}-title`;\n const statusSelectId = `${baseId}-status`;\n const teamsInputId = `${baseId}-teams`;\n const tagsInputId = `${baseId}-tags`;\n const bodyTextareaId = `${baseId}-body`;\n return (\n <>\n {idField ? (\n <div>\n <label htmlFor={idInputId} className=\"text-xs text-[color:var(--ck-text-tertiary)]\">\n ID\n </label>\n <input\n id={idInputId}\n className={`${inputClass} font-mono`}\n value={idField.id}\n onChange={(e) => idField.setId(e.target.value)}\n placeholder=\"increase-trial-activation\"\n aria-describedby={`${baseId}-id-hint`}\n />\n <div id={`${baseId}-id-hint`} className=\"mt-1 text-xs text-[color:var(--ck-text-tertiary)]\">\n Lowercase letters, numbers, hyphens. Stored as <code className=\"font-mono\">{idField.id || \"<id>\"}.md</code>\n .\n {idField.suggestedId && !idField.id.trim() ? (\n <>\n {\" \"}\n Suggested:{\" \"}\n <button type=\"button\" className=\"underline\" onClick={() => idField.setId(idField.suggestedId ?? \"\")}>\n {idField.suggestedId}\n </button>\n </>\n ) : null}\n </div>\n </div>\n ) : null}\n\n <div>\n <label htmlFor={titleInputId} className=\"text-xs text-[color:var(--ck-text-tertiary)]\">\n Title\n </label>\n <input\n id={titleInputId}\n className={inputClass}\n value={title}\n onChange={(e) => setTitle(e.target.value)}\n placeholder={idField ? \"Increase trial activation\" : \"Goal title\"}\n />\n </div>\n\n <div className=\"grid grid-cols-1 gap-4 sm:grid-cols-3\">\n <div>\n <label htmlFor={statusSelectId} className=\"text-xs text-[color:var(--ck-text-tertiary)]\">\n Status\n </label>\n <select\n id={statusSelectId}\n className={inputClass}\n value={status}\n onChange={(e) => setStatus(e.target.value as GoalStatus)}\n aria-label=\"Goal status\"\n >\n <option value=\"planned\">Planned</option>\n <option value=\"active\">Active</option>\n <option value=\"done\">Done</option>\n </select>\n </div>\n <div>\n <label htmlFor={teamsInputId} className=\"text-xs text-[color:var(--ck-text-tertiary)]\">\n Teams (comma-separated)\n </label>\n <input\n id={teamsInputId}\n className={inputClass}\n value={teamsRaw}\n onChange={(e) => setTeamsRaw(e.target.value)}\n placeholder=\"development-team, marketing-team\"\n />\n </div>\n <div>\n <label htmlFor={tagsInputId} className=\"text-xs text-[color:var(--ck-text-tertiary)]\">\n Tags (comma-separated)\n </label>\n <input\n id={tagsInputId}\n className={inputClass}\n value={tagsRaw}\n onChange={(e) => setTagsRaw(e.target.value)}\n placeholder=\"onboarding, growth\"\n />\n </div>\n </div>\n\n <div>\n <div className=\"flex items-center justify-between\">\n <label htmlFor={bodyTextareaId} className=\"text-xs text-[color:var(--ck-text-tertiary)]\">\n Body (markdown)\n </label>\n {updatedAt != null ? (\n <div className=\"text-xs text-[color:var(--ck-text-tertiary)]\">\n {updatedAt ? `updated ${new Date(updatedAt).toLocaleString()}` : \"\"}\n </div>\n ) : null}\n </div>\n <textarea\n id={bodyTextareaId}\n className={`mt-1 ${bodyHeight} w-full rounded-[var(--ck-radius-sm)] border border-[color:var(--ck-border-subtle)] bg-transparent px-3 py-2 font-mono text-sm`}\n value={body}\n onChange={(e) => setBody(e.target.value)}\n placeholder=\"Write the goal here…\"\n />\n </div>\n </>\n );\n}\n","\"use client\";\n\nimport { useMemo, useState } from \"react\";\n\n/** Client-safe goal types and utils (no node deps). */\n\nexport type GoalStatus = \"planned\" | \"active\" | \"done\";\n\nexport type GoalFrontmatter = {\n id: string;\n title: string;\n status: GoalStatus;\n tags: string[];\n teams: string[];\n updatedAt: string;\n};\n\n/** Form state shape for GoalFormFields. */\nexport type GoalFormState = {\n title: string;\n setTitle: (v: string) => void;\n status: GoalStatus;\n setStatus: (v: GoalStatus) => void;\n tagsRaw: string;\n setTagsRaw: (v: string) => void;\n teamsRaw: string;\n setTeamsRaw: (v: string) => void;\n body: string;\n setBody: (v: string) => void;\n};\n\n/** Parses comma-separated string into trimmed non-empty array. */\nexport function parseCommaList(raw: string): string[] {\n return raw.split(\",\").map((s) => s.trim()).filter(Boolean);\n}\n\n/** Shared form state for goal create/edit. Returns formState for GoalFormFields and parsed tags/teams. */\nexport function useGoalFormState(initial?: Partial<GoalFormState>): {\n formState: GoalFormState;\n tags: string[];\n teams: string[];\n} {\n const [title, setTitle] = useState(initial?.title ?? \"\");\n const [status, setStatus] = useState<GoalStatus>(initial?.status ?? \"planned\");\n const [tagsRaw, setTagsRaw] = useState(initial?.tagsRaw ?? \"\");\n const [teamsRaw, setTeamsRaw] = useState(initial?.teamsRaw ?? \"\");\n const [body, setBody] = useState(initial?.body ?? \"\");\n\n const formState: GoalFormState = useMemo(\n () => ({\n title,\n setTitle,\n status,\n setStatus,\n tagsRaw,\n setTagsRaw,\n teamsRaw,\n setTeamsRaw,\n body,\n setBody,\n }),\n [title, status, tagsRaw, teamsRaw, body]\n );\n\n const tags = useMemo(() => parseCommaList(tagsRaw), [tagsRaw]);\n const teams = useMemo(() => parseCommaList(teamsRaw), [teamsRaw]);\n\n return { formState, tags, teams };\n}\n","\"use client\";\n\nimport Link from \"next/link\";\nimport { GoalFormCard, GoalFormFields } from \"@/components/GoalFormFields\";\nimport { useRouter } from \"next/navigation\";\nimport { useMemo, useState } from \"react\";\nimport { slugifyId } from \"@/lib/slugify\";\nimport { errorMessage } from \"@/lib/errors\";\nimport { fetchJson } from \"@/lib/fetch-json\";\nimport { useGoalFormState } from \"@/lib/goals-client\";\n\nexport default function NewGoalPage() {\n const router = useRouter();\n\n const [id, setId] = useState(\"\");\n const [error, setError] = useState<string | null>(null);\n const [saving, setSaving] = useState(false);\n\n const defaultBody =\n \"## Workflow\\n<!-- goal-workflow -->\\n- Use **Promote to inbox** to send this goal to the development-team inbox for scoping.\\n- When promoted, set goal status to **active**.\\n- Track implementation work via tickets (add links/IDs under a **Tickets** section in this goal).\\n- When development is complete (all associated tickets marked done), set goal status to **done**.\\n\\n## Tickets\\n- (add ticket links/ids)\\n\";\n const { formState, tags, teams } = useGoalFormState({ body: defaultBody });\n const { title } = formState;\n\n const suggestedId = useMemo(() => {\n const s = slugifyId(title, 64);\n return s.length >= 2 ? s : \"\";\n }, [title]);\n\n async function create() {\n setSaving(true);\n setError(null);\n const finalId = id.trim();\n try {\n await fetchJson(\"/api/goals\", {\n method: \"POST\",\n headers: { \"content-type\": \"application/json\" },\n body: JSON.stringify({\n id: finalId,\n title: formState.title,\n status: formState.status,\n tags,\n teams,\n body: formState.body,\n }),\n });\n router.push(`/goals/${encodeURIComponent(finalId)}`);\n } catch (e: unknown) {\n setError(errorMessage(e));\n } finally {\n setSaving(false);\n }\n }\n\n return (\n <div className=\"space-y-4\">\n <Link href=\"/goals\" className=\"text-sm font-medium hover:underline\">\n ← Back\n </Link>\n\n <GoalFormCard\n error={error}\n actions={\n <button\n onClick={() => void create()}\n disabled={saving}\n className=\"rounded-[var(--ck-radius-sm)] bg-[var(--ck-accent-red)] px-3 py-2 text-sm font-medium text-white disabled:opacity-50\"\n >\n {saving ? \"Creating…\" : \"Create\"}\n </button>\n }\n >\n <h1 className=\"text-xl font-semibold tracking-tight\">Create goal</h1>\n <GoalFormFields\n formState={formState}\n idField={{ id, setId, suggestedId: suggestedId || undefined }}\n bodyHeight=\"h-[260px]\"\n />\n </GoalFormCard>\n </div>\n );\n}\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["../../../../src/lib/errors.ts","../../../../src/lib/slugify.ts","../../../../src/components/GoalFormFields.tsx","../../../../src/lib/goals-client.ts","../../../../src/app/goals/new/page.tsx"],"sourcesContent":["/**\n * Extracts a string message from an unknown error value.\n * Used consistently across API routes and client components.\n */\nexport function errorMessage(e: unknown): string {\n return e instanceof Error ? e.message : String(e);\n}\n","/**\n * Slugify a string for use in ids, file names, or URLs.\n * Normalizes to lowercase, replaces non-alphanumeric sequences with hyphens, trims edges.\n * Uses character-by-character processing to avoid regex ReDoS.\n * @param maxLength - optional max length (default 80). Use 64 for goal ids.\n */\nexport function slugifyId(input: string, maxLength = 80): string {\n const s = String(input ?? \"\").toLowerCase().trim();\n const cap = Math.min(s.length, maxLength * 2);\n let result = \"\";\n let prevHyphen = false;\n for (let i = 0; i < cap; i++) {\n const c = s[i];\n if ((c >= \"a\" && c <= \"z\") || (c >= \"0\" && c <= \"9\")) {\n result += c;\n prevHyphen = false;\n } else if ((c === \" \" || c === \"-\" || c === \"_\") && !prevHyphen) {\n result += \"-\";\n prevHyphen = true;\n }\n }\n while (result.startsWith(\"-\")) result = result.slice(1);\n while (result.endsWith(\"-\")) result = result.slice(0, -1);\n return result.slice(0, maxLength);\n}\n","\"use client\";\n\nimport type { ReactNode } from \"react\";\nimport { useId } from \"react\";\nimport type { GoalFormState, GoalStatus } from \"@/lib/goals-client\";\n\nexport type { GoalFormState };\n\n/** Wraps goal form content with error display and action buttons. */\nexport function GoalFormCard({\n children,\n error,\n actions,\n}: {\n children: ReactNode;\n error: string | null;\n actions: ReactNode;\n}) {\n return (\n <div className=\"ck-card p-6 space-y-4\">\n {children}\n {error ? <div className=\"text-sm text-red-300\">{error}</div> : null}\n {actions}\n </div>\n );\n}\n\nconst inputClass =\n \"mt-1 w-full rounded-lg border border-[color:var(--ck-border-subtle)] bg-transparent px-3 py-2 text-sm\";\n\ntype Props = {\n formState: GoalFormState;\n /** When provided, renders the ID field (for create flow). */\n idField?: { id: string; setId: (v: string) => void; suggestedId?: string };\n /** When provided, shows updated timestamp next to body label. */\n updatedAt?: string | null;\n /** Body textarea height override (e.g. 260 for new page). */\n bodyHeight?: string;\n};\n\nexport function GoalFormFields({\n formState,\n idField,\n updatedAt,\n bodyHeight = \"h-[320px]\",\n}: Props) {\n const { title, setTitle, status, setStatus, tagsRaw, setTagsRaw, teamsRaw, setTeamsRaw, body, setBody } = formState;\n const baseId = useId();\n const idInputId = `${baseId}-id`;\n const titleInputId = `${baseId}-title`;\n const statusSelectId = `${baseId}-status`;\n const teamsInputId = `${baseId}-teams`;\n const tagsInputId = `${baseId}-tags`;\n const bodyTextareaId = `${baseId}-body`;\n return (\n <>\n {idField ? (\n <div>\n <label htmlFor={idInputId} className=\"text-xs text-[color:var(--ck-text-tertiary)]\">\n ID\n </label>\n <input\n id={idInputId}\n className={`${inputClass} font-mono`}\n value={idField.id}\n onChange={(e) => idField.setId(e.target.value)}\n placeholder=\"increase-trial-activation\"\n aria-describedby={`${baseId}-id-hint`}\n />\n <div id={`${baseId}-id-hint`} className=\"mt-1 text-xs text-[color:var(--ck-text-tertiary)]\">\n Lowercase letters, numbers, hyphens. Stored as <code className=\"font-mono\">{idField.id || \"<id>\"}.md</code>\n .\n {idField.suggestedId && !idField.id.trim() ? (\n <>\n {\" \"}\n Suggested:{\" \"}\n <button type=\"button\" className=\"underline\" onClick={() => idField.setId(idField.suggestedId ?? \"\")}>\n {idField.suggestedId}\n </button>\n </>\n ) : null}\n </div>\n </div>\n ) : null}\n\n <div>\n <label htmlFor={titleInputId} className=\"text-xs text-[color:var(--ck-text-tertiary)]\">\n Title\n </label>\n <input\n id={titleInputId}\n className={inputClass}\n value={title}\n onChange={(e) => setTitle(e.target.value)}\n placeholder={idField ? \"Increase trial activation\" : \"Goal title\"}\n />\n </div>\n\n <div className=\"grid grid-cols-1 gap-4 sm:grid-cols-3\">\n <div>\n <label htmlFor={statusSelectId} className=\"text-xs text-[color:var(--ck-text-tertiary)]\">\n Status\n </label>\n <select\n id={statusSelectId}\n className={inputClass}\n value={status}\n onChange={(e) => setStatus(e.target.value as GoalStatus)}\n aria-label=\"Goal status\"\n >\n <option value=\"planned\">Planned</option>\n <option value=\"active\">Active</option>\n <option value=\"done\">Done</option>\n </select>\n </div>\n <div>\n <label htmlFor={teamsInputId} className=\"text-xs text-[color:var(--ck-text-tertiary)]\">\n Teams (comma-separated)\n </label>\n <input\n id={teamsInputId}\n className={inputClass}\n value={teamsRaw}\n onChange={(e) => setTeamsRaw(e.target.value)}\n placeholder=\"development-team, marketing-team\"\n />\n </div>\n <div>\n <label htmlFor={tagsInputId} className=\"text-xs text-[color:var(--ck-text-tertiary)]\">\n Tags (comma-separated)\n </label>\n <input\n id={tagsInputId}\n className={inputClass}\n value={tagsRaw}\n onChange={(e) => setTagsRaw(e.target.value)}\n placeholder=\"onboarding, growth\"\n />\n </div>\n </div>\n\n <div>\n <div className=\"flex items-center justify-between\">\n <label htmlFor={bodyTextareaId} className=\"text-xs text-[color:var(--ck-text-tertiary)]\">\n Body (markdown)\n </label>\n {updatedAt != null ? (\n <div className=\"text-xs text-[color:var(--ck-text-tertiary)]\">\n {updatedAt ? `updated ${new Date(updatedAt).toLocaleString()}` : \"\"}\n </div>\n ) : null}\n </div>\n <textarea\n id={bodyTextareaId}\n className={`mt-1 ${bodyHeight} w-full rounded-lg border border-[color:var(--ck-border-subtle)] bg-transparent px-3 py-2 font-mono text-sm`}\n value={body}\n onChange={(e) => setBody(e.target.value)}\n placeholder=\"Write the goal here…\"\n />\n </div>\n </>\n );\n}\n","\"use client\";\n\nimport { useMemo, useState } from \"react\";\n\n/** Client-safe goal types and utils (no node deps). */\n\nexport type GoalStatus = \"planned\" | \"active\" | \"done\";\n\nexport type GoalFrontmatter = {\n id: string;\n title: string;\n status: GoalStatus;\n tags: string[];\n teams: string[];\n updatedAt: string;\n};\n\n/** Form state shape for GoalFormFields. */\nexport type GoalFormState = {\n title: string;\n setTitle: (v: string) => void;\n status: GoalStatus;\n setStatus: (v: GoalStatus) => void;\n tagsRaw: string;\n setTagsRaw: (v: string) => void;\n teamsRaw: string;\n setTeamsRaw: (v: string) => void;\n body: string;\n setBody: (v: string) => void;\n};\n\n/** Parses comma-separated string into trimmed non-empty array. */\nexport function parseCommaList(raw: string): string[] {\n return raw.split(\",\").map((s) => s.trim()).filter(Boolean);\n}\n\n/** Shared form state for goal create/edit. Returns formState for GoalFormFields and parsed tags/teams. */\nexport function useGoalFormState(initial?: Partial<GoalFormState>): {\n formState: GoalFormState;\n tags: string[];\n teams: string[];\n} {\n const [title, setTitle] = useState(initial?.title ?? \"\");\n const [status, setStatus] = useState<GoalStatus>(initial?.status ?? \"planned\");\n const [tagsRaw, setTagsRaw] = useState(initial?.tagsRaw ?? \"\");\n const [teamsRaw, setTeamsRaw] = useState(initial?.teamsRaw ?? \"\");\n const [body, setBody] = useState(initial?.body ?? \"\");\n\n const formState: GoalFormState = useMemo(\n () => ({\n title,\n setTitle,\n status,\n setStatus,\n tagsRaw,\n setTagsRaw,\n teamsRaw,\n setTeamsRaw,\n body,\n setBody,\n }),\n [title, status, tagsRaw, teamsRaw, body]\n );\n\n const tags = useMemo(() => parseCommaList(tagsRaw), [tagsRaw]);\n const teams = useMemo(() => parseCommaList(teamsRaw), [teamsRaw]);\n\n return { formState, tags, teams };\n}\n","\"use client\";\n\nimport Link from \"next/link\";\nimport { GoalFormCard, GoalFormFields } from \"@/components/GoalFormFields\";\nimport { useRouter } from \"next/navigation\";\nimport { useMemo, useState } from \"react\";\nimport { slugifyId } from \"@/lib/slugify\";\nimport { errorMessage } from \"@/lib/errors\";\nimport { fetchJson } from \"@/lib/fetch-json\";\nimport { useGoalFormState } from \"@/lib/goals-client\";\n\nexport default function NewGoalPage() {\n const router = useRouter();\n\n const [id, setId] = useState(\"\");\n const [error, setError] = useState<string | null>(null);\n const [saving, setSaving] = useState(false);\n\n const defaultBody =\n \"## Workflow\\n<!-- goal-workflow -->\\n- Use **Promote to inbox** to send this goal to the development-team inbox for scoping.\\n- When promoted, set goal status to **active**.\\n- Track implementation work via tickets (add links/IDs under a **Tickets** section in this goal).\\n- When development is complete (all associated tickets marked done), set goal status to **done**.\\n\\n## Tickets\\n- (add ticket links/ids)\\n\";\n const { formState, tags, teams } = useGoalFormState({ body: defaultBody });\n const { title } = formState;\n\n const suggestedId = useMemo(() => {\n const s = slugifyId(title, 64);\n return s.length >= 2 ? s : \"\";\n }, [title]);\n\n async function create() {\n setSaving(true);\n setError(null);\n const finalId = id.trim();\n try {\n await fetchJson(\"/api/goals\", {\n method: \"POST\",\n headers: { \"content-type\": \"application/json\" },\n body: JSON.stringify({\n id: finalId,\n title: formState.title,\n status: formState.status,\n tags,\n teams,\n body: formState.body,\n }),\n });\n router.push(`/goals/${encodeURIComponent(finalId)}`);\n } catch (e: unknown) {\n setError(errorMessage(e));\n } finally {\n setSaving(false);\n }\n }\n\n return (\n <div className=\"space-y-4\">\n <Link href=\"/goals\" className=\"text-sm font-medium hover:underline\">\n ← Back\n </Link>\n\n <GoalFormCard\n error={error}\n actions={\n <button\n onClick={() => void create()}\n disabled={saving}\n className=\"rounded-lg bg-[var(--ck-accent-red)] px-3 py-2 text-sm font-medium text-white disabled:opacity-50\"\n >\n {saving ? \"Creating…\" : \"Create\"}\n </button>\n }\n >\n <h1 className=\"text-xl font-semibold tracking-tight\">Create goal</h1>\n <GoalFormFields\n formState={formState}\n idField={{ id, setId, suggestedId: suggestedId || undefined }}\n bodyHeight=\"h-[260px]\"\n />\n </GoalFormCard>\n </div>\n );\n}\n"],"names":[],"mappings":"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"}
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
module.exports=[74621,a=>{"use strict";function b(a){return a instanceof Error?a.message:String(a)}a.s(["errorMessage",()=>b])},81004,a=>{"use strict";var b=a.i(87924),c=a.i(38246),d=a.i(74621),e=a.i(51200),f=a.i(50944),g=a.i(72131);async function h(){try{return{goals:(await (0,e.fetchJson)("/api/goals",{cache:"no-store"})).goals??[],error:null}}catch(a){return{goals:[],error:(0,d.errorMessage)(a)}}}function i({children:a}){return(0,b.jsx)("span",{className:"rounded-full bg-
|
|
1
|
+
module.exports=[74621,a=>{"use strict";function b(a){return a instanceof Error?a.message:String(a)}a.s(["errorMessage",()=>b])},81004,a=>{"use strict";var b=a.i(87924),c=a.i(38246),d=a.i(74621),e=a.i(51200),f=a.i(50944),g=a.i(72131);async function h(){try{return{goals:(await (0,e.fetchJson)("/api/goals",{cache:"no-store"})).goals??[],error:null}}catch(a){return{goals:[],error:(0,d.errorMessage)(a)}}}function i({children:a}){return(0,b.jsx)("span",{className:"rounded-full bg-white/5 px-2 py-0.5 text-xs text-[color:var(--ck-text-secondary)]",children:a})}function j(){let[a,e]=(0,g.useState)(null),[j,k]=(0,g.useState)(null),l=((0,f.useSearchParams)().get("team")??"").trim(),[m,n]=(0,g.useState)("all");async function o(){e(null),k(null);try{let{goals:a,error:b}=await h();k(b),e(b?[]:a)}catch(a){k((0,d.errorMessage)(a)),e([])}}(0,g.useEffect)(()=>{let a=!1;return(async()=>{try{let{goals:b,error:c}=await h();if(a)return;k(c),e(c?[]:b)}catch(b){if(a)return;k((0,d.errorMessage)(b)),e([])}})(),()=>{a=!0}},[]);let p=(0,g.useMemo)(()=>{let b=a??[];return(l&&(b=b.filter(a=>Array.isArray(a.teams)&&a.teams.includes(l))),"all"===m)?b:b.filter(a=>a.status===m)},[a,m,l]),q=(0,g.useMemo)(()=>{let b=a??[],c={all:b.length,active:0,planned:0,done:0};for(let a of b)"active"===a.status?c.active+=1:"done"===a.status?c.done+=1:c.planned+=1;return c},[a]);function r(a){return(0,b.jsx)(c.default,{href:`/goals/${encodeURIComponent(a.id)}`,className:"block ck-glass p-5 transition hover:bg-white/5",children:(0,b.jsxs)("div",{className:"flex flex-wrap items-start justify-between gap-3",children:[(0,b.jsxs)("div",{className:"min-w-0",children:[(0,b.jsx)("div",{className:"truncate text-base font-semibold text-[color:var(--ck-text-primary)]",children:a.title}),(0,b.jsxs)("div",{className:"mt-1 text-xs text-[color:var(--ck-text-tertiary)]",children:[(0,b.jsx)("span",{className:"font-mono",children:a.id}),a.updatedAt?` • updated ${new Date(a.updatedAt).toLocaleString()}`:""]})]}),(0,b.jsxs)("div",{className:"flex flex-wrap gap-2",children:[(0,b.jsx)(i,{children:a.status}),a.teams?.slice(0,3).map(a=>(0,b.jsx)(i,{children:a},a)),a.tags?.slice(0,3).map(a=>(0,b.jsxs)(i,{children:["#",a]},a))]})]})},a.id)}return(0,b.jsxs)("div",{className:"space-y-6",children:[(0,b.jsxs)("div",{className:"flex flex-wrap items-center justify-between gap-3",children:[(0,b.jsxs)("div",{children:[(0,b.jsx)("h1",{className:"text-2xl font-semibold tracking-tight",children:"Goals"}),(0,b.jsxs)("p",{className:"mt-1 text-sm text-[color:var(--ck-text-secondary)]",children:["Stored in ",(0,b.jsx)("code",{className:"font-mono",children:"~/.openclaw/workspace/notes/goals/"}),l?(0,b.jsxs)(b.Fragment,{children:[" ","• filtered by team ",(0,b.jsx)("code",{className:"font-mono",children:l})]}):null]})]}),(0,b.jsx)(c.default,{href:"/goals/new",className:"rounded-lg bg-[var(--ck-accent-red)] px-3 py-2 text-sm font-medium text-white",children:"Create goal"})]}),(0,b.jsx)("div",{className:"ck-card p-4",children:(0,b.jsxs)("div",{className:"flex flex-wrap items-center gap-3",children:[(0,b.jsx)("label",{className:"text-sm text-[color:var(--ck-text-secondary)]",children:"Status"}),(0,b.jsxs)("select",{className:"rounded-lg border border-[color:var(--ck-border-subtle)] bg-transparent px-2 py-1 text-sm",value:m,onChange:a=>n(a.target.value),children:[(0,b.jsxs)("option",{value:"all",children:["All (",q.all,")"]}),(0,b.jsxs)("option",{value:"active",children:["Active (",q.active,")"]}),(0,b.jsxs)("option",{value:"planned",children:["Planned (",q.planned,")"]}),(0,b.jsxs)("option",{value:"done",children:["Done (",q.done,")"]})]}),(0,b.jsx)("button",{className:"ml-auto text-sm font-medium hover:underline",onClick:()=>void o(),children:"Refresh"})]})}),j?(0,b.jsx)("div",{className:"ck-card p-4 text-sm text-red-300",children:j}):null,null==a&&(0,b.jsx)("div",{className:"ck-card p-6 text-sm text-[color:var(--ck-text-secondary)]",children:"Loading…"}),null!=a&&0===p.length&&(0,b.jsxs)("div",{className:"ck-card p-6",children:[(0,b.jsx)("div",{className:"text-sm text-[color:var(--ck-text-secondary)]",children:"No goals yet."}),(0,b.jsx)("div",{className:"mt-3",children:(0,b.jsx)(c.default,{href:"/goals/new",className:"text-sm font-medium hover:underline",children:"Create your first goal →"})})]}),null!=a&&p.length>0&&"all"!==m&&(0,b.jsx)("div",{className:"space-y-3",children:p.map(r)}),null!=a&&p.length>0&&"all"===m&&(0,b.jsx)("div",{className:"space-y-8",children:["active","planned","done"].map(a=>{let c=p.filter(b=>b.status===a);return c.length?(0,b.jsxs)("section",{children:[(0,b.jsx)("div",{className:"mb-2 flex items-end justify-between",children:(0,b.jsxs)("h2",{className:"text-sm font-semibold tracking-wide text-[color:var(--ck-text-secondary)] uppercase",children:[a," (",c.length,")"]})}),(0,b.jsx)("div",{className:"space-y-3",children:c.map(r)})]},a):null})})]})}a.s(["default",()=>j])}];
|
|
2
2
|
|
|
3
3
|
//# sourceMappingURL=src_2dbb3b7f._.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../src/lib/errors.ts","../../../../src/app/goals/goals-client.tsx"],"sourcesContent":["/**\n * Extracts a string message from an unknown error value.\n * Used consistently across API routes and client components.\n */\nexport function errorMessage(e: unknown): string {\n return e instanceof Error ? e.message : String(e);\n}\n","\"use client\";\n\nimport Link from \"next/link\";\nimport { errorMessage } from \"@/lib/errors\";\nimport { fetchJson } from \"@/lib/fetch-json\";\nimport { type GoalFrontmatter } from \"@/lib/goals-client\";\nimport { useSearchParams } from \"next/navigation\";\nimport { useEffect, useMemo, useState } from \"react\";\n\nasync function fetchGoals(): Promise<{ goals: GoalFrontmatter[]; error: string | null }> {\n try {\n const data = await fetchJson<{ goals?: GoalFrontmatter[] }>(\"/api/goals\", { cache: \"no-store\" });\n return { goals: data.goals ?? [], error: null };\n } catch (e: unknown) {\n return { goals: [], error: errorMessage(e) };\n }\n}\n\nfunction Badge({ children }: { children: React.ReactNode }) {\n return (\n <span className=\"rounded-full bg-[color:var(--ck-bg-glass)] px-2 py-0.5 text-xs text-[color:var(--ck-text-secondary)]\">\n {children}\n </span>\n );\n}\n\nexport default function GoalsClient() {\n const [goals, setGoals] = useState<GoalFrontmatter[] | null>(null);\n const [error, setError] = useState<string | null>(null);\n\n const searchParams = useSearchParams();\n const teamFilter = (searchParams.get(\"team\") ?? \"\").trim();\n\n const [filterStatus, setFilterStatus] = useState<string>(\"all\");\n\n useEffect(() => {\n let cancelled = false;\n (async () => {\n try {\n const { goals: g, error: err } = await fetchGoals();\n if (cancelled) return;\n setError(err);\n setGoals(err ? [] : g);\n } catch (e: unknown) {\n if (cancelled) return;\n setError(errorMessage(e));\n setGoals([]);\n }\n })();\n\n return () => {\n cancelled = true;\n };\n }, []);\n\n async function reload() {\n setGoals(null);\n setError(null);\n try {\n const { goals: g, error: err } = await fetchGoals();\n setError(err);\n setGoals(err ? [] : g);\n } catch (e: unknown) {\n setError(errorMessage(e));\n setGoals([]);\n }\n }\n\n const filtered = useMemo(() => {\n let list = goals ?? [];\n if (teamFilter) list = list.filter((g) => Array.isArray(g.teams) && g.teams.includes(teamFilter));\n if (filterStatus === \"all\") return list;\n return list.filter((g) => g.status === filterStatus);\n }, [goals, filterStatus, teamFilter]);\n\n const counts = useMemo(() => {\n const list = goals ?? [];\n const c = { all: list.length, active: 0, planned: 0, done: 0 };\n for (const g of list) {\n if (g.status === \"active\") c.active += 1;\n else if (g.status === \"done\") c.done += 1;\n else c.planned += 1;\n }\n return c;\n }, [goals]);\n\n function renderGoal(g: GoalFrontmatter) {\n return (\n <Link\n key={g.id}\n href={`/goals/${encodeURIComponent(g.id)}`}\n className=\"block ck-glass p-5 transition hover:bg-[color:var(--ck-bg-glass)]\"\n >\n <div className=\"flex flex-wrap items-start justify-between gap-3\">\n <div className=\"min-w-0\">\n <div className=\"truncate text-base font-semibold text-[color:var(--ck-text-primary)]\">{g.title}</div>\n <div className=\"mt-1 text-xs text-[color:var(--ck-text-tertiary)]\">\n <span className=\"font-mono\">{g.id}</span>\n {g.updatedAt ? ` • updated ${new Date(g.updatedAt).toLocaleString()}` : \"\"}\n </div>\n </div>\n <div className=\"flex flex-wrap gap-2\">\n <Badge>{g.status}</Badge>\n {g.teams?.slice(0, 3).map((t) => (\n <Badge key={t}>{t}</Badge>\n ))}\n {g.tags?.slice(0, 3).map((t) => (\n <Badge key={t}>#{t}</Badge>\n ))}\n </div>\n </div>\n </Link>\n );\n }\n\n return (\n <div className=\"space-y-6\">\n <div className=\"flex flex-wrap items-center justify-between gap-3\">\n <div>\n <h1 className=\"text-2xl font-semibold tracking-tight\">Goals</h1>\n <p className=\"mt-1 text-sm text-[color:var(--ck-text-secondary)]\">\n Stored in <code className=\"font-mono\">~/.openclaw/workspace/notes/goals/</code>\n {teamFilter ? (\n <>\n {\" \"}• filtered by team <code className=\"font-mono\">{teamFilter}</code>\n </>\n ) : null}\n </p>\n </div>\n <Link\n href=\"/goals/new\"\n className=\"rounded-[var(--ck-radius-sm)] bg-[var(--ck-accent-red)] px-3 py-2 text-sm font-medium text-white\"\n >\n Create goal\n </Link>\n </div>\n\n <div className=\"ck-glass p-4\">\n <div className=\"flex flex-wrap items-center gap-3\">\n <label className=\"text-sm text-[color:var(--ck-text-secondary)]\">Status</label>\n <select\n className=\"rounded-[var(--ck-radius-sm)] border border-[color:var(--ck-border-subtle)] bg-transparent px-2 py-1 text-sm\"\n value={filterStatus}\n onChange={(e) => setFilterStatus(e.target.value)}\n >\n <option value=\"all\">All ({counts.all})</option>\n <option value=\"active\">Active ({counts.active})</option>\n <option value=\"planned\">Planned ({counts.planned})</option>\n <option value=\"done\">Done ({counts.done})</option>\n </select>\n\n <button\n className=\"ml-auto text-sm font-medium hover:underline\"\n onClick={() => void reload()}\n >\n Refresh\n </button>\n </div>\n </div>\n\n {error ? (\n <div className=\"ck-glass p-4 text-sm text-red-300\">{error}</div>\n ) : null}\n\n {goals == null && (\n <div className=\"ck-glass p-6 text-sm text-[color:var(--ck-text-secondary)]\">Loading…</div>\n )}\n {goals != null && filtered.length === 0 && (\n <div className=\"ck-glass p-6\">\n <div className=\"text-sm text-[color:var(--ck-text-secondary)]\">No goals yet.</div>\n <div className=\"mt-3\">\n <Link href=\"/goals/new\" className=\"text-sm font-medium hover:underline\">\n Create your first goal →\n </Link>\n </div>\n </div>\n )}\n {goals != null && filtered.length > 0 && filterStatus !== \"all\" && (\n <div className=\"space-y-3\">{filtered.map(renderGoal)}</div>\n )}\n {goals != null && filtered.length > 0 && filterStatus === \"all\" && (\n <div className=\"space-y-8\">\n {([\"active\", \"planned\", \"done\"] as const).map((status) => {\n const section = filtered.filter((g) => g.status === status);\n if (!section.length) return null;\n return (\n <section key={status}>\n <div className=\"mb-2 flex items-end justify-between\">\n <h2 className=\"text-sm font-semibold tracking-wide text-[color:var(--ck-text-secondary)] uppercase\">\n {status} ({section.length})\n </h2>\n </div>\n <div className=\"space-y-3\">{section.map(renderGoal)}</div>\n </section>\n );\n })}\n </div>\n )}\n </div>\n );\n}\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["../../../../src/lib/errors.ts","../../../../src/app/goals/goals-client.tsx"],"sourcesContent":["/**\n * Extracts a string message from an unknown error value.\n * Used consistently across API routes and client components.\n */\nexport function errorMessage(e: unknown): string {\n return e instanceof Error ? e.message : String(e);\n}\n","\"use client\";\n\nimport Link from \"next/link\";\nimport { errorMessage } from \"@/lib/errors\";\nimport { fetchJson } from \"@/lib/fetch-json\";\nimport { type GoalFrontmatter } from \"@/lib/goals-client\";\nimport { useSearchParams } from \"next/navigation\";\nimport { useEffect, useMemo, useState } from \"react\";\n\nasync function fetchGoals(): Promise<{ goals: GoalFrontmatter[]; error: string | null }> {\n try {\n const data = await fetchJson<{ goals?: GoalFrontmatter[] }>(\"/api/goals\", { cache: \"no-store\" });\n return { goals: data.goals ?? [], error: null };\n } catch (e: unknown) {\n return { goals: [], error: errorMessage(e) };\n }\n}\n\nfunction Badge({ children }: { children: React.ReactNode }) {\n return (\n <span className=\"rounded-full bg-white/5 px-2 py-0.5 text-xs text-[color:var(--ck-text-secondary)]\">\n {children}\n </span>\n );\n}\n\nexport default function GoalsClient() {\n const [goals, setGoals] = useState<GoalFrontmatter[] | null>(null);\n const [error, setError] = useState<string | null>(null);\n\n const searchParams = useSearchParams();\n const teamFilter = (searchParams.get(\"team\") ?? \"\").trim();\n\n const [filterStatus, setFilterStatus] = useState<string>(\"all\");\n\n useEffect(() => {\n let cancelled = false;\n (async () => {\n try {\n const { goals: g, error: err } = await fetchGoals();\n if (cancelled) return;\n setError(err);\n setGoals(err ? [] : g);\n } catch (e: unknown) {\n if (cancelled) return;\n setError(errorMessage(e));\n setGoals([]);\n }\n })();\n\n return () => {\n cancelled = true;\n };\n }, []);\n\n async function reload() {\n setGoals(null);\n setError(null);\n try {\n const { goals: g, error: err } = await fetchGoals();\n setError(err);\n setGoals(err ? [] : g);\n } catch (e: unknown) {\n setError(errorMessage(e));\n setGoals([]);\n }\n }\n\n const filtered = useMemo(() => {\n let list = goals ?? [];\n if (teamFilter) list = list.filter((g) => Array.isArray(g.teams) && g.teams.includes(teamFilter));\n if (filterStatus === \"all\") return list;\n return list.filter((g) => g.status === filterStatus);\n }, [goals, filterStatus, teamFilter]);\n\n const counts = useMemo(() => {\n const list = goals ?? [];\n const c = { all: list.length, active: 0, planned: 0, done: 0 };\n for (const g of list) {\n if (g.status === \"active\") c.active += 1;\n else if (g.status === \"done\") c.done += 1;\n else c.planned += 1;\n }\n return c;\n }, [goals]);\n\n function renderGoal(g: GoalFrontmatter) {\n return (\n <Link\n key={g.id}\n href={`/goals/${encodeURIComponent(g.id)}`}\n className=\"block ck-glass p-5 transition hover:bg-white/5\"\n >\n <div className=\"flex flex-wrap items-start justify-between gap-3\">\n <div className=\"min-w-0\">\n <div className=\"truncate text-base font-semibold text-[color:var(--ck-text-primary)]\">{g.title}</div>\n <div className=\"mt-1 text-xs text-[color:var(--ck-text-tertiary)]\">\n <span className=\"font-mono\">{g.id}</span>\n {g.updatedAt ? ` • updated ${new Date(g.updatedAt).toLocaleString()}` : \"\"}\n </div>\n </div>\n <div className=\"flex flex-wrap gap-2\">\n <Badge>{g.status}</Badge>\n {g.teams?.slice(0, 3).map((t) => (\n <Badge key={t}>{t}</Badge>\n ))}\n {g.tags?.slice(0, 3).map((t) => (\n <Badge key={t}>#{t}</Badge>\n ))}\n </div>\n </div>\n </Link>\n );\n }\n\n return (\n <div className=\"space-y-6\">\n <div className=\"flex flex-wrap items-center justify-between gap-3\">\n <div>\n <h1 className=\"text-2xl font-semibold tracking-tight\">Goals</h1>\n <p className=\"mt-1 text-sm text-[color:var(--ck-text-secondary)]\">\n Stored in <code className=\"font-mono\">~/.openclaw/workspace/notes/goals/</code>\n {teamFilter ? (\n <>\n {\" \"}• filtered by team <code className=\"font-mono\">{teamFilter}</code>\n </>\n ) : null}\n </p>\n </div>\n <Link\n href=\"/goals/new\"\n className=\"rounded-lg bg-[var(--ck-accent-red)] px-3 py-2 text-sm font-medium text-white\"\n >\n Create goal\n </Link>\n </div>\n\n <div className=\"ck-card p-4\">\n <div className=\"flex flex-wrap items-center gap-3\">\n <label className=\"text-sm text-[color:var(--ck-text-secondary)]\">Status</label>\n <select\n className=\"rounded-lg border border-[color:var(--ck-border-subtle)] bg-transparent px-2 py-1 text-sm\"\n value={filterStatus}\n onChange={(e) => setFilterStatus(e.target.value)}\n >\n <option value=\"all\">All ({counts.all})</option>\n <option value=\"active\">Active ({counts.active})</option>\n <option value=\"planned\">Planned ({counts.planned})</option>\n <option value=\"done\">Done ({counts.done})</option>\n </select>\n\n <button\n className=\"ml-auto text-sm font-medium hover:underline\"\n onClick={() => void reload()}\n >\n Refresh\n </button>\n </div>\n </div>\n\n {error ? (\n <div className=\"ck-card p-4 text-sm text-red-300\">{error}</div>\n ) : null}\n\n {goals == null && (\n <div className=\"ck-card p-6 text-sm text-[color:var(--ck-text-secondary)]\">Loading…</div>\n )}\n {goals != null && filtered.length === 0 && (\n <div className=\"ck-card p-6\">\n <div className=\"text-sm text-[color:var(--ck-text-secondary)]\">No goals yet.</div>\n <div className=\"mt-3\">\n <Link href=\"/goals/new\" className=\"text-sm font-medium hover:underline\">\n Create your first goal →\n </Link>\n </div>\n </div>\n )}\n {goals != null && filtered.length > 0 && filterStatus !== \"all\" && (\n <div className=\"space-y-3\">{filtered.map(renderGoal)}</div>\n )}\n {goals != null && filtered.length > 0 && filterStatus === \"all\" && (\n <div className=\"space-y-8\">\n {([\"active\", \"planned\", \"done\"] as const).map((status) => {\n const section = filtered.filter((g) => g.status === status);\n if (!section.length) return null;\n return (\n <section key={status}>\n <div className=\"mb-2 flex items-end justify-between\">\n <h2 className=\"text-sm font-semibold tracking-wide text-[color:var(--ck-text-secondary)] uppercase\">\n {status} ({section.length})\n </h2>\n </div>\n <div className=\"space-y-3\">{section.map(renderGoal)}</div>\n </section>\n );\n })}\n </div>\n )}\n </div>\n );\n}\n"],"names":[],"mappings":"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"}
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
module.exports=[74621,a=>{"use strict";function b(a){return a instanceof Error?a.message:String(a)}a.s(["errorMessage",()=>b])},90198,a=>{"use strict";var b=a.i(87924),c=a.i(72131),d=a.i(74621),e=a.i(51200);function f(){let[a,f]=(0,c.useState)(!0),[g,h]=(0,c.useState)(!1),[i,j]=(0,c.useState)("prompt"),[k,l]=(0,c.useState)("");async function m(a){h(!0),l("");try{let b=await (0,e.fetchJson)("/api/settings/cron-installation",{method:"PUT",headers:{"content-type":"application/json"},body:JSON.stringify({value:a})});if(!b.ok)throw Error(b.error||"Save failed");j(a),l("Saved.")}catch(a){l((0,d.errorMessage)(a))}finally{h(!1)}}(0,c.useEffect)(()=>{(async()=>{f(!0),l("");try{let a=await (0,e.fetchJson)("/api/settings/cron-installation",{cache:"no-store"});if(!a.ok)throw Error(a.error||"Failed to load config");let b=String(a.value||"").trim();"off"===b||"prompt"===b||"on"===b?j(b):j("prompt")}catch(a){l((0,d.errorMessage)(a))}finally{f(!1)}})()},[]);let n=({value:c,title:d,help:e})=>(0,b.jsxs)("button",{type:"button",onClick:()=>m(c),disabled:a||g,className:`ck-glass w-full text-left px-4 py-3 transition-colors hover:bg-white/10 ${i===c?"border-[color:var(--ck-accent-red)]":""}`,children:[(0,b.jsxs)("div",{className:"flex items-baseline justify-between gap-3",children:[(0,b.jsx)("div",{className:"font-medium",children:d}),i===c?(0,b.jsx)("div",{className:"text-xs font-medium text-[color:var(--ck-accent-red)]",children:"Selected"}):null]}),(0,b.jsx)("div",{className:"mt-1 text-sm text-[color:var(--ck-text-secondary)]",children:e})]});return(0,b.jsxs)("div",{className:"space-y-3",children:[(0,b.jsx)(n,{value:"off",title:"Off",help:"Never install or reconcile recipe-defined cron jobs."}),(0,b.jsx)(n,{value:"prompt",title:"Prompt (default)",help:"Ask at scaffold time. Default answer should be No; jobs are installed disabled unless you opt in."}),(0,b.jsx)(n,{value:"on",title:"On",help:"Install/reconcile jobs during scaffold (enabledByDefault controls new jobs)."}),k?(0,b.jsx)("div",{className:"mt-2 rounded-
|
|
1
|
+
module.exports=[74621,a=>{"use strict";function b(a){return a instanceof Error?a.message:String(a)}a.s(["errorMessage",()=>b])},90198,a=>{"use strict";var b=a.i(87924),c=a.i(72131),d=a.i(74621),e=a.i(51200);function f(){let[a,f]=(0,c.useState)(!0),[g,h]=(0,c.useState)(!1),[i,j]=(0,c.useState)("prompt"),[k,l]=(0,c.useState)("");async function m(a){h(!0),l("");try{let b=await (0,e.fetchJson)("/api/settings/cron-installation",{method:"PUT",headers:{"content-type":"application/json"},body:JSON.stringify({value:a})});if(!b.ok)throw Error(b.error||"Save failed");j(a),l("Saved.")}catch(a){l((0,d.errorMessage)(a))}finally{h(!1)}}(0,c.useEffect)(()=>{(async()=>{f(!0),l("");try{let a=await (0,e.fetchJson)("/api/settings/cron-installation",{cache:"no-store"});if(!a.ok)throw Error(a.error||"Failed to load config");let b=String(a.value||"").trim();"off"===b||"prompt"===b||"on"===b?j(b):j("prompt")}catch(a){l((0,d.errorMessage)(a))}finally{f(!1)}})()},[]);let n=({value:c,title:d,help:e})=>(0,b.jsxs)("button",{type:"button",onClick:()=>m(c),disabled:a||g,className:`ck-glass w-full text-left px-4 py-3 transition-colors hover:bg-white/10 ${i===c?"border-[color:var(--ck-accent-red)]":""}`,children:[(0,b.jsxs)("div",{className:"flex items-baseline justify-between gap-3",children:[(0,b.jsx)("div",{className:"font-medium",children:d}),i===c?(0,b.jsx)("div",{className:"text-xs font-medium text-[color:var(--ck-accent-red)]",children:"Selected"}):null]}),(0,b.jsx)("div",{className:"mt-1 text-sm text-[color:var(--ck-text-secondary)]",children:e})]});return(0,b.jsxs)("div",{className:"space-y-3",children:[(0,b.jsx)(n,{value:"off",title:"Off",help:"Never install or reconcile recipe-defined cron jobs."}),(0,b.jsx)(n,{value:"prompt",title:"Prompt (default)",help:"Ask at scaffold time. Default answer should be No; jobs are installed disabled unless you opt in."}),(0,b.jsx)(n,{value:"on",title:"On",help:"Install/reconcile jobs during scaffold (enabledByDefault controls new jobs)."}),k?(0,b.jsx)("div",{className:"mt-2 rounded-lg border border-white/10 bg-white/5 p-3 text-sm",children:k}):null]})}a.s(["default",()=>f])}];
|
|
2
2
|
|
|
3
3
|
//# sourceMappingURL=src_417bc4a6._.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../src/lib/errors.ts","../../../../src/app/settings/settings-client.tsx"],"sourcesContent":["/**\n * Extracts a string message from an unknown error value.\n * Used consistently across API routes and client components.\n */\nexport function errorMessage(e: unknown): string {\n return e instanceof Error ? e.message : String(e);\n}\n","\"use client\";\n\nimport { useEffect, useState } from \"react\";\nimport { errorMessage } from \"@/lib/errors\";\nimport { fetchJson } from \"@/lib/fetch-json\";\n\ntype Mode = \"off\" | \"prompt\" | \"on\";\n\nexport default function SettingsClient() {\n const [loading, setLoading] = useState(true);\n const [saving, setSaving] = useState(false);\n const [mode, setMode] = useState<Mode>(\"prompt\");\n const [msg, setMsg] = useState<string>(\"\");\n\n useEffect(() => {\n (async () => {\n setLoading(true);\n setMsg(\"\");\n try {\n const json = await fetchJson<{ ok?: boolean; value?: string; error?: string }>(\n \"/api/settings/cron-installation\",\n { cache: \"no-store\" }\n );\n if (!json.ok) throw new Error(json.error || \"Failed to load config\");\n const v = String(json.value || \"\").trim();\n if (v === \"off\" || v === \"prompt\" || v === \"on\") setMode(v);\n else setMode(\"prompt\");\n } catch (e: unknown) {\n setMsg(errorMessage(e));\n } finally {\n setLoading(false);\n }\n })();\n }, []);\n\n async function save(next: Mode) {\n setSaving(true);\n setMsg(\"\");\n try {\n const json = await fetchJson<{ ok?: boolean; error?: string }>(\"/api/settings/cron-installation\", {\n method: \"PUT\",\n headers: { \"content-type\": \"application/json\" },\n body: JSON.stringify({ value: next }),\n });\n if (!json.ok) throw new Error(json.error || \"Save failed\");\n setMode(next);\n setMsg(\"Saved.\");\n } catch (e: unknown) {\n setMsg(errorMessage(e));\n } finally {\n setSaving(false);\n }\n }\n\n const Option = ({ value, title, help }: { value: Mode; title: string; help: string }) => (\n <button\n type=\"button\"\n onClick={() => save(value)}\n disabled={loading || saving}\n className={`ck-glass w-full text-left px-4 py-3 transition-colors hover:bg-white/10 ${\n mode === value ? \"border-[color:var(--ck-accent-red)]\" : \"\"\n }`}\n >\n <div className=\"flex items-baseline justify-between gap-3\">\n <div className=\"font-medium\">{title}</div>\n {mode === value ? (\n <div className=\"text-xs font-medium text-[color:var(--ck-accent-red)]\">Selected</div>\n ) : null}\n </div>\n <div className=\"mt-1 text-sm text-[color:var(--ck-text-secondary)]\">{help}</div>\n </button>\n );\n\n return (\n <div className=\"space-y-3\">\n <Option value=\"off\" title=\"Off\" help=\"Never install or reconcile recipe-defined cron jobs.\" />\n <Option\n value=\"prompt\"\n title=\"Prompt (default)\"\n help=\"Ask at scaffold time. Default answer should be No; jobs are installed disabled unless you opt in.\"\n />\n <Option value=\"on\" title=\"On\" help=\"Install/reconcile jobs during scaffold (enabledByDefault controls new jobs).\" />\n\n {msg ? (\n <div className=\"mt-2 rounded-
|
|
1
|
+
{"version":3,"sources":["../../../../src/lib/errors.ts","../../../../src/app/settings/settings-client.tsx"],"sourcesContent":["/**\n * Extracts a string message from an unknown error value.\n * Used consistently across API routes and client components.\n */\nexport function errorMessage(e: unknown): string {\n return e instanceof Error ? e.message : String(e);\n}\n","\"use client\";\n\nimport { useEffect, useState } from \"react\";\nimport { errorMessage } from \"@/lib/errors\";\nimport { fetchJson } from \"@/lib/fetch-json\";\n\ntype Mode = \"off\" | \"prompt\" | \"on\";\n\nexport default function SettingsClient() {\n const [loading, setLoading] = useState(true);\n const [saving, setSaving] = useState(false);\n const [mode, setMode] = useState<Mode>(\"prompt\");\n const [msg, setMsg] = useState<string>(\"\");\n\n useEffect(() => {\n (async () => {\n setLoading(true);\n setMsg(\"\");\n try {\n const json = await fetchJson<{ ok?: boolean; value?: string; error?: string }>(\n \"/api/settings/cron-installation\",\n { cache: \"no-store\" }\n );\n if (!json.ok) throw new Error(json.error || \"Failed to load config\");\n const v = String(json.value || \"\").trim();\n if (v === \"off\" || v === \"prompt\" || v === \"on\") setMode(v);\n else setMode(\"prompt\");\n } catch (e: unknown) {\n setMsg(errorMessage(e));\n } finally {\n setLoading(false);\n }\n })();\n }, []);\n\n async function save(next: Mode) {\n setSaving(true);\n setMsg(\"\");\n try {\n const json = await fetchJson<{ ok?: boolean; error?: string }>(\"/api/settings/cron-installation\", {\n method: \"PUT\",\n headers: { \"content-type\": \"application/json\" },\n body: JSON.stringify({ value: next }),\n });\n if (!json.ok) throw new Error(json.error || \"Save failed\");\n setMode(next);\n setMsg(\"Saved.\");\n } catch (e: unknown) {\n setMsg(errorMessage(e));\n } finally {\n setSaving(false);\n }\n }\n\n const Option = ({ value, title, help }: { value: Mode; title: string; help: string }) => (\n <button\n type=\"button\"\n onClick={() => save(value)}\n disabled={loading || saving}\n className={`ck-glass w-full text-left px-4 py-3 transition-colors hover:bg-white/10 ${\n mode === value ? \"border-[color:var(--ck-accent-red)]\" : \"\"\n }`}\n >\n <div className=\"flex items-baseline justify-between gap-3\">\n <div className=\"font-medium\">{title}</div>\n {mode === value ? (\n <div className=\"text-xs font-medium text-[color:var(--ck-accent-red)]\">Selected</div>\n ) : null}\n </div>\n <div className=\"mt-1 text-sm text-[color:var(--ck-text-secondary)]\">{help}</div>\n </button>\n );\n\n return (\n <div className=\"space-y-3\">\n <Option value=\"off\" title=\"Off\" help=\"Never install or reconcile recipe-defined cron jobs.\" />\n <Option\n value=\"prompt\"\n title=\"Prompt (default)\"\n help=\"Ask at scaffold time. Default answer should be No; jobs are installed disabled unless you opt in.\"\n />\n <Option value=\"on\" title=\"On\" help=\"Install/reconcile jobs during scaffold (enabledByDefault controls new jobs).\" />\n\n {msg ? (\n <div className=\"mt-2 rounded-lg border border-white/10 bg-white/5 p-3 text-sm\">\n {msg}\n </div>\n ) : null}\n </div>\n );\n}\n"],"names":[],"mappings":"uCAIO,SAAS,EAAa,CAAU,EACrC,OAAO,aAAa,MAAQ,EAAE,OAAO,CAAG,OAAO,EACjD,sECJA,EAAA,EAAA,CAAA,CAAA,OACA,EAAA,EAAA,CAAA,CAAA,OACA,EAAA,EAAA,CAAA,CAAA,OAIe,SAAS,IACtB,GAAM,CAAC,EAAS,EAAW,CAAG,CAAA,EAAA,EAAA,QAAA,AAAQ,GAAC,GACjC,CAAC,EAAQ,EAAU,CAAG,CAAA,EAAA,EAAA,QAAA,AAAQ,GAAC,GAC/B,CAAC,EAAM,EAAQ,CAAG,CAAA,EAAA,EAAA,QAAA,AAAQ,EAAO,UACjC,CAAC,EAAK,EAAO,CAAG,CAAA,EAAA,EAAA,QAAA,AAAQ,EAAS,IAuBvC,eAAe,EAAK,CAAU,EAC5B,GAAU,GACV,EAAO,IACP,GAAI,CACF,IAAM,EAAO,MAAM,CAAA,EAAA,EAAA,SAAA,AAAS,EAAmC,kCAAmC,CAChG,OAAQ,MACR,QAAS,CAAE,eAAgB,kBAAmB,EAC9C,KAAM,KAAK,SAAS,CAAC,CAAE,MAAO,CAAK,EACrC,GACA,GAAI,CAAC,EAAK,EAAE,CAAE,MAAM,AAAI,MAAM,EAAK,KAAK,EAAI,eAC5C,EAAQ,GACR,EAAO,SACT,CAAE,MAAO,EAAY,CACnB,EAAO,CAAA,EAAA,EAAA,YAAA,AAAY,EAAC,GACtB,QAAU,CACR,GAAU,EACZ,CACF,CAtCA,CAAA,EAAA,EAAA,SAAA,AAAS,EAAC,KACR,CAAC,UACC,GAAW,GACX,EAAO,IACP,GAAI,CACF,IAAM,EAAO,MAAM,CAAA,EAAA,EAAA,SAAS,AAAT,EACjB,kCACA,CAAE,MAAO,UAAW,GAEtB,GAAI,CAAC,EAAK,EAAE,CAAE,MAAM,AAAI,MAAM,EAAK,KAAK,EAAI,yBAC5C,IAAM,EAAI,OAAO,EAAK,KAAK,EAAI,IAAI,IAAI,GAC7B,QAAN,GAAqB,WAAN,GAAwB,OAAN,EAAY,EAAQ,GACpD,EAAQ,SACf,CAAE,MAAO,EAAY,CACnB,EAAO,CAAA,EAAA,EAAA,YAAA,AAAY,EAAC,GACtB,QAAU,CACR,GAAW,EACb,EACF,CAAC,EACH,EAAG,EAAE,EAqBL,IAAM,EAAS,CAAC,OAAE,CAAK,OAAE,CAAK,MAAE,CAAI,CAAgD,GAClF,CAAA,EAAA,EAAA,IAAA,EAAC,SAAA,CACC,KAAK,SACL,QAAS,IAAM,EAAK,GACpB,SAAU,GAAW,EACrB,UAAW,CAAC,wEAAwE,EAClF,IAAS,EAAQ,sCAAwC,GAAA,CACzD,WAEF,CAAA,EAAA,EAAA,IAAA,EAAC,MAAA,CAAI,UAAU,sDACb,CAAA,EAAA,EAAA,GAAA,EAAC,MAAA,CAAI,UAAU,uBAAe,IAC7B,IAAS,EACR,CAAA,EAAA,EAAA,GAAA,EAAC,MAAA,CAAI,UAAU,iEAAwD,aACrE,QAEN,CAAA,EAAA,EAAA,GAAA,EAAC,MAAA,CAAI,UAAU,8DAAsD,OAIzE,MACE,CAAA,EAAA,EAAA,IAAA,EAAC,MAAA,CAAI,UAAU,sBACb,CAAA,EAAA,EAAA,GAAA,EAAC,EAAA,CAAO,MAAM,MAAM,MAAM,MAAM,KAAK,yDACrC,CAAA,EAAA,EAAA,GAAA,EAAC,EAAA,CACC,MAAM,SACN,MAAM,mBACN,KAAK,sGAEP,CAAA,EAAA,EAAA,GAAA,EAAC,EAAA,CAAO,MAAM,KAAK,MAAM,KAAK,KAAK,iFAElC,EACC,CAAA,EAAA,EAAA,GAAA,EAAC,MAAA,CAAI,UAAU,yEACZ,IAED,OAGV"}
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
module.exports=[74621,a=>{"use strict";function b(a){return a instanceof Error?a.message:String(a)}a.s(["errorMessage",()=>b])},16627,a=>{"use strict";var b=a.i(87924),c=a.i(38246),d=a.i(50944),e=a.i(72131),f=a.i(61889),g=a.i(74621),h=a.i(51200);let i=new Set(["lead","dev","qa","tester","agent","system"]);function j({teamId:a,ticket:c,currentOwner:f}){let g=(0,d.useRouter)(),[h,i]=(0,e.useState)([]),[j,k]=(0,e.useState)(f??""),[l,m]=(0,e.useState)(!1),[n,o]=(0,e.useState)(null);(0,e.useEffect)(()=>{let b=!1;return(async()=>{try{let c=a?`/api/teams/${encodeURIComponent(a)}/tickets/assignees`:"/api/tickets/assignees",d=await fetch(c,{cache:"no-store"}),e=await d.json();if(b)return;i(Array.isArray(e.assignees)?e.assignees:[])}catch{if(b)return;i([])}})(),()=>{b=!0}},[]);let p=(0,e.useMemo)(()=>{let a=new Set(h);return f&&a.add(f),Array.from(a).sort()},[h,f]);async function q(){m(!0),o(null);try{let b=a?`/api/teams/${encodeURIComponent(a)}/tickets/assign`:"/api/tickets/assign",d=await fetch(b,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({ticket:c,assignee:j,...a?{teamId:a}:{}})}),e=await d.json();if(!d.ok)return void o(e.error||"Assign failed");g.refresh()}catch{o("Assign failed")}finally{m(!1)}}return(0,b.jsxs)("div",{className:"ck-glass p-4",children:[(0,b.jsxs)("div",{className:"flex flex-wrap items-center gap-3",children:[(0,b.jsx)("div",{className:"text-xs font-medium text-[color:var(--ck-text-tertiary)]",children:"Assignee"}),(0,b.jsxs)("select",{className:"rounded-md border border-white/10 bg-black/20 px-3 py-2 text-sm text-[color:var(--ck-text-primary)]",value:j,onChange:a=>k(a.target.value),children:[(0,b.jsx)("option",{value:"",disabled:!0,children:"Select…"}),p.map(a=>(0,b.jsx)("option",{value:a,children:a},a))]}),(0,b.jsx)("button",{type:"button",onClick:q,disabled:l||!j||j===(f??""),className:"rounded-md bg-emerald-600 px-3 py-2 text-sm font-semibold text-white hover:bg-emerald-500 disabled:cursor-not-allowed disabled:opacity-50",children:l?"Assigning…":"Assign"}),f?(0,b.jsxs)("div",{className:"text-xs text-[color:var(--ck-text-tertiary)]",children:["Currently: ",f]}):null]}),n?(0,b.jsx)("div",{className:"mt-2 text-xs text-red-300",children:n}):null]})}function k(a,b){return b||0==a.trim().length}function l(a){let l=(0,d.useRouter)(),m=(0,f.useToast)(),[n,o]=(0,e.useTransition)(),[p,q]=(0,e.useState)(null),[r,s]=(0,e.useState)(null),t=(0,e.useMemo)(()=>(function(a){let b=function(a){let b=/^## Comments\s*$/gim.exec(a);if(!b)return null;let c=b.index+b[0].length,d=a.slice(c).search(/^##\s+/m),e=-1===d?a.length:c+d;return{start:c,end:e}}(a);if(!b)return[];let c=a.slice(b.start,b.end).replace(/^\s+/,"").split("\n"),d=[],e=null,f=/^- \*\*(.+?)\*\*\s+—\s+(.*)$/;for(let a of c){let b=a.replace(/\r$/,""),c=b.match(f);if(c){e&&d.push({...e,body:e.body.trimEnd()});let a=c[1].trim(),b=c[2].trim(),f=b.indexOf(":"),g=(f>=0?b.slice(0,f):b).trim()||"unknown",h=f>=0?b.slice(f+1).trimStart():"",j=function(a){let b=a?.trim()||"unknown",c=b.match(/^(.*?)\s*\((.*?)\)\s*$/);if(c){let a=c[1].trim()||"unknown",d=c[2].trim();return{name:a,role:d&&d.toLowerCase()!=a.toLowerCase()?d:void 0,raw:b}}for(let a of[" — "," - "," | "]){if(!b.includes(a))continue;let[c,d]=b.split(a).map(a=>a.trim()).filter(Boolean);if(!c||!d)break;let e=i.has(c.toLowerCase()),f=i.has(d.toLowerCase());if(e&&!f)return{name:d,role:c,raw:b};return{name:c,role:d,raw:b}}return{name:b,raw:b}}(g);e={timestamp:a,authorName:j.name,authorRole:j.role,authorRaw:j.raw,body:h?h+"\n":""};continue}e&&(e.body+=b.replace(/^\s{0,2}/,"")+"\n")}return e&&d.push({...e,body:e.body.trimEnd()}),d})(a.markdown),[a.markdown]),[u,v]=(0,e.useState)(""),[w,x]=(0,e.useState)("");async function y(){q(null),await (0,h.fetchJson)(`/api/teams/${encodeURIComponent(a.teamId)}/tickets/move-to-goals`,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({ticket:a.ticketId})})}async function z(){q(null),await (0,h.fetchJson)(`/api/teams/${encodeURIComponent(a.teamId)}/tickets/delete`,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({ticket:a.ticketId})})}async function A(b){q(null),await (0,h.fetchJson)(`/api/teams/${encodeURIComponent(a.teamId)}/tickets/move`,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({ticket:a.ticketId,to:b})})}async function B(){q(null);let b=w.trim();if(!b)throw Error("Comment cannot be empty.");await (0,h.fetchJson)(`/api/teams/${encodeURIComponent(a.teamId)}/tickets/comment`,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({ticket:a.ticketId,author:u.trim()||void 0,comment:b})}),x(""),m.push({kind:"success",message:"Comment added."}),l.refresh()}return(0,b.jsxs)("div",{className:"space-y-4",children:[(0,b.jsxs)("div",{className:"flex items-center justify-between gap-3",children:[(0,b.jsx)(c.default,{href:a.backHref??"/tickets",className:"text-sm font-medium hover:underline",children:"← Back"}),(0,b.jsx)("span",{className:"text-xs text-[color:var(--ck-text-tertiary)]",children:a.file})]}),p?(0,b.jsx)("div",{className:"ck-glass border border-[color:var(--ck-border-strong)] p-3 text-sm text-[color:var(--ck-text-primary)]",children:p}):null,(0,b.jsxs)("div",{className:"ck-glass p-6",children:[(0,b.jsxs)("div",{className:"flex flex-wrap items-center justify-between gap-3",children:[(0,b.jsx)("div",{className:"text-sm font-semibold text-[color:var(--ck-text-primary)]",children:"Ticket"}),(0,b.jsxs)("div",{className:"flex flex-wrap items-center justify-end gap-2",children:[(0,b.jsxs)("label",{className:"flex items-center gap-2 text-xs text-[color:var(--ck-text-secondary)]",children:[(0,b.jsx)("span",{children:"Status"}),(0,b.jsxs)("select",{className:"rounded border border-[color:var(--ck-border-subtle)] bg-black/20 px-2 py-1 text-xs text-[color:var(--ck-text-primary)]",disabled:n,value:a.stage,onChange:b=>{let c=b.target.value;if(c!==a.stage){if("done"===c&&!window.confirm("Mark this ticket done? This will move the file to work/done and add an audit comment."))return;o(()=>{A(c).then(()=>{m.push({kind:"success",message:`Status updated to ${c}.`}),l.refresh()}).catch(a=>q((0,g.errorMessage)(a)))})}},children:[(0,b.jsx)("option",{value:"backlog",children:"backlog"}),(0,b.jsx)("option",{value:"in-progress",children:"in-progress"}),(0,b.jsx)("option",{value:"testing",children:"testing"}),(0,b.jsx)("option",{value:"done",children:"done"})]})]}),(0,b.jsx)("button",{className:"rounded border border-[color:var(--ck-border-subtle)] px-3 py-1.5 text-xs font-medium text-[color:var(--ck-text-secondary)] hover:border-[color:var(--ck-border-strong)]",onClick:()=>s({kind:"goals"}),disabled:n,children:"Move to Goals"}),(0,b.jsx)("button",{className:"rounded border border-[color:var(--ck-accent-red)] bg-[color:var(--ck-accent-red-soft)] px-3 py-1.5 text-xs font-medium text-[color:var(--ck-accent-red)] hover:bg-[color:var(--ck-accent-red-soft-strong)]",onClick:()=>s({kind:"delete"}),disabled:n,children:"Delete Ticket"})]})]}),void 0!==a.currentOwner?(0,b.jsx)("div",{className:"mt-4",children:(0,b.jsx)(j,{teamId:a.teamId,ticket:a.ticketId,currentOwner:a.currentOwner??null})}):null,(0,b.jsxs)("div",{className:"mt-6 border-t border-[color:var(--ck-border-subtle)] pt-6",children:[(0,b.jsxs)("div",{className:"flex items-center justify-between gap-3",children:[(0,b.jsx)("div",{className:"text-sm font-semibold text-[color:var(--ck-text-primary)]",children:"Comments"}),(0,b.jsx)("div",{className:"text-xs text-[color:var(--ck-text-tertiary)]",children:t.length})]}),t.length?(0,b.jsx)("div",{className:"mt-3 space-y-3",children:t.map((a,c)=>(0,b.jsxs)("div",{className:"rounded-[var(--ck-radius-sm)] border border-[color:var(--ck-border-subtle)] bg-black/10 p-3",children:[(0,b.jsxs)("div",{className:"flex flex-wrap items-baseline justify-between gap-2",children:[(0,b.jsxs)("div",{className:"flex flex-wrap items-baseline gap-2",children:[(0,b.jsx)("div",{className:"text-xs font-medium text-[color:var(--ck-text-primary)]",children:a.authorName}),a.authorRole?(0,b.jsx)("div",{className:"rounded border border-[color:var(--ck-border-subtle)] bg-black/10 px-1.5 py-0.5 text-[10px] font-medium text-[color:var(--ck-text-tertiary)]",children:a.authorRole}):null]}),(0,b.jsx)("div",{className:"text-xs text-[color:var(--ck-text-tertiary)]",children:a.timestamp})]}),(0,b.jsx)("div",{className:"mt-2 whitespace-pre-wrap break-words text-sm leading-6 text-[color:var(--ck-text-secondary)]",children:a.body})]},`${a.timestamp}-${c}`))}):(0,b.jsx)("div",{className:"mt-3 text-sm text-[color:var(--ck-text-secondary)]",children:"No comments yet."}),(0,b.jsxs)("div",{className:"mt-4 border-t border-[color:var(--ck-border-subtle)] pt-4",children:[(0,b.jsx)("div",{className:"text-sm font-semibold text-[color:var(--ck-text-primary)]",children:"Add comment"}),(0,b.jsxs)("div",{className:"mt-3 grid gap-3",children:[(0,b.jsxs)("div",{className:"grid gap-1",children:[(0,b.jsx)("label",{className:"text-xs font-medium text-[color:var(--ck-text-secondary)]",htmlFor:"ck-comment-author",children:"Author (optional)"}),(0,b.jsx)("input",{id:"ck-comment-author",value:u,onChange:a=>v(a.target.value),placeholder:"unknown",className:"w-full rounded border border-[color:var(--ck-border-subtle)] bg-black/20 px-3 py-2 text-sm text-[color:var(--ck-text-primary)] outline-none focus:border-[color:var(--ck-border-strong)]",disabled:n})]}),(0,b.jsxs)("div",{className:"grid gap-1",children:[(0,b.jsx)("label",{className:"text-xs font-medium text-[color:var(--ck-text-secondary)]",htmlFor:"ck-comment-body",children:"Comment"}),(0,b.jsx)("textarea",{id:"ck-comment-body",value:w,onChange:a=>x(a.target.value),rows:4,className:"w-full rounded border border-[color:var(--ck-border-subtle)] bg-black/20 px-3 py-2 text-sm text-[color:var(--ck-text-primary)] outline-none focus:border-[color:var(--ck-border-strong)]",disabled:n})]}),(0,b.jsx)("div",{className:"flex items-center justify-end",children:(0,b.jsx)("button",{type:"button","aria-busy":n,className:"rounded-[var(--ck-radius-sm)] bg-[color:var(--ck-accent)] px-3 py-2 text-xs font-semibold text-black transition hover:brightness-110 active:brightness-95 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[color:var(--ck-border-strong)] focus-visible:ring-offset-2 focus-visible:ring-offset-black/30 disabled:cursor-not-allowed disabled:border disabled:border-[color:var(--ck-border-subtle)] disabled:bg-[color:var(--ck-bg-glass)] disabled:text-[color:var(--ck-text-tertiary)]",onClick:()=>{o(()=>{B().catch(a=>q((0,g.errorMessage)(a)))})},disabled:k(w,n),children:n?"Posting…":"Post comment"})})]})]})]})]}),(0,b.jsx)("div",{className:"ck-glass p-6",children:(0,b.jsx)("pre",{className:"whitespace-pre-wrap break-words text-sm leading-6 text-[color:var(--ck-text-primary)]",children:a.markdown})}),r?(0,b.jsx)("div",{className:"fixed inset-0 z-50 flex items-center justify-center bg-black/60 p-4",children:(0,b.jsxs)("div",{className:"ck-glass w-full max-w-lg rounded-[var(--ck-radius-md)] border border-[color:var(--ck-border-strong)] p-4",children:[(0,b.jsx)("div",{className:"text-sm font-semibold text-[color:var(--ck-text-primary)]",children:"goals"===r.kind?"Move to Goals":"Delete ticket"}),(0,b.jsx)("div",{className:"mt-2 text-sm text-[color:var(--ck-text-secondary)]",children:"goals"===r.kind?(0,b.jsxs)(b.Fragment,{children:["This will move the ticket out of the work lanes into ",(0,b.jsx)("code",{children:"work/goals/"})," so it won’t be picked up by automation."]}):(0,b.jsx)(b.Fragment,{children:"This will permanently remove the ticket markdown file. Assignment stubs (if any) will be archived."})}),(0,b.jsxs)("div",{className:"mt-4 flex items-center justify-end gap-2",children:[(0,b.jsx)("button",{className:"rounded border border-[color:var(--ck-border-subtle)] px-3 py-1.5 text-xs text-[color:var(--ck-text-secondary)]",onClick:()=>s(null),disabled:n,children:"Cancel"}),(0,b.jsx)("button",{className:"delete"===r.kind?"rounded bg-[color:var(--ck-accent-red)] px-3 py-1.5 text-xs font-medium text-white":"rounded bg-[color:var(--ck-accent)] px-3 py-1.5 text-xs font-medium text-black",onClick:()=>{let b=r.kind;s(null),o(()=>{("goals"===b?y():z()).then(()=>{m.push({kind:"success",message:"delete"===b?"Ticket deleted.":"Moved to Goals."}),"delete"===b?l.push(a.backHref??"/tickets"):l.refresh()}).catch(a=>q((0,g.errorMessage)(a)))})},disabled:n,children:"Confirm"})]})]})}):null]})}a.s(["TicketDetailClient",()=>l,"isPostCommentDisabled",()=>k],16627)}];
|
|
1
|
+
module.exports=[74621,a=>{"use strict";function b(a){return a instanceof Error?a.message:String(a)}a.s(["errorMessage",()=>b])},16627,a=>{"use strict";var b=a.i(87924),c=a.i(38246),d=a.i(50944),e=a.i(72131),f=a.i(61889),g=a.i(74621),h=a.i(51200);let i=new Set(["lead","dev","qa","tester","agent","system"]);function j({teamId:a,ticket:c,currentOwner:f}){let g=(0,d.useRouter)(),[h,i]=(0,e.useState)([]),[j,k]=(0,e.useState)(f??""),[l,m]=(0,e.useState)(!1),[n,o]=(0,e.useState)(null);(0,e.useEffect)(()=>{let b=!1;return(async()=>{try{let c=a?`/api/teams/${encodeURIComponent(a)}/tickets/assignees`:"/api/tickets/assignees",d=await fetch(c,{cache:"no-store"}),e=await d.json();if(b)return;i(Array.isArray(e.assignees)?e.assignees:[])}catch{if(b)return;i([])}})(),()=>{b=!0}},[]);let p=(0,e.useMemo)(()=>{let a=new Set(h);return f&&a.add(f),Array.from(a).sort()},[h,f]);async function q(){m(!0),o(null);try{let b=a?`/api/teams/${encodeURIComponent(a)}/tickets/assign`:"/api/tickets/assign",d=await fetch(b,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({ticket:c,assignee:j,...a?{teamId:a}:{}})}),e=await d.json();if(!d.ok)return void o(e.error||"Assign failed");g.refresh()}catch{o("Assign failed")}finally{m(!1)}}return(0,b.jsxs)("div",{className:"ck-card p-4",children:[(0,b.jsxs)("div",{className:"flex flex-wrap items-center gap-3",children:[(0,b.jsx)("div",{className:"text-xs font-medium text-[color:var(--ck-text-tertiary)]",children:"Assignee"}),(0,b.jsxs)("select",{className:"rounded-md border border-white/10 bg-white/5 px-3 py-2 text-sm text-[color:var(--ck-text-primary)]",value:j,onChange:a=>k(a.target.value),children:[(0,b.jsx)("option",{value:"",disabled:!0,children:"Select…"}),p.map(a=>(0,b.jsx)("option",{value:a,children:a},a))]}),(0,b.jsx)("button",{type:"button",onClick:q,disabled:l||!j||j===(f??""),className:"rounded-md bg-emerald-600 px-3 py-2 text-sm font-semibold text-white hover:bg-emerald-500 disabled:cursor-not-allowed disabled:opacity-50",children:l?"Assigning…":"Assign"}),f?(0,b.jsxs)("div",{className:"text-xs text-[color:var(--ck-text-tertiary)]",children:["Currently: ",f]}):null]}),n?(0,b.jsx)("div",{className:"mt-2 text-xs text-red-300",children:n}):null]})}function k(a,b){return b||0==a.trim().length}function l(a){let l=(0,d.useRouter)(),m=(0,f.useToast)(),[n,o]=(0,e.useTransition)(),[p,q]=(0,e.useState)(null),[r,s]=(0,e.useState)(null),t=(0,e.useMemo)(()=>(function(a){let b=function(a){let b=/^## Comments\s*$/gim.exec(a);if(!b)return null;let c=b.index+b[0].length,d=a.slice(c).search(/^##\s+/m),e=-1===d?a.length:c+d;return{start:c,end:e}}(a);if(!b)return[];let c=a.slice(b.start,b.end).replace(/^\s+/,"").split("\n"),d=[],e=null,f=/^- \*\*(.+?)\*\*\s+—\s+(.*)$/;for(let a of c){let b=a.replace(/\r$/,""),c=b.match(f);if(c){e&&d.push({...e,body:e.body.trimEnd()});let a=c[1].trim(),b=c[2].trim(),f=b.indexOf(":"),g=(f>=0?b.slice(0,f):b).trim()||"unknown",h=f>=0?b.slice(f+1).trimStart():"",j=function(a){let b=a?.trim()||"unknown",c=b.match(/^(.*?)\s*\((.*?)\)\s*$/);if(c){let a=c[1].trim()||"unknown",d=c[2].trim();return{name:a,role:d&&d.toLowerCase()!=a.toLowerCase()?d:void 0,raw:b}}for(let a of[" — "," - "," | "]){if(!b.includes(a))continue;let[c,d]=b.split(a).map(a=>a.trim()).filter(Boolean);if(!c||!d)break;let e=i.has(c.toLowerCase()),f=i.has(d.toLowerCase());if(e&&!f)return{name:d,role:c,raw:b};return{name:c,role:d,raw:b}}return{name:b,raw:b}}(g);e={timestamp:a,authorName:j.name,authorRole:j.role,authorRaw:j.raw,body:h?h+"\n":""};continue}e&&(e.body+=b.replace(/^\s{0,2}/,"")+"\n")}return e&&d.push({...e,body:e.body.trimEnd()}),d})(a.markdown),[a.markdown]),[u,v]=(0,e.useState)(""),[w,x]=(0,e.useState)("");async function y(){q(null),await (0,h.fetchJson)(`/api/teams/${encodeURIComponent(a.teamId)}/tickets/move-to-goals`,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({ticket:a.ticketId})})}async function z(){q(null),await (0,h.fetchJson)(`/api/teams/${encodeURIComponent(a.teamId)}/tickets/delete`,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({ticket:a.ticketId})})}async function A(b){q(null),await (0,h.fetchJson)(`/api/teams/${encodeURIComponent(a.teamId)}/tickets/move`,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({ticket:a.ticketId,to:b})})}async function B(){q(null);let b=w.trim();if(!b)throw Error("Comment cannot be empty.");await (0,h.fetchJson)(`/api/teams/${encodeURIComponent(a.teamId)}/tickets/comment`,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({ticket:a.ticketId,author:u.trim()||void 0,comment:b})}),x(""),m.push({kind:"success",message:"Comment added."}),l.refresh()}return(0,b.jsxs)("div",{className:"space-y-4",children:[(0,b.jsxs)("div",{className:"flex items-center justify-between gap-3",children:[(0,b.jsx)(c.default,{href:a.backHref??"/tickets",className:"text-sm font-medium hover:underline",children:"← Back"}),(0,b.jsx)("span",{className:"text-xs text-[color:var(--ck-text-tertiary)]",children:a.file})]}),p?(0,b.jsx)("div",{className:"ck-card border border-[color:var(--ck-border-strong)] p-3 text-sm text-[color:var(--ck-text-primary)]",children:p}):null,(0,b.jsxs)("div",{className:"ck-card p-6",children:[(0,b.jsxs)("div",{className:"flex flex-wrap items-center justify-between gap-3",children:[(0,b.jsx)("div",{className:"text-sm font-semibold text-[color:var(--ck-text-primary)]",children:"Ticket"}),(0,b.jsxs)("div",{className:"flex flex-wrap items-center justify-end gap-2",children:[(0,b.jsxs)("label",{className:"flex items-center gap-2 text-xs text-[color:var(--ck-text-secondary)]",children:[(0,b.jsx)("span",{children:"Status"}),(0,b.jsxs)("select",{className:"rounded border border-[color:var(--ck-border-subtle)] bg-white/5 px-2 py-1 text-xs text-[color:var(--ck-text-primary)]",disabled:n,value:a.stage,onChange:b=>{let c=b.target.value;if(c!==a.stage){if("done"===c&&!window.confirm("Mark this ticket done? This will move the file to work/done and add an audit comment."))return;o(()=>{A(c).then(()=>{m.push({kind:"success",message:`Status updated to ${c}.`}),l.refresh()}).catch(a=>q((0,g.errorMessage)(a)))})}},children:[(0,b.jsx)("option",{value:"backlog",children:"backlog"}),(0,b.jsx)("option",{value:"in-progress",children:"in-progress"}),(0,b.jsx)("option",{value:"testing",children:"testing"}),(0,b.jsx)("option",{value:"done",children:"done"})]})]}),(0,b.jsx)("button",{className:"rounded border border-[color:var(--ck-border-subtle)] px-3 py-1.5 text-xs font-medium text-[color:var(--ck-text-secondary)] hover:border-[color:var(--ck-border-strong)]",onClick:()=>s({kind:"goals"}),disabled:n,children:"Move to Goals"}),(0,b.jsx)("button",{className:"rounded border border-[color:var(--ck-accent-red)] bg-[color:var(--ck-accent-red-soft)] px-3 py-1.5 text-xs font-medium text-[color:var(--ck-accent-red)] hover:bg-[color:var(--ck-accent-red-soft-strong)]",onClick:()=>s({kind:"delete"}),disabled:n,children:"Delete Ticket"})]})]}),void 0!==a.currentOwner?(0,b.jsx)("div",{className:"mt-4",children:(0,b.jsx)(j,{teamId:a.teamId,ticket:a.ticketId,currentOwner:a.currentOwner??null})}):null,(0,b.jsxs)("div",{className:"mt-6 border-t border-[color:var(--ck-border-subtle)] pt-6",children:[(0,b.jsxs)("div",{className:"flex items-center justify-between gap-3",children:[(0,b.jsx)("div",{className:"text-sm font-semibold text-[color:var(--ck-text-primary)]",children:"Comments"}),(0,b.jsx)("div",{className:"text-xs text-[color:var(--ck-text-tertiary)]",children:t.length})]}),t.length?(0,b.jsx)("div",{className:"mt-3 space-y-3",children:t.map((a,c)=>(0,b.jsxs)("div",{className:"rounded-lg border border-[color:var(--ck-border-subtle)] bg-black/10 p-3",children:[(0,b.jsxs)("div",{className:"flex flex-wrap items-baseline justify-between gap-2",children:[(0,b.jsxs)("div",{className:"flex flex-wrap items-baseline gap-2",children:[(0,b.jsx)("div",{className:"text-xs font-medium text-[color:var(--ck-text-primary)]",children:a.authorName}),a.authorRole?(0,b.jsx)("div",{className:"rounded border border-[color:var(--ck-border-subtle)] bg-black/10 px-1.5 py-0.5 text-[10px] font-medium text-[color:var(--ck-text-tertiary)]",children:a.authorRole}):null]}),(0,b.jsx)("div",{className:"text-xs text-[color:var(--ck-text-tertiary)]",children:a.timestamp})]}),(0,b.jsx)("div",{className:"mt-2 whitespace-pre-wrap break-words text-sm leading-6 text-[color:var(--ck-text-secondary)]",children:a.body})]},`${a.timestamp}-${c}`))}):(0,b.jsx)("div",{className:"mt-3 text-sm text-[color:var(--ck-text-secondary)]",children:"No comments yet."}),(0,b.jsxs)("div",{className:"mt-4 border-t border-[color:var(--ck-border-subtle)] pt-4",children:[(0,b.jsx)("div",{className:"text-sm font-semibold text-[color:var(--ck-text-primary)]",children:"Add comment"}),(0,b.jsxs)("div",{className:"mt-3 grid gap-3",children:[(0,b.jsxs)("div",{className:"grid gap-1",children:[(0,b.jsx)("label",{className:"text-xs font-medium text-[color:var(--ck-text-secondary)]",htmlFor:"ck-comment-author",children:"Author (optional)"}),(0,b.jsx)("input",{id:"ck-comment-author",value:u,onChange:a=>v(a.target.value),placeholder:"unknown",className:"w-full rounded border border-[color:var(--ck-border-subtle)] bg-white/5 px-3 py-2 text-sm text-[color:var(--ck-text-primary)] outline-none focus:border-[color:var(--ck-border-strong)]",disabled:n})]}),(0,b.jsxs)("div",{className:"grid gap-1",children:[(0,b.jsx)("label",{className:"text-xs font-medium text-[color:var(--ck-text-secondary)]",htmlFor:"ck-comment-body",children:"Comment"}),(0,b.jsx)("textarea",{id:"ck-comment-body",value:w,onChange:a=>x(a.target.value),rows:4,className:"w-full rounded border border-[color:var(--ck-border-subtle)] bg-white/5 px-3 py-2 text-sm text-[color:var(--ck-text-primary)] outline-none focus:border-[color:var(--ck-border-strong)]",disabled:n})]}),(0,b.jsx)("div",{className:"flex items-center justify-end",children:(0,b.jsx)("button",{type:"button","aria-busy":n,className:"rounded-lg bg-[color:var(--ck-accent)] px-3 py-2 text-xs font-semibold text-black transition hover:brightness-110 active:brightness-95 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[color:var(--ck-border-strong)] focus-visible:ring-offset-2 focus-visible:ring-offset-black/30 disabled:cursor-not-allowed disabled:border disabled:border-[color:var(--ck-border-subtle)] disabled:bg-white/5 disabled:text-[color:var(--ck-text-tertiary)]",onClick:()=>{o(()=>{B().catch(a=>q((0,g.errorMessage)(a)))})},disabled:k(w,n),children:n?"Posting…":"Post comment"})})]})]})]})]}),(0,b.jsx)("div",{className:"ck-card p-6",children:(0,b.jsx)("pre",{className:"whitespace-pre-wrap break-words text-sm leading-6 text-[color:var(--ck-text-primary)]",children:a.markdown})}),r?(0,b.jsx)("div",{className:"fixed inset-0 z-50 flex items-center justify-center bg-black/60 p-4",children:(0,b.jsxs)("div",{className:"ck-card w-full max-w-lg rounded-2xl border border-[color:var(--ck-border-strong)] p-4",children:[(0,b.jsx)("div",{className:"text-sm font-semibold text-[color:var(--ck-text-primary)]",children:"goals"===r.kind?"Move to Goals":"Delete ticket"}),(0,b.jsx)("div",{className:"mt-2 text-sm text-[color:var(--ck-text-secondary)]",children:"goals"===r.kind?(0,b.jsxs)(b.Fragment,{children:["This will move the ticket out of the work lanes into ",(0,b.jsx)("code",{children:"work/goals/"})," so it won’t be picked up by automation."]}):(0,b.jsx)(b.Fragment,{children:"This will permanently remove the ticket markdown file. Assignment stubs (if any) will be archived."})}),(0,b.jsxs)("div",{className:"mt-4 flex items-center justify-end gap-2",children:[(0,b.jsx)("button",{className:"rounded border border-[color:var(--ck-border-subtle)] px-3 py-1.5 text-xs text-[color:var(--ck-text-secondary)]",onClick:()=>s(null),disabled:n,children:"Cancel"}),(0,b.jsx)("button",{className:"delete"===r.kind?"rounded bg-[color:var(--ck-accent-red)] px-3 py-1.5 text-xs font-medium text-white":"rounded bg-[color:var(--ck-accent)] px-3 py-1.5 text-xs font-medium text-black",onClick:()=>{let b=r.kind;s(null),o(()=>{("goals"===b?y():z()).then(()=>{m.push({kind:"success",message:"delete"===b?"Ticket deleted.":"Moved to Goals."}),"delete"===b?l.push(a.backHref??"/tickets"):l.refresh()}).catch(a=>q((0,g.errorMessage)(a)))})},disabled:n,children:"Confirm"})]})]})}):null]})}a.s(["TicketDetailClient",()=>l,"isPostCommentDisabled",()=>k],16627)}];
|
|
2
2
|
|
|
3
3
|
//# sourceMappingURL=src_59477309._.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../src/lib/errors.ts","../../../../src/app/tickets/TicketDetailClient.tsx","../../../../src/lib/ticket-comments.ts","../../../../src/app/tickets/%5Bticket%5D/TicketAssignControl.tsx"],"sourcesContent":["/**\n * Extracts a string message from an unknown error value.\n * Used consistently across API routes and client components.\n */\nexport function errorMessage(e: unknown): string {\n return e instanceof Error ? e.message : String(e);\n}\n","\"use client\";\n\nimport Link from \"next/link\";\nimport { useRouter } from \"next/navigation\";\nimport { useMemo, useState, useTransition } from \"react\";\n\nimport { useToast } from \"@/components/ToastProvider\";\nimport { errorMessage } from \"@/lib/errors\";\nimport { fetchJson } from \"@/lib/fetch-json\";\nimport type { TicketStage } from \"@/lib/tickets\";\nimport { parseTicketComments } from \"@/lib/ticket-comments\";\nimport { TicketAssignControl } from \"@/app/tickets/[ticket]/TicketAssignControl\";\n\nexport function isPostCommentDisabled(commentBody: string, isPending: boolean) {\n return isPending || commentBody.trim().length == 0;\n}\n\nexport function TicketDetailClient(props: {\n teamId: string;\n ticketId: string;\n file: string;\n markdown: string;\n stage: TicketStage;\n backHref?: string;\n currentOwner?: string | null;\n}) {\n const router = useRouter();\n const toast = useToast();\n const [isPending, startTransition] = useTransition();\n const [error, setError] = useState<string | null>(null);\n const [confirm, setConfirm] = useState<null | { kind: \"goals\" | \"delete\" }>(null);\n\n const comments = useMemo(() => parseTicketComments(props.markdown), [props.markdown]);\n\n const [commentAuthor, setCommentAuthor] = useState<string>(\"\");\n const [commentBody, setCommentBody] = useState<string>(\"\");\n\n async function moveToGoals() {\n setError(null);\n await fetchJson(`/api/teams/${encodeURIComponent(props.teamId)}/tickets/move-to-goals`, {\n method: \"POST\",\n headers: { \"content-type\": \"application/json\" },\n body: JSON.stringify({ ticket: props.ticketId }),\n });\n }\n\n async function deleteTicket() {\n setError(null);\n await fetchJson(`/api/teams/${encodeURIComponent(props.teamId)}/tickets/delete`, {\n method: \"POST\",\n headers: { \"content-type\": \"application/json\" },\n body: JSON.stringify({ ticket: props.ticketId }),\n });\n }\n\n async function moveTicket(to: TicketStage) {\n setError(null);\n await fetchJson(`/api/teams/${encodeURIComponent(props.teamId)}/tickets/move`, {\n method: \"POST\",\n headers: { \"content-type\": \"application/json\" },\n body: JSON.stringify({ ticket: props.ticketId, to }),\n });\n }\n\n async function submitComment() {\n setError(null);\n const body = commentBody.trim();\n if (!body) throw new Error(\"Comment cannot be empty.\");\n\n await fetchJson(`/api/teams/${encodeURIComponent(props.teamId)}/tickets/comment`, {\n method: \"POST\",\n headers: { \"content-type\": \"application/json\" },\n body: JSON.stringify({\n ticket: props.ticketId,\n author: commentAuthor.trim() || undefined,\n comment: body,\n }),\n });\n\n setCommentBody(\"\");\n toast.push({ kind: \"success\", message: \"Comment added.\" });\n router.refresh();\n }\n\n return (\n <div className=\"space-y-4\">\n <div className=\"flex items-center justify-between gap-3\">\n <Link href={props.backHref ?? \"/tickets\"} className=\"text-sm font-medium hover:underline\">\n ← Back\n </Link>\n <span className=\"text-xs text-[color:var(--ck-text-tertiary)]\">{props.file}</span>\n </div>\n\n {error ? (\n <div className=\"ck-glass border border-[color:var(--ck-border-strong)] p-3 text-sm text-[color:var(--ck-text-primary)]\">\n {error}\n </div>\n ) : null}\n\n <div className=\"ck-glass p-6\">\n <div className=\"flex flex-wrap items-center justify-between gap-3\">\n <div className=\"text-sm font-semibold text-[color:var(--ck-text-primary)]\">Ticket</div>\n <div className=\"flex flex-wrap items-center justify-end gap-2\">\n <label className=\"flex items-center gap-2 text-xs text-[color:var(--ck-text-secondary)]\">\n <span>Status</span>\n <select\n className=\"rounded border border-[color:var(--ck-border-subtle)] bg-black/20 px-2 py-1 text-xs text-[color:var(--ck-text-primary)]\"\n disabled={isPending}\n value={props.stage}\n onChange={(e) => {\n const next = e.target.value as TicketStage;\n if (next === props.stage) return;\n\n if (next === \"done\") {\n const ok = window.confirm(\n \"Mark this ticket done? This will move the file to work/done and add an audit comment.\",\n );\n if (!ok) return;\n }\n\n startTransition(() => {\n moveTicket(next)\n .then(() => {\n toast.push({ kind: \"success\", message: `Status updated to ${next}.` });\n router.refresh();\n })\n .catch((err: unknown) => setError(errorMessage(err)));\n });\n }}\n >\n <option value=\"backlog\">backlog</option>\n <option value=\"in-progress\">in-progress</option>\n <option value=\"testing\">testing</option>\n <option value=\"done\">done</option>\n </select>\n </label>\n\n <button\n className=\"rounded border border-[color:var(--ck-border-subtle)] px-3 py-1.5 text-xs font-medium text-[color:var(--ck-text-secondary)] hover:border-[color:var(--ck-border-strong)]\"\n onClick={() => setConfirm({ kind: \"goals\" })}\n disabled={isPending}\n >\n Move to Goals\n </button>\n <button\n className=\"rounded border border-[color:var(--ck-accent-red)] bg-[color:var(--ck-accent-red-soft)] px-3 py-1.5 text-xs font-medium text-[color:var(--ck-accent-red)] hover:bg-[color:var(--ck-accent-red-soft-strong)]\"\n onClick={() => setConfirm({ kind: \"delete\" })}\n disabled={isPending}\n >\n Delete Ticket\n </button>\n </div>\n </div>\n\n {props.currentOwner !== undefined ? (\n <div className=\"mt-4\">\n <TicketAssignControl teamId={props.teamId} ticket={props.ticketId} currentOwner={props.currentOwner ?? null} />\n </div>\n ) : null}\n\n <div className=\"mt-6 border-t border-[color:var(--ck-border-subtle)] pt-6\">\n <div className=\"flex items-center justify-between gap-3\">\n <div className=\"text-sm font-semibold text-[color:var(--ck-text-primary)]\">Comments</div>\n <div className=\"text-xs text-[color:var(--ck-text-tertiary)]\">{comments.length}</div>\n </div>\n\n {comments.length ? (\n <div className=\"mt-3 space-y-3\">\n {comments.map((c, idx) => (\n <div\n key={`${c.timestamp}-${idx}`}\n className=\"rounded-[var(--ck-radius-sm)] border border-[color:var(--ck-border-subtle)] bg-black/10 p-3\"\n >\n <div className=\"flex flex-wrap items-baseline justify-between gap-2\">\n <div className=\"flex flex-wrap items-baseline gap-2\">\n <div className=\"text-xs font-medium text-[color:var(--ck-text-primary)]\">{c.authorName}</div>\n {c.authorRole ? (\n <div className=\"rounded border border-[color:var(--ck-border-subtle)] bg-black/10 px-1.5 py-0.5 text-[10px] font-medium text-[color:var(--ck-text-tertiary)]\">\n {c.authorRole}\n </div>\n ) : null}\n </div>\n <div className=\"text-xs text-[color:var(--ck-text-tertiary)]\">{c.timestamp}</div>\n </div>\n <div className=\"mt-2 whitespace-pre-wrap break-words text-sm leading-6 text-[color:var(--ck-text-secondary)]\">\n {c.body}\n </div>\n </div>\n ))}\n </div>\n ) : (\n <div className=\"mt-3 text-sm text-[color:var(--ck-text-secondary)]\">No comments yet.</div>\n )}\n\n <div className=\"mt-4 border-t border-[color:var(--ck-border-subtle)] pt-4\">\n <div className=\"text-sm font-semibold text-[color:var(--ck-text-primary)]\">Add comment</div>\n\n <div className=\"mt-3 grid gap-3\">\n <div className=\"grid gap-1\">\n <label className=\"text-xs font-medium text-[color:var(--ck-text-secondary)]\" htmlFor=\"ck-comment-author\">\n Author (optional)\n </label>\n <input\n id=\"ck-comment-author\"\n value={commentAuthor}\n onChange={(e) => setCommentAuthor(e.target.value)}\n placeholder=\"unknown\"\n className=\"w-full rounded border border-[color:var(--ck-border-subtle)] bg-black/20 px-3 py-2 text-sm text-[color:var(--ck-text-primary)] outline-none focus:border-[color:var(--ck-border-strong)]\"\n disabled={isPending}\n />\n </div>\n\n <div className=\"grid gap-1\">\n <label className=\"text-xs font-medium text-[color:var(--ck-text-secondary)]\" htmlFor=\"ck-comment-body\">\n Comment\n </label>\n <textarea\n id=\"ck-comment-body\"\n value={commentBody}\n onChange={(e) => setCommentBody(e.target.value)}\n rows={4}\n className=\"w-full rounded border border-[color:var(--ck-border-subtle)] bg-black/20 px-3 py-2 text-sm text-[color:var(--ck-text-primary)] outline-none focus:border-[color:var(--ck-border-strong)]\"\n disabled={isPending}\n />\n </div>\n\n <div className=\"flex items-center justify-end\">\n <button\n type=\"button\"\n aria-busy={isPending}\n className={\n \"rounded-[var(--ck-radius-sm)] bg-[color:var(--ck-accent)] px-3 py-2 text-xs font-semibold text-black transition \" +\n \"hover:brightness-110 active:brightness-95 \" +\n \"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[color:var(--ck-border-strong)] focus-visible:ring-offset-2 focus-visible:ring-offset-black/30 \" +\n \"disabled:cursor-not-allowed disabled:border disabled:border-[color:var(--ck-border-subtle)] disabled:bg-[color:var(--ck-bg-glass)] disabled:text-[color:var(--ck-text-tertiary)]\"\n }\n onClick={() => {\n startTransition(() => {\n submitComment().catch((e: unknown) => setError(errorMessage(e)));\n });\n }}\n disabled={isPostCommentDisabled(commentBody, isPending)}\n >\n {isPending ? \"Posting…\" : \"Post comment\"}\n </button>\n </div>\n </div>\n </div>\n </div>\n </div>\n\n <div className=\"ck-glass p-6\">\n <pre className=\"whitespace-pre-wrap break-words text-sm leading-6 text-[color:var(--ck-text-primary)]\">\n {props.markdown}\n </pre>\n </div>\n\n {confirm ? (\n <div className=\"fixed inset-0 z-50 flex items-center justify-center bg-black/60 p-4\">\n <div className=\"ck-glass w-full max-w-lg rounded-[var(--ck-radius-md)] border border-[color:var(--ck-border-strong)] p-4\">\n <div className=\"text-sm font-semibold text-[color:var(--ck-text-primary)]\">\n {confirm.kind === \"goals\" ? \"Move to Goals\" : \"Delete ticket\"}\n </div>\n\n <div className=\"mt-2 text-sm text-[color:var(--ck-text-secondary)]\">\n {confirm.kind === \"goals\" ? (\n <>\n This will move the ticket out of the work lanes into <code>work/goals/</code> so it won’t be picked up by\n automation.\n </>\n ) : (\n <>This will permanently remove the ticket markdown file. Assignment stubs (if any) will be archived.</>\n )}\n </div>\n\n <div className=\"mt-4 flex items-center justify-end gap-2\">\n <button\n className=\"rounded border border-[color:var(--ck-border-subtle)] px-3 py-1.5 text-xs text-[color:var(--ck-text-secondary)]\"\n onClick={() => setConfirm(null)}\n disabled={isPending}\n >\n Cancel\n </button>\n <button\n className={\n confirm.kind === \"delete\"\n ? \"rounded bg-[color:var(--ck-accent-red)] px-3 py-1.5 text-xs font-medium text-white\"\n : \"rounded bg-[color:var(--ck-accent)] px-3 py-1.5 text-xs font-medium text-black\"\n }\n onClick={() => {\n const kind = confirm.kind;\n setConfirm(null);\n startTransition(() => {\n const op = kind === \"goals\" ? moveToGoals() : deleteTicket();\n op\n .then(() => {\n toast.push({\n kind: \"success\",\n message: kind === \"delete\" ? \"Ticket deleted.\" : \"Moved to Goals.\",\n });\n if (kind === \"delete\") {\n router.push(props.backHref ?? \"/tickets\");\n } else {\n router.refresh();\n }\n })\n .catch((e: unknown) => setError(errorMessage(e)));\n });\n }}\n disabled={isPending}\n >\n Confirm\n </button>\n </div>\n </div>\n </div>\n ) : null}\n </div>\n );\n}\n","export type TicketComment = {\n timestamp: string;\n authorName: string;\n authorRole?: string;\n authorRaw: string;\n body: string;\n};\n\nfunction findCommentsSection(md: string): { start: number; end: number } | null {\n const headerRe = /^## Comments\\s*$/gim;\n const m = headerRe.exec(md);\n if (!m) return null;\n\n const start = m.index + m[0].length;\n\n // Find next heading of same or higher level.\n const rest = md.slice(start);\n const nextHeading = rest.search(/^##\\s+/m);\n const end = nextHeading === -1 ? md.length : start + nextHeading;\n return { start, end };\n}\n\nconst ROLE_HINTS = new Set([\"lead\", \"dev\", \"qa\", \"tester\", \"agent\", \"system\"]);\n\nfunction parseAuthor(rawAuthor: string): { name: string; role?: string; raw: string } {\n const raw = rawAuthor?.trim() || \"\";\n const normalized = raw || \"unknown\";\n\n // Pattern: \"RJ (lead)\"\n const paren = normalized.match(/^(.*?)\\s*\\((.*?)\\)\\s*$/);\n if (paren) {\n const name = paren[1].trim() || \"unknown\";\n const role = paren[2].trim();\n return { name, role: role && role.toLowerCase() != name.toLowerCase() ? role : undefined, raw: normalized };\n }\n\n // Pattern: \"lead — RJ\" / \"RJ — lead\" / \"lead | RJ\" / \"RJ | lead\"\n for (const sep of [\" — \", \" - \", \" | \"] as const) {\n if (!normalized.includes(sep)) continue;\n const [a, b] = normalized.split(sep).map((s) => s.trim()).filter(Boolean);\n if (!a || !b) break;\n\n const aIsRole = ROLE_HINTS.has(a.toLowerCase());\n const bIsRole = ROLE_HINTS.has(b.toLowerCase());\n\n if (aIsRole && !bIsRole) return { name: b, role: a, raw: normalized };\n if (bIsRole && !aIsRole) return { name: a, role: b, raw: normalized };\n\n // Otherwise, treat the left as the primary author label and right as secondary detail.\n return { name: a, role: b, raw: normalized };\n }\n\n return { name: normalized, raw: normalized };\n}\n\nexport function parseTicketComments(md: string): TicketComment[] {\n const section = findCommentsSection(md);\n if (!section) return [];\n\n const body = md.slice(section.start, section.end).replace(/^\\s+/, \"\");\n const lines = body.split(\"\\n\");\n\n const out: TicketComment[] = [];\n let current: TicketComment | null = null;\n\n const header = /^- \\*\\*(.+?)\\*\\*\\s+—\\s+(.*)$/;\n\n for (const rawLine of lines) {\n const line = rawLine.replace(/\\r$/, \"\");\n const m = line.match(header);\n if (m) {\n if (current) out.push({ ...current, body: current.body.trimEnd() });\n const timestamp = m[1].trim();\n const rest = m[2].trim();\n // Support either \"author: first line\" or just \"author\".\n const colonIdx = rest.indexOf(\":\");\n const authorRaw = (colonIdx >= 0 ? rest.slice(0, colonIdx) : rest).trim() || \"unknown\";\n const firstBody = colonIdx >= 0 ? rest.slice(colonIdx + 1).trimStart() : \"\";\n const author = parseAuthor(authorRaw);\n current = {\n timestamp,\n authorName: author.name,\n authorRole: author.role,\n authorRaw: author.raw,\n body: firstBody ? firstBody + \"\\n\" : \"\",\n };\n continue;\n }\n\n if (!current) continue;\n\n // Allow list paragraph indentation, but keep it simple.\n current.body += line.replace(/^\\s{0,2}/, \"\") + \"\\n\";\n }\n\n if (current) out.push({ ...current, body: current.body.trimEnd() });\n return out;\n}\n\nexport function formatTicketCommentMarkdown(args: { timestamp: string; author: string; body: string }): string {\n const body = args.body.trim().replace(/\\r\\n/g, \"\\n\");\n const indented = body\n .split(\"\\n\")\n .map((l) => ` ${l}`)\n .join(\"\\n\");\n\n const author = args.author?.trim() || \"unknown\";\n return `\\n- **${args.timestamp}** — ${author}:\\n${indented}\\n`;\n}\n","\"use client\";\n\nimport { useEffect, useMemo, useState } from \"react\";\nimport { useRouter } from \"next/navigation\";\n\nexport function TicketAssignControl({\n teamId,\n ticket,\n currentOwner,\n}: {\n teamId?: string | null;\n ticket: string;\n currentOwner: string | null;\n}) {\n const router = useRouter();\n const [assignees, setAssignees] = useState<string[]>([]);\n const [selected, setSelected] = useState<string>(currentOwner ?? \"\");\n const [loading, setLoading] = useState(false);\n const [error, setError] = useState<string | null>(null);\n\n useEffect(() => {\n let cancelled = false;\n (async () => {\n try {\n const url = teamId\n ? `/api/teams/${encodeURIComponent(teamId)}/tickets/assignees`\n : \"/api/tickets/assignees\";\n const res = await fetch(url, { cache: \"no-store\" });\n const json = (await res.json()) as { assignees?: string[] };\n if (cancelled) return;\n setAssignees(Array.isArray(json.assignees) ? json.assignees : []);\n } catch {\n if (cancelled) return;\n setAssignees([]);\n }\n })();\n return () => {\n cancelled = true;\n };\n }, []);\n\n const options = useMemo(() => {\n const base = new Set(assignees);\n if (currentOwner) base.add(currentOwner);\n return Array.from(base).sort();\n }, [assignees, currentOwner]);\n\n async function onAssign() {\n setLoading(true);\n setError(null);\n try {\n const url = teamId\n ? `/api/teams/${encodeURIComponent(teamId)}/tickets/assign`\n : \"/api/tickets/assign\";\n\n const res = await fetch(url, {\n method: \"POST\",\n headers: { \"content-type\": \"application/json\" },\n body: JSON.stringify({ ticket, assignee: selected, ...(teamId ? { teamId } : {}) }),\n });\n\n const json = (await res.json()) as { error?: string };\n if (!res.ok) {\n setError(json.error || \"Assign failed\");\n return;\n }\n\n router.refresh();\n } catch {\n setError(\"Assign failed\");\n } finally {\n setLoading(false);\n }\n }\n\n return (\n <div className=\"ck-glass p-4\">\n <div className=\"flex flex-wrap items-center gap-3\">\n <div className=\"text-xs font-medium text-[color:var(--ck-text-tertiary)]\">Assignee</div>\n <select\n className=\"rounded-md border border-white/10 bg-black/20 px-3 py-2 text-sm text-[color:var(--ck-text-primary)]\"\n value={selected}\n onChange={(e) => setSelected(e.target.value)}\n >\n <option value=\"\" disabled>\n Select…\n </option>\n {options.map((a) => (\n <option key={a} value={a}>\n {a}\n </option>\n ))}\n </select>\n\n <button\n type=\"button\"\n onClick={onAssign}\n disabled={loading || !selected || selected === (currentOwner ?? \"\")}\n className=\"rounded-md bg-emerald-600 px-3 py-2 text-sm font-semibold text-white hover:bg-emerald-500 disabled:cursor-not-allowed disabled:opacity-50\"\n >\n {loading ? \"Assigning…\" : \"Assign\"}\n </button>\n\n {currentOwner ? (\n <div className=\"text-xs text-[color:var(--ck-text-tertiary)]\">Currently: {currentOwner}</div>\n ) : null}\n </div>\n\n {error ? <div className=\"mt-2 text-xs text-red-300\">{error}</div> : null}\n </div>\n );\n}\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["../../../../src/lib/errors.ts","../../../../src/app/tickets/TicketDetailClient.tsx","../../../../src/lib/ticket-comments.ts","../../../../src/app/tickets/%5Bticket%5D/TicketAssignControl.tsx"],"sourcesContent":["/**\n * Extracts a string message from an unknown error value.\n * Used consistently across API routes and client components.\n */\nexport function errorMessage(e: unknown): string {\n return e instanceof Error ? e.message : String(e);\n}\n","\"use client\";\n\nimport Link from \"next/link\";\nimport { useRouter } from \"next/navigation\";\nimport { useMemo, useState, useTransition } from \"react\";\n\nimport { useToast } from \"@/components/ToastProvider\";\nimport { errorMessage } from \"@/lib/errors\";\nimport { fetchJson } from \"@/lib/fetch-json\";\nimport type { TicketStage } from \"@/lib/tickets\";\nimport { parseTicketComments } from \"@/lib/ticket-comments\";\nimport { TicketAssignControl } from \"@/app/tickets/[ticket]/TicketAssignControl\";\n\nexport function isPostCommentDisabled(commentBody: string, isPending: boolean) {\n return isPending || commentBody.trim().length == 0;\n}\n\nexport function TicketDetailClient(props: {\n teamId: string;\n ticketId: string;\n file: string;\n markdown: string;\n stage: TicketStage;\n backHref?: string;\n currentOwner?: string | null;\n}) {\n const router = useRouter();\n const toast = useToast();\n const [isPending, startTransition] = useTransition();\n const [error, setError] = useState<string | null>(null);\n const [confirm, setConfirm] = useState<null | { kind: \"goals\" | \"delete\" }>(null);\n\n const comments = useMemo(() => parseTicketComments(props.markdown), [props.markdown]);\n\n const [commentAuthor, setCommentAuthor] = useState<string>(\"\");\n const [commentBody, setCommentBody] = useState<string>(\"\");\n\n async function moveToGoals() {\n setError(null);\n await fetchJson(`/api/teams/${encodeURIComponent(props.teamId)}/tickets/move-to-goals`, {\n method: \"POST\",\n headers: { \"content-type\": \"application/json\" },\n body: JSON.stringify({ ticket: props.ticketId }),\n });\n }\n\n async function deleteTicket() {\n setError(null);\n await fetchJson(`/api/teams/${encodeURIComponent(props.teamId)}/tickets/delete`, {\n method: \"POST\",\n headers: { \"content-type\": \"application/json\" },\n body: JSON.stringify({ ticket: props.ticketId }),\n });\n }\n\n async function moveTicket(to: TicketStage) {\n setError(null);\n await fetchJson(`/api/teams/${encodeURIComponent(props.teamId)}/tickets/move`, {\n method: \"POST\",\n headers: { \"content-type\": \"application/json\" },\n body: JSON.stringify({ ticket: props.ticketId, to }),\n });\n }\n\n async function submitComment() {\n setError(null);\n const body = commentBody.trim();\n if (!body) throw new Error(\"Comment cannot be empty.\");\n\n await fetchJson(`/api/teams/${encodeURIComponent(props.teamId)}/tickets/comment`, {\n method: \"POST\",\n headers: { \"content-type\": \"application/json\" },\n body: JSON.stringify({\n ticket: props.ticketId,\n author: commentAuthor.trim() || undefined,\n comment: body,\n }),\n });\n\n setCommentBody(\"\");\n toast.push({ kind: \"success\", message: \"Comment added.\" });\n router.refresh();\n }\n\n return (\n <div className=\"space-y-4\">\n <div className=\"flex items-center justify-between gap-3\">\n <Link href={props.backHref ?? \"/tickets\"} className=\"text-sm font-medium hover:underline\">\n ← Back\n </Link>\n <span className=\"text-xs text-[color:var(--ck-text-tertiary)]\">{props.file}</span>\n </div>\n\n {error ? (\n <div className=\"ck-card border border-[color:var(--ck-border-strong)] p-3 text-sm text-[color:var(--ck-text-primary)]\">\n {error}\n </div>\n ) : null}\n\n <div className=\"ck-card p-6\">\n <div className=\"flex flex-wrap items-center justify-between gap-3\">\n <div className=\"text-sm font-semibold text-[color:var(--ck-text-primary)]\">Ticket</div>\n <div className=\"flex flex-wrap items-center justify-end gap-2\">\n <label className=\"flex items-center gap-2 text-xs text-[color:var(--ck-text-secondary)]\">\n <span>Status</span>\n <select\n className=\"rounded border border-[color:var(--ck-border-subtle)] bg-white/5 px-2 py-1 text-xs text-[color:var(--ck-text-primary)]\"\n disabled={isPending}\n value={props.stage}\n onChange={(e) => {\n const next = e.target.value as TicketStage;\n if (next === props.stage) return;\n\n if (next === \"done\") {\n const ok = window.confirm(\n \"Mark this ticket done? This will move the file to work/done and add an audit comment.\",\n );\n if (!ok) return;\n }\n\n startTransition(() => {\n moveTicket(next)\n .then(() => {\n toast.push({ kind: \"success\", message: `Status updated to ${next}.` });\n router.refresh();\n })\n .catch((err: unknown) => setError(errorMessage(err)));\n });\n }}\n >\n <option value=\"backlog\">backlog</option>\n <option value=\"in-progress\">in-progress</option>\n <option value=\"testing\">testing</option>\n <option value=\"done\">done</option>\n </select>\n </label>\n\n <button\n className=\"rounded border border-[color:var(--ck-border-subtle)] px-3 py-1.5 text-xs font-medium text-[color:var(--ck-text-secondary)] hover:border-[color:var(--ck-border-strong)]\"\n onClick={() => setConfirm({ kind: \"goals\" })}\n disabled={isPending}\n >\n Move to Goals\n </button>\n <button\n className=\"rounded border border-[color:var(--ck-accent-red)] bg-[color:var(--ck-accent-red-soft)] px-3 py-1.5 text-xs font-medium text-[color:var(--ck-accent-red)] hover:bg-[color:var(--ck-accent-red-soft-strong)]\"\n onClick={() => setConfirm({ kind: \"delete\" })}\n disabled={isPending}\n >\n Delete Ticket\n </button>\n </div>\n </div>\n\n {props.currentOwner !== undefined ? (\n <div className=\"mt-4\">\n <TicketAssignControl teamId={props.teamId} ticket={props.ticketId} currentOwner={props.currentOwner ?? null} />\n </div>\n ) : null}\n\n <div className=\"mt-6 border-t border-[color:var(--ck-border-subtle)] pt-6\">\n <div className=\"flex items-center justify-between gap-3\">\n <div className=\"text-sm font-semibold text-[color:var(--ck-text-primary)]\">Comments</div>\n <div className=\"text-xs text-[color:var(--ck-text-tertiary)]\">{comments.length}</div>\n </div>\n\n {comments.length ? (\n <div className=\"mt-3 space-y-3\">\n {comments.map((c, idx) => (\n <div\n key={`${c.timestamp}-${idx}`}\n className=\"rounded-lg border border-[color:var(--ck-border-subtle)] bg-black/10 p-3\"\n >\n <div className=\"flex flex-wrap items-baseline justify-between gap-2\">\n <div className=\"flex flex-wrap items-baseline gap-2\">\n <div className=\"text-xs font-medium text-[color:var(--ck-text-primary)]\">{c.authorName}</div>\n {c.authorRole ? (\n <div className=\"rounded border border-[color:var(--ck-border-subtle)] bg-black/10 px-1.5 py-0.5 text-[10px] font-medium text-[color:var(--ck-text-tertiary)]\">\n {c.authorRole}\n </div>\n ) : null}\n </div>\n <div className=\"text-xs text-[color:var(--ck-text-tertiary)]\">{c.timestamp}</div>\n </div>\n <div className=\"mt-2 whitespace-pre-wrap break-words text-sm leading-6 text-[color:var(--ck-text-secondary)]\">\n {c.body}\n </div>\n </div>\n ))}\n </div>\n ) : (\n <div className=\"mt-3 text-sm text-[color:var(--ck-text-secondary)]\">No comments yet.</div>\n )}\n\n <div className=\"mt-4 border-t border-[color:var(--ck-border-subtle)] pt-4\">\n <div className=\"text-sm font-semibold text-[color:var(--ck-text-primary)]\">Add comment</div>\n\n <div className=\"mt-3 grid gap-3\">\n <div className=\"grid gap-1\">\n <label className=\"text-xs font-medium text-[color:var(--ck-text-secondary)]\" htmlFor=\"ck-comment-author\">\n Author (optional)\n </label>\n <input\n id=\"ck-comment-author\"\n value={commentAuthor}\n onChange={(e) => setCommentAuthor(e.target.value)}\n placeholder=\"unknown\"\n className=\"w-full rounded border border-[color:var(--ck-border-subtle)] bg-white/5 px-3 py-2 text-sm text-[color:var(--ck-text-primary)] outline-none focus:border-[color:var(--ck-border-strong)]\"\n disabled={isPending}\n />\n </div>\n\n <div className=\"grid gap-1\">\n <label className=\"text-xs font-medium text-[color:var(--ck-text-secondary)]\" htmlFor=\"ck-comment-body\">\n Comment\n </label>\n <textarea\n id=\"ck-comment-body\"\n value={commentBody}\n onChange={(e) => setCommentBody(e.target.value)}\n rows={4}\n className=\"w-full rounded border border-[color:var(--ck-border-subtle)] bg-white/5 px-3 py-2 text-sm text-[color:var(--ck-text-primary)] outline-none focus:border-[color:var(--ck-border-strong)]\"\n disabled={isPending}\n />\n </div>\n\n <div className=\"flex items-center justify-end\">\n <button\n type=\"button\"\n aria-busy={isPending}\n className={\n \"rounded-lg bg-[color:var(--ck-accent)] px-3 py-2 text-xs font-semibold text-black transition \" +\n \"hover:brightness-110 active:brightness-95 \" +\n \"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[color:var(--ck-border-strong)] focus-visible:ring-offset-2 focus-visible:ring-offset-black/30 \" +\n \"disabled:cursor-not-allowed disabled:border disabled:border-[color:var(--ck-border-subtle)] disabled:bg-white/5 disabled:text-[color:var(--ck-text-tertiary)]\"\n }\n onClick={() => {\n startTransition(() => {\n submitComment().catch((e: unknown) => setError(errorMessage(e)));\n });\n }}\n disabled={isPostCommentDisabled(commentBody, isPending)}\n >\n {isPending ? \"Posting…\" : \"Post comment\"}\n </button>\n </div>\n </div>\n </div>\n </div>\n </div>\n\n <div className=\"ck-card p-6\">\n <pre className=\"whitespace-pre-wrap break-words text-sm leading-6 text-[color:var(--ck-text-primary)]\">\n {props.markdown}\n </pre>\n </div>\n\n {confirm ? (\n <div className=\"fixed inset-0 z-50 flex items-center justify-center bg-black/60 p-4\">\n <div className=\"ck-card w-full max-w-lg rounded-2xl border border-[color:var(--ck-border-strong)] p-4\">\n <div className=\"text-sm font-semibold text-[color:var(--ck-text-primary)]\">\n {confirm.kind === \"goals\" ? \"Move to Goals\" : \"Delete ticket\"}\n </div>\n\n <div className=\"mt-2 text-sm text-[color:var(--ck-text-secondary)]\">\n {confirm.kind === \"goals\" ? (\n <>\n This will move the ticket out of the work lanes into <code>work/goals/</code> so it won’t be picked up by\n automation.\n </>\n ) : (\n <>This will permanently remove the ticket markdown file. Assignment stubs (if any) will be archived.</>\n )}\n </div>\n\n <div className=\"mt-4 flex items-center justify-end gap-2\">\n <button\n className=\"rounded border border-[color:var(--ck-border-subtle)] px-3 py-1.5 text-xs text-[color:var(--ck-text-secondary)]\"\n onClick={() => setConfirm(null)}\n disabled={isPending}\n >\n Cancel\n </button>\n <button\n className={\n confirm.kind === \"delete\"\n ? \"rounded bg-[color:var(--ck-accent-red)] px-3 py-1.5 text-xs font-medium text-white\"\n : \"rounded bg-[color:var(--ck-accent)] px-3 py-1.5 text-xs font-medium text-black\"\n }\n onClick={() => {\n const kind = confirm.kind;\n setConfirm(null);\n startTransition(() => {\n const op = kind === \"goals\" ? moveToGoals() : deleteTicket();\n op\n .then(() => {\n toast.push({\n kind: \"success\",\n message: kind === \"delete\" ? \"Ticket deleted.\" : \"Moved to Goals.\",\n });\n if (kind === \"delete\") {\n router.push(props.backHref ?? \"/tickets\");\n } else {\n router.refresh();\n }\n })\n .catch((e: unknown) => setError(errorMessage(e)));\n });\n }}\n disabled={isPending}\n >\n Confirm\n </button>\n </div>\n </div>\n </div>\n ) : null}\n </div>\n );\n}\n","export type TicketComment = {\n timestamp: string;\n authorName: string;\n authorRole?: string;\n authorRaw: string;\n body: string;\n};\n\nfunction findCommentsSection(md: string): { start: number; end: number } | null {\n const headerRe = /^## Comments\\s*$/gim;\n const m = headerRe.exec(md);\n if (!m) return null;\n\n const start = m.index + m[0].length;\n\n // Find next heading of same or higher level.\n const rest = md.slice(start);\n const nextHeading = rest.search(/^##\\s+/m);\n const end = nextHeading === -1 ? md.length : start + nextHeading;\n return { start, end };\n}\n\nconst ROLE_HINTS = new Set([\"lead\", \"dev\", \"qa\", \"tester\", \"agent\", \"system\"]);\n\nfunction parseAuthor(rawAuthor: string): { name: string; role?: string; raw: string } {\n const raw = rawAuthor?.trim() || \"\";\n const normalized = raw || \"unknown\";\n\n // Pattern: \"RJ (lead)\"\n const paren = normalized.match(/^(.*?)\\s*\\((.*?)\\)\\s*$/);\n if (paren) {\n const name = paren[1].trim() || \"unknown\";\n const role = paren[2].trim();\n return { name, role: role && role.toLowerCase() != name.toLowerCase() ? role : undefined, raw: normalized };\n }\n\n // Pattern: \"lead — RJ\" / \"RJ — lead\" / \"lead | RJ\" / \"RJ | lead\"\n for (const sep of [\" — \", \" - \", \" | \"] as const) {\n if (!normalized.includes(sep)) continue;\n const [a, b] = normalized.split(sep).map((s) => s.trim()).filter(Boolean);\n if (!a || !b) break;\n\n const aIsRole = ROLE_HINTS.has(a.toLowerCase());\n const bIsRole = ROLE_HINTS.has(b.toLowerCase());\n\n if (aIsRole && !bIsRole) return { name: b, role: a, raw: normalized };\n if (bIsRole && !aIsRole) return { name: a, role: b, raw: normalized };\n\n // Otherwise, treat the left as the primary author label and right as secondary detail.\n return { name: a, role: b, raw: normalized };\n }\n\n return { name: normalized, raw: normalized };\n}\n\nexport function parseTicketComments(md: string): TicketComment[] {\n const section = findCommentsSection(md);\n if (!section) return [];\n\n const body = md.slice(section.start, section.end).replace(/^\\s+/, \"\");\n const lines = body.split(\"\\n\");\n\n const out: TicketComment[] = [];\n let current: TicketComment | null = null;\n\n const header = /^- \\*\\*(.+?)\\*\\*\\s+—\\s+(.*)$/;\n\n for (const rawLine of lines) {\n const line = rawLine.replace(/\\r$/, \"\");\n const m = line.match(header);\n if (m) {\n if (current) out.push({ ...current, body: current.body.trimEnd() });\n const timestamp = m[1].trim();\n const rest = m[2].trim();\n // Support either \"author: first line\" or just \"author\".\n const colonIdx = rest.indexOf(\":\");\n const authorRaw = (colonIdx >= 0 ? rest.slice(0, colonIdx) : rest).trim() || \"unknown\";\n const firstBody = colonIdx >= 0 ? rest.slice(colonIdx + 1).trimStart() : \"\";\n const author = parseAuthor(authorRaw);\n current = {\n timestamp,\n authorName: author.name,\n authorRole: author.role,\n authorRaw: author.raw,\n body: firstBody ? firstBody + \"\\n\" : \"\",\n };\n continue;\n }\n\n if (!current) continue;\n\n // Allow list paragraph indentation, but keep it simple.\n current.body += line.replace(/^\\s{0,2}/, \"\") + \"\\n\";\n }\n\n if (current) out.push({ ...current, body: current.body.trimEnd() });\n return out;\n}\n\nexport function formatTicketCommentMarkdown(args: { timestamp: string; author: string; body: string }): string {\n const body = args.body.trim().replace(/\\r\\n/g, \"\\n\");\n const indented = body\n .split(\"\\n\")\n .map((l) => ` ${l}`)\n .join(\"\\n\");\n\n const author = args.author?.trim() || \"unknown\";\n return `\\n- **${args.timestamp}** — ${author}:\\n${indented}\\n`;\n}\n","\"use client\";\n\nimport { useEffect, useMemo, useState } from \"react\";\nimport { useRouter } from \"next/navigation\";\n\nexport function TicketAssignControl({\n teamId,\n ticket,\n currentOwner,\n}: {\n teamId?: string | null;\n ticket: string;\n currentOwner: string | null;\n}) {\n const router = useRouter();\n const [assignees, setAssignees] = useState<string[]>([]);\n const [selected, setSelected] = useState<string>(currentOwner ?? \"\");\n const [loading, setLoading] = useState(false);\n const [error, setError] = useState<string | null>(null);\n\n useEffect(() => {\n let cancelled = false;\n (async () => {\n try {\n const url = teamId\n ? `/api/teams/${encodeURIComponent(teamId)}/tickets/assignees`\n : \"/api/tickets/assignees\";\n const res = await fetch(url, { cache: \"no-store\" });\n const json = (await res.json()) as { assignees?: string[] };\n if (cancelled) return;\n setAssignees(Array.isArray(json.assignees) ? json.assignees : []);\n } catch {\n if (cancelled) return;\n setAssignees([]);\n }\n })();\n return () => {\n cancelled = true;\n };\n }, []);\n\n const options = useMemo(() => {\n const base = new Set(assignees);\n if (currentOwner) base.add(currentOwner);\n return Array.from(base).sort();\n }, [assignees, currentOwner]);\n\n async function onAssign() {\n setLoading(true);\n setError(null);\n try {\n const url = teamId\n ? `/api/teams/${encodeURIComponent(teamId)}/tickets/assign`\n : \"/api/tickets/assign\";\n\n const res = await fetch(url, {\n method: \"POST\",\n headers: { \"content-type\": \"application/json\" },\n body: JSON.stringify({ ticket, assignee: selected, ...(teamId ? { teamId } : {}) }),\n });\n\n const json = (await res.json()) as { error?: string };\n if (!res.ok) {\n setError(json.error || \"Assign failed\");\n return;\n }\n\n router.refresh();\n } catch {\n setError(\"Assign failed\");\n } finally {\n setLoading(false);\n }\n }\n\n return (\n <div className=\"ck-card p-4\">\n <div className=\"flex flex-wrap items-center gap-3\">\n <div className=\"text-xs font-medium text-[color:var(--ck-text-tertiary)]\">Assignee</div>\n <select\n className=\"rounded-md border border-white/10 bg-white/5 px-3 py-2 text-sm text-[color:var(--ck-text-primary)]\"\n value={selected}\n onChange={(e) => setSelected(e.target.value)}\n >\n <option value=\"\" disabled>\n Select…\n </option>\n {options.map((a) => (\n <option key={a} value={a}>\n {a}\n </option>\n ))}\n </select>\n\n <button\n type=\"button\"\n onClick={onAssign}\n disabled={loading || !selected || selected === (currentOwner ?? \"\")}\n className=\"rounded-md bg-emerald-600 px-3 py-2 text-sm font-semibold text-white hover:bg-emerald-500 disabled:cursor-not-allowed disabled:opacity-50\"\n >\n {loading ? \"Assigning…\" : \"Assign\"}\n </button>\n\n {currentOwner ? (\n <div className=\"text-xs text-[color:var(--ck-text-tertiary)]\">Currently: {currentOwner}</div>\n ) : null}\n </div>\n\n {error ? <div className=\"mt-2 text-xs text-red-300\">{error}</div> : null}\n </div>\n );\n}\n"],"names":[],"mappings":"uCAIO,SAAS,EAAa,CAAU,EACrC,OAAO,aAAa,MAAQ,EAAE,OAAO,CAAG,OAAO,EACjD,sECJA,EAAA,EAAA,CAAA,CAAA,OACA,EAAA,EAAA,CAAA,CAAA,OACA,EAAA,EAAA,CAAA,CAAA,OAEA,EAAA,EAAA,CAAA,CAAA,OACA,EAAA,EAAA,CAAA,CAAA,OACA,EAAA,EAAA,CAAA,CAAA,OCcA,IAAM,EAAa,IAAI,IAAI,CAAC,OAAQ,MAAO,KAAM,SAAU,QAAS,SAAS,ECjBtE,SAAS,EAAoB,QAClC,CAAM,CACN,QAAM,CACN,cAAY,CAKb,EACC,IAAM,EAAS,CAAA,EAAA,EAAA,SAAS,AAAT,IACT,CAAC,EAAW,EAAa,CAAG,CAAA,EAAA,EAAA,QAAA,AAAQ,EAAW,EAAE,EACjD,CAAC,EAAU,EAAY,CAAG,CAAA,EAAA,EAAA,QAAQ,AAAR,EAAiB,GAAgB,IAC3D,CAAC,EAAS,EAAW,CAAG,CAAA,EAAA,EAAA,QAAA,AAAQ,EAAC,IACjC,CAAC,EAAO,EAAS,CAAG,CAAA,EAAA,EAAA,QAAA,AAAQ,EAAgB,MAElD,CAAA,EAAA,EAAA,SAAA,AAAS,EAAC,KACR,IAAI,GAAY,EAehB,MAdA,CAAC,UACC,GAAI,CACF,IAAM,EAAM,EACR,CAAC,WAAW,EAAE,mBAAmB,GAAQ,kBAAkB,CAAC,CAC5D,yBACE,EAAM,MAAM,MAAM,EAAK,CAAE,MAAO,UAAW,GAC3C,EAAQ,MAAM,EAAI,IAAI,GAC5B,GAAI,EAAW,OACf,EAAa,MAAM,OAAO,CAAC,EAAK,SAAS,EAAI,EAAK,SAAS,CAAG,EAAE,CAClE,CAAE,KAAM,CACN,GAAI,EAAW,OACf,EAAa,EAAE,CACjB,EACF,CAAC,GACM,KACL,GAAY,CACd,CACF,EAAG,EAAE,EAEL,IAAM,EAAU,CAAA,EAAA,EAAA,OAAO,AAAP,EAAQ,KACtB,IAAM,EAAO,IAAI,IAAI,GAErB,OADI,GAAc,EAAK,GAAG,CAAC,GACpB,MAAM,IAAI,CAAC,GAAM,IAAI,EAC9B,EAAG,CAAC,EAAW,EAAa,EAE5B,eAAe,IACb,EAAW,IACX,EAAS,MACT,GAAI,CACF,IAAM,EAAM,EACR,CAAC,WAAW,EAAE,mBAAmB,GAAQ,eAAe,CAAC,CACzD,sBAEE,EAAM,MAAM,MAAM,EAAK,CAC3B,OAAQ,OACR,QAAS,CAAE,eAAgB,kBAAmB,EAC9C,KAAM,KAAK,SAAS,CAAC,QAAE,EAAQ,SAAU,EAAU,GAAI,EAAS,QAAE,CAAO,EAAI,CAAC,CAAC,AAAE,EACnF,GAEM,EAAQ,MAAM,EAAI,IAAI,GAC5B,GAAI,CAAC,EAAI,EAAE,CAAE,YACX,EAAS,EAAK,KAAK,EAAI,iBAIzB,EAAO,OAAO,EAChB,CAAE,KAAM,CACN,EAAS,gBACX,QAAU,CACR,GAAW,EACb,CACF,CAEA,MACE,CAAA,EAAA,EAAA,IAAA,EAAC,MAAA,CAAI,UAAU,wBACb,CAAA,EAAA,EAAA,IAAA,EAAC,MAAA,CAAI,UAAU,8CACb,CAAA,EAAA,EAAA,GAAA,EAAC,MAAA,CAAI,UAAU,oEAA2D,aAC1E,CAAA,EAAA,EAAA,IAAA,EAAC,SAAA,CACC,UAAU,qGACV,MAAO,EACP,SAAU,AAAC,GAAM,EAAY,EAAE,MAAM,CAAC,KAAK,YAE3C,CAAA,EAAA,EAAA,GAAA,EAAC,SAAA,CAAO,MAAM,GAAG,QAAQ,CAAA,CAAA,WAAC,YAGzB,EAAQ,GAAG,CAAC,AAAC,GACZ,CAAA,EAAA,EAAA,GAAA,EAAC,SAAA,CAAe,MAAO,WACpB,GADU,OAMjB,CAAA,EAAA,EAAA,GAAA,EAAC,SAAA,CACC,KAAK,SACL,QAAS,EACT,SAAU,GAAW,CAAC,GAAY,KAAc,GAAgB,EAAA,CAAE,CAClE,CAD+C,SACrC,qJAET,EAAU,aAAe,WAG3B,EACC,CAAA,EAAA,EAAA,IAAA,EAAC,MAAA,CAAI,UAAU,yDAA+C,cAAY,KACxE,QAGL,EAAQ,CAAA,EAAA,EAAA,GAAA,EAAC,MAAA,CAAI,UAAU,qCAA6B,IAAe,OAG1E,CFlGO,SAAS,EAAsB,CAAmB,CAAE,CAAkB,EAC3E,OAAO,GAA0C,GAA7B,EAAY,IAAI,GAAG,MAAM,AAC/C,CAEO,SAAS,EAAmB,CAQlC,EACC,IAAM,EAAS,CAAA,EAAA,EAAA,SAAA,AAAS,IAClB,EAAQ,CAAA,EAAA,EAAA,QAAA,AAAQ,IAChB,CAAC,EAAW,EAAgB,CAAG,CAAA,EAAA,EAAA,aAAA,AAAa,IAC5C,CAAC,EAAO,EAAS,CAAG,CAAA,EAAA,EAAA,QAAA,AAAQ,EAAgB,MAC5C,CAAC,EAAS,EAAW,CAAG,CAAA,EAAA,EAAA,QAAA,AAAQ,EAAsC,MAEtE,EAAW,CAAA,EAAA,EAAA,OAAA,AAAO,EAAC,IAAM,CCuB1B,SAA6B,AAApB,CAA8B,EAC5C,IAAM,EAAU,AAhDlB,SAAS,AAAoB,CAAU,EAErC,IAAM,EADW,AACP,sBAAS,IAAI,CAAC,GACxB,GAAI,CAAC,EAAG,OAAO,KAEf,IAAM,EAAQ,EAAE,KAAK,CAAG,CAAC,CAAC,EAAE,CAAC,MAAM,CAI7B,EADO,AACO,EADJ,KAAK,CAAC,GACG,MAAM,CAAC,WAC1B,EAAsB,CAAC,IAAjB,EAAqB,EAAG,MAAM,CAAG,EAAQ,EACrD,MAAO,OAAE,MAAO,CAAI,CACtB,EAoCsC,GACpC,GAAI,CAAC,EAAS,MAAO,EAAE,CAGvB,IAAM,EAAQ,AADD,EAAG,KAAK,CAAC,EAAQ,KAAK,CAAE,EAAQ,GAAG,EAAE,OAAO,CAAC,OAAQ,IAC/C,KAAK,CAAC,MAEnB,EAAuB,EAAE,CAC3B,EAAgC,KAE9B,EAAS,+BAEf,IAAK,IAAM,KAAW,EAAO,CAC3B,IAAM,EAAO,EAAQ,OAAO,CAAC,MAAO,IAC9B,EAAI,EAAK,KAAK,CAAC,GACrB,GAAI,EAAG,CACD,GAAS,EAAI,IAAI,CAAC,CAAE,GAAG,CAAO,CAAE,KAAM,EAAQ,IAAI,CAAC,OAAO,EAAG,GACjE,IAAM,EAAY,CAAC,CAAC,EAAE,CAAC,IAAI,GACrB,EAAO,CAAC,CAAC,EAAE,CAAC,IAAI,GAEhB,EAAW,EAAK,OAAO,CAAC,KACxB,EAAY,CAAC,GAAY,EAAI,EAAK,KAAK,CAAC,EAAG,GAAY,CAAA,CAAI,CAAE,IAAI,IAAM,UACvE,EAAY,GAAY,EAAI,EAAK,KAAK,CAAC,EAAW,GAAG,SAAS,GAAK,GACnE,EAAS,AAtDrB,SAAS,AAAY,CAAiB,EAEpC,IAAM,EADM,AACO,GADI,QACG,EADO,QAI3B,EAAQ,EAAW,KAAK,CAAC,0BAC/B,GAAI,EAAO,CACT,IAAM,EAAO,CAAK,CAAC,EAAE,CAAC,IAAI,IAAM,UAC1B,EAAO,CAAK,CAAC,EAAE,CAAC,IAAI,GAC1B,MAAO,CAAE,OAAM,KAAM,GAAQ,EAAK,WAAW,IAAM,EAAK,WAAW,GAAK,OAAO,EAAW,IAAK,CAAW,CAC5G,CAGA,IAAK,IAAM,IAAO,CAAC,MAAO,MAAO,MAAM,CAAW,CAChD,GAAI,CAAC,EAAW,QAAQ,CAAC,GAAM,SAC/B,GAAM,CAAC,EAAG,EAAE,CAAG,EAAW,KAAK,CAAC,GAAK,GAAG,CAAC,AAAC,GAAM,EAAE,IAAI,IAAI,MAAM,CAAC,SACjE,GAAI,CAAC,GAAK,CAAC,EAAG,MAEd,IAAM,EAAU,EAAW,GAAG,CAAC,EAAE,WAAW,IACtC,EAAU,EAAW,GAAG,CAAC,EAAE,WAAW,IAE5C,GAAI,GAAW,CAAC,EAAS,MAAO,CAAE,KAAM,EAAG,KAAM,EAAG,IAAK,CAAW,EAIpE,MAAO,CAAE,KAAM,EAAG,KAAM,EAAG,IAAK,CAAW,CAC7C,CAEA,MAAO,CAAE,KAAM,EAAY,IAAK,CAAW,CAC7C,EAyBiC,GAC3B,EAAU,WACR,EACA,WAAY,EAAO,IAAI,CACvB,WAAY,EAAO,IAAI,CACvB,UAAW,EAAO,GAAG,CACrB,KAAM,EAAY,EAAY,KAAO,EACvC,EACA,QACF,CAEK,IAGL,EAAQ,GAHM,CAGF,EAAI,EAAK,OAAO,CAAC,WAAY,IAAM,IAAA,CACjD,CAGA,OADI,GAAS,EAAI,IAAI,CAAC,CAAE,GAAG,CAAO,CAAE,KAAM,EAAQ,IAAI,CAAC,OAAO,EAAG,GAC1D,EACT,EDjEqD,EAAM,QAAQ,EAAG,CAAC,EAAM,QAAQ,CAAC,EAE9E,CAAC,EAAe,EAAiB,CAAG,CAAA,EAAA,EAAA,QAAQ,AAAR,EAAiB,IACrD,CAAC,EAAa,EAAe,CAAG,CAAA,EAAA,EAAA,QAAA,AAAQ,EAAS,IAEvD,eAAe,IACb,EAAS,MACT,MAAM,CAAA,EAAA,EAAA,SAAA,AAAS,EAAC,CAAC,WAAW,EAAE,mBAAmB,EAAM,MAAM,EAAE,sBAAsB,CAAC,CAAE,CACtF,OAAQ,OACR,QAAS,CAAE,eAAgB,kBAAmB,EAC9C,KAAM,KAAK,SAAS,CAAC,CAAE,OAAQ,EAAM,QAAQ,AAAC,EAChD,EACF,CAEA,eAAe,IACb,EAAS,MACT,MAAM,CAAA,EAAA,EAAA,SAAS,AAAT,EAAU,CAAC,WAAW,EAAE,mBAAmB,EAAM,MAAM,EAAE,eAAe,CAAC,CAAE,CAC/E,OAAQ,OACR,QAAS,CAAE,eAAgB,kBAAmB,EAC9C,KAAM,KAAK,SAAS,CAAC,CAAE,OAAQ,EAAM,QAAQ,AAAC,EAChD,EACF,CAEA,eAAe,EAAW,CAAe,EACvC,EAAS,MACT,MAAM,CAAA,EAAA,EAAA,SAAA,AAAS,EAAC,CAAC,WAAW,EAAE,mBAAmB,EAAM,MAAM,EAAE,aAAa,CAAC,CAAE,CAC7E,OAAQ,OACR,QAAS,CAAE,eAAgB,kBAAmB,EAC9C,KAAM,KAAK,SAAS,CAAC,CAAE,OAAQ,EAAM,QAAQ,IAAE,CAAG,EACpD,EACF,CAEA,eAAe,IACb,EAAS,MACT,IAAM,EAAO,EAAY,IAAI,GAC7B,GAAI,CAAC,EAAM,MAAM,AAAI,MAAM,2BAE3B,OAAM,CAAA,EAAA,EAAA,SAAA,AAAS,EAAC,CAAC,WAAW,EAAE,mBAAmB,EAAM,MAAM,EAAE,gBAAgB,CAAC,CAAE,CAChF,OAAQ,OACR,QAAS,CAAE,eAAgB,kBAAmB,EAC9C,KAAM,KAAK,SAAS,CAAC,CACnB,OAAQ,EAAM,QAAQ,CACtB,OAAQ,EAAc,IAAI,SAAM,EAChC,QAAS,CACX,EACF,GAEA,EAAe,IACf,EAAM,IAAI,CAAC,CAAE,KAAM,UAAW,QAAS,gBAAiB,GACxD,EAAO,OAAO,EAChB,CAEA,MACE,CAAA,EAAA,EAAA,IAAA,EAAC,MAAA,CAAI,UAAU,sBACb,CAAA,EAAA,EAAA,IAAA,EAAC,MAAA,CAAI,UAAU,oDACb,CAAA,EAAA,EAAA,GAAA,EAAC,EAAA,OAAI,CAAA,CAAC,KAAM,EAAM,QAAQ,EAAI,WAAY,UAAU,+CAAsC,WAG1F,CAAA,EAAA,EAAA,GAAA,EAAC,OAAA,CAAK,UAAU,wDAAgD,EAAM,IAAI,MAG3E,EACC,CAAA,EAAA,EAAA,GAAA,EAAC,MAAA,CAAI,UAAU,iHACZ,IAED,KAEJ,CAAA,EAAA,EAAA,IAAA,EAAC,MAAA,CAAI,UAAU,wBACb,CAAA,EAAA,EAAA,IAAA,EAAC,MAAA,CAAI,UAAU,8DACb,CAAA,EAAA,EAAA,GAAA,EAAC,MAAA,CAAI,UAAU,qEAA4D,WAC3E,CAAA,EAAA,EAAA,IAAA,EAAC,MAAA,CAAI,UAAU,0DACb,CAAA,EAAA,EAAA,IAAA,EAAC,QAAA,CAAM,UAAU,kFACf,CAAA,EAAA,EAAA,GAAA,EAAC,OAAA,UAAK,WACN,CAAA,EAAA,EAAA,IAAA,EAAC,SAAA,CACC,UAAU,yHACV,SAAU,EACV,MAAO,EAAM,KAAK,CAClB,SAAU,AAAC,IACT,IAAM,EAAO,EAAE,MAAM,CAAC,KAAK,CAC3B,GAAI,IAAS,EAAM,KAAK,EAAE,AAE1B,GAAa,QAAQ,CAAjB,GAIE,CAHO,AAGN,OAHa,OAAO,CACvB,yFAEO,OAGX,EAAgB,KACd,EAAW,GACR,IAAI,CAAC,KACJ,EAAM,IAAI,CAAC,CAAE,KAAM,UAAW,QAAS,CAAC,kBAAkB,EAAE,EAAK,CAAC,CAAC,AAAC,GACpE,EAAO,OAAO,EAChB,GACC,KAAK,CAAC,AAAC,GAAiB,EAAS,CAAA,EAAA,EAAA,YAAA,AAAY,EAAC,IACnD,GACF,YAEA,CAAA,EAAA,EAAA,GAAA,EAAC,SAAA,CAAO,MAAM,mBAAU,YACxB,CAAA,EAAA,EAAA,GAAA,EAAC,SAAA,CAAO,MAAM,uBAAc,gBAC5B,CAAA,EAAA,EAAA,GAAA,EAAC,SAAA,CAAO,MAAM,mBAAU,YACxB,CAAA,EAAA,EAAA,GAAA,EAAC,SAAA,CAAO,MAAM,gBAAO,eAIzB,CAAA,EAAA,EAAA,GAAA,EAAC,SAAA,CACC,UAAU,2KACV,QAAS,IAAM,EAAW,CAAE,KAAM,OAAQ,GAC1C,SAAU,WACX,kBAGD,CAAA,EAAA,EAAA,GAAA,EAAC,SAAA,CACC,UAAU,8MACV,QAAS,IAAM,EAAW,CAAE,KAAM,QAAS,GAC3C,SAAU,WACX,6BAMmB,IAAvB,EAAM,YAAY,CACjB,CAAA,EAAA,EAAA,GAAA,EAAC,MAAA,CAAI,UAAU,gBACb,CAAA,EAAA,EAAA,GAAA,EAAC,EAAA,CAAoB,OAAQ,EAAM,MAAM,CAAE,OAAQ,EAAM,QAAQ,CAAE,aAAc,EAAM,YAAY,EAAI,SAEvG,KAEJ,CAAA,EAAA,EAAA,IAAA,EAAC,MAAA,CAAI,UAAU,sEACb,CAAA,EAAA,EAAA,IAAA,EAAC,MAAA,CAAI,UAAU,oDACb,CAAA,EAAA,EAAA,GAAA,EAAC,MAAA,CAAI,UAAU,qEAA4D,aAC3E,CAAA,EAAA,EAAA,GAAA,EAAC,MAAA,CAAI,UAAU,wDAAgD,EAAS,MAAM,MAG/E,EAAS,MAAM,CACd,CAAA,EAAA,EAAA,GAAA,EAAC,MAAA,CAAI,UAAU,0BACZ,EAAS,GAAG,CAAC,CAAC,EAAG,IAChB,CAAA,EAAA,EAAA,IAAA,EAAC,MAAA,CAEC,UAAU,qFAEV,CAAA,EAAA,EAAA,IAAA,EAAC,MAAA,CAAI,UAAU,gEACb,CAAA,EAAA,EAAA,IAAA,EAAC,MAAA,CAAI,UAAU,gDACb,CAAA,EAAA,EAAA,GAAA,EAAC,MAAA,CAAI,UAAU,mEAA2D,EAAE,UAAU,GACrF,EAAE,UAAU,CACX,CAAA,EAAA,EAAA,GAAA,EAAC,MAAA,CAAI,UAAU,wJACZ,EAAE,UAAU,GAEb,QAEN,CAAA,EAAA,EAAA,GAAA,EAAC,MAAA,CAAI,UAAU,wDAAgD,EAAE,SAAS,MAE5E,CAAA,EAAA,EAAA,GAAA,EAAC,MAAA,CAAI,UAAU,wGACZ,EAAE,IAAI,KAfJ,CAAA,EAAG,EAAE,SAAS,CAAC,CAAC,EAAE,EAAA,CAAK,KAqBlC,CAAA,EAAA,EAAA,GAAA,EAAC,MAAA,CAAI,UAAU,8DAAqD,qBAGtE,CAAA,EAAA,EAAA,IAAA,EAAC,MAAA,CAAI,UAAU,sEACb,CAAA,EAAA,EAAA,GAAA,EAAC,MAAA,CAAI,UAAU,qEAA4D,gBAE3E,CAAA,EAAA,EAAA,IAAA,EAAC,MAAA,CAAI,UAAU,4BACb,CAAA,EAAA,EAAA,IAAA,EAAC,MAAA,CAAI,UAAU,uBACb,CAAA,EAAA,EAAA,GAAA,EAAC,QAAA,CAAM,UAAU,4DAA4D,QAAQ,6BAAoB,sBAGzG,CAAA,EAAA,EAAA,GAAA,EAAC,QAAA,CACC,GAAG,oBACH,MAAO,EACP,SAAU,AAAC,GAAM,EAAiB,EAAE,MAAM,CAAC,KAAK,EAChD,YAAY,UACZ,UAAU,0LACV,SAAU,OAId,CAAA,EAAA,EAAA,IAAA,EAAC,MAAA,CAAI,UAAU,uBACb,CAAA,EAAA,EAAA,GAAA,EAAC,QAAA,CAAM,UAAU,4DAA4D,QAAQ,2BAAkB,YAGvG,CAAA,EAAA,EAAA,GAAA,EAAC,WAAA,CACC,GAAG,kBACH,MAAO,EACP,SAAU,AAAC,GAAM,EAAe,EAAE,MAAM,CAAC,KAAK,EAC9C,KAAM,EACN,UAAU,0LACV,SAAU,OAId,CAAA,EAAA,EAAA,GAAA,EAAC,MAAA,CAAI,UAAU,yCACb,CAAA,EAAA,EAAA,GAAA,EAAC,SAAA,CACC,KAAK,SACL,YAAW,EACX,UACE,kGACA,+CACA,uKACA,iJAEF,QAAS,KACP,EAAgB,KACd,IAAgB,KAAK,CAAC,AAAC,GAAe,EAAS,CAAA,EAAA,EAAA,YAAA,AAAY,EAAC,IAC9D,EACF,EACA,SAAU,EAAsB,EAAa,YAE5C,EAAY,WAAa,+BAQtC,CAAA,EAAA,EAAA,GAAA,EAAC,MAAA,CAAI,UAAU,uBACb,CAAA,EAAA,EAAA,GAAA,EAAC,MAAA,CAAI,UAAU,iGACZ,EAAM,QAAQ,KAIlB,EACC,CAAA,EAAA,EAAA,GAAA,EAAC,MAAA,CAAI,UAAU,+EACb,CAAA,EAAA,EAAA,IAAA,EAAC,MAAA,CAAI,UAAU,kGACb,CAAA,EAAA,EAAA,GAAA,EAAC,MAAA,CAAI,UAAU,qEACK,UAAjB,EAAQ,IAAI,CAAe,gBAAkB,kBAGhD,CAAA,EAAA,EAAA,GAAA,EAAC,MAAA,CAAI,UAAU,8DACK,UAAjB,EAAQ,IAAI,CACX,CAAA,EAAA,EAAA,IAAA,EAAA,EAAA,QAAA,CAAA,WAAE,wDACqD,CAAA,EAAA,EAAA,GAAA,EAAC,OAAA,UAAK,gBAAkB,8CAI/E,CAAA,EAAA,EAAA,GAAA,EAAA,EAAA,QAAA,CAAA,UAAE,yGAIN,CAAA,EAAA,EAAA,IAAA,EAAC,MAAA,CAAI,UAAU,qDACb,CAAA,EAAA,EAAA,GAAA,EAAC,SAAA,CACC,UAAU,kHACV,QAAS,IAAM,EAAW,MAC1B,SAAU,WACX,WAGD,CAAA,EAAA,EAAA,GAAA,EAAC,SAAA,CACC,UACmB,WAAjB,EAAQ,IAAI,CACR,qFACA,iFAEN,QAAS,KACP,IAAM,EAAO,EAAQ,IAAI,CACzB,EAAW,MACX,EAAgB,KAEd,CADoB,UAAT,EAAmB,IAAgB,GAAA,EAE3C,IAAI,CAAC,KACJ,EAAM,IAAI,CAAC,CACT,KAAM,UACN,QAAkB,WAAT,EAAoB,kBAAoB,iBACnD,GACa,UAAU,CAAnB,EACF,EAAO,IAAI,CAAC,EAAM,QAAQ,EAAI,YAE9B,EAAO,OAAO,EAElB,GACC,KAAK,CAAC,AAAC,GAAe,EAAS,CAAA,EAAA,EAAA,YAAA,AAAY,EAAC,IACjD,EACF,EACA,SAAU,WACX,oBAML,OAGV"}
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
module.exports=[74621,a=>{"use strict";function b(a){return a instanceof Error?a.message:String(a)}a.s(["errorMessage",()=>b])},2561,14878,a=>{"use strict";var b=a.i(87924),c=a.i(72131);function d({children:a,error:c,actions:d}){return(0,b.jsxs)("div",{className:"ck-
|
|
1
|
+
module.exports=[74621,a=>{"use strict";function b(a){return a instanceof Error?a.message:String(a)}a.s(["errorMessage",()=>b])},2561,14878,a=>{"use strict";var b=a.i(87924),c=a.i(72131);function d({children:a,error:c,actions:d}){return(0,b.jsxs)("div",{className:"ck-card p-6 space-y-4",children:[a,c?(0,b.jsx)("div",{className:"text-sm text-red-300",children:c}):null,d]})}let e="mt-1 w-full rounded-lg border border-[color:var(--ck-border-subtle)] bg-transparent px-3 py-2 text-sm";function f({formState:a,idField:d,updatedAt:f,bodyHeight:g="h-[320px]"}){let{title:h,setTitle:i,status:j,setStatus:k,tagsRaw:l,setTagsRaw:m,teamsRaw:n,setTeamsRaw:o,body:p,setBody:q}=a,r=(0,c.useId)(),s=`${r}-id`,t=`${r}-title`,u=`${r}-status`,v=`${r}-teams`,w=`${r}-tags`,x=`${r}-body`;return(0,b.jsxs)(b.Fragment,{children:[d?(0,b.jsxs)("div",{children:[(0,b.jsx)("label",{htmlFor:s,className:"text-xs text-[color:var(--ck-text-tertiary)]",children:"ID"}),(0,b.jsx)("input",{id:s,className:`${e} font-mono`,value:d.id,onChange:a=>d.setId(a.target.value),placeholder:"increase-trial-activation","aria-describedby":`${r}-id-hint`}),(0,b.jsxs)("div",{id:`${r}-id-hint`,className:"mt-1 text-xs text-[color:var(--ck-text-tertiary)]",children:["Lowercase letters, numbers, hyphens. Stored as ",(0,b.jsxs)("code",{className:"font-mono",children:[d.id||"<id>",".md"]}),".",d.suggestedId&&!d.id.trim()?(0,b.jsxs)(b.Fragment,{children:[" ","Suggested:"," ",(0,b.jsx)("button",{type:"button",className:"underline",onClick:()=>d.setId(d.suggestedId??""),children:d.suggestedId})]}):null]})]}):null,(0,b.jsxs)("div",{children:[(0,b.jsx)("label",{htmlFor:t,className:"text-xs text-[color:var(--ck-text-tertiary)]",children:"Title"}),(0,b.jsx)("input",{id:t,className:e,value:h,onChange:a=>i(a.target.value),placeholder:d?"Increase trial activation":"Goal title"})]}),(0,b.jsxs)("div",{className:"grid grid-cols-1 gap-4 sm:grid-cols-3",children:[(0,b.jsxs)("div",{children:[(0,b.jsx)("label",{htmlFor:u,className:"text-xs text-[color:var(--ck-text-tertiary)]",children:"Status"}),(0,b.jsxs)("select",{id:u,className:e,value:j,onChange:a=>k(a.target.value),"aria-label":"Goal status",children:[(0,b.jsx)("option",{value:"planned",children:"Planned"}),(0,b.jsx)("option",{value:"active",children:"Active"}),(0,b.jsx)("option",{value:"done",children:"Done"})]})]}),(0,b.jsxs)("div",{children:[(0,b.jsx)("label",{htmlFor:v,className:"text-xs text-[color:var(--ck-text-tertiary)]",children:"Teams (comma-separated)"}),(0,b.jsx)("input",{id:v,className:e,value:n,onChange:a=>o(a.target.value),placeholder:"development-team, marketing-team"})]}),(0,b.jsxs)("div",{children:[(0,b.jsx)("label",{htmlFor:w,className:"text-xs text-[color:var(--ck-text-tertiary)]",children:"Tags (comma-separated)"}),(0,b.jsx)("input",{id:w,className:e,value:l,onChange:a=>m(a.target.value),placeholder:"onboarding, growth"})]})]}),(0,b.jsxs)("div",{children:[(0,b.jsxs)("div",{className:"flex items-center justify-between",children:[(0,b.jsx)("label",{htmlFor:x,className:"text-xs text-[color:var(--ck-text-tertiary)]",children:"Body (markdown)"}),null!=f?(0,b.jsx)("div",{className:"text-xs text-[color:var(--ck-text-tertiary)]",children:f?`updated ${new Date(f).toLocaleString()}`:""}):null]}),(0,b.jsx)("textarea",{id:x,className:`mt-1 ${g} w-full rounded-lg border border-[color:var(--ck-border-subtle)] bg-transparent px-3 py-2 font-mono text-sm`,value:p,onChange:a=>q(a.target.value),placeholder:"Write the goal here…"})]})]})}function g(a){return a.split(",").map(a=>a.trim()).filter(Boolean)}function h(a){let[b,d]=(0,c.useState)(a?.title??""),[e,f]=(0,c.useState)(a?.status??"planned"),[h,i]=(0,c.useState)(a?.tagsRaw??""),[j,k]=(0,c.useState)(a?.teamsRaw??""),[l,m]=(0,c.useState)(a?.body??""),n=(0,c.useMemo)(()=>({title:b,setTitle:d,status:e,setStatus:f,tagsRaw:h,setTagsRaw:i,teamsRaw:j,setTeamsRaw:k,body:l,setBody:m}),[b,e,h,j,l]);return{formState:n,tags:(0,c.useMemo)(()=>g(h),[h]),teams:(0,c.useMemo)(()=>g(j),[j])}}a.s(["GoalFormCard",()=>d,"GoalFormFields",()=>f],2561),a.s(["useGoalFormState",()=>h],14878)},96325,a=>{"use strict";var b=a.i(87924),c=a.i(38246),d=a.i(2561),e=a.i(74621),f=a.i(51200),g=a.i(14878),h=a.i(50944),i=a.i(72131);function j({goalId:a}){let j=(0,h.useRouter)(),[k,l]=(0,i.useState)(!0),[m,n]=(0,i.useState)(!1),[o,p]=(0,i.useState)(null),[q,r]=(0,i.useState)(null),{formState:s,tags:t,teams:u}=(0,g.useGoalFormState)(),{setTitle:v,setStatus:w,setTagsRaw:x,setTeamsRaw:y,setBody:z}=s,A=(0,i.useCallback)(async()=>{l(!0),p(null);try{let b=await (0,f.fetchJson)(`/api/goals/${encodeURIComponent(a)}`,{cache:"no-store"}),c=b.goal;v(c.title??""),w(c.status??"planned"),x((c.tags??[]).join(", ")),y((c.teams??[]).join(", ")),z(b.body??""),r(c.updatedAt??null)}catch(a){p((0,e.errorMessage)(a))}finally{l(!1)}},[a,v,w,x,y,z]);async function B(){n(!0),p(null);try{let b=await (0,f.fetchJson)(`/api/goals/${encodeURIComponent(a)}`,{method:"PUT",headers:{"content-type":"application/json"},body:JSON.stringify({title:s.title,status:s.status,tags:t,teams:u,body:s.body})});r(b.goal.updatedAt??null),j.push("/goals")}catch(a){p((0,e.errorMessage)(a))}finally{n(!1)}}async function C(){n(!0),p(null);try{await (0,f.fetchJson)(`/api/goals/${encodeURIComponent(a)}/promote`,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({})}),await A()}catch(a){p((0,e.errorMessage)(a))}finally{n(!1)}}async function D(){if(window.confirm(`Delete goal "${a}"? This will delete the markdown file.`)){n(!0),p(null);try{await (0,f.fetchJson)(`/api/goals/${encodeURIComponent(a)}`,{method:"DELETE"}),j.push("/goals")}catch(a){p((0,e.errorMessage)(a))}finally{n(!1)}}}return(0,i.useEffect)(()=>{A()},[A]),(0,b.jsxs)("div",{className:"space-y-4",children:[(0,b.jsxs)("div",{className:"flex items-center justify-between gap-3",children:[(0,b.jsx)(c.default,{href:"/goals",className:"text-sm font-medium hover:underline",children:"← Back"}),(0,b.jsx)("div",{className:"text-xs text-[color:var(--ck-text-tertiary)] font-mono",children:a})]}),(0,b.jsx)(d.GoalFormCard,{error:o,actions:(0,b.jsxs)("div",{className:"flex flex-wrap items-center gap-3",children:[(0,b.jsx)("button",{onClick:()=>void B(),disabled:m||k,className:"rounded-lg bg-[var(--ck-accent-red)] px-3 py-2 text-sm font-medium text-white disabled:opacity-50",children:m?"Saving…":"Save"}),(0,b.jsx)("button",{onClick:()=>void A(),disabled:m,className:"rounded-lg border border-[color:var(--ck-border-subtle)] px-3 py-2 text-sm",children:"Reload"}),(0,b.jsx)("button",{onClick:()=>void C(),disabled:m||k,className:"rounded-lg border border-[color:var(--ck-border-subtle)] px-3 py-2 text-sm font-medium",children:"Promote to inbox"}),(0,b.jsx)("button",{onClick:()=>void D(),disabled:m||k,className:"rounded-lg border border-[color:rgba(255,59,48,0.45)] bg-[color:rgba(255,59,48,0.08)] px-3 py-2 text-sm font-medium text-[color:var(--ck-accent-red)] transition-colors hover:bg-[color:rgba(255,59,48,0.12)]",children:"Delete"})]}),children:(0,b.jsx)(d.GoalFormFields,{formState:s,updatedAt:q})}),(0,b.jsxs)("div",{className:"ck-card p-6",children:[(0,b.jsx)("div",{className:"text-sm font-medium",children:"Preview"}),(0,b.jsx)("pre",{className:"mt-2 whitespace-pre-wrap break-words text-sm leading-6 text-[color:var(--ck-text-primary)]",children:s.body})]}),k?(0,b.jsx)("div",{className:"text-sm text-[color:var(--ck-text-secondary)]",children:"Loading…"}):null]})}a.s(["default",()=>j])}];
|
|
2
2
|
|
|
3
3
|
//# sourceMappingURL=src_79d55c05._.js.map
|