@gh-symphony/cli 0.0.2 → 0.0.3

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.
@@ -22,7 +22,6 @@ export type EcosystemResult = {
22
22
  skillsWritten: string[];
23
23
  skillsSkipped: string[];
24
24
  };
25
- export declare function resolveTenantRuntime(configDir: string, tenantId: string, tenantWorkerCommand?: string): Promise<string>;
26
25
  export declare function writeEcosystem(opts: EcosystemOptions): Promise<EcosystemResult>;
27
26
  type WriteConfigInput = {
28
27
  tenantId: string;
@@ -1,13 +1,12 @@
1
1
  import * as p from "@clack/prompts";
2
- import { parseWorkflowMarkdown } from "@gh-symphony/core";
3
2
  import { createHash } from "node:crypto";
4
- import { mkdir, readFile, rename, writeFile } from "node:fs/promises";
3
+ import { mkdir, rename, writeFile } from "node:fs/promises";
5
4
  import { basename, dirname, join, relative, resolve } from "node:path";
6
5
  import { fileURLToPath } from "node:url";
7
6
  import { createClient, validateToken, checkRequiredScopes, listUserProjects, getProjectDetail, GitHubScopeError, } from "../github/client.js";
8
7
  import { inferAllStateRoles, toWorkflowLifecycleConfig, validateStateMapping, } from "../mapping/smart-defaults.js";
9
8
  import { generateWorkflowMarkdown } from "../workflow/generate-workflow-md.js";
10
- import { loadGlobalConfig, loadTenantConfig, saveGlobalConfig, saveTenantConfig, saveWorkflowMapping, } from "../config.js";
9
+ import { loadGlobalConfig, saveGlobalConfig, saveTenantConfig, saveWorkflowMapping, } from "../config.js";
11
10
  import { getGhToken, ensureGhAuth, GhAuthError } from "../github/gh-auth.js";
12
11
  import { detectEnvironment } from "../detection/environment-detector.js";
13
12
  import { buildContextYaml, writeContextYaml, } from "../context/generate-context-yaml.js";
@@ -76,43 +75,6 @@ const handler = async (args, options) => {
76
75
  await runInteractive(options);
77
76
  };
78
77
  export default handler;
79
- function inferAgentRuntimeFromCommand(command) {
80
- if (!command) {
81
- return null;
82
- }
83
- if (command.includes("claude-code")) {
84
- return "claude-code";
85
- }
86
- if (command.includes("codex")) {
87
- return "codex";
88
- }
89
- return null;
90
- }
91
- function isWorkerBootstrapCommand(command) {
92
- return (command.includes("@gh-symphony/worker/dist/index.js") ||
93
- command.includes("packages/worker/dist/index.js"));
94
- }
95
- function isMissingAgentEnvError(error) {
96
- return (error instanceof Error &&
97
- error.message.includes("Workflow front matter requires environment variable"));
98
- }
99
- export async function resolveTenantRuntime(configDir, tenantId, tenantWorkerCommand) {
100
- const workflowPath = join(configDir, "tenants", tenantId, "WORKFLOW.md");
101
- try {
102
- const workflowMarkdown = await readFile(workflowPath, "utf8");
103
- const agentCommand = parseWorkflowMarkdown(workflowMarkdown, {}).agentCommand;
104
- if (!isWorkerBootstrapCommand(agentCommand)) {
105
- return agentCommand;
106
- }
107
- }
108
- catch (error) {
109
- const err = error;
110
- if (err.code !== "ENOENT" && !isMissingAgentEnvError(error)) {
111
- throw error;
112
- }
113
- }
114
- return inferAgentRuntimeFromCommand(tenantWorkerCommand) ?? "codex";
115
- }
116
78
  export async function writeEcosystem(opts) {
117
79
  const { cwd, projectDetail, statusField, runtime, skipSkills, skipContext } = opts;
118
80
  const ghSymphonyDir = join(cwd, ".gh-symphony");
@@ -327,103 +289,9 @@ async function runNonInteractive(flags, options) {
327
289
  // ── Interactive mode: WORKFLOW.md generation ─────────────────────────────────
328
290
  async function runInteractive(options) {
329
291
  p.intro("gh-symphony — WORKFLOW.md Setup");
330
- // Case A: tenant(s) already configured
331
- const globalConfig = await loadGlobalConfig(options.configDir);
332
- if (globalConfig?.tenants?.length) {
333
- await runInteractiveFromTenant(globalConfig, options);
334
- return;
335
- }
336
- // Case B: no tenants — standalone WORKFLOW.md generation
337
292
  await runInteractiveStandalone(options);
338
293
  }
339
- // ── Case A: Generate WORKFLOW.md from existing tenant config ─────────────────
340
- async function runInteractiveFromTenant(globalConfig, options) {
341
- const tenants = globalConfig.tenants;
342
- let tenantId;
343
- if (tenants.length === 1) {
344
- tenantId = tenants[0];
345
- }
346
- else {
347
- // Multiple tenants: ask which one to base WORKFLOW.md on
348
- const tenantConfigs = await Promise.all(tenants.map(async (id) => {
349
- const cfg = await loadTenantConfig(options.configDir, id);
350
- return { id, label: cfg?.slug ?? id };
351
- }));
352
- tenantId = await abortIfCancelled(p.select({
353
- message: "Select a tenant to base WORKFLOW.md on:",
354
- options: tenantConfigs.map((t) => ({
355
- value: t.id,
356
- label: t.label,
357
- hint: globalConfig.activeTenant === t.id ? "active" : undefined,
358
- })),
359
- }));
360
- }
361
- const tenantConfig = await loadTenantConfig(options.configDir, tenantId);
362
- if (!tenantConfig) {
363
- p.log.error(`Tenant config not found for "${tenantId}".`);
364
- process.exitCode = 1;
365
- return;
366
- }
367
- const lifecycle = tenantConfig.workflowMapping?.lifecycle;
368
- if (!lifecycle) {
369
- p.log.error(`Tenant "${tenantId}" has no workflow lifecycle config. Run 'gh-symphony tenant add' first.`);
370
- process.exitCode = 1;
371
- return;
372
- }
373
- const mappings = {};
374
- const workflowMapping = tenantConfig.workflowMapping;
375
- if (workflowMapping) {
376
- Object.assign(mappings, workflowMapping.mappings);
377
- }
378
- const projectId = tenantConfig.tracker.settings?.projectId;
379
- const stateFieldName = workflowMapping?.stateFieldName ?? lifecycle.stateFieldName;
380
- const runtime = await resolveTenantRuntime(options.configDir, tenantId, tenantConfig.runtime.workerCommand);
381
- const workflowMd = generateWorkflowMarkdown({
382
- projectId: projectId ?? "",
383
- stateFieldName,
384
- mappings,
385
- lifecycle,
386
- runtime,
387
- });
388
- const outputPath = resolve("WORKFLOW.md");
389
- await writeFile(outputPath, workflowMd, "utf8");
390
- const projId = tenantConfig.tracker.settings?.projectId;
391
- let ecosystemResult = null;
392
- let token;
393
- try {
394
- token = getGhToken();
395
- }
396
- catch {
397
- // getGhToken failed — token stays undefined; ecosystem write proceeds best-effort
398
- }
399
- if (token && projId) {
400
- try {
401
- const client = createClient(token);
402
- const fullProject = await getProjectDetail(client, projId);
403
- const sf = fullProject.statusFields.find((f) => f.name.toLowerCase() === stateFieldName.toLowerCase()) ?? fullProject.statusFields[0];
404
- if (sf) {
405
- ecosystemResult = await writeEcosystem({
406
- cwd: process.cwd(),
407
- projectDetail: fullProject,
408
- statusField: sf,
409
- runtime,
410
- skipSkills: false,
411
- skipContext: false,
412
- });
413
- }
414
- }
415
- catch {
416
- // best-effort: don't fail init if GitHub API is unreachable
417
- }
418
- }
419
- if (ecosystemResult) {
420
- printEcosystemSummary(ecosystemResult, outputPath, { interactive: true });
421
- }
422
- else {
423
- p.outro(`WORKFLOW.md generated at ${outputPath}`);
424
- }
425
- }
426
- // ── Case B: Standalone WORKFLOW.md generation (no tenant) ────────────────────
294
+ // ── Interactive WORKFLOW.md generation ────────────────────────────────────────
427
295
  async function runInteractiveStandalone(_options) {
428
296
  const s1 = p.spinner();
429
297
  s1.start("Checking gh CLI authentication...");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gh-symphony/cli",
3
- "version": "0.0.2",
3
+ "version": "0.0.3",
4
4
  "license": "MIT",
5
5
  "author": "hojinzs",
6
6
  "description": "Interactive CLI for GitHub Symphony orchestration",
@@ -36,10 +36,10 @@
36
36
  },
37
37
  "dependencies": {
38
38
  "@clack/prompts": "^0.9.1",
39
- "@gh-symphony/orchestrator": "0.0.2",
40
- "@gh-symphony/core": "0.0.2",
41
- "@gh-symphony/worker": "0.0.2",
42
- "@gh-symphony/tracker-github": "0.0.2"
39
+ "@gh-symphony/core": "0.0.3",
40
+ "@gh-symphony/orchestrator": "0.0.3",
41
+ "@gh-symphony/tracker-github": "0.0.3",
42
+ "@gh-symphony/worker": "0.0.3"
43
43
  },
44
44
  "scripts": {
45
45
  "build": "tsc -p tsconfig.json",