@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
@@ -54,9 +54,15 @@ async function saveGlobalConfig(configDir, config) {
54
54
  await writeJsonFile(configFilePath(configDir), config);
55
55
  }
56
56
  async function loadProjectConfig(configDir, projectId) {
57
- return readJsonFile(
58
- projectConfigPath(configDir, projectId)
59
- );
57
+ const config = await readJsonFile(projectConfigPath(configDir, projectId));
58
+ if (!config) {
59
+ return null;
60
+ }
61
+ const repository = config.repository ?? firstConfiguredRepository(config);
62
+ return {
63
+ ...config,
64
+ ...repository ? { repository } : {}
65
+ };
60
66
  }
61
67
  async function saveProjectConfig(configDir, projectId, config) {
62
68
  await writeJsonFile(projectConfigPath(configDir, projectId), config);
@@ -91,6 +97,11 @@ function isFileMissing(error) {
91
97
  error && typeof error === "object" && "code" in error && (error.code === "ENOENT" || error.code === "ENOTDIR")
92
98
  );
93
99
  }
100
+ function firstConfiguredRepository(config) {
101
+ return config.repositories?.find(
102
+ (repository) => typeof repository.owner === "string" && repository.owner.length > 0 && typeof repository.name === "string" && repository.name.length > 0
103
+ );
104
+ }
94
105
 
95
106
  export {
96
107
  resolveConfigDir,
@@ -4,34 +4,55 @@ import {
4
4
  generateProjectId,
5
5
  warnIfProjectDiscoveryPartial,
6
6
  writeConfig
7
- } from "./chunk-JN3TQVFV.js";
7
+ } from "./chunk-HMLBBZNY.js";
8
8
  import {
9
9
  start_default
10
- } from "./chunk-KY6WKH66.js";
10
+ } from "./chunk-E7HYEEZD.js";
11
+ import {
12
+ explainIssueDispatch,
13
+ isActiveRunRecordStatus,
14
+ parseIssueIdentifier,
15
+ resolveTrackerAdapter
16
+ } from "./chunk-PUDXVBSN.js";
17
+ import {
18
+ findGithubProjectIssue
19
+ } from "./chunk-2TSM3INR.js";
11
20
  import {
12
21
  GhAuthError,
13
22
  GitHubScopeError,
14
23
  checkRequiredScopes,
15
24
  createClient,
16
25
  discoverUserProjects,
26
+ getGhToken,
17
27
  getGhTokenWithSource,
18
28
  getProjectDetail,
19
29
  listUserProjects,
20
30
  resolveGitHubAuth,
21
31
  validateToken
22
32
  } from "./chunk-C67H3OUL.js";
33
+ import {
34
+ WorkflowConfigStore
35
+ } from "./chunk-EEQQWTXS.js";
23
36
  import {
24
37
  status_default
25
- } from "./chunk-XN5ABWZ6.js";
38
+ } from "./chunk-DFLXHNYQ.js";
26
39
  import {
27
- stripAnsi
28
- } from "./chunk-MVRF7BES.js";
40
+ bold,
41
+ green,
42
+ red,
43
+ stripAnsi,
44
+ yellow
45
+ } from "./chunk-36KYEDEO.js";
29
46
  import {
30
47
  resolveRuntimeRoot
31
- } from "./chunk-5NV3LSAJ.js";
48
+ } from "./chunk-IWFX2FMA.js";
32
49
  import {
33
50
  stop_default
34
- } from "./chunk-Y6TYJMNT.js";
51
+ } from "./chunk-GSX2FV3M.js";
52
+ import {
53
+ handleMissingManagedProjectConfig,
54
+ resolveManagedProjectConfig
55
+ } from "./chunk-DDL4BWSL.js";
35
56
  import {
36
57
  daemonPidPath,
37
58
  httpStatusPath,
@@ -39,14 +60,15 @@ import {
39
60
  loadProjectConfig,
40
61
  projectConfigDir,
41
62
  saveGlobalConfig
42
- } from "./chunk-ROGRTUFI.js";
63
+ } from "./chunk-QIRE2VXS.js";
43
64
 
44
65
  // src/commands/project.ts
45
66
  import * as p from "@clack/prompts";
46
67
  import { execFile as execFileCallback } from "child_process";
