@shepai/cli 1.122.1 → 1.122.2-pr381.7d9e407
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 +187 -29
- package/dist/packages/core/src/infrastructure/services/agents/feature-agent/feature-agent-graph.d.ts.map +1 -1
- package/dist/packages/core/src/infrastructure/services/agents/feature-agent/feature-agent-graph.js +21 -4
- 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 +1 -1
- package/dist/packages/core/src/infrastructure/services/agents/feature-agent/nodes/node-helpers.js +2 -2
- package/dist/packages/core/src/infrastructure/services/agents/feature-agent/nodes/validate.node.d.ts +7 -1
- package/dist/packages/core/src/infrastructure/services/agents/feature-agent/nodes/validate.node.d.ts.map +1 -1
- package/dist/packages/core/src/infrastructure/services/agents/feature-agent/nodes/validate.node.js +24 -2
- 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]__2698e9f4._.js +1 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__2698e9f4._.js.map +1 -1
- 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]__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]__8e3bf5d7._.js +1 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__8e3bf5d7._.js.map +1 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__a022445f._.js +2 -2
- package/web/.next/server/chunks/ssr/[root-of-the-server]__a7de2711._.js +2 -2
- package/web/.next/server/chunks/ssr/[root-of-the-server]__c07f9f79._.js +1 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__c07f9f79._.js.map +1 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__c605a375._.js +1 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__c605a375._.js.map +1 -1
- package/web/.next/server/chunks/ssr/_0dc2cfd3._.js +1 -1
- package/web/.next/server/chunks/ssr/_0dc2cfd3._.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/_204ecb5a._.js +3 -0
- package/web/.next/server/chunks/ssr/{_469c5451._.js.map → _204ecb5a._.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/{_92d851b4._.js → _434878d3._.js} +2 -2
- package/web/.next/server/chunks/ssr/{_92d851b4._.js.map → _434878d3._.js.map} +1 -1
- package/web/.next/server/chunks/ssr/{_b294a667._.js → _510be09a._.js} +2 -2
- package/web/.next/server/chunks/ssr/{_b294a667._.js.map → _510be09a._.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/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_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/{e6a2fb8707e079ff.js → 19401b65e1298cb0.js} +1 -1
- package/web/.next/static/chunks/{941c13dcdb1978a4.js → 2c0191c062d5f7ae.js} +2 -2
- package/web/.next/static/chunks/{9df4681de92ebfc3.js → 4da275e6ef808c4d.js} +1 -1
- package/web/.next/static/chunks/{78ab7b134f0649ac.js → 50bf223ed146d4ed.js} +1 -1
- package/web/.next/static/chunks/5a9e671eb04de758.js +1 -0
- package/web/.next/static/chunks/6a8fb1992b738cc9.js +1 -0
- package/web/.next/static/chunks/{37ac7fe1cd493293.js → 89ffd07cdb158389.js} +1 -1
- package/web/.next/static/chunks/{50dd80c8aafa3b20.js → a637e16d364af323.js} +1 -1
- package/web/.next/static/chunks/bc1ce100834f414a.js +1 -0
- package/web/.next/static/chunks/{658fc2f5f65cf3b5.js → df88f3e08b196bbf.js} +2 -2
- package/web/.next/server/chunks/ssr/_469c5451._.js +0 -3
- package/web/.next/static/chunks/11e4439096f8d652.js +0 -1
- package/web/.next/static/chunks/df85e52b1afb7340.js +0 -1
- package/web/.next/static/chunks/e9c3fbbeb418cbfa.js +0 -1
- /package/web/.next/static/{hsK1x0unrjI_pUsvQhn6P → NKkt3_PEmNxKD_ihRAzNE}/_buildManifest.js +0 -0
- /package/web/.next/static/{hsK1x0unrjI_pUsvQhn6P → NKkt3_PEmNxKD_ihRAzNE}/_clientMiddlewareManifest.json +0 -0
- /package/web/.next/static/{hsK1x0unrjI_pUsvQhn6P → NKkt3_PEmNxKD_ihRAzNE}/_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;AAMH,OAAO,KAAK,
|
|
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;AAMH,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;IA2MtF,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;IA+ElB,OAAO,CAAC,eAAe;CAgDxB"}
|
|
@@ -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 { writeFileSync, unlinkSync } from 'node:fs';
|
|
11
|
+
import { writeFileSync, unlinkSync, readdirSync, existsSync } from 'node:fs';
|
|
12
12
|
import { execFileSync } from 'node:child_process';
|
|
13
13
|
import { tmpdir } from 'node:os';
|
|
14
14
|
import { join } from 'node:path';
|
|
@@ -36,11 +36,13 @@ const SUPPORTED_FEATURES = new Set(['session-resume', 'streaming']);
|
|
|
36
36
|
*/
|
|
37
37
|
export class CursorExecutorService {
|
|
38
38
|
spawn;
|
|
39
|
+
authConfig;
|
|
39
40
|
agentType = 'cursor';
|
|
40
41
|
/** When true, suppresses debug logging (set per-call via options.silent) */
|
|
41
42
|
silent = false;
|
|
42
|
-
constructor(spawn) {
|
|
43
|
+
constructor(spawn, authConfig) {
|
|
43
44
|
this.spawn = spawn;
|
|
45
|
+
this.authConfig = authConfig;
|
|
44
46
|
}
|
|
45
47
|
/** Debug logging — writes to stdout so it appears in the worker log file */
|
|
46
48
|
log(message) {
|
|
@@ -58,19 +60,34 @@ export class CursorExecutorService {
|
|
|
58
60
|
// stream-json is unreliable on Windows where shell: true can mangle args.
|
|
59
61
|
const args = this.buildArgs(prompt, options);
|
|
60
62
|
const { proc, tmpFile } = this.spawnAgent(prompt, args, options);
|
|
63
|
+
// Diagnostic: verify streams are connected and process is alive
|
|
64
|
+
this.log(`[diag] proc.pid=${proc.pid}, killed=${proc.killed}`);
|
|
65
|
+
this.log(`[diag] stdout=${!!proc.stdout}, stderr=${!!proc.stderr}, stdin=${!!proc.stdin}`);
|
|
66
|
+
this.log(`[diag] CURSOR_API_KEY set=${!!process.env.CURSOR_API_KEY}, len=${process.env.CURSOR_API_KEY?.length ?? 0}`);
|
|
67
|
+
this.log(`[diag] authConfig.token set=${!!this.authConfig?.token}, method=${this.authConfig?.authMethod ?? 'none'}`);
|
|
68
|
+
this.log(`[diag] platform=${process.platform}, cwd=${options?.cwd ?? '(inherited)'}`);
|
|
61
69
|
return new Promise((resolve, reject) => {
|
|
62
70
|
let lineBuffer = '';
|
|
63
71
|
let stderr = '';
|
|
64
72
|
let timedOut = false;
|
|
65
73
|
let timeoutId;
|
|
74
|
+
let stdoutChunks = 0;
|
|
75
|
+
let stderrChunks = 0;
|
|
76
|
+
const startTime = Date.now();
|
|
66
77
|
// Accumulated from JSON events or raw text fallback
|
|
67
78
|
let resultText = '';
|
|
68
79
|
let rawText = '';
|
|
69
80
|
let sessionId;
|
|
70
81
|
let metadata;
|
|
82
|
+
// Periodic heartbeat to prove the executor is alive and waiting
|
|
83
|
+
const heartbeatId = setInterval(() => {
|
|
84
|
+
const elapsed = Math.round((Date.now() - startTime) / 1000);
|
|
85
|
+
this.log(`[diag] heartbeat ${elapsed}s: stdout_chunks=${stdoutChunks}, stderr_chunks=${stderrChunks}, pid_killed=${proc.killed}`);
|
|
86
|
+
}, 15_000);
|
|
71
87
|
if (options?.timeout) {
|
|
72
88
|
timeoutId = setTimeout(() => {
|
|
73
89
|
timedOut = true;
|
|
90
|
+
this.log(`[diag] TIMEOUT after ${options.timeout}ms — killing process tree`);
|
|
74
91
|
// On Windows, proc.kill() may not kill the entire process tree
|
|
75
92
|
// (PowerShell + child agent process). Use taskkill /T for tree kill.
|
|
76
93
|
if (process.platform === 'win32' && proc.pid) {
|
|
@@ -78,9 +95,11 @@ export class CursorExecutorService {
|
|
|
78
95
|
execFileSync('taskkill', ['/F', '/T', '/PID', String(proc.pid)], {
|
|
79
96
|
stdio: 'ignore',
|
|
80
97
|
});
|
|
98
|
+
this.log(`[diag] taskkill /T /PID ${proc.pid} succeeded`);
|
|
81
99
|
}
|
|
82
100
|
catch {
|
|
83
101
|
proc.kill();
|
|
102
|
+
this.log(`[diag] taskkill failed, fell back to proc.kill()`);
|
|
84
103
|
}
|
|
85
104
|
}
|
|
86
105
|
else {
|
|
@@ -107,17 +126,35 @@ export class CursorExecutorService {
|
|
|
107
126
|
if (parsed.duration_ms !== undefined) {
|
|
108
127
|
metadata = { ...metadata, duration_ms: parsed.duration_ms };
|
|
109
128
|
}
|
|
129
|
+
if (parsed.is_error) {
|
|
130
|
+
this.log(`[diag] result event has is_error=true: ${JSON.stringify(parsed).slice(0, 300)}`);
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
else if (parsed.type === 'error') {
|
|
134
|
+
this.log(`[diag] cursor error event: ${JSON.stringify(parsed).slice(0, 500)}`);
|
|
135
|
+
}
|
|
136
|
+
else if (parsed.type !== 'user' &&
|
|
137
|
+
parsed.type !== 'system' &&
|
|
138
|
+
parsed.type !== 'thinking' &&
|
|
139
|
+
parsed.type !== 'tool_call') {
|
|
140
|
+
this.log(`[diag] unknown event type="${parsed.type}": ${JSON.stringify(parsed).slice(0, 300)}`);
|
|
110
141
|
}
|
|
111
|
-
// user, system, thinking events: logged but don't affect result
|
|
112
142
|
}
|
|
113
143
|
catch {
|
|
114
144
|
// Non-JSON output — accumulate as raw text fallback
|
|
115
|
-
if (line.length > 0)
|
|
145
|
+
if (line.length > 0) {
|
|
116
146
|
rawText += `${line}\n`;
|
|
147
|
+
this.log(`[diag] non-JSON line (${line.length} chars): ${line.slice(0, 200)}`);
|
|
148
|
+
}
|
|
117
149
|
}
|
|
118
150
|
};
|
|
119
151
|
proc.stdout?.on('data', (chunk) => {
|
|
120
|
-
|
|
152
|
+
stdoutChunks++;
|
|
153
|
+
const data = chunk.toString();
|
|
154
|
+
if (stdoutChunks <= 3) {
|
|
155
|
+
this.log(`[diag] stdout chunk #${stdoutChunks}: ${data.length} bytes, first 200: ${data.slice(0, 200).replace(/\n/g, '\\n')}`);
|
|
156
|
+
}
|
|
157
|
+
lineBuffer += data;
|
|
121
158
|
const lines = lineBuffer.split('\n');
|
|
122
159
|
lineBuffer = lines.pop() ?? '';
|
|
123
160
|
for (const line of lines) {
|
|
@@ -127,19 +164,22 @@ export class CursorExecutorService {
|
|
|
127
164
|
}
|
|
128
165
|
});
|
|
129
166
|
proc.stderr?.on('data', (chunk) => {
|
|
167
|
+
stderrChunks++;
|
|
130
168
|
const data = chunk.toString();
|
|
131
169
|
stderr += data;
|
|
132
|
-
this.log(`stderr: ${data.trimEnd()}`);
|
|
170
|
+
this.log(`[diag] stderr chunk #${stderrChunks}: ${data.trimEnd()}`);
|
|
133
171
|
// Detect fatal errors early so callers don't waste time retrying
|
|
134
172
|
if (data.includes('Cannot use this model')) {
|
|
135
173
|
if (timeoutId)
|
|
136
174
|
clearTimeout(timeoutId);
|
|
175
|
+
clearInterval(heartbeatId);
|
|
137
176
|
proc.kill();
|
|
138
177
|
reject(new Error(data.trim()));
|
|
139
178
|
}
|
|
140
179
|
});
|
|
141
180
|
proc.on('error', (error) => {
|
|
142
|
-
this.log(`Process
|
|
181
|
+
this.log(`[diag] Process ERROR event: ${error.message} (code=${error.code})`);
|
|
182
|
+
clearInterval(heartbeatId);
|
|
143
183
|
if (timeoutId)
|
|
144
184
|
clearTimeout(timeoutId);
|
|
145
185
|
if (error.code === 'ENOENT') {
|
|
@@ -150,6 +190,8 @@ export class CursorExecutorService {
|
|
|
150
190
|
}
|
|
151
191
|
});
|
|
152
192
|
proc.on('close', (code) => {
|
|
193
|
+
const elapsed = Math.round((Date.now() - startTime) / 1000);
|
|
194
|
+
clearInterval(heartbeatId);
|
|
153
195
|
// Clean up temp file on Windows
|
|
154
196
|
if (tmpFile) {
|
|
155
197
|
try {
|
|
@@ -163,7 +205,7 @@ export class CursorExecutorService {
|
|
|
163
205
|
processLine(lineBuffer.trim());
|
|
164
206
|
// Use raw text as fallback when no JSON result was captured
|
|
165
207
|
const finalText = resultText || rawText.trim();
|
|
166
|
-
this.log(`Process
|
|
208
|
+
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
209
|
if (timeoutId)
|
|
168
210
|
clearTimeout(timeoutId);
|
|
169
211
|
if (timedOut) {
|
|
@@ -171,9 +213,17 @@ export class CursorExecutorService {
|
|
|
171
213
|
return;
|
|
172
214
|
}
|
|
173
215
|
if (code !== 0 && code !== null) {
|
|
174
|
-
|
|
216
|
+
const errMsg = stderr.trim() || `Process exited with code ${code}`;
|
|
217
|
+
this.log(`[diag] non-zero exit — rejecting with: ${errMsg.slice(0, 200)}`);
|
|
218
|
+
reject(new Error(errMsg));
|
|
175
219
|
return;
|
|
176
220
|
}
|
|
221
|
+
if (stdoutChunks === 0 && stderrChunks === 0) {
|
|
222
|
+
this.log(`[diag] WARNING: process exited with code 0 but produced ZERO output (stdout=0, stderr=0, elapsed=${elapsed}s)`);
|
|
223
|
+
}
|
|
224
|
+
if (!finalText && code === 0) {
|
|
225
|
+
this.log(`[diag] WARNING: process exited code=0 but result is empty (resultText=${resultText.length}, rawText=${rawText.length})`);
|
|
226
|
+
}
|
|
177
227
|
const result = { result: finalText };
|
|
178
228
|
if (sessionId)
|
|
179
229
|
result.sessionId = sessionId;
|
|
@@ -184,20 +234,25 @@ export class CursorExecutorService {
|
|
|
184
234
|
});
|
|
185
235
|
}
|
|
186
236
|
async *executeStream(prompt, options) {
|
|
237
|
+
this.silent = options?.silent ?? false;
|
|
187
238
|
const args = this.buildStreamArgs(prompt, options);
|
|
188
239
|
const { proc, tmpFile } = this.spawnAgent(prompt, args, options);
|
|
240
|
+
this.log(`[stream] pid=${proc.pid}, stdout=${!!proc.stdout}, stderr=${!!proc.stderr}`);
|
|
189
241
|
let lineBuffer = '';
|
|
190
242
|
let stderr = '';
|
|
243
|
+
let stdoutChunks = 0;
|
|
244
|
+
let stderrChunks = 0;
|
|
245
|
+
const startTime = Date.now();
|
|
191
246
|
const queue = [];
|
|
192
247
|
let resolve = null;
|
|
193
248
|
let error = null;
|
|
194
|
-
|
|
249
|
+
const enqueue = (event) => {
|
|
195
250
|
queue.push(event);
|
|
196
251
|
if (resolve) {
|
|
197
252
|
resolve();
|
|
198
253
|
resolve = null;
|
|
199
254
|
}
|
|
200
|
-
}
|
|
255
|
+
};
|
|
201
256
|
function waitForItem() {
|
|
202
257
|
if (queue.length > 0)
|
|
203
258
|
return Promise.resolve();
|
|
@@ -205,8 +260,18 @@ export class CursorExecutorService {
|
|
|
205
260
|
resolve = r;
|
|
206
261
|
});
|
|
207
262
|
}
|
|
263
|
+
// Heartbeat for stream mode too
|
|
264
|
+
const heartbeatId = setInterval(() => {
|
|
265
|
+
const elapsed = Math.round((Date.now() - startTime) / 1000);
|
|
266
|
+
this.log(`[stream] heartbeat ${elapsed}s: stdout_chunks=${stdoutChunks}, stderr_chunks=${stderrChunks}, pid_killed=${proc.killed}`);
|
|
267
|
+
}, 30_000);
|
|
208
268
|
proc.stdout?.on('data', (chunk) => {
|
|
209
|
-
|
|
269
|
+
stdoutChunks++;
|
|
270
|
+
const data = chunk.toString();
|
|
271
|
+
if (stdoutChunks <= 3) {
|
|
272
|
+
this.log(`[stream] stdout chunk #${stdoutChunks}: ${data.length} bytes`);
|
|
273
|
+
}
|
|
274
|
+
lineBuffer += data;
|
|
210
275
|
const lines = lineBuffer.split('\n');
|
|
211
276
|
lineBuffer = lines.pop() ?? '';
|
|
212
277
|
for (const line of lines) {
|
|
@@ -219,13 +284,21 @@ export class CursorExecutorService {
|
|
|
219
284
|
}
|
|
220
285
|
});
|
|
221
286
|
proc.stderr?.on('data', (chunk) => {
|
|
222
|
-
|
|
287
|
+
stderrChunks++;
|
|
288
|
+
const data = chunk.toString();
|
|
289
|
+
stderr += data;
|
|
290
|
+
this.log(`[stream] stderr chunk #${stderrChunks}: ${data.trimEnd()}`);
|
|
223
291
|
});
|
|
224
292
|
proc.on('error', (err) => {
|
|
293
|
+
this.log(`[stream] Process ERROR: ${err.message}`);
|
|
294
|
+
clearInterval(heartbeatId);
|
|
225
295
|
error = err;
|
|
226
296
|
enqueue(null);
|
|
227
297
|
});
|
|
228
298
|
proc.on('close', (code) => {
|
|
299
|
+
const elapsed = Math.round((Date.now() - startTime) / 1000);
|
|
300
|
+
clearInterval(heartbeatId);
|
|
301
|
+
this.log(`[stream] Process CLOSE: code=${code}, elapsed=${elapsed}s, stdout_chunks=${stdoutChunks}, stderr_chunks=${stderrChunks}`);
|
|
229
302
|
if (tmpFile) {
|
|
230
303
|
try {
|
|
231
304
|
unlinkSync(tmpFile);
|
|
@@ -239,8 +312,10 @@ export class CursorExecutorService {
|
|
|
239
312
|
if (event)
|
|
240
313
|
enqueue(event);
|
|
241
314
|
}
|
|
242
|
-
if (code !== 0 && code !== null
|
|
243
|
-
|
|
315
|
+
if (code !== 0 && code !== null) {
|
|
316
|
+
const errMsg = stderr.trim() || `Process exited with code ${code}`;
|
|
317
|
+
this.log(`[stream] non-zero exit: ${errMsg}`);
|
|
318
|
+
enqueue({ type: 'error', content: errMsg, timestamp: new Date() });
|
|
244
319
|
}
|
|
245
320
|
enqueue(null);
|
|
246
321
|
});
|
|
@@ -286,6 +361,10 @@ export class CursorExecutorService {
|
|
|
286
361
|
}
|
|
287
362
|
if (parsed.type === 'user')
|
|
288
363
|
return; // Skip echoed input
|
|
364
|
+
// Log any unrecognized event type so nothing is silently dropped
|
|
365
|
+
if (!['assistant', 'tool_call', 'result', 'user', 'system', 'thinking'].includes(parsed.type)) {
|
|
366
|
+
this.log(`[diag] unhandled stream event type="${parsed.type}": ${line.slice(0, 200)}`);
|
|
367
|
+
}
|
|
289
368
|
}
|
|
290
369
|
catch {
|
|
291
370
|
if (line.length > 0)
|
|
@@ -310,36 +389,115 @@ export class CursorExecutorService {
|
|
|
310
389
|
return args;
|
|
311
390
|
}
|
|
312
391
|
/**
|
|
313
|
-
*
|
|
392
|
+
* Resolve the cursor CLI's bundled node.exe and index.js paths on Windows.
|
|
393
|
+
*
|
|
394
|
+
* The cursor CLI installs to `%LOCALAPPDATA%\cursor-agent\` with:
|
|
395
|
+
* - `agent.cmd` / `cursor-agent.ps1` (shell wrappers)
|
|
396
|
+
* - `versions/<YYYY.MM.DD-commit>/node.exe` + `index.js`
|
|
314
397
|
*
|
|
315
|
-
*
|
|
316
|
-
*
|
|
317
|
-
*
|
|
318
|
-
*
|
|
319
|
-
*
|
|
398
|
+
* Spawning via agent.cmd creates a problematic nesting chain:
|
|
399
|
+
* PowerShell → agent.cmd → PowerShell → cursor-agent.ps1 → node.exe
|
|
400
|
+
* This chain hangs on Windows CI runners. Direct invocation bypasses it.
|
|
401
|
+
*
|
|
402
|
+
* @returns `{ nodePath, indexPath }` or `undefined` if not found
|
|
403
|
+
*/
|
|
404
|
+
resolveCursorBinary() {
|
|
405
|
+
const localAppData = process.env.LOCALAPPDATA;
|
|
406
|
+
if (!localAppData) {
|
|
407
|
+
this.log('[diag] resolveCursorBinary: LOCALAPPDATA not set');
|
|
408
|
+
return undefined;
|
|
409
|
+
}
|
|
410
|
+
const versionsDir = join(localAppData, 'cursor-agent', 'versions');
|
|
411
|
+
if (!existsSync(versionsDir)) {
|
|
412
|
+
this.log(`[diag] resolveCursorBinary: versions dir not found: ${versionsDir}`);
|
|
413
|
+
return undefined;
|
|
414
|
+
}
|
|
415
|
+
// Find the latest version directory (format: YYYY.MM.DD-commit)
|
|
416
|
+
const versionPattern = /^\d{4}\.\d{1,2}\.\d{1,2}-[a-f0-9]+$/;
|
|
417
|
+
const versions = readdirSync(versionsDir)
|
|
418
|
+
.filter((d) => versionPattern.test(d))
|
|
419
|
+
.sort()
|
|
420
|
+
.reverse();
|
|
421
|
+
if (versions.length === 0) {
|
|
422
|
+
this.log(`[diag] resolveCursorBinary: no version dirs in ${versionsDir}`);
|
|
423
|
+
return undefined;
|
|
424
|
+
}
|
|
425
|
+
const versionDir = join(versionsDir, versions[0]);
|
|
426
|
+
const nodePath = join(versionDir, 'node.exe');
|
|
427
|
+
const indexPath = join(versionDir, 'index.js');
|
|
428
|
+
if (!existsSync(nodePath) || !existsSync(indexPath)) {
|
|
429
|
+
this.log(`[diag] resolveCursorBinary: missing binary — node=${existsSync(nodePath)}, index=${existsSync(indexPath)}`);
|
|
430
|
+
return undefined;
|
|
431
|
+
}
|
|
432
|
+
this.log(`[diag] resolveCursorBinary: resolved version=${versions[0]}`);
|
|
433
|
+
return { nodePath, indexPath };
|
|
434
|
+
}
|
|
435
|
+
/**
|
|
436
|
+
* Spawn the agent process, handling Windows specially.
|
|
437
|
+
*
|
|
438
|
+
* On Windows, the cursor CLI ships as `agent.cmd` which spawns PowerShell
|
|
439
|
+
* which runs `cursor-agent.ps1` which runs `node.exe index.js`. This triple
|
|
440
|
+
* nesting (PowerShell → cmd.exe → PowerShell → node.exe) hangs on Windows
|
|
441
|
+
* CI runners. Solution: resolve the cursor CLI's bundled `node.exe` and
|
|
442
|
+
* `index.js` directly, bypassing all shell wrappers.
|
|
320
443
|
*
|
|
321
444
|
* On Linux/macOS, spawn `agent` directly — no shell needed.
|
|
322
445
|
*/
|
|
323
|
-
|
|
446
|
+
/**
|
|
447
|
+
* Build the subprocess environment: strip CLAUDECODE, inject CURSOR_API_KEY
|
|
448
|
+
* from authConfig when token auth is configured.
|
|
449
|
+
*/
|
|
450
|
+
buildEnv(extra) {
|
|
324
451
|
const { CLAUDECODE: _, ...cleanEnv } = process.env;
|
|
452
|
+
// Inject CURSOR_API_KEY from stored settings so the cursor CLI authenticates
|
|
453
|
+
// even when the env var isn't inherited (e.g. direct node.exe invocation on Windows).
|
|
454
|
+
if (this.authConfig?.authMethod === 'token' && this.authConfig.token) {
|
|
455
|
+
cleanEnv.CURSOR_API_KEY = this.authConfig.token;
|
|
456
|
+
this.log(`[diag] buildEnv: injected CURSOR_API_KEY from authConfig (${this.authConfig.token.length} chars)`);
|
|
457
|
+
}
|
|
458
|
+
else {
|
|
459
|
+
this.log(`[diag] buildEnv: NO token injection (authMethod=${this.authConfig?.authMethod ?? 'none'}, hasToken=${!!this.authConfig?.token}, envKey=${!!cleanEnv.CURSOR_API_KEY})`);
|
|
460
|
+
}
|
|
461
|
+
const env = extra ? { ...cleanEnv, ...extra } : cleanEnv;
|
|
462
|
+
this.log(`[diag] buildEnv: final CURSOR_API_KEY in env=${!!env.CURSOR_API_KEY}, len=${env.CURSOR_API_KEY?.length ?? 0}`);
|
|
463
|
+
return env;
|
|
464
|
+
}
|
|
465
|
+
spawnAgent(prompt, args, options) {
|
|
325
466
|
const cwd = options?.cwd;
|
|
326
467
|
if (IS_WINDOWS) {
|
|
327
|
-
|
|
468
|
+
const resolved = this.resolveCursorBinary();
|
|
469
|
+
if (resolved) {
|
|
470
|
+
// Direct invocation: node.exe index.js <args>
|
|
471
|
+
// No shell wrappers, no nesting, no hangs.
|
|
472
|
+
const directArgs = [resolved.indexPath, ...args];
|
|
473
|
+
this.log(`Windows direct mode: ${resolved.nodePath}`);
|
|
474
|
+
this.log(`Args: ${directArgs.map((a) => (a.length > 80 ? `${a.slice(0, 77)}...` : a)).join(' ')}`);
|
|
475
|
+
const proc = this.spawn(resolved.nodePath, directArgs, {
|
|
476
|
+
cwd,
|
|
477
|
+
stdio: ['pipe', 'pipe', 'pipe'],
|
|
478
|
+
windowsHide: true,
|
|
479
|
+
env: this.buildEnv({ CURSOR_INVOKED_AS: 'agent' }),
|
|
480
|
+
});
|
|
481
|
+
this.log(`Direct PID: ${proc.pid ?? 'undefined (spawn may have failed)'}`);
|
|
482
|
+
if (proc.stdin)
|
|
483
|
+
proc.stdin.end();
|
|
484
|
+
return { proc, tmpFile: undefined };
|
|
485
|
+
}
|
|
486
|
+
// Fallback: if direct resolution fails, use PowerShell + temp file
|
|
487
|
+
this.log('[diag] Windows fallback: cursor binary not resolved, using PowerShell + temp file');
|
|
328
488
|
const tmpFile = join(tmpdir(), `shep-cursor-${Date.now()}-${Math.random().toString(36).slice(2, 6)}.txt`);
|
|
329
489
|
writeFileSync(tmpFile, prompt, 'utf8');
|
|
330
|
-
// Build the agent args WITHOUT -p and the prompt (they go via temp file)
|
|
331
490
|
const agentFlags = args.filter((a) => a !== '-p' && a !== prompt).join(' ');
|
|
332
491
|
const safePath = tmpFile.replace(/'/g, "''");
|
|
333
492
|
const psCmd = `$p = Get-Content -Raw '${safePath}'; & agent ${agentFlags} -p $p`;
|
|
334
|
-
this.log(`
|
|
335
|
-
this.log(`PS command: ${psCmd.replace(prompt, `<${prompt.length} chars>`)}`);
|
|
493
|
+
this.log(`[diag] PS command: ${psCmd.replace(prompt, `<${prompt.length} chars>`)}`);
|
|
336
494
|
const proc = this.spawn('powershell.exe', ['-NoProfile', '-NonInteractive', '-Command', psCmd], {
|
|
337
495
|
cwd,
|
|
338
496
|
stdio: ['pipe', 'pipe', 'pipe'],
|
|
339
497
|
windowsHide: true,
|
|
340
|
-
env:
|
|
498
|
+
env: this.buildEnv(),
|
|
341
499
|
});
|
|
342
|
-
this.log(`PowerShell PID: ${proc.pid ?? 'undefined (spawn may have failed)'}`);
|
|
500
|
+
this.log(`[diag] PowerShell PID: ${proc.pid ?? 'undefined (spawn may have failed)'}`);
|
|
343
501
|
if (proc.stdin)
|
|
344
502
|
proc.stdin.end();
|
|
345
503
|
return { proc, tmpFile };
|
|
@@ -347,7 +505,7 @@ export class CursorExecutorService {
|
|
|
347
505
|
// Linux/macOS: spawn agent directly, no shell needed
|
|
348
506
|
const spawnOpts = {
|
|
349
507
|
stdio: ['pipe', 'pipe', 'pipe'],
|
|
350
|
-
env:
|
|
508
|
+
env: this.buildEnv(),
|
|
351
509
|
};
|
|
352
510
|
if (cwd)
|
|
353
511
|
spawnOpts.cwd = cwd;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"feature-agent-graph.d.ts","sourceRoot":"","sources":["../../../../../../../../packages/core/src/infrastructure/services/agents/feature-agent/feature-agent-graph.ts"],"names":[],"mappings":"AAAA,OAAO,EAA0B,KAAK,mBAAmB,EAAE,MAAM,sBAAsB,CAAC;AACxF,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,+DAA+D,CAAC;AAOpG,OAAO,EAAmB,KAAK,aAAa,EAAE,MAAM,6BAA6B,CAAC;
|
|
1
|
+
{"version":3,"file":"feature-agent-graph.d.ts","sourceRoot":"","sources":["../../../../../../../../packages/core/src/infrastructure/services/agents/feature-agent/feature-agent-graph.ts"],"names":[],"mappings":"AAAA,OAAO,EAA0B,KAAK,mBAAmB,EAAE,MAAM,sBAAsB,CAAC;AACxF,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,+DAA+D,CAAC;AAOpG,OAAO,EAAmB,KAAK,aAAa,EAAE,MAAM,6BAA6B,CAAC;AAclF,OAAO,EAAE,sBAAsB,EAAE,KAAK,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAE5E;;;GAGG;AACH,MAAM,WAAW,qBAAqB;IACpC,QAAQ,EAAE,cAAc,CAAC;IACzB,aAAa,CAAC,EAAE,IAAI,CAAC,aAAa,EAAE,UAAU,CAAC,CAAC;CACjD;AAwID;;;;;;;;;;;;GAYG;AACH,wBAAgB,uBAAuB,CACrC,cAAc,EAAE,qBAAqB,GAAG,cAAc,EACtD,YAAY,CAAC,EAAE,mBAAmB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;qBAgFnC"}
|
package/dist/packages/core/src/infrastructure/services/agents/feature-agent/feature-agent-graph.js
CHANGED
|
@@ -11,7 +11,7 @@ import { createRepairNode } from './nodes/repair.node.js';
|
|
|
11
11
|
import { validateSpecAnalyze, validateSpecRequirements } from './nodes/schemas/spec.schema.js';
|
|
12
12
|
import { validateResearch } from './nodes/schemas/research.schema.js';
|
|
13
13
|
import { validatePlan, validateTasks } from './nodes/schemas/plan.schema.js';
|
|
14
|
-
import { readSpecFile, safeYamlLoad, createNodeLogger } from './nodes/node-helpers.js';
|
|
14
|
+
import { readSpecFile, safeYamlLoad, createNodeLogger, getCompletedPhases, } from './nodes/node-helpers.js';
|
|
15
15
|
// Re-export state types for consumers
|
|
16
16
|
export { FeatureAgentAnnotation } from './state.js';
|
|
17
17
|
/**
|
|
@@ -54,6 +54,18 @@ function createPlanTasksValidator() {
|
|
|
54
54
|
const log = createNodeLogger('validate:plan+tasks');
|
|
55
55
|
return async (state) => {
|
|
56
56
|
log.activate();
|
|
57
|
+
// Skip validation when the successor phase (implement) is already completed.
|
|
58
|
+
// This proves validation already passed and the pipeline progressed beyond it.
|
|
59
|
+
// Same logic as createValidateNode's successorPhase guard.
|
|
60
|
+
if (getCompletedPhases(state.specDir).includes('implement')) {
|
|
61
|
+
log.info("Successor phase 'implement' already completed, skipping validation");
|
|
62
|
+
return {
|
|
63
|
+
lastValidationTarget: 'plan.yaml+tasks.yaml',
|
|
64
|
+
lastValidationErrors: [],
|
|
65
|
+
validationRetries: 0,
|
|
66
|
+
messages: ["[validate:plan+tasks] SKIP (successor 'implement' already completed)"],
|
|
67
|
+
};
|
|
68
|
+
}
|
|
57
69
|
log.info('Validating plan.yaml and tasks.yaml');
|
|
58
70
|
const allErrors = [];
|
|
59
71
|
// Validate plan.yaml
|
|
@@ -145,9 +157,14 @@ export function createFeatureAgentGraph(depsOrExecutor, checkpointer) {
|
|
|
145
157
|
.addNode('plan', createPlanNode(executor))
|
|
146
158
|
.addNode('implement', createImplementNode(executor))
|
|
147
159
|
// --- Validate nodes ---
|
|
148
|
-
|
|
149
|
-
.
|
|
150
|
-
|
|
160
|
+
// Each validate node receives its SUCCESSOR phase name (the phase that runs
|
|
161
|
+
// after validation passes). On resume, validation is skipped only when the
|
|
162
|
+
// successor is already completed — proving this validation already passed.
|
|
163
|
+
// Using the successor (not the producer) avoids skipping validation when the
|
|
164
|
+
// producer ran successfully but validation itself failed.
|
|
165
|
+
.addNode('validate_spec_analyze', createValidateNode('spec.yaml', validateSpecAnalyze, 'requirements'))
|
|
166
|
+
.addNode('validate_spec_requirements', createValidateNode('spec.yaml', validateSpecRequirements, 'research'))
|
|
167
|
+
.addNode('validate_research', createValidateNode('research.yaml', validateResearch, 'plan'))
|
|
151
168
|
.addNode('validate_plan_tasks', createPlanTasksValidator())
|
|
152
169
|
// --- Repair nodes ---
|
|
153
170
|
.addNode('repair_spec_analyze', createRepairNode('spec.yaml', executor))
|
|
@@ -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"}
|