@shepai/cli 1.123.0 → 1.124.0-pr381.1811a4e
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/dist/packages/core/src/infrastructure/services/agents/common/agent-executor-factory.service.js +1 -1
- package/dist/packages/core/src/infrastructure/services/agents/common/executors/cursor-executor.service.d.ts +28 -8
- package/dist/packages/core/src/infrastructure/services/agents/common/executors/cursor-executor.service.d.ts.map +1 -1
- package/dist/packages/core/src/infrastructure/services/agents/common/executors/cursor-executor.service.js +250 -43
- package/dist/packages/core/src/infrastructure/services/agents/feature-agent/feature-agent-worker.d.ts.map +1 -1
- package/dist/packages/core/src/infrastructure/services/agents/feature-agent/feature-agent-worker.js +9 -0
- package/dist/packages/core/src/infrastructure/services/agents/feature-agent/nodes/merge/merge.node.d.ts +5 -0
- package/dist/packages/core/src/infrastructure/services/agents/feature-agent/nodes/merge/merge.node.d.ts.map +1 -1
- package/dist/packages/core/src/infrastructure/services/agents/feature-agent/nodes/merge/merge.node.js +82 -54
- package/dist/packages/core/src/infrastructure/services/agents/feature-agent/nodes/node-helpers.d.ts.map +1 -1
- package/dist/packages/core/src/infrastructure/services/agents/feature-agent/nodes/node-helpers.js +2 -2
- package/dist/src/presentation/web/components/common/feature-node/feature-node.d.ts.map +1 -1
- package/dist/src/presentation/web/components/common/feature-node/feature-node.js +14 -6
- package/dist/src/presentation/web/components/common/feature-node/feature-node.stories.d.ts +1 -0
- package/dist/src/presentation/web/components/common/feature-node/feature-node.stories.d.ts.map +1 -1
- package/dist/src/presentation/web/components/common/feature-node/feature-node.stories.js +16 -0
- package/dist/tsconfig.build.tsbuildinfo +1 -1
- package/package.json +1 -1
- package/web/.next/BUILD_ID +1 -1
- package/web/.next/build-manifest.json +2 -2
- package/web/.next/fallback-build-manifest.json +2 -2
- package/web/.next/prerender-manifest.json +3 -3
- package/web/.next/required-server-files.js +3 -3
- package/web/.next/required-server-files.json +3 -3
- package/web/.next/server/app/(dashboard)/@drawer/create/page/server-reference-manifest.json +22 -22
- package/web/.next/server/app/(dashboard)/@drawer/create/page.js.nft.json +1 -1
- package/web/.next/server/app/(dashboard)/@drawer/create/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/(dashboard)/@drawer/feature/[featureId]/[tab]/page/server-reference-manifest.json +28 -28
- package/web/.next/server/app/(dashboard)/@drawer/feature/[featureId]/[tab]/page.js.nft.json +1 -1
- package/web/.next/server/app/(dashboard)/@drawer/feature/[featureId]/[tab]/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/(dashboard)/@drawer/feature/[featureId]/page/server-reference-manifest.json +28 -28
- package/web/.next/server/app/(dashboard)/@drawer/feature/[featureId]/page.js.nft.json +1 -1
- package/web/.next/server/app/(dashboard)/@drawer/feature/[featureId]/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/(dashboard)/@drawer/repository/[repositoryId]/page/server-reference-manifest.json +20 -20
- package/web/.next/server/app/(dashboard)/@drawer/repository/[repositoryId]/page.js.nft.json +1 -1
- package/web/.next/server/app/(dashboard)/@drawer/repository/[repositoryId]/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/(dashboard)/create/page/server-reference-manifest.json +22 -22
- package/web/.next/server/app/(dashboard)/create/page.js.nft.json +1 -1
- package/web/.next/server/app/(dashboard)/create/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/(dashboard)/feature/[featureId]/[tab]/page/server-reference-manifest.json +28 -28
- package/web/.next/server/app/(dashboard)/feature/[featureId]/[tab]/page.js.nft.json +1 -1
- package/web/.next/server/app/(dashboard)/feature/[featureId]/[tab]/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/(dashboard)/feature/[featureId]/page/server-reference-manifest.json +28 -28
- package/web/.next/server/app/(dashboard)/feature/[featureId]/page.js.nft.json +1 -1
- package/web/.next/server/app/(dashboard)/feature/[featureId]/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/(dashboard)/page/server-reference-manifest.json +20 -20
- package/web/.next/server/app/(dashboard)/page.js.nft.json +1 -1
- package/web/.next/server/app/(dashboard)/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/(dashboard)/repository/[repositoryId]/page/server-reference-manifest.json +20 -20
- package/web/.next/server/app/(dashboard)/repository/[repositoryId]/page.js.nft.json +1 -1
- package/web/.next/server/app/(dashboard)/repository/[repositoryId]/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/_global-error.html +2 -2
- package/web/.next/server/app/_global-error.rsc +1 -1
- package/web/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +1 -1
- package/web/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
- package/web/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
- package/web/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
- package/web/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
- package/web/.next/server/app/_not-found/page/server-reference-manifest.json +1 -1
- package/web/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/settings/page/server-reference-manifest.json +6 -6
- package/web/.next/server/app/settings/page.js.nft.json +1 -1
- package/web/.next/server/app/settings/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/skills/page/server-reference-manifest.json +6 -6
- package/web/.next/server/app/skills/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/tools/page/server-reference-manifest.json +6 -6
- package/web/.next/server/app/tools/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/version/page/server-reference-manifest.json +1 -1
- package/web/.next/server/app/version/page_client-reference-manifest.js +1 -1
- package/web/.next/server/chunks/[root-of-the-server]__a402b567._.js +1 -1
- package/web/.next/server/chunks/ssr/744ca_web_components_common_control-center-drawer_create-drawer-client_tsx_5e26fc0a._.js +1 -1
- package/web/.next/server/chunks/ssr/744ca_web_components_common_control-center-drawer_create-drawer-client_tsx_5e26fc0a._.js.map +1 -1
- package/web/.next/server/chunks/ssr/8ba4b_server_app_(dashboard)_@drawer_repository_[repositoryId]_page_actions_f30d0343.js +1 -1
- package/web/.next/server/chunks/ssr/8ba4b_server_app_(dashboard)_@drawer_repository_[repositoryId]_page_actions_f30d0343.js.map +1 -1
- package/web/.next/server/chunks/ssr/8ba4b_server_app_(dashboard)_repository_[repositoryId]_page_actions_9f1775bb.js +1 -1
- package/web/.next/server/chunks/ssr/8ba4b_server_app_(dashboard)_repository_[repositoryId]_page_actions_9f1775bb.js.map +1 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__06fef644._.js +1 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__14664e9b._.js +2 -2
- package/web/.next/server/chunks/ssr/[root-of-the-server]__545792ab._.js +1 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__545792ab._.js.map +1 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__6b17a22d._.js +1 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__6b17a22d._.js.map +1 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__6bb00d90._.js +2 -2
- package/web/.next/server/chunks/ssr/[root-of-the-server]__6bb00d90._.js.map +1 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__7cbda1ea._.js +1 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__7cbda1ea._.js.map +1 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__804c006d._.js +1 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__804c006d._.js.map +1 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__8c553503._.js +2 -2
- package/web/.next/server/chunks/ssr/[root-of-the-server]__9e8b25ad._.js +1 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__9e8b25ad._.js.map +1 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__a7de2711._.js +2 -2
- package/web/.next/server/chunks/ssr/[root-of-the-server]__aed1d6f8._.js +1 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__aed1d6f8._.js.map +1 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__ce6057f6._.js +1 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__ce6057f6._.js.map +1 -1
- package/web/.next/server/chunks/ssr/_135edb9c._.js +1 -1
- package/web/.next/server/chunks/ssr/_135edb9c._.js.map +1 -1
- package/web/.next/server/chunks/ssr/_2f6f48b8._.js +1 -1
- package/web/.next/server/chunks/ssr/_2f6f48b8._.js.map +1 -1
- package/web/.next/server/chunks/ssr/{_960ceb5d._.js → _6f706886._.js} +2 -2
- package/web/.next/server/chunks/ssr/{_960ceb5d._.js.map → _6f706886._.js.map} +1 -1
- package/web/.next/server/chunks/ssr/_b0053195._.js +3 -0
- package/web/.next/server/chunks/ssr/{_fd4c574b._.js.map → _b0053195._.js.map} +1 -1
- package/web/.next/server/chunks/ssr/_cc77a143._.js +1 -1
- package/web/.next/server/chunks/ssr/_cc77a143._.js.map +1 -1
- package/web/.next/server/chunks/ssr/_e9703421._.js +1 -1
- package/web/.next/server/chunks/ssr/_e9703421._.js.map +1 -1
- package/web/.next/server/chunks/ssr/b1a17_presentation_web_components_features_settings_settings-page-client_tsx_6ed9d5f8._.js +1 -1
- package/web/.next/server/chunks/ssr/b1a17_presentation_web_components_features_settings_settings-page-client_tsx_6ed9d5f8._.js.map +1 -1
- package/web/.next/server/chunks/ssr/src_presentation_web_04a55deb._.js +3 -0
- package/web/.next/server/chunks/ssr/{src_presentation_web_db779ef4._.js.map → src_presentation_web_04a55deb._.js.map} +1 -1
- package/web/.next/server/chunks/ssr/src_presentation_web_5f039db1._.js +2 -2
- package/web/.next/server/chunks/ssr/src_presentation_web_5f039db1._.js.map +1 -1
- package/web/.next/server/chunks/ssr/src_presentation_web__next-internal_server_app_(dashboard)_page_actions_2a52b697.js +1 -1
- package/web/.next/server/chunks/ssr/src_presentation_web__next-internal_server_app_(dashboard)_page_actions_2a52b697.js.map +1 -1
- package/web/.next/server/chunks/ssr/src_presentation_web__next-internal_server_app_skills_page_actions_1fa8042e.js +1 -1
- package/web/.next/server/chunks/ssr/src_presentation_web__next-internal_server_app_skills_page_actions_1fa8042e.js.map +1 -1
- package/web/.next/server/chunks/ssr/src_presentation_web__next-internal_server_app_tools_page_actions_24684200.js +1 -1
- package/web/.next/server/chunks/ssr/src_presentation_web__next-internal_server_app_tools_page_actions_24684200.js.map +1 -1
- package/web/.next/server/chunks/ssr/src_presentation_web_c4337169._.js +2 -2
- package/web/.next/server/chunks/ssr/src_presentation_web_c4337169._.js.map +1 -1
- package/web/.next/server/chunks/ssr/src_presentation_web_components_bf50c527._.js +1 -1
- package/web/.next/server/chunks/ssr/src_presentation_web_components_bf50c527._.js.map +1 -1
- package/web/.next/server/chunks/ssr/src_presentation_web_components_de814675._.js +1 -1
- package/web/.next/server/chunks/ssr/src_presentation_web_components_de814675._.js.map +1 -1
- package/web/.next/server/chunks/ssr/src_presentation_web_components_features_control-center_7ac3562e._.js +1 -1
- package/web/.next/server/chunks/ssr/src_presentation_web_components_features_control-center_7ac3562e._.js.map +1 -1
- package/web/.next/server/pages/500.html +2 -2
- package/web/.next/server/server-reference-manifest.js +1 -1
- package/web/.next/server/server-reference-manifest.json +34 -34
- package/web/.next/static/chunks/{373e10090c6410c4.js → 0e237ba1b2244a18.js} +1 -1
- package/web/.next/static/chunks/{3f6c44cbad751310.js → 133cd3e797f5e394.js} +1 -1
- package/web/.next/static/chunks/{f0dfeedb263eb906.js → 15903d6fbe2a6ca6.js} +1 -1
- package/web/.next/static/chunks/{64d063449c3be0ec.js → 4bdce057ac032126.js} +1 -1
- package/web/.next/static/chunks/{9821072252ddb89a.js → 501ce5d8bdf8f088.js} +1 -1
- package/web/.next/static/chunks/{310be54600c8ce20.js → 7aa01f1bf09ed016.js} +2 -2
- package/web/.next/static/chunks/91ecdc800a99fedf.js +1 -0
- package/web/.next/static/chunks/{94af5be1ccf8842e.js → eaefc7de14c204d3.js} +1 -1
- package/web/.next/static/chunks/{878643f90bc6360f.js → f746f850470ea93e.js} +2 -2
- package/web/.next/static/chunks/{694718e5449b3150.js → fc0969d0a83b0342.js} +1 -1
- package/web/.next/server/chunks/ssr/_fd4c574b._.js +0 -3
- package/web/.next/server/chunks/ssr/src_presentation_web_db779ef4._.js +0 -3
- package/web/.next/static/chunks/e418898e8e02f50a.js +0 -1
- /package/web/.next/static/{gBTe97SiNDA2hbG9dbfpb → hSz-kDGgMc7NVINRO5rze}/_buildManifest.js +0 -0
- /package/web/.next/static/{gBTe97SiNDA2hbG9dbfpb → hSz-kDGgMc7NVINRO5rze}/_clientMiddlewareManifest.json +0 -0
- /package/web/.next/static/{gBTe97SiNDA2hbG9dbfpb → hSz-kDGgMc7NVINRO5rze}/_ssgManifest.js +0 -0
|
@@ -45,7 +45,7 @@ export class AgentExecutorFactory {
|
|
|
45
45
|
executor = new ClaudeCodeExecutorService(this.spawn);
|
|
46
46
|
break;
|
|
47
47
|
case 'cursor':
|
|
48
|
-
executor = new CursorExecutorService(this.spawn);
|
|
48
|
+
executor = new CursorExecutorService(this.spawn, _authConfig);
|
|
49
49
|
break;
|
|
50
50
|
case 'dev':
|
|
51
51
|
executor = new DevAgentExecutorService();
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
* Uses constructor dependency injection for the spawn function
|
|
9
9
|
* to enable testability without mocking node:child_process directly.
|
|
10
10
|
*/
|
|
11
|
-
import type { AgentType, AgentFeature } from '../../../../../domain/generated/output.js';
|
|
11
|
+
import type { AgentType, AgentFeature, AgentConfig } from '../../../../../domain/generated/output.js';
|
|
12
12
|
import type { IAgentExecutor, AgentExecutionOptions, AgentExecutionResult, AgentExecutionStreamEvent } from '../../../../../application/ports/output/agents/agent-executor.interface.js';
|
|
13
13
|
import type { SpawnFunction } from '../types.js';
|
|
14
14
|
/**
|
|
@@ -17,10 +17,11 @@ import type { SpawnFunction } from '../types.js';
|
|
|
17
17
|
*/
|
|
18
18
|
export declare class CursorExecutorService implements IAgentExecutor {
|
|
19
19
|
private readonly spawn;
|
|
20
|
+
private readonly authConfig?;
|
|
20
21
|
readonly agentType: AgentType;
|
|
21
22
|
/** When true, suppresses debug logging (set per-call via options.silent) */
|
|
22
23
|
private silent;
|
|
23
|
-
constructor(spawn: SpawnFunction);
|
|
24
|
+
constructor(spawn: SpawnFunction, authConfig?: AgentConfig | undefined);
|
|
24
25
|
/** Debug logging — writes to stdout so it appears in the worker log file */
|
|
25
26
|
private log;
|
|
26
27
|
supportsFeature(feature: AgentFeature): boolean;
|
|
@@ -33,16 +34,35 @@ export declare class CursorExecutorService implements IAgentExecutor {
|
|
|
33
34
|
private buildArgs;
|
|
34
35
|
private buildStreamArgs;
|
|
35
36
|
/**
|
|
36
|
-
*
|
|
37
|
+
* Resolve the cursor CLI's bundled node.exe and index.js paths on Windows.
|
|
37
38
|
*
|
|
38
|
-
*
|
|
39
|
-
*
|
|
40
|
-
*
|
|
41
|
-
*
|
|
42
|
-
*
|
|
39
|
+
* The cursor CLI installs to `%LOCALAPPDATA%\cursor-agent\` with:
|
|
40
|
+
* - `agent.cmd` / `cursor-agent.ps1` (shell wrappers)
|
|
41
|
+
* - `versions/<YYYY.MM.DD-commit>/node.exe` + `index.js`
|
|
42
|
+
*
|
|
43
|
+
* Spawning via agent.cmd creates a problematic nesting chain:
|
|
44
|
+
* PowerShell → agent.cmd → PowerShell → cursor-agent.ps1 → node.exe
|
|
45
|
+
* This chain hangs on Windows CI runners. Direct invocation bypasses it.
|
|
46
|
+
*
|
|
47
|
+
* @returns `{ nodePath, indexPath }` or `undefined` if not found
|
|
48
|
+
*/
|
|
49
|
+
private resolveCursorBinary;
|
|
50
|
+
/**
|
|
51
|
+
* Spawn the agent process, handling Windows specially.
|
|
52
|
+
*
|
|
53
|
+
* On Windows, the cursor CLI ships as `agent.cmd` which spawns PowerShell
|
|
54
|
+
* which runs `cursor-agent.ps1` which runs `node.exe index.js`. This triple
|
|
55
|
+
* nesting (PowerShell → cmd.exe → PowerShell → node.exe) hangs on Windows
|
|
56
|
+
* CI runners. Solution: resolve the cursor CLI's bundled `node.exe` and
|
|
57
|
+
* `index.js` directly, bypassing all shell wrappers.
|
|
43
58
|
*
|
|
44
59
|
* On Linux/macOS, spawn `agent` directly — no shell needed.
|
|
45
60
|
*/
|
|
61
|
+
/**
|
|
62
|
+
* Build the subprocess environment: strip CLAUDECODE, inject CURSOR_API_KEY
|
|
63
|
+
* from authConfig when token auth is configured.
|
|
64
|
+
*/
|
|
65
|
+
private buildEnv;
|
|
46
66
|
private spawnAgent;
|
|
47
67
|
private parseStreamLine;
|
|
48
68
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cursor-executor.service.d.ts","sourceRoot":"","sources":["../../../../../../../../../packages/core/src/infrastructure/services/agents/common/executors/cursor-executor.service.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;
|
|
1
|
+
{"version":3,"file":"cursor-executor.service.d.ts","sourceRoot":"","sources":["../../../../../../../../../packages/core/src/infrastructure/services/agents/common/executors/cursor-executor.service.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAKH,OAAO,KAAK,EACV,SAAS,EACT,YAAY,EACZ,WAAW,EACZ,MAAM,2CAA2C,CAAC;AACnD,OAAO,KAAK,EACV,cAAc,EACd,qBAAqB,EACrB,oBAAoB,EACpB,yBAAyB,EAC1B,MAAM,4EAA4E,CAAC;AACpF,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAuBjD;;;GAGG;AACH,qBAAa,qBAAsB,YAAW,cAAc;IAOxD,OAAO,CAAC,QAAQ,CAAC,KAAK;IACtB,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAC;IAP9B,QAAQ,CAAC,SAAS,EAAE,SAAS,CAAyB;IAEtD,4EAA4E;IAC5E,OAAO,CAAC,MAAM,CAAS;gBAGJ,KAAK,EAAE,aAAa,EACpB,UAAU,CAAC,EAAE,WAAW,YAAA;IAG3C,4EAA4E;IAC5E,OAAO,CAAC,GAAG;IAMX,eAAe,CAAC,OAAO,EAAE,YAAY,GAAG,OAAO;IAIzC,OAAO,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,qBAAqB,GAAG,OAAO,CAAC,oBAAoB,CAAC;IAiPtF,aAAa,CAClB,MAAM,EAAE,MAAM,EACd,OAAO,CAAC,EAAE,qBAAqB,GAC9B,aAAa,CAAC,yBAAyB,CAAC;IAiH3C;;OAEG;IACH,OAAO,CAAC,cAAc;IAyCtB,OAAO,CAAC,SAAS;IASjB,OAAO,CAAC,eAAe;IAOvB;;;;;;;;;;;;OAYG;IACH,OAAO,CAAC,mBAAmB;IAwC3B;;;;;;;;;;OAUG;IACH;;;OAGG;IACH,OAAO,CAAC,QAAQ;IAuBhB,OAAO,CAAC,UAAU;IA6FlB,OAAO,CAAC,eAAe;CAgDxB"}
|
|
@@ -8,9 +8,8 @@
|
|
|
8
8
|
* Uses constructor dependency injection for the spawn function
|
|
9
9
|
* to enable testability without mocking node:child_process directly.
|
|
10
10
|
*/
|
|
11
|
-
import {
|
|
11
|
+
import { unlinkSync, readdirSync, existsSync } from 'node:fs';
|
|
12
12
|
import { execFileSync } from 'node:child_process';
|
|
13
|
-
import { tmpdir } from 'node:os';
|
|
14
13
|
import { join } from 'node:path';
|
|
15
14
|
import { getCurrentPhase, getLogPrefix } from '../../feature-agent/log-context.js';
|
|
16
15
|
import { IS_WINDOWS } from '../../../../platform.js';
|
|
@@ -36,11 +35,13 @@ const SUPPORTED_FEATURES = new Set(['session-resume', 'streaming']);
|
|
|
36
35
|
*/
|
|
37
36
|
export class CursorExecutorService {
|
|
38
37
|
spawn;
|
|
38
|
+
authConfig;
|
|
39
39
|
agentType = 'cursor';
|
|
40
40
|
/** When true, suppresses debug logging (set per-call via options.silent) */
|
|
41
41
|
silent = false;
|
|
42
|
-
constructor(spawn) {
|
|
42
|
+
constructor(spawn, authConfig) {
|
|
43
43
|
this.spawn = spawn;
|
|
44
|
+
this.authConfig = authConfig;
|
|
44
45
|
}
|
|
45
46
|
/** Debug logging — writes to stdout so it appears in the worker log file */
|
|
46
47
|
log(message) {
|
|
@@ -58,19 +59,67 @@ export class CursorExecutorService {
|
|
|
58
59
|
// stream-json is unreliable on Windows where shell: true can mangle args.
|
|
59
60
|
const args = this.buildArgs(prompt, options);
|
|
60
61
|
const { proc, tmpFile } = this.spawnAgent(prompt, args, options);
|
|
62
|
+
// Diagnostic: verify streams are connected and process is alive
|
|
63
|
+
this.log(`[diag] proc.pid=${proc.pid}, killed=${proc.killed}`);
|
|
64
|
+
this.log(`[diag] stdout=${!!proc.stdout}, stderr=${!!proc.stderr}, stdin=${!!proc.stdin}`);
|
|
65
|
+
this.log(`[diag] CURSOR_API_KEY set=${!!process.env.CURSOR_API_KEY}, len=${process.env.CURSOR_API_KEY?.length ?? 0}`);
|
|
66
|
+
this.log(`[diag] authConfig.token set=${!!this.authConfig?.token}, method=${this.authConfig?.authMethod ?? 'none'}`);
|
|
67
|
+
this.log(`[diag] platform=${process.platform}, cwd=${options?.cwd ?? '(inherited)'}`);
|
|
61
68
|
return new Promise((resolve, reject) => {
|
|
62
69
|
let lineBuffer = '';
|
|
63
70
|
let stderr = '';
|
|
64
71
|
let timedOut = false;
|
|
65
72
|
let timeoutId;
|
|
73
|
+
let stdoutChunks = 0;
|
|
74
|
+
let stderrChunks = 0;
|
|
75
|
+
const startTime = Date.now();
|
|
66
76
|
// Accumulated from JSON events or raw text fallback
|
|
67
77
|
let resultText = '';
|
|
68
78
|
let rawText = '';
|
|
69
79
|
let sessionId;
|
|
70
80
|
let metadata;
|
|
81
|
+
// Periodic heartbeat + zero-output watchdog.
|
|
82
|
+
// Cursor CLI on Windows sometimes starts but never produces any output.
|
|
83
|
+
// If no stdout/stderr arrives within SILENCE_TIMEOUT_MS, kill the process
|
|
84
|
+
// so retryExecute can retry instead of waiting 30 minutes.
|
|
85
|
+
const SILENCE_TIMEOUT_MS = 180_000; // 3 minutes of zero output = stuck
|
|
86
|
+
let lastOutputAt = Date.now();
|
|
87
|
+
const heartbeatId = setInterval(() => {
|
|
88
|
+
const elapsed = Math.round((Date.now() - startTime) / 1000);
|
|
89
|
+
const silenceMs = Date.now() - lastOutputAt;
|
|
90
|
+
// Check if child process is actually alive (proc.killed only reflects OUR kills)
|
|
91
|
+
let processAlive = false;
|
|
92
|
+
if (proc.pid) {
|
|
93
|
+
try {
|
|
94
|
+
process.kill(proc.pid, 0); // signal 0 = check existence
|
|
95
|
+
processAlive = true;
|
|
96
|
+
}
|
|
97
|
+
catch {
|
|
98
|
+
processAlive = false;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
this.log(`[diag] heartbeat ${elapsed}s: stdout=${stdoutChunks}, stderr=${stderrChunks}, silence=${Math.round(silenceMs / 1000)}s, alive=${processAlive}, pid=${proc.pid}`);
|
|
102
|
+
// Kill if zero output for too long
|
|
103
|
+
if (silenceMs > SILENCE_TIMEOUT_MS && !proc.killed) {
|
|
104
|
+
this.log(`[diag] SILENCE WATCHDOG: no output for ${Math.round(silenceMs / 1000)}s — killing process`);
|
|
105
|
+
timedOut = true;
|
|
106
|
+
if (process.platform === 'win32' && proc.pid) {
|
|
107
|
+
try {
|
|
108
|
+
execFileSync('taskkill', ['/F', '/T', '/PID', String(proc.pid)], { stdio: 'ignore' });
|
|
109
|
+
}
|
|
110
|
+
catch {
|
|
111
|
+
proc.kill();
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
else {
|
|
115
|
+
proc.kill();
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
}, 15_000);
|
|
71
119
|
if (options?.timeout) {
|
|
72
120
|
timeoutId = setTimeout(() => {
|
|
73
121
|
timedOut = true;
|
|
122
|
+
this.log(`[diag] TIMEOUT after ${options.timeout}ms — killing process tree`);
|
|
74
123
|
// On Windows, proc.kill() may not kill the entire process tree
|
|
75
124
|
// (PowerShell + child agent process). Use taskkill /T for tree kill.
|
|
76
125
|
if (process.platform === 'win32' && proc.pid) {
|
|
@@ -78,9 +127,11 @@ export class CursorExecutorService {
|
|
|
78
127
|
execFileSync('taskkill', ['/F', '/T', '/PID', String(proc.pid)], {
|
|
79
128
|
stdio: 'ignore',
|
|
80
129
|
});
|
|
130
|
+
this.log(`[diag] taskkill /T /PID ${proc.pid} succeeded`);
|
|
81
131
|
}
|
|
82
132
|
catch {
|
|
83
133
|
proc.kill();
|
|
134
|
+
this.log(`[diag] taskkill failed, fell back to proc.kill()`);
|
|
84
135
|
}
|
|
85
136
|
}
|
|
86
137
|
else {
|
|
@@ -107,17 +158,36 @@ export class CursorExecutorService {
|
|
|
107
158
|
if (parsed.duration_ms !== undefined) {
|
|
108
159
|
metadata = { ...metadata, duration_ms: parsed.duration_ms };
|
|
109
160
|
}
|
|
161
|
+
if (parsed.is_error) {
|
|
162
|
+
this.log(`[diag] result event has is_error=true: ${JSON.stringify(parsed).slice(0, 300)}`);
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
else if (parsed.type === 'error') {
|
|
166
|
+
this.log(`[diag] cursor error event: ${JSON.stringify(parsed).slice(0, 500)}`);
|
|
167
|
+
}
|
|
168
|
+
else if (parsed.type !== 'user' &&
|
|
169
|
+
parsed.type !== 'system' &&
|
|
170
|
+
parsed.type !== 'thinking' &&
|
|
171
|
+
parsed.type !== 'tool_call') {
|
|
172
|
+
this.log(`[diag] unknown event type="${parsed.type}": ${JSON.stringify(parsed).slice(0, 300)}`);
|
|
110
173
|
}
|
|
111
|
-
// user, system, thinking events: logged but don't affect result
|
|
112
174
|
}
|
|
113
175
|
catch {
|
|
114
176
|
// Non-JSON output — accumulate as raw text fallback
|
|
115
|
-
if (line.length > 0)
|
|
177
|
+
if (line.length > 0) {
|
|
116
178
|
rawText += `${line}\n`;
|
|
179
|
+
this.log(`[diag] non-JSON line (${line.length} chars): ${line.slice(0, 200)}`);
|
|
180
|
+
}
|
|
117
181
|
}
|
|
118
182
|
};
|
|
119
183
|
proc.stdout?.on('data', (chunk) => {
|
|
120
|
-
|
|
184
|
+
stdoutChunks++;
|
|
185
|
+
lastOutputAt = Date.now();
|
|
186
|
+
const data = chunk.toString();
|
|
187
|
+
if (stdoutChunks <= 3) {
|
|
188
|
+
this.log(`[diag] stdout chunk #${stdoutChunks}: ${data.length} bytes, first 200: ${data.slice(0, 200).replace(/\n/g, '\\n')}`);
|
|
189
|
+
}
|
|
190
|
+
lineBuffer += data;
|
|
121
191
|
const lines = lineBuffer.split('\n');
|
|
122
192
|
lineBuffer = lines.pop() ?? '';
|
|
123
193
|
for (const line of lines) {
|
|
@@ -127,19 +197,23 @@ export class CursorExecutorService {
|
|
|
127
197
|
}
|
|
128
198
|
});
|
|
129
199
|
proc.stderr?.on('data', (chunk) => {
|
|
200
|
+
stderrChunks++;
|
|
201
|
+
lastOutputAt = Date.now();
|
|
130
202
|
const data = chunk.toString();
|
|
131
203
|
stderr += data;
|
|
132
|
-
this.log(`stderr: ${data.trimEnd()}`);
|
|
204
|
+
this.log(`[diag] stderr chunk #${stderrChunks}: ${data.trimEnd()}`);
|
|
133
205
|
// Detect fatal errors early so callers don't waste time retrying
|
|
134
206
|
if (data.includes('Cannot use this model')) {
|
|
135
207
|
if (timeoutId)
|
|
136
208
|
clearTimeout(timeoutId);
|
|
209
|
+
clearInterval(heartbeatId);
|
|
137
210
|
proc.kill();
|
|
138
211
|
reject(new Error(data.trim()));
|
|
139
212
|
}
|
|
140
213
|
});
|
|
141
214
|
proc.on('error', (error) => {
|
|
142
|
-
this.log(`Process
|
|
215
|
+
this.log(`[diag] Process ERROR event: ${error.message} (code=${error.code})`);
|
|
216
|
+
clearInterval(heartbeatId);
|
|
143
217
|
if (timeoutId)
|
|
144
218
|
clearTimeout(timeoutId);
|
|
145
219
|
if (error.code === 'ENOENT') {
|
|
@@ -150,6 +224,8 @@ export class CursorExecutorService {
|
|
|
150
224
|
}
|
|
151
225
|
});
|
|
152
226
|
proc.on('close', (code) => {
|
|
227
|
+
const elapsed = Math.round((Date.now() - startTime) / 1000);
|
|
228
|
+
clearInterval(heartbeatId);
|
|
153
229
|
// Clean up temp file on Windows
|
|
154
230
|
if (tmpFile) {
|
|
155
231
|
try {
|
|
@@ -163,7 +239,7 @@ export class CursorExecutorService {
|
|
|
163
239
|
processLine(lineBuffer.trim());
|
|
164
240
|
// Use raw text as fallback when no JSON result was captured
|
|
165
241
|
const finalText = resultText || rawText.trim();
|
|
166
|
-
this.log(`Process
|
|
242
|
+
this.log(`[diag] Process CLOSE: code=${code}, elapsed=${elapsed}s, stdout_chunks=${stdoutChunks}, stderr_chunks=${stderrChunks}, result=${finalText.length} chars, raw=${rawText.length} chars`);
|
|
167
243
|
if (timeoutId)
|
|
168
244
|
clearTimeout(timeoutId);
|
|
169
245
|
if (timedOut) {
|
|
@@ -171,9 +247,17 @@ export class CursorExecutorService {
|
|
|
171
247
|
return;
|
|
172
248
|
}
|
|
173
249
|
if (code !== 0 && code !== null) {
|
|
174
|
-
|
|
250
|
+
const errMsg = stderr.trim() || `Process exited with code ${code}`;
|
|
251
|
+
this.log(`[diag] non-zero exit — rejecting with: ${errMsg.slice(0, 200)}`);
|
|
252
|
+
reject(new Error(errMsg));
|
|
175
253
|
return;
|
|
176
254
|
}
|
|
255
|
+
if (stdoutChunks === 0 && stderrChunks === 0) {
|
|
256
|
+
this.log(`[diag] WARNING: process exited with code 0 but produced ZERO output (stdout=0, stderr=0, elapsed=${elapsed}s)`);
|
|
257
|
+
}
|
|
258
|
+
if (!finalText && code === 0) {
|
|
259
|
+
this.log(`[diag] WARNING: process exited code=0 but result is empty (resultText=${resultText.length}, rawText=${rawText.length})`);
|
|
260
|
+
}
|
|
177
261
|
const result = { result: finalText };
|
|
178
262
|
if (sessionId)
|
|
179
263
|
result.sessionId = sessionId;
|
|
@@ -184,20 +268,25 @@ export class CursorExecutorService {
|
|
|
184
268
|
});
|
|
185
269
|
}
|
|
186
270
|
async *executeStream(prompt, options) {
|
|
271
|
+
this.silent = options?.silent ?? false;
|
|
187
272
|
const args = this.buildStreamArgs(prompt, options);
|
|
188
273
|
const { proc, tmpFile } = this.spawnAgent(prompt, args, options);
|
|
274
|
+
this.log(`[stream] pid=${proc.pid}, stdout=${!!proc.stdout}, stderr=${!!proc.stderr}`);
|
|
189
275
|
let lineBuffer = '';
|
|
190
276
|
let stderr = '';
|
|
277
|
+
let stdoutChunks = 0;
|
|
278
|
+
let stderrChunks = 0;
|
|
279
|
+
const startTime = Date.now();
|
|
191
280
|
const queue = [];
|
|
192
281
|
let resolve = null;
|
|
193
282
|
let error = null;
|
|
194
|
-
|
|
283
|
+
const enqueue = (event) => {
|
|
195
284
|
queue.push(event);
|
|
196
285
|
if (resolve) {
|
|
197
286
|
resolve();
|
|
198
287
|
resolve = null;
|
|
199
288
|
}
|
|
200
|
-
}
|
|
289
|
+
};
|
|
201
290
|
function waitForItem() {
|
|
202
291
|
if (queue.length > 0)
|
|
203
292
|
return Promise.resolve();
|
|
@@ -205,8 +294,18 @@ export class CursorExecutorService {
|
|
|
205
294
|
resolve = r;
|
|
206
295
|
});
|
|
207
296
|
}
|
|
297
|
+
// Heartbeat for stream mode too
|
|
298
|
+
const heartbeatId = setInterval(() => {
|
|
299
|
+
const elapsed = Math.round((Date.now() - startTime) / 1000);
|
|
300
|
+
this.log(`[stream] heartbeat ${elapsed}s: stdout_chunks=${stdoutChunks}, stderr_chunks=${stderrChunks}, pid_killed=${proc.killed}`);
|
|
301
|
+
}, 30_000);
|
|
208
302
|
proc.stdout?.on('data', (chunk) => {
|
|
209
|
-
|
|
303
|
+
stdoutChunks++;
|
|
304
|
+
const data = chunk.toString();
|
|
305
|
+
if (stdoutChunks <= 3) {
|
|
306
|
+
this.log(`[stream] stdout chunk #${stdoutChunks}: ${data.length} bytes`);
|
|
307
|
+
}
|
|
308
|
+
lineBuffer += data;
|
|
210
309
|
const lines = lineBuffer.split('\n');
|
|
211
310
|
lineBuffer = lines.pop() ?? '';
|
|
212
311
|
for (const line of lines) {
|
|
@@ -219,13 +318,21 @@ export class CursorExecutorService {
|
|
|
219
318
|
}
|
|
220
319
|
});
|
|
221
320
|
proc.stderr?.on('data', (chunk) => {
|
|
222
|
-
|
|
321
|
+
stderrChunks++;
|
|
322
|
+
const data = chunk.toString();
|
|
323
|
+
stderr += data;
|
|
324
|
+
this.log(`[stream] stderr chunk #${stderrChunks}: ${data.trimEnd()}`);
|
|
223
325
|
});
|
|
224
326
|
proc.on('error', (err) => {
|
|
327
|
+
this.log(`[stream] Process ERROR: ${err.message}`);
|
|
328
|
+
clearInterval(heartbeatId);
|
|
225
329
|
error = err;
|
|
226
330
|
enqueue(null);
|
|
227
331
|
});
|
|
228
332
|
proc.on('close', (code) => {
|
|
333
|
+
const elapsed = Math.round((Date.now() - startTime) / 1000);
|
|
334
|
+
clearInterval(heartbeatId);
|
|
335
|
+
this.log(`[stream] Process CLOSE: code=${code}, elapsed=${elapsed}s, stdout_chunks=${stdoutChunks}, stderr_chunks=${stderrChunks}`);
|
|
229
336
|
if (tmpFile) {
|
|
230
337
|
try {
|
|
231
338
|
unlinkSync(tmpFile);
|
|
@@ -239,8 +346,10 @@ export class CursorExecutorService {
|
|
|
239
346
|
if (event)
|
|
240
347
|
enqueue(event);
|
|
241
348
|
}
|
|
242
|
-
if (code !== 0 && code !== null
|
|
243
|
-
|
|
349
|
+
if (code !== 0 && code !== null) {
|
|
350
|
+
const errMsg = stderr.trim() || `Process exited with code ${code}`;
|
|
351
|
+
this.log(`[stream] non-zero exit: ${errMsg}`);
|
|
352
|
+
enqueue({ type: 'error', content: errMsg, timestamp: new Date() });
|
|
244
353
|
}
|
|
245
354
|
enqueue(null);
|
|
246
355
|
});
|
|
@@ -286,20 +395,24 @@ export class CursorExecutorService {
|
|
|
286
395
|
}
|
|
287
396
|
if (parsed.type === 'user')
|
|
288
397
|
return; // Skip echoed input
|
|
398
|
+
// Log any unrecognized event type so nothing is silently dropped
|
|
399
|
+
if (!['assistant', 'tool_call', 'result', 'user', 'system', 'thinking'].includes(parsed.type)) {
|
|
400
|
+
this.log(`[diag] unhandled stream event type="${parsed.type}": ${line.slice(0, 200)}`);
|
|
401
|
+
}
|
|
289
402
|
}
|
|
290
403
|
catch {
|
|
291
404
|
if (line.length > 0)
|
|
292
405
|
this.log(`[raw] ${line}`);
|
|
293
406
|
}
|
|
294
407
|
}
|
|
295
|
-
buildArgs(
|
|
296
|
-
|
|
408
|
+
buildArgs(_prompt, options) {
|
|
409
|
+
// Prompt is piped via stdin (not passed as arg) to avoid Windows command line
|
|
410
|
+
// length limits and argument escaping issues on Windows Server CI.
|
|
411
|
+
const args = ['--yolo', '-p', '--output-format', 'json'];
|
|
297
412
|
if (options?.resumeSession)
|
|
298
413
|
args.push('--resume', options.resumeSession);
|
|
299
414
|
if (options?.model)
|
|
300
415
|
args.push('--model', toCursorModelName(options.model));
|
|
301
|
-
// Unsupported options silently omitted: systemPrompt, allowedTools, maxTurns, outputSchema
|
|
302
|
-
// No auth flags — binary handles its own auth
|
|
303
416
|
return args;
|
|
304
417
|
}
|
|
305
418
|
buildStreamArgs(prompt, options) {
|
|
@@ -310,44 +423,135 @@ export class CursorExecutorService {
|
|
|
310
423
|
return args;
|
|
311
424
|
}
|
|
312
425
|
/**
|
|
313
|
-
*
|
|
426
|
+
* Resolve the cursor CLI's bundled node.exe and index.js paths on Windows.
|
|
427
|
+
*
|
|
428
|
+
* The cursor CLI installs to `%LOCALAPPDATA%\cursor-agent\` with:
|
|
429
|
+
* - `agent.cmd` / `cursor-agent.ps1` (shell wrappers)
|
|
430
|
+
* - `versions/<YYYY.MM.DD-commit>/node.exe` + `index.js`
|
|
431
|
+
*
|
|
432
|
+
* Spawning via agent.cmd creates a problematic nesting chain:
|
|
433
|
+
* PowerShell → agent.cmd → PowerShell → cursor-agent.ps1 → node.exe
|
|
434
|
+
* This chain hangs on Windows CI runners. Direct invocation bypasses it.
|
|
435
|
+
*
|
|
436
|
+
* @returns `{ nodePath, indexPath }` or `undefined` if not found
|
|
437
|
+
*/
|
|
438
|
+
resolveCursorBinary() {
|
|
439
|
+
const localAppData = process.env.LOCALAPPDATA;
|
|
440
|
+
if (!localAppData) {
|
|
441
|
+
this.log('[diag] resolveCursorBinary: LOCALAPPDATA not set');
|
|
442
|
+
return undefined;
|
|
443
|
+
}
|
|
444
|
+
const versionsDir = join(localAppData, 'cursor-agent', 'versions');
|
|
445
|
+
if (!existsSync(versionsDir)) {
|
|
446
|
+
this.log(`[diag] resolveCursorBinary: versions dir not found: ${versionsDir}`);
|
|
447
|
+
return undefined;
|
|
448
|
+
}
|
|
449
|
+
// Find the latest version directory (format: YYYY.MM.DD-commit)
|
|
450
|
+
const versionPattern = /^\d{4}\.\d{1,2}\.\d{1,2}-[a-f0-9]+$/;
|
|
451
|
+
const versions = readdirSync(versionsDir)
|
|
452
|
+
.filter((d) => versionPattern.test(d))
|
|
453
|
+
.sort()
|
|
454
|
+
.reverse();
|
|
455
|
+
if (versions.length === 0) {
|
|
456
|
+
this.log(`[diag] resolveCursorBinary: no version dirs in ${versionsDir}`);
|
|
457
|
+
return undefined;
|
|
458
|
+
}
|
|
459
|
+
const versionDir = join(versionsDir, versions[0]);
|
|
460
|
+
const nodePath = join(versionDir, 'node.exe');
|
|
461
|
+
const indexPath = join(versionDir, 'index.js');
|
|
462
|
+
if (!existsSync(nodePath) || !existsSync(indexPath)) {
|
|
463
|
+
this.log(`[diag] resolveCursorBinary: missing binary — node=${existsSync(nodePath)}, index=${existsSync(indexPath)}`);
|
|
464
|
+
return undefined;
|
|
465
|
+
}
|
|
466
|
+
this.log(`[diag] resolveCursorBinary: resolved version=${versions[0]}`);
|
|
467
|
+
return { nodePath, indexPath };
|
|
468
|
+
}
|
|
469
|
+
/**
|
|
470
|
+
* Spawn the agent process, handling Windows specially.
|
|
314
471
|
*
|
|
315
|
-
* On Windows, cursor CLI ships as `agent.cmd` which
|
|
316
|
-
*
|
|
317
|
-
*
|
|
318
|
-
*
|
|
319
|
-
*
|
|
472
|
+
* On Windows, the cursor CLI ships as `agent.cmd` which spawns PowerShell
|
|
473
|
+
* which runs `cursor-agent.ps1` which runs `node.exe index.js`. This triple
|
|
474
|
+
* nesting (PowerShell → cmd.exe → PowerShell → node.exe) hangs on Windows
|
|
475
|
+
* CI runners. Solution: resolve the cursor CLI's bundled `node.exe` and
|
|
476
|
+
* `index.js` directly, bypassing all shell wrappers.
|
|
320
477
|
*
|
|
321
478
|
* On Linux/macOS, spawn `agent` directly — no shell needed.
|
|
322
479
|
*/
|
|
323
|
-
|
|
480
|
+
/**
|
|
481
|
+
* Build the subprocess environment: strip CLAUDECODE, inject CURSOR_API_KEY
|
|
482
|
+
* from authConfig when token auth is configured.
|
|
483
|
+
*/
|
|
484
|
+
buildEnv(extra) {
|
|
324
485
|
const { CLAUDECODE: _, ...cleanEnv } = process.env;
|
|
486
|
+
// Inject CURSOR_API_KEY from stored settings so the cursor CLI authenticates
|
|
487
|
+
// even when the env var isn't inherited (e.g. direct node.exe invocation on Windows).
|
|
488
|
+
if (this.authConfig?.authMethod === 'token' && this.authConfig.token) {
|
|
489
|
+
cleanEnv.CURSOR_API_KEY = this.authConfig.token;
|
|
490
|
+
this.log(`[diag] buildEnv: injected CURSOR_API_KEY from authConfig (${this.authConfig.token.length} chars)`);
|
|
491
|
+
}
|
|
492
|
+
else {
|
|
493
|
+
this.log(`[diag] buildEnv: NO token injection (authMethod=${this.authConfig?.authMethod ?? 'none'}, hasToken=${!!this.authConfig?.token}, envKey=${!!cleanEnv.CURSOR_API_KEY})`);
|
|
494
|
+
}
|
|
495
|
+
const env = extra ? { ...cleanEnv, ...extra } : cleanEnv;
|
|
496
|
+
this.log(`[diag] buildEnv: final CURSOR_API_KEY in env=${!!env.CURSOR_API_KEY}, len=${env.CURSOR_API_KEY?.length ?? 0}`);
|
|
497
|
+
return env;
|
|
498
|
+
}
|
|
499
|
+
spawnAgent(prompt, args, options) {
|
|
325
500
|
const cwd = options?.cwd;
|
|
326
501
|
if (IS_WINDOWS) {
|
|
327
|
-
//
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
502
|
+
// Direct invocation: resolve cursor's bundled node.exe + index.js and
|
|
503
|
+
// spawn directly. This bypasses agent.cmd/PowerShell which can trigger
|
|
504
|
+
// GUI "Open with" dialogs on Windows when `agent` isn't on PATH.
|
|
505
|
+
const resolved = this.resolveCursorBinary();
|
|
506
|
+
if (resolved) {
|
|
507
|
+
const directArgs = [resolved.indexPath, ...args];
|
|
508
|
+
this.log(`Windows direct mode: ${resolved.nodePath}`);
|
|
509
|
+
this.log(`[diag] node.exe exists: ${existsSync(resolved.nodePath)}, index.js exists: ${existsSync(resolved.indexPath)}`);
|
|
510
|
+
this.log(`[diag] cwd: ${cwd ?? '(inherited)'}, cwd exists: ${cwd ? existsSync(cwd) : 'n/a'}`);
|
|
511
|
+
this.log(`Args: ${directArgs.map((a) => (a.length > 80 ? `${a.slice(0, 77)}...` : a)).join(' ')}`);
|
|
512
|
+
const spawnEnv = this.buildEnv({ CURSOR_INVOKED_AS: 'agent' });
|
|
513
|
+
const proc = this.spawn(resolved.nodePath, directArgs, {
|
|
514
|
+
cwd,
|
|
515
|
+
stdio: ['pipe', 'pipe', 'pipe'],
|
|
516
|
+
windowsHide: true,
|
|
517
|
+
env: spawnEnv,
|
|
518
|
+
});
|
|
519
|
+
this.log(`Direct PID: ${proc.pid ?? 'undefined (spawn may have failed)'}`);
|
|
520
|
+
if (!proc.pid) {
|
|
521
|
+
this.log(`[diag] WARNING: spawn returned no PID — process may not have started`);
|
|
522
|
+
}
|
|
523
|
+
// Pipe prompt via stdin (like claude-code executor) to avoid Windows
|
|
524
|
+
// command line length limits that cause zero-output hangs on Windows Server.
|
|
525
|
+
this.log(`[diag] Piping ${prompt.length} chars via stdin`);
|
|
526
|
+
if (proc.stdin) {
|
|
527
|
+
proc.stdin.write(prompt);
|
|
528
|
+
proc.stdin.end();
|
|
529
|
+
}
|
|
530
|
+
return { proc, tmpFile: undefined };
|
|
531
|
+
}
|
|
532
|
+
// Fallback: spawn agent.cmd directly with shell: true
|
|
533
|
+
// (only used when cursor binary resolution fails)
|
|
534
|
+
const agentCmd = join(process.env.LOCALAPPDATA ?? '', 'cursor-agent', 'agent.cmd');
|
|
535
|
+
this.log(`[diag] Windows fallback: using agent.cmd at ${agentCmd}`);
|
|
536
|
+
const proc = this.spawn(agentCmd, args, {
|
|
337
537
|
cwd,
|
|
338
538
|
stdio: ['pipe', 'pipe', 'pipe'],
|
|
339
539
|
windowsHide: true,
|
|
340
|
-
|
|
540
|
+
shell: true,
|
|
541
|
+
env: this.buildEnv(),
|
|
341
542
|
});
|
|
342
|
-
this.log(`
|
|
343
|
-
|
|
543
|
+
this.log(`[diag] Fallback PID: ${proc.pid ?? 'undefined (spawn may have failed)'}`);
|
|
544
|
+
this.log(`[diag] Piping ${prompt.length} chars via stdin`);
|
|
545
|
+
if (proc.stdin) {
|
|
546
|
+
proc.stdin.write(prompt);
|
|
344
547
|
proc.stdin.end();
|
|
345
|
-
|
|
548
|
+
}
|
|
549
|
+
return { proc, tmpFile: undefined };
|
|
346
550
|
}
|
|
347
551
|
// Linux/macOS: spawn agent directly, no shell needed
|
|
348
552
|
const spawnOpts = {
|
|
349
553
|
stdio: ['pipe', 'pipe', 'pipe'],
|
|
350
|
-
env:
|
|
554
|
+
env: this.buildEnv(),
|
|
351
555
|
};
|
|
352
556
|
if (cwd)
|
|
353
557
|
spawnOpts.cwd = cwd;
|
|
@@ -355,8 +559,11 @@ export class CursorExecutorService {
|
|
|
355
559
|
this.log(`Spawn cwd: ${cwd ?? '(inherited)'}`);
|
|
356
560
|
const proc = this.spawn('agent', args, spawnOpts);
|
|
357
561
|
this.log(`Subprocess PID: ${proc.pid ?? 'undefined (spawn may have failed)'}`);
|
|
358
|
-
|
|
562
|
+
this.log(`[diag] Piping ${prompt.length} chars via stdin`);
|
|
563
|
+
if (proc.stdin) {
|
|
564
|
+
proc.stdin.write(prompt);
|
|
359
565
|
proc.stdin.end();
|
|
566
|
+
}
|
|
360
567
|
return { proc, tmpFile: undefined };
|
|
361
568
|
}
|
|
362
569
|
parseStreamLine(line) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"feature-agent-worker.d.ts","sourceRoot":"","sources":["../../../../../../../../packages/core/src/infrastructure/services/agents/feature-agent/feature-agent-worker.ts"],"names":[],"mappings":";AACA;;;;;;;;GAQG;AAEH,OAAO,kBAAkB,CAAC;AAe1B,OAAO,EAAiC,KAAK,SAAS,EAAE,MAAM,8BAA8B,CAAC;AAW7F,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,8BAA8B,CAAC;AAElE,MAAM,WAAW,UAAU;IACzB,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,aAAa,CAAC,EAAE,aAAa,CAAC;IAC9B,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,mBAAmB,CAAC,EAAE,OAAO,CAAC;IAC9B,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,SAAS,CAAC,EAAE,SAAS,CAAC;IACtB,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED;;;GAGG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,UAAU,CAwE1D;AAgCD;;;GAGG;AACH,wBAAsB,SAAS,CAAC,IAAI,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC,
|
|
1
|
+
{"version":3,"file":"feature-agent-worker.d.ts","sourceRoot":"","sources":["../../../../../../../../packages/core/src/infrastructure/services/agents/feature-agent/feature-agent-worker.ts"],"names":[],"mappings":";AACA;;;;;;;;GAQG;AAEH,OAAO,kBAAkB,CAAC;AAe1B,OAAO,EAAiC,KAAK,SAAS,EAAE,MAAM,8BAA8B,CAAC;AAW7F,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,8BAA8B,CAAC;AAElE,MAAM,WAAW,UAAU;IACzB,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,aAAa,CAAC,EAAE,aAAa,CAAC;IAC9B,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,mBAAmB,CAAC,EAAE,OAAO,CAAC;IAC9B,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,SAAS,CAAC,EAAE,SAAS,CAAC;IACtB,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED;;;GAGG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,UAAU,CAwE1D;AAgCD;;;GAGG;AACH,wBAAsB,SAAS,CAAC,IAAI,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC,CAkS/D"}
|
package/dist/packages/core/src/infrastructure/services/agents/feature-agent/feature-agent-worker.js
CHANGED
|
@@ -182,6 +182,15 @@ export async function runWorker(args) {
|
|
|
182
182
|
getDefaultBranch: (cwd) => gitPrService.getDefaultBranch(cwd),
|
|
183
183
|
verifyMerge: (cwd, featureBranch, baseBranch, premergeBaseSha) => gitPrService.verifyMerge(cwd, featureBranch, baseBranch, premergeBaseSha),
|
|
184
184
|
revParse: (cwd, ref) => gitPrService.revParse(cwd, ref),
|
|
185
|
+
commitAll: async (cwd, message) => {
|
|
186
|
+
try {
|
|
187
|
+
return await gitPrService.commitAll(cwd, message);
|
|
188
|
+
}
|
|
189
|
+
catch {
|
|
190
|
+
// commitAll throws when there's nothing to commit — return undefined
|
|
191
|
+
return undefined;
|
|
192
|
+
}
|
|
193
|
+
},
|
|
185
194
|
localMergeSquash: (cwd, featureBranch, baseBranch, commitMessage, hasRemote) => gitPrService.localMergeSquash(cwd, featureBranch, baseBranch, commitMessage, hasRemote),
|
|
186
195
|
featureRepository,
|
|
187
196
|
gitPrService,
|
|
@@ -36,6 +36,11 @@ export interface MergeNodeDeps {
|
|
|
36
36
|
* Resolve a branch ref to its current SHA.
|
|
37
37
|
*/
|
|
38
38
|
revParse: (cwd: string, ref: string) => Promise<string>;
|
|
39
|
+
/**
|
|
40
|
+
* Stage all changes and commit in the given directory.
|
|
41
|
+
* Returns the commit hash, or undefined if there was nothing to commit.
|
|
42
|
+
*/
|
|
43
|
+
commitAll: (cwd: string, message: string) => Promise<string | undefined>;
|
|
39
44
|
gitPrService: IGitPrService;
|
|
40
45
|
cleanupFeatureWorktreeUseCase: Pick<CleanupFeatureWorktreeUseCase, 'execute'>;
|
|
41
46
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"merge.node.d.ts","sourceRoot":"","sources":["../../../../../../../../../../packages/core/src/infrastructure/services/agents/feature-agent/nodes/merge/merge.node.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAGH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,+DAA+D,CAAC;AACpG,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AACxD,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,yEAAyE,CAAC;AAClH,OAAO,KAAK,EACV,WAAW,EACX,aAAa,EACd,MAAM,iEAAiE,CAAC;AAmBzE,OAAO,KAAK,EAAE,6BAA6B,EAAE,MAAM,uEAAuE,CAAC;AAE3H,MAAM,WAAW,aAAa;IAC5B,QAAQ,EAAE,cAAc,CAAC;IACzB,cAAc,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,KAAK,OAAO,CAAC,WAAW,CAAC,CAAC;IAC1E,SAAS,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;IAC7C,gBAAgB,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;IACnD,iBAAiB,EAAE,IAAI,CAAC,kBAAkB,EAAE,UAAU,GAAG,QAAQ,CAAC,CAAC;IACnE;;OAEG;IACH,gBAAgB,EAAE,CAChB,GAAG,EAAE,MAAM,EACX,aAAa,EAAE,MAAM,EACrB,UAAU,EAAE,MAAM,EAClB,aAAa,EAAE,MAAM,EACrB,SAAS,CAAC,EAAE,OAAO,KAChB,OAAO,CAAC,IAAI,CAAC,CAAC;IACnB;;;OAGG;IACH,WAAW,EAAE,CACX,GAAG,EAAE,MAAM,EACX,aAAa,EAAE,MAAM,EACrB,UAAU,EAAE,MAAM,EAClB,eAAe,CAAC,EAAE,MAAM,KACrB,OAAO,CAAC,OAAO,CAAC,CAAC;IACtB;;OAEG;IACH,QAAQ,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;IACxD,YAAY,EAAE,aAAa,CAAC;IAC5B,6BAA6B,EAAE,IAAI,CAAC,6BAA6B,EAAE,SAAS,CAAC,CAAC;CAC/E;AAED;;;;;GAKG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,aAAa,IAGnC,OAAO,iBAAiB,KAAG,OAAO,CAAC,OAAO,CAAC,iBAAiB,CAAC,CAAC,
|
|
1
|
+
{"version":3,"file":"merge.node.d.ts","sourceRoot":"","sources":["../../../../../../../../../../packages/core/src/infrastructure/services/agents/feature-agent/nodes/merge/merge.node.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAGH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,+DAA+D,CAAC;AACpG,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AACxD,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,yEAAyE,CAAC;AAClH,OAAO,KAAK,EACV,WAAW,EACX,aAAa,EACd,MAAM,iEAAiE,CAAC;AAmBzE,OAAO,KAAK,EAAE,6BAA6B,EAAE,MAAM,uEAAuE,CAAC;AAE3H,MAAM,WAAW,aAAa;IAC5B,QAAQ,EAAE,cAAc,CAAC;IACzB,cAAc,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,KAAK,OAAO,CAAC,WAAW,CAAC,CAAC;IAC1E,SAAS,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;IAC7C,gBAAgB,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;IACnD,iBAAiB,EAAE,IAAI,CAAC,kBAAkB,EAAE,UAAU,GAAG,QAAQ,CAAC,CAAC;IACnE;;OAEG;IACH,gBAAgB,EAAE,CAChB,GAAG,EAAE,MAAM,EACX,aAAa,EAAE,MAAM,EACrB,UAAU,EAAE,MAAM,EAClB,aAAa,EAAE,MAAM,EACrB,SAAS,CAAC,EAAE,OAAO,KAChB,OAAO,CAAC,IAAI,CAAC,CAAC;IACnB;;;OAGG;IACH,WAAW,EAAE,CACX,GAAG,EAAE,MAAM,EACX,aAAa,EAAE,MAAM,EACrB,UAAU,EAAE,MAAM,EAClB,eAAe,CAAC,EAAE,MAAM,KACrB,OAAO,CAAC,OAAO,CAAC,CAAC;IACtB;;OAEG;IACH,QAAQ,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;IACxD;;;OAGG;IACH,SAAS,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAAC;IACzE,YAAY,EAAE,aAAa,CAAC;IAC5B,6BAA6B,EAAE,IAAI,CAAC,6BAA6B,EAAE,SAAS,CAAC,CAAC;CAC/E;AAED;;;;;GAKG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,aAAa,IAGnC,OAAO,iBAAiB,KAAG,OAAO,CAAC,OAAO,CAAC,iBAAiB,CAAC,CAAC,CA0V7E"}
|