@gh-symphony/cli 0.0.21 → 0.0.22

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.
Files changed (38) hide show
  1. package/README.md +36 -0
  2. package/dist/{chunk-SXGT7LOF.js → chunk-2TSM3INR.js} +26 -1
  3. package/dist/{chunk-A67CMOYE.js → chunk-2UW7NQLX.js} +1 -1
  4. package/dist/{chunk-MVRF7BES.js → chunk-36KYEDEO.js} +10 -1
  5. package/dist/{chunk-C7G7RJ4G.js → chunk-DDL4BWSL.js} +1 -1
  6. package/dist/{chunk-XN5ABWZ6.js → chunk-DFLXHNYQ.js} +26 -30
  7. package/dist/{chunk-KY6WKH66.js → chunk-E7HYEEZD.js} +70 -52
  8. package/dist/{chunk-QEONJ5DZ.js → chunk-EEQQWTXS.js} +1288 -92
  9. package/dist/chunk-GDE6FYN4.js +26 -0
  10. package/dist/{chunk-Y6TYJMNT.js → chunk-GSX2FV3M.js} +10 -16
  11. package/dist/{chunk-JN3TQVFV.js → chunk-HMLBBZNY.js} +11 -2
  12. package/dist/{chunk-5NV3LSAJ.js → chunk-IWFX2FMA.js} +5 -1
  13. package/dist/{chunk-MYVJ6HK4.js → chunk-PUDXVBSN.js} +706 -376
  14. package/dist/{chunk-ROGRTUFI.js → chunk-QIRE2VXS.js} +14 -3
  15. package/dist/{chunk-S6VIK4FF.js → chunk-ZHOKYUO3.js} +337 -13
  16. package/dist/{config-cmd-DNXNL26Z.js → config-cmd-Z3A7V6NC.js} +1 -1
  17. package/dist/{doctor-4HBRICHP.js → doctor-EJUMPBMW.js} +4 -4
  18. package/dist/index.js +88 -21
  19. package/dist/{init-HZ3JEDGQ.js → init-54HMKNYI.js} +3 -3
  20. package/dist/{logs-6JKKYDGJ.js → logs-GTZ4U5JE.js} +2 -2
  21. package/dist/project-RMYMZSFV.js +25 -0
  22. package/dist/{recover-L3MJHHDA.js → recover-LTLKMTRX.js} +7 -7
  23. package/dist/repo-WI7GF6XQ.js +749 -0
  24. package/dist/{run-XJQ6BF7U.js → run-IHN3ZL35.js} +21 -9
  25. package/dist/{setup-B2SVLW2R.js → setup-TZJSM3QV.js} +14 -13
  26. package/dist/start-RTAHQMR2.js +19 -0
  27. package/dist/status-F4D52OVK.js +12 -0
  28. package/dist/stop-MDKMJPVR.js +10 -0
  29. package/dist/{upgrade-OJXPZRYE.js → upgrade-O33S2SJK.js} +2 -2
  30. package/dist/{version-TBDCTKDO.js → version-CW54Q7BK.js} +1 -1
  31. package/dist/worker-entry.js +369 -13
  32. package/dist/{workflow-BLJH2HC3.js → workflow-L3KT6HB7.js} +5 -5
  33. package/package.json +3 -3
  34. package/dist/project-25NQ4J4Y.js +0 -24
  35. package/dist/repo-TDCWQR6P.js +0 -379
  36. package/dist/start-I2CC7BLW.js +0 -18
  37. package/dist/status-QSCFVGRQ.js +0 -11
  38. package/dist/stop-7MFCBQVW.js +0 -9
@@ -1,18 +1,18 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  runCli
4
- } from "./chunk-MYVJ6HK4.js";
5
- import "./chunk-A67CMOYE.js";
6
- import "./chunk-SXGT7LOF.js";
7
- import "./chunk-QEONJ5DZ.js";
4
+ } from "./chunk-PUDXVBSN.js";
5
+ import "./chunk-2UW7NQLX.js";
6
+ import "./chunk-2TSM3INR.js";
7
+ import "./chunk-EEQQWTXS.js";
8
8
  import {
9
9
  resolveRuntimeRoot
10
- } from "./chunk-5NV3LSAJ.js";
10
+ } from "./chunk-IWFX2FMA.js";
11
11
  import {
12
12
  handleMissingManagedProjectConfig,
13
13
  resolveManagedProjectConfig
14
- } from "./chunk-C7G7RJ4G.js";
15
- import "./chunk-ROGRTUFI.js";
14
+ } from "./chunk-DDL4BWSL.js";
15
+ import "./chunk-QIRE2VXS.js";
16
16
 
