@alexjbarnes/cockpit 0.1.1 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.next/BUILD_ID +1 -1
- package/.next/app-path-routes-manifest.json +28 -3
- package/.next/build-manifest.json +3 -3
- package/.next/prerender-manifest.json +147 -3
- package/.next/react-loadable-manifest.json +19 -3
- package/.next/required-server-files.js +3 -0
- package/.next/required-server-files.json +3 -0
- package/.next/routes-manifest.json +162 -0
- package/.next/server/app/(app)/agents/[name]/page.js +3 -3
- package/.next/server/app/(app)/agents/[name]/page.js.nft.json +1 -1
- package/.next/server/app/(app)/agents/[name]/page_client-reference-manifest.js +1 -1
- package/.next/server/app/(app)/agents/page.js +2 -2
- package/.next/server/app/(app)/agents/page.js.nft.json +1 -1
- package/.next/server/app/(app)/agents/page_client-reference-manifest.js +1 -1
- package/.next/server/app/(app)/changes/page.js +2 -2
- package/.next/server/app/(app)/changes/page.js.nft.json +1 -1
- package/.next/server/app/(app)/changes/page_client-reference-manifest.js +1 -1
- package/.next/server/app/(app)/claude-md/edit/page.js +2 -2
- package/.next/server/app/(app)/claude-md/edit/page.js.nft.json +1 -1
- package/.next/server/app/(app)/claude-md/edit/page_client-reference-manifest.js +1 -1
- package/.next/server/app/(app)/claude-md/page.js +2 -2
- package/.next/server/app/(app)/claude-md/page.js.nft.json +1 -1
- package/.next/server/app/(app)/claude-md/page_client-reference-manifest.js +1 -1
- package/.next/server/app/(app)/commands/[name]/page.js +3 -3
- package/.next/server/app/(app)/commands/[name]/page.js.nft.json +1 -1
- package/.next/server/app/(app)/commands/[name]/page_client-reference-manifest.js +1 -1
- package/.next/server/app/(app)/commands/page.js +2 -2
- package/.next/server/app/(app)/commands/page.js.nft.json +1 -1
- package/.next/server/app/(app)/commands/page_client-reference-manifest.js +1 -1
- package/.next/server/app/(app)/files/page.js +2 -2
- package/.next/server/app/(app)/files/page.js.nft.json +1 -1
- package/.next/server/app/(app)/files/page_client-reference-manifest.js +1 -1
- package/.next/server/app/(app)/hooks/[event]/page.js +3 -3
- package/.next/server/app/(app)/hooks/[event]/page.js.nft.json +1 -1
- package/.next/server/app/(app)/hooks/[event]/page_client-reference-manifest.js +1 -1
- package/.next/server/app/(app)/hooks/page.js +2 -2
- package/.next/server/app/(app)/hooks/page.js.nft.json +1 -1
- package/.next/server/app/(app)/hooks/page_client-reference-manifest.js +1 -1
- package/.next/server/app/(app)/inbox/[id]/page.js +2 -0
- package/.next/server/app/(app)/inbox/[id]/page.js.nft.json +1 -0
- package/.next/server/app/(app)/inbox/[id]/page_client-reference-manifest.js +1 -0
- package/.next/server/app/(app)/inbox/page.js +2 -0
- package/.next/server/app/(app)/inbox/page.js.nft.json +1 -0
- package/.next/server/app/(app)/inbox/page_client-reference-manifest.js +1 -0
- package/.next/server/app/(app)/jobs/[id]/edit/page.js +2 -2
- package/.next/server/app/(app)/jobs/[id]/edit/page.js.nft.json +1 -1
- package/.next/server/app/(app)/jobs/[id]/edit/page_client-reference-manifest.js +1 -1
- package/.next/server/app/(app)/jobs/[id]/page.js +2 -2
- package/.next/server/app/(app)/jobs/[id]/page.js.nft.json +1 -1
- package/.next/server/app/(app)/jobs/[id]/page_client-reference-manifest.js +1 -1
- package/.next/server/app/(app)/jobs/[id]/runs/[runId]/page.js +2 -2
- package/.next/server/app/(app)/jobs/[id]/runs/[runId]/page.js.nft.json +1 -1
- package/.next/server/app/(app)/jobs/[id]/runs/[runId]/page_client-reference-manifest.js +1 -1
- package/.next/server/app/(app)/jobs/page.js +2 -2
- package/.next/server/app/(app)/jobs/page.js.nft.json +1 -1
- package/.next/server/app/(app)/jobs/page_client-reference-manifest.js +1 -1
- package/.next/server/app/(app)/mcp-servers/[name]/page.js +2 -2
- package/.next/server/app/(app)/mcp-servers/[name]/page.js.nft.json +1 -1
- package/.next/server/app/(app)/mcp-servers/[name]/page_client-reference-manifest.js +1 -1
- package/.next/server/app/(app)/mcp-servers/page.js +2 -2
- package/.next/server/app/(app)/mcp-servers/page.js.nft.json +1 -1
- package/.next/server/app/(app)/mcp-servers/page_client-reference-manifest.js +1 -1
- package/.next/server/app/(app)/page.js +2 -2
- package/.next/server/app/(app)/page.js.nft.json +1 -1
- package/.next/server/app/(app)/page_client-reference-manifest.js +1 -1
- package/.next/server/app/(app)/reviews/[owner]/[repo]/[number]/page.js +6 -6
- package/.next/server/app/(app)/reviews/[owner]/[repo]/[number]/page.js.nft.json +1 -1
- package/.next/server/app/(app)/reviews/[owner]/[repo]/[number]/page_client-reference-manifest.js +1 -1
- package/.next/server/app/(app)/reviews/[owner]/[repo]/page.js +2 -2
- package/.next/server/app/(app)/reviews/[owner]/[repo]/page.js.nft.json +1 -1
- package/.next/server/app/(app)/reviews/[owner]/[repo]/page_client-reference-manifest.js +1 -1
- package/.next/server/app/(app)/reviews/page.js +2 -2
- package/.next/server/app/(app)/reviews/page.js.nft.json +1 -1
- package/.next/server/app/(app)/reviews/page_client-reference-manifest.js +1 -1
- package/.next/server/app/(app)/sessions/[id]/page.js +2 -2
- package/.next/server/app/(app)/sessions/[id]/page.js.nft.json +1 -1
- package/.next/server/app/(app)/sessions/[id]/page_client-reference-manifest.js +1 -1
- package/.next/server/app/(app)/settings/appearance/page.js +2 -0
- package/.next/server/app/(app)/settings/appearance/page.js.nft.json +1 -0
- package/.next/server/app/(app)/settings/appearance/page_client-reference-manifest.js +1 -0
- package/.next/server/app/(app)/settings/notifications/page.js +2 -0
- package/.next/server/app/(app)/settings/notifications/page.js.nft.json +1 -0
- package/.next/server/app/(app)/settings/notifications/page_client-reference-manifest.js +1 -0
- package/.next/server/app/(app)/settings/page.js +2 -2
- package/.next/server/app/(app)/settings/page.js.nft.json +1 -1
- package/.next/server/app/(app)/settings/page_client-reference-manifest.js +1 -1
- package/.next/server/app/(app)/settings/providers/[id]/page.js +2 -0
- package/.next/server/app/(app)/settings/providers/[id]/page.js.nft.json +1 -0
- package/.next/server/app/(app)/settings/providers/[id]/page_client-reference-manifest.js +1 -0
- package/.next/server/app/(app)/settings/providers/new/page.js +2 -0
- package/.next/server/app/(app)/settings/providers/new/page.js.nft.json +1 -0
- package/.next/server/app/(app)/settings/providers/new/page_client-reference-manifest.js +1 -0
- package/.next/server/app/(app)/settings/providers/page.js +2 -0
- package/.next/server/app/(app)/settings/providers/page.js.nft.json +1 -0
- package/.next/server/app/(app)/settings/providers/page_client-reference-manifest.js +1 -0
- package/.next/server/app/(app)/settings/session/page.js +2 -0
- package/.next/server/app/(app)/settings/session/page.js.nft.json +1 -0
- package/.next/server/app/(app)/settings/session/page_client-reference-manifest.js +1 -0
- package/.next/server/app/(app)/skills/[name]/page.js +3 -3
- package/.next/server/app/(app)/skills/[name]/page.js.nft.json +1 -1
- package/.next/server/app/(app)/skills/[name]/page_client-reference-manifest.js +1 -1
- package/.next/server/app/(app)/skills/page.js +2 -2
- package/.next/server/app/(app)/skills/page.js.nft.json +1 -1
- package/.next/server/app/(app)/skills/page_client-reference-manifest.js +1 -1
- package/.next/server/app/_global-error/page.js +3 -3
- package/.next/server/app/_global-error/page_client-reference-manifest.js +1 -1
- package/.next/server/app/_global-error.html +1 -1
- package/.next/server/app/_global-error.rsc +1 -1
- package/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
- package/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
- package/.next/server/app/_global-error.segments/_global-error.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.js +2 -2
- 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 +2 -2
- package/.next/server/app/_not-found.segments/_full.segment.rsc +2 -2
- package/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
- package/.next/server/app/_not-found.segments/_index.segment.rsc +2 -2
- 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.html +1 -1
- package/.next/server/app/agents.rsc +4 -4
- package/.next/server/app/agents.segments/!KGFwcCk/agents/__PAGE__.segment.rsc +2 -2
- package/.next/server/app/agents.segments/!KGFwcCk/agents.segment.rsc +1 -1
- package/.next/server/app/agents.segments/!KGFwcCk.segment.rsc +2 -2
- package/.next/server/app/agents.segments/_full.segment.rsc +4 -4
- package/.next/server/app/agents.segments/_head.segment.rsc +1 -1
- package/.next/server/app/agents.segments/_index.segment.rsc +2 -2
- package/.next/server/app/agents.segments/_tree.segment.rsc +2 -2
- package/.next/server/app/api/agents/[name]/route.js +1 -1
- package/.next/server/app/api/agents/route.js +1 -1
- package/.next/server/app/api/auth/check/route.js +1 -1
- package/.next/server/app/api/auth/login/route.js +1 -1
- package/.next/server/app/api/auth/setup/route.js +1 -1
- package/.next/server/app/api/auth/ws-token/route.js +1 -1
- package/.next/server/app/api/btw/route.js +2 -2
- package/.next/server/app/api/claude-md/route.js +1 -1
- package/.next/server/app/api/commands/[name]/route.js +1 -1
- package/.next/server/app/api/commands/route.js +1 -1
- package/.next/server/app/api/defaults/route.js +1 -1
- package/.next/server/app/api/filesystem/browse/route.js +1 -1
- package/.next/server/app/api/filesystem/files/route.js +1 -1
- package/.next/server/app/api/filesystem/mkdir/route.js +1 -1
- package/.next/server/app/api/filesystem/read/route.js +1 -1
- package/.next/server/app/api/git/clone/route.js +1 -1
- package/.next/server/app/api/git/commit/route.js +1 -1
- package/.next/server/app/api/git/diff/route.js +1 -1
- package/.next/server/app/api/git/discard/route.js +1 -1
- package/.next/server/app/api/git/generate-message/route.js +2 -2
- package/.next/server/app/api/git/push/route.js +1 -1
- package/.next/server/app/api/git/status/route.js +1 -1
- package/.next/server/app/api/github/file-content/route.js +1 -1
- package/.next/server/app/api/github/orgs/route.js +1 -1
- package/.next/server/app/api/github/prs/checks/route.js +1 -1
- package/.next/server/app/api/github/prs/diff/route.js +1 -1
- package/.next/server/app/api/github/prs/review/route.js +1 -1
- package/.next/server/app/api/github/prs/route.js +1 -1
- package/.next/server/app/api/github/prs/view/route.js +1 -1
- package/.next/server/app/api/github/repos/route.js +1 -1
- package/.next/server/app/api/github/review-session/route.js +1 -1
- package/.next/server/app/api/github/review-session/route.js.nft.json +1 -1
- package/.next/server/app/api/health/route.js +1 -1
- package/.next/server/app/api/hooks/route.js +1 -1
- package/.next/server/app/api/inbox/[id]/route.js +5 -0
- package/.next/server/app/api/inbox/[id]/route.js.nft.json +1 -0
- package/.next/server/app/api/inbox/[id]/route_client-reference-manifest.js +1 -0
- package/.next/server/app/api/inbox/route.js +5 -0
- package/.next/server/app/api/inbox/route.js.nft.json +1 -0
- package/.next/server/app/api/inbox/route_client-reference-manifest.js +1 -0
- package/.next/server/app/api/jobs/[id]/route.js +1 -1
- package/.next/server/app/api/jobs/[id]/route.js.nft.json +1 -1
- package/.next/server/app/api/jobs/[id]/runs/[runId]/route.js +1 -1
- package/.next/server/app/api/jobs/[id]/runs/[runId]/transcript/route.js +1 -1
- package/.next/server/app/api/jobs/[id]/runs/route.js +1 -1
- package/.next/server/app/api/jobs/[id]/trigger/route.js +1 -1
- package/.next/server/app/api/jobs/[id]/trigger/route.js.nft.json +1 -1
- package/.next/server/app/api/jobs/mcp-discover/route.js +1 -1
- package/.next/server/app/api/jobs/mcp-discover/route.js.nft.json +1 -1
- package/.next/server/app/api/jobs/route.js +1 -1
- package/.next/server/app/api/jobs/route.js.nft.json +1 -1
- package/.next/server/app/api/jobs/status/route.js +1 -1
- package/.next/server/app/api/mcp-servers/[name]/route.js +1 -1
- package/.next/server/app/api/mcp-servers/[name]/test/route.js +1 -1
- package/.next/server/app/api/mcp-servers/route.js +1 -1
- package/.next/server/app/api/notifications/route.js +1 -0
- package/.next/server/app/api/notifications/route.js.nft.json +1 -0
- package/.next/server/app/api/notifications/route_client-reference-manifest.js +1 -0
- package/.next/server/app/api/notifications/test/route.js +5 -0
- package/.next/server/app/api/notifications/test/route.js.nft.json +1 -0
- package/.next/server/app/api/notifications/test/route_client-reference-manifest.js +1 -0
- package/.next/server/app/api/providers/[id]/route.js +1 -0
- package/.next/server/app/api/providers/[id]/route.js.nft.json +1 -0
- package/.next/server/app/api/providers/[id]/route_client-reference-manifest.js +1 -0
- package/.next/server/app/api/providers/route.js +1 -0
- package/.next/server/app/api/providers/route.js.nft.json +1 -0
- package/.next/server/app/api/providers/route_client-reference-manifest.js +1 -0
- package/.next/server/app/api/reviews/pinned/route.js +1 -0
- package/.next/server/app/api/reviews/pinned/route.js.nft.json +1 -0
- package/.next/server/app/api/reviews/pinned/route_client-reference-manifest.js +1 -0
- package/.next/server/app/api/sessions/[id]/context/route.js +1 -1
- package/.next/server/app/api/sessions/[id]/mcp/route.js +1 -1
- package/.next/server/app/api/sessions/[id]/mcp/route.js.nft.json +1 -1
- package/.next/server/app/api/sessions/[id]/route.js +1 -1
- package/.next/server/app/api/sessions/[id]/route.js.nft.json +1 -1
- package/.next/server/app/api/sessions/[id]/search/route.js +1 -1
- package/.next/server/app/api/sessions/[id]/tabs/route.js +1 -0
- package/.next/server/app/api/sessions/[id]/tabs/route.js.nft.json +1 -0
- package/.next/server/app/api/sessions/[id]/tabs/route_client-reference-manifest.js +1 -0
- package/.next/server/app/api/sessions/bulk-delete/route.js +1 -0
- package/.next/server/app/api/sessions/bulk-delete/route.js.nft.json +1 -0
- package/.next/server/app/api/sessions/bulk-delete/route_client-reference-manifest.js +1 -0
- package/.next/server/app/api/sessions/by-ids/route.js +1 -0
- package/.next/server/app/api/sessions/by-ids/route.js.nft.json +1 -0
- package/.next/server/app/api/sessions/by-ids/route_client-reference-manifest.js +1 -0
- package/.next/server/app/api/sessions/group/route.js +1 -0
- package/.next/server/app/api/sessions/group/route.js.nft.json +1 -0
- package/.next/server/app/api/sessions/group/route_client-reference-manifest.js +1 -0
- package/.next/server/app/api/sessions/pinned/route.js +1 -1
- package/.next/server/app/api/sessions/route.js +1 -1
- package/.next/server/app/api/sessions/route.js.nft.json +1 -1
- package/.next/server/app/api/sessions/search/route.js +1 -0
- package/.next/server/app/api/sessions/search/route.js.nft.json +1 -0
- package/.next/server/app/api/sessions/search/route_client-reference-manifest.js +1 -0
- package/.next/server/app/api/sessions/thinking/route.js +1 -0
- package/.next/server/app/api/sessions/thinking/route.js.nft.json +1 -0
- package/.next/server/app/api/sessions/thinking/route_client-reference-manifest.js +1 -0
- package/.next/server/app/api/skills/[name]/route.js +1 -1
- package/.next/server/app/api/skills/route.js +1 -1
- package/.next/server/app/api/terminal/[id]/route.js +1 -0
- package/.next/server/app/api/terminal/[id]/route.js.nft.json +1 -0
- package/.next/server/app/api/terminal/[id]/route_client-reference-manifest.js +1 -0
- package/.next/server/app/api/terminal/route.js +1 -0
- package/.next/server/app/api/terminal/route.js.nft.json +1 -0
- package/.next/server/app/api/terminal/route_client-reference-manifest.js +1 -0
- package/.next/server/app/api/usage/route.js +1 -1
- package/.next/server/app/api/version/changelog/route.js +1 -0
- package/.next/server/app/api/version/changelog/route.js.nft.json +1 -0
- package/.next/server/app/api/version/changelog/route_client-reference-manifest.js +1 -0
- package/.next/server/app/api/version/cockpit/changelog/route.js +1 -0
- package/.next/server/app/api/version/cockpit/changelog/route.js.nft.json +1 -0
- package/.next/server/app/api/version/cockpit/changelog/route_client-reference-manifest.js +1 -0
- package/.next/server/app/api/version/cockpit/route.js +1 -1
- package/.next/server/app/api/version/route.js +2 -2
- package/.next/server/app/changes.html +1 -1
- package/.next/server/app/changes.rsc +4 -4
- package/.next/server/app/changes.segments/!KGFwcCk/changes/__PAGE__.segment.rsc +2 -2
- package/.next/server/app/changes.segments/!KGFwcCk/changes.segment.rsc +1 -1
- package/.next/server/app/changes.segments/!KGFwcCk.segment.rsc +2 -2
- package/.next/server/app/changes.segments/_full.segment.rsc +4 -4
- package/.next/server/app/changes.segments/_head.segment.rsc +1 -1
- package/.next/server/app/changes.segments/_index.segment.rsc +2 -2
- package/.next/server/app/changes.segments/_tree.segment.rsc +2 -2
- package/.next/server/app/claude-md/edit.html +1 -1
- package/.next/server/app/claude-md/edit.rsc +4 -4
- package/.next/server/app/claude-md/edit.segments/!KGFwcCk/claude-md/edit/__PAGE__.segment.rsc +2 -2
- package/.next/server/app/claude-md/edit.segments/!KGFwcCk/claude-md/edit.segment.rsc +1 -1
- package/.next/server/app/claude-md/edit.segments/!KGFwcCk/claude-md.segment.rsc +1 -1
- package/.next/server/app/claude-md/edit.segments/!KGFwcCk.segment.rsc +2 -2
- package/.next/server/app/claude-md/edit.segments/_full.segment.rsc +4 -4
- package/.next/server/app/claude-md/edit.segments/_head.segment.rsc +1 -1
- package/.next/server/app/claude-md/edit.segments/_index.segment.rsc +2 -2
- package/.next/server/app/claude-md/edit.segments/_tree.segment.rsc +2 -2
- package/.next/server/app/claude-md.html +1 -1
- package/.next/server/app/claude-md.rsc +4 -4
- package/.next/server/app/claude-md.segments/!KGFwcCk/claude-md/__PAGE__.segment.rsc +2 -2
- package/.next/server/app/claude-md.segments/!KGFwcCk/claude-md.segment.rsc +1 -1
- package/.next/server/app/claude-md.segments/!KGFwcCk.segment.rsc +2 -2
- package/.next/server/app/claude-md.segments/_full.segment.rsc +4 -4
- package/.next/server/app/claude-md.segments/_head.segment.rsc +1 -1
- package/.next/server/app/claude-md.segments/_index.segment.rsc +2 -2
- package/.next/server/app/claude-md.segments/_tree.segment.rsc +2 -2
- package/.next/server/app/commands.html +1 -1
- package/.next/server/app/commands.rsc +4 -4
- package/.next/server/app/commands.segments/!KGFwcCk/commands/__PAGE__.segment.rsc +2 -2
- package/.next/server/app/commands.segments/!KGFwcCk/commands.segment.rsc +1 -1
- package/.next/server/app/commands.segments/!KGFwcCk.segment.rsc +2 -2
- package/.next/server/app/commands.segments/_full.segment.rsc +4 -4
- package/.next/server/app/commands.segments/_head.segment.rsc +1 -1
- package/.next/server/app/commands.segments/_index.segment.rsc +2 -2
- package/.next/server/app/commands.segments/_tree.segment.rsc +2 -2
- package/.next/server/app/files.html +1 -1
- package/.next/server/app/files.rsc +4 -4
- package/.next/server/app/files.segments/!KGFwcCk/files/__PAGE__.segment.rsc +2 -2
- package/.next/server/app/files.segments/!KGFwcCk/files.segment.rsc +1 -1
- package/.next/server/app/files.segments/!KGFwcCk.segment.rsc +2 -2
- package/.next/server/app/files.segments/_full.segment.rsc +4 -4
- package/.next/server/app/files.segments/_head.segment.rsc +1 -1
- package/.next/server/app/files.segments/_index.segment.rsc +2 -2
- package/.next/server/app/files.segments/_tree.segment.rsc +2 -2
- package/.next/server/app/hooks.html +1 -1
- package/.next/server/app/hooks.rsc +4 -4
- package/.next/server/app/hooks.segments/!KGFwcCk/hooks/__PAGE__.segment.rsc +2 -2
- package/.next/server/app/hooks.segments/!KGFwcCk/hooks.segment.rsc +1 -1
- package/.next/server/app/hooks.segments/!KGFwcCk.segment.rsc +2 -2
- package/.next/server/app/hooks.segments/_full.segment.rsc +4 -4
- package/.next/server/app/hooks.segments/_head.segment.rsc +1 -1
- package/.next/server/app/hooks.segments/_index.segment.rsc +2 -2
- package/.next/server/app/hooks.segments/_tree.segment.rsc +2 -2
- package/.next/server/app/inbox.html +1 -0
- package/.next/server/app/inbox.meta +16 -0
- package/.next/server/app/inbox.rsc +23 -0
- package/.next/server/app/inbox.segments/!KGFwcCk/inbox/__PAGE__.segment.rsc +9 -0
- package/.next/server/app/inbox.segments/!KGFwcCk/inbox.segment.rsc +5 -0
- package/.next/server/app/inbox.segments/!KGFwcCk.segment.rsc +7 -0
- package/.next/server/app/inbox.segments/_full.segment.rsc +23 -0
- package/.next/server/app/inbox.segments/_head.segment.rsc +6 -0
- package/.next/server/app/inbox.segments/_index.segment.rsc +5 -0
- package/.next/server/app/inbox.segments/_tree.segment.rsc +2 -0
- package/.next/server/app/index.html +1 -1
- package/.next/server/app/index.rsc +4 -4
- package/.next/server/app/index.segments/!KGFwcCk/__PAGE__.segment.rsc +2 -2
- package/.next/server/app/index.segments/!KGFwcCk.segment.rsc +2 -2
- package/.next/server/app/index.segments/_full.segment.rsc +4 -4
- package/.next/server/app/index.segments/_head.segment.rsc +1 -1
- package/.next/server/app/index.segments/_index.segment.rsc +2 -2
- package/.next/server/app/index.segments/_tree.segment.rsc +2 -2
- package/.next/server/app/jobs.html +1 -1
- package/.next/server/app/jobs.rsc +4 -4
- package/.next/server/app/jobs.segments/!KGFwcCk/jobs/__PAGE__.segment.rsc +2 -2
- package/.next/server/app/jobs.segments/!KGFwcCk/jobs.segment.rsc +1 -1
- package/.next/server/app/jobs.segments/!KGFwcCk.segment.rsc +2 -2
- package/.next/server/app/jobs.segments/_full.segment.rsc +4 -4
- package/.next/server/app/jobs.segments/_head.segment.rsc +1 -1
- package/.next/server/app/jobs.segments/_index.segment.rsc +2 -2
- package/.next/server/app/jobs.segments/_tree.segment.rsc +2 -2
- package/.next/server/app/login/page.js +2 -2
- package/.next/server/app/login/page_client-reference-manifest.js +1 -1
- package/.next/server/app/login.html +1 -1
- package/.next/server/app/login.rsc +2 -2
- package/.next/server/app/login.segments/_full.segment.rsc +2 -2
- package/.next/server/app/login.segments/_head.segment.rsc +1 -1
- package/.next/server/app/login.segments/_index.segment.rsc +2 -2
- package/.next/server/app/login.segments/_tree.segment.rsc +2 -2
- package/.next/server/app/login.segments/login/__PAGE__.segment.rsc +1 -1
- package/.next/server/app/login.segments/login.segment.rsc +1 -1
- package/.next/server/app/mcp-servers.html +1 -1
- package/.next/server/app/mcp-servers.rsc +4 -4
- package/.next/server/app/mcp-servers.segments/!KGFwcCk/mcp-servers/__PAGE__.segment.rsc +2 -2
- package/.next/server/app/mcp-servers.segments/!KGFwcCk/mcp-servers.segment.rsc +1 -1
- package/.next/server/app/mcp-servers.segments/!KGFwcCk.segment.rsc +2 -2
- package/.next/server/app/mcp-servers.segments/_full.segment.rsc +4 -4
- package/.next/server/app/mcp-servers.segments/_head.segment.rsc +1 -1
- package/.next/server/app/mcp-servers.segments/_index.segment.rsc +2 -2
- package/.next/server/app/mcp-servers.segments/_tree.segment.rsc +2 -2
- package/.next/server/app/reviews.html +1 -1
- package/.next/server/app/reviews.rsc +4 -4
- package/.next/server/app/reviews.segments/!KGFwcCk/reviews/__PAGE__.segment.rsc +2 -2
- package/.next/server/app/reviews.segments/!KGFwcCk/reviews.segment.rsc +1 -1
- package/.next/server/app/reviews.segments/!KGFwcCk.segment.rsc +2 -2
- package/.next/server/app/reviews.segments/_full.segment.rsc +4 -4
- package/.next/server/app/reviews.segments/_head.segment.rsc +1 -1
- package/.next/server/app/reviews.segments/_index.segment.rsc +2 -2
- package/.next/server/app/reviews.segments/_tree.segment.rsc +2 -2
- package/.next/server/app/settings/appearance.html +1 -0
- package/.next/server/app/settings/appearance.meta +17 -0
- package/.next/server/app/settings/appearance.rsc +23 -0
- package/.next/server/app/settings/appearance.segments/!KGFwcCk/settings/appearance/__PAGE__.segment.rsc +9 -0
- package/.next/server/app/settings/appearance.segments/!KGFwcCk/settings/appearance.segment.rsc +5 -0
- package/.next/server/app/settings/appearance.segments/!KGFwcCk/settings.segment.rsc +5 -0
- package/.next/server/app/settings/appearance.segments/!KGFwcCk.segment.rsc +7 -0
- package/.next/server/app/settings/appearance.segments/_full.segment.rsc +23 -0
- package/.next/server/app/settings/appearance.segments/_head.segment.rsc +6 -0
- package/.next/server/app/settings/appearance.segments/_index.segment.rsc +5 -0
- package/.next/server/app/settings/appearance.segments/_tree.segment.rsc +2 -0
- package/.next/server/app/settings/notifications.html +1 -0
- package/.next/server/app/settings/notifications.meta +17 -0
- package/.next/server/app/settings/notifications.rsc +23 -0
- package/.next/server/app/settings/notifications.segments/!KGFwcCk/settings/notifications/__PAGE__.segment.rsc +9 -0
- package/.next/server/app/settings/notifications.segments/!KGFwcCk/settings/notifications.segment.rsc +5 -0
- package/.next/server/app/settings/notifications.segments/!KGFwcCk/settings.segment.rsc +5 -0
- package/.next/server/app/settings/notifications.segments/!KGFwcCk.segment.rsc +7 -0
- package/.next/server/app/settings/notifications.segments/_full.segment.rsc +23 -0
- package/.next/server/app/settings/notifications.segments/_head.segment.rsc +6 -0
- package/.next/server/app/settings/notifications.segments/_index.segment.rsc +5 -0
- package/.next/server/app/settings/notifications.segments/_tree.segment.rsc +2 -0
- package/.next/server/app/settings/providers/new.html +1 -0
- package/.next/server/app/settings/providers/new.meta +18 -0
- package/.next/server/app/settings/providers/new.rsc +23 -0
- package/.next/server/app/settings/providers/new.segments/!KGFwcCk/settings/providers/new/__PAGE__.segment.rsc +9 -0
- package/.next/server/app/settings/providers/new.segments/!KGFwcCk/settings/providers/new.segment.rsc +5 -0
- package/.next/server/app/settings/providers/new.segments/!KGFwcCk/settings/providers.segment.rsc +5 -0
- package/.next/server/app/settings/providers/new.segments/!KGFwcCk/settings.segment.rsc +5 -0
- package/.next/server/app/settings/providers/new.segments/!KGFwcCk.segment.rsc +7 -0
- package/.next/server/app/settings/providers/new.segments/_full.segment.rsc +23 -0
- package/.next/server/app/settings/providers/new.segments/_head.segment.rsc +6 -0
- package/.next/server/app/settings/providers/new.segments/_index.segment.rsc +5 -0
- package/.next/server/app/settings/providers/new.segments/_tree.segment.rsc +2 -0
- package/.next/server/app/settings/providers.html +1 -0
- package/.next/server/app/settings/providers.meta +17 -0
- package/.next/server/app/settings/providers.rsc +23 -0
- package/.next/server/app/settings/providers.segments/!KGFwcCk/settings/providers/__PAGE__.segment.rsc +9 -0
- package/.next/server/app/settings/providers.segments/!KGFwcCk/settings/providers.segment.rsc +5 -0
- package/.next/server/app/settings/providers.segments/!KGFwcCk/settings.segment.rsc +5 -0
- package/.next/server/app/settings/providers.segments/!KGFwcCk.segment.rsc +7 -0
- package/.next/server/app/settings/providers.segments/_full.segment.rsc +23 -0
- package/.next/server/app/settings/providers.segments/_head.segment.rsc +6 -0
- package/.next/server/app/settings/providers.segments/_index.segment.rsc +5 -0
- package/.next/server/app/settings/providers.segments/_tree.segment.rsc +2 -0
- package/.next/server/app/settings/session.html +1 -0
- package/.next/server/app/settings/session.meta +17 -0
- package/.next/server/app/settings/session.rsc +23 -0
- package/.next/server/app/settings/session.segments/!KGFwcCk/settings/session/__PAGE__.segment.rsc +9 -0
- package/.next/server/app/settings/session.segments/!KGFwcCk/settings/session.segment.rsc +5 -0
- package/.next/server/app/settings/session.segments/!KGFwcCk/settings.segment.rsc +5 -0
- package/.next/server/app/settings/session.segments/!KGFwcCk.segment.rsc +7 -0
- package/.next/server/app/settings/session.segments/_full.segment.rsc +23 -0
- package/.next/server/app/settings/session.segments/_head.segment.rsc +6 -0
- package/.next/server/app/settings/session.segments/_index.segment.rsc +5 -0
- package/.next/server/app/settings/session.segments/_tree.segment.rsc +2 -0
- package/.next/server/app/settings.html +1 -1
- package/.next/server/app/settings.rsc +4 -4
- package/.next/server/app/settings.segments/!KGFwcCk/settings/__PAGE__.segment.rsc +2 -2
- package/.next/server/app/settings.segments/!KGFwcCk/settings.segment.rsc +1 -1
- package/.next/server/app/settings.segments/!KGFwcCk.segment.rsc +2 -2
- package/.next/server/app/settings.segments/_full.segment.rsc +4 -4
- package/.next/server/app/settings.segments/_head.segment.rsc +1 -1
- package/.next/server/app/settings.segments/_index.segment.rsc +2 -2
- package/.next/server/app/settings.segments/_tree.segment.rsc +2 -2
- package/.next/server/app/skills.html +1 -1
- package/.next/server/app/skills.rsc +4 -4
- package/.next/server/app/skills.segments/!KGFwcCk/skills/__PAGE__.segment.rsc +2 -2
- package/.next/server/app/skills.segments/!KGFwcCk/skills.segment.rsc +1 -1
- package/.next/server/app/skills.segments/!KGFwcCk.segment.rsc +2 -2
- package/.next/server/app/skills.segments/_full.segment.rsc +4 -4
- package/.next/server/app/skills.segments/_head.segment.rsc +1 -1
- package/.next/server/app/skills.segments/_index.segment.rsc +2 -2
- package/.next/server/app/skills.segments/_tree.segment.rsc +2 -2
- package/.next/server/app-paths-manifest.json +28 -3
- package/.next/server/chunks/1002.js +18 -0
- package/.next/server/chunks/1011.js +1 -0
- package/.next/server/chunks/1979.js +2 -2
- package/.next/server/chunks/{9012.js → 3006.js} +3 -3
- package/.next/server/chunks/3108.js +1 -0
- package/.next/server/chunks/3434.js +1 -0
- package/.next/server/chunks/{6142.js → 4342.js} +1 -1
- package/.next/server/chunks/4352.js +1 -0
- package/.next/server/chunks/4445.js +1 -1
- package/.next/server/chunks/5965.js +1 -1
- package/.next/server/chunks/7782.js +6 -0
- package/.next/server/chunks/8148.js +1 -0
- package/.next/server/chunks/9599.js +11 -0
- package/.next/server/middleware-build-manifest.js +1 -1
- package/.next/server/middleware-react-loadable-manifest.js +1 -1
- package/.next/server/pages/404.html +1 -1
- package/.next/server/pages/500.html +1 -1
- package/.next/server/server-reference-manifest.json +1 -1
- package/.next/static/chunks/{35922.5bdf78a760129504.js → 13541.056c34ca7fde6869.js} +1 -1
- package/.next/static/chunks/26126-97874904b42befb8.js +1 -0
- package/.next/static/chunks/{22086-756d490e3320ad15.js → 31010-6e87f77b97544424.js} +1 -1
- package/.next/static/chunks/3765-d323c6675307a63e.js +20 -0
- package/.next/static/chunks/41487-d802643f4a8fad3c.js +199 -0
- package/.next/static/chunks/48273-bbd15bac6733dfc4.js +6 -0
- package/.next/static/chunks/{80392.bca860d8b5972706.js → 58011.3de5770e8b0d8759.js} +1 -1
- package/.next/static/chunks/63606.a387b0261d6523ab.js +1 -0
- package/.next/static/chunks/6935-f436a624267529fb.js +1 -0
- package/.next/static/chunks/{69427.755a0a4013596f7a.js → 69427.a0b463c808aa54c8.js} +1 -1
- package/.next/static/chunks/86939-dfc6f8eb395caa89.js +1 -0
- package/.next/static/chunks/app/(app)/agents/[name]/page-8bdd0359043537d4.js +8 -0
- package/.next/static/chunks/app/(app)/agents/page-6fcfd7ab6781814e.js +1 -0
- package/.next/static/chunks/app/(app)/changes/page-4549a5bd72d77e3e.js +1 -0
- package/.next/static/chunks/app/(app)/claude-md/edit/page-08e6e120e71979f4.js +1 -0
- package/.next/static/chunks/app/(app)/claude-md/page-cd9e2176a12ba241.js +1 -0
- package/.next/static/chunks/app/(app)/commands/[name]/page-7cdfdef29ded0aa0.js +6 -0
- package/.next/static/chunks/app/(app)/commands/page-f126b608b04747ac.js +1 -0
- package/.next/static/chunks/app/(app)/files/page-f526eb95821e000e.js +1 -0
- package/.next/static/chunks/app/(app)/hooks/[event]/page-28038323fd29adfa.js +6 -0
- package/.next/static/chunks/app/(app)/hooks/page-f1f39284e53c0344.js +1 -0
- package/.next/static/chunks/app/(app)/inbox/[id]/page-bc1ff3a0db0114a4.js +1 -0
- package/.next/static/chunks/app/(app)/inbox/page-82e03870103ce9bd.js +1 -0
- package/.next/static/chunks/app/(app)/jobs/[id]/edit/page-7fb788f772ff2129.js +1 -0
- package/.next/static/chunks/app/(app)/jobs/[id]/page-a5856b9ae967ff59.js +1 -0
- package/.next/static/chunks/app/(app)/jobs/[id]/runs/[runId]/page-b7c513402db11db6.js +1 -0
- package/.next/static/chunks/app/(app)/jobs/page-e9bbd6c116b9699f.js +1 -0
- package/.next/static/chunks/app/(app)/layout-ce9e1be301c60fe5.js +1 -0
- package/.next/static/chunks/app/(app)/mcp-servers/[name]/page-d6d805a27ec0b0c0.js +1 -0
- package/.next/static/chunks/app/(app)/mcp-servers/page-4b7276d43451cd43.js +1 -0
- package/.next/static/chunks/app/(app)/page-027a5382da30ddb9.js +1 -0
- package/.next/static/chunks/app/(app)/reviews/[owner]/[repo]/[number]/page-9ab2955c455bb5fa.js +13 -0
- package/.next/static/chunks/app/(app)/reviews/[owner]/[repo]/page-c5fd013309ab3eba.js +1 -0
- package/.next/static/chunks/app/(app)/reviews/page-47530d93bb9d4a76.js +1 -0
- package/.next/static/chunks/app/(app)/sessions/[id]/page-94f891e1b54fd05f.js +1 -0
- package/.next/static/chunks/app/(app)/settings/appearance/page-95902da748ac5f1e.js +1 -0
- package/.next/static/chunks/app/(app)/settings/notifications/page-229f1db6beb1d19c.js +1 -0
- package/.next/static/chunks/app/(app)/settings/page-8ed16a66fdde10cd.js +1 -0
- package/.next/static/chunks/app/(app)/settings/providers/[id]/page-13654263246617b3.js +1 -0
- package/.next/static/chunks/app/(app)/settings/providers/new/page-e1798e321ccbc6df.js +1 -0
- package/.next/static/chunks/app/(app)/settings/providers/page-0bb4c1db2ee35b3d.js +1 -0
- package/.next/static/chunks/app/(app)/settings/session/page-ab216a8fa37a0f76.js +1 -0
- package/.next/static/chunks/app/(app)/skills/[name]/page-8ab85d5090967ee4.js +6 -0
- package/.next/static/chunks/app/(app)/skills/page-c52773eacb27c04e.js +1 -0
- package/.next/static/chunks/app/_global-error/page-fc747760bd4c8a4b.js +1 -0
- package/.next/static/chunks/app/api/agents/[name]/route-fc747760bd4c8a4b.js +1 -0
- package/.next/static/chunks/app/api/agents/route-fc747760bd4c8a4b.js +1 -0
- package/.next/static/chunks/app/api/auth/check/route-fc747760bd4c8a4b.js +1 -0
- package/.next/static/chunks/app/api/auth/login/route-fc747760bd4c8a4b.js +1 -0
- package/.next/static/chunks/app/api/auth/setup/route-fc747760bd4c8a4b.js +1 -0
- package/.next/static/chunks/app/api/auth/ws-token/route-fc747760bd4c8a4b.js +1 -0
- package/.next/static/chunks/app/api/btw/route-fc747760bd4c8a4b.js +1 -0
- package/.next/static/chunks/app/api/claude-md/route-fc747760bd4c8a4b.js +1 -0
- package/.next/static/chunks/app/api/commands/[name]/route-fc747760bd4c8a4b.js +1 -0
- package/.next/static/chunks/app/api/commands/route-fc747760bd4c8a4b.js +1 -0
- package/.next/static/chunks/app/api/defaults/route-fc747760bd4c8a4b.js +1 -0
- package/.next/static/chunks/app/api/filesystem/browse/route-fc747760bd4c8a4b.js +1 -0
- package/.next/static/chunks/app/api/filesystem/files/route-fc747760bd4c8a4b.js +1 -0
- package/.next/static/chunks/app/api/filesystem/mkdir/route-fc747760bd4c8a4b.js +1 -0
- package/.next/static/chunks/app/api/filesystem/read/route-fc747760bd4c8a4b.js +1 -0
- package/.next/static/chunks/app/api/git/clone/route-fc747760bd4c8a4b.js +1 -0
- package/.next/static/chunks/app/api/git/commit/route-fc747760bd4c8a4b.js +1 -0
- package/.next/static/chunks/app/api/git/diff/route-fc747760bd4c8a4b.js +1 -0
- package/.next/static/chunks/app/api/git/discard/route-fc747760bd4c8a4b.js +1 -0
- package/.next/static/chunks/app/api/git/generate-message/route-fc747760bd4c8a4b.js +1 -0
- package/.next/static/chunks/app/api/git/push/route-fc747760bd4c8a4b.js +1 -0
- package/.next/static/chunks/app/api/git/status/route-fc747760bd4c8a4b.js +1 -0
- package/.next/static/chunks/app/api/github/file-content/route-fc747760bd4c8a4b.js +1 -0
- package/.next/static/chunks/app/api/github/orgs/route-fc747760bd4c8a4b.js +1 -0
- package/.next/static/chunks/app/api/github/prs/checks/route-fc747760bd4c8a4b.js +1 -0
- package/.next/static/chunks/app/api/github/prs/diff/route-fc747760bd4c8a4b.js +1 -0
- package/.next/static/chunks/app/api/github/prs/review/route-fc747760bd4c8a4b.js +1 -0
- package/.next/static/chunks/app/api/github/prs/route-fc747760bd4c8a4b.js +1 -0
- package/.next/static/chunks/app/api/github/prs/view/route-fc747760bd4c8a4b.js +1 -0
- package/.next/static/chunks/app/api/github/repos/route-fc747760bd4c8a4b.js +1 -0
- package/.next/static/chunks/app/api/github/review-session/route-fc747760bd4c8a4b.js +1 -0
- package/.next/static/chunks/app/api/health/route-fc747760bd4c8a4b.js +1 -0
- package/.next/static/chunks/app/api/hooks/route-fc747760bd4c8a4b.js +1 -0
- package/.next/static/chunks/app/api/inbox/[id]/route-fc747760bd4c8a4b.js +1 -0
- package/.next/static/chunks/app/api/inbox/route-fc747760bd4c8a4b.js +1 -0
- package/.next/static/chunks/app/api/jobs/[id]/route-fc747760bd4c8a4b.js +1 -0
- package/.next/static/chunks/app/api/jobs/[id]/runs/[runId]/route-fc747760bd4c8a4b.js +1 -0
- package/.next/static/chunks/app/api/jobs/[id]/runs/[runId]/transcript/route-fc747760bd4c8a4b.js +1 -0
- package/.next/static/chunks/app/api/jobs/[id]/runs/route-fc747760bd4c8a4b.js +1 -0
- package/.next/static/chunks/app/api/jobs/[id]/trigger/route-fc747760bd4c8a4b.js +1 -0
- package/.next/static/chunks/app/api/jobs/mcp-discover/route-fc747760bd4c8a4b.js +1 -0
- package/.next/static/chunks/app/api/jobs/route-fc747760bd4c8a4b.js +1 -0
- package/.next/static/chunks/app/api/jobs/status/route-fc747760bd4c8a4b.js +1 -0
- package/.next/static/chunks/app/api/mcp-servers/[name]/route-fc747760bd4c8a4b.js +1 -0
- package/.next/static/chunks/app/api/mcp-servers/[name]/test/route-fc747760bd4c8a4b.js +1 -0
- package/.next/static/chunks/app/api/mcp-servers/route-fc747760bd4c8a4b.js +1 -0
- package/.next/static/chunks/app/api/notifications/route-fc747760bd4c8a4b.js +1 -0
- package/.next/static/chunks/app/api/notifications/test/route-fc747760bd4c8a4b.js +1 -0
- package/.next/static/chunks/app/api/providers/[id]/route-fc747760bd4c8a4b.js +1 -0
- package/.next/static/chunks/app/api/providers/route-fc747760bd4c8a4b.js +1 -0
- package/.next/static/chunks/app/api/reviews/pinned/route-fc747760bd4c8a4b.js +1 -0
- package/.next/static/chunks/app/api/sessions/[id]/context/route-fc747760bd4c8a4b.js +1 -0
- package/.next/static/chunks/app/api/sessions/[id]/mcp/route-fc747760bd4c8a4b.js +1 -0
- package/.next/static/chunks/app/api/sessions/[id]/route-fc747760bd4c8a4b.js +1 -0
- package/.next/static/chunks/app/api/sessions/[id]/search/route-fc747760bd4c8a4b.js +1 -0
- package/.next/static/chunks/app/api/sessions/[id]/tabs/route-fc747760bd4c8a4b.js +1 -0
- package/.next/static/chunks/app/api/sessions/bulk-delete/route-fc747760bd4c8a4b.js +1 -0
- package/.next/static/chunks/app/api/sessions/by-ids/route-fc747760bd4c8a4b.js +1 -0
- package/.next/static/chunks/app/api/sessions/group/route-fc747760bd4c8a4b.js +1 -0
- package/.next/static/chunks/app/api/sessions/pinned/route-fc747760bd4c8a4b.js +1 -0
- package/.next/static/chunks/app/api/sessions/route-fc747760bd4c8a4b.js +1 -0
- package/.next/static/chunks/app/api/sessions/search/route-fc747760bd4c8a4b.js +1 -0
- package/.next/static/chunks/app/api/sessions/thinking/route-fc747760bd4c8a4b.js +1 -0
- package/.next/static/chunks/app/api/skills/[name]/route-fc747760bd4c8a4b.js +1 -0
- package/.next/static/chunks/app/api/skills/route-fc747760bd4c8a4b.js +1 -0
- package/.next/static/chunks/app/api/terminal/[id]/route-fc747760bd4c8a4b.js +1 -0
- package/.next/static/chunks/app/api/terminal/route-fc747760bd4c8a4b.js +1 -0
- package/.next/static/chunks/app/api/usage/route-fc747760bd4c8a4b.js +1 -0
- package/.next/static/chunks/app/api/version/changelog/route-fc747760bd4c8a4b.js +1 -0
- package/.next/static/chunks/app/api/version/cockpit/changelog/route-fc747760bd4c8a4b.js +1 -0
- package/.next/static/chunks/app/api/version/cockpit/route-fc747760bd4c8a4b.js +1 -0
- package/.next/static/chunks/app/api/version/route-fc747760bd4c8a4b.js +1 -0
- package/.next/static/chunks/e868780c.f24b6da08e62c7b2.js +18 -0
- package/.next/static/chunks/next/dist/client/components/builtin/app-error-fc747760bd4c8a4b.js +1 -0
- package/.next/static/chunks/next/dist/client/components/builtin/forbidden-fc747760bd4c8a4b.js +1 -0
- package/.next/static/chunks/next/dist/client/components/builtin/not-found-fc747760bd4c8a4b.js +1 -0
- package/.next/static/chunks/next/dist/client/components/builtin/unauthorized-fc747760bd4c8a4b.js +1 -0
- package/.next/static/chunks/webpack-e31bb45fa59caed8.js +1 -0
- package/.next/static/css/3f8af4ae6f812d5c.css +1 -0
- package/.next/static/zr8XZzqb74eHitdlkpo-C/_buildManifest.js +1 -0
- package/README.md +14 -4
- package/bin/cockpit-hook-bridge.mjs +101 -0
- package/dist/server.js +49 -2
- package/dist/src/lib/models.js +48 -7
- package/dist/src/server/auth.js +32 -10
- package/dist/src/server/claude-settings.js +153 -0
- package/dist/src/server/cli-init-fetch.js +86 -0
- package/dist/src/server/cron-utils.js +16 -5
- package/dist/src/server/debug-logger.js +2 -2
- package/dist/src/server/defaults.js +18 -7
- package/dist/src/server/fs-watcher.js +50 -0
- package/dist/src/server/hook-bridge-path.js +34 -0
- package/dist/src/server/hook-event-translator.js +211 -0
- package/dist/src/server/hook-router.js +150 -0
- package/dist/src/server/inbox.js +136 -0
- package/dist/src/server/job-lock.js +103 -0
- package/dist/src/server/job-scheduler.js +170 -43
- package/dist/src/server/job-storage.js +32 -20
- package/dist/src/server/notification-settings.js +43 -0
- package/dist/src/server/notifications.js +125 -0
- package/dist/src/server/paths.js +23 -0
- package/dist/src/server/plans.js +8 -5
- package/dist/src/server/providers.js +128 -0
- package/dist/src/server/pty-runtime.js +324 -0
- package/dist/src/server/pty-session.js +178 -0
- package/dist/src/server/session-manager.js +838 -152
- package/dist/src/server/session-prefs.js +33 -8
- package/dist/src/server/singleton.js +18 -0
- package/dist/src/server/stream-processor.js +61 -48
- package/dist/src/server/terminal-manager.js +153 -0
- package/dist/src/server/todo-watcher.js +178 -0
- package/dist/src/server/transcript-watcher.js +91 -0
- package/dist/src/server/transcript.js +444 -13
- package/dist/src/server/ws-handler.js +251 -74
- package/next.config.ts +1 -0
- package/package.json +10 -3
- package/public/fonts/symbols-nerd-font-mono.woff2 +0 -0
- package/.next/server/chunks/1941.js +0 -9
- package/.next/server/chunks/2444.js +0 -6
- package/.next/server/chunks/8346.js +0 -1
- package/.next/static/V2EfPtTUC96VYyF12K0om/_buildManifest.js +0 -1
- package/.next/static/chunks/30120-1535e9064b17ce74.js +0 -20
- package/.next/static/chunks/66997-652baf5596173fea.js +0 -199
- package/.next/static/chunks/93273-c5cb6dcedef67c81.js +0 -6
- package/.next/static/chunks/app/(app)/agents/[name]/page-44c5691c80f17d38.js +0 -8
- package/.next/static/chunks/app/(app)/agents/page-4ce7a715bc0145dc.js +0 -1
- package/.next/static/chunks/app/(app)/changes/page-84cf4cd3ca347d98.js +0 -1
- package/.next/static/chunks/app/(app)/claude-md/edit/page-fb7117171d0f94d2.js +0 -1
- package/.next/static/chunks/app/(app)/claude-md/page-9503f1415e660911.js +0 -1
- package/.next/static/chunks/app/(app)/commands/[name]/page-6ef571e73b105248.js +0 -6
- package/.next/static/chunks/app/(app)/commands/page-e8a506da73d1c280.js +0 -1
- package/.next/static/chunks/app/(app)/files/page-67a95d351a685d79.js +0 -1
- package/.next/static/chunks/app/(app)/hooks/[event]/page-03f85595561b068a.js +0 -6
- package/.next/static/chunks/app/(app)/hooks/page-5578c83ad353e307.js +0 -1
- package/.next/static/chunks/app/(app)/jobs/[id]/edit/page-51d784c59737778c.js +0 -1
- package/.next/static/chunks/app/(app)/jobs/[id]/page-7d00e7a01c70a261.js +0 -1
- package/.next/static/chunks/app/(app)/jobs/[id]/runs/[runId]/page-665191da233fde19.js +0 -1
- package/.next/static/chunks/app/(app)/jobs/page-8b4ee1166a53d5e1.js +0 -1
- package/.next/static/chunks/app/(app)/layout-8dad55d6ce637a01.js +0 -1
- package/.next/static/chunks/app/(app)/mcp-servers/[name]/page-c30f0d78daf7719e.js +0 -1
- package/.next/static/chunks/app/(app)/mcp-servers/page-737b87d338afdb49.js +0 -1
- package/.next/static/chunks/app/(app)/page-40052655d2a9a84f.js +0 -1
- package/.next/static/chunks/app/(app)/reviews/[owner]/[repo]/[number]/page-1d9179bf5a4de7a4.js +0 -13
- package/.next/static/chunks/app/(app)/reviews/[owner]/[repo]/page-d8a9ee39e7cc056a.js +0 -1
- package/.next/static/chunks/app/(app)/reviews/page-098e6e6fe3123e02.js +0 -1
- package/.next/static/chunks/app/(app)/sessions/[id]/page-a74f7fe8322678ba.js +0 -1
- package/.next/static/chunks/app/(app)/settings/page-1fa46b8ac8e22927.js +0 -1
- package/.next/static/chunks/app/(app)/skills/[name]/page-e6572062a6ad90df.js +0 -6
- package/.next/static/chunks/app/(app)/skills/page-8fca8814aa818ae6.js +0 -1
- package/.next/static/chunks/app/_global-error/page-b277aba73f9e0212.js +0 -1
- package/.next/static/chunks/app/api/agents/[name]/route-b277aba73f9e0212.js +0 -1
- package/.next/static/chunks/app/api/agents/route-b277aba73f9e0212.js +0 -1
- package/.next/static/chunks/app/api/auth/check/route-b277aba73f9e0212.js +0 -1
- package/.next/static/chunks/app/api/auth/login/route-b277aba73f9e0212.js +0 -1
- package/.next/static/chunks/app/api/auth/setup/route-b277aba73f9e0212.js +0 -1
- package/.next/static/chunks/app/api/auth/ws-token/route-b277aba73f9e0212.js +0 -1
- package/.next/static/chunks/app/api/btw/route-b277aba73f9e0212.js +0 -1
- package/.next/static/chunks/app/api/claude-md/route-b277aba73f9e0212.js +0 -1
- package/.next/static/chunks/app/api/commands/[name]/route-b277aba73f9e0212.js +0 -1
- package/.next/static/chunks/app/api/commands/route-b277aba73f9e0212.js +0 -1
- package/.next/static/chunks/app/api/defaults/route-b277aba73f9e0212.js +0 -1
- package/.next/static/chunks/app/api/filesystem/browse/route-b277aba73f9e0212.js +0 -1
- package/.next/static/chunks/app/api/filesystem/files/route-b277aba73f9e0212.js +0 -1
- package/.next/static/chunks/app/api/filesystem/mkdir/route-b277aba73f9e0212.js +0 -1
- package/.next/static/chunks/app/api/filesystem/read/route-b277aba73f9e0212.js +0 -1
- package/.next/static/chunks/app/api/git/clone/route-b277aba73f9e0212.js +0 -1
- package/.next/static/chunks/app/api/git/commit/route-b277aba73f9e0212.js +0 -1
- package/.next/static/chunks/app/api/git/diff/route-b277aba73f9e0212.js +0 -1
- package/.next/static/chunks/app/api/git/discard/route-b277aba73f9e0212.js +0 -1
- package/.next/static/chunks/app/api/git/generate-message/route-b277aba73f9e0212.js +0 -1
- package/.next/static/chunks/app/api/git/push/route-b277aba73f9e0212.js +0 -1
- package/.next/static/chunks/app/api/git/status/route-b277aba73f9e0212.js +0 -1
- package/.next/static/chunks/app/api/github/file-content/route-b277aba73f9e0212.js +0 -1
- package/.next/static/chunks/app/api/github/orgs/route-b277aba73f9e0212.js +0 -1
- package/.next/static/chunks/app/api/github/prs/checks/route-b277aba73f9e0212.js +0 -1
- package/.next/static/chunks/app/api/github/prs/diff/route-b277aba73f9e0212.js +0 -1
- package/.next/static/chunks/app/api/github/prs/review/route-b277aba73f9e0212.js +0 -1
- package/.next/static/chunks/app/api/github/prs/route-b277aba73f9e0212.js +0 -1
- package/.next/static/chunks/app/api/github/prs/view/route-b277aba73f9e0212.js +0 -1
- package/.next/static/chunks/app/api/github/repos/route-b277aba73f9e0212.js +0 -1
- package/.next/static/chunks/app/api/github/review-session/route-b277aba73f9e0212.js +0 -1
- package/.next/static/chunks/app/api/health/route-b277aba73f9e0212.js +0 -1
- package/.next/static/chunks/app/api/hooks/route-b277aba73f9e0212.js +0 -1
- package/.next/static/chunks/app/api/jobs/[id]/route-b277aba73f9e0212.js +0 -1
- package/.next/static/chunks/app/api/jobs/[id]/runs/[runId]/route-b277aba73f9e0212.js +0 -1
- package/.next/static/chunks/app/api/jobs/[id]/runs/[runId]/transcript/route-b277aba73f9e0212.js +0 -1
- package/.next/static/chunks/app/api/jobs/[id]/runs/route-b277aba73f9e0212.js +0 -1
- package/.next/static/chunks/app/api/jobs/[id]/trigger/route-b277aba73f9e0212.js +0 -1
- package/.next/static/chunks/app/api/jobs/mcp-discover/route-b277aba73f9e0212.js +0 -1
- package/.next/static/chunks/app/api/jobs/route-b277aba73f9e0212.js +0 -1
- package/.next/static/chunks/app/api/jobs/status/route-b277aba73f9e0212.js +0 -1
- package/.next/static/chunks/app/api/mcp-servers/[name]/route-b277aba73f9e0212.js +0 -1
- package/.next/static/chunks/app/api/mcp-servers/[name]/test/route-b277aba73f9e0212.js +0 -1
- package/.next/static/chunks/app/api/mcp-servers/route-b277aba73f9e0212.js +0 -1
- package/.next/static/chunks/app/api/sessions/[id]/context/route-b277aba73f9e0212.js +0 -1
- package/.next/static/chunks/app/api/sessions/[id]/mcp/route-b277aba73f9e0212.js +0 -1
- package/.next/static/chunks/app/api/sessions/[id]/route-b277aba73f9e0212.js +0 -1
- package/.next/static/chunks/app/api/sessions/[id]/search/route-b277aba73f9e0212.js +0 -1
- package/.next/static/chunks/app/api/sessions/pinned/route-b277aba73f9e0212.js +0 -1
- package/.next/static/chunks/app/api/sessions/route-b277aba73f9e0212.js +0 -1
- package/.next/static/chunks/app/api/skills/[name]/route-b277aba73f9e0212.js +0 -1
- package/.next/static/chunks/app/api/skills/route-b277aba73f9e0212.js +0 -1
- package/.next/static/chunks/app/api/usage/route-b277aba73f9e0212.js +0 -1
- package/.next/static/chunks/app/api/version/cockpit/route-b277aba73f9e0212.js +0 -1
- package/.next/static/chunks/app/api/version/route-b277aba73f9e0212.js +0 -1
- package/.next/static/chunks/next/dist/client/components/builtin/app-error-b277aba73f9e0212.js +0 -1
- package/.next/static/chunks/next/dist/client/components/builtin/forbidden-b277aba73f9e0212.js +0 -1
- package/.next/static/chunks/next/dist/client/components/builtin/not-found-b277aba73f9e0212.js +0 -1
- package/.next/static/chunks/next/dist/client/components/builtin/unauthorized-b277aba73f9e0212.js +0 -1
- package/.next/static/chunks/webpack-2a5835e108df6f34.js +0 -1
- package/.next/static/css/1e1239c76b265910.css +0 -1
- /package/.next/static/{V2EfPtTUC96VYyF12K0om → zr8XZzqb74eHitdlkpo-C}/_ssgManifest.js +0 -0
|
@@ -4,21 +4,41 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
exports.SessionManager = void 0;
|
|
7
|
-
exports.extractTodosFromHistory = extractTodosFromHistory;
|
|
8
7
|
const node_child_process_1 = require("node:child_process");
|
|
9
8
|
const node_events_1 = require("node:events");
|
|
10
9
|
const node_fs_1 = require("node:fs");
|
|
11
|
-
const node_os_1 = require("node:os");
|
|
12
10
|
const node_path_1 = __importDefault(require("node:path"));
|
|
13
11
|
const uuid_1 = require("uuid");
|
|
14
12
|
const models_1 = require("../lib/models");
|
|
13
|
+
const paths_1 = require("../server/paths");
|
|
14
|
+
const providers_1 = require("../server/providers");
|
|
15
15
|
const debug_logger_1 = require("./debug-logger");
|
|
16
16
|
const defaults_1 = require("./defaults");
|
|
17
17
|
const event_parser_1 = require("./event-parser");
|
|
18
18
|
const plans_1 = require("./plans");
|
|
19
|
+
const pty_runtime_1 = require("./pty-runtime");
|
|
19
20
|
const session_prefs_1 = require("./session-prefs");
|
|
21
|
+
const singleton_1 = require("./singleton");
|
|
20
22
|
const stream_processor_1 = require("./stream-processor");
|
|
23
|
+
const todo_watcher_1 = require("./todo-watcher");
|
|
21
24
|
const transcript_1 = require("./transcript");
|
|
25
|
+
const transcript_watcher_1 = require("./transcript-watcher");
|
|
26
|
+
function defaultRuntime() {
|
|
27
|
+
return "stream";
|
|
28
|
+
}
|
|
29
|
+
let resolvedClaudeBin = null;
|
|
30
|
+
function getClaudeBin() {
|
|
31
|
+
if (resolvedClaudeBin)
|
|
32
|
+
return resolvedClaudeBin;
|
|
33
|
+
const cmd = process.platform === "win32" ? "where" : "which";
|
|
34
|
+
try {
|
|
35
|
+
resolvedClaudeBin = (0, node_child_process_1.execFileSync)(cmd, ["claude"], { encoding: "utf-8" }).trim().split("\n")[0];
|
|
36
|
+
}
|
|
37
|
+
catch {
|
|
38
|
+
resolvedClaudeBin = "claude";
|
|
39
|
+
}
|
|
40
|
+
return resolvedClaudeBin;
|
|
41
|
+
}
|
|
22
42
|
const smLog = (sessionId, msg) => {
|
|
23
43
|
if (!(0, debug_logger_1.isDebugEnabled)())
|
|
24
44
|
return;
|
|
@@ -32,9 +52,9 @@ class SessionManager {
|
|
|
32
52
|
// Periodically check for sessions stuck in "running" with a dead process
|
|
33
53
|
setInterval(() => {
|
|
34
54
|
for (const [id, session] of this.sessions) {
|
|
35
|
-
if (session.info.status === "running" && !session.process) {
|
|
55
|
+
if (session.info.status === "running" && !session.process && !session.ptyRuntime?.isAlive) {
|
|
36
56
|
const short = id.slice(0, 8);
|
|
37
|
-
(0, debug_logger_1.debugLog)(`[session:${short}] stale check: status=running but process
|
|
57
|
+
(0, debug_logger_1.debugLog)(`[session:${short}] stale check: status=running but no live process, correcting to idle`);
|
|
38
58
|
(0, debug_logger_1.logDiag)(id, "idle:stale-check");
|
|
39
59
|
session.info.status = "idle";
|
|
40
60
|
session.emitter.emit("status", id, "idle");
|
|
@@ -46,6 +66,8 @@ class SessionManager {
|
|
|
46
66
|
const id = (0, uuid_1.v4)();
|
|
47
67
|
const now = Date.now();
|
|
48
68
|
const defaults = (0, defaults_1.getDefaults)();
|
|
69
|
+
const modelSlots = { main: defaults.modelSlots.main ?? "sonnet" };
|
|
70
|
+
const rt = options?.runtime ?? defaultRuntime();
|
|
49
71
|
const info = {
|
|
50
72
|
id,
|
|
51
73
|
name: name || node_path_1.default.basename(cwd) || cwd,
|
|
@@ -53,7 +75,10 @@ class SessionManager {
|
|
|
53
75
|
createdAt: now,
|
|
54
76
|
lastActiveAt: now,
|
|
55
77
|
status: "idle",
|
|
56
|
-
model:
|
|
78
|
+
model: modelSlots.main,
|
|
79
|
+
contextSize: defaults.modelSlots?.mainContext ?? models_1.DEFAULT_CONTEXT_SIZE,
|
|
80
|
+
runtime: rt,
|
|
81
|
+
pendingRequestCount: 0,
|
|
57
82
|
};
|
|
58
83
|
this.sessions.set(id, {
|
|
59
84
|
info,
|
|
@@ -70,27 +95,42 @@ class SessionManager {
|
|
|
70
95
|
thinkingLevel: defaults.thinkingLevel,
|
|
71
96
|
streamState: null,
|
|
72
97
|
contextUsage: null,
|
|
73
|
-
contextWindowSize:
|
|
98
|
+
contextWindowSize: (0, models_1.contextSizeToWindow)(info.contextSize ?? models_1.DEFAULT_CONTEXT_SIZE),
|
|
74
99
|
todoItems: [],
|
|
75
100
|
pendingRequests: new Map(),
|
|
76
101
|
controlCallbacks: new Map(),
|
|
77
102
|
streamingSnapshot: null,
|
|
78
103
|
queuedMessages: [],
|
|
79
104
|
queuePaused: false,
|
|
105
|
+
modelSlots,
|
|
80
106
|
transcriptBuffer: [],
|
|
81
107
|
transcriptByteOffset: 0,
|
|
82
108
|
transcriptTotalSize: 0,
|
|
83
109
|
bufferCliSessionId: id,
|
|
84
110
|
paginationPrevIds: [],
|
|
111
|
+
runtime: rt,
|
|
112
|
+
ptyRuntime: null,
|
|
113
|
+
transcriptWatcher: null,
|
|
114
|
+
todoWatcher: null,
|
|
115
|
+
attachmentPaths: [],
|
|
116
|
+
totalTokens: { input: 0, output: 0, cacheCreate: 0, cacheRead: 0 },
|
|
85
117
|
});
|
|
118
|
+
(0, session_prefs_1.setSessionPrefs)(id, { runtime: rt });
|
|
86
119
|
return info;
|
|
87
120
|
}
|
|
88
121
|
ensureSession(id, cwd) {
|
|
89
122
|
let session = this.sessions.get(id);
|
|
90
123
|
if (!session) {
|
|
91
124
|
const prefs = (0, session_prefs_1.getSessionPrefs)(id);
|
|
125
|
+
const cliId = prefs?.cliSessionId || id;
|
|
126
|
+
const prevIds = prefs?.previousCliSessionIds || [];
|
|
127
|
+
const short = id.slice(0, 8);
|
|
128
|
+
(0, debug_logger_1.debugLog)(`[session:${short}] ensureSession: cliSessionId=${cliId.slice(0, 8)}, prevIds=[${prevIds.map((p) => p.slice(0, 8)).join(",")}], hasPrefs=${!!prefs}`);
|
|
92
129
|
const defaults = (0, defaults_1.getDefaults)();
|
|
93
130
|
const now = Date.now();
|
|
131
|
+
const modelSlots = prefs?.modelSlots ?? (prefs?.model ? { main: prefs.model } : { main: defaults.modelSlots.main ?? "sonnet" });
|
|
132
|
+
const restoredRuntime = prefs?.runtime ?? defaultRuntime();
|
|
133
|
+
const restoredContextSize = prefs?.contextSize ?? prefs?.modelSlots?.mainContext ?? models_1.DEFAULT_CONTEXT_SIZE;
|
|
94
134
|
session = {
|
|
95
135
|
info: {
|
|
96
136
|
id,
|
|
@@ -99,23 +139,28 @@ class SessionManager {
|
|
|
99
139
|
createdAt: now,
|
|
100
140
|
lastActiveAt: now,
|
|
101
141
|
status: "idle",
|
|
102
|
-
model:
|
|
142
|
+
model: modelSlots.main,
|
|
143
|
+
contextSize: restoredContextSize,
|
|
144
|
+
runtime: restoredRuntime,
|
|
145
|
+
pendingRequestCount: 0,
|
|
103
146
|
},
|
|
104
147
|
process: null,
|
|
105
148
|
stdin: null,
|
|
106
149
|
emitter: new node_events_1.EventEmitter(),
|
|
107
150
|
hasSpawnedBefore: true,
|
|
108
|
-
cliSessionId:
|
|
109
|
-
previousCliSessionIds:
|
|
151
|
+
cliSessionId: cliId,
|
|
152
|
+
previousCliSessionIds: prevIds,
|
|
110
153
|
bypassAllPermissions: prefs?.bypassAllPermissions ?? defaults.bypassAllPermissions,
|
|
111
154
|
planMode: prefs?.planMode ?? false,
|
|
112
155
|
pendingPlanReminder: prefs?.planMode ?? false,
|
|
113
156
|
needsRespawnForPermissions: false,
|
|
114
157
|
compacting: false,
|
|
115
|
-
thinkingLevel: prefs?.thinkingLevel ??
|
|
158
|
+
thinkingLevel: prefs?.thinkingLevel ??
|
|
159
|
+
(0, models_1.recommendedEffort)((0, models_1.resolveModel)((prefs?.model || defaults.modelSlots.main) ?? "sonnet")) ??
|
|
160
|
+
defaults.thinkingLevel,
|
|
116
161
|
streamState: null,
|
|
117
162
|
contextUsage: null,
|
|
118
|
-
contextWindowSize:
|
|
163
|
+
contextWindowSize: (0, models_1.contextSizeToWindow)(restoredContextSize),
|
|
119
164
|
todoItems: [],
|
|
120
165
|
pendingRequests: new Map(),
|
|
121
166
|
controlCallbacks: new Map(),
|
|
@@ -123,11 +168,18 @@ class SessionManager {
|
|
|
123
168
|
streamingSnapshot: null,
|
|
124
169
|
queuedMessages: [],
|
|
125
170
|
queuePaused: false,
|
|
171
|
+
modelSlots,
|
|
126
172
|
transcriptBuffer: [],
|
|
127
173
|
transcriptByteOffset: 0,
|
|
128
174
|
transcriptTotalSize: 0,
|
|
129
|
-
bufferCliSessionId:
|
|
175
|
+
bufferCliSessionId: cliId,
|
|
130
176
|
paginationPrevIds: [],
|
|
177
|
+
runtime: restoredRuntime,
|
|
178
|
+
ptyRuntime: null,
|
|
179
|
+
transcriptWatcher: null,
|
|
180
|
+
todoWatcher: null,
|
|
181
|
+
attachmentPaths: [],
|
|
182
|
+
totalTokens: { input: 0, output: 0, cacheCreate: 0, cacheRead: 0 },
|
|
131
183
|
};
|
|
132
184
|
this.sessions.set(id, session);
|
|
133
185
|
}
|
|
@@ -146,30 +198,31 @@ class SessionManager {
|
|
|
146
198
|
this.ensureSession(id, cwd);
|
|
147
199
|
session = this.sessions.get(id);
|
|
148
200
|
}
|
|
149
|
-
const
|
|
201
|
+
const stitching = (0, defaults_1.getDefaults)().messageStitching;
|
|
202
|
+
const willStitch = stitching && session.previousCliSessionIds.length > 0;
|
|
203
|
+
// Load full current session when stitching to avoid losing middle messages.
|
|
204
|
+
// Without stitching, tail-read is fine because byteOffset stays pointing at
|
|
205
|
+
// the current session's file for backward pagination.
|
|
206
|
+
const result = await (0, transcript_1.loadTranscript)(session.cliSessionId, session.info.cwd, willStitch ? undefined : { tailLines: 150 });
|
|
150
207
|
let { messages, byteOffset, totalSize, lastUsage } = result;
|
|
151
208
|
session.bufferCliSessionId = session.cliSessionId;
|
|
152
|
-
|
|
153
|
-
// conversation is visible on refresh instead of only post-clear messages.
|
|
154
|
-
if (session.previousCliSessionIds.length > 0) {
|
|
155
|
-
const currentMessages = messages;
|
|
209
|
+
if (willStitch) {
|
|
156
210
|
for (let i = session.previousCliSessionIds.length - 1; i >= 0; i--) {
|
|
157
211
|
const prevId = session.previousCliSessionIds[i];
|
|
158
212
|
const prevResult = await (0, transcript_1.loadTranscript)(prevId, session.info.cwd, { tailLines: 150 });
|
|
159
213
|
if (prevResult.messages.length > 0) {
|
|
160
214
|
const marker = {
|
|
161
|
-
id:
|
|
215
|
+
id: `clear-boundary-${i}`,
|
|
162
216
|
role: "system",
|
|
163
217
|
content: "__context_reset__",
|
|
164
218
|
toolUses: [],
|
|
165
219
|
blocks: [],
|
|
166
220
|
timestamp: Date.now(),
|
|
167
221
|
};
|
|
168
|
-
messages = [...prevResult.messages, marker, ...
|
|
222
|
+
messages = [...prevResult.messages, marker, ...messages];
|
|
169
223
|
byteOffset = prevResult.byteOffset;
|
|
170
224
|
lastUsage = lastUsage || prevResult.lastUsage;
|
|
171
225
|
session.bufferCliSessionId = prevId;
|
|
172
|
-
break;
|
|
173
226
|
}
|
|
174
227
|
}
|
|
175
228
|
}
|
|
@@ -178,11 +231,11 @@ class SessionManager {
|
|
|
178
231
|
session.transcriptByteOffset = byteOffset;
|
|
179
232
|
session.transcriptTotalSize = totalSize;
|
|
180
233
|
// Fresh pagination copy so getMoreHistory doesn't consume the canonical list
|
|
181
|
-
session.paginationPrevIds = [...session.previousCliSessionIds];
|
|
234
|
+
session.paginationPrevIds = stitching ? [...session.previousCliSessionIds] : [];
|
|
182
235
|
// Send last 50 to client, keep rest in buffer
|
|
183
236
|
const PAGE = 50;
|
|
184
237
|
const clientMessages = messages.length > PAGE ? messages.slice(-PAGE) : messages;
|
|
185
|
-
const hasMore = messages.length > PAGE || byteOffset > 0 || session.previousCliSessionIds.length > 0;
|
|
238
|
+
const hasMore = messages.length > PAGE || byteOffset > 0 || (stitching && session.previousCliSessionIds.length > 0);
|
|
186
239
|
const defaultName = node_path_1.default.basename(session.info.cwd) || session.info.cwd;
|
|
187
240
|
if (session.info.name === defaultName && messages.length > 0) {
|
|
188
241
|
const firstUser = messages.find((m) => m.role === "user" && m.content && !m.content.startsWith("[") && !m.content.startsWith("<"));
|
|
@@ -190,35 +243,46 @@ class SessionManager {
|
|
|
190
243
|
session.info.name = firstUser.content.slice(0, 120);
|
|
191
244
|
}
|
|
192
245
|
}
|
|
193
|
-
|
|
246
|
+
const allCliIds = [...session.previousCliSessionIds, session.cliSessionId];
|
|
247
|
+
const historyArrays = await Promise.all(allCliIds.map((id) => (0, transcript_1.loadPromptHistory)(id, session.info.cwd)));
|
|
248
|
+
const seen = new Set();
|
|
249
|
+
const allPrompts = [];
|
|
250
|
+
for (const arr of historyArrays) {
|
|
251
|
+
for (const p of arr) {
|
|
252
|
+
if (seen.has(p))
|
|
253
|
+
continue;
|
|
254
|
+
seen.add(p);
|
|
255
|
+
allPrompts.push(p);
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
const normalized = lastUsage ? { used: lastUsage.used, total: session.contextWindowSize } : null;
|
|
259
|
+
return { info: session.info, messages: clientMessages, hasMore, lastUsage: normalized, promptHistory: allPrompts };
|
|
194
260
|
}
|
|
195
261
|
async getSessionByCwd(id, cwd) {
|
|
196
262
|
this.ensureSession(id, cwd);
|
|
197
263
|
const session = this.sessions.get(id);
|
|
198
|
-
const
|
|
264
|
+
const stitching = (0, defaults_1.getDefaults)().messageStitching;
|
|
265
|
+
const willStitch = stitching && session.previousCliSessionIds.length > 0;
|
|
266
|
+
const result = await (0, transcript_1.loadTranscript)(session.cliSessionId, cwd, willStitch ? undefined : { tailLines: 150 });
|
|
199
267
|
let { messages, byteOffset, totalSize, lastUsage } = result;
|
|
200
268
|
session.bufferCliSessionId = session.cliSessionId;
|
|
201
|
-
|
|
202
|
-
// conversation is visible on refresh instead of only post-clear messages.
|
|
203
|
-
if (session.previousCliSessionIds.length > 0) {
|
|
204
|
-
const currentMessages = messages;
|
|
269
|
+
if (willStitch) {
|
|
205
270
|
for (let i = session.previousCliSessionIds.length - 1; i >= 0; i--) {
|
|
206
271
|
const prevId = session.previousCliSessionIds[i];
|
|
207
272
|
const prevResult = await (0, transcript_1.loadTranscript)(prevId, cwd, { tailLines: 150 });
|
|
208
273
|
if (prevResult.messages.length > 0) {
|
|
209
274
|
const marker = {
|
|
210
|
-
id:
|
|
275
|
+
id: `clear-boundary-${i}`,
|
|
211
276
|
role: "system",
|
|
212
277
|
content: "__context_reset__",
|
|
213
278
|
toolUses: [],
|
|
214
279
|
blocks: [],
|
|
215
280
|
timestamp: Date.now(),
|
|
216
281
|
};
|
|
217
|
-
messages = [...prevResult.messages, marker, ...
|
|
282
|
+
messages = [...prevResult.messages, marker, ...messages];
|
|
218
283
|
byteOffset = prevResult.byteOffset;
|
|
219
284
|
lastUsage = lastUsage || prevResult.lastUsage;
|
|
220
285
|
session.bufferCliSessionId = prevId;
|
|
221
|
-
break;
|
|
222
286
|
}
|
|
223
287
|
}
|
|
224
288
|
}
|
|
@@ -227,11 +291,11 @@ class SessionManager {
|
|
|
227
291
|
session.transcriptByteOffset = byteOffset;
|
|
228
292
|
session.transcriptTotalSize = totalSize;
|
|
229
293
|
// Fresh pagination copy so getMoreHistory doesn't consume the canonical list
|
|
230
|
-
session.paginationPrevIds = [...session.previousCliSessionIds];
|
|
294
|
+
session.paginationPrevIds = stitching ? [...session.previousCliSessionIds] : [];
|
|
231
295
|
// Send last 50 to client, keep rest in buffer
|
|
232
296
|
const PAGE = 50;
|
|
233
297
|
const clientMessages = messages.length > PAGE ? messages.slice(-PAGE) : messages;
|
|
234
|
-
const hasMore = messages.length > PAGE || byteOffset > 0 || session.previousCliSessionIds.length > 0;
|
|
298
|
+
const hasMore = messages.length > PAGE || byteOffset > 0 || (stitching && session.previousCliSessionIds.length > 0);
|
|
235
299
|
// Derive title from first user message if name is still the default
|
|
236
300
|
const defaultName = node_path_1.default.basename(cwd) || cwd;
|
|
237
301
|
if (session.info.name === defaultName && messages.length > 0) {
|
|
@@ -240,31 +304,43 @@ class SessionManager {
|
|
|
240
304
|
session.info.name = firstUser.content.slice(0, 120);
|
|
241
305
|
}
|
|
242
306
|
}
|
|
243
|
-
|
|
307
|
+
const allCliIds = [...session.previousCliSessionIds, session.cliSessionId];
|
|
308
|
+
const historyArrays = await Promise.all(allCliIds.map((id) => (0, transcript_1.loadPromptHistory)(id, cwd)));
|
|
309
|
+
const seen = new Set();
|
|
310
|
+
const allPrompts = [];
|
|
311
|
+
for (const arr of historyArrays) {
|
|
312
|
+
for (const p of arr) {
|
|
313
|
+
if (seen.has(p))
|
|
314
|
+
continue;
|
|
315
|
+
seen.add(p);
|
|
316
|
+
allPrompts.push(p);
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
const normalized = lastUsage ? { used: lastUsage.used, total: session.contextWindowSize } : null;
|
|
320
|
+
return { info: session.info, messages: clientMessages, hasMore, lastUsage: normalized, promptHistory: allPrompts };
|
|
244
321
|
}
|
|
245
322
|
async getCliSessionView(cliId, cwd) {
|
|
246
323
|
if (!(0, transcript_1.transcriptExists)(cliId, cwd))
|
|
247
324
|
return null;
|
|
248
325
|
const chain = (0, session_prefs_1.findChainForCliSession)(cliId);
|
|
249
326
|
const prevIds = chain ? chain.truncatedPrevIds : [];
|
|
250
|
-
const
|
|
327
|
+
const willStitch = (0, defaults_1.getDefaults)().messageStitching && prevIds.length > 0;
|
|
328
|
+
const result = await (0, transcript_1.loadTranscript)(cliId, cwd, willStitch ? undefined : { tailLines: 150 });
|
|
251
329
|
let { messages, lastUsage } = result;
|
|
252
|
-
if (
|
|
253
|
-
const currentMessages = messages;
|
|
330
|
+
if (willStitch) {
|
|
254
331
|
for (let i = prevIds.length - 1; i >= 0; i--) {
|
|
255
332
|
const prevResult = await (0, transcript_1.loadTranscript)(prevIds[i], cwd, { tailLines: 150 });
|
|
256
333
|
if (prevResult.messages.length > 0) {
|
|
257
334
|
const marker = {
|
|
258
|
-
id:
|
|
335
|
+
id: `clear-boundary-${i}`,
|
|
259
336
|
role: "system",
|
|
260
337
|
content: "__context_reset__",
|
|
261
338
|
toolUses: [],
|
|
262
339
|
blocks: [],
|
|
263
340
|
timestamp: Date.now(),
|
|
264
341
|
};
|
|
265
|
-
messages = [...prevResult.messages, marker, ...
|
|
342
|
+
messages = [...prevResult.messages, marker, ...messages];
|
|
266
343
|
lastUsage = lastUsage || prevResult.lastUsage;
|
|
267
|
-
break;
|
|
268
344
|
}
|
|
269
345
|
}
|
|
270
346
|
}
|
|
@@ -277,11 +353,27 @@ class SessionManager {
|
|
|
277
353
|
name = firstUser.content.slice(0, 120);
|
|
278
354
|
}
|
|
279
355
|
}
|
|
356
|
+
const allCliIds = [...prevIds, cliId];
|
|
357
|
+
const historyArrays = await Promise.all(allCliIds.map((id) => (0, transcript_1.loadPromptHistory)(id, cwd)));
|
|
358
|
+
const seen = new Set();
|
|
359
|
+
const allPrompts = [];
|
|
360
|
+
for (const arr of historyArrays) {
|
|
361
|
+
for (const p of arr) {
|
|
362
|
+
if (seen.has(p))
|
|
363
|
+
continue;
|
|
364
|
+
seen.add(p);
|
|
365
|
+
allPrompts.push(p);
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
const prefs = (0, session_prefs_1.getSessionPrefs)(cliId);
|
|
369
|
+
const viewSize = prefs?.contextSize ?? prefs?.modelSlots?.mainContext ?? models_1.DEFAULT_CONTEXT_SIZE;
|
|
370
|
+
const normalized = lastUsage ? { used: lastUsage.used, total: (0, models_1.contextSizeToWindow)(viewSize) } : null;
|
|
280
371
|
return {
|
|
281
372
|
info: { id: cliId, name, cwd, createdAt: Date.now(), lastActiveAt: Date.now(), status: "idle" },
|
|
282
373
|
messages: clientMessages,
|
|
283
374
|
hasMore: messages.length > PAGE,
|
|
284
|
-
lastUsage,
|
|
375
|
+
lastUsage: normalized,
|
|
376
|
+
promptHistory: allPrompts,
|
|
285
377
|
};
|
|
286
378
|
}
|
|
287
379
|
async getMoreHistory(sessionId, beforeMessageId) {
|
|
@@ -356,9 +448,21 @@ class SessionManager {
|
|
|
356
448
|
isCompacting(id) {
|
|
357
449
|
return this.sessions.get(id)?.compacting ?? false;
|
|
358
450
|
}
|
|
451
|
+
getRuntime(id) {
|
|
452
|
+
return this.sessions.get(id)?.runtime ?? "stream";
|
|
453
|
+
}
|
|
454
|
+
getSessionCwd(id) {
|
|
455
|
+
return this.sessions.get(id)?.info.cwd ?? null;
|
|
456
|
+
}
|
|
457
|
+
getCliSessionId(id) {
|
|
458
|
+
return this.sessions.get(id)?.cliSessionId ?? null;
|
|
459
|
+
}
|
|
460
|
+
getSessionModel(id) {
|
|
461
|
+
return this.sessions.get(id)?.info.model ?? null;
|
|
462
|
+
}
|
|
359
463
|
listActiveSessions() {
|
|
360
464
|
return Array.from(this.sessions.values())
|
|
361
|
-
.filter((s) => s.process !== null)
|
|
465
|
+
.filter((s) => s.process !== null || !!s.ptyRuntime?.isAlive)
|
|
362
466
|
.map((s) => s.info);
|
|
363
467
|
}
|
|
364
468
|
listKnownSessions() {
|
|
@@ -380,13 +484,18 @@ class SessionManager {
|
|
|
380
484
|
}
|
|
381
485
|
isProcessAlive(id) {
|
|
382
486
|
const session = this.sessions.get(id);
|
|
383
|
-
return !!session?.process;
|
|
487
|
+
return !!session?.process || !!session?.ptyRuntime?.isAlive;
|
|
488
|
+
}
|
|
489
|
+
hasRunningProcess(id) {
|
|
490
|
+
const session = this.sessions.get(id);
|
|
491
|
+
return !!session?.process || !!session?.ptyRuntime?.isAlive;
|
|
384
492
|
}
|
|
385
493
|
fixStaleStatus(id) {
|
|
386
494
|
const session = this.sessions.get(id);
|
|
387
|
-
if (session && session.info.status === "running" && !session.process) {
|
|
495
|
+
if (session && session.info.status === "running" && !session.process && !session.ptyRuntime?.isAlive) {
|
|
388
496
|
session.info.status = "idle";
|
|
389
497
|
session.pendingRequests.clear();
|
|
498
|
+
this.notifyPendingChanged(session, id);
|
|
390
499
|
}
|
|
391
500
|
}
|
|
392
501
|
restartSession(sessionId) {
|
|
@@ -398,7 +507,11 @@ class SessionManager {
|
|
|
398
507
|
return false;
|
|
399
508
|
}
|
|
400
509
|
this.killProcess(session);
|
|
510
|
+
if (!(0, transcript_1.transcriptExists)(session.cliSessionId, session.info.cwd)) {
|
|
511
|
+
session.hasSpawnedBefore = false;
|
|
512
|
+
}
|
|
401
513
|
session.pendingRequests.clear();
|
|
514
|
+
this.notifyPendingChanged(session, sessionId);
|
|
402
515
|
session.streamingSnapshot = null;
|
|
403
516
|
session.info.status = "idle";
|
|
404
517
|
session.emitter.emit("status", sessionId, "idle");
|
|
@@ -413,6 +526,20 @@ class SessionManager {
|
|
|
413
526
|
if (session.process) {
|
|
414
527
|
this.endProcess(session, "session_destroyed");
|
|
415
528
|
}
|
|
529
|
+
if (session.ptyRuntime) {
|
|
530
|
+
const runtime = session.ptyRuntime;
|
|
531
|
+
session.ptyRuntime = null;
|
|
532
|
+
runtime.kill().catch(() => { });
|
|
533
|
+
}
|
|
534
|
+
if (session.transcriptWatcher) {
|
|
535
|
+
session.transcriptWatcher.stop();
|
|
536
|
+
session.transcriptWatcher = null;
|
|
537
|
+
}
|
|
538
|
+
if (session.todoWatcher) {
|
|
539
|
+
session.todoWatcher.stop();
|
|
540
|
+
session.todoWatcher = null;
|
|
541
|
+
}
|
|
542
|
+
this.cleanupAttachments(session);
|
|
416
543
|
session.emitter.removeAllListeners();
|
|
417
544
|
this.sessions.delete(id);
|
|
418
545
|
return true;
|
|
@@ -429,14 +556,26 @@ class SessionManager {
|
|
|
429
556
|
}
|
|
430
557
|
onStatus(id, listener) {
|
|
431
558
|
const session = this.sessions.get(id);
|
|
432
|
-
if (!session)
|
|
559
|
+
if (!session) {
|
|
560
|
+
smLog(id, "onStatus: session not in memory, returning null");
|
|
433
561
|
return null;
|
|
562
|
+
}
|
|
434
563
|
const handler = (_sessionId, status) => {
|
|
435
564
|
listener(status);
|
|
436
565
|
};
|
|
437
566
|
session.emitter.on("status", handler);
|
|
438
567
|
return () => session.emitter.off("status", handler);
|
|
439
568
|
}
|
|
569
|
+
onPending(id, listener) {
|
|
570
|
+
const session = this.sessions.get(id);
|
|
571
|
+
if (!session)
|
|
572
|
+
return null;
|
|
573
|
+
const handler = (_sessionId, count) => {
|
|
574
|
+
listener(count);
|
|
575
|
+
};
|
|
576
|
+
session.emitter.on("pending", handler);
|
|
577
|
+
return () => session.emitter.off("pending", handler);
|
|
578
|
+
}
|
|
440
579
|
onError(id, listener) {
|
|
441
580
|
const session = this.sessions.get(id);
|
|
442
581
|
if (!session)
|
|
@@ -447,19 +586,55 @@ class SessionManager {
|
|
|
447
586
|
session.emitter.on("error", handler);
|
|
448
587
|
return () => session.emitter.off("error", handler);
|
|
449
588
|
}
|
|
589
|
+
onTranscript(id, listener) {
|
|
590
|
+
const session = this.sessions.get(id);
|
|
591
|
+
if (!session)
|
|
592
|
+
return null;
|
|
593
|
+
const handler = (_sessionId, messages) => listener(messages);
|
|
594
|
+
session.emitter.on("transcript", handler);
|
|
595
|
+
return () => session.emitter.off("transcript", handler);
|
|
596
|
+
}
|
|
450
597
|
interrupt(id) {
|
|
451
598
|
const session = this.sessions.get(id);
|
|
452
|
-
if (!session
|
|
453
|
-
(0, debug_logger_1.logDiag)(id, "interrupt:no-process", { hasSession:
|
|
599
|
+
if (!session) {
|
|
600
|
+
(0, debug_logger_1.logDiag)(id, "interrupt:no-process", { hasSession: false });
|
|
454
601
|
return false;
|
|
455
602
|
}
|
|
456
603
|
// Pause the queue atomically with the interrupt so
|
|
457
604
|
// flushQueuedMessage (called on message_done) becomes a no-op.
|
|
458
|
-
// This prevents a race where message_done fires before a
|
|
459
|
-
// separate pause_queue WS message can arrive.
|
|
460
605
|
if (session.queuedMessages.length > 0) {
|
|
461
606
|
session.queuePaused = true;
|
|
462
607
|
}
|
|
608
|
+
if (session.runtime === "pty") {
|
|
609
|
+
if (!session.ptyRuntime?.isAlive) {
|
|
610
|
+
(0, debug_logger_1.logDiag)(id, "interrupt:no-pty");
|
|
611
|
+
return false;
|
|
612
|
+
}
|
|
613
|
+
(0, debug_logger_1.logDiag)(id, "interrupt:pty-esc");
|
|
614
|
+
session.ptyRuntime.interrupt();
|
|
615
|
+
// Esc cancels the claude TUI turn but may not produce a Stop hook if it
|
|
616
|
+
// arrived before any response. Force-idle so the UI unsticks; the PTY
|
|
617
|
+
// process stays alive at its REPL prompt and accepts the next message.
|
|
618
|
+
if (session.info.status === "running") {
|
|
619
|
+
session.info.status = "idle";
|
|
620
|
+
session.streamingSnapshot = null;
|
|
621
|
+
if (session.streamState) {
|
|
622
|
+
session.streamState.pendingBlocks.length = 0;
|
|
623
|
+
session.streamState.pendingToolUses.length = 0;
|
|
624
|
+
session.streamState.agentStack.length = 0;
|
|
625
|
+
session.streamState.currentAssistantMsgId = null;
|
|
626
|
+
session.streamState.flushedOnMessageDone = false;
|
|
627
|
+
}
|
|
628
|
+
session.emitter.emit("status", id, "idle");
|
|
629
|
+
}
|
|
630
|
+
session.pendingRequests.clear();
|
|
631
|
+
this.notifyPendingChanged(session, id);
|
|
632
|
+
return true;
|
|
633
|
+
}
|
|
634
|
+
if (!session.process) {
|
|
635
|
+
(0, debug_logger_1.logDiag)(id, "interrupt:no-process", { hasSession: true });
|
|
636
|
+
return false;
|
|
637
|
+
}
|
|
463
638
|
// Send a control_request interrupt via stdin instead of SIGINT.
|
|
464
639
|
// SIGINT kills the process, forcing a full respawn + transcript reload
|
|
465
640
|
// on the next message. The control_request interrupt aborts the current
|
|
@@ -473,23 +648,34 @@ class SessionManager {
|
|
|
473
648
|
};
|
|
474
649
|
(0, debug_logger_1.logDiag)(id, "interrupt:stdin", { requestId: request.request_id });
|
|
475
650
|
session.stdin.write(JSON.stringify(request) + "\n");
|
|
651
|
+
session.pendingRequests.clear();
|
|
652
|
+
this.notifyPendingChanged(session, id);
|
|
476
653
|
return true;
|
|
477
654
|
}
|
|
478
655
|
// Fallback: if stdin is gone, kill the process group
|
|
479
656
|
(0, debug_logger_1.logDiag)(id, "interrupt:kill-fallback");
|
|
480
657
|
this.killProcessGroup(session.process);
|
|
658
|
+
session.pendingRequests.clear();
|
|
659
|
+
this.notifyPendingChanged(session, id);
|
|
481
660
|
return true;
|
|
482
661
|
}
|
|
483
662
|
addPendingRequest(sessionId, request) {
|
|
484
663
|
const session = this.sessions.get(sessionId);
|
|
485
664
|
if (session) {
|
|
486
665
|
session.pendingRequests.set(request.requestId, request);
|
|
666
|
+
this.notifyPendingChanged(session, sessionId);
|
|
487
667
|
}
|
|
488
668
|
}
|
|
489
669
|
removePendingRequest(sessionId, requestId) {
|
|
490
670
|
const session = this.sessions.get(sessionId);
|
|
491
671
|
if (session) {
|
|
672
|
+
const had = session.pendingRequests.has(requestId);
|
|
673
|
+
const wasQuestion = session.pendingRequests.get(requestId)?.type === "question";
|
|
492
674
|
session.pendingRequests.delete(requestId);
|
|
675
|
+
if (wasQuestion) {
|
|
676
|
+
console.log(`[question-debug] removePendingRequest: session=${sessionId.slice(0, 8)}, requestId=${requestId}, existed=${had}, remaining=${session.pendingRequests.size}`);
|
|
677
|
+
}
|
|
678
|
+
this.notifyPendingChanged(session, sessionId);
|
|
493
679
|
}
|
|
494
680
|
}
|
|
495
681
|
getPendingRequests(sessionId) {
|
|
@@ -498,11 +684,26 @@ class SessionManager {
|
|
|
498
684
|
return [];
|
|
499
685
|
return Array.from(session.pendingRequests.values());
|
|
500
686
|
}
|
|
687
|
+
getPendingRequest(sessionId, requestId) {
|
|
688
|
+
return this.sessions.get(sessionId)?.pendingRequests.get(requestId);
|
|
689
|
+
}
|
|
501
690
|
respondToPermission(sessionId, requestId, allowed, toolInput, permissionSuggestions, denyReason) {
|
|
502
691
|
const session = this.sessions.get(sessionId);
|
|
503
|
-
if (!session
|
|
692
|
+
if (!session)
|
|
693
|
+
return false;
|
|
694
|
+
if (session.runtime === "pty") {
|
|
695
|
+
if (!session.ptyRuntime?.isAlive)
|
|
696
|
+
return false;
|
|
697
|
+
session.pendingRequests.delete(requestId);
|
|
698
|
+
this.notifyPendingChanged(session, sessionId);
|
|
699
|
+
return session.ptyRuntime.notifyPermissionDecision(requestId, allowed
|
|
700
|
+
? { behavior: "allow", ...(toolInput ? { updatedInput: toolInput } : {}) }
|
|
701
|
+
: { behavior: "deny", message: denyReason ?? "User denied" });
|
|
702
|
+
}
|
|
703
|
+
if (!session.stdin)
|
|
504
704
|
return false;
|
|
505
705
|
session.pendingRequests.delete(requestId);
|
|
706
|
+
this.notifyPendingChanged(session, sessionId);
|
|
506
707
|
const response = {
|
|
507
708
|
type: "control_response",
|
|
508
709
|
response: {
|
|
@@ -511,7 +712,7 @@ class SessionManager {
|
|
|
511
712
|
response: allowed
|
|
512
713
|
? {
|
|
513
714
|
behavior: "allow",
|
|
514
|
-
|
|
715
|
+
updatedInput: toolInput ?? {},
|
|
515
716
|
...(permissionSuggestions?.length ? { updatedPermissions: permissionSuggestions } : {}),
|
|
516
717
|
}
|
|
517
718
|
: { behavior: "deny", message: denyReason ?? "User denied" },
|
|
@@ -540,6 +741,7 @@ class SessionManager {
|
|
|
540
741
|
// Don't change CLI mode while in plan mode; bypass will restore on plan exit
|
|
541
742
|
if (!session.planMode) {
|
|
542
743
|
this.sendPermissionMode(session, sessionId, "bypassPermissions");
|
|
744
|
+
this.scheduleRespawnForPermissions(session);
|
|
543
745
|
}
|
|
544
746
|
this.emitSystem(session, sessionId, "__bypass_state::on");
|
|
545
747
|
}
|
|
@@ -551,9 +753,36 @@ class SessionManager {
|
|
|
551
753
|
(0, session_prefs_1.setSessionPrefs)(sessionId, { bypassAllPermissions: false });
|
|
552
754
|
if (!session.planMode) {
|
|
553
755
|
this.sendPermissionMode(session, sessionId, "default");
|
|
756
|
+
this.scheduleRespawnForPermissions(session);
|
|
554
757
|
}
|
|
555
758
|
this.emitSystem(session, sessionId, "__bypass_state::off");
|
|
556
759
|
}
|
|
760
|
+
// Runtime set_permission_mode is unreliable when the CLI was spawned without
|
|
761
|
+
// the target mode. Respawning the process picks up --permission-mode from
|
|
762
|
+
// session state, guaranteeing the next message runs in the right mode.
|
|
763
|
+
// If a message is in flight, defer until message_done so we don't orphan it.
|
|
764
|
+
scheduleRespawnForPermissions(session) {
|
|
765
|
+
if (!session.process && !session.ptyRuntime?.isAlive)
|
|
766
|
+
return;
|
|
767
|
+
if (session.info.status === "idle") {
|
|
768
|
+
this.killProcess(session);
|
|
769
|
+
session.hasSpawnedBefore = (0, transcript_1.transcriptExists)(session.cliSessionId, session.info.cwd);
|
|
770
|
+
}
|
|
771
|
+
else {
|
|
772
|
+
session.needsRespawnForPermissions = true;
|
|
773
|
+
}
|
|
774
|
+
}
|
|
775
|
+
setRuntime(sessionId, runtime) {
|
|
776
|
+
const session = this.sessions.get(sessionId);
|
|
777
|
+
if (!session || session.runtime === runtime)
|
|
778
|
+
return false;
|
|
779
|
+
session.runtime = runtime;
|
|
780
|
+
session.info.runtime = runtime;
|
|
781
|
+
(0, session_prefs_1.setSessionPrefs)(sessionId, { runtime });
|
|
782
|
+
this.killProcess(session);
|
|
783
|
+
this.emitInfoUpdated(session, sessionId);
|
|
784
|
+
return true;
|
|
785
|
+
}
|
|
557
786
|
isBypassActive(sessionId) {
|
|
558
787
|
const session = this.sessions.get(sessionId);
|
|
559
788
|
return session?.bypassAllPermissions ?? false;
|
|
@@ -567,13 +796,14 @@ class SessionManager {
|
|
|
567
796
|
(0, session_prefs_1.setSessionPrefs)(sessionId, { planMode: true });
|
|
568
797
|
// Kill process so it restarts without --allow-dangerously-skip-permissions,
|
|
569
798
|
// which lets the CLI natively enforce plan mode tool restrictions.
|
|
570
|
-
if (session.process) {
|
|
799
|
+
if (session.process || session.ptyRuntime?.isAlive) {
|
|
571
800
|
this.killProcess(session);
|
|
572
801
|
session.info.status = "idle";
|
|
573
802
|
session.emitter.emit("status", sessionId, "idle");
|
|
574
803
|
}
|
|
575
804
|
// Clear orphaned pending requests from the killed process
|
|
576
805
|
session.pendingRequests.clear();
|
|
806
|
+
this.notifyPendingChanged(session, sessionId);
|
|
577
807
|
this.emitSystem(session, sessionId, "__plan_state::on");
|
|
578
808
|
}
|
|
579
809
|
clearPlanMode(sessionId) {
|
|
@@ -584,13 +814,14 @@ class SessionManager {
|
|
|
584
814
|
(0, session_prefs_1.setSessionPrefs)(sessionId, { planMode: false });
|
|
585
815
|
// Kill process so it restarts with --allow-dangerously-skip-permissions,
|
|
586
816
|
// restoring bypass capability for build mode.
|
|
587
|
-
if (session.process) {
|
|
817
|
+
if (session.process || session.ptyRuntime?.isAlive) {
|
|
588
818
|
this.killProcess(session);
|
|
589
819
|
session.info.status = "idle";
|
|
590
820
|
session.emitter.emit("status", sessionId, "idle");
|
|
591
821
|
}
|
|
592
822
|
// Clear orphaned pending requests from the killed process
|
|
593
823
|
session.pendingRequests.clear();
|
|
824
|
+
this.notifyPendingChanged(session, sessionId);
|
|
594
825
|
this.emitSystem(session, sessionId, "__plan_state::off");
|
|
595
826
|
// Re-sync bypass state with the client so the UI reflects it correctly
|
|
596
827
|
// after the plan-mode process is torn down.
|
|
@@ -602,19 +833,41 @@ class SessionManager {
|
|
|
602
833
|
const session = this.sessions.get(sessionId);
|
|
603
834
|
return session?.planMode ?? false;
|
|
604
835
|
}
|
|
605
|
-
setModel(sessionId, model) {
|
|
836
|
+
setModel(sessionId, model, contextSize) {
|
|
606
837
|
const session = this.sessions.get(sessionId);
|
|
607
|
-
|
|
838
|
+
this.log(sessionId, `setModel: requested=${model} size=${contextSize ?? "(unspecified)"}, current=${session?.info.model} currentSize=${session?.info.contextSize ?? "(unset)"}, hasStdin=${!!session?.stdin}, hasPty=${!!session?.ptyRuntime}`);
|
|
839
|
+
if (!session)
|
|
840
|
+
return;
|
|
841
|
+
const currentSize = session.info.contextSize ?? models_1.DEFAULT_CONTEXT_SIZE;
|
|
842
|
+
const requestedSize = contextSize ?? currentSize;
|
|
843
|
+
const resolvedSize = (() => {
|
|
844
|
+
const sizes = (0, models_1.resolveModel)(model)?.contextSizes;
|
|
845
|
+
if (!sizes || sizes.length === 0)
|
|
846
|
+
return requestedSize;
|
|
847
|
+
return sizes.includes(requestedSize) ? requestedSize : sizes[0];
|
|
848
|
+
})();
|
|
849
|
+
// CLAUDE_CODE_DISABLE_1M_CONTEXT is applied at spawn, so a context-size
|
|
850
|
+
// change mid-session requires a CLI restart to take effect.
|
|
851
|
+
const contextChanged = currentSize !== resolvedSize;
|
|
852
|
+
if (session.info.model === model && !contextChanged) {
|
|
853
|
+
this.log(sessionId, `setModel: skipping (already ${model} with size ${resolvedSize})`);
|
|
608
854
|
return;
|
|
609
|
-
|
|
610
|
-
// applied at spawn, so toggling the [1m] suffix mid-session needs a CLI
|
|
611
|
-
// restart for the new context window to actually take effect.
|
|
612
|
-
const has1m = (m) => !!m && /\[1m\]/i.test(m);
|
|
613
|
-
const contextChanged = has1m(session.info.model) !== has1m(model);
|
|
855
|
+
}
|
|
614
856
|
session.info.model = model;
|
|
615
|
-
|
|
857
|
+
session.info.contextSize = resolvedSize;
|
|
858
|
+
session.modelSlots = { ...session.modelSlots, main: model, mainContext: resolvedSize };
|
|
859
|
+
(0, session_prefs_1.setSessionPrefs)(sessionId, { model, contextSize: resolvedSize, modelSlots: session.modelSlots });
|
|
616
860
|
const nextEntry = (0, models_1.resolveModel)(model);
|
|
617
|
-
const coerced =
|
|
861
|
+
const coerced = nextEntry
|
|
862
|
+
? (0, models_1.coerceEffort)(session.thinkingLevel, nextEntry)
|
|
863
|
+
: (() => {
|
|
864
|
+
const levels = this.modelEffortLevels(model);
|
|
865
|
+
if (levels.length === 0)
|
|
866
|
+
return null;
|
|
867
|
+
if (levels.includes(session.thinkingLevel))
|
|
868
|
+
return session.thinkingLevel;
|
|
869
|
+
return levels[levels.length - 1];
|
|
870
|
+
})();
|
|
618
871
|
const levelChanged = coerced !== null && coerced !== session.thinkingLevel;
|
|
619
872
|
if (levelChanged) {
|
|
620
873
|
session.thinkingLevel = coerced;
|
|
@@ -622,13 +875,14 @@ class SessionManager {
|
|
|
622
875
|
this.emitSystem(session, sessionId, `__thinking_level::${coerced}`);
|
|
623
876
|
}
|
|
624
877
|
if (session.stdin && !contextChanged) {
|
|
878
|
+
this.log(sessionId, `setModel: sending control_request set_model=${model}`);
|
|
625
879
|
const request = {
|
|
626
880
|
type: "control_request",
|
|
627
881
|
request_id: `model-${Date.now()}`,
|
|
628
882
|
request: { subtype: "set_model", model },
|
|
629
883
|
};
|
|
630
884
|
session.stdin.write(JSON.stringify(request) + "\n");
|
|
631
|
-
if (
|
|
885
|
+
if (this.modelEffortLevels(model).length > 0) {
|
|
632
886
|
const effortRequest = {
|
|
633
887
|
type: "control_request",
|
|
634
888
|
request_id: `effort-${Date.now()}`,
|
|
@@ -638,13 +892,44 @@ class SessionManager {
|
|
|
638
892
|
}
|
|
639
893
|
}
|
|
640
894
|
else {
|
|
895
|
+
this.log(sessionId, `setModel: killing process (hasStdin=${!!session.stdin}, contextChanged=${contextChanged})`);
|
|
641
896
|
this.killProcess(session);
|
|
897
|
+
if (!(0, transcript_1.transcriptExists)(session.cliSessionId, session.info.cwd)) {
|
|
898
|
+
session.hasSpawnedBefore = false;
|
|
899
|
+
}
|
|
642
900
|
session.queuedMessages.length = 0;
|
|
643
901
|
session.queuePaused = false;
|
|
644
902
|
session.info.status = "idle";
|
|
645
903
|
session.emitter.emit("status", sessionId, "idle");
|
|
646
904
|
}
|
|
647
905
|
this.emitInfoUpdated(session, sessionId);
|
|
906
|
+
if (contextChanged) {
|
|
907
|
+
session.contextWindowSize = (0, models_1.contextSizeToWindow)(resolvedSize);
|
|
908
|
+
}
|
|
909
|
+
const cur = session.contextUsage;
|
|
910
|
+
if (cur) {
|
|
911
|
+
session.emitter.emit("usage", sessionId, { used: cur.used, total: session.contextWindowSize });
|
|
912
|
+
}
|
|
913
|
+
}
|
|
914
|
+
setModelSlot(sessionId, slot, modelId) {
|
|
915
|
+
const session = this.sessions.get(sessionId);
|
|
916
|
+
if (!session)
|
|
917
|
+
return;
|
|
918
|
+
const slots = { ...session.modelSlots };
|
|
919
|
+
slots[slot] = modelId;
|
|
920
|
+
session.modelSlots = slots;
|
|
921
|
+
(0, session_prefs_1.setSessionPrefs)(sessionId, { modelSlots: slots });
|
|
922
|
+
if (slot === "main") {
|
|
923
|
+
this.setModel(sessionId, modelId);
|
|
924
|
+
}
|
|
925
|
+
else {
|
|
926
|
+
this.killProcess(session);
|
|
927
|
+
session.queuedMessages.length = 0;
|
|
928
|
+
session.queuePaused = false;
|
|
929
|
+
session.info.status = "idle";
|
|
930
|
+
session.emitter.emit("status", sessionId, "idle");
|
|
931
|
+
this.emitInfoUpdated(session, sessionId);
|
|
932
|
+
}
|
|
648
933
|
}
|
|
649
934
|
getModel(sessionId) {
|
|
650
935
|
return this.sessions.get(sessionId)?.info.model || "sonnet";
|
|
@@ -655,7 +940,7 @@ class SessionManager {
|
|
|
655
940
|
return;
|
|
656
941
|
session.thinkingLevel = level;
|
|
657
942
|
(0, session_prefs_1.setSessionPrefs)(sessionId, { thinkingLevel: level });
|
|
658
|
-
const supportsEffort =
|
|
943
|
+
const supportsEffort = this.modelEffortLevels(session.info.model).length > 0;
|
|
659
944
|
if (session.stdin && supportsEffort) {
|
|
660
945
|
const request = {
|
|
661
946
|
type: "control_request",
|
|
@@ -857,45 +1142,33 @@ class SessionManager {
|
|
|
857
1142
|
session.emitter.on("init", handler);
|
|
858
1143
|
return () => session.emitter.off("init", handler);
|
|
859
1144
|
}
|
|
860
|
-
|
|
861
|
-
try {
|
|
862
|
-
const input = JSON.parse(toolInput);
|
|
863
|
-
const todos = input.todos;
|
|
864
|
-
if (!Array.isArray(todos))
|
|
865
|
-
return;
|
|
866
|
-
session.todoItems = todos
|
|
867
|
-
.filter((t) => t.content && t.status)
|
|
868
|
-
.map((t) => ({
|
|
869
|
-
content: t.content,
|
|
870
|
-
status: t.status,
|
|
871
|
-
activeForm: t.activeForm || undefined,
|
|
872
|
-
}));
|
|
873
|
-
session.emitter.emit("todos", sessionId, [...session.todoItems]);
|
|
874
|
-
}
|
|
875
|
-
catch {
|
|
876
|
-
// invalid input, ignore
|
|
877
|
-
}
|
|
878
|
-
}
|
|
879
|
-
rebuildTodosFromHistory(sessionId, messages) {
|
|
1145
|
+
loadTodosFromFiles(sessionId) {
|
|
880
1146
|
const session = this.sessions.get(sessionId);
|
|
881
1147
|
if (!session)
|
|
882
1148
|
return;
|
|
883
|
-
// If there's already a live todo state (set during the current process),
|
|
884
|
-
// don't overwrite it from history.
|
|
885
1149
|
if (session.todoItems.length > 0)
|
|
886
1150
|
return;
|
|
887
|
-
const
|
|
1151
|
+
const watcher = new todo_watcher_1.TodoWatcher(session.cliSessionId, () => { });
|
|
1152
|
+
const todos = watcher.readOnce();
|
|
888
1153
|
if (todos.length === 0)
|
|
889
1154
|
return;
|
|
890
1155
|
session.todoItems = todos;
|
|
891
1156
|
session.emitter.emit("todos", sessionId, [...session.todoItems]);
|
|
892
1157
|
}
|
|
1158
|
+
startTodoWatcher(session, sessionId) {
|
|
1159
|
+
if (session.todoWatcher) {
|
|
1160
|
+
session.todoWatcher.stop();
|
|
1161
|
+
}
|
|
1162
|
+
const watcher = new todo_watcher_1.TodoWatcher(session.cliSessionId, (todos) => {
|
|
1163
|
+
session.todoItems = todos;
|
|
1164
|
+
session.emitter.emit("todos", sessionId, [...todos]);
|
|
1165
|
+
});
|
|
1166
|
+
session.todoWatcher = watcher;
|
|
1167
|
+
watcher.start();
|
|
1168
|
+
}
|
|
893
1169
|
extractUsage(session, sessionId, line) {
|
|
894
1170
|
try {
|
|
895
1171
|
const raw = JSON.parse(line.trim());
|
|
896
|
-
if (raw.type === "result" && raw.modelUsage) {
|
|
897
|
-
this.extractContextWindowSize(session, raw.modelUsage);
|
|
898
|
-
}
|
|
899
1172
|
if (raw.type !== "assistant" || !raw.message?.usage)
|
|
900
1173
|
return;
|
|
901
1174
|
// Skip synthetic responses (e.g. /context) that have all-zero usage
|
|
@@ -906,19 +1179,15 @@ class SessionManager {
|
|
|
906
1179
|
const usage = { used, total: session.contextWindowSize };
|
|
907
1180
|
session.contextUsage = usage;
|
|
908
1181
|
session.emitter.emit("usage", sessionId, usage);
|
|
1182
|
+
session.totalTokens.input += u.input_tokens || 0;
|
|
1183
|
+
session.totalTokens.output += u.output_tokens || 0;
|
|
1184
|
+
session.totalTokens.cacheCreate += u.cache_creation_input_tokens || 0;
|
|
1185
|
+
session.totalTokens.cacheRead += u.cache_read_input_tokens || 0;
|
|
909
1186
|
}
|
|
910
1187
|
catch {
|
|
911
1188
|
// not valid JSON, ignore
|
|
912
1189
|
}
|
|
913
1190
|
}
|
|
914
|
-
extractContextWindowSize(session, modelUsage) {
|
|
915
|
-
for (const model of Object.values(modelUsage)) {
|
|
916
|
-
if (model.contextWindow && model.contextWindow > 0) {
|
|
917
|
-
session.contextWindowSize = model.contextWindow;
|
|
918
|
-
return;
|
|
919
|
-
}
|
|
920
|
-
}
|
|
921
|
-
}
|
|
922
1191
|
killProcessGroup(proc) {
|
|
923
1192
|
if (!proc.pid)
|
|
924
1193
|
return;
|
|
@@ -963,12 +1232,28 @@ class SessionManager {
|
|
|
963
1232
|
session.process = null;
|
|
964
1233
|
session.stdin = null;
|
|
965
1234
|
}
|
|
1235
|
+
if (session.ptyRuntime) {
|
|
1236
|
+
const runtime = session.ptyRuntime;
|
|
1237
|
+
session.ptyRuntime = null;
|
|
1238
|
+
runtime.kill().catch(() => { });
|
|
1239
|
+
}
|
|
966
1240
|
session.compacting = false;
|
|
967
1241
|
}
|
|
968
1242
|
emitSystem(session, sessionId, text) {
|
|
969
1243
|
session.emitter.emit("system", sessionId, text);
|
|
970
1244
|
}
|
|
1245
|
+
notifyPendingChanged(session, sessionId) {
|
|
1246
|
+
const count = session.pendingRequests.size;
|
|
1247
|
+
if (session.info.pendingRequestCount === count)
|
|
1248
|
+
return;
|
|
1249
|
+
session.info.pendingRequestCount = count;
|
|
1250
|
+
session.emitter.emit("pending", sessionId, count);
|
|
1251
|
+
}
|
|
971
1252
|
applyProcessedResult(session, sessionId, result) {
|
|
1253
|
+
const eventTypes = result.emit.map((e) => e.type).join(", ");
|
|
1254
|
+
if (eventTypes) {
|
|
1255
|
+
console.log(`[sm] applyProcessedResult for ${sessionId.slice(0, 8)}: events=[${eventTypes}], statusChange=${result.statusChange ?? "none"}, currentStatus=${session.info.status}`);
|
|
1256
|
+
}
|
|
972
1257
|
for (const msg of result.intermediateMessages) {
|
|
973
1258
|
session.emitter.emit("event", sessionId, { type: "message_done", message: msg });
|
|
974
1259
|
if (msg.toolUses.some((t) => t.name === "Agent")) {
|
|
@@ -976,6 +1261,37 @@ class SessionManager {
|
|
|
976
1261
|
}
|
|
977
1262
|
}
|
|
978
1263
|
for (const sysMsg of result.systemMessages) {
|
|
1264
|
+
if (sysMsg === "__tool_use_start") {
|
|
1265
|
+
session.info.status = "running";
|
|
1266
|
+
console.log(`[sm] emit status running (via tool_use_start) for ${sessionId.slice(0, 8)} (runtime=${session.runtime})`);
|
|
1267
|
+
session.emitter.emit("status", sessionId, "running");
|
|
1268
|
+
continue;
|
|
1269
|
+
}
|
|
1270
|
+
if (sysMsg === "__compact::hook_start") {
|
|
1271
|
+
if (!session.compacting) {
|
|
1272
|
+
(0, debug_logger_1.logDiag)(sessionId, "compact:hook-start");
|
|
1273
|
+
session.compacting = true;
|
|
1274
|
+
this.emitSystem(session, sessionId, "__compact::start");
|
|
1275
|
+
}
|
|
1276
|
+
continue;
|
|
1277
|
+
}
|
|
1278
|
+
if (sysMsg === "__compact::hook_done") {
|
|
1279
|
+
if (session.compacting) {
|
|
1280
|
+
(0, debug_logger_1.logDiag)(sessionId, "compact:hook-done");
|
|
1281
|
+
session.compacting = false;
|
|
1282
|
+
this.emitSystem(session, sessionId, "__compact::done");
|
|
1283
|
+
const postCompactEstimate = {
|
|
1284
|
+
used: Math.round(session.contextWindowSize * 0.1),
|
|
1285
|
+
total: session.contextWindowSize,
|
|
1286
|
+
};
|
|
1287
|
+
session.contextUsage = postCompactEstimate;
|
|
1288
|
+
session.emitter.emit("usage", sessionId, postCompactEstimate);
|
|
1289
|
+
session.info.status = "idle";
|
|
1290
|
+
session.emitter.emit("status", sessionId, "idle");
|
|
1291
|
+
this.flushQueuedMessage(session, sessionId);
|
|
1292
|
+
}
|
|
1293
|
+
continue;
|
|
1294
|
+
}
|
|
979
1295
|
const permModePrefix = "__permission_mode::";
|
|
980
1296
|
if (sysMsg.startsWith(permModePrefix)) {
|
|
981
1297
|
const mode = sysMsg.slice(permModePrefix.length);
|
|
@@ -998,9 +1314,14 @@ class SessionManager {
|
|
|
998
1314
|
for (const errMsg of result.errors) {
|
|
999
1315
|
session.emitter.emit("error", sessionId, errMsg);
|
|
1000
1316
|
}
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1317
|
+
// After exiting plan mode the CLI process is killed and respawned with the
|
|
1318
|
+
// correct --permission-mode flag (see needsRespawnForPermissions). Between
|
|
1319
|
+
// the plan exit and the message_done that triggers the respawn, the old
|
|
1320
|
+
// process may still send permission_request events. The server auto-approves
|
|
1321
|
+
// these so the CLI isn't blocked, but we must also suppress the events from
|
|
1322
|
+
// reaching the UI -- otherwise the user sees phantom permission prompts that
|
|
1323
|
+
// don't actually gate anything.
|
|
1324
|
+
const bypassedRequestIds = new Set();
|
|
1004
1325
|
for (const pa of result.permissionActions) {
|
|
1005
1326
|
if (pa.type === "auto_approve") {
|
|
1006
1327
|
this.respondToPermission(sessionId, pa.requestId, true, pa.rawToolInput);
|
|
@@ -1008,22 +1329,38 @@ class SessionManager {
|
|
|
1008
1329
|
else if (pa.type === "auto_deny") {
|
|
1009
1330
|
this.respondToPermission(sessionId, pa.requestId, false, undefined, undefined, pa.denyReason);
|
|
1010
1331
|
}
|
|
1332
|
+
else if (session.bypassAllPermissions && !session.planMode && pa.toolName !== "AskUserQuestion") {
|
|
1333
|
+
this.respondToPermission(sessionId, pa.requestId, true, pa.rawToolInput);
|
|
1334
|
+
bypassedRequestIds.add(pa.requestId);
|
|
1335
|
+
}
|
|
1011
1336
|
else {
|
|
1012
1337
|
const planPath = pa.toolName === "ExitPlanMode" ? (0, plans_1.findLatestPlanFile)() : undefined;
|
|
1338
|
+
const reqType = pa.toolName === "AskUserQuestion" ? "question" : "permission";
|
|
1339
|
+
if (reqType === "question") {
|
|
1340
|
+
console.log(`[question-debug] adding pending question: session=${sessionId.slice(0, 8)}, requestId=${pa.requestId}, total=${session.pendingRequests.size + 1}`);
|
|
1341
|
+
}
|
|
1013
1342
|
session.pendingRequests.set(pa.requestId, {
|
|
1014
|
-
type:
|
|
1343
|
+
type: reqType,
|
|
1015
1344
|
requestId: pa.requestId,
|
|
1016
1345
|
toolName: pa.toolName,
|
|
1017
1346
|
toolInput: pa.toolInput || "",
|
|
1018
1347
|
rawToolInput: pa.rawToolInput,
|
|
1348
|
+
permissionSuggestions: pa.permissionSuggestions,
|
|
1019
1349
|
planFilePath: planPath,
|
|
1020
1350
|
planContent: planPath ? (0, plans_1.readPlanFile)(planPath) : undefined,
|
|
1021
1351
|
});
|
|
1352
|
+
this.notifyPendingChanged(session, sessionId);
|
|
1022
1353
|
}
|
|
1023
1354
|
}
|
|
1024
1355
|
if (result.compactDone) {
|
|
1025
1356
|
session.compacting = false;
|
|
1026
1357
|
this.emitSystem(session, sessionId, "__compact::done");
|
|
1358
|
+
const postCompactEstimate = {
|
|
1359
|
+
used: Math.round(session.contextWindowSize * 0.1),
|
|
1360
|
+
total: session.contextWindowSize,
|
|
1361
|
+
};
|
|
1362
|
+
session.contextUsage = postCompactEstimate;
|
|
1363
|
+
session.emitter.emit("usage", sessionId, postCompactEstimate);
|
|
1027
1364
|
}
|
|
1028
1365
|
if (result.emit.length > 0) {
|
|
1029
1366
|
const listeners = session.emitter.listenerCount("event");
|
|
@@ -1032,6 +1369,9 @@ class SessionManager {
|
|
|
1032
1369
|
}
|
|
1033
1370
|
}
|
|
1034
1371
|
for (const event of result.emit) {
|
|
1372
|
+
// Skip phantom permission events that were already bypass-approved above
|
|
1373
|
+
if (event.type === "permission_request" && event.requestId && bypassedRequestIds.has(event.requestId))
|
|
1374
|
+
continue;
|
|
1035
1375
|
session.emitter.emit("event", sessionId, event);
|
|
1036
1376
|
}
|
|
1037
1377
|
session.streamingSnapshot = result.snapshot;
|
|
@@ -1049,6 +1389,7 @@ class SessionManager {
|
|
|
1049
1389
|
}
|
|
1050
1390
|
if (result.statusChange === "idle") {
|
|
1051
1391
|
session.info.status = "idle";
|
|
1392
|
+
console.log(`[sm] emit status idle for ${sessionId.slice(0, 8)} (runtime=${session.runtime})`);
|
|
1052
1393
|
session.emitter.emit("status", sessionId, "idle");
|
|
1053
1394
|
this.flushQueuedMessage(session, sessionId);
|
|
1054
1395
|
}
|
|
@@ -1115,6 +1456,7 @@ class SessionManager {
|
|
|
1115
1456
|
this.emitSystem(session, sessionId, `__model_picker::${current}`);
|
|
1116
1457
|
return true;
|
|
1117
1458
|
}
|
|
1459
|
+
this.log(sessionId, `/model command: args="${args}", was=${session.info.model}`);
|
|
1118
1460
|
this.killProcess(session);
|
|
1119
1461
|
session.info.model = args;
|
|
1120
1462
|
session.info.status = "idle";
|
|
@@ -1141,18 +1483,148 @@ class SessionManager {
|
|
|
1141
1483
|
" /clear, /reset, /new - Clear conversation and start fresh",
|
|
1142
1484
|
" /model [name] - Show or switch model",
|
|
1143
1485
|
" /rename <name> - Rename this session",
|
|
1486
|
+
" /cost - Show session token usage",
|
|
1487
|
+
" /context - Show context window usage",
|
|
1488
|
+
" /status - Show session status",
|
|
1144
1489
|
" /help - Show this help message",
|
|
1145
1490
|
"",
|
|
1146
|
-
"
|
|
1147
|
-
"/review, /analyze, etc.) are passed directly to Claude.",
|
|
1491
|
+
"Other commands (/compact, /commit, /review, etc.) are passed to Claude when possible.",
|
|
1148
1492
|
].join("\n");
|
|
1149
1493
|
this.emitSystem(session, sessionId, helpText);
|
|
1150
1494
|
return true;
|
|
1151
1495
|
}
|
|
1496
|
+
case "/cost": {
|
|
1497
|
+
const t = session.totalTokens;
|
|
1498
|
+
const lines = [
|
|
1499
|
+
`Input tokens: ${t.input.toLocaleString()}`,
|
|
1500
|
+
`Output tokens: ${t.output.toLocaleString()}`,
|
|
1501
|
+
`Cache write tokens: ${t.cacheCreate.toLocaleString()}`,
|
|
1502
|
+
`Cache read tokens: ${t.cacheRead.toLocaleString()}`,
|
|
1503
|
+
];
|
|
1504
|
+
this.emitSystem(session, sessionId, lines.join("\n"));
|
|
1505
|
+
return true;
|
|
1506
|
+
}
|
|
1507
|
+
case "/context": {
|
|
1508
|
+
if (!session.contextUsage) {
|
|
1509
|
+
this.emitSystem(session, sessionId, "Context usage data not available yet.");
|
|
1510
|
+
return true;
|
|
1511
|
+
}
|
|
1512
|
+
const pct = session.contextWindowSize > 0 ? Math.round((session.contextUsage.used / session.contextWindowSize) * 100) : 0;
|
|
1513
|
+
this.emitSystem(session, sessionId, `Context window: ${session.contextUsage.used.toLocaleString()} / ${session.contextWindowSize.toLocaleString()} (${pct}%)`);
|
|
1514
|
+
return true;
|
|
1515
|
+
}
|
|
1516
|
+
case "/status": {
|
|
1517
|
+
const model = session.info.model || "sonnet";
|
|
1518
|
+
const runtime = session.runtime;
|
|
1519
|
+
const plan = session.planMode ? " [plan]" : "";
|
|
1520
|
+
this.emitSystem(session, sessionId, `Model: ${model} Runtime: ${runtime}${plan}`);
|
|
1521
|
+
return true;
|
|
1522
|
+
}
|
|
1523
|
+
}
|
|
1524
|
+
// In PTY mode, intercept commands that render CLI dialogs to prevent hangs
|
|
1525
|
+
if (session.ptyRuntime?.isAlive) {
|
|
1526
|
+
const dialogCmd = cmd.replace("/", "");
|
|
1527
|
+
if (SessionManager.DIALOG_COMMANDS.has(dialogCmd)) {
|
|
1528
|
+
this.emitSystem(session, sessionId, `"${cmd}" opens an interactive CLI dialog that isn't available in remote mode.`);
|
|
1529
|
+
return true;
|
|
1530
|
+
}
|
|
1152
1531
|
}
|
|
1153
1532
|
// All other slash commands pass through to Claude
|
|
1154
1533
|
return false;
|
|
1155
1534
|
}
|
|
1535
|
+
static DIALOG_COMMANDS = new Set([
|
|
1536
|
+
"config",
|
|
1537
|
+
"usage",
|
|
1538
|
+
"session",
|
|
1539
|
+
"stats",
|
|
1540
|
+
"doctor",
|
|
1541
|
+
"diff",
|
|
1542
|
+
"mcp",
|
|
1543
|
+
"permissions",
|
|
1544
|
+
"hooks",
|
|
1545
|
+
"tasks",
|
|
1546
|
+
"agents",
|
|
1547
|
+
"skills",
|
|
1548
|
+
"memory",
|
|
1549
|
+
"theme",
|
|
1550
|
+
"fast",
|
|
1551
|
+
"feedback",
|
|
1552
|
+
"copy",
|
|
1553
|
+
"branch",
|
|
1554
|
+
"plan",
|
|
1555
|
+
"chrome",
|
|
1556
|
+
"desktop",
|
|
1557
|
+
"ide",
|
|
1558
|
+
"mobile",
|
|
1559
|
+
"bridge",
|
|
1560
|
+
"sandbox",
|
|
1561
|
+
"export",
|
|
1562
|
+
"login",
|
|
1563
|
+
"logout",
|
|
1564
|
+
"upgrade",
|
|
1565
|
+
"rate-limit-options",
|
|
1566
|
+
"privacy-settings",
|
|
1567
|
+
"terminal-setup",
|
|
1568
|
+
"install-github-app",
|
|
1569
|
+
"remote-env",
|
|
1570
|
+
"remote-setup",
|
|
1571
|
+
"resume",
|
|
1572
|
+
"add-dir",
|
|
1573
|
+
"btw",
|
|
1574
|
+
"extra-usage",
|
|
1575
|
+
"passes",
|
|
1576
|
+
"think-back",
|
|
1577
|
+
"ultrareview",
|
|
1578
|
+
"tag",
|
|
1579
|
+
"exit",
|
|
1580
|
+
"effort",
|
|
1581
|
+
"color",
|
|
1582
|
+
"files",
|
|
1583
|
+
]);
|
|
1584
|
+
static MEDIA_EXT = {
|
|
1585
|
+
"image/png": ".png",
|
|
1586
|
+
"image/jpeg": ".jpg",
|
|
1587
|
+
"image/gif": ".gif",
|
|
1588
|
+
"image/webp": ".webp",
|
|
1589
|
+
"application/pdf": ".pdf",
|
|
1590
|
+
};
|
|
1591
|
+
writeAttachments(images, documents) {
|
|
1592
|
+
if (!images?.length && !documents?.length)
|
|
1593
|
+
return [];
|
|
1594
|
+
const dir = node_path_1.default.join((0, paths_1.getCockpitCacheDir)(), "attachments");
|
|
1595
|
+
(0, node_fs_1.mkdirSync)(dir, { recursive: true });
|
|
1596
|
+
const paths = [];
|
|
1597
|
+
for (const img of images ?? []) {
|
|
1598
|
+
const ext = SessionManager.MEDIA_EXT[img.mediaType] || ".png";
|
|
1599
|
+
const p = node_path_1.default.join(dir, `${(0, uuid_1.v4)()}${ext}`);
|
|
1600
|
+
(0, node_fs_1.writeFileSync)(p, Buffer.from(img.data, "base64"));
|
|
1601
|
+
paths.push(p);
|
|
1602
|
+
}
|
|
1603
|
+
for (const doc of documents ?? []) {
|
|
1604
|
+
const ext = SessionManager.MEDIA_EXT[doc.mediaType] || ".pdf";
|
|
1605
|
+
const p = node_path_1.default.join(dir, `${(0, uuid_1.v4)()}${ext}`);
|
|
1606
|
+
(0, node_fs_1.writeFileSync)(p, Buffer.from(doc.data, "base64"));
|
|
1607
|
+
paths.push(p);
|
|
1608
|
+
}
|
|
1609
|
+
return paths;
|
|
1610
|
+
}
|
|
1611
|
+
cleanupAttachments(session) {
|
|
1612
|
+
for (const p of session.attachmentPaths) {
|
|
1613
|
+
try {
|
|
1614
|
+
(0, node_fs_1.unlinkSync)(p);
|
|
1615
|
+
}
|
|
1616
|
+
catch {
|
|
1617
|
+
// file already cleaned up
|
|
1618
|
+
}
|
|
1619
|
+
}
|
|
1620
|
+
session.attachmentPaths = [];
|
|
1621
|
+
}
|
|
1622
|
+
buildPtyText(text, attachmentPaths) {
|
|
1623
|
+
if (attachmentPaths.length === 0)
|
|
1624
|
+
return text;
|
|
1625
|
+
const refs = attachmentPaths.map((p) => `[Attached image: ${p}]`).join("\n");
|
|
1626
|
+
return `${refs}\n${text}`;
|
|
1627
|
+
}
|
|
1156
1628
|
buildContent(session, text, images, documents) {
|
|
1157
1629
|
const reminder = session.pendingPlanReminder ? this.planModeReminderText() : null;
|
|
1158
1630
|
if (session.pendingPlanReminder)
|
|
@@ -1197,6 +1669,27 @@ Additional Cockpit rules beyond the CLI's defaults:
|
|
|
1197
1669
|
smLog(id, `recovery succeeded: restored from ${cwd}`);
|
|
1198
1670
|
return true;
|
|
1199
1671
|
}
|
|
1672
|
+
estimateMessageTokens(text, images, documents) {
|
|
1673
|
+
let tokens = Math.ceil(text.length / 4);
|
|
1674
|
+
if (images)
|
|
1675
|
+
tokens += images.length * 2000;
|
|
1676
|
+
if (documents)
|
|
1677
|
+
tokens += documents.reduce((sum, d) => sum + Math.ceil(d.data.length / 5), 0);
|
|
1678
|
+
return tokens;
|
|
1679
|
+
}
|
|
1680
|
+
shouldPreCompact(session, text, images, documents) {
|
|
1681
|
+
if (!session.contextUsage)
|
|
1682
|
+
return false;
|
|
1683
|
+
if (session.compacting)
|
|
1684
|
+
return false;
|
|
1685
|
+
if (text.trim().toLowerCase().startsWith("/compact"))
|
|
1686
|
+
return false;
|
|
1687
|
+
if (text.trim().startsWith("/"))
|
|
1688
|
+
return false;
|
|
1689
|
+
const estimate = this.estimateMessageTokens(text, images, documents);
|
|
1690
|
+
const { used, total } = session.contextUsage;
|
|
1691
|
+
return used + estimate > total * 0.85;
|
|
1692
|
+
}
|
|
1200
1693
|
sendMessage(sessionId, text, images, documents) {
|
|
1201
1694
|
const session = this.sessions.get(sessionId);
|
|
1202
1695
|
if (!session) {
|
|
@@ -1214,6 +1707,29 @@ Additional Cockpit rules beyond the CLI's defaults:
|
|
|
1214
1707
|
this.emitSystem(session, sessionId, "__compact::start");
|
|
1215
1708
|
}
|
|
1216
1709
|
}
|
|
1710
|
+
// If the message would likely overflow the context window, compact first
|
|
1711
|
+
// and queue the message for delivery after compaction finishes.
|
|
1712
|
+
if (session.info.status !== "running" && this.shouldPreCompact(session, text, images, documents)) {
|
|
1713
|
+
this.log(sessionId, "pre-send compact: message would exceed 85% of context window");
|
|
1714
|
+
(0, debug_logger_1.logDiag)(sessionId, "compact:pre-send");
|
|
1715
|
+
session.queuedMessages.push({ id: `q-${Date.now()}-${Math.random().toString(36).slice(2, 6)}`, text, images, documents });
|
|
1716
|
+
session.emitter.emit("queued", sessionId, session.queuedMessages.length);
|
|
1717
|
+
session.compacting = true;
|
|
1718
|
+
this.emitSystem(session, sessionId, "__compact::start");
|
|
1719
|
+
session.info.status = "running";
|
|
1720
|
+
session.emitter.emit("status", sessionId, "running");
|
|
1721
|
+
if (session.ptyRuntime?.isAlive) {
|
|
1722
|
+
session.ptyRuntime.sendText("/compact").catch(() => { });
|
|
1723
|
+
}
|
|
1724
|
+
else if (session.process && session.stdin) {
|
|
1725
|
+
const compactInput = { type: "user", message: { role: "user", content: "/compact" } };
|
|
1726
|
+
session.stdin.write(JSON.stringify(compactInput) + "\n");
|
|
1727
|
+
}
|
|
1728
|
+
else {
|
|
1729
|
+
this.spawnProcess(session, sessionId, "/compact");
|
|
1730
|
+
}
|
|
1731
|
+
return true;
|
|
1732
|
+
}
|
|
1217
1733
|
const content = this.buildContent(session, text, images, documents);
|
|
1218
1734
|
// If queue was paused (user interrupted then sent a new message),
|
|
1219
1735
|
// discard the paused messages and reset the flag.
|
|
@@ -1228,9 +1744,27 @@ Additional Cockpit rules beyond the CLI's defaults:
|
|
|
1228
1744
|
session.emitter.emit("queued", sessionId, session.queuedMessages.length);
|
|
1229
1745
|
return true;
|
|
1230
1746
|
}
|
|
1231
|
-
(0, debug_logger_1.logDiag)(sessionId, "running:send", {
|
|
1747
|
+
(0, debug_logger_1.logDiag)(sessionId, "running:send", {
|
|
1748
|
+
hasProcess: !!session.process,
|
|
1749
|
+
hasStdin: !!session.stdin,
|
|
1750
|
+
runtime: session.runtime,
|
|
1751
|
+
ptyAlive: !!session.ptyRuntime?.isAlive,
|
|
1752
|
+
});
|
|
1232
1753
|
session.info.status = "running";
|
|
1754
|
+
console.log(`[sm] emit status running for ${sessionId.slice(0, 8)} (runtime=${session.runtime})`);
|
|
1233
1755
|
session.emitter.emit("status", sessionId, "running");
|
|
1756
|
+
if (session.runtime === "pty" && session.ptyRuntime?.isAlive) {
|
|
1757
|
+
if (session.streamState)
|
|
1758
|
+
session.streamState.thinkingStartedAt = Date.now();
|
|
1759
|
+
this.cleanupAttachments(session);
|
|
1760
|
+
const attachments = this.writeAttachments(images, documents);
|
|
1761
|
+
session.attachmentPaths.push(...attachments);
|
|
1762
|
+
const ptyText = this.buildPtyText(text, attachments);
|
|
1763
|
+
session.ptyRuntime.sendText(ptyText).catch((err) => {
|
|
1764
|
+
this.log(sessionId, `pty sendText failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
1765
|
+
});
|
|
1766
|
+
return true;
|
|
1767
|
+
}
|
|
1234
1768
|
if (session.process && session.stdin) {
|
|
1235
1769
|
if (session.streamState)
|
|
1236
1770
|
session.streamState.thinkingStartedAt = Date.now();
|
|
@@ -1250,11 +1784,27 @@ Additional Cockpit rules beyond the CLI's defaults:
|
|
|
1250
1784
|
}
|
|
1251
1785
|
ensureProcess(sessionId) {
|
|
1252
1786
|
const session = this.sessions.get(sessionId);
|
|
1253
|
-
if (!session || session.process)
|
|
1787
|
+
if (!session || session.process || session.ptyRuntime?.isAlive)
|
|
1254
1788
|
return;
|
|
1255
1789
|
this.spawnProcess(session, sessionId);
|
|
1256
1790
|
}
|
|
1791
|
+
/** Check effort levels for built-in models or custom provider models. */
|
|
1792
|
+
modelEffortLevels(modelId) {
|
|
1793
|
+
if (!modelId)
|
|
1794
|
+
return [];
|
|
1795
|
+
const builtin = (0, models_1.resolveModel)(modelId);
|
|
1796
|
+
if (builtin)
|
|
1797
|
+
return (0, models_1.allowedEffortLevels)(builtin);
|
|
1798
|
+
const resolved = (0, providers_1.resolveProviderModel)(modelId);
|
|
1799
|
+
if (resolved)
|
|
1800
|
+
return resolved.model.effortLevels;
|
|
1801
|
+
return [];
|
|
1802
|
+
}
|
|
1257
1803
|
spawnProcess(session, sessionId, text, images, documents) {
|
|
1804
|
+
if (session.runtime === "pty") {
|
|
1805
|
+
this.spawnPtyProcess(session, sessionId, text, images, documents);
|
|
1806
|
+
return;
|
|
1807
|
+
}
|
|
1258
1808
|
this.log(sessionId, `spawning CLI process (resume=${session.hasSpawnedBefore}, model=${session.info.model || "sonnet"})`);
|
|
1259
1809
|
const args = ["-p", "--verbose", "--output-format", "stream-json", "--input-format", "stream-json"];
|
|
1260
1810
|
// In plan mode, omit --allow-dangerously-skip-permissions so the CLI
|
|
@@ -1277,25 +1827,35 @@ Additional Cockpit rules beyond the CLI's defaults:
|
|
|
1277
1827
|
else {
|
|
1278
1828
|
args.push("--session-id", session.cliSessionId);
|
|
1279
1829
|
}
|
|
1280
|
-
|
|
1281
|
-
|
|
1830
|
+
const resolved = (0, providers_1.resolveProviderModel)(session.info.model ?? "sonnet");
|
|
1831
|
+
const cliModel = resolved ? resolved.model.modelId : session.info.model;
|
|
1832
|
+
this.log(sessionId, `spawn: info.model=${session.info.model}, resolved=${resolved ? `${resolved.provider.id}:${resolved.model.modelId}` : "null"}, cliModel=${cliModel}`);
|
|
1833
|
+
if (cliModel) {
|
|
1834
|
+
args.push("--model", cliModel);
|
|
1282
1835
|
}
|
|
1283
|
-
if (
|
|
1836
|
+
if (this.modelEffortLevels(session.info.model).length > 0) {
|
|
1284
1837
|
args.push("--effort", session.thinkingLevel);
|
|
1285
1838
|
}
|
|
1286
1839
|
const env = { ...process.env };
|
|
1287
1840
|
delete env.CLAUDECODE;
|
|
1288
1841
|
delete env.CLAUDE_CODE_ENTRYPOINT;
|
|
1289
|
-
|
|
1290
|
-
|
|
1291
|
-
|
|
1292
|
-
//
|
|
1293
|
-
|
|
1842
|
+
if (resolved) {
|
|
1843
|
+
Object.assign(env, resolved.provider.envVars);
|
|
1844
|
+
}
|
|
1845
|
+
// CLAUDE_CODE_DISABLE_1M_CONTEXT is the only switch that forces a model
|
|
1846
|
+
// back to 200K regardless of its capability. Set it when the user picked
|
|
1847
|
+
// 200K for this session.
|
|
1848
|
+
const sizeKey = session.info.contextSize ?? models_1.DEFAULT_CONTEXT_SIZE;
|
|
1849
|
+
if (models_1.CONTEXT_SIZES[sizeKey].disableEnv) {
|
|
1294
1850
|
env.CLAUDE_CODE_DISABLE_1M_CONTEXT = "1";
|
|
1295
1851
|
}
|
|
1852
|
+
if (session.modelSlots.subagent && session.modelSlots.subagent !== session.modelSlots.main) {
|
|
1853
|
+
const resolvedSub = (0, providers_1.resolveProviderModel)(session.modelSlots.subagent);
|
|
1854
|
+
env.ANTHROPIC_SMALL_FAST_MODEL = resolvedSub ? resolvedSub.model.modelId : session.modelSlots.subagent;
|
|
1855
|
+
}
|
|
1296
1856
|
(0, node_fs_1.mkdirSync)(session.info.cwd, { recursive: true });
|
|
1297
1857
|
const isWin = process.platform === "win32";
|
|
1298
|
-
const proc = (0, node_child_process_1.spawn)(
|
|
1858
|
+
const proc = (0, node_child_process_1.spawn)(getClaudeBin(), args, {
|
|
1299
1859
|
cwd: session.info.cwd,
|
|
1300
1860
|
env,
|
|
1301
1861
|
stdio: ["pipe", "pipe", "pipe"],
|
|
@@ -1305,6 +1865,7 @@ Additional Cockpit rules beyond the CLI's defaults:
|
|
|
1305
1865
|
session.stdin = proc.stdin;
|
|
1306
1866
|
session.hasSpawnedBefore = true;
|
|
1307
1867
|
this.log(sessionId, `CLI process spawned (pid=${proc.pid})`);
|
|
1868
|
+
this.startTodoWatcher(session, sessionId);
|
|
1308
1869
|
// Send initialize control request before the first user message to get
|
|
1309
1870
|
// model capabilities, account info, and command metadata from the CLI.
|
|
1310
1871
|
const initRequest = {
|
|
@@ -1405,6 +1966,12 @@ Additional Cockpit rules beyond the CLI's defaults:
|
|
|
1405
1966
|
(0, debug_logger_1.logDiag)(sessionId, "compact:done-on-close");
|
|
1406
1967
|
session.compacting = false;
|
|
1407
1968
|
this.emitSystem(session, sessionId, "__compact::done");
|
|
1969
|
+
const postCompactEstimate = {
|
|
1970
|
+
used: Math.round(session.contextWindowSize * 0.1),
|
|
1971
|
+
total: session.contextWindowSize,
|
|
1972
|
+
};
|
|
1973
|
+
session.contextUsage = postCompactEstimate;
|
|
1974
|
+
session.emitter.emit("usage", sessionId, postCompactEstimate);
|
|
1408
1975
|
}
|
|
1409
1976
|
if (session.todoItems.length > 0 && session.todoItems.every((t) => t.status === "completed")) {
|
|
1410
1977
|
session.todoItems = [];
|
|
@@ -1428,6 +1995,153 @@ Additional Cockpit rules beyond the CLI's defaults:
|
|
|
1428
1995
|
this.flushQueuedMessage(session, sessionId);
|
|
1429
1996
|
});
|
|
1430
1997
|
}
|
|
1998
|
+
spawnPtyProcess(session, sessionId, text, images, documents) {
|
|
1999
|
+
if (session.ptyRuntime?.isAlive) {
|
|
2000
|
+
const existing = session.ptyRuntime;
|
|
2001
|
+
session.ptyRuntime = null;
|
|
2002
|
+
existing.kill().catch(() => { });
|
|
2003
|
+
}
|
|
2004
|
+
const hookRouter = (0, singleton_1.getHookRouter)();
|
|
2005
|
+
if (!hookRouter) {
|
|
2006
|
+
const msg = "PTY runtime requires the hook router; server boot did not register one";
|
|
2007
|
+
this.log(sessionId, msg);
|
|
2008
|
+
session.info.status = "idle";
|
|
2009
|
+
session.emitter.emit("status", sessionId, "idle");
|
|
2010
|
+
session.emitter.emit("error", sessionId, msg);
|
|
2011
|
+
return;
|
|
2012
|
+
}
|
|
2013
|
+
this.log(sessionId, `spawning PTY claude (resume=${session.hasSpawnedBefore}, model=${session.info.model || "sonnet"})`);
|
|
2014
|
+
(0, node_fs_1.mkdirSync)(session.info.cwd, { recursive: true });
|
|
2015
|
+
const streamState = (0, stream_processor_1.createStreamState)();
|
|
2016
|
+
session.streamState = streamState;
|
|
2017
|
+
streamState.thinkingStartedAt = Date.now();
|
|
2018
|
+
const extraArgs = [];
|
|
2019
|
+
if (session.hasSpawnedBefore || (0, transcript_1.transcriptExists)(session.cliSessionId, session.info.cwd)) {
|
|
2020
|
+
extraArgs.push("--resume", session.cliSessionId);
|
|
2021
|
+
}
|
|
2022
|
+
else {
|
|
2023
|
+
extraArgs.push("--session-id", session.cliSessionId);
|
|
2024
|
+
}
|
|
2025
|
+
const resolvedPty = (0, providers_1.resolveProviderModel)(session.info.model ?? "sonnet");
|
|
2026
|
+
const cliModelPty = resolvedPty ? resolvedPty.model.modelId : session.info.model;
|
|
2027
|
+
if (cliModelPty)
|
|
2028
|
+
extraArgs.push("--model", cliModelPty);
|
|
2029
|
+
if (this.modelEffortLevels(session.info.model).length > 0) {
|
|
2030
|
+
extraArgs.push("--effort", session.thinkingLevel);
|
|
2031
|
+
}
|
|
2032
|
+
if (session.planMode) {
|
|
2033
|
+
extraArgs.push("--permission-mode", "plan");
|
|
2034
|
+
}
|
|
2035
|
+
else if (session.bypassAllPermissions) {
|
|
2036
|
+
extraArgs.push("--permission-mode", "bypassPermissions");
|
|
2037
|
+
}
|
|
2038
|
+
const extraEnv = {};
|
|
2039
|
+
if (resolvedPty)
|
|
2040
|
+
Object.assign(extraEnv, resolvedPty.provider.envVars);
|
|
2041
|
+
const sizeKeyPty = session.info.contextSize ?? models_1.DEFAULT_CONTEXT_SIZE;
|
|
2042
|
+
if (models_1.CONTEXT_SIZES[sizeKeyPty].disableEnv) {
|
|
2043
|
+
extraEnv.CLAUDE_CODE_DISABLE_1M_CONTEXT = "1";
|
|
2044
|
+
}
|
|
2045
|
+
if (session.modelSlots.subagent && session.modelSlots.subagent !== session.modelSlots.main) {
|
|
2046
|
+
const resolvedSub = (0, providers_1.resolveProviderModel)(session.modelSlots.subagent);
|
|
2047
|
+
extraEnv.ANTHROPIC_SMALL_FAST_MODEL = resolvedSub ? resolvedSub.model.modelId : session.modelSlots.subagent;
|
|
2048
|
+
}
|
|
2049
|
+
const runtime = new pty_runtime_1.PtyRuntime({
|
|
2050
|
+
sessionId,
|
|
2051
|
+
cwd: session.info.cwd,
|
|
2052
|
+
cliSessionId: session.cliSessionId,
|
|
2053
|
+
hookRouter,
|
|
2054
|
+
claudeBin: getClaudeBin(),
|
|
2055
|
+
extraArgs,
|
|
2056
|
+
extraEnv,
|
|
2057
|
+
onEvents: (events) => {
|
|
2058
|
+
const types = events.map((e) => e.type).join(", ");
|
|
2059
|
+
console.log(`[sm] pty onEvents for ${sessionId.slice(0, 8)}: [${types}]`);
|
|
2060
|
+
const result = (0, stream_processor_1.processEvents)(events, streamState, { planMode: session.planMode, compacting: session.compacting });
|
|
2061
|
+
this.applyProcessedResult(session, sessionId, result);
|
|
2062
|
+
},
|
|
2063
|
+
onError: (err) => {
|
|
2064
|
+
this.log(sessionId, `pty runtime error: ${err}`);
|
|
2065
|
+
session.emitter.emit("error", sessionId, err);
|
|
2066
|
+
},
|
|
2067
|
+
onExit: ({ exitCode, signal }) => {
|
|
2068
|
+
this.log(sessionId, `PTY claude exited (code=${exitCode}, signal=${signal ?? "none"})`);
|
|
2069
|
+
if (session.ptyRuntime !== runtime)
|
|
2070
|
+
return;
|
|
2071
|
+
session.ptyRuntime = null;
|
|
2072
|
+
session.streamingSnapshot = null;
|
|
2073
|
+
(0, debug_logger_1.logDiag)(sessionId, "idle:pty-exit", { exitCode, flushedOnMessageDone: streamState.flushedOnMessageDone });
|
|
2074
|
+
if (session.transcriptWatcher) {
|
|
2075
|
+
session.transcriptWatcher.stop();
|
|
2076
|
+
session.transcriptWatcher = null;
|
|
2077
|
+
}
|
|
2078
|
+
session.info.status = "idle";
|
|
2079
|
+
session.emitter.emit("status", sessionId, "idle");
|
|
2080
|
+
if (session.compacting) {
|
|
2081
|
+
(0, debug_logger_1.logDiag)(sessionId, "compact:done-on-pty-exit");
|
|
2082
|
+
session.compacting = false;
|
|
2083
|
+
this.emitSystem(session, sessionId, "__compact::done");
|
|
2084
|
+
const postCompactEstimate = {
|
|
2085
|
+
used: Math.round(session.contextWindowSize * 0.1),
|
|
2086
|
+
total: session.contextWindowSize,
|
|
2087
|
+
};
|
|
2088
|
+
session.contextUsage = postCompactEstimate;
|
|
2089
|
+
session.emitter.emit("usage", sessionId, postCompactEstimate);
|
|
2090
|
+
}
|
|
2091
|
+
if (session.todoItems.length > 0 && session.todoItems.every((t) => t.status === "completed")) {
|
|
2092
|
+
session.todoItems = [];
|
|
2093
|
+
session.emitter.emit("todos", sessionId, []);
|
|
2094
|
+
}
|
|
2095
|
+
if (!streamState.flushedOnMessageDone) {
|
|
2096
|
+
this.flushQueuedMessage(session, sessionId);
|
|
2097
|
+
}
|
|
2098
|
+
},
|
|
2099
|
+
});
|
|
2100
|
+
session.ptyRuntime = runtime;
|
|
2101
|
+
session.hasSpawnedBefore = true;
|
|
2102
|
+
this.cleanupAttachments(session);
|
|
2103
|
+
const attachments = this.writeAttachments(images, documents);
|
|
2104
|
+
session.attachmentPaths.push(...attachments);
|
|
2105
|
+
const ptyText = text ? this.buildPtyText(text, attachments) : text;
|
|
2106
|
+
const watcher = new transcript_watcher_1.TranscriptWatcher(session.cliSessionId, session.info.cwd, (messages, lastUsage) => {
|
|
2107
|
+
session.emitter.emit("transcript", sessionId, messages);
|
|
2108
|
+
if (lastUsage) {
|
|
2109
|
+
const usage = { used: lastUsage.used, total: session.contextWindowSize };
|
|
2110
|
+
session.contextUsage = usage;
|
|
2111
|
+
session.emitter.emit("usage", sessionId, usage);
|
|
2112
|
+
}
|
|
2113
|
+
if (session.compacting && messages.some((m) => m.content === "__compacted__")) {
|
|
2114
|
+
(0, debug_logger_1.logDiag)(sessionId, "compact:done-on-transcript");
|
|
2115
|
+
session.compacting = false;
|
|
2116
|
+
this.emitSystem(session, sessionId, "__compact::done");
|
|
2117
|
+
const postCompactEstimate = {
|
|
2118
|
+
used: Math.round(session.contextWindowSize * 0.1),
|
|
2119
|
+
total: session.contextWindowSize,
|
|
2120
|
+
};
|
|
2121
|
+
session.contextUsage = postCompactEstimate;
|
|
2122
|
+
session.emitter.emit("usage", sessionId, postCompactEstimate);
|
|
2123
|
+
session.info.status = "idle";
|
|
2124
|
+
session.emitter.emit("status", sessionId, "idle");
|
|
2125
|
+
this.flushQueuedMessage(session, sessionId);
|
|
2126
|
+
}
|
|
2127
|
+
});
|
|
2128
|
+
session.transcriptWatcher = watcher;
|
|
2129
|
+
this.startTodoWatcher(session, sessionId);
|
|
2130
|
+
runtime
|
|
2131
|
+
.start(ptyText)
|
|
2132
|
+
.then(() => {
|
|
2133
|
+
this.log(sessionId, `PTY claude ready (pid=${runtime.pid})`);
|
|
2134
|
+
watcher.start();
|
|
2135
|
+
})
|
|
2136
|
+
.catch((err) => {
|
|
2137
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
2138
|
+
this.log(sessionId, `pty runtime start failed: ${msg}`);
|
|
2139
|
+
session.ptyRuntime = null;
|
|
2140
|
+
session.info.status = "idle";
|
|
2141
|
+
session.emitter.emit("status", sessionId, "idle");
|
|
2142
|
+
session.emitter.emit("error", sessionId, msg);
|
|
2143
|
+
});
|
|
2144
|
+
}
|
|
1431
2145
|
async loadAgentChildren(session, sessionId, messageId, cwd) {
|
|
1432
2146
|
try {
|
|
1433
2147
|
const result = await (0, transcript_1.loadTranscript)(session.cliSessionId, cwd);
|
|
@@ -1451,12 +2165,15 @@ Additional Cockpit rules beyond the CLI's defaults:
|
|
|
1451
2165
|
}
|
|
1452
2166
|
}
|
|
1453
2167
|
exports.SessionManager = SessionManager;
|
|
1454
|
-
|
|
2168
|
+
function mcpCachePath() {
|
|
2169
|
+
return node_path_1.default.join((0, paths_1.getCockpitDir)(), "mcp-servers.json");
|
|
2170
|
+
}
|
|
1455
2171
|
function loadMcpServerCache() {
|
|
1456
2172
|
try {
|
|
1457
|
-
|
|
2173
|
+
const fp = mcpCachePath();
|
|
2174
|
+
if (!(0, node_fs_1.existsSync)(fp))
|
|
1458
2175
|
return [];
|
|
1459
|
-
return JSON.parse((0, node_fs_1.readFileSync)(
|
|
2176
|
+
return JSON.parse((0, node_fs_1.readFileSync)(fp, "utf-8"));
|
|
1460
2177
|
}
|
|
1461
2178
|
catch {
|
|
1462
2179
|
return [];
|
|
@@ -1464,43 +2181,12 @@ function loadMcpServerCache() {
|
|
|
1464
2181
|
}
|
|
1465
2182
|
function saveMcpServerCache(servers) {
|
|
1466
2183
|
try {
|
|
1467
|
-
const
|
|
2184
|
+
const fp = mcpCachePath();
|
|
2185
|
+
const dir = node_path_1.default.dirname(fp);
|
|
1468
2186
|
(0, node_fs_1.mkdirSync)(dir, { recursive: true });
|
|
1469
|
-
(0, node_fs_1.writeFileSync)(
|
|
2187
|
+
(0, node_fs_1.writeFileSync)(fp, JSON.stringify(servers));
|
|
1470
2188
|
}
|
|
1471
2189
|
catch {
|
|
1472
2190
|
// best-effort
|
|
1473
2191
|
}
|
|
1474
2192
|
}
|
|
1475
|
-
// Walk messages newest-first, stop at the most recent /clear boundary, and
|
|
1476
|
-
// pull todos from the last TodoWrite call. Pure function so the history-view
|
|
1477
|
-
// branch can use it without an in-memory session.
|
|
1478
|
-
function extractTodosFromHistory(messages) {
|
|
1479
|
-
for (let i = messages.length - 1; i >= 0; i--) {
|
|
1480
|
-
const msg = messages[i];
|
|
1481
|
-
if (msg.role === "system" && msg.content === "__compacted__")
|
|
1482
|
-
return [];
|
|
1483
|
-
if (msg.role !== "assistant")
|
|
1484
|
-
continue;
|
|
1485
|
-
for (let j = msg.toolUses.length - 1; j >= 0; j--) {
|
|
1486
|
-
if (msg.toolUses[j].name !== "TodoWrite")
|
|
1487
|
-
continue;
|
|
1488
|
-
try {
|
|
1489
|
-
const input = JSON.parse(msg.toolUses[j].input);
|
|
1490
|
-
if (!Array.isArray(input.todos))
|
|
1491
|
-
return [];
|
|
1492
|
-
return input.todos
|
|
1493
|
-
.filter((t) => t.content && t.status)
|
|
1494
|
-
.map((t) => ({
|
|
1495
|
-
content: t.content,
|
|
1496
|
-
status: t.status,
|
|
1497
|
-
activeForm: t.activeForm || undefined,
|
|
1498
|
-
}));
|
|
1499
|
-
}
|
|
1500
|
-
catch {
|
|
1501
|
-
return [];
|
|
1502
|
-
}
|
|
1503
|
-
}
|
|
1504
|
-
}
|
|
1505
|
-
return [];
|
|
1506
|
-
}
|