@akagilnc/pi-workflow-roles 0.1.5938 → 0.1.5946
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 +58 -33
- package/dist/headless-host/production-host.js +50 -25
- package/dist/public-cli/instruction-seat-run.js +2 -1
- package/dist/public-cli/main.js +52 -27
- package/dist/public-cli/run-lifecycle.js +1 -1
- package/dist/public-cli/seat-ticket-binding.js +45 -17
- package/package.json +3 -4
- package/src/public-cli/instruction-seat-run.ts +2 -1
- package/src/public-cli/run-lifecycle.ts +1 -1
- package/src/public-cli/seat-ticket-binding.ts +43 -16
package/README.md
CHANGED
|
@@ -140,7 +140,7 @@ ak-role --model <provider/model[:thinking]> resume <runId> "<ruling>"
|
|
|
140
140
|
|
|
141
141
|
## Tests
|
|
142
142
|
|
|
143
|
-
|
|
143
|
+
Tests run on Vitest ([ADR 0090](docs/adr/0090-tests-run-on-vitest-fixtures-and-helpers-from-the-platform.md)). `pnpm test` runs the unit and contract projects, including root-level tests. `pnpm test:all` runs all three projects. `pnpm test:integration` runs the integration project. For a focused run:
|
|
144
144
|
|
|
145
145
|
```bash
|
|
146
146
|
pnpm exec vitest run --project unit-contract
|
package/README.zh-CN.md
CHANGED
|
@@ -14233,24 +14233,48 @@ var init_post_admission = __esm({
|
|
|
14233
14233
|
});
|
|
14234
14234
|
|
|
14235
14235
|
// src/public-cli/seat-ticket-binding.ts
|
|
14236
|
+
import { join as join22 } from "node:path";
|
|
14237
|
+
function resumedSessionIdMissing(result, runId) {
|
|
14238
|
+
if (typeof result !== "object" || result === null) return false;
|
|
14239
|
+
const terminal = result.terminal;
|
|
14240
|
+
if (typeof terminal !== "object" || terminal === null) return false;
|
|
14241
|
+
if (terminal.runId !== runId) return false;
|
|
14242
|
+
const outcome = terminal.roleOutcome;
|
|
14243
|
+
if (typeof outcome !== "object" || outcome === null) return false;
|
|
14244
|
+
if (outcome.kind !== "failure") return false;
|
|
14245
|
+
const facts = outcome.decisiveFacts;
|
|
14246
|
+
if (typeof facts !== "object" || facts === null) return false;
|
|
14247
|
+
return facts.errorCode === SESSION_ID_MISSING;
|
|
14248
|
+
}
|
|
14249
|
+
async function writerLockBlocksFreshSummons(runDirectory) {
|
|
14250
|
+
const autopsy = await autopsyWriterLock(join22(runDirectory, WRITER_LOCK_FILE));
|
|
14251
|
+
return autopsy.verdict === "alive" || autopsy.verdict === "unknown";
|
|
14252
|
+
}
|
|
14236
14253
|
async function tryResumeSameTicketSeatRun(input) {
|
|
14237
14254
|
if (input.freshSummons === true) return void 0;
|
|
14238
14255
|
if (input.parentRunPath.trim() === "") return void 0;
|
|
14256
|
+
const bookKey = resolveBookKeyFromGit(input.projectRoot);
|
|
14239
14257
|
const previous = await findLatestRunForSeatTicket({
|
|
14240
14258
|
home: input.home,
|
|
14241
|
-
bookKey
|
|
14259
|
+
bookKey,
|
|
14242
14260
|
role: input.role,
|
|
14243
14261
|
parentRunPath: input.parentRunPath,
|
|
14244
14262
|
...input.ticketNumber === void 0 ? {} : { ticketNumber: input.ticketNumber }
|
|
14245
14263
|
});
|
|
14246
14264
|
if (previous === void 0) return void 0;
|
|
14247
|
-
|
|
14265
|
+
const resumed = await input.resume(previous.runId, input.summons, previous.runDirectory);
|
|
14266
|
+
if (!resumedSessionIdMissing(resumed, previous.runId)) return resumed;
|
|
14267
|
+
const live = await resolveLiveRunDirectoryPath(previous.runDirectory, input.home, bookKey);
|
|
14268
|
+
if (live !== void 0 && await writerLockBlocksFreshSummons(live)) return resumed;
|
|
14269
|
+
return void 0;
|
|
14248
14270
|
}
|
|
14271
|
+
var SESSION_ID_MISSING;
|
|
14249
14272
|
var init_seat_ticket_binding = __esm({
|
|
14250
14273
|
"src/public-cli/seat-ticket-binding.ts"() {
|
|
14251
14274
|
"use strict";
|
|
14252
14275
|
init_activation_ledger_git();
|
|
14253
14276
|
init_run_lifecycle();
|
|
14277
|
+
SESSION_ID_MISSING = "session-id-missing";
|
|
14254
14278
|
}
|
|
14255
14279
|
});
|
|
14256
14280
|
|
|
@@ -15909,10 +15933,10 @@ var init_analyst_book_key = __esm({
|
|
|
15909
15933
|
// src/atomic-write.ts
|
|
15910
15934
|
import { randomUUID as randomUUID7 } from "node:crypto";
|
|
15911
15935
|
import { rename as rename2, rm, writeFile as writeFile3 } from "node:fs/promises";
|
|
15912
|
-
import { dirname as dirname14, join as
|
|
15936
|
+
import { dirname as dirname14, join as join23 } from "node:path";
|
|
15913
15937
|
async function writeFileAtomically(destination, contents, options) {
|
|
15914
15938
|
const parent = dirname14(destination);
|
|
15915
|
-
const temporary =
|
|
15939
|
+
const temporary = join23(parent, `.atomic-write-${randomUUID7()}.tmp`);
|
|
15916
15940
|
try {
|
|
15917
15941
|
await writeFile3(temporary, contents, options);
|
|
15918
15942
|
await rename2(temporary, destination);
|
|
@@ -15929,12 +15953,12 @@ var init_atomic_write = __esm({
|
|
|
15929
15953
|
|
|
15930
15954
|
// src/analyst-index.ts
|
|
15931
15955
|
import { open, readFile as readFile10, unlink } from "node:fs/promises";
|
|
15932
|
-
import { dirname as dirname15, join as
|
|
15956
|
+
import { dirname as dirname15, join as join24 } from "node:path";
|
|
15933
15957
|
import { setTimeout as sleep } from "node:timers/promises";
|
|
15934
15958
|
async function withAnalystLibraryIndexLock(ledgerHome, fn) {
|
|
15935
15959
|
const indexPath = analystLibraryIndexPath(ledgerHome);
|
|
15936
15960
|
ensureRealDirectoryTree(ledgerHome, dirname15(indexPath));
|
|
15937
|
-
const lockPath =
|
|
15961
|
+
const lockPath = join24(dirname15(indexPath), LIBRARY_INDEX_LOCK_NAME);
|
|
15938
15962
|
assertLedgerFileInsideHome(lockPath, ledgerHome);
|
|
15939
15963
|
const startedAt = Date.now();
|
|
15940
15964
|
while (true) {
|
|
@@ -15961,7 +15985,7 @@ async function withAnalystLibraryIndexLock(ledgerHome, fn) {
|
|
|
15961
15985
|
}
|
|
15962
15986
|
}
|
|
15963
15987
|
function analystLibraryIndexPath(ledgerHome) {
|
|
15964
|
-
return
|
|
15988
|
+
return join24(ledgerHome, "analyst", "library-index.json");
|
|
15965
15989
|
}
|
|
15966
15990
|
function rowFromIssueMetricsPage(page) {
|
|
15967
15991
|
return {
|
|
@@ -16255,7 +16279,7 @@ var init_analyst_cohort = __esm({
|
|
|
16255
16279
|
});
|
|
16256
16280
|
|
|
16257
16281
|
// src/archivist-record-pointer.ts
|
|
16258
|
-
import { basename as basename11, join as
|
|
16282
|
+
import { basename as basename11, join as join25 } from "node:path";
|
|
16259
16283
|
async function resolveOfficerPointer(raw, parentRunDirectory) {
|
|
16260
16284
|
const where = `${parentRunDirectory} officers`;
|
|
16261
16285
|
if (!isRecord(raw) || raw.kind !== DIRECT_OFFICER_RUN_POINTER_KIND || raw.version !== 1) {
|
|
@@ -16288,7 +16312,7 @@ async function resolveOfficerPointer(raw, parentRunDirectory) {
|
|
|
16288
16312
|
};
|
|
16289
16313
|
}
|
|
16290
16314
|
async function readBookedOfficerPointers(parentRunDirectory) {
|
|
16291
|
-
const { records, diagnostics } = await readSitianRecords(
|
|
16315
|
+
const { records, diagnostics } = await readSitianRecords(join25(parentRunDirectory, RUN_HISTORY_FILE));
|
|
16292
16316
|
if (diagnostics.length > 0) {
|
|
16293
16317
|
throw new Error(
|
|
16294
16318
|
`${RUN_HISTORY_FILE} has ${diagnostics.length} malformed row(s); officer pointers unreadable: ${parentRunDirectory}`
|
|
@@ -16571,7 +16595,7 @@ var init_analyst_gate_cycles_read = __esm({
|
|
|
16571
16595
|
|
|
16572
16596
|
// src/analyst-ledger.ts
|
|
16573
16597
|
import { readdir as readdir3 } from "node:fs/promises";
|
|
16574
|
-
import { basename as basename12, join as
|
|
16598
|
+
import { basename as basename12, join as join26 } from "node:path";
|
|
16575
16599
|
async function readExistingRunLifecycleState(runDirectory) {
|
|
16576
16600
|
return (await readRoleRunIdentity(runDirectory))?.state;
|
|
16577
16601
|
}
|
|
@@ -16591,7 +16615,7 @@ function ghostLeaseCheckFromAutopsy(autopsy) {
|
|
|
16591
16615
|
}
|
|
16592
16616
|
}
|
|
16593
16617
|
async function classifyGhostCandidate(input) {
|
|
16594
|
-
const autopsy = await autopsyWriterLock(
|
|
16618
|
+
const autopsy = await autopsyWriterLock(join26(input.runDirectory, "writer.lock"));
|
|
16595
16619
|
const leaseCheck = ghostLeaseCheckFromAutopsy(autopsy);
|
|
16596
16620
|
if (leaseCheck === void 0) return { kind: "live" };
|
|
16597
16621
|
return {
|
|
@@ -16881,7 +16905,7 @@ async function classifyScopedRun(input) {
|
|
|
16881
16905
|
async function scanAnalystIssueRuns(input) {
|
|
16882
16906
|
const ledgerHome = resolveActivationLedgerHome(input.home);
|
|
16883
16907
|
const scopeTicketNumber = input.ticketNumber;
|
|
16884
|
-
const booksRoot =
|
|
16908
|
+
const booksRoot = join26(ledgerHome, "books");
|
|
16885
16909
|
let wholeBook = false;
|
|
16886
16910
|
let scopeRootIdentity;
|
|
16887
16911
|
let bookNames;
|
|
@@ -16914,7 +16938,7 @@ async function scanAnalystIssueRuns(input) {
|
|
|
16914
16938
|
const ghostLegs = [];
|
|
16915
16939
|
const scopeConflicts = [];
|
|
16916
16940
|
for (const book of bookNames) {
|
|
16917
|
-
const bookDir =
|
|
16941
|
+
const bookDir = join26(booksRoot, book);
|
|
16918
16942
|
let runDirectories;
|
|
16919
16943
|
try {
|
|
16920
16944
|
runDirectories = await listBookRunDirectories(bookDir);
|
|
@@ -17660,7 +17684,7 @@ var init_analyst_metric_family = __esm({
|
|
|
17660
17684
|
});
|
|
17661
17685
|
|
|
17662
17686
|
// src/analyst-page.ts
|
|
17663
|
-
import { dirname as dirname16, join as
|
|
17687
|
+
import { dirname as dirname16, join as join27 } from "node:path";
|
|
17664
17688
|
function analystIssuePageKey(address) {
|
|
17665
17689
|
const parts = ["book", address.bookKey];
|
|
17666
17690
|
if (address.issueNumber !== void 0) {
|
|
@@ -17671,7 +17695,7 @@ function analystIssuePageKey(address) {
|
|
|
17671
17695
|
return sha256Hex(parts.join("\0")).slice(0, 32);
|
|
17672
17696
|
}
|
|
17673
17697
|
function analystIssuePagePath(ledgerHome, address) {
|
|
17674
|
-
return
|
|
17698
|
+
return join27(ledgerHome, "analyst", "issues", `${analystIssuePageKey(address)}.json`);
|
|
17675
17699
|
}
|
|
17676
17700
|
function analystIssuePageAddressFromPage(page) {
|
|
17677
17701
|
return {
|
|
@@ -19235,7 +19259,7 @@ __export(public_role_summons_exports, {
|
|
|
19235
19259
|
import { execFile as execFile3 } from "node:child_process";
|
|
19236
19260
|
import { existsSync as existsSync12 } from "node:fs";
|
|
19237
19261
|
import { realpath as realpath6 } from "node:fs/promises";
|
|
19238
|
-
import { join as
|
|
19262
|
+
import { join as join28 } from "node:path";
|
|
19239
19263
|
import { promisify as promisify3 } from "node:util";
|
|
19240
19264
|
function createCapturingIo() {
|
|
19241
19265
|
const chunks = [];
|
|
@@ -19259,7 +19283,7 @@ function parentDir(path) {
|
|
|
19259
19283
|
function walkPackageRoot(start) {
|
|
19260
19284
|
let dir = start;
|
|
19261
19285
|
for (let i = 0; i < 12; i += 1) {
|
|
19262
|
-
if (existsSync12(
|
|
19286
|
+
if (existsSync12(join28(dir, "package.json")) && existsSync12(join28(dir, "souls"))) {
|
|
19263
19287
|
return dir;
|
|
19264
19288
|
}
|
|
19265
19289
|
const parent = parentDir(dir);
|
|
@@ -19808,7 +19832,7 @@ var init_compliance_transport = __esm({
|
|
|
19808
19832
|
});
|
|
19809
19833
|
|
|
19810
19834
|
// src/role-run-relocation.ts
|
|
19811
|
-
import { dirname as dirname17, join as
|
|
19835
|
+
import { dirname as dirname17, join as join29 } from "node:path";
|
|
19812
19836
|
async function retainedRunPathsMatch(recordedPath, currentPath, currentRunDirectory) {
|
|
19813
19837
|
if (recordedPath === currentPath) return true;
|
|
19814
19838
|
if (typeof recordedPath !== "string") return false;
|
|
@@ -19854,6 +19878,7 @@ var run_lifecycle_exports = {};
|
|
|
19854
19878
|
__export(run_lifecycle_exports, {
|
|
19855
19879
|
AUTO_RESUME_LIMIT: () => AUTO_RESUME_LIMIT,
|
|
19856
19880
|
RunWriterLeaseHeldError: () => RunWriterLeaseHeldError,
|
|
19881
|
+
WRITER_LOCK_FILE: () => WRITER_LOCK_FILE,
|
|
19857
19882
|
acquireRunWriterLease: () => acquireRunWriterLease,
|
|
19858
19883
|
autopsyWriterLock: () => autopsyWriterLock,
|
|
19859
19884
|
clearCurrentCourt: () => clearCurrentCourt,
|
|
@@ -19876,7 +19901,7 @@ __export(run_lifecycle_exports, {
|
|
|
19876
19901
|
});
|
|
19877
19902
|
import { existsSync as existsSync13 } from "node:fs";
|
|
19878
19903
|
import { chmod, lstat as lstat3, open as open2, readdir as readdir4, readFile as readFile14, unlink as unlink2 } from "node:fs/promises";
|
|
19879
|
-
import { basename as basename13, join as
|
|
19904
|
+
import { basename as basename13, join as join30 } from "node:path";
|
|
19880
19905
|
async function writeRoleRunState(runDirectory, record) {
|
|
19881
19906
|
const payload = { ...record, runDirectory };
|
|
19882
19907
|
writeSectionSync(runDirectory, "runState", { ...payload });
|
|
@@ -20171,7 +20196,7 @@ async function createWriterLease(lockPath, runDirectory, reportCleanupFailure) {
|
|
|
20171
20196
|
},
|
|
20172
20197
|
relocate(nextRunDirectory) {
|
|
20173
20198
|
currentRunDirectory = nextRunDirectory;
|
|
20174
|
-
currentLockPath =
|
|
20199
|
+
currentLockPath = join30(nextRunDirectory, WRITER_LOCK_FILE);
|
|
20175
20200
|
},
|
|
20176
20201
|
async release() {
|
|
20177
20202
|
if (released) return;
|
|
@@ -20210,10 +20235,10 @@ async function acquireRunWriterLease(runDirectory, onCleanupFailure) {
|
|
|
20210
20235
|
};
|
|
20211
20236
|
const reportReadFailure = (error) => {
|
|
20212
20237
|
reportDiagnostic(
|
|
20213
|
-
`writer lease lock read failed (holder liveness unverifiable; lock left in place) at ${
|
|
20238
|
+
`writer lease lock read failed (holder liveness unverifiable; lock left in place) at ${join30(runDirectory, WRITER_LOCK_FILE)}: ${describeErrorIdentity(error)}`
|
|
20214
20239
|
);
|
|
20215
20240
|
};
|
|
20216
|
-
const lockPath =
|
|
20241
|
+
const lockPath = join30(runDirectory, WRITER_LOCK_FILE);
|
|
20217
20242
|
let lastAutopsy = { verdict: "absent" };
|
|
20218
20243
|
let lastReclaimFailure;
|
|
20219
20244
|
for (let reclaimsLeft = WRITER_LEASE_RECLAIM_ROUNDS; ; reclaimsLeft -= 1) {
|
|
@@ -20279,7 +20304,7 @@ async function findRunDirectoryById(home, runId, onlyBookKey, onlyRole, knownRun
|
|
|
20279
20304
|
}
|
|
20280
20305
|
if (runId.trim() === "") return void 0;
|
|
20281
20306
|
const ledgerHome = resolveActivationLedgerHome(home);
|
|
20282
|
-
const booksRoot =
|
|
20307
|
+
const booksRoot = join30(ledgerHome, "books");
|
|
20283
20308
|
let bookKeys;
|
|
20284
20309
|
try {
|
|
20285
20310
|
bookKeys = await readdir4(booksRoot);
|
|
@@ -20329,7 +20354,7 @@ async function findLatestRunForSeatTicket(input) {
|
|
|
20329
20354
|
let runDirectories;
|
|
20330
20355
|
try {
|
|
20331
20356
|
runDirectories = await listBookRunDirectories(
|
|
20332
|
-
input.ticketNumber === void 0 ? bookDir :
|
|
20357
|
+
input.ticketNumber === void 0 ? bookDir : join30(bookDir, String(input.ticketNumber))
|
|
20333
20358
|
);
|
|
20334
20359
|
} catch (error) {
|
|
20335
20360
|
if (errorCodeOf(error) === "ENOENT") return void 0;
|
|
@@ -21068,7 +21093,7 @@ init_submission_ledger();
|
|
|
21068
21093
|
init_filed_submission();
|
|
21069
21094
|
init_report_ticket_tool();
|
|
21070
21095
|
import { writeSync as writeSync2 } from "node:fs";
|
|
21071
|
-
import { join as
|
|
21096
|
+
import { join as join31 } from "node:path";
|
|
21072
21097
|
import { Value as Value2 } from "typebox/value";
|
|
21073
21098
|
|
|
21074
21099
|
// src/activation-trace.ts
|
|
@@ -22865,7 +22890,7 @@ function readRoleRunCoordinates(ctx, label) {
|
|
|
22865
22890
|
if (runDirectory === void 0) throw new Error(`${label} requires AK_ROLE_RUN_DIR`);
|
|
22866
22891
|
const admitted = readPageSync(runDirectory, "admitted");
|
|
22867
22892
|
if (typeof admitted?.projectRoot !== "string" || admitted.projectRoot.trim() === "") {
|
|
22868
|
-
throw new Error(`${label} state.jsonl admitted-request row missing projectRoot (${
|
|
22893
|
+
throw new Error(`${label} state.jsonl admitted-request row missing projectRoot (${join31(runDirectory, RUN_STATE_FILE)})`);
|
|
22869
22894
|
}
|
|
22870
22895
|
return {
|
|
22871
22896
|
runDirectory,
|
|
@@ -24632,12 +24657,12 @@ function createAcpRoleTurnHost(config) {
|
|
|
24632
24657
|
// src/acp-host/seat-profile-soul.ts
|
|
24633
24658
|
import { constants as constants3 } from "node:fs";
|
|
24634
24659
|
import { access as access3, copyFile, lstat as lstat4, mkdir as mkdir4, readlink, symlink as symlink2, unlink as unlink3 } from "node:fs/promises";
|
|
24635
|
-
import { dirname as dirname19, join as
|
|
24660
|
+
import { dirname as dirname19, join as join32, relative as relative4, resolve as resolve16 } from "node:path";
|
|
24636
24661
|
function seatProfileName(spec, role) {
|
|
24637
24662
|
return `${spec.namePrefix}${role}`;
|
|
24638
24663
|
}
|
|
24639
24664
|
function packageRoleSoulPath(packageRoot, role) {
|
|
24640
|
-
return
|
|
24665
|
+
return join32(packageRoot, "souls", `${role}.md`);
|
|
24641
24666
|
}
|
|
24642
24667
|
async function pathExists2(path) {
|
|
24643
24668
|
try {
|
|
@@ -24654,16 +24679,16 @@ async function ensureSeatProfileSoul(options) {
|
|
|
24654
24679
|
if (!await pathExists2(soulTarget)) {
|
|
24655
24680
|
throw new Error(`packaged role soul missing: ${soulTarget}`);
|
|
24656
24681
|
}
|
|
24657
|
-
const profilesRoot =
|
|
24658
|
-
const profileDir =
|
|
24682
|
+
const profilesRoot = join32(operatorHome, ...spec.profilesRootFromHome);
|
|
24683
|
+
const profileDir = join32(profilesRoot, profileName);
|
|
24659
24684
|
const hostRoot = dirname19(profilesRoot);
|
|
24660
|
-
const soulPath =
|
|
24685
|
+
const soulPath = join32(profileDir, spec.soulFileName);
|
|
24661
24686
|
if (!await pathExists2(profileDir)) {
|
|
24662
24687
|
await mkdir4(profileDir, { recursive: true });
|
|
24663
24688
|
for (const name of ["auth.json", ".env", "config.yaml"]) {
|
|
24664
|
-
const source =
|
|
24689
|
+
const source = join32(hostRoot, name);
|
|
24665
24690
|
if (!await pathExists2(source)) continue;
|
|
24666
|
-
await copyFile(source,
|
|
24691
|
+
await copyFile(source, join32(profileDir, name));
|
|
24667
24692
|
}
|
|
24668
24693
|
} else {
|
|
24669
24694
|
await mkdir4(profileDir, { recursive: true });
|
|
@@ -9390,6 +9390,7 @@ var run_lifecycle_exports = {};
|
|
|
9390
9390
|
__export(run_lifecycle_exports, {
|
|
9391
9391
|
AUTO_RESUME_LIMIT: () => AUTO_RESUME_LIMIT,
|
|
9392
9392
|
RunWriterLeaseHeldError: () => RunWriterLeaseHeldError,
|
|
9393
|
+
WRITER_LOCK_FILE: () => WRITER_LOCK_FILE,
|
|
9393
9394
|
acquireRunWriterLease: () => acquireRunWriterLease,
|
|
9394
9395
|
autopsyWriterLock: () => autopsyWriterLock,
|
|
9395
9396
|
clearCurrentCourt: () => clearCurrentCourt,
|
|
@@ -15580,24 +15581,48 @@ var init_post_admission = __esm({
|
|
|
15580
15581
|
});
|
|
15581
15582
|
|
|
15582
15583
|
// src/public-cli/seat-ticket-binding.ts
|
|
15584
|
+
import { join as join24 } from "node:path";
|
|
15585
|
+
function resumedSessionIdMissing(result, runId) {
|
|
15586
|
+
if (typeof result !== "object" || result === null) return false;
|
|
15587
|
+
const terminal = result.terminal;
|
|
15588
|
+
if (typeof terminal !== "object" || terminal === null) return false;
|
|
15589
|
+
if (terminal.runId !== runId) return false;
|
|
15590
|
+
const outcome = terminal.roleOutcome;
|
|
15591
|
+
if (typeof outcome !== "object" || outcome === null) return false;
|
|
15592
|
+
if (outcome.kind !== "failure") return false;
|
|
15593
|
+
const facts = outcome.decisiveFacts;
|
|
15594
|
+
if (typeof facts !== "object" || facts === null) return false;
|
|
15595
|
+
return facts.errorCode === SESSION_ID_MISSING;
|
|
15596
|
+
}
|
|
15597
|
+
async function writerLockBlocksFreshSummons(runDirectory) {
|
|
15598
|
+
const autopsy = await autopsyWriterLock(join24(runDirectory, WRITER_LOCK_FILE));
|
|
15599
|
+
return autopsy.verdict === "alive" || autopsy.verdict === "unknown";
|
|
15600
|
+
}
|
|
15583
15601
|
async function tryResumeSameTicketSeatRun(input) {
|
|
15584
15602
|
if (input.freshSummons === true) return void 0;
|
|
15585
15603
|
if (input.parentRunPath.trim() === "") return void 0;
|
|
15604
|
+
const bookKey = resolveBookKeyFromGit(input.projectRoot);
|
|
15586
15605
|
const previous = await findLatestRunForSeatTicket({
|
|
15587
15606
|
home: input.home,
|
|
15588
|
-
bookKey
|
|
15607
|
+
bookKey,
|
|
15589
15608
|
role: input.role,
|
|
15590
15609
|
parentRunPath: input.parentRunPath,
|
|
15591
15610
|
...input.ticketNumber === void 0 ? {} : { ticketNumber: input.ticketNumber }
|
|
15592
15611
|
});
|
|
15593
15612
|
if (previous === void 0) return void 0;
|
|
15594
|
-
|
|
15613
|
+
const resumed = await input.resume(previous.runId, input.summons, previous.runDirectory);
|
|
15614
|
+
if (!resumedSessionIdMissing(resumed, previous.runId)) return resumed;
|
|
15615
|
+
const live = await resolveLiveRunDirectoryPath(previous.runDirectory, input.home, bookKey);
|
|
15616
|
+
if (live !== void 0 && await writerLockBlocksFreshSummons(live)) return resumed;
|
|
15617
|
+
return void 0;
|
|
15595
15618
|
}
|
|
15619
|
+
var SESSION_ID_MISSING;
|
|
15596
15620
|
var init_seat_ticket_binding = __esm({
|
|
15597
15621
|
"src/public-cli/seat-ticket-binding.ts"() {
|
|
15598
15622
|
"use strict";
|
|
15599
15623
|
init_activation_ledger_git();
|
|
15600
15624
|
init_run_lifecycle();
|
|
15625
|
+
SESSION_ID_MISSING = "session-id-missing";
|
|
15601
15626
|
}
|
|
15602
15627
|
});
|
|
15603
15628
|
|
|
@@ -17256,10 +17281,10 @@ var init_analyst_book_key = __esm({
|
|
|
17256
17281
|
// src/atomic-write.ts
|
|
17257
17282
|
import { randomUUID as randomUUID7 } from "node:crypto";
|
|
17258
17283
|
import { rename as rename2, rm, writeFile as writeFile4 } from "node:fs/promises";
|
|
17259
|
-
import { dirname as dirname15, join as
|
|
17284
|
+
import { dirname as dirname15, join as join25 } from "node:path";
|
|
17260
17285
|
async function writeFileAtomically(destination, contents, options) {
|
|
17261
17286
|
const parent = dirname15(destination);
|
|
17262
|
-
const temporary =
|
|
17287
|
+
const temporary = join25(parent, `.atomic-write-${randomUUID7()}.tmp`);
|
|
17263
17288
|
try {
|
|
17264
17289
|
await writeFile4(temporary, contents, options);
|
|
17265
17290
|
await rename2(temporary, destination);
|
|
@@ -17276,12 +17301,12 @@ var init_atomic_write = __esm({
|
|
|
17276
17301
|
|
|
17277
17302
|
// src/analyst-index.ts
|
|
17278
17303
|
import { open as open2, readFile as readFile11, unlink as unlink2 } from "node:fs/promises";
|
|
17279
|
-
import { dirname as dirname16, join as
|
|
17304
|
+
import { dirname as dirname16, join as join26 } from "node:path";
|
|
17280
17305
|
import { setTimeout as sleep } from "node:timers/promises";
|
|
17281
17306
|
async function withAnalystLibraryIndexLock(ledgerHome, fn) {
|
|
17282
17307
|
const indexPath = analystLibraryIndexPath(ledgerHome);
|
|
17283
17308
|
ensureRealDirectoryTree(ledgerHome, dirname16(indexPath));
|
|
17284
|
-
const lockPath =
|
|
17309
|
+
const lockPath = join26(dirname16(indexPath), LIBRARY_INDEX_LOCK_NAME);
|
|
17285
17310
|
assertLedgerFileInsideHome(lockPath, ledgerHome);
|
|
17286
17311
|
const startedAt = Date.now();
|
|
17287
17312
|
while (true) {
|
|
@@ -17308,7 +17333,7 @@ async function withAnalystLibraryIndexLock(ledgerHome, fn) {
|
|
|
17308
17333
|
}
|
|
17309
17334
|
}
|
|
17310
17335
|
function analystLibraryIndexPath(ledgerHome) {
|
|
17311
|
-
return
|
|
17336
|
+
return join26(ledgerHome, "analyst", "library-index.json");
|
|
17312
17337
|
}
|
|
17313
17338
|
function rowFromIssueMetricsPage(page) {
|
|
17314
17339
|
return {
|
|
@@ -17602,7 +17627,7 @@ var init_analyst_cohort = __esm({
|
|
|
17602
17627
|
});
|
|
17603
17628
|
|
|
17604
17629
|
// src/archivist-record-pointer.ts
|
|
17605
|
-
import { basename as basename12, join as
|
|
17630
|
+
import { basename as basename12, join as join27 } from "node:path";
|
|
17606
17631
|
async function resolveOfficerPointer(raw, parentRunDirectory) {
|
|
17607
17632
|
const where = `${parentRunDirectory} officers`;
|
|
17608
17633
|
if (!isRecord(raw) || raw.kind !== DIRECT_OFFICER_RUN_POINTER_KIND || raw.version !== 1) {
|
|
@@ -17635,7 +17660,7 @@ async function resolveOfficerPointer(raw, parentRunDirectory) {
|
|
|
17635
17660
|
};
|
|
17636
17661
|
}
|
|
17637
17662
|
async function readBookedOfficerPointers(parentRunDirectory) {
|
|
17638
|
-
const { records, diagnostics } = await readSitianRecords(
|
|
17663
|
+
const { records, diagnostics } = await readSitianRecords(join27(parentRunDirectory, RUN_HISTORY_FILE));
|
|
17639
17664
|
if (diagnostics.length > 0) {
|
|
17640
17665
|
throw new Error(
|
|
17641
17666
|
`${RUN_HISTORY_FILE} has ${diagnostics.length} malformed row(s); officer pointers unreadable: ${parentRunDirectory}`
|
|
@@ -17918,7 +17943,7 @@ var init_analyst_gate_cycles_read = __esm({
|
|
|
17918
17943
|
|
|
17919
17944
|
// src/analyst-ledger.ts
|
|
17920
17945
|
import { readdir as readdir4 } from "node:fs/promises";
|
|
17921
|
-
import { basename as basename13, join as
|
|
17946
|
+
import { basename as basename13, join as join28 } from "node:path";
|
|
17922
17947
|
async function readExistingRunLifecycleState(runDirectory) {
|
|
17923
17948
|
return (await readRoleRunIdentity(runDirectory))?.state;
|
|
17924
17949
|
}
|
|
@@ -17938,7 +17963,7 @@ function ghostLeaseCheckFromAutopsy(autopsy) {
|
|
|
17938
17963
|
}
|
|
17939
17964
|
}
|
|
17940
17965
|
async function classifyGhostCandidate(input) {
|
|
17941
|
-
const autopsy = await autopsyWriterLock(
|
|
17966
|
+
const autopsy = await autopsyWriterLock(join28(input.runDirectory, "writer.lock"));
|
|
17942
17967
|
const leaseCheck = ghostLeaseCheckFromAutopsy(autopsy);
|
|
17943
17968
|
if (leaseCheck === void 0) return { kind: "live" };
|
|
17944
17969
|
return {
|
|
@@ -18228,7 +18253,7 @@ async function classifyScopedRun(input) {
|
|
|
18228
18253
|
async function scanAnalystIssueRuns(input) {
|
|
18229
18254
|
const ledgerHome = resolveActivationLedgerHome(input.home);
|
|
18230
18255
|
const scopeTicketNumber = input.ticketNumber;
|
|
18231
|
-
const booksRoot =
|
|
18256
|
+
const booksRoot = join28(ledgerHome, "books");
|
|
18232
18257
|
let wholeBook = false;
|
|
18233
18258
|
let scopeRootIdentity;
|
|
18234
18259
|
let bookNames;
|
|
@@ -18261,7 +18286,7 @@ async function scanAnalystIssueRuns(input) {
|
|
|
18261
18286
|
const ghostLegs = [];
|
|
18262
18287
|
const scopeConflicts = [];
|
|
18263
18288
|
for (const book of bookNames) {
|
|
18264
|
-
const bookDir =
|
|
18289
|
+
const bookDir = join28(booksRoot, book);
|
|
18265
18290
|
let runDirectories;
|
|
18266
18291
|
try {
|
|
18267
18292
|
runDirectories = await listBookRunDirectories(bookDir);
|
|
@@ -19007,7 +19032,7 @@ var init_analyst_metric_family = __esm({
|
|
|
19007
19032
|
});
|
|
19008
19033
|
|
|
19009
19034
|
// src/analyst-page.ts
|
|
19010
|
-
import { dirname as dirname17, join as
|
|
19035
|
+
import { dirname as dirname17, join as join29 } from "node:path";
|
|
19011
19036
|
function analystIssuePageKey(address) {
|
|
19012
19037
|
const parts = ["book", address.bookKey];
|
|
19013
19038
|
if (address.issueNumber !== void 0) {
|
|
@@ -19018,7 +19043,7 @@ function analystIssuePageKey(address) {
|
|
|
19018
19043
|
return sha256Hex(parts.join("\0")).slice(0, 32);
|
|
19019
19044
|
}
|
|
19020
19045
|
function analystIssuePagePath(ledgerHome, address) {
|
|
19021
|
-
return
|
|
19046
|
+
return join29(ledgerHome, "analyst", "issues", `${analystIssuePageKey(address)}.json`);
|
|
19022
19047
|
}
|
|
19023
19048
|
function analystIssuePageAddressFromPage(page) {
|
|
19024
19049
|
return {
|
|
@@ -20582,7 +20607,7 @@ __export(public_role_summons_exports, {
|
|
|
20582
20607
|
import { execFile as execFile3 } from "node:child_process";
|
|
20583
20608
|
import { existsSync as existsSync13 } from "node:fs";
|
|
20584
20609
|
import { realpath as realpath6 } from "node:fs/promises";
|
|
20585
|
-
import { join as
|
|
20610
|
+
import { join as join30 } from "node:path";
|
|
20586
20611
|
import { promisify as promisify3 } from "node:util";
|
|
20587
20612
|
function createCapturingIo() {
|
|
20588
20613
|
const chunks = [];
|
|
@@ -20606,7 +20631,7 @@ function parentDir(path) {
|
|
|
20606
20631
|
function walkPackageRoot(start) {
|
|
20607
20632
|
let dir = start;
|
|
20608
20633
|
for (let i = 0; i < 12; i += 1) {
|
|
20609
|
-
if (existsSync13(
|
|
20634
|
+
if (existsSync13(join30(dir, "package.json")) && existsSync13(join30(dir, "souls"))) {
|
|
20610
20635
|
return dir;
|
|
20611
20636
|
}
|
|
20612
20637
|
const parent = parentDir(dir);
|
|
@@ -21214,7 +21239,7 @@ init_submission_ledger();
|
|
|
21214
21239
|
init_filed_submission();
|
|
21215
21240
|
init_report_ticket_tool();
|
|
21216
21241
|
import { writeSync as writeSync2 } from "node:fs";
|
|
21217
|
-
import { join as
|
|
21242
|
+
import { join as join31 } from "node:path";
|
|
21218
21243
|
import { Value as Value2 } from "typebox/value";
|
|
21219
21244
|
|
|
21220
21245
|
// src/activation-trace.ts
|
|
@@ -22832,7 +22857,7 @@ function readRoleRunCoordinates(ctx, label) {
|
|
|
22832
22857
|
if (runDirectory === void 0) throw new Error(`${label} requires AK_ROLE_RUN_DIR`);
|
|
22833
22858
|
const admitted = readPageSync(runDirectory, "admitted");
|
|
22834
22859
|
if (typeof admitted?.projectRoot !== "string" || admitted.projectRoot.trim() === "") {
|
|
22835
|
-
throw new Error(`${label} state.jsonl admitted-request row missing projectRoot (${
|
|
22860
|
+
throw new Error(`${label} state.jsonl admitted-request row missing projectRoot (${join31(runDirectory, RUN_STATE_FILE)})`);
|
|
22836
22861
|
}
|
|
22837
22862
|
return {
|
|
22838
22863
|
runDirectory,
|
|
@@ -24225,7 +24250,7 @@ import { randomUUID as randomUUID10 } from "node:crypto";
|
|
|
24225
24250
|
import { existsSync as existsSync15 } from "node:fs";
|
|
24226
24251
|
import { mkdtemp, rm as rm2, writeFile as writeFile6 } from "node:fs/promises";
|
|
24227
24252
|
import { tmpdir } from "node:os";
|
|
24228
|
-
import { dirname as dirname19, isAbsolute as isAbsolute11, join as
|
|
24253
|
+
import { dirname as dirname19, isAbsolute as isAbsolute11, join as join32, resolve as resolve16 } from "node:path";
|
|
24229
24254
|
|
|
24230
24255
|
// src/agent-start-materials.ts
|
|
24231
24256
|
function renderAgentStartMaterials(body, materials) {
|
|
@@ -24611,7 +24636,7 @@ function formatCodexFailurePayload(payload) {
|
|
|
24611
24636
|
function cwdIsGitWorkTree(cwd) {
|
|
24612
24637
|
let dir = cwd;
|
|
24613
24638
|
for (; ; ) {
|
|
24614
|
-
if (existsSync15(
|
|
24639
|
+
if (existsSync15(join32(dir, ".git"))) return true;
|
|
24615
24640
|
const parent = dirname19(dir);
|
|
24616
24641
|
if (parent === dir) return false;
|
|
24617
24642
|
dir = parent;
|
|
@@ -24828,8 +24853,8 @@ function createHeadlessRoleTurnHost(config) {
|
|
|
24828
24853
|
}
|
|
24829
24854
|
const env = { ...process.env, ...config.env ?? {} };
|
|
24830
24855
|
const liveSessionParent = () => config.sessionIdentity.resolveSessionFile(request.principal);
|
|
24831
|
-
const inputsDirectory = await mkdtemp(
|
|
24832
|
-
const systemPromptPath =
|
|
24856
|
+
const inputsDirectory = await mkdtemp(join32(tmpdir(), "ak-role-headless-"));
|
|
24857
|
+
const systemPromptPath = join32(inputsDirectory, "system-prompt.txt");
|
|
24833
24858
|
let mcpConfigPath;
|
|
24834
24859
|
let outputSchemaPath;
|
|
24835
24860
|
let startedWithSchema;
|
|
@@ -24837,12 +24862,12 @@ function createHeadlessRoleTurnHost(config) {
|
|
|
24837
24862
|
await writeFile6(systemPromptPath, systemPrompt, "utf8");
|
|
24838
24863
|
let deliveredSchema;
|
|
24839
24864
|
if (codex) {
|
|
24840
|
-
outputSchemaPath =
|
|
24865
|
+
outputSchemaPath = join32(inputsDirectory, "output-schema.json");
|
|
24841
24866
|
deliveredSchema = closeJsonSchemaForCodex(prepared.jsonSchema);
|
|
24842
24867
|
await writeFile6(outputSchemaPath, `${JSON.stringify(deliveredSchema, null, 2)}
|
|
24843
24868
|
`, "utf8");
|
|
24844
24869
|
} else {
|
|
24845
|
-
mcpConfigPath =
|
|
24870
|
+
mcpConfigPath = join32(inputsDirectory, "mcp-config.json");
|
|
24846
24871
|
await writeFile6(
|
|
24847
24872
|
mcpConfigPath,
|
|
24848
24873
|
`${JSON.stringify(headlessMcpConfigDocument(prepared.mcpServers), null, 2)}
|
|
@@ -703,7 +703,8 @@ async function runOmittedLensBatch(argv, parsed, env, io) {
|
|
|
703
703
|
}
|
|
704
704
|
/**
|
|
705
705
|
* One same-parent lookup. Seat branches still build their own summons.
|
|
706
|
-
* A found child resumes that child
|
|
706
|
+
* A found child resumes that child. No prior run, explicit new, or a typed
|
|
707
|
+
* session-id-missing resume (失败照记,记完再起新) returns undefined so the caller mints.
|
|
707
708
|
*/
|
|
708
709
|
function resumeSameParentInstructionSeat(input) {
|
|
709
710
|
return tryResumeSameTicketSeatRun({
|
package/dist/public-cli/main.js
CHANGED
|
@@ -19492,24 +19492,48 @@ var init_auto_resume = __esm({
|
|
|
19492
19492
|
});
|
|
19493
19493
|
|
|
19494
19494
|
// src/public-cli/seat-ticket-binding.ts
|
|
19495
|
+
import { join as join21 } from "node:path";
|
|
19496
|
+
function resumedSessionIdMissing(result, runId) {
|
|
19497
|
+
if (typeof result !== "object" || result === null) return false;
|
|
19498
|
+
const terminal = result.terminal;
|
|
19499
|
+
if (typeof terminal !== "object" || terminal === null) return false;
|
|
19500
|
+
if (terminal.runId !== runId) return false;
|
|
19501
|
+
const outcome = terminal.roleOutcome;
|
|
19502
|
+
if (typeof outcome !== "object" || outcome === null) return false;
|
|
19503
|
+
if (outcome.kind !== "failure") return false;
|
|
19504
|
+
const facts = outcome.decisiveFacts;
|
|
19505
|
+
if (typeof facts !== "object" || facts === null) return false;
|
|
19506
|
+
return facts.errorCode === SESSION_ID_MISSING;
|
|
19507
|
+
}
|
|
19508
|
+
async function writerLockBlocksFreshSummons(runDirectory) {
|
|
19509
|
+
const autopsy = await autopsyWriterLock(join21(runDirectory, WRITER_LOCK_FILE));
|
|
19510
|
+
return autopsy.verdict === "alive" || autopsy.verdict === "unknown";
|
|
19511
|
+
}
|
|
19495
19512
|
async function tryResumeSameTicketSeatRun(input) {
|
|
19496
19513
|
if (input.freshSummons === true) return void 0;
|
|
19497
19514
|
if (input.parentRunPath.trim() === "") return void 0;
|
|
19515
|
+
const bookKey = resolveBookKeyFromGit(input.projectRoot);
|
|
19498
19516
|
const previous = await findLatestRunForSeatTicket({
|
|
19499
19517
|
home: input.home,
|
|
19500
|
-
bookKey
|
|
19518
|
+
bookKey,
|
|
19501
19519
|
role: input.role,
|
|
19502
19520
|
parentRunPath: input.parentRunPath,
|
|
19503
19521
|
...input.ticketNumber === void 0 ? {} : { ticketNumber: input.ticketNumber }
|
|
19504
19522
|
});
|
|
19505
19523
|
if (previous === void 0) return void 0;
|
|
19506
|
-
|
|
19524
|
+
const resumed = await input.resume(previous.runId, input.summons, previous.runDirectory);
|
|
19525
|
+
if (!resumedSessionIdMissing(resumed, previous.runId)) return resumed;
|
|
19526
|
+
const live = await resolveLiveRunDirectoryPath(previous.runDirectory, input.home, bookKey);
|
|
19527
|
+
if (live !== void 0 && await writerLockBlocksFreshSummons(live)) return resumed;
|
|
19528
|
+
return void 0;
|
|
19507
19529
|
}
|
|
19530
|
+
var SESSION_ID_MISSING;
|
|
19508
19531
|
var init_seat_ticket_binding = __esm({
|
|
19509
19532
|
"src/public-cli/seat-ticket-binding.ts"() {
|
|
19510
19533
|
"use strict";
|
|
19511
19534
|
init_activation_ledger_git();
|
|
19512
19535
|
init_run_lifecycle();
|
|
19536
|
+
SESSION_ID_MISSING = "session-id-missing";
|
|
19513
19537
|
}
|
|
19514
19538
|
});
|
|
19515
19539
|
|
|
@@ -21208,7 +21232,7 @@ __export(public_role_summons_exports, {
|
|
|
21208
21232
|
import { execFile as execFile3 } from "node:child_process";
|
|
21209
21233
|
import { existsSync as existsSync10 } from "node:fs";
|
|
21210
21234
|
import { realpath as realpath5 } from "node:fs/promises";
|
|
21211
|
-
import { join as
|
|
21235
|
+
import { join as join22 } from "node:path";
|
|
21212
21236
|
import { promisify as promisify3 } from "node:util";
|
|
21213
21237
|
function createCapturingIo() {
|
|
21214
21238
|
const chunks = [];
|
|
@@ -21232,7 +21256,7 @@ function parentDir(path) {
|
|
|
21232
21256
|
function walkPackageRoot(start) {
|
|
21233
21257
|
let dir = start;
|
|
21234
21258
|
for (let i = 0; i < 12; i += 1) {
|
|
21235
|
-
if (existsSync10(
|
|
21259
|
+
if (existsSync10(join22(dir, "package.json")) && existsSync10(join22(dir, "souls"))) {
|
|
21236
21260
|
return dir;
|
|
21237
21261
|
}
|
|
21238
21262
|
const parent = parentDir(dir);
|
|
@@ -21775,7 +21799,7 @@ var init_compliance_transport = __esm({
|
|
|
21775
21799
|
});
|
|
21776
21800
|
|
|
21777
21801
|
// src/role-run-relocation.ts
|
|
21778
|
-
import { dirname as dirname14, join as
|
|
21802
|
+
import { dirname as dirname14, join as join23 } from "node:path";
|
|
21779
21803
|
async function retainedRunPathsMatch(recordedPath, currentPath, currentRunDirectory) {
|
|
21780
21804
|
if (recordedPath === currentPath) return true;
|
|
21781
21805
|
if (typeof recordedPath !== "string") return false;
|
|
@@ -21821,6 +21845,7 @@ var run_lifecycle_exports = {};
|
|
|
21821
21845
|
__export(run_lifecycle_exports, {
|
|
21822
21846
|
AUTO_RESUME_LIMIT: () => AUTO_RESUME_LIMIT,
|
|
21823
21847
|
RunWriterLeaseHeldError: () => RunWriterLeaseHeldError,
|
|
21848
|
+
WRITER_LOCK_FILE: () => WRITER_LOCK_FILE,
|
|
21824
21849
|
acquireRunWriterLease: () => acquireRunWriterLease,
|
|
21825
21850
|
autopsyWriterLock: () => autopsyWriterLock,
|
|
21826
21851
|
clearCurrentCourt: () => clearCurrentCourt,
|
|
@@ -21843,7 +21868,7 @@ __export(run_lifecycle_exports, {
|
|
|
21843
21868
|
});
|
|
21844
21869
|
import { existsSync as existsSync11 } from "node:fs";
|
|
21845
21870
|
import { chmod, lstat as lstat3, open, readdir as readdir3, readFile as readFile10, unlink } from "node:fs/promises";
|
|
21846
|
-
import { basename as basename11, join as
|
|
21871
|
+
import { basename as basename11, join as join24 } from "node:path";
|
|
21847
21872
|
async function writeRoleRunState(runDirectory, record) {
|
|
21848
21873
|
const payload = { ...record, runDirectory };
|
|
21849
21874
|
writeSectionSync(runDirectory, "runState", { ...payload });
|
|
@@ -22138,7 +22163,7 @@ async function createWriterLease(lockPath, runDirectory, reportCleanupFailure) {
|
|
|
22138
22163
|
},
|
|
22139
22164
|
relocate(nextRunDirectory) {
|
|
22140
22165
|
currentRunDirectory = nextRunDirectory;
|
|
22141
|
-
currentLockPath =
|
|
22166
|
+
currentLockPath = join24(nextRunDirectory, WRITER_LOCK_FILE);
|
|
22142
22167
|
},
|
|
22143
22168
|
async release() {
|
|
22144
22169
|
if (released) return;
|
|
@@ -22177,10 +22202,10 @@ async function acquireRunWriterLease(runDirectory, onCleanupFailure) {
|
|
|
22177
22202
|
};
|
|
22178
22203
|
const reportReadFailure = (error) => {
|
|
22179
22204
|
reportDiagnostic(
|
|
22180
|
-
`writer lease lock read failed (holder liveness unverifiable; lock left in place) at ${
|
|
22205
|
+
`writer lease lock read failed (holder liveness unverifiable; lock left in place) at ${join24(runDirectory, WRITER_LOCK_FILE)}: ${describeErrorIdentity(error)}`
|
|
22181
22206
|
);
|
|
22182
22207
|
};
|
|
22183
|
-
const lockPath =
|
|
22208
|
+
const lockPath = join24(runDirectory, WRITER_LOCK_FILE);
|
|
22184
22209
|
let lastAutopsy = { verdict: "absent" };
|
|
22185
22210
|
let lastReclaimFailure;
|
|
22186
22211
|
for (let reclaimsLeft = WRITER_LEASE_RECLAIM_ROUNDS; ; reclaimsLeft -= 1) {
|
|
@@ -22246,7 +22271,7 @@ async function findRunDirectoryById(home, runId, onlyBookKey, onlyRole, knownRun
|
|
|
22246
22271
|
}
|
|
22247
22272
|
if (runId.trim() === "") return void 0;
|
|
22248
22273
|
const ledgerHome = resolveActivationLedgerHome(home);
|
|
22249
|
-
const booksRoot =
|
|
22274
|
+
const booksRoot = join24(ledgerHome, "books");
|
|
22250
22275
|
let bookKeys;
|
|
22251
22276
|
try {
|
|
22252
22277
|
bookKeys = await readdir3(booksRoot);
|
|
@@ -22296,7 +22321,7 @@ async function findLatestRunForSeatTicket(input) {
|
|
|
22296
22321
|
let runDirectories;
|
|
22297
22322
|
try {
|
|
22298
22323
|
runDirectories = await listBookRunDirectories(
|
|
22299
|
-
input.ticketNumber === void 0 ? bookDir :
|
|
22324
|
+
input.ticketNumber === void 0 ? bookDir : join24(bookDir, String(input.ticketNumber))
|
|
22300
22325
|
);
|
|
22301
22326
|
} catch (error) {
|
|
22302
22327
|
if (errorCodeOf(error) === "ENOENT") return void 0;
|
|
@@ -30068,10 +30093,10 @@ var init_analyst_book_key = __esm({
|
|
|
30068
30093
|
// src/atomic-write.ts
|
|
30069
30094
|
import { randomUUID as randomUUID7 } from "node:crypto";
|
|
30070
30095
|
import { rename as rename2, rm, writeFile as writeFile4 } from "node:fs/promises";
|
|
30071
|
-
import { dirname as dirname15, join as
|
|
30096
|
+
import { dirname as dirname15, join as join25 } from "node:path";
|
|
30072
30097
|
async function writeFileAtomically(destination, contents, options) {
|
|
30073
30098
|
const parent = dirname15(destination);
|
|
30074
|
-
const temporary =
|
|
30099
|
+
const temporary = join25(parent, `.atomic-write-${randomUUID7()}.tmp`);
|
|
30075
30100
|
try {
|
|
30076
30101
|
await writeFile4(temporary, contents, options);
|
|
30077
30102
|
await rename2(temporary, destination);
|
|
@@ -30088,12 +30113,12 @@ var init_atomic_write = __esm({
|
|
|
30088
30113
|
|
|
30089
30114
|
// src/analyst-index.ts
|
|
30090
30115
|
import { open as open2, readFile as readFile11, unlink as unlink2 } from "node:fs/promises";
|
|
30091
|
-
import { dirname as dirname16, join as
|
|
30116
|
+
import { dirname as dirname16, join as join26 } from "node:path";
|
|
30092
30117
|
import { setTimeout as sleep } from "node:timers/promises";
|
|
30093
30118
|
async function withAnalystLibraryIndexLock(ledgerHome, fn) {
|
|
30094
30119
|
const indexPath = analystLibraryIndexPath(ledgerHome);
|
|
30095
30120
|
ensureRealDirectoryTree(ledgerHome, dirname16(indexPath));
|
|
30096
|
-
const lockPath =
|
|
30121
|
+
const lockPath = join26(dirname16(indexPath), LIBRARY_INDEX_LOCK_NAME);
|
|
30097
30122
|
assertLedgerFileInsideHome(lockPath, ledgerHome);
|
|
30098
30123
|
const startedAt = Date.now();
|
|
30099
30124
|
while (true) {
|
|
@@ -30120,7 +30145,7 @@ async function withAnalystLibraryIndexLock(ledgerHome, fn) {
|
|
|
30120
30145
|
}
|
|
30121
30146
|
}
|
|
30122
30147
|
function analystLibraryIndexPath(ledgerHome) {
|
|
30123
|
-
return
|
|
30148
|
+
return join26(ledgerHome, "analyst", "library-index.json");
|
|
30124
30149
|
}
|
|
30125
30150
|
function rowFromIssueMetricsPage(page) {
|
|
30126
30151
|
return {
|
|
@@ -30414,7 +30439,7 @@ var init_analyst_cohort = __esm({
|
|
|
30414
30439
|
});
|
|
30415
30440
|
|
|
30416
30441
|
// src/archivist-record-pointer.ts
|
|
30417
|
-
import { basename as basename12, join as
|
|
30442
|
+
import { basename as basename12, join as join27 } from "node:path";
|
|
30418
30443
|
async function resolveOfficerPointer(raw, parentRunDirectory) {
|
|
30419
30444
|
const where = `${parentRunDirectory} officers`;
|
|
30420
30445
|
if (!isRecord(raw) || raw.kind !== DIRECT_OFFICER_RUN_POINTER_KIND || raw.version !== 1) {
|
|
@@ -30447,7 +30472,7 @@ async function resolveOfficerPointer(raw, parentRunDirectory) {
|
|
|
30447
30472
|
};
|
|
30448
30473
|
}
|
|
30449
30474
|
async function readBookedOfficerPointers(parentRunDirectory) {
|
|
30450
|
-
const { records, diagnostics } = await readSitianRecords(
|
|
30475
|
+
const { records, diagnostics } = await readSitianRecords(join27(parentRunDirectory, RUN_HISTORY_FILE));
|
|
30451
30476
|
if (diagnostics.length > 0) {
|
|
30452
30477
|
throw new Error(
|
|
30453
30478
|
`${RUN_HISTORY_FILE} has ${diagnostics.length} malformed row(s); officer pointers unreadable: ${parentRunDirectory}`
|
|
@@ -30730,7 +30755,7 @@ var init_analyst_gate_cycles_read = __esm({
|
|
|
30730
30755
|
|
|
30731
30756
|
// src/analyst-ledger.ts
|
|
30732
30757
|
import { readdir as readdir4 } from "node:fs/promises";
|
|
30733
|
-
import { basename as basename13, join as
|
|
30758
|
+
import { basename as basename13, join as join28 } from "node:path";
|
|
30734
30759
|
async function readExistingRunLifecycleState(runDirectory) {
|
|
30735
30760
|
return (await readRoleRunIdentity(runDirectory))?.state;
|
|
30736
30761
|
}
|
|
@@ -30750,7 +30775,7 @@ function ghostLeaseCheckFromAutopsy(autopsy) {
|
|
|
30750
30775
|
}
|
|
30751
30776
|
}
|
|
30752
30777
|
async function classifyGhostCandidate(input) {
|
|
30753
|
-
const autopsy = await autopsyWriterLock(
|
|
30778
|
+
const autopsy = await autopsyWriterLock(join28(input.runDirectory, "writer.lock"));
|
|
30754
30779
|
const leaseCheck = ghostLeaseCheckFromAutopsy(autopsy);
|
|
30755
30780
|
if (leaseCheck === void 0) return { kind: "live" };
|
|
30756
30781
|
return {
|
|
@@ -31040,7 +31065,7 @@ async function classifyScopedRun(input) {
|
|
|
31040
31065
|
async function scanAnalystIssueRuns(input) {
|
|
31041
31066
|
const ledgerHome = resolveActivationLedgerHome(input.home);
|
|
31042
31067
|
const scopeTicketNumber = input.ticketNumber;
|
|
31043
|
-
const booksRoot =
|
|
31068
|
+
const booksRoot = join28(ledgerHome, "books");
|
|
31044
31069
|
let wholeBook = false;
|
|
31045
31070
|
let scopeRootIdentity;
|
|
31046
31071
|
let bookNames;
|
|
@@ -31073,7 +31098,7 @@ async function scanAnalystIssueRuns(input) {
|
|
|
31073
31098
|
const ghostLegs = [];
|
|
31074
31099
|
const scopeConflicts = [];
|
|
31075
31100
|
for (const book of bookNames) {
|
|
31076
|
-
const bookDir =
|
|
31101
|
+
const bookDir = join28(booksRoot, book);
|
|
31077
31102
|
let runDirectories;
|
|
31078
31103
|
try {
|
|
31079
31104
|
runDirectories = await listBookRunDirectories(bookDir);
|
|
@@ -31819,7 +31844,7 @@ var init_analyst_metric_family = __esm({
|
|
|
31819
31844
|
});
|
|
31820
31845
|
|
|
31821
31846
|
// src/analyst-page.ts
|
|
31822
|
-
import { dirname as dirname17, join as
|
|
31847
|
+
import { dirname as dirname17, join as join29 } from "node:path";
|
|
31823
31848
|
function analystIssuePageKey(address) {
|
|
31824
31849
|
const parts = ["book", address.bookKey];
|
|
31825
31850
|
if (address.issueNumber !== void 0) {
|
|
@@ -31830,7 +31855,7 @@ function analystIssuePageKey(address) {
|
|
|
31830
31855
|
return sha256Hex(parts.join("\0")).slice(0, 32);
|
|
31831
31856
|
}
|
|
31832
31857
|
function analystIssuePagePath(ledgerHome, address) {
|
|
31833
|
-
return
|
|
31858
|
+
return join29(ledgerHome, "analyst", "issues", `${analystIssuePageKey(address)}.json`);
|
|
31834
31859
|
}
|
|
31835
31860
|
function analystIssuePageAddressFromPage(page) {
|
|
31836
31861
|
return {
|
|
@@ -33384,12 +33409,12 @@ var init_cli = __esm({
|
|
|
33384
33409
|
|
|
33385
33410
|
// src/public-cli/main.ts
|
|
33386
33411
|
import { existsSync as existsSync12 } from "node:fs";
|
|
33387
|
-
import { dirname as dirname18, join as
|
|
33412
|
+
import { dirname as dirname18, join as join30 } from "node:path";
|
|
33388
33413
|
import { fileURLToPath as fileURLToPath2 } from "node:url";
|
|
33389
33414
|
var here = dirname18(fileURLToPath2(import.meta.url));
|
|
33390
33415
|
function resolvePackageRoot(binDir) {
|
|
33391
|
-
const canonical =
|
|
33392
|
-
if (existsSync12(
|
|
33416
|
+
const canonical = join30(binDir, "..", "..");
|
|
33417
|
+
if (existsSync12(join30(canonical, "package.json"))) {
|
|
33393
33418
|
return canonical;
|
|
33394
33419
|
}
|
|
33395
33420
|
return binDir;
|
|
@@ -23,7 +23,7 @@ import { isRecord, errorText, isEnoent } from "../unknown-value.js";
|
|
|
23
23
|
* source: runWithAutoResumeLoop receives the effective value once per call.
|
|
24
24
|
*/
|
|
25
25
|
export const AUTO_RESUME_LIMIT = 2;
|
|
26
|
-
const WRITER_LOCK_FILE = "writer.lock";
|
|
26
|
+
export const WRITER_LOCK_FILE = "writer.lock";
|
|
27
27
|
export async function writeRoleRunState(runDirectory, record) {
|
|
28
28
|
const payload = { ...record, runDirectory };
|
|
29
29
|
writeSectionSync(runDirectory, "runState", { ...payload });
|
|
@@ -1,38 +1,66 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Shared same-parent resume seam for gate / officer seats (#635 / #637 / #747 / #987).
|
|
3
|
-
*
|
|
4
|
-
* Lookup uses the parent run path; a typed ticket narrows same-ticket gate
|
|
5
|
-
* re-summons, never creates an issue identity. Callers can also use explicit
|
|
6
|
-
* `ak-role resume <runId>`. Lookup/resume failures propagate (失败诚实) — never wash into
|
|
7
|
-
* a fresh mint. Returns undefined when the caller declared an explicit fresh
|
|
8
|
-
* summons (`ak-role new`) or when no prior run exists; both mint new.
|
|
9
|
-
* freshSummons is required so no seat can drift back into its own skip branch.
|
|
2
|
+
* Shared same-parent resume seam for gate / officer seats (#635 / #637 / #747 / #987 / #1253).
|
|
3
|
+
* Contract is on tryResumeSameTicketSeatRun.
|
|
10
4
|
*/
|
|
5
|
+
import { join } from "node:path";
|
|
11
6
|
import { resolveBookKeyFromGit } from "../activation-ledger-git.js";
|
|
12
|
-
import { findLatestRunForSeatTicket, } from "./run-lifecycle.js";
|
|
7
|
+
import { autopsyWriterLock, findLatestRunForSeatTicket, resolveLiveRunDirectoryPath, WRITER_LOCK_FILE, } from "./run-lifecycle.js";
|
|
8
|
+
const SESSION_ID_MISSING = "session-id-missing";
|
|
9
|
+
function resumedSessionIdMissing(result, runId) {
|
|
10
|
+
if (typeof result !== "object" || result === null)
|
|
11
|
+
return false;
|
|
12
|
+
const terminal = result.terminal;
|
|
13
|
+
if (typeof terminal !== "object" || terminal === null)
|
|
14
|
+
return false;
|
|
15
|
+
if (terminal.runId !== runId)
|
|
16
|
+
return false;
|
|
17
|
+
const outcome = terminal.roleOutcome;
|
|
18
|
+
if (typeof outcome !== "object" || outcome === null)
|
|
19
|
+
return false;
|
|
20
|
+
if (outcome.kind !== "failure")
|
|
21
|
+
return false;
|
|
22
|
+
const facts = outcome.decisiveFacts;
|
|
23
|
+
if (typeof facts !== "object" || facts === null)
|
|
24
|
+
return false;
|
|
25
|
+
return facts.errorCode === SESSION_ID_MISSING;
|
|
26
|
+
}
|
|
27
|
+
/** Live or unverifiable holder: same fail-closed verdict as lease acquire. */
|
|
28
|
+
async function writerLockBlocksFreshSummons(runDirectory) {
|
|
29
|
+
const autopsy = await autopsyWriterLock(join(runDirectory, WRITER_LOCK_FILE));
|
|
30
|
+
return autopsy.verdict === "alive" || autopsy.verdict === "unknown";
|
|
31
|
+
}
|
|
13
32
|
/**
|
|
14
|
-
* Sole same-seat → resume decision by parent run path (#637 / #724 / #747 / #987).
|
|
33
|
+
* Sole same-seat → resume decision by parent run path (#637 / #724 / #747 / #987 / #1253).
|
|
15
34
|
* A supplied typed ticket only narrows the prior-run search. When a prior run is
|
|
16
35
|
* found, resume carries this summons' materials and the located runDirectory so
|
|
17
|
-
* load does not re-walk every book for the bare runId (#1195).
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
*
|
|
36
|
+
* load does not re-walk every book for the bare runId (#1195). Typed
|
|
37
|
+
* session-id-missing is already recorded on that run (失败照记,记完再起新);
|
|
38
|
+
* return undefined so the caller mints once. Resume runs first; this seam does
|
|
39
|
+
* not look up a session id. A held or unverifiable writer lock, and every other
|
|
40
|
+
* result, returns as-is. Also returns undefined for explicit `ak-role new`, a
|
|
41
|
+
* blank parent path, or no prior run. freshSummons is required so no seat can
|
|
42
|
+
* drift back into its own skip branch.
|
|
22
43
|
*/
|
|
23
44
|
export async function tryResumeSameTicketSeatRun(input) {
|
|
24
45
|
if (input.freshSummons === true)
|
|
25
46
|
return undefined;
|
|
26
47
|
if (input.parentRunPath.trim() === "")
|
|
27
48
|
return undefined;
|
|
49
|
+
const bookKey = resolveBookKeyFromGit(input.projectRoot);
|
|
28
50
|
const previous = await findLatestRunForSeatTicket({
|
|
29
51
|
home: input.home,
|
|
30
|
-
bookKey
|
|
52
|
+
bookKey,
|
|
31
53
|
role: input.role,
|
|
32
54
|
parentRunPath: input.parentRunPath,
|
|
33
55
|
...(input.ticketNumber === undefined ? {} : { ticketNumber: input.ticketNumber }),
|
|
34
56
|
});
|
|
35
57
|
if (previous === undefined)
|
|
36
58
|
return undefined;
|
|
37
|
-
|
|
59
|
+
const resumed = await input.resume(previous.runId, input.summons, previous.runDirectory);
|
|
60
|
+
if (!resumedSessionIdMissing(resumed, previous.runId))
|
|
61
|
+
return resumed;
|
|
62
|
+
const live = await resolveLiveRunDirectoryPath(previous.runDirectory, input.home, bookKey);
|
|
63
|
+
if (live !== undefined && await writerLockBlocksFreshSummons(live))
|
|
64
|
+
return resumed;
|
|
65
|
+
return undefined;
|
|
38
66
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@akagilnc/pi-workflow-roles",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.5946",
|
|
4
4
|
"description": "Soul-bound workflow roles for Pi",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "Apache-2.0",
|
|
@@ -46,9 +46,8 @@
|
|
|
46
46
|
"prepack": "npm run build",
|
|
47
47
|
"test": "vitest run --project unit-contract",
|
|
48
48
|
"test:fast": "pnpm test",
|
|
49
|
-
"test:integration": "
|
|
50
|
-
"test:all": "
|
|
51
|
-
"test:vitest": "vitest run",
|
|
49
|
+
"test:integration": "vitest run --project integration",
|
|
50
|
+
"test:all": "vitest run",
|
|
52
51
|
"typecheck": "tsc --noEmit",
|
|
53
52
|
"migrate:book-topology": "node dist/migrate-book-topology.js"
|
|
54
53
|
},
|
|
@@ -973,7 +973,8 @@ async function runOmittedLensBatch(
|
|
|
973
973
|
|
|
974
974
|
/**
|
|
975
975
|
* One same-parent lookup. Seat branches still build their own summons.
|
|
976
|
-
* A found child resumes that child
|
|
976
|
+
* A found child resumes that child. No prior run, explicit new, or a typed
|
|
977
|
+
* session-id-missing resume (失败照记,记完再起新) returns undefined so the caller mints.
|
|
977
978
|
*/
|
|
978
979
|
function resumeSameParentInstructionSeat(input: {
|
|
979
980
|
readonly env: InstructionSeatRunEnv;
|
|
@@ -130,7 +130,7 @@ export type SameTicketSummonsMaterials = {
|
|
|
130
130
|
readonly sourceRun?: NotarySourceRunLocator;
|
|
131
131
|
};
|
|
132
132
|
|
|
133
|
-
const WRITER_LOCK_FILE = "writer.lock";
|
|
133
|
+
export const WRITER_LOCK_FILE = "writer.lock";
|
|
134
134
|
|
|
135
135
|
export async function writeRoleRunState(
|
|
136
136
|
runDirectory: string,
|
|
@@ -1,29 +1,51 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Shared same-parent resume seam for gate / officer seats (#635 / #637 / #747 / #987).
|
|
3
|
-
*
|
|
4
|
-
* Lookup uses the parent run path; a typed ticket narrows same-ticket gate
|
|
5
|
-
* re-summons, never creates an issue identity. Callers can also use explicit
|
|
6
|
-
* `ak-role resume <runId>`. Lookup/resume failures propagate (失败诚实) — never wash into
|
|
7
|
-
* a fresh mint. Returns undefined when the caller declared an explicit fresh
|
|
8
|
-
* summons (`ak-role new`) or when no prior run exists; both mint new.
|
|
9
|
-
* freshSummons is required so no seat can drift back into its own skip branch.
|
|
2
|
+
* Shared same-parent resume seam for gate / officer seats (#635 / #637 / #747 / #987 / #1253).
|
|
3
|
+
* Contract is on tryResumeSameTicketSeatRun.
|
|
10
4
|
*/
|
|
5
|
+
import { join } from "node:path";
|
|
6
|
+
|
|
11
7
|
import { resolveBookKeyFromGit } from "../activation-ledger-git.ts";
|
|
12
8
|
import {
|
|
9
|
+
autopsyWriterLock,
|
|
13
10
|
findLatestRunForSeatTicket,
|
|
11
|
+
resolveLiveRunDirectoryPath,
|
|
12
|
+
WRITER_LOCK_FILE,
|
|
14
13
|
type RoleRunRecord,
|
|
15
14
|
type SameTicketSummonsMaterials,
|
|
16
15
|
} from "./run-lifecycle.ts";
|
|
17
16
|
|
|
17
|
+
const SESSION_ID_MISSING = "session-id-missing";
|
|
18
|
+
|
|
19
|
+
function resumedSessionIdMissing(result: unknown, runId: string): boolean {
|
|
20
|
+
if (typeof result !== "object" || result === null) return false;
|
|
21
|
+
const terminal = (result as { terminal?: unknown }).terminal;
|
|
22
|
+
if (typeof terminal !== "object" || terminal === null) return false;
|
|
23
|
+
if ((terminal as { runId?: unknown }).runId !== runId) return false;
|
|
24
|
+
const outcome = (terminal as { roleOutcome?: unknown }).roleOutcome;
|
|
25
|
+
if (typeof outcome !== "object" || outcome === null) return false;
|
|
26
|
+
if ((outcome as { kind?: unknown }).kind !== "failure") return false;
|
|
27
|
+
const facts = (outcome as { decisiveFacts?: unknown }).decisiveFacts;
|
|
28
|
+
if (typeof facts !== "object" || facts === null) return false;
|
|
29
|
+
return (facts as { errorCode?: unknown }).errorCode === SESSION_ID_MISSING;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/** Live or unverifiable holder: same fail-closed verdict as lease acquire. */
|
|
33
|
+
async function writerLockBlocksFreshSummons(runDirectory: string): Promise<boolean> {
|
|
34
|
+
const autopsy = await autopsyWriterLock(join(runDirectory, WRITER_LOCK_FILE));
|
|
35
|
+
return autopsy.verdict === "alive" || autopsy.verdict === "unknown";
|
|
36
|
+
}
|
|
37
|
+
|
|
18
38
|
/**
|
|
19
|
-
* Sole same-seat → resume decision by parent run path (#637 / #724 / #747 / #987).
|
|
39
|
+
* Sole same-seat → resume decision by parent run path (#637 / #724 / #747 / #987 / #1253).
|
|
20
40
|
* A supplied typed ticket only narrows the prior-run search. When a prior run is
|
|
21
41
|
* found, resume carries this summons' materials and the located runDirectory so
|
|
22
|
-
* load does not re-walk every book for the bare runId (#1195).
|
|
23
|
-
*
|
|
24
|
-
*
|
|
25
|
-
*
|
|
26
|
-
*
|
|
42
|
+
* load does not re-walk every book for the bare runId (#1195). Typed
|
|
43
|
+
* session-id-missing is already recorded on that run (失败照记,记完再起新);
|
|
44
|
+
* return undefined so the caller mints once. Resume runs first; this seam does
|
|
45
|
+
* not look up a session id. A held or unverifiable writer lock, and every other
|
|
46
|
+
* result, returns as-is. Also returns undefined for explicit `ak-role new`, a
|
|
47
|
+
* blank parent path, or no prior run. freshSummons is required so no seat can
|
|
48
|
+
* drift back into its own skip branch.
|
|
27
49
|
*/
|
|
28
50
|
export async function tryResumeSameTicketSeatRun<T>(input: {
|
|
29
51
|
readonly home: string;
|
|
@@ -41,13 +63,18 @@ export async function tryResumeSameTicketSeatRun<T>(input: {
|
|
|
41
63
|
}): Promise<T | undefined> {
|
|
42
64
|
if (input.freshSummons === true) return undefined;
|
|
43
65
|
if (input.parentRunPath.trim() === "") return undefined;
|
|
66
|
+
const bookKey = resolveBookKeyFromGit(input.projectRoot);
|
|
44
67
|
const previous = await findLatestRunForSeatTicket({
|
|
45
68
|
home: input.home,
|
|
46
|
-
bookKey
|
|
69
|
+
bookKey,
|
|
47
70
|
role: input.role,
|
|
48
71
|
parentRunPath: input.parentRunPath,
|
|
49
72
|
...(input.ticketNumber === undefined ? {} : { ticketNumber: input.ticketNumber }),
|
|
50
73
|
});
|
|
51
74
|
if (previous === undefined) return undefined;
|
|
52
|
-
|
|
75
|
+
const resumed = await input.resume(previous.runId, input.summons, previous.runDirectory);
|
|
76
|
+
if (!resumedSessionIdMissing(resumed, previous.runId)) return resumed;
|
|
77
|
+
const live = await resolveLiveRunDirectoryPath(previous.runDirectory, input.home, bookKey);
|
|
78
|
+
if (live !== undefined && await writerLockBlocksFreshSummons(live)) return resumed;
|
|
79
|
+
return undefined;
|
|
53
80
|
}
|