@gh-symphony/cli 0.0.22 → 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 +72 -77
  2. package/dist/{chunk-IWFX2FMA.js → chunk-6I753NYO.js} +4 -1
  3. package/dist/{workflow-L3KT6HB7.js → chunk-B4ZJMAZL.js} +27 -19
  4. package/dist/{chunk-2TSM3INR.js → chunk-DLZAJXZL.js} +575 -12
  5. package/dist/chunk-GHVDABFO.js +235 -0
  6. package/dist/{chunk-EEQQWTXS.js → chunk-GPRCOJDJ.js} +158 -75
  7. package/dist/{chunk-36KYEDEO.js → chunk-MVRF7BES.js} +1 -10
  8. package/dist/{chunk-2UW7NQLX.js → chunk-VFHMHHZW.js} +1 -1
  9. package/dist/{chunk-HMLBBZNY.js → chunk-WM2B6BJ7.js} +16 -71
  10. package/dist/{chunk-QIRE2VXS.js → chunk-WOVNN5NW.js} +16 -17
  11. package/dist/{chunk-C67H3OUL.js → chunk-Z3NZOPLZ.js} +0 -81
  12. package/dist/{config-cmd-Z3A7V6NC.js → config-cmd-2ADPUYWA.js} +1 -1
  13. package/dist/{doctor-EJUMPBMW.js → doctor-EEPNFCGF.js} +464 -40
  14. package/dist/index.js +340 -294
  15. package/dist/{chunk-PUDXVBSN.js → repo-RX4OK7XH.js} +5944 -3001
  16. package/dist/{setup-TZJSM3QV.js → setup-XNHHRBGU.js} +57 -92
  17. package/dist/{upgrade-O33S2SJK.js → upgrade-NS53EO2B.js} +2 -2
  18. package/dist/{version-CW54Q7BK.js → version-2RHFZ5CI.js} +1 -1
  19. package/dist/worker-entry.js +10 -5
  20. package/dist/workflow-26QNZZWH.js +22 -0
  21. package/package.json +4 -4
  22. package/dist/chunk-DDL4BWSL.js +0 -146
  23. package/dist/chunk-DFLXHNYQ.js +0 -482
  24. package/dist/chunk-E7HYEEZD.js +0 -1318
  25. package/dist/chunk-GDE6FYN4.js +0 -26
  26. package/dist/chunk-GSX2FV3M.js +0 -103
  27. package/dist/chunk-ZHOKYUO3.js +0 -1047
  28. package/dist/init-54HMKNYI.js +0 -38
  29. package/dist/logs-GTZ4U5JE.js +0 -188
  30. package/dist/project-RMYMZSFV.js +0 -25
  31. package/dist/recover-LTLKMTRX.js +0 -133
  32. package/dist/repo-WI7GF6XQ.js +0 -749
  33. package/dist/run-IHN3ZL35.js +0 -122
  34. package/dist/start-RTAHQMR2.js +0 -19
  35. package/dist/status-F4D52OVK.js +0 -12
  36. package/dist/stop-MDKMJPVR.js +0 -10
