crewly 1.0.11 → 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/config/constants.ts +6 -0
- package/config/roles/orchestrator/self-evolution.md +72 -0
- package/config/skills/orchestrator/read-session-logs/execute.sh +14 -0
- package/config/skills/orchestrator/read-session-logs/instructions.md +33 -0
- package/config/skills/orchestrator/read-session-logs/skill.json +20 -0
- package/config/skills/orchestrator/read-system-logs/execute.sh +18 -0
- package/config/skills/orchestrator/read-system-logs/instructions.md +30 -0
- package/config/skills/orchestrator/read-system-logs/skill.json +20 -0
- package/config/skills/orchestrator/reply-slack/execute.sh +12 -0
- package/config/skills/orchestrator/reply-slack/instructions.md +16 -1
- package/config/skills/orchestrator/report-bug/execute.sh +49 -0
- package/config/skills/orchestrator/report-bug/instructions.md +30 -0
- package/config/skills/orchestrator/report-bug/skill.json +20 -0
- package/dist/backend/backend/src/constants.d.ts +24 -1
- package/dist/backend/backend/src/constants.d.ts.map +1 -1
- package/dist/backend/backend/src/constants.js +25 -2
- package/dist/backend/backend/src/constants.js.map +1 -1
- package/dist/backend/backend/src/controllers/monitoring/terminal.controller.d.ts +14 -0
- package/dist/backend/backend/src/controllers/monitoring/terminal.controller.d.ts.map +1 -1
- package/dist/backend/backend/src/controllers/monitoring/terminal.controller.js +74 -0
- package/dist/backend/backend/src/controllers/monitoring/terminal.controller.js.map +1 -1
- package/dist/backend/backend/src/controllers/orchestrator/orchestrator.controller.d.ts.map +1 -1
- package/dist/backend/backend/src/controllers/orchestrator/orchestrator.controller.js +20 -34
- package/dist/backend/backend/src/controllers/orchestrator/orchestrator.controller.js.map +1 -1
- package/dist/backend/backend/src/index.d.ts.map +1 -1
- package/dist/backend/backend/src/index.js +16 -1
- package/dist/backend/backend/src/index.js.map +1 -1
- package/dist/backend/backend/src/routes/modules/terminal.routes.d.ts.map +1 -1
- package/dist/backend/backend/src/routes/modules/terminal.routes.js +2 -0
- package/dist/backend/backend/src/routes/modules/terminal.routes.js.map +1 -1
- package/dist/backend/backend/src/services/agent/agent-registration.service.d.ts +24 -2
- 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 +191 -89
- package/dist/backend/backend/src/services/agent/agent-registration.service.js.map +1 -1
- package/dist/backend/backend/src/services/agent/codex-runtime.service.d.ts +5 -1
- package/dist/backend/backend/src/services/agent/codex-runtime.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/agent/codex-runtime.service.js +10 -17
- package/dist/backend/backend/src/services/agent/codex-runtime.service.js.map +1 -1
- package/dist/backend/backend/src/services/agent/context-window-monitor.service.d.ts +16 -0
- package/dist/backend/backend/src/services/agent/context-window-monitor.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/agent/context-window-monitor.service.js +111 -10
- package/dist/backend/backend/src/services/agent/context-window-monitor.service.js.map +1 -1
- package/dist/backend/backend/src/services/agent/gemini-runtime.service.d.ts +33 -2
- package/dist/backend/backend/src/services/agent/gemini-runtime.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/agent/gemini-runtime.service.js +388 -20
- package/dist/backend/backend/src/services/agent/gemini-runtime.service.js.map +1 -1
- package/dist/backend/backend/src/services/agent/runtime-agent.service.abstract.d.ts +1 -1
- package/dist/backend/backend/src/services/agent/runtime-agent.service.abstract.d.ts.map +1 -1
- package/dist/backend/backend/src/services/agent/runtime-agent.service.abstract.js +1 -1
- package/dist/backend/backend/src/services/agent/runtime-agent.service.abstract.js.map +1 -1
- package/dist/backend/backend/src/services/agent/runtime-exit-monitor.service.d.ts +17 -2
- package/dist/backend/backend/src/services/agent/runtime-exit-monitor.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/agent/runtime-exit-monitor.service.js +105 -12
- package/dist/backend/backend/src/services/agent/runtime-exit-monitor.service.js.map +1 -1
- package/dist/backend/backend/src/services/core/config.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/core/config.service.js +3 -2
- package/dist/backend/backend/src/services/core/config.service.js.map +1 -1
- package/dist/backend/backend/src/services/messaging/message-queue.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/messaging/message-queue.service.js +17 -0
- package/dist/backend/backend/src/services/messaging/message-queue.service.js.map +1 -1
- package/dist/backend/backend/src/services/orchestrator/orchestrator-restart.service.d.ts +5 -0
- package/dist/backend/backend/src/services/orchestrator/orchestrator-restart.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/orchestrator/orchestrator-restart.service.js +42 -2
- package/dist/backend/backend/src/services/orchestrator/orchestrator-restart.service.js.map +1 -1
- package/dist/backend/backend/src/services/session/pty/pty-session-backend.d.ts +39 -0
- package/dist/backend/backend/src/services/session/pty/pty-session-backend.d.ts.map +1 -1
- package/dist/backend/backend/src/services/session/pty/pty-session-backend.js +121 -1
- package/dist/backend/backend/src/services/session/pty/pty-session-backend.js.map +1 -1
- package/dist/backend/backend/src/services/settings/settings.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/settings/settings.service.js +6 -0
- package/dist/backend/backend/src/services/settings/settings.service.js.map +1 -1
- package/dist/backend/backend/src/services/workflow/message-scheduler.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/workflow/message-scheduler.service.js +8 -1
- package/dist/backend/backend/src/services/workflow/message-scheduler.service.js.map +1 -1
- package/dist/backend/backend/src/services/workflow/scheduler.service.d.ts +1 -0
- package/dist/backend/backend/src/services/workflow/scheduler.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/workflow/scheduler.service.js +28 -1
- package/dist/backend/backend/src/services/workflow/scheduler.service.js.map +1 -1
- package/dist/backend/backend/src/types/settings.types.d.ts +4 -0
- package/dist/backend/backend/src/types/settings.types.d.ts.map +1 -1
- package/dist/backend/backend/src/types/settings.types.js +9 -1
- package/dist/backend/backend/src/types/settings.types.js.map +1 -1
- package/dist/backend/config/constants.d.ts +6 -0
- package/dist/backend/config/constants.d.ts.map +1 -1
- package/dist/backend/config/constants.js +6 -0
- package/dist/backend/config/constants.js.map +1 -1
- package/dist/backend/config/index.d.ts +3 -0
- package/dist/backend/config/index.d.ts.map +1 -1
- package/dist/cli/backend/src/constants.d.ts +24 -1
- package/dist/cli/backend/src/constants.d.ts.map +1 -1
- package/dist/cli/backend/src/constants.js +25 -2
- package/dist/cli/backend/src/constants.js.map +1 -1
- package/dist/cli/backend/src/services/core/config.service.d.ts.map +1 -1
- package/dist/cli/backend/src/services/core/config.service.js +3 -2
- package/dist/cli/backend/src/services/core/config.service.js.map +1 -1
- package/dist/cli/backend/src/types/settings.types.d.ts +4 -0
- package/dist/cli/backend/src/types/settings.types.d.ts.map +1 -1
- package/dist/cli/backend/src/types/settings.types.js +9 -1
- package/dist/cli/backend/src/types/settings.types.js.map +1 -1
- package/dist/cli/cli/src/index.js +1 -0
- package/dist/cli/cli/src/index.js.map +1 -1
- package/dist/cli/config/constants.d.ts +6 -0
- package/dist/cli/config/constants.d.ts.map +1 -1
- package/dist/cli/config/constants.js +6 -0
- package/dist/cli/config/constants.js.map +1 -1
- package/dist/cli/config/index.d.ts +3 -0
- package/dist/cli/config/index.d.ts.map +1 -1
- package/frontend/dist/assets/{index-0a245b0d.js → index-45eeea99.js} +2 -2
- package/frontend/dist/index.html +1 -1
- package/package.json +1 -1
|
@@ -26,6 +26,7 @@ export declare class AgentRegistrationService {
|
|
|
26
26
|
private stuckMessageDetectorTimer;
|
|
27
27
|
private tuiSessionRegistry;
|
|
28
28
|
private sentMessageTracker;
|
|
29
|
+
private sessionDeliveryMutex;
|
|
29
30
|
private static get CLAUDE_PROMPT_INDICATORS();
|
|
30
31
|
private static get CLAUDE_PROMPT_STREAM_PATTERN();
|
|
31
32
|
private static get CLAUDE_PROCESSING_INDICATORS();
|
|
@@ -46,6 +47,17 @@ export declare class AgentRegistrationService {
|
|
|
46
47
|
* Get session helper synchronously (may throw if not initialized)
|
|
47
48
|
*/
|
|
48
49
|
private getSessionHelperSync;
|
|
50
|
+
/**
|
|
51
|
+
* Resolve the runtime type for a session from storage.
|
|
52
|
+
* Checks orchestrator status first, then team member data.
|
|
53
|
+
* Falls back to CLAUDE_CODE if nothing is found.
|
|
54
|
+
*
|
|
55
|
+
* IMPORTANT: Callers should prefer passing runtimeType explicitly.
|
|
56
|
+
* This method exists as a safety net so that Ctrl+C (Claude Code
|
|
57
|
+
* cleanup) is never sent to a Gemini CLI session, which would
|
|
58
|
+
* trigger /quit and kill the agent.
|
|
59
|
+
*/
|
|
60
|
+
private resolveSessionRuntimeType;
|
|
49
61
|
/**
|
|
50
62
|
* Find the project root by looking for package.json
|
|
51
63
|
*/
|
|
@@ -85,7 +97,7 @@ export declare class AgentRegistrationService {
|
|
|
85
97
|
* Initialize agent with optimized 2-step escalation process
|
|
86
98
|
* Reduced from 4-step to 2-step with shorter timeouts for better concurrency
|
|
87
99
|
*/
|
|
88
|
-
initializeAgentWithRegistration(sessionName: string, role: string, projectPath?: string, timeout?: number, memberId?: string, runtimeType?: RuntimeType, runtimeFlags?: string[]): Promise<{
|
|
100
|
+
initializeAgentWithRegistration(sessionName: string, role: string, projectPath?: string, timeout?: number, memberId?: string, runtimeType?: RuntimeType, runtimeFlags?: string[], additionalAllowlistPaths?: string[]): Promise<{
|
|
89
101
|
success: boolean;
|
|
90
102
|
message?: string;
|
|
91
103
|
error?: string;
|
|
@@ -134,10 +146,13 @@ export declare class AgentRegistrationService {
|
|
|
134
146
|
*
|
|
135
147
|
* @param sessionName - Session name (used for filename)
|
|
136
148
|
* @param prompt - The full prompt content
|
|
137
|
-
* @param runtimeType - Runtime type (determines directory)
|
|
138
149
|
* @returns The absolute path to the written file, or undefined on error
|
|
139
150
|
*/
|
|
140
151
|
private writePromptFile;
|
|
152
|
+
/**
|
|
153
|
+
* Build the unified init prompt path used by all runtimes.
|
|
154
|
+
*/
|
|
155
|
+
private getInitPromptFilePath;
|
|
141
156
|
/**
|
|
142
157
|
* Wait for agent registration to complete
|
|
143
158
|
*/
|
|
@@ -179,6 +194,13 @@ export declare class AgentRegistrationService {
|
|
|
179
194
|
* @default false
|
|
180
195
|
*/
|
|
181
196
|
forceRecreate?: boolean;
|
|
197
|
+
/**
|
|
198
|
+
* Additional paths to add to Gemini CLI's /directory allowlist during
|
|
199
|
+
* postInitialize, before the registration prompt is sent. Used by the
|
|
200
|
+
* orchestrator to include all existing project paths so they don't
|
|
201
|
+
* race with the "Read the file..." prompt.
|
|
202
|
+
*/
|
|
203
|
+
additionalAllowlistPaths?: string[];
|
|
182
204
|
}): Promise<{
|
|
183
205
|
success: boolean;
|
|
184
206
|
sessionName?: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"agent-registration.service.d.ts","sourceRoot":"","sources":["../../../../../../backend/src/services/agent/agent-registration.service.ts"],"names":[],"mappings":"AAaA,OAAO,EAAE,cAAc,EAAE,MAAM,4BAA4B,CAAC;AAC5D,OAAO,EACN,gBAAgB,
|
|
1
|
+
{"version":3,"file":"agent-registration.service.d.ts","sourceRoot":"","sources":["../../../../../../backend/src/services/agent/agent-registration.service.ts"],"names":[],"mappings":"AAaA,OAAO,EAAE,cAAc,EAAE,MAAM,4BAA4B,CAAC;AAC5D,OAAO,EACN,gBAAgB,EAMhB,WAAW,EAKX,MAAM,oBAAoB,CAAC;AAU5B,MAAM,WAAW,kBAAkB;IAClC,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,CAAC,EAAE,MAAM,CAAC;CACpB;AAED;;;;;;;;;GASG;AACH,qBAAa,wBAAwB;IACpC,OAAO,CAAC,MAAM,CAAkB;IAChC,OAAO,CAAC,cAAc,CAAqC;IAC3D,OAAO,CAAC,cAAc,CAAiB;IACvC,OAAO,CAAC,WAAW,CAAS;IAG5B,OAAO,CAAC,WAAW,CAA6B;IAGhD,OAAO,CAAC,oBAAoB,CAA4G;IAGxI,OAAO,CAAC,4BAA4B,CAAsC;IAG1E,OAAO,CAAC,yBAAyB,CAA+C;IAGhF,OAAO,CAAC,kBAAkB,CAAkC;IAI5D,OAAO,CAAC,kBAAkB,CAIpB;IAKN,OAAO,CAAC,oBAAoB,CAAoC;IAKhE,OAAO,CAAC,MAAM,KAAK,wBAAwB,GAE1C;IAED,OAAO,CAAC,MAAM,KAAK,4BAA4B,GAE9C;IAED,OAAO,CAAC,MAAM,KAAK,4BAA4B,GAE9C;gBAGA,kBAAkB,EAAE,OAAO,EAAE,+CAA+C;IAC5E,WAAW,EAAE,MAAM,GAAG,IAAI,EAC1B,cAAc,EAAE,cAAc;IAmB/B;;;;;OAKG;IACH,yBAAyB,CAAC,WAAW,EAAE,MAAM,GAAG,IAAI;IASpD;;OAEG;YACW,gBAAgB;IA2B9B;;OAEG;IACH,OAAO,CAAC,oBAAoB;IAW5B;;;;;;;;;OASG;YACW,yBAAyB;IAyBvC;;OAEG;IACH,OAAO,CAAC,eAAe;IAKvB;;;;;;;;;OASG;YACW,mBAAmB;IAkDjC;;;OAGG;IACH,OAAO,CAAC,oBAAoB;IAI5B;;;OAGG;IACH,OAAO,CAAC,gBAAgB;IAIxB;;;OAGG;YACW,qBAAqB;IAkBnC;;;OAGG;YACW,oBAAoB;IAMlC;;;OAGG;IACG,+BAA+B,CACpC,WAAW,EAAE,MAAM,EACnB,IAAI,EAAE,MAAM,EACZ,WAAW,CAAC,EAAE,MAAM,EACpB,OAAO,GAAE,MAAoD,EAC7D,QAAQ,CAAC,EAAE,MAAM,EACjB,WAAW,GAAE,WAAuC,EACpD,YAAY,CAAC,EAAE,MAAM,EAAE,EACvB,wBAAwB,CAAC,EAAE,MAAM,EAAE,GACjC,OAAO,CAAC;QACV,OAAO,EAAE,OAAO,CAAC;QACjB,OAAO,CAAC,EAAE,MAAM,CAAC;QACjB,KAAK,CAAC,EAAE,MAAM,CAAC;KACf,CAAC;IAkFF;;;OAGG;YACW,qBAAqB;IA8CnC;;;OAGG;YACW,mBAAmB;IA+IjC;;;;;;;;;;;OAWG;YACW,uBAAuB;IA0CrC;;;;OAIG;YACW,2BAA2B;IA2CzC;;;OAGG;YACW,iBAAiB;IAkN/B;;OAEG;YACW,sBAAsB;IAuKpC;;;;;;;OAOG;YACW,eAAe;IA0B7B;;OAEG;IACH,OAAO,CAAC,qBAAqB;IAS7B;;OAEG;YACW,mBAAmB;IA8BjC;;OAEG;YACW,sBAAsB;IAiCpC;;;;OAIG;YACW,mCAAmC;IAgJjD;;OAEG;YACW,uBAAuB;IA8BrC;;OAEG;YACW,yBAAyB;IA0BvC;;;;OAIG;IACG,kBAAkB,CAAC,MAAM,EAAE;QAChC,WAAW,EAAE,MAAM,CAAC;QACpB,IAAI,EAAE,MAAM,CAAC;QACb,WAAW,CAAC,EAAE,MAAM,CAAC;QACrB,UAAU,CAAC,EAAE,MAAM,CAAC;QACpB,QAAQ,CAAC,EAAE,MAAM,CAAC;QAClB,WAAW,CAAC,EAAE,WAAW,CAAC;QAC1B,MAAM,CAAC,EAAE,MAAM,CAAC;QAChB;;;;WAIG;QACH,aAAa,CAAC,EAAE,OAAO,CAAC;QACxB;;;;;WAKG;QACH,wBAAwB,CAAC,EAAE,MAAM,EAAE,CAAC;KACpC,GAAG,OAAO,CAAC;QACX,OAAO,EAAE,OAAO,CAAC;QACjB,WAAW,CAAC,EAAE,MAAM,CAAC;QACrB,OAAO,CAAC,EAAE,MAAM,CAAC;QACjB,KAAK,CAAC,EAAE,MAAM,CAAC;KACf,CAAC;IA4BF;;;;OAIG;YACW,uBAAuB;IAmYrC;;;;;OAKG;IACG,qBAAqB,CAC1B,WAAW,EAAE,MAAM,EACnB,IAAI,GAAE,MAAkB,GACtB,OAAO,CAAC;QACV,OAAO,EAAE,OAAO,CAAC;QACjB,OAAO,CAAC,EAAE,MAAM,CAAC;QACjB,KAAK,CAAC,EAAE,MAAM,CAAC;KACf,CAAC;IAyEF;;;;;;;;;;;;;;;;;;;;;OAqBG;IACG,kBAAkB,CACvB,WAAW,EAAE,MAAM,EACnB,OAAO,EAAE,MAAM,EACf,WAAW,CAAC,EAAE,WAAW,GACvB,OAAO,CAAC;QACV,OAAO,EAAE,OAAO,CAAC;QACjB,OAAO,CAAC,EAAE,MAAM,CAAC;QACjB,KAAK,CAAC,EAAE,MAAM,CAAC;KACf,CAAC;IAiGF;;;;;;;;;;;OAWG;IACG,iBAAiB,CACtB,WAAW,EAAE,MAAM,EACnB,SAAS,GAAE,MAAqD,EAChE,WAAW,CAAC,EAAE,WAAW,GACvB,OAAO,CAAC,OAAO,CAAC;IAsFnB;;;;OAIG;YACW,kCAAkC;IAsRhD;;;;;;;;;OASG;YACW,oBAAoB;IAwelC;;;;;;;;;;OAUG;YACW,sBAAsB;IAmDpC;;;;;;;;;;;;;;;;OAgBG;IACH,OAAO,CAAC,sBAAsB;IAoD9B;;;;;;;OAOG;YACW,sBAAsB;IAuBpC;;;;;;;;;;OAUG;IACH,yBAAyB,IAAI,IAAI;IAsBjC;;OAEG;IACH,wBAAwB,IAAI,IAAI;IAQhC;;;;;;;;OAQG;YACW,oBAAoB;IA+GlC;;;;;OAKG;IACH,oBAAoB,CAAC,WAAW,EAAE,MAAM,GAAG,IAAI;IAK/C;;;;;;;OAOG;IACH,gBAAgB,CAAC,WAAW,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,IAAI;IAuB5D;;;;;;OAMG;IACH,OAAO,CAAC,0BAA0B;IAMlC;;;;;;OAMG;IACH,OAAO,CAAC,gBAAgB;IA8ExB;;;;;;;;;;OAUG;IACH,OAAO,CAAC,mBAAmB;IA0B3B;;;;;;;;;OASG;YACW,qBAAqB;IA+BnC;;;;;OAKG;IACG,cAAc,CACnB,WAAW,EAAE,MAAM,EACnB,GAAG,EAAE,MAAM,GACT,OAAO,CAAC;QACV,OAAO,EAAE,OAAO,CAAC;QACjB,OAAO,CAAC,EAAE,MAAM,CAAC;QACjB,KAAK,CAAC,EAAE,MAAM,CAAC;KACf,CAAC;IAyCF;;;;;;OAMG;IACG,gBAAgB,CACrB,WAAW,EAAE,MAAM,EACnB,IAAI,CAAC,EAAE,MAAM,EACb,OAAO,GAAE,MAAa,GACpB,OAAO,CAAC;QACV,OAAO,EAAE,OAAO,CAAC;QACjB,IAAI,CAAC,EAAE;YACN,KAAK,EAAE;gBACN,WAAW,EAAE,MAAM,CAAC;gBACpB,IAAI,CAAC,EAAE,MAAM,CAAC;gBACd,OAAO,EAAE,OAAO,CAAC;gBACjB,MAAM,EAAE,CAAC,OAAO,gBAAgB,CAAC,cAAc,CAAC,CAAC,MAAM,OAAO,gBAAgB,CAAC,cAAc,CAAC,CAAC;aAC/F,CAAC;YACF,SAAS,EAAE,MAAM,CAAC;SAClB,CAAC;QACF,KAAK,CAAC,EAAE,MAAM,CAAC;KACf,CAAC;IAuCF;;;;;;;;;;;;;OAaG;YACW,kBAAkB;CA6JhC"}
|
|
@@ -4,7 +4,7 @@ import { readFile, readdir, stat, mkdir, writeFile } from 'fs/promises';
|
|
|
4
4
|
import { LoggerService } from '../core/logger.service.js';
|
|
5
5
|
import { createSessionCommandHelper, getSessionBackendSync, createSessionBackend, getSessionStatePersistence, } from '../session/index.js';
|
|
6
6
|
import { RuntimeServiceFactory } from './runtime-service.factory.js';
|
|
7
|
-
import { CREWLY_CONSTANTS, ENV_CONSTANTS, AGENT_TIMEOUTS, ORCHESTRATOR_ROLE, RUNTIME_TYPES, SESSION_COMMAND_DELAYS, EVENT_DELIVERY_CONSTANTS, TERMINAL_PATTERNS, GEMINI_SHELL_MODE_CONSTANTS, } from '../../constants.js';
|
|
7
|
+
import { CREWLY_CONSTANTS, ENV_CONSTANTS, AGENT_TIMEOUTS, ORCHESTRATOR_SESSION_NAME, ORCHESTRATOR_ROLE, RUNTIME_TYPES, SESSION_COMMAND_DELAYS, EVENT_DELIVERY_CONSTANTS, TERMINAL_PATTERNS, GEMINI_SHELL_MODE_CONSTANTS, } from '../../constants.js';
|
|
8
8
|
import { WEB_CONSTANTS } from '../../../../config/constants.js';
|
|
9
9
|
import { delay } from '../../utils/async.utils.js';
|
|
10
10
|
import { getSettingsService } from '../settings/settings.service.js';
|
|
@@ -41,6 +41,10 @@ export class AgentRegistrationService {
|
|
|
41
41
|
// Track recently-sent messages for background stuck-detection (all runtimes).
|
|
42
42
|
// Key: sessionName, Value: array of tracked message entries
|
|
43
43
|
sentMessageTracker = new Map();
|
|
44
|
+
// Per-session delivery mutex to serialize message delivery.
|
|
45
|
+
// Prevents concurrent sendMessageWithRetry calls to the same session,
|
|
46
|
+
// which causes multiple Ctrl+C presses that can crash the runtime.
|
|
47
|
+
sessionDeliveryMutex = new Map();
|
|
44
48
|
// Terminal patterns are now centralized in TERMINAL_PATTERNS constant
|
|
45
49
|
// Keeping these as static getters for backwards compatibility within the class
|
|
46
50
|
static get CLAUDE_PROMPT_INDICATORS() {
|
|
@@ -119,6 +123,39 @@ export class AgentRegistrationService {
|
|
|
119
123
|
}
|
|
120
124
|
return this._sessionHelper;
|
|
121
125
|
}
|
|
126
|
+
/**
|
|
127
|
+
* Resolve the runtime type for a session from storage.
|
|
128
|
+
* Checks orchestrator status first, then team member data.
|
|
129
|
+
* Falls back to CLAUDE_CODE if nothing is found.
|
|
130
|
+
*
|
|
131
|
+
* IMPORTANT: Callers should prefer passing runtimeType explicitly.
|
|
132
|
+
* This method exists as a safety net so that Ctrl+C (Claude Code
|
|
133
|
+
* cleanup) is never sent to a Gemini CLI session, which would
|
|
134
|
+
* trigger /quit and kill the agent.
|
|
135
|
+
*/
|
|
136
|
+
async resolveSessionRuntimeType(sessionName) {
|
|
137
|
+
try {
|
|
138
|
+
// Check if this is the orchestrator session
|
|
139
|
+
if (sessionName === ORCHESTRATOR_SESSION_NAME) {
|
|
140
|
+
const orchestratorStatus = await this.storageService.getOrchestratorStatus();
|
|
141
|
+
if (orchestratorStatus?.runtimeType) {
|
|
142
|
+
return orchestratorStatus.runtimeType;
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
// Check team member data
|
|
146
|
+
const memberInfo = await this.storageService.findMemberBySessionName(sessionName);
|
|
147
|
+
if (memberInfo?.member?.runtimeType) {
|
|
148
|
+
return memberInfo.member.runtimeType;
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
catch (error) {
|
|
152
|
+
this.logger.debug('Could not resolve runtime type from storage, using default', {
|
|
153
|
+
sessionName,
|
|
154
|
+
error: error instanceof Error ? error.message : String(error),
|
|
155
|
+
});
|
|
156
|
+
}
|
|
157
|
+
return RUNTIME_TYPES.CLAUDE_CODE;
|
|
158
|
+
}
|
|
122
159
|
/**
|
|
123
160
|
* Find the project root by looking for package.json
|
|
124
161
|
*/
|
|
@@ -224,7 +261,7 @@ export class AgentRegistrationService {
|
|
|
224
261
|
* Initialize agent with optimized 2-step escalation process
|
|
225
262
|
* Reduced from 4-step to 2-step with shorter timeouts for better concurrency
|
|
226
263
|
*/
|
|
227
|
-
async initializeAgentWithRegistration(sessionName, role, projectPath, timeout = AGENT_TIMEOUTS.REGULAR_AGENT_INITIALIZATION, memberId, runtimeType = RUNTIME_TYPES.CLAUDE_CODE, runtimeFlags) {
|
|
264
|
+
async initializeAgentWithRegistration(sessionName, role, projectPath, timeout = AGENT_TIMEOUTS.REGULAR_AGENT_INITIALIZATION, memberId, runtimeType = RUNTIME_TYPES.CLAUDE_CODE, runtimeFlags, additionalAllowlistPaths) {
|
|
228
265
|
const startTime = Date.now();
|
|
229
266
|
this.logger.info('Starting optimized agent initialization with registration', {
|
|
230
267
|
sessionName,
|
|
@@ -245,7 +282,7 @@ export class AgentRegistrationService {
|
|
|
245
282
|
sessionName,
|
|
246
283
|
});
|
|
247
284
|
const step1Success = await this.tryCleanupAndReinit(sessionName, role, 70000, // 70 seconds for cleanup and reinit (allows 60s for runtime ready)
|
|
248
|
-
projectPath, memberId, runtimeType, runtimeFlags);
|
|
285
|
+
projectPath, memberId, runtimeType, runtimeFlags, additionalAllowlistPaths);
|
|
249
286
|
if (step1Success) {
|
|
250
287
|
return {
|
|
251
288
|
success: true,
|
|
@@ -325,7 +362,7 @@ export class AgentRegistrationService {
|
|
|
325
362
|
* Step 2: Cleanup with Ctrl+C and reinitialize
|
|
326
363
|
* Tries to reset the runtime session and start fresh
|
|
327
364
|
*/
|
|
328
|
-
async tryCleanupAndReinit(sessionName, role, timeout, projectPath, memberId, runtimeType = RUNTIME_TYPES.CLAUDE_CODE, runtimeFlags) {
|
|
365
|
+
async tryCleanupAndReinit(sessionName, role, timeout, projectPath, memberId, runtimeType = RUNTIME_TYPES.CLAUDE_CODE, runtimeFlags, additionalAllowlistPaths) {
|
|
329
366
|
// Clear Commandline
|
|
330
367
|
await (await this.getSessionHelper()).clearCurrentCommandLine(sessionName);
|
|
331
368
|
// Inject --resume flag if this was a previously running Claude Code session
|
|
@@ -360,7 +397,7 @@ export class AgentRegistrationService {
|
|
|
360
397
|
if (runtimeType === RUNTIME_TYPES.CLAUDE_CODE) {
|
|
361
398
|
try {
|
|
362
399
|
const prompt = await this.loadRegistrationPrompt(role, sessionName, memberId);
|
|
363
|
-
promptFilePath = await this.writePromptFile(sessionName, prompt
|
|
400
|
+
promptFilePath = await this.writePromptFile(sessionName, prompt);
|
|
364
401
|
}
|
|
365
402
|
catch (promptError) {
|
|
366
403
|
this.logger.warn('Failed to pre-write prompt file (non-fatal, will fall back to direct delivery)', {
|
|
@@ -387,7 +424,7 @@ export class AgentRegistrationService {
|
|
|
387
424
|
RuntimeExitMonitorService.getInstance().startMonitoring(sessionName, runtimeType, role);
|
|
388
425
|
// Run post-initialization hook (e.g., Gemini CLI directory allowlist)
|
|
389
426
|
try {
|
|
390
|
-
await runtimeService2.postInitialize(sessionName, projectPath);
|
|
427
|
+
await runtimeService2.postInitialize(sessionName, projectPath, additionalAllowlistPaths);
|
|
391
428
|
// Drain stale terminal escape sequences (e.g. DA1 [?1;2c) that may have
|
|
392
429
|
// arrived during postInitialize commands, so they don't leak into the prompt input
|
|
393
430
|
await delay(500);
|
|
@@ -502,13 +539,22 @@ export class AgentRegistrationService {
|
|
|
502
539
|
const controller = new AbortController();
|
|
503
540
|
this.registrationAbortControllers.set(sessionName, controller);
|
|
504
541
|
try {
|
|
542
|
+
this.logger.info('Loading registration prompt', { sessionName, role, runtimeType });
|
|
505
543
|
if (controller.signal.aborted)
|
|
506
544
|
return;
|
|
507
545
|
const prompt = await this.loadRegistrationPrompt(role, sessionName, memberId);
|
|
546
|
+
this.logger.info('Registration prompt loaded, sending to agent', {
|
|
547
|
+
sessionName, role, runtimeType, promptLength: prompt.length,
|
|
548
|
+
});
|
|
508
549
|
if (controller.signal.aborted)
|
|
509
550
|
return;
|
|
510
|
-
await this.sendPromptRobustly(sessionName, prompt, runtimeType, controller.signal);
|
|
511
|
-
|
|
551
|
+
const sent = await this.sendPromptRobustly(sessionName, prompt, runtimeType, controller.signal);
|
|
552
|
+
if (sent) {
|
|
553
|
+
this.logger.info('Registration prompt sent successfully', { sessionName, role });
|
|
554
|
+
}
|
|
555
|
+
else {
|
|
556
|
+
this.logger.warn('Registration prompt delivery returned false', { sessionName, role, runtimeType });
|
|
557
|
+
}
|
|
512
558
|
}
|
|
513
559
|
catch (error) {
|
|
514
560
|
if (controller.signal.aborted) {
|
|
@@ -518,6 +564,7 @@ export class AgentRegistrationService {
|
|
|
518
564
|
this.logger.warn('Failed to send registration prompt asynchronously', {
|
|
519
565
|
sessionName,
|
|
520
566
|
error: error instanceof Error ? error.message : String(error),
|
|
567
|
+
stack: error instanceof Error ? error.stack : undefined,
|
|
521
568
|
});
|
|
522
569
|
}
|
|
523
570
|
finally {
|
|
@@ -565,7 +612,7 @@ export class AgentRegistrationService {
|
|
|
565
612
|
if (runtimeType === RUNTIME_TYPES.CLAUDE_CODE) {
|
|
566
613
|
try {
|
|
567
614
|
const prompt = await this.loadRegistrationPrompt(role, sessionName, memberId);
|
|
568
|
-
promptFilePath = await this.writePromptFile(sessionName, prompt
|
|
615
|
+
promptFilePath = await this.writePromptFile(sessionName, prompt);
|
|
569
616
|
}
|
|
570
617
|
catch (promptError) {
|
|
571
618
|
this.logger.warn('Failed to pre-write prompt file in full recreation (non-fatal)', {
|
|
@@ -598,16 +645,27 @@ export class AgentRegistrationService {
|
|
|
598
645
|
// Wait a bit longer for runtime to fully load after showing welcome message
|
|
599
646
|
this.logger.debug('Runtime ready detected for orchestrator, waiting for full startup before verification', { sessionName, runtimeType });
|
|
600
647
|
await delay(5000);
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
648
|
+
// Codex CLI is sensitive to active key-probe verification (it may drop to
|
|
649
|
+
// the shell when probe keys are interpreted outside the TUI). We already
|
|
650
|
+
// passed waitForRuntimeReady above, so skip the extra command probe here.
|
|
651
|
+
if (runtimeType !== RUNTIME_TYPES.CODEX_CLI) {
|
|
652
|
+
this.logger.debug('Verifying orchestrator runtime responsiveness', {
|
|
653
|
+
sessionName,
|
|
654
|
+
runtimeType,
|
|
655
|
+
});
|
|
656
|
+
// runtimeService4: Final verification instance for orchestrator responsiveness
|
|
657
|
+
// Clean instance for post-initialization responsiveness testing
|
|
658
|
+
const runtimeService4 = this.createRuntimeService(runtimeType);
|
|
659
|
+
const runtimeResponding = await runtimeService4.detectRuntimeWithCommand(sessionName);
|
|
660
|
+
if (!runtimeResponding) {
|
|
661
|
+
throw new Error(`${runtimeType} not responding to commands after orchestrator recreation`);
|
|
662
|
+
}
|
|
663
|
+
}
|
|
664
|
+
else {
|
|
665
|
+
this.logger.debug('Skipping active runtime probe for Codex orchestrator recreation', {
|
|
666
|
+
sessionName,
|
|
667
|
+
runtimeType,
|
|
668
|
+
});
|
|
611
669
|
}
|
|
612
670
|
this.logger.debug('Runtime confirmed ready for orchestrator in Step 3', { sessionName, runtimeType });
|
|
613
671
|
}
|
|
@@ -789,6 +847,24 @@ export class AgentRegistrationService {
|
|
|
789
847
|
if (memberId) {
|
|
790
848
|
prompt += `\n- **Member ID:** ${memberId}`;
|
|
791
849
|
}
|
|
850
|
+
// Conditionally append Self Evolution instructions for the orchestrator
|
|
851
|
+
if (role === ORCHESTRATOR_ROLE) {
|
|
852
|
+
try {
|
|
853
|
+
const settings = await getSettingsService().getSettings();
|
|
854
|
+
if (settings.general.enableSelfEvolution) {
|
|
855
|
+
const selfEvoPath = path.join(this.projectRoot, 'config', 'roles', 'orchestrator', 'self-evolution.md');
|
|
856
|
+
const selfEvoPrompt = await readFile(selfEvoPath, 'utf8');
|
|
857
|
+
prompt += `\n\n---\n\n${selfEvoPrompt}`;
|
|
858
|
+
this.logger.info('Self Evolution prompt injected', { sessionName });
|
|
859
|
+
}
|
|
860
|
+
}
|
|
861
|
+
catch (selfEvoError) {
|
|
862
|
+
this.logger.warn('Failed to load self-evolution prompt (non-critical)', {
|
|
863
|
+
sessionName,
|
|
864
|
+
error: selfEvoError instanceof Error ? selfEvoError.message : String(selfEvoError),
|
|
865
|
+
});
|
|
866
|
+
}
|
|
867
|
+
}
|
|
792
868
|
return prompt;
|
|
793
869
|
}
|
|
794
870
|
catch (error) {
|
|
@@ -825,15 +901,11 @@ After checking in, just say "Ready for tasks" and wait for me to send you work.`
|
|
|
825
901
|
*
|
|
826
902
|
* @param sessionName - Session name (used for filename)
|
|
827
903
|
* @param prompt - The full prompt content
|
|
828
|
-
* @param runtimeType - Runtime type (determines directory)
|
|
829
904
|
* @returns The absolute path to the written file, or undefined on error
|
|
830
905
|
*/
|
|
831
|
-
async writePromptFile(sessionName, prompt
|
|
832
|
-
const
|
|
833
|
-
const promptsDir =
|
|
834
|
-
? path.join(os.homedir(), CREWLY_CONSTANTS.PATHS.CREWLY_HOME, 'prompts')
|
|
835
|
-
: path.join(this.projectRoot, '.crewly', 'prompts');
|
|
836
|
-
const promptFilePath = path.join(promptsDir, `${sessionName}-init.md`);
|
|
906
|
+
async writePromptFile(sessionName, prompt) {
|
|
907
|
+
const promptFilePath = this.getInitPromptFilePath(sessionName);
|
|
908
|
+
const promptsDir = path.dirname(promptFilePath);
|
|
837
909
|
try {
|
|
838
910
|
await mkdir(promptsDir, { recursive: true });
|
|
839
911
|
await writeFile(promptFilePath, prompt, 'utf8');
|
|
@@ -853,6 +925,12 @@ After checking in, just say "Ready for tasks" and wait for me to send you work.`
|
|
|
853
925
|
return undefined;
|
|
854
926
|
}
|
|
855
927
|
}
|
|
928
|
+
/**
|
|
929
|
+
* Build the unified init prompt path used by all runtimes.
|
|
930
|
+
*/
|
|
931
|
+
getInitPromptFilePath(sessionName) {
|
|
932
|
+
return path.join(os.homedir(), CREWLY_CONSTANTS.PATHS.CREWLY_HOME, 'prompts', `${sessionName}-init.md`);
|
|
933
|
+
}
|
|
856
934
|
/**
|
|
857
935
|
* Wait for agent registration to complete
|
|
858
936
|
*/
|
|
@@ -1291,7 +1369,7 @@ After checking in, just say "Ready for tasks" and wait for me to send you work.`
|
|
|
1291
1369
|
}
|
|
1292
1370
|
// Start context window monitoring for recovered non-orchestrator session
|
|
1293
1371
|
if (role !== ORCHESTRATOR_ROLE && config.teamId && config.memberId) {
|
|
1294
|
-
ContextWindowMonitorService.getInstance().startSessionMonitoring(sessionName, config.memberId, config.teamId, role);
|
|
1372
|
+
ContextWindowMonitorService.getInstance().startSessionMonitoring(sessionName, config.memberId, config.teamId, role, runtimeType);
|
|
1295
1373
|
}
|
|
1296
1374
|
return {
|
|
1297
1375
|
success: true,
|
|
@@ -1366,7 +1444,7 @@ After checking in, just say "Ready for tasks" and wait for me to send you work.`
|
|
|
1366
1444
|
const timeout = role === ORCHESTRATOR_ROLE
|
|
1367
1445
|
? AGENT_TIMEOUTS.ORCHESTRATOR_INITIALIZATION
|
|
1368
1446
|
: AGENT_TIMEOUTS.REGULAR_AGENT_INITIALIZATION;
|
|
1369
|
-
const initResult = await this.initializeAgentWithRegistration(sessionName, role, projectPath, timeout, memberId, runtimeType, runtimeFlags);
|
|
1447
|
+
const initResult = await this.initializeAgentWithRegistration(sessionName, role, projectPath, timeout, memberId, runtimeType, runtimeFlags, config.additionalAllowlistPaths);
|
|
1370
1448
|
if (!initResult.success) {
|
|
1371
1449
|
return {
|
|
1372
1450
|
success: false,
|
|
@@ -1376,7 +1454,7 @@ After checking in, just say "Ready for tasks" and wait for me to send you work.`
|
|
|
1376
1454
|
}
|
|
1377
1455
|
// Start context window monitoring for newly created non-orchestrator session
|
|
1378
1456
|
if (role !== ORCHESTRATOR_ROLE && config.teamId && config.memberId) {
|
|
1379
|
-
ContextWindowMonitorService.getInstance().startSessionMonitoring(sessionName, config.memberId, config.teamId, role);
|
|
1457
|
+
ContextWindowMonitorService.getInstance().startSessionMonitoring(sessionName, config.memberId, config.teamId, role, runtimeType);
|
|
1380
1458
|
}
|
|
1381
1459
|
return {
|
|
1382
1460
|
success: true,
|
|
@@ -1490,7 +1568,22 @@ After checking in, just say "Ready for tasks" and wait for me to send you work.`
|
|
|
1490
1568
|
* }
|
|
1491
1569
|
* ```
|
|
1492
1570
|
*/
|
|
1493
|
-
async sendMessageToAgent(sessionName, message, runtimeType
|
|
1571
|
+
async sendMessageToAgent(sessionName, message, runtimeType) {
|
|
1572
|
+
// Per-session delivery serialization: chain this delivery after any
|
|
1573
|
+
// in-flight delivery to the same session. This prevents concurrent
|
|
1574
|
+
// sendMessageWithRetry calls that each send Ctrl+C on retry attempts,
|
|
1575
|
+
// which can kill the runtime when 25+ scheduled checks fire at once.
|
|
1576
|
+
const previousDelivery = this.sessionDeliveryMutex.get(sessionName);
|
|
1577
|
+
let releaseMutex;
|
|
1578
|
+
const currentDelivery = new Promise((r) => { releaseMutex = r; });
|
|
1579
|
+
this.sessionDeliveryMutex.set(sessionName, currentDelivery);
|
|
1580
|
+
if (previousDelivery) {
|
|
1581
|
+
this.logger.info('Waiting for in-flight delivery to complete before sending', {
|
|
1582
|
+
sessionName,
|
|
1583
|
+
messageLength: message.length,
|
|
1584
|
+
});
|
|
1585
|
+
await previousDelivery.catch(() => { });
|
|
1586
|
+
}
|
|
1494
1587
|
try {
|
|
1495
1588
|
if (!message || typeof message !== 'string') {
|
|
1496
1589
|
return {
|
|
@@ -1498,6 +1591,12 @@ After checking in, just say "Ready for tasks" and wait for me to send you work.`
|
|
|
1498
1591
|
error: 'Message is required and must be a string',
|
|
1499
1592
|
};
|
|
1500
1593
|
}
|
|
1594
|
+
// Auto-resolve runtime type if not provided.
|
|
1595
|
+
// CRITICAL: defaulting to CLAUDE_CODE is dangerous because
|
|
1596
|
+
// Ctrl+C cleanup (Claude Code behavior) triggers /quit on Gemini CLI.
|
|
1597
|
+
if (!runtimeType) {
|
|
1598
|
+
runtimeType = await this.resolveSessionRuntimeType(sessionName);
|
|
1599
|
+
}
|
|
1501
1600
|
// Get session helper once for this method
|
|
1502
1601
|
const sessionHelper = await this.getSessionHelper();
|
|
1503
1602
|
// Check if session exists
|
|
@@ -1549,6 +1648,12 @@ After checking in, just say "Ready for tasks" and wait for me to send you work.`
|
|
|
1549
1648
|
error: errorMessage,
|
|
1550
1649
|
};
|
|
1551
1650
|
}
|
|
1651
|
+
finally {
|
|
1652
|
+
releaseMutex();
|
|
1653
|
+
if (this.sessionDeliveryMutex.get(sessionName) === currentDelivery) {
|
|
1654
|
+
this.sessionDeliveryMutex.delete(sessionName);
|
|
1655
|
+
}
|
|
1656
|
+
}
|
|
1552
1657
|
}
|
|
1553
1658
|
/**
|
|
1554
1659
|
* Wait for an agent session to be at a ready prompt before sending messages.
|
|
@@ -2275,8 +2380,14 @@ After checking in, just say "Ready for tasks" and wait for me to send you work.`
|
|
|
2275
2380
|
const hasGeminiIndicators = newContent.length > 0
|
|
2276
2381
|
&& /reading|thinking|processing|analyzing|generating|searching/i.test(newContent);
|
|
2277
2382
|
const significantLengthChange = Math.abs(lengthDiff) > 10;
|
|
2383
|
+
// For Gemini CLI, contentChanged alone is sufficient evidence of
|
|
2384
|
+
// delivery. The TUI redraws minimally (lengthDiff can be as low as
|
|
2385
|
+
// 1-2 chars) when processing starts, so requiring significantLengthChange
|
|
2386
|
+
// causes false "stuck" detection. False "stuck" + Ctrl+C kills the CLI.
|
|
2387
|
+
const isGemini = runtimeType === RUNTIME_TYPES.GEMINI_CLI;
|
|
2278
2388
|
const delivered = (lengthDiff > 20)
|
|
2279
2389
|
|| (contentChanged && significantLengthChange)
|
|
2390
|
+
|| (contentChanged && isGemini)
|
|
2280
2391
|
|| hasProcessingIndicators
|
|
2281
2392
|
|| hasGeminiIndicators;
|
|
2282
2393
|
if (delivered) {
|
|
@@ -2311,31 +2422,18 @@ After checking in, just say "Ready for tasks" and wait for me to send you work.`
|
|
|
2311
2422
|
await sessionHelper.clearCurrentCommandLine(sessionName);
|
|
2312
2423
|
}
|
|
2313
2424
|
else {
|
|
2314
|
-
// Gemini CLI retry cleanup:
|
|
2315
|
-
//
|
|
2316
|
-
// input box
|
|
2317
|
-
//
|
|
2318
|
-
|
|
2319
|
-
|
|
2320
|
-
|
|
2321
|
-
|
|
2322
|
-
|
|
2323
|
-
|
|
2324
|
-
|
|
2325
|
-
|
|
2326
|
-
// Tab triggers focusNext() in Ink's FocusContext, which should
|
|
2327
|
-
// cycle focus back to the InputPrompt component even when it's
|
|
2328
|
-
// defocused. This is more reliable than Enter (which is silently
|
|
2329
|
-
// consumed when no component is focused).
|
|
2330
|
-
await sessionHelper.sendKey(sessionName, 'Tab');
|
|
2331
|
-
await delay(300);
|
|
2332
|
-
await sessionHelper.sendEnter(sessionName);
|
|
2333
|
-
await delay(300);
|
|
2334
|
-
}
|
|
2335
|
-
else {
|
|
2336
|
-
await sessionHelper.sendCtrlC(sessionName);
|
|
2337
|
-
await delay(200);
|
|
2338
|
-
}
|
|
2425
|
+
// Gemini CLI retry cleanup: NEVER send Ctrl+C — it triggers /quit
|
|
2426
|
+
// and kills the CLI entirely, regardless of whether text is in the
|
|
2427
|
+
// input box or not. Use Tab to cycle Ink focus back to the input
|
|
2428
|
+
// prompt, then Enter to submit any pending text.
|
|
2429
|
+
this.logger.warn('Gemini CLI message stuck — using Tab focus recovery (no Ctrl+C)', {
|
|
2430
|
+
sessionName,
|
|
2431
|
+
attempt,
|
|
2432
|
+
});
|
|
2433
|
+
await sessionHelper.sendKey(sessionName, 'Tab');
|
|
2434
|
+
await delay(300);
|
|
2435
|
+
await sessionHelper.sendEnter(sessionName);
|
|
2436
|
+
await delay(300);
|
|
2339
2437
|
}
|
|
2340
2438
|
await delay(SESSION_COMMAND_DELAYS.CLEAR_COMMAND_DELAY);
|
|
2341
2439
|
if (attempt < maxAttempts) {
|
|
@@ -2950,7 +3048,7 @@ After checking in, just say "Ready for tasks" and wait for me to send you work.`
|
|
|
2950
3048
|
const isClaudeCode = runtimeType === RUNTIME_TYPES.CLAUDE_CODE;
|
|
2951
3049
|
const sessionHelper = await this.getSessionHelper();
|
|
2952
3050
|
// Step 1: Write prompt to a file (idempotent — may already exist from pre-launch write).
|
|
2953
|
-
const promptFilePath = await this.writePromptFile(sessionName, prompt
|
|
3051
|
+
const promptFilePath = await this.writePromptFile(sessionName, prompt);
|
|
2954
3052
|
if (!promptFilePath) {
|
|
2955
3053
|
// File write failure is fatal — all runtimes use the file-read approach.
|
|
2956
3054
|
return false;
|
|
@@ -2964,12 +3062,16 @@ After checking in, just say "Ready for tasks" and wait for me to send you work.`
|
|
|
2964
3062
|
const messageToSend = isClaudeCode
|
|
2965
3063
|
? 'Begin your work now. Follow the instructions you were given and start by doing an initial assessment of the project.'
|
|
2966
3064
|
: `Read the file at ${promptFilePath} and follow all instructions in it.`;
|
|
2967
|
-
//
|
|
2968
|
-
//
|
|
2969
|
-
//
|
|
2970
|
-
//
|
|
2971
|
-
//
|
|
2972
|
-
|
|
3065
|
+
// Single attempt for all runtimes. Retrying causes duplicate messages because:
|
|
3066
|
+
// - Claude Code: returns to its prompt between tool calls, making retry
|
|
3067
|
+
// checks think the first message wasn't received.
|
|
3068
|
+
// - Gemini CLI: the echoed message "Read the file at..." starts with `> `
|
|
3069
|
+
// which isClaudeAtPrompt misdetects as an idle prompt, and the TUI's
|
|
3070
|
+
// input box shows `> ` even during processing. Both cause false-negative
|
|
3071
|
+
// delivery verification and unnecessary retries.
|
|
3072
|
+
// The sendMessage helper reliably writes to the PTY — if it succeeds,
|
|
3073
|
+
// the message was delivered.
|
|
3074
|
+
const maxAttempts = 1;
|
|
2973
3075
|
for (let attempt = 1; attempt <= maxAttempts; attempt++) {
|
|
2974
3076
|
// Check abort before each attempt
|
|
2975
3077
|
if (abortSignal?.aborted) {
|
|
@@ -2977,7 +3079,7 @@ After checking in, just say "Ready for tasks" and wait for me to send you work.`
|
|
|
2977
3079
|
return false;
|
|
2978
3080
|
}
|
|
2979
3081
|
try {
|
|
2980
|
-
this.logger.
|
|
3082
|
+
this.logger.info('Sending prompt to agent', {
|
|
2981
3083
|
sessionName,
|
|
2982
3084
|
attempt,
|
|
2983
3085
|
runtimeType,
|
|
@@ -2990,13 +3092,23 @@ After checking in, just say "Ready for tasks" and wait for me to send you work.`
|
|
|
2990
3092
|
return false;
|
|
2991
3093
|
}
|
|
2992
3094
|
// Clear any pending input before sending the instruction (first attempt only).
|
|
2993
|
-
|
|
2994
|
-
|
|
2995
|
-
|
|
2996
|
-
|
|
2997
|
-
|
|
2998
|
-
|
|
2999
|
-
|
|
3095
|
+
if (attempt === 1) {
|
|
3096
|
+
if (isClaudeCode) {
|
|
3097
|
+
// Claude Code: Escape closes slash menus + Ctrl+U clears line.
|
|
3098
|
+
await sessionHelper.sendEscape(sessionName);
|
|
3099
|
+
await delay(200);
|
|
3100
|
+
await sessionHelper.sendKey(sessionName, 'C-u');
|
|
3101
|
+
await delay(300);
|
|
3102
|
+
}
|
|
3103
|
+
else {
|
|
3104
|
+
// Gemini CLI (Ink TUI): After /directory add processing, the TUI
|
|
3105
|
+
// input may lose focus or have stale invisible characters.
|
|
3106
|
+
// Send Enter to flush any residual input, then wait for the
|
|
3107
|
+
// prompt to settle before sending the real instruction.
|
|
3108
|
+
this.logger.debug('Gemini CLI pre-send: flushing input with Enter', { sessionName });
|
|
3109
|
+
await sessionHelper.sendEnter(sessionName);
|
|
3110
|
+
await delay(1000);
|
|
3111
|
+
}
|
|
3000
3112
|
}
|
|
3001
3113
|
// Check abort right before writing instruction to terminal
|
|
3002
3114
|
if (abortSignal?.aborted) {
|
|
@@ -3039,27 +3151,17 @@ After checking in, just say "Ready for tasks" and wait for me to send you work.`
|
|
|
3039
3151
|
});
|
|
3040
3152
|
return false;
|
|
3041
3153
|
}
|
|
3042
|
-
// Gemini CLI / other runtimes:
|
|
3043
|
-
//
|
|
3044
|
-
//
|
|
3045
|
-
|
|
3046
|
-
|
|
3047
|
-
|
|
3048
|
-
|
|
3049
|
-
const afterOutput = sessionHelper.capturePane(sessionName, 20);
|
|
3050
|
-
const hasProcessingIndicators = /thinking|processing|analyzing|registering|reading/i.test(afterOutput);
|
|
3051
|
-
if (hasProcessingIndicators) {
|
|
3052
|
-
this.logger.debug('Prompt instruction delivered successfully', {
|
|
3053
|
-
sessionName, attempt, runtimeType,
|
|
3054
|
-
});
|
|
3055
|
-
return true;
|
|
3056
|
-
}
|
|
3057
|
-
this.logger.debug('Prompt instruction delivery unconfirmed - retrying', {
|
|
3154
|
+
// Gemini CLI / other runtimes: trust the PTY delivery.
|
|
3155
|
+
// sendMessage writes directly to the PTY — if it didn't throw,
|
|
3156
|
+
// the message was delivered. Terminal-based verification is unreliable
|
|
3157
|
+
// because Gemini's TUI always shows `> ` (even during processing)
|
|
3158
|
+
// and our echoed message starts with `> `, both causing false
|
|
3159
|
+
// "at prompt" detection.
|
|
3160
|
+
this.logger.info('Prompt instruction sent to PTY (trusting delivery)', {
|
|
3058
3161
|
sessionName, attempt, runtimeType,
|
|
3162
|
+
messageLength: messageToSend.length,
|
|
3059
3163
|
});
|
|
3060
|
-
|
|
3061
|
-
await delay(1000);
|
|
3062
|
-
}
|
|
3164
|
+
return true;
|
|
3063
3165
|
}
|
|
3064
3166
|
catch (error) {
|
|
3065
3167
|
this.logger.error('Error during prompt instruction delivery', {
|