ccski 1.0.2 → 1.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/dist/cli.mjs CHANGED
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import { A as intersectionType, D as custom, E as booleanType, F as recordType, G as __require, H as SkillNotFoundError, I as stringType, K as __toESM, L as unionType, M as numberType, N as objectType, O as discriminatedUnionType, P as optionalType, R as unknownType, T as arrayType, W as __commonJS, _ as tone, b as parseSkillFile, c as colors$3, d as formatBytes, f as heading, g as success, h as setColorEnabled, j as literalType, k as enumType, l as dim, m as renderList, n as containsCaseInsensitive, p as highlight, r as rankStrings, t as SkillRegistry, u as error, v as warn, x as validateSkillFile, y as wrap } from "./registry-ChUc2356.mjs";
2
+ import { A as intersectionType, D as custom, E as booleanType, F as recordType, G as __require, H as SkillNotFoundError, I as stringType, K as __toESM, L as unionType, M as numberType, N as objectType, O as discriminatedUnionType, P as optionalType, R as unknownType, T as arrayType, W as __commonJS, _ as tone, b as parseSkillFile, c as colors$3, d as formatBytes, f as heading, g as success, h as setColorEnabled, j as literalType, k as enumType, l as dim, m as renderList, n as containsCaseInsensitive, p as highlight, r as rankStrings, t as SkillRegistry, u as error, v as warn, x as validateSkillFile, y as wrap } from "./registry-DtGaEhsM.mjs";
3
3
  import { cpSync, existsSync, mkdirSync, mkdtempSync, readFileSync, renameSync, rmSync, statSync } from "node:fs";
4
4
  import { stripVTControlCharacters } from "node:util";
5
5
  import { readFileSync as readFileSync$1, readdirSync as readdirSync$1, statSync as statSync$1, writeFile } from "fs";
