@autosk/worktree 0.1.1 → 0.1.2
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 +21 -13
- package/package.json +2 -3
- package/src/index.ts +15 -29
package/README.md
CHANGED
|
@@ -22,8 +22,11 @@ autosk.registerWorkflow({
|
|
|
22
22
|
```
|
|
23
23
|
|
|
24
24
|
Each isolated task runs in its own checkout so concurrent tasks never collide on
|
|
25
|
-
the working tree. The engine calls `acquire` before scheduling
|
|
26
|
-
returned `cwd` becomes `ctx.cwd`) and `
|
|
25
|
+
the working tree. The engine calls `acquire` before scheduling each session (its
|
|
26
|
+
returned `cwd` becomes `ctx.cwd`) and `reap` only on a terminal transition
|
|
27
|
+
(`done`/`cancel`). This provider has no live env to stop, so it **omits**
|
|
28
|
+
`release` entirely — keeping the checkout on disk across sibling/human-park steps
|
|
29
|
+
is exactly the absence of teardown.
|
|
27
30
|
|
|
28
31
|
## Behaviour
|
|
29
32
|
|
|
@@ -35,22 +38,27 @@ either stack resolves to the same place:
|
|
|
35
38
|
branch = autosk/<task-id>
|
|
36
39
|
```
|
|
37
40
|
|
|
38
|
-
- **acquire** — allocates the per-task worktree on branch
|
|
39
|
-
(off `HEAD`), or re-uses it when a prior step kept it. A
|
|
40
|
-
re-allocated on the *existing* branch (v1 "missing worktree
|
|
41
|
-
|
|
42
|
-
|
|
41
|
+
- **acquire** (ensure-ready) — allocates the per-task worktree on branch
|
|
42
|
+
`autosk/<task-id>` (off `HEAD`), or re-uses it when a prior step kept it. A
|
|
43
|
+
**missing** dir is re-allocated on the *existing* branch (v1 "missing worktree
|
|
44
|
+
auto-recovery"). Idempotent and re-entered per step. Returns
|
|
45
|
+
`{ cwd, meta: { branch, projectRoot } }`.
|
|
46
|
+
- **(no `release`)** — sibling step and human-park keep the dir on disk
|
|
47
|
+
untouched, so the next `acquire` re-uses the same checkout. There is nothing to
|
|
48
|
+
quiesce, so the method is omitted.
|
|
49
|
+
- **reap** (destroy-on-terminal, done / cancel) — keyed by `(projectRoot,
|
|
50
|
+
taskId)`, so it works with no live handle (engine terminal, a manual
|
|
51
|
+
`done`/`cancel` after a park, or crash recovery). Removes the worktree dir but
|
|
43
52
|
**preserves** the `autosk/<task-id>` branch (so the work survives for review /
|
|
44
|
-
merge).
|
|
45
|
-
|
|
46
|
-
the next step re-uses the same checkout.
|
|
53
|
+
merge). With `force:false` it refuses to discard uncommitted changes and
|
|
54
|
+
reports `{ removed:false, dirty:true }`; `force:true` removes regardless.
|
|
47
55
|
|
|
48
56
|
### Failure handling
|
|
49
57
|
|
|
50
58
|
The provider **only throws descriptive messages** — the engine wraps them
|
|
51
|
-
(`isolation_acquire_failed: …` on acquire, `
|
|
52
|
-
|
|
53
|
-
|
|
59
|
+
(`isolation_acquire_failed: …` on acquire, `isolation_reap_failed: …` on a
|
|
60
|
+
terminal reap) and parks the task to `human`. It never parks or formats those
|
|
61
|
+
prefixes itself. Throw cases:
|
|
54
62
|
|
|
55
63
|
- **non-git root** — `not a git repository: <root>` (the project root isn't a
|
|
56
64
|
git repo).
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@autosk/worktree",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.2",
|
|
4
4
|
"description": "Shipped autoskd v2 isolation provider: per-task git worktree isolation (worktreeIsolation()) attachable to any workflow.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "wierdbytes",
|
|
@@ -16,8 +16,7 @@
|
|
|
16
16
|
"keywords": [
|
|
17
17
|
"autosk",
|
|
18
18
|
"autosk-extension",
|
|
19
|
-
"
|
|
20
|
-
"isolation"
|
|
19
|
+
"autosk-isolation"
|
|
21
20
|
],
|
|
22
21
|
"type": "module",
|
|
23
22
|
"publishConfig": {
|
package/src/index.ts
CHANGED
|
@@ -2,12 +2,15 @@
|
|
|
2
2
|
* `@autosk/worktree` — the shipped `worktreeIsolation()` provider (plan §3.5).
|
|
3
3
|
*
|
|
4
4
|
* Ports v1's per-task git worktree isolation onto the v2
|
|
5
|
-
* {@link IsolationProvider} contract. The
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
* `release`
|
|
10
|
-
*
|
|
5
|
+
* {@link IsolationProvider} contract. The engine
|
|
6
|
+
* (`daemon/core/src/engine/session.ts`) calls `acquire` before scheduling an
|
|
7
|
+
* isolated session (idempotently re-used across the run's steps) and `reap` on a
|
|
8
|
+
* terminal transition (`done`/`cancel`). A worktree has nothing to "stop", so
|
|
9
|
+
* this provider omits `release` entirely — keeping the dir across a step→step or
|
|
10
|
+
* a human-park IS the absence of teardown. FAILURES ARE WRAPPED BY THE ENGINE
|
|
11
|
+
* (`acquire` throw → `isolation_acquire_failed: <msg>`, `reap` throw →
|
|
12
|
+
* `isolation_reap_failed: <msg>`), so this provider just throws descriptive
|
|
13
|
+
* messages — it never parks or formats those prefixes itself.
|
|
11
14
|
*
|
|
12
15
|
* Deterministic mapping (byte-identical to the v1 Go/Rust slug so a worktree
|
|
13
16
|
* allocated by either stack resolves to the same place):
|
|
@@ -42,7 +45,7 @@ export const WORKTREE_TAG = "worktree";
|
|
|
42
45
|
/** Provider-internal bookkeeping carried on every {@link IsolationHandle}. */
|
|
43
46
|
interface WorktreeMeta extends Record<string, unknown> {
|
|
44
47
|
branch: string;
|
|
45
|
-
/** The canonical project root
|
|
48
|
+
/** The canonical project root the worktree was checked out from. */
|
|
46
49
|
projectRoot: string;
|
|
47
50
|
}
|
|
48
51
|
|
|
@@ -50,9 +53,9 @@ interface WorktreeMeta extends Record<string, unknown> {
|
|
|
50
53
|
* Builds the shipped worktree {@link IsolationProvider}. Attach it to a workflow
|
|
51
54
|
* via `isolation: worktreeIsolation()` (plan §3.6). `acquire` allocates (or
|
|
52
55
|
* re-uses / re-allocates) the per-task worktree and hands the engine its path as
|
|
53
|
-
* `ctx.cwd`; `
|
|
54
|
-
* `autosk/<task>` branch
|
|
55
|
-
*
|
|
56
|
+
* `ctx.cwd`; `reap` removes the dir on a terminal transition but PRESERVES the
|
|
57
|
+
* `autosk/<task>` branch. There is no `release`: the dir is simply kept across
|
|
58
|
+
* step→step and human-park (the env is reused on the next `acquire`).
|
|
56
59
|
*/
|
|
57
60
|
export function worktreeIsolation(opts: WorktreeIsolationOptions = {}): IsolationProvider {
|
|
58
61
|
const gitBin = opts.gitBin ?? "git";
|
|
@@ -95,23 +98,6 @@ export function worktreeIsolation(opts: WorktreeIsolationOptions = {}): Isolatio
|
|
|
95
98
|
return { cwd: path, meta };
|
|
96
99
|
},
|
|
97
100
|
|
|
98
|
-
async release(handle, { terminal, force }): Promise<void> {
|
|
99
|
-
// Non-terminal (sibling step / human-park): keep the dir so the next step
|
|
100
|
-
// re-uses the same checkout. Nothing to do.
|
|
101
|
-
if (!terminal) return;
|
|
102
|
-
const meta = (handle.meta ?? {}) as Partial<WorktreeMeta>;
|
|
103
|
-
const path = handle.cwd;
|
|
104
|
-
const canon = meta.projectRoot ? canonRoot(meta.projectRoot) : "";
|
|
105
|
-
await ensureGitAvailable(gitBin);
|
|
106
|
-
const r = await cleanupTerminal(gitBin, canon, path, force);
|
|
107
|
-
// The engine drives a terminal `release` with `force:true`, so this never
|
|
108
|
-
// fires there; an explicit `force:false` caller gets a descriptive throw it
|
|
109
|
-
// can surface (the engine would wrap it as `isolation_release_failed:`).
|
|
110
|
-
if (r.dirty && !r.removed) {
|
|
111
|
-
throw new Error(`worktree_dirty: ${path}${r.detail ? ` (${r.detail})` : ""}`);
|
|
112
|
-
}
|
|
113
|
-
},
|
|
114
|
-
|
|
115
101
|
async reap({ projectRoot, taskId }, { force }): Promise<IsolationReapResult> {
|
|
116
102
|
const canon = canonRoot(projectRoot);
|
|
117
103
|
const path = pathFor(canon, taskId, opts.home);
|
|
@@ -186,8 +172,8 @@ async function verifyHealthy(gitBin: string, canon: string, path: string): Promi
|
|
|
186
172
|
}
|
|
187
173
|
|
|
188
174
|
/**
|
|
189
|
-
* The
|
|
190
|
-
*
|
|
175
|
+
* The terminal-cleanup core behind {@link IsolationProvider.reap} (session-free,
|
|
176
|
+
* keyed by identity).
|
|
191
177
|
*
|
|
192
178
|
* Removes the worktree dir while PRESERVING its branch, gated on `force`:
|
|
193
179
|
* `force:false` leaves a dirty checkout in place and reports `{dirty:true}` so
|