17
17
  // src/commands/run.ts
18
18
  function parseRunArgs(args) {
@@ -72,10 +72,22 @@ var handler = async (args, options) => {
72
72
  const runtimeRoot = resolveRuntimeRoot(options.configDir);
73
73
  const projectId = projectConfig.projectId;
74
74
  const [repoSpec] = parsed.issue.split("#");
75
- if (repoSpec && !projectConfig.repositories.some((r) => `${r.owner}/${r.name}` === repoSpec)) {
75
+ const configuredRepos = [
76
+ ...projectConfig.repository ? [projectConfig.repository] : [],
77
+ ...projectConfig.repositories ?? []
78
+ ].filter((repository) => repository.owner && repository.name).map((repository) => `${repository.owner}/${repository.name}`);
79
+ const configuredRepoSet = new Set(configuredRepos);
80
+ if (configuredRepoSet.size === 0) {
81
+ process.stderr.write(
82
+ "No repository is configured in this project. Run 'gh-symphony repo add owner/name' first.\n"
83
+ );
84
+ process.exitCode = 1;
85
+ return;
86
+ }
87
+ if (repoSpec && !configuredRepoSet.has(repoSpec)) {
76
88
  process.stderr.write(
77
89
  `Repository "${repoSpec}" is not configured in this project.
78
- Configured repos: ${projectConfig.repositories.map((r) => `${r.owner}/${r.name}`).join(", ")}
90
+ Configured repo: ${configuredRepos.join(", ")}
79
91
  `
80
92
  );
81
93
  process.exitCode = 1;
@@ -2,7 +2,7 @@
2
2
  import {
3
3
  promptProjectRegistrationOptions,
4
4
  renderProjectRegistrationSummary
5
- } from "./chunk-S6VIK4FF.js";
5
+ } from "./chunk-ZHOKYUO3.js";
6
6
  import {
7
7
  abortIfCancelled,
8
8
  buildAutomaticStateMappings,
@@ -16,11 +16,11 @@ import {
16
16
  writeConfig,
17
17
  writeEcosystem,
18
18
  writeWorkflowPlan
19
- } from "./chunk-JN3TQVFV.js";
20
- import "./chunk-KY6WKH66.js";
21
- import "./chunk-MYVJ6HK4.js";
22
- import "./chunk-A67CMOYE.js";
23
- import "./chunk-SXGT7LOF.js";
19
+ } from "./chunk-HMLBBZNY.js";
20
+ import "./chunk-E7HYEEZD.js";
21
+ import "./chunk-PUDXVBSN.js";
22
+ import "./chunk-2UW7NQLX.js";
23
+ import "./chunk-2TSM3INR.js";
24
24
  import {
25
25
  GhAuthError,
26
26
  GitHubScopeError,
@@ -32,13 +32,14 @@ import {
32
32
  listUserProjects,
33
33
  validateToken
34
34
  } from "./chunk-C67H3OUL.js";
35
- import "./chunk-QEONJ5DZ.js";
36
- import "./chunk-XN5ABWZ6.js";
37
- import "./chunk-MVRF7BES.js";
38
- import "./chunk-5NV3LSAJ.js";
39
- import "./chunk-Y6TYJMNT.js";
40
- import "./chunk-C7G7RJ4G.js";
41
- import "./chunk-ROGRTUFI.js";
35
+ import "./chunk-EEQQWTXS.js";
36
+ import "./chunk-DFLXHNYQ.js";
37
+ import "./chunk-36KYEDEO.js";
38
+ import "./chunk-IWFX2FMA.js";
39
+ import "./chunk-GSX2FV3M.js";
40
+ import "./chunk-GDE6FYN4.js";
41
+ import "./chunk-DDL4BWSL.js";
42
+ import "./chunk-QIRE2VXS.js";
42
43
 
43
44
  // src/commands/setup.ts
44
45
  import * as p from "@clack/prompts";
@@ -0,0 +1,19 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ shutdownForegroundOrchestrator,
4
+ start_default
5
+ } from "./chunk-E7HYEEZD.js";
6
+ import "./chunk-PUDXVBSN.js";
7
+ import "./chunk-2UW7NQLX.js";
8
+ import "./chunk-2TSM3INR.js";
9
+ import "./chunk-C67H3OUL.js";
10
+ import "./chunk-EEQQWTXS.js";
11
+ import "./chunk-36KYEDEO.js";
12
+ import "./chunk-IWFX2FMA.js";
13
+ import "./chunk-GDE6FYN4.js";
14
+ import "./chunk-DDL4BWSL.js";
15
+ import "./chunk-QIRE2VXS.js";
16
+ export {
17
+ start_default as default,
18
+ shutdownForegroundOrchestrator
19
+ };
@@ -0,0 +1,12 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ status_default
4
+ } from "./chunk-DFLXHNYQ.js";
5
+ import "./chunk-36KYEDEO.js";
6
+ import "./chunk-IWFX2FMA.js";
7
+ import "./chunk-GDE6FYN4.js";
8
+ import "./chunk-DDL4BWSL.js";
9
+ import "./chunk-QIRE2VXS.js";
10
+ export {
11
+ status_default as default
12
+ };
@@ -0,0 +1,10 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ stop_default
4
+ } from "./chunk-GSX2FV3M.js";
5
+ import "./chunk-GDE6FYN4.js";
6
+ import "./chunk-DDL4BWSL.js";
7
+ import "./chunk-QIRE2VXS.js";
8
+ export {
9
+ stop_default as default
10
+ };
@@ -16,8 +16,8 @@ function execFileAsync(file, args, execFileImpl = execFileCallback) {
16
16
  });
