@gh-symphony/cli 0.0.19 → 0.0.21
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 +30 -2
- package/dist/chunk-A67CMOYE.js +684 -0
- package/dist/{chunk-TILHWBP6.js → chunk-C67H3OUL.js} +239 -36
- package/dist/{chunk-RN2PACNV.js → chunk-JN3TQVFV.js} +721 -74
- package/dist/{chunk-GKENCODJ.js → chunk-KY6WKH66.js} +437 -101
- package/dist/{chunk-6CI3UUMH.js → chunk-MYVJ6HK4.js} +950 -1240
- package/dist/{chunk-M3IFVLQS.js → chunk-QEONJ5DZ.js} +978 -72
- package/dist/{chunk-H2YXSYOZ.js → chunk-S6VIK4FF.js} +59 -31
- package/dist/chunk-SXGT7LOF.js +1060 -0
- package/dist/{doctor-IYHCFXOZ.js → doctor-4HBRICHP.js} +102 -37
- package/dist/index.js +38 -17
- package/dist/{init-KZT6YNOH.js → init-HZ3JEDGQ.js} +7 -2
- package/dist/{project-DNALEWO3.js → project-25NQ4J4Y.js} +8 -6
- package/dist/{recover-C3V2QAUB.js → recover-L3MJHHDA.js} +4 -2
- package/dist/{repo-HDDE7OUI.js → repo-TDCWQR6P.js} +72 -14
- package/dist/{run-XI2S5Y4V.js → run-XJQ6BF7U.js} +4 -2
- package/dist/{setup-K4CYYJBF.js → setup-B2SVLW2R.js} +46 -8
- package/dist/{start-M6IQGRFO.js → start-I2CC7BLW.js} +6 -4
- package/dist/{upgrade-F4VE4XBS.js → upgrade-OJXPZRYE.js} +2 -2
- package/dist/{version-Y5RYNWMF.js → version-TBDCTKDO.js} +1 -1
- package/dist/worker-entry.js +522 -867
- package/dist/{workflow-TBIFY5MO.js → workflow-BLJH2HC3.js} +176 -10
- package/package.json +5 -3
|
@@ -1,13 +1,26 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
init_default
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-JN3TQVFV.js";
|
|
5
|
+
import {
|
|
6
|
+
fetchGithubProjectIssueByRepositoryAndNumber
|
|
7
|
+
} from "./chunk-SXGT7LOF.js";
|
|
8
|
+
import {
|
|
9
|
+
GitHubApiError,
|
|
10
|
+
createClient,
|
|
11
|
+
findLinkedRepository,
|
|
12
|
+
getGhTokenWithSource,
|
|
13
|
+
getProjectDetail,
|
|
14
|
+
validateGitHubToken
|
|
15
|
+
} from "./chunk-C67H3OUL.js";
|
|
5
16
|
import {
|
|
6
17
|
buildPromptVariables,
|
|
7
18
|
parseWorkflowMarkdown,
|
|
8
19
|
renderPrompt
|
|
9
|
-
} from "./chunk-
|
|
10
|
-
import
|
|
20
|
+
} from "./chunk-QEONJ5DZ.js";
|
|
21
|
+
import {
|
|
22
|
+
inspectManagedProjectSelection
|
|
23
|
+
} from "./chunk-C7G7RJ4G.js";
|
|
11
24
|
import "./chunk-ROGRTUFI.js";
|
|
12
25
|
|
|
13
26
|
// src/commands/workflow.ts
|
|
@@ -50,6 +63,25 @@ var SAMPLE_CONTINUATION_VARIABLES = {
|
|
|
50
63
|
lastTurnSummary: "Validated the prompt template and updated the CLI routing.",
|
|
51
64
|
cumulativeTurnCount: 3
|
|
52
65
|
};
|
|
66
|
+
var workflowCommandDependencies = {
|
|
67
|
+
createGitHubClient: createClient,
|
|
68
|
+
fetchLiveIssue: fetchGithubProjectIssueByRepositoryAndNumber,
|
|
69
|
+
getGitHubProjectDetail: getProjectDetail,
|
|
70
|
+
getGitHubTokenWithSource: getGhTokenWithSource,
|
|
71
|
+
resolveManagedProjectSelection: inspectManagedProjectSelection,
|
|
72
|
+
validateGitHubToken
|
|
73
|
+
};
|
|
74
|
+
function setWorkflowCommandDependenciesForTest(overrides) {
|
|
75
|
+
Object.assign(workflowCommandDependencies, overrides);
|
|
76
|
+
}
|
|
77
|
+
function resetWorkflowCommandDependenciesForTest() {
|
|
78
|
+
workflowCommandDependencies.createGitHubClient = createClient;
|
|
79
|
+
workflowCommandDependencies.fetchLiveIssue = fetchGithubProjectIssueByRepositoryAndNumber;
|
|
80
|
+
workflowCommandDependencies.getGitHubProjectDetail = getProjectDetail;
|
|
81
|
+
workflowCommandDependencies.getGitHubTokenWithSource = getGhTokenWithSource;
|
|
82
|
+
workflowCommandDependencies.resolveManagedProjectSelection = inspectManagedProjectSelection;
|
|
83
|
+
workflowCommandDependencies.validateGitHubToken = validateGitHubToken;
|
|
84
|
+
}
|
|
53
85
|
function parseWorkflowArgs(args) {
|
|
54
86
|
const [subcommand, ...rest] = args;
|
|
55
87
|
if (!subcommand) {
|
|
@@ -107,6 +139,21 @@ function parsePreviewFlags(args) {
|
|
|
107
139
|
flags.sample = value;
|
|
108
140
|
i += 1;
|
|
109
141
|
break;
|
|
142
|
+
case "--issue":
|
|
143
|
+
if (!value || value.startsWith("-")) {
|
|
144
|
+
throw new Error("Option '--issue' argument missing");
|
|
145
|
+
}
|
|
146
|
+
flags.issue = value;
|
|
147
|
+
i += 1;
|
|
148
|
+
break;
|
|
149
|
+
case "--project-id":
|
|
150
|
+
case "--project":
|
|
151
|
+
if (!value || value.startsWith("-")) {
|
|
152
|
+
throw new Error(`Option '${arg}' argument missing`);
|
|
153
|
+
}
|
|
154
|
+
flags.projectId = value;
|
|
155
|
+
i += 1;
|
|
156
|
+
break;
|
|
110
157
|
case "--attempt":
|
|
111
158
|
if (!value || value.startsWith("-")) {
|
|
112
159
|
throw new Error("Option '--attempt' argument missing");
|
|
@@ -136,12 +183,12 @@ function printWorkflowUsage() {
|
|
|
136
183
|
Commands:
|
|
137
184
|
init Generate WORKFLOW.md and workflow support files
|
|
138
185
|
validate Parse and strictly validate a WORKFLOW.md file
|
|
139
|
-
preview Render the final worker prompt from a sample issue
|
|
186
|
+
preview Render the final worker prompt from a sample or live issue
|
|
140
187
|
|
|
141
188
|
Options:
|
|
142
189
|
workflow init [--non-interactive] [--project <id>] [--output <path>] [--skip-skills] [--skip-context] [--dry-run]
|
|
143
190
|
workflow validate [--file <path>]
|
|
144
|
-
workflow preview [--file <path>] [--sample <json>] [--attempt <n>]
|
|
191
|
+
workflow preview [--file <path>] [--issue <owner/repo#number>] [--project-id <projectId>] [--sample <json>] [--attempt <n>]
|
|
145
192
|
`);
|
|
146
193
|
}
|
|
147
194
|
async function loadWorkflowMarkdown(workflowPath) {
|
|
@@ -166,7 +213,10 @@ function normalizeIssue(value) {
|
|
|
166
213
|
repositoryRecord.name,
|
|
167
214
|
"repository.name"
|
|
168
215
|
);
|
|
169
|
-
const repositoryUrl = readOptionalString(
|
|
216
|
+
const repositoryUrl = readOptionalString(
|
|
217
|
+
repositoryRecord.url,
|
|
218
|
+
"repository.url"
|
|
219
|
+
);
|
|
170
220
|
return {
|
|
171
221
|
id: readRequiredString(record.id, "id"),
|
|
172
222
|
identifier: readRequiredString(record.identifier, "identifier"),
|
|
@@ -245,7 +295,9 @@ function readStringArray(value, field) {
|
|
|
245
295
|
return [];
|
|
246
296
|
}
|
|
247
297
|
if (!Array.isArray(value) || value.some((entry) => typeof entry !== "string")) {
|
|
248
|
-
throw new Error(
|
|
298
|
+
throw new Error(
|
|
299
|
+
`Sample JSON field '${field}' must be an array of strings.`
|
|
300
|
+
);
|
|
249
301
|
}
|
|
250
302
|
return value;
|
|
251
303
|
}
|
|
@@ -254,7 +306,9 @@ function readBlockers(value) {
|
|
|
254
306
|
return [];
|
|
255
307
|
}
|
|
256
308
|
if (!Array.isArray(value)) {
|
|
257
|
-
throw new Error(
|
|
309
|
+
throw new Error(
|
|
310
|
+
"Sample JSON field 'blockedBy/blocked_by' must be an array."
|
|
311
|
+
);
|
|
258
312
|
}
|
|
259
313
|
return value.map((entry, index) => {
|
|
260
314
|
const record = asRecord(entry, `blockedBy/blocked_by[${index}]`);
|
|
@@ -313,6 +367,106 @@ async function loadSampleIssue(samplePath) {
|
|
|
313
367
|
sampleSource: resolvedPath
|
|
314
368
|
};
|
|
315
369
|
}
|
|
370
|
+
function parseIssueReference(value) {
|
|
371
|
+
const match = /^(?<owner>[A-Za-z0-9_.-]+)\/(?<name>[A-Za-z0-9_.-]+)#(?<number>\d+)$/.exec(
|
|
372
|
+
value.trim()
|
|
373
|
+
);
|
|
374
|
+
if (!match?.groups) {
|
|
375
|
+
throw new Error(
|
|
376
|
+
"Option '--issue' must be in the format 'owner/repo#number'."
|
|
377
|
+
);
|
|
378
|
+
}
|
|
379
|
+
return {
|
|
380
|
+
owner: match.groups.owner,
|
|
381
|
+
name: match.groups.name,
|
|
382
|
+
number: Number.parseInt(match.groups.number, 10),
|
|
383
|
+
identifier: `${match.groups.owner}/${match.groups.name}#${match.groups.number}`
|
|
384
|
+
};
|
|
385
|
+
}
|
|
386
|
+
function readGitHubProjectBinding(projectConfig) {
|
|
387
|
+
const bindingId = projectConfig.tracker.bindingId?.trim();
|
|
388
|
+
if (bindingId) {
|
|
389
|
+
return bindingId;
|
|
390
|
+
}
|
|
391
|
+
const settingsProjectId = projectConfig.tracker.settings?.projectId;
|
|
392
|
+
return typeof settingsProjectId === "string" && settingsProjectId.trim().length > 0 ? settingsProjectId.trim() : null;
|
|
393
|
+
}
|
|
394
|
+
function formatAuthError(error) {
|
|
395
|
+
return `GitHub authentication is required for live issue preview. ${error.message}`;
|
|
396
|
+
}
|
|
397
|
+
async function loadLiveIssue(issueReference, projectId, options) {
|
|
398
|
+
const issue = parseIssueReference(issueReference);
|
|
399
|
+
const selection = await workflowCommandDependencies.resolveManagedProjectSelection({
|
|
400
|
+
configDir: options.configDir,
|
|
401
|
+
requestedProjectId: projectId
|
|
402
|
+
});
|
|
403
|
+
if (selection.kind !== "resolved") {
|
|
404
|
+
throw new Error(selection.message);
|
|
405
|
+
}
|
|
406
|
+
const githubProjectId = readGitHubProjectBinding(selection.projectConfig);
|
|
407
|
+
if (!githubProjectId) {
|
|
408
|
+
throw new Error(
|
|
409
|
+
`Managed project "${selection.projectId}" is not bound to a GitHub Project. Re-run 'gh-symphony project add' and select a valid GitHub Project binding.`
|
|
410
|
+
);
|
|
411
|
+
}
|
|
412
|
+
let auth;
|
|
413
|
+
try {
|
|
414
|
+
const tokenResult = workflowCommandDependencies.getGitHubTokenWithSource();
|
|
415
|
+
auth = await workflowCommandDependencies.validateGitHubToken(
|
|
416
|
+
tokenResult.token,
|
|
417
|
+
tokenResult.source
|
|
418
|
+
);
|
|
419
|
+
} catch (error) {
|
|
420
|
+
if (error instanceof Error) {
|
|
421
|
+
throw new Error(formatAuthError(error));
|
|
422
|
+
}
|
|
423
|
+
throw error;
|
|
424
|
+
}
|
|
425
|
+
const client = workflowCommandDependencies.createGitHubClient(auth.token, {
|
|
426
|
+
apiUrl: selection.projectConfig.tracker.apiUrl
|
|
427
|
+
});
|
|
428
|
+
let detail;
|
|
429
|
+
try {
|
|
430
|
+
detail = await workflowCommandDependencies.getGitHubProjectDetail(
|
|
431
|
+
client,
|
|
432
|
+
githubProjectId
|
|
433
|
+
);
|
|
434
|
+
} catch (error) {
|
|
435
|
+
const message = error instanceof GitHubApiError ? error.message : error instanceof Error ? error.message : "Unknown GitHub API error.";
|
|
436
|
+
throw new Error(
|
|
437
|
+
`Failed to resolve the configured GitHub Project binding '${githubProjectId}': ${message}`
|
|
438
|
+
);
|
|
439
|
+
}
|
|
440
|
+
if (!findLinkedRepository(detail, issue.owner, issue.name)) {
|
|
441
|
+
throw new Error(
|
|
442
|
+
`Repository ${issue.owner}/${issue.name} is not linked to the configured GitHub Project "${detail.title}". Run 'gh-symphony repo add ${issue.owner}/${issue.name}' or re-run 'gh-symphony project add' with the correct project binding.`
|
|
443
|
+
);
|
|
444
|
+
}
|
|
445
|
+
const trackedIssue = await workflowCommandDependencies.fetchLiveIssue(
|
|
446
|
+
{
|
|
447
|
+
projectId: githubProjectId,
|
|
448
|
+
token: auth.token,
|
|
449
|
+
apiUrl: selection.projectConfig.tracker.apiUrl,
|
|
450
|
+
assignedOnly: selection.projectConfig.tracker.settings?.assignedOnly === true,
|
|
451
|
+
priorityFieldName: typeof selection.projectConfig.tracker.settings?.priorityFieldName === "string" ? selection.projectConfig.tracker.settings.priorityFieldName : void 0,
|
|
452
|
+
timeoutMs: typeof selection.projectConfig.tracker.settings?.timeoutMs === "number" ? selection.projectConfig.tracker.settings.timeoutMs : void 0
|
|
453
|
+
},
|
|
454
|
+
{
|
|
455
|
+
owner: issue.owner,
|
|
456
|
+
name: issue.name
|
|
457
|
+
},
|
|
458
|
+
issue.number
|
|
459
|
+
);
|
|
460
|
+
if (!trackedIssue) {
|
|
461
|
+
throw new Error(
|
|
462
|
+
`Issue ${issue.identifier} is not in the configured GitHub Project "${detail.title}". Add the issue to the project and re-run the preview.`
|
|
463
|
+
);
|
|
464
|
+
}
|
|
465
|
+
return {
|
|
466
|
+
issue: trackedIssue,
|
|
467
|
+
sampleSource: `live:${trackedIssue.identifier}`
|
|
468
|
+
};
|
|
469
|
+
}
|
|
316
470
|
function validateWorkflow(workflowPath, markdown) {
|
|
317
471
|
const workflow = parseWorkflowMarkdown(markdown);
|
|
318
472
|
const promptFreshVariables = buildPromptVariables(SAMPLE_ISSUE, {
|
|
@@ -420,9 +574,19 @@ async function runValidate(args, options) {
|
|
|
420
574
|
}
|
|
421
575
|
async function runPreview(args, options) {
|
|
422
576
|
const flags = parsePreviewFlags(args);
|
|
577
|
+
if (flags.sample && flags.issue) {
|
|
578
|
+
throw new Error(
|
|
579
|
+
"Options '--sample' and '--issue' cannot be used together."
|
|
580
|
+
);
|
|
581
|
+
}
|
|
423
582
|
const { workflowPath, markdown } = await loadWorkflowMarkdown(flags.file);
|
|
424
583
|
const workflow = parseWorkflowMarkdown(markdown);
|
|
425
|
-
|
|
584
|
+
if (flags.issue && workflow.tracker.kind !== "github-project") {
|
|
585
|
+
throw new Error(
|
|
586
|
+
"Live issue preview requires 'tracker.kind: github-project' in WORKFLOW.md."
|
|
587
|
+
);
|
|
588
|
+
}
|
|
589
|
+
const { issue, sampleSource } = flags.issue ? await loadLiveIssue(flags.issue, flags.projectId, options) : await loadSampleIssue(flags.sample);
|
|
426
590
|
const variables = buildPromptVariables(issue, {
|
|
427
591
|
attempt: flags.attempt
|
|
428
592
|
});
|
|
@@ -493,5 +657,7 @@ var handler = async (args, options) => {
|
|
|
493
657
|
};
|
|
494
658
|
var workflow_default = handler;
|
|
495
659
|
export {
|
|
496
|
-
workflow_default as default
|
|
660
|
+
workflow_default as default,
|
|
661
|
+
resetWorkflowCommandDependenciesForTest,
|
|
662
|
+
setWorkflowCommandDependenciesForTest
|
|
497
663
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gh-symphony/cli",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.21",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"author": "hojinzs",
|
|
6
6
|
"description": "Interactive CLI for GitHub Symphony orchestration",
|
|
@@ -41,11 +41,13 @@
|
|
|
41
41
|
},
|
|
42
42
|
"devDependencies": {
|
|
43
43
|
"tsup": "^8.5.1",
|
|
44
|
+
"@gh-symphony/control-plane": "0.0.14",
|
|
44
45
|
"@gh-symphony/core": "0.0.14",
|
|
45
46
|
"@gh-symphony/orchestrator": "0.0.14",
|
|
46
47
|
"@gh-symphony/dashboard": "0.0.14",
|
|
47
|
-
"@gh-symphony/
|
|
48
|
-
"@gh-symphony/tracker-github": "0.0.14"
|
|
48
|
+
"@gh-symphony/runtime-claude": "0.0.14",
|
|
49
|
+
"@gh-symphony/tracker-github": "0.0.14",
|
|
50
|
+
"@gh-symphony/worker": "0.0.14"
|
|
49
51
|
},
|
|
50
52
|
"scripts": {
|
|
51
53
|
"build": "tsup",
|