@gh-symphony/cli 0.4.7 → 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.
@@ -16,7 +16,7 @@ import {
16
16
  formatClaudePreflightText,
17
17
  resolveClaudeCommandBinary,
18
18
  runClaudePreflight
19
- } from "./chunk-RGCSM2KZ.js";
19
+ } from "./chunk-PKUD2SVX.js";
20
20
 
21
21
  // src/mapping/smart-defaults.ts
22
22
  var ROLE_PATTERNS = [
@@ -93,6 +93,105 @@ function validateStateMapping(mappings) {
93
93
  return { valid: errors.length === 0, errors, warnings };
94
94
  }
95
95
 
96
+ // src/workflow/workflow-runtime.ts
97
+ var CODEX_RUNTIME_TOKENS = ["codex-app-server", "codex"];
98
+ var CLAUDE_RUNTIME_TOKENS = ["claude-print", "claude-code"];
99
+ var DEFAULT_CLAUDE_PRINT_ARGS = [
100
+ "-p",
101
+ "--output-format",
102
+ "stream-json",
103
+ "--input-format",
104
+ "stream-json",
105
+ "--include-partial-messages",
106
+ "--verbose",
107
+ "--permission-mode",
108
+ "bypassPermissions"
109
+ ];
110
+ function normalizeInitRuntime(runtime) {
111
+ if (runtime === "codex") {
112
+ return "codex-app-server";
113
+ }
114
+ if (runtime === "claude-code") {
115
+ return "claude-print";
116
+ }
117
+ return runtime;
118
+ }
119
+ function isSupportedInitRuntime(runtime) {
120
+ const normalized = normalizeInitRuntime(runtime);
121
+ return normalized === "codex-app-server" || normalized === "claude-print";
122
+ }
123
+ function containsRuntimeToken(runtime, tokens) {
124
+ return tokens.some((token) => {
125
+ const escaped = token.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
126
+ return new RegExp(`(^|[\\s"'\\\`])${escaped}(?=$|[\\s"'\\\`])`).test(
127
+ runtime
128
+ );
129
+ });
130
+ }
131
+ function isCodexRuntime(runtime) {
132
+ return normalizeInitRuntime(runtime) === "codex-app-server" || containsRuntimeToken(runtime, CODEX_RUNTIME_TOKENS);
133
+ }
134
+ function isClaudeRuntime(runtime) {
135
+ return normalizeInitRuntime(runtime) === "claude-print" || containsRuntimeToken(runtime, CLAUDE_RUNTIME_TOKENS);
136
+ }
137
+ function resolveRuntimeCommand(runtime) {
138
+ const normalized = normalizeInitRuntime(runtime);
139
+ if (normalized === "codex-app-server") {
140
+ return "codex";
141
+ }
142
+ if (normalized === "claude-print") {
143
+ return "claude";
144
+ }
145
+ return runtime;
146
+ }
147
+ function buildRuntimeFrontMatter(runtime) {
148
+ const normalized = normalizeInitRuntime(runtime);
149
+ if (normalized === "codex-app-server") {
150
+ return [
151
+ "runtime:",
152
+ " kind: codex-app-server",
153
+ " command: codex",
154
+ " args:",
155
+ " - app-server",
156
+ " isolation:",
157
+ " bare: false",
158
+ " strict_mcp_config: false",
159
+ " timeouts:",
160
+ " read_timeout_ms: 5000",
161
+ " turn_timeout_ms: 3600000",
162
+ " stall_timeout_ms: 300000"
163
+ ];
164
+ }
165
+ if (normalized === "claude-print") {
166
+ return [
167
+ "runtime:",
168
+ " kind: claude-print",
169
+ " command: claude",
170
+ " args:",
171
+ ...DEFAULT_CLAUDE_PRINT_ARGS.map((arg) => ` - ${arg}`),
172
+ " isolation:",
173
+ " bare: false",
174
+ " strict_mcp_config: false",
175
+ " timeouts:",
176
+ " read_timeout_ms: 5000",
177
+ " turn_timeout_ms: 3600000",
178
+ " stall_timeout_ms: 900000"
179
+ ];
180
+ }
181
+ return [
182
+ "runtime:",
183
+ " kind: custom",
184
+ ` command: ${runtime}`,
185
+ " isolation:",
186
+ " bare: false",
187
+ " strict_mcp_config: false",
188
+ " timeouts:",
189
+ " read_timeout_ms: 5000",
190
+ " turn_timeout_ms: 3600000",
191
+ " stall_timeout_ms: 300000"
192
+ ];
193
+ }
194
+
96
195
  // src/commands/workflow-init.ts
97
196
  import * as p from "@clack/prompts";
98
197
  import { spawnSync } from "child_process";
@@ -215,105 +314,6 @@ function buildRepositoryValidationGuidance(input) {
215
314
  return lines;
216
315
  }
217
316
 
218
- // src/workflow/workflow-runtime.ts
219
- var CODEX_RUNTIME_TOKENS = ["codex-app-server", "codex"];
220
- var CLAUDE_RUNTIME_TOKENS = ["claude-print", "claude-code"];
221
- var DEFAULT_CLAUDE_PRINT_ARGS = [
222
- "-p",
223
- "--output-format",
224
- "stream-json",
225
- "--input-format",
226
- "stream-json",
227
- "--include-partial-messages",
228
- "--verbose",
229
- "--permission-mode",
230
- "bypassPermissions"
231
- ];
232
- function normalizeInitRuntime(runtime) {
233
- if (runtime === "codex") {
234
- return "codex-app-server";
235
- }
236
- if (runtime === "claude-code") {
237
- return "claude-print";
238
- }
239
- return runtime;
240
- }
241
- function isSupportedInitRuntime(runtime) {
242
- const normalized = normalizeInitRuntime(runtime);
243
- return normalized === "codex-app-server" || normalized === "claude-print";
244
- }
245
- function containsRuntimeToken(runtime, tokens) {
246
- return tokens.some((token) => {
247
- const escaped = token.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
248
- return new RegExp(`(^|[\\s"'\\\`])${escaped}(?=$|[\\s"'\\\`])`).test(
249
- runtime
250
- );
251
- });
252
- }
253
- function isCodexRuntime(runtime) {
254
- return normalizeInitRuntime(runtime) === "codex-app-server" || containsRuntimeToken(runtime, CODEX_RUNTIME_TOKENS);
255
- }
256
- function isClaudeRuntime(runtime) {
257
- return normalizeInitRuntime(runtime) === "claude-print" || containsRuntimeToken(runtime, CLAUDE_RUNTIME_TOKENS);
258
- }
259
- function resolveRuntimeCommand(runtime) {
260
- const normalized = normalizeInitRuntime(runtime);
261
- if (normalized === "codex-app-server") {
262
- return "codex";
263
- }
264
- if (normalized === "claude-print") {
265
- return "claude";
266
- }
267
- return runtime;
268
- }
269
- function buildRuntimeFrontMatter(runtime) {
270
- const normalized = normalizeInitRuntime(runtime);
271
- if (normalized === "codex-app-server") {
272
- return [
273
- "runtime:",
274
- " kind: codex-app-server",
275
- " command: codex",
276
- " args:",
277
- " - app-server",
278
- " isolation:",
279
- " bare: false",
280
- " strict_mcp_config: false",
281
- " timeouts:",
282
- " read_timeout_ms: 5000",
283
- " turn_timeout_ms: 3600000",
284
- " stall_timeout_ms: 300000"
285
- ];
286
- }
287
- if (normalized === "claude-print") {
288
- return [
289
- "runtime:",
290
- " kind: claude-print",
291
- " command: claude",
292
- " args:",
293
- ...DEFAULT_CLAUDE_PRINT_ARGS.map((arg) => ` - ${arg}`),
294
- " isolation:",
295
- " bare: false",
296
- " strict_mcp_config: false",
297
- " timeouts:",
298
- " read_timeout_ms: 5000",
299
- " turn_timeout_ms: 3600000",
300
- " stall_timeout_ms: 900000"
301
- ];
302
- }
303
- return [
304
- "runtime:",
305
- " kind: custom",
306
- ` command: ${runtime}`,
307
- " isolation:",
308
- " bare: false",
309
- " strict_mcp_config: false",
310
- " timeouts:",
311
- " read_timeout_ms: 5000",
312
- " turn_timeout_ms: 3600000",
313
- " stall_timeout_ms: 300000"
314
- ];
315
- }
316
-
317
317
  // src/workflow/generate-workflow-md.ts
318
318
  function generateWorkflowMarkdown(input) {
319
319
  const frontMatter = buildFrontMatter(input);
@@ -3537,6 +3537,9 @@ async function runInteractiveStandalone(flags, _options) {
3537
3537
  export {
3538
3538
  toWorkflowLifecycleConfig,
3539
3539
  validateStateMapping,
3540
+ normalizeInitRuntime,
3541
+ isSupportedInitRuntime,
3542
+ resolveRuntimeCommand,
3540
3543
  abortIfCancelled,
3541
3544
  warnDeprecatedSkipContext,
3542
3545
  workflow_init_default,
@@ -4,7 +4,7 @@ import {
4
4
  } from "./chunk-3IRPSPAF.js";
5
5
  import {
6
6
  parseWorkflowMarkdown
7
- } from "./chunk-RGCSM2KZ.js";
7
+ } from "./chunk-77H5ED5L.js";
8
8
  import {
9
9
  saveGlobalConfig,
10
10
  saveProjectConfig
@@ -25,6 +25,14 @@ import { basename, dirname, join, resolve } from "path";
25
25
  var INTERNAL_PROJECT_ID = "repository";
26
26
  var RepoRuntimeMigrationError = class extends Error {
27
27
  };
28
+ var MissingWorkflowFileError = class extends Error {
29
+ constructor(workflowPath) {
30
+ super(
31
+ `WORKFLOW.md was not found at ${workflowPath}. Run 'gh-symphony workflow init' in this repository or add a valid WORKFLOW.md at the repo root.`
32
+ );
33
+ this.workflowPath = workflowPath;
34
+ }
35
+ };
28
36
  function parseRepoRuntimeFlags(args) {
29
37
  const flags = { repoDir: process.cwd() };
30
38
  for (let i = 0; i < args.length; i += 1) {
@@ -57,6 +65,9 @@ async function initRepoRuntime(flags) {
57
65
  const runtimeRoot = resolveRepoRuntimeRoot(repoDir);
58
66
  await migrateLegacyRuntime(runtimeRoot);
59
67
  const workflowPath = resolve(repoDir, flags.workflowFile ?? "WORKFLOW.md");
68
+ if (!await pathExists(workflowPath)) {
69
+ throw new MissingWorkflowFileError(workflowPath);
70
+ }
60
71
  const workflow = parseWorkflowMarkdown(await readFile(workflowPath, "utf8"));
61
72
  validateRepoInitWorkflow(workflow);
62
73
  const repository = resolveRepository(repoDir);
@@ -248,6 +259,7 @@ function isMissing(error) {
248
259
  }
249
260
 
250
261
  export {
262
+ MissingWorkflowFileError,
251
263
  parseRepoRuntimeFlags,
252
264
  initRepoRuntime
253
265
  };
@@ -1,4 +1,7 @@
1
1
  #!/usr/bin/env node
2
+ import {
3
+ writeCliError
4
+ } from "./chunk-MAJOIZ5Q.js";
2
5
  import {
3
6
  DEFAULT_LINEAR_GRAPHQL_URL,
4
7
  DEFAULT_MAX_FAILURE_RETRIES,
@@ -13,6 +16,8 @@ import {
13
16
  deriveIssueWorkspaceKeyFromIdentifier,
14
17
  deriveLegacyIssueWorkspaceKey,
15
18
  executeWorkspaceHook,
19
+ formatErrorForTerminal,
20
+ hasVerboseFlag,
16
21
  isFileMissing,
17
22
  isMatchingIssueRun,
18
23
  isOrchestratorChannelEvent,
@@ -30,7 +35,7 @@ import {
30
35
  resolveWorkflowRuntimeTimeouts,
31
36
  safeReadDir,
32
37
  scheduleRetryAt
33
- } from "./chunk-RGCSM2KZ.js";
38
+ } from "./chunk-77H5ED5L.js";
34
39
  import {
35
40
  loadGlobalConfig,
36
41
  loadProjectConfig
@@ -6461,7 +6466,7 @@ function parseArgs(args) {
6461
6466
  for (let index = 0; index < args.length; index += 1) {
6462
6467
  const argument = args[index];
6463
6468
  const value = args[index + 1];
6464
- if (!argument?.startsWith("--")) {
6469
+ if (!argument?.startsWith("-")) {
6465
6470
  continue;
6466
6471
  }
6467
6472
  switch (argument) {
@@ -6492,6 +6497,10 @@ function parseArgs(args) {
6492
6497
  parsed.logLevel = value;
6493
6498
  index += 1;
6494
6499
  break;
6500
+ case "--verbose":
6501
+ case "-v":
6502
+ parsed.logLevel = "verbose";
6503
+ break;
6495
6504
  default:
6496
6505
  throw new Error(`Unknown option: ${argument}`);
6497
6506
  }
@@ -6507,12 +6516,21 @@ function resolveOptionalPath(value) {
6507
6516
  if (process.argv[1] && import.meta.url === pathToFileURL(process.argv[1]).href) {
6508
6517
  main().catch((error) => {
6509
6518
  process.stderr.write(
6510
- `${error instanceof Error ? error.message : "Unknown error"}
6511
- `
6519
+ formatErrorForTerminal(error, {
6520
+ verbose: hasVerboseOrchestratorDiagnostics(process.argv.slice(2))
6521
+ })
6512
6522
  );
6513
6523
  process.exitCode = 1;
6514
6524
  });
6515
6525
  }
6526
+ function hasVerboseOrchestratorDiagnostics(argv) {
6527
+ if (hasVerboseFlag(argv) || process.env.SYMPHONY_LOG_LEVEL === "verbose") {
6528
+ return true;
6529
+ }
6530
+ return argv.some(
6531
+ (arg, index) => arg === "--log-level" && argv[index + 1] === "verbose"
6532
+ );
6533
+ }
6516
6534
 
6517
6535
  // src/project-selection.ts
6518
6536
  import * as p from "@clack/prompts";
@@ -6613,8 +6631,11 @@ async function resolveManagedProjectConfig(input) {
6613
6631
  return loadProjectConfig(input.configDir, projectIds[0]);
6614
6632
  }
6615
6633
  if (!isInteractiveTerminal()) {
6616
- process.stderr.write(explicitProjectRequiredMessage());
6617
- process.exitCode = 1;
6634
+ writeCliError({
6635
+ code: "missing_repository_runtime_config",
6636
+ message: explicitProjectRequiredMessage().trimEnd(),
6637
+ json: input.json
6638
+ });
6618
6639
  return null;
6619
6640
  }
6620
6641
  const projects = await Promise.all(
@@ -6639,14 +6660,15 @@ async function resolveManagedProjectConfig(input) {
6639
6660
  }
6640
6661
  return loadProjectConfig(input.configDir, selected);
6641
6662
  }
6642
- function handleMissingManagedProjectConfig() {
6663
+ function handleMissingManagedProjectConfig(options) {
6643
6664
  if (process.exitCode) {
6644
6665
  return;
6645
6666
  }
6646
- process.stderr.write(
6647
- "No repository runtime config found. Run 'gh-symphony repo init' first.\n"
6648
- );
6649
- process.exitCode = 1;
6667
+ writeCliError({
6668
+ code: "missing_repository_runtime_config",
6669
+ message: options?.message ?? "No repository runtime config found. Run 'gh-symphony repo init' first.",
6670
+ json: options?.json
6671
+ });
6650
6672
  }
6651
6673
 
6652
6674
  export {
@@ -0,0 +1,52 @@
1
+ #!/usr/bin/env node
2
+
3
+ // src/utils/command-exists-on-path.ts
4
+ import { constants } from "fs";
5
+ import { delimiter, isAbsolute, join, resolve } from "path";
6
+ function getCommandCandidates(binary, deps) {
7
+ if (deps.platform !== "win32") {
8
+ return [binary];
9
+ }
10
+ const pathExts = (deps.pathExtEnv ?? ".COM;.EXE;.BAT;.CMD").split(";").map((ext) => ext.trim()).filter(Boolean);
11
+ const normalizedBinary = binary.toLowerCase();
12
+ if (pathExts.some((ext) => normalizedBinary.endsWith(ext.toLowerCase()))) {
13
+ return [binary];
14
+ }
15
+ return [binary, ...pathExts.map((ext) => `${binary}${ext}`)];
16
+ }
17
+ async function commandExistsOnPath(binary, deps) {
18
+ if (!binary) {
19
+ return false;
20
+ }
21
+ const candidates = getCommandCandidates(binary, deps);
22
+ if (isAbsolute(binary) || binary.includes("/") || binary.includes("\\")) {
23
+ for (const candidate of candidates) {
24
+ try {
25
+ await deps.access(resolve(candidate), constants.X_OK);
26
+ return true;
27
+ } catch {
28
+ continue;
29
+ }
30
+ }
31
+ return false;
32
+ }
33
+ for (const segment of (deps.pathEnv ?? "").split(delimiter)) {
34
+ if (!segment) {
35
+ continue;
36
+ }
37
+ for (const command of candidates) {
38
+ const candidate = join(segment, command);
39
+ try {
40
+ await deps.access(candidate, constants.X_OK);
41
+ return true;
42
+ } catch {
43
+ continue;
44
+ }
45
+ }
46
+ }
47
+ return false;
48
+ }
49
+
50
+ export {
51
+ commandExistsOnPath
52
+ };
@@ -1,16 +1,18 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
- DEFAULT_LINEAR_GRAPHQL_URL,
4
- buildAgentInputRequiredReason,
5
3
  createGitHubGraphQLMcpServerEntry,
6
4
  createLinearGraphQLMcpServerEntry,
5
+ resolveGitHubGraphQLToken
6
+ } from "./chunk-PKUD2SVX.js";
7
+ import {
8
+ DEFAULT_LINEAR_GRAPHQL_URL,
9
+ buildAgentInputRequiredReason,
7
10
  extractEnvForCodex,
8
11
  readAgentCredentialCache,
9
12
  readEnvFile,
10
- resolveGitHubGraphQLToken,
11
13
  shouldReuseAgentCredentialCache,
12
14
  writeAgentCredentialCache
13
- } from "./chunk-RGCSM2KZ.js";
15
+ } from "./chunk-77H5ED5L.js";
14
16
 
15
17
  // ../runtime-codex/src/runtime.ts
16
18
  import { spawn } from "child_process";
@@ -0,0 +1,32 @@
1
+ #!/usr/bin/env node
2
+
3
+ // src/cli-error.ts
4
+ function writeCliError(input) {
5
+ const exitCode = input.exitCode ?? 1;
6
+ if (input.json) {
7
+ process.stdout.write(
8
+ JSON.stringify(
9
+ {
10
+ error: {
11
+ code: input.code,
12
+ message: input.message
13
+ }
14
+ },
15
+ null,
16
+ 2
17
+ ) + "\n"
18
+ );
19
+ } else {
20
+ process.stderr.write(`${input.message}
21
+ `);
22
+ if (input.usage) {
23
+ process.stderr.write(`${input.usage}
24
+ `);
25
+ }
26
+ }
27
+ process.exitCode = exitCode;
28
+ }
29
+
30
+ export {
31
+ writeCliError
32
+ };