@akagilnc/pi-workflow-roles 0.1.2336 → 0.1.2348
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 +32 -8
- package/README.zh-CN.md +43 -15
- package/dist/public-cli/main.js +57 -104
- package/package.json +1 -1
- package/src/factory-board.ts +2 -2
- package/src/public-cli/cli.ts +38 -11
- package/src/public-cli/coder-run.ts +7 -20
- package/src/public-cli/fixer-run.ts +7 -20
- package/src/public-cli/judge-run.ts +7 -21
- package/src/public-cli/merger-run.ts +7 -20
- package/src/public-cli/option-definitions.ts +5 -2
- package/src/public-cli/reviewer-run.ts +7 -20
- package/src/public-cli/run-lifecycle.ts +16 -0
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# @akagilnc/pi-workflow-roles
|
|
2
2
|
|
|
3
|
-
Packaged workflow roles for [Pi](https://pi.dev): `judge`, `fixer`, `coder`, `reviewer`, `collector`, `doctor`, `merger`. 中文说明见 [README.zh-CN.md](https://github.com/Akagilnc/ak-pi-workflow-roles/blob/main/README.zh-CN.md)。
|
|
3
|
+
Packaged workflow roles for [Pi](https://pi.dev): `judge`, `fixer`, `coder`, `reviewer`, `collector`, `doctor`, `merger`, `notary`, `analyst`. 中文说明见 [README.zh-CN.md](https://github.com/Akagilnc/ak-pi-workflow-roles/blob/main/README.zh-CN.md)。
|
|
4
4
|
|
|
5
5
|
## Install
|
|
6
6
|
|
|
@@ -11,7 +11,7 @@ pi install npm:@akagilnc/pi-workflow-roles
|
|
|
11
11
|
export PATH="$HOME/.pi/agent/npm/node_modules/.bin:$PATH"
|
|
12
12
|
```
|
|
13
13
|
|
|
14
|
-
Update with `pi update npm:@akagilnc/pi-workflow-roles`—never a second global `npm install -g`. Inspect with `ak-role roles` and `ak-role help <role>`; set per-seat model defaults with `ak-role config set
|
|
14
|
+
Update with `pi update npm:@akagilnc/pi-workflow-roles`—never a second global `npm install -g`. Inspect with `ak-role roles` and `ak-role help <role>`; set per-seat model defaults with `ak-role config set <seat> <provider/model[:thinking]>` (callable seats plus automatic `gatekeeper` / `inspector` / `navigator`); clear a Menxia officer override with `ak-role config unset <gatekeeper|inspector|notary>`; set or clear a persistent labor engine (callable roles) with `ak-role config set-engine <seat> <name>` / `ak-role config unset-engine <seat>`.
|
|
15
15
|
|
|
16
16
|
## Reading results
|
|
17
17
|
|
|
@@ -23,31 +23,41 @@ ak-role judge --attach ./plan.md "Review this plan." > result.txt
|
|
|
23
23
|
|
|
24
24
|
Exit status reports lifecycle honesty, not business success: every lawful typed result (including `audit_escalation`) exits zero; a failure without a lawful result exits nonzero, and its Terminal carries the Error Artifact ref and original cause instead of a fabricated receipt.
|
|
25
25
|
|
|
26
|
-
`ak-role resume <runId
|
|
26
|
+
`ak-role resume <runId> [message]` reopens that run's exact Pi session. Standard chain after a role `escalate`s: take the owner ruling and feed it back with `ak-role resume <runId> "<ruling>"` so the same session continues to a terminal. The optional `message` after `runId` is passed through unchanged as the continuation prompt (opaque: not parsed as flags); omit it to use the package resume envelope. Whether to resume is the caller's decision: the command does not require a typed HTTP 429 or a `resumable` state. Unknown run IDs and missing session principals are rejected. Collector, Doctor, and Notary remain one-shot. The package never auto-switches providers; override the model for one run with the global flags.
|
|
27
27
|
|
|
28
28
|
Judge, coder, fixer, reviewer, and merger also retry a non-lawful LLM call in place (same `runId` and session) up to `autoResumeLimit` times. Unset defaults to 2; `ak-role config set-auto-resume-limit <N>` writes the ceiling (`0` disables). Lawful typed terminals (`accepted`, `audit_escalation`, `no_receipt`) stop immediately. Manual `ak-role resume` stays available.
|
|
29
29
|
|
|
30
|
-
Global overrides work before
|
|
30
|
+
Global overrides work before the opaque message segment: `ak-role --model <provider/model[:thinking]> resume <runId>` or `ak-role resume --model <provider/model[:thinking]> <runId>`.
|
|
31
31
|
|
|
32
|
-
Every run also prepares Navigator advice in the same Terminal. Configure
|
|
32
|
+
Every run also prepares Navigator advice in the same Terminal. Configure seats like this:
|
|
33
33
|
|
|
34
34
|
```bash
|
|
35
|
-
ak-role config set
|
|
35
|
+
ak-role config set judge <provider/model[:thinking]>
|
|
36
|
+
ak-role config set navigator <provider/model[:thinking]>
|
|
37
|
+
# Menxia officers (automatic on submission; not caller commands except direct notary)
|
|
38
|
+
ak-role config set gatekeeper <provider/model[:thinking]>
|
|
39
|
+
ak-role config set inspector <provider/model[:thinking]>
|
|
40
|
+
ak-role config set notary <provider/model[:thinking]>
|
|
41
|
+
ak-role config unset gatekeeper
|
|
36
42
|
# persistent labor engine (callable roles; not navigator); one-shot override remains --engine
|
|
37
43
|
ak-role config set-engine judge opus
|
|
38
44
|
ak-role config unset-engine judge
|
|
39
45
|
ak-role config set-auto-resume-limit 3
|
|
40
46
|
```
|
|
41
47
|
|
|
42
|
-
`config set` stores the seat model default; `config set-engine` / `unset-engine` store or clear the persistent labor-engine name on callable roles (same seats as `--engine`; navigator refused — no independent activation). `config set-auto-resume-limit` stores the single-call auto-resume ceiling. Usage and refusal text are owned by `ak-role config`
|
|
48
|
+
`config set` stores the seat model default. For Menxia officers (`gatekeeper` / `inspector` / `notary`) resolution is officer pin → province (`gatekeeper`) pin → inherit parent session; an explicit selection that fails is loud and does not fall back. `config unset` clears only those officer overrides. `config set-engine` / `unset-engine` store or clear the persistent labor-engine name on callable roles (same seats as `--engine`; navigator refused — no independent activation). `config set-auto-resume-limit` stores the single-call auto-resume ceiling. Usage and refusal text are owned by `ak-role config` / `ak-role help config`.
|
|
43
49
|
|
|
44
50
|
Receipts are typed, so callers compose roles without parsing prose; ordering and stopping stay caller-owned. Programmatic consumers derive contracts from the exported schemas in `src/package-contracts/`, not from this guide.
|
|
45
51
|
|
|
52
|
+
### Menxia submission gate
|
|
53
|
+
|
|
54
|
+
On completing-side submissions the package may spawn the Menxia province before the run settles: `gatekeeper` reads the subject and dispatches an officer (`inspector` or `notary`); existing auditor hooks stay where already wired. The gate runs inside the submission session; bounce means rewrite-and-resubmit in that same session — not role failure; the final receipt is the post-gate product. `planned` / `refused` / `unfinished` skip the province. Pointers only: [ADR 0067](docs/adr/0067-menxia-province-founding-jishizhong-fubaolang.md), [ADR 0072](docs/adr/0072-menxia-pre-pr-submission-hooks.md). Do not scrape session prose for gate status.
|
|
55
|
+
|
|
46
56
|
When a labor-engine detour fails and the seat continues the labor on the main road, the typed receipt may carry a mechanical `engineLaborFallback` field: `{ engine, failure, laborBy: "seat" }`. It appears only after a real detour failure that fell back to seat labor—not on detour success or caller cancel. First failure wins for the activation; model-forged `engineLaborFallback` keys are stripped unless the package latch recorded one. Sole producer: `src/engine-labor-fallback.ts`; decision record: [ADR 0071](docs/adr/0071-engine-detour-failure-seat-fallback-declaration.md). This README only projects that contract.
|
|
47
57
|
|
|
48
58
|
## Call the roles
|
|
49
59
|
|
|
50
|
-
Public option identity, aliases, requiredness, and mode faces live in the generated [Public CLI options](#public-cli-options-generated) table and in `ak-role help <command>` — both project the same typed source. The examples below are usage sketches, not a second flag contract. An instruction is optional for judge, collector, and doctor
|
|
60
|
+
Public option identity, aliases, requiredness, and mode faces live in the generated [Public CLI options](#public-cli-options-generated) table and in `ak-role help <command>` — both project the same typed source. The examples below are usage sketches, not a second flag contract. An instruction is optional for judge, collector, and doctor; notary admits no caller prompt or attachment; analyst is deterministic (see help). Required nonblank for coder, fixer, reviewer, and merger.
|
|
51
61
|
|
|
52
62
|
```bash
|
|
53
63
|
# judge — adjudicate the supplied materials; infers its burden, no burden flag
|
|
@@ -79,6 +89,20 @@ ak-role doctor --issue 115 "Diagnose this retained case."
|
|
|
79
89
|
# merger — resolve one merge already in conflict (start it first with Git’s ort)
|
|
80
90
|
ak-role merger --project /path/to/worktree "Reconcile the active merge."
|
|
81
91
|
# hands new intent/authority questions back instead of inventing authority
|
|
92
|
+
|
|
93
|
+
# notary — document-fidelity check on one retained source run; zero prompt/attachment; one-shot
|
|
94
|
+
ak-role notary --source-run <runId@role|path>
|
|
95
|
+
|
|
96
|
+
# analyst — deterministic metrics over the book (cwd git common-dir); bare = whole book
|
|
97
|
+
ak-role analyst
|
|
98
|
+
ak-role analyst --ticket <N>
|
|
99
|
+
ak-role analyst sweep --attach ./payload.md
|
|
100
|
+
ak-role analyst --cohort \
|
|
101
|
+
--group-a-label A --group-a-issues 1,2 \
|
|
102
|
+
--group-b-label B --group-b-issues 3,4
|
|
103
|
+
|
|
104
|
+
# after escalate: feed the owner ruling into the same session (standard chain; see resume under Reading results)
|
|
105
|
+
ak-role resume <runId> "<ruling>"
|
|
82
106
|
```
|
|
83
107
|
|
|
84
108
|
## Names
|
package/README.zh-CN.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# @akagilnc/pi-workflow-roles
|
|
2
2
|
|
|
3
|
-
为 [Pi](https://pi.dev) 打包的工作流角色:大理寺(judge)、修内司(fixer)、将作监(coder)、御史台(reviewer
|
|
3
|
+
为 [Pi](https://pi.dev) 打包的工作流角色:大理寺(judge)、修内司(fixer)、将作监(coder)、御史台(reviewer)、通进司(collector)、太医署(doctor)、校书郎(merger)、符宝郎(notary)、太史(analyst)。English: [README.md](https://github.com/Akagilnc/ak-pi-workflow-roles/blob/main/README.md)。
|
|
4
4
|
|
|
5
5
|
## 安装
|
|
6
6
|
|
|
@@ -11,7 +11,7 @@ pi install npm:@akagilnc/pi-workflow-roles
|
|
|
11
11
|
export PATH="$HOME/.pi/agent/npm/node_modules/.bin:$PATH"
|
|
12
12
|
```
|
|
13
13
|
|
|
14
|
-
更新用 `pi update npm:@akagilnc/pi-workflow-roles`——勿另起全局 `npm install -g`。查看能力:`ak-role roles`、`ak-role help <role>`;设席位模型默认:`ak-role config set
|
|
14
|
+
更新用 `pi update npm:@akagilnc/pi-workflow-roles`——勿另起全局 `npm install -g`。查看能力:`ak-role roles`、`ak-role help <role>`;设席位模型默认:`ak-role config set <seat> <provider/model[:thinking]>`(可调用席位,以及自动出席的 `gatekeeper`/`inspector`/`navigator`);清除门下省官钉:`ak-role config unset <gatekeeper|inspector|notary>`;设或清持久劳务引擎(可调用角色):`ak-role config set-engine <seat> <name>` / `ak-role config unset-engine <seat>`。
|
|
15
15
|
|
|
16
16
|
## 读结果
|
|
17
17
|
|
|
@@ -23,31 +23,41 @@ ak-role judge --attach ./plan.md "Review this plan." > result.txt
|
|
|
23
23
|
|
|
24
24
|
退出码报的是生命周期诚实,不是业务成败:一切合法 typed 终态(含 `audit_escalation`)退出零;无合法终态的失败退出非零,其 Terminal 携带 Error Artifact 引用与原始原因,不伪造回执。
|
|
25
25
|
|
|
26
|
-
`ak-role resume <runId
|
|
26
|
+
`ak-role resume <runId> [message]` 重开该次运行的同一 Pi session。角色 `escalate`(直通御前)后拿到 owner 裁定,标准续跑是 `ak-role resume <runId> "<裁定>"`——把裁定喂回同一 session,角色继续走到终局。`runId` 后可选的 `message` 原样作为续跑 prompt(opaque:不进全局旗标语法);省略则用包自带 resume envelope。要不要续跑由调用者决定:不再要求 typed HTTP 429,也不要求 `resumable` 状态。未知 run ID、session 主体不在则拒绝。通进司、太医署、符宝郎仍为一次性,无 resume。包绝不自动换 provider;临时换模型用全局旗标。
|
|
27
27
|
|
|
28
28
|
大理寺、将作监、修内司、御史台、校书郎在单次调用内对非 lawful LLM 终态原地续跑(同一 `runId` 与 session),次数上限为 `autoResumeLimit`。缺键默认 2;`ak-role config set-auto-resume-limit <N>` 写入(`0` 关闭自动续)。lawful typed 终态(`accepted` / `audit_escalation` / `no_receipt`)立即停止。手动 `ak-role resume` 仍可用。
|
|
29
29
|
|
|
30
|
-
|
|
30
|
+
全局覆盖须在 opaque message 段之前:`ak-role --model <provider/model[:thinking]> resume <runId>` 或 `ak-role resume --model <provider/model[:thinking]> <runId>`。
|
|
31
31
|
|
|
32
32
|
每次运行游奕使自动出席,建议随同一 Terminal 给出。配置:
|
|
33
33
|
|
|
34
34
|
```bash
|
|
35
|
-
ak-role config set
|
|
35
|
+
ak-role config set judge <provider/model[:thinking]>
|
|
36
|
+
ak-role config set navigator <provider/model[:thinking]>
|
|
37
|
+
# 门下省官席(交卷自动出席;除直调符宝郎外无独立命令)
|
|
38
|
+
ak-role config set gatekeeper <provider/model[:thinking]>
|
|
39
|
+
ak-role config set inspector <provider/model[:thinking]>
|
|
40
|
+
ak-role config set notary <provider/model[:thinking]>
|
|
41
|
+
ak-role config unset gatekeeper
|
|
36
42
|
# 持久劳务引擎(可调用角色;不含 navigator);一次性覆盖仍用 --engine
|
|
37
43
|
ak-role config set-engine judge opus
|
|
38
44
|
ak-role config unset-engine judge
|
|
39
45
|
ak-role config set-auto-resume-limit 3
|
|
40
46
|
```
|
|
41
47
|
|
|
42
|
-
`config set`
|
|
48
|
+
`config set` 存席位模型默认。门下省官席(`gatekeeper`/`inspector`/`notary`)解析顺序:官自钉 → 省钉(`gatekeeper`)→ 继承父 session;显式指定失败响亮、不回退。`config unset` 只清这三官的覆盖。`config set-engine`/`unset-engine` 在可调用角色上写入或清除持久劳务引擎名(与 `--engine` 同轴;拒收 navigator——无独立 activation)。`config set-auto-resume-limit` 写入单次调用自动续跑上限。用法与拒绝文案以 `ak-role config`/`ak-role help config` 为准。
|
|
43
49
|
|
|
44
50
|
回执是 typed 的,调用者不必解析散文即可组合角色;顺序与停止归调用者。编程消费者从 `src/package-contracts/` 导出推导契约,不从本文。
|
|
45
51
|
|
|
52
|
+
### 门下省交卷闸
|
|
53
|
+
|
|
54
|
+
完成侧交卷时,包可能在本局结算前起门下省:`gatekeeper` 读受审物并派官(`inspector` 给事中或 `notary` 符宝郎);既有审刑院挂钩仍在原位。闸在交卷 session 内运行;封驳=当场重写重交,不是角色失败;最终回执即过闸产物。`planned`/`refused`/`unfinished` 不调省。指针:[ADR 0067](docs/adr/0067-menxia-province-founding-jishizhong-fubaolang.md)、[ADR 0072](docs/adr/0072-menxia-pre-pr-submission-hooks.md)。勿刮 session 散文当闸状态。
|
|
55
|
+
|
|
46
56
|
当劳务引擎绕行失败、座席回到主路继续劳务时,typed 回执可带机械字段 `engineLaborFallback`:`{ engine, failure, laborBy: "seat" }`。仅在真实绕行失败并座席顶班后出现——成功绕行或调用方 cancel 不出现。同一次 activation 内先到先得;无包内 latch 时剥离模型伪造的 `engineLaborFallback` 键。唯一构造点:`src/engine-labor-fallback.ts`;决策记录:[ADR 0071](docs/adr/0071-engine-detour-failure-seat-fallback-declaration.md)。本文只投影该契约。
|
|
47
57
|
|
|
48
58
|
## 调用百官
|
|
49
59
|
|
|
50
|
-
公开 option 身份、别名、必填性与 mode 面以生成区 [公开 CLI 选项(生成)](#公开-cli-选项生成) 与 `ak-role help <command>`
|
|
60
|
+
公开 option 身份、别名、必填性与 mode 面以生成区 [公开 CLI 选项(生成)](#公开-cli-选项生成) 与 `ak-role help <command>` 为准——二者同源。下例只是用法速写,不是第二份旗标合同。指令对大理寺、通进司、太医署可省略;符宝郎零 prompt/附件;太史为确定性命令(见 help)。对将作监、修内司、御史台、校书郎必须非空。
|
|
51
61
|
|
|
52
62
|
```bash
|
|
53
63
|
# 大理寺——审断所供材料;自行推断举证责任,无 burden 旗标
|
|
@@ -63,7 +73,7 @@ ak-role reviewer --base main "Review the branch."
|
|
|
63
73
|
# --base 为必填并钉住 fixed point;御史台不接受 --attach
|
|
64
74
|
# completed ≠ 准行——findings 在 Terminal 里
|
|
65
75
|
|
|
66
|
-
#
|
|
76
|
+
# 通进司——GitHub PR 收证;仅 github.com,需 gh 已认证;一次性
|
|
67
77
|
ak-role collector --pr 42 --repo owner/repository
|
|
68
78
|
ak-role collector --pr 42 --request-manifest ./requests.json
|
|
69
79
|
# 无配置时仅观察;可选 request manifest 为 {requests:[{id,body}]};repo 默认取 origin
|
|
@@ -79,6 +89,20 @@ ak-role doctor --issue 115 "Diagnose this retained case."
|
|
|
79
89
|
# 校书郎——雠校一个已在冲突的 merge(先用 Git ort 起动)
|
|
80
90
|
ak-role merger --project /path/to/worktree "Reconcile the active merge."
|
|
81
91
|
# 遇新意图/权限问题交回调用者,不捏造 authority
|
|
92
|
+
|
|
93
|
+
# 符宝郎——对一份留存 source run 做文书核验;零 prompt/附件;一次性
|
|
94
|
+
ak-role notary --source-run <runId@role|path>
|
|
95
|
+
|
|
96
|
+
# 太史——确定性指标(cwd 候簿=git common-dir);裸调=整簿
|
|
97
|
+
ak-role analyst
|
|
98
|
+
ak-role analyst --ticket <N>
|
|
99
|
+
ak-role analyst sweep --attach ./payload.md
|
|
100
|
+
ak-role analyst --cohort \
|
|
101
|
+
--group-a-label A --group-a-issues 1,2 \
|
|
102
|
+
--group-b-label B --group-b-issues 3,4
|
|
103
|
+
|
|
104
|
+
# escalate 后:把 owner 裁定喂回同一 session(标准链;细则见上方「读结果」resume 段)
|
|
105
|
+
ak-role resume <runId> "<裁定>"
|
|
82
106
|
```
|
|
83
107
|
|
|
84
108
|
## 班子(唐宋官署命名)
|
|
@@ -93,8 +117,11 @@ ak-role merger --project /path/to/worktree "Reconcile the active merge."
|
|
|
93
117
|
| **修内司** | fixer | **缮修旧物。** 面对已有问题,不急于表面修补,而是追寻问题根源,找到真正需要修整之处。既要修复眼前缺漏,也要防止同类问题再次出现。 |
|
|
94
118
|
| **御史台** | reviewer | **察举百弊。** 置身事外,以旁观之眼审视成果,寻找其中的不妥、遗漏与隐患。只负责指出问题、陈明依据,不参与修改,也不替人作最终判断。 |
|
|
95
119
|
| **大理寺** | judge | **审理定谳。** 承接各方意见与材料,依照既定规则逐项判断,辨明是非曲直。可以准行、退回或请示更高决定,但自身不参与建设与修改。 |
|
|
96
|
-
| **审刑院** | judge-auditor/reviewer-auditor(无 CLI,共享内部接缝) | **复核成案。**
|
|
97
|
-
| **门下省** |
|
|
120
|
+
| **审刑院** | judge-auditor/reviewer-auditor(无 CLI,共享内部接缝) | **复核成案。** 不重新争论事情本身,而是检查整个办理过程是否合乎规矩。关注是否有人越过职责、是否遗漏必要步骤、是否以错误方式得出正确结果。直属陛下,不入门下省编制。 |
|
|
121
|
+
| **门下省** | gatekeeper(无独立 CLI;交卷自动出席) | **质量保证省。** 交卷时判断受审物、够不够审、该谁审,派给事中或符宝郎;省内政,不是外层编排器。规范见 [ADR 0067](docs/adr/0067-menxia-province-founding-jishizhong-fubaolang.md)、[ADR 0072](docs/adr/0072-menxia-pre-pr-submission-hooks.md)。 |
|
|
122
|
+
| **给事中** | inspector(无独立 CLI;可由门下省派发) | **复杂度与测试质量两轴质检。** 受审物是将作监/修内司完成侧交卷;封驳=当场打回重写,不是本局失败。 |
|
|
123
|
+
| **符宝郎** | notary | **引语真伪与票面对齐。** 受审物是大理寺拟判等文书;可被门下省派发,也可 `ak-role notary` 单独调。 |
|
|
124
|
+
| **通进司** | collector | **承接百议/收证。** 门下省下的收证衙门:收集外部 GitHub PR 材料与意见,只收不审、不替人裁决。canonical 键仍为 `collector`。 |
|
|
98
125
|
| **校书郎** | merger | **雠校异文。** 面对不同来源的修改,负责整理、校合与调和。保留双方有价值的部分,解决彼此冲突;遇到无法自行决定之处,则留待重新裁量。 |
|
|
99
126
|
| **游奕使** | navigator(无 CLI,自动出席) | **巡行问路。** 不掌具体事务,而是观察全局变化,结合当前局面提醒下一步方向。它提供建议与路径参考,但最终选择仍由执掌之人决定。 |
|
|
100
127
|
|
|
@@ -103,14 +130,15 @@ ak-role merger --project /path/to/worktree "Reconcile the active merge."
|
|
|
103
130
|
| 席位 | 名 | 职掌 | 状态 |
|
|
104
131
|
| --- | --- | --- | --- |
|
|
105
132
|
| doctor | **太医署** | 单案诊断工厂机制,开 `keep|thin|delete` 方 | 已建 |
|
|
106
|
-
|
|
|
107
|
-
| — |
|
|
108
|
-
| — |
|
|
133
|
+
| analyst | **太史** | 司天台分析席:只读司天记录、出高阶指标;确定性机制,非 LLM,可单独调用 | 已建([ADR 0068](docs/adr/0068-taishi-analysis-seat-reads-records-writes-sibling-home.md);机器面键 `analyst`,[#445](https://github.com/Akagilnc/ak-pi-workflow-roles/issues/445) 拼音清零) |
|
|
134
|
+
| — | **司天台** | 记候簿——只打点、只指针,不分析不执法 | **一期不是角色**([ADR 0047](docs/adr/0047-sitian-phase-one-mechanism-not-role.md):零 LLM 双面对账);分析席已由太史承担;机器面键 `archivist`([#445](https://github.com/Akagilnc/ak-pi-workflow-roles/issues/445)) |
|
|
135
|
+
| — | **兰台** | 读档议制——耗时/缺口/冗余三条,上奏不执法 | 未建 |
|
|
136
|
+
| — | **考功司** | 考具体效率——角色与档位的升档率、一次通过率、每票成本 | 留档,需要时另立票 |
|
|
109
137
|
| — | **主簿** | 合并后勾稽销案:核实确已合上、清理残留、报到达 | 未建 |
|
|
110
138
|
|
|
111
|
-
**merge
|
|
139
|
+
**merge 按钮归调用者**,没有任何角色握不可逆权限:通进司把收证这件苦活做完并报收集终态,人(或 AI)自己判断、自己点,点完想调主簿就调、不调也可以。
|
|
112
140
|
|
|
113
|
-
上表**不规定调用顺序**——组合、顺序、重复次数归调用者([ADR 0010](docs/adr/0010-callers-own-role-composition-and-repetition.md)
|
|
141
|
+
上表**不规定调用顺序**——组合、顺序、重复次数归调用者([ADR 0010](docs/adr/0010-callers-own-role-composition-and-repetition.md))。御史台/大理寺/审刑院是**职责分立的类比,不是必经链**;审刑院也并非只跟在大理寺之后,大理寺、御史台、太医署各自都有一次。门下省交卷闸是完成侧挂钩,不是调用者必经编排链。
|
|
114
142
|
|
|
115
143
|
`拾遗补阙` 成对留档,待将来出现第二个进言席再启用。
|
|
116
144
|
|
package/dist/public-cli/main.js
CHANGED
|
@@ -15904,6 +15904,9 @@ var init_typed_provider_http = __esm({
|
|
|
15904
15904
|
// src/public-cli/run-lifecycle.ts
|
|
15905
15905
|
import { chmod, lstat, open, readdir as readdir2, readFile as readFile5, unlink as unlink2, writeFile as writeFile3 } from "node:fs/promises";
|
|
15906
15906
|
import { join as join7 } from "node:path";
|
|
15907
|
+
function selectResumeContinuationPrompt(message) {
|
|
15908
|
+
return message !== void 0 ? message : RESUME_TRANSPORT_ENVELOPE;
|
|
15909
|
+
}
|
|
15907
15910
|
function isV1ResumableProvider(provider) {
|
|
15908
15911
|
return V1_RESUMABLE_PROVIDERS.includes(provider);
|
|
15909
15912
|
}
|
|
@@ -17486,8 +17489,11 @@ var init_option_definitions = __esm({
|
|
|
17486
17489
|
resume: {
|
|
17487
17490
|
command: "resume",
|
|
17488
17491
|
summary: "Reopen an exact role run whose Pi session principal still exists.",
|
|
17489
|
-
usage: ["ak-role resume <runId>"],
|
|
17490
|
-
examples: [
|
|
17492
|
+
usage: ["ak-role resume <runId> [message]"],
|
|
17493
|
+
examples: [
|
|
17494
|
+
"ak-role resume 01abc\u2026",
|
|
17495
|
+
'ak-role resume 01abc\u2026 "owner ruling"'
|
|
17496
|
+
]
|
|
17491
17497
|
}
|
|
17492
17498
|
};
|
|
17493
17499
|
PUBLIC_COMMAND_HELP = {
|
|
@@ -23571,7 +23577,7 @@ function buildCoderResumeActivationExtraArgs(admitted, options) {
|
|
|
23571
23577
|
"--mode",
|
|
23572
23578
|
"json",
|
|
23573
23579
|
...buildSeatModelCliArgs(options.model),
|
|
23574
|
-
|
|
23580
|
+
selectResumeContinuationPrompt(options.message)
|
|
23575
23581
|
];
|
|
23576
23582
|
}
|
|
23577
23583
|
async function presentControlledFailure2(admitted, failureInput, io) {
|
|
@@ -23806,25 +23812,10 @@ async function runPublicCoder(argv, env, io, parseCoderArgv2) {
|
|
|
23806
23812
|
})
|
|
23807
23813
|
});
|
|
23808
23814
|
}
|
|
23809
|
-
async function runPublicCoderResume(
|
|
23810
|
-
const runId = argv[0];
|
|
23811
|
-
if (runId === void 0 || runId.trim() === "" || runId.startsWith("-")) {
|
|
23812
|
-
presentStructuralRejection(
|
|
23813
|
-
new CliUsageError("usage: ak-role resume <runId>"),
|
|
23814
|
-
io
|
|
23815
|
-
);
|
|
23816
|
-
return { exitCode: 2 };
|
|
23817
|
-
}
|
|
23818
|
-
if (argv.length > 1) {
|
|
23819
|
-
presentStructuralRejection(
|
|
23820
|
-
new CliUsageError("resume takes exactly one run id"),
|
|
23821
|
-
io
|
|
23822
|
-
);
|
|
23823
|
-
return { exitCode: 2 };
|
|
23824
|
-
}
|
|
23815
|
+
async function runPublicCoderResume(request, env, io) {
|
|
23825
23816
|
let loaded;
|
|
23826
23817
|
try {
|
|
23827
|
-
loaded = await loadResumableCoderRun(env.home, runId);
|
|
23818
|
+
loaded = await loadResumableCoderRun(env.home, request.runId);
|
|
23828
23819
|
} catch (error) {
|
|
23829
23820
|
if (error instanceof CliUsageError) {
|
|
23830
23821
|
presentStructuralRejection(error, io);
|
|
@@ -23869,7 +23860,8 @@ async function runPublicCoderResume(argv, env, io) {
|
|
|
23869
23860
|
const extraArgs = buildCoderResumeActivationExtraArgs(admitted, {
|
|
23870
23861
|
packageRoot: env.packageRoot,
|
|
23871
23862
|
...env.model === void 0 ? {} : { model: env.model },
|
|
23872
|
-
...env.extraPiArgs === void 0 ? {} : { extraPiArgs: env.extraPiArgs }
|
|
23863
|
+
...env.extraPiArgs === void 0 ? {} : { extraPiArgs: env.extraPiArgs },
|
|
23864
|
+
...request.message === void 0 ? {} : { message: request.message }
|
|
23873
23865
|
});
|
|
23874
23866
|
const result2 = await dispatchAdmittedCoder({
|
|
23875
23867
|
admitted,
|
|
@@ -24475,7 +24467,7 @@ function buildFixerResumeActivationExtraArgs(admitted, options) {
|
|
|
24475
24467
|
"--mode",
|
|
24476
24468
|
"json",
|
|
24477
24469
|
...buildSeatModelCliArgs(options.model),
|
|
24478
|
-
|
|
24470
|
+
selectResumeContinuationPrompt(options.message)
|
|
24479
24471
|
];
|
|
24480
24472
|
}
|
|
24481
24473
|
async function presentControlledFailure5(admitted, failureInput, io) {
|
|
@@ -24723,25 +24715,10 @@ async function runPublicFixer(argv, env, io, parseFixerArgv2) {
|
|
|
24723
24715
|
})
|
|
24724
24716
|
});
|
|
24725
24717
|
}
|
|
24726
|
-
async function runPublicFixerResume(
|
|
24727
|
-
const runId = argv[0];
|
|
24728
|
-
if (runId === void 0 || runId.trim() === "" || runId.startsWith("-")) {
|
|
24729
|
-
presentStructuralRejection(
|
|
24730
|
-
new CliUsageError("usage: ak-role resume <runId>"),
|
|
24731
|
-
io
|
|
24732
|
-
);
|
|
24733
|
-
return { exitCode: 2 };
|
|
24734
|
-
}
|
|
24735
|
-
if (argv.length > 1) {
|
|
24736
|
-
presentStructuralRejection(
|
|
24737
|
-
new CliUsageError("resume takes exactly one run id"),
|
|
24738
|
-
io
|
|
24739
|
-
);
|
|
24740
|
-
return { exitCode: 2 };
|
|
24741
|
-
}
|
|
24718
|
+
async function runPublicFixerResume(request, env, io) {
|
|
24742
24719
|
let loaded;
|
|
24743
24720
|
try {
|
|
24744
|
-
loaded = await loadResumableFixerRun(env.home, runId);
|
|
24721
|
+
loaded = await loadResumableFixerRun(env.home, request.runId);
|
|
24745
24722
|
} catch (error) {
|
|
24746
24723
|
if (error instanceof CliUsageError) {
|
|
24747
24724
|
presentStructuralRejection(error, io);
|
|
@@ -24779,7 +24756,8 @@ async function runPublicFixerResume(argv, env, io) {
|
|
|
24779
24756
|
const extraArgs = buildFixerResumeActivationExtraArgs(admitted, {
|
|
24780
24757
|
packageRoot: env.packageRoot,
|
|
24781
24758
|
...env.model === void 0 ? {} : { model: env.model },
|
|
24782
|
-
...env.extraPiArgs === void 0 ? {} : { extraPiArgs: env.extraPiArgs }
|
|
24759
|
+
...env.extraPiArgs === void 0 ? {} : { extraPiArgs: env.extraPiArgs },
|
|
24760
|
+
...request.message === void 0 ? {} : { message: request.message }
|
|
24783
24761
|
});
|
|
24784
24762
|
const result2 = await dispatchAdmittedFixer({
|
|
24785
24763
|
admitted,
|
|
@@ -24932,7 +24910,7 @@ function buildJudgeResumeActivationExtraArgs(admitted, options = {}) {
|
|
|
24932
24910
|
"--mode",
|
|
24933
24911
|
"json",
|
|
24934
24912
|
...buildSeatModelCliArgs(options.model),
|
|
24935
|
-
|
|
24913
|
+
selectResumeContinuationPrompt(options.message)
|
|
24936
24914
|
];
|
|
24937
24915
|
}
|
|
24938
24916
|
async function presentControlledFailure6(admitted, failureInput, io) {
|
|
@@ -25164,25 +25142,10 @@ async function runPublicJudge(argv, env, io, parseJudgeArgv2) {
|
|
|
25164
25142
|
})
|
|
25165
25143
|
});
|
|
25166
25144
|
}
|
|
25167
|
-
async function runPublicResume(
|
|
25168
|
-
const runId = argv[0];
|
|
25169
|
-
if (runId === void 0 || runId.trim() === "" || runId.startsWith("-")) {
|
|
25170
|
-
presentStructuralRejection(
|
|
25171
|
-
new CliUsageError("usage: ak-role resume <runId>"),
|
|
25172
|
-
io
|
|
25173
|
-
);
|
|
25174
|
-
return { exitCode: 2 };
|
|
25175
|
-
}
|
|
25176
|
-
if (argv.length > 1) {
|
|
25177
|
-
presentStructuralRejection(
|
|
25178
|
-
new CliUsageError("resume takes exactly one run id"),
|
|
25179
|
-
io
|
|
25180
|
-
);
|
|
25181
|
-
return { exitCode: 2 };
|
|
25182
|
-
}
|
|
25145
|
+
async function runPublicResume(request, env, io) {
|
|
25183
25146
|
let loaded;
|
|
25184
25147
|
try {
|
|
25185
|
-
loaded = await loadResumableJudgeRun(env.home, runId);
|
|
25148
|
+
loaded = await loadResumableJudgeRun(env.home, request.runId);
|
|
25186
25149
|
} catch (error) {
|
|
25187
25150
|
if (error instanceof CliUsageError) {
|
|
25188
25151
|
presentStructuralRejection(error, io);
|
|
@@ -25203,7 +25166,8 @@ async function runPublicResume(argv, env, io) {
|
|
|
25203
25166
|
}
|
|
25204
25167
|
const extraArgs = buildJudgeResumeActivationExtraArgs(admitted, {
|
|
25205
25168
|
...env.model === void 0 ? {} : { model: env.model },
|
|
25206
|
-
...env.extraPiArgs === void 0 ? {} : { extraPiArgs: env.extraPiArgs }
|
|
25169
|
+
...env.extraPiArgs === void 0 ? {} : { extraPiArgs: env.extraPiArgs },
|
|
25170
|
+
...request.message === void 0 ? {} : { message: request.message }
|
|
25207
25171
|
});
|
|
25208
25172
|
const result2 = await dispatchAdmittedJudge({
|
|
25209
25173
|
admitted,
|
|
@@ -25294,7 +25258,7 @@ function buildMergerResumeActivationExtraArgs(admitted, options) {
|
|
|
25294
25258
|
"--mode",
|
|
25295
25259
|
"json",
|
|
25296
25260
|
...buildSeatModelCliArgs(options.model),
|
|
25297
|
-
|
|
25261
|
+
selectResumeContinuationPrompt(options.message)
|
|
25298
25262
|
];
|
|
25299
25263
|
}
|
|
25300
25264
|
async function presentControlledFailure7(admitted, failureInput, io) {
|
|
@@ -25615,25 +25579,10 @@ async function runPublicMerger(argv, env, io, parseMergerArgv2) {
|
|
|
25615
25579
|
})
|
|
25616
25580
|
});
|
|
25617
25581
|
}
|
|
25618
|
-
async function runPublicMergerResume(
|
|
25619
|
-
const runId = argv[0];
|
|
25620
|
-
if (runId === void 0 || runId.trim() === "" || runId.startsWith("-")) {
|
|
25621
|
-
presentStructuralRejection(
|
|
25622
|
-
new CliUsageError("usage: ak-role resume <runId>"),
|
|
25623
|
-
io
|
|
25624
|
-
);
|
|
25625
|
-
return { exitCode: 2 };
|
|
25626
|
-
}
|
|
25627
|
-
if (argv.length > 1) {
|
|
25628
|
-
presentStructuralRejection(
|
|
25629
|
-
new CliUsageError("resume takes exactly one run id"),
|
|
25630
|
-
io
|
|
25631
|
-
);
|
|
25632
|
-
return { exitCode: 2 };
|
|
25633
|
-
}
|
|
25582
|
+
async function runPublicMergerResume(request, env, io) {
|
|
25634
25583
|
let loaded;
|
|
25635
25584
|
try {
|
|
25636
|
-
loaded = await loadResumableMergerRun(env.home, runId);
|
|
25585
|
+
loaded = await loadResumableMergerRun(env.home, request.runId);
|
|
25637
25586
|
} catch (error) {
|
|
25638
25587
|
if (error instanceof CliUsageError) {
|
|
25639
25588
|
presentStructuralRejection(error, io);
|
|
@@ -25672,7 +25621,8 @@ async function runPublicMergerResume(argv, env, io) {
|
|
|
25672
25621
|
const extraArgs = buildMergerResumeActivationExtraArgs(admitted, {
|
|
25673
25622
|
packageRoot: env.packageRoot,
|
|
25674
25623
|
...env.model === void 0 ? {} : { model: env.model },
|
|
25675
|
-
...env.extraPiArgs === void 0 ? {} : { extraPiArgs: env.extraPiArgs }
|
|
25624
|
+
...env.extraPiArgs === void 0 ? {} : { extraPiArgs: env.extraPiArgs },
|
|
25625
|
+
...request.message === void 0 ? {} : { message: request.message }
|
|
25676
25626
|
});
|
|
25677
25627
|
const result2 = await dispatchAdmittedMerger({
|
|
25678
25628
|
admitted,
|
|
@@ -25777,7 +25727,7 @@ function buildReviewerResumeActivationExtraArgs(admitted, options) {
|
|
|
25777
25727
|
"--mode",
|
|
25778
25728
|
"json",
|
|
25779
25729
|
...buildSeatModelCliArgs(options.model),
|
|
25780
|
-
|
|
25730
|
+
selectResumeContinuationPrompt(options.message)
|
|
25781
25731
|
];
|
|
25782
25732
|
}
|
|
25783
25733
|
async function presentControlledFailure8(admitted, failureInput, io) {
|
|
@@ -26033,25 +25983,10 @@ async function runPublicReviewer(argv, env, io, parseReviewerArgv2) {
|
|
|
26033
25983
|
})
|
|
26034
25984
|
});
|
|
26035
25985
|
}
|
|
26036
|
-
async function runPublicReviewerResume(
|
|
26037
|
-
const runId = argv[0];
|
|
26038
|
-
if (runId === void 0 || runId.trim() === "" || runId.startsWith("-")) {
|
|
26039
|
-
presentStructuralRejection(
|
|
26040
|
-
new CliUsageError("usage: ak-role resume <runId>"),
|
|
26041
|
-
io
|
|
26042
|
-
);
|
|
26043
|
-
return { exitCode: 2 };
|
|
26044
|
-
}
|
|
26045
|
-
if (argv.length > 1) {
|
|
26046
|
-
presentStructuralRejection(
|
|
26047
|
-
new CliUsageError("resume takes exactly one run id"),
|
|
26048
|
-
io
|
|
26049
|
-
);
|
|
26050
|
-
return { exitCode: 2 };
|
|
26051
|
-
}
|
|
25986
|
+
async function runPublicReviewerResume(request, env, io) {
|
|
26052
25987
|
let loaded;
|
|
26053
25988
|
try {
|
|
26054
|
-
loaded = await loadResumableReviewerRun(env.home, runId);
|
|
25989
|
+
loaded = await loadResumableReviewerRun(env.home, request.runId);
|
|
26055
25990
|
} catch (error) {
|
|
26056
25991
|
if (error instanceof CliUsageError) {
|
|
26057
25992
|
presentStructuralRejection(error, io);
|
|
@@ -26089,7 +26024,8 @@ async function runPublicReviewerResume(argv, env, io) {
|
|
|
26089
26024
|
const extraArgs = buildReviewerResumeActivationExtraArgs(admitted, {
|
|
26090
26025
|
packageRoot: env.packageRoot,
|
|
26091
26026
|
...env.model === void 0 ? {} : { model: env.model },
|
|
26092
|
-
...env.extraPiArgs === void 0 ? {} : { extraPiArgs: env.extraPiArgs }
|
|
26027
|
+
...env.extraPiArgs === void 0 ? {} : { extraPiArgs: env.extraPiArgs },
|
|
26028
|
+
...request.message === void 0 ? {} : { message: request.message }
|
|
26093
26029
|
});
|
|
26094
26030
|
const result2 = await dispatchAdmittedReviewer({
|
|
26095
26031
|
admitted,
|
|
@@ -28729,6 +28665,10 @@ function parseArgv(argv) {
|
|
|
28729
28665
|
const positional = [];
|
|
28730
28666
|
const globalOptions = createTypedOptionConsumer(PUBLIC_GLOBAL_OPTIONS);
|
|
28731
28667
|
while (args.length > 0) {
|
|
28668
|
+
if (positional[0] === "resume" && positional.length >= 2) {
|
|
28669
|
+
positional.push(...args);
|
|
28670
|
+
break;
|
|
28671
|
+
}
|
|
28732
28672
|
if (args[0] === "--") {
|
|
28733
28673
|
args.shift();
|
|
28734
28674
|
positional.push(...args);
|
|
@@ -28779,6 +28719,19 @@ function parseArgv(argv) {
|
|
|
28779
28719
|
help
|
|
28780
28720
|
};
|
|
28781
28721
|
}
|
|
28722
|
+
function parseResumeRequest(args) {
|
|
28723
|
+
const runId = args[0];
|
|
28724
|
+
if (runId === void 0 || runId.trim() === "" || runId.startsWith("-")) {
|
|
28725
|
+
throw new CliUsageError("usage: ak-role resume <runId> [message]");
|
|
28726
|
+
}
|
|
28727
|
+
if (args.length > 2) {
|
|
28728
|
+
throw new CliUsageError("usage: ak-role resume <runId> [message]");
|
|
28729
|
+
}
|
|
28730
|
+
if (args.length === 2) {
|
|
28731
|
+
return { runId, message: args[1] };
|
|
28732
|
+
}
|
|
28733
|
+
return { runId };
|
|
28734
|
+
}
|
|
28782
28735
|
function invocationFromParsed(parsed) {
|
|
28783
28736
|
if (parsed.model === void 0 && parsed.thinking === void 0 && parsed.engine === void 0) {
|
|
28784
28737
|
return void 0;
|
|
@@ -29149,8 +29102,8 @@ async function runAkRole(argv, env) {
|
|
|
29149
29102
|
const cwd = env.cwd ?? process.cwd();
|
|
29150
29103
|
const config = await loadAndValidateConfig(home, env.packageRoot);
|
|
29151
29104
|
const credentials = env.credentials ?? await loadCredentialProviders(agentDir);
|
|
29152
|
-
const
|
|
29153
|
-
const resumeRole =
|
|
29105
|
+
const resumeRequest = parseResumeRequest(parsed.args);
|
|
29106
|
+
const resumeRole = await peekRoleRunRole(home, resumeRequest.runId);
|
|
29154
29107
|
if (resumeRole === "collector") {
|
|
29155
29108
|
throw new CliUsageError(
|
|
29156
29109
|
"collector role runs are one-shot and cannot be resumed"
|
|
@@ -29170,7 +29123,7 @@ async function runAkRole(argv, env) {
|
|
|
29170
29123
|
);
|
|
29171
29124
|
if (resumeRole === "coder") {
|
|
29172
29125
|
const result3 = await runPublicCoderResume(
|
|
29173
|
-
|
|
29126
|
+
resumeRequest,
|
|
29174
29127
|
{
|
|
29175
29128
|
home,
|
|
29176
29129
|
agentDir,
|
|
@@ -29192,7 +29145,7 @@ async function runAkRole(argv, env) {
|
|
|
29192
29145
|
}
|
|
29193
29146
|
if (resumeRole === "fixer") {
|
|
29194
29147
|
const result3 = await runPublicFixerResume(
|
|
29195
|
-
|
|
29148
|
+
resumeRequest,
|
|
29196
29149
|
{
|
|
29197
29150
|
home,
|
|
29198
29151
|
agentDir,
|
|
@@ -29214,7 +29167,7 @@ async function runAkRole(argv, env) {
|
|
|
29214
29167
|
}
|
|
29215
29168
|
if (resumeRole === "reviewer") {
|
|
29216
29169
|
const result3 = await runPublicReviewerResume(
|
|
29217
|
-
|
|
29170
|
+
resumeRequest,
|
|
29218
29171
|
{
|
|
29219
29172
|
home,
|
|
29220
29173
|
agentDir,
|
|
@@ -29236,7 +29189,7 @@ async function runAkRole(argv, env) {
|
|
|
29236
29189
|
}
|
|
29237
29190
|
if (resumeRole === "merger") {
|
|
29238
29191
|
const result3 = await runPublicMergerResume(
|
|
29239
|
-
|
|
29192
|
+
resumeRequest,
|
|
29240
29193
|
{
|
|
29241
29194
|
home,
|
|
29242
29195
|
agentDir,
|
|
@@ -29257,7 +29210,7 @@ async function runAkRole(argv, env) {
|
|
|
29257
29210
|
};
|
|
29258
29211
|
}
|
|
29259
29212
|
const result2 = await runPublicResume(
|
|
29260
|
-
|
|
29213
|
+
resumeRequest,
|
|
29261
29214
|
{
|
|
29262
29215
|
home,
|
|
29263
29216
|
agentDir,
|
package/package.json
CHANGED
package/src/factory-board.ts
CHANGED
|
@@ -398,7 +398,7 @@ const YAMEN_LABELS: Readonly<Record<string, string>> = {
|
|
|
398
398
|
coder: "将作监",
|
|
399
399
|
fixer: "修内司",
|
|
400
400
|
reviewer: "御史台",
|
|
401
|
-
collector: "
|
|
401
|
+
collector: "通进司",
|
|
402
402
|
doctor: "太医署",
|
|
403
403
|
merger: "校书郎",
|
|
404
404
|
marshal: "刑部",
|
|
@@ -808,7 +808,7 @@ const COLUMN_LABELS: Readonly<Record<string, string>> = {
|
|
|
808
808
|
court: "大理寺 · 审票",
|
|
809
809
|
coder: "将作监",
|
|
810
810
|
marshal: "刑部",
|
|
811
|
-
collector: "
|
|
811
|
+
collector: "通进司",
|
|
812
812
|
done: "已完成",
|
|
813
813
|
};
|
|
814
814
|
|
package/src/public-cli/cli.ts
CHANGED
|
@@ -64,7 +64,11 @@ import { runPublicJudge, runPublicResume } from "./judge-run.ts";
|
|
|
64
64
|
import { runPublicMerger, runPublicMergerResume } from "./merger-run.ts";
|
|
65
65
|
import { runPublicReviewer, runPublicReviewerResume } from "./reviewer-run.ts";
|
|
66
66
|
import { runPublicAnalyst } from "./analyst-run.ts";
|
|
67
|
-
import {
|
|
67
|
+
import {
|
|
68
|
+
AUTO_RESUME_LIMIT,
|
|
69
|
+
peekRoleRunRole,
|
|
70
|
+
type PublicResumeRequest,
|
|
71
|
+
} from "./run-lifecycle.ts";
|
|
68
72
|
import {
|
|
69
73
|
INTERNAL_ROLE_ENTRYPOINT_RELATIVE,
|
|
70
74
|
isAutomaticConfigurableSeat,
|
|
@@ -270,7 +274,14 @@ function parseArgv(argv: readonly string[]): ParsedGlobal {
|
|
|
270
274
|
// Global flags may appear before or after the subcommand
|
|
271
275
|
// (`ak-role --model x roles` and `ak-role roles --model x`).
|
|
272
276
|
// Grammar authority: shared typed consumer over PUBLIC_OPTION_TABLE.global.
|
|
277
|
+
// #471: after `resume <runId>`, remaining argv is the opaque message segment
|
|
278
|
+
// and must not re-enter the global-option consumer — including bare `--`,
|
|
279
|
+
// which is a legal opaque message token, not an argv delimiter here.
|
|
273
280
|
while (args.length > 0) {
|
|
281
|
+
if (positional[0] === "resume" && positional.length >= 2) {
|
|
282
|
+
positional.push(...args);
|
|
283
|
+
break;
|
|
284
|
+
}
|
|
274
285
|
if (args[0] === "--") {
|
|
275
286
|
args.shift();
|
|
276
287
|
positional.push(...args);
|
|
@@ -326,6 +337,24 @@ function parseArgv(argv: readonly string[]): ParsedGlobal {
|
|
|
326
337
|
};
|
|
327
338
|
}
|
|
328
339
|
|
|
340
|
+
/**
|
|
341
|
+
* Unique public resume request parser (#471).
|
|
342
|
+
* One optional argv after runId is the opaque message; no further positionals.
|
|
343
|
+
*/
|
|
344
|
+
function parseResumeRequest(args: readonly string[]): PublicResumeRequest {
|
|
345
|
+
const runId = args[0];
|
|
346
|
+
if (runId === undefined || runId.trim() === "" || runId.startsWith("-")) {
|
|
347
|
+
throw new CliUsageError("usage: ak-role resume <runId> [message]");
|
|
348
|
+
}
|
|
349
|
+
if (args.length > 2) {
|
|
350
|
+
throw new CliUsageError("usage: ak-role resume <runId> [message]");
|
|
351
|
+
}
|
|
352
|
+
if (args.length === 2) {
|
|
353
|
+
return { runId, message: args[1]! };
|
|
354
|
+
}
|
|
355
|
+
return { runId };
|
|
356
|
+
}
|
|
357
|
+
|
|
329
358
|
function invocationFromParsed(parsed: ParsedGlobal): InvocationModelOverride | undefined {
|
|
330
359
|
if (
|
|
331
360
|
parsed.model === undefined &&
|
|
@@ -784,17 +813,15 @@ export async function runAkRole(
|
|
|
784
813
|
|
|
785
814
|
// Resume reopens an exact Role run (#416): caller decides; session principal
|
|
786
815
|
// must still exist. Seat and dispatch follow the durable admitted role.
|
|
816
|
+
// #471: unique parser owns {runId, message?}; five role paths only consume it.
|
|
787
817
|
if (parsed.command === "resume") {
|
|
788
818
|
const agentDir = resolveAgentDir(env, home);
|
|
789
819
|
const cwd = env.cwd ?? process.cwd();
|
|
790
820
|
const config = await loadAndValidateConfig(home, env.packageRoot);
|
|
791
821
|
const credentials =
|
|
792
822
|
env.credentials ?? (await loadCredentialProviders(agentDir));
|
|
793
|
-
const
|
|
794
|
-
const resumeRole =
|
|
795
|
-
resumeRunId === undefined || resumeRunId.trim() === ""
|
|
796
|
-
? undefined
|
|
797
|
-
: await peekRoleRunRole(home, resumeRunId);
|
|
823
|
+
const resumeRequest = parseResumeRequest(parsed.args);
|
|
824
|
+
const resumeRole = await peekRoleRunRole(home, resumeRequest.runId);
|
|
798
825
|
if (resumeRole === "collector") {
|
|
799
826
|
throw new CliUsageError(
|
|
800
827
|
"collector role runs are one-shot and cannot be resumed",
|
|
@@ -824,7 +851,7 @@ export async function runAkRole(
|
|
|
824
851
|
);
|
|
825
852
|
if (resumeRole === "coder") {
|
|
826
853
|
const result = await runPublicCoderResume(
|
|
827
|
-
|
|
854
|
+
resumeRequest,
|
|
828
855
|
{
|
|
829
856
|
home,
|
|
830
857
|
agentDir,
|
|
@@ -852,7 +879,7 @@ export async function runAkRole(
|
|
|
852
879
|
}
|
|
853
880
|
if (resumeRole === "fixer") {
|
|
854
881
|
const result = await runPublicFixerResume(
|
|
855
|
-
|
|
882
|
+
resumeRequest,
|
|
856
883
|
{
|
|
857
884
|
home,
|
|
858
885
|
agentDir,
|
|
@@ -880,7 +907,7 @@ export async function runAkRole(
|
|
|
880
907
|
}
|
|
881
908
|
if (resumeRole === "reviewer") {
|
|
882
909
|
const result = await runPublicReviewerResume(
|
|
883
|
-
|
|
910
|
+
resumeRequest,
|
|
884
911
|
{
|
|
885
912
|
home,
|
|
886
913
|
agentDir,
|
|
@@ -908,7 +935,7 @@ export async function runAkRole(
|
|
|
908
935
|
}
|
|
909
936
|
if (resumeRole === "merger") {
|
|
910
937
|
const result = await runPublicMergerResume(
|
|
911
|
-
|
|
938
|
+
resumeRequest,
|
|
912
939
|
{
|
|
913
940
|
home,
|
|
914
941
|
agentDir,
|
|
@@ -935,7 +962,7 @@ export async function runAkRole(
|
|
|
935
962
|
};
|
|
936
963
|
}
|
|
937
964
|
const result = await runPublicResume(
|
|
938
|
-
|
|
965
|
+
resumeRequest,
|
|
939
966
|
{
|
|
940
967
|
home,
|
|
941
968
|
agentDir,
|
|
@@ -45,7 +45,8 @@ import {
|
|
|
45
45
|
markRunRunning,
|
|
46
46
|
markRunTerminal,
|
|
47
47
|
renderResumeCommand,
|
|
48
|
-
|
|
48
|
+
type PublicResumeRequest,
|
|
49
|
+
selectResumeContinuationPrompt,
|
|
49
50
|
RunWriterLeaseHeldError,
|
|
50
51
|
type RunWriterLease,
|
|
51
52
|
type TypedProviderHttpObservation,
|
|
@@ -152,6 +153,7 @@ export function buildCoderResumeActivationExtraArgs(
|
|
|
152
153
|
packageRoot: string;
|
|
153
154
|
model?: SeatModelConfig;
|
|
154
155
|
extraPiArgs?: readonly string[];
|
|
156
|
+
message?: string;
|
|
155
157
|
},
|
|
156
158
|
): string[] {
|
|
157
159
|
const skillArgs =
|
|
@@ -181,7 +183,7 @@ export function buildCoderResumeActivationExtraArgs(
|
|
|
181
183
|
"--mode",
|
|
182
184
|
"json",
|
|
183
185
|
...buildSeatModelCliArgs(options.model),
|
|
184
|
-
|
|
186
|
+
selectResumeContinuationPrompt(options.message),
|
|
185
187
|
];
|
|
186
188
|
}
|
|
187
189
|
|
|
@@ -513,7 +515,7 @@ export async function runPublicCoder(
|
|
|
513
515
|
* Restores role/phase/task/session identity; model override is temporary.
|
|
514
516
|
*/
|
|
515
517
|
export async function runPublicCoderResume(
|
|
516
|
-
|
|
518
|
+
request: PublicResumeRequest,
|
|
517
519
|
env: CoderRunEnv,
|
|
518
520
|
io: CliIo,
|
|
519
521
|
): Promise<{
|
|
@@ -521,25 +523,9 @@ export async function runPublicCoderResume(
|
|
|
521
523
|
admitted?: AdmittedCoderInvocation;
|
|
522
524
|
terminal?: TerminalResult;
|
|
523
525
|
}> {
|
|
524
|
-
const runId = argv[0];
|
|
525
|
-
if (runId === undefined || runId.trim() === "" || runId.startsWith("-")) {
|
|
526
|
-
presentStructuralRejection(
|
|
527
|
-
new CliUsageError("usage: ak-role resume <runId>"),
|
|
528
|
-
io,
|
|
529
|
-
);
|
|
530
|
-
return { exitCode: 2 };
|
|
531
|
-
}
|
|
532
|
-
if (argv.length > 1) {
|
|
533
|
-
presentStructuralRejection(
|
|
534
|
-
new CliUsageError("resume takes exactly one run id"),
|
|
535
|
-
io,
|
|
536
|
-
);
|
|
537
|
-
return { exitCode: 2 };
|
|
538
|
-
}
|
|
539
|
-
|
|
540
526
|
let loaded;
|
|
541
527
|
try {
|
|
542
|
-
loaded = await loadResumableCoderRun(env.home, runId);
|
|
528
|
+
loaded = await loadResumableCoderRun(env.home, request.runId);
|
|
543
529
|
} catch (error) {
|
|
544
530
|
if (error instanceof CliUsageError) {
|
|
545
531
|
presentStructuralRejection(error, io);
|
|
@@ -590,6 +576,7 @@ export async function runPublicCoderResume(
|
|
|
590
576
|
packageRoot: env.packageRoot,
|
|
591
577
|
...(env.model === undefined ? {} : { model: env.model }),
|
|
592
578
|
...(env.extraPiArgs === undefined ? {} : { extraPiArgs: env.extraPiArgs }),
|
|
579
|
+
...(request.message === undefined ? {} : { message: request.message }),
|
|
593
580
|
});
|
|
594
581
|
|
|
595
582
|
const result = await dispatchAdmittedCoder({
|
|
@@ -47,7 +47,8 @@ import {
|
|
|
47
47
|
markRunRunning,
|
|
48
48
|
markRunTerminal,
|
|
49
49
|
renderResumeCommand,
|
|
50
|
-
|
|
50
|
+
type PublicResumeRequest,
|
|
51
|
+
selectResumeContinuationPrompt,
|
|
51
52
|
RunWriterLeaseHeldError,
|
|
52
53
|
type RunWriterLease,
|
|
53
54
|
type TypedProviderHttpObservation,
|
|
@@ -161,6 +162,7 @@ export function buildFixerResumeActivationExtraArgs(
|
|
|
161
162
|
packageRoot: string;
|
|
162
163
|
model?: SeatModelConfig;
|
|
163
164
|
extraPiArgs?: readonly string[];
|
|
165
|
+
message?: string;
|
|
164
166
|
},
|
|
165
167
|
): string[] {
|
|
166
168
|
const diagnosisSkillPath = resolvePackagedMethodSkillPath(
|
|
@@ -196,7 +198,7 @@ export function buildFixerResumeActivationExtraArgs(
|
|
|
196
198
|
"--mode",
|
|
197
199
|
"json",
|
|
198
200
|
...buildSeatModelCliArgs(options.model),
|
|
199
|
-
|
|
201
|
+
selectResumeContinuationPrompt(options.message),
|
|
200
202
|
];
|
|
201
203
|
}
|
|
202
204
|
|
|
@@ -532,7 +534,7 @@ export async function runPublicFixer(
|
|
|
532
534
|
* Restores role/phase/packet/prerequisites/session identity; model override is temporary.
|
|
533
535
|
*/
|
|
534
536
|
export async function runPublicFixerResume(
|
|
535
|
-
|
|
537
|
+
request: PublicResumeRequest,
|
|
536
538
|
env: FixerRunEnv,
|
|
537
539
|
io: CliIo,
|
|
538
540
|
): Promise<{
|
|
@@ -540,25 +542,9 @@ export async function runPublicFixerResume(
|
|
|
540
542
|
admitted?: AdmittedFixerInvocation;
|
|
541
543
|
terminal?: TerminalResult;
|
|
542
544
|
}> {
|
|
543
|
-
const runId = argv[0];
|
|
544
|
-
if (runId === undefined || runId.trim() === "" || runId.startsWith("-")) {
|
|
545
|
-
presentStructuralRejection(
|
|
546
|
-
new CliUsageError("usage: ak-role resume <runId>"),
|
|
547
|
-
io,
|
|
548
|
-
);
|
|
549
|
-
return { exitCode: 2 };
|
|
550
|
-
}
|
|
551
|
-
if (argv.length > 1) {
|
|
552
|
-
presentStructuralRejection(
|
|
553
|
-
new CliUsageError("resume takes exactly one run id"),
|
|
554
|
-
io,
|
|
555
|
-
);
|
|
556
|
-
return { exitCode: 2 };
|
|
557
|
-
}
|
|
558
|
-
|
|
559
545
|
let loaded;
|
|
560
546
|
try {
|
|
561
|
-
loaded = await loadResumableFixerRun(env.home, runId);
|
|
547
|
+
loaded = await loadResumableFixerRun(env.home, request.runId);
|
|
562
548
|
} catch (error) {
|
|
563
549
|
if (error instanceof CliUsageError) {
|
|
564
550
|
presentStructuralRejection(error, io);
|
|
@@ -601,6 +587,7 @@ export async function runPublicFixerResume(
|
|
|
601
587
|
packageRoot: env.packageRoot,
|
|
602
588
|
...(env.model === undefined ? {} : { model: env.model }),
|
|
603
589
|
...(env.extraPiArgs === undefined ? {} : { extraPiArgs: env.extraPiArgs }),
|
|
590
|
+
...(request.message === undefined ? {} : { message: request.message }),
|
|
604
591
|
});
|
|
605
592
|
|
|
606
593
|
const result = await dispatchAdmittedFixer({
|
|
@@ -41,7 +41,8 @@ import {
|
|
|
41
41
|
markRunTerminal,
|
|
42
42
|
renderResumeCommand,
|
|
43
43
|
type TypedProviderHttpObservation,
|
|
44
|
-
|
|
44
|
+
type PublicResumeRequest,
|
|
45
|
+
selectResumeContinuationPrompt,
|
|
45
46
|
RunWriterLeaseHeldError,
|
|
46
47
|
type RunWriterLease,
|
|
47
48
|
} from "./run-lifecycle.ts";
|
|
@@ -147,6 +148,7 @@ export function buildJudgeResumeActivationExtraArgs(
|
|
|
147
148
|
options: {
|
|
148
149
|
model?: SeatModelConfig;
|
|
149
150
|
extraPiArgs?: readonly string[];
|
|
151
|
+
message?: string;
|
|
150
152
|
} = {},
|
|
151
153
|
): string[] {
|
|
152
154
|
return [
|
|
@@ -164,7 +166,7 @@ export function buildJudgeResumeActivationExtraArgs(
|
|
|
164
166
|
"--mode",
|
|
165
167
|
"json",
|
|
166
168
|
...buildSeatModelCliArgs(options.model),
|
|
167
|
-
|
|
169
|
+
selectResumeContinuationPrompt(options.message),
|
|
168
170
|
];
|
|
169
171
|
}
|
|
170
172
|
|
|
@@ -500,7 +502,7 @@ export async function runPublicJudge(
|
|
|
500
502
|
* is temporary for this invocation only.
|
|
501
503
|
*/
|
|
502
504
|
export async function runPublicResume(
|
|
503
|
-
|
|
505
|
+
request: PublicResumeRequest,
|
|
504
506
|
env: JudgeRunEnv,
|
|
505
507
|
io: CliIo,
|
|
506
508
|
): Promise<{
|
|
@@ -508,26 +510,9 @@ export async function runPublicResume(
|
|
|
508
510
|
admitted?: AdmittedJudgeInvocation;
|
|
509
511
|
terminal?: TerminalResult;
|
|
510
512
|
}> {
|
|
511
|
-
const runId = argv[0];
|
|
512
|
-
if (runId === undefined || runId.trim() === "" || runId.startsWith("-")) {
|
|
513
|
-
presentStructuralRejection(
|
|
514
|
-
new CliUsageError("usage: ak-role resume <runId>"),
|
|
515
|
-
io,
|
|
516
|
-
);
|
|
517
|
-
return { exitCode: 2 };
|
|
518
|
-
}
|
|
519
|
-
if (argv.length > 1) {
|
|
520
|
-
// Resume does not accept free positionals beyond runId (model/thinking are global).
|
|
521
|
-
presentStructuralRejection(
|
|
522
|
-
new CliUsageError("resume takes exactly one run id"),
|
|
523
|
-
io,
|
|
524
|
-
);
|
|
525
|
-
return { exitCode: 2 };
|
|
526
|
-
}
|
|
527
|
-
|
|
528
513
|
let loaded;
|
|
529
514
|
try {
|
|
530
|
-
loaded = await loadResumableJudgeRun(env.home, runId);
|
|
515
|
+
loaded = await loadResumableJudgeRun(env.home, request.runId);
|
|
531
516
|
} catch (error) {
|
|
532
517
|
if (error instanceof CliUsageError) {
|
|
533
518
|
presentStructuralRejection(error, io);
|
|
@@ -553,6 +538,7 @@ export async function runPublicResume(
|
|
|
553
538
|
const extraArgs = buildJudgeResumeActivationExtraArgs(admitted, {
|
|
554
539
|
...(env.model === undefined ? {} : { model: env.model }),
|
|
555
540
|
...(env.extraPiArgs === undefined ? {} : { extraPiArgs: env.extraPiArgs }),
|
|
541
|
+
...(request.message === undefined ? {} : { message: request.message }),
|
|
556
542
|
});
|
|
557
543
|
|
|
558
544
|
const result = await dispatchAdmittedJudge({
|
|
@@ -50,7 +50,8 @@ import {
|
|
|
50
50
|
markRunRunning,
|
|
51
51
|
markRunTerminal,
|
|
52
52
|
renderResumeCommand,
|
|
53
|
-
|
|
53
|
+
type PublicResumeRequest,
|
|
54
|
+
selectResumeContinuationPrompt,
|
|
54
55
|
RunWriterLeaseHeldError,
|
|
55
56
|
type RunWriterLease,
|
|
56
57
|
type TypedProviderHttpObservation,
|
|
@@ -152,6 +153,7 @@ export function buildMergerResumeActivationExtraArgs(
|
|
|
152
153
|
packageRoot: string;
|
|
153
154
|
model?: SeatModelConfig;
|
|
154
155
|
extraPiArgs?: readonly string[];
|
|
156
|
+
message?: string;
|
|
155
157
|
},
|
|
156
158
|
): string[] {
|
|
157
159
|
const skillPath = resolvePackagedMethodSkillPath(
|
|
@@ -177,7 +179,7 @@ export function buildMergerResumeActivationExtraArgs(
|
|
|
177
179
|
"--mode",
|
|
178
180
|
"json",
|
|
179
181
|
...buildSeatModelCliArgs(options.model),
|
|
180
|
-
|
|
182
|
+
selectResumeContinuationPrompt(options.message),
|
|
181
183
|
];
|
|
182
184
|
}
|
|
183
185
|
|
|
@@ -613,7 +615,7 @@ export async function runPublicMerger(
|
|
|
613
615
|
* Restores derived input/session identity; model override is temporary.
|
|
614
616
|
*/
|
|
615
617
|
export async function runPublicMergerResume(
|
|
616
|
-
|
|
618
|
+
request: PublicResumeRequest,
|
|
617
619
|
env: MergerRunEnv,
|
|
618
620
|
io: CliIo,
|
|
619
621
|
): Promise<{
|
|
@@ -621,25 +623,9 @@ export async function runPublicMergerResume(
|
|
|
621
623
|
admitted?: AdmittedMergerInvocation;
|
|
622
624
|
terminal?: TerminalResult;
|
|
623
625
|
}> {
|
|
624
|
-
const runId = argv[0];
|
|
625
|
-
if (runId === undefined || runId.trim() === "" || runId.startsWith("-")) {
|
|
626
|
-
presentStructuralRejection(
|
|
627
|
-
new CliUsageError("usage: ak-role resume <runId>"),
|
|
628
|
-
io,
|
|
629
|
-
);
|
|
630
|
-
return { exitCode: 2 };
|
|
631
|
-
}
|
|
632
|
-
if (argv.length > 1) {
|
|
633
|
-
presentStructuralRejection(
|
|
634
|
-
new CliUsageError("resume takes exactly one run id"),
|
|
635
|
-
io,
|
|
636
|
-
);
|
|
637
|
-
return { exitCode: 2 };
|
|
638
|
-
}
|
|
639
|
-
|
|
640
626
|
let loaded;
|
|
641
627
|
try {
|
|
642
|
-
loaded = await loadResumableMergerRun(env.home, runId);
|
|
628
|
+
loaded = await loadResumableMergerRun(env.home, request.runId);
|
|
643
629
|
} catch (error) {
|
|
644
630
|
if (error instanceof CliUsageError) {
|
|
645
631
|
presentStructuralRejection(error, io);
|
|
@@ -683,6 +669,7 @@ export async function runPublicMergerResume(
|
|
|
683
669
|
packageRoot: env.packageRoot,
|
|
684
670
|
...(env.model === undefined ? {} : { model: env.model }),
|
|
685
671
|
...(env.extraPiArgs === undefined ? {} : { extraPiArgs: env.extraPiArgs }),
|
|
672
|
+
...(request.message === undefined ? {} : { message: request.message }),
|
|
686
673
|
});
|
|
687
674
|
|
|
688
675
|
const result = await dispatchAdmittedMerger({
|
|
@@ -1146,8 +1146,11 @@ const SUPPORT_COMMAND_HELP = {
|
|
|
1146
1146
|
resume: {
|
|
1147
1147
|
command: "resume",
|
|
1148
1148
|
summary: "Reopen an exact role run whose Pi session principal still exists.",
|
|
1149
|
-
usage: ["ak-role resume <runId>"],
|
|
1150
|
-
examples: [
|
|
1149
|
+
usage: ["ak-role resume <runId> [message]"],
|
|
1150
|
+
examples: [
|
|
1151
|
+
"ak-role resume 01abc…",
|
|
1152
|
+
"ak-role resume 01abc… \"owner ruling\"",
|
|
1153
|
+
],
|
|
1151
1154
|
},
|
|
1152
1155
|
} as const satisfies Record<string, PublicCommandHelpFacts>;
|
|
1153
1156
|
|
|
@@ -48,7 +48,8 @@ import {
|
|
|
48
48
|
markRunRunning,
|
|
49
49
|
markRunTerminal,
|
|
50
50
|
renderResumeCommand,
|
|
51
|
-
|
|
51
|
+
type PublicResumeRequest,
|
|
52
|
+
selectResumeContinuationPrompt,
|
|
52
53
|
RunWriterLeaseHeldError,
|
|
53
54
|
type RunWriterLease,
|
|
54
55
|
type TypedProviderHttpObservation,
|
|
@@ -169,6 +170,7 @@ export function buildReviewerResumeActivationExtraArgs(
|
|
|
169
170
|
packageRoot: string;
|
|
170
171
|
model?: SeatModelConfig;
|
|
171
172
|
extraPiArgs?: readonly string[];
|
|
173
|
+
message?: string;
|
|
172
174
|
},
|
|
173
175
|
): string[] {
|
|
174
176
|
const skillPath = resolvePackagedMethodSkillPath(
|
|
@@ -201,7 +203,7 @@ export function buildReviewerResumeActivationExtraArgs(
|
|
|
201
203
|
"--mode",
|
|
202
204
|
"json",
|
|
203
205
|
...buildSeatModelCliArgs(options.model),
|
|
204
|
-
|
|
206
|
+
selectResumeContinuationPrompt(options.message),
|
|
205
207
|
];
|
|
206
208
|
}
|
|
207
209
|
|
|
@@ -552,7 +554,7 @@ export async function runPublicReviewer(
|
|
|
552
554
|
* Restores task/base/session identity; model override is temporary.
|
|
553
555
|
*/
|
|
554
556
|
export async function runPublicReviewerResume(
|
|
555
|
-
|
|
557
|
+
request: PublicResumeRequest,
|
|
556
558
|
env: ReviewerRunEnv,
|
|
557
559
|
io: CliIo,
|
|
558
560
|
): Promise<{
|
|
@@ -560,25 +562,9 @@ export async function runPublicReviewerResume(
|
|
|
560
562
|
admitted?: AdmittedReviewerInvocation;
|
|
561
563
|
terminal?: TerminalResult;
|
|
562
564
|
}> {
|
|
563
|
-
const runId = argv[0];
|
|
564
|
-
if (runId === undefined || runId.trim() === "" || runId.startsWith("-")) {
|
|
565
|
-
presentStructuralRejection(
|
|
566
|
-
new CliUsageError("usage: ak-role resume <runId>"),
|
|
567
|
-
io,
|
|
568
|
-
);
|
|
569
|
-
return { exitCode: 2 };
|
|
570
|
-
}
|
|
571
|
-
if (argv.length > 1) {
|
|
572
|
-
presentStructuralRejection(
|
|
573
|
-
new CliUsageError("resume takes exactly one run id"),
|
|
574
|
-
io,
|
|
575
|
-
);
|
|
576
|
-
return { exitCode: 2 };
|
|
577
|
-
}
|
|
578
|
-
|
|
579
565
|
let loaded;
|
|
580
566
|
try {
|
|
581
|
-
loaded = await loadResumableReviewerRun(env.home, runId);
|
|
567
|
+
loaded = await loadResumableReviewerRun(env.home, request.runId);
|
|
582
568
|
} catch (error) {
|
|
583
569
|
if (error instanceof CliUsageError) {
|
|
584
570
|
presentStructuralRejection(error, io);
|
|
@@ -621,6 +607,7 @@ export async function runPublicReviewerResume(
|
|
|
621
607
|
packageRoot: env.packageRoot,
|
|
622
608
|
...(env.model === undefined ? {} : { model: env.model }),
|
|
623
609
|
...(env.extraPiArgs === undefined ? {} : { extraPiArgs: env.extraPiArgs }),
|
|
610
|
+
...(request.message === undefined ? {} : { message: request.message }),
|
|
624
611
|
});
|
|
625
612
|
|
|
626
613
|
const result = await dispatchAdmittedReviewer({
|
|
@@ -88,6 +88,22 @@ export type RoleRunRecord = {
|
|
|
88
88
|
/** Package-owned turn trigger for resume. Not caller instruction and not semantic task content. */
|
|
89
89
|
export const RESUME_TRANSPORT_ENVELOPE = "[ak-role:resume-continue]" as const;
|
|
90
90
|
|
|
91
|
+
/** Public manual resume request after the unique CLI parser owns runId + optional message. */
|
|
92
|
+
export type PublicResumeRequest = {
|
|
93
|
+
readonly runId: string;
|
|
94
|
+
/** Present when the caller supplied the post-runId argv (including empty string). */
|
|
95
|
+
readonly message?: string;
|
|
96
|
+
};
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* Unique continuation-prompt selector for manual/auto resume (#471).
|
|
100
|
+
* Message present → return bytes unchanged; absent → package transport envelope.
|
|
101
|
+
* Zero parse, zero classify, zero narrow.
|
|
102
|
+
*/
|
|
103
|
+
export function selectResumeContinuationPrompt(message?: string): string {
|
|
104
|
+
return message !== undefined ? message : RESUME_TRANSPORT_ENVELOPE;
|
|
105
|
+
}
|
|
106
|
+
|
|
91
107
|
const RUN_STATE_FILE = "run-state.json";
|
|
92
108
|
const WRITER_LOCK_FILE = "writer.lock";
|
|
93
109
|
|