@@ -0,0 +1,235 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ resolveRepoRuntimeRoot
4
+ } from "./chunk-6I753NYO.js";
5
+ import {
6
+ parseWorkflowMarkdown
7
+ } from "./chunk-GPRCOJDJ.js";
8
+ import {
9
+ saveGlobalConfig,
10
+ saveProjectConfig
11
+ } from "./chunk-WOVNN5NW.js";
12
+
13
+ // src/repo-runtime.ts
14
+ import { execFileSync } from "child_process";
15
+ import {
16
+ mkdir,
17
+ readdir,
18
+ readFile,
19
+ rename,
20
+ rm,
21
+ stat,
22
+ writeFile
23
+ } from "fs/promises";
24
+ import { basename, dirname, join, resolve } from "path";
25
+ var INTERNAL_PROJECT_ID = "repository";
26
+ var RepoRuntimeMigrationError = class extends Error {
27
+ };
28
+ function parseRepoRuntimeFlags(args) {
29
+ const flags = { repoDir: process.cwd() };
30
+ for (let i = 0; i < args.length; i += 1) {
31
+ const arg = args[i];
32
+ const value = args[i + 1];
33
+ if (arg === "--repo-dir") {
34
+ if (!value || value.startsWith("-")) {
35
+ throw new Error("Option '--repo-dir' argument missing");
36
+ }
37
+ flags.repoDir = resolve(value);
38
+ i += 1;
39
+ continue;
40
+ }
41
+ if (arg === "--workflow-file") {
42
+ if (!value || value.startsWith("-")) {
43
+ throw new Error("Option '--workflow-file' argument missing");
44
+ }
45
+ flags.workflowFile = value;
46
+ i += 1;
47
+ continue;
48
+ }
49
+ if (arg?.startsWith("-")) {
50
+ throw new Error(`Unknown option '${arg}'`);
51
+ }
52
+ }
53
+ return flags;
54
+ }
55
+ async function initRepoRuntime(flags) {
56
+ const repoDir = resolve(flags.repoDir);
57
+ const runtimeRoot = resolveRepoRuntimeRoot(repoDir);
58
+ await migrateLegacyRuntime(runtimeRoot);
59
+ const workflowPath = resolve(repoDir, flags.workflowFile ?? "WORKFLOW.md");
60
+ const workflow = parseWorkflowMarkdown(await readFile(workflowPath, "utf8"));
61
+ const repository = resolveRepository(repoDir);
62
+ const trackerAdapter = workflow.tracker.kind ?? "github-project";
63
+ const trackerBindingId = workflow.tracker.projectId ?? workflow.tracker.projectSlug ?? "";
64
+ const trackerSettings = {
65
+ ...workflow.tracker.projectId ? { projectId: workflow.tracker.projectId } : {},
66
+ repository: `${repository.owner}/${repository.name}`
67
+ };
68
+ if (flags.assignedOnly) {
69
+ trackerSettings.assignedOnly = true;
70
+ }
71
+ if (trackerAdapter === "file") {
72
+ if (!process.env.GH_SYMPHONY_FILE_TRACKER_ISSUES_PATH) {
73
+ throw new Error(
74
+ "File tracker repo init requires GH_SYMPHONY_FILE_TRACKER_ISSUES_PATH to point to the issues fixture."
75
+ );
76
+ }
77
+ trackerSettings.issuesPath = process.env.GH_SYMPHONY_FILE_TRACKER_ISSUES_PATH;
78
+ }
79
+ const projectConfig = {
80
+ projectId: INTERNAL_PROJECT_ID,
81
+ slug: basename(repoDir) || INTERNAL_PROJECT_ID,
82
+ displayName: `${repository.owner}/${repository.name}`,
83
+ workspaceDir: repoDir,
84
+ repository,
85
+ tracker: {
86
+ adapter: trackerAdapter,
87
+ bindingId: trackerBindingId,
88
+ settings: trackerSettings
89
+ }
90
+ };
91
+ await mkdir(runtimeRoot, { recursive: true });
92
+ await saveProjectConfig(runtimeRoot, INTERNAL_PROJECT_ID, projectConfig);
93
+ await saveGlobalConfig(runtimeRoot, {
94
+ activeProject: INTERNAL_PROJECT_ID,
95
+ projects: [INTERNAL_PROJECT_ID]
96
+ });
97
+ const orchestratorConfig = {
98
+ projectId: INTERNAL_PROJECT_ID,
99
+ slug: projectConfig.slug,
100
+ workspaceDir: repoDir,
101
+ repository,
102
+ tracker: projectConfig.tracker
103
+ };
104
+ await writeJsonFile(join(runtimeRoot, "project.json"), orchestratorConfig);
105
+ return {
106
+ configDir: runtimeRoot,
107
+ projectId: INTERNAL_PROJECT_ID,
108
+ workflowPath,
109
+ repository
110
+ };
111
+ }
112
+ async function migrateLegacyRuntime(runtimeRoot) {
113
+ const projectsDir = join(runtimeRoot, "projects");
114
+ const projectIds = await readDirectoryNames(projectsDir);
115
+ if (projectIds.length === 0) {
116
+ return;
117
+ }
118
+ if (projectIds.length === 1 && projectIds[0] === INTERNAL_PROJECT_ID && await pathExists(join(runtimeRoot, "project.json"))) {
119
+ return;
120
+ }
121
+ if (projectIds.length > 1) {
122
+ throw new RepoRuntimeMigrationError(
123
+ [
124
+ "Multiple legacy project runtime directories were found under .runtime/orchestrator/projects.",
125
+ `Found: ${projectIds.join(", ")}`,
126
+ "Automatic migration is only supported when exactly one project directory exists.",
127
+ "Manually keep the project directory you want to promote, archive or remove the others, then re-run 'gh-symphony repo init'."
128
+ ].join("\n")
129
+ );
130
+ }
131
+ const sourceDir = join(projectsDir, projectIds[0]);
132
+ const entries = await readdir(sourceDir);
133
+ for (const entry of entries) {
134
+ const target = join(runtimeRoot, entry);
135
+ if (await pathExists(target)) {
136
+ throw new RepoRuntimeMigrationError(
137
+ `Cannot promote legacy runtime data because '${entry}' already exists in .runtime/orchestrator. Move or remove it, then re-run 'gh-symphony repo init'.`
138
+ );
139
+ }
140
+ await rename(join(sourceDir, entry), target);
141
+ }
142
+ await stripProjectIdFromRunRecords(join(runtimeRoot, "runs"));
143
+ await rm(projectsDir, { recursive: true, force: true });
144
+ }
145
+ async function stripProjectIdFromRunRecords(runsDir) {
146
+ for (const runId of await readDirectoryNames(runsDir)) {
147
+ const runPath = join(runsDir, runId, "run.json");
148
+ const run = await readJsonFile(runPath);
149
+ if (!run || !("projectId" in run)) {
150
+ continue;
151
+ }
152
+ delete run.projectId;
153
+ await writeJsonFile(runPath, run);
154
+ }
155
+ }
156
+ async function readDirectoryNames(path) {
157
+ try {
158
+ const entries = await readdir(path, { withFileTypes: true });
159
+ return entries.filter((entry) => entry.isDirectory()).map((entry) => entry.name).sort();
160
+ } catch (error) {
161
+ if (isMissing(error)) {
162
+ return [];
163
+ }
164
+ throw error;
165
+ }
166
+ }
167
+ function resolveRepository(repoDir) {
168
+ const remote = readGitOrigin(repoDir);
169
+ const cleanedRemote = remote.replace(/\.git$/, "");
170
+ const match = cleanedRemote.match(/github\.com[:/]([^/]+)\/([^/]+)$/) ?? cleanedRemote.match(/^([^/]+)\/([^/]+)$/);
171
+ if (!match) {
172
+ throw new Error(
173
+ "Unable to infer GitHub repository from git remote 'origin'. Run from a cloned GitHub repository or set origin to owner/name."
174
+ );
175
+ }
176
+ return {
177
+ owner: match[1],
178
+ name: match[2],
179
+ cloneUrl: remote.startsWith("http") ? remote : `https://github.com/${match[1]}/${match[2]}.git`,
180
+ path: repoDir
181
+ };
182
+ }
183
+ function readGitOrigin(repoDir) {
184
+ try {
185
+ return execFileSync(
186
+ "git",
187
+ ["-C", repoDir, "config", "--get", "remote.origin.url"],
188
+ {
189
+ encoding: "utf8",
190
+ stdio: ["ignore", "pipe", "ignore"]
191
+ }
192
+ ).trim();
193
+ } catch {
194
+ throw new Error(
195
+ "Unable to read git remote 'origin'. Run 'gh-symphony repo init' inside a cloned repository."
196
+ );
197
+ }
198
+ }
199
+ async function readJsonFile(path) {
200
+ try {
201
+ return JSON.parse(await readFile(path, "utf8"));
202
+ } catch (error) {
203
+ if (isMissing(error)) {
204
+ return null;
205
+ }
206
+ throw error;
207
+ }
208
+ }
209
+ async function writeJsonFile(path, value) {
210
+ await mkdir(dirname(path), { recursive: true });
211
+ const temporaryPath = `${path}.tmp`;
212
+ await writeFile(temporaryPath, JSON.stringify(value, null, 2) + "\n", "utf8");
213
+ await rename(temporaryPath, path);
214
+ }
215
+ async function pathExists(path) {
216
+ try {
217
+ await stat(path);
218
+ return true;
219
+ } catch (error) {
220
+ if (isMissing(error)) {
221
+ return false;
222
+ }
223
+ throw error;
224
+ }
225
+ }
226
+ function isMissing(error) {
227
+ return Boolean(
228
+ error && typeof error === "object" && "code" in error && (error.code === "ENOENT" || error.code === "ENOTDIR")
229
+ );
230
+ }
231
+
232
+ export {
233
+ parseRepoRuntimeFlags,
234
+ initRepoRuntime
235
+ };
@@ -583,73 +583,6 @@ function matchOptionalSection(markdown, heading) {
583
583
  return match?.[1]?.trim() ?? null;
584
584
  }
