crewly 1.12.1 → 1.13.1
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/config/skills/_common/complete-body-shape.test.sh +113 -0
- package/config/skills/_common/no-dangling-symlinks.test.sh +63 -0
- package/config/skills/_common/task-pool-body-shape.test.sh +471 -0
- package/config/skills/agent/core/accept-task/execute.sh +30 -5
- package/config/skills/agent/core/block-task/execute.sh +59 -6
- package/config/skills/agent/core/complete-task/SKILL.md +37 -5
- package/config/skills/agent/core/complete-task/execute.sh +40 -9
- package/config/skills/agent/core/complete-task/execute.test.sh +213 -0
- package/config/skills/agent/core/create-task/SKILL.md +33 -0
- package/config/skills/agent/core/create-task/execute.sh +82 -23
- package/config/skills/agent/core/delegate-task/execute.sh +46 -0
- package/config/skills/agent/core/get-team-norms/SKILL.md +1 -1
- package/config/skills/agent/core/get-team-norms/execute.sh +73 -2
- package/config/skills/agent/core/handoff-task/execute.sh +8 -1
- package/config/skills/agent/core/report-status/SKILL.md +26 -0
- package/config/skills/agent/core/report-status/execute.sh +40 -5
- package/config/skills/orchestrator/delegate-task/SKILL.md +1 -1
- package/config/skills/orchestrator/delegate-task/execute.sh +45 -11
- package/config/skills/orchestrator/delegate-task/execute.test.sh +153 -1
- package/config/skills/team-leader/aggregate-results/SKILL.md +1 -1
- package/config/skills/team-leader/decompose-goal/execute.sh +11 -16
- package/config/skills/team-leader/delegate-task/SKILL.md +14 -1
- package/config/skills/team-leader/delegate-task/execute.sh +132 -43
- package/config/skills/team-leader/delegate-task/execute.test.sh +180 -27
- package/config/vitest-exclude.constants.ts +56 -0
- package/dist/backend/backend/src/controllers/chat/chat.controller.d.ts.map +1 -1
- package/dist/backend/backend/src/controllers/chat/chat.controller.js +29 -7
- package/dist/backend/backend/src/controllers/chat/chat.controller.js.map +1 -1
- package/dist/backend/backend/src/controllers/cloud/cloud.controller.d.ts.map +1 -1
- package/dist/backend/backend/src/controllers/cloud/cloud.controller.js +1 -1
- package/dist/backend/backend/src/controllers/cloud/cloud.controller.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 -3
- package/dist/backend/backend/src/controllers/monitoring/terminal.controller.js.map +1 -1
- package/dist/backend/backend/src/controllers/slack/slack.controller.d.ts.map +1 -1
- package/dist/backend/backend/src/controllers/slack/slack.controller.js +18 -15
- package/dist/backend/backend/src/controllers/slack/slack.controller.js.map +1 -1
- package/dist/backend/backend/src/controllers/task-pool/task-pool.controller.d.ts +6 -1
- package/dist/backend/backend/src/controllers/task-pool/task-pool.controller.d.ts.map +1 -1
- package/dist/backend/backend/src/controllers/task-pool/task-pool.controller.js +19 -10
- package/dist/backend/backend/src/controllers/task-pool/task-pool.controller.js.map +1 -1
- package/dist/backend/backend/src/index.d.ts.map +1 -1
- package/dist/backend/backend/src/index.js +20 -0
- package/dist/backend/backend/src/index.js.map +1 -1
- package/dist/backend/backend/src/scripts/stamp-build.d.ts +25 -0
- package/dist/backend/backend/src/scripts/stamp-build.d.ts.map +1 -0
- package/dist/backend/backend/src/scripts/stamp-build.js +48 -0
- package/dist/backend/backend/src/scripts/stamp-build.js.map +1 -0
- 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 +33 -1
- package/dist/backend/backend/src/services/agent/agent-registration.service.js.map +1 -1
- package/dist/backend/backend/src/services/agent/crewly-agent/crewly-agent-external-runtime.service.d.ts +78 -2
- package/dist/backend/backend/src/services/agent/crewly-agent/crewly-agent-external-runtime.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/agent/crewly-agent/crewly-agent-external-runtime.service.js +248 -44
- package/dist/backend/backend/src/services/agent/crewly-agent/crewly-agent-external-runtime.service.js.map +1 -1
- package/dist/backend/backend/src/services/agent/crewly-agent/types.d.ts +51 -3
- package/dist/backend/backend/src/services/agent/crewly-agent/types.d.ts.map +1 -1
- package/dist/backend/backend/src/services/agent/crewly-agent/types.js +31 -1
- package/dist/backend/backend/src/services/agent/crewly-agent/types.js.map +1 -1
- package/dist/backend/backend/src/services/cloud/cloud-client.service.d.ts +5 -0
- package/dist/backend/backend/src/services/cloud/cloud-client.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/cloud/cloud-client.service.js +7 -0
- package/dist/backend/backend/src/services/cloud/cloud-client.service.js.map +1 -1
- package/dist/backend/backend/src/services/event-bus/event-to-workitem-bridge.service.d.ts +15 -0
- package/dist/backend/backend/src/services/event-bus/event-to-workitem-bridge.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/event-bus/event-to-workitem-bridge.service.js +40 -0
- package/dist/backend/backend/src/services/event-bus/event-to-workitem-bridge.service.js.map +1 -1
- package/dist/backend/backend/src/services/orchestrator/commitment-approval-guard.d.ts.map +1 -1
- package/dist/backend/backend/src/services/orchestrator/commitment-approval-guard.js +26 -0
- package/dist/backend/backend/src/services/orchestrator/commitment-approval-guard.js.map +1 -1
- package/dist/backend/backend/src/services/orchestrator/onboarding/materialize-team.d.ts.map +1 -1
- package/dist/backend/backend/src/services/orchestrator/onboarding/materialize-team.js +19 -3
- package/dist/backend/backend/src/services/orchestrator/onboarding/materialize-team.js.map +1 -1
- package/dist/backend/backend/src/services/orchestrator/orchestrator-status.service.d.ts +28 -3
- package/dist/backend/backend/src/services/orchestrator/orchestrator-status.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/orchestrator/orchestrator-status.service.js +65 -8
- package/dist/backend/backend/src/services/orchestrator/orchestrator-status.service.js.map +1 -1
- package/dist/backend/backend/src/services/reconciler/reconcile-rules.d.ts +214 -4
- package/dist/backend/backend/src/services/reconciler/reconcile-rules.d.ts.map +1 -1
- package/dist/backend/backend/src/services/reconciler/reconcile-rules.js +330 -48
- package/dist/backend/backend/src/services/reconciler/reconcile-rules.js.map +1 -1
- package/dist/backend/backend/src/services/reconciler/reconciler-data-provider.d.ts +13 -1
- package/dist/backend/backend/src/services/reconciler/reconciler-data-provider.d.ts.map +1 -1
- package/dist/backend/backend/src/services/reconciler/reconciler-data-provider.js +84 -5
- package/dist/backend/backend/src/services/reconciler/reconciler-data-provider.js.map +1 -1
- package/dist/backend/backend/src/services/reconciler/reconciler.service.d.ts +14 -0
- package/dist/backend/backend/src/services/reconciler/reconciler.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/reconciler/reconciler.service.js +77 -3
- package/dist/backend/backend/src/services/reconciler/reconciler.service.js.map +1 -1
- package/dist/backend/backend/src/services/task-pool/task-pool.service.d.ts +152 -7
- package/dist/backend/backend/src/services/task-pool/task-pool.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/task-pool/task-pool.service.js +268 -36
- package/dist/backend/backend/src/services/task-pool/task-pool.service.js.map +1 -1
- package/dist/backend/backend/src/services/v3/escalation-router.service.js +2 -2
- package/dist/backend/backend/src/services/v3/escalation-router.service.js.map +1 -1
- package/dist/backend/backend/src/services/v3/request-sla.subscriber.d.ts.map +1 -1
- package/dist/backend/backend/src/services/v3/request-sla.subscriber.js +39 -2
- package/dist/backend/backend/src/services/v3/request-sla.subscriber.js.map +1 -1
- package/dist/backend/backend/src/services/wiki/wiki-migrate.service.d.ts +3 -0
- package/dist/backend/backend/src/services/wiki/wiki-migrate.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/wiki/wiki-migrate.service.js +21 -10
- package/dist/backend/backend/src/services/wiki/wiki-migrate.service.js.map +1 -1
- package/dist/backend/backend/src/types/v2/index.d.ts +1 -1
- package/dist/backend/backend/src/types/v2/index.d.ts.map +1 -1
- package/dist/backend/backend/src/types/v2/index.js +1 -1
- package/dist/backend/backend/src/types/v2/index.js.map +1 -1
- package/dist/backend/backend/src/types/v2/work-item.types.d.ts +181 -1
- package/dist/backend/backend/src/types/v2/work-item.types.d.ts.map +1 -1
- package/dist/backend/backend/src/types/v2/work-item.types.js +104 -17
- package/dist/backend/backend/src/types/v2/work-item.types.js.map +1 -1
- package/dist/backend/backend/src/utils/build-provenance.d.ts +150 -0
- package/dist/backend/backend/src/utils/build-provenance.d.ts.map +1 -0
- package/dist/backend/backend/src/utils/build-provenance.js +211 -0
- package/dist/backend/backend/src/utils/build-provenance.js.map +1 -0
- package/dist/backend/backend/src/websocket/chat.gateway.d.ts.map +1 -1
- package/dist/backend/backend/src/websocket/chat.gateway.js +7 -1
- package/dist/backend/backend/src/websocket/chat.gateway.js.map +1 -1
- package/dist/backend/build-info.json +4 -0
- package/dist/backend/config/vitest-exclude.constants.d.ts +53 -0
- package/dist/backend/config/vitest-exclude.constants.d.ts.map +1 -0
- package/dist/backend/config/vitest-exclude.constants.js +55 -0
- package/dist/backend/config/vitest-exclude.constants.js.map +1 -0
- package/dist/cli/backend/src/services/agent/active-work-briefing.service.d.ts +538 -0
- package/dist/cli/backend/src/services/agent/active-work-briefing.service.d.ts.map +1 -0
- package/dist/cli/backend/src/services/agent/active-work-briefing.service.js +802 -0
- package/dist/cli/backend/src/services/agent/active-work-briefing.service.js.map +1 -0
- package/dist/cli/backend/src/services/agent/agent-heartbeat.service.d.ts +240 -0
- package/dist/cli/backend/src/services/agent/agent-heartbeat.service.d.ts.map +1 -0
- package/dist/cli/backend/src/services/agent/agent-heartbeat.service.js +524 -0
- package/dist/cli/backend/src/services/agent/agent-heartbeat.service.js.map +1 -0
- package/dist/cli/backend/src/services/agent/agent-registration.service.d.ts +629 -0
- package/dist/cli/backend/src/services/agent/agent-registration.service.d.ts.map +1 -0
- package/dist/cli/backend/src/services/agent/agent-registration.service.js +4548 -0
- package/dist/cli/backend/src/services/agent/agent-registration.service.js.map +1 -0
- package/dist/cli/backend/src/services/agent/agent-suspend.service.d.ts +118 -0
- package/dist/cli/backend/src/services/agent/agent-suspend.service.d.ts.map +1 -0
- package/dist/cli/backend/src/services/agent/agent-suspend.service.js +304 -0
- package/dist/cli/backend/src/services/agent/agent-suspend.service.js.map +1 -0
- package/dist/cli/backend/src/services/agent/auditor-scheduler.service.d.ts +196 -0
- package/dist/cli/backend/src/services/agent/auditor-scheduler.service.d.ts.map +1 -0
- package/dist/cli/backend/src/services/agent/auditor-scheduler.service.js +504 -0
- package/dist/cli/backend/src/services/agent/auditor-scheduler.service.js.map +1 -0
- package/dist/cli/backend/src/services/agent/claude-runtime.service.d.ts +97 -0
- package/dist/cli/backend/src/services/agent/claude-runtime.service.d.ts.map +1 -0
- package/dist/cli/backend/src/services/agent/claude-runtime.service.js +334 -0
- package/dist/cli/backend/src/services/agent/claude-runtime.service.js.map +1 -0
- package/dist/cli/backend/src/services/agent/codex-runtime.service.d.ts +47 -0
- package/dist/cli/backend/src/services/agent/codex-runtime.service.d.ts.map +1 -0
- package/dist/cli/backend/src/services/agent/codex-runtime.service.js +112 -0
- package/dist/cli/backend/src/services/agent/codex-runtime.service.js.map +1 -0
- package/dist/cli/backend/src/services/agent/context-window-monitor.service.d.ts +323 -0
- package/dist/cli/backend/src/services/agent/context-window-monitor.service.d.ts.map +1 -0
- package/dist/cli/backend/src/services/agent/context-window-monitor.service.js +1056 -0
- package/dist/cli/backend/src/services/agent/context-window-monitor.service.js.map +1 -0
- package/dist/cli/backend/src/services/agent/crewly-agent/crewly-agent-external-runtime.service.d.ts +198 -0
- package/dist/cli/backend/src/services/agent/crewly-agent/crewly-agent-external-runtime.service.d.ts.map +1 -0
- package/dist/cli/backend/src/services/agent/crewly-agent/crewly-agent-external-runtime.service.js +816 -0
- package/dist/cli/backend/src/services/agent/crewly-agent/crewly-agent-external-runtime.service.js.map +1 -0
- package/dist/cli/backend/src/services/agent/crewly-agent/in-process-log-buffer.d.ts +155 -0
- package/dist/cli/backend/src/services/agent/crewly-agent/in-process-log-buffer.d.ts.map +1 -0
- package/dist/cli/backend/src/services/agent/crewly-agent/in-process-log-buffer.js +272 -0
- package/dist/cli/backend/src/services/agent/crewly-agent/in-process-log-buffer.js.map +1 -0
- package/dist/cli/backend/src/services/agent/crewly-agent/in-process-runtime-registry.d.ts +91 -0
- package/dist/cli/backend/src/services/agent/crewly-agent/in-process-runtime-registry.d.ts.map +1 -0
- package/dist/cli/backend/src/services/agent/crewly-agent/in-process-runtime-registry.js +120 -0
- package/dist/cli/backend/src/services/agent/crewly-agent/in-process-runtime-registry.js.map +1 -0
- package/dist/cli/backend/src/services/agent/crewly-agent/types.d.ts +536 -0
- package/dist/cli/backend/src/services/agent/crewly-agent/types.d.ts.map +1 -0
- package/dist/cli/backend/src/services/agent/crewly-agent/types.js +282 -0
- package/dist/cli/backend/src/services/agent/crewly-agent/types.js.map +1 -0
- package/dist/cli/backend/src/services/agent/disk-cleanup.service.d.ts +100 -0
- package/dist/cli/backend/src/services/agent/disk-cleanup.service.d.ts.map +1 -0
- package/dist/cli/backend/src/services/agent/disk-cleanup.service.js +149 -0
- package/dist/cli/backend/src/services/agent/disk-cleanup.service.js.map +1 -0
- package/dist/cli/backend/src/services/agent/gemini-runtime.service.d.ts +130 -0
- package/dist/cli/backend/src/services/agent/gemini-runtime.service.d.ts.map +1 -0
- package/dist/cli/backend/src/services/agent/gemini-runtime.service.js +758 -0
- package/dist/cli/backend/src/services/agent/gemini-runtime.service.js.map +1 -0
- package/dist/cli/backend/src/services/agent/oauth-relogin-monitor.service.d.ts +216 -0
- package/dist/cli/backend/src/services/agent/oauth-relogin-monitor.service.d.ts.map +1 -0
- package/dist/cli/backend/src/services/agent/oauth-relogin-monitor.service.js +508 -0
- package/dist/cli/backend/src/services/agent/oauth-relogin-monitor.service.js.map +1 -0
- package/dist/cli/backend/src/services/agent/pty-activity-tracker.service.d.ts +113 -0
- package/dist/cli/backend/src/services/agent/pty-activity-tracker.service.d.ts.map +1 -0
- package/dist/cli/backend/src/services/agent/pty-activity-tracker.service.js +161 -0
- package/dist/cli/backend/src/services/agent/pty-activity-tracker.service.js.map +1 -0
- package/dist/cli/backend/src/services/agent/runtime-agent.service.abstract.d.ts +156 -0
- package/dist/cli/backend/src/services/agent/runtime-agent.service.abstract.d.ts.map +1 -0
- package/dist/cli/backend/src/services/agent/runtime-agent.service.abstract.js +641 -0
- package/dist/cli/backend/src/services/agent/runtime-agent.service.abstract.js.map +1 -0
- package/dist/cli/backend/src/services/agent/runtime-exit-monitor.service.d.ts +295 -0
- package/dist/cli/backend/src/services/agent/runtime-exit-monitor.service.d.ts.map +1 -0
- package/dist/cli/backend/src/services/agent/runtime-exit-monitor.service.js +1166 -0
- package/dist/cli/backend/src/services/agent/runtime-exit-monitor.service.js.map +1 -0
- package/dist/cli/backend/src/services/agent/runtime-service.factory.d.ts +71 -0
- package/dist/cli/backend/src/services/agent/runtime-service.factory.d.ts.map +1 -0
- package/dist/cli/backend/src/services/agent/runtime-service.factory.js +174 -0
- package/dist/cli/backend/src/services/agent/runtime-service.factory.js.map +1 -0
- package/dist/cli/backend/src/services/ai/prompt-builder.service.d.ts +435 -0
- package/dist/cli/backend/src/services/ai/prompt-builder.service.d.ts.map +1 -0
- package/dist/cli/backend/src/services/ai/prompt-builder.service.js +1331 -0
- package/dist/cli/backend/src/services/ai/prompt-builder.service.js.map +1 -0
- package/dist/cli/backend/src/services/ai/prompt-modules/capability-overlay.module.d.ts +33 -0
- package/dist/cli/backend/src/services/ai/prompt-modules/capability-overlay.module.d.ts.map +1 -0
- package/dist/cli/backend/src/services/ai/prompt-modules/capability-overlay.module.js +70 -0
- package/dist/cli/backend/src/services/ai/prompt-modules/capability-overlay.module.js.map +1 -0
- package/dist/cli/backend/src/services/ai/prompt-modules/communication.module.d.ts +100 -0
- package/dist/cli/backend/src/services/ai/prompt-modules/communication.module.d.ts.map +1 -0
- package/dist/cli/backend/src/services/ai/prompt-modules/communication.module.js +296 -0
- package/dist/cli/backend/src/services/ai/prompt-modules/communication.module.js.map +1 -0
- package/dist/cli/backend/src/services/ai/prompt-modules/decision-rights.module.d.ts +59 -0
- package/dist/cli/backend/src/services/ai/prompt-modules/decision-rights.module.d.ts.map +1 -0
- package/dist/cli/backend/src/services/ai/prompt-modules/decision-rights.module.js +87 -0
- package/dist/cli/backend/src/services/ai/prompt-modules/decision-rights.module.js.map +1 -0
- package/dist/cli/backend/src/services/ai/prompt-modules/default-execution-loop.module.d.ts +67 -0
- package/dist/cli/backend/src/services/ai/prompt-modules/default-execution-loop.module.d.ts.map +1 -0
- package/dist/cli/backend/src/services/ai/prompt-modules/default-execution-loop.module.js +84 -0
- package/dist/cli/backend/src/services/ai/prompt-modules/default-execution-loop.module.js.map +1 -0
- package/dist/cli/backend/src/services/ai/prompt-modules/domain-sop.module.d.ts +35 -0
- package/dist/cli/backend/src/services/ai/prompt-modules/domain-sop.module.d.ts.map +1 -0
- package/dist/cli/backend/src/services/ai/prompt-modules/domain-sop.module.js +50 -0
- package/dist/cli/backend/src/services/ai/prompt-modules/domain-sop.module.js.map +1 -0
- package/dist/cli/backend/src/services/ai/prompt-modules/expert-profile.module.d.ts +41 -0
- package/dist/cli/backend/src/services/ai/prompt-modules/expert-profile.module.d.ts.map +1 -0
- package/dist/cli/backend/src/services/ai/prompt-modules/expert-profile.module.js +95 -0
- package/dist/cli/backend/src/services/ai/prompt-modules/expert-profile.module.js.map +1 -0
- package/dist/cli/backend/src/services/ai/prompt-modules/identity.module.d.ts +28 -0
- package/dist/cli/backend/src/services/ai/prompt-modules/identity.module.d.ts.map +1 -0
- package/dist/cli/backend/src/services/ai/prompt-modules/identity.module.js +47 -0
- package/dist/cli/backend/src/services/ai/prompt-modules/identity.module.js.map +1 -0
- package/dist/cli/backend/src/services/ai/prompt-modules/lazy-anti-patterns.module.d.ts +65 -0
- package/dist/cli/backend/src/services/ai/prompt-modules/lazy-anti-patterns.module.d.ts.map +1 -0
- package/dist/cli/backend/src/services/ai/prompt-modules/lazy-anti-patterns.module.js +79 -0
- package/dist/cli/backend/src/services/ai/prompt-modules/lazy-anti-patterns.module.js.map +1 -0
- package/dist/cli/backend/src/services/ai/prompt-modules/learning-reference.module.d.ts +28 -0
- package/dist/cli/backend/src/services/ai/prompt-modules/learning-reference.module.d.ts.map +1 -0
- package/dist/cli/backend/src/services/ai/prompt-modules/learning-reference.module.js +55 -0
- package/dist/cli/backend/src/services/ai/prompt-modules/learning-reference.module.js.map +1 -0
- package/dist/cli/backend/src/services/ai/prompt-modules/lifecycle.module.d.ts +44 -0
- package/dist/cli/backend/src/services/ai/prompt-modules/lifecycle.module.d.ts.map +1 -0
- package/dist/cli/backend/src/services/ai/prompt-modules/lifecycle.module.js +120 -0
- package/dist/cli/backend/src/services/ai/prompt-modules/lifecycle.module.js.map +1 -0
- package/dist/cli/backend/src/services/ai/prompt-modules/markdown-file-module.d.ts +46 -0
- package/dist/cli/backend/src/services/ai/prompt-modules/markdown-file-module.d.ts.map +1 -0
- package/dist/cli/backend/src/services/ai/prompt-modules/markdown-file-module.js +44 -0
- package/dist/cli/backend/src/services/ai/prompt-modules/markdown-file-module.js.map +1 -0
- package/dist/cli/backend/src/services/ai/prompt-modules/memory-reference.module.d.ts +28 -0
- package/dist/cli/backend/src/services/ai/prompt-modules/memory-reference.module.d.ts.map +1 -0
- package/dist/cli/backend/src/services/ai/prompt-modules/memory-reference.module.js +46 -0
- package/dist/cli/backend/src/services/ai/prompt-modules/memory-reference.module.js.map +1 -0
- package/dist/cli/backend/src/services/ai/prompt-modules/mission-context.module.d.ts +60 -0
- package/dist/cli/backend/src/services/ai/prompt-modules/mission-context.module.d.ts.map +1 -0
- package/dist/cli/backend/src/services/ai/prompt-modules/mission-context.module.js +104 -0
- package/dist/cli/backend/src/services/ai/prompt-modules/mission-context.module.js.map +1 -0
- package/dist/cli/backend/src/services/ai/prompt-modules/project-reference.module.d.ts +29 -0
- package/dist/cli/backend/src/services/ai/prompt-modules/project-reference.module.d.ts.map +1 -0
- package/dist/cli/backend/src/services/ai/prompt-modules/project-reference.module.js +50 -0
- package/dist/cli/backend/src/services/ai/prompt-modules/project-reference.module.js.map +1 -0
- package/dist/cli/backend/src/services/ai/prompt-modules/prompt-assembly.service.d.ts +103 -0
- package/dist/cli/backend/src/services/ai/prompt-modules/prompt-assembly.service.d.ts.map +1 -0
- package/dist/cli/backend/src/services/ai/prompt-modules/prompt-assembly.service.js +383 -0
- package/dist/cli/backend/src/services/ai/prompt-modules/prompt-assembly.service.js.map +1 -0
- package/dist/cli/backend/src/services/ai/prompt-modules/recovery.module.d.ts +34 -0
- package/dist/cli/backend/src/services/ai/prompt-modules/recovery.module.d.ts.map +1 -0
- package/dist/cli/backend/src/services/ai/prompt-modules/recovery.module.js +96 -0
- package/dist/cli/backend/src/services/ai/prompt-modules/recovery.module.js.map +1 -0
- package/dist/cli/backend/src/services/ai/prompt-modules/request-contract.module.d.ts +106 -0
- package/dist/cli/backend/src/services/ai/prompt-modules/request-contract.module.d.ts.map +1 -0
- package/dist/cli/backend/src/services/ai/prompt-modules/request-contract.module.js +167 -0
- package/dist/cli/backend/src/services/ai/prompt-modules/request-contract.module.js.map +1 -0
- package/dist/cli/backend/src/services/ai/prompt-modules/risk-policy.module.d.ts +35 -0
- package/dist/cli/backend/src/services/ai/prompt-modules/risk-policy.module.d.ts.map +1 -0
- package/dist/cli/backend/src/services/ai/prompt-modules/risk-policy.module.js +50 -0
- package/dist/cli/backend/src/services/ai/prompt-modules/risk-policy.module.js.map +1 -0
- package/dist/cli/backend/src/services/ai/prompt-modules/role-boundary.module.d.ts +91 -0
- package/dist/cli/backend/src/services/ai/prompt-modules/role-boundary.module.d.ts.map +1 -0
- package/dist/cli/backend/src/services/ai/prompt-modules/role-boundary.module.js +411 -0
- package/dist/cli/backend/src/services/ai/prompt-modules/role-boundary.module.js.map +1 -0
- package/dist/cli/backend/src/services/ai/prompt-modules/skills-reference.module.d.ts +62 -0
- package/dist/cli/backend/src/services/ai/prompt-modules/skills-reference.module.d.ts.map +1 -0
- package/dist/cli/backend/src/services/ai/prompt-modules/skills-reference.module.js +199 -0
- package/dist/cli/backend/src/services/ai/prompt-modules/skills-reference.module.js.map +1 -0
- package/dist/cli/backend/src/services/ai/prompt-modules/sop-norm-distinction.module.d.ts +79 -0
- package/dist/cli/backend/src/services/ai/prompt-modules/sop-norm-distinction.module.d.ts.map +1 -0
- package/dist/cli/backend/src/services/ai/prompt-modules/sop-norm-distinction.module.js +118 -0
- package/dist/cli/backend/src/services/ai/prompt-modules/sop-norm-distinction.module.js.map +1 -0
- package/dist/cli/backend/src/services/ai/prompt-modules/soul.module.d.ts +102 -0
- package/dist/cli/backend/src/services/ai/prompt-modules/soul.module.d.ts.map +1 -0
- package/dist/cli/backend/src/services/ai/prompt-modules/soul.module.js +229 -0
- package/dist/cli/backend/src/services/ai/prompt-modules/soul.module.js.map +1 -0
- package/dist/cli/backend/src/services/ai/prompt-modules/team-norms.module.d.ts +61 -0
- package/dist/cli/backend/src/services/ai/prompt-modules/team-norms.module.d.ts.map +1 -0
- package/dist/cli/backend/src/services/ai/prompt-modules/team-norms.module.js +197 -0
- package/dist/cli/backend/src/services/ai/prompt-modules/team-norms.module.js.map +1 -0
- package/dist/cli/backend/src/services/ai/prompt-modules/team-reference.module.d.ts +54 -0
- package/dist/cli/backend/src/services/ai/prompt-modules/team-reference.module.d.ts.map +1 -0
- package/dist/cli/backend/src/services/ai/prompt-modules/team-reference.module.js +149 -0
- package/dist/cli/backend/src/services/ai/prompt-modules/team-reference.module.js.map +1 -0
- package/dist/cli/backend/src/services/ai/prompt-modules/user-profile-reference.module.d.ts +32 -0
- package/dist/cli/backend/src/services/ai/prompt-modules/user-profile-reference.module.d.ts.map +1 -0
- package/dist/cli/backend/src/services/ai/prompt-modules/user-profile-reference.module.js +69 -0
- package/dist/cli/backend/src/services/ai/prompt-modules/user-profile-reference.module.js.map +1 -0
- package/dist/cli/backend/src/services/ai/prompt-modules/working-memory.module.d.ts +91 -0
- package/dist/cli/backend/src/services/ai/prompt-modules/working-memory.module.d.ts.map +1 -0
- package/dist/cli/backend/src/services/ai/prompt-modules/working-memory.module.js +136 -0
- package/dist/cli/backend/src/services/ai/prompt-modules/working-memory.module.js.map +1 -0
- package/dist/cli/backend/src/services/ai/self-improvement/growth-areas.service.d.ts +81 -0
- package/dist/cli/backend/src/services/ai/self-improvement/growth-areas.service.d.ts.map +1 -0
- package/dist/cli/backend/src/services/ai/self-improvement/growth-areas.service.js +135 -0
- package/dist/cli/backend/src/services/ai/self-improvement/growth-areas.service.js.map +1 -0
- package/dist/cli/backend/src/services/chat-v2/chat-v2.service.d.ts +737 -0
- package/dist/cli/backend/src/services/chat-v2/chat-v2.service.d.ts.map +1 -0
- package/dist/cli/backend/src/services/chat-v2/chat-v2.service.js +1213 -0
- package/dist/cli/backend/src/services/chat-v2/chat-v2.service.js.map +1 -0
- package/dist/cli/backend/src/services/chat-v2/chat-v2.singleton.d.ts +27 -0
- package/dist/cli/backend/src/services/chat-v2/chat-v2.singleton.d.ts.map +1 -0
- package/dist/cli/backend/src/services/chat-v2/chat-v2.singleton.js +57 -0
- package/dist/cli/backend/src/services/chat-v2/chat-v2.singleton.js.map +1 -0
- package/dist/cli/backend/src/services/chat-v2/config.d.ts +100 -0
- package/dist/cli/backend/src/services/chat-v2/config.d.ts.map +1 -0
- package/dist/cli/backend/src/services/chat-v2/config.js +174 -0
- package/dist/cli/backend/src/services/chat-v2/config.js.map +1 -0
- package/dist/cli/backend/src/services/chat-v2/legacy-dto.utils.d.ts +118 -0
- package/dist/cli/backend/src/services/chat-v2/legacy-dto.utils.d.ts.map +1 -0
- package/dist/cli/backend/src/services/chat-v2/legacy-dto.utils.js +171 -0
- package/dist/cli/backend/src/services/chat-v2/legacy-dto.utils.js.map +1 -0
- package/dist/cli/backend/src/services/chat-v2/sqlite/channel.store.d.ts +188 -0
- package/dist/cli/backend/src/services/chat-v2/sqlite/channel.store.d.ts.map +1 -0
- package/dist/cli/backend/src/services/chat-v2/sqlite/channel.store.js +317 -0
- package/dist/cli/backend/src/services/chat-v2/sqlite/channel.store.js.map +1 -0
- package/dist/cli/backend/src/services/chat-v2/sqlite/chat-db.d.ts +119 -0
- package/dist/cli/backend/src/services/chat-v2/sqlite/chat-db.d.ts.map +1 -0
- package/dist/cli/backend/src/services/chat-v2/sqlite/chat-db.js +551 -0
- package/dist/cli/backend/src/services/chat-v2/sqlite/chat-db.js.map +1 -0
- package/dist/cli/backend/src/services/chat-v2/sqlite/message.store.d.ts +208 -0
- package/dist/cli/backend/src/services/chat-v2/sqlite/message.store.d.ts.map +1 -0
- package/dist/cli/backend/src/services/chat-v2/sqlite/message.store.js +405 -0
- package/dist/cli/backend/src/services/chat-v2/sqlite/message.store.js.map +1 -0
- package/dist/cli/backend/src/services/chat-v2/types.d.ts +341 -0
- package/dist/cli/backend/src/services/chat-v2/types.d.ts.map +1 -0
- package/dist/cli/backend/src/services/chat-v2/types.js +61 -0
- package/dist/cli/backend/src/services/chat-v2/types.js.map +1 -0
- package/dist/cli/backend/src/services/cloud/cloud-client.service.d.ts +5 -0
- package/dist/cli/backend/src/services/cloud/cloud-client.service.d.ts.map +1 -1
- package/dist/cli/backend/src/services/cloud/cloud-client.service.js +7 -0
- package/dist/cli/backend/src/services/cloud/cloud-client.service.js.map +1 -1
- package/dist/cli/backend/src/services/continuation/patterns/idle-patterns.d.ts +37 -0
- package/dist/cli/backend/src/services/continuation/patterns/idle-patterns.d.ts.map +1 -0
- package/dist/cli/backend/src/services/continuation/patterns/idle-patterns.js +63 -0
- package/dist/cli/backend/src/services/continuation/patterns/idle-patterns.js.map +1 -0
- package/dist/cli/backend/src/services/intent-task/intent-classifier.rules.d.ts +335 -0
- package/dist/cli/backend/src/services/intent-task/intent-classifier.rules.d.ts.map +1 -0
- package/dist/cli/backend/src/services/intent-task/intent-classifier.rules.js +421 -0
- package/dist/cli/backend/src/services/intent-task/intent-classifier.rules.js.map +1 -0
- package/dist/cli/backend/src/services/mcp-client.d.ts +233 -0
- package/dist/cli/backend/src/services/mcp-client.d.ts.map +1 -0
- package/dist/cli/backend/src/services/mcp-client.js +302 -0
- package/dist/cli/backend/src/services/mcp-client.js.map +1 -0
- package/dist/cli/backend/src/services/memory/mission-context.service.d.ts +168 -0
- package/dist/cli/backend/src/services/memory/mission-context.service.d.ts.map +1 -0
- package/dist/cli/backend/src/services/memory/mission-context.service.js +365 -0
- package/dist/cli/backend/src/services/memory/mission-context.service.js.map +1 -0
- package/dist/cli/backend/src/services/memory/session-memory.service.d.ts +197 -0
- package/dist/cli/backend/src/services/memory/session-memory.service.d.ts.map +1 -0
- package/dist/cli/backend/src/services/memory/session-memory.service.js +369 -0
- package/dist/cli/backend/src/services/memory/session-memory.service.js.map +1 -0
- package/dist/cli/backend/src/services/memory/user-profile.service.d.ts +77 -0
- package/dist/cli/backend/src/services/memory/user-profile.service.d.ts.map +1 -0
- package/dist/cli/backend/src/services/memory/user-profile.service.js +171 -0
- package/dist/cli/backend/src/services/memory/user-profile.service.js.map +1 -0
- package/dist/cli/backend/src/services/memory/working-memory.service.d.ts +232 -0
- package/dist/cli/backend/src/services/memory/working-memory.service.d.ts.map +1 -0
- package/dist/cli/backend/src/services/memory/working-memory.service.js +417 -0
- package/dist/cli/backend/src/services/memory/working-memory.service.js.map +1 -0
- package/dist/cli/backend/src/services/messaging/sub-agent-message-queue.service.d.ts +84 -0
- package/dist/cli/backend/src/services/messaging/sub-agent-message-queue.service.d.ts.map +1 -0
- package/dist/cli/backend/src/services/messaging/sub-agent-message-queue.service.js +136 -0
- package/dist/cli/backend/src/services/messaging/sub-agent-message-queue.service.js.map +1 -0
- package/dist/cli/backend/src/services/messaging/thread-status-queue.service.d.ts +358 -0
- package/dist/cli/backend/src/services/messaging/thread-status-queue.service.d.ts.map +1 -0
- package/dist/cli/backend/src/services/messaging/thread-status-queue.service.js +755 -0
- package/dist/cli/backend/src/services/messaging/thread-status-queue.service.js.map +1 -0
- package/dist/cli/backend/src/services/monitoring/token-usage.service.d.ts +269 -0
- package/dist/cli/backend/src/services/monitoring/token-usage.service.d.ts.map +1 -0
- package/dist/cli/backend/src/services/monitoring/token-usage.service.js +391 -0
- package/dist/cli/backend/src/services/monitoring/token-usage.service.js.map +1 -0
- package/dist/cli/backend/src/services/observability/agent-behavior-log.service.d.ts +132 -0
- package/dist/cli/backend/src/services/observability/agent-behavior-log.service.d.ts.map +1 -0
- package/dist/cli/backend/src/services/observability/agent-behavior-log.service.js +284 -0
- package/dist/cli/backend/src/services/observability/agent-behavior-log.service.js.map +1 -0
- package/dist/cli/backend/src/services/observability/agent-behavior-log.singleton.d.ts +70 -0
- package/dist/cli/backend/src/services/observability/agent-behavior-log.singleton.d.ts.map +1 -0
- package/dist/cli/backend/src/services/observability/agent-behavior-log.singleton.js +121 -0
- package/dist/cli/backend/src/services/observability/agent-behavior-log.singleton.js.map +1 -0
- package/dist/cli/backend/src/services/observability/agent-behavior-log.types.d.ts +130 -0
- package/dist/cli/backend/src/services/observability/agent-behavior-log.types.d.ts.map +1 -0
- package/dist/cli/backend/src/services/observability/agent-behavior-log.types.js +48 -0
- package/dist/cli/backend/src/services/observability/agent-behavior-log.types.js.map +1 -0
- package/dist/cli/backend/src/services/observability/observability-db.d.ts +84 -0
- package/dist/cli/backend/src/services/observability/observability-db.d.ts.map +1 -0
- package/dist/cli/backend/src/services/observability/observability-db.js +165 -0
- package/dist/cli/backend/src/services/observability/observability-db.js.map +1 -0
- package/dist/cli/backend/src/services/onboarding/content-approval.service.d.ts +124 -0
- package/dist/cli/backend/src/services/onboarding/content-approval.service.d.ts.map +1 -0
- package/dist/cli/backend/src/services/onboarding/content-approval.service.js +256 -0
- package/dist/cli/backend/src/services/onboarding/content-approval.service.js.map +1 -0
- package/dist/cli/backend/src/services/onboarding/content-approval.types.d.ts +80 -0
- package/dist/cli/backend/src/services/onboarding/content-approval.types.d.ts.map +1 -0
- package/dist/cli/backend/src/services/onboarding/content-approval.types.js +16 -0
- package/dist/cli/backend/src/services/onboarding/content-approval.types.js.map +1 -0
- package/dist/cli/backend/src/services/orc/orc-delivery-enforcer.service.d.ts +142 -0
- package/dist/cli/backend/src/services/orc/orc-delivery-enforcer.service.d.ts.map +1 -0
- package/dist/cli/backend/src/services/orc/orc-delivery-enforcer.service.js +265 -0
- package/dist/cli/backend/src/services/orc/orc-delivery-enforcer.service.js.map +1 -0
- package/dist/cli/backend/src/services/orchestrator/improvement-marker.service.d.ts +231 -0
- package/dist/cli/backend/src/services/orchestrator/improvement-marker.service.d.ts.map +1 -0
- package/dist/cli/backend/src/services/orchestrator/improvement-marker.service.js +353 -0
- package/dist/cli/backend/src/services/orchestrator/improvement-marker.service.js.map +1 -0
- package/dist/cli/backend/src/services/orchestrator/improvement-startup.service.d.ts +157 -0
- package/dist/cli/backend/src/services/orchestrator/improvement-startup.service.d.ts.map +1 -0
- package/dist/cli/backend/src/services/orchestrator/improvement-startup.service.js +483 -0
- package/dist/cli/backend/src/services/orchestrator/improvement-startup.service.js.map +1 -0
- package/dist/cli/backend/src/services/orchestrator/index.d.ts +16 -0
- package/dist/cli/backend/src/services/orchestrator/index.d.ts.map +1 -0
- package/dist/cli/backend/src/services/orchestrator/index.js +16 -0
- package/dist/cli/backend/src/services/orchestrator/index.js.map +1 -0
- package/dist/cli/backend/src/services/orchestrator/orchestrator-restart.service.d.ts +117 -0
- package/dist/cli/backend/src/services/orchestrator/orchestrator-restart.service.d.ts.map +1 -0
- package/dist/cli/backend/src/services/orchestrator/orchestrator-restart.service.js +300 -0
- package/dist/cli/backend/src/services/orchestrator/orchestrator-restart.service.js.map +1 -0
- package/dist/cli/backend/src/services/orchestrator/orchestrator-setup.service.d.ts +114 -0
- package/dist/cli/backend/src/services/orchestrator/orchestrator-setup.service.d.ts.map +1 -0
- package/dist/cli/backend/src/services/orchestrator/orchestrator-setup.service.js +195 -0
- package/dist/cli/backend/src/services/orchestrator/orchestrator-setup.service.js.map +1 -0
- package/dist/cli/backend/src/services/orchestrator/orchestrator-status.service.d.ts +94 -0
- package/dist/cli/backend/src/services/orchestrator/orchestrator-status.service.d.ts.map +1 -0
- package/dist/cli/backend/src/services/orchestrator/orchestrator-status.service.js +279 -0
- package/dist/cli/backend/src/services/orchestrator/orchestrator-status.service.js.map +1 -0
- package/dist/cli/backend/src/services/orchestrator/safe-restart.service.d.ts +192 -0
- package/dist/cli/backend/src/services/orchestrator/safe-restart.service.d.ts.map +1 -0
- package/dist/cli/backend/src/services/orchestrator/safe-restart.service.js +395 -0
- package/dist/cli/backend/src/services/orchestrator/safe-restart.service.js.map +1 -0
- package/dist/cli/backend/src/services/orchestrator/self-improvement.service.d.ts +201 -0
- package/dist/cli/backend/src/services/orchestrator/self-improvement.service.d.ts.map +1 -0
- package/dist/cli/backend/src/services/orchestrator/self-improvement.service.js +396 -0
- package/dist/cli/backend/src/services/orchestrator/self-improvement.service.js.map +1 -0
- package/dist/cli/backend/src/services/orchestrator/slack-bridge-lazy.d.ts +17 -0
- package/dist/cli/backend/src/services/orchestrator/slack-bridge-lazy.d.ts.map +1 -0
- package/dist/cli/backend/src/services/orchestrator/slack-bridge-lazy.js +30 -0
- package/dist/cli/backend/src/services/orchestrator/slack-bridge-lazy.js.map +1 -0
- package/dist/cli/backend/src/services/orchestrator/state-persistence.service.d.ts +249 -0
- package/dist/cli/backend/src/services/orchestrator/state-persistence.service.d.ts.map +1 -0
- package/dist/cli/backend/src/services/orchestrator/state-persistence.service.js +569 -0
- package/dist/cli/backend/src/services/orchestrator/state-persistence.service.js.map +1 -0
- package/dist/cli/backend/src/services/session/index.d.ts +47 -0
- package/dist/cli/backend/src/services/session/index.d.ts.map +1 -0
- package/dist/cli/backend/src/services/session/index.js +50 -0
- package/dist/cli/backend/src/services/session/index.js.map +1 -0
- package/dist/cli/backend/src/services/session/log-rotation.service.d.ts +163 -0
- package/dist/cli/backend/src/services/session/log-rotation.service.d.ts.map +1 -0
- package/dist/cli/backend/src/services/session/log-rotation.service.js +362 -0
- package/dist/cli/backend/src/services/session/log-rotation.service.js.map +1 -0
- package/dist/cli/backend/src/services/session/pty/index.d.ts +11 -0
- package/dist/cli/backend/src/services/session/pty/index.d.ts.map +1 -0
- package/dist/cli/backend/src/services/session/pty/index.js +11 -0
- package/dist/cli/backend/src/services/session/pty/index.js.map +1 -0
- package/dist/cli/backend/src/services/session/pty/pty-session-backend.d.ts +445 -0
- package/dist/cli/backend/src/services/session/pty/pty-session-backend.d.ts.map +1 -0
- package/dist/cli/backend/src/services/session/pty/pty-session-backend.js +804 -0
- package/dist/cli/backend/src/services/session/pty/pty-session-backend.js.map +1 -0
- package/dist/cli/backend/src/services/session/pty/pty-session.d.ts +252 -0
- package/dist/cli/backend/src/services/session/pty/pty-session.d.ts.map +1 -0
- package/dist/cli/backend/src/services/session/pty/pty-session.js +611 -0
- package/dist/cli/backend/src/services/session/pty/pty-session.js.map +1 -0
- package/dist/cli/backend/src/services/session/pty/pty-terminal-buffer.d.ts +275 -0
- package/dist/cli/backend/src/services/session/pty/pty-terminal-buffer.d.ts.map +1 -0
- package/dist/cli/backend/src/services/session/pty/pty-terminal-buffer.js +403 -0
- package/dist/cli/backend/src/services/session/pty/pty-terminal-buffer.js.map +1 -0
- package/dist/cli/backend/src/services/session/runtime-pid-registry.service.d.ts +86 -0
- package/dist/cli/backend/src/services/session/runtime-pid-registry.service.d.ts.map +1 -0
- package/dist/cli/backend/src/services/session/runtime-pid-registry.service.js +214 -0
- package/dist/cli/backend/src/services/session/runtime-pid-registry.service.js.map +1 -0
- package/dist/cli/backend/src/services/session/session-backend.factory.d.ts +127 -0
- package/dist/cli/backend/src/services/session/session-backend.factory.d.ts.map +1 -0
- package/dist/cli/backend/src/services/session/session-backend.factory.js +226 -0
- package/dist/cli/backend/src/services/session/session-backend.factory.js.map +1 -0
- package/dist/cli/backend/src/services/session/session-backend.interface.d.ts +390 -0
- package/dist/cli/backend/src/services/session/session-backend.interface.d.ts.map +1 -0
- package/dist/cli/backend/src/services/session/session-backend.interface.js +19 -0
- package/dist/cli/backend/src/services/session/session-backend.interface.js.map +1 -0
- package/dist/cli/backend/src/services/session/session-command-helper.d.ts +350 -0
- package/dist/cli/backend/src/services/session/session-command-helper.d.ts.map +1 -0
- package/dist/cli/backend/src/services/session/session-command-helper.js +810 -0
- package/dist/cli/backend/src/services/session/session-command-helper.js.map +1 -0
- package/dist/cli/backend/src/services/session/session-handoff.service.d.ts +307 -0
- package/dist/cli/backend/src/services/session/session-handoff.service.d.ts.map +1 -0
- package/dist/cli/backend/src/services/session/session-handoff.service.js +742 -0
- package/dist/cli/backend/src/services/session/session-handoff.service.js.map +1 -0
- package/dist/cli/backend/src/services/session/session-state-persistence.d.ts +231 -0
- package/dist/cli/backend/src/services/session/session-state-persistence.d.ts.map +1 -0
- package/dist/cli/backend/src/services/session/session-state-persistence.js +407 -0
- package/dist/cli/backend/src/services/session/session-state-persistence.js.map +1 -0
- package/dist/cli/backend/src/services/settings/role.service.d.ts +277 -0
- package/dist/cli/backend/src/services/settings/role.service.d.ts.map +1 -0
- package/dist/cli/backend/src/services/settings/role.service.js +728 -0
- package/dist/cli/backend/src/services/settings/role.service.js.map +1 -0
- package/dist/cli/backend/src/services/slack/cross-machine-message.service.d.ts +152 -0
- package/dist/cli/backend/src/services/slack/cross-machine-message.service.d.ts.map +1 -0
- package/dist/cli/backend/src/services/slack/cross-machine-message.service.js +354 -0
- package/dist/cli/backend/src/services/slack/cross-machine-message.service.js.map +1 -0
- package/dist/cli/backend/src/services/slack/slack-image.service.d.ts +114 -0
- package/dist/cli/backend/src/services/slack/slack-image.service.d.ts.map +1 -0
- package/dist/cli/backend/src/services/slack/slack-image.service.js +331 -0
- package/dist/cli/backend/src/services/slack/slack-image.service.js.map +1 -0
- package/dist/cli/backend/src/services/slack/slack-orchestrator-bridge.d.ts +499 -0
- package/dist/cli/backend/src/services/slack/slack-orchestrator-bridge.d.ts.map +1 -0
- package/dist/cli/backend/src/services/slack/slack-orchestrator-bridge.js +1928 -0
- package/dist/cli/backend/src/services/slack/slack-orchestrator-bridge.js.map +1 -0
- package/dist/cli/backend/src/services/slack/slack.service.d.ts +315 -0
- package/dist/cli/backend/src/services/slack/slack.service.d.ts.map +1 -0
- package/dist/cli/backend/src/services/slack/slack.service.js +1094 -0
- package/dist/cli/backend/src/services/slack/slack.service.js.map +1 -0
- package/dist/cli/backend/src/services/sop/sop.service.d.ts +364 -0
- package/dist/cli/backend/src/services/sop/sop.service.d.ts.map +1 -0
- package/dist/cli/backend/src/services/sop/sop.service.js +734 -0
- package/dist/cli/backend/src/services/sop/sop.service.js.map +1 -0
- package/dist/cli/backend/src/services/task-pool/task-pool.service.d.ts +152 -7
- package/dist/cli/backend/src/services/task-pool/task-pool.service.d.ts.map +1 -1
- package/dist/cli/backend/src/services/task-pool/task-pool.service.js +268 -36
- package/dist/cli/backend/src/services/task-pool/task-pool.service.js.map +1 -1
- package/dist/cli/backend/src/services/v3/escalation-router.service.d.ts +178 -0
- package/dist/cli/backend/src/services/v3/escalation-router.service.d.ts.map +1 -0
- package/dist/cli/backend/src/services/v3/escalation-router.service.js +692 -0
- package/dist/cli/backend/src/services/v3/escalation-router.service.js.map +1 -0
- package/dist/cli/backend/src/services/v3/kr-tracking.service.d.ts +200 -0
- package/dist/cli/backend/src/services/v3/kr-tracking.service.d.ts.map +1 -0
- package/dist/cli/backend/src/services/v3/kr-tracking.service.js +482 -0
- package/dist/cli/backend/src/services/v3/kr-tracking.service.js.map +1 -0
- package/dist/cli/backend/src/services/v3/mission-executor.service.d.ts +117 -0
- package/dist/cli/backend/src/services/v3/mission-executor.service.d.ts.map +1 -0
- package/dist/cli/backend/src/services/v3/mission-executor.service.js +321 -0
- package/dist/cli/backend/src/services/v3/mission-executor.service.js.map +1 -0
- package/dist/cli/backend/src/services/v3/request-sla.subscriber.d.ts +610 -0
- package/dist/cli/backend/src/services/v3/request-sla.subscriber.d.ts.map +1 -0
- package/dist/cli/backend/src/services/v3/request-sla.subscriber.js +1529 -0
- package/dist/cli/backend/src/services/v3/request-sla.subscriber.js.map +1 -0
- package/dist/cli/backend/src/services/v3/request-tracker.service.d.ts +78 -0
- package/dist/cli/backend/src/services/v3/request-tracker.service.d.ts.map +1 -0
- package/dist/cli/backend/src/services/v3/request-tracker.service.js +108 -0
- package/dist/cli/backend/src/services/v3/request-tracker.service.js.map +1 -0
- package/dist/cli/backend/src/services/v3/request.service.d.ts +295 -0
- package/dist/cli/backend/src/services/v3/request.service.d.ts.map +1 -0
- package/dist/cli/backend/src/services/v3/request.service.js +534 -0
- package/dist/cli/backend/src/services/v3/request.service.js.map +1 -0
- package/dist/cli/backend/src/services/v3/v3-data.service.d.ts +340 -0
- package/dist/cli/backend/src/services/v3/v3-data.service.d.ts.map +1 -0
- package/dist/cli/backend/src/services/v3/v3-data.service.js +1113 -0
- package/dist/cli/backend/src/services/v3/v3-data.service.js.map +1 -0
- package/dist/cli/backend/src/types/cross-machine.types.d.ts +103 -0
- package/dist/cli/backend/src/types/cross-machine.types.d.ts.map +1 -0
- package/dist/cli/backend/src/types/cross-machine.types.js +47 -0
- package/dist/cli/backend/src/types/cross-machine.types.js.map +1 -0
- package/dist/cli/backend/src/types/intent-task.types.d.ts +402 -0
- package/dist/cli/backend/src/types/intent-task.types.d.ts.map +1 -0
- package/dist/cli/backend/src/types/intent-task.types.js +403 -0
- package/dist/cli/backend/src/types/intent-task.types.js.map +1 -0
- package/dist/cli/backend/src/types/orchestrator-state.types.d.ts +531 -0
- package/dist/cli/backend/src/types/orchestrator-state.types.d.ts.map +1 -0
- package/dist/cli/backend/src/types/orchestrator-state.types.js +110 -0
- package/dist/cli/backend/src/types/orchestrator-state.types.js.map +1 -0
- package/dist/cli/backend/src/types/v2/index.d.ts +30 -0
- package/dist/cli/backend/src/types/v2/index.d.ts.map +1 -0
- package/dist/cli/backend/src/types/v2/index.js +22 -0
- package/dist/cli/backend/src/types/v2/index.js.map +1 -0
- package/dist/cli/backend/src/types/v2/key-result.types.d.ts +279 -0
- package/dist/cli/backend/src/types/v2/key-result.types.d.ts.map +1 -0
- package/dist/cli/backend/src/types/v2/key-result.types.js +264 -0
- package/dist/cli/backend/src/types/v2/key-result.types.js.map +1 -0
- package/dist/cli/backend/src/types/v2/mission.types.d.ts +661 -0
- package/dist/cli/backend/src/types/v2/mission.types.d.ts.map +1 -0
- package/dist/cli/backend/src/types/v2/mission.types.js +713 -0
- package/dist/cli/backend/src/types/v2/mission.types.js.map +1 -0
- package/dist/cli/backend/src/types/v2/reconcile.types.d.ts +204 -0
- package/dist/cli/backend/src/types/v2/reconcile.types.d.ts.map +1 -0
- package/dist/cli/backend/src/types/v2/reconcile.types.js +121 -0
- package/dist/cli/backend/src/types/v2/reconcile.types.js.map +1 -0
- package/dist/cli/backend/src/types/v2/request.types.d.ts +192 -0
- package/dist/cli/backend/src/types/v2/request.types.d.ts.map +1 -0
- package/dist/cli/backend/src/types/v2/request.types.js +179 -0
- package/dist/cli/backend/src/types/v2/request.types.js.map +1 -0
- package/dist/cli/backend/src/types/v2/work-item.types.d.ts +181 -1
- package/dist/cli/backend/src/types/v2/work-item.types.d.ts.map +1 -1
- package/dist/cli/backend/src/types/v2/work-item.types.js +104 -17
- package/dist/cli/backend/src/types/v2/work-item.types.js.map +1 -1
- package/dist/cli/backend/src/types/v2/workspace.types.d.ts +157 -0
- package/dist/cli/backend/src/types/v2/workspace.types.d.ts.map +1 -0
- package/dist/cli/backend/src/types/v2/workspace.types.js +173 -0
- package/dist/cli/backend/src/types/v2/workspace.types.js.map +1 -0
- package/dist/cli/backend/src/utils/async.utils.d.ts +68 -0
- package/dist/cli/backend/src/utils/async.utils.d.ts.map +1 -0
- package/dist/cli/backend/src/utils/async.utils.js +80 -0
- package/dist/cli/backend/src/utils/async.utils.js.map +1 -0
- package/dist/cli/backend/src/utils/native-binding.utils.d.ts +128 -0
- package/dist/cli/backend/src/utils/native-binding.utils.d.ts.map +1 -0
- package/dist/cli/backend/src/utils/native-binding.utils.js +206 -0
- package/dist/cli/backend/src/utils/native-binding.utils.js.map +1 -0
- package/dist/cli/backend/src/websocket/chat.gateway.d.ts +142 -0
- package/dist/cli/backend/src/websocket/chat.gateway.d.ts.map +1 -0
- package/dist/cli/backend/src/websocket/chat.gateway.js +327 -0
- package/dist/cli/backend/src/websocket/chat.gateway.js.map +1 -0
- package/dist/cli/backend/src/websocket/terminal.gateway.d.ts +341 -0
- package/dist/cli/backend/src/websocket/terminal.gateway.d.ts.map +1 -0
- package/dist/cli/backend/src/websocket/terminal.gateway.js +933 -0
- package/dist/cli/backend/src/websocket/terminal.gateway.js.map +1 -0
- package/dist/cli/config/vitest-exclude.constants.d.ts +53 -0
- package/dist/cli/config/vitest-exclude.constants.d.ts.map +1 -0
- package/dist/cli/config/vitest-exclude.constants.js +55 -0
- package/dist/cli/config/vitest-exclude.constants.js.map +1 -0
- package/package.json +2 -2
- package/packages/crewly-agent/src/cli.ts +16 -6
- package/packages/crewly-agent/src/runtime/agent-runner.service.test.ts +311 -33
- package/packages/crewly-agent/src/runtime/agent-runner.service.ts +221 -12
- package/packages/crewly-agent/src/runtime/tool-registry.test.ts +19 -0
- package/packages/crewly-agent/src/runtime/tool-registry.ts +4 -1
- package/packages/crewly-agent/src/runtime/types.ts +65 -5
|
@@ -0,0 +1,1166 @@
|
|
|
1
|
+
import * as fs from 'fs/promises';
|
|
2
|
+
import * as http from 'http';
|
|
3
|
+
import { LoggerService } from '../core/logger.service.js';
|
|
4
|
+
import { StorageService } from '../core/storage.service.js';
|
|
5
|
+
import { getSessionBackendSync, createSessionCommandHelper, } from '../session/index.js';
|
|
6
|
+
import { getSessionStatePersistence } from '../session/session-state-persistence.js';
|
|
7
|
+
import { RuntimeServiceFactory } from './runtime-service.factory.js';
|
|
8
|
+
import { SessionMemoryService } from '../memory/session-memory.service.js';
|
|
9
|
+
import { getTerminalGateway } from '../../websocket/terminal.gateway.js';
|
|
10
|
+
import { SHELL_PROMPT_PATTERNS } from '../continuation/patterns/idle-patterns.js';
|
|
11
|
+
import { PtyActivityTrackerService } from './pty-activity-tracker.service.js';
|
|
12
|
+
import { OrchestratorRestartService } from '../orchestrator/orchestrator-restart.service.js';
|
|
13
|
+
import * as crypto from 'crypto';
|
|
14
|
+
import { CREWLY_CONSTANTS, ORCHESTRATOR_SESSION_NAME, ORCHESTRATOR_ROLE, RUNTIME_EXIT_CONSTANTS, AGENT_SUSPEND_CONSTANTS, SESSION_COMMAND_DELAYS, RUNTIME_TYPES, GEMINI_FAILURE_PATTERNS, GEMINI_FORCE_RESTART_PATTERNS, GEMINI_DELIBERATION_PATTERN, GEMINI_DELIBERATION_THRESHOLD, GEMINI_TOOL_CHECK_LOOP_PATTERN, GEMINI_TOOL_CHECK_LOOP_THRESHOLD, GEMINI_TOOL_CHECK_LOOP_WINDOW_MS, CLAUDE_FATAL_PATTERNS, GEMINI_FAILURE_RETRY_CONSTANTS, GEMINI_READY_PATTERNS, WEB_CONSTANTS, AGENT_HEARTBEAT_MONITOR_CONSTANTS, } from '../../constants.js';
|
|
15
|
+
import { delay } from '../../utils/async.utils.js';
|
|
16
|
+
/**
|
|
17
|
+
* Service that monitors PTY sessions for runtime exit patterns.
|
|
18
|
+
*
|
|
19
|
+
* When an agent CLI (Claude Code, Gemini CLI, Codex CLI) exits inside a PTY
|
|
20
|
+
* session, the PTY shell itself stays alive. This service watches terminal
|
|
21
|
+
* output for runtime-specific exit patterns and reacts by:
|
|
22
|
+
*
|
|
23
|
+
* 1. Updating the agent status to `inactive`
|
|
24
|
+
* 2. Capturing session memory
|
|
25
|
+
* 3. Broadcasting WebSocket events to the frontend
|
|
26
|
+
* 4. Cancelling pending registration operations
|
|
27
|
+
*
|
|
28
|
+
* For Gemini CLI, the service also detects failure patterns (API errors,
|
|
29
|
+
* quota exhaustion, network issues) that indicate the CLI is stuck and
|
|
30
|
+
* needs recovery. These failure patterns bypass the shell prompt verification
|
|
31
|
+
* since the CLI may still be running but non-functional.
|
|
32
|
+
*
|
|
33
|
+
* For Claude Code, the service detects fatal API errors (e.g. thinking
|
|
34
|
+
* block corruption) that make the CLI permanently non-functional within
|
|
35
|
+
* the current session. These trigger immediate recovery without retry.
|
|
36
|
+
*
|
|
37
|
+
* @example
|
|
38
|
+
* ```typescript
|
|
39
|
+
* const monitor = RuntimeExitMonitorService.getInstance();
|
|
40
|
+
* monitor.startMonitoring('agent-dev-001', 'claude-code', 'developer');
|
|
41
|
+
* // ... later ...
|
|
42
|
+
* monitor.stopMonitoring('agent-dev-001');
|
|
43
|
+
* ```
|
|
44
|
+
*/
|
|
45
|
+
export class RuntimeExitMonitorService {
|
|
46
|
+
static instance = null;
|
|
47
|
+
logger;
|
|
48
|
+
sessions = new Map();
|
|
49
|
+
onExitDetectedCallback;
|
|
50
|
+
agentRegistrationService = null;
|
|
51
|
+
eventBusService = null;
|
|
52
|
+
/**
|
|
53
|
+
* Restart timestamps per session, persisted across monitoring cycles.
|
|
54
|
+
* Unlike MonitoredSession (which is recreated on each startMonitoring call),
|
|
55
|
+
* this map survives agent restarts to prevent infinite restart loops
|
|
56
|
+
* when agents keep crashing (e.g. during network outages).
|
|
57
|
+
*/
|
|
58
|
+
restartHistory = new Map();
|
|
59
|
+
constructor() {
|
|
60
|
+
this.logger = LoggerService.getInstance().createComponentLogger('RuntimeExitMonitorService');
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Get the singleton instance.
|
|
64
|
+
*/
|
|
65
|
+
static getInstance() {
|
|
66
|
+
if (!RuntimeExitMonitorService.instance) {
|
|
67
|
+
RuntimeExitMonitorService.instance = new RuntimeExitMonitorService();
|
|
68
|
+
}
|
|
69
|
+
return RuntimeExitMonitorService.instance;
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Reset the singleton (for testing).
|
|
73
|
+
*/
|
|
74
|
+
static resetInstance() {
|
|
75
|
+
if (RuntimeExitMonitorService.instance) {
|
|
76
|
+
RuntimeExitMonitorService.instance.destroy();
|
|
77
|
+
}
|
|
78
|
+
RuntimeExitMonitorService.instance = null;
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Register a callback invoked when a runtime exit is detected.
|
|
82
|
+
* Used by AgentRegistrationService to cancel pending registrations.
|
|
83
|
+
*
|
|
84
|
+
* @param callback - Called with the sessionName on exit detection
|
|
85
|
+
*/
|
|
86
|
+
setOnExitDetectedCallback(callback) {
|
|
87
|
+
this.onExitDetectedCallback = callback;
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Set the AgentRegistrationService dependency for agent restart.
|
|
91
|
+
*
|
|
92
|
+
* @param service - The AgentRegistrationService instance
|
|
93
|
+
*/
|
|
94
|
+
setAgentRegistrationService(service) {
|
|
95
|
+
this.agentRegistrationService = service;
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* Backwards-compatible no-op. Kept so `index.ts` compiles during the
|
|
99
|
+
* TaskTrackingService deletion window. In-progress task queries now
|
|
100
|
+
* read directly from TaskPoolService.
|
|
101
|
+
*
|
|
102
|
+
* @deprecated Will be removed in a follow-up. Do not call from new code.
|
|
103
|
+
*/
|
|
104
|
+
setTaskTrackingService(_service) {
|
|
105
|
+
// intentionally empty
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* Set the EventBusService dependency for publishing agent lifecycle events.
|
|
109
|
+
*
|
|
110
|
+
* @param service - The EventBusService instance
|
|
111
|
+
*/
|
|
112
|
+
setEventBusService(service) {
|
|
113
|
+
this.eventBusService = service;
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* Start monitoring a PTY session for runtime exit patterns.
|
|
117
|
+
*
|
|
118
|
+
* @param sessionName - PTY session name
|
|
119
|
+
* @param runtimeType - Agent runtime type (claude-code, gemini-cli, codex-cli)
|
|
120
|
+
* @param role - Agent role name
|
|
121
|
+
* @param teamId - Optional team identifier
|
|
122
|
+
* @param memberId - Optional member identifier
|
|
123
|
+
*/
|
|
124
|
+
startMonitoring(sessionName, runtimeType, role, teamId, memberId) {
|
|
125
|
+
// Stop any existing monitoring for this session
|
|
126
|
+
if (this.sessions.has(sessionName)) {
|
|
127
|
+
this.stopMonitoring(sessionName);
|
|
128
|
+
}
|
|
129
|
+
const backend = getSessionBackendSync();
|
|
130
|
+
if (!backend) {
|
|
131
|
+
this.logger.warn('Cannot start monitoring: session backend not initialized', { sessionName });
|
|
132
|
+
return;
|
|
133
|
+
}
|
|
134
|
+
const helper = createSessionCommandHelper(backend);
|
|
135
|
+
const session = helper.getSession(sessionName);
|
|
136
|
+
if (!session) {
|
|
137
|
+
this.logger.warn('Cannot start monitoring: session not found', { sessionName });
|
|
138
|
+
return;
|
|
139
|
+
}
|
|
140
|
+
const monitored = {
|
|
141
|
+
sessionName,
|
|
142
|
+
runtimeType,
|
|
143
|
+
role,
|
|
144
|
+
memberId,
|
|
145
|
+
teamId,
|
|
146
|
+
buffer: '',
|
|
147
|
+
startedAt: Date.now(),
|
|
148
|
+
exitDetected: false,
|
|
149
|
+
confirmationInFlight: false,
|
|
150
|
+
unsubscribe: () => { },
|
|
151
|
+
geminiFailureRetries: 0,
|
|
152
|
+
toolCheckLoopTimestamps: [],
|
|
153
|
+
};
|
|
154
|
+
// Get exit patterns for this runtime type
|
|
155
|
+
let exitPatterns;
|
|
156
|
+
try {
|
|
157
|
+
const runtimeService = RuntimeServiceFactory.create(runtimeType, null, process.cwd());
|
|
158
|
+
exitPatterns = runtimeService.getExitPatterns();
|
|
159
|
+
}
|
|
160
|
+
catch {
|
|
161
|
+
this.logger.warn('Failed to get exit patterns, using empty set', { sessionName, runtimeType });
|
|
162
|
+
exitPatterns = [];
|
|
163
|
+
}
|
|
164
|
+
if (exitPatterns.length === 0) {
|
|
165
|
+
this.logger.debug('No exit patterns for runtime, skipping monitoring', { sessionName, runtimeType });
|
|
166
|
+
return;
|
|
167
|
+
}
|
|
168
|
+
// Subscribe to PTY output
|
|
169
|
+
const unsubscribe = session.onData((data) => {
|
|
170
|
+
this.handleData(sessionName, data, exitPatterns, helper);
|
|
171
|
+
});
|
|
172
|
+
monitored.unsubscribe = unsubscribe;
|
|
173
|
+
// Start periodic process-alive polling as a fallback.
|
|
174
|
+
// This catches exits that don't produce recognizable text patterns
|
|
175
|
+
// (e.g. context window exhaustion, SIGKILL, unexpected crashes).
|
|
176
|
+
monitored.processPollingInterval = setInterval(() => {
|
|
177
|
+
this.checkProcessAlive(sessionName, backend, helper);
|
|
178
|
+
}, RUNTIME_EXIT_CONSTANTS.PROCESS_POLL_INTERVAL_MS);
|
|
179
|
+
this.sessions.set(sessionName, monitored);
|
|
180
|
+
this.logger.info('Started runtime exit monitoring', {
|
|
181
|
+
sessionName,
|
|
182
|
+
runtimeType,
|
|
183
|
+
role,
|
|
184
|
+
patternCount: exitPatterns.length,
|
|
185
|
+
});
|
|
186
|
+
}
|
|
187
|
+
/**
|
|
188
|
+
* Stop monitoring a PTY session.
|
|
189
|
+
*
|
|
190
|
+
* Also prunes the restartHistory entry for this session if it has no
|
|
191
|
+
* recent timestamps within the cooldown window, preventing slow memory
|
|
192
|
+
* leak for terminated sessions.
|
|
193
|
+
*
|
|
194
|
+
* @param sessionName - PTY session name
|
|
195
|
+
*/
|
|
196
|
+
stopMonitoring(sessionName) {
|
|
197
|
+
const monitored = this.sessions.get(sessionName);
|
|
198
|
+
if (!monitored) {
|
|
199
|
+
return;
|
|
200
|
+
}
|
|
201
|
+
if (monitored.debounceTimer) {
|
|
202
|
+
clearTimeout(monitored.debounceTimer);
|
|
203
|
+
}
|
|
204
|
+
if (monitored.processPollingInterval) {
|
|
205
|
+
clearInterval(monitored.processPollingInterval);
|
|
206
|
+
}
|
|
207
|
+
monitored.unsubscribe();
|
|
208
|
+
this.sessions.delete(sessionName);
|
|
209
|
+
// Fix 3: Clean up restartHistory for terminated sessions to prevent
|
|
210
|
+
// unbounded Map growth. Keep the entry only if it has recent timestamps
|
|
211
|
+
// within the cooldown window (they may still be needed if the session
|
|
212
|
+
// is restarted soon). Delete the entry entirely otherwise.
|
|
213
|
+
const timestamps = this.restartHistory.get(sessionName);
|
|
214
|
+
if (timestamps) {
|
|
215
|
+
const windowStart = Date.now() - AGENT_HEARTBEAT_MONITOR_CONSTANTS.COOLDOWN_WINDOW_MS;
|
|
216
|
+
const recent = timestamps.filter(ts => ts > windowStart);
|
|
217
|
+
if (recent.length === 0) {
|
|
218
|
+
this.restartHistory.delete(sessionName);
|
|
219
|
+
}
|
|
220
|
+
else {
|
|
221
|
+
this.restartHistory.set(sessionName, recent);
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
this.logger.debug('Stopped runtime exit monitoring', { sessionName });
|
|
225
|
+
}
|
|
226
|
+
/**
|
|
227
|
+
* Check if a session is being monitored.
|
|
228
|
+
*/
|
|
229
|
+
isMonitoring(sessionName) {
|
|
230
|
+
return this.sessions.has(sessionName);
|
|
231
|
+
}
|
|
232
|
+
/**
|
|
233
|
+
* Destroy all monitoring subscriptions.
|
|
234
|
+
*/
|
|
235
|
+
destroy() {
|
|
236
|
+
const sessionNames = [...this.sessions.keys()];
|
|
237
|
+
for (const sessionName of sessionNames) {
|
|
238
|
+
this.stopMonitoring(sessionName);
|
|
239
|
+
}
|
|
240
|
+
this.restartHistory.clear();
|
|
241
|
+
this.logger.debug('All runtime exit monitors destroyed');
|
|
242
|
+
}
|
|
243
|
+
/**
|
|
244
|
+
* Handle incoming PTY data for a monitored session.
|
|
245
|
+
*/
|
|
246
|
+
handleData(sessionName, data, exitPatterns, helper) {
|
|
247
|
+
const monitored = this.sessions.get(sessionName);
|
|
248
|
+
if (!monitored || monitored.exitDetected) {
|
|
249
|
+
return;
|
|
250
|
+
}
|
|
251
|
+
// Append to rolling buffer, cap at MAX_BUFFER_SIZE
|
|
252
|
+
monitored.buffer += data;
|
|
253
|
+
if (monitored.buffer.length > RUNTIME_EXIT_CONSTANTS.MAX_BUFFER_SIZE) {
|
|
254
|
+
monitored.buffer = monitored.buffer.slice(-RUNTIME_EXIT_CONSTANTS.MAX_BUFFER_SIZE);
|
|
255
|
+
}
|
|
256
|
+
// Skip pattern matching during startup grace period
|
|
257
|
+
if (Date.now() - monitored.startedAt < RUNTIME_EXIT_CONSTANTS.STARTUP_GRACE_PERIOD_MS) {
|
|
258
|
+
return;
|
|
259
|
+
}
|
|
260
|
+
// Test buffer against exit patterns
|
|
261
|
+
let matched = exitPatterns.some((pattern) => pattern.test(monitored.buffer));
|
|
262
|
+
// #188: Deliberation loop detection for Gemini CLI agents.
|
|
263
|
+
// Count occurrences of "Wait, I'll..." / "Actually, I'll..." in the buffer.
|
|
264
|
+
// A single occurrence is normal; 5+ in the visible buffer means the agent
|
|
265
|
+
// is stuck planning without executing tool calls and needs a restart.
|
|
266
|
+
if (!matched && monitored.runtimeType === RUNTIME_TYPES.GEMINI_CLI) {
|
|
267
|
+
const deliberationCount = monitored.buffer.split(GEMINI_DELIBERATION_PATTERN).length - 1;
|
|
268
|
+
if (deliberationCount >= GEMINI_DELIBERATION_THRESHOLD) {
|
|
269
|
+
this.logger.warn('Gemini deliberation loop detected, triggering recovery', {
|
|
270
|
+
sessionName,
|
|
271
|
+
deliberationCount,
|
|
272
|
+
threshold: GEMINI_DELIBERATION_THRESHOLD,
|
|
273
|
+
});
|
|
274
|
+
matched = true;
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
// #251: Tool-check loop detection for Gemini CLI agents.
|
|
278
|
+
// Detects "Ready. Final response." / "Wait, I will check if I should use mcp_"
|
|
279
|
+
// cycling through Chrome DevTools MCP tools without completing.
|
|
280
|
+
// Time-windowed: THRESHOLD matches within WINDOW_MS triggers force-stop.
|
|
281
|
+
if (!matched && monitored.runtimeType === RUNTIME_TYPES.GEMINI_CLI) {
|
|
282
|
+
if (GEMINI_TOOL_CHECK_LOOP_PATTERN.test(data)) {
|
|
283
|
+
const now = Date.now();
|
|
284
|
+
monitored.toolCheckLoopTimestamps.push(now);
|
|
285
|
+
// Prune timestamps outside the time window
|
|
286
|
+
const windowStart = now - GEMINI_TOOL_CHECK_LOOP_WINDOW_MS;
|
|
287
|
+
monitored.toolCheckLoopTimestamps = monitored.toolCheckLoopTimestamps.filter((ts) => ts >= windowStart);
|
|
288
|
+
if (monitored.toolCheckLoopTimestamps.length >= GEMINI_TOOL_CHECK_LOOP_THRESHOLD) {
|
|
289
|
+
this.logger.warn('Gemini tool-check loop detected (#251), force-stopping agent', {
|
|
290
|
+
sessionName,
|
|
291
|
+
matchCount: monitored.toolCheckLoopTimestamps.length,
|
|
292
|
+
threshold: GEMINI_TOOL_CHECK_LOOP_THRESHOLD,
|
|
293
|
+
windowMs: GEMINI_TOOL_CHECK_LOOP_WINDOW_MS,
|
|
294
|
+
});
|
|
295
|
+
matched = true;
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
if (!matched) {
|
|
300
|
+
return;
|
|
301
|
+
}
|
|
302
|
+
// Pattern matched — start debounce timer to confirm
|
|
303
|
+
if (monitored.debounceTimer) {
|
|
304
|
+
clearTimeout(monitored.debounceTimer);
|
|
305
|
+
}
|
|
306
|
+
monitored.debounceTimer = setTimeout(() => {
|
|
307
|
+
this.confirmAndReact(sessionName, helper);
|
|
308
|
+
}, RUNTIME_EXIT_CONSTANTS.CONFIRMATION_DELAY_MS);
|
|
309
|
+
}
|
|
310
|
+
/**
|
|
311
|
+
* Confirm exit by checking for a shell prompt, then react.
|
|
312
|
+
*
|
|
313
|
+
* Runtime-specific failure checks are gated by runtimeType so that
|
|
314
|
+
* patterns for one runtime cannot accidentally match another (e.g. a
|
|
315
|
+
* Codex exit matching Claude or Gemini patterns).
|
|
316
|
+
*
|
|
317
|
+
* For Gemini CLI failure patterns (API errors, quota exhaustion, etc.),
|
|
318
|
+
* the system retries with exponential backoff before declaring the agent
|
|
319
|
+
* dead. Gemini CLI often recovers automatically from transient API errors
|
|
320
|
+
* (RESOURCE_EXHAUSTED, UNAVAILABLE, Connection error). Only after
|
|
321
|
+
* MAX_RETRIES does the system proceed with the exit/restart flow.
|
|
322
|
+
*
|
|
323
|
+
* For Claude Code fatal patterns (thinking block corruption, etc.),
|
|
324
|
+
* the system skips retry and forces immediate recovery since these
|
|
325
|
+
* errors are permanently unrecoverable within the same session.
|
|
326
|
+
*/
|
|
327
|
+
async confirmAndReact(sessionName, helper) {
|
|
328
|
+
const monitored = this.sessions.get(sessionName);
|
|
329
|
+
if (!monitored || monitored.exitDetected || monitored.confirmationInFlight) {
|
|
330
|
+
return;
|
|
331
|
+
}
|
|
332
|
+
monitored.confirmationInFlight = true;
|
|
333
|
+
try {
|
|
334
|
+
// Verify shell prompt is visible (avoids false positives)
|
|
335
|
+
const shellPromptConfirmed = this.verifyExitWithShellPrompt(sessionName, helper);
|
|
336
|
+
if (!shellPromptConfirmed) {
|
|
337
|
+
const runtimeSpecificMatch = await this.checkRuntimeSpecificFailure(sessionName, monitored, helper);
|
|
338
|
+
if (!runtimeSpecificMatch) {
|
|
339
|
+
this.logger.debug('Exit pattern matched but shell prompt not confirmed, ignoring', { sessionName });
|
|
340
|
+
return;
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
// Mark as detected to prevent double-processing
|
|
344
|
+
monitored.exitDetected = true;
|
|
345
|
+
// Identify which exit pattern triggered detection for diagnostics
|
|
346
|
+
let matchedPatternSource;
|
|
347
|
+
try {
|
|
348
|
+
const runtimeService = RuntimeServiceFactory.create(monitored.runtimeType, null, process.cwd());
|
|
349
|
+
const patterns = runtimeService.getExitPatterns();
|
|
350
|
+
const matched = patterns.find((p) => p.test(monitored.buffer));
|
|
351
|
+
matchedPatternSource = matched?.source;
|
|
352
|
+
}
|
|
353
|
+
catch {
|
|
354
|
+
// Non-critical — pattern name is best-effort diagnostics
|
|
355
|
+
}
|
|
356
|
+
this.logger.info('Runtime exit detected and confirmed', {
|
|
357
|
+
sessionName,
|
|
358
|
+
runtimeType: monitored.runtimeType,
|
|
359
|
+
role: monitored.role,
|
|
360
|
+
matchedPattern: matchedPatternSource,
|
|
361
|
+
bufferTail: monitored.buffer.slice(-500),
|
|
362
|
+
});
|
|
363
|
+
// Fire the exit-detected callback (used to cancel pending registrations)
|
|
364
|
+
this.fireExitDetectedCallback(sessionName);
|
|
365
|
+
// Try agent restart if it has in-progress tasks (non-orchestrator only).
|
|
366
|
+
// V3-only as of spec 2026-05-06-task-management-v1-deprecation.md:
|
|
367
|
+
// active tasks are read from TaskPoolService inside `tryAgentRestartWithTasks`.
|
|
368
|
+
if (monitored.role !== ORCHESTRATOR_ROLE && this.agentRegistrationService) {
|
|
369
|
+
const restarted = await this.tryAgentRestartWithTasks(sessionName, monitored);
|
|
370
|
+
if (restarted)
|
|
371
|
+
return;
|
|
372
|
+
}
|
|
373
|
+
// #228/#234: Auto-restart agents that exit idle (Claude Code + Codex CLI).
|
|
374
|
+
// These runtimes exit after task completion or idle timeout. Restart to keep available.
|
|
375
|
+
if ((monitored.runtimeType === 'claude-code' || monitored.runtimeType === 'codex-cli')
|
|
376
|
+
&& monitored.role !== ORCHESTRATOR_ROLE
|
|
377
|
+
&& this.agentRegistrationService && this.isAgentRestartAllowed(sessionName)) {
|
|
378
|
+
try {
|
|
379
|
+
this.logger.info('Agent idle/clean exit — auto-restarting to maintain availability', { sessionName, runtimeType: monitored.runtimeType });
|
|
380
|
+
await this.restartAgentWithTasks(sessionName, monitored, []);
|
|
381
|
+
this.recordAgentRestart(sessionName);
|
|
382
|
+
this.stopMonitoring(sessionName);
|
|
383
|
+
return;
|
|
384
|
+
}
|
|
385
|
+
catch (restartError) {
|
|
386
|
+
this.logger.warn('Agent idle restart failed, transitioning to inactive', {
|
|
387
|
+
sessionName,
|
|
388
|
+
error: restartError instanceof Error ? restartError.message : String(restartError),
|
|
389
|
+
});
|
|
390
|
+
}
|
|
391
|
+
}
|
|
392
|
+
// Orchestrator-specific restart
|
|
393
|
+
if (sessionName === ORCHESTRATOR_SESSION_NAME) {
|
|
394
|
+
const restarted = await this.tryOrchestratorRestart(sessionName, monitored);
|
|
395
|
+
if (restarted)
|
|
396
|
+
return;
|
|
397
|
+
}
|
|
398
|
+
// Normal inactive flow: update status, capture memory, broadcast
|
|
399
|
+
await this.transitionToInactive(sessionName, monitored);
|
|
400
|
+
// Cleanup this subscription
|
|
401
|
+
this.stopMonitoring(sessionName);
|
|
402
|
+
}
|
|
403
|
+
finally {
|
|
404
|
+
monitored.confirmationInFlight = false;
|
|
405
|
+
}
|
|
406
|
+
}
|
|
407
|
+
/**
|
|
408
|
+
* Check for runtime-specific failure patterns when shell prompt is not confirmed.
|
|
409
|
+
*
|
|
410
|
+
* Gated by runtimeType so patterns for one runtime cannot accidentally
|
|
411
|
+
* match another. Returns true if a runtime-specific failure was detected,
|
|
412
|
+
* or 'deferred' handling occurred (Gemini retry).
|
|
413
|
+
*
|
|
414
|
+
* @param sessionName - PTY session name
|
|
415
|
+
* @param monitored - Monitored session state
|
|
416
|
+
* @param helper - Session command helper
|
|
417
|
+
* @returns True if a runtime-specific failure was confirmed
|
|
418
|
+
*/
|
|
419
|
+
async checkRuntimeSpecificFailure(sessionName, monitored, helper) {
|
|
420
|
+
if (monitored.runtimeType === RUNTIME_TYPES.CODEX_CLI) {
|
|
421
|
+
const isCodexInterrupted = /Conversation interrupted/i.test(monitored.buffer);
|
|
422
|
+
if (isCodexInterrupted) {
|
|
423
|
+
this.logger.warn('Codex interruption detected, proceeding with recovery flow', { sessionName });
|
|
424
|
+
return true;
|
|
425
|
+
}
|
|
426
|
+
}
|
|
427
|
+
else if (monitored.runtimeType === RUNTIME_TYPES.CLAUDE_CODE) {
|
|
428
|
+
const isClaudeFatal = CLAUDE_FATAL_PATTERNS.some((pattern) => pattern.test(monitored.buffer));
|
|
429
|
+
if (isClaudeFatal) {
|
|
430
|
+
const detectedPattern = CLAUDE_FATAL_PATTERNS.find((p) => p.test(monitored.buffer))?.source;
|
|
431
|
+
this.logger.warn('Claude Code fatal error detected, forcing immediate recovery', {
|
|
432
|
+
sessionName,
|
|
433
|
+
detectedPattern,
|
|
434
|
+
});
|
|
435
|
+
return true;
|
|
436
|
+
}
|
|
437
|
+
}
|
|
438
|
+
else if (monitored.runtimeType === RUNTIME_TYPES.GEMINI_CLI) {
|
|
439
|
+
// #251: Tool-check loop is a confirmed failure — agent is alive but stuck
|
|
440
|
+
if (monitored.toolCheckLoopTimestamps.length >= GEMINI_TOOL_CHECK_LOOP_THRESHOLD) {
|
|
441
|
+
this.logger.warn('Gemini tool-check loop confirmed (#251), forcing recovery', { sessionName });
|
|
442
|
+
return true;
|
|
443
|
+
}
|
|
444
|
+
// #188: Deliberation loop is also a confirmed failure
|
|
445
|
+
const deliberationCount = monitored.buffer.split(GEMINI_DELIBERATION_PATTERN).length - 1;
|
|
446
|
+
if (deliberationCount >= GEMINI_DELIBERATION_THRESHOLD) {
|
|
447
|
+
this.logger.warn('Gemini deliberation loop confirmed (#188), forcing recovery', { sessionName });
|
|
448
|
+
return true;
|
|
449
|
+
}
|
|
450
|
+
const isGeminiFailure = GEMINI_FAILURE_PATTERNS.some((pattern) => pattern.test(monitored.buffer));
|
|
451
|
+
const isGeminiForceRestart = GEMINI_FORCE_RESTART_PATTERNS.some((pattern) => pattern.test(monitored.buffer));
|
|
452
|
+
if (isGeminiFailure || isGeminiForceRestart) {
|
|
453
|
+
if (isGeminiForceRestart) {
|
|
454
|
+
this.logger.warn('Gemini auto-update interruption detected, forcing recovery flow', { sessionName });
|
|
455
|
+
}
|
|
456
|
+
else {
|
|
457
|
+
const retryResult = await this.handleGeminiFailureWithRetry(sessionName, monitored, helper);
|
|
458
|
+
if (retryResult === 'recovered' || retryResult === 'deferred') {
|
|
459
|
+
return false; // Not a confirmed exit — caller should return early
|
|
460
|
+
}
|
|
461
|
+
}
|
|
462
|
+
return true;
|
|
463
|
+
}
|
|
464
|
+
}
|
|
465
|
+
return false;
|
|
466
|
+
}
|
|
467
|
+
/**
|
|
468
|
+
* Fire the onExitDetected callback safely.
|
|
469
|
+
*
|
|
470
|
+
* @param sessionName - PTY session name
|
|
471
|
+
*/
|
|
472
|
+
fireExitDetectedCallback(sessionName) {
|
|
473
|
+
if (!this.onExitDetectedCallback)
|
|
474
|
+
return;
|
|
475
|
+
try {
|
|
476
|
+
this.onExitDetectedCallback(sessionName);
|
|
477
|
+
}
|
|
478
|
+
catch (error) {
|
|
479
|
+
this.logger.warn('onExitDetected callback error', {
|
|
480
|
+
sessionName,
|
|
481
|
+
error: error instanceof Error ? error.message : String(error),
|
|
482
|
+
});
|
|
483
|
+
}
|
|
484
|
+
}
|
|
485
|
+
/**
|
|
486
|
+
* Try to restart an agent that has in-progress tasks.
|
|
487
|
+
*
|
|
488
|
+
* @param sessionName - PTY session name
|
|
489
|
+
* @param monitored - Monitored session state
|
|
490
|
+
* @returns True if the agent was successfully restarted (caller should return)
|
|
491
|
+
*/
|
|
492
|
+
async tryAgentRestartWithTasks(sessionName, monitored) {
|
|
493
|
+
try {
|
|
494
|
+
// V3-only as of spec 2026-05-06-task-management-v1-deprecation.md.
|
|
495
|
+
// Replaces TaskTrackingService.getTasksForTeamMember with V3 pool
|
|
496
|
+
// query filtered by `target` (session name) and projected to
|
|
497
|
+
// the legacy InProgressTask shape so the rest of this method
|
|
498
|
+
// (notifyOrchestratorOfFailure, restartAgentWithTasks) works
|
|
499
|
+
// unchanged.
|
|
500
|
+
const { TaskPoolService } = await import('../task-pool/task-pool.service.js');
|
|
501
|
+
const { projectWorkItemToInProgressTask } = await import('../v3/work-item-projection.js');
|
|
502
|
+
const items = await TaskPoolService.getInstance().getAllItems();
|
|
503
|
+
const tasks = items
|
|
504
|
+
.filter((wi) => wi.target === sessionName)
|
|
505
|
+
.map(projectWorkItemToInProgressTask);
|
|
506
|
+
const activeTasks = tasks.filter(t => t.status === 'assigned' || t.status === 'active' || t.status === 'pending_assignment');
|
|
507
|
+
if (activeTasks.length === 0)
|
|
508
|
+
return false;
|
|
509
|
+
if (!this.isAgentRestartAllowed(sessionName)) {
|
|
510
|
+
this.logger.warn('Agent restart cooldown active, skipping restart', {
|
|
511
|
+
sessionName,
|
|
512
|
+
activeTaskCount: activeTasks.length,
|
|
513
|
+
maxRestartsPerWindow: AGENT_HEARTBEAT_MONITOR_CONSTANTS.MAX_RESTARTS_PER_WINDOW,
|
|
514
|
+
cooldownWindowMs: AGENT_HEARTBEAT_MONITOR_CONSTANTS.COOLDOWN_WINDOW_MS,
|
|
515
|
+
});
|
|
516
|
+
this.notifyOrchestratorOfFailure(sessionName, 'runtime_exited_cooldown', activeTasks, false);
|
|
517
|
+
return false;
|
|
518
|
+
}
|
|
519
|
+
this.logger.info('Runtime exit with in-progress tasks, attempting restart', {
|
|
520
|
+
sessionName,
|
|
521
|
+
activeTaskCount: activeTasks.length,
|
|
522
|
+
});
|
|
523
|
+
try {
|
|
524
|
+
await this.restartAgentWithTasks(sessionName, monitored, activeTasks);
|
|
525
|
+
this.recordAgentRestart(sessionName);
|
|
526
|
+
this.notifyOrchestratorOfFailure(sessionName, 'runtime_exited', activeTasks, true);
|
|
527
|
+
this.stopMonitoring(sessionName);
|
|
528
|
+
return true;
|
|
529
|
+
}
|
|
530
|
+
catch (restartError) {
|
|
531
|
+
this.logger.warn('Agent restart after runtime exit failed, falling back to inactive', {
|
|
532
|
+
sessionName,
|
|
533
|
+
error: restartError instanceof Error ? restartError.message : String(restartError),
|
|
534
|
+
});
|
|
535
|
+
this.recordAgentRestart(sessionName);
|
|
536
|
+
this.notifyOrchestratorOfFailure(sessionName, 'runtime_exited', activeTasks, false);
|
|
537
|
+
return false;
|
|
538
|
+
}
|
|
539
|
+
}
|
|
540
|
+
catch (error) {
|
|
541
|
+
this.logger.warn('Failed to check in-progress tasks after runtime exit', {
|
|
542
|
+
sessionName,
|
|
543
|
+
error: error instanceof Error ? error.message : String(error),
|
|
544
|
+
});
|
|
545
|
+
return false;
|
|
546
|
+
}
|
|
547
|
+
}
|
|
548
|
+
/**
|
|
549
|
+
* Try to restart the orchestrator after runtime exit.
|
|
550
|
+
*
|
|
551
|
+
* Sets status to inactive before restart to prevent queue processor
|
|
552
|
+
* from delivering messages during postInitialize, captures session
|
|
553
|
+
* memory, and broadcasts restart status.
|
|
554
|
+
*
|
|
555
|
+
* @param sessionName - PTY session name (should be ORCHESTRATOR_SESSION_NAME)
|
|
556
|
+
* @param monitored - Monitored session state
|
|
557
|
+
* @returns True if orchestrator was successfully restarted (caller should return)
|
|
558
|
+
*/
|
|
559
|
+
async tryOrchestratorRestart(sessionName, monitored) {
|
|
560
|
+
// Set status to inactive BEFORE restart so the queue processor
|
|
561
|
+
// doesn't deliver messages during postInitialize.
|
|
562
|
+
try {
|
|
563
|
+
const storageService = StorageService.getInstance();
|
|
564
|
+
await storageService.updateAgentStatus(sessionName, CREWLY_CONSTANTS.AGENT_STATUSES.INACTIVE);
|
|
565
|
+
}
|
|
566
|
+
catch {
|
|
567
|
+
// Best-effort — continue with restart
|
|
568
|
+
}
|
|
569
|
+
// Capture session memory before restart
|
|
570
|
+
try {
|
|
571
|
+
const sessionMemoryService = SessionMemoryService.getInstance();
|
|
572
|
+
await sessionMemoryService.onSessionEnd(sessionName, monitored.role, process.cwd());
|
|
573
|
+
}
|
|
574
|
+
catch (error) {
|
|
575
|
+
this.logger.warn('Failed to capture session memory before orchestrator restart', {
|
|
576
|
+
sessionName,
|
|
577
|
+
error: error instanceof Error ? error.message : String(error),
|
|
578
|
+
});
|
|
579
|
+
}
|
|
580
|
+
try {
|
|
581
|
+
const restartService = OrchestratorRestartService.getInstance();
|
|
582
|
+
const success = await restartService.attemptRestart();
|
|
583
|
+
if (success) {
|
|
584
|
+
this.logger.info('Orchestrator restarted after runtime exit', { sessionName });
|
|
585
|
+
// Broadcast STARTED (not ACTIVE) — agent becomes ACTIVE only
|
|
586
|
+
// after registration prompt is processed and MCP call completes.
|
|
587
|
+
try {
|
|
588
|
+
const terminalGateway = getTerminalGateway();
|
|
589
|
+
if (terminalGateway) {
|
|
590
|
+
terminalGateway.broadcastOrchestratorStatus({
|
|
591
|
+
sessionName,
|
|
592
|
+
agentStatus: CREWLY_CONSTANTS.AGENT_STATUSES.STARTED,
|
|
593
|
+
reason: 'runtime_exit_restart',
|
|
594
|
+
});
|
|
595
|
+
}
|
|
596
|
+
}
|
|
597
|
+
catch {
|
|
598
|
+
// Best-effort broadcast
|
|
599
|
+
}
|
|
600
|
+
this.stopMonitoring(sessionName);
|
|
601
|
+
return true;
|
|
602
|
+
}
|
|
603
|
+
this.logger.warn('Orchestrator restart after runtime exit failed or not allowed, falling back to inactive', {
|
|
604
|
+
sessionName,
|
|
605
|
+
});
|
|
606
|
+
}
|
|
607
|
+
catch (error) {
|
|
608
|
+
this.logger.warn('Orchestrator restart attempt threw error, falling back to inactive', {
|
|
609
|
+
sessionName,
|
|
610
|
+
error: error instanceof Error ? error.message : String(error),
|
|
611
|
+
});
|
|
612
|
+
}
|
|
613
|
+
return false;
|
|
614
|
+
}
|
|
615
|
+
/**
|
|
616
|
+
* Transition agent to inactive state: update storage, capture memory,
|
|
617
|
+
* publish events, and broadcast WebSocket status.
|
|
618
|
+
*
|
|
619
|
+
* @param sessionName - PTY session name
|
|
620
|
+
* @param monitored - Monitored session state
|
|
621
|
+
*/
|
|
622
|
+
async transitionToInactive(sessionName, monitored, dropoutReason) {
|
|
623
|
+
// #235: Determine dropout reason from exit patterns if not provided
|
|
624
|
+
const reason = dropoutReason || this.inferDropoutReason(monitored);
|
|
625
|
+
// Update agent status to inactive
|
|
626
|
+
try {
|
|
627
|
+
const storageService = StorageService.getInstance();
|
|
628
|
+
await storageService.updateAgentStatus(sessionName, CREWLY_CONSTANTS.AGENT_STATUSES.INACTIVE, reason);
|
|
629
|
+
this.logger.info('Agent status updated to inactive after runtime exit', { sessionName, dropoutReason: reason });
|
|
630
|
+
// Publish agent:inactive event to EventBus so orchestrator is notified
|
|
631
|
+
if (this.eventBusService) {
|
|
632
|
+
try {
|
|
633
|
+
await this.publishInactiveEvent(sessionName, monitored, storageService);
|
|
634
|
+
}
|
|
635
|
+
catch (eventError) {
|
|
636
|
+
this.logger.warn('Failed to publish agent:inactive event to EventBus', {
|
|
637
|
+
sessionName,
|
|
638
|
+
error: eventError instanceof Error ? eventError.message : String(eventError),
|
|
639
|
+
});
|
|
640
|
+
}
|
|
641
|
+
}
|
|
642
|
+
}
|
|
643
|
+
catch (error) {
|
|
644
|
+
this.logger.warn('Failed to update agent status after runtime exit', {
|
|
645
|
+
sessionName,
|
|
646
|
+
error: error instanceof Error ? error.message : String(error),
|
|
647
|
+
});
|
|
648
|
+
}
|
|
649
|
+
// Capture session memory (skip for orchestrator — already captured above)
|
|
650
|
+
if (sessionName !== ORCHESTRATOR_SESSION_NAME) {
|
|
651
|
+
try {
|
|
652
|
+
const sessionMemoryService = SessionMemoryService.getInstance();
|
|
653
|
+
await sessionMemoryService.onSessionEnd(sessionName, monitored.role, process.cwd());
|
|
654
|
+
}
|
|
655
|
+
catch (error) {
|
|
656
|
+
this.logger.warn('Failed to capture session memory after runtime exit', {
|
|
657
|
+
sessionName,
|
|
658
|
+
error: error instanceof Error ? error.message : String(error),
|
|
659
|
+
});
|
|
660
|
+
}
|
|
661
|
+
}
|
|
662
|
+
// Broadcast WebSocket event
|
|
663
|
+
try {
|
|
664
|
+
const terminalGateway = getTerminalGateway();
|
|
665
|
+
if (terminalGateway) {
|
|
666
|
+
const statusPayload = {
|
|
667
|
+
sessionName,
|
|
668
|
+
agentStatus: CREWLY_CONSTANTS.AGENT_STATUSES.INACTIVE,
|
|
669
|
+
reason: 'runtime_exited',
|
|
670
|
+
};
|
|
671
|
+
if (sessionName === ORCHESTRATOR_SESSION_NAME) {
|
|
672
|
+
terminalGateway.broadcastOrchestratorStatus(statusPayload);
|
|
673
|
+
}
|
|
674
|
+
else {
|
|
675
|
+
terminalGateway.broadcastTeamMemberStatus(statusPayload);
|
|
676
|
+
}
|
|
677
|
+
}
|
|
678
|
+
}
|
|
679
|
+
catch (error) {
|
|
680
|
+
this.logger.warn('Failed to broadcast runtime exit event', {
|
|
681
|
+
sessionName,
|
|
682
|
+
error: error instanceof Error ? error.message : String(error),
|
|
683
|
+
});
|
|
684
|
+
}
|
|
685
|
+
}
|
|
686
|
+
/**
|
|
687
|
+
* Handle a Gemini CLI failure with exponential backoff retry.
|
|
688
|
+
*
|
|
689
|
+
* Waits with increasing delays and checks if the CLI recovers (returns
|
|
690
|
+
* to a ready prompt). Returns 'recovered' if the CLI is back,
|
|
691
|
+
* 'deferred' if retries remain (skip exit flow, re-check on next
|
|
692
|
+
* failure detection), or 'exhausted' if max retries have been reached.
|
|
693
|
+
*
|
|
694
|
+
* @param sessionName - PTY session name
|
|
695
|
+
* @param monitored - Monitored session state (retry counter is mutated)
|
|
696
|
+
* @param helper - Session command helper for terminal output capture
|
|
697
|
+
* @returns 'recovered' | 'deferred' | 'exhausted'
|
|
698
|
+
*/
|
|
699
|
+
async handleGeminiFailureWithRetry(sessionName, monitored, helper) {
|
|
700
|
+
const detectedPattern = GEMINI_FAILURE_PATTERNS.find((p) => p.test(monitored.buffer))?.source;
|
|
701
|
+
monitored.geminiFailureRetries++;
|
|
702
|
+
const { MAX_RETRIES, INITIAL_BACKOFF_MS, MAX_BACKOFF_MS, BACKOFF_MULTIPLIER, RECOVERY_CHECK_LINES, } = GEMINI_FAILURE_RETRY_CONSTANTS;
|
|
703
|
+
if (monitored.geminiFailureRetries > MAX_RETRIES) {
|
|
704
|
+
this.logger.warn('Gemini CLI failure retries exhausted, proceeding with exit flow', {
|
|
705
|
+
sessionName,
|
|
706
|
+
retries: monitored.geminiFailureRetries,
|
|
707
|
+
maxRetries: MAX_RETRIES,
|
|
708
|
+
detectedPattern,
|
|
709
|
+
});
|
|
710
|
+
return 'exhausted';
|
|
711
|
+
}
|
|
712
|
+
// Exponential backoff: INITIAL * MULTIPLIER^(retry-1), capped at MAX
|
|
713
|
+
const backoffMs = Math.min(INITIAL_BACKOFF_MS * Math.pow(BACKOFF_MULTIPLIER, monitored.geminiFailureRetries - 1), MAX_BACKOFF_MS);
|
|
714
|
+
this.logger.info('Gemini CLI failure detected, waiting for recovery', {
|
|
715
|
+
sessionName,
|
|
716
|
+
retry: monitored.geminiFailureRetries,
|
|
717
|
+
maxRetries: MAX_RETRIES,
|
|
718
|
+
backoffMs,
|
|
719
|
+
detectedPattern,
|
|
720
|
+
});
|
|
721
|
+
// Clear the buffer so the same error text doesn't immediately re-trigger
|
|
722
|
+
monitored.buffer = '';
|
|
723
|
+
await delay(backoffMs);
|
|
724
|
+
// Check if the CLI has recovered by looking for ready prompt patterns
|
|
725
|
+
try {
|
|
726
|
+
const output = helper.capturePane(sessionName, RECOVERY_CHECK_LINES);
|
|
727
|
+
const hasRecovered = GEMINI_READY_PATTERNS.some((pattern) => output.includes(pattern));
|
|
728
|
+
if (hasRecovered) {
|
|
729
|
+
this.logger.info('Gemini CLI recovered after transient failure', {
|
|
730
|
+
sessionName,
|
|
731
|
+
retry: monitored.geminiFailureRetries,
|
|
732
|
+
detectedPattern,
|
|
733
|
+
});
|
|
734
|
+
monitored.geminiFailureRetries = 0;
|
|
735
|
+
return 'recovered';
|
|
736
|
+
}
|
|
737
|
+
this.logger.debug('Gemini CLI has not recovered yet after backoff', {
|
|
738
|
+
sessionName,
|
|
739
|
+
retry: monitored.geminiFailureRetries,
|
|
740
|
+
maxRetries: MAX_RETRIES,
|
|
741
|
+
});
|
|
742
|
+
}
|
|
743
|
+
catch (error) {
|
|
744
|
+
this.logger.warn('Error checking Gemini CLI recovery', {
|
|
745
|
+
sessionName,
|
|
746
|
+
error: error instanceof Error ? error.message : String(error),
|
|
747
|
+
});
|
|
748
|
+
}
|
|
749
|
+
// Not recovered but retries remain — defer to the next failure detection cycle.
|
|
750
|
+
// The buffer was cleared above, so a new failure must appear in terminal
|
|
751
|
+
// output to re-trigger this method.
|
|
752
|
+
if (monitored.geminiFailureRetries < MAX_RETRIES) {
|
|
753
|
+
return 'deferred';
|
|
754
|
+
}
|
|
755
|
+
return 'exhausted';
|
|
756
|
+
}
|
|
757
|
+
/**
|
|
758
|
+
* Restart an agent that exited while it had in-progress tasks.
|
|
759
|
+
*
|
|
760
|
+
* Mirrors the restart pattern from AgentHeartbeatMonitorService:
|
|
761
|
+
* 1. Save Claude session ID for resume
|
|
762
|
+
* 2. Kill old PTY session + clear PTY activity tracker
|
|
763
|
+
* 3. Pre-set session ID for resume
|
|
764
|
+
* 4. Recreate agent session via AgentRegistrationService
|
|
765
|
+
* 5. Broadcast restarted status via WebSocket
|
|
766
|
+
* 6. Re-deliver tasks asynchronously
|
|
767
|
+
*
|
|
768
|
+
* @param sessionName - PTY session name
|
|
769
|
+
* @param monitored - Monitored session state
|
|
770
|
+
* @param activeTasks - In-progress tasks to re-deliver
|
|
771
|
+
*/
|
|
772
|
+
async restartAgentWithTasks(sessionName, monitored, activeTasks) {
|
|
773
|
+
const backend = getSessionBackendSync();
|
|
774
|
+
if (!backend || !this.agentRegistrationService) {
|
|
775
|
+
throw new Error('Missing dependencies for agent restart');
|
|
776
|
+
}
|
|
777
|
+
// Save Claude session ID before killing
|
|
778
|
+
let claudeSessionId;
|
|
779
|
+
try {
|
|
780
|
+
const persistence = getSessionStatePersistence();
|
|
781
|
+
claudeSessionId = persistence.getSessionId(sessionName);
|
|
782
|
+
}
|
|
783
|
+
catch {
|
|
784
|
+
this.logger.warn('Could not retrieve Claude session ID for restart', { sessionName });
|
|
785
|
+
}
|
|
786
|
+
// Kill old PTY session
|
|
787
|
+
if (backend.sessionExists(sessionName)) {
|
|
788
|
+
await backend.killSession(sessionName);
|
|
789
|
+
}
|
|
790
|
+
// Clear PTY activity tracker
|
|
791
|
+
PtyActivityTrackerService.getInstance().clearSession(sessionName);
|
|
792
|
+
// Pre-set session ID for resume
|
|
793
|
+
if (claudeSessionId) {
|
|
794
|
+
try {
|
|
795
|
+
const persistence = getSessionStatePersistence();
|
|
796
|
+
const metadata = persistence.getSessionMetadata(sessionName);
|
|
797
|
+
if (metadata) {
|
|
798
|
+
persistence.updateSessionId(sessionName, claudeSessionId);
|
|
799
|
+
}
|
|
800
|
+
}
|
|
801
|
+
catch {
|
|
802
|
+
this.logger.warn('Could not pre-set session ID for resume', { sessionName });
|
|
803
|
+
}
|
|
804
|
+
}
|
|
805
|
+
// Recreate agent session
|
|
806
|
+
const result = await this.agentRegistrationService.createAgentSession({
|
|
807
|
+
sessionName,
|
|
808
|
+
role: monitored.role,
|
|
809
|
+
teamId: monitored.teamId,
|
|
810
|
+
memberId: monitored.memberId,
|
|
811
|
+
});
|
|
812
|
+
if (!result.success) {
|
|
813
|
+
throw new Error(result.error || 'createAgentSession failed');
|
|
814
|
+
}
|
|
815
|
+
// Broadcast agent restarted event
|
|
816
|
+
const terminalGateway = getTerminalGateway();
|
|
817
|
+
if (terminalGateway) {
|
|
818
|
+
terminalGateway.broadcastTeamMemberStatus({
|
|
819
|
+
teamId: monitored.teamId,
|
|
820
|
+
memberId: monitored.memberId,
|
|
821
|
+
sessionName,
|
|
822
|
+
agentStatus: CREWLY_CONSTANTS.AGENT_STATUSES.ACTIVE,
|
|
823
|
+
});
|
|
824
|
+
}
|
|
825
|
+
this.logger.info('Agent restarted after runtime exit with in-progress tasks', {
|
|
826
|
+
sessionName,
|
|
827
|
+
activeTaskCount: activeTasks.length,
|
|
828
|
+
claudeSessionId: claudeSessionId ? '(resumed)' : '(fresh)',
|
|
829
|
+
});
|
|
830
|
+
// Re-deliver in-progress tasks (async, non-blocking)
|
|
831
|
+
this.redeliverTasks(sessionName, activeTasks).catch((err) => {
|
|
832
|
+
this.logger.error('Task re-delivery failed after runtime exit restart', {
|
|
833
|
+
sessionName,
|
|
834
|
+
error: err instanceof Error ? err.message : String(err),
|
|
835
|
+
});
|
|
836
|
+
});
|
|
837
|
+
}
|
|
838
|
+
/**
|
|
839
|
+
* Re-deliver in-progress tasks to a restarted agent.
|
|
840
|
+
*
|
|
841
|
+
* Waits for the agent to initialize, reads task files, and writes
|
|
842
|
+
* summaries into the agent's PTY session.
|
|
843
|
+
*
|
|
844
|
+
* @param sessionName - PTY session name
|
|
845
|
+
* @param activeTasks - Tasks to re-deliver
|
|
846
|
+
*/
|
|
847
|
+
async redeliverTasks(sessionName, activeTasks) {
|
|
848
|
+
// Wait for agent initialization
|
|
849
|
+
await delay(AGENT_SUSPEND_CONSTANTS.REHYDRATION_TIMEOUT_MS);
|
|
850
|
+
const backend = getSessionBackendSync();
|
|
851
|
+
if (!backend || !backend.sessionExists(sessionName)) {
|
|
852
|
+
this.logger.warn('Agent session not found after restart, skipping task re-delivery', { sessionName });
|
|
853
|
+
return;
|
|
854
|
+
}
|
|
855
|
+
const session = backend.getSession(sessionName);
|
|
856
|
+
if (!session) {
|
|
857
|
+
return;
|
|
858
|
+
}
|
|
859
|
+
this.logger.info('Re-delivering tasks to restarted agent', {
|
|
860
|
+
sessionName,
|
|
861
|
+
taskCount: activeTasks.length,
|
|
862
|
+
});
|
|
863
|
+
for (const task of activeTasks) {
|
|
864
|
+
let taskContent = '';
|
|
865
|
+
try {
|
|
866
|
+
taskContent = await fs.readFile(task.taskFilePath, 'utf-8');
|
|
867
|
+
if (taskContent.length > 2000) {
|
|
868
|
+
taskContent = taskContent.slice(0, 2000) + '\n... (truncated)';
|
|
869
|
+
}
|
|
870
|
+
}
|
|
871
|
+
catch {
|
|
872
|
+
taskContent = '(task file not found)';
|
|
873
|
+
}
|
|
874
|
+
const message = [
|
|
875
|
+
'[TASK RE-DELIVERY] You were working on this task before your session was restarted:',
|
|
876
|
+
`Task: ${task.taskName}`,
|
|
877
|
+
`File: ${task.taskFilePath}`,
|
|
878
|
+
'---',
|
|
879
|
+
taskContent,
|
|
880
|
+
'---',
|
|
881
|
+
'Please continue working on this task.',
|
|
882
|
+
].join('\n');
|
|
883
|
+
// Write message and Enter as separate writes so that Enter is not
|
|
884
|
+
// swallowed by the terminal's bracketed paste mode.
|
|
885
|
+
session.write(message);
|
|
886
|
+
// Delay to let the terminal finish processing the paste, then send Enter
|
|
887
|
+
const pasteDelay = Math.min(SESSION_COMMAND_DELAYS.MESSAGE_DELAY + Math.ceil(message.length / 10), 5000);
|
|
888
|
+
await delay(pasteDelay);
|
|
889
|
+
session.write('\r');
|
|
890
|
+
// Delay between tasks to avoid flooding
|
|
891
|
+
await delay(2000);
|
|
892
|
+
}
|
|
893
|
+
this.logger.info('Task re-delivery complete', {
|
|
894
|
+
sessionName,
|
|
895
|
+
tasksDelivered: activeTasks.length,
|
|
896
|
+
});
|
|
897
|
+
}
|
|
898
|
+
/**
|
|
899
|
+
* Periodic check: is the runtime child process still alive?
|
|
900
|
+
*
|
|
901
|
+
* Uses the session backend's isChildProcessAlive() (pgrep -P <pid>)
|
|
902
|
+
* to determine if the CLI process has exited. This is a version-agnostic
|
|
903
|
+
* fallback that doesn't depend on any text the CLI prints.
|
|
904
|
+
*
|
|
905
|
+
* @param sessionName - PTY session name
|
|
906
|
+
* @param backend - Session backend for process checks
|
|
907
|
+
* @param helper - Session command helper for shell prompt verification
|
|
908
|
+
*/
|
|
909
|
+
checkProcessAlive(sessionName, backend, helper) {
|
|
910
|
+
const monitored = this.sessions.get(sessionName);
|
|
911
|
+
if (!monitored || monitored.exitDetected) {
|
|
912
|
+
return;
|
|
913
|
+
}
|
|
914
|
+
// Skip during startup grace period (CLI may not have spawned yet)
|
|
915
|
+
if (Date.now() - monitored.startedAt < RUNTIME_EXIT_CONSTANTS.PROCESS_POLL_GRACE_PERIOD_MS) {
|
|
916
|
+
return;
|
|
917
|
+
}
|
|
918
|
+
// Check if the backend supports process-alive checks
|
|
919
|
+
if (!backend.isChildProcessAlive) {
|
|
920
|
+
return;
|
|
921
|
+
}
|
|
922
|
+
const isAlive = backend.isChildProcessAlive(sessionName);
|
|
923
|
+
if (isAlive) {
|
|
924
|
+
return;
|
|
925
|
+
}
|
|
926
|
+
// Process is not alive — verify with shell prompt before confirming
|
|
927
|
+
if (!this.verifyExitWithShellPrompt(sessionName, helper)) {
|
|
928
|
+
this.logger.debug('Process not alive but shell prompt not confirmed, skipping', { sessionName });
|
|
929
|
+
return;
|
|
930
|
+
}
|
|
931
|
+
this.logger.info('Runtime exit detected via process check (no child process)', {
|
|
932
|
+
sessionName,
|
|
933
|
+
runtimeType: monitored.runtimeType,
|
|
934
|
+
});
|
|
935
|
+
// Trigger the same exit flow as pattern-based detection
|
|
936
|
+
this.confirmAndReact(sessionName, helper).catch((error) => {
|
|
937
|
+
this.logger.warn('confirmAndReact error from process check', {
|
|
938
|
+
sessionName,
|
|
939
|
+
error: error instanceof Error ? error.message : String(error),
|
|
940
|
+
});
|
|
941
|
+
});
|
|
942
|
+
}
|
|
943
|
+
/**
|
|
944
|
+
* Verify that a shell prompt is visible in the terminal, confirming
|
|
945
|
+
* that the agent CLI has actually exited and returned to the shell.
|
|
946
|
+
*/
|
|
947
|
+
verifyExitWithShellPrompt(sessionName, helper) {
|
|
948
|
+
try {
|
|
949
|
+
const output = helper.capturePane(sessionName);
|
|
950
|
+
return SHELL_PROMPT_PATTERNS.some((pattern) => pattern.test(output));
|
|
951
|
+
}
|
|
952
|
+
catch {
|
|
953
|
+
return false;
|
|
954
|
+
}
|
|
955
|
+
}
|
|
956
|
+
/**
|
|
957
|
+
* Check if an agent restart is allowed based on cooldown window.
|
|
958
|
+
* Prevents infinite restart loops when agents keep crashing (e.g. during
|
|
959
|
+
* network outages). Uses the same limits as AgentHeartbeatMonitorService.
|
|
960
|
+
*
|
|
961
|
+
* @param sessionName - PTY session name
|
|
962
|
+
* @returns True if restart is allowed, false if cooldown is active
|
|
963
|
+
*/
|
|
964
|
+
isAgentRestartAllowed(sessionName) {
|
|
965
|
+
const now = Date.now();
|
|
966
|
+
const windowStart = now - AGENT_HEARTBEAT_MONITOR_CONSTANTS.COOLDOWN_WINDOW_MS;
|
|
967
|
+
const timestamps = this.restartHistory.get(sessionName) || [];
|
|
968
|
+
// Prune old timestamps outside the cooldown window
|
|
969
|
+
const recent = timestamps.filter(ts => ts > windowStart);
|
|
970
|
+
this.restartHistory.set(sessionName, recent);
|
|
971
|
+
return recent.length < AGENT_HEARTBEAT_MONITOR_CONSTANTS.MAX_RESTARTS_PER_WINDOW;
|
|
972
|
+
}
|
|
973
|
+
/**
|
|
974
|
+
* Record a restart attempt for cooldown tracking.
|
|
975
|
+
*
|
|
976
|
+
* @param sessionName - PTY session name
|
|
977
|
+
*/
|
|
978
|
+
recordAgentRestart(sessionName) {
|
|
979
|
+
const timestamps = this.restartHistory.get(sessionName) || [];
|
|
980
|
+
timestamps.push(Date.now());
|
|
981
|
+
this.restartHistory.set(sessionName, timestamps);
|
|
982
|
+
}
|
|
983
|
+
/**
|
|
984
|
+
* Classify an error reason as transient or persistent.
|
|
985
|
+
*
|
|
986
|
+
* Transient errors (connectivity, timeout, quota) may resolve on retry.
|
|
987
|
+
* Persistent errors (auth, config, crash loop) require manual intervention.
|
|
988
|
+
*
|
|
989
|
+
* @param reason - The failure reason string
|
|
990
|
+
* @returns 'TRANSIENT' | 'PERSISTENT' | 'UNKNOWN'
|
|
991
|
+
*/
|
|
992
|
+
classifyError(reason) {
|
|
993
|
+
const transientPatterns = [
|
|
994
|
+
'timeout', 'connectivity', 'connection', 'quota', 'RESOURCE_EXHAUSTED',
|
|
995
|
+
'UNAVAILABLE', 'DEADLINE_EXCEEDED', 'network', 'INTERNAL',
|
|
996
|
+
];
|
|
997
|
+
const persistentPatterns = [
|
|
998
|
+
'auth', 'UNAUTHENTICATED', 'PERMISSION_DENIED', 'config',
|
|
999
|
+
'crash', 'cooldown', 'corruption', 'thinking.*blocks',
|
|
1000
|
+
];
|
|
1001
|
+
const lowerReason = reason.toLowerCase();
|
|
1002
|
+
if (transientPatterns.some(p => lowerReason.includes(p.toLowerCase()))) {
|
|
1003
|
+
return 'TRANSIENT';
|
|
1004
|
+
}
|
|
1005
|
+
if (persistentPatterns.some(p => new RegExp(p, 'i').test(reason))) {
|
|
1006
|
+
return 'PERSISTENT';
|
|
1007
|
+
}
|
|
1008
|
+
return 'UNKNOWN';
|
|
1009
|
+
}
|
|
1010
|
+
/**
|
|
1011
|
+
* Notify the orchestrator about an agent failure via the chat API (#129).
|
|
1012
|
+
*
|
|
1013
|
+
* Sends a structured failure notification with error classification so the
|
|
1014
|
+
* orchestrator can decide whether to restart the agent, reassign tasks,
|
|
1015
|
+
* or inform the user. This is fire-and-forget — failures are logged but
|
|
1016
|
+
* do not block the exit flow.
|
|
1017
|
+
*
|
|
1018
|
+
* @param sessionName - Failed agent's PTY session name
|
|
1019
|
+
* @param reason - Failure reason (runtime_exited, api_failure, etc.)
|
|
1020
|
+
* @param activeTasks - In-progress tasks the agent had, if any
|
|
1021
|
+
* @param restartSucceeded - Whether automatic restart succeeded
|
|
1022
|
+
*/
|
|
1023
|
+
notifyOrchestratorOfFailure(sessionName, reason, activeTasks, restartSucceeded) {
|
|
1024
|
+
const errorClass = this.classifyError(reason);
|
|
1025
|
+
const taskSummary = activeTasks.length > 0
|
|
1026
|
+
? activeTasks.map(t => `${t.taskName} (${t.status})`).join(', ')
|
|
1027
|
+
: '';
|
|
1028
|
+
const message = [
|
|
1029
|
+
`Agent failure notification: ${sessionName} became inactive.`,
|
|
1030
|
+
`Reason: ${reason}`,
|
|
1031
|
+
`Error classification: ${errorClass}`,
|
|
1032
|
+
activeTasks.length > 0 ? `Active tasks: ${taskSummary}` : 'No active tasks.',
|
|
1033
|
+
restartSucceeded
|
|
1034
|
+
? 'Automatic restart succeeded — agent is recovering.'
|
|
1035
|
+
: 'Automatic restart FAILED — please restart the agent or reassign its tasks.',
|
|
1036
|
+
].join('\n');
|
|
1037
|
+
// Send via chat API (fire-and-forget)
|
|
1038
|
+
const backend = getSessionBackendSync();
|
|
1039
|
+
if (!backend)
|
|
1040
|
+
return;
|
|
1041
|
+
const helper = createSessionCommandHelper(backend);
|
|
1042
|
+
const orchestratorSession = helper.getSession(ORCHESTRATOR_SESSION_NAME);
|
|
1043
|
+
if (!orchestratorSession) {
|
|
1044
|
+
this.logger.debug('Orchestrator session not found, skipping failure notification', { sessionName });
|
|
1045
|
+
return;
|
|
1046
|
+
}
|
|
1047
|
+
// Use the deliver endpoint for reliable delivery to the orchestrator
|
|
1048
|
+
const baseUrl = process.env.CREWLY_API_URL || `http://localhost:${WEB_CONSTANTS.PORTS.BACKEND}`;
|
|
1049
|
+
const body = JSON.stringify({
|
|
1050
|
+
message,
|
|
1051
|
+
force: true,
|
|
1052
|
+
});
|
|
1053
|
+
// Fire-and-forget HTTP call
|
|
1054
|
+
try {
|
|
1055
|
+
const url = new URL(`${baseUrl}/api/terminal/${ORCHESTRATOR_SESSION_NAME}/deliver`);
|
|
1056
|
+
const req = http.request(url, {
|
|
1057
|
+
method: 'POST',
|
|
1058
|
+
headers: {
|
|
1059
|
+
'Content-Type': 'application/json',
|
|
1060
|
+
'Content-Length': Buffer.byteLength(body).toString(),
|
|
1061
|
+
},
|
|
1062
|
+
});
|
|
1063
|
+
req.on('response', (res) => res.resume()); // Consume response to free socket
|
|
1064
|
+
req.on('error', (err) => {
|
|
1065
|
+
this.logger.debug('Failed to deliver failure notification to orchestrator (non-fatal)', {
|
|
1066
|
+
sessionName,
|
|
1067
|
+
error: err.message,
|
|
1068
|
+
});
|
|
1069
|
+
});
|
|
1070
|
+
req.write(body);
|
|
1071
|
+
req.end();
|
|
1072
|
+
}
|
|
1073
|
+
catch {
|
|
1074
|
+
// Non-fatal — notification delivery is best-effort
|
|
1075
|
+
}
|
|
1076
|
+
this.logger.info('Sent agent failure notification to orchestrator (#129)', {
|
|
1077
|
+
sessionName,
|
|
1078
|
+
reason,
|
|
1079
|
+
activeTaskCount: activeTasks.length,
|
|
1080
|
+
restartSucceeded,
|
|
1081
|
+
});
|
|
1082
|
+
}
|
|
1083
|
+
/**
|
|
1084
|
+
* #235: Infer dropout reason from the monitored session's buffer.
|
|
1085
|
+
*
|
|
1086
|
+
* @param monitored - Monitored session state
|
|
1087
|
+
* @returns Inferred dropout reason
|
|
1088
|
+
*/
|
|
1089
|
+
inferDropoutReason(monitored) {
|
|
1090
|
+
const buffer = monitored.buffer.toLowerCase();
|
|
1091
|
+
// #251: Check for tool-check loop (time-windowed timestamps)
|
|
1092
|
+
if (monitored.toolCheckLoopTimestamps.length >= GEMINI_TOOL_CHECK_LOOP_THRESHOLD) {
|
|
1093
|
+
return 'loop_detected';
|
|
1094
|
+
}
|
|
1095
|
+
// #188: Check for deliberation loop
|
|
1096
|
+
const deliberationCount = buffer.split(GEMINI_DELIBERATION_PATTERN).length - 1;
|
|
1097
|
+
if (deliberationCount >= GEMINI_DELIBERATION_THRESHOLD) {
|
|
1098
|
+
return 'loop_detected';
|
|
1099
|
+
}
|
|
1100
|
+
if (buffer.includes('update') && (buffer.includes('restart') || buffer.includes('upgrade'))) {
|
|
1101
|
+
return 'update_exit';
|
|
1102
|
+
}
|
|
1103
|
+
if (buffer.includes('fatal') || buffer.includes('panic') || buffer.includes('segfault') || buffer.includes('killed')) {
|
|
1104
|
+
return 'crash';
|
|
1105
|
+
}
|
|
1106
|
+
if (buffer.includes('task') && (buffer.includes('complete') || buffer.includes('done') || buffer.includes('finished'))) {
|
|
1107
|
+
return 'task_complete';
|
|
1108
|
+
}
|
|
1109
|
+
return 'idle_exit';
|
|
1110
|
+
}
|
|
1111
|
+
/**
|
|
1112
|
+
* Publish agent:status_changed and agent:inactive events to the EventBus.
|
|
1113
|
+
*
|
|
1114
|
+
* Looks up team/member names from StorageService to build the full
|
|
1115
|
+
* AgentEvent. This mirrors the pattern used in TeamsJsonWatcherService.
|
|
1116
|
+
*
|
|
1117
|
+
* @param sessionName - PTY session name
|
|
1118
|
+
* @param monitored - Monitored session state with teamId/memberId
|
|
1119
|
+
* @param storageService - StorageService instance for team/member lookup
|
|
1120
|
+
*/
|
|
1121
|
+
async publishInactiveEvent(sessionName, monitored, storageService) {
|
|
1122
|
+
if (!this.eventBusService) {
|
|
1123
|
+
return;
|
|
1124
|
+
}
|
|
1125
|
+
// Look up team and member names
|
|
1126
|
+
let teamName = '';
|
|
1127
|
+
let memberName = '';
|
|
1128
|
+
try {
|
|
1129
|
+
const result = await storageService.findMemberBySessionName(sessionName);
|
|
1130
|
+
if (result) {
|
|
1131
|
+
teamName = result.team.name;
|
|
1132
|
+
memberName = result.member.name;
|
|
1133
|
+
}
|
|
1134
|
+
}
|
|
1135
|
+
catch {
|
|
1136
|
+
// Best-effort — use empty names if lookup fails
|
|
1137
|
+
}
|
|
1138
|
+
const baseEvent = {
|
|
1139
|
+
id: crypto.randomUUID(),
|
|
1140
|
+
type: 'agent:status_changed',
|
|
1141
|
+
timestamp: new Date().toISOString(),
|
|
1142
|
+
teamId: monitored.teamId || '',
|
|
1143
|
+
teamName,
|
|
1144
|
+
memberId: monitored.memberId || '',
|
|
1145
|
+
memberName,
|
|
1146
|
+
sessionName,
|
|
1147
|
+
previousValue: CREWLY_CONSTANTS.AGENT_STATUSES.ACTIVE,
|
|
1148
|
+
newValue: CREWLY_CONSTANTS.AGENT_STATUSES.INACTIVE,
|
|
1149
|
+
changedField: 'agentStatus',
|
|
1150
|
+
};
|
|
1151
|
+
// Publish generic status_changed event
|
|
1152
|
+
this.eventBusService.publish(baseEvent);
|
|
1153
|
+
// Publish specific agent:inactive event
|
|
1154
|
+
this.eventBusService.publish({
|
|
1155
|
+
...baseEvent,
|
|
1156
|
+
id: crypto.randomUUID(),
|
|
1157
|
+
type: 'agent:inactive',
|
|
1158
|
+
});
|
|
1159
|
+
this.logger.info('Published agent:inactive event to EventBus', {
|
|
1160
|
+
sessionName,
|
|
1161
|
+
teamId: monitored.teamId,
|
|
1162
|
+
memberId: monitored.memberId,
|
|
1163
|
+
});
|
|
1164
|
+
}
|
|
1165
|
+
}
|
|
1166
|
+
//# sourceMappingURL=runtime-exit-monitor.service.js.map
|