17
17
  }
18
18
  function resolveCurrentCliVersion() {
19
- if ("0.0.21".length > 0) {
20
- return "0.0.21";
19
+ if ("0.0.22".length > 0) {
20
+ return "0.0.22";
21
21
  }
22
22
  const pkg = JSON.parse(
23
23
  readFileSync(new URL("../../package.json", import.meta.url), "utf8")
@@ -2,7 +2,7 @@
2
2
 
3
3
  // src/commands/version.ts
4
4
  var handler = async (_args, options) => {
5
- const version = "0.0.21";
5
+ const version = "0.0.22";
6
6
  if (options.json) {
7
7
  process.stdout.write(JSON.stringify({ version }) + "\n");
8
8
  } else {
@@ -6,20 +6,22 @@ import {
6
6
  normalizeCodexRuntimeEvents,
7
7
  prepareCodexRuntimePlan,
8
8
  resolveLocalRuntimeLaunchConfig
9
- } from "./chunk-A67CMOYE.js";
9
+ } from "./chunk-2UW7NQLX.js";
10
10
  import {
11
11
  DEFAULT_AGENT_INPUT_REQUIRED_REASON,
12
12
  classifySessionExit,
13
+ createClaudePrintRuntimeAdapter,
14
+ extractEnvForClaude,
13
15
  formatClaudePreflightText,
14
16
  isClaudeRuntimeCommand,
15
17
  parseWorkflowMarkdown,
16
18
  resolveClaudeCommandBinary,
17
19
  resolveWorkflowRuntimeCommand,
18
20
  runClaudePreflight
19
- } from "./chunk-QEONJ5DZ.js";
21
+ } from "./chunk-EEQQWTXS.js";
20
22
 
21
23
  // ../worker/src/index.ts
22
- import { spawn } from "child_process";
24
+ import { spawn as spawn2 } from "child_process";
23
25
  import { readFile } from "fs/promises";
24
26
  import { join as join2 } from "path";
25
27
 
@@ -124,6 +126,152 @@ function normalizeError(value) {
124
126
  return normalized.length > 0 ? normalized : null;
125
127
  }
126
128
 
129
+ // ../worker/src/non-codex-runtime.ts
130
+ import {
131
+ spawn
132
+ } from "child_process";
133
+ import { finished } from "stream/promises";
134
+ var CustomCommandWorkerRuntimeAdapter = class {
135
+ constructor(config, dependencies = {}) {
136
+ this.config = config;
137
+ this.dependencies = dependencies;
138
+ }
139
+ activeChild = null;
140
+ prepare() {
141
+ }
142
+ async spawnTurn(input) {
143
+ const command = this.config.command;
144
+ const args = [...this.config.args];
145
+ const cwd = input.cwd ?? this.config.workingDirectory;
146
+ const child = (this.dependencies.spawnImpl ?? spawn)(command, args, {
147
+ cwd,
148
+ env: {
149
+ ...this.config.env,
150
+ ...input.env,
151
+ SYMPHONY_RENDERED_PROMPT: input.prompt
152
+ },
153
+ stdio: "pipe"
154
+ });
155
+ this.activeChild = child;
156
+ this.config.onSpawned?.(child);
157
+ let stdout = "";
158
+ let stderr = "";
159
+ let spawnError;
160
+ child.stdout?.setEncoding("utf8");
161
+ child.stderr?.setEncoding("utf8");
162
+ child.stdout?.on("data", (chunk) => {
163
+ stdout += chunk;
164
+ });
165
+ child.stderr?.on("data", (chunk) => {
166
+ stderr += chunk;
167
+ });
168
+ child.once("error", (error) => {
169
+ spawnError = error.message;
170
+ });
171
+ if (child.stdin && !child.stdin.destroyed) {
172
+ child.stdin.end(input.prompt);
173
+ }
174
+ const { exitCode, signal } = await waitForChildExit(child);
175
+ await Promise.all([
176
+ child.stdout ? finished(child.stdout).catch(() => void 0) : void 0,
177
+ child.stderr ? finished(child.stderr).catch(() => void 0) : void 0
178
+ ]);
179
+ this.activeChild = null;
180
+ const result = exitCode === 0 && signal === null && !spawnError ? "success" : "process-error";
181
+ return {
182
+ command,
183
+ args,
184
+ cwd,
185
+ stdout,
186
+ stderr,
187
+ exitCode,
188
+ signal,
189
+ result,
190
+ errorMessage: spawnError
191
+ };
192
+ }
193
+ onEvent(_handler) {
194
+ return () => {
195
+ };
196
+ }
197
+ resolveCredentials(brokerResponse) {
198
+ if (!this.config.authEnvKey) {
199
+ return {};
200
+ }
201
+ return extractEnvForClaude(brokerResponse.env, this.config.authEnvKey);
202
+ }
203
+ shutdown() {
204
+ this.stopActiveChild();
205
+ }
206
+ cancel() {
207
+ this.stopActiveChild();
208
+ }
209
+ stopActiveChild() {
210
+ if (!this.activeChild || this.activeChild.killed) {
211
+ this.activeChild = null;
212
+ return;
213
+ }
214
+ this.activeChild.kill("SIGTERM");
215
+ this.activeChild = null;
216
+ }
217
+ };
218
+ function createWorkerNonCodexRuntimeAdapter(workflow, context) {
219
+ const runtime = workflow.runtime;
220
+ if (!runtime || runtime.kind === "codex-app-server") {
221
+ throw new Error(
222
+ "Worker non-Codex runtime adapter requested for a Codex runtime."
223
+ );
224
+ }
225
+ switch (runtime.kind) {
226
+ case "claude-print":
227
+ return createClaudePrintRuntimeAdapter(
228
+ {
229
+ workingDirectory: context.workingDirectory,
230
+ runtimeRoot: context.runtimeRoot,
231
+ runtimeDirectory: context.runtimeDirectory,
232
+ command: runtime.command,
233
+ args: runtime.args,
234
+ env: context.env,
235
+ authEnvKey: runtime.auth.env ?? void 0,
236
+ isolation: {
237
+ bare: runtime.isolation.bare,
238
+ strictMcpConfig: runtime.isolation.strictMcpConfig
239
+ }
240
+ },
241
+ {
242
+ ...context.claudeDependencies,
243
+ onSpawned: context.onSpawned
244
+ }
245
+ );
246
+ case "custom":
247
+ return new CustomCommandWorkerRuntimeAdapter(
248
+ {
249
+ workingDirectory: context.workingDirectory,
250
+ command: runtime.command,
251
+ args: runtime.args,
252
+ env: context.env,
253
+ authEnvKey: runtime.auth.env ?? void 0,
254
+ onSpawned: context.onSpawned
255
+ },
256
+ context.customDependencies
257
+ );
258
+ }
259
+ }
260
+ function waitForChildExit(child) {
261
+ return new Promise((resolve) => {
262
+ let settled = false;
263
+ const settle = (exitCode, signal) => {
264
+ if (settled) {
265
+ return;
266
+ }
267
+ settled = true;
268
+ resolve({ exitCode, signal });
269
+ };
270
+ child.once("exit", settle);
271
+ child.once("error", () => settle(1, null));
272
+ });
273
+ }
274
+
127
275
  // ../worker/src/run-phase.ts
128
276
  var TERMINAL_RUN_PHASES = /* @__PURE__ */ new Set([
129
277
  "succeeded",
@@ -139,6 +287,15 @@ function resolveExitRunPhase(currentRunPhase, exit) {
139
287
  return exit.code === 0 && !exit.signal ? "succeeded" : "failed";
140
288
  }
141
289
 
290
+ // ../worker/src/runtime-routing.ts
291
+ function resolveWorkerRuntimeRoute(workflow) {
292
+ const kind = workflow.runtime?.kind;
293
+ if (!kind || kind === "codex-app-server") {
294
+ return "codex-app-server";
295
+ }
296
+ return "runtime-adapter";
297
+ }
298
+
142
299
  // ../worker/src/thread-resume.ts
143
300
  var DEFAULT_CONTINUATION_GUIDANCE = "Continue working on the issue. Review your progress and complete any remaining tasks.";
144
301
  function parseNonNegativeInteger(value) {
@@ -298,6 +455,7 @@ console.log(
298
455
  )
299
456
  );
300
457
  var childProcess = null;
458
+ var runtimeAdapter = null;
301
459
  var shutdownPromise = null;
302
460
  var orchestratorChannelDrainPending = false;
303
461
  var pendingOrchestratorChannelPayloads = [];
@@ -328,6 +486,7 @@ function shutdown(signal) {
328
486
  } catch {
329
487
  }
330
488
  }
489
+ await runtimeAdapter?.cancel(`worker received ${signal}`);
331
490
  stopOrchestratorHeartbeatTimer();
332
491
  emitOrchestratorHeartbeat();
333
492
  await persistSessionTokenUsageArtifact(launcherEnv);
@@ -569,7 +728,8 @@ async function startAssignedRun() {
569
728
  await readFile(workflowPath, "utf8"),
570
729
  launcherEnv
571
730
  );
572
- if (isClaudeRuntimeCommand(workflow.codex.command)) {
731
+ const route = resolveWorkerRuntimeRoute(workflow);
732
+ if (route === "runtime-adapter" && workflow.runtime?.kind === "claude-print" && isClaudeRuntimeCommand(resolveWorkflowRuntimeCommand(workflow))) {
573
733
  const hasGitHubGraphqlToken = typeof launcherEnv.GITHUB_GRAPHQL_TOKEN === "string" && launcherEnv.GITHUB_GRAPHQL_TOKEN.trim().length > 0;
574
734
  const preflight = await runClaudePreflight({
575
735
  cwd: launcherEnv.WORKING_DIRECTORY,
@@ -587,19 +747,19 @@ async function startAssignedRun() {
587
747
  );
588
748
  return;
589
749
  }
590
- await exitWorkerStartupFailure(
591
- "Claude runtime worker launch is not yet implemented in this branch."
592
- );
593
- return;
594
750
  }
595
751
  runtimeState.executionPhase = resolveInitialExecutionPhase({
596
752
  issueState: runtimeState.run?.state,
597
753
  blockerCheckStates: workflow.lifecycle.blockerCheckStates,
598
754
  activeStates: workflow.lifecycle.activeStates
599
755
  });
756
+ runtimeState.runPhase = "launching_agent";
757
+ if (route === "runtime-adapter") {
758
+ await runNonCodexRuntimeAdapterLifecycle(workflow, launcherEnv);
759
+ return;
760
+ }
600
761
  const config = resolveLocalRuntimeLaunchConfig(launcherEnv);
601
762
  config.agentCommand = resolveWorkflowRuntimeCommand(workflow);
602
- runtimeState.runPhase = "launching_agent";
603
763
  const plan = await prepareCodexRuntimePlan(config);
604
764
  childProcess = launchCodexAppServer(plan);
605
765
  runtimeState.status = "running";
@@ -640,14 +800,210 @@ async function startAssignedRun() {
640
800
  void persistSessionTokenUsageArtifact(launcherEnv);
641
801
  });
642
802
  } catch (error) {
803
+ const message = error instanceof Error ? error.message : "Unknown worker startup error";
643
804
  runtimeState.status = "failed";
644
805
  runtimeState.runPhase = "failed";
645
806
  if (runtimeState.run) {
646
- runtimeState.run.lastError = error instanceof Error ? error.message : "Unknown worker startup error";
807
+ runtimeState.run.lastError = message;
647
808
  }
809
+ process.stderr.write(`[worker] startup failed: ${message}
810
+ `);
648
811
  await persistSessionTokenUsageArtifact(launcherEnv);
649
812
  }
650
813
  }
814
+ async function runNonCodexRuntimeAdapterLifecycle(workflow, env) {
815
+ const renderedPrompt = env.SYMPHONY_RENDERED_PROMPT;
816
+ if (!renderedPrompt) {
817
+ await exitWorkerStartupFailure(
818
+ "SYMPHONY_RENDERED_PROMPT not set; cannot run runtime adapter lifecycle."
819
+ );
820
+ return;
821
+ }
822
+ const runId = env.SYMPHONY_RUN_ID;
823
+ if (!runId) {
824
+ await exitWorkerStartupFailure(
825
+ "SYMPHONY_RUN_ID not set; cannot prepare runtime adapter lifecycle."
826
+ );
827
+ return;
828
+ }
829
+ const runtimeKind = workflow.runtime?.kind;
830
+ if (runtimeKind !== "claude-print" && runtimeKind !== "custom") {
831
+ await exitWorkerStartupFailure(
832
+ "Runtime adapter lifecycle requested for an unsupported runtime kind."
833
+ );
834
+ return;
835
+ }
836
+ const adapter = createWorkerNonCodexRuntimeAdapter(workflow, {
837
+ workingDirectory: env.WORKING_DIRECTORY,
838
+ env,
839
+ runtimeRoot: env.WORKSPACE_RUNTIME_DIR,
840
+ runtimeDirectory: env.WORKSPACE_RUNTIME_DIR,
841
+ onSpawned: (child) => {
842
+ childProcess = child;
843
+ if (runtimeState.run) {
844
+ runtimeState.run.processId = child.pid ?? null;
845
+ }
846
+ }
847
+ });
848
+ runtimeAdapter = adapter;
849
+ let terminalFailure = null;
850
+ const unsubscribe = adapter.onEvent((event) => {
851
+ const agentEvent = event;
852
+ handleNonCodexRuntimeEvent(agentEvent);
853
+ if (agentEvent.name === "agent.inputRequired") {
854
+ terminalFailure = agentEvent.payload.reason;
855
+ }
856
+ if (agentEvent.name === "agent.turnFailed" || agentEvent.name === "agent.error") {
857
+ terminalFailure = agentEvent.name === "agent.error" ? agentEvent.payload.error : JSON.stringify(agentEvent.payload.params);
858
+ }
859
+ });
860
+ const turnTelemetry = {
861
+ startedAt: (/* @__PURE__ */ new Date()).toISOString(),
862
+ threadId: null,
863
+ turnId: `${runId}-turn-1`,
864
+ turnCount: 1,
865
+ sessionId: runId,
866
+ tokenUsageBaseline: cloneTokenUsageSnapshot()
867
+ };
868
+ try {
869
+ await adapter.prepare({
870
+ runId
871
+ });
872
+ runtimeState.status = "running";
873
+ runtimeState.runPhase = "streaming_turn";
874
+ runtimeState.sessionInfo = {
875
+ threadId: turnTelemetry.threadId,
876
+ turnId: turnTelemetry.turnId,
877
+ turnCount: turnTelemetry.turnCount,
878
+ sessionId: turnTelemetry.sessionId,
879
+ exitClassification: null
880
+ };
881
+ runtimeState.sessionId = turnTelemetry.sessionId;
882
+ emitTurnStartedEvent(turnTelemetry);
883
+ const result = await spawnNonCodexRuntimeTurn(
884
+ adapter,
885
+ runtimeKind,
886
+ renderedPrompt,
887
+ env
888
+ );
889
+ if (isNonCodexTurnFailure(result)) {
890
+ terminalFailure = describeNonCodexTurnFailure(result);
891
+ }
892
+ runtimeState.status = terminalFailure ? "failed" : "completed";
893
+ runtimeState.runPhase = terminalFailure ? "failed" : "succeeded";
894
+ if (runtimeState.run) {
895
+ runtimeState.run.lastError = terminalFailure;
896
+ }
897
+ runtimeState.sessionInfo.exitClassification = classifySessionExit({
898
+ runPhase: runtimeState.runPhase,
899
+ userInputRequired: terminalFailure === DEFAULT_AGENT_INPUT_REQUIRED_REASON || terminalFailure?.startsWith("turn_input_required:") === true,
900
+ budgetExceeded: false,
901
+ convergenceDetected: false,
902
+ maxTurnsReached: false
903
+ });
904
+ if (terminalFailure) {
905
+ emitTurnFailedEvent(turnTelemetry, terminalFailure);
906
+ } else {
907
+ emitTurnCompletedEvent(turnTelemetry);
908
+ }
909
+ } catch (error) {
910
+ const message = error instanceof Error ? error.message : "Unknown runtime adapter lifecycle error";
911
+ runtimeState.status = "failed";
912
+ runtimeState.runPhase = "failed";
913
+ if (runtimeState.run) {
914
+ runtimeState.run.lastError = message;
915
+ }
916
+ runtimeState.sessionInfo.exitClassification = classifySessionExit({
917
+ runPhase: runtimeState.runPhase,
918
+ userInputRequired: false,
919
+ budgetExceeded: false,
920
+ convergenceDetected: false,
921
+ maxTurnsReached: false
922
+ });
923
+ emitTurnFailedEvent(turnTelemetry, message);
924
+ } finally {
925
+ unsubscribe();
926
+ await adapter.shutdown();
927
+ runtimeAdapter = null;
928
+ childProcess = null;
929
+ runtimeState.runPhase = runtimeState.runPhase ?? "failed";
930
+ stopOrchestratorHeartbeatTimer();
931
+ emitOrchestratorHeartbeat();
932
+ await persistSessionTokenUsageArtifact(env);
933
+ await waitForPendingOrchestratorChannelFlush(
934
+ resolveTerminalOrchestratorChannelFlushTimeoutMs()
935
+ );
936
+ setTimeout(() => {
937
+ process.exit(runtimeState.status === "completed" ? 0 : 1);
938
+ }, 1500);
939
+ }
940
+ }
941
+ async function spawnNonCodexRuntimeTurn(adapter, runtimeKind, renderedPrompt, env) {
942
+ if (runtimeKind === "claude-print") {
943
+ return await adapter.spawnTurn({
944
+ messages: [{ type: "user", text: renderedPrompt }],
945
+ cwd: env.WORKING_DIRECTORY,
946
+ env
947
+ });
948
+ }
949
+ return await adapter.spawnTurn({
950
+ prompt: renderedPrompt,
951
+ cwd: env.WORKING_DIRECTORY,
952
+ env
953
+ });
954
+ }
955
+ function handleNonCodexRuntimeEvent(event) {
956
+ if (event.payload.suppressUpdate) {
957
+ return;
958
+ }
959
+ runtimeState.lastEventAt = (/* @__PURE__ */ new Date()).toISOString();
960
+ switch (event.name) {
961
+ case "agent.tokenUsageUpdated": {
962
+ const tokenUsage = extractAbsoluteTokenUsage(event.payload.params);
963
+ if (tokenUsage) {
964
+ applyTokenUsageUpdate(
965
+ event.payload.observabilityEvent ?? event.name,
966
+ tokenUsage
967
+ );
968
+ }
969
+ break;
970
+ }
971
+ case "agent.rateLimit": {
972
+ const rateLimits = extractRateLimitPayload(event.payload.params);
973
+ if (rateLimits) {
974
+ applyRateLimitUpdate(
975
+ event.payload.observabilityEvent ?? event.name,
976
+ rateLimits,
977
+ "runtime-adapter"
978
+ );
979
+ }
980
+ break;
981
+ }
982
+ case "agent.inputRequired":
983
+ runtimeState.status = "failed";
984
+ if (runtimeState.run) {
985
+ runtimeState.run.lastError = event.payload.reason;
986
+ }
987
+ break;
988
+ case "agent.turnFailed":
989
+ case "agent.turnCancelled":
990
+ case "agent.error":
991
+ runtimeState.status = "failed";
992
+ if (runtimeState.run) {
993
+ runtimeState.run.lastError = event.name === "agent.error" ? event.payload.error : JSON.stringify(event.payload.params);
994
+ }
995
+ break;
996
+ default:
997
+ break;
998
+ }
999
+ emitOrchestratorChannelEvent(event.payload.observabilityEvent ?? event.name);
1000
+ }
1001
+ function isNonCodexTurnFailure(result) {
1002
+ return result.result !== "success";
1003
+ }
1004
+ function describeNonCodexTurnFailure(result) {
1005
+ return result.errorMessage ?? `${result.command} exited with ${result.signal ?? result.exitCode ?? "unknown"}`;
1006
+ }
651
1007
  async function exitWorkerStartupFailure(message) {
652
1008
  runtimeState.status = "failed";
653
1009
  runtimeState.runPhase = "failed";
@@ -1328,10 +1684,10 @@ function applyTokenUsageUpdate(source, tokenUsage) {
1328
1684
  `
1329
1685
  );
1330
1686
  }
1331
- function applyRateLimitUpdate(source, rateLimits) {
1687
+ function applyRateLimitUpdate(source, rateLimits, runtimeSource = "codex") {
1332
1688
  runtimeState.rateLimits = {
1333
1689
  ...rateLimits,
1334
- source: "codex"
1690
+ source: runtimeSource
1335
1691
  };
1336
1692
  process.stderr.write(
1337
1693
  `[worker] rate_limits source=${source} payload=${JSON.stringify(runtimeState.rateLimits).slice(0, 300)}
@@ -1483,7 +1839,7 @@ function runToolProcess(toolDef, inputJson) {
1483
1839
  ...process.env,
1484
1840
  ...toolDef.env
1485
1841
  };
1486
- const toolProc = spawn(toolDef.command, toolDef.args, {
1842
+ const toolProc = spawn2(toolDef.command, toolDef.args, {
1487
1843
  env: toolEnv,
1488
1844
  stdio: "pipe"
1489
1845
  });
@@ -1,10 +1,10 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  init_default
4
- } from "./chunk-JN3TQVFV.js";
4
+ } from "./chunk-HMLBBZNY.js";
5
5
  import {
6
6
  fetchGithubProjectIssueByRepositoryAndNumber
7
- } from "./chunk-SXGT7LOF.js";
7
+ } from "./chunk-2TSM3INR.js";
8
8
  import {
9
9
  GitHubApiError,
10
10
  createClient,
@@ -17,11 +17,11 @@ import {
17
17
  buildPromptVariables,
18
18
  parseWorkflowMarkdown,
19
19
  renderPrompt
20
- } from "./chunk-QEONJ5DZ.js";
20
+ } from "./chunk-EEQQWTXS.js";
21
21
  import {
22
22
  inspectManagedProjectSelection
23
- } from "./chunk-C7G7RJ4G.js";
24
- import "./chunk-ROGRTUFI.js";
23
+ } from "./chunk-DDL4BWSL.js";
24
+ import "./chunk-QIRE2VXS.js";
25
25
 
26
26
  // src/commands/workflow.ts
27
27
  import { readFile } from "fs/promises";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gh-symphony/cli",
3
- "version": "0.0.21",
3
+ "version": "0.0.22",
4
4
  "license": "MIT",
5
5
  "author": "hojinzs",
6
6
  "description": "Interactive CLI for GitHub Symphony orchestration",
@@ -41,10 +41,10 @@
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",
45
+ "@gh-symphony/control-plane": "0.0.15",
47
46
  "@gh-symphony/dashboard": "0.0.14",
47
+ "@gh-symphony/orchestrator": "0.0.14",
48
48
  "@gh-symphony/runtime-claude": "0.0.14",
49
49
  "@gh-symphony/tracker-github": "0.0.14",
50
50
  "@gh-symphony/worker": "0.0.14"