@prestyj/cli 5.4.1 → 5.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +25 -12
- package/assets/end-notification.mp3 +0 -0
- package/assets/skills/evidence-led-ui/LICENSES.md +68 -0
- package/assets/skills/evidence-led-ui/SKILL.md +139 -0
- package/{LICENSE → assets/skills/evidence-led-ui/corpus/awesome-design-md/LICENSE} +1 -1
- package/assets/skills/evidence-led-ui/corpus/awesome-design-md/design-md/airbnb/DESIGN.md +545 -0
- package/assets/skills/evidence-led-ui/corpus/awesome-design-md/design-md/airtable/DESIGN.md +554 -0
- package/assets/skills/evidence-led-ui/corpus/awesome-design-md/design-md/apple/DESIGN.md +562 -0
- package/assets/skills/evidence-led-ui/corpus/awesome-design-md/design-md/binance/DESIGN.md +634 -0
- package/assets/skills/evidence-led-ui/corpus/awesome-design-md/design-md/bmw/DESIGN.md +544 -0
- package/assets/skills/evidence-led-ui/corpus/awesome-design-md/design-md/bmw-m/DESIGN.md +503 -0
- package/assets/skills/evidence-led-ui/corpus/awesome-design-md/design-md/bugatti/DESIGN.md +454 -0
- package/assets/skills/evidence-led-ui/corpus/awesome-design-md/design-md/cal/DESIGN.md +542 -0
- package/assets/skills/evidence-led-ui/corpus/awesome-design-md/design-md/claude/DESIGN.md +589 -0
- package/assets/skills/evidence-led-ui/corpus/awesome-design-md/design-md/clay/DESIGN.md +541 -0
- package/assets/skills/evidence-led-ui/corpus/awesome-design-md/design-md/clickhouse/DESIGN.md +544 -0
- package/assets/skills/evidence-led-ui/corpus/awesome-design-md/design-md/cohere/DESIGN.md +451 -0
- package/assets/skills/evidence-led-ui/corpus/awesome-design-md/design-md/coinbase/DESIGN.md +570 -0
- package/assets/skills/evidence-led-ui/corpus/awesome-design-md/design-md/composio/DESIGN.md +506 -0
- package/assets/skills/evidence-led-ui/corpus/awesome-design-md/design-md/cursor/DESIGN.md +537 -0
- package/assets/skills/evidence-led-ui/corpus/awesome-design-md/design-md/dell-1996/DESIGN.md +632 -0
- package/assets/skills/evidence-led-ui/corpus/awesome-design-md/design-md/elevenlabs/DESIGN.md +504 -0
- package/assets/skills/evidence-led-ui/corpus/awesome-design-md/design-md/expo/DESIGN.md +526 -0
- package/assets/skills/evidence-led-ui/corpus/awesome-design-md/design-md/ferrari/DESIGN.md +531 -0
- package/assets/skills/evidence-led-ui/corpus/awesome-design-md/design-md/figma/DESIGN.md +578 -0
- package/assets/skills/evidence-led-ui/corpus/awesome-design-md/design-md/framer/DESIGN.md +544 -0
- package/assets/skills/evidence-led-ui/corpus/awesome-design-md/design-md/hashicorp/DESIGN.md +575 -0
- package/assets/skills/evidence-led-ui/corpus/awesome-design-md/design-md/hp/DESIGN.md +670 -0
- package/assets/skills/evidence-led-ui/corpus/awesome-design-md/design-md/ibm/DESIGN.md +550 -0
- package/assets/skills/evidence-led-ui/corpus/awesome-design-md/design-md/intercom/DESIGN.md +546 -0
- package/assets/skills/evidence-led-ui/corpus/awesome-design-md/design-md/kraken/DESIGN.md +125 -0
- package/assets/skills/evidence-led-ui/corpus/awesome-design-md/design-md/lamborghini/DESIGN.md +288 -0
- package/assets/skills/evidence-led-ui/corpus/awesome-design-md/design-md/linear.app/DESIGN.md +548 -0
- package/assets/skills/evidence-led-ui/corpus/awesome-design-md/design-md/lovable/DESIGN.md +298 -0
- package/assets/skills/evidence-led-ui/corpus/awesome-design-md/design-md/mastercard/DESIGN.md +365 -0
- package/assets/skills/evidence-led-ui/corpus/awesome-design-md/design-md/meta/DESIGN.md +683 -0
- package/assets/skills/evidence-led-ui/corpus/awesome-design-md/design-md/minimax/DESIGN.md +746 -0
- package/assets/skills/evidence-led-ui/corpus/awesome-design-md/design-md/mintlify/DESIGN.md +852 -0
- package/assets/skills/evidence-led-ui/corpus/awesome-design-md/design-md/miro/DESIGN.md +825 -0
- package/assets/skills/evidence-led-ui/corpus/awesome-design-md/design-md/mistral.ai/DESIGN.md +773 -0
- package/assets/skills/evidence-led-ui/corpus/awesome-design-md/design-md/mongodb/DESIGN.md +767 -0
- package/assets/skills/evidence-led-ui/corpus/awesome-design-md/design-md/nike/DESIGN.md +575 -0
- package/assets/skills/evidence-led-ui/corpus/awesome-design-md/design-md/nintendo-2001/DESIGN.md +649 -0
- package/assets/skills/evidence-led-ui/corpus/awesome-design-md/design-md/notion/DESIGN.md +821 -0
- package/assets/skills/evidence-led-ui/corpus/awesome-design-md/design-md/nvidia/DESIGN.md +640 -0
- package/assets/skills/evidence-led-ui/corpus/awesome-design-md/design-md/ollama/DESIGN.md +539 -0
- package/assets/skills/evidence-led-ui/corpus/awesome-design-md/design-md/opencode.ai/DESIGN.md +521 -0
- package/assets/skills/evidence-led-ui/corpus/awesome-design-md/design-md/pinterest/DESIGN.md +597 -0
- package/assets/skills/evidence-led-ui/corpus/awesome-design-md/design-md/playstation/DESIGN.md +661 -0
- package/assets/skills/evidence-led-ui/corpus/awesome-design-md/design-md/posthog/DESIGN.md +690 -0
- package/assets/skills/evidence-led-ui/corpus/awesome-design-md/design-md/raycast/DESIGN.md +669 -0
- package/assets/skills/evidence-led-ui/corpus/awesome-design-md/design-md/renault/DESIGN.md +589 -0
- package/assets/skills/evidence-led-ui/corpus/awesome-design-md/design-md/replicate/DESIGN.md +616 -0
- package/assets/skills/evidence-led-ui/corpus/awesome-design-md/design-md/resend/DESIGN.md +585 -0
- package/assets/skills/evidence-led-ui/corpus/awesome-design-md/design-md/revolut/DESIGN.md +636 -0
- package/assets/skills/evidence-led-ui/corpus/awesome-design-md/design-md/runwayml/DESIGN.md +244 -0
- package/assets/skills/evidence-led-ui/corpus/awesome-design-md/design-md/sanity/DESIGN.md +357 -0
- package/assets/skills/evidence-led-ui/corpus/awesome-design-md/design-md/sentry/DESIGN.md +551 -0
- package/assets/skills/evidence-led-ui/corpus/awesome-design-md/design-md/shopify/DESIGN.md +516 -0
- package/assets/skills/evidence-led-ui/corpus/awesome-design-md/design-md/slack/DESIGN.md +482 -0
- package/assets/skills/evidence-led-ui/corpus/awesome-design-md/design-md/spacex/DESIGN.md +363 -0
- package/assets/skills/evidence-led-ui/corpus/awesome-design-md/design-md/spotify/DESIGN.md +246 -0
- package/assets/skills/evidence-led-ui/corpus/awesome-design-md/design-md/starbucks/DESIGN.md +580 -0
- package/assets/skills/evidence-led-ui/corpus/awesome-design-md/design-md/stripe/DESIGN.md +487 -0
- package/assets/skills/evidence-led-ui/corpus/awesome-design-md/design-md/supabase/DESIGN.md +462 -0
- package/assets/skills/evidence-led-ui/corpus/awesome-design-md/design-md/superhuman/DESIGN.md +448 -0
- package/assets/skills/evidence-led-ui/corpus/awesome-design-md/design-md/tesla/DESIGN.md +286 -0
- package/assets/skills/evidence-led-ui/corpus/awesome-design-md/design-md/theverge/DESIGN.md +339 -0
- package/assets/skills/evidence-led-ui/corpus/awesome-design-md/design-md/together.ai/DESIGN.md +633 -0
- package/assets/skills/evidence-led-ui/corpus/awesome-design-md/design-md/uber/DESIGN.md +636 -0
- package/assets/skills/evidence-led-ui/corpus/awesome-design-md/design-md/vercel/DESIGN.md +736 -0
- package/assets/skills/evidence-led-ui/corpus/awesome-design-md/design-md/vodafone/DESIGN.md +538 -0
- package/assets/skills/evidence-led-ui/corpus/awesome-design-md/design-md/voltagent/DESIGN.md +521 -0
- package/assets/skills/evidence-led-ui/corpus/awesome-design-md/design-md/warp/DESIGN.md +526 -0
- package/assets/skills/evidence-led-ui/corpus/awesome-design-md/design-md/webflow/DESIGN.md +588 -0
- package/assets/skills/evidence-led-ui/corpus/awesome-design-md/design-md/wired/DESIGN.md +497 -0
- package/assets/skills/evidence-led-ui/corpus/awesome-design-md/design-md/wise/DESIGN.md +544 -0
- package/assets/skills/evidence-led-ui/corpus/awesome-design-md/design-md/x.ai/DESIGN.md +465 -0
- package/assets/skills/evidence-led-ui/corpus/awesome-design-md/design-md/zapier/DESIGN.md +537 -0
- package/assets/skills/evidence-led-ui/data/corpus-manifest.json +768 -0
- package/assets/skills/evidence-led-ui/data/observations.json +47053 -0
- package/assets/skills/evidence-led-ui/references/anti-defaults.md +203 -0
- package/assets/skills/evidence-led-ui/references/archetypes.md +97 -0
- package/assets/skills/evidence-led-ui/references/craft-rulings.md +167 -0
- package/assets/skills/evidence-led-ui/references/methodology.md +72 -0
- package/assets/skills/evidence-led-ui/references/observed-patterns.md +68 -0
- package/assets/skills/evidence-led-ui/references/production-contract.md +120 -0
- package/assets/skills/evidence-led-ui/references/provenance.md +117 -0
- package/assets/skills/evidence-led-ui/references/quality-rubric.md +126 -0
- package/dist/app-sidecar.js +272 -74
- package/dist/app-sidecar.js.map +1 -1
- package/dist/chat-agents/general.d.ts +7 -0
- package/dist/chat-agents/general.d.ts.map +1 -0
- package/dist/chat-agents/general.js +16 -0
- package/dist/chat-agents/general.js.map +1 -0
- package/dist/chat-agents/general.test.d.ts +2 -0
- package/dist/chat-agents/general.test.d.ts.map +1 -0
- package/dist/chat-agents/general.test.js +50 -0
- package/dist/chat-agents/general.test.js.map +1 -0
- package/dist/chat-agents/index.d.ts +11 -0
- package/dist/chat-agents/index.d.ts.map +1 -0
- package/dist/chat-agents/index.js +89 -0
- package/dist/chat-agents/index.js.map +1 -0
- package/dist/chat-agents/jiwa.d.ts +53 -0
- package/dist/chat-agents/jiwa.d.ts.map +1 -0
- package/dist/chat-agents/jiwa.js +352 -0
- package/dist/chat-agents/jiwa.js.map +1 -0
- package/dist/chat-agents/jiwa.test.d.ts +2 -0
- package/dist/chat-agents/jiwa.test.d.ts.map +1 -0
- package/dist/chat-agents/jiwa.test.js +66 -0
- package/dist/chat-agents/jiwa.test.js.map +1 -0
- package/dist/chat-agents/memory.d.ts +53 -0
- package/dist/chat-agents/memory.d.ts.map +1 -0
- package/dist/chat-agents/memory.js +362 -0
- package/dist/chat-agents/memory.js.map +1 -0
- package/dist/chat-agents/memory.test.d.ts +2 -0
- package/dist/chat-agents/memory.test.d.ts.map +1 -0
- package/dist/chat-agents/memory.test.js +155 -0
- package/dist/chat-agents/memory.test.js.map +1 -0
- package/dist/chat-agents/research.d.ts +7 -0
- package/dist/chat-agents/research.d.ts.map +1 -0
- package/dist/chat-agents/research.js +18 -0
- package/dist/chat-agents/research.js.map +1 -0
- package/dist/chat-agents/shared.d.ts +11 -0
- package/dist/chat-agents/shared.d.ts.map +1 -0
- package/dist/chat-agents/shared.js +52 -0
- package/dist/chat-agents/shared.js.map +1 -0
- package/dist/chat-agents/specialists.test.d.ts +2 -0
- package/dist/chat-agents/specialists.test.d.ts.map +1 -0
- package/dist/chat-agents/specialists.test.js +97 -0
- package/dist/chat-agents/specialists.test.js.map +1 -0
- package/dist/chat-agents/therapist.d.ts +7 -0
- package/dist/chat-agents/therapist.d.ts.map +1 -0
- package/dist/chat-agents/therapist.js +20 -0
- package/dist/chat-agents/therapist.js.map +1 -0
- package/dist/chat-agents/types.d.ts +4 -0
- package/dist/chat-agents/types.d.ts.map +1 -0
- package/dist/chat-agents/types.js +7 -0
- package/dist/chat-agents/types.js.map +1 -0
- package/dist/cli/auth.js +1 -1
- package/dist/cli/auth.js.map +1 -1
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +72 -22
- package/dist/cli.js.map +1 -1
- package/dist/core/agent-session-memory-tail.test.d.ts +2 -0
- package/dist/core/agent-session-memory-tail.test.d.ts.map +1 -0
- package/dist/core/agent-session-memory-tail.test.js +122 -0
- package/dist/core/agent-session-memory-tail.test.js.map +1 -0
- package/dist/core/agent-session-subagent-policy.test.d.ts +2 -0
- package/dist/core/agent-session-subagent-policy.test.d.ts.map +1 -0
- package/dist/core/agent-session-subagent-policy.test.js +36 -0
- package/dist/core/agent-session-subagent-policy.test.js.map +1 -0
- package/dist/core/agent-session.d.ts +39 -11
- package/dist/core/agent-session.d.ts.map +1 -1
- package/dist/core/agent-session.js +178 -125
- package/dist/core/agent-session.js.map +1 -1
- package/dist/core/agents.d.ts +1 -1
- package/dist/core/agents.d.ts.map +1 -1
- package/dist/core/agents.js +4 -2
- package/dist/core/agents.js.map +1 -1
- package/dist/core/auth-providers.js +5 -5
- package/dist/core/auth-providers.js.map +1 -1
- package/dist/core/compaction/compactor.d.ts +7 -0
- package/dist/core/compaction/compactor.d.ts.map +1 -1
- package/dist/core/compaction/compactor.js +73 -9
- package/dist/core/compaction/compactor.js.map +1 -1
- package/dist/core/compaction/compactor.test.js +31 -4
- package/dist/core/compaction/compactor.test.js.map +1 -1
- package/dist/core/event-bus.d.ts +2 -0
- package/dist/core/event-bus.d.ts.map +1 -1
- package/dist/core/event-bus.js.map +1 -1
- package/dist/core/goal-worker.test.js +3 -2
- package/dist/core/goal-worker.test.js.map +1 -1
- package/dist/core/loop-breaker.d.ts +23 -16
- package/dist/core/loop-breaker.d.ts.map +1 -1
- package/dist/core/loop-breaker.js +52 -11
- package/dist/core/loop-breaker.js.map +1 -1
- package/dist/core/loop-breaker.test.js +37 -16
- package/dist/core/loop-breaker.test.js.map +1 -1
- package/dist/core/mcp/defaults.d.ts +1 -1
- package/dist/core/mcp/defaults.js +1 -1
- package/dist/core/mcp/store.d.ts +2 -2
- package/dist/core/mcp/store.test.js +1 -1
- package/dist/core/mcp/store.test.js.map +1 -1
- package/dist/core/nolan-prompt.d.ts +3 -3
- package/dist/core/nolan-prompt.d.ts.map +1 -1
- package/dist/core/nolan-prompt.js +10 -10
- package/dist/core/nolan-prompt.js.map +1 -1
- package/dist/core/nolan-prompt.test.js +17 -0
- package/dist/core/nolan-prompt.test.js.map +1 -1
- package/dist/core/progress/rebuild.d.ts +3 -3
- package/dist/core/progress/rebuild.d.ts.map +1 -1
- package/dist/core/progress/rebuild.js +33 -27
- package/dist/core/progress/rebuild.js.map +1 -1
- package/dist/core/progress/rebuild.test.js +15 -0
- package/dist/core/progress/rebuild.test.js.map +1 -1
- package/dist/core/project-discovery.d.ts +1 -1
- package/dist/core/project-discovery.d.ts.map +1 -1
- package/dist/core/project-discovery.js +5 -6
- package/dist/core/project-discovery.js.map +1 -1
- package/dist/core/project-discovery.test.js +14 -1
- package/dist/core/project-discovery.test.js.map +1 -1
- package/dist/core/radio.d.ts +3 -0
- package/dist/core/radio.d.ts.map +1 -1
- package/dist/core/radio.js +150 -21
- package/dist/core/radio.js.map +1 -1
- package/dist/core/radio.test.d.ts +2 -0
- package/dist/core/radio.test.d.ts.map +1 -0
- package/dist/core/radio.test.js +101 -0
- package/dist/core/radio.test.js.map +1 -0
- package/dist/core/session-history.test.js +1 -1
- package/dist/core/session-history.test.js.map +1 -1
- package/dist/core/session-manager.d.ts +1 -1
- package/dist/core/session-manager.d.ts.map +1 -1
- package/dist/core/session-manager.js +2 -1
- package/dist/core/session-manager.js.map +1 -1
- package/dist/core/session-manager.test.js +18 -0
- package/dist/core/session-manager.test.js.map +1 -1
- package/dist/core/settings-manager.d.ts +1 -0
- package/dist/core/settings-manager.d.ts.map +1 -1
- package/dist/core/settings-manager.js +1 -1
- package/dist/core/settings-manager.js.map +1 -1
- package/dist/core/skills-routing.test.d.ts +2 -0
- package/dist/core/skills-routing.test.d.ts.map +1 -0
- package/dist/core/skills-routing.test.js +70 -0
- package/dist/core/skills-routing.test.js.map +1 -0
- package/dist/core/skills.d.ts +2 -0
- package/dist/core/skills.d.ts.map +1 -1
- package/dist/core/skills.js +32 -9
- package/dist/core/skills.js.map +1 -1
- package/dist/core/subagent-manager.d.ts +73 -0
- package/dist/core/subagent-manager.d.ts.map +1 -0
- package/dist/core/subagent-manager.js +412 -0
- package/dist/core/subagent-manager.js.map +1 -0
- package/dist/core/subagent-manager.test.d.ts +2 -0
- package/dist/core/subagent-manager.test.d.ts.map +1 -0
- package/dist/core/subagent-manager.test.js +103 -0
- package/dist/core/subagent-manager.test.js.map +1 -0
- package/dist/core/subagent-policy.d.ts +4 -0
- package/dist/core/subagent-policy.d.ts.map +1 -0
- package/dist/core/subagent-policy.js +19 -0
- package/dist/core/subagent-policy.js.map +1 -0
- package/dist/modes/json-mode.d.ts.map +1 -1
- package/dist/modes/json-mode.js +3 -4
- package/dist/modes/json-mode.js.map +1 -1
- package/dist/modes/subagent-worker-mode.d.ts +14 -0
- package/dist/modes/subagent-worker-mode.d.ts.map +1 -0
- package/dist/modes/subagent-worker-mode.js +191 -0
- package/dist/modes/subagent-worker-mode.js.map +1 -0
- package/dist/system-prompt.js +2 -2
- package/dist/system-prompt.js.map +1 -1
- package/dist/system-prompt.test.js +7 -5
- package/dist/system-prompt.test.js.map +1 -1
- package/dist/tools/generate-image.d.ts.map +1 -1
- package/dist/tools/generate-image.js +12 -5
- package/dist/tools/generate-image.js.map +1 -1
- package/dist/tools/generate-image.test.js +17 -0
- package/dist/tools/generate-image.test.js.map +1 -1
- package/dist/tools/goals.d.ts +3 -3
- package/dist/tools/index.d.ts +10 -2
- package/dist/tools/index.d.ts.map +1 -1
- package/dist/tools/index.js +17 -1
- package/dist/tools/index.js.map +1 -1
- package/dist/tools/skill.d.ts.map +1 -1
- package/dist/tools/skill.js +8 -3
- package/dist/tools/skill.js.map +1 -1
- package/dist/tools/subagent-control.d.ts +6 -0
- package/dist/tools/subagent-control.d.ts.map +1 -0
- package/dist/tools/subagent-control.js +95 -0
- package/dist/tools/subagent-control.js.map +1 -0
- package/dist/tools/subagent-control.test.d.ts +2 -0
- package/dist/tools/subagent-control.test.d.ts.map +1 -0
- package/dist/tools/subagent-control.test.js +40 -0
- package/dist/tools/subagent-control.test.js.map +1 -0
- package/dist/tools/subagent-shared.d.ts +24 -0
- package/dist/tools/subagent-shared.d.ts.map +1 -0
- package/dist/tools/subagent-shared.js +53 -0
- package/dist/tools/subagent-shared.js.map +1 -0
- package/dist/tools/subagent-shared.test.d.ts +2 -0
- package/dist/tools/subagent-shared.test.d.ts.map +1 -0
- package/dist/tools/subagent-shared.test.js +29 -0
- package/dist/tools/subagent-shared.test.js.map +1 -0
- package/dist/tools/subagent.d.ts.map +1 -1
- package/dist/tools/subagent.js +21 -64
- package/dist/tools/subagent.js.map +1 -1
- package/dist/tools/subagent.test.js +27 -1
- package/dist/tools/subagent.test.js.map +1 -1
- package/dist/tools/web-fetch.d.ts +1 -0
- package/dist/tools/web-fetch.d.ts.map +1 -1
- package/dist/tools/web-fetch.js +112 -35
- package/dist/tools/web-fetch.js.map +1 -1
- package/dist/tools/web-fetch.test.js +146 -1
- package/dist/tools/web-fetch.test.js.map +1 -1
- package/dist/tools/web-search.d.ts +10 -0
- package/dist/tools/web-search.d.ts.map +1 -1
- package/dist/tools/web-search.js +236 -28
- package/dist/tools/web-search.js.map +1 -1
- package/dist/tools/web-search.test.js +77 -6
- package/dist/tools/web-search.test.js.map +1 -1
- package/dist/ui/App.d.ts +2 -0
- package/dist/ui/App.d.ts.map +1 -1
- package/dist/ui/App.js +61 -2
- package/dist/ui/App.js.map +1 -1
- package/dist/ui/components/SkillsOverlay.d.ts.map +1 -1
- package/dist/ui/components/SkillsOverlay.js +8 -3
- package/dist/ui/components/SkillsOverlay.js.map +1 -1
- package/dist/ui/hooks/useAgentLoop.d.ts.map +1 -1
- package/dist/ui/hooks/useAgentLoop.js +7 -18
- package/dist/ui/hooks/useAgentLoop.js.map +1 -1
- package/dist/ui/hooks/useAgentLoop.test.js +27 -0
- package/dist/ui/hooks/useAgentLoop.test.js.map +1 -1
- package/dist/ui/hooks/useModeState.d.ts +4 -2
- package/dist/ui/hooks/useModeState.d.ts.map +1 -1
- package/dist/ui/hooks/useModeState.js +14 -3
- package/dist/ui/hooks/useModeState.js.map +1 -1
- package/dist/ui/login.d.ts.map +1 -1
- package/dist/ui/login.js +13 -5
- package/dist/ui/login.js.map +1 -1
- package/dist/ui/render.d.ts +14 -0
- package/dist/ui/render.d.ts.map +1 -1
- package/dist/ui/render.js +2 -0
- package/dist/ui/render.js.map +1 -1
- package/dist/ui/render.test.js +17 -0
- package/dist/ui/render.test.js.map +1 -1
- package/package.json +7 -6
package/dist/app-sidecar.js
CHANGED
|
@@ -20,7 +20,11 @@ import { randomUUID } from "node:crypto";
|
|
|
20
20
|
import { parseArgs } from "node:util";
|
|
21
21
|
import { formatError } from "@prestyj/ai";
|
|
22
22
|
import { runJsonMode } from "./modes/json-mode.js";
|
|
23
|
+
import { runSubagentWorkerMode } from "./modes/subagent-worker-mode.js";
|
|
23
24
|
import { AgentSession } from "./core/agent-session.js";
|
|
25
|
+
import { CHAT_AGENT_IDS, chatAgentSessionsDir, createChatAgent, parseChatAgentId, sessionsDirForChatAgent, switchChatAgent, } from "./chat-agents/index.js";
|
|
26
|
+
import { buildJiwaTools, JiwaStore } from "./chat-agents/jiwa.js";
|
|
27
|
+
import { buildMemoryTools, MemoryStore } from "./chat-agents/memory.js";
|
|
24
28
|
import { buildNolanSystemPrompt, buildNolanAutopilotSystemPrompt } from "./core/nolan-prompt.js";
|
|
25
29
|
import { buildNolanDigest, buildNolanAutopilotContext, buildNolanAutopilotPlanContext, } from "./core/nolan-context.js";
|
|
26
30
|
import { parseAutopilotVerdict } from "./core/autopilot-verdict.js";
|
|
@@ -46,7 +50,7 @@ import { loadCustomCommands } from "./core/custom-commands.js";
|
|
|
46
50
|
import { discoverProjects, listRecentSessions } from "./core/project-discovery.js";
|
|
47
51
|
import { loadTasksSync, saveTasksSync, pruneDoneTasksSync, getNextPendingTask, markTaskInProgress, } from "./core/task-store.js";
|
|
48
52
|
import { initLogger, log } from "./core/logger.js";
|
|
49
|
-
import { RADIO_STATIONS, getCurrentStation, playRadio, stopRadio } from "./core/radio.js";
|
|
53
|
+
import { RADIO_STATIONS, getCurrentStation, getRadioVolume, playRadio, setRadioVolume, stopRadio, } from "./core/radio.js";
|
|
50
54
|
import { enrichProcessPath } from "./core/shell-path.js";
|
|
51
55
|
import { downscaleForPreview, validateVisionImage } from "./utils/image.js";
|
|
52
56
|
import { startServeMode } from "./modes/serve-mode.js";
|
|
@@ -457,6 +461,11 @@ function daemonJson(res, status, body) {
|
|
|
457
461
|
res.end(JSON.stringify(body));
|
|
458
462
|
}
|
|
459
463
|
async function main() {
|
|
464
|
+
// Hidden persistent-worker dispatch must win before strict JSON/server parsing.
|
|
465
|
+
if (process.argv.includes("--subagent-worker")) {
|
|
466
|
+
await runSubagentWorkerMode();
|
|
467
|
+
return;
|
|
468
|
+
}
|
|
460
469
|
// Sub-agent JSON-mode dispatch must win before any sidecar/server setup.
|
|
461
470
|
if (await runJsonModeIfRequested())
|
|
462
471
|
return;
|
|
@@ -502,6 +511,20 @@ async function main() {
|
|
|
502
511
|
// request to its window's session via the `x-gg-session` header (and the
|
|
503
512
|
// `?session=` query for the SSE /events stream).
|
|
504
513
|
const sessions = new Map();
|
|
514
|
+
const memoryStore = new MemoryStore({
|
|
515
|
+
onChange: ({ memories }) => {
|
|
516
|
+
for (const ctx of sessions.values()) {
|
|
517
|
+
ctx.broadcast("memory_change", { count: memories.length });
|
|
518
|
+
}
|
|
519
|
+
},
|
|
520
|
+
});
|
|
521
|
+
const jiwaStore = new JiwaStore({
|
|
522
|
+
onChange: ({ jiwa }) => {
|
|
523
|
+
for (const ctx of sessions.values()) {
|
|
524
|
+
ctx.broadcast("jiwa_change", { count: jiwa.length });
|
|
525
|
+
}
|
|
526
|
+
},
|
|
527
|
+
});
|
|
505
528
|
// XP/rank progress — loaded once per daemon; awards fan out to every window.
|
|
506
529
|
// Each frame is tagged `origin: true` only for the session that earned the
|
|
507
530
|
// XP, so that window alone plays sounds/chips while the rest just re-render.
|
|
@@ -600,7 +623,7 @@ async function main() {
|
|
|
600
623
|
return;
|
|
601
624
|
}
|
|
602
625
|
// ── Daemon-level routes (session lifecycle) ──────────────────────────
|
|
603
|
-
// Create a session for a window: { cwd, sessionPath? } → { sessionId }.
|
|
626
|
+
// Create a session for a window: { mode?, cwd, sessionPath? } → { sessionId }.
|
|
604
627
|
if (method === "POST" && url === "/session") {
|
|
605
628
|
void daemonReadBody(req).then(async (raw) => {
|
|
606
629
|
let body = {};
|
|
@@ -610,15 +633,22 @@ async function main() {
|
|
|
610
633
|
catch {
|
|
611
634
|
/* empty/invalid body → defaults below */
|
|
612
635
|
}
|
|
636
|
+
const mode = body.mode === "chat" ? "chat" : "code";
|
|
637
|
+
const chatAgent = parseChatAgentId(body.chatAgent);
|
|
613
638
|
const sessionCwd = typeof body.cwd === "string" && body.cwd
|
|
614
639
|
? body.cwd
|
|
615
640
|
: (process.env.GG_APP_CWD ?? process.cwd());
|
|
616
641
|
const sessionPath = typeof body.sessionPath === "string" && body.sessionPath ? body.sessionPath : undefined;
|
|
617
642
|
const id = randomUUID();
|
|
618
643
|
try {
|
|
619
|
-
const ctx = await createSession({ auth, paths, progress }, { id, cwd: sessionCwd, sessionPath });
|
|
644
|
+
const ctx = await createSession({ auth, paths, progress, memoryStore, jiwaStore }, { id, mode, chatAgent, cwd: sessionCwd, sessionPath });
|
|
620
645
|
sessions.set(id, ctx);
|
|
621
|
-
log("INFO", "app-sidecar", "session created", {
|
|
646
|
+
log("INFO", "app-sidecar", "session created", {
|
|
647
|
+
id,
|
|
648
|
+
mode,
|
|
649
|
+
chatAgent,
|
|
650
|
+
cwd: sessionCwd,
|
|
651
|
+
});
|
|
622
652
|
daemonJson(res, 200, { sessionId: id });
|
|
623
653
|
}
|
|
624
654
|
catch (err) {
|
|
@@ -681,16 +711,40 @@ async function main() {
|
|
|
681
711
|
process.stdout.write(`GG_APP_LISTENING ${addr.port}\n`);
|
|
682
712
|
log("INFO", "app-sidecar", "daemon listening", { port: String(addr.port), host });
|
|
683
713
|
});
|
|
684
|
-
const
|
|
714
|
+
const shellPid = process.ppid;
|
|
715
|
+
let shuttingDown = false;
|
|
716
|
+
async function shutdown() {
|
|
717
|
+
if (shuttingDown)
|
|
718
|
+
return;
|
|
719
|
+
shuttingDown = true;
|
|
720
|
+
clearInterval(parentWatch);
|
|
685
721
|
// Radio playback is app-wide (one stream across all windows), so it stops
|
|
686
722
|
// at the daemon level, not per session.
|
|
687
723
|
stopRadio();
|
|
688
724
|
await Promise.all([...sessions.values()].map((c) => c.dispose().catch(() => { })));
|
|
689
725
|
server.close();
|
|
690
726
|
process.exit(0);
|
|
691
|
-
}
|
|
727
|
+
}
|
|
692
728
|
process.on("SIGINT", () => void shutdown());
|
|
693
729
|
process.on("SIGTERM", () => void shutdown());
|
|
730
|
+
process.once("exit", stopRadio);
|
|
731
|
+
// Tauri can disappear without delivering a signal (force-quit, dev runner
|
|
732
|
+
// teardown, crash). Detect reparenting or a dead shell so the daemon and its
|
|
733
|
+
// radio player do not survive as audible orphans.
|
|
734
|
+
const parentWatch = setInterval(() => {
|
|
735
|
+
let parentAlive = process.ppid === shellPid;
|
|
736
|
+
if (parentAlive && shellPid > 1) {
|
|
737
|
+
try {
|
|
738
|
+
process.kill(shellPid, 0);
|
|
739
|
+
}
|
|
740
|
+
catch (error) {
|
|
741
|
+
parentAlive = error.code === "EPERM";
|
|
742
|
+
}
|
|
743
|
+
}
|
|
744
|
+
if (!parentAlive)
|
|
745
|
+
void shutdown();
|
|
746
|
+
}, 1_000);
|
|
747
|
+
parentWatch.unref?.();
|
|
694
748
|
}
|
|
695
749
|
/** Nolan's read-only tool allow-list. Excludes every mutating tool (write/edit/
|
|
696
750
|
* bash/tasks/subagent/generate_image/enter_plan/exit_plan/task_*) so the mentor
|
|
@@ -745,8 +799,14 @@ function buildNolanContext(buildSession, cwd, gitBranch, question, workflowComma
|
|
|
745
799
|
});
|
|
746
800
|
}
|
|
747
801
|
async function createProgressManager(agentDir, broadcastAll) {
|
|
748
|
-
// Boot: recovery chain main → backup →
|
|
749
|
-
|
|
802
|
+
// Boot: recovery chain main → backup → coding + chat session rebuild → empty.
|
|
803
|
+
const coderSessionsDir = path.join(agentDir, "sessions");
|
|
804
|
+
let file = await loadProgress({
|
|
805
|
+
rebuild: () => rebuildFromSessions([
|
|
806
|
+
coderSessionsDir,
|
|
807
|
+
...CHAT_AGENT_IDS.map((agentId) => chatAgentSessionsDir(coderSessionsDir, agentId)),
|
|
808
|
+
]),
|
|
809
|
+
});
|
|
750
810
|
// Don't re-celebrate an old levelUp event on boot.
|
|
751
811
|
let lastSeenNonce = file.lastEvent?.nonce ?? null;
|
|
752
812
|
log("INFO", "app-sidecar", "progress loaded", {
|
|
@@ -794,7 +854,7 @@ async function createProgressManager(agentDir, broadcastAll) {
|
|
|
794
854
|
});
|
|
795
855
|
}
|
|
796
856
|
}
|
|
797
|
-
// Watch ~/.
|
|
857
|
+
// Watch ~/.ezcoder (dir watch survives the atomic tmp+rename) for progress.json
|
|
798
858
|
// writes from other daemon processes; debounce, reload read-only, dedupe by nonce.
|
|
799
859
|
let watchDebounce = null;
|
|
800
860
|
try {
|
|
@@ -834,8 +894,10 @@ async function createProgressManager(agentDir, broadcastAll) {
|
|
|
834
894
|
* logger, PATH, shared auth file, and radio live at the daemon level.
|
|
835
895
|
*/
|
|
836
896
|
async function createSession(deps, opts) {
|
|
837
|
-
const { auth, progress } = deps;
|
|
897
|
+
const { auth, progress, memoryStore, jiwaStore } = deps;
|
|
838
898
|
const paths = deps.paths;
|
|
899
|
+
const mode = opts.mode;
|
|
900
|
+
let chatAgent = opts.chatAgent;
|
|
839
901
|
const cwd = opts.cwd;
|
|
840
902
|
// Base host for parsing request-URL query params (value is irrelevant to
|
|
841
903
|
// parsing); the daemon owns the real listen host.
|
|
@@ -938,66 +1000,77 @@ async function createSession(deps, opts) {
|
|
|
938
1000
|
// empty/unset starts a fresh session.
|
|
939
1001
|
const resumeSessionPath = opts.sessionPath;
|
|
940
1002
|
let abort = new AbortController();
|
|
941
|
-
const
|
|
1003
|
+
const baseSessionOptions = {
|
|
942
1004
|
provider,
|
|
943
1005
|
model,
|
|
944
1006
|
cwd,
|
|
945
1007
|
thinkingLevel,
|
|
946
1008
|
sessionId: resumeSessionPath,
|
|
947
1009
|
signal: abort.signal,
|
|
948
|
-
//
|
|
949
|
-
// can't fire until initialize() resolves. Connect MCP in the background so a
|
|
950
|
-
// slow or hanging stdio server (e.g. a first-run `npx -y @playwright/mcp`
|
|
951
|
-
// download) can't delay the sidecar past the webview's startup timeout
|
|
952
|
-
// ("sidecar did not start in time"). Tools attach when the servers come up.
|
|
1010
|
+
// Keep MCP startup off the readiness path in both modes.
|
|
953
1011
|
backgroundMcpConnect: true,
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
1012
|
+
};
|
|
1013
|
+
let session;
|
|
1014
|
+
if (mode === "chat") {
|
|
1015
|
+
session = createChatAgent(chatAgent, {
|
|
1016
|
+
...baseSessionOptions,
|
|
1017
|
+
sessionsDir: paths.sessionsDir,
|
|
1018
|
+
additionalTools: [...buildMemoryTools(memoryStore), ...buildJiwaTools(jiwaStore)],
|
|
1019
|
+
getSystemPromptTail: () => `${memoryStore.renderForPrompt()}\n\n${jiwaStore.renderForPrompt()}`,
|
|
1020
|
+
onAgentChange: async (nextAgent) => {
|
|
1021
|
+
chatAgent = nextAgent;
|
|
1022
|
+
broadcast("chat_agent_change", { chatAgent: nextAgent });
|
|
1023
|
+
await session.persistAppMarker("agent_handoff", { chatAgent: nextAgent }).catch((error) => {
|
|
1024
|
+
log("WARN", "app-sidecar", "agent handoff marker persist failed", {
|
|
1025
|
+
message: error instanceof Error ? error.message : String(error),
|
|
1026
|
+
});
|
|
1027
|
+
});
|
|
1028
|
+
},
|
|
1029
|
+
});
|
|
1030
|
+
}
|
|
1031
|
+
else {
|
|
1032
|
+
session = new AgentSession({
|
|
1033
|
+
...baseSessionOptions,
|
|
1034
|
+
// Plan mode belongs only to the coding agent.
|
|
1035
|
+
onEnterPlan: async (reason) => {
|
|
1036
|
+
// Unattended task runs cannot approve plans; implement directly instead.
|
|
1037
|
+
if (taskRunActive)
|
|
1038
|
+
return false;
|
|
1039
|
+
await session.setPlanMode(true);
|
|
1040
|
+
broadcast("plan_enter", { reason: reason ?? "" });
|
|
1041
|
+
void session.persistAppMarker("plan", { reason: reason ?? "" }).catch(() => { });
|
|
1042
|
+
},
|
|
1043
|
+
onExitPlan: async (planPath) => {
|
|
1044
|
+
if (taskRunActive) {
|
|
1045
|
+
await session.setPlanMode(false);
|
|
1046
|
+
return ("Plan review is unavailable during a task run. Skip review and implement " +
|
|
1047
|
+
"the plan directly now: make the changes, verify them, then mark the task done.");
|
|
1048
|
+
}
|
|
975
1049
|
await session.setPlanMode(false);
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
// Record the submitted plan so the autopilot gate can route this turn
|
|
990
|
-
// into a PLAN review instead of a stale work review (plan mode is
|
|
991
|
-
// already false here, so the gate's planMode check alone never catches
|
|
992
|
-
// a submission). setPendingPlan bumps planGeneration, which invalidates
|
|
993
|
-
// any in-flight Nolan plan review racing a user action.
|
|
994
|
-
setPendingPlan(planPath, content);
|
|
995
|
-
broadcast("plan_exit", { planPath, content });
|
|
996
|
-
return "Plan submitted for user review. Wait for the user to approve, reject, or dismiss it before implementing.";
|
|
997
|
-
},
|
|
998
|
-
});
|
|
1050
|
+
let content;
|
|
1051
|
+
try {
|
|
1052
|
+
content = await fs.readFile(planPath, "utf-8");
|
|
1053
|
+
}
|
|
1054
|
+
catch {
|
|
1055
|
+
content = "";
|
|
1056
|
+
}
|
|
1057
|
+
setPendingPlan(planPath, content);
|
|
1058
|
+
broadcast("plan_exit", { planPath, content });
|
|
1059
|
+
return "Plan submitted for user review. Wait for the user to approve, reject, or dismiss it before implementing.";
|
|
1060
|
+
},
|
|
1061
|
+
});
|
|
1062
|
+
}
|
|
999
1063
|
await session.initialize();
|
|
1000
|
-
|
|
1064
|
+
if (mode === "chat") {
|
|
1065
|
+
const restoredAgent = [...session.getAppMarkers()]
|
|
1066
|
+
.reverse()
|
|
1067
|
+
.find((marker) => marker.kind === "agent_handoff")?.data.chatAgent;
|
|
1068
|
+
if (typeof restoredAgent === "string") {
|
|
1069
|
+
chatAgent = parseChatAgentId(restoredAgent);
|
|
1070
|
+
await switchChatAgent(session, chatAgent, false);
|
|
1071
|
+
}
|
|
1072
|
+
}
|
|
1073
|
+
log("INFO", "app-sidecar", "session ready", { provider, model, mode, chatAgent, cwd });
|
|
1001
1074
|
// Footer extras (context window, git branch, background tasks). The git
|
|
1002
1075
|
// branch is resolved once at startup and refreshed lazily; the context
|
|
1003
1076
|
// window follows the active model.
|
|
@@ -1060,6 +1133,7 @@ async function createSession(deps, opts) {
|
|
|
1060
1133
|
});
|
|
1061
1134
|
session.eventBus.on("model_change", (d) => broadcast("model_change", d));
|
|
1062
1135
|
session.eventBus.on("hook", (d) => broadcast("hook", d));
|
|
1136
|
+
session.eventBus.on("subagent_state", (d) => broadcast("subagent_state", d));
|
|
1063
1137
|
session.eventBus.on("compaction_start", (d) => broadcast("compaction_start", d));
|
|
1064
1138
|
session.eventBus.on("compaction_end", (d) => broadcast("compaction_end", d));
|
|
1065
1139
|
let running = false;
|
|
@@ -1071,7 +1145,7 @@ async function createSession(deps, opts) {
|
|
|
1071
1145
|
// ezcoder-app.json on boot; flipped via POST /autopilot. When on, POST /prompt runs
|
|
1072
1146
|
// runAutopilotCycle after the user's turn settles — Nolan auto-reviews the work
|
|
1073
1147
|
// and drives the review→prompt→review loop.
|
|
1074
|
-
let autopilot = await loadAutopilot(cwd);
|
|
1148
|
+
let autopilot = mode === "code" && (await loadAutopilot(cwd));
|
|
1075
1149
|
// True while an autopilot review is in flight (used to defer nolanAuto model
|
|
1076
1150
|
// switches, like nolanRunning does for chat Nolan, and to drive the spinner).
|
|
1077
1151
|
let autopilotReviewing = false;
|
|
@@ -1139,7 +1213,7 @@ async function createSession(deps, opts) {
|
|
|
1139
1213
|
let nolanRunning = false;
|
|
1140
1214
|
let pendingNolanModel = null;
|
|
1141
1215
|
const nolanToolCallNames = new Map();
|
|
1142
|
-
// Nolan's per-project model override. null → Nolan (chat + autopilot) follows
|
|
1216
|
+
// Nolan's per-project model override. null → Nolan (chat + autopilot) follows EZ
|
|
1143
1217
|
// Coder's model, including live switches (the historical behavior). Set → Nolan
|
|
1144
1218
|
// is pinned to his own model and EZ Coder switches no longer touch him. A
|
|
1145
1219
|
// stale persisted pin (model dropped from the registry / provider logged
|
|
@@ -1149,7 +1223,7 @@ async function createSession(deps, opts) {
|
|
|
1149
1223
|
providerConnected: () => true, // async auth checked below
|
|
1150
1224
|
});
|
|
1151
1225
|
if (nolanModelOverride && !(await auth.hasProviderAuth(nolanModelOverride.provider))) {
|
|
1152
|
-
log("WARN", "app-sidecar", "
|
|
1226
|
+
log("WARN", "app-sidecar", "Nolan model override provider not connected — following EZ Coder", {
|
|
1153
1227
|
provider: nolanModelOverride.provider,
|
|
1154
1228
|
model: nolanModelOverride.model,
|
|
1155
1229
|
});
|
|
@@ -1764,6 +1838,8 @@ async function createSession(deps, opts) {
|
|
|
1764
1838
|
const st = session.getState();
|
|
1765
1839
|
json(res, 200, {
|
|
1766
1840
|
...st,
|
|
1841
|
+
mode,
|
|
1842
|
+
chatAgent,
|
|
1767
1843
|
running,
|
|
1768
1844
|
ready: true,
|
|
1769
1845
|
thinkingLevel: session.getThinkingLevel() ?? null,
|
|
@@ -1779,6 +1855,46 @@ async function createSession(deps, opts) {
|
|
|
1779
1855
|
json(res, 200, progress.snapshot());
|
|
1780
1856
|
return;
|
|
1781
1857
|
}
|
|
1858
|
+
if (method === "GET" && url === "/memories") {
|
|
1859
|
+
void memoryStore
|
|
1860
|
+
.snapshot()
|
|
1861
|
+
.then((snapshot) => json(res, 200, snapshot))
|
|
1862
|
+
.catch((error) => json(res, 500, { error: error instanceof Error ? error.message : String(error) }));
|
|
1863
|
+
return;
|
|
1864
|
+
}
|
|
1865
|
+
if (method === "DELETE" && url.startsWith("/memories/")) {
|
|
1866
|
+
const id = decodeURIComponent(url.slice("/memories/".length));
|
|
1867
|
+
if (!id) {
|
|
1868
|
+
json(res, 400, { error: "memory id is required" });
|
|
1869
|
+
return;
|
|
1870
|
+
}
|
|
1871
|
+
void memoryStore
|
|
1872
|
+
.forget(id)
|
|
1873
|
+
.then(() => memoryStore.snapshot())
|
|
1874
|
+
.then((snapshot) => json(res, 200, snapshot))
|
|
1875
|
+
.catch((error) => json(res, 500, { error: error instanceof Error ? error.message : String(error) }));
|
|
1876
|
+
return;
|
|
1877
|
+
}
|
|
1878
|
+
if (method === "GET" && url === "/jiwa") {
|
|
1879
|
+
void jiwaStore
|
|
1880
|
+
.snapshot()
|
|
1881
|
+
.then((snapshot) => json(res, 200, snapshot))
|
|
1882
|
+
.catch((error) => json(res, 500, { error: error instanceof Error ? error.message : String(error) }));
|
|
1883
|
+
return;
|
|
1884
|
+
}
|
|
1885
|
+
if (method === "DELETE" && url.startsWith("/jiwa/")) {
|
|
1886
|
+
const id = decodeURIComponent(url.slice("/jiwa/".length));
|
|
1887
|
+
if (!id) {
|
|
1888
|
+
json(res, 400, { error: "Jiwa entry id is required" });
|
|
1889
|
+
return;
|
|
1890
|
+
}
|
|
1891
|
+
void jiwaStore
|
|
1892
|
+
.forget(id)
|
|
1893
|
+
.then(() => jiwaStore.snapshot())
|
|
1894
|
+
.then((snapshot) => json(res, 200, snapshot))
|
|
1895
|
+
.catch((error) => json(res, 500, { error: error instanceof Error ? error.message : String(error) }));
|
|
1896
|
+
return;
|
|
1897
|
+
}
|
|
1782
1898
|
if (method === "GET" && (url === "/events" || url.startsWith("/events?"))) {
|
|
1783
1899
|
res.writeHead(200, {
|
|
1784
1900
|
"content-type": "text/event-stream",
|
|
@@ -1794,6 +1910,8 @@ async function createSession(deps, opts) {
|
|
|
1794
1910
|
type: "ready",
|
|
1795
1911
|
data: {
|
|
1796
1912
|
...st,
|
|
1913
|
+
mode,
|
|
1914
|
+
chatAgent,
|
|
1797
1915
|
running,
|
|
1798
1916
|
thinkingLevel: session.getThinkingLevel() ?? null,
|
|
1799
1917
|
supportedThinkingLevels: getSupportedThinkingLevels(st.provider, st.model),
|
|
@@ -1909,7 +2027,36 @@ async function createSession(deps, opts) {
|
|
|
1909
2027
|
json(res, 400, { error: "missing cwd query param" });
|
|
1910
2028
|
return;
|
|
1911
2029
|
}
|
|
1912
|
-
|
|
2030
|
+
const requestedAgent = new URL(url, `http://${host}`).searchParams.get("chatAgent");
|
|
2031
|
+
if (requestedAgent === "all") {
|
|
2032
|
+
void Promise.all(CHAT_AGENT_IDS.map(async (agentId) => {
|
|
2033
|
+
const agentSessions = await listRecentSessions(target, 5, chatAgentSessionsDir(paths.sessionsDir, agentId));
|
|
2034
|
+
return agentSessions.map((item) => ({ ...item, chatAgent: agentId }));
|
|
2035
|
+
}))
|
|
2036
|
+
.then(async (groups) => {
|
|
2037
|
+
const dated = await Promise.all(groups.flat().map(async (item) => ({
|
|
2038
|
+
item,
|
|
2039
|
+
mtime: await fs
|
|
2040
|
+
.stat(item.path)
|
|
2041
|
+
.then((stat) => stat.mtimeMs)
|
|
2042
|
+
.catch(() => 0),
|
|
2043
|
+
})));
|
|
2044
|
+
const recent = dated
|
|
2045
|
+
.sort((left, right) => right.mtime - left.mtime)
|
|
2046
|
+
.slice(0, 5)
|
|
2047
|
+
.map(({ item }) => item);
|
|
2048
|
+
json(res, 200, { sessions: recent });
|
|
2049
|
+
})
|
|
2050
|
+
.catch(() => json(res, 200, { sessions: [] }));
|
|
2051
|
+
return;
|
|
2052
|
+
}
|
|
2053
|
+
// The picker may be served by a sidecar currently running in Chat mode.
|
|
2054
|
+
// An omitted chatAgent always means coding history; chat callers identify
|
|
2055
|
+
// their namespace explicitly (one agent or "all").
|
|
2056
|
+
const sessionsDir = requestedAgent
|
|
2057
|
+
? sessionsDirForChatAgent(paths.sessionsDir, requestedAgent)
|
|
2058
|
+
: paths.sessionsDir;
|
|
2059
|
+
void listRecentSessions(target, 5, sessionsDir)
|
|
1913
2060
|
.then((sessions) => json(res, 200, { sessions }))
|
|
1914
2061
|
.catch(() => json(res, 200, { sessions: [] }));
|
|
1915
2062
|
return;
|
|
@@ -2174,12 +2321,17 @@ async function createSession(deps, opts) {
|
|
|
2174
2321
|
}
|
|
2175
2322
|
// Assistant tool_call blocks: detect sub-agent delegations.
|
|
2176
2323
|
if (msg.role === "assistant" && typeof msg.content !== "string") {
|
|
2177
|
-
const subagentCalls = msg.content.filter((c) => c.type === "tool_call" && c.name === "subagent");
|
|
2324
|
+
const subagentCalls = msg.content.filter((c) => c.type === "tool_call" && (c.name === "subagent" || c.name === "spawn_agent"));
|
|
2178
2325
|
if (subagentCalls.length > 0) {
|
|
2179
2326
|
const agents = subagentCalls.map((c) => {
|
|
2180
2327
|
const result = toolResultMap.get(c.id);
|
|
2181
2328
|
return {
|
|
2182
|
-
agentName:
|
|
2329
|
+
agentName: c.name === "spawn_agent" && typeof c.args?.task_name === "string"
|
|
2330
|
+
? c.args.task_name
|
|
2331
|
+
: typeof c.args?.agent === "string"
|
|
2332
|
+
? c.args.agent
|
|
2333
|
+
: undefined,
|
|
2334
|
+
// Async workers are intentionally non-resumable; restored rows are historical.
|
|
2183
2335
|
status: result?.isError ? "error" : "done",
|
|
2184
2336
|
toolUseCount: 0,
|
|
2185
2337
|
};
|
|
@@ -2211,6 +2363,10 @@ async function createSession(deps, opts) {
|
|
|
2211
2363
|
return;
|
|
2212
2364
|
}
|
|
2213
2365
|
if (method === "GET" && url === "/commands") {
|
|
2366
|
+
if (mode === "chat") {
|
|
2367
|
+
json(res, 200, { commands: [] });
|
|
2368
|
+
return;
|
|
2369
|
+
}
|
|
2214
2370
|
// Workflow commands with agent functionality: built-in prompt templates +
|
|
2215
2371
|
// the user's own `.ezcoder/commands/*.md`. UI commands (model/quit/etc.) are
|
|
2216
2372
|
// handled webview-side and intentionally excluded.
|
|
@@ -2258,7 +2414,7 @@ async function createSession(deps, opts) {
|
|
|
2258
2414
|
// an autopilot cycle is active but between injected runs (build idle,
|
|
2259
2415
|
// Nolan reviewing) so the message never starts a run that collides with
|
|
2260
2416
|
// an injected one on the same session. Attachments are persisted to
|
|
2261
|
-
// .
|
|
2417
|
+
// .ezcoder/uploads first so the queued media rides the same native-block
|
|
2262
2418
|
// path as a non-queued attachment prompt when it drains.
|
|
2263
2419
|
const prepared = attachments.length > 0 ? await prepareAttachments(cwd, attachments) : [];
|
|
2264
2420
|
const count = session.queueMessage(text, prepared);
|
|
@@ -2351,6 +2507,10 @@ async function createSession(deps, opts) {
|
|
|
2351
2507
|
// webview keeps the bubbles separate. The context digest is assembled fresh
|
|
2352
2508
|
// from the BUILD session's transcript each turn (one-way mirror).
|
|
2353
2509
|
if (method === "POST" && url === "/ken/prompt") {
|
|
2510
|
+
if (mode === "chat") {
|
|
2511
|
+
json(res, 404, { error: "Nolan is not available in EZ Chat." });
|
|
2512
|
+
return;
|
|
2513
|
+
}
|
|
2354
2514
|
void readBody(req).then(async (raw) => {
|
|
2355
2515
|
let text;
|
|
2356
2516
|
try {
|
|
@@ -2406,6 +2566,10 @@ async function createSession(deps, opts) {
|
|
|
2406
2566
|
return;
|
|
2407
2567
|
}
|
|
2408
2568
|
if (method === "POST" && url === "/autopilot") {
|
|
2569
|
+
if (mode === "chat") {
|
|
2570
|
+
json(res, 404, { error: "Autopilot is not available in EZ Chat." });
|
|
2571
|
+
return;
|
|
2572
|
+
}
|
|
2409
2573
|
void readBody(req).then(async (raw) => {
|
|
2410
2574
|
let enabled;
|
|
2411
2575
|
try {
|
|
@@ -2464,7 +2628,34 @@ async function createSession(deps, opts) {
|
|
|
2464
2628
|
// duplicate audio across windows (the original per-window goal), now for
|
|
2465
2629
|
// free. (To restore per-window radio, key playback by sessionId.)
|
|
2466
2630
|
if (method === "GET" && url === "/radio") {
|
|
2467
|
-
json(res, 200, {
|
|
2631
|
+
json(res, 200, {
|
|
2632
|
+
stations: RADIO_STATIONS,
|
|
2633
|
+
current: getCurrentStation(),
|
|
2634
|
+
volume: getRadioVolume(),
|
|
2635
|
+
});
|
|
2636
|
+
return;
|
|
2637
|
+
}
|
|
2638
|
+
if (method === "POST" && url === "/radio/volume") {
|
|
2639
|
+
void readBody(req).then((raw) => {
|
|
2640
|
+
let volume;
|
|
2641
|
+
try {
|
|
2642
|
+
volume = Number(JSON.parse(raw).volume);
|
|
2643
|
+
}
|
|
2644
|
+
catch {
|
|
2645
|
+
json(res, 400, { error: "invalid JSON body" });
|
|
2646
|
+
return;
|
|
2647
|
+
}
|
|
2648
|
+
if (!Number.isFinite(volume)) {
|
|
2649
|
+
json(res, 400, { error: "volume must be a number" });
|
|
2650
|
+
return;
|
|
2651
|
+
}
|
|
2652
|
+
const result = setRadioVolume(volume);
|
|
2653
|
+
if (!result.ok) {
|
|
2654
|
+
json(res, 400, { error: result.error ?? "Radio volume failed to update." });
|
|
2655
|
+
return;
|
|
2656
|
+
}
|
|
2657
|
+
json(res, 200, { current: getCurrentStation(), volume: getRadioVolume() });
|
|
2658
|
+
});
|
|
2468
2659
|
return;
|
|
2469
2660
|
}
|
|
2470
2661
|
if (method === "POST" && url === "/radio") {
|
|
@@ -2657,7 +2848,7 @@ async function createSession(deps, opts) {
|
|
|
2657
2848
|
await auth.reload();
|
|
2658
2849
|
await session.switchModel(target.provider, target.id);
|
|
2659
2850
|
// Nolan follows EZ Coder's model only while un-pinned; a user-set Nolan
|
|
2660
|
-
// override survives
|
|
2851
|
+
// override survives EZ Coder model switches untouched.
|
|
2661
2852
|
if (!nolanModelOverride) {
|
|
2662
2853
|
await syncNolanModel(target.provider, target.id);
|
|
2663
2854
|
await syncNolanAutoModel(target.provider, target.id);
|
|
@@ -2690,8 +2881,8 @@ async function createSession(deps, opts) {
|
|
|
2690
2881
|
broadcast("thinking_change", payload);
|
|
2691
2882
|
// Un-pinned Nolan just followed the switch — update his footer chip too.
|
|
2692
2883
|
// When Nolan is pinned, his effective model did not change, so skip the
|
|
2693
|
-
// no-op event (keeps footer/event tests from treating
|
|
2694
|
-
// Nolan switch).
|
|
2884
|
+
// no-op event (keeps footer/event tests from treating an EZ Coder
|
|
2885
|
+
// switch as a Nolan switch).
|
|
2695
2886
|
if (!nolanModelOverride)
|
|
2696
2887
|
broadcast("ken_model_change", nolanStatePayload());
|
|
2697
2888
|
// The new model usually has a different context window — push extras so
|
|
@@ -2723,7 +2914,7 @@ async function createSession(deps, opts) {
|
|
|
2723
2914
|
const st = session.getState();
|
|
2724
2915
|
await syncNolanModel(st.provider, st.model);
|
|
2725
2916
|
await syncNolanAutoModel(st.provider, st.model);
|
|
2726
|
-
log("INFO", "app-sidecar", "
|
|
2917
|
+
log("INFO", "app-sidecar", "Nolan model pin cleared — following EZ Coder", {
|
|
2727
2918
|
provider: st.provider,
|
|
2728
2919
|
model: st.model,
|
|
2729
2920
|
});
|
|
@@ -2821,7 +3012,10 @@ async function createSession(deps, opts) {
|
|
|
2821
3012
|
}
|
|
2822
3013
|
void session
|
|
2823
3014
|
.newSession()
|
|
2824
|
-
.then(() => {
|
|
3015
|
+
.then(async () => {
|
|
3016
|
+
if (mode === "chat") {
|
|
3017
|
+
await session.persistAppMarker("agent_handoff", { chatAgent });
|
|
3018
|
+
}
|
|
2825
3019
|
injectedAutopilotPrompts = [];
|
|
2826
3020
|
clearPendingPlan();
|
|
2827
3021
|
broadcast("session_reset", {});
|
|
@@ -3320,6 +3514,10 @@ async function createSession(deps, opts) {
|
|
|
3320
3514
|
}
|
|
3321
3515
|
return {
|
|
3322
3516
|
id: opts.id,
|
|
3517
|
+
mode,
|
|
3518
|
+
get chatAgent() {
|
|
3519
|
+
return chatAgent;
|
|
3520
|
+
},
|
|
3323
3521
|
cwd,
|
|
3324
3522
|
sessionPath: opts.sessionPath,
|
|
3325
3523
|
session,
|