585
585
 
586
- // ../core/src/workflow/loader.ts
587
- import { createHash } from "crypto";
588
- import { access, readFile, stat } from "fs/promises";
589
- import { constants } from "fs";
590
- var WorkflowConfigStore = class {
591
- cache = /* @__PURE__ */ new Map();
592
- async load(workflowPath, env = process.env) {
593
- await access(workflowPath, constants.R_OK);
594
- const fileStat = await stat(workflowPath);
595
- const cached = this.cache.get(workflowPath);
596
- const markdown = await readFile(workflowPath, "utf8");
597
- const fingerprint = `${fileStat.mtimeMs}:${fileStat.size}:${createHash("sha256").update(markdown).digest("hex")}`;
598
- if (cached && cached.fingerprint === fingerprint) {
599
- return toWorkflowResolution(workflowPath, cached.workflow, {
600
- isValid: true,
601
- usedLastKnownGood: false,
602
- validationError: null
603
- });
604
- }
605
- try {
606
- const workflow = parseWorkflowMarkdown(markdown, env);
607
- this.cache.set(workflowPath, {
608
- fingerprint,
609
- workflow,
610
- loadedAt: (/* @__PURE__ */ new Date()).toISOString()
611
- });
612
- return toWorkflowResolution(workflowPath, workflow, {
613
- isValid: true,
614
- usedLastKnownGood: false,
615
- validationError: null
616
- });
617
- } catch (error) {
618
- if (cached) {
619
- return toWorkflowResolution(workflowPath, cached.workflow, {
620
- isValid: false,
621
- usedLastKnownGood: true,
622
- validationError: error instanceof Error ? error.message : "Invalid workflow definition."
623
- });
624
- }
625
- throw error;
626
- }
627
- }
628
- };
629
- function createDefaultWorkflowResolution() {
630
- return createInvalidWorkflowResolution(null, "missing_workflow_file");
631
- }
632
- function createInvalidWorkflowResolution(workflowPath, validationError) {
633
- return toWorkflowResolution(workflowPath, DEFAULT_WORKFLOW_DEFINITION, {
634
- isValid: false,
635
- usedLastKnownGood: false,
636
- validationError
637
- });
638
- }
639
- function toWorkflowResolution(workflowPath, workflow, metadata) {
640
- return {
641
- workflowPath,
642
- workflow,
643
- lifecycle: workflow.lifecycle,
644
- promptTemplate: workflow.promptTemplate,
645
- agentCommand: workflow.agentCommand,
646
- hookPath: workflow.hookPath ?? "",
647
- isValid: metadata.isValid,
648
- usedLastKnownGood: metadata.usedLastKnownGood,
649
- validationError: metadata.validationError
650
- };
651
- }
652
-
653
586
  // ../core/src/workflow/render.ts
