@ferueda/grove 0.2.0 → 0.3.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.
@@ -3,9 +3,16 @@ export interface ProcessInfo {
3
3
  PID: number;
4
4
  Name?: string;
5
5
  }
6
+ export interface ProcessScanResult {
7
+ processes: ProcessInfo[];
8
+ unverified: boolean;
9
+ }
6
10
  export declare function startedAt(pid: number): Promise<number | null>;
7
11
  export declare function reserveOwner(entry: WorktreeEntry): Promise<void>;
8
12
  export declare function ownerAlive(entry: WorktreeEntry): Promise<boolean>;
9
- export declare function findInWorktree(worktreePath: string): Promise<ProcessInfo[]>;
10
- export declare function isWorktreeInUse(worktreePath: string): Promise<boolean>;
13
+ export declare function findInWorktree(worktreePath: string): Promise<ProcessScanResult>;
14
+ export declare function isWorktreeInUse(worktreePath: string): Promise<{
15
+ inUse: boolean;
16
+ unverified: boolean;
17
+ }>;
11
18
  //# sourceMappingURL=detect.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"detect.d.ts","sourceRoot":"","sources":["../../src/process/detect.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAEnD,MAAM,WAAW,WAAW;IAC1B,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAkBD,wBAAsB,SAAS,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CA+BnE;AAED,wBAAsB,YAAY,CAAC,KAAK,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC,CAMtE;AAED,wBAAsB,UAAU,CAAC,KAAK,EAAE,aAAa,GAAG,OAAO,CAAC,OAAO,CAAC,CAsBvE;AAUD,wBAAsB,cAAc,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,EAAE,CAAC,CAgDjF;AAED,wBAAsB,eAAe,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAG5E"}
1
+ {"version":3,"file":"detect.d.ts","sourceRoot":"","sources":["../../src/process/detect.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAEnD,MAAM,WAAW,WAAW;IAC1B,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,iBAAiB;IAChC,SAAS,EAAE,WAAW,EAAE,CAAC;IACzB,UAAU,EAAE,OAAO,CAAC;CACrB;AAkBD,wBAAsB,SAAS,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CA+BnE;AAED,wBAAsB,YAAY,CAAC,KAAK,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC,CAMtE;AAED,wBAAsB,UAAU,CAAC,KAAK,EAAE,aAAa,GAAG,OAAO,CAAC,OAAO,CAAC,CAsBvE;AAUD,wBAAsB,cAAc,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,iBAAiB,CAAC,CAkDrF;AAED,wBAAsB,eAAe,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC;IAAE,KAAK,EAAE,OAAO,CAAC;IAAC,UAAU,EAAE,OAAO,CAAA;CAAE,CAAC,CAG5G"}
@@ -98,7 +98,7 @@ export async function findInWorktree(worktreePath) {
98
98
  procs = await readdir("/proc");
99
99
  }
100
100
  catch {
101
- return [];
101
+ return { processes: [], unverified: true };
102
102
  }
103
103
  for (const p of procs) {
104
104
  if (!/^\d+$/.test(p))
@@ -115,6 +115,7 @@ export async function findInWorktree(worktreePath) {
115
115
  continue;
116
116
  }
117
117
  }
118
+ return { processes: result, unverified: false };
118
119
  }
119
120
  else if (process.platform === "darwin") {
120
121
  try {
@@ -134,14 +135,15 @@ export async function findInWorktree(worktreePath) {
134
135
  }
135
136
  }
136
137
  }
138
+ return { processes: result, unverified: false };
137
139
  }
138
140
  catch {
139
- // lsof returns error code if it finds no files or encounters permission errors.
141
+ return { processes: [], unverified: true };
140
142
  }
141
143
  }
142
- return result;
144
+ return { processes: [], unverified: true };
143
145
  }
144
146
  export async function isWorktreeInUse(worktreePath) {
145
- const procs = await findInWorktree(worktreePath);
146
- return procs.length > 0;
147
+ const scan = await findInWorktree(worktreePath);
148
+ return { inUse: scan.processes.length > 0, unverified: scan.unverified };
147
149
  }