47
68
  import { promisify } from "util";
48
- import { readFile } from "fs/promises";
69
+ import { readdir, readFile } from "fs/promises";
49
70
  import { join } from "path";
71
+ import { resolve } from "path";
50
72
  var execFile = promisify(execFileCallback);
51
73
  var KNOWN_REQUIRED_SCOPES = ["repo", "read:org", "project"];
52
74
  function formatProjectRepoSummary(selectedRepos, totalLinked) {
@@ -113,6 +135,47 @@ function parseProjectAddFlags(args) {
113
135
  }
114
136
  return flags;
115
137
  }
138
+ function parseProjectExplainFlags(args) {
139
+ const parsed = {};
140
+ for (let i = 0; i < args.length; i += 1) {
141
+ const arg = args[i];
142
+ if (arg === "--project" || arg === "--project-id") {
143
+ const value = args[i + 1];
144
+ if (!value || value.startsWith("-")) {
145
+ parsed.error = `Option '${arg}' argument missing`;
146
+ return parsed;
147
+ }
148
+ parsed.projectId = value;
149
+ i += 1;
150
+ continue;
151
+ }
152
+ if (arg === "--workflow" || arg === "--workflow-path") {
153
+ const value = args[i + 1];
154
+ if (!value || value.startsWith("-")) {
155
+ parsed.error = `Option '${arg}' argument missing`;
156
+ return parsed;
157
+ }
158
+ parsed.workflowPath = value;
159
+ i += 1;
160
+ continue;
161
+ }
162
+ if (arg?.startsWith("-")) {
163
+ parsed.error = `Unknown option '${arg}'`;
164
+ return parsed;
165
+ }
166
+ if (parsed.identifier) {
167
+ parsed.error = "Only one issue identifier can be explained at a time";
168
+ return parsed;
169
+ }
170
+ parsed.identifier = arg;
171
+ }
172
+ if (!parsed.identifier) {
173
+ parsed.error = "Issue identifier argument missing";
174
+ } else if (!parseIssueIdentifier(parsed.identifier)) {
175
+ parsed.error = "Issue identifier must use the form <owner>/<repo>#<number>";
176
+ }
177
+ return parsed;
178
+ }
116
179
  var handler = async (args, options) => {
117
180
  const [subcommand, ...rest] = args;
118
181
  switch (subcommand) {
@@ -137,9 +200,12 @@ var handler = async (args, options) => {
137
200
  case "status":
138
201
  await status_default(rest, options);
139
202
  return;
203
+ case "explain":
204
+ await projectExplain(rest, options);
205
+ return;
140
206
  default:
141
207
  process.stdout.write(
142
- "Usage: gh-symphony project <add|list|remove|start|stop|switch|status>\n"
208
+ "Usage: gh-symphony project <add|list|remove|start|stop|switch|status|explain>\n"
143
209
  );
144
210
  }
145
211
  };
@@ -237,9 +303,260 @@ async function readPersistedSnapshot(configDir, projectId) {
237
303
  async function fetchProjectSnapshot(configDir, projectId) {
238
304
  return readPersistedSnapshot(configDir, projectId);
239
305
  }
306
+ async function projectExplain(args, options) {
307
+ const parsed = parseProjectExplainFlags(args);
308
+ if (parsed.error) {
309
+ process.stderr.write(`${parsed.error}
310
+ `);
311
+ process.stderr.write(
312
+ "Usage: gh-symphony project explain <owner/repo#number> [--project-id <project-id>] [--workflow <path>]\n"
313
+ );
314
+ process.exitCode = 2;
315
+ return;
316
+ }
317
+ const projectConfig = await resolveManagedProjectConfig({
318
+ configDir: options.configDir,
319
+ requestedProjectId: parsed.projectId
320
+ });
321
+ if (!projectConfig) {
322
+ handleMissingManagedProjectConfig();
323
+ return;
324
+ }
325
+ const identifier = parsed.identifier;
326
+ const parsedIdentifier = parseIssueIdentifier(identifier);
327
+ const fallbackRepository = {
328
+ owner: parsedIdentifier.owner,
329
+ name: parsedIdentifier.name,
330
+ cloneUrl: `https://github.com/${parsedIdentifier.owner}/${parsedIdentifier.name}.git`
331
+ };
332
+ const workflowRepository = projectConfig.repository ?? fallbackRepository;
333
+ let token;
334
+ try {
335
+ token = getGhToken();
336
+ } catch (error) {
337
+ if (error instanceof GhAuthError) {
338
+ process.stderr.write(
339
+ `Error: GitHub authentication is required for project explain. ${error.message}
340
+ `
341
+ );
342
+ process.stderr.write(
343
+ "Run 'gh auth login --scopes repo,read:org,project' or set GITHUB_GRAPHQL_TOKEN, then re-run this command.\n"
344
+ );
345
+ process.exitCode = 2;
346
+ return;
347
+ }
348
+ throw error;
349
+ }
350
+ const trackerAdapter = resolveTrackerAdapter(projectConfig.tracker);
351
+ const orchestratorProject = {
352
+ ...projectConfig,
353
+ repository: workflowRepository
354
+ };
355
+ const trackerDependencies = {
356
+ token,
357
+ projectItemsCache: createProjectItemsCache()
358
+ };
359
+ const runtimeRoot = join(
360
+ resolveRuntimeRoot(options.configDir),
361
+ "projects",
362
+ projectConfig.projectId
363
+ );
364
+ const issuesPromise = trackerAdapter.listIssues(
365
+ orchestratorProject,
366
+ trackerDependencies
367
+ );
368
+ const issuePromise = projectConfig.tracker.adapter === "github-project" ? findGithubProjectIssue(
369
+ orchestratorProject,
370
+ identifier,
371
+ trackerDependencies
372
+ ) : issuesPromise.then(
373
+ (issues2) => issues2.find(
374
+ (candidate) => candidate.identifier.trim().toLowerCase() === identifier.trim().toLowerCase()
375
+ ) ?? null
376
+ );
377
+ const [issues, issue, issueRecords, runs, snapshot] = await Promise.all([
378
+ issuesPromise,
379
+ issuePromise,
380
+ readJsonFile(join(runtimeRoot, "issues.json")),
381
+ readRuns(runtimeRoot, projectConfig.projectId),
382
+ readPersistedSnapshot(options.configDir, projectConfig.projectId)
383
+ ]);
384
+ let workflow;
385
+ try {
386
+ workflow = await loadExplainWorkflow({
387
+ explicitWorkflowPath: parsed.workflowPath,
388
+ repository: workflowRepository,
389
+ runs
390
+ });
391
+ } catch (error) {
392
+ if (error instanceof ProjectExplainWorkflowError) {
393
+ process.stderr.write(`Error: ${error.message}
394
+ `);
395
+ process.stderr.write(
396
+ "Hint: pass --workflow <path-to-WORKFLOW.md> or run 'gh-symphony workflow preview --file <path>' to verify the workflow file.\n"
397
+ );
398
+ process.exitCode = 2;
399
+ return;
400
+ }
401
+ throw error;
402
+ }
403
+ const activeRunCount = runs.filter(
404
+ (run) => isActiveRunRecordStatus(run.status)
405
+ ).length;
406
+ const report = explainIssueDispatch({
407
+ identifier,
408
+ issue,
409
+ projectRepository: projectConfig.repository ?? null,
410
+ allIssues: issues,
411
+ lifecycle: workflow.lifecycle,
412
+ issueRecords: issueRecords ?? [],
413
+ runs,
414
+ activeRunCount,
415
+ maxConcurrentAgents: workflow.maxConcurrentAgents,
416
+ maxConcurrentAgentsByState: workflow.maxConcurrentAgentsByState
417
+ });
418
+ const enrichedReport = {
419
+ ...report,
420
+ project: {
421
+ id: projectConfig.projectId,
422
+ slug: projectConfig.slug,
423
+ tracker: projectConfig.tracker,
424
+ lastTickAt: snapshot?.lastTickAt ?? null,
425
+ health: snapshot?.health ?? null
426
+ }
427
+ };
428
+ if (options.json) {
429
+ process.stdout.write(JSON.stringify(enrichedReport, null, 2) + "\n");
430
+ return;
431
+ }
432
+ process.stdout.write(renderProjectExplainReport(report, options.noColor));
433
+ }
434
+ var ProjectExplainWorkflowError = class extends Error {
435
+ constructor(message) {
436
+ super(message);
437
+ this.name = "ProjectExplainWorkflowError";
438
+ }
439
+ };
440
+ async function loadExplainWorkflow(input) {
441
+ const workflowPaths = resolveExplainWorkflowCandidates(input);
442
+ if (workflowPaths.length === 0) {
443
+ throw new ProjectExplainWorkflowError(
444
+ "No WORKFLOW.md path could be resolved from --workflow, the configured repository path, or previous run records."
445
+ );
446
+ }
447
+ const failures = [];
448
+ for (const workflowPath of workflowPaths) {
449
+ try {
450
+ const resolution = await new WorkflowConfigStore().load(workflowPath);
451
+ return {
452
+ lifecycle: resolution.lifecycle,
453
+ maxConcurrentAgents: resolution.workflow.agent.maxConcurrentAgents,
454
+ maxConcurrentAgentsByState: resolution.workflow.agent.maxConcurrentAgentsByState
455
+ };
456
+ } catch (error) {
457
+ const message = error instanceof Error ? error.message : String(error);
458
+ failures.push(`${workflowPath}: ${message}`);
459
+ }
460
+ }
461
+ throw new ProjectExplainWorkflowError(
462
+ `Unable to load WORKFLOW.md for project explain. Checked: ${failures.join("; ")}`
463
+ );
464
+ }
465
+ function resolveExplainWorkflowCandidates(input) {
466
+ const paths = [];
467
+ if (input.explicitWorkflowPath) {
468
+ paths.push(resolve(input.explicitWorkflowPath));
469
+ }
470
+ if (input.repository.path) {
471
+ paths.push(join(resolve(input.repository.path), "WORKFLOW.md"));
472
+ }
473
+ const newestRuns = [...input.runs].sort(
474
+ (left, right) => (Date.parse(right.updatedAt) || 0) - (Date.parse(left.updatedAt) || 0)
475
+ );
476
+ for (const run of newestRuns) {
477
+ if (run.workflowPath) {
478
+ paths.push(resolve(run.workflowPath));
479
+ }
480
+ if (run.workingDirectory) {
481
+ paths.push(join(resolve(run.workingDirectory), "WORKFLOW.md"));
482
+ }
483
+ }
484
+ return [...new Set(paths)];
485
+ }
486
+ function createProjectItemsCache() {
487
+ const entries = /* @__PURE__ */ new Map();
488
+ return {
489
+ getOrLoad(key, load) {
490
+ const cached = entries.get(key);
491
+ if (cached) {
492
+ return cached;
493
+ }
494
+ const pending = load().catch((error) => {
495
+ entries.delete(key);
496
+ throw error;
497
+ });
498
+ entries.set(key, pending);
499
+ return pending;
500
+ }
501
+ };
502
+ }
503
+ async function readRuns(runtimeRoot, projectId) {
504
+ let runIds;
505
+ try {
506
+ runIds = await readdir(join(runtimeRoot, "runs"));
507
+ } catch {
508
+ return [];
509
+ }
510
+ const runs = await Promise.all(
511
+ runIds.map(
512
+ (runId) => readJsonFile(
513
+ join(runtimeRoot, "runs", runId, "run.json")
514
+ )
515
+ )
516
+ );
517
+ return runs.filter(
518
+ (run) => run !== null && run.projectId === projectId
519
+ );
520
+ }
521
+ async function readJsonFile(path) {
522
+ try {
523
+ return JSON.parse(await readFile(path, "utf8"));
524
+ } catch {
525
+ return null;
526
+ }
527
+ }
528
+ function renderProjectExplainReport(report, noColor) {
529
+ const apply = noColor ? (value) => stripAnsi(value) : (value) => value;
530
+ const lines = [
531
+ apply(bold(`Issue dispatch explanation: ${report.issue.identifier}`)),
532
+ report.summary,
533
+ "",
534
+ `State: ${report.issue.state ?? "unknown"}`,
535
+ `Repository: ${report.issue.repository}`,
536
+ "",
537
+ "Checks:"
538
+ ];
539
+ for (const check of report.checks) {
540
+ const marker = check.status === "pass" ? green("\u2713") : check.status === "warn" ? yellow("!") : red("\u2717");
541
+ lines.push(` ${apply(marker)} ${check.message}`);
542
+ if (check.hint) {
543
+ lines.push(` Hint: ${check.hint}`);
544
+ }
545
+ }
546
+ lines.push("");
547
+ lines.push("Related commands:");
548
+ lines.push(" gh-symphony workflow preview");
549
+ lines.push(" gh-symphony doctor");
550
+ lines.push(" gh-symphony project status");
551
+ lines.push(" gh-symphony logs --issue " + report.issue.identifier);
552
+ return lines.join("\n") + "\n";
553
+ }
240
554
  async function readHttpEndpoint(configDir, projectId) {
241
555
  try {
242
- const content = await readFile(httpStatusPath(configDir, projectId), "utf8");
556
+ const content = await readFile(
557
+ httpStatusPath(configDir, projectId),
558
+ "utf8"
559
+ );
243
560
  const state = JSON.parse(content);
244
561
  return typeof state.endpoint === "string" && state.endpoint.length > 0 ? state.endpoint : null;
245
562
  } catch {
@@ -251,7 +568,12 @@ async function readProcessUptime(pid) {
251
568
  return "-";
252
569
  }
253
570
  try {
254
- const { stdout } = await execFile("ps", ["-o", "etime=", "-p", String(pid)]);
571
+ const { stdout } = await execFile("ps", [
572
+ "-o",
573
+ "etime=",
574
+ "-p",
575
+ String(pid)
576
+ ]);
255
577
  const seconds = parsePsElapsedTime(stdout);
256
578
  return seconds === null ? "-" : formatDuration(seconds);
257
579
  } catch {
@@ -660,7 +982,9 @@ async function projectRemove(args, options) {
660
982
  process.exitCode = 1;
661
983
  return;
662
984
  }
663
- const updatedProjects = global.projects.filter((entry) => entry !== projectId);
985
+ const updatedProjects = global.projects.filter(
986
+ (entry) => entry !== projectId
987
+ );
664
988
  if (updatedProjects.length === global.projects.length) {
665
989
  process.stderr.write(`Project "${projectId}" not found.
666
990
  `);
@@ -3,7 +3,7 @@ import {
3
3
  configFilePath,
4
4
  loadGlobalConfig,
5
5
  saveGlobalConfig
6
- } from "./chunk-ROGRTUFI.js";
6
+ } from "./chunk-QIRE2VXS.js";
7
7
 
8
8
  // src/commands/config-cmd.ts
9
9
  import { spawn } from "child_process";
@@ -19,14 +19,14 @@ import {
19
19
  resolveClaudeCommandBinary,
20
20
  resolveRuntimeCommandBinary,
21
21
  runClaudePreflight
22
- } from "./chunk-QEONJ5DZ.js";
22
+ } from "./chunk-EEQQWTXS.js";
23
23
  import {
24
24
  resolveRuntimeRoot
25
- } from "./chunk-5NV3LSAJ.js";
25
+ } from "./chunk-IWFX2FMA.js";
26
26
  import {
27
27
  inspectManagedProjectSelection
28
- } from "./chunk-C7G7RJ4G.js";
29
- import "./chunk-ROGRTUFI.js";
28
+ } from "./chunk-DDL4BWSL.js";
29
+ import "./chunk-QIRE2VXS.js";
30
30
 
31
31
  // src/commands/doctor.ts
32
32
  import { constants } from "fs";
package/dist/index.js CHANGED
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  resolveConfigDir
4
- } from "./chunk-ROGRTUFI.js";
4
+ } from "./chunk-QIRE2VXS.js";
5
5
 
