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