@prismatic-io/lux 0.0.2-preview.14 → 0.0.2-preview.16
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/lib/answerers/claude-code/index.d.ts +14 -2
- package/lib/answerers/claude-code/index.d.ts.map +1 -1
- package/lib/answerers/claude-code/index.js +3 -3
- package/lib/answerers/claude-code/index.js.map +1 -1
- package/lib/answerers/persona/index.d.ts +28 -2
- package/lib/answerers/persona/index.d.ts.map +1 -1
- package/lib/answerers/persona/index.js +3 -3
- package/lib/answerers/persona/index.js.map +1 -1
- package/lib/answerers/terminal/index.d.ts +8 -2
- package/lib/answerers/terminal/index.d.ts.map +1 -1
- package/lib/answerers/terminal/index.js +3 -2
- package/lib/answerers/terminal/index.js.map +1 -1
- package/lib/assertions/core/resource-checks.d.ts.map +1 -1
- package/lib/assertions/core/resource-checks.js +3 -5
- package/lib/assertions/core/resource-checks.js.map +1 -1
- package/lib/assertions/rubric/index.d.ts.map +1 -1
- package/lib/assertions/rubric/index.js +7 -1
- package/lib/assertions/rubric/index.js.map +1 -1
- package/lib/assertions/rubric/internal.d.ts +16 -5
- package/lib/assertions/rubric/internal.d.ts.map +1 -1
- package/lib/assertions/rubric/internal.js +10 -6
- package/lib/assertions/rubric/internal.js.map +1 -1
- package/lib/authoring.d.ts +32 -2
- package/lib/authoring.d.ts.map +1 -1
- package/lib/authoring.js +33 -1
- package/lib/authoring.js.map +1 -1
- package/lib/cli/bin.js +2 -13
- package/lib/cli/bin.js.map +1 -1
- package/lib/cli/command-runtime.d.ts +3 -3
- package/lib/cli/command-runtime.d.ts.map +1 -1
- package/lib/cli/command-runtime.js +17 -6
- package/lib/cli/command-runtime.js.map +1 -1
- package/lib/cli/init-templates.d.ts +11 -0
- package/lib/cli/init-templates.d.ts.map +1 -0
- package/lib/cli/init-templates.js +207 -0
- package/lib/cli/init-templates.js.map +1 -0
- package/lib/cli/init.d.ts +7 -0
- package/lib/cli/init.d.ts.map +1 -1
- package/lib/cli/init.js +23 -173
- package/lib/cli/init.js.map +1 -1
- package/lib/cli/output-schemas.d.ts +1399 -0
- package/lib/cli/output-schemas.d.ts.map +1 -0
- package/lib/cli/output-schemas.js +91 -0
- package/lib/cli/output-schemas.js.map +1 -0
- package/lib/cli/program.d.ts +135 -4
- package/lib/cli/program.d.ts.map +1 -1
- package/lib/cli/program.js +725 -520
- package/lib/cli/program.js.map +1 -1
- package/lib/cli/render/reporter.d.ts.map +1 -1
- package/lib/cli/render/reporter.js +24 -4
- package/lib/cli/render/reporter.js.map +1 -1
- package/lib/cli/run-options.d.ts +0 -4
- package/lib/cli/run-options.d.ts.map +1 -1
- package/lib/cli/run-options.js +8 -19
- package/lib/cli/run-options.js.map +1 -1
- package/lib/cli/view.d.ts +5 -3
- package/lib/cli/view.d.ts.map +1 -1
- package/lib/cli/view.js +120 -78
- package/lib/cli/view.js.map +1 -1
- package/lib/core/annotation.d.ts +6 -2
- package/lib/core/annotation.d.ts.map +1 -1
- package/lib/core/annotation.js +2 -1
- package/lib/core/annotation.js.map +1 -1
- package/lib/core/answerer.d.ts +12 -0
- package/lib/core/answerer.d.ts.map +1 -1
- package/lib/core/answerer.js +2 -0
- package/lib/core/answerer.js.map +1 -1
- package/lib/core/assertion.d.ts +3 -0
- package/lib/core/assertion.d.ts.map +1 -1
- package/lib/core/assertion.js +3 -0
- package/lib/core/assertion.js.map +1 -1
- package/lib/core/case.d.ts +24 -2
- package/lib/core/case.d.ts.map +1 -1
- package/lib/core/case.js +5 -1
- package/lib/core/case.js.map +1 -1
- package/lib/core/driver.d.ts +40 -0
- package/lib/core/driver.d.ts.map +1 -1
- package/lib/core/driver.js +12 -0
- package/lib/core/driver.js.map +1 -1
- package/lib/core/environment.d.ts +18 -0
- package/lib/core/environment.d.ts.map +1 -0
- package/lib/core/environment.js +21 -0
- package/lib/core/environment.js.map +1 -0
- package/lib/core/evaluation-clusters.d.ts +17 -0
- package/lib/core/evaluation-clusters.d.ts.map +1 -0
- package/lib/core/evaluation-clusters.js +23 -0
- package/lib/core/evaluation-clusters.js.map +1 -0
- package/lib/core/experiment.d.ts +11 -0
- package/lib/core/experiment.d.ts.map +1 -1
- package/lib/core/experiment.js +31 -17
- package/lib/core/experiment.js.map +1 -1
- package/lib/core/file-tree.d.ts +7 -0
- package/lib/core/file-tree.d.ts.map +1 -0
- package/lib/core/file-tree.js +35 -0
- package/lib/core/file-tree.js.map +1 -0
- package/lib/core/index.d.ts +1 -0
- package/lib/core/index.d.ts.map +1 -1
- package/lib/core/index.js +1 -0
- package/lib/core/index.js.map +1 -1
- package/lib/core/lifecycle-fixtures.d.ts.map +1 -1
- package/lib/core/lifecycle-fixtures.js +4 -2
- package/lib/core/lifecycle-fixtures.js.map +1 -1
- package/lib/core/platform-process.d.ts +5 -1
- package/lib/core/platform-process.d.ts.map +1 -1
- package/lib/core/platform-process.js +48 -10
- package/lib/core/platform-process.js.map +1 -1
- package/lib/core/run.d.ts +93 -1
- package/lib/core/run.d.ts.map +1 -1
- package/lib/core/run.js +16 -0
- package/lib/core/run.js.map +1 -1
- package/lib/core/usage.d.ts +5 -0
- package/lib/core/usage.d.ts.map +1 -1
- package/lib/core/usage.js +3 -0
- package/lib/core/usage.js.map +1 -1
- package/lib/drivers/claude-code/index.d.ts +65 -2
- package/lib/drivers/claude-code/index.d.ts.map +1 -1
- package/lib/drivers/claude-code/index.js +30 -3
- package/lib/drivers/claude-code/index.js.map +1 -1
- package/lib/drivers/codex/app-events.d.ts.map +1 -1
- package/lib/drivers/codex/app-events.js +41 -30
- package/lib/drivers/codex/app-events.js.map +1 -1
- package/lib/drivers/codex/exec-events.d.ts +4 -0
- package/lib/drivers/codex/exec-events.d.ts.map +1 -0
- package/lib/drivers/codex/exec-events.js +230 -0
- package/lib/drivers/codex/exec-events.js.map +1 -0
- package/lib/drivers/codex/index.d.ts +76 -4
- package/lib/drivers/codex/index.d.ts.map +1 -1
- package/lib/drivers/codex/index.js +35 -232
- package/lib/drivers/codex/index.js.map +1 -1
- package/lib/drivers/cursor/acp-transport.d.ts +38 -0
- package/lib/drivers/cursor/acp-transport.d.ts.map +1 -0
- package/lib/drivers/cursor/acp-transport.js +152 -0
- package/lib/drivers/cursor/acp-transport.js.map +1 -0
- package/lib/drivers/cursor/config.d.ts +22 -0
- package/lib/drivers/cursor/config.d.ts.map +1 -0
- package/lib/drivers/cursor/config.js +26 -0
- package/lib/drivers/cursor/config.js.map +1 -0
- package/lib/drivers/cursor/events.d.ts +13 -0
- package/lib/drivers/cursor/events.d.ts.map +1 -0
- package/lib/drivers/cursor/events.js +73 -0
- package/lib/drivers/cursor/events.js.map +1 -0
- package/lib/drivers/cursor/index.d.ts +37 -0
- package/lib/drivers/cursor/index.d.ts.map +1 -0
- package/lib/drivers/cursor/index.js +276 -0
- package/lib/drivers/cursor/index.js.map +1 -0
- package/lib/drivers/cursor/interaction.d.ts +7 -0
- package/lib/drivers/cursor/interaction.d.ts.map +1 -0
- package/lib/drivers/cursor/interaction.js +66 -0
- package/lib/drivers/cursor/interaction.js.map +1 -0
- package/lib/drivers/mcp/index.d.ts +35 -2
- package/lib/drivers/mcp/index.d.ts.map +1 -1
- package/lib/drivers/mcp/index.js +16 -3
- package/lib/drivers/mcp/index.js.map +1 -1
- package/lib/drivers/shared/experiment-behavior.d.ts +13 -0
- package/lib/drivers/shared/experiment-behavior.d.ts.map +1 -0
- package/lib/drivers/shared/experiment-behavior.js +197 -0
- package/lib/drivers/shared/experiment-behavior.js.map +1 -0
- package/lib/drivers/shared/experiment-policy.d.ts +4 -0
- package/lib/drivers/shared/experiment-policy.d.ts.map +1 -0
- package/lib/drivers/shared/experiment-policy.js +143 -0
- package/lib/drivers/shared/experiment-policy.js.map +1 -0
- package/lib/drivers/subprocess/index.d.ts +37 -2
- package/lib/drivers/subprocess/index.d.ts.map +1 -1
- package/lib/drivers/subprocess/index.js +46 -6
- package/lib/drivers/subprocess/index.js.map +1 -1
- package/lib/index.d.ts +6 -5
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js +4 -3
- package/lib/index.js.map +1 -1
- package/lib/orchestrator/annotation-loader.d.ts +6 -2
- package/lib/orchestrator/annotation-loader.d.ts.map +1 -1
- package/lib/orchestrator/annotation-loader.js +8 -0
- package/lib/orchestrator/annotation-loader.js.map +1 -1
- package/lib/orchestrator/annotation-store.d.ts.map +1 -1
- package/lib/orchestrator/annotation-store.js +16 -2
- package/lib/orchestrator/annotation-store.js.map +1 -1
- package/lib/orchestrator/campaign-lifecycle.d.ts +1 -0
- package/lib/orchestrator/campaign-lifecycle.d.ts.map +1 -1
- package/lib/orchestrator/campaign-lifecycle.js +4 -1
- package/lib/orchestrator/campaign-lifecycle.js.map +1 -1
- package/lib/orchestrator/compare.d.ts +4 -0
- package/lib/orchestrator/compare.d.ts.map +1 -1
- package/lib/orchestrator/compare.js +13 -1
- package/lib/orchestrator/compare.js.map +1 -1
- package/lib/orchestrator/comparison-identity.d.ts.map +1 -1
- package/lib/orchestrator/comparison-identity.js +1 -0
- package/lib/orchestrator/comparison-identity.js.map +1 -1
- package/lib/orchestrator/config.d.ts +42 -0
- package/lib/orchestrator/config.d.ts.map +1 -1
- package/lib/orchestrator/config.js +6 -2
- package/lib/orchestrator/config.js.map +1 -1
- package/lib/orchestrator/discover.d.ts +1 -0
- package/lib/orchestrator/discover.d.ts.map +1 -1
- package/lib/orchestrator/discover.js +7 -1
- package/lib/orchestrator/discover.js.map +1 -1
- package/lib/orchestrator/doctor.d.ts.map +1 -1
- package/lib/orchestrator/doctor.js +34 -26
- package/lib/orchestrator/doctor.js.map +1 -1
- package/lib/orchestrator/driver-capabilities.d.ts +3 -0
- package/lib/orchestrator/driver-capabilities.d.ts.map +1 -0
- package/lib/orchestrator/driver-capabilities.js +10 -0
- package/lib/orchestrator/driver-capabilities.js.map +1 -0
- package/lib/orchestrator/driver-identity.d.ts +5 -0
- package/lib/orchestrator/driver-identity.d.ts.map +1 -0
- package/lib/orchestrator/driver-identity.js +41 -0
- package/lib/orchestrator/driver-identity.js.map +1 -0
- package/lib/orchestrator/experiment-context.d.ts +10 -0
- package/lib/orchestrator/experiment-context.d.ts.map +1 -1
- package/lib/orchestrator/experiment-contracts.d.ts +10 -0
- package/lib/orchestrator/experiment-contracts.d.ts.map +1 -1
- package/lib/orchestrator/experiment-corpus.d.ts.map +1 -1
- package/lib/orchestrator/experiment-corpus.js +17 -19
- package/lib/orchestrator/experiment-corpus.js.map +1 -1
- package/lib/orchestrator/experiment-effects.d.ts +33 -0
- package/lib/orchestrator/experiment-effects.d.ts.map +1 -0
- package/lib/orchestrator/experiment-effects.js +44 -0
- package/lib/orchestrator/experiment-effects.js.map +1 -0
- package/lib/orchestrator/experiment-evaluation.d.ts.map +1 -1
- package/lib/orchestrator/experiment-evaluation.js +36 -3
- package/lib/orchestrator/experiment-evaluation.js.map +1 -1
- package/lib/orchestrator/experiment-identity.d.ts.map +1 -1
- package/lib/orchestrator/experiment-identity.js +18 -29
- package/lib/orchestrator/experiment-identity.js.map +1 -1
- package/lib/orchestrator/experiment-loader.d.ts +7 -2
- package/lib/orchestrator/experiment-loader.d.ts.map +1 -1
- package/lib/orchestrator/experiment-report.d.ts +70 -0
- package/lib/orchestrator/experiment-report.d.ts.map +1 -1
- package/lib/orchestrator/experiment-report.js +9 -1
- package/lib/orchestrator/experiment-report.js.map +1 -1
- package/lib/orchestrator/experiment-runs.d.ts +22 -1
- package/lib/orchestrator/experiment-runs.d.ts.map +1 -1
- package/lib/orchestrator/experiment-runs.js +13 -5
- package/lib/orchestrator/experiment-runs.js.map +1 -1
- package/lib/orchestrator/experiment-runtime-identity.d.ts +0 -16
- package/lib/orchestrator/experiment-runtime-identity.d.ts.map +1 -1
- package/lib/orchestrator/experiment-runtime-identity.js +5 -220
- package/lib/orchestrator/experiment-runtime-identity.js.map +1 -1
- package/lib/orchestrator/experiment-selection.d.ts.map +1 -1
- package/lib/orchestrator/experiment-selection.js +52 -0
- package/lib/orchestrator/experiment-selection.js.map +1 -1
- package/lib/orchestrator/experiment.d.ts +0 -2
- package/lib/orchestrator/experiment.d.ts.map +1 -1
- package/lib/orchestrator/experiment.js +23 -15
- package/lib/orchestrator/experiment.js.map +1 -1
- package/lib/orchestrator/fs-read.d.ts +1 -6
- package/lib/orchestrator/fs-read.d.ts.map +1 -1
- package/lib/orchestrator/fs-read.js +2 -32
- package/lib/orchestrator/fs-read.js.map +1 -1
- package/lib/orchestrator/grader-experiment.d.ts +17 -1
- package/lib/orchestrator/grader-experiment.d.ts.map +1 -1
- package/lib/orchestrator/grader-experiment.js +52 -7
- package/lib/orchestrator/grader-experiment.js.map +1 -1
- package/lib/orchestrator/grading.d.ts.map +1 -1
- package/lib/orchestrator/grading.js +13 -6
- package/lib/orchestrator/grading.js.map +1 -1
- package/lib/orchestrator/list-runs.d.ts +1 -0
- package/lib/orchestrator/list-runs.d.ts.map +1 -1
- package/lib/orchestrator/list-runs.js +27 -6
- package/lib/orchestrator/list-runs.js.map +1 -1
- package/lib/orchestrator/optimization-lifecycle.d.ts.map +1 -1
- package/lib/orchestrator/optimization-lifecycle.js +3 -1
- package/lib/orchestrator/optimization-lifecycle.js.map +1 -1
- package/lib/orchestrator/orchestrator.d.ts +6 -1
- package/lib/orchestrator/orchestrator.d.ts.map +1 -1
- package/lib/orchestrator/orchestrator.js +17 -143
- package/lib/orchestrator/orchestrator.js.map +1 -1
- package/lib/orchestrator/paired-effects.d.ts +34 -0
- package/lib/orchestrator/paired-effects.d.ts.map +1 -0
- package/lib/orchestrator/paired-effects.js +158 -0
- package/lib/orchestrator/paired-effects.js.map +1 -0
- package/lib/orchestrator/provenance.d.ts +5 -1
- package/lib/orchestrator/provenance.d.ts.map +1 -1
- package/lib/orchestrator/provenance.js +16 -3
- package/lib/orchestrator/provenance.js.map +1 -1
- package/lib/orchestrator/regrade.d.ts +1 -0
- package/lib/orchestrator/regrade.d.ts.map +1 -1
- package/lib/orchestrator/run-execution.d.ts +2 -0
- package/lib/orchestrator/run-execution.d.ts.map +1 -1
- package/lib/orchestrator/run-execution.js +18 -3
- package/lib/orchestrator/run-execution.js.map +1 -1
- package/lib/orchestrator/run-lifecycle.d.ts +1 -0
- package/lib/orchestrator/run-lifecycle.d.ts.map +1 -1
- package/lib/orchestrator/run-lifecycle.js +3 -2
- package/lib/orchestrator/run-lifecycle.js.map +1 -1
- package/lib/orchestrator/suite-runs.d.ts +3 -1
- package/lib/orchestrator/suite-runs.d.ts.map +1 -1
- package/lib/orchestrator/suite-runs.js +12 -2
- package/lib/orchestrator/suite-runs.js.map +1 -1
- package/lib/orchestrator/suite-summary.d.ts.map +1 -1
- package/lib/orchestrator/suite-summary.js +2 -1
- package/lib/orchestrator/suite-summary.js.map +1 -1
- package/lib/previewer/server.d.ts +6 -0
- package/lib/previewer/server.d.ts.map +1 -1
- package/lib/previewer/server.js +21 -5
- package/lib/previewer/server.js.map +1 -1
- package/package.json +2 -2
- package/skills/lux/references/cli.md +5 -2
- package/skills/lux/references/eval-authoring.md +0 -7
- package/skills/lux-answerer/SKILL.md +1 -1
- package/src/answerers/claude-code/index.ts +3 -3
- package/src/answerers/persona/index.ts +3 -3
- package/src/answerers/terminal/index.ts +4 -9
- package/src/assertions/core/resource-checks.ts +3 -5
- package/src/assertions/rubric/index.ts +7 -1
- package/src/assertions/rubric/internal.ts +13 -8
- package/src/authoring.ts +331 -2
- package/src/cli/bin.ts +2 -12
- package/src/cli/command-runtime.ts +20 -9
- package/src/cli/init-templates.ts +223 -0
- package/src/cli/init.ts +38 -184
- package/src/cli/output-schemas.ts +106 -0
- package/src/cli/program.ts +621 -548
- package/src/cli/render/reporter.ts +25 -4
- package/src/cli/run-options.ts +8 -25
- package/src/cli/view.ts +45 -84
- package/src/core/annotation.ts +2 -1
- package/src/core/answerer.ts +9 -0
- package/src/core/assertion.ts +3 -0
- package/src/core/case.ts +5 -1
- package/src/core/driver.ts +38 -0
- package/src/core/environment.ts +22 -0
- package/src/core/evaluation-clusters.ts +35 -0
- package/src/core/experiment.ts +60 -23
- package/src/core/file-tree.ts +35 -0
- package/src/core/index.ts +1 -0
- package/src/core/lifecycle-fixtures.ts +4 -2
- package/src/core/platform-process.ts +54 -6
- package/src/core/run.ts +20 -0
- package/src/core/usage.ts +8 -0
- package/src/drivers/claude-code/index.ts +34 -3
- package/src/drivers/codex/app-events.ts +43 -33
- package/src/drivers/codex/exec-events.ts +258 -0
- package/src/drivers/codex/index.ts +37 -262
- package/src/drivers/cursor/README.md +57 -0
- package/src/drivers/cursor/acp-transport.ts +182 -0
- package/src/drivers/cursor/config.ts +29 -0
- package/src/drivers/cursor/events.ts +83 -0
- package/src/drivers/cursor/index.ts +316 -0
- package/src/drivers/cursor/interaction.ts +90 -0
- package/src/drivers/mcp/index.ts +16 -3
- package/src/drivers/shared/experiment-behavior.ts +214 -0
- package/src/drivers/shared/experiment-policy.ts +195 -0
- package/src/drivers/subprocess/index.ts +45 -6
- package/src/index.ts +16 -5
- package/src/orchestrator/annotation-loader.ts +10 -0
- package/src/orchestrator/annotation-store.ts +24 -3
- package/src/orchestrator/campaign-lifecycle.ts +5 -1
- package/src/orchestrator/compare.ts +16 -1
- package/src/orchestrator/comparison-identity.ts +1 -0
- package/src/orchestrator/config.ts +6 -2
- package/src/orchestrator/discover.ts +8 -1
- package/src/orchestrator/doctor.ts +40 -22
- package/src/orchestrator/driver-capabilities.ts +16 -0
- package/src/orchestrator/driver-identity.ts +59 -0
- package/src/orchestrator/experiment-corpus.ts +23 -28
- package/src/orchestrator/experiment-effects.ts +61 -0
- package/src/orchestrator/experiment-evaluation.ts +45 -5
- package/src/orchestrator/experiment-identity.ts +27 -36
- package/src/orchestrator/experiment-report.ts +21 -1
- package/src/orchestrator/experiment-runs.ts +11 -4
- package/src/orchestrator/experiment-runtime-identity.ts +5 -243
- package/src/orchestrator/experiment-selection.ts +77 -0
- package/src/orchestrator/experiment.ts +26 -24
- package/src/orchestrator/fs-read.ts +2 -32
- package/src/orchestrator/grader-experiment.ts +72 -8
- package/src/orchestrator/grading.ts +15 -6
- package/src/orchestrator/list-runs.ts +29 -6
- package/src/orchestrator/optimization-lifecycle.ts +4 -1
- package/src/orchestrator/orchestrator.ts +26 -183
- package/src/orchestrator/paired-effects.ts +209 -0
- package/src/orchestrator/provenance.ts +23 -3
- package/src/orchestrator/run-execution.ts +18 -3
- package/src/orchestrator/run-lifecycle.ts +4 -2
- package/src/orchestrator/suite-runs.ts +10 -1
- package/src/orchestrator/suite-summary.ts +2 -1
- package/src/previewer/server.ts +27 -5
- package/viewer/app.js +27 -6
- package/viewer/detail.js +22 -5
- package/lib/answerers/scripted/index.d.ts +0 -18
- package/lib/answerers/scripted/index.d.ts.map +0 -1
- package/lib/answerers/scripted/index.js +0 -63
- package/lib/answerers/scripted/index.js.map +0 -1
- package/lib/cli/skills.d.ts +0 -38
- package/lib/cli/skills.d.ts.map +0 -1
- package/lib/cli/skills.js +0 -84
- package/lib/cli/skills.js.map +0 -1
- package/src/answerers/scripted/index.ts +0 -78
- package/src/cli/skills.ts +0 -129
|
@@ -3,23 +3,22 @@ import { homedir } from "node:os";
|
|
|
3
3
|
import { dirname, join } from "node:path";
|
|
4
4
|
import { createInterface } from "node:readline";
|
|
5
5
|
import { temporaryDirectory } from "tempy";
|
|
6
|
-
import { z } from "zod";
|
|
7
6
|
import {
|
|
8
7
|
type AgentDriver,
|
|
9
8
|
type Answer,
|
|
10
9
|
type Artifact,
|
|
11
10
|
type DriverEventMap,
|
|
12
|
-
|
|
11
|
+
defineDriver,
|
|
13
12
|
discoverCliVersion,
|
|
14
|
-
type ParsedDriverEvent,
|
|
15
13
|
type ReadyState,
|
|
16
14
|
type StartContext,
|
|
17
15
|
spawnManagedProcess,
|
|
18
16
|
type TokenUsage,
|
|
19
17
|
TypedEmitter,
|
|
20
|
-
toolResultProgress,
|
|
21
18
|
} from "../../core/index.js";
|
|
22
19
|
import { walkArtifacts } from "../shared/artifacts.js";
|
|
20
|
+
import { configuredClaudeSourceHashes } from "../shared/experiment-behavior.js";
|
|
21
|
+
import { prepareCodexExperimentConfig } from "../shared/experiment-policy.js";
|
|
23
22
|
import { copyRegularFileNoFollow } from "../shared/secure-copy.js";
|
|
24
23
|
import { subprocessDriver } from "../subprocess/index.js";
|
|
25
24
|
import {
|
|
@@ -43,264 +42,11 @@ import {
|
|
|
43
42
|
CodexDriverConfigSchema,
|
|
44
43
|
} from "./config.js";
|
|
45
44
|
|
|
45
|
+
import { makeParseEvent } from "./exec-events.js";
|
|
46
|
+
|
|
46
47
|
const LUX_BOOKKEEPING_FILES = new Set(["events.jsonl", "case.json", "run.json", "grading.json"]);
|
|
47
48
|
const commandName = (command: string): string => command.split(/[\\/]/).at(-1) ?? command;
|
|
48
49
|
|
|
49
|
-
const CodexUsageSchema = z.object({
|
|
50
|
-
input_tokens: z.number().nonnegative().catch(0),
|
|
51
|
-
cached_input_tokens: z.number().nonnegative().catch(0),
|
|
52
|
-
output_tokens: z.number().nonnegative().catch(0),
|
|
53
|
-
});
|
|
54
|
-
|
|
55
|
-
const parseUsage = (raw: unknown): TokenUsage | null => {
|
|
56
|
-
const usage = CodexUsageSchema.safeParse(raw).data;
|
|
57
|
-
if (!usage) return null;
|
|
58
|
-
return {
|
|
59
|
-
input: Math.max(0, usage.input_tokens - usage.cached_input_tokens),
|
|
60
|
-
output: usage.output_tokens,
|
|
61
|
-
cacheRead: usage.cached_input_tokens,
|
|
62
|
-
cacheCreation: 0,
|
|
63
|
-
};
|
|
64
|
-
};
|
|
65
|
-
|
|
66
|
-
const resultText = (content: unknown): string => {
|
|
67
|
-
if (typeof content === "string") return content;
|
|
68
|
-
if (!Array.isArray(content)) return "";
|
|
69
|
-
return content
|
|
70
|
-
.filter(
|
|
71
|
-
(block): block is { type: "text"; text: string } =>
|
|
72
|
-
typeof block === "object" &&
|
|
73
|
-
block !== null &&
|
|
74
|
-
(block as { type?: unknown }).type === "text" &&
|
|
75
|
-
typeof (block as { text?: unknown }).text === "string",
|
|
76
|
-
)
|
|
77
|
-
.map((block) => block.text)
|
|
78
|
-
.join("\n");
|
|
79
|
-
};
|
|
80
|
-
|
|
81
|
-
const startedItemProgress = (
|
|
82
|
-
item: Record<string, unknown>,
|
|
83
|
-
id: string,
|
|
84
|
-
): ParsedDriverEvent | null => {
|
|
85
|
-
if (item.type === "command_execution") {
|
|
86
|
-
return {
|
|
87
|
-
tag: "progress",
|
|
88
|
-
progress: {
|
|
89
|
-
id: `tc-${id}`,
|
|
90
|
-
kind: "tool-call",
|
|
91
|
-
payload: { name: "command_execution", input: { command: item.command }, toolUseId: id },
|
|
92
|
-
ts: Date.now(),
|
|
93
|
-
},
|
|
94
|
-
};
|
|
95
|
-
}
|
|
96
|
-
if (item.type === "mcp_tool_call") {
|
|
97
|
-
const tool = typeof item.tool === "string" ? item.tool : String(item.name ?? "mcp_tool_call");
|
|
98
|
-
const server = typeof item.server === "string" ? item.server : undefined;
|
|
99
|
-
return {
|
|
100
|
-
tag: "progress",
|
|
101
|
-
progress: {
|
|
102
|
-
id: `tc-${id}`,
|
|
103
|
-
kind: "tool-call",
|
|
104
|
-
payload: {
|
|
105
|
-
name: tool,
|
|
106
|
-
input: item.arguments ?? item.input,
|
|
107
|
-
toolUseId: id,
|
|
108
|
-
...(server ? { server } : {}),
|
|
109
|
-
},
|
|
110
|
-
ts: Date.now(),
|
|
111
|
-
},
|
|
112
|
-
};
|
|
113
|
-
}
|
|
114
|
-
if (item.type === "web_search") {
|
|
115
|
-
return {
|
|
116
|
-
tag: "progress",
|
|
117
|
-
progress: {
|
|
118
|
-
id: `tc-${id}`,
|
|
119
|
-
kind: "tool-call",
|
|
120
|
-
payload: { name: "web_search", input: { query: item.query }, toolUseId: id },
|
|
121
|
-
ts: Date.now(),
|
|
122
|
-
},
|
|
123
|
-
};
|
|
124
|
-
}
|
|
125
|
-
if (item.type === "file_change") {
|
|
126
|
-
return {
|
|
127
|
-
tag: "progress",
|
|
128
|
-
progress: {
|
|
129
|
-
id: `tc-${id}`,
|
|
130
|
-
kind: "tool-call",
|
|
131
|
-
payload: { name: "file_change", input: { changes: item.changes }, toolUseId: id },
|
|
132
|
-
ts: Date.now(),
|
|
133
|
-
},
|
|
134
|
-
};
|
|
135
|
-
}
|
|
136
|
-
return null;
|
|
137
|
-
};
|
|
138
|
-
|
|
139
|
-
const completedItemProgress = (
|
|
140
|
-
item: Record<string, unknown>,
|
|
141
|
-
id: string,
|
|
142
|
-
): ParsedDriverEvent | null => {
|
|
143
|
-
if (item.type === "agent_message" && typeof item.text === "string") {
|
|
144
|
-
return {
|
|
145
|
-
tag: "progress",
|
|
146
|
-
progress: {
|
|
147
|
-
id: `am-${id}`,
|
|
148
|
-
kind: "agent-message",
|
|
149
|
-
payload: { text: item.text },
|
|
150
|
-
ts: Date.now(),
|
|
151
|
-
},
|
|
152
|
-
};
|
|
153
|
-
}
|
|
154
|
-
if (item.type === "reasoning") {
|
|
155
|
-
const text = typeof item.text === "string" ? item.text : item.summary;
|
|
156
|
-
return {
|
|
157
|
-
tag: "progress",
|
|
158
|
-
progress: { id: `reasoning-${id}`, kind: "reasoning", payload: { text }, ts: Date.now() },
|
|
159
|
-
};
|
|
160
|
-
}
|
|
161
|
-
if (item.type === "mcp_tool_call") {
|
|
162
|
-
const tool = typeof item.tool === "string" ? item.tool : String(item.name ?? "mcp_tool_call");
|
|
163
|
-
const raw =
|
|
164
|
-
item.result && typeof item.result === "object"
|
|
165
|
-
? (item.result as Record<string, unknown>)
|
|
166
|
-
: item;
|
|
167
|
-
const content = raw.content ?? item.result ?? [];
|
|
168
|
-
const structuredContent = raw.structuredContent ?? raw.structured_content;
|
|
169
|
-
return {
|
|
170
|
-
tag: "progress",
|
|
171
|
-
progress: toolResultProgress(
|
|
172
|
-
0,
|
|
173
|
-
{
|
|
174
|
-
name: tool,
|
|
175
|
-
toolUseId: id,
|
|
176
|
-
content,
|
|
177
|
-
...(structuredContent && typeof structuredContent === "object"
|
|
178
|
-
? { structuredContent: structuredContent as Record<string, unknown> }
|
|
179
|
-
: {}),
|
|
180
|
-
isError:
|
|
181
|
-
raw.isError === true ||
|
|
182
|
-
raw.is_error === true ||
|
|
183
|
-
item.status === "failed" ||
|
|
184
|
-
(item.error !== undefined && item.error !== null),
|
|
185
|
-
text: resultText(content) || (typeof item.error === "string" ? item.error : ""),
|
|
186
|
-
},
|
|
187
|
-
Date.now(),
|
|
188
|
-
),
|
|
189
|
-
};
|
|
190
|
-
}
|
|
191
|
-
if (item.type === "command_execution") {
|
|
192
|
-
const output = item.aggregated_output ?? item.output ?? "";
|
|
193
|
-
const exitCode = typeof item.exit_code === "number" ? item.exit_code : undefined;
|
|
194
|
-
return {
|
|
195
|
-
tag: "progress",
|
|
196
|
-
progress: toolResultProgress(
|
|
197
|
-
0,
|
|
198
|
-
{
|
|
199
|
-
name: "command_execution",
|
|
200
|
-
toolUseId: id,
|
|
201
|
-
content: { output, ...(exitCode !== undefined ? { exitCode } : {}) },
|
|
202
|
-
isError: item.status === "failed" || (exitCode !== undefined && exitCode !== 0),
|
|
203
|
-
text: typeof output === "string" ? output : JSON.stringify(output),
|
|
204
|
-
},
|
|
205
|
-
Date.now(),
|
|
206
|
-
),
|
|
207
|
-
};
|
|
208
|
-
}
|
|
209
|
-
if (item.type === "web_search" || item.type === "file_change") {
|
|
210
|
-
const isWebSearch = item.type === "web_search";
|
|
211
|
-
const content = isWebSearch
|
|
212
|
-
? { query: item.query }
|
|
213
|
-
: { changes: item.changes, status: item.status };
|
|
214
|
-
let text = JSON.stringify(item.changes ?? []);
|
|
215
|
-
if (isWebSearch) text = typeof item.query === "string" ? item.query : "";
|
|
216
|
-
return {
|
|
217
|
-
tag: "progress",
|
|
218
|
-
progress: toolResultProgress(
|
|
219
|
-
0,
|
|
220
|
-
{
|
|
221
|
-
name: item.type,
|
|
222
|
-
toolUseId: id,
|
|
223
|
-
content,
|
|
224
|
-
isError: item.status === "failed",
|
|
225
|
-
text,
|
|
226
|
-
},
|
|
227
|
-
Date.now(),
|
|
228
|
-
),
|
|
229
|
-
};
|
|
230
|
-
}
|
|
231
|
-
return null;
|
|
232
|
-
};
|
|
233
|
-
|
|
234
|
-
const itemProgress = (
|
|
235
|
-
item: Record<string, unknown>,
|
|
236
|
-
phase: "started" | "completed",
|
|
237
|
-
): ParsedDriverEvent | null => {
|
|
238
|
-
const id = typeof item.id === "string" ? item.id : `${String(item.type)}-${Date.now()}`;
|
|
239
|
-
return phase === "started" ? startedItemProgress(item, id) : completedItemProgress(item, id);
|
|
240
|
-
};
|
|
241
|
-
|
|
242
|
-
const makeParseEvent = (config: CodexDriverConfig, cliVersion?: string) => {
|
|
243
|
-
let threadId: string | undefined;
|
|
244
|
-
return (line: string): ParsedDriverEvent | ParsedDriverEvent[] | null => {
|
|
245
|
-
let event: Record<string, unknown>;
|
|
246
|
-
try {
|
|
247
|
-
event = JSON.parse(line) as Record<string, unknown>;
|
|
248
|
-
} catch {
|
|
249
|
-
return null;
|
|
250
|
-
}
|
|
251
|
-
if (event.type === "thread.started") {
|
|
252
|
-
threadId = typeof event.thread_id === "string" ? event.thread_id : undefined;
|
|
253
|
-
return {
|
|
254
|
-
tag: "ready",
|
|
255
|
-
ready: {
|
|
256
|
-
agentId: "codex",
|
|
257
|
-
model: config.model,
|
|
258
|
-
detail: { ...(threadId ? { threadId } : {}), ...(cliVersion ? { cliVersion } : {}) },
|
|
259
|
-
},
|
|
260
|
-
};
|
|
261
|
-
}
|
|
262
|
-
if (event.type === "item.started" || event.type === "item.completed") {
|
|
263
|
-
if (!event.item || typeof event.item !== "object") return null;
|
|
264
|
-
return itemProgress(
|
|
265
|
-
event.item as Record<string, unknown>,
|
|
266
|
-
event.type === "item.started" ? "started" : "completed",
|
|
267
|
-
);
|
|
268
|
-
}
|
|
269
|
-
if (event.type === "turn.completed") {
|
|
270
|
-
const usage = parseUsage(event.usage);
|
|
271
|
-
const events: ParsedDriverEvent[] = [];
|
|
272
|
-
if (usage) {
|
|
273
|
-
events.push({
|
|
274
|
-
tag: "progress",
|
|
275
|
-
progress: {
|
|
276
|
-
id: `usage-${threadId ?? Date.now()}`,
|
|
277
|
-
kind: "usage",
|
|
278
|
-
payload: usage,
|
|
279
|
-
ts: Date.now(),
|
|
280
|
-
},
|
|
281
|
-
});
|
|
282
|
-
}
|
|
283
|
-
events.push({
|
|
284
|
-
tag: "done",
|
|
285
|
-
done: { exitReason: "done", summary: { threadId, ...(usage ? { usage } : {}) } },
|
|
286
|
-
});
|
|
287
|
-
return events;
|
|
288
|
-
}
|
|
289
|
-
if (event.type === "turn.failed" || event.type === "error") {
|
|
290
|
-
const nestedMessage =
|
|
291
|
-
event.error && typeof event.error === "object"
|
|
292
|
-
? (event.error as Record<string, unknown>).message
|
|
293
|
-
: undefined;
|
|
294
|
-
let message = "codex reported an error";
|
|
295
|
-
if (typeof event.message === "string") message = event.message;
|
|
296
|
-
else if (typeof event.error === "string") message = event.error;
|
|
297
|
-
else if (typeof nestedMessage === "string") message = nestedMessage;
|
|
298
|
-
return { tag: "error", error: { exitReason: "error", reason: message } };
|
|
299
|
-
}
|
|
300
|
-
return null;
|
|
301
|
-
};
|
|
302
|
-
};
|
|
303
|
-
|
|
304
50
|
class CodexAppServerDriverImpl implements AgentDriver {
|
|
305
51
|
private readonly emitter = new TypedEmitter<DriverEventMap>();
|
|
306
52
|
private readonly config: CodexDriverConfig;
|
|
@@ -661,6 +407,7 @@ class CodexAppServerDriverImpl implements AgentDriver {
|
|
|
661
407
|
}
|
|
662
408
|
|
|
663
409
|
private async dispatch(message: RpcRecord): Promise<void> {
|
|
410
|
+
if (this.terminal) return;
|
|
664
411
|
const method = typeof message.method === "string" ? message.method : "";
|
|
665
412
|
const params = asRecord(message.params) ?? {};
|
|
666
413
|
if (message.id !== undefined && method) {
|
|
@@ -671,6 +418,14 @@ class CodexAppServerDriverImpl implements AgentDriver {
|
|
|
671
418
|
await this.handleItemNotification(method, params);
|
|
672
419
|
return;
|
|
673
420
|
}
|
|
421
|
+
if (
|
|
422
|
+
(method === "thread/tokenUsage/updated" ||
|
|
423
|
+
method === "turn/completed" ||
|
|
424
|
+
method === "error") &&
|
|
425
|
+
typeof params.threadId === "string" &&
|
|
426
|
+
params.threadId !== this.threadId
|
|
427
|
+
)
|
|
428
|
+
return;
|
|
674
429
|
if (method === "thread/tokenUsage/updated") {
|
|
675
430
|
this.handleTokenUsageNotification(params);
|
|
676
431
|
return;
|
|
@@ -725,7 +480,7 @@ class CodexAppServerDriverImpl implements AgentDriver {
|
|
|
725
480
|
|
|
726
481
|
private handleTokenUsageNotification(params: RpcRecord): void {
|
|
727
482
|
const tokenUsage = asRecord(params.tokenUsage);
|
|
728
|
-
const usage = appUsage(tokenUsage?.last);
|
|
483
|
+
const usage = appUsage(tokenUsage?.total) ?? appUsage(tokenUsage?.last);
|
|
729
484
|
if (usage) this.latestUsage = usage;
|
|
730
485
|
}
|
|
731
486
|
|
|
@@ -777,6 +532,7 @@ class CodexAppServerDriverImpl implements AgentDriver {
|
|
|
777
532
|
}
|
|
778
533
|
|
|
779
534
|
private handleErrorNotification(params: RpcRecord): void {
|
|
535
|
+
if (params.willRetry === true) return;
|
|
780
536
|
const error = asRecord(params.error);
|
|
781
537
|
let errorMessage = "codex app-server reported an error";
|
|
782
538
|
if (typeof params.message === "string") errorMessage = params.message;
|
|
@@ -984,14 +740,33 @@ class CodexExecDriverImpl implements AgentDriver {
|
|
|
984
740
|
}
|
|
985
741
|
}
|
|
986
742
|
|
|
987
|
-
export const codexDriver
|
|
743
|
+
export const codexDriver = defineDriver({
|
|
988
744
|
name: "codex",
|
|
989
745
|
configSchema: CodexDriverConfigSchema,
|
|
746
|
+
runtime: (config) => ({
|
|
747
|
+
commands: [config.command],
|
|
748
|
+
capabilities: {
|
|
749
|
+
interactive: config.interactionMode === "app-server",
|
|
750
|
+
"tool-calls": true,
|
|
751
|
+
"tool-results": true,
|
|
752
|
+
artifacts: true,
|
|
753
|
+
subagents: config.interactionMode === "app-server",
|
|
754
|
+
usage: true,
|
|
755
|
+
cost: false,
|
|
756
|
+
isolation: Boolean(config.isolation),
|
|
757
|
+
},
|
|
758
|
+
}),
|
|
759
|
+
experiment: {
|
|
760
|
+
version: "1",
|
|
761
|
+
prepare: prepareCodexExperimentConfig,
|
|
762
|
+
identity: (config, { rootDir }) =>
|
|
763
|
+
configuredClaudeSourceHashes({ name: "codex", config }, rootDir),
|
|
764
|
+
},
|
|
990
765
|
create: (config) =>
|
|
991
766
|
config.interactionMode === "app-server"
|
|
992
767
|
? new CodexAppServerDriverImpl(config)
|
|
993
768
|
: new CodexExecDriverImpl(config),
|
|
994
|
-
};
|
|
769
|
+
});
|
|
995
770
|
|
|
996
771
|
export type { CodexDriverConfig };
|
|
997
772
|
export { appItemProgress, buildAppServerArgs, buildArgs, CodexDriverConfigSchema, makeParseEvent };
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
# Cursor driver
|
|
2
|
+
|
|
3
|
+
The `cursor` driver uses Cursor CLI's ACP transport. Install Cursor CLI and
|
|
4
|
+
authenticate it before running Lux. The executable is normally named `agent`;
|
|
5
|
+
set `command` to its absolute path if another application owns that name.
|
|
6
|
+
|
|
7
|
+
```ts
|
|
8
|
+
{
|
|
9
|
+
name: "cursor",
|
|
10
|
+
config: {
|
|
11
|
+
command: "/absolute/path/to/cursor/agent",
|
|
12
|
+
model: "YOUR_CURSOR_MODEL_ID",
|
|
13
|
+
// Optional: only accepted when ACP advertises this effort value.
|
|
14
|
+
// reasoningEffort: "low",
|
|
15
|
+
},
|
|
16
|
+
}
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
`model` is required. Use an explicit model ID from your installed Cursor CLI;
|
|
20
|
+
some IDs encode reasoning effort. Lux passes that ID through `--model` and
|
|
21
|
+
rejects a different model when the session reports one. If `reasoningEffort` is
|
|
22
|
+
supplied, Lux requires a matching advertised ACP thought-level selector and
|
|
23
|
+
checks the response confirms the requested value before sending the prompt.
|
|
24
|
+
|
|
25
|
+
Supported interactions are Cursor's native multiple-choice questions, plan
|
|
26
|
+
approval, and ACP tool permissions. Lux grants one-operation permissions only;
|
|
27
|
+
it never converts an approval into a remembered permission. Multi-question
|
|
28
|
+
answers use a JSON mapping from question IDs to option IDs, with arrays for
|
|
29
|
+
multiple selections. The generated question prompt explains this format.
|
|
30
|
+
|
|
31
|
+
The driver normalizes streamed text, reasoning and tool calls/results. Other
|
|
32
|
+
session updates and Cursor notifications remain available as `cursor-update`
|
|
33
|
+
and `cursor-event` progress. Tool names use ACP's supplied title; assertions
|
|
34
|
+
based on tool names may therefore need harness-specific selectors.
|
|
35
|
+
|
|
36
|
+
The default working directory is the run's staged artifacts directory. `cwd`
|
|
37
|
+
can select another existing workspace. Neither setting provides a security
|
|
38
|
+
sandbox or ambient-configuration isolation. Cursor can inherit its user and
|
|
39
|
+
project rules, hooks, MCP servers, credentials and persisted state. The driver
|
|
40
|
+
does not claim controlled-experiment support or complete usage/cost accounting;
|
|
41
|
+
usage availability is recorded as unknown, not a zero-token observation.
|
|
42
|
+
|
|
43
|
+
Startup RPCs, idle periods, protocol lines, queued events and retained tool state
|
|
44
|
+
are bounded. On close, Lux attempts ACP cancellation, then terminates the
|
|
45
|
+
managed process tree before collecting artifacts. Aborting a run also terminates
|
|
46
|
+
the managed tree. Unsupported client filesystem/terminal operations are not
|
|
47
|
+
advertised and unsupported requests receive a JSON-RPC error.
|
|
48
|
+
|
|
49
|
+
The adapter is covered by synthetic protocol and lifecycle tests. Its initial
|
|
50
|
+
implementation has not been validated against an authenticated Cursor session.
|
|
51
|
+
|
|
52
|
+
Protocol references:
|
|
53
|
+
|
|
54
|
+
- [Cursor ACP](https://cursor.com/docs/cli/acp)
|
|
55
|
+
- [Cursor CLI parameters](https://cursor.com/docs/cli/reference/parameters)
|
|
56
|
+
- [ACP configuration options](https://agentclientprotocol.com/protocol/session-config-options)
|
|
57
|
+
- [ACP tool calls and permissions](https://agentclientprotocol.com/protocol/tool-calls)
|
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
import { type ManagedProcess, spawnManagedProcess } from "../../core/index.js";
|
|
2
|
+
|
|
3
|
+
export type RpcRecord = Record<string, unknown>;
|
|
4
|
+
export type RpcId = number | string;
|
|
5
|
+
export const asRecord = (value: unknown): RpcRecord | undefined =>
|
|
6
|
+
value !== null && typeof value === "object" && !Array.isArray(value)
|
|
7
|
+
? (value as RpcRecord)
|
|
8
|
+
: undefined;
|
|
9
|
+
|
|
10
|
+
type TransportOptions = {
|
|
11
|
+
command: string;
|
|
12
|
+
args: string[];
|
|
13
|
+
cwd: string;
|
|
14
|
+
env?: NodeJS.ProcessEnv;
|
|
15
|
+
signal: AbortSignal;
|
|
16
|
+
maxLineBytes: number;
|
|
17
|
+
maxQueuedBytes: number;
|
|
18
|
+
onMessage: (message: RpcRecord) => Promise<void>;
|
|
19
|
+
onFailure: (error: Error) => void;
|
|
20
|
+
onActivity: () => void;
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
export class AcpTransport {
|
|
24
|
+
private readonly process: ManagedProcess;
|
|
25
|
+
private readonly pending = new Map<
|
|
26
|
+
RpcId,
|
|
27
|
+
{
|
|
28
|
+
resolve: (result: RpcRecord) => void;
|
|
29
|
+
reject: (error: Error) => void;
|
|
30
|
+
timer: NodeJS.Timeout | undefined;
|
|
31
|
+
}
|
|
32
|
+
>();
|
|
33
|
+
private nextId = 1;
|
|
34
|
+
private buffer = Buffer.alloc(0);
|
|
35
|
+
private queuedBytes = 0;
|
|
36
|
+
private chain: Promise<void> = Promise.resolve();
|
|
37
|
+
private stopped = false;
|
|
38
|
+
private stderrTail = "";
|
|
39
|
+
|
|
40
|
+
private readonly options: TransportOptions;
|
|
41
|
+
|
|
42
|
+
constructor(options: TransportOptions) {
|
|
43
|
+
this.options = options;
|
|
44
|
+
this.process = spawnManagedProcess(options.command, options.args, {
|
|
45
|
+
cwd: options.cwd,
|
|
46
|
+
...(options.env ? { env: options.env } : {}),
|
|
47
|
+
signal: options.signal,
|
|
48
|
+
});
|
|
49
|
+
this.process.child.stdout.on("data", (chunk: Buffer) => this.read(chunk));
|
|
50
|
+
this.process.child.stderr.setEncoding("utf8");
|
|
51
|
+
this.process.child.stderr.on("data", (chunk: string) => {
|
|
52
|
+
this.stderrTail = (this.stderrTail + chunk).slice(-8_192);
|
|
53
|
+
});
|
|
54
|
+
void this.process.exited.then(({ exitCode, signal }) => {
|
|
55
|
+
if (!this.stopped)
|
|
56
|
+
this.fail(
|
|
57
|
+
new Error(
|
|
58
|
+
`Cursor ACP exited before completion (code=${exitCode}, signal=${signal})${this.stderrTail ? `: ${this.stderrTail}` : ""}`,
|
|
59
|
+
),
|
|
60
|
+
);
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
async spawned(): Promise<void> {
|
|
65
|
+
await this.process.spawned;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
request(method: string, params: RpcRecord, timeoutMs?: number): Promise<RpcRecord> {
|
|
69
|
+
if (this.stopped) return Promise.reject(new Error("Cursor ACP is closed"));
|
|
70
|
+
const id = this.nextId++;
|
|
71
|
+
return new Promise((resolve, reject) => {
|
|
72
|
+
const timer =
|
|
73
|
+
timeoutMs === undefined
|
|
74
|
+
? undefined
|
|
75
|
+
: setTimeout(() => {
|
|
76
|
+
this.fail(new Error(`Cursor ACP ${method} timed out after ${timeoutMs}ms`));
|
|
77
|
+
}, timeoutMs);
|
|
78
|
+
this.pending.set(id, { resolve, reject, timer });
|
|
79
|
+
try {
|
|
80
|
+
this.write({ id, method, params });
|
|
81
|
+
} catch (error) {
|
|
82
|
+
this.fail(error instanceof Error ? error : new Error(String(error)));
|
|
83
|
+
}
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
write(message: RpcRecord): void {
|
|
88
|
+
if (this.stopped) throw new Error("Cursor ACP is closed");
|
|
89
|
+
const line = `${JSON.stringify({ jsonrpc: "2.0", ...message })}\n`;
|
|
90
|
+
if (Buffer.byteLength(line) > this.options.maxLineBytes)
|
|
91
|
+
throw new Error("Cursor ACP outgoing message exceeded maxLineBytes");
|
|
92
|
+
this.process.child.stdin.write(line);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
async drained(): Promise<void> {
|
|
96
|
+
await this.chain;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
async close(): Promise<void> {
|
|
100
|
+
this.stopped = true;
|
|
101
|
+
this.rejectPending(new Error("Cursor ACP is closed"));
|
|
102
|
+
this.buffer = Buffer.alloc(0);
|
|
103
|
+
await this.process.terminate();
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
private rejectPending(error: Error): void {
|
|
107
|
+
for (const pending of this.pending.values()) {
|
|
108
|
+
clearTimeout(pending.timer);
|
|
109
|
+
pending.reject(error);
|
|
110
|
+
}
|
|
111
|
+
this.pending.clear();
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
private fail(error: Error): void {
|
|
115
|
+
if (this.stopped) return;
|
|
116
|
+
this.stopped = true;
|
|
117
|
+
this.rejectPending(error);
|
|
118
|
+
this.options.onFailure(error);
|
|
119
|
+
void this.process.terminate();
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
private read(chunk: Buffer): void {
|
|
123
|
+
let offset = 0;
|
|
124
|
+
while (offset < chunk.length && !this.stopped) {
|
|
125
|
+
const newline = chunk.indexOf(0x0a, offset);
|
|
126
|
+
const end = newline === -1 ? chunk.length : newline;
|
|
127
|
+
const segment = chunk.subarray(offset, end);
|
|
128
|
+
if (this.buffer.length + segment.length > this.options.maxLineBytes) {
|
|
129
|
+
this.fail(new Error("Cursor ACP stdout line exceeded maxLineBytes"));
|
|
130
|
+
return;
|
|
131
|
+
}
|
|
132
|
+
this.buffer = Buffer.concat([this.buffer, segment]);
|
|
133
|
+
if (newline === -1) return;
|
|
134
|
+
const line = this.buffer;
|
|
135
|
+
this.buffer = Buffer.alloc(0);
|
|
136
|
+
this.line(line);
|
|
137
|
+
offset = newline + 1;
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
private line(line: Buffer): void {
|
|
142
|
+
if (!line.toString("utf8").trim()) return;
|
|
143
|
+
let message: RpcRecord | undefined;
|
|
144
|
+
try {
|
|
145
|
+
message = asRecord(JSON.parse(line.toString("utf8")));
|
|
146
|
+
} catch {
|
|
147
|
+
/* Rejected below. */
|
|
148
|
+
}
|
|
149
|
+
if (message?.jsonrpc !== "2.0") {
|
|
150
|
+
this.fail(new Error("Cursor ACP returned an invalid JSON-RPC message"));
|
|
151
|
+
return;
|
|
152
|
+
}
|
|
153
|
+
this.options.onActivity();
|
|
154
|
+
if (message.method === undefined) {
|
|
155
|
+
const pending = this.pending.get(message.id as RpcId);
|
|
156
|
+
if (!pending) return;
|
|
157
|
+
this.pending.delete(message.id as RpcId);
|
|
158
|
+
clearTimeout(pending.timer);
|
|
159
|
+
const error = asRecord(message.error);
|
|
160
|
+
if (error) pending.reject(new Error(String(error.message ?? "Cursor ACP request failed")));
|
|
161
|
+
else pending.resolve(asRecord(message.result) ?? {});
|
|
162
|
+
return;
|
|
163
|
+
}
|
|
164
|
+
this.queuedBytes += line.length;
|
|
165
|
+
if (this.queuedBytes > this.options.maxQueuedBytes) {
|
|
166
|
+
this.fail(new Error("Cursor ACP pending events exceeded maxQueuedBytes"));
|
|
167
|
+
return;
|
|
168
|
+
}
|
|
169
|
+
const queued = message;
|
|
170
|
+
this.chain = this.chain
|
|
171
|
+
.then(async () => {
|
|
172
|
+
try {
|
|
173
|
+
if (!this.stopped) await this.options.onMessage(queued);
|
|
174
|
+
} finally {
|
|
175
|
+
this.queuedBytes -= line.length;
|
|
176
|
+
}
|
|
177
|
+
})
|
|
178
|
+
.catch((error: unknown) =>
|
|
179
|
+
this.fail(error instanceof Error ? error : new Error(String(error))),
|
|
180
|
+
);
|
|
181
|
+
}
|
|
182
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
|
|
3
|
+
export const CursorDriverConfigSchema = z
|
|
4
|
+
.object({
|
|
5
|
+
command: z.string().min(1).default("agent"),
|
|
6
|
+
/** Cursor model IDs may include an effort suffix; never inherit Auto. */
|
|
7
|
+
model: z.string().min(1),
|
|
8
|
+
/** Applied only through an advertised ACP thought-level selector. */
|
|
9
|
+
reasoningEffort: z.string().min(1).optional(),
|
|
10
|
+
mode: z.enum(["agent", "plan", "ask"]).default("agent"),
|
|
11
|
+
cwd: z.string().optional(),
|
|
12
|
+
env: z.record(z.string(), z.string()).optional(),
|
|
13
|
+
startupTimeoutMs: z.number().int().positive().default(30_000),
|
|
14
|
+
idleTimeoutMs: z.number().int().positive().default(600_000),
|
|
15
|
+
maxInterrupts: z.number().int().positive().default(20),
|
|
16
|
+
maxLineBytes: z.number().int().positive().default(10_000_000),
|
|
17
|
+
maxQueuedBytes: z.number().int().positive().default(20_000_000),
|
|
18
|
+
maxToolCalls: z.number().int().positive().default(10_000),
|
|
19
|
+
})
|
|
20
|
+
.strict();
|
|
21
|
+
|
|
22
|
+
export type CursorDriverConfig = z.infer<typeof CursorDriverConfigSchema>;
|
|
23
|
+
|
|
24
|
+
export const buildCursorArgs = (config: CursorDriverConfig): string[] => [
|
|
25
|
+
"--model",
|
|
26
|
+
config.model,
|
|
27
|
+
...(config.mode === "agent" ? [] : ["--mode", config.mode]),
|
|
28
|
+
"acp",
|
|
29
|
+
];
|