@akagilnc/pi-workflow-roles 0.1.2120 → 0.1.2124
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 +2 -4
- package/README.zh-CN.md +2 -4
- package/dist/public-cli/main.js +214 -165
- package/package.json +1 -1
- package/src/public-cli/invocation.ts +18 -28
- package/src/public-cli/option-definitions.ts +35 -62
- package/src/public-cli/taishi-run.ts +41 -52
- package/src/taishi-cohort.ts +4 -0
- package/src/taishi-entry.ts +111 -49
- package/src/taishi-index.ts +39 -20
- package/src/taishi-ledger.ts +90 -45
- package/src/taishi-page.ts +64 -8
package/package.json
CHANGED
|
@@ -412,19 +412,17 @@ export type ParseMergerArgvResult = {
|
|
|
412
412
|
};
|
|
413
413
|
|
|
414
414
|
/**
|
|
415
|
-
* #336/#337/#338 taishi public argv —
|
|
416
|
-
* - issue (default): ticket N
|
|
415
|
+
* #336/#337/#338/#399 taishi public argv — three live faces on one registration seam.
|
|
416
|
+
* - issue (default): bare whole-book or --ticket N (cwd git common-dir)
|
|
417
417
|
* - sweep (#337): optional positional `sweep` and/or --attach paths;
|
|
418
418
|
* sweep payload rides exactly one typed JSON attachment (not argv/stdin)
|
|
419
419
|
* - cohort: two labeled issue-number groups
|
|
420
|
-
* - model-groups
|
|
420
|
+
* --project-root deleted; --model-groups public face disabled (library kernel retained).
|
|
421
421
|
*/
|
|
422
422
|
export type ParseTaishiIssueArgv = {
|
|
423
423
|
readonly query: "issue";
|
|
424
424
|
/** Caller ticket / issue number face (#176 numbering space). */
|
|
425
425
|
readonly ticket?: number;
|
|
426
|
-
/** Direct projectRoot mechanical key (ADR 0068). */
|
|
427
|
-
readonly projectRoot?: string;
|
|
428
426
|
};
|
|
429
427
|
|
|
430
428
|
export type ParseTaishiSweepArgv = {
|
|
@@ -444,16 +442,10 @@ export type ParseTaishiCohortArgv = {
|
|
|
444
442
|
];
|
|
445
443
|
};
|
|
446
444
|
|
|
447
|
-
export type ParseTaishiModelGroupsArgv = {
|
|
448
|
-
readonly query: "model-groups";
|
|
449
|
-
readonly projectRoots: readonly string[];
|
|
450
|
-
};
|
|
451
|
-
|
|
452
445
|
export type ParseTaishiArgvResult =
|
|
453
446
|
| ParseTaishiIssueArgv
|
|
454
447
|
| ParseTaishiSweepArgv
|
|
455
|
-
| ParseTaishiCohortArgv
|
|
456
|
-
| ParseTaishiModelGroupsArgv;
|
|
448
|
+
| ParseTaishiCohortArgv;
|
|
457
449
|
|
|
458
450
|
/** Honest activation-class failure while deriving the active-merge envelope. */
|
|
459
451
|
export class MergerEnvelopeDerivationError extends Error {
|
|
@@ -2271,13 +2263,6 @@ export function parseTaishiArgv(args: readonly string[]): ParseTaishiArgvResult
|
|
|
2271
2263
|
pushValue("ticket", taken.value);
|
|
2272
2264
|
continue;
|
|
2273
2265
|
}
|
|
2274
|
-
if (taken.def.id === "project-root") {
|
|
2275
|
-
pushValue(
|
|
2276
|
-
"project-root",
|
|
2277
|
-
requireOptionPath(taken.def.canonical, taken.value),
|
|
2278
|
-
);
|
|
2279
|
-
continue;
|
|
2280
|
-
}
|
|
2281
2266
|
if (taken.def.id === "attach") {
|
|
2282
2267
|
pushValue(
|
|
2283
2268
|
"attach",
|
|
@@ -2308,6 +2293,20 @@ export function parseTaishiArgv(args: readonly string[]): ParseTaishiArgvResult
|
|
|
2308
2293
|
throw new CliUsageError(`unknown taishi option: ${taken.def.canonical}`);
|
|
2309
2294
|
}
|
|
2310
2295
|
const token = tokens.shift()!;
|
|
2296
|
+
// #399: deleted --project-root; disabled --model-groups public face.
|
|
2297
|
+
if (isRejectedPublicSpelling("taishi", token)) {
|
|
2298
|
+
if (token === "--project-root" || token.startsWith("--project-root=")) {
|
|
2299
|
+
throw new CliUsageError(
|
|
2300
|
+
"taishi no longer accepts --project-root (deleted); use bare call for whole book or --ticket N (cwd git common-dir selects the book)",
|
|
2301
|
+
);
|
|
2302
|
+
}
|
|
2303
|
+
if (token === "--model-groups" || token.startsWith("--model-groups=")) {
|
|
2304
|
+
throw new CliUsageError(
|
|
2305
|
+
"taishi --model-groups public CLI face is disabled; input face is being redesigned for multi-issue comparison (see follow-up ticket)",
|
|
2306
|
+
);
|
|
2307
|
+
}
|
|
2308
|
+
throw new CliUsageError(`unknown taishi option: ${token}`);
|
|
2309
|
+
}
|
|
2311
2310
|
if (token.startsWith("-") && token !== "-") {
|
|
2312
2311
|
throw new CliUsageError(`unknown taishi option: ${token}`);
|
|
2313
2312
|
}
|
|
@@ -2351,13 +2350,6 @@ export function parseTaishiArgv(args: readonly string[]): ParseTaishiArgvResult
|
|
|
2351
2350
|
};
|
|
2352
2351
|
}
|
|
2353
2352
|
|
|
2354
|
-
if (mode === "model-groups") {
|
|
2355
|
-
return {
|
|
2356
|
-
query: "model-groups",
|
|
2357
|
-
projectRoots: valueLists.get("project-root") ?? [],
|
|
2358
|
-
};
|
|
2359
|
-
}
|
|
2360
|
-
|
|
2361
2353
|
if (mode === "sweep") {
|
|
2362
2354
|
return {
|
|
2363
2355
|
query: "sweep",
|
|
@@ -2366,12 +2358,10 @@ export function parseTaishiArgv(args: readonly string[]): ParseTaishiArgvResult
|
|
|
2366
2358
|
}
|
|
2367
2359
|
|
|
2368
2360
|
const ticketRaw = valueLists.get("ticket")?.[0];
|
|
2369
|
-
const projectRoot = valueLists.get("project-root")?.[0];
|
|
2370
2361
|
return {
|
|
2371
2362
|
query: "issue",
|
|
2372
2363
|
...(ticketRaw === undefined
|
|
2373
2364
|
? {}
|
|
2374
2365
|
: { ticket: parseTaishiTicketNumber(ticketRaw) }),
|
|
2375
|
-
...(projectRoot === undefined ? {} : { projectRoot }),
|
|
2376
2366
|
};
|
|
2377
2367
|
}
|
|
@@ -13,8 +13,8 @@
|
|
|
13
13
|
|
|
14
14
|
import { CliUsageError } from "./cli-errors.ts";
|
|
15
15
|
|
|
16
|
-
/** Taishi query faces (#336/#337/#338). */
|
|
17
|
-
export type TaishiMode = "issue" | "sweep" | "cohort"
|
|
16
|
+
/** Taishi public query faces (#336/#337/#338/#399). model-groups CLI face disabled (library kernel retained). */
|
|
17
|
+
export type TaishiMode = "issue" | "sweep" | "cohort";
|
|
18
18
|
|
|
19
19
|
/** Coder/Fixer public phase tokens. */
|
|
20
20
|
export type RolePhase = "plan" | "apply";
|
|
@@ -62,11 +62,10 @@ export type PublicOptionDefinition = {
|
|
|
62
62
|
/** Modes in which this option is required (taishi conditional requiredness). */
|
|
63
63
|
readonly requiredInModes?: readonly TaishiMode[];
|
|
64
64
|
/**
|
|
65
|
-
* Other option ids on the same owner that cannot co-occur
|
|
66
|
-
* (e.g. cohort × model-groups).
|
|
65
|
+
* Other option ids on the same owner that cannot co-occur.
|
|
67
66
|
*/
|
|
68
67
|
readonly exclusiveWith?: readonly string[];
|
|
69
|
-
/** Per-mode maximum occurrences
|
|
68
|
+
/** Per-mode maximum occurrences. */
|
|
70
69
|
readonly maxCountByMode?: Readonly<Partial<Record<TaishiMode, number>>>;
|
|
71
70
|
/**
|
|
72
71
|
* When this option (or positional) is present it activates this mode.
|
|
@@ -85,10 +84,11 @@ export type TaishiRequireAnyOfRule = {
|
|
|
85
84
|
readonly optionIds: readonly string[];
|
|
86
85
|
};
|
|
87
86
|
|
|
88
|
-
/**
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
87
|
+
/**
|
|
88
|
+
* Cross-field at-least-one rules for taishi modes.
|
|
89
|
+
* #399: issue bare call is lawful (whole book from cwd) — no require-any-of on issue.
|
|
90
|
+
*/
|
|
91
|
+
export const TAISHI_REQUIRE_ANY_OF: readonly TaishiRequireAnyOfRule[] = [];
|
|
92
92
|
|
|
93
93
|
/** Residual taishi mode when no `selectsMode` option is present. */
|
|
94
94
|
export const TAISHI_DEFAULT_MODE: TaishiMode = "issue";
|
|
@@ -107,7 +107,6 @@ export function resolveTaishiMode(
|
|
|
107
107
|
}
|
|
108
108
|
if (selected.size === 0) return TAISHI_DEFAULT_MODE;
|
|
109
109
|
if (selected.has("cohort")) return "cohort";
|
|
110
|
-
if (selected.has("model-groups")) return "model-groups";
|
|
111
110
|
if (selected.has("sweep")) return "sweep";
|
|
112
111
|
if (selected.has("issue")) return "issue";
|
|
113
112
|
return TAISHI_DEFAULT_MODE;
|
|
@@ -181,13 +180,6 @@ export function evaluateTaishiModeOptionContract(
|
|
|
181
180
|
"usage: ak-role taishi --cohort --group-a-label <L> --group-a-issues <N[,N...]> --group-b-label <L> --group-b-issues <N[,N...]",
|
|
182
181
|
};
|
|
183
182
|
}
|
|
184
|
-
if (mode === "model-groups") {
|
|
185
|
-
return {
|
|
186
|
-
ok: false,
|
|
187
|
-
message:
|
|
188
|
-
"usage: ak-role taishi --model-groups --project-root <P> [--project-root <P> ...]",
|
|
189
|
-
};
|
|
190
|
-
}
|
|
191
183
|
return {
|
|
192
184
|
ok: false,
|
|
193
185
|
message: `usage: ak-role taishi ${mode} requires ${missingRequired
|
|
@@ -205,7 +197,7 @@ export function evaluateTaishiModeOptionContract(
|
|
|
205
197
|
return {
|
|
206
198
|
ok: false,
|
|
207
199
|
message:
|
|
208
|
-
"usage: ak-role taishi (
|
|
200
|
+
"usage: ak-role taishi ([--ticket <N>] | [sweep] --attach <sweep.json> | --cohort ...)",
|
|
209
201
|
};
|
|
210
202
|
}
|
|
211
203
|
const flags = rule.optionIds
|
|
@@ -247,6 +239,22 @@ export const REJECTED_PUBLIC_SPELLINGS = [
|
|
|
247
239
|
zh: "校书郎 input packet 由内部装配,不是公开旗标。",
|
|
248
240
|
},
|
|
249
241
|
},
|
|
242
|
+
{
|
|
243
|
+
owner: "taishi",
|
|
244
|
+
spellings: ["--project-root"],
|
|
245
|
+
reason: {
|
|
246
|
+
en: "Deleted (#399). taishi no longer accepts --project-root; use bare call for whole book or --ticket N (cwd git common-dir selects the book).",
|
|
247
|
+
zh: "已删除(#399)。taishi 不再接受 --project-root;裸调用=整簿,或 --ticket N(cwd git common-dir 定簿)。",
|
|
248
|
+
},
|
|
249
|
+
},
|
|
250
|
+
{
|
|
251
|
+
owner: "taishi",
|
|
252
|
+
spellings: ["--model-groups"],
|
|
253
|
+
reason: {
|
|
254
|
+
en: "Public CLI face disabled (#399). Input face is being redesigned for multi-issue comparison (see follow-up ticket). Library kernel retained.",
|
|
255
|
+
zh: "公开 CLI 面已停用(#399)。输入面按多 issue 重设计中(见后续票)。聚合内核保留。",
|
|
256
|
+
},
|
|
257
|
+
},
|
|
250
258
|
] as const satisfies readonly RejectedSpelling[];
|
|
251
259
|
|
|
252
260
|
const GLOBAL_OPTIONS = [
|
|
@@ -311,8 +319,8 @@ const GLOBAL_OPTIONS = [
|
|
|
311
319
|
/**
|
|
312
320
|
* Immutable shared semantics for the common ledger `--project` face.
|
|
313
321
|
* Role rows bind owner only — do not copy these fields per role.
|
|
314
|
-
* Role-specific project faces (merger merge-root
|
|
315
|
-
*
|
|
322
|
+
* Role-specific project faces (merger merge-root) stay explicit below and
|
|
323
|
+
* must not use this binding. taishi `--project-root` is deleted (#399).
|
|
316
324
|
*/
|
|
317
325
|
const SHARED_PROJECT_SEMANTICS = {
|
|
318
326
|
id: "project",
|
|
@@ -565,23 +573,6 @@ const TAISHI_OPTIONS = [
|
|
|
565
573
|
zh: "可选 sweep 模式词元(至多一次;不得夹带其他 positional)。",
|
|
566
574
|
},
|
|
567
575
|
},
|
|
568
|
-
{
|
|
569
|
-
id: "project-root",
|
|
570
|
-
owner: "taishi",
|
|
571
|
-
canonical: "--project-root",
|
|
572
|
-
aliases: [],
|
|
573
|
-
valueMetavar: "path",
|
|
574
|
-
required: false,
|
|
575
|
-
repeatable: true,
|
|
576
|
-
form: "option",
|
|
577
|
-
modes: ["issue", "model-groups"],
|
|
578
|
-
requiredInModes: ["model-groups"],
|
|
579
|
-
maxCountByMode: { issue: 1 },
|
|
580
|
-
description: {
|
|
581
|
-
en: "Project-root scope key. Issue: at most one (with --ticket at least one of the two). Model-groups: one or more required.",
|
|
582
|
-
zh: "projectRoot 范围键。issue:至多一个(与 --ticket 至少居其一)。model-groups:一个或多个且必填。",
|
|
583
|
-
},
|
|
584
|
-
},
|
|
585
576
|
{
|
|
586
577
|
id: "ticket",
|
|
587
578
|
owner: "taishi",
|
|
@@ -593,8 +584,8 @@ const TAISHI_OPTIONS = [
|
|
|
593
584
|
form: "option",
|
|
594
585
|
modes: ["issue"],
|
|
595
586
|
description: {
|
|
596
|
-
en: "Ticket/issue number
|
|
597
|
-
zh: "
|
|
587
|
+
en: "Ticket/issue number; live filter by invocation.ticketNumber inside the cwd book (git common-dir). Bare call = whole book. No library-index bootstrap.",
|
|
588
|
+
zh: "票号;在 cwd 候簿(git common-dir)内按 invocation.ticketNumber 现取现算。裸调用=整簿。不依赖 library-index 自举。",
|
|
598
589
|
},
|
|
599
590
|
},
|
|
600
591
|
{
|
|
@@ -625,28 +616,10 @@ const TAISHI_OPTIONS = [
|
|
|
625
616
|
repeatable: false,
|
|
626
617
|
form: "option",
|
|
627
618
|
modes: ["cohort"],
|
|
628
|
-
exclusiveWith: ["model-groups"],
|
|
629
619
|
selectsMode: "cohort",
|
|
630
620
|
description: {
|
|
631
|
-
en: "Select cohort mode
|
|
632
|
-
zh: "选择 cohort
|
|
633
|
-
},
|
|
634
|
-
},
|
|
635
|
-
{
|
|
636
|
-
id: "model-groups",
|
|
637
|
-
owner: "taishi",
|
|
638
|
-
canonical: "--model-groups",
|
|
639
|
-
aliases: [],
|
|
640
|
-
valueMetavar: null,
|
|
641
|
-
required: false,
|
|
642
|
-
repeatable: false,
|
|
643
|
-
form: "option",
|
|
644
|
-
modes: ["model-groups"],
|
|
645
|
-
exclusiveWith: ["cohort"],
|
|
646
|
-
selectsMode: "model-groups",
|
|
647
|
-
description: {
|
|
648
|
-
en: "Select model-groups mode (mutually exclusive with --cohort).",
|
|
649
|
-
zh: "选择 model-groups 模式(与 --cohort 互斥)。",
|
|
621
|
+
en: "Select cohort mode.",
|
|
622
|
+
zh: "选择 cohort 模式。",
|
|
650
623
|
},
|
|
651
624
|
},
|
|
652
625
|
{
|
|
@@ -1097,14 +1070,14 @@ const ROLE_COMMAND_HELP = {
|
|
|
1097
1070
|
},
|
|
1098
1071
|
taishi: {
|
|
1099
1072
|
command: "taishi",
|
|
1100
|
-
summary: "Deterministic analysis seat (issue / sweep / cohort
|
|
1073
|
+
summary: "Deterministic analysis seat (issue / sweep / cohort).",
|
|
1101
1074
|
usage: [
|
|
1102
|
-
"ak-role taishi
|
|
1075
|
+
"ak-role taishi [--ticket <N>]",
|
|
1103
1076
|
"ak-role taishi [sweep] --attach <path>",
|
|
1104
1077
|
"ak-role taishi --cohort --group-a-label <L> --group-a-issues <N[,N...]> --group-b-label <L> --group-b-issues <N[,N...]>",
|
|
1105
|
-
"ak-role taishi --model-groups --project-root <P> [--project-root <P> ...]",
|
|
1106
1078
|
],
|
|
1107
1079
|
examples: [
|
|
1080
|
+
"ak-role taishi",
|
|
1108
1081
|
"ak-role taishi --ticket 125",
|
|
1109
1082
|
"ak-role taishi sweep --attach ./sweep.json",
|
|
1110
1083
|
],
|
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Public taishi adapter (#336/#337/#338): argv → typed query → runTaishi family.
|
|
2
|
+
* Public taishi adapter (#336/#337/#338/#399): argv → typed query → runTaishi family.
|
|
3
3
|
* Deterministic analysis seat — no Pi runner, no admission lease.
|
|
4
4
|
* Reuses existing CLI failure envelope (CliUsageError + structural reject +
|
|
5
5
|
* ControlledFailure).
|
|
6
|
-
*
|
|
6
|
+
* #399: issue query = book (cwd git common-dir) × optional --ticket N.
|
|
7
|
+
* Bare call = whole book; --project-root deleted; --model-groups public face disabled;
|
|
8
|
+
* no library-index bootstrap. Library model-groups kernel retained for follow-up.
|
|
7
9
|
* #337 sweep: exactly one typed JSON attachment → TaishiSweepModeInput → #329 kernel.
|
|
8
|
-
* #338:
|
|
10
|
+
* #338: issue/cohort (+ library model-groups); sync compute-if-missing; whole-compute failure →
|
|
9
11
|
* ControlledFailure terminal (code/projectRoot/issueNumber/real cause).
|
|
10
12
|
* "Unobtrusive" binds #337 merge auto-trigger only, not this user-initiated query.
|
|
11
13
|
*/
|
|
@@ -13,16 +15,16 @@ import { readFile } from "node:fs/promises";
|
|
|
13
15
|
import { isAbsolute, resolve } from "node:path";
|
|
14
16
|
import { Value } from "typebox/value";
|
|
15
17
|
|
|
18
|
+
import {
|
|
19
|
+
ActivationGitRepositoryRequiredError,
|
|
20
|
+
resolveBookKeyFromGit,
|
|
21
|
+
} from "../activation-ledger-git.ts";
|
|
16
22
|
import {
|
|
17
23
|
errnoCode,
|
|
18
24
|
physicalPathIdentity,
|
|
19
25
|
resolveActivationLedgerHome,
|
|
20
26
|
} from "../activation-ledger-topology.ts";
|
|
21
27
|
import { exactUtf8 } from "../exact-utf8.ts";
|
|
22
|
-
import {
|
|
23
|
-
findTaishiLibraryIndexRow,
|
|
24
|
-
readTaishiLibraryIndexPage,
|
|
25
|
-
} from "../taishi-index.ts";
|
|
26
28
|
import {
|
|
27
29
|
readOrComputeTaishiIssuePage,
|
|
28
30
|
runTaishi,
|
|
@@ -44,58 +46,52 @@ export type TaishiRunEnv = {
|
|
|
44
46
|
};
|
|
45
47
|
|
|
46
48
|
/**
|
|
47
|
-
*
|
|
48
|
-
* -
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
49
|
+
* Resolve the issue-query book from cwd git common-dir (same owner as record layer).
|
|
50
|
+
* Non-git cwd fails loud — bare / --ticket both require a book identity.
|
|
51
|
+
*/
|
|
52
|
+
export function resolveTaishiIssueBookKeyFromCwd(cwd: string = process.cwd()): string {
|
|
53
|
+
try {
|
|
54
|
+
return resolveBookKeyFromGit(cwd);
|
|
55
|
+
} catch (error) {
|
|
56
|
+
if (error instanceof ActivationGitRepositoryRequiredError) {
|
|
57
|
+
throw new CliUsageError(
|
|
58
|
+
"taishi issue query requires a git repository cwd (book = git common-dir); run inside a repository (bare = whole book, or --ticket N)",
|
|
59
|
+
{ cause: error },
|
|
60
|
+
);
|
|
61
|
+
}
|
|
62
|
+
throw error;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Build the sole library issue-mode input from public argv faces (#399).
|
|
68
|
+
* - bare → whole book from cwd git common-dir
|
|
69
|
+
* - --ticket N → issueNumber = ticketNumber = N inside that book (strict; no index)
|
|
70
|
+
* - --project-root rejected at parse (deleted unconditionally)
|
|
54
71
|
*/
|
|
55
72
|
export async function buildTaishiIssueModeInputFromPublicArgv(
|
|
56
73
|
parsed: ParseTaishiIssueArgv,
|
|
57
|
-
|
|
74
|
+
_ledgerHome: string,
|
|
58
75
|
): Promise<TaishiIssueModeInput> {
|
|
76
|
+
const cwd = process.cwd();
|
|
77
|
+
const bookKey = resolveTaishiIssueBookKeyFromCwd(cwd);
|
|
78
|
+
const projectRoot = physicalPathIdentity(cwd);
|
|
59
79
|
const ticket = parsed.ticket;
|
|
60
|
-
const directRoot = parsed.projectRoot;
|
|
61
80
|
|
|
62
81
|
if (ticket === undefined) {
|
|
63
82
|
return {
|
|
64
83
|
mode: "issue",
|
|
65
|
-
|
|
84
|
+
bookKey,
|
|
85
|
+
projectRoot,
|
|
66
86
|
};
|
|
67
87
|
}
|
|
68
88
|
|
|
69
|
-
// ticket N = issueNumber (no conversion); also the C4 typed ticket face.
|
|
70
|
-
const index = await readTaishiLibraryIndexPage(ledgerHome);
|
|
71
|
-
const row = findTaishiLibraryIndexRow(index, ticket);
|
|
72
|
-
|
|
73
|
-
let projectRoot: string;
|
|
74
|
-
if (row !== undefined) {
|
|
75
|
-
// Ticket-resolved index projectRoot wins over any concurrent --project-root.
|
|
76
|
-
projectRoot = row.projectRoot;
|
|
77
|
-
} else if (directRoot !== undefined) {
|
|
78
|
-
// Index miss with project-root fallback (ticket faces still set for C4).
|
|
79
|
-
projectRoot = directRoot;
|
|
80
|
-
} else {
|
|
81
|
-
throw new CliUsageError(
|
|
82
|
-
`taishi library index has no row for ticket ${ticket}`,
|
|
83
|
-
);
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
// Dual-param conflict: index root won, but caller also supplied a distinct --project-root.
|
|
87
|
-
// Carry the losing root so the metrics page records the call-face conflict fact.
|
|
88
|
-
const dualParamConflict =
|
|
89
|
-
row !== undefined
|
|
90
|
-
&& directRoot !== undefined
|
|
91
|
-
&& physicalPathIdentity(directRoot) !== physicalPathIdentity(projectRoot);
|
|
92
|
-
|
|
93
89
|
return {
|
|
94
90
|
mode: "issue",
|
|
91
|
+
bookKey,
|
|
95
92
|
projectRoot,
|
|
96
93
|
ticketNumber: ticket,
|
|
97
94
|
issueNumber: ticket,
|
|
98
|
-
...(dualParamConflict ? { conflictingProjectRoot: directRoot } : {}),
|
|
99
95
|
};
|
|
100
96
|
}
|
|
101
97
|
|
|
@@ -164,7 +160,8 @@ export async function buildTaishiSweepModeInputFromAttachmentPaths(
|
|
|
164
160
|
|
|
165
161
|
/**
|
|
166
162
|
* Public taishi run path — parse → resolve → query → typed receipt on stdout.
|
|
167
|
-
* Issue (#336/#338 compute-if-missing), sweep (#337), cohort
|
|
163
|
+
* Issue (#336/#338 compute-if-missing), sweep (#337), cohort (#338).
|
|
164
|
+
* model-groups public face disabled at parse (#399); library kernel retained.
|
|
168
165
|
*/
|
|
169
166
|
export async function runPublicTaishi(
|
|
170
167
|
argv: readonly string[],
|
|
@@ -195,15 +192,6 @@ export async function runPublicTaishi(
|
|
|
195
192
|
return { exitCode: 0 };
|
|
196
193
|
}
|
|
197
194
|
|
|
198
|
-
if (parsed.query === "model-groups") {
|
|
199
|
-
const result = await runTaishi({
|
|
200
|
-
mode: "model-groups",
|
|
201
|
-
projectRoots: parsed.projectRoots,
|
|
202
|
-
});
|
|
203
|
-
io.stdout(`${JSON.stringify(result, null, 2)}\n`);
|
|
204
|
-
return { exitCode: 0 };
|
|
205
|
-
}
|
|
206
|
-
|
|
207
195
|
// issue query — compute-if-missing (#338); sole kernel on miss.
|
|
208
196
|
const input = await buildTaishiIssueModeInputFromPublicArgv(parsed, ledgerHome);
|
|
209
197
|
const result = await readOrComputeTaishiIssuePage(input);
|
|
@@ -224,6 +212,7 @@ export async function runPublicTaishi(
|
|
|
224
212
|
...(code === undefined ? {} : { identity: { code } }),
|
|
225
213
|
details: {
|
|
226
214
|
code: error.code,
|
|
215
|
+
bookKey: error.bookKey,
|
|
227
216
|
projectRoot: error.projectRoot,
|
|
228
217
|
...(error.issueNumber === undefined ? {} : { issueNumber: error.issueNumber }),
|
|
229
218
|
},
|
package/src/taishi-cohort.ts
CHANGED
|
@@ -32,6 +32,7 @@ import type { TaishiAcceptanceSuccessReworkSection } from "./taishi-metric-famil
|
|
|
32
32
|
export type TaishiIssuePageEnsuring = (input: {
|
|
33
33
|
readonly projectRoot: string;
|
|
34
34
|
readonly issueNumber: number;
|
|
35
|
+
readonly bookKey?: string;
|
|
35
36
|
}) => Promise<TaishiIssueMetricsPage>;
|
|
36
37
|
|
|
37
38
|
/** LOC-style optional metric — never encode absence as 0 or Infinity. */
|
|
@@ -56,6 +57,7 @@ export type TaishiCohortIssueEntry =
|
|
|
56
57
|
| {
|
|
57
58
|
readonly issueNumber: number;
|
|
58
59
|
readonly status: "present";
|
|
60
|
+
readonly bookKey: string;
|
|
59
61
|
readonly projectRoot: string;
|
|
60
62
|
}
|
|
61
63
|
| {
|
|
@@ -170,11 +172,13 @@ async function aggregateGroup(
|
|
|
170
172
|
const page = (await ensureIssuePage({
|
|
171
173
|
projectRoot: row.projectRoot,
|
|
172
174
|
issueNumber,
|
|
175
|
+
bookKey: row.bookKey,
|
|
173
176
|
})) as TaishiCohortSourcePage;
|
|
174
177
|
|
|
175
178
|
issueEntries.push({
|
|
176
179
|
issueNumber,
|
|
177
180
|
status: "present",
|
|
181
|
+
bookKey: row.bookKey,
|
|
178
182
|
projectRoot: row.projectRoot,
|
|
179
183
|
});
|
|
180
184
|
|