@wbern/claude-instructions 1.8.0 → 1.9.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/README.md +14 -10
- package/bin/cli.js +677 -49
- package/downloads/with-beads/ask.md +1 -4
- package/downloads/with-beads/beepboop.md +0 -1
- package/downloads/with-beads/busycommit.md +0 -1
- package/downloads/with-beads/commands-metadata.json +43 -15
- package/downloads/with-beads/commit.md +0 -1
- package/downloads/with-beads/cycle.md +0 -1
- package/downloads/with-beads/green.md +0 -1
- package/downloads/with-beads/issue.md +0 -1
- package/downloads/with-beads/plan.md +0 -1
- package/downloads/with-beads/pr.md +82 -0
- package/downloads/with-beads/red.md +0 -1
- package/downloads/with-beads/refactor.md +0 -1
- package/downloads/with-beads/ship.md +1 -4
- package/downloads/with-beads/show.md +1 -4
- package/downloads/with-beads/spike.md +0 -1
- package/downloads/with-beads/summarize.md +0 -1
- package/downloads/with-beads/tdd.md +0 -1
- package/downloads/with-beads/worktree-add.md +0 -1
- package/downloads/with-beads/worktree-cleanup.md +0 -1
- package/downloads/without-beads/ask.md +1 -4
- package/downloads/without-beads/beepboop.md +0 -1
- package/downloads/without-beads/busycommit.md +0 -1
- package/downloads/without-beads/commands-metadata.json +43 -15
- package/downloads/without-beads/commit.md +0 -1
- package/downloads/without-beads/cycle.md +1 -5
- package/downloads/without-beads/green.md +1 -5
- package/downloads/without-beads/issue.md +0 -1
- package/downloads/without-beads/plan.md +0 -1
- package/downloads/without-beads/pr.md +70 -0
- package/downloads/without-beads/red.md +1 -5
- package/downloads/without-beads/refactor.md +1 -5
- package/downloads/without-beads/ship.md +1 -4
- package/downloads/without-beads/show.md +1 -4
- package/downloads/without-beads/spike.md +1 -5
- package/downloads/without-beads/summarize.md +0 -1
- package/downloads/without-beads/tdd.md +0 -1
- package/downloads/without-beads/worktree-add.md +0 -1
- package/downloads/without-beads/worktree-cleanup.md +0 -1
- package/package.json +4 -1
package/bin/cli.js
CHANGED
|
@@ -1,16 +1,400 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __esm = (fn, res) => function __init() {
|
|
9
|
+
return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
|
|
10
|
+
};
|
|
11
|
+
var __commonJS = (cb, mod) => function __require() {
|
|
12
|
+
return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
|
|
13
|
+
};
|
|
14
|
+
var __copyProps = (to, from, except, desc) => {
|
|
15
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
16
|
+
for (let key of __getOwnPropNames(from))
|
|
17
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
18
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
19
|
+
}
|
|
20
|
+
return to;
|
|
21
|
+
};
|
|
22
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
23
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
24
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
25
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
26
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
27
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
28
|
+
mod
|
|
29
|
+
));
|
|
30
|
+
|
|
31
|
+
// node_modules/.pnpm/tsup@8.5.1_jiti@2.6.1_postcss@8.5.6_tsx@4.21.0_typescript@5.9.3_yaml@2.8.2/node_modules/tsup/assets/esm_shims.js
|
|
32
|
+
import path from "path";
|
|
33
|
+
import { fileURLToPath } from "url";
|
|
34
|
+
var init_esm_shims = __esm({
|
|
35
|
+
"node_modules/.pnpm/tsup@8.5.1_jiti@2.6.1_postcss@8.5.6_tsx@4.21.0_typescript@5.9.3_yaml@2.8.2/node_modules/tsup/assets/esm_shims.js"() {
|
|
36
|
+
"use strict";
|
|
37
|
+
}
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
// node_modules/.pnpm/picocolors@1.1.1/node_modules/picocolors/picocolors.js
|
|
41
|
+
var require_picocolors = __commonJS({
|
|
42
|
+
"node_modules/.pnpm/picocolors@1.1.1/node_modules/picocolors/picocolors.js"(exports, module) {
|
|
43
|
+
"use strict";
|
|
44
|
+
init_esm_shims();
|
|
45
|
+
var p = process || {};
|
|
46
|
+
var argv = p.argv || [];
|
|
47
|
+
var env = p.env || {};
|
|
48
|
+
var isColorSupported = !(!!env.NO_COLOR || argv.includes("--no-color")) && (!!env.FORCE_COLOR || argv.includes("--color") || p.platform === "win32" || (p.stdout || {}).isTTY && env.TERM !== "dumb" || !!env.CI);
|
|
49
|
+
var formatter = (open, close, replace = open) => (input) => {
|
|
50
|
+
let string = "" + input, index = string.indexOf(close, open.length);
|
|
51
|
+
return ~index ? open + replaceClose(string, close, replace, index) + close : open + string + close;
|
|
52
|
+
};
|
|
53
|
+
var replaceClose = (string, close, replace, index) => {
|
|
54
|
+
let result = "", cursor = 0;
|
|
55
|
+
do {
|
|
56
|
+
result += string.substring(cursor, index) + replace;
|
|
57
|
+
cursor = index + close.length;
|
|
58
|
+
index = string.indexOf(close, cursor);
|
|
59
|
+
} while (~index);
|
|
60
|
+
return result + string.substring(cursor);
|
|
61
|
+
};
|
|
62
|
+
var createColors = (enabled = isColorSupported) => {
|
|
63
|
+
let f = enabled ? formatter : () => String;
|
|
64
|
+
return {
|
|
65
|
+
isColorSupported: enabled,
|
|
66
|
+
reset: f("\x1B[0m", "\x1B[0m"),
|
|
67
|
+
bold: f("\x1B[1m", "\x1B[22m", "\x1B[22m\x1B[1m"),
|
|
68
|
+
dim: f("\x1B[2m", "\x1B[22m", "\x1B[22m\x1B[2m"),
|
|
69
|
+
italic: f("\x1B[3m", "\x1B[23m"),
|
|
70
|
+
underline: f("\x1B[4m", "\x1B[24m"),
|
|
71
|
+
inverse: f("\x1B[7m", "\x1B[27m"),
|
|
72
|
+
hidden: f("\x1B[8m", "\x1B[28m"),
|
|
73
|
+
strikethrough: f("\x1B[9m", "\x1B[29m"),
|
|
74
|
+
black: f("\x1B[30m", "\x1B[39m"),
|
|
75
|
+
red: f("\x1B[31m", "\x1B[39m"),
|
|
76
|
+
green: f("\x1B[32m", "\x1B[39m"),
|
|
77
|
+
yellow: f("\x1B[33m", "\x1B[39m"),
|
|
78
|
+
blue: f("\x1B[34m", "\x1B[39m"),
|
|
79
|
+
magenta: f("\x1B[35m", "\x1B[39m"),
|
|
80
|
+
cyan: f("\x1B[36m", "\x1B[39m"),
|
|
81
|
+
white: f("\x1B[37m", "\x1B[39m"),
|
|
82
|
+
gray: f("\x1B[90m", "\x1B[39m"),
|
|
83
|
+
bgBlack: f("\x1B[40m", "\x1B[49m"),
|
|
84
|
+
bgRed: f("\x1B[41m", "\x1B[49m"),
|
|
85
|
+
bgGreen: f("\x1B[42m", "\x1B[49m"),
|
|
86
|
+
bgYellow: f("\x1B[43m", "\x1B[49m"),
|
|
87
|
+
bgBlue: f("\x1B[44m", "\x1B[49m"),
|
|
88
|
+
bgMagenta: f("\x1B[45m", "\x1B[49m"),
|
|
89
|
+
bgCyan: f("\x1B[46m", "\x1B[49m"),
|
|
90
|
+
bgWhite: f("\x1B[47m", "\x1B[49m"),
|
|
91
|
+
blackBright: f("\x1B[90m", "\x1B[39m"),
|
|
92
|
+
redBright: f("\x1B[91m", "\x1B[39m"),
|
|
93
|
+
greenBright: f("\x1B[92m", "\x1B[39m"),
|
|
94
|
+
yellowBright: f("\x1B[93m", "\x1B[39m"),
|
|
95
|
+
blueBright: f("\x1B[94m", "\x1B[39m"),
|
|
96
|
+
magentaBright: f("\x1B[95m", "\x1B[39m"),
|
|
97
|
+
cyanBright: f("\x1B[96m", "\x1B[39m"),
|
|
98
|
+
whiteBright: f("\x1B[97m", "\x1B[39m"),
|
|
99
|
+
bgBlackBright: f("\x1B[100m", "\x1B[49m"),
|
|
100
|
+
bgRedBright: f("\x1B[101m", "\x1B[49m"),
|
|
101
|
+
bgGreenBright: f("\x1B[102m", "\x1B[49m"),
|
|
102
|
+
bgYellowBright: f("\x1B[103m", "\x1B[49m"),
|
|
103
|
+
bgBlueBright: f("\x1B[104m", "\x1B[49m"),
|
|
104
|
+
bgMagentaBright: f("\x1B[105m", "\x1B[49m"),
|
|
105
|
+
bgCyanBright: f("\x1B[106m", "\x1B[49m"),
|
|
106
|
+
bgWhiteBright: f("\x1B[107m", "\x1B[49m")
|
|
107
|
+
};
|
|
108
|
+
};
|
|
109
|
+
module.exports = createColors();
|
|
110
|
+
module.exports.createColors = createColors;
|
|
111
|
+
}
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
// scripts/bin.ts
|
|
115
|
+
init_esm_shims();
|
|
2
116
|
|
|
3
117
|
// scripts/cli.ts
|
|
4
|
-
|
|
118
|
+
init_esm_shims();
|
|
119
|
+
import {
|
|
120
|
+
select,
|
|
121
|
+
text,
|
|
122
|
+
groupMultiselect,
|
|
123
|
+
isCancel,
|
|
124
|
+
intro,
|
|
125
|
+
outro,
|
|
126
|
+
confirm,
|
|
127
|
+
note,
|
|
128
|
+
log
|
|
129
|
+
} from "@clack/prompts";
|
|
5
130
|
import os2 from "os";
|
|
6
131
|
|
|
132
|
+
// node_modules/.pnpm/diff@8.0.2/node_modules/diff/libesm/index.js
|
|
133
|
+
init_esm_shims();
|
|
134
|
+
|
|
135
|
+
// node_modules/.pnpm/diff@8.0.2/node_modules/diff/libesm/diff/base.js
|
|
136
|
+
init_esm_shims();
|
|
137
|
+
var Diff = class {
|
|
138
|
+
diff(oldStr, newStr, options = {}) {
|
|
139
|
+
let callback;
|
|
140
|
+
if (typeof options === "function") {
|
|
141
|
+
callback = options;
|
|
142
|
+
options = {};
|
|
143
|
+
} else if ("callback" in options) {
|
|
144
|
+
callback = options.callback;
|
|
145
|
+
}
|
|
146
|
+
const oldString = this.castInput(oldStr, options);
|
|
147
|
+
const newString = this.castInput(newStr, options);
|
|
148
|
+
const oldTokens = this.removeEmpty(this.tokenize(oldString, options));
|
|
149
|
+
const newTokens = this.removeEmpty(this.tokenize(newString, options));
|
|
150
|
+
return this.diffWithOptionsObj(oldTokens, newTokens, options, callback);
|
|
151
|
+
}
|
|
152
|
+
diffWithOptionsObj(oldTokens, newTokens, options, callback) {
|
|
153
|
+
var _a;
|
|
154
|
+
const done = (value) => {
|
|
155
|
+
value = this.postProcess(value, options);
|
|
156
|
+
if (callback) {
|
|
157
|
+
setTimeout(function() {
|
|
158
|
+
callback(value);
|
|
159
|
+
}, 0);
|
|
160
|
+
return void 0;
|
|
161
|
+
} else {
|
|
162
|
+
return value;
|
|
163
|
+
}
|
|
164
|
+
};
|
|
165
|
+
const newLen = newTokens.length, oldLen = oldTokens.length;
|
|
166
|
+
let editLength = 1;
|
|
167
|
+
let maxEditLength = newLen + oldLen;
|
|
168
|
+
if (options.maxEditLength != null) {
|
|
169
|
+
maxEditLength = Math.min(maxEditLength, options.maxEditLength);
|
|
170
|
+
}
|
|
171
|
+
const maxExecutionTime = (_a = options.timeout) !== null && _a !== void 0 ? _a : Infinity;
|
|
172
|
+
const abortAfterTimestamp = Date.now() + maxExecutionTime;
|
|
173
|
+
const bestPath = [{ oldPos: -1, lastComponent: void 0 }];
|
|
174
|
+
let newPos = this.extractCommon(bestPath[0], newTokens, oldTokens, 0, options);
|
|
175
|
+
if (bestPath[0].oldPos + 1 >= oldLen && newPos + 1 >= newLen) {
|
|
176
|
+
return done(this.buildValues(bestPath[0].lastComponent, newTokens, oldTokens));
|
|
177
|
+
}
|
|
178
|
+
let minDiagonalToConsider = -Infinity, maxDiagonalToConsider = Infinity;
|
|
179
|
+
const execEditLength = () => {
|
|
180
|
+
for (let diagonalPath = Math.max(minDiagonalToConsider, -editLength); diagonalPath <= Math.min(maxDiagonalToConsider, editLength); diagonalPath += 2) {
|
|
181
|
+
let basePath;
|
|
182
|
+
const removePath = bestPath[diagonalPath - 1], addPath = bestPath[diagonalPath + 1];
|
|
183
|
+
if (removePath) {
|
|
184
|
+
bestPath[diagonalPath - 1] = void 0;
|
|
185
|
+
}
|
|
186
|
+
let canAdd = false;
|
|
187
|
+
if (addPath) {
|
|
188
|
+
const addPathNewPos = addPath.oldPos - diagonalPath;
|
|
189
|
+
canAdd = addPath && 0 <= addPathNewPos && addPathNewPos < newLen;
|
|
190
|
+
}
|
|
191
|
+
const canRemove = removePath && removePath.oldPos + 1 < oldLen;
|
|
192
|
+
if (!canAdd && !canRemove) {
|
|
193
|
+
bestPath[diagonalPath] = void 0;
|
|
194
|
+
continue;
|
|
195
|
+
}
|
|
196
|
+
if (!canRemove || canAdd && removePath.oldPos < addPath.oldPos) {
|
|
197
|
+
basePath = this.addToPath(addPath, true, false, 0, options);
|
|
198
|
+
} else {
|
|
199
|
+
basePath = this.addToPath(removePath, false, true, 1, options);
|
|
200
|
+
}
|
|
201
|
+
newPos = this.extractCommon(basePath, newTokens, oldTokens, diagonalPath, options);
|
|
202
|
+
if (basePath.oldPos + 1 >= oldLen && newPos + 1 >= newLen) {
|
|
203
|
+
return done(this.buildValues(basePath.lastComponent, newTokens, oldTokens)) || true;
|
|
204
|
+
} else {
|
|
205
|
+
bestPath[diagonalPath] = basePath;
|
|
206
|
+
if (basePath.oldPos + 1 >= oldLen) {
|
|
207
|
+
maxDiagonalToConsider = Math.min(maxDiagonalToConsider, diagonalPath - 1);
|
|
208
|
+
}
|
|
209
|
+
if (newPos + 1 >= newLen) {
|
|
210
|
+
minDiagonalToConsider = Math.max(minDiagonalToConsider, diagonalPath + 1);
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
editLength++;
|
|
215
|
+
};
|
|
216
|
+
if (callback) {
|
|
217
|
+
(function exec() {
|
|
218
|
+
setTimeout(function() {
|
|
219
|
+
if (editLength > maxEditLength || Date.now() > abortAfterTimestamp) {
|
|
220
|
+
return callback(void 0);
|
|
221
|
+
}
|
|
222
|
+
if (!execEditLength()) {
|
|
223
|
+
exec();
|
|
224
|
+
}
|
|
225
|
+
}, 0);
|
|
226
|
+
})();
|
|
227
|
+
} else {
|
|
228
|
+
while (editLength <= maxEditLength && Date.now() <= abortAfterTimestamp) {
|
|
229
|
+
const ret = execEditLength();
|
|
230
|
+
if (ret) {
|
|
231
|
+
return ret;
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
addToPath(path3, added, removed, oldPosInc, options) {
|
|
237
|
+
const last = path3.lastComponent;
|
|
238
|
+
if (last && !options.oneChangePerToken && last.added === added && last.removed === removed) {
|
|
239
|
+
return {
|
|
240
|
+
oldPos: path3.oldPos + oldPosInc,
|
|
241
|
+
lastComponent: { count: last.count + 1, added, removed, previousComponent: last.previousComponent }
|
|
242
|
+
};
|
|
243
|
+
} else {
|
|
244
|
+
return {
|
|
245
|
+
oldPos: path3.oldPos + oldPosInc,
|
|
246
|
+
lastComponent: { count: 1, added, removed, previousComponent: last }
|
|
247
|
+
};
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
extractCommon(basePath, newTokens, oldTokens, diagonalPath, options) {
|
|
251
|
+
const newLen = newTokens.length, oldLen = oldTokens.length;
|
|
252
|
+
let oldPos = basePath.oldPos, newPos = oldPos - diagonalPath, commonCount = 0;
|
|
253
|
+
while (newPos + 1 < newLen && oldPos + 1 < oldLen && this.equals(oldTokens[oldPos + 1], newTokens[newPos + 1], options)) {
|
|
254
|
+
newPos++;
|
|
255
|
+
oldPos++;
|
|
256
|
+
commonCount++;
|
|
257
|
+
if (options.oneChangePerToken) {
|
|
258
|
+
basePath.lastComponent = { count: 1, previousComponent: basePath.lastComponent, added: false, removed: false };
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
if (commonCount && !options.oneChangePerToken) {
|
|
262
|
+
basePath.lastComponent = { count: commonCount, previousComponent: basePath.lastComponent, added: false, removed: false };
|
|
263
|
+
}
|
|
264
|
+
basePath.oldPos = oldPos;
|
|
265
|
+
return newPos;
|
|
266
|
+
}
|
|
267
|
+
equals(left, right, options) {
|
|
268
|
+
if (options.comparator) {
|
|
269
|
+
return options.comparator(left, right);
|
|
270
|
+
} else {
|
|
271
|
+
return left === right || !!options.ignoreCase && left.toLowerCase() === right.toLowerCase();
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
removeEmpty(array) {
|
|
275
|
+
const ret = [];
|
|
276
|
+
for (let i = 0; i < array.length; i++) {
|
|
277
|
+
if (array[i]) {
|
|
278
|
+
ret.push(array[i]);
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
return ret;
|
|
282
|
+
}
|
|
283
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
284
|
+
castInput(value, options) {
|
|
285
|
+
return value;
|
|
286
|
+
}
|
|
287
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
288
|
+
tokenize(value, options) {
|
|
289
|
+
return Array.from(value);
|
|
290
|
+
}
|
|
291
|
+
join(chars) {
|
|
292
|
+
return chars.join("");
|
|
293
|
+
}
|
|
294
|
+
postProcess(changeObjects, options) {
|
|
295
|
+
return changeObjects;
|
|
296
|
+
}
|
|
297
|
+
get useLongestToken() {
|
|
298
|
+
return false;
|
|
299
|
+
}
|
|
300
|
+
buildValues(lastComponent, newTokens, oldTokens) {
|
|
301
|
+
const components = [];
|
|
302
|
+
let nextComponent;
|
|
303
|
+
while (lastComponent) {
|
|
304
|
+
components.push(lastComponent);
|
|
305
|
+
nextComponent = lastComponent.previousComponent;
|
|
306
|
+
delete lastComponent.previousComponent;
|
|
307
|
+
lastComponent = nextComponent;
|
|
308
|
+
}
|
|
309
|
+
components.reverse();
|
|
310
|
+
const componentLen = components.length;
|
|
311
|
+
let componentPos = 0, newPos = 0, oldPos = 0;
|
|
312
|
+
for (; componentPos < componentLen; componentPos++) {
|
|
313
|
+
const component = components[componentPos];
|
|
314
|
+
if (!component.removed) {
|
|
315
|
+
if (!component.added && this.useLongestToken) {
|
|
316
|
+
let value = newTokens.slice(newPos, newPos + component.count);
|
|
317
|
+
value = value.map(function(value2, i) {
|
|
318
|
+
const oldValue = oldTokens[oldPos + i];
|
|
319
|
+
return oldValue.length > value2.length ? oldValue : value2;
|
|
320
|
+
});
|
|
321
|
+
component.value = this.join(value);
|
|
322
|
+
} else {
|
|
323
|
+
component.value = this.join(newTokens.slice(newPos, newPos + component.count));
|
|
324
|
+
}
|
|
325
|
+
newPos += component.count;
|
|
326
|
+
if (!component.added) {
|
|
327
|
+
oldPos += component.count;
|
|
328
|
+
}
|
|
329
|
+
} else {
|
|
330
|
+
component.value = this.join(oldTokens.slice(oldPos, oldPos + component.count));
|
|
331
|
+
oldPos += component.count;
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
return components;
|
|
335
|
+
}
|
|
336
|
+
};
|
|
337
|
+
|
|
338
|
+
// node_modules/.pnpm/diff@8.0.2/node_modules/diff/libesm/diff/line.js
|
|
339
|
+
init_esm_shims();
|
|
340
|
+
var LineDiff = class extends Diff {
|
|
341
|
+
constructor() {
|
|
342
|
+
super(...arguments);
|
|
343
|
+
this.tokenize = tokenize;
|
|
344
|
+
}
|
|
345
|
+
equals(left, right, options) {
|
|
346
|
+
if (options.ignoreWhitespace) {
|
|
347
|
+
if (!options.newlineIsToken || !left.includes("\n")) {
|
|
348
|
+
left = left.trim();
|
|
349
|
+
}
|
|
350
|
+
if (!options.newlineIsToken || !right.includes("\n")) {
|
|
351
|
+
right = right.trim();
|
|
352
|
+
}
|
|
353
|
+
} else if (options.ignoreNewlineAtEof && !options.newlineIsToken) {
|
|
354
|
+
if (left.endsWith("\n")) {
|
|
355
|
+
left = left.slice(0, -1);
|
|
356
|
+
}
|
|
357
|
+
if (right.endsWith("\n")) {
|
|
358
|
+
right = right.slice(0, -1);
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
return super.equals(left, right, options);
|
|
362
|
+
}
|
|
363
|
+
};
|
|
364
|
+
var lineDiff = new LineDiff();
|
|
365
|
+
function diffLines(oldStr, newStr, options) {
|
|
366
|
+
return lineDiff.diff(oldStr, newStr, options);
|
|
367
|
+
}
|
|
368
|
+
function tokenize(value, options) {
|
|
369
|
+
if (options.stripTrailingCr) {
|
|
370
|
+
value = value.replace(/\r\n/g, "\n");
|
|
371
|
+
}
|
|
372
|
+
const retLines = [], linesAndNewlines = value.split(/(\n|\r\n)/);
|
|
373
|
+
if (!linesAndNewlines[linesAndNewlines.length - 1]) {
|
|
374
|
+
linesAndNewlines.pop();
|
|
375
|
+
}
|
|
376
|
+
for (let i = 0; i < linesAndNewlines.length; i++) {
|
|
377
|
+
const line = linesAndNewlines[i];
|
|
378
|
+
if (i % 2 && !options.newlineIsToken) {
|
|
379
|
+
retLines[retLines.length - 1] += line;
|
|
380
|
+
} else {
|
|
381
|
+
retLines.push(line);
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
return retLines;
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
// scripts/cli.ts
|
|
388
|
+
var import_picocolors = __toESM(require_picocolors(), 1);
|
|
389
|
+
|
|
7
390
|
// scripts/cli-generator.ts
|
|
391
|
+
init_esm_shims();
|
|
8
392
|
import fs from "fs-extra";
|
|
9
|
-
import
|
|
10
|
-
import { fileURLToPath } from "url";
|
|
393
|
+
import path2 from "path";
|
|
394
|
+
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
11
395
|
import os from "os";
|
|
12
|
-
var
|
|
13
|
-
var
|
|
396
|
+
var __filename2 = fileURLToPath2(import.meta.url);
|
|
397
|
+
var __dirname2 = path2.dirname(__filename2);
|
|
14
398
|
var VARIANTS = {
|
|
15
399
|
WITH_BEADS: "with-beads",
|
|
16
400
|
WITHOUT_BEADS: "without-beads"
|
|
@@ -38,20 +422,88 @@ function truncatePathFromLeft(pathStr, maxLength) {
|
|
|
38
422
|
return ELLIPSIS + truncated;
|
|
39
423
|
}
|
|
40
424
|
var VARIANT_OPTIONS = [
|
|
41
|
-
{
|
|
42
|
-
|
|
425
|
+
{
|
|
426
|
+
value: VARIANTS.WITH_BEADS,
|
|
427
|
+
label: "With Beads",
|
|
428
|
+
hint: "Includes Beads task tracking"
|
|
429
|
+
},
|
|
430
|
+
{
|
|
431
|
+
value: VARIANTS.WITHOUT_BEADS,
|
|
432
|
+
label: "Without Beads",
|
|
433
|
+
hint: "Standard commands only"
|
|
434
|
+
}
|
|
43
435
|
];
|
|
44
436
|
function getScopeOptions(terminalWidth = 80) {
|
|
45
|
-
const projectPath =
|
|
46
|
-
|
|
437
|
+
const projectPath = path2.join(
|
|
438
|
+
process.cwd(),
|
|
439
|
+
DIRECTORIES.CLAUDE,
|
|
440
|
+
DIRECTORIES.COMMANDS
|
|
441
|
+
);
|
|
442
|
+
const userPath = path2.join(
|
|
443
|
+
os.homedir(),
|
|
444
|
+
DIRECTORIES.CLAUDE,
|
|
445
|
+
DIRECTORIES.COMMANDS
|
|
446
|
+
);
|
|
47
447
|
return [
|
|
48
|
-
{
|
|
49
|
-
|
|
448
|
+
{
|
|
449
|
+
value: SCOPES.PROJECT,
|
|
450
|
+
label: "Project/Repository",
|
|
451
|
+
hint: truncatePathFromLeft(projectPath, terminalWidth)
|
|
452
|
+
},
|
|
453
|
+
{
|
|
454
|
+
value: SCOPES.USER,
|
|
455
|
+
label: "User (Global)",
|
|
456
|
+
hint: truncatePathFromLeft(userPath, terminalWidth)
|
|
457
|
+
}
|
|
50
458
|
];
|
|
51
459
|
}
|
|
460
|
+
async function checkExistingFiles(outputPath, variant, scope, options) {
|
|
461
|
+
const sourcePath = path2.join(
|
|
462
|
+
__dirname2,
|
|
463
|
+
"..",
|
|
464
|
+
DIRECTORIES.DOWNLOADS,
|
|
465
|
+
variant || VARIANTS.WITH_BEADS
|
|
466
|
+
);
|
|
467
|
+
const destinationPath = outputPath || getDestinationPath(outputPath, scope);
|
|
468
|
+
if (!destinationPath) {
|
|
469
|
+
return [];
|
|
470
|
+
}
|
|
471
|
+
const files = await fs.readdir(sourcePath);
|
|
472
|
+
const existingFiles = [];
|
|
473
|
+
const prefix = options?.commandPrefix || "";
|
|
474
|
+
for (const file of files) {
|
|
475
|
+
const destFileName = prefix + file;
|
|
476
|
+
const destFilePath = path2.join(destinationPath, destFileName);
|
|
477
|
+
const sourceFilePath = path2.join(sourcePath, file);
|
|
478
|
+
if (await fs.pathExists(destFilePath)) {
|
|
479
|
+
const existingContent = await fs.readFile(destFilePath, "utf-8");
|
|
480
|
+
const newContent = await fs.readFile(sourceFilePath, "utf-8");
|
|
481
|
+
existingFiles.push({
|
|
482
|
+
filename: destFileName,
|
|
483
|
+
existingContent,
|
|
484
|
+
newContent,
|
|
485
|
+
isIdentical: existingContent === newContent
|
|
486
|
+
});
|
|
487
|
+
}
|
|
488
|
+
}
|
|
489
|
+
return existingFiles;
|
|
490
|
+
}
|
|
491
|
+
var CATEGORY_ORDER = [
|
|
492
|
+
"Test-Driven Development",
|
|
493
|
+
"Planning",
|
|
494
|
+
"Workflow",
|
|
495
|
+
"Worktree Management",
|
|
496
|
+
"Utilities",
|
|
497
|
+
"Ship / Show / Ask"
|
|
498
|
+
];
|
|
52
499
|
async function getCommandsGroupedByCategory(variant) {
|
|
53
|
-
const sourcePath =
|
|
54
|
-
|
|
500
|
+
const sourcePath = path2.join(
|
|
501
|
+
__dirname2,
|
|
502
|
+
"..",
|
|
503
|
+
DIRECTORIES.DOWNLOADS,
|
|
504
|
+
variant || VARIANTS.WITH_BEADS
|
|
505
|
+
);
|
|
506
|
+
const metadataPath = path2.join(sourcePath, "commands-metadata.json");
|
|
55
507
|
const metadataContent = await fs.readFile(metadataPath, "utf-8");
|
|
56
508
|
const metadata = JSON.parse(metadataContent);
|
|
57
509
|
const grouped = {};
|
|
@@ -62,7 +514,9 @@ async function getCommandsGroupedByCategory(variant) {
|
|
|
62
514
|
}
|
|
63
515
|
grouped[category].push({
|
|
64
516
|
value: filename,
|
|
65
|
-
label: filename
|
|
517
|
+
label: filename,
|
|
518
|
+
hint: data.hint,
|
|
519
|
+
selectedByDefault: data.selectedByDefault !== false
|
|
66
520
|
});
|
|
67
521
|
}
|
|
68
522
|
for (const category of Object.keys(grouped)) {
|
|
@@ -72,54 +526,80 @@ async function getCommandsGroupedByCategory(variant) {
|
|
|
72
526
|
return orderA - orderB;
|
|
73
527
|
});
|
|
74
528
|
}
|
|
75
|
-
|
|
529
|
+
const sortedCategories = Object.keys(grouped).sort((a, b) => {
|
|
530
|
+
const indexA = CATEGORY_ORDER.indexOf(a);
|
|
531
|
+
const indexB = CATEGORY_ORDER.indexOf(b);
|
|
532
|
+
if (indexA !== -1 && indexB !== -1) return indexA - indexB;
|
|
533
|
+
if (indexA !== -1) return -1;
|
|
534
|
+
if (indexB !== -1) return 1;
|
|
535
|
+
return a.localeCompare(b);
|
|
536
|
+
});
|
|
537
|
+
const sortedGrouped = {};
|
|
538
|
+
for (const category of sortedCategories) {
|
|
539
|
+
sortedGrouped[category] = grouped[category];
|
|
540
|
+
}
|
|
541
|
+
return sortedGrouped;
|
|
76
542
|
}
|
|
77
543
|
function getDestinationPath(outputPath, scope) {
|
|
78
544
|
if (outputPath) {
|
|
79
545
|
return outputPath;
|
|
80
546
|
}
|
|
81
547
|
if (scope === SCOPES.PROJECT) {
|
|
82
|
-
return
|
|
548
|
+
return path2.join(process.cwd(), DIRECTORIES.CLAUDE, DIRECTORIES.COMMANDS);
|
|
83
549
|
}
|
|
84
550
|
if (scope === SCOPES.USER) {
|
|
85
|
-
return
|
|
551
|
+
return path2.join(os.homedir(), DIRECTORIES.CLAUDE, DIRECTORIES.COMMANDS);
|
|
86
552
|
}
|
|
87
553
|
return void 0;
|
|
88
554
|
}
|
|
89
555
|
function extractTemplateBlocks(content) {
|
|
90
|
-
const
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
556
|
+
const blocks = [];
|
|
557
|
+
const withCommandsRegex = /<claude-commands-template\s+commands="([^"]+)">([\s\S]*?)<\/claude-commands-template>/g;
|
|
558
|
+
for (const match of content.matchAll(withCommandsRegex)) {
|
|
559
|
+
blocks.push({
|
|
560
|
+
content: match[2].trim(),
|
|
561
|
+
commands: match[1].split(",").map((c) => c.trim())
|
|
562
|
+
});
|
|
96
563
|
}
|
|
97
|
-
const
|
|
98
|
-
|
|
99
|
-
|
|
564
|
+
const withoutCommandsRegex = /<claude-commands-template>([\s\S]*?)<\/claude-commands-template>/g;
|
|
565
|
+
for (const match of content.matchAll(withoutCommandsRegex)) {
|
|
566
|
+
blocks.push({
|
|
567
|
+
content: match[1].trim()
|
|
568
|
+
});
|
|
100
569
|
}
|
|
101
|
-
return
|
|
570
|
+
return blocks;
|
|
102
571
|
}
|
|
103
572
|
async function generateToDirectory(outputPath, variant, scope, options) {
|
|
104
|
-
const sourcePath =
|
|
573
|
+
const sourcePath = path2.join(
|
|
574
|
+
__dirname2,
|
|
575
|
+
"..",
|
|
576
|
+
DIRECTORIES.DOWNLOADS,
|
|
577
|
+
variant || VARIANTS.WITH_BEADS
|
|
578
|
+
);
|
|
105
579
|
const destinationPath = getDestinationPath(outputPath, scope);
|
|
106
580
|
if (!destinationPath) {
|
|
107
581
|
throw new Error("Either outputPath or scope must be provided");
|
|
108
582
|
}
|
|
109
583
|
const allFiles = await fs.readdir(sourcePath);
|
|
110
|
-
|
|
111
|
-
if (options?.
|
|
584
|
+
let files = options?.commands ? allFiles.filter((f) => options.commands.includes(f)) : allFiles;
|
|
585
|
+
if (options?.skipFiles) {
|
|
586
|
+
files = files.filter((f) => !options.skipFiles.includes(f));
|
|
587
|
+
}
|
|
588
|
+
if (options?.commands || options?.skipFiles) {
|
|
112
589
|
await fs.ensureDir(destinationPath);
|
|
113
590
|
for (const file of files) {
|
|
114
|
-
await fs.copy(
|
|
591
|
+
await fs.copy(
|
|
592
|
+
path2.join(sourcePath, file),
|
|
593
|
+
path2.join(destinationPath, file)
|
|
594
|
+
);
|
|
115
595
|
}
|
|
116
596
|
} else {
|
|
117
597
|
await fs.copy(sourcePath, destinationPath, {});
|
|
118
598
|
}
|
|
119
599
|
if (options?.commandPrefix) {
|
|
120
600
|
for (const file of files) {
|
|
121
|
-
const oldPath =
|
|
122
|
-
const newPath =
|
|
601
|
+
const oldPath = path2.join(destinationPath, file);
|
|
602
|
+
const newPath = path2.join(destinationPath, options.commandPrefix + file);
|
|
123
603
|
await fs.rename(oldPath, newPath);
|
|
124
604
|
}
|
|
125
605
|
}
|
|
@@ -127,7 +607,7 @@ async function generateToDirectory(outputPath, variant, scope, options) {
|
|
|
127
607
|
if (!options?.skipTemplateInjection) {
|
|
128
608
|
let templateSourcePath = null;
|
|
129
609
|
for (const filename of TEMPLATE_SOURCE_FILES) {
|
|
130
|
-
const candidatePath =
|
|
610
|
+
const candidatePath = path2.join(process.cwd(), filename);
|
|
131
611
|
if (await fs.pathExists(candidatePath)) {
|
|
132
612
|
templateSourcePath = candidatePath;
|
|
133
613
|
break;
|
|
@@ -135,17 +615,24 @@ async function generateToDirectory(outputPath, variant, scope, options) {
|
|
|
135
615
|
}
|
|
136
616
|
if (templateSourcePath) {
|
|
137
617
|
const sourceContent = await fs.readFile(templateSourcePath, "utf-8");
|
|
138
|
-
const
|
|
139
|
-
if (
|
|
618
|
+
const templates = extractTemplateBlocks(sourceContent);
|
|
619
|
+
if (templates.length > 0) {
|
|
140
620
|
for (const file of files) {
|
|
141
|
-
const commandName =
|
|
142
|
-
if (template.commands && !template.commands.includes(commandName)) {
|
|
143
|
-
continue;
|
|
144
|
-
}
|
|
621
|
+
const commandName = path2.basename(file, ".md");
|
|
145
622
|
const actualFileName = options?.commandPrefix ? options.commandPrefix + file : file;
|
|
146
|
-
const filePath =
|
|
147
|
-
|
|
148
|
-
|
|
623
|
+
const filePath = path2.join(destinationPath, actualFileName);
|
|
624
|
+
let content = await fs.readFile(filePath, "utf-8");
|
|
625
|
+
let modified = false;
|
|
626
|
+
for (const template of templates) {
|
|
627
|
+
if (template.commands && !template.commands.includes(commandName)) {
|
|
628
|
+
continue;
|
|
629
|
+
}
|
|
630
|
+
content = content + "\n\n" + template.content;
|
|
631
|
+
modified = true;
|
|
632
|
+
}
|
|
633
|
+
if (modified) {
|
|
634
|
+
await fs.writeFile(filePath, content);
|
|
635
|
+
}
|
|
149
636
|
}
|
|
150
637
|
templateInjected = true;
|
|
151
638
|
}
|
|
@@ -161,6 +648,106 @@ async function generateToDirectory(outputPath, variant, scope, options) {
|
|
|
161
648
|
}
|
|
162
649
|
|
|
163
650
|
// scripts/cli.ts
|
|
651
|
+
var pc = process.env.FORCE_COLOR ? import_picocolors.default.createColors(true) : import_picocolors.default;
|
|
652
|
+
function splitChangeIntoLines(value) {
|
|
653
|
+
const lines = value.split("\n");
|
|
654
|
+
if (lines[lines.length - 1] === "") lines.pop();
|
|
655
|
+
return lines;
|
|
656
|
+
}
|
|
657
|
+
function formatCompactDiff(oldContent, newContent, contextLines = 3) {
|
|
658
|
+
const changes = diffLines(oldContent, newContent);
|
|
659
|
+
const lines = [];
|
|
660
|
+
const allLines = [];
|
|
661
|
+
let oldLineNum = 1;
|
|
662
|
+
let newLineNum = 1;
|
|
663
|
+
for (const change of changes) {
|
|
664
|
+
const changeLines = splitChangeIntoLines(change.value);
|
|
665
|
+
for (const text2 of changeLines) {
|
|
666
|
+
if (change.added) {
|
|
667
|
+
allLines.push({
|
|
668
|
+
text: text2,
|
|
669
|
+
type: "added",
|
|
670
|
+
oldLineNum: -1,
|
|
671
|
+
newLineNum: newLineNum++
|
|
672
|
+
});
|
|
673
|
+
} else if (change.removed) {
|
|
674
|
+
allLines.push({
|
|
675
|
+
text: text2,
|
|
676
|
+
type: "removed",
|
|
677
|
+
oldLineNum: oldLineNum++,
|
|
678
|
+
newLineNum: -1
|
|
679
|
+
});
|
|
680
|
+
} else {
|
|
681
|
+
allLines.push({
|
|
682
|
+
text: text2,
|
|
683
|
+
type: "unchanged",
|
|
684
|
+
oldLineNum: oldLineNum++,
|
|
685
|
+
newLineNum: newLineNum++
|
|
686
|
+
});
|
|
687
|
+
}
|
|
688
|
+
}
|
|
689
|
+
}
|
|
690
|
+
let i = 0;
|
|
691
|
+
while (i < allLines.length) {
|
|
692
|
+
if (allLines[i].type === "unchanged") {
|
|
693
|
+
i++;
|
|
694
|
+
continue;
|
|
695
|
+
}
|
|
696
|
+
const hunkStart = Math.max(0, i - contextLines);
|
|
697
|
+
let hunkEnd = i;
|
|
698
|
+
while (hunkEnd < allLines.length) {
|
|
699
|
+
if (allLines[hunkEnd].type !== "unchanged") {
|
|
700
|
+
hunkEnd++;
|
|
701
|
+
} else {
|
|
702
|
+
let nextChange = hunkEnd;
|
|
703
|
+
while (nextChange < allLines.length && nextChange < hunkEnd + contextLines * 2 + 1) {
|
|
704
|
+
if (allLines[nextChange].type !== "unchanged") break;
|
|
705
|
+
nextChange++;
|
|
706
|
+
}
|
|
707
|
+
if (nextChange < allLines.length && nextChange < hunkEnd + contextLines * 2 + 1 && allLines[nextChange].type !== "unchanged") {
|
|
708
|
+
hunkEnd = nextChange + 1;
|
|
709
|
+
} else {
|
|
710
|
+
break;
|
|
711
|
+
}
|
|
712
|
+
}
|
|
713
|
+
}
|
|
714
|
+
hunkEnd = Math.min(allLines.length, hunkEnd + contextLines);
|
|
715
|
+
const hunkLines = allLines.slice(hunkStart, hunkEnd);
|
|
716
|
+
const firstOldLine = hunkLines.find((l) => l.oldLineNum > 0)?.oldLineNum || 1;
|
|
717
|
+
const firstNewLine = hunkLines.find((l) => l.newLineNum > 0)?.newLineNum || 1;
|
|
718
|
+
const oldCount = hunkLines.filter((l) => l.type !== "added").length;
|
|
719
|
+
const newCount = hunkLines.filter((l) => l.type !== "removed").length;
|
|
720
|
+
lines.push(
|
|
721
|
+
pc.cyan(
|
|
722
|
+
`@@ -${firstOldLine},${oldCount} +${firstNewLine},${newCount} @@`
|
|
723
|
+
)
|
|
724
|
+
);
|
|
725
|
+
for (let j = hunkStart; j < hunkEnd; j++) {
|
|
726
|
+
const line = allLines[j];
|
|
727
|
+
if (line.type === "added") {
|
|
728
|
+
lines.push(pc.bgGreen(pc.black(`+ ${line.text}`)));
|
|
729
|
+
} else if (line.type === "removed") {
|
|
730
|
+
lines.push(pc.bgRed(pc.black(`- ${line.text}`)));
|
|
731
|
+
} else {
|
|
732
|
+
lines.push(pc.dim(` ${line.text}`));
|
|
733
|
+
}
|
|
734
|
+
}
|
|
735
|
+
lines.push("");
|
|
736
|
+
i = hunkEnd;
|
|
737
|
+
}
|
|
738
|
+
return lines.join("\n").trimEnd();
|
|
739
|
+
}
|
|
740
|
+
function getDiffStats(oldContent, newContent) {
|
|
741
|
+
const changes = diffLines(oldContent, newContent);
|
|
742
|
+
let added = 0;
|
|
743
|
+
let removed = 0;
|
|
744
|
+
for (const change of changes) {
|
|
745
|
+
const lineCount = splitChangeIntoLines(change.value).length;
|
|
746
|
+
if (change.added) added += lineCount;
|
|
747
|
+
else if (change.removed) removed += lineCount;
|
|
748
|
+
}
|
|
749
|
+
return { added, removed };
|
|
750
|
+
}
|
|
164
751
|
var BATMAN_LOGO = `
|
|
165
752
|
_==/ i i \\==_
|
|
166
753
|
/XX/ |\\___/| \\XX\\
|
|
@@ -212,24 +799,65 @@ async function main(args) {
|
|
|
212
799
|
if (isCancel(commandPrefix)) {
|
|
213
800
|
return;
|
|
214
801
|
}
|
|
215
|
-
const groupedCommands = await getCommandsGroupedByCategory(
|
|
216
|
-
|
|
802
|
+
const groupedCommands = await getCommandsGroupedByCategory(
|
|
803
|
+
variant
|
|
804
|
+
);
|
|
805
|
+
const enabledCommandValues = Object.values(groupedCommands).flat().filter((cmd) => cmd.selectedByDefault).map((cmd) => cmd.value);
|
|
217
806
|
selectedCommands = await groupMultiselect({
|
|
218
807
|
message: "Select commands to install (Enter to accept all)",
|
|
219
808
|
options: groupedCommands,
|
|
220
|
-
initialValues:
|
|
809
|
+
initialValues: enabledCommandValues
|
|
221
810
|
});
|
|
222
811
|
if (isCancel(selectedCommands)) {
|
|
223
812
|
return;
|
|
224
813
|
}
|
|
225
814
|
}
|
|
226
|
-
const
|
|
815
|
+
const existingFiles = await checkExistingFiles(
|
|
816
|
+
void 0,
|
|
817
|
+
variant,
|
|
818
|
+
scope,
|
|
819
|
+
{
|
|
820
|
+
commandPrefix,
|
|
821
|
+
commands: selectedCommands
|
|
822
|
+
}
|
|
823
|
+
);
|
|
824
|
+
const skipFiles = [];
|
|
825
|
+
for (const file of existingFiles) {
|
|
826
|
+
if (file.isIdentical) {
|
|
827
|
+
log.info(`${file.filename} is identical, skipping`);
|
|
828
|
+
skipFiles.push(file.filename);
|
|
829
|
+
continue;
|
|
830
|
+
}
|
|
831
|
+
const stats = getDiffStats(file.existingContent, file.newContent);
|
|
832
|
+
const diff = formatCompactDiff(file.existingContent, file.newContent);
|
|
833
|
+
note(diff, `Diff: ${file.filename}`);
|
|
834
|
+
log.info(`+${stats.added} -${stats.removed}`);
|
|
835
|
+
const shouldOverwrite = await confirm({
|
|
836
|
+
message: `Overwrite ${file.filename}?`
|
|
837
|
+
});
|
|
838
|
+
if (!shouldOverwrite) {
|
|
839
|
+
skipFiles.push(file.filename);
|
|
840
|
+
}
|
|
841
|
+
}
|
|
842
|
+
const result = await generateToDirectory(
|
|
843
|
+
void 0,
|
|
844
|
+
variant,
|
|
845
|
+
scope,
|
|
846
|
+
{
|
|
847
|
+
commandPrefix,
|
|
848
|
+
skipTemplateInjection: args?.skipTemplateInjection,
|
|
849
|
+
commands: selectedCommands,
|
|
850
|
+
skipFiles
|
|
851
|
+
}
|
|
852
|
+
);
|
|
227
853
|
const fullPath = scope === "project" ? `${process.cwd()}/.claude/commands` : `${os2.homedir()}/.claude/commands`;
|
|
228
|
-
outro(
|
|
854
|
+
outro(
|
|
855
|
+
`Installed ${result.filesGenerated} commands to ${fullPath}
|
|
229
856
|
|
|
230
857
|
If Claude Code is already running, restart it to pick up the new commands.
|
|
231
858
|
|
|
232
|
-
Happy TDD'ing!`
|
|
859
|
+
Happy TDD'ing!`
|
|
860
|
+
);
|
|
233
861
|
}
|
|
234
862
|
|
|
235
863
|
// scripts/bin.ts
|