@backburner/cli 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +329 -0
- package/dist/src/agents/antigravity-launch.js +162 -0
- package/dist/src/agents/antigravity.js +251 -0
- package/dist/src/agents/claude-launch.js +117 -0
- package/dist/src/agents/claude.js +271 -0
- package/dist/src/agents/codex-launch.js +82 -0
- package/dist/src/agents/codex.js +261 -0
- package/dist/src/agents/composite-runner.js +13 -0
- package/dist/src/agents/extraction.js +442 -0
- package/dist/src/agents/failure-feedback.js +132 -0
- package/dist/src/agents/gemini-launch.js +96 -0
- package/dist/src/agents/gemini.js +392 -0
- package/dist/src/agents/job-agent-assignments.js +180 -0
- package/dist/src/agents/lifecycle-feedback.js +147 -0
- package/dist/src/agents/limit-detector.js +83 -0
- package/dist/src/agents/opencode-launch.js +138 -0
- package/dist/src/agents/opencode.js +156 -0
- package/dist/src/agents/plan-breakdown-feedback.js +97 -0
- package/dist/src/agents/pool.js +168 -0
- package/dist/src/agents/prompt.js +462 -0
- package/dist/src/agents/provider-sessions.js +105 -0
- package/dist/src/agents/review-feedback.js +255 -0
- package/dist/src/agents/selection.js +113 -0
- package/dist/src/agents/service.js +1087 -0
- package/dist/src/agents/types.js +1 -0
- package/dist/src/agents/wave-assessment-feedback.js +69 -0
- package/dist/src/attention/derive.js +337 -0
- package/dist/src/capabilities/index.js +2 -0
- package/dist/src/capabilities/projection.js +183 -0
- package/dist/src/capabilities/types.js +1 -0
- package/dist/src/capabilities/validator.js +87 -0
- package/dist/src/cli/commands/broker-smoke.js +96 -0
- package/dist/src/cli/commands/broker.js +56 -0
- package/dist/src/cli/commands/init.js +4 -0
- package/dist/src/cli/commands/journal.js +43 -0
- package/dist/src/cli/commands/run-loop.js +56 -0
- package/dist/src/cli/commands/run.js +1241 -0
- package/dist/src/cli/commands/tui.js +187 -0
- package/dist/src/cli/dispatcher.js +51 -0
- package/dist/src/cli/errors.js +2 -0
- package/dist/src/cli/init.js +92 -0
- package/dist/src/cli/options.js +86 -0
- package/dist/src/cli/output.js +231 -0
- package/dist/src/cli/run-journal.js +342 -0
- package/dist/src/cli/run-types.js +1 -0
- package/dist/src/cli/run.js +32 -0
- package/dist/src/cli/runtime/dispatch-lifecycle.js +772 -0
- package/dist/src/cli/runtime/provider-runtime-types.js +1 -0
- package/dist/src/cli/runtime/provider-runtime.js +152 -0
- package/dist/src/cli/runtime/provider-tools.js +73 -0
- package/dist/src/cli/runtime/providers/antigravity.js +26 -0
- package/dist/src/cli/runtime/providers/claude.js +20 -0
- package/dist/src/cli/runtime/providers/codex.js +20 -0
- package/dist/src/cli/runtime/providers/gemini.js +20 -0
- package/dist/src/cli/runtime/providers/opencode.js +20 -0
- package/dist/src/cli/runtime/run-context.js +131 -0
- package/dist/src/cli/tui/index.js +3 -0
- package/dist/src/cli/tui/screen.js +388 -0
- package/dist/src/cli/tui/tracker.js +558 -0
- package/dist/src/cli/tui/types.js +1 -0
- package/dist/src/cli/tui/views.js +1006 -0
- package/dist/src/config/loader.js +136 -0
- package/dist/src/config/schemas.js +403 -0
- package/dist/src/config/types.js +1 -0
- package/dist/src/context/types.js +331 -0
- package/dist/src/domain/entities.js +1 -0
- package/dist/src/git/backburner-git-tool-service.js +680 -0
- package/dist/src/git/gitops-lifecycle.js +56 -0
- package/dist/src/git/merge-prep-workspace.js +357 -0
- package/dist/src/git/types.js +484 -0
- package/dist/src/github/broker-model-content.js +215 -0
- package/dist/src/github/broker-server.js +237 -0
- package/dist/src/github/broker.js +638 -0
- package/dist/src/github/composed.js +53 -0
- package/dist/src/github/gateway.js +478 -0
- package/dist/src/github/normalize.js +222 -0
- package/dist/src/github/pr-classification.js +73 -0
- package/dist/src/github/scoped-broker.js +35 -0
- package/dist/src/github/security.js +126 -0
- package/dist/src/github/service.js +332 -0
- package/dist/src/github/types.js +1 -0
- package/dist/src/github/utils.js +16 -0
- package/dist/src/journal/index.js +4 -0
- package/dist/src/journal/reader.js +62 -0
- package/dist/src/journal/renderer.js +50 -0
- package/dist/src/journal/service.js +72 -0
- package/dist/src/journal/types.js +1 -0
- package/dist/src/journal/writer.js +19 -0
- package/dist/src/mcps/bridge.js +166 -0
- package/dist/src/mcps/index.js +5 -0
- package/dist/src/mcps/reconcile.js +113 -0
- package/dist/src/mcps/smithery-client.js +186 -0
- package/dist/src/mcps/smithery.js +164 -0
- package/dist/src/mcps/types.js +1 -0
- package/dist/src/memory/json-store.js +71 -0
- package/dist/src/memory/prompt.js +16 -0
- package/dist/src/memory/scope.js +31 -0
- package/dist/src/memory/store.js +1 -0
- package/dist/src/memory/tool-service.js +142 -0
- package/dist/src/memory/types.js +12 -0
- package/dist/src/onboarding/config-writer.js +96 -0
- package/dist/src/onboarding/engine.js +86 -0
- package/dist/src/onboarding/prompt.js +102 -0
- package/dist/src/onboarding/services/provider-discovery.js +58 -0
- package/dist/src/onboarding/services/repo-discovery.js +246 -0
- package/dist/src/onboarding/steps/check-github-auth.js +32 -0
- package/dist/src/onboarding/steps/check-requirements.js +34 -0
- package/dist/src/onboarding/steps/configure-models.js +105 -0
- package/dist/src/onboarding/steps/configure-paths.js +33 -0
- package/dist/src/onboarding/steps/discover-providers.js +38 -0
- package/dist/src/onboarding/steps/discover-repos.js +39 -0
- package/dist/src/onboarding/steps/generate-config.js +106 -0
- package/dist/src/onboarding/steps/readiness-validation.js +158 -0
- package/dist/src/onboarding/steps/select-repos.js +76 -0
- package/dist/src/onboarding/steps/show-summary.js +97 -0
- package/dist/src/onboarding/steps/welcome.js +27 -0
- package/dist/src/onboarding/types.js +1 -0
- package/dist/src/onboarding/validators/git-access.js +63 -0
- package/dist/src/onboarding/validators/github-auth.js +85 -0
- package/dist/src/onboarding/validators/tool-checker.js +153 -0
- package/dist/src/onboarding/validators/workspace.js +83 -0
- package/dist/src/prompts/resolver.js +106 -0
- package/dist/src/retrospectives/candidates.js +224 -0
- package/dist/src/retrospectives/derive.js +169 -0
- package/dist/src/retrospectives/ingest.js +321 -0
- package/dist/src/retrospectives/management-prs.js +380 -0
- package/dist/src/retrospectives/proposals.js +199 -0
- package/dist/src/retrospectives/scopes.js +272 -0
- package/dist/src/retrospectives/scoring.js +171 -0
- package/dist/src/retrospectives/types.js +1 -0
- package/dist/src/state/loader.js +473 -0
- package/dist/src/state/types.js +15 -0
- package/dist/src/tasks/derivation/builders.js +70 -0
- package/dist/src/tasks/derivation/handlers/comment-response.js +169 -0
- package/dist/src/tasks/derivation/handlers/implement-plan.js +103 -0
- package/dist/src/tasks/derivation/handlers/index.js +54 -0
- package/dist/src/tasks/derivation/handlers/packet-pr-control.js +92 -0
- package/dist/src/tasks/derivation/handlers/packet-worktree.js +29 -0
- package/dist/src/tasks/derivation/handlers/plan-breakdown.js +45 -0
- package/dist/src/tasks/derivation/handlers/prepare-for-merge.js +91 -0
- package/dist/src/tasks/derivation/handlers/product-discovery.js +36 -0
- package/dist/src/tasks/derivation/handlers/retry-failed-task.js +125 -0
- package/dist/src/tasks/derivation/handlers/review-pr.js +28 -0
- package/dist/src/tasks/derivation/handlers/shared.js +24 -0
- package/dist/src/tasks/derivation/handlers/sync-parent-branch.js +100 -0
- package/dist/src/tasks/derivation/handlers/wave-assessment.js +223 -0
- package/dist/src/tasks/derivation/handlers/write-plan.js +101 -0
- package/dist/src/tasks/derivation/handlers/write-product-spec.js +49 -0
- package/dist/src/tasks/derivation/runner.js +18 -0
- package/dist/src/tasks/derivation/types.js +1 -0
- package/dist/src/tasks/derive.js +810 -0
- package/dist/src/tasks/mcp-skip.js +10 -0
- package/dist/src/tasks/retry.js +10 -0
- package/dist/src/tasks/task.js +184 -0
- package/dist/src/tasks/types.js +1 -0
- package/dist/src/utils/command-runner.js +192 -0
- package/dist/src/utils/json.js +38 -0
- package/dist/src/utils/logger.js +43 -0
- package/dist/src/utils/paths.js +38 -0
- package/dist/src/utils/slug.js +10 -0
- package/dist/src/workflows/registry.js +174 -0
- package/dist/src/workflows/triage.js +90 -0
- package/dist/src/workflows/workstream-machine/derive-events.js +121 -0
- package/dist/src/workflows/workstream-machine/evaluate.js +24 -0
- package/dist/src/workflows/workstream-machine/events.js +1 -0
- package/dist/src/workflows/workstream-machine/machine.js +355 -0
- package/dist/src/workflows/workstream-machine/selectors.js +19 -0
- package/dist/src/workflows/workstream-machine/types.js +1 -0
- package/dist/src/workstreams/branch-sync.js +87 -0
- package/dist/src/workstreams/derive.js +629 -0
- package/dist/src/workstreams/mcp-blockers.js +420 -0
- package/dist/src/workstreams/packet-candidates.js +42 -0
- package/dist/src/workstreams/packet-lifecycle-feedback.js +60 -0
- package/dist/src/workstreams/packet-lifecycle-report.js +199 -0
- package/dist/src/workstreams/packet-plan.js +597 -0
- package/dist/src/workstreams/packet-projections.js +190 -0
- package/dist/src/workstreams/parent-branch-sync-action.js +312 -0
- package/dist/src/workstreams/parent-branch-sync.js +148 -0
- package/dist/src/workstreams/phases.js +4 -0
- package/dist/src/workstreams/plan-breakdown-generator/export.js +19 -0
- package/dist/src/workstreams/plan-breakdown-generator/index.js +6 -0
- package/dist/src/workstreams/plan-breakdown-generator/inspect.js +50 -0
- package/dist/src/workstreams/plan-breakdown-generator/patch.js +139 -0
- package/dist/src/workstreams/plan-breakdown-generator/session.js +19 -0
- package/dist/src/workstreams/plan-breakdown-generator/store.js +27 -0
- package/dist/src/workstreams/plan-breakdown-generator/tools.js +407 -0
- package/dist/src/workstreams/plan-breakdown-generator/types.js +6 -0
- package/dist/src/workstreams/plan-breakdown-generator/validate.js +212 -0
- package/dist/src/workstreams/plan-breakdown-schema.js +175 -0
- package/dist/src/workstreams/utils.js +15 -0
- package/dist/src/workstreams/wave-assessment/checkpoint.js +172 -0
- package/dist/src/workstreams/wave-assessment/index.js +3 -0
- package/dist/src/workstreams/wave-assessment/session.js +84 -0
- package/dist/src/workstreams/wave-assessment/store.js +51 -0
- package/dist/src/workstreams/wave-assessment/tools.js +419 -0
- package/dist/src/workstreams/wave-assessment/types.js +1 -0
- package/dist/src/workstreams/wave-assessment/validate.js +78 -0
- package/dist/src/worktrees/service.js +839 -0
- package/dist/src/worktrees/workspace-ownership.js +34 -0
- package/dist/src/worktrees/workspace-recovery.js +177 -0
- package/package.json +61 -0
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
export function resolveCodexLaunchConfig(input) {
|
|
2
|
+
return {
|
|
3
|
+
executionPermission: input.executionPermission,
|
|
4
|
+
sandboxMode: mapExecutionPermissionToSandboxMode(input.executionPermission),
|
|
5
|
+
expectsPushableHandoff: input.handoffPolicy.expectsPushableHandoff,
|
|
6
|
+
orchestratorOwnsPush: input.handoffPolicy.orchestratorOwnsPush,
|
|
7
|
+
remotePublishOwner: input.handoffPolicy.remotePublishOwner
|
|
8
|
+
};
|
|
9
|
+
}
|
|
10
|
+
export function mapExecutionPermissionToSandboxMode(executionPermission) {
|
|
11
|
+
switch (executionPermission) {
|
|
12
|
+
case "read-only":
|
|
13
|
+
return "read-only";
|
|
14
|
+
case "workspace-write":
|
|
15
|
+
return "workspace-write";
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
export function buildCodexCliArgs(input) {
|
|
19
|
+
const args = ["exec", "--json", "--sandbox", input.sandboxMode, "--skip-git-repo-check", "--color", "never"];
|
|
20
|
+
if (input.sandboxMode === "workspace-write") {
|
|
21
|
+
args.push("-c", "sandbox_workspace_write.network_access=true");
|
|
22
|
+
}
|
|
23
|
+
if (input.githubBroker) {
|
|
24
|
+
const safeServerName = toCodexCliSafeServerName(input.githubBroker.serverName);
|
|
25
|
+
args.push("-c", `mcp_servers.${safeServerName}.url=${quoteTomlString(input.githubBroker.serverUrl)}`, "-c", `mcp_servers.${safeServerName}.default_tools_approval_mode="approve"`);
|
|
26
|
+
}
|
|
27
|
+
if (input.model) {
|
|
28
|
+
args.push("--model", input.model);
|
|
29
|
+
}
|
|
30
|
+
if (input.resumeThreadId) {
|
|
31
|
+
args.push("resume", input.resumeThreadId);
|
|
32
|
+
}
|
|
33
|
+
args.push("-");
|
|
34
|
+
return args;
|
|
35
|
+
}
|
|
36
|
+
export function buildGlobalCodexLaunchInstructions(input) {
|
|
37
|
+
return [
|
|
38
|
+
"# Global Codex Instructions",
|
|
39
|
+
"",
|
|
40
|
+
"These instructions apply across repositories for this orchestrated run.",
|
|
41
|
+
"",
|
|
42
|
+
"## MCP Server",
|
|
43
|
+
`Use the local MCP server \`${input.githubBroker.serverName}\` for normal GitHub reads and writes.`,
|
|
44
|
+
"- Do not call `gh` directly for normal GitHub issue, pull request, comment, or code-search work.",
|
|
45
|
+
"",
|
|
46
|
+
"## When To Use It",
|
|
47
|
+
"- Use the broker for normal GitHub context gathering and GitHub write actions.",
|
|
48
|
+
"- Repo-local `AGENTS.md` files still apply for repository-specific build, test, and style rules.",
|
|
49
|
+
"",
|
|
50
|
+
"Enabled broker tools for this run:",
|
|
51
|
+
...input.githubBroker.toolAllowList.map((tool) => `- \`${tool}\``),
|
|
52
|
+
"",
|
|
53
|
+
"## Fallback",
|
|
54
|
+
"- If a needed GitHub capability is missing from the broker, report the gap clearly instead of silently bypassing it.",
|
|
55
|
+
"- Continue with local repository work where possible while making the missing broker capability explicit.",
|
|
56
|
+
"- Any GitHub-authored message you post must begin with `🤖` when the task requires writing back to GitHub.",
|
|
57
|
+
""
|
|
58
|
+
].join("\n");
|
|
59
|
+
}
|
|
60
|
+
export function prependGlobalLaunchInstructions(promptText, input) {
|
|
61
|
+
if (!input.githubBroker) {
|
|
62
|
+
return promptText;
|
|
63
|
+
}
|
|
64
|
+
return `${buildGlobalCodexLaunchInstructions({ githubBroker: input.githubBroker })}\n\n${promptText}`;
|
|
65
|
+
}
|
|
66
|
+
export function toCodexCliSafeServerName(value) {
|
|
67
|
+
const segments = value
|
|
68
|
+
.split(/[^a-zA-Z0-9]+/)
|
|
69
|
+
.map((segment) => segment.trim())
|
|
70
|
+
.filter((segment) => segment.length > 0);
|
|
71
|
+
if (segments.length === 0) {
|
|
72
|
+
return "githubBroker";
|
|
73
|
+
}
|
|
74
|
+
return segments
|
|
75
|
+
.map((segment, index) => index === 0
|
|
76
|
+
? segment[0].toLowerCase() + segment.slice(1)
|
|
77
|
+
: segment[0].toUpperCase() + segment.slice(1))
|
|
78
|
+
.join("");
|
|
79
|
+
}
|
|
80
|
+
function quoteTomlString(value) {
|
|
81
|
+
return JSON.stringify(value);
|
|
82
|
+
}
|
|
@@ -0,0 +1,261 @@
|
|
|
1
|
+
import { closeSync, openSync, writeSync } from "node:fs";
|
|
2
|
+
import { mkdir, writeFile } from "node:fs/promises";
|
|
3
|
+
import * as path from "node:path";
|
|
4
|
+
import { writeJsonFileAtomic } from "../utils/json.js";
|
|
5
|
+
import { buildCodexCliArgs, prependGlobalLaunchInstructions, resolveCodexLaunchConfig, toCodexCliSafeServerName } from "./codex-launch.js";
|
|
6
|
+
import { buildExecutionId, extractExitCode, extractAndExportPlanBreakdownResult, extractAndExportWaveAssessmentResult, extractReviewResult, extractStderr, extractStdout, extractTriageResult, detectProviderLimit } from "./extraction.js";
|
|
7
|
+
import { buildPromptPacket, renderPrompt } from "./prompt.js";
|
|
8
|
+
const DEFAULT_TIMEOUT_MS = 10 * 60 * 1000;
|
|
9
|
+
export class CodexCliAgent {
|
|
10
|
+
options;
|
|
11
|
+
now;
|
|
12
|
+
timeoutMs;
|
|
13
|
+
logger;
|
|
14
|
+
constructor(options) {
|
|
15
|
+
this.options = options;
|
|
16
|
+
this.now = options.now ?? (() => new Date().toISOString());
|
|
17
|
+
this.timeoutMs = options.timeoutMs ?? DEFAULT_TIMEOUT_MS;
|
|
18
|
+
this.logger = options.logger;
|
|
19
|
+
}
|
|
20
|
+
async dispatch(task, context, agentConfig, sessionDecision, promptContent) {
|
|
21
|
+
const launchConfig = resolveCodexLaunchConfig({
|
|
22
|
+
executionPermission: task.executionPermission,
|
|
23
|
+
handoffPolicy: task.handoffPolicy
|
|
24
|
+
});
|
|
25
|
+
const githubBroker = this.options.githubBroker
|
|
26
|
+
? {
|
|
27
|
+
...this.options.githubBroker,
|
|
28
|
+
serverName: toCodexCliSafeServerName(this.options.githubBroker.serverName)
|
|
29
|
+
}
|
|
30
|
+
: undefined;
|
|
31
|
+
const promptPacket = buildPromptPacket(task, context);
|
|
32
|
+
const promptText = prependGlobalLaunchInstructions(renderPrompt(task, promptPacket, {
|
|
33
|
+
customConstraints: promptContent?.content,
|
|
34
|
+
learningOverlays: promptContent?.learningOverlays
|
|
35
|
+
}), githubBroker ? { githubBroker } : {});
|
|
36
|
+
const startedAt = this.now();
|
|
37
|
+
const executionId = buildExecutionId(task.id, startedAt);
|
|
38
|
+
const artifactDir = path.join(this.options.logDir, "artifacts", executionId);
|
|
39
|
+
const promptPacketPath = path.join(artifactDir, "prompt-packet.json");
|
|
40
|
+
const promptArtifactPath = path.join(artifactDir, "prompt.md");
|
|
41
|
+
const stdoutArtifactPath = path.join(artifactDir, "stdout.txt");
|
|
42
|
+
const stderrArtifactPath = path.join(artifactDir, "stderr.txt");
|
|
43
|
+
const streamArtifactPath = path.join(artifactDir, "stdout-stream.jsonl");
|
|
44
|
+
const resumeThreadId = sessionDecision?.mode === "native_resume_candidate"
|
|
45
|
+
? sessionDecision.record.providerSessionId
|
|
46
|
+
: undefined;
|
|
47
|
+
const args = buildCodexCliArgs({
|
|
48
|
+
sandboxMode: launchConfig.sandboxMode,
|
|
49
|
+
resumeThreadId,
|
|
50
|
+
...(githubBroker ? { githubBroker } : {}),
|
|
51
|
+
...(agentConfig.model ? { model: agentConfig.model } : {})
|
|
52
|
+
});
|
|
53
|
+
const cwd = context.localRepoPath ?? process.cwd();
|
|
54
|
+
await mkdir(artifactDir, { recursive: true });
|
|
55
|
+
await Promise.all([
|
|
56
|
+
writeJsonFileAtomic(promptPacketPath, promptPacket),
|
|
57
|
+
writeFile(promptArtifactPath, promptText, "utf8")
|
|
58
|
+
]);
|
|
59
|
+
if (githubBroker) {
|
|
60
|
+
this.logger?.info(JSON.stringify({
|
|
61
|
+
component: "codex-launch",
|
|
62
|
+
taskKind: task.kind,
|
|
63
|
+
targetRepoPath: cwd,
|
|
64
|
+
executionPermission: launchConfig.executionPermission,
|
|
65
|
+
sandboxMode: launchConfig.sandboxMode,
|
|
66
|
+
expectsPushableHandoff: launchConfig.expectsPushableHandoff,
|
|
67
|
+
orchestratorOwnsPush: launchConfig.orchestratorOwnsPush,
|
|
68
|
+
remotePublishOwner: launchConfig.remotePublishOwner,
|
|
69
|
+
mcpServerName: githubBroker.serverName,
|
|
70
|
+
mcpServerUrl: githubBroker.serverUrl,
|
|
71
|
+
enabledToolAllowList: githubBroker.toolAllowList,
|
|
72
|
+
configOverrides: args.filter((_, index) => args[index - 1] === "-c")
|
|
73
|
+
}));
|
|
74
|
+
}
|
|
75
|
+
else {
|
|
76
|
+
this.logger?.info(JSON.stringify({
|
|
77
|
+
component: "codex-launch",
|
|
78
|
+
taskKind: task.kind,
|
|
79
|
+
targetRepoPath: cwd,
|
|
80
|
+
executionPermission: launchConfig.executionPermission,
|
|
81
|
+
sandboxMode: launchConfig.sandboxMode,
|
|
82
|
+
expectsPushableHandoff: launchConfig.expectsPushableHandoff,
|
|
83
|
+
orchestratorOwnsPush: launchConfig.orchestratorOwnsPush,
|
|
84
|
+
remotePublishOwner: launchConfig.remotePublishOwner
|
|
85
|
+
}));
|
|
86
|
+
}
|
|
87
|
+
let exitCode = 0;
|
|
88
|
+
let stdout = "";
|
|
89
|
+
let stderr = "";
|
|
90
|
+
let endedAt = startedAt;
|
|
91
|
+
let stdoutStreamFd;
|
|
92
|
+
try {
|
|
93
|
+
stdoutStreamFd = openSync(streamArtifactPath, "w");
|
|
94
|
+
const result = await this.options.commandRunner.run(agentConfig.command, args, {
|
|
95
|
+
cwd,
|
|
96
|
+
input: promptText,
|
|
97
|
+
timeoutMs: this.timeoutMs,
|
|
98
|
+
onOutputChunk: (stream, chunk) => {
|
|
99
|
+
if (stream === "stdout" && stdoutStreamFd !== undefined) {
|
|
100
|
+
writeSync(stdoutStreamFd, chunk);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
});
|
|
104
|
+
exitCode = result.exitCode;
|
|
105
|
+
stdout = result.stdout;
|
|
106
|
+
stderr = result.stderr;
|
|
107
|
+
endedAt = this.now();
|
|
108
|
+
}
|
|
109
|
+
catch (error) {
|
|
110
|
+
exitCode = extractExitCode(error);
|
|
111
|
+
stdout = extractStdout(error);
|
|
112
|
+
stderr = extractStderr(error);
|
|
113
|
+
endedAt = this.now();
|
|
114
|
+
}
|
|
115
|
+
finally {
|
|
116
|
+
if (stdoutStreamFd !== undefined) {
|
|
117
|
+
closeSync(stdoutStreamFd);
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
const derivedStdout = exitCode === 0
|
|
121
|
+
? extractCodexStreamJsonAssistantText(stdout) ?? stdout
|
|
122
|
+
: stdout;
|
|
123
|
+
await Promise.all([
|
|
124
|
+
writeFile(stdoutArtifactPath, derivedStdout, "utf8"),
|
|
125
|
+
writeFile(stderrArtifactPath, stderr, "utf8")
|
|
126
|
+
]);
|
|
127
|
+
const triageResult = extractTriageResult(task, derivedStdout);
|
|
128
|
+
const reviewResult = extractReviewResult(task, derivedStdout);
|
|
129
|
+
const planBreakdownExtraction = extractAndExportPlanBreakdownResult(task, derivedStdout, this.options.planBreakdownSessionStore);
|
|
130
|
+
const waveAssessmentExtraction = extractAndExportWaveAssessmentResult(task, derivedStdout, this.options.waveAssessmentSessionStore);
|
|
131
|
+
let taskStatus = exitCode === 0 ? "completed" : "failed";
|
|
132
|
+
let errorMessage = exitCode === 0 ? undefined : stderr.trim() || "Codex CLI exited with a non-zero status.";
|
|
133
|
+
if (task.kind === "review_pr" && exitCode === 0 && !reviewResult) {
|
|
134
|
+
taskStatus = "failed";
|
|
135
|
+
errorMessage = "Agent output did not contain a valid structured review result.";
|
|
136
|
+
}
|
|
137
|
+
if ((task.kind === "plan_breakdown" || task.kind === "wave_plan_replanning") && exitCode === 0) {
|
|
138
|
+
if (!planBreakdownExtraction.ok) {
|
|
139
|
+
taskStatus = "failed";
|
|
140
|
+
errorMessage = planBreakdownExtraction.message;
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
if (task.kind === "wave_plan_assessment" && exitCode === 0) {
|
|
144
|
+
if (!waveAssessmentExtraction.ok) {
|
|
145
|
+
taskStatus = "failed";
|
|
146
|
+
errorMessage = waveAssessmentExtraction.message;
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
const execution = {
|
|
150
|
+
id: executionId,
|
|
151
|
+
taskId: task.id,
|
|
152
|
+
taskKind: task.kind,
|
|
153
|
+
taskStatus,
|
|
154
|
+
repoId: task.repoId,
|
|
155
|
+
repoSlug: task.repoSlug,
|
|
156
|
+
agentId: agentConfig.id,
|
|
157
|
+
agentProvider: "codex",
|
|
158
|
+
...(agentConfig.model ? { agentModel: agentConfig.model } : {}),
|
|
159
|
+
command: {
|
|
160
|
+
executable: agentConfig.command,
|
|
161
|
+
args,
|
|
162
|
+
cwd,
|
|
163
|
+
timeoutMs: this.timeoutMs
|
|
164
|
+
},
|
|
165
|
+
promptArtifactPath,
|
|
166
|
+
stdoutArtifactPath,
|
|
167
|
+
stderrArtifactPath,
|
|
168
|
+
streamArtifactPath,
|
|
169
|
+
promptPacketPath,
|
|
170
|
+
startedAt,
|
|
171
|
+
endedAt,
|
|
172
|
+
exitCode,
|
|
173
|
+
...(errorMessage ? { errorMessage } : {}),
|
|
174
|
+
...(triageResult || reviewResult || planBreakdownExtraction.ok || waveAssessmentExtraction.ok
|
|
175
|
+
? {
|
|
176
|
+
result: {
|
|
177
|
+
...(triageResult ? { triage: triageResult } : {}),
|
|
178
|
+
...(reviewResult ? { review: reviewResult } : {}),
|
|
179
|
+
...(planBreakdownExtraction.ok
|
|
180
|
+
? {
|
|
181
|
+
planBreakdown: planBreakdownExtraction.planBreakdown,
|
|
182
|
+
planBreakdownSessionId: planBreakdownExtraction.sessionId
|
|
183
|
+
}
|
|
184
|
+
: {}),
|
|
185
|
+
...(waveAssessmentExtraction.ok
|
|
186
|
+
? {
|
|
187
|
+
waveAssessment: waveAssessmentExtraction.waveAssessment
|
|
188
|
+
}
|
|
189
|
+
: {})
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
: {})
|
|
193
|
+
};
|
|
194
|
+
const parsedThreadId = extractThreadIdFromCodexOutput(stdout);
|
|
195
|
+
const providerLimitSignal = detectProviderLimit("codex", exitCode, stdout, stderr);
|
|
196
|
+
return {
|
|
197
|
+
taskStatus: execution.taskStatus,
|
|
198
|
+
execution,
|
|
199
|
+
...(providerLimitSignal ? { providerLimitSignal } : {}),
|
|
200
|
+
...(parsedThreadId ? { providerSession: { providerSessionId: parsedThreadId, status: "active" } } : {})
|
|
201
|
+
};
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
function extractThreadIdFromCodexOutput(streamText) {
|
|
205
|
+
if (!streamText.trim()) {
|
|
206
|
+
return undefined;
|
|
207
|
+
}
|
|
208
|
+
const plainTextMatch = /\bsession id:\s*([0-9a-f-]{36})\b/i.exec(streamText);
|
|
209
|
+
if (plainTextMatch?.[1]) {
|
|
210
|
+
return plainTextMatch[1];
|
|
211
|
+
}
|
|
212
|
+
for (const line of streamText.split(/\r?\n/)) {
|
|
213
|
+
const trimmed = line.trim();
|
|
214
|
+
if (!trimmed) {
|
|
215
|
+
continue;
|
|
216
|
+
}
|
|
217
|
+
try {
|
|
218
|
+
const event = JSON.parse(trimmed);
|
|
219
|
+
if (event && typeof event === "object" && event.type === "thread.started" && typeof event.thread_id === "string") {
|
|
220
|
+
return event.thread_id;
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
catch {
|
|
224
|
+
continue;
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
return undefined;
|
|
228
|
+
}
|
|
229
|
+
function extractCodexStreamJsonAssistantText(streamText) {
|
|
230
|
+
if (!streamText.trim()) {
|
|
231
|
+
return undefined;
|
|
232
|
+
}
|
|
233
|
+
let assistantText = "";
|
|
234
|
+
let sawAssistantMessage = false;
|
|
235
|
+
for (const line of streamText.split(/\r?\n/)) {
|
|
236
|
+
const trimmed = line.trim();
|
|
237
|
+
if (!trimmed) {
|
|
238
|
+
continue;
|
|
239
|
+
}
|
|
240
|
+
try {
|
|
241
|
+
const event = JSON.parse(trimmed);
|
|
242
|
+
if (event &&
|
|
243
|
+
typeof event === "object" &&
|
|
244
|
+
event.type === "item.completed" &&
|
|
245
|
+
event.item &&
|
|
246
|
+
typeof event.item === "object" &&
|
|
247
|
+
event.item.type === "agent_message" &&
|
|
248
|
+
typeof event.item.text === "string") {
|
|
249
|
+
assistantText += event.item.text;
|
|
250
|
+
sawAssistantMessage = true;
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
catch {
|
|
254
|
+
continue;
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
if (sawAssistantMessage) {
|
|
258
|
+
return assistantText;
|
|
259
|
+
}
|
|
260
|
+
return undefined;
|
|
261
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export class CompositeAgentRunner {
|
|
2
|
+
runners = new Map();
|
|
3
|
+
register(provider, runner) {
|
|
4
|
+
this.runners.set(provider, runner);
|
|
5
|
+
}
|
|
6
|
+
async dispatch(task, context, agentConfig, sessionDecision, promptContent) {
|
|
7
|
+
const runner = this.runners.get(agentConfig.provider);
|
|
8
|
+
if (!runner) {
|
|
9
|
+
throw new Error(`No runner registered for agent provider "${agentConfig.provider}" (agent: ${agentConfig.id})`);
|
|
10
|
+
}
|
|
11
|
+
return runner.dispatch(task, context, agentConfig, sessionDecision, promptContent);
|
|
12
|
+
}
|
|
13
|
+
}
|