@gh-symphony/cli 0.4.5 → 0.4.7
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.
- package/README.md +4 -1
- package/dist/{chunk-I3CZXKS5.js → chunk-3ACU7O47.js} +4 -4
- package/dist/{chunk-4ZHWEQQL.js → chunk-775A5LB5.js} +2 -2
- package/dist/{chunk-HHBXGE23.js → chunk-C4QCVQVY.js} +5 -6
- package/dist/{chunk-34YCGQD2.js → chunk-EILO332E.js} +1 -1
- package/dist/{chunk-SMNIGNS3.js → chunk-FFY5VKNV.js} +66 -24
- package/dist/{chunk-LJUEOVAQ.js → chunk-RGCSM2KZ.js} +1 -0
- package/dist/{chunk-7KFCWMMW.js → chunk-XLDJTMW5.js} +1 -1
- package/dist/{doctor-GHKE7TRO.js → doctor-TFKCAGZF.js} +145 -49
- package/dist/index.d.ts +40 -1
- package/dist/index.js +19 -7
- package/dist/{repo-V72OM7JL.js → repo-7UOBO3QG.js} +102 -19
- package/dist/{setup-DMYXHOCB.js → setup-KCBVNMUJ.js} +4 -4
- package/dist/{upgrade-UZAGYCRJ.js → upgrade-YOYZAIIY.js} +2 -2
- package/dist/{version-UUVKCGQA.js → version-ZTY3SPRG.js} +1 -1
- package/dist/worker-entry.js +2 -2
- package/dist/{workflow-L5UEE7JH.js → workflow-JQNOLYAM.js} +6 -6
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -8,6 +8,9 @@ The following tools must be installed before using the CLI:
|
|
|
8
8
|
|
|
9
9
|
- **[Node.js](https://nodejs.org/)** (v24+) with npm
|
|
10
10
|
- **[Git](https://git-scm.com/)**
|
|
11
|
+
- At least one AI agent runtime on `PATH` before `gh-symphony repo start`:
|
|
12
|
+
- **[Codex CLI](https://developers.openai.com/codex/cli/)** (`codex`) - install from the official Codex CLI guide, then authenticate with `codex login`.
|
|
13
|
+
- **[Claude Code](https://code.claude.com/docs/en/quickstart)** (`claude`) - install from the official Claude Code quickstart, then authenticate with `ANTHROPIC_API_KEY` or a local Claude login for non-bare runs.
|
|
11
14
|
- One GitHub auth source with required scopes (`repo`, `read:org`, `project`):
|
|
12
15
|
- **[GitHub CLI (`gh`)](https://cli.github.com/)**:
|
|
13
16
|
```bash
|
|
@@ -106,7 +109,7 @@ Examples of generated validation guidance include `make test`, `just build`, `uv
|
|
|
106
109
|
|
|
107
110
|
You can further customize the agent's behavior by editing `WORKFLOW.md` — this is the policy layer that controls what the agent does at each workflow phase.
|
|
108
111
|
|
|
109
|
-
> Currently supported runtimes: **Codex
|
|
112
|
+
> Currently supported runtimes: **[Codex CLI](https://developers.openai.com/codex/cli/)** and **[Claude Code](https://code.claude.com/docs/en/quickstart)**. The selected runtime command must be installed and authenticated before `gh-symphony repo start` can dispatch worker runs.
|
|
110
113
|
|
|
111
114
|
### Explicit Priority Mapping
|
|
112
115
|
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
workflow_init_default
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-775A5LB5.js";
|
|
5
5
|
import {
|
|
6
6
|
fetchGithubProjectIssueByRepositoryAndNumber,
|
|
7
7
|
inspectManagedProjectSelection,
|
|
8
8
|
resolveTrackerAdapter
|
|
9
|
-
} from "./chunk-
|
|
9
|
+
} from "./chunk-C4QCVQVY.js";
|
|
10
10
|
import {
|
|
11
11
|
GitHubApiError,
|
|
12
12
|
createClient,
|
|
@@ -14,12 +14,12 @@ import {
|
|
|
14
14
|
getGhTokenWithSource,
|
|
15
15
|
getProjectDetail,
|
|
16
16
|
validateGitHubToken
|
|
17
|
-
} from "./chunk-
|
|
17
|
+
} from "./chunk-FFY5VKNV.js";
|
|
18
18
|
import {
|
|
19
19
|
buildPromptVariables,
|
|
20
20
|
parseWorkflowMarkdown,
|
|
21
21
|
renderPrompt
|
|
22
|
-
} from "./chunk-
|
|
22
|
+
} from "./chunk-RGCSM2KZ.js";
|
|
23
23
|
import {
|
|
24
24
|
loadActiveProjectConfig
|
|
25
25
|
} from "./chunk-YZP5N5XP.js";
|
|
@@ -11,12 +11,12 @@ import {
|
|
|
11
11
|
listUserProjects,
|
|
12
12
|
resolveGitHubAuth,
|
|
13
13
|
validateToken
|
|
14
|
-
} from "./chunk-
|
|
14
|
+
} from "./chunk-FFY5VKNV.js";
|
|
15
15
|
import {
|
|
16
16
|
formatClaudePreflightText,
|
|
17
17
|
resolveClaudeCommandBinary,
|
|
18
18
|
runClaudePreflight
|
|
19
|
-
} from "./chunk-
|
|
19
|
+
} from "./chunk-RGCSM2KZ.js";
|
|
20
20
|
|
|
21
21
|
// src/mapping/smart-defaults.ts
|
|
22
22
|
var ROLE_PATTERNS = [
|
|
@@ -30,7 +30,7 @@ import {
|
|
|
30
30
|
resolveWorkflowRuntimeTimeouts,
|
|
31
31
|
safeReadDir,
|
|
32
32
|
scheduleRetryAt
|
|
33
|
-
} from "./chunk-
|
|
33
|
+
} from "./chunk-RGCSM2KZ.js";
|
|
34
34
|
import {
|
|
35
35
|
loadGlobalConfig,
|
|
36
36
|
loadProjectConfig
|
|
@@ -1470,8 +1470,10 @@ var githubProjectTrackerAdapter = {
|
|
|
1470
1470
|
return fetchProjectIssueStatesByIds(project, issueIds, dependencies);
|
|
1471
1471
|
},
|
|
1472
1472
|
buildWorkerEnvironment(project) {
|
|
1473
|
+
const apiUrl = project.tracker.apiUrl?.trim();
|
|
1473
1474
|
return {
|
|
1474
|
-
GITHUB_PROJECT_ID: requireTrackerSetting(project.tracker, "projectId")
|
|
1475
|
+
GITHUB_PROJECT_ID: requireTrackerSetting(project.tracker, "projectId"),
|
|
1476
|
+
...apiUrl ? { GITHUB_GRAPHQL_API_URL: apiUrl } : {}
|
|
1475
1477
|
};
|
|
1476
1478
|
},
|
|
1477
1479
|
reviveIssue(project, run) {
|
|
@@ -1564,10 +1566,7 @@ function resolveAssignedOnly(tracker, dependencies) {
|
|
|
1564
1566
|
if (dependencies.assignedOnly !== void 0) {
|
|
1565
1567
|
return dependencies.assignedOnly;
|
|
1566
1568
|
}
|
|
1567
|
-
const legacyAssignedOnly = readBooleanTrackerSetting(
|
|
1568
|
-
tracker,
|
|
1569
|
-
"assignedOnly"
|
|
1570
|
-
);
|
|
1569
|
+
const legacyAssignedOnly = readBooleanTrackerSetting(tracker, "assignedOnly");
|
|
1571
1570
|
if (legacyAssignedOnly) {
|
|
1572
1571
|
const warningKey = `${tracker.adapter}:${tracker.bindingId}`;
|
|
1573
1572
|
if (!warnedLegacyAssignedOnlyProjectIds.has(warningKey)) {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
// src/github/client.ts
|
|
4
|
-
var
|
|
4
|
+
var DEFAULT_GITHUB_GRAPHQL_API_URL = "https://api.github.com/graphql";
|
|
5
5
|
var REST_API_URL = "https://api.github.com";
|
|
6
6
|
function findLinkedRepository(project, owner, name) {
|
|
7
7
|
const normalizedOwner = owner.trim().toLowerCase();
|
|
@@ -28,13 +28,35 @@ var GitHubScopeError = class extends GitHubApiError {
|
|
|
28
28
|
function createClient(token, options) {
|
|
29
29
|
return {
|
|
30
30
|
token,
|
|
31
|
-
apiUrl: options?.apiUrl ??
|
|
31
|
+
apiUrl: options?.apiUrl ?? DEFAULT_GITHUB_GRAPHQL_API_URL,
|
|
32
32
|
fetchImpl: options?.fetchImpl ?? fetch
|
|
33
33
|
};
|
|
34
34
|
}
|
|
35
|
+
function deriveGitHubRestApiUrl(graphqlApiUrl) {
|
|
36
|
+
try {
|
|
37
|
+
const url = new URL(graphqlApiUrl);
|
|
38
|
+
const normalizedPath = url.pathname.replace(/\/+$/, "");
|
|
39
|
+
if (url.hostname.toLowerCase() === "api.github.com") {
|
|
40
|
+
return REST_API_URL;
|
|
41
|
+
}
|
|
42
|
+
if (normalizedPath === "/api/graphql") {
|
|
43
|
+
url.pathname = "/api/v3";
|
|
44
|
+
url.search = "";
|
|
45
|
+
url.hash = "";
|
|
46
|
+
return url.toString().replace(/\/$/, "");
|
|
47
|
+
}
|
|
48
|
+
if (normalizedPath.endsWith("/graphql")) {
|
|
49
|
+
url.pathname = normalizedPath.slice(0, -"/graphql".length) || "/";
|
|
50
|
+
url.search = "";
|
|
51
|
+
url.hash = "";
|
|
52
|
+
return url.toString().replace(/\/$/, "");
|
|
53
|
+
}
|
|
54
|
+
} catch {
|
|
55
|
+
}
|
|
56
|
+
return REST_API_URL;
|
|
57
|
+
}
|
|
35
58
|
async function listRepositoryLabels(client, owner, name) {
|
|
36
|
-
const
|
|
37
|
-
const baseUrl = restUrl === client.apiUrl ? REST_API_URL : restUrl;
|
|
59
|
+
const baseUrl = deriveGitHubRestApiUrl(client.apiUrl);
|
|
38
60
|
const labels = [];
|
|
39
61
|
let page = 1;
|
|
40
62
|
while (true) {
|
|
@@ -75,8 +97,7 @@ async function listRepositoryLabels(client, owner, name) {
|
|
|
75
97
|
return labels;
|
|
76
98
|
}
|
|
77
99
|
async function validateToken(client) {
|
|
78
|
-
const
|
|
79
|
-
const baseUrl = restUrl === client.apiUrl ? REST_API_URL : restUrl;
|
|
100
|
+
const baseUrl = deriveGitHubRestApiUrl(client.apiUrl);
|
|
80
101
|
const response = await client.fetchImpl(`${baseUrl}/user`, {
|
|
81
102
|
headers: {
|
|
82
103
|
authorization: `Bearer ${client.token}`,
|
|
@@ -646,12 +667,20 @@ function checkGhInstalled(opts) {
|
|
|
646
667
|
throw error;
|
|
647
668
|
}
|
|
648
669
|
}
|
|
670
|
+
function ghAuthHostArgs(hostname) {
|
|
671
|
+
const trimmed = hostname?.trim();
|
|
672
|
+
return trimmed ? ["--hostname", trimmed] : [];
|
|
673
|
+
}
|
|
649
674
|
function checkGhAuthenticated(opts) {
|
|
650
675
|
const spawnImpl = opts?.spawnImpl ?? spawnSync;
|
|
651
|
-
const result = spawnImpl(
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
676
|
+
const result = spawnImpl(
|
|
677
|
+
"gh",
|
|
678
|
+
["auth", "status", ...ghAuthHostArgs(opts?.hostname)],
|
|
679
|
+
{
|
|
680
|
+
encoding: "utf8",
|
|
681
|
+
stdio: ["pipe", "pipe", "pipe"]
|
|
682
|
+
}
|
|
683
|
+
);
|
|
655
684
|
if ((result.status ?? 1) !== 0) {
|
|
656
685
|
return { authenticated: false };
|
|
657
686
|
}
|
|
@@ -660,10 +689,14 @@ function checkGhAuthenticated(opts) {
|
|
|
660
689
|
}
|
|
661
690
|
function checkGhScopes(opts) {
|
|
662
691
|
const spawnImpl = opts?.spawnImpl ?? spawnSync;
|
|
663
|
-
const result = spawnImpl(
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
692
|
+
const result = spawnImpl(
|
|
693
|
+
"gh",
|
|
694
|
+
["auth", "status", ...ghAuthHostArgs(opts?.hostname)],
|
|
695
|
+
{
|
|
696
|
+
encoding: "utf8",
|
|
697
|
+
stdio: ["pipe", "pipe", "pipe"]
|
|
698
|
+
}
|
|
699
|
+
);
|
|
667
700
|
const output = (result.stdout ?? "").toString();
|
|
668
701
|
const scopes = parseScopes(output);
|
|
669
702
|
if (scopes.length === 0) {
|
|
@@ -686,7 +719,8 @@ function getGhToken(opts) {
|
|
|
686
719
|
}
|
|
687
720
|
return getGhTokenWithSource({
|
|
688
721
|
execImpl: opts?.execImpl,
|
|
689
|
-
envToken: void 0
|
|
722
|
+
envToken: void 0,
|
|
723
|
+
hostname: opts?.hostname
|
|
690
724
|
}).token;
|
|
691
725
|
}
|
|
692
726
|
function getGhTokenWithSource(opts) {
|
|
@@ -697,10 +731,14 @@ function getGhTokenWithSource(opts) {
|
|
|
697
731
|
}
|
|
698
732
|
const execImpl = opts?.execImpl ?? execFileSync;
|
|
699
733
|
try {
|
|
700
|
-
const token = execImpl(
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
734
|
+
const token = execImpl(
|
|
735
|
+
"gh",
|
|
736
|
+
["auth", "token", ...ghAuthHostArgs(opts?.hostname)],
|
|
737
|
+
{
|
|
738
|
+
encoding: "utf8",
|
|
739
|
+
stdio: ["pipe", "pipe", "pipe"]
|
|
740
|
+
}
|
|
741
|
+
).toString().trim();
|
|
704
742
|
if (!token) {
|
|
705
743
|
throw new GhAuthError("token_failed", ghTokenReadErrorMessage());
|
|
706
744
|
}
|
|
@@ -718,7 +756,9 @@ async function validateGitHubToken(token, source, opts) {
|
|
|
718
756
|
const checkRequiredScopesImpl = opts?.checkRequiredScopesImpl ?? checkRequiredScopes;
|
|
719
757
|
let viewer;
|
|
720
758
|
try {
|
|
721
|
-
const client = createClientImpl(token
|
|
759
|
+
const client = createClientImpl(token, {
|
|
760
|
+
apiUrl: opts?.apiUrl
|
|
761
|
+
});
|
|
722
762
|
viewer = await validateTokenImpl(client);
|
|
723
763
|
} catch (error) {
|
|
724
764
|
throw classifyTokenValidationError(error, source);
|
|
@@ -787,7 +827,7 @@ function ensureGhAuth(opts) {
|
|
|
787
827
|
{ source: "gh" }
|
|
788
828
|
);
|
|
789
829
|
}
|
|
790
|
-
const auth = checkGhAuthenticated({ spawnImpl });
|
|
830
|
+
const auth = checkGhAuthenticated({ spawnImpl, hostname: opts?.hostname });
|
|
791
831
|
if (!auth.authenticated) {
|
|
792
832
|
throw new GhAuthError(
|
|
793
833
|
"not_authenticated",
|
|
@@ -795,7 +835,7 @@ function ensureGhAuth(opts) {
|
|
|
795
835
|
{ source: "gh" }
|
|
796
836
|
);
|
|
797
837
|
}
|
|
798
|
-
const scopeCheck = checkGhScopes({ spawnImpl });
|
|
838
|
+
const scopeCheck = checkGhScopes({ spawnImpl, hostname: opts?.hostname });
|
|
799
839
|
if (!scopeCheck.valid) {
|
|
800
840
|
throw new GhAuthError(
|
|
801
841
|
"missing_scopes",
|
|
@@ -809,7 +849,8 @@ function ensureGhAuth(opts) {
|
|
|
809
849
|
}
|
|
810
850
|
const { token } = getGhTokenWithSource({
|
|
811
851
|
execImpl,
|
|
812
|
-
envToken: void 0
|
|
852
|
+
envToken: void 0,
|
|
853
|
+
hostname: opts?.hostname
|
|
813
854
|
});
|
|
814
855
|
return { login: auth.login ?? "unknown", token, source: "gh" };
|
|
815
856
|
}
|
|
@@ -858,7 +899,7 @@ function runGhAuthRefresh(opts) {
|
|
|
858
899
|
}
|
|
859
900
|
function parseLogin(output) {
|
|
860
901
|
const matched = output.match(
|
|
861
|
-
/Logged in to
|
|
902
|
+
/Logged in to \S+ account\s+\*?\*?([A-Za-z0-9_-]+)\*?\*?/i
|
|
862
903
|
);
|
|
863
904
|
return matched?.[1];
|
|
864
905
|
}
|
|
@@ -871,6 +912,7 @@ function parseScopes(output) {
|
|
|
871
912
|
}
|
|
872
913
|
|
|
873
914
|
export {
|
|
915
|
+
DEFAULT_GITHUB_GRAPHQL_API_URL,
|
|
874
916
|
findLinkedRepository,
|
|
875
917
|
GitHubApiError,
|
|
876
918
|
GitHubScopeError,
|
|
@@ -5,18 +5,19 @@ import {
|
|
|
5
5
|
parseIssueReference,
|
|
6
6
|
readGitHubProjectBinding,
|
|
7
7
|
renderIssueWorkflowPreview
|
|
8
|
-
} from "./chunk-
|
|
9
|
-
import "./chunk-
|
|
8
|
+
} from "./chunk-3ACU7O47.js";
|
|
9
|
+
import "./chunk-775A5LB5.js";
|
|
10
10
|
import {
|
|
11
11
|
fetchGithubProjectIssueByRepositoryAndNumber,
|
|
12
12
|
fetchGithubProjectIssues,
|
|
13
13
|
inspectManagedProjectSelection
|
|
14
|
-
} from "./chunk-
|
|
15
|
-
import "./chunk-
|
|
14
|
+
} from "./chunk-C4QCVQVY.js";
|
|
15
|
+
import "./chunk-XLDJTMW5.js";
|
|
16
16
|
import {
|
|
17
17
|
resolveRuntimeRoot
|
|
18
18
|
} from "./chunk-3IRPSPAF.js";
|
|
19
19
|
import {
|
|
20
|
+
DEFAULT_GITHUB_GRAPHQL_API_URL,
|
|
20
21
|
GitHubApiError,
|
|
21
22
|
REQUIRED_GH_SCOPES,
|
|
22
23
|
checkGhAuthenticated,
|
|
@@ -31,7 +32,7 @@ import {
|
|
|
31
32
|
runGhAuthLogin,
|
|
32
33
|
runGhAuthRefresh,
|
|
33
34
|
validateGitHubToken
|
|
34
|
-
} from "./chunk-
|
|
35
|
+
} from "./chunk-FFY5VKNV.js";
|
|
35
36
|
import {
|
|
36
37
|
isClaudeRuntimeCommand,
|
|
37
38
|
parseWorkflowMarkdown,
|
|
@@ -40,7 +41,7 @@ import {
|
|
|
40
41
|
resolveClaudeCommandBinary,
|
|
41
42
|
resolveRuntimeCommandBinary,
|
|
42
43
|
runClaudePreflight
|
|
43
|
-
} from "./chunk-
|
|
44
|
+
} from "./chunk-RGCSM2KZ.js";
|
|
44
45
|
import {
|
|
45
46
|
configFilePath,
|
|
46
47
|
orchestratorLogPath,
|
|
@@ -537,6 +538,67 @@ function warnCheck(id, title, summary, remediation, details) {
|
|
|
537
538
|
function formatAuthSource(source) {
|
|
538
539
|
return source === "env" ? "GITHUB_GRAPHQL_TOKEN" : "gh CLI";
|
|
539
540
|
}
|
|
541
|
+
function normalizeGitHubGraphqlEndpoint(value) {
|
|
542
|
+
const trimmed = value?.trim();
|
|
543
|
+
if (!trimmed) {
|
|
544
|
+
return null;
|
|
545
|
+
}
|
|
546
|
+
try {
|
|
547
|
+
const url = new URL(trimmed);
|
|
548
|
+
url.hostname = url.hostname.toLowerCase();
|
|
549
|
+
url.pathname = url.pathname.replace(/\/+$/, "") || "/";
|
|
550
|
+
url.search = "";
|
|
551
|
+
url.hash = "";
|
|
552
|
+
return url.toString().replace(/\/$/, "");
|
|
553
|
+
} catch {
|
|
554
|
+
return trimmed.replace(/\/+$/, "");
|
|
555
|
+
}
|
|
556
|
+
}
|
|
557
|
+
function deriveGhHostnameFromGraphqlEndpoint(endpoint) {
|
|
558
|
+
try {
|
|
559
|
+
const hostname = new URL(endpoint).hostname.toLowerCase();
|
|
560
|
+
return hostname === "api.github.com" ? "github.com" : hostname;
|
|
561
|
+
} catch {
|
|
562
|
+
return void 0;
|
|
563
|
+
}
|
|
564
|
+
}
|
|
565
|
+
function resolveGitHubGraphqlEndpoint(input) {
|
|
566
|
+
const trackerApiUrl = normalizeGitHubGraphqlEndpoint(input.trackerApiUrl);
|
|
567
|
+
const envApiUrl = normalizeGitHubGraphqlEndpoint(input.envApiUrl);
|
|
568
|
+
const resolvedEndpoint = trackerApiUrl ?? envApiUrl ?? DEFAULT_GITHUB_GRAPHQL_API_URL;
|
|
569
|
+
return {
|
|
570
|
+
resolvedEndpoint,
|
|
571
|
+
source: trackerApiUrl ? "tracker" : envApiUrl ? "env" : "default",
|
|
572
|
+
trackerApiUrl,
|
|
573
|
+
envApiUrl,
|
|
574
|
+
mismatch: trackerApiUrl !== null && envApiUrl !== null && trackerApiUrl !== envApiUrl,
|
|
575
|
+
ghHostname: deriveGhHostnameFromGraphqlEndpoint(resolvedEndpoint)
|
|
576
|
+
};
|
|
577
|
+
}
|
|
578
|
+
function buildGitHubGraphqlEndpointCheck(input) {
|
|
579
|
+
const details = {
|
|
580
|
+
resolvedEndpoint: input.resolvedEndpoint,
|
|
581
|
+
source: input.source,
|
|
582
|
+
trackerApiUrl: input.trackerApiUrl,
|
|
583
|
+
envApiUrl: input.envApiUrl,
|
|
584
|
+
ghHostname: input.ghHostname
|
|
585
|
+
};
|
|
586
|
+
if (input.mismatch) {
|
|
587
|
+
return warnCheck(
|
|
588
|
+
"github_graphql_endpoint",
|
|
589
|
+
"GitHub GraphQL endpoint",
|
|
590
|
+
`Resolved GitHub GraphQL endpoint is ${input.resolvedEndpoint}, but GITHUB_GRAPHQL_API_URL is ${input.envApiUrl}.`,
|
|
591
|
+
"Keep WORKFLOW.md tracker.endpoint/tracker.apiUrl and GITHUB_GRAPHQL_API_URL aligned, or unset GITHUB_GRAPHQL_API_URL so the workflow endpoint is authoritative.",
|
|
592
|
+
details
|
|
593
|
+
);
|
|
594
|
+
}
|
|
595
|
+
return passCheck(
|
|
596
|
+
"github_graphql_endpoint",
|
|
597
|
+
"GitHub GraphQL endpoint",
|
|
598
|
+
`Resolved GitHub GraphQL endpoint: ${input.resolvedEndpoint}.`,
|
|
599
|
+
details
|
|
600
|
+
);
|
|
601
|
+
}
|
|
540
602
|
function remediationStep(id, checkId, title, status, summary, command, details) {
|
|
541
603
|
return { id, checkId, title, status, summary, command, details };
|
|
542
604
|
}
|
|
@@ -768,7 +830,10 @@ function buildGithubTrackerConfig(input) {
|
|
|
768
830
|
}
|
|
769
831
|
async function checkLinearTrackerResolution(input) {
|
|
770
832
|
const tracker = input.projectConfig.projectConfig.tracker;
|
|
771
|
-
const projectSlug = readStringSetting(
|
|
833
|
+
const projectSlug = readStringSetting(
|
|
834
|
+
tracker.settings,
|
|
835
|
+
"projectSlug"
|
|
836
|
+
)?.trim();
|
|
772
837
|
const activeStates = readLinearActiveStates(tracker.settings);
|
|
773
838
|
const pickupLabels = readLinearPickupLabels(tracker.settings);
|
|
774
839
|
if (!projectSlug) {
|
|
@@ -915,7 +980,9 @@ async function fetchLinearProjectBySlug(input) {
|
|
|
915
980
|
})
|
|
916
981
|
});
|
|
917
982
|
if (!response.ok) {
|
|
918
|
-
throw new Error(
|
|
983
|
+
throw new Error(
|
|
984
|
+
`Linear GraphQL request failed with HTTP ${response.status}.`
|
|
985
|
+
);
|
|
919
986
|
}
|
|
920
987
|
const payload = await response.json();
|
|
921
988
|
if (payload.errors?.length) {
|
|
@@ -1453,6 +1520,7 @@ ${DOCTOR_USAGE}`);
|
|
|
1453
1520
|
let resolvedProjectConfig = null;
|
|
1454
1521
|
let resolvedGithubProjectDetail = null;
|
|
1455
1522
|
let resolvedGithubProjectBindingId = null;
|
|
1523
|
+
let githubGraphqlEndpoint = null;
|
|
1456
1524
|
const envToken = deps.getEnvGitHubToken();
|
|
1457
1525
|
const currentNodeVersion = deps.processVersion;
|
|
1458
1526
|
const currentNodeMajor = parseMajorNodeVersion(currentNodeVersion);
|
|
@@ -1531,19 +1599,68 @@ ${DOCTOR_USAGE}`);
|
|
|
1531
1599
|
)
|
|
1532
1600
|
);
|
|
1533
1601
|
}
|
|
1534
|
-
|
|
1535
|
-
|
|
1602
|
+
resolvedProjectConfig = await deps.inspectManagedProjectSelection({
|
|
1603
|
+
configDir: options.configDir,
|
|
1604
|
+
requestedProjectId: parsedArgs.projectId
|
|
1605
|
+
});
|
|
1606
|
+
if (resolvedProjectConfig.kind === "resolved") {
|
|
1607
|
+
resolvedProjectId = resolvedProjectConfig.projectId;
|
|
1608
|
+
checks.push(
|
|
1609
|
+
passCheck(
|
|
1610
|
+
"managed_project",
|
|
1611
|
+
"Managed project selection",
|
|
1612
|
+
`Resolved managed project "${resolvedProjectConfig.projectId}".`,
|
|
1613
|
+
{
|
|
1614
|
+
projectId: resolvedProjectConfig.projectId,
|
|
1615
|
+
workspaceDir: resolvedProjectConfig.projectConfig.workspaceDir
|
|
1616
|
+
}
|
|
1617
|
+
)
|
|
1618
|
+
);
|
|
1619
|
+
if (resolvedProjectConfig.projectConfig.tracker.adapter !== "linear") {
|
|
1620
|
+
githubGraphqlEndpoint = resolveGitHubGraphqlEndpoint({
|
|
1621
|
+
trackerApiUrl: resolvedProjectConfig.projectConfig.tracker.apiUrl,
|
|
1622
|
+
envApiUrl: process.env.GITHUB_GRAPHQL_API_URL
|
|
1623
|
+
});
|
|
1624
|
+
checks.push(buildGitHubGraphqlEndpointCheck(githubGraphqlEndpoint));
|
|
1625
|
+
}
|
|
1626
|
+
} else {
|
|
1627
|
+
checks.push(
|
|
1628
|
+
failCheck(
|
|
1629
|
+
"managed_project",
|
|
1630
|
+
"Managed project selection",
|
|
1631
|
+
resolvedProjectConfig.message,
|
|
1632
|
+
"Run 'gh-symphony repo init' from the target repository.",
|
|
1633
|
+
{
|
|
1634
|
+
reason: resolvedProjectConfig.kind,
|
|
1635
|
+
...resolvedProjectConfig.projectId ? { projectId: resolvedProjectConfig.projectId } : {}
|
|
1636
|
+
}
|
|
1637
|
+
)
|
|
1638
|
+
);
|
|
1639
|
+
}
|
|
1640
|
+
const ghHostname = githubGraphqlEndpoint?.ghHostname;
|
|
1641
|
+
const ghAuth = ghInstalled ? deps.checkGhAuthenticated({ hostname: ghHostname }) : { authenticated: false };
|
|
1642
|
+
const ghScopes = ghInstalled && ghAuth.authenticated ? deps.checkGhScopes({ hostname: ghHostname }) : { valid: false, missing: [...REQUIRED_GH_SCOPES], scopes: [] };
|
|
1643
|
+
const ghHostnameArg = ghHostname ? ` --hostname ${ghHostname}` : "";
|
|
1644
|
+
const ghLoginCommand = `gh auth login --scopes ${REQUIRED_GH_SCOPES.join(",")}${ghHostnameArg}`;
|
|
1645
|
+
const ghRefreshCommand = `gh auth refresh --scopes ${REQUIRED_GH_SCOPES.join(",")}${ghHostnameArg}`;
|
|
1536
1646
|
if (envToken) {
|
|
1537
1647
|
try {
|
|
1538
|
-
auth = await deps.validateGitHubToken(envToken, "env"
|
|
1648
|
+
auth = await deps.validateGitHubToken(envToken, "env", {
|
|
1649
|
+
apiUrl: githubGraphqlEndpoint?.resolvedEndpoint
|
|
1650
|
+
});
|
|
1539
1651
|
} catch (error) {
|
|
1540
1652
|
envTokenError = error instanceof Error ? error.message : "Unknown token validation error.";
|
|
1541
1653
|
}
|
|
1542
1654
|
}
|
|
1543
1655
|
if (!auth && ghInstalled && ghAuth.authenticated && ghScopes.valid) {
|
|
1544
1656
|
try {
|
|
1545
|
-
const ghToken = deps.getGhToken({
|
|
1546
|
-
|
|
1657
|
+
const ghToken = deps.getGhToken({
|
|
1658
|
+
allowEnv: false,
|
|
1659
|
+
hostname: ghHostname
|
|
1660
|
+
});
|
|
1661
|
+
auth = await deps.validateGitHubToken(ghToken, "gh", {
|
|
1662
|
+
apiUrl: githubGraphqlEndpoint?.resolvedEndpoint
|
|
1663
|
+
});
|
|
1547
1664
|
} catch (error) {
|
|
1548
1665
|
tokenError = error instanceof Error ? error.message : "Unknown token retrieval error.";
|
|
1549
1666
|
}
|
|
@@ -1575,7 +1692,7 @@ ${DOCTOR_USAGE}`);
|
|
|
1575
1692
|
"gh_authentication",
|
|
1576
1693
|
"GitHub authentication",
|
|
1577
1694
|
"gh auth status failed or no GitHub login is configured.",
|
|
1578
|
-
`Run '
|
|
1695
|
+
`Run '${ghLoginCommand}' and re-run the doctor command.`
|
|
1579
1696
|
)
|
|
1580
1697
|
);
|
|
1581
1698
|
}
|
|
@@ -1605,42 +1722,11 @@ ${DOCTOR_USAGE}`);
|
|
|
1605
1722
|
"gh_scopes",
|
|
1606
1723
|
"GitHub token scopes",
|
|
1607
1724
|
`Missing required scopes: ${missingScopes.join(", ")}.`,
|
|
1608
|
-
`Run '
|
|
1725
|
+
`Run '${ghRefreshCommand}' and confirm 'gh auth status${ghHostnameArg}' shows the updated scopes.`,
|
|
1609
1726
|
{ missing: missingScopes, scopes: ghScopes.scopes }
|
|
1610
1727
|
)
|
|
1611
1728
|
);
|
|
1612
1729
|
}
|
|
1613
|
-
resolvedProjectConfig = await deps.inspectManagedProjectSelection({
|
|
1614
|
-
configDir: options.configDir,
|
|
1615
|
-
requestedProjectId: parsedArgs.projectId
|
|
1616
|
-
});
|
|
1617
|
-
if (resolvedProjectConfig.kind === "resolved") {
|
|
1618
|
-
resolvedProjectId = resolvedProjectConfig.projectId;
|
|
1619
|
-
checks.push(
|
|
1620
|
-
passCheck(
|
|
1621
|
-
"managed_project",
|
|
1622
|
-
"Managed project selection",
|
|
1623
|
-
`Resolved managed project "${resolvedProjectConfig.projectId}".`,
|
|
1624
|
-
{
|
|
1625
|
-
projectId: resolvedProjectConfig.projectId,
|
|
1626
|
-
workspaceDir: resolvedProjectConfig.projectConfig.workspaceDir
|
|
1627
|
-
}
|
|
1628
|
-
)
|
|
1629
|
-
);
|
|
1630
|
-
} else {
|
|
1631
|
-
checks.push(
|
|
1632
|
-
failCheck(
|
|
1633
|
-
"managed_project",
|
|
1634
|
-
"Managed project selection",
|
|
1635
|
-
resolvedProjectConfig.message,
|
|
1636
|
-
"Run 'gh-symphony repo init' from the target repository.",
|
|
1637
|
-
{
|
|
1638
|
-
reason: resolvedProjectConfig.kind,
|
|
1639
|
-
...resolvedProjectConfig.projectId ? { projectId: resolvedProjectConfig.projectId } : {}
|
|
1640
|
-
}
|
|
1641
|
-
)
|
|
1642
|
-
);
|
|
1643
|
-
}
|
|
1644
1730
|
if (resolvedProjectConfig.kind === "resolved" && resolvedProjectConfig.projectConfig.tracker.adapter === "linear") {
|
|
1645
1731
|
checks.push(
|
|
1646
1732
|
await checkLinearTrackerResolution({
|
|
@@ -1683,7 +1769,9 @@ ${DOCTOR_USAGE}`);
|
|
|
1683
1769
|
throw new Error("Managed project is not bound to a GitHub Project.");
|
|
1684
1770
|
}
|
|
1685
1771
|
resolvedGithubProjectBindingId = bindingId;
|
|
1686
|
-
const client = deps.createClient(auth.token
|
|
1772
|
+
const client = deps.createClient(auth.token, {
|
|
1773
|
+
apiUrl: githubGraphqlEndpoint?.resolvedEndpoint
|
|
1774
|
+
});
|
|
1687
1775
|
const detail = await deps.getProjectDetail(client, bindingId);
|
|
1688
1776
|
resolvedGithubProjectDetail = detail;
|
|
1689
1777
|
checks.push(
|
|
@@ -1886,10 +1974,18 @@ ${DOCTOR_USAGE}`);
|
|
|
1886
1974
|
}
|
|
1887
1975
|
function buildRuntimeInstallGuidance(binary, platform) {
|
|
1888
1976
|
if (binary === "codex") {
|
|
1889
|
-
return
|
|
1977
|
+
return [
|
|
1978
|
+
"Install Codex CLI from https://developers.openai.com/codex/cli/",
|
|
1979
|
+
"and ensure 'codex' is on PATH.",
|
|
1980
|
+
"Then authenticate with 'codex login'."
|
|
1981
|
+
].join(" ");
|
|
1890
1982
|
}
|
|
1891
1983
|
if (binary === "claude" || binary === "claude-code") {
|
|
1892
|
-
return
|
|
1984
|
+
return [
|
|
1985
|
+
"Install Claude Code from https://code.claude.com/docs/en/quickstart",
|
|
1986
|
+
"and ensure the runtime binary is on PATH.",
|
|
1987
|
+
"Then set ANTHROPIC_API_KEY or complete a local Claude login for non-bare runs."
|
|
1988
|
+
].join(" ");
|
|
1893
1989
|
}
|
|
1894
1990
|
if (platform === "win32" && binary) {
|
|
1895
1991
|
return `Install '${binary}' using its official installation instructions and ensure the directory containing '${binary}.exe' is on PATH.`;
|
package/dist/index.d.ts
CHANGED
|
@@ -1,10 +1,49 @@
|
|
|
1
1
|
type GlobalOptions = {
|
|
2
2
|
configDir: string;
|
|
3
|
+
configDirOverride?: boolean;
|
|
4
|
+
configDirSource?: "cli" | "env" | "default";
|
|
3
5
|
verbose: boolean;
|
|
4
6
|
json: boolean;
|
|
5
7
|
noColor: boolean;
|
|
6
8
|
};
|
|
7
9
|
type CommandHandler = (args: string[], options: GlobalOptions) => Promise<void>;
|
|
10
|
+
type CliOptionValues = Partial<GlobalOptions & {
|
|
11
|
+
assignedOnly?: boolean;
|
|
12
|
+
config?: string;
|
|
13
|
+
daemon?: boolean;
|
|
14
|
+
dryRun?: boolean;
|
|
15
|
+
file?: string;
|
|
16
|
+
fix?: boolean;
|
|
17
|
+
follow?: boolean;
|
|
18
|
+
force?: boolean;
|
|
19
|
+
http?: string | boolean;
|
|
20
|
+
issue?: string;
|
|
21
|
+
level?: string;
|
|
22
|
+
logLevel?: string;
|
|
23
|
+
linearProjectSlug?: string;
|
|
24
|
+
nonInteractive?: boolean;
|
|
25
|
+
once?: boolean;
|
|
26
|
+
output?: string;
|
|
27
|
+
project?: string;
|
|
28
|
+
projectId?: string;
|
|
29
|
+
prune?: boolean;
|
|
30
|
+
run?: string;
|
|
31
|
+
runtime?: string;
|
|
32
|
+
skipContext?: boolean;
|
|
33
|
+
skipSkills?: boolean;
|
|
34
|
+
version?: boolean;
|
|
35
|
+
web?: string | boolean;
|
|
36
|
+
repoDir?: string;
|
|
37
|
+
workflowFile?: string;
|
|
38
|
+
workflow?: string;
|
|
39
|
+
watch?: boolean;
|
|
40
|
+
sample?: string;
|
|
41
|
+
smoke?: boolean;
|
|
42
|
+
bundle?: string | boolean;
|
|
43
|
+
attempt?: string;
|
|
44
|
+
tracker?: string;
|
|
45
|
+
}>;
|
|
46
|
+
declare function resolveGlobalOptions(values: CliOptionValues): GlobalOptions;
|
|
8
47
|
declare function runCli(argv: string[]): Promise<void>;
|
|
9
48
|
|
|
10
|
-
export { type CommandHandler, type GlobalOptions, runCli };
|
|
49
|
+
export { type CommandHandler, type GlobalOptions, resolveGlobalOptions, runCli };
|
package/dist/index.js
CHANGED
|
@@ -417,21 +417,25 @@ function createRemovedCommandHandler(message) {
|
|
|
417
417
|
|
|
418
418
|
// src/index.ts
|
|
419
419
|
var COMMANDS = {
|
|
420
|
-
workflow: () => import("./workflow-
|
|
421
|
-
setup: () => import("./setup-
|
|
422
|
-
doctor: () => import("./doctor-
|
|
423
|
-
upgrade: () => import("./upgrade-
|
|
424
|
-
repo: () => import("./repo-
|
|
420
|
+
workflow: () => import("./workflow-JQNOLYAM.js"),
|
|
421
|
+
setup: () => import("./setup-KCBVNMUJ.js"),
|
|
422
|
+
doctor: () => import("./doctor-TFKCAGZF.js"),
|
|
423
|
+
upgrade: () => import("./upgrade-YOYZAIIY.js"),
|
|
424
|
+
repo: () => import("./repo-7UOBO3QG.js"),
|
|
425
425
|
config: () => import("./config-cmd-OIVIUKG7.js"),
|
|
426
|
-
version: () => import("./version-
|
|
426
|
+
version: () => import("./version-ZTY3SPRG.js")
|
|
427
427
|
};
|
|
428
428
|
function addGlobalOptions(command) {
|
|
429
429
|
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");
|
|
430
430
|
}
|
|
431
431
|
function resolveGlobalOptions(values) {
|
|
432
432
|
const configInput = typeof values.config === "string" ? values.config : typeof values.configDir === "string" ? values.configDir : void 0;
|
|
433
|
+
const configDirSource = configInput !== void 0 ? "cli" : typeof process.env.GH_SYMPHONY_CONFIG_DIR === "string" ? "env" : "default";
|
|
434
|
+
const hasConfigOverride = configDirSource === "cli" || hasExplicitConfigEnvOverride();
|
|
433
435
|
const options = {
|
|
434
436
|
configDir: resolveConfigDir(configInput),
|
|
437
|
+
configDirOverride: hasConfigOverride,
|
|
438
|
+
configDirSource,
|
|
435
439
|
verbose: Boolean(values.verbose),
|
|
436
440
|
json: Boolean(values.json),
|
|
437
441
|
noColor: Boolean(values.noColor)
|
|
@@ -442,6 +446,13 @@ function resolveGlobalOptions(values) {
|
|
|
442
446
|
setNoColor(options.noColor);
|
|
443
447
|
return options;
|
|
444
448
|
}
|
|
449
|
+
function hasExplicitConfigEnvOverride() {
|
|
450
|
+
const envConfigDir = process.env.GH_SYMPHONY_CONFIG_DIR;
|
|
451
|
+
if (!envConfigDir) {
|
|
452
|
+
return false;
|
|
453
|
+
}
|
|
454
|
+
return envConfigDir !== "/var/lib/gh-symphony";
|
|
455
|
+
}
|
|
445
456
|
function resolveProjectId(values) {
|
|
446
457
|
return values.projectId ?? values.project;
|
|
447
458
|
}
|
|
@@ -706,7 +717,7 @@ function createProgram() {
|
|
|
706
717
|
addGlobalOptions(
|
|
707
718
|
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("--assigned-only", "Limit this run to assigned issues").option(
|
|
708
719
|
"--http [port]",
|
|
709
|
-
"Expose
|
|
720
|
+
"Expose the JSON status API and refresh endpoints over HTTP"
|
|
710
721
|
).option(
|
|
711
722
|
"--web [port]",
|
|
712
723
|
"Expose the control plane web dashboard and API over HTTP"
|
|
@@ -872,5 +883,6 @@ if (process.argv[1] && import.meta.url === pathToFileURL(realpathSync(process.ar
|
|
|
872
883
|
});
|
|
873
884
|
}
|
|
874
885
|
export {
|
|
886
|
+
resolveGlobalOptions,
|
|
875
887
|
runCli
|
|
876
888
|
};
|
|
@@ -17,7 +17,7 @@ import {
|
|
|
17
17
|
import {
|
|
18
18
|
initRepoRuntime,
|
|
19
19
|
parseRepoRuntimeFlags
|
|
20
|
-
} from "./chunk-
|
|
20
|
+
} from "./chunk-EILO332E.js";
|
|
21
21
|
import {
|
|
22
22
|
OrchestratorService,
|
|
23
23
|
acquireProjectLock,
|
|
@@ -33,8 +33,8 @@ import {
|
|
|
33
33
|
resolveOrchestratorLogLevel,
|
|
34
34
|
resolveTrackerAdapter,
|
|
35
35
|
runCli
|
|
36
|
-
} from "./chunk-
|
|
37
|
-
import "./chunk-
|
|
36
|
+
} from "./chunk-C4QCVQVY.js";
|
|
37
|
+
import "./chunk-XLDJTMW5.js";
|
|
38
38
|
import {
|
|
39
39
|
resolveRepoRuntimeRoot,
|
|
40
40
|
resolveRuntimeRoot
|
|
@@ -48,18 +48,20 @@ import {
|
|
|
48
48
|
resolveGitHubAuth,
|
|
49
49
|
runGhAuthLogin,
|
|
50
50
|
runGhAuthRefresh
|
|
51
|
-
} from "./chunk-
|
|
51
|
+
} from "./chunk-FFY5VKNV.js";
|
|
52
52
|
import {
|
|
53
53
|
WorkflowConfigStore,
|
|
54
54
|
deriveIssueWorkspaceKeyFromIdentifier,
|
|
55
|
+
formatEventMessage,
|
|
55
56
|
isFileMissing,
|
|
56
57
|
isMatchingIssueRun,
|
|
57
58
|
mapIssueOrchestrationStateToStatus,
|
|
58
59
|
parseRecentEvents,
|
|
59
60
|
readJsonFile,
|
|
60
61
|
safeReadDir
|
|
61
|
-
} from "./chunk-
|
|
62
|
+
} from "./chunk-RGCSM2KZ.js";
|
|
62
63
|
import {
|
|
64
|
+
configFilePath,
|
|
63
65
|
daemonPidPath,
|
|
64
66
|
httpStatusPath,
|
|
65
67
|
loadActiveProjectConfig,
|
|
@@ -67,11 +69,15 @@ import {
|
|
|
67
69
|
writeJsonFile
|
|
68
70
|
} from "./chunk-YZP5N5XP.js";
|
|
69
71
|
|
|
72
|
+
// src/commands/repo.ts
|
|
73
|
+
import { existsSync } from "fs";
|
|
74
|
+
|
|
70
75
|
// src/commands/logs.ts
|
|
71
76
|
import { readFile, readdir, stat } from "fs/promises";
|
|
72
77
|
import { join, resolve } from "path";
|
|
73
78
|
import { createReadStream } from "fs";
|
|
74
79
|
import { createInterface } from "readline";
|
|
80
|
+
var LOG_LEVELS = ["error", "warn", "info"];
|
|
75
81
|
function parseLogsArgs(args) {
|
|
76
82
|
const parsed = { follow: false };
|
|
77
83
|
for (let i = 0; i < args.length; i += 1) {
|
|
@@ -100,6 +106,17 @@ function parseLogsArgs(args) {
|
|
|
100
106
|
}
|
|
101
107
|
var handler = async (args, options) => {
|
|
102
108
|
const parsed = parseLogsArgs(args);
|
|
109
|
+
const level = parseLogLevel(parsed.level);
|
|
110
|
+
if (parsed.level && !level) {
|
|
111
|
+
process.stderr.write(
|
|
112
|
+
`Unknown --level "${parsed.level}". Valid values: ${LOG_LEVELS.join(
|
|
113
|
+
", "
|
|
114
|
+
)}.
|
|
115
|
+
`
|
|
116
|
+
);
|
|
117
|
+
process.exitCode = 1;
|
|
118
|
+
return;
|
|
119
|
+
}
|
|
103
120
|
const runtimeRoot = resolve(options.configDir);
|
|
104
121
|
if (parsed.run) {
|
|
105
122
|
const eventsPath = parsed.projectId ? join(
|
|
@@ -119,12 +136,19 @@ var handler = async (args, options) => {
|
|
|
119
136
|
try {
|
|
120
137
|
const content = await readFile(eventsPath, "utf8");
|
|
121
138
|
const lines = content.trim().split("\n").filter(Boolean);
|
|
139
|
+
let matchedEvents2 = 0;
|
|
122
140
|
for (const line of lines) {
|
|
123
141
|
const event = JSON.parse(line);
|
|
124
|
-
if (parsed.projectId && event
|
|
125
|
-
|
|
126
|
-
if (
|
|
142
|
+
if (parsed.projectId && getProjectId(event) !== parsed.projectId)
|
|
143
|
+
continue;
|
|
144
|
+
if (level && getLevel(event) !== level) continue;
|
|
145
|
+
if (parsed.issue && getIssueIdentifier(event) !== parsed.issue)
|
|
146
|
+
continue;
|
|
127
147
|
process.stdout.write(formatEvent(event) + "\n");
|
|
148
|
+
matchedEvents2 += 1;
|
|
149
|
+
}
|
|
150
|
+
if (level && matchedEvents2 === 0) {
|
|
151
|
+
process.stderr.write(noMatchedEventsMessage(level));
|
|
128
152
|
}
|
|
129
153
|
} catch {
|
|
130
154
|
process.stderr.write(`No events found for run: ${parsed.run}
|
|
@@ -177,6 +201,8 @@ var handler = async (args, options) => {
|
|
|
177
201
|
}
|
|
178
202
|
const runRoots = parsed.projectId ? [join(runtimeRoot, "projects", parsed.projectId, "runs")] : await listProjectRunRoots(runtimeRoot);
|
|
179
203
|
let foundRuns = false;
|
|
204
|
+
let matchedEvents = 0;
|
|
205
|
+
const events = [];
|
|
180
206
|
try {
|
|
181
207
|
for (const runsDir of runRoots) {
|
|
182
208
|
const entries = await safeReadDir2(runsDir);
|
|
@@ -191,11 +217,13 @@ var handler = async (args, options) => {
|
|
|
191
217
|
const lines = content.trim().split("\n").filter(Boolean);
|
|
192
218
|
for (const line of lines) {
|
|
193
219
|
const event = JSON.parse(line);
|
|
194
|
-
if (parsed.projectId && event
|
|
220
|
+
if (parsed.projectId && getProjectId(event) !== parsed.projectId)
|
|
195
221
|
continue;
|
|
196
|
-
if (
|
|
197
|
-
if (parsed.issue && event
|
|
198
|
-
|
|
222
|
+
if (level && getLevel(event) !== level) continue;
|
|
223
|
+
if (parsed.issue && getIssueIdentifier(event) !== parsed.issue)
|
|
224
|
+
continue;
|
|
225
|
+
events.push(event);
|
|
226
|
+
matchedEvents += 1;
|
|
199
227
|
}
|
|
200
228
|
} catch {
|
|
201
229
|
}
|
|
@@ -205,15 +233,58 @@ var handler = async (args, options) => {
|
|
|
205
233
|
}
|
|
206
234
|
if (!foundRuns) {
|
|
207
235
|
process.stderr.write("No runs found. Start the orchestrator first.\n");
|
|
236
|
+
return;
|
|
237
|
+
}
|
|
238
|
+
if (level && matchedEvents === 0) {
|
|
239
|
+
process.stderr.write(noMatchedEventsMessage(level));
|
|
240
|
+
return;
|
|
241
|
+
}
|
|
242
|
+
events.sort(
|
|
243
|
+
(left, right) => String(left.at ?? "").localeCompare(String(right.at ?? ""))
|
|
244
|
+
);
|
|
245
|
+
for (const event of events) {
|
|
246
|
+
process.stdout.write(formatEvent(event) + "\n");
|
|
208
247
|
}
|
|
209
248
|
};
|
|
210
249
|
var logs_default = handler;
|
|
211
250
|
function formatEvent(event) {
|
|
212
251
|
const at = event.at ?? "";
|
|
213
252
|
const eventType = event.event ?? "unknown";
|
|
214
|
-
const issue = event
|
|
215
|
-
const
|
|
216
|
-
|
|
253
|
+
const issue = getIssueIdentifier(event);
|
|
254
|
+
const message = formatEventMessage(event);
|
|
255
|
+
const subject = issue ? ` ${issue}` : "";
|
|
256
|
+
const extra = message ? ` ${message}` : "";
|
|
257
|
+
return `[${at}] ${eventType}${subject}${extra}`;
|
|
258
|
+
}
|
|
259
|
+
function getProjectId(event) {
|
|
260
|
+
return typeof event.projectId === "string" ? event.projectId : void 0;
|
|
261
|
+
}
|
|
262
|
+
function getLevel(event) {
|
|
263
|
+
switch (event.event) {
|
|
264
|
+
case "run-failed":
|
|
265
|
+
case "turn_failed":
|
|
266
|
+
case "worker-error":
|
|
267
|
+
case "hook-failed":
|
|
268
|
+
return "error";
|
|
269
|
+
case "run-suppressed":
|
|
270
|
+
case "run-retried":
|
|
271
|
+
return "warn";
|
|
272
|
+
default:
|
|
273
|
+
return "info";
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
function parseLogLevel(level) {
|
|
277
|
+
if (!level) {
|
|
278
|
+
return void 0;
|
|
279
|
+
}
|
|
280
|
+
return LOG_LEVELS.includes(level) ? level : void 0;
|
|
281
|
+
}
|
|
282
|
+
function noMatchedEventsMessage(level) {
|
|
283
|
+
return `No events matched the provided filters (--level ${level}).
|
|
284
|
+
`;
|
|
285
|
+
}
|
|
286
|
+
function getIssueIdentifier(event) {
|
|
287
|
+
return typeof event.issueIdentifier === "string" ? event.issueIdentifier : "";
|
|
217
288
|
}
|
|
218
289
|
async function listProjectRunRoots(runtimeRoot) {
|
|
219
290
|
const roots = [join(runtimeRoot, "runs")];
|
|
@@ -2066,7 +2137,7 @@ var handler5 = async (args, options) => {
|
|
|
2066
2137
|
if (httpServer) {
|
|
2067
2138
|
logLine(
|
|
2068
2139
|
cyan("\u25A1"),
|
|
2069
|
-
parsed.webPort !== void 0 ? `Web dashboard listening on ${httpServer.url}` : `HTTP
|
|
2140
|
+
parsed.webPort !== void 0 ? `Web dashboard listening on ${httpServer.url}` : `HTTP status API listening on ${httpServer.url}`
|
|
2070
2141
|
);
|
|
2071
2142
|
}
|
|
2072
2143
|
logLine(
|
|
@@ -2085,7 +2156,7 @@ var handler5 = async (args, options) => {
|
|
|
2085
2156
|
if (httpServer) {
|
|
2086
2157
|
logLine(
|
|
2087
2158
|
cyan("\u25A1"),
|
|
2088
|
-
parsed.webPort !== void 0 ? "One-shot tick completed; web dashboard remains available until Ctrl+C" : "One-shot tick completed; HTTP
|
|
2159
|
+
parsed.webPort !== void 0 ? "One-shot tick completed; web dashboard remains available until Ctrl+C" : "One-shot tick completed; HTTP status API remains available until Ctrl+C"
|
|
2089
2160
|
);
|
|
2090
2161
|
if (shuttingDown) {
|
|
2091
2162
|
break;
|
|
@@ -2807,6 +2878,7 @@ var handler7 = async (args, options) => {
|
|
|
2807
2878
|
var stop_default = handler7;
|
|
2808
2879
|
|
|
2809
2880
|
// src/commands/repo.ts
|
|
2881
|
+
var DOCKER_DEFAULT_CONFIG_DIR = "/var/lib/gh-symphony";
|
|
2810
2882
|
var handler8 = async (args, options) => {
|
|
2811
2883
|
const [subcommand, ...rest] = args;
|
|
2812
2884
|
switch (subcommand) {
|
|
@@ -2850,11 +2922,21 @@ var handler8 = async (args, options) => {
|
|
|
2850
2922
|
};
|
|
2851
2923
|
var repo_default = handler8;
|
|
2852
2924
|
function repoOptions(options) {
|
|
2925
|
+
const repoRuntimeRoot = resolveRepoRuntimeRoot();
|
|
2853
2926
|
return {
|
|
2854
2927
|
...options,
|
|
2855
|
-
configDir:
|
|
2928
|
+
configDir: shouldUseConfigDirOverride(options, repoRuntimeRoot) ? options.configDir : repoRuntimeRoot
|
|
2856
2929
|
};
|
|
2857
2930
|
}
|
|
2931
|
+
function shouldUseConfigDirOverride(options, repoRuntimeRoot) {
|
|
2932
|
+
if (!options.configDirOverride) {
|
|
2933
|
+
return false;
|
|
2934
|
+
}
|
|
2935
|
+
if (options.configDirSource === "env" && options.configDir === DOCKER_DEFAULT_CONFIG_DIR && existsSync(configFilePath(repoRuntimeRoot))) {
|
|
2936
|
+
return false;
|
|
2937
|
+
}
|
|
2938
|
+
return true;
|
|
2939
|
+
}
|
|
2858
2940
|
async function repoInit(args, options) {
|
|
2859
2941
|
if (rejectRemovedProjectId(args)) {
|
|
2860
2942
|
return;
|
|
@@ -2898,5 +2980,6 @@ function formatRepoSpec(repo) {
|
|
|
2898
2980
|
return `${repo.owner}/${repo.name}`;
|
|
2899
2981
|
}
|
|
2900
2982
|
export {
|
|
2901
|
-
repo_default as default
|
|
2983
|
+
repo_default as default,
|
|
2984
|
+
repoOptions
|
|
2902
2985
|
};
|
|
@@ -16,10 +16,10 @@ import {
|
|
|
16
16
|
warnDeprecatedSkipContext,
|
|
17
17
|
writeEcosystem,
|
|
18
18
|
writeWorkflowPlan
|
|
19
|
-
} from "./chunk-
|
|
19
|
+
} from "./chunk-775A5LB5.js";
|
|
20
20
|
import {
|
|
21
21
|
initRepoRuntime
|
|
22
|
-
} from "./chunk-
|
|
22
|
+
} from "./chunk-EILO332E.js";
|
|
23
23
|
import "./chunk-3IRPSPAF.js";
|
|
24
24
|
import {
|
|
25
25
|
GhAuthError,
|
|
@@ -32,8 +32,8 @@ import {
|
|
|
32
32
|
getProjectDetail,
|
|
33
33
|
listUserProjects,
|
|
34
34
|
validateToken
|
|
35
|
-
} from "./chunk-
|
|
36
|
-
import "./chunk-
|
|
35
|
+
} from "./chunk-FFY5VKNV.js";
|
|
36
|
+
import "./chunk-RGCSM2KZ.js";
|
|
37
37
|
import "./chunk-YZP5N5XP.js";
|
|
38
38
|
|
|
39
39
|
// src/commands/setup.ts
|
|
@@ -16,8 +16,8 @@ function execFileAsync(file, args, execFileImpl = execFileCallback) {
|
|
|
16
16
|
});
|
|
17
17
|
}
|
|
18
18
|
function resolveCurrentCliVersion() {
|
|
19
|
-
if ("0.4.
|
|
20
|
-
return "0.4.
|
|
19
|
+
if ("0.4.7".length > 0) {
|
|
20
|
+
return "0.4.7";
|
|
21
21
|
}
|
|
22
22
|
const pkg = JSON.parse(
|
|
23
23
|
readFileSync(new URL("../../package.json", import.meta.url), "utf8")
|
package/dist/worker-entry.js
CHANGED
|
@@ -6,7 +6,7 @@ import {
|
|
|
6
6
|
normalizeCodexRuntimeEvents,
|
|
7
7
|
prepareCodexRuntimePlan,
|
|
8
8
|
resolveLocalRuntimeLaunchConfig
|
|
9
|
-
} from "./chunk-
|
|
9
|
+
} from "./chunk-XLDJTMW5.js";
|
|
10
10
|
import {
|
|
11
11
|
DEFAULT_AGENT_INPUT_REQUIRED_REASON,
|
|
12
12
|
classifySessionExit,
|
|
@@ -17,7 +17,7 @@ import {
|
|
|
17
17
|
resolveClaudeCommandBinary,
|
|
18
18
|
resolveWorkflowRuntimeCommand,
|
|
19
19
|
runClaudePreflight
|
|
20
|
-
} from "./chunk-
|
|
20
|
+
} from "./chunk-RGCSM2KZ.js";
|
|
21
21
|
|
|
22
22
|
// ../worker/src/index.ts
|
|
23
23
|
import { spawn as spawn2 } from "child_process";
|
|
@@ -6,12 +6,12 @@ import {
|
|
|
6
6
|
resetWorkflowCommandDependenciesForTest,
|
|
7
7
|
setWorkflowCommandDependenciesForTest,
|
|
8
8
|
workflow_default
|
|
9
|
-
} from "./chunk-
|
|
10
|
-
import "./chunk-
|
|
11
|
-
import "./chunk-
|
|
12
|
-
import "./chunk-
|
|
13
|
-
import "./chunk-
|
|
14
|
-
import "./chunk-
|
|
9
|
+
} from "./chunk-3ACU7O47.js";
|
|
10
|
+
import "./chunk-775A5LB5.js";
|
|
11
|
+
import "./chunk-C4QCVQVY.js";
|
|
12
|
+
import "./chunk-XLDJTMW5.js";
|
|
13
|
+
import "./chunk-FFY5VKNV.js";
|
|
14
|
+
import "./chunk-RGCSM2KZ.js";
|
|
15
15
|
import "./chunk-YZP5N5XP.js";
|
|
16
16
|
export {
|
|
17
17
|
workflow_default as default,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gh-symphony/cli",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.7",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"author": "hojinzs",
|
|
6
6
|
"description": "Interactive CLI for GitHub Symphony orchestration",
|
|
@@ -43,10 +43,10 @@
|
|
|
43
43
|
"tsup": "^8.5.1",
|
|
44
44
|
"@gh-symphony/core": "0.0.14",
|
|
45
45
|
"@gh-symphony/control-plane": "0.0.15",
|
|
46
|
-
"@gh-symphony/dashboard": "0.0.14",
|
|
47
46
|
"@gh-symphony/orchestrator": "0.0.14",
|
|
48
47
|
"@gh-symphony/runtime-claude": "0.0.14",
|
|
49
48
|
"@gh-symphony/tracker-github": "0.0.14",
|
|
49
|
+
"@gh-symphony/dashboard": "0.0.14",
|
|
50
50
|
"@gh-symphony/worker": "0.0.14"
|
|
51
51
|
},
|
|
52
52
|
"scripts": {
|