@akagilnc/pi-workflow-roles 0.1.5357 → 0.1.5368

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.
Files changed (43) hide show
  1. package/dist/acp-host/production-host.js +5353 -5480
  2. package/dist/doctor-contracts.js +22 -34
  3. package/dist/headless-host/production-host.js +1215 -1342
  4. package/dist/merger-contracts.js +11 -6
  5. package/dist/migrate-book-topology.js +57 -101
  6. package/dist/open-tool-schema.js +1 -25
  7. package/dist/package-contracts/fixer-output.js +21 -35
  8. package/dist/public-cli/auto-resume.js +1 -1
  9. package/dist/public-cli/cli.js +57 -56
  10. package/dist/public-cli/config.js +4 -0
  11. package/dist/public-cli/instruction-seat-run.js +65 -40
  12. package/dist/public-cli/invocation.js +132 -128
  13. package/dist/public-cli/main.js +449 -506
  14. package/dist/public-cli/post-admission.js +85 -86
  15. package/dist/public-cli/role-seat-runtime.js +29 -0
  16. package/dist/public-cli/run-lifecycle.js +6 -6
  17. package/dist/public-cli/turn-request.js +14 -0
  18. package/dist/public-role-summons.js +20 -33
  19. package/dist/role-run-placement.js +4 -0
  20. package/package.json +1 -1
  21. package/src/book-topology-migration-placement.ts +3 -5
  22. package/src/diarist-role.ts +12 -49
  23. package/src/doctor-contracts.ts +38 -49
  24. package/src/gleaner-left-role.ts +10 -11
  25. package/src/merger-contracts.ts +19 -12
  26. package/src/open-tool-schema.ts +8 -32
  27. package/src/package-contracts/fixer-output.ts +49 -52
  28. package/src/public-cli/auto-resume.ts +1 -1
  29. package/src/public-cli/cli.ts +67 -73
  30. package/src/public-cli/config.ts +8 -0
  31. package/src/public-cli/instruction-seat-run.ts +82 -55
  32. package/src/public-cli/invocation.ts +148 -162
  33. package/src/public-cli/post-admission.ts +110 -100
  34. package/src/public-cli/role-seat-runtime.ts +72 -0
  35. package/src/public-cli/run-lifecycle.ts +7 -26
  36. package/src/public-cli/terminal.ts +2 -17
  37. package/src/public-cli/turn-request.ts +26 -0
  38. package/src/public-role-summons.ts +20 -45
  39. package/src/reviewer-role.ts +16 -35
  40. package/src/role-run-placement.ts +5 -0
  41. package/src/secretariat-role.ts +16 -12
  42. package/src/worker-role.ts +14 -29
  43. package/src/worker-submission-gates.ts +14 -3
@@ -10,6 +10,7 @@ import { writeFile } from "node:fs/promises";
10
10
  import { isAbsolute, join, resolve } from "node:path";
11
11
  import { buildAutoResumeContinuationPrompt, findRunDirectoryById, readRoleRunState, RESUME_TRANSPORT_ENVELOPE, } from "./run-lifecycle.js";
12
12
  import { CliUsageError } from "./cli-errors.js";
13
+ import { projectPublicTurnAxes } from "./turn-request.js";
13
14
  import { bindAdmittedTicketNumber, buildInstructionTransportPrompt, freezeAttachmentsIntoRun, relocateAdmittedRunToTicket, } from "./invocation.js";
14
15
  import { readRecordedSubmissionRows } from "../submission-ledger.js";
15
16
  import { readDeclaredTicketNumber } from "../run-ticket-number.js";
@@ -41,7 +42,7 @@ import { homeFromRunDirectory } from "../activation-ledger-topology.js";
41
42
  import { recordRunStart } from "../host-session-record.js";
42
43
  import { attemptProducedFreshSubmission, classifyPostAdmissionFailure, controlledFailureInputFromResolution, exitCodeForTerminalOutcome, explicitInternalKnownFailureClassificationInput, formatCliDiagnostic, formatErrorCauseDetail, formatTerminalResult, inspectJudgeSession, isLawfulTypedTerminalOutcome, presentFailureTerminal, publishedFailureErrorPath, presentStructuralRejection, resolveAuditedRunnerFailureResolution, resolveControlledFailureResumeObservation, settleFailureTerminalResult, settleHostEndedNoReceipt, attachRecordedSubmissions, rewritePublishedFailureErrorPath, } from "./settlement.js";
