@akagilnc/pi-workflow-roles 0.1.2033 → 0.1.2043
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 +88 -1
- package/README.zh-CN.md +88 -1
- package/dist/public-cli/main.js +1051 -443
- package/package.json +1 -1
- package/src/public-cli/cli.ts +95 -53
- package/src/public-cli/invocation.ts +295 -404
- package/src/public-cli/option-definitions.ts +1173 -0
|
@@ -48,6 +48,15 @@ import {
|
|
|
48
48
|
import { sha256Hex } from "../sha256.ts";
|
|
49
49
|
import { uuidv7 } from "../uuidv7.ts";
|
|
50
50
|
import { CliUsageError } from "./cli-errors.ts";
|
|
51
|
+
import {
|
|
52
|
+
REJECTED_PUBLIC_SPELLINGS,
|
|
53
|
+
createTypedOptionConsumer,
|
|
54
|
+
evaluateTaishiModeOptionContract,
|
|
55
|
+
optionsForOwner,
|
|
56
|
+
resolveTaishiMode,
|
|
57
|
+
type OptionOwner,
|
|
58
|
+
type PublicOptionDefinition,
|
|
59
|
+
} from "./option-definitions.ts";
|
|
51
60
|
|
|
52
61
|
export type FrozenAttachment = {
|
|
53
62
|
/** Original caller path retained only as provenance. */
|
|
@@ -448,13 +457,7 @@ export class MergerEnvelopeDerivationError extends Error {
|
|
|
448
457
|
|
|
449
458
|
/** Reject missing/blank path values so empty overrides cannot silently degrade. */
|
|
450
459
|
function requireOptionPath(
|
|
451
|
-
flag:
|
|
452
|
-
| "--project"
|
|
453
|
-
| "--attach"
|
|
454
|
-
| "--prerequisites"
|
|
455
|
-
| "--request-manifest"
|
|
456
|
-
| "--base"
|
|
457
|
-
| "--project-root",
|
|
460
|
+
flag: string,
|
|
458
461
|
value: string | undefined,
|
|
459
462
|
): string {
|
|
460
463
|
if (value === undefined || value.trim() === "") {
|
|
@@ -467,6 +470,22 @@ function requireOptionPath(
|
|
|
467
470
|
return value;
|
|
468
471
|
}
|
|
469
472
|
|
|
473
|
+
/** True when token is a retained rejected spelling for the owner (#342). */
|
|
474
|
+
function isRejectedPublicSpelling(owner: OptionOwner, token: string): boolean {
|
|
475
|
+
for (const entry of REJECTED_PUBLIC_SPELLINGS) {
|
|
476
|
+
if (entry.owner !== owner) continue;
|
|
477
|
+
for (const spelling of entry.spellings) {
|
|
478
|
+
if (token === spelling || token.startsWith(`${spelling}=`)) return true;
|
|
479
|
+
}
|
|
480
|
+
}
|
|
481
|
+
return false;
|
|
482
|
+
}
|
|
483
|
+
|
|
484
|
+
/** Role option definitions — sole spelling source for the matching parser. */
|
|
485
|
+
function roleOptions(owner: Exclude<OptionOwner, "global">): readonly PublicOptionDefinition[] {
|
|
486
|
+
return optionsForOwner(owner);
|
|
487
|
+
}
|
|
488
|
+
|
|
470
489
|
/**
|
|
471
490
|
* Public --authority-ref admission grammar (refs-only).
|
|
472
491
|
* Unique owner for fresh argv and durable resume restore — no string-only parallel.
|
|
@@ -488,47 +507,37 @@ export function requireAuthorityRef(value: string | undefined): string {
|
|
|
488
507
|
|
|
489
508
|
/**
|
|
490
509
|
* Parse Judge-specific argv after the `judge` token.
|
|
491
|
-
*
|
|
510
|
+
* Spellings from PUBLIC_OPTION_TABLE.judge; rejects burden family (#342).
|
|
492
511
|
*/
|
|
493
512
|
export function parseJudgeArgv(args: readonly string[]): ParseJudgeArgvResult {
|
|
494
513
|
const attachmentPaths: string[] = [];
|
|
495
514
|
let project: string | undefined;
|
|
496
515
|
const positional: string[] = [];
|
|
497
516
|
const tokens = [...args];
|
|
517
|
+
const definitions = roleOptions("judge");
|
|
518
|
+
const options = createTypedOptionConsumer(definitions);
|
|
498
519
|
|
|
499
520
|
while (tokens.length > 0) {
|
|
500
|
-
|
|
501
|
-
|
|
521
|
+
if (tokens[0] === "--") {
|
|
522
|
+
tokens.shift();
|
|
502
523
|
positional.push(...tokens);
|
|
503
524
|
break;
|
|
504
525
|
}
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
project = requireOptionPath("--project", tokens.shift());
|
|
517
|
-
continue;
|
|
518
|
-
}
|
|
519
|
-
if (token.startsWith("--project=")) {
|
|
520
|
-
project = requireOptionPath("--project", token.slice("--project=".length));
|
|
521
|
-
continue;
|
|
526
|
+
const taken = options.takeDashed(tokens);
|
|
527
|
+
if (taken !== undefined) {
|
|
528
|
+
if (taken.def.id === "attach") {
|
|
529
|
+
attachmentPaths.push(requireOptionPath(taken.def.canonical, taken.value));
|
|
530
|
+
continue;
|
|
531
|
+
}
|
|
532
|
+
if (taken.def.id === "project") {
|
|
533
|
+
project = requireOptionPath(taken.def.canonical, taken.value);
|
|
534
|
+
continue;
|
|
535
|
+
}
|
|
536
|
+
throw new CliUsageError(`unknown judge option: ${taken.def.canonical}`);
|
|
522
537
|
}
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
token.startsWith("--burden=") ||
|
|
527
|
-
token === "--ak-judge-burden" ||
|
|
528
|
-
token.startsWith("--ak-judge-burden=") ||
|
|
529
|
-
token === "--judge-burden" ||
|
|
530
|
-
token.startsWith("--judge-burden=")
|
|
531
|
-
) {
|
|
538
|
+
const token = tokens.shift()!;
|
|
539
|
+
// Judge owns burden inference — rejected spellings from REJECTED_PUBLIC_SPELLINGS.
|
|
540
|
+
if (isRejectedPublicSpelling("judge", token)) {
|
|
532
541
|
throw new CliUsageError(
|
|
533
542
|
"judge does not accept a public burden selector; Judge infers its own burden",
|
|
534
543
|
);
|
|
@@ -539,6 +548,7 @@ export function parseJudgeArgv(args: readonly string[]): ParseJudgeArgvResult {
|
|
|
539
548
|
positional.push(token);
|
|
540
549
|
}
|
|
541
550
|
|
|
551
|
+
options.assertRequired();
|
|
542
552
|
return {
|
|
543
553
|
instruction: positional.join(" "),
|
|
544
554
|
attachmentPaths,
|
|
@@ -548,49 +558,44 @@ export function parseJudgeArgv(args: readonly string[]): ParseJudgeArgvResult {
|
|
|
548
558
|
|
|
549
559
|
/**
|
|
550
560
|
* Parse Coder-specific argv after the `coder` token.
|
|
551
|
-
* Phase defaults to apply;
|
|
552
|
-
* Common Invocation flags: --attach / --project.
|
|
561
|
+
* Phase defaults to apply; spellings from PUBLIC_OPTION_TABLE.coder (#342).
|
|
553
562
|
*/
|
|
554
563
|
export function parseCoderArgv(args: readonly string[]): ParseCoderArgvResult {
|
|
555
564
|
const attachmentPaths: string[] = [];
|
|
556
565
|
let project: string | undefined;
|
|
557
566
|
const positional: string[] = [];
|
|
558
567
|
const tokens = [...args];
|
|
568
|
+
const definitions = roleOptions("coder");
|
|
569
|
+
const options = createTypedOptionConsumer(definitions);
|
|
559
570
|
|
|
560
571
|
while (tokens.length > 0) {
|
|
561
|
-
|
|
562
|
-
|
|
572
|
+
if (tokens[0] === "--") {
|
|
573
|
+
tokens.shift();
|
|
563
574
|
positional.push(...tokens);
|
|
564
575
|
break;
|
|
565
576
|
}
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
project = requireOptionPath("--project", tokens.shift());
|
|
578
|
-
continue;
|
|
579
|
-
}
|
|
580
|
-
if (token.startsWith("--project=")) {
|
|
581
|
-
project = requireOptionPath("--project", token.slice("--project=".length));
|
|
582
|
-
continue;
|
|
577
|
+
const taken = options.takeDashed(tokens);
|
|
578
|
+
if (taken !== undefined) {
|
|
579
|
+
if (taken.def.id === "attach") {
|
|
580
|
+
attachmentPaths.push(requireOptionPath(taken.def.canonical, taken.value));
|
|
581
|
+
continue;
|
|
582
|
+
}
|
|
583
|
+
if (taken.def.id === "project") {
|
|
584
|
+
project = requireOptionPath(taken.def.canonical, taken.value);
|
|
585
|
+
continue;
|
|
586
|
+
}
|
|
587
|
+
throw new CliUsageError(`unknown coder option: ${taken.def.canonical}`);
|
|
583
588
|
}
|
|
589
|
+
const token = tokens.shift()!;
|
|
584
590
|
if (token.startsWith("-") && token !== "-") {
|
|
585
591
|
throw new CliUsageError(`unknown coder option: ${token}`);
|
|
586
592
|
}
|
|
587
593
|
positional.push(token);
|
|
588
594
|
}
|
|
589
595
|
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
}
|
|
596
|
+
// Phase aliases + default come solely from the typed coder phase row (#342).
|
|
597
|
+
const phase = options.consumeLeadingPhase(positional);
|
|
598
|
+
options.assertRequired();
|
|
594
599
|
|
|
595
600
|
return {
|
|
596
601
|
phase,
|
|
@@ -602,8 +607,7 @@ export function parseCoderArgv(args: readonly string[]): ParseCoderArgvResult {
|
|
|
602
607
|
|
|
603
608
|
/**
|
|
604
609
|
* Parse Fixer-specific argv after the `fixer` token.
|
|
605
|
-
* Phase defaults to apply;
|
|
606
|
-
* Common Invocation flags: --attach / --project. Role-specific: optional --prerequisites.
|
|
610
|
+
* Phase defaults to apply; spellings from PUBLIC_OPTION_TABLE.fixer (#342).
|
|
607
611
|
*/
|
|
608
612
|
export function parseFixerArgv(args: readonly string[]): ParseFixerArgvResult {
|
|
609
613
|
const attachmentPaths: string[] = [];
|
|
@@ -611,52 +615,41 @@ export function parseFixerArgv(args: readonly string[]): ParseFixerArgvResult {
|
|
|
611
615
|
let prerequisitesPath: string | undefined;
|
|
612
616
|
const positional: string[] = [];
|
|
613
617
|
const tokens = [...args];
|
|
618
|
+
const definitions = roleOptions("fixer");
|
|
619
|
+
const options = createTypedOptionConsumer(definitions);
|
|
614
620
|
|
|
615
621
|
while (tokens.length > 0) {
|
|
616
|
-
|
|
617
|
-
|
|
622
|
+
if (tokens[0] === "--") {
|
|
623
|
+
tokens.shift();
|
|
618
624
|
positional.push(...tokens);
|
|
619
625
|
break;
|
|
620
626
|
}
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
project = requireOptionPath("--project", token.slice("--project=".length));
|
|
637
|
-
continue;
|
|
638
|
-
}
|
|
639
|
-
if (token === "--prerequisites") {
|
|
640
|
-
prerequisitesPath = requireOptionPath("--prerequisites", tokens.shift());
|
|
641
|
-
continue;
|
|
642
|
-
}
|
|
643
|
-
if (token.startsWith("--prerequisites=")) {
|
|
644
|
-
prerequisitesPath = requireOptionPath(
|
|
645
|
-
"--prerequisites",
|
|
646
|
-
token.slice("--prerequisites=".length),
|
|
647
|
-
);
|
|
648
|
-
continue;
|
|
627
|
+
const taken = options.takeDashed(tokens);
|
|
628
|
+
if (taken !== undefined) {
|
|
629
|
+
if (taken.def.id === "attach") {
|
|
630
|
+
attachmentPaths.push(requireOptionPath(taken.def.canonical, taken.value));
|
|
631
|
+
continue;
|
|
632
|
+
}
|
|
633
|
+
if (taken.def.id === "project") {
|
|
634
|
+
project = requireOptionPath(taken.def.canonical, taken.value);
|
|
635
|
+
continue;
|
|
636
|
+
}
|
|
637
|
+
if (taken.def.id === "prerequisites") {
|
|
638
|
+
prerequisitesPath = requireOptionPath(taken.def.canonical, taken.value);
|
|
639
|
+
continue;
|
|
640
|
+
}
|
|
641
|
+
throw new CliUsageError(`unknown fixer option: ${taken.def.canonical}`);
|
|
649
642
|
}
|
|
643
|
+
const token = tokens.shift()!;
|
|
650
644
|
if (token.startsWith("-") && token !== "-") {
|
|
651
645
|
throw new CliUsageError(`unknown fixer option: ${token}`);
|
|
652
646
|
}
|
|
653
647
|
positional.push(token);
|
|
654
648
|
}
|
|
655
649
|
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
}
|
|
650
|
+
// Phase aliases + default come solely from the typed fixer phase row (#342).
|
|
651
|
+
const phase = options.consumeLeadingPhase(positional);
|
|
652
|
+
options.assertRequired();
|
|
660
653
|
|
|
661
654
|
return {
|
|
662
655
|
phase,
|
|
@@ -1139,6 +1132,7 @@ function parseRepoOption(raw: string | undefined): string {
|
|
|
1139
1132
|
return raw;
|
|
1140
1133
|
}
|
|
1141
1134
|
export function parseCollectorArgv(args: readonly string[]): ParseCollectorArgvResult {
|
|
1135
|
+
// Spellings from PUBLIC_OPTION_TABLE.collector (#342).
|
|
1142
1136
|
const attachmentPaths: string[] = [];
|
|
1143
1137
|
let project: string | undefined;
|
|
1144
1138
|
let repo: string | undefined;
|
|
@@ -1146,24 +1140,54 @@ export function parseCollectorArgv(args: readonly string[]): ParseCollectorArgvR
|
|
|
1146
1140
|
let requestManifestPath: string | undefined;
|
|
1147
1141
|
const positional: string[] = [];
|
|
1148
1142
|
const tokens = [...args];
|
|
1143
|
+
const definitions = roleOptions("collector");
|
|
1144
|
+
const options = createTypedOptionConsumer(definitions);
|
|
1149
1145
|
while (tokens.length > 0) {
|
|
1146
|
+
if (tokens[0] === "--") {
|
|
1147
|
+
tokens.shift();
|
|
1148
|
+
positional.push(...tokens);
|
|
1149
|
+
break;
|
|
1150
|
+
}
|
|
1151
|
+
const taken = options.takeDashed(tokens);
|
|
1152
|
+
if (taken !== undefined) {
|
|
1153
|
+
if (taken.def.id === "attach") {
|
|
1154
|
+
attachmentPaths.push(requireOptionPath(taken.def.canonical, taken.value));
|
|
1155
|
+
continue;
|
|
1156
|
+
}
|
|
1157
|
+
if (taken.def.id === "project") {
|
|
1158
|
+
project = requireOptionPath(taken.def.canonical, taken.value);
|
|
1159
|
+
continue;
|
|
1160
|
+
}
|
|
1161
|
+
if (taken.def.id === "pr") {
|
|
1162
|
+
prNumber = parsePositivePrOption(taken.value);
|
|
1163
|
+
continue;
|
|
1164
|
+
}
|
|
1165
|
+
if (taken.def.id === "repo") {
|
|
1166
|
+
repo = parseRepoOption(taken.value);
|
|
1167
|
+
continue;
|
|
1168
|
+
}
|
|
1169
|
+
if (taken.def.id === "request-manifest") {
|
|
1170
|
+
requestManifestPath = requireOptionPath(taken.def.canonical, taken.value);
|
|
1171
|
+
continue;
|
|
1172
|
+
}
|
|
1173
|
+
throw new CliUsageError(`unknown collector option: ${taken.def.canonical}`);
|
|
1174
|
+
}
|
|
1150
1175
|
const token = tokens.shift()!;
|
|
1151
|
-
if (token
|
|
1152
|
-
|
|
1153
|
-
|
|
1154
|
-
if (token === "--project") { project = requireOptionPath("--project", tokens.shift()); continue; }
|
|
1155
|
-
if (token.startsWith("--project=")) { project = requireOptionPath("--project", token.slice(10)); continue; }
|
|
1156
|
-
if (token === "--pr") { prNumber = parsePositivePrOption(tokens.shift()); continue; }
|
|
1157
|
-
if (token.startsWith("--pr=")) { prNumber = parsePositivePrOption(token.slice(5)); continue; }
|
|
1158
|
-
if (token === "--repo") { repo = parseRepoOption(tokens.shift()); continue; }
|
|
1159
|
-
if (token.startsWith("--repo=")) { repo = parseRepoOption(token.slice(7)); continue; }
|
|
1160
|
-
if (token === "--request-manifest") { requestManifestPath = requireOptionPath("--request-manifest", tokens.shift()); continue; }
|
|
1161
|
-
if (token.startsWith("--request-manifest=")) { requestManifestPath = requireOptionPath("--request-manifest", token.slice(19)); continue; }
|
|
1162
|
-
if (token.startsWith("-") && token !== "-") throw new CliUsageError(`unknown collector option: ${token}`);
|
|
1176
|
+
if (token.startsWith("-") && token !== "-") {
|
|
1177
|
+
throw new CliUsageError(`unknown collector option: ${token}`);
|
|
1178
|
+
}
|
|
1163
1179
|
positional.push(token);
|
|
1164
1180
|
}
|
|
1165
|
-
|
|
1166
|
-
|
|
1181
|
+
// Unconditional required (e.g. --pr) from typed table via shared consumer (#342).
|
|
1182
|
+
options.assertRequired();
|
|
1183
|
+
return {
|
|
1184
|
+
prNumber: prNumber!,
|
|
1185
|
+
instruction: positional.join(" "),
|
|
1186
|
+
attachmentPaths,
|
|
1187
|
+
...(project === undefined ? {} : { project }),
|
|
1188
|
+
...(repo === undefined ? {} : { repo }),
|
|
1189
|
+
...(requestManifestPath === undefined ? {} : { requestManifestPath }),
|
|
1190
|
+
};
|
|
1167
1191
|
}
|
|
1168
1192
|
|
|
1169
1193
|
/**
|
|
@@ -1409,78 +1433,58 @@ export function parseDoctorIssueNumber(raw: string): number {
|
|
|
1409
1433
|
* Requires --issue; optional confined --runs override; common --attach/--project.
|
|
1410
1434
|
*/
|
|
1411
1435
|
export function parseDoctorArgv(args: readonly string[]): ParseDoctorArgvResult {
|
|
1436
|
+
// Spellings from PUBLIC_OPTION_TABLE.doctor (#342).
|
|
1412
1437
|
const attachmentPaths: string[] = [];
|
|
1413
1438
|
let project: string | undefined;
|
|
1414
1439
|
let issueRaw: string | undefined;
|
|
1415
1440
|
let runs: string | undefined;
|
|
1416
1441
|
const positional: string[] = [];
|
|
1417
1442
|
const tokens = [...args];
|
|
1443
|
+
const definitions = roleOptions("doctor");
|
|
1444
|
+
const options = createTypedOptionConsumer(definitions);
|
|
1418
1445
|
|
|
1419
1446
|
while (tokens.length > 0) {
|
|
1420
|
-
|
|
1421
|
-
|
|
1447
|
+
if (tokens[0] === "--") {
|
|
1448
|
+
tokens.shift();
|
|
1422
1449
|
positional.push(...tokens);
|
|
1423
1450
|
break;
|
|
1424
1451
|
}
|
|
1425
|
-
|
|
1426
|
-
|
|
1427
|
-
if (
|
|
1428
|
-
|
|
1452
|
+
const taken = options.takeDashed(tokens);
|
|
1453
|
+
if (taken !== undefined) {
|
|
1454
|
+
if (taken.def.id === "issue") {
|
|
1455
|
+
if (taken.value === undefined || taken.value.trim() === "") {
|
|
1456
|
+
throw new CliUsageError("doctor --issue requires a positive integer");
|
|
1457
|
+
}
|
|
1458
|
+
issueRaw = taken.value;
|
|
1459
|
+
continue;
|
|
1429
1460
|
}
|
|
1430
|
-
|
|
1431
|
-
|
|
1432
|
-
|
|
1433
|
-
|
|
1434
|
-
|
|
1435
|
-
|
|
1436
|
-
throw new CliUsageError("doctor --issue requires a positive integer");
|
|
1461
|
+
if (taken.def.id === "runs") {
|
|
1462
|
+
if (taken.value === undefined || taken.value.trim() === "") {
|
|
1463
|
+
throw new CliUsageError("doctor --runs requires a path");
|
|
1464
|
+
}
|
|
1465
|
+
runs = taken.value;
|
|
1466
|
+
continue;
|
|
1437
1467
|
}
|
|
1438
|
-
|
|
1439
|
-
|
|
1440
|
-
|
|
1441
|
-
const value = tokens.shift();
|
|
1442
|
-
if (value === undefined || value.trim() === "") {
|
|
1443
|
-
throw new CliUsageError("doctor --runs requires a path");
|
|
1468
|
+
if (taken.def.id === "attach") {
|
|
1469
|
+
attachmentPaths.push(requireOptionPath(taken.def.canonical, taken.value));
|
|
1470
|
+
continue;
|
|
1444
1471
|
}
|
|
1445
|
-
|
|
1446
|
-
|
|
1447
|
-
|
|
1448
|
-
if (token.startsWith("--runs=")) {
|
|
1449
|
-
const value = token.slice("--runs=".length);
|
|
1450
|
-
if (value.trim() === "") {
|
|
1451
|
-
throw new CliUsageError("doctor --runs requires a path");
|
|
1472
|
+
if (taken.def.id === "project") {
|
|
1473
|
+
project = requireOptionPath(taken.def.canonical, taken.value);
|
|
1474
|
+
continue;
|
|
1452
1475
|
}
|
|
1453
|
-
|
|
1454
|
-
continue;
|
|
1455
|
-
}
|
|
1456
|
-
if (token === "--attach") {
|
|
1457
|
-
attachmentPaths.push(requireOptionPath("--attach", tokens.shift()));
|
|
1458
|
-
continue;
|
|
1459
|
-
}
|
|
1460
|
-
if (token.startsWith("--attach=")) {
|
|
1461
|
-
attachmentPaths.push(
|
|
1462
|
-
requireOptionPath("--attach", token.slice("--attach=".length)),
|
|
1463
|
-
);
|
|
1464
|
-
continue;
|
|
1465
|
-
}
|
|
1466
|
-
if (token === "--project") {
|
|
1467
|
-
project = requireOptionPath("--project", tokens.shift());
|
|
1468
|
-
continue;
|
|
1469
|
-
}
|
|
1470
|
-
if (token.startsWith("--project=")) {
|
|
1471
|
-
project = requireOptionPath("--project", token.slice("--project=".length));
|
|
1472
|
-
continue;
|
|
1476
|
+
throw new CliUsageError(`unknown doctor option: ${taken.def.canonical}`);
|
|
1473
1477
|
}
|
|
1478
|
+
const token = tokens.shift()!;
|
|
1474
1479
|
if (token.startsWith("-") && token !== "-") {
|
|
1475
1480
|
throw new CliUsageError(`unknown doctor option: ${token}`);
|
|
1476
1481
|
}
|
|
1477
1482
|
positional.push(token);
|
|
1478
1483
|
}
|
|
1479
1484
|
|
|
1480
|
-
|
|
1481
|
-
|
|
1482
|
-
|
|
1483
|
-
const issueNumber = parseDoctorIssueNumber(issueRaw);
|
|
1485
|
+
// Unconditional required (e.g. --issue) from typed table via shared consumer (#342).
|
|
1486
|
+
options.assertRequired();
|
|
1487
|
+
const issueNumber = parseDoctorIssueNumber(issueRaw!);
|
|
1484
1488
|
|
|
1485
1489
|
if (runs !== undefined && runs.trim() === "") {
|
|
1486
1490
|
throw new CliUsageError("doctor --runs requires a path");
|
|
@@ -1731,56 +1735,51 @@ export function buildDoctorTransportPrompt(
|
|
|
1731
1735
|
export function parseReviewerArgv(
|
|
1732
1736
|
args: readonly string[],
|
|
1733
1737
|
): ParseReviewerArgvResult {
|
|
1738
|
+
// Spellings from PUBLIC_OPTION_TABLE.reviewer (#342). No --attach face.
|
|
1734
1739
|
const attachmentPaths: string[] = [];
|
|
1735
1740
|
const authorityRefs: string[] = [];
|
|
1736
1741
|
let project: string | undefined;
|
|
1737
1742
|
let baseRevision: string | undefined;
|
|
1738
1743
|
const positional: string[] = [];
|
|
1739
1744
|
const tokens = [...args];
|
|
1745
|
+
const definitions = roleOptions("reviewer");
|
|
1746
|
+
const options = createTypedOptionConsumer(definitions);
|
|
1740
1747
|
|
|
1741
1748
|
while (tokens.length > 0) {
|
|
1742
|
-
|
|
1743
|
-
|
|
1749
|
+
if (tokens[0] === "--") {
|
|
1750
|
+
tokens.shift();
|
|
1744
1751
|
positional.push(...tokens);
|
|
1745
1752
|
break;
|
|
1746
1753
|
}
|
|
1747
|
-
|
|
1748
|
-
|
|
1749
|
-
|
|
1750
|
-
|
|
1751
|
-
|
|
1752
|
-
|
|
1753
|
-
|
|
1754
|
-
|
|
1755
|
-
|
|
1756
|
-
|
|
1757
|
-
|
|
1758
|
-
|
|
1759
|
-
|
|
1760
|
-
|
|
1761
|
-
|
|
1762
|
-
}
|
|
1763
|
-
if (token === "--authority-ref") {
|
|
1764
|
-
authorityRefs.push(requireAuthorityRef(tokens.shift()));
|
|
1765
|
-
continue;
|
|
1766
|
-
}
|
|
1767
|
-
if (token.startsWith("--authority-ref=")) {
|
|
1768
|
-
authorityRefs.push(requireAuthorityRef(token.slice("--authority-ref=".length)));
|
|
1769
|
-
continue;
|
|
1754
|
+
const taken = options.takeDashed(tokens);
|
|
1755
|
+
if (taken !== undefined) {
|
|
1756
|
+
if (taken.def.id === "project") {
|
|
1757
|
+
project = requireOptionPath(taken.def.canonical, taken.value);
|
|
1758
|
+
continue;
|
|
1759
|
+
}
|
|
1760
|
+
if (taken.def.id === "base") {
|
|
1761
|
+
baseRevision = requireOptionPath(taken.def.canonical, taken.value);
|
|
1762
|
+
continue;
|
|
1763
|
+
}
|
|
1764
|
+
if (taken.def.id === "authority-ref") {
|
|
1765
|
+
authorityRefs.push(requireAuthorityRef(taken.value));
|
|
1766
|
+
continue;
|
|
1767
|
+
}
|
|
1768
|
+
throw new CliUsageError(`unknown reviewer option: ${taken.def.canonical}`);
|
|
1770
1769
|
}
|
|
1770
|
+
const token = tokens.shift()!;
|
|
1771
1771
|
if (token.startsWith("-") && token !== "-") {
|
|
1772
1772
|
throw new CliUsageError(`unknown reviewer option: ${token}`);
|
|
1773
1773
|
}
|
|
1774
1774
|
positional.push(token);
|
|
1775
1775
|
}
|
|
1776
1776
|
|
|
1777
|
-
|
|
1778
|
-
|
|
1779
|
-
}
|
|
1777
|
+
// Unconditional required (e.g. --base) from typed table via shared consumer (#342).
|
|
1778
|
+
options.assertRequired();
|
|
1780
1779
|
return {
|
|
1781
1780
|
instruction: positional.join(" "),
|
|
1782
1781
|
attachmentPaths,
|
|
1783
|
-
baseRevision
|
|
1782
|
+
baseRevision: baseRevision!,
|
|
1784
1783
|
authorityRefs,
|
|
1785
1784
|
...(project === undefined ? {} : { project }),
|
|
1786
1785
|
};
|
|
@@ -1898,43 +1897,38 @@ export function buildReviewerTransportPrompt(
|
|
|
1898
1897
|
|
|
1899
1898
|
/**
|
|
1900
1899
|
* Parse Merger-specific argv after the `merger` token.
|
|
1901
|
-
*
|
|
1902
|
-
* Parents, conflicts, scope, and internal merger-input are never public fields.
|
|
1900
|
+
* Spellings from PUBLIC_OPTION_TABLE.merger; internal packet fields rejected (#342).
|
|
1903
1901
|
*/
|
|
1904
1902
|
export function parseMergerArgv(args: readonly string[]): ParseMergerArgvResult {
|
|
1905
1903
|
const attachmentPaths: string[] = [];
|
|
1906
1904
|
let project: string | undefined;
|
|
1907
1905
|
const positional: string[] = [];
|
|
1908
1906
|
const tokens = [...args];
|
|
1907
|
+
const definitions = roleOptions("merger");
|
|
1908
|
+
const options = createTypedOptionConsumer(definitions);
|
|
1909
1909
|
|
|
1910
1910
|
while (tokens.length > 0) {
|
|
1911
|
-
|
|
1912
|
-
|
|
1911
|
+
if (tokens[0] === "--") {
|
|
1912
|
+
tokens.shift();
|
|
1913
1913
|
positional.push(...tokens);
|
|
1914
1914
|
break;
|
|
1915
1915
|
}
|
|
1916
|
-
|
|
1917
|
-
|
|
1918
|
-
|
|
1919
|
-
|
|
1920
|
-
|
|
1921
|
-
|
|
1922
|
-
|
|
1923
|
-
|
|
1924
|
-
|
|
1925
|
-
|
|
1926
|
-
|
|
1927
|
-
project = requireOptionPath("--project", tokens.shift());
|
|
1928
|
-
continue;
|
|
1929
|
-
}
|
|
1930
|
-
if (token.startsWith("--project=")) {
|
|
1931
|
-
project = requireOptionPath("--project", token.slice("--project=".length));
|
|
1932
|
-
continue;
|
|
1916
|
+
const taken = options.takeDashed(tokens);
|
|
1917
|
+
if (taken !== undefined) {
|
|
1918
|
+
if (taken.def.id === "attach") {
|
|
1919
|
+
attachmentPaths.push(requireOptionPath(taken.def.canonical, taken.value));
|
|
1920
|
+
continue;
|
|
1921
|
+
}
|
|
1922
|
+
if (taken.def.id === "project") {
|
|
1923
|
+
project = requireOptionPath(taken.def.canonical, taken.value);
|
|
1924
|
+
continue;
|
|
1925
|
+
}
|
|
1926
|
+
throw new CliUsageError(`unknown merger option: ${taken.def.canonical}`);
|
|
1933
1927
|
}
|
|
1934
|
-
|
|
1928
|
+
const token = tokens.shift()!;
|
|
1929
|
+
// Rejected public spellings (#342) plus other internal packet field faces.
|
|
1935
1930
|
if (
|
|
1936
|
-
|
|
1937
|
-
token.startsWith("--ak-merger-input=") ||
|
|
1931
|
+
isRejectedPublicSpelling("merger", token) ||
|
|
1938
1932
|
token === "--targetObjectId" ||
|
|
1939
1933
|
token.startsWith("--targetObjectId=") ||
|
|
1940
1934
|
token === "--sourceObjectId" ||
|
|
@@ -1954,6 +1948,7 @@ export function parseMergerArgv(args: readonly string[]): ParseMergerArgvResult
|
|
|
1954
1948
|
positional.push(token);
|
|
1955
1949
|
}
|
|
1956
1950
|
|
|
1951
|
+
options.assertRequired();
|
|
1957
1952
|
return {
|
|
1958
1953
|
instruction: positional.join(" "),
|
|
1959
1954
|
attachmentPaths,
|
|
@@ -2216,178 +2211,110 @@ function requireOptionValue(
|
|
|
2216
2211
|
|
|
2217
2212
|
/**
|
|
2218
2213
|
* Parse taishi-specific argv after the `taishi` token (#336/#337/#338).
|
|
2219
|
-
*
|
|
2220
|
-
*
|
|
2221
|
-
*
|
|
2222
|
-
*
|
|
2214
|
+
* Spellings + mode relation contracts from PUBLIC_OPTION_TABLE.taishi / TAISHI_* (#342).
|
|
2215
|
+
* Mode exclusion, conditional requiredness, cardinality, and at-least-one are
|
|
2216
|
+
* table-driven — do not restate them as parallel handwritten branches here.
|
|
2217
|
+
* Unconditional required:true also goes through the shared consumer.
|
|
2223
2218
|
*/
|
|
2224
2219
|
export function parseTaishiArgv(args: readonly string[]): ParseTaishiArgvResult {
|
|
2225
|
-
|
|
2226
|
-
let ticketRaw: string | undefined;
|
|
2227
|
-
const projectRoots: string[] = [];
|
|
2228
|
-
let groupALabel: string | undefined;
|
|
2229
|
-
let groupAIssuesRaw: string | undefined;
|
|
2230
|
-
let groupBLabel: string | undefined;
|
|
2231
|
-
let groupBIssuesRaw: string | undefined;
|
|
2232
|
-
let sweepToken = false;
|
|
2233
|
-
const attachmentPaths: string[] = [];
|
|
2220
|
+
const valueLists = new Map<string, string[]>();
|
|
2234
2221
|
const tokens = [...args];
|
|
2222
|
+
const definitions = roleOptions("taishi");
|
|
2223
|
+
// Shared typed consumer: dashed + positional take, repeatable, required (#342).
|
|
2224
|
+
const options = createTypedOptionConsumer(definitions);
|
|
2225
|
+
|
|
2226
|
+
const pushValue = (id: string, value: string): void => {
|
|
2227
|
+
const existing = valueLists.get(id);
|
|
2228
|
+
if (existing === undefined) valueLists.set(id, [value]);
|
|
2229
|
+
else existing.push(value);
|
|
2230
|
+
};
|
|
2235
2231
|
|
|
2236
2232
|
while (tokens.length > 0) {
|
|
2237
|
-
|
|
2238
|
-
|
|
2233
|
+
if (tokens[0] === "--") {
|
|
2234
|
+
tokens.shift();
|
|
2239
2235
|
if (tokens.length > 0) {
|
|
2240
2236
|
throw new CliUsageError(`unexpected taishi argument: ${tokens[0]}`);
|
|
2241
2237
|
}
|
|
2242
2238
|
break;
|
|
2243
2239
|
}
|
|
2244
|
-
|
|
2245
|
-
|
|
2246
|
-
|
|
2240
|
+
const taken = options.takeDashed(tokens);
|
|
2241
|
+
if (taken !== undefined) {
|
|
2242
|
+
if (taken.def.valueMetavar === null) {
|
|
2243
|
+
pushValue(taken.def.id, "");
|
|
2244
|
+
continue;
|
|
2247
2245
|
}
|
|
2248
|
-
|
|
2249
|
-
|
|
2250
|
-
|
|
2251
|
-
|
|
2252
|
-
|
|
2253
|
-
|
|
2246
|
+
if (taken.def.id === "ticket") {
|
|
2247
|
+
if (taken.value === undefined || taken.value.trim() === "") {
|
|
2248
|
+
throw new CliUsageError("taishi --ticket requires a positive integer");
|
|
2249
|
+
}
|
|
2250
|
+
pushValue("ticket", taken.value);
|
|
2251
|
+
continue;
|
|
2254
2252
|
}
|
|
2255
|
-
|
|
2256
|
-
|
|
2257
|
-
|
|
2258
|
-
|
|
2259
|
-
|
|
2260
|
-
|
|
2261
|
-
throw new CliUsageError("taishi --ticket requires a positive integer");
|
|
2253
|
+
if (taken.def.id === "project-root") {
|
|
2254
|
+
pushValue(
|
|
2255
|
+
"project-root",
|
|
2256
|
+
requireOptionPath(taken.def.canonical, taken.value),
|
|
2257
|
+
);
|
|
2258
|
+
continue;
|
|
2262
2259
|
}
|
|
2263
|
-
|
|
2264
|
-
|
|
2265
|
-
|
|
2266
|
-
|
|
2267
|
-
|
|
2268
|
-
|
|
2269
|
-
throw new CliUsageError("taishi --ticket requires a positive integer");
|
|
2260
|
+
if (taken.def.id === "attach") {
|
|
2261
|
+
pushValue(
|
|
2262
|
+
"attach",
|
|
2263
|
+
requireOptionPath(taken.def.canonical, taken.value),
|
|
2264
|
+
);
|
|
2265
|
+
continue;
|
|
2270
2266
|
}
|
|
2271
|
-
|
|
2272
|
-
|
|
2273
|
-
|
|
2274
|
-
|
|
2275
|
-
|
|
2276
|
-
|
|
2277
|
-
|
|
2278
|
-
|
|
2279
|
-
|
|
2280
|
-
)
|
|
2281
|
-
|
|
2282
|
-
|
|
2283
|
-
|
|
2284
|
-
|
|
2285
|
-
|
|
2286
|
-
|
|
2287
|
-
|
|
2288
|
-
|
|
2289
|
-
|
|
2290
|
-
|
|
2291
|
-
|
|
2292
|
-
);
|
|
2293
|
-
continue;
|
|
2294
|
-
}
|
|
2295
|
-
if (token === "--group-a-issues") {
|
|
2296
|
-
groupAIssuesRaw = requireOptionValue(
|
|
2297
|
-
"--group-a-issues",
|
|
2298
|
-
tokens.shift(),
|
|
2299
|
-
"a comma-separated positive integer list",
|
|
2300
|
-
);
|
|
2301
|
-
continue;
|
|
2302
|
-
}
|
|
2303
|
-
if (token.startsWith("--group-a-issues=")) {
|
|
2304
|
-
groupAIssuesRaw = requireOptionValue(
|
|
2305
|
-
"--group-a-issues",
|
|
2306
|
-
token.slice("--group-a-issues=".length),
|
|
2307
|
-
"a comma-separated positive integer list",
|
|
2308
|
-
);
|
|
2309
|
-
continue;
|
|
2310
|
-
}
|
|
2311
|
-
if (token === "--group-b-label") {
|
|
2312
|
-
groupBLabel = requireOptionValue("--group-b-label", tokens.shift(), "a label");
|
|
2313
|
-
continue;
|
|
2314
|
-
}
|
|
2315
|
-
if (token.startsWith("--group-b-label=")) {
|
|
2316
|
-
groupBLabel = requireOptionValue(
|
|
2317
|
-
"--group-b-label",
|
|
2318
|
-
token.slice("--group-b-label=".length),
|
|
2319
|
-
"a label",
|
|
2320
|
-
);
|
|
2321
|
-
continue;
|
|
2322
|
-
}
|
|
2323
|
-
if (token === "--group-b-issues") {
|
|
2324
|
-
groupBIssuesRaw = requireOptionValue(
|
|
2325
|
-
"--group-b-issues",
|
|
2326
|
-
tokens.shift(),
|
|
2327
|
-
"a comma-separated positive integer list",
|
|
2328
|
-
);
|
|
2329
|
-
continue;
|
|
2330
|
-
}
|
|
2331
|
-
if (token.startsWith("--group-b-issues=")) {
|
|
2332
|
-
groupBIssuesRaw = requireOptionValue(
|
|
2333
|
-
"--group-b-issues",
|
|
2334
|
-
token.slice("--group-b-issues=".length),
|
|
2335
|
-
"a comma-separated positive integer list",
|
|
2336
|
-
);
|
|
2337
|
-
continue;
|
|
2338
|
-
}
|
|
2339
|
-
if (token === "--attach") {
|
|
2340
|
-
attachmentPaths.push(requireOptionPath("--attach", tokens.shift()));
|
|
2341
|
-
continue;
|
|
2342
|
-
}
|
|
2343
|
-
if (token.startsWith("--attach=")) {
|
|
2344
|
-
attachmentPaths.push(
|
|
2345
|
-
requireOptionPath("--attach", token.slice("--attach=".length)),
|
|
2346
|
-
);
|
|
2347
|
-
continue;
|
|
2267
|
+
if (taken.def.id === "group-a-label" || taken.def.id === "group-b-label") {
|
|
2268
|
+
pushValue(
|
|
2269
|
+
taken.def.id,
|
|
2270
|
+
requireOptionValue(taken.def.canonical, taken.value, "a label"),
|
|
2271
|
+
);
|
|
2272
|
+
continue;
|
|
2273
|
+
}
|
|
2274
|
+
if (
|
|
2275
|
+
taken.def.id === "group-a-issues" || taken.def.id === "group-b-issues"
|
|
2276
|
+
) {
|
|
2277
|
+
pushValue(
|
|
2278
|
+
taken.def.id,
|
|
2279
|
+
requireOptionValue(
|
|
2280
|
+
taken.def.canonical,
|
|
2281
|
+
taken.value,
|
|
2282
|
+
"a comma-separated positive integer list",
|
|
2283
|
+
),
|
|
2284
|
+
);
|
|
2285
|
+
continue;
|
|
2286
|
+
}
|
|
2287
|
+
throw new CliUsageError(`unknown taishi option: ${taken.def.canonical}`);
|
|
2348
2288
|
}
|
|
2289
|
+
const token = tokens.shift()!;
|
|
2349
2290
|
if (token.startsWith("-") && token !== "-") {
|
|
2350
2291
|
throw new CliUsageError(`unknown taishi option: ${token}`);
|
|
2351
2292
|
}
|
|
2352
|
-
//
|
|
2353
|
-
|
|
2354
|
-
|
|
2355
|
-
|
|
2356
|
-
}
|
|
2357
|
-
sweepToken = true;
|
|
2293
|
+
// Positional selectors (e.g. sweep) via shared typed consumer — not a parallel list.
|
|
2294
|
+
const positional = options.takePositional(token);
|
|
2295
|
+
if (positional !== undefined) {
|
|
2296
|
+
pushValue(positional.id, "");
|
|
2358
2297
|
continue;
|
|
2359
2298
|
}
|
|
2360
2299
|
throw new CliUsageError(`unexpected taishi argument: ${token}`);
|
|
2361
2300
|
}
|
|
2362
2301
|
|
|
2363
|
-
const
|
|
2364
|
-
const
|
|
2365
|
-
|
|
2366
|
-
|
|
2367
|
-
|
|
2368
|
-
|
|
2302
|
+
const counts = new Map<string, number>();
|
|
2303
|
+
for (const [id, values] of valueLists) {
|
|
2304
|
+
counts.set(id, values.length);
|
|
2305
|
+
}
|
|
2306
|
+
options.assertRequired();
|
|
2307
|
+
const mode = resolveTaishiMode(new Set(counts.keys()));
|
|
2308
|
+
const verdict = evaluateTaishiModeOptionContract(mode, counts);
|
|
2309
|
+
if (!verdict.ok) {
|
|
2310
|
+
throw new CliUsageError(verdict.message);
|
|
2311
|
+
}
|
|
2369
2312
|
|
|
2370
|
-
if (
|
|
2371
|
-
|
|
2372
|
-
|
|
2373
|
-
|
|
2374
|
-
|
|
2375
|
-
|| groupBIssuesRaw === undefined
|
|
2376
|
-
) {
|
|
2377
|
-
throw new CliUsageError(
|
|
2378
|
-
"usage: ak-role taishi --cohort --group-a-label <L> --group-a-issues <N[,N...]> --group-b-label <L> --group-b-issues <N[,N...]>",
|
|
2379
|
-
);
|
|
2380
|
-
}
|
|
2381
|
-
if (ticketRaw !== undefined || projectRoots.length > 0) {
|
|
2382
|
-
throw new CliUsageError(
|
|
2383
|
-
"taishi --cohort does not accept --ticket or --project-root",
|
|
2384
|
-
);
|
|
2385
|
-
}
|
|
2386
|
-
if (hasSweepFace) {
|
|
2387
|
-
throw new CliUsageError(
|
|
2388
|
-
"taishi --cohort does not accept sweep --attach",
|
|
2389
|
-
);
|
|
2390
|
-
}
|
|
2313
|
+
if (mode === "cohort") {
|
|
2314
|
+
const groupALabel = valueLists.get("group-a-label")![0]!;
|
|
2315
|
+
const groupAIssuesRaw = valueLists.get("group-a-issues")![0]!;
|
|
2316
|
+
const groupBLabel = valueLists.get("group-b-label")![0]!;
|
|
2317
|
+
const groupBIssuesRaw = valueLists.get("group-b-issues")![0]!;
|
|
2391
2318
|
return {
|
|
2392
2319
|
query: "cohort",
|
|
2393
2320
|
groups: [
|
|
@@ -2403,58 +2330,22 @@ export function parseTaishiArgv(args: readonly string[]): ParseTaishiArgvResult
|
|
|
2403
2330
|
};
|
|
2404
2331
|
}
|
|
2405
2332
|
|
|
2406
|
-
if (
|
|
2407
|
-
if (projectRoots.length === 0) {
|
|
2408
|
-
throw new CliUsageError(
|
|
2409
|
-
"usage: ak-role taishi --model-groups --project-root <P> [--project-root <P> ...]",
|
|
2410
|
-
);
|
|
2411
|
-
}
|
|
2412
|
-
if (ticketRaw !== undefined) {
|
|
2413
|
-
throw new CliUsageError("taishi --model-groups does not accept --ticket");
|
|
2414
|
-
}
|
|
2415
|
-
if (hasCohortFlags) {
|
|
2416
|
-
throw new CliUsageError("taishi --model-groups does not accept cohort group flags");
|
|
2417
|
-
}
|
|
2418
|
-
if (hasSweepFace) {
|
|
2419
|
-
throw new CliUsageError(
|
|
2420
|
-
"taishi --model-groups does not accept sweep --attach",
|
|
2421
|
-
);
|
|
2422
|
-
}
|
|
2333
|
+
if (mode === "model-groups") {
|
|
2423
2334
|
return {
|
|
2424
2335
|
query: "model-groups",
|
|
2425
|
-
projectRoots,
|
|
2336
|
+
projectRoots: valueLists.get("project-root") ?? [],
|
|
2426
2337
|
};
|
|
2427
2338
|
}
|
|
2428
2339
|
|
|
2429
|
-
|
|
2430
|
-
if (hasCohortFlags) {
|
|
2431
|
-
throw new CliUsageError("taishi issue query does not accept cohort group flags");
|
|
2432
|
-
}
|
|
2433
|
-
|
|
2434
|
-
if (hasSweepFace) {
|
|
2435
|
-
if (ticketRaw !== undefined || projectRoots.length > 0) {
|
|
2436
|
-
throw new CliUsageError(
|
|
2437
|
-
"taishi sweep --attach cannot combine with --ticket or --project-root",
|
|
2438
|
-
);
|
|
2439
|
-
}
|
|
2340
|
+
if (mode === "sweep") {
|
|
2440
2341
|
return {
|
|
2441
2342
|
query: "sweep",
|
|
2442
|
-
attachmentPaths,
|
|
2343
|
+
attachmentPaths: valueLists.get("attach") ?? [],
|
|
2443
2344
|
};
|
|
2444
2345
|
}
|
|
2445
2346
|
|
|
2446
|
-
|
|
2447
|
-
|
|
2448
|
-
"taishi issue query accepts at most one --project-root (use --model-groups for many)",
|
|
2449
|
-
);
|
|
2450
|
-
}
|
|
2451
|
-
const projectRoot = projectRoots[0];
|
|
2452
|
-
if (ticketRaw === undefined && projectRoot === undefined) {
|
|
2453
|
-
throw new CliUsageError(
|
|
2454
|
-
"usage: ak-role taishi ((--ticket <N> | --project-root <P>) | [sweep] --attach <sweep.json> | --cohort ... | --model-groups ...)",
|
|
2455
|
-
);
|
|
2456
|
-
}
|
|
2457
|
-
|
|
2347
|
+
const ticketRaw = valueLists.get("ticket")?.[0];
|
|
2348
|
+
const projectRoot = valueLists.get("project-root")?.[0];
|
|
2458
2349
|
return {
|
|
2459
2350
|
query: "issue",
|
|
2460
2351
|
...(ticketRaw === undefined
|