@gh-symphony/cli 0.4.6 → 0.4.9

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.
@@ -1,8 +1,13 @@
1
1
  #!/usr/bin/env node
2
+ import {
3
+ commandExistsOnPath
4
+ } from "./chunk-JNEP7OYK.js";
2
5
  import {
3
6
  abortIfCancelled,
4
7
  buildAutomaticStateMappings,
5
8
  collectPriorityLabelNames,
9
+ isSupportedInitRuntime,
10
+ normalizeInitRuntime,
6
11
  planWorkflowArtifacts,
7
12
  promptBlockerCheck,
8
13
  promptLegacyGhSymphonyCleanup,
@@ -10,16 +15,17 @@ import {
10
15
  promptStateMappings,
11
16
  renderDryRunPreview,
12
17
  resolvePriorityField,
18
+ resolveRuntimeCommand,
13
19
  resolveStatusField,
14
20
  toWorkflowLifecycleConfig,
15
21
  validateStateMapping,
16
22
  warnDeprecatedSkipContext,
17
23
  writeEcosystem,
18
24
  writeWorkflowPlan
19
- } from "./chunk-DENDF6S6.js";
25
+ } from "./chunk-77INSSMM.js";
20
26
  import {
21
27
  initRepoRuntime
22
- } from "./chunk-EILO332E.js";
28
+ } from "./chunk-7XHWAJJA.js";
23
29
  import "./chunk-3IRPSPAF.js";
24
30
  import {
25
31
  GhAuthError,
@@ -28,17 +34,21 @@ import {
28
34
  checkRequiredScopes,
29
35
  createClient,
30
36
  ensureGhAuth,
37
+ formatGhAuthRemediation,
31
38
  getGhToken,
32
39
  getProjectDetail,
33
40
  listUserProjects,
34
41
  validateToken
35
- } from "./chunk-SMNIGNS3.js";
36
- import "./chunk-RGCSM2KZ.js";
42
+ } from "./chunk-FFY5VKNV.js";
43
+ import "./chunk-PKUD2SVX.js";
44
+ import "./chunk-77H5ED5L.js";
37
45
  import "./chunk-YZP5N5XP.js";
38
46
 
39
47
  // src/commands/setup.ts
40
48
  import * as p from "@clack/prompts";
49
+ import { access } from "fs/promises";
41
50
  import { resolve } from "path";
