crewly 1.2.1 → 1.2.4
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/LICENSE +1 -1
- package/README.md +1 -1
- package/config/constants.ts +44 -1
- package/config/index.ts +4 -0
- package/config/roles/architect/prompt.md +7 -5
- package/config/roles/backend-developer/prompt.md +8 -4
- package/config/roles/content-strategist/prompt.md +12 -4
- package/config/roles/designer/prompt.md +8 -4
- package/config/roles/developer/prompt.md +7 -4
- package/config/roles/frontend-developer/prompt.md +8 -4
- package/config/roles/fullstack-dev/prompt.md +8 -4
- package/config/roles/generalist/prompt.md +7 -4
- package/config/roles/ops/prompt.md +7 -4
- package/config/roles/orchestrator/prompt.md +52 -3
- package/config/roles/product-manager/prompt.md +8 -4
- package/config/roles/qa/prompt.md +8 -4
- package/config/roles/qa-engineer/prompt.md +8 -4
- package/config/roles/sales/prompt.md +8 -4
- package/config/roles/support/prompt.md +8 -4
- package/config/roles/team-leader/prompt.md +169 -0
- package/config/roles/team-leader/role.json +13 -0
- package/config/roles/team-leader/tl-addon.md +142 -0
- package/config/roles/tpm/prompt.md +8 -4
- package/config/runtime_scripts/runtime-config.json +7 -0
- package/config/skills/_common/lib.sh +37 -0
- package/config/skills/agent/computer-use/execute.sh +228 -0
- package/config/skills/agent/computer-use/instructions.md +103 -0
- package/config/skills/agent/computer-use/lib/accessibility.sh +292 -0
- package/config/skills/agent/computer-use/lib/applescript.sh +117 -0
- package/config/skills/agent/computer-use/lib/discover.sh +122 -0
- package/config/skills/agent/computer-use/lib/playwright.sh +153 -0
- package/config/skills/agent/computer-use/lib/screenshot.sh +61 -0
- package/config/skills/agent/computer-use/skill.json +29 -0
- package/config/skills/agent/core/accept-task/execute.sh +7 -1
- package/config/skills/agent/core/complete-task/execute.sh +38 -1
- package/config/skills/agent/core/report-status/execute.sh +51 -2
- package/config/skills/agent/desktop-app-control/execute.sh +561 -0
- package/config/skills/agent/desktop-app-control/instructions.md +102 -0
- package/config/skills/agent/desktop-app-control/skill.json +33 -0
- package/config/skills/orchestrator/broadcast-to-org/execute.sh +88 -0
- package/config/skills/orchestrator/broadcast-to-org/instructions.md +51 -0
- package/config/skills/orchestrator/broadcast-to-org/skill.json +20 -0
- package/config/skills/orchestrator/delegate-task/execute.sh +76 -11
- package/config/skills/orchestrator/delegate-task/instructions.md +11 -1
- package/config/skills/orchestrator/handle-agent-failure/execute.sh +45 -0
- package/config/skills/orchestrator/handle-agent-failure/instructions.md +29 -0
- package/config/skills/orchestrator/handle-agent-failure/skill.json +20 -0
- package/config/skills/orchestrator/restart-crewly/instructions.md +9 -2
- package/config/skills/team-leader/_common/lib.sh +4 -0
- package/config/skills/team-leader/aggregate-results/execute.sh +168 -0
- package/config/skills/team-leader/aggregate-results/instructions.md +89 -0
- package/config/skills/team-leader/aggregate-results/skill.json +20 -0
- package/config/skills/team-leader/decompose-goal/execute.sh +86 -0
- package/config/skills/team-leader/decompose-goal/instructions.md +84 -0
- package/config/skills/team-leader/decompose-goal/skill.json +20 -0
- package/config/skills/team-leader/delegate-task/execute.sh +142 -0
- package/config/skills/team-leader/delegate-task/instructions.md +55 -0
- package/config/skills/team-leader/delegate-task/skill.json +20 -0
- package/config/skills/team-leader/handle-failure/execute.sh +119 -0
- package/config/skills/team-leader/handle-failure/instructions.md +93 -0
- package/config/skills/team-leader/handle-failure/skill.json +20 -0
- package/config/skills/team-leader/schedule-check/execute.sh +65 -0
- package/config/skills/team-leader/schedule-check/execute.test.sh +247 -0
- package/config/skills/team-leader/schedule-check/instructions.md +49 -0
- package/config/skills/team-leader/schedule-check/skill.json +20 -0
- package/config/skills/team-leader/start-agent/execute.sh +39 -0
- package/config/skills/team-leader/start-agent/instructions.md +48 -0
- package/config/skills/team-leader/start-agent/skill.json +20 -0
- package/config/skills/team-leader/stop-agent/execute.sh +39 -0
- package/config/skills/team-leader/stop-agent/instructions.md +49 -0
- package/config/skills/team-leader/stop-agent/skill.json +20 -0
- package/config/skills/team-leader/verify-output/execute.sh +296 -0
- package/config/skills/team-leader/verify-output/instructions.md +122 -0
- package/config/skills/team-leader/verify-output/skill.json +20 -0
- package/config/templates/agent-claude-md.md +10 -5
- package/config/templates/core-team/demo-script.md +41 -0
- package/config/templates/core-team/goals.md +20 -0
- package/config/templates/core-team/team.json +22 -0
- package/config/templates/dev-fullstack/template.json +115 -0
- package/config/templates/education-smb/README.md +27 -0
- package/config/templates/education-smb/goals.md +16 -0
- package/config/templates/education-smb/knowledge/docs/content-standards.md +24 -0
- package/config/templates/education-smb/knowledge/docs/education-industry-context.md +13 -0
- package/config/templates/education-smb/knowledge/index.json +24 -0
- package/config/templates/education-smb/learned-patterns.json +16 -0
- package/config/templates/education-smb/quality-gates.yaml +66 -0
- package/config/templates/education-smb/roles/analytics-specialist.md +6 -0
- package/config/templates/education-smb/roles/content-creator.md +6 -0
- package/config/templates/education-smb/roles/curriculum-designer.md +6 -0
- package/config/templates/education-smb/roles/engagement-manager.md +6 -0
- package/config/templates/education-smb/team.json +40 -0
- package/config/templates/education-smb/template.json +26 -0
- package/config/templates/education-smb/workflows/course-content-generation.yaml +44 -0
- package/config/templates/education-smb/workflows/reporting.yaml +31 -0
- package/config/templates/education-smb/workflows/student-communication.yaml +44 -0
- package/config/templates/education-smb/workflows.yaml +40 -0
- package/config/templates/insurance-smb/README.md +28 -0
- package/config/templates/insurance-smb/goals.md +21 -0
- package/config/templates/insurance-smb/knowledge/docs/compliance-checklist.md +28 -0
- package/config/templates/insurance-smb/knowledge/docs/insurance-industry-context.md +23 -0
- package/config/templates/insurance-smb/knowledge/index.json +24 -0
- package/config/templates/insurance-smb/learned-patterns.json +16 -0
- package/config/templates/insurance-smb/quality-gates.yaml +54 -0
- package/config/templates/insurance-smb/roles/claims-processor.md +6 -0
- package/config/templates/insurance-smb/roles/client-manager.md +6 -0
- package/config/templates/insurance-smb/roles/compliance-officer.md +6 -0
- package/config/templates/insurance-smb/roles/marketing-specialist.md +6 -0
- package/config/templates/insurance-smb/roles/policy-analyst.md +6 -0
- package/config/templates/insurance-smb/team.json +48 -0
- package/config/templates/insurance-smb/template.json +26 -0
- package/config/templates/insurance-smb/workflows/claims-processing.yaml +48 -0
- package/config/templates/insurance-smb/workflows.yaml +43 -0
- package/config/templates/research-analysis/template.json +88 -0
- package/config/templates/social-media-ops/template.json +85 -0
- package/config/templates/video-production/template.json +123 -0
- package/dist/backend/backend/src/constants.d.ts +310 -84
- package/dist/backend/backend/src/constants.d.ts.map +1 -1
- package/dist/backend/backend/src/constants.js +303 -89
- package/dist/backend/backend/src/constants.js.map +1 -1
- package/dist/backend/backend/src/controllers/chat/chat.controller.d.ts.map +1 -1
- package/dist/backend/backend/src/controllers/chat/chat.controller.js +86 -26
- package/dist/backend/backend/src/controllers/chat/chat.controller.js.map +1 -1
- package/dist/backend/backend/src/controllers/cloud/auth/auth.controller.d.ts +81 -0
- package/dist/backend/backend/src/controllers/cloud/auth/auth.controller.d.ts.map +1 -0
- package/dist/backend/backend/src/controllers/cloud/auth/auth.controller.js +234 -0
- package/dist/backend/backend/src/controllers/cloud/auth/auth.controller.js.map +1 -0
- package/dist/backend/backend/src/controllers/cloud/auth/auth.routes.d.ts +25 -0
- package/dist/backend/backend/src/controllers/cloud/auth/auth.routes.d.ts.map +1 -0
- package/dist/backend/backend/src/controllers/cloud/auth/auth.routes.js +38 -0
- package/dist/backend/backend/src/controllers/cloud/auth/auth.routes.js.map +1 -0
- package/dist/backend/backend/src/controllers/cloud/cloud-auth.controller.d.ts +69 -0
- package/dist/backend/backend/src/controllers/cloud/cloud-auth.controller.d.ts.map +1 -0
- package/dist/backend/backend/src/controllers/cloud/cloud-auth.controller.js +165 -0
- package/dist/backend/backend/src/controllers/cloud/cloud-auth.controller.js.map +1 -0
- package/dist/backend/backend/src/controllers/cloud/cloud-auth.routes.d.ts +23 -0
- package/dist/backend/backend/src/controllers/cloud/cloud-auth.routes.d.ts.map +1 -0
- package/dist/backend/backend/src/controllers/cloud/cloud-auth.routes.js +32 -0
- package/dist/backend/backend/src/controllers/cloud/cloud-auth.routes.js.map +1 -0
- package/dist/backend/backend/src/controllers/cloud/cloud.controller.d.ts +52 -0
- package/dist/backend/backend/src/controllers/cloud/cloud.controller.d.ts.map +1 -0
- package/dist/backend/backend/src/controllers/cloud/cloud.controller.js +122 -0
- package/dist/backend/backend/src/controllers/cloud/cloud.controller.js.map +1 -0
- package/dist/backend/backend/src/controllers/cloud/cloud.routes.d.ts +21 -0
- package/dist/backend/backend/src/controllers/cloud/cloud.routes.d.ts.map +1 -0
- package/dist/backend/backend/src/controllers/cloud/cloud.routes.js +32 -0
- package/dist/backend/backend/src/controllers/cloud/cloud.routes.js.map +1 -0
- package/dist/backend/backend/src/controllers/cloud/files/cloud-file.controller.d.ts +42 -0
- package/dist/backend/backend/src/controllers/cloud/files/cloud-file.controller.d.ts.map +1 -0
- package/dist/backend/backend/src/controllers/cloud/files/cloud-file.controller.js +138 -0
- package/dist/backend/backend/src/controllers/cloud/files/cloud-file.controller.js.map +1 -0
- package/dist/backend/backend/src/controllers/cloud/files/cloud-file.routes.d.ts +23 -0
- package/dist/backend/backend/src/controllers/cloud/files/cloud-file.routes.d.ts.map +1 -0
- package/dist/backend/backend/src/controllers/cloud/files/cloud-file.routes.js +34 -0
- package/dist/backend/backend/src/controllers/cloud/files/cloud-file.routes.js.map +1 -0
- package/dist/backend/backend/src/controllers/cloud/files/cloud-file.types.d.ts +43 -0
- package/dist/backend/backend/src/controllers/cloud/files/cloud-file.types.d.ts.map +1 -0
- package/dist/backend/backend/src/controllers/cloud/files/cloud-file.types.js +9 -0
- package/dist/backend/backend/src/controllers/cloud/files/cloud-file.types.js.map +1 -0
- package/dist/backend/backend/src/controllers/cloud/files/index.d.ts +7 -0
- package/dist/backend/backend/src/controllers/cloud/files/index.d.ts.map +1 -0
- package/dist/backend/backend/src/controllers/cloud/files/index.js +7 -0
- package/dist/backend/backend/src/controllers/cloud/files/index.js.map +1 -0
- package/dist/backend/backend/src/controllers/cloud/h5/h5-entry.controller.d.ts +47 -0
- package/dist/backend/backend/src/controllers/cloud/h5/h5-entry.controller.d.ts.map +1 -0
- package/dist/backend/backend/src/controllers/cloud/h5/h5-entry.controller.js +131 -0
- package/dist/backend/backend/src/controllers/cloud/h5/h5-entry.controller.js.map +1 -0
- package/dist/backend/backend/src/controllers/cloud/h5/h5-entry.routes.d.ts +23 -0
- package/dist/backend/backend/src/controllers/cloud/h5/h5-entry.routes.d.ts.map +1 -0
- package/dist/backend/backend/src/controllers/cloud/h5/h5-entry.routes.js +30 -0
- package/dist/backend/backend/src/controllers/cloud/h5/h5-entry.routes.js.map +1 -0
- package/dist/backend/backend/src/controllers/cloud/h5/h5-entry.types.d.ts +81 -0
- package/dist/backend/backend/src/controllers/cloud/h5/h5-entry.types.d.ts.map +1 -0
- package/dist/backend/backend/src/controllers/cloud/h5/h5-entry.types.js +85 -0
- package/dist/backend/backend/src/controllers/cloud/h5/h5-entry.types.js.map +1 -0
- package/dist/backend/backend/src/controllers/cloud/h5/index.d.ts +7 -0
- package/dist/backend/backend/src/controllers/cloud/h5/index.d.ts.map +1 -0
- package/dist/backend/backend/src/controllers/cloud/h5/index.js +7 -0
- package/dist/backend/backend/src/controllers/cloud/h5/index.js.map +1 -0
- package/dist/backend/backend/src/controllers/cloud/index.d.ts +14 -0
- package/dist/backend/backend/src/controllers/cloud/index.d.ts.map +1 -0
- package/dist/backend/backend/src/controllers/cloud/index.js +14 -0
- package/dist/backend/backend/src/controllers/cloud/index.js.map +1 -0
- package/dist/backend/backend/src/controllers/cloud/magic-moment/index.d.ts +7 -0
- package/dist/backend/backend/src/controllers/cloud/magic-moment/index.d.ts.map +1 -0
- package/dist/backend/backend/src/controllers/cloud/magic-moment/index.js +7 -0
- package/dist/backend/backend/src/controllers/cloud/magic-moment/index.js.map +1 -0
- package/dist/backend/backend/src/controllers/cloud/magic-moment/magic-moment.controller.d.ts +45 -0
- package/dist/backend/backend/src/controllers/cloud/magic-moment/magic-moment.controller.d.ts.map +1 -0
- package/dist/backend/backend/src/controllers/cloud/magic-moment/magic-moment.controller.js +155 -0
- package/dist/backend/backend/src/controllers/cloud/magic-moment/magic-moment.controller.js.map +1 -0
- package/dist/backend/backend/src/controllers/cloud/magic-moment/magic-moment.routes.d.ts +25 -0
- package/dist/backend/backend/src/controllers/cloud/magic-moment/magic-moment.routes.d.ts.map +1 -0
- package/dist/backend/backend/src/controllers/cloud/magic-moment/magic-moment.routes.js +32 -0
- package/dist/backend/backend/src/controllers/cloud/magic-moment/magic-moment.routes.js.map +1 -0
- package/dist/backend/backend/src/controllers/cloud/relay.controller.d.ts +101 -0
- package/dist/backend/backend/src/controllers/cloud/relay.controller.d.ts.map +1 -0
- package/dist/backend/backend/src/controllers/cloud/relay.controller.js +343 -0
- package/dist/backend/backend/src/controllers/cloud/relay.controller.js.map +1 -0
- package/dist/backend/backend/src/controllers/cloud/relay.routes.d.ts +29 -0
- package/dist/backend/backend/src/controllers/cloud/relay.routes.d.ts.map +1 -0
- package/dist/backend/backend/src/controllers/cloud/relay.routes.js +44 -0
- package/dist/backend/backend/src/controllers/cloud/relay.routes.js.map +1 -0
- package/dist/backend/backend/src/controllers/cloud/tasks/cloud-task.controller.d.ts +49 -0
- package/dist/backend/backend/src/controllers/cloud/tasks/cloud-task.controller.d.ts.map +1 -0
- package/dist/backend/backend/src/controllers/cloud/tasks/cloud-task.controller.js +152 -0
- package/dist/backend/backend/src/controllers/cloud/tasks/cloud-task.controller.js.map +1 -0
- package/dist/backend/backend/src/controllers/cloud/tasks/cloud-task.routes.d.ts +24 -0
- package/dist/backend/backend/src/controllers/cloud/tasks/cloud-task.routes.d.ts.map +1 -0
- package/dist/backend/backend/src/controllers/cloud/tasks/cloud-task.routes.js +34 -0
- package/dist/backend/backend/src/controllers/cloud/tasks/cloud-task.routes.js.map +1 -0
- package/dist/backend/backend/src/controllers/cloud/tasks/cloud-task.types.d.ts +90 -0
- package/dist/backend/backend/src/controllers/cloud/tasks/cloud-task.types.d.ts.map +1 -0
- package/dist/backend/backend/src/controllers/cloud/tasks/cloud-task.types.js +48 -0
- package/dist/backend/backend/src/controllers/cloud/tasks/cloud-task.types.js.map +1 -0
- package/dist/backend/backend/src/controllers/cloud/tasks/index.d.ts +7 -0
- package/dist/backend/backend/src/controllers/cloud/tasks/index.d.ts.map +1 -0
- package/dist/backend/backend/src/controllers/cloud/tasks/index.js +7 -0
- package/dist/backend/backend/src/controllers/cloud/tasks/index.js.map +1 -0
- package/dist/backend/backend/src/controllers/marketplace/index.d.ts +2 -0
- package/dist/backend/backend/src/controllers/marketplace/index.d.ts.map +1 -1
- package/dist/backend/backend/src/controllers/marketplace/index.js +3 -0
- package/dist/backend/backend/src/controllers/marketplace/index.js.map +1 -1
- package/dist/backend/backend/src/controllers/marketplace/marketplace.controller.d.ts +12 -12
- package/dist/backend/backend/src/controllers/marketplace/marketplace.controller.d.ts.map +1 -1
- package/dist/backend/backend/src/controllers/marketplace/marketplace.controller.js +1 -18
- package/dist/backend/backend/src/controllers/marketplace/marketplace.controller.js.map +1 -1
- package/dist/backend/backend/src/controllers/marketplace/marketplace.routes.d.ts.map +1 -1
- package/dist/backend/backend/src/controllers/marketplace/marketplace.routes.js +3 -0
- package/dist/backend/backend/src/controllers/marketplace/marketplace.routes.js.map +1 -1
- package/dist/backend/backend/src/controllers/marketplace/template-marketplace.controller.d.ts +111 -0
- package/dist/backend/backend/src/controllers/marketplace/template-marketplace.controller.d.ts.map +1 -0
- package/dist/backend/backend/src/controllers/marketplace/template-marketplace.controller.js +220 -0
- package/dist/backend/backend/src/controllers/marketplace/template-marketplace.controller.js.map +1 -0
- package/dist/backend/backend/src/controllers/marketplace/template-marketplace.routes.d.ts +33 -0
- package/dist/backend/backend/src/controllers/marketplace/template-marketplace.routes.d.ts.map +1 -0
- package/dist/backend/backend/src/controllers/marketplace/template-marketplace.routes.js +50 -0
- package/dist/backend/backend/src/controllers/marketplace/template-marketplace.routes.js.map +1 -0
- package/dist/backend/backend/src/controllers/messaging/messenger.routes.d.ts.map +1 -1
- package/dist/backend/backend/src/controllers/messaging/messenger.routes.js +4 -1
- package/dist/backend/backend/src/controllers/messaging/messenger.routes.js.map +1 -1
- package/dist/backend/backend/src/controllers/monitoring/terminal.controller.d.ts.map +1 -1
- package/dist/backend/backend/src/controllers/monitoring/terminal.controller.js +18 -2
- package/dist/backend/backend/src/controllers/monitoring/terminal.controller.js.map +1 -1
- package/dist/backend/backend/src/controllers/payment/index.d.ts +7 -0
- package/dist/backend/backend/src/controllers/payment/index.d.ts.map +1 -0
- package/dist/backend/backend/src/controllers/payment/index.js +7 -0
- package/dist/backend/backend/src/controllers/payment/index.js.map +1 -0
- package/dist/backend/backend/src/controllers/payment/payment.controller.d.ts +57 -0
- package/dist/backend/backend/src/controllers/payment/payment.controller.d.ts.map +1 -0
- package/dist/backend/backend/src/controllers/payment/payment.controller.js +136 -0
- package/dist/backend/backend/src/controllers/payment/payment.controller.js.map +1 -0
- package/dist/backend/backend/src/controllers/payment/payment.routes.d.ts +27 -0
- package/dist/backend/backend/src/controllers/payment/payment.routes.d.ts.map +1 -0
- package/dist/backend/backend/src/controllers/payment/payment.routes.js +38 -0
- package/dist/backend/backend/src/controllers/payment/payment.routes.js.map +1 -0
- package/dist/backend/backend/src/controllers/payment/payment.types.d.ts +109 -0
- package/dist/backend/backend/src/controllers/payment/payment.types.d.ts.map +1 -0
- package/dist/backend/backend/src/controllers/payment/payment.types.js +54 -0
- package/dist/backend/backend/src/controllers/payment/payment.types.js.map +1 -0
- package/dist/backend/backend/src/controllers/request-types.d.ts +34 -5
- package/dist/backend/backend/src/controllers/request-types.d.ts.map +1 -1
- package/dist/backend/backend/src/controllers/session/session.controller.d.ts +14 -0
- package/dist/backend/backend/src/controllers/session/session.controller.d.ts.map +1 -1
- package/dist/backend/backend/src/controllers/session/session.controller.js +48 -0
- package/dist/backend/backend/src/controllers/session/session.controller.js.map +1 -1
- package/dist/backend/backend/src/controllers/session/session.routes.d.ts.map +1 -1
- package/dist/backend/backend/src/controllers/session/session.routes.js +3 -1
- package/dist/backend/backend/src/controllers/session/session.routes.js.map +1 -1
- package/dist/backend/backend/src/controllers/system/scheduler.controller.d.ts.map +1 -1
- package/dist/backend/backend/src/controllers/system/scheduler.controller.js +4 -3
- package/dist/backend/backend/src/controllers/system/scheduler.controller.js.map +1 -1
- package/dist/backend/backend/src/controllers/system/system.controller.d.ts.map +1 -1
- package/dist/backend/backend/src/controllers/system/system.controller.js +13 -15
- package/dist/backend/backend/src/controllers/system/system.controller.js.map +1 -1
- package/dist/backend/backend/src/controllers/task-management/assignments.controller.d.ts.map +1 -1
- package/dist/backend/backend/src/controllers/task-management/assignments.controller.js.map +1 -1
- package/dist/backend/backend/src/controllers/task-management/task-management.controller.d.ts.map +1 -1
- package/dist/backend/backend/src/controllers/task-management/task-management.controller.js +40 -4
- package/dist/backend/backend/src/controllers/task-management/task-management.controller.js.map +1 -1
- package/dist/backend/backend/src/controllers/task-management/tasks.controller.js.map +1 -1
- package/dist/backend/backend/src/controllers/team/team.controller.d.ts.map +1 -1
- package/dist/backend/backend/src/controllers/team/team.controller.js +259 -13
- package/dist/backend/backend/src/controllers/team/team.controller.js.map +1 -1
- package/dist/backend/backend/src/controllers/template/index.d.ts +8 -0
- package/dist/backend/backend/src/controllers/template/index.d.ts.map +1 -0
- package/dist/backend/backend/src/controllers/template/index.js +8 -0
- package/dist/backend/backend/src/controllers/template/index.js.map +1 -0
- package/dist/backend/backend/src/controllers/template/template.controller.d.ts +63 -0
- package/dist/backend/backend/src/controllers/template/template.controller.d.ts.map +1 -0
- package/dist/backend/backend/src/controllers/template/template.controller.js +112 -0
- package/dist/backend/backend/src/controllers/template/template.controller.js.map +1 -0
- package/dist/backend/backend/src/controllers/template/template.routes.d.ts +24 -0
- package/dist/backend/backend/src/controllers/template/template.routes.d.ts.map +1 -0
- package/dist/backend/backend/src/controllers/template/template.routes.js +33 -0
- package/dist/backend/backend/src/controllers/template/template.routes.js.map +1 -0
- package/dist/backend/backend/src/index.d.ts.map +1 -1
- package/dist/backend/backend/src/index.js +105 -13
- package/dist/backend/backend/src/index.js.map +1 -1
- package/dist/backend/backend/src/middleware/agent-heartbeat.middleware.js +3 -3
- package/dist/backend/backend/src/middleware/agent-heartbeat.middleware.js.map +1 -1
- package/dist/backend/backend/src/models/Team.d.ts +5 -0
- package/dist/backend/backend/src/models/Team.d.ts.map +1 -1
- package/dist/backend/backend/src/models/Team.js +24 -0
- package/dist/backend/backend/src/models/Team.js.map +1 -1
- package/dist/backend/backend/src/routes/api.routes.d.ts.map +1 -1
- package/dist/backend/backend/src/routes/api.routes.js +21 -0
- package/dist/backend/backend/src/routes/api.routes.js.map +1 -1
- package/dist/backend/backend/src/services/agent/agent-registration.service.d.ts +3 -19
- package/dist/backend/backend/src/services/agent/agent-registration.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/agent/agent-registration.service.js +274 -398
- package/dist/backend/backend/src/services/agent/agent-registration.service.js.map +1 -1
- package/dist/backend/backend/src/services/agent/claude-runtime.service.d.ts +7 -1
- package/dist/backend/backend/src/services/agent/claude-runtime.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/agent/claude-runtime.service.js +11 -2
- package/dist/backend/backend/src/services/agent/claude-runtime.service.js.map +1 -1
- package/dist/backend/backend/src/services/agent/gemini-runtime.service.d.ts +2 -1
- package/dist/backend/backend/src/services/agent/gemini-runtime.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/agent/gemini-runtime.service.js +38 -51
- package/dist/backend/backend/src/services/agent/gemini-runtime.service.js.map +1 -1
- package/dist/backend/backend/src/services/agent/oauth-relogin-monitor.service.d.ts +216 -0
- package/dist/backend/backend/src/services/agent/oauth-relogin-monitor.service.d.ts.map +1 -0
- package/dist/backend/backend/src/services/agent/oauth-relogin-monitor.service.js +496 -0
- package/dist/backend/backend/src/services/agent/oauth-relogin-monitor.service.js.map +1 -0
- package/dist/backend/backend/src/services/agent/openhands-runtime.service.d.ts +70 -0
- package/dist/backend/backend/src/services/agent/openhands-runtime.service.d.ts.map +1 -0
- package/dist/backend/backend/src/services/agent/openhands-runtime.service.js +131 -0
- package/dist/backend/backend/src/services/agent/openhands-runtime.service.js.map +1 -0
- package/dist/backend/backend/src/services/agent/pty-activity-tracker.service.d.ts +21 -1
- package/dist/backend/backend/src/services/agent/pty-activity-tracker.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/agent/pty-activity-tracker.service.js +32 -1
- package/dist/backend/backend/src/services/agent/pty-activity-tracker.service.js.map +1 -1
- package/dist/backend/backend/src/services/agent/runtime-exit-monitor.service.d.ts +77 -3
- package/dist/backend/backend/src/services/agent/runtime-exit-monitor.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/agent/runtime-exit-monitor.service.js +281 -30
- package/dist/backend/backend/src/services/agent/runtime-exit-monitor.service.js.map +1 -1
- package/dist/backend/backend/src/services/agent/runtime-service.factory.d.ts.map +1 -1
- package/dist/backend/backend/src/services/agent/runtime-service.factory.js +9 -0
- package/dist/backend/backend/src/services/agent/runtime-service.factory.js.map +1 -1
- package/dist/backend/backend/src/services/ai/prompt-builder.service.d.ts +49 -2
- package/dist/backend/backend/src/services/ai/prompt-builder.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/ai/prompt-builder.service.js +124 -2
- package/dist/backend/backend/src/services/ai/prompt-builder.service.js.map +1 -1
- package/dist/backend/backend/src/services/chat/chat.service.d.ts +10 -2
- package/dist/backend/backend/src/services/chat/chat.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/chat/chat.service.js +49 -8
- package/dist/backend/backend/src/services/chat/chat.service.js.map +1 -1
- package/dist/backend/backend/src/services/cloud/auth/auth.service.d.ts +174 -0
- package/dist/backend/backend/src/services/cloud/auth/auth.service.d.ts.map +1 -0
- package/dist/backend/backend/src/services/cloud/auth/auth.service.js +402 -0
- package/dist/backend/backend/src/services/cloud/auth/auth.service.js.map +1 -0
- package/dist/backend/backend/src/services/cloud/auth/auth.types.d.ts +110 -0
- package/dist/backend/backend/src/services/cloud/auth/auth.types.d.ts.map +1 -0
- package/dist/backend/backend/src/services/cloud/auth/auth.types.js +54 -0
- package/dist/backend/backend/src/services/cloud/auth/auth.types.js.map +1 -0
- package/dist/backend/backend/src/services/cloud/auth/auth.utils.d.ts +36 -0
- package/dist/backend/backend/src/services/cloud/auth/auth.utils.d.ts.map +1 -0
- package/dist/backend/backend/src/services/cloud/auth/auth.utils.js +31 -0
- package/dist/backend/backend/src/services/cloud/auth/auth.utils.js.map +1 -0
- package/dist/backend/backend/src/services/cloud/auth/jwt-auth.middleware.d.ts +47 -0
- package/dist/backend/backend/src/services/cloud/auth/jwt-auth.middleware.d.ts.map +1 -0
- package/dist/backend/backend/src/services/cloud/auth/jwt-auth.middleware.js +116 -0
- package/dist/backend/backend/src/services/cloud/auth/jwt-auth.middleware.js.map +1 -0
- package/dist/backend/backend/src/services/cloud/auth/supabase-auth.middleware.d.ts +61 -0
- package/dist/backend/backend/src/services/cloud/auth/supabase-auth.middleware.d.ts.map +1 -0
- package/dist/backend/backend/src/services/cloud/auth/supabase-auth.middleware.js +203 -0
- package/dist/backend/backend/src/services/cloud/auth/supabase-auth.middleware.js.map +1 -0
- package/dist/backend/backend/src/services/cloud/cloud-auth.middleware.d.ts +46 -0
- package/dist/backend/backend/src/services/cloud/cloud-auth.middleware.d.ts.map +1 -0
- package/dist/backend/backend/src/services/cloud/cloud-auth.middleware.js +95 -0
- package/dist/backend/backend/src/services/cloud/cloud-auth.middleware.js.map +1 -0
- package/dist/backend/backend/src/services/cloud/cloud-auth.service.d.ts +136 -0
- package/dist/backend/backend/src/services/cloud/cloud-auth.service.d.ts.map +1 -0
- package/dist/backend/backend/src/services/cloud/cloud-auth.service.js +204 -0
- package/dist/backend/backend/src/services/cloud/cloud-auth.service.js.map +1 -0
- package/dist/backend/backend/src/services/cloud/cloud-client.service.d.ts +179 -0
- package/dist/backend/backend/src/services/cloud/cloud-client.service.d.ts.map +1 -0
- package/dist/backend/backend/src/services/cloud/cloud-client.service.js +237 -0
- package/dist/backend/backend/src/services/cloud/cloud-client.service.js.map +1 -0
- package/dist/backend/backend/src/services/cloud/cloud-file.service.d.ts +97 -0
- package/dist/backend/backend/src/services/cloud/cloud-file.service.d.ts.map +1 -0
- package/dist/backend/backend/src/services/cloud/cloud-file.service.js +184 -0
- package/dist/backend/backend/src/services/cloud/cloud-file.service.js.map +1 -0
- package/dist/backend/backend/src/services/cloud/cloud-image-analysis.service.d.ts +114 -0
- package/dist/backend/backend/src/services/cloud/cloud-image-analysis.service.d.ts.map +1 -0
- package/dist/backend/backend/src/services/cloud/cloud-image-analysis.service.js +196 -0
- package/dist/backend/backend/src/services/cloud/cloud-image-analysis.service.js.map +1 -0
- package/dist/backend/backend/src/services/cloud/cloud-task-processor.service.d.ts +118 -0
- package/dist/backend/backend/src/services/cloud/cloud-task-processor.service.d.ts.map +1 -0
- package/dist/backend/backend/src/services/cloud/cloud-task-processor.service.js +322 -0
- package/dist/backend/backend/src/services/cloud/cloud-task-processor.service.js.map +1 -0
- package/dist/backend/backend/src/services/cloud/cloud-task.service.d.ts +115 -0
- package/dist/backend/backend/src/services/cloud/cloud-task.service.d.ts.map +1 -0
- package/dist/backend/backend/src/services/cloud/cloud-task.service.js +265 -0
- package/dist/backend/backend/src/services/cloud/cloud-task.service.js.map +1 -0
- package/dist/backend/backend/src/services/cloud/relay-client.service.d.ts +175 -0
- package/dist/backend/backend/src/services/cloud/relay-client.service.d.ts.map +1 -0
- package/dist/backend/backend/src/services/cloud/relay-client.service.js +392 -0
- package/dist/backend/backend/src/services/cloud/relay-client.service.js.map +1 -0
- package/dist/backend/backend/src/services/cloud/relay-crypto.service.d.ts +87 -0
- package/dist/backend/backend/src/services/cloud/relay-crypto.service.d.ts.map +1 -0
- package/dist/backend/backend/src/services/cloud/relay-crypto.service.js +140 -0
- package/dist/backend/backend/src/services/cloud/relay-crypto.service.js.map +1 -0
- package/dist/backend/backend/src/services/cloud/relay-server.service.d.ts +183 -0
- package/dist/backend/backend/src/services/cloud/relay-server.service.d.ts.map +1 -0
- package/dist/backend/backend/src/services/cloud/relay-server.service.js +523 -0
- package/dist/backend/backend/src/services/cloud/relay-server.service.js.map +1 -0
- package/dist/backend/backend/src/services/cloud/relay.types.d.ts +170 -0
- package/dist/backend/backend/src/services/cloud/relay.types.d.ts.map +1 -0
- package/dist/backend/backend/src/services/cloud/relay.types.js +69 -0
- package/dist/backend/backend/src/services/cloud/relay.types.js.map +1 -0
- package/dist/backend/backend/src/services/continuation/patterns/idle-patterns.d.ts +9 -1
- package/dist/backend/backend/src/services/continuation/patterns/idle-patterns.d.ts.map +1 -1
- package/dist/backend/backend/src/services/continuation/patterns/idle-patterns.js +18 -4
- package/dist/backend/backend/src/services/continuation/patterns/idle-patterns.js.map +1 -1
- package/dist/backend/backend/src/services/core/env.config.d.ts +147 -0
- package/dist/backend/backend/src/services/core/env.config.d.ts.map +1 -0
- package/dist/backend/backend/src/services/core/env.config.js +226 -0
- package/dist/backend/backend/src/services/core/env.config.js.map +1 -0
- package/dist/backend/backend/src/services/core/storage.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/core/storage.service.js +5 -0
- package/dist/backend/backend/src/services/core/storage.service.js.map +1 -1
- package/dist/backend/backend/src/services/event-bus/event-bus.service.d.ts +20 -7
- package/dist/backend/backend/src/services/event-bus/event-bus.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/event-bus/event-bus.service.js +35 -31
- package/dist/backend/backend/src/services/event-bus/event-bus.service.js.map +1 -1
- package/dist/backend/backend/src/services/hierarchy/hierarchy-escalation.service.d.ts +160 -0
- package/dist/backend/backend/src/services/hierarchy/hierarchy-escalation.service.d.ts.map +1 -0
- package/dist/backend/backend/src/services/hierarchy/hierarchy-escalation.service.js +261 -0
- package/dist/backend/backend/src/services/hierarchy/hierarchy-escalation.service.js.map +1 -0
- package/dist/backend/backend/src/services/hierarchy/hierarchy-reporting.service.d.ts +161 -0
- package/dist/backend/backend/src/services/hierarchy/hierarchy-reporting.service.d.ts.map +1 -0
- package/dist/backend/backend/src/services/hierarchy/hierarchy-reporting.service.js +276 -0
- package/dist/backend/backend/src/services/hierarchy/hierarchy-reporting.service.js.map +1 -0
- package/dist/backend/backend/src/services/marketplace/index.d.ts +1 -0
- package/dist/backend/backend/src/services/marketplace/index.d.ts.map +1 -1
- package/dist/backend/backend/src/services/marketplace/index.js +2 -0
- package/dist/backend/backend/src/services/marketplace/index.js.map +1 -1
- package/dist/backend/backend/src/services/marketplace/marketplace.service.js +2 -2
- package/dist/backend/backend/src/services/marketplace/template-marketplace.service.d.ts +149 -0
- package/dist/backend/backend/src/services/marketplace/template-marketplace.service.d.ts.map +1 -0
- package/dist/backend/backend/src/services/marketplace/template-marketplace.service.js +500 -0
- package/dist/backend/backend/src/services/marketplace/template-marketplace.service.js.map +1 -0
- package/dist/backend/backend/src/services/mcp-server.js +1 -1
- package/dist/backend/backend/src/services/mcp-server.js.map +1 -1
- package/dist/backend/backend/src/services/messaging/adapters/google-chat-messenger.adapter.d.ts +90 -0
- package/dist/backend/backend/src/services/messaging/adapters/google-chat-messenger.adapter.d.ts.map +1 -0
- package/dist/backend/backend/src/services/messaging/adapters/google-chat-messenger.adapter.js +233 -0
- package/dist/backend/backend/src/services/messaging/adapters/google-chat-messenger.adapter.js.map +1 -0
- package/dist/backend/backend/src/services/messaging/messenger-adapter.interface.d.ts +1 -1
- package/dist/backend/backend/src/services/messaging/messenger-adapter.interface.d.ts.map +1 -1
- package/dist/backend/backend/src/services/messaging/queue-processor.service.js +1 -1
- package/dist/backend/backend/src/services/messaging/queue-processor.service.js.map +1 -1
- package/dist/backend/backend/src/services/monitoring/activity-monitor.service.d.ts +28 -4
- package/dist/backend/backend/src/services/monitoring/activity-monitor.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/monitoring/activity-monitor.service.js +113 -60
- package/dist/backend/backend/src/services/monitoring/activity-monitor.service.js.map +1 -1
- package/dist/backend/backend/src/services/orchestrator/orchestrator-heartbeat-monitor.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/orchestrator/orchestrator-heartbeat-monitor.service.js +29 -8
- package/dist/backend/backend/src/services/orchestrator/orchestrator-heartbeat-monitor.service.js.map +1 -1
- package/dist/backend/backend/src/services/payment/magic-moment.service.d.ts +69 -0
- package/dist/backend/backend/src/services/payment/magic-moment.service.d.ts.map +1 -0
- package/dist/backend/backend/src/services/payment/magic-moment.service.js +158 -0
- package/dist/backend/backend/src/services/payment/magic-moment.service.js.map +1 -0
- package/dist/backend/backend/src/services/payment/magic-moment.types.d.ts +95 -0
- package/dist/backend/backend/src/services/payment/magic-moment.types.d.ts.map +1 -0
- package/dist/backend/backend/src/services/payment/magic-moment.types.js +91 -0
- package/dist/backend/backend/src/services/payment/magic-moment.types.js.map +1 -0
- package/dist/backend/backend/src/services/payment/stripe.service.d.ts +122 -0
- package/dist/backend/backend/src/services/payment/stripe.service.d.ts.map +1 -0
- package/dist/backend/backend/src/services/payment/stripe.service.js +403 -0
- package/dist/backend/backend/src/services/payment/stripe.service.js.map +1 -0
- package/dist/backend/backend/src/services/plugin/index.d.ts +9 -0
- package/dist/backend/backend/src/services/plugin/index.d.ts.map +1 -0
- package/dist/backend/backend/src/services/plugin/index.js +8 -0
- package/dist/backend/backend/src/services/plugin/index.js.map +1 -0
- package/dist/backend/backend/src/services/plugin/plugin.service.d.ts +102 -0
- package/dist/backend/backend/src/services/plugin/plugin.service.d.ts.map +1 -0
- package/dist/backend/backend/src/services/plugin/plugin.service.js +179 -0
- package/dist/backend/backend/src/services/plugin/plugin.service.js.map +1 -0
- package/dist/backend/backend/src/services/plugin/plugin.types.d.ts +88 -0
- package/dist/backend/backend/src/services/plugin/plugin.types.d.ts.map +1 -0
- package/dist/backend/backend/src/services/plugin/plugin.types.js +17 -0
- package/dist/backend/backend/src/services/plugin/plugin.types.js.map +1 -0
- package/dist/backend/backend/src/services/project/task-tracking.service.d.ts +17 -0
- package/dist/backend/backend/src/services/project/task-tracking.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/project/task-tracking.service.js +63 -0
- package/dist/backend/backend/src/services/project/task-tracking.service.js.map +1 -1
- package/dist/backend/backend/src/services/session/pty/pty-session-backend.js +1 -1
- package/dist/backend/backend/src/services/session/pty/pty-session-backend.js.map +1 -1
- package/dist/backend/backend/src/services/session/session-command-helper.d.ts +14 -0
- package/dist/backend/backend/src/services/session/session-command-helper.d.ts.map +1 -1
- package/dist/backend/backend/src/services/session/session-command-helper.js +70 -4
- package/dist/backend/backend/src/services/session/session-command-helper.js.map +1 -1
- package/dist/backend/backend/src/services/settings/settings.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/settings/settings.service.js +1 -0
- package/dist/backend/backend/src/services/settings/settings.service.js.map +1 -1
- package/dist/backend/backend/src/services/slack/slack-orchestrator-bridge.d.ts.map +1 -1
- package/dist/backend/backend/src/services/slack/slack-orchestrator-bridge.js +15 -5
- package/dist/backend/backend/src/services/slack/slack-orchestrator-bridge.js.map +1 -1
- package/dist/backend/backend/src/services/template/template.service.d.ts +153 -0
- package/dist/backend/backend/src/services/template/template.service.d.ts.map +1 -0
- package/dist/backend/backend/src/services/template/template.service.js +372 -0
- package/dist/backend/backend/src/services/template/template.service.js.map +1 -0
- package/dist/backend/backend/src/services/workflow/scheduler.service.d.ts +51 -0
- package/dist/backend/backend/src/services/workflow/scheduler.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/workflow/scheduler.service.js +118 -2
- package/dist/backend/backend/src/services/workflow/scheduler.service.js.map +1 -1
- package/dist/backend/backend/src/types/chat.types.d.ts +39 -1
- package/dist/backend/backend/src/types/chat.types.d.ts.map +1 -1
- package/dist/backend/backend/src/types/chat.types.js +45 -2
- package/dist/backend/backend/src/types/chat.types.js.map +1 -1
- package/dist/backend/backend/src/types/event-bus.types.d.ts +14 -2
- package/dist/backend/backend/src/types/event-bus.types.d.ts.map +1 -1
- package/dist/backend/backend/src/types/event-bus.types.js +15 -0
- package/dist/backend/backend/src/types/event-bus.types.js.map +1 -1
- package/dist/backend/backend/src/types/hierarchy-message.types.d.ts +101 -0
- package/dist/backend/backend/src/types/hierarchy-message.types.d.ts.map +1 -0
- package/dist/backend/backend/src/types/hierarchy-message.types.js +15 -0
- package/dist/backend/backend/src/types/hierarchy-message.types.js.map +1 -0
- package/dist/backend/backend/src/types/index.d.ts +54 -4
- package/dist/backend/backend/src/types/index.d.ts.map +1 -1
- package/dist/backend/backend/src/types/index.js.map +1 -1
- package/dist/backend/backend/src/types/marketplace.types.d.ts +99 -0
- package/dist/backend/backend/src/types/marketplace.types.d.ts.map +1 -1
- package/dist/backend/backend/src/types/settings.types.d.ts +1 -1
- package/dist/backend/backend/src/types/settings.types.d.ts.map +1 -1
- package/dist/backend/backend/src/types/settings.types.js +4 -0
- package/dist/backend/backend/src/types/settings.types.js.map +1 -1
- package/dist/backend/backend/src/types/task-tracking.types.d.ts +79 -1
- package/dist/backend/backend/src/types/task-tracking.types.d.ts.map +1 -1
- package/dist/backend/backend/src/types/task-tracking.types.js.map +1 -1
- package/dist/backend/backend/src/types/team-template.types.d.ts +166 -0
- package/dist/backend/backend/src/types/team-template.types.d.ts.map +1 -0
- package/dist/backend/backend/src/types/team-template.types.js +139 -0
- package/dist/backend/backend/src/types/team-template.types.js.map +1 -0
- package/dist/backend/backend/src/utils/async-handler.d.ts +20 -0
- package/dist/backend/backend/src/utils/async-handler.d.ts.map +1 -0
- package/dist/backend/backend/src/utils/async-handler.js +29 -0
- package/dist/backend/backend/src/utils/async-handler.js.map +1 -0
- package/dist/backend/backend/src/utils/defaultPrompts.d.ts +4 -4
- package/dist/backend/backend/src/utils/defaultPrompts.d.ts.map +1 -1
- package/dist/backend/backend/src/utils/defaultPrompts.js +16 -0
- package/dist/backend/backend/src/utils/defaultPrompts.js.map +1 -1
- package/dist/backend/backend/src/utils/gemini-trusted-folders.d.ts +43 -0
- package/dist/backend/backend/src/utils/gemini-trusted-folders.d.ts.map +1 -0
- package/dist/backend/backend/src/utils/gemini-trusted-folders.js +94 -0
- package/dist/backend/backend/src/utils/gemini-trusted-folders.js.map +1 -0
- package/dist/backend/backend/src/utils/message-serializer.d.ts +74 -0
- package/dist/backend/backend/src/utils/message-serializer.d.ts.map +1 -0
- package/dist/backend/backend/src/utils/message-serializer.js +380 -0
- package/dist/backend/backend/src/utils/message-serializer.js.map +1 -0
- package/dist/backend/backend/src/utils/terminal-output.utils.d.ts +2 -1
- package/dist/backend/backend/src/utils/terminal-output.utils.d.ts.map +1 -1
- package/dist/backend/backend/src/utils/terminal-output.utils.js +2 -28
- package/dist/backend/backend/src/utils/terminal-output.utils.js.map +1 -1
- package/dist/backend/backend/src/utils/terminal-string-ops.d.ts +183 -0
- package/dist/backend/backend/src/utils/terminal-string-ops.d.ts.map +1 -0
- package/dist/backend/backend/src/utils/terminal-string-ops.js +726 -0
- package/dist/backend/backend/src/utils/terminal-string-ops.js.map +1 -0
- package/dist/backend/backend/src/websocket/terminal.gateway.d.ts.map +1 -1
- package/dist/backend/backend/src/websocket/terminal.gateway.js +22 -27
- package/dist/backend/backend/src/websocket/terminal.gateway.js.map +1 -1
- package/dist/backend/config/constants.d.ts +40 -1
- package/dist/backend/config/constants.d.ts.map +1 -1
- package/dist/backend/config/constants.js +41 -1
- package/dist/backend/config/constants.js.map +1 -1
- package/dist/backend/config/index.d.ts +2 -2
- package/dist/backend/config/index.d.ts.map +1 -1
- package/dist/backend/config/index.js +2 -2
- package/dist/backend/config/index.js.map +1 -1
- package/dist/cli/backend/src/constants.d.ts +310 -84
- package/dist/cli/backend/src/constants.d.ts.map +1 -1
- package/dist/cli/backend/src/constants.js +303 -89
- package/dist/cli/backend/src/constants.js.map +1 -1
- package/dist/cli/backend/src/models/Team.d.ts +5 -0
- package/dist/cli/backend/src/models/Team.d.ts.map +1 -1
- package/dist/cli/backend/src/models/Team.js +24 -0
- package/dist/cli/backend/src/models/Team.js.map +1 -1
- package/dist/cli/backend/src/services/core/storage.service.d.ts.map +1 -1
- package/dist/cli/backend/src/services/core/storage.service.js +5 -0
- package/dist/cli/backend/src/services/core/storage.service.js.map +1 -1
- package/dist/cli/backend/src/services/mcp-server.js +1 -1
- package/dist/cli/backend/src/services/mcp-server.js.map +1 -1
- package/dist/cli/backend/src/types/chat.types.d.ts +39 -1
- package/dist/cli/backend/src/types/chat.types.d.ts.map +1 -1
- package/dist/cli/backend/src/types/chat.types.js +45 -2
- package/dist/cli/backend/src/types/chat.types.js.map +1 -1
- package/dist/cli/backend/src/types/index.d.ts +54 -4
- package/dist/cli/backend/src/types/index.d.ts.map +1 -1
- package/dist/cli/backend/src/types/index.js.map +1 -1
- package/dist/cli/backend/src/types/settings.types.d.ts +1 -1
- package/dist/cli/backend/src/types/settings.types.d.ts.map +1 -1
- package/dist/cli/backend/src/types/settings.types.js +4 -0
- package/dist/cli/backend/src/types/settings.types.js.map +1 -1
- package/dist/cli/backend/src/utils/gemini-trusted-folders.d.ts +43 -0
- package/dist/cli/backend/src/utils/gemini-trusted-folders.d.ts.map +1 -0
- package/dist/cli/backend/src/utils/gemini-trusted-folders.js +94 -0
- package/dist/cli/backend/src/utils/gemini-trusted-folders.js.map +1 -0
- package/dist/cli/backend/src/utils/terminal-output.utils.d.ts +2 -1
- package/dist/cli/backend/src/utils/terminal-output.utils.d.ts.map +1 -1
- package/dist/cli/backend/src/utils/terminal-output.utils.js +2 -28
- package/dist/cli/backend/src/utils/terminal-output.utils.js.map +1 -1
- package/dist/cli/backend/src/utils/terminal-string-ops.d.ts +183 -0
- package/dist/cli/backend/src/utils/terminal-string-ops.d.ts.map +1 -0
- package/dist/cli/backend/src/utils/terminal-string-ops.js +726 -0
- package/dist/cli/backend/src/utils/terminal-string-ops.js.map +1 -0
- package/dist/cli/cli/src/commands/onboard.d.ts +2 -1
- package/dist/cli/cli/src/commands/onboard.d.ts.map +1 -1
- package/dist/cli/cli/src/commands/onboard.js +21 -8
- package/dist/cli/cli/src/commands/onboard.js.map +1 -1
- package/dist/cli/cli/src/commands/start.d.ts +1 -0
- package/dist/cli/cli/src/commands/start.d.ts.map +1 -1
- package/dist/cli/cli/src/commands/start.js +71 -23
- package/dist/cli/cli/src/commands/start.js.map +1 -1
- package/dist/cli/cli/src/constants.d.ts +1 -1
- package/dist/cli/cli/src/constants.d.ts.map +1 -1
- package/dist/cli/cli/src/constants.js +1 -1
- package/dist/cli/cli/src/constants.js.map +1 -1
- package/dist/cli/cli/src/index.js +1 -0
- package/dist/cli/cli/src/index.js.map +1 -1
- package/dist/cli/cli/src/utils/project-scaffold.d.ts +109 -0
- package/dist/cli/cli/src/utils/project-scaffold.d.ts.map +1 -0
- package/dist/cli/cli/src/utils/project-scaffold.js +346 -0
- package/dist/cli/cli/src/utils/project-scaffold.js.map +1 -0
- package/dist/cli/cli/src/utils/templates.d.ts +7 -2
- package/dist/cli/cli/src/utils/templates.d.ts.map +1 -1
- package/dist/cli/cli/src/utils/templates.js +76 -7
- package/dist/cli/cli/src/utils/templates.js.map +1 -1
- package/dist/cli/config/constants.d.ts +40 -1
- package/dist/cli/config/constants.d.ts.map +1 -1
- package/dist/cli/config/constants.js +41 -1
- package/dist/cli/config/constants.js.map +1 -1
- package/dist/cli/config/index.d.ts +2 -2
- package/dist/cli/config/index.d.ts.map +1 -1
- package/dist/cli/config/index.js +2 -2
- package/dist/cli/config/index.js.map +1 -1
- package/frontend/dist/assets/index-510ab719.css +33 -0
- package/frontend/dist/assets/index-935cd846.js +4961 -0
- package/frontend/dist/index.html +2 -2
- package/package.json +9 -4
- package/frontend/dist/assets/index-a23214ae.js +0 -4919
- package/frontend/dist/assets/index-c407fe13.css +0 -33
|
@@ -4,16 +4,20 @@ import { readFile, readdir, stat, mkdir, writeFile, access } from 'fs/promises';
|
|
|
4
4
|
import { LoggerService } from '../core/logger.service.js';
|
|
5
5
|
import { createSessionCommandHelper, getSessionBackendSync, createSessionBackend, getSessionStatePersistence, } from '../session/index.js';
|
|
6
6
|
import { RuntimeServiceFactory } from './runtime-service.factory.js';
|
|
7
|
-
import { CREWLY_CONSTANTS, ENV_CONSTANTS, AGENT_TIMEOUTS, ORCHESTRATOR_SESSION_NAME, ORCHESTRATOR_ROLE, RUNTIME_TYPES, SESSION_COMMAND_DELAYS, EVENT_DELIVERY_CONSTANTS, TERMINAL_PATTERNS, GEMINI_SHELL_MODE_CONSTANTS, } from '../../constants.js';
|
|
7
|
+
import { CREWLY_CONSTANTS, ENV_CONSTANTS, AGENT_TIMEOUTS, ORCHESTRATOR_SESSION_NAME, ORCHESTRATOR_ROLE, RUNTIME_TYPES, SESSION_COMMAND_DELAYS, EVENT_DELIVERY_CONSTANTS, TERMINAL_PATTERNS, GEMINI_SHELL_MODE_CONSTANTS, GEMINI_STUCK_CONNECTIVITY_PATTERN, GEMINI_ERROR_STATE_CONSTANTS, } from '../../constants.js';
|
|
8
8
|
import { WEB_CONSTANTS } from '../../../../config/constants.js';
|
|
9
9
|
import { delay } from '../../utils/async.utils.js';
|
|
10
10
|
import { getSettingsService } from '../settings/settings.service.js';
|
|
11
11
|
import { SessionMemoryService } from '../memory/session-memory.service.js';
|
|
12
12
|
import { RuntimeExitMonitorService } from './runtime-exit-monitor.service.js';
|
|
13
13
|
import { ContextWindowMonitorService } from './context-window-monitor.service.js';
|
|
14
|
+
import { OAuthReloginMonitorService } from './oauth-relogin-monitor.service.js';
|
|
14
15
|
import { SubAgentMessageQueue } from '../messaging/sub-agent-message-queue.service.js';
|
|
15
16
|
import { AgentSuspendService } from './agent-suspend.service.js';
|
|
17
|
+
import { PromptBuilderService } from '../ai/prompt-builder.service.js';
|
|
16
18
|
import { stripAnsiCodes } from '../../utils/terminal-output.utils.js';
|
|
19
|
+
import { isPromptLine, containsSpinnerOrWorkingIndicator, containsProcessingIndicator, containsBusyStatusBar, containsRewindMode, containsGeminiProcessingKeywords, extractChatPrefix, stripTuiLineBorders, matchTuiPromptLine, } from '../../utils/terminal-string-ops.js';
|
|
20
|
+
import { PtyActivityTrackerService } from './pty-activity-tracker.service.js';
|
|
17
21
|
/**
|
|
18
22
|
* Service responsible for the complex, multi-step process of agent initialization and registration.
|
|
19
23
|
* Isolates the complex state management of agent startup with progressive escalation.
|
|
@@ -46,17 +50,14 @@ export class AgentRegistrationService {
|
|
|
46
50
|
// Prevents concurrent sendMessageWithRetry calls to the same session,
|
|
47
51
|
// which causes multiple Ctrl+C presses that can crash the runtime.
|
|
48
52
|
sessionDeliveryMutex = new Map();
|
|
53
|
+
// Per-session hash of last sent message to prevent duplicate writes (#128).
|
|
54
|
+
// Key: sessionName, Value: { hash, sentAt }
|
|
55
|
+
lastSentMessageHash = new Map();
|
|
49
56
|
// Terminal patterns are now centralized in TERMINAL_PATTERNS constant
|
|
50
|
-
// Keeping
|
|
57
|
+
// Keeping prompt chars as static getter for backwards compatibility within the class
|
|
51
58
|
static get CLAUDE_PROMPT_INDICATORS() {
|
|
52
59
|
return TERMINAL_PATTERNS.PROMPT_CHARS;
|
|
53
60
|
}
|
|
54
|
-
static get CLAUDE_PROMPT_STREAM_PATTERN() {
|
|
55
|
-
return TERMINAL_PATTERNS.PROMPT_STREAM;
|
|
56
|
-
}
|
|
57
|
-
static get CLAUDE_PROCESSING_INDICATORS() {
|
|
58
|
-
return TERMINAL_PATTERNS.PROCESSING_INDICATORS;
|
|
59
|
-
}
|
|
60
61
|
constructor(_legacyTmuxService, // Legacy parameter for backwards compatibility
|
|
61
62
|
projectRoot, storageService) {
|
|
62
63
|
this.logger = LoggerService.getInstance().createComponentLogger('AgentRegistrationService');
|
|
@@ -455,6 +456,8 @@ export class AgentRegistrationService {
|
|
|
455
456
|
// Must be before postInitialize and sendRegistrationPromptAsync so exits
|
|
456
457
|
// during those phases are detected and the abort signal fires in time.
|
|
457
458
|
RuntimeExitMonitorService.getInstance().startMonitoring(sessionName, runtimeType, role);
|
|
459
|
+
// Start OAuth relogin monitoring for automatic re-authentication
|
|
460
|
+
OAuthReloginMonitorService.getInstance().startMonitoring(sessionName, runtimeType);
|
|
458
461
|
// Look up per-agent browser automation override from member config
|
|
459
462
|
let browserAutomationOverride;
|
|
460
463
|
if (memberId) {
|
|
@@ -691,6 +694,8 @@ export class AgentRegistrationService {
|
|
|
691
694
|
}
|
|
692
695
|
// Start runtime exit monitoring immediately after runtime is ready
|
|
693
696
|
RuntimeExitMonitorService.getInstance().startMonitoring(sessionName, runtimeType, role);
|
|
697
|
+
// Start OAuth relogin monitoring for automatic re-authentication
|
|
698
|
+
OAuthReloginMonitorService.getInstance().startMonitoring(sessionName, runtimeType);
|
|
694
699
|
// Additional verification: Use runtime detection to confirm runtime is responding
|
|
695
700
|
// Wait a bit longer for runtime to fully load after showing welcome message
|
|
696
701
|
this.logger.debug('Runtime ready detected for orchestrator, waiting for full startup before verification', { sessionName, runtimeType });
|
|
@@ -733,6 +738,8 @@ export class AgentRegistrationService {
|
|
|
733
738
|
}
|
|
734
739
|
// Start runtime exit monitoring immediately after runtime is ready
|
|
735
740
|
RuntimeExitMonitorService.getInstance().startMonitoring(sessionName, runtimeType, role);
|
|
741
|
+
// Start OAuth relogin monitoring for automatic re-authentication
|
|
742
|
+
OAuthReloginMonitorService.getInstance().startMonitoring(sessionName, runtimeType);
|
|
736
743
|
}
|
|
737
744
|
// Look up per-agent browser automation override from member config
|
|
738
745
|
let browserOverrideForRecreation;
|
|
@@ -840,17 +847,23 @@ export class AgentRegistrationService {
|
|
|
840
847
|
// For orchestrator or cases without member ID, remove the memberId parameter
|
|
841
848
|
prompt = prompt.replace(/,\s*"memberId":\s*"\{\{MEMBER_ID\}\}"/g, '');
|
|
842
849
|
}
|
|
843
|
-
// Look up project path for team members
|
|
850
|
+
// Look up project path and TL hierarchy for team members
|
|
844
851
|
let projectPath = process.cwd();
|
|
852
|
+
let foundTeam = null;
|
|
853
|
+
let foundMember = null;
|
|
845
854
|
try {
|
|
846
855
|
const teams = await this.storageService.getTeams();
|
|
847
856
|
for (const team of teams) {
|
|
848
857
|
const member = team.members?.find((m) => m.sessionName === sessionName);
|
|
849
|
-
if (member
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
if (
|
|
853
|
-
|
|
858
|
+
if (member) {
|
|
859
|
+
foundTeam = team;
|
|
860
|
+
foundMember = member;
|
|
861
|
+
if (team.projectIds[0]) {
|
|
862
|
+
const projects = await this.storageService.getProjects();
|
|
863
|
+
const project = projects.find((p) => p.id === team.projectIds[0]);
|
|
864
|
+
if (project?.path) {
|
|
865
|
+
projectPath = project.path;
|
|
866
|
+
}
|
|
854
867
|
}
|
|
855
868
|
break;
|
|
856
869
|
}
|
|
@@ -892,6 +905,53 @@ export class AgentRegistrationService {
|
|
|
892
905
|
// Replace marketplace skills path placeholder
|
|
893
906
|
const marketplaceSkillsPath = path.join(os.homedir(), '.crewly', 'marketplace', 'skills');
|
|
894
907
|
prompt = prompt.replace(/\{\{MARKETPLACE_SKILLS_PATH\}\}/g, marketplaceSkillsPath);
|
|
908
|
+
// Inject Team Lead addon for members with canDelegate=true and subordinates
|
|
909
|
+
if (foundMember?.canDelegate && foundMember.subordinateIds && foundMember.subordinateIds.length > 0 && foundTeam) {
|
|
910
|
+
try {
|
|
911
|
+
// Resolve subordinateIds to SubordinateInfo[]
|
|
912
|
+
const subordinates = foundMember.subordinateIds
|
|
913
|
+
.map((subId) => {
|
|
914
|
+
const subMember = foundTeam.members?.find((m) => m.id === subId);
|
|
915
|
+
if (!subMember)
|
|
916
|
+
return null;
|
|
917
|
+
return {
|
|
918
|
+
name: subMember.name,
|
|
919
|
+
sessionName: subMember.sessionName || '',
|
|
920
|
+
role: subMember.role || 'developer',
|
|
921
|
+
};
|
|
922
|
+
})
|
|
923
|
+
.filter((s) => s !== null);
|
|
924
|
+
if (subordinates.length > 0) {
|
|
925
|
+
const tlConfig = {
|
|
926
|
+
name: sessionName,
|
|
927
|
+
role: role,
|
|
928
|
+
systemPrompt: '',
|
|
929
|
+
projectPath,
|
|
930
|
+
memberId,
|
|
931
|
+
teamId: foundTeam.id,
|
|
932
|
+
canDelegate: true,
|
|
933
|
+
subordinates,
|
|
934
|
+
};
|
|
935
|
+
const promptBuilder = new PromptBuilderService(this.projectRoot);
|
|
936
|
+
const tlSection = await promptBuilder.buildTeamLeadSection(tlConfig);
|
|
937
|
+
if (tlSection) {
|
|
938
|
+
prompt += `\n\n---\n\n${tlSection}`;
|
|
939
|
+
this.logger.info('TL addon injected into init prompt', {
|
|
940
|
+
sessionName,
|
|
941
|
+
subordinateCount: subordinates.length,
|
|
942
|
+
subordinateNames: subordinates.map((s) => s.name),
|
|
943
|
+
tlSectionLength: tlSection.length,
|
|
944
|
+
});
|
|
945
|
+
}
|
|
946
|
+
}
|
|
947
|
+
}
|
|
948
|
+
catch (tlError) {
|
|
949
|
+
this.logger.warn('Failed to inject TL addon (non-critical)', {
|
|
950
|
+
sessionName,
|
|
951
|
+
error: tlError instanceof Error ? tlError.message : String(tlError),
|
|
952
|
+
});
|
|
953
|
+
}
|
|
954
|
+
}
|
|
895
955
|
// Generate and inject startup briefing from session memory
|
|
896
956
|
try {
|
|
897
957
|
const sessionMemoryService = SessionMemoryService.getInstance();
|
|
@@ -1444,6 +1504,8 @@ After checking in, just say "Ready for tasks" and wait for me to send you work.`
|
|
|
1444
1504
|
if (role !== ORCHESTRATOR_ROLE && config.teamId && config.memberId) {
|
|
1445
1505
|
ContextWindowMonitorService.getInstance().startSessionMonitoring(sessionName, config.memberId, config.teamId, role, runtimeType);
|
|
1446
1506
|
}
|
|
1507
|
+
// Start OAuth relogin monitoring for recovered session
|
|
1508
|
+
OAuthReloginMonitorService.getInstance().startMonitoring(sessionName, runtimeType);
|
|
1447
1509
|
return {
|
|
1448
1510
|
success: true,
|
|
1449
1511
|
sessionName,
|
|
@@ -1508,6 +1570,14 @@ After checking in, just say "Ready for tasks" and wait for me to send you work.`
|
|
|
1508
1570
|
await sessionHelper.setEnvironmentVariable(sessionName, ENV_CONSTANTS.CREWLY_SESSION_NAME, sessionName);
|
|
1509
1571
|
await sessionHelper.setEnvironmentVariable(sessionName, ENV_CONSTANTS.CREWLY_ROLE, role);
|
|
1510
1572
|
await sessionHelper.setEnvironmentVariable(sessionName, ENV_CONSTANTS.CREWLY_API_URL, `http://localhost:${WEB_CONSTANTS.PORTS.BACKEND}`);
|
|
1573
|
+
// Pass Gemini API key to gemini-cli agents so they authenticate
|
|
1574
|
+
// with the paid API key instead of the free-tier Google login.
|
|
1575
|
+
if (runtimeType === RUNTIME_TYPES.GEMINI_CLI) {
|
|
1576
|
+
const geminiApiKey = process.env[ENV_CONSTANTS.GEMINI_API_KEY];
|
|
1577
|
+
if (geminiApiKey) {
|
|
1578
|
+
await sessionHelper.setEnvironmentVariable(sessionName, ENV_CONSTANTS.GEMINI_API_KEY, geminiApiKey);
|
|
1579
|
+
}
|
|
1580
|
+
}
|
|
1511
1581
|
this.logger.info('Agent session created and environment variables set, initializing with registration', {
|
|
1512
1582
|
sessionName,
|
|
1513
1583
|
role,
|
|
@@ -1529,6 +1599,8 @@ After checking in, just say "Ready for tasks" and wait for me to send you work.`
|
|
|
1529
1599
|
if (role !== ORCHESTRATOR_ROLE && config.teamId && config.memberId) {
|
|
1530
1600
|
ContextWindowMonitorService.getInstance().startSessionMonitoring(sessionName, config.memberId, config.teamId, role, runtimeType);
|
|
1531
1601
|
}
|
|
1602
|
+
// Start OAuth relogin monitoring for newly created session
|
|
1603
|
+
OAuthReloginMonitorService.getInstance().startMonitoring(sessionName, runtimeType);
|
|
1532
1604
|
return {
|
|
1533
1605
|
success: true,
|
|
1534
1606
|
sessionName,
|
|
@@ -1560,6 +1632,8 @@ After checking in, just say "Ready for tasks" and wait for me to send you work.`
|
|
|
1560
1632
|
this.logger.info('Terminating agent session (unified approach)', { sessionName, role });
|
|
1561
1633
|
// Stop runtime exit monitoring before killing the session
|
|
1562
1634
|
RuntimeExitMonitorService.getInstance().stopMonitoring(sessionName);
|
|
1635
|
+
// Stop OAuth relogin monitoring before killing the session
|
|
1636
|
+
OAuthReloginMonitorService.getInstance().stopMonitoring(sessionName);
|
|
1563
1637
|
// Stop context window monitoring before killing the session
|
|
1564
1638
|
ContextWindowMonitorService.getInstance().stopSessionMonitoring(sessionName);
|
|
1565
1639
|
// Get session helper once to avoid repeated async calls
|
|
@@ -1701,9 +1775,9 @@ After checking in, just say "Ready for tasks" and wait for me to send you work.`
|
|
|
1701
1775
|
if (!delivered) {
|
|
1702
1776
|
// Check if the agent is actively processing (busy) — the queue
|
|
1703
1777
|
// processor can re-queue instead of permanently failing the message.
|
|
1704
|
-
|
|
1705
|
-
const
|
|
1706
|
-
|
|
1778
|
+
// Use PTY idle time instead of regex patterns for robust cross-runtime detection.
|
|
1779
|
+
const idleMs = PtyActivityTrackerService.getInstance().getIdleTimeMs(sessionName);
|
|
1780
|
+
const isBusy = idleMs < SESSION_COMMAND_DELAYS.AGENT_BUSY_IDLE_THRESHOLD_MS;
|
|
1707
1781
|
return {
|
|
1708
1782
|
success: false,
|
|
1709
1783
|
error: isBusy
|
|
@@ -1768,9 +1842,6 @@ After checking in, just say "Ready for tasks" and wait for me to send you work.`
|
|
|
1768
1842
|
if (!session) {
|
|
1769
1843
|
return false;
|
|
1770
1844
|
}
|
|
1771
|
-
// Use runtime-specific pattern for stream detection to avoid false positives
|
|
1772
|
-
// (e.g. Gemini's `> ` pattern matching markdown blockquotes in Claude Code output)
|
|
1773
|
-
const streamPattern = this.getPromptPatternForRuntime(runtimeType);
|
|
1774
1845
|
return new Promise((resolve) => {
|
|
1775
1846
|
let resolved = false;
|
|
1776
1847
|
const pollInterval = EVENT_DELIVERY_CONSTANTS.AGENT_READY_POLL_INTERVAL;
|
|
@@ -1817,9 +1888,11 @@ After checking in, just say "Ready for tasks" and wait for me to send you work.`
|
|
|
1817
1888
|
if (resolved)
|
|
1818
1889
|
return;
|
|
1819
1890
|
// Strip ANSI escape sequences before testing — raw PTY data contains
|
|
1820
|
-
// cursor positioning, color codes, etc. that break
|
|
1891
|
+
// cursor positioning, color codes, etc. that break pattern matching (#106)
|
|
1821
1892
|
const cleanData = stripAnsiCodes(data);
|
|
1822
|
-
|
|
1893
|
+
// Check each line for prompt pattern (string-based, no regex)
|
|
1894
|
+
const hasPromptInStream = cleanData.split('\n').some(line => line.trim().length > 0 && isPromptLine(line, runtimeType));
|
|
1895
|
+
if (hasPromptInStream) {
|
|
1823
1896
|
// Double-check with capturePane to avoid false positives from partial data
|
|
1824
1897
|
const output = sessionHelper.capturePane(sessionName);
|
|
1825
1898
|
if (this.isClaudeAtPrompt(output, runtimeType)) {
|
|
@@ -1831,256 +1904,6 @@ After checking in, just say "Ready for tasks" and wait for me to send you work.`
|
|
|
1831
1904
|
});
|
|
1832
1905
|
});
|
|
1833
1906
|
}
|
|
1834
|
-
/**
|
|
1835
|
-
* @deprecated Replaced by SessionCommandHelper.sendMessage() in sendMessageWithRetry.
|
|
1836
|
-
* Complex event-driven state machine was fragile — Enter key often got lost.
|
|
1837
|
-
* Kept as dead code for reference during transition.
|
|
1838
|
-
*/
|
|
1839
|
-
async _deprecated_sendMessageEventDriven(sessionName, message, timeoutMs = EVENT_DELIVERY_CONSTANTS.TOTAL_DELIVERY_TIMEOUT) {
|
|
1840
|
-
const sessionHelper = await this.getSessionHelper();
|
|
1841
|
-
const session = sessionHelper.getSession(sessionName);
|
|
1842
|
-
if (!session) {
|
|
1843
|
-
this.logger.error('Session not found for event-driven delivery', { sessionName });
|
|
1844
|
-
return false;
|
|
1845
|
-
}
|
|
1846
|
-
return new Promise((resolve) => {
|
|
1847
|
-
let buffer = '';
|
|
1848
|
-
let messageSent = false;
|
|
1849
|
-
let enterSent = false;
|
|
1850
|
-
let enterAccepted = false;
|
|
1851
|
-
let deliveryConfirmed = false;
|
|
1852
|
-
let resolved = false;
|
|
1853
|
-
// Track all timeouts to prevent memory leaks (P1.1 fix)
|
|
1854
|
-
const pendingTimeouts = [];
|
|
1855
|
-
const scheduleTimeout = (fn, delayMs) => {
|
|
1856
|
-
const id = setTimeout(fn, delayMs);
|
|
1857
|
-
pendingTimeouts.push(id);
|
|
1858
|
-
return id;
|
|
1859
|
-
};
|
|
1860
|
-
const cleanup = () => {
|
|
1861
|
-
// Immediately mark as resolved to prevent race conditions (P1.2 fix)
|
|
1862
|
-
const wasResolved = resolved;
|
|
1863
|
-
resolved = true;
|
|
1864
|
-
if (!wasResolved) {
|
|
1865
|
-
// Clear all pending timeouts to prevent memory leaks
|
|
1866
|
-
pendingTimeouts.forEach((id) => clearTimeout(id));
|
|
1867
|
-
clearTimeout(timeoutId);
|
|
1868
|
-
unsubscribe();
|
|
1869
|
-
}
|
|
1870
|
-
};
|
|
1871
|
-
// Use centralized patterns from TERMINAL_PATTERNS
|
|
1872
|
-
const PASTE_PATTERN = TERMINAL_PATTERNS.PASTE_INDICATOR;
|
|
1873
|
-
const PROCESSING_PATTERN = TERMINAL_PATTERNS.PROCESSING;
|
|
1874
|
-
// Use centralized timing from EVENT_DELIVERY_CONSTANTS
|
|
1875
|
-
const INITIAL_DELAY = EVENT_DELIVERY_CONSTANTS.INITIAL_MESSAGE_DELAY;
|
|
1876
|
-
const PASTE_CHECK_DELAY = EVENT_DELIVERY_CONSTANTS.PASTE_CHECK_DELAY;
|
|
1877
|
-
const ENTER_RETRY_DELAY = EVENT_DELIVERY_CONSTANTS.ENTER_RETRY_DELAY;
|
|
1878
|
-
const MAX_ENTER_RETRIES = EVENT_DELIVERY_CONSTANTS.MAX_ENTER_RETRIES;
|
|
1879
|
-
const MAX_BUFFER_SIZE = EVENT_DELIVERY_CONSTANTS.MAX_BUFFER_SIZE;
|
|
1880
|
-
// Helper to send the message when prompt is detected
|
|
1881
|
-
const sendMessageNow = () => {
|
|
1882
|
-
if (messageSent || resolved)
|
|
1883
|
-
return;
|
|
1884
|
-
this.logger.debug('Claude at prompt, sending message', {
|
|
1885
|
-
sessionName,
|
|
1886
|
-
messageLength: message.length,
|
|
1887
|
-
isMultiLine: message.includes('\n'),
|
|
1888
|
-
});
|
|
1889
|
-
// Send the message text
|
|
1890
|
-
session.write(message);
|
|
1891
|
-
messageSent = true;
|
|
1892
|
-
const isMultiLine = message.includes('\n');
|
|
1893
|
-
// Track Enter key state
|
|
1894
|
-
let enterAttempts = 0;
|
|
1895
|
-
let processingDetected = false;
|
|
1896
|
-
const bufferAtSend = buffer;
|
|
1897
|
-
// Function to send Enter and track attempts
|
|
1898
|
-
const sendEnterKey = (reason) => {
|
|
1899
|
-
if (resolved || processingDetected)
|
|
1900
|
-
return;
|
|
1901
|
-
enterAttempts++;
|
|
1902
|
-
session.write('\r');
|
|
1903
|
-
enterSent = true;
|
|
1904
|
-
this.logger.debug('Enter key sent', {
|
|
1905
|
-
sessionName,
|
|
1906
|
-
attempt: enterAttempts,
|
|
1907
|
-
reason,
|
|
1908
|
-
});
|
|
1909
|
-
};
|
|
1910
|
-
// Function to check if Enter was accepted (processing started)
|
|
1911
|
-
const checkProcessingStarted = () => {
|
|
1912
|
-
const newData = buffer.slice(bufferAtSend.length);
|
|
1913
|
-
return PROCESSING_PATTERN.test(newData);
|
|
1914
|
-
};
|
|
1915
|
-
// Function to check for paste indicator
|
|
1916
|
-
const checkPasteIndicator = () => {
|
|
1917
|
-
const newData = buffer.slice(bufferAtSend.length);
|
|
1918
|
-
return PASTE_PATTERN.test(newData);
|
|
1919
|
-
};
|
|
1920
|
-
// Strategy: Send Enter with progressive timing, retry if not accepted
|
|
1921
|
-
const attemptEnter = (attemptNum) => {
|
|
1922
|
-
if (resolved || processingDetected)
|
|
1923
|
-
return;
|
|
1924
|
-
// Check if processing already started
|
|
1925
|
-
if (checkProcessingStarted()) {
|
|
1926
|
-
processingDetected = true;
|
|
1927
|
-
enterAccepted = true;
|
|
1928
|
-
this.logger.debug('Processing detected, message accepted', { sessionName, attemptNum });
|
|
1929
|
-
buffer = ''; // Reset for processing indicator detection
|
|
1930
|
-
return;
|
|
1931
|
-
}
|
|
1932
|
-
if (attemptNum > MAX_ENTER_RETRIES) {
|
|
1933
|
-
this.logger.warn('Max Enter retries reached, verifying message acceptance', { sessionName });
|
|
1934
|
-
scheduleTimeout(async () => {
|
|
1935
|
-
if (resolved)
|
|
1936
|
-
return;
|
|
1937
|
-
const stuck = await this.isMessageStuckAtPrompt(sessionName, message);
|
|
1938
|
-
if (stuck) {
|
|
1939
|
-
this.logger.warn('Message stuck at prompt after all Enter retries', { sessionName });
|
|
1940
|
-
const stuckHelper = await this.getSessionHelper();
|
|
1941
|
-
await stuckHelper.clearCurrentCommandLine(sessionName);
|
|
1942
|
-
enterAccepted = false;
|
|
1943
|
-
}
|
|
1944
|
-
else {
|
|
1945
|
-
this.logger.debug('Message appears accepted (no longer at prompt)', { sessionName });
|
|
1946
|
-
enterAccepted = true;
|
|
1947
|
-
buffer = '';
|
|
1948
|
-
}
|
|
1949
|
-
}, EVENT_DELIVERY_CONSTANTS.POST_ENTER_VERIFICATION_DELAY);
|
|
1950
|
-
return;
|
|
1951
|
-
}
|
|
1952
|
-
sendEnterKey(attemptNum === 1 ? 'initial' : `retry-${attemptNum}`);
|
|
1953
|
-
// Schedule check and possible retry (using tracked timeout to prevent leaks)
|
|
1954
|
-
scheduleTimeout(() => {
|
|
1955
|
-
if (resolved)
|
|
1956
|
-
return;
|
|
1957
|
-
if (checkProcessingStarted()) {
|
|
1958
|
-
processingDetected = true;
|
|
1959
|
-
enterAccepted = true;
|
|
1960
|
-
this.logger.debug('Processing detected after Enter', { sessionName, attemptNum });
|
|
1961
|
-
buffer = '';
|
|
1962
|
-
}
|
|
1963
|
-
else {
|
|
1964
|
-
// Not accepted yet, retry
|
|
1965
|
-
this.logger.debug('Enter may not have been accepted, retrying', {
|
|
1966
|
-
sessionName,
|
|
1967
|
-
attemptNum,
|
|
1968
|
-
bufferLength: buffer.length,
|
|
1969
|
-
});
|
|
1970
|
-
attemptEnter(attemptNum + 1);
|
|
1971
|
-
}
|
|
1972
|
-
}, ENTER_RETRY_DELAY);
|
|
1973
|
-
};
|
|
1974
|
-
// For multi-line messages, wait longer for paste indicator
|
|
1975
|
-
// For single-line messages, send Enter sooner
|
|
1976
|
-
const initialWait = isMultiLine ? PASTE_CHECK_DELAY : INITIAL_DELAY;
|
|
1977
|
-
scheduleTimeout(() => {
|
|
1978
|
-
if (resolved)
|
|
1979
|
-
return;
|
|
1980
|
-
// For multi-line: check if paste indicator appeared
|
|
1981
|
-
if (isMultiLine && checkPasteIndicator()) {
|
|
1982
|
-
this.logger.debug('Paste indicator detected', { sessionName });
|
|
1983
|
-
}
|
|
1984
|
-
// Start Enter key attempts
|
|
1985
|
-
attemptEnter(1);
|
|
1986
|
-
}, initialWait);
|
|
1987
|
-
};
|
|
1988
|
-
const timeoutId = setTimeout(async () => {
|
|
1989
|
-
this.logger.debug('Event-driven delivery timed out', {
|
|
1990
|
-
sessionName,
|
|
1991
|
-
messageSent,
|
|
1992
|
-
enterSent,
|
|
1993
|
-
enterAccepted,
|
|
1994
|
-
deliveryConfirmed,
|
|
1995
|
-
bufferLength: buffer.length,
|
|
1996
|
-
});
|
|
1997
|
-
// If Enter was sent but not confirmed accepted, verify via terminal capture
|
|
1998
|
-
if (enterSent && !enterAccepted && !deliveryConfirmed) {
|
|
1999
|
-
const timeoutHelper = await this.getSessionHelper();
|
|
2000
|
-
const stuck = await this.isMessageStuckAtPrompt(sessionName, message);
|
|
2001
|
-
if (stuck) {
|
|
2002
|
-
this.logger.warn('Timeout: message stuck at prompt, clearing and failing', { sessionName });
|
|
2003
|
-
await timeoutHelper.clearCurrentCommandLine(sessionName);
|
|
2004
|
-
cleanup();
|
|
2005
|
-
resolve(false);
|
|
2006
|
-
return;
|
|
2007
|
-
}
|
|
2008
|
-
this.logger.debug('Timeout: message not at prompt, treating as accepted', { sessionName });
|
|
2009
|
-
}
|
|
2010
|
-
cleanup();
|
|
2011
|
-
resolve(enterAccepted || deliveryConfirmed);
|
|
2012
|
-
}, timeoutMs);
|
|
2013
|
-
// IMPORTANT: Check current terminal state, but wait for output to settle first.
|
|
2014
|
-
// If the orchestrator just finished outputting (greeting, notification, status bar),
|
|
2015
|
-
// the prompt may not be cleanly detectable. We capture the pane, wait briefly,
|
|
2016
|
-
// and re-capture. If output is still changing, wait again before checking prompt.
|
|
2017
|
-
// Use 50 lines to account for status bars and notifications that can
|
|
2018
|
-
// wrap across many lines and push the prompt out of a smaller window.
|
|
2019
|
-
const waitForSettled = async () => {
|
|
2020
|
-
let prevOutput = sessionHelper.capturePane(sessionName);
|
|
2021
|
-
for (let i = 0; i < 5; i++) { // Max 5 checks, 500ms apart = 2.5s max
|
|
2022
|
-
if (resolved)
|
|
2023
|
-
return;
|
|
2024
|
-
await delay(500);
|
|
2025
|
-
if (resolved)
|
|
2026
|
-
return;
|
|
2027
|
-
const currentOutput = sessionHelper.capturePane(sessionName);
|
|
2028
|
-
if (currentOutput === prevOutput) {
|
|
2029
|
-
// Output settled
|
|
2030
|
-
if (this.isClaudeAtPrompt(currentOutput)) {
|
|
2031
|
-
this.logger.debug('Claude at prompt after output settled', { sessionName, settleChecks: i + 1 });
|
|
2032
|
-
sendMessageNow();
|
|
2033
|
-
}
|
|
2034
|
-
return;
|
|
2035
|
-
}
|
|
2036
|
-
prevOutput = currentOutput;
|
|
2037
|
-
}
|
|
2038
|
-
// Output still changing after 2.5s - check anyway
|
|
2039
|
-
if (!resolved && this.isClaudeAtPrompt(prevOutput)) {
|
|
2040
|
-
this.logger.debug('Claude at prompt (output still changing, checking anyway)', { sessionName });
|
|
2041
|
-
sendMessageNow();
|
|
2042
|
-
}
|
|
2043
|
-
};
|
|
2044
|
-
waitForSettled();
|
|
2045
|
-
const unsubscribe = session.onData((data) => {
|
|
2046
|
-
if (resolved)
|
|
2047
|
-
return;
|
|
2048
|
-
// Accumulate data with size limit to prevent memory exhaustion (P2.3 fix)
|
|
2049
|
-
buffer += data;
|
|
2050
|
-
if (buffer.length > MAX_BUFFER_SIZE) {
|
|
2051
|
-
buffer = buffer.slice(-MAX_BUFFER_SIZE);
|
|
2052
|
-
}
|
|
2053
|
-
// Phase 1: Wait for Claude to be at prompt before sending
|
|
2054
|
-
if (!messageSent) {
|
|
2055
|
-
const isAtPrompt = AgentRegistrationService.CLAUDE_PROMPT_STREAM_PATTERN.test(buffer);
|
|
2056
|
-
if (isAtPrompt) {
|
|
2057
|
-
sendMessageNow();
|
|
2058
|
-
}
|
|
2059
|
-
return;
|
|
2060
|
-
}
|
|
2061
|
-
// Phase 2: Only check for processing indicators AFTER Enter has been sent
|
|
2062
|
-
if (!enterSent) {
|
|
2063
|
-
return; // Wait for Enter to be sent
|
|
2064
|
-
}
|
|
2065
|
-
// Look for processing indicators confirming delivery
|
|
2066
|
-
const hasProcessingIndicator = AgentRegistrationService.CLAUDE_PROCESSING_INDICATORS.some((pattern) => pattern.test(buffer));
|
|
2067
|
-
// Also check if prompt disappeared (Claude is working)
|
|
2068
|
-
const promptStillVisible = AgentRegistrationService.CLAUDE_PROMPT_STREAM_PATTERN.test(buffer);
|
|
2069
|
-
// Use constant for minimum buffer check (P3.2 fix)
|
|
2070
|
-
if (hasProcessingIndicator || (!promptStillVisible && buffer.length > EVENT_DELIVERY_CONSTANTS.MIN_BUFFER_FOR_PROCESSING_DETECTION)) {
|
|
2071
|
-
this.logger.debug('Message delivery confirmed (event-driven)', {
|
|
2072
|
-
sessionName,
|
|
2073
|
-
hasProcessingIndicator,
|
|
2074
|
-
promptStillVisible,
|
|
2075
|
-
bufferLength: buffer.length,
|
|
2076
|
-
});
|
|
2077
|
-
deliveryConfirmed = true;
|
|
2078
|
-
cleanup();
|
|
2079
|
-
resolve(true);
|
|
2080
|
-
}
|
|
2081
|
-
});
|
|
2082
|
-
});
|
|
2083
|
-
}
|
|
2084
1907
|
/**
|
|
2085
1908
|
* Send message with retry logic for reliable delivery to Claude Code.
|
|
2086
1909
|
* Uses SessionCommandHelper.sendMessage() (proven two-step write pattern)
|
|
@@ -2111,15 +1934,24 @@ After checking in, just say "Ready for tasks" and wait for me to send you work.`
|
|
|
2111
1934
|
});
|
|
2112
1935
|
// Verify agent is at prompt before sending
|
|
2113
1936
|
const output = sessionHelper.capturePane(sessionName);
|
|
1937
|
+
// Gemini CLI stuck-connectivity guard (#128): If the CLI is in a
|
|
1938
|
+
// "Trying to reach <model>" retry loop, it will never process
|
|
1939
|
+
// new messages. Bail out immediately so the caller gets a clear
|
|
1940
|
+
// failure signal and the runtime-exit-monitor can trigger recovery.
|
|
1941
|
+
if (runtimeType === RUNTIME_TYPES.GEMINI_CLI && GEMINI_STUCK_CONNECTIVITY_PATTERN.test(output)) {
|
|
1942
|
+
this.logger.warn('Gemini CLI stuck in connectivity retry loop, aborting message delivery (#128)', {
|
|
1943
|
+
sessionName,
|
|
1944
|
+
attempt,
|
|
1945
|
+
});
|
|
1946
|
+
return false;
|
|
1947
|
+
}
|
|
2114
1948
|
if (!this.isClaudeAtPrompt(output, runtimeType)) {
|
|
2115
1949
|
if (attempt === maxAttempts) {
|
|
2116
1950
|
// On the final attempt, check if the agent is DEFINITELY busy
|
|
2117
|
-
// before force-delivering.
|
|
2118
|
-
//
|
|
2119
|
-
|
|
2120
|
-
const
|
|
2121
|
-
const isBusy = TERMINAL_PATTERNS.BUSY_STATUS_BAR.test(tailForBusyCheck) ||
|
|
2122
|
-
TERMINAL_PATTERNS.PROCESSING_WITH_TEXT.test(tailForBusyCheck);
|
|
1951
|
+
// before force-delivering. Use PTY idle time for robust
|
|
1952
|
+
// cross-runtime detection instead of fragile regex patterns.
|
|
1953
|
+
const idleMs = PtyActivityTrackerService.getInstance().getIdleTimeMs(sessionName);
|
|
1954
|
+
const isBusy = idleMs < SESSION_COMMAND_DELAYS.AGENT_BUSY_IDLE_THRESHOLD_MS;
|
|
2123
1955
|
if (isBusy) {
|
|
2124
1956
|
this.logger.warn('Agent is busy (processing indicators detected), skipping force delivery', {
|
|
2125
1957
|
sessionName,
|
|
@@ -2182,20 +2014,49 @@ After checking in, just say "Ready for tasks" and wait for me to send you work.`
|
|
|
2182
2014
|
// for focus cycling and overlay dismissal.
|
|
2183
2015
|
if (isClaudeCode) {
|
|
2184
2016
|
if (attempt > 1) {
|
|
2017
|
+
// On retry: Ctrl+C to cancel stale input, then PTY resize to force
|
|
2018
|
+
// TUI re-render (SIGWINCH), then Tab to cycle Ink focus.
|
|
2185
2019
|
await sessionHelper.sendCtrlC(sessionName);
|
|
2186
2020
|
await delay(300);
|
|
2187
2021
|
}
|
|
2022
|
+
// PTY resize on ALL attempts to force SIGWINCH → Ink TUI re-render.
|
|
2023
|
+
// Claude Code's Ink TUI can lose internal input focus after stop hooks
|
|
2024
|
+
// (especially ones that error), state transitions, or idle periods.
|
|
2025
|
+
// When defocused, the `❯` prompt is visible in the terminal buffer
|
|
2026
|
+
// but writes are silently consumed by the framework — NOT routed to
|
|
2027
|
+
// the InputPrompt. Tab alone was insufficient; PTY resize forces a
|
|
2028
|
+
// full TUI re-render that reliably restores focus state.
|
|
2029
|
+
// This matches the manual workaround where pressing a key in the
|
|
2030
|
+
// frontend terminal "wakes up" the input handler.
|
|
2031
|
+
try {
|
|
2032
|
+
const session = sessionHelper.getSession(sessionName);
|
|
2033
|
+
if (session) {
|
|
2034
|
+
session.resize(81, 25);
|
|
2035
|
+
await delay(200);
|
|
2036
|
+
session.resize(80, 24);
|
|
2037
|
+
await delay(300);
|
|
2038
|
+
}
|
|
2039
|
+
}
|
|
2040
|
+
catch { /* non-fatal */ }
|
|
2041
|
+
await sessionHelper.sendKey(sessionName, 'Tab');
|
|
2042
|
+
await delay(300);
|
|
2188
2043
|
}
|
|
2189
2044
|
else {
|
|
2190
2045
|
// Detect recent /compress — Ink TUI loses internal focus after
|
|
2191
2046
|
// /compress re-renders, causing subsequent messages to be silently
|
|
2192
2047
|
// dropped even though the prompt `>` is visible (#114).
|
|
2193
2048
|
// Always force PTY resize on attempt 1 if /compress detected.
|
|
2049
|
+
// Also detect ✖ error state (#130) — MCP connection errors
|
|
2050
|
+
// cause a persistent error indicator that steals TUI focus.
|
|
2194
2051
|
const recentOutput = sessionHelper.capturePane(sessionName, 40);
|
|
2195
2052
|
const compressDetected = recentOutput.includes('/compress') ||
|
|
2196
2053
|
recentOutput.includes('Context compressed') ||
|
|
2197
2054
|
recentOutput.includes('Compressing context');
|
|
2198
|
-
|
|
2055
|
+
// Check for Gemini CLI error indicators in the status bar area (#130).
|
|
2056
|
+
const statusArea = recentOutput.split('\n').slice(-GEMINI_ERROR_STATE_CONSTANTS.STATUS_AREA_LINES).join('\n');
|
|
2057
|
+
const errorStateDetected = recentOutput.includes(GEMINI_ERROR_STATE_CONSTANTS.ERROR_MARKER) ||
|
|
2058
|
+
GEMINI_ERROR_STATE_CONSTANTS.ERROR_COUNT_PATTERN.test(statusArea);
|
|
2059
|
+
const needsResize = attempt > 1 || compressDetected || errorStateDetected;
|
|
2199
2060
|
// Force a PTY resize to trigger SIGWINCH, making Ink
|
|
2200
2061
|
// re-render the TUI and potentially restore focus state.
|
|
2201
2062
|
if (needsResize) {
|
|
@@ -2221,19 +2082,39 @@ After checking in, just say "Ready for tasks" and wait for me to send you work.`
|
|
|
2221
2082
|
});
|
|
2222
2083
|
}
|
|
2223
2084
|
}
|
|
2085
|
+
// If error state detected (✖), dismiss the error overlay first (#130).
|
|
2086
|
+
// F12 toggles the error details panel in Gemini CLI, Enter dismisses
|
|
2087
|
+
// any overlay/notification, and the combination restores the TUI to a
|
|
2088
|
+
// state where the InputPrompt can accept input.
|
|
2089
|
+
if (errorStateDetected) {
|
|
2090
|
+
this.logger.info('Gemini CLI error state detected (✖), dismissing before delivery (#130)', {
|
|
2091
|
+
sessionName,
|
|
2092
|
+
attempt,
|
|
2093
|
+
});
|
|
2094
|
+
// F12 to close error details panel if open
|
|
2095
|
+
await sessionHelper.sendKey(sessionName, 'F12');
|
|
2096
|
+
await delay(300);
|
|
2097
|
+
// Enter to dismiss any remaining overlay/notification
|
|
2098
|
+
await sessionHelper.sendEnter(sessionName);
|
|
2099
|
+
await delay(500);
|
|
2100
|
+
}
|
|
2224
2101
|
// Send Tab to cycle Ink focus. In Ink v6, Tab triggers
|
|
2225
2102
|
// focusNext() in FocusContext, which moves focus to the next
|
|
2226
2103
|
// focusable component (InputPrompt). This works even when the
|
|
2227
2104
|
// input is defocused because the Tab handler runs at the Ink
|
|
2228
2105
|
// framework level, not the component level.
|
|
2106
|
+
// Send two Tabs to cycle through error/notification components
|
|
2107
|
+
// that may be in the focus chain (#130).
|
|
2108
|
+
await sessionHelper.sendKey(sessionName, 'Tab');
|
|
2109
|
+
await delay(200);
|
|
2229
2110
|
await sessionHelper.sendKey(sessionName, 'Tab');
|
|
2230
2111
|
await delay(300);
|
|
2231
2112
|
// Then Enter to dismiss any notification overlay and ensure
|
|
2232
2113
|
// the input is engaged. Enter on an empty `> ` prompt is a
|
|
2233
2114
|
// safe no-op (just shows a new blank prompt line).
|
|
2234
2115
|
await sessionHelper.sendEnter(sessionName);
|
|
2235
|
-
// Extra settling time after /compress to let Ink TUI stabilize
|
|
2236
|
-
await delay(compressDetected ? 1000 : 500);
|
|
2116
|
+
// Extra settling time after /compress or error state to let Ink TUI stabilize
|
|
2117
|
+
await delay((compressDetected || errorStateDetected) ? 1000 : 500);
|
|
2237
2118
|
}
|
|
2238
2119
|
// For Gemini CLI: detect and gently escape interactive modes before
|
|
2239
2120
|
// sending the message. Avoid Ctrl-C here — Gemini interprets it as
|
|
@@ -2266,6 +2147,50 @@ After checking in, just say "Ready for tasks" and wait for me to send you work.`
|
|
|
2266
2147
|
// border redraws that can cause length changes unrelated to delivery.
|
|
2267
2148
|
const beforeOutput = sessionHelper.capturePane(sessionName, 20);
|
|
2268
2149
|
const beforeLength = beforeOutput.length;
|
|
2150
|
+
// Deduplication guard (#128): Check if the agent is already
|
|
2151
|
+
// processing on ALL attempts (not just retries). A previous
|
|
2152
|
+
// write may have succeeded but verification failed. Re-writing
|
|
2153
|
+
// the same message creates a duplicate in the input buffer.
|
|
2154
|
+
{
|
|
2155
|
+
const preWriteCheck = sessionHelper.capturePane(sessionName);
|
|
2156
|
+
const hasSpinner = containsSpinnerOrWorkingIndicator(preWriteCheck);
|
|
2157
|
+
if (hasSpinner) {
|
|
2158
|
+
// Hash-based dedup: if the same message was recently sent
|
|
2159
|
+
// and the agent is processing, it's very likely our message.
|
|
2160
|
+
const msgHash = message.substring(0, 200);
|
|
2161
|
+
const lastSent = this.lastSentMessageHash.get(sessionName);
|
|
2162
|
+
const isRecentDuplicate = lastSent
|
|
2163
|
+
&& lastSent.hash === msgHash
|
|
2164
|
+
&& (Date.now() - lastSent.sentAt) < 60000;
|
|
2165
|
+
if (isRecentDuplicate || attempt > 1) {
|
|
2166
|
+
this.logger.info('Agent already processing — skipping write to prevent duplicate (#128)', {
|
|
2167
|
+
sessionName,
|
|
2168
|
+
attempt,
|
|
2169
|
+
isRecentDuplicate: !!isRecentDuplicate,
|
|
2170
|
+
});
|
|
2171
|
+
return true;
|
|
2172
|
+
}
|
|
2173
|
+
}
|
|
2174
|
+
// On retries: also check if agent is not at prompt AND our
|
|
2175
|
+
// message text is NOT stuck at the bottom.
|
|
2176
|
+
if (attempt > 1) {
|
|
2177
|
+
const notAtPrompt = !this.isClaudeAtPrompt(preWriteCheck, runtimeType);
|
|
2178
|
+
if (notAtPrompt) {
|
|
2179
|
+
const msgSnippet = (message.length > 20
|
|
2180
|
+
? message.substring(0, 80)
|
|
2181
|
+
: message).replace(/\s+/g, ' ').trim();
|
|
2182
|
+
const bottomLines = preWriteCheck.split('\n').slice(-10).join(' ').replace(/\s+/g, ' ');
|
|
2183
|
+
const textStuck = bottomLines.includes(msgSnippet);
|
|
2184
|
+
if (!textStuck) {
|
|
2185
|
+
this.logger.info('Agent not at prompt and message not stuck — skipping re-write (#128)', {
|
|
2186
|
+
sessionName,
|
|
2187
|
+
attempt,
|
|
2188
|
+
});
|
|
2189
|
+
return true;
|
|
2190
|
+
}
|
|
2191
|
+
}
|
|
2192
|
+
}
|
|
2193
|
+
}
|
|
2269
2194
|
// Use SessionCommandHelper.sendMessage() — proven two-step write:
|
|
2270
2195
|
// 1. session.write(message) — triggers bracketed paste
|
|
2271
2196
|
// 2. await delay(scaled) — waits for paste processing
|
|
@@ -2276,6 +2201,11 @@ After checking in, just say "Ready for tasks" and wait for me to send you work.`
|
|
|
2276
2201
|
// If progressive verification below misses an Enter drop, the
|
|
2277
2202
|
// background scanner will catch it within 30s.
|
|
2278
2203
|
this.trackSentMessage(sessionName, message);
|
|
2204
|
+
// Track message hash for deduplication on retry (#128)
|
|
2205
|
+
this.lastSentMessageHash.set(sessionName, {
|
|
2206
|
+
hash: message.substring(0, 200),
|
|
2207
|
+
sentAt: Date.now(),
|
|
2208
|
+
});
|
|
2279
2209
|
// Wait for agent to start processing, then verify delivery.
|
|
2280
2210
|
// TUI runtimes need a longer delay (3s) for the TUI to redraw
|
|
2281
2211
|
// and show processing indicators after accepting input.
|
|
@@ -2318,7 +2248,7 @@ After checking in, just say "Ready for tasks" and wait for me to send you work.`
|
|
|
2318
2248
|
// definitive proof the agent accepted and is working.
|
|
2319
2249
|
// Only check spinner/⏺ chars — NOT text words like
|
|
2320
2250
|
// "thinking" which appear in historical response text.
|
|
2321
|
-
if (
|
|
2251
|
+
if (containsSpinnerOrWorkingIndicator(currentOutput)) {
|
|
2322
2252
|
this.logger.debug('Processing indicators detected — message accepted', {
|
|
2323
2253
|
sessionName,
|
|
2324
2254
|
attempt,
|
|
@@ -2342,18 +2272,24 @@ After checking in, just say "Ready for tasks" and wait for me to send you work.`
|
|
|
2342
2272
|
: message).replace(/\s+/g, ' ').trim();
|
|
2343
2273
|
const promptBottomLines = currentOutput.split('\n').slice(-10).join(' ').replace(/\s+/g, ' ');
|
|
2344
2274
|
if (promptBottomLines.includes(promptMsgSnippet)) {
|
|
2345
|
-
this.logger.warn('At prompt with message text at bottom — pressing Enter', {
|
|
2275
|
+
this.logger.warn('At prompt with message text at bottom — pressing Tab+Enter', {
|
|
2346
2276
|
sessionName,
|
|
2347
2277
|
attempt,
|
|
2348
2278
|
intervalMs,
|
|
2349
2279
|
});
|
|
2280
|
+
// Tab restores Ink TUI focus before Enter — without this,
|
|
2281
|
+
// Enter may be consumed by the framework but not routed to
|
|
2282
|
+
// the input component if focus was lost during a re-render
|
|
2283
|
+
// (e.g., after stop hooks, state transitions).
|
|
2284
|
+
await sessionHelper.sendKey(sessionName, 'Tab');
|
|
2285
|
+
await delay(200);
|
|
2350
2286
|
await sessionHelper.sendEnter(sessionName);
|
|
2351
2287
|
await delay(500);
|
|
2352
2288
|
await sessionHelper.sendEnter(sessionName); // backup
|
|
2353
2289
|
await delay(SESSION_COMMAND_DELAYS.MESSAGE_PROCESSING_DELAY);
|
|
2354
2290
|
// Verify recovery
|
|
2355
2291
|
const postEnterOutput = sessionHelper.capturePane(sessionName);
|
|
2356
|
-
if (
|
|
2292
|
+
if (containsSpinnerOrWorkingIndicator(postEnterOutput) ||
|
|
2357
2293
|
!this.isClaudeAtPrompt(postEnterOutput, runtimeType)) {
|
|
2358
2294
|
this.logger.info('Enter recovery from prompt successful', {
|
|
2359
2295
|
sessionName,
|
|
@@ -2387,12 +2323,14 @@ After checking in, just say "Ready for tasks" and wait for me to send you work.`
|
|
|
2387
2323
|
// Message text is at the bottom of the terminal but the
|
|
2388
2324
|
// prompt is no longer in its idle form — Enter was dropped.
|
|
2389
2325
|
// Instead of waiting and doing a full Ctrl+C + resend retry,
|
|
2390
|
-
//
|
|
2391
|
-
this.logger.warn('Message text stuck at bottom — pressing Enter to recover', {
|
|
2326
|
+
// use Tab to restore TUI focus, then Enter to submit.
|
|
2327
|
+
this.logger.warn('Message text stuck at bottom — pressing Tab+Enter to recover', {
|
|
2392
2328
|
sessionName,
|
|
2393
2329
|
attempt,
|
|
2394
2330
|
intervalMs,
|
|
2395
2331
|
});
|
|
2332
|
+
await sessionHelper.sendKey(sessionName, 'Tab');
|
|
2333
|
+
await delay(200);
|
|
2396
2334
|
await sessionHelper.sendEnter(sessionName);
|
|
2397
2335
|
await delay(500);
|
|
2398
2336
|
await sessionHelper.sendEnter(sessionName); // backup Enter
|
|
@@ -2400,7 +2338,7 @@ After checking in, just say "Ready for tasks" and wait for me to send you work.`
|
|
|
2400
2338
|
await delay(SESSION_COMMAND_DELAYS.MESSAGE_PROCESSING_DELAY);
|
|
2401
2339
|
// Verify recovery: check if processing started
|
|
2402
2340
|
const recoveryOutput = sessionHelper.capturePane(sessionName);
|
|
2403
|
-
if (
|
|
2341
|
+
if (containsSpinnerOrWorkingIndicator(recoveryOutput)) {
|
|
2404
2342
|
this.logger.info('Enter recovery successful — processing started', {
|
|
2405
2343
|
sessionName,
|
|
2406
2344
|
attempt,
|
|
@@ -2487,9 +2425,9 @@ After checking in, just say "Ready for tasks" and wait for me to send you work.`
|
|
|
2487
2425
|
.filter((line) => !beforeLines.has(line))
|
|
2488
2426
|
.join('\n');
|
|
2489
2427
|
}
|
|
2490
|
-
const hasProcessingIndicators =
|
|
2428
|
+
const hasProcessingIndicators = containsProcessingIndicator(newContent || afterOutput.slice(-500));
|
|
2491
2429
|
const hasGeminiIndicators = newContent.length > 0
|
|
2492
|
-
&&
|
|
2430
|
+
&& containsGeminiProcessingKeywords(newContent);
|
|
2493
2431
|
const significantLengthChange = Math.abs(lengthDiff) > 10;
|
|
2494
2432
|
// For Gemini CLI, contentChanged alone is sufficient evidence of
|
|
2495
2433
|
// delivery. The TUI redraws minimally (lengthDiff can be as low as
|
|
@@ -2568,19 +2506,11 @@ After checking in, just say "Ready for tasks" and wait for me to send you work.`
|
|
|
2568
2506
|
}
|
|
2569
2507
|
}
|
|
2570
2508
|
}
|
|
2571
|
-
|
|
2572
|
-
|
|
2573
|
-
|
|
2574
|
-
|
|
2575
|
-
|
|
2576
|
-
if (childAlive !== false) {
|
|
2577
|
-
this.logger.warn('Message delivery verification inconclusive but session alive — assuming success', {
|
|
2578
|
-
sessionName,
|
|
2579
|
-
maxAttempts,
|
|
2580
|
-
messageLength: message.length,
|
|
2581
|
-
});
|
|
2582
|
-
return true;
|
|
2583
|
-
}
|
|
2509
|
+
this.logger.warn('Message delivery verification failed — all attempts exhausted', {
|
|
2510
|
+
sessionName,
|
|
2511
|
+
maxAttempts,
|
|
2512
|
+
messageLength: message.length,
|
|
2513
|
+
});
|
|
2584
2514
|
this.logger.error('Message delivery failed after all retry attempts', {
|
|
2585
2515
|
sessionName,
|
|
2586
2516
|
maxAttempts,
|
|
@@ -2608,13 +2538,13 @@ After checking in, just say "Ready for tasks" and wait for me to send you work.`
|
|
|
2608
2538
|
}
|
|
2609
2539
|
// Extract a search token from the message:
|
|
2610
2540
|
// Strip [CHAT:uuid] prefix if present, then take the first 40 chars
|
|
2611
|
-
const
|
|
2612
|
-
const contentAfterPrefix =
|
|
2613
|
-
? message.slice(
|
|
2541
|
+
const { prefixLength } = extractChatPrefix(message);
|
|
2542
|
+
const contentAfterPrefix = prefixLength > 0
|
|
2543
|
+
? message.slice(prefixLength)
|
|
2614
2544
|
: message;
|
|
2615
2545
|
const searchToken = contentAfterPrefix.slice(0, 40).trim();
|
|
2616
2546
|
// Also use [CHAT: as a secondary token if message has a CHAT prefix
|
|
2617
|
-
const chatToken =
|
|
2547
|
+
const chatToken = prefixLength > 0 ? '[CHAT:' : null;
|
|
2618
2548
|
// Check last 20 non-empty lines for either token.
|
|
2619
2549
|
// Gemini CLI TUI has status bars at the bottom (branch, sandbox, model info)
|
|
2620
2550
|
// that push input content further up. 5 lines was insufficient.
|
|
@@ -2622,7 +2552,7 @@ After checking in, just say "Ready for tasks" and wait for me to send you work.`
|
|
|
2622
2552
|
const linesToCheck = lines.slice(-20);
|
|
2623
2553
|
const isStuck = linesToCheck.some((line) => {
|
|
2624
2554
|
// Strip TUI box-drawing borders before checking (Gemini CLI wraps content in │...│)
|
|
2625
|
-
const stripped = line
|
|
2555
|
+
const stripped = stripTuiLineBorders(line);
|
|
2626
2556
|
if (searchToken && (line.includes(searchToken) || stripped.includes(searchToken)))
|
|
2627
2557
|
return true;
|
|
2628
2558
|
if (chatToken && (line.includes(chatToken) || stripped.includes(chatToken)))
|
|
@@ -2672,9 +2602,9 @@ After checking in, just say "Ready for tasks" and wait for me to send you work.`
|
|
|
2672
2602
|
return false;
|
|
2673
2603
|
// Extract search token: first 30 chars of the message content
|
|
2674
2604
|
// (after stripping any [CHAT:uuid] prefix)
|
|
2675
|
-
const
|
|
2676
|
-
const contentAfterPrefix =
|
|
2677
|
-
? message.slice(
|
|
2605
|
+
const { prefixLength } = extractChatPrefix(message);
|
|
2606
|
+
const contentAfterPrefix = prefixLength > 0
|
|
2607
|
+
? message.slice(prefixLength)
|
|
2678
2608
|
: message;
|
|
2679
2609
|
const searchToken = contentAfterPrefix.slice(0, 30).trim();
|
|
2680
2610
|
if (!searchToken)
|
|
@@ -2684,14 +2614,13 @@ After checking in, just say "Ready for tasks" and wait for me to send you work.`
|
|
|
2684
2614
|
// Or without borders: > text
|
|
2685
2615
|
// The prompt line is the line with `> ` followed by actual content.
|
|
2686
2616
|
const lines = output.split('\n');
|
|
2687
|
-
const promptLineRegex = /^[│┃║|\s]*>\s+(.+)/;
|
|
2688
2617
|
for (let i = lines.length - 1; i >= Math.max(0, lines.length - 25); i--) {
|
|
2689
2618
|
const line = lines[i];
|
|
2690
|
-
const
|
|
2691
|
-
if (
|
|
2692
|
-
const
|
|
2619
|
+
const promptContent = matchTuiPromptLine(line);
|
|
2620
|
+
if (promptContent !== null) {
|
|
2621
|
+
const trimmedContent = stripTuiLineBorders(promptContent).trim();
|
|
2693
2622
|
// Check if the prompt line content contains our message text
|
|
2694
|
-
if (
|
|
2623
|
+
if (trimmedContent.length > 5 && trimmedContent.includes(searchToken)) {
|
|
2695
2624
|
this.logger.warn('Text stuck at TUI prompt — Enter was not pressed', {
|
|
2696
2625
|
sessionName,
|
|
2697
2626
|
searchToken: searchToken.slice(0, 20),
|
|
@@ -2721,8 +2650,12 @@ After checking in, just say "Ready for tasks" and wait for me to send you work.`
|
|
|
2721
2650
|
*/
|
|
2722
2651
|
async recoverStuckTuiMessage(sessionName, message) {
|
|
2723
2652
|
const sessionHelper = await this.getSessionHelper();
|
|
2724
|
-
//
|
|
2725
|
-
|
|
2653
|
+
// Tab restores Ink TUI focus, then Enter to submit the stuck text.
|
|
2654
|
+
// Without Tab, Enter may be consumed by the framework but not routed
|
|
2655
|
+
// to the input component if focus was lost during a re-render.
|
|
2656
|
+
this.logger.info('Pressing Tab+Enter to recover stuck TUI message', { sessionName });
|
|
2657
|
+
await sessionHelper.sendKey(sessionName, 'Tab');
|
|
2658
|
+
await delay(200);
|
|
2726
2659
|
await sessionHelper.sendEnter(sessionName);
|
|
2727
2660
|
await delay(500);
|
|
2728
2661
|
// Double-tap: send a backup Enter in case the first was consumed
|
|
@@ -2797,7 +2730,7 @@ After checking in, just say "Ready for tasks" and wait for me to send you work.`
|
|
|
2797
2730
|
for (const sessionName of sessionHelper.listSessions()) {
|
|
2798
2731
|
try {
|
|
2799
2732
|
const output = sessionHelper.capturePane(sessionName);
|
|
2800
|
-
if (
|
|
2733
|
+
if (containsRewindMode(output)) {
|
|
2801
2734
|
this.logger.warn('Rewind mode detected, sending q to exit', { sessionName });
|
|
2802
2735
|
sessionHelper.writeRaw(sessionName, 'q');
|
|
2803
2736
|
await delay(500);
|
|
@@ -2820,27 +2753,29 @@ After checking in, just say "Ready for tasks" and wait for me to send you work.`
|
|
|
2820
2753
|
continue;
|
|
2821
2754
|
// Look for any text sitting on the prompt line
|
|
2822
2755
|
const lines = output.split('\n');
|
|
2823
|
-
const promptLineRegex = /^[│┃║|\s]*>\s+(.+)/;
|
|
2824
2756
|
for (let i = lines.length - 1; i >= Math.max(0, lines.length - 25); i--) {
|
|
2825
|
-
const
|
|
2826
|
-
if (
|
|
2827
|
-
const
|
|
2757
|
+
const promptContent = matchTuiPromptLine(lines[i]);
|
|
2758
|
+
if (promptContent !== null) {
|
|
2759
|
+
const trimmedContent = stripTuiLineBorders(promptContent).trim();
|
|
2828
2760
|
// Only act on substantial text (> 10 chars) to avoid false positives
|
|
2829
2761
|
// from TUI rendering artifacts or short status text
|
|
2830
|
-
if (
|
|
2762
|
+
if (trimmedContent.length > 10) {
|
|
2831
2763
|
// Skip known Gemini CLI idle placeholder text that sits at
|
|
2832
2764
|
// the `> ` prompt when no user input is present. These are
|
|
2833
2765
|
// NOT stuck messages — they are TUI decoration.
|
|
2834
|
-
const
|
|
2835
|
-
|
|
2766
|
+
const lowerContent = trimmedContent.toLowerCase();
|
|
2767
|
+
const isPlaceholder = lowerContent.startsWith('type your message') ||
|
|
2768
|
+
trimmedContent.startsWith('@'); // e.g., "@path/to/file"
|
|
2836
2769
|
if (isPlaceholder) {
|
|
2837
2770
|
break;
|
|
2838
2771
|
}
|
|
2839
|
-
this.logger.warn('Background scan: text stuck at TUI prompt, pressing Enter', {
|
|
2772
|
+
this.logger.warn('Background scan: text stuck at TUI prompt, pressing Tab+Enter', {
|
|
2840
2773
|
sessionName,
|
|
2841
2774
|
promptContent: promptContent.slice(0, 80),
|
|
2842
2775
|
});
|
|
2843
|
-
//
|
|
2776
|
+
// Tab restores Ink TUI focus before Enter
|
|
2777
|
+
await sessionHelper.sendKey(sessionName, 'Tab');
|
|
2778
|
+
await delay(200);
|
|
2844
2779
|
await sessionHelper.sendEnter(sessionName);
|
|
2845
2780
|
await delay(500);
|
|
2846
2781
|
// Backup Enter
|
|
@@ -2876,11 +2811,14 @@ After checking in, just say "Ready for tasks" and wait for me to send you work.`
|
|
|
2876
2811
|
if (now - entry.sentAt < MIN_AGE_MS)
|
|
2877
2812
|
continue;
|
|
2878
2813
|
if (bottomText.includes(entry.snippet)) {
|
|
2879
|
-
this.logger.warn('Background scan: tracked message stuck, pressing Enter', {
|
|
2814
|
+
this.logger.warn('Background scan: tracked message stuck, pressing Tab+Enter', {
|
|
2880
2815
|
sessionName,
|
|
2881
2816
|
snippet: entry.snippet.slice(0, 50),
|
|
2882
2817
|
ageMs: now - entry.sentAt,
|
|
2883
2818
|
});
|
|
2819
|
+
// Tab restores Ink TUI focus before Enter
|
|
2820
|
+
await sessionHelper.sendKey(sessionName, 'Tab');
|
|
2821
|
+
await delay(200);
|
|
2884
2822
|
await sessionHelper.sendEnter(sessionName);
|
|
2885
2823
|
await delay(500);
|
|
2886
2824
|
await sessionHelper.sendEnter(sessionName); // backup
|
|
@@ -2927,8 +2865,8 @@ After checking in, just say "Ready for tasks" and wait for me to send you work.`
|
|
|
2927
2865
|
*/
|
|
2928
2866
|
trackSentMessage(sessionName, message) {
|
|
2929
2867
|
// Extract a search snippet: skip [CHAT:uuid] prefix, take first 80 chars
|
|
2930
|
-
const
|
|
2931
|
-
const contentStart =
|
|
2868
|
+
const { prefixLength } = extractChatPrefix(message);
|
|
2869
|
+
const contentStart = prefixLength;
|
|
2932
2870
|
// Normalize whitespace: messages may contain \n from enhanced templates.
|
|
2933
2871
|
// Terminal bottom text is join(' '), so \n in snippet would never match.
|
|
2934
2872
|
const snippet = message.slice(contentStart, contentStart + 80).replace(/\s+/g, ' ').trim();
|
|
@@ -2942,27 +2880,10 @@ After checking in, just say "Ready for tasks" and wait for me to send you work.`
|
|
|
2942
2880
|
// Ensure the background scanner is running
|
|
2943
2881
|
this.startStuckMessageDetector();
|
|
2944
2882
|
}
|
|
2945
|
-
/**
|
|
2946
|
-
* Get the runtime-specific prompt regex pattern.
|
|
2947
|
-
* Avoids false positives by using narrow patterns when runtime is known.
|
|
2948
|
-
*
|
|
2949
|
-
* @param runtimeType - The runtime type (claude-code, gemini-cli, etc.)
|
|
2950
|
-
* @returns The appropriate prompt detection regex
|
|
2951
|
-
*/
|
|
2952
|
-
getPromptPatternForRuntime(runtimeType) {
|
|
2953
|
-
if (runtimeType === RUNTIME_TYPES.CLAUDE_CODE)
|
|
2954
|
-
return TERMINAL_PATTERNS.CLAUDE_CODE_PROMPT;
|
|
2955
|
-
if (runtimeType === RUNTIME_TYPES.GEMINI_CLI)
|
|
2956
|
-
return TERMINAL_PATTERNS.GEMINI_CLI_PROMPT;
|
|
2957
|
-
if (runtimeType === RUNTIME_TYPES.CODEX_CLI)
|
|
2958
|
-
return TERMINAL_PATTERNS.CODEX_CLI_PROMPT;
|
|
2959
|
-
return TERMINAL_PATTERNS.PROMPT_STREAM;
|
|
2960
|
-
}
|
|
2961
2883
|
/**
|
|
2962
2884
|
* Check if the agent appears to be at an input prompt.
|
|
2963
|
-
*
|
|
2964
|
-
*
|
|
2965
|
-
* to avoid false negatives when the agent is processing.
|
|
2885
|
+
* Delegates to the regex-free isAgentAtPrompt() from terminal-string-ops,
|
|
2886
|
+
* with additional logging and per-line prompt detection using isPromptLine().
|
|
2966
2887
|
*
|
|
2967
2888
|
* @param terminalOutput - The terminal output to check
|
|
2968
2889
|
* @param runtimeType - The runtime type for pattern selection
|
|
@@ -2979,57 +2900,12 @@ After checking in, just say "Ready for tasks" and wait for me to send you work.`
|
|
|
2979
2900
|
// Use 5000 chars to accommodate large tool outputs that push the prompt
|
|
2980
2901
|
// further back in the buffer (#106).
|
|
2981
2902
|
const tailSection = terminalOutput.slice(-5000);
|
|
2982
|
-
const isGemini = runtimeType === RUNTIME_TYPES.GEMINI_CLI;
|
|
2983
|
-
const isClaudeCode = runtimeType === RUNTIME_TYPES.CLAUDE_CODE;
|
|
2984
|
-
const isCodex = runtimeType === RUNTIME_TYPES.CODEX_CLI;
|
|
2985
|
-
const streamPattern = this.getPromptPatternForRuntime(runtimeType);
|
|
2986
2903
|
// Check for prompt FIRST. Processing indicators like "thinking" or "analyzing"
|
|
2987
2904
|
// can appear in the agent's previous response text and persist in the terminal
|
|
2988
2905
|
// scroll buffer, causing false negatives if checked before the prompt.
|
|
2989
|
-
if (streamPattern.test(tailSection)) {
|
|
2990
|
-
return true;
|
|
2991
|
-
}
|
|
2992
|
-
// Fallback: check last several lines for prompt indicators.
|
|
2993
|
-
// The prompt may not be on the very last line due to status bars,
|
|
2994
|
-
// notifications, or terminal wrapping below the prompt.
|
|
2995
2906
|
const lines = tailSection.split('\n').filter((line) => line.trim().length > 0);
|
|
2996
2907
|
const linesToCheck = lines.slice(-10);
|
|
2997
|
-
const hasPrompt = linesToCheck.some(
|
|
2998
|
-
const trimmed = line.trim();
|
|
2999
|
-
// Strip TUI box-drawing borders that Gemini CLI and other TUI frameworks
|
|
3000
|
-
// wrap around prompts. Covers full Unicode box-drawing range (#106).
|
|
3001
|
-
const stripped = trimmed
|
|
3002
|
-
.replace(/^[\u2500-\u257F|+\-═║╭╮╰╯]+\s*/, '')
|
|
3003
|
-
.replace(/\s*[\u2500-\u257F|+\-═║╭╮╰╯]+$/, '');
|
|
3004
|
-
// Claude Code prompts: ❯, ⏵, $ alone on a line
|
|
3005
|
-
if (!isGemini && !isCodex) {
|
|
3006
|
-
if (['❯', '⏵', '$'].some(ch => trimmed === ch || stripped === ch)) {
|
|
3007
|
-
return true;
|
|
3008
|
-
}
|
|
3009
|
-
// ❯❯ = bypass permissions prompt (idle).
|
|
3010
|
-
// Matches "❯❯", "❯❯ ", and "❯❯ bypass permissions on (shift+tab to cycle)".
|
|
3011
|
-
// Note: ⏵⏵ appears in the status bar but is visible both when idle AND
|
|
3012
|
-
// busy, so it cannot be used as a reliable prompt indicator.
|
|
3013
|
-
if (trimmed.startsWith('❯❯')) {
|
|
3014
|
-
return true;
|
|
3015
|
-
}
|
|
3016
|
-
}
|
|
3017
|
-
// Gemini CLI prompts: > or ! followed by space
|
|
3018
|
-
if (!isClaudeCode) {
|
|
3019
|
-
if (isCodex) {
|
|
3020
|
-
// Codex prompt uses `›`; avoid plain `> ` to prevent false-positives
|
|
3021
|
-
// from markdown blockquotes in agent output.
|
|
3022
|
-
if (trimmed.startsWith('› ') || stripped.startsWith('› ')) {
|
|
3023
|
-
return true;
|
|
3024
|
-
}
|
|
3025
|
-
}
|
|
3026
|
-
else if (trimmed.startsWith('> ') || trimmed.startsWith('! ') ||
|
|
3027
|
-
stripped.startsWith('> ') || stripped.startsWith('! ')) {
|
|
3028
|
-
return true;
|
|
3029
|
-
}
|
|
3030
|
-
}
|
|
3031
|
-
return false;
|
|
3032
|
-
});
|
|
2908
|
+
const hasPrompt = linesToCheck.some(line => isPromptLine(line, runtimeType));
|
|
3033
2909
|
if (hasPrompt) {
|
|
3034
2910
|
return true;
|
|
3035
2911
|
}
|
|
@@ -3037,14 +2913,14 @@ After checking in, just say "Ready for tasks" and wait for me to send you work.`
|
|
|
3037
2913
|
// Check last 10 lines (not just 5) because tool output can push processing
|
|
3038
2914
|
// indicators further up while the status bar stays at the bottom.
|
|
3039
2915
|
const recentLines = linesToCheck.join('\n');
|
|
3040
|
-
if (
|
|
2916
|
+
if (containsProcessingIndicator(recentLines)) {
|
|
3041
2917
|
this.logger.debug('Processing indicators present near bottom of output');
|
|
3042
2918
|
return false;
|
|
3043
2919
|
}
|
|
3044
2920
|
// Check for "esc to interrupt" in the status bar — this is a definitive
|
|
3045
2921
|
// busy signal. Claude Code only shows this text while actively processing.
|
|
3046
2922
|
// It disappears when the agent returns to idle at the prompt.
|
|
3047
|
-
if (
|
|
2923
|
+
if (containsBusyStatusBar(recentLines)) {
|
|
3048
2924
|
this.logger.debug('Busy status bar detected (esc to interrupt)');
|
|
3049
2925
|
return false;
|
|
3050
2926
|
}
|
|
@@ -3302,7 +3178,7 @@ After checking in, just say "Ready for tasks" and wait for me to send you work.`
|
|
|
3302
3178
|
return false;
|
|
3303
3179
|
const currentOutput = sessionHelper.capturePane(sessionName);
|
|
3304
3180
|
// Processing indicators (spinners) = definitive success
|
|
3305
|
-
if (
|
|
3181
|
+
if (containsSpinnerOrWorkingIndicator(currentOutput)) {
|
|
3306
3182
|
this.logger.debug('Kickoff delivered — processing indicators detected', {
|
|
3307
3183
|
sessionName, checkIndex: i,
|
|
3308
3184
|
});
|