@akagilnc/pi-workflow-roles 0.1.5504 → 0.1.5575
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 +5965 -5994
- package/dist/analyst-gate-cycles-read.js +23 -55
- package/dist/analyst-ledger.js +21 -35
- package/dist/analyst-metric-families/acceptance-success-rework.js +25 -1
- package/dist/analyst-metric-families/round-timeline.js +2 -5
- package/dist/archivist-record-pointer.js +38 -30
- package/dist/auditor-dossier-tool.js +4 -3
- package/dist/auditor-soul.js +3 -11
- package/dist/doctor-evidence.js +3 -3
- package/dist/engine-detour-usage.js +6 -14
- package/dist/headless-host/production-host.js +5316 -5324
- package/dist/host-descriptions.js +0 -4
- package/dist/host-session-record.js +266 -267
- package/dist/migrate-book-topology.js +1314 -696
- package/dist/notary-source-run.js +1 -1
- package/dist/packaged-role-registry.js +5 -44
- package/dist/pi/role-turn-host.js +53 -3
- package/dist/public-cli/auto-resume.js +8 -47
- package/dist/public-cli/instruction-seat-run.js +5 -3
- package/dist/public-cli/invocation.js +51 -56
- package/dist/public-cli/main.js +1916 -1748
- package/dist/public-cli/post-admission.js +96 -55
- package/dist/public-cli/run-lifecycle.js +27 -53
- package/dist/public-cli/settlement.js +157 -302
- package/dist/role-run-placement.js +1 -11
- package/dist/role-run-relocation.js +72 -50
- package/dist/run-dossier-files.js +30 -0
- package/dist/run-dossier.js +322 -0
- package/dist/run-terminal-artifacts.js +68 -197
- package/dist/run-ticket-number.js +16 -3
- package/dist/session-identity.js +49 -18
- package/dist/sitian-appender.js +13 -16
- package/dist/sitian-facade.js +11 -0
- package/dist/sitian-reader.js +44 -29
- package/dist/submission-gate.js +1 -1
- package/dist/ticket-provenance.js +22 -7
- package/package.json +1 -1
- package/scripts/build-package.mjs +2 -0
- package/src/acp-host/production-host.ts +1 -1
- package/src/acp-host/role-turn-host.ts +9 -2
- package/src/analyst-gate-cycles-read.ts +26 -60
- package/src/analyst-ledger.ts +27 -42
- package/src/analyst-metric-families/acceptance-success-rework.ts +24 -1
- package/src/analyst-metric-families/gate-cycles.ts +1 -1
- package/src/analyst-metric-families/round-timeline.ts +2 -5
- package/src/analyst-page.ts +3 -3
- package/src/archivist-record-entry.ts +2 -2
- package/src/archivist-record-pointer.ts +50 -36
- package/src/auditor-dossier-tool.ts +7 -5
- package/src/auditor-soul.ts +3 -9
- package/src/book-topology-migration-placement.ts +16 -3
- package/src/book-topology-record-class-migrators.ts +4 -2
- package/src/book-topology-runs-migrator.ts +6 -3
- package/src/doctor-contracts.ts +1 -1
- package/src/doctor-evidence.ts +2 -2
- package/src/engine-detour-tool.ts +1 -1
- package/src/engine-detour-usage.ts +6 -16
- package/src/external-host-turn-loop.ts +25 -0
- package/src/headless-host/production-host.ts +1 -4
- package/src/headless-host/role-turn-host.ts +54 -20
- package/src/host-descriptions.ts +0 -6
- package/src/host-session-record.ts +224 -140
- package/src/notary-source-run.ts +1 -1
- package/src/packaged-role-registry.ts +1 -50
- package/src/pi/adapter.ts +50 -7
- package/src/pi/role-turn-host.ts +51 -3
- package/src/public-cli/auto-resume.ts +7 -43
- package/src/public-cli/instruction-seat-run.ts +9 -2
- package/src/public-cli/invocation.ts +61 -87
- package/src/public-cli/post-admission.ts +111 -72
- package/src/public-cli/run-lifecycle.ts +27 -72
- package/src/public-cli/settlement.ts +193 -418
- package/src/public-cli/terminal.ts +1 -1
- package/src/role-run-placement.ts +2 -13
- package/src/role-run-relocation.ts +71 -68
- package/src/role-runtime.ts +6 -10
- package/src/run-dossier-files.ts +33 -0
- package/src/run-dossier.ts +357 -0
- package/src/run-terminal-artifacts.ts +83 -237
- package/src/run-ticket-number.ts +41 -11
- package/src/session-identity.ts +52 -20
- package/src/sitian-appender.ts +17 -18
- package/src/sitian-facade.ts +22 -0
- package/src/sitian-reader.ts +62 -32
- package/src/submission-gate.ts +1 -1
- package/src/ticket-provenance.ts +20 -7
- package/src/ticket-trajectory.ts +10 -10
|
@@ -26,7 +26,6 @@ export const HOST_DESCRIPTIONS = Object.freeze({
|
|
|
26
26
|
}),
|
|
27
27
|
modelPassing: "set_model",
|
|
28
28
|
setModelId: "bare",
|
|
29
|
-
sessionBindingFile: "grok-acp-session.json",
|
|
30
29
|
}),
|
|
31
30
|
/**
|
|
32
31
|
* Operator home `~/.hermes`, native session/load resume, `acp` subcommand.
|
|
@@ -44,7 +43,6 @@ export const HOST_DESCRIPTIONS = Object.freeze({
|
|
|
44
43
|
}),
|
|
45
44
|
modelPassing: "set_model",
|
|
46
45
|
setModelId: "provider:model",
|
|
47
|
-
sessionBindingFile: "hermes-acp-session.json",
|
|
48
46
|
seatProfileSoul: Object.freeze({
|
|
49
47
|
flag: "-p",
|
|
50
48
|
namePrefix: "ak-",
|
|
@@ -64,7 +62,6 @@ export const HEADLESS_HOST_DESCRIPTIONS = Object.freeze({
|
|
|
64
62
|
"claude": Object.freeze({
|
|
65
63
|
protocol: "claude-print",
|
|
66
64
|
binaryFromHome: Object.freeze([".local", "bin", "claude"]),
|
|
67
|
-
sessionBindingFile: "claude-headless-session.json",
|
|
68
65
|
fixedArgs: Object.freeze([
|
|
69
66
|
// Live NDJSON events → sitian host-session records (#811); last line is the result receipt.
|
|
70
67
|
"--output-format", "stream-json",
|
|
@@ -89,7 +86,6 @@ export const HEADLESS_HOST_DESCRIPTIONS = Object.freeze({
|
|
|
89
86
|
"codex": Object.freeze({
|
|
90
87
|
protocol: "codex-exec",
|
|
91
88
|
binaryFromHome: Object.freeze([".local", "bin", "codex"]),
|
|
92
|
-
sessionBindingFile: "codex-headless-session.json",
|
|
93
89
|
}),
|
|
94
90
|
});
|
|
95
91
|
export function lookupHostDescription(host) {
|
|
@@ -1,304 +1,303 @@
|
|
|
1
|
-
|
|
2
|
-
* Host conversation dossiers are native file copies; sitian append-only (ADR 0086).
|
|
3
|
-
* Replaces live event streaming (ADR 0077) with post-exit CLI original copy.
|
|
4
|
-
* Writes native-session-pointer when session ID is obtained.
|
|
5
|
-
* Writes native-session-copy (or native-session-warning on retry failure) after CLI exit.
|
|
6
|
-
* Log line write failures declare to stderr and never abort the leg.
|
|
7
|
-
*/
|
|
1
|
+
import { randomBytes } from "node:crypto";
|
|
8
2
|
import { spawnSync } from "node:child_process";
|
|
9
|
-
import {
|
|
3
|
+
import {
|
|
4
|
+
copyFileSync,
|
|
5
|
+
existsSync,
|
|
6
|
+
mkdirSync,
|
|
7
|
+
readdirSync,
|
|
8
|
+
renameSync,
|
|
9
|
+
rmSync,
|
|
10
|
+
statSync
|
|
11
|
+
} from "node:fs";
|
|
10
12
|
import { homedir } from "node:os";
|
|
11
13
|
import { dirname, join } from "node:path";
|
|
12
14
|
import { sitianReport } from "./sitian-facade.js";
|
|
13
|
-
import { errorText } from "./unknown-value.js";
|
|
14
|
-
|
|
15
|
-
export const HOST_SESSION_RECORD_KIND = "host-session";
|
|
15
|
+
import { errorText, isEnoent } from "./unknown-value.js";
|
|
16
|
+
const HOST_SESSION_RECORD_KIND = "host-session";
|
|
16
17
|
function declareHostSessionFailure(error) {
|
|
17
|
-
|
|
18
|
-
|
|
18
|
+
const message = error instanceof Error ? error.stack || error.message : String(error);
|
|
19
|
+
process.stderr.write(`[host-session] Dossier record failure: ${message}
|
|
20
|
+
`);
|
|
19
21
|
}
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
declareHostSessionFailure(error);
|
|
27
|
-
}
|
|
22
|
+
function sitianReportSafe(input) {
|
|
23
|
+
try {
|
|
24
|
+
sitianReport(input);
|
|
25
|
+
} catch (error) {
|
|
26
|
+
declareHostSessionFailure(error);
|
|
27
|
+
}
|
|
28
28
|
}
|
|
29
|
-
/** Recursively scan for Codex rollout file matching sessionId under sessionsDir. */
|
|
30
29
|
function findCodexRollout(sessionsDir, sessionId) {
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
30
|
+
const matches = [];
|
|
31
|
+
function scan(dir, depth = 0) {
|
|
32
|
+
if (depth > 6) return;
|
|
33
|
+
let entries;
|
|
34
|
+
try {
|
|
35
|
+
entries = readdirSync(dir, { withFileTypes: true });
|
|
36
|
+
} catch (error) {
|
|
37
|
+
if (isEnoent(error)) return;
|
|
38
|
+
throw error;
|
|
39
|
+
}
|
|
40
|
+
for (const entry of entries) {
|
|
41
|
+
const fullPath = join(dir, entry.name);
|
|
42
|
+
if (entry.isDirectory()) {
|
|
43
|
+
scan(fullPath, depth + 1);
|
|
44
|
+
} else if (entry.isFile() && entry.name.endsWith(".jsonl") && entry.name.includes(sessionId)) {
|
|
38
45
|
try {
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
catch {
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
for (const entry of entries) {
|
|
45
|
-
const fullPath = join(dir, entry.name);
|
|
46
|
-
if (entry.isDirectory()) {
|
|
47
|
-
scan(fullPath, depth + 1);
|
|
48
|
-
}
|
|
49
|
-
else if (entry.isFile() && entry.name.endsWith(".jsonl") && entry.name.includes(sessionId)) {
|
|
50
|
-
try {
|
|
51
|
-
const stat = statSync(fullPath);
|
|
52
|
-
matches.push({ path: fullPath, mtime: stat.mtimeMs });
|
|
53
|
-
}
|
|
54
|
-
catch {
|
|
55
|
-
matches.push({ path: fullPath, mtime: 0 });
|
|
56
|
-
}
|
|
57
|
-
}
|
|
46
|
+
const stat = statSync(fullPath);
|
|
47
|
+
matches.push({ path: fullPath, mtime: stat.mtimeMs });
|
|
48
|
+
} catch (error) {
|
|
49
|
+
if (isEnoent(error)) continue;
|
|
50
|
+
throw error;
|
|
58
51
|
}
|
|
52
|
+
}
|
|
59
53
|
}
|
|
54
|
+
}
|
|
55
|
+
try {
|
|
60
56
|
scan(sessionsDir);
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
57
|
+
} catch (error) {
|
|
58
|
+
if (isEnoent(error)) return void 0;
|
|
59
|
+
throw error;
|
|
60
|
+
}
|
|
61
|
+
if (matches.length === 0 || matches[0] === void 0) return void 0;
|
|
62
|
+
matches.sort((a, b) => b.mtime - a.mtime);
|
|
63
|
+
return matches[0]?.path;
|
|
65
64
|
}
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
* Claude Code replaces all non-alphanumeric characters (slashes, dots, underscores, spaces, etc.) with '-'.
|
|
69
|
-
*/
|
|
70
|
-
export function sanitizeClaudeCwd(cwd) {
|
|
71
|
-
return cwd.replace(/[^a-zA-Z0-9]/g, "-");
|
|
65
|
+
function sanitizeClaudeCwd(cwd) {
|
|
66
|
+
return cwd.replace(/[^a-zA-Z0-9]/g, "-");
|
|
72
67
|
}
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
return findCodexRollout(codexSessionsDirectory(home), options.sessionId);
|
|
89
|
-
}
|
|
90
|
-
if (options.host === "grok-build") {
|
|
91
|
-
const grokHome = process.env.GROK_HOME || join(home, ".grok");
|
|
92
|
-
return join(grokHome, "sessions", encodeURIComponent(options.cwd), options.sessionId);
|
|
93
|
-
}
|
|
94
|
-
return undefined;
|
|
68
|
+
function resolveNativeSessionPath(options) {
|
|
69
|
+
const home = options.home || homedir();
|
|
70
|
+
if (options.host === "claude") {
|
|
71
|
+
const configDir = process.env.CLAUDE_CONFIG_DIR || join(home, ".claude");
|
|
72
|
+
const sanitizedCwd = sanitizeClaudeCwd(options.cwd);
|
|
73
|
+
return join(configDir, "projects", sanitizedCwd, `${options.sessionId}.jsonl`);
|
|
74
|
+
}
|
|
75
|
+
if (options.host === "codex") {
|
|
76
|
+
return findCodexRollout(codexSessionsDirectory(home), options.sessionId);
|
|
77
|
+
}
|
|
78
|
+
if (options.host === "grok-build") {
|
|
79
|
+
const grokHome = process.env.GROK_HOME || join(home, ".grok");
|
|
80
|
+
return join(grokHome, "sessions", encodeURIComponent(options.cwd), options.sessionId);
|
|
81
|
+
}
|
|
82
|
+
return void 0;
|
|
95
83
|
}
|
|
96
84
|
function codexSessionsDirectory(home) {
|
|
97
|
-
|
|
85
|
+
return join(process.env.CODEX_HOME || join(home || homedir(), ".codex"), "sessions");
|
|
98
86
|
}
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
try {
|
|
102
|
-
appendFileSync(join(runDirectory, ".run-starts"), "\n");
|
|
103
|
-
}
|
|
104
|
-
catch (error) {
|
|
105
|
-
declareHostSessionFailure(error);
|
|
106
|
-
}
|
|
87
|
+
function resolveHostDossierLandingPath(options) {
|
|
88
|
+
return options.host === "grok-build" ? join(options.sessionDirectory, options.host) : join(options.sessionDirectory, `${options.host}.jsonl`);
|
|
107
89
|
}
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
maxOrdinal = val;
|
|
126
|
-
}
|
|
127
|
-
}
|
|
128
|
-
}
|
|
129
|
-
}
|
|
130
|
-
catch {
|
|
131
|
-
// Ignore directory read errors
|
|
132
|
-
}
|
|
133
|
-
}
|
|
134
|
-
const startsPath = join(dirname(options.sessionDirectory), ".run-starts");
|
|
135
|
-
let starts = 0;
|
|
136
|
-
if (existsSync(startsPath))
|
|
137
|
-
starts = readFileSync(startsPath, "utf8").length;
|
|
138
|
-
const ordinal = Math.max(maxOrdinal + 1, starts, options.continuation.kind === "resume" ? 2 : 1);
|
|
139
|
-
const baseName = `${options.host}-${sanitizedModel}-${ordinal}`;
|
|
140
|
-
const landingPath = options.host === "grok-build"
|
|
141
|
-
? join(options.sessionDirectory, baseName)
|
|
142
|
-
: join(options.sessionDirectory, `${baseName}.jsonl`);
|
|
143
|
-
return { landingPath, ordinal, sanitizedModel };
|
|
144
|
-
}
|
|
145
|
-
/** Record native session pointer line to Sitian as soon as session ID is known. */
|
|
146
|
-
export function recordNativeSessionPointer(options) {
|
|
147
|
-
if (options.host === "pi" || options.host === "hermes") {
|
|
148
|
-
return undefined;
|
|
90
|
+
function recordNativeSessionPointer(options) {
|
|
91
|
+
if (options.host === "pi" || options.host === "hermes") {
|
|
92
|
+
return void 0;
|
|
93
|
+
}
|
|
94
|
+
const nativePath = options.host === "codex" ? codexSessionsDirectory(options.home) : resolveNativeSessionPath(options);
|
|
95
|
+
if (nativePath === void 0) return void 0;
|
|
96
|
+
sitianReportSafe({
|
|
97
|
+
level: "event",
|
|
98
|
+
kind: HOST_SESSION_RECORD_KIND,
|
|
99
|
+
host: options.host,
|
|
100
|
+
cwd: options.cwd,
|
|
101
|
+
sessionParent: options.sessionParent,
|
|
102
|
+
source: `${options.host}-dossier`,
|
|
103
|
+
payload: {
|
|
104
|
+
type: "native-session-pointer",
|
|
105
|
+
nativePath,
|
|
106
|
+
sessionId: options.sessionId
|
|
149
107
|
}
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
: resolveNativeSessionPath(options);
|
|
153
|
-
if (nativePath === undefined)
|
|
154
|
-
return undefined;
|
|
155
|
-
sitianReportSafe({
|
|
156
|
-
level: "event",
|
|
157
|
-
kind: HOST_SESSION_RECORD_KIND,
|
|
158
|
-
host: options.host,
|
|
159
|
-
cwd: options.cwd,
|
|
160
|
-
sessionParent: options.sessionParent,
|
|
161
|
-
source: `${options.host}-dossier`,
|
|
162
|
-
payload: {
|
|
163
|
-
type: "native-session-pointer",
|
|
164
|
-
nativePath,
|
|
165
|
-
sessionId: options.sessionId,
|
|
166
|
-
},
|
|
167
|
-
});
|
|
168
|
-
return nativePath;
|
|
108
|
+
});
|
|
109
|
+
return nativePath;
|
|
169
110
|
}
|
|
170
|
-
/** File clone via APFS `cp -c` with fallback to `copyFileSync`. */
|
|
171
111
|
function copyFileCloneOrFallback(src, dest) {
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
// cp execution failed, fall back
|
|
179
|
-
}
|
|
180
|
-
copyFileSync(src, dest);
|
|
112
|
+
try {
|
|
113
|
+
const res = spawnSync("cp", ["-c", src, dest]);
|
|
114
|
+
if (res.status === 0) return;
|
|
115
|
+
} catch {
|
|
116
|
+
}
|
|
117
|
+
copyFileSync(src, dest);
|
|
181
118
|
}
|
|
182
|
-
/** Copy both grok-build originals: chat_history.jsonl and usage.json into destDir. */
|
|
183
119
|
function copyGrokDossier(srcDir, destDir) {
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
}
|
|
188
|
-
mkdirSync(destDir, { recursive: true });
|
|
189
|
-
const chatHistoryDest = join(destDir, "chat_history.jsonl");
|
|
190
|
-
copyFileCloneOrFallback(chatHistorySrc, chatHistoryDest);
|
|
191
|
-
const usageSrc = join(srcDir, "usage.json");
|
|
192
|
-
if (!existsSync(usageSrc)) {
|
|
193
|
-
throw new Error(`Grok native usage.json missing at ${usageSrc}`);
|
|
194
|
-
}
|
|
195
|
-
copyFileCloneOrFallback(usageSrc, join(destDir, "usage.json"));
|
|
120
|
+
mkdirSync(destDir, { recursive: true });
|
|
121
|
+
copyFileCloneOrFallback(join(srcDir, "chat_history.jsonl"), join(destDir, "chat_history.jsonl"));
|
|
122
|
+
copyFileCloneOrFallback(join(srcDir, "usage.json"), join(destDir, "usage.json"));
|
|
196
123
|
}
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
}
|
|
208
|
-
|
|
124
|
+
function copyAndRecordHostDossier(options) {
|
|
125
|
+
if (options.host === "hermes") {
|
|
126
|
+
return;
|
|
127
|
+
}
|
|
128
|
+
const report = (payload) => sitianReportSafe({
|
|
129
|
+
level: "event",
|
|
130
|
+
kind: HOST_SESSION_RECORD_KIND,
|
|
131
|
+
host: options.host,
|
|
132
|
+
cwd: options.cwd,
|
|
133
|
+
sessionParent: options.sessionParent,
|
|
134
|
+
source: `${options.host}-dossier`,
|
|
135
|
+
payload
|
|
136
|
+
});
|
|
137
|
+
if (options.host === "pi") {
|
|
138
|
+
report({
|
|
139
|
+
type: "native-session-copy",
|
|
140
|
+
nativePath: options.sessionParent,
|
|
141
|
+
landingPath: options.sessionParent,
|
|
142
|
+
sessionId: options.sessionId
|
|
143
|
+
});
|
|
144
|
+
return;
|
|
145
|
+
}
|
|
146
|
+
const landingPath = resolveHostDossierLandingPath(options);
|
|
147
|
+
let lastError;
|
|
148
|
+
let copySuccess = false;
|
|
149
|
+
let stagingForCleanup;
|
|
150
|
+
let nativePath;
|
|
151
|
+
for (let attempt = 1; attempt <= 2; attempt++) {
|
|
152
|
+
const attemptToken = randomBytes(6).toString("hex");
|
|
153
|
+
const staging = `${landingPath}.copying.${attemptToken}`;
|
|
154
|
+
stagingForCleanup = staging;
|
|
155
|
+
try {
|
|
156
|
+
nativePath = resolveNativeSessionPath({
|
|
209
157
|
host: options.host,
|
|
210
158
|
sessionId: options.sessionId,
|
|
211
159
|
cwd: options.cwd,
|
|
212
|
-
...
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
let destination;
|
|
217
|
-
try {
|
|
218
|
-
destination = resolveHostDossierLandingPath(options);
|
|
219
|
-
}
|
|
220
|
-
catch (error) {
|
|
221
|
-
sitianReportSafe({
|
|
222
|
-
level: "event",
|
|
223
|
-
kind: HOST_SESSION_RECORD_KIND,
|
|
224
|
-
host: options.host,
|
|
225
|
-
cwd: options.cwd,
|
|
226
|
-
sessionParent: options.sessionParent,
|
|
227
|
-
source: `${options.host}-dossier`,
|
|
228
|
-
payload: {
|
|
229
|
-
type: "native-session-warning",
|
|
230
|
-
sessionId: options.sessionId,
|
|
231
|
-
error: errorText(error),
|
|
232
|
-
},
|
|
233
|
-
});
|
|
160
|
+
...options.home !== void 0 ? { home: options.home } : {}
|
|
161
|
+
});
|
|
162
|
+
if (nativePath === void 0 && options.host !== "codex") {
|
|
163
|
+
stagingForCleanup = void 0;
|
|
234
164
|
return;
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
165
|
+
}
|
|
166
|
+
if (options.host === "grok-build") {
|
|
167
|
+
copyGrokDossier(nativePath, staging);
|
|
168
|
+
} else {
|
|
169
|
+
if (nativePath === void 0) {
|
|
170
|
+
throw new Error(`Native session file missing for ${options.host} session ${options.sessionId}`);
|
|
171
|
+
}
|
|
172
|
+
mkdirSync(dirname(landingPath), { recursive: true });
|
|
173
|
+
copyFileCloneOrFallback(nativePath, staging);
|
|
174
|
+
}
|
|
175
|
+
if (options.host === "grok-build") {
|
|
176
|
+
const previous = `${landingPath}.previous.${attemptToken}`;
|
|
177
|
+
const hadPrevious = existsSync(landingPath);
|
|
178
|
+
let parked = false;
|
|
179
|
+
let keepUniquePrevious = false;
|
|
180
|
+
let cleanupError;
|
|
181
|
+
let swapFailure;
|
|
182
|
+
let restoreError;
|
|
240
183
|
try {
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
184
|
+
if (hadPrevious) {
|
|
185
|
+
renameSync(landingPath, previous);
|
|
186
|
+
parked = true;
|
|
187
|
+
}
|
|
188
|
+
try {
|
|
189
|
+
renameSync(staging, landingPath);
|
|
190
|
+
} catch (swapError) {
|
|
191
|
+
if (parked && existsSync(previous) && !existsSync(landingPath)) {
|
|
192
|
+
try {
|
|
193
|
+
renameSync(previous, landingPath);
|
|
194
|
+
} catch (error) {
|
|
195
|
+
restoreError = error;
|
|
196
|
+
if (existsSync(previous) && !existsSync(landingPath)) {
|
|
197
|
+
keepUniquePrevious = true;
|
|
247
198
|
}
|
|
248
|
-
|
|
249
|
-
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
swapFailure = swapError;
|
|
202
|
+
}
|
|
203
|
+
} finally {
|
|
204
|
+
if (parked && existsSync(previous) && !keepUniquePrevious) {
|
|
205
|
+
try {
|
|
206
|
+
rmSync(previous, { recursive: true, force: true });
|
|
207
|
+
} catch (error) {
|
|
208
|
+
cleanupError = error;
|
|
250
209
|
}
|
|
251
|
-
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
if (swapFailure !== void 0) {
|
|
213
|
+
lastError = combineCopyFailureCauses(
|
|
214
|
+
swapFailure,
|
|
215
|
+
restoreError,
|
|
216
|
+
cleanupError,
|
|
217
|
+
cleanupError === void 0 ? void 0 : previous
|
|
218
|
+
);
|
|
219
|
+
if (restoreError !== void 0 || cleanupError !== void 0) {
|
|
220
|
+
break;
|
|
221
|
+
}
|
|
222
|
+
try {
|
|
223
|
+
rmSync(staging, { recursive: true, force: true });
|
|
224
|
+
stagingForCleanup = void 0;
|
|
225
|
+
} catch (stagingCleanupError) {
|
|
226
|
+
lastError = combineCopyFailureCauses(
|
|
227
|
+
swapFailure,
|
|
228
|
+
void 0,
|
|
229
|
+
stagingCleanupError,
|
|
230
|
+
staging
|
|
231
|
+
);
|
|
232
|
+
stagingForCleanup = void 0;
|
|
252
233
|
break;
|
|
234
|
+
}
|
|
235
|
+
continue;
|
|
253
236
|
}
|
|
254
|
-
|
|
255
|
-
|
|
237
|
+
if (cleanupError !== void 0) {
|
|
238
|
+
lastError = combineCopyFailureCauses(cleanupError, void 0, cleanupError, previous);
|
|
239
|
+
stagingForCleanup = void 0;
|
|
240
|
+
break;
|
|
256
241
|
}
|
|
242
|
+
} else {
|
|
243
|
+
renameSync(staging, landingPath);
|
|
244
|
+
}
|
|
245
|
+
copySuccess = true;
|
|
246
|
+
stagingForCleanup = void 0;
|
|
247
|
+
break;
|
|
248
|
+
} catch (error) {
|
|
249
|
+
lastError = error;
|
|
250
|
+
try {
|
|
251
|
+
rmSync(staging, { recursive: true, force: true });
|
|
252
|
+
stagingForCleanup = void 0;
|
|
253
|
+
} catch (cleanupError) {
|
|
254
|
+
lastError = combineCopyFailureCauses(error, void 0, cleanupError, staging);
|
|
255
|
+
stagingForCleanup = void 0;
|
|
256
|
+
break;
|
|
257
|
+
}
|
|
257
258
|
}
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
nativePath,
|
|
269
|
-
landingPath,
|
|
270
|
-
ordinal,
|
|
271
|
-
sessionId: options.sessionId,
|
|
272
|
-
},
|
|
273
|
-
});
|
|
274
|
-
}
|
|
275
|
-
else {
|
|
276
|
-
// A partial first attempt must not masquerade as a complete native original.
|
|
277
|
-
try {
|
|
278
|
-
rmSync(landingPath, { recursive: options.host === "grok-build", force: true });
|
|
279
|
-
}
|
|
280
|
-
catch { /* warning below reports the original copy failure */ }
|
|
281
|
-
// Reserve the failed ordinal outside the native dossier landing namespace.
|
|
282
|
-
try {
|
|
283
|
-
mkdirSync(options.sessionDirectory, { recursive: true });
|
|
284
|
-
closeSync(openSync(join(options.sessionDirectory, `${options.host}-${sanitizedModel}-${ordinal}.failed`), "a"));
|
|
285
|
-
}
|
|
286
|
-
catch { /* the warning below retains the original copy failure */ }
|
|
287
|
-
sitianReportSafe({
|
|
288
|
-
level: "event",
|
|
289
|
-
kind: HOST_SESSION_RECORD_KIND,
|
|
290
|
-
host: options.host,
|
|
291
|
-
cwd: options.cwd,
|
|
292
|
-
sessionParent: options.sessionParent,
|
|
293
|
-
source: `${options.host}-dossier`,
|
|
294
|
-
payload: {
|
|
295
|
-
type: "native-session-warning",
|
|
296
|
-
nativePath,
|
|
297
|
-
landingPath,
|
|
298
|
-
ordinal,
|
|
299
|
-
sessionId: options.sessionId,
|
|
300
|
-
error: errorText(lastError),
|
|
301
|
-
},
|
|
302
|
-
});
|
|
259
|
+
}
|
|
260
|
+
if (copySuccess) {
|
|
261
|
+
report({ type: "native-session-copy", nativePath, landingPath, sessionId: options.sessionId });
|
|
262
|
+
} else {
|
|
263
|
+
if (stagingForCleanup !== void 0) {
|
|
264
|
+
try {
|
|
265
|
+
rmSync(stagingForCleanup, { recursive: true, force: true });
|
|
266
|
+
} catch (cleanupError) {
|
|
267
|
+
lastError = combineCopyFailureCauses(lastError, void 0, cleanupError, stagingForCleanup);
|
|
268
|
+
}
|
|
303
269
|
}
|
|
270
|
+
report({
|
|
271
|
+
type: "native-session-warning",
|
|
272
|
+
nativePath,
|
|
273
|
+
landingPath,
|
|
274
|
+
sessionId: options.sessionId,
|
|
275
|
+
error: errorText(lastError)
|
|
276
|
+
});
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
function combineCopyFailureCauses(primary, restoreError, cleanupError, residualPath) {
|
|
280
|
+
const errors = [primary];
|
|
281
|
+
const parts = [errorText(primary)];
|
|
282
|
+
if (restoreError !== void 0) {
|
|
283
|
+
errors.push(restoreError);
|
|
284
|
+
parts.push(`restore failed: ${errorText(restoreError)}`);
|
|
285
|
+
}
|
|
286
|
+
if (cleanupError !== void 0) {
|
|
287
|
+
if (cleanupError !== primary) errors.push(cleanupError);
|
|
288
|
+
parts.push(
|
|
289
|
+
residualPath === void 0 ? `cleanup failed: ${errorText(cleanupError)}` : `cleanup failed: ${errorText(cleanupError)} (residual: ${residualPath})`
|
|
290
|
+
);
|
|
291
|
+
}
|
|
292
|
+
if (errors.length === 1 && parts.length === 1) return primary;
|
|
293
|
+
return new AggregateError(errors, parts.join("; "), { cause: primary });
|
|
304
294
|
}
|
|
295
|
+
export {
|
|
296
|
+
HOST_SESSION_RECORD_KIND,
|
|
297
|
+
copyAndRecordHostDossier,
|
|
298
|
+
recordNativeSessionPointer,
|
|
299
|
+
resolveHostDossierLandingPath,
|
|
300
|
+
resolveNativeSessionPath,
|
|
301
|
+
sanitizeClaudeCwd,
|
|
302
|
+
sitianReportSafe
|
|
303
|
+
};
|