@gh-symphony/cli 0.0.21 → 0.1.2
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/README.md +100 -69
- package/dist/chunk-6I753NYO.js +18 -0
- package/dist/{workflow-BLJH2HC3.js → chunk-B4ZJMAZL.js} +27 -19
- package/dist/{chunk-SXGT7LOF.js → chunk-DLZAJXZL.js} +600 -12
- package/dist/chunk-GHVDABFO.js +235 -0
- package/dist/{chunk-QEONJ5DZ.js → chunk-GPRCOJDJ.js} +1314 -35
- package/dist/{chunk-A67CMOYE.js → chunk-VFHMHHZW.js} +1 -1
- package/dist/{chunk-JN3TQVFV.js → chunk-WM2B6BJ7.js} +16 -62
- package/dist/{chunk-ROGRTUFI.js → chunk-WOVNN5NW.js} +16 -6
- package/dist/{chunk-C67H3OUL.js → chunk-Z3NZOPLZ.js} +0 -81
- package/dist/{config-cmd-DNXNL26Z.js → config-cmd-2ADPUYWA.js} +1 -1
- package/dist/{doctor-4HBRICHP.js → doctor-EEPNFCGF.js} +464 -40
- package/dist/index.js +357 -244
- package/dist/repo-RX4OK7XH.js +6783 -0
- package/dist/{setup-B2SVLW2R.js → setup-XNHHRBGU.js} +57 -91
- package/dist/{upgrade-OJXPZRYE.js → upgrade-NS53EO2B.js} +2 -2
- package/dist/{version-TBDCTKDO.js → version-2RHFZ5CI.js} +1 -1
- package/dist/worker-entry.js +376 -15
- package/dist/workflow-26QNZZWH.js +22 -0
- package/package.json +5 -5
- package/dist/chunk-5NV3LSAJ.js +0 -11
- package/dist/chunk-C7G7RJ4G.js +0 -146
- package/dist/chunk-KY6WKH66.js +0 -1300
- package/dist/chunk-MYVJ6HK4.js +0 -3510
- package/dist/chunk-S6VIK4FF.js +0 -723
- package/dist/chunk-XN5ABWZ6.js +0 -486
- package/dist/chunk-Y6TYJMNT.js +0 -109
- package/dist/init-HZ3JEDGQ.js +0 -38
- package/dist/logs-6JKKYDGJ.js +0 -188
- package/dist/project-25NQ4J4Y.js +0 -24
- package/dist/recover-L3MJHHDA.js +0 -133
- package/dist/repo-TDCWQR6P.js +0 -379
- package/dist/run-XJQ6BF7U.js +0 -110
- package/dist/start-I2CC7BLW.js +0 -18
- package/dist/status-QSCFVGRQ.js +0 -11
- package/dist/stop-7MFCBQVW.js +0 -9
package/dist/worker-entry.js
CHANGED
|
@@ -6,20 +6,21 @@ import {
|
|
|
6
6
|
normalizeCodexRuntimeEvents,
|
|
7
7
|
prepareCodexRuntimePlan,
|
|
8
8
|
resolveLocalRuntimeLaunchConfig
|
|
9
|
-
} from "./chunk-
|
|
9
|
+
} from "./chunk-VFHMHHZW.js";
|
|
10
10
|
import {
|
|
11
11
|
DEFAULT_AGENT_INPUT_REQUIRED_REASON,
|
|
12
12
|
classifySessionExit,
|
|
13
|
+
createClaudePrintRuntimeAdapter,
|
|
14
|
+
extractEnvForClaude,
|
|
13
15
|
formatClaudePreflightText,
|
|
14
|
-
isClaudeRuntimeCommand,
|
|
15
16
|
parseWorkflowMarkdown,
|
|
16
17
|
resolveClaudeCommandBinary,
|
|
17
18
|
resolveWorkflowRuntimeCommand,
|
|
18
19
|
runClaudePreflight
|
|
19
|
-
} from "./chunk-
|
|
20
|
+
} from "./chunk-GPRCOJDJ.js";
|
|
20
21
|
|
|
21
22
|
// ../worker/src/index.ts
|
|
22
|
-
import { spawn } from "child_process";
|
|
23
|
+
import { spawn as spawn2 } from "child_process";
|
|
23
24
|
import { readFile } from "fs/promises";
|
|
24
25
|
import { join as join2 } from "path";
|
|
25
26
|
|
|
@@ -124,6 +125,152 @@ function normalizeError(value) {
|
|
|
124
125
|
return normalized.length > 0 ? normalized : null;
|
|
125
126
|
}
|
|
126
127
|
|
|
128
|
+
// ../worker/src/non-codex-runtime.ts
|
|
129
|
+
import {
|
|
130
|
+
spawn
|
|
131
|
+
} from "child_process";
|
|
132
|
+
import { finished } from "stream/promises";
|
|
133
|
+
var CustomCommandWorkerRuntimeAdapter = class {
|
|
134
|
+
constructor(config, dependencies = {}) {
|
|
135
|
+
this.config = config;
|
|
136
|
+
this.dependencies = dependencies;
|
|
137
|
+
}
|
|
138
|
+
activeChild = null;
|
|
139
|
+
prepare() {
|
|
140
|
+
}
|
|
141
|
+
async spawnTurn(input) {
|
|
142
|
+
const command = this.config.command;
|
|
143
|
+
const args = [...this.config.args];
|
|
144
|
+
const cwd = input.cwd ?? this.config.workingDirectory;
|
|
145
|
+
const child = (this.dependencies.spawnImpl ?? spawn)(command, args, {
|
|
146
|
+
cwd,
|
|
147
|
+
env: {
|
|
148
|
+
...this.config.env,
|
|
149
|
+
...input.env,
|
|
150
|
+
SYMPHONY_RENDERED_PROMPT: input.prompt
|
|
151
|
+
},
|
|
152
|
+
stdio: "pipe"
|
|
153
|
+
});
|
|
154
|
+
this.activeChild = child;
|
|
155
|
+
this.config.onSpawned?.(child);
|
|
156
|
+
let stdout = "";
|
|
157
|
+
let stderr = "";
|
|
158
|
+
let spawnError;
|
|
159
|
+
child.stdout?.setEncoding("utf8");
|
|
160
|
+
child.stderr?.setEncoding("utf8");
|
|
161
|
+
child.stdout?.on("data", (chunk) => {
|
|
162
|
+
stdout += chunk;
|
|
163
|
+
});
|
|
164
|
+
child.stderr?.on("data", (chunk) => {
|
|
165
|
+
stderr += chunk;
|
|
166
|
+
});
|
|
167
|
+
child.once("error", (error) => {
|
|
168
|
+
spawnError = error.message;
|
|
169
|
+
});
|
|
170
|
+
if (child.stdin && !child.stdin.destroyed) {
|
|
171
|
+
child.stdin.end(input.prompt);
|
|
172
|
+
}
|
|
173
|
+
const { exitCode, signal } = await waitForChildExit(child);
|
|
174
|
+
await Promise.all([
|
|
175
|
+
child.stdout ? finished(child.stdout).catch(() => void 0) : void 0,
|
|
176
|
+
child.stderr ? finished(child.stderr).catch(() => void 0) : void 0
|
|
177
|
+
]);
|
|
178
|
+
this.activeChild = null;
|
|
179
|
+
const result = exitCode === 0 && signal === null && !spawnError ? "success" : "process-error";
|
|
180
|
+
return {
|
|
181
|
+
command,
|
|
182
|
+
args,
|
|
183
|
+
cwd,
|
|
184
|
+
stdout,
|
|
185
|
+
stderr,
|
|
186
|
+
exitCode,
|
|
187
|
+
signal,
|
|
188
|
+
result,
|
|
189
|
+
errorMessage: spawnError
|
|
190
|
+
};
|
|
191
|
+
}
|
|
192
|
+
onEvent(_handler) {
|
|
193
|
+
return () => {
|
|
194
|
+
};
|
|
195
|
+
}
|
|
196
|
+
resolveCredentials(brokerResponse) {
|
|
197
|
+
if (!this.config.authEnvKey) {
|
|
198
|
+
return {};
|
|
199
|
+
}
|
|
200
|
+
return extractEnvForClaude(brokerResponse.env, this.config.authEnvKey);
|
|
201
|
+
}
|
|
202
|
+
shutdown() {
|
|
203
|
+
this.stopActiveChild();
|
|
204
|
+
}
|
|
205
|
+
cancel() {
|
|
206
|
+
this.stopActiveChild();
|
|
207
|
+
}
|
|
208
|
+
stopActiveChild() {
|
|
209
|
+
if (!this.activeChild || this.activeChild.killed) {
|
|
210
|
+
this.activeChild = null;
|
|
211
|
+
return;
|
|
212
|
+
}
|
|
213
|
+
this.activeChild.kill("SIGTERM");
|
|
214
|
+
this.activeChild = null;
|
|
215
|
+
}
|
|
216
|
+
};
|
|
217
|
+
function createWorkerNonCodexRuntimeAdapter(workflow, context) {
|
|
218
|
+
const runtime = workflow.runtime;
|
|
219
|
+
if (!runtime || runtime.kind === "codex-app-server") {
|
|
220
|
+
throw new Error(
|
|
221
|
+
"Worker non-Codex runtime adapter requested for a Codex runtime."
|
|
222
|
+
);
|
|
223
|
+
}
|
|
224
|
+
switch (runtime.kind) {
|
|
225
|
+
case "claude-print":
|
|
226
|
+
return createClaudePrintRuntimeAdapter(
|
|
227
|
+
{
|
|
228
|
+
workingDirectory: context.workingDirectory,
|
|
229
|
+
runtimeRoot: context.runtimeRoot,
|
|
230
|
+
runtimeDirectory: context.runtimeDirectory,
|
|
231
|
+
command: runtime.command,
|
|
232
|
+
args: runtime.args,
|
|
233
|
+
env: context.env,
|
|
234
|
+
authEnvKey: runtime.auth.env ?? void 0,
|
|
235
|
+
isolation: {
|
|
236
|
+
bare: runtime.isolation.bare,
|
|
237
|
+
strictMcpConfig: runtime.isolation.strictMcpConfig
|
|
238
|
+
}
|
|
239
|
+
},
|
|
240
|
+
{
|
|
241
|
+
...context.claudeDependencies,
|
|
242
|
+
onSpawned: context.onSpawned
|
|
243
|
+
}
|
|
244
|
+
);
|
|
245
|
+
case "custom":
|
|
246
|
+
return new CustomCommandWorkerRuntimeAdapter(
|
|
247
|
+
{
|
|
248
|
+
workingDirectory: context.workingDirectory,
|
|
249
|
+
command: runtime.command,
|
|
250
|
+
args: runtime.args,
|
|
251
|
+
env: context.env,
|
|
252
|
+
authEnvKey: runtime.auth.env ?? void 0,
|
|
253
|
+
onSpawned: context.onSpawned
|
|
254
|
+
},
|
|
255
|
+
context.customDependencies
|
|
256
|
+
);
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
function waitForChildExit(child) {
|
|
260
|
+
return new Promise((resolve) => {
|
|
261
|
+
let settled = false;
|
|
262
|
+
const settle = (exitCode, signal) => {
|
|
263
|
+
if (settled) {
|
|
264
|
+
return;
|
|
265
|
+
}
|
|
266
|
+
settled = true;
|
|
267
|
+
resolve({ exitCode, signal });
|
|
268
|
+
};
|
|
269
|
+
child.once("exit", settle);
|
|
270
|
+
child.once("error", () => settle(1, null));
|
|
271
|
+
});
|
|
272
|
+
}
|
|
273
|
+
|
|
127
274
|
// ../worker/src/run-phase.ts
|
|
128
275
|
var TERMINAL_RUN_PHASES = /* @__PURE__ */ new Set([
|
|
129
276
|
"succeeded",
|
|
@@ -139,6 +286,18 @@ function resolveExitRunPhase(currentRunPhase, exit) {
|
|
|
139
286
|
return exit.code === 0 && !exit.signal ? "succeeded" : "failed";
|
|
140
287
|
}
|
|
141
288
|
|
|
289
|
+
// ../worker/src/runtime-routing.ts
|
|
290
|
+
function resolveWorkerRuntimeRoute(workflow) {
|
|
291
|
+
const kind = workflow.runtime?.kind;
|
|
292
|
+
if (!kind || kind === "codex-app-server") {
|
|
293
|
+
return "codex-app-server";
|
|
294
|
+
}
|
|
295
|
+
return "runtime-adapter";
|
|
296
|
+
}
|
|
297
|
+
function resolveClaudePreflightAuthMode(workflow) {
|
|
298
|
+
return workflow.runtime?.isolation.bare === true ? "api-key-required" : "local-or-api-key";
|
|
299
|
+
}
|
|
300
|
+
|
|
142
301
|
// ../worker/src/thread-resume.ts
|
|
143
302
|
var DEFAULT_CONTINUATION_GUIDANCE = "Continue working on the issue. Review your progress and complete any remaining tasks.";
|
|
144
303
|
function parseNonNegativeInteger(value) {
|
|
@@ -298,6 +457,7 @@ console.log(
|
|
|
298
457
|
)
|
|
299
458
|
);
|
|
300
459
|
var childProcess = null;
|
|
460
|
+
var runtimeAdapter = null;
|
|
301
461
|
var shutdownPromise = null;
|
|
302
462
|
var orchestratorChannelDrainPending = false;
|
|
303
463
|
var pendingOrchestratorChannelPayloads = [];
|
|
@@ -328,6 +488,7 @@ function shutdown(signal) {
|
|
|
328
488
|
} catch {
|
|
329
489
|
}
|
|
330
490
|
}
|
|
491
|
+
await runtimeAdapter?.cancel(`worker received ${signal}`);
|
|
331
492
|
stopOrchestratorHeartbeatTimer();
|
|
332
493
|
emitOrchestratorHeartbeat();
|
|
333
494
|
await persistSessionTokenUsageArtifact(launcherEnv);
|
|
@@ -569,12 +730,16 @@ async function startAssignedRun() {
|
|
|
569
730
|
await readFile(workflowPath, "utf8"),
|
|
570
731
|
launcherEnv
|
|
571
732
|
);
|
|
572
|
-
|
|
733
|
+
const route = resolveWorkerRuntimeRoute(workflow);
|
|
734
|
+
const runtimeCommand = resolveWorkflowRuntimeCommand(workflow);
|
|
735
|
+
const claudeCommand = resolveClaudeCommandBinary(runtimeCommand);
|
|
736
|
+
if (route === "runtime-adapter" && workflow.runtime?.kind === "claude-print" && claudeCommand) {
|
|
573
737
|
const hasGitHubGraphqlToken = typeof launcherEnv.GITHUB_GRAPHQL_TOKEN === "string" && launcherEnv.GITHUB_GRAPHQL_TOKEN.trim().length > 0;
|
|
574
738
|
const preflight = await runClaudePreflight({
|
|
575
739
|
cwd: launcherEnv.WORKING_DIRECTORY,
|
|
576
740
|
env: launcherEnv,
|
|
577
|
-
command:
|
|
741
|
+
command: claudeCommand,
|
|
742
|
+
authMode: resolveClaudePreflightAuthMode(workflow),
|
|
578
743
|
includeGhAuth: !hasGitHubGraphqlToken
|
|
579
744
|
});
|
|
580
745
|
process.stderr.write(
|
|
@@ -587,19 +752,19 @@ async function startAssignedRun() {
|
|
|
587
752
|
);
|
|
588
753
|
return;
|
|
589
754
|
}
|
|
590
|
-
await exitWorkerStartupFailure(
|
|
591
|
-
"Claude runtime worker launch is not yet implemented in this branch."
|
|
592
|
-
);
|
|
593
|
-
return;
|
|
594
755
|
}
|
|
595
756
|
runtimeState.executionPhase = resolveInitialExecutionPhase({
|
|
596
757
|
issueState: runtimeState.run?.state,
|
|
597
758
|
blockerCheckStates: workflow.lifecycle.blockerCheckStates,
|
|
598
759
|
activeStates: workflow.lifecycle.activeStates
|
|
599
760
|
});
|
|
761
|
+
runtimeState.runPhase = "launching_agent";
|
|
762
|
+
if (route === "runtime-adapter") {
|
|
763
|
+
await runNonCodexRuntimeAdapterLifecycle(workflow, launcherEnv);
|
|
764
|
+
return;
|
|
765
|
+
}
|
|
600
766
|
const config = resolveLocalRuntimeLaunchConfig(launcherEnv);
|
|
601
767
|
config.agentCommand = resolveWorkflowRuntimeCommand(workflow);
|
|
602
|
-
runtimeState.runPhase = "launching_agent";
|
|
603
768
|
const plan = await prepareCodexRuntimePlan(config);
|
|
604
769
|
childProcess = launchCodexAppServer(plan);
|
|
605
770
|
runtimeState.status = "running";
|
|
@@ -640,14 +805,210 @@ async function startAssignedRun() {
|
|
|
640
805
|
void persistSessionTokenUsageArtifact(launcherEnv);
|
|
641
806
|
});
|
|
642
807
|
} catch (error) {
|
|
808
|
+
const message = error instanceof Error ? error.message : "Unknown worker startup error";
|
|
643
809
|
runtimeState.status = "failed";
|
|
644
810
|
runtimeState.runPhase = "failed";
|
|
645
811
|
if (runtimeState.run) {
|
|
646
|
-
runtimeState.run.lastError =
|
|
812
|
+
runtimeState.run.lastError = message;
|
|
647
813
|
}
|
|
814
|
+
process.stderr.write(`[worker] startup failed: ${message}
|
|
815
|
+
`);
|
|
648
816
|
await persistSessionTokenUsageArtifact(launcherEnv);
|
|
649
817
|
}
|
|
650
818
|
}
|
|
819
|
+
async function runNonCodexRuntimeAdapterLifecycle(workflow, env) {
|
|
820
|
+
const renderedPrompt = env.SYMPHONY_RENDERED_PROMPT;
|
|
821
|
+
if (!renderedPrompt) {
|
|
822
|
+
await exitWorkerStartupFailure(
|
|
823
|
+
"SYMPHONY_RENDERED_PROMPT not set; cannot run runtime adapter lifecycle."
|
|
824
|
+
);
|
|
825
|
+
return;
|
|
826
|
+
}
|
|
827
|
+
const runId = env.SYMPHONY_RUN_ID;
|
|
828
|
+
if (!runId) {
|
|
829
|
+
await exitWorkerStartupFailure(
|
|
830
|
+
"SYMPHONY_RUN_ID not set; cannot prepare runtime adapter lifecycle."
|
|
831
|
+
);
|
|
832
|
+
return;
|
|
833
|
+
}
|
|
834
|
+
const runtimeKind = workflow.runtime?.kind;
|
|
835
|
+
if (runtimeKind !== "claude-print" && runtimeKind !== "custom") {
|
|
836
|
+
await exitWorkerStartupFailure(
|
|
837
|
+
"Runtime adapter lifecycle requested for an unsupported runtime kind."
|
|
838
|
+
);
|
|
839
|
+
return;
|
|
840
|
+
}
|
|
841
|
+
const adapter = createWorkerNonCodexRuntimeAdapter(workflow, {
|
|
842
|
+
workingDirectory: env.WORKING_DIRECTORY,
|
|
843
|
+
env,
|
|
844
|
+
runtimeRoot: env.WORKSPACE_RUNTIME_DIR,
|
|
845
|
+
runtimeDirectory: env.WORKSPACE_RUNTIME_DIR,
|
|
846
|
+
onSpawned: (child) => {
|
|
847
|
+
childProcess = child;
|
|
848
|
+
if (runtimeState.run) {
|
|
849
|
+
runtimeState.run.processId = child.pid ?? null;
|
|
850
|
+
}
|
|
851
|
+
}
|
|
852
|
+
});
|
|
853
|
+
runtimeAdapter = adapter;
|
|
854
|
+
let terminalFailure = null;
|
|
855
|
+
const unsubscribe = adapter.onEvent((event) => {
|
|
856
|
+
const agentEvent = event;
|
|
857
|
+
handleNonCodexRuntimeEvent(agentEvent);
|
|
858
|
+
if (agentEvent.name === "agent.inputRequired") {
|
|
859
|
+
terminalFailure = agentEvent.payload.reason;
|
|
860
|
+
}
|
|
861
|
+
if (agentEvent.name === "agent.turnFailed" || agentEvent.name === "agent.error") {
|
|
862
|
+
terminalFailure = agentEvent.name === "agent.error" ? agentEvent.payload.error : JSON.stringify(agentEvent.payload.params);
|
|
863
|
+
}
|
|
864
|
+
});
|
|
865
|
+
const turnTelemetry = {
|
|
866
|
+
startedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
867
|
+
threadId: null,
|
|
868
|
+
turnId: `${runId}-turn-1`,
|
|
869
|
+
turnCount: 1,
|
|
870
|
+
sessionId: runId,
|
|
871
|
+
tokenUsageBaseline: cloneTokenUsageSnapshot()
|
|
872
|
+
};
|
|
873
|
+
try {
|
|
874
|
+
await adapter.prepare({
|
|
875
|
+
runId
|
|
876
|
+
});
|
|
877
|
+
runtimeState.status = "running";
|
|
878
|
+
runtimeState.runPhase = "streaming_turn";
|
|
879
|
+
runtimeState.sessionInfo = {
|
|
880
|
+
threadId: turnTelemetry.threadId,
|
|
881
|
+
turnId: turnTelemetry.turnId,
|
|
882
|
+
turnCount: turnTelemetry.turnCount,
|
|
883
|
+
sessionId: turnTelemetry.sessionId,
|
|
884
|
+
exitClassification: null
|
|
885
|
+
};
|
|
886
|
+
runtimeState.sessionId = turnTelemetry.sessionId;
|
|
887
|
+
emitTurnStartedEvent(turnTelemetry);
|
|
888
|
+
const result = await spawnNonCodexRuntimeTurn(
|
|
889
|
+
adapter,
|
|
890
|
+
runtimeKind,
|
|
891
|
+
renderedPrompt,
|
|
892
|
+
env
|
|
893
|
+
);
|
|
894
|
+
if (isNonCodexTurnFailure(result)) {
|
|
895
|
+
terminalFailure = describeNonCodexTurnFailure(result);
|
|
896
|
+
}
|
|
897
|
+
runtimeState.status = terminalFailure ? "failed" : "completed";
|
|
898
|
+
runtimeState.runPhase = terminalFailure ? "failed" : "succeeded";
|
|
899
|
+
if (runtimeState.run) {
|
|
900
|
+
runtimeState.run.lastError = terminalFailure;
|
|
901
|
+
}
|
|
902
|
+
runtimeState.sessionInfo.exitClassification = classifySessionExit({
|
|
903
|
+
runPhase: runtimeState.runPhase,
|
|
904
|
+
userInputRequired: terminalFailure === DEFAULT_AGENT_INPUT_REQUIRED_REASON || terminalFailure?.startsWith("turn_input_required:") === true,
|
|
905
|
+
budgetExceeded: false,
|
|
906
|
+
convergenceDetected: false,
|
|
907
|
+
maxTurnsReached: false
|
|
908
|
+
});
|
|
909
|
+
if (terminalFailure) {
|
|
910
|
+
emitTurnFailedEvent(turnTelemetry, terminalFailure);
|
|
911
|
+
} else {
|
|
912
|
+
emitTurnCompletedEvent(turnTelemetry);
|
|
913
|
+
}
|
|
914
|
+
} catch (error) {
|
|
915
|
+
const message = error instanceof Error ? error.message : "Unknown runtime adapter lifecycle error";
|
|
916
|
+
runtimeState.status = "failed";
|
|
917
|
+
runtimeState.runPhase = "failed";
|
|
918
|
+
if (runtimeState.run) {
|
|
919
|
+
runtimeState.run.lastError = message;
|
|
920
|
+
}
|
|
921
|
+
runtimeState.sessionInfo.exitClassification = classifySessionExit({
|
|
922
|
+
runPhase: runtimeState.runPhase,
|
|
923
|
+
userInputRequired: false,
|
|
924
|
+
budgetExceeded: false,
|
|
925
|
+
convergenceDetected: false,
|
|
926
|
+
maxTurnsReached: false
|
|
927
|
+
});
|
|
928
|
+
emitTurnFailedEvent(turnTelemetry, message);
|
|
929
|
+
} finally {
|
|
930
|
+
unsubscribe();
|
|
931
|
+
await adapter.shutdown();
|
|
932
|
+
runtimeAdapter = null;
|
|
933
|
+
childProcess = null;
|
|
934
|
+
runtimeState.runPhase = runtimeState.runPhase ?? "failed";
|
|
935
|
+
stopOrchestratorHeartbeatTimer();
|
|
936
|
+
emitOrchestratorHeartbeat();
|
|
937
|
+
await persistSessionTokenUsageArtifact(env);
|
|
938
|
+
await waitForPendingOrchestratorChannelFlush(
|
|
939
|
+
resolveTerminalOrchestratorChannelFlushTimeoutMs()
|
|
940
|
+
);
|
|
941
|
+
setTimeout(() => {
|
|
942
|
+
process.exit(runtimeState.status === "completed" ? 0 : 1);
|
|
943
|
+
}, 1500);
|
|
944
|
+
}
|
|
945
|
+
}
|
|
946
|
+
async function spawnNonCodexRuntimeTurn(adapter, runtimeKind, renderedPrompt, env) {
|
|
947
|
+
if (runtimeKind === "claude-print") {
|
|
948
|
+
return await adapter.spawnTurn({
|
|
949
|
+
messages: [{ type: "user", text: renderedPrompt }],
|
|
950
|
+
cwd: env.WORKING_DIRECTORY,
|
|
951
|
+
env
|
|
952
|
+
});
|
|
953
|
+
}
|
|
954
|
+
return await adapter.spawnTurn({
|
|
955
|
+
prompt: renderedPrompt,
|
|
956
|
+
cwd: env.WORKING_DIRECTORY,
|
|
957
|
+
env
|
|
958
|
+
});
|
|
959
|
+
}
|
|
960
|
+
function handleNonCodexRuntimeEvent(event) {
|
|
961
|
+
if (event.payload.suppressUpdate) {
|
|
962
|
+
return;
|
|
963
|
+
}
|
|
964
|
+
runtimeState.lastEventAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
965
|
+
switch (event.name) {
|
|
966
|
+
case "agent.tokenUsageUpdated": {
|
|
967
|
+
const tokenUsage = extractAbsoluteTokenUsage(event.payload.params);
|
|
968
|
+
if (tokenUsage) {
|
|
969
|
+
applyTokenUsageUpdate(
|
|
970
|
+
event.payload.observabilityEvent ?? event.name,
|
|
971
|
+
tokenUsage
|
|
972
|
+
);
|
|
973
|
+
}
|
|
974
|
+
break;
|
|
975
|
+
}
|
|
976
|
+
case "agent.rateLimit": {
|
|
977
|
+
const rateLimits = extractRateLimitPayload(event.payload.params);
|
|
978
|
+
if (rateLimits) {
|
|
979
|
+
applyRateLimitUpdate(
|
|
980
|
+
event.payload.observabilityEvent ?? event.name,
|
|
981
|
+
rateLimits,
|
|
982
|
+
"runtime-adapter"
|
|
983
|
+
);
|
|
984
|
+
}
|
|
985
|
+
break;
|
|
986
|
+
}
|
|
987
|
+
case "agent.inputRequired":
|
|
988
|
+
runtimeState.status = "failed";
|
|
989
|
+
if (runtimeState.run) {
|
|
990
|
+
runtimeState.run.lastError = event.payload.reason;
|
|
991
|
+
}
|
|
992
|
+
break;
|
|
993
|
+
case "agent.turnFailed":
|
|
994
|
+
case "agent.turnCancelled":
|
|
995
|
+
case "agent.error":
|
|
996
|
+
runtimeState.status = "failed";
|
|
997
|
+
if (runtimeState.run) {
|
|
998
|
+
runtimeState.run.lastError = event.name === "agent.error" ? event.payload.error : JSON.stringify(event.payload.params);
|
|
999
|
+
}
|
|
1000
|
+
break;
|
|
1001
|
+
default:
|
|
1002
|
+
break;
|
|
1003
|
+
}
|
|
1004
|
+
emitOrchestratorChannelEvent(event.payload.observabilityEvent ?? event.name);
|
|
1005
|
+
}
|
|
1006
|
+
function isNonCodexTurnFailure(result) {
|
|
1007
|
+
return result.result !== "success";
|
|
1008
|
+
}
|
|
1009
|
+
function describeNonCodexTurnFailure(result) {
|
|
1010
|
+
return result.errorMessage ?? `${result.command} exited with ${result.signal ?? result.exitCode ?? "unknown"}`;
|
|
1011
|
+
}
|
|
651
1012
|
async function exitWorkerStartupFailure(message) {
|
|
652
1013
|
runtimeState.status = "failed";
|
|
653
1014
|
runtimeState.runPhase = "failed";
|
|
@@ -1328,10 +1689,10 @@ function applyTokenUsageUpdate(source, tokenUsage) {
|
|
|
1328
1689
|
`
|
|
1329
1690
|
);
|
|
1330
1691
|
}
|
|
1331
|
-
function applyRateLimitUpdate(source, rateLimits) {
|
|
1692
|
+
function applyRateLimitUpdate(source, rateLimits, runtimeSource = "codex") {
|
|
1332
1693
|
runtimeState.rateLimits = {
|
|
1333
1694
|
...rateLimits,
|
|
1334
|
-
source:
|
|
1695
|
+
source: runtimeSource
|
|
1335
1696
|
};
|
|
1336
1697
|
process.stderr.write(
|
|
1337
1698
|
`[worker] rate_limits source=${source} payload=${JSON.stringify(runtimeState.rateLimits).slice(0, 300)}
|
|
@@ -1483,7 +1844,7 @@ function runToolProcess(toolDef, inputJson) {
|
|
|
1483
1844
|
...process.env,
|
|
1484
1845
|
...toolDef.env
|
|
1485
1846
|
};
|
|
1486
|
-
const toolProc =
|
|
1847
|
+
const toolProc = spawn2(toolDef.command, toolDef.args, {
|
|
1487
1848
|
env: toolEnv,
|
|
1488
1849
|
stdio: "pipe"
|
|
1489
1850
|
});
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
parseIssueReference,
|
|
4
|
+
readGitHubProjectBinding,
|
|
5
|
+
renderIssueWorkflowPreview,
|
|
6
|
+
resetWorkflowCommandDependenciesForTest,
|
|
7
|
+
setWorkflowCommandDependenciesForTest,
|
|
8
|
+
workflow_default
|
|
9
|
+
} from "./chunk-B4ZJMAZL.js";
|
|
10
|
+
import "./chunk-WM2B6BJ7.js";
|
|
11
|
+
import "./chunk-DLZAJXZL.js";
|
|
12
|
+
import "./chunk-Z3NZOPLZ.js";
|
|
13
|
+
import "./chunk-GPRCOJDJ.js";
|
|
14
|
+
import "./chunk-WOVNN5NW.js";
|
|
15
|
+
export {
|
|
16
|
+
workflow_default as default,
|
|
17
|
+
parseIssueReference,
|
|
18
|
+
readGitHubProjectBinding,
|
|
19
|
+
renderIssueWorkflowPreview,
|
|
20
|
+
resetWorkflowCommandDependenciesForTest,
|
|
21
|
+
setWorkflowCommandDependenciesForTest
|
|
22
|
+
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gh-symphony/cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.1.2",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"author": "hojinzs",
|
|
6
6
|
"description": "Interactive CLI for GitHub Symphony orchestration",
|
|
@@ -41,13 +41,13 @@
|
|
|
41
41
|
},
|
|
42
42
|
"devDependencies": {
|
|
43
43
|
"tsup": "^8.5.1",
|
|
44
|
-
"@gh-symphony/control-plane": "0.0.14",
|
|
45
44
|
"@gh-symphony/core": "0.0.14",
|
|
46
|
-
"@gh-symphony/orchestrator": "0.0.14",
|
|
47
45
|
"@gh-symphony/dashboard": "0.0.14",
|
|
46
|
+
"@gh-symphony/control-plane": "0.0.15",
|
|
47
|
+
"@gh-symphony/orchestrator": "0.0.14",
|
|
48
48
|
"@gh-symphony/runtime-claude": "0.0.14",
|
|
49
|
-
"@gh-symphony/
|
|
50
|
-
"@gh-symphony/
|
|
49
|
+
"@gh-symphony/worker": "0.0.14",
|
|
50
|
+
"@gh-symphony/tracker-github": "0.0.14"
|
|
51
51
|
},
|
|
52
52
|
"scripts": {
|
|
53
53
|
"build": "tsup",
|
package/dist/chunk-5NV3LSAJ.js
DELETED
package/dist/chunk-C7G7RJ4G.js
DELETED
|
@@ -1,146 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
import {
|
|
3
|
-
loadGlobalConfig,
|
|
4
|
-
loadProjectConfig
|
|
5
|
-
} from "./chunk-ROGRTUFI.js";
|
|
6
|
-
|
|
7
|
-
// src/project-selection.ts
|
|
8
|
-
import * as p from "@clack/prompts";
|
|
9
|
-
function isInteractiveTerminal() {
|
|
10
|
-
return process.stdin.isTTY === true && process.stdout.isTTY === true;
|
|
11
|
-
}
|
|
12
|
-
function explicitProjectRequiredMessage() {
|
|
13
|
-
return "Multiple projects are configured. Re-run with --project-id in non-interactive environments.\n";
|
|
14
|
-
}
|
|
15
|
-
async function inspectManagedProjectSelection(input) {
|
|
16
|
-
if (input.requestedProjectId) {
|
|
17
|
-
const projectConfig = await loadProjectConfig(
|
|
18
|
-
input.configDir,
|
|
19
|
-
input.requestedProjectId
|
|
20
|
-
);
|
|
21
|
-
if (!projectConfig) {
|
|
22
|
-
return {
|
|
23
|
-
kind: "requested_project_missing",
|
|
24
|
-
projectId: input.requestedProjectId,
|
|
25
|
-
message: `Project "${input.requestedProjectId}" is not configured. Run 'gh-symphony project add' or choose an existing project.`
|
|
26
|
-
};
|
|
27
|
-
}
|
|
28
|
-
return {
|
|
29
|
-
kind: "resolved",
|
|
30
|
-
projectId: input.requestedProjectId,
|
|
31
|
-
projectConfig
|
|
32
|
-
};
|
|
33
|
-
}
|
|
34
|
-
const global = await loadGlobalConfig(input.configDir);
|
|
35
|
-
if (!global) {
|
|
36
|
-
return {
|
|
37
|
-
kind: "missing_global_config",
|
|
38
|
-
message: "No CLI configuration found. Run 'gh-symphony project add' first."
|
|
39
|
-
};
|
|
40
|
-
}
|
|
41
|
-
const projectIds = global.projects ?? [];
|
|
42
|
-
if (projectIds.length === 0) {
|
|
43
|
-
return {
|
|
44
|
-
kind: "no_projects",
|
|
45
|
-
message: "No managed projects are configured. Run 'gh-symphony project add' first."
|
|
46
|
-
};
|
|
47
|
-
}
|
|
48
|
-
if (projectIds.length > 1 && !isInteractiveTerminal()) {
|
|
49
|
-
return {
|
|
50
|
-
kind: "multiple_projects_require_selection",
|
|
51
|
-
message: explicitProjectRequiredMessage().trimEnd()
|
|
52
|
-
};
|
|
53
|
-
}
|
|
54
|
-
if (global.activeProject) {
|
|
55
|
-
const projectConfig = await loadProjectConfig(
|
|
56
|
-
input.configDir,
|
|
57
|
-
global.activeProject
|
|
58
|
-
);
|
|
59
|
-
if (!projectConfig) {
|
|
60
|
-
return {
|
|
61
|
-
kind: "active_project_missing",
|
|
62
|
-
projectId: global.activeProject,
|
|
63
|
-
message: `Active project "${global.activeProject}" is configured in config.json but its project config is missing. Re-run 'gh-symphony project add' or 'gh-symphony project switch'.`
|
|
64
|
-
};
|
|
65
|
-
}
|
|
66
|
-
return {
|
|
67
|
-
kind: "resolved",
|
|
68
|
-
projectId: global.activeProject,
|
|
69
|
-
projectConfig
|
|
70
|
-
};
|
|
71
|
-
}
|
|
72
|
-
if (projectIds.length === 1) {
|
|
73
|
-
const projectId = projectIds[0];
|
|
74
|
-
const projectConfig = await loadProjectConfig(input.configDir, projectId);
|
|
75
|
-
if (!projectConfig) {
|
|
76
|
-
return {
|
|
77
|
-
kind: "configured_project_missing",
|
|
78
|
-
projectId,
|
|
79
|
-
message: `Configured project "${projectId}" is missing its project config file. Re-run 'gh-symphony project add'.`
|
|
80
|
-
};
|
|
81
|
-
}
|
|
82
|
-
return {
|
|
83
|
-
kind: "resolved",
|
|
84
|
-
projectId,
|
|
85
|
-
projectConfig
|
|
86
|
-
};
|
|
87
|
-
}
|
|
88
|
-
return {
|
|
89
|
-
kind: "multiple_projects_require_selection",
|
|
90
|
-
message: "Multiple projects are configured and no active project is set. Run 'gh-symphony project switch' or re-run with --project-id."
|
|
91
|
-
};
|
|
92
|
-
}
|
|
93
|
-
async function resolveManagedProjectConfig(input) {
|
|
94
|
-
if (input.requestedProjectId) {
|
|
95
|
-
return loadProjectConfig(input.configDir, input.requestedProjectId);
|
|
96
|
-
}
|
|
97
|
-
const global = await loadGlobalConfig(input.configDir);
|
|
98
|
-
const projectIds = global?.projects ?? [];
|
|
99
|
-
if (projectIds.length === 0) {
|
|
100
|
-
return null;
|
|
101
|
-
}
|
|
102
|
-
if (projectIds.length === 1) {
|
|
103
|
-
return loadProjectConfig(input.configDir, projectIds[0]);
|
|
104
|
-
}
|
|
105
|
-
if (!isInteractiveTerminal()) {
|
|
106
|
-
process.stderr.write(explicitProjectRequiredMessage());
|
|
107
|
-
process.exitCode = 1;
|
|
108
|
-
return null;
|
|
109
|
-
}
|
|
110
|
-
const projects = await Promise.all(
|
|
111
|
-
projectIds.map(async (projectId) => ({
|
|
112
|
-
projectId,
|
|
113
|
-
config: await loadProjectConfig(input.configDir, projectId)
|
|
114
|
-
}))
|
|
115
|
-
);
|
|
116
|
-
const selected = await p.select({
|
|
117
|
-
message: "Select a project:",
|
|
118
|
-
options: projects.map(({ projectId, config }) => ({
|
|
119
|
-
value: projectId,
|
|
120
|
-
label: config?.displayName ?? config?.slug ?? projectId,
|
|
121
|
-
hint: projectId === global?.activeProject ? "current" : config && config.displayName && config.displayName !== projectId ? projectId : void 0
|
|
122
|
-
})),
|
|
123
|
-
maxItems: 10
|
|
124
|
-
});
|
|
125
|
-
if (p.isCancel(selected)) {
|
|
126
|
-
p.cancel("Cancelled.");
|
|
127
|
-
process.exitCode = 130;
|
|
128
|
-
return null;
|
|
129
|
-
}
|
|
130
|
-
return loadProjectConfig(input.configDir, selected);
|
|
131
|
-
}
|
|
132
|
-
function handleMissingManagedProjectConfig() {
|
|
133
|
-
if (process.exitCode) {
|
|
134
|
-
return;
|
|
135
|
-
}
|
|
136
|
-
process.stderr.write(
|
|
137
|
-
"No project configured. Run 'gh-symphony project add' first.\n"
|
|
138
|
-
);
|
|
139
|
-
process.exitCode = 1;
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
export {
|
|
143
|
-
inspectManagedProjectSelection,
|
|
144
|
-
resolveManagedProjectConfig,
|
|
145
|
-
handleMissingManagedProjectConfig
|
|
146
|
-
};
|