pakhale 0.1.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/LICENSE +21 -0
- package/README.md +72 -0
- package/assets/instructions/AGENTS.md +29 -0
- package/assets/statusline/claude-code.sh +100 -0
- package/dist/cli.js +2037 -0
- package/package.json +50 -0
- package/skills/architecture/SKILL.md +14 -0
- package/skills/consistency-check/DIMENSIONS.md +91 -0
- package/skills/consistency-check/SKILL.md +74 -0
- package/skills/consistency-check/scripts/consistency-workflow.js +158 -0
- package/skills/deslop/SKILL.md +153 -0
- package/skills/deslop/references/python.md +65 -0
- package/skills/deslop/references/react.md +71 -0
- package/skills/deslop/references/typescript.md +62 -0
- package/skills/sitedrop/SKILL.md +40 -0
- package/skills/stackup/SKILL.md +96 -0
- package/skills/stackup/references/hooks-ci.md +132 -0
- package/skills/stackup/references/python.md +81 -0
- package/skills/stackup/references/react.md +79 -0
- package/skills/stackup/references/typescript.md +114 -0
package/dist/cli.js
ADDED
|
@@ -0,0 +1,2037 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { copyFile, lstat, mkdir, readFile, readdir, readlink, rename, rm, symlink, writeFile } from "node:fs/promises";
|
|
3
|
+
import { basename, dirname, join, resolve } from "node:path";
|
|
4
|
+
import { fileURLToPath } from "node:url";
|
|
5
|
+
import { homedir } from "node:os";
|
|
6
|
+
import { parseArgs, styleText } from "node:util";
|
|
7
|
+
import process$1, { stdin, stdout } from "node:process";
|
|
8
|
+
import l__default from "node:readline";
|
|
9
|
+
import { spawn } from "node:child_process";
|
|
10
|
+
|
|
11
|
+
//#region rolldown:runtime
|
|
12
|
+
var __create = Object.create;
|
|
13
|
+
var __defProp = Object.defineProperty;
|
|
14
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
15
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
16
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
17
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
18
|
+
var __commonJS = (cb, mod) => function() {
|
|
19
|
+
return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
|
|
20
|
+
};
|
|
21
|
+
var __copyProps = (to, from, except, desc) => {
|
|
22
|
+
if (from && typeof from === "object" || typeof from === "function") for (var keys = __getOwnPropNames(from), i$1 = 0, n$2 = keys.length, key; i$1 < n$2; i$1++) {
|
|
23
|
+
key = keys[i$1];
|
|
24
|
+
if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, {
|
|
25
|
+
get: ((k) => from[k]).bind(null, key),
|
|
26
|
+
enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
return to;
|
|
30
|
+
};
|
|
31
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", {
|
|
32
|
+
value: mod,
|
|
33
|
+
enumerable: true
|
|
34
|
+
}) : target, mod));
|
|
35
|
+
|
|
36
|
+
//#endregion
|
|
37
|
+
//#region node_modules/picocolors/picocolors.js
|
|
38
|
+
var require_picocolors = /* @__PURE__ */ __commonJS({ "node_modules/picocolors/picocolors.js": ((exports, module) => {
|
|
39
|
+
let p = process || {}, argv = p.argv || [], env = p.env || {};
|
|
40
|
+
let 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);
|
|
41
|
+
let formatter = (open, close, replace = open) => (input) => {
|
|
42
|
+
let string = "" + input, index = string.indexOf(close, open.length);
|
|
43
|
+
return ~index ? open + replaceClose(string, close, replace, index) + close : open + string + close;
|
|
44
|
+
};
|
|
45
|
+
let replaceClose = (string, close, replace, index) => {
|
|
46
|
+
let result = "", cursor$3 = 0;
|
|
47
|
+
do {
|
|
48
|
+
result += string.substring(cursor$3, index) + replace;
|
|
49
|
+
cursor$3 = index + close.length;
|
|
50
|
+
index = string.indexOf(close, cursor$3);
|
|
51
|
+
} while (~index);
|
|
52
|
+
return result + string.substring(cursor$3);
|
|
53
|
+
};
|
|
54
|
+
let createColors = (enabled = isColorSupported) => {
|
|
55
|
+
let f = enabled ? formatter : () => String;
|
|
56
|
+
return {
|
|
57
|
+
isColorSupported: enabled,
|
|
58
|
+
reset: f("\x1B[0m", "\x1B[0m"),
|
|
59
|
+
bold: f("\x1B[1m", "\x1B[22m", "\x1B[22m\x1B[1m"),
|
|
60
|
+
dim: f("\x1B[2m", "\x1B[22m", "\x1B[22m\x1B[2m"),
|
|
61
|
+
italic: f("\x1B[3m", "\x1B[23m"),
|
|
62
|
+
underline: f("\x1B[4m", "\x1B[24m"),
|
|
63
|
+
inverse: f("\x1B[7m", "\x1B[27m"),
|
|
64
|
+
hidden: f("\x1B[8m", "\x1B[28m"),
|
|
65
|
+
strikethrough: f("\x1B[9m", "\x1B[29m"),
|
|
66
|
+
black: f("\x1B[30m", "\x1B[39m"),
|
|
67
|
+
red: f("\x1B[31m", "\x1B[39m"),
|
|
68
|
+
green: f("\x1B[32m", "\x1B[39m"),
|
|
69
|
+
yellow: f("\x1B[33m", "\x1B[39m"),
|
|
70
|
+
blue: f("\x1B[34m", "\x1B[39m"),
|
|
71
|
+
magenta: f("\x1B[35m", "\x1B[39m"),
|
|
72
|
+
cyan: f("\x1B[36m", "\x1B[39m"),
|
|
73
|
+
white: f("\x1B[37m", "\x1B[39m"),
|
|
74
|
+
gray: f("\x1B[90m", "\x1B[39m"),
|
|
75
|
+
bgBlack: f("\x1B[40m", "\x1B[49m"),
|
|
76
|
+
bgRed: f("\x1B[41m", "\x1B[49m"),
|
|
77
|
+
bgGreen: f("\x1B[42m", "\x1B[49m"),
|
|
78
|
+
bgYellow: f("\x1B[43m", "\x1B[49m"),
|
|
79
|
+
bgBlue: f("\x1B[44m", "\x1B[49m"),
|
|
80
|
+
bgMagenta: f("\x1B[45m", "\x1B[49m"),
|
|
81
|
+
bgCyan: f("\x1B[46m", "\x1B[49m"),
|
|
82
|
+
bgWhite: f("\x1B[47m", "\x1B[49m"),
|
|
83
|
+
blackBright: f("\x1B[90m", "\x1B[39m"),
|
|
84
|
+
redBright: f("\x1B[91m", "\x1B[39m"),
|
|
85
|
+
greenBright: f("\x1B[92m", "\x1B[39m"),
|
|
86
|
+
yellowBright: f("\x1B[93m", "\x1B[39m"),
|
|
87
|
+
blueBright: f("\x1B[94m", "\x1B[39m"),
|
|
88
|
+
magentaBright: f("\x1B[95m", "\x1B[39m"),
|
|
89
|
+
cyanBright: f("\x1B[96m", "\x1B[39m"),
|
|
90
|
+
whiteBright: f("\x1B[97m", "\x1B[39m"),
|
|
91
|
+
bgBlackBright: f("\x1B[100m", "\x1B[49m"),
|
|
92
|
+
bgRedBright: f("\x1B[101m", "\x1B[49m"),
|
|
93
|
+
bgGreenBright: f("\x1B[102m", "\x1B[49m"),
|
|
94
|
+
bgYellowBright: f("\x1B[103m", "\x1B[49m"),
|
|
95
|
+
bgBlueBright: f("\x1B[104m", "\x1B[49m"),
|
|
96
|
+
bgMagentaBright: f("\x1B[105m", "\x1B[49m"),
|
|
97
|
+
bgCyanBright: f("\x1B[106m", "\x1B[49m"),
|
|
98
|
+
bgWhiteBright: f("\x1B[107m", "\x1B[49m")
|
|
99
|
+
};
|
|
100
|
+
};
|
|
101
|
+
module.exports = createColors();
|
|
102
|
+
module.exports.createColors = createColors;
|
|
103
|
+
}) });
|
|
104
|
+
|
|
105
|
+
//#endregion
|
|
106
|
+
//#region config.ts
|
|
107
|
+
var import_picocolors$3 = /* @__PURE__ */ __toESM(require_picocolors(), 1);
|
|
108
|
+
const config = {
|
|
109
|
+
agents: ["claude-code", "opencode"],
|
|
110
|
+
marketplaces: {
|
|
111
|
+
"claude-plugins-official": {
|
|
112
|
+
repo: "anthropics/claude-plugins-official",
|
|
113
|
+
builtin: true
|
|
114
|
+
},
|
|
115
|
+
plannotator: { repo: "backnotprop/plannotator" },
|
|
116
|
+
impeccable: { repo: "pbakaus/impeccable" }
|
|
117
|
+
},
|
|
118
|
+
extensions: [
|
|
119
|
+
{
|
|
120
|
+
name: "context7",
|
|
121
|
+
deliver: {
|
|
122
|
+
"claude-code": {
|
|
123
|
+
via: "claude-plugin",
|
|
124
|
+
marketplace: "claude-plugins-official",
|
|
125
|
+
plugin: "context7"
|
|
126
|
+
},
|
|
127
|
+
opencode: {
|
|
128
|
+
via: "mcp",
|
|
129
|
+
server: {
|
|
130
|
+
transport: "stdio",
|
|
131
|
+
command: [
|
|
132
|
+
"npx",
|
|
133
|
+
"-y",
|
|
134
|
+
"@upstash/context7-mcp"
|
|
135
|
+
]
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
},
|
|
140
|
+
{
|
|
141
|
+
name: "mattpocock-skills",
|
|
142
|
+
deliver: {
|
|
143
|
+
"claude-code": {
|
|
144
|
+
via: "claude-plugin",
|
|
145
|
+
marketplace: "claude-plugins-official",
|
|
146
|
+
plugin: "mattpocock-skills"
|
|
147
|
+
},
|
|
148
|
+
opencode: {
|
|
149
|
+
via: "skills",
|
|
150
|
+
repo: "mattpocock/skills"
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
},
|
|
154
|
+
{
|
|
155
|
+
name: "plannotator",
|
|
156
|
+
deliver: {
|
|
157
|
+
"claude-code": {
|
|
158
|
+
via: "claude-plugin",
|
|
159
|
+
marketplace: "plannotator",
|
|
160
|
+
plugin: "plannotator"
|
|
161
|
+
},
|
|
162
|
+
opencode: {
|
|
163
|
+
via: "opencode-plugin",
|
|
164
|
+
package: "@plannotator/opencode@latest"
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
},
|
|
168
|
+
{
|
|
169
|
+
name: "impeccable",
|
|
170
|
+
deliver: {
|
|
171
|
+
"claude-code": {
|
|
172
|
+
via: "claude-plugin",
|
|
173
|
+
marketplace: "impeccable",
|
|
174
|
+
plugin: "impeccable"
|
|
175
|
+
},
|
|
176
|
+
opencode: {
|
|
177
|
+
via: "skills",
|
|
178
|
+
repo: "pbakaus/impeccable",
|
|
179
|
+
skills: ["impeccable"]
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
},
|
|
183
|
+
{
|
|
184
|
+
name: "vercel-agent-skills",
|
|
185
|
+
deliver: { all: {
|
|
186
|
+
via: "skills",
|
|
187
|
+
repo: "vercel-labs/agent-skills",
|
|
188
|
+
skills: ["vercel-react-best-practices", "vercel-composition-patterns"]
|
|
189
|
+
} }
|
|
190
|
+
},
|
|
191
|
+
{
|
|
192
|
+
name: "gh-stack",
|
|
193
|
+
deliver: { all: {
|
|
194
|
+
via: "skills",
|
|
195
|
+
repo: "github/gh-stack",
|
|
196
|
+
skills: ["gh-stack"]
|
|
197
|
+
} }
|
|
198
|
+
}
|
|
199
|
+
],
|
|
200
|
+
authoredSkillsDir: "skills",
|
|
201
|
+
instructionsFile: "assets/instructions/AGENTS.md",
|
|
202
|
+
claudeCode: {
|
|
203
|
+
statuslineScript: "assets/statusline/claude-code.sh",
|
|
204
|
+
autoCompactWindow: 25e4,
|
|
205
|
+
tui: "fullscreen",
|
|
206
|
+
cleanupPeriodDays: 14,
|
|
207
|
+
voice: true,
|
|
208
|
+
autoDream: false,
|
|
209
|
+
agentPushNotifications: true,
|
|
210
|
+
permissions: {
|
|
211
|
+
defaultMode: "auto",
|
|
212
|
+
skipDangerousModePrompt: true,
|
|
213
|
+
skipAutoPrompt: true
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
};
|
|
217
|
+
|
|
218
|
+
//#endregion
|
|
219
|
+
//#region src/util/log.ts
|
|
220
|
+
const log = {
|
|
221
|
+
agent: (s) => console.log(`\n${import_picocolors$3.default.bold(import_picocolors$3.default.magenta(`■ ${s}`))}`),
|
|
222
|
+
section: (s) => console.log(`\n${import_picocolors$3.default.bold(import_picocolors$3.default.cyan(`▸ ${s}`))}`),
|
|
223
|
+
ok: (s) => console.log(` ${import_picocolors$3.default.green("✓")} ${s}`),
|
|
224
|
+
skip: (s) => console.log(` ${import_picocolors$3.default.dim("·")} ${import_picocolors$3.default.dim(s)}`),
|
|
225
|
+
warn: (s) => console.log(` ${import_picocolors$3.default.yellow("!")} ${s}`),
|
|
226
|
+
fail: (s) => console.log(` ${import_picocolors$3.default.red("✗")} ${s}`),
|
|
227
|
+
plan: (s) => console.log(` ${import_picocolors$3.default.yellow("would")} ${s}`),
|
|
228
|
+
info: (s) => console.log(` ${import_picocolors$3.default.dim(s)}`)
|
|
229
|
+
};
|
|
230
|
+
|
|
231
|
+
//#endregion
|
|
232
|
+
//#region node_modules/fast-string-truncated-width/dist/utils.js
|
|
233
|
+
const getCodePointsLength = (() => {
|
|
234
|
+
const SURROGATE_PAIR_RE = /[\uD800-\uDBFF][\uDC00-\uDFFF]/g;
|
|
235
|
+
return (input) => {
|
|
236
|
+
let surrogatePairsNr = 0;
|
|
237
|
+
SURROGATE_PAIR_RE.lastIndex = 0;
|
|
238
|
+
while (SURROGATE_PAIR_RE.test(input)) surrogatePairsNr += 1;
|
|
239
|
+
return input.length - surrogatePairsNr;
|
|
240
|
+
};
|
|
241
|
+
})();
|
|
242
|
+
const isFullWidth = (x) => {
|
|
243
|
+
return x === 12288 || x >= 65281 && x <= 65376 || x >= 65504 && x <= 65510;
|
|
244
|
+
};
|
|
245
|
+
const isWideNotCJKTNotEmoji = (x) => {
|
|
246
|
+
return x === 8987 || x === 9001 || x >= 12272 && x <= 12287 || x >= 12289 && x <= 12350 || x >= 12441 && x <= 12543 || x >= 12549 && x <= 12591 || x >= 12593 && x <= 12686 || x >= 12688 && x <= 12771 || x >= 12783 && x <= 12830 || x >= 12832 && x <= 12871 || x >= 12880 && x <= 19903 || x >= 65040 && x <= 65049 || x >= 65072 && x <= 65106 || x >= 65108 && x <= 65126 || x >= 65128 && x <= 65131 || x >= 127488 && x <= 127490 || x >= 127504 && x <= 127547 || x >= 127552 && x <= 127560 || x >= 131072 && x <= 196605 || x >= 196608 && x <= 262141;
|
|
247
|
+
};
|
|
248
|
+
|
|
249
|
+
//#endregion
|
|
250
|
+
//#region node_modules/fast-string-truncated-width/dist/index.js
|
|
251
|
+
const ANSI_RE = /[\u001b\u009b][[()#;?]*(?:[0-9]{1,4}(?:;[0-9]{0,4})*)?[0-9A-ORZcf-nqry=><]|\u001b\]8;[^;]*;.*?(?:\u0007|\u001b\u005c)/y;
|
|
252
|
+
const CONTROL_RE = /[\x00-\x08\x0A-\x1F\x7F-\x9F]{1,1000}/y;
|
|
253
|
+
const CJKT_WIDE_RE = /(?:(?![\uFF61-\uFF9F\uFF00-\uFFEF])[\p{Script=Han}\p{Script=Hiragana}\p{Script=Katakana}\p{Script=Hangul}\p{Script=Tangut}]){1,1000}/uy;
|
|
254
|
+
const TAB_RE = /\t{1,1000}/y;
|
|
255
|
+
const EMOJI_RE = /[\u{1F1E6}-\u{1F1FF}]{2}|\u{1F3F4}[\u{E0061}-\u{E007A}]{2}[\u{E0030}-\u{E0039}\u{E0061}-\u{E007A}]{1,3}\u{E007F}|(?:\p{Emoji}\uFE0F\u20E3?|\p{Emoji_Modifier_Base}\p{Emoji_Modifier}?|\p{Emoji_Presentation})(?:\u200D(?:\p{Emoji_Modifier_Base}\p{Emoji_Modifier}?|\p{Emoji_Presentation}|\p{Emoji}\uFE0F\u20E3?))*/uy;
|
|
256
|
+
const LATIN_RE = /(?:[\x20-\x7E\xA0-\xFF](?!\uFE0F)){1,1000}/y;
|
|
257
|
+
const MODIFIER_RE = /\p{M}+/gu;
|
|
258
|
+
const NO_TRUNCATION$1 = {
|
|
259
|
+
limit: Infinity,
|
|
260
|
+
ellipsis: ""
|
|
261
|
+
};
|
|
262
|
+
const getStringTruncatedWidth = (input, truncationOptions = {}, widthOptions = {}) => {
|
|
263
|
+
const LIMIT = truncationOptions.limit ?? Infinity;
|
|
264
|
+
const ELLIPSIS = truncationOptions.ellipsis ?? "";
|
|
265
|
+
const ELLIPSIS_WIDTH = truncationOptions?.ellipsisWidth ?? (ELLIPSIS ? getStringTruncatedWidth(ELLIPSIS, NO_TRUNCATION$1, widthOptions).width : 0);
|
|
266
|
+
const ANSI_WIDTH = 0;
|
|
267
|
+
const CONTROL_WIDTH = widthOptions.controlWidth ?? 0;
|
|
268
|
+
const TAB_WIDTH = widthOptions.tabWidth ?? 8;
|
|
269
|
+
const EMOJI_WIDTH = widthOptions.emojiWidth ?? 2;
|
|
270
|
+
const FULL_WIDTH_WIDTH = 2;
|
|
271
|
+
const REGULAR_WIDTH = widthOptions.regularWidth ?? 1;
|
|
272
|
+
const WIDE_WIDTH = widthOptions.wideWidth ?? FULL_WIDTH_WIDTH;
|
|
273
|
+
const PARSE_BLOCKS = [
|
|
274
|
+
[LATIN_RE, REGULAR_WIDTH],
|
|
275
|
+
[ANSI_RE, ANSI_WIDTH],
|
|
276
|
+
[CONTROL_RE, CONTROL_WIDTH],
|
|
277
|
+
[TAB_RE, TAB_WIDTH],
|
|
278
|
+
[EMOJI_RE, EMOJI_WIDTH],
|
|
279
|
+
[CJKT_WIDE_RE, WIDE_WIDTH]
|
|
280
|
+
];
|
|
281
|
+
let indexPrev = 0;
|
|
282
|
+
let index = 0;
|
|
283
|
+
let length = input.length;
|
|
284
|
+
let lengthExtra = 0;
|
|
285
|
+
let truncationEnabled = false;
|
|
286
|
+
let truncationIndex = length;
|
|
287
|
+
let truncationLimit = Math.max(0, LIMIT - ELLIPSIS_WIDTH);
|
|
288
|
+
let unmatchedStart = 0;
|
|
289
|
+
let unmatchedEnd = 0;
|
|
290
|
+
let width = 0;
|
|
291
|
+
let widthExtra = 0;
|
|
292
|
+
outer: while (true) {
|
|
293
|
+
if (unmatchedEnd > unmatchedStart || index >= length && index > indexPrev) {
|
|
294
|
+
const unmatched = input.slice(unmatchedStart, unmatchedEnd) || input.slice(indexPrev, index);
|
|
295
|
+
lengthExtra = 0;
|
|
296
|
+
for (const char of unmatched.replaceAll(MODIFIER_RE, "")) {
|
|
297
|
+
const codePoint = char.codePointAt(0) || 0;
|
|
298
|
+
if (isFullWidth(codePoint)) widthExtra = FULL_WIDTH_WIDTH;
|
|
299
|
+
else if (isWideNotCJKTNotEmoji(codePoint)) widthExtra = WIDE_WIDTH;
|
|
300
|
+
else widthExtra = REGULAR_WIDTH;
|
|
301
|
+
if (width + widthExtra > truncationLimit) truncationIndex = Math.min(truncationIndex, Math.max(unmatchedStart, indexPrev) + lengthExtra);
|
|
302
|
+
if (width + widthExtra > LIMIT) {
|
|
303
|
+
truncationEnabled = true;
|
|
304
|
+
break outer;
|
|
305
|
+
}
|
|
306
|
+
lengthExtra += char.length;
|
|
307
|
+
width += widthExtra;
|
|
308
|
+
}
|
|
309
|
+
unmatchedStart = unmatchedEnd = 0;
|
|
310
|
+
}
|
|
311
|
+
if (index >= length) break outer;
|
|
312
|
+
for (let i$1 = 0, l = PARSE_BLOCKS.length; i$1 < l; i$1++) {
|
|
313
|
+
const [BLOCK_RE, BLOCK_WIDTH] = PARSE_BLOCKS[i$1];
|
|
314
|
+
BLOCK_RE.lastIndex = index;
|
|
315
|
+
if (BLOCK_RE.test(input)) {
|
|
316
|
+
lengthExtra = BLOCK_RE === CJKT_WIDE_RE ? getCodePointsLength(input.slice(index, BLOCK_RE.lastIndex)) : BLOCK_RE === EMOJI_RE ? 1 : BLOCK_RE.lastIndex - index;
|
|
317
|
+
widthExtra = lengthExtra * BLOCK_WIDTH;
|
|
318
|
+
if (width + widthExtra > truncationLimit) truncationIndex = Math.min(truncationIndex, index + Math.floor((truncationLimit - width) / BLOCK_WIDTH));
|
|
319
|
+
if (width + widthExtra > LIMIT) {
|
|
320
|
+
truncationEnabled = true;
|
|
321
|
+
break outer;
|
|
322
|
+
}
|
|
323
|
+
width += widthExtra;
|
|
324
|
+
unmatchedStart = indexPrev;
|
|
325
|
+
unmatchedEnd = index;
|
|
326
|
+
index = indexPrev = BLOCK_RE.lastIndex;
|
|
327
|
+
continue outer;
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
index += 1;
|
|
331
|
+
}
|
|
332
|
+
return {
|
|
333
|
+
width: truncationEnabled ? truncationLimit : width,
|
|
334
|
+
index: truncationEnabled ? truncationIndex : length,
|
|
335
|
+
truncated: truncationEnabled,
|
|
336
|
+
ellipsed: truncationEnabled && LIMIT >= ELLIPSIS_WIDTH
|
|
337
|
+
};
|
|
338
|
+
};
|
|
339
|
+
var dist_default$1 = getStringTruncatedWidth;
|
|
340
|
+
|
|
341
|
+
//#endregion
|
|
342
|
+
//#region node_modules/fast-string-width/dist/index.js
|
|
343
|
+
const NO_TRUNCATION = {
|
|
344
|
+
limit: Infinity,
|
|
345
|
+
ellipsis: "",
|
|
346
|
+
ellipsisWidth: 0
|
|
347
|
+
};
|
|
348
|
+
const fastStringWidth = (input, options = {}) => {
|
|
349
|
+
return dist_default$1(input, NO_TRUNCATION, options).width;
|
|
350
|
+
};
|
|
351
|
+
var dist_default = fastStringWidth;
|
|
352
|
+
|
|
353
|
+
//#endregion
|
|
354
|
+
//#region node_modules/fast-wrap-ansi/lib/main.js
|
|
355
|
+
const ESC$1 = "\x1B";
|
|
356
|
+
const CSI$1 = "";
|
|
357
|
+
const END_CODE = 39;
|
|
358
|
+
const ANSI_ESCAPE_BELL = "\x07";
|
|
359
|
+
const ANSI_CSI = "[";
|
|
360
|
+
const ANSI_OSC = "]";
|
|
361
|
+
const ANSI_SGR_TERMINATOR = "m";
|
|
362
|
+
const ANSI_ESCAPE_LINK = `${ANSI_OSC}8;;`;
|
|
363
|
+
const GROUP_REGEX = new RegExp(`(?:\\${ANSI_CSI}(?<code>\\d+)m|\\${ANSI_ESCAPE_LINK}(?<uri>.*)${ANSI_ESCAPE_BELL})`, "y");
|
|
364
|
+
const getClosingCode = (openingCode) => {
|
|
365
|
+
if (openingCode >= 30 && openingCode <= 37) return 39;
|
|
366
|
+
if (openingCode >= 90 && openingCode <= 97) return 39;
|
|
367
|
+
if (openingCode >= 40 && openingCode <= 47) return 49;
|
|
368
|
+
if (openingCode >= 100 && openingCode <= 107) return 49;
|
|
369
|
+
if (openingCode === 1 || openingCode === 2) return 22;
|
|
370
|
+
if (openingCode === 3) return 23;
|
|
371
|
+
if (openingCode === 4) return 24;
|
|
372
|
+
if (openingCode === 7) return 27;
|
|
373
|
+
if (openingCode === 8) return 28;
|
|
374
|
+
if (openingCode === 9) return 29;
|
|
375
|
+
if (openingCode === 0) return 0;
|
|
376
|
+
};
|
|
377
|
+
const wrapAnsiCode = (code) => `${ESC$1}${ANSI_CSI}${code}${ANSI_SGR_TERMINATOR}`;
|
|
378
|
+
const wrapAnsiHyperlink = (url) => `${ESC$1}${ANSI_ESCAPE_LINK}${url}${ANSI_ESCAPE_BELL}`;
|
|
379
|
+
const wrapWord = (rows, word, columns) => {
|
|
380
|
+
const characters = word[Symbol.iterator]();
|
|
381
|
+
let isInsideEscape = false;
|
|
382
|
+
let isInsideLinkEscape = false;
|
|
383
|
+
let lastRow = rows.at(-1);
|
|
384
|
+
let visible = lastRow === void 0 ? 0 : dist_default(lastRow);
|
|
385
|
+
let currentCharacter = characters.next();
|
|
386
|
+
let nextCharacter = characters.next();
|
|
387
|
+
let rawCharacterIndex = 0;
|
|
388
|
+
while (!currentCharacter.done) {
|
|
389
|
+
const character = currentCharacter.value;
|
|
390
|
+
const characterLength = dist_default(character);
|
|
391
|
+
if (visible + characterLength <= columns) rows[rows.length - 1] += character;
|
|
392
|
+
else {
|
|
393
|
+
rows.push(character);
|
|
394
|
+
visible = 0;
|
|
395
|
+
}
|
|
396
|
+
if (character === ESC$1 || character === CSI$1) {
|
|
397
|
+
isInsideEscape = true;
|
|
398
|
+
isInsideLinkEscape = word.startsWith(ANSI_ESCAPE_LINK, rawCharacterIndex + 1);
|
|
399
|
+
}
|
|
400
|
+
if (isInsideEscape) {
|
|
401
|
+
if (isInsideLinkEscape) {
|
|
402
|
+
if (character === ANSI_ESCAPE_BELL) {
|
|
403
|
+
isInsideEscape = false;
|
|
404
|
+
isInsideLinkEscape = false;
|
|
405
|
+
}
|
|
406
|
+
} else if (character === ANSI_SGR_TERMINATOR) isInsideEscape = false;
|
|
407
|
+
} else {
|
|
408
|
+
visible += characterLength;
|
|
409
|
+
if (visible === columns && !nextCharacter.done) {
|
|
410
|
+
rows.push("");
|
|
411
|
+
visible = 0;
|
|
412
|
+
}
|
|
413
|
+
}
|
|
414
|
+
currentCharacter = nextCharacter;
|
|
415
|
+
nextCharacter = characters.next();
|
|
416
|
+
rawCharacterIndex += character.length;
|
|
417
|
+
}
|
|
418
|
+
lastRow = rows.at(-1);
|
|
419
|
+
if (!visible && lastRow !== void 0 && lastRow.length && rows.length > 1) rows[rows.length - 2] += rows.pop();
|
|
420
|
+
};
|
|
421
|
+
const stringVisibleTrimSpacesRight = (string) => {
|
|
422
|
+
const words = string.split(" ");
|
|
423
|
+
let last = words.length;
|
|
424
|
+
while (last) {
|
|
425
|
+
if (dist_default(words[last - 1])) break;
|
|
426
|
+
last--;
|
|
427
|
+
}
|
|
428
|
+
if (last === words.length) return string;
|
|
429
|
+
return words.slice(0, last).join(" ") + words.slice(last).join("");
|
|
430
|
+
};
|
|
431
|
+
const exec = (string, columns, options = {}) => {
|
|
432
|
+
if (options.trim !== false && string.trim() === "") return "";
|
|
433
|
+
let returnValue = "";
|
|
434
|
+
let escapeCode;
|
|
435
|
+
let escapeUrl;
|
|
436
|
+
const words = string.split(" ");
|
|
437
|
+
let rows = [""];
|
|
438
|
+
let rowLength = 0;
|
|
439
|
+
for (let index = 0; index < words.length; index++) {
|
|
440
|
+
const word = words[index];
|
|
441
|
+
if (options.trim !== false) {
|
|
442
|
+
const row = rows.at(-1) ?? "";
|
|
443
|
+
const trimmed = row.trimStart();
|
|
444
|
+
if (row.length !== trimmed.length) {
|
|
445
|
+
rows[rows.length - 1] = trimmed;
|
|
446
|
+
rowLength = dist_default(trimmed);
|
|
447
|
+
}
|
|
448
|
+
}
|
|
449
|
+
if (index !== 0) {
|
|
450
|
+
if (rowLength >= columns && (options.wordWrap === false || options.trim === false)) {
|
|
451
|
+
rows.push("");
|
|
452
|
+
rowLength = 0;
|
|
453
|
+
}
|
|
454
|
+
if (rowLength || options.trim === false) {
|
|
455
|
+
rows[rows.length - 1] += " ";
|
|
456
|
+
rowLength++;
|
|
457
|
+
}
|
|
458
|
+
}
|
|
459
|
+
const wordLength = dist_default(word);
|
|
460
|
+
if (options.hard && wordLength > columns) {
|
|
461
|
+
const remainingColumns = columns - rowLength;
|
|
462
|
+
const breaksStartingThisLine = 1 + Math.floor((wordLength - remainingColumns - 1) / columns);
|
|
463
|
+
if (Math.floor((wordLength - 1) / columns) < breaksStartingThisLine) rows.push("");
|
|
464
|
+
wrapWord(rows, word, columns);
|
|
465
|
+
rowLength = dist_default(rows.at(-1) ?? "");
|
|
466
|
+
continue;
|
|
467
|
+
}
|
|
468
|
+
if (rowLength + wordLength > columns && rowLength && wordLength) {
|
|
469
|
+
if (options.wordWrap === false && rowLength < columns) {
|
|
470
|
+
wrapWord(rows, word, columns);
|
|
471
|
+
rowLength = dist_default(rows.at(-1) ?? "");
|
|
472
|
+
continue;
|
|
473
|
+
}
|
|
474
|
+
rows.push("");
|
|
475
|
+
rowLength = 0;
|
|
476
|
+
}
|
|
477
|
+
if (rowLength + wordLength > columns && options.wordWrap === false) {
|
|
478
|
+
wrapWord(rows, word, columns);
|
|
479
|
+
rowLength = dist_default(rows.at(-1) ?? "");
|
|
480
|
+
continue;
|
|
481
|
+
}
|
|
482
|
+
rows[rows.length - 1] += word;
|
|
483
|
+
rowLength += wordLength;
|
|
484
|
+
}
|
|
485
|
+
if (options.trim !== false) rows = rows.map((row) => stringVisibleTrimSpacesRight(row));
|
|
486
|
+
const preString = rows.join("\n");
|
|
487
|
+
let inSurrogate = false;
|
|
488
|
+
for (let i$1 = 0; i$1 < preString.length; i$1++) {
|
|
489
|
+
const character = preString[i$1];
|
|
490
|
+
returnValue += character;
|
|
491
|
+
if (!inSurrogate) {
|
|
492
|
+
inSurrogate = character >= "\ud800" && character <= "\udbff";
|
|
493
|
+
if (inSurrogate) continue;
|
|
494
|
+
} else inSurrogate = false;
|
|
495
|
+
if (character === ESC$1 || character === CSI$1) {
|
|
496
|
+
GROUP_REGEX.lastIndex = i$1 + 1;
|
|
497
|
+
const groups = GROUP_REGEX.exec(preString)?.groups;
|
|
498
|
+
if (groups?.code !== void 0) {
|
|
499
|
+
const code = Number.parseFloat(groups.code);
|
|
500
|
+
escapeCode = code === END_CODE ? void 0 : code;
|
|
501
|
+
} else if (groups?.uri !== void 0) escapeUrl = groups.uri.length === 0 ? void 0 : groups.uri;
|
|
502
|
+
}
|
|
503
|
+
if (preString[i$1 + 1] === "\n") {
|
|
504
|
+
if (escapeUrl) returnValue += wrapAnsiHyperlink("");
|
|
505
|
+
const closingCode = escapeCode ? getClosingCode(escapeCode) : void 0;
|
|
506
|
+
if (escapeCode && closingCode) returnValue += wrapAnsiCode(closingCode);
|
|
507
|
+
} else if (character === "\n") {
|
|
508
|
+
if (escapeCode && getClosingCode(escapeCode)) returnValue += wrapAnsiCode(escapeCode);
|
|
509
|
+
if (escapeUrl) returnValue += wrapAnsiHyperlink(escapeUrl);
|
|
510
|
+
}
|
|
511
|
+
}
|
|
512
|
+
return returnValue;
|
|
513
|
+
};
|
|
514
|
+
const CRLF_OR_LF = /\r?\n/;
|
|
515
|
+
function wrapAnsi(string, columns, options) {
|
|
516
|
+
return String(string).normalize().split(CRLF_OR_LF).map((line) => exec(line, columns, options)).join("\n");
|
|
517
|
+
}
|
|
518
|
+
|
|
519
|
+
//#endregion
|
|
520
|
+
//#region node_modules/sisteransi/src/index.js
|
|
521
|
+
var require_src = /* @__PURE__ */ __commonJS({ "node_modules/sisteransi/src/index.js": ((exports, module) => {
|
|
522
|
+
const ESC = "\x1B";
|
|
523
|
+
const CSI = `${ESC}[`;
|
|
524
|
+
const beep = "\x07";
|
|
525
|
+
const cursor$2 = {
|
|
526
|
+
to(x, y) {
|
|
527
|
+
if (!y) return `${CSI}${x + 1}G`;
|
|
528
|
+
return `${CSI}${y + 1};${x + 1}H`;
|
|
529
|
+
},
|
|
530
|
+
move(x, y) {
|
|
531
|
+
let ret = "";
|
|
532
|
+
if (x < 0) ret += `${CSI}${-x}D`;
|
|
533
|
+
else if (x > 0) ret += `${CSI}${x}C`;
|
|
534
|
+
if (y < 0) ret += `${CSI}${-y}A`;
|
|
535
|
+
else if (y > 0) ret += `${CSI}${y}B`;
|
|
536
|
+
return ret;
|
|
537
|
+
},
|
|
538
|
+
up: (count = 1) => `${CSI}${count}A`,
|
|
539
|
+
down: (count = 1) => `${CSI}${count}B`,
|
|
540
|
+
forward: (count = 1) => `${CSI}${count}C`,
|
|
541
|
+
backward: (count = 1) => `${CSI}${count}D`,
|
|
542
|
+
nextLine: (count = 1) => `${CSI}E`.repeat(count),
|
|
543
|
+
prevLine: (count = 1) => `${CSI}F`.repeat(count),
|
|
544
|
+
left: `${CSI}G`,
|
|
545
|
+
hide: `${CSI}?25l`,
|
|
546
|
+
show: `${CSI}?25h`,
|
|
547
|
+
save: `${ESC}7`,
|
|
548
|
+
restore: `${ESC}8`
|
|
549
|
+
};
|
|
550
|
+
const scroll = {
|
|
551
|
+
up: (count = 1) => `${CSI}S`.repeat(count),
|
|
552
|
+
down: (count = 1) => `${CSI}T`.repeat(count)
|
|
553
|
+
};
|
|
554
|
+
const erase$2 = {
|
|
555
|
+
screen: `${CSI}2J`,
|
|
556
|
+
up: (count = 1) => `${CSI}1J`.repeat(count),
|
|
557
|
+
down: (count = 1) => `${CSI}J`.repeat(count),
|
|
558
|
+
line: `${CSI}2K`,
|
|
559
|
+
lineEnd: `${CSI}K`,
|
|
560
|
+
lineStart: `${CSI}1K`,
|
|
561
|
+
lines(count) {
|
|
562
|
+
let clear = "";
|
|
563
|
+
for (let i$1 = 0; i$1 < count; i$1++) clear += this.line + (i$1 < count - 1 ? cursor$2.up() : "");
|
|
564
|
+
if (count) clear += cursor$2.left;
|
|
565
|
+
return clear;
|
|
566
|
+
}
|
|
567
|
+
};
|
|
568
|
+
module.exports = {
|
|
569
|
+
cursor: cursor$2,
|
|
570
|
+
scroll,
|
|
571
|
+
erase: erase$2,
|
|
572
|
+
beep
|
|
573
|
+
};
|
|
574
|
+
}) });
|
|
575
|
+
|
|
576
|
+
//#endregion
|
|
577
|
+
//#region node_modules/@clack/core/dist/index.mjs
|
|
578
|
+
var import_src$1 = /* @__PURE__ */ __toESM(require_src(), 1);
|
|
579
|
+
function findCursor(s, o, l) {
|
|
580
|
+
if (!l.some((r$1) => !r$1.disabled)) return s;
|
|
581
|
+
const t = s + o, n$2 = Math.max(l.length - 1, 0), e = t < 0 ? n$2 : t > n$2 ? 0 : t;
|
|
582
|
+
return l[e]?.disabled ? findCursor(e, o < 0 ? -1 : 1, l) : e;
|
|
583
|
+
}
|
|
584
|
+
const settings = {
|
|
585
|
+
actions: new Set([
|
|
586
|
+
"up",
|
|
587
|
+
"down",
|
|
588
|
+
"left",
|
|
589
|
+
"right",
|
|
590
|
+
"space",
|
|
591
|
+
"enter",
|
|
592
|
+
"cancel"
|
|
593
|
+
]),
|
|
594
|
+
aliases: /* @__PURE__ */ new Map([
|
|
595
|
+
["k", "up"],
|
|
596
|
+
["j", "down"],
|
|
597
|
+
["h", "left"],
|
|
598
|
+
["l", "right"],
|
|
599
|
+
["", "cancel"],
|
|
600
|
+
["escape", "cancel"]
|
|
601
|
+
]),
|
|
602
|
+
messages: {
|
|
603
|
+
cancel: "Canceled",
|
|
604
|
+
error: "Something went wrong"
|
|
605
|
+
},
|
|
606
|
+
withGuide: true,
|
|
607
|
+
date: {
|
|
608
|
+
monthNames: [...[
|
|
609
|
+
"January",
|
|
610
|
+
"February",
|
|
611
|
+
"March",
|
|
612
|
+
"April",
|
|
613
|
+
"May",
|
|
614
|
+
"June",
|
|
615
|
+
"July",
|
|
616
|
+
"August",
|
|
617
|
+
"September",
|
|
618
|
+
"October",
|
|
619
|
+
"November",
|
|
620
|
+
"December"
|
|
621
|
+
]],
|
|
622
|
+
messages: {
|
|
623
|
+
required: "Please enter a valid date",
|
|
624
|
+
invalidMonth: "There are only 12 months in a year",
|
|
625
|
+
invalidDay: (n$2, e) => `There are only ${n$2} days in ${e}`,
|
|
626
|
+
afterMin: (n$2) => `Date must be on or after ${n$2.toISOString().slice(0, 10)}`,
|
|
627
|
+
beforeMax: (n$2) => `Date must be on or before ${n$2.toISOString().slice(0, 10)}`
|
|
628
|
+
}
|
|
629
|
+
}
|
|
630
|
+
};
|
|
631
|
+
function isActionKey(n$2, e) {
|
|
632
|
+
if (typeof n$2 == "string") return settings.aliases.get(n$2) === e;
|
|
633
|
+
for (const s of n$2) if (s !== void 0 && isActionKey(s, e)) return true;
|
|
634
|
+
return false;
|
|
635
|
+
}
|
|
636
|
+
function diffLines(i$1, s) {
|
|
637
|
+
if (i$1 === s) return;
|
|
638
|
+
const e = i$1.split(`
|
|
639
|
+
`), t = s.split(`
|
|
640
|
+
`), r$1 = Math.max(e.length, t.length), f = [];
|
|
641
|
+
for (let n$2 = 0; n$2 < r$1; n$2++) e[n$2] !== t[n$2] && f.push(n$2);
|
|
642
|
+
return {
|
|
643
|
+
lines: f,
|
|
644
|
+
numLinesBefore: e.length,
|
|
645
|
+
numLinesAfter: t.length,
|
|
646
|
+
numLines: r$1
|
|
647
|
+
};
|
|
648
|
+
}
|
|
649
|
+
const R = globalThis.process.platform.startsWith("win");
|
|
650
|
+
const CANCEL_SYMBOL = Symbol("clack:cancel");
|
|
651
|
+
function isCancel(e) {
|
|
652
|
+
return e === CANCEL_SYMBOL;
|
|
653
|
+
}
|
|
654
|
+
function setRawMode(e, r$1) {
|
|
655
|
+
const o = e;
|
|
656
|
+
o.isTTY && o.setRawMode(r$1);
|
|
657
|
+
}
|
|
658
|
+
const getColumns = (e) => "columns" in e && typeof e.columns == "number" ? e.columns : 80, getRows = (e) => "rows" in e && typeof e.rows == "number" ? e.rows : 20;
|
|
659
|
+
function wrapTextWithPrefix(e, r$1, o, t = o, s = o, n$2) {
|
|
660
|
+
return wrapAnsi(r$1, getColumns(e ?? stdout) - o.length, {
|
|
661
|
+
hard: true,
|
|
662
|
+
trim: false
|
|
663
|
+
}).split(`
|
|
664
|
+
`).map((c, i$1, m$1) => {
|
|
665
|
+
const d = n$2 ? n$2(c, i$1) : c;
|
|
666
|
+
return i$1 === 0 ? `${t}${d}` : i$1 === m$1.length - 1 ? `${s}${d}` : `${o}${d}`;
|
|
667
|
+
}).join(`
|
|
668
|
+
`);
|
|
669
|
+
}
|
|
670
|
+
function runValidation(e, n$2) {
|
|
671
|
+
if ("~standard" in e) {
|
|
672
|
+
const a$1 = e["~standard"].validate(n$2);
|
|
673
|
+
if (a$1 instanceof Promise) throw new TypeError("Schema validation must be synchronous. Update `validate()` and remove any asynchronous logic.");
|
|
674
|
+
return a$1.issues?.at(0)?.message;
|
|
675
|
+
}
|
|
676
|
+
return e(n$2);
|
|
677
|
+
}
|
|
678
|
+
var V = class {
|
|
679
|
+
input;
|
|
680
|
+
output;
|
|
681
|
+
_abortSignal;
|
|
682
|
+
rl;
|
|
683
|
+
opts;
|
|
684
|
+
_render;
|
|
685
|
+
_track = false;
|
|
686
|
+
_prevFrame = "";
|
|
687
|
+
_subscribers = /* @__PURE__ */ new Map();
|
|
688
|
+
_cursor = 0;
|
|
689
|
+
state = "initial";
|
|
690
|
+
error = "";
|
|
691
|
+
value;
|
|
692
|
+
userInput = "";
|
|
693
|
+
constructor(t, e = true) {
|
|
694
|
+
const { input: i$1 = stdin, output: n$2 = stdout, render: s, signal: r$1,...o } = t;
|
|
695
|
+
this.opts = o, this.onKeypress = this.onKeypress.bind(this), this.close = this.close.bind(this), this.render = this.render.bind(this), this._render = s.bind(this), this._track = e, this._abortSignal = r$1, this.input = i$1, this.output = n$2;
|
|
696
|
+
}
|
|
697
|
+
/**
|
|
698
|
+
* Unsubscribe all listeners
|
|
699
|
+
*/
|
|
700
|
+
unsubscribe() {
|
|
701
|
+
this._subscribers.clear();
|
|
702
|
+
}
|
|
703
|
+
/**
|
|
704
|
+
* Set a subscriber with opts
|
|
705
|
+
* @param event - The event name
|
|
706
|
+
*/
|
|
707
|
+
setSubscriber(t, e) {
|
|
708
|
+
const i$1 = this._subscribers.get(t) ?? [];
|
|
709
|
+
i$1.push(e), this._subscribers.set(t, i$1);
|
|
710
|
+
}
|
|
711
|
+
/**
|
|
712
|
+
* Subscribe to an event
|
|
713
|
+
* @param event - The event name
|
|
714
|
+
* @param cb - The callback
|
|
715
|
+
*/
|
|
716
|
+
on(t, e) {
|
|
717
|
+
this.setSubscriber(t, { cb: e });
|
|
718
|
+
}
|
|
719
|
+
/**
|
|
720
|
+
* Subscribe to an event once
|
|
721
|
+
* @param event - The event name
|
|
722
|
+
* @param cb - The callback
|
|
723
|
+
*/
|
|
724
|
+
once(t, e) {
|
|
725
|
+
this.setSubscriber(t, {
|
|
726
|
+
cb: e,
|
|
727
|
+
once: true
|
|
728
|
+
});
|
|
729
|
+
}
|
|
730
|
+
/**
|
|
731
|
+
* Emit an event with data
|
|
732
|
+
* @param event - The event name
|
|
733
|
+
* @param data - The data to pass to the callback
|
|
734
|
+
*/
|
|
735
|
+
emit(t, ...e) {
|
|
736
|
+
const i$1 = this._subscribers.get(t) ?? [], n$2 = [];
|
|
737
|
+
for (const s of i$1) s.cb(...e), s.once && n$2.push(() => i$1.splice(i$1.indexOf(s), 1));
|
|
738
|
+
for (const s of n$2) s();
|
|
739
|
+
}
|
|
740
|
+
prompt() {
|
|
741
|
+
return new Promise((t) => {
|
|
742
|
+
if (this._abortSignal) {
|
|
743
|
+
if (this._abortSignal.aborted) return this.state = "cancel", this.close(), t(CANCEL_SYMBOL);
|
|
744
|
+
this._abortSignal.addEventListener("abort", () => {
|
|
745
|
+
this.state = "cancel", this.close();
|
|
746
|
+
}, { once: true });
|
|
747
|
+
}
|
|
748
|
+
this.rl = l__default.createInterface({
|
|
749
|
+
input: this.input,
|
|
750
|
+
tabSize: 2,
|
|
751
|
+
prompt: "",
|
|
752
|
+
escapeCodeTimeout: 50,
|
|
753
|
+
terminal: true
|
|
754
|
+
}), this.rl.prompt(), this.opts.initialUserInput !== void 0 && this._setUserInput(this.opts.initialUserInput, true), this.input.on("keypress", this.onKeypress), setRawMode(this.input, true), this.output.on("resize", this.render), this.render(), this.once("submit", () => {
|
|
755
|
+
this.output.write(import_src$1.cursor.show), this.output.off("resize", this.render), setRawMode(this.input, false), t(this.value);
|
|
756
|
+
}), this.once("cancel", () => {
|
|
757
|
+
this.output.write(import_src$1.cursor.show), this.output.off("resize", this.render), setRawMode(this.input, false), t(CANCEL_SYMBOL);
|
|
758
|
+
});
|
|
759
|
+
});
|
|
760
|
+
}
|
|
761
|
+
_isActionKey(t, e) {
|
|
762
|
+
return t === " ";
|
|
763
|
+
}
|
|
764
|
+
_shouldSubmit(t, e) {
|
|
765
|
+
return true;
|
|
766
|
+
}
|
|
767
|
+
_setValue(t) {
|
|
768
|
+
this.value = t, this.emit("value", this.value);
|
|
769
|
+
}
|
|
770
|
+
_setUserInput(t, e) {
|
|
771
|
+
this.userInput = t ?? "", this.emit("userInput", this.userInput), e && this._track && this.rl && (this.rl.write(this.userInput), this._cursor = this.rl.cursor);
|
|
772
|
+
}
|
|
773
|
+
_clearUserInput() {
|
|
774
|
+
this.rl?.write(null, {
|
|
775
|
+
ctrl: true,
|
|
776
|
+
name: "u"
|
|
777
|
+
}), this._setUserInput("");
|
|
778
|
+
}
|
|
779
|
+
onKeypress(t, e) {
|
|
780
|
+
if (this._track && e.name !== "return" && (e.name && this._isActionKey(t, e) && this.rl?.write(null, {
|
|
781
|
+
ctrl: true,
|
|
782
|
+
name: "h"
|
|
783
|
+
}), this._cursor = this.rl?.cursor ?? 0, this._setUserInput(this.rl?.line)), this.state === "error" && (this.state = "active"), e?.name && (!this._track && settings.aliases.has(e.name) && this.emit("cursor", settings.aliases.get(e.name)), settings.actions.has(e.name) && this.emit("cursor", e.name)), t && (t.toLowerCase() === "y" || t.toLowerCase() === "n") && this.emit("confirm", t.toLowerCase() === "y"), this.emit("key", t, e), e?.name === "return" && this._shouldSubmit(t, e)) {
|
|
784
|
+
if (this.opts.validate) {
|
|
785
|
+
const i$1 = runValidation(this.opts.validate, this.value);
|
|
786
|
+
i$1 && (this.error = i$1 instanceof Error ? i$1.message : i$1, this.state = "error", this.rl?.write(this.userInput));
|
|
787
|
+
}
|
|
788
|
+
this.state !== "error" && (this.state = "submit");
|
|
789
|
+
}
|
|
790
|
+
isActionKey([
|
|
791
|
+
t,
|
|
792
|
+
e?.name,
|
|
793
|
+
e?.sequence
|
|
794
|
+
], "cancel") && (this.state = "cancel"), (this.state === "submit" || this.state === "cancel") && this.emit("finalize"), this.render(), (this.state === "submit" || this.state === "cancel") && this.close();
|
|
795
|
+
}
|
|
796
|
+
close() {
|
|
797
|
+
this.input.unpipe(), this.input.removeListener("keypress", this.onKeypress), this.output.write(`
|
|
798
|
+
`), setRawMode(this.input, false), this.rl?.close(), this.rl = void 0, this.emit(`${this.state}`, this.value), this.unsubscribe();
|
|
799
|
+
}
|
|
800
|
+
restoreCursor() {
|
|
801
|
+
const t = wrapAnsi(this._prevFrame, process.stdout.columns, {
|
|
802
|
+
hard: true,
|
|
803
|
+
trim: false
|
|
804
|
+
}).split(`
|
|
805
|
+
`).length - 1;
|
|
806
|
+
this.output.write(import_src$1.cursor.move(-999, t * -1));
|
|
807
|
+
}
|
|
808
|
+
render() {
|
|
809
|
+
const t = wrapAnsi(this._render(this) ?? "", process.stdout.columns, {
|
|
810
|
+
hard: true,
|
|
811
|
+
trim: false
|
|
812
|
+
});
|
|
813
|
+
if (t !== this._prevFrame) {
|
|
814
|
+
if (this.state === "initial") this.output.write(import_src$1.cursor.hide);
|
|
815
|
+
else {
|
|
816
|
+
const e = diffLines(this._prevFrame, t), i$1 = getRows(this.output);
|
|
817
|
+
if (this.restoreCursor(), e) {
|
|
818
|
+
const n$2 = Math.max(0, e.numLinesAfter - i$1), s = Math.max(0, e.numLinesBefore - i$1);
|
|
819
|
+
let r$1 = e.lines.find((o) => o >= n$2);
|
|
820
|
+
if (r$1 === void 0) {
|
|
821
|
+
this._prevFrame = t;
|
|
822
|
+
return;
|
|
823
|
+
}
|
|
824
|
+
if (e.lines.length === 1) {
|
|
825
|
+
this.output.write(import_src$1.cursor.move(0, r$1 - s)), this.output.write(import_src$1.erase.lines(1));
|
|
826
|
+
const o = t.split(`
|
|
827
|
+
`);
|
|
828
|
+
this.output.write(o[r$1]), this._prevFrame = t, this.output.write(import_src$1.cursor.move(0, o.length - r$1 - 1));
|
|
829
|
+
return;
|
|
830
|
+
} else if (e.lines.length > 1) {
|
|
831
|
+
if (n$2 < s) r$1 = n$2;
|
|
832
|
+
else {
|
|
833
|
+
const h$1 = r$1 - s;
|
|
834
|
+
h$1 > 0 && this.output.write(import_src$1.cursor.move(0, h$1));
|
|
835
|
+
}
|
|
836
|
+
this.output.write(import_src$1.erase.down());
|
|
837
|
+
const f = t.split(`
|
|
838
|
+
`).slice(r$1);
|
|
839
|
+
this.output.write(f.join(`
|
|
840
|
+
`)), this._prevFrame = t;
|
|
841
|
+
return;
|
|
842
|
+
}
|
|
843
|
+
}
|
|
844
|
+
this.output.write(import_src$1.erase.down());
|
|
845
|
+
}
|
|
846
|
+
this.output.write(t), this.state === "initial" && (this.state = "active"), this._prevFrame = t;
|
|
847
|
+
}
|
|
848
|
+
}
|
|
849
|
+
};
|
|
850
|
+
var a = class extends V {
|
|
851
|
+
options;
|
|
852
|
+
cursor = 0;
|
|
853
|
+
get _value() {
|
|
854
|
+
return this.options[this.cursor]?.value;
|
|
855
|
+
}
|
|
856
|
+
get _enabledOptions() {
|
|
857
|
+
return this.options.filter((e) => e.disabled !== true);
|
|
858
|
+
}
|
|
859
|
+
toggleAll() {
|
|
860
|
+
const e = this._enabledOptions;
|
|
861
|
+
this.value = this.value !== void 0 && this.value.length === e.length ? [] : e.map((t) => t.value);
|
|
862
|
+
}
|
|
863
|
+
toggleInvert() {
|
|
864
|
+
const e = this.value;
|
|
865
|
+
if (!e) return;
|
|
866
|
+
this.value = this._enabledOptions.filter((t) => !e.includes(t.value)).map((t) => t.value);
|
|
867
|
+
}
|
|
868
|
+
toggleValue() {
|
|
869
|
+
this.value === void 0 && (this.value = []);
|
|
870
|
+
this.value = this.value.includes(this._value) ? this.value.filter((i$1) => i$1 !== this._value) : [...this.value, this._value];
|
|
871
|
+
}
|
|
872
|
+
constructor(e) {
|
|
873
|
+
super(e, false), this.options = e.options, this.value = [...e.initialValues ?? []];
|
|
874
|
+
const i$1 = Math.max(this.options.findIndex(({ value: t }) => t === e.cursorAt), 0);
|
|
875
|
+
this.cursor = this.options[i$1]?.disabled ? findCursor(i$1, 1, this.options) : i$1, this.on("key", (t, l) => {
|
|
876
|
+
l.name === "a" && this.toggleAll(), l.name === "i" && this.toggleInvert();
|
|
877
|
+
}), this.on("cursor", (t) => {
|
|
878
|
+
switch (t) {
|
|
879
|
+
case "left":
|
|
880
|
+
case "up":
|
|
881
|
+
this.cursor = findCursor(this.cursor, -1, this.options);
|
|
882
|
+
break;
|
|
883
|
+
case "down":
|
|
884
|
+
case "right":
|
|
885
|
+
this.cursor = findCursor(this.cursor, 1, this.options);
|
|
886
|
+
break;
|
|
887
|
+
case "space":
|
|
888
|
+
this.toggleValue();
|
|
889
|
+
break;
|
|
890
|
+
}
|
|
891
|
+
});
|
|
892
|
+
}
|
|
893
|
+
};
|
|
894
|
+
|
|
895
|
+
//#endregion
|
|
896
|
+
//#region node_modules/@clack/prompts/dist/index.mjs
|
|
897
|
+
var import_src = /* @__PURE__ */ __toESM(require_src(), 1);
|
|
898
|
+
function isUnicodeSupported() {
|
|
899
|
+
if (process$1.platform !== "win32") return process$1.env.TERM !== "linux";
|
|
900
|
+
return Boolean(process$1.env.CI) || Boolean(process$1.env.WT_SESSION) || Boolean(process$1.env.TERMINUS_SUBLIME) || process$1.env.ConEmuTask === "{cmd::Cmder}" || process$1.env.TERM_PROGRAM === "Terminus-Sublime" || process$1.env.TERM_PROGRAM === "vscode" || process$1.env.TERM === "xterm-256color" || process$1.env.TERM === "alacritty" || process$1.env.TERMINAL_EMULATOR === "JetBrains-JediTerm";
|
|
901
|
+
}
|
|
902
|
+
const unicode = isUnicodeSupported(), isCI = () => process.env.CI === "true", isTTY = (o) => o.isTTY === true, unicodeOr = (o, e) => unicode ? o : e, S_STEP_ACTIVE = unicodeOr("◆", "*"), S_STEP_CANCEL = unicodeOr("■", "x"), S_STEP_ERROR = unicodeOr("▲", "x"), S_STEP_SUBMIT = unicodeOr("◇", "o"), S_BAR_START = unicodeOr("┌", "T"), S_BAR = unicodeOr("│", "|"), S_BAR_END = unicodeOr("└", "—"), S_BAR_START_RIGHT = unicodeOr("┐", "T"), S_BAR_END_RIGHT = unicodeOr("┘", "—"), S_RADIO_ACTIVE = unicodeOr("●", ">"), S_RADIO_INACTIVE = unicodeOr("○", " "), S_CHECKBOX_ACTIVE = unicodeOr("◻", "[•]"), S_CHECKBOX_SELECTED = unicodeOr("◼", "[+]"), S_CHECKBOX_INACTIVE = unicodeOr("◻", "[ ]"), S_PASSWORD_MASK = unicodeOr("▪", "•"), S_BAR_H = unicodeOr("─", "-"), S_CORNER_TOP_RIGHT = unicodeOr("╮", "+"), S_CONNECT_LEFT = unicodeOr("├", "+"), S_CORNER_BOTTOM_RIGHT = unicodeOr("╯", "+"), S_CORNER_BOTTOM_LEFT = unicodeOr("╰", "+"), S_CORNER_TOP_LEFT = unicodeOr("╭", "+"), S_INFO = unicodeOr("●", "•"), S_SUCCESS = unicodeOr("◆", "*"), S_WARN = unicodeOr("▲", "!"), S_ERROR = unicodeOr("■", "x"), symbol = (o) => {
|
|
903
|
+
switch (o) {
|
|
904
|
+
case "initial":
|
|
905
|
+
case "active": return styleText("cyan", S_STEP_ACTIVE);
|
|
906
|
+
case "cancel": return styleText("red", S_STEP_CANCEL);
|
|
907
|
+
case "error": return styleText("yellow", S_STEP_ERROR);
|
|
908
|
+
case "submit": return styleText("green", S_STEP_SUBMIT);
|
|
909
|
+
}
|
|
910
|
+
}, symbolBar = (o) => {
|
|
911
|
+
switch (o) {
|
|
912
|
+
case "initial":
|
|
913
|
+
case "active": return styleText("cyan", S_BAR);
|
|
914
|
+
case "cancel": return styleText("red", S_BAR);
|
|
915
|
+
case "error": return styleText("yellow", S_BAR);
|
|
916
|
+
case "submit": return styleText("green", S_BAR);
|
|
917
|
+
}
|
|
918
|
+
};
|
|
919
|
+
function formatInstructionFooter(o, e) {
|
|
920
|
+
const r$1 = [`${e ? `${styleText("cyan", S_BAR)} ` : ""}${o.join(" • ")}`];
|
|
921
|
+
return e && r$1.push(styleText("cyan", S_BAR_END)), r$1;
|
|
922
|
+
}
|
|
923
|
+
const I = (l, e, w, p$1, b, C = false) => {
|
|
924
|
+
let r$1 = e, O = 0;
|
|
925
|
+
if (C) for (let i$1 = p$1 - 1; i$1 >= w; i$1--) {
|
|
926
|
+
const m$1 = l[i$1];
|
|
927
|
+
if (m$1 && (r$1 -= m$1.length), O++, r$1 <= b) break;
|
|
928
|
+
}
|
|
929
|
+
else for (let i$1 = w; i$1 < p$1; i$1++) {
|
|
930
|
+
const m$1 = l[i$1];
|
|
931
|
+
if (m$1 && (r$1 -= m$1.length), O++, r$1 <= b) break;
|
|
932
|
+
}
|
|
933
|
+
return {
|
|
934
|
+
lineCount: r$1,
|
|
935
|
+
removals: O
|
|
936
|
+
};
|
|
937
|
+
};
|
|
938
|
+
const limitOptions = ({ cursor: l, options: e, style: w, output: p$1 = process.stdout, maxItems: b = Number.POSITIVE_INFINITY, columnPadding: C = 0, rowPadding: r$1 = 4 }) => {
|
|
939
|
+
const i$1 = getColumns(p$1) - C, m$1 = getRows(p$1), M = styleText("dim", "..."), v = Math.max(m$1 - r$1, 0), a$1 = Math.max(Math.min(b, v), 5);
|
|
940
|
+
let f = 0;
|
|
941
|
+
l >= a$1 - 3 && (f = Math.max(Math.min(l - a$1 + 3, e.length - a$1), 0));
|
|
942
|
+
let d = a$1 < e.length && f > 0, c = a$1 < e.length && f + a$1 < e.length;
|
|
943
|
+
const W = Math.min(f + a$1, e.length), s = [];
|
|
944
|
+
let g = 0;
|
|
945
|
+
d && g++, c && g++;
|
|
946
|
+
const T = f + (d ? 1 : 0), y = W - (c ? 1 : 0);
|
|
947
|
+
for (let t = T; t < y; t++) {
|
|
948
|
+
const n$2 = e[t], h$1 = wrapAnsi(n$2 ? w(n$2, t === l) : "", i$1, {
|
|
949
|
+
hard: true,
|
|
950
|
+
trim: false
|
|
951
|
+
}).split(`
|
|
952
|
+
`);
|
|
953
|
+
s.push(h$1), g += h$1.length;
|
|
954
|
+
}
|
|
955
|
+
if (g > v) {
|
|
956
|
+
let t = 0, n$2 = 0, o = g;
|
|
957
|
+
const h$1 = l - T;
|
|
958
|
+
let u$4 = v;
|
|
959
|
+
const L = () => I(s, o, 0, h$1, u$4), E = () => I(s, o, h$1 + 1, s.length, u$4, true);
|
|
960
|
+
d ? ({lineCount: o, removals: t} = L(), o > u$4 && (c || (u$4 -= 1), {lineCount: o, removals: n$2} = E())) : (c || (u$4 -= 1), {lineCount: o, removals: n$2} = E(), o > u$4 && (u$4 -= 1, {lineCount: o, removals: t} = L())), t > 0 && (d = true, s.splice(0, t)), n$2 > 0 && (c = true, s.splice(s.length - n$2, n$2));
|
|
961
|
+
}
|
|
962
|
+
const x = [];
|
|
963
|
+
d && x.push(M);
|
|
964
|
+
for (const t of s) for (const n$2 of t) x.push(n$2);
|
|
965
|
+
return c && x.push(M), x;
|
|
966
|
+
};
|
|
967
|
+
const MULTISELECT_INSTRUCTIONS = [
|
|
968
|
+
`${styleText("dim", "↑/↓")} to navigate`,
|
|
969
|
+
`${styleText("dim", "Space:")} select`,
|
|
970
|
+
`${styleText("dim", "Enter:")} confirm`
|
|
971
|
+
];
|
|
972
|
+
const m = (i$1, u$4) => i$1.split(`
|
|
973
|
+
`).map((d) => u$4(d)).join(`
|
|
974
|
+
`);
|
|
975
|
+
const multiselect = (i$1) => {
|
|
976
|
+
const u$4 = (t, a$1) => {
|
|
977
|
+
const r$1 = t.label ?? String(t.value);
|
|
978
|
+
return a$1 === "disabled" ? `${styleText("gray", S_CHECKBOX_INACTIVE)} ${m(r$1, (o) => styleText(["strikethrough", "gray"], o))}${t.hint ? ` ${styleText("dim", `(${t.hint ?? "disabled"})`)}` : ""}` : a$1 === "active" ? `${styleText("cyan", S_CHECKBOX_ACTIVE)} ${r$1}${t.hint ? ` ${styleText("dim", `(${t.hint})`)}` : ""}` : a$1 === "selected" ? `${styleText("green", S_CHECKBOX_SELECTED)} ${m(r$1, (o) => styleText("dim", o))}${t.hint ? ` ${styleText("dim", `(${t.hint})`)}` : ""}` : a$1 === "cancelled" ? `${m(r$1, (o) => styleText(["strikethrough", "dim"], o))}` : a$1 === "active-selected" ? `${styleText("green", S_CHECKBOX_SELECTED)} ${r$1}${t.hint ? ` ${styleText("dim", `(${t.hint})`)}` : ""}` : a$1 === "submitted" ? `${m(r$1, (o) => styleText("dim", o))}` : `${styleText("dim", S_CHECKBOX_INACTIVE)} ${m(r$1, (o) => styleText("dim", o))}`;
|
|
979
|
+
}, d = i$1.required ?? true, v = i$1.showInstructions ?? true;
|
|
980
|
+
return new a({
|
|
981
|
+
options: i$1.options,
|
|
982
|
+
signal: i$1.signal,
|
|
983
|
+
input: i$1.input,
|
|
984
|
+
output: i$1.output,
|
|
985
|
+
initialValues: i$1.initialValues,
|
|
986
|
+
required: d,
|
|
987
|
+
cursorAt: i$1.cursorAt,
|
|
988
|
+
validate(t) {
|
|
989
|
+
if (d && (t === void 0 || t.length === 0)) return `Please select at least one option.
|
|
990
|
+
${styleText("reset", styleText("dim", `Press ${styleText([
|
|
991
|
+
"gray",
|
|
992
|
+
"bgWhite",
|
|
993
|
+
"inverse"
|
|
994
|
+
], " space ")} to select, ${styleText("gray", styleText("bgWhite", styleText("inverse", " enter ")))} to submit`))}`;
|
|
995
|
+
},
|
|
996
|
+
render() {
|
|
997
|
+
const t = i$1.withGuide ?? settings.withGuide, a$1 = wrapTextWithPrefix(i$1.output, i$1.message, t ? `${symbolBar(this.state)} ` : "", `${symbol(this.state)} `), r$1 = `${t ? `${styleText("gray", S_BAR)}
|
|
998
|
+
` : ""}${a$1}
|
|
999
|
+
`, o = this.value ?? [], p$1 = (n$2, l) => {
|
|
1000
|
+
if (n$2.disabled) return u$4(n$2, "disabled");
|
|
1001
|
+
const s = o.includes(n$2.value);
|
|
1002
|
+
return l && s ? u$4(n$2, "active-selected") : s ? u$4(n$2, "selected") : u$4(n$2, l ? "active" : "inactive");
|
|
1003
|
+
};
|
|
1004
|
+
switch (this.state) {
|
|
1005
|
+
case "submit": {
|
|
1006
|
+
const n$2 = this.options.filter(({ value: s }) => o.includes(s)).map((s) => u$4(s, "submitted")).join(styleText("dim", ", ")) || styleText("dim", "none");
|
|
1007
|
+
return `${r$1}${wrapTextWithPrefix(i$1.output, n$2, t ? `${styleText("gray", S_BAR)} ` : "")}`;
|
|
1008
|
+
}
|
|
1009
|
+
case "cancel": {
|
|
1010
|
+
const n$2 = this.options.filter(({ value: s }) => o.includes(s)).map((s) => u$4(s, "cancelled")).join(styleText("dim", ", "));
|
|
1011
|
+
if (n$2.trim() === "") return `${r$1}${styleText("gray", S_BAR)}`;
|
|
1012
|
+
return `${r$1}${wrapTextWithPrefix(i$1.output, n$2, t ? `${styleText("gray", S_BAR)} ` : "")}${t ? `
|
|
1013
|
+
${styleText("gray", S_BAR)}` : ""}`;
|
|
1014
|
+
}
|
|
1015
|
+
case "error": {
|
|
1016
|
+
const n$2 = t ? `${styleText("yellow", S_BAR)} ` : "", l = this.error.split(`
|
|
1017
|
+
`).map(($, C) => C === 0 ? `${t ? `${styleText("yellow", S_BAR_END)} ` : ""}${styleText("yellow", $)}` : ` ${$}`).join(`
|
|
1018
|
+
`), s = r$1.split(`
|
|
1019
|
+
`).length, h$1 = l.split(`
|
|
1020
|
+
`).length + 1;
|
|
1021
|
+
return `${r$1}${n$2}${limitOptions({
|
|
1022
|
+
output: i$1.output,
|
|
1023
|
+
options: this.options,
|
|
1024
|
+
cursor: this.cursor,
|
|
1025
|
+
maxItems: i$1.maxItems,
|
|
1026
|
+
columnPadding: n$2.length,
|
|
1027
|
+
rowPadding: s + h$1,
|
|
1028
|
+
style: p$1
|
|
1029
|
+
}).join(`
|
|
1030
|
+
${n$2}`)}
|
|
1031
|
+
${l}
|
|
1032
|
+
`;
|
|
1033
|
+
}
|
|
1034
|
+
default: {
|
|
1035
|
+
const n$2 = t ? `${styleText("cyan", S_BAR)} ` : "", l = r$1.split(`
|
|
1036
|
+
`).length, s = v ? formatInstructionFooter(MULTISELECT_INSTRUCTIONS, t) : t ? [styleText("cyan", S_BAR_END)] : [], h$1 = s.join(`
|
|
1037
|
+
`), $ = s.length + 1;
|
|
1038
|
+
return `${r$1}${n$2}${limitOptions({
|
|
1039
|
+
output: i$1.output,
|
|
1040
|
+
options: this.options,
|
|
1041
|
+
cursor: this.cursor,
|
|
1042
|
+
maxItems: i$1.maxItems,
|
|
1043
|
+
columnPadding: n$2.length,
|
|
1044
|
+
rowPadding: l + $,
|
|
1045
|
+
style: p$1
|
|
1046
|
+
}).join(`
|
|
1047
|
+
${n$2}`)}
|
|
1048
|
+
${h$1}
|
|
1049
|
+
`;
|
|
1050
|
+
}
|
|
1051
|
+
}
|
|
1052
|
+
}
|
|
1053
|
+
}).prompt();
|
|
1054
|
+
};
|
|
1055
|
+
const cancel = (o = "", t) => {
|
|
1056
|
+
const i$1 = t?.output ?? process.stdout, e = t?.withGuide ?? settings.withGuide ? `${styleText("gray", S_BAR_END)} ` : "";
|
|
1057
|
+
i$1.write(`${e}${styleText("red", o)}
|
|
1058
|
+
|
|
1059
|
+
`);
|
|
1060
|
+
}, intro = (o = "", t) => {
|
|
1061
|
+
const i$1 = t?.output ?? process.stdout, e = t?.withGuide ?? settings.withGuide ? `${styleText("gray", S_BAR_START)} ` : "";
|
|
1062
|
+
i$1.write(`${e}${o}
|
|
1063
|
+
`);
|
|
1064
|
+
}, outro = (o = "", t) => {
|
|
1065
|
+
const i$1 = t?.output ?? process.stdout, e = t?.withGuide ?? settings.withGuide ? `${styleText("gray", S_BAR)}
|
|
1066
|
+
${styleText("gray", S_BAR_END)} ` : "";
|
|
1067
|
+
i$1.write(`${e}${o}
|
|
1068
|
+
|
|
1069
|
+
`);
|
|
1070
|
+
};
|
|
1071
|
+
const u$3 = {
|
|
1072
|
+
light: unicodeOr("─", "-"),
|
|
1073
|
+
heavy: unicodeOr("━", "="),
|
|
1074
|
+
block: unicodeOr("█", "#")
|
|
1075
|
+
};
|
|
1076
|
+
const SELECT_INSTRUCTIONS = [`${styleText("dim", "↑/↓")} to navigate`, `${styleText("dim", "Enter:")} confirm`];
|
|
1077
|
+
const i = `${styleText("gray", S_BAR)} `;
|
|
1078
|
+
|
|
1079
|
+
//#endregion
|
|
1080
|
+
//#region src/util/prompt.ts
|
|
1081
|
+
/** Space to toggle, `a` for all, enter to confirm. Cancelling selects nothing. */
|
|
1082
|
+
async function multiSelect(message, choices) {
|
|
1083
|
+
if (!choices.length) return [];
|
|
1084
|
+
const picked = await multiselect({
|
|
1085
|
+
message,
|
|
1086
|
+
options: choices.map((c) => ({
|
|
1087
|
+
value: c.value,
|
|
1088
|
+
label: c.label,
|
|
1089
|
+
hint: c.hint
|
|
1090
|
+
})),
|
|
1091
|
+
initialValues: choices.map((c) => c.value),
|
|
1092
|
+
required: false
|
|
1093
|
+
});
|
|
1094
|
+
if (isCancel(picked)) {
|
|
1095
|
+
cancel("cancelled");
|
|
1096
|
+
return [];
|
|
1097
|
+
}
|
|
1098
|
+
return picked;
|
|
1099
|
+
}
|
|
1100
|
+
function isInteractive() {
|
|
1101
|
+
return Boolean(process.stdin.isTTY && process.stdout.isTTY);
|
|
1102
|
+
}
|
|
1103
|
+
/**
|
|
1104
|
+
* Ask only when the user has not already decided and someone is there to answer. A prompt in
|
|
1105
|
+
* a piped or scripted run would hang forever, so this is the one gate that must not regress.
|
|
1106
|
+
*/
|
|
1107
|
+
function shouldAsk(opts) {
|
|
1108
|
+
return opts.requested === 0 && !opts.all && opts.interactive;
|
|
1109
|
+
}
|
|
1110
|
+
|
|
1111
|
+
//#endregion
|
|
1112
|
+
//#region src/util/fs.ts
|
|
1113
|
+
async function exists(p$1) {
|
|
1114
|
+
try {
|
|
1115
|
+
await lstat(p$1);
|
|
1116
|
+
return true;
|
|
1117
|
+
} catch {
|
|
1118
|
+
return false;
|
|
1119
|
+
}
|
|
1120
|
+
}
|
|
1121
|
+
async function ensureDir(path) {
|
|
1122
|
+
await mkdir(path, { recursive: true });
|
|
1123
|
+
}
|
|
1124
|
+
async function backup(path, archiveDir) {
|
|
1125
|
+
if (!await exists(path)) return null;
|
|
1126
|
+
const dest = join(archiveDir, basename(path));
|
|
1127
|
+
await ensureDir(archiveDir);
|
|
1128
|
+
await copyFile(path, dest);
|
|
1129
|
+
return dest;
|
|
1130
|
+
}
|
|
1131
|
+
function stable(value) {
|
|
1132
|
+
if (value === null || typeof value !== "object") return JSON.stringify(value) ?? "null";
|
|
1133
|
+
if (Array.isArray(value)) return `[${value.map(stable).join(",")}]`;
|
|
1134
|
+
return `{${Object.entries(value).sort(([a$1], [b]) => a$1 < b ? -1 : a$1 > b ? 1 : 0).map(([k, v]) => `${JSON.stringify(k)}:${stable(v)}`).join(",")}}`;
|
|
1135
|
+
}
|
|
1136
|
+
async function writeJson(path, value) {
|
|
1137
|
+
await ensureDir(dirname(path));
|
|
1138
|
+
await writeFile(path, `${JSON.stringify(value, null, 2)}\n`);
|
|
1139
|
+
}
|
|
1140
|
+
|
|
1141
|
+
//#endregion
|
|
1142
|
+
//#region src/commands/setup/agents/extensions.ts
|
|
1143
|
+
/** The delivery an extension uses on one agent, or null when it deliberately reaches none. */
|
|
1144
|
+
function deliveryFor(extension, agent) {
|
|
1145
|
+
const declared = extension.deliver[agent] ?? extension.deliver.all;
|
|
1146
|
+
if (!declared) throw new Error(`extension "${extension.name}" declares no delivery for ${agent}`);
|
|
1147
|
+
return typeof declared === "string" ? null : declared;
|
|
1148
|
+
}
|
|
1149
|
+
function skillDeliveries(config$1, agent) {
|
|
1150
|
+
const out = [];
|
|
1151
|
+
for (const extension of config$1.extensions) {
|
|
1152
|
+
const delivery = deliveryFor(extension, agent);
|
|
1153
|
+
if (delivery?.via === "skills") out.push(delivery);
|
|
1154
|
+
}
|
|
1155
|
+
return out;
|
|
1156
|
+
}
|
|
1157
|
+
function claudePluginDeliveries(config$1) {
|
|
1158
|
+
const out = [];
|
|
1159
|
+
for (const extension of config$1.extensions) {
|
|
1160
|
+
const delivery = deliveryFor(extension, "claude-code");
|
|
1161
|
+
if (delivery?.via === "claude-plugin") out.push(delivery);
|
|
1162
|
+
}
|
|
1163
|
+
return out;
|
|
1164
|
+
}
|
|
1165
|
+
function opencodePluginPackages(config$1) {
|
|
1166
|
+
const out = [];
|
|
1167
|
+
for (const extension of config$1.extensions) {
|
|
1168
|
+
const delivery = deliveryFor(extension, "opencode");
|
|
1169
|
+
if (delivery?.via === "opencode-plugin") out.push(delivery.package);
|
|
1170
|
+
}
|
|
1171
|
+
return out;
|
|
1172
|
+
}
|
|
1173
|
+
/** MCP servers this agent should run, keyed by extension name. */
|
|
1174
|
+
function mcpServersFor(config$1, agent) {
|
|
1175
|
+
const out = {};
|
|
1176
|
+
for (const extension of config$1.extensions) {
|
|
1177
|
+
const delivery = deliveryFor(extension, agent);
|
|
1178
|
+
if (delivery?.via === "mcp") out[extension.name] = delivery.server;
|
|
1179
|
+
}
|
|
1180
|
+
return out;
|
|
1181
|
+
}
|
|
1182
|
+
/**
|
|
1183
|
+
* Every extension must resolve on every configured agent, and every `claude-plugin` delivery
|
|
1184
|
+
* must name a declared marketplace. Runs before any emitter so a gap fails the whole run
|
|
1185
|
+
* rather than silently under-installing one agent.
|
|
1186
|
+
*/
|
|
1187
|
+
function validateExtensions(config$1) {
|
|
1188
|
+
const problems = [];
|
|
1189
|
+
for (const extension of config$1.extensions) {
|
|
1190
|
+
for (const agent of config$1.agents) if (!(extension.deliver[agent] ?? extension.deliver.all)) problems.push(`${extension.name}: no delivery for ${agent} — add one, or "unsupported"/"skip"`);
|
|
1191
|
+
for (const [key, delivery] of Object.entries(extension.deliver)) {
|
|
1192
|
+
if (key !== "all" && !config$1.agents.includes(key)) problems.push(`${extension.name}: delivery for "${key}", which is not in config.agents`);
|
|
1193
|
+
if (typeof delivery === "object" && delivery.via === "claude-plugin") {
|
|
1194
|
+
if (!config$1.marketplaces[delivery.marketplace]) problems.push(`${extension.name}: unknown marketplace "${delivery.marketplace}"`);
|
|
1195
|
+
}
|
|
1196
|
+
}
|
|
1197
|
+
}
|
|
1198
|
+
if (problems.length) throw new Error(`config.extensions is incomplete:\n - ${problems.join("\n - ")}`);
|
|
1199
|
+
}
|
|
1200
|
+
/** One line per extension showing how it reaches each agent — "does X cover opencode?". */
|
|
1201
|
+
function logCoverage(config$1) {
|
|
1202
|
+
log.section("Extensions");
|
|
1203
|
+
const rows = config$1.extensions.map((extension) => ({
|
|
1204
|
+
name: extension.name,
|
|
1205
|
+
cells: config$1.agents.map((agent) => {
|
|
1206
|
+
const declared = extension.deliver[agent] ?? extension.deliver.all;
|
|
1207
|
+
return `${agent} → ${typeof declared === "string" ? declared : declared.via}`;
|
|
1208
|
+
})
|
|
1209
|
+
}));
|
|
1210
|
+
const nameWidth = Math.max(...rows.map((r$1) => r$1.name.length));
|
|
1211
|
+
const cellWidths = config$1.agents.map((_, i$1) => Math.max(...rows.map((r$1) => r$1.cells[i$1].length)));
|
|
1212
|
+
for (const { name: name$1, cells } of rows) {
|
|
1213
|
+
const line = cells.map((c, i$1) => c.padEnd(cellWidths[i$1])).join(" ");
|
|
1214
|
+
log.info(`${name$1.padEnd(nameWidth)} ${line.trimEnd()}`);
|
|
1215
|
+
}
|
|
1216
|
+
}
|
|
1217
|
+
|
|
1218
|
+
//#endregion
|
|
1219
|
+
//#region src/commands/setup/agents/installs.ts
|
|
1220
|
+
const SKILL_LOCK = ".agents/.skill-lock.json";
|
|
1221
|
+
const MARKETPLACE_REGISTRY = ".claude/plugins/known_marketplaces.json";
|
|
1222
|
+
/**
|
|
1223
|
+
* `claude plugin` installs, preceded by the marketplaces they come from. Each marketplace
|
|
1224
|
+
* appears once however many plugins reference it; built-in ones ship with Claude Code.
|
|
1225
|
+
*/
|
|
1226
|
+
function claudePluginInstalls(config$1, home) {
|
|
1227
|
+
const out = [];
|
|
1228
|
+
const added = /* @__PURE__ */ new Set();
|
|
1229
|
+
for (const { marketplace, plugin } of claudePluginDeliveries(config$1)) {
|
|
1230
|
+
const market = config$1.marketplaces[marketplace];
|
|
1231
|
+
if (!market.builtin && !added.has(marketplace)) {
|
|
1232
|
+
added.add(marketplace);
|
|
1233
|
+
out.push({
|
|
1234
|
+
kind: "install",
|
|
1235
|
+
label: `marketplace ${marketplace}`,
|
|
1236
|
+
requires: "claude",
|
|
1237
|
+
command: [
|
|
1238
|
+
"claude",
|
|
1239
|
+
"plugin",
|
|
1240
|
+
"marketplace",
|
|
1241
|
+
"add",
|
|
1242
|
+
market.repo
|
|
1243
|
+
],
|
|
1244
|
+
probe: {
|
|
1245
|
+
kind: "claude-marketplace",
|
|
1246
|
+
name: marketplace,
|
|
1247
|
+
registryFile: join(home, MARKETPLACE_REGISTRY)
|
|
1248
|
+
}
|
|
1249
|
+
});
|
|
1250
|
+
}
|
|
1251
|
+
const id = `${plugin}@${marketplace}`;
|
|
1252
|
+
out.push({
|
|
1253
|
+
kind: "install",
|
|
1254
|
+
label: id,
|
|
1255
|
+
requires: "claude",
|
|
1256
|
+
command: [
|
|
1257
|
+
"claude",
|
|
1258
|
+
"plugin",
|
|
1259
|
+
"install",
|
|
1260
|
+
id
|
|
1261
|
+
],
|
|
1262
|
+
probe: {
|
|
1263
|
+
kind: "claude-plugin",
|
|
1264
|
+
id
|
|
1265
|
+
}
|
|
1266
|
+
});
|
|
1267
|
+
}
|
|
1268
|
+
return out;
|
|
1269
|
+
}
|
|
1270
|
+
/**
|
|
1271
|
+
* skills.sh installs into the shared `~/.agents` store. `linkDir` is where the agent expects
|
|
1272
|
+
* to find each skill afterwards — omit it for agents that read the store directly.
|
|
1273
|
+
*/
|
|
1274
|
+
function skillInstalls(config$1, agent, home, linkDir) {
|
|
1275
|
+
return skillDeliveries(config$1, agent).map((delivery) => {
|
|
1276
|
+
const command$1 = [
|
|
1277
|
+
"npx",
|
|
1278
|
+
"-y",
|
|
1279
|
+
"skills",
|
|
1280
|
+
"add",
|
|
1281
|
+
delivery.repo,
|
|
1282
|
+
"-g",
|
|
1283
|
+
"-y",
|
|
1284
|
+
"-a",
|
|
1285
|
+
agent
|
|
1286
|
+
];
|
|
1287
|
+
if (delivery.skills?.length) command$1.push("-s", ...delivery.skills);
|
|
1288
|
+
return {
|
|
1289
|
+
kind: "install",
|
|
1290
|
+
label: `${delivery.repo} (${delivery.skills?.length ?? "all"})`,
|
|
1291
|
+
requires: "npx",
|
|
1292
|
+
command: command$1,
|
|
1293
|
+
probe: {
|
|
1294
|
+
kind: "skills",
|
|
1295
|
+
lockFile: join(home, SKILL_LOCK),
|
|
1296
|
+
names: delivery.skills ?? [],
|
|
1297
|
+
...linkDir && { linkDir }
|
|
1298
|
+
}
|
|
1299
|
+
};
|
|
1300
|
+
});
|
|
1301
|
+
}
|
|
1302
|
+
|
|
1303
|
+
//#endregion
|
|
1304
|
+
//#region src/commands/setup/agents/store.ts
|
|
1305
|
+
const AGENTS_STORE = ".agents/skills";
|
|
1306
|
+
async function authoredSkillNames(ctx) {
|
|
1307
|
+
return (await readdir(join(ctx.repoRoot, ctx.config.authoredSkillsDir), { withFileTypes: true })).filter((e) => e.isDirectory()).map((e) => e.name);
|
|
1308
|
+
}
|
|
1309
|
+
async function buildStorePlan(ctx) {
|
|
1310
|
+
const src = join(ctx.repoRoot, ctx.config.authoredSkillsDir);
|
|
1311
|
+
const stamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
|
|
1312
|
+
const archiveDir = join(ctx.home, ".agents/.setup-backups", stamp);
|
|
1313
|
+
return {
|
|
1314
|
+
archiveDir,
|
|
1315
|
+
groups: [{
|
|
1316
|
+
section: "Skills store (~/.agents/skills)",
|
|
1317
|
+
artifacts: (await authoredSkillNames(ctx)).map((name$1) => ({
|
|
1318
|
+
kind: "symlink",
|
|
1319
|
+
target: join(src, name$1),
|
|
1320
|
+
linkPath: join(ctx.home, AGENTS_STORE, name$1),
|
|
1321
|
+
archiveDisplaced: join(archiveDir, "skills")
|
|
1322
|
+
}))
|
|
1323
|
+
}]
|
|
1324
|
+
};
|
|
1325
|
+
}
|
|
1326
|
+
|
|
1327
|
+
//#endregion
|
|
1328
|
+
//#region src/commands/setup/agents/emitters/claude-code.ts
|
|
1329
|
+
const CONFIG_DIR$1 = ".claude";
|
|
1330
|
+
const ARCHIVE_DIR = ".setup-backups";
|
|
1331
|
+
const claudeCode = {
|
|
1332
|
+
id: "claude-code",
|
|
1333
|
+
configDir: CONFIG_DIR$1,
|
|
1334
|
+
buildPlan: buildPlan$1
|
|
1335
|
+
};
|
|
1336
|
+
async function buildPlan$1(ctx) {
|
|
1337
|
+
const root = join(ctx.home, CONFIG_DIR$1);
|
|
1338
|
+
const archiveDir = join(root, ARCHIVE_DIR, (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-"));
|
|
1339
|
+
const cc = ctx.config.claudeCode;
|
|
1340
|
+
const statuslinePath = join(root, "statusline-command.sh");
|
|
1341
|
+
const plugins = claudePluginDeliveries(ctx.config);
|
|
1342
|
+
const groups = [
|
|
1343
|
+
{
|
|
1344
|
+
section: "Plugins",
|
|
1345
|
+
artifacts: claudePluginInstalls(ctx.config, ctx.home)
|
|
1346
|
+
},
|
|
1347
|
+
{
|
|
1348
|
+
section: "Skills (remote)",
|
|
1349
|
+
artifacts: skillInstalls(ctx.config, "claude-code", ctx.home, join(root, "skills"))
|
|
1350
|
+
},
|
|
1351
|
+
{
|
|
1352
|
+
section: "Skills (authored)",
|
|
1353
|
+
artifacts: await authoredSkillLinks(ctx, root, archiveDir)
|
|
1354
|
+
},
|
|
1355
|
+
{
|
|
1356
|
+
section: "Instructions & statusline",
|
|
1357
|
+
artifacts: [{
|
|
1358
|
+
kind: "file",
|
|
1359
|
+
src: join(ctx.repoRoot, ctx.config.instructionsFile),
|
|
1360
|
+
dest: join(root, "CLAUDE.md")
|
|
1361
|
+
}, {
|
|
1362
|
+
kind: "file",
|
|
1363
|
+
src: join(ctx.repoRoot, cc.statuslineScript),
|
|
1364
|
+
dest: statuslinePath,
|
|
1365
|
+
mode: 493
|
|
1366
|
+
}]
|
|
1367
|
+
},
|
|
1368
|
+
{
|
|
1369
|
+
section: "settings.json",
|
|
1370
|
+
artifacts: [{
|
|
1371
|
+
kind: "jsonMerge",
|
|
1372
|
+
dest: join(root, "settings.json"),
|
|
1373
|
+
managed: settingsFor(cc),
|
|
1374
|
+
derived: {
|
|
1375
|
+
statusLine: {
|
|
1376
|
+
type: "command",
|
|
1377
|
+
command: `bash ${statuslinePath}`
|
|
1378
|
+
},
|
|
1379
|
+
enabledPlugins: enabledPluginsMap(plugins),
|
|
1380
|
+
extraKnownMarketplaces: marketplacesMap(plugins, ctx.config.marketplaces)
|
|
1381
|
+
}
|
|
1382
|
+
}]
|
|
1383
|
+
}
|
|
1384
|
+
];
|
|
1385
|
+
const mcpServers = mcpServersFor(ctx.config, "claude-code");
|
|
1386
|
+
if (Object.keys(mcpServers).length) groups.push({
|
|
1387
|
+
section: "~/.claude.json",
|
|
1388
|
+
artifacts: [{
|
|
1389
|
+
kind: "jsonMerge",
|
|
1390
|
+
dest: join(ctx.home, ".claude.json"),
|
|
1391
|
+
managed: {},
|
|
1392
|
+
derived: { mcpServers: mapValues(mcpServers, claudeMcp) }
|
|
1393
|
+
}]
|
|
1394
|
+
});
|
|
1395
|
+
if (cc.commandsDir) groups.push({
|
|
1396
|
+
section: "Commands",
|
|
1397
|
+
artifacts: await commandFiles(ctx.repoRoot, cc.commandsDir, root)
|
|
1398
|
+
});
|
|
1399
|
+
return {
|
|
1400
|
+
archiveDir,
|
|
1401
|
+
groups
|
|
1402
|
+
};
|
|
1403
|
+
}
|
|
1404
|
+
function enabledPluginsMap(deliveries) {
|
|
1405
|
+
return Object.fromEntries(deliveries.map((d) => [`${d.plugin}@${d.marketplace}`, true]));
|
|
1406
|
+
}
|
|
1407
|
+
function marketplacesMap(deliveries, marketplaces) {
|
|
1408
|
+
const referenced = [...new Set(deliveries.map((d) => d.marketplace))];
|
|
1409
|
+
return Object.fromEntries(referenced.filter((name$1) => !marketplaces[name$1].builtin).map((name$1) => [name$1, { source: {
|
|
1410
|
+
source: "github",
|
|
1411
|
+
repo: marketplaces[name$1].repo
|
|
1412
|
+
} }]));
|
|
1413
|
+
}
|
|
1414
|
+
function claudeMcp(server) {
|
|
1415
|
+
return server.transport === "stdio" ? {
|
|
1416
|
+
type: "stdio",
|
|
1417
|
+
command: server.command[0],
|
|
1418
|
+
args: server.command.slice(1),
|
|
1419
|
+
...server.env && { env: server.env }
|
|
1420
|
+
} : {
|
|
1421
|
+
type: "http",
|
|
1422
|
+
url: server.url,
|
|
1423
|
+
...server.headers && { headers: server.headers }
|
|
1424
|
+
};
|
|
1425
|
+
}
|
|
1426
|
+
function mapValues(record, fn) {
|
|
1427
|
+
return Object.fromEntries(Object.entries(record).map(([k, v]) => [k, fn(v)]));
|
|
1428
|
+
}
|
|
1429
|
+
async function authoredSkillLinks(ctx, root, archiveDir) {
|
|
1430
|
+
return (await authoredSkillNames(ctx)).map((name$1) => ({
|
|
1431
|
+
kind: "symlink",
|
|
1432
|
+
target: `../../${AGENTS_STORE}/${name$1}`,
|
|
1433
|
+
linkPath: join(root, "skills", name$1),
|
|
1434
|
+
archiveDisplaced: join(archiveDir, "agent-skills")
|
|
1435
|
+
}));
|
|
1436
|
+
}
|
|
1437
|
+
async function commandFiles(repoRoot, dir, root) {
|
|
1438
|
+
const src = resolve(repoRoot, dir);
|
|
1439
|
+
return (await readdir(src)).filter((f) => f.endsWith(".md")).sort().map((f) => ({
|
|
1440
|
+
kind: "file",
|
|
1441
|
+
src: join(src, f),
|
|
1442
|
+
dest: join(root, "commands", f)
|
|
1443
|
+
}));
|
|
1444
|
+
}
|
|
1445
|
+
function settingsFor(cc) {
|
|
1446
|
+
const out = {};
|
|
1447
|
+
if (cc.effort !== void 0) out.effortLevel = cc.effort;
|
|
1448
|
+
if (cc.autoCompactWindow !== void 0) out.autoCompactWindow = cc.autoCompactWindow;
|
|
1449
|
+
if (cc.tui !== void 0) out.tui = cc.tui;
|
|
1450
|
+
if (cc.cleanupPeriodDays !== void 0) out.cleanupPeriodDays = cc.cleanupPeriodDays;
|
|
1451
|
+
if (cc.voice !== void 0) out.voiceEnabled = cc.voice;
|
|
1452
|
+
if (cc.autoDream !== void 0) out.autoDreamEnabled = cc.autoDream;
|
|
1453
|
+
if (cc.agentPushNotifications !== void 0) out.agentPushNotifEnabled = cc.agentPushNotifications;
|
|
1454
|
+
if (cc.permissions?.defaultMode !== void 0) out.permissions = { defaultMode: cc.permissions.defaultMode };
|
|
1455
|
+
if (cc.permissions?.skipDangerousModePrompt !== void 0) out.skipDangerousModePermissionPrompt = cc.permissions.skipDangerousModePrompt;
|
|
1456
|
+
if (cc.permissions?.skipAutoPrompt !== void 0) out.skipAutoPermissionPrompt = cc.permissions.skipAutoPrompt;
|
|
1457
|
+
if (cc.hooks !== void 0) out.hooks = cc.hooks;
|
|
1458
|
+
return out;
|
|
1459
|
+
}
|
|
1460
|
+
|
|
1461
|
+
//#endregion
|
|
1462
|
+
//#region src/commands/setup/agents/emitters/opencode.ts
|
|
1463
|
+
const CONFIG_DIR = ".config/opencode";
|
|
1464
|
+
/** opencode accepts either name; write to whichever already exists so we never fork the config. */
|
|
1465
|
+
const CONFIG_FILES = ["opencode.jsonc", "opencode.json"];
|
|
1466
|
+
const opencode = {
|
|
1467
|
+
id: "opencode",
|
|
1468
|
+
configDir: CONFIG_DIR,
|
|
1469
|
+
buildPlan
|
|
1470
|
+
};
|
|
1471
|
+
async function buildPlan(ctx) {
|
|
1472
|
+
const root = join(ctx.home, CONFIG_DIR);
|
|
1473
|
+
const stamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
|
|
1474
|
+
const groups = [{
|
|
1475
|
+
section: "Skills (remote)",
|
|
1476
|
+
artifacts: skillInstalls(ctx.config, "opencode", ctx.home)
|
|
1477
|
+
}, {
|
|
1478
|
+
section: "Instructions",
|
|
1479
|
+
artifacts: [{
|
|
1480
|
+
kind: "file",
|
|
1481
|
+
src: join(ctx.repoRoot, ctx.config.instructionsFile),
|
|
1482
|
+
dest: join(root, "AGENTS.md")
|
|
1483
|
+
}]
|
|
1484
|
+
}];
|
|
1485
|
+
const derived = configKeys(ctx.config);
|
|
1486
|
+
if (Object.keys(derived).length) groups.push({
|
|
1487
|
+
section: "opencode config",
|
|
1488
|
+
artifacts: [{
|
|
1489
|
+
kind: "jsonMerge",
|
|
1490
|
+
dest: await configPath(root),
|
|
1491
|
+
managed: {},
|
|
1492
|
+
derived
|
|
1493
|
+
}]
|
|
1494
|
+
});
|
|
1495
|
+
return {
|
|
1496
|
+
archiveDir: join(root, ".setup-backups", stamp),
|
|
1497
|
+
groups
|
|
1498
|
+
};
|
|
1499
|
+
}
|
|
1500
|
+
async function configPath(root) {
|
|
1501
|
+
for (const name$1 of CONFIG_FILES) if (await exists(join(root, name$1))) return join(root, name$1);
|
|
1502
|
+
return join(root, CONFIG_FILES[1]);
|
|
1503
|
+
}
|
|
1504
|
+
function configKeys(config$1) {
|
|
1505
|
+
const out = {};
|
|
1506
|
+
const plugin = opencodePluginPackages(config$1);
|
|
1507
|
+
if (plugin.length) out.plugin = plugin;
|
|
1508
|
+
const servers = Object.entries(mcpServersFor(config$1, "opencode"));
|
|
1509
|
+
if (servers.length) out.mcp = Object.fromEntries(servers.map(([name$1, server]) => [name$1, opencodeMcp(server)]));
|
|
1510
|
+
return out;
|
|
1511
|
+
}
|
|
1512
|
+
function opencodeMcp(server) {
|
|
1513
|
+
return server.transport === "stdio" ? {
|
|
1514
|
+
type: "local",
|
|
1515
|
+
command: server.command,
|
|
1516
|
+
enabled: true,
|
|
1517
|
+
...server.env && { environment: server.env }
|
|
1518
|
+
} : {
|
|
1519
|
+
type: "remote",
|
|
1520
|
+
url: server.url,
|
|
1521
|
+
enabled: true,
|
|
1522
|
+
...server.headers && { headers: server.headers }
|
|
1523
|
+
};
|
|
1524
|
+
}
|
|
1525
|
+
|
|
1526
|
+
//#endregion
|
|
1527
|
+
//#region src/commands/setup/agents/emitters/index.ts
|
|
1528
|
+
const emitters = {
|
|
1529
|
+
"claude-code": claudeCode,
|
|
1530
|
+
opencode,
|
|
1531
|
+
codex: null
|
|
1532
|
+
};
|
|
1533
|
+
|
|
1534
|
+
//#endregion
|
|
1535
|
+
//#region src/util/exec.ts
|
|
1536
|
+
function run(cmd) {
|
|
1537
|
+
return new Promise((resolve$1) => {
|
|
1538
|
+
const [bin, ...args] = cmd;
|
|
1539
|
+
const proc = spawn(bin, args);
|
|
1540
|
+
let stdout$1 = "";
|
|
1541
|
+
let stderr = "";
|
|
1542
|
+
proc.stdout.on("data", (d) => stdout$1 += d);
|
|
1543
|
+
proc.stderr.on("data", (d) => stderr += d);
|
|
1544
|
+
proc.on("error", () => resolve$1({
|
|
1545
|
+
ok: false,
|
|
1546
|
+
stdout: stdout$1,
|
|
1547
|
+
stderr
|
|
1548
|
+
}));
|
|
1549
|
+
proc.on("close", (code) => resolve$1({
|
|
1550
|
+
ok: code === 0,
|
|
1551
|
+
stdout: stdout$1,
|
|
1552
|
+
stderr
|
|
1553
|
+
}));
|
|
1554
|
+
});
|
|
1555
|
+
}
|
|
1556
|
+
async function which(bin) {
|
|
1557
|
+
return (await run([
|
|
1558
|
+
"sh",
|
|
1559
|
+
"-c",
|
|
1560
|
+
`command -v ${bin}`
|
|
1561
|
+
])).ok;
|
|
1562
|
+
}
|
|
1563
|
+
|
|
1564
|
+
//#endregion
|
|
1565
|
+
//#region src/commands/setup/agents/diff.ts
|
|
1566
|
+
async function diff(plan) {
|
|
1567
|
+
const probes = new Probes();
|
|
1568
|
+
const sections = [];
|
|
1569
|
+
for (const group of plan.groups) {
|
|
1570
|
+
const changes = [];
|
|
1571
|
+
for (const artifact of group.artifacts) changes.push(await changeFor(artifact, plan.archiveDir, probes));
|
|
1572
|
+
sections.push({
|
|
1573
|
+
title: group.section,
|
|
1574
|
+
changes
|
|
1575
|
+
});
|
|
1576
|
+
}
|
|
1577
|
+
return sections;
|
|
1578
|
+
}
|
|
1579
|
+
function changeFor(a$1, archiveDir, probes) {
|
|
1580
|
+
switch (a$1.kind) {
|
|
1581
|
+
case "file": return fileChange(a$1);
|
|
1582
|
+
case "symlink": return symlinkChange(a$1);
|
|
1583
|
+
case "jsonMerge": return jsonMergeChange(a$1, archiveDir);
|
|
1584
|
+
case "install": return installChange(a$1, probes);
|
|
1585
|
+
}
|
|
1586
|
+
}
|
|
1587
|
+
async function fileChange(a$1) {
|
|
1588
|
+
const next = await readFile(a$1.src);
|
|
1589
|
+
if ((await readFile(a$1.dest).catch(() => null))?.equals(next)) return {
|
|
1590
|
+
status: "unchanged",
|
|
1591
|
+
label: a$1.dest
|
|
1592
|
+
};
|
|
1593
|
+
return {
|
|
1594
|
+
status: "pending",
|
|
1595
|
+
label: a$1.dest,
|
|
1596
|
+
action: {
|
|
1597
|
+
do: "write-file",
|
|
1598
|
+
src: a$1.src,
|
|
1599
|
+
dest: a$1.dest,
|
|
1600
|
+
...a$1.mode && { mode: a$1.mode }
|
|
1601
|
+
}
|
|
1602
|
+
};
|
|
1603
|
+
}
|
|
1604
|
+
async function symlinkChange(a$1) {
|
|
1605
|
+
const label = `${a$1.linkPath} → ${a$1.target}`;
|
|
1606
|
+
const link = {
|
|
1607
|
+
do: "link",
|
|
1608
|
+
target: a$1.target,
|
|
1609
|
+
linkPath: a$1.linkPath
|
|
1610
|
+
};
|
|
1611
|
+
if (!await exists(a$1.linkPath)) return {
|
|
1612
|
+
status: "pending",
|
|
1613
|
+
label,
|
|
1614
|
+
action: link
|
|
1615
|
+
};
|
|
1616
|
+
if ((await lstat(a$1.linkPath)).isSymbolicLink()) {
|
|
1617
|
+
if (await readlink(a$1.linkPath) === a$1.target) return {
|
|
1618
|
+
status: "unchanged",
|
|
1619
|
+
label
|
|
1620
|
+
};
|
|
1621
|
+
return {
|
|
1622
|
+
status: "pending",
|
|
1623
|
+
label,
|
|
1624
|
+
action: {
|
|
1625
|
+
...link,
|
|
1626
|
+
removeExisting: true
|
|
1627
|
+
}
|
|
1628
|
+
};
|
|
1629
|
+
}
|
|
1630
|
+
if (!a$1.archiveDisplaced) return {
|
|
1631
|
+
status: "blocked",
|
|
1632
|
+
label,
|
|
1633
|
+
reason: `${a$1.linkPath} exists as a real directory`
|
|
1634
|
+
};
|
|
1635
|
+
const archiveTo = join(a$1.archiveDisplaced, basename(a$1.linkPath));
|
|
1636
|
+
return {
|
|
1637
|
+
status: "pending",
|
|
1638
|
+
label,
|
|
1639
|
+
action: {
|
|
1640
|
+
...link,
|
|
1641
|
+
archiveTo
|
|
1642
|
+
}
|
|
1643
|
+
};
|
|
1644
|
+
}
|
|
1645
|
+
async function jsonMergeChange(a$1, archiveDir) {
|
|
1646
|
+
const label = basename(a$1.dest);
|
|
1647
|
+
const raw = await readFile(a$1.dest, "utf8").catch(() => null);
|
|
1648
|
+
let current = {};
|
|
1649
|
+
if (raw !== null) try {
|
|
1650
|
+
current = JSON.parse(raw);
|
|
1651
|
+
} catch {
|
|
1652
|
+
return {
|
|
1653
|
+
status: "blocked",
|
|
1654
|
+
label,
|
|
1655
|
+
reason: "not parseable JSON (comments?)"
|
|
1656
|
+
};
|
|
1657
|
+
}
|
|
1658
|
+
const value = {
|
|
1659
|
+
...current,
|
|
1660
|
+
...a$1.managed,
|
|
1661
|
+
...a$1.derived
|
|
1662
|
+
};
|
|
1663
|
+
if (stable(current) === stable(value)) return {
|
|
1664
|
+
status: "unchanged",
|
|
1665
|
+
label
|
|
1666
|
+
};
|
|
1667
|
+
const notes = Object.keys(value).filter((k) => stable(current[k]) !== stable(value[k])).map((k) => `set ${k}${k in a$1.derived ? " (derived)" : ""}`);
|
|
1668
|
+
const unmanaged = Object.keys(current).filter((k) => !(k in a$1.managed) && !(k in a$1.derived));
|
|
1669
|
+
if (unmanaged.length) notes.push(`preserved unmanaged keys: ${unmanaged.join(", ")}`);
|
|
1670
|
+
return {
|
|
1671
|
+
status: "pending",
|
|
1672
|
+
label,
|
|
1673
|
+
action: {
|
|
1674
|
+
do: "write-json",
|
|
1675
|
+
dest: a$1.dest,
|
|
1676
|
+
value,
|
|
1677
|
+
backupTo: archiveDir
|
|
1678
|
+
},
|
|
1679
|
+
notes
|
|
1680
|
+
};
|
|
1681
|
+
}
|
|
1682
|
+
async function installChange(a$1, probes) {
|
|
1683
|
+
if (!await probes.onPath(a$1.requires)) return {
|
|
1684
|
+
status: "blocked",
|
|
1685
|
+
label: a$1.label,
|
|
1686
|
+
reason: `\`${a$1.requires}\` not on PATH`
|
|
1687
|
+
};
|
|
1688
|
+
if (await probes.satisfied(a$1.probe)) return {
|
|
1689
|
+
status: "unchanged",
|
|
1690
|
+
label: a$1.label
|
|
1691
|
+
};
|
|
1692
|
+
return {
|
|
1693
|
+
status: "pending",
|
|
1694
|
+
label: a$1.label,
|
|
1695
|
+
action: {
|
|
1696
|
+
do: "run",
|
|
1697
|
+
command: a$1.command
|
|
1698
|
+
}
|
|
1699
|
+
};
|
|
1700
|
+
}
|
|
1701
|
+
/** Memoised machine lookups — `claude plugin list` costs a process spawn, so it runs once. */
|
|
1702
|
+
var Probes = class {
|
|
1703
|
+
onPathCache = /* @__PURE__ */ new Map();
|
|
1704
|
+
jsonCache = /* @__PURE__ */ new Map();
|
|
1705
|
+
plugins;
|
|
1706
|
+
onPath(bin) {
|
|
1707
|
+
let hit = this.onPathCache.get(bin);
|
|
1708
|
+
if (!hit) this.onPathCache.set(bin, hit = which(bin));
|
|
1709
|
+
return hit;
|
|
1710
|
+
}
|
|
1711
|
+
async satisfied(probe) {
|
|
1712
|
+
switch (probe.kind) {
|
|
1713
|
+
case "claude-plugin": return (await this.installedPlugins()).has(probe.id);
|
|
1714
|
+
case "claude-marketplace": {
|
|
1715
|
+
const registry = await this.json(probe.registryFile);
|
|
1716
|
+
return !!registry && probe.name in registry;
|
|
1717
|
+
}
|
|
1718
|
+
case "skills": {
|
|
1719
|
+
if (!probe.names.length) return false;
|
|
1720
|
+
const skills = (await this.json(probe.lockFile))?.skills ?? {};
|
|
1721
|
+
for (const name$1 of probe.names) {
|
|
1722
|
+
if (!(name$1 in skills)) return false;
|
|
1723
|
+
if (probe.linkDir && !await exists(join(probe.linkDir, name$1))) return false;
|
|
1724
|
+
}
|
|
1725
|
+
return true;
|
|
1726
|
+
}
|
|
1727
|
+
}
|
|
1728
|
+
}
|
|
1729
|
+
installedPlugins() {
|
|
1730
|
+
this.plugins ??= run([
|
|
1731
|
+
"claude",
|
|
1732
|
+
"plugin",
|
|
1733
|
+
"list"
|
|
1734
|
+
]).then((res) => new Set(res.stdout.match(/[\w.-]+@[\w.-]+/g) ?? []));
|
|
1735
|
+
return this.plugins;
|
|
1736
|
+
}
|
|
1737
|
+
json(file) {
|
|
1738
|
+
let hit = this.jsonCache.get(file);
|
|
1739
|
+
if (!hit) {
|
|
1740
|
+
hit = readFile(file, "utf8").then((raw) => {
|
|
1741
|
+
try {
|
|
1742
|
+
return JSON.parse(raw);
|
|
1743
|
+
} catch {
|
|
1744
|
+
return null;
|
|
1745
|
+
}
|
|
1746
|
+
}, () => null);
|
|
1747
|
+
this.jsonCache.set(file, hit);
|
|
1748
|
+
}
|
|
1749
|
+
return hit;
|
|
1750
|
+
}
|
|
1751
|
+
};
|
|
1752
|
+
|
|
1753
|
+
//#endregion
|
|
1754
|
+
//#region src/commands/setup/agents/executor.ts
|
|
1755
|
+
/** The one place `dryRun` is consulted: the same diff is either printed or committed. */
|
|
1756
|
+
async function runPlan(plan, dryRun) {
|
|
1757
|
+
await walk(await diff(plan), dryRun ? render : commit);
|
|
1758
|
+
}
|
|
1759
|
+
async function walk(sections, handle) {
|
|
1760
|
+
for (const { title, changes } of sections) {
|
|
1761
|
+
log.section(title);
|
|
1762
|
+
for (const change of changes) await handle(change);
|
|
1763
|
+
}
|
|
1764
|
+
}
|
|
1765
|
+
function render(change) {
|
|
1766
|
+
switch (change.status) {
|
|
1767
|
+
case "unchanged": return log.skip(`${change.label} (unchanged)`);
|
|
1768
|
+
case "blocked": return log.warn(`${change.label} — ${change.reason}, leaving it alone`);
|
|
1769
|
+
case "pending":
|
|
1770
|
+
log.plan(phrase(change.action));
|
|
1771
|
+
for (const note of change.notes ?? []) log.info(note);
|
|
1772
|
+
}
|
|
1773
|
+
}
|
|
1774
|
+
async function commit(change) {
|
|
1775
|
+
switch (change.status) {
|
|
1776
|
+
case "unchanged": return log.skip(`${change.label} (unchanged)`);
|
|
1777
|
+
case "blocked": return log.fail(`${change.label} — ${change.reason}, leaving it alone`);
|
|
1778
|
+
case "pending": {
|
|
1779
|
+
const { ok, notes } = await perform(change.action);
|
|
1780
|
+
if (!ok) return log.fail(`${change.label}: ${notes.join(" ")}`);
|
|
1781
|
+
log.ok(change.label);
|
|
1782
|
+
for (const note of [...notes, ...change.notes ?? []]) log.info(note);
|
|
1783
|
+
}
|
|
1784
|
+
}
|
|
1785
|
+
}
|
|
1786
|
+
async function perform(action) {
|
|
1787
|
+
switch (action.do) {
|
|
1788
|
+
case "write-file": {
|
|
1789
|
+
const bytes = await readFile(action.src);
|
|
1790
|
+
await ensureDir(dirname(action.dest));
|
|
1791
|
+
await writeFile(action.dest, bytes, action.mode ? { mode: action.mode } : void 0);
|
|
1792
|
+
return {
|
|
1793
|
+
ok: true,
|
|
1794
|
+
notes: []
|
|
1795
|
+
};
|
|
1796
|
+
}
|
|
1797
|
+
case "link": {
|
|
1798
|
+
const notes = [];
|
|
1799
|
+
if (action.archiveTo) {
|
|
1800
|
+
await ensureDir(dirname(action.archiveTo));
|
|
1801
|
+
await rename(action.linkPath, action.archiveTo);
|
|
1802
|
+
notes.push(`archived → ${action.archiveTo}`);
|
|
1803
|
+
} else if (action.removeExisting) await rm(action.linkPath, {
|
|
1804
|
+
recursive: true,
|
|
1805
|
+
force: true
|
|
1806
|
+
});
|
|
1807
|
+
await ensureDir(dirname(action.linkPath));
|
|
1808
|
+
await symlink(action.target, action.linkPath);
|
|
1809
|
+
return {
|
|
1810
|
+
ok: true,
|
|
1811
|
+
notes
|
|
1812
|
+
};
|
|
1813
|
+
}
|
|
1814
|
+
case "write-json": {
|
|
1815
|
+
const bak = await backup(action.dest, action.backupTo);
|
|
1816
|
+
await writeJson(action.dest, action.value);
|
|
1817
|
+
return {
|
|
1818
|
+
ok: true,
|
|
1819
|
+
notes: bak ? [`backed up → ${bak}`] : []
|
|
1820
|
+
};
|
|
1821
|
+
}
|
|
1822
|
+
case "run": {
|
|
1823
|
+
const res = await run(action.command);
|
|
1824
|
+
const output = res.stdout + res.stderr;
|
|
1825
|
+
if (res.ok) return {
|
|
1826
|
+
ok: true,
|
|
1827
|
+
notes: []
|
|
1828
|
+
};
|
|
1829
|
+
if (/already/i.test(output)) return {
|
|
1830
|
+
ok: true,
|
|
1831
|
+
notes: ["already present"]
|
|
1832
|
+
};
|
|
1833
|
+
return {
|
|
1834
|
+
ok: false,
|
|
1835
|
+
notes: [output.trim().split("\n").slice(-1)[0] ?? "failed"]
|
|
1836
|
+
};
|
|
1837
|
+
}
|
|
1838
|
+
}
|
|
1839
|
+
}
|
|
1840
|
+
function phrase(action) {
|
|
1841
|
+
switch (action.do) {
|
|
1842
|
+
case "write-file": return `write ${action.dest}`;
|
|
1843
|
+
case "link":
|
|
1844
|
+
if (action.archiveTo) return `archive ${action.linkPath} → ${action.archiveTo}, then link`;
|
|
1845
|
+
return `${action.removeExisting ? "relink" : "link"} ${action.linkPath} → ${action.target}`;
|
|
1846
|
+
case "write-json": return `write ${action.dest}`;
|
|
1847
|
+
case "run": return action.command.join(" ");
|
|
1848
|
+
}
|
|
1849
|
+
}
|
|
1850
|
+
|
|
1851
|
+
//#endregion
|
|
1852
|
+
//#region src/commands/setup/agents/apply.ts
|
|
1853
|
+
/** An agent with no config directory is not on this machine — skip it, never create it. */
|
|
1854
|
+
function isInstalled(home, emitter) {
|
|
1855
|
+
return exists(join(home, emitter.configDir));
|
|
1856
|
+
}
|
|
1857
|
+
async function applyAgents(ctx, ids, dryRun) {
|
|
1858
|
+
validateExtensions(ctx.config);
|
|
1859
|
+
logCoverage(ctx.config);
|
|
1860
|
+
await runPlan(await buildStorePlan(ctx), dryRun);
|
|
1861
|
+
for (const id of ids) {
|
|
1862
|
+
const emitter = emitters[id];
|
|
1863
|
+
if (!emitter) continue;
|
|
1864
|
+
log.agent(id);
|
|
1865
|
+
if (!await isInstalled(ctx.home, emitter)) {
|
|
1866
|
+
log.warn(`${id} not installed on this machine — skipping`);
|
|
1867
|
+
continue;
|
|
1868
|
+
}
|
|
1869
|
+
await runPlan(await emitter.buildPlan(ctx), dryRun);
|
|
1870
|
+
}
|
|
1871
|
+
}
|
|
1872
|
+
|
|
1873
|
+
//#endregion
|
|
1874
|
+
//#region src/commands/setup/agents/index.ts
|
|
1875
|
+
var import_picocolors$2 = /* @__PURE__ */ __toESM(require_picocolors(), 1);
|
|
1876
|
+
const USAGE$1 = `Usage: pakhale setup agents [plan] [options]
|
|
1877
|
+
|
|
1878
|
+
Apply the coding-agent workflow (plugins, skills, settings) to this machine.
|
|
1879
|
+
With a terminal and no --agent, you are asked which agents to apply to; piped or
|
|
1880
|
+
scripted runs apply to every configured agent.
|
|
1881
|
+
|
|
1882
|
+
plan dry run — show every change, write nothing
|
|
1883
|
+
|
|
1884
|
+
Options:
|
|
1885
|
+
-n, --dry-run same as plan
|
|
1886
|
+
-a, --agent <id> target one agent (repeatable) — skips the prompt
|
|
1887
|
+
--all every configured agent — skips the prompt
|
|
1888
|
+
--home <dir> apply against a different home directory
|
|
1889
|
+
-h, --help show this help`;
|
|
1890
|
+
const agents = {
|
|
1891
|
+
name: "agents",
|
|
1892
|
+
describe: "apply the coding-agent workflow (plugins, skills, settings) to this machine",
|
|
1893
|
+
async run(argv$1, packageRoot$1) {
|
|
1894
|
+
const { values, positionals } = parseArgs({
|
|
1895
|
+
args: argv$1,
|
|
1896
|
+
options: {
|
|
1897
|
+
"dry-run": {
|
|
1898
|
+
type: "boolean",
|
|
1899
|
+
short: "n",
|
|
1900
|
+
default: false
|
|
1901
|
+
},
|
|
1902
|
+
agent: {
|
|
1903
|
+
type: "string",
|
|
1904
|
+
short: "a",
|
|
1905
|
+
multiple: true
|
|
1906
|
+
},
|
|
1907
|
+
all: {
|
|
1908
|
+
type: "boolean",
|
|
1909
|
+
default: false
|
|
1910
|
+
},
|
|
1911
|
+
home: { type: "string" },
|
|
1912
|
+
help: {
|
|
1913
|
+
type: "boolean",
|
|
1914
|
+
short: "h",
|
|
1915
|
+
default: false
|
|
1916
|
+
}
|
|
1917
|
+
},
|
|
1918
|
+
allowPositionals: true
|
|
1919
|
+
});
|
|
1920
|
+
if (values.help) {
|
|
1921
|
+
console.log(USAGE$1);
|
|
1922
|
+
return 0;
|
|
1923
|
+
}
|
|
1924
|
+
const dryRun = values["dry-run"] || positionals.includes("plan");
|
|
1925
|
+
const home = values.home ? resolve(values.home) : homedir();
|
|
1926
|
+
const only = values.agent ?? [];
|
|
1927
|
+
const available = (only.length ? only : config.agents).filter((id) => {
|
|
1928
|
+
if (emitters[id]) return true;
|
|
1929
|
+
log.warn(`no emitter for "${id}" yet — skipping`);
|
|
1930
|
+
return false;
|
|
1931
|
+
});
|
|
1932
|
+
const selected = shouldAsk({
|
|
1933
|
+
requested: only.length,
|
|
1934
|
+
all: values.all,
|
|
1935
|
+
interactive: isInteractive()
|
|
1936
|
+
}) ? await chooseAgents(available, home) : available;
|
|
1937
|
+
if (!selected.length) {
|
|
1938
|
+
log.fail("nothing to do");
|
|
1939
|
+
return 1;
|
|
1940
|
+
}
|
|
1941
|
+
const mode = dryRun ? ` ${import_picocolors$2.default.yellow("(dry run)")}` : "";
|
|
1942
|
+
const where = home === homedir() ? "" : ` ${import_picocolors$2.default.magenta(`[home=${home}]`)}`;
|
|
1943
|
+
console.log(`\npakhale setup agents${mode}${where} → ${selected.join(", ")}`);
|
|
1944
|
+
await applyAgents({
|
|
1945
|
+
home,
|
|
1946
|
+
repoRoot: packageRoot$1,
|
|
1947
|
+
config
|
|
1948
|
+
}, selected, dryRun);
|
|
1949
|
+
console.log(dryRun ? `\n${import_picocolors$2.default.yellow("dry run complete — nothing written")}\n` : `\n${import_picocolors$2.default.green("done")}\n`);
|
|
1950
|
+
return 0;
|
|
1951
|
+
}
|
|
1952
|
+
};
|
|
1953
|
+
async function chooseAgents(ids, home) {
|
|
1954
|
+
return await multiSelect("Which agents?", await Promise.all(ids.map(async (id) => ({
|
|
1955
|
+
value: id,
|
|
1956
|
+
label: id,
|
|
1957
|
+
hint: await isInstalled(home, emitters[id]) ? "" : "not installed here"
|
|
1958
|
+
}))));
|
|
1959
|
+
}
|
|
1960
|
+
|
|
1961
|
+
//#endregion
|
|
1962
|
+
//#region src/commands/setup/index.ts
|
|
1963
|
+
var import_picocolors$1 = /* @__PURE__ */ __toESM(require_picocolors(), 1);
|
|
1964
|
+
/** One entry per thing this machine can be set up from `config.ts`. */
|
|
1965
|
+
const targets = { [agents.name]: agents };
|
|
1966
|
+
const USAGE = `Usage: pakhale setup <target> [options]
|
|
1967
|
+
|
|
1968
|
+
Set up part of this machine from the declarations in config.ts.
|
|
1969
|
+
|
|
1970
|
+
Targets:
|
|
1971
|
+
${Object.values(targets).map((t) => ` ${t.name.padEnd(10)} ${t.describe}`).join("\n")}
|
|
1972
|
+
|
|
1973
|
+
Run \`pakhale setup <target> --help\` for a target's own options.`;
|
|
1974
|
+
const setup = {
|
|
1975
|
+
name: "setup",
|
|
1976
|
+
describe: "set up this machine from config.ts",
|
|
1977
|
+
async run(argv$1, packageRoot$1) {
|
|
1978
|
+
const [name$1, ...rest$1] = argv$1;
|
|
1979
|
+
if (!name$1) {
|
|
1980
|
+
console.error(import_picocolors$1.default.red("setup needs a target\n"));
|
|
1981
|
+
console.log(USAGE);
|
|
1982
|
+
return 1;
|
|
1983
|
+
}
|
|
1984
|
+
if (name$1 === "--help" || name$1 === "-h") {
|
|
1985
|
+
console.log(USAGE);
|
|
1986
|
+
return 0;
|
|
1987
|
+
}
|
|
1988
|
+
const target = targets[name$1];
|
|
1989
|
+
if (!target) {
|
|
1990
|
+
console.error(import_picocolors$1.default.red(`unknown setup target: ${name$1}\n`));
|
|
1991
|
+
console.log(USAGE);
|
|
1992
|
+
return 1;
|
|
1993
|
+
}
|
|
1994
|
+
return target.run(rest$1, packageRoot$1);
|
|
1995
|
+
}
|
|
1996
|
+
};
|
|
1997
|
+
|
|
1998
|
+
//#endregion
|
|
1999
|
+
//#region src/commands/index.ts
|
|
2000
|
+
const commands = { [setup.name]: setup };
|
|
2001
|
+
|
|
2002
|
+
//#endregion
|
|
2003
|
+
//#region src/cli.ts
|
|
2004
|
+
var import_picocolors = /* @__PURE__ */ __toESM(require_picocolors(), 1);
|
|
2005
|
+
const packageRoot = resolve(dirname(fileURLToPath(import.meta.url)), "..");
|
|
2006
|
+
const [name, ...rest] = process.argv.slice(2);
|
|
2007
|
+
async function version() {
|
|
2008
|
+
return JSON.parse(await readFile(join(packageRoot, "package.json"), "utf8")).version;
|
|
2009
|
+
}
|
|
2010
|
+
function usage() {
|
|
2011
|
+
console.log(`Usage: pakhale <command> [options]\n\nCommands:`);
|
|
2012
|
+
for (const c of Object.values(commands)) console.log(` ${c.name.padEnd(10)} ${c.describe}`);
|
|
2013
|
+
console.log(`\nOptions:\n -h, --help show this help\n -v, --version show version`);
|
|
2014
|
+
}
|
|
2015
|
+
if (!name || name === "--help" || name === "-h") {
|
|
2016
|
+
usage();
|
|
2017
|
+
process.exit(0);
|
|
2018
|
+
}
|
|
2019
|
+
if (name === "--version" || name === "-v") {
|
|
2020
|
+
console.log(await version());
|
|
2021
|
+
process.exit(0);
|
|
2022
|
+
}
|
|
2023
|
+
const command = commands[name];
|
|
2024
|
+
if (!command) {
|
|
2025
|
+
console.error(import_picocolors.default.red(`unknown command: ${name}\n`));
|
|
2026
|
+
usage();
|
|
2027
|
+
process.exit(1);
|
|
2028
|
+
}
|
|
2029
|
+
try {
|
|
2030
|
+
process.exit(await command.run(rest, packageRoot));
|
|
2031
|
+
} catch (err) {
|
|
2032
|
+
console.error(import_picocolors.default.red(err instanceof Error ? err.message : String(err)));
|
|
2033
|
+
process.exit(1);
|
|
2034
|
+
}
|
|
2035
|
+
|
|
2036
|
+
//#endregion
|
|
2037
|
+
export { };
|