@ketecode/loom 0.0.0-stage → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (656) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +516 -2
  3. package/agents/accessibility-reviewer/AGENT.md +70 -0
  4. package/agents/accessibility-reviewer/evals/triggers.json +15 -0
  5. package/agents/agent-evaluator/AGENT.md +74 -0
  6. package/agents/agent-evaluator/evals/triggers.json +15 -0
  7. package/agents/architect/AGENT.md +82 -0
  8. package/agents/architect/evals/triggers.json +17 -0
  9. package/agents/billing-reviewer/AGENT.md +68 -0
  10. package/agents/billing-reviewer/evals/triggers.json +16 -0
  11. package/agents/code-reviewer/AGENT.md +51 -0
  12. package/agents/code-reviewer/evals/triggers.json +14 -0
  13. package/agents/code-simplifier/AGENT.md +74 -0
  14. package/agents/code-simplifier/evals/triggers.json +15 -0
  15. package/agents/cpp-build-resolver/AGENT.md +73 -0
  16. package/agents/cpp-build-resolver/evals/triggers.json +16 -0
  17. package/agents/cpp-reviewer/AGENT.md +59 -0
  18. package/agents/cpp-reviewer/evals/triggers.json +16 -0
  19. package/agents/csharp-build-resolver/AGENT.md +84 -0
  20. package/agents/csharp-build-resolver/evals/triggers.json +17 -0
  21. package/agents/csharp-reviewer/AGENT.md +88 -0
  22. package/agents/csharp-reviewer/evals/triggers.json +17 -0
  23. package/agents/dart-build-resolver/AGENT.md +80 -0
  24. package/agents/dart-build-resolver/evals/triggers.json +17 -0
  25. package/agents/dart-reviewer/AGENT.md +66 -0
  26. package/agents/dart-reviewer/evals/triggers.json +17 -0
  27. package/agents/database-reviewer/AGENT.md +72 -0
  28. package/agents/database-reviewer/evals/triggers.json +16 -0
  29. package/agents/django-reviewer/AGENT.md +61 -0
  30. package/agents/django-reviewer/evals/triggers.json +15 -0
  31. package/agents/doc-updater/AGENT.md +92 -0
  32. package/agents/doc-updater/evals/triggers.json +14 -0
  33. package/agents/e2e-runner/AGENT.md +88 -0
  34. package/agents/e2e-runner/evals/triggers.json +16 -0
  35. package/agents/fastapi-reviewer/AGENT.md +63 -0
  36. package/agents/fastapi-reviewer/evals/triggers.json +15 -0
  37. package/agents/flutter-reviewer/AGENT.md +70 -0
  38. package/agents/flutter-reviewer/evals/triggers.json +15 -0
  39. package/agents/fsharp-build-resolver/AGENT.md +81 -0
  40. package/agents/fsharp-build-resolver/evals/triggers.json +15 -0
  41. package/agents/fsharp-reviewer/AGENT.md +77 -0
  42. package/agents/fsharp-reviewer/evals/triggers.json +15 -0
  43. package/agents/go-build-resolver/AGENT.md +85 -0
  44. package/agents/go-build-resolver/evals/triggers.json +16 -0
  45. package/agents/go-reviewer/AGENT.md +66 -0
  46. package/agents/go-reviewer/evals/triggers.json +16 -0
  47. package/agents/healthcare-reviewer/AGENT.md +65 -0
  48. package/agents/healthcare-reviewer/evals/triggers.json +16 -0
  49. package/agents/i18n-reviewer/AGENT.md +64 -0
  50. package/agents/i18n-reviewer/evals/triggers.json +16 -0
  51. package/agents/infra-reviewer/AGENT.md +93 -0
  52. package/agents/infra-reviewer/evals/triggers.json +15 -0
  53. package/agents/java-build-resolver/AGENT.md +82 -0
  54. package/agents/java-build-resolver/evals/triggers.json +16 -0
  55. package/agents/java-reviewer/AGENT.md +64 -0
  56. package/agents/java-reviewer/evals/triggers.json +16 -0
  57. package/agents/kotlin-build-resolver/AGENT.md +89 -0
  58. package/agents/kotlin-build-resolver/evals/triggers.json +16 -0
  59. package/agents/kotlin-reviewer/AGENT.md +75 -0
  60. package/agents/kotlin-reviewer/evals/triggers.json +16 -0
  61. package/agents/mle-reviewer/AGENT.md +68 -0
  62. package/agents/mle-reviewer/evals/triggers.json +16 -0
  63. package/agents/network-config-reviewer/AGENT.md +68 -0
  64. package/agents/network-config-reviewer/evals/triggers.json +17 -0
  65. package/agents/payments-reviewer/AGENT.md +64 -0
  66. package/agents/payments-reviewer/evals/triggers.json +16 -0
  67. package/agents/performance-optimizer/AGENT.md +86 -0
  68. package/agents/performance-optimizer/evals/triggers.json +16 -0
  69. package/agents/perl-build-resolver/AGENT.md +84 -0
  70. package/agents/perl-build-resolver/evals/triggers.json +15 -0
  71. package/agents/perl-reviewer/AGENT.md +77 -0
  72. package/agents/perl-reviewer/evals/triggers.json +15 -0
  73. package/agents/php-build-resolver/AGENT.md +88 -0
  74. package/agents/php-build-resolver/evals/triggers.json +16 -0
  75. package/agents/php-reviewer/AGENT.md +61 -0
  76. package/agents/php-reviewer/evals/triggers.json +15 -0
  77. package/agents/planner/AGENT.md +75 -0
  78. package/agents/planner/evals/triggers.json +17 -0
  79. package/agents/pr-test-analyzer/AGENT.md +82 -0
  80. package/agents/pr-test-analyzer/evals/triggers.json +16 -0
  81. package/agents/python-build-resolver/AGENT.md +87 -0
  82. package/agents/python-build-resolver/evals/triggers.json +16 -0
  83. package/agents/python-reviewer/AGENT.md +63 -0
  84. package/agents/python-reviewer/evals/triggers.json +15 -0
  85. package/agents/rag-reviewer/AGENT.md +71 -0
  86. package/agents/rag-reviewer/evals/triggers.json +16 -0
  87. package/agents/react-reviewer/AGENT.md +70 -0
  88. package/agents/react-reviewer/evals/triggers.json +16 -0
  89. package/agents/refactor-cleaner/AGENT.md +82 -0
  90. package/agents/refactor-cleaner/evals/triggers.json +16 -0
  91. package/agents/ruby-build-resolver/AGENT.md +93 -0
  92. package/agents/ruby-build-resolver/evals/triggers.json +16 -0
  93. package/agents/ruby-reviewer/AGENT.md +62 -0
  94. package/agents/ruby-reviewer/evals/triggers.json +16 -0
  95. package/agents/rust-build-resolver/AGENT.md +98 -0
  96. package/agents/rust-build-resolver/evals/triggers.json +16 -0
  97. package/agents/rust-reviewer/AGENT.md +78 -0
  98. package/agents/rust-reviewer/evals/triggers.json +15 -0
  99. package/agents/security-reviewer/AGENT.md +84 -0
  100. package/agents/security-reviewer/evals/triggers.json +16 -0
  101. package/agents/silent-failure-hunter/AGENT.md +66 -0
  102. package/agents/silent-failure-hunter/evals/triggers.json +16 -0
  103. package/agents/solidity-reviewer/AGENT.md +70 -0
  104. package/agents/solidity-reviewer/evals/triggers.json +16 -0
  105. package/agents/swift-build-resolver/AGENT.md +85 -0
  106. package/agents/swift-build-resolver/evals/triggers.json +15 -0
  107. package/agents/swift-reviewer/AGENT.md +75 -0
  108. package/agents/swift-reviewer/evals/triggers.json +15 -0
  109. package/agents/typescript-build-resolver/AGENT.md +76 -0
  110. package/agents/typescript-build-resolver/evals/triggers.json +15 -0
  111. package/agents/typescript-reviewer/AGENT.md +76 -0
  112. package/agents/typescript-reviewer/evals/triggers.json +15 -0
  113. package/agents/vue-reviewer/AGENT.md +75 -0
  114. package/agents/vue-reviewer/evals/triggers.json +15 -0
  115. package/bin/kete-loom.js +683 -0
  116. package/commands/aside.md +19 -0
  117. package/commands/build-fix.md +26 -0
  118. package/commands/campaign.md +19 -0
  119. package/commands/changelog.md +36 -0
  120. package/commands/checkpoint.md +26 -0
  121. package/commands/codemap.md +25 -0
  122. package/commands/commit.md +26 -0
  123. package/commands/deps-audit.md +32 -0
  124. package/commands/epic-decompose.md +21 -0
  125. package/commands/explain.md +37 -0
  126. package/commands/feature-dev.md +22 -0
  127. package/commands/hookify.md +23 -0
  128. package/commands/i18n-check.md +39 -0
  129. package/commands/issue-sync.md +22 -0
  130. package/commands/jira.md +19 -0
  131. package/commands/learn.md +23 -0
  132. package/commands/loom.md +21 -0
  133. package/commands/loop.md +20 -0
  134. package/commands/model-route.md +27 -0
  135. package/commands/onboard.md +35 -0
  136. package/commands/orchestrate.md +21 -0
  137. package/commands/plan-feature.md +36 -0
  138. package/commands/postmortem.md +42 -0
  139. package/commands/pr-describe.md +39 -0
  140. package/commands/pr.md +22 -0
  141. package/commands/prd.md +41 -0
  142. package/commands/project-init.md +21 -0
  143. package/commands/refactor-clean.md +24 -0
  144. package/commands/resume-session.md +22 -0
  145. package/commands/review.md +35 -0
  146. package/commands/save-session.md +37 -0
  147. package/commands/security-scan.md +32 -0
  148. package/commands/sessions.md +21 -0
  149. package/commands/skill-create.md +21 -0
  150. package/commands/tdd.md +36 -0
  151. package/commands/test-coverage.md +24 -0
  152. package/commands/threat-model.md +36 -0
  153. package/commands/update-docs.md +25 -0
  154. package/commands/verify.md +21 -0
  155. package/hooks/block-dangerous-commands/HOOK.md +30 -0
  156. package/hooks/block-dangerous-commands/cases.json +50 -0
  157. package/hooks/block-dangerous-commands/hook.js +75 -0
  158. package/hooks/block-no-verify/HOOK.md +25 -0
  159. package/hooks/block-no-verify/cases.json +30 -0
  160. package/hooks/block-no-verify/hook.js +43 -0
  161. package/hooks/format-on-edit/HOOK.md +24 -0
  162. package/hooks/format-on-edit/hook.js +89 -0
  163. package/hooks/guard-secrets/HOOK.md +19 -0
  164. package/hooks/guard-secrets/cases.json +110 -0
  165. package/hooks/guard-secrets/hook.js +44 -0
  166. package/hooks/load-session-context/HOOK.md +20 -0
  167. package/hooks/load-session-context/hook.js +56 -0
  168. package/hooks/protect-files/HOOK.md +24 -0
  169. package/hooks/protect-files/cases.json +27 -0
  170. package/hooks/protect-files/hook.js +39 -0
  171. package/hooks/run.js +132 -0
  172. package/mcp/atlassian.json +11 -0
  173. package/mcp/chrome-devtools.json +18 -0
  174. package/mcp/cloudflare.json +11 -0
  175. package/mcp/context7.json +11 -0
  176. package/mcp/fetch.json +17 -0
  177. package/mcp/figma.json +11 -0
  178. package/mcp/git.json +17 -0
  179. package/mcp/github.json +11 -0
  180. package/mcp/linear.json +11 -0
  181. package/mcp/memory.json +18 -0
  182. package/mcp/notion.json +11 -0
  183. package/mcp/playwright.json +18 -0
  184. package/mcp/sentry.json +11 -0
  185. package/mcp/stripe.json +11 -0
  186. package/mcp/supabase.json +11 -0
  187. package/mcp/time.json +17 -0
  188. package/package.json +59 -4
  189. package/profiles.json +165 -0
  190. package/rules/common.md +21 -0
  191. package/rules/cpp.md +29 -0
  192. package/rules/csharp.md +25 -0
  193. package/rules/dart.md +29 -0
  194. package/rules/fsharp.md +28 -0
  195. package/rules/git.md +26 -0
  196. package/rules/go.md +29 -0
  197. package/rules/java.md +29 -0
  198. package/rules/kotlin.md +27 -0
  199. package/rules/perl.md +26 -0
  200. package/rules/php.md +28 -0
  201. package/rules/python.md +30 -0
  202. package/rules/ruby.md +27 -0
  203. package/rules/rust.md +26 -0
  204. package/rules/security.md +29 -0
  205. package/rules/swift.md +28 -0
  206. package/rules/testing.md +25 -0
  207. package/rules/typescript.md +29 -0
  208. package/schemas/skill-frontmatter.schema.json +52 -0
  209. package/scripts/lib/audit.js +96 -0
  210. package/scripts/lib/frontmatter.js +65 -0
  211. package/scripts/lib/hooks-install.js +292 -0
  212. package/scripts/lib/i18n.js +51 -0
  213. package/scripts/lib/inventory.js +85 -0
  214. package/scripts/lib/lint.js +158 -0
  215. package/scripts/lib/mcp-install.js +284 -0
  216. package/scripts/lib/profiles.js +128 -0
  217. package/scripts/lib/render.js +86 -0
  218. package/scripts/lib/rules-install.js +118 -0
  219. package/scripts/lib/skills.js +86 -0
  220. package/scripts/lib/targets.js +113 -0
  221. package/skills/accounting-api-integration/SKILL.md +81 -0
  222. package/skills/accounting-api-integration/evals/triggers.json +17 -0
  223. package/skills/accounting-api-integration/references/quickbooks.md +48 -0
  224. package/skills/accounting-api-integration/references/xero.md +45 -0
  225. package/skills/agent-harness-design/SKILL.md +125 -0
  226. package/skills/agent-harness-design/evals/triggers.json +21 -0
  227. package/skills/ai-media-generation/SKILL.md +89 -0
  228. package/skills/ai-media-generation/evals/triggers.json +16 -0
  229. package/skills/ai-media-generation/references/job-pipeline.md +76 -0
  230. package/skills/angular-patterns/SKILL.md +122 -0
  231. package/skills/angular-patterns/evals/triggers.json +16 -0
  232. package/skills/api-design/SKILL.md +96 -0
  233. package/skills/api-design/evals/triggers.json +18 -0
  234. package/skills/api-design/references/conventions.md +133 -0
  235. package/skills/architecture-decision-records/SKILL.md +98 -0
  236. package/skills/architecture-decision-records/evals/triggers.json +17 -0
  237. package/skills/article-writing/SKILL.md +108 -0
  238. package/skills/article-writing/evals/triggers.json +16 -0
  239. package/skills/aspnet-core-patterns/SKILL.md +149 -0
  240. package/skills/aspnet-core-patterns/evals/triggers.json +16 -0
  241. package/skills/auth-patterns/SKILL.md +104 -0
  242. package/skills/auth-patterns/evals/triggers.json +17 -0
  243. package/skills/auth-patterns/references/oauth-oidc.md +64 -0
  244. package/skills/autonomous-loops/SKILL.md +99 -0
  245. package/skills/autonomous-loops/evals/triggers.json +14 -0
  246. package/skills/aws-patterns/SKILL.md +91 -0
  247. package/skills/aws-patterns/evals/triggers.json +16 -0
  248. package/skills/azure-patterns/SKILL.md +86 -0
  249. package/skills/azure-patterns/evals/triggers.json +16 -0
  250. package/skills/benchmark-methodology/SKILL.md +88 -0
  251. package/skills/benchmark-methodology/evals/triggers.json +16 -0
  252. package/skills/benchmark-methodology/references/language-harnesses.md +130 -0
  253. package/skills/bgp-diagnostics/SKILL.md +84 -0
  254. package/skills/bgp-diagnostics/evals/triggers.json +18 -0
  255. package/skills/bgp-diagnostics/references/bgp-reference.md +81 -0
  256. package/skills/bioinformatics-workflows/SKILL.md +108 -0
  257. package/skills/bioinformatics-workflows/evals/triggers.json +16 -0
  258. package/skills/bioinformatics-workflows/references/commands.md +71 -0
  259. package/skills/bioinformatics-workflows/references/formats.md +24 -0
  260. package/skills/bioinformatics-workflows/references/workflow-managers.md +107 -0
  261. package/skills/brand-voice/SKILL.md +112 -0
  262. package/skills/brand-voice/evals/triggers.json +16 -0
  263. package/skills/browser-qa/SKILL.md +99 -0
  264. package/skills/browser-qa/evals/triggers.json +16 -0
  265. package/skills/bun-runtime/SKILL.md +93 -0
  266. package/skills/bun-runtime/evals/triggers.json +16 -0
  267. package/skills/cisco-ios-config/SKILL.md +101 -0
  268. package/skills/cisco-ios-config/evals/triggers.json +18 -0
  269. package/skills/cisco-ios-config/references/verification.md +63 -0
  270. package/skills/clickhouse-patterns/SKILL.md +101 -0
  271. package/skills/clickhouse-patterns/evals/triggers.json +18 -0
  272. package/skills/clickhouse-patterns/references/engines-and-views.md +138 -0
  273. package/skills/clinical-decision-support/SKILL.md +90 -0
  274. package/skills/clinical-decision-support/evals/triggers.json +16 -0
  275. package/skills/clinical-decision-support/references/cds-hooks.md +76 -0
  276. package/skills/clinical-decision-support/references/regulatory-boundaries.md +37 -0
  277. package/skills/code-tour/SKILL.md +97 -0
  278. package/skills/code-tour/evals/triggers.json +14 -0
  279. package/skills/codebase-onboarding/SKILL.md +112 -0
  280. package/skills/codebase-onboarding/evals/triggers.json +14 -0
  281. package/skills/cold-outreach-sequences/SKILL.md +90 -0
  282. package/skills/cold-outreach-sequences/evals/triggers.json +16 -0
  283. package/skills/content-repurposing/SKILL.md +82 -0
  284. package/skills/content-repurposing/evals/triggers.json +16 -0
  285. package/skills/context-budget/SKILL.md +84 -0
  286. package/skills/context-budget/evals/triggers.json +14 -0
  287. package/skills/conventional-commits/SKILL.md +144 -0
  288. package/skills/conventional-commits/evals/triggers.json +16 -0
  289. package/skills/cpp-patterns/SKILL.md +129 -0
  290. package/skills/cpp-patterns/evals/triggers.json +16 -0
  291. package/skills/cpp-patterns/references/cmake-and-tooling.md +88 -0
  292. package/skills/cpp-patterns/references/undefined-behaviour.md +75 -0
  293. package/skills/cpp-testing/SKILL.md +131 -0
  294. package/skills/cpp-testing/evals/triggers.json +16 -0
  295. package/skills/csharp-patterns/SKILL.md +110 -0
  296. package/skills/csharp-patterns/evals/triggers.json +17 -0
  297. package/skills/csharp-patterns/references/analyzers.md +59 -0
  298. package/skills/csharp-testing/SKILL.md +85 -0
  299. package/skills/csharp-testing/evals/triggers.json +17 -0
  300. package/skills/csharp-testing/references/integration-tests.md +77 -0
  301. package/skills/css-architecture/SKILL.md +143 -0
  302. package/skills/css-architecture/evals/triggers.json +16 -0
  303. package/skills/customs-trade-compliance/SKILL.md +95 -0
  304. package/skills/customs-trade-compliance/evals/triggers.json +16 -0
  305. package/skills/customs-trade-compliance/references/incoterms-2020.md +42 -0
  306. package/skills/dart-patterns/SKILL.md +157 -0
  307. package/skills/dart-patterns/evals/triggers.json +18 -0
  308. package/skills/dart-testing/SKILL.md +164 -0
  309. package/skills/dart-testing/evals/triggers.json +18 -0
  310. package/skills/data-analysis-notebooks/SKILL.md +113 -0
  311. package/skills/data-analysis-notebooks/evals/triggers.json +16 -0
  312. package/skills/data-analysis-notebooks/references/dataframe-pitfalls.md +49 -0
  313. package/skills/data-analysis-notebooks/references/statistics-pitfalls.md +24 -0
  314. package/skills/data-pipelines/SKILL.md +90 -0
  315. package/skills/data-pipelines/evals/triggers.json +16 -0
  316. package/skills/data-pipelines/references/orchestrators.md +64 -0
  317. package/skills/database-migrations/SKILL.md +102 -0
  318. package/skills/database-migrations/evals/triggers.json +16 -0
  319. package/skills/database-migrations/references/recipes.md +98 -0
  320. package/skills/database-migrations/references/tools.md +21 -0
  321. package/skills/dbt-patterns/SKILL.md +96 -0
  322. package/skills/dbt-patterns/evals/triggers.json +16 -0
  323. package/skills/dbt-patterns/references/yaml-examples.md +114 -0
  324. package/skills/deep-research/SKILL.md +107 -0
  325. package/skills/deep-research/evals/triggers.json +14 -0
  326. package/skills/dependency-audit/SKILL.md +103 -0
  327. package/skills/dependency-audit/evals/triggers.json +16 -0
  328. package/skills/dependency-audit/references/tools.md +124 -0
  329. package/skills/deployment-strategies/SKILL.md +108 -0
  330. package/skills/deployment-strategies/evals/triggers.json +16 -0
  331. package/skills/django-patterns/SKILL.md +123 -0
  332. package/skills/django-patterns/evals/triggers.json +16 -0
  333. package/skills/docker-patterns/SKILL.md +132 -0
  334. package/skills/docker-patterns/evals/triggers.json +16 -0
  335. package/skills/docker-patterns/references/dockerfiles.md +105 -0
  336. package/skills/e2e-testing-playwright/SKILL.md +94 -0
  337. package/skills/e2e-testing-playwright/evals/triggers.json +16 -0
  338. package/skills/e2e-testing-playwright/references/config-and-ci.md +129 -0
  339. package/skills/ef-core-patterns/SKILL.md +117 -0
  340. package/skills/ef-core-patterns/evals/triggers.json +16 -0
  341. package/skills/email-deliverability/SKILL.md +99 -0
  342. package/skills/email-deliverability/evals/triggers.json +17 -0
  343. package/skills/email-deliverability/references/dns-records.md +85 -0
  344. package/skills/error-handling-patterns/SKILL.md +112 -0
  345. package/skills/error-handling-patterns/evals/triggers.json +18 -0
  346. package/skills/error-handling-patterns/references/language-idioms.md +49 -0
  347. package/skills/estimation-and-scoping/SKILL.md +97 -0
  348. package/skills/estimation-and-scoping/evals/triggers.json +14 -0
  349. package/skills/evm-dapp-integration/SKILL.md +73 -0
  350. package/skills/evm-dapp-integration/evals/triggers.json +16 -0
  351. package/skills/fastapi-patterns/SKILL.md +127 -0
  352. package/skills/fastapi-patterns/evals/triggers.json +16 -0
  353. package/skills/ffmpeg-media-processing/SKILL.md +94 -0
  354. package/skills/ffmpeg-media-processing/evals/triggers.json +16 -0
  355. package/skills/ffmpeg-media-processing/references/recipes.md +112 -0
  356. package/skills/fhir-integration/SKILL.md +81 -0
  357. package/skills/fhir-integration/evals/triggers.json +16 -0
  358. package/skills/fhir-integration/references/search-and-bundles.md +73 -0
  359. package/skills/fhir-integration/references/smart-on-fhir.md +50 -0
  360. package/skills/flask-patterns/SKILL.md +132 -0
  361. package/skills/flask-patterns/evals/triggers.json +16 -0
  362. package/skills/flutter-patterns/SKILL.md +99 -0
  363. package/skills/flutter-patterns/evals/triggers.json +16 -0
  364. package/skills/flutterwave-integration/SKILL.md +75 -0
  365. package/skills/flutterwave-integration/evals/triggers.json +16 -0
  366. package/skills/flutterwave-integration/references/api.md +73 -0
  367. package/skills/flutterwave-integration/references/webhooks.md +49 -0
  368. package/skills/fsharp-patterns/SKILL.md +133 -0
  369. package/skills/fsharp-patterns/evals/triggers.json +16 -0
  370. package/skills/fsharp-testing/SKILL.md +136 -0
  371. package/skills/fsharp-testing/evals/triggers.json +16 -0
  372. package/skills/gcp-patterns/SKILL.md +86 -0
  373. package/skills/gcp-patterns/evals/triggers.json +16 -0
  374. package/skills/git-workflow/SKILL.md +114 -0
  375. package/skills/git-workflow/evals/triggers.json +16 -0
  376. package/skills/github-actions-ci/SKILL.md +117 -0
  377. package/skills/github-actions-ci/evals/triggers.json +16 -0
  378. package/skills/github-api-automation/SKILL.md +101 -0
  379. package/skills/github-api-automation/evals/triggers.json +17 -0
  380. package/skills/go-patterns/SKILL.md +118 -0
  381. package/skills/go-patterns/evals/triggers.json +17 -0
  382. package/skills/go-patterns/references/concurrency.md +162 -0
  383. package/skills/go-testing/SKILL.md +154 -0
  384. package/skills/go-testing/evals/triggers.json +17 -0
  385. package/skills/hexagonal-architecture/SKILL.md +89 -0
  386. package/skills/hexagonal-architecture/evals/triggers.json +17 -0
  387. package/skills/hipaa-compliance/SKILL.md +91 -0
  388. package/skills/hipaa-compliance/evals/triggers.json +18 -0
  389. package/skills/hipaa-compliance/references/safeguards.md +68 -0
  390. package/skills/hl7v2-integration/SKILL.md +69 -0
  391. package/skills/hl7v2-integration/evals/triggers.json +16 -0
  392. package/skills/hl7v2-integration/references/messages-and-ack.md +78 -0
  393. package/skills/homelab-network-setup/SKILL.md +125 -0
  394. package/skills/homelab-network-setup/evals/triggers.json +18 -0
  395. package/skills/homelab-network-setup/references/firewall-and-dns.md +45 -0
  396. package/skills/homelab-network-setup/references/wireguard.md +72 -0
  397. package/skills/hubtel-integration/SKILL.md +77 -0
  398. package/skills/hubtel-integration/evals/triggers.json +16 -0
  399. package/skills/hubtel-integration/references/api.md +92 -0
  400. package/skills/i18n-localization/SKILL.md +114 -0
  401. package/skills/i18n-localization/evals/triggers.json +16 -0
  402. package/skills/i18n-localization/references/libraries.md +52 -0
  403. package/skills/incident-postmortem/SKILL.md +118 -0
  404. package/skills/incident-postmortem/evals/triggers.json +14 -0
  405. package/skills/inventory-demand-planning/SKILL.md +89 -0
  406. package/skills/inventory-demand-planning/evals/triggers.json +16 -0
  407. package/skills/inventory-demand-planning/references/formulas.md +62 -0
  408. package/skills/investor-materials/SKILL.md +127 -0
  409. package/skills/investor-materials/evals/triggers.json +16 -0
  410. package/skills/investor-materials/references/templates.md +74 -0
  411. package/skills/invoicing-and-tax/SKILL.md +84 -0
  412. package/skills/invoicing-and-tax/evals/triggers.json +17 -0
  413. package/skills/invoicing-and-tax/references/e-invoicing.md +24 -0
  414. package/skills/invoicing-and-tax/references/invoice-fields.md +38 -0
  415. package/skills/invoicing-and-tax/references/rounding.md +26 -0
  416. package/skills/java-patterns/SKILL.md +141 -0
  417. package/skills/java-patterns/evals/triggers.json +17 -0
  418. package/skills/java-testing/SKILL.md +142 -0
  419. package/skills/java-testing/evals/triggers.json +16 -0
  420. package/skills/jetpack-compose-patterns/SKILL.md +88 -0
  421. package/skills/jetpack-compose-patterns/evals/triggers.json +16 -0
  422. package/skills/jira-integration/SKILL.md +92 -0
  423. package/skills/jira-integration/evals/triggers.json +17 -0
  424. package/skills/jpa-hibernate/SKILL.md +92 -0
  425. package/skills/jpa-hibernate/evals/triggers.json +18 -0
  426. package/skills/jpa-hibernate/references/mapping.md +99 -0
  427. package/skills/kotlin-multiplatform/SKILL.md +97 -0
  428. package/skills/kotlin-multiplatform/evals/triggers.json +16 -0
  429. package/skills/kotlin-patterns/SKILL.md +128 -0
  430. package/skills/kotlin-patterns/evals/triggers.json +16 -0
  431. package/skills/kotlin-testing/SKILL.md +117 -0
  432. package/skills/kotlin-testing/evals/triggers.json +16 -0
  433. package/skills/ktor-patterns/SKILL.md +135 -0
  434. package/skills/ktor-patterns/evals/triggers.json +18 -0
  435. package/skills/kubernetes-patterns/SKILL.md +106 -0
  436. package/skills/kubernetes-patterns/evals/triggers.json +16 -0
  437. package/skills/kubernetes-patterns/references/manifests.md +115 -0
  438. package/skills/laravel-patterns/SKILL.md +136 -0
  439. package/skills/laravel-patterns/evals/triggers.json +16 -0
  440. package/skills/linear-integration/SKILL.md +98 -0
  441. package/skills/linear-integration/evals/triggers.json +17 -0
  442. package/skills/literature-review/SKILL.md +109 -0
  443. package/skills/literature-review/evals/triggers.json +16 -0
  444. package/skills/literature-review/references/appraisal.md +41 -0
  445. package/skills/literature-review/references/search-sources.md +39 -0
  446. package/skills/llm-app-patterns/SKILL.md +97 -0
  447. package/skills/llm-app-patterns/evals/triggers.json +17 -0
  448. package/skills/llm-evals/SKILL.md +98 -0
  449. package/skills/llm-evals/evals/triggers.json +16 -0
  450. package/skills/llm-evals/references/graders.md +66 -0
  451. package/skills/logistics-exception-management/SKILL.md +90 -0
  452. package/skills/logistics-exception-management/evals/triggers.json +16 -0
  453. package/skills/manim-animations/SKILL.md +106 -0
  454. package/skills/manim-animations/evals/triggers.json +16 -0
  455. package/skills/market-research/SKILL.md +117 -0
  456. package/skills/market-research/evals/triggers.json +16 -0
  457. package/skills/marketing-campaign/SKILL.md +111 -0
  458. package/skills/marketing-campaign/evals/triggers.json +16 -0
  459. package/skills/mcp-server-patterns/SKILL.md +127 -0
  460. package/skills/mcp-server-patterns/evals/triggers.json +18 -0
  461. package/skills/mcp-server-patterns/references/protocol-notes.md +68 -0
  462. package/skills/metrics-dashboards/SKILL.md +113 -0
  463. package/skills/metrics-dashboards/evals/triggers.json +16 -0
  464. package/skills/ml-experiment-workflow/SKILL.md +125 -0
  465. package/skills/ml-experiment-workflow/evals/triggers.json +16 -0
  466. package/skills/mongodb-patterns/SKILL.md +115 -0
  467. package/skills/mongodb-patterns/evals/triggers.json +18 -0
  468. package/skills/mongodb-patterns/references/indexes-and-aggregation.md +94 -0
  469. package/skills/mpesa-daraja-integration/SKILL.md +70 -0
  470. package/skills/mpesa-daraja-integration/evals/triggers.json +16 -0
  471. package/skills/mpesa-daraja-integration/references/api.md +103 -0
  472. package/skills/mpesa-daraja-integration/references/callbacks.md +74 -0
  473. package/skills/mtn-momo-integration/SKILL.md +66 -0
  474. package/skills/mtn-momo-integration/evals/triggers.json +16 -0
  475. package/skills/mtn-momo-integration/references/api.md +153 -0
  476. package/skills/mtn-momo-integration/references/callbacks.md +92 -0
  477. package/skills/mtn-momo-integration/references/sandbox-and-go-live.md +51 -0
  478. package/skills/mtn-momo-integration/scripts/sandbox-setup.js +79 -0
  479. package/skills/mysql-patterns/SKILL.md +96 -0
  480. package/skills/mysql-patterns/evals/triggers.json +16 -0
  481. package/skills/mysql-patterns/references/explain.md +34 -0
  482. package/skills/mysql-patterns/references/online-ddl.md +41 -0
  483. package/skills/nestjs-patterns/SKILL.md +114 -0
  484. package/skills/nestjs-patterns/evals/triggers.json +16 -0
  485. package/skills/nestjs-patterns/references/testing.md +68 -0
  486. package/skills/network-automation/SKILL.md +107 -0
  487. package/skills/network-automation/evals/triggers.json +18 -0
  488. package/skills/network-automation/references/tool-snippets.md +153 -0
  489. package/skills/network-troubleshooting/SKILL.md +152 -0
  490. package/skills/network-troubleshooting/evals/triggers.json +18 -0
  491. package/skills/network-troubleshooting/references/commands.md +33 -0
  492. package/skills/nextjs-patterns/SKILL.md +150 -0
  493. package/skills/nextjs-patterns/evals/triggers.json +18 -0
  494. package/skills/nextjs-patterns/references/caching.md +87 -0
  495. package/skills/node-backend-patterns/SKILL.md +103 -0
  496. package/skills/node-backend-patterns/evals/triggers.json +16 -0
  497. package/skills/node-backend-patterns/references/templates.md +122 -0
  498. package/skills/nuxt-patterns/SKILL.md +103 -0
  499. package/skills/nuxt-patterns/evals/triggers.json +16 -0
  500. package/skills/parallel-agent-orchestration/SKILL.md +106 -0
  501. package/skills/parallel-agent-orchestration/evals/triggers.json +14 -0
  502. package/skills/paystack-integration/SKILL.md +59 -0
  503. package/skills/paystack-integration/evals/triggers.json +14 -0
  504. package/skills/paystack-integration/references/api.md +73 -0
  505. package/skills/paystack-integration/references/mobile-money.md +50 -0
  506. package/skills/paystack-integration/references/webhooks.md +80 -0
  507. package/skills/pci-dss-scope/SKILL.md +103 -0
  508. package/skills/pci-dss-scope/evals/triggers.json +18 -0
  509. package/skills/pci-dss-scope/references/saq-and-data.md +36 -0
  510. package/skills/perl-patterns/SKILL.md +135 -0
  511. package/skills/perl-patterns/evals/triggers.json +18 -0
  512. package/skills/perl-testing/SKILL.md +126 -0
  513. package/skills/perl-testing/evals/triggers.json +17 -0
  514. package/skills/php-patterns/SKILL.md +116 -0
  515. package/skills/php-patterns/evals/triggers.json +16 -0
  516. package/skills/php-testing/SKILL.md +123 -0
  517. package/skills/php-testing/evals/triggers.json +16 -0
  518. package/skills/postgres-patterns/SKILL.md +103 -0
  519. package/skills/postgres-patterns/evals/triggers.json +17 -0
  520. package/skills/postgres-patterns/references/explain.md +59 -0
  521. package/skills/postgres-patterns/references/locks.md +53 -0
  522. package/skills/prd-writing/SKILL.md +124 -0
  523. package/skills/prd-writing/evals/triggers.json +15 -0
  524. package/skills/prisma-patterns/SKILL.md +83 -0
  525. package/skills/prisma-patterns/evals/triggers.json +18 -0
  526. package/skills/prisma-patterns/references/prisma-8.md +46 -0
  527. package/skills/prisma-patterns/references/workflow.md +50 -0
  528. package/skills/privacy-compliance/SKILL.md +121 -0
  529. package/skills/privacy-compliance/evals/triggers.json +18 -0
  530. package/skills/privacy-compliance/references/jurisdictions.md +51 -0
  531. package/skills/production-scheduling/SKILL.md +98 -0
  532. package/skills/production-scheduling/evals/triggers.json +16 -0
  533. package/skills/prompt-engineering/SKILL.md +92 -0
  534. package/skills/prompt-engineering/evals/triggers.json +16 -0
  535. package/skills/python-patterns/SKILL.md +107 -0
  536. package/skills/python-patterns/evals/triggers.json +16 -0
  537. package/skills/python-patterns/references/tooling.md +101 -0
  538. package/skills/python-testing/SKILL.md +126 -0
  539. package/skills/python-testing/evals/triggers.json +16 -0
  540. package/skills/python-testing/references/mocking.md +71 -0
  541. package/skills/pytorch-patterns/SKILL.md +139 -0
  542. package/skills/pytorch-patterns/evals/triggers.json +16 -0
  543. package/skills/pytorch-patterns/references/debugging.md +39 -0
  544. package/skills/quarkus-patterns/SKILL.md +93 -0
  545. package/skills/quarkus-patterns/evals/triggers.json +18 -0
  546. package/skills/rag-pipeline-patterns/SKILL.md +117 -0
  547. package/skills/rag-pipeline-patterns/evals/triggers.json +18 -0
  548. package/skills/rag-pipeline-patterns/references/evaluation.md +37 -0
  549. package/skills/rag-pipeline-patterns/references/retrieval-recipes.md +78 -0
  550. package/skills/rails-patterns/SKILL.md +132 -0
  551. package/skills/rails-patterns/evals/triggers.json +16 -0
  552. package/skills/react-native-patterns/SKILL.md +101 -0
  553. package/skills/react-native-patterns/evals/triggers.json +16 -0
  554. package/skills/react-patterns/SKILL.md +140 -0
  555. package/skills/react-patterns/evals/triggers.json +18 -0
  556. package/skills/react-performance/SKILL.md +107 -0
  557. package/skills/react-performance/evals/triggers.json +18 -0
  558. package/skills/redis-patterns/SKILL.md +109 -0
  559. package/skills/redis-patterns/evals/triggers.json +18 -0
  560. package/skills/redis-patterns/references/operations.md +61 -0
  561. package/skills/refactoring-safely/SKILL.md +107 -0
  562. package/skills/refactoring-safely/evals/triggers.json +17 -0
  563. package/skills/release-management/SKILL.md +141 -0
  564. package/skills/release-management/evals/triggers.json +16 -0
  565. package/skills/remotion-video/SKILL.md +91 -0
  566. package/skills/remotion-video/evals/triggers.json +16 -0
  567. package/skills/remotion-video/references/lambda.md +66 -0
  568. package/skills/returns-reverse-logistics/SKILL.md +97 -0
  569. package/skills/returns-reverse-logistics/evals/triggers.json +16 -0
  570. package/skills/ruby-patterns/SKILL.md +127 -0
  571. package/skills/ruby-patterns/evals/triggers.json +18 -0
  572. package/skills/ruby-testing/SKILL.md +113 -0
  573. package/skills/ruby-testing/evals/triggers.json +18 -0
  574. package/skills/runbook-writing/SKILL.md +101 -0
  575. package/skills/runbook-writing/evals/triggers.json +14 -0
  576. package/skills/rust-patterns/SKILL.md +118 -0
  577. package/skills/rust-patterns/evals/triggers.json +16 -0
  578. package/skills/rust-patterns/references/cargo-and-clippy.md +105 -0
  579. package/skills/rust-patterns/references/errors-and-traits.md +97 -0
  580. package/skills/rust-testing/SKILL.md +148 -0
  581. package/skills/rust-testing/evals/triggers.json +16 -0
  582. package/skills/rust-testing/references/fakes-proptest-async.md +113 -0
  583. package/skills/search-first/SKILL.md +73 -0
  584. package/skills/search-first/evals/triggers.json +14 -0
  585. package/skills/security-review/SKILL.md +58 -0
  586. package/skills/security-review/evals/triggers.json +14 -0
  587. package/skills/security-review/references/checklist.md +54 -0
  588. package/skills/security-review/scripts/scan-secrets.js +79 -0
  589. package/skills/seo-audit/SKILL.md +111 -0
  590. package/skills/seo-audit/evals/triggers.json +16 -0
  591. package/skills/seo-audit/references/checks.md +65 -0
  592. package/skills/session-handoff/SKILL.md +101 -0
  593. package/skills/session-handoff/evals/triggers.json +14 -0
  594. package/skills/skill-authoring/SKILL.md +87 -0
  595. package/skills/skill-authoring/evals/triggers.json +14 -0
  596. package/skills/skill-authoring/references/frontmatter.md +40 -0
  597. package/skills/slack-app-integration/SKILL.md +108 -0
  598. package/skills/slack-app-integration/evals/triggers.json +17 -0
  599. package/skills/smart-contract-security/SKILL.md +110 -0
  600. package/skills/smart-contract-security/evals/triggers.json +16 -0
  601. package/skills/smart-contract-security/references/vulnerability-checklist.md +79 -0
  602. package/skills/social-media-publishing/SKILL.md +84 -0
  603. package/skills/social-media-publishing/evals/triggers.json +17 -0
  604. package/skills/social-media-publishing/references/platform-apis.md +116 -0
  605. package/skills/solidity-patterns/SKILL.md +95 -0
  606. package/skills/solidity-patterns/evals/triggers.json +16 -0
  607. package/skills/spring-boot-patterns/SKILL.md +128 -0
  608. package/skills/spring-boot-patterns/evals/triggers.json +18 -0
  609. package/skills/spring-boot-patterns/references/testing.md +72 -0
  610. package/skills/stripe-integration/SKILL.md +69 -0
  611. package/skills/stripe-integration/evals/triggers.json +16 -0
  612. package/skills/stripe-integration/references/api.md +71 -0
  613. package/skills/stripe-integration/references/billing.md +58 -0
  614. package/skills/stripe-integration/references/webhooks.md +76 -0
  615. package/skills/subscription-billing-ops/SKILL.md +118 -0
  616. package/skills/subscription-billing-ops/evals/triggers.json +17 -0
  617. package/skills/subscription-billing-ops/references/proration.md +47 -0
  618. package/skills/subscription-billing-ops/references/revenue-metrics.md +38 -0
  619. package/skills/svelte-patterns/SKILL.md +122 -0
  620. package/skills/svelte-patterns/evals/triggers.json +16 -0
  621. package/skills/swift-patterns/SKILL.md +113 -0
  622. package/skills/swift-patterns/evals/triggers.json +16 -0
  623. package/skills/swift-patterns/references/concurrency-migration.md +40 -0
  624. package/skills/swift-testing/SKILL.md +121 -0
  625. package/skills/swift-testing/evals/triggers.json +16 -0
  626. package/skills/swift-testing/references/swift-testing-cheatsheet.md +81 -0
  627. package/skills/swiftui-patterns/SKILL.md +102 -0
  628. package/skills/swiftui-patterns/evals/triggers.json +16 -0
  629. package/skills/tdd-workflow/SKILL.md +67 -0
  630. package/skills/tdd-workflow/evals/triggers.json +14 -0
  631. package/skills/technical-writing/SKILL.md +95 -0
  632. package/skills/technical-writing/evals/triggers.json +14 -0
  633. package/skills/terraform-patterns/SKILL.md +122 -0
  634. package/skills/terraform-patterns/evals/triggers.json +16 -0
  635. package/skills/terraform-patterns/references/backends.md +67 -0
  636. package/skills/test-coverage-improvement/SKILL.md +107 -0
  637. package/skills/test-coverage-improvement/evals/triggers.json +16 -0
  638. package/skills/threat-modeling/SKILL.md +113 -0
  639. package/skills/threat-modeling/evals/triggers.json +16 -0
  640. package/skills/typescript-patterns/SKILL.md +122 -0
  641. package/skills/typescript-patterns/evals/triggers.json +16 -0
  642. package/skills/typescript-testing/SKILL.md +101 -0
  643. package/skills/typescript-testing/evals/triggers.json +16 -0
  644. package/skills/verification-loop/SKILL.md +70 -0
  645. package/skills/verification-loop/evals/triggers.json +14 -0
  646. package/skills/verification-loop/scripts/detect-checks.js +102 -0
  647. package/skills/vite-patterns/SKILL.md +117 -0
  648. package/skills/vite-patterns/evals/triggers.json +16 -0
  649. package/skills/vue-patterns/SKILL.md +104 -0
  650. package/skills/vue-patterns/evals/triggers.json +16 -0
  651. package/skills/web-accessibility/SKILL.md +119 -0
  652. package/skills/web-accessibility/evals/triggers.json +16 -0
  653. package/skills/web-performance/SKILL.md +107 -0
  654. package/skills/web-performance/evals/triggers.json +16 -0
  655. package/skills/web-scraping/SKILL.md +80 -0
  656. package/skills/web-scraping/evals/triggers.json +16 -0