6
6
  // src/index.ts
7
7
  import { realpathSync } from "fs";
@@ -278,21 +278,21 @@ ${bashFunction}complete -F _gh_symphony_completion gh-symphony
278
278
 
279
279
  // src/index.ts
280
280
  var COMMANDS = {
281
- workflow: () => import("./workflow-BLJH2HC3.js"),
282
- init: () => import("./init-HZ3JEDGQ.js"),
283
- setup: () => import("./setup-B2SVLW2R.js"),
284
- doctor: () => import("./doctor-4HBRICHP.js"),
285
- upgrade: () => import("./upgrade-OJXPZRYE.js"),
286
- start: () => import("./start-I2CC7BLW.js"),
287
- stop: () => import("./stop-7MFCBQVW.js"),
288
- status: () => import("./status-QSCFVGRQ.js"),
289
- run: () => import("./run-XJQ6BF7U.js"),
290
- recover: () => import("./recover-L3MJHHDA.js"),
291
- logs: () => import("./logs-6JKKYDGJ.js"),
292
- project: () => import("./project-25NQ4J4Y.js"),
293
- repo: () => import("./repo-TDCWQR6P.js"),
294
- config: () => import("./config-cmd-DNXNL26Z.js"),
295
- version: () => import("./version-TBDCTKDO.js")
281
+ workflow: () => import("./workflow-L3KT6HB7.js"),
282
+ init: () => import("./init-54HMKNYI.js"),
283
+ setup: () => import("./setup-TZJSM3QV.js"),
284
+ doctor: () => import("./doctor-EJUMPBMW.js"),
285
+ upgrade: () => import("./upgrade-O33S2SJK.js"),
286
+ start: () => import("./start-RTAHQMR2.js"),
287
+ stop: () => import("./stop-MDKMJPVR.js"),
288
+ status: () => import("./status-F4D52OVK.js"),
289
+ run: () => import("./run-IHN3ZL35.js"),
290
+ recover: () => import("./recover-LTLKMTRX.js"),
291
+ logs: () => import("./logs-GTZ4U5JE.js"),
292
+ project: () => import("./project-RMYMZSFV.js"),
293
+ repo: () => import("./repo-WI7GF6XQ.js"),
294
+ config: () => import("./config-cmd-Z3A7V6NC.js"),
295
+ version: () => import("./version-CW54Q7BK.js")
296
296
  };
