@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.
Files changed (36) hide show
  1. package/README.md +100 -69
  2. package/dist/chunk-6I753NYO.js +18 -0
  3. package/dist/{workflow-BLJH2HC3.js → chunk-B4ZJMAZL.js} +27 -19
  4. package/dist/{chunk-SXGT7LOF.js → chunk-DLZAJXZL.js} +600 -12
  5. package/dist/chunk-GHVDABFO.js +235 -0
  6. package/dist/{chunk-QEONJ5DZ.js → chunk-GPRCOJDJ.js} +1314 -35
  7. package/dist/{chunk-A67CMOYE.js → chunk-VFHMHHZW.js} +1 -1
  8. package/dist/{chunk-JN3TQVFV.js → chunk-WM2B6BJ7.js} +16 -62
  9. package/dist/{chunk-ROGRTUFI.js → chunk-WOVNN5NW.js} +16 -6
  10. package/dist/{chunk-C67H3OUL.js → chunk-Z3NZOPLZ.js} +0 -81
  11. package/dist/{config-cmd-DNXNL26Z.js → config-cmd-2ADPUYWA.js} +1 -1
  12. package/dist/{doctor-4HBRICHP.js → doctor-EEPNFCGF.js} +464 -40
  13. package/dist/index.js +357 -244
  14. package/dist/repo-RX4OK7XH.js +6783 -0
  15. package/dist/{setup-B2SVLW2R.js → setup-XNHHRBGU.js} +57 -91
  16. package/dist/{upgrade-OJXPZRYE.js → upgrade-NS53EO2B.js} +2 -2
  17. package/dist/{version-TBDCTKDO.js → version-2RHFZ5CI.js} +1 -1
  18. package/dist/worker-entry.js +376 -15
  19. package/dist/workflow-26QNZZWH.js +22 -0
  20. package/package.json +5 -5
  21. package/dist/chunk-5NV3LSAJ.js +0 -11
  22. package/dist/chunk-C7G7RJ4G.js +0 -146
  23. package/dist/chunk-KY6WKH66.js +0 -1300
  24. package/dist/chunk-MYVJ6HK4.js +0 -3510
  25. package/dist/chunk-S6VIK4FF.js +0 -723
  26. package/dist/chunk-XN5ABWZ6.js +0 -486
  27. package/dist/chunk-Y6TYJMNT.js +0 -109
  28. package/dist/init-HZ3JEDGQ.js +0 -38
  29. package/dist/logs-6JKKYDGJ.js +0 -188
  30. package/dist/project-25NQ4J4Y.js +0 -24
  31. package/dist/recover-L3MJHHDA.js +0 -133
  32. package/dist/repo-TDCWQR6P.js +0 -379
  33. package/dist/run-XJQ6BF7U.js +0 -110
  34. package/dist/start-I2CC7BLW.js +0 -18
  35. package/dist/status-QSCFVGRQ.js +0 -11
  36. package/dist/stop-7MFCBQVW.js +0 -9
@@ -6,20 +6,21 @@ import {
6
6
  normalizeCodexRuntimeEvents,
7
7
  prepareCodexRuntimePlan,
8
8
  resolveLocalRuntimeLaunchConfig
9
- } from "./chunk-A67CMOYE.js";
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-QEONJ5DZ.js";
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
- if (isClaudeRuntimeCommand(workflow.codex.command)) {
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: resolveClaudeCommandBinary(workflow.codex.command) ?? void 0,
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 = error instanceof Error ? error.message : "Unknown worker startup error";
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: "codex"
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 = spawn(toolDef.command, toolDef.args, {
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.0.21",
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/tracker-github": "0.0.14",
50
- "@gh-symphony/worker": "0.0.14"
49
+ "@gh-symphony/worker": "0.0.14",
50
+ "@gh-symphony/tracker-github": "0.0.14"
51
51
  },
52
52
  "scripts": {
53
53
  "build": "tsup",
@@ -1,11 +0,0 @@
1
- #!/usr/bin/env node
2
-
3
- // src/orchestrator-runtime.ts
4
- import { resolve } from "path";
5
- function resolveRuntimeRoot(configDir) {
6
- return resolve(configDir);
7
- }
8
-
9
- export {
10
- resolveRuntimeRoot
11
- };
@@ -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
- };