work-kit-cli 0.2.5 → 0.2.6
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/cli/src/commands/cancel.ts +103 -0
- package/cli/src/index.ts +18 -0
- package/package.json +1 -1
- package/skills/cancel-kit/SKILL.md +34 -0
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import { execFileSync } from "node:child_process";
|
|
2
|
+
import * as fs from "node:fs";
|
|
3
|
+
import * as path from "node:path";
|
|
4
|
+
import { readState, findWorktreeRoot, stateDir } from "../state/store.js";
|
|
5
|
+
|
|
6
|
+
export interface CancelResult {
|
|
7
|
+
action: "cancelled" | "error";
|
|
8
|
+
slug?: string;
|
|
9
|
+
branch?: string;
|
|
10
|
+
worktreeRemoved: boolean;
|
|
11
|
+
branchDeleted: boolean;
|
|
12
|
+
message: string;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
function resolveMainRepoRoot(worktreeRoot: string): string {
|
|
16
|
+
try {
|
|
17
|
+
const output = execFileSync("git", ["worktree", "list", "--porcelain"], {
|
|
18
|
+
cwd: worktreeRoot,
|
|
19
|
+
encoding: "utf-8",
|
|
20
|
+
timeout: 5000,
|
|
21
|
+
});
|
|
22
|
+
const firstLine = output.split("\n").find(l => l.startsWith("worktree "));
|
|
23
|
+
if (firstLine) return firstLine.slice("worktree ".length).trim();
|
|
24
|
+
} catch {
|
|
25
|
+
// fallback
|
|
26
|
+
}
|
|
27
|
+
return worktreeRoot;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export function cancelCommand(worktreeRoot?: string): CancelResult {
|
|
31
|
+
const root = worktreeRoot || findWorktreeRoot();
|
|
32
|
+
if (!root) {
|
|
33
|
+
return {
|
|
34
|
+
action: "error",
|
|
35
|
+
worktreeRemoved: false,
|
|
36
|
+
branchDeleted: false,
|
|
37
|
+
message: "No work-kit state found. Nothing to cancel.",
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
const state = readState(root);
|
|
42
|
+
|
|
43
|
+
if (state.status === "completed") {
|
|
44
|
+
return {
|
|
45
|
+
action: "error",
|
|
46
|
+
slug: state.slug,
|
|
47
|
+
worktreeRemoved: false,
|
|
48
|
+
branchDeleted: false,
|
|
49
|
+
message: `${state.slug} is already completed. Nothing to cancel.`,
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
const slug = state.slug;
|
|
54
|
+
const branch = state.branch;
|
|
55
|
+
const mainRoot = resolveMainRepoRoot(root);
|
|
56
|
+
const isWorktree = path.resolve(root) !== path.resolve(mainRoot);
|
|
57
|
+
|
|
58
|
+
let worktreeRemoved = false;
|
|
59
|
+
let branchDeleted = false;
|
|
60
|
+
|
|
61
|
+
// Remove .work-kit/ state directory
|
|
62
|
+
const stDir = stateDir(root);
|
|
63
|
+
if (fs.existsSync(stDir)) {
|
|
64
|
+
fs.rmSync(stDir, { recursive: true, force: true });
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// Remove the worktree (if we're in one)
|
|
68
|
+
if (isWorktree) {
|
|
69
|
+
try {
|
|
70
|
+
execFileSync("git", ["worktree", "remove", root, "--force"], {
|
|
71
|
+
cwd: mainRoot,
|
|
72
|
+
encoding: "utf-8",
|
|
73
|
+
timeout: 10000,
|
|
74
|
+
});
|
|
75
|
+
worktreeRemoved = true;
|
|
76
|
+
} catch {
|
|
77
|
+
// Worktree removal failed — may need manual cleanup
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
// Delete the feature branch
|
|
82
|
+
if (branch) {
|
|
83
|
+
try {
|
|
84
|
+
execFileSync("git", ["branch", "-D", branch], {
|
|
85
|
+
cwd: mainRoot,
|
|
86
|
+
encoding: "utf-8",
|
|
87
|
+
timeout: 5000,
|
|
88
|
+
});
|
|
89
|
+
branchDeleted = true;
|
|
90
|
+
} catch {
|
|
91
|
+
// Branch may not exist or may be checked out elsewhere
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
return {
|
|
96
|
+
action: "cancelled",
|
|
97
|
+
slug,
|
|
98
|
+
branch,
|
|
99
|
+
worktreeRemoved,
|
|
100
|
+
branchDeleted,
|
|
101
|
+
message: `Cancelled ${slug}.${worktreeRemoved ? " Worktree removed." : ""}${branchDeleted ? " Branch deleted." : ""}`,
|
|
102
|
+
};
|
|
103
|
+
}
|
package/cli/src/index.ts
CHANGED
|
@@ -16,6 +16,7 @@ import { completionsCommand } from "./commands/completions.js";
|
|
|
16
16
|
import { observeCommand } from "./commands/observe.js";
|
|
17
17
|
import { uninstallCommand } from "./commands/uninstall.js";
|
|
18
18
|
import { bootstrapCommand } from "./commands/bootstrap.js";
|
|
19
|
+
import { cancelCommand } from "./commands/cancel.js";
|
|
19
20
|
import { bold, green, yellow, red } from "./utils/colors.js";
|
|
20
21
|
import type { Classification, PhaseName } from "./state/schema.js";
|
|
21
22
|
|
|
@@ -269,4 +270,21 @@ program
|
|
|
269
270
|
}
|
|
270
271
|
});
|
|
271
272
|
|
|
273
|
+
// ── cancel ──────────────────────────────────────────────────────────
|
|
274
|
+
|
|
275
|
+
program
|
|
276
|
+
.command("cancel")
|
|
277
|
+
.description("Cancel the active work-kit, remove worktree and branch")
|
|
278
|
+
.option("--worktree-root <path>", "Override worktree root")
|
|
279
|
+
.action((opts) => {
|
|
280
|
+
try {
|
|
281
|
+
const result = cancelCommand(opts.worktreeRoot);
|
|
282
|
+
console.log(JSON.stringify(result, null, 2));
|
|
283
|
+
process.exit(result.action === "error" ? 1 : 0);
|
|
284
|
+
} catch (e: any) {
|
|
285
|
+
console.error(JSON.stringify({ action: "error", message: e.message }));
|
|
286
|
+
process.exit(1);
|
|
287
|
+
}
|
|
288
|
+
});
|
|
289
|
+
|
|
272
290
|
program.parse();
|
package/package.json
CHANGED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: cancel-kit
|
|
3
|
+
description: "Cancel the active work-kit session. Removes state, worktree, and feature branch."
|
|
4
|
+
user-invocable: true
|
|
5
|
+
allowed-tools: Bash, Read
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# Cancel Kit
|
|
9
|
+
|
|
10
|
+
Cancels the active work-kit session and cleans up all artifacts.
|
|
11
|
+
|
|
12
|
+
## What it does
|
|
13
|
+
|
|
14
|
+
1. Finds the active work-kit session (via `bootstrap`)
|
|
15
|
+
2. Confirms with the user before proceeding
|
|
16
|
+
3. Runs `npx work-kit-cli cancel` to:
|
|
17
|
+
- Remove `.work-kit/` state directory
|
|
18
|
+
- Remove the git worktree
|
|
19
|
+
- Delete the feature branch
|
|
20
|
+
4. Reports what was cleaned up
|
|
21
|
+
|
|
22
|
+
## Instructions
|
|
23
|
+
|
|
24
|
+
1. Run `npx work-kit-cli bootstrap` to detect the active session
|
|
25
|
+
2. If no active session: tell the user there's nothing to cancel
|
|
26
|
+
3. If active: show the user what will be cancelled:
|
|
27
|
+
- Slug and branch name
|
|
28
|
+
- Current phase and sub-stage
|
|
29
|
+
- Any uncommitted work in the worktree will be lost
|
|
30
|
+
4. **Ask the user to confirm** — do not proceed without explicit confirmation
|
|
31
|
+
5. `cd` into the worktree directory
|
|
32
|
+
6. Run `npx work-kit-cli cancel`
|
|
33
|
+
7. `cd` back to the main repo root
|
|
34
|
+
8. Report the result to the user
|