@akagilnc/pi-workflow-roles 0.1.5212 → 0.1.5235
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/dist/acp-host/production-host.js +580 -1031
- package/dist/engine-detour-usage.js +4 -16
- package/dist/headless-host/production-host.js +701 -1066
- package/dist/host-session-record.js +303 -0
- package/dist/migrate-book-topology.js +0 -1
- package/dist/pi/role-turn-host.js +1 -21
- package/dist/public-cli/main.js +153 -362
- package/dist/public-cli/post-admission.js +7 -43
- package/dist/sitian-appender.js +10 -146
- package/dist/ticket-provenance-contracts.js +4 -42
- package/dist/ticket-provenance.js +27 -456
- package/package.json +1 -1
- package/src/acp-host/role-turn-host.ts +36 -108
- package/src/diarist.ts +5 -5
- package/src/engine-detour-usage.ts +4 -16
- package/src/external-host-turn-loop.ts +2 -18
- package/src/headless-host/role-turn-host.ts +67 -31
- package/src/host-contracts.ts +0 -15
- package/src/host-session-record.ts +325 -25
- package/src/pi/role-turn-host.ts +1 -25
- package/src/public-cli/post-admission.ts +6 -51
- package/src/public-role-summons.ts +1 -2
- package/src/sitian-appender.ts +16 -191
- package/src/ticket-provenance-contracts.ts +10 -48
- package/src/ticket-provenance.ts +33 -499
- package/dist/host-transition-prior-native.js +0 -78
- package/src/host-transition-prior-native.ts +0 -80
- package/src/pi/pi-normalization.ts +0 -291
|
@@ -35,11 +35,11 @@ function describeCaughtError(error) {
|
|
|
35
35
|
function isStationChildOfficerDialogue(role, env) {
|
|
36
36
|
return env.stationChild === true && isOfficerReviewSeat(role);
|
|
37
37
|
}
|
|
38
|
-
import { mintEngineDetourInvocationScope,
|
|
39
|
-
import { projectHostTransitionPriorNative } from "../host-transition-prior-native.js";
|
|
38
|
+
import { mintEngineDetourInvocationScope, withEngineDetourInvocationScope, } from "../engine-detour-usage.js";
|
|
40
39
|
import { clearCurrentCourt, clearTypedProviderHttpObservation, describeErrorIdentity, markRunRunning, readCurrentCourt, recordCurrentCourt, renderResumeCommand, } from "./run-lifecycle.js";
|
|
41
40
|
import { processCancelDiagnostic, processCancelSignalName, } from "./process-cancel.js";
|
|
42
41
|
import { homeFromRunDirectory } from "../activation-ledger-topology.js";
|
|
42
|
+
import { recordRunStart } from "../host-session-record.js";
|
|
43
43
|
import { attemptProducedFreshSubmission, classifyPostAdmissionFailure, controlledFailureInputFromResolution, exitCodeForTerminalOutcome, explicitInternalKnownFailureClassificationInput, formatCliDiagnostic, formatErrorCauseDetail, formatTerminalResult, inspectJudgeSession, isLawfulTypedTerminalOutcome, presentFailureTerminal, publishedFailureErrorPath, presentStructuralRejection, resolveAuditedRunnerFailureResolution, resolveControlledFailureResumeObservation, settleFailureTerminalResult, settleHostEndedNoReceipt, attachRecordedSubmissions, rewritePublishedFailureErrorPath, } from "./settlement.js";
|
|
44
44
|
import {} from "./terminal.js";
|
|
45
45
|
import { ensureRealArtifactsDirectory, persistReturnedRunState, runWithAutoResumeLoop, TurnDispatchedFailure, } from "./auto-resume.js";
|
|
@@ -407,45 +407,11 @@ export async function dispatchPostAdmissionTurn(input) {
|
|
|
407
407
|
try {
|
|
408
408
|
// #987: do not pre-block or classify host dispatch from AK credential
|
|
409
409
|
// catalog facts. Per-invocation runner/host evidence owns provider identity.
|
|
410
|
-
// #617 DK-4: capture previous invocation host before markRunRunning overwrites it.
|
|
411
|
-
// Single authority projectHostTransitionPriorNative classifies the prior native volume.
|
|
412
|
-
// Same-run resume (#637) keeps host identity on the run's invocation page.
|
|
413
|
-
let previousHost;
|
|
414
|
-
const liveHost = env.host;
|
|
415
|
-
const principalCoordinates = admitted.principal === undefined
|
|
416
|
-
? undefined
|
|
417
|
-
: env.principalAuthority.decode(admitted.principal);
|
|
418
|
-
let hostTransition;
|
|
419
|
-
try {
|
|
420
|
-
previousHost = readInvocationSelectedHost(admitted.runDirectory);
|
|
421
|
-
hostTransition =
|
|
422
|
-
previousHost !== undefined && liveHost !== undefined && principalCoordinates !== undefined
|
|
423
|
-
? await projectHostTransitionPriorNative({
|
|
424
|
-
previousHost,
|
|
425
|
-
liveHost,
|
|
426
|
-
piSessionFile: principalCoordinates.sessionFile,
|
|
427
|
-
})
|
|
428
|
-
: undefined;
|
|
429
|
-
}
|
|
430
|
-
catch (error) {
|
|
431
|
-
// prior-native IO is on the public one-shot path — controlled failure, not bare throw.
|
|
432
|
-
return {
|
|
433
|
-
...(await presentControlledFailure(admitted, withEngineDetourInvocationScope({
|
|
434
|
-
timedOut: false,
|
|
435
|
-
code: null,
|
|
436
|
-
stderr: "",
|
|
437
|
-
thrown: error,
|
|
438
|
-
}, request.invocationScopeId), adapters, env.principalAuthority, io, persistRunState)),
|
|
439
|
-
...deferredPersist,
|
|
440
|
-
};
|
|
441
|
-
}
|
|
442
410
|
await clearTypedProviderHttpObservation(admitted.runDirectory);
|
|
443
411
|
// The authoritative host write (markRunRunning) is delayed to just before
|
|
444
412
|
// executeTurn — not merely past beforeDispatch (#840 r9 判词 class 2). Any
|
|
445
|
-
// pre-turn retry (beforeDispatch,
|
|
446
|
-
//
|
|
447
|
-
// committing env.host earlier would make readInvocationSelectedHost read back the
|
|
448
|
-
// new host on the retry and silently drop hostTransition.
|
|
413
|
+
// pre-turn retry (beforeDispatch, continuation assembly) must not commit a host
|
|
414
|
+
// identity until the turn is ready.
|
|
449
415
|
// Failures settle the run (presentControlledFailure); they must not leave it
|
|
450
416
|
// permanently running. Call-local auto-resume retries this hook until it
|
|
451
417
|
// succeeds; only an exhausted nested station child skips the parent loop
|
|
@@ -487,13 +453,10 @@ export async function dispatchPostAdmissionTurn(input) {
|
|
|
487
453
|
if (env.stationChild !== undefined) {
|
|
488
454
|
turnRequest = { ...turnRequest, stationChild: env.stationChild };
|
|
489
455
|
}
|
|
490
|
-
if (hostTransition !== undefined) {
|
|
491
|
-
turnRequest = { ...turnRequest, hostTransition };
|
|
492
|
-
}
|
|
493
456
|
// Selected host axis rides the shared Host envelope for in-turn tools
|
|
494
457
|
// (detour usage ledger) — never a pre-spawn invocation.json reread.
|
|
495
|
-
if (typeof
|
|
496
|
-
turnRequest = { ...turnRequest, host:
|
|
458
|
+
if (typeof env.host === "string" && env.host.trim() !== "") {
|
|
459
|
+
turnRequest = { ...turnRequest, host: env.host.trim() };
|
|
497
460
|
}
|
|
498
461
|
// 0081 non-dialogue face: freeze pointer section under run/attachments/.
|
|
499
462
|
// Seat consumes via loadCaseDossierReadingMaterial → existing agent-start
|
|
@@ -514,6 +477,7 @@ export async function dispatchPostAdmissionTurn(input) {
|
|
|
514
477
|
// auto-resume re-enters this dispatch and must reuse the same scope.
|
|
515
478
|
let result;
|
|
516
479
|
try {
|
|
480
|
+
recordRunStart(admitted.runDirectory);
|
|
517
481
|
result = await env.roleTurnHost.executeTurn(turnRequest);
|
|
518
482
|
}
|
|
519
483
|
catch (error) {
|
package/dist/sitian-appender.js
CHANGED
|
@@ -1,11 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
appendFileSync,
|
|
4
|
-
existsSync,
|
|
5
|
-
readFileSync,
|
|
6
|
-
unlinkSync,
|
|
7
|
-
writeFileSync
|
|
8
|
-
} from "node:fs";
|
|
1
|
+
import { randomUUID } from "node:crypto";
|
|
2
|
+
import { appendFileSync } from "node:fs";
|
|
9
3
|
import { dirname, join } from "node:path";
|
|
10
4
|
import { resolveBookKeyFromGit } from "./activation-ledger-git.js";
|
|
11
5
|
import {
|
|
@@ -19,48 +13,12 @@ import {
|
|
|
19
13
|
import {
|
|
20
14
|
SitianInfrastructureError
|
|
21
15
|
} from "./sitian-contracts.js";
|
|
22
|
-
function isRecord(value) {
|
|
23
|
-
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
24
|
-
}
|
|
25
|
-
function errorCodeOf(error) {
|
|
26
|
-
return error.code;
|
|
27
|
-
}
|
|
28
|
-
function identityClaimPath(recordFile, identity) {
|
|
29
|
-
const digest = createHash("sha256").update(identity, "utf8").digest("hex");
|
|
30
|
-
return `${recordFile}.id-${digest}`;
|
|
31
|
-
}
|
|
32
|
-
function createExclusiveFile(path, contents) {
|
|
33
|
-
writeFileSync(path, contents, { encoding: "utf8", flag: "wx" });
|
|
34
|
-
}
|
|
35
|
-
function sealTornTail(recordFile) {
|
|
36
|
-
if (!existsSync(recordFile)) return;
|
|
37
|
-
const buffer = readFileSync(recordFile);
|
|
38
|
-
if (buffer.length > 0 && buffer[buffer.length - 1] !== 10) {
|
|
39
|
-
appendFileSync(recordFile, "\n", "utf8");
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
16
|
function appendSitianRecordBlock(input, block) {
|
|
43
17
|
if (block === "") return;
|
|
44
18
|
try {
|
|
45
19
|
const { sessionDir, recordFile, ledgerHome } = resolveSitianRecordPath(input);
|
|
46
20
|
ensureRealDirectoryTree(ledgerHome, sessionDir);
|
|
47
|
-
appendFileSync(recordFile,
|
|
48
|
-
sealTornTail(recordFile);
|
|
49
|
-
const identityOf = (line) => {
|
|
50
|
-
try {
|
|
51
|
-
const row = JSON.parse(line);
|
|
52
|
-
return isRecord(row) && typeof row.identity === "string" ? row.identity : void 0;
|
|
53
|
-
} catch {
|
|
54
|
-
return void 0;
|
|
55
|
-
}
|
|
56
|
-
};
|
|
57
|
-
const identities = new Set(readFileSync(recordFile, "utf8").split("\n").map(identityOf).filter((id) => id !== void 0));
|
|
58
|
-
for (const line of block.match(/[^\n]*\n|[^\n]+$/g) ?? []) {
|
|
59
|
-
const identity = identityOf(line);
|
|
60
|
-
if (identity !== void 0 && identities.has(identity)) continue;
|
|
61
|
-
appendFileSync(recordFile, line, "utf8");
|
|
62
|
-
if (identity !== void 0) identities.add(identity);
|
|
63
|
-
}
|
|
21
|
+
appendFileSync(recordFile, block, "utf8");
|
|
64
22
|
} catch (error) {
|
|
65
23
|
if (error instanceof SitianInfrastructureError) throw error;
|
|
66
24
|
throw new SitianInfrastructureError(
|
|
@@ -69,106 +27,6 @@ function appendSitianRecordBlock(input, block) {
|
|
|
69
27
|
);
|
|
70
28
|
}
|
|
71
29
|
}
|
|
72
|
-
function findIdentityPointer(recordFile, identity, kind, level) {
|
|
73
|
-
if (!existsSync(recordFile)) return void 0;
|
|
74
|
-
const text = readFileSync(recordFile, "utf8");
|
|
75
|
-
for (const line of text.split("\n")) {
|
|
76
|
-
const trimmed = line.trim();
|
|
77
|
-
if (!trimmed) continue;
|
|
78
|
-
try {
|
|
79
|
-
const parsed = JSON.parse(trimmed);
|
|
80
|
-
if (isRecord(parsed) && parsed.identity === identity) {
|
|
81
|
-
return { identity, recordFile, kind, level };
|
|
82
|
-
}
|
|
83
|
-
} catch {
|
|
84
|
-
}
|
|
85
|
-
}
|
|
86
|
-
return void 0;
|
|
87
|
-
}
|
|
88
|
-
function unlinkAbsentOk(path) {
|
|
89
|
-
try {
|
|
90
|
-
unlinkSync(path);
|
|
91
|
-
return void 0;
|
|
92
|
-
} catch (error) {
|
|
93
|
-
if (errorCodeOf(error) === "ENOENT") return void 0;
|
|
94
|
-
return error instanceof Error ? error : new Error(errorText(error));
|
|
95
|
-
}
|
|
96
|
-
}
|
|
97
|
-
function appendWithIdentityClaim(recordFile, record, row) {
|
|
98
|
-
sealTornTail(recordFile);
|
|
99
|
-
const claimPath = identityClaimPath(recordFile, record.identity);
|
|
100
|
-
const existing = findIdentityPointer(
|
|
101
|
-
recordFile,
|
|
102
|
-
record.identity,
|
|
103
|
-
record.kind,
|
|
104
|
-
record.level
|
|
105
|
-
);
|
|
106
|
-
if (existing !== void 0) {
|
|
107
|
-
unlinkAbsentOk(claimPath);
|
|
108
|
-
return existing;
|
|
109
|
-
}
|
|
110
|
-
try {
|
|
111
|
-
createExclusiveFile(claimPath, "");
|
|
112
|
-
} catch (error) {
|
|
113
|
-
if (errorCodeOf(error) !== "EEXIST") throw error;
|
|
114
|
-
sealTornTail(recordFile);
|
|
115
|
-
const published = findIdentityPointer(
|
|
116
|
-
recordFile,
|
|
117
|
-
record.identity,
|
|
118
|
-
record.kind,
|
|
119
|
-
record.level
|
|
120
|
-
);
|
|
121
|
-
if (published !== void 0) {
|
|
122
|
-
unlinkAbsentOk(claimPath);
|
|
123
|
-
return published;
|
|
124
|
-
}
|
|
125
|
-
throw new SitianInfrastructureError(
|
|
126
|
-
`Sitian identity claim at ${claimPath} already exists for identity ${record.identity}`,
|
|
127
|
-
{ cause: error }
|
|
128
|
-
);
|
|
129
|
-
}
|
|
130
|
-
let primaryFailure;
|
|
131
|
-
let result;
|
|
132
|
-
let cleanupFailure;
|
|
133
|
-
try {
|
|
134
|
-
sealTornTail(recordFile);
|
|
135
|
-
const raced = findIdentityPointer(
|
|
136
|
-
recordFile,
|
|
137
|
-
record.identity,
|
|
138
|
-
record.kind,
|
|
139
|
-
record.level
|
|
140
|
-
);
|
|
141
|
-
if (raced !== void 0) {
|
|
142
|
-
result = raced;
|
|
143
|
-
} else {
|
|
144
|
-
appendFileSync(recordFile, row, "utf8");
|
|
145
|
-
result = {
|
|
146
|
-
identity: record.identity,
|
|
147
|
-
recordFile,
|
|
148
|
-
kind: record.kind,
|
|
149
|
-
level: record.level
|
|
150
|
-
};
|
|
151
|
-
}
|
|
152
|
-
} catch (error) {
|
|
153
|
-
primaryFailure = error;
|
|
154
|
-
} finally {
|
|
155
|
-
cleanupFailure = unlinkAbsentOk(claimPath);
|
|
156
|
-
}
|
|
157
|
-
if (primaryFailure !== void 0) {
|
|
158
|
-
if (primaryFailure instanceof SitianInfrastructureError) throw primaryFailure;
|
|
159
|
-
throw new SitianInfrastructureError(
|
|
160
|
-
`Sitian appender persistence failure: ${errorText(primaryFailure)}`,
|
|
161
|
-
{ cause: primaryFailure }
|
|
162
|
-
);
|
|
163
|
-
}
|
|
164
|
-
if (cleanupFailure !== void 0) {
|
|
165
|
-
throw new SitianInfrastructureError(
|
|
166
|
-
`Sitian identity claim at ${claimPath} could not be released after append for identity ${record.identity}: ${errorText(cleanupFailure)}`,
|
|
167
|
-
{ cause: cleanupFailure }
|
|
168
|
-
);
|
|
169
|
-
}
|
|
170
|
-
return result;
|
|
171
|
-
}
|
|
172
30
|
const S4_SUBMISSION_LEDGER_KINDS = /* @__PURE__ */ new Set([
|
|
173
31
|
"candidate",
|
|
174
32
|
"roundContext",
|
|
@@ -249,7 +107,13 @@ function appendSitianRecord(input) {
|
|
|
249
107
|
};
|
|
250
108
|
const row = `${JSON.stringify(record)}
|
|
251
109
|
`;
|
|
252
|
-
|
|
110
|
+
appendFileSync(recordFile, row, "utf8");
|
|
111
|
+
return {
|
|
112
|
+
identity: record.identity,
|
|
113
|
+
recordFile,
|
|
114
|
+
kind: record.kind,
|
|
115
|
+
level: record.level
|
|
116
|
+
};
|
|
253
117
|
} catch (error) {
|
|
254
118
|
if (error instanceof SitianInfrastructureError) throw error;
|
|
255
119
|
throw new SitianInfrastructureError(
|
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* 起居录(ticket-provenance)typed 形状 —— ADR 0075
|
|
2
|
+
* 起居录(ticket-provenance)typed 形状 —— ADR 0075 / ADR 0081 / #1090。
|
|
3
3
|
*
|
|
4
|
-
* 一册=一个追加式 records.jsonl
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
* 交卷 `sessions` 输入语义仍是「本轮对话边界」;累计并集是机械合并,不是角色交什么。
|
|
4
|
+
* 一册=一个追加式 records.jsonl。每轮交卷的 `sessions`=本轮对话边界;
|
|
5
|
+
* 成录接缝按该边界从宿主卷投影并追加,不回读已成录历史去重或折叠。
|
|
6
|
+
* 既有「首行册子头+裸对话行」snapshot 仍可读;后续提交不回写旧行。
|
|
8
7
|
*/
|
|
9
8
|
/** Sitian kind for per-ticket court diary volumes. */
|
|
10
9
|
export const TICKET_PROVENANCE_KIND = "ticket-provenance";
|
|
@@ -21,19 +20,6 @@ function positiveInteger(value) {
|
|
|
21
20
|
}
|
|
22
21
|
return undefined;
|
|
23
22
|
}
|
|
24
|
-
function nonNegativeInteger(value) {
|
|
25
|
-
if (typeof value === "number" && Number.isSafeInteger(value) && value >= 0)
|
|
26
|
-
return value;
|
|
27
|
-
if (typeof value === "string" && /^(0|[1-9][0-9]*)$/.test(value)) {
|
|
28
|
-
const parsed = Number(value);
|
|
29
|
-
if (Number.isSafeInteger(parsed))
|
|
30
|
-
return parsed;
|
|
31
|
-
}
|
|
32
|
-
return undefined;
|
|
33
|
-
}
|
|
34
|
-
function projectSpeaker(value) {
|
|
35
|
-
return value === "owner" || value === "runner" ? value : undefined;
|
|
36
|
-
}
|
|
37
23
|
function projectBound(value) {
|
|
38
24
|
if (!isRecord(value))
|
|
39
25
|
return undefined;
|
|
@@ -102,27 +88,3 @@ export function projectTicketProvenanceHeader(value) {
|
|
|
102
88
|
sessions,
|
|
103
89
|
};
|
|
104
90
|
}
|
|
105
|
-
/** 读回一条对话行。 */
|
|
106
|
-
export function projectTicketProvenanceLine(value) {
|
|
107
|
-
if (!isRecord(value))
|
|
108
|
-
return undefined;
|
|
109
|
-
const speaker = projectSpeaker(value.speaker);
|
|
110
|
-
const s = nonNegativeInteger(value.s);
|
|
111
|
-
if (speaker === undefined || s === undefined)
|
|
112
|
-
return undefined;
|
|
113
|
-
if (typeof value.text !== "string")
|
|
114
|
-
return undefined;
|
|
115
|
-
const sourcePosition = nonNegativeInteger(value.sourcePosition);
|
|
116
|
-
const sourceIdentity = typeof value.sourceIdentity === "string" && value.sourceIdentity !== ""
|
|
117
|
-
? value.sourceIdentity
|
|
118
|
-
: undefined;
|
|
119
|
-
const id = typeof value.id === "string" && value.id !== "" ? value.id : undefined;
|
|
120
|
-
return {
|
|
121
|
-
speaker,
|
|
122
|
-
s,
|
|
123
|
-
...(sourcePosition === undefined ? {} : { sourcePosition }),
|
|
124
|
-
...(sourceIdentity === undefined ? {} : { sourceIdentity }),
|
|
125
|
-
...(id === undefined ? {} : { id }),
|
|
126
|
-
text: value.text,
|
|
127
|
-
};
|
|
128
|
-
}
|