297
297
  function addGlobalOptions(command) {
298
298
  return command.option("--config <dir>", "Config directory").addOption(new Option("--config-dir <dir>").hideHelp()).option("-v, --verbose", "Enable verbose output").option("--json", "Output in JSON format").option("--no-color", "Disable color output");
@@ -356,7 +356,10 @@ function createProgram() {
356
356
  new Command().name("gh-symphony").description("AI Coding Agent Orchestrator").exitOverride().helpOption("-h, --help", "Show help").addHelpCommand("help [command]", "Show help for command").showHelpAfterError("(run with --help for usage)").option("-V, --version", "Show version")
357
357
  );
358
358
  addGlobalOptions(
359
- program.command("init", { hidden: true }).description("Alias for 'gh-symphony workflow init'").option("--non-interactive", "Run without prompts").option("--project <id>", "GitHub Project ID or URL").option("--output <path>", "Write WORKFLOW.md to a custom path").option("--runtime <kind>", "Runtime preset: codex-app-server or claude-print").option("--skip-skills", "Skip runtime skill generation").option("--skip-context", "Skip .gh-symphony/context.yaml generation").option("--dry-run", "Preview generated files without writing them").allowExcessArguments(false)
359
+ program.command("init", { hidden: true }).description("Alias for 'gh-symphony workflow init'").option("--non-interactive", "Run without prompts").option("--project <id>", "GitHub Project ID or URL").option("--output <path>", "Write WORKFLOW.md to a custom path").option(
360
+ "--runtime <kind>",
361
+ "Runtime preset: codex-app-server or claude-print"
362
+ ).option("--skip-skills", "Skip runtime skill generation").option("--skip-context", "Skip .gh-symphony/context.yaml generation").option("--dry-run", "Preview generated files without writing them").allowExcessArguments(false)
360
363
  ).action(async function() {
361
364
  markInvoked();
362
365
  const values = this.optsWithGlobals();
@@ -382,7 +385,10 @@ function createProgram() {
382
385
  );
383
386
  });
384
387
  addGlobalOptions(
385
- workflow.command("init").description("Generate WORKFLOW.md and workflow support files").option("--non-interactive", "Run without prompts").option("--project <id>", "GitHub Project ID or URL").option("--output <path>", "Write WORKFLOW.md to a custom path").option("--runtime <kind>", "Runtime preset: codex-app-server or claude-print").option("--skip-skills", "Skip runtime skill generation").option("--skip-context", "Skip .gh-symphony/context.yaml generation").option("--dry-run", "Preview generated files without writing them").allowExcessArguments(false)
388
+ workflow.command("init").description("Generate WORKFLOW.md and workflow support files").option("--non-interactive", "Run without prompts").option("--project <id>", "GitHub Project ID or URL").option("--output <path>", "Write WORKFLOW.md to a custom path").option(
389
+ "--runtime <kind>",
390
+ "Runtime preset: codex-app-server or claude-print"
391
+ ).option("--skip-skills", "Skip runtime skill generation").option("--skip-context", "Skip .gh-symphony/context.yaml generation").option("--dry-run", "Preview generated files without writing them").allowExcessArguments(false)
386
392
  ).action(async function() {
387
393
  markInvoked();
388
394
  const values = this.optsWithGlobals();
@@ -459,7 +465,7 @@ function createProgram() {
459
465
  ).option(
460
466
  "--web [port]",
461
467
  "Expose the control plane web dashboard and API over HTTP"
462
- ).option("--log-level <level>", "Orchestrator lifecycle log level").option("--project-id <projectId>", "Project identifier").addOption(new Option("--project <projectId>").hideHelp()).allowExcessArguments(false)
468
+ ).option("--log-level <level>", "Orchestrator lifecycle log level").addOption(new Option("--project-id <projectId>").hideHelp()).addOption(new Option("--project <projectId>").hideHelp()).allowExcessArguments(false)
463
469
  ).action(async function() {
464
470
  markInvoked();
465
471
  const values = this.optsWithGlobals();
@@ -473,7 +479,7 @@ function createProgram() {
473
479
  await invokeHandler("start", args, values);
474
480
  });
475
481
  addGlobalOptions(
476
- program.command("stop").description("Stop the background orchestrator").option("--force", "Force stop with SIGKILL").option("--project-id <projectId>", "Project identifier").addOption(new Option("--project <projectId>").hideHelp()).allowExcessArguments(false)
482
+ program.command("stop").description("Stop the background orchestrator").option("--force", "Force stop with SIGKILL").addOption(new Option("--project-id <projectId>").hideHelp()).addOption(new Option("--project <projectId>").hideHelp()).allowExcessArguments(false)
477
483
  ).action(async function() {
478
484
  markInvoked();
479
485
  const values = this.optsWithGlobals();
@@ -483,7 +489,7 @@ function createProgram() {
483
489
  await invokeHandler("stop", args, values);
484
490
  });
485
491
  addGlobalOptions(
486
- program.command("status").description("Show orchestrator status").option("-w, --watch", "Watch status continuously").option("--project-id <projectId>", "Project identifier").addOption(new Option("--project <projectId>").hideHelp()).allowExcessArguments(false)
492
+ program.command("status").description("Show orchestrator status").option("-w, --watch", "Watch status continuously").addOption(new Option("--project-id <projectId>").hideHelp()).addOption(new Option("--project <projectId>").hideHelp()).allowExcessArguments(false)
487
493
  ).action(async function() {
488
494
  markInvoked();
489
495
  const values = this.optsWithGlobals();
@@ -612,6 +618,16 @@ function createProgram() {
612
618
  pushOption(args, "--watch", values.watch);
613
619
  await invokeHandler("project", args, values);
614
620
  });
621
+ addGlobalOptions(
622
+ project.command("explain").description("Explain why a project issue is not dispatching").argument("<issue>", "Issue identifier, for example owner/repo#123").option("--project-id <projectId>", "Project identifier").option("--workflow <path>", "Path to the WORKFLOW.md file to evaluate").addOption(new Option("--project <projectId>").hideHelp()).allowExcessArguments(false)
623
+ ).action(async function(issue) {
624
+ markInvoked();
625
+ const values = this.optsWithGlobals();
626
+ const args = ["explain", issue];
627
+ pushOption(args, "--project-id", resolveProjectId(values));
628
+ pushOption(args, "--workflow", values.workflow);
629
+ await invokeHandler("project", args, values);
630
+ });
615
631
  const repo = addGlobalOptions(
616
632
  program.command("repo").description("Manage repositories in the active project")
617
633
  );
@@ -629,6 +645,57 @@ function createProgram() {
629
645
  this.optsWithGlobals()
630
646
  );
631
647
  });
648
+ addGlobalOptions(
649
+ repo.command("init").description("Initialize gh-symphony for the current repository").option("--repo-dir <path>", "Repository directory").option("--workflow-file <path>", "Use a custom WORKFLOW.md path").addOption(new Option("--project-id <projectId>").hideHelp()).addOption(new Option("--project <projectId>").hideHelp()).allowExcessArguments(false)
650
+ ).action(async function() {
651
+ markInvoked();
652
+ const values = this.optsWithGlobals();
653
+ const args = ["init"];
654
+ pushOption(args, "--repo-dir", values.repoDir);
655
+ pushOption(args, "--workflow-file", values.workflowFile);
656
+ pushOption(args, "--project-id", resolveProjectId(values));
657
+ await invokeHandler("repo", args, values);
658
+ });
659
+ addGlobalOptions(
660
+ repo.command("start").description("Start the orchestrator for the current repository").option("-d, --daemon", "Start in daemon mode").option("--once", "Run a single orchestration tick and exit").option(
661
+ "--http [port]",
662
+ "Expose dashboard and refresh endpoints over HTTP"
663
+ ).option(
664
+ "--web [port]",
665
+ "Expose the control plane web dashboard and API over HTTP"
666
+ ).option("--log-level <level>", "Orchestrator lifecycle log level").addOption(new Option("--project-id <projectId>").hideHelp()).addOption(new Option("--project <projectId>").hideHelp()).allowExcessArguments(false)
667
+ ).action(async function() {
668
+ markInvoked();
669
+ const values = this.optsWithGlobals();
670
+ const args = ["start"];
671
+ pushOption(args, "--project-id", resolveProjectId(values));
672
+ pushOption(args, "--daemon", values.daemon);
673
+ pushOption(args, "--once", values.once);
674
+ pushOption(args, "--http", values.http);
675
+ pushOption(args, "--web", values.web);
676
+ pushOption(args, "--log-level", values.logLevel);
677
+ await invokeHandler("repo", args, values);
678
+ });
679
+ addGlobalOptions(
680
+ repo.command("status").description("Show current repository orchestrator status").option("-w, --watch", "Watch status continuously").addOption(new Option("--project-id <projectId>").hideHelp()).addOption(new Option("--project <projectId>").hideHelp()).allowExcessArguments(false)
681
+ ).action(async function() {
682
+ markInvoked();
683
+ const values = this.optsWithGlobals();
684
+ const args = ["status"];
685
+ pushOption(args, "--project-id", resolveProjectId(values));
686
+ pushOption(args, "--watch", values.watch);
687
+ await invokeHandler("repo", args, values);
688
+ });
689
+ addGlobalOptions(
690
+ repo.command("stop").description("Stop the current repository background orchestrator").option("--force", "Force stop with SIGKILL").addOption(new Option("--project-id <projectId>").hideHelp()).addOption(new Option("--project <projectId>").hideHelp()).allowExcessArguments(false)
691
+ ).action(async function() {
692
+ markInvoked();
693
+ const values = this.optsWithGlobals();
694
+ const args = ["stop"];
695
+ pushOption(args, "--project-id", resolveProjectId(values));
696
+ pushOption(args, "--force", values.force);
697
+ await invokeHandler("repo", args, values);
698
+ });
632
699
  addGlobalOptions(
633
700
  repo.command("add").description("Add a repository").argument("<owner/name>", "Repository spec").allowExcessArguments(false)
634
701
  ).action(async function(repoSpec) {
@@ -15,10 +15,10 @@ import {
15
15
  writeConfig,
16
16
  writeEcosystem,
17
17
  writeWorkflowPlan
18
- } from "./chunk-JN3TQVFV.js";
18
+ } from "./chunk-HMLBBZNY.js";
19
19
  import "./chunk-C67H3OUL.js";
20
- import "./chunk-QEONJ5DZ.js";
21
- import "./chunk-ROGRTUFI.js";
20
+ import "./chunk-EEQQWTXS.js";
21
+ import "./chunk-QIRE2VXS.js";
22
22
  export {
23
23
  abortIfCancelled,
24
24
  buildAutomaticStateMappings,