skilld 1.7.4 → 2.0.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.
Files changed (156) hide show
  1. package/dist/_chunks/add.mjs +66 -0
  2. package/dist/_chunks/add.mjs.map +1 -0
  3. package/dist/_chunks/agent-prompt.mjs +88 -0
  4. package/dist/_chunks/agent-prompt.mjs.map +1 -0
  5. package/dist/_chunks/agent.mjs +81 -57
  6. package/dist/_chunks/agent.mjs.map +1 -1
  7. package/dist/_chunks/args.mjs +42 -0
  8. package/dist/_chunks/args.mjs.map +1 -0
  9. package/dist/_chunks/assemble.mjs +10 -7
  10. package/dist/_chunks/assemble.mjs.map +1 -1
  11. package/dist/_chunks/author.mjs +33 -17
  12. package/dist/_chunks/author.mjs.map +1 -1
  13. package/dist/_chunks/cache.mjs +143 -183
  14. package/dist/_chunks/cache.mjs.map +1 -1
  15. package/dist/_chunks/cache2.mjs +7 -6
  16. package/dist/_chunks/cache2.mjs.map +1 -1
  17. package/dist/_chunks/client.mjs +117 -0
  18. package/dist/_chunks/client.mjs.map +1 -0
  19. package/dist/_chunks/core.mjs +5 -5
  20. package/dist/_chunks/detect.mjs +53 -43
  21. package/dist/_chunks/detect.mjs.map +1 -1
  22. package/dist/_chunks/eject.mjs +69 -0
  23. package/dist/_chunks/eject.mjs.map +1 -0
  24. package/dist/_chunks/embedding-cache2.mjs +1 -1
  25. package/dist/_chunks/env.mjs +19 -0
  26. package/dist/_chunks/env.mjs.map +1 -0
  27. package/dist/_chunks/install-many.mjs +376 -0
  28. package/dist/_chunks/install-many.mjs.map +1 -0
  29. package/dist/_chunks/install.mjs +81 -326
  30. package/dist/_chunks/install.mjs.map +1 -1
  31. package/dist/_chunks/intro.mjs +63 -0
  32. package/dist/_chunks/intro.mjs.map +1 -0
  33. package/dist/_chunks/list.mjs +2 -2
  34. package/dist/_chunks/list.mjs.map +1 -1
  35. package/dist/_chunks/lockfile.mjs +3 -2
  36. package/dist/_chunks/lockfile.mjs.map +1 -1
  37. package/dist/_chunks/login.mjs +233 -0
  38. package/dist/_chunks/login.mjs.map +1 -0
  39. package/dist/_chunks/logout.mjs +27 -0
  40. package/dist/_chunks/logout.mjs.map +1 -0
  41. package/dist/_chunks/map.mjs +11 -0
  42. package/dist/_chunks/map.mjs.map +1 -0
  43. package/dist/_chunks/markdown.mjs +79 -54
  44. package/dist/_chunks/markdown.mjs.map +1 -1
  45. package/dist/_chunks/menu.mjs +33 -0
  46. package/dist/_chunks/menu.mjs.map +1 -0
  47. package/dist/_chunks/model-picker.mjs +61 -0
  48. package/dist/_chunks/model-picker.mjs.map +1 -0
  49. package/dist/_chunks/monorepo.mjs +4 -2
  50. package/dist/_chunks/monorepo.mjs.map +1 -1
  51. package/dist/_chunks/package-json.mjs.map +1 -1
  52. package/dist/_chunks/paths.mjs +3 -5
  53. package/dist/_chunks/paths.mjs.map +1 -1
  54. package/dist/_chunks/{sync-pipeline.mjs → pipeline.mjs} +346 -313
  55. package/dist/_chunks/pipeline.mjs.map +1 -0
  56. package/dist/_chunks/pool2.mjs +1 -1
  57. package/dist/_chunks/portable.mjs +151 -0
  58. package/dist/_chunks/portable.mjs.map +1 -0
  59. package/dist/_chunks/prepare-hook.mjs +2 -0
  60. package/dist/_chunks/prepare-hook2.mjs +61 -0
  61. package/dist/_chunks/prepare-hook2.mjs.map +1 -0
  62. package/dist/_chunks/prepare.mjs +47 -3
  63. package/dist/_chunks/prepare.mjs.map +1 -1
  64. package/dist/_chunks/prepare2.mjs +7 -6
  65. package/dist/_chunks/prepare2.mjs.map +1 -1
  66. package/dist/_chunks/prompts.mjs +484 -74
  67. package/dist/_chunks/prompts.mjs.map +1 -1
  68. package/dist/_chunks/pull.mjs +219 -0
  69. package/dist/_chunks/pull.mjs.map +1 -0
  70. package/dist/_chunks/regex.mjs +19 -0
  71. package/dist/_chunks/regex.mjs.map +1 -0
  72. package/dist/_chunks/retriv.mjs +2 -171
  73. package/dist/_chunks/retriv2.mjs +159 -0
  74. package/dist/_chunks/retriv2.mjs.map +1 -0
  75. package/dist/_chunks/sanitize.mjs +12 -9
  76. package/dist/_chunks/sanitize.mjs.map +1 -1
  77. package/dist/_chunks/search-helpers.mjs +8 -6
  78. package/dist/_chunks/search-helpers.mjs.map +1 -1
  79. package/dist/_chunks/search-interactive.mjs +23 -20
  80. package/dist/_chunks/search-interactive.mjs.map +1 -1
  81. package/dist/_chunks/search.mjs +3 -3
  82. package/dist/_chunks/search.mjs.map +1 -1
  83. package/dist/_chunks/semver.mjs +2755 -1
  84. package/dist/_chunks/semver.mjs.map +1 -1
  85. package/dist/_chunks/skill-installer2.mjs +10 -11
  86. package/dist/_chunks/skill-installer2.mjs.map +1 -1
  87. package/dist/_chunks/skills.mjs +6 -7
  88. package/dist/_chunks/skills.mjs.map +1 -1
  89. package/dist/_chunks/store.mjs +107 -0
  90. package/dist/_chunks/store.mjs.map +1 -0
  91. package/dist/_chunks/sync.mjs +411 -910
  92. package/dist/_chunks/sync.mjs.map +1 -1
  93. package/dist/_chunks/sync2.mjs +2 -5
  94. package/dist/_chunks/telemetry.mjs +26 -0
  95. package/dist/_chunks/telemetry.mjs.map +1 -0
  96. package/dist/_chunks/uninstall.mjs +12 -9
  97. package/dist/_chunks/uninstall.mjs.map +1 -1
  98. package/dist/_chunks/update.mjs +171 -0
  99. package/dist/_chunks/update.mjs.map +1 -0
  100. package/dist/_chunks/upload.mjs +3 -3
  101. package/dist/_chunks/validate.mjs +1 -1
  102. package/dist/_chunks/version.mjs +16 -17
  103. package/dist/_chunks/version.mjs.map +1 -1
  104. package/dist/_chunks/whoami.mjs +21 -0
  105. package/dist/_chunks/whoami.mjs.map +1 -0
  106. package/dist/_chunks/wizard.mjs +2 -190
  107. package/dist/_chunks/wizard2.mjs +200 -0
  108. package/dist/_chunks/wizard2.mjs.map +1 -0
  109. package/dist/cli.mjs +72 -53
  110. package/dist/cli.mjs.map +1 -1
  111. package/dist/prepare.mjs +4 -3
  112. package/dist/prepare.mjs.map +1 -1
  113. package/dist/retriv/worker.d.mts +5 -1
  114. package/dist/retriv/worker.d.mts.map +1 -1
  115. package/dist/retriv/worker.mjs +1 -1
  116. package/package.json +19 -28
  117. package/dist/_chunks/author-group.mjs +0 -17
  118. package/dist/_chunks/author-group.mjs.map +0 -1
  119. package/dist/_chunks/cli-helpers.mjs +0 -335
  120. package/dist/_chunks/cli-helpers.mjs.map +0 -1
  121. package/dist/_chunks/cli-helpers2.mjs +0 -2
  122. package/dist/_chunks/index.d.mts +0 -344
  123. package/dist/_chunks/index.d.mts.map +0 -1
  124. package/dist/_chunks/index2.d.mts +0 -279
  125. package/dist/_chunks/index2.d.mts.map +0 -1
  126. package/dist/_chunks/index3.d.mts +0 -44
  127. package/dist/_chunks/index3.d.mts.map +0 -1
  128. package/dist/_chunks/index4.d.mts +0 -553
  129. package/dist/_chunks/index4.d.mts.map +0 -1
  130. package/dist/_chunks/package-registry.mjs +0 -465
  131. package/dist/_chunks/package-registry.mjs.map +0 -1
  132. package/dist/_chunks/retriv.mjs.map +0 -1
  133. package/dist/_chunks/setup.mjs +0 -17
  134. package/dist/_chunks/setup.mjs.map +0 -1
  135. package/dist/_chunks/sources.mjs +0 -2654
  136. package/dist/_chunks/sources.mjs.map +0 -1
  137. package/dist/_chunks/sync-pipeline.mjs.map +0 -1
  138. package/dist/_chunks/sync-registry.mjs +0 -65
  139. package/dist/_chunks/sync-registry.mjs.map +0 -1
  140. package/dist/_chunks/types.d.mts +0 -76
  141. package/dist/_chunks/types.d.mts.map +0 -1
  142. package/dist/_chunks/types2.d.mts +0 -88
  143. package/dist/_chunks/types2.d.mts.map +0 -1
  144. package/dist/_chunks/wizard.mjs.map +0 -1
  145. package/dist/agent/index.d.mts +0 -2
  146. package/dist/agent/index.mjs +0 -4
  147. package/dist/cache/index.d.mts +0 -2
  148. package/dist/cache/index.mjs +0 -5
  149. package/dist/index.d.mts +0 -6
  150. package/dist/index.mjs +0 -6
  151. package/dist/retriv/index.d.mts +0 -3
  152. package/dist/retriv/index.mjs +0 -2
  153. package/dist/sources/index.d.mts +0 -3
  154. package/dist/sources/index.mjs +0 -3
  155. package/dist/types.d.mts +0 -4
  156. package/dist/types.mjs +0 -1