43
44
  import {} from "./terminal.js";
44
- import { ensureRealArtifactsDirectory, persistReturnedRunState, runWithAutoResumeLoop, TurnDispatchedFailure, } from "./auto-resume.js";
45
+ import { ensureRealArtifactsDirectory, persistReturnedRunState, runWithAutoResumeLoop, TurnDispatchedFailure, writeHardenedArtifactFile, } from "./auto-resume.js";
45
46
  function projectRelocatedTurnIdentity(request, result, admitted, relocation) {
46
47
  const rewrite = (value) => rewriteRunDirectoryPathValue(value, relocation.oldRunDirectory, relocation.newRunDirectory);
47
48
  const mutableRequest = request;
@@ -131,7 +132,10 @@ async function recordBestEffortPostDispatchDiagnostic(admitted, env, diagnostic,
131
132
  catch (appendError) {
132
133
  try {
133
134
  const artifactsDir = await ensureRealArtifactsDirectory(admitted.runDirectory);
134
- await writeFile(join(artifactsDir, `post-admission-diagnostic-${randomUUID()}.json`), `${JSON.stringify({ version: 1, ...payload }, null, 2)}\n`, { encoding: "utf8", flag: "wx" });
135
+ await writeHardenedArtifactFile(artifactsDir, "post-admission-diagnostic", {
136
+ version: 1,
137
+ ...payload,
138
+ });
135
139
  }
136
140
  catch (artifactError) {
137
141
  retentionFailure =
@@ -817,13 +821,8 @@ export function resumeTurnRequestProjectionOptions(admitted, request, env, summo
817
821
  prompt = "";
818
822
  }
819
823
  return {
820
- packageRoot: env.packageRoot,
821
- home: env.home,
824
+ ...projectPublicTurnAxes(env),
822
825
  ...(env.host === undefined ? {} : { host: env.host }),
823
- agentDir: env.agentDir,
824
- ...(env.model === undefined ? {} : { model: env.model }),
825
- ...pickEngineAxis(env),
826
- ...(env.timeoutMs === undefined ? {} : { timeoutMs: env.timeoutMs }),
827
826
  ...(env.correlationId === undefined && admitted.correlationId === undefined
828
827
  ? {}
829
828
  : { correlationId: env.correlationId ?? admitted.correlationId }),
@@ -839,13 +838,8 @@ export function resumeTurnRequestProjectionOptions(admitted, request, env, summo
839
838
  export function roleTurnOptions(env, admitted, continuation) {
840
839
  const correlationId = env.correlationId ?? admitted.correlationId;
841
840
  return {
842
- packageRoot: env.packageRoot,
843
- home: env.home,
841
+ ...projectPublicTurnAxes(env),
844
842
  ...(env.host === undefined ? {} : { host: env.host }),
845
- agentDir: env.agentDir,
846
- ...(env.model === undefined ? {} : { model: env.model }),
847
- ...pickEngineAxis(env),
848
- ...(env.timeoutMs === undefined ? {} : { timeoutMs: env.timeoutMs }),
849
843
  ...(correlationId === undefined || correlationId.trim() === ""
850
844
  ? {}
851
845
  : { correlationId }),
@@ -872,6 +866,44 @@ async function dispatchAfterWriterLease(input) {
872
866
  }
873
867
  }
874
868
  }
869
+ /**
870
+ * One auto-resume dispatch: deferred run-state persist settles on the same
871
+ * path for station-child and ordinary in-call retries. The caller owns how
872
+ * the turn request is built and which correlation id the env carries.
873
+ */
874
+ async function runSettledAutoResumeLoop(input) {
875
+ const adapters = withOnceSuccessfulBeforeDispatch(input.adapters);
876
+ const dispatchEnv = input.dispatchEnv ?? input.env;
877
+ return runWithAutoResumeLoop({
878
+ admitted: input.admitted,
879
+ principalAuthority: input.env.principalAuthority,
880
+ io: input.io,
881
+ sessionAppender: input.env.sessionAppender,
882
+ autoResumeLimit: input.env.autoResumeLimit,
883
+ ...(input.env.signal === undefined ? {} : { signal: input.env.signal }),
884
+ buildInitialPayload: input.buildInitialPayload,
885
+ buildResumePayload: input.buildResumePayload,
886
+ dispatch: async (payload, lease, _isFirst, attemptIo) => dispatchAfterWriterLease({
887
+ ...(lease === undefined ? {} : { lease }),
888
+ build: () => input.toRequest(payload),
889
+ dispatch: async (request) => {
890
+ const result = await dispatchPostAdmissionTurn({
891
+ admitted: input.admitted,
892
+ env: dispatchEnv,
893
+ io: attemptIo,
894
+ request,
895
+ ...(lease === undefined ? {} : { lease }),
896
+ adapters,
897
+ persistRunState: false,
898
+ ...(input.effectiveEngine === undefined
899
+ ? {}
900
+ : { effectiveEngine: input.effectiveEngine }),
901
+ });
902
+ return settleDeferredPersist(input.admitted, input.env.principalAuthority, adapters, attemptIo, result);
903
+ },
904
+ }),
905
+ });
906
+ }
875
907
  function isAlreadyFrozenSummonsAttachment(runDirectory, attachmentPath) {
876
908
  const absolute = isAbsolute(attachmentPath)
877
909
  ? attachmentPath
@@ -1018,65 +1050,45 @@ export async function runPostAdmissionSeatResume(input) {
1018
1050
  try {
1019
1051
  if (env.stationChild === true) {
1020
1052
  let firstTurn;
1021
- const stationAdapters = withOnceSuccessfulBeforeDispatch(adapters);
1022
1053
  // One public call → one detour scope across in-place auto-resume dispatches.
1023
1054
  const invocationScopeId = mintEngineDetourInvocationScope({
1024
1055
  ...(input.effectiveEngine === undefined
1025
1056
  ? {}
1026
1057
  : { effectiveEngine: input.effectiveEngine }),
1027
1058
  });
1028
- return await runWithAutoResumeLoop({
1059
+ return await runSettledAutoResumeLoop({
1029
1060
  admitted: loaded.admitted,
1030
- principalAuthority: env.principalAuthority,
1061
+ env,
1031
1062
  io: input.io,
1032
- sessionAppender: env.sessionAppender,
1033
- autoResumeLimit: env.autoResumeLimit,
1034
- ...(env.signal === undefined ? {} : { signal: env.signal }),
1063
+ adapters,
1064
+ ...(input.effectiveEngine === undefined
1065
+ ? {}
1066
+ : { effectiveEngine: input.effectiveEngine }),
1035
1067
  buildInitialPayload: () => ({ resumeTurn: false }),
1036
1068
  buildResumePayload: () => ({ resumeTurn: true }),
1037
- // Same as public manual resume: prior-court sealed acceptance is not a
1038
- // redispatch brake (#833). New-court station-child turns still auto-resume.
1039
- dispatch: async (payload, lease, _isFirst, attemptIo) => dispatchAfterWriterLease({
1040
- ...(lease === undefined ? {} : { lease }),
1041
- build: async () => {
1042
- // #840 r8 判词 class 2: this call-local retry must keep this
1043
- // court's frozen summons / 交卷 body / attachments verbatim
1044
- // (same object as firstTurn) and project only the minimal
1045
- // host-needed resume trigger — never engine handbook material,
1046
- // which would replace a 审核循环 same-ticket continuation with a bare outsourcing
1047
- // 「重新读」 envelope (#755 contract, resumeTurnRequestProjectionOptions
1048
- // above). RESUME_TRANSPORT_ENVELOPE is the same package-owned,
1049
- // non-semantic trigger that projection already uses for a
1050
- // same-ticket summons carrying no instruction/attachments.
1051
- if (payload.resumeTurn && firstTurn !== undefined) {
1052
- return {
1053
- ...firstTurn,
1054
- continuation: {
1055
- kind: "resume",
1056
- prompt: RESUME_TRANSPORT_ENVELOPE,
1057
- },
1058
- };
1059
- }
1060
- const turnRequest = withEngineDetourInvocationScope(await buildRequestAfterLease(), invocationScopeId);
1061
- firstTurn = turnRequest;
1062
- return turnRequest;
1063
- },
1064
- dispatch: async (turnRequest) => {
1065
- const result = await dispatchPostAdmissionTurn({
1066
- admitted: loaded.admitted,
1067
- env,
1068
- io: attemptIo,
1069
- request: turnRequest,
1070
- ...(lease === undefined ? {} : { lease }),
1071
- adapters: stationAdapters,
1072
- persistRunState: false,
1073
- ...(input.effectiveEngine === undefined
1074
- ? {}
1075
- : { effectiveEngine: input.effectiveEngine }),
1076
- });
1077
- return settleDeferredPersist(loaded.admitted, env.principalAuthority, stationAdapters, attemptIo, result);
1078
- },
1079
- }),
1069
+ toRequest: async (payload) => {
1070
+ // #840 r8 判词 class 2: this call-local retry must keep this
1071
+ // court's frozen summons / 交卷 body / attachments verbatim
1072
+ // (same object as firstTurn) and project only the minimal
1073
+ // host-needed resume trigger — never engine handbook material,
1074
+ // which would replace a 审核循环 same-ticket continuation with a bare outsourcing
1075
+ // 「重新读」 envelope (#755 contract, resumeTurnRequestProjectionOptions
1076
+ // above). RESUME_TRANSPORT_ENVELOPE is the same package-owned,
1077
+ // non-semantic trigger that projection already uses for a
1078
+ // same-ticket summons carrying no instruction/attachments.
1079
+ if (payload.resumeTurn && firstTurn !== undefined) {
1080
+ return {
1081
+ ...firstTurn,
1082
+ continuation: {
1083
+ kind: "resume",
1084
+ prompt: RESUME_TRANSPORT_ENVELOPE,
1085
+ },
1086
+ };
1087
+ }
1088
+ const turnRequest = withEngineDetourInvocationScope(await buildRequestAfterLease(), invocationScopeId);
1089
+ firstTurn = turnRequest;
1090
+ return turnRequest;
1091
+ },
1080
1092
  });
1081
1093
  }
1082
1094
  const resumed = await runPostAdmissionManualResume({
@@ -1208,39 +1220,26 @@ export async function runPostAdmissionOneShot(input) {
1208
1220
  */
1209
1221
  export async function runPostAdmissionResumable(input) {
1210
1222
  const { admitted, env, io, buildInitialRequest, buildResumeRequest, effectiveEngine } = input;
1211
- const adapters = withOnceSuccessfulBeforeDispatch(input.adapters);
1212
1223
  // One public call → one detour scope across in-place auto-resume dispatches.
1213
1224
  const invocationScopeId = mintEngineDetourInvocationScope({
1214
1225
  ...(effectiveEngine === undefined ? {} : { effectiveEngine }),
1215
1226
  });
1216
1227
  const buildScopedInitial = () => withEngineDetourInvocationScope(buildInitialRequest(), invocationScopeId);
1217
1228
  const buildScopedResume = () => withEngineDetourInvocationScope(buildResumeRequest(), invocationScopeId);
1218
- return runWithAutoResumeLoop({
1229
+ return runSettledAutoResumeLoop({
1219
1230
  admitted,
1220
- principalAuthority: env.principalAuthority,
1231
+ env,
1221
1232
  io,
1222
- sessionAppender: env.sessionAppender,
1223
- autoResumeLimit: env.autoResumeLimit,
1224
- ...(env.signal === undefined ? {} : { signal: env.signal }),
1233
+ adapters: input.adapters,
1234
+ ...(effectiveEngine === undefined ? {} : { effectiveEngine }),
1235
+ // Ordinary in-call retry keeps the admitted correlation when one was stored.
1236
+ dispatchEnv: {
1237
+ ...env,
1238
+ ...(admitted.correlationId === undefined ? {} : { correlationId: admitted.correlationId }),
1239
+ },
1225
1240
  buildInitialPayload: buildScopedInitial,
1226
1241
  buildResumePayload: buildScopedResume,
1227
- dispatch: async (request, lease, _isFirst, attemptIo) => {
1228
- const result = await dispatchPostAdmissionTurn({
1229
- admitted,
1230
- env: {
1231
- ...env,
1232
- ...(admitted.correlationId === undefined ? {} : { correlationId: admitted.correlationId }),
1233
- },
1234
- io: attemptIo,
1235
- request,
1236
- ...(lease === undefined ? {} : { lease }),
1237
- adapters,
1238
- persistRunState: false,
1239
- // #600: every attempt (initial + auto-resume) writes seat engine when present.
1240
- ...(effectiveEngine === undefined ? {} : { effectiveEngine }),
1241
- });
1242
- return settleDeferredPersist(admitted, env.principalAuthority, adapters, attemptIo, result);
1243
- },
1242
+ toRequest: async (request) => request,
1244
1243
  });
1245
1244
  }
1246
1245
  /**
@@ -0,0 +1,29 @@
1
+ /**
2
+ * One seat-runtime assembly for the public CLI and nested summons.
3
+ * Order is host selection, the caller's argv parse, the missing-model fact,
4
+ * then host-facing provider projection. Callers own how a missing model is shown.
5
+ */
6
+ import { pickEngineAxis } from "../package-resources/engine-material.js";
7
+ import { resolvedSeatWithModel, } from "./config.js";
8
+ import { loadHostProvidersTable, projectHostFacingProvider, } from "./host-providers.js";
9
+ import { composeRoleTurnHostAdapters, selectRoleTurnHost, } from "./role-turn-host-resolution.js";
10
+ export function openRoleSeatRuntime(input) {
11
+ const hostAdapters = composeRoleTurnHostAdapters(input.resolution, input.principalAuthority);
12
+ const roleTurnHost = selectRoleTurnHost(hostAdapters, {
13
+ role: input.role,
14
+ seat: input.seat,
15
+ });
16
+ input.afterHost?.();
17
+ const seatWithModel = resolvedSeatWithModel(input.seat);
18
+ if (seatWithModel === undefined)
19
+ return { ok: false };
20
+ const projected = input.hostFacingModel ?? projectHostFacingProvider(seatWithModel.selection, seatWithModel.host, loadHostProvidersTable(input.home), input.home);
21
+ return {
22
+ ok: true,
23
+ roleTurnHost,
24
+ hostAdapters,
25
+ ...(projected === undefined ? {} : { model: projected }),
26
+ ...pickEngineAxis(seatWithModel),
27
+ host: seatWithModel.host,
28
+ };
29
+ }
@@ -17,7 +17,7 @@ import { parseCollectorRepository } from "../collector-config.js";
17
17
  import { rewriteAdmittedRoleRunPage, rewriteRunDirectoryPathValue, } from "../role-run-relocation.js";
18
18
  import { appendEngineSessionMaterial, engineSessionMaterialFromOptions, pickEngineAxis, } from "../package-resources/engine-material.js";
19
19
  import { packagedResumeSourcePath, packagedRoleMetadata, } from "../packaged-role-registry.js";
20
- import { recordEffectiveInvocationModel, requireAuthorityRef, isReviewerLens, } from "./invocation.js";
20
+ import { admittedReviewerBaseFault, recordEffectiveInvocationModel, requireAuthorityRef, isReviewerLens, } from "./invocation.js";
21
21
  /** Providers eligible for v1 typed-429 resume (Codex / xAI only).
22
22
  * @deprecated v1 429-only gate removed by #416 (owner 2026-08-22: "根本不要有限制"). Kept for compatibility; do not use for new branching.
23
23
  */
@@ -1263,11 +1263,11 @@ function admitResumedRole(loaded) {
1263
1263
  }
1264
1264
  case "review-basis": {
1265
1265
  const rawBase = fields.baseRevision;
1266
- if (rawBase === undefined || rawBase.trim() === "") {
1267
- throw new CliUsageError(`role run admitted reviewer base revision is missing: ${runId}`);
1268
- }
1269
- if (/\s/.test(rawBase) || rawBase.startsWith("-")) {
1270
- throw new CliUsageError(`role run admitted reviewer base revision is damaged: ${runId}`);
1266
+ const baseFault = admittedReviewerBaseFault(rawBase);
1267
+ if (baseFault !== undefined || rawBase === undefined) {
1268
+ throw new CliUsageError(baseFault === "damaged"
1269
+ ? `role run admitted reviewer base revision is damaged: ${runId}`
1270
+ : `role run admitted reviewer base revision is missing: ${runId}`);
1271
1271
  }
1272
1272
  const lens = fields.lens;
1273
1273
  if (!isReviewerLens(lens)) {
@@ -2,6 +2,20 @@ import { pickEngineAxis } from "../package-resources/engine-material.js";
2
2
  import { packagedRoleActivationFlags, packagedRoleMetadata, } from "../packaged-role-registry.js";
3
3
  import { installedMethodSkillPath } from "./machine-method-skills.js";
4
4
  import { parentRunPathFromGatePointerInstruction } from "./run-lifecycle.js";
5
+ /**
6
+ * Env axes shared by every public turn projection.
7
+ * Callers add correlation, continuation, host, and station-only fields.
8
+ */
9
+ export function projectPublicTurnAxes(env) {
10
+ return {
11
+ packageRoot: env.packageRoot,
12
+ home: env.home,
13
+ agentDir: env.agentDir,
14
+ ...(env.model === undefined ? {} : { model: env.model }),
15
+ ...pickEngineAxis(env),
16
+ ...(env.timeoutMs === undefined ? {} : { timeoutMs: env.timeoutMs }),
17
+ };
18
+ }
5
19
  export function projectRoleTurnRequest(admitted, roleDetails, options) {
6
20
  const cwd = admitted.projectRoot ?? admitted.repoRoot ?? admitted.cwd;
7
21
  if (cwd === undefined)
@@ -3,7 +3,6 @@ import { existsSync } from "node:fs";
3
3
  import { realpath } from "node:fs/promises";
4
4
  import { join } from "node:path";
5
5
  import { promisify } from "node:util";
6
- import { pickEngineAxis } from "./package-resources/engine-material.js";
7
6
  const AK_ROLE_PACKAGE_ROOT_ENV = "AK_ROLE_PACKAGE_ROOT";
8
7
  const execFileAsync = promisify(execFile);
9
8
  function createCapturingIo() {
@@ -69,12 +68,6 @@ async function resolveSummonHome(options) {
69
68
  if (fromCwd !== void 0 && fromCwd.length > 0) return fromCwd;
70
69
  return packageMachineHome();
71
70
  }
72
- function projectSeatEngine(seat) {
73
- return pickEngineAxis(seat);
74
- }
75
- function projectSeatHost(seat) {
76
- return seat.host === void 0 ? {} : { host: seat.host };
77
- }
78
71
  function hostSelectionFailureFromUnknown(error) {
79
72
  if (typeof error !== "object" || error === null) return void 0;
80
73
  if (error.name !== "HostSelectionError") return void 0;
@@ -85,44 +78,36 @@ async function createSummonEnv(options, afterHost) {
85
78
  const [
86
79
  { piDurablePrincipalAuthority },
87
80
  { appendPiSessionCustomEntry },
88
- { resolveRoleTurnHost },
89
- { missingResolvedSeatModelMessage, resolvedSeatWithModel }
81
+ { openRoleSeatRuntime },
82
+ { missingResolvedSeatModelMessage }
90
83
  ] = await Promise.all([
91
84
  import("./pi/durable-principal.js"),
92
85
  import("./pi/role-turn-host.js"),
93
- import("./public-cli/role-turn-host-resolution.js"),
86
+ import("./public-cli/role-seat-runtime.js"),
94
87
  import("./public-cli/config.js")
95
88
  ]);
96
89
  const principalAuthority = options.principalAuthority ?? piDurablePrincipalAuthority;
97
- const roleTurnHost = resolveRoleTurnHost(
98
- {
90
+ const opened = openRoleSeatRuntime({
91
+ resolution: {
99
92
  packageRoot: options.packageRoot,
100
93
  ...options.roleTurnHost === void 0 ? {} : { roleTurnHost: options.roleTurnHost },
101
94
  ...options.hostAdapters === void 0 ? {} : { hostAdapters: options.hostAdapters },
102
95
  ...options.extraPiArgs === void 0 || options.extraPiArgs.length === 0 ? {} : { extraPiArgs: options.extraPiArgs },
103
96
  ...options.timeoutMs === void 0 ? {} : { timeoutMs: options.timeoutMs }
104
97
  },
105
- { role: options.role, seat: options.seat, principalAuthority }
106
- );
107
- afterHost?.();
108
- const seatWithModel = resolvedSeatWithModel(options.seat);
109
- if (seatWithModel === void 0) {
98
+ principalAuthority,
99
+ role: options.role,
100
+ seat: options.seat,
101
+ home: options.home,
102
+ ...afterHost === void 0 ? {} : { afterHost },
103
+ ...options.hostFacingModel === void 0 ? {} : { hostFacingModel: options.hostFacingModel }
104
+ });
105
+ if (!opened.ok) {
110
106
  return {
111
107
  ok: false,
112
108
  missingModelMessage: missingResolvedSeatModelMessage(options.role)
113
109
  };
114
110
  }
115
- const hostName = seatWithModel.host ?? "pi";
116
- let hostFacingSelection = options.hostFacingModel;
117
- if (hostFacingSelection === void 0) {
118
- const { loadHostProvidersTable, projectHostFacingProvider } = await import("./public-cli/host-providers.js");
119
- hostFacingSelection = projectHostFacingProvider(
120
- seatWithModel.selection,
121
- hostName,
122
- loadHostProvidersTable(options.home),
123
- options.home
124
- );
125
- }
126
111
  return {
127
112
  ok: true,
128
113
  env: {
@@ -131,12 +116,13 @@ async function createSummonEnv(options, afterHost) {
131
116
  agentDir: options.agentDir,
132
117
  sessionAppender: appendPiSessionCustomEntry,
133
118
  packageRoot: options.packageRoot,
134
- roleTurnHost,
119
+ roleTurnHost: opened.roleTurnHost,
135
120
  cwd: options.cwd,
136
121
  credentials: options.credentials,
137
- ...hostFacingSelection === void 0 ? {} : { model: hostFacingSelection },
138
- ...projectSeatEngine(seatWithModel),
139
- ...projectSeatHost(seatWithModel),
122
+ ...opened.model === void 0 ? {} : { model: opened.model },
123
+ ...opened.engine === void 0 ? {} : { engine: opened.engine },
124
+ ...opened.engineModel === void 0 ? {} : { engineModel: opened.engineModel },
125
+ host: opened.host,
140
126
  ...options.timeoutMs === void 0 ? {} : { timeoutMs: options.timeoutMs }
141
127
  }
142
128
  };
@@ -144,13 +130,14 @@ async function createSummonEnv(options, afterHost) {
144
130
  async function summonPublicRole(options) {
145
131
  const packageRoot = resolveSummonsPackageRoot(options.packageRoot);
146
132
  const home = await resolveSummonHome(options);
147
- const agentDir = options.agentDir ?? process.env.PI_CODING_AGENT_DIR ?? join(home, ".pi", "agent");
148
133
  const {
149
134
  loadCredentialProviders,
150
135
  loadPublicCliConfig,
151
136
  resolveEffectiveSeat,
137
+ resolvePublicAgentDir,
152
138
  validatePublicCliConfigAxes
153
139
  } = await import("./public-cli/config.js");
140
+ const agentDir = resolvePublicAgentDir(options.agentDir, home);
154
141
  const credentials = options.credentials ?? await loadCredentialProviders(agentDir);
155
142
  const config = await loadPublicCliConfig(home);
156
143
  validatePublicCliConfigAxes(config, packageRoot);
@@ -64,6 +64,9 @@ function roleRunPlacement(ledgerHome, input) {
64
64
  function roleRunArtifactsDirectory(runDirectory) {
65
65
  return join(runDirectory, "artifacts");
66
66
  }
67
+ function isUnboundRunDirectory(runDirectory) {
68
+ return runDirectory.replaceAll("\\", "/").includes("/unbound/runs/");
69
+ }
67
70
  function ensureRoleRunDirectory(ledgerHome, directory) {
68
71
  return ensureRealDirectoryTree(ledgerHome, directory);
69
72
  }
@@ -78,6 +81,7 @@ function ensureRoleRunPlacement(ledgerHome, placement) {
78
81
  export {
79
82
  ensureRoleRunDirectory,
80
83
  ensureRoleRunPlacement,
84
+ isUnboundRunDirectory,
81
85
  listBookRunDirectories,
82
86
  roleRunArtifactsDirectory,
83
87
  roleRunPlacement
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@akagilnc/pi-workflow-roles",
3
- "version": "0.1.5357",
3
+ "version": "0.1.5368",
4
4
  "description": "Soul-bound workflow roles for Pi",
5
5
  "type": "module",
6
6
  "license": "Apache-2.0",
@@ -10,7 +10,9 @@ import { readdir, readFile } from "node:fs/promises";
10
10
  import { basename, dirname, isAbsolute, join, relative, resolve, sep } from "node:path";
11
11
 
12
12
  import { pathContainedIn } from "./activation-ledger-topology.ts";
13
- import { roleRunPlacement } from "./role-run-placement.ts";
13
+ import { isUnboundRunDirectory, roleRunPlacement } from "./role-run-placement.ts";
14
+
15
+ export { isUnboundRunDirectory };
14
16
  import {
15
17
  MIGRATION_TICKET_DERIVATION_PAGE,
16
18
  readBoardTicketNumber,
@@ -167,10 +169,6 @@ export async function resolveMigratingRunTicket(runDirectory: string): Promise<{
167
169
  };
168
170
  }
169
171
 
170
- export function isUnboundRunDirectory(runDirectory: string): boolean {
171
- return runDirectory.replaceAll("\\", "/").includes("/unbound/runs/");
172
- }
173
-
174
172
  export function bookHistoricalRoots(
175
173
  booksDirectory: string,
176
174
  backupBooksDirectory: string,
@@ -18,38 +18,12 @@ export { validateRecordedDiaristOutput };
18
18
  /**
19
19
  * 起居郎交卷形状。
20
20
  * #901:交边界(sessions);正文与不可解析原字节由机械投影。
21
+ * status 的合法词(completed | escalate)写在 description,结算认这些词。
22
+ * sessions / ticketSessions 是投影所读的边界:卷路径或端点读不出时走既有 reask,不中止本轮。
23
+ * 声明只留字段名和语义说明,不留类型、嵌套、长度、必填。
21
24
  */
22
- const diaristSessionsSchema = Type.Array(
23
- Type.Object(
24
- {
25
- path: Type.Optional(Type.String({ description: "会话卷绝对或可读路径" })),
26
- ranges: Type.Optional(
27
- Type.Array(
28
- Type.Object(
29
- {
30
- from: Type.Optional(
31
- Type.Object(
32
- { id: Type.Optional(Type.String()), line: Type.Optional(Type.Unknown()) },
33
- { additionalProperties: true, description: "起点:原生 id 或本轮行号二选一" },
34
- ),
35
- ),
36
- to: Type.Optional(
37
- Type.Object(
38
- { id: Type.Optional(Type.String()), line: Type.Optional(Type.Unknown()) },
39
- { additionalProperties: true, description: "终点:原生 id 或本轮行号二选一" },
40
- ),
41
- ),
42
- },
43
- { additionalProperties: true, description: "一段对话区间" },
44
- ),
45
- { description: "本卷本轮各区间;至少一段" },
46
- ),
47
- ),
48
- },
49
- { additionalProperties: true, description: "一卷会话的边界" },
50
- ),
51
- { description: "对话边界;空列表=本轮无对话可划。端点无法指名时走 reask,不中止。" },
52
- );
25
+ const DIARIST_SESSIONS_DESCRIPTION =
26
+ "对话边界。每卷含 path(会话卷绝对或可读路径)与 ranges(本卷本轮各区间)。每段区间含 from / to;起点与终点各写 id(原生 id)或 line(本轮行号),二选一。空列表=本轮无对话可划。端点无法指名时走 reask,不中止。" as const;
53
27
 
54
28
  export const diaristOutputSchema = withTerminatingOutputDeclarations(
55
29
  openToolObject(
@@ -63,24 +37,13 @@ export const diaristOutputSchema = withTerminatingOutputDeclarations(
63
37
  "本庭对象票号(正整数)或 null/省略=真无票;下游走 typed 键;认不出用 status=escalate,不洗成无录。机械层不重判。",
64
38
  }),
65
39
  ),
66
- reason: Type.Optional(
67
- Type.String({
68
- description: "status 为 escalate 时:认不出本庭对象的原因",
69
- }),
70
- ),
71
- sessions: Type.Optional(diaristSessionsSchema),
72
- ticketSessions: Type.Optional(
73
- Type.Array(
74
- Type.Object(
75
- {
76
- ticketNumber: Type.Unknown({ description: "本条边界所归票号(正整数)" }),
77
- sessions: diaristSessionsSchema,
78
- },
79
- { additionalProperties: true },
80
- ),
81
- { description: "多票庭逐票对话边界;一次交卷各票各自分录。与单票 sessions 二选一。" },
82
- ),
83
- ),
40
+ reason: Type.Unknown({
41
+ description: "status 为 escalate 时:认不出本庭对象的原因",
42
+ }),
43
+ sessions: Type.Optional(Type.Unknown({ description: DIARIST_SESSIONS_DESCRIPTION })),
44
+ ticketSessions: Type.Unknown({
45
+ description: `多票庭逐票对话边界;每票含 ticketNumber(本条边界所归票号,正整数)与 sessions(${DIARIST_SESSIONS_DESCRIPTION})。一次交卷各票各自分录。与单票 sessions 二选一。`,
46
+ }),
84
47
  }),
85
48
  ),
86
49
  );