51
+ var SETUP_RUNTIME_CHOICES = "codex-app-server, claude-print";
42
52
  function parseSetupFlags(args) {
43
53
  const flags = {
44
54
  nonInteractive: false,
@@ -53,9 +63,19 @@ function parseSetupFlags(args) {
53
63
  flags.nonInteractive = true;
54
64
  break;
55
65
  case "--output":
66
+ if (!next || next.startsWith("-")) {
67
+ throw new Error("Option '--output' argument missing");
68
+ }
56
69
  flags.output = next;
57
70
  i += 1;
58
71
  break;
72
+ case "--runtime":
73
+ if (!next || next.startsWith("-")) {
74
+ throw new Error("Option '--runtime' argument missing");
75
+ }
76
+ flags.runtime = next;
77
+ i += 1;
78
+ break;
59
79
  case "--skip-skills":
60
80
  flags.skipSkills = true;
61
81
  break;
@@ -65,13 +85,68 @@ function parseSetupFlags(args) {
65
85
  default:
66
86
  if (arg?.startsWith("-")) {
67
87
  throw new Error(
68
- `Unknown option '${arg}'. Removed project/workspace flags are no longer supported; run 'gh-symphony setup' from inside the target repository. Supported flags: --non-interactive, --output, --skip-skills. Deprecated no-op: --skip-context.`
88
+ `Unknown option '${arg}'. Removed project/workspace flags are no longer supported; run 'gh-symphony setup' from inside the target repository. Supported flags: --non-interactive, --output, --runtime, --skip-skills. Deprecated no-op: --skip-context.`
69
89
  );
70
90
  }
71
91
  }
72
92
  }
73
93
  return flags;
74
94
  }
95
+ function resolveSetupRuntime(runtime) {
96
+ return normalizeInitRuntime(runtime ?? "codex-app-server");
97
+ }
98
+ function validateSetupRuntime(runtime) {
99
+ if (isSupportedInitRuntime(runtime)) {
100
+ return null;
101
+ }
102
+ return `Unsupported runtime '${runtime}'. Choose one of: ${SETUP_RUNTIME_CHOICES}.`;
103
+ }
104
+ async function promptRuntimeSelection() {
105
+ return abortIfCancelled(
106
+ p.select({
107
+ message: "Step 1/5 \u2014 Select the agent runtime:",
108
+ options: [
109
+ {
110
+ value: "codex-app-server",
111
+ label: "codex-app-server",
112
+ hint: "Codex app-server JSON-RPC runtime"
113
+ },
114
+ {
115
+ value: "claude-print",
116
+ label: "claude-print",
117
+ hint: "Claude Code non-interactive stream-json runtime"
118
+ }
119
+ ]
120
+ })
121
+ );
122
+ }
123
+ function runtimeInstallHint(runtime) {
124
+ const command = resolveRuntimeCommand(runtime);
125
+ if (runtime === "claude-print") {
126
+ return `Selected runtime '${runtime}' requires the '${command}' command, but it was not found on PATH. Install Claude Code and confirm '${command} --version' works before running 'gh-symphony repo start'.`;
127
+ }
128
+ return `Selected runtime '${runtime}' requires the '${command}' command, but it was not found on PATH. Install Codex and confirm '${command} --version' works before running 'gh-symphony repo start'.`;
129
+ }
130
+ async function checkRuntimeInstall(runtime) {
131
+ const command = resolveRuntimeCommand(runtime);
132
+ return commandExistsOnPath(command, {
133
+ access,
134
+ pathEnv: process.env.PATH,
135
+ pathExtEnv: process.env.PATHEXT,
136
+ platform: process.platform
137
+ });
138
+ }
139
+ async function warnIfRuntimeMissing(runtime, options) {
140
+ if (!await checkRuntimeInstall(runtime)) {
141
+ const hint = runtimeInstallHint(runtime);
142
+ if (options.json) {
143
+ process.stderr.write(`Warning: ${hint}
144
+ `);
145
+ return;
146
+ }
147
+ p.log.warn(hint);
148
+ }
149
+ }
75
150
  function displayScopeError(error, retryCommand) {
76
151
  const plural = error.requiredScopes.length === 1 ? "" : "s";
77
152
  p.log.error(
@@ -87,6 +162,13 @@ Then re-run: ${retryCommand}`,
87
162
  "Fix missing scope"
88
163
  );
89
164
  }
165
+ function displayGhAuthError(error) {
166
+ const remediation = formatGhAuthRemediation(error, {
167
+ retryCommand: "gh-symphony setup"
168
+ });
169
+ p.log.error(`${remediation.title}: ${remediation.message}`);
170
+ p.log.error(remediation.hint);
171
+ }
90
172
  async function resolveProjectDetail(client) {
91
173
  const projects = await listUserProjects(client);
92
174
  if (projects.length === 0) {
@@ -110,7 +192,7 @@ async function selectProjectSummary(client) {
110
192
  }
111
193
  const selectedProjectId = await abortIfCancelled(
112
194
  p.select({
113
- message: "Step 1/4 \u2014 Select a GitHub Project board:",
195
+ message: "Step 2/5 \u2014 Select a GitHub Project board:",
114
196
  options: projects.map((project) => ({
115
197
  value: project.id,
116
198
  label: `${project.owner.login}/${project.title}`,
@@ -127,6 +209,7 @@ function printNonInteractiveSummary(input) {
127
209
  `GitHub Project ${input.githubProjectTitle} (${input.githubProjectId})`,
128
210
  `Repository ${input.repository}`,
129
211
  `WORKFLOW.md ${input.workflowPath}`,
212
+ `Agent runtime ${input.runtime}`,
130
213
  `Runtime ${input.runtimeDir}`,
131
214
  "Ready. Run 'gh-symphony repo start' to begin orchestration."
132
215
  ].map((line) => ` ${line}`).join("\n") + "\n"
@@ -155,6 +238,14 @@ var handler = async (args, options) => {
155
238
  };
156
239
  var setup_default = handler;
157
240
  async function runNonInteractive(flags, options) {
241
+ const selectedRuntime = resolveSetupRuntime(flags.runtime);
242
+ const runtimeError = validateSetupRuntime(selectedRuntime);
243
+ if (runtimeError) {
244
+ process.stderr.write(`Error: ${runtimeError}
245
+ `);
246
+ process.exitCode = 1;
247
+ return;
248
+ }
158
249
  let token;
159
250
  try {
160
251
  token = getGhToken();
@@ -235,7 +326,7 @@ Run setup without --non-interactive for manual mapping.
235
326
  priority,
236
327
  includePriorityTemplates: !priorityField,
237
328
  mappings,
238
- runtime: "codex",
329
+ runtime: selectedRuntime,
239
330
  skipSkills: flags.skipSkills,
240
331
  skipContext: flags.skipContext
241
332
  });
@@ -247,7 +338,7 @@ Run setup without --non-interactive for manual mapping.
247
338
  priorityField,
248
339
  priority,
249
340
  includePriorityTemplates: !priorityField,
250
- runtime: "codex",
341
+ runtime: selectedRuntime,
251
342
  skipSkills: flags.skipSkills,
252
343
  skipContext: flags.skipContext
253
344
  });
@@ -255,11 +346,13 @@ Run setup without --non-interactive for manual mapping.
255
346
  repoDir: process.cwd(),
256
347
  workflowFile: workflowPath
257
348
  });
349
+ await warnIfRuntimeMissing(selectedRuntime, options);
258
350
  if (options.json) {
259
351
  process.stdout.write(
260
352
  JSON.stringify({
261
353
  status: "created",
262
354
  output: workflowPath,
355
+ runtime: selectedRuntime,
263
356
  runtimeDir: runtime.configDir,
264
357
  repository: `${runtime.repository.owner}/${runtime.repository.name}`,
265
358
  githubProjectId: projectDetail.id
@@ -271,11 +364,12 @@ Run setup without --non-interactive for manual mapping.
271
364
  githubProjectTitle: projectDetail.title,
272
365
  githubProjectId: projectDetail.id,
273
366
  workflowPath,
367
+ runtime: selectedRuntime,
274
368
  runtimeDir: runtime.configDir,
275
369
  repository: `${runtime.repository.owner}/${runtime.repository.name}`
276
370
  });
277
371
  }
278
- async function runInteractive(flags, _options) {
372
+ async function runInteractive(flags, options) {
279
373
  p.intro("gh-symphony \u2014 One-command Setup");
280
374
  const authSpinner = p.spinner();
281
375
  authSpinner.start("Checking gh CLI authentication...");
@@ -289,27 +383,14 @@ async function runInteractive(flags, _options) {
289
383
  } catch (error) {
290
384
  authSpinner.stop("Authentication failed.");
291
385
  if (error instanceof GhAuthError) {
292
- if (error.code === "not_installed") {
293
- p.log.error(
294
- "gh CLI\uAC00 \uC124\uCE58\uB418\uC5B4 \uC788\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4. https://cli.github.com \uC5D0\uC11C \uC124\uCE58\uD558\uC138\uC694."
295
- );
296
- } else if (error.code === "not_authenticated") {
297
- p.log.error(
298
- "gh auth login --scopes repo,read:org,project \uB97C \uC2E4\uD589\uD558\uC138\uC694."
299
- );
300
- } else if (error.code === "missing_scopes") {
301
- p.log.error(
302
- "gh auth refresh --scopes repo,read:org,project \uB97C \uC2E4\uD589\uD558\uC138\uC694."
303
- );
304
- } else {
305
- p.log.error(error.message);
306
- }
386
+ displayGhAuthError(error);
307
387
  } else {
308
388
  p.log.error(error instanceof Error ? error.message : "Unknown error");
309
389
  }
310
390
  process.exitCode = 1;
311
391
  return;
312
392
  }
393
+ const selectedRuntime = await promptRuntimeSelection();
313
394
  const projectsSpinner = p.spinner();
314
395
  projectsSpinner.start("Loading GitHub Project boards...");
315
396
  let selectedProject;
@@ -352,7 +433,7 @@ async function runInteractive(flags, _options) {
352
433
  projectDetail.linkedRepositories
353
434
  );
354
435
  const mappings = await promptStateMappings(statusField, {
355
- stepLabel: "Step 2/4"
436
+ stepLabel: "Step 3/5"
356
437
  });
357
438
  const workflowValidation = validateStateMapping(mappings);
358
439
  if (!workflowValidation.valid) {
@@ -368,7 +449,7 @@ async function runInteractive(flags, _options) {
368
449
  }
369
450
  const lifecycleBase = toWorkflowLifecycleConfig(statusField.name, mappings);
370
451
  const blockerCheckStates = await promptBlockerCheck(lifecycleBase, {
371
- stepLabel: "Step 3/4"
452
+ stepLabel: "Step 4/5"
372
453
  });
373
454
  const lifecycle = toWorkflowLifecycleConfig(statusField.name, mappings, {
374
455
  blockerCheckStates,
@@ -377,7 +458,7 @@ async function runInteractive(flags, _options) {
377
458
  const { priority, priorityField } = await promptPriorityConfig({
378
459
  priorityResolution,
379
460
  labelNames: priorityLabelNames,
380
- stepLabel: "Step 4/4"
461
+ stepLabel: "Step 5/5"
381
462
  });
382
463
  const workflowPath = resolve(flags.output ?? "WORKFLOW.md");
383
464
  const { workflowPlan, ecosystemPlan } = await planWorkflowArtifacts({
@@ -390,7 +471,7 @@ async function runInteractive(flags, _options) {
390
471
  includePriorityTemplates: priority.source === "disabled",
391
472
  mappings,
392
473
  lifecycle,
393
- runtime: "codex",
474
+ runtime: selectedRuntime,
394
475
  skipSkills: flags.skipSkills,
395
476
  skipContext: flags.skipContext
396
477
  });
@@ -398,6 +479,7 @@ async function runInteractive(flags, _options) {
398
479
  [
399
480
  `GitHub Project: ${projectDetail.title}`,
400
481
  `Authenticated: ${login}`,
482
+ `Agent runtime: ${selectedRuntime}`,
401
483
  `Repository: current working directory`,
402
484
  "",
403
485
  renderDryRunPreview(workflowPath, workflowPlan, ecosystemPlan).trimEnd()
@@ -425,7 +507,7 @@ async function runInteractive(flags, _options) {
425
507
  priority,
426
508
  lifecycle,
427
509
  includePriorityTemplates: priority.source === "disabled",
428
- runtime: "codex",
510
+ runtime: selectedRuntime,
429
511
  skipSkills: flags.skipSkills,
430
512
  skipContext: flags.skipContext
431
513
  });
@@ -442,8 +524,10 @@ async function runInteractive(flags, _options) {
442
524
  process.exitCode = 1;
443
525
  return;
444
526
  }
527
+ await warnIfRuntimeMissing(selectedRuntime, options);
445
528
  p.outro(
446
- "Repository runtime is ready.\n Run 'gh-symphony repo start' to begin orchestration."
529
+ `Repository runtime is ready for ${selectedRuntime}.
530
+ Run 'gh-symphony repo start' to begin orchestration.`
447
531
  );
448
532
  }
449
533
  export {
@@ -16,8 +16,8 @@ function execFileAsync(file, args, execFileImpl = execFileCallback) {
16
16
  });
17
17
  }
18
18
  function resolveCurrentCliVersion() {
19
- if ("0.4.6".length > 0) {
20
- return "0.4.6";
19
+ if ("0.4.9".length > 0) {
20
+ return "0.4.9";
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.4.6";
5
+ const version = "0.4.9";
6
6
  if (options.json) {
7
7
  process.stdout.write(JSON.stringify({ version }) + "\n");
8
8
  } else {
@@ -6,18 +6,20 @@ import {
6
6
  normalizeCodexRuntimeEvents,
7
7
  prepareCodexRuntimePlan,
8
8
  resolveLocalRuntimeLaunchConfig
9
- } from "./chunk-XLDJTMW5.js";
9
+ } from "./chunk-LSH5HRQT.js";
10
10
  import {
11
- DEFAULT_AGENT_INPUT_REQUIRED_REASON,
12
- classifySessionExit,
13
11
  createClaudePrintRuntimeAdapter,
14
- extractEnvForClaude,
15
12
  formatClaudePreflightText,
16
- parseWorkflowMarkdown,
17
13
  resolveClaudeCommandBinary,
18
- resolveWorkflowRuntimeCommand,
19
14
  runClaudePreflight
20
- } from "./chunk-RGCSM2KZ.js";
15
+ } from "./chunk-PKUD2SVX.js";
16
+ import {
17
+ DEFAULT_AGENT_INPUT_REQUIRED_REASON,
18
+ classifySessionExit,
19
+ extractEnvForClaude,
20
+ parseWorkflowMarkdown,
21
+ resolveWorkflowRuntimeCommand
22
+ } from "./chunk-77H5ED5L.js";
21
23
 
22
24
  // ../worker/src/index.ts
23
25
  import { spawn as spawn2 } from "child_process";
@@ -6,12 +6,14 @@ import {
6
6
  resetWorkflowCommandDependenciesForTest,
7
7
  setWorkflowCommandDependenciesForTest,
8
8
  workflow_default
9
- } from "./chunk-FBJRJWE5.js";
10
- import "./chunk-DENDF6S6.js";
11
- import "./chunk-RMNLHTIK.js";
12
- import "./chunk-XLDJTMW5.js";
13
- import "./chunk-SMNIGNS3.js";
14
- import "./chunk-RGCSM2KZ.js";
9
+ } from "./chunk-RMXW2QQF.js";
10
+ import "./chunk-77INSSMM.js";
11
+ import "./chunk-D7HICFZ5.js";
12
+ import "./chunk-MAJOIZ5Q.js";
13
+ import "./chunk-LSH5HRQT.js";
14
+ import "./chunk-FFY5VKNV.js";
15
+ import "./chunk-PKUD2SVX.js";
16
+ import "./chunk-77H5ED5L.js";
15
17
  import "./chunk-YZP5N5XP.js";
16
18
  export {
17
19
  workflow_default as default,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gh-symphony/cli",
3
- "version": "0.4.6",
3
+ "version": "0.4.9",
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/core": "0.0.14",
44
+ "@gh-symphony/control-plane": "0.0.15",
45
45
  "@gh-symphony/dashboard": "0.0.14",
46
46
  "@gh-symphony/orchestrator": "0.0.14",
47
- "@gh-symphony/tracker-github": "0.0.14",
47
+ "@gh-symphony/core": "0.0.14",
48
48
  "@gh-symphony/runtime-claude": "0.0.14",
49
- "@gh-symphony/worker": "0.0.14",
50
- "@gh-symphony/control-plane": "0.0.15"
49
+ "@gh-symphony/tracker-github": "0.0.14",
50
+ "@gh-symphony/worker": "0.0.14"
51
51
  },
52
52
  "scripts": {
53
53
  "build": "tsup",