@@ -0,0 +1,66 @@
1
+ import { n as COMMA_OR_WHITESPACE_RE } from "./regex.mjs";
2
+ import { l as hasCompletedWizard } from "./cache.mjs";
3
+ import { t as autoResolveAgent } from "./agent-prompt.mjs";
4
+ import { t as sharedArgs } from "./args.mjs";
5
+ import { s as parseSkillInput } from "./semver.mjs";
6
+ import { t as runWizard } from "./wizard2.mjs";
7
+ import { t as installSkills } from "./install-many.mjs";
8
+ import { t as exportPortablePrompts } from "./portable.mjs";
9
+ import * as p from "@clack/prompts";
10
+ import { defineCommand } from "citty";
11
+ const addCommandDef = defineCommand({
12
+ meta: {
13
+ name: "add",
14
+ description: "Install skills (npm:<pkg>, crate:<name>, gh:<owner/repo>, @<curator>)"
15
+ },
16
+ args: {
17
+ "package": {
18
+ type: "positional",
19
+ description: "Package(s) to sync (space/comma-separated; npm:<pkg>, crate:<name>, or owner/repo)",
20
+ required: true
21
+ },
22
+ "skill": {
23
+ type: "string",
24
+ alias: "s",
25
+ description: "Select specific skills from a git repo (comma-separated)",
26
+ valueHint: "name"
27
+ },
28
+ "allow-unsafe": {
29
+ type: "boolean",
30
+ description: "Install skills that fail the upstream audit gate"
31
+ },
32
+ ...sharedArgs
33
+ },
34
+ async run({ args }) {
35
+ const rawInputs = [...new Set([args.package, ...args._ || []].map((s) => s.trim()).filter(Boolean))];
36
+ if (args.agent === "none") {
37
+ const packages = [...new Set(rawInputs.flatMap((s) => s.split(COMMA_OR_WHITESPACE_RE)).map((s) => s.trim()).filter(Boolean))];
38
+ for (const pkg of packages) await exportPortablePrompts(pkg, {
39
+ force: args.force,
40
+ agent: "none"
41
+ });
42
+ return;
43
+ }
44
+ const agent = autoResolveAgent(args.agent);
45
+ if (!agent) {
46
+ p.log.error("No target agent detected.\n Pass --agent <name> (claude-code, cursor, codex, …) or run `skilld config` to set a default.\n Use --agent none for portable export.");
47
+ process.exitCode = 1;
48
+ return;
49
+ }
50
+ if (!hasCompletedWizard()) await runWizard({ agent });
51
+ await installSkills(rawInputs.map(parseSkillInput), {
52
+ agent,
53
+ surface: "cli:add",
54
+ global: args.global,
55
+ yes: args.yes,
56
+ force: args.force,
57
+ debug: args.debug,
58
+ model: args.model,
59
+ skillFilter: args.skill,
60
+ allowUnsafe: args["allow-unsafe"]
61
+ });
62
+ }
63
+ });
64
+ export { addCommandDef };
65
+
66
+ //# sourceMappingURL=add.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"add.mjs","names":[],"sources":["../../src/commands/sync/add.ts"],"sourcesContent":["import type { AgentType, OptimizeModel } from '../../agent/index.ts'\nimport * as p from '@clack/prompts'\nimport { defineCommand } from 'citty'\nimport { autoResolveAgent } from '../../cli/agent-prompt.ts'\nimport { sharedArgs } from '../../cli/args.ts'\nimport { hasCompletedWizard } from '../../core/config.ts'\nimport { parseSkillInput } from '../../core/prefix.ts'\nimport { COMMA_OR_WHITESPACE_RE } from '../../core/regex.ts'\nimport { runWizard } from '../wizard.ts'\nimport { installSkills } from './install-many.ts'\nimport { exportPortablePrompts } from './portable.ts'\n\nexport const addCommandDef = defineCommand({\n meta: { name: 'add', description: 'Install skills (npm:<pkg>, crate:<name>, gh:<owner/repo>, @<curator>)' },\n args: {\n 'package': {\n type: 'positional',\n description: 'Package(s) to sync (space/comma-separated; npm:<pkg>, crate:<name>, or owner/repo)',\n required: true,\n },\n 'skill': {\n type: 'string',\n alias: 's',\n description: 'Select specific skills from a git repo (comma-separated)',\n valueHint: 'name',\n },\n 'allow-unsafe': {\n type: 'boolean',\n description: 'Install skills that fail the upstream audit gate',\n },\n ...sharedArgs,\n },\n async run({ args }) {\n const rawInputs = [...new Set(\n [args.package, ...((args as any)._ || [])]\n .map((s: string) => s.trim())\n .filter(Boolean),\n )]\n\n // --agent none → portable export (no installed-agent target needed).\n if (args.agent === 'none') {\n const packages = [...new Set(rawInputs.flatMap(s => s.split(COMMA_OR_WHITESPACE_RE)).map(s => s.trim()).filter(Boolean))]\n for (const pkg of packages)\n await exportPortablePrompts(pkg, { force: args.force, agent: 'none' })\n return\n }\n\n const agent: AgentType | null = autoResolveAgent(args.agent)\n if (!agent) {\n p.log.error('No target agent detected.\\n Pass --agent <name> (claude-code, cursor, codex, …) or run `skilld config` to set a default.\\n Use --agent none for portable export.')\n process.exitCode = 1\n return\n }\n\n if (!hasCompletedWizard())\n await runWizard({ agent })\n\n const items = rawInputs.map(parseSkillInput)\n await installSkills(items, {\n agent,\n surface: 'cli:add',\n global: args.global,\n yes: args.yes,\n force: args.force,\n debug: args.debug,\n model: args.model as OptimizeModel | undefined,\n skillFilter: args.skill,\n allowUnsafe: args['allow-unsafe'],\n })\n },\n})\n"],"mappings":";;;;;;;;;;AAYA,MAAa,gBAAgB,cAAc;CACzC,MAAM;EAAE,MAAM;EAAO,aAAa;EAAyE;CAC3G,MAAM;EACJ,WAAW;GACT,MAAM;GACN,aAAa;GACb,UAAU;GACX;EACD,SAAS;GACP,MAAM;GACN,OAAO;GACP,aAAa;GACb,WAAW;GACZ;EACD,gBAAgB;GACd,MAAM;GACN,aAAa;GACd;EACD,GAAG;EACJ;CACD,MAAM,IAAI,EAAE,QAAQ;EAClB,MAAM,YAAY,CAAC,GAAG,IAAI,IACxB,CAAC,KAAK,SAAS,GAAK,KAAa,KAAK,EAAE,CAAE,CACvC,KAAK,MAAc,EAAE,MAAM,CAAC,CAC5B,OAAO,QAAQ,CACnB,CAAC;EAGF,IAAI,KAAK,UAAU,QAAQ;GACzB,MAAM,WAAW,CAAC,GAAG,IAAI,IAAI,UAAU,SAAQ,MAAK,EAAE,MAAM,uBAAuB,CAAC,CAAC,KAAI,MAAK,EAAE,MAAM,CAAC,CAAC,OAAO,QAAQ,CAAC,CAAC;GACzH,KAAK,MAAM,OAAO,UAChB,MAAM,sBAAsB,KAAK;IAAE,OAAO,KAAK;IAAO,OAAO;IAAQ,CAAC;GACxE;;EAGF,MAAM,QAA0B,iBAAiB,KAAK,MAAM;EAC5D,IAAI,CAAC,OAAO;GACV,EAAE,IAAI,MAAM,qKAAqK;GACjL,QAAQ,WAAW;GACnB;;EAGF,IAAI,CAAC,oBAAoB,EACvB,MAAM,UAAU,EAAE,OAAO,CAAC;EAG5B,MAAM,cADQ,UAAU,IAAI,gBACH,EAAE;GACzB;GACA,SAAS;GACT,QAAQ,KAAK;GACb,KAAK,KAAK;GACV,OAAO,KAAK;GACZ,OAAO,KAAK;GACZ,OAAO,KAAK;GACZ,aAAa,KAAK;GAClB,aAAa,KAAK;GACnB,CAAC;;CAEL,CAAC"}
@@ -0,0 +1,88 @@
1
+ import { a as targets, n as detectProjectAgents, r as detectTargetAgent, t as detectInstalledAgents } from "./detect.mjs";
2
+ import "./agent.mjs";
3
+ import { d as readConfig, m as updateConfig } from "./cache.mjs";
4
+ import { t as isInteractive } from "./env.mjs";
5
+ import { styleText } from "node:util";
6
+ import * as p from "@clack/prompts";
7
+ function resolveAgent(agentFlag) {
8
+ if (process.env.SKILLD_NO_AGENT) return null;
9
+ return agentFlag ?? detectTargetAgent() ?? readConfig().agent ?? null;
10
+ }
11
+ function autoResolveAgent(agentFlag) {
12
+ const resolved = resolveAgent(agentFlag);
13
+ if (resolved && resolved !== "none") return resolved;
14
+ if (process.env.SKILLD_NO_AGENT) return null;
15
+ const projectMatches = detectProjectAgents();
16
+ if (projectMatches.length === 1) return projectMatches[0];
17
+ const installed = detectInstalledAgents();
18
+ if (installed.length === 1) return installed[0];
19
+ return null;
20
+ }
21
+ let _warnedNoAgent = false;
22
+ function warnNoAgent() {
23
+ if (_warnedNoAgent) return;
24
+ _warnedNoAgent = true;
25
+ p.log.warn("No target agent detected — falling back to prompt-only mode.\n Use --agent <name> to specify, or run `skilld config` to set a default.");
26
+ }
27
+ async function promptForAgent() {
28
+ const noAgent = !!process.env.SKILLD_NO_AGENT;
29
+ const installed = noAgent ? [] : detectInstalledAgents();
30
+ const projectMatches = noAgent ? [] : detectProjectAgents();
31
+ if (!isInteractive()) {
32
+ if (installed.length === 1) {
33
+ updateConfig({ agent: installed[0] });
34
+ return installed[0];
35
+ }
36
+ warnNoAgent();
37
+ return "none";
38
+ }
39
+ p.log.info("Skilld generates reference cards from package docs so your AI agent\n always has accurate APIs for your exact dependency versions.");
40
+ const candidateIds = projectMatches.length > 0 ? projectMatches : installed.length > 0 ? installed : Object.keys(targets);
41
+ const sharedAgents = new Set(Object.entries(targets).filter(([, a]) => a.additionalSkillsDirs.some((d) => d.includes(".claude/skills"))).map(([id]) => id));
42
+ const sharedIds = candidateIds.filter((id) => id === "claude-code" || sharedAgents.has(id));
43
+ const isolatedIds = candidateIds.filter((id) => id !== "claude-code" && !sharedAgents.has(id));
44
+ const options = [];
45
+ if (sharedIds.length > 0 && isolatedIds.length > 0) for (const id of sharedIds) {
46
+ const a = targets[id];
47
+ const hint = id === "claude-code" ? `skills shared with ${sharedIds.length - 1} other agents` : `skills shared with Claude Code and others`;
48
+ options.push({
49
+ label: a.displayName,
50
+ value: id,
51
+ hint
52
+ });
53
+ }
54
+ const isolatedAgentIds = new Set(Object.entries(targets).filter(([, a]) => a.additionalSkillsDirs.length === 0).map(([id]) => id));
55
+ for (const id of sharedIds.length > 0 && isolatedIds.length > 0 ? isolatedIds : candidateIds) {
56
+ if (options.some((o) => o.value === id)) continue;
57
+ const a = targets[id];
58
+ const hint = sharedAgents.has(id) && id !== "claude-code" ? "skills shared with Claude Code and others" : isolatedAgentIds.has(id) ? "skills only visible to this agent" : void 0;
59
+ options.push({
60
+ label: a.displayName,
61
+ value: id,
62
+ hint
63
+ });
64
+ }
65
+ options.push({
66
+ label: "No agent",
67
+ value: "none",
68
+ hint: "export as standalone files for any AI"
69
+ });
70
+ if (!_warnedNoAgent) {
71
+ _warnedNoAgent = true;
72
+ const hint = projectMatches.length > 1 ? `Multiple agent directories found: ${projectMatches.map((t) => targets[t].displayName).join(", ")}` : installed.length > 0 ? `Found ${installed.map((t) => targets[t].displayName).join(", ")} but couldn't determine which to use` : "No agents auto-detected";
73
+ const crossNote = sharedIds.length > 1 ? `\n ${styleText("gray", `Tip: Picking Claude Code shares skills with ${sharedIds.filter((id) => id !== "claude-code").map((id) => targets[id].displayName).join(", ")} automatically.`)}` : "";
74
+ p.log.warn(`${hint}\n Pick the agent you actively code with.${crossNote}`);
75
+ }
76
+ const choice = await p.select({
77
+ message: "Which AI coding agent do you use?",
78
+ options
79
+ });
80
+ if (p.isCancel(choice)) return null;
81
+ if (choice === "none") return "none";
82
+ updateConfig({ agent: choice });
83
+ p.log.success(`Target agent set to ${targets[choice].displayName}`);
84
+ return choice;
85
+ }
86
+ export { promptForAgent as n, resolveAgent as r, autoResolveAgent as t };
87
+
88
+ //# sourceMappingURL=agent-prompt.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"agent-prompt.mjs","names":["agents"],"sources":["../../src/cli/agent-prompt.ts"],"sourcesContent":["import type { AgentType } from '../agent/index.ts'\nimport { styleText } from 'node:util'\nimport * as p from '@clack/prompts'\nimport { agents, detectInstalledAgents, detectProjectAgents, detectTargetAgent } from '../agent/index.ts'\nimport { readConfig, updateConfig } from '../core/config.ts'\nimport { isInteractive } from './env.ts'\n\nexport function resolveAgent(agentFlag?: string): AgentType | 'none' | null {\n if (process.env.SKILLD_NO_AGENT)\n return null\n return (agentFlag as AgentType | undefined)\n ?? detectTargetAgent()\n ?? (readConfig().agent as AgentType | undefined)\n ?? null\n}\n\n/**\n * Auto-resolve target agent without prompting. Consults, in order:\n * 1. Explicit `--agent` flag.\n * 2. Env-detected target (`CLAUDE_CODE`, `CURSOR_SESSION`, etc).\n * 3. Saved config default.\n * 4. Project marker dirs (`.claude/skills`, `.cursor/`, …) when exactly one\n * agent matches the cwd.\n * 5. Installed agents on the machine when exactly one is found.\n *\n * Returns `null` when nothing is determined. Callers should error with a clear\n * \"pass --agent <name>\" hint rather than prompting — keeps commands\n * scriptable.\n */\nexport function autoResolveAgent(agentFlag?: string): AgentType | null {\n const resolved = resolveAgent(agentFlag)\n if (resolved && resolved !== 'none')\n return resolved\n\n if (process.env.SKILLD_NO_AGENT)\n return null\n\n const projectMatches = detectProjectAgents()\n if (projectMatches.length === 1)\n return projectMatches[0]!\n\n const installed = detectInstalledAgents()\n if (installed.length === 1)\n return installed[0]!\n\n return null\n}\n\nexport function listKnownAgents(): AgentType[] {\n return Object.keys(agents) as AgentType[]\n}\n\nlet _warnedNoAgent = false\nfunction warnNoAgent(): void {\n if (_warnedNoAgent)\n return\n _warnedNoAgent = true\n p.log.warn('No target agent detected — falling back to prompt-only mode.\\n Use --agent <name> to specify, or run `skilld config` to set a default.')\n}\n\nexport async function promptForAgent(): Promise<AgentType | 'none' | null> {\n const noAgent = !!process.env.SKILLD_NO_AGENT\n const installed = noAgent ? [] : detectInstalledAgents()\n const projectMatches = noAgent ? [] : detectProjectAgents()\n\n if (!isInteractive()) {\n if (installed.length === 1) {\n updateConfig({ agent: installed[0] })\n return installed[0]!\n }\n warnNoAgent()\n return 'none'\n }\n\n p.log.info(\n `Skilld generates reference cards from package docs so your AI agent\\n`\n + ` always has accurate APIs for your exact dependency versions.`,\n )\n\n const candidateIds = projectMatches.length > 0\n ? projectMatches\n : installed.length > 0\n ? installed\n : Object.keys(agents) as AgentType[]\n\n const sharedAgents = new Set(\n Object.entries(agents)\n .filter(([, a]) => a.additionalSkillsDirs.some(d => d.includes('.claude/skills')))\n .map(([id]) => id),\n )\n\n const sharedIds = candidateIds.filter(id => id === 'claude-code' || sharedAgents.has(id))\n const isolatedIds = candidateIds.filter(id => id !== 'claude-code' && !sharedAgents.has(id))\n\n const options: Array<{ label: string, value: AgentType | 'none', hint?: string }> = []\n\n if (sharedIds.length > 0 && isolatedIds.length > 0) {\n for (const id of sharedIds) {\n const a = agents[id]\n const hint = id === 'claude-code'\n ? `skills shared with ${sharedIds.length - 1} other agents`\n : `skills shared with Claude Code and others`\n options.push({ label: a.displayName, value: id as AgentType, hint })\n }\n }\n\n const isolatedAgentIds = new Set(\n Object.entries(agents)\n .filter(([, a]) => a.additionalSkillsDirs.length === 0)\n .map(([id]) => id),\n )\n\n for (const id of (sharedIds.length > 0 && isolatedIds.length > 0 ? isolatedIds : candidateIds)) {\n if (options.some(o => o.value === id))\n continue\n const a = agents[id]\n const hint = sharedAgents.has(id) && id !== 'claude-code'\n ? 'skills shared with Claude Code and others'\n : isolatedAgentIds.has(id)\n ? 'skills only visible to this agent'\n : undefined\n options.push({ label: a.displayName, value: id as AgentType, hint })\n }\n\n options.push({ label: 'No agent', value: 'none', hint: 'export as standalone files for any AI' })\n\n if (!_warnedNoAgent) {\n _warnedNoAgent = true\n const hint = projectMatches.length > 1\n ? `Multiple agent directories found: ${projectMatches.map(t => agents[t].displayName).join(', ')}`\n : installed.length > 0\n ? `Found ${installed.map(t => agents[t].displayName).join(', ')} but couldn't determine which to use`\n : 'No agents auto-detected'\n const crossNote = sharedIds.length > 1\n ? `\\n ${styleText('gray', `Tip: Picking Claude Code shares skills with ${sharedIds.filter(id => id !== 'claude-code').map(id => agents[id].displayName).join(', ')} automatically.`)}`\n : ''\n p.log.warn(`${hint}\\n Pick the agent you actively code with.${crossNote}`)\n }\n\n const choice = await p.select({\n message: 'Which AI coding agent do you use?',\n options,\n })\n\n if (p.isCancel(choice))\n return null\n\n if (choice === 'none')\n return 'none'\n\n updateConfig({ agent: choice })\n p.log.success(`Target agent set to ${agents[choice].displayName}`)\n return choice\n}\n"],"mappings":";;;;;;AAOA,SAAgB,aAAa,WAA+C;CAC1E,IAAI,QAAQ,IAAI,iBACd,OAAO;CACT,OAAQ,aACH,mBAAmB,IAClB,YAAY,CAAC,SACd;;;;;;;;;;;;;;CAgBP,IAAA,gBAAgB;CACd,iBAAiB;CACjB,EAAA,IAAI,KAAA,0IACK;;eAKH,iBAAiB;CACvB,MAAI,UAAA,CAAA,CAAA,QAAe,IAAW;CAG9B,MAAM,YAAY,UAAA,EAAA,GAAA,uBAAuB;CACzC,MAAI,iBAAU,UACZ,EAAO,GAAA,qBAAU;CAEnB,IAAA,CAAA,eAAO,EAAA;;GAOT,aAAI,EAAA,OAAiB,UAAA,IAAA,CAAA;GACrB,OAAS,UAAA;;EAGP,aAAA;EACA,OAAM;;CAGR,EAAA,IAAA,KAAA,sIAA2E;CACzE,MAAM,eAAY,eAAY,SAAA,IAAA,iBAAA,UAAA,SAAA,IAAA,YAAA,OAAA,KAAA,QAAA;CAC9B,MAAM,eAAY,IAAA,IAAU,OAAK,QAAA,QAAA,CAAA,QAAuB,GAAA,OAAA,EAAA,qBAAA,MAAA,MAAA,EAAA,SAAA,iBAAA,CAAA,CAAA,CAAA,KAAA,CAAA,QAAA,GAAA,CAAA;CACxD,MAAM,YAAA,aAAiB,QAAe,OAAA,OAAA,iBAAqB,aAAA,IAAA,GAAA,CAAA;CAE3D,MAAK,cAAe,aAAE,QAAA,OAAA,OAAA,iBAAA,CAAA,aAAA,IAAA,GAAA,CAAA;OAChB,UAAU,EAAA;KACZ,UAAA,SAAe,KAAO,YAAe,SAAA,GAAA,KAAA,MAAA,MAAA,WAAA;QACrC,IAAO,QAAU;;EAEnB,QAAA,KAAa;GACb,OAAO,EAAA;;GAGP;GAKF,CAAA;;CAYA,MAAM,mBAAY,IAAA,IAAa,OAAO,QAAM,QAAO,CAAA,QAAA,GAAA,OAAiB,EAAA,qBAAqB,WAAA,EAAA,CAAA,KAAA,CAAA,QAAA,GAAA,CAAA;CACzF,KAAA,MAAM,MAAA,UAAc,SAAa,KAAO,YAAM,SAAO,IAAA,cAAkB,cAAqB;EAE5F,IAAA,QAAM,MAAgF,MAAA,EAAA,UAAA,GAAA,EAAA;EAEtF,MAAI,IAAA,QAAU;EAEV,MAAM,OAAIA,aAAO,IAAA,GAAA,IAAA,OAAA,gBAAA,8CAAA,iBAAA,IAAA,GAAA,GAAA,sCAAA,KAAA;EACjB,QAAM,KAAO;GAGb,OAAQ,EAAA;GAAO,OAAO;GAAe;GAAwB,CAAA;;;EAIjE,OAAM;EAMN,OAAK;EACH,MAAI;EAEJ,CAAA;KACA,CAAA,gBAAa;EAKb,iBAAa;QAAE,OAAS,eAAA,SAAA,IAAA,qCAAA,eAAA,KAAA,MAAA,QAAA,GAAA,YAAA,CAAA,KAAA,KAAA,KAAA,UAAA,SAAA,IAAA,SAAA,UAAA,KAAA,MAAA,QAAA,GAAA,YAAA,CAAA,KAAA,KAAA,CAAA,wCAAA;QAAa,YAAO,UAAA,SAAA,IAAA,OAAA,UAAA,QAAA,+CAAA,UAAA,QAAA,OAAA,OAAA,cAAA,CAAA,KAAA,OAAA,QAAA,IAAA,YAAA,CAAA,KAAA,KAAA,CAAA,iBAAA,KAAA;IAAiB,IAAA,KAAA,GAAA,KAAA,4CAAA,YAAA;;;EAG/D,SAAQ;EAAO;EAAmB,CAAA;KAAe,EAAA,SAAM,OAAA,EAAA,OAAA;KAA0C,WAAA,QAAA,OAAA;CAEjG,aAAK,EAAA,OAAgB,QAAA,CAAA;GACnB,IAAA,QAAA,uBAAiB,QAAA,QAAA,cAAA;QACX"}
@@ -1,28 +1,30 @@
1
- import { a as PI_AI_AUTH_PATH, h as skillLogDir, p as skillInternalDir, r as LLM_CACHE_DIR, t as CACHE_DIR } from "./paths.mjs";
2
- import { E as getSkillReferenceDirs, t as createReferenceCache } from "./cache.mjs";
3
- import { n as sanitizeMarkdown } from "./sanitize.mjs";
4
1
  import { a as targets, t as detectInstalledAgents } from "./detect.mjs";
