@wjarka/cezarion 0.14.2-pr404.619 → 0.14.2-pr406.627
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 +17 -1
- package/dist/runs/agent-tmpdir.d.ts +42 -4
- package/dist/runs/agent-tmpdir.js +145 -31
- package/dist/runs/agent-tmpdir.js.map +1 -1
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -599,7 +599,7 @@ Useful environment variables:
|
|
|
599
599
|
| `GITHUB_TOKEN` | Fallback for GitHub reads/PRs when `gh` isn't authenticated. |
|
|
600
600
|
| `CEZ_ENV_PASSTHROUGH=A,B` | Forward these extra host env vars to spawned agents. By default agents get a least-privilege env (safe shell/toolchain vars + the backend's own auth + `GITHUB_TOKEN` + `CEZ_*`), not your full environment — use this to add a var an agent needs. |
|
|
601
601
|
| `CEZ_AGENT_ENV_FULL=1` | Escape hatch: give spawned agents the full host environment (pre-hardening behavior). Off by default; only set it if you understand that this hands every host secret to the agent process. |
|
|
602
|
-
| `CEZ_AGENT_TMPDIR=0` | Stop giving each task its own temp directory and hand agents the host `TMPDIR` again (pre-#785 behavior). On by default: every run gets `TMPDIR`/`TEMP`/`TMP` pointing at `.ai/cezar/tmp/<task-id>`, created and write-probed before the agent spawns and reaped when the run ends
|
|
602
|
+
| `CEZ_AGENT_TMPDIR=0` | Stop giving each task its own temp directory and hand agents the host `TMPDIR` again (pre-#785 behavior). On by default: every run gets `TMPDIR`/`TEMP`/`TMP` pointing at `.ai/cezar/tmp/<task-id>`, created and write-probed before the agent spawns and reaped when the run ends — and kept short enough for unix-socket paths: a checkout so deep that `.ai/cezar/tmp/<task-id>` would cross the kernel's socket-path limit resolves it to a `cez-agent-…` directory under the system temp dir instead (#387). So concurrent tasks stop sharing one directory and a task refuses to start rather than run against a temp directory that silently swallows its shell output (see Troubleshooting below). Only an exact `0` disables it, and it disables the whole thing — the pre-spawn check included, so this stays an escape hatch you can actually take. |
|
|
603
603
|
| `CEZ_REDACT_SECRETS=0` | Disable scrubbing of credential values/token shapes from the on-disk state (the NDJSON transcript and the free-text fields of `runs.json`). On by default; leave it on. Controller-generated delegation tokens are always scrubbed. Best-effort defense-in-depth, not a guarantee: it catches known token shapes and the values of your own secret-named env vars, so a credential in neither category can still get through. |
|
|
604
604
|
| `CEZ_TITLE_UPDATES=0` | Turn off the live task-title refresh (namer re-runs on each turn end). The Settings → Agents toggle overrides this default. |
|
|
605
605
|
| `CEZ_AUTONAME=0` | Disable ALL LLM task naming (creation + live) — titles stay heuristic (`437: /om-auto-review-pr`). Under `CEZ_DRY_RUN=1` naming is already off unless forced with `CEZ_AUTONAME=1`. |
|
|
@@ -636,6 +636,22 @@ per-task directory and pre-spawn check alike — and hands agents the host
|
|
|
636
636
|
`TMPDIR` again, which is the way out if the check itself is wrong on your
|
|
637
637
|
platform.
|
|
638
638
|
|
|
639
|
+
### Troubleshooting: tools inside a task fail with a socket-path error
|
|
640
|
+
|
|
641
|
+
**Symptom.** Inside a task, `npm install`, `npm run typecheck`, or another tool
|
|
642
|
+
dies with `listen EINVAL` or a "socket path too long" / `ENAMETOOLONG` error —
|
|
643
|
+
with `TMPDIR=/tmp` set by hand, the same commands succeed. Tools like `tsx` bind
|
|
644
|
+
*named* unix sockets under `TMPDIR` (its IPC server builds
|
|
645
|
+
`<tmpdir>/tsx-<uid>/<pid>.pipe`), and the kernel caps a socket path at 104–108
|
|
646
|
+
bytes — a temp directory near that length leaves no room for the name.
|
|
647
|
+
|
|
648
|
+
**Fix.** Since #387 cezar keeps each task's temp directory at most 78 bytes. A
|
|
649
|
+
checkout deep enough to push `.ai/cezar/tmp/<task-id>` past that limit gets a
|
|
650
|
+
short `cez-agent-…` directory under the system temp directory instead — still
|
|
651
|
+
per-task, still write-probed before the agent spawns, still reaped when the run
|
|
652
|
+
ends. Checkouts whose path already fits keep the repo-local directory.
|
|
653
|
+
`CEZ_AGENT_TMPDIR=0` reverts the whole mechanism to the host `TMPDIR`.
|
|
654
|
+
|
|
639
655
|
---
|
|
640
656
|
|
|
641
657
|
## Coding agent backends
|
|
@@ -1,5 +1,24 @@
|
|
|
1
1
|
/** Where a run's agent-scoped temp directory lives. */
|
|
2
2
|
export declare function agentTmpDir(dataDir: string, runId: string): string;
|
|
3
|
+
/**
|
|
4
|
+
* The longest a per-run temp directory may be so that tools binding named
|
|
5
|
+
* unix sockets under it still work (#387). `sockaddr_un.sun_path` holds 108
|
|
6
|
+
* bytes on Linux and 104 on macOS, NUL included; the longest name a known
|
|
7
|
+
* tool lays down under TMPDIR is tsx's IPC socket, `<tmpdir>/tsx-<uid>/
|
|
8
|
+
* <pid>.pipe`, ~22 bytes (Chrome's `SingletonSocket` is 16). A 78-byte
|
|
9
|
+
* ceiling leaves ≥25 bytes of headroom on the tighter platform — past
|
|
10
|
+
* anything these tools generate — while keeping ordinary checkouts on their
|
|
11
|
+
* repo-local scratch: only a genuinely deep path, like the 100-character
|
|
12
|
+
* directories #387 reports, moves to the fallback.
|
|
13
|
+
*/
|
|
14
|
+
export declare const MAX_SOCKET_SAFE_DIR_LENGTH = 78;
|
|
15
|
+
/**
|
|
16
|
+
* The temp directory this run should use: the repo-local per-run directory
|
|
17
|
+
* when it is short enough for unix-socket paths, and a short directory under
|
|
18
|
+
* the OS temp root when it is not (#387). Pure resolution — nothing is
|
|
19
|
+
* created, nothing is probed; `agentTmpEnv` owns the side effects.
|
|
20
|
+
*/
|
|
21
|
+
export declare function resolveAgentTmpDir(dataDir: string, runId: string): string;
|
|
3
22
|
/**
|
|
4
23
|
* The preflight's failure. Named so the spawn path can tell it apart from an
|
|
5
24
|
* ordinary crash and turn it into the run's `error` — the same treatment
|
|
@@ -17,12 +36,19 @@ export declare function agentTmpDirEnabled(env?: NodeJS.ProcessEnv): boolean;
|
|
|
17
36
|
* directory actually accepts writes. Throws `AgentTempDirError` when it does
|
|
18
37
|
* not — callers turn that into the run's error rather than spawning.
|
|
19
38
|
*
|
|
39
|
+
* The directory is `resolveAgentTmpDir`'s call: repo-local when that path is
|
|
40
|
+
* short enough for unix-socket paths, a digest-named directory under the OS
|
|
41
|
+
* temp root when the checkout is too deep for one (#387). In the shared OS
|
|
42
|
+
* root the directory is created private to this user (0700); repo-local
|
|
43
|
+
* scratch already sits inside the user's own tree and keeps the default mode
|
|
44
|
+
* it always had.
|
|
45
|
+
*
|
|
20
46
|
* All three spellings are set, on every platform: a tool that reads `TMP` (or
|
|
21
47
|
* `TEMP`) would otherwise keep following the host value straight back to the
|
|
22
48
|
* exhausted directory this exists to escape.
|
|
23
49
|
*
|
|
24
|
-
* Returns `{}` under the opt-out, without probing anything: the hatch turns
|
|
25
|
-
* whole feature off, preflight included, so it stays an escape someone can
|
|
50
|
+
* Returns `{}` under the opt-out, without probing anything: the hatch turns
|
|
51
|
+
* the whole feature off, preflight included, so it stays an escape someone can
|
|
26
52
|
* actually take.
|
|
27
53
|
*/
|
|
28
54
|
export declare function agentTmpEnv(dataDir: string, runId: string, env?: NodeJS.ProcessEnv): Record<string, string>;
|
|
@@ -30,12 +56,24 @@ export declare function agentTmpEnv(dataDir: string, runId: string, env?: NodeJS
|
|
|
30
56
|
* Reap one run's directory. Scratch, not an artifact: nothing reads it once the
|
|
31
57
|
* agent is gone, and a Continue re-creates it through `agentTmpEnv`. Never
|
|
32
58
|
* throws — reaping must not break a terminal transition.
|
|
59
|
+
*
|
|
60
|
+
* Both locations are tried because the resolution depends on the length of
|
|
61
|
+
* `dataDir`, which a Continue or a re-base can change between mint and reap;
|
|
62
|
+
* removing a name that was never minted is a no-op, so trying both is pure
|
|
63
|
+
* safety.
|
|
33
64
|
*/
|
|
34
65
|
export declare function removeAgentTmpDir(dataDir: string, runId: string): void;
|
|
35
66
|
/**
|
|
36
67
|
* Remove every per-run directory that is not in `keepRunIds` — the startup
|
|
37
68
|
* sweep, so a crash (which never reaches the terminal-transition reap) cannot
|
|
38
|
-
* accumulate them forever.
|
|
39
|
-
*
|
|
69
|
+
* accumulate them forever. Two confined roots are swept and nothing else:
|
|
70
|
+
*
|
|
71
|
+
* - `<dataDir>/tmp`, where entries ARE the run ids (reports the ids reaped);
|
|
72
|
+
* - the OS temp root's `cez-agent-<12 hex>` directories (#387), where the
|
|
73
|
+
* name digests the dataDir and is not reversible to a run id (reports the
|
|
74
|
+
* directory names reaped). The pattern is exact — prefix, lowercase hex,
|
|
75
|
+
* fixed length, directories only — and a directory is removed only when
|
|
76
|
+
* THIS dataDir cannot claim it, so another repo's scratch in the shared
|
|
77
|
+
* root is never touched.
|
|
40
78
|
*/
|
|
41
79
|
export declare function sweepAgentTmpDirs(dataDir: string, keepRunIds: Iterable<string>): string[];
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Task-scoped temp directory for spawned agents (#785).
|
|
2
|
+
* Task-scoped temp directory for spawned agents (#785, length-capped by #387).
|
|
3
3
|
*
|
|
4
4
|
* Every agent used to inherit the host's `TMPDIR`/`TEMP`/`TMP` verbatim — they
|
|
5
5
|
* ride in on `buildChildEnv`'s base allowlist — so every run on the machine
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
* the agent reads back an empty result with a bogus exit status. Nothing in the
|
|
13
13
|
* cockpit says anything is wrong.
|
|
14
14
|
*
|
|
15
|
-
*
|
|
15
|
+
* Three properties fix that, and this module owns all of them:
|
|
16
16
|
*
|
|
17
17
|
* 1. **Isolation** — each run gets `<dataDir>/tmp/<runId>`, on the same disk
|
|
18
18
|
* as the run's own state rather than a shared tmpfs, reaped when the run
|
|
@@ -21,15 +21,28 @@
|
|
|
21
21
|
* 2. **Fail loud** — the directory is write-probed before the backend spawns.
|
|
22
22
|
* A run that cannot get a working temp directory fails immediately with a
|
|
23
23
|
* named, actionable error instead of spawning an agent that will run blind.
|
|
24
|
+
* 3. **Short enough to bind** (#387) — tools bind *named* unix sockets under
|
|
25
|
+
* `TMPDIR` (tsx's IPC server lays down `<tmpdir>/tsx-<uid>/<pid>.pipe`,
|
|
26
|
+
* Chrome a `SingletonSocket`), and the kernel caps a socket path at
|
|
27
|
+
* `sun_path` — 108 bytes on Linux, 104 on macOS, NUL included. A checkout
|
|
28
|
+
* deep enough (Cezar's own nested task worktrees land past 100 chars)
|
|
29
|
+
* pushed every such bind past the cap and broke `npm install` and
|
|
30
|
+
* typechecking inside the run. A directory that would land too deep
|
|
31
|
+
* resolves instead to a short digest-named directory under the OS temp
|
|
32
|
+
* root — still per-run, still probed, still reaped. A repo whose own path
|
|
33
|
+
* already fits keeps today's directory, byte for byte.
|
|
24
34
|
*
|
|
25
|
-
* `CEZ_AGENT_TMPDIR=0` opts out of
|
|
26
|
-
* directory entirely and the pre-#785 behaviour is back, byte for byte.
|
|
27
|
-
* deliberate: an escape hatch that still imposed the preflight would be
|
|
28
|
-
* you cannot actually escape through, and this repo's
|
|
29
|
-
* says a new check must never become the only way to
|
|
35
|
+
* `CEZ_AGENT_TMPDIR=0` opts out of ALL THREE — cezar keeps its hands off the
|
|
36
|
+
* temp directory entirely and the pre-#785 behaviour is back, byte for byte.
|
|
37
|
+
* That is deliberate: an escape hatch that still imposed the preflight would be
|
|
38
|
+
* a hatch you cannot actually escape through, and this repo's
|
|
39
|
+
* graceful-degradation rule says a new check must never become the only way to
|
|
40
|
+
* run.
|
|
30
41
|
*/
|
|
31
|
-
import {
|
|
32
|
-
import {
|
|
42
|
+
import { createHash } from 'node:crypto';
|
|
43
|
+
import { existsSync, mkdirSync, readdirSync, realpathSync, rmSync, writeFileSync } from 'node:fs';
|
|
44
|
+
import { tmpdir } from 'node:os';
|
|
45
|
+
import { basename, join } from 'node:path';
|
|
33
46
|
/** Run ids are uuids; anything else must never reach a recursive `rmSync`.
|
|
34
47
|
*
|
|
35
48
|
* `.` and `..` are excluded explicitly, not as pedantry: they match the
|
|
@@ -48,6 +61,58 @@ export function agentTmpDir(dataDir, runId) {
|
|
|
48
61
|
function agentTmpRoot(dataDir) {
|
|
49
62
|
return join(dataDir, 'tmp');
|
|
50
63
|
}
|
|
64
|
+
/**
|
|
65
|
+
* The longest a per-run temp directory may be so that tools binding named
|
|
66
|
+
* unix sockets under it still work (#387). `sockaddr_un.sun_path` holds 108
|
|
67
|
+
* bytes on Linux and 104 on macOS, NUL included; the longest name a known
|
|
68
|
+
* tool lays down under TMPDIR is tsx's IPC socket, `<tmpdir>/tsx-<uid>/
|
|
69
|
+
* <pid>.pipe`, ~22 bytes (Chrome's `SingletonSocket` is 16). A 78-byte
|
|
70
|
+
* ceiling leaves ≥25 bytes of headroom on the tighter platform — past
|
|
71
|
+
* anything these tools generate — while keeping ordinary checkouts on their
|
|
72
|
+
* repo-local scratch: only a genuinely deep path, like the 100-character
|
|
73
|
+
* directories #387 reports, moves to the fallback.
|
|
74
|
+
*/
|
|
75
|
+
export const MAX_SOCKET_SAFE_DIR_LENGTH = 78;
|
|
76
|
+
/** The OS temp root, symlink-resolved: `bind(2)` bounds the path the kernel
|
|
77
|
+
* walks, so the check must measure what the path resolves to, not what it
|
|
78
|
+
* says (macOS hands out `/var/folders/...` through a `/private/var` symlink). */
|
|
79
|
+
function osTempRoot() {
|
|
80
|
+
try {
|
|
81
|
+
return realpathSync(tmpdir());
|
|
82
|
+
}
|
|
83
|
+
catch {
|
|
84
|
+
return tmpdir();
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
const FALLBACK_PREFIX = 'cez-agent-';
|
|
88
|
+
const FALLBACK_NAME_LENGTH = 12;
|
|
89
|
+
/**
|
|
90
|
+
* Where the fallback lives for this dataDir+run pair. The name digests the
|
|
91
|
+
* dataDir in, because the OS temp root is SHARED: a name derived from the run
|
|
92
|
+
* id alone would let one repo's reap or sweep delete another repo's live
|
|
93
|
+
* scratch when two run ids happen to share their leading characters.
|
|
94
|
+
*/
|
|
95
|
+
function fallbackTmpDir(dataDir, runId) {
|
|
96
|
+
const digest = createHash('sha256').update(`${dataDir}:${runId}`).digest('hex');
|
|
97
|
+
return join(osTempRoot(), FALLBACK_PREFIX + digest.slice(0, FALLBACK_NAME_LENGTH));
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* The temp directory this run should use: the repo-local per-run directory
|
|
101
|
+
* when it is short enough for unix-socket paths, and a short directory under
|
|
102
|
+
* the OS temp root when it is not (#387). Pure resolution — nothing is
|
|
103
|
+
* created, nothing is probed; `agentTmpEnv` owns the side effects.
|
|
104
|
+
*/
|
|
105
|
+
export function resolveAgentTmpDir(dataDir, runId) {
|
|
106
|
+
const local = agentTmpDir(dataDir, runId);
|
|
107
|
+
if (local.length <= MAX_SOCKET_SAFE_DIR_LENGTH)
|
|
108
|
+
return local;
|
|
109
|
+
const fallback = fallbackTmpDir(dataDir, runId);
|
|
110
|
+
if (fallback.length <= MAX_SOCKET_SAFE_DIR_LENGTH)
|
|
111
|
+
return fallback;
|
|
112
|
+
// No candidate fits (a pathological host TMPDIR over a pathological repo
|
|
113
|
+
// path together): keep whichever leaves socket names the most room.
|
|
114
|
+
return fallback.length < local.length ? fallback : local;
|
|
115
|
+
}
|
|
51
116
|
/** `errno` → the phrasing a human recognises from their shell. */
|
|
52
117
|
const REASONS = {
|
|
53
118
|
EDQUOT: 'Disk quota exceeded',
|
|
@@ -110,20 +175,28 @@ function probeWritable(dir) {
|
|
|
110
175
|
* directory actually accepts writes. Throws `AgentTempDirError` when it does
|
|
111
176
|
* not — callers turn that into the run's error rather than spawning.
|
|
112
177
|
*
|
|
178
|
+
* The directory is `resolveAgentTmpDir`'s call: repo-local when that path is
|
|
179
|
+
* short enough for unix-socket paths, a digest-named directory under the OS
|
|
180
|
+
* temp root when the checkout is too deep for one (#387). In the shared OS
|
|
181
|
+
* root the directory is created private to this user (0700); repo-local
|
|
182
|
+
* scratch already sits inside the user's own tree and keeps the default mode
|
|
183
|
+
* it always had.
|
|
184
|
+
*
|
|
113
185
|
* All three spellings are set, on every platform: a tool that reads `TMP` (or
|
|
114
186
|
* `TEMP`) would otherwise keep following the host value straight back to the
|
|
115
187
|
* exhausted directory this exists to escape.
|
|
116
188
|
*
|
|
117
|
-
* Returns `{}` under the opt-out, without probing anything: the hatch turns
|
|
118
|
-
* whole feature off, preflight included, so it stays an escape someone can
|
|
189
|
+
* Returns `{}` under the opt-out, without probing anything: the hatch turns
|
|
190
|
+
* the whole feature off, preflight included, so it stays an escape someone can
|
|
119
191
|
* actually take.
|
|
120
192
|
*/
|
|
121
193
|
export function agentTmpEnv(dataDir, runId, env = process.env) {
|
|
122
194
|
if (!agentTmpDirEnabled(env))
|
|
123
195
|
return {};
|
|
124
|
-
const
|
|
196
|
+
const local = agentTmpDir(dataDir, runId);
|
|
197
|
+
const dir = resolveAgentTmpDir(dataDir, runId);
|
|
125
198
|
try {
|
|
126
|
-
mkdirSync(dir, { recursive: true });
|
|
199
|
+
mkdirSync(dir, dir === local ? { recursive: true } : { recursive: true, mode: 0o700 });
|
|
127
200
|
}
|
|
128
201
|
catch (err) {
|
|
129
202
|
throw new AgentTempDirError(dir, err);
|
|
@@ -135,44 +208,85 @@ export function agentTmpEnv(dataDir, runId, env = process.env) {
|
|
|
135
208
|
* Reap one run's directory. Scratch, not an artifact: nothing reads it once the
|
|
136
209
|
* agent is gone, and a Continue re-creates it through `agentTmpEnv`. Never
|
|
137
210
|
* throws — reaping must not break a terminal transition.
|
|
211
|
+
*
|
|
212
|
+
* Both locations are tried because the resolution depends on the length of
|
|
213
|
+
* `dataDir`, which a Continue or a re-base can change between mint and reap;
|
|
214
|
+
* removing a name that was never minted is a no-op, so trying both is pure
|
|
215
|
+
* safety.
|
|
138
216
|
*/
|
|
139
217
|
export function removeAgentTmpDir(dataDir, runId) {
|
|
140
218
|
if (!safeRunId(runId))
|
|
141
219
|
return;
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
220
|
+
for (const dir of [agentTmpDir(dataDir, runId), fallbackTmpDir(dataDir, runId)]) {
|
|
221
|
+
try {
|
|
222
|
+
rmSync(dir, { recursive: true, force: true });
|
|
223
|
+
}
|
|
224
|
+
catch {
|
|
225
|
+
// best-effort; the startup sweep picks up whatever survives.
|
|
226
|
+
}
|
|
147
227
|
}
|
|
148
228
|
}
|
|
149
229
|
/**
|
|
150
230
|
* Remove every per-run directory that is not in `keepRunIds` — the startup
|
|
151
231
|
* sweep, so a crash (which never reaches the terminal-transition reap) cannot
|
|
152
|
-
* accumulate them forever.
|
|
153
|
-
*
|
|
232
|
+
* accumulate them forever. Two confined roots are swept and nothing else:
|
|
233
|
+
*
|
|
234
|
+
* - `<dataDir>/tmp`, where entries ARE the run ids (reports the ids reaped);
|
|
235
|
+
* - the OS temp root's `cez-agent-<12 hex>` directories (#387), where the
|
|
236
|
+
* name digests the dataDir and is not reversible to a run id (reports the
|
|
237
|
+
* directory names reaped). The pattern is exact — prefix, lowercase hex,
|
|
238
|
+
* fixed length, directories only — and a directory is removed only when
|
|
239
|
+
* THIS dataDir cannot claim it, so another repo's scratch in the shared
|
|
240
|
+
* root is never touched.
|
|
154
241
|
*/
|
|
155
242
|
export function sweepAgentTmpDirs(dataDir, keepRunIds) {
|
|
156
|
-
const root = agentTmpRoot(dataDir);
|
|
157
|
-
if (!existsSync(root))
|
|
158
|
-
return [];
|
|
159
243
|
const keep = new Set(keepRunIds);
|
|
160
244
|
const reaped = [];
|
|
161
245
|
let entries;
|
|
246
|
+
const root = agentTmpRoot(dataDir);
|
|
247
|
+
if (existsSync(root)) {
|
|
248
|
+
try {
|
|
249
|
+
entries = readdirSync(root, { withFileTypes: true })
|
|
250
|
+
.filter((e) => e.isDirectory())
|
|
251
|
+
.map((e) => e.name);
|
|
252
|
+
}
|
|
253
|
+
catch {
|
|
254
|
+
entries = [];
|
|
255
|
+
}
|
|
256
|
+
for (const name of entries) {
|
|
257
|
+
if (keep.has(name) || !safeRunId(name))
|
|
258
|
+
continue;
|
|
259
|
+
try {
|
|
260
|
+
rmSync(join(root, name), { recursive: true, force: true });
|
|
261
|
+
reaped.push(name);
|
|
262
|
+
}
|
|
263
|
+
catch {
|
|
264
|
+
// best-effort: a locked directory is retried on the next boot.
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
// The #387 fallback location, in the shared OS temp root. Kept narrow on
|
|
269
|
+
// purpose: exact prefix, 12 lowercase-hex name, directories only, and only
|
|
270
|
+
// names this dataDir cannot claim.
|
|
271
|
+
const claimed = new Set([...keep].filter(safeRunId).map((id) => basename(fallbackTmpDir(dataDir, id))));
|
|
272
|
+
const osRoot = osTempRoot();
|
|
273
|
+
let fallbackEntries;
|
|
162
274
|
try {
|
|
163
|
-
|
|
164
|
-
.filter((e) => e.isDirectory())
|
|
165
|
-
.map((e) => e.name);
|
|
275
|
+
fallbackEntries = readdirSync(osRoot, { withFileTypes: true });
|
|
166
276
|
}
|
|
167
277
|
catch {
|
|
168
|
-
return
|
|
278
|
+
return reaped;
|
|
169
279
|
}
|
|
170
|
-
for (const
|
|
171
|
-
if (
|
|
280
|
+
for (const entry of fallbackEntries) {
|
|
281
|
+
if (!entry.isDirectory() || !entry.name.startsWith(FALLBACK_PREFIX))
|
|
282
|
+
continue;
|
|
283
|
+
if (!/^[0-9a-f]{12}$/.test(entry.name.slice(FALLBACK_PREFIX.length)))
|
|
284
|
+
continue;
|
|
285
|
+
if (claimed.has(entry.name))
|
|
172
286
|
continue;
|
|
173
287
|
try {
|
|
174
|
-
rmSync(join(
|
|
175
|
-
reaped.push(name);
|
|
288
|
+
rmSync(join(osRoot, entry.name), { recursive: true, force: true });
|
|
289
|
+
reaped.push(entry.name);
|
|
176
290
|
}
|
|
177
291
|
catch {
|
|
178
292
|
// best-effort: a locked directory is retried on the next boot.
|
|
@@ -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":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAwCG;AACH,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAEzC,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAClG,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AACjC,OAAO,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAE3C;;;;;8EAK8E;AAC9E,SAAS,SAAS,CAAC,EAAU;IAC3B,OAAO,mBAAmB,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,EAAE,KAAK,GAAG,IAAI,EAAE,KAAK,IAAI,CAAC;AACnE,CAAC;AAED,uDAAuD;AACvD,MAAM,UAAU,WAAW,CAAC,OAAe,EAAE,KAAa;IACxD,OAAO,IAAI,CAAC,OAAO,EAAE,KAAK,EAAE,KAAK,CAAC,CAAC;AACrC,CAAC;AAED;kFACkF;AAClF,SAAS,YAAY,CAAC,OAAe;IACnC,OAAO,IAAI,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC;AAC9B,CAAC;AAED;;;;;;;;;;GAUG;AACH,MAAM,CAAC,MAAM,0BAA0B,GAAG,EAAE,CAAC;AAE7C;;kFAEkF;AAClF,SAAS,UAAU;IACjB,IAAI,CAAC;QACH,OAAO,YAAY,CAAC,MAAM,EAAE,CAAC,CAAC;IAChC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,MAAM,EAAE,CAAC;IAClB,CAAC;AACH,CAAC;AAED,MAAM,eAAe,GAAG,YAAY,CAAC;AACrC,MAAM,oBAAoB,GAAG,EAAE,CAAC;AAEhC;;;;;GAKG;AACH,SAAS,cAAc,CAAC,OAAe,EAAE,KAAa;IACpD,MAAM,MAAM,GAAG,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,GAAG,OAAO,IAAI,KAAK,EAAE,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;IAChF,OAAO,IAAI,CAAC,UAAU,EAAE,EAAE,eAAe,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE,oBAAoB,CAAC,CAAC,CAAC;AACrF,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,kBAAkB,CAAC,OAAe,EAAE,KAAa;IAC/D,MAAM,KAAK,GAAG,WAAW,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC;IAC1C,IAAI,KAAK,CAAC,MAAM,IAAI,0BAA0B;QAAE,OAAO,KAAK,CAAC;IAC7D,MAAM,QAAQ,GAAG,cAAc,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC;IAChD,IAAI,QAAQ,CAAC,MAAM,IAAI,0BAA0B;QAAE,OAAO,QAAQ,CAAC;IACnE,yEAAyE;IACzE,oEAAoE;IACpE,OAAO,QAAQ,CAAC,MAAM,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC;AAC3D,CAAC;AAED,kEAAkE;AAClE,MAAM,OAAO,GAAqC;IAChD,MAAM,EAAE,qBAAqB;IAC7B,MAAM,EAAE,yBAAyB;IACjC,MAAM,EAAE,mBAAmB;IAC3B,KAAK,EAAE,yBAAyB;IAChC,KAAK,EAAE,uBAAuB;CAC/B,CAAC;AAEF;;;;GAIG;AACH,MAAM,OAAO,iBAAkB,SAAQ,KAAK;IACjC,IAAI,CAAS;IAEtB,YAAY,IAAY,EAAE,MAAe;QACvC,MAAM,IAAI,GAAI,MAA4C,EAAE,IAAI,CAAC;QACjE,MAAM,GAAG,GAAG,CAAC,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;eAC9B,IAAI;eACJ,CAAC,MAAM,YAAY,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC;QACjE,KAAK,CACH,yCAAyC,IAAI,KAAK,GAAG,uBAAuB;cACxE,2DAA2D,CAChE,CAAC;QACF,IAAI,CAAC,IAAI,GAAG,mBAAmB,CAAC;QAChC,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;IACnB,CAAC;CACF;AAED;kFACkF;AAClF,MAAM,UAAU,kBAAkB,CAAC,GAAG,GAAsB,OAAO,CAAC,GAAG;IACrE,OAAO,GAAG,CAAC,gBAAgB,KAAK,GAAG,CAAC;AACtC,CAAC;AAED;8EAC8E;AAC9E,IAAI,QAAQ,GAAG,CAAC,CAAC;AAEjB;;;;;GAKG;AACH,SAAS,aAAa,CAAC,GAAW;IAChC,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,EAAE,kBAAkB,OAAO,CAAC,GAAG,IAAI,CAAC,QAAQ,IAAI,CAAC,CAAC,EAAE,CAAC,CAAC;IAC5E,IAAI,CAAC;QACH,aAAa,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC;IAC9B,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,MAAM,IAAI,iBAAiB,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;IACxC,CAAC;YAAS,CAAC;QACT,IAAI,CAAC;YACH,MAAM,CAAC,KAAK,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;QACjC,CAAC;QAAC,MAAM,CAAC;YACP,0EAA0E;QAC5E,CAAC;IACH,CAAC;AACH,CAAC;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,MAAM,UAAU,WAAW,CACzB,OAAe,EACf,KAAa,EACb,GAAG,GAAsB,OAAO,CAAC,GAAG;IAEpC,IAAI,CAAC,kBAAkB,CAAC,GAAG,CAAC;QAAE,OAAO,EAAE,CAAC;IACxC,MAAM,KAAK,GAAG,WAAW,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC;IAC1C,MAAM,GAAG,GAAG,kBAAkB,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC;IAC/C,IAAI,CAAC;QACH,SAAS,CAAC,GAAG,EAAE,GAAG,KAAK,KAAK,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;IACzF,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,MAAM,IAAI,iBAAiB,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;IACxC,CAAC;IACD,aAAa,CAAC,GAAG,CAAC,CAAC;IACnB,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,IAAI,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,CAAC;AAC9C,CAAC;AAED;;;;;;;;;GASG;AACH,MAAM,UAAU,iBAAiB,CAAC,OAAe,EAAE,KAAa;IAC9D,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC;QAAE,OAAO;IAC9B,KAAK,MAAM,GAAG,IAAI,CAAC,WAAW,CAAC,OAAO,EAAE,KAAK,CAAC,EAAE,cAAc,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC,EAAE,CAAC;QAChF,IAAI,CAAC;YACH,MAAM,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;QAChD,CAAC;QAAC,MAAM,CAAC;YACP,6DAA6D;QAC/D,CAAC;IACH,CAAC;AACH,CAAC;AAED;;;;;;;;;;;;GAYG;AACH,MAAM,UAAU,iBAAiB,CAAC,OAAe,EAAE,UAA4B;IAC7E,MAAM,IAAI,GAAG,IAAI,GAAG,CAAC,UAAU,CAAC,CAAC;IACjC,MAAM,MAAM,GAAa,EAAE,CAAC;IAC5B,IAAI,OAAiB,CAAC;IACtB,MAAM,IAAI,GAAG,YAAY,CAAC,OAAO,CAAC,CAAC;IACnC,IAAI,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC;QACrB,IAAI,CAAC;YACH,OAAO,GAAG,WAAW,CAAC,IAAI,EAAE,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC;iBACjD,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC;iBAC9B,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;QACxB,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,GAAG,EAAE,CAAC;QACf,CAAC;QACD,KAAK,MAAM,IAAI,IAAI,OAAO,EAAE,CAAC;YAC3B,IAAI,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC;gBAAE,SAAS;YACjD,IAAI,CAAC;gBACH,MAAM,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;gBAC3D,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YACpB,CAAC;YAAC,MAAM,CAAC;gBACP,+DAA+D;YACjE,CAAC;QACH,CAAC;IACH,CAAC;IACD,yEAAyE;IACzE,2EAA2E;IAC3E,mCAAmC;IACnC,MAAM,OAAO,GAAG,IAAI,GAAG,CACrB,CAAC,GAAG,IAAI,CAAC,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,GAAG,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,QAAQ,CAAC,cAAc,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,CAAC,CAC/E,CAAC;IACF,MAAM,MAAM,GAAG,UAAU,EAAE,CAAC;IAC5B,IAAI,eAAyB,CAAC;IAC9B,IAAI,CAAC;QACH,eAAe,GAAG,WAAW,CAAC,MAAM,EAAE,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC,CAAC;IACjE,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,MAAM,CAAC;IAChB,CAAC;IACD,KAAK,MAAM,KAAK,IAAI,eAAe,EAAE,CAAC;QACpC,IAAI,CAAC,KAAK,CAAC,WAAW,EAAE,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,UAAU,CAAC,eAAe,CAAC;YAAE,SAAS;QAC9E,IAAI,CAAC,gBAAgB,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,eAAe,CAAC,MAAM,CAAC,CAAC;YAAE,SAAS;QAC/E,IAAI,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC;YAAE,SAAS;QACtC,IAAI,CAAC;YACH,MAAM,CAAC,IAAI,CAAC,MAAM,EAAE,KAAK,CAAC,IAAI,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;YACnE,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QAC1B,CAAC;QAAC,MAAM,CAAC;YACP,+DAA+D;QACjE,CAAC;IACH,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@wjarka/cezarion",
|
|
3
|
-
"version": "0.14.2-
|
|
3
|
+
"version": "0.14.2-pr406.627",
|
|
4
4
|
"description": "Local cockpit for running and tracking AI agent tasks in your repo. Uses your logged-in `claude` CLI and `gh` — zero config, zero database.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -50,8 +50,8 @@
|
|
|
50
50
|
"zod": "^4.4.3"
|
|
51
51
|
},
|
|
52
52
|
"devDependencies": {
|
|
53
|
-
"@open-mercato/cezar-api-client": "0.14.2-
|
|
54
|
-
"@open-mercato/cezar-contract": "0.14.2-
|
|
53
|
+
"@open-mercato/cezar-api-client": "0.14.2-pr406.627",
|
|
54
|
+
"@open-mercato/cezar-contract": "0.14.2-pr406.627",
|
|
55
55
|
"@types/node": "^20.14.0",
|
|
56
56
|
"@types/ws": "^8.18.1",
|
|
57
57
|
"esbuild": "^0.28.1",
|