654
587
  import {
655
588
  Liquid,
@@ -659,6 +592,17 @@ import {
659
592
  UndefinedVariableError
660
593
  } from "liquidjs";
661
594
  function buildPromptVariables(issue, options) {
595
+ const contentType = issue.metadata.contentType ?? "Issue";
596
+ const linkedPullRequests = Array.isArray(issue.metadata.linkedPullRequests) ? issue.metadata.linkedPullRequests.map(normalizePullRequestContext) : [];
597
+ const primaryPullRequest = contentType === "PullRequest" ? normalizePullRequestContext(
598
+ issue.metadata.pullRequest ?? linkedPullRequests[0] ?? buildPullRequestContextFromIssue(issue)
599
+ ) : linkedPullRequests[0] ?? null;
600
+ const pullRequestContext = buildPullRequestVariables({
601
+ contentType,
602
+ linkedPullRequests,
603
+ primaryPullRequest,
604
+ issueBranchName: issue.branchName
605
+ });
662
606
  return {
663
607
  issue: {
664
608
  id: issue.id,
@@ -672,13 +616,61 @@ function buildPromptVariables(issue, options) {
672
616
  labels: issue.labels,
673
617
  blocked_by: issue.blockedBy,
674
618
  branch_name: issue.branchName,
619
+ content_type: contentType,
620
+ linked_pull_requests: linkedPullRequests,
621
+ primary_pull_request: primaryPullRequest,
622
+ has_linked_pr: linkedPullRequests.length > 0,
675
623
  created_at: issue.createdAt,
676
624
  updated_at: issue.updatedAt,
677
625
  repository: `${issue.repository.owner}/${issue.repository.name}`
678
626
  },
627
+ pull_request_context: pullRequestContext,
679
628
  attempt: options.attempt
680
629
  };
681
630
  }
631
+ function normalizePullRequestContext(pullRequest) {
632
+ return {
633
+ ...pullRequest,
634
+ state: pullRequest.state ?? null,
635
+ projectState: pullRequest.projectState ?? null,
636
+ isDraft: pullRequest.isDraft ?? null,
637
+ merged: pullRequest.merged ?? null,
638
+ headRefName: pullRequest.headRefName ?? null,
639
+ baseRefName: pullRequest.baseRefName ?? null
640
+ };
641
+ }
642
+ function buildPullRequestVariables(options) {
643
+ const checkoutBranch = options.primaryPullRequest?.headRefName ?? (options.contentType === "PullRequest" ? options.issueBranchName : null);
644
+ const hasPrimaryPr = options.primaryPullRequest !== null;
645
+ return {
646
+ subject_type: options.contentType,
647
+ linked_pull_requests: options.linkedPullRequests,
648
+ primary_pull_request: options.primaryPullRequest,
649
+ has_linked_pr: options.linkedPullRequests.length > 0,
650
+ has_primary_pr: hasPrimaryPr,
651
+ checkout_branch: checkoutBranch,
652
+ // Policy flag for prompt templates: any primary PR means the worker must
653
+ // inspect review threads and checks before editing code.
654
+ review_first: hasPrimaryPr
655
+ };
656
+ }
657
+ function buildPullRequestContextFromIssue(issue) {
658
+ return {
659
+ id: issue.id,
660
+ number: issue.number,
661
+ identifier: issue.identifier,
662
+ url: issue.url,
663
+ state: null,
664
+ projectState: issue.state,
665
+ headRefName: issue.branchName,
666
+ repository: {
667
+ owner: issue.repository.owner,
668
+ name: issue.repository.name,
669
+ url: issue.repository.url ?? "",
670
+ cloneUrl: issue.repository.cloneUrl
671
+ }
672
+ };
673
+ }
682
674
  var STRICT_LIQUID_ENGINE = new Liquid({
683
675
  strictVariables: true,
684
676
  strictFilters: true,
@@ -873,6 +865,73 @@ function isOrchestratorChannelEvent(value) {
873
865
  return false;
874
866
  }
875
867
 
868
+ // ../core/src/workflow/loader.ts
869
+ import { createHash } from "crypto";
870
+ import { access, readFile, stat } from "fs/promises";
871
+ import { constants } from "fs";
872
+ var WorkflowConfigStore = class {
873
+ cache = /* @__PURE__ */ new Map();
874
+ async load(workflowPath, env = process.env) {
875
+ await access(workflowPath, constants.R_OK);
876
+ const fileStat = await stat(workflowPath);
877
+ const cached = this.cache.get(workflowPath);
878
+ const markdown = await readFile(workflowPath, "utf8");
879
+ const fingerprint = `${fileStat.mtimeMs}:${fileStat.size}:${createHash("sha256").update(markdown).digest("hex")}`;
880
+ if (cached && cached.fingerprint === fingerprint) {
881
+ return toWorkflowResolution(workflowPath, cached.workflow, {
882
+ isValid: true,
883
+ usedLastKnownGood: false,
884
+ validationError: null
885
+ });
886
+ }
887
+ try {
888
+ const workflow = parseWorkflowMarkdown(markdown, env);
889
+ this.cache.set(workflowPath, {
890
+ fingerprint,
891
+ workflow,
892
+ loadedAt: (/* @__PURE__ */ new Date()).toISOString()
893
+ });
894
+ return toWorkflowResolution(workflowPath, workflow, {
895
+ isValid: true,
896
+ usedLastKnownGood: false,
897
+ validationError: null
898
+ });
899
+ } catch (error) {
900
+ if (cached) {
901
+ return toWorkflowResolution(workflowPath, cached.workflow, {
902
+ isValid: false,
903
+ usedLastKnownGood: true,
904
+ validationError: error instanceof Error ? error.message : "Invalid workflow definition."
905
+ });
906
+ }
907
+ throw error;
908
+ }
909
+ }
910
+ };
911
+ function createDefaultWorkflowResolution() {
912
+ return createInvalidWorkflowResolution(null, "missing_workflow_file");
913
+ }
914
+ function createInvalidWorkflowResolution(workflowPath, validationError) {
915
+ return toWorkflowResolution(workflowPath, DEFAULT_WORKFLOW_DEFINITION, {
916
+ isValid: false,
917
+ usedLastKnownGood: false,
918
+ validationError
919
+ });
920
+ }
921
+ function toWorkflowResolution(workflowPath, workflow, metadata) {
922
+ return {
923
+ workflowPath,
924
+ workflow,
925
+ lifecycle: workflow.lifecycle,
926
+ promptTemplate: workflow.promptTemplate,
927
+ agentCommand: workflow.agentCommand,
928
+ hookPath: workflow.hookPath ?? "",
929
+ isValid: metadata.isValid,
930
+ usedLastKnownGood: metadata.usedLastKnownGood,
931
+ validationError: metadata.validationError
932
+ };
933
+ }
934
+
876
935
  // ../core/src/workflow/exit-classification.ts
877
936
  function classifySessionExit(params) {
878
937
  if (params.userInputRequired) {
@@ -1471,7 +1530,7 @@ async function runClaudePreflight(options, dependencies = {}) {
1471
1530
  const command = resolveRuntimeCommandBinary(options.command) ?? "claude";
1472
1531
  const checks = [];
1473
1532
  checks.push(checkClaudeBinary(command, options.cwd, deps));
1474
- checks.push(await checkAnthropicApiKey(env, options, deps));
1533
+ checks.push(await checkClaudeAuthentication(env, options, deps));
1475
1534
  checks.push(await checkWorkspaceMcpConfig(options.cwd, deps));
1476
1535
  if (options.includeGhAuth) {
1477
1536
  checks.push(checkGhAuthentication(options.cwd, deps));
@@ -1573,11 +1632,12 @@ function checkGhAuthentication(cwd, deps) {
1573
1632
  );
1574
1633
  }
1575
1634
  }
1576
- async function checkAnthropicApiKey(env, options, deps) {
1635
+ async function checkClaudeAuthentication(env, options, deps) {
1636
+ const authMode = options.authMode ?? "api-key-required";
1577
1637
  if (env.ANTHROPIC_API_KEY?.trim()) {
1578
1638
  return pass(
1579
1639
  "anthropic_api_key",
1580
- "Anthropic API key",
1640
+ "Claude authentication",
1581
1641
  "ANTHROPIC_API_KEY is configured in the environment.",
1582
1642
  { source: "env" }
1583
1643
  );
@@ -1585,9 +1645,32 @@ async function checkAnthropicApiKey(env, options, deps) {
1585
1645
  const brokerUrl = env.AGENT_CREDENTIAL_BROKER_URL?.trim();
1586
1646
  const brokerSecret = env.AGENT_CREDENTIAL_BROKER_SECRET?.trim();
1587
1647
  if (!brokerUrl || !brokerSecret) {
1648
+ if (authMode === "local-or-api-key" && !brokerUrl && !brokerSecret) {
1649
+ return warn(
1650
+ "anthropic_api_key",
1651
+ "Claude authentication",
1652
+ "ANTHROPIC_API_KEY and agent credential broker are not configured; Claude Code local login may be used for this non-bare runtime.",
1653
+ "If this runtime will run headlessly or with runtime.isolation.bare: true, set ANTHROPIC_API_KEY or configure AGENT_CREDENTIAL_BROKER_URL and AGENT_CREDENTIAL_BROKER_SECRET.",
1654
+ { source: "local" }
1655
+ );
1656
+ }
1657
+ if (brokerUrl || brokerSecret) {
1658
+ const missingName = brokerUrl ? "AGENT_CREDENTIAL_BROKER_SECRET" : "AGENT_CREDENTIAL_BROKER_URL";
1659
+ return fail(
1660
+ "anthropic_api_key",
1661
+ "Claude authentication",
1662
+ `Agent credential broker configuration is incomplete: ${missingName} is not configured.`,
1663
+ `Set ${missingName} or remove the partial broker configuration and use ANTHROPIC_API_KEY instead.`,
1664
+ {
1665
+ source: "broker",
1666
+ brokerUrl: brokerUrl ?? null,
1667
+ missing: missingName
1668
+ }
1669
+ );
1670
+ }
1588
1671
  return fail(
1589
1672
  "anthropic_api_key",
1590
- "Anthropic API key",
1673
+ "Claude authentication",
1591
1674
  "Neither ANTHROPIC_API_KEY nor an agent credential broker is configured.",
1592
1675
  "Set ANTHROPIC_API_KEY or configure AGENT_CREDENTIAL_BROKER_URL and AGENT_CREDENTIAL_BROKER_SECRET.",
1593
1676
  { source: "missing" }
@@ -1596,7 +1679,7 @@ async function checkAnthropicApiKey(env, options, deps) {
1596
1679
  if (options.probeCredentialBroker === false) {
1597
1680
  return pass(
1598
1681
  "anthropic_api_key",
1599
- "Anthropic API key",
1682
+ "Claude authentication",
1600
1683
  "Agent credential broker configuration is present.",
1601
1684
  { source: "broker", brokerUrl }
1602
1685
  );
@@ -1614,14 +1697,14 @@ async function checkAnthropicApiKey(env, options, deps) {
1614
1697
  if (response.ok && payload.env?.ANTHROPIC_API_KEY?.trim()) {
1615
1698
  return pass(
1616
1699
  "anthropic_api_key",
1617
- "Anthropic API key",
1700
+ "Claude authentication",
1618
1701
  "Agent credential broker is reachable and returned ANTHROPIC_API_KEY.",
1619
1702
  { source: "broker", brokerUrl }
1620
1703
  );
1621
1704
  }
1622
1705
  return fail(
1623
1706
  "anthropic_api_key",
1624
- "Anthropic API key",
1707
+ "Claude authentication",
1625
1708
  payload.error ? `Agent credential broker did not return ANTHROPIC_API_KEY: ${payload.error}.` : "Agent credential broker did not return ANTHROPIC_API_KEY.",
1626
1709
  "Set ANTHROPIC_API_KEY or configure the credential broker to return ANTHROPIC_API_KEY.",
1627
1710
  { source: "broker", brokerUrl, status: response.status }
@@ -1629,7 +1712,7 @@ async function checkAnthropicApiKey(env, options, deps) {
1629
1712
  } catch (error) {
1630
1713
  return fail(
1631
1714
  "anthropic_api_key",
1632
- "Anthropic API key",
1715
+ "Claude authentication",
1633
1716
  "Agent credential broker could not be reached.",
1634
1717
  "Set ANTHROPIC_API_KEY or fix AGENT_CREDENTIAL_BROKER_URL and AGENT_CREDENTIAL_BROKER_SECRET.",
1635
1718
  {
@@ -51,14 +51,6 @@ function showCursor() {
51
51
  return "\x1B[?25h";
52
52
  }
53
53
 
54
- // src/format/repository.ts
55
- function formatRepositoryDisplay(snapshot, fallback = "repository") {
56
- if (snapshot.repository) {
57
- return `${snapshot.repository.owner}/${snapshot.repository.name}`;
58
- }
59
- return snapshot.slug ?? fallback;
60
- }
61
-
62
54
  export {
63
55
  bold,
64
56
  dim,
@@ -72,6 +64,5 @@ export {
72
64
  setNoColor,
73
65
  clearScreen,
74
66
  hideCursor,
75
- showCursor,
76
- formatRepositoryDisplay
67
+ showCursor
77
68
  };
@@ -8,7 +8,7 @@ import {
8
8
  resolveGitHubGraphQLToken,
9
9
  shouldReuseAgentCredentialCache,
10
10
  writeAgentCredentialCache
11
- } from "./chunk-EEQQWTXS.js";
11
+ } from "./chunk-GPRCOJDJ.js";
12
12
 
13
13
  // ../runtime-codex/src/runtime.ts
14
14
  import { spawn } from "child_process";