@akagilnc/pi-workflow-roles 0.1.2114 → 0.1.2118

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 CHANGED
@@ -82,33 +82,9 @@ ak-role merger --project /path/to/worktree "Reconcile the active merge."
82
82
 
83
83
  Roles are named after Tang/Song offices; the full roster and naming rule live in [README.zh-CN.md](https://github.com/Akagilnc/ak-pi-workflow-roles/blob/main/README.zh-CN.md).
84
84
 
85
- ## Developer seam: raw session invocation (advanced)
85
+ ## Codex fast tier
86
86
 
87
- Most callers never need this. The source tree retains an explicitly loadable raw-Pi seam for package development and low-level diagnosis; it is not a supported invocation recipe—external callers use `ak-role`.
88
-
89
- A raw run loads the role runtime explicitly and selects the role through the internal flag. This is the real argv shape, taken from the CLI’s own builders and recorded runs under the ledger book:
90
-
91
- ```bash
92
- run=~/.ak-roles/books/<book>/issues/<issue>/runs/<invocation>@<source-tree>
93
- pi --no-extensions \
94
- -e <packageRoot>/extensions/role-runtime.ts \
95
- --no-skills --no-prompt-templates --no-themes --no-context-files \
96
- --session "$run/session/session.jsonl" \
97
- --session-dir "$run/session" \
98
- --ak-role judge --mode json \
99
- "Adjudicate the attached materials." \
100
- </dev/null >/dev/null 2>"$run/stderr.log"
101
- ```
102
-
103
- `--session` names the exact session file principal (never directory-latest); `--session-dir` is its directory. Judge takes the instruction as the prompt; other roles pass durable payload files through their own internal flags (`--ak-coder-task`, `--ak-fix-packet`, and siblings), assembled by each role’s builder in `src/public-cli/*-run.ts` through the load boundary in `src/public-cli/explicit-internal.ts`. Derive flags from that source—and from recorded runs under the ledger book—never from prose.
104
-
105
- Discipline:
106
-
107
- - seal stdin with `</dev/null`—Pi reads a non-TTY stdin to EOF before starting, so an open background pipe parks the run forever;
108
- - send stdout to `/dev/null`—the session file is the authoritative record and stdout is an unbounded copy surface; attach dashboards to `stderr.log` and the session file;
109
- - keep `stderr.log` and `invocation.json` in the same `runs/` directory, as in the example above.
110
-
111
- Codex fast tier: enable fast tier with `echo "fast_mode = on" > ~/.pi-codex-fast`; disable it with `echo "fast_mode = off" > ~/.pi-codex-fast` (or delete the file). The change takes effect on the next request without a restart. Fast tier costs more than the default tier.
87
+ Enable fast tier with `echo "fast_mode = on" > ~/.pi-codex-fast`; disable it with `echo "fast_mode = off" > ~/.pi-codex-fast` (or delete the file). The change takes effect on the next request without a restart. Fast tier costs more than the default tier.
112
88
 
113
89
  <!-- BEGIN GENERATED: public-cli-options -->
114
90
  ## Public CLI options (generated)
package/README.zh-CN.md CHANGED
@@ -111,33 +111,9 @@ ak-role merger --project /path/to/worktree "Reconcile the active merge."
111
111
 
112
112
  `拾遗补阙` 成对留档,待将来出现第二个进言席再启用。
113
113
 
114
- ## 开发者接缝:手拼 session(高级)
114
+ ## Codex fast 档
115
115
 
116
- 多数调用者不需要本节。源码树保留一条可显式装载的 raw-Pi 接缝,供包开发与底层诊断;它不是受支持的调用配方——外部调用者用 `ak-role`。
117
-
118
- 原始运行显式装载角色运行时,经内部旗标选角色。以下 argv 全形取自 CLI 自身 builder 与卷宗实记:
119
-
120
- ```bash
121
- run=~/.ak-roles/books/<book>/issues/<issue>/runs/<invocation>@<源树>
122
- pi --no-extensions \
123
- -e <packageRoot>/extensions/role-runtime.ts \
124
- --no-skills --no-prompt-templates --no-themes --no-context-files \
125
- --session "$run/session/session.jsonl" \
126
- --session-dir "$run/session" \
127
- --ak-role judge --mode json \
128
- "Adjudicate the attached materials." \
129
- </dev/null >/dev/null 2>"$run/stderr.log"
130
- ```
131
-
132
- `--session` 指精确 session 文件正本(非 directory-latest);`--session-dir` 为其目录。大理寺的指令走 prompt;其余角色经各自内部旗标传持久 payload 文件(`--ak-coder-task`、`--ak-fix-packet` 等),由各角色 builder(`src/public-cli/*-run.ts`)经装载边界 `src/public-cli/explicit-internal.ts` 装配。旗标从源码与卷宗实记推导,勿从散文推导。
133
-
134
- 纪律:
135
-
136
- - stdin 须以 `</dev/null` 封死——Pi 会将非 TTY stdin 读到 EOF 才开工,未封死的后台管道=永久停车;
137
- - stdout 丢 `/dev/null`——session 文件才是正本,stdout 是无上限副本面;仪表挂 `stderr.log` 与 session 文件;
138
- - `stderr.log` 与 `invocation.json` 落在同次 `runs/` 目录,如上例。
139
-
140
- Codex fast 档:开启:`echo "fast_mode = on" > ~/.pi-codex-fast`;关闭:`echo "fast_mode = off" > ~/.pi-codex-fast`(或删文件)。修改后无需重启,下一个请求即生效。Fast 档价格高于默认档。
116
+ 开启:`echo "fast_mode = on" > ~/.pi-codex-fast`;关闭:`echo "fast_mode = off" > ~/.pi-codex-fast`(或删文件)。修改后无需重启,下一个请求即生效。Fast 档价格高于默认档。
141
117
 
142
118
  <!-- BEGIN GENERATED: public-cli-options -->
143
119
  ## 公开 CLI 选项(生成)
@@ -15806,44 +15806,46 @@ function projectOwnerOptions(owner) {
15806
15806
  description: def.description
15807
15807
  }));
