@claudexor/workspace 1.0.0
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/LICENSE +21 -0
- package/README.md +7 -0
- package/dist/artifact-paths.d.ts +40 -0
- package/dist/artifact-paths.d.ts.map +1 -0
- package/dist/artifact-paths.js +128 -0
- package/dist/artifact-paths.js.map +1 -0
- package/dist/git.d.ts +110 -0
- package/dist/git.d.ts.map +1 -0
- package/dist/git.js +376 -0
- package/dist/git.js.map +1 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +5 -0
- package/dist/index.js.map +1 -0
- package/dist/manager.d.ts +88 -0
- package/dist/manager.d.ts.map +1 -0
- package/dist/manager.js +398 -0
- package/dist/manager.js.map +1 -0
- package/dist/self-ignore.d.ts +10 -0
- package/dist/self-ignore.d.ts.map +1 -0
- package/dist/self-ignore.js +24 -0
- package/dist/self-ignore.js.map +1 -0
- package/dist/thread-tree.d.ts +20 -0
- package/dist/thread-tree.d.ts.map +1 -0
- package/dist/thread-tree.js +69 -0
- package/dist/thread-tree.js.map +1 -0
- package/package.json +42 -0
package/dist/manager.js
ADDED
|
@@ -0,0 +1,398 @@
|
|
|
1
|
+
import { execFileSync } from "node:child_process";
|
|
2
|
+
import { cpSync, existsSync, mkdtempSync, readdirSync, rmSync, writeFileSync } from "node:fs";
|
|
3
|
+
import { tmpdir } from "node:os";
|
|
4
|
+
import { join, sep } from "node:path";
|
|
5
|
+
import { WorkspaceEnvelope as WorkspaceEnvelopeSchema } from "@claudexor/schema";
|
|
6
|
+
import { runCaptureRaw, WorkspaceError } from "@claudexor/core";
|
|
7
|
+
import { ensureDir, newId, nowIso } from "@claudexor/util";
|
|
8
|
+
import { branchDelete, diffStaged, diffTrees, isGitRepo, revParse, snapshotTree, statusPorcelain, stashCreate, worktreeAdd, worktreePrune, worktreeRemove, } from "./git.js";
|
|
9
|
+
import { ensureSelfIgnore } from "./self-ignore.js";
|
|
10
|
+
/**
|
|
11
|
+
* Manages WorkspaceEnvelopes: an isolated git worktree plus scoped HOME and
|
|
12
|
+
* per-harness config dirs, and dirty-tree handling. Claudexor owns these
|
|
13
|
+
* envelopes (it does not rely on a harness's native --worktree).
|
|
14
|
+
*/
|
|
15
|
+
/** `ps` start time for a pid, or null when unavailable. Pid+start-time
|
|
16
|
+
* equality is the recycling-proof liveness identity for envelope owners
|
|
17
|
+
* (command names/titles mutate; the kernel start time never does). */
|
|
18
|
+
export function processStartTime(pid) {
|
|
19
|
+
try {
|
|
20
|
+
const out = execFileSync("ps", ["-p", String(pid), "-o", "lstart="], { encoding: "utf8" }).trim();
|
|
21
|
+
return out.length > 0 ? out : null;
|
|
22
|
+
}
|
|
23
|
+
catch {
|
|
24
|
+
return null;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
export class WorkspaceManager {
|
|
28
|
+
repoRoot;
|
|
29
|
+
constructor(repoRoot) {
|
|
30
|
+
this.repoRoot = repoRoot;
|
|
31
|
+
}
|
|
32
|
+
workspacesDir() {
|
|
33
|
+
return join(this.repoRoot, ".claudexor", "workspaces");
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* The scoped envelope base for a task/attempt. The sole on-disk root we
|
|
37
|
+
* delete on dispose — so the ids MUST be path-safe segments and the resolved
|
|
38
|
+
* base MUST stay inside the workspaces dir (a crafted `../` id could
|
|
39
|
+
* otherwise turn dispose() into an arbitrary recursive delete).
|
|
40
|
+
*/
|
|
41
|
+
envelopeBase(taskId, attemptId) {
|
|
42
|
+
const idPattern = /^[A-Za-z0-9._-]+$/;
|
|
43
|
+
for (const [label, id] of [["taskId", taskId], ["attemptId", attemptId]]) {
|
|
44
|
+
if (!idPattern.test(id) || id === "." || id === "..") {
|
|
45
|
+
throw new WorkspaceError(`${label} '${id}' is not a safe path segment`);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
const base = join(this.workspacesDir(), taskId, attemptId);
|
|
49
|
+
if (!base.startsWith(this.workspacesDir() + sep)) {
|
|
50
|
+
throw new WorkspaceError(`envelope base escapes the workspaces dir: ${base}`);
|
|
51
|
+
}
|
|
52
|
+
return base;
|
|
53
|
+
}
|
|
54
|
+
async create(opts) {
|
|
55
|
+
// Envelope base holds scoped dirs (HOME + per-harness config) and, for git
|
|
56
|
+
// mode, the worktree as a subdir — so harness-written HOME state (auth tokens,
|
|
57
|
+
// caches, plugins, session logs) lives outside the work tree and never lands
|
|
58
|
+
// in a diff.
|
|
59
|
+
const base = this.envelopeBase(opts.taskId, opts.attemptId);
|
|
60
|
+
ensureDir(base);
|
|
61
|
+
// Self-ignoring runtime dir: a `.gitignore` with `*` INSIDE .claudexor makes
|
|
62
|
+
// the whole dir invisible to git in PRE-EXISTING repos too (v0.9 widened the
|
|
63
|
+
// seeded credentials from API keys to subscription OAuth copies; a user's
|
|
64
|
+
// `git add -A` in their own repo must never capture them). Content-checked
|
|
65
|
+
// repair lives in the shared ensureSelfIgnore owner.
|
|
66
|
+
ensureSelfIgnore(join(this.repoRoot, ".claudexor"));
|
|
67
|
+
const homeDir = join(base, "home");
|
|
68
|
+
const codexHome = join(homeDir, ".codex");
|
|
69
|
+
const claudeConfig = join(homeDir, ".claude");
|
|
70
|
+
const cursorConfig = join(homeDir, ".cursor");
|
|
71
|
+
const opencodeConfig = join(homeDir, ".config", "opencode");
|
|
72
|
+
for (const d of [homeDir, codexHome, claudeConfig, cursorConfig, opencodeConfig]) {
|
|
73
|
+
ensureDir(d);
|
|
74
|
+
}
|
|
75
|
+
const harnessConfigDirs = {
|
|
76
|
+
codex_home: codexHome,
|
|
77
|
+
claude_config: claudeConfig,
|
|
78
|
+
cursor_config: cursorConfig,
|
|
79
|
+
opencode_config: opencodeConfig,
|
|
80
|
+
};
|
|
81
|
+
// Liveness marker for crash GC: the sweeper must never dispose an envelope
|
|
82
|
+
// whose creating process (daemon, CLI, MCP/ACP serve) is still alive —
|
|
83
|
+
// startup GC's "nothing can own an envelope" premise only holds for
|
|
84
|
+
// daemon-tracked runs. Pid + ps START TIME form a recycling-proof identity
|
|
85
|
+
// (command names/titles mutate — vitest, daemons and tools retitle
|
|
86
|
+
// themselves; the kernel start time never does).
|
|
87
|
+
writeFileSync(join(base, "owner.json"), JSON.stringify({ pid: process.pid, started: processStartTime(process.pid), created_at: nowIso() }) + "\n");
|
|
88
|
+
// In-place mode: mutate the live repoRoot directly (no isolated worktree).
|
|
89
|
+
// Used for thread turns (chat-first: the next turn sees this one's work) and
|
|
90
|
+
// for stateful external environments where runtime state is the deliverable.
|
|
91
|
+
// For a git project we record a per-turn snapshot sha so diff() captures only
|
|
92
|
+
// THIS turn's net change; a non-git folder falls back to a cpSync baseline.
|
|
93
|
+
if (opts.inPlace) {
|
|
94
|
+
const gitRepo = await isGitRepo(this.repoRoot);
|
|
95
|
+
const baseSha = gitRepo ? await snapshotTree(this.repoRoot) : null;
|
|
96
|
+
if (!gitRepo)
|
|
97
|
+
this.snapshotBaseline(base);
|
|
98
|
+
return WorkspaceEnvelopeSchema.parse({
|
|
99
|
+
id: newId("env"),
|
|
100
|
+
task_id: opts.taskId,
|
|
101
|
+
attempt_id: opts.attemptId,
|
|
102
|
+
repo_root: this.repoRoot,
|
|
103
|
+
base_ref: opts.baseRef ?? "HEAD",
|
|
104
|
+
base_sha: baseSha,
|
|
105
|
+
worktree_path: this.repoRoot,
|
|
106
|
+
branch_name: "inplace",
|
|
107
|
+
home_dir: homeDir,
|
|
108
|
+
harness_config_dirs: harnessConfigDirs,
|
|
109
|
+
policy_profile: opts.accessProfile ?? "workspace_write",
|
|
110
|
+
// Record the EFFECTIVE policy, not the ignored request: in-place runs
|
|
111
|
+
// always fold dirty state into the per-turn base snapshot above.
|
|
112
|
+
dirty_policy: "snapshot",
|
|
113
|
+
created_at: nowIso(),
|
|
114
|
+
});
|
|
115
|
+
}
|
|
116
|
+
if (!(await isGitRepo(this.repoRoot))) {
|
|
117
|
+
throw new WorkspaceError(`not a git repository: ${this.repoRoot}`);
|
|
118
|
+
}
|
|
119
|
+
const baseRef = opts.baseRef ?? "HEAD";
|
|
120
|
+
const dirtyPolicy = opts.dirtyPolicy ?? "refuse";
|
|
121
|
+
let baseSha = await revParse(this.repoRoot, baseRef);
|
|
122
|
+
const porcelain = await statusPorcelain(this.repoRoot);
|
|
123
|
+
const dirty = porcelain.trim().length > 0;
|
|
124
|
+
if (dirty) {
|
|
125
|
+
if (dirtyPolicy === "refuse") {
|
|
126
|
+
throw new WorkspaceError("working tree is dirty; commit/stash or set dirty_policy: snapshot");
|
|
127
|
+
}
|
|
128
|
+
// snapshot: a stash-create commit becomes the base SHA without touching
|
|
129
|
+
// the live tree. (The include/stash aliases and the untested `copy`
|
|
130
|
+
// variant were retired in the v0.15 triage.)
|
|
131
|
+
const snap = await stashCreate(this.repoRoot);
|
|
132
|
+
if (snap)
|
|
133
|
+
baseSha = snap;
|
|
134
|
+
}
|
|
135
|
+
const path = join(base, "tree");
|
|
136
|
+
const branch = `claudexor/${opts.taskId}/${opts.attemptId}`;
|
|
137
|
+
await worktreeAdd(this.repoRoot, path, branch, baseSha);
|
|
138
|
+
return WorkspaceEnvelopeSchema.parse({
|
|
139
|
+
id: newId("env"),
|
|
140
|
+
task_id: opts.taskId,
|
|
141
|
+
attempt_id: opts.attemptId,
|
|
142
|
+
repo_root: this.repoRoot,
|
|
143
|
+
base_ref: baseRef,
|
|
144
|
+
base_sha: baseSha,
|
|
145
|
+
worktree_path: path,
|
|
146
|
+
branch_name: branch,
|
|
147
|
+
home_dir: homeDir,
|
|
148
|
+
harness_config_dirs: harnessConfigDirs,
|
|
149
|
+
policy_profile: opts.accessProfile ?? "workspace_write",
|
|
150
|
+
dirty_policy: dirtyPolicy,
|
|
151
|
+
created_at: nowIso(),
|
|
152
|
+
});
|
|
153
|
+
}
|
|
154
|
+
/**
|
|
155
|
+
* Best-effort baseline copy of the live tree for in-place diff(). Copies each
|
|
156
|
+
* top-level entry individually (skipping heavy/ephemeral dirs, notably `.claudexor`
|
|
157
|
+
* which holds this base) — this both prunes noise and avoids Node's "cannot copy
|
|
158
|
+
* a directory into its own subdirectory" guard, since the baseline lives under
|
|
159
|
+
* `.claudexor`. On any failure the baseline is simply absent and diff() returns
|
|
160
|
+
* empty; reviewers still read the live tree directly.
|
|
161
|
+
*/
|
|
162
|
+
snapshotBaseline(base) {
|
|
163
|
+
const baseline = join(base, "baseline");
|
|
164
|
+
const skip = new Set([".git", ".claudexor", "node_modules", "__pycache__", ".venv", "venv"]);
|
|
165
|
+
try {
|
|
166
|
+
ensureDir(baseline);
|
|
167
|
+
for (const entry of readdirSync(this.repoRoot)) {
|
|
168
|
+
if (skip.has(entry))
|
|
169
|
+
continue;
|
|
170
|
+
cpSync(join(this.repoRoot, entry), join(baseline, entry), { recursive: true });
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
catch {
|
|
174
|
+
/* baseline unavailable -> diff() falls back to empty */
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
/** Env vars that scope a child harness to this envelope (HOME + per-harness config dirs). */
|
|
178
|
+
envFor(env) {
|
|
179
|
+
return {
|
|
180
|
+
HOME: env.home_dir,
|
|
181
|
+
CODEX_HOME: env.harness_config_dirs["codex_home"] ?? join(env.home_dir, ".codex"),
|
|
182
|
+
CLAUDE_CONFIG_DIR: env.harness_config_dirs["claude_config"] ?? join(env.home_dir, ".claude"),
|
|
183
|
+
// Pin XDG_CONFIG_HOME to the scoped home so an XDG-aware harness
|
|
184
|
+
// (opencode/cursor) cannot follow an INHERITED XDG_CONFIG_HOME back into the
|
|
185
|
+
// operator's real ~/.config under `mirror_native` (§6 containment).
|
|
186
|
+
XDG_CONFIG_HOME: join(env.home_dir, ".config"),
|
|
187
|
+
};
|
|
188
|
+
}
|
|
189
|
+
/**
|
|
190
|
+
* Provision a SCOPED, worktree-less harness HOME for READ-ONLY routes (plan,
|
|
191
|
+
* ask, audit, orchestrate, reviewers). Read-only modes build no git worktree,
|
|
192
|
+
* but a harness still writes native state — claude-code plan files, codex
|
|
193
|
+
* session rollouts, transcripts — into `$HOME/.claude`, `$CODEX_HOME`, etc.
|
|
194
|
+
* Without this, those land in the operator's REAL home (a live-caught leak: a
|
|
195
|
+
* read-only `plan` wrote into `~/.claude/plans`). Same env shape as `envFor`,
|
|
196
|
+
* so the adapters seed auth (subscription creds / api key) into these scoped
|
|
197
|
+
* dirs exactly as they do for a write envelope (CLAUDEXOR_BIBLE §6). Caller
|
|
198
|
+
* disposes when the run ends.
|
|
199
|
+
*/
|
|
200
|
+
readOnlyHomeEnv() {
|
|
201
|
+
// A throwaway temp base — never under the project / synthetic repo root, so a
|
|
202
|
+
// no-project Ask leaves nothing in its cwd (§7) and nothing in any worktree (§6).
|
|
203
|
+
const base = mkdtempSync(join(tmpdir(), "claudexor-ro-"));
|
|
204
|
+
const homeDir = join(base, "home");
|
|
205
|
+
const codexHome = join(homeDir, ".codex");
|
|
206
|
+
const claudeConfig = join(homeDir, ".claude");
|
|
207
|
+
const cursorConfig = join(homeDir, ".cursor");
|
|
208
|
+
const opencodeConfig = join(homeDir, ".config", "opencode");
|
|
209
|
+
for (const d of [homeDir, codexHome, claudeConfig, cursorConfig, opencodeConfig])
|
|
210
|
+
ensureDir(d);
|
|
211
|
+
return {
|
|
212
|
+
env: { HOME: homeDir, CODEX_HOME: codexHome, CLAUDE_CONFIG_DIR: claudeConfig, XDG_CONFIG_HOME: join(homeDir, ".config") },
|
|
213
|
+
dispose: () => {
|
|
214
|
+
try {
|
|
215
|
+
rmSync(base, { recursive: true, force: true });
|
|
216
|
+
}
|
|
217
|
+
catch {
|
|
218
|
+
/* best-effort: a leftover scoped home is harmless and gc-able */
|
|
219
|
+
}
|
|
220
|
+
},
|
|
221
|
+
};
|
|
222
|
+
}
|
|
223
|
+
/**
|
|
224
|
+
* Header-only rewrite of a plain GNU `diff -ruN <baseline> <live>` document:
|
|
225
|
+
* absolute baseline/live prefixes become git-style `a/<rel>` / `b/<rel>` so
|
|
226
|
+
* repo-relative protected-path and risk globs see the SAME shape they see
|
|
227
|
+
* for git diffs. STATEFUL, mirroring the shared plain-diff parser's
|
|
228
|
+
* structural rules: only the GNU `diff …` command echo, the `--- `/`+++ `
|
|
229
|
+
* pair of a real file-header triple (`--- ` + `+++ ` + `@@` on consecutive
|
|
230
|
+
* lines), and structural `Binary files … differ` lines are rewritten.
|
|
231
|
+
* Hunk CONTENT is never touched — a removed/added content line that merely
|
|
232
|
+
* starts with `-- `/`++ ` (rendering as `--- `/`+++ ` in the diff) keeps
|
|
233
|
+
* its bytes, per the diff-fidelity contract (INV-041).
|
|
234
|
+
*/
|
|
235
|
+
static relativizePlainDiffHeadersFor(text, baselineRoot, liveRoot) {
|
|
236
|
+
const base = baselineRoot.endsWith("/") ? baselineRoot : `${baselineRoot}/`;
|
|
237
|
+
const live = liveRoot.endsWith("/") ? liveRoot : `${liveRoot}/`;
|
|
238
|
+
const swap = (s) => s.split(base).join("a/").split(live).join("b/");
|
|
239
|
+
const lines = text.split("\n");
|
|
240
|
+
// Same structural rule as the shared plain-diff parser: INSIDE a hunk the
|
|
241
|
+
// loose triple can be forged by content (a deleted `-- …` line + an added
|
|
242
|
+
// `++ …` line + the next `@@`), so a mid-hunk boundary must also carry a
|
|
243
|
+
// header witness — the GNU tab-separated timestamp (or /dev/null) on both
|
|
244
|
+
// path lines, which +/- content lines never have.
|
|
245
|
+
const headerWitness = (l) => l !== undefined && (l.includes("\t") || l.slice(4).trim() === "/dev/null");
|
|
246
|
+
const isFileHeaderTriple = (idx, midHunk) => {
|
|
247
|
+
const triple = (lines[idx]?.startsWith("--- ") ?? false) &&
|
|
248
|
+
(lines[idx + 1]?.startsWith("+++ ") ?? false) &&
|
|
249
|
+
(lines[idx + 2]?.startsWith("@@") ?? false);
|
|
250
|
+
if (!triple)
|
|
251
|
+
return false;
|
|
252
|
+
return midHunk ? headerWitness(lines[idx]) && headerWitness(lines[idx + 1]) : true;
|
|
253
|
+
};
|
|
254
|
+
let inHunk = false;
|
|
255
|
+
for (let i = 0; i < lines.length; i += 1) {
|
|
256
|
+
const line = lines[i];
|
|
257
|
+
if (line.startsWith("diff ")) {
|
|
258
|
+
// GNU command echo between files: structural, resets hunk state.
|
|
259
|
+
inHunk = false;
|
|
260
|
+
lines[i] = swap(line);
|
|
261
|
+
continue;
|
|
262
|
+
}
|
|
263
|
+
if (isFileHeaderTriple(i, inHunk)) {
|
|
264
|
+
// Real file boundary — same rule as the shared parser (a full triple
|
|
265
|
+
// opens a file even mid-document without a `diff` echo).
|
|
266
|
+
lines[i] = swap(line);
|
|
267
|
+
lines[i + 1] = swap(lines[i + 1]);
|
|
268
|
+
inHunk = false;
|
|
269
|
+
i += 1; // the `+++ ` line is handled; `@@` flips state next.
|
|
270
|
+
continue;
|
|
271
|
+
}
|
|
272
|
+
if (line.startsWith("@@")) {
|
|
273
|
+
inHunk = true;
|
|
274
|
+
continue;
|
|
275
|
+
}
|
|
276
|
+
if (line.startsWith("Binary files ") && line.endsWith(" differ") && !inHunk) {
|
|
277
|
+
lines[i] = swap(line);
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
return lines.join("\n");
|
|
281
|
+
}
|
|
282
|
+
async diff(env) {
|
|
283
|
+
// In-place: there is no isolated worktree. For a git project, diff the
|
|
284
|
+
// per-turn base snapshot against a fresh end snapshot — net change of THIS
|
|
285
|
+
// turn only, untracked included, prior dirty state folded into base.
|
|
286
|
+
if (env.worktree_path === env.repo_root) {
|
|
287
|
+
if (env.base_sha) {
|
|
288
|
+
const end = await snapshotTree(env.repo_root);
|
|
289
|
+
return diffTrees(env.repo_root, env.base_sha, end);
|
|
290
|
+
}
|
|
291
|
+
// Non-git fallback: diff the best-effort cpSync baseline against the live
|
|
292
|
+
// tree; if no baseline was captured, return empty (reviewers read the tree).
|
|
293
|
+
const baseline = join(this.envelopeBase(env.task_id, env.attempt_id), "baseline");
|
|
294
|
+
if (!existsSync(baseline))
|
|
295
|
+
return "";
|
|
296
|
+
try {
|
|
297
|
+
const r = await runCaptureRaw("diff", ["-ruN", "-x", ".git", "-x", ".claudexor", "-x", ".claudexor-review-evidence", "-x", "node_modules", "-x", "__pycache__", "-x", ".venv", "-x", "venv", baseline, env.repo_root], { timeoutMs: 120_000 });
|
|
298
|
+
// Relativize the header paths to the git-style a/<rel> b/<rel> shape.
|
|
299
|
+
// Downstream consumers (diffstat, protected-path/risk gating) match
|
|
300
|
+
// REPO-RELATIVE globs like `test/**`; absolute `/…/repo/test/x`
|
|
301
|
+
// headers would silently bypass every one of them.
|
|
302
|
+
const relativized = WorkspaceManager.relativizePlainDiffHeadersFor(r.stdout, baseline, env.repo_root);
|
|
303
|
+
const CAP = 200_000;
|
|
304
|
+
return relativized.length > CAP ? relativized.slice(0, CAP) + "\n... [diff truncated]\n" : relativized;
|
|
305
|
+
}
|
|
306
|
+
catch {
|
|
307
|
+
// best-effort: if `diff` is unavailable the loop still works (reviewers read the live tree)
|
|
308
|
+
return "";
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
return diffStaged(env.worktree_path, env.base_sha ?? undefined);
|
|
312
|
+
}
|
|
313
|
+
async dispose(env) {
|
|
314
|
+
// In-place envelopes point worktree_path at the live repo root; NEVER remove a
|
|
315
|
+
// worktree or the tree itself in that case.
|
|
316
|
+
const inPlace = env.worktree_path === env.repo_root;
|
|
317
|
+
if (!inPlace) {
|
|
318
|
+
try {
|
|
319
|
+
await worktreeRemove(this.repoRoot, env.worktree_path);
|
|
320
|
+
}
|
|
321
|
+
catch {
|
|
322
|
+
/* best-effort */
|
|
323
|
+
}
|
|
324
|
+
// Delete the per-attempt branch so re-attempts with the same ids don't
|
|
325
|
+
// collide on `worktree add -b`, and the user's repo doesn't accumulate
|
|
326
|
+
// permanent claudexor/<task>/<attempt> branches (the v0.8 leak).
|
|
327
|
+
if (env.branch_name && env.branch_name !== "inplace") {
|
|
328
|
+
try {
|
|
329
|
+
await branchDelete(this.repoRoot, env.branch_name);
|
|
330
|
+
}
|
|
331
|
+
catch {
|
|
332
|
+
/* best-effort */
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
// Remove only the scoped envelope base (worktree + scoped home/env/logs/artifacts/
|
|
337
|
+
// baseline, including any seeded credentials), derived from task/attempt ids.
|
|
338
|
+
// For git mode this equals dirname(worktree_path); for in-place it is a sibling
|
|
339
|
+
// under `.claudexor/workspaces`, so deriving from ids is exactly what prevents
|
|
340
|
+
// dispose() from ever deleting the live tree.
|
|
341
|
+
try {
|
|
342
|
+
rmSync(this.envelopeBase(env.task_id, env.attempt_id), { recursive: true, force: true });
|
|
343
|
+
}
|
|
344
|
+
catch {
|
|
345
|
+
/* best-effort */
|
|
346
|
+
}
|
|
347
|
+
// Prune the now-empty per-task parent dir (envelopeBase = <task>/<attempt>),
|
|
348
|
+
// guarded to stay strictly inside the workspaces dir.
|
|
349
|
+
try {
|
|
350
|
+
const taskDir = join(this.workspacesDir(), env.task_id);
|
|
351
|
+
if (taskDir.startsWith(this.workspacesDir() + sep) &&
|
|
352
|
+
existsSync(taskDir) &&
|
|
353
|
+
readdirSync(taskDir).length === 0) {
|
|
354
|
+
rmSync(taskDir, { recursive: true, force: true });
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
catch {
|
|
358
|
+
/* best-effort */
|
|
359
|
+
}
|
|
360
|
+
try {
|
|
361
|
+
await worktreePrune(this.repoRoot);
|
|
362
|
+
}
|
|
363
|
+
catch {
|
|
364
|
+
/* best-effort (repo may not be git in in-place mode) */
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
/**
|
|
368
|
+
* Dispose an ORPHANED envelope by ids alone (crash GC): a daemon
|
|
369
|
+
* crash leaves envelopes with no live job. Reconstructs the disposal
|
|
370
|
+
* surface (worktree path, branch name, envelope base) from the same id
|
|
371
|
+
* derivation create() used, so the safety invariants (id-validated base,
|
|
372
|
+
* never the live tree) hold without a persisted envelope record.
|
|
373
|
+
*/
|
|
374
|
+
async disposeOrphan(taskId, attemptId) {
|
|
375
|
+
const base = this.envelopeBase(taskId, attemptId);
|
|
376
|
+
await this.dispose(WorkspaceEnvelopeSchema.parse({
|
|
377
|
+
id: newId("env"),
|
|
378
|
+
task_id: taskId,
|
|
379
|
+
attempt_id: attemptId,
|
|
380
|
+
repo_root: this.repoRoot,
|
|
381
|
+
base_ref: "HEAD",
|
|
382
|
+
base_sha: "0000000000000000000000000000000000000000",
|
|
383
|
+
worktree_path: join(base, "tree"),
|
|
384
|
+
branch_name: `claudexor/${taskId}/${attemptId}`,
|
|
385
|
+
home_dir: join(base, "home"),
|
|
386
|
+
harness_config_dirs: {
|
|
387
|
+
codex_home: join(base, "home", ".codex"),
|
|
388
|
+
claude_config: join(base, "home", ".claude"),
|
|
389
|
+
cursor_config: join(base, "home", ".cursor"),
|
|
390
|
+
opencode_config: join(base, "home", ".config", "opencode"),
|
|
391
|
+
},
|
|
392
|
+
policy_profile: "workspace_write",
|
|
393
|
+
dirty_policy: "snapshot",
|
|
394
|
+
created_at: nowIso(),
|
|
395
|
+
}));
|
|
396
|
+
}
|
|
397
|
+
}
|
|
398
|
+
//# sourceMappingURL=manager.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"manager.js","sourceRoot":"","sources":["../src/manager.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Ensure `.claudexor/.gitignore` CONTAINS `*` so the runtime dir stays
|
|
3
|
+
* invisible to the project's git (the git-native trick that avoids mutating
|
|
4
|
+
* the user's own .gitignore). Content-checked, not just existence-checked:
|
|
5
|
+
* a user-edited or emptied file would silently re-expose envelopes, thread
|
|
6
|
+
* worktrees, and seeded credentials to `git add -A`. Shared by the envelope
|
|
7
|
+
* manager and the thread-worktree creator (single owner of the invariant).
|
|
8
|
+
*/
|
|
9
|
+
export declare function ensureSelfIgnore(claudexorDir: string): void;
|
|
10
|
+
//# sourceMappingURL=self-ignore.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"self-ignore.d.ts","sourceRoot":"","sources":["../src/self-ignore.ts"],"names":[],"mappings":"AAIA;;;;;;;GAOG;AACH,wBAAgB,gBAAgB,CAAC,YAAY,EAAE,MAAM,GAAG,IAAI,CAS3D"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { readFileSync, writeFileSync } from "node:fs";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
import { ensureDir } from "@claudexor/util";
|
|
4
|
+
/**
|
|
5
|
+
* Ensure `.claudexor/.gitignore` CONTAINS `*` so the runtime dir stays
|
|
6
|
+
* invisible to the project's git (the git-native trick that avoids mutating
|
|
7
|
+
* the user's own .gitignore). Content-checked, not just existence-checked:
|
|
8
|
+
* a user-edited or emptied file would silently re-expose envelopes, thread
|
|
9
|
+
* worktrees, and seeded credentials to `git add -A`. Shared by the envelope
|
|
10
|
+
* manager and the thread-worktree creator (single owner of the invariant).
|
|
11
|
+
*/
|
|
12
|
+
export function ensureSelfIgnore(claudexorDir) {
|
|
13
|
+
const path = join(claudexorDir, ".gitignore");
|
|
14
|
+
try {
|
|
15
|
+
if (readFileSync(path, "utf8").trim() === "*")
|
|
16
|
+
return;
|
|
17
|
+
}
|
|
18
|
+
catch {
|
|
19
|
+
/* missing/unreadable -> (re)write below */
|
|
20
|
+
}
|
|
21
|
+
ensureDir(claudexorDir);
|
|
22
|
+
writeFileSync(path, "*\n");
|
|
23
|
+
}
|
|
24
|
+
//# sourceMappingURL=self-ignore.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"self-ignore.js","sourceRoot":"","sources":["../src/self-ignore.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AACtD,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAE5C;;;;;;;GAOG;AACH,MAAM,UAAU,gBAAgB,CAAC,YAAoB;IACnD,MAAM,IAAI,GAAG,IAAI,CAAC,YAAY,EAAE,YAAY,CAAC,CAAC;IAC9C,IAAI,CAAC;QACH,IAAI,YAAY,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC,IAAI,EAAE,KAAK,GAAG;YAAE,OAAO;IACxD,CAAC;IAAC,MAAM,CAAC;QACP,2CAA2C;IAC7C,CAAC;IACD,SAAS,CAAC,YAAY,CAAC,CAAC;IACxB,aAAa,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;AAC7B,CAAC"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
export interface ThreadWorktreeResult {
|
|
2
|
+
/** Absolute path to the thread's persistent worktree (the execution root). */
|
|
3
|
+
path: string;
|
|
4
|
+
/** Snapshot sha the worktree was branched from (the apply base). */
|
|
5
|
+
baseSha: string;
|
|
6
|
+
/** True when the worktree was just created (vs reused). */
|
|
7
|
+
created: boolean;
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Lazily create (or reuse) the persistent git worktree backing an ISOLATED
|
|
11
|
+
* thread. Turns run in-place WITHIN this worktree so each sees the previous
|
|
12
|
+
* one's work; `apply` later diffs the worktree against `baseSha` and delivers
|
|
13
|
+
* the cumulative patch to the project. Race candidates still branch off the
|
|
14
|
+
* worktree's current state into throwaway envelopes.
|
|
15
|
+
*
|
|
16
|
+
* The worktree lives under the project's self-ignored `.claudexor/`, so the
|
|
17
|
+
* project's own git never sees it and snapshots exclude it.
|
|
18
|
+
*/
|
|
19
|
+
export declare function ensureThreadWorktree(projectRoot: string, threadId: string): Promise<ThreadWorktreeResult>;
|
|
20
|
+
//# sourceMappingURL=thread-tree.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"thread-tree.d.ts","sourceRoot":"","sources":["../src/thread-tree.ts"],"names":[],"mappings":"AAOA,MAAM,WAAW,oBAAoB;IACnC,8EAA8E;IAC9E,IAAI,EAAE,MAAM,CAAC;IACb,oEAAoE;IACpE,OAAO,EAAE,MAAM,CAAC;IAChB,2DAA2D;IAC3D,OAAO,EAAE,OAAO,CAAC;CAClB;AAED;;;;;;;;;GASG;AACH,wBAAsB,oBAAoB,CAAC,WAAW,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,oBAAoB,CAAC,CAiD/G"}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { existsSync, rmSync } from "node:fs";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
import { WorkspaceError } from "@claudexor/core";
|
|
4
|
+
import { ensureDir } from "@claudexor/util";
|
|
5
|
+
import { branchDelete, isGitRepo, revParse, snapshotTree, worktreeAdd, worktreeAddExisting } from "./git.js";
|
|
6
|
+
import { ensureSelfIgnore } from "./self-ignore.js";
|
|
7
|
+
/**
|
|
8
|
+
* Lazily create (or reuse) the persistent git worktree backing an ISOLATED
|
|
9
|
+
* thread. Turns run in-place WITHIN this worktree so each sees the previous
|
|
10
|
+
* one's work; `apply` later diffs the worktree against `baseSha` and delivers
|
|
11
|
+
* the cumulative patch to the project. Race candidates still branch off the
|
|
12
|
+
* worktree's current state into throwaway envelopes.
|
|
13
|
+
*
|
|
14
|
+
* The worktree lives under the project's self-ignored `.claudexor/`, so the
|
|
15
|
+
* project's own git never sees it and snapshots exclude it.
|
|
16
|
+
*/
|
|
17
|
+
export async function ensureThreadWorktree(projectRoot, threadId) {
|
|
18
|
+
if (!/^[A-Za-z0-9._-]+$/.test(threadId) || threadId === "." || threadId === "..") {
|
|
19
|
+
throw new WorkspaceError(`threadId '${threadId}' is not a safe path segment`);
|
|
20
|
+
}
|
|
21
|
+
if (!(await isGitRepo(projectRoot))) {
|
|
22
|
+
throw new WorkspaceError(`isolated threads require a git project: ${projectRoot}`);
|
|
23
|
+
}
|
|
24
|
+
const path = join(projectRoot, ".claudexor", "threads", threadId, "tree");
|
|
25
|
+
if (existsSync(join(path, ".git"))) {
|
|
26
|
+
// Turns never commit on the branch (in-place envelopes leave changes in the
|
|
27
|
+
// working tree), so HEAD still points at the original base snapshot.
|
|
28
|
+
return { path, baseSha: await revParse(path, "HEAD"), created: false };
|
|
29
|
+
}
|
|
30
|
+
const baseSha = await snapshotTree(projectRoot);
|
|
31
|
+
const threadDir = join(projectRoot, ".claudexor", "threads", threadId);
|
|
32
|
+
ensureDir(threadDir);
|
|
33
|
+
// Self-ignore the project's `.claudexor/` so the user's own `git add -A` never
|
|
34
|
+
// captures the thread worktree (shared content-checked owner with
|
|
35
|
+
// WorkspaceManager: a user-edited/emptied file is repaired, not trusted).
|
|
36
|
+
ensureSelfIgnore(join(projectRoot, ".claudexor"));
|
|
37
|
+
const branch = `claudexor/thread-${threadId}`;
|
|
38
|
+
// Thread branches are PERSISTENT live-thread state. When the branch
|
|
39
|
+
// survives but the worktree directory was lost, RECOVER by recreating the
|
|
40
|
+
// worktree FROM the branch (its tip is the thread's base — turns never
|
|
41
|
+
// commit on it) instead of failing `worktree add -b` on the collision.
|
|
42
|
+
const branchExisted = await revParse(projectRoot, branch)
|
|
43
|
+
.then(() => true)
|
|
44
|
+
.catch(() => false);
|
|
45
|
+
if (branchExisted) {
|
|
46
|
+
try {
|
|
47
|
+
await worktreeAddExisting(projectRoot, path, branch);
|
|
48
|
+
}
|
|
49
|
+
catch (err) {
|
|
50
|
+
rmSync(threadDir, { recursive: true, force: true });
|
|
51
|
+
throw err; // never delete the surviving branch
|
|
52
|
+
}
|
|
53
|
+
return { path, baseSha: await revParse(path, "HEAD"), created: true };
|
|
54
|
+
}
|
|
55
|
+
try {
|
|
56
|
+
await worktreeAdd(projectRoot, path, branch, baseSha);
|
|
57
|
+
}
|
|
58
|
+
catch (err) {
|
|
59
|
+
// A failed worktree add must not leave a partial thread dir (whose `.git`
|
|
60
|
+
// check above would then be false forever) or a stale OWN branch behind
|
|
61
|
+
// (this call created the branch attempt; a surviving branch is handled
|
|
62
|
+
// by the recovery path above and never deleted here).
|
|
63
|
+
rmSync(threadDir, { recursive: true, force: true });
|
|
64
|
+
await branchDelete(projectRoot, branch).catch(() => { });
|
|
65
|
+
throw err;
|
|
66
|
+
}
|
|
67
|
+
return { path, baseSha, created: true };
|
|
68
|
+
}
|
|
69
|
+
//# sourceMappingURL=thread-tree.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"thread-tree.js","sourceRoot":"","sources":["../src/thread-tree.ts"],"names":[],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@claudexor/workspace",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"license": "MIT",
|
|
5
|
+
"description": "WorkspaceEnvelope manager: git worktree + scoped HOME/harness-config isolation + dirty policy.",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"main": "./dist/index.js",
|
|
8
|
+
"types": "./dist/index.d.ts",
|
|
9
|
+
"exports": {
|
|
10
|
+
".": {
|
|
11
|
+
"types": "./dist/index.d.ts",
|
|
12
|
+
"default": "./dist/index.js"
|
|
13
|
+
}
|
|
14
|
+
},
|
|
15
|
+
"files": [
|
|
16
|
+
"dist"
|
|
17
|
+
],
|
|
18
|
+
"dependencies": {
|
|
19
|
+
"@claudexor/core": "1.0.0",
|
|
20
|
+
"@claudexor/schema": "1.0.0",
|
|
21
|
+
"@claudexor/util": "1.0.0"
|
|
22
|
+
},
|
|
23
|
+
"repository": {
|
|
24
|
+
"type": "git",
|
|
25
|
+
"url": "git+https://github.com/razzant/claudexor.git",
|
|
26
|
+
"directory": "packages/workspace"
|
|
27
|
+
},
|
|
28
|
+
"homepage": "https://github.com/razzant/claudexor#readme",
|
|
29
|
+
"bugs": {
|
|
30
|
+
"url": "https://github.com/razzant/claudexor/issues"
|
|
31
|
+
},
|
|
32
|
+
"engines": {
|
|
33
|
+
"node": ">=20.19"
|
|
34
|
+
},
|
|
35
|
+
"publishConfig": {
|
|
36
|
+
"access": "public"
|
|
37
|
+
},
|
|
38
|
+
"scripts": {
|
|
39
|
+
"build": "tsc",
|
|
40
|
+
"typecheck": "tsc --noEmit"
|
|
41
|
+
}
|
|
42
|
+
}
|