@@ -85,8 +85,8 @@ export async function filterProtectedProcesses(procs, currentPID) {
85
85
  return procs.filter((p) => !protectedPids.has(p.PID));
86
86
  }
87
87
  export async function terminateWorktreeProcesses(worktreePath, gracePeriodMs) {
88
- const procs = await findInWorktree(worktreePath);
89
- const targetProcs = await filterProtectedProcesses(procs, process.pid);
88
+ const { processes } = await findInWorktree(worktreePath);
89
+ const targetProcs = await filterProtectedProcesses(processes, process.pid);
90
90
  if (targetProcs.length === 0) {
91
91
  return [];
92
92
  }
@@ -0,0 +1,8 @@
1
+ import type { WorktreeEntry } from "./schemas.js";
2
+ import type { WorktreeStatus, GroveLease } from "./types.js";
3
+ import type { GroveConfig } from "./index.js";
4
+ export declare function entryToLease(wt: WorktreeEntry, processSafety: "verified" | "unverified", repoRoot: string): GroveLease;
5
+ export declare function listWorktrees(poolDir: string): Promise<WorktreeStatus[]>;
6
+ export declare function listLeases(poolDir: string, config: GroveConfig): Promise<GroveLease[]>;
7
+ export declare function inspectLease(leaseIdOrPath: string, poolDir: string, config: GroveConfig): Promise<GroveLease | null>;
8
+ //# sourceMappingURL=queries.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"queries.d.ts","sourceRoot":"","sources":["../src/queries.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAClD,OAAO,KAAK,EAAE,cAAc,EAAE,UAAU,EAAsB,MAAM,YAAY,CAAC;AACjF,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAO9C,wBAAgB,YAAY,CAAC,EAAE,EAAE,aAAa,EAAE,aAAa,EAAE,UAAU,GAAG,YAAY,EAAE,QAAQ,EAAE,MAAM,GAAG,UAAU,CAkBtH;AAED,wBAAsB,aAAa,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,EAAE,CAAC,CAsC9E;AAED,wBAAsB,UAAU,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,WAAW,GAAG,OAAO,CAAC,UAAU,EAAE,CAAC,CAqB5F;AAED,wBAAsB,YAAY,CAAC,aAAa,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,WAAW,GAAG,OAAO,CAAC,UAAU,GAAG,IAAI,CAAC,CAkB1H"}
@@ -0,0 +1,97 @@
1
+ import { relative, isAbsolute } from "node:path";
2
+ import { isDirty, getHeadSha } from "./git/index.js";
3
+ import { readState, healState, writeState } from "./state.js";
4
+ import { ownerAlive, findInWorktree } from "./process/detect.js";
5
+ import { withStateLock } from "./lock.js";
6
+ function cwdInWorktree(cwd, worktreePath) {
7
+ const rel = relative(worktreePath, cwd);
8
+ return !rel.startsWith("..") && !isAbsolute(rel);
9
+ }
10
+ export function entryToLease(wt, processSafety, repoRoot) {
11
+ return {
12
+ leaseId: wt.leaseId,
13
+ ownerId: wt.ownerId,
14
+ slotName: wt.name,
15
+ path: wt.path,
16
+ repoRoot,
17
+ branch: wt.branch,
18
+ baseRef: wt.baseRef,
19
+ baseSha: wt.baseSha,
20
+ acquiredHeadSha: wt.acquiredHeadSha || "",
21
+ currentHeadSha: wt.currentHeadSha || "",
22
+ state: wt.state || "available",
23
+ pendingCleanup: wt.pendingCleanup,
24
+ processSafety,
25
+ createdAt: wt.createdAt || wt.created_at || "",
26
+ updatedAt: wt.updatedAt || wt.created_at || "",
27
+ };
28
+ }
29
+ export async function listWorktrees(poolDir) {
30
+ const result = [];
31
+ await withStateLock(poolDir, async () => {
32
+ let state = await readState(poolDir);
33
+ state = await healState(state);
34
+ await writeState(poolDir, state);
35
+ const cwd = process.cwd();
36
+ for (const wt of state.worktrees) {
37
+ if (wt.destroying || wt.state === "destroying" || wt.leaseId)
38
+ continue;
39
+ let status = "available";
40
+ const { processes } = await findInWorktree(wt.path);
41
+ const alive = await ownerAlive(wt);
42
+ if (alive) {
43
+ status = "in-use";
44
+ }
45
+ else if (processes.length > 0) {
46
+ status = "in-use";
47
+ if (cwdInWorktree(cwd, wt.path)) {
48
+ status = "you're here";
49
+ }
50
+ }
51
+ else if (await isDirty(wt.path)) {
52
+ status = "dirty";
53
+ }
54
+ result.push({
55
+ name: wt.name,
56
+ path: wt.path,
57
+ status,
58
+ processes,
59
+ });
60
+ }
61
+ });
62
+ return result;
63
+ }
64
+ export async function listLeases(poolDir, config) {
65
+ const result = [];
66
+ await withStateLock(poolDir, async () => {
67
+ let state = await readState(poolDir);
68
+ state = await healState(state);
69
+ for (const wt of state.worktrees) {
70
+ if (!wt.leaseId)
71
+ continue;
72
+ const { unverified } = await findInWorktree(wt.path);
73
+ try {
74
+ wt.currentHeadSha = await getHeadSha(wt.path);
75
+ }
76
+ catch { }
77
+ result.push(entryToLease(wt, unverified ? "unverified" : "verified", config.repoRoot));
78
+ }
79
+ });
80
+ return result;
81
+ }
82
+ export async function inspectLease(leaseIdOrPath, poolDir, config) {
83
+ let wt;
84
+ await withStateLock(poolDir, async () => {
85
+ let state = await readState(poolDir);
86
+ state = await healState(state);
87
+ wt = state.worktrees.find(w => w.leaseId === leaseIdOrPath || w.path === leaseIdOrPath);
88
+ });
89
+ if (!wt || !wt.leaseId)
90
+ return null;
91
+ const { unverified } = await findInWorktree(wt.path);
92
+ try {
93
+ wt.currentHeadSha = await getHeadSha(wt.path);
94
+ }
95
+ catch { }
96
+ return entryToLease(wt, unverified ? "unverified" : "verified", config.repoRoot);
97
+ }
package/dist/schemas.d.ts CHANGED
@@ -1,4 +1,16 @@
1
1
  import { z } from "zod";
2
+ export declare const GroveCleanupIntentSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
3
+ cleanup: z.ZodLiteral<"preserve">;
4
+ }, z.core.$strip>, z.ZodObject<{
5
+ cleanup: z.ZodLiteral<"reset">;
6
+ resetTo: z.ZodOptional<z.ZodString>;
7
+ force: z.ZodOptional<z.ZodBoolean>;
8
+ cleanIgnored: z.ZodOptional<z.ZodBoolean>;
9
+ }, z.core.$strip>, z.ZodObject<{
10
+ cleanup: z.ZodLiteral<"quarantine">;
11
+ }, z.core.$strip>], "cleanup">;
12
+ export type GroveCleanupIntent = z.infer<typeof GroveCleanupIntentSchema>;
13
+ export declare const LeaseIdSchema: z.ZodString;
2
14
  export declare const WorktreeEntrySchema: z.ZodObject<{
3
15
  name: z.ZodString;
4
16
  path: z.ZodString;
@@ -6,6 +18,35 @@ export declare const WorktreeEntrySchema: z.ZodObject<{
6
18
  destroying: z.ZodOptional<z.ZodBoolean>;
7
19
  owner_pid: z.ZodOptional<z.ZodNumber>;
8
20
  owner_started_at: z.ZodOptional<z.ZodNumber>;
21
+ leaseId: z.ZodOptional<z.ZodString>;
22
+ ownerId: z.ZodOptional<z.ZodString>;
23
+ baseRef: z.ZodOptional<z.ZodString>;
24
+ baseSha: z.ZodOptional<z.ZodString>;
25
+ acquiredHeadSha: z.ZodOptional<z.ZodString>;
26
+ currentHeadSha: z.ZodOptional<z.ZodString>;
27
+ branch: z.ZodOptional<z.ZodString>;
28
+ state: z.ZodOptional<z.ZodEnum<{
29
+ available: "available";
30
+ destroying: "destroying";
31
+ leased: "leased";
32
+ quarantined: "quarantined";
33
+ releasing: "releasing";
34
+ }>>;
35
+ pendingCleanup: z.ZodOptional<z.ZodDiscriminatedUnion<[z.ZodObject<{
36
+ cleanup: z.ZodLiteral<"preserve">;
37
+ }, z.core.$strip>, z.ZodObject<{
38
+ cleanup: z.ZodLiteral<"reset">;
39
+ resetTo: z.ZodOptional<z.ZodString>;
40
+ force: z.ZodOptional<z.ZodBoolean>;
41
+ cleanIgnored: z.ZodOptional<z.ZodBoolean>;
42
+ }, z.core.$strip>, z.ZodObject<{
43
+ cleanup: z.ZodLiteral<"quarantine">;
44
+ }, z.core.$strip>], "cleanup">>;
45
+ processSafety: z.ZodOptional<z.ZodEnum<{
46
+ unverified: "unverified";
47
+ verified: "verified";
48
+ }>>;
49
+ updatedAt: z.ZodOptional<z.ZodString>;
9
50
  }, z.core.$strip>;
10
51
  export type WorktreeEntry = z.infer<typeof WorktreeEntrySchema>;
11
52
  export declare const GroveStateSchema: z.ZodObject<{
@@ -16,6 +57,35 @@ export declare const GroveStateSchema: z.ZodObject<{
16
57
  destroying: z.ZodOptional<z.ZodBoolean>;
17
58
  owner_pid: z.ZodOptional<z.ZodNumber>;
18
59
  owner_started_at: z.ZodOptional<z.ZodNumber>;
60
+ leaseId: z.ZodOptional<z.ZodString>;
61
+ ownerId: z.ZodOptional<z.ZodString>;
62
+ baseRef: z.ZodOptional<z.ZodString>;
63
+ baseSha: z.ZodOptional<z.ZodString>;
64
+ acquiredHeadSha: z.ZodOptional<z.ZodString>;
65
+ currentHeadSha: z.ZodOptional<z.ZodString>;
66
+ branch: z.ZodOptional<z.ZodString>;
67
+ state: z.ZodOptional<z.ZodEnum<{
68
+ available: "available";
69
+ destroying: "destroying";
70
+ leased: "leased";
71
+ quarantined: "quarantined";
72
+ releasing: "releasing";
73
+ }>>;
74
+ pendingCleanup: z.ZodOptional<z.ZodDiscriminatedUnion<[z.ZodObject<{
75
+ cleanup: z.ZodLiteral<"preserve">;
76
+ }, z.core.$strip>, z.ZodObject<{
77
+ cleanup: z.ZodLiteral<"reset">;
78
+ resetTo: z.ZodOptional<z.ZodString>;
79
+ force: z.ZodOptional<z.ZodBoolean>;
80
+ cleanIgnored: z.ZodOptional<z.ZodBoolean>;
81
+ }, z.core.$strip>, z.ZodObject<{
82
+ cleanup: z.ZodLiteral<"quarantine">;
83
+ }, z.core.$strip>], "cleanup">>;
84
+ processSafety: z.ZodOptional<z.ZodEnum<{
85
+ unverified: "unverified";
86
+ verified: "verified";
87
+ }>>;
88
+ updatedAt: z.ZodOptional<z.ZodString>;
19
89
  }, z.core.$strip>>;
20
90
  }, z.core.$strip>;
21
91
  export type GroveState = z.infer<typeof GroveStateSchema>;
@@ -24,10 +94,19 @@ export declare const GroveConfigSchema: z.ZodObject<{
24
94
  groveDir: z.ZodOptional<z.ZodString>;
25
95
  groveRoot: z.ZodOptional<z.ZodString>;
26
96
  maxTrees: z.ZodDefault<z.ZodOptional<z.ZodNumber>>;
97
+ safeDeleteBranchPrefixes: z.ZodOptional<z.ZodArray<z.ZodString>>;
98
+ hookTimeoutMs: z.ZodOptional<z.ZodNumber>;
27
99
  hooks: z.ZodOptional<z.ZodObject<{
28
100
  postCreate: z.ZodOptional<z.ZodArray<z.ZodString>>;
101
+ postAcquire: z.ZodOptional<z.ZodArray<z.ZodString>>;
102
+ preRelease: z.ZodOptional<z.ZodArray<z.ZodString>>;
103
+ postRelease: z.ZodOptional<z.ZodArray<z.ZodString>>;
29
104
  preDestroy: z.ZodOptional<z.ZodArray<z.ZodString>>;
30
105
  }, z.core.$strip>>;
106
+ onHookFailure: z.ZodDefault<z.ZodOptional<z.ZodEnum<{
107
+ fail: "fail";
108
+ ignore: "ignore";
109
+ }>>>;
31
110
  fetchOnAcquire: z.ZodDefault<z.ZodOptional<z.ZodBoolean>>;
32
111
  }, z.core.$strip>;
33
112
  export type GroveConfig = z.input<typeof GroveConfigSchema>;
@@ -1 +1 @@
1
- {"version":3,"file":"schemas.d.ts","sourceRoot":"","sources":["../src/schemas.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,eAAO,MAAM,mBAAmB;;;;;;;iBAO9B,CAAC;AAEH,MAAM,MAAM,aAAa,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,mBAAmB,CAAC,CAAC;AAEhE,eAAO,MAAM,gBAAgB;;;;;;;;;iBAE3B,CAAC;AAEH,MAAM,MAAM,UAAU,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,gBAAgB,CAAC,CAAC;AAE1D,eAAO,MAAM,iBAAiB;;;;;;;;;;iBAY5B,CAAC;AAEH,MAAM,MAAM,WAAW,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,iBAAiB,CAAC,CAAC"}
1
+ {"version":3,"file":"schemas.d.ts","sourceRoot":"","sources":["../src/schemas.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,eAAO,MAAM,wBAAwB;;;;;;;;;8BASnC,CAAC;AAEH,MAAM,MAAM,kBAAkB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,wBAAwB,CAAC,CAAC;AAE1E,eAAO,MAAM,aAAa,aAAoF,CAAC;AAE/G,eAAO,MAAM,mBAAmB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAoB9B,CAAC;AAEH,MAAM,MAAM,aAAa,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,mBAAmB,CAAC,CAAC;AAEhE,eAAO,MAAM,gBAAgB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAE3B,CAAC;AAEH,MAAM,MAAM,UAAU,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,gBAAgB,CAAC,CAAC;AAE1D,eAAO,MAAM,iBAAiB;;;;;;;;;;;;;;;;;;;iBAkB5B,CAAC;AAEH,MAAM,MAAM,WAAW,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,iBAAiB,CAAC,CAAC"}
package/dist/schemas.js CHANGED
@@ -1,4 +1,15 @@
1
1
  import { z } from "zod";
2
+ export const GroveCleanupIntentSchema = z.discriminatedUnion("cleanup", [
3
+ z.object({ cleanup: z.literal("preserve") }),
4
+ z.object({
5
+ cleanup: z.literal("reset"),
6
+ resetTo: z.string().optional(),
7
+ force: z.boolean().optional(),
8
+ cleanIgnored: z.boolean().optional(),
9
+ }),
10
+ z.object({ cleanup: z.literal("quarantine") }),
11
+ ]);
12
+ export const LeaseIdSchema = z.string().regex(/^[a-zA-Z0-9][a-zA-Z0-9._-]{0,127}$/, "Invalid lease ID format");
2
13
  export const WorktreeEntrySchema = z.object({
3
14
  name: z.string(),
4
15
  path: z.string(),
@@ -6,6 +17,18 @@ export const WorktreeEntrySchema = z.object({
6
17
  destroying: z.boolean().optional(),
7
18
  owner_pid: z.number().optional(),
8
19
  owner_started_at: z.number().optional(),
20
+ // Lease Mode fields
21
+ leaseId: LeaseIdSchema.optional(),
22
+ ownerId: z.string().optional(),
23
+ baseRef: z.string().optional(),
24
+ baseSha: z.string().optional(),
25
+ acquiredHeadSha: z.string().optional(),
26
+ currentHeadSha: z.string().optional(),
27
+ branch: z.string().optional(),
28
+ state: z.enum(["leased", "available", "releasing", "destroying", "quarantined"]).optional(),
29
+ pendingCleanup: GroveCleanupIntentSchema.optional(),
30
+ processSafety: z.enum(["verified", "unverified"]).optional(),
31
+ updatedAt: z.string().optional(),
9
32
  });
10
33
  export const GroveStateSchema = z.object({
11
34
  worktrees: z.array(WorktreeEntrySchema),
@@ -15,11 +38,17 @@ export const GroveConfigSchema = z.object({
15
38
  groveDir: z.string().optional(),
16
39
  groveRoot: z.string().optional(),
17
40
  maxTrees: z.number().optional().default(16),
41
+ safeDeleteBranchPrefixes: z.array(z.string()).optional(),
42
+ hookTimeoutMs: z.number().optional(),
18
43
  hooks: z
19
44
  .object({
20
45
  postCreate: z.array(z.string()).optional(),
46
+ postAcquire: z.array(z.string()).optional(),
47
+ preRelease: z.array(z.string()).optional(),
48
+ postRelease: z.array(z.string()).optional(),
21
49
  preDestroy: z.array(z.string()).optional(),
22
50
  })
23
51
  .optional(),
52
+ onHookFailure: z.enum(["ignore", "fail"]).optional().default("ignore"),
24
53
  fetchOnAcquire: z.boolean().optional().default(true),
25
54
  });
@@ -1 +1 @@
1
- {"version":3,"file":"state.d.ts","sourceRoot":"","sources":["../src/state.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAK/C,wBAAgB,aAAa,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAEtD;AAED,wBAAsB,SAAS,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC,CAwBrE;AAED,wBAAsB,UAAU,CAAC,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC,CAMnF;AAED,wBAAsB,SAAS,CAAC,KAAK,EAAE,UAAU,GAAG,OAAO,CAAC,UAAU,CAAC,CAqBtE"}
1
+ {"version":3,"file":"state.d.ts","sourceRoot":"","sources":["../src/state.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAK/C,wBAAgB,aAAa,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAEtD;AAED,wBAAsB,SAAS,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC,CAwBrE;AAED,wBAAsB,UAAU,CAAC,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC,CAMnF;AAED,wBAAsB,SAAS,CAAC,KAAK,EAAE,UAAU,GAAG,OAAO,CAAC,UAAU,CAAC,CA2BtE"}
package/dist/state.js CHANGED
@@ -54,5 +54,10 @@ export async function healState(state) {
54
54
  }
55
55
  healed.worktrees.push(entry);
56
56
  }
57
+ for (const entry of healed.worktrees) {
58
+ if (!entry.state) {
59
+ entry.state = "available";
60
+ }
61
+ }
57
62
  return healed;
58
63
  }
@@ -0,0 +1,62 @@
1
+ import type { GroveCleanupIntent } from "./schemas.js";
2
+ export type WorktreeStatusInfo = "available" | "dirty" | "in-use" | "you're here";
3
+ export interface AcquiredSlot {
4
+ readonly path: string;
5
+ readonly name: string;
6
+ }
7
+ export interface WorktreeStatus {
8
+ name: string;
9
+ path: string;
10
+ status: WorktreeStatusInfo;
11
+ processes: {
12
+ PID: number;
13
+ Name?: string;
14
+ }[];
15
+ }
16
+ type AcquireMode = {
17
+ mode: "branch";
18
+ branch: string;
19
+ createBranch?: {
20
+ from: string;
21
+ ifExists?: "reuse" | "fail";
22
+ };
23
+ } | {
24
+ mode: "detached";
25
+ ref: string;
26
+ };
27
+ export type AcquireLeaseOptions = AcquireMode & {
28
+ leaseId: string;
29
+ ownerId?: string;
30
+ ifLeased?: "return-existing" | "fail";
31
+ fetchOnAcquire?: boolean;
32
+ metadata?: Record<string, string>;
33
+ };
34
+ export type ReleaseLeaseOptions = GroveCleanupIntent;
35
+ export interface DestroyLeaseOptions {
36
+ force?: boolean;
37
+ deleteBranch?: boolean;
38
+ }
39
+ export interface RepairLeaseOptions {
40
+ leaseId: string;
41
+ action: "quarantine" | "resume-cleanup" | "force-destroy";
42
+ force?: boolean;
43
+ }
44
+ export interface GroveLease {
45
+ leaseId: string;
46
+ ownerId?: string | undefined;
47
+ slotName: string;
48
+ path: string;
49
+ repoRoot: string;
50
+ branch?: string | undefined;
51
+ baseRef?: string | undefined;
52
+ baseSha?: string | undefined;
53
+ acquiredHeadSha: string;
54
+ currentHeadSha: string;
55
+ state: "leased" | "available" | "releasing" | "destroying" | "quarantined";
56
+ pendingCleanup?: GroveCleanupIntent | undefined;
57
+ processSafety?: "verified" | "unverified" | undefined;
58
+ createdAt: string;
59
+ updatedAt: string;
60
+ }
61
+ export {};
62
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAC;AAEvD,MAAM,MAAM,kBAAkB,GAAG,WAAW,GAAG,OAAO,GAAG,QAAQ,GAAG,aAAa,CAAC;AAElF,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;CACvB;AAED,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,kBAAkB,CAAC;IAC3B,SAAS,EAAE;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;CAC7C;AAED,KAAK,WAAW,GACZ;IACE,IAAI,EAAE,QAAQ,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,YAAY,CAAC,EAAE;QACb,IAAI,EAAE,MAAM,CAAC;QACb,QAAQ,CAAC,EAAE,OAAO,GAAG,MAAM,CAAC;KAC7B,CAAC;CACH,GACD;IACE,IAAI,EAAE,UAAU,CAAC;IACjB,GAAG,EAAE,MAAM,CAAC;CACb,CAAC;AAEN,MAAM,MAAM,mBAAmB,GAAG,WAAW,GAAG;IAC9C,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,iBAAiB,GAAG,MAAM,CAAC;IACtC,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACnC,CAAC;AAEF,MAAM,MAAM,mBAAmB,GAAG,kBAAkB,CAAC;AAErD,MAAM,WAAW,mBAAmB;IAClC,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,YAAY,CAAC,EAAE,OAAO,CAAC;CACxB;AAED,MAAM,WAAW,kBAAkB;IACjC,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,YAAY,GAAG,gBAAgB,GAAG,eAAe,CAAC;IAC1D,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB;AAED,MAAM,WAAW,UAAU;IACzB,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC7B,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC5B,OAAO,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC7B,OAAO,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC7B,eAAe,EAAE,MAAM,CAAC;IACxB,cAAc,EAAE,MAAM,CAAC;IACvB,KAAK,EAAE,QAAQ,GAAG,WAAW,GAAG,WAAW,GAAG,YAAY,GAAG,aAAa,CAAC;IAC3E,cAAc,CAAC,EAAE,kBAAkB,GAAG,SAAS,CAAC;IAChD,aAAa,CAAC,EAAE,UAAU,GAAG,YAAY,GAAG,SAAS,CAAC;IACtD,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;CACnB"}
package/dist/types.js ADDED
@@ -0,0 +1 @@
1
+ export {};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ferueda/grove",
3
- "version": "0.2.0",
3
+ "version": "0.3.0",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "https://github.com/ferueda/grove.git"