@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/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 joi-lab
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
# @claudexor/workspace
|
|
2
|
+
|
|
3
|
+
Internal package of [Claudexor](https://github.com/razzant/claudexor) — WorkspaceEnvelope manager: git worktree + scoped HOME/harness-config isolation + dirty policy.
|
|
4
|
+
|
|
5
|
+
Published as part of the Claudexor toolchain; it follows the monorepo's
|
|
6
|
+
lockstep version and has no separate semver contract. Use the `claudexor`
|
|
7
|
+
CLI (or `@claudexor/cli`) as the supported entry point.
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
export declare const CLAUDEXOR_ARTIFACT_DIRS: readonly [".claudexor", ".claudexor-review-evidence"];
|
|
2
|
+
/** True when the RELATIVE path is inside one of Claudexor's artifact dirs. */
|
|
3
|
+
export declare function isClaudexorArtifactPath(rel: string): boolean;
|
|
4
|
+
/**
|
|
5
|
+
* TRACKED files under the artifact dirs are USER STATE, not artifacts: a
|
|
6
|
+
* project may VERSION `.claudexor/config.yaml` / `review-panel.yaml` (this
|
|
7
|
+
* repo does), and a candidate legitimately editing a tracked config must not
|
|
8
|
+
* have that edit silently dropped from status/snapshots/patches (that would
|
|
9
|
+
* be silent truncation of user work). Runtime artifacts are, by
|
|
10
|
+
* construction, never tracked. Returns a predicate: true = artifact
|
|
11
|
+
* (filterable), false = user state.
|
|
12
|
+
*/
|
|
13
|
+
export declare function claudexorArtifactPredicate(repo: string): Promise<(rel: string) => boolean>;
|
|
14
|
+
/**
|
|
15
|
+
* User-state paths under the artifact dirs = INDEX ∪ HEAD. Index alone
|
|
16
|
+
* misses a deletion the user already STAGED (`git rm .claudexor/config.yaml`
|
|
17
|
+
* removes the index entry — the path must still count as user state so the
|
|
18
|
+
* staged deletion survives dirty checks and snapshots); HEAD alone misses a
|
|
19
|
+
* user-`git add`ed new config that is not yet committed.
|
|
20
|
+
*/
|
|
21
|
+
export declare function trackedArtifactDirPaths(repo: string): Promise<Set<string>>;
|
|
22
|
+
/**
|
|
23
|
+
* `git status --porcelain` minus Claudexor artifact paths: the honest
|
|
24
|
+
* "is the USER's tree dirty" check. Never uses `:(exclude)` pathspecs — a
|
|
25
|
+
* pathspec that names a gitignored path makes git hard-error in exactly the
|
|
26
|
+
* repos Claudexor itself initializes (it seeds `.claudexor/` into
|
|
27
|
+
* .gitignore).
|
|
28
|
+
*/
|
|
29
|
+
export declare function statusPorcelainMeaningful(repo: string): Promise<string[]>;
|
|
30
|
+
/**
|
|
31
|
+
* Stage EVERYTHING except Claudexor artifacts, loudly. Bare `git add -A`
|
|
32
|
+
* (honors .gitignore) followed by unstaging the artifact dirs from the
|
|
33
|
+
* index — the same recipe the snapshot scratch-index uses, because it is
|
|
34
|
+
* the only one that works whether or not `.claudexor` is gitignored.
|
|
35
|
+
* THROWS on failure: a silent staging error turns into "nothing to commit"
|
|
36
|
+
* AFTER the patch already mutated the tree (the audit's half-delivered
|
|
37
|
+
* state).
|
|
38
|
+
*/
|
|
39
|
+
export declare function stageAllExcludingArtifacts(repo: string): Promise<void>;
|
|
40
|
+
//# sourceMappingURL=artifact-paths.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"artifact-paths.d.ts","sourceRoot":"","sources":["../src/artifact-paths.ts"],"names":[],"mappings":"AAYA,eAAO,MAAM,uBAAuB,uDAAwD,CAAC;AAE7F,8EAA8E;AAC9E,wBAAgB,uBAAuB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAG5D;AAED;;;;;;;;GAQG;AACH,wBAAsB,0BAA0B,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC,CAMhG;AAED;;;;;;GAMG;AACH,wBAAsB,uBAAuB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAoBhF;AAOD;;;;;;GAMG;AACH,wBAAsB,yBAAyB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAQ/E;AAED;;;;;;;;GAQG;AACH,wBAAsB,0BAA0B,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAgC5E"}
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The ONE owner of "Claudexor's own artifact dirs are not user tree state".
|
|
3
|
+
* Eight call sites used five different mechanisms — `:(exclude)`
|
|
4
|
+
* pathspecs (which HARD-ERROR when the project gitignores `.claudexor`),
|
|
5
|
+
* prefix filters (which over-match `.claudexorfoo`), skip-sets, and
|
|
6
|
+
* hardcoded name pairs. They converge here.
|
|
7
|
+
*/
|
|
8
|
+
import { existsSync } from "node:fs";
|
|
9
|
+
import { join } from "node:path";
|
|
10
|
+
import { runCaptureRaw } from "@claudexor/core";
|
|
11
|
+
import { WorkspaceError } from "@claudexor/core";
|
|
12
|
+
export const CLAUDEXOR_ARTIFACT_DIRS = [".claudexor", ".claudexor-review-evidence"];
|
|
13
|
+
/** True when the RELATIVE path is inside one of Claudexor's artifact dirs. */
|
|
14
|
+
export function isClaudexorArtifactPath(rel) {
|
|
15
|
+
const clean = rel.replace(/^"|"$/g, "");
|
|
16
|
+
return CLAUDEXOR_ARTIFACT_DIRS.some((dir) => clean === dir || clean.startsWith(`${dir}/`));
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* TRACKED files under the artifact dirs are USER STATE, not artifacts: a
|
|
20
|
+
* project may VERSION `.claudexor/config.yaml` / `review-panel.yaml` (this
|
|
21
|
+
* repo does), and a candidate legitimately editing a tracked config must not
|
|
22
|
+
* have that edit silently dropped from status/snapshots/patches (that would
|
|
23
|
+
* be silent truncation of user work). Runtime artifacts are, by
|
|
24
|
+
* construction, never tracked. Returns a predicate: true = artifact
|
|
25
|
+
* (filterable), false = user state.
|
|
26
|
+
*/
|
|
27
|
+
export async function claudexorArtifactPredicate(repo) {
|
|
28
|
+
const tracked = await trackedArtifactDirPaths(repo);
|
|
29
|
+
return (rel) => {
|
|
30
|
+
const clean = rel.replace(/^"|"$/g, "");
|
|
31
|
+
return isClaudexorArtifactPath(clean) && !tracked.has(clean);
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* User-state paths under the artifact dirs = INDEX ∪ HEAD. Index alone
|
|
36
|
+
* misses a deletion the user already STAGED (`git rm .claudexor/config.yaml`
|
|
37
|
+
* removes the index entry — the path must still count as user state so the
|
|
38
|
+
* staged deletion survives dirty checks and snapshots); HEAD alone misses a
|
|
39
|
+
* user-`git add`ed new config that is not yet committed.
|
|
40
|
+
*/
|
|
41
|
+
export async function trackedArtifactDirPaths(repo) {
|
|
42
|
+
const tracked = new Set();
|
|
43
|
+
// -z output is EXACT (NUL-delimited, no quoting): never trim — a legal
|
|
44
|
+
// filename may carry leading/trailing whitespace and a mangled key would
|
|
45
|
+
// silently reclassify it as an artifact.
|
|
46
|
+
const index = await git(repo, ["ls-files", "-z", "--", ...CLAUDEXOR_ARTIFACT_DIRS]);
|
|
47
|
+
if (index.code === 0) {
|
|
48
|
+
for (const p of index.stdout.split("\0")) {
|
|
49
|
+
if (p)
|
|
50
|
+
tracked.add(p);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
// HEAD may not exist yet (fresh repo) — tolerated: nothing can be
|
|
54
|
+
// HEAD-tracked before the first commit, so the index alone IS complete.
|
|
55
|
+
const head = await git(repo, ["ls-tree", "-r", "--name-only", "-z", "HEAD", "--", ...CLAUDEXOR_ARTIFACT_DIRS]);
|
|
56
|
+
if (head.code === 0) {
|
|
57
|
+
for (const p of head.stdout.split("\0")) {
|
|
58
|
+
if (p)
|
|
59
|
+
tracked.add(p);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
return tracked;
|
|
63
|
+
}
|
|
64
|
+
async function git(repo, args) {
|
|
65
|
+
const r = await runCaptureRaw("git", ["-C", repo, ...args], { timeoutMs: 60_000 });
|
|
66
|
+
return { code: r.code, stdout: r.stdout, stderr: r.stderr };
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* `git status --porcelain` minus Claudexor artifact paths: the honest
|
|
70
|
+
* "is the USER's tree dirty" check. Never uses `:(exclude)` pathspecs — a
|
|
71
|
+
* pathspec that names a gitignored path makes git hard-error in exactly the
|
|
72
|
+
* repos Claudexor itself initializes (it seeds `.claudexor/` into
|
|
73
|
+
* .gitignore).
|
|
74
|
+
*/
|
|
75
|
+
export async function statusPorcelainMeaningful(repo) {
|
|
76
|
+
const r = await git(repo, ["status", "--porcelain"]);
|
|
77
|
+
if (r.code !== 0)
|
|
78
|
+
throw new WorkspaceError(`git status failed: ${r.stderr.trim()}`);
|
|
79
|
+
const isArtifact = await claudexorArtifactPredicate(repo);
|
|
80
|
+
return r.stdout
|
|
81
|
+
.split("\n")
|
|
82
|
+
.filter((line) => line.trim().length > 0)
|
|
83
|
+
.filter((line) => !isArtifact(line.slice(3).trim()));
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Stage EVERYTHING except Claudexor artifacts, loudly. Bare `git add -A`
|
|
87
|
+
* (honors .gitignore) followed by unstaging the artifact dirs from the
|
|
88
|
+
* index — the same recipe the snapshot scratch-index uses, because it is
|
|
89
|
+
* the only one that works whether or not `.claudexor` is gitignored.
|
|
90
|
+
* THROWS on failure: a silent staging error turns into "nothing to commit"
|
|
91
|
+
* AFTER the patch already mutated the tree (the audit's half-delivered
|
|
92
|
+
* state).
|
|
93
|
+
*/
|
|
94
|
+
export async function stageAllExcludingArtifacts(repo) {
|
|
95
|
+
// TRACKED files under the artifact dirs are user state (versioned config);
|
|
96
|
+
// capture their paths BEFORE `git add -A` (afterwards freshly-staged
|
|
97
|
+
// runtime artifacts would also read as index-tracked), then restore them
|
|
98
|
+
// into the index after the bulk unstage — dropping a tracked-config edit
|
|
99
|
+
// from the patch would be silent truncation of the candidate's work.
|
|
100
|
+
const tracked = [...(await trackedArtifactDirPaths(repo))];
|
|
101
|
+
const add = await git(repo, ["add", "-A"]);
|
|
102
|
+
if (add.code !== 0)
|
|
103
|
+
throw new WorkspaceError(`git add -A failed during staging: ${add.stderr.trim()}`);
|
|
104
|
+
const unstage = await git(repo, [
|
|
105
|
+
"rm",
|
|
106
|
+
"-r",
|
|
107
|
+
"--cached",
|
|
108
|
+
"--quiet",
|
|
109
|
+
"--ignore-unmatch",
|
|
110
|
+
...CLAUDEXOR_ARTIFACT_DIRS,
|
|
111
|
+
]);
|
|
112
|
+
if (unstage.code !== 0) {
|
|
113
|
+
throw new WorkspaceError(`unstaging Claudexor artifacts failed: ${unstage.stderr.trim()}`);
|
|
114
|
+
}
|
|
115
|
+
// Re-add only paths still PRESENT in the worktree: a tracked file the
|
|
116
|
+
// user DELETED needs no re-add — the bulk unstage already leaves the
|
|
117
|
+
// index without it, which IS the staged deletion (add on a path absent
|
|
118
|
+
// from both worktree and index hard-errors). -f covers the seeded-
|
|
119
|
+
// gitignore case where the whole dir is ignore-listed.
|
|
120
|
+
const present = tracked.filter((p) => existsSync(join(repo, p)));
|
|
121
|
+
if (present.length > 0) {
|
|
122
|
+
const readd = await git(repo, ["add", "-f", "--", ...present]);
|
|
123
|
+
if (readd.code !== 0) {
|
|
124
|
+
throw new WorkspaceError(`re-staging tracked artifact-dir user files failed: ${readd.stderr.trim()}`);
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
//# sourceMappingURL=artifact-paths.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"artifact-paths.js","sourceRoot":"","sources":["../src/artifact-paths.ts"],"names":[],"mappings":"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"}
|
package/dist/git.d.ts
ADDED
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
/** BYTE-FAITHFUL git capture: raw buffers, never readline — CR
|
|
2
|
+
* bytes in CRLF diff content survive, and no trailing newline is fabricated
|
|
3
|
+
* (trim-based consumers like revParse are unaffected: git ends its own
|
|
4
|
+
* output with \n). */
|
|
5
|
+
export declare function git(repo: string, args: string[], input?: string): Promise<{
|
|
6
|
+
code: number | null;
|
|
7
|
+
stdout: string;
|
|
8
|
+
stderr: string;
|
|
9
|
+
}>;
|
|
10
|
+
export declare function isGitRepo(repo: string): Promise<boolean>;
|
|
11
|
+
export declare function revParse(repo: string, ref: string): Promise<string>;
|
|
12
|
+
export interface EnsureGitRepositoryResult {
|
|
13
|
+
/** True when `git init` ran (the folder was not a repository). */
|
|
14
|
+
initialized: boolean;
|
|
15
|
+
/** True when a baseline commit was created (fresh repo or unborn HEAD). */
|
|
16
|
+
baselineCommitted: boolean;
|
|
17
|
+
/** True when `.claudexor/` was added to (or created in) .gitignore. */
|
|
18
|
+
gitignoreSeeded: boolean;
|
|
19
|
+
/** HEAD sha after the call. */
|
|
20
|
+
headSha: string;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Make a project folder usable as a git boundary for write-mode runs.
|
|
24
|
+
*
|
|
25
|
+
* Comparator note: Codex CLI refuses to run outside a git repo (its official
|
|
26
|
+
* quick start is `mkdir && git init && codex`); Claudexor goes one step
|
|
27
|
+
* further and creates the boundary itself, announced via the
|
|
28
|
+
* `project.git.initialized` run event. The baseline commit makes worktree
|
|
29
|
+
* diffs honest from the very first run; `.claudexor/` is seeded into
|
|
30
|
+
* .gitignore FIRST so run artifacts never enter the baseline.
|
|
31
|
+
*
|
|
32
|
+
* The baseline commit is authored as "Claudexor" deterministically — it is a
|
|
33
|
+
* tool-created commit and must not depend on (or pollute) user git identity.
|
|
34
|
+
*/
|
|
35
|
+
export declare function ensureGitRepository(repo: string): Promise<EnsureGitRepositoryResult>;
|
|
36
|
+
export declare function statusPorcelain(repo: string): Promise<string>;
|
|
37
|
+
/**
|
|
38
|
+
* Capture the full dirty working tree (tracked AND untracked) as a dangling
|
|
39
|
+
* commit; null if clean. Plain `git stash create` captures only TRACKED
|
|
40
|
+
* changes, silently dropping the user's new-but-unstaged files from the run's
|
|
41
|
+
* base. We instead seed a scratch index from HEAD, `add -A` into it (which
|
|
42
|
+
* respects .gitignore, so run artifacts stay out), and commit-tree the result.
|
|
43
|
+
*/
|
|
44
|
+
export declare function stashCreate(repo: string): Promise<string | null>;
|
|
45
|
+
/**
|
|
46
|
+
* Capture the CURRENT working-tree state (tracked + untracked, minus `.claudexor`)
|
|
47
|
+
* as a commit sha — always returns one. Dirty trees become a dangling snapshot
|
|
48
|
+
* commit (via `stashCreate`); a clean tree resolves to HEAD. This is the per-turn
|
|
49
|
+
* diff base for in-place threads: snapshot at turn start, snapshot at turn end,
|
|
50
|
+
* `diffTrees(base, end)` yields exactly that turn's net change (pre-existing dirty
|
|
51
|
+
* state is folded into `base`, so the reviewer never sees prior turns' edits).
|
|
52
|
+
*/
|
|
53
|
+
export declare function snapshotTree(repo: string): Promise<string>;
|
|
54
|
+
/** Net diff between two tree-ish shas (used for in-place per-turn diffs).
|
|
55
|
+
* `--binary`: binary changes carry an APPLYABLE payload instead of
|
|
56
|
+
* degrading to a "Binary files differ" stub that silently loses the work. */
|
|
57
|
+
export declare function diffTrees(repo: string, baseSha: string, endSha: string): Promise<string>;
|
|
58
|
+
export interface RevertResult {
|
|
59
|
+
reverted: boolean;
|
|
60
|
+
/** Turn-added files removed to restore the pre-turn state (`.claudexor` preserved). */
|
|
61
|
+
removed: string[];
|
|
62
|
+
reason?: string;
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Server-owned in-place revert: restore the live working tree to a recorded
|
|
66
|
+
* pre-turn snapshot, but ONLY when the tree still matches the recorded post-turn
|
|
67
|
+
* snapshot (i.e. the user hasn't edited since) — otherwise it fails loudly and
|
|
68
|
+
* touches nothing. Reverts tracked modifications/deletions AND removes files the
|
|
69
|
+
* turn added; `.claudexor` (run artifacts) is always preserved.
|
|
70
|
+
*/
|
|
71
|
+
export declare function revertWorkingTreeTo(repo: string, preTurnSha: string, expectedPostSha: string): Promise<RevertResult>;
|
|
72
|
+
export declare function worktreeAdd(repo: string, path: string, branch: string, baseSha: string): Promise<void>;
|
|
73
|
+
/** Recreate a worktree for an EXISTING branch (recovery: dir lost, branch survived). */
|
|
74
|
+
export declare function worktreeAddExisting(repo: string, path: string, branch: string): Promise<void>;
|
|
75
|
+
export declare function worktreeRemove(repo: string, path: string): Promise<void>;
|
|
76
|
+
/**
|
|
77
|
+
* Apply a unified diff to a tree with a 3-way merge (race-winner adoption into
|
|
78
|
+
* the live in-place tree). Throws loudly on conflict so the caller can disclose
|
|
79
|
+
* `adopted:false` and offer a manual apply — the work is never silently lost.
|
|
80
|
+
*/
|
|
81
|
+
export interface ProtectedApplyResult {
|
|
82
|
+
ok: boolean;
|
|
83
|
+
/** True when the tree does NOT match its pre-apply state (restore failed). */
|
|
84
|
+
treeMutated: boolean;
|
|
85
|
+
detail?: string;
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* The PROTECTED apply path: `git apply --check` first (clean typed
|
|
89
|
+
* refusal, tree untouched), then `--3way`; if 3way still fails (race with a
|
|
90
|
+
* concurrent edit), RESTORE — `checkout -- .` for tracked content plus
|
|
91
|
+
* removal of files the partial apply CREATED (from the shared diff parser's
|
|
92
|
+
* added-paths) — and verify with `status --porcelain`. `ok:false,
|
|
93
|
+
* treeMutated:false` is a GUARANTEE the tree is byte-identical (INV-114);
|
|
94
|
+
* a failed restoration reports `treeMutated:true` honestly instead.
|
|
95
|
+
*/
|
|
96
|
+
export declare function applyPatchProtected(repo: string, diff: string): Promise<ProtectedApplyResult>;
|
|
97
|
+
export declare function worktreePrune(repo: string): Promise<void>;
|
|
98
|
+
/** Delete a local branch (best-effort GC of per-attempt claudexor/* branches). */
|
|
99
|
+
export declare function branchDelete(repo: string, branch: string): Promise<void>;
|
|
100
|
+
/**
|
|
101
|
+
* Stage everything (so untracked files appear) and return the diff vs the
|
|
102
|
+
* recorded BASE sha — NOT the worktree HEAD. A harness that commits inside the
|
|
103
|
+
* worktree (Claude Code does this routinely) advances HEAD; diffing vs HEAD
|
|
104
|
+
* would then hide the committed work and report an empty no-op diff, silently
|
|
105
|
+
* losing the candidate's real output. Diffing the staged tree vs base_sha
|
|
106
|
+
* captures all net change since the run started regardless of intermediate
|
|
107
|
+
* commits. Git op failures throw loudly instead of masquerading as "no changes".
|
|
108
|
+
*/
|
|
109
|
+
export declare function diffStaged(worktreePath: string, baseSha?: string): Promise<string>;
|
|
110
|
+
//# sourceMappingURL=git.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"git.d.ts","sourceRoot":"","sources":["../src/git.ts"],"names":[],"mappings":"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"}
|