@wjarka/cezarion 0.14.3-pr445.673 → 0.14.3-pr445.678
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/dist/delegation/transport.d.ts +50 -50
- package/dist/runs/agent-tmpdir.d.ts +20 -11
- package/dist/runs/agent-tmpdir.js +109 -60
- package/dist/runs/agent-tmpdir.js.map +1 -1
- package/dist/runs/event-history.js +11 -1
- package/dist/runs/event-history.js.map +1 -1
- package/dist/server/server.d.ts +1109 -1109
- package/package.json +3 -3
- package/web/dist/assets/{commit-list-BeUMZVTG.js → commit-list-qdzAPi8Z.js} +1 -1
- package/web/dist/assets/{compare-variants-C6cWQRm6.js → compare-variants-C6_Cv6VF.js} +1 -1
- package/web/dist/assets/{github-DOdsQOK1.js → github-BQqHSJy_.js} +1 -1
- package/web/dist/assets/{index-Bgof7Re_.js → index-CLWCibEp.js} +2 -2
- package/web/dist/assets/{repo-git-DrwyyyTd.js → repo-git-DhF1KMFd.js} +1 -1
- package/web/dist/assets/{skills-Cic3wuT0.js → skills-DnmPLWJD.js} +1 -1
- package/web/dist/assets/{task-changes-BTeip8SF.js → task-changes-CcwZXXmr.js} +1 -1
- package/web/dist/assets/{task-commits-_B5Er_bk.js → task-commits-HNUeqwZs.js} +1 -1
- package/web/dist/assets/{task-files-gBSmQiWh.js → task-files-D98MFv71.js} +1 -1
- package/web/dist/assets/{task-thread-DpWTRA9Y.js → task-thread-D1KURj8H.js} +8 -8
- package/web/dist/assets/{workflows-bnMSTYwO.js → workflows-CxIz1O58.js} +1 -1
- package/web/dist/index.html +1 -1
|
@@ -286,18 +286,6 @@ export declare function createDelegationApp(routes: DelegationRoutes): import("h
|
|
|
286
286
|
} & {
|
|
287
287
|
"/:workerId": {
|
|
288
288
|
$get: {
|
|
289
|
-
output: {
|
|
290
|
-
error: string;
|
|
291
|
-
code?: "invalid_input" | undefined;
|
|
292
|
-
};
|
|
293
|
-
outputFormat: "json";
|
|
294
|
-
status: 400;
|
|
295
|
-
input: {
|
|
296
|
-
param: {
|
|
297
|
-
workerId: string;
|
|
298
|
-
};
|
|
299
|
-
};
|
|
300
|
-
} | {
|
|
301
289
|
output: {
|
|
302
290
|
workerId: string;
|
|
303
291
|
parentRunId: string;
|
|
@@ -374,11 +362,7 @@ export declare function createDelegationApp(routes: DelegationRoutes): import("h
|
|
|
374
362
|
workerId: string;
|
|
375
363
|
};
|
|
376
364
|
};
|
|
377
|
-
}
|
|
378
|
-
};
|
|
379
|
-
} & {
|
|
380
|
-
"/:workerId/collect": {
|
|
381
|
-
$post: {
|
|
365
|
+
} | {
|
|
382
366
|
output: {
|
|
383
367
|
error: string;
|
|
384
368
|
code?: "invalid_input" | undefined;
|
|
@@ -389,10 +373,12 @@ export declare function createDelegationApp(routes: DelegationRoutes): import("h
|
|
|
389
373
|
param: {
|
|
390
374
|
workerId: string;
|
|
391
375
|
};
|
|
392
|
-
} & {
|
|
393
|
-
json: Record<string, never>;
|
|
394
376
|
};
|
|
395
|
-
}
|
|
377
|
+
};
|
|
378
|
+
};
|
|
379
|
+
} & {
|
|
380
|
+
"/:workerId/collect": {
|
|
381
|
+
$post: {
|
|
396
382
|
output: {
|
|
397
383
|
workerId: string;
|
|
398
384
|
parentRunId: string;
|
|
@@ -494,11 +480,7 @@ export declare function createDelegationApp(routes: DelegationRoutes): import("h
|
|
|
494
480
|
} & {
|
|
495
481
|
json: Record<string, never>;
|
|
496
482
|
};
|
|
497
|
-
}
|
|
498
|
-
};
|
|
499
|
-
} & {
|
|
500
|
-
"/:workerId/steer": {
|
|
501
|
-
$post: {
|
|
483
|
+
} | {
|
|
502
484
|
output: {
|
|
503
485
|
error: string;
|
|
504
486
|
code?: "invalid_input" | undefined;
|
|
@@ -510,11 +492,13 @@ export declare function createDelegationApp(routes: DelegationRoutes): import("h
|
|
|
510
492
|
workerId: string;
|
|
511
493
|
};
|
|
512
494
|
} & {
|
|
513
|
-
json:
|
|
514
|
-
text: string;
|
|
515
|
-
};
|
|
495
|
+
json: Record<string, never>;
|
|
516
496
|
};
|
|
517
|
-
}
|
|
497
|
+
};
|
|
498
|
+
};
|
|
499
|
+
} & {
|
|
500
|
+
"/:workerId/steer": {
|
|
501
|
+
$post: {
|
|
518
502
|
output: {
|
|
519
503
|
workerId: string;
|
|
520
504
|
state: "delivered" | "queued";
|
|
@@ -530,11 +514,7 @@ export declare function createDelegationApp(routes: DelegationRoutes): import("h
|
|
|
530
514
|
text: string;
|
|
531
515
|
};
|
|
532
516
|
};
|
|
533
|
-
}
|
|
534
|
-
};
|
|
535
|
-
} & {
|
|
536
|
-
"/:workerId/stop": {
|
|
537
|
-
$post: {
|
|
517
|
+
} | {
|
|
538
518
|
output: {
|
|
539
519
|
error: string;
|
|
540
520
|
code?: "invalid_input" | undefined;
|
|
@@ -546,9 +526,15 @@ export declare function createDelegationApp(routes: DelegationRoutes): import("h
|
|
|
546
526
|
workerId: string;
|
|
547
527
|
};
|
|
548
528
|
} & {
|
|
549
|
-
json:
|
|
529
|
+
json: {
|
|
530
|
+
text: string;
|
|
531
|
+
};
|
|
550
532
|
};
|
|
551
|
-
}
|
|
533
|
+
};
|
|
534
|
+
};
|
|
535
|
+
} & {
|
|
536
|
+
"/:workerId/stop": {
|
|
537
|
+
$post: {
|
|
552
538
|
output: {
|
|
553
539
|
workerId: string;
|
|
554
540
|
state: "stopping" | "terminated";
|
|
@@ -562,11 +548,7 @@ export declare function createDelegationApp(routes: DelegationRoutes): import("h
|
|
|
562
548
|
} & {
|
|
563
549
|
json: Record<string, never>;
|
|
564
550
|
};
|
|
565
|
-
}
|
|
566
|
-
};
|
|
567
|
-
} & {
|
|
568
|
-
"/:workerId/destroy": {
|
|
569
|
-
$post: {
|
|
551
|
+
} | {
|
|
570
552
|
output: {
|
|
571
553
|
error: string;
|
|
572
554
|
code?: "invalid_input" | undefined;
|
|
@@ -580,7 +562,11 @@ export declare function createDelegationApp(routes: DelegationRoutes): import("h
|
|
|
580
562
|
} & {
|
|
581
563
|
json: Record<string, never>;
|
|
582
564
|
};
|
|
583
|
-
}
|
|
565
|
+
};
|
|
566
|
+
};
|
|
567
|
+
} & {
|
|
568
|
+
"/:workerId/destroy": {
|
|
569
|
+
$post: {
|
|
584
570
|
output: {
|
|
585
571
|
workerId: string;
|
|
586
572
|
state: "complete" | "incomplete";
|
|
@@ -603,6 +589,20 @@ export declare function createDelegationApp(routes: DelegationRoutes): import("h
|
|
|
603
589
|
} & {
|
|
604
590
|
json: Record<string, never>;
|
|
605
591
|
};
|
|
592
|
+
} | {
|
|
593
|
+
output: {
|
|
594
|
+
error: string;
|
|
595
|
+
code?: "invalid_input" | undefined;
|
|
596
|
+
};
|
|
597
|
+
outputFormat: "json";
|
|
598
|
+
status: 400;
|
|
599
|
+
input: {
|
|
600
|
+
param: {
|
|
601
|
+
workerId: string;
|
|
602
|
+
};
|
|
603
|
+
} & {
|
|
604
|
+
json: Record<string, never>;
|
|
605
|
+
};
|
|
606
606
|
} | {
|
|
607
607
|
output: {
|
|
608
608
|
workerId: string;
|
|
@@ -632,11 +632,13 @@ export declare function createDelegationApp(routes: DelegationRoutes): import("h
|
|
|
632
632
|
"/:workerId/diff": {
|
|
633
633
|
$get: {
|
|
634
634
|
output: {
|
|
635
|
-
|
|
636
|
-
|
|
635
|
+
workerId: string;
|
|
636
|
+
baselineSha: string;
|
|
637
|
+
diff: string;
|
|
638
|
+
truncated: boolean;
|
|
637
639
|
};
|
|
638
640
|
outputFormat: "json";
|
|
639
|
-
status:
|
|
641
|
+
status: 200;
|
|
640
642
|
input: {
|
|
641
643
|
param: {
|
|
642
644
|
workerId: string;
|
|
@@ -644,13 +646,11 @@ export declare function createDelegationApp(routes: DelegationRoutes): import("h
|
|
|
644
646
|
};
|
|
645
647
|
} | {
|
|
646
648
|
output: {
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
diff: string;
|
|
650
|
-
truncated: boolean;
|
|
649
|
+
error: string;
|
|
650
|
+
code?: "invalid_input" | undefined;
|
|
651
651
|
};
|
|
652
652
|
outputFormat: "json";
|
|
653
|
-
status:
|
|
653
|
+
status: 400;
|
|
654
654
|
input: {
|
|
655
655
|
param: {
|
|
656
656
|
workerId: string;
|
|
@@ -13,11 +13,18 @@ export declare function agentTmpDir(dataDir: string, runId: string): string;
|
|
|
13
13
|
* like the 100-character directories #387 reports, moves to the fallback.
|
|
14
14
|
*/
|
|
15
15
|
export declare const MAX_SOCKET_SAFE_DIR_LENGTH = 78;
|
|
16
|
+
/** The first path whose UTF-8 byte length fits the socket budget, or
|
|
17
|
+
* `undefined` when none does. Pure on purpose (#440): resolution calls it
|
|
18
|
+
* with the real candidates, tests with synthetic ones, so the nothing-fits
|
|
19
|
+
* branch stays exercised even though a real platform root is always short. */
|
|
20
|
+
export declare function firstSocketSafeDir(paths: readonly string[]): string | undefined;
|
|
16
21
|
/**
|
|
17
22
|
* The temp directory this run should use: the repo-local per-run directory
|
|
18
|
-
* when it is short enough for unix-socket paths, and a short
|
|
19
|
-
* the OS temp root
|
|
20
|
-
*
|
|
23
|
+
* when it is short enough for unix-socket paths, and otherwise a short
|
|
24
|
+
* digest-named directory under the first OS temp root whose candidate fits —
|
|
25
|
+
* the env-honouring root first, the platform default when `TMPDIR` itself is
|
|
26
|
+
* too deep (#387, #440). Pure resolution — nothing is created, nothing is
|
|
27
|
+
* probed; `agentTmpEnv` owns the side effects.
|
|
21
28
|
*/
|
|
22
29
|
export declare function resolveAgentTmpDir(dataDir: string, runId: string): string;
|
|
23
30
|
/**
|
|
@@ -58,24 +65,26 @@ export declare function agentTmpEnv(dataDir: string, runId: string, env?: NodeJS
|
|
|
58
65
|
* agent is gone, and a Continue re-creates it through `agentTmpEnv`. Never
|
|
59
66
|
* throws — reaping must not break a terminal transition.
|
|
60
67
|
*
|
|
61
|
-
*
|
|
62
|
-
*
|
|
63
|
-
*
|
|
64
|
-
*
|
|
68
|
+
* The repo-local directory and the digest name under EVERY root are tried,
|
|
69
|
+
* because the resolution depends on the lengths of `dataDir` and the ambient
|
|
70
|
+
* `TMPDIR`, either of which a Continue, a re-base or a changed env can move
|
|
71
|
+
* between mint and reap; removing a name that was never minted is a no-op, so
|
|
72
|
+
* trying them all is pure safety.
|
|
65
73
|
*/
|
|
66
74
|
export declare function removeAgentTmpDir(dataDir: string, runId: string): void;
|
|
67
75
|
/**
|
|
68
76
|
* Remove every per-run directory that is not in `keepRunIds` — the startup
|
|
69
77
|
* sweep, so a crash (which never reaches the terminal-transition reap) cannot
|
|
70
|
-
* accumulate them forever.
|
|
78
|
+
* accumulate them forever. Three confined sets are swept and nothing else:
|
|
71
79
|
*
|
|
72
80
|
* - `<dataDir>/tmp`, where entries ARE the run ids (reports the ids reaped);
|
|
73
|
-
* - the
|
|
74
|
-
*
|
|
81
|
+
* - the `cez-agent-<12 hex>` directories under EVERY OS temp root — the
|
|
82
|
+
* env-honouring root and the platform default (#440) — where the name
|
|
83
|
+
* digests the dataDir and is not reversible to a run id (reports the
|
|
75
84
|
* directory names reaped). The pattern is exact — prefix, lowercase hex,
|
|
76
85
|
* fixed length, directories only — and a directory is removed only when
|
|
77
86
|
* its `.cez-owner` marker names THIS dataDir and none of this dataDir's
|
|
78
|
-
* kept runs claims it, so another project's scratch in
|
|
87
|
+
* kept runs claims it, so another project's scratch in a shared root is
|
|
79
88
|
* never touched.
|
|
80
89
|
*/
|
|
81
90
|
export declare function sweepAgentTmpDirs(dataDir: string, keepRunIds: Iterable<string>): string[];
|
|
@@ -30,7 +30,12 @@
|
|
|
30
30
|
* typechecking inside the run. A directory that would land too deep
|
|
31
31
|
* resolves instead to a short digest-named directory under the OS temp
|
|
32
32
|
* root — still per-run, still probed, still reaped. A repo whose own path
|
|
33
|
-
* already fits keeps today's directory, byte for byte.
|
|
33
|
+
* already fits keeps today's directory, byte for byte. When the ambient
|
|
34
|
+
* `TMPDIR` itself is too deep for that root's candidate (#440 — routine
|
|
35
|
+
* inside a cezar task session, whose `TMPDIR` is the checkout's own
|
|
36
|
+
* scratch tree per #785), the next root is the platform's own temp root
|
|
37
|
+
* (`/tmp`), which `TMPDIR` cannot deepen; only when no root fits does the
|
|
38
|
+
* spawn refuse.
|
|
34
39
|
*
|
|
35
40
|
* `CEZ_AGENT_TMPDIR=0` opts out of ALL THREE — cezar keeps its hands off the
|
|
36
41
|
* temp directory entirely and the pre-#785 behaviour is back, byte for byte.
|
|
@@ -85,6 +90,33 @@ function osTempRoot() {
|
|
|
85
90
|
return tmpdir();
|
|
86
91
|
}
|
|
87
92
|
}
|
|
93
|
+
/** The platform's own temp root — the one `TMPDIR`/`TEMP`/`TMP` cannot move.
|
|
94
|
+
* POSIX spells it `/tmp` (resolved through symlinks for the same reason
|
|
95
|
+
* `osTempRoot` resolves them). Windows has no such constant and no named
|
|
96
|
+
* unix sockets to protect, so it contributes no second root and keeps
|
|
97
|
+
* today's single-root behaviour. */
|
|
98
|
+
function platformTempRoot() {
|
|
99
|
+
if (process.platform === 'win32')
|
|
100
|
+
return undefined;
|
|
101
|
+
try {
|
|
102
|
+
return realpathSync('/tmp');
|
|
103
|
+
}
|
|
104
|
+
catch {
|
|
105
|
+
return '/tmp';
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
/** Every root a fallback directory can hang off, most preferred first: the
|
|
109
|
+
* env-honouring OS temp root, then the platform default (#440). A cezar task
|
|
110
|
+
* session exports a `TMPDIR` as deep as the checkout it belongs to (#785),
|
|
111
|
+
* so the first root's candidate can itself cross the socket cap while the
|
|
112
|
+
* platform default still fits. Resolution picks the first root whose
|
|
113
|
+
* candidate fits; removal and the sweep walk them all, because the env can
|
|
114
|
+
* differ between mint and reap. */
|
|
115
|
+
function osTempRoots() {
|
|
116
|
+
const env = osTempRoot();
|
|
117
|
+
const platform = platformTempRoot();
|
|
118
|
+
return platform && platform !== env ? [env, platform] : [env];
|
|
119
|
+
}
|
|
88
120
|
const FALLBACK_PREFIX = 'cez-agent-';
|
|
89
121
|
const FALLBACK_NAME_LENGTH = 12;
|
|
90
122
|
/** The marker file inside a fallback directory naming the dataDir that minted
|
|
@@ -124,39 +156,52 @@ function writeOwnerMarker(dir, dataDir) {
|
|
|
124
156
|
}
|
|
125
157
|
}
|
|
126
158
|
/**
|
|
127
|
-
* Where the fallback lives for this dataDir+run pair. The name
|
|
128
|
-
* dataDir in, because the OS temp
|
|
129
|
-
* id alone would let one repo's reap delete another repo's live
|
|
130
|
-
* two run ids happen to share their leading characters. The name
|
|
131
|
-
* make the sweep safe — a digest is not reversible, so a sweep
|
|
132
|
-
* its own stale directories from another project's live ones —
|
|
133
|
-
* every fallback directory also carries the `.cez-owner` marker.
|
|
159
|
+
* Where the fallback lives for this dataDir+run pair under one root. The name
|
|
160
|
+
* digests the dataDir in, because the OS temp roots are SHARED: a name derived
|
|
161
|
+
* from the run id alone would let one repo's reap delete another repo's live
|
|
162
|
+
* scratch when two run ids happen to share their leading characters. The name
|
|
163
|
+
* alone cannot make the sweep safe — a digest is not reversible, so a sweep
|
|
164
|
+
* could not tell its own stale directories from another project's live ones —
|
|
165
|
+
* which is why every fallback directory also carries the `.cez-owner` marker.
|
|
166
|
+
* The digest does not include the root, so the name is stable across roots:
|
|
167
|
+
* whatever env a later reap or sweep runs under, it can find the directory.
|
|
134
168
|
*/
|
|
135
|
-
function fallbackTmpDir(dataDir, runId) {
|
|
169
|
+
function fallbackTmpDir(root, dataDir, runId) {
|
|
136
170
|
const digest = createHash('sha256').update(`${dataDir}:${runId}`).digest('hex');
|
|
137
|
-
return join(
|
|
171
|
+
return join(root, FALLBACK_PREFIX + digest.slice(0, FALLBACK_NAME_LENGTH));
|
|
172
|
+
}
|
|
173
|
+
/** The first path whose UTF-8 byte length fits the socket budget, or
|
|
174
|
+
* `undefined` when none does. Pure on purpose (#440): resolution calls it
|
|
175
|
+
* with the real candidates, tests with synthetic ones, so the nothing-fits
|
|
176
|
+
* branch stays exercised even though a real platform root is always short. */
|
|
177
|
+
export function firstSocketSafeDir(paths) {
|
|
178
|
+
return paths.find((path) => Buffer.byteLength(path, 'utf8') <= MAX_SOCKET_SAFE_DIR_LENGTH);
|
|
138
179
|
}
|
|
139
180
|
/**
|
|
140
181
|
* The temp directory this run should use: the repo-local per-run directory
|
|
141
|
-
* when it is short enough for unix-socket paths, and a short
|
|
142
|
-
* the OS temp root
|
|
143
|
-
*
|
|
182
|
+
* when it is short enough for unix-socket paths, and otherwise a short
|
|
183
|
+
* digest-named directory under the first OS temp root whose candidate fits —
|
|
184
|
+
* the env-honouring root first, the platform default when `TMPDIR` itself is
|
|
185
|
+
* too deep (#387, #440). Pure resolution — nothing is created, nothing is
|
|
186
|
+
* probed; `agentTmpEnv` owns the side effects.
|
|
144
187
|
*/
|
|
145
188
|
export function resolveAgentTmpDir(dataDir, runId) {
|
|
146
189
|
const local = agentTmpDir(dataDir, runId);
|
|
147
190
|
if (Buffer.byteLength(local, 'utf8') <= MAX_SOCKET_SAFE_DIR_LENGTH)
|
|
148
191
|
return local;
|
|
149
|
-
const
|
|
150
|
-
|
|
192
|
+
const candidates = osTempRoots().map((root) => fallbackTmpDir(root, dataDir, runId));
|
|
193
|
+
const fallback = firstSocketSafeDir(candidates);
|
|
194
|
+
if (fallback)
|
|
151
195
|
return fallback;
|
|
152
|
-
// Nothing fits —
|
|
153
|
-
//
|
|
154
|
-
//
|
|
155
|
-
//
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
+ `${Buffer.byteLength(
|
|
159
|
-
+ `${MAX_SOCKET_SAFE_DIR_LENGTH}-byte unix socket budget`
|
|
196
|
+
// Nothing fits — every root, the platform default included, has a candidate
|
|
197
|
+
// past the cap. Minting any would hand the agent a temp directory that
|
|
198
|
+
// cannot serve unix sockets: the silent failure #387 is about. Fail the
|
|
199
|
+
// spawn with the named error instead; the remedy names the escape.
|
|
200
|
+
const shortest = candidates.reduce((a, b) => Buffer.byteLength(a, 'utf8') < Buffer.byteLength(b, 'utf8') ? a : b);
|
|
201
|
+
throw new AgentTempDirError(Buffer.byteLength(shortest) < Buffer.byteLength(local) ? shortest : local, new Error(`no socket-safe temp directory exists — repo-local path is `
|
|
202
|
+
+ `${Buffer.byteLength(local)} bytes and every OS temp root candidate is past the `
|
|
203
|
+
+ `${MAX_SOCKET_SAFE_DIR_LENGTH}-byte unix socket budget (tried: `
|
|
204
|
+
+ candidates.map((c) => `${c} (${Buffer.byteLength(c)} bytes)`).join(', ') + ')'));
|
|
160
205
|
}
|
|
161
206
|
/** `errno` → the phrasing a human recognises from their shell. */
|
|
162
207
|
const REASONS = {
|
|
@@ -259,15 +304,17 @@ export function agentTmpEnv(dataDir, runId, env = process.env) {
|
|
|
259
304
|
* agent is gone, and a Continue re-creates it through `agentTmpEnv`. Never
|
|
260
305
|
* throws — reaping must not break a terminal transition.
|
|
261
306
|
*
|
|
262
|
-
*
|
|
263
|
-
*
|
|
264
|
-
*
|
|
265
|
-
*
|
|
307
|
+
* The repo-local directory and the digest name under EVERY root are tried,
|
|
308
|
+
* because the resolution depends on the lengths of `dataDir` and the ambient
|
|
309
|
+
* `TMPDIR`, either of which a Continue, a re-base or a changed env can move
|
|
310
|
+
* between mint and reap; removing a name that was never minted is a no-op, so
|
|
311
|
+
* trying them all is pure safety.
|
|
266
312
|
*/
|
|
267
313
|
export function removeAgentTmpDir(dataDir, runId) {
|
|
268
314
|
if (!safeRunId(runId))
|
|
269
315
|
return;
|
|
270
|
-
|
|
316
|
+
const locations = [agentTmpDir(dataDir, runId), ...osTempRoots().map((root) => fallbackTmpDir(root, dataDir, runId))];
|
|
317
|
+
for (const dir of locations) {
|
|
271
318
|
try {
|
|
272
319
|
rmSync(dir, { recursive: true, force: true });
|
|
273
320
|
}
|
|
@@ -279,15 +326,16 @@ export function removeAgentTmpDir(dataDir, runId) {
|
|
|
279
326
|
/**
|
|
280
327
|
* Remove every per-run directory that is not in `keepRunIds` — the startup
|
|
281
328
|
* sweep, so a crash (which never reaches the terminal-transition reap) cannot
|
|
282
|
-
* accumulate them forever.
|
|
329
|
+
* accumulate them forever. Three confined sets are swept and nothing else:
|
|
283
330
|
*
|
|
284
331
|
* - `<dataDir>/tmp`, where entries ARE the run ids (reports the ids reaped);
|
|
285
|
-
* - the
|
|
286
|
-
*
|
|
332
|
+
* - the `cez-agent-<12 hex>` directories under EVERY OS temp root — the
|
|
333
|
+
* env-honouring root and the platform default (#440) — where the name
|
|
334
|
+
* digests the dataDir and is not reversible to a run id (reports the
|
|
287
335
|
* directory names reaped). The pattern is exact — prefix, lowercase hex,
|
|
288
336
|
* fixed length, directories only — and a directory is removed only when
|
|
289
337
|
* its `.cez-owner` marker names THIS dataDir and none of this dataDir's
|
|
290
|
-
* kept runs claims it, so another project's scratch in
|
|
338
|
+
* kept runs claims it, so another project's scratch in a shared root is
|
|
291
339
|
* never touched.
|
|
292
340
|
*/
|
|
293
341
|
export function sweepAgentTmpDirs(dataDir, keepRunIds) {
|
|
@@ -316,44 +364,45 @@ export function sweepAgentTmpDirs(dataDir, keepRunIds) {
|
|
|
316
364
|
}
|
|
317
365
|
}
|
|
318
366
|
}
|
|
319
|
-
// The #387 fallback
|
|
367
|
+
// The #387 fallback locations, in every shared OS temp root. Kept narrow on
|
|
320
368
|
// purpose: exact prefix, 12 lowercase-hex name, directories only, and
|
|
321
369
|
// ownership — a directory is removed only when its `.cez-owner` marker
|
|
322
370
|
// names THIS dataDir (a marker that is missing or foreign is another
|
|
323
371
|
// project's, or unknown, and is never ours to remove) and none of this
|
|
324
372
|
// dataDir's kept runs claims it.
|
|
325
373
|
const owner = dataDirOwner(dataDir);
|
|
326
|
-
const claimed = new Set([...keep].filter(safeRunId).map((id) => basename(fallbackTmpDir(dataDir, id))));
|
|
327
|
-
const osRoot
|
|
328
|
-
|
|
329
|
-
try {
|
|
330
|
-
fallbackEntries = readdirSync(osRoot, { withFileTypes: true });
|
|
331
|
-
}
|
|
332
|
-
catch {
|
|
333
|
-
return reaped;
|
|
334
|
-
}
|
|
335
|
-
for (const entry of fallbackEntries) {
|
|
336
|
-
if (!entry.isDirectory() || !entry.name.startsWith(FALLBACK_PREFIX))
|
|
337
|
-
continue;
|
|
338
|
-
if (!/^[0-9a-f]{12}$/.test(entry.name.slice(FALLBACK_PREFIX.length)))
|
|
339
|
-
continue;
|
|
340
|
-
let entryOwner;
|
|
374
|
+
const claimed = new Set([...keep].filter(safeRunId).map((id) => basename(fallbackTmpDir(osTempRoot(), dataDir, id))));
|
|
375
|
+
for (const osRoot of osTempRoots()) {
|
|
376
|
+
let fallbackEntries;
|
|
341
377
|
try {
|
|
342
|
-
|
|
378
|
+
fallbackEntries = readdirSync(osRoot, { withFileTypes: true });
|
|
343
379
|
}
|
|
344
380
|
catch {
|
|
345
|
-
continue; //
|
|
381
|
+
continue; // an unreadable root is skipped, not fatal: others remain.
|
|
346
382
|
}
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
383
|
+
for (const entry of fallbackEntries) {
|
|
384
|
+
if (!entry.isDirectory() || !entry.name.startsWith(FALLBACK_PREFIX))
|
|
385
|
+
continue;
|
|
386
|
+
if (!/^[0-9a-f]{12}$/.test(entry.name.slice(FALLBACK_PREFIX.length)))
|
|
387
|
+
continue;
|
|
388
|
+
let entryOwner;
|
|
389
|
+
try {
|
|
390
|
+
entryOwner = readFileSync(join(osRoot, entry.name, OWNER_FILE), 'utf8').trim();
|
|
391
|
+
}
|
|
392
|
+
catch {
|
|
393
|
+
continue; // no readable marker: unknown ownership is never ours to remove.
|
|
394
|
+
}
|
|
395
|
+
if (entryOwner !== owner)
|
|
396
|
+
continue;
|
|
397
|
+
if (claimed.has(entry.name))
|
|
398
|
+
continue;
|
|
399
|
+
try {
|
|
400
|
+
rmSync(join(osRoot, entry.name), { recursive: true, force: true });
|
|
401
|
+
reaped.push(entry.name);
|
|
402
|
+
}
|
|
403
|
+
catch {
|
|
404
|
+
// best-effort: a locked directory is retried on the next boot.
|
|
405
|
+
}
|
|
357
406
|
}
|
|
358
407
|
}
|
|
359
408
|
return reaped;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"agent-tmpdir.js","sourceRoot":"","sources":["../../src/runs/agent-tmpdir.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"agent-tmpdir.js","sourceRoot":"","sources":["../../src/runs/agent-tmpdir.ts"],"names":[],"mappings":"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"}
|
|
@@ -106,6 +106,7 @@ export function canonicalSessionItems(events) {
|
|
|
106
106
|
const v1Tools = [];
|
|
107
107
|
const v1Texts = [];
|
|
108
108
|
const v2Texts = [];
|
|
109
|
+
const requestOutcomes = [];
|
|
109
110
|
const upsert = (key, event) => {
|
|
110
111
|
const existing = items.get(key);
|
|
111
112
|
if (existing) {
|
|
@@ -221,7 +222,10 @@ export function canonicalSessionItems(events) {
|
|
|
221
222
|
// terminal projection of the request card, so pagination must keep both events under
|
|
222
223
|
// one canonical identity rather than allowing a standalone outcome at a page boundary.
|
|
223
224
|
if (parsed.success)
|
|
224
|
-
|
|
225
|
+
requestOutcomes.push({
|
|
226
|
+
key: `conversation-message:${parsed.data.outcome.requestId}`,
|
|
227
|
+
event,
|
|
228
|
+
});
|
|
225
229
|
continue;
|
|
226
230
|
}
|
|
227
231
|
if (event.type === 'agent-input') {
|
|
@@ -234,6 +238,12 @@ export function canonicalSessionItems(events) {
|
|
|
234
238
|
upsert(`standalone:${event.seq}`, event);
|
|
235
239
|
}
|
|
236
240
|
flushTurn();
|
|
241
|
+
// Keep the projection in the returned event slice for attachment after an older page loads,
|
|
242
|
+
// but do not let an outcome whose request is outside this scan consume a visible item slot.
|
|
243
|
+
for (const { key, event } of requestOutcomes) {
|
|
244
|
+
if (items.has(key))
|
|
245
|
+
upsert(key, event);
|
|
246
|
+
}
|
|
237
247
|
return [...items.values()].sort((a, b) => a.firstSeq - b.firstSeq);
|
|
238
248
|
}
|
|
239
249
|
async function reverseEventsUntil(filePath, beforeSeq, wantedItems) {
|