15808
15808
  }
15809
- function renderOwnerOptionHelpLines(owner, locale2 = "en") {
15809
+ function projectCommandHelp(topic) {
15810
+ if (!(topic in PUBLIC_COMMAND_HELP)) return void 0;
15811
+ const facts = PUBLIC_COMMAND_HELP[topic];
15812
+ return {
15813
+ command: facts.command,
15814
+ summary: facts.summary,
15815
+ usage: [...facts.usage],
15816
+ examples: [...facts.examples]
15817
+ };
15818
+ }
15819
+ function renderHumanOwnerOptionLines(owner, locale2 = "en") {
15810
15820
  const lines = [];
15811
15821
  for (const opt of projectOwnerOptions(owner)) {
15812
- const aliasText = opt.aliases.length === 0 ? "-" : opt.aliases.join(",");
15813
- const metavar = opt.valueMetavar ?? "-";
15814
- const required = opt.required ? "required" : "optional";
15815
- const repeatable = opt.repeatable ? "repeatable" : "single";
15816
- const form = opt.form;
15817
- const phases = opt.phases === void 0 ? "-" : opt.phases.join("|");
15818
- const modes = opt.modes === void 0 ? "-" : opt.modes.join("|");
15819
- const requiredInModes = opt.requiredInModes === void 0 ? "-" : opt.requiredInModes.join("|");
15820
- const exclusiveWith = opt.exclusiveWith === void 0 ? "-" : opt.exclusiveWith.join("|");
15821
- const maxCount = opt.maxCountByMode === void 0 ? "-" : Object.entries(opt.maxCountByMode).map(([mode, n]) => `${mode}:${n}`).join(",");
15822
- const defaultValue = opt.defaultValue ?? "-";
15822
+ let spelling = opt.canonical;
15823
+ if (opt.valueMetavar !== null) {
15824
+ spelling = `${spelling} <${opt.valueMetavar}>`;
15825
+ }
15826
+ if (opt.aliases.length > 0) {
15827
+ const aliasHint = opt.aliases.join(", ");
15828
+ if (opt.form === "positional") {
15829
+ spelling = opt.aliases.length > 0 ? opt.aliases.join("|") : spelling;
15830
+ } else {
15831
+ spelling = `${spelling} (${aliasHint})`;
15832
+ }
15833
+ }
15834
+ const tags = [];
15835
+ if (opt.required) tags.push("required");
15836
+ if (opt.requiredInModes !== void 0) {
15837
+ tags.push(`required:${opt.requiredInModes.join("|")}`);
15838
+ }
15839
+ if (opt.repeatable) tags.push("repeatable");
15840
+ if (opt.defaultValue !== void 0) tags.push(`default=${opt.defaultValue}`);
15841
+ if (opt.form === "positional") tags.push("positional");
15842
+ const tagText = tags.length === 0 ? "" : ` [${tags.join(", ")}]`;
15823
15843
  const desc = locale2 === "zh" ? opt.description.zh : opt.description.en;
15824
- lines.push(
15825
- [
15826
- "option",
15827
- opt.id,
15828
- opt.canonical,
15829
- `aliases=${aliasText}`,
15830
- `metavar=${metavar}`,
15831
- required,
15832
- repeatable,
15833
- `form=${form}`,
15834
- `phases=${phases}`,
15835
- `modes=${modes}`,
15836
- `requiredInModes=${requiredInModes}`,
15837
- `exclusiveWith=${exclusiveWith}`,
15838
- `maxCountByMode=${maxCount}`,
15839
- `default=${defaultValue}`,
15840
- desc
15841
- ].join(" ")
15842
- );
15844
+ lines.push(` ${spelling}${tagText} ${desc}`);
15843
15845
  }
15844
15846
  return lines;
15845
15847
  }
15846
- var TAISHI_REQUIRE_ANY_OF, TAISHI_DEFAULT_MODE, REJECTED_PUBLIC_SPELLINGS, GLOBAL_OPTIONS, SHARED_PROJECT_SEMANTICS, SHARED_ATTACH_SEMANTICS, JUDGE_OPTIONS, CODER_OPTIONS, FIXER_OPTIONS, REVIEWER_OPTIONS, COLLECTOR_OPTIONS, DOCTOR_OPTIONS, MERGER_OPTIONS, TAISHI_OPTIONS, PUBLIC_OPTION_TABLE;
15848
+ var TAISHI_REQUIRE_ANY_OF, TAISHI_DEFAULT_MODE, REJECTED_PUBLIC_SPELLINGS, GLOBAL_OPTIONS, SHARED_PROJECT_SEMANTICS, SHARED_ATTACH_SEMANTICS, JUDGE_OPTIONS, CODER_OPTIONS, FIXER_OPTIONS, REVIEWER_OPTIONS, COLLECTOR_OPTIONS, DOCTOR_OPTIONS, MERGER_OPTIONS, TAISHI_OPTIONS, PUBLIC_OPTION_TABLE, PUBLIC_NAVIGATOR_HELP_NOTE, TOP_LEVEL_HELP, ROLE_COMMAND_HELP, SUPPORT_COMMAND_HELP, PUBLIC_COMMAND_HELP;
15847
15849
  var init_option_definitions = __esm({
15848
15850
  "src/public-cli/option-definitions.ts"() {
15849
15851
  "use strict";
@@ -16317,6 +16319,133 @@ var init_option_definitions = __esm({
16317
16319
  merger: MERGER_OPTIONS,
16318
16320
  taishi: TAISHI_OPTIONS
16319
16321
  };
16322
+ PUBLIC_NAVIGATOR_HELP_NOTE = "Navigator attends automatically on every run; configure with `ak-role config set navigator <provider/model[:thinking]>` (not a caller command).";
16323
+ TOP_LEVEL_HELP = {
16324
+ command: "top",
16325
+ summary: "public role CLI",
16326
+ usage: [
16327
+ "ak-role <command> [options]",
16328
+ "ak-role help <command>"
16329
+ ],
16330
+ examples: [
16331
+ 'ak-role judge --attach ./plan.md "Review this plan."',
16332
+ 'ak-role coder plan "Propose the first implementation plan."'
16333
+ ]
16334
+ };
16335
+ ROLE_COMMAND_HELP = {
16336
+ judge: {
16337
+ command: "judge",
16338
+ summary: "Adjudicate the supplied materials; infers its own burden.",
16339
+ usage: ["ak-role judge [options] [instruction]"],
16340
+ examples: [
16341
+ 'ak-role judge --attach ./plan.md "Review this plan."',
16342
+ 'ak-role judge --attach ./findings.md --attach ./adr.md "Adjudicate every finding."'
16343
+ ]
16344
+ },
16345
+ coder: {
16346
+ command: "coder",
16347
+ summary: "First implementation; phase defaults to apply.",
16348
+ usage: ["ak-role coder [plan|apply] [options] <instruction>"],
16349
+ examples: [
16350
+ 'ak-role coder plan "Propose the first implementation plan."',
16351
+ 'ak-role coder apply --attach ./plan.md "Implement the approved slice."'
16352
+ ]
16353
+ },
16354
+ fixer: {
16355
+ command: "fixer",
16356
+ summary: "Repair the assigned findings; phase defaults to apply.",
16357
+ usage: ["ak-role fixer [plan|apply] [options] <instruction>"],
16358
+ examples: [
16359
+ 'ak-role fixer --attach ./findings.md --prerequisites ./prereqs.json "Repair the findings."',
16360
+ 'ak-role fixer plan --attach ./findings.md "Propose the repair plan."'
16361
+ ]
16362
+ },
16363
+ reviewer: {
16364
+ command: "reviewer",
16365
+ summary: "Fixed-target two-axis review (Standards + Spec).",
16366
+ usage: ["ak-role reviewer --base <revision> [options] <instruction>"],
16367
+ examples: [
16368
+ 'ak-role reviewer --base main "Review the branch against the governing issue and repository authority."'
16369
+ ]
16370
+ },
16371
+ collector: {
16372
+ command: "collector",
16373
+ summary: "Collect GitHub PR review evidence (one-shot).",
16374
+ usage: ["ak-role collector --pr <number> [options] [instruction]"],
16375
+ examples: [
16376
+ "ak-role collector --pr 42 --repo owner/repository",
16377
+ "ak-role collector --pr 42 --request-manifest ./requests.json"
16378
+ ]
16379
+ },
16380
+ doctor: {
16381
+ command: "doctor",
16382
+ summary: "Diagnose one retained case (one-shot).",
16383
+ usage: ["ak-role doctor --issue <number> [options] [instruction]"],
16384
+ examples: [
16385
+ 'ak-role doctor --issue 115 "Diagnose this retained case."'
16386
+ ]
16387
+ },
16388
+ merger: {
16389
+ command: "merger",
16390
+ summary: "Resolve one ordinary merge already in conflict.",
16391
+ usage: ["ak-role merger [options] <instruction>"],
16392
+ examples: [
16393
+ 'ak-role merger --project /path/to/worktree "Reconcile the active merge."'
16394
+ ]
16395
+ },
16396
+ taishi: {
16397
+ command: "taishi",
16398
+ summary: "Deterministic analysis seat (issue / sweep / cohort / model-groups).",
16399
+ usage: [
16400
+ "ak-role taishi (--ticket <N> | --project-root <P>) [options]",
16401
+ "ak-role taishi [sweep] --attach <path>",
16402
+ "ak-role taishi --cohort --group-a-label <L> --group-a-issues <N[,N...]> --group-b-label <L> --group-b-issues <N[,N...]>",
16403
+ "ak-role taishi --model-groups --project-root <P> [--project-root <P> ...]"
16404
+ ],
16405
+ examples: [
16406
+ "ak-role taishi --ticket 125",
16407
+ "ak-role taishi sweep --attach ./sweep.json"
16408
+ ]
16409
+ }
16410
+ };
16411
+ SUPPORT_COMMAND_HELP = {
16412
+ roles: {
16413
+ command: "roles",
16414
+ summary: "List effective seats and models.",
16415
+ usage: ["ak-role roles"],
16416
+ examples: ["ak-role roles"]
16417
+ },
16418
+ config: {
16419
+ command: "config",
16420
+ summary: "Persistent seat model and labor-engine defaults.",
16421
+ usage: [
16422
+ "ak-role config set <seat> <provider/model[:thinking]> [<seat> <spec> ...]",
16423
+ "ak-role config set-engine <seat> <name>",
16424
+ "ak-role config unset-engine <seat>"
16425
+ ],
16426
+ examples: [
16427
+ "ak-role config set judge openai-codex/gpt-5.6-sol:high",
16428
+ "ak-role config set-engine judge opus"
16429
+ ]
16430
+ },
16431
+ help: {
16432
+ command: "help",
16433
+ summary: "Show public CLI help.",
16434
+ usage: ["ak-role help [command]", "ak-role --help"],
16435
+ examples: ["ak-role help coder", "ak-role help judge"]
16436
+ },
16437
+ resume: {
16438
+ command: "resume",
16439
+ summary: "Reopen an exact role run after a typed HTTP 429.",
16440
+ usage: ["ak-role resume <runId>"],
16441
+ examples: ["ak-role resume 01abc\u2026"]
16442
+ }
16443
+ };
16444
+ PUBLIC_COMMAND_HELP = {
16445
+ top: TOP_LEVEL_HELP,
16446
+ ...ROLE_COMMAND_HELP,
16447
+ ...SUPPORT_COMMAND_HELP
16448
+ };
16320
16449
  }
16321
16450
  });
16322
16451
 
@@ -27130,13 +27259,29 @@ function helpDocumentForCommand(command) {
27130
27259
  }
27131
27260
  return void 0;
27132
27261
  }
27262
+ function appendUsageAndExamples(lines, topic) {
27263
+ const facts = projectCommandHelp(topic);
27264
+ if (facts === void 0) return;
27265
+ lines.push("", "USAGE");
27266
+ for (const line2 of facts.usage) {
27267
+ lines.push(` ${line2}`);
27268
+ }
27269
+ if (facts.examples.length > 0) {
27270
+ lines.push("", "EXAMPLES");
27271
+ for (const example of facts.examples) {
27272
+ lines.push(` ${example}`);
27273
+ }
27274
+ }
27275
+ }
27133
27276
  function renderHelp() {
27134
27277
  const doc = helpDocument();
27278
+ const top = projectCommandHelp("top");
27135
27279
  const lines = [
27136
- "ak-role \u2014 public role CLI",
27137
- "",
27138
- "Support commands:"
27280
+ `ak-role \u2014 ${top?.summary ?? "public role CLI"}`
27139
27281
  ];
27282
+ appendUsageAndExamples(lines, "top");
27283
+ lines.push("", PUBLIC_NAVIGATOR_HELP_NOTE);
27284
+ lines.push("", "Support commands:");
27140
27285
  for (const cap of doc.capabilities) {
27141
27286
  if (cap.kind === "support") {
27142
27287
  lines.push(` ${cap.name}`);
@@ -27155,8 +27300,8 @@ function renderHelp() {
27155
27300
  lines.push(` ${cap.name}`);
27156
27301
  }
27157
27302
  }
27158
- lines.push("", "Global options:");
27159
- lines.push(...renderOwnerOptionHelpLines("global"));
27303
+ lines.push("", "OPTIONS");
27304
+ lines.push(...renderHumanOwnerOptionLines("global"));
27160
27305
  lines.push(
27161
27306
  "",
27162
27307
  "Role options: ak-role help <command>",
@@ -27171,22 +27316,22 @@ function renderCommandHelp(command) {
27171
27316
  const caps = listHelpCapabilities();
27172
27317
  const match = caps.find((cap) => cap.name === command);
27173
27318
  if (match === void 0) return void 0;
27319
+ const facts = projectCommandHelp(command);
27174
27320
  const lines = [];
27175
- if (match.kind === "support") {
27176
- lines.push(`command ${match.name} kind support`);
27321
+ if (facts !== void 0) {
27322
+ lines.push(`ak-role ${facts.command} \u2014 ${facts.summary}`);
27323
+ } else if (match.kind === "support") {
27324
+ lines.push(`ak-role ${match.name}`);
27177
27325
  } else if (match.kind === "deterministic") {
27178
- lines.push(`command ${match.name} kind deterministic`);
27326
+ lines.push(`ak-role ${match.name}`);
27179
27327
  } else {
27180
- lines.push(
27181
- `command ${match.name} kind role phases ${match.phases.map((p) => p === null ? "none" : p).join(",")} default ${match.defaultPhase ?? "none"}`
27182
- );
27328
+ lines.push(`ak-role ${match.name}`);
27183
27329
  }
27184
- if (command in PUBLIC_ROLE_ARGV) {
27185
- lines.push(
27186
- ...renderOwnerOptionHelpLines(
27187
- command
27188
- )
27189
- );
27330
+ appendUsageAndExamples(lines, command);
27331
+ if (command in PUBLIC_ROLE_ARGV || command === "global") {
27332
+ const owner = command === "global" ? "global" : command;
27333
+ lines.push("", "OPTIONS");
27334
+ lines.push(...renderHumanOwnerOptionLines(owner));
27190
27335
  }
27191
27336
  return `${lines.join("\n")}
27192
27337
  `;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@akagilnc/pi-workflow-roles",
3
- "version": "0.1.2114",
3
+ "version": "0.1.2118",
4
4
  "description": "Soul-bound workflow roles for Pi",
5
5
  "type": "module",
6
6
  "license": "Apache-2.0",
@@ -43,8 +43,10 @@ import {
43
43
  import {
44
44
  createTypedOptionConsumer,
45
45
  optionsForOwner,
46
+ projectCommandHelp,
46
47
  projectOwnerOptions,
47
- renderOwnerOptionHelpLines,
48
+ PUBLIC_NAVIGATOR_HELP_NOTE,
49
+ renderHumanOwnerOptionLines,
48
50
  type PublicOptionDefinition,
49
51
  type TypedOptionConsumer,
50
52
  } from "./option-definitions.ts";
@@ -412,13 +414,34 @@ export function helpDocumentForCommand(command: string) {
412
414
  return undefined;
413
415
  }
414
416
 
417
+ /** Append USAGE + EXAMPLES blocks from the sole public help-copy owner. */
418
+ function appendUsageAndExamples(
419
+ lines: string[],
420
+ topic: string,
421
+ ): void {
422
+ const facts = projectCommandHelp(topic);
423
+ if (facts === undefined) return;
424
+ lines.push("", "USAGE");
425
+ for (const line of facts.usage) {
426
+ lines.push(` ${line}`);
427
+ }
428
+ if (facts.examples.length > 0) {
429
+ lines.push("", "EXAMPLES");
430
+ for (const example of facts.examples) {
431
+ lines.push(` ${example}`);
432
+ }
433
+ }
434
+ }
435
+
415
436
  function renderHelp(): string {
416
437
  const doc = helpDocument();
438
+ const top = projectCommandHelp("top");
417
439
  const lines: string[] = [
418
- "ak-role — public role CLI",
419
- "",
420
- "Support commands:",
440
+ `ak-role — ${top?.summary ?? "public role CLI"}`,
421
441
  ];
442
+ appendUsageAndExamples(lines, "top");
443
+ lines.push("", PUBLIC_NAVIGATOR_HELP_NOTE);
444
+ lines.push("", "Support commands:");
422
445
  for (const cap of doc.capabilities) {
423
446
  if (cap.kind === "support") {
424
447
  lines.push(` ${cap.name}`);
@@ -441,8 +464,8 @@ function renderHelp(): string {
441
464
  lines.push(` ${cap.name}`);
442
465
  }
443
466
  }
444
- lines.push("", "Global options:");
445
- lines.push(...renderOwnerOptionHelpLines("global"));
467
+ lines.push("", "OPTIONS");
468
+ lines.push(...renderHumanOwnerOptionLines("global"));
446
469
  lines.push(
447
470
  "",
448
471
  "Role options: ak-role help <command>",
@@ -457,24 +480,25 @@ function renderCommandHelp(command: string): string | undefined {
457
480
  const caps = listHelpCapabilities();
458
481
  const match = caps.find((cap) => cap.name === command);
459
482
  if (match === undefined) return undefined;
483
+ const facts = projectCommandHelp(command);
460
484
  const lines: string[] = [];
461
- if (match.kind === "support") {
462
- lines.push(`command\t${match.name}\tkind\tsupport`);
485
+ if (facts !== undefined) {
486
+ lines.push(`ak-role ${facts.command} — ${facts.summary}`);
487
+ } else if (match.kind === "support") {
488
+ lines.push(`ak-role ${match.name}`);
463
489
  } else if (match.kind === "deterministic") {
464
- lines.push(`command\t${match.name}\tkind\tdeterministic`);
490
+ lines.push(`ak-role ${match.name}`);
465
491
  } else {
466
- lines.push(
467
- `command\t${match.name}\tkind\trole\tphases\t${match.phases
468
- .map((p) => (p === null ? "none" : p))
469
- .join(",")}\tdefault\t${match.defaultPhase ?? "none"}`,
470
- );
492
+ lines.push(`ak-role ${match.name}`);
471
493
  }
472
- if (command in PUBLIC_ROLE_ARGV) {
473
- lines.push(
474
- ...renderOwnerOptionHelpLines(
475
- command as keyof typeof PUBLIC_ROLE_ARGV,
476
- ),
477
- );
494
+ appendUsageAndExamples(lines, command);
495
+ if (command in PUBLIC_ROLE_ARGV || command === "global") {
496
+ const owner =
497
+ command === "global"
498
+ ? "global"
499
+ : (command as keyof typeof PUBLIC_ROLE_ARGV);
500
+ lines.push("", "OPTIONS");
501
+ lines.push(...renderHumanOwnerOptionLines(owner));
478
502
  }
479
503
  return `${lines.join("\n")}\n`;
480
504
  }
@@ -998,57 +998,214 @@ export function allRejectedSpellingTokens(): readonly string[] {
998
998
  }
999
999
 
1000
1000
  /**
1001
- * Render one owner’s options as stable TSV lines for help.
1002
- * Layout is presentation; identity columns are the structured contract.
1001
+ * #125 public command help facts on the sole option-owner module.
1002
+ * Presentation inputs only (USAGE synopsis + public `ak-role` examples).
1003
+ * Option identity/requiredness remain on PUBLIC_OPTION_TABLE rows.
1004
+ * Free text is not a test contract (机器只咬契约,不咬呈现).
1003
1005
  */
1004
- export function renderOwnerOptionHelpLines(
1006
+ export type PublicCommandHelpFacts = {
1007
+ /** Command / topic id (role owner, support command, or "top"). */
1008
+ readonly command: string;
1009
+ /** One-line what-it-does (presentation). */
1010
+ readonly summary: string;
1011
+ /** USAGE synopsis line(s), each a full public `ak-role …` sketch. */
1012
+ readonly usage: readonly string[];
1013
+ /** 1–2 public invocation examples using only public spellings. */
1014
+ readonly examples: readonly string[];
1015
+ };
1016
+
1017
+ /**
1018
+ * Top-level public help short note for automatic Navigator attendance.
1019
+ * Not a caller command; configure via `ak-role config set navigator …`.
1020
+ */
1021
+ export const PUBLIC_NAVIGATOR_HELP_NOTE =
1022
+ "Navigator attends automatically on every run; configure with `ak-role config set navigator <provider/model[:thinking]>` (not a caller command)." as const;
1023
+
1024
+ const TOP_LEVEL_HELP = {
1025
+ command: "top",
1026
+ summary: "public role CLI",
1027
+ usage: [
1028
+ "ak-role <command> [options]",
1029
+ "ak-role help <command>",
1030
+ ],
1031
+ examples: [
1032
+ 'ak-role judge --attach ./plan.md "Review this plan."',
1033
+ 'ak-role coder plan "Propose the first implementation plan."',
1034
+ ],
1035
+ } as const satisfies PublicCommandHelpFacts;
1036
+
1037
+ const ROLE_COMMAND_HELP = {
1038
+ judge: {
1039
+ command: "judge",
1040
+ summary: "Adjudicate the supplied materials; infers its own burden.",
1041
+ usage: ["ak-role judge [options] [instruction]"],
1042
+ examples: [
1043
+ 'ak-role judge --attach ./plan.md "Review this plan."',
1044
+ 'ak-role judge --attach ./findings.md --attach ./adr.md "Adjudicate every finding."',
1045
+ ],
1046
+ },
1047
+ coder: {
1048
+ command: "coder",
1049
+ summary: "First implementation; phase defaults to apply.",
1050
+ usage: ["ak-role coder [plan|apply] [options] <instruction>"],
1051
+ examples: [
1052
+ 'ak-role coder plan "Propose the first implementation plan."',
1053
+ 'ak-role coder apply --attach ./plan.md "Implement the approved slice."',
1054
+ ],
1055
+ },
1056
+ fixer: {
1057
+ command: "fixer",
1058
+ summary: "Repair the assigned findings; phase defaults to apply.",
1059
+ usage: ["ak-role fixer [plan|apply] [options] <instruction>"],
1060
+ examples: [
1061
+ 'ak-role fixer --attach ./findings.md --prerequisites ./prereqs.json "Repair the findings."',
1062
+ 'ak-role fixer plan --attach ./findings.md "Propose the repair plan."',
1063
+ ],
1064
+ },
1065
+ reviewer: {
1066
+ command: "reviewer",
1067
+ summary: "Fixed-target two-axis review (Standards + Spec).",
1068
+ usage: ["ak-role reviewer --base <revision> [options] <instruction>"],
1069
+ examples: [
1070
+ 'ak-role reviewer --base main "Review the branch against the governing issue and repository authority."',
1071
+ ],
1072
+ },
1073
+ collector: {
1074
+ command: "collector",
1075
+ summary: "Collect GitHub PR review evidence (one-shot).",
1076
+ usage: ["ak-role collector --pr <number> [options] [instruction]"],
1077
+ examples: [
1078
+ "ak-role collector --pr 42 --repo owner/repository",
1079
+ "ak-role collector --pr 42 --request-manifest ./requests.json",
1080
+ ],
1081
+ },
1082
+ doctor: {
1083
+ command: "doctor",
1084
+ summary: "Diagnose one retained case (one-shot).",
1085
+ usage: ["ak-role doctor --issue <number> [options] [instruction]"],
1086
+ examples: [
1087
+ 'ak-role doctor --issue 115 "Diagnose this retained case."',
1088
+ ],
1089
+ },
1090
+ merger: {
1091
+ command: "merger",
1092
+ summary: "Resolve one ordinary merge already in conflict.",
1093
+ usage: ["ak-role merger [options] <instruction>"],
1094
+ examples: [
1095
+ 'ak-role merger --project /path/to/worktree "Reconcile the active merge."',
1096
+ ],
1097
+ },
1098
+ taishi: {
1099
+ command: "taishi",
1100
+ summary: "Deterministic analysis seat (issue / sweep / cohort / model-groups).",
1101
+ usage: [
1102
+ "ak-role taishi (--ticket <N> | --project-root <P>) [options]",
1103
+ "ak-role taishi [sweep] --attach <path>",
1104
+ "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
+ ],
1107
+ examples: [
1108
+ "ak-role taishi --ticket 125",
1109
+ "ak-role taishi sweep --attach ./sweep.json",
1110
+ ],
1111
+ },
1112
+ } as const satisfies Record<PublicRoleOptionOwner, PublicCommandHelpFacts>;
1113
+
1114
+ const SUPPORT_COMMAND_HELP = {
1115
+ roles: {
1116
+ command: "roles",
1117
+ summary: "List effective seats and models.",
1118
+ usage: ["ak-role roles"],
1119
+ examples: ["ak-role roles"],
1120
+ },
1121
+ config: {
1122
+ command: "config",
1123
+ summary: "Persistent seat model and labor-engine defaults.",
1124
+ usage: [
1125
+ "ak-role config set <seat> <provider/model[:thinking]> [<seat> <spec> ...]",
1126
+ "ak-role config set-engine <seat> <name>",
1127
+ "ak-role config unset-engine <seat>",
1128
+ ],
1129
+ examples: [
1130
+ "ak-role config set judge openai-codex/gpt-5.6-sol:high",
1131
+ "ak-role config set-engine judge opus",
1132
+ ],
1133
+ },
1134
+ help: {
1135
+ command: "help",
1136
+ summary: "Show public CLI help.",
1137
+ usage: ["ak-role help [command]", "ak-role --help"],
1138
+ examples: ["ak-role help coder", "ak-role help judge"],
1139
+ },
1140
+ resume: {
1141
+ command: "resume",
1142
+ summary: "Reopen an exact role run after a typed HTTP 429.",
1143
+ usage: ["ak-role resume <runId>"],
1144
+ examples: ["ak-role resume 01abc…"],
1145
+ },
1146
+ } as const satisfies Record<string, PublicCommandHelpFacts>;
1147
+
1148
+ /**
1149
+ * Sole public help-copy owner keyed by command/topic id.
1150
+ * Role topics share identity with PUBLIC_ROLE_OPTION_OWNERS; options still
1151
+ * project from PUBLIC_OPTION_TABLE. Support topics cover non-option commands.
1152
+ */
1153
+ export const PUBLIC_COMMAND_HELP = {
1154
+ top: TOP_LEVEL_HELP,
1155
+ ...ROLE_COMMAND_HELP,
1156
+ ...SUPPORT_COMMAND_HELP,
1157
+ } as const;
1158
+
1159
+ export type PublicCommandHelpTopic = keyof typeof PUBLIC_COMMAND_HELP;
1160
+
1161
+ /** Structured projector — identity + presence; free text is presentation. */
1162
+ export function projectCommandHelp(
1163
+ topic: string,
1164
+ ): PublicCommandHelpFacts | undefined {
1165
+ if (!(topic in PUBLIC_COMMAND_HELP)) return undefined;
1166
+ const facts = PUBLIC_COMMAND_HELP[topic as PublicCommandHelpTopic];
1167
+ return {
1168
+ command: facts.command,
1169
+ summary: facts.summary,
1170
+ usage: [...facts.usage],
1171
+ examples: [...facts.examples],
1172
+ };
1173
+ }
1174
+
1175
+ /**
1176
+ * Human OPTIONS lines from the sole option table.
1177
+ * Layout is presentation; structured identity stays on projectOwnerOptions.
1178
+ */
1179
+ export function renderHumanOwnerOptionLines(
1005
1180
  owner: OptionOwner,
1006
1181
  locale: "en" | "zh" = "en",
1007
1182
  ): string[] {
1008
1183
  const lines: string[] = [];
1009
1184
  for (const opt of projectOwnerOptions(owner)) {
1010
- const aliasText =
1011
- opt.aliases.length === 0 ? "-" : opt.aliases.join(",");
1012
- const metavar = opt.valueMetavar ?? "-";
1013
- const required = opt.required ? "required" : "optional";
1014
- const repeatable = opt.repeatable ? "repeatable" : "single";
1015
- const form = opt.form;
1016
- const phases =
1017
- opt.phases === undefined ? "-" : opt.phases.join("|");
1018
- const modes = opt.modes === undefined ? "-" : opt.modes.join("|");
1019
- const requiredInModes =
1020
- opt.requiredInModes === undefined
1021
- ? "-"
1022
- : opt.requiredInModes.join("|");
1023
- const exclusiveWith =
1024
- opt.exclusiveWith === undefined ? "-" : opt.exclusiveWith.join("|");
1025
- const maxCount =
1026
- opt.maxCountByMode === undefined
1027
- ? "-"
1028
- : Object.entries(opt.maxCountByMode)
1029
- .map(([mode, n]) => `${mode}:${n}`)
1030
- .join(",");
1031
- const defaultValue = opt.defaultValue ?? "-";
1185
+ let spelling = opt.canonical;
1186
+ if (opt.valueMetavar !== null) {
1187
+ spelling = `${spelling} <${opt.valueMetavar}>`;
1188
+ }
1189
+ if (opt.aliases.length > 0) {
1190
+ // Prefer single-token aliases in the spelling hint (plan/apply, -h).
1191
+ const aliasHint = opt.aliases.join(", ");
1192
+ if (opt.form === "positional") {
1193
+ spelling = opt.aliases.length > 0 ? opt.aliases.join("|") : spelling;
1194
+ } else {
1195
+ spelling = `${spelling} (${aliasHint})`;
1196
+ }
1197
+ }
1198
+ const tags: string[] = [];
1199
+ if (opt.required) tags.push("required");
1200
+ if (opt.requiredInModes !== undefined) {
1201
+ tags.push(`required:${opt.requiredInModes.join("|")}`);
1202
+ }
1203
+ if (opt.repeatable) tags.push("repeatable");
1204
+ if (opt.defaultValue !== undefined) tags.push(`default=${opt.defaultValue}`);
1205
+ if (opt.form === "positional") tags.push("positional");
1206
+ const tagText = tags.length === 0 ? "" : ` [${tags.join(", ")}]`;
1032
1207
  const desc = locale === "zh" ? opt.description.zh : opt.description.en;
1033
- lines.push(
1034
- [
1035
- "option",
1036
- opt.id,
1037
- opt.canonical,
1038
- `aliases=${aliasText}`,
1039
- `metavar=${metavar}`,
1040
- required,
1041
- repeatable,
1042
- `form=${form}`,
1043
- `phases=${phases}`,
1044
- `modes=${modes}`,
1045
- `requiredInModes=${requiredInModes}`,
1046
- `exclusiveWith=${exclusiveWith}`,
1047
- `maxCountByMode=${maxCount}`,
1048
- `default=${defaultValue}`,
1049
- desc,
1050
- ].join("\t"),
1051
- );
1208
+ lines.push(` ${spelling}${tagText} ${desc}`);
1052
1209
  }
1053
1210
  return lines;
1054
1211
  }