git-worktree-organize 1.0.8 → 1.0.10
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/dist/cli.js +382 -0
- package/package.json +7 -3
- package/.beads/README.md +0 -81
- package/.beads/backup/backup_state.json +0 -13
- package/.beads/backup/comments.jsonl +0 -0
- package/.beads/backup/config.jsonl +0 -11
- package/.beads/backup/dependencies.jsonl +0 -10
- package/.beads/backup/events.jsonl +0 -31
- package/.beads/backup/issues.jsonl +0 -9
- package/.beads/backup/labels.jsonl +0 -0
- package/.beads/config.yaml +0 -55
- package/.beads/hooks/post-checkout +0 -9
- package/.beads/hooks/post-merge +0 -9
- package/.beads/hooks/pre-commit +0 -9
- package/.beads/hooks/pre-push +0 -9
- package/.beads/hooks/prepare-commit-msg +0 -9
- package/.beads/interactions.jsonl +0 -0
- package/.beads/metadata.json +0 -9
- package/.claude/settings.local.json +0 -8
- package/AGENTS.md +0 -150
- package/bun.lock +0 -205
- package/src/cli.ts +0 -143
- package/src/detect.ts +0 -95
- package/src/fs.ts +0 -22
- package/src/git.ts +0 -40
- package/src/migrate.ts +0 -162
- package/src/worktrees.ts +0 -54
- package/test/__bun-shim__.ts +0 -78
- package/test/detect.test.ts +0 -99
- package/test/helpers/repo.ts +0 -75
- package/test/migrate.test.ts +0 -124
- package/test/security.test.ts +0 -25
- package/test/worktrees.test.ts +0 -164
- package/tsconfig.json +0 -13
- package/vitest.config.ts +0 -13
package/dist/cli.js
ADDED
|
@@ -0,0 +1,382 @@
|
|
|
1
|
+
#!/usr/bin/env bun
|
|
2
|
+
// @bun
|
|
3
|
+
|
|
4
|
+
// src/cli.ts
|
|
5
|
+
import { resolve as resolve3, join as join3, dirname as dirname2, basename as basename2 } from "path";
|
|
6
|
+
|
|
7
|
+
// src/run.ts
|
|
8
|
+
import { spawnSync } from "node:child_process";
|
|
9
|
+
function run(cmd, args, options) {
|
|
10
|
+
const result = spawnSync(cmd, args, {
|
|
11
|
+
encoding: "utf8",
|
|
12
|
+
cwd: options?.cwd,
|
|
13
|
+
env: options?.env ?? process.env
|
|
14
|
+
});
|
|
15
|
+
if (result.status !== 0) {
|
|
16
|
+
const err = new Error(`${cmd} ${args.join(" ")} failed: ${result.stderr?.trim() || result.error?.message}`);
|
|
17
|
+
err.exitCode = result.status;
|
|
18
|
+
err.stderr = result.stderr;
|
|
19
|
+
throw err;
|
|
20
|
+
}
|
|
21
|
+
return { stdout: result.stdout ?? "", stderr: result.stderr ?? "" };
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
// src/detect.ts
|
|
25
|
+
import { existsSync, statSync, readFileSync } from "node:fs";
|
|
26
|
+
import { join, resolve, isAbsolute } from "node:path";
|
|
27
|
+
|
|
28
|
+
// src/run.ts
|
|
29
|
+
import { spawnSync as spawnSync2 } from "node:child_process";
|
|
30
|
+
function run2(cmd, args, options) {
|
|
31
|
+
const result = spawnSync2(cmd, args, {
|
|
32
|
+
encoding: "utf8",
|
|
33
|
+
cwd: options?.cwd,
|
|
34
|
+
env: options?.env ?? process.env
|
|
35
|
+
});
|
|
36
|
+
if (result.status !== 0) {
|
|
37
|
+
const err = new Error(`${cmd} ${args.join(" ")} failed: ${result.stderr?.trim() || result.error?.message}`);
|
|
38
|
+
err.exitCode = result.status;
|
|
39
|
+
err.stderr = result.stderr;
|
|
40
|
+
throw err;
|
|
41
|
+
}
|
|
42
|
+
return { stdout: result.stdout ?? "", stderr: result.stderr ?? "" };
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// src/detect.ts
|
|
46
|
+
function readCoreBare(gitdir) {
|
|
47
|
+
try {
|
|
48
|
+
const result = run2("git", ["--git-dir", gitdir, "config", "--get", "core.bare"]);
|
|
49
|
+
return result.stdout.trim() === "true";
|
|
50
|
+
} catch {
|
|
51
|
+
return false;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
async function detect(repoPath) {
|
|
55
|
+
const gitEntryPath = join(repoPath, ".git");
|
|
56
|
+
const gitEntryExists = existsSync(gitEntryPath);
|
|
57
|
+
if (gitEntryExists) {
|
|
58
|
+
const stat = statSync(gitEntryPath);
|
|
59
|
+
if (stat.isDirectory()) {
|
|
60
|
+
const isbare = readCoreBare(gitEntryPath);
|
|
61
|
+
if (isbare) {
|
|
62
|
+
return { type: "bare-dotgit", gitdir: gitEntryPath };
|
|
63
|
+
} else {
|
|
64
|
+
return { type: "standard", gitdir: gitEntryPath, mainWorktree: repoPath };
|
|
65
|
+
}
|
|
66
|
+
} else if (stat.isFile()) {
|
|
67
|
+
const contents = readFileSync(gitEntryPath, "utf8");
|
|
68
|
+
const firstLine = contents.split(`
|
|
69
|
+
`)[0].trim();
|
|
70
|
+
const match = firstLine.match(/^gitdir:\s*(.+)$/);
|
|
71
|
+
if (!match) {
|
|
72
|
+
throw new Error(`not a git repository: ${repoPath}`);
|
|
73
|
+
}
|
|
74
|
+
const rawGitdir = match[1].trim();
|
|
75
|
+
const absGitdir = isAbsolute(rawGitdir) ? rawGitdir : resolve(repoPath, rawGitdir);
|
|
76
|
+
if (absGitdir.includes("/worktrees/")) {
|
|
77
|
+
throw new Error("is a linked worktree, not a repo root");
|
|
78
|
+
}
|
|
79
|
+
if (!existsSync(join(absGitdir, "HEAD")) || !existsSync(join(absGitdir, "objects")) || !existsSync(join(absGitdir, "refs"))) {
|
|
80
|
+
throw new Error(`gitdir does not appear to be a git repository: ${absGitdir}`);
|
|
81
|
+
}
|
|
82
|
+
if (absGitdir.endsWith(".bare")) {
|
|
83
|
+
return { type: "bare-hub", gitdir: absGitdir };
|
|
84
|
+
}
|
|
85
|
+
return { type: "bare-external", gitdir: absGitdir };
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
const headExists = existsSync(join(repoPath, "HEAD"));
|
|
89
|
+
const refsExists = existsSync(join(repoPath, "refs"));
|
|
90
|
+
const objectsExists = existsSync(join(repoPath, "objects"));
|
|
91
|
+
if (headExists && refsExists && objectsExists) {
|
|
92
|
+
return { type: "bare-root", gitdir: repoPath };
|
|
93
|
+
}
|
|
94
|
+
throw new Error(`not a git repository: ${repoPath}`);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
// src/worktrees.ts
|
|
98
|
+
function parsePorcelain(output) {
|
|
99
|
+
const worktrees = [];
|
|
100
|
+
const blocks = output.trim().split(/\n\n+/);
|
|
101
|
+
for (const block of blocks) {
|
|
102
|
+
if (!block.trim())
|
|
103
|
+
continue;
|
|
104
|
+
const lines = block.trim().split(`
|
|
105
|
+
`);
|
|
106
|
+
let path = "";
|
|
107
|
+
let head = "";
|
|
108
|
+
let branch = null;
|
|
109
|
+
let isBare = false;
|
|
110
|
+
for (const line of lines) {
|
|
111
|
+
if (line.startsWith("worktree ")) {
|
|
112
|
+
path = line.slice("worktree ".length);
|
|
113
|
+
} else if (line.startsWith("HEAD ")) {
|
|
114
|
+
head = line.slice("HEAD ".length);
|
|
115
|
+
} else if (line.startsWith("branch ")) {
|
|
116
|
+
const ref = line.slice("branch ".length);
|
|
117
|
+
branch = ref.startsWith("refs/heads/") ? ref.slice("refs/heads/".length) : ref;
|
|
118
|
+
} else if (line === "detached") {
|
|
119
|
+
branch = null;
|
|
120
|
+
} else if (line === "bare") {
|
|
121
|
+
isBare = true;
|
|
122
|
+
branch = null;
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
worktrees.push({ path, head, branch, isBare });
|
|
126
|
+
}
|
|
127
|
+
return worktrees;
|
|
128
|
+
}
|
|
129
|
+
async function listWorktrees(repoPath) {
|
|
130
|
+
const result = run2("git", ["-C", repoPath, "worktree", "list", "--porcelain"]);
|
|
131
|
+
return parsePorcelain(result.stdout);
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
// src/migrate.ts
|
|
135
|
+
import { mkdirSync, writeFileSync, readFileSync as readFileSync2, existsSync as existsSync2, renameSync, statSync as statSync2 } from "node:fs";
|
|
136
|
+
import { join as join2, dirname, basename, resolve as resolve2 } from "node:path";
|
|
137
|
+
|
|
138
|
+
// src/worktrees.ts
|
|
139
|
+
function parsePorcelain2(output) {
|
|
140
|
+
const worktrees = [];
|
|
141
|
+
const blocks = output.trim().split(/\n\n+/);
|
|
142
|
+
for (const block of blocks) {
|
|
143
|
+
if (!block.trim())
|
|
144
|
+
continue;
|
|
145
|
+
const lines = block.trim().split(`
|
|
146
|
+
`);
|
|
147
|
+
let path = "";
|
|
148
|
+
let head = "";
|
|
149
|
+
let branch = null;
|
|
150
|
+
let isBare = false;
|
|
151
|
+
for (const line of lines) {
|
|
152
|
+
if (line.startsWith("worktree ")) {
|
|
153
|
+
path = line.slice("worktree ".length);
|
|
154
|
+
} else if (line.startsWith("HEAD ")) {
|
|
155
|
+
head = line.slice("HEAD ".length);
|
|
156
|
+
} else if (line.startsWith("branch ")) {
|
|
157
|
+
const ref = line.slice("branch ".length);
|
|
158
|
+
branch = ref.startsWith("refs/heads/") ? ref.slice("refs/heads/".length) : ref;
|
|
159
|
+
} else if (line === "detached") {
|
|
160
|
+
branch = null;
|
|
161
|
+
} else if (line === "bare") {
|
|
162
|
+
isBare = true;
|
|
163
|
+
branch = null;
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
worktrees.push({ path, head, branch, isBare });
|
|
167
|
+
}
|
|
168
|
+
return worktrees;
|
|
169
|
+
}
|
|
170
|
+
async function listWorktrees2(repoPath) {
|
|
171
|
+
const result = run2("git", ["-C", repoPath, "worktree", "list", "--porcelain"]);
|
|
172
|
+
return parsePorcelain2(result.stdout);
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
// src/git.ts
|
|
176
|
+
async function git(args, options) {
|
|
177
|
+
const result = run2("git", args, {
|
|
178
|
+
cwd: options?.cwd,
|
|
179
|
+
env: options?.env ? { ...process.env, ...options.env } : undefined
|
|
180
|
+
});
|
|
181
|
+
return result.stdout;
|
|
182
|
+
}
|
|
183
|
+
async function setGitConfig(key, value, options) {
|
|
184
|
+
const env = {};
|
|
185
|
+
if (options?.gitdir)
|
|
186
|
+
env["GIT_DIR"] = options.gitdir;
|
|
187
|
+
await git(["config", key, value], { cwd: options?.cwd, env });
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
// src/migrate.ts
|
|
191
|
+
async function moveDir(src, dest) {
|
|
192
|
+
const destForStat = existsSync2(dest) ? dest : dirname(dest);
|
|
193
|
+
if (statSync2(src).dev === statSync2(destForStat).dev) {
|
|
194
|
+
renameSync(src, dest);
|
|
195
|
+
} else {
|
|
196
|
+
run2("cp", ["-a", src, dest]);
|
|
197
|
+
run2("rm", ["-rf", src]);
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
function sanitizeBranch(branch) {
|
|
201
|
+
return branch.replace(/\//g, "-");
|
|
202
|
+
}
|
|
203
|
+
async function migrate(config, options) {
|
|
204
|
+
const source = resolve2(options.source);
|
|
205
|
+
const dest = options.dest ? resolve2(options.dest) : join2(dirname(source), basename(source) + "-bare");
|
|
206
|
+
const destBare = join2(dest, ".bare");
|
|
207
|
+
if (existsSync2(destBare)) {
|
|
208
|
+
throw new Error(`'${destBare}' already exists`);
|
|
209
|
+
}
|
|
210
|
+
const allWorktrees = await listWorktrees2(source);
|
|
211
|
+
const worktrees = allWorktrees.filter((wt) => !wt.isBare);
|
|
212
|
+
const seen = new Map;
|
|
213
|
+
for (const wt of worktrees) {
|
|
214
|
+
const branch = wt.branch ?? `detached-${wt.head.slice(0, 8)}`;
|
|
215
|
+
const safe = sanitizeBranch(branch);
|
|
216
|
+
if (seen.has(safe)) {
|
|
217
|
+
throw new Error(`branch name collision: '${seen.get(safe)}' and '${branch}' both map to '${safe}'`);
|
|
218
|
+
}
|
|
219
|
+
seen.set(safe, branch);
|
|
220
|
+
}
|
|
221
|
+
mkdirSync(destBare, { recursive: true });
|
|
222
|
+
run2("cp", ["-a", config.gitdir + "/.", destBare + "/"]);
|
|
223
|
+
await setGitConfig("core.bare", "true", { gitdir: destBare });
|
|
224
|
+
await setGitConfig("remote.origin.fetch", "+refs/heads/*:refs/remotes/origin/*", { gitdir: destBare });
|
|
225
|
+
writeFileSync(join2(dest, ".git"), `gitdir: ./.bare
|
|
226
|
+
`);
|
|
227
|
+
if (config.type === "standard") {
|
|
228
|
+
const mainBranch = worktrees[0].branch;
|
|
229
|
+
const mainSafe = sanitizeBranch(mainBranch);
|
|
230
|
+
const mainDest = join2(dest, mainSafe);
|
|
231
|
+
const mainHeadContent = readFileSync2(join2(destBare, "HEAD"), "utf8");
|
|
232
|
+
run2("rm", ["-rf", join2(source, ".git")]);
|
|
233
|
+
await moveDir(source, mainDest);
|
|
234
|
+
const mainAdminDir = join2(destBare, "worktrees", mainSafe);
|
|
235
|
+
mkdirSync(mainAdminDir, { recursive: true });
|
|
236
|
+
writeFileSync(join2(mainAdminDir, "gitdir"), mainDest + `/.git
|
|
237
|
+
`);
|
|
238
|
+
writeFileSync(join2(mainAdminDir, "commondir"), `../../
|
|
239
|
+
`);
|
|
240
|
+
const headToWrite = mainHeadContent.endsWith(`
|
|
241
|
+
`) ? mainHeadContent : mainHeadContent + `
|
|
242
|
+
`;
|
|
243
|
+
writeFileSync(join2(mainAdminDir, "HEAD"), headToWrite);
|
|
244
|
+
const bareIndex = join2(destBare, "index");
|
|
245
|
+
if (existsSync2(bareIndex)) {
|
|
246
|
+
renameSync(bareIndex, join2(mainAdminDir, "index"));
|
|
247
|
+
}
|
|
248
|
+
writeFileSync(join2(mainDest, ".git"), `gitdir: ${mainAdminDir}
|
|
249
|
+
`);
|
|
250
|
+
for (let i = 1;i < worktrees.length; i++) {
|
|
251
|
+
await processLinkedWorktree(worktrees[i], dest, destBare);
|
|
252
|
+
}
|
|
253
|
+
} else {
|
|
254
|
+
for (const wt of worktrees) {
|
|
255
|
+
await processLinkedWorktree(wt, dest, destBare);
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
return dest;
|
|
259
|
+
}
|
|
260
|
+
async function processLinkedWorktree(wt, dest, destBare) {
|
|
261
|
+
const wtSrc = wt.path;
|
|
262
|
+
const wtBranch = wt.branch ?? `detached-${wt.head.slice(0, 8)}`;
|
|
263
|
+
const wtSafe = sanitizeBranch(wtBranch);
|
|
264
|
+
const wtDest = join2(dest, wtSafe);
|
|
265
|
+
await moveDir(wtSrc, wtDest);
|
|
266
|
+
const gitFileContent = readFileSync2(join2(wtDest, ".git"), "utf8");
|
|
267
|
+
const match = gitFileContent.match(/^gitdir:\s*(.+)/m);
|
|
268
|
+
if (!match) {
|
|
269
|
+
console.warn(`Could not parse .git file in ${wtDest}`);
|
|
270
|
+
return;
|
|
271
|
+
}
|
|
272
|
+
const oldPath = match[1].trim();
|
|
273
|
+
const adminName = basename(oldPath);
|
|
274
|
+
const newAdmin = join2(destBare, "worktrees", adminName);
|
|
275
|
+
writeFileSync(join2(wtDest, ".git"), `gitdir: ${newAdmin}
|
|
276
|
+
`);
|
|
277
|
+
if (existsSync2(newAdmin)) {
|
|
278
|
+
writeFileSync(join2(newAdmin, "gitdir"), wtDest + `/.git
|
|
279
|
+
`);
|
|
280
|
+
} else {
|
|
281
|
+
console.warn(`Admin dir ${newAdmin} does not exist for worktree ${wtDest}`);
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
// src/cli.ts
|
|
286
|
+
var GREEN = "\x1B[32m";
|
|
287
|
+
var YELLOW = "\x1B[33m";
|
|
288
|
+
var BOLD = "\x1B[1m";
|
|
289
|
+
var RESET = "\x1B[0m";
|
|
290
|
+
function green(s) {
|
|
291
|
+
return `${GREEN}${s}${RESET}`;
|
|
292
|
+
}
|
|
293
|
+
function yellow(s) {
|
|
294
|
+
return `${YELLOW}${s}${RESET}`;
|
|
295
|
+
}
|
|
296
|
+
function bold(s) {
|
|
297
|
+
return `${BOLD}${s}${RESET}`;
|
|
298
|
+
}
|
|
299
|
+
function usage() {
|
|
300
|
+
console.log(`Usage: git-worktree-organize <source> [destination]
|
|
301
|
+
|
|
302
|
+
Convert a git repository into the canonical bare-hub worktree layout:
|
|
303
|
+
|
|
304
|
+
<dest>/.bare/ \u2190 bare git repo
|
|
305
|
+
<dest>/.git \u2190 plain file: "gitdir: ./.bare"
|
|
306
|
+
<dest>/<branch>/ \u2190 one directory per worktree
|
|
307
|
+
|
|
308
|
+
Arguments:
|
|
309
|
+
source Path to existing git repository
|
|
310
|
+
destination Target hub directory (default: <parent>/<name>-bare)
|
|
311
|
+
|
|
312
|
+
Options:
|
|
313
|
+
-h, --help Show help`);
|
|
314
|
+
}
|
|
315
|
+
async function main() {
|
|
316
|
+
const args = process.argv.slice(2);
|
|
317
|
+
if (args.length === 0 || args[0] === "-h" || args[0] === "--help") {
|
|
318
|
+
usage();
|
|
319
|
+
process.exit(0);
|
|
320
|
+
}
|
|
321
|
+
const sourcePath = args[0];
|
|
322
|
+
const destArg = args[1];
|
|
323
|
+
const source = resolve3(sourcePath);
|
|
324
|
+
const dest = destArg ? resolve3(destArg) : join3(dirname2(source), basename2(source) + "-bare");
|
|
325
|
+
console.log(`
|
|
326
|
+
${green("==>")} Reading worktrees from ${source}
|
|
327
|
+
`);
|
|
328
|
+
const config = await detect(source);
|
|
329
|
+
const allWorktrees = await listWorktrees(source);
|
|
330
|
+
const worktrees = allWorktrees.filter((wt) => !wt.isBare);
|
|
331
|
+
let mainBranch = null;
|
|
332
|
+
if (config.type === "standard" && worktrees.length > 0) {
|
|
333
|
+
mainBranch = worktrees[0].branch;
|
|
334
|
+
}
|
|
335
|
+
console.log("Worktrees to migrate:");
|
|
336
|
+
const entries = worktrees.map((wt) => {
|
|
337
|
+
const branch = wt.branch ?? `detached-${wt.head.slice(0, 8)}`;
|
|
338
|
+
const safe = sanitizeBranch(branch);
|
|
339
|
+
const isMain = branch === mainBranch;
|
|
340
|
+
const destDir = join3(dest, safe);
|
|
341
|
+
return { branch, isMain, destDir };
|
|
342
|
+
});
|
|
343
|
+
const maxNameLen = entries.reduce((m, e) => Math.max(m, e.branch.length), 0);
|
|
344
|
+
for (const { branch, isMain, destDir } of entries) {
|
|
345
|
+
const tag = isMain ? yellow("[main]") : "";
|
|
346
|
+
const tagPad = isMain ? ` (labeled ${yellow("[main]")})` : "";
|
|
347
|
+
const nameCol = bold(`[${branch}]`).padEnd(maxNameLen + 2 + BOLD.length + RESET.length);
|
|
348
|
+
const annotation = isMain ? ` (labeled ${yellow("[main]")})`.padEnd(18 + YELLOW.length + RESET.length) : "".padEnd(18);
|
|
349
|
+
console.log(` ${nameCol}${annotation} \u2192 ${destDir}`);
|
|
350
|
+
}
|
|
351
|
+
console.log();
|
|
352
|
+
console.log(`Hub destination: ${bold(dest)} (bare repo at ${dest}/.bare)`);
|
|
353
|
+
console.log();
|
|
354
|
+
process.stdout.write("Proceed? [y/N] ");
|
|
355
|
+
const ans = await new Promise((resolve4) => {
|
|
356
|
+
process.stdin.setEncoding("utf8");
|
|
357
|
+
process.stdin.once("data", (chunk) => resolve4(chunk.toString().trim()));
|
|
358
|
+
});
|
|
359
|
+
process.stdin.destroy();
|
|
360
|
+
if (!/^[Yy]$/.test(ans)) {
|
|
361
|
+
console.log("Aborted.");
|
|
362
|
+
process.exit(0);
|
|
363
|
+
}
|
|
364
|
+
console.log();
|
|
365
|
+
const hubPath = await migrate(config, { source: sourcePath, dest: destArg ?? "" });
|
|
366
|
+
console.log(`${green("==>")} Verifying with git worktree list...`);
|
|
367
|
+
const verifyOutput = run("git", ["-C", hubPath, "worktree", "list"]).stdout;
|
|
368
|
+
console.log(verifyOutput);
|
|
369
|
+
console.log(`Done! Hub: ${hubPath}`);
|
|
370
|
+
console.log();
|
|
371
|
+
const mainSafe = mainBranch ? sanitizeBranch(mainBranch) : entries[0]?.branch ? sanitizeBranch(entries[0].branch) : "";
|
|
372
|
+
console.log("Useful commands:");
|
|
373
|
+
console.log(` git -C ${hubPath} worktree list`);
|
|
374
|
+
if (mainSafe) {
|
|
375
|
+
console.log(` git -C ${hubPath}/${mainSafe} log --oneline -5`);
|
|
376
|
+
}
|
|
377
|
+
}
|
|
378
|
+
main().catch((err) => {
|
|
379
|
+
process.stderr.write(`error: ${err.message}
|
|
380
|
+
`);
|
|
381
|
+
process.exit(1);
|
|
382
|
+
});
|
package/package.json
CHANGED
|
@@ -1,16 +1,20 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "git-worktree-organize",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.10",
|
|
4
4
|
"description": "Convert any git repo into the canonical bare-hub worktree layout",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
7
|
-
"git-worktree-organize": "./
|
|
7
|
+
"git-worktree-organize": "./dist/cli.js"
|
|
8
8
|
},
|
|
9
|
+
"files": [
|
|
10
|
+
"dist/"
|
|
11
|
+
],
|
|
9
12
|
"scripts": {
|
|
10
13
|
"build": "bun build src/cli.ts --outfile dist/cli.js --target node",
|
|
14
|
+
"prepublishOnly": "bun run build",
|
|
11
15
|
"test": "bun test",
|
|
12
16
|
"test:watch": "vitest",
|
|
13
|
-
"
|
|
17
|
+
"release": "op run -- npm publish"
|
|
14
18
|
},
|
|
15
19
|
"devDependencies": {
|
|
16
20
|
"@types/bun": "latest",
|
package/.beads/README.md
DELETED
|
@@ -1,81 +0,0 @@
|
|
|
1
|
-
# Beads - AI-Native Issue Tracking
|
|
2
|
-
|
|
3
|
-
Welcome to Beads! This repository uses **Beads** for issue tracking - a modern, AI-native tool designed to live directly in your codebase alongside your code.
|
|
4
|
-
|
|
5
|
-
## What is Beads?
|
|
6
|
-
|
|
7
|
-
Beads is issue tracking that lives in your repo, making it perfect for AI coding agents and developers who want their issues close to their code. No web UI required - everything works through the CLI and integrates seamlessly with git.
|
|
8
|
-
|
|
9
|
-
**Learn more:** [github.com/steveyegge/beads](https://github.com/steveyegge/beads)
|
|
10
|
-
|
|
11
|
-
## Quick Start
|
|
12
|
-
|
|
13
|
-
### Essential Commands
|
|
14
|
-
|
|
15
|
-
```bash
|
|
16
|
-
# Create new issues
|
|
17
|
-
bd create "Add user authentication"
|
|
18
|
-
|
|
19
|
-
# View all issues
|
|
20
|
-
bd list
|
|
21
|
-
|
|
22
|
-
# View issue details
|
|
23
|
-
bd show <issue-id>
|
|
24
|
-
|
|
25
|
-
# Update issue status
|
|
26
|
-
bd update <issue-id> --claim
|
|
27
|
-
bd update <issue-id> --status done
|
|
28
|
-
|
|
29
|
-
# Sync with Dolt remote
|
|
30
|
-
bd dolt push
|
|
31
|
-
```
|
|
32
|
-
|
|
33
|
-
### Working with Issues
|
|
34
|
-
|
|
35
|
-
Issues in Beads are:
|
|
36
|
-
- **Git-native**: Stored in `.beads/issues.jsonl` and synced like code
|
|
37
|
-
- **AI-friendly**: CLI-first design works perfectly with AI coding agents
|
|
38
|
-
- **Branch-aware**: Issues can follow your branch workflow
|
|
39
|
-
- **Always in sync**: Auto-syncs with your commits
|
|
40
|
-
|
|
41
|
-
## Why Beads?
|
|
42
|
-
|
|
43
|
-
✨ **AI-Native Design**
|
|
44
|
-
- Built specifically for AI-assisted development workflows
|
|
45
|
-
- CLI-first interface works seamlessly with AI coding agents
|
|
46
|
-
- No context switching to web UIs
|
|
47
|
-
|
|
48
|
-
🚀 **Developer Focused**
|
|
49
|
-
- Issues live in your repo, right next to your code
|
|
50
|
-
- Works offline, syncs when you push
|
|
51
|
-
- Fast, lightweight, and stays out of your way
|
|
52
|
-
|
|
53
|
-
🔧 **Git Integration**
|
|
54
|
-
- Automatic sync with git commits
|
|
55
|
-
- Branch-aware issue tracking
|
|
56
|
-
- Intelligent JSONL merge resolution
|
|
57
|
-
|
|
58
|
-
## Get Started with Beads
|
|
59
|
-
|
|
60
|
-
Try Beads in your own projects:
|
|
61
|
-
|
|
62
|
-
```bash
|
|
63
|
-
# Install Beads
|
|
64
|
-
curl -sSL https://raw.githubusercontent.com/steveyegge/beads/main/scripts/install.sh | bash
|
|
65
|
-
|
|
66
|
-
# Initialize in your repo
|
|
67
|
-
bd init
|
|
68
|
-
|
|
69
|
-
# Create your first issue
|
|
70
|
-
bd create "Try out Beads"
|
|
71
|
-
```
|
|
72
|
-
|
|
73
|
-
## Learn More
|
|
74
|
-
|
|
75
|
-
- **Documentation**: [github.com/steveyegge/beads/docs](https://github.com/steveyegge/beads/tree/main/docs)
|
|
76
|
-
- **Quick Start Guide**: Run `bd quickstart`
|
|
77
|
-
- **Examples**: [github.com/steveyegge/beads/examples](https://github.com/steveyegge/beads/tree/main/examples)
|
|
78
|
-
|
|
79
|
-
---
|
|
80
|
-
|
|
81
|
-
*Beads: Issue tracking that moves at the speed of thought* ⚡
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"last_dolt_commit": "l1dnbhthsfgi9v89teho6b2efhklvlv0",
|
|
3
|
-
"last_event_id": 0,
|
|
4
|
-
"timestamp": "2026-03-06T13:05:38.518606871Z",
|
|
5
|
-
"counts": {
|
|
6
|
-
"issues": 9,
|
|
7
|
-
"events": 31,
|
|
8
|
-
"comments": 0,
|
|
9
|
-
"dependencies": 10,
|
|
10
|
-
"labels": 0,
|
|
11
|
-
"config": 11
|
|
12
|
-
}
|
|
13
|
-
}
|
|
File without changes
|
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
{"key":"auto_compact_enabled","value":"false"}
|
|
2
|
-
{"key":"compact_batch_size","value":"50"}
|
|
3
|
-
{"key":"compact_parallel_workers","value":"5"}
|
|
4
|
-
{"key":"compact_tier1_days","value":"30"}
|
|
5
|
-
{"key":"compact_tier1_dep_levels","value":"2"}
|
|
6
|
-
{"key":"compact_tier2_commits","value":"100"}
|
|
7
|
-
{"key":"compact_tier2_days","value":"90"}
|
|
8
|
-
{"key":"compact_tier2_dep_levels","value":"5"}
|
|
9
|
-
{"key":"compaction_enabled","value":"false"}
|
|
10
|
-
{"key":"issue_prefix","value":"git-worktree-organize"}
|
|
11
|
-
{"key":"schema_version","value":"6"}
|
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
{"created_at":"2026-03-05T23:28:12Z","created_by":"Mike Crowe","depends_on_id":"git-worktree-organize-pa7","issue_id":"git-worktree-organize-3h1","type":"blocks"}
|
|
2
|
-
{"created_at":"2026-03-05T23:28:12Z","created_by":"Mike Crowe","depends_on_id":"git-worktree-organize-3h1","issue_id":"git-worktree-organize-53n","type":"blocks"}
|
|
3
|
-
{"created_at":"2026-03-05T23:28:12Z","created_by":"Mike Crowe","depends_on_id":"git-worktree-organize-jnu","issue_id":"git-worktree-organize-5ea","type":"blocks"}
|
|
4
|
-
{"created_at":"2026-03-05T23:28:12Z","created_by":"Mike Crowe","depends_on_id":"git-worktree-organize-q2e","issue_id":"git-worktree-organize-5ea","type":"blocks"}
|
|
5
|
-
{"created_at":"2026-03-05T23:28:12Z","created_by":"Mike Crowe","depends_on_id":"git-worktree-organize-t83","issue_id":"git-worktree-organize-5ea","type":"blocks"}
|
|
6
|
-
{"created_at":"2026-03-05T23:28:12Z","created_by":"Mike Crowe","depends_on_id":"git-worktree-organize-3yq","issue_id":"git-worktree-organize-7sk","type":"blocks"}
|
|
7
|
-
{"created_at":"2026-03-05T23:28:12Z","created_by":"Mike Crowe","depends_on_id":"git-worktree-organize-7sk","issue_id":"git-worktree-organize-jnu","type":"blocks"}
|
|
8
|
-
{"created_at":"2026-03-05T23:28:12Z","created_by":"Mike Crowe","depends_on_id":"git-worktree-organize-5ea","issue_id":"git-worktree-organize-pa7","type":"blocks"}
|
|
9
|
-
{"created_at":"2026-03-05T23:28:12Z","created_by":"Mike Crowe","depends_on_id":"git-worktree-organize-7sk","issue_id":"git-worktree-organize-q2e","type":"blocks"}
|
|
10
|
-
{"created_at":"2026-03-05T23:28:12Z","created_by":"Mike Crowe","depends_on_id":"git-worktree-organize-7sk","issue_id":"git-worktree-organize-t83","type":"blocks"}
|
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
{"actor":"Mike Crowe","comment":null,"created_at":"2026-03-05T23:27:46Z","event_type":"created","id":1,"issue_id":"git-worktree-organize-3yq","new_value":"","old_value":""}
|
|
2
|
-
{"actor":"Mike Crowe","comment":null,"created_at":"2026-03-05T23:27:46Z","event_type":"created","id":2,"issue_id":"git-worktree-organize-7sk","new_value":"","old_value":""}
|
|
3
|
-
{"actor":"Mike Crowe","comment":null,"created_at":"2026-03-05T23:27:54Z","event_type":"created","id":3,"issue_id":"git-worktree-organize-t83","new_value":"","old_value":""}
|
|
4
|
-
{"actor":"Mike Crowe","comment":null,"created_at":"2026-03-05T23:27:54Z","event_type":"created","id":4,"issue_id":"git-worktree-organize-q2e","new_value":"","old_value":""}
|
|
5
|
-
{"actor":"Mike Crowe","comment":null,"created_at":"2026-03-05T23:27:54Z","event_type":"created","id":5,"issue_id":"git-worktree-organize-jnu","new_value":"","old_value":""}
|
|
6
|
-
{"actor":"Mike Crowe","comment":null,"created_at":"2026-03-05T23:28:02Z","event_type":"created","id":6,"issue_id":"git-worktree-organize-3h1","new_value":"","old_value":""}
|
|
7
|
-
{"actor":"Mike Crowe","comment":null,"created_at":"2026-03-05T23:28:02Z","event_type":"created","id":7,"issue_id":"git-worktree-organize-5ea","new_value":"","old_value":""}
|
|
8
|
-
{"actor":"Mike Crowe","comment":null,"created_at":"2026-03-05T23:28:02Z","event_type":"created","id":8,"issue_id":"git-worktree-organize-pa7","new_value":"","old_value":""}
|
|
9
|
-
{"actor":"Mike Crowe","comment":null,"created_at":"2026-03-05T23:28:02Z","event_type":"created","id":9,"issue_id":"git-worktree-organize-53n","new_value":"","old_value":""}
|
|
10
|
-
{"actor":"Mike Crowe","comment":null,"created_at":"2026-03-06T06:17:41Z","event_type":"closed","id":10,"issue_id":"git-worktree-organize-53n","new_value":"Removed — not tracking npm publish as a task","old_value":""}
|
|
11
|
-
{"actor":"Mike Crowe","comment":null,"created_at":"2026-03-06T06:24:30Z","event_type":"status_changed","id":11,"issue_id":"git-worktree-organize-3yq","new_value":"{\"status\":\"in_progress\"}","old_value":"{\"id\":\"git-worktree-organize-3yq\",\"title\":\"Set up package.json for Bun + TypeScript + Vitest\",\"description\":\"Configure package.json with correct bin entry, scripts (build, test), deps (typescript, vitest, @types/bun), tsconfig.json. Stack: Bun runtime, TypeScript, Vitest.\",\"status\":\"open\",\"priority\":0,\"issue_type\":\"task\",\"owner\":\"drmikecrowe@gmail.com\",\"created_at\":\"2026-03-06T04:27:47Z\",\"created_by\":\"Mike Crowe\",\"updated_at\":\"2026-03-06T04:27:47Z\"}"}
|
|
12
|
-
{"actor":"Mike Crowe","comment":null,"created_at":"2026-03-06T06:25:33Z","event_type":"closed","id":12,"issue_id":"git-worktree-organize-3yq","new_value":"Closed","old_value":""}
|
|
13
|
-
{"actor":"Mike Crowe","comment":null,"created_at":"2026-03-06T06:25:33Z","event_type":"status_changed","id":13,"issue_id":"git-worktree-organize-7sk","new_value":"{\"status\":\"in_progress\"}","old_value":"{\"id\":\"git-worktree-organize-7sk\",\"title\":\"Scaffold source files with types and stubs\",\"description\":\"Create src/cli.ts, src/detect.ts, src/worktrees.ts, src/migrate.ts, src/git.ts, src/fs.ts with the types from AGENT_HANDOVER.md (RepoConfig, Worktree) and stub implementations.\",\"status\":\"open\",\"priority\":0,\"issue_type\":\"task\",\"owner\":\"drmikecrowe@gmail.com\",\"created_at\":\"2026-03-06T04:27:47Z\",\"created_by\":\"Mike Crowe\",\"updated_at\":\"2026-03-06T04:27:47Z\"}"}
|
|
14
|
-
{"actor":"Mike Crowe","comment":null,"created_at":"2026-03-06T06:26:35Z","event_type":"closed","id":14,"issue_id":"git-worktree-organize-7sk","new_value":"Closed","old_value":""}
|
|
15
|
-
{"actor":"Mike Crowe","comment":null,"created_at":"2026-03-06T06:26:38Z","event_type":"status_changed","id":15,"issue_id":"git-worktree-organize-jnu","new_value":"{\"status\":\"in_progress\"}","old_value":"{\"id\":\"git-worktree-organize-jnu\",\"title\":\"Implement git.ts and fs.ts thin wrappers\",\"description\":\"git.ts: run git commands, read git config. fs.ts: move/copy with cross-filesystem detection via statSync().dev. These are the only modules that touch the real system.\",\"status\":\"open\",\"priority\":1,\"issue_type\":\"feature\",\"owner\":\"drmikecrowe@gmail.com\",\"created_at\":\"2026-03-06T04:27:55Z\",\"created_by\":\"Mike Crowe\",\"updated_at\":\"2026-03-06T04:27:55Z\"}"}
|
|
16
|
-
{"actor":"Mike Crowe","comment":null,"created_at":"2026-03-06T06:26:39Z","event_type":"status_changed","id":16,"issue_id":"git-worktree-organize-q2e","new_value":"{\"status\":\"in_progress\"}","old_value":"{\"id\":\"git-worktree-organize-q2e\",\"title\":\"Implement worktrees.ts + tests\",\"description\":\"Parse git worktree list --porcelain output into typed Worktree[]. Handle bare, linked, detached HEAD cases. Tests in test/worktrees.test.ts.\",\"status\":\"open\",\"priority\":1,\"issue_type\":\"feature\",\"owner\":\"drmikecrowe@gmail.com\",\"created_at\":\"2026-03-06T04:27:55Z\",\"created_by\":\"Mike Crowe\",\"updated_at\":\"2026-03-06T04:27:55Z\"}"}
|
|
17
|
-
{"actor":"Mike Crowe","comment":null,"created_at":"2026-03-06T06:26:39Z","event_type":"status_changed","id":17,"issue_id":"git-worktree-organize-t83","new_value":"{\"status\":\"in_progress\"}","old_value":"{\"id\":\"git-worktree-organize-t83\",\"title\":\"Implement detect.ts + full test suite\",\"description\":\"Implement all 7 detection cases from the detection matrix: standard, bare-hub, bare-root, bare-dotgit, bare-external, reject-linked-worktree, reject-not-a-repo. Tests in test/detect.test.ts using real git repos in tmpdir.\",\"status\":\"open\",\"priority\":1,\"issue_type\":\"feature\",\"owner\":\"drmikecrowe@gmail.com\",\"created_at\":\"2026-03-06T04:27:55Z\",\"created_by\":\"Mike Crowe\",\"updated_at\":\"2026-03-06T04:27:55Z\"}"}
|
|
18
|
-
{"actor":"Mike Crowe","comment":null,"created_at":"2026-03-06T06:27:31Z","event_type":"closed","id":18,"issue_id":"git-worktree-organize-jnu","new_value":"Closed","old_value":""}
|
|
19
|
-
{"actor":"Mike Crowe","comment":null,"created_at":"2026-03-06T06:29:41Z","event_type":"closed","id":19,"issue_id":"git-worktree-organize-q2e","new_value":"Closed","old_value":""}
|
|
20
|
-
{"actor":"Mike Crowe","comment":null,"created_at":"2026-03-06T06:30:04Z","event_type":"closed","id":20,"issue_id":"git-worktree-organize-t83","new_value":"Closed","old_value":""}
|
|
21
|
-
{"actor":"Mike Crowe","comment":null,"created_at":"2026-03-06T06:30:25Z","event_type":"closed","id":21,"issue_id":"git-worktree-organize-jnu","new_value":"Closed","old_value":""}
|
|
22
|
-
{"actor":"Mike Crowe","comment":null,"created_at":"2026-03-06T06:30:26Z","event_type":"closed","id":22,"issue_id":"git-worktree-organize-q2e","new_value":"Closed","old_value":""}
|
|
23
|
-
{"actor":"Mike Crowe","comment":null,"created_at":"2026-03-06T06:30:26Z","event_type":"closed","id":23,"issue_id":"git-worktree-organize-t83","new_value":"Closed","old_value":""}
|
|
24
|
-
{"actor":"Mike Crowe","comment":null,"created_at":"2026-03-06T06:32:04Z","event_type":"status_changed","id":24,"issue_id":"git-worktree-organize-5ea","new_value":"{\"status\":\"in_progress\"}","old_value":"{\"id\":\"git-worktree-organize-5ea\",\"title\":\"Implement migrate.ts + full test suite\",\"description\":\"Orchestrate the full migration for all repo config types. Tests: standard→hub, bare-root→hub, bare-hub→new location, no worktrees→hub, cross-filesystem, branch with / sanitized to -, collision detection.\",\"status\":\"open\",\"priority\":2,\"issue_type\":\"feature\",\"owner\":\"drmikecrowe@gmail.com\",\"created_at\":\"2026-03-06T04:28:03Z\",\"created_by\":\"Mike Crowe\",\"updated_at\":\"2026-03-06T04:28:03Z\"}"}
|
|
25
|
-
{"actor":"Mike Crowe","comment":null,"created_at":"2026-03-06T06:35:54Z","event_type":"closed","id":25,"issue_id":"git-worktree-organize-5ea","new_value":"Closed","old_value":""}
|
|
26
|
-
{"actor":"Mike Crowe","comment":null,"created_at":"2026-03-06T06:36:16Z","event_type":"closed","id":26,"issue_id":"git-worktree-organize-5ea","new_value":"Closed","old_value":""}
|
|
27
|
-
{"actor":"Mike Crowe","comment":null,"created_at":"2026-03-06T06:36:25Z","event_type":"status_changed","id":27,"issue_id":"git-worktree-organize-pa7","new_value":"{\"status\":\"in_progress\"}","old_value":"{\"id\":\"git-worktree-organize-pa7\",\"title\":\"Implement cli.ts entry point\",\"description\":\"Arg parsing (citty or yargs), interactive confirmation prompt, formatted output matching bash prototype (colors, worktree preview table, done message). Wire up npx binary entry.\",\"status\":\"open\",\"priority\":2,\"issue_type\":\"feature\",\"owner\":\"drmikecrowe@gmail.com\",\"created_at\":\"2026-03-06T04:28:03Z\",\"created_by\":\"Mike Crowe\",\"updated_at\":\"2026-03-06T04:28:03Z\"}"}
|
|
28
|
-
{"actor":"Mike Crowe","comment":null,"created_at":"2026-03-06T06:37:52Z","event_type":"closed","id":28,"issue_id":"git-worktree-organize-pa7","new_value":"Closed","old_value":""}
|
|
29
|
-
{"actor":"Mike Crowe","comment":null,"created_at":"2026-03-06T06:38:11Z","event_type":"closed","id":29,"issue_id":"git-worktree-organize-pa7","new_value":"Closed","old_value":""}
|
|
30
|
-
{"actor":"Mike Crowe","comment":null,"created_at":"2026-03-06T06:38:11Z","event_type":"status_changed","id":30,"issue_id":"git-worktree-organize-3h1","new_value":"{\"status\":\"in_progress\"}","old_value":"{\"id\":\"git-worktree-organize-3h1\",\"title\":\"Write README\",\"description\":\"Document usage, installation methods (npx, direct install), what the tool does, before/after directory structure examples.\",\"status\":\"open\",\"priority\":3,\"issue_type\":\"task\",\"owner\":\"drmikecrowe@gmail.com\",\"created_at\":\"2026-03-06T04:28:03Z\",\"created_by\":\"Mike Crowe\",\"updated_at\":\"2026-03-06T04:28:03Z\"}"}
|
|
31
|
-
{"actor":"Mike Crowe","comment":null,"created_at":"2026-03-06T06:39:00Z","event_type":"closed","id":31,"issue_id":"git-worktree-organize-3h1","new_value":"Closed","old_value":""}
|
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
{"acceptance_criteria":"","actor":"","agent_state":"","assignee":null,"await_id":"","await_type":"","close_reason":"Closed","closed_at":"2026-03-06T11:39:01Z","closed_by_session":"","compacted_at":null,"compacted_at_commit":null,"compaction_level":0,"content_hash":"561f6b5866ebbb03db36aa8f14a46eb580c05a0691c30814cefe8d90133a6dfc","created_at":"2026-03-06T04:28:03Z","created_by":"Mike Crowe","crystallizes":0,"defer_until":null,"description":"Document usage, installation methods (npx, direct install), what the tool does, before/after directory structure examples.","design":"","due_at":null,"ephemeral":0,"estimated_minutes":null,"event_kind":"","external_ref":null,"hook_bead":"","id":"git-worktree-organize-3h1","is_template":0,"issue_type":"task","last_activity":null,"metadata":"{}","mol_type":"","notes":"","original_size":null,"owner":"drmikecrowe@gmail.com","payload":"","pinned":0,"priority":3,"quality_score":null,"rig":"","role_bead":"","role_type":"","sender":"","source_repo":"","source_system":"","spec_id":"","status":"closed","target":"","timeout_ns":0,"title":"Write README","updated_at":"2026-03-06T11:39:01Z","waiters":"","wisp_type":"","work_type":""}
|
|
2
|
-
{"acceptance_criteria":"","actor":"","agent_state":"","assignee":null,"await_id":"","await_type":"","close_reason":"Closed","closed_at":"2026-03-06T11:25:33Z","closed_by_session":"","compacted_at":null,"compacted_at_commit":null,"compaction_level":0,"content_hash":"fb0acfcdb0465d4f5b9dc129ddeb6d91efd79069adc8d86ad1acb4e207809b4a","created_at":"2026-03-06T04:27:47Z","created_by":"Mike Crowe","crystallizes":0,"defer_until":null,"description":"Configure package.json with correct bin entry, scripts (build, test), deps (typescript, vitest, @types/bun), tsconfig.json. Stack: Bun runtime, TypeScript, Vitest.","design":"","due_at":null,"ephemeral":0,"estimated_minutes":null,"event_kind":"","external_ref":null,"hook_bead":"","id":"git-worktree-organize-3yq","is_template":0,"issue_type":"task","last_activity":null,"metadata":"{}","mol_type":"","notes":"","original_size":null,"owner":"drmikecrowe@gmail.com","payload":"","pinned":0,"priority":0,"quality_score":null,"rig":"","role_bead":"","role_type":"","sender":"","source_repo":"","source_system":"","spec_id":"","status":"closed","target":"","timeout_ns":0,"title":"Set up package.json for Bun + TypeScript + Vitest","updated_at":"2026-03-06T11:25:33Z","waiters":"","wisp_type":"","work_type":""}
|
|
3
|
-
{"acceptance_criteria":"","actor":"","agent_state":"","assignee":null,"await_id":"","await_type":"","close_reason":"Removed — not tracking npm publish as a task","closed_at":"2026-03-06T11:17:42Z","closed_by_session":"","compacted_at":null,"compacted_at_commit":null,"compaction_level":0,"content_hash":"dd2362b7ac9b221851317c89933365a9244782bf7e243b487f0f58cbfcc3731e","created_at":"2026-03-06T04:28:03Z","created_by":"Mike Crowe","crystallizes":0,"defer_until":null,"description":"Verify npx git-worktree-organize works locally, then publish package to npm registry.","design":"","due_at":null,"ephemeral":0,"estimated_minutes":null,"event_kind":"","external_ref":null,"hook_bead":"","id":"git-worktree-organize-53n","is_template":0,"issue_type":"task","last_activity":null,"metadata":"{}","mol_type":"","notes":"","original_size":null,"owner":"drmikecrowe@gmail.com","payload":"","pinned":0,"priority":4,"quality_score":null,"rig":"","role_bead":"","role_type":"","sender":"","source_repo":"","source_system":"","spec_id":"","status":"closed","target":"","timeout_ns":0,"title":"Publish to npm","updated_at":"2026-03-06T11:17:42Z","waiters":"","wisp_type":"","work_type":""}
|
|
4
|
-
{"acceptance_criteria":"","actor":"","agent_state":"","assignee":null,"await_id":"","await_type":"","close_reason":"Closed","closed_at":"2026-03-06T11:36:16Z","closed_by_session":"","compacted_at":null,"compacted_at_commit":null,"compaction_level":0,"content_hash":"ee988a5cd9bba616c11f15991543ca2991525f0ccf7a42570e78f6d58305eb1d","created_at":"2026-03-06T04:28:03Z","created_by":"Mike Crowe","crystallizes":0,"defer_until":null,"description":"Orchestrate the full migration for all repo config types. Tests: standard→hub, bare-root→hub, bare-hub→new location, no worktrees→hub, cross-filesystem, branch with / sanitized to -, collision detection.","design":"","due_at":null,"ephemeral":0,"estimated_minutes":null,"event_kind":"","external_ref":null,"hook_bead":"","id":"git-worktree-organize-5ea","is_template":0,"issue_type":"feature","last_activity":null,"metadata":"{}","mol_type":"","notes":"","original_size":null,"owner":"drmikecrowe@gmail.com","payload":"","pinned":0,"priority":2,"quality_score":null,"rig":"","role_bead":"","role_type":"","sender":"","source_repo":"","source_system":"","spec_id":"","status":"closed","target":"","timeout_ns":0,"title":"Implement migrate.ts + full test suite","updated_at":"2026-03-06T11:36:16Z","waiters":"","wisp_type":"","work_type":""}
|
|
5
|
-
{"acceptance_criteria":"","actor":"","agent_state":"","assignee":null,"await_id":"","await_type":"","close_reason":"Closed","closed_at":"2026-03-06T11:26:36Z","closed_by_session":"","compacted_at":null,"compacted_at_commit":null,"compaction_level":0,"content_hash":"7aabd95b4fd55f537a1de1d736dcf6dfbc2bdb4606022497d617bd4327f0d176","created_at":"2026-03-06T04:27:47Z","created_by":"Mike Crowe","crystallizes":0,"defer_until":null,"description":"Create src/cli.ts, src/detect.ts, src/worktrees.ts, src/migrate.ts, src/git.ts, src/fs.ts with the types from AGENT_HANDOVER.md (RepoConfig, Worktree) and stub implementations.","design":"","due_at":null,"ephemeral":0,"estimated_minutes":null,"event_kind":"","external_ref":null,"hook_bead":"","id":"git-worktree-organize-7sk","is_template":0,"issue_type":"task","last_activity":null,"metadata":"{}","mol_type":"","notes":"","original_size":null,"owner":"drmikecrowe@gmail.com","payload":"","pinned":0,"priority":0,"quality_score":null,"rig":"","role_bead":"","role_type":"","sender":"","source_repo":"","source_system":"","spec_id":"","status":"closed","target":"","timeout_ns":0,"title":"Scaffold source files with types and stubs","updated_at":"2026-03-06T11:26:36Z","waiters":"","wisp_type":"","work_type":""}
|
|
6
|
-
{"acceptance_criteria":"","actor":"","agent_state":"","assignee":null,"await_id":"","await_type":"","close_reason":"Closed","closed_at":"2026-03-06T11:30:26Z","closed_by_session":"","compacted_at":null,"compacted_at_commit":null,"compaction_level":0,"content_hash":"0a01642f655d9349862290f82014254401d6614d5160b5763253fd6738775dea","created_at":"2026-03-06T04:27:55Z","created_by":"Mike Crowe","crystallizes":0,"defer_until":null,"description":"git.ts: run git commands, read git config. fs.ts: move/copy with cross-filesystem detection via statSync().dev. These are the only modules that touch the real system.","design":"","due_at":null,"ephemeral":0,"estimated_minutes":null,"event_kind":"","external_ref":null,"hook_bead":"","id":"git-worktree-organize-jnu","is_template":0,"issue_type":"feature","last_activity":null,"metadata":"{}","mol_type":"","notes":"","original_size":null,"owner":"drmikecrowe@gmail.com","payload":"","pinned":0,"priority":1,"quality_score":null,"rig":"","role_bead":"","role_type":"","sender":"","source_repo":"","source_system":"","spec_id":"","status":"closed","target":"","timeout_ns":0,"title":"Implement git.ts and fs.ts thin wrappers","updated_at":"2026-03-06T11:30:26Z","waiters":"","wisp_type":"","work_type":""}
|
|
7
|
-
{"acceptance_criteria":"","actor":"","agent_state":"","assignee":null,"await_id":"","await_type":"","close_reason":"Closed","closed_at":"2026-03-06T11:38:11Z","closed_by_session":"","compacted_at":null,"compacted_at_commit":null,"compaction_level":0,"content_hash":"aac42923f4098c6b3b314b1c10374e205085707e0dd4df714a3e0fc2868ce2ba","created_at":"2026-03-06T04:28:03Z","created_by":"Mike Crowe","crystallizes":0,"defer_until":null,"description":"Arg parsing (citty or yargs), interactive confirmation prompt, formatted output matching bash prototype (colors, worktree preview table, done message). Wire up npx binary entry.","design":"","due_at":null,"ephemeral":0,"estimated_minutes":null,"event_kind":"","external_ref":null,"hook_bead":"","id":"git-worktree-organize-pa7","is_template":0,"issue_type":"feature","last_activity":null,"metadata":"{}","mol_type":"","notes":"","original_size":null,"owner":"drmikecrowe@gmail.com","payload":"","pinned":0,"priority":2,"quality_score":null,"rig":"","role_bead":"","role_type":"","sender":"","source_repo":"","source_system":"","spec_id":"","status":"closed","target":"","timeout_ns":0,"title":"Implement cli.ts entry point","updated_at":"2026-03-06T11:38:11Z","waiters":"","wisp_type":"","work_type":""}
|
|
8
|
-
{"acceptance_criteria":"","actor":"","agent_state":"","assignee":null,"await_id":"","await_type":"","close_reason":"Closed","closed_at":"2026-03-06T11:30:26Z","closed_by_session":"","compacted_at":null,"compacted_at_commit":null,"compaction_level":0,"content_hash":"74d94c1a48786197343e664f31b426b3105f9142e00f2bc70a923ca4d12adadb","created_at":"2026-03-06T04:27:55Z","created_by":"Mike Crowe","crystallizes":0,"defer_until":null,"description":"Parse git worktree list --porcelain output into typed Worktree[]. Handle bare, linked, detached HEAD cases. Tests in test/worktrees.test.ts.","design":"","due_at":null,"ephemeral":0,"estimated_minutes":null,"event_kind":"","external_ref":null,"hook_bead":"","id":"git-worktree-organize-q2e","is_template":0,"issue_type":"feature","last_activity":null,"metadata":"{}","mol_type":"","notes":"","original_size":null,"owner":"drmikecrowe@gmail.com","payload":"","pinned":0,"priority":1,"quality_score":null,"rig":"","role_bead":"","role_type":"","sender":"","source_repo":"","source_system":"","spec_id":"","status":"closed","target":"","timeout_ns":0,"title":"Implement worktrees.ts + tests","updated_at":"2026-03-06T11:30:26Z","waiters":"","wisp_type":"","work_type":""}
|
|
9
|
-
{"acceptance_criteria":"","actor":"","agent_state":"","assignee":null,"await_id":"","await_type":"","close_reason":"Closed","closed_at":"2026-03-06T11:30:26Z","closed_by_session":"","compacted_at":null,"compacted_at_commit":null,"compaction_level":0,"content_hash":"e1c9d043c99e2fbecc16f2c9e7ceae6d43600a5ab07c7dea9a53e8dc082552f6","created_at":"2026-03-06T04:27:55Z","created_by":"Mike Crowe","crystallizes":0,"defer_until":null,"description":"Implement all 7 detection cases from the detection matrix: standard, bare-hub, bare-root, bare-dotgit, bare-external, reject-linked-worktree, reject-not-a-repo. Tests in test/detect.test.ts using real git repos in tmpdir.","design":"","due_at":null,"ephemeral":0,"estimated_minutes":null,"event_kind":"","external_ref":null,"hook_bead":"","id":"git-worktree-organize-t83","is_template":0,"issue_type":"feature","last_activity":null,"metadata":"{}","mol_type":"","notes":"","original_size":null,"owner":"drmikecrowe@gmail.com","payload":"","pinned":0,"priority":1,"quality_score":null,"rig":"","role_bead":"","role_type":"","sender":"","source_repo":"","source_system":"","spec_id":"","status":"closed","target":"","timeout_ns":0,"title":"Implement detect.ts + full test suite","updated_at":"2026-03-06T11:30:26Z","waiters":"","wisp_type":"","work_type":""}
|
|
File without changes
|