5
- import { E as SECTION_OUTPUT_FILES, S as getSectionValidator, T as SECTION_MERGE_ORDER, k as resolveSkilldCommand, w as wrapSection, y as buildAllSectionPrompts } from "./prompts.mjs";
2
+ import { A as resolveSkilldCommand, C as SECTION_OUTPUT_FILES, S as SECTION_MERGE_ORDER, _ as buildAllSectionPrompts, x as wrapSection, y as getSectionValidator } from "./prompts.mjs";
3
+ import { g as skillLogDir, i as LLM_CACHE_DIR, m as skillInternalDir, n as CACHE_DIR, o as PI_AI_AUTH_PATH } from "./paths.mjs";
4
+ import { d as SECTION_HEADING_RE, m as TRAILING_SLASH_RE, p as SOURCE_LINK_RE, t as API_CHANGE_BULLET_RE } from "./regex.mjs";
5
+ import { n as sanitizeMarkdown } from "./sanitize.mjs";
6
+ import { n as getSkillReferenceDirs, t as createReferenceCache } from "./cache.mjs";
6
7
  import { existsSync, lstatSync, mkdirSync, readFileSync, readdirSync, unlinkSync, writeFileSync } from "node:fs";
7
- import { homedir } from "node:os";
8
+ import { promisify, styleText } from "node:util";
8
9
  import { join } from "pathe";
