@hasna/skills 0.1.13 → 0.1.15

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 (207) hide show
  1. package/bin/index.js +1743 -420
  2. package/bin/mcp.js +791 -259
  3. package/dist/index.d.ts +5 -2
  4. package/dist/index.js +533 -75
  5. package/dist/lib/config.d.ts +27 -0
  6. package/dist/lib/config.test.d.ts +1 -0
  7. package/dist/lib/installer.d.ts +36 -2
  8. package/dist/lib/registry.d.ts +16 -0
  9. package/dist/lib/scheduler.d.ts +47 -0
  10. package/dist/types/api.d.ts +74 -0
  11. package/package.json +5 -2
  12. package/skills/_common/index.ts +4 -0
  13. package/skills/_common/vision.ts +374 -0
  14. package/skills/skill-academic-journal-matcher/bin/cli.ts +34 -0
  15. package/skills/skill-action-item-router/bin/cli.ts +34 -0
  16. package/skills/skill-ad-creative-generator/bin/cli.ts +34 -0
  17. package/skills/skill-advanced-math/bin/cli.ts +34 -0
  18. package/skills/skill-analyze-data/bin/cli.ts +19 -0
  19. package/skills/skill-anomaly-investigator/bin/cli.ts +34 -0
  20. package/skills/skill-api-test-suite/bin/cli.ts +34 -0
  21. package/skills/skill-apidocs/bin/cli.ts +87 -0
  22. package/skills/skill-audio-cleanup-lab/bin/cli.ts +6 -0
  23. package/skills/skill-audiobook-chapter-proofer/bin/cli.ts +34 -0
  24. package/skills/skill-banner-ad-suite/bin/cli.ts +34 -0
  25. package/skills/skill-benchmark-finder/bin/cli.ts +34 -0
  26. package/skills/skill-bio-sequence-tool/bin/cli.ts +34 -0
  27. package/skills/skill-blog-topic-cluster/bin/cli.ts +34 -0
  28. package/skills/skill-brand-style-guide/bin/cli.ts +19 -0
  29. package/skills/skill-brand-voice-audit/bin/cli.ts +34 -0
  30. package/skills/skill-budget-variance-analyzer/bin/cli.ts +6 -0
  31. package/skills/skill-businessactivity/bin/cli.ts +28 -0
  32. package/skills/skill-calendar-events/bin/cli.ts +34 -0
  33. package/skills/skill-campaign-metric-brief/bin/cli.ts +34 -0
  34. package/skills/skill-campaign-moodboard/bin/cli.ts +34 -0
  35. package/skills/skill-caption-style-stylist/bin/cli.ts +34 -0
  36. package/skills/skill-chemistry-calculator/bin/cli.ts +34 -0
  37. package/skills/skill-churn-risk-notifier/bin/cli.ts +34 -0
  38. package/skills/skill-citation-formatter/bin/cli.ts +34 -0
  39. package/skills/skill-classroom-newsletter-kit/bin/cli.ts +34 -0
  40. package/skills/skill-color-palette-harmonizer/bin/cli.ts +34 -0
  41. package/skills/skill-colorextract/SKILL.md +35 -0
  42. package/skills/skill-colorextract/bun.lock +102 -0
  43. package/skills/skill-colorextract/package.json +13 -0
  44. package/skills/skill-colorextract/src/index.ts +405 -0
  45. package/skills/skill-competitor-ad-analyzer/bin/cli.ts +34 -0
  46. package/skills/skill-compliance-copy-check/bin/cli.ts +34 -0
  47. package/skills/skill-compliance-report-pack/bin/cli.ts +34 -0
  48. package/skills/skill-compress-video/bin/cli.ts +19 -0
  49. package/skills/skill-consolelog/bin/cli.ts +884 -0
  50. package/skills/skill-contract-plainlanguage/bin/cli.ts +34 -0
  51. package/skills/skill-copytone-translator/bin/cli.ts +34 -0
  52. package/skills/skill-create-blog-article/bin/cli.ts +34 -0
  53. package/skills/skill-create-ebook/bin/cli.ts +34 -0
  54. package/skills/skill-crm-note-enhancer/bin/cli.ts +34 -0
  55. package/skills/skill-customer-journey-mapper/bin/cli.ts +34 -0
  56. package/skills/skill-dashboard-builder/bin/cli.ts +34 -0
  57. package/skills/skill-dashboard-narrator/bin/cli.ts +34 -0
  58. package/skills/skill-data-anonymizer/bin/cli.ts +34 -0
  59. package/skills/skill-database-explorer/bin/cli.ts +34 -0
  60. package/skills/skill-dataset-health-check/bin/cli.ts +34 -0
  61. package/skills/skill-decision-journal/bin/cli.ts +34 -0
  62. package/skills/skill-delegation-brief-writer/bin/cli.ts +34 -0
  63. package/skills/skill-destination-briefing/bin/cli.ts +34 -0
  64. package/skills/skill-diff-viewer/bin/cli.ts +34 -0
  65. package/skills/skill-domainpurchase/SKILL.md +46 -0
  66. package/skills/skill-domainpurchase/bin/cli.ts +683 -0
  67. package/skills/skill-domainsearch/SKILL.md +41 -0
  68. package/skills/skill-domainsearch/bin/cli.ts +410 -0
  69. package/skills/skill-educational-resource-finder/bin/cli.ts +34 -0
  70. package/skills/skill-email-campaign/bin/cli.ts +34 -0
  71. package/skills/skill-exam-readiness-check/bin/cli.ts +34 -0
  72. package/skills/skill-experiment-power-calculator/bin/cli.ts +34 -0
  73. package/skills/skill-extract-audio/bin/cli.ts +19 -0
  74. package/skills/skill-extract-frames/bin/cli.ts +34 -0
  75. package/skills/skill-extract-invoice/bin/cli.ts +34 -0
  76. package/skills/skill-family-activity-curator/bin/cli.ts +34 -0
  77. package/skills/skill-faq-packager/bin/cli.ts +34 -0
  78. package/skills/skill-feedback-survey-designer/bin/cli.ts +34 -0
  79. package/skills/skill-field-trip-planner/bin/cli.ts +34 -0
  80. package/skills/skill-file-organizer/bin/cli.ts +34 -0
  81. package/skills/skill-folder-tree/bin/cli.ts +34 -0
  82. package/skills/skill-forecast-scenario-lab/bin/cli.ts +34 -0
  83. package/skills/skill-form-filler/bin/cli.ts +34 -0
  84. package/skills/skill-generate-api-client/bin/cli.ts +34 -0
  85. package/skills/skill-generate-book-cover/bin/cli.ts +34 -0
  86. package/skills/skill-generate-chart/bin/cli.ts +34 -0
  87. package/skills/skill-generate-diagram/bin/cli.ts +34 -0
  88. package/skills/skill-generate-dockerfile/bin/cli.ts +34 -0
  89. package/skills/skill-generate-documentation/bin/cli.ts +34 -0
  90. package/skills/skill-generate-docx/bin/cli.ts +6 -0
  91. package/skills/skill-generate-env/bin/cli.ts +34 -0
  92. package/skills/skill-generate-excel/bin/cli.ts +34 -0
  93. package/skills/skill-generate-favicon/bin/cli.ts +34 -0
  94. package/skills/skill-generate-mock-data/bin/cli.ts +34 -0
  95. package/skills/skill-generate-pdf/bin/cli.ts +6 -0
  96. package/skills/skill-generate-pr-description/bin/cli.ts +34 -0
  97. package/skills/skill-generate-presentation/bin/cli.ts +34 -0
  98. package/skills/skill-generate-qrcode/bin/cli.ts +34 -0
  99. package/skills/skill-generate-regex/bin/cli.ts +34 -0
  100. package/skills/skill-generate-resume/bin/cli.ts +34 -0
  101. package/skills/skill-generate-sitemap/bin/cli.ts +34 -0
  102. package/skills/skill-generate-social-posts/bin/cli.ts +34 -0
  103. package/skills/skill-generate-sql/bin/cli.ts +34 -0
  104. package/skills/skill-gif-maker/bin/cli.ts +34 -0
  105. package/skills/skill-github-manager/bin/cli.ts +34 -0
  106. package/skills/skill-gmail/bin/cli.ts +34 -0
  107. package/skills/skill-goal-quarterly-roadmap/bin/cli.ts +34 -0
  108. package/skills/skill-grant-application-drafter/bin/cli.ts +34 -0
  109. package/skills/skill-grocery-basket-optimizer/bin/cli.ts +34 -0
  110. package/skills/skill-guest-communication-suite/bin/cli.ts +34 -0
  111. package/skills/skill-habit-reflection-digest/bin/cli.ts +34 -0
  112. package/skills/skill-highlight-reel-generator/bin/cli.ts +34 -0
  113. package/skills/skill-homework-feedback-coach/bin/cli.ts +34 -0
  114. package/skills/skill-hook/bunfig.toml +5 -0
  115. package/skills/skill-household-maintenance-mgr/bin/cli.ts +34 -0
  116. package/skills/skill-http-server/bin/cli.ts +34 -0
  117. package/skills/skill-implementation/bunfig.toml +5 -0
  118. package/skills/skill-implementation-agent/bin/cli.ts +34 -0
  119. package/skills/skill-implementation-plan/bin/cli.ts +34 -0
  120. package/skills/skill-implementation-todo/bin/cli.ts +34 -0
  121. package/skills/skill-inbox-priority-planner/bin/cli.ts +34 -0
  122. package/skills/skill-invoice/bin/cli.ts +20 -0
  123. package/skills/skill-invoice-dispute-helper/bin/cli.ts +34 -0
  124. package/skills/skill-itinerary-architect/bin/cli.ts +34 -0
  125. package/skills/skill-jingle-composer/bin/cli.ts +34 -0
  126. package/skills/skill-kpi-digest-generator/bin/cli.ts +34 -0
  127. package/skills/skill-lab-notebook-formatter/bin/cli.ts +34 -0
  128. package/skills/skill-landing-page-copy/bin/cli.ts +34 -0
  129. package/skills/skill-latex-table-generator/bin/cli.ts +34 -0
  130. package/skills/skill-learning-style-profiler/bin/cli.ts +34 -0
  131. package/skills/skill-lesson-plan-customizer/bin/cli.ts +34 -0
  132. package/skills/skill-livestream-runofshow/bin/cli.ts +34 -0
  133. package/skills/skill-longform-structurer/bin/cli.ts +34 -0
  134. package/skills/skill-lorem-generator/bin/cli.ts +34 -0
  135. package/skills/skill-managehook/bin/cli.ts +241 -0
  136. package/skills/skill-managemcp/bin/cli.ts +241 -0
  137. package/skills/skill-manageskill/bin/cli.ts +241 -0
  138. package/skills/skill-markdown-validator/bin/cli.ts +34 -0
  139. package/skills/skill-mcp-builder/bin/cli.ts +34 -0
  140. package/skills/skill-meal-plan-designer/bin/cli.ts +34 -0
  141. package/skills/skill-meeting-insight-summarizer/bin/cli.ts +34 -0
  142. package/skills/skill-merge-pdfs/bin/cli.ts +34 -0
  143. package/skills/skill-microcopy-generator/bin/cli.ts +34 -0
  144. package/skills/skill-mindfulness-prompt-cache/bin/cli.ts +34 -0
  145. package/skills/skill-notion-manager/bin/cli.ts +34 -0
  146. package/skills/skill-onboarding-sequence-builder/bin/cli.ts +34 -0
  147. package/skills/skill-onsite-ops-checklist/bin/cli.ts +34 -0
  148. package/skills/skill-outreach-cadence-designer/bin/cli.ts +34 -0
  149. package/skills/skill-packaging-concept-studio/bin/cli.ts +34 -0
  150. package/skills/skill-packing-plan-pro/bin/cli.ts +34 -0
  151. package/skills/skill-parent-teacher-brief/bin/cli.ts +34 -0
  152. package/skills/skill-partner-kit-assembler/bin/cli.ts +34 -0
  153. package/skills/skill-payroll-change-prepper/bin/cli.ts +34 -0
  154. package/skills/skill-persona-based-adwriter/bin/cli.ts +34 -0
  155. package/skills/skill-persona-generator/bin/cli.ts +34 -0
  156. package/skills/skill-personal-daily-ops/bin/cli.ts +34 -0
  157. package/skills/skill-pet-care-scheduler/bin/cli.ts +34 -0
  158. package/skills/skill-podcast-show-notes/bin/cli.ts +34 -0
  159. package/skills/skill-presentation-theme-maker/bin/cli.ts +34 -0
  160. package/skills/skill-press-release-drafter/bin/cli.ts +34 -0
  161. package/skills/skill-print-collateral-designer/bin/cli.ts +34 -0
  162. package/skills/skill-procurement-scorecard/bin/cli.ts +34 -0
  163. package/skills/skill-product-demo-script/bin/cli.ts +34 -0
  164. package/skills/skill-product-mockup/bin/cli.ts +34 -0
  165. package/skills/skill-project-retro-companion/bin/cli.ts +34 -0
  166. package/skills/skill-proposal-redline-advisor/bin/cli.ts +34 -0
  167. package/skills/skill-regex-tester/bin/cli.ts +34 -0
  168. package/skills/skill-remove-background/bin/cli.ts +34 -0
  169. package/skills/skill-risk-disclosure-kit/bin/cli.ts +34 -0
  170. package/skills/skill-roi-comparison-tool/bin/cli.ts +34 -0
  171. package/skills/skill-sales-call-recapper/bin/cli.ts +34 -0
  172. package/skills/skill-salescopy/bin/cli.ts +20 -0
  173. package/skills/skill-scaffold-project/bin/cli.ts +34 -0
  174. package/skills/skill-scholarship-tracker/bin/cli.ts +34 -0
  175. package/skills/skill-scientific-figure-check/bin/cli.ts +34 -0
  176. package/skills/skill-seating-chart-maker/bin/cli.ts +34 -0
  177. package/skills/skill-security-audit/bin/cli.ts +34 -0
  178. package/skills/skill-seo-brief-builder/bin/cli.ts +34 -0
  179. package/skills/skill-siteanalyze/SKILL.md +25 -0
  180. package/skills/skill-siteanalyze/package.json +13 -0
  181. package/skills/skill-siteanalyze/src/index.ts +592 -0
  182. package/skills/skill-slack-assistant/bin/cli.ts +34 -0
  183. package/skills/skill-sleep-routine-analyzer/bin/cli.ts +34 -0
  184. package/skills/skill-social-media-kit/bin/cli.ts +34 -0
  185. package/skills/skill-split-pdf/bin/cli.ts +34 -0
  186. package/skills/skill-sponsorship-proposal-lab/bin/cli.ts +34 -0
  187. package/skills/skill-spreadsheet-cleanroom/bin/cli.ts +34 -0
  188. package/skills/skill-statistical-test-selector/bin/cli.ts +34 -0
  189. package/skills/skill-stress-relief-playbook/bin/cli.ts +34 -0
  190. package/skills/skill-study-guide-builder/bin/cli.ts +34 -0
  191. package/skills/skill-subscription-spend-watcher/bin/cli.ts +34 -0
  192. package/skills/skill-subtitle/bin/cli.ts +20 -0
  193. package/skills/skill-survey-insight-extractor/bin/cli.ts +34 -0
  194. package/skills/skill-terraform-generator/bin/cli.ts +34 -0
  195. package/skills/skill-testimonial-graphics/bin/cli.ts +34 -0
  196. package/skills/skill-timesheet/bin/cli.ts +47 -0
  197. package/skills/skill-travel-budget-balancer/bin/cli.ts +34 -0
  198. package/skills/skill-validate-config/bin/cli.ts +34 -0
  199. package/skills/skill-video-cut-suggester/bin/cli.ts +34 -0
  200. package/skills/skill-video-downloader/bin/cli.ts +34 -0
  201. package/skills/skill-video-thumbnail/bin/cli.ts +34 -0
  202. package/skills/skill-voiceover-casting-assistant/bin/cli.ts +34 -0
  203. package/skills/skill-watermark/bin/cli.ts +34 -0
  204. package/skills/skill-webcrawling/bin/cli.ts +21 -0
  205. package/skills/skill-webinar-script-coach/bin/cli.ts +34 -0
  206. package/skills/skill-wellness-progress-reporter/bin/cli.ts +34 -0
  207. package/skills/skill-workout-cycle-planner/bin/cli.ts +34 -0
package/bin/index.js CHANGED
@@ -4,26 +4,62 @@ var __create = Object.create;
4
4
  var __getProtoOf = Object.getPrototypeOf;
5
5
  var __defProp = Object.defineProperty;
6
6
  var __getOwnPropNames = Object.getOwnPropertyNames;
7
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
7
8
  var __hasOwnProp = Object.prototype.hasOwnProperty;
9
+ function __accessProp(key) {
10
+ return this[key];
11
+ }
12
+ var __toESMCache_node;
13
+ var __toESMCache_esm;
8
14
  var __toESM = (mod, isNodeMode, target) => {
15
+ var canCache = mod != null && typeof mod === "object";
16
+ if (canCache) {
17
+ var cache = isNodeMode ? __toESMCache_node ??= new WeakMap : __toESMCache_esm ??= new WeakMap;
18
+ var cached = cache.get(mod);
19
+ if (cached)
20
+ return cached;
21
+ }
9
22
  target = mod != null ? __create(__getProtoOf(mod)) : {};
10
23
  const to = isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target;
11
24
  for (let key of __getOwnPropNames(mod))
12
25
  if (!__hasOwnProp.call(to, key))
13
26
  __defProp(to, key, {
14
- get: () => mod[key],
27
+ get: __accessProp.bind(mod, key),
15
28
  enumerable: true
16
29
  });
30
+ if (canCache)
31
+ cache.set(mod, to);
17
32
  return to;
18
33
  };
34
+ var __toCommonJS = (from) => {
35
+ var entry = (__moduleCache ??= new WeakMap).get(from), desc;
36
+ if (entry)
37
+ return entry;
38
+ entry = __defProp({}, "__esModule", { value: true });
39
+ if (from && typeof from === "object" || typeof from === "function") {
40
+ for (var key of __getOwnPropNames(from))
41
+ if (!__hasOwnProp.call(entry, key))
42
+ __defProp(entry, key, {
43
+ get: __accessProp.bind(from, key),
44
+ enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
45
+ });
46
+ }
47
+ __moduleCache.set(from, entry);
48
+ return entry;
49
+ };
50
+ var __moduleCache;
19
51
  var __commonJS = (cb, mod) => () => (mod || cb((mod = { exports: {} }).exports, mod), mod.exports);
52
+ var __returnValue = (v) => v;
53
+ function __exportSetter(name, newValue) {
54
+ this[name] = __returnValue.bind(null, newValue);
55
+ }
20
56
  var __export = (target, all) => {
21
57
  for (var name in all)
22
58
  __defProp(target, name, {
23
59
  get: all[name],
24
60
  enumerable: true,
25
61
  configurable: true,
26
- set: (newValue) => all[name] = () => newValue
62
+ set: __exportSetter.bind(all, name)
27
63
  });
28
64
  };
29
65
  var __esm = (fn, res) => () => (fn && (res = fn(fn = 0)), res);