@@ -4219,7 +4219,7 @@ async function infoCommand(argv) {
4219
4219
  async function listCommand(argv) {
4220
4220
  if (argv.noColor || process.env.FORCE_COLOR === "0") setColorEnabled(false);
4221
4221
  if (argv.color) setColorEnabled(true);
4222
- let skills = new SkillRegistry(buildRegistryOptions(argv, { includeDisabled: argv.all || argv.disabled })).getAll();
4222
+ let skills = new SkillRegistry(buildRegistryOptions(argv, { includeDisabled: Boolean(argv.all || argv.disabled) })).getAll();
4223
4223
  if (argv.disabled) skills = skills.filter((s) => s.disabled);
4224
4224
  else if (!argv.all) skills = skills.filter((s) => !s.disabled);
4225
4225
  skills = skills.sort((a, b) => a.name.localeCompare(b.name));
@@ -4249,13 +4249,20 @@ async function listCommand(argv) {
4249
4249
  const list = groups[location];
4250
4250
  if (!list.length) continue;
4251
4251
  sections.push(`${colors$3.underline(colors$3.bold(labels[location]))} (${list.length})`);
4252
- sections.push(renderList(list.map((skill) => ({
4253
- title: skill.name,
4254
- color: skill.disabled ? colors$3.red : void 0,
4255
- badge: skill.disabled ? colors$3.red("[disabled]") : void 0,
4256
- meta: location === "plugin" ? skill.pluginInfo?.pluginName ?? dim(location) : dim(location),
4257
- description: skill.description
4258
- }))));
4252
+ const listItems = list.map((skill) => {
4253
+ const base = {
4254
+ title: skill.name,
4255
+ meta: location === "plugin" ? skill.pluginInfo?.pluginName ?? dim(location) : dim(location),
4256
+ ...skill.description ? { description: skill.description } : {}
4257
+ };
4258
+ if (skill.disabled) return {
4259
+ ...base,
4260
+ color: colors$3.red,
4261
+ badge: colors$3.red("[disabled]")
4262
+ };
4263
+ return base;
4264
+ });
4265
+ sections.push(renderList(listItems));
4259
4266
  }
4260
4267
  if (sections.length === 0) {
4261
4268
  console.log(argv.disabled ? "No disabled skills found." : "No skills found.");
@@ -22930,309 +22937,113 @@ function resolveSkillFile(input) {
22930
22937
  }
22931
22938
 
22932
22939
  //#endregion
22933
- //#region node_modules/.pnpm/@inquirer+figures@1.0.0/node_modules/@inquirer/figures/dist/esm/index.mjs
22934
- function isUnicodeSupported$1() {
22935
- if (process$1.platform !== "win32") return process$1.env["TERM"] !== "linux";
22936
- return 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";
22940
+ //#region src/utils/git-url-parser.ts
22941
+ /**
22942
+ * 内部辅助函数:标准化仓库 URL
22943
+ * 1. 去除尾部斜杠
22944
+ * 2. 确保以 .git 结尾
22945
+ */
22946
+ function normalizeRepoUrl(origin, path) {
22947
+ let cleanPath = path.replace(/\/+$/, "");
22948
+ if (cleanPath.endsWith(".git")) cleanPath = cleanPath.slice(0, -4);
22949
+ return `${origin}${cleanPath}.git`;
22937
22950
  }
22938
- const common$1 = {
22939
- circleQuestionMark: "(?)",
22940
- questionMarkPrefix: "(?)",
22941
- square: "█",
22942
- squareDarkShade: "▓",
22943
- squareMediumShade: "▒",
22944
- squareLightShade: "░",
22945
- squareTop: "",
22946
- squareBottom: "▄",
22947
- squareLeft: "▌",
22948
- squareRight: "",
22949
- squareCenter: "",
22950
- bullet: "",
22951
- dot: "․",
22952
- ellipsis: "…",
22953
- pointerSmall: "",
22954
- triangleUp: "",
22955
- triangleUpSmall: "▴",
22956
- triangleDown: "▼",
22957
- triangleDownSmall: "",
22958
- triangleLeftSmall: "",
22959
- triangleRightSmall: "▸",
22960
- home: "⌂",
22961
- heart: "",
22962
- musicNote: "",
22963
- musicNoteBeamed: "♫",
22964
- arrowUp: "↑",
22965
- arrowDown: "",
22966
- arrowLeft: "",
22967
- arrowRight: "→",
22968
- arrowLeftRight: "↔",
22969
- arrowUpDown: "",
22970
- almostEqual: "",
22971
- notEqual: "≠",
22972
- lessOrEqual: "≤",
22973
- greaterOrEqual: "≥",
22974
- identical: "≡",
22975
- infinity: "∞",
22976
- subscriptZero: "₀",
22977
- subscriptOne: "₁",
22978
- subscriptTwo: "₂",
22979
- subscriptThree: "₃",
22980
- subscriptFour: "₄",
22981
- subscriptFive: "₅",
22982
- subscriptSix: "",
22983
- subscriptSeven: "",
22984
- subscriptEight: "",
22985
- subscriptNine: "₉",
22986
- oneHalf: "½",
22987
- oneThird: "⅓",
22988
- oneQuarter: "¼",
22989
- oneFifth: "⅕",
22990
- oneSixth: "⅙",
22991
- oneEighth: "",
22992
- twoThirds: "⅔",
22993
- twoFifths: "",
22994
- threeQuarters: "¾",
22995
- threeFifths: "⅗",
22996
- threeEighths: "⅜",
22997
- fourFifths: "⅘",
22998
- fiveSixths: "⅚",
22999
- fiveEighths: "",
23000
- sevenEighths: "⅞",
23001
- line: "─",
23002
- lineBold: "━",
23003
- lineDouble: "═",
23004
- lineDashed0: "┄",
23005
- lineDashed1: "┅",
23006
- lineDashed2: "┈",
23007
- lineDashed3: "┉",
23008
- lineDashed4: "",
23009
- lineDashed5: "",
23010
- lineDashed6: "",
23011
- lineDashed7: "╶",
23012
- lineDashed8: "╸",
23013
- lineDashed9: "╺",
23014
- lineDashed10: "╼",
23015
- lineDashed11: "╾",
23016
- lineDashed12: "−",
23017
- lineDashed13: "–",
23018
- lineDashed14: "‐",
23019
- lineDashed15: "",
23020
- lineVertical: "",
23021
- lineVerticalBold: "",
23022
- lineVerticalDouble: "",
23023
- lineVerticalDashed0: "",
23024
- lineVerticalDashed1: "┇",
23025
- lineVerticalDashed2: "┊",
23026
- lineVerticalDashed3: "┋",
23027
- lineVerticalDashed4: "╎",
23028
- lineVerticalDashed5: "",
23029
- lineVerticalDashed6: "",
23030
- lineVerticalDashed7: "╷",
23031
- lineVerticalDashed8: "╹",
23032
- lineVerticalDashed9: "╻",
23033
- lineVerticalDashed10: "╽",
23034
- lineVerticalDashed11: "╿",
23035
- lineDownLeft: "┐",
23036
- lineDownLeftArc: "╮",
23037
- lineDownBoldLeftBold: "┓",
23038
- lineDownBoldLeft: "┒",
23039
- lineDownLeftBold: "┑",
23040
- lineDownDoubleLeftDouble: "╗",
23041
- lineDownDoubleLeft: "╖",
23042
- lineDownLeftDouble: "╕",
23043
- lineDownRight: "┌",
23044
- lineDownRightArc: "╭",
23045
- lineDownBoldRightBold: "┏",
23046
- lineDownBoldRight: "┎",
23047
- lineDownRightBold: "┍",
23048
- lineDownDoubleRightDouble: "╔",
23049
- lineDownDoubleRight: "╓",
23050
- lineDownRightDouble: "╒",
23051
- lineUpLeft: "┘",
23052
- lineUpLeftArc: "╯",
23053
- lineUpBoldLeftBold: "┛",
23054
- lineUpBoldLeft: "┚",
23055
- lineUpLeftBold: "┙",
23056
- lineUpDoubleLeftDouble: "╝",
23057
- lineUpDoubleLeft: "╜",
23058
- lineUpLeftDouble: "╛",
23059
- lineUpRight: "└",
23060
- lineUpRightArc: "╰",
23061
- lineUpBoldRightBold: "┗",
23062
- lineUpBoldRight: "┖",
23063
- lineUpRightBold: "┕",
23064
- lineUpDoubleRightDouble: "╚",
23065
- lineUpDoubleRight: "╙",
23066
- lineUpRightDouble: "╘",
23067
- lineUpDownLeft: "┤",
23068
- lineUpBoldDownBoldLeftBold: "┫",
23069
- lineUpBoldDownBoldLeft: "┨",
23070
- lineUpDownLeftBold: "┥",
23071
- lineUpBoldDownLeftBold: "┩",
23072
- lineUpDownBoldLeftBold: "┪",
23073
- lineUpDownBoldLeft: "┧",
23074
- lineUpBoldDownLeft: "┦",
23075
- lineUpDoubleDownDoubleLeftDouble: "╣",
23076
- lineUpDoubleDownDoubleLeft: "╢",
23077
- lineUpDownLeftDouble: "╡",
23078
- lineUpDownRight: "├",
23079
- lineUpBoldDownBoldRightBold: "┣",
23080
- lineUpBoldDownBoldRight: "┠",
23081
- lineUpDownRightBold: "┝",
23082
- lineUpBoldDownRightBold: "┡",
23083
- lineUpDownBoldRightBold: "┢",
23084
- lineUpDownBoldRight: "┟",
23085
- lineUpBoldDownRight: "┞",
23086
- lineUpDoubleDownDoubleRightDouble: "╠",
23087
- lineUpDoubleDownDoubleRight: "╟",
23088
- lineUpDownRightDouble: "╞",
23089
- lineDownLeftRight: "┬",
23090
- lineDownBoldLeftBoldRightBold: "┳",
23091
- lineDownLeftBoldRightBold: "┯",
23092
- lineDownBoldLeftRight: "┰",
23093
- lineDownBoldLeftBoldRight: "┱",
23094
- lineDownBoldLeftRightBold: "┲",
23095
- lineDownLeftRightBold: "┮",
23096
- lineDownLeftBoldRight: "┭",
23097
- lineDownDoubleLeftDoubleRightDouble: "╦",
23098
- lineDownDoubleLeftRight: "╥",
23099
- lineDownLeftDoubleRightDouble: "╤",
23100
- lineUpLeftRight: "┴",
23101
- lineUpBoldLeftBoldRightBold: "┻",
23102
- lineUpLeftBoldRightBold: "┷",
23103
- lineUpBoldLeftRight: "┸",
23104
- lineUpBoldLeftBoldRight: "┹",
23105
- lineUpBoldLeftRightBold: "┺",
23106
- lineUpLeftRightBold: "┶",
23107
- lineUpLeftBoldRight: "┵",
23108
- lineUpDoubleLeftDoubleRightDouble: "╩",
23109
- lineUpDoubleLeftRight: "╨",
23110
- lineUpLeftDoubleRightDouble: "╧",
23111
- lineUpDownLeftRight: "┼",
23112
- lineUpBoldDownBoldLeftBoldRightBold: "╋",
23113
- lineUpDownBoldLeftBoldRightBold: "╈",
23114
- lineUpBoldDownLeftBoldRightBold: "╇",
23115
- lineUpBoldDownBoldLeftRightBold: "╊",
23116
- lineUpBoldDownBoldLeftBoldRight: "╉",
23117
- lineUpBoldDownLeftRight: "╀",
23118
- lineUpDownBoldLeftRight: "╁",
23119
- lineUpDownLeftBoldRight: "┽",
23120
- lineUpDownLeftRightBold: "┾",
23121
- lineUpBoldDownBoldLeftRight: "╂",
23122
- lineUpDownLeftBoldRightBold: "┿",
23123
- lineUpBoldDownLeftBoldRight: "╃",
23124
- lineUpBoldDownLeftRightBold: "╄",
23125
- lineUpDownBoldLeftBoldRight: "╅",
23126
- lineUpDownBoldLeftRightBold: "╆",
23127
- lineUpDoubleDownDoubleLeftDoubleRightDouble: "╬",
23128
- lineUpDoubleDownDoubleLeftRight: "╫",
23129
- lineUpDownLeftDoubleRightDouble: "╪",
23130
- lineCross: "╳",
23131
- lineBackslash: "╲",
23132
- lineSlash: "╱"
23133
- };
23134
- const specialMainSymbols$1 = {
23135
- tick: "✔",
23136
- info: "ℹ",
23137
- warning: "⚠",
23138
- cross: "✘",
23139
- squareSmall: "◻",
23140
- squareSmallFilled: "◼",
23141
- circle: "◯",
23142
- circleFilled: "◉",
23143
- circleDotted: "◌",
23144
- circleDouble: "◎",
23145
- circleCircle: "ⓞ",
23146
- circleCross: "ⓧ",
23147
- circlePipe: "Ⓘ",
23148
- radioOn: "◉",
23149
- radioOff: "◯",
23150
- checkboxOn: "☒",
23151
- checkboxOff: "☐",
23152
- checkboxCircleOn: "ⓧ",
23153
- checkboxCircleOff: "Ⓘ",
23154
- pointer: "❯",
23155
- triangleUpOutline: "△",
23156
- triangleLeft: "◀",
23157
- triangleRight: "▶",
23158
- lozenge: "◆",
23159
- lozengeOutline: "◇",
23160
- hamburger: "☰",
23161
- smiley: "㋡",
23162
- mustache: "෴",
23163
- star: "★",
23164
- play: "▶",
23165
- nodejs: "⬢",
23166
- oneSeventh: "⅐",
23167
- oneNinth: "⅑",
23168
- oneTenth: "⅒"
23169
- };
23170
- const specialFallbackSymbols$1 = {
23171
- tick: "√",
23172
- info: "i",
23173
- warning: "‼",
23174
- cross: "×",
23175
- squareSmall: "□",
23176
- squareSmallFilled: "■",
23177
- circle: "( )",
23178
- circleFilled: "(*)",
23179
- circleDotted: "( )",
23180
- circleDouble: "( )",
23181
- circleCircle: "(○)",
23182
- circleCross: "(×)",
23183
- circlePipe: "(│)",
23184
- radioOn: "(*)",
23185
- radioOff: "( )",
23186
- checkboxOn: "[×]",
23187
- checkboxOff: "[ ]",
23188
- checkboxCircleOn: "(×)",
23189
- checkboxCircleOff: "( )",
23190
- pointer: ">",
23191
- triangleUpOutline: "∆",
23192
- triangleLeft: "◄",
23193
- triangleRight: "►",
23194
- lozenge: "♦",
23195
- lozengeOutline: "◊",
23196
- hamburger: "≡",
23197
- smiley: "☺",
23198
- mustache: "┌─┐",
23199
- star: "✶",
23200
- play: "►",
23201
- nodejs: "♦",
23202
- oneSeventh: "1/7",
23203
- oneNinth: "1/9",
23204
- oneTenth: "1/10"
23205
- };
23206
- const mainSymbols$1 = {
23207
- ...common$1,
23208
- ...specialMainSymbols$1
23209
- };
23210
- const fallbackSymbols$1 = {
23211
- ...common$1,
23212
- ...specialFallbackSymbols$1
23213
- };
23214
- const shouldUseMain$1 = isUnicodeSupported$1();
23215
- const figures$1 = shouldUseMain$1 ? mainSymbols$1 : fallbackSymbols$1;
23216
- var esm_default = figures$1;
23217
- const replacements$1 = Object.entries(specialMainSymbols$1);
23218
-
23219
- //#endregion
23220
- //#region node_modules/.pnpm/@inquirer+core@10.3.2_@types+node@22.19.1/node_modules/@inquirer/core/dist/esm/lib/key.js
23221
- const isUpKey = (key$1, keybindings = []) => key$1.name === "up" || keybindings.includes("vim") && key$1.name === "k" || keybindings.includes("emacs") && key$1.ctrl && key$1.name === "p";
23222
- const isDownKey = (key$1, keybindings = []) => key$1.name === "down" || keybindings.includes("vim") && key$1.name === "j" || keybindings.includes("emacs") && key$1.ctrl && key$1.name === "n";
23223
- const isSpaceKey = (key$1) => key$1.name === "space";
23224
- const isNumberKey = (key$1) => "1234567890".includes(key$1.name);
23225
- const isEnterKey = (key$1) => key$1.name === "enter" || key$1.name === "return";
23226
-
23227
- //#endregion
23228
- //#region node_modules/.pnpm/@inquirer+core@10.3.2_@types+node@22.19.1/node_modules/@inquirer/core/dist/esm/lib/errors.js
23229
- var AbortPromptError = class extends Error {
23230
- name = "AbortPromptError";
23231
- message = "Prompt was aborted";
23232
- constructor(options) {
23233
- super();
23234
- this.cause = options?.cause;
23235
- }
22951
+ /**
22952
+ * Git URL 嗅探与解析器
22953
+ *
22954
+ * @param inputUrl 用户输入的任意 URL 字符串
22955
+ * @returns 解析结果对象,如果 URL 无效则返回 null
22956
+ */
22957
+ function parseGitUrl(inputUrl) {
22958
+ if (!inputUrl || typeof inputUrl !== "string" || !inputUrl.trim()) return null;
22959
+ try {
22960
+ const url = new URL(inputUrl.trim());
22961
+ if (!["http:", "https:"].includes(url.protocol)) return null;
22962
+ const normalizedPath = url.pathname.replace(/\/+/g, "/");
22963
+ if (normalizedPath === "/" || normalizedPath === "") return null;
22964
+ const strategies = [
22965
+ {
22966
+ pattern: "/-/blob/",
22967
+ type: "blob"
22968
+ },
22969
+ {
22970
+ pattern: "/-/tree/",
22971
+ type: "tree"
22972
+ },
22973
+ {
22974
+ pattern: "/src/",
22975
+ type: "blob"
22976
+ },
22977
+ {
22978
+ pattern: "/blob/",
22979
+ type: "blob"
22980
+ },
22981
+ {
22982
+ pattern: "/tree/",
22983
+ type: "tree"
22984
+ }
22985
+ ];
22986
+ let bestStrategy = null;
22987
+ let minIndex = Infinity;
22988
+ for (const strategy of strategies) {
22989
+ const index = normalizedPath.indexOf(strategy.pattern);
22990
+ if (index !== -1 && index < minIndex) {
22991
+ minIndex = index;
22992
+ bestStrategy = strategy;
22993
+ }
22994
+ }
22995
+ let repoPathPart = "";
22996
+ let remainingPart = "";
22997
+ let type = "tree";
22998
+ if (bestStrategy && minIndex !== Infinity) {
22999
+ type = bestStrategy.type;
23000
+ repoPathPart = normalizedPath.substring(0, minIndex);
23001
+ remainingPart = normalizedPath.substring(minIndex + bestStrategy.pattern.length);
23002
+ } else {
23003
+ repoPathPart = normalizedPath;
23004
+ type = "tree";
23005
+ }
23006
+ if (!repoPathPart || repoPathPart === "/") return null;
23007
+ const result = {
23008
+ repo: normalizeRepoUrl(url.origin, repoPathPart),
23009
+ type
23010
+ };
23011
+ if (remainingPart) {
23012
+ const segments = remainingPart.split("/").map((s) => {
23013
+ try {
23014
+ return decodeURIComponent(s);
23015
+ } catch {
23016
+ return s;
23017
+ }
23018
+ }).filter(Boolean);
23019
+ if (segments.length > 0) {
23020
+ result.branch = segments[0];
23021
+ if (segments.length > 1) result.path = segments.slice(1).join("/");
23022
+ } else result.type = "tree";
23023
+ } else if (bestStrategy) result.type = "tree";
23024
+ return result;
23025
+ } catch (error$2) {
23026
+ return null;
23027
+ }
23028
+ }
23029
+
23030
+ //#endregion
23031
+ //#region node_modules/.pnpm/@inquirer+core@10.3.2_@types+node@22.19.1/node_modules/@inquirer/core/dist/esm/lib/key.js
23032
+ const isUpKey = (key$1, keybindings = []) => key$1.name === "up" || keybindings.includes("vim") && key$1.name === "k" || keybindings.includes("emacs") && key$1.ctrl && key$1.name === "p";
23033
+ const isDownKey = (key$1, keybindings = []) => key$1.name === "down" || keybindings.includes("vim") && key$1.name === "j" || keybindings.includes("emacs") && key$1.ctrl && key$1.name === "n";
23034
+ const isSpaceKey = (key$1) => key$1.name === "space";
23035
+ const isNumberKey = (key$1) => "1234567890".includes(key$1.name);
23036
+ const isEnterKey = (key$1) => key$1.name === "enter" || key$1.name === "return";
23037
+
23038
+ //#endregion
23039
+ //#region node_modules/.pnpm/@inquirer+core@10.3.2_@types+node@22.19.1/node_modules/@inquirer/core/dist/esm/lib/errors.js
23040
+ var AbortPromptError = class extends Error {
23041
+ name = "AbortPromptError";
23042
+ message = "Prompt was aborted";
23043
+ constructor(options) {
23044
+ super();
23045
+ this.cause = options?.cause;
23046
+ }
23236
23047
  };
23237
23048
  var CancelPromptError = class extends Error {
23238
23049
  name = "CancelPromptError";
@@ -23443,11 +23254,11 @@ var require_yoctocolors_cjs = /* @__PURE__ */ __commonJS({ "node_modules/.pnpm/y
23443
23254
 
23444
23255
  //#endregion
23445
23256
  //#region node_modules/.pnpm/@inquirer+figures@1.0.15/node_modules/@inquirer/figures/dist/esm/index.js
23446
- function isUnicodeSupported() {
23257
+ function isUnicodeSupported$1() {
23447
23258
  if (process$1.platform !== "win32") return process$1.env["TERM"] !== "linux";
23448
23259
  return 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";
23449
23260
  }
23450
- const common = {
23261
+ const common$1 = {
23451
23262
  circleQuestionMark: "(?)",
23452
23263
  questionMarkPrefix: "(?)",
23453
23264
  square: "█",
@@ -23643,7 +23454,7 @@ const common = {
23643
23454
  lineBackslash: "╲",
23644
23455
  lineSlash: "╱"
23645
23456
  };
23646
- const specialMainSymbols = {
23457
+ const specialMainSymbols$1 = {
23647
23458
  tick: "✔",
23648
23459
  info: "ℹ",
23649
23460
  warning: "⚠",
@@ -23679,7 +23490,7 @@ const specialMainSymbols = {
23679
23490
  oneNinth: "⅑",
23680
23491
  oneTenth: "⅒"
23681
23492
  };
23682
- const specialFallbackSymbols = {
23493
+ const specialFallbackSymbols$1 = {
23683
23494
  tick: "√",
23684
23495
  info: "i",
23685
23496
  warning: "‼",
@@ -23715,18 +23526,18 @@ const specialFallbackSymbols = {
23715
23526
  oneNinth: "1/9",
23716
23527
  oneTenth: "1/10"
23717
23528
  };
23718
- const mainSymbols = {
23719
- ...common,
23720
- ...specialMainSymbols
23529
+ const mainSymbols$1 = {
23530
+ ...common$1,
23531
+ ...specialMainSymbols$1
23721
23532
  };
23722
- const fallbackSymbols = {
23723
- ...common,
23724
- ...specialFallbackSymbols
23533
+ const fallbackSymbols$1 = {
23534
+ ...common$1,
23535
+ ...specialFallbackSymbols$1
23725
23536
  };
23726
- const shouldUseMain = isUnicodeSupported();
23727
- const figures = shouldUseMain ? mainSymbols : fallbackSymbols;
23728
- var esm_default$1 = figures;
23729
- const replacements = Object.entries(specialMainSymbols);
23537
+ const shouldUseMain$1 = isUnicodeSupported$1();
23538
+ const figures$1 = shouldUseMain$1 ? mainSymbols$1 : fallbackSymbols$1;
23539
+ var esm_default$1 = figures$1;
23540
+ const replacements$1 = Object.entries(specialMainSymbols$1);
23730
23541
 
23731
23542
  //#endregion
23732
23543
  //#region node_modules/.pnpm/@inquirer+core@10.3.2_@types+node@22.19.1/node_modules/@inquirer/core/dist/esm/lib/theme.js
@@ -26433,6 +26244,293 @@ var Separator = class {
26433
26244
  }
26434
26245
  };
26435
26246
 
26247
+ //#endregion
26248
+ //#region node_modules/.pnpm/@inquirer+figures@1.0.0/node_modules/@inquirer/figures/dist/esm/index.mjs
26249
+ function isUnicodeSupported() {
26250
+ if (process$1.platform !== "win32") return process$1.env["TERM"] !== "linux";
26251
+ return 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";
26252
+ }
26253
+ const common = {
26254
+ circleQuestionMark: "(?)",
26255
+ questionMarkPrefix: "(?)",
26256
+ square: "█",
26257
+ squareDarkShade: "▓",
26258
+ squareMediumShade: "▒",
26259
+ squareLightShade: "░",
26260
+ squareTop: "▀",
26261
+ squareBottom: "▄",
26262
+ squareLeft: "▌",
26263
+ squareRight: "▐",
26264
+ squareCenter: "■",
26265
+ bullet: "●",
26266
+ dot: "․",
26267
+ ellipsis: "…",
26268
+ pointerSmall: "›",
26269
+ triangleUp: "▲",
26270
+ triangleUpSmall: "▴",
26271
+ triangleDown: "▼",
26272
+ triangleDownSmall: "▾",
26273
+ triangleLeftSmall: "◂",
26274
+ triangleRightSmall: "▸",
26275
+ home: "⌂",
26276
+ heart: "♥",
26277
+ musicNote: "♪",
26278
+ musicNoteBeamed: "♫",
26279
+ arrowUp: "↑",
26280
+ arrowDown: "↓",
26281
+ arrowLeft: "←",
26282
+ arrowRight: "→",
26283
+ arrowLeftRight: "↔",
26284
+ arrowUpDown: "↕",
26285
+ almostEqual: "≈",
26286
+ notEqual: "≠",
26287
+ lessOrEqual: "≤",
26288
+ greaterOrEqual: "≥",
26289
+ identical: "≡",
26290
+ infinity: "∞",
26291
+ subscriptZero: "₀",
26292
+ subscriptOne: "₁",
26293
+ subscriptTwo: "₂",
26294
+ subscriptThree: "₃",
26295
+ subscriptFour: "₄",
26296
+ subscriptFive: "₅",
26297
+ subscriptSix: "₆",
26298
+ subscriptSeven: "₇",
26299
+ subscriptEight: "₈",
26300
+ subscriptNine: "₉",
26301
+ oneHalf: "½",
26302
+ oneThird: "⅓",
26303
+ oneQuarter: "¼",
26304
+ oneFifth: "⅕",
26305
+ oneSixth: "⅙",
26306
+ oneEighth: "⅛",
26307
+ twoThirds: "⅔",
26308
+ twoFifths: "⅖",
26309
+ threeQuarters: "¾",
26310
+ threeFifths: "⅗",
26311
+ threeEighths: "⅜",
26312
+ fourFifths: "⅘",
26313
+ fiveSixths: "⅚",
26314
+ fiveEighths: "⅝",
26315
+ sevenEighths: "⅞",
26316
+ line: "─",
26317
+ lineBold: "━",
26318
+ lineDouble: "═",
26319
+ lineDashed0: "┄",
26320
+ lineDashed1: "┅",
26321
+ lineDashed2: "┈",
26322
+ lineDashed3: "┉",
26323
+ lineDashed4: "╌",
26324
+ lineDashed5: "╍",
26325
+ lineDashed6: "╴",
26326
+ lineDashed7: "╶",
26327
+ lineDashed8: "╸",
26328
+ lineDashed9: "╺",
26329
+ lineDashed10: "╼",
26330
+ lineDashed11: "╾",
26331
+ lineDashed12: "−",
26332
+ lineDashed13: "–",
26333
+ lineDashed14: "‐",
26334
+ lineDashed15: "⁃",
26335
+ lineVertical: "│",
26336
+ lineVerticalBold: "┃",
26337
+ lineVerticalDouble: "║",
26338
+ lineVerticalDashed0: "┆",
26339
+ lineVerticalDashed1: "┇",
26340
+ lineVerticalDashed2: "┊",
26341
+ lineVerticalDashed3: "┋",
26342
+ lineVerticalDashed4: "╎",
26343
+ lineVerticalDashed5: "╏",
26344
+ lineVerticalDashed6: "╵",
26345
+ lineVerticalDashed7: "╷",
26346
+ lineVerticalDashed8: "╹",
26347
+ lineVerticalDashed9: "╻",
26348
+ lineVerticalDashed10: "╽",
26349
+ lineVerticalDashed11: "╿",
26350
+ lineDownLeft: "┐",
26351
+ lineDownLeftArc: "╮",
26352
+ lineDownBoldLeftBold: "┓",
26353
+ lineDownBoldLeft: "┒",
26354
+ lineDownLeftBold: "┑",
26355
+ lineDownDoubleLeftDouble: "╗",
26356
+ lineDownDoubleLeft: "╖",
26357
+ lineDownLeftDouble: "╕",
26358
+ lineDownRight: "┌",
26359
+ lineDownRightArc: "╭",
26360
+ lineDownBoldRightBold: "┏",
26361
+ lineDownBoldRight: "┎",
26362
+ lineDownRightBold: "┍",
26363
+ lineDownDoubleRightDouble: "╔",
26364
+ lineDownDoubleRight: "╓",
26365
+ lineDownRightDouble: "╒",
26366
+ lineUpLeft: "┘",
26367
+ lineUpLeftArc: "╯",
26368
+ lineUpBoldLeftBold: "┛",
26369
+ lineUpBoldLeft: "┚",
26370
+ lineUpLeftBold: "┙",
26371
+ lineUpDoubleLeftDouble: "╝",
26372
+ lineUpDoubleLeft: "╜",
26373
+ lineUpLeftDouble: "╛",
26374
+ lineUpRight: "└",
26375
+ lineUpRightArc: "╰",
26376
+ lineUpBoldRightBold: "┗",
26377
+ lineUpBoldRight: "┖",
26378
+ lineUpRightBold: "┕",
26379
+ lineUpDoubleRightDouble: "╚",
26380
+ lineUpDoubleRight: "╙",
26381
+ lineUpRightDouble: "╘",
26382
+ lineUpDownLeft: "┤",
26383
+ lineUpBoldDownBoldLeftBold: "┫",
26384
+ lineUpBoldDownBoldLeft: "┨",
26385
+ lineUpDownLeftBold: "┥",
26386
+ lineUpBoldDownLeftBold: "┩",
26387
+ lineUpDownBoldLeftBold: "┪",
26388
+ lineUpDownBoldLeft: "┧",
26389
+ lineUpBoldDownLeft: "┦",
26390
+ lineUpDoubleDownDoubleLeftDouble: "╣",
26391
+ lineUpDoubleDownDoubleLeft: "╢",
26392
+ lineUpDownLeftDouble: "╡",
26393
+ lineUpDownRight: "├",
26394
+ lineUpBoldDownBoldRightBold: "┣",
26395
+ lineUpBoldDownBoldRight: "┠",
26396
+ lineUpDownRightBold: "┝",
26397
+ lineUpBoldDownRightBold: "┡",
26398
+ lineUpDownBoldRightBold: "┢",
26399
+ lineUpDownBoldRight: "┟",
26400
+ lineUpBoldDownRight: "┞",
26401
+ lineUpDoubleDownDoubleRightDouble: "╠",
26402
+ lineUpDoubleDownDoubleRight: "╟",
26403
+ lineUpDownRightDouble: "╞",
26404
+ lineDownLeftRight: "┬",
26405
+ lineDownBoldLeftBoldRightBold: "┳",
26406
+ lineDownLeftBoldRightBold: "┯",
26407
+ lineDownBoldLeftRight: "┰",
26408
+ lineDownBoldLeftBoldRight: "┱",
26409
+ lineDownBoldLeftRightBold: "┲",
26410
+ lineDownLeftRightBold: "┮",
26411
+ lineDownLeftBoldRight: "┭",
26412
+ lineDownDoubleLeftDoubleRightDouble: "╦",
26413
+ lineDownDoubleLeftRight: "╥",
26414
+ lineDownLeftDoubleRightDouble: "╤",
26415
+ lineUpLeftRight: "┴",
26416
+ lineUpBoldLeftBoldRightBold: "┻",
26417
+ lineUpLeftBoldRightBold: "┷",
26418
+ lineUpBoldLeftRight: "┸",
26419
+ lineUpBoldLeftBoldRight: "┹",
26420
+ lineUpBoldLeftRightBold: "┺",
26421
+ lineUpLeftRightBold: "┶",
26422
+ lineUpLeftBoldRight: "┵",
26423
+ lineUpDoubleLeftDoubleRightDouble: "╩",
26424
+ lineUpDoubleLeftRight: "╨",
26425
+ lineUpLeftDoubleRightDouble: "╧",
26426
+ lineUpDownLeftRight: "┼",
26427
+ lineUpBoldDownBoldLeftBoldRightBold: "╋",
26428
+ lineUpDownBoldLeftBoldRightBold: "╈",
26429
+ lineUpBoldDownLeftBoldRightBold: "╇",
26430
+ lineUpBoldDownBoldLeftRightBold: "╊",
26431
+ lineUpBoldDownBoldLeftBoldRight: "╉",
26432
+ lineUpBoldDownLeftRight: "╀",
26433
+ lineUpDownBoldLeftRight: "╁",
26434
+ lineUpDownLeftBoldRight: "┽",
26435
+ lineUpDownLeftRightBold: "┾",
26436
+ lineUpBoldDownBoldLeftRight: "╂",
26437
+ lineUpDownLeftBoldRightBold: "┿",
26438
+ lineUpBoldDownLeftBoldRight: "╃",
26439
+ lineUpBoldDownLeftRightBold: "╄",
26440
+ lineUpDownBoldLeftBoldRight: "╅",
26441
+ lineUpDownBoldLeftRightBold: "╆",
26442
+ lineUpDoubleDownDoubleLeftDoubleRightDouble: "╬",
26443
+ lineUpDoubleDownDoubleLeftRight: "╫",
26444
+ lineUpDownLeftDoubleRightDouble: "╪",
26445
+ lineCross: "╳",
26446
+ lineBackslash: "╲",
26447
+ lineSlash: "╱"
26448
+ };
26449
+ const specialMainSymbols = {
26450
+ tick: "✔",
26451
+ info: "ℹ",
26452
+ warning: "⚠",
26453
+ cross: "✘",
26454
+ squareSmall: "◻",
26455
+ squareSmallFilled: "◼",
26456
+ circle: "◯",
26457
+ circleFilled: "◉",
26458
+ circleDotted: "◌",
26459
+ circleDouble: "◎",
26460
+ circleCircle: "ⓞ",
26461
+ circleCross: "ⓧ",
26462
+ circlePipe: "Ⓘ",
26463
+ radioOn: "◉",
26464
+ radioOff: "◯",
26465
+ checkboxOn: "☒",
26466
+ checkboxOff: "☐",
26467
+ checkboxCircleOn: "ⓧ",
26468
+ checkboxCircleOff: "Ⓘ",
26469
+ pointer: "❯",
26470
+ triangleUpOutline: "△",
26471
+ triangleLeft: "◀",
26472
+ triangleRight: "▶",
26473
+ lozenge: "◆",
26474
+ lozengeOutline: "◇",
26475
+ hamburger: "☰",
26476
+ smiley: "㋡",
26477
+ mustache: "෴",
26478
+ star: "★",
26479
+ play: "▶",
26480
+ nodejs: "⬢",
26481
+ oneSeventh: "⅐",
26482
+ oneNinth: "⅑",
26483
+ oneTenth: "⅒"
26484
+ };
26485
+ const specialFallbackSymbols = {
26486
+ tick: "√",
26487
+ info: "i",
26488
+ warning: "‼",
26489
+ cross: "×",
26490
+ squareSmall: "□",
26491
+ squareSmallFilled: "■",
26492
+ circle: "( )",
26493
+ circleFilled: "(*)",
26494
+ circleDotted: "( )",
26495
+ circleDouble: "( )",
26496
+ circleCircle: "(○)",
26497
+ circleCross: "(×)",
26498
+ circlePipe: "(│)",
26499
+ radioOn: "(*)",
26500
+ radioOff: "( )",
26501
+ checkboxOn: "[×]",
26502
+ checkboxOff: "[ ]",
26503
+ checkboxCircleOn: "(×)",
26504
+ checkboxCircleOff: "( )",
26505
+ pointer: ">",
26506
+ triangleUpOutline: "∆",
26507
+ triangleLeft: "◄",
26508
+ triangleRight: "►",
26509
+ lozenge: "♦",
26510
+ lozengeOutline: "◊",
26511
+ hamburger: "≡",
26512
+ smiley: "☺",
26513
+ mustache: "┌─┐",
26514
+ star: "✶",
26515
+ play: "►",
26516
+ nodejs: "♦",
26517
+ oneSeventh: "1/7",
26518
+ oneNinth: "1/9",
26519
+ oneTenth: "1/10"
26520
+ };
26521
+ const mainSymbols = {
26522
+ ...common,
26523
+ ...specialMainSymbols
26524
+ };
26525
+ const fallbackSymbols = {
26526
+ ...common,
26527
+ ...specialFallbackSymbols
26528
+ };
26529
+ const shouldUseMain = isUnicodeSupported();
26530
+ const figures = shouldUseMain ? mainSymbols : fallbackSymbols;
26531
+ var esm_default = figures;
26532
+ const replacements = Object.entries(specialMainSymbols);
26533
+
26436
26534
  //#endregion
26437
26535
  //#region src/cli/prompts/multiSelect.ts
26438
26536
  const checkboxTheme = {
@@ -26453,15 +26551,18 @@ const checkboxTheme = {
26453
26551
  const isSelectable = (item) => !Separator.isSeparator(item) && !item.disabled;
26454
26552
  const isChecked = (item) => isSelectable(item) && item.checked === true;
26455
26553
  function normalizeChoices(choices, defaultChecked) {
26456
- return choices.map((choice) => ({
26457
- value: choice.value,
26458
- name: choice.label,
26459
- short: choice.label,
26460
- checkedName: choice.label,
26461
- description: choice.description,
26462
- checked: choice.checked ?? defaultChecked,
26463
- disabled: false
26464
- }));
26554
+ return choices.map((choice) => {
26555
+ const desc = choice.description;
26556
+ return {
26557
+ value: choice.value,
26558
+ name: choice.label,
26559
+ short: choice.label,
26560
+ checkedName: choice.label,
26561
+ ...desc ? { description: desc } : {},
26562
+ checked: choice.checked ?? defaultChecked,
26563
+ disabled: false
26564
+ };
26565
+ });
26465
26566
  }
26466
26567
  function buildPreview(command$1, selected) {
26467
26568
  if (!command$1) return void 0;
@@ -26473,20 +26574,38 @@ function buildPreview(command$1, selected) {
26473
26574
  return `${tone.info(`${label}:`)} ${renderedBase}${suffix}`;
26474
26575
  }
26475
26576
  const promptImpl = createPrompt((config, done) => {
26476
- const { instructions, pageSize = 12, loop = false, required, validate = () => true, defaultChecked = false, command: command$1 } = config;
26577
+ const { instructions, pageSize, loop = false, required, validate = () => true, defaultChecked = false, command: command$1 } = config;
26477
26578
  const shortcuts = {
26478
26579
  all: "a",
26479
26580
  invert: "i",
26480
26581
  ...config.shortcuts
26481
26582
  };
26482
26583
  const theme = makeTheme(checkboxTheme, config.theme);
26483
- const { keybindings } = theme;
26584
+ const keybindings = theme.keybindings;
26484
26585
  const [status$1, setStatus] = useState("idle");
26485
26586
  const prefix = usePrefix({
26486
26587
  status: status$1,
26487
26588
  theme
26488
26589
  });
26489
26590
  const [items, setItems] = useState(normalizeChoices(config.choices, defaultChecked));
26591
+ const [termSize, setTermSize] = useState(() => ({
26592
+ rows: process.stdout?.rows ?? 24,
26593
+ cols: process.stdout?.columns ?? 80
26594
+ }));
26595
+ useEffect(() => {
26596
+ const stdout = process.stdout;
26597
+ if (!stdout?.on || !stdout?.off) return;
26598
+ const handleResize = () => {
26599
+ setTermSize({
26600
+ rows: stdout.rows ?? termSize.rows,
26601
+ cols: stdout.columns ?? termSize.cols
26602
+ });
26603
+ };
26604
+ stdout.on("resize", handleResize);
26605
+ return () => {
26606
+ stdout.off("resize", handleResize);
26607
+ };
26608
+ }, []);
26490
26609
  const bounds = useMemo(() => {
26491
26610
  const first = items.findIndex(isSelectable);
26492
26611
  let last = -1;
@@ -26569,6 +26688,29 @@ const promptImpl = createPrompt((config, done) => {
26569
26688
  });
26570
26689
  const message = theme.style.message(config.message, status$1);
26571
26690
  const preview = buildPreview(command$1, items.filter(isChecked).map((c) => c.value));
26691
+ const termRows = termSize.rows;
26692
+ const usableRows = Math.max(1, termRows);
26693
+ const termCols = Math.max(40, termSize.cols - 4);
26694
+ const activeDescriptionRaw = config.showActiveDescription && items[active]?.description ? items[active]?.description : void 0;
26695
+ const wrappedDescription = activeDescriptionRaw && activeDescriptionRaw.length > 0 ? wrap(activeDescriptionRaw, {
26696
+ width: termCols,
26697
+ cut: false,
26698
+ trim: true
26699
+ }) : void 0;
26700
+ const descriptionLineCount = wrappedDescription ? wrappedDescription.split("\n").length : 0;
26701
+ const wrappedPreview = preview && preview.length > 0 ? wrap(preview, {
26702
+ width: termCols,
26703
+ cut: false,
26704
+ trim: true
26705
+ }) : void 0;
26706
+ const previewLineCount = wrappedPreview ? wrappedPreview.split("\n").length : 0;
26707
+ const helpLinesReserved = instructions === false ? 0 : 1;
26708
+ const errorLinesReserved = errorMsg ? 1 : 0;
26709
+ const leadingLines = 0;
26710
+ const reservedLines = 2 + previewLineCount + descriptionLineCount + errorLinesReserved + helpLinesReserved;
26711
+ const maxPageSize = Math.max(1, usableRows - reservedLines - leadingLines);
26712
+ const basePageSize = pageSize ?? maxPageSize;
26713
+ const finalPageSize = Math.max(1, Math.min(basePageSize, maxPageSize));
26572
26714
  let description;
26573
26715
  const page = usePagination({
26574
26716
  items,
@@ -26579,12 +26721,12 @@ const promptImpl = createPrompt((config, done) => {
26579
26721
  const disabledLabel = typeof item.disabled === "string" ? item.disabled : "(disabled)";
26580
26722
  return theme.style.disabledChoice(`${item.name} ${disabledLabel}`);
26581
26723
  }
26582
- if (isActive && config.showActiveDescription) description = item.description;
26724
+ if (isActive && config.showActiveDescription) description = wrappedDescription ?? item.description;
26583
26725
  const checkbox = item.checked ? theme.icon.checked : theme.icon.unchecked;
26584
26726
  const name = item.checked ? item.checkedName : item.name;
26585
26727
  return (isActive ? theme.style.highlight : (x) => x)(`${isActive ? theme.icon.cursor : " "}${checkbox} ${name}`);
26586
26728
  },
26587
- pageSize,
26729
+ pageSize: finalPageSize,
26588
26730
  loop
26589
26731
  });
26590
26732
  if (status$1 === "done") {
@@ -26592,11 +26734,11 @@ const promptImpl = createPrompt((config, done) => {
26592
26734
  return [
26593
26735
  prefix,
26594
26736
  message,
26595
- theme.style.answer(theme.style.renderSelectedChoices(selection, items))
26737
+ theme.style.answer(theme.style.renderSelectedChoices(selection))
26596
26738
  ].filter(Boolean).join(" ");
26597
26739
  }
26598
26740
  let helpLine;
26599
- if (theme.helpMode !== "never" && instructions !== false) if (typeof instructions === "string") helpLine = instructions;
26741
+ if (instructions !== false) if (typeof instructions === "string") helpLine = instructions;
26600
26742
  else {
26601
26743
  const keys = [["↑↓", "navigate"], ["space", "select"]];
26602
26744
  if (shortcuts.all) keys.push([shortcuts.all, "all"]);
@@ -26604,15 +26746,31 @@ const promptImpl = createPrompt((config, done) => {
26604
26746
  keys.push(["⏎", "submit"]);
26605
26747
  helpLine = theme.style.keysHelpTip(keys);
26606
26748
  }
26607
- return [
26749
+ const renderedLines = [
26608
26750
  [prefix, message].filter(Boolean).join(" "),
26609
26751
  page,
26610
26752
  " ",
26611
- preview,
26753
+ wrappedPreview ?? preview,
26612
26754
  description ? theme.style.description(description) : "",
26613
26755
  errorMsg ? theme.style.error(errorMsg) : "",
26614
26756
  helpLine
26615
- ].filter(Boolean).join("\n").trimEnd();
26757
+ ].filter(Boolean).join("\n").replace(/\n+$/, "").split("\n");
26758
+ if (process.env.CCSKI_PROMPT_DEBUG === "1") console.error([
26759
+ "[prompt-debug]",
26760
+ `rows=${termRows}`,
26761
+ `usable=${usableRows}`,
26762
+ `leading=${leadingLines}`,
26763
+ `reserved=${reservedLines}`,
26764
+ `preview=${previewLineCount}`,
26765
+ `desc=${descriptionLineCount}`,
26766
+ `pageSize=${finalPageSize}`,
26767
+ `items=${items.length}`,
26768
+ `rendered=${renderedLines.length}`
26769
+ ].join(" "));
26770
+ renderedLines.unshift("");
26771
+ const padding = Math.max(0, usableRows - renderedLines.length);
26772
+ if (padding > 0) renderedLines.push(...Array(padding).fill(""));
26773
+ return renderedLines.join("\n");
26616
26774
  });
26617
26775
  function promptMultiSelect(options) {
26618
26776
  return promptImpl(options);
@@ -26651,11 +26809,16 @@ async function installCommand(argv) {
26651
26809
  if (argv.color) setColorEnabled(true);
26652
26810
  try {
26653
26811
  const targetRoot = argv.global ? join(process.env.HOME ?? "~", ".claude/skills") : join(process.cwd(), ".claude/skills");
26654
- const materialized = await materializeSource(argv.source);
26655
- const targets = resolveInstallTargets(materialized.base, argv.use ?? materialized.useHint);
26656
- if (targets.length === 0) throw new Error(`No skills found to install in ${materialized.base}`);
26812
+ const materialized = await materializeSource(argv.source, {
26813
+ ...argv.mode ? { mode: argv.mode } : {},
26814
+ ...argv.branch ? { branch: argv.branch } : {}
26815
+ });
26816
+ const explicitPath = argv.path ?? materialized.useHint;
26817
+ const sourceLabel = formatSourceLabel(argv.source, materialized.branch ?? argv.branch, explicitPath, materialized.repo);
26818
+ const targets = resolveInstallTargets(materialized.base, explicitPath, sourceLabel);
26819
+ if (targets.length === 0) throw new Error(`No skills found for ${sourceLabel}. Resolved directory: ${materialized.base}`);
26657
26820
  const force = argv.force === true || argv.override === true;
26658
- const selection = await selectSkills(targets, argv, argv.source);
26821
+ const selection = await selectSkills(targets, argv, sourceLabel);
26659
26822
  const installed = [];
26660
26823
  for (const entry of selection) installed.push(installSkillDir(entry.dir, targetRoot, force));
26661
26824
  console.log(success(`Installed ${installed.length} skill(s):`));
@@ -26670,99 +26833,92 @@ async function installCommand(argv) {
26670
26833
  process.exitCode = 1;
26671
26834
  }
26672
26835
  }
26673
- function parseGithubTree(url) {
26674
- const parts = url.pathname.split("/").filter(Boolean);
26675
- if (parts.length >= 4 && parts[2] === "tree") {
26676
- const [owner, repo, , ref, ...rest] = parts;
26677
- return {
26678
- repo: `https://github.com/${owner}/${repo}.git`,
26679
- ref,
26680
- subdir: rest.length ? rest.join("/") : void 0
26681
- };
26682
- }
26683
- return null;
26836
+ function formatSourceLabel(input, branch, path, repo) {
26837
+ const pieces = [repo ?? input];
26838
+ if (branch) pieces.push(`branch=${branch}`);
26839
+ if (path) pieces.push(`path=${path}`);
26840
+ return pieces.join(" ");
26684
26841
  }
26685
- function parseGithubBlob(url) {
26686
- const parts = url.pathname.split("/").filter(Boolean);
26687
- if (parts.length >= 5 && parts[2] === "blob") {
26688
- const [owner, repo, , ref, ...rest] = parts;
26689
- return {
26690
- repo: `https://github.com/${owner}/${repo}.git`,
26691
- ref,
26692
- path: rest.join("/")
26693
- };
26694
- }
26695
- return null;
26842
+ function defaultMode(source, explicit) {
26843
+ if (explicit) return explicit;
26844
+ if (source.endsWith(".git")) return "git";
26845
+ return source.startsWith("http://") || source.startsWith("https://") ? "git" : "file";
26696
26846
  }
26697
- async function materializeSource(source) {
26698
- if (source.startsWith("file://")) return { base: new URL(source).pathname };
26699
- if (source.startsWith("http://") || source.startsWith("https://") || source.endsWith(".git")) {
26700
- let repo = source;
26701
- let ref;
26702
- let subdir;
26703
- let useHint;
26704
- try {
26705
- const url = new URL(source);
26706
- const ghTree = parseGithubTree(url);
26707
- if (ghTree) {
26708
- repo = ghTree.repo;
26709
- ref = ghTree.ref;
26710
- subdir = ghTree.subdir;
26711
- } else {
26712
- const ghBlob = parseGithubBlob(url);
26713
- if (ghBlob) {
26714
- repo = ghBlob.repo;
26715
- ref = ghBlob.ref;
26716
- useHint = ghBlob.path;
26717
- }
26718
- }
26719
- } catch {}
26720
- const tmp = mkdtempSync(join(tmpdir(), "ccski-install-"));
26721
- const clone = [
26722
- "git",
26723
- "clone",
26724
- "--depth",
26725
- "1"
26726
- ];
26727
- if (ref) clone.push("--branch", ref);
26728
- clone.push(repo, tmp);
26729
- execSync(clone.join(" "), { stdio: "ignore" });
26847
+ async function materializeSource(source, options) {
26848
+ const mode = defaultMode(source, options.mode);
26849
+ if (mode === "file") {
26850
+ if (source.startsWith("http://") || source.startsWith("https://")) throw new Error("mode=file requires a local path; http(s) sources must use --mode git (default).");
26730
26851
  return {
26731
- base: subdir ? join(tmp, subdir) : tmp,
26732
- useHint
26852
+ base: normalizeSourcePath(source),
26853
+ label: formatSourceLabel(source, void 0, void 0),
26854
+ mode
26733
26855
  };
26734
26856
  }
26735
- return { base: normalizeSourcePath(source) };
26857
+ const parsed = parseGitUrl(source);
26858
+ const repo = parsed?.repo ?? source;
26859
+ const branch = options.branch ?? parsed?.branch;
26860
+ const tmp = mkdtempSync(join(tmpdir(), "ccski-install-"));
26861
+ const clone = [
26862
+ "git",
26863
+ "clone",
26864
+ "--depth",
26865
+ "1"
26866
+ ];
26867
+ if (branch) clone.push("--branch", branch);
26868
+ clone.push(repo, tmp);
26869
+ execSync(clone.join(" "), { stdio: "ignore" });
26870
+ const useHint = parsed?.type === "blob" ? parsed.path : void 0;
26871
+ const result = {
26872
+ base: parsed?.type === "tree" && parsed.path ? join(tmp, parsed.path) : tmp,
26873
+ label: formatSourceLabel(source, branch, useHint, repo),
26874
+ mode
26875
+ };
26876
+ if (useHint) result.useHint = useHint;
26877
+ if (branch) result.branch = branch;
26878
+ if (repo) result.repo = repo;
26879
+ return result;
26736
26880
  }
26737
- function resolveSkillPath(baseDir, rel) {
26881
+ function resolveSkillPath(baseDirs, rel) {
26738
26882
  const cleaned = rel.replace(/^\.\//, "");
26883
+ const bases = Array.isArray(baseDirs) ? baseDirs : [baseDirs];
26739
26884
  const candidates = [];
26740
- if (cleaned.endsWith("SKILL.md")) {
26741
- candidates.push(dirname(join(baseDir, cleaned)));
26742
- candidates.push(dirname(join(baseDir, "..", cleaned)));
26743
- } else {
26744
- candidates.push(join(baseDir, cleaned));
26745
- candidates.push(join(baseDir, "..", cleaned));
26885
+ for (const baseDir of bases) {
26886
+ const resolvedBase = resolve(baseDir);
26887
+ if (cleaned.endsWith("SKILL.md")) {
26888
+ candidates.push(dirname(join(resolvedBase, cleaned)));
26889
+ candidates.push(dirname(join(resolvedBase, "..", cleaned)));
26890
+ } else {
26891
+ candidates.push(join(resolvedBase, cleaned));
26892
+ candidates.push(join(resolvedBase, "..", cleaned));
26893
+ }
26746
26894
  }
26747
26895
  for (const dir of candidates) if (existsSync(join(dir, "SKILL.md"))) return dir;
26748
26896
  return null;
26749
26897
  }
26750
26898
  function marketplaceSkills(marketplacePath) {
26751
26899
  const data = JSON.parse(readFileSync(marketplacePath, "utf8"));
26752
- const dir = dirname(marketplacePath);
26900
+ const marketplaceDir = dirname(marketplacePath);
26901
+ const repoRoot = resolve(marketplaceDir, "..");
26753
26902
  const plugins = Array.isArray(data.plugins) ? data.plugins : [];
26754
26903
  const skillPaths = /* @__PURE__ */ new Set();
26755
26904
  for (const plugin of plugins) {
26756
26905
  if (!plugin || !Array.isArray(plugin.skills)) continue;
26906
+ const pluginSource = typeof plugin.source === "string" ? plugin.source : void 0;
26907
+ const baseCandidates = new Set([marketplaceDir, repoRoot]);
26908
+ if (pluginSource) {
26909
+ const cleanedSource = pluginSource.replace(/^\.\//, "");
26910
+ baseCandidates.add(resolve(marketplaceDir, cleanedSource));
26911
+ baseCandidates.add(resolve(repoRoot, cleanedSource));
26912
+ }
26757
26913
  for (const rel of plugin.skills) {
26758
26914
  if (typeof rel !== "string") continue;
26759
- const resolved = resolveSkillPath(dir, rel);
26915
+ const resolved = resolveSkillPath(Array.from(baseCandidates), rel);
26760
26916
  if (resolved) skillPaths.add(resolve(resolved));
26761
26917
  }
26762
26918
  }
26763
26919
  return Array.from(skillPaths);
26764
26920
  }
26765
- function resolveInstallTargets(root, usePath) {
26921
+ function resolveInstallTargets(root, usePath, label) {
26766
26922
  const base = resolve(root);
26767
26923
  const candidatePath = usePath ? resolve(base, usePath) : base;
26768
26924
  if (!usePath && base.toLowerCase().endsWith("skill.md") && existsSync(base)) return [dirname(base)];
@@ -26775,7 +26931,7 @@ function resolveInstallTargets(root, usePath) {
26775
26931
  if (existsSync(join(base, ".claude-plugin", "marketplace.json"))) return marketplaceSkills(join(base, ".claude-plugin", "marketplace.json"));
26776
26932
  if (existsSync(join(base, "SKILL.md"))) return [base];
26777
26933
  if (existsSync(join(base, "marketplace.json"))) return marketplaceSkills(join(base, "marketplace.json"));
26778
- throw new Error(`No SKILL.md or marketplace.json found in ${base}${usePath ? ` (use: ${usePath})` : ""}`);
26934
+ throw new Error(`No SKILL.md or marketplace.json found for ${label}${usePath ? ` (path: ${usePath})` : ""}. Resolved directory: ${base}`);
26779
26935
  }
26780
26936
  function buildSkillEntries(dirs) {
26781
26937
  return dirs.map((dir) => {
@@ -26790,12 +26946,14 @@ function buildSkillEntries(dirs) {
26790
26946
  async function promptSelectSkills(entries, sourceLabel) {
26791
26947
  const pickedNames = await promptMultiSelect({
26792
26948
  message: `Select skills to install from ${sourceLabel}`,
26793
- choices: entries.map((e) => ({
26794
- value: e.name,
26795
- label: formatChoiceLabel$1(e),
26796
- description: e.description,
26797
- checked: true
26798
- })),
26949
+ choices: entries.map((e) => {
26950
+ return {
26951
+ value: e.name,
26952
+ label: formatChoiceLabel$1(e),
26953
+ description: e.description,
26954
+ checked: true
26955
+ };
26956
+ }),
26799
26957
  defaultChecked: true,
26800
26958
  command: {
26801
26959
  base: "ccski install",
@@ -26850,13 +27008,15 @@ function formatSkillListing(entries, label) {
26850
27008
  }
26851
27009
  function formatChoiceLabel$1(entry) {
26852
27010
  const wrapWidth = Math.max(24, Math.min(process.stdout?.columns ?? 80, 120) - 6);
26853
- const description = entry.description ? "\n " + wrap(entry.description, {
27011
+ const descriptionText = entry.description ?? "";
27012
+ const wrapped = descriptionText ? wrap(descriptionText, {
26854
27013
  width: wrapWidth,
26855
27014
  indent: "",
26856
27015
  newline: "\n",
26857
27016
  trim: true,
26858
27017
  cut: false
26859
- }).replace(/\n/g, "\n ") : "";
27018
+ }) : "";
27019
+ const description = wrapped && wrapped.length > 0 ? "\n " + wrapped.replace(/\n/g, "\n ") : "";
26860
27020
  return `${tone.primary(entry.name)}${description}`;
26861
27021
  }
26862
27022
 
@@ -26988,23 +27148,30 @@ function enableSkill(skill, force) {
26988
27148
  renameSync(disabledFile, skillFile);
26989
27149
  }
26990
27150
  function toListItems(skills) {
26991
- return skills.map((skill) => ({
26992
- title: skill.name,
26993
- color: skill.disabled ? tone.danger : void 0,
26994
- badge: skill.disabled ? tone.danger("[disabled]") : void 0,
26995
- meta: skill.location === "plugin" ? skill.pluginInfo?.pluginName ?? dim(skill.location) : dim(skill.location),
26996
- description: skill.description
26997
- }));
27151
+ return skills.map((skill) => {
27152
+ const base = {
27153
+ title: skill.name,
27154
+ meta: skill.location === "plugin" ? skill.pluginInfo?.pluginName ?? dim(skill.location) : dim(skill.location),
27155
+ ...skill.description ? { description: skill.description } : {}
27156
+ };
27157
+ if (skill.disabled) return {
27158
+ ...base,
27159
+ color: tone.danger,
27160
+ badge: tone.danger("[disabled]")
27161
+ };
27162
+ return base;
27163
+ });
26998
27164
  }
26999
27165
  function formatChoiceLabel(skill) {
27000
27166
  const wrapWidth = Math.max(24, Math.min(process.stdout?.columns ?? 80, 120) - 6);
27001
- const description = skill.description ? "\n " + wrap(skill.description, {
27167
+ const wrapped = wrap(skill.description, {
27002
27168
  width: wrapWidth,
27003
27169
  indent: "",
27004
27170
  newline: "\n",
27005
27171
  trim: true,
27006
27172
  cut: false
27007
- }).replace(/\n/g, "\n ") : "";
27173
+ });
27174
+ const description = wrapped && wrapped.length > 0 ? "\n " + wrapped.replace(/\n/g, "\n ") : "";
27008
27175
  return `${tone.primary(skill.name)}${description}`;
27009
27176
  }
27010
27177
  function capitalize(value) {
@@ -27130,9 +27297,15 @@ const installModule = {
27130
27297
  type: "boolean",
27131
27298
  default: false,
27132
27299
  description: "Alias for --force"
27133
- }).option("use", {
27300
+ }).option("path", {
27134
27301
  type: "string",
27135
27302
  description: "Explicit SKILL.md or marketplace.json path inside source"
27303
+ }).option("mode", {
27304
+ choices: ["git", "file"],
27305
+ description: "Materialization mode (default: git for http/https sources, file otherwise)"
27306
+ }).option("branch", {
27307
+ type: "string",
27308
+ description: "Branch to checkout when using git mode"
27136
27309
  }).option("interactive", {
27137
27310
  alias: "i",
27138
27311
  type: "boolean",