@@ -0,0 +1,683 @@
1
+ #!/usr/bin/env node
2
+ 'use strict';
3
+
4
+ // kete-loom: install Kete Loom skills, agents and commands into any Agent Skills host.
5
+ // Zero dependencies; Node 18+.
6
+
7
+ const fs = require('fs');
8
+ const os = require('os');
9
+ const path = require('path');
10
+ const { execFileSync } = require('child_process');
11
+ const { SKILLS_DIR, HOOKS_DIR, listSkills, listAgents, listCommands, listHooks, listRules, loadSkill, loadAgent, loadCommand, loadHook, loadRule } = require('../scripts/lib/skills');
12
+ const { lintItem } = require('../scripts/lib/lint');
13
+ const { audit } = require('../scripts/lib/audit');
14
+ const { TARGETS, KINDS, HOST_READS, resolveTarget, detected } = require('../scripts/lib/targets');
15
+ const { MARKER_RE, render } = require('../scripts/lib/render');
16
+ const Hooks = require('../scripts/lib/hooks-install');
17
+ const { loadProfiles, resolveProfiles } = require('../scripts/lib/profiles');
18
+ const Rules = require('../scripts/lib/rules-install');
19
+ const Mcp = require('../scripts/lib/mcp-install');
20
+ const { inventory, compare } = require('../scripts/lib/inventory');
21
+
22
+ const MARKER = '.kete-loom.json';
23
+ const pkg = require('../package.json');
24
+
25
+ const csv = (s) => s.split(',').map((x) => x.trim()).filter(Boolean);
26
+
27
+ function parseArgs(argv) {
28
+ const opts = { _: [], scope: 'user', dryRun: false, force: false, link: false };
29
+ for (let i = 0; i < argv.length; i++) {
30
+ const a = argv[i];
31
+ const next = () => {
32
+ if (i + 1 >= argv.length) throw new Error(`${a} needs a value`);
33
+ return argv[++i];
34
+ };
35
+ if (a === '--target' || a === '-t') opts.targets = csv(next());
36
+ else if (a === '--all-targets') opts.targets = Object.keys(TARGETS);
37
+ else if (a === '--skill' || a === '-s') opts.skills = csv(next());
38
+ else if (a === '--agent' || a === '-a') opts.agents = csv(next());
39
+ else if (a === '--command') opts.commands = csv(next());
40
+ else if (a === '--hook') opts.hookNames = csv(next());
41
+ else if (a === '--rule' || a === '-r') opts.rules = csv(next());
42
+ else if (a === '--mcp') opts.mcp = csv(next());
43
+ else if (a === '--hooks') opts.withHooks = true;
44
+ else if (a === '--profile' || a === '-P') opts.profiles = csv(next());
45
+ else if (a === '--category' || a === '-c') opts.categories = csv(next());
46
+ else if (a === '--scope') opts.scope = next();
47
+ else if (a === '--project' || a === '-p') opts.scope = 'project';
48
+ else if (a === '--dir') opts.dir = path.resolve(next());
49
+ else if (a === '--home') opts.home = path.resolve(next());
50
+ else if (a === '--source') opts.source = path.resolve(next());
51
+ else if (a === '--dry-run' || a === '-n') opts.dryRun = true;
52
+ else if (a === '--force' || a === '-f') opts.force = true;
53
+ else if (a === '--link') opts.link = true;
54
+ else if (a === '--json') opts.json = true;
55
+ else if (a === '--help' || a === '-h') opts._.unshift('help');
56
+ else if (a === '--version' || a === '-v') opts._.unshift('version');
57
+ else if (a.startsWith('-')) throw new Error(`unknown option ${a}`);
58
+ else opts._.push(a);
59
+ }
60
+ if (!['user', 'project'].includes(opts.scope)) throw new Error('--scope must be user or project');
61
+ if (opts.targets) for (const t of opts.targets) if (!TARGETS[t]) throw new Error(`unknown target "${t}". Known: ${Object.keys(TARGETS).join(', ')}`);
62
+ return opts;
63
+ }
64
+
65
+ function help() {
66
+ console.log(`kete-loom ${pkg.version} — install Kete Loom skills, agents and commands into any Agent Skills host
67
+
68
+ Usage
69
+ kete-loom install [options] Copy skills, agents and commands into host folders (hooks with --hooks)
70
+ kete-loom update [options] Refresh exactly what kete-loom installed, in the hosts it's in
71
+ kete-loom outdated [--json] Installed items that are older than this version of Kete Loom
72
+ kete-loom audit [--json] Score this project's readiness for coding agents, with fixes
73
+ kete-loom check <path> Lint your own skills, agents, commands, rules or hooks against the spec
74
+ kete-loom uninstall [options] Remove items that kete-loom installed
75
+ kete-loom list [--json] List available skills, agents, commands and hooks
76
+ kete-loom profiles [--json] List install profiles
77
+ kete-loom doctor [options] Show what is installed where, and which hosts can see it
78
+
79
+ Options
80
+ -t, --target <a,b> Targets: ${Object.keys(TARGETS).join(', ')}
81
+ Default: agents,claude (skills for every host; agents and
82
+ commands for Claude Code, Cursor and VS Code Copilot), plus
83
+ agents and commands for Codex, OpenCode, Gemini CLI and
84
+ Kete Code when they are installed
85
+ --all-targets Install into every host-specific folder as well
86
+ -p, --project Install into the current repo instead of your home folder
87
+ --scope <s> user (default) or project
88
+ --dir <path> Install skills into a custom skills folder (any other agent)
89
+ -s, --skill <a,b> Only these skills
90
+ -a, --agent <a,b> Only these agents
91
+ --command <a,b> Only these commands
92
+ -r, --rule <a,b> Only these rules
93
+ --hook <a,b> Only these hooks
94
+ (--skill, --agent, --command, --rule and --hook combine; with none,
95
+ all skills, agents, commands and rules are installed)
96
+ --mcp <a,b> Also register these MCP servers (see "kete-loom list"). Remote
97
+ servers sign in with OAuth; none need a token in a config file.
98
+ --hooks Also install every hook. Hooks run before each shell command and are
99
+ registered in each host's config, including Claude Code's and Gemini
100
+ CLI's settings.json (backed up first). User scope only.
101
+ -P, --profile <a,b> Install a preset: minimal, core, developer, security, ai, data,
102
+ business, full (see "kete-loom profiles"). core and the profiles
103
+ built on it add the language and framework packs this project uses.
104
+ Combines with --skill, --agent, --command and --hook.
105
+ -c, --category <a,b> Only these categories
106
+ --link Symlink skills instead of copying (for skill authors)
107
+ -f, --force Overwrite items with the same name not installed by kete-loom
108
+ -n, --dry-run Show what would happen without changing anything
109
+
110
+ Examples
111
+ npx @ketecode/loom install
112
+ npx @ketecode/loom install --project --skill tdd-workflow,verification-loop
113
+ npx @ketecode/loom install --target claude
114
+ npx @ketecode/loom install --target codex --agent code-reviewer
115
+ npx @ketecode/loom install --dir ~/.my-agent/skills
116
+ npx @ketecode/loom install --hook block-dangerous-commands
117
+ npx @ketecode/loom install --profile developer
118
+ `);
119
+ }
120
+
121
+ function catalog(opts) {
122
+ return { skills: listSkills(opts.source || SKILLS_DIR), agents: listAgents(), commands: listCommands(), rules: listRules(), hooks: listHooks(), mcp: Mcp.listMcp() };
123
+ }
124
+
125
+ // Folds --profile into the explicit --skill/--agent/--command/--hook lists (or "everything" for full).
126
+ function applyProfiles(opts, all) {
127
+ if (!opts.profiles || opts.profileApplied) return;
128
+ const r = resolveProfiles(opts.profiles, { catalog: all, cwd: process.cwd() });
129
+ opts.profileApplied = true;
130
+ opts.detected = r.detected;
131
+ if (r.all) {
132
+ opts.withHooks = true;
133
+ opts.mcp = all.mcp.map((m) => m.dir);
134
+ return;
135
+ }
136
+ if (r.mcp.size) opts.mcp = [...new Set([...(opts.mcp || []), ...r.mcp])];
137
+ const merge = (key, set) => (set.size || opts[key] ? (opts[key] = [...new Set([...(opts[key] || []), ...set])]) : undefined);
138
+ merge('skills', r.skills);
139
+ merge('agents', r.agents);
140
+ merge('commands', r.commands);
141
+ merge('rules', r.rules);
142
+ if (r.hooks.size && opts.scope === 'project') opts.droppedHooks = [...r.hooks];
143
+ else merge('hookNames', r.hooks);
144
+ // A profile names its items, so an empty kind means "none of these", not "all of them".
145
+ for (const k of KINDS) opts[k] ||= [];
146
+ }
147
+
148
+ // Returns { skills, agents, commands, hooks } after the profile and --skill/--agent/--command/--hook/--category filters.
149
+ function selectItems(opts) {
150
+ const all = catalog(opts);
151
+ applyProfiles(opts, all);
152
+ const named = KINDS.some((k) => opts[k]) || Boolean(opts.hookNames) || Boolean(opts.mcp);
153
+ const chosen = {};
154
+ for (const kind of KINDS) {
155
+ let items = all[kind];
156
+ if (named) {
157
+ const want = opts[kind] || [];
158
+ const unknown = want.filter((n) => !items.some((i) => i.dir === n));
159
+ if (unknown.length) throw new Error(`unknown ${kind.slice(0, -1)}(s): ${unknown.join(', ')}. Run "kete-loom list".`);
160
+ items = items.filter((i) => want.includes(i.dir));
161
+ }
162
+ if (opts.categories) items = items.filter((i) => opts.categories.includes(i.category));
163
+ chosen[kind] = items;
164
+ }
165
+ // Hooks are opt-in: only with --hooks or when named with --hook.
166
+ const unknownHooks = (opts.hookNames || []).filter((n) => !all.hooks.some((h) => h.dir === n));
167
+ if (unknownHooks.length) throw new Error(`unknown hook(s): ${unknownHooks.join(', ')}. Run "kete-loom list".`);
168
+ chosen.hooks = opts.hookNames ? all.hooks.filter((h) => opts.hookNames.includes(h.dir)) : opts.withHooks ? all.hooks : [];
169
+ if (opts.categories) chosen.hooks = chosen.hooks.filter((h) => opts.categories.includes(h.category));
170
+ // MCP servers are opt-in too: only with --mcp or a profile that names them.
171
+ const unknownMcp = (opts.mcp || []).filter((n) => !all.mcp.some((m) => m.dir === n));
172
+ if (unknownMcp.length) throw new Error(`unknown MCP server(s): ${unknownMcp.join(', ')}. Run "kete-loom list".`);
173
+ chosen.mcp = all.mcp.filter((m) => (opts.mcp || []).includes(m.dir));
174
+ return chosen;
175
+ }
176
+
177
+ function destinations(opts) {
178
+ if (opts.dir) return [{ target: 'custom', kind: 'skills', dir: opts.dir }];
179
+ const where = { scope: opts.scope, home: opts.home || os.homedir(), cwd: process.cwd() };
180
+ const picks = opts.targets
181
+ ? opts.targets.map((t) => ({ target: t, kinds: KINDS }))
182
+ : Object.keys(TARGETS)
183
+ .filter((t) => TARGETS[t].default || detected(t, where))
184
+ // Detected hosts read skills from .agents already; they only need their own agents, commands and
185
+ // rules (Cursor and Copilot read agents from .claude too, so they only need rules).
186
+ .map((t) => ({ target: t, kinds: TARGETS[t].default ? KINDS : TARGETS[t].auto ? ['agents', 'commands', 'rules'] : ['rules'] }));
187
+ return picks.flatMap(({ target, kinds }) =>
188
+ kinds.map((kind) => ({ target, kind, dir: resolveTarget(target, { ...where, kind }) })).filter((d) => d.dir)
189
+ );
190
+ }
191
+
192
+ // Hosts to register hooks with: the --target list, or Claude Code plus every other hook host found.
193
+ function hookHosts(opts) {
194
+ const where = { scope: 'user', home: opts.home || os.homedir(), cwd: process.cwd() };
195
+ if (opts.targets) return opts.targets.filter((t) => TARGETS[t].hooks);
196
+ return Hooks.HOOK_HOSTS.filter((t) => TARGETS[t].default || detected(t, where));
197
+ }
198
+
199
+ function installHooks(hooks, opts) {
200
+ if (!hooks.length) return [];
201
+ if (opts.scope === 'project') throw new Error('hooks install at user scope only; drop --project, or pass --skill/--agent/--command to choose what to install in the project');
202
+ const home = opts.home || os.homedir();
203
+ Hooks.installRuntime(hooks, { home, dryRun: opts.dryRun, sourceDir: HOOKS_DIR });
204
+ const results = [];
205
+ for (const target of hookHosts(opts)) {
206
+ for (const hook of hooks) results.push({ target, kind: 'hook', name: hook.dir, ...Hooks.register(target, hook.dir, hook.event, { home, dryRun: opts.dryRun }) });
207
+ }
208
+ return results;
209
+ }
210
+
211
+ function uninstallHooks(opts, named) {
212
+ if (named && !opts.hookNames) return [];
213
+ const home = opts.home || os.homedir();
214
+ const names = listHooks().map((h) => h.dir);
215
+ const hosts = opts.targets ? opts.targets.filter((t) => TARGETS[t].hooks) : Hooks.HOOK_HOSTS;
216
+ const results = [];
217
+ for (const target of hosts) {
218
+ for (const hook of opts.hookNames || [null]) {
219
+ for (const r of Hooks.unregister(target, hook, { home, dryRun: opts.dryRun, names })) results.push({ target, kind: 'hook', action: 'removed', ...r });
220
+ }
221
+ }
222
+ // The shared runtime goes once no host is told to call it any more.
223
+ const left = Hooks.HOOK_HOSTS.flatMap((t) => Hooks.registered(t, { home, names }));
224
+ if (!opts.dryRun) {
225
+ for (const hook of opts.hookNames || names) if (!left.includes(hook)) fs.rmSync(path.join(Hooks.runtimeDir(home), hook), { recursive: true, force: true });
226
+ if (!left.length) {
227
+ fs.rmSync(Hooks.runtimeDir(home), { recursive: true, force: true });
228
+ const parent = path.dirname(Hooks.runtimeDir(home));
229
+ if (fs.existsSync(parent) && !fs.readdirSync(parent).length) fs.rmdirSync(parent);
230
+ }
231
+ }
232
+ return results;
233
+ }
234
+
235
+ // Hosts that can't scope rules to paths get them through their instructions file (rules-install.js).
236
+ function linkedRuleHosts(opts) {
237
+ if (opts.dir || opts.scope === 'project') return [];
238
+ const where = { scope: 'user', home: opts.home || os.homedir(), cwd: process.cwd() };
239
+ return Rules.RULE_HOSTS.filter((t) => (opts.targets ? opts.targets.includes(t) : detected(t, where)));
240
+ }
241
+
242
+ // Hosts to register MCP servers with: the --target list, or Claude Code plus every other host found.
243
+ function mcpHosts(opts) {
244
+ const where = { scope: opts.scope, home: opts.home || os.homedir(), cwd: process.cwd() };
245
+ const hosts = opts.targets ? opts.targets.filter((t) => Mcp.MCP_HOSTS.includes(t)) : Mcp.MCP_HOSTS.filter((t) => TARGETS[t].default || detected(t, where));
246
+ // At project scope Copilot reads the .mcp.json written for Claude Code.
247
+ return opts.scope === 'project' ? hosts.filter((t) => t !== 'copilot') : hosts;
248
+ }
249
+
250
+ function readMarker(dir) {
251
+ try {
252
+ return JSON.parse(fs.readFileSync(path.join(dir, MARKER), 'utf8'));
253
+ } catch {
254
+ return null;
255
+ }
256
+ }
257
+
258
+ function isInside(child, parent) {
259
+ const rel = path.relative(parent, child);
260
+ return rel !== '' && !rel.startsWith('..') && !path.isAbsolute(rel);
261
+ }
262
+
263
+ // A symlink is ours when it points into our skills folder or the --source folder it was linked from.
264
+ function isOurs(dir, opts = {}) {
265
+ try {
266
+ if (fs.lstatSync(dir).isSymbolicLink()) {
267
+ const target = path.resolve(path.dirname(dir), fs.readlinkSync(dir));
268
+ return [SKILLS_DIR, opts.source].some((src) => src && isInside(target, path.resolve(src)));
269
+ }
270
+ } catch {
271
+ return false;
272
+ }
273
+ return readMarker(dir) !== null;
274
+ }
275
+
276
+ // Agent and command files are ours when they carry the `# kete-loom name@version` comment.
277
+ function isOursFile(file) {
278
+ try {
279
+ if (!fs.lstatSync(file).isFile()) return false;
280
+ const fd = fs.openSync(file, 'r');
281
+ const buf = Buffer.alloc(512);
282
+ const n = fs.readSync(fd, buf, 0, 512, 0);
283
+ fs.closeSync(fd);
284
+ return MARKER_RE.test(buf.toString('utf8', 0, n));
285
+ } catch {
286
+ return false;
287
+ }
288
+ }
289
+
290
+ function isSymlink(p) {
291
+ try {
292
+ return fs.lstatSync(p).isSymbolicLink();
293
+ } catch {
294
+ return false;
295
+ }
296
+ }
297
+
298
+ function copyDir(src, dest) {
299
+ fs.mkdirSync(dest, { recursive: true });
300
+ for (const entry of fs.readdirSync(src, { withFileTypes: true })) {
301
+ if (entry.name === 'evals') continue; // evals are for this repo's CI, not for hosts
302
+ const s = path.join(src, entry.name);
303
+ const d = path.join(dest, entry.name);
304
+ if (entry.isDirectory()) copyDir(s, d);
305
+ else {
306
+ fs.copyFileSync(s, d);
307
+ if (fs.statSync(s).mode & 0o111) fs.chmodSync(d, 0o755);
308
+ }
309
+ }
310
+ }
311
+
312
+ const NOT_OURS = 'an item with this name exists and was not installed by kete-loom (use --force)';
313
+
314
+ function installSkill(skill, dir, opts) {
315
+ const dest = path.join(dir, skill.dir);
316
+ const exists = fs.existsSync(dest) || isSymlink(dest);
317
+ if (exists && !isOurs(dest, opts) && !opts.force) return { action: 'skipped', reason: NOT_OURS, dest };
318
+ if (!opts.dryRun) {
319
+ if (exists) fs.rmSync(dest, { recursive: true, force: true });
320
+ fs.mkdirSync(dir, { recursive: true });
321
+ if (opts.link) {
322
+ fs.symlinkSync(skill.path, dest, 'dir');
323
+ } else {
324
+ copyDir(skill.path, dest);
325
+ fs.writeFileSync(
326
+ path.join(dest, MARKER),
327
+ JSON.stringify({ source: 'kete-loom', skill: skill.dir, version: skill.version, installer: pkg.version, installedAt: new Date().toISOString() }, null, 2) + '\n'
328
+ );
329
+ }
330
+ }
331
+ return { action: exists ? 'updated' : 'installed', dest };
332
+ }
333
+
334
+ // Agents and commands are rendered per host, so they are always written, never linked.
335
+ function installFile(item, dir, target, opts) {
336
+ const out = render(item, target);
337
+ if (!out) return null;
338
+ const dest = path.join(dir, out.file);
339
+ const exists = fs.existsSync(dest) || isSymlink(dest);
340
+ if (exists && !isOursFile(dest) && !opts.force) return { action: 'skipped', reason: NOT_OURS, dest };
341
+ if (!opts.dryRun) {
342
+ fs.mkdirSync(dir, { recursive: true });
343
+ if (exists) fs.rmSync(dest, { force: true });
344
+ fs.writeFileSync(dest, out.content);
345
+ }
346
+ return { action: exists ? 'updated' : 'installed', dest };
347
+ }
348
+
349
+ function install(opts) {
350
+ const selected = selectItems(opts);
351
+ if (![...KINDS, 'hooks', 'mcp'].some((k) => selected[k].length)) throw new Error('nothing matched your filters');
352
+ const results = [];
353
+ for (const { target, kind, dir } of destinations(opts)) {
354
+ for (const item of selected[kind]) {
355
+ const r = kind === 'skills' ? installSkill(item, dir, opts) : installFile(item, dir, target, opts);
356
+ if (r) results.push({ target, kind: item.kind, name: item.dir, ...r });
357
+ }
358
+ }
359
+ // Hosts that can't scope by path load every rule they get on every turn, so they only get rules that
360
+ // were chosen (--rule or a profile), never the whole library.
361
+ if (selected.rules.length && opts.rules) for (const host of linkedRuleHosts(opts)) results.push(...Rules.installRules(host, selected.rules, { home: opts.home || os.homedir(), dryRun: opts.dryRun }));
362
+ if (selected.mcp.length && !opts.dir) {
363
+ const all = Mcp.listMcp();
364
+ for (const host of mcpHosts(opts)) results.push(...Mcp.installMcp(host, selected.mcp, all, { scope: opts.scope, home: opts.home || os.homedir(), cwd: process.cwd(), dryRun: opts.dryRun }));
365
+ }
366
+ results.push(...installHooks(selected.hooks, opts));
367
+ report(results, opts);
368
+ if (!opts.json && opts.detected && opts.detected.length) console.log(`\nDetected in this project: ${opts.detected.join(', ')}.`);
369
+ if (!opts.json && opts.droppedHooks) console.log(`\nSkipped the profile's hooks (${opts.droppedHooks.join(', ')}): hooks install for your user only. Run the install without --project to add them.`);
370
+ const notes = [...new Set(results.map((r) => r.note).filter(Boolean))];
371
+ if (notes.length && !opts.json) console.log(`\n${notes.join('\n')}`);
372
+ const missing = missingRequirements(KINDS.flatMap((k) => selected[k]));
373
+ if (missing.length && !opts.json) {
374
+ console.log(`\nNote: some items expect tools that are not on your PATH:`);
375
+ for (const m of missing) console.log(` ${m.name}: ${m.tools.join(', ')}`);
376
+ }
377
+ if (!opts.json && !opts.dryRun) console.log('\nRestart your agent (or start a new session) so it picks up the new items.');
378
+ return results;
379
+ }
380
+
381
+ // `code-reviewer.agent.md` -> `code-reviewer`, `python.instructions.md` -> `python`, `python.mdc` -> `python`
382
+ const itemName = (entry) => entry.replace(/(?:\.agent|\.instructions)?\.(?:md|mdc|toml)$/, '');
383
+
384
+ function uninstall(opts) {
385
+ applyProfiles(opts, catalog(opts)); // `uninstall --profile x` removes only that profile's items
386
+ const named = KINDS.some((k) => opts[k]) || Boolean(opts.hookNames);
387
+ const results = [];
388
+ for (const { target, kind, dir } of destinations(opts)) {
389
+ if (named && !opts[kind]) continue;
390
+ if (!fs.existsSync(dir)) continue;
391
+ for (const entry of fs.readdirSync(dir)) {
392
+ const p = path.join(dir, entry);
393
+ const name = kind === 'skills' ? entry : itemName(entry);
394
+ if (named && !opts[kind].includes(name)) continue;
395
+ if (!(kind === 'skills' ? isOurs(p, opts) : isOursFile(p))) continue;
396
+ if (!opts.dryRun) fs.rmSync(p, { recursive: true, force: true });
397
+ results.push({ target, kind: kind.slice(0, -1), name, action: 'removed', dest: p });
398
+ }
399
+ }
400
+ if (!named || opts.rules) for (const host of linkedRuleHosts(opts)) results.push(...Rules.uninstallRules(host, named ? opts.rules : null, { home: opts.home || os.homedir(), dryRun: opts.dryRun }));
401
+ if (!opts.dir && (!named || opts.mcp)) {
402
+ const all = Mcp.listMcp();
403
+ const servers = opts.mcp ? all.filter((m) => opts.mcp.includes(m.dir)) : all;
404
+ const hosts = opts.targets ? opts.targets.filter((t) => Mcp.MCP_HOSTS.includes(t)) : Mcp.MCP_HOSTS;
405
+ for (const host of hosts) results.push(...Mcp.uninstallMcp(host, servers, all, { scope: opts.scope, home: opts.home || os.homedir(), cwd: process.cwd(), dryRun: opts.dryRun }));
406
+ }
407
+ results.push(...uninstallHooks(opts, named));
408
+ report(results, opts);
409
+ return results;
410
+ }
411
+
412
+ function report(results, opts) {
413
+ if (opts.json) return console.log(JSON.stringify(results, null, 2));
414
+ if (!results.length) return console.log('Nothing to do.');
415
+ const prefix = opts.dryRun ? '[dry-run] ' : '';
416
+ for (const r of results) {
417
+ const where = r.dest.replace(os.homedir(), '~');
418
+ console.log(`${prefix}${r.action.padEnd(9)} ${r.kind.padEnd(7)} ${r.name.padEnd(24)} ${where}${r.reason ? ` (${r.reason})` : ''}`);
419
+ }
420
+ }
421
+
422
+ function onPath(tool) {
423
+ try {
424
+ execFileSync(process.platform === 'win32' ? 'where' : 'which', [tool], { stdio: 'ignore' });
425
+ return true;
426
+ } catch {
427
+ return false;
428
+ }
429
+ }
430
+
431
+ function missingRequirements(items) {
432
+ const cache = {};
433
+ return items
434
+ .map((s) => ({ name: s.dir, tools: s.requires.filter((t) => (cache[t] ??= onPath(t)) === false) }))
435
+ .filter((m) => m.tools.length);
436
+ }
437
+
438
+ function list(opts) {
439
+ const selected = selectItems(opts);
440
+ const items = [...KINDS, 'hooks', 'mcp'].flatMap((k) => (k === 'hooks' || k === 'mcp' ? catalog(opts)[k] : selected[k]));
441
+ if (opts.json) {
442
+ return console.log(JSON.stringify(items.map(({ kind, dir, version, category, risk, description }) => ({ kind, name: dir, version, category, risk, description })), null, 2));
443
+ }
444
+ for (const s of items) {
445
+ console.log(`${s.kind.padEnd(8)} ${s.dir.padEnd(24)} v${(s.version || '?').padEnd(7)} ${String(s.category).padEnd(12)} ${s.risk}`);
446
+ }
447
+ const count = (k) => `${selected[k].length} ${k.slice(0, -1)}(s)`;
448
+ console.log(`\n${KINDS.map(count).join(', ')}, ${catalog(opts).hooks.length} hook(s), ${catalog(opts).mcp.length} MCP server(s). Install with: npx @ketecode/loom install (hooks: --hooks, MCP servers: --mcp <names>)`);
449
+ }
450
+
451
+ // Installed items for this scope, with the library's current version beside each.
452
+ function installed(opts) {
453
+ const all = catalog(opts);
454
+ const version = new Map([...KINDS, 'hooks', 'mcp'].flatMap((k) => (all[k] || []).map((i) => [`${k}:${i.dir}`, i.version])));
455
+ const rows = inventory({ scope: opts.scope, home: opts.home || os.homedir(), cwd: process.cwd(), mcpAll: all.mcp, hookNames: all.hooks.map((h) => h.dir) });
456
+ return rows.map((r) => ({ ...r, latest: version.get(`${r.kind}:${r.name}`) || null }));
457
+ }
458
+
459
+ // update: re-apply exactly what is installed, in the hosts it is installed in.
460
+ function update(opts) {
461
+ const rows = installed(opts);
462
+ if (!rows.length) {
463
+ console.log(`Nothing installed by kete-loom at ${opts.scope} scope. Run: npx @ketecode/loom install`);
464
+ return [];
465
+ }
466
+ const gone = [...new Set(rows.filter((r) => !r.latest && r.kind !== 'hooks' && r.kind !== 'mcp').map((r) => `${r.kind.replace(/s$/, '')} ${r.name}`))];
467
+ const pick = (kind) => [...new Set(rows.filter((r) => r.kind === kind && !r.linked && (r.latest || kind === 'hooks' || kind === 'mcp')).map((r) => r.name))];
468
+ const known = (kind, names) => names.filter((n) => catalog(opts)[kind].some((i) => i.dir === n));
469
+ const next = {
470
+ ...opts,
471
+ force: false,
472
+ targets: [...new Set(rows.map((r) => r.target))],
473
+ skills: pick('skills'),
474
+ agents: pick('agents'),
475
+ commands: pick('commands'),
476
+ rules: pick('rules'),
477
+ hookNames: known('hooks', pick('hooks')),
478
+ mcp: known('mcp', pick('mcp')),
479
+ };
480
+ for (const k of ['skills', 'agents', 'commands', 'rules', 'hookNames', 'mcp']) if (!next[k].length) delete next[k];
481
+ const changes = rows.filter((r) => r.version && r.latest && compare(r.version, r.latest) < 0);
482
+ const results = install(next);
483
+ if (!opts.json) {
484
+ const versions = [...new Map(changes.map((r) => [`${r.kind}:${r.name}`, ` ${r.kind.replace(/s$/, '').padEnd(8)} ${r.name.padEnd(28)} ${r.version} -> ${r.latest}`])).values()];
485
+ console.log(versions.length ? `\nNew versions:\n${versions.join('\n')}` : '\nEverything was already at the latest version.');
486
+ const linked = rows.filter((r) => r.linked).map((r) => r.name);
487
+ if (linked.length) console.log(`Linked skills are live already and were left alone: ${[...new Set(linked)].join(', ')}.`);
488
+ if (gone.length) console.log(`No longer in Kete Loom, left in place (remove with uninstall): ${gone.join(', ')}.`);
489
+ }
490
+ return results;
491
+ }
492
+
493
+ function outdated(opts) {
494
+ const rows = installed(opts).filter((r) => r.version && r.latest && compare(r.version, r.latest) < 0);
495
+ if (opts.json) {
496
+ console.log(JSON.stringify(rows.map(({ target, kind, name, version, latest }) => ({ target, kind, name, version, latest })), null, 2));
497
+ return rows.length ? 1 : 0;
498
+ }
499
+ if (!rows.length) {
500
+ console.log('Everything kete-loom installed is up to date.');
501
+ return 0;
502
+ }
503
+ for (const r of rows) console.log(`${r.kind.replace(/s$/, '').padEnd(8)} ${r.name.padEnd(28)} ${r.version.padEnd(8)} -> ${r.latest.padEnd(8)} ${r.target}`);
504
+ console.log('\nRun: npx @ketecode/loom@latest update');
505
+ return 1;
506
+ }
507
+
508
+ // check: lint items you wrote, wherever they live.
509
+ function itemsAt(target) {
510
+ const p = path.resolve(target);
511
+ if (!fs.existsSync(p)) throw new Error(`${target} does not exist`);
512
+ if (fs.statSync(p).isFile()) {
513
+ if (!p.endsWith('.md')) throw new Error(`${target}: expected a .md command or rule, or a folder`);
514
+ return [path.basename(path.dirname(p)) === 'rules' ? loadRule(p) : loadCommand(p)];
515
+ }
516
+ const kinds = [['SKILL.md', loadSkill], ['AGENT.md', loadAgent], ['HOOK.md', loadHook]];
517
+ const own = kinds.find(([f]) => fs.existsSync(path.join(p, f)));
518
+ if (own) return [own[1](p)];
519
+ return fs.readdirSync(p).sort().flatMap((entry) => {
520
+ const child = path.join(p, entry);
521
+ if (fs.statSync(child).isDirectory()) {
522
+ const k = kinds.find(([f]) => fs.existsSync(path.join(child, f)));
523
+ return k ? [k[1](child)] : [];
524
+ }
525
+ return entry.endsWith('.md') && !/^(README|CHANGELOG|AGENTS|CLAUDE)\.md$/i.test(entry) ? [path.basename(p) === 'rules' ? loadRule(child) : loadCommand(child)] : [];
526
+ });
527
+ }
528
+
529
+ function check(opts) {
530
+ const target = opts._[1];
531
+ if (!target) throw new Error('usage: kete-loom check <path to a skill, agent, hook, command or rule, or a folder of them>');
532
+ const items = itemsAt(target);
533
+ if (!items.length) throw new Error(`no skills, agents, commands, rules or hooks found in ${target}`);
534
+ let errors = 0;
535
+ const out = items.map((item) => {
536
+ const r = lintItem(item);
537
+ errors += r.errors.length;
538
+ return { kind: item.kind, name: item.dir, path: item.path, ...r };
539
+ });
540
+ if (opts.json) console.log(JSON.stringify(out, null, 2));
541
+ else {
542
+ for (const r of out) {
543
+ if (!r.errors.length && !r.warnings.length) console.log(`✓ ${r.kind.padEnd(7)} ${r.name}`);
544
+ for (const e of r.errors) console.log(`✗ ${r.kind.padEnd(7)} ${r.name} ${e}`);
545
+ for (const w of r.warnings) console.log(`! ${r.kind.padEnd(7)} ${r.name} ${w}`);
546
+ }
547
+ console.log(`\n${out.length} item(s), ${errors} error(s). The rules are in docs/SKILL_SPEC.md of the Kete Loom repository.`);
548
+ }
549
+ return errors ? 1 : 0;
550
+ }
551
+
552
+ function auditCmd(opts) {
553
+ const all = catalog(opts);
554
+ const r = audit({ cwd: process.cwd(), home: opts.home || os.homedir(), catalog: all });
555
+ if (opts.json) console.log(JSON.stringify(r, null, 2));
556
+ else {
557
+ console.log(`Agent readiness for ${r.root.replace(os.homedir(), '~')}: ${r.score}/100\n`);
558
+ const mark = { pass: '✓', warn: '!', fail: '✗' };
559
+ for (const c of r.checks) {
560
+ console.log(`${mark[c.status]} ${c.title}: ${c.detail}`);
561
+ if (c.fix) console.log(` fix: ${c.fix}`);
562
+ }
563
+ }
564
+ return r.checks.some((c) => c.status === 'fail') ? 1 : 0;
565
+ }
566
+
567
+ function profiles(opts) {
568
+ const all = loadProfiles();
569
+ const items = catalog(opts);
570
+ const rows = Object.entries(all).map(([name, p]) => {
571
+ const r = resolveProfiles([name], { catalog: items, cwd: process.cwd() });
572
+ const count = r.all ? 'everything' : ['skills', 'agents', 'commands', 'hooks'].map((k) => `${r[k].size} ${k}`).join(', ');
573
+ return { name, description: p.description, count, detects: Boolean(p.detect) || (p.extends || []).some((e) => all[e] && all[e].detect) };
574
+ });
575
+ if (opts.json) return console.log(JSON.stringify(rows, null, 2));
576
+ for (const r of rows) console.log(`${r.name.padEnd(10)} ${r.description}\n${' '.repeat(11)}${r.count} in this folder${r.detects ? ' (includes packs detected here)' : ''}\n`);
577
+ console.log('Install one with: npx @ketecode/loom install --profile <name>');
578
+ }
579
+
580
+ function doctor(opts) {
581
+ const home = opts.home || os.homedir();
582
+ const rows = [];
583
+ for (const scope of ['user', 'project']) {
584
+ for (const target of Object.keys(TARGETS)) {
585
+ for (const kind of KINDS) {
586
+ const dir = resolveTarget(target, { scope, home, cwd: process.cwd(), kind });
587
+ if (!dir) continue;
588
+ const entries = fs.existsSync(dir) ? fs.readdirSync(dir) : [];
589
+ const ours = kind === 'skills'
590
+ ? entries.filter((e) => isOurs(path.join(dir, e), opts))
591
+ : entries.filter((e) => isOursFile(path.join(dir, e))).map(itemName);
592
+ rows.push({ scope, target, kind, dir, items: ours });
593
+ }
594
+ }
595
+ }
596
+ if (opts.json) return console.log(JSON.stringify(rows, null, 2));
597
+ console.log('Installed kete-loom items:\n');
598
+ for (const r of rows.filter((x) => x.items.length)) {
599
+ console.log(` [${r.scope}] ${r.target.padEnd(9)} ${r.kind.padEnd(9)} ${r.dir.replace(os.homedir(), '~')} (${r.items.length})`);
600
+ }
601
+ if (!rows.some((r) => r.items.length)) console.log(' none yet. Run: npx @ketecode/loom install');
602
+ const linked = Rules.RULE_HOSTS.map((t) => ({ target: t, rules: Rules.installedNames(Rules.HOSTS[t].dir(home)) })).filter((r) => r.rules.length);
603
+ if (linked.length) {
604
+ console.log('\nRules loaded through instructions files:');
605
+ for (const r of linked) console.log(` ${r.target.padEnd(9)} ${r.rules.join(', ')}`);
606
+ }
607
+ const hookNames = listHooks().map((h) => h.dir);
608
+ const hookRows = Hooks.HOOK_HOSTS.map((t) => ({ target: t, hooks: Hooks.registered(t, { home, names: hookNames }) })).filter((r) => r.hooks.length);
609
+ if (hookRows.length) {
610
+ console.log('\nHooks:');
611
+ for (const r of hookRows) console.log(` ${r.target.padEnd(9)} ${r.hooks.join(', ')}`);
612
+ if (!fs.existsSync(path.join(Hooks.runtimeDir(home), 'run.js'))) console.log(` ! the hook runtime is missing from ${Hooks.runtimeDir(home)}; run install --hooks again`);
613
+ }
614
+ console.log('\nSkills visible to each host:');
615
+ for (const [host, reads] of Object.entries(HOST_READS)) {
616
+ const seen = new Set(rows.filter((r) => r.kind === 'skills' && reads.includes(r.target)).flatMap((r) => r.items));
617
+ console.log(` ${host.padEnd(15)} ${seen.size} skill(s)`);
618
+ }
619
+ const all = catalog(opts);
620
+ const missing = missingRequirements(KINDS.flatMap((k) => all[k]));
621
+ if (missing.length) {
622
+ console.log('\nMissing tools:');
623
+ for (const m of missing) console.log(` ${m.name}: ${m.tools.join(', ')}`);
624
+ }
625
+ }
626
+
627
+ function main(argv) {
628
+ let opts;
629
+ try {
630
+ opts = parseArgs(argv);
631
+ } catch (e) {
632
+ console.error(`error: ${e.message}\nRun "kete-loom help" for usage.`);
633
+ return 2;
634
+ }
635
+ const cmd = opts._[0] || 'help';
636
+ try {
637
+ switch (cmd) {
638
+ case 'install':
639
+ install(opts);
640
+ break;
641
+ case 'update':
642
+ update(opts);
643
+ break;
644
+ case 'outdated':
645
+ return outdated(opts);
646
+ case 'audit':
647
+ return auditCmd(opts);
648
+ case 'check':
649
+ return check(opts);
650
+ case 'uninstall':
651
+ case 'remove':
652
+ uninstall(opts);
653
+ break;
654
+ case 'list':
655
+ case 'ls':
656
+ list(opts);
657
+ break;
658
+ case 'profiles':
659
+ profiles(opts);
660
+ break;
661
+ case 'doctor':
662
+ doctor(opts);
663
+ break;
664
+ case 'version':
665
+ console.log(pkg.version);
666
+ break;
667
+ case 'help':
668
+ help();
669
+ break;
670
+ default:
671
+ console.error(`unknown command "${cmd}". Run "kete-loom help".`);
672
+ return 2;
673
+ }
674
+ } catch (e) {
675
+ console.error(`error: ${e.message}`);
676
+ return 1;
677
+ }
678
+ return 0;
679
+ }
680
+
681
+ if (require.main === module) process.exitCode = main(process.argv.slice(2));
682
+
683
+ module.exports = { main, parseArgs, install, uninstall, MARKER };