@@ -1878,7 +1914,7 @@ var package_default;
1878
1914
  var init_package = __esm(() => {
1879
1915
  package_default = {
1880
1916
  name: "@hasna/skills",
1881
- version: "0.1.13",
1917
+ version: "0.1.15",
1882
1918
  description: "Skills library for AI coding agents",
1883
1919
  type: "module",
1884
1920
  bin: {
@@ -1901,9 +1937,12 @@ var init_package = __esm(() => {
1901
1937
  main: "./dist/index.js",
1902
1938
  types: "./dist/index.d.ts",
1903
1939
  scripts: {
1904
- build: "bun build ./src/cli/index.tsx --outdir ./bin --target bun --external ink --external react --external chalk && bun build ./src/mcp/index.ts --outfile ./bin/mcp.js --target bun && bun build ./src/index.ts --outdir ./dist --target bun && tsc --emitDeclarationOnly --declaration --outDir dist",
1940
+ clean: "rm -rf bin/ dist/",
1941
+ build: "bun run clean && bun build ./src/cli/index.tsx --outdir ./bin --target bun --external ink --external react --external chalk && bun build ./src/mcp/index.ts --outfile ./bin/mcp.js --target bun && bun build ./src/index.ts --outdir ./dist --target bun && tsc --emitDeclarationOnly --declaration --outDir dist",
1905
1942
  test: "bun test",
1906
1943
  dev: "bun run ./src/cli/index.tsx",
1944
+ "dev:watch": "bun --watch run ./src/cli/index.tsx",
1945
+ "dev:mcp": "bun --watch run ./src/mcp/index.ts",
1907
1946
  typecheck: "tsc --noEmit",
1908
1947
  prepublishOnly: "bun run build",
1909
1948
  "dashboard:dev": "cd dashboard && bun run dev",
@@ -1960,8 +1999,91 @@ var init_package = __esm(() => {
1960
1999
  });
1961
2000
 
1962
2001
  // src/lib/registry.ts
2002
+ import { existsSync, readFileSync, readdirSync } from "fs";
2003
+ import { join } from "path";
2004
+ import { homedir } from "os";
2005
+ function parseSkillMdFrontmatter(content) {
2006
+ const match = content.match(/^---\n([\s\S]*?)\n---/);
2007
+ if (!match)
2008
+ return null;
2009
+ const result = {};
2010
+ for (const line of match[1].split(`
2011
+ `)) {
2012
+ const colon = line.indexOf(":");
2013
+ if (colon === -1)
2014
+ continue;
2015
+ const key = line.slice(0, colon).trim();
2016
+ const value = line.slice(colon + 1).trim();
2017
+ if (!key || !value)
2018
+ continue;
2019
+ if (key === "name")
2020
+ result.name = value;
2021
+ else if (key === "description")
2022
+ result.description = value;
2023
+ else if (key === "displayName" || key === "display_name")
2024
+ result.displayName = value;
2025
+ else if (key === "category")
2026
+ result.category = value;
2027
+ else if (key === "tags") {
2028
+ result.tags = value.replace(/[\[\]]/g, "").split(",").map((t) => t.trim()).filter(Boolean);
2029
+ }
2030
+ }
2031
+ return Object.keys(result).length > 0 ? result : null;
2032
+ }
2033
+ function discoverSkillsInDir(dir) {
2034
+ if (!existsSync(dir))
2035
+ return [];
2036
+ const result = [];
2037
+ try {
2038
+ const entries = readdirSync(dir, { withFileTypes: true });
2039
+ for (const entry of entries) {
2040
+ if (!entry.isDirectory())
2041
+ continue;
2042
+ const skillMdPath = join(dir, entry.name, "SKILL.md");
2043
+ if (!existsSync(skillMdPath))
2044
+ continue;
2045
+ let content;
2046
+ try {
2047
+ content = readFileSync(skillMdPath, "utf-8");
2048
+ } catch {
2049
+ continue;
2050
+ }
2051
+ const fm = parseSkillMdFrontmatter(content);
2052
+ if (!fm?.name)
2053
+ continue;
2054
+ const name = fm.name.replace(/^skill-/, "");
2055
+ result.push({
2056
+ name,
2057
+ displayName: fm.displayName || name.replace(/-/g, " ").replace(/\b\w/g, (c) => c.toUpperCase()),
2058
+ description: fm.description || "",
2059
+ category: fm.category || "Development Tools",
2060
+ tags: fm.tags || [],
2061
+ source: "custom"
2062
+ });
2063
+ }
2064
+ } catch {}
2065
+ return result;
2066
+ }
2067
+ function loadRegistry(cwd) {
2068
+ const now = Date.now();
2069
+ if (_registryCache && now - _registryCacheTime < REGISTRY_CACHE_TTL) {
2070
+ return _registryCache;
2071
+ }
2072
+ const official = SKILLS.map((s) => ({ ...s, source: "official" }));
2073
+ const globalCustom = discoverSkillsInDir(join(homedir(), ".skills"));
2074
+ const projectCustom = discoverSkillsInDir(join(cwd || process.cwd(), ".skills", "custom-skills"));
2075
+ const customNames = new Set([...globalCustom, ...projectCustom].map((s) => s.name));
2076
+ const filtered = official.filter((s) => !customNames.has(s.name));
2077
+ _registryCache = [...filtered, ...globalCustom, ...projectCustom];
2078
+ _registryCacheTime = now;
2079
+ return _registryCache;
2080
+ }
2081
+ function clearRegistryCache() {
2082
+ _registryCache = null;
2083
+ _registryCacheTime = 0;
2084
+ }
1963
2085
  function getSkillsByCategory(category) {
1964
- return SKILLS.filter((s) => s.category === category);
2086
+ return loadRegistry().filter((s) => s.category === category);
1965
2087
  }
1966
2088
  function editDistance(a, b) {
1967
2089
  if (a === b)
@@ -2007,7 +2129,7 @@ function searchSkills(query) {
2007
2129
  if (words.length === 0)
2008
2130
  return [];
2009
2131
  const scored = [];
2010
- for (const skill of SKILLS) {
2132
+ for (const skill of loadRegistry()) {
2011
2133
  const nameLower = skill.name.toLowerCase();
2012
2134
  const displayNameLower = skill.displayName.toLowerCase();
2013
2135
  const descriptionLower = skill.description.toLowerCase();
@@ -2043,9 +2165,24 @@ function searchSkills(query) {
2043
2165
  return scored.map((s) => s.skill);
2044
2166
  }
2045
2167
  function getSkill(name) {
2046
- return SKILLS.find((s) => s.name === name);
2168
+ return loadRegistry().find((s) => s.name === name);
2169
+ }
2170
+ function levenshtein(a, b) {
2171
+ const m = a.length, n = b.length;
2172
+ const dp = Array.from({ length: m + 1 }, (_, i) => Array.from({ length: n + 1 }, (_2, j) => i === 0 ? j : j === 0 ? i : 0));
2173
+ for (let i = 1;i <= m; i++) {
2174
+ for (let j = 1;j <= n; j++) {
2175
+ dp[i][j] = a[i - 1] === b[j - 1] ? dp[i - 1][j - 1] : 1 + Math.min(dp[i - 1][j], dp[i][j - 1], dp[i - 1][j - 1]);
2176
+ }
2177
+ }
2178
+ return dp[m][n];
2179
+ }
2180
+ function findSimilarSkills(query, maxResults = 3) {
2181
+ const q = query.toLowerCase();
2182
+ const scored = loadRegistry().map((s) => ({ name: s.name, dist: levenshtein(q, s.name.toLowerCase()) })).filter((s) => s.dist <= Math.max(3, Math.floor(q.length / 2))).sort((a, b) => a.dist - b.dist);
2183
+ return scored.slice(0, maxResults).map((s) => s.name);
2047
2184
  }
2048
- var CATEGORIES, SKILLS;
2185
+ var CATEGORIES, SKILLS, _registryCache = null, _registryCacheTime = 0, REGISTRY_CACHE_TTL = 5000;
2049
2186
  var init_registry = __esm(() => {
2050
2187
  CATEGORIES = [
2051
2188
  "Development Tools",
@@ -3083,6 +3220,20 @@ var init_registry = __esm(() => {
3083
3220
  category: "Design & Branding",
3084
3221
  tags: ["testimonials", "graphics", "social-proof", "marketing"]
3085
3222
  },
3223
+ {
3224
+ name: "colorextract",
3225
+ displayName: "Color Extract",
3226
+ description: "Extract complete color palettes from screenshots and images using Claude Vision. Outputs open-styles compatible profiles.",
3227
+ category: "Design & Branding",
3228
+ tags: ["colors", "palette", "design", "vision", "screenshot", "extract", "open-styles"]
3229
+ },
3230
+ {
3231
+ name: "siteanalyze",
3232
+ displayName: "Site Analyze",
3233
+ description: "Analyze any website's design system \u2014 detects shadcn/ui, Tailwind, extracts colors, typography, and components via Playwright + Claude Vision.",
3234
+ category: "Design & Branding",
3235
+ tags: ["design", "shadcn", "tailwind", "colors", "typography", "playwright", "analysis", "open-styles"]
3236
+ },
3086
3237
  {
3087
3238
  name: "browse",
3088
3239
  displayName: "Browse",
@@ -5126,39 +5277,39 @@ var require_cli_spinners = __commonJS((exports, module) => {
5126
5277
  });
5127
5278
 
5128
5279
  // src/lib/installer.ts
5129
- import { existsSync, cpSync, mkdirSync, writeFileSync, rmSync, readdirSync, statSync, readFileSync } from "fs";
5130
- import { join, dirname } from "path";
5131
- import { homedir } from "os";
5280
+ import { existsSync as existsSync2, cpSync, mkdirSync, writeFileSync, rmSync, readdirSync as readdirSync2, statSync, readFileSync as readFileSync2, accessSync, constants } from "fs";
5281
+ import { join as join2, dirname } from "path";
5282
+ import { homedir as homedir2 } from "os";
5132
5283
  import { fileURLToPath } from "url";
5133
5284
  function findSkillsDir() {
5134
5285
  let dir = __dirname2;
5135
5286
  for (let i = 0;i < 5; i++) {
5136
- const candidate = join(dir, "skills");
5137
- if (existsSync(candidate)) {
5287
+ const candidate = join2(dir, "skills");
5288
+ if (existsSync2(candidate) && !dir.includes(".skills")) {
5138
5289
  return candidate;
5139
5290
  }
5140
5291
  dir = dirname(dir);
5141
5292
  }
5142
- return join(__dirname2, "..", "skills");
5293
+ return join2(__dirname2, "..", "skills");
5143
5294
  }
5144
5295
  function getSkillPath(name) {
5145
5296
  const skillName = normalizeSkillName(name);
5146
- return join(SKILLS_DIR, skillName);
5297
+ return join2(SKILLS_DIR, skillName);
5147
5298
  }
5148
5299
  function installSkill(name, options = {}) {
5149
5300
  const { targetDir = process.cwd(), overwrite = false } = options;
5150
5301
  const skillName = normalizeSkillName(name);
5151
5302
  const sourcePath = getSkillPath(name);
5152
- const destDir = join(targetDir, ".skills");
5153
- const destPath = join(destDir, skillName);
5154
- if (!existsSync(sourcePath)) {
5303
+ const destDir = join2(targetDir, ".skills");
5304
+ const destPath = join2(destDir, skillName);
5305
+ if (!existsSync2(sourcePath)) {
5155
5306
  return {
5156
5307
  skill: name,
5157
5308
  success: false,
5158
5309
  error: `Skill '${name}' not found`
5159
5310
  };
5160
5311
  }
5161
- if (existsSync(destPath) && !overwrite) {
5312
+ if (existsSync2(destPath) && !overwrite) {
5162
5313
  return {
5163
5314
  skill: name,
5164
5315
  success: false,
@@ -5167,10 +5318,10 @@ function installSkill(name, options = {}) {
5167
5318
  };
5168
5319
  }
5169
5320
  try {
5170
- if (!existsSync(destDir)) {
5321
+ if (!existsSync2(destDir)) {
5171
5322
  mkdirSync(destDir, { recursive: true });
5172
5323
  }
5173
- if (existsSync(destPath) && overwrite) {
5324
+ if (existsSync2(destPath) && overwrite) {
5174
5325
  rmSync(destPath, { recursive: true, force: true });
5175
5326
  }
5176
5327
  cpSync(sourcePath, destPath, {
@@ -5181,6 +5332,7 @@ function installSkill(name, options = {}) {
5181
5332
  }
5182
5333
  });
5183
5334
  updateSkillsIndex(destDir);
5335
+ recordInstall(destDir, name);
5184
5336
  const meta = getSkill(name);
5185
5337
  if (meta?.dependencies && meta.dependencies.length > 0) {
5186
5338
  const installed = getInstalledSkills(targetDir);
@@ -5205,8 +5357,10 @@ function installSkill(name, options = {}) {
5205
5357
  }
5206
5358
  }
5207
5359
  function updateSkillsIndex(skillsDir) {
5208
- const indexPath = join(skillsDir, "index.ts");
5209
- const skills = readdirSync(skillsDir).filter((f) => f.startsWith("skill-") && !f.includes("."));
5360
+ const indexPath = join2(skillsDir, "index.ts");
5361
+ const meta = loadMeta(skillsDir);
5362
+ const disabledSet = new Set(meta.disabled || []);
5363
+ const skills = readdirSync2(skillsDir).filter((f) => f.startsWith("skill-") && !f.includes(".") && !disabledSet.has(f.replace("skill-", "")));
5210
5364
  const exports = skills.map((s) => {
5211
5365
  const name = s.replace("skill-", "").replace(/-/g, "_");
5212
5366
  return `export * as ${name} from './${s}/src/index.js';`;
@@ -5221,25 +5375,63 @@ ${exports}
5221
5375
  `;
5222
5376
  writeFileSync(indexPath, content);
5223
5377
  }
5378
+ function getMetaPath(skillsDir) {
5379
+ return join2(skillsDir, ".meta.json");
5380
+ }
5381
+ function loadMeta(skillsDir) {
5382
+ const metaPath = getMetaPath(skillsDir);
5383
+ if (existsSync2(metaPath)) {
5384
+ try {
5385
+ return JSON.parse(readFileSync2(metaPath, "utf-8"));
5386
+ } catch {}
5387
+ }
5388
+ return { skills: {} };
5389
+ }
5390
+ function saveMeta(skillsDir, meta) {
5391
+ writeFileSync(getMetaPath(skillsDir), JSON.stringify(meta, null, 2));
5392
+ }
5393
+ function recordInstall(skillsDir, name) {
5394
+ const meta = loadMeta(skillsDir);
5395
+ const skillName = normalizeSkillName(name);
5396
+ let version = "unknown";
5397
+ try {
5398
+ const pkgPath = join2(skillsDir, skillName, "package.json");
5399
+ if (existsSync2(pkgPath)) {
5400
+ const pkg = JSON.parse(readFileSync2(pkgPath, "utf-8"));
5401
+ version = pkg.version || "unknown";
5402
+ }
5403
+ } catch {}
5404
+ meta.skills[name] = { installedAt: new Date().toISOString(), version };
5405
+ saveMeta(skillsDir, meta);
5406
+ }
5407
+ function recordRemove(skillsDir, name) {
5408
+ const meta = loadMeta(skillsDir);
5409
+ delete meta.skills[name];
5410
+ saveMeta(skillsDir, meta);
5411
+ }
5412
+ function getInstallMeta(targetDir = process.cwd()) {
5413
+ return loadMeta(join2(targetDir, ".skills"));
5414
+ }
5224
5415
  function getInstalledSkills(targetDir = process.cwd()) {
5225
- const skillsDir = join(targetDir, ".skills");
5226
- if (!existsSync(skillsDir)) {
5416
+ const skillsDir = join2(targetDir, ".skills");
5417
+ if (!existsSync2(skillsDir)) {
5227
5418
  return [];
5228
5419
  }
5229
- return readdirSync(skillsDir).filter((f) => {
5230
- const fullPath = join(skillsDir, f);
5420
+ return readdirSync2(skillsDir).filter((f) => {
5421
+ const fullPath = join2(skillsDir, f);
5231
5422
  return f.startsWith("skill-") && statSync(fullPath).isDirectory();
5232
5423
  }).map((f) => f.replace("skill-", ""));
5233
5424
  }
5234
5425
  function removeSkill(name, targetDir = process.cwd()) {
5235
5426
  const skillName = normalizeSkillName(name);
5236
- const skillsDir = join(targetDir, ".skills");
5237
- const skillPath = join(skillsDir, skillName);
5238
- if (!existsSync(skillPath)) {
5427
+ const skillsDir = join2(targetDir, ".skills");
5428
+ const skillPath = join2(skillsDir, skillName);
5429
+ if (!existsSync2(skillPath)) {
5239
5430
  return false;
5240
5431
  }
5241
5432
  rmSync(skillPath, { recursive: true, force: true });
5242
5433
  updateSkillsIndex(skillsDir);
5434
+ recordRemove(skillsDir, name);
5243
5435
  return true;
5244
5436
  }
5245
5437
  function resolveAgents(agentArg) {
@@ -5252,27 +5444,31 @@ function resolveAgents(agentArg) {
5252
5444
  return [agent];
5253
5445
  }
5254
5446
  function getAgentSkillsDir(agent, scope = "global", projectDir) {
5255
- const agentDir = `.${agent}`;
5256
- if (scope === "project") {
5257
- return join(projectDir || process.cwd(), agentDir, "skills");
5447
+ const base = projectDir || process.cwd();
5448
+ switch (agent) {
5449
+ case "pi":
5450
+ return scope === "project" ? join2(base, ".pi", "skills") : join2(homedir2(), ".pi", "agent", "skills");
5451
+ case "opencode":
5452
+ return scope === "project" ? join2(base, ".opencode", "skills") : join2(homedir2(), ".opencode", "skills");
5453
+ default:
5454
+ return scope === "project" ? join2(base, `.${agent}`, "skills") : join2(homedir2(), `.${agent}`, "skills");
5258
5455
  }
5259
- return join(homedir(), agentDir, "skills");
5260
5456
  }
5261
5457
  function getAgentSkillPath(name, agent, scope = "global", projectDir) {
5262
5458
  const skillName = normalizeSkillName(name);
5263
- return join(getAgentSkillsDir(agent, scope, projectDir), skillName);
5459
+ return join2(getAgentSkillsDir(agent, scope, projectDir), skillName);
5264
5460
  }
5265
5461
  function installSkillForAgent(name, options, generateSkillMd) {
5266
5462
  const { agent, scope = "global", projectDir } = options;
5267
5463
  const skillName = normalizeSkillName(name);
5268
5464
  const sourcePath = getSkillPath(name);
5269
- if (!existsSync(sourcePath)) {
5465
+ if (!existsSync2(sourcePath)) {
5270
5466
  return { skill: name, success: false, error: `Skill '${name}' not found` };
5271
5467
  }
5272
5468
  let skillMdContent = null;
5273
- const skillMdPath = join(sourcePath, "SKILL.md");
5274
- if (existsSync(skillMdPath)) {
5275
- skillMdContent = readFileSync(skillMdPath, "utf-8");
5469
+ const skillMdPath = join2(sourcePath, "SKILL.md");
5470
+ if (existsSync2(skillMdPath)) {
5471
+ skillMdContent = readFileSync2(skillMdPath, "utf-8");
5276
5472
  } else if (generateSkillMd) {
5277
5473
  skillMdContent = generateSkillMd(name);
5278
5474
  }
@@ -5280,9 +5476,28 @@ function installSkillForAgent(name, options, generateSkillMd) {
5280
5476
  return { skill: name, success: false, error: `No SKILL.md found and could not generate one for '${name}'` };
5281
5477
  }
5282
5478
  const destDir = getAgentSkillPath(name, agent, scope, projectDir);
5479
+ if (scope === "global") {
5480
+ const agentBaseDir = agent === "pi" ? join2(homedir2(), ".pi", "agent") : join2(homedir2(), `.${agent}`);
5481
+ if (!existsSync2(agentBaseDir)) {
5482
+ return {
5483
+ skill: name,
5484
+ success: false,
5485
+ error: `Agent directory ${agentBaseDir} does not exist. Is ${AGENT_LABELS[agent]} installed?`
5486
+ };
5487
+ }
5488
+ try {
5489
+ accessSync(agentBaseDir, constants.W_OK);
5490
+ } catch {
5491
+ return {
5492
+ skill: name,
5493
+ success: false,
5494
+ error: `Agent directory ${agentBaseDir} is not writable. Check permissions.`
5495
+ };
5496
+ }
5497
+ }
5283
5498
  try {
5284
5499
  mkdirSync(destDir, { recursive: true });
5285
- writeFileSync(join(destDir, "SKILL.md"), skillMdContent);
5500
+ writeFileSync(join2(destDir, "SKILL.md"), skillMdContent);
5286
5501
  return { skill: name, success: true, path: destDir };
5287
5502
  } catch (error) {
5288
5503
  return {
@@ -5295,31 +5510,48 @@ function installSkillForAgent(name, options, generateSkillMd) {
5295
5510
  function removeSkillForAgent(name, options) {
5296
5511
  const { agent, scope = "global", projectDir } = options;
5297
5512
  const destDir = getAgentSkillPath(name, agent, scope, projectDir);
5298
- if (!existsSync(destDir)) {
5513
+ if (!existsSync2(destDir)) {
5299
5514
  return false;
5300
5515
  }
5301
5516
  rmSync(destDir, { recursive: true, force: true });
5302
5517
  return true;
5303
5518
  }
5304
- var __dirname2, SKILLS_DIR, AGENT_TARGETS;
5519
+ var __dirname2, SKILLS_DIR, AGENT_TARGETS, AGENT_LABELS;
5305
5520
  var init_installer = __esm(() => {
5306
5521
  init_registry();
5307
5522
  __dirname2 = dirname(fileURLToPath(import.meta.url));
5308
5523
  SKILLS_DIR = findSkillsDir();
5309
- AGENT_TARGETS = ["claude", "codex", "gemini"];
5524
+ AGENT_TARGETS = ["claude", "codex", "gemini", "pi", "opencode"];
5525
+ AGENT_LABELS = {
5526
+ claude: "Claude Code",
5527
+ codex: "Codex CLI",
5528
+ gemini: "Gemini CLI",
5529
+ pi: "pi.dev",
5530
+ opencode: "OpenCode"
5531
+ };
5310
5532
  });
5311
5533
 
5312
5534
  // src/lib/skillinfo.ts
5313
- import { existsSync as existsSync2, readFileSync as readFileSync2, readdirSync as readdirSync2 } from "fs";
5314
- import { join as join2 } from "path";
5535
+ var exports_skillinfo = {};
5536
+ __export(exports_skillinfo, {
5537
+ runSkill: () => runSkill,
5538
+ getSkillRequirements: () => getSkillRequirements,
5539
+ getSkillDocs: () => getSkillDocs,
5540
+ getSkillBestDoc: () => getSkillBestDoc,
5541
+ generateSkillMd: () => generateSkillMd,
5542
+ generateEnvExample: () => generateEnvExample,
5543
+ detectProjectSkills: () => detectProjectSkills
5544
+ });
5545
+ import { existsSync as existsSync3, readFileSync as readFileSync3, readdirSync as readdirSync3 } from "fs";
5546
+ import { join as join3 } from "path";
5315
5547
  function getSkillDocs(name) {
5316
5548
  const skillPath = getSkillPath(name);
5317
- if (!existsSync2(skillPath))
5549
+ if (!existsSync3(skillPath))
5318
5550
  return null;
5319
5551
  return {
5320
- skillMd: readIfExists(join2(skillPath, "SKILL.md")),
5321
- readme: readIfExists(join2(skillPath, "README.md")),
5322
- claudeMd: readIfExists(join2(skillPath, "CLAUDE.md"))
5552
+ skillMd: readIfExists(join3(skillPath, "SKILL.md")),
5553
+ readme: readIfExists(join3(skillPath, "README.md")),
5554
+ claudeMd: readIfExists(join3(skillPath, "CLAUDE.md"))
5323
5555
  };
5324
5556
  }
5325
5557
  function getSkillBestDoc(name) {
@@ -5330,11 +5562,11 @@ function getSkillBestDoc(name) {
5330
5562
  }
5331
5563
  function getSkillRequirements(name) {
5332
5564
  const skillPath = getSkillPath(name);
5333
- if (!existsSync2(skillPath))
5565
+ if (!existsSync3(skillPath))
5334
5566
  return null;
5335
5567
  const texts = [];
5336
5568
  for (const file of ["SKILL.md", "README.md", "CLAUDE.md", ".env.example", ".env.local.example"]) {
5337
- const content = readIfExists(join2(skillPath, file));
5569
+ const content = readIfExists(join3(skillPath, file));
5338
5570
  if (content)
5339
5571
  texts.push(content);
5340
5572
  }
@@ -5361,10 +5593,10 @@ function getSkillRequirements(name) {
5361
5593
  }
5362
5594
  let cliCommand = null;
5363
5595
  let dependencies = {};
5364
- const pkgPath = join2(skillPath, "package.json");
5365
- if (existsSync2(pkgPath)) {
5596
+ const pkgPath = join3(skillPath, "package.json");
5597
+ if (existsSync3(pkgPath)) {
5366
5598
  try {
5367
- const pkg = JSON.parse(readFileSync2(pkgPath, "utf-8"));
5599
+ const pkg = JSON.parse(readFileSync3(pkgPath, "utf-8"));
5368
5600
  if (pkg.bin) {
5369
5601
  const binKeys = Object.keys(pkg.bin);
5370
5602
  if (binKeys.length > 0)
@@ -5384,25 +5616,25 @@ async function runSkill(name, args, options = {}) {
5384
5616
  const skillName = normalizeSkillName(name);
5385
5617
  let skillPath;
5386
5618
  if (options.installed) {
5387
- skillPath = join2(process.cwd(), ".skills", skillName);
5619
+ skillPath = join3(process.cwd(), ".skills", skillName);
5388
5620
  } else {
5389
- const installedPath = join2(process.cwd(), ".skills", skillName);
5390
- if (existsSync2(installedPath)) {
5621
+ const installedPath = join3(process.cwd(), ".skills", skillName);
5622
+ if (existsSync3(installedPath)) {
5391
5623
  skillPath = installedPath;
5392
5624
  } else {
5393
5625
  skillPath = getSkillPath(name);
5394
5626
  }
5395
5627
  }
5396
- if (!existsSync2(skillPath)) {
5628
+ if (!existsSync3(skillPath)) {
5397
5629
  return { exitCode: 1, error: `Skill '${name}' not found` };
5398
5630
  }
5399
- const pkgPath = join2(skillPath, "package.json");
5400
- if (!existsSync2(pkgPath)) {
5631
+ const pkgPath = join3(skillPath, "package.json");
5632
+ if (!existsSync3(pkgPath)) {
5401
5633
  return { exitCode: 1, error: `No package.json in skill '${name}'` };
5402
5634
  }
5403
5635
  let entryPoint;
5404
5636
  try {
5405
- const pkg = JSON.parse(readFileSync2(pkgPath, "utf-8"));
5637
+ const pkg = JSON.parse(readFileSync3(pkgPath, "utf-8"));
5406
5638
  if (pkg.bin) {
5407
5639
  const binValues = Object.values(pkg.bin);
5408
5640
  entryPoint = binValues[0];
@@ -5416,12 +5648,12 @@ async function runSkill(name, args, options = {}) {
5416
5648
  } catch {
5417
5649
  return { exitCode: 1, error: `Failed to parse package.json for skill '${name}'` };
5418
5650
  }
5419
- const entryPath = join2(skillPath, entryPoint);
5420
- if (!existsSync2(entryPath)) {
5651
+ const entryPath = join3(skillPath, entryPoint);
5652
+ if (!existsSync3(entryPath)) {
5421
5653
  return { exitCode: 1, error: `Entry point '${entryPoint}' not found in skill '${name}'` };
5422
5654
  }
5423
- const nodeModules = join2(skillPath, "node_modules");
5424
- if (!existsSync2(nodeModules)) {
5655
+ const nodeModules = join3(skillPath, "node_modules");
5656
+ if (!existsSync3(nodeModules)) {
5425
5657
  const install = Bun.spawn(["bun", "install", "--no-save"], {
5426
5658
  cwd: skillPath,
5427
5659
  stdout: "pipe",
@@ -5439,18 +5671,18 @@ async function runSkill(name, args, options = {}) {
5439
5671
  return { exitCode };
5440
5672
  }
5441
5673
  function detectProjectSkills(cwd = process.cwd()) {
5442
- const pkgPath = join2(cwd, "package.json");
5443
- if (!existsSync2(pkgPath)) {
5674
+ const pkgPath = join3(cwd, "package.json");
5675
+ if (!existsSync3(pkgPath)) {
5444
5676
  const alwaysRecommend = ["implementation-plan", "write", "deepresearch"];
5445
- const recommended2 = alwaysRecommend.map((name) => SKILLS.find((s) => s.name === name)).filter((s) => s !== undefined);
5677
+ const recommended2 = alwaysRecommend.map((name) => loadRegistry().find((s) => s.name === name)).filter((s) => s !== undefined);
5446
5678
  return { detected: [], recommended: recommended2 };
5447
5679
  }
5448
5680
  let pkg;
5449
5681
  try {
5450
- pkg = JSON.parse(readFileSync2(pkgPath, "utf-8"));
5682
+ pkg = JSON.parse(readFileSync3(pkgPath, "utf-8"));
5451
5683
  } catch {
5452
5684
  const alwaysRecommend = ["implementation-plan", "write", "deepresearch"];
5453
- const recommended2 = alwaysRecommend.map((name) => SKILLS.find((s) => s.name === name)).filter((s) => s !== undefined);
5685
+ const recommended2 = alwaysRecommend.map((name) => loadRegistry().find((s) => s.name === name)).filter((s) => s !== undefined);
5454
5686
  return { detected: [], recommended: recommended2 };
5455
5687
  }
5456
5688
  const allDeps = {
@@ -5522,15 +5754,66 @@ function detectProjectSkills(cwd = process.cwd()) {
5522
5754
  }
5523
5755
  }
5524
5756
  const uniqueDetected = Array.from(new Set(detected));
5525
- const recommended = Array.from(recommendedNames).map((name) => SKILLS.find((s) => s.name === name)).filter((s) => s !== undefined);
5757
+ const recommended = Array.from(recommendedNames).map((name) => loadRegistry().find((s) => s.name === name)).filter((s) => s !== undefined);
5526
5758
  return { detected: uniqueDetected, recommended };
5527
5759
  }
5760
+ function generateEnvExample(targetDir = process.cwd()) {
5761
+ const skillsDir = join3(targetDir, ".skills");
5762
+ if (!existsSync3(skillsDir))
5763
+ return "";
5764
+ const dirs = readdirSync3(skillsDir).filter((f) => f.startsWith("skill-") && existsSync3(join3(skillsDir, f, "package.json")));
5765
+ const envMap = new Map;
5766
+ for (const dir of dirs) {
5767
+ const skillName = dir.replace("skill-", "");
5768
+ const skillPath = join3(skillsDir, dir);
5769
+ const texts = [];
5770
+ for (const file of ["SKILL.md", "README.md", "CLAUDE.md", ".env.example"]) {
5771
+ const content = readIfExists(join3(skillPath, file));
5772
+ if (content)
5773
+ texts.push(content);
5774
+ }
5775
+ const allText = texts.join(`
5776
+ `);
5777
+ const foundVars = extractEnvVars(allText);
5778
+ for (const envVar of foundVars) {
5779
+ if (!envMap.has(envVar)) {
5780
+ envMap.set(envVar, []);
5781
+ }
5782
+ if (!envMap.get(envVar).includes(skillName)) {
5783
+ envMap.get(envVar).push(skillName);
5784
+ }
5785
+ }
5786
+ }
5787
+ if (envMap.size === 0)
5788
+ return "";
5789
+ const lines = [
5790
+ "# Environment variables for installed skills",
5791
+ "# Auto-generated by: skills init",
5792
+ ""
5793
+ ];
5794
+ const sorted = Array.from(envMap.entries()).sort(([a], [b]) => a.localeCompare(b));
5795
+ let lastPrefix = "";
5796
+ for (const [envVar, skills] of sorted) {
5797
+ const prefix = envVar.split("_")[0];
5798
+ if (prefix !== lastPrefix) {
5799
+ if (lastPrefix)
5800
+ lines.push("");
5801
+ lines.push(`# ${prefix}`);
5802
+ lastPrefix = prefix;
5803
+ }
5804
+ lines.push(`# Used by: ${skills.join(", ")}`);
5805
+ lines.push(`${envVar}=`);
5806
+ }
5807
+ return lines.join(`
5808
+ `) + `
5809
+ `;
5810
+ }
5528
5811
  function generateSkillMd(name) {
5529
5812
  const meta = getSkill(name);
5530
5813
  if (!meta)
5531
5814
  return null;
5532
5815
  const skillPath = getSkillPath(name);
5533
- if (!existsSync2(skillPath))
5816
+ if (!existsSync3(skillPath))
5534
5817
  return null;
5535
5818
  const frontmatter = [
5536
5819
  "---",
@@ -5539,13 +5822,13 @@ function generateSkillMd(name) {
5539
5822
  "---"
5540
5823
  ].join(`
5541
5824
  `);
5542
- const readme = readIfExists(join2(skillPath, "README.md"));
5543
- const claudeMd = readIfExists(join2(skillPath, "CLAUDE.md"));
5825
+ const readme = readIfExists(join3(skillPath, "README.md"));
5826
+ const claudeMd = readIfExists(join3(skillPath, "CLAUDE.md"));
5544
5827
  let cliCommand = null;
5545
- const pkgPath = join2(skillPath, "package.json");
5546
- if (existsSync2(pkgPath)) {
5828
+ const pkgPath = join3(skillPath, "package.json");
5829
+ if (existsSync3(pkgPath)) {
5547
5830
  try {
5548
- const pkg = JSON.parse(readFileSync2(pkgPath, "utf-8"));
5831
+ const pkg = JSON.parse(readFileSync3(pkgPath, "utf-8"));
5549
5832
  if (pkg.bin) {
5550
5833
  const binKeys = Object.keys(pkg.bin);
5551
5834
  if (binKeys.length > 0)
@@ -5618,8 +5901,8 @@ function extractEnvVars(text) {
5618
5901
  }
5619
5902
  function readIfExists(path) {
5620
5903
  try {
5621
- if (existsSync2(path)) {
5622
- return readFileSync2(path, "utf-8");
5904
+ if (existsSync3(path)) {
5905
+ return readFileSync3(path, "utf-8");
5623
5906
  }
5624
5907
  } catch {}
5625
5908
  return null;
@@ -5632,7 +5915,174 @@ var init_skillinfo = __esm(() => {
5632
5915
  GENERIC_ENV_PATTERN = /\b((?:OPENAI|ANTHROPIC|GEMINI|XAI|ELEVENLABS|DEEPGRAM|REPLICATE|FAL|STABILITY|EXA|FIRECRAWL|TWILIO|SENDGRID|RESEND|SLACK|DISCORD|NOTION|LINEAR|GITHUB|AWS|GOOGLE|CLOUDFLARE|VERCEL|SUPABASE|STRIPE)_[A-Z_]+)\b/g;
5633
5916
  });
5634
5917
 
5635
- // node_modules/zod/v3/helpers/util.js
5918
+ // src/lib/scheduler.ts
5919
+ var exports_scheduler = {};
5920
+ __export(exports_scheduler, {
5921
+ validateCron: () => validateCron,
5922
+ setScheduleEnabled: () => setScheduleEnabled,
5923
+ removeSchedule: () => removeSchedule,
5924
+ recordScheduleRun: () => recordScheduleRun,
5925
+ listSchedules: () => listSchedules,
5926
+ getNextRun: () => getNextRun,
5927
+ getDueSchedules: () => getDueSchedules,
5928
+ addSchedule: () => addSchedule
5929
+ });
5930
+ import { existsSync as existsSync5, readFileSync as readFileSync5, writeFileSync as writeFileSync3, mkdirSync as mkdirSync3 } from "fs";
5931
+ import { join as join5 } from "path";
5932
+ function getSchedulesPath(targetDir = process.cwd()) {
5933
+ return join5(targetDir, ".skills", "schedules.json");
5934
+ }
5935
+ function loadSchedules(targetDir = process.cwd()) {
5936
+ const path = getSchedulesPath(targetDir);
5937
+ if (existsSync5(path)) {
5938
+ try {
5939
+ return JSON.parse(readFileSync5(path, "utf-8"));
5940
+ } catch {}
5941
+ }
5942
+ return { version: 1, schedules: [] };
5943
+ }
5944
+ function saveSchedules(data, targetDir = process.cwd()) {
5945
+ const path = getSchedulesPath(targetDir);
5946
+ const dir = join5(targetDir, ".skills");
5947
+ if (!existsSync5(dir))
5948
+ mkdirSync3(dir, { recursive: true });
5949
+ writeFileSync3(path, JSON.stringify(data, null, 2));
5950
+ }
5951
+ function validateCron(expr) {
5952
+ const fields = expr.trim().split(/\s+/);
5953
+ if (fields.length !== 5) {
5954
+ return { valid: false, error: `Expected 5 fields, got ${fields.length}. Format: "minute hour day-of-month month day-of-week"` };
5955
+ }
5956
+ return { valid: true };
5957
+ }
5958
+ function getNextRun(cron, from = new Date) {
5959
+ const { valid } = validateCron(cron);
5960
+ if (!valid)
5961
+ return null;
5962
+ const [minuteF, hourF, domF, monthF, dowF] = cron.trim().split(/\s+/);
5963
+ function parseField(f, min, max) {
5964
+ if (f === "*")
5965
+ return Array.from({ length: max - min + 1 }, (_, i) => i + min);
5966
+ if (f.startsWith("*/")) {
5967
+ const step = parseInt(f.slice(2));
5968
+ if (isNaN(step))
5969
+ return [];
5970
+ const vals = [];
5971
+ for (let i = min;i <= max; i += step)
5972
+ vals.push(i);
5973
+ return vals;
5974
+ }
5975
+ return f.split(",").flatMap((part) => {
5976
+ if (part.includes("-")) {
5977
+ const [lo, hi] = part.split("-").map(Number);
5978
+ return Array.from({ length: hi - lo + 1 }, (_, i) => i + lo);
5979
+ }
5980
+ const n = parseInt(part);
5981
+ return isNaN(n) ? [] : [n];
5982
+ });
5983
+ }
5984
+ const minutes = parseField(minuteF, 0, 59);
5985
+ const hours = parseField(hourF, 0, 23);
5986
+ const doms = parseField(domF, 1, 31);
5987
+ const months = parseField(monthF, 1, 12);
5988
+ const dows = parseField(dowF, 0, 6);
5989
+ const candidate = new Date(from);
5990
+ candidate.setSeconds(0, 0);
5991
+ candidate.setMinutes(candidate.getMinutes() + 1);
5992
+ const limit = new Date(from);
5993
+ limit.setFullYear(limit.getFullYear() + 1);
5994
+ while (candidate < limit) {
5995
+ const month = candidate.getMonth() + 1;
5996
+ const dom = candidate.getDate();
5997
+ const dow = candidate.getDay();
5998
+ const hour = candidate.getHours();
5999
+ const minute = candidate.getMinutes();
6000
+ if (!months.includes(month)) {
6001
+ candidate.setMonth(candidate.getMonth() + 1, 1);
6002
+ candidate.setHours(0, 0, 0, 0);
6003
+ continue;
6004
+ }
6005
+ if (!doms.includes(dom) || !dows.includes(dow)) {
6006
+ candidate.setDate(candidate.getDate() + 1);
6007
+ candidate.setHours(0, 0, 0, 0);
6008
+ continue;
6009
+ }
6010
+ if (!hours.includes(hour)) {
6011
+ candidate.setHours(candidate.getHours() + 1, 0, 0, 0);
6012
+ continue;
6013
+ }
6014
+ if (!minutes.includes(minute)) {
6015
+ candidate.setMinutes(candidate.getMinutes() + 1, 0, 0);
6016
+ continue;
6017
+ }
6018
+ return new Date(candidate);
6019
+ }
6020
+ return null;
6021
+ }
6022
+ function addSchedule(skill, cron, options = {}) {
6023
+ const { valid, error } = validateCron(cron);
6024
+ if (!valid)
6025
+ return { schedule: null, error };
6026
+ const data = loadSchedules(options.targetDir);
6027
+ const id = `${skill}-${Date.now()}`;
6028
+ const now = new Date;
6029
+ const nextRun = getNextRun(cron, now);
6030
+ const schedule = {
6031
+ id,
6032
+ name: options.name || `${skill} (${cron})`,
6033
+ skill,
6034
+ cron,
6035
+ args: options.args,
6036
+ enabled: true,
6037
+ createdAt: now.toISOString(),
6038
+ nextRun: nextRun?.toISOString()
6039
+ };
6040
+ data.schedules.push(schedule);
6041
+ saveSchedules(data, options.targetDir);
6042
+ return { schedule };
6043
+ }
6044
+ function listSchedules(targetDir) {
6045
+ return loadSchedules(targetDir).schedules;
6046
+ }
6047
+ function removeSchedule(idOrName, targetDir) {
6048
+ const data = loadSchedules(targetDir);
6049
+ const before = data.schedules.length;
6050
+ data.schedules = data.schedules.filter((s) => s.id !== idOrName && s.name !== idOrName);
6051
+ if (data.schedules.length === before)
6052
+ return false;
6053
+ saveSchedules(data, targetDir);
6054
+ return true;
6055
+ }
6056
+ function setScheduleEnabled(idOrName, enabled, targetDir) {
6057
+ const data = loadSchedules(targetDir);
6058
+ const schedule = data.schedules.find((s) => s.id === idOrName || s.name === idOrName);
6059
+ if (!schedule)
6060
+ return false;
6061
+ schedule.enabled = enabled;
6062
+ if (enabled) {
6063
+ schedule.nextRun = getNextRun(schedule.cron)?.toISOString();
6064
+ }
6065
+ saveSchedules(data, targetDir);
6066
+ return true;
6067
+ }
6068
+ function getDueSchedules(targetDir) {
6069
+ const now = new Date;
6070
+ return listSchedules(targetDir).filter((s) => s.enabled && s.nextRun && new Date(s.nextRun) <= now);
6071
+ }
6072
+ function recordScheduleRun(id, status, targetDir) {
6073
+ const data = loadSchedules(targetDir);
6074
+ const schedule = data.schedules.find((s) => s.id === id);
6075
+ if (!schedule)
6076
+ return;
6077
+ const now = new Date;
6078
+ schedule.lastRun = now.toISOString();
6079
+ schedule.lastRunStatus = status;
6080
+ schedule.nextRun = getNextRun(schedule.cron, now)?.toISOString();
6081
+ saveSchedules(data, targetDir);
6082
+ }
6083
+ var init_scheduler = () => {};
6084
+
6085
+ // ../../../../hasnastudio/hasnastudio-alumia/platform/platformdev/platform-alumia/node_modules/.pnpm/zod@4.3.6/node_modules/zod/v3/helpers/util.js
5636
6086
  var util, objectUtil, ZodParsedType, getParsedType = (data) => {
5637
6087
  const t = typeof data;
5638
6088
  switch (t) {
@@ -5763,7 +6213,7 @@ var init_util = __esm(() => {
5763
6213
  ]);
5764
6214
  });
5765
6215
 
5766
- // node_modules/zod/v3/ZodError.js
6216
+ // ../../../../hasnastudio/hasnastudio-alumia/platform/platformdev/platform-alumia/node_modules/.pnpm/zod@4.3.6/node_modules/zod/v3/ZodError.js
5767
6217
  var ZodIssueCode, ZodError;
5768
6218
  var init_ZodError = __esm(() => {
5769
6219
  init_util();
@@ -5881,7 +6331,7 @@ var init_ZodError = __esm(() => {
5881
6331
  };
5882
6332
  });
5883
6333
 
5884
- // node_modules/zod/v3/locales/en.js
6334
+ // ../../../../hasnastudio/hasnastudio-alumia/platform/platformdev/platform-alumia/node_modules/.pnpm/zod@4.3.6/node_modules/zod/v3/locales/en.js
5885
6335
  var errorMap = (issue, _ctx) => {
5886
6336
  let message;
5887
6337
  switch (issue.code) {
@@ -5988,7 +6438,7 @@ var init_en = __esm(() => {
5988
6438
  en_default = errorMap;
5989
6439
  });
5990
6440
 
5991
- // node_modules/zod/v3/errors.js
6441
+ // ../../../../hasnastudio/hasnastudio-alumia/platform/platformdev/platform-alumia/node_modules/.pnpm/zod@4.3.6/node_modules/zod/v3/errors.js
5992
6442
  function getErrorMap() {
5993
6443
  return overrideErrorMap;
5994
6444
  }
@@ -5998,7 +6448,7 @@ var init_errors = __esm(() => {
5998
6448
  overrideErrorMap = en_default;
5999
6449
  });
6000
6450
 
6001
- // node_modules/zod/v3/helpers/parseUtil.js
6451
+ // ../../../../hasnastudio/hasnastudio-alumia/platform/platformdev/platform-alumia/node_modules/.pnpm/zod@4.3.6/node_modules/zod/v3/helpers/parseUtil.js
6002
6452
  function addIssueToContext(ctx, issueData) {
6003
6453
  const overrideMap = getErrorMap();
6004
6454
  const issue = makeIssue({
@@ -6102,10 +6552,10 @@ var init_parseUtil = __esm(() => {
6102
6552
  });
6103
6553
  });
6104
6554
 
6105
- // node_modules/zod/v3/helpers/typeAliases.js
6555
+ // ../../../../hasnastudio/hasnastudio-alumia/platform/platformdev/platform-alumia/node_modules/.pnpm/zod@4.3.6/node_modules/zod/v3/helpers/typeAliases.js
6106
6556
  var init_typeAliases = () => {};
6107
6557
 
6108
- // node_modules/zod/v3/helpers/errorUtil.js
6558
+ // ../../../../hasnastudio/hasnastudio-alumia/platform/platformdev/platform-alumia/node_modules/.pnpm/zod@4.3.6/node_modules/zod/v3/helpers/errorUtil.js
6109
6559
  var errorUtil;
6110
6560
  var init_errorUtil = __esm(() => {
6111
6561
  (function(errorUtil2) {
@@ -6114,7 +6564,7 @@ var init_errorUtil = __esm(() => {
6114
6564
  })(errorUtil || (errorUtil = {}));
6115
6565
  });
6116
6566
 
6117
- // node_modules/zod/v3/types.js
6567
+ // ../../../../hasnastudio/hasnastudio-alumia/platform/platformdev/platform-alumia/node_modules/.pnpm/zod@4.3.6/node_modules/zod/v3/types.js
6118
6568
  class ParseInputLazyPath {
6119
6569
  constructor(parent, value, path, key) {
6120
6570
  this._cachedPath = [];
@@ -9425,7 +9875,7 @@ var init_types = __esm(() => {
9425
9875
  pipelineType = ZodPipeline.create;
9426
9876
  });
9427
9877
 
9428
- // node_modules/zod/v3/external.js
9878
+ // ../../../../hasnastudio/hasnastudio-alumia/platform/platformdev/platform-alumia/node_modules/.pnpm/zod@4.3.6/node_modules/zod/v3/external.js
9429
9879
  var init_external = __esm(() => {
9430
9880
  init_errors();
9431
9881
  init_parseUtil();
@@ -9435,12 +9885,12 @@ var init_external = __esm(() => {
9435
9885
  init_ZodError();
9436
9886
  });
9437
9887
 
9438
- // node_modules/zod/v3/index.js
9888
+ // ../../../../hasnastudio/hasnastudio-alumia/platform/platformdev/platform-alumia/node_modules/.pnpm/zod@4.3.6/node_modules/zod/v3/index.js
9439
9889
  var init_v3 = __esm(() => {
9440
9890
  init_external();
9441
9891
  });
9442
9892
 
9443
- // node_modules/zod/v4/core/core.js
9893
+ // ../../../../hasnastudio/hasnastudio-alumia/platform/platformdev/platform-alumia/node_modules/.pnpm/zod@4.3.6/node_modules/zod/v4/core/core.js
9444
9894
  function $constructor(name, initializer, params) {
9445
9895
  function init(inst, def) {
9446
9896
  if (!inst._zod) {
@@ -9518,7 +9968,7 @@ var init_core = __esm(() => {
9518
9968
  globalConfig = {};
9519
9969
  });
9520
9970
 
9521
- // node_modules/zod/v4/core/util.js
9971
+ // ../../../../hasnastudio/hasnastudio-alumia/platform/platformdev/platform-alumia/node_modules/.pnpm/zod@4.3.6/node_modules/zod/v4/core/util.js
9522
9972
  var exports_util = {};
9523
9973
  __export(exports_util, {
9524
9974
  unwrapMessage: () => unwrapMessage,
@@ -10194,7 +10644,7 @@ var init_util2 = __esm(() => {
10194
10644
  };
10195
10645
  });
10196
10646
 
10197
- // node_modules/zod/v4/core/errors.js
10647
+ // ../../../../hasnastudio/hasnastudio-alumia/platform/platformdev/platform-alumia/node_modules/.pnpm/zod@4.3.6/node_modules/zod/v4/core/errors.js
10198
10648
  function flattenError(error, mapper = (issue2) => issue2.message) {
10199
10649
  const fieldErrors = {};
10200
10650
  const formErrors = [];
@@ -10335,7 +10785,7 @@ var init_errors2 = __esm(() => {
10335
10785
  $ZodRealError = $constructor("$ZodError", initializer, { Parent: Error });
10336
10786
  });
10337
10787
 
10338
- // node_modules/zod/v4/core/parse.js
10788
+ // ../../../../hasnastudio/hasnastudio-alumia/platform/platformdev/platform-alumia/node_modules/.pnpm/zod@4.3.6/node_modules/zod/v4/core/parse.js
10339
10789
  var _parse = (_Err) => (schema, value, _ctx, _params) => {
10340
10790
  const ctx = _ctx ? Object.assign(_ctx, { async: false }) : { async: false };
10341
10791
  const result = schema._zod.run({ value, issues: [] }, ctx);
@@ -10417,7 +10867,7 @@ var init_parse = __esm(() => {
10417
10867
  safeDecodeAsync = /* @__PURE__ */ _safeDecodeAsync($ZodRealError);
10418
10868
  });
10419
10869
 
10420
- // node_modules/zod/v4/core/regexes.js
10870
+ // ../../../../hasnastudio/hasnastudio-alumia/platform/platformdev/platform-alumia/node_modules/.pnpm/zod@4.3.6/node_modules/zod/v4/core/regexes.js
10421
10871
  var exports_regexes = {};
10422
10872
  __export(exports_regexes, {
10423
10873
  xid: () => xid,
@@ -10573,7 +11023,7 @@ var init_regexes = __esm(() => {
10573
11023
  sha512_base64url = /* @__PURE__ */ fixedBase64url(86);
10574
11024
  });
10575
11025
 
10576
- // node_modules/zod/v4/core/checks.js
11026
+ // ../../../../hasnastudio/hasnastudio-alumia/platform/platformdev/platform-alumia/node_modules/.pnpm/zod@4.3.6/node_modules/zod/v4/core/checks.js
10577
11027
  function handleCheckPropertyResult(result, payload, property) {
10578
11028
  if (result.issues.length) {
10579
11029
  payload.issues.push(...prefixIssues(property, result.issues));
@@ -11126,7 +11576,7 @@ var init_checks = __esm(() => {
11126
11576
  });
11127
11577
  });
11128
11578
 
11129
- // node_modules/zod/v4/core/doc.js
11579
+ // ../../../../hasnastudio/hasnastudio-alumia/platform/platformdev/platform-alumia/node_modules/.pnpm/zod@4.3.6/node_modules/zod/v4/core/doc.js
11130
11580
  class Doc {
11131
11581
  constructor(args = []) {
11132
11582
  this.content = [];
@@ -11164,7 +11614,7 @@ class Doc {
11164
11614
  }
11165
11615
  }
11166
11616
 
11167
- // node_modules/zod/v4/core/versions.js
11617
+ // ../../../../hasnastudio/hasnastudio-alumia/platform/platformdev/platform-alumia/node_modules/.pnpm/zod@4.3.6/node_modules/zod/v4/core/versions.js
11168
11618
  var version;
11169
11619
  var init_versions = __esm(() => {
11170
11620
  version = {
@@ -11174,7 +11624,7 @@ var init_versions = __esm(() => {
11174
11624
  };
11175
11625
  });
11176
11626
 
11177
- // node_modules/zod/v4/core/schemas.js
11627
+ // ../../../../hasnastudio/hasnastudio-alumia/platform/platformdev/platform-alumia/node_modules/.pnpm/zod@4.3.6/node_modules/zod/v4/core/schemas.js
11178
11628
  function isValidBase64(data) {
11179
11629
  if (data === "")
11180
11630
  return true;
@@ -13147,7 +13597,7 @@ var init_schemas = __esm(() => {
13147
13597
  });
13148
13598
  });
13149
13599
 
13150
- // node_modules/zod/v4/locales/ar.js
13600
+ // ../../../../hasnastudio/hasnastudio-alumia/platform/platformdev/platform-alumia/node_modules/.pnpm/zod@4.3.6/node_modules/zod/v4/locales/ar.js
13151
13601
  function ar_default() {
13152
13602
  return {
13153
13603
  localeError: error()
@@ -13257,7 +13707,7 @@ var init_ar = __esm(() => {
13257
13707
  init_util2();
13258
13708
  });
13259
13709
 
13260
- // node_modules/zod/v4/locales/az.js
13710
+ // ../../../../hasnastudio/hasnastudio-alumia/platform/platformdev/platform-alumia/node_modules/.pnpm/zod@4.3.6/node_modules/zod/v4/locales/az.js
13261
13711
  function az_default() {
13262
13712
  return {
13263
13713
  localeError: error2()
@@ -13366,7 +13816,7 @@ var init_az = __esm(() => {
13366
13816
  init_util2();
13367
13817
  });
13368
13818
 
13369
- // node_modules/zod/v4/locales/be.js
13819
+ // ../../../../hasnastudio/hasnastudio-alumia/platform/platformdev/platform-alumia/node_modules/.pnpm/zod@4.3.6/node_modules/zod/v4/locales/be.js
13370
13820
  function getBelarusianPlural(count, one, few, many) {
13371
13821
  const absCount = Math.abs(count);
13372
13822
  const lastDigit = absCount % 10;
@@ -13526,7 +13976,7 @@ var init_be = __esm(() => {
13526
13976
  init_util2();
13527
13977
  });
13528
13978
 
13529
- // node_modules/zod/v4/locales/bg.js
13979
+ // ../../../../hasnastudio/hasnastudio-alumia/platform/platformdev/platform-alumia/node_modules/.pnpm/zod@4.3.6/node_modules/zod/v4/locales/bg.js
13530
13980
  function bg_default() {
13531
13981
  return {
13532
13982
  localeError: error4()
@@ -13650,7 +14100,7 @@ var init_bg = __esm(() => {
13650
14100
  init_util2();
13651
14101
  });
13652
14102
 
13653
- // node_modules/zod/v4/locales/ca.js
14103
+ // ../../../../hasnastudio/hasnastudio-alumia/platform/platformdev/platform-alumia/node_modules/.pnpm/zod@4.3.6/node_modules/zod/v4/locales/ca.js
13654
14104
  function ca_default() {
13655
14105
  return {
13656
14106
  localeError: error5()
@@ -13761,7 +14211,7 @@ var init_ca = __esm(() => {
13761
14211
  init_util2();
13762
14212
  });
13763
14213
 
13764
- // node_modules/zod/v4/locales/cs.js
14214
+ // ../../../../hasnastudio/hasnastudio-alumia/platform/platformdev/platform-alumia/node_modules/.pnpm/zod@4.3.6/node_modules/zod/v4/locales/cs.js
13765
14215
  function cs_default() {
13766
14216
  return {
13767
14217
  localeError: error6()
@@ -13876,7 +14326,7 @@ var init_cs = __esm(() => {
13876
14326
  init_util2();
13877
14327
  });
13878
14328
 
13879
- // node_modules/zod/v4/locales/da.js
14329
+ // ../../../../hasnastudio/hasnastudio-alumia/platform/platformdev/platform-alumia/node_modules/.pnpm/zod@4.3.6/node_modules/zod/v4/locales/da.js
13880
14330
  function da_default() {
13881
14331
  return {
13882
14332
  localeError: error7()
@@ -13995,7 +14445,7 @@ var init_da = __esm(() => {
13995
14445
  init_util2();
13996
14446
  });
13997
14447
 
13998
- // node_modules/zod/v4/locales/de.js
14448
+ // ../../../../hasnastudio/hasnastudio-alumia/platform/platformdev/platform-alumia/node_modules/.pnpm/zod@4.3.6/node_modules/zod/v4/locales/de.js
13999
14449
  function de_default() {
14000
14450
  return {
14001
14451
  localeError: error8()
@@ -14107,7 +14557,7 @@ var init_de = __esm(() => {
14107
14557
  init_util2();
14108
14558
  });
14109
14559
 
14110
- // node_modules/zod/v4/locales/en.js
14560
+ // ../../../../hasnastudio/hasnastudio-alumia/platform/platformdev/platform-alumia/node_modules/.pnpm/zod@4.3.6/node_modules/zod/v4/locales/en.js
14111
14561
  function en_default2() {
14112
14562
  return {
14113
14563
  localeError: error9()
@@ -14217,7 +14667,7 @@ var init_en2 = __esm(() => {
14217
14667
  init_util2();
14218
14668
  });
14219
14669
 
14220
- // node_modules/zod/v4/locales/eo.js
14670
+ // ../../../../hasnastudio/hasnastudio-alumia/platform/platformdev/platform-alumia/node_modules/.pnpm/zod@4.3.6/node_modules/zod/v4/locales/eo.js
14221
14671
  function eo_default() {
14222
14672
  return {
14223
14673
  localeError: error10()
@@ -14330,7 +14780,7 @@ var init_eo = __esm(() => {
14330
14780
  init_util2();
14331
14781
  });
14332
14782
 
14333
- // node_modules/zod/v4/locales/es.js
14783
+ // ../../../../hasnastudio/hasnastudio-alumia/platform/platformdev/platform-alumia/node_modules/.pnpm/zod@4.3.6/node_modules/zod/v4/locales/es.js
14334
14784
  function es_default() {
14335
14785
  return {
14336
14786
  localeError: error11()
@@ -14466,7 +14916,7 @@ var init_es = __esm(() => {
14466
14916
  init_util2();
14467
14917
  });
14468
14918
 
14469
- // node_modules/zod/v4/locales/fa.js
14919
+ // ../../../../hasnastudio/hasnastudio-alumia/platform/platformdev/platform-alumia/node_modules/.pnpm/zod@4.3.6/node_modules/zod/v4/locales/fa.js
14470
14920
  function fa_default() {
14471
14921
  return {
14472
14922
  localeError: error12()
@@ -14584,7 +15034,7 @@ var init_fa = __esm(() => {
14584
15034
  init_util2();
14585
15035
  });
14586
15036
 
14587
- // node_modules/zod/v4/locales/fi.js
15037
+ // ../../../../hasnastudio/hasnastudio-alumia/platform/platformdev/platform-alumia/node_modules/.pnpm/zod@4.3.6/node_modules/zod/v4/locales/fi.js
14588
15038
  function fi_default() {
14589
15039
  return {
14590
15040
  localeError: error13()
@@ -14700,7 +15150,7 @@ var init_fi = __esm(() => {
14700
15150
  init_util2();
14701
15151
  });
14702
15152
 
14703
- // node_modules/zod/v4/locales/fr.js
15153
+ // ../../../../hasnastudio/hasnastudio-alumia/platform/platformdev/platform-alumia/node_modules/.pnpm/zod@4.3.6/node_modules/zod/v4/locales/fr.js
14704
15154
  function fr_default() {
14705
15155
  return {
14706
15156
  localeError: error14()
@@ -14812,7 +15262,7 @@ var init_fr = __esm(() => {
14812
15262
  init_util2();
14813
15263
  });
14814
15264
 
14815
- // node_modules/zod/v4/locales/fr-CA.js
15265
+ // ../../../../hasnastudio/hasnastudio-alumia/platform/platformdev/platform-alumia/node_modules/.pnpm/zod@4.3.6/node_modules/zod/v4/locales/fr-CA.js
14816
15266
  function fr_CA_default() {
14817
15267
  return {
14818
15268
  localeError: error15()
@@ -14923,7 +15373,7 @@ var init_fr_CA = __esm(() => {
14923
15373
  init_util2();
14924
15374
  });
14925
15375
 
14926
- // node_modules/zod/v4/locales/he.js
15376
+ // ../../../../hasnastudio/hasnastudio-alumia/platform/platformdev/platform-alumia/node_modules/.pnpm/zod@4.3.6/node_modules/zod/v4/locales/he.js
14927
15377
  function he_default() {
14928
15378
  return {
14929
15379
  localeError: error16()
@@ -15120,7 +15570,7 @@ var init_he = __esm(() => {
15120
15570
  init_util2();
15121
15571
  });
15122
15572
 
15123
- // node_modules/zod/v4/locales/hu.js
15573
+ // ../../../../hasnastudio/hasnastudio-alumia/platform/platformdev/platform-alumia/node_modules/.pnpm/zod@4.3.6/node_modules/zod/v4/locales/hu.js
15124
15574
  function hu_default() {
15125
15575
  return {
15126
15576
  localeError: error17()
@@ -15232,7 +15682,7 @@ var init_hu = __esm(() => {
15232
15682
  init_util2();
15233
15683
  });
15234
15684
 
15235
- // node_modules/zod/v4/locales/hy.js
15685
+ // ../../../../hasnastudio/hasnastudio-alumia/platform/platformdev/platform-alumia/node_modules/.pnpm/zod@4.3.6/node_modules/zod/v4/locales/hy.js
15236
15686
  function getArmenianPlural(count, one, many) {
15237
15687
  return Math.abs(count) === 1 ? one : many;
15238
15688
  }
@@ -15383,7 +15833,7 @@ var init_hy = __esm(() => {
15383
15833
  init_util2();
15384
15834
  });
15385
15835
 
15386
- // node_modules/zod/v4/locales/id.js
15836
+ // ../../../../hasnastudio/hasnastudio-alumia/platform/platformdev/platform-alumia/node_modules/.pnpm/zod@4.3.6/node_modules/zod/v4/locales/id.js
15387
15837
  function id_default() {
15388
15838
  return {
15389
15839
  localeError: error19()
@@ -15493,7 +15943,7 @@ var init_id = __esm(() => {
15493
15943
  init_util2();
15494
15944
  });
15495
15945
 
15496
- // node_modules/zod/v4/locales/is.js
15946
+ // ../../../../hasnastudio/hasnastudio-alumia/platform/platformdev/platform-alumia/node_modules/.pnpm/zod@4.3.6/node_modules/zod/v4/locales/is.js
15497
15947
  function is_default() {
15498
15948
  return {
15499
15949
  localeError: error20()
@@ -15606,7 +16056,7 @@ var init_is = __esm(() => {
15606
16056
  init_util2();
15607
16057
  });
15608
16058
 
15609
- // node_modules/zod/v4/locales/it.js
16059
+ // ../../../../hasnastudio/hasnastudio-alumia/platform/platformdev/platform-alumia/node_modules/.pnpm/zod@4.3.6/node_modules/zod/v4/locales/it.js
15610
16060
  function it_default() {
15611
16061
  return {
15612
16062
  localeError: error21()
@@ -15718,7 +16168,7 @@ var init_it = __esm(() => {
15718
16168
  init_util2();
15719
16169
  });
15720
16170
 
15721
- // node_modules/zod/v4/locales/ja.js
16171
+ // ../../../../hasnastudio/hasnastudio-alumia/platform/platformdev/platform-alumia/node_modules/.pnpm/zod@4.3.6/node_modules/zod/v4/locales/ja.js
15722
16172
  function ja_default() {
15723
16173
  return {
15724
16174
  localeError: error22()
@@ -15829,7 +16279,7 @@ var init_ja = __esm(() => {
15829
16279
  init_util2();
15830
16280
  });
15831
16281
 
15832
- // node_modules/zod/v4/locales/ka.js
16282
+ // ../../../../hasnastudio/hasnastudio-alumia/platform/platformdev/platform-alumia/node_modules/.pnpm/zod@4.3.6/node_modules/zod/v4/locales/ka.js
15833
16283
  function ka_default() {
15834
16284
  return {
15835
16285
  localeError: error23()
@@ -15945,7 +16395,7 @@ var init_ka = __esm(() => {
15945
16395
  init_util2();
15946
16396
  });
15947
16397
 
15948
- // node_modules/zod/v4/locales/km.js
16398
+ // ../../../../hasnastudio/hasnastudio-alumia/platform/platformdev/platform-alumia/node_modules/.pnpm/zod@4.3.6/node_modules/zod/v4/locales/km.js
15949
16399
  function km_default() {
15950
16400
  return {
15951
16401
  localeError: error24()
@@ -16059,7 +16509,7 @@ var init_km = __esm(() => {
16059
16509
  init_util2();
16060
16510
  });
16061
16511
 
16062
- // node_modules/zod/v4/locales/kh.js
16512
+ // ../../../../hasnastudio/hasnastudio-alumia/platform/platformdev/platform-alumia/node_modules/.pnpm/zod@4.3.6/node_modules/zod/v4/locales/kh.js
16063
16513
  function kh_default() {
16064
16514
  return km_default();
16065
16515
  }
@@ -16067,7 +16517,7 @@ var init_kh = __esm(() => {
16067
16517
  init_km();
16068
16518
  });
16069
16519
 
16070
- // node_modules/zod/v4/locales/ko.js
16520
+ // ../../../../hasnastudio/hasnastudio-alumia/platform/platformdev/platform-alumia/node_modules/.pnpm/zod@4.3.6/node_modules/zod/v4/locales/ko.js
16071
16521
  function ko_default() {
16072
16522
  return {
16073
16523
  localeError: error25()
@@ -16182,7 +16632,7 @@ var init_ko = __esm(() => {
16182
16632
  init_util2();
16183
16633
  });
16184
16634
 
16185
- // node_modules/zod/v4/locales/lt.js
16635
+ // ../../../../hasnastudio/hasnastudio-alumia/platform/platformdev/platform-alumia/node_modules/.pnpm/zod@4.3.6/node_modules/zod/v4/locales/lt.js
16186
16636
  function getUnitTypeFromNumber(number2) {
16187
16637
  const abs = Math.abs(number2);
16188
16638
  const last = abs % 10;
@@ -16388,7 +16838,7 @@ var init_lt = __esm(() => {
16388
16838
  init_util2();
16389
16839
  });
16390
16840
 
16391
- // node_modules/zod/v4/locales/mk.js
16841
+ // ../../../../hasnastudio/hasnastudio-alumia/platform/platformdev/platform-alumia/node_modules/.pnpm/zod@4.3.6/node_modules/zod/v4/locales/mk.js
16392
16842
  function mk_default() {
16393
16843
  return {
16394
16844
  localeError: error27()
@@ -16501,7 +16951,7 @@ var init_mk = __esm(() => {
16501
16951
  init_util2();
16502
16952
  });
16503
16953
 
16504
- // node_modules/zod/v4/locales/ms.js
16954
+ // ../../../../hasnastudio/hasnastudio-alumia/platform/platformdev/platform-alumia/node_modules/.pnpm/zod@4.3.6/node_modules/zod/v4/locales/ms.js
16505
16955
  function ms_default() {
16506
16956
  return {
16507
16957
  localeError: error28()
@@ -16612,7 +17062,7 @@ var init_ms = __esm(() => {
16612
17062
  init_util2();
16613
17063
  });
16614
17064
 
16615
- // node_modules/zod/v4/locales/nl.js
17065
+ // ../../../../hasnastudio/hasnastudio-alumia/platform/platformdev/platform-alumia/node_modules/.pnpm/zod@4.3.6/node_modules/zod/v4/locales/nl.js
16616
17066
  function nl_default() {
16617
17067
  return {
16618
17068
  localeError: error29()
@@ -16726,7 +17176,7 @@ var init_nl = __esm(() => {
16726
17176
  init_util2();
16727
17177
  });
16728
17178
 
16729
- // node_modules/zod/v4/locales/no.js
17179
+ // ../../../../hasnastudio/hasnastudio-alumia/platform/platformdev/platform-alumia/node_modules/.pnpm/zod@4.3.6/node_modules/zod/v4/locales/no.js
16730
17180
  function no_default() {
16731
17181
  return {
16732
17182
  localeError: error30()
@@ -16838,7 +17288,7 @@ var init_no = __esm(() => {
16838
17288
  init_util2();
16839
17289
  });
16840
17290
 
16841
- // node_modules/zod/v4/locales/ota.js
17291
+ // ../../../../hasnastudio/hasnastudio-alumia/platform/platformdev/platform-alumia/node_modules/.pnpm/zod@4.3.6/node_modules/zod/v4/locales/ota.js
16842
17292
  function ota_default() {
16843
17293
  return {
16844
17294
  localeError: error31()
@@ -16951,7 +17401,7 @@ var init_ota = __esm(() => {
16951
17401
  init_util2();
16952
17402
  });
16953
17403
 
16954
- // node_modules/zod/v4/locales/ps.js
17404
+ // ../../../../hasnastudio/hasnastudio-alumia/platform/platformdev/platform-alumia/node_modules/.pnpm/zod@4.3.6/node_modules/zod/v4/locales/ps.js
16955
17405
  function ps_default() {
16956
17406
  return {
16957
17407
  localeError: error32()
@@ -17069,7 +17519,7 @@ var init_ps = __esm(() => {
17069
17519
  init_util2();
17070
17520
  });
17071
17521
 
17072
- // node_modules/zod/v4/locales/pl.js
17522
+ // ../../../../hasnastudio/hasnastudio-alumia/platform/platformdev/platform-alumia/node_modules/.pnpm/zod@4.3.6/node_modules/zod/v4/locales/pl.js
17073
17523
  function pl_default() {
17074
17524
  return {
17075
17525
  localeError: error33()
@@ -17182,7 +17632,7 @@ var init_pl = __esm(() => {
17182
17632
  init_util2();
17183
17633
  });
17184
17634
 
17185
- // node_modules/zod/v4/locales/pt.js
17635
+ // ../../../../hasnastudio/hasnastudio-alumia/platform/platformdev/platform-alumia/node_modules/.pnpm/zod@4.3.6/node_modules/zod/v4/locales/pt.js
17186
17636
  function pt_default() {
17187
17637
  return {
17188
17638
  localeError: error34()
@@ -17294,7 +17744,7 @@ var init_pt = __esm(() => {
17294
17744
  init_util2();
17295
17745
  });
17296
17746
 
17297
- // node_modules/zod/v4/locales/ru.js
17747
+ // ../../../../hasnastudio/hasnastudio-alumia/platform/platformdev/platform-alumia/node_modules/.pnpm/zod@4.3.6/node_modules/zod/v4/locales/ru.js
17298
17748
  function getRussianPlural(count, one, few, many) {
17299
17749
  const absCount = Math.abs(count);
17300
17750
  const lastDigit = absCount % 10;
@@ -17454,7 +17904,7 @@ var init_ru = __esm(() => {
17454
17904
  init_util2();
17455
17905
  });
17456
17906
 
17457
- // node_modules/zod/v4/locales/sl.js
17907
+ // ../../../../hasnastudio/hasnastudio-alumia/platform/platformdev/platform-alumia/node_modules/.pnpm/zod@4.3.6/node_modules/zod/v4/locales/sl.js
17458
17908
  function sl_default() {
17459
17909
  return {
17460
17910
  localeError: error36()
@@ -17567,7 +18017,7 @@ var init_sl = __esm(() => {
17567
18017
  init_util2();
17568
18018
  });
17569
18019
 
17570
- // node_modules/zod/v4/locales/sv.js
18020
+ // ../../../../hasnastudio/hasnastudio-alumia/platform/platformdev/platform-alumia/node_modules/.pnpm/zod@4.3.6/node_modules/zod/v4/locales/sv.js
17571
18021
  function sv_default() {
17572
18022
  return {
17573
18023
  localeError: error37()
@@ -17681,7 +18131,7 @@ var init_sv = __esm(() => {
17681
18131
  init_util2();
17682
18132
  });
17683
18133
 
17684
- // node_modules/zod/v4/locales/ta.js
18134
+ // ../../../../hasnastudio/hasnastudio-alumia/platform/platformdev/platform-alumia/node_modules/.pnpm/zod@4.3.6/node_modules/zod/v4/locales/ta.js
17685
18135
  function ta_default() {
17686
18136
  return {
17687
18137
  localeError: error38()
@@ -17795,7 +18245,7 @@ var init_ta = __esm(() => {
17795
18245
  init_util2();
17796
18246
  });
17797
18247
 
17798
- // node_modules/zod/v4/locales/th.js
18248
+ // ../../../../hasnastudio/hasnastudio-alumia/platform/platformdev/platform-alumia/node_modules/.pnpm/zod@4.3.6/node_modules/zod/v4/locales/th.js
17799
18249
  function th_default() {
17800
18250
  return {
17801
18251
  localeError: error39()
@@ -17909,7 +18359,7 @@ var init_th = __esm(() => {
17909
18359
  init_util2();
17910
18360
  });
17911
18361
 
17912
- // node_modules/zod/v4/locales/tr.js
18362
+ // ../../../../hasnastudio/hasnastudio-alumia/platform/platformdev/platform-alumia/node_modules/.pnpm/zod@4.3.6/node_modules/zod/v4/locales/tr.js
17913
18363
  function tr_default() {
17914
18364
  return {
17915
18365
  localeError: error40()
@@ -18018,7 +18468,7 @@ var init_tr = __esm(() => {
18018
18468
  init_util2();
18019
18469
  });
18020
18470
 
18021
- // node_modules/zod/v4/locales/uk.js
18471
+ // ../../../../hasnastudio/hasnastudio-alumia/platform/platformdev/platform-alumia/node_modules/.pnpm/zod@4.3.6/node_modules/zod/v4/locales/uk.js
18022
18472
  function uk_default() {
18023
18473
  return {
18024
18474
  localeError: error41()
@@ -18130,7 +18580,7 @@ var init_uk = __esm(() => {
18130
18580
  init_util2();
18131
18581
  });
18132
18582
 
18133
- // node_modules/zod/v4/locales/ua.js
18583
+ // ../../../../hasnastudio/hasnastudio-alumia/platform/platformdev/platform-alumia/node_modules/.pnpm/zod@4.3.6/node_modules/zod/v4/locales/ua.js
18134
18584
  function ua_default() {
18135
18585
  return uk_default();
18136
18586
  }
@@ -18138,7 +18588,7 @@ var init_ua = __esm(() => {
18138
18588
  init_uk();
18139
18589
  });
18140
18590
 
18141
- // node_modules/zod/v4/locales/ur.js
18591
+ // ../../../../hasnastudio/hasnastudio-alumia/platform/platformdev/platform-alumia/node_modules/.pnpm/zod@4.3.6/node_modules/zod/v4/locales/ur.js
18142
18592
  function ur_default() {
18143
18593
  return {
18144
18594
  localeError: error42()
@@ -18252,7 +18702,7 @@ var init_ur = __esm(() => {
18252
18702
  init_util2();
18253
18703
  });
18254
18704
 
18255
- // node_modules/zod/v4/locales/uz.js
18705
+ // ../../../../hasnastudio/hasnastudio-alumia/platform/platformdev/platform-alumia/node_modules/.pnpm/zod@4.3.6/node_modules/zod/v4/locales/uz.js
18256
18706
  function uz_default() {
18257
18707
  return {
18258
18708
  localeError: error43()
@@ -18365,7 +18815,7 @@ var init_uz = __esm(() => {
18365
18815
  init_util2();
18366
18816
  });
18367
18817
 
18368
- // node_modules/zod/v4/locales/vi.js
18818
+ // ../../../../hasnastudio/hasnastudio-alumia/platform/platformdev/platform-alumia/node_modules/.pnpm/zod@4.3.6/node_modules/zod/v4/locales/vi.js
18369
18819
  function vi_default() {
18370
18820
  return {
18371
18821
  localeError: error44()
@@ -18477,7 +18927,7 @@ var init_vi = __esm(() => {
18477
18927
  init_util2();
18478
18928
  });
18479
18929
 
18480
- // node_modules/zod/v4/locales/zh-CN.js
18930
+ // ../../../../hasnastudio/hasnastudio-alumia/platform/platformdev/platform-alumia/node_modules/.pnpm/zod@4.3.6/node_modules/zod/v4/locales/zh-CN.js
18481
18931
  function zh_CN_default() {
18482
18932
  return {
18483
18933
  localeError: error45()
@@ -18590,7 +19040,7 @@ var init_zh_CN = __esm(() => {
18590
19040
  init_util2();
18591
19041
  });
18592
19042
 
18593
- // node_modules/zod/v4/locales/zh-TW.js
19043
+ // ../../../../hasnastudio/hasnastudio-alumia/platform/platformdev/platform-alumia/node_modules/.pnpm/zod@4.3.6/node_modules/zod/v4/locales/zh-TW.js
18594
19044
  function zh_TW_default() {
18595
19045
  return {
18596
19046
  localeError: error46()
@@ -18701,7 +19151,7 @@ var init_zh_TW = __esm(() => {
18701
19151
  init_util2();
18702
19152
  });
18703
19153
 
18704
- // node_modules/zod/v4/locales/yo.js
19154
+ // ../../../../hasnastudio/hasnastudio-alumia/platform/platformdev/platform-alumia/node_modules/.pnpm/zod@4.3.6/node_modules/zod/v4/locales/yo.js
18705
19155
  function yo_default() {
18706
19156
  return {
18707
19157
  localeError: error47()
@@ -18812,7 +19262,7 @@ var init_yo = __esm(() => {
18812
19262
  init_util2();
18813
19263
  });
18814
19264
 
18815
- // node_modules/zod/v4/locales/index.js
19265
+ // ../../../../hasnastudio/hasnastudio-alumia/platform/platformdev/platform-alumia/node_modules/.pnpm/zod@4.3.6/node_modules/zod/v4/locales/index.js
18816
19266
  var exports_locales = {};
18817
19267
  __export(exports_locales, {
18818
19268
  zhTW: () => zh_TW_default,
@@ -18917,7 +19367,7 @@ var init_locales = __esm(() => {
18917
19367
  init_yo();
18918
19368
  });
18919
19369
 
18920
- // node_modules/zod/v4/core/registries.js
19370
+ // ../../../../hasnastudio/hasnastudio-alumia/platform/platformdev/platform-alumia/node_modules/.pnpm/zod@4.3.6/node_modules/zod/v4/core/registries.js
18921
19371
  class $ZodRegistry {
18922
19372
  constructor() {
18923
19373
  this._map = new WeakMap;
@@ -18969,7 +19419,7 @@ var init_registries = __esm(() => {
18969
19419
  globalRegistry = globalThis.__zod_globalRegistry;
18970
19420
  });
18971
19421
 
18972
- // node_modules/zod/v4/core/api.js
19422
+ // ../../../../hasnastudio/hasnastudio-alumia/platform/platformdev/platform-alumia/node_modules/.pnpm/zod@4.3.6/node_modules/zod/v4/core/api.js
18973
19423
  function _string(Class2, params) {
18974
19424
  return new Class2({
18975
19425
  type: "string",
@@ -19897,7 +20347,7 @@ var init_api = __esm(() => {
19897
20347
  };
19898
20348
  });
19899
20349
 
19900
- // node_modules/zod/v4/core/to-json-schema.js
20350
+ // ../../../../hasnastudio/hasnastudio-alumia/platform/platformdev/platform-alumia/node_modules/.pnpm/zod@4.3.6/node_modules/zod/v4/core/to-json-schema.js
19901
20351
  function initializeContext(params) {
19902
20352
  let target = params?.target ?? "draft-2020-12";
19903
20353
  if (target === "draft-4")
@@ -20245,7 +20695,7 @@ var init_to_json_schema = __esm(() => {
20245
20695
  init_registries();
20246
20696
  });
20247
20697
 
20248
- // node_modules/zod/v4/core/json-schema-processors.js
20698
+ // ../../../../hasnastudio/hasnastudio-alumia/platform/platformdev/platform-alumia/node_modules/.pnpm/zod@4.3.6/node_modules/zod/v4/core/json-schema-processors.js
20249
20699
  function toJSONSchema(input, params) {
20250
20700
  if ("_idmap" in input) {
20251
20701
  const registry2 = input;
@@ -20757,7 +21207,7 @@ var init_json_schema_processors = __esm(() => {
20757
21207
  };
20758
21208
  });
20759
21209
 
20760
- // node_modules/zod/v4/core/json-schema-generator.js
21210
+ // ../../../../hasnastudio/hasnastudio-alumia/platform/platformdev/platform-alumia/node_modules/.pnpm/zod@4.3.6/node_modules/zod/v4/core/json-schema-generator.js
20761
21211
  class JSONSchemaGenerator {
20762
21212
  get metadataRegistry() {
20763
21213
  return this.ctx.metadataRegistry;
@@ -20821,11 +21271,11 @@ var init_json_schema_generator = __esm(() => {
20821
21271
  init_to_json_schema();
20822
21272
  });
20823
21273
 
20824
- // node_modules/zod/v4/core/json-schema.js
21274
+ // ../../../../hasnastudio/hasnastudio-alumia/platform/platformdev/platform-alumia/node_modules/.pnpm/zod@4.3.6/node_modules/zod/v4/core/json-schema.js
20825
21275
  var exports_json_schema = {};
20826
21276
  var init_json_schema = () => {};
20827
21277
 
20828
- // node_modules/zod/v4/core/index.js
21278
+ // ../../../../hasnastudio/hasnastudio-alumia/platform/platformdev/platform-alumia/node_modules/.pnpm/zod@4.3.6/node_modules/zod/v4/core/index.js
20829
21279
  var exports_core2 = {};
20830
21280
  __export(exports_core2, {
20831
21281
  version: () => version,
@@ -21120,12 +21570,12 @@ var init_core2 = __esm(() => {
21120
21570
  init_to_json_schema();
21121
21571
  });
21122
21572
 
21123
- // node_modules/zod/v4/mini/parse.js
21573
+ // ../../../../hasnastudio/hasnastudio-alumia/platform/platformdev/platform-alumia/node_modules/.pnpm/zod@4.3.6/node_modules/zod/v4/mini/parse.js
21124
21574
  var init_parse2 = __esm(() => {
21125
21575
  init_core2();
21126
21576
  });
21127
21577
 
21128
- // node_modules/zod/v4/mini/schemas.js
21578
+ // ../../../../hasnastudio/hasnastudio-alumia/platform/platformdev/platform-alumia/node_modules/.pnpm/zod@4.3.6/node_modules/zod/v4/mini/schemas.js
21129
21579
  function object(shape, params) {
21130
21580
  const def = {
21131
21581
  type: "object",
@@ -21174,16 +21624,16 @@ var init_schemas2 = __esm(() => {
21174
21624
  });
21175
21625
  });
21176
21626
 
21177
- // node_modules/zod/v4/mini/checks.js
21627
+ // ../../../../hasnastudio/hasnastudio-alumia/platform/platformdev/platform-alumia/node_modules/.pnpm/zod@4.3.6/node_modules/zod/v4/mini/checks.js
21178
21628
  var init_checks2 = () => {};
21179
21629
 
21180
- // node_modules/zod/v4/mini/iso.js
21630
+ // ../../../../hasnastudio/hasnastudio-alumia/platform/platformdev/platform-alumia/node_modules/.pnpm/zod@4.3.6/node_modules/zod/v4/mini/iso.js
21181
21631
  var init_iso = () => {};
21182
21632
 
21183
- // node_modules/zod/v4/mini/coerce.js
21633
+ // ../../../../hasnastudio/hasnastudio-alumia/platform/platformdev/platform-alumia/node_modules/.pnpm/zod@4.3.6/node_modules/zod/v4/mini/coerce.js
21184
21634
  var init_coerce = () => {};
21185
21635
 
21186
- // node_modules/zod/v4/mini/external.js
21636
+ // ../../../../hasnastudio/hasnastudio-alumia/platform/platformdev/platform-alumia/node_modules/.pnpm/zod@4.3.6/node_modules/zod/v4/mini/external.js
21187
21637
  var init_external2 = __esm(() => {
21188
21638
  init_core2();
21189
21639
  init_json_schema_processors();
@@ -21195,7 +21645,7 @@ var init_external2 = __esm(() => {
21195
21645
  init_checks2();
21196
21646
  });
21197
21647
 
21198
- // node_modules/zod/v4-mini/index.js
21648
+ // ../../../../hasnastudio/hasnastudio-alumia/platform/platformdev/platform-alumia/node_modules/.pnpm/zod@4.3.6/node_modules/zod/v4-mini/index.js
21199
21649
  var init_v4_mini = __esm(() => {
21200
21650
  init_external2();
21201
21651
  });
@@ -21348,7 +21798,7 @@ var init_zod_compat = __esm(() => {
21348
21798
  init_v4_mini();
21349
21799
  });
21350
21800
 
21351
- // node_modules/zod/v4/classic/checks.js
21801
+ // ../../../../hasnastudio/hasnastudio-alumia/platform/platformdev/platform-alumia/node_modules/.pnpm/zod@4.3.6/node_modules/zod/v4/classic/checks.js
21352
21802
  var exports_checks2 = {};
21353
21803
  __export(exports_checks2, {
21354
21804
  uppercase: () => _uppercase,
@@ -21385,7 +21835,7 @@ var init_checks3 = __esm(() => {
21385
21835
  init_core2();
21386
21836
  });
21387
21837
 
21388
- // node_modules/zod/v4/classic/iso.js
21838
+ // ../../../../hasnastudio/hasnastudio-alumia/platform/platformdev/platform-alumia/node_modules/.pnpm/zod@4.3.6/node_modules/zod/v4/classic/iso.js
21389
21839
  var exports_iso2 = {};
21390
21840
  __export(exports_iso2, {
21391
21841
  time: () => time2,
@@ -21431,7 +21881,7 @@ var init_iso2 = __esm(() => {
21431
21881
  });
21432
21882
  });
21433
21883
 
21434
- // node_modules/zod/v4/classic/errors.js
21884
+ // ../../../../hasnastudio/hasnastudio-alumia/platform/platformdev/platform-alumia/node_modules/.pnpm/zod@4.3.6/node_modules/zod/v4/classic/errors.js
21435
21885
  var initializer2 = (inst, issues) => {
21436
21886
  $ZodError.init(inst, issues);
21437
21887
  inst.name = "ZodError";
@@ -21471,7 +21921,7 @@ var init_errors3 = __esm(() => {
21471
21921
  });
21472
21922
  });
21473
21923
 
21474
- // node_modules/zod/v4/classic/parse.js
21924
+ // ../../../../hasnastudio/hasnastudio-alumia/platform/platformdev/platform-alumia/node_modules/.pnpm/zod@4.3.6/node_modules/zod/v4/classic/parse.js
21475
21925
  var parse4, parseAsync2, safeParse3, safeParseAsync3, encode2, decode2, encodeAsync2, decodeAsync2, safeEncode2, safeDecode2, safeEncodeAsync2, safeDecodeAsync2;
21476
21926
  var init_parse3 = __esm(() => {
21477
21927
  init_core2();
@@ -21490,7 +21940,7 @@ var init_parse3 = __esm(() => {
21490
21940
  safeDecodeAsync2 = /* @__PURE__ */ _safeDecodeAsync(ZodRealError);
21491
21941
  });
21492
21942
 
21493
- // node_modules/zod/v4/classic/schemas.js
21943
+ // ../../../../hasnastudio/hasnastudio-alumia/platform/platformdev/platform-alumia/node_modules/.pnpm/zod@4.3.6/node_modules/zod/v4/classic/schemas.js
21494
21944
  var exports_schemas2 = {};
21495
21945
  __export(exports_schemas2, {
21496
21946
  xor: () => xor,
@@ -22743,7 +23193,7 @@ var init_schemas3 = __esm(() => {
22743
23193
  meta2 = meta;
22744
23194
  });
22745
23195
 
22746
- // node_modules/zod/v4/classic/compat.js
23196
+ // ../../../../hasnastudio/hasnastudio-alumia/platform/platformdev/platform-alumia/node_modules/.pnpm/zod@4.3.6/node_modules/zod/v4/classic/compat.js
22747
23197
  function setErrorMap(map2) {
22748
23198
  config({
22749
23199
  customError: map2
@@ -22771,7 +23221,7 @@ var init_compat = __esm(() => {
22771
23221
  (function(ZodFirstPartyTypeKind3) {})(ZodFirstPartyTypeKind2 || (ZodFirstPartyTypeKind2 = {}));
22772
23222
  });
22773
23223
 
22774
- // node_modules/zod/v4/classic/from-json-schema.js
23224
+ // ../../../../hasnastudio/hasnastudio-alumia/platform/platformdev/platform-alumia/node_modules/.pnpm/zod@4.3.6/node_modules/zod/v4/classic/from-json-schema.js
22775
23225
  function detectVersion(schema, defaultTarget) {
22776
23226
  const $schema = schema.$schema;
22777
23227
  if ($schema === "https://json-schema.org/draft/2020-12/schema") {
@@ -23240,7 +23690,7 @@ var init_from_json_schema = __esm(() => {
23240
23690
  ]);
23241
23691
  });
23242
23692
 
23243
- // node_modules/zod/v4/classic/coerce.js
23693
+ // ../../../../hasnastudio/hasnastudio-alumia/platform/platformdev/platform-alumia/node_modules/.pnpm/zod@4.3.6/node_modules/zod/v4/classic/coerce.js
23244
23694
  var exports_coerce2 = {};
23245
23695
  __export(exports_coerce2, {
23246
23696
  string: () => string3,
@@ -23269,7 +23719,7 @@ var init_coerce2 = __esm(() => {
23269
23719
  init_schemas3();
23270
23720
  });
23271
23721
 
23272
- // node_modules/zod/v4/classic/external.js
23722
+ // ../../../../hasnastudio/hasnastudio-alumia/platform/platformdev/platform-alumia/node_modules/.pnpm/zod@4.3.6/node_modules/zod/v4/classic/external.js
23273
23723
  var exports_external = {};
23274
23724
  __export(exports_external, {
23275
23725
  xor: () => xor,
@@ -23528,12 +23978,12 @@ var init_external3 = __esm(() => {
23528
23978
  config(en_default2());
23529
23979
  });
23530
23980
 
23531
- // node_modules/zod/v4/classic/index.js
23981
+ // ../../../../hasnastudio/hasnastudio-alumia/platform/platformdev/platform-alumia/node_modules/.pnpm/zod@4.3.6/node_modules/zod/v4/classic/index.js
23532
23982
  var init_classic = __esm(() => {
23533
23983
  init_external3();
23534
23984
  });
23535
23985
 
23536
- // node_modules/zod/v4/index.js
23986
+ // ../../../../hasnastudio/hasnastudio-alumia/platform/platformdev/platform-alumia/node_modules/.pnpm/zod@4.3.6/node_modules/zod/v4/index.js
23537
23987
  var init_v4 = __esm(() => {
23538
23988
  init_classic();
23539
23989
  });
@@ -27041,11 +27491,11 @@ var require_codegen = __commonJS((exports) => {
27041
27491
  const rhs = this.rhs === undefined ? "" : ` = ${this.rhs}`;
27042
27492
  return `${varKind} ${this.name}${rhs};` + _n;
27043
27493
  }
27044
- optimizeNames(names, constants) {
27494
+ optimizeNames(names, constants2) {
27045
27495
  if (!names[this.name.str])
27046
27496
  return;
27047
27497
  if (this.rhs)
27048
- this.rhs = optimizeExpr(this.rhs, names, constants);
27498
+ this.rhs = optimizeExpr(this.rhs, names, constants2);
27049
27499
  return this;
27050
27500
  }
27051
27501
  get names() {
@@ -27063,10 +27513,10 @@ var require_codegen = __commonJS((exports) => {
27063
27513
  render({ _n }) {
27064
27514
  return `${this.lhs} = ${this.rhs};` + _n;
27065
27515
  }
27066
- optimizeNames(names, constants) {
27516
+ optimizeNames(names, constants2) {
27067
27517
  if (this.lhs instanceof code_1.Name && !names[this.lhs.str] && !this.sideEffects)
27068
27518
  return;
27069
- this.rhs = optimizeExpr(this.rhs, names, constants);
27519
+ this.rhs = optimizeExpr(this.rhs, names, constants2);
27070
27520
  return this;
27071
27521
  }
27072
27522
  get names() {
@@ -27132,8 +27582,8 @@ var require_codegen = __commonJS((exports) => {
27132
27582
  optimizeNodes() {
27133
27583
  return `${this.code}` ? this : undefined;
27134
27584
  }
27135
- optimizeNames(names, constants) {
27136
- this.code = optimizeExpr(this.code, names, constants);
27585
+ optimizeNames(names, constants2) {
27586
+ this.code = optimizeExpr(this.code, names, constants2);
27137
27587
  return this;
27138
27588
  }
27139
27589
  get names() {
@@ -27163,12 +27613,12 @@ var require_codegen = __commonJS((exports) => {
27163
27613
  }
27164
27614
  return nodes.length > 0 ? this : undefined;
27165
27615
  }
27166
- optimizeNames(names, constants) {
27616
+ optimizeNames(names, constants2) {
27167
27617
  const { nodes } = this;
27168
27618
  let i = nodes.length;
27169
27619
  while (i--) {
27170
27620
  const n = nodes[i];
27171
- if (n.optimizeNames(names, constants))
27621
+ if (n.optimizeNames(names, constants2))
27172
27622
  continue;
27173
27623
  subtractNames(names, n.names);
27174
27624
  nodes.splice(i, 1);
@@ -27225,12 +27675,12 @@ var require_codegen = __commonJS((exports) => {
27225
27675
  return;
27226
27676
  return this;
27227
27677
  }
27228
- optimizeNames(names, constants) {
27678
+ optimizeNames(names, constants2) {
27229
27679
  var _a2;
27230
- this.else = (_a2 = this.else) === null || _a2 === undefined ? undefined : _a2.optimizeNames(names, constants);
27231
- if (!(super.optimizeNames(names, constants) || this.else))
27680
+ this.else = (_a2 = this.else) === null || _a2 === undefined ? undefined : _a2.optimizeNames(names, constants2);
27681
+ if (!(super.optimizeNames(names, constants2) || this.else))
27232
27682
  return;
27233
- this.condition = optimizeExpr(this.condition, names, constants);
27683
+ this.condition = optimizeExpr(this.condition, names, constants2);
27234
27684
  return this;
27235
27685
  }
27236
27686
  get names() {
@@ -27255,10 +27705,10 @@ var require_codegen = __commonJS((exports) => {
27255
27705
  render(opts) {
27256
27706
  return `for(${this.iteration})` + super.render(opts);
27257
27707
  }
27258
- optimizeNames(names, constants) {
27259
- if (!super.optimizeNames(names, constants))
27708
+ optimizeNames(names, constants2) {
27709
+ if (!super.optimizeNames(names, constants2))
27260
27710
  return;
27261
- this.iteration = optimizeExpr(this.iteration, names, constants);
27711
+ this.iteration = optimizeExpr(this.iteration, names, constants2);
27262
27712
  return this;
27263
27713
  }
27264
27714
  get names() {
@@ -27296,10 +27746,10 @@ var require_codegen = __commonJS((exports) => {
27296
27746
  render(opts) {
27297
27747
  return `for(${this.varKind} ${this.name} ${this.loop} ${this.iterable})` + super.render(opts);
27298
27748
  }
27299
- optimizeNames(names, constants) {
27300
- if (!super.optimizeNames(names, constants))
27749
+ optimizeNames(names, constants2) {
27750
+ if (!super.optimizeNames(names, constants2))
27301
27751
  return;
27302
- this.iterable = optimizeExpr(this.iterable, names, constants);
27752
+ this.iterable = optimizeExpr(this.iterable, names, constants2);
27303
27753
  return this;
27304
27754
  }
27305
27755
  get names() {
@@ -27344,11 +27794,11 @@ var require_codegen = __commonJS((exports) => {
27344
27794
  (_b = this.finally) === null || _b === undefined || _b.optimizeNodes();
27345
27795
  return this;
27346
27796
  }
27347
- optimizeNames(names, constants) {
27797
+ optimizeNames(names, constants2) {
27348
27798
  var _a2, _b;
27349
- super.optimizeNames(names, constants);
27350
- (_a2 = this.catch) === null || _a2 === undefined || _a2.optimizeNames(names, constants);
27351
- (_b = this.finally) === null || _b === undefined || _b.optimizeNames(names, constants);
27799
+ super.optimizeNames(names, constants2);
27800
+ (_a2 = this.catch) === null || _a2 === undefined || _a2.optimizeNames(names, constants2);
27801
+ (_b = this.finally) === null || _b === undefined || _b.optimizeNames(names, constants2);
27352
27802
  return this;
27353
27803
  }
27354
27804
  get names() {
@@ -27622,7 +28072,7 @@ var require_codegen = __commonJS((exports) => {
27622
28072
  function addExprNames(names, from) {
27623
28073
  return from instanceof code_1._CodeOrName ? addNames(names, from.names) : names;
27624
28074
  }
27625
- function optimizeExpr(expr, names, constants) {
28075
+ function optimizeExpr(expr, names, constants2) {
27626
28076
  if (expr instanceof code_1.Name)
27627
28077
  return replaceName(expr);
27628
28078
  if (!canOptimize(expr))
@@ -27637,14 +28087,14 @@ var require_codegen = __commonJS((exports) => {
27637
28087
  return items;
27638
28088
  }, []));
27639
28089
  function replaceName(n) {
27640
- const c = constants[n.str];
28090
+ const c = constants2[n.str];
27641
28091
  if (c === undefined || names[n.str] !== 1)
27642
28092
  return n;
27643
28093
  delete names[n.str];
27644
28094
  return c;
27645
28095
  }
27646
28096
  function canOptimize(e) {
27647
- return e instanceof code_1._Code && e._items.some((c) => c instanceof code_1.Name && names[c.str] === 1 && constants[c.str] !== undefined);
28097
+ return e instanceof code_1._Code && e._items.some((c) => c instanceof code_1.Name && names[c.str] === 1 && constants2[c.str] !== undefined);
27648
28098
  }
27649
28099
  }
27650
28100
  function subtractNames(names, from) {
@@ -32913,7 +33363,7 @@ var require_formats = __commonJS((exports) => {
32913
33363
  }
32914
33364
  var TIME = /^(\d\d):(\d\d):(\d\d(?:\.\d+)?)(z|([+-])(\d\d)(?::?(\d\d))?)?$/i;
32915
33365
  function getTime(strictTimeZone) {
32916
- return function time(str) {
33366
+ return function time3(str) {
32917
33367
  const matches = TIME.exec(str);
32918
33368
  if (!matches)
32919
33369
  return false;
@@ -33177,62 +33627,6 @@ class ExperimentalServerTasks {
33177
33627
  requestStream(request, resultSchema, options) {
33178
33628
  return this._server.requestStream(request, resultSchema, options);
33179
33629
  }
33180
- createMessageStream(params, options) {
33181
- const clientCapabilities = this._server.getClientCapabilities();
33182
- if ((params.tools || params.toolChoice) && !clientCapabilities?.sampling?.tools) {
33183
- throw new Error("Client does not support sampling tools capability.");
33184
- }
33185
- if (params.messages.length > 0) {
33186
- const lastMessage = params.messages[params.messages.length - 1];
33187
- const lastContent = Array.isArray(lastMessage.content) ? lastMessage.content : [lastMessage.content];
33188
- const hasToolResults = lastContent.some((c) => c.type === "tool_result");
33189
- const previousMessage = params.messages.length > 1 ? params.messages[params.messages.length - 2] : undefined;
33190
- const previousContent = previousMessage ? Array.isArray(previousMessage.content) ? previousMessage.content : [previousMessage.content] : [];
33191
- const hasPreviousToolUse = previousContent.some((c) => c.type === "tool_use");
33192
- if (hasToolResults) {
33193
- if (lastContent.some((c) => c.type !== "tool_result")) {
33194
- throw new Error("The last message must contain only tool_result content if any is present");
33195
- }
33196
- if (!hasPreviousToolUse) {
33197
- throw new Error("tool_result blocks are not matching any tool_use from the previous message");
33198
- }
33199
- }
33200
- if (hasPreviousToolUse) {
33201
- const toolUseIds = new Set(previousContent.filter((c) => c.type === "tool_use").map((c) => c.id));
33202
- const toolResultIds = new Set(lastContent.filter((c) => c.type === "tool_result").map((c) => c.toolUseId));
33203
- if (toolUseIds.size !== toolResultIds.size || ![...toolUseIds].every((id) => toolResultIds.has(id))) {
33204
- throw new Error("ids of tool_result blocks and tool_use blocks from previous message do not match");
33205
- }
33206
- }
33207
- }
33208
- return this.requestStream({
33209
- method: "sampling/createMessage",
33210
- params
33211
- }, CreateMessageResultSchema, options);
33212
- }
33213
- elicitInputStream(params, options) {
33214
- const clientCapabilities = this._server.getClientCapabilities();
33215
- const mode = params.mode ?? "form";
33216
- switch (mode) {
33217
- case "url": {
33218
- if (!clientCapabilities?.elicitation?.url) {
33219
- throw new Error("Client does not support url elicitation.");
33220
- }
33221
- break;
33222
- }
33223
- case "form": {
33224
- if (!clientCapabilities?.elicitation?.form) {
33225
- throw new Error("Client does not support form elicitation.");
33226
- }
33227
- break;
33228
- }
33229
- }
33230
- const normalizedParams = mode === "form" && params.mode === undefined ? { ...params, mode: "form" } : params;
33231
- return this.requestStream({
33232
- method: "elicitation/create",
33233
- params: normalizedParams
33234
- }, ElicitResultSchema, options);
33235
- }
33236
33630
  async getTask(taskId, options) {
33237
33631
  return this._server.getTask({ taskId }, options);
33238
33632
  }
@@ -33246,9 +33640,6 @@ class ExperimentalServerTasks {
33246
33640
  return this._server.cancelTask({ taskId }, options);
33247
33641
  }
33248
33642
  }
33249
- var init_server = __esm(() => {
33250
- init_types2();
33251
- });
33252
33643
 
33253
33644
  // node_modules/@modelcontextprotocol/sdk/dist/esm/experimental/tasks/helpers.js
33254
33645
  function assertToolsCallTaskCapability(requests, method, entityName) {
@@ -33287,12 +33678,11 @@ function assertClientRequestTaskCapability(requests, method, entityName) {
33287
33678
 
33288
33679
  // node_modules/@modelcontextprotocol/sdk/dist/esm/server/index.js
33289
33680
  var Server;
33290
- var init_server2 = __esm(() => {
33681
+ var init_server = __esm(() => {
33291
33682
  init_protocol();
33292
33683
  init_types2();
33293
33684
  init_ajv_provider();
33294
33685
  init_zod_compat();
33295
- init_server();
33296
33686
  Server = class Server extends Protocol {
33297
33687
  constructor(_serverInfo, options) {
33298
33688
  super(options);
@@ -33932,7 +34322,7 @@ class ExperimentalMcpServerTasks {
33932
34322
  }
33933
34323
  }
33934
34324
 
33935
- // node_modules/zod/index.js
34325
+ // ../../../../hasnastudio/hasnastudio-alumia/platform/platformdev/platform-alumia/node_modules/.pnpm/zod@4.3.6/node_modules/zod/index.js
33936
34326
  var init_zod = __esm(() => {
33937
34327
  init_external3();
33938
34328
  init_external3();
@@ -34665,7 +35055,7 @@ function createCompletionResult(suggestions) {
34665
35055
  }
34666
35056
  var EMPTY_OBJECT_JSON_SCHEMA, EMPTY_COMPLETION_RESULT;
34667
35057
  var init_mcp = __esm(() => {
34668
- init_server2();
35058
+ init_server();
34669
35059
  init_zod_compat();
34670
35060
  init_zod_json_schema_compat();
34671
35061
  init_types2();
@@ -34782,17 +35172,39 @@ var init_stdio2 = __esm(() => {
34782
35172
 
34783
35173
  // src/mcp/index.ts
34784
35174
  var exports_mcp = {};
34785
- import { existsSync as existsSync3, readdirSync as readdirSync3, statSync as statSync2 } from "fs";
34786
- import { join as join3 } from "path";
34787
- import { homedir as homedir2 } from "os";
35175
+ import { existsSync as existsSync6, readdirSync as readdirSync4, statSync as statSync2 } from "fs";
35176
+ import { join as join6 } from "path";
34788
35177
  function stripNulls(obj) {
34789
35178
  return Object.fromEntries(Object.entries(obj).filter(([, v]) => v !== null && v !== undefined && !(Array.isArray(v) && v.length === 0)));
34790
35179
  }
35180
+ function cacheGet(key) {
35181
+ return searchCache.get(key);
35182
+ }
35183
+ function cacheSet(key, value) {
35184
+ if (searchCache.size >= CACHE_MAX) {
35185
+ const first = searchCache.keys().next().value;
35186
+ if (first !== undefined)
35187
+ searchCache.delete(first);
35188
+ }
35189
+ searchCache.set(key, value);
35190
+ }
35191
+ function cacheClear() {
35192
+ searchCache.clear();
35193
+ }
35194
+ function mcpError(code, message, suggestions) {
35195
+ const obj = { code, message };
35196
+ if (suggestions && suggestions.length > 0)
35197
+ obj.suggestions = suggestions;
35198
+ return {
35199
+ content: [{ type: "text", text: JSON.stringify(obj) }],
35200
+ isError: true
35201
+ };
35202
+ }
34791
35203
  async function main() {
34792
35204
  const transport = new StdioServerTransport;
34793
35205
  await server.connect(transport);
34794
35206
  }
34795
- var server;
35207
+ var server, searchCache, CACHE_MAX = 100, _agentReg;
34796
35208
  var init_mcp2 = __esm(() => {
34797
35209
  init_mcp();
34798
35210
  init_stdio2();
@@ -34801,34 +35213,71 @@ var init_mcp2 = __esm(() => {
34801
35213
  init_registry();
34802
35214
  init_installer();
34803
35215
  init_skillinfo();
35216
+ init_scheduler();
34804
35217
  server = new McpServer({
34805
35218
  name: "skills",
34806
35219
  version: package_default.version
34807
35220
  });
35221
+ searchCache = new Map;
34808
35222
  server.registerTool("list_skills", {
34809
35223
  title: "List Skills",
34810
- description: "List skills. Returns {name,category} by default; detail:true for full objects.",
35224
+ description: "List skills. Returns {name,category} by default; detail:true for full objects. Supports limit/offset pagination.",
34811
35225
  inputSchema: {
34812
35226
  category: exports_external.string().optional(),
34813
- detail: exports_external.boolean().optional()
35227
+ detail: exports_external.boolean().optional(),
35228
+ limit: exports_external.number().optional(),
35229
+ offset: exports_external.number().optional()
35230
+ }
35231
+ }, async ({ category, detail, limit, offset }) => {
35232
+ const skills = category ? getSkillsByCategory(category) : loadRegistry();
35233
+ const mapped = detail ? skills : skills.map((s) => ({ name: s.name, category: s.category }));
35234
+ if (limit !== undefined || offset !== undefined) {
35235
+ const start = offset || 0;
35236
+ const sliced = limit !== undefined ? mapped.slice(start, start + limit) : mapped.slice(start);
35237
+ return {
35238
+ content: [{ type: "text", text: JSON.stringify({ skills: sliced, total: mapped.length, offset: start, limit: limit ?? null }) }]
35239
+ };
34814
35240
  }
34815
- }, async ({ category, detail }) => {
34816
- const skills = category ? getSkillsByCategory(category) : SKILLS;
34817
- const result = detail ? skills : skills.map((s) => ({ name: s.name, category: s.category }));
34818
35241
  return {
34819
- content: [{ type: "text", text: JSON.stringify(result) }]
35242
+ content: [{ type: "text", text: JSON.stringify(mapped) }]
35243
+ };
35244
+ });
35245
+ server.registerTool("list_installed_skills", {
35246
+ title: "List Installed Skills",
35247
+ description: "List skills installed in the current project's .skills/ directory.",
35248
+ inputSchema: {
35249
+ directory: exports_external.string().optional()
35250
+ }
35251
+ }, async ({ directory }) => {
35252
+ const dir = directory || process.cwd();
35253
+ const installed = getInstalledSkills(dir);
35254
+ return {
35255
+ content: [{ type: "text", text: JSON.stringify({ directory: dir, count: installed.length, skills: installed }) }]
34820
35256
  };
34821
35257
  });
34822
35258
  server.registerTool("search_skills", {
34823
35259
  title: "Search Skills",
34824
- description: "Search skills by name, description, or tags. Returns compact list by default.",
35260
+ description: "Search skills by name, description, or tags. Returns compact list by default. Supports limit/offset pagination.",
34825
35261
  inputSchema: {
34826
35262
  query: exports_external.string(),
34827
- detail: exports_external.boolean().optional()
34828
- }
34829
- }, async ({ query, detail }) => {
34830
- const results = searchSkills(query);
35263
+ detail: exports_external.boolean().optional(),
35264
+ limit: exports_external.number().optional(),
35265
+ offset: exports_external.number().optional()
35266
+ }
35267
+ }, async ({ query, detail, limit, offset }) => {
35268
+ const cacheKey = `${query}:${detail ?? false}`;
35269
+ const cached2 = cacheGet(cacheKey);
35270
+ const results = cached2 ? cached2 : searchSkills(query);
35271
+ if (!cached2)
35272
+ cacheSet(cacheKey, results);
34831
35273
  const out = detail ? results : results.map((s) => ({ name: s.name, category: s.category }));
35274
+ if (limit !== undefined || offset !== undefined) {
35275
+ const start = offset || 0;
35276
+ const sliced = limit !== undefined ? out.slice(start, start + limit) : out.slice(start);
35277
+ return {
35278
+ content: [{ type: "text", text: JSON.stringify({ skills: sliced, total: out.length, offset: start, limit: limit ?? null }) }]
35279
+ };
35280
+ }
34832
35281
  return {
34833
35282
  content: [{ type: "text", text: JSON.stringify(out) }]
34834
35283
  };
@@ -34842,7 +35291,7 @@ var init_mcp2 = __esm(() => {
34842
35291
  }, async ({ name }) => {
34843
35292
  const skill = getSkill(name);
34844
35293
  if (!skill) {
34845
- return { content: [{ type: "text", text: `Skill '${name}' not found` }], isError: true };
35294
+ return mcpError("SKILL_NOT_FOUND", `Skill '${name}' not found`, findSimilarSkills(name));
34846
35295
  }
34847
35296
  const reqs = getSkillRequirements(name);
34848
35297
  const result = stripNulls({ ...skill, ...reqs });
@@ -34859,13 +35308,13 @@ var init_mcp2 = __esm(() => {
34859
35308
  }, async ({ name }) => {
34860
35309
  const doc2 = getSkillBestDoc(name);
34861
35310
  if (!doc2) {
34862
- return { content: [{ type: "text", text: `No documentation found for '${name}'` }], isError: true };
35311
+ return mcpError("NO_DOCS", `No documentation found for '${name}'`);
34863
35312
  }
34864
35313
  return { content: [{ type: "text", text: doc2 }] };
34865
35314
  });
34866
35315
  server.registerTool("install_skill", {
34867
35316
  title: "Install Skill",
34868
- description: "Install a skill to .skills/ or to an agent dir (for: claude|codex|gemini|all).",
35317
+ description: "Install a skill to .skills/ or to an agent dir (for: claude|codex|gemini|pi|opencode|all).",
34869
35318
  inputSchema: {
34870
35319
  name: exports_external.string(),
34871
35320
  for: exports_external.string().optional(),
@@ -34877,10 +35326,7 @@ var init_mcp2 = __esm(() => {
34877
35326
  try {
34878
35327
  agents = resolveAgents(agentArg);
34879
35328
  } catch (err) {
34880
- return {
34881
- content: [{ type: "text", text: err.message }],
34882
- isError: true
34883
- };
35329
+ return mcpError("INVALID_AGENT", err.message, [...AGENT_TARGETS, "all"]);
34884
35330
  }
34885
35331
  const results = agents.map((a) => installSkillForAgent(name, { agent: a, scope: scope || "global" }, generateSkillMd));
34886
35332
  return {
@@ -34889,6 +35335,8 @@ var init_mcp2 = __esm(() => {
34889
35335
  };
34890
35336
  }
34891
35337
  const result = installSkill(name);
35338
+ if (result.success)
35339
+ cacheClear();
34892
35340
  return {
34893
35341
  content: [{ type: "text", text: JSON.stringify(result, null, 2) }],
34894
35342
  isError: !result.success
@@ -34906,8 +35354,7 @@ var init_mcp2 = __esm(() => {
34906
35354
  const matchedCategory = CATEGORIES.find((c) => c.toLowerCase() === category.toLowerCase());
34907
35355
  if (!matchedCategory) {
34908
35356
  return {
34909
- content: [{ type: "text", text: `Unknown category: ${category}. Available: ${CATEGORIES.join(", ")}` }],
34910
- isError: true
35357
+ ...mcpError("UNKNOWN_CATEGORY", `Unknown category: ${category}`, CATEGORIES.slice())
34911
35358
  };
34912
35359
  }
34913
35360
  const categorySkills = getSkillsByCategory(matchedCategory);
@@ -34917,10 +35364,7 @@ var init_mcp2 = __esm(() => {
34917
35364
  try {
34918
35365
  agents = resolveAgents(agentArg);
34919
35366
  } catch (err) {
34920
- return {
34921
- content: [{ type: "text", text: err.message }],
34922
- isError: true
34923
- };
35367
+ return mcpError("INVALID_AGENT", err.message, [...AGENT_TARGETS, "all"]);
34924
35368
  }
34925
35369
  const results2 = [];
34926
35370
  for (const name of names) {
@@ -34954,10 +35398,7 @@ var init_mcp2 = __esm(() => {
34954
35398
  try {
34955
35399
  agents = resolveAgents(agentArg);
34956
35400
  } catch (err) {
34957
- return {
34958
- content: [{ type: "text", text: err.message }],
34959
- isError: true
34960
- };
35401
+ return mcpError("INVALID_AGENT", err.message, [...AGENT_TARGETS, "all"]);
34961
35402
  }
34962
35403
  const results = agents.map((a) => ({
34963
35404
  skill: name,
@@ -34969,6 +35410,8 @@ var init_mcp2 = __esm(() => {
34969
35410
  };
34970
35411
  }
34971
35412
  const removed = removeSkill(name);
35413
+ if (removed)
35414
+ cacheClear();
34972
35415
  return {
34973
35416
  content: [{ type: "text", text: JSON.stringify({ skill: name, removed }, null, 2) }]
34974
35417
  };
@@ -34988,7 +35431,7 @@ var init_mcp2 = __esm(() => {
34988
35431
  description: "List all unique skill tags with occurrence counts."
34989
35432
  }, async () => {
34990
35433
  const tagCounts = new Map;
34991
- for (const skill of SKILLS) {
35434
+ for (const skill of loadRegistry()) {
34992
35435
  for (const tag of skill.tags) {
34993
35436
  tagCounts.set(tag, (tagCounts.get(tag) ?? 0) + 1);
34994
35437
  }
@@ -35005,7 +35448,7 @@ var init_mcp2 = __esm(() => {
35005
35448
  }, async ({ name }) => {
35006
35449
  const reqs = getSkillRequirements(name);
35007
35450
  if (!reqs) {
35008
- return { content: [{ type: "text", text: `Skill '${name}' not found` }], isError: true };
35451
+ return mcpError("SKILL_NOT_FOUND", `Skill '${name}' not found`, findSimilarSkills(name));
35009
35452
  }
35010
35453
  return { content: [{ type: "text", text: JSON.stringify(reqs, null, 2) }] };
35011
35454
  });
@@ -35019,7 +35462,7 @@ var init_mcp2 = __esm(() => {
35019
35462
  }, async ({ name, args }) => {
35020
35463
  const skill = getSkill(name);
35021
35464
  if (!skill) {
35022
- return { content: [{ type: "text", text: `Skill '${name}' not found` }], isError: true };
35465
+ return mcpError("SKILL_NOT_FOUND", `Skill '${name}' not found`, findSimilarSkills(name));
35023
35466
  }
35024
35467
  const result = await runSkill(name, args || []);
35025
35468
  if (result.error) {
@@ -35062,10 +35505,7 @@ var init_mcp2 = __esm(() => {
35062
35505
  try {
35063
35506
  agents = resolveAgents(agentArg);
35064
35507
  } catch (err) {
35065
- return {
35066
- content: [{ type: "text", text: err.message }],
35067
- isError: true
35068
- };
35508
+ return mcpError("INVALID_AGENT", err.message, [...AGENT_TARGETS, "all"]);
35069
35509
  }
35070
35510
  for (const name of skillList) {
35071
35511
  const agentResults = agents.map((a) => installSkillForAgent(name, { agent: a, scope: scope || "global" }, generateSkillMd));
@@ -35093,21 +35533,20 @@ var init_mcp2 = __esm(() => {
35093
35533
  const version2 = package_default.version;
35094
35534
  const cwd = process.cwd();
35095
35535
  const installed = getInstalledSkills();
35096
- const agentNames = ["claude", "codex", "gemini"];
35097
35536
  const agents = [];
35098
- for (const agent of agentNames) {
35099
- const agentSkillsPath = join3(homedir2(), `.${agent}`, "skills");
35100
- const exists = existsSync3(agentSkillsPath);
35537
+ for (const agent of AGENT_TARGETS) {
35538
+ const agentSkillsPath = getAgentSkillsDir(agent, "global");
35539
+ const exists = existsSync6(agentSkillsPath);
35101
35540
  let skillCount = 0;
35102
35541
  if (exists) {
35103
35542
  try {
35104
- skillCount = readdirSync3(agentSkillsPath).filter((f) => {
35105
- const full = join3(agentSkillsPath, f);
35543
+ skillCount = readdirSync4(agentSkillsPath).filter((f) => {
35544
+ const full = join6(agentSkillsPath, f);
35106
35545
  return f.startsWith("skill-") && statSync2(full).isDirectory();
35107
35546
  }).length;
35108
35547
  } catch {}
35109
35548
  }
35110
- agents.push({ agent, path: agentSkillsPath, exists, skillCount });
35549
+ agents.push({ agent, label: AGENT_LABELS[agent], path: agentSkillsPath, exists, skillCount });
35111
35550
  }
35112
35551
  const skillsDir = getSkillPath("image").replace(/[/\\][^/\\]*$/, "");
35113
35552
  const result = {
@@ -35120,12 +35559,107 @@ var init_mcp2 = __esm(() => {
35120
35559
  };
35121
35560
  return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
35122
35561
  });
35562
+ server.registerTool("schedule_skill", {
35563
+ title: "Schedule Skill",
35564
+ description: "Add a cron schedule to run a skill at a recurring time. Cron format: 'minute hour dom month dow' (e.g. '0 9 * * *' = daily at 9am).",
35565
+ inputSchema: {
35566
+ skill: exports_external.string(),
35567
+ cron: exports_external.string(),
35568
+ name: exports_external.string().optional(),
35569
+ args: exports_external.array(exports_external.string()).optional()
35570
+ }
35571
+ }, async ({ skill, cron, name, args }) => {
35572
+ const { schedule, error: error48 } = addSchedule(skill, cron, { name, args });
35573
+ if (error48 || !schedule) {
35574
+ return { content: [{ type: "text", text: JSON.stringify({ error: error48 || "Failed to add schedule" }) }] };
35575
+ }
35576
+ return { content: [{ type: "text", text: JSON.stringify(schedule, null, 2) }] };
35577
+ });
35578
+ server.registerTool("list_schedules", {
35579
+ title: "List Schedules",
35580
+ description: "List all scheduled skill runs.",
35581
+ inputSchema: {}
35582
+ }, async () => {
35583
+ const schedules = listSchedules();
35584
+ return { content: [{ type: "text", text: JSON.stringify(schedules, null, 2) }] };
35585
+ });
35586
+ server.registerTool("remove_schedule", {
35587
+ title: "Remove Schedule",
35588
+ description: "Remove a schedule by its ID or name.",
35589
+ inputSchema: {
35590
+ id_or_name: exports_external.string()
35591
+ }
35592
+ }, async ({ id_or_name }) => {
35593
+ const removed = removeSchedule(id_or_name);
35594
+ return { content: [{ type: "text", text: JSON.stringify({ removed, id_or_name }) }] };
35595
+ });
35596
+ server.registerTool("detect_project_skills", {
35597
+ title: "Detect Project Skills",
35598
+ description: "Detect project type from package.json and return recommended skills based on dependencies.",
35599
+ inputSchema: {
35600
+ directory: exports_external.string().optional()
35601
+ }
35602
+ }, async ({ directory }) => {
35603
+ const cwd = directory || process.cwd();
35604
+ const { detected, recommended } = detectProjectSkills(cwd);
35605
+ return {
35606
+ content: [{
35607
+ type: "text",
35608
+ text: JSON.stringify({
35609
+ directory: cwd,
35610
+ detected,
35611
+ recommended: recommended.map((s) => ({ name: s.name, displayName: s.displayName, description: s.description, category: s.category }))
35612
+ }, null, 2)
35613
+ }]
35614
+ };
35615
+ });
35616
+ server.registerTool("validate_skill", {
35617
+ title: "Validate Skill",
35618
+ description: "Check a skill's structure: SKILL.md, package.json with bin entry, tsconfig.json, src/index.ts. Returns validation result with list of issues.",
35619
+ inputSchema: {
35620
+ name: exports_external.string()
35621
+ }
35622
+ }, async ({ name }) => {
35623
+ const skillPath = getSkillPath(name);
35624
+ const issues = [];
35625
+ if (!existsSync6(skillPath)) {
35626
+ return {
35627
+ content: [{ type: "text", text: JSON.stringify({ name, valid: false, issues: [`Skill directory not found: ${skillPath}`] }) }]
35628
+ };
35629
+ }
35630
+ if (!existsSync6(join6(skillPath, "SKILL.md")))
35631
+ issues.push("Missing SKILL.md");
35632
+ if (!existsSync6(join6(skillPath, "tsconfig.json")))
35633
+ issues.push("Missing tsconfig.json");
35634
+ const pkgPath = join6(skillPath, "package.json");
35635
+ if (!existsSync6(pkgPath)) {
35636
+ issues.push("Missing package.json");
35637
+ } else {
35638
+ try {
35639
+ const pkg = JSON.parse(__require("fs").readFileSync(pkgPath, "utf-8"));
35640
+ if (!pkg.bin || Object.keys(pkg.bin).length === 0)
35641
+ issues.push("package.json missing 'bin' entry");
35642
+ } catch {
35643
+ issues.push("package.json is invalid JSON");
35644
+ }
35645
+ }
35646
+ const srcDir = join6(skillPath, "src");
35647
+ if (!existsSync6(srcDir)) {
35648
+ issues.push("Missing src/ directory");
35649
+ } else if (!existsSync6(join6(srcDir, "index.ts"))) {
35650
+ issues.push("Missing src/index.ts");
35651
+ }
35652
+ const valid = issues.length === 0;
35653
+ return {
35654
+ content: [{ type: "text", text: JSON.stringify({ name, valid, path: skillPath, issues }) }]
35655
+ };
35656
+ });
35123
35657
  server.registerResource("Skills Registry", "skills://registry", {
35124
35658
  description: "Compact skill list [{name,category}]. Use skills://{name} for detail."
35125
35659
  }, async () => ({
35126
35660
  contents: [{
35127
35661
  uri: "skills://registry",
35128
- text: JSON.stringify(SKILLS.map((s) => ({ name: s.name, category: s.category }))),
35662
+ text: JSON.stringify(loadRegistry().map((s) => ({ name: s.name, category: s.category }))),
35129
35663
  mimeType: "application/json"
35130
35664
  }]
35131
35665
  }));
@@ -35150,6 +35684,7 @@ var init_mcp2 = __esm(() => {
35150
35684
  }, async ({ query }) => {
35151
35685
  const all = [
35152
35686
  "list_skills",
35687
+ "list_installed_skills",
35153
35688
  "search_skills",
35154
35689
  "get_skill_info",
35155
35690
  "get_skill_docs",
@@ -35176,6 +35711,7 @@ var init_mcp2 = __esm(() => {
35176
35711
  }, async ({ names }) => {
35177
35712
  const descriptions = {
35178
35713
  list_skills: "List skills {name,category}. Params: category?, detail?",
35714
+ list_installed_skills: "List installed skills in .skills/. Params: directory?",
35179
35715
  search_skills: "Search skills by name/tags. Params: query, detail?",
35180
35716
  get_skill_info: "Get skill metadata and env vars. Params: name",
35181
35717
  get_skill_docs: "Get skill documentation. Params: name",
@@ -35194,6 +35730,32 @@ var init_mcp2 = __esm(() => {
35194
35730
  `);
35195
35731
  return { content: [{ type: "text", text: result }] };
35196
35732
  });
35733
+ _agentReg = new Map;
35734
+ server.tool("register_agent", "Register this agent session. Returns agent_id for use in heartbeat/set_focus.", { name: exports_external.string(), session_id: exports_external.string().optional() }, async (a) => {
35735
+ const existing = [..._agentReg.values()].find((x) => x.name === a.name);
35736
+ if (existing) {
35737
+ existing.last_seen_at = new Date().toISOString();
35738
+ return { content: [{ type: "text", text: JSON.stringify(existing) }] };
35739
+ }
35740
+ const id = Math.random().toString(36).slice(2, 10);
35741
+ const ag = { id, name: a.name, last_seen_at: new Date().toISOString() };
35742
+ _agentReg.set(id, ag);
35743
+ return { content: [{ type: "text", text: JSON.stringify(ag) }] };
35744
+ });
35745
+ server.tool("heartbeat", "Update last_seen_at to signal agent is active.", { agent_id: exports_external.string() }, async (a) => {
35746
+ const ag = _agentReg.get(a.agent_id);
35747
+ if (!ag)
35748
+ return { content: [{ type: "text", text: `Agent not found: ${a.agent_id}` }], isError: true };
35749
+ ag.last_seen_at = new Date().toISOString();
35750
+ return { content: [{ type: "text", text: `\u2665 ${ag.name} \u2014 active` }] };
35751
+ });
35752
+ server.tool("set_focus", "Set active project context for this agent session.", { agent_id: exports_external.string(), project_id: exports_external.string().optional() }, async (a) => {
35753
+ const ag = _agentReg.get(a.agent_id);
35754
+ if (!ag)
35755
+ return { content: [{ type: "text", text: `Agent not found: ${a.agent_id}` }], isError: true };
35756
+ ag.project_id = a.project_id;
35757
+ return { content: [{ type: "text", text: a.project_id ? `Focus: ${a.project_id}` : "Focus cleared" }] };
35758
+ });
35197
35759
  main().catch((error48) => {
35198
35760
  console.error("MCP server error:", error48);
35199
35761
  process.exit(1);
@@ -35206,16 +35768,16 @@ __export(exports_serve, {
35206
35768
  startServer: () => startServer,
35207
35769
  createFetchHandler: () => createFetchHandler
35208
35770
  });
35209
- import { existsSync as existsSync4, readFileSync as readFileSync3 } from "fs";
35210
- import { join as join4, dirname as dirname2, extname } from "path";
35771
+ import { existsSync as existsSync7, readFileSync as readFileSync6 } from "fs";
35772
+ import { join as join7, dirname as dirname3, extname } from "path";
35211
35773
  import { fileURLToPath as fileURLToPath2 } from "url";
35212
35774
  function getPackageJson() {
35213
35775
  try {
35214
- const scriptDir = dirname2(fileURLToPath2(import.meta.url));
35776
+ const scriptDir = dirname3(fileURLToPath2(import.meta.url));
35215
35777
  for (const rel of ["../..", ".."]) {
35216
- const pkgPath = join4(scriptDir, rel, "package.json");
35217
- if (existsSync4(pkgPath)) {
35218
- const pkg = JSON.parse(readFileSync3(pkgPath, "utf-8"));
35778
+ const pkgPath = join7(scriptDir, rel, "package.json");
35779
+ if (existsSync7(pkgPath)) {
35780
+ const pkg = JSON.parse(readFileSync6(pkgPath, "utf-8"));
35219
35781
  return { version: pkg.version || "unknown", name: pkg.name || "skills" };
35220
35782
  }
35221
35783
  }
@@ -35225,27 +35787,28 @@ function getPackageJson() {
35225
35787
  function resolveDashboardDir() {
35226
35788
  const candidates = [];
35227
35789
  try {
35228
- const scriptDir = dirname2(fileURLToPath2(import.meta.url));
35229
- candidates.push(join4(scriptDir, "..", "dashboard", "dist"));
35230
- candidates.push(join4(scriptDir, "..", "..", "dashboard", "dist"));
35790
+ const scriptDir = dirname3(fileURLToPath2(import.meta.url));
35791
+ candidates.push(join7(scriptDir, "..", "dashboard", "dist"));
35792
+ candidates.push(join7(scriptDir, "..", "..", "dashboard", "dist"));
35231
35793
  } catch {}
35232
35794
  if (process.argv[1]) {
35233
- const mainDir = dirname2(process.argv[1]);
35234
- candidates.push(join4(mainDir, "..", "dashboard", "dist"));
35235
- candidates.push(join4(mainDir, "..", "..", "dashboard", "dist"));
35795
+ const mainDir = dirname3(process.argv[1]);
35796
+ candidates.push(join7(mainDir, "..", "dashboard", "dist"));
35797
+ candidates.push(join7(mainDir, "..", "..", "dashboard", "dist"));
35236
35798
  }
35237
- candidates.push(join4(process.cwd(), "dashboard", "dist"));
35799
+ candidates.push(join7(process.cwd(), "dashboard", "dist"));
35238
35800
  for (const candidate of candidates) {
35239
- if (existsSync4(candidate))
35801
+ if (existsSync7(candidate))
35240
35802
  return candidate;
35241
35803
  }
35242
- return join4(process.cwd(), "dashboard", "dist");
35804
+ return join7(process.cwd(), "dashboard", "dist");
35243
35805
  }
35244
35806
  function json2(data, status = 200) {
35245
35807
  return new Response(JSON.stringify(data), {
35246
35808
  status,
35247
35809
  headers: {
35248
35810
  "Content-Type": "application/json",
35811
+ "X-API-Version": "1",
35249
35812
  ...SECURITY_HEADERS
35250
35813
  }
35251
35814
  });
@@ -35267,7 +35830,7 @@ function parseFields(searchParams) {
35267
35830
  }
35268
35831
  function getAllSkillsWithStatus() {
35269
35832
  const installed = new Set(getInstalledSkills());
35270
- return SKILLS.map((meta3) => {
35833
+ return loadRegistry().map((meta3) => {
35271
35834
  const reqs = getSkillRequirements(meta3.name);
35272
35835
  const envVars = reqs?.envVars || [];
35273
35836
  return {
@@ -35280,12 +35843,13 @@ function getAllSkillsWithStatus() {
35280
35843
  envVars,
35281
35844
  envVarsSet: envVars.filter((v) => !!process.env[v]),
35282
35845
  systemDeps: reqs?.systemDeps || [],
35283
- cliCommand: reqs?.cliCommand || null
35846
+ cliCommand: reqs?.cliCommand || null,
35847
+ source: meta3.source ?? "official"
35284
35848
  };
35285
35849
  });
35286
35850
  }
35287
35851
  function serveStaticFile(filePath) {
35288
- if (!existsSync4(filePath))
35852
+ if (!existsSync7(filePath))
35289
35853
  return null;
35290
35854
  const ext = extname(filePath);
35291
35855
  const contentType = MIME_TYPES[ext] || "application/octet-stream";
@@ -35295,15 +35859,48 @@ function serveStaticFile(filePath) {
35295
35859
  }
35296
35860
  function createFetchHandler(options) {
35297
35861
  const dashboardDir = options?.dashboardDir ?? resolveDashboardDir();
35298
- const dashboardExists = options?.dashboardExists ?? existsSync4(dashboardDir);
35862
+ const dashboardExists = options?.dashboardExists ?? existsSync7(dashboardDir);
35299
35863
  return async function fetchHandler(req) {
35300
35864
  const url2 = new URL(req.url);
35301
- const path = url2.pathname;
35865
+ const path = url2.pathname.replace(/^\/api\/v1\//, "/api/");
35302
35866
  const method = req.method;
35867
+ if (path === "/api/health" && method === "GET") {
35868
+ const pkg = getPackageJson();
35869
+ return json2({
35870
+ status: "ok",
35871
+ version: pkg.version,
35872
+ uptime: Math.floor(process.uptime()),
35873
+ skillCount: loadRegistry().length
35874
+ });
35875
+ }
35303
35876
  if (path === "/api/skills" && method === "GET") {
35304
35877
  const fields = parseFields(url2.searchParams);
35305
35878
  const skills = getAllSkillsWithStatus();
35306
- return json2(fields.length ? skills.map((s) => pickFields(s, fields)) : skills);
35879
+ const data = fields.length ? skills.map((s) => pickFields(s, fields)) : skills;
35880
+ if (url2.searchParams.get("stream") === "true") {
35881
+ const CHUNK_SIZE = 20;
35882
+ const stream = new ReadableStream({
35883
+ start(controller) {
35884
+ controller.enqueue("[");
35885
+ for (let i = 0;i < data.length; i += CHUNK_SIZE) {
35886
+ const chunk = data.slice(i, i + CHUNK_SIZE);
35887
+ const prefix = i === 0 ? "" : ",";
35888
+ controller.enqueue(prefix + chunk.map((s) => JSON.stringify(s)).join(","));
35889
+ }
35890
+ controller.enqueue("]");
35891
+ controller.close();
35892
+ }
35893
+ });
35894
+ return new Response(stream, {
35895
+ headers: {
35896
+ "Content-Type": "application/json",
35897
+ "Transfer-Encoding": "chunked",
35898
+ "X-API-Version": "1",
35899
+ ...SECURITY_HEADERS
35900
+ }
35901
+ });
35902
+ }
35903
+ return json2(data);
35307
35904
  }
35308
35905
  if (path === "/api/categories" && method === "GET") {
35309
35906
  const counts = CATEGORIES.map((cat) => ({
@@ -35314,7 +35911,7 @@ function createFetchHandler(options) {
35314
35911
  }
35315
35912
  if (path === "/api/tags" && method === "GET") {
35316
35913
  const tagCounts = new Map;
35317
- for (const skill of SKILLS) {
35914
+ for (const skill of loadRegistry()) {
35318
35915
  for (const tag of skill.tags) {
35319
35916
  tagCounts.set(tag, (tagCounts.get(tag) ?? 0) + 1);
35320
35917
  }
@@ -35360,14 +35957,27 @@ function createFetchHandler(options) {
35360
35957
  const reqs = getSkillRequirements(name);
35361
35958
  const docs = getSkillBestDoc(name);
35362
35959
  const installed = new Set(getInstalledSkills());
35960
+ const isInstalled = installed.has(meta3.name);
35363
35961
  const envVars = reqs?.envVars || [];
35962
+ let installedAt = null;
35963
+ let installedVersion = null;
35964
+ if (isInstalled) {
35965
+ const installMeta = getInstallMeta();
35966
+ const skillMeta = installMeta.skills?.[meta3.name];
35967
+ if (skillMeta) {
35968
+ installedAt = skillMeta.installedAt || null;
35969
+ installedVersion = skillMeta.version || null;
35970
+ }
35971
+ }
35364
35972
  const obj = {
35365
35973
  name: meta3.name,
35366
35974
  displayName: meta3.displayName,
35367
35975
  description: meta3.description,
35368
35976
  category: meta3.category,
35369
35977
  tags: meta3.tags,
35370
- installed: installed.has(meta3.name),
35978
+ installed: isInstalled,
35979
+ installedAt,
35980
+ installedVersion,
35371
35981
  envVars,
35372
35982
  envVarsSet: envVars.filter((v) => !!process.env[v]),
35373
35983
  systemDeps: reqs?.systemDeps || [],
@@ -35533,12 +36143,12 @@ function createFetchHandler(options) {
35533
36143
  }
35534
36144
  if (dashboardExists && (method === "GET" || method === "HEAD")) {
35535
36145
  if (path !== "/") {
35536
- const filePath = join4(dashboardDir, path);
36146
+ const filePath = join7(dashboardDir, path);
35537
36147
  const res2 = serveStaticFile(filePath);
35538
36148
  if (res2)
35539
36149
  return res2;
35540
36150
  }
35541
- const indexPath = join4(dashboardDir, "index.html");
36151
+ const indexPath = join7(dashboardDir, "index.html");
35542
36152
  const res = serveStaticFile(indexPath);
35543
36153
  if (res)
35544
36154
  return res;
@@ -35549,7 +36159,7 @@ function createFetchHandler(options) {
35549
36159
  async function startServer(port = 0, options) {
35550
36160
  const shouldOpen = options?.open ?? true;
35551
36161
  const dashboardDir = resolveDashboardDir();
35552
- const dashboardExists = existsSync4(dashboardDir);
36162
+ const dashboardExists = existsSync7(dashboardDir);
35553
36163
  if (!dashboardExists) {
35554
36164
  console.error(`
35555
36165
  Dashboard not found at: ${dashboardDir}`);
@@ -35629,8 +36239,8 @@ var {
35629
36239
  // src/cli/index.tsx
35630
36240
  init_package();
35631
36241
  import chalk2 from "chalk";
35632
- import { existsSync as existsSync5, writeFileSync as writeFileSync2, appendFileSync, readFileSync as readFileSync4, readdirSync as readdirSync4, statSync as statSync3 } from "fs";
35633
- import { join as join5 } from "path";
36242
+ import { existsSync as existsSync8, writeFileSync as writeFileSync4, appendFileSync, readFileSync as readFileSync7, readdirSync as readdirSync5, statSync as statSync3, mkdirSync as mkdirSync4 } from "fs";
36243
+ import { join as join8 } from "path";
35634
36244
 
35635
36245
  // src/cli/components/App.tsx
35636
36246
  import { useState as useState7 } from "react";
@@ -36754,10 +37364,104 @@ function App({ initialSkills, overwrite = false }) {
36754
37364
  init_registry();
36755
37365
  init_installer();
36756
37366
  init_skillinfo();
37367
+
37368
+ // src/lib/config.ts
37369
+ import { existsSync as existsSync4, readFileSync as readFileSync4, writeFileSync as writeFileSync2, mkdirSync as mkdirSync2 } from "fs";
37370
+ import { join as join4, dirname as dirname2 } from "path";
37371
+ import { homedir as homedir3 } from "os";
37372
+ var VALID_KEYS = {
37373
+ defaultAgent: ["claude", "codex", "gemini", "all"],
37374
+ defaultScope: ["global", "project"],
37375
+ format: ["compact", "json", "csv"]
37376
+ };
37377
+ function getConfigPath(scope) {
37378
+ if (scope === "global") {
37379
+ return join4(homedir3(), ".skillsrc");
37380
+ }
37381
+ return join4(process.cwd(), "skills.config.json");
37382
+ }
37383
+ function readConfigFile(path) {
37384
+ if (!existsSync4(path))
37385
+ return {};
37386
+ try {
37387
+ const raw = readFileSync4(path, "utf-8");
37388
+ const parsed = JSON.parse(raw);
37389
+ if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed))
37390
+ return {};
37391
+ const config = {};
37392
+ for (const [key, allowed] of Object.entries(VALID_KEYS)) {
37393
+ const val = parsed[key];
37394
+ if (typeof val === "string" && allowed.includes(val)) {
37395
+ config[key] = val;
37396
+ }
37397
+ }
37398
+ return config;
37399
+ } catch {
37400
+ return {};
37401
+ }
37402
+ }
37403
+ function loadConfig() {
37404
+ const globalConfig = readConfigFile(getConfigPath("global"));
37405
+ const projectConfig = readConfigFile(getConfigPath("project"));
37406
+ return { ...globalConfig, ...projectConfig };
37407
+ }
37408
+ function saveConfig(key, value, scope = "project") {
37409
+ if (!(key in VALID_KEYS)) {
37410
+ throw new Error(`Unknown config key: ${key}. Valid keys: ${Object.keys(VALID_KEYS).join(", ")}`);
37411
+ }
37412
+ const allowed = VALID_KEYS[key];
37413
+ if (!allowed.includes(value)) {
37414
+ throw new Error(`Invalid value '${value}' for ${key}. Allowed: ${allowed.join(", ")}`);
37415
+ }
37416
+ const filePath = getConfigPath(scope);
37417
+ let existing = {};
37418
+ if (existsSync4(filePath)) {
37419
+ try {
37420
+ existing = JSON.parse(readFileSync4(filePath, "utf-8"));
37421
+ if (typeof existing !== "object" || existing === null || Array.isArray(existing)) {
37422
+ existing = {};
37423
+ }
37424
+ } catch {
37425
+ existing = {};
37426
+ }
37427
+ } else {
37428
+ const dir = dirname2(filePath);
37429
+ if (!existsSync4(dir)) {
37430
+ mkdirSync2(dir, { recursive: true });
37431
+ }
37432
+ }
37433
+ existing[key] = value;
37434
+ writeFileSync2(filePath, JSON.stringify(existing, null, 2) + `
37435
+ `);
37436
+ }
37437
+
37438
+ // src/cli/index.tsx
37439
+ init_scheduler();
36757
37440
  import { jsxDEV as jsxDEV7 } from "react/jsx-dev-runtime";
36758
37441
  var isTTY = (process.stdout.isTTY ?? false) && (process.stdin.isTTY ?? false);
37442
+ if (process.argv.includes("--no-color")) {
37443
+ chalk2.level = 0;
37444
+ const idx = process.argv.indexOf("--no-color");
37445
+ process.argv.splice(idx, 1);
37446
+ }
36759
37447
  var program2 = new Command;
36760
- program2.name("skills").description("Install AI agent skills for your project").version(package_default.version).option("--verbose", "Enable verbose logging", false).enablePositionalOptions();
37448
+ var _verbose;
37449
+ function debug(msg) {
37450
+ if (_verbose === undefined) {
37451
+ _verbose = program2.opts().verbose || process.argv.includes("--verbose");
37452
+ }
37453
+ if (_verbose) {
37454
+ console.error(`[debug] ${msg}`);
37455
+ }
37456
+ }
37457
+ function skillNotFound(name) {
37458
+ console.error(`Skill '${name}' not found`);
37459
+ const similar = findSimilarSkills(name);
37460
+ if (similar.length > 0) {
37461
+ console.error(chalk2.dim(`Did you mean: ${similar.join(", ")}?`));
37462
+ }
37463
+ }
37464
+ program2.name("skills").description("Install AI agent skills for your project").version(package_default.version).option("--verbose", "Enable verbose logging", false).option("--no-color", "Disable colored output (also respects NO_COLOR env var)").enablePositionalOptions();
36761
37465
  program2.command("interactive", { isDefault: true }).alias("i").description("Interactive skill browser (TUI)").action(() => {
36762
37466
  if (!isTTY) {
36763
37467
  console.log(JSON.stringify(SKILLS.map((s) => ({ name: s.name, category: s.category }))));
@@ -36765,7 +37469,15 @@ program2.command("interactive", { isDefault: true }).alias("i").description("Int
36765
37469
  }
36766
37470
  render(/* @__PURE__ */ jsxDEV7(App, {}, undefined, false, undefined, this));
36767
37471
  });
36768
- program2.command("install").alias("add").argument("[skills...]", "Skills to install").option("-o, --overwrite", "Overwrite existing skills", false).option("--json", "Output results as JSON", false).option("--for <agent>", "Install for agent: claude, codex, gemini, or all").option("--scope <scope>", "Install scope: global or project", "global").option("--dry-run", "Print what would happen without actually installing", false).option("--category <category>", "Install all skills in a category (case-insensitive)").description("Install one or more skills").action((skills, options) => {
37472
+ program2.command("install").alias("add").argument("[skills...]", "Skills to install").option("--verbose", "Enable verbose debug logging", false).option("-o, --overwrite", "Overwrite existing skills", false).option("--json", "Output results as JSON", false).option("--for <agent>", "Install for agent: claude, codex, gemini, pi, opencode, or all").option("--scope <scope>", "Install scope: global or project", "global").option("--dry-run", "Print what would happen without actually installing", false).option("--category <category>", "Install all skills in a category (case-insensitive)").description("Install one or more skills").action((skills, options) => {
37473
+ const config2 = loadConfig();
37474
+ if (!options.for && config2.defaultAgent) {
37475
+ options.for = config2.defaultAgent;
37476
+ }
37477
+ if (!process.argv.includes("--scope") && config2.defaultScope) {
37478
+ options.scope = config2.defaultScope;
37479
+ }
37480
+ debug(`install: skills=[${skills.join(", ")}] overwrite=${options.overwrite} for=${options.for ?? "none"} scope=${options.scope} dryRun=${options.dryRun}`);
36769
37481
  if (skills.length === 0 && !options.category) {
36770
37482
  console.error("error: missing required argument 'skills' or --category option");
36771
37483
  process.exitCode = 1;
@@ -36792,6 +37504,7 @@ Installing ${skills.length} skills from "${matchedCategory}"...
36792
37504
  let agents;
36793
37505
  try {
36794
37506
  agents = resolveAgents(options.for);
37507
+ debug(`install: resolved agents=[${agents.join(", ")}]`);
36795
37508
  } catch (err) {
36796
37509
  console.error(chalk2.red(err.message));
36797
37510
  process.exitCode = 1;
@@ -36807,10 +37520,12 @@ Installing ${skills.length} skills from "${matchedCategory}"...
36807
37520
  }
36808
37521
  for (const name of skills) {
36809
37522
  for (const agent of agents) {
37523
+ debug(`install: installing ${name} for agent=${agent} scope=${options.scope}`);
36810
37524
  const result = installSkillForAgent(name, {
36811
37525
  agent,
36812
37526
  scope: options.scope
36813
37527
  }, generateSkillMd);
37528
+ debug(`install: ${name} \u2192 ${result.success ? "ok" : "failed"} path=${result.path ?? "n/a"}`);
36814
37529
  results.push({ ...result, agent, scope: options.scope });
36815
37530
  }
36816
37531
  }
@@ -36839,15 +37554,31 @@ SKILL.md copied to agent skill directories`));
36839
37554
  return;
36840
37555
  }
36841
37556
  const total = skills.length;
37557
+ const startTime = Date.now();
36842
37558
  for (let i = 0;i < total; i++) {
36843
37559
  const name = skills[i];
37560
+ debug(`install: source=${getSkillPath(name)} dest=.skills/${normalizeSkillName(name)}`);
36844
37561
  if (total > 1 && !options.json) {
36845
37562
  process.stdout.write(`[${i + 1}/${total}] Installing ${name}...`);
36846
37563
  }
36847
37564
  const result = installSkill(name, { overwrite: options.overwrite });
37565
+ debug(`install: ${name} \u2192 ${result.success ? "ok" : "failed"} path=${result.path ?? "n/a"}`);
36848
37566
  results.push(result);
36849
37567
  if (total > 1 && !options.json) {
36850
- console.log(result.success ? " done" : " failed");
37568
+ console.log(result.success ? " done" : ` ${chalk2.red("failed")}`);
37569
+ }
37570
+ }
37571
+ if (total > 1 && !options.json) {
37572
+ const elapsed = ((Date.now() - startTime) / 1000).toFixed(1);
37573
+ const succeeded = results.filter((r) => r.success).length;
37574
+ const failed = results.filter((r) => !r.success);
37575
+ if (failed.length > 0) {
37576
+ console.log(chalk2.yellow(`
37577
+ ${succeeded}/${total} installed in ${elapsed}s, ${failed.length} failed: ${failed.map((r) => r.skill).join(", ")}`));
37578
+ process.exitCode = 1;
37579
+ } else {
37580
+ console.log(chalk2.green(`
37581
+ ${succeeded}/${total} installed in ${elapsed}s`));
36851
37582
  }
36852
37583
  }
36853
37584
  if (options.json) {
@@ -36879,7 +37610,14 @@ program2.command("list").alias("ls").option("-c, --category <category>", "Filter
36879
37610
  if (options.installed) {
36880
37611
  const installed = getInstalledSkills();
36881
37612
  if (options.json) {
36882
- console.log(JSON.stringify(installed));
37613
+ const meta4 = getInstallMeta();
37614
+ const registry3 = loadRegistry();
37615
+ const output = installed.map((name) => {
37616
+ const m = meta4.skills[name];
37617
+ const s = registry3.find((r) => r.name === name);
37618
+ return { name, version: m?.version ?? null, installedAt: m?.installedAt ?? null, source: s?.source ?? "official" };
37619
+ });
37620
+ console.log(JSON.stringify(output));
36883
37621
  return;
36884
37622
  }
36885
37623
  if (installed.length === 0) {
@@ -36887,16 +37625,22 @@ program2.command("list").alias("ls").option("-c, --category <category>", "Filter
36887
37625
  return;
36888
37626
  }
36889
37627
  if (brief) {
36890
- for (const name of installed) {
37628
+ for (const name of installed)
36891
37629
  console.log(name);
36892
- }
36893
37630
  return;
36894
37631
  }
37632
+ const meta3 = getInstallMeta();
37633
+ const registry2 = loadRegistry();
36895
37634
  console.log(chalk2.bold(`
36896
37635
  Installed skills (${installed.length}):
36897
37636
  `));
36898
37637
  for (const name of installed) {
36899
- console.log(` ${name}`);
37638
+ const m = meta3.skills[name];
37639
+ const s = registry2.find((r) => r.name === name);
37640
+ const version2 = m?.version ? chalk2.dim(`v${m.version}`) : "";
37641
+ const installedAt = m?.installedAt ? chalk2.dim(new Date(m.installedAt).toLocaleDateString()) : "";
37642
+ const source = s?.source === "custom" ? chalk2.yellow(" [custom]") : "";
37643
+ console.log(` ${chalk2.cyan(name)}${source} ${version2} ${installedAt}`);
36900
37644
  }
36901
37645
  return;
36902
37646
  }
@@ -36932,7 +37676,7 @@ ${category} (${skills.length}):
36932
37676
  return;
36933
37677
  }
36934
37678
  if (tagFilter) {
36935
- const skills = SKILLS.filter((s) => s.tags.some((tag) => tagFilter.includes(tag.toLowerCase())));
37679
+ const skills = loadRegistry().filter((s) => s.tags.some((tag) => tagFilter.includes(tag.toLowerCase())));
36936
37680
  if (options.json) {
36937
37681
  console.log(JSON.stringify(skills, null, 2));
36938
37682
  return;
@@ -36947,29 +37691,31 @@ ${category} (${skills.length}):
36947
37691
  Skills matching tags [${tagFilter.join(", ")}] (${skills.length}):
36948
37692
  `));
36949
37693
  for (const s of skills) {
36950
- console.log(` ${chalk2.cyan(s.name)} ${chalk2.dim(`[${s.category}]`)} - ${s.description}`);
37694
+ const customBadge = s.source === "custom" ? chalk2.yellow(" [custom]") : "";
37695
+ console.log(` ${chalk2.cyan(s.name)}${customBadge} ${chalk2.dim(`[${s.category}]`)} - ${s.description}`);
36951
37696
  }
36952
37697
  return;
36953
37698
  }
37699
+ const allSkills = loadRegistry();
36954
37700
  if (options.json) {
36955
- console.log(JSON.stringify(SKILLS, null, 2));
37701
+ console.log(JSON.stringify(allSkills, null, 2));
36956
37702
  return;
36957
37703
  }
36958
37704
  if (fmt === "compact") {
36959
- for (const s of SKILLS)
37705
+ for (const s of allSkills)
36960
37706
  console.log(s.name);
36961
37707
  return;
36962
37708
  }
36963
37709
  if (fmt === "csv") {
36964
- console.log("name,category,description");
36965
- for (const s of SKILLS) {
37710
+ console.log("name,category,description,source");
37711
+ for (const s of allSkills) {
36966
37712
  const desc = s.description.replace(/"/g, '""');
36967
- console.log(`${s.name},${s.category},"${desc}"`);
37713
+ console.log(`${s.name},${s.category},"${desc}",${s.source ?? "official"}`);
36968
37714
  }
36969
37715
  return;
36970
37716
  }
36971
37717
  if (brief) {
36972
- const sorted = [...SKILLS].sort((a, b) => {
37718
+ const sorted = [...allSkills].sort((a, b) => {
36973
37719
  const catCmp = a.category.localeCompare(b.category);
36974
37720
  return catCmp !== 0 ? catCmp : a.name.localeCompare(b.name);
36975
37721
  });
@@ -36979,19 +37725,30 @@ Skills matching tags [${tagFilter.join(", ")}] (${skills.length}):
36979
37725
  return;
36980
37726
  }
36981
37727
  console.log(chalk2.bold(`
36982
- Available skills (${SKILLS.length}):
37728
+ Available skills (${allSkills.length}):
36983
37729
  `));
36984
37730
  for (const category of CATEGORIES) {
36985
37731
  const skills = getSkillsByCategory(category);
37732
+ if (skills.length === 0)
37733
+ continue;
36986
37734
  console.log(chalk2.bold(`${category} (${skills.length}):`));
36987
37735
  for (const s of skills) {
36988
- console.log(` ${chalk2.cyan(s.name)} - ${s.description}`);
37736
+ const customBadge = s.source === "custom" ? chalk2.yellow(" [custom]") : "";
37737
+ console.log(` ${chalk2.cyan(s.name)}${customBadge} - ${s.description}`);
36989
37738
  }
36990
37739
  console.log();
36991
37740
  }
37741
+ const customUncategorized = allSkills.filter((s) => s.source === "custom" && !CATEGORIES.includes(s.category));
37742
+ if (customUncategorized.length > 0) {
37743
+ console.log(chalk2.bold(`Custom (${customUncategorized.length}):`));
37744
+ for (const s of customUncategorized) {
37745
+ console.log(` ${chalk2.yellow(s.name)} - ${s.description}`);
37746
+ }
37747
+ }
36992
37748
  });
36993
- program2.command("search").argument("<query>", "Search term").option("--json", "Output as JSON", false).option("--brief", "One line per skill: name \u2014 description [category]", false).option("--format <format>", "Output format: compact (names only) or csv (name,category,description)").option("-c, --category <category>", "Filter results by category").option("-t, --tags <tags>", "Filter results by comma-separated tags (OR logic, case-insensitive)").description("Search for skills").action((query, options) => {
37749
+ program2.command("search").alias("s").argument("<query>", "Search term").option("--verbose", "Enable verbose debug logging", false).option("--json", "Output as JSON", false).option("--brief", "One line per skill: name \u2014 description [category]", false).option("--format <format>", "Output format: compact (names only) or csv (name,category,description)").option("-c, --category <category>", "Filter results by category").option("-t, --tags <tags>", "Filter results by comma-separated tags (OR logic, case-insensitive)").description("Search for skills").action((query, options) => {
36994
37750
  let results = searchSkills(query);
37751
+ debug(`search: query="${query}" results=${results.length} category=${options.category ?? "none"} tags=${options.tags ?? "none"}`);
36995
37752
  if (options.category) {
36996
37753
  const category = CATEGORIES.find((c) => c.toLowerCase() === options.category.toLowerCase());
36997
37754
  if (!category) {
@@ -37014,6 +37771,10 @@ program2.command("search").argument("<query>", "Search term").option("--json", "
37014
37771
  }
37015
37772
  if (results.length === 0) {
37016
37773
  console.log(chalk2.dim(`No skills found for "${query}"`));
37774
+ const similar = findSimilarSkills(query, 5);
37775
+ if (similar.length > 0) {
37776
+ console.log(chalk2.dim(`Related skills: ${similar.join(", ")}`));
37777
+ }
37017
37778
  return;
37018
37779
  }
37019
37780
  if (fmt === "compact") {
@@ -37046,7 +37807,7 @@ Found ${results.length} skill(s):
37046
37807
  program2.command("info").argument("<skill>", "Skill name").option("--json", "Output as JSON", false).option("--brief", "Single line: name \u2014 description [category] (tags: ...)", false).description("Show details about a specific skill").action((name, options) => {
37047
37808
  const skill = getSkill(name);
37048
37809
  if (!skill) {
37049
- console.error(`Skill '${name}' not found`);
37810
+ skillNotFound(name);
37050
37811
  process.exitCode = 1;
37051
37812
  return;
37052
37813
  }
@@ -37059,8 +37820,17 @@ program2.command("info").argument("<skill>", "Skill name").option("--json", "Out
37059
37820
  console.log(`${skill.name} \u2014 ${skill.description} [${skill.category}] (tags: ${skill.tags.join(", ")})`);
37060
37821
  return;
37061
37822
  }
37823
+ const { execSync: execSyncInfo } = __require("child_process");
37824
+ function cmdAvailable(cmd) {
37825
+ try {
37826
+ execSyncInfo(`which ${cmd}`, { stdio: "ignore" });
37827
+ return true;
37828
+ } catch {
37829
+ return false;
37830
+ }
37831
+ }
37062
37832
  console.log(`
37063
- ${chalk2.bold(skill.displayName)}`);
37833
+ ${chalk2.bold(skill.displayName)}${skill.source === "custom" ? chalk2.yellow(" [custom]") : ""}`);
37064
37834
  console.log(`${skill.description}`);
37065
37835
  console.log(`${chalk2.dim("Category:")} ${skill.category}`);
37066
37836
  console.log(`${chalk2.dim("Tags:")} ${skill.tags.join(", ")}`);
@@ -37068,17 +37838,25 @@ ${chalk2.bold(skill.displayName)}`);
37068
37838
  console.log(`${chalk2.dim("CLI:")} ${reqs.cliCommand}`);
37069
37839
  }
37070
37840
  if (reqs?.envVars.length) {
37071
- console.log(`${chalk2.dim("Env vars:")} ${reqs.envVars.join(", ")}`);
37841
+ console.log(`${chalk2.dim("Env vars:")}`);
37842
+ for (const v of reqs.envVars) {
37843
+ const set3 = !!process.env[v];
37844
+ console.log(` ${set3 ? chalk2.green("\u2713") : chalk2.red("\u2717")} ${v}${set3 ? "" : chalk2.dim(" (not set)")}`);
37845
+ }
37072
37846
  }
37073
37847
  if (reqs?.systemDeps.length) {
37074
- console.log(`${chalk2.dim("System deps:")} ${reqs.systemDeps.join(", ")}`);
37848
+ console.log(`${chalk2.dim("System deps:")}`);
37849
+ for (const d of reqs.systemDeps) {
37850
+ const avail = cmdAvailable(d);
37851
+ console.log(` ${avail ? chalk2.green("\u2713") : chalk2.red("\u2717")} ${d}${avail ? "" : chalk2.dim(" (not found)")}`);
37852
+ }
37075
37853
  }
37076
37854
  console.log(`${chalk2.dim("Install:")} skills install ${skill.name}`);
37077
37855
  });
37078
37856
  program2.command("docs").argument("<skill>", "Skill name").option("--json", "Output as JSON", false).option("--file <file>", "Specific file: skill, readme, claude", "").description("Show documentation for a skill").action((name, options) => {
37079
37857
  const docs = getSkillDocs(name);
37080
37858
  if (!docs) {
37081
- console.error(`Skill '${name}' not found`);
37859
+ skillNotFound(name);
37082
37860
  process.exitCode = 1;
37083
37861
  return;
37084
37862
  }
@@ -37121,7 +37899,7 @@ program2.command("docs").argument("<skill>", "Skill name").option("--json", "Out
37121
37899
  program2.command("requires").argument("<skill>", "Skill name").option("--json", "Output as JSON", false).description("Show what a skill needs (env vars, system deps, dependencies)").action((name, options) => {
37122
37900
  const reqs = getSkillRequirements(name);
37123
37901
  if (!reqs) {
37124
- console.error(`Skill '${name}' not found`);
37902
+ skillNotFound(name);
37125
37903
  process.exitCode = 1;
37126
37904
  return;
37127
37905
  }
@@ -37165,7 +37943,7 @@ ${chalk2.bold("npm dependencies:")} ${depCount} packages`);
37165
37943
  program2.command("run").argument("<skill>", "Skill name").argument("[args...]", "Arguments to pass to the skill").allowUnknownOption(true).passThroughOptions(true).description("Run a skill directly").action(async (name, args) => {
37166
37944
  const skill = getSkill(name);
37167
37945
  if (!skill) {
37168
- console.error(`Skill '${name}' not found in registry`);
37946
+ skillNotFound(name);
37169
37947
  process.exitCode = 1;
37170
37948
  return;
37171
37949
  }
@@ -37175,7 +37953,7 @@ program2.command("run").argument("<skill>", "Skill name").argument("[args...]",
37175
37953
  }
37176
37954
  process.exitCode = result.exitCode;
37177
37955
  });
37178
- program2.command("init").option("--json", "Output as JSON", false).option("--for <agent>", "Detect project type and install recommended skills for agent: claude, codex, gemini, or all").option("--scope <scope>", "Install scope: global or project", "global").description("Initialize project for installed skills (.env.example, .gitignore)").action((options) => {
37956
+ program2.command("init").option("--json", "Output as JSON", false).option("--for <agent>", "Detect project type and install recommended skills for agent: claude, codex, gemini, pi, opencode, or all").option("--scope <scope>", "Install scope: global or project", "global").description("Initialize project for installed skills (.env.example, .gitignore)").action((options) => {
37179
37957
  const cwd = process.cwd();
37180
37958
  if (options.for) {
37181
37959
  let agents;
@@ -37289,8 +38067,8 @@ Installing recommended skills for ${options.for} (${options.scope})...
37289
38067
  const envContent = lines.join(`
37290
38068
  `) + `
37291
38069
  `;
37292
- const envPath = join5(cwd, ".env.example");
37293
- writeFileSync2(envPath, envContent);
38070
+ const envPath = join8(cwd, ".env.example");
38071
+ writeFileSync4(envPath, envContent);
37294
38072
  envVarCount = envMap.size;
37295
38073
  if (!options.json) {
37296
38074
  console.log(chalk2.green(`\u2713 Generated .env.example (${envVarCount} variables from ${installed.length} skills)`));
@@ -37300,11 +38078,11 @@ Installing recommended skills for ${options.for} (${options.scope})...
37300
38078
  console.log(chalk2.dim(" No environment variables detected across installed skills"));
37301
38079
  }
37302
38080
  }
37303
- const gitignorePath = join5(cwd, ".gitignore");
38081
+ const gitignorePath = join8(cwd, ".gitignore");
37304
38082
  const gitignoreEntry = ".skills/";
37305
38083
  let gitignoreContent = "";
37306
- if (existsSync5(gitignorePath)) {
37307
- gitignoreContent = readFileSync4(gitignorePath, "utf-8");
38084
+ if (existsSync8(gitignorePath)) {
38085
+ gitignoreContent = readFileSync7(gitignorePath, "utf-8");
37308
38086
  }
37309
38087
  let gitignoreUpdated = false;
37310
38088
  if (!gitignoreContent.includes(gitignoreEntry)) {
@@ -37350,11 +38128,27 @@ Initialized for ${installed.length} installed skill(s)`));
37350
38128
  }
37351
38129
  }
37352
38130
  });
37353
- program2.command("remove").alias("rm").argument("<skill>", "Skill to remove").option("--json", "Output as JSON", false).option("--for <agent>", "Remove from agent: claude, codex, gemini, or all").option("--scope <scope>", "Remove scope: global or project", "global").option("--dry-run", "Print what would happen without actually removing", false).description("Remove an installed skill").action((skill, options) => {
38131
+ program2.command("remove").alias("rm").argument("<skill>", "Skill to remove").option("--verbose", "Enable verbose debug logging", false).option("--json", "Output as JSON", false).option("--for <agent>", "Remove from agent: claude, codex, gemini, pi, opencode, or all").option("--scope <scope>", "Remove scope: global or project", "global").option("--dry-run", "Print what would happen without actually removing", false).option("-y, --yes", "Skip confirmation prompt", false).description("Remove an installed skill").action(async (skill, options) => {
38132
+ debug(`remove: skill=${skill} for=${options.for ?? "none"} scope=${options.scope} dryRun=${options.dryRun}`);
38133
+ if (!options.yes && !options.dryRun && isTTY) {
38134
+ const skillName = normalizeSkillName(skill);
38135
+ const target = options.for ? `from ${options.for} (${options.scope})` : "from .skills/";
38136
+ const readline = await import("readline");
38137
+ const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
38138
+ const answer = await new Promise((resolve) => {
38139
+ rl.question(`Remove ${skillName} ${target}? (y/N) `, resolve);
38140
+ });
38141
+ rl.close();
38142
+ if (answer.toLowerCase() !== "y") {
38143
+ console.log("Cancelled.");
38144
+ return;
38145
+ }
38146
+ }
37354
38147
  if (options.for) {
37355
38148
  let agents;
37356
38149
  try {
37357
38150
  agents = resolveAgents(options.for);
38151
+ debug(`remove: resolved agents=[${agents.join(", ")}]`);
37358
38152
  } catch (err) {
37359
38153
  console.error(chalk2.red(err.message));
37360
38154
  process.exitCode = 1;
@@ -37368,10 +38162,12 @@ program2.command("remove").alias("rm").argument("<skill>", "Skill to remove").op
37368
38162
  }
37369
38163
  const results = [];
37370
38164
  for (const agent of agents) {
38165
+ debug(`remove: removing ${skill} from agent=${agent} scope=${options.scope}`);
37371
38166
  const removed = removeSkillForAgent(skill, {
37372
38167
  agent,
37373
38168
  scope: options.scope
37374
38169
  });
38170
+ debug(`remove: ${skill} from ${agent} \u2192 ${removed ? "removed" : "not found"}`);
37375
38171
  results.push({ skill, agent, scope: options.scope, removed });
37376
38172
  }
37377
38173
  if (options.json) {
@@ -37394,7 +38190,9 @@ program2.command("remove").alias("rm").argument("<skill>", "Skill to remove").op
37394
38190
  console.log(chalk2.dim(`[dry-run] Would remove ${skill} from .skills/`));
37395
38191
  return;
37396
38192
  }
38193
+ debug(`remove: deleting .skills/${normalizeSkillName(skill)}`);
37397
38194
  const removed = removeSkill(skill);
38195
+ debug(`remove: ${skill} \u2192 ${removed ? "removed" : "not found"}`);
37398
38196
  if (options.json) {
37399
38197
  console.log(JSON.stringify({ skill, removed }));
37400
38198
  } else if (removed) {
@@ -37413,10 +38211,10 @@ program2.command("update").argument("[skills...]", "Skills to update (default: a
37413
38211
  }
37414
38212
  function collectFiles(dir, base = "") {
37415
38213
  const files = new Set;
37416
- if (!existsSync5(dir))
38214
+ if (!existsSync8(dir))
37417
38215
  return files;
37418
- for (const entry of readdirSync4(dir)) {
37419
- const full = join5(dir, entry);
38216
+ for (const entry of readdirSync5(dir)) {
38217
+ const full = join8(dir, entry);
37420
38218
  const rel = base ? `${base}/${entry}` : entry;
37421
38219
  if (statSync3(full).isDirectory()) {
37422
38220
  for (const f of collectFiles(full, rel))
@@ -37430,7 +38228,7 @@ program2.command("update").argument("[skills...]", "Skills to update (default: a
37430
38228
  const updateResults = [];
37431
38229
  for (const name of toUpdate) {
37432
38230
  const skillName = normalizeSkillName(name);
37433
- const destPath = join5(process.cwd(), ".skills", skillName);
38231
+ const destPath = join8(process.cwd(), ".skills", skillName);
37434
38232
  const beforeFiles = collectFiles(destPath);
37435
38233
  const result = installSkill(name, { overwrite: true });
37436
38234
  const afterFiles = collectFiles(destPath);
@@ -37508,10 +38306,11 @@ Tags:
37508
38306
  console.log(` ${chalk2.cyan(name)} (${count})`);
37509
38307
  }
37510
38308
  });
37511
- program2.command("mcp").option("--register <agent>", "Register MCP server with agent: claude, codex, gemini, or all").description("Start MCP server (stdio) or register with an agent").action(async (options) => {
38309
+ program2.command("mcp").option("--register <agent>", "Register MCP server with agent: claude, codex, gemini, pi, opencode, or all").description("Start MCP server (stdio) or register with an agent").action(async (options) => {
37512
38310
  if (options.register) {
37513
- const agents = options.register === "all" ? ["claude", "codex", "gemini"] : [options.register];
37514
- const binPath = join5(import.meta.dir, "..", "mcp", "index.ts");
38311
+ const agents = options.register === "all" ? [...AGENT_TARGETS] : [options.register];
38312
+ const binPath = join8(import.meta.dir, "..", "mcp", "index.ts");
38313
+ const { homedir: hd } = await import("os");
37515
38314
  for (const agent of agents) {
37516
38315
  if (agent === "claude") {
37517
38316
  try {
@@ -37525,8 +38324,7 @@ program2.command("mcp").option("--register <agent>", "Register MCP server with a
37525
38324
  console.log(chalk2.yellow(`Manual registration: claude mcp add skills -- bun run ${binPath}`));
37526
38325
  }
37527
38326
  } else if (agent === "codex") {
37528
- const { homedir: homedir3 } = await import("os");
37529
- const configPath = join5(homedir3(), ".codex", "config.toml");
38327
+ const configPath = join8(hd(), ".codex", "config.toml");
37530
38328
  console.log(chalk2.bold(`
37531
38329
  Add to ${configPath}:`));
37532
38330
  console.log(chalk2.dim(`[mcp_servers.skills]
@@ -37534,16 +38332,25 @@ command = "bun"
37534
38332
  args = ["run", "${binPath}"]`));
37535
38333
  console.log(chalk2.green(`\u2713 Codex MCP config shown above`));
37536
38334
  } else if (agent === "gemini") {
37537
- const { homedir: homedir3 } = await import("os");
37538
- const configPath = join5(homedir3(), ".gemini", "settings.json");
38335
+ const configPath = join8(hd(), ".gemini", "settings.json");
37539
38336
  console.log(chalk2.bold(`
37540
38337
  Add to ${configPath} mcpServers:`));
37541
- console.log(chalk2.dim(JSON.stringify({
37542
- skills: { command: "bun", args: ["run", binPath] }
37543
- }, null, 2)));
38338
+ console.log(chalk2.dim(JSON.stringify({ skills: { command: "bun", args: ["run", binPath] } }, null, 2)));
37544
38339
  console.log(chalk2.green(`\u2713 Gemini MCP config shown above`));
38340
+ } else if (agent === "pi") {
38341
+ const configPath = join8(hd(), ".pi", "agent", "mcp.json");
38342
+ console.log(chalk2.bold(`
38343
+ Add to ${configPath}:`));
38344
+ console.log(chalk2.dim(JSON.stringify({ skills: { command: "bun", args: ["run", binPath] } }, null, 2)));
38345
+ console.log(chalk2.green(`\u2713 pi.dev MCP config shown above`));
38346
+ } else if (agent === "opencode") {
38347
+ const configPath = join8(hd(), ".opencode", "config.json");
38348
+ console.log(chalk2.bold(`
38349
+ Add to ${configPath} mcp section:`));
38350
+ console.log(chalk2.dim(JSON.stringify({ skills: { command: "bun", args: ["run", binPath] } }, null, 2)));
38351
+ console.log(chalk2.green(`\u2713 OpenCode MCP config shown above`));
37545
38352
  } else {
37546
- console.error(chalk2.red(`Unknown agent: ${agent}. Available: claude, codex, gemini, all`));
38353
+ console.error(chalk2.red(`Unknown agent: ${agent}. Available: ${AGENT_TARGETS.join(", ")}, all`));
37547
38354
  process.exitCode = 1;
37548
38355
  }
37549
38356
  }
@@ -37729,18 +38536,18 @@ program2.command("export").option("--json", "Output as JSON (default behavior)",
37729
38536
  };
37730
38537
  console.log(JSON.stringify(payload, null, 2));
37731
38538
  });
37732
- program2.command("import").argument("<file>", "JSON file to import (use - for stdin)").option("--json", "Output results as JSON", false).option("--for <agent>", "Install for agent: claude, codex, gemini, or all").option("--scope <scope>", "Install scope: global or project", "global").option("--dry-run", "Show what would be installed without actually installing", false).description("Import and install skills from a JSON export file").action(async (file2, options) => {
38539
+ program2.command("import").argument("<file>", "JSON file to import (use - for stdin)").option("--json", "Output results as JSON", false).option("--for <agent>", "Install for agent: claude, codex, gemini, pi, opencode, or all").option("--scope <scope>", "Install scope: global or project", "global").option("--dry-run", "Show what would be installed without actually installing", false).description("Import and install skills from a JSON export file").action(async (file2, options) => {
37733
38540
  let raw;
37734
38541
  try {
37735
38542
  if (file2 === "-") {
37736
38543
  raw = await new Response(process.stdin).text();
37737
38544
  } else {
37738
- if (!existsSync5(file2)) {
38545
+ if (!existsSync8(file2)) {
37739
38546
  console.error(chalk2.red(`File not found: ${file2}`));
37740
38547
  process.exitCode = 1;
37741
38548
  return;
37742
38549
  }
37743
- raw = readFileSync4(file2, "utf-8");
38550
+ raw = readFileSync7(file2, "utf-8");
37744
38551
  }
37745
38552
  } catch (err) {
37746
38553
  console.error(chalk2.red(`Failed to read file: ${err.message}`));
@@ -37831,7 +38638,8 @@ Imported ${succeeded}/${total} skill(s)${failed > 0 ? ` (${failed} failed)` : ""
37831
38638
  process.exitCode = 1;
37832
38639
  }
37833
38640
  });
37834
- program2.command("doctor").option("--json", "Output as JSON", false).description("Check environment variables for installed skills").action((options) => {
38641
+ program2.command("doctor").option("--json", "Output as JSON", false).description("Check env vars, system deps, and install health for installed skills").action((options) => {
38642
+ const { execSync } = __require("child_process");
37835
38643
  const installed = getInstalledSkills();
37836
38644
  if (installed.length === 0) {
37837
38645
  if (options.json) {
@@ -37841,37 +38649,53 @@ program2.command("doctor").option("--json", "Output as JSON", false).description
37841
38649
  }
37842
38650
  return;
37843
38651
  }
38652
+ function isCommandAvailable(cmd) {
38653
+ try {
38654
+ execSync(`which ${cmd}`, { stdio: "ignore" });
38655
+ return true;
38656
+ } catch {
38657
+ return false;
38658
+ }
38659
+ }
37844
38660
  const report = [];
37845
38661
  for (const name of installed) {
37846
38662
  const reqs = getSkillRequirements(name);
37847
- const envVars = (reqs?.envVars ?? []).map((v) => ({
37848
- name: v,
37849
- set: !!process.env[v]
37850
- }));
37851
- report.push({ skill: name, envVars });
38663
+ const envVars = (reqs?.envVars ?? []).map((v) => ({ name: v, set: !!process.env[v] }));
38664
+ const systemDeps = (reqs?.systemDeps ?? []).map((d) => ({ name: d, available: isCommandAvailable(d) }));
38665
+ const healthy = envVars.every((v) => v.set) && systemDeps.every((d) => d.available);
38666
+ report.push({ skill: name, envVars, systemDeps, healthy });
37852
38667
  }
37853
38668
  if (options.json) {
37854
38669
  console.log(JSON.stringify(report, null, 2));
37855
38670
  return;
37856
38671
  }
38672
+ const issues = report.filter((r) => !r.healthy);
37857
38673
  console.log(chalk2.bold(`
37858
- Skills Doctor (${installed.length} installed):
38674
+ Skills Doctor \u2014 ${installed.length} installed, ${issues.length} with issues:
37859
38675
  `));
37860
38676
  for (const entry of report) {
37861
- console.log(chalk2.bold(` ${entry.skill}`));
37862
- if (entry.envVars.length === 0) {
37863
- console.log(chalk2.dim(" No environment variables required"));
37864
- } else {
37865
- for (const v of entry.envVars) {
37866
- const status = v.set ? chalk2.green("set") : chalk2.red("missing");
37867
- console.log(` ${v.name} [${status}]`);
37868
- }
38677
+ const icon = entry.healthy ? chalk2.green("\u2713") : chalk2.red("\u2717");
38678
+ console.log(` ${icon} ${chalk2.bold(entry.skill)}`);
38679
+ for (const v of entry.envVars) {
38680
+ const status = v.set ? chalk2.green("set") : chalk2.red("missing");
38681
+ console.log(` ${v.name} [${status}]`);
37869
38682
  }
38683
+ for (const d of entry.systemDeps) {
38684
+ const status = d.available ? chalk2.green("available") : chalk2.red("not found");
38685
+ console.log(` ${d.name} [${status}]`);
38686
+ }
38687
+ if (entry.envVars.length === 0 && entry.systemDeps.length === 0) {
38688
+ console.log(chalk2.dim(" No requirements"));
38689
+ }
38690
+ }
38691
+ if (issues.length === 0) {
38692
+ console.log(chalk2.green(`
38693
+ All skills healthy! \u2713`));
37870
38694
  }
37871
38695
  });
37872
38696
  program2.command("auth").argument("[skill]", "Skill name (omit to check all installed skills)").option("--set <assignment>", "Set an env var in .env file (format: KEY=VALUE)").option("--json", "Output as JSON", false).description("Show auth/env var status for a skill or all installed skills").action((name, options) => {
37873
38697
  const cwd = process.cwd();
37874
- const envFilePath = join5(cwd, ".env");
38698
+ const envFilePath = join8(cwd, ".env");
37875
38699
  if (options.set) {
37876
38700
  const eqIdx = options.set.indexOf("=");
37877
38701
  if (eqIdx === -1) {
@@ -37887,8 +38711,8 @@ program2.command("auth").argument("[skill]", "Skill name (omit to check all inst
37887
38711
  return;
37888
38712
  }
37889
38713
  let existing = "";
37890
- if (existsSync5(envFilePath)) {
37891
- existing = readFileSync4(envFilePath, "utf-8");
38714
+ if (existsSync8(envFilePath)) {
38715
+ existing = readFileSync7(envFilePath, "utf-8");
37892
38716
  }
37893
38717
  const keyPattern = new RegExp(`^${key}=.*$`, "m");
37894
38718
  let updated;
@@ -37901,7 +38725,7 @@ program2.command("auth").argument("[skill]", "Skill name (omit to check all inst
37901
38725
  ${key}=${value}
37902
38726
  `;
37903
38727
  }
37904
- writeFileSync2(envFilePath, updated, "utf-8");
38728
+ writeFileSync4(envFilePath, updated, "utf-8");
37905
38729
  console.log(chalk2.green(`Set ${key} in ${envFilePath}`));
37906
38730
  return;
37907
38731
  }
@@ -37967,25 +38791,24 @@ Auth status (${installed.length} installed skills):
37967
38791
  }
37968
38792
  });
37969
38793
  program2.command("whoami").option("--json", "Output as JSON", false).description("Show setup summary: version, installed skills, agent configs, and paths").action((options) => {
37970
- const { homedir: homedir3 } = __require("os");
38794
+ const { homedir: homedir4 } = __require("os");
37971
38795
  const version2 = package_default.version;
37972
38796
  const cwd = process.cwd();
37973
38797
  const installed = getInstalledSkills();
37974
- const agentNames = ["claude", "codex", "gemini"];
37975
38798
  const agentConfigs = [];
37976
- for (const agent of agentNames) {
37977
- const agentSkillsPath = join5(homedir3(), `.${agent}`, "skills");
37978
- const exists = existsSync5(agentSkillsPath);
38799
+ for (const agent of AGENT_TARGETS) {
38800
+ const agentSkillsPath = getAgentSkillsDir(agent, "global");
38801
+ const exists = existsSync8(agentSkillsPath);
37979
38802
  let skillCount = 0;
37980
38803
  if (exists) {
37981
38804
  try {
37982
- skillCount = readdirSync4(agentSkillsPath).filter((f) => {
37983
- const full = join5(agentSkillsPath, f);
38805
+ skillCount = readdirSync5(agentSkillsPath).filter((f) => {
38806
+ const full = join8(agentSkillsPath, f);
37984
38807
  return f.startsWith("skill-") && statSync3(full).isDirectory();
37985
38808
  }).length;
37986
38809
  } catch {}
37987
38810
  }
37988
- agentConfigs.push({ agent, path: agentSkillsPath, exists, skillCount });
38811
+ agentConfigs.push({ agent, label: AGENT_LABELS[agent], path: agentSkillsPath, exists, skillCount });
37989
38812
  }
37990
38813
  const skillsDir = getSkillPath("image").replace(/[/\\][^/\\]*$/, "");
37991
38814
  if (options.json) {
@@ -38125,19 +38948,19 @@ program2.command("outdated").option("--json", "Output as JSON", false).descripti
38125
38948
  const upToDate = [];
38126
38949
  for (const name of installed) {
38127
38950
  const skillName = normalizeSkillName(name);
38128
- const installedPkgPath = join5(cwd, ".skills", skillName, "package.json");
38951
+ const installedPkgPath = join8(cwd, ".skills", skillName, "package.json");
38129
38952
  let installedVersion = "unknown";
38130
- if (existsSync5(installedPkgPath)) {
38953
+ if (existsSync8(installedPkgPath)) {
38131
38954
  try {
38132
- installedVersion = JSON.parse(readFileSync4(installedPkgPath, "utf-8")).version || "unknown";
38955
+ installedVersion = JSON.parse(readFileSync7(installedPkgPath, "utf-8")).version || "unknown";
38133
38956
  } catch {}
38134
38957
  }
38135
38958
  const registryPath = getSkillPath(name);
38136
- const registryPkgPath = join5(registryPath, "package.json");
38959
+ const registryPkgPath = join8(registryPath, "package.json");
38137
38960
  let registryVersion = "unknown";
38138
- if (existsSync5(registryPkgPath)) {
38961
+ if (existsSync8(registryPkgPath)) {
38139
38962
  try {
38140
- registryVersion = JSON.parse(readFileSync4(registryPkgPath, "utf-8")).version || "unknown";
38963
+ registryVersion = JSON.parse(readFileSync7(registryPkgPath, "utf-8")).version || "unknown";
38141
38964
  } catch {}
38142
38965
  }
38143
38966
  if (installedVersion !== registryVersion) {
@@ -38168,4 +38991,504 @@ ${upToDate.length} skill(s) up to date`));
38168
38991
  console.log(chalk2.dim(`
38169
38992
  Run ${chalk2.bold("skills update")} to update all outdated skills`));
38170
38993
  });
38994
+ var configCmd = program2.command("config").description("Manage skills configuration");
38995
+ configCmd.command("show", { isDefault: true }).description("Show current merged configuration").action(() => {
38996
+ const config2 = loadConfig();
38997
+ const keys = Object.keys(config2);
38998
+ if (keys.length === 0) {
38999
+ console.log(chalk2.dim("No configuration set"));
39000
+ return;
39001
+ }
39002
+ for (const [key, value] of Object.entries(config2)) {
39003
+ console.log(`${chalk2.cyan(key)} = ${chalk2.bold(value)}`);
39004
+ }
39005
+ });
39006
+ configCmd.command("set <key> <value>").option("--global", "Save to global config (~/.skillsrc)", false).description("Set a configuration value").action((key, value, options) => {
39007
+ const scope = options.global ? "global" : "project";
39008
+ try {
39009
+ saveConfig(key, value, scope);
39010
+ console.log(chalk2.green(`Set ${key} = ${value} (${scope})`));
39011
+ } catch (err) {
39012
+ console.error(chalk2.red(err.message));
39013
+ process.exitCode = 1;
39014
+ }
39015
+ });
39016
+ configCmd.command("get <key>").description("Get a specific configuration value").action((key) => {
39017
+ const config2 = loadConfig();
39018
+ const value = config2[key];
39019
+ if (value === undefined) {
39020
+ console.log(chalk2.dim(`${key} is not set`));
39021
+ } else {
39022
+ console.log(value);
39023
+ }
39024
+ });
39025
+ configCmd.command("path").description("Show configuration file paths").action(() => {
39026
+ const globalPath = getConfigPath("global");
39027
+ const projectPath = getConfigPath("project");
39028
+ console.log(`${chalk2.cyan("global")}: ${globalPath}${existsSync8(globalPath) ? chalk2.green(" (exists)") : chalk2.dim(" (not found)")}`);
39029
+ console.log(`${chalk2.cyan("project")}: ${projectPath}${existsSync8(projectPath) ? chalk2.green(" (exists)") : chalk2.dim(" (not found)")}`);
39030
+ });
39031
+ program2.command("create").argument("<name>", "Skill name (e.g. my-tool)").option("--category <category>", "Skill category", "Development Tools").option("--description <description>", "Short description of what the skill does").option("--tags <tags>", "Comma-separated tags (e.g. api,testing,automation)").option("--global", "Create in ~/.skills/ instead of .skills/custom-skills/", false).option("--json", "Output result as JSON", false).description("Scaffold a new custom skill directory").action((name, options) => {
39032
+ const { homedir: homedir4 } = __require("os");
39033
+ const bare = name.replace(/^skill-/, "");
39034
+ const dirName = `skill-${bare}`;
39035
+ const baseDir = options.global ? join8(homedir4(), ".skills") : join8(process.cwd(), ".skills", "custom-skills");
39036
+ const skillDir = join8(baseDir, dirName);
39037
+ if (existsSync8(skillDir)) {
39038
+ if (options.json) {
39039
+ console.log(JSON.stringify({ error: `Skill '${bare}' already exists at ${skillDir}` }));
39040
+ } else {
39041
+ console.error(chalk2.red(`Skill '${bare}' already exists at ${skillDir}`));
39042
+ }
39043
+ process.exitCode = 1;
39044
+ return;
39045
+ }
39046
+ const description = options.description || `${bare} skill`;
39047
+ const tags = options.tags ? options.tags.split(",").map((t) => t.trim()).filter(Boolean) : [bare];
39048
+ const displayName = bare.replace(/-/g, " ").replace(/\b\w/g, (c) => c.toUpperCase());
39049
+ const category = options.category;
39050
+ mkdirSync4(join8(skillDir, "src"), { recursive: true });
39051
+ writeFileSync4(join8(skillDir, "SKILL.md"), [
39052
+ "---",
39053
+ `name: ${bare}`,
39054
+ `description: ${description}`,
39055
+ `displayName: ${displayName}`,
39056
+ `category: ${category}`,
39057
+ `tags: [${tags.join(", ")}]`,
39058
+ "---",
39059
+ "",
39060
+ `# ${displayName}`,
39061
+ "",
39062
+ description,
39063
+ "",
39064
+ "## Usage",
39065
+ "",
39066
+ "```bash",
39067
+ `${bare} --help`,
39068
+ "```",
39069
+ ""
39070
+ ].join(`
39071
+ `));
39072
+ writeFileSync4(join8(skillDir, "src", "index.ts"), [
39073
+ `#!/usr/bin/env bun`,
39074
+ `/**`,
39075
+ ` * ${displayName} \u2014 ${description}`,
39076
+ ` */`,
39077
+ "",
39078
+ `console.log("${displayName}");`,
39079
+ ""
39080
+ ].join(`
39081
+ `));
39082
+ writeFileSync4(join8(skillDir, "package.json"), JSON.stringify({
39083
+ name: `skill-${bare}`,
39084
+ version: "0.1.0",
39085
+ description,
39086
+ bin: { [bare]: "./src/index.ts" },
39087
+ scripts: { dev: `bun src/index.ts` },
39088
+ dependencies: {}
39089
+ }, null, 2) + `
39090
+ `);
39091
+ writeFileSync4(join8(skillDir, "tsconfig.json"), JSON.stringify({
39092
+ compilerOptions: {
39093
+ target: "ES2022",
39094
+ module: "ESNext",
39095
+ moduleResolution: "bundler",
39096
+ strict: true,
39097
+ outDir: "dist"
39098
+ },
39099
+ include: ["src/**/*.ts"]
39100
+ }, null, 2) + `
39101
+ `);
39102
+ clearRegistryCache();
39103
+ if (options.json) {
39104
+ console.log(JSON.stringify({ created: true, name: bare, path: skillDir, category, tags }));
39105
+ } else {
39106
+ console.log(chalk2.green(`\u2713 Created custom skill '${bare}' at ${skillDir}`));
39107
+ console.log(chalk2.dim(` Category: ${category}`));
39108
+ console.log(chalk2.dim(` Tags: ${tags.join(", ")}`));
39109
+ console.log("");
39110
+ console.log(` ${chalk2.cyan("Edit:")} ${join8(skillDir, "src", "index.ts")}`);
39111
+ console.log(` ${chalk2.cyan("Run:")} bun ${join8(skillDir, "src", "index.ts")}`);
39112
+ console.log(` ${chalk2.cyan("Docs:")} ${join8(skillDir, "SKILL.md")}`);
39113
+ }
39114
+ });
39115
+ program2.command("sync").option("--to <agent>", "Push custom skills to agent: claude, codex, gemini, pi, opencode, or all").option("--from <agent>", "List agent skills and show which are unknown to the registry").option("--register", "With --from: copy unknown agent skills into ~/.skills/ to add them to the registry", false).option("--scope <scope>", "Agent install scope: global or project", "global").option("--json", "Output as JSON", false).description("Sync custom skills with agent directories (--to or --from)").action((options) => {
39116
+ const { homedir: homedir4 } = __require("os");
39117
+ if (!options.to && !options.from) {
39118
+ console.error(chalk2.red("Specify --to <agent> or --from <agent>"));
39119
+ process.exitCode = 1;
39120
+ return;
39121
+ }
39122
+ if (options.from) {
39123
+ const agentName = options.from;
39124
+ if (!AGENT_TARGETS.includes(agentName)) {
39125
+ console.error(chalk2.red(`Unknown agent: ${agentName}. Available: ${AGENT_TARGETS.join(", ")}`));
39126
+ process.exitCode = 1;
39127
+ return;
39128
+ }
39129
+ const agentDir = getAgentSkillsDir(agentName, options.scope);
39130
+ if (!existsSync8(agentDir)) {
39131
+ if (options.json) {
39132
+ console.log(JSON.stringify({ agentDir, skills: [], message: "Directory not found" }));
39133
+ } else {
39134
+ console.log(chalk2.dim(`No skills directory found at ${agentDir}`));
39135
+ }
39136
+ return;
39137
+ }
39138
+ const registry2 = loadRegistry();
39139
+ const registryNames = new Set(registry2.map((s) => s.name));
39140
+ const found = [];
39141
+ for (const entry of readdirSync5(agentDir, { withFileTypes: true })) {
39142
+ if (!entry.isDirectory())
39143
+ continue;
39144
+ const bare = entry.name.replace(/^skill-/, "");
39145
+ found.push({
39146
+ name: bare,
39147
+ path: join8(agentDir, entry.name),
39148
+ inRegistry: registryNames.has(bare)
39149
+ });
39150
+ }
39151
+ const unknown3 = found.filter((s) => !s.inRegistry);
39152
+ if (options.register && unknown3.length > 0) {
39153
+ const globalSkillsDir = join8(homedir4(), ".skills");
39154
+ const registered = [];
39155
+ for (const s of unknown3) {
39156
+ const srcSkillMd = join8(s.path, "SKILL.md");
39157
+ if (!existsSync8(srcSkillMd))
39158
+ continue;
39159
+ const destDir = join8(globalSkillsDir, `skill-${s.name}`);
39160
+ if (!existsSync8(destDir)) {
39161
+ mkdirSync4(destDir, { recursive: true });
39162
+ }
39163
+ writeFileSync4(join8(destDir, "SKILL.md"), readFileSync7(srcSkillMd, "utf-8"));
39164
+ registered.push(s.name);
39165
+ }
39166
+ clearRegistryCache();
39167
+ if (options.json) {
39168
+ console.log(JSON.stringify({ agentDir, skills: found, registered }));
39169
+ } else {
39170
+ for (const name of registered) {
39171
+ console.log(chalk2.green(`\u2713 Registered '${name}' into ~/.skills/ (global custom)`));
39172
+ }
39173
+ if (registered.length === 0)
39174
+ console.log(chalk2.dim("No new skills to register (all SKILL.md files missing)"));
39175
+ }
39176
+ return;
39177
+ }
39178
+ if (options.json) {
39179
+ console.log(JSON.stringify({ agentDir, skills: found }));
39180
+ } else {
39181
+ console.log(chalk2.bold(`
39182
+ Agent skills in ~/.${agentName}/skills/ (${found.length} found):
39183
+ `));
39184
+ for (const s of found) {
39185
+ const label = s.inRegistry ? chalk2.green("\u2713 in registry") : chalk2.yellow("\u2717 not in registry");
39186
+ console.log(` ${chalk2.cyan(s.name)} \u2014 ${label}`);
39187
+ }
39188
+ if (unknown3.length > 0) {
39189
+ console.log("");
39190
+ console.log(chalk2.dim(`Tip: ${unknown3.length} skill(s) not in registry. Run with --register to add them to ~/.skills/.`));
39191
+ }
39192
+ }
39193
+ return;
39194
+ }
39195
+ if (options.to) {
39196
+ let agents;
39197
+ try {
39198
+ agents = resolveAgents(options.to);
39199
+ } catch (err) {
39200
+ console.error(chalk2.red(err.message));
39201
+ process.exitCode = 1;
39202
+ return;
39203
+ }
39204
+ const registry2 = loadRegistry();
39205
+ const customSkills = registry2.filter((s) => s.source === "custom");
39206
+ if (customSkills.length === 0) {
39207
+ if (options.json) {
39208
+ console.log(JSON.stringify({ pushed: 0, message: "No custom skills found" }));
39209
+ } else {
39210
+ console.log(chalk2.dim("No custom skills found. Use 'skills create <name>' to scaffold one."));
39211
+ }
39212
+ return;
39213
+ }
39214
+ const results = [];
39215
+ for (const skill of customSkills) {
39216
+ for (const agent of agents) {
39217
+ const result = installSkillForAgent(skill.name, {
39218
+ agent,
39219
+ scope: options.scope
39220
+ }, generateSkillMd);
39221
+ results.push({ skill: skill.name, agent, success: result.success, error: result.error });
39222
+ }
39223
+ }
39224
+ if (options.json) {
39225
+ console.log(JSON.stringify({ pushed: results.filter((r) => r.success).length, results }));
39226
+ } else {
39227
+ for (const r of results) {
39228
+ if (r.success) {
39229
+ console.log(chalk2.green(`\u2713 ${r.skill} \u2192 ${r.agent}`));
39230
+ } else {
39231
+ console.log(chalk2.red(`\u2717 ${r.skill} \u2192 ${r.agent}: ${r.error}`));
39232
+ }
39233
+ }
39234
+ }
39235
+ }
39236
+ });
39237
+ program2.command("validate").argument("<name>", "Skill name to validate").option("--json", "Output as JSON", false).description("Validate a skill's directory structure (SKILL.md, package.json, src/index.ts, tsconfig.json)").action((name, options) => {
39238
+ const skillPath = getSkillPath(name);
39239
+ const issues = [];
39240
+ if (!existsSync8(skillPath)) {
39241
+ if (options.json) {
39242
+ console.log(JSON.stringify({ name, valid: false, issues: [`Skill directory not found: ${skillPath}`] }));
39243
+ } else {
39244
+ console.error(chalk2.red(`Skill '${name}' not found at ${skillPath}`));
39245
+ }
39246
+ process.exitCode = 1;
39247
+ return;
39248
+ }
39249
+ if (!existsSync8(join8(skillPath, "SKILL.md")))
39250
+ issues.push("Missing SKILL.md");
39251
+ if (!existsSync8(join8(skillPath, "tsconfig.json")))
39252
+ issues.push("Missing tsconfig.json");
39253
+ const pkgPath = join8(skillPath, "package.json");
39254
+ if (!existsSync8(pkgPath)) {
39255
+ issues.push("Missing package.json");
39256
+ } else {
39257
+ try {
39258
+ const pkg = JSON.parse(readFileSync7(pkgPath, "utf-8"));
39259
+ if (!pkg.bin || Object.keys(pkg.bin).length === 0)
39260
+ issues.push("package.json missing 'bin' entry");
39261
+ } catch {
39262
+ issues.push("package.json is invalid JSON");
39263
+ }
39264
+ }
39265
+ if (!existsSync8(join8(skillPath, "src"))) {
39266
+ issues.push("Missing src/ directory");
39267
+ } else if (!existsSync8(join8(skillPath, "src", "index.ts"))) {
39268
+ issues.push("Missing src/index.ts");
39269
+ }
39270
+ const valid = issues.length === 0;
39271
+ if (options.json) {
39272
+ console.log(JSON.stringify({ name, valid, path: skillPath, issues }));
39273
+ } else if (valid) {
39274
+ console.log(chalk2.green(`\u2713 ${name} \u2014 all checks passed`));
39275
+ } else {
39276
+ console.log(chalk2.red(`\u2717 ${name} \u2014 ${issues.length} issue(s):`));
39277
+ for (const issue2 of issues)
39278
+ console.log(chalk2.red(` \u2022 ${issue2}`));
39279
+ process.exitCode = 1;
39280
+ }
39281
+ });
39282
+ program2.command("diff").argument("<name>", "Skill name to diff").option("--json", "Output as JSON", false).description("Show files that differ between installed version and source (preview before update)").action((name, options) => {
39283
+ const bare = name.replace(/^skill-/, "");
39284
+ const skillName = `skill-${bare}`;
39285
+ const destPath = join8(process.cwd(), ".skills", skillName);
39286
+ const sourcePath = getSkillPath(bare);
39287
+ if (!existsSync8(sourcePath)) {
39288
+ if (options.json) {
39289
+ console.log(JSON.stringify({ error: `Skill '${bare}' not found in registry` }));
39290
+ } else {
39291
+ skillNotFound(bare);
39292
+ }
39293
+ process.exitCode = 1;
39294
+ return;
39295
+ }
39296
+ if (!existsSync8(destPath)) {
39297
+ if (options.json) {
39298
+ console.log(JSON.stringify({ installed: false, message: `'${bare}' is not installed locally` }));
39299
+ } else {
39300
+ console.log(chalk2.dim(`'${bare}' is not installed. Run: skills install ${bare}`));
39301
+ }
39302
+ return;
39303
+ }
39304
+ function collectFiles(dir, base = "") {
39305
+ const files = new Map;
39306
+ if (!existsSync8(dir))
39307
+ return files;
39308
+ for (const entry of readdirSync5(dir)) {
39309
+ const full = join8(dir, entry);
39310
+ const rel = base ? `${base}/${entry}` : entry;
39311
+ if (statSync3(full).isDirectory()) {
39312
+ for (const [k, v] of collectFiles(full, rel))
39313
+ files.set(k, v);
39314
+ } else {
39315
+ try {
39316
+ files.set(rel, readFileSync7(full, "utf-8"));
39317
+ } catch {
39318
+ files.set(rel, "");
39319
+ }
39320
+ }
39321
+ }
39322
+ return files;
39323
+ }
39324
+ const installed = collectFiles(destPath);
39325
+ const source = collectFiles(sourcePath);
39326
+ const changed = [];
39327
+ const added = [];
39328
+ const removed = [];
39329
+ for (const [file2, content] of source) {
39330
+ if (!installed.has(file2))
39331
+ added.push(file2);
39332
+ else if (installed.get(file2) !== content)
39333
+ changed.push(file2);
39334
+ }
39335
+ for (const file2 of installed.keys()) {
39336
+ if (!source.has(file2))
39337
+ removed.push(file2);
39338
+ }
39339
+ if (options.json) {
39340
+ console.log(JSON.stringify({ name: bare, changed, added, removed, upToDate: changed.length === 0 && added.length === 0 && removed.length === 0 }));
39341
+ return;
39342
+ }
39343
+ if (changed.length === 0 && added.length === 0 && removed.length === 0) {
39344
+ console.log(chalk2.green(`\u2713 ${bare} \u2014 up to date`));
39345
+ return;
39346
+ }
39347
+ console.log(chalk2.bold(`
39348
+ Diff for '${bare}':
39349
+ `));
39350
+ for (const f of changed)
39351
+ console.log(chalk2.yellow(` ~ ${f}`));
39352
+ for (const f of added)
39353
+ console.log(chalk2.green(` + ${f}`));
39354
+ for (const f of removed)
39355
+ console.log(chalk2.red(` - ${f}`));
39356
+ console.log(`
39357
+ ${chalk2.dim(`Run 'skills update ${bare}' to apply changes`)}`);
39358
+ });
39359
+ var scheduleCmd = program2.command("schedule").description("Manage scheduled skill runs (cron-based)");
39360
+ scheduleCmd.command("add").argument("<skill>", "Skill to schedule (bare name, e.g. image)").argument("<cron>", '5-field cron expression (e.g. "0 9 * * *" = daily at 9am)').option("--name <label>", "Human-readable label for this schedule").option("--args <args>", "Space-separated args to pass to the skill").option("--json", "Output as JSON", false).description("Add a cron schedule for a skill").action((skill, cron, options) => {
39361
+ const args = options.args ? options.args.split(" ").filter(Boolean) : undefined;
39362
+ const { schedule, error: error48 } = addSchedule(skill, cron, { name: options.name, args });
39363
+ if (options.json) {
39364
+ console.log(JSON.stringify(schedule ? { schedule } : { error: error48 }));
39365
+ return;
39366
+ }
39367
+ if (error48 || !schedule) {
39368
+ console.error(chalk2.red(`\u2717 ${error48 || "Failed to add schedule"}`));
39369
+ process.exitCode = 1;
39370
+ return;
39371
+ }
39372
+ console.log(chalk2.green(`\u2713 Scheduled '${schedule.name}'`));
39373
+ console.log(chalk2.dim(` Cron: ${schedule.cron}`));
39374
+ if (schedule.nextRun) {
39375
+ console.log(chalk2.dim(` Next run: ${new Date(schedule.nextRun).toLocaleString()}`));
39376
+ }
39377
+ console.log(chalk2.dim(` ID: ${schedule.id}`));
39378
+ });
39379
+ scheduleCmd.command("list").option("--json", "Output as JSON", false).description("List all scheduled skills").action((options) => {
39380
+ const schedules = listSchedules();
39381
+ if (options.json) {
39382
+ console.log(JSON.stringify(schedules));
39383
+ return;
39384
+ }
39385
+ if (schedules.length === 0) {
39386
+ console.log(chalk2.dim("No schedules. Run: skills schedule add <skill> <cron>"));
39387
+ return;
39388
+ }
39389
+ console.log(chalk2.bold(`
39390
+ Scheduled skills (${schedules.length}):
39391
+ `));
39392
+ for (const s of schedules) {
39393
+ const status = s.enabled ? chalk2.green("enabled") : chalk2.dim("disabled");
39394
+ const last = s.lastRun ? `last: ${new Date(s.lastRun).toLocaleString()} [${s.lastRunStatus ?? "?"}]` : "never run";
39395
+ const next = s.nextRun ? `next: ${new Date(s.nextRun).toLocaleString()}` : "";
39396
+ console.log(` ${chalk2.cyan(s.name)} [${status}]`);
39397
+ console.log(chalk2.dim(` skill: ${s.skill} cron: ${s.cron} ${last} ${next}`));
39398
+ }
39399
+ });
39400
+ scheduleCmd.command("remove").argument("<id-or-name>", "Schedule ID or name to remove").option("--json", "Output as JSON", false).description("Remove a schedule").action((idOrName, options) => {
39401
+ const removed = removeSchedule(idOrName);
39402
+ if (options.json) {
39403
+ console.log(JSON.stringify({ removed, idOrName }));
39404
+ return;
39405
+ }
39406
+ if (removed) {
39407
+ console.log(chalk2.green(`\u2713 Removed schedule '${idOrName}'`));
39408
+ } else {
39409
+ console.error(chalk2.red(`Schedule '${idOrName}' not found`));
39410
+ process.exitCode = 1;
39411
+ }
39412
+ });
39413
+ scheduleCmd.command("enable").argument("<id-or-name>", "Schedule ID or name").description("Enable a disabled schedule").action((idOrName) => {
39414
+ const ok = setScheduleEnabled(idOrName, true);
39415
+ if (ok)
39416
+ console.log(chalk2.green(`\u2713 Enabled '${idOrName}'`));
39417
+ else {
39418
+ console.error(chalk2.red(`Schedule '${idOrName}' not found`));
39419
+ process.exitCode = 1;
39420
+ }
39421
+ });
39422
+ scheduleCmd.command("disable").argument("<id-or-name>", "Schedule ID or name").description("Disable a schedule without removing it").action((idOrName) => {
39423
+ const ok = setScheduleEnabled(idOrName, false);
39424
+ if (ok)
39425
+ console.log(chalk2.green(`\u2713 Disabled '${idOrName}'`));
39426
+ else {
39427
+ console.error(chalk2.red(`Schedule '${idOrName}' not found`));
39428
+ process.exitCode = 1;
39429
+ }
39430
+ });
39431
+ scheduleCmd.command("run").option("--dry-run", "Show which schedules are due without running them", false).option("--json", "Output as JSON", false).description("Execute all due schedules now").action(async (options) => {
39432
+ const due = getDueSchedules();
39433
+ if (due.length === 0) {
39434
+ if (options.json)
39435
+ console.log(JSON.stringify({ ran: 0, schedules: [] }));
39436
+ else
39437
+ console.log(chalk2.dim("No schedules are due."));
39438
+ return;
39439
+ }
39440
+ if (options.dryRun) {
39441
+ if (options.json)
39442
+ console.log(JSON.stringify({ due: due.map((s) => s.name) }));
39443
+ else {
39444
+ console.log(chalk2.bold(`${due.length} schedule(s) due:
39445
+ `));
39446
+ for (const s of due)
39447
+ console.log(` ${chalk2.cyan(s.name)} \u2014 ${s.skill} (${s.cron})`);
39448
+ }
39449
+ return;
39450
+ }
39451
+ const results = [];
39452
+ for (const s of due) {
39453
+ try {
39454
+ const { runSkill: runSkill2 } = await Promise.resolve().then(() => (init_skillinfo(), exports_skillinfo));
39455
+ await runSkill2(s.skill, s.args ?? []);
39456
+ recordScheduleRun(s.id, "success");
39457
+ results.push({ name: s.name, skill: s.skill, status: "success" });
39458
+ } catch (err) {
39459
+ recordScheduleRun(s.id, "error");
39460
+ results.push({ name: s.name, skill: s.skill, status: "error", error: err.message });
39461
+ }
39462
+ }
39463
+ if (options.json) {
39464
+ console.log(JSON.stringify({ ran: results.length, results }));
39465
+ } else {
39466
+ for (const r of results) {
39467
+ const icon = r.status === "success" ? chalk2.green("\u2713") : chalk2.red("\u2717");
39468
+ console.log(`${icon} ${r.name} (${r.skill})`);
39469
+ if (r.error)
39470
+ console.log(chalk2.dim(` ${r.error}`));
39471
+ }
39472
+ }
39473
+ });
39474
+ scheduleCmd.command("validate").argument("<cron>", "Cron expression to validate").description("Validate a cron expression and show the next 5 run times").action((cron) => {
39475
+ const { getNextRun: getNextRun2 } = (init_scheduler(), __toCommonJS(exports_scheduler));
39476
+ const { valid, error: error48 } = validateCron(cron);
39477
+ if (!valid) {
39478
+ console.error(chalk2.red(`Invalid cron: ${error48}`));
39479
+ process.exitCode = 1;
39480
+ return;
39481
+ }
39482
+ console.log(chalk2.green(`\u2713 Valid cron: "${cron}"`));
39483
+ console.log(chalk2.dim(`
39484
+ Next 5 run times:`));
39485
+ let d = new Date;
39486
+ for (let i = 0;i < 5; i++) {
39487
+ const next = getNextRun2(cron, d);
39488
+ if (!next)
39489
+ break;
39490
+ console.log(` ${next.toLocaleString()}`);
39491
+ d = next;
39492
+ }
39493
+ });
38171
39494
  program2.parse();