9
10
  import { exec, execFileSync, spawn } from "node:child_process";
10
- import { glob } from "tinyglobby";
11
- import { findDynamicImports, findStaticImports } from "mlly";
12
- import { promisify } from "node:util";
13
11
  import { isWindows } from "std-env";
14
- import { getEnvApiKey, getEnvApiKey as getEnvApiKey$1, getModel, getModels, getProviders, streamSimple } from "@mariozechner/pi-ai";
15
- import { getOAuthApiKey, getOAuthProvider, getOAuthProviders } from "@mariozechner/pi-ai/oauth";
12
+ import { homedir } from "node:os";
13
+ import { getEnvApiKey, getEnvApiKey as getEnvApiKey$1, getModel, getModels, getProviders, streamSimple } from "@earendil-works/pi-ai";
14
+ import { getOAuthApiKey, getOAuthProvider, getOAuthProviders } from "@earendil-works/pi-ai/oauth";
16
15
  import { resolve as resolve$1 } from "node:path";
17
16
  import { Type } from "typebox";
18
- import { readFile } from "node:fs/promises";
17
+ import { glob, readFile } from "node:fs/promises";
19
18
  import { parseSync } from "oxc-parser";
20
19
  import { setTimeout as setTimeout$1 } from "node:timers/promises";
21
20
  import { createHash } from "node:crypto";
21
+ const STATIC_REGEX_1$6 = /-\d{8}$/;
22
+ const STATIC_REGEX_2$5 = /-\d{4}-\d{2}-\d{2}$/;
23
+ const STATIC_REGEX_3$3 = /-preview/;
22
24
  function isStableId(id) {
23
- if (/-\d{8}$/.test(id)) return false;
24
- if (/-\d{4}-\d{2}-\d{2}$/.test(id)) return false;
25
- if (/-preview/.test(id)) return false;
25
+ if (STATIC_REGEX_1$6.test(id)) return false;
26
+ if (STATIC_REGEX_2$5.test(id)) return false;
27
+ if (STATIC_REGEX_3$3.test(id)) return false;
26
28
  return true;
27
29
  }
28
30
  function compareVersions(a, b) {
@@ -120,7 +122,9 @@ function extractToolHint(input) {
120
122
  if (typeof v === "string" && v) return v;
121
123
  }
122
124
  }
123
- const stripClaude = (n) => n.replace(/^Claude\s+/, "").replace(/\s*\(latest\)\s*$/i, "");
125
+ const STATIC_REGEX_1$5 = /^Claude\s+/;
126
+ const STATIC_REGEX_2$4 = /\s*\(latest\)\s*$/i;
127
+ const stripClaude = (n) => n.replace(STATIC_REGEX_1$5, "").replace(STATIC_REGEX_2$4, "");
124
128
  function buildArgs$2(model, skillDir, symlinkDirs) {
125
129
  return [
126
130
  "-p",
@@ -218,6 +222,7 @@ const adapter$2 = {
218
222
  buildArgs: buildArgs$2,
219
223
  parseEvent: parseEvent$2
220
224
  };
225
+ const STATIC_REGEX_1$4 = /^cat\s*>|>/;
221
226
  function buildArgs$1(model, _skillDir, _symlinkDirs) {
222
227
  return [
223
228
  "exec",
@@ -240,7 +245,7 @@ function parseEvent$1(line) {
240
245
  };
241
246
  if (item.type === "command_execution" && item.aggregated_output) {
242
247
  const cmd = item.command || "";
243
- const writeContent = /^cat\s*>|>/.test(cmd) ? item.aggregated_output : void 0;
248
+ const writeContent = STATIC_REGEX_1$4.test(cmd) ? item.aggregated_output : void 0;
244
249
  return {
245
250
  kind: "tool-call",
246
251
  tool: "Bash",
@@ -546,6 +551,10 @@ function getAvailablePiAiModels() {
546
551
  }
547
552
  return available;
548
553
  }
554
+ const STATIC_REGEX_1$3 = /^\.\/\.skilld\//;
555
+ const STATIC_REGEX_2$3 = /^\.skilld\//;
556
+ const STATIC_REGEX_3$2 = /^\.\//;
557
+ const STATIC_REGEX_5$2 = /\s+/;
549
558
  const TOOLS = [
550
559
  {
551
560
  name: "Read",
@@ -582,7 +591,7 @@ const SAFE_COMMANDS = new Set([
582
591
  ]);
583
592
  const SHELL_META_RE = /[;&|`$()<>]/;
584
593
  function resolveSandboxedPath(p, skilldDir) {
585
- const resolved = resolve$1(skilldDir, String(p).replace(/^\.\/\.skilld\//, "./").replace(/^\.skilld\//, "./").replace(/^\.\//, ""));
594
+ const resolved = resolve$1(skilldDir, String(p).replace(STATIC_REGEX_1$3, "./").replace(STATIC_REGEX_2$3, "./").replace(STATIC_REGEX_3$2, ""));
586
595
  if (!resolved.startsWith(`${skilldDir}/`) && resolved !== skilldDir) throw new Error(`Path traversal blocked: ${p}`);
587
596
  return resolved;
588
597
  }
@@ -638,7 +647,7 @@ function executeTool(toolCall, skilldDir) {
638
647
  return sanitizeMarkdown(readFileSync(filePath, "utf-8"));
639
648
  }
640
649
  case "Glob": {
641
- const pattern = String(args.pattern).replace(/^\.\/\.skilld\//, "./").replace(/^\.skilld\//, "./").replace(/^\.\//, "");
650
+ const pattern = String(args.pattern).replace(STATIC_REGEX_1$3, "./").replace(STATIC_REGEX_2$3, "./").replace(STATIC_REGEX_3$2, "");
642
651
  const results = [];
643
652
  const walkDir = (dir, prefix) => {
644
653
  if (!existsSync(dir)) return;
@@ -648,9 +657,9 @@ function executeTool(toolCall, skilldDir) {
648
657
  else results.push(`./.skilld/${relPath}`);
649
658
  }
650
659
  };
651
- const baseDir = pattern.split("*")[0]?.replace(/\/$/, "") ?? "";
660
+ const baseDir = pattern.split("*")[0]?.replace(TRAILING_SLASH_RE, "") ?? "";
652
661
  walkDir(join(skilldDir, baseDir), baseDir);
653
- const matched = results.filter((r) => globMatch(r.replace(/^\.\/\.skilld\//, ""), pattern));
662
+ const matched = results.filter((r) => globMatch(r.replace(STATIC_REGEX_1$3, ""), pattern));
654
663
  return matched.length > 0 ? matched.join("\n") : `No files matching: ${args.pattern}`;
655
664
  }
656
665
  case "Write":
@@ -658,7 +667,7 @@ function executeTool(toolCall, skilldDir) {
658
667
  return "File written successfully.";
659
668
  case "Bash": {
660
669
  const cmd = String(args.command).trim();
661
- const parts = cmd.split(/\s+/);
670
+ const parts = cmd.split(STATIC_REGEX_5$2);
662
671
  const bin = parts[0] ?? "";
663
672
  if (!SAFE_COMMANDS.has(bin) || SHELL_META_RE.test(cmd)) return `Error: command not allowed. Only skilld, ls, cat, find commands are permitted.`;
664
673
  try {
@@ -789,24 +798,31 @@ async function optimizeSectionPiAi(opts) {
789
798
  cost: totalCost
790
799
  };
791
800
  }
801
+ const STATIC_REGEX_1$2 = /^```(?:markdown|md)?[^\S\n]*\n([\s\S]+)\n```[^\S\n]*$/;
802
+ const STATIC_REGEX_2$2 = /^```(?:markdown|md)/;
803
+ const STATIC_REGEX_5$1 = /^-{3,}\n/;
804
+ const STATIC_REGEX_6 = /\n-{3,}/;
805
+ const STATIC_REGEX_7 = /^(##\s|- (?:BREAKING|DEPRECATED|NEW): )/m;
806
+ const STATIC_REGEX_8 = /^(## .+)\n/;
807
+ const STATIC_REGEX_9 = /^\.\/(?:\.skilld\/|references\/)/;
792
808
  function cleanSectionOutput(content) {
793
809
  let cleaned = content.trim();
794
- const wrapMatch = cleaned.match(/^```(?:markdown|md)?[^\S\n]*\n([\s\S]+)\n```[^\S\n]*$/);
810
+ const wrapMatch = cleaned.match(STATIC_REGEX_1$2);
795
811
  if (wrapMatch) {
796
812
  const inner = wrapMatch[1].trim();
797
- if (/^```(?:markdown|md)/.test(cleaned) || /^##\s/m.test(inner) || /^- (?:BREAKING|DEPRECATED|NEW): /m.test(inner)) cleaned = inner;
813
+ if (STATIC_REGEX_2$2.test(cleaned) || SECTION_HEADING_RE.test(inner) || API_CHANGE_BULLET_RE.test(inner)) cleaned = inner;
798
814
  }
799
815
  cleaned = cleaned.replace(/^# (?!#)/gm, "## ");
800
- const fmMatch = cleaned.match(/^-{3,}\n/);
816
+ const fmMatch = cleaned.match(STATIC_REGEX_5$1);
801
817
  if (fmMatch) {
802
818
  const afterOpen = fmMatch[0].length;
803
- const closeMatch = cleaned.slice(afterOpen).match(/\n-{3,}/);
819
+ const closeMatch = cleaned.slice(afterOpen).match(STATIC_REGEX_6);
804
820
  if (closeMatch) cleaned = cleaned.slice(afterOpen + closeMatch.index + closeMatch[0].length).trim();
805
821
  else cleaned = cleaned.slice(afterOpen).trim();
806
822
  }
807
- const firstMarker = cleaned.match(/^(##\s|- (?:BREAKING|DEPRECATED|NEW): )/m);
823
+ const firstMarker = cleaned.match(STATIC_REGEX_7);
808
824
  if (firstMarker?.index && firstMarker.index > 0) cleaned = cleaned.slice(firstMarker.index).trim();
809
- const headingMatch = cleaned.match(/^(## .+)\n/);
825
+ const headingMatch = cleaned.match(STATIC_REGEX_8);
810
826
  if (headingMatch) {
811
827
  const heading = headingMatch[1];
812
828
  const afterFirst = headingMatch[0].length;
@@ -816,14 +832,17 @@ function cleanSectionOutput(content) {
816
832
  }
817
833
  }
818
834
  cleaned = cleaned.replace(/\(?\[`?\.\/(?:\.skilld\/|references\/)[^)\]]*\]\(([^)]+)\)\)?/g, (match, url) => {
819
- if (/^\.\/(?:\.skilld\/|references\/)/.test(url)) return `[source](${url})`;
835
+ if (STATIC_REGEX_9.test(url)) return `[source](${url})`;
820
836
  return match;
821
837
  });
822
838
  cleaned = cleaned.replace(/\[source\]\(\.\/((docs|issues|discussions|releases|pkg|guide)\/)/g, "[source](./.skilld/$1");
823
839
  cleaned = sanitizeMarkdown(cleaned);
824
- if (!/^##\s/m.test(cleaned) && !/^- (?:BREAKING|DEPRECATED|NEW): /m.test(cleaned) && !/\[source\]/.test(cleaned)) return "";
840
+ if (!SECTION_HEADING_RE.test(cleaned) && !API_CHANGE_BULLET_RE.test(cleaned) && !SOURCE_LINK_RE.test(cleaned)) return "";
825
841
  return cleaned;
826
842
  }
843
+ const STATIC_REGEX_1$1 = /^\[(?:starting|retrying|cached)/;
844
+ const STATIC_REGEX_2$1 = /^\[([^:[\]]+)(?::\s(.+))?\]$/;
845
+ const STATIC_REGEX_3$1 = /skilld search\s+"([^"]+)"/;
827
846
  function createToolProgress(log) {
828
847
  let lastMsg = "";
829
848
  let repeatCount = 0;
@@ -832,7 +851,7 @@ function createToolProgress(log) {
832
851
  function emit(msg) {
833
852
  if (msg === lastMsg) {
834
853
  repeatCount++;
835
- log.message(`${msg} \x1B[90m(+${repeatCount})\x1B[0m`);
854
+ log.message(`${msg} ${styleText("gray", `(+${repeatCount})`)}`);
836
855
  } else {
837
856
  lastMsg = msg;
838
857
  repeatCount = 0;
@@ -845,17 +864,17 @@ function createToolProgress(log) {
845
864
  const now = Date.now();
846
865
  if (now - (lastTextEmit.get(key) ?? 0) < TEXT_THROTTLE_MS) return;
847
866
  lastTextEmit.set(key, now);
848
- const prefix = section ? `\x1B[90m[${section}]\x1B[0m ` : "";
867
+ const prefix = section ? `${styleText("gray", `[${section}]`)} ` : "";
849
868
  const items = text ? text.match(/^- (?:BREAKING|DEPRECATED|NEW|CHANGED|REMOVED|Use |Do |Set |Add |Avoid |Always |Never |Prefer |Check |Ensure )/gm)?.length ?? 0 : 0;
850
- emit(items > 0 ? `${prefix}Writing... \x1B[90m(${items} items)\x1B[0m` : `${prefix}Writing...`);
869
+ emit(items > 0 ? `${prefix}Writing... ${styleText("gray", `(${items} items)`)}` : `${prefix}Writing...`);
851
870
  return;
852
871
  }
853
872
  if (type !== "reasoning" || !chunk.startsWith("[")) return;
854
- if (/^\[(?:starting|retrying|cached)/.test(chunk)) {
855
- emit(`${section ? `\x1B[90m[${section}]\x1B[0m ` : ""}${chunk.slice(1, -1)}`);
873
+ if (STATIC_REGEX_1$1.test(chunk)) {
874
+ emit(`${section ? `${styleText("gray", `[${section}]`)} ` : ""}${chunk.slice(1, -1)}`);
856
875
  return;
857
876
  }
858
- const match = chunk.match(/^\[([^:[\]]+)(?::\s(.+))?\]$/);
877
+ const match = chunk.match(STATIC_REGEX_2$1);
859
878
  if (!match) return;
860
879
  const names = match[1].split(",").map((n) => n.trim());
861
880
  const hints = match[2]?.split(",").map((h) => h.trim()) ?? [];
@@ -863,16 +882,16 @@ function createToolProgress(log) {
863
882
  const rawName = names[i];
864
883
  const hint = hints[i] ?? hints[0] ?? "";
865
884
  const verb = TOOL_NAMES[rawName]?.verb ?? rawName;
866
- const prefix = section ? `\x1B[90m[${section}]\x1B[0m ` : "";
885
+ const prefix = section ? `${styleText("gray", `[${section}]`)} ` : "";
867
886
  if ((rawName === "Bash" || rawName === "run_shell_command") && hint) {
868
- const searchMatch = hint.match(/skilld search\s+"([^"]+)"/);
869
- if (searchMatch) emit(`${prefix}Searching \x1B[36m"${searchMatch[1]}"\x1B[0m`);
887
+ const searchMatch = hint.match(STATIC_REGEX_3$1);
888
+ if (searchMatch) emit(`${prefix}Searching ${styleText("cyan", `"${searchMatch[1]}"`)}`);
870
889
  else if (hint.includes("skilld validate")) emit(`${prefix}Validating...`);
871
890
  else {
872
891
  const shortened = shortenCommand(hint);
873
892
  emit(`${prefix}Running ${shortened.length > 50 ? `${shortened.slice(0, 47)}...` : shortened}`);
874
893
  }
875
- } else emit(`${prefix}${verb} \x1B[90m${shortenPath(hint || "...")}\x1B[0m`);
894
+ } else emit(`${prefix}${verb} ${styleText("gray", shortenPath(hint || "..."))}`);
876
895
  }
877
896
  };
878
897
  }
@@ -1031,13 +1050,16 @@ async function detectNuxtModules(cwd) {
1031
1050
  async function detectPresetPackages(cwd) {
1032
1051
  return detectNuxtModules(cwd);
1033
1052
  }
1053
+ const FROM_STATIC_IMPORT_RE = /\bfrom\s*['"]([^'"\n]+)['"]/g;
1054
+ const SIDE_EFFECT_IMPORT_RE = /\bimport\s*['"]([^'"\n]+)['"]/g;
1055
+ const DYNAMIC_IMPORT_RE = /\bimport\s*\(\s*['"]([^'"\n]+)['"]\s*\)/g;
1034
1056
  const PATTERNS = ["**/*.{ts,js,vue,mjs,cjs,tsx,jsx,mts,cts}"];
1035
- const IGNORE = [
1036
- "**/node_modules/**",
1037
- "**/dist/**",
1038
- "**/.nuxt/**",
1039
- "**/.output/**",
1040
- "**/coverage/**"
1057
+ const IGNORE_DIRS = [
1058
+ "node_modules",
1059
+ "dist",
1060
+ ".nuxt",
1061
+ ".output",
1062
+ "coverage"
1041
1063
  ];
1042
1064
  function addPackage(counts, specifier) {
1043
1065
  if (!specifier || specifier.startsWith(".") || specifier.startsWith("/")) return;
@@ -1047,19 +1069,16 @@ function addPackage(counts, specifier) {
1047
1069
  async function detectImportedPackages(cwd = process.cwd()) {
1048
1070
  try {
1049
1071
  const counts = /* @__PURE__ */ new Map();
1050
- const files = await glob(PATTERNS, {
1072
+ const files = [];
1073
+ for await (const file of glob(PATTERNS, {
1051
1074
  cwd,
1052
- ignore: IGNORE,
1053
- absolute: true,
1054
- expandDirectories: false
1055
- });
1075
+ exclude: (p) => IGNORE_DIRS.some((dir) => p === dir || p.endsWith(`/${dir}`))
1076
+ })) files.push(join(cwd, file));
1056
1077
  await Promise.all(files.map(async (file) => {
1057
1078
  const content = await readFile(file, "utf8");
1058
- for (const imp of findStaticImports(content)) addPackage(counts, imp.specifier);
1059
- for (const imp of findDynamicImports(content)) {
1060
- const match = imp.expression.match(/^['"]([^'"]+)['"]$/);
1061
- if (match) addPackage(counts, match[1]);
1062
- }
1079
+ for (const m of content.matchAll(FROM_STATIC_IMPORT_RE)) addPackage(counts, m[1]);
1080
+ for (const m of content.matchAll(SIDE_EFFECT_IMPORT_RE)) addPackage(counts, m[1]);
1081
+ for (const m of content.matchAll(DYNAMIC_IMPORT_RE)) addPackage(counts, m[1]);
1063
1082
  }));
1064
1083
  const packages = Array.from(counts.entries(), ([name, count]) => ({
1065
1084
  name,
@@ -1358,6 +1377,11 @@ function piAiExecutor(model) {
1358
1377
  function selectExecutor(model) {
1359
1378
  return isPiAiModel(model) ? piAiExecutor(model) : cliExecutor(model);
1360
1379
  }
1380
+ const STATIC_REGEX_1 = /\b429\b/;
1381
+ const STATIC_REGEX_2 = /rate.?limit/i;
1382
+ const STATIC_REGEX_3 = /exhausted.*capacity/i;
1383
+ const STATIC_REGEX_4 = /quota.*reset/i;
1384
+ const STATIC_REGEX_5 = /reset\s+after\s+(\d+)s/i;
1361
1385
  async function optimizeSection(opts) {
1362
1386
  const { section, prompt, outputFile, skillDir, executor, onProgress, timeout, debug, preExistingFiles } = opts;
1363
1387
  const skilldDir = skillInternalDir(skillDir);
@@ -1604,11 +1628,11 @@ async function optimizeDocs(opts) {
1604
1628
  }
1605
1629
  function isRateLimitError(error) {
1606
1630
  if (!error) return false;
1607
- return /\b429\b/.test(error) || /rate.?limit/i.test(error) || /exhausted.*capacity/i.test(error) || /quota.*reset/i.test(error);
1631
+ return STATIC_REGEX_1.test(error) || STATIC_REGEX_2.test(error) || STATIC_REGEX_3.test(error) || STATIC_REGEX_4.test(error);
1608
1632
  }
1609
1633
  function parseRateLimitDelay(error) {
1610
1634
  if (!error || !isRateLimitError(error)) return void 0;
1611
- const match = error.match(/reset\s+after\s+(\d+)s/i);
1635
+ const match = error.match(STATIC_REGEX_5);
1612
1636
  return match ? Number(match[1]) : 10;
1613
1637
  }
1614
1638
  function getRetryError(result) {