@akagilnc/pi-workflow-roles 0.1.3733 → 0.1.3741
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 +1 -3
- package/README.zh-CN.md +1 -3
- package/dist/acp-host/production-host.js +278 -201
- package/dist/public-cli/config.js +2 -102
- package/dist/public-cli/host-providers.js +188 -0
- package/dist/public-cli/main.js +350 -324
- package/dist/public-cli/option-definitions.js +1 -4
- package/dist/public-role-summons.js +8 -4
- package/package.json +1 -1
- package/souls/countersign.md +1 -1
- package/souls/judge.md +21 -68
- package/souls/notary.md +1 -1
- package/src/public-cli/cli.ts +38 -71
- package/src/public-cli/config.ts +3 -153
- package/src/public-cli/host-providers.ts +246 -0
- package/src/public-cli/option-definitions.ts +1 -4
- package/src/public-role-summons.ts +14 -7
|
@@ -1068,7 +1068,7 @@ const SUPPORT_COMMAND_HELP = {
|
|
|
1068
1068
|
},
|
|
1069
1069
|
config: {
|
|
1070
1070
|
command: "config",
|
|
1071
|
-
summary: "Persistent seat model, labor-engine, host, and auto-resume defaults.",
|
|
1071
|
+
summary: "Persistent seat model, labor-engine, host, and auto-resume defaults. Host providers live in ~/.ak-roles/host-providers.json (owner-edited).",
|
|
1072
1072
|
usage: [
|
|
1073
1073
|
"ak-role config set <seat> <provider/model[:thinking]> [<seat> <spec> ...]",
|
|
1074
1074
|
"ak-role config unset <gatekeeper|inspector|notary>",
|
|
@@ -1077,8 +1077,6 @@ const SUPPORT_COMMAND_HELP = {
|
|
|
1077
1077
|
"ak-role config set-host <seat> <name>",
|
|
1078
1078
|
"ak-role config unset-host <seat>",
|
|
1079
1079
|
"ak-role config set-auto-resume-limit <N>",
|
|
1080
|
-
"ak-role config set-provider-alias <provider> <host> <alias>",
|
|
1081
|
-
"ak-role config unset-provider-alias <provider> <host>",
|
|
1082
1080
|
],
|
|
1083
1081
|
examples: [
|
|
1084
1082
|
"ak-role config set judge openai-codex/gpt-5.6-sol:high",
|
|
@@ -1086,7 +1084,6 @@ const SUPPORT_COMMAND_HELP = {
|
|
|
1086
1084
|
"ak-role config set-engine judge opus",
|
|
1087
1085
|
"ak-role config set-host judge grok-build",
|
|
1088
1086
|
"ak-role config set-auto-resume-limit 3",
|
|
1089
|
-
"ak-role config set-provider-alias xai hermes xai-oauth",
|
|
1090
1087
|
],
|
|
1091
1088
|
},
|
|
1092
1089
|
help: {
|
|
@@ -70,9 +70,6 @@ function projectSeatEngine(seat) {
|
|
|
70
70
|
function projectSeatHost(seat) {
|
|
71
71
|
return seat.host === void 0 ? {} : { host: seat.host };
|
|
72
72
|
}
|
|
73
|
-
function projectSeatModel(seat) {
|
|
74
|
-
return seat.selection === void 0 ? {} : { model: seat.selection };
|
|
75
|
-
}
|
|
76
73
|
async function createSummonEnv(options) {
|
|
77
74
|
const [{ piDurablePrincipalAuthority }, { appendPiSessionCustomEntry, createPiRoleTurnHost }] = await Promise.all([
|
|
78
75
|
import("./pi/durable-principal.js"),
|
|
@@ -122,6 +119,13 @@ async function createSummonEnv(options) {
|
|
|
122
119
|
}
|
|
123
120
|
};
|
|
124
121
|
}
|
|
122
|
+
const { loadHostProvidersTable, projectHostFacingProvider } = await import("./public-cli/host-providers.js");
|
|
123
|
+
const hostFacingSelection = options.seat.selection === void 0 ? void 0 : projectHostFacingProvider(
|
|
124
|
+
options.seat.selection,
|
|
125
|
+
hostName,
|
|
126
|
+
loadHostProvidersTable(options.home),
|
|
127
|
+
options.home
|
|
128
|
+
);
|
|
125
129
|
return {
|
|
126
130
|
home: options.home,
|
|
127
131
|
principalAuthority,
|
|
@@ -131,7 +135,7 @@ async function createSummonEnv(options) {
|
|
|
131
135
|
roleTurnHost,
|
|
132
136
|
cwd: options.cwd,
|
|
133
137
|
credentials: options.credentials,
|
|
134
|
-
...
|
|
138
|
+
...hostFacingSelection === void 0 ? {} : { model: hostFacingSelection },
|
|
135
139
|
...projectSeatEngine(options.seat),
|
|
136
140
|
...projectSeatHost(options.seat)
|
|
137
141
|
};
|
package/package.json
CHANGED
package/souls/countersign.md
CHANGED
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
2 第二发源立法:
|
|
12
12
|
适用 ADR——由你自行检索,按票面触及的席位、接缝、术语在 docs/adr 与 CONTEXT.md 查全,票面引没引都算——并逐键列出其决策键;质量法、审刑院法典;
|
|
13
13
|
|
|
14
|
-
3 第二法源合法性检查:判断第二法源 以及 输入的
|
|
14
|
+
3 第二法源合法性检查:判断第二法源 以及 输入的 prompt等 对比第一法源是否有超出或不足,曲解。如有,除非有陛下原话批准,否则直接封驳 要求改正或陛下批准。
|
|
15
15
|
|
|
16
16
|
**二、相抵。** 票面,相关票与在飞分支与法源有无抵触。
|
|
17
17
|
|
package/souls/judge.md
CHANGED
|
@@ -1,68 +1,21 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
同查),然后落判词。判词与驳回须锚到具体法源;无可依法源时不得以「无法可依」
|
|
23
|
-
收敛,应上抛请立法。立案先于按派单收缩的审理范围。
|
|
24
|
-
|
|
25
|
-
**法源位阶:已落定 ADR 的具体决策在本仓优先于宪法通则;疑似违宪须核其所绑陛下原话与 decision key。已批断言不容翻。** 动过既有断言的改动须溯源到票面授权、ADR 或
|
|
26
|
-
先前裁定;权威仍在而相抵触即为 blocking。改动触及治理法文件(含 `docs/adr/`、
|
|
27
|
-
`CONTEXT.md`)而票面未授权时,实质审理并在判词中点名;确属宪法问题则上抛。
|
|
28
|
-
|
|
29
|
-
**全部提交物都是案面**:票面、计划、处置清单、packet、派单措辞与输入 prompt、
|
|
30
|
-
代码、测试。举证责任由所审材料决定,不由派单指定。
|
|
31
|
-
|
|
32
|
-
**审查范围绑定本次授权的 target/range**,覆盖范围内完整变更与未声明的生产
|
|
33
|
-
默认行为;不得因派单或票面清单缩减举证责任。派单非法缩 scope:可施工纠正判
|
|
34
|
-
`continue`;属陛下取舍、法源冲突或无法安全裁定判 `escalate`。
|
|
35
|
-
|
|
36
|
-
**落判前逐项过改动清单,与票面双向对表。** 每项改动标明由票面哪条驱动,
|
|
37
|
-
标不出来的即为夹带;票面有要求而清单没有的即为缺口(夹带的默认值、护栏、
|
|
38
|
-
平行机制、仅测试用的生产钩子同论)。多与少同为缺陷,逐条处置;清单未列全
|
|
39
|
-
不得收敛。
|
|
40
|
-
|
|
41
|
-
## 修理原则
|
|
42
|
-
|
|
43
|
-
删除或简化根因优先于增加平行机制。提出或批准护栏前必答三问:①哪个真实、
|
|
44
|
-
可复现的失败证明需要它?②哪个接缝拥有它要维护的不变式?③为什么删除或简化
|
|
45
|
-
根因不足以解决这类失败?
|
|
46
|
-
|
|
47
|
-
审查修复波及面,区分原始缺陷所需改动、修复引入后再修的改动和无依据的新机制;
|
|
48
|
-
后两类主导时优先删除/简化。超出本次授权的取舍必须上抛。**一轮轮只加不减的
|
|
49
|
-
修复流,本身就是该上报的病。**
|
|
50
|
-
|
|
51
|
-
**测试质量亲审。** 亲审测试是否忠实证明所主张行为并向 spec 负责;准绳唯 quality-law。
|
|
52
|
-
|
|
53
|
-
## 判词
|
|
54
|
-
|
|
55
|
-
合法判词只有三种,含义相对所审材料的举证责任:
|
|
56
|
-
|
|
57
|
-
- `converged` — 适用举证责任下的事项均已明确处置。修内司/将作监的提交,建议有
|
|
58
|
-
本轮御史台无 p2 及以上 finding 为辅证(p 级由你自行判定;被你驳回的不计数)。
|
|
59
|
-
- `continue` — 仍有可施工的问题;给出清晰、可验证的修理正文。
|
|
60
|
-
- `escalate` — 存在必须由陛下决定的门槛、相互冲突的法源,或依据失败走势
|
|
61
|
-
与专业证据已无法形成安全裁定;写明问题和可选项。
|
|
62
|
-
|
|
63
|
-
**送修正文由你执笔——判词即包。** 首轮可薄(finding + 法源锚点 + 边界);有
|
|
64
|
-
病史则综合(病史全列、方向可钉、拆除清单明文)。同缝反复、根因不明、范围
|
|
65
|
-
持续发散、疑跨接缝或 flake 即为发散,送修单中要求先做最小化、证据驱动的
|
|
66
|
-
诊断定根因。
|
|
67
|
-
|
|
68
|
-
送修仅含尚未结清、须派施工的根因类;已结清项、过程账与双向抽样不得入送修。
|
|
1
|
+
Judge Soul(大理寺)
|
|
2
|
+
你是大理寺。负责逐条裁决并判断是否收敛;不施工做修复。票庭归给事中
|
|
3
|
+
审理
|
|
4
|
+
一、立第一法源。 起居录、全局宪法,仓级治理文件,
|
|
5
|
+
二、立第二法源。自行查全相关 ADR(票面引了也不等于适用,自行判断。)、CONTEXT.md、票面、派单、输入的prompt等决策相关,你自身自带的质量/测试/审核等法典。
|
|
6
|
+
三、核第二法源:如有违反第一法源且没有陛下原话授权的,直接上呈。
|
|
7
|
+
四、核案。 全审本次授权的 target/range。计划、处置清单、packet、代码、测试都是案面,举证责任由材料决定,不由派单指定。
|
|
8
|
+
每项改动须有票面依据,每项要求须有落实或明确处置;相抵、夹带、缺口一并查(标不出来的即为夹带;有要求而清单没有的即为缺口(夹带的默认值、护栏、平行机制、仅测试用的生产钩子同论)),未授权改治理法文件,未声明的生产默认行为同论。清单不全不得收敛。复审亦全审授权范围,上轮问题不划定本轮案面。
|
|
9
|
+
五、裁断。 主张不是证据。一切 LLM 主张须亲验;当前事实只认当前 head,修复者自述不能替代新 head 上的机械验证与独立复查。出自机器执行,而非任何 LLM 之口的确定性事实,核指针加抽查即可。
|
|
10
|
+
事实与处方分判:事实成立而处方违法源,保留事实,驳回处方或另开合法处方。 每条问题显式记录和处置,严重度由你裁定,不因级别低而遗漏或暗降;裁决与驳回须锚定法源和证据。依当前一手证据独立双向抽样重推,误删与该删未删同查。
|
|
11
|
+
测试质量须亲审。取证与同类复核依《审法》;复杂度、测试质量与成本依《质量法》,不另立一套标准。
|
|
12
|
+
删简根因优先。提出或批准护栏,须说明真实可复现的失败、不变式所属接缝,以及为何删简根因不足。
|
|
13
|
+
区分原缺陷所需改动、修复自身造成的返工、无依据的新机制;后两类主导时优先拆除或简化。同缝反复、根因不明、范围发散、疑跨接缝或 flake,先做最小化、证据驱动的诊断,不继续猜修。一轮轮只加不减,本身就是须上报的问题。
|
|
14
|
+
判词
|
|
15
|
+
|
|
16
|
+
* converged——署:适用举证责任下的事项均已明确处置。施工提交推荐有本轮御史台无 p2 及以上 finding 为辅证,严重度由你裁定,已驳回的不计。
|
|
17
|
+
* continue——封驳:仍有授权内可纠正的问题,给出需修理的问题类别与法源,具体发现可作为案例/证据,不作施工白名单;授权范围内同类问题一并处置,超出授权的取舍上呈。一次扫净所有类别。
|
|
18
|
+
* escalate——上呈:缺少法源、法源冲突、取舍超出授权,或依据失败走势与证据已无法安全裁定;写明争点与选项。
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
封驳时 有病史须列全相关失败经过,钉明方向。送修只含未结清、须施工的根因类,不带已结清项、过程账和双向抽样记录。
|
package/souls/notary.md
CHANGED
package/src/public-cli/cli.ts
CHANGED
|
@@ -28,14 +28,17 @@ import {
|
|
|
28
28
|
setPersistentSeatConfig,
|
|
29
29
|
setPersistentSeatEngine,
|
|
30
30
|
setPersistentSeatHost,
|
|
31
|
-
setProviderHostAlias,
|
|
32
|
-
unsetProviderHostAlias,
|
|
33
31
|
validatePublicCliConfigAxes,
|
|
34
32
|
type CredentialProviders,
|
|
35
33
|
type EffectiveSeat,
|
|
36
34
|
type InvocationModelOverride,
|
|
37
35
|
type PublicCliConfig,
|
|
38
36
|
} from "./config.ts";
|
|
37
|
+
import {
|
|
38
|
+
loadHostProvidersTable,
|
|
39
|
+
projectHostFacingProvider,
|
|
40
|
+
renderHostProvidersTable,
|
|
41
|
+
} from "./host-providers.ts";
|
|
39
42
|
import { seatModelOnly } from "./registry.ts";
|
|
40
43
|
import { CliUsageError } from "./cli-errors.ts";
|
|
41
44
|
import type { CliIo } from "./cli-io.ts";
|
|
@@ -428,23 +431,36 @@ function createRoleEnvironment(
|
|
|
428
431
|
|
|
429
432
|
// #617 DK-3: resume and new legs share one seat resolution — model/host/engine
|
|
430
433
|
// come from the live seat table (invocation flag → persistent → default).
|
|
434
|
+
// #788 expectation 2: select a registered host first; only then project the
|
|
435
|
+
// host-facing provider (table > unique directory > fail). Bad host never
|
|
436
|
+
// reaches model resolution.
|
|
437
|
+
const roleTurnHost = resolveRoleTurnHost(env, {
|
|
438
|
+
role,
|
|
439
|
+
seat: options.seat,
|
|
440
|
+
principalAuthority: env.principalAuthority!,
|
|
441
|
+
...(extraPiArgs === undefined ? {} : { extraPiArgs }),
|
|
442
|
+
...(timeoutMs === undefined ? {} : { timeoutMs }),
|
|
443
|
+
});
|
|
444
|
+
const hostFacingSelection =
|
|
445
|
+
options.seat.selection === undefined
|
|
446
|
+
? undefined
|
|
447
|
+
: projectHostFacingProvider(
|
|
448
|
+
options.seat.selection,
|
|
449
|
+
options.seat.host,
|
|
450
|
+
loadHostProvidersTable(options.home),
|
|
451
|
+
options.home,
|
|
452
|
+
);
|
|
431
453
|
return {
|
|
432
454
|
home: options.home,
|
|
433
455
|
principalAuthority: env.principalAuthority!,
|
|
434
456
|
agentDir: options.agentDir,
|
|
435
457
|
sessionAppender: appendPiSessionCustomEntry,
|
|
436
458
|
packageRoot: env.packageRoot,
|
|
437
|
-
roleTurnHost
|
|
438
|
-
role,
|
|
439
|
-
seat: options.seat,
|
|
440
|
-
principalAuthority: env.principalAuthority!,
|
|
441
|
-
...(extraPiArgs === undefined ? {} : { extraPiArgs }),
|
|
442
|
-
...(timeoutMs === undefined ? {} : { timeoutMs }),
|
|
443
|
-
}),
|
|
459
|
+
roleTurnHost,
|
|
444
460
|
cwd: options.cwd,
|
|
445
461
|
...(options.credentials === undefined ? {} : { credentials: options.credentials }),
|
|
446
462
|
...(env.correlationId === undefined ? {} : { correlationId: env.correlationId }),
|
|
447
|
-
...(
|
|
463
|
+
...(hostFacingSelection === undefined ? {} : { model: hostFacingSelection }),
|
|
448
464
|
...projectSeatEngine(options.seat),
|
|
449
465
|
...projectSeatHost(options.seat),
|
|
450
466
|
...(timeoutMs === undefined ? {} : { timeoutMs }),
|
|
@@ -771,7 +787,7 @@ function renderHelp(): string {
|
|
|
771
787
|
"Persistent config: ak-role config set <seat> <provider/model[:thinking]> | unset <gatekeeper|inspector|notary>",
|
|
772
788
|
"Persistent engine (callable roles): ak-role config set-engine <seat> <name> | unset-engine <seat>",
|
|
773
789
|
"Persistent host (callable roles): ak-role config set-host <seat> <name> | unset-host <seat>",
|
|
774
|
-
"
|
|
790
|
+
"Host providers: ~/.ak-roles/host-providers.json (owner-edited; table > unique host directory > fail)",
|
|
775
791
|
"Host resolution: --host → persistent seat host → pi (resume uses the same order; #617)",
|
|
776
792
|
"Effective seats: ak-role roles",
|
|
777
793
|
);
|
|
@@ -900,7 +916,7 @@ function renderConfigDisplaySeat(row: ConfigDisplaySeat): string {
|
|
|
900
916
|
return `${row.seat}\t${row.source}\t${model}\t${engine}\t${host}`;
|
|
901
917
|
}
|
|
902
918
|
|
|
903
|
-
function renderConfig(config: PublicCliConfig): string {
|
|
919
|
+
function renderConfig(config: PublicCliConfig, home: string): string {
|
|
904
920
|
const lines: string[] = ["seat\tsource\tmodel\tengine\thost"];
|
|
905
921
|
const rows = projectConfigDisplaySeats(config);
|
|
906
922
|
if (rows.length === 0) {
|
|
@@ -912,17 +928,9 @@ function renderConfig(config: PublicCliConfig): string {
|
|
|
912
928
|
}
|
|
913
929
|
// #422: show the effective auto-resume ceiling (configured value or default).
|
|
914
930
|
lines.push(`autoResumeLimit\t${config.autoResumeLimit ?? AUTO_RESUME_LIMIT}`);
|
|
915
|
-
// #
|
|
916
|
-
const
|
|
917
|
-
|
|
918
|
-
for (const provider of Object.keys(aliases).sort()) {
|
|
919
|
-
const byHost = aliases[provider]!;
|
|
920
|
-
for (const host of Object.keys(byHost).sort()) {
|
|
921
|
-
lines.push(`providerAlias\t${provider}\t${host}\t${byHost[host]}`);
|
|
922
|
-
}
|
|
923
|
-
}
|
|
924
|
-
}
|
|
925
|
-
return `${lines.join("\n")}\n`;
|
|
931
|
+
// #788: owner host-providers table as written on disk (separate file).
|
|
932
|
+
const hostProvidersBlock = renderHostProvidersTable(loadHostProvidersTable(home));
|
|
933
|
+
return `${lines.join("\n")}\n${hostProvidersBlock}`;
|
|
926
934
|
}
|
|
927
935
|
|
|
928
936
|
async function runConfigCommand(
|
|
@@ -942,7 +950,7 @@ async function runConfigCommand(
|
|
|
942
950
|
);
|
|
943
951
|
return 0;
|
|
944
952
|
}
|
|
945
|
-
io.stdout(renderConfig(config));
|
|
953
|
+
io.stdout(renderConfig(config, home));
|
|
946
954
|
return 0;
|
|
947
955
|
}
|
|
948
956
|
|
|
@@ -971,7 +979,7 @@ async function runConfigCommand(
|
|
|
971
979
|
config = setPersistentSeatConfig(config, seat, parseModelSpec(spec));
|
|
972
980
|
}
|
|
973
981
|
await savePublicCliConfig(config, home);
|
|
974
|
-
io.stdout(renderConfig(config));
|
|
982
|
+
io.stdout(renderConfig(config, home));
|
|
975
983
|
return 0;
|
|
976
984
|
}
|
|
977
985
|
|
|
@@ -993,7 +1001,7 @@ async function runConfigCommand(
|
|
|
993
1001
|
seat,
|
|
994
1002
|
);
|
|
995
1003
|
await savePublicCliConfig(config, home);
|
|
996
|
-
io.stdout(renderConfig(config));
|
|
1004
|
+
io.stdout(renderConfig(config, home));
|
|
997
1005
|
return 0;
|
|
998
1006
|
}
|
|
999
1007
|
|
|
@@ -1011,7 +1019,7 @@ async function runConfigCommand(
|
|
|
1011
1019
|
throw new CliUsageError(error instanceof Error ? error.message : String(error), { cause: error });
|
|
1012
1020
|
}
|
|
1013
1021
|
await savePublicCliConfig(config, home);
|
|
1014
|
-
io.stdout(renderConfig(config));
|
|
1022
|
+
io.stdout(renderConfig(config, home));
|
|
1015
1023
|
return 0;
|
|
1016
1024
|
}
|
|
1017
1025
|
|
|
@@ -1035,7 +1043,7 @@ async function runConfigCommand(
|
|
|
1035
1043
|
);
|
|
1036
1044
|
}
|
|
1037
1045
|
await savePublicCliConfig(config, home);
|
|
1038
|
-
io.stdout(renderConfig(config));
|
|
1046
|
+
io.stdout(renderConfig(config, home));
|
|
1039
1047
|
return 0;
|
|
1040
1048
|
}
|
|
1041
1049
|
|
|
@@ -1057,7 +1065,7 @@ async function runConfigCommand(
|
|
|
1057
1065
|
);
|
|
1058
1066
|
}
|
|
1059
1067
|
await savePublicCliConfig(config, home);
|
|
1060
|
-
io.stdout(renderConfig(config));
|
|
1068
|
+
io.stdout(renderConfig(config, home));
|
|
1061
1069
|
return 0;
|
|
1062
1070
|
}
|
|
1063
1071
|
|
|
@@ -1090,48 +1098,7 @@ async function runConfigCommand(
|
|
|
1090
1098
|
let config = await loadAndValidateConfig(home, packageRoot);
|
|
1091
1099
|
config = setAutoResumeLimit(config, converted);
|
|
1092
1100
|
await savePublicCliConfig(config, home);
|
|
1093
|
-
io.stdout(renderConfig(config));
|
|
1094
|
-
return 0;
|
|
1095
|
-
}
|
|
1096
|
-
|
|
1097
|
-
// #778: owner-registered provider→host alias (opaque strings; no host catalog).
|
|
1098
|
-
if (args[0] === "set-provider-alias") {
|
|
1099
|
-
if (args.length !== 4) {
|
|
1100
|
-
throw new CliUsageError(
|
|
1101
|
-
"usage: ak-role config set-provider-alias <provider> <host> <alias>",
|
|
1102
|
-
);
|
|
1103
|
-
}
|
|
1104
|
-
let config = await loadAndValidateConfig(home, packageRoot);
|
|
1105
|
-
try {
|
|
1106
|
-
config = setProviderHostAlias(config, args[1]!, args[2]!, args[3]!);
|
|
1107
|
-
} catch (error) {
|
|
1108
|
-
throw new CliUsageError(
|
|
1109
|
-
error instanceof Error ? error.message : String(error),
|
|
1110
|
-
{ cause: error },
|
|
1111
|
-
);
|
|
1112
|
-
}
|
|
1113
|
-
await savePublicCliConfig(config, home);
|
|
1114
|
-
io.stdout(renderConfig(config));
|
|
1115
|
-
return 0;
|
|
1116
|
-
}
|
|
1117
|
-
|
|
1118
|
-
if (args[0] === "unset-provider-alias") {
|
|
1119
|
-
if (args.length !== 3) {
|
|
1120
|
-
throw new CliUsageError(
|
|
1121
|
-
"usage: ak-role config unset-provider-alias <provider> <host>",
|
|
1122
|
-
);
|
|
1123
|
-
}
|
|
1124
|
-
let config = await loadAndValidateConfig(home, packageRoot);
|
|
1125
|
-
try {
|
|
1126
|
-
config = unsetProviderHostAlias(config, args[1]!, args[2]!);
|
|
1127
|
-
} catch (error) {
|
|
1128
|
-
throw new CliUsageError(
|
|
1129
|
-
error instanceof Error ? error.message : String(error),
|
|
1130
|
-
{ cause: error },
|
|
1131
|
-
);
|
|
1132
|
-
}
|
|
1133
|
-
await savePublicCliConfig(config, home);
|
|
1134
|
-
io.stdout(renderConfig(config));
|
|
1101
|
+
io.stdout(renderConfig(config, home));
|
|
1135
1102
|
return 0;
|
|
1136
1103
|
}
|
|
1137
1104
|
|
package/src/public-cli/config.ts
CHANGED
|
@@ -54,15 +54,6 @@ export type PersistentSeatConfig = {
|
|
|
54
54
|
host?: string;
|
|
55
55
|
};
|
|
56
56
|
|
|
57
|
-
/**
|
|
58
|
-
* #778: owner-registered provider name by host. Keyed seat-table provider →
|
|
59
|
-
* host → host-facing provider. Package code carries the map only — no built-in
|
|
60
|
-
* pairs. Unregistered (provider, host) pairs pass the seat provider through.
|
|
61
|
-
*/
|
|
62
|
-
export type ProviderHostAliases = Readonly<
|
|
63
|
-
Record<string, Readonly<Record<string, string>>>
|
|
64
|
-
>;
|
|
65
|
-
|
|
66
57
|
export type PublicCliConfig = {
|
|
67
58
|
seats: Partial<Record<PublicConfigurableSeat, PersistentSeatConfig>>;
|
|
68
59
|
/**
|
|
@@ -72,11 +63,6 @@ export type PublicCliConfig = {
|
|
|
72
63
|
* bound (ADR 0035).
|
|
73
64
|
*/
|
|
74
65
|
autoResumeLimit?: number;
|
|
75
|
-
/**
|
|
76
|
-
* #778: owner-registered provider→host aliases. Sibling of `seats`; never
|
|
77
|
-
* invents pairs. Absent or empty means pure pass-through.
|
|
78
|
-
*/
|
|
79
|
-
providerAliases?: ProviderHostAliases;
|
|
80
66
|
/**
|
|
81
67
|
* #592: opaque seat rows this build does not own. Carried through every
|
|
82
68
|
* parse→save cycle so a write never silently erases neighboring-line rows
|
|
@@ -307,81 +293,6 @@ export function setAutoResumeLimit(
|
|
|
307
293
|
return { ...config, autoResumeLimit: parseAutoResumeLimit(limit) };
|
|
308
294
|
}
|
|
309
295
|
|
|
310
|
-
function requireNonEmptyToken(value: string, label: string): string {
|
|
311
|
-
const trimmed = value.trim();
|
|
312
|
-
if (trimmed === "") {
|
|
313
|
-
throw new Error(`${label} must be a non-empty string`);
|
|
314
|
-
}
|
|
315
|
-
return trimmed;
|
|
316
|
-
}
|
|
317
|
-
|
|
318
|
-
/**
|
|
319
|
-
* #778: register one owner provider→host alias. Opaque strings only — no host
|
|
320
|
-
* catalog check and no built-in provider pairs. Sibling keys (seats included)
|
|
321
|
-
* are preserved.
|
|
322
|
-
*/
|
|
323
|
-
export function setProviderHostAlias(
|
|
324
|
-
config: PublicCliConfig,
|
|
325
|
-
provider: string,
|
|
326
|
-
host: string,
|
|
327
|
-
alias: string,
|
|
328
|
-
): PublicCliConfig {
|
|
329
|
-
const from = requireNonEmptyToken(provider, "provider");
|
|
330
|
-
const hostName = requireNonEmptyToken(host, "host");
|
|
331
|
-
const to = requireNonEmptyToken(alias, "alias");
|
|
332
|
-
const previous = config.providerAliases ?? {};
|
|
333
|
-
return {
|
|
334
|
-
...config,
|
|
335
|
-
providerAliases: {
|
|
336
|
-
...previous,
|
|
337
|
-
[from]: {
|
|
338
|
-
...(previous[from] ?? {}),
|
|
339
|
-
[hostName]: to,
|
|
340
|
-
},
|
|
341
|
-
},
|
|
342
|
-
};
|
|
343
|
-
}
|
|
344
|
-
|
|
345
|
-
/** #778: drop one owner provider→host alias. Empty map collapses to absent. */
|
|
346
|
-
export function unsetProviderHostAlias(
|
|
347
|
-
config: PublicCliConfig,
|
|
348
|
-
provider: string,
|
|
349
|
-
host: string,
|
|
350
|
-
): PublicCliConfig {
|
|
351
|
-
const from = requireNonEmptyToken(provider, "provider");
|
|
352
|
-
const hostName = requireNonEmptyToken(host, "host");
|
|
353
|
-
const previous = config.providerAliases;
|
|
354
|
-
if (previous === undefined || previous[from] === undefined) return config;
|
|
355
|
-
const { [hostName]: _dropped, ...restHosts } = previous[from]!;
|
|
356
|
-
const nextForProvider =
|
|
357
|
-
Object.keys(restHosts).length === 0 ? undefined : restHosts;
|
|
358
|
-
const { [from]: _provider, ...restProviders } = previous;
|
|
359
|
-
const nextAliases =
|
|
360
|
-
nextForProvider === undefined
|
|
361
|
-
? restProviders
|
|
362
|
-
: { ...restProviders, [from]: nextForProvider };
|
|
363
|
-
if (Object.keys(nextAliases).length === 0) {
|
|
364
|
-
const { providerAliases: _gone, ...rest } = config;
|
|
365
|
-
return rest;
|
|
366
|
-
}
|
|
367
|
-
return { ...config, providerAliases: nextAliases };
|
|
368
|
-
}
|
|
369
|
-
|
|
370
|
-
/**
|
|
371
|
-
* #778: project seat-table provider through owner aliases for one host.
|
|
372
|
-
* Unregistered pairs return the seat selection unchanged (pass-through).
|
|
373
|
-
*/
|
|
374
|
-
export function applyProviderHostAlias(
|
|
375
|
-
selection: SeatModelConfig | undefined,
|
|
376
|
-
host: string,
|
|
377
|
-
aliases: ProviderHostAliases | undefined,
|
|
378
|
-
): SeatModelConfig | undefined {
|
|
379
|
-
if (selection === undefined || aliases === undefined) return selection;
|
|
380
|
-
const mapped = aliases[selection.provider]?.[host];
|
|
381
|
-
if (mapped === undefined) return selection;
|
|
382
|
-
return { ...selection, provider: mapped };
|
|
383
|
-
}
|
|
384
|
-
|
|
385
296
|
/**
|
|
386
297
|
* Config-parse seam: persistent call axes belong to PUBLIC_CALLABLE_ROLES;
|
|
387
298
|
* engine names need only path-safety syntax (no closed material catalog;
|
|
@@ -476,7 +387,6 @@ export function buildSeatModelCliArgs(model: SeatModelConfig | undefined): strin
|
|
|
476
387
|
function serializePublicCliConfig(config: PublicCliConfig): {
|
|
477
388
|
seats: Record<string, unknown>;
|
|
478
389
|
autoResumeLimit?: number;
|
|
479
|
-
providerAliases?: ProviderHostAliases;
|
|
480
390
|
} {
|
|
481
391
|
return {
|
|
482
392
|
// Known seats win on any key clash; by construction the two maps are
|
|
@@ -488,48 +398,9 @@ function serializePublicCliConfig(config: PublicCliConfig): {
|
|
|
488
398
|
...(config.autoResumeLimit === undefined
|
|
489
399
|
? {}
|
|
490
400
|
: { autoResumeLimit: config.autoResumeLimit }),
|
|
491
|
-
...(config.providerAliases === undefined ||
|
|
492
|
-
Object.keys(config.providerAliases).length === 0
|
|
493
|
-
? {}
|
|
494
|
-
: { providerAliases: config.providerAliases }),
|
|
495
401
|
};
|
|
496
402
|
}
|
|
497
403
|
|
|
498
|
-
function parseProviderHostAliases(value: unknown): ProviderHostAliases {
|
|
499
|
-
if (value === null || typeof value !== "object" || Array.isArray(value)) {
|
|
500
|
-
throw new Error("public CLI config.providerAliases must be an object");
|
|
501
|
-
}
|
|
502
|
-
const out: Record<string, Record<string, string>> = {};
|
|
503
|
-
for (const [provider, byHost] of Object.entries(value as Record<string, unknown>)) {
|
|
504
|
-
if (provider.trim() === "") {
|
|
505
|
-
throw new Error("public CLI config.providerAliases provider key must be non-empty");
|
|
506
|
-
}
|
|
507
|
-
if (byHost === null || typeof byHost !== "object" || Array.isArray(byHost)) {
|
|
508
|
-
throw new Error(
|
|
509
|
-
`public CLI config.providerAliases[${provider}] must be an object`,
|
|
510
|
-
);
|
|
511
|
-
}
|
|
512
|
-
const hosts: Record<string, string> = {};
|
|
513
|
-
for (const [host, alias] of Object.entries(byHost as Record<string, unknown>)) {
|
|
514
|
-
if (host.trim() === "") {
|
|
515
|
-
throw new Error(
|
|
516
|
-
`public CLI config.providerAliases[${provider}] host key must be non-empty`,
|
|
517
|
-
);
|
|
518
|
-
}
|
|
519
|
-
if (typeof alias !== "string" || alias.trim() === "") {
|
|
520
|
-
throw new Error(
|
|
521
|
-
`public CLI config.providerAliases[${provider}][${host}] must be a non-empty string`,
|
|
522
|
-
);
|
|
523
|
-
}
|
|
524
|
-
hosts[host] = alias;
|
|
525
|
-
}
|
|
526
|
-
if (Object.keys(hosts).length > 0) {
|
|
527
|
-
out[provider] = hosts;
|
|
528
|
-
}
|
|
529
|
-
}
|
|
530
|
-
return out;
|
|
531
|
-
}
|
|
532
|
-
|
|
533
404
|
function parsePublicCliConfig(value: unknown): PublicCliConfig {
|
|
534
405
|
if (value === null || typeof value !== "object" || Array.isArray(value)) {
|
|
535
406
|
throw new Error("public CLI config must be an object");
|
|
@@ -537,7 +408,6 @@ function parsePublicCliConfig(value: unknown): PublicCliConfig {
|
|
|
537
408
|
const record = value as {
|
|
538
409
|
seats?: unknown;
|
|
539
410
|
autoResumeLimit?: unknown;
|
|
540
|
-
providerAliases?: unknown;
|
|
541
411
|
unknownSeats?: unknown;
|
|
542
412
|
};
|
|
543
413
|
// #422 round-trip preservation: the sibling top-level key must survive every
|
|
@@ -546,15 +416,6 @@ function parsePublicCliConfig(value: unknown): PublicCliConfig {
|
|
|
546
416
|
if (record.autoResumeLimit !== undefined) {
|
|
547
417
|
autoResumeLimit = parseAutoResumeLimit(record.autoResumeLimit);
|
|
548
418
|
}
|
|
549
|
-
// #778: same survival duty as autoResumeLimit — owner aliases must not vanish
|
|
550
|
-
// on an unrelated seat write.
|
|
551
|
-
let providerAliases: ProviderHostAliases | undefined;
|
|
552
|
-
if (record.providerAliases !== undefined) {
|
|
553
|
-
const parsed = parseProviderHostAliases(record.providerAliases);
|
|
554
|
-
if (Object.keys(parsed).length > 0) {
|
|
555
|
-
providerAliases = parsed;
|
|
556
|
-
}
|
|
557
|
-
}
|
|
558
419
|
// #592: opaque bucket may already be present on an in-memory round-trip
|
|
559
420
|
// (load→set→save calls parse again). Carry it before seats iteration so a
|
|
560
421
|
// disk-shaped seats map and a memory-shaped bucket both survive.
|
|
@@ -572,7 +433,6 @@ function parsePublicCliConfig(value: unknown): PublicCliConfig {
|
|
|
572
433
|
const withOpaque = (seats: PublicCliConfig["seats"]): PublicCliConfig => ({
|
|
573
434
|
seats,
|
|
574
435
|
...(autoResumeLimit === undefined ? {} : { autoResumeLimit }),
|
|
575
|
-
...(providerAliases === undefined ? {} : { providerAliases }),
|
|
576
436
|
...(Object.keys(unknownSeats).length === 0 ? {} : { unknownSeats }),
|
|
577
437
|
});
|
|
578
438
|
if (record.seats === undefined) {
|
|
@@ -818,23 +678,13 @@ export function resolveEffectiveSeat(
|
|
|
818
678
|
}
|
|
819
679
|
}
|
|
820
680
|
|
|
821
|
-
|
|
681
|
+
// Seat axes only. Host-facing provider projection (#788) runs after the host
|
|
682
|
+
// is selected as registered — never before (bad host must not reach model).
|
|
683
|
+
return attachHostAxis(
|
|
822
684
|
attachEngineAxis(modelSeat, config, invocation),
|
|
823
685
|
config,
|
|
824
686
|
invocation,
|
|
825
687
|
);
|
|
826
|
-
// #778: host-facing provider is the seat-table value after owner aliases.
|
|
827
|
-
// Disk seats stay as written; only the effective selection is projected.
|
|
828
|
-
const selection = applyProviderHostAlias(
|
|
829
|
-
withAxes.selection,
|
|
830
|
-
withAxes.host,
|
|
831
|
-
config.providerAliases,
|
|
832
|
-
);
|
|
833
|
-
if (selection === undefined) {
|
|
834
|
-
const { selection: _dropped, ...rest } = withAxes;
|
|
835
|
-
return rest;
|
|
836
|
-
}
|
|
837
|
-
return { ...withAxes, selection };
|
|
838
688
|
}
|
|
839
689
|
|
|
840
690
|
export function effectiveSeatConfigurations(
|