@akagilnc/pi-workflow-roles 0.1.4782 → 0.1.4802
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 -1
- package/README.zh-CN.md +1 -1
- package/dist/acp-host/production-host.js +104 -215
- package/dist/headless-host/production-host.js +149 -229
- package/dist/migrate-book-topology.js +1 -1
- package/dist/pi/role-turn-host.js +1 -1
- package/dist/public-cli/auto-resume.js +9 -15
- package/dist/public-cli/countersign-run.js +75 -87
- package/dist/public-cli/diarist-run.js +6 -26
- package/dist/public-cli/inspector-run.js +1 -1
- package/dist/public-cli/main.js +64 -177
- package/dist/public-cli/notary-run.js +0 -3
- package/dist/public-cli/option-definitions.js +1 -1
- package/dist/public-cli/post-admission.js +35 -65
- package/dist/public-cli/reviewer-run.js +1 -1
- package/dist/public-cli/run-lifecycle.js +14 -46
- package/dist/public-cli/seat-ticket-binding.js +11 -25
- package/dist/public-role-summons.js +2 -0
- package/package.json +1 -1
- package/souls/coder.md +1 -2
- package/src/headless-host/role-turn-host.ts +49 -12
- package/src/pi/role-turn-host.ts +1 -1
- package/src/public-cli/auto-resume.ts +19 -18
- package/src/public-cli/countersign-run.ts +76 -129
- package/src/public-cli/diarist-run.ts +6 -33
- package/src/public-cli/inspector-run.ts +1 -1
- package/src/public-cli/invocation.ts +5 -0
- package/src/public-cli/notary-run.ts +3 -7
- package/src/public-cli/option-definitions.ts +1 -1
- package/src/public-cli/post-admission.ts +37 -69
- package/src/public-cli/reviewer-run.ts +1 -1
- package/src/public-cli/run-lifecycle.ts +18 -66
- package/src/public-cli/seat-ticket-binding.ts +12 -28
- package/src/public-role-summons.ts +15 -6
- package/src/role-runtime.ts +9 -0
|
@@ -11,7 +11,6 @@ import { isAbsolute, join, resolve } from "node:path";
|
|
|
11
11
|
|
|
12
12
|
import {
|
|
13
13
|
buildAutoResumeContinuationPrompt,
|
|
14
|
-
buildResumeContinuationPrompt,
|
|
15
14
|
RESUME_TRANSPORT_ENVELOPE,
|
|
16
15
|
type PublicResumeRequest,
|
|
17
16
|
type SameTicketSummonsMaterials,
|
|
@@ -1103,15 +1102,12 @@ export async function dispatchPostAdmissionTurn<
|
|
|
1103
1102
|
// Settlement already sealed accepted — a cleanup failure here must
|
|
1104
1103
|
// not erase that fact or make the caller replay this court's
|
|
1105
1104
|
// summons over already-delivered work (#840 已交劳动只整理终局不重做).
|
|
1106
|
-
//
|
|
1107
|
-
//
|
|
1108
|
-
// continue-under-failure contract, not a swallow — 失败诚实宪法 真因
|
|
1109
|
-
// 必须落痕) — durably, since every auto-resume attempt's io here is
|
|
1110
|
-
// dummyIo (#840 r9 判词 class 1).
|
|
1105
|
+
// Preserve the cleanup failure as a post-dispatch diagnostic; the
|
|
1106
|
+
// accepted settlement remains authoritative (#840 r9 判词 class 1).
|
|
1111
1107
|
await recordBestEffortPostDispatchDiagnostic(
|
|
1112
1108
|
admitted,
|
|
1113
1109
|
env,
|
|
1114
|
-
`current-court cleanup failed after accepted settlement (best-effort continue
|
|
1110
|
+
`current-court cleanup failed after accepted settlement (best-effort continue): ${describeErrorIdentity(error)}`,
|
|
1115
1111
|
io,
|
|
1116
1112
|
);
|
|
1117
1113
|
}
|
|
@@ -1310,8 +1306,7 @@ export async function dispatchPostAdmissionTurn<
|
|
|
1310
1306
|
/**
|
|
1311
1307
|
* Shared resume continuation projection (#471 / #600 / #633 / #637 / #755 / #879):
|
|
1312
1308
|
* seat-table model/engine/timeout axes, restored correlation, and either
|
|
1313
|
-
* - manual resume (no same-ticket summons):
|
|
1314
|
-
* message, with engine-axis handbook via buildResumeContinuationPrompt, or
|
|
1309
|
+
* - manual resume (no same-ticket summons): caller message bytes, or
|
|
1315
1310
|
* - same-ticket summons (审核循环续话): caller/peer words + optional frozen
|
|
1316
1311
|
* attachment paths only — no「请重读」、no code-authored content substitute,
|
|
1317
1312
|
* no engine handbook packaging (#750/#755/#879).
|
|
@@ -1351,12 +1346,7 @@ export function resumeTurnRequestProjectionOptions(
|
|
|
1351
1346
|
// #755: same-ticket summons without prepared materials — caller words only.
|
|
1352
1347
|
prompt = request.message;
|
|
1353
1348
|
} else {
|
|
1354
|
-
|
|
1355
|
-
prompt = buildResumeContinuationPrompt({
|
|
1356
|
-
packageRoot: env.packageRoot,
|
|
1357
|
-
...pickEngineAxis(env),
|
|
1358
|
-
message: request.message,
|
|
1359
|
-
});
|
|
1349
|
+
prompt = request.message;
|
|
1360
1350
|
}
|
|
1361
1351
|
} else if (summonsPrepared !== undefined) {
|
|
1362
1352
|
// #879 station-child officer: instruction bytes === peer body/reask (no wrap).
|
|
@@ -1369,11 +1359,7 @@ export function resumeTurnRequestProjectionOptions(
|
|
|
1369
1359
|
// only). Pointer is activation/sourceRun material — not dialogue content.
|
|
1370
1360
|
prompt = "";
|
|
1371
1361
|
} else {
|
|
1372
|
-
|
|
1373
|
-
prompt = buildResumeContinuationPrompt({
|
|
1374
|
-
packageRoot: env.packageRoot,
|
|
1375
|
-
...pickEngineAxis(env),
|
|
1376
|
-
});
|
|
1362
|
+
prompt = "";
|
|
1377
1363
|
}
|
|
1378
1364
|
return {
|
|
1379
1365
|
packageRoot: env.packageRoot,
|
|
@@ -1395,12 +1381,13 @@ export function resumeTurnRequestProjectionOptions(
|
|
|
1395
1381
|
}
|
|
1396
1382
|
|
|
1397
1383
|
/**
|
|
1398
|
-
*
|
|
1399
|
-
*
|
|
1400
|
-
*
|
|
1384
|
+
* Build the turn request, then hand off to dispatch. When a writer lease is
|
|
1385
|
+
* held, release it if build throws before handoff — dispatch's finally only
|
|
1386
|
+
* runs after this handoff (manual resume and station-child auto-resume).
|
|
1387
|
+
* #987: lease is optional; auto-resume no longer pre-acquires before host CLI.
|
|
1401
1388
|
*/
|
|
1402
1389
|
async function dispatchAfterWriterLease<T>(input: {
|
|
1403
|
-
lease
|
|
1390
|
+
lease?: RunWriterLease;
|
|
1404
1391
|
build: () => Promise<RoleTurnRequest>;
|
|
1405
1392
|
dispatch: (request: RoleTurnRequest) => Promise<T>;
|
|
1406
1393
|
}): Promise<T> {
|
|
@@ -1410,7 +1397,7 @@ async function dispatchAfterWriterLease<T>(input: {
|
|
|
1410
1397
|
handedOffToDispatch = true;
|
|
1411
1398
|
return await input.dispatch(request);
|
|
1412
1399
|
} finally {
|
|
1413
|
-
if (!handedOffToDispatch) {
|
|
1400
|
+
if (!handedOffToDispatch && input.lease !== undefined) {
|
|
1414
1401
|
await input.lease.release();
|
|
1415
1402
|
}
|
|
1416
1403
|
}
|
|
@@ -1430,7 +1417,7 @@ function isAlreadyFrozenSummonsAttachment(
|
|
|
1430
1417
|
* Freeze same-ticket summons attachments into the retained run directory (#637).
|
|
1431
1418
|
* No-op materials (no paths / instruction-only) skip the freeze.
|
|
1432
1419
|
* Paths already under this run's attachments/ are the accepted freeze identity —
|
|
1433
|
-
* reuse them
|
|
1420
|
+
* reuse them for the same internal re-summons flow.
|
|
1434
1421
|
* Manual resume never calls this — old attachment semantics stay intact.
|
|
1435
1422
|
*/
|
|
1436
1423
|
export async function prepareSummonsResumeMaterials(
|
|
@@ -1464,16 +1451,15 @@ export async function prepareSummonsResumeMaterials(
|
|
|
1464
1451
|
}
|
|
1465
1452
|
|
|
1466
1453
|
/**
|
|
1467
|
-
* Shared manual-resume orchestration for seats
|
|
1468
|
-
*
|
|
1454
|
+
* Shared manual-resume orchestration for seats (#599 / #633):
|
|
1455
|
+
* load once → structural rejection →
|
|
1469
1456
|
* optional seat afterAdmittedLoad (method material / controlled failure) →
|
|
1470
1457
|
* seat turn projection → station-child auto-resume or public manual resume.
|
|
1471
1458
|
* Seat-owned loader
|
|
1472
1459
|
* validation, turn builder, and adapters stay on the seat.
|
|
1473
1460
|
*
|
|
1474
|
-
* Court
|
|
1475
|
-
*
|
|
1476
|
-
* and record. No pre-lease clear or stale court-snapshot consumption.
|
|
1461
|
+
* Court handling (#637): public manual resume reads only the open court's
|
|
1462
|
+
* settlement identity; internal re-summons may freeze and record its materials.
|
|
1477
1463
|
*/
|
|
1478
1464
|
export async function runPostAdmissionSeatResume<
|
|
1479
1465
|
A extends AdmittedRoleInvocation,
|
|
@@ -1482,7 +1468,7 @@ export async function runPostAdmissionSeatResume<
|
|
|
1482
1468
|
request: PublicResumeRequest;
|
|
1483
1469
|
env: PostAdmissionEnv;
|
|
1484
1470
|
io: CliIo;
|
|
1485
|
-
/** Load admitted state
|
|
1471
|
+
/** Load admitted state from the caller's resume request. */
|
|
1486
1472
|
load: (request: PublicResumeRequest) => Promise<{ admitted: A }>;
|
|
1487
1473
|
/** Build turn from admitted + effective request (summons ride existing projection). */
|
|
1488
1474
|
buildTurnRequest: (
|
|
@@ -1494,8 +1480,7 @@ export async function runPostAdmissionSeatResume<
|
|
|
1494
1480
|
* After the single pre-lease load. Factory seats resolve method-material
|
|
1495
1481
|
* adapters here via resolveResumeMethodMaterialAdapters (or short-circuit
|
|
1496
1482
|
* with the same controlled-failure face as initial). Must not re-load the
|
|
1497
|
-
* same admitted
|
|
1498
|
-
* and only when materials change.
|
|
1483
|
+
* same admitted.
|
|
1499
1484
|
*/
|
|
1500
1485
|
afterAdmittedLoad?: (
|
|
1501
1486
|
admitted: A,
|
|
@@ -1517,7 +1502,7 @@ export async function runPostAdmissionSeatResume<
|
|
|
1517
1502
|
// Load once for runDirectory / structural rejection / afterAdmittedLoad.
|
|
1518
1503
|
// Court identity for public manual resume is judged in the turn builder
|
|
1519
1504
|
// (#987: no package writer-lease gate before host CLI resume). Station-child
|
|
1520
|
-
// auto-resume
|
|
1505
|
+
// auto-resume shares that rule via runWithAutoResumeLoop (no pre-acquire).
|
|
1521
1506
|
let loaded;
|
|
1522
1507
|
try {
|
|
1523
1508
|
loaded = await input.load(request);
|
|
@@ -1548,34 +1533,19 @@ export async function runPostAdmissionSeatResume<
|
|
|
1548
1533
|
|
|
1549
1534
|
const buildRequestAfterLease = async (): Promise<RoleTurnRequest> => {
|
|
1550
1535
|
let openCourtAttemptId: string | undefined;
|
|
1551
|
-
//
|
|
1552
|
-
|
|
1553
|
-
// Name kept for station-child callers that still build under lease.
|
|
1554
|
-
let admittedForBuild = loaded.admitted;
|
|
1536
|
+
// Settlement identity stays on the outer admitted.
|
|
1537
|
+
const admittedForBuild = loaded.admitted;
|
|
1555
1538
|
|
|
1556
|
-
// Bare resume
|
|
1539
|
+
// Bare resume keeps the open court's settlement identity, but public resume
|
|
1540
|
+
// never re-delivers the prior summons or its attachments (#987).
|
|
1557
1541
|
if (request.summons === undefined) {
|
|
1558
1542
|
const openCourt = await readCurrentCourt(admittedForBuild.runDirectory);
|
|
1559
1543
|
if (openCourt !== undefined) {
|
|
1560
1544
|
openCourtAttemptId = openCourt.courtAttemptId;
|
|
1561
|
-
request = {
|
|
1562
|
-
runId: request.runId,
|
|
1563
|
-
...(request.message === undefined
|
|
1564
|
-
? {}
|
|
1565
|
-
: { message: request.message }),
|
|
1566
|
-
...(openCourt.summons === undefined
|
|
1567
|
-
? {}
|
|
1568
|
-
: { summons: openCourt.summons }),
|
|
1569
|
-
};
|
|
1570
|
-
if (openCourt.summons !== undefined) {
|
|
1571
|
-
const reloaded = await input.load(request);
|
|
1572
|
-
admittedForBuild = reloaded.admitted;
|
|
1573
|
-
}
|
|
1574
1545
|
}
|
|
1575
1546
|
}
|
|
1576
1547
|
|
|
1577
|
-
//
|
|
1578
|
-
// currentCourt + later bare resume reuse the accepted snapshot.
|
|
1548
|
+
// Internal re-summons freezes external paths once and records that identity.
|
|
1579
1549
|
if (request.summons !== undefined) {
|
|
1580
1550
|
const prepared = await prepareSummonsResumeMaterials(
|
|
1581
1551
|
admittedForBuild.runDirectory,
|
|
@@ -1626,10 +1596,10 @@ export async function runPostAdmissionSeatResume<
|
|
|
1626
1596
|
return turnRequest;
|
|
1627
1597
|
};
|
|
1628
1598
|
|
|
1629
|
-
// Court recovery / open, then dispatch. Public manual resume
|
|
1630
|
-
//
|
|
1631
|
-
// Station-child same-ticket/same-parent resume is
|
|
1632
|
-
// (#840 / #416)
|
|
1599
|
+
// Court recovery / open, then dispatch. Public manual resume and station-child
|
|
1600
|
+
// auto-resume both pass through to the host CLI without a package writer-lease
|
|
1601
|
+
// pre-gate (#987 / ADR 0080). Station-child same-ticket/same-parent resume is
|
|
1602
|
+
// still call-local auto-resume (#840 / #416).
|
|
1633
1603
|
// afterAdmittedPrepare runs inside this try so mint failure and cleanup share one finally.
|
|
1634
1604
|
try {
|
|
1635
1605
|
if (input.afterAdmittedPrepare !== undefined) {
|
|
@@ -1664,14 +1634,13 @@ export async function runPostAdmissionSeatResume<
|
|
|
1664
1634
|
// redispatch brake (#833). New-court station-child turns still auto-resume.
|
|
1665
1635
|
dispatch: async (payload, lease, _isFirst, attemptIo) =>
|
|
1666
1636
|
dispatchAfterWriterLease({
|
|
1667
|
-
lease,
|
|
1637
|
+
...(lease === undefined ? {} : { lease }),
|
|
1668
1638
|
build: async () => {
|
|
1669
1639
|
// #840 r8 判词 class 2: this call-local retry must keep this
|
|
1670
1640
|
// court's frozen summons / 交卷 body / attachments verbatim
|
|
1671
1641
|
// (same object as firstTurn) and project only the minimal
|
|
1672
|
-
// host-needed resume trigger — never
|
|
1673
|
-
//
|
|
1674
|
-
// a 审核循环 same-ticket continuation with a bare outsourcing
|
|
1642
|
+
// host-needed resume trigger — never engine handbook material,
|
|
1643
|
+
// which would replace a 审核循环 same-ticket continuation with a bare outsourcing
|
|
1675
1644
|
// 「重新读」 envelope (#755 contract, resumeTurnRequestProjectionOptions
|
|
1676
1645
|
// above). RESUME_TRANSPORT_ENVELOPE is the same package-owned,
|
|
1677
1646
|
// non-semantic trigger that projection already uses for a
|
|
@@ -1698,7 +1667,7 @@ export async function runPostAdmissionSeatResume<
|
|
|
1698
1667
|
env,
|
|
1699
1668
|
io: attemptIo,
|
|
1700
1669
|
request: turnRequest,
|
|
1701
|
-
lease,
|
|
1670
|
+
...(lease === undefined ? {} : { lease }),
|
|
1702
1671
|
adapters: stationAdapters,
|
|
1703
1672
|
persistRunState: false,
|
|
1704
1673
|
...(input.effectiveEngine === undefined
|
|
@@ -1727,8 +1696,7 @@ export async function runPostAdmissionSeatResume<
|
|
|
1727
1696
|
buildRequestAfterLease,
|
|
1728
1697
|
});
|
|
1729
1698
|
} catch (error) {
|
|
1730
|
-
//
|
|
1731
|
-
// rejection (e.g. notary rejects caller message) — same exit face as pre-lease.
|
|
1699
|
+
// Seat preparation may still surface structural rejection.
|
|
1732
1700
|
if (error instanceof CliUsageError) {
|
|
1733
1701
|
presentStructuralRejection(error, input.io);
|
|
1734
1702
|
return { exitCode: 2 };
|
|
@@ -1836,7 +1804,7 @@ export async function runPostAdmissionResumable<
|
|
|
1836
1804
|
},
|
|
1837
1805
|
io: attemptIo,
|
|
1838
1806
|
request,
|
|
1839
|
-
lease,
|
|
1807
|
+
...(lease === undefined ? {} : { lease }),
|
|
1840
1808
|
adapters,
|
|
1841
1809
|
persistRunState: false,
|
|
1842
1810
|
// #600: every attempt (initial + auto-resume) writes seat engine when present.
|
|
@@ -1851,8 +1819,8 @@ export async function runPostAdmissionResumable<
|
|
|
1851
1819
|
* Manual resume: pass-through to the host CLI resume — no package writer-lease
|
|
1852
1820
|
* pre-gate (#987), no sealed-accepted short-circuit (#833 / #416). Court open
|
|
1853
1821
|
* (summons / message / open court) is built when using buildRequestAfterLease;
|
|
1854
|
-
* sole-final stays per-attempt. Station-child auto-resume
|
|
1855
|
-
*
|
|
1822
|
+
* sole-final stays per-attempt. Station-child auto-resume shares the same
|
|
1823
|
+
* no-pre-gate rule via runWithAutoResumeLoop + dispatchAfterWriterLease.
|
|
1856
1824
|
*/
|
|
1857
1825
|
export async function runPostAdmissionManualResume<
|
|
1858
1826
|
A extends AdmittedRoleInvocation,
|
|
@@ -440,7 +440,7 @@ export async function runPublicReviewerResume(
|
|
|
440
440
|
...(sandbox.executionCwd === undefined ? {} : { cwd: sandbox.executionCwd }),
|
|
441
441
|
continuation: {
|
|
442
442
|
kind: "resume",
|
|
443
|
-
prompt:
|
|
443
|
+
prompt: effective.message ?? "",
|
|
444
444
|
},
|
|
445
445
|
});
|
|
446
446
|
},
|
|
@@ -17,10 +17,7 @@ import {
|
|
|
17
17
|
resolveActivationLedgerHome,
|
|
18
18
|
} from "../activation-ledger-topology.ts";
|
|
19
19
|
import { listBookRunDirectories } from "../role-run-placement.ts";
|
|
20
|
-
import {
|
|
21
|
-
isSafePositiveTicketNumber,
|
|
22
|
-
readBoardTicketNumber,
|
|
23
|
-
} from "../run-ticket-number.ts";
|
|
20
|
+
import { isSafePositiveTicketNumber } from "../run-ticket-number.ts";
|
|
24
21
|
import { CliUsageError } from "./cli-errors.ts";
|
|
25
22
|
import {
|
|
26
23
|
readLatestTypedProviderHttpObservation,
|
|
@@ -48,7 +45,6 @@ import {
|
|
|
48
45
|
appendEngineSessionMaterial,
|
|
49
46
|
engineSessionMaterialFromOptions,
|
|
50
47
|
pickEngineAxis,
|
|
51
|
-
type EngineSessionMaterial,
|
|
52
48
|
} from "../package-resources/engine-material.ts";
|
|
53
49
|
import type { PublicThinkingLevel } from "./registry.ts";
|
|
54
50
|
import {
|
|
@@ -135,11 +131,8 @@ export type RoleRunRecord = {
|
|
|
135
131
|
* Package-owned non-empty Chinese neutral resume transport (#959 / ADR 0073).
|
|
136
132
|
* Used by:
|
|
137
133
|
* - auto-resume (all seats via buildAutoResumeContinuationPrompt) — required so
|
|
138
|
-
* hosts that reject empty stdin (codex) still receive a prompt
|
|
139
|
-
*
|
|
140
|
-
* that seat's own manual entry.
|
|
141
|
-
* Generic bare `ak-role resume` stays empty-capable via selectResumeContinuationPrompt
|
|
142
|
-
* / buildResumeContinuationPrompt — ADR 0080 keeps auto and generic-manual entries separate.
|
|
134
|
+
* hosts that reject empty stdin (codex) still receive a prompt.
|
|
135
|
+
* Public manual resume forwards only the caller's bytes (#987).
|
|
143
136
|
*/
|
|
144
137
|
export const RESUME_TRANSPORT_ENVELOPE = "继续。" as const;
|
|
145
138
|
|
|
@@ -151,15 +144,15 @@ export type PublicResumeRequest = {
|
|
|
151
144
|
/**
|
|
152
145
|
* Same-ticket re-summons materials (#637). Present only when a public seat
|
|
153
146
|
* re-enters via the summons face — never from `ak-role resume`.
|
|
154
|
-
* Manual resume
|
|
147
|
+
* Manual resume forwards only caller-supplied bytes and never re-delivers them.
|
|
155
148
|
*/
|
|
156
149
|
readonly summons?: SameTicketSummonsMaterials;
|
|
157
150
|
};
|
|
158
151
|
|
|
159
152
|
/**
|
|
160
153
|
* Open court turn on a retained run (#637).
|
|
161
|
-
* courtAttemptId
|
|
162
|
-
*
|
|
154
|
+
* courtAttemptId identifies settlement across later public manual resume calls.
|
|
155
|
+
* Summons materials belong only to the internal re-summons face.
|
|
163
156
|
* Cleared when this courtAttemptId seals.
|
|
164
157
|
*/
|
|
165
158
|
export type CurrentCourtState = {
|
|
@@ -181,40 +174,6 @@ export type SameTicketSummonsMaterials = {
|
|
|
181
174
|
readonly sourceRun?: NotarySourceRunLocator;
|
|
182
175
|
};
|
|
183
176
|
|
|
184
|
-
/**
|
|
185
|
-
* Manual resume continuation selector (#471 / #600 / #736 / ADR 0080).
|
|
186
|
-
* Message present → those bytes; absent → engine pointers only (may be empty).
|
|
187
|
-
* Caller message (including blank) still wins verbatim when supplied.
|
|
188
|
-
* Auto-resume must use buildAutoResumeContinuationPrompt — do not fold the
|
|
189
|
-
* non-empty Chinese envelope into this shared manual selector (#959).
|
|
190
|
-
*/
|
|
191
|
-
export function selectResumeContinuationPrompt(
|
|
192
|
-
message?: string,
|
|
193
|
-
engineMaterial?: EngineSessionMaterial,
|
|
194
|
-
): string {
|
|
195
|
-
const lines = message !== undefined ? [message] : [];
|
|
196
|
-
return appendEngineSessionMaterial(lines, engineMaterial).join("\n");
|
|
197
|
-
}
|
|
198
|
-
|
|
199
|
-
/**
|
|
200
|
-
* Manual resume continuation with engine material from the seat env (#600).
|
|
201
|
-
* Bare manual resume stays empty-prompt-capable; auto-resume is a separate entry.
|
|
202
|
-
*/
|
|
203
|
-
export function buildResumeContinuationPrompt(options: {
|
|
204
|
-
packageRoot: string;
|
|
205
|
-
engine?: string;
|
|
206
|
-
engineModel?: string;
|
|
207
|
-
message?: string;
|
|
208
|
-
}): string {
|
|
209
|
-
return selectResumeContinuationPrompt(
|
|
210
|
-
options.message,
|
|
211
|
-
engineSessionMaterialFromOptions({
|
|
212
|
-
packageRoot: options.packageRoot,
|
|
213
|
-
...pickEngineAxis(options),
|
|
214
|
-
}),
|
|
215
|
-
);
|
|
216
|
-
}
|
|
217
|
-
|
|
218
177
|
/**
|
|
219
178
|
* Auto-resume continuation only (#959 / ADR 0080).
|
|
220
179
|
* Always non-empty: Chinese neutral envelope plus optional engine pointers.
|
|
@@ -225,13 +184,13 @@ export function buildAutoResumeContinuationPrompt(options: {
|
|
|
225
184
|
engine?: string;
|
|
226
185
|
engineModel?: string;
|
|
227
186
|
}): string {
|
|
228
|
-
return
|
|
229
|
-
RESUME_TRANSPORT_ENVELOPE,
|
|
187
|
+
return appendEngineSessionMaterial(
|
|
188
|
+
[RESUME_TRANSPORT_ENVELOPE],
|
|
230
189
|
engineSessionMaterialFromOptions({
|
|
231
190
|
packageRoot: options.packageRoot,
|
|
232
191
|
...pickEngineAxis(options),
|
|
233
192
|
}),
|
|
234
|
-
);
|
|
193
|
+
).join("\n");
|
|
235
194
|
}
|
|
236
195
|
|
|
237
196
|
const RUN_STATE_FILE = "run-state.json";
|
|
@@ -672,8 +631,7 @@ export async function markRunTerminal(runDirectory: string): Promise<void> {
|
|
|
672
631
|
if (current === undefined) {
|
|
673
632
|
throw new Error("cannot mark terminal: run state missing");
|
|
674
633
|
}
|
|
675
|
-
// Preserve open
|
|
676
|
-
// let bare resume continue that court (#637).
|
|
634
|
+
// Preserve the open court's settlement identity after a failed/incomplete turn (#637).
|
|
677
635
|
await writeRoleRunStateDisk(runDirectory, {
|
|
678
636
|
runId: current.runId,
|
|
679
637
|
role: current.role,
|
|
@@ -1183,19 +1141,19 @@ async function runHasFormedSessionPrincipal(runDirectory: string): Promise<boole
|
|
|
1183
1141
|
/**
|
|
1184
1142
|
* Locate the latest retained run for one seat under a book (#637 / #747).
|
|
1185
1143
|
* Same walk surface as findRunDirectoryById (listBookRunDirectories). Match by
|
|
1186
|
-
* parent run path (officer seats, #747
|
|
1187
|
-
*
|
|
1188
|
-
*
|
|
1144
|
+
* parent run path (officer / gate seats, #747 / #987). runId is UUIDv7 —
|
|
1145
|
+
* lexicographic max is latest among runs that formed a session principal. No
|
|
1146
|
+
* parallel index. Public ticket-number selection of a prior run was deleted
|
|
1147
|
+
* (#987 Result 7); callers use explicit `ak-role resume <runId>`.
|
|
1189
1148
|
* Only a truly missing book directory means no history; damage/permission errors propagate.
|
|
1190
1149
|
*/
|
|
1191
1150
|
export async function findLatestRunIdForSeatTicket(input: {
|
|
1192
1151
|
readonly home: string;
|
|
1193
1152
|
readonly bookKey: string;
|
|
1194
1153
|
readonly role: RoleRunRecord["role"];
|
|
1195
|
-
readonly
|
|
1196
|
-
readonly parentRunPath?: string;
|
|
1154
|
+
readonly parentRunPath: string;
|
|
1197
1155
|
}): Promise<string | undefined> {
|
|
1198
|
-
if (input.
|
|
1156
|
+
if (input.parentRunPath.trim() === "") {
|
|
1199
1157
|
return undefined;
|
|
1200
1158
|
}
|
|
1201
1159
|
const ledgerHome = resolveActivationLedgerHome(input.home);
|
|
@@ -1214,14 +1172,8 @@ export async function findLatestRunIdForSeatTicket(input: {
|
|
|
1214
1172
|
if (!entry.endsWith(suffix)) continue;
|
|
1215
1173
|
const runId = entry.slice(0, entry.length - suffix.length);
|
|
1216
1174
|
if (runId.length === 0) continue;
|
|
1217
|
-
|
|
1218
|
-
|
|
1219
|
-
if (parentPath !== input.parentRunPath) continue;
|
|
1220
|
-
} else if (input.ticketNumber !== undefined) {
|
|
1221
|
-
// Same-ticket resume is board identity only — never migration-derived.
|
|
1222
|
-
const ticketNumber = await readBoardTicketNumber(runDirectory);
|
|
1223
|
-
if (ticketNumber !== input.ticketNumber) continue;
|
|
1224
|
-
}
|
|
1175
|
+
const parentPath = await readRunParentPath(runDirectory);
|
|
1176
|
+
if (parentPath !== input.parentRunPath) continue;
|
|
1225
1177
|
// Durable fact: never resume-select a provisional that never formed principal.
|
|
1226
1178
|
if (!(await runHasFormedSessionPrincipal(runDirectory))) continue;
|
|
1227
1179
|
if (best === undefined || runId > best) best = runId;
|
|
@@ -1,15 +1,13 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Shared
|
|
2
|
+
* Shared same-parent resume seam for gate / officer seats (#635 / #637 / #747 / #987).
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
* This module owns same-ticket / same-parent resume only.
|
|
4
|
+
* Lookup key is parent run path only (#747 / #987 Result 7). Public seats no
|
|
5
|
+
* longer select a prior run by ticket number — callers use explicit
|
|
6
|
+
* `ak-role resume <runId>`. Officer and gate countersign same-parent re-summons
|
|
7
|
+
* keep this seam. Lookup/resume failures propagate (失败诚实) — never wash into
|
|
8
|
+
* a fresh mint. Returns undefined when the caller declared an explicit fresh
|
|
9
|
+
* summons (`ak-role new`) or when no prior run exists; both mint new.
|
|
10
|
+
* freshSummons is required so no seat can drift back into its own skip branch.
|
|
13
11
|
*/
|
|
14
12
|
import { resolveBookKeyFromGit } from "../activation-ledger-git.ts";
|
|
15
13
|
import {
|
|
@@ -19,20 +17,13 @@ import {
|
|
|
19
17
|
} from "./run-lifecycle.ts";
|
|
20
18
|
|
|
21
19
|
/**
|
|
22
|
-
* Sole same-seat → resume decision (#637 / #724 / #747).
|
|
23
|
-
* Officer seats (notary/inspector/auditor) look up by parent run path; countersign
|
|
24
|
-
* / diarist keep ticket-number principal. When found, runs resume with this
|
|
25
|
-
* summons' materials. Lookup/resume failures propagate (失败诚实) — never wash
|
|
26
|
-
* into a fresh mint. Returns undefined when the caller declared an explicit
|
|
27
|
-
* fresh summons (`ak-role new`) or when no prior run exists; both mint new.
|
|
28
|
-
* freshSummons is required so no seat can drift back into its own skip branch.
|
|
20
|
+
* Sole same-seat → resume decision by parent run path (#637 / #724 / #747 / #987).
|
|
29
21
|
*/
|
|
30
22
|
export async function tryResumeSameTicketSeatRun<T>(input: {
|
|
31
23
|
readonly home: string;
|
|
32
24
|
readonly projectRoot: string;
|
|
33
25
|
readonly role: RoleRunRecord["role"];
|
|
34
|
-
readonly
|
|
35
|
-
readonly parentRunPath?: string;
|
|
26
|
+
readonly parentRunPath: string;
|
|
36
27
|
readonly freshSummons: true | undefined;
|
|
37
28
|
readonly summons?: SameTicketSummonsMaterials;
|
|
38
29
|
readonly resume: (
|
|
@@ -41,19 +32,12 @@ export async function tryResumeSameTicketSeatRun<T>(input: {
|
|
|
41
32
|
) => Promise<T>;
|
|
42
33
|
}): Promise<T | undefined> {
|
|
43
34
|
if (input.freshSummons === true) return undefined;
|
|
44
|
-
if (input.parentRunPath ===
|
|
45
|
-
return undefined;
|
|
46
|
-
}
|
|
35
|
+
if (input.parentRunPath.trim() === "") return undefined;
|
|
47
36
|
const previousRunId = await findLatestRunIdForSeatTicket({
|
|
48
37
|
home: input.home,
|
|
49
38
|
bookKey: resolveBookKeyFromGit(input.projectRoot),
|
|
50
39
|
role: input.role,
|
|
51
|
-
|
|
52
|
-
? {}
|
|
53
|
-
: { parentRunPath: input.parentRunPath }),
|
|
54
|
-
...(input.ticketNumber === undefined
|
|
55
|
-
? {}
|
|
56
|
-
: { ticketNumber: input.ticketNumber }),
|
|
40
|
+
parentRunPath: input.parentRunPath,
|
|
57
41
|
});
|
|
58
42
|
if (previousRunId === undefined) return undefined;
|
|
59
43
|
return await input.resume(previousRunId, input.summons);
|
|
@@ -99,8 +99,13 @@ export type PublicSummonRequest = {
|
|
|
99
99
|
readonly hostAdapters?: readonly NamedRoleTurnHostAdapter[];
|
|
100
100
|
/** Offline test inject for deterministic run ids (same face as public CLI). */
|
|
101
101
|
readonly createRunId?: () => string;
|
|
102
|
-
/** Typed ticket number handoff for diarist child run (#840). */
|
|
102
|
+
/** Typed ticket number handoff for diarist child run (#840). Bind only — not a resume key (#987). */
|
|
103
103
|
readonly boundTicketNumber?: number;
|
|
104
|
+
/**
|
|
105
|
+
* Gate / officer same-parent resume key (#747 / #987). Countersign gate re-ask
|
|
106
|
+
* looks up prior 给事中 by this parent run directory, never by ticket number.
|
|
107
|
+
*/
|
|
108
|
+
readonly parentRunPath?: string;
|
|
104
109
|
/** Caller correlation id for nested leg ledger (ADR 0010 / #924). */
|
|
105
110
|
readonly correlationId?: string;
|
|
106
111
|
/**
|
|
@@ -436,6 +441,9 @@ export async function summonPublicRole(
|
|
|
436
441
|
...(options.boundTicketNumber === undefined
|
|
437
442
|
? {}
|
|
438
443
|
: { boundTicketNumber: options.boundTicketNumber }),
|
|
444
|
+
...(options.parentRunPath === undefined || options.parentRunPath.trim() === ""
|
|
445
|
+
? {}
|
|
446
|
+
: { parentRunPath: options.parentRunPath }),
|
|
439
447
|
...(options.correlationId === undefined || options.correlationId.trim() === ""
|
|
440
448
|
? {}
|
|
441
449
|
: { correlationId: options.correlationId }),
|
|
@@ -1040,7 +1048,7 @@ export async function summonParallelReviewerLenses(options: {
|
|
|
1040
1048
|
return results;
|
|
1041
1049
|
}
|
|
1042
1050
|
|
|
1043
|
-
/** Gate officer summons: notary/auditor via --source-run; inspector via pointer; countersign via
|
|
1051
|
+
/** Gate officer summons: notary/auditor via --source-run; inspector via pointer; countersign via parentRunPath (#969 / #987). */
|
|
1044
1052
|
export async function summonGateOfficer(options: {
|
|
1045
1053
|
readonly officer: "inspector" | "notary" | "auditor" | "countersign";
|
|
1046
1054
|
readonly sourceRunDirectory: string;
|
|
@@ -1122,11 +1130,11 @@ export async function summonGateOfficer(options: {
|
|
|
1122
1130
|
});
|
|
1123
1131
|
}
|
|
1124
1132
|
if (options.officer === "countersign") {
|
|
1125
|
-
// #969: Secretariat submission gate → 给事中.
|
|
1133
|
+
// #969 / #987: Secretariat submission gate → 给事中.
|
|
1126
1134
|
// Dialogue / identity instruction = parent typed payload 原话 (ADR 0079) or reask;
|
|
1127
|
-
// no code-authored summons prose (#924).
|
|
1128
|
-
// board
|
|
1129
|
-
//
|
|
1135
|
+
// no code-authored summons prose (#924). Gate resume key = parentRunPath
|
|
1136
|
+
// (sourceRunDirectory); board ticket handoff is bind-only, never a resume
|
|
1137
|
+
// lookup (#987 Result 7). Receipt ticketNumber stays payload content.
|
|
1130
1138
|
// correlationId only on this officer — notary/auditor/inspector stay untouched.
|
|
1131
1139
|
const { runIdFromRunDirectory } = await import("./run-terminal-artifacts.ts");
|
|
1132
1140
|
const correlationId = runIdFromRunDirectory(options.sourceRunDirectory);
|
|
@@ -1144,6 +1152,7 @@ export async function summonGateOfficer(options: {
|
|
|
1144
1152
|
argv: ["--project", options.cwd, "--", instruction],
|
|
1145
1153
|
...common,
|
|
1146
1154
|
correlationId,
|
|
1155
|
+
parentRunPath: options.sourceRunDirectory,
|
|
1147
1156
|
...(parentTicket === undefined ? {} : { boundTicketNumber: parentTicket }),
|
|
1148
1157
|
});
|
|
1149
1158
|
}
|
package/src/role-runtime.ts
CHANGED
|
@@ -1199,13 +1199,22 @@ export function createSecretariatRoleRuntime(
|
|
|
1199
1199
|
const summon = dependencies.summonCountersign;
|
|
1200
1200
|
const summoned = summon === undefined
|
|
1201
1201
|
? await (async () => {
|
|
1202
|
+
// #987 Result 7 / #747: mid-turn summon resumes by parentRunPath
|
|
1203
|
+
// (secretariat run dir), same key as summonGateOfficer countersign.
|
|
1204
|
+
// Board ticket is bind-only — never the resume lookup.
|
|
1202
1205
|
const coordinates = readRoleRunCoordinates(ctx, "secretariat summons");
|
|
1203
1206
|
const { summonPublicRole } = await import("./public-role-summons.ts");
|
|
1207
|
+
const { readBoardTicketNumber } = await import("./run-ticket-number.ts");
|
|
1208
|
+
const parentTicket = await readBoardTicketNumber(coordinates.runDirectory);
|
|
1204
1209
|
return summonPublicRole({
|
|
1205
1210
|
role: "countersign",
|
|
1206
1211
|
argv: ["--project", coordinates.projectRoot, "--", instruction],
|
|
1207
1212
|
cwd: coordinates.projectRoot,
|
|
1208
1213
|
home: coordinates.home,
|
|
1214
|
+
parentRunPath: coordinates.runDirectory,
|
|
1215
|
+
...(parentTicket === undefined
|
|
1216
|
+
? {}
|
|
1217
|
+
: { boundTicketNumber: parentTicket }),
|
|
1209
1218
|
...(signal === undefined ? {} : { signal }),
|
|
1210
1219
|
...(correlationId === undefined ? {} : { correlationId }),
|
|
1211
1220
|
...(dependencies.packageRoot === undefined
|