imhcode 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (986) hide show
  1. package/.github/ISSUE_TEMPLATE/bug_report.md +41 -0
  2. package/.github/ISSUE_TEMPLATE/feature_request.md +39 -0
  3. package/.github/PULL_REQUEST_TEMPLATE.md +29 -0
  4. package/.github/copilot-instructions.md +43 -0
  5. package/.github/workflows/framework-validator.yml +53 -0
  6. package/.gitignore.template +15 -0
  7. package/AGENTS.md +69 -0
  8. package/CLAUDE.md +27 -0
  9. package/README.md +63 -0
  10. package/SETUP.md +81 -0
  11. package/USER_MANUAL.md +70 -0
  12. package/agents/android-executor/SYSTEM.md +32 -0
  13. package/agents/android-executor/agent.yml +53 -0
  14. package/agents/debugger/SYSTEM.md +32 -0
  15. package/agents/debugger/agent.yml +56 -0
  16. package/agents/designer/SYSTEM.md +32 -0
  17. package/agents/designer/agent.yml +59 -0
  18. package/agents/devops-executor/SYSTEM.md +32 -0
  19. package/agents/devops-executor/agent.yml +56 -0
  20. package/agents/flutter-executor/SYSTEM.md +32 -0
  21. package/agents/flutter-executor/agent.yml +54 -0
  22. package/agents/ios-executor/SYSTEM.md +32 -0
  23. package/agents/ios-executor/agent.yml +53 -0
  24. package/agents/java-executor/SYSTEM.md +32 -0
  25. package/agents/java-executor/agent.yml +57 -0
  26. package/agents/laravel-executor/SYSTEM.md +32 -0
  27. package/agents/laravel-executor/agent.yml +59 -0
  28. package/agents/nextjs-executor/SYSTEM.md +32 -0
  29. package/agents/nextjs-executor/agent.yml +60 -0
  30. package/agents/planner/SYSTEM.md +32 -0
  31. package/agents/planner/agent.yml +56 -0
  32. package/agents/python-executor/SYSTEM.md +32 -0
  33. package/agents/python-executor/agent.yml +58 -0
  34. package/agents/react-executor/SYSTEM.md +32 -0
  35. package/agents/react-executor/agent.yml +58 -0
  36. package/agents/react-native-executor/SYSTEM.md +32 -0
  37. package/agents/react-native-executor/agent.yml +53 -0
  38. package/agents/security-auditor/SYSTEM.md +32 -0
  39. package/agents/security-auditor/agent.yml +56 -0
  40. package/agents/seo-optimizer/SYSTEM.md +32 -0
  41. package/agents/seo-optimizer/agent.yml +54 -0
  42. package/agents/systems-executor/SYSTEM.md +32 -0
  43. package/agents/systems-executor/agent.yml +54 -0
  44. package/agents/tester/SYSTEM.md +32 -0
  45. package/agents/tester/agent.yml +58 -0
  46. package/agents/vue-executor/SYSTEM.md +32 -0
  47. package/agents/vue-executor/agent.yml +58 -0
  48. package/agents/web3-executor/SYSTEM.md +32 -0
  49. package/agents/web3-executor/agent.yml +55 -0
  50. package/bin/imhcode.js +1634 -0
  51. package/dist/orchestrator/builder.d.ts +23 -0
  52. package/dist/orchestrator/builder.d.ts.map +1 -0
  53. package/dist/orchestrator/builder.js +231 -0
  54. package/dist/orchestrator/builder.js.map +1 -0
  55. package/dist/orchestrator/executor.d.ts +43 -0
  56. package/dist/orchestrator/executor.d.ts.map +1 -0
  57. package/dist/orchestrator/executor.js +356 -0
  58. package/dist/orchestrator/executor.js.map +1 -0
  59. package/dist/orchestrator/index.d.ts +35 -0
  60. package/dist/orchestrator/index.d.ts.map +1 -0
  61. package/dist/orchestrator/index.js +490 -0
  62. package/dist/orchestrator/index.js.map +1 -0
  63. package/dist/orchestrator/loader.d.ts +33 -0
  64. package/dist/orchestrator/loader.d.ts.map +1 -0
  65. package/dist/orchestrator/loader.js +203 -0
  66. package/dist/orchestrator/loader.js.map +1 -0
  67. package/dist/orchestrator/registry.d.ts +63 -0
  68. package/dist/orchestrator/registry.d.ts.map +1 -0
  69. package/dist/orchestrator/registry.js +181 -0
  70. package/dist/orchestrator/registry.js.map +1 -0
  71. package/dist/orchestrator/schema.d.ts +132 -0
  72. package/dist/orchestrator/schema.d.ts.map +1 -0
  73. package/dist/orchestrator/schema.js +101 -0
  74. package/dist/orchestrator/schema.js.map +1 -0
  75. package/dist/orchestrator/session.d.ts +25 -0
  76. package/dist/orchestrator/session.d.ts.map +1 -0
  77. package/dist/orchestrator/session.js +80 -0
  78. package/dist/orchestrator/session.js.map +1 -0
  79. package/dist/orchestrator/types.d.ts +91 -0
  80. package/dist/orchestrator/types.d.ts.map +1 -0
  81. package/dist/orchestrator/types.js +7 -0
  82. package/dist/orchestrator/types.js.map +1 -0
  83. package/package.json +95 -0
  84. package/skills/AnimatePresence/SKILL.md +3 -0
  85. package/skills/accessibility/SKILL.md +146 -0
  86. package/skills/agent-architecture-audit/SKILL.md +256 -0
  87. package/skills/agent-eval/SKILL.md +145 -0
  88. package/skills/agent-introspection-debugging/SKILL.md +153 -0
  89. package/skills/agentic-engineering/SKILL.md +63 -0
  90. package/skills/ai-regression-testing/SKILL.md +385 -0
  91. package/skills/android-clean-architecture/SKILL.md +339 -0
  92. package/skills/animated-component-libraries/SKILL.md +8 -0
  93. package/skills/animejs/SKILL.md +8 -0
  94. package/skills/api-connector-builder/SKILL.md +120 -0
  95. package/skills/api-design/SKILL.md +523 -0
  96. package/skills/apple/SKILL.md +158 -0
  97. package/skills/apple/metadata.json +16 -0
  98. package/skills/architecture-decision-records/SKILL.md +179 -0
  99. package/skills/article-writing/SKILL.md +79 -0
  100. package/skills/automation-audit-ops/SKILL.md +142 -0
  101. package/skills/awwwards/SKILL.md +162 -0
  102. package/skills/awwwards/metadata.json +16 -0
  103. package/skills/babylonjs-engine/SKILL.md +8 -0
  104. package/skills/backend-patterns/SKILL.md +561 -0
  105. package/skills/baqir-docs/SKILL.md +3 -0
  106. package/skills/barba-js/SKILL.md +8 -0
  107. package/skills/benchmark/SKILL.md +93 -0
  108. package/skills/best-practice/SKILL.md +7 -0
  109. package/skills/best-practice/assets/claude-memory/claude-memory-monorepo.jpg +0 -0
  110. package/skills/best-practice/assets/claude-power-ups/dial-the-model-1.png +0 -0
  111. package/skills/best-practice/assets/claude-power-ups/dial-the-model-2.png +0 -0
  112. package/skills/best-practice/assets/claude-power-ups/dial-the-model-3.png +0 -0
  113. package/skills/best-practice/assets/claude-power-ups/powerup-menu.png +0 -0
  114. package/skills/best-practice/claude-cli-startup-flags.md +231 -0
  115. package/skills/best-practice/claude-commands.md +132 -0
  116. package/skills/best-practice/claude-mcp.md +132 -0
  117. package/skills/best-practice/claude-memory.md +121 -0
  118. package/skills/best-practice/claude-power-ups.md +66 -0
  119. package/skills/best-practice/claude-settings.md +1170 -0
  120. package/skills/best-practice/claude-skills.md +58 -0
  121. package/skills/best-practice/claude-subagents.md +56 -0
  122. package/skills/blender-motion-state-inspection/SKILL.md +164 -0
  123. package/skills/bootstrap-patterns/SKILL.md +316 -0
  124. package/skills/brand-guidelines/LICENSE.txt +202 -0
  125. package/skills/brand-guidelines/SKILL.md +73 -0
  126. package/skills/brand-voice/SKILL.md +97 -0
  127. package/skills/brand-voice/references/voice-profile-schema.md +55 -0
  128. package/skills/browser-qa/SKILL.md +87 -0
  129. package/skills/canary-watch/SKILL.md +107 -0
  130. package/skills/canvas-design/LICENSE.txt +202 -0
  131. package/skills/canvas-design/SKILL.md +8 -0
  132. package/skills/canvas-design/canvas-fonts/ArsenalSC-OFL.txt +93 -0
  133. package/skills/canvas-design/canvas-fonts/ArsenalSC-Regular.ttf +0 -0
  134. package/skills/canvas-design/canvas-fonts/BigShoulders-Bold.ttf +0 -0
  135. package/skills/canvas-design/canvas-fonts/BigShoulders-OFL.txt +93 -0
  136. package/skills/canvas-design/canvas-fonts/BigShoulders-Regular.ttf +0 -0
  137. package/skills/canvas-design/canvas-fonts/Boldonse-OFL.txt +93 -0
  138. package/skills/canvas-design/canvas-fonts/Boldonse-Regular.ttf +0 -0
  139. package/skills/canvas-design/canvas-fonts/BricolageGrotesque-Bold.ttf +0 -0
  140. package/skills/canvas-design/canvas-fonts/BricolageGrotesque-OFL.txt +93 -0
  141. package/skills/canvas-design/canvas-fonts/BricolageGrotesque-Regular.ttf +0 -0
  142. package/skills/canvas-design/canvas-fonts/CrimsonPro-Bold.ttf +0 -0
  143. package/skills/canvas-design/canvas-fonts/CrimsonPro-Italic.ttf +0 -0
  144. package/skills/canvas-design/canvas-fonts/CrimsonPro-OFL.txt +93 -0
  145. package/skills/canvas-design/canvas-fonts/CrimsonPro-Regular.ttf +0 -0
  146. package/skills/canvas-design/canvas-fonts/DMMono-OFL.txt +93 -0
  147. package/skills/canvas-design/canvas-fonts/DMMono-Regular.ttf +0 -0
  148. package/skills/canvas-design/canvas-fonts/EricaOne-OFL.txt +94 -0
  149. package/skills/canvas-design/canvas-fonts/EricaOne-Regular.ttf +0 -0
  150. package/skills/canvas-design/canvas-fonts/GeistMono-Bold.ttf +0 -0
  151. package/skills/canvas-design/canvas-fonts/GeistMono-OFL.txt +93 -0
  152. package/skills/canvas-design/canvas-fonts/GeistMono-Regular.ttf +0 -0
  153. package/skills/canvas-design/canvas-fonts/Gloock-OFL.txt +93 -0
  154. package/skills/canvas-design/canvas-fonts/Gloock-Regular.ttf +0 -0
  155. package/skills/canvas-design/canvas-fonts/IBMPlexMono-Bold.ttf +0 -0
  156. package/skills/canvas-design/canvas-fonts/IBMPlexMono-OFL.txt +93 -0
  157. package/skills/canvas-design/canvas-fonts/IBMPlexMono-Regular.ttf +0 -0
  158. package/skills/canvas-design/canvas-fonts/IBMPlexSerif-Bold.ttf +0 -0
  159. package/skills/canvas-design/canvas-fonts/IBMPlexSerif-BoldItalic.ttf +0 -0
  160. package/skills/canvas-design/canvas-fonts/IBMPlexSerif-Italic.ttf +0 -0
  161. package/skills/canvas-design/canvas-fonts/IBMPlexSerif-Regular.ttf +0 -0
  162. package/skills/canvas-design/canvas-fonts/InstrumentSans-Bold.ttf +0 -0
  163. package/skills/canvas-design/canvas-fonts/InstrumentSans-BoldItalic.ttf +0 -0
  164. package/skills/canvas-design/canvas-fonts/InstrumentSans-Italic.ttf +0 -0
  165. package/skills/canvas-design/canvas-fonts/InstrumentSans-OFL.txt +93 -0
  166. package/skills/canvas-design/canvas-fonts/InstrumentSans-Regular.ttf +0 -0
  167. package/skills/canvas-design/canvas-fonts/InstrumentSerif-Italic.ttf +0 -0
  168. package/skills/canvas-design/canvas-fonts/InstrumentSerif-Regular.ttf +0 -0
  169. package/skills/canvas-design/canvas-fonts/Italiana-OFL.txt +93 -0
  170. package/skills/canvas-design/canvas-fonts/Italiana-Regular.ttf +0 -0
  171. package/skills/canvas-design/canvas-fonts/JetBrainsMono-Bold.ttf +0 -0
  172. package/skills/canvas-design/canvas-fonts/JetBrainsMono-OFL.txt +93 -0
  173. package/skills/canvas-design/canvas-fonts/JetBrainsMono-Regular.ttf +0 -0
  174. package/skills/canvas-design/canvas-fonts/Jura-Light.ttf +0 -0
  175. package/skills/canvas-design/canvas-fonts/Jura-Medium.ttf +0 -0
  176. package/skills/canvas-design/canvas-fonts/Jura-OFL.txt +93 -0
  177. package/skills/canvas-design/canvas-fonts/LibreBaskerville-OFL.txt +93 -0
  178. package/skills/canvas-design/canvas-fonts/LibreBaskerville-Regular.ttf +0 -0
  179. package/skills/canvas-design/canvas-fonts/Lora-Bold.ttf +0 -0
  180. package/skills/canvas-design/canvas-fonts/Lora-BoldItalic.ttf +0 -0
  181. package/skills/canvas-design/canvas-fonts/Lora-Italic.ttf +0 -0
  182. package/skills/canvas-design/canvas-fonts/Lora-OFL.txt +93 -0
  183. package/skills/canvas-design/canvas-fonts/Lora-Regular.ttf +0 -0
  184. package/skills/canvas-design/canvas-fonts/NationalPark-Bold.ttf +0 -0
  185. package/skills/canvas-design/canvas-fonts/NationalPark-OFL.txt +93 -0
  186. package/skills/canvas-design/canvas-fonts/NationalPark-Regular.ttf +0 -0
  187. package/skills/canvas-design/canvas-fonts/NothingYouCouldDo-OFL.txt +93 -0
  188. package/skills/canvas-design/canvas-fonts/NothingYouCouldDo-Regular.ttf +0 -0
  189. package/skills/canvas-design/canvas-fonts/Outfit-Bold.ttf +0 -0
  190. package/skills/canvas-design/canvas-fonts/Outfit-OFL.txt +93 -0
  191. package/skills/canvas-design/canvas-fonts/Outfit-Regular.ttf +0 -0
  192. package/skills/canvas-design/canvas-fonts/PixelifySans-Medium.ttf +0 -0
  193. package/skills/canvas-design/canvas-fonts/PixelifySans-OFL.txt +93 -0
  194. package/skills/canvas-design/canvas-fonts/PoiretOne-OFL.txt +93 -0
  195. package/skills/canvas-design/canvas-fonts/PoiretOne-Regular.ttf +0 -0
  196. package/skills/canvas-design/canvas-fonts/RedHatMono-Bold.ttf +0 -0
  197. package/skills/canvas-design/canvas-fonts/RedHatMono-OFL.txt +93 -0
  198. package/skills/canvas-design/canvas-fonts/RedHatMono-Regular.ttf +0 -0
  199. package/skills/canvas-design/canvas-fonts/Silkscreen-OFL.txt +93 -0
  200. package/skills/canvas-design/canvas-fonts/Silkscreen-Regular.ttf +0 -0
  201. package/skills/canvas-design/canvas-fonts/SmoochSans-Medium.ttf +0 -0
  202. package/skills/canvas-design/canvas-fonts/SmoochSans-OFL.txt +93 -0
  203. package/skills/canvas-design/canvas-fonts/Tektur-Medium.ttf +0 -0
  204. package/skills/canvas-design/canvas-fonts/Tektur-OFL.txt +93 -0
  205. package/skills/canvas-design/canvas-fonts/Tektur-Regular.ttf +0 -0
  206. package/skills/canvas-design/canvas-fonts/WorkSans-Bold.ttf +0 -0
  207. package/skills/canvas-design/canvas-fonts/WorkSans-BoldItalic.ttf +0 -0
  208. package/skills/canvas-design/canvas-fonts/WorkSans-Italic.ttf +0 -0
  209. package/skills/canvas-design/canvas-fonts/WorkSans-OFL.txt +93 -0
  210. package/skills/canvas-design/canvas-fonts/WorkSans-Regular.ttf +0 -0
  211. package/skills/canvas-design/canvas-fonts/YoungSerif-OFL.txt +93 -0
  212. package/skills/canvas-design/canvas-fonts/YoungSerif-Regular.ttf +0 -0
  213. package/skills/caveman/SKILL.md +74 -0
  214. package/skills/changelog-generator/SKILL.md +104 -0
  215. package/skills/cisco-ios-patterns/SKILL.md +163 -0
  216. package/skills/ckm:design-system/SKILL.md +3 -0
  217. package/skills/ckm:slides/SKILL.md +3 -0
  218. package/skills/claude-red/SKILL.md +35 -0
  219. package/skills/click-path-audit/SKILL.md +244 -0
  220. package/skills/clickhouse-io/SKILL.md +439 -0
  221. package/skills/codebase-onboarding/SKILL.md +233 -0
  222. package/skills/coding-standards/SKILL.md +549 -0
  223. package/skills/compose-multiplatform-patterns/SKILL.md +299 -0
  224. package/skills/computational-architecture/SKILL.md +31 -0
  225. package/skills/content-engine/SKILL.md +131 -0
  226. package/skills/content-research-writer/SKILL.md +538 -0
  227. package/skills/continuous-agent-loop/SKILL.md +45 -0
  228. package/skills/cost-aware-llm-pipeline/SKILL.md +183 -0
  229. package/skills/cpp-coding-standards/SKILL.md +723 -0
  230. package/skills/crosspost/SKILL.md +111 -0
  231. package/skills/css-container-queries/SKILL.md +132 -0
  232. package/skills/customer-billing-ops/SKILL.md +140 -0
  233. package/skills/customs-trade-compliance/SKILL.md +263 -0
  234. package/skills/dart-flutter-patterns/SKILL.md +563 -0
  235. package/skills/dashboard-builder/SKILL.md +108 -0
  236. package/skills/data-scraper-agent/SKILL.md +764 -0
  237. package/skills/database-migrations/SKILL.md +429 -0
  238. package/skills/deep-research/SKILL.md +159 -0
  239. package/skills/defi-amm-security/SKILL.md +166 -0
  240. package/skills/deployment-patterns/SKILL.md +427 -0
  241. package/skills/design-auditor/README.md +504 -0
  242. package/skills/design-auditor/README_KR.md +327 -0
  243. package/skills/design-auditor/SKILL.md +8 -0
  244. package/skills/design-auditor/references/animation.md +300 -0
  245. package/skills/design-auditor/references/color.md +241 -0
  246. package/skills/design-auditor/references/corner-radius.md +331 -0
  247. package/skills/design-auditor/references/elevation.md +249 -0
  248. package/skills/design-auditor/references/ethics.md +877 -0
  249. package/skills/design-auditor/references/figma-mcp.md +377 -0
  250. package/skills/design-auditor/references/heuristics.md +730 -0
  251. package/skills/design-auditor/references/i18n.md +254 -0
  252. package/skills/design-auditor/references/iconography.md +201 -0
  253. package/skills/design-auditor/references/microcopy.md +227 -0
  254. package/skills/design-auditor/references/navigation.md +311 -0
  255. package/skills/design-auditor/references/spacing.md +313 -0
  256. package/skills/design-auditor/references/states.md +254 -0
  257. package/skills/design-auditor/references/tokens.md +286 -0
  258. package/skills/design-auditor/references/typography.md +273 -0
  259. package/skills/design-system/SKILL.md +82 -0
  260. package/skills/design-tokens-system/SKILL.md +156 -0
  261. package/skills/development-workflows/SKILL.md +7 -0
  262. package/skills/development-workflows/cross-model-workflow/assets/cross-model-workflow.png +0 -0
  263. package/skills/development-workflows/cross-model-workflow/cross-model-workflow.md +55 -0
  264. package/skills/development-workflows/rpi/.claude/agents/code-reviewer.md +21 -0
  265. package/skills/development-workflows/rpi/.claude/agents/constitutional-validator.md +288 -0
  266. package/skills/development-workflows/rpi/.claude/agents/documentation-analyst-writer.md +64 -0
  267. package/skills/development-workflows/rpi/.claude/agents/product-manager.md +15 -0
  268. package/skills/development-workflows/rpi/.claude/agents/requirement-parser.md +238 -0
  269. package/skills/development-workflows/rpi/.claude/agents/senior-software-engineer.md +15 -0
  270. package/skills/development-workflows/rpi/.claude/agents/technical-cto-advisor.md +201 -0
  271. package/skills/development-workflows/rpi/.claude/agents/ux-designer.md +14 -0
  272. package/skills/development-workflows/rpi/.claude/commands/rpi/implement.md +634 -0
  273. package/skills/development-workflows/rpi/.claude/commands/rpi/plan.md +416 -0
  274. package/skills/development-workflows/rpi/.claude/commands/rpi/research.md +381 -0
  275. package/skills/development-workflows/rpi/rpi-workflow.md +101 -0
  276. package/skills/development-workflows/rpi/rpi-workflow.svg +178 -0
  277. package/skills/django-celery/SKILL.md +457 -0
  278. package/skills/django-patterns/SKILL.md +734 -0
  279. package/skills/django-security/SKILL.md +593 -0
  280. package/skills/django-tdd/SKILL.md +729 -0
  281. package/skills/dmux-workflows/SKILL.md +7 -0
  282. package/skills/docker-patterns/SKILL.md +364 -0
  283. package/skills/documentation-lookup/SKILL.md +90 -0
  284. package/skills/domain-name-brainstormer/SKILL.md +212 -0
  285. package/skills/dribbble/SKILL.md +160 -0
  286. package/skills/dribbble/metadata.json +16 -0
  287. package/skills/e2e-testing/SKILL.md +326 -0
  288. package/skills/empirical-research/SKILL.md +22 -0
  289. package/skills/error-handling/SKILL.md +376 -0
  290. package/skills/eval-harness/SKILL.md +270 -0
  291. package/skills/evm-token-decimals/SKILL.md +130 -0
  292. package/skills/fastapi-patterns/SKILL.md +327 -0
  293. package/skills/finance-billing-ops/SKILL.md +127 -0
  294. package/skills/flox-environments/SKILL.md +496 -0
  295. package/skills/flutter-dart-code-review/SKILL.md +435 -0
  296. package/skills/foundation-models-on-device/SKILL.md +243 -0
  297. package/skills/framer/SKILL.md +159 -0
  298. package/skills/framer/metadata.json +16 -0
  299. package/skills/frontend-design/LICENSE.txt +21 -0
  300. package/skills/frontend-design/README.md +71 -0
  301. package/skills/frontend-design/SKILL.md +115 -0
  302. package/skills/frontend-design-direction/SKILL.md +92 -0
  303. package/skills/frontend-patterns/SKILL.md +7 -0
  304. package/skills/frontend-slides/SKILL.md +184 -0
  305. package/skills/frontend-slides/STYLE_PRESETS.md +330 -0
  306. package/skills/frontend-slides/animation-patterns.md +122 -0
  307. package/skills/frontend-slides/html-template.md +419 -0
  308. package/skills/frontend-slides/scripts/export-pdf.sh +418 -0
  309. package/skills/frontend-slides/scripts/extract-pptx.py +96 -0
  310. package/skills/frontend-slides/viewport-base.css +153 -0
  311. package/skills/gateguard/SKILL.md +125 -0
  312. package/skills/git-workflow/SKILL.md +715 -0
  313. package/skills/github-ops/SKILL.md +144 -0
  314. package/skills/golang-patterns/SKILL.md +674 -0
  315. package/skills/golang-testing/SKILL.md +720 -0
  316. package/skills/graphify/__init__.py +28 -0
  317. package/skills/graphify/__main__.py +2899 -0
  318. package/skills/graphify/analyze.py +608 -0
  319. package/skills/graphify/benchmark.py +152 -0
  320. package/skills/graphify/build.py +366 -0
  321. package/skills/graphify/cache.py +244 -0
  322. package/skills/graphify/callflow_html.py +2014 -0
  323. package/skills/graphify/cluster.py +267 -0
  324. package/skills/graphify/dedup.py +414 -0
  325. package/skills/graphify/detect.py +1018 -0
  326. package/skills/graphify/export.py +1264 -0
  327. package/skills/graphify/extract.py +6646 -0
  328. package/skills/graphify/global_graph.py +155 -0
  329. package/skills/graphify/google_workspace.py +223 -0
  330. package/skills/graphify/hooks.py +304 -0
  331. package/skills/graphify/ingest.py +331 -0
  332. package/skills/graphify/llm.py +1111 -0
  333. package/skills/graphify/manifest.py +4 -0
  334. package/skills/graphify/prs.py +746 -0
  335. package/skills/graphify/report.py +203 -0
  336. package/skills/graphify/security.py +242 -0
  337. package/skills/graphify/serve.py +899 -0
  338. package/skills/graphify/skill-aider.md +1229 -0
  339. package/skills/graphify/skill-claw.md +1229 -0
  340. package/skills/graphify/skill-codex.md +1290 -0
  341. package/skills/graphify/skill-copilot.md +1317 -0
  342. package/skills/graphify/skill-droid.md +1285 -0
  343. package/skills/graphify/skill-kiro.md +1228 -0
  344. package/skills/graphify/skill-opencode.md +1340 -0
  345. package/skills/graphify/skill-pi.md +1228 -0
  346. package/skills/graphify/skill-trae.md +1254 -0
  347. package/skills/graphify/skill-vscode.md +258 -0
  348. package/skills/graphify/skill-windows.md +1434 -0
  349. package/skills/graphify/skill.md +1086 -0
  350. package/skills/graphify/transcribe.py +184 -0
  351. package/skills/graphify/tree_html.py +580 -0
  352. package/skills/graphify/validate.py +72 -0
  353. package/skills/graphify/watch.py +728 -0
  354. package/skills/graphify/wiki.py +259 -0
  355. package/skills/growth-marketing/SKILL.md +26 -0
  356. package/skills/gsap-scrolltrigger/SKILL.md +8 -0
  357. package/skills/healthcare-cdss-patterns/SKILL.md +245 -0
  358. package/skills/healthcare-emr-patterns/SKILL.md +159 -0
  359. package/skills/healthcare-phi-compliance/SKILL.md +145 -0
  360. package/skills/hexagonal-architecture/SKILL.md +276 -0
  361. package/skills/hipaa-compliance/SKILL.md +78 -0
  362. package/skills/homelab-network-setup/SKILL.md +129 -0
  363. package/skills/imhcode/SKILL.md +183 -0
  364. package/skills/imhcode-brainstorm/SKILL.md +37 -0
  365. package/skills/imhcode-codebase-knowledge/SKILL.md +37 -0
  366. package/skills/imhcode-codebase-knowledge/assets/templates/ARCHITECTURE.md +49 -0
  367. package/skills/imhcode-codebase-knowledge/assets/templates/CONCERNS.md +56 -0
  368. package/skills/imhcode-codebase-knowledge/assets/templates/CONVENTIONS.md +52 -0
  369. package/skills/imhcode-codebase-knowledge/assets/templates/INTEGRATIONS.md +48 -0
  370. package/skills/imhcode-codebase-knowledge/assets/templates/STACK.md +56 -0
  371. package/skills/imhcode-codebase-knowledge/assets/templates/STRUCTURE.md +44 -0
  372. package/skills/imhcode-codebase-knowledge/assets/templates/TESTING.md +57 -0
  373. package/skills/imhcode-codebase-knowledge/references/inquiry-checkpoints.md +70 -0
  374. package/skills/imhcode-codebase-knowledge/references/stack-detection.md +131 -0
  375. package/skills/imhcode-codebase-knowledge/scripts/scan.py +712 -0
  376. package/skills/imhcode-dispatch/SKILL.md +31 -0
  377. package/skills/imhcode-saas-architect/SKILL.md +55 -0
  378. package/skills/imhcode-security/SKILL.md +42 -0
  379. package/skills/imhcode-sprint-planner/SKILL.md +42 -0
  380. package/skills/inventory-demand-planning/SKILL.md +247 -0
  381. package/skills/investor-materials/SKILL.md +96 -0
  382. package/skills/investor-outreach/SKILL.md +91 -0
  383. package/skills/ios-icon-gen/SKILL.md +157 -0
  384. package/skills/ios-icon-gen/scripts/generate_icons.swift +258 -0
  385. package/skills/ios-icon-gen/scripts/iconify_gen.sh +235 -0
  386. package/skills/java-coding-standards/SKILL.md +383 -0
  387. package/skills/jpa-patterns/SKILL.md +151 -0
  388. package/skills/kotlin-ktor-patterns/SKILL.md +689 -0
  389. package/skills/kotlin-patterns/SKILL.md +711 -0
  390. package/skills/laravel-patterns/SKILL.md +415 -0
  391. package/skills/laravel-plugin-discovery/SKILL.md +229 -0
  392. package/skills/laravel-security/SKILL.md +285 -0
  393. package/skills/laravel-tdd/SKILL.md +283 -0
  394. package/skills/laravel-verification/SKILL.md +179 -0
  395. package/skills/lightweight-3d-effects/SKILL.md +8 -0
  396. package/skills/linear/SKILL.md +156 -0
  397. package/skills/linear/metadata.json +16 -0
  398. package/skills/liquid-glass-design/SKILL.md +279 -0
  399. package/skills/llm-trading-agent-security/SKILL.md +146 -0
  400. package/skills/locomotive-scroll/SKILL.md +8 -0
  401. package/skills/logistics-exception-management/SKILL.md +222 -0
  402. package/skills/lottie-animations/SKILL.md +8 -0
  403. package/skills/make-interfaces-feel-better/SKILL.md +151 -0
  404. package/skills/mcp-server-patterns/SKILL.md +69 -0
  405. package/skills/meeting-insights-analyzer/SKILL.md +327 -0
  406. package/skills/micro-interactions/SKILL.md +178 -0
  407. package/skills/mle-workflow/SKILL.md +346 -0
  408. package/skills/mobbin/SKILL.md +157 -0
  409. package/skills/mobbin/metadata.json +16 -0
  410. package/skills/mobile-app-design/README.md +302 -0
  411. package/skills/mobile-app-design/SKILL.md +330 -0
  412. package/skills/mobile-app-design/examples/design-system-config.ts +685 -0
  413. package/skills/mobile-app-design/examples/form-validation-example.tsx +501 -0
  414. package/skills/mobile-app-design/examples/optimized-list-example.tsx +384 -0
  415. package/skills/mobile-app-design/examples/profile-screen-example.tsx +450 -0
  416. package/skills/mobile-app-design/references/accessibility-checklist.md +525 -0
  417. package/skills/mobile-app-design/references/android-guidelines.md +582 -0
  418. package/skills/mobile-app-design/references/common-mistakes.md +834 -0
  419. package/skills/mobile-app-design/references/ios-guidelines.md +421 -0
  420. package/skills/mobile-app-design/references/performance-patterns.md +705 -0
  421. package/skills/mobile-app-design/references/platform-differences.md +353 -0
  422. package/skills/mobile-app-design/references/ui-libraries.md +729 -0
  423. package/skills/mobile-app-design/scripts/accessibility-audit.sh +281 -0
  424. package/skills/mobile-app-design/scripts/check-contrast.py +188 -0
  425. package/skills/mobile-app-design/scripts/validate-touch-targets.sh +228 -0
  426. package/skills/mobile-app-ui-design/INDEX.md +131 -0
  427. package/skills/mobile-app-ui-design/README.md +135 -0
  428. package/skills/mobile-app-ui-design/SKILL.md +7 -0
  429. package/skills/mobile-app-ui-design/references/industry-conventions.md +151 -0
  430. package/skills/modern-web-design/SKILL.md +8 -0
  431. package/skills/motion-advanced/SKILL.md +596 -0
  432. package/skills/motion-design/SKILL.md +21 -0
  433. package/skills/motion-foundations/SKILL.md +299 -0
  434. package/skills/motion-framer/SKILL.md +8 -0
  435. package/skills/motion-patterns/SKILL.md +435 -0
  436. package/skills/motion-ui/SKILL.md +575 -0
  437. package/skills/mysql-patterns/SKILL.md +412 -0
  438. package/skills/nestjs-patterns/SKILL.md +230 -0
  439. package/skills/network-config-validation/SKILL.md +210 -0
  440. package/skills/nextjs-turbopack/SKILL.md +44 -0
  441. package/skills/nodejs-keccak256/SKILL.md +102 -0
  442. package/skills/nothing-design/SKILL.md +177 -0
  443. package/skills/nothing-design/references/components.md +153 -0
  444. package/skills/nothing-design/references/platform-mapping.md +64 -0
  445. package/skills/nothing-design/references/tokens.md +142 -0
  446. package/skills/nuxt4-patterns/SKILL.md +100 -0
  447. package/skills/openclaw-persona-forge/SKILL.md +288 -0
  448. package/skills/openclaw-persona-forge/gacha.py +224 -0
  449. package/skills/openclaw-persona-forge/gacha.sh +5 -0
  450. package/skills/openclaw-persona-forge/references/avatar-style.md +124 -0
  451. package/skills/openclaw-persona-forge/references/boundary-rules.md +53 -0
  452. package/skills/openclaw-persona-forge/references/error-handling.md +53 -0
  453. package/skills/openclaw-persona-forge/references/identity-tension.md +48 -0
  454. package/skills/openclaw-persona-forge/references/naming-system.md +39 -0
  455. package/skills/openclaw-persona-forge/references/output-template.md +166 -0
  456. package/skills/orchestration-workflow/SKILL.md +199 -0
  457. package/skills/orchestration-workflow/orchestration-workflow.gif +0 -0
  458. package/skills/orchestration-workflow/orchestration-workflow.md +199 -0
  459. package/skills/orchestration-workflow/orchestration-workflow.svg +78 -0
  460. package/skills/orchestration-workflow/output.md +13 -0
  461. package/skills/orchestration-workflow/weather.svg +6 -0
  462. package/skills/pixijs-2d/SKILL.md +8 -0
  463. package/skills/plan-orchestrate/SKILL.md +262 -0
  464. package/skills/plankton-code-quality/SKILL.md +236 -0
  465. package/skills/postgres-patterns/SKILL.md +147 -0
  466. package/skills/ppt-mckinsey/SKILL.md +27 -0
  467. package/skills/prisma-patterns/SKILL.md +371 -0
  468. package/skills/product-capability/SKILL.md +141 -0
  469. package/skills/product-lens/SKILL.md +92 -0
  470. package/skills/production-audit/SKILL.md +206 -0
  471. package/skills/project-flow-ops/SKILL.md +111 -0
  472. package/skills/prompt-optimizer/SKILL.md +398 -0
  473. package/skills/python-patterns/SKILL.md +750 -0
  474. package/skills/python-testing/SKILL.md +816 -0
  475. package/skills/pytorch-patterns/SKILL.md +396 -0
  476. package/skills/quarkus-patterns/SKILL.md +722 -0
  477. package/skills/radix-ui-primitives/SKILL.md +86 -0
  478. package/skills/react-native-best-practices/SKILL.md +83 -0
  479. package/skills/react-native-brownfield-migration/SKILL.md +115 -0
  480. package/skills/react-spring-physics/SKILL.md +8 -0
  481. package/skills/react-three-fiber/SKILL.md +8 -0
  482. package/skills/recsys-pipeline-architect/SKILL.md +114 -0
  483. package/skills/redis-patterns/SKILL.md +403 -0
  484. package/skills/remotion-video-creation/SKILL.md +43 -0
  485. package/skills/remotion-video-creation/rules/3d.md +86 -0
  486. package/skills/remotion-video-creation/rules/animations.md +29 -0
  487. package/skills/remotion-video-creation/rules/assets/charts-bar-chart.tsx +173 -0
  488. package/skills/remotion-video-creation/rules/assets/text-animations-typewriter.tsx +100 -0
  489. package/skills/remotion-video-creation/rules/assets/text-animations-word-highlight.tsx +108 -0
  490. package/skills/remotion-video-creation/rules/assets.md +78 -0
  491. package/skills/remotion-video-creation/rules/audio.md +172 -0
  492. package/skills/remotion-video-creation/rules/calculate-metadata.md +104 -0
  493. package/skills/remotion-video-creation/rules/can-decode.md +75 -0
  494. package/skills/remotion-video-creation/rules/charts.md +58 -0
  495. package/skills/remotion-video-creation/rules/compositions.md +146 -0
  496. package/skills/remotion-video-creation/rules/display-captions.md +126 -0
  497. package/skills/remotion-video-creation/rules/extract-frames.md +229 -0
  498. package/skills/remotion-video-creation/rules/fonts.md +152 -0
  499. package/skills/remotion-video-creation/rules/get-audio-duration.md +58 -0
  500. package/skills/remotion-video-creation/rules/get-video-dimensions.md +68 -0
  501. package/skills/remotion-video-creation/rules/get-video-duration.md +58 -0
  502. package/skills/remotion-video-creation/rules/gifs.md +138 -0
  503. package/skills/remotion-video-creation/rules/images.md +130 -0
  504. package/skills/remotion-video-creation/rules/import-srt-captions.md +67 -0
  505. package/skills/remotion-video-creation/rules/lottie.md +67 -0
  506. package/skills/remotion-video-creation/rules/measuring-dom-nodes.md +34 -0
  507. package/skills/remotion-video-creation/rules/measuring-text.md +143 -0
  508. package/skills/remotion-video-creation/rules/sequencing.md +106 -0
  509. package/skills/remotion-video-creation/rules/tailwind.md +11 -0
  510. package/skills/remotion-video-creation/rules/text-animations.md +20 -0
  511. package/skills/remotion-video-creation/rules/timing.md +179 -0
  512. package/skills/remotion-video-creation/rules/transcribe-captions.md +19 -0
  513. package/skills/remotion-video-creation/rules/transitions.md +122 -0
  514. package/skills/remotion-video-creation/rules/trimming.md +52 -0
  515. package/skills/remotion-video-creation/rules/videos.md +171 -0
  516. package/skills/repo-scan/SKILL.md +78 -0
  517. package/skills/responsive-email-templates/SKILL.md +110 -0
  518. package/skills/rive-interactive/SKILL.md +8 -0
  519. package/skills/rust-patterns/SKILL.md +499 -0
  520. package/skills/rust-testing/SKILL.md +500 -0
  521. package/skills/scroll-reveal-libraries/SKILL.md +8 -0
  522. package/skills/security-bounty-hunter/SKILL.md +99 -0
  523. package/skills/security-review/SKILL.md +503 -0
  524. package/skills/security-review/cloud-infrastructure-security.md +361 -0
  525. package/skills/security-scan/SKILL.md +165 -0
  526. package/skills/seo/SKILL.md +154 -0
  527. package/skills/seo-growth/SKILL.md +34 -0
  528. package/skills/shadcn-ui-patterns/SKILL.md +123 -0
  529. package/skills/spline-interactive/SKILL.md +8 -0
  530. package/skills/springboot-patterns/SKILL.md +314 -0
  531. package/skills/springboot-security/SKILL.md +272 -0
  532. package/skills/springboot-tdd/SKILL.md +158 -0
  533. package/skills/strategic-compact/SKILL.md +131 -0
  534. package/skills/stripe/SKILL.md +168 -0
  535. package/skills/stripe/metadata.json +16 -0
  536. package/skills/swift-actor-persistence/SKILL.md +143 -0
  537. package/skills/swift-concurrency-6-2/SKILL.md +216 -0
  538. package/skills/swiftui-patterns/SKILL.md +259 -0
  539. package/skills/systematic-debugging/CREATION-LOG.md +119 -0
  540. package/skills/systematic-debugging/SKILL.md +296 -0
  541. package/skills/systematic-debugging/condition-based-waiting-example.ts +158 -0
  542. package/skills/systematic-debugging/condition-based-waiting.md +115 -0
  543. package/skills/systematic-debugging/defense-in-depth.md +122 -0
  544. package/skills/systematic-debugging/find-polluter.sh +63 -0
  545. package/skills/systematic-debugging/root-cause-tracing.md +169 -0
  546. package/skills/systematic-debugging/test-academic.md +14 -0
  547. package/skills/systematic-debugging/test-pressure-1.md +58 -0
  548. package/skills/systematic-debugging/test-pressure-2.md +68 -0
  549. package/skills/systematic-debugging/test-pressure-3.md +69 -0
  550. package/skills/tailwindcss-v4/SKILL.md +107 -0
  551. package/skills/tdd-workflow/SKILL.md +463 -0
  552. package/skills/team-builder/SKILL.md +168 -0
  553. package/skills/test-driven-development/SKILL.md +371 -0
  554. package/skills/test-driven-development/testing-anti-patterns.md +299 -0
  555. package/skills/theme-factory/LICENSE.txt +202 -0
  556. package/skills/theme-factory/SKILL.md +59 -0
  557. package/skills/theme-factory/theme-showcase.pdf +0 -0
  558. package/skills/theme-factory/themes/arctic-frost.md +19 -0
  559. package/skills/theme-factory/themes/botanical-garden.md +19 -0
  560. package/skills/theme-factory/themes/desert-rose.md +19 -0
  561. package/skills/theme-factory/themes/forest-canopy.md +19 -0
  562. package/skills/theme-factory/themes/golden-hour.md +19 -0
  563. package/skills/theme-factory/themes/midnight-galaxy.md +19 -0
  564. package/skills/theme-factory/themes/modern-minimalist.md +19 -0
  565. package/skills/theme-factory/themes/ocean-depths.md +19 -0
  566. package/skills/theme-factory/themes/sunset-boulevard.md +19 -0
  567. package/skills/theme-factory/themes/tech-innovation.md +19 -0
  568. package/skills/threejs-webgl/SKILL.md +8 -0
  569. package/skills/trailofbits-auditing/SKILL.md +30 -0
  570. package/skills/twitter-algorithm-optimizer/SKILL.md +327 -0
  571. package/skills/typeui-cli/SKILL.md +90 -0
  572. package/skills/typeui-main/DESIGN.md +114 -0
  573. package/skills/typeui-main/LICENSE.md +9 -0
  574. package/skills/typeui-main/README.md +84 -0
  575. package/skills/typeui-main/REGISTRY.md +60 -0
  576. package/skills/typeui-main/SKILL.md +114 -0
  577. package/skills/typeui-main/package-lock.json +2123 -0
  578. package/skills/typeui-main/package.json +56 -0
  579. package/skills/typeui-main/skills/typeui-cli/SKILL.md +90 -0
  580. package/skills/typeui-main/src/cli.ts +282 -0
  581. package/skills/typeui-main/src/config.ts +28 -0
  582. package/skills/typeui-main/src/domain/designSystemSchema.ts +77 -0
  583. package/skills/typeui-main/src/generation/existingDesignSystem.ts +228 -0
  584. package/skills/typeui-main/src/generation/randomDesignSystem.ts +348 -0
  585. package/skills/typeui-main/src/generation/runDesignGeneration.ts +31 -0
  586. package/skills/typeui-main/src/generation/runGeneration.ts +36 -0
  587. package/skills/typeui-main/src/generation/runPull.ts +62 -0
  588. package/skills/typeui-main/src/io/updateSkillFile.ts +118 -0
  589. package/skills/typeui-main/src/prompts/designSystem.ts +755 -0
  590. package/skills/typeui-main/src/prompts/registry.ts +72 -0
  591. package/skills/typeui-main/src/registry/registryClient.ts +246 -0
  592. package/skills/typeui-main/src/renderers/claudeRenderer.ts +10 -0
  593. package/skills/typeui-main/src/renderers/codexRenderer.ts +10 -0
  594. package/skills/typeui-main/src/renderers/cursorRenderer.ts +10 -0
  595. package/skills/typeui-main/src/renderers/index.ts +14 -0
  596. package/skills/typeui-main/src/renderers/openCodeRenderer.ts +10 -0
  597. package/skills/typeui-main/src/renderers/shared.ts +252 -0
  598. package/skills/typeui-main/src/skillMetadata.ts +19 -0
  599. package/skills/typeui-main/src/types.ts +204 -0
  600. package/skills/typeui-main/src/ui/banner.ts +20 -0
  601. package/skills/typeui-main/test/existingDesignSystem.test.ts +67 -0
  602. package/skills/typeui-main/test/orchestrator.test.ts +113 -0
  603. package/skills/typeui-main/test/randomDesignSystem.test.ts +20 -0
  604. package/skills/typeui-main/test/registryClient.test.ts +408 -0
  605. package/skills/typeui-main/test/renderers.test.ts +41 -0
  606. package/skills/typeui-main/test/runDesignGeneration.test.ts +52 -0
  607. package/skills/typeui-main/test/runPull.test.ts +92 -0
  608. package/skills/typeui-main/test/skillMetadata.test.ts +11 -0
  609. package/skills/typeui-main/test/updateSkillFile.test.ts +160 -0
  610. package/skills/typeui-main/tsconfig.json +16 -0
  611. package/skills/ui-demo/SKILL.md +465 -0
  612. package/skills/ui-to-vue/SKILL.md +134 -0
  613. package/skills/ui-ux-pro-max/.claude/skills/banner-design/SKILL.md +192 -0
  614. package/skills/ui-ux-pro-max/.claude/skills/banner-design/references/banner-sizes-and-styles.md +118 -0
  615. package/skills/ui-ux-pro-max/.claude/skills/brand/SKILL.md +97 -0
  616. package/skills/ui-ux-pro-max/.claude/skills/brand/references/approval-checklist.md +169 -0
  617. package/skills/ui-ux-pro-max/.claude/skills/brand/references/asset-organization.md +157 -0
  618. package/skills/ui-ux-pro-max/.claude/skills/brand/references/brand-guideline-template.md +140 -0
  619. package/skills/ui-ux-pro-max/.claude/skills/brand/references/color-palette-management.md +186 -0
  620. package/skills/ui-ux-pro-max/.claude/skills/brand/references/consistency-checklist.md +94 -0
  621. package/skills/ui-ux-pro-max/.claude/skills/brand/references/logo-usage-rules.md +185 -0
  622. package/skills/ui-ux-pro-max/.claude/skills/brand/references/messaging-framework.md +85 -0
  623. package/skills/ui-ux-pro-max/.claude/skills/brand/references/typography-specifications.md +214 -0
  624. package/skills/ui-ux-pro-max/.claude/skills/brand/references/update.md +118 -0
  625. package/skills/ui-ux-pro-max/.claude/skills/brand/references/visual-identity.md +96 -0
  626. package/skills/ui-ux-pro-max/.claude/skills/brand/references/voice-framework.md +88 -0
  627. package/skills/ui-ux-pro-max/.claude/skills/brand/scripts/extract-colors.cjs +341 -0
  628. package/skills/ui-ux-pro-max/.claude/skills/brand/scripts/inject-brand-context.cjs +349 -0
  629. package/skills/ui-ux-pro-max/.claude/skills/brand/scripts/sync-brand-to-tokens.cjs +266 -0
  630. package/skills/ui-ux-pro-max/.claude/skills/brand/scripts/validate-asset.cjs +387 -0
  631. package/skills/ui-ux-pro-max/.claude/skills/brand/templates/brand-guidelines-starter.md +275 -0
  632. package/skills/ui-ux-pro-max/.claude/skills/design/SKILL.md +302 -0
  633. package/skills/ui-ux-pro-max/.claude/skills/design/data/cip/deliverables.csv +51 -0
  634. package/skills/ui-ux-pro-max/.claude/skills/design/data/cip/industries.csv +21 -0
  635. package/skills/ui-ux-pro-max/.claude/skills/design/data/cip/mockup-contexts.csv +21 -0
  636. package/skills/ui-ux-pro-max/.claude/skills/design/data/cip/styles.csv +21 -0
  637. package/skills/ui-ux-pro-max/.claude/skills/design/data/icon/styles.csv +16 -0
  638. package/skills/ui-ux-pro-max/.claude/skills/design/data/logo/colors.csv +56 -0
  639. package/skills/ui-ux-pro-max/.claude/skills/design/data/logo/industries.csv +56 -0
  640. package/skills/ui-ux-pro-max/.claude/skills/design/data/logo/styles.csv +56 -0
  641. package/skills/ui-ux-pro-max/.claude/skills/design/references/banner-sizes-and-styles.md +118 -0
  642. package/skills/ui-ux-pro-max/.claude/skills/design/references/cip-deliverable-guide.md +95 -0
  643. package/skills/ui-ux-pro-max/.claude/skills/design/references/cip-design.md +121 -0
  644. package/skills/ui-ux-pro-max/.claude/skills/design/references/cip-prompt-engineering.md +84 -0
  645. package/skills/ui-ux-pro-max/.claude/skills/design/references/cip-style-guide.md +68 -0
  646. package/skills/ui-ux-pro-max/.claude/skills/design/references/design-routing.md +207 -0
  647. package/skills/ui-ux-pro-max/.claude/skills/design/references/icon-design.md +122 -0
  648. package/skills/ui-ux-pro-max/.claude/skills/design/references/logo-color-psychology.md +101 -0
  649. package/skills/ui-ux-pro-max/.claude/skills/design/references/logo-design.md +92 -0
  650. package/skills/ui-ux-pro-max/.claude/skills/design/references/logo-prompt-engineering.md +158 -0
  651. package/skills/ui-ux-pro-max/.claude/skills/design/references/logo-style-guide.md +109 -0
  652. package/skills/ui-ux-pro-max/.claude/skills/design/references/slides-copywriting-formulas.md +84 -0
  653. package/skills/ui-ux-pro-max/.claude/skills/design/references/slides-create.md +4 -0
  654. package/skills/ui-ux-pro-max/.claude/skills/design/references/slides-html-template.md +295 -0
  655. package/skills/ui-ux-pro-max/.claude/skills/design/references/slides-layout-patterns.md +137 -0
  656. package/skills/ui-ux-pro-max/.claude/skills/design/references/slides-strategies.md +94 -0
  657. package/skills/ui-ux-pro-max/.claude/skills/design/references/slides.md +42 -0
  658. package/skills/ui-ux-pro-max/.claude/skills/design/references/social-photos-design.md +329 -0
  659. package/skills/ui-ux-pro-max/.claude/skills/design/scripts/cip/core.py +215 -0
  660. package/skills/ui-ux-pro-max/.claude/skills/design/scripts/cip/generate.py +484 -0
  661. package/skills/ui-ux-pro-max/.claude/skills/design/scripts/cip/render-html.py +424 -0
  662. package/skills/ui-ux-pro-max/.claude/skills/design/scripts/cip/search.py +127 -0
  663. package/skills/ui-ux-pro-max/.claude/skills/design/scripts/icon/generate.py +487 -0
  664. package/skills/ui-ux-pro-max/.claude/skills/design/scripts/logo/core.py +175 -0
  665. package/skills/ui-ux-pro-max/.claude/skills/design/scripts/logo/generate.py +362 -0
  666. package/skills/ui-ux-pro-max/.claude/skills/design/scripts/logo/search.py +114 -0
  667. package/skills/ui-ux-pro-max/.claude/skills/design-system/SKILL.md +244 -0
  668. package/skills/ui-ux-pro-max/.claude/skills/design-system/data/slide-backgrounds.csv +11 -0
  669. package/skills/ui-ux-pro-max/.claude/skills/design-system/data/slide-charts.csv +26 -0
  670. package/skills/ui-ux-pro-max/.claude/skills/design-system/data/slide-color-logic.csv +14 -0
  671. package/skills/ui-ux-pro-max/.claude/skills/design-system/data/slide-copy.csv +26 -0
  672. package/skills/ui-ux-pro-max/.claude/skills/design-system/data/slide-layout-logic.csv +16 -0
  673. package/skills/ui-ux-pro-max/.claude/skills/design-system/data/slide-layouts.csv +26 -0
  674. package/skills/ui-ux-pro-max/.claude/skills/design-system/data/slide-strategies.csv +16 -0
  675. package/skills/ui-ux-pro-max/.claude/skills/design-system/data/slide-typography.csv +15 -0
  676. package/skills/ui-ux-pro-max/.claude/skills/design-system/references/component-specs.md +236 -0
  677. package/skills/ui-ux-pro-max/.claude/skills/design-system/references/component-tokens.md +214 -0
  678. package/skills/ui-ux-pro-max/.claude/skills/design-system/references/primitive-tokens.md +203 -0
  679. package/skills/ui-ux-pro-max/.claude/skills/design-system/references/semantic-tokens.md +215 -0
  680. package/skills/ui-ux-pro-max/.claude/skills/design-system/references/states-and-variants.md +241 -0
  681. package/skills/ui-ux-pro-max/.claude/skills/design-system/references/tailwind-integration.md +251 -0
  682. package/skills/ui-ux-pro-max/.claude/skills/design-system/references/token-architecture.md +224 -0
  683. package/skills/ui-ux-pro-max/.claude/skills/design-system/scripts/embed-tokens.cjs +99 -0
  684. package/skills/ui-ux-pro-max/.claude/skills/design-system/scripts/fetch-background.py +317 -0
  685. package/skills/ui-ux-pro-max/.claude/skills/design-system/scripts/generate-slide.py +753 -0
  686. package/skills/ui-ux-pro-max/.claude/skills/design-system/scripts/generate-tokens.cjs +205 -0
  687. package/skills/ui-ux-pro-max/.claude/skills/design-system/scripts/html-token-validator.py +327 -0
  688. package/skills/ui-ux-pro-max/.claude/skills/design-system/scripts/search-slides.py +218 -0
  689. package/skills/ui-ux-pro-max/.claude/skills/design-system/scripts/slide-token-validator.py +35 -0
  690. package/skills/ui-ux-pro-max/.claude/skills/design-system/scripts/slide_search_core.py +453 -0
  691. package/skills/ui-ux-pro-max/.claude/skills/design-system/scripts/validate-tokens.cjs +251 -0
  692. package/skills/ui-ux-pro-max/.claude/skills/design-system/templates/design-tokens-starter.json +143 -0
  693. package/skills/ui-ux-pro-max/.claude/skills/slides/SKILL.md +42 -0
  694. package/skills/ui-ux-pro-max/.claude/skills/slides/references/copywriting-formulas.md +84 -0
  695. package/skills/ui-ux-pro-max/.claude/skills/slides/references/create.md +4 -0
  696. package/skills/ui-ux-pro-max/.claude/skills/slides/references/html-template.md +295 -0
  697. package/skills/ui-ux-pro-max/.claude/skills/slides/references/layout-patterns.md +137 -0
  698. package/skills/ui-ux-pro-max/.claude/skills/slides/references/slide-strategies.md +94 -0
  699. package/skills/ui-ux-pro-max/.claude/skills/ui-styling/LICENSE.txt +202 -0
  700. package/skills/ui-ux-pro-max/.claude/skills/ui-styling/SKILL.md +324 -0
  701. package/skills/ui-ux-pro-max/.claude/skills/ui-styling/canvas-fonts/ArsenalSC-OFL.txt +93 -0
  702. package/skills/ui-ux-pro-max/.claude/skills/ui-styling/canvas-fonts/ArsenalSC-Regular.ttf +0 -0
  703. package/skills/ui-ux-pro-max/.claude/skills/ui-styling/canvas-fonts/BigShoulders-Bold.ttf +0 -0
  704. package/skills/ui-ux-pro-max/.claude/skills/ui-styling/canvas-fonts/BigShoulders-OFL.txt +93 -0
  705. package/skills/ui-ux-pro-max/.claude/skills/ui-styling/canvas-fonts/BigShoulders-Regular.ttf +0 -0
  706. package/skills/ui-ux-pro-max/.claude/skills/ui-styling/canvas-fonts/Boldonse-OFL.txt +93 -0
  707. package/skills/ui-ux-pro-max/.claude/skills/ui-styling/canvas-fonts/Boldonse-Regular.ttf +0 -0
  708. package/skills/ui-ux-pro-max/.claude/skills/ui-styling/canvas-fonts/BricolageGrotesque-Bold.ttf +0 -0
  709. package/skills/ui-ux-pro-max/.claude/skills/ui-styling/canvas-fonts/BricolageGrotesque-OFL.txt +93 -0
  710. package/skills/ui-ux-pro-max/.claude/skills/ui-styling/canvas-fonts/BricolageGrotesque-Regular.ttf +0 -0
  711. package/skills/ui-ux-pro-max/.claude/skills/ui-styling/canvas-fonts/CrimsonPro-Bold.ttf +0 -0
  712. package/skills/ui-ux-pro-max/.claude/skills/ui-styling/canvas-fonts/CrimsonPro-Italic.ttf +0 -0
  713. package/skills/ui-ux-pro-max/.claude/skills/ui-styling/canvas-fonts/CrimsonPro-OFL.txt +93 -0
  714. package/skills/ui-ux-pro-max/.claude/skills/ui-styling/canvas-fonts/CrimsonPro-Regular.ttf +0 -0
  715. package/skills/ui-ux-pro-max/.claude/skills/ui-styling/canvas-fonts/DMMono-OFL.txt +93 -0
  716. package/skills/ui-ux-pro-max/.claude/skills/ui-styling/canvas-fonts/DMMono-Regular.ttf +0 -0
  717. package/skills/ui-ux-pro-max/.claude/skills/ui-styling/canvas-fonts/EricaOne-OFL.txt +94 -0
  718. package/skills/ui-ux-pro-max/.claude/skills/ui-styling/canvas-fonts/EricaOne-Regular.ttf +0 -0
  719. package/skills/ui-ux-pro-max/.claude/skills/ui-styling/canvas-fonts/GeistMono-Bold.ttf +0 -0
  720. package/skills/ui-ux-pro-max/.claude/skills/ui-styling/canvas-fonts/GeistMono-OFL.txt +93 -0
  721. package/skills/ui-ux-pro-max/.claude/skills/ui-styling/canvas-fonts/GeistMono-Regular.ttf +0 -0
  722. package/skills/ui-ux-pro-max/.claude/skills/ui-styling/canvas-fonts/Gloock-OFL.txt +93 -0
  723. package/skills/ui-ux-pro-max/.claude/skills/ui-styling/canvas-fonts/Gloock-Regular.ttf +0 -0
  724. package/skills/ui-ux-pro-max/.claude/skills/ui-styling/canvas-fonts/IBMPlexMono-Bold.ttf +0 -0
  725. package/skills/ui-ux-pro-max/.claude/skills/ui-styling/canvas-fonts/IBMPlexMono-OFL.txt +93 -0
  726. package/skills/ui-ux-pro-max/.claude/skills/ui-styling/canvas-fonts/IBMPlexMono-Regular.ttf +0 -0
  727. package/skills/ui-ux-pro-max/.claude/skills/ui-styling/canvas-fonts/IBMPlexSerif-Bold.ttf +0 -0
  728. package/skills/ui-ux-pro-max/.claude/skills/ui-styling/canvas-fonts/IBMPlexSerif-BoldItalic.ttf +0 -0
  729. package/skills/ui-ux-pro-max/.claude/skills/ui-styling/canvas-fonts/IBMPlexSerif-Italic.ttf +0 -0
  730. package/skills/ui-ux-pro-max/.claude/skills/ui-styling/canvas-fonts/IBMPlexSerif-Regular.ttf +0 -0
  731. package/skills/ui-ux-pro-max/.claude/skills/ui-styling/canvas-fonts/InstrumentSans-Bold.ttf +0 -0
  732. package/skills/ui-ux-pro-max/.claude/skills/ui-styling/canvas-fonts/InstrumentSans-BoldItalic.ttf +0 -0
  733. package/skills/ui-ux-pro-max/.claude/skills/ui-styling/canvas-fonts/InstrumentSans-Italic.ttf +0 -0
  734. package/skills/ui-ux-pro-max/.claude/skills/ui-styling/canvas-fonts/InstrumentSans-OFL.txt +93 -0
  735. package/skills/ui-ux-pro-max/.claude/skills/ui-styling/canvas-fonts/InstrumentSans-Regular.ttf +0 -0
  736. package/skills/ui-ux-pro-max/.claude/skills/ui-styling/canvas-fonts/InstrumentSerif-Italic.ttf +0 -0
  737. package/skills/ui-ux-pro-max/.claude/skills/ui-styling/canvas-fonts/InstrumentSerif-Regular.ttf +0 -0
  738. package/skills/ui-ux-pro-max/.claude/skills/ui-styling/canvas-fonts/Italiana-OFL.txt +93 -0
  739. package/skills/ui-ux-pro-max/.claude/skills/ui-styling/canvas-fonts/Italiana-Regular.ttf +0 -0
  740. package/skills/ui-ux-pro-max/.claude/skills/ui-styling/canvas-fonts/JetBrainsMono-Bold.ttf +0 -0
  741. package/skills/ui-ux-pro-max/.claude/skills/ui-styling/canvas-fonts/JetBrainsMono-OFL.txt +93 -0
  742. package/skills/ui-ux-pro-max/.claude/skills/ui-styling/canvas-fonts/JetBrainsMono-Regular.ttf +0 -0
  743. package/skills/ui-ux-pro-max/.claude/skills/ui-styling/canvas-fonts/Jura-Light.ttf +0 -0
  744. package/skills/ui-ux-pro-max/.claude/skills/ui-styling/canvas-fonts/Jura-Medium.ttf +0 -0
  745. package/skills/ui-ux-pro-max/.claude/skills/ui-styling/canvas-fonts/Jura-OFL.txt +93 -0
  746. package/skills/ui-ux-pro-max/.claude/skills/ui-styling/canvas-fonts/LibreBaskerville-OFL.txt +93 -0
  747. package/skills/ui-ux-pro-max/.claude/skills/ui-styling/canvas-fonts/LibreBaskerville-Regular.ttf +0 -0
  748. package/skills/ui-ux-pro-max/.claude/skills/ui-styling/canvas-fonts/Lora-Bold.ttf +0 -0
  749. package/skills/ui-ux-pro-max/.claude/skills/ui-styling/canvas-fonts/Lora-BoldItalic.ttf +0 -0
  750. package/skills/ui-ux-pro-max/.claude/skills/ui-styling/canvas-fonts/Lora-Italic.ttf +0 -0
  751. package/skills/ui-ux-pro-max/.claude/skills/ui-styling/canvas-fonts/Lora-OFL.txt +93 -0
  752. package/skills/ui-ux-pro-max/.claude/skills/ui-styling/canvas-fonts/Lora-Regular.ttf +0 -0
  753. package/skills/ui-ux-pro-max/.claude/skills/ui-styling/canvas-fonts/NationalPark-Bold.ttf +0 -0
  754. package/skills/ui-ux-pro-max/.claude/skills/ui-styling/canvas-fonts/NationalPark-OFL.txt +93 -0
  755. package/skills/ui-ux-pro-max/.claude/skills/ui-styling/canvas-fonts/NationalPark-Regular.ttf +0 -0
  756. package/skills/ui-ux-pro-max/.claude/skills/ui-styling/canvas-fonts/NothingYouCouldDo-OFL.txt +93 -0
  757. package/skills/ui-ux-pro-max/.claude/skills/ui-styling/canvas-fonts/NothingYouCouldDo-Regular.ttf +0 -0
  758. package/skills/ui-ux-pro-max/.claude/skills/ui-styling/canvas-fonts/Outfit-Bold.ttf +0 -0
  759. package/skills/ui-ux-pro-max/.claude/skills/ui-styling/canvas-fonts/Outfit-OFL.txt +93 -0
  760. package/skills/ui-ux-pro-max/.claude/skills/ui-styling/canvas-fonts/Outfit-Regular.ttf +0 -0
  761. package/skills/ui-ux-pro-max/.claude/skills/ui-styling/canvas-fonts/PixelifySans-Medium.ttf +0 -0
  762. package/skills/ui-ux-pro-max/.claude/skills/ui-styling/canvas-fonts/PixelifySans-OFL.txt +93 -0
  763. package/skills/ui-ux-pro-max/.claude/skills/ui-styling/canvas-fonts/PoiretOne-OFL.txt +93 -0
  764. package/skills/ui-ux-pro-max/.claude/skills/ui-styling/canvas-fonts/PoiretOne-Regular.ttf +0 -0
  765. package/skills/ui-ux-pro-max/.claude/skills/ui-styling/canvas-fonts/RedHatMono-Bold.ttf +0 -0
  766. package/skills/ui-ux-pro-max/.claude/skills/ui-styling/canvas-fonts/RedHatMono-OFL.txt +93 -0
  767. package/skills/ui-ux-pro-max/.claude/skills/ui-styling/canvas-fonts/RedHatMono-Regular.ttf +0 -0
  768. package/skills/ui-ux-pro-max/.claude/skills/ui-styling/canvas-fonts/Silkscreen-OFL.txt +93 -0
  769. package/skills/ui-ux-pro-max/.claude/skills/ui-styling/canvas-fonts/Silkscreen-Regular.ttf +0 -0
  770. package/skills/ui-ux-pro-max/.claude/skills/ui-styling/canvas-fonts/SmoochSans-Medium.ttf +0 -0
  771. package/skills/ui-ux-pro-max/.claude/skills/ui-styling/canvas-fonts/SmoochSans-OFL.txt +93 -0
  772. package/skills/ui-ux-pro-max/.claude/skills/ui-styling/canvas-fonts/Tektur-Medium.ttf +0 -0
  773. package/skills/ui-ux-pro-max/.claude/skills/ui-styling/canvas-fonts/Tektur-OFL.txt +93 -0
  774. package/skills/ui-ux-pro-max/.claude/skills/ui-styling/canvas-fonts/Tektur-Regular.ttf +0 -0
  775. package/skills/ui-ux-pro-max/.claude/skills/ui-styling/canvas-fonts/WorkSans-Bold.ttf +0 -0
  776. package/skills/ui-ux-pro-max/.claude/skills/ui-styling/canvas-fonts/WorkSans-BoldItalic.ttf +0 -0
  777. package/skills/ui-ux-pro-max/.claude/skills/ui-styling/canvas-fonts/WorkSans-Italic.ttf +0 -0
  778. package/skills/ui-ux-pro-max/.claude/skills/ui-styling/canvas-fonts/WorkSans-OFL.txt +93 -0
  779. package/skills/ui-ux-pro-max/.claude/skills/ui-styling/canvas-fonts/WorkSans-Regular.ttf +0 -0
  780. package/skills/ui-ux-pro-max/.claude/skills/ui-styling/canvas-fonts/YoungSerif-OFL.txt +93 -0
  781. package/skills/ui-ux-pro-max/.claude/skills/ui-styling/canvas-fonts/YoungSerif-Regular.ttf +0 -0
  782. package/skills/ui-ux-pro-max/.claude/skills/ui-styling/references/canvas-design-system.md +320 -0
  783. package/skills/ui-ux-pro-max/.claude/skills/ui-styling/references/shadcn-accessibility.md +471 -0
  784. package/skills/ui-ux-pro-max/.claude/skills/ui-styling/references/shadcn-components.md +424 -0
  785. package/skills/ui-ux-pro-max/.claude/skills/ui-styling/references/shadcn-theming.md +373 -0
  786. package/skills/ui-ux-pro-max/.claude/skills/ui-styling/references/tailwind-customization.md +483 -0
  787. package/skills/ui-ux-pro-max/.claude/skills/ui-styling/references/tailwind-responsive.md +382 -0
  788. package/skills/ui-ux-pro-max/.claude/skills/ui-styling/references/tailwind-utilities.md +455 -0
  789. package/skills/ui-ux-pro-max/.claude/skills/ui-styling/scripts/.coverage +0 -0
  790. package/skills/ui-ux-pro-max/.claude/skills/ui-styling/scripts/requirements.txt +17 -0
  791. package/skills/ui-ux-pro-max/.claude/skills/ui-styling/scripts/shadcn_add.py +292 -0
  792. package/skills/ui-ux-pro-max/.claude/skills/ui-styling/scripts/tailwind_config_gen.py +456 -0
  793. package/skills/ui-ux-pro-max/.claude/skills/ui-styling/scripts/tests/coverage-ui.json +1 -0
  794. package/skills/ui-ux-pro-max/.claude/skills/ui-styling/scripts/tests/requirements.txt +3 -0
  795. package/skills/ui-ux-pro-max/.claude/skills/ui-styling/scripts/tests/test_shadcn_add.py +266 -0
  796. package/skills/ui-ux-pro-max/.claude/skills/ui-styling/scripts/tests/test_tailwind_config_gen.py +336 -0
  797. package/skills/ui-ux-pro-max/.claude/skills/ui-ux-pro-max/SKILL.md +659 -0
  798. package/skills/ui-ux-pro-max/.claude-plugin/marketplace.json +35 -0
  799. package/skills/ui-ux-pro-max/.claude-plugin/plugin.json +11 -0
  800. package/skills/ui-ux-pro-max/.github/workflows/claude-code-review.yml +44 -0
  801. package/skills/ui-ux-pro-max/.github/workflows/claude.yml +50 -0
  802. package/skills/ui-ux-pro-max/.github/workflows/python-package-conda.yml +34 -0
  803. package/skills/ui-ux-pro-max/CLAUDE.md +98 -0
  804. package/skills/ui-ux-pro-max/LICENSE +21 -0
  805. package/skills/ui-ux-pro-max/README.md +513 -0
  806. package/skills/ui-ux-pro-max/SKILL.md +292 -0
  807. package/skills/ui-ux-pro-max/cli/README.md +63 -0
  808. package/skills/ui-ux-pro-max/cli/assets/data/_sync_all.py +414 -0
  809. package/skills/ui-ux-pro-max/cli/assets/data/app-interface.csv +31 -0
  810. package/skills/ui-ux-pro-max/cli/assets/data/charts.csv +26 -0
  811. package/skills/ui-ux-pro-max/cli/assets/data/colors.csv +162 -0
  812. package/skills/ui-ux-pro-max/cli/assets/data/design.csv +1776 -0
  813. package/skills/ui-ux-pro-max/cli/assets/data/draft.csv +1779 -0
  814. package/skills/ui-ux-pro-max/cli/assets/data/google-fonts.csv +1924 -0
  815. package/skills/ui-ux-pro-max/cli/assets/data/icons.csv +105 -0
  816. package/skills/ui-ux-pro-max/cli/assets/data/landing.csv +31 -0
  817. package/skills/ui-ux-pro-max/cli/assets/data/products.csv +162 -0
  818. package/skills/ui-ux-pro-max/cli/assets/data/react-performance.csv +45 -0
  819. package/skills/ui-ux-pro-max/cli/assets/data/stacks/angular.csv +51 -0
  820. package/skills/ui-ux-pro-max/cli/assets/data/stacks/astro.csv +54 -0
  821. package/skills/ui-ux-pro-max/cli/assets/data/stacks/flutter.csv +53 -0
  822. package/skills/ui-ux-pro-max/cli/assets/data/stacks/html-tailwind.csv +56 -0
  823. package/skills/ui-ux-pro-max/cli/assets/data/stacks/jetpack-compose.csv +53 -0
  824. package/skills/ui-ux-pro-max/cli/assets/data/stacks/laravel.csv +51 -0
  825. package/skills/ui-ux-pro-max/cli/assets/data/stacks/nextjs.csv +53 -0
  826. package/skills/ui-ux-pro-max/cli/assets/data/stacks/nuxt-ui.csv +51 -0
  827. package/skills/ui-ux-pro-max/cli/assets/data/stacks/nuxtjs.csv +59 -0
  828. package/skills/ui-ux-pro-max/cli/assets/data/stacks/react-native.csv +52 -0
  829. package/skills/ui-ux-pro-max/cli/assets/data/stacks/react.csv +54 -0
  830. package/skills/ui-ux-pro-max/cli/assets/data/stacks/shadcn.csv +61 -0
  831. package/skills/ui-ux-pro-max/cli/assets/data/stacks/svelte.csv +54 -0
  832. package/skills/ui-ux-pro-max/cli/assets/data/stacks/swiftui.csv +51 -0
  833. package/skills/ui-ux-pro-max/cli/assets/data/stacks/threejs.csv +54 -0
  834. package/skills/ui-ux-pro-max/cli/assets/data/stacks/vue.csv +50 -0
  835. package/skills/ui-ux-pro-max/cli/assets/data/styles.csv +85 -0
  836. package/skills/ui-ux-pro-max/cli/assets/data/typography.csv +74 -0
  837. package/skills/ui-ux-pro-max/cli/assets/data/ui-reasoning.csv +162 -0
  838. package/skills/ui-ux-pro-max/cli/assets/data/ux-guidelines.csv +100 -0
  839. package/skills/ui-ux-pro-max/cli/assets/scripts/core.py +247 -0
  840. package/skills/ui-ux-pro-max/cli/assets/scripts/design_system.py +1148 -0
  841. package/skills/ui-ux-pro-max/cli/assets/scripts/search.py +114 -0
  842. package/skills/ui-ux-pro-max/cli/assets/templates/base/quick-reference.md +297 -0
  843. package/skills/ui-ux-pro-max/cli/assets/templates/base/skill-content.md +353 -0
  844. package/skills/ui-ux-pro-max/cli/assets/templates/platforms/agent.json +21 -0
  845. package/skills/ui-ux-pro-max/cli/assets/templates/platforms/augment.json +18 -0
  846. package/skills/ui-ux-pro-max/cli/assets/templates/platforms/claude.json +21 -0
  847. package/skills/ui-ux-pro-max/cli/assets/templates/platforms/codebuddy.json +21 -0
  848. package/skills/ui-ux-pro-max/cli/assets/templates/platforms/codex.json +21 -0
  849. package/skills/ui-ux-pro-max/cli/assets/templates/platforms/continue.json +21 -0
  850. package/skills/ui-ux-pro-max/cli/assets/templates/platforms/copilot.json +21 -0
  851. package/skills/ui-ux-pro-max/cli/assets/templates/platforms/cursor.json +21 -0
  852. package/skills/ui-ux-pro-max/cli/assets/templates/platforms/droid.json +21 -0
  853. package/skills/ui-ux-pro-max/cli/assets/templates/platforms/gemini.json +21 -0
  854. package/skills/ui-ux-pro-max/cli/assets/templates/platforms/kilocode.json +21 -0
  855. package/skills/ui-ux-pro-max/cli/assets/templates/platforms/kiro.json +21 -0
  856. package/skills/ui-ux-pro-max/cli/assets/templates/platforms/opencode.json +21 -0
  857. package/skills/ui-ux-pro-max/cli/assets/templates/platforms/qoder.json +21 -0
  858. package/skills/ui-ux-pro-max/cli/assets/templates/platforms/roocode.json +21 -0
  859. package/skills/ui-ux-pro-max/cli/assets/templates/platforms/trae.json +21 -0
  860. package/skills/ui-ux-pro-max/cli/assets/templates/platforms/warp.json +18 -0
  861. package/skills/ui-ux-pro-max/cli/assets/templates/platforms/windsurf.json +21 -0
  862. package/skills/ui-ux-pro-max/cli/bun.lock +77 -0
  863. package/skills/ui-ux-pro-max/cli/package-lock.json +370 -0
  864. package/skills/ui-ux-pro-max/cli/package.json +48 -0
  865. package/skills/ui-ux-pro-max/cli/src/commands/init.ts +216 -0
  866. package/skills/ui-ux-pro-max/cli/src/commands/uninstall.ts +135 -0
  867. package/skills/ui-ux-pro-max/cli/src/commands/update.ts +36 -0
  868. package/skills/ui-ux-pro-max/cli/src/commands/versions.ts +42 -0
  869. package/skills/ui-ux-pro-max/cli/src/index.ts +83 -0
  870. package/skills/ui-ux-pro-max/cli/src/types/index.ts +68 -0
  871. package/skills/ui-ux-pro-max/cli/src/utils/detect.ts +120 -0
  872. package/skills/ui-ux-pro-max/cli/src/utils/extract.ts +149 -0
  873. package/skills/ui-ux-pro-max/cli/src/utils/github.ts +104 -0
  874. package/skills/ui-ux-pro-max/cli/src/utils/logger.ts +11 -0
  875. package/skills/ui-ux-pro-max/cli/src/utils/template.ts +243 -0
  876. package/skills/ui-ux-pro-max/cli/tsconfig.json +17 -0
  877. package/skills/ui-ux-pro-max/data/charts.csv +26 -0
  878. package/skills/ui-ux-pro-max/data/colors.csv +97 -0
  879. package/skills/ui-ux-pro-max/data/icons.csv +101 -0
  880. package/skills/ui-ux-pro-max/data/landing.csv +31 -0
  881. package/skills/ui-ux-pro-max/data/products.csv +97 -0
  882. package/skills/ui-ux-pro-max/data/react-performance.csv +45 -0
  883. package/skills/ui-ux-pro-max/data/stacks/astro.csv +54 -0
  884. package/skills/ui-ux-pro-max/data/stacks/flutter.csv +53 -0
  885. package/skills/ui-ux-pro-max/data/stacks/html-tailwind.csv +56 -0
  886. package/skills/ui-ux-pro-max/data/stacks/jetpack-compose.csv +53 -0
  887. package/skills/ui-ux-pro-max/data/stacks/nextjs.csv +53 -0
  888. package/skills/ui-ux-pro-max/data/stacks/nuxt-ui.csv +51 -0
  889. package/skills/ui-ux-pro-max/data/stacks/nuxtjs.csv +59 -0
  890. package/skills/ui-ux-pro-max/data/stacks/react-native.csv +52 -0
  891. package/skills/ui-ux-pro-max/data/stacks/react.csv +54 -0
  892. package/skills/ui-ux-pro-max/data/stacks/shadcn.csv +61 -0
  893. package/skills/ui-ux-pro-max/data/stacks/svelte.csv +54 -0
  894. package/skills/ui-ux-pro-max/data/stacks/swiftui.csv +51 -0
  895. package/skills/ui-ux-pro-max/data/stacks/vue.csv +50 -0
  896. package/skills/ui-ux-pro-max/data/styles.csv +68 -0
  897. package/skills/ui-ux-pro-max/data/typography.csv +58 -0
  898. package/skills/ui-ux-pro-max/data/ui-reasoning.csv +101 -0
  899. package/skills/ui-ux-pro-max/data/ux-guidelines.csv +100 -0
  900. package/skills/ui-ux-pro-max/data/web-interface.csv +31 -0
  901. package/skills/ui-ux-pro-max/docs//344/270/211/344/270/252 data-scripts-templates /347/232/204/345/214/272/345/210/253.md" +30 -0
  902. package/skills/ui-ux-pro-max/preview/xiaomaomi-app.html +411 -0
  903. package/skills/ui-ux-pro-max/screenshots/website.png +0 -0
  904. package/skills/ui-ux-pro-max/scripts/core.py +253 -0
  905. package/skills/ui-ux-pro-max/scripts/design_system.py +1067 -0
  906. package/skills/ui-ux-pro-max/scripts/search.py +114 -0
  907. package/skills/ui-ux-pro-max/skill.json +41 -0
  908. package/skills/ui-ux-pro-max/src/ui-ux-pro-max/data/_sync_all.py +414 -0
  909. package/skills/ui-ux-pro-max/src/ui-ux-pro-max/data/app-interface.csv +31 -0
  910. package/skills/ui-ux-pro-max/src/ui-ux-pro-max/data/charts.csv +26 -0
  911. package/skills/ui-ux-pro-max/src/ui-ux-pro-max/data/colors.csv +162 -0
  912. package/skills/ui-ux-pro-max/src/ui-ux-pro-max/data/design.csv +1776 -0
  913. package/skills/ui-ux-pro-max/src/ui-ux-pro-max/data/draft.csv +1779 -0
  914. package/skills/ui-ux-pro-max/src/ui-ux-pro-max/data/google-fonts.csv +1924 -0
  915. package/skills/ui-ux-pro-max/src/ui-ux-pro-max/data/icons.csv +106 -0
  916. package/skills/ui-ux-pro-max/src/ui-ux-pro-max/data/landing.csv +35 -0
  917. package/skills/ui-ux-pro-max/src/ui-ux-pro-max/data/products.csv +162 -0
  918. package/skills/ui-ux-pro-max/src/ui-ux-pro-max/data/react-performance.csv +45 -0
  919. package/skills/ui-ux-pro-max/src/ui-ux-pro-max/data/stacks/angular.csv +51 -0
  920. package/skills/ui-ux-pro-max/src/ui-ux-pro-max/data/stacks/astro.csv +54 -0
  921. package/skills/ui-ux-pro-max/src/ui-ux-pro-max/data/stacks/flutter.csv +53 -0
  922. package/skills/ui-ux-pro-max/src/ui-ux-pro-max/data/stacks/html-tailwind.csv +56 -0
  923. package/skills/ui-ux-pro-max/src/ui-ux-pro-max/data/stacks/jetpack-compose.csv +53 -0
  924. package/skills/ui-ux-pro-max/src/ui-ux-pro-max/data/stacks/laravel.csv +51 -0
  925. package/skills/ui-ux-pro-max/src/ui-ux-pro-max/data/stacks/nextjs.csv +53 -0
  926. package/skills/ui-ux-pro-max/src/ui-ux-pro-max/data/stacks/nuxt-ui.csv +51 -0
  927. package/skills/ui-ux-pro-max/src/ui-ux-pro-max/data/stacks/nuxtjs.csv +59 -0
  928. package/skills/ui-ux-pro-max/src/ui-ux-pro-max/data/stacks/react-native.csv +52 -0
  929. package/skills/ui-ux-pro-max/src/ui-ux-pro-max/data/stacks/react.csv +54 -0
  930. package/skills/ui-ux-pro-max/src/ui-ux-pro-max/data/stacks/shadcn.csv +61 -0
  931. package/skills/ui-ux-pro-max/src/ui-ux-pro-max/data/stacks/svelte.csv +54 -0
  932. package/skills/ui-ux-pro-max/src/ui-ux-pro-max/data/stacks/swiftui.csv +51 -0
  933. package/skills/ui-ux-pro-max/src/ui-ux-pro-max/data/stacks/threejs.csv +54 -0
  934. package/skills/ui-ux-pro-max/src/ui-ux-pro-max/data/stacks/vue.csv +50 -0
  935. package/skills/ui-ux-pro-max/src/ui-ux-pro-max/data/styles.csv +85 -0
  936. package/skills/ui-ux-pro-max/src/ui-ux-pro-max/data/typography.csv +74 -0
  937. package/skills/ui-ux-pro-max/src/ui-ux-pro-max/data/ui-reasoning.csv +162 -0
  938. package/skills/ui-ux-pro-max/src/ui-ux-pro-max/data/ux-guidelines.csv +100 -0
  939. package/skills/ui-ux-pro-max/src/ui-ux-pro-max/scripts/core.py +262 -0
  940. package/skills/ui-ux-pro-max/src/ui-ux-pro-max/scripts/design_system.py +1148 -0
  941. package/skills/ui-ux-pro-max/src/ui-ux-pro-max/scripts/search.py +114 -0
  942. package/skills/ui-ux-pro-max/src/ui-ux-pro-max/templates/base/quick-reference.md +297 -0
  943. package/skills/ui-ux-pro-max/src/ui-ux-pro-max/templates/base/skill-content.md +358 -0
  944. package/skills/ui-ux-pro-max/src/ui-ux-pro-max/templates/platforms/agent.json +21 -0
  945. package/skills/ui-ux-pro-max/src/ui-ux-pro-max/templates/platforms/augment.json +18 -0
  946. package/skills/ui-ux-pro-max/src/ui-ux-pro-max/templates/platforms/claude.json +21 -0
  947. package/skills/ui-ux-pro-max/src/ui-ux-pro-max/templates/platforms/codebuddy.json +21 -0
  948. package/skills/ui-ux-pro-max/src/ui-ux-pro-max/templates/platforms/codex.json +21 -0
  949. package/skills/ui-ux-pro-max/src/ui-ux-pro-max/templates/platforms/continue.json +21 -0
  950. package/skills/ui-ux-pro-max/src/ui-ux-pro-max/templates/platforms/copilot.json +21 -0
  951. package/skills/ui-ux-pro-max/src/ui-ux-pro-max/templates/platforms/cursor.json +21 -0
  952. package/skills/ui-ux-pro-max/src/ui-ux-pro-max/templates/platforms/droid.json +21 -0
  953. package/skills/ui-ux-pro-max/src/ui-ux-pro-max/templates/platforms/gemini.json +21 -0
  954. package/skills/ui-ux-pro-max/src/ui-ux-pro-max/templates/platforms/kilocode.json +21 -0
  955. package/skills/ui-ux-pro-max/src/ui-ux-pro-max/templates/platforms/kiro.json +21 -0
  956. package/skills/ui-ux-pro-max/src/ui-ux-pro-max/templates/platforms/opencode.json +21 -0
  957. package/skills/ui-ux-pro-max/src/ui-ux-pro-max/templates/platforms/qoder.json +21 -0
  958. package/skills/ui-ux-pro-max/src/ui-ux-pro-max/templates/platforms/roocode.json +21 -0
  959. package/skills/ui-ux-pro-max/src/ui-ux-pro-max/templates/platforms/trae.json +21 -0
  960. package/skills/ui-ux-pro-max/src/ui-ux-pro-max/templates/platforms/warp.json +18 -0
  961. package/skills/ui-ux-pro-max/src/ui-ux-pro-max/templates/platforms/windsurf.json +21 -0
  962. package/skills/uncloud/SKILL.md +343 -0
  963. package/skills/upgrading-react-native/SKILL.md +58 -0
  964. package/skills/using-git-worktrees/SKILL.md +215 -0
  965. package/skills/vercel/SKILL.md +161 -0
  966. package/skills/vercel/metadata.json +16 -0
  967. package/skills/verification-loop/SKILL.md +126 -0
  968. package/skills/view-transitions-api/SKILL.md +108 -0
  969. package/skills/vite-patterns/SKILL.md +449 -0
  970. package/skills/vue3-composition-patterns/SKILL.md +375 -0
  971. package/skills/waza-habits/SKILL.md +22 -0
  972. package/skills/webapp-testing/LICENSE.txt +202 -0
  973. package/skills/webapp-testing/SKILL.md +96 -0
  974. package/skills/webapp-testing/examples/console_logging.py +35 -0
  975. package/skills/webapp-testing/examples/element_discovery.py +40 -0
  976. package/skills/webapp-testing/examples/static_html_automation.py +33 -0
  977. package/skills/webapp-testing/scripts/with_server.py +106 -0
  978. package/src/orchestrator/builder.ts +234 -0
  979. package/src/orchestrator/executor.ts +386 -0
  980. package/src/orchestrator/index.ts +535 -0
  981. package/src/orchestrator/loader.ts +237 -0
  982. package/src/orchestrator/registry.ts +211 -0
  983. package/src/orchestrator/schema.ts +141 -0
  984. package/src/orchestrator/session.ts +128 -0
  985. package/src/orchestrator/types.ts +109 -0
  986. package/tsconfig.json +21 -0
@@ -0,0 +1,1111 @@
1
+ # Direct LLM backend for semantic extraction — supports Claude, Kimi K2.6,
2
+ # Gemini, and OpenAI.
3
+ # Used by `graphify extract . --backend gemini` and the benchmark scripts.
4
+ # The default graphify pipeline uses Claude Code subagents via skill.md;
5
+ # this module provides a direct API path for non-Claude-Code environments.
6
+ from __future__ import annotations
7
+
8
+ import json
9
+ import os
10
+ import sys
11
+ import time
12
+ from collections.abc import Callable
13
+ from concurrent.futures import ThreadPoolExecutor, as_completed
14
+ from pathlib import Path
15
+
16
+ # `_read_files` truncates each file at this many characters before joining into
17
+ # the user message. Token estimates use the same cap so packing matches reality.
18
+ _FILE_CHAR_CAP = 20_000
19
+ # `_read_files` also wraps each file in a `=== {rel} ===\n...\n\n` separator;
20
+ # this is roughly the per-file overhead in characters that the prompt adds.
21
+ _PER_FILE_OVERHEAD_CHARS = 80
22
+ # Coarse fallback used only when `tiktoken` is not installed. 1 token ≈ 4 chars
23
+ # is the standard heuristic for English/code on BPE tokenizers.
24
+ _CHARS_PER_TOKEN = 4
25
+
26
+
27
+ def _get_tokenizer():
28
+ """Return a tiktoken encoder for accurate token counts, or None if tiktoken
29
+ is not installed. We use `cl100k_base` (GPT-4 / GPT-3.5-turbo) as a proxy:
30
+ Kimi-K2 ships a tiktoken-based tokenizer with very similar BPE behaviour,
31
+ and Claude's tokenizer has a comparable token-to-char ratio for prose/code.
32
+ Estimates only need to be within ~5%, not exact.
33
+ """
34
+ try:
35
+ import tiktoken
36
+ except ImportError:
37
+ return None
38
+ try:
39
+ return tiktoken.get_encoding("cl100k_base")
40
+ except Exception: # network failure on first-use download, etc.
41
+ return None
42
+
43
+
44
+ # Cached at import time. None if tiktoken is unavailable; consumers must handle.
45
+ _TOKENIZER = _get_tokenizer()
46
+
47
+ BACKENDS: dict[str, dict] = {
48
+ "claude": {
49
+ "base_url": "https://api.anthropic.com",
50
+ "default_model": "claude-sonnet-4-6",
51
+ "env_key": "ANTHROPIC_API_KEY",
52
+ "pricing": {"input": 3.0, "output": 15.0}, # USD per 1M tokens
53
+ "temperature": 0,
54
+ "max_tokens": 16384,
55
+ },
56
+ "kimi": {
57
+ "base_url": "https://api.moonshot.ai/v1",
58
+ "default_model": "kimi-k2.6",
59
+ "env_key": "MOONSHOT_API_KEY",
60
+ "pricing": {"input": 0.74, "output": 4.66}, # USD per 1M tokens
61
+ "temperature": None, # kimi-k2.6 enforces its own fixed temperature; sending any value raises 400
62
+ "max_tokens": 16384,
63
+ },
64
+ "ollama": {
65
+ "base_url": os.environ.get("OLLAMA_BASE_URL", "http://localhost:11434/v1"),
66
+ "default_model": os.environ.get("OLLAMA_MODEL", "qwen2.5-coder:7b"),
67
+ "env_key": "OLLAMA_API_KEY",
68
+ "pricing": {"input": 0.0, "output": 0.0},
69
+ "temperature": 0,
70
+ "max_tokens": 16384,
71
+ },
72
+ "gemini": {
73
+ "base_url": "https://generativelanguage.googleapis.com/v1beta/openai/",
74
+ "default_model": "gemini-3-flash-preview",
75
+ "env_keys": ["GEMINI_API_KEY", "GOOGLE_API_KEY"],
76
+ "model_env_key": "GRAPHIFY_GEMINI_MODEL",
77
+ "pricing": {"input": 0.50, "output": 3.00}, # USD per 1M tokens
78
+ "temperature": 0,
79
+ "reasoning_effort": "low",
80
+ "max_completion_tokens": 16384,
81
+ },
82
+ "openai": {
83
+ "base_url": "https://api.openai.com/v1",
84
+ "default_model": "gpt-4.1-mini",
85
+ "env_key": "OPENAI_API_KEY",
86
+ "model_env_key": "GRAPHIFY_OPENAI_MODEL",
87
+ "pricing": {"input": 0.40, "output": 1.60}, # USD per 1M tokens
88
+ "temperature": 0,
89
+ },
90
+ "deepseek": {
91
+ "base_url": "https://api.deepseek.com",
92
+ "default_model": "deepseek-v4-flash",
93
+ "env_key": "DEEPSEEK_API_KEY",
94
+ "model_env_key": "GRAPHIFY_DEEPSEEK_MODEL",
95
+ "pricing": {"input": 0.14, "output": 0.28}, # USD per 1M tokens (v4-flash)
96
+ # deepseek-reasoner / thinking-mode models silently ignore temperature;
97
+ # deepseek-chat / v4-flash (non-thinking) accept 0-2. Safe to send 0.
98
+ "temperature": 0,
99
+ "max_tokens": 16384,
100
+ },
101
+ "bedrock": {
102
+ "default_model": "anthropic.claude-3-5-sonnet-20241022-v2:0",
103
+ "model_env_key": "GRAPHIFY_BEDROCK_MODEL",
104
+ "pricing": {"input": 3.0, "output": 15.0}, # USD per 1M tokens
105
+ "temperature": 0,
106
+ "max_tokens": 16384,
107
+ },
108
+ "claude-cli": {
109
+ # Routes through the locally-installed `claude` CLI (Claude Code) using
110
+ # `-p --output-format json`. Authenticates via the user's existing
111
+ # Pro/Max subscription instead of a separate ANTHROPIC_API_KEY — costs
112
+ # are billed to the plan, not pay-as-you-go API credit.
113
+ "default_model": "claude-code-plan",
114
+ "pricing": {"input": 0.0, "output": 0.0},
115
+ "temperature": 0,
116
+ "max_tokens": 16384,
117
+ },
118
+ }
119
+
120
+
121
+ def _resolve_max_tokens(default: int) -> int:
122
+ """Honour GRAPHIFY_MAX_OUTPUT_TOKENS env var override, else use backend default."""
123
+ raw = os.environ.get("GRAPHIFY_MAX_OUTPUT_TOKENS", "").strip()
124
+ if raw:
125
+ try:
126
+ v = int(raw)
127
+ if v > 0:
128
+ return v
129
+ except ValueError:
130
+ pass
131
+ return default
132
+
133
+ _EXTRACTION_SYSTEM = """\
134
+ You are a graphify semantic extraction agent. Extract a knowledge graph fragment from the files provided.
135
+ Output ONLY valid JSON — no explanation, no markdown fences, no preamble.
136
+
137
+ Rules:
138
+ - EXTRACTED: relationship explicit in source (import, call, citation, reference)
139
+ - INFERRED: reasonable inference (shared data structure, implied dependency)
140
+ - AMBIGUOUS: uncertain — flag for review, do not omit
141
+
142
+ Node ID format: lowercase, only [a-z0-9_], no dots or slashes.
143
+ Format: {stem}_{entity} where stem = filename without extension, entity = symbol name (both normalised).
144
+
145
+ Output exactly this schema:
146
+ {"nodes":[{"id":"stem_entity","label":"Human Readable Name","file_type":"code|document|paper|image|rationale|concept","source_file":"relative/path","source_location":null,"source_url":null,"captured_at":null,"author":null,"contributor":null}],"edges":[{"source":"node_id","target":"node_id","relation":"calls|implements|references|cites|conceptually_related_to|shares_data_with|semantically_similar_to","confidence":"EXTRACTED|INFERRED|AMBIGUOUS","confidence_score":1.0,"source_file":"relative/path","source_location":null,"weight":1.0}],"hyperedges":[],"input_tokens":0,"output_tokens":0}
147
+ """
148
+
149
+
150
+ def _read_files(paths: list[Path], root: Path) -> str:
151
+ """Return file contents formatted for the extraction prompt."""
152
+ parts: list[str] = []
153
+ for p in paths:
154
+ try:
155
+ rel = p.relative_to(root)
156
+ except ValueError:
157
+ rel = p
158
+ try:
159
+ content = p.read_text(encoding="utf-8", errors="replace")
160
+ except OSError:
161
+ continue
162
+ parts.append(f"=== {rel} ===\n{content[:20000]}")
163
+ return "\n\n".join(parts)
164
+
165
+
166
+ _LLM_JSON_MAX_BYTES = 10 * 1024 * 1024 # 10 MB hard cap before json.loads (F-016)
167
+
168
+
169
+ def _parse_llm_json(raw: str) -> dict:
170
+ """Strip optional markdown fences and parse JSON. Returns empty fragment on failure.
171
+
172
+ Caps the input at `_LLM_JSON_MAX_BYTES` so a hostile or runaway model
173
+ response cannot exhaust memory inside `json.loads` (F-016).
174
+ """
175
+ if len(raw) > _LLM_JSON_MAX_BYTES:
176
+ print(
177
+ f"[graphify] LLM response exceeds {_LLM_JSON_MAX_BYTES} bytes "
178
+ f"({len(raw)} bytes); refusing to parse and dropping chunk.",
179
+ file=sys.stderr,
180
+ )
181
+ return {"nodes": [], "edges": [], "hyperedges": []}
182
+ if raw.startswith("```"):
183
+ raw = raw.split("```", 2)[1]
184
+ if raw.startswith("json"):
185
+ raw = raw[4:]
186
+ raw = raw.rsplit("```", 1)[0]
187
+ try:
188
+ return json.loads(raw.strip())
189
+ except json.JSONDecodeError as exc:
190
+ print(f"[graphify] LLM returned invalid JSON, skipping chunk: {exc}", file=sys.stderr)
191
+ return {"nodes": [], "edges": [], "hyperedges": []}
192
+
193
+
194
+ def _response_is_hollow(raw_content: str | None, parsed: dict) -> bool:
195
+ """Detect a successful HTTP response that yielded no usable extraction.
196
+
197
+ A local model under load (most often Ollama) can return HTTP 200 with an
198
+ empty / null `message.content`, with whitespace, or with a half-generated
199
+ JSON prefix that fails to parse. All of these collapse to a "successful"
200
+ call producing zero nodes and zero edges. Without this check the chunk
201
+ is silently dropped from the corpus because no exception is raised and
202
+ `finish_reason` is `"stop"` rather than `"length"`. By flagging the
203
+ result as hollow, callers can re-route it through the same bisection
204
+ path used for context-window overflow and `finish_reason="length"`.
205
+ """
206
+ if raw_content is None or not raw_content.strip():
207
+ return True
208
+ nodes = parsed.get("nodes")
209
+ edges = parsed.get("edges")
210
+ hyperedges = parsed.get("hyperedges")
211
+ return not nodes and not edges and not hyperedges
212
+
213
+
214
+ def _backend_env_keys(backend: str) -> list[str]:
215
+ """Return accepted API-key environment variables for a backend."""
216
+ cfg = BACKENDS[backend]
217
+ keys = cfg.get("env_keys")
218
+ if keys:
219
+ return list(keys)
220
+ env_key = cfg.get("env_key")
221
+ if env_key:
222
+ return [env_key]
223
+ return []
224
+
225
+
226
+ def _get_backend_api_key(backend: str) -> str:
227
+ """Return the first configured API key for backend, or an empty string."""
228
+ for env_key in _backend_env_keys(backend):
229
+ value = os.environ.get(env_key)
230
+ if value:
231
+ return value
232
+ return ""
233
+
234
+
235
+ def _format_backend_env_keys(backend: str) -> str:
236
+ """Return user-facing accepted API-key variable names."""
237
+ keys = _backend_env_keys(backend)
238
+ return " or ".join(keys) if keys else "AWS_PROFILE or AWS_REGION"
239
+
240
+
241
+ def _default_model_for_backend(backend: str) -> str:
242
+ """Return configured model override or backend default model."""
243
+ cfg = BACKENDS[backend]
244
+ model_env_key = cfg.get("model_env_key")
245
+ if model_env_key:
246
+ model = os.environ.get(model_env_key)
247
+ if model:
248
+ return model
249
+ return cfg["default_model"]
250
+
251
+
252
+ def _call_openai_compat(
253
+ base_url: str,
254
+ api_key: str,
255
+ model: str,
256
+ user_message: str,
257
+ temperature: float | None = 0,
258
+ reasoning_effort: str | None = None,
259
+ max_completion_tokens: int = 8192,
260
+ *,
261
+ backend: str = "",
262
+ ) -> dict:
263
+ """Call any OpenAI-compatible API (Kimi, OpenAI, etc.) and return parsed JSON."""
264
+ try:
265
+ from openai import OpenAI
266
+ except ImportError as exc:
267
+ pkg_hint = "graphifyy[kimi]" if backend == "kimi" else "openai"
268
+ raise ImportError(
269
+ "Gemini/Kimi/Ollama/OpenAI-compatible extraction requires the openai package. "
270
+ f"Run: pip install {pkg_hint}"
271
+ ) from exc
272
+
273
+ # Local backends (ollama, llama.cpp, vLLM) routinely take >60s for a
274
+ # single chunk on a large model — far longer than the openai SDK's
275
+ # default. Honour GRAPHIFY_API_TIMEOUT (seconds) for explicit override;
276
+ # default to 600s, which is long enough for a 31B model on a 16k chunk
277
+ # but still bounds runaway connections (issue #792 addendum).
278
+ timeout_raw = os.environ.get("GRAPHIFY_API_TIMEOUT", "").strip()
279
+ timeout_s: float = 600.0
280
+ if timeout_raw:
281
+ try:
282
+ v = float(timeout_raw)
283
+ if v > 0:
284
+ timeout_s = v
285
+ except ValueError:
286
+ pass
287
+ client = OpenAI(api_key=api_key, base_url=base_url, timeout=timeout_s)
288
+ kwargs: dict = {
289
+ "model": model,
290
+ "messages": [
291
+ {"role": "system", "content": _EXTRACTION_SYSTEM},
292
+ {"role": "user", "content": user_message},
293
+ ],
294
+ "max_completion_tokens": max_completion_tokens,
295
+ }
296
+ if temperature is not None:
297
+ kwargs["temperature"] = temperature
298
+ if reasoning_effort is not None:
299
+ kwargs["reasoning_effort"] = reasoning_effort
300
+ # Kimi-k2.6 is a reasoning model — disable thinking so content isn't empty
301
+ if "moonshot" in base_url:
302
+ kwargs["extra_body"] = {"thinking": {"type": "disabled"}}
303
+ # Ollama defaults num_ctx to 2048 and silently truncates prompts larger
304
+ # than that — the symptom is hollow 200 OK responses after the first few
305
+ # chunks (#798). We derive num_ctx from the actual prompt size so we don't
306
+ # over-allocate KV-cache VRAM. Over-allocation (e.g. 128k slots for an 8k
307
+ # prompt on a 31B model) exhausts VRAM by chunk 4 and produces the same
308
+ # hollow-200 symptom — just from a different direction (#798 follow-up).
309
+ # Formula: actual input tokens + output cap + system prompt headroom.
310
+ # Capped at 131072 (enough for the default 60k token_budget); env var wins.
311
+ if backend == "ollama":
312
+ num_ctx_raw = os.environ.get("GRAPHIFY_OLLAMA_NUM_CTX", "").strip()
313
+ # Auto-derive num_ctx from actual chunk size regardless — used as the
314
+ # fallback and for the mismatch check below.
315
+ estimated_input = len(user_message) // _CHARS_PER_TOKEN + 400
316
+ auto_num_ctx = min(estimated_input + max_completion_tokens + 2000, 131072)
317
+ auto_num_ctx = max(auto_num_ctx, 8192)
318
+ if num_ctx_raw:
319
+ try:
320
+ num_ctx = int(num_ctx_raw)
321
+ except ValueError:
322
+ # Bad env var: fall through to auto-derivation (not 131072 —
323
+ # hardcoding the cap is what causes OOM on constrained VRAM).
324
+ print(
325
+ f"[graphify] GRAPHIFY_OLLAMA_NUM_CTX={num_ctx_raw!r} is not a valid integer; "
326
+ f"using auto-derived value ({auto_num_ctx}).",
327
+ file=sys.stderr,
328
+ )
329
+ num_ctx = auto_num_ctx
330
+ else:
331
+ # Warn when the pinned value is smaller than the estimated input —
332
+ # Ollama silently truncates the prompt and returns empty responses.
333
+ if num_ctx < estimated_input:
334
+ print(
335
+ f"[graphify] warning: GRAPHIFY_OLLAMA_NUM_CTX={num_ctx} is smaller than "
336
+ f"the estimated chunk input (~{estimated_input} tokens). Ollama will "
337
+ f"silently truncate the prompt and return empty responses. "
338
+ f"Try --token-budget {max(1024, num_ctx // 3)} or increase NUM_CTX.",
339
+ file=sys.stderr,
340
+ )
341
+ else:
342
+ # Estimate input tokens: user_message chars / 4 (standard BPE
343
+ # heuristic) + 400 for the system prompt, then add output headroom.
344
+ num_ctx = auto_num_ctx
345
+ keep_alive = os.environ.get("GRAPHIFY_OLLAMA_KEEP_ALIVE", "30m")
346
+ kwargs["extra_body"] = {"options": {"num_ctx": num_ctx}, "keep_alive": keep_alive}
347
+ resp = client.chat.completions.create(**kwargs)
348
+ if not resp.choices or resp.choices[0].message is None:
349
+ raise ValueError("LLM returned empty or filtered response")
350
+ raw_content = resp.choices[0].message.content
351
+ result = _parse_llm_json(raw_content or "{}")
352
+ result["input_tokens"] = resp.usage.prompt_tokens if resp.usage else 0
353
+ result["output_tokens"] = resp.usage.completion_tokens if resp.usage else 0
354
+ result["model"] = model
355
+ # `finish_reason == "length"` means the model hit max_completion_tokens
356
+ # mid-generation. The JSON we got back is truncated; callers should
357
+ # treat this as a signal to retry with smaller input.
358
+ result["finish_reason"] = resp.choices[0].finish_reason
359
+ # An overwhelmed local model (typically Ollama) can return HTTP 200 with
360
+ # empty / null content or unparseable half-generated JSON. The call looks
361
+ # successful, `finish_reason` is `"stop"`, and the chunk would be silently
362
+ # dropped from the corpus. Re-label as `"length"` so the adaptive retry
363
+ # layer bisects the chunk — same recovery as a true truncation.
364
+ if _response_is_hollow(raw_content, result) and result["finish_reason"] != "length":
365
+ print(
366
+ f"[graphify] {backend or 'backend'} returned a hollow response "
367
+ f"(content={'empty' if not (raw_content or '').strip() else 'no nodes/edges'}, "
368
+ f"output_tokens={result['output_tokens']}); "
369
+ "treating as truncation so adaptive retry can bisect the chunk.",
370
+ file=sys.stderr,
371
+ )
372
+ result["finish_reason"] = "length"
373
+ output_tokens = result["output_tokens"]
374
+ if output_tokens < 50 and backend == "ollama":
375
+ print(
376
+ "[graphify] warning: ollama returned very few tokens — likely causes: "
377
+ "(1) VRAM pressure: check `nvidia-smi` and reduce chunk size with "
378
+ "--token-budget (e.g. --token-budget 4096) or set "
379
+ "GRAPHIFY_OLLAMA_NUM_CTX to a smaller value; "
380
+ "(2) model too small for JSON instruction following — "
381
+ "try a larger model with --model (e.g. --model qwen2.5-coder:14b).",
382
+ file=sys.stderr,
383
+ )
384
+ return result
385
+
386
+
387
+ def _call_claude(api_key: str, model: str, user_message: str, max_tokens: int = 8192) -> dict:
388
+ """Call Anthropic Claude directly (not via OpenAI compat layer)."""
389
+ try:
390
+ import anthropic
391
+ except ImportError as exc:
392
+ raise ImportError(
393
+ "Claude direct extraction requires the anthropic package. "
394
+ "Run: pip install anthropic"
395
+ ) from exc
396
+
397
+ client = anthropic.Anthropic(api_key=api_key)
398
+ resp = client.messages.create(
399
+ model=model,
400
+ max_tokens=max_tokens,
401
+ system=_EXTRACTION_SYSTEM,
402
+ messages=[{"role": "user", "content": user_message}],
403
+ )
404
+ raw_content = resp.content[0].text if resp.content else None
405
+ result = _parse_llm_json(raw_content or "{}")
406
+ result["input_tokens"] = resp.usage.input_tokens if resp.usage else 0
407
+ result["output_tokens"] = resp.usage.output_tokens if resp.usage else 0
408
+ result["model"] = model
409
+ # Normalise Anthropic's `stop_reason` to the OpenAI-compat `finish_reason`
410
+ # vocabulary so the adaptive-retry layer doesn't have to know which
411
+ # backend produced the result.
412
+ result["finish_reason"] = "length" if resp.stop_reason == "max_tokens" else "stop"
413
+ if _response_is_hollow(raw_content, result) and result["finish_reason"] != "length":
414
+ print(
415
+ "[graphify] claude returned a hollow response; treating as "
416
+ "truncation so adaptive retry can bisect the chunk.",
417
+ file=sys.stderr,
418
+ )
419
+ result["finish_reason"] = "length"
420
+ return result
421
+
422
+
423
+ def _call_claude_cli(user_message: str, max_tokens: int = 8192) -> dict:
424
+ """Call Claude via the locally-installed Claude Code CLI (`claude -p`).
425
+
426
+ Routes through the user's Claude Code subscription auth instead of a separate
427
+ ANTHROPIC_API_KEY. Useful for Pro/Max subscribers who don't want to provision
428
+ a pay-as-you-go API key just to run graphify's semantic pass.
429
+ """
430
+ import shutil
431
+ import subprocess
432
+
433
+ if shutil.which("claude") is None:
434
+ raise RuntimeError(
435
+ "Claude Code CLI not found on $PATH. Install from "
436
+ "https://claude.ai/code and run `claude` once to authenticate."
437
+ )
438
+
439
+ proc = subprocess.run(
440
+ [
441
+ "claude", "-p",
442
+ "--output-format", "json",
443
+ "--no-session-persistence",
444
+ "--append-system-prompt", _EXTRACTION_SYSTEM,
445
+ ],
446
+ input=user_message,
447
+ capture_output=True,
448
+ text=True,
449
+ encoding="utf-8", # Force UTF-8 — prevents UnicodeEncodeError on Windows cp1252
450
+ timeout=600,
451
+ check=False,
452
+ )
453
+ if proc.returncode != 0:
454
+ raise RuntimeError(
455
+ f"claude -p exited {proc.returncode}: {proc.stderr.strip()[:500]}"
456
+ )
457
+
458
+ try:
459
+ envelope = json.loads(proc.stdout)
460
+ except json.JSONDecodeError as exc:
461
+ raise RuntimeError(
462
+ f"claude -p produced unparseable JSON envelope: {exc}; "
463
+ f"first 500 chars of stdout: {proc.stdout[:500]!r}"
464
+ ) from exc
465
+
466
+ raw_content = envelope.get("result", "")
467
+ result = _parse_llm_json(raw_content or "{}")
468
+ usage = envelope.get("usage") or {}
469
+ result["input_tokens"] = (
470
+ int(usage.get("input_tokens", 0) or 0)
471
+ + int(usage.get("cache_read_input_tokens", 0) or 0)
472
+ + int(usage.get("cache_creation_input_tokens", 0) or 0)
473
+ )
474
+ result["output_tokens"] = int(usage.get("output_tokens", 0) or 0)
475
+ model_usage = envelope.get("modelUsage") or {}
476
+ result["model"] = next(iter(model_usage), "claude-code-plan")
477
+ stop_reason = envelope.get("stop_reason", "")
478
+ result["finish_reason"] = "length" if stop_reason == "max_tokens" else "stop"
479
+ if _response_is_hollow(raw_content, result) and result["finish_reason"] != "length":
480
+ print(
481
+ "[graphify] claude-cli returned a hollow response; treating as "
482
+ "truncation so adaptive retry can bisect the chunk.",
483
+ file=sys.stderr,
484
+ )
485
+ result["finish_reason"] = "length"
486
+ return result
487
+
488
+
489
+ def _call_bedrock(model: str, user_message: str, max_tokens: int = 8192) -> dict:
490
+ """Call AWS Bedrock via boto3 Converse API using the standard AWS credential chain."""
491
+ try:
492
+ import boto3
493
+ import botocore.exceptions
494
+ except ImportError as exc:
495
+ raise ImportError(
496
+ "AWS Bedrock extraction requires boto3. Run: pip install graphifyy[bedrock]"
497
+ ) from exc
498
+
499
+ region = os.environ.get("AWS_REGION") or os.environ.get("AWS_DEFAULT_REGION") or "us-east-1"
500
+ profile = os.environ.get("AWS_PROFILE")
501
+ session = boto3.Session(profile_name=profile, region_name=region)
502
+ client = session.client("bedrock-runtime")
503
+
504
+ try:
505
+ resp = client.converse(
506
+ modelId=model,
507
+ system=[{"text": _EXTRACTION_SYSTEM}],
508
+ messages=[{"role": "user", "content": [{"text": user_message}]}],
509
+ inferenceConfig={"maxTokens": max_tokens, "temperature": 0},
510
+ )
511
+ except botocore.exceptions.ClientError as exc:
512
+ code = exc.response["Error"]["Code"]
513
+ msg = exc.response["Error"]["Message"]
514
+ raise RuntimeError(f"Bedrock API error ({code}): {msg}") from exc
515
+
516
+ text = resp.get("output", {}).get("message", {}).get("content", [{}])[0].get("text", "{}")
517
+ result = _parse_llm_json(text)
518
+ usage = resp.get("usage", {})
519
+ result["input_tokens"] = usage.get("inputTokens", 0)
520
+ result["output_tokens"] = usage.get("outputTokens", 0)
521
+ result["model"] = model
522
+ result["finish_reason"] = "length" if resp.get("stopReason") == "max_tokens" else "stop"
523
+ if _response_is_hollow(text, result) and result["finish_reason"] != "length":
524
+ print(
525
+ "[graphify] bedrock returned a hollow response; treating as "
526
+ "truncation so adaptive retry can bisect the chunk.",
527
+ file=sys.stderr,
528
+ )
529
+ result["finish_reason"] = "length"
530
+ return result
531
+
532
+
533
+ def extract_files_direct(
534
+ files: list[Path],
535
+ backend: str = "kimi",
536
+ api_key: str | None = None,
537
+ model: str | None = None,
538
+ root: Path = Path("."),
539
+ ) -> dict:
540
+ """Extract semantic nodes/edges from a list of files using the given backend.
541
+
542
+ Returns dict with nodes, edges, hyperedges, input_tokens, output_tokens.
543
+ Raises ValueError for unknown backends. Raises ImportError if SDK missing.
544
+ """
545
+ if backend not in BACKENDS:
546
+ raise ValueError(f"Unknown backend {backend!r}. Available: {sorted(BACKENDS)}")
547
+
548
+ cfg = BACKENDS[backend]
549
+ key = api_key or _get_backend_api_key(backend)
550
+ if not key and backend == "ollama":
551
+ # Ollama ignores auth but the OpenAI client library requires a non-empty
552
+ # string. Use a placeholder and surface a visible warning so this never
553
+ # silently routes traffic without the user realising — see F-029.
554
+ ollama_url = os.environ.get("OLLAMA_BASE_URL", cfg.get("base_url", ""))
555
+ _validate_ollama_base_url(ollama_url)
556
+ print(
557
+ "[graphify] WARNING: ollama backend selected with no OLLAMA_API_KEY set; "
558
+ f"sending corpus to {ollama_url}. Set OLLAMA_API_KEY (any non-empty value) "
559
+ "to suppress this warning.",
560
+ file=sys.stderr,
561
+ )
562
+ key = "ollama"
563
+ if not key and backend not in ("bedrock", "claude-cli"):
564
+ raise ValueError(
565
+ f"No API key for backend '{backend}'. "
566
+ f"Set {_format_backend_env_keys(backend)} or pass api_key=."
567
+ )
568
+ mdl = model or _default_model_for_backend(backend)
569
+ user_msg = _read_files(files, root)
570
+ max_out = _resolve_max_tokens(cfg.get("max_tokens", 8192))
571
+
572
+ if backend == "claude":
573
+ return _call_claude(key, mdl, user_msg, max_tokens=max_out)
574
+ if backend == "claude-cli":
575
+ return _call_claude_cli(user_msg, max_tokens=max_out)
576
+ if backend == "bedrock":
577
+ return _call_bedrock(mdl, user_msg, max_tokens=max_out)
578
+ return _call_openai_compat(
579
+ cfg["base_url"],
580
+ key,
581
+ mdl,
582
+ user_msg,
583
+ temperature=cfg.get("temperature", 0),
584
+ reasoning_effort=cfg.get("reasoning_effort"),
585
+ max_completion_tokens=cfg.get("max_completion_tokens", max_out),
586
+ backend=backend,
587
+ )
588
+
589
+
590
+ def _estimate_file_tokens(path: Path) -> int:
591
+ """Estimate the prompt-token cost of a single file under `_read_files` rules.
592
+
593
+ Uses tiktoken (`cl100k_base`) when available for accurate counts. Falls back
594
+ to the chars/4 heuristic if tiktoken is not installed. Both paths cap at
595
+ `_FILE_CHAR_CAP` to match `_read_files`'s truncation, plus a constant for
596
+ the `=== rel ===` separator. Returns 0 for unreadable paths so they don't
597
+ blow up packing.
598
+ """
599
+ if _TOKENIZER is None:
600
+ try:
601
+ size = path.stat().st_size
602
+ except OSError:
603
+ return 0
604
+ chars = min(size, _FILE_CHAR_CAP) + _PER_FILE_OVERHEAD_CHARS
605
+ return chars // _CHARS_PER_TOKEN
606
+
607
+ try:
608
+ content = path.read_text(encoding="utf-8", errors="replace")[:_FILE_CHAR_CAP]
609
+ except OSError:
610
+ return 0
611
+ return len(_TOKENIZER.encode(content)) + (_PER_FILE_OVERHEAD_CHARS // _CHARS_PER_TOKEN)
612
+
613
+
614
+ def _pack_chunks_by_tokens(
615
+ files: list[Path],
616
+ token_budget: int,
617
+ ) -> list[list[Path]]:
618
+ """Greedily pack files into chunks that fit a token budget.
619
+
620
+ Files are first grouped by parent directory so related artifacts share a
621
+ chunk (cross-file edges are more likely to be extracted within a chunk
622
+ than across chunks). Within each directory, files are added one at a
623
+ time; a chunk is closed when adding the next file would exceed the
624
+ budget. A single file larger than the budget gets its own chunk and the
625
+ caller is expected to handle the API error if it actually overflows the
626
+ model's context window — packing can't shrink one big file.
627
+ """
628
+ if token_budget <= 0:
629
+ raise ValueError(f"token_budget must be positive, got {token_budget}")
630
+
631
+ by_dir: dict[Path, list[Path]] = {}
632
+ for f in files:
633
+ by_dir.setdefault(f.parent, []).append(f)
634
+
635
+ chunks: list[list[Path]] = []
636
+ current: list[Path] = []
637
+ current_tokens = 0
638
+
639
+ for directory in sorted(by_dir):
640
+ for path in by_dir[directory]:
641
+ cost = _estimate_file_tokens(path)
642
+ if current and current_tokens + cost > token_budget:
643
+ chunks.append(current)
644
+ current = []
645
+ current_tokens = 0
646
+ current.append(path)
647
+ current_tokens += cost
648
+
649
+ if current:
650
+ chunks.append(current)
651
+ return chunks
652
+
653
+
654
+ _CONTEXT_EXCEEDED_MARKERS = (
655
+ "context size",
656
+ "context length",
657
+ "context_length",
658
+ "context window",
659
+ "n_keep",
660
+ "exceeds the available",
661
+ "n_ctx",
662
+ "maximum context",
663
+ "too many tokens",
664
+ "prompt is too long",
665
+ "context_length_exceeded",
666
+ )
667
+
668
+
669
+ def _looks_like_context_exceeded(exc: BaseException) -> bool:
670
+ """Heuristically classify an exception as a context-window overflow.
671
+
672
+ Different backends raise different exception types and messages for the
673
+ same underlying problem ("the prompt + max_completion_tokens did not fit
674
+ in the model's context window"). We match on substrings of the stringified
675
+ exception so the retry layer can recover without depending on a specific
676
+ SDK class. False positives are cheap (we'll re-extract on halves and
677
+ likely recover); false negatives are expensive (chunk fails entirely).
678
+ """
679
+ msg = str(exc).lower()
680
+ return any(marker in msg for marker in _CONTEXT_EXCEEDED_MARKERS)
681
+
682
+
683
+ def _extract_with_adaptive_retry(
684
+ chunk: list[Path],
685
+ backend: str,
686
+ api_key: str | None,
687
+ model: str | None,
688
+ root: Path,
689
+ max_depth: int,
690
+ _depth: int = 0,
691
+ ) -> dict:
692
+ """Extract a chunk; if the response is truncated (`finish_reason="length"`)
693
+ or the API rejects the prompt as too large for the model's context window,
694
+ split the chunk in half and recurse.
695
+
696
+ Three signals drive the retry, all funnelled through the same code:
697
+
698
+ - `finish_reason == "length"` — the model accepted the input but ran out of
699
+ `max_completion_tokens` mid-output. The truncated JSON is unparseable, so
700
+ we discard it and re-extract on smaller inputs that produce shorter
701
+ outputs.
702
+
703
+ - context-window-exceeded API errors — the model rejected the input
704
+ outright (HTTP 400 from LM Studio, llama.cpp, vLLM, OpenAI, etc.).
705
+ Without a retry the whole chunk would fail with no output. Splitting in
706
+ half is the same recovery as for the `length` case and works for the
707
+ same reason.
708
+
709
+ - hollow successful responses — the model returned HTTP 200 with empty,
710
+ null, or unparseable content (typical of a local Ollama under load).
711
+ `_call_openai_compat` re-labels these as `finish_reason="length"` so they
712
+ take the same recovery path; without that the chunk would be silently
713
+ dropped from the corpus.
714
+
715
+ Recursion is capped at `max_depth` to bound worst-case cost. A chunk of N
716
+ files can split into up to 2**max_depth pieces — at depth=3 that's 8x. If
717
+ still failing at the cap, we surface the (likely empty) result with a
718
+ warning rather than infinite-loop.
719
+
720
+ A single-file chunk that overflows is unrecoverable here — we can't make
721
+ one file smaller than itself, so we return what we got and warn.
722
+ """
723
+ try:
724
+ result = extract_files_direct(
725
+ chunk, backend=backend, api_key=api_key, model=model, root=root
726
+ )
727
+ except Exception as exc: # noqa: BLE001 — re-raise unless it's a known context overflow
728
+ if not _looks_like_context_exceeded(exc):
729
+ raise
730
+ if len(chunk) <= 1:
731
+ print(
732
+ f"[graphify] single-file chunk {chunk[0]} exceeds model context "
733
+ f"and cannot be split further: {exc}",
734
+ file=sys.stderr,
735
+ )
736
+ return {"nodes": [], "edges": [], "hyperedges": [], "input_tokens": 0, "output_tokens": 0, "model": model, "finish_reason": "stop"}
737
+ if _depth >= max_depth:
738
+ print(
739
+ f"[graphify] chunk of {len(chunk)} still overflows context at "
740
+ f"recursion depth {_depth} (max {max_depth}) — dropping",
741
+ file=sys.stderr,
742
+ )
743
+ return {"nodes": [], "edges": [], "hyperedges": [], "input_tokens": 0, "output_tokens": 0, "model": model, "finish_reason": "stop"}
744
+ print(
745
+ f"[graphify] chunk of {len(chunk)} exceeded context at depth "
746
+ f"{_depth} ({type(exc).__name__}); splitting in half and retrying",
747
+ file=sys.stderr,
748
+ )
749
+ mid = len(chunk) // 2
750
+ left = _extract_with_adaptive_retry(
751
+ chunk[:mid], backend, api_key, model, root, max_depth, _depth + 1
752
+ )
753
+ right = _extract_with_adaptive_retry(
754
+ chunk[mid:], backend, api_key, model, root, max_depth, _depth + 1
755
+ )
756
+ return {
757
+ "nodes": left.get("nodes", []) + right.get("nodes", []),
758
+ "edges": left.get("edges", []) + right.get("edges", []),
759
+ "hyperedges": left.get("hyperedges", []) + right.get("hyperedges", []),
760
+ "input_tokens": left.get("input_tokens", 0) + right.get("input_tokens", 0),
761
+ "output_tokens": left.get("output_tokens", 0) + right.get("output_tokens", 0),
762
+ "model": model,
763
+ "finish_reason": "stop",
764
+ }
765
+
766
+ if result.get("finish_reason") != "length":
767
+ return result
768
+
769
+ if len(chunk) <= 1:
770
+ print(
771
+ f"[graphify] single-file chunk {chunk[0]} truncated at "
772
+ f"max_completion_tokens — partial result kept",
773
+ file=sys.stderr,
774
+ )
775
+ return result
776
+
777
+ if _depth >= max_depth:
778
+ print(
779
+ f"[graphify] chunk of {len(chunk)} still truncated at recursion "
780
+ f"depth {_depth} (max {max_depth}) — partial result kept",
781
+ file=sys.stderr,
782
+ )
783
+ return result
784
+
785
+ print(
786
+ f"[graphify] chunk of {len(chunk)} truncated at depth {_depth}, "
787
+ f"splitting into halves of {len(chunk) // 2} and "
788
+ f"{len(chunk) - len(chunk) // 2}",
789
+ file=sys.stderr,
790
+ )
791
+ mid = len(chunk) // 2
792
+ left = _extract_with_adaptive_retry(
793
+ chunk[:mid], backend, api_key, model, root, max_depth, _depth + 1
794
+ )
795
+ right = _extract_with_adaptive_retry(
796
+ chunk[mid:], backend, api_key, model, root, max_depth, _depth + 1
797
+ )
798
+
799
+ return {
800
+ "nodes": left.get("nodes", []) + right.get("nodes", []),
801
+ "edges": left.get("edges", []) + right.get("edges", []),
802
+ "hyperedges": left.get("hyperedges", []) + right.get("hyperedges", []),
803
+ "input_tokens": left.get("input_tokens", 0) + right.get("input_tokens", 0),
804
+ "output_tokens": left.get("output_tokens", 0) + right.get("output_tokens", 0),
805
+ "model": result.get("model"),
806
+ # Both halves either succeeded or have already surfaced their own
807
+ # truncation warning; the merged result is no longer truncated as a
808
+ # logical unit.
809
+ "finish_reason": "stop",
810
+ }
811
+
812
+
813
+ def extract_corpus_parallel(
814
+ files: list[Path],
815
+ backend: str = "kimi",
816
+ api_key: str | None = None,
817
+ model: str | None = None,
818
+ root: Path = Path("."),
819
+ chunk_size: int = 20,
820
+ on_chunk_done: Callable | None = None,
821
+ token_budget: int | None = 60_000,
822
+ max_concurrency: int = 4,
823
+ max_retry_depth: int = 3,
824
+ ) -> dict:
825
+ """Extract a corpus in chunks, merging results.
826
+
827
+ Chunking strategy:
828
+ - If `token_budget` is set (default 60_000), files are packed to fit
829
+ the budget and grouped by parent directory. This avoids the worst
830
+ case where 20 randomly-grouped files exceed a model's context
831
+ window in a single request.
832
+ - If `token_budget=None`, falls back to the legacy fixed-count
833
+ `chunk_size` packing for backwards compatibility.
834
+
835
+ Concurrency:
836
+ - Chunks run in parallel via a thread pool capped at `max_concurrency`
837
+ (default 4 — conservative to stay under provider rate limits).
838
+ - Set `max_concurrency=1` to force sequential execution.
839
+
840
+ Adaptive retry on truncation:
841
+ - When the LLM returns `finish_reason="length"` (output truncated at
842
+ `max_completion_tokens`), the chunk is split in half and each half
843
+ re-extracted recursively, up to `max_retry_depth` levels deep
844
+ (default 3 → max 8x expansion of one chunk).
845
+ - This is signal-driven: chunks too dense to fit in one response
846
+ self-heal by splitting until they do, while well-sized chunks pay
847
+ no extra cost. Set `max_retry_depth=0` to disable retries.
848
+
849
+ `on_chunk_done(idx, total, chunk_result)` fires once per chunk as it
850
+ completes (in completion order, not submission order). `idx` is the
851
+ chunk's submission index so callers can correlate progress. The
852
+ callback fires once per top-level chunk; recursive splits are merged
853
+ transparently before the callback is invoked.
854
+
855
+ Returns merged dict with nodes, edges, hyperedges, input_tokens,
856
+ output_tokens. Failed chunks are logged to stderr and skipped — one bad
857
+ chunk does not abort the run.
858
+ """
859
+ if token_budget is not None:
860
+ chunks = _pack_chunks_by_tokens(files, token_budget=token_budget)
861
+ else:
862
+ chunks = [files[i:i + chunk_size] for i in range(0, len(files), chunk_size)]
863
+
864
+ merged: dict = {
865
+ "nodes": [], "edges": [], "hyperedges": [],
866
+ "input_tokens": 0, "output_tokens": 0,
867
+ "failed_chunks": 0, # count of chunks that raised — loud failure on chunk errors
868
+ }
869
+ total = len(chunks)
870
+
871
+ def _run_one(idx: int, chunk: list[Path]) -> tuple[int, dict | None, Exception | None]:
872
+ t0 = time.time()
873
+ try:
874
+ result = _extract_with_adaptive_retry(
875
+ chunk,
876
+ backend=backend,
877
+ api_key=api_key,
878
+ model=model,
879
+ root=root,
880
+ max_depth=max_retry_depth,
881
+ )
882
+ result["elapsed_seconds"] = round(time.time() - t0, 2)
883
+ return idx, result, None
884
+ except Exception as exc: # noqa: BLE001 — caller-facing surface, log + continue
885
+ return idx, None, exc
886
+
887
+ # Ollama serves one request at a time per loaded model on a single GPU.
888
+ # Four concurrent 60k-token requests cause VRAM pressure and hollow
889
+ # responses after 3-4 chunks (#798). Force serial unless the user opts in.
890
+ if backend == "ollama" and os.environ.get("GRAPHIFY_OLLAMA_PARALLEL", "").strip() != "1":
891
+ max_concurrency = 1
892
+ # claude-cli shells out to a Claude Code session; parallel subprocesses conflict
893
+ # over session state. Force serial unless the user explicitly opts in.
894
+ if backend == "claude-cli" and os.environ.get("GRAPHIFY_CLAUDE_CLI_PARALLEL", "").strip() != "1":
895
+ max_concurrency = 1
896
+ workers = max(1, min(max_concurrency, total))
897
+ if workers == 1:
898
+ # Avoid thread pool overhead for single-worker runs (and keep
899
+ # callback ordering identical to the pre-refactor sequential path).
900
+ for idx, chunk in enumerate(chunks):
901
+ _, result, exc = _run_one(idx, chunk)
902
+ if exc is not None:
903
+ print(f"[graphify] chunk {idx + 1}/{total} failed: {exc}", file=sys.stderr)
904
+ merged["failed_chunks"] += 1
905
+ continue
906
+ assert result is not None
907
+ _merge_into(merged, result)
908
+ if callable(on_chunk_done):
909
+ on_chunk_done(idx, total, result)
910
+ else:
911
+ with ThreadPoolExecutor(max_workers=workers) as pool:
912
+ futures = [pool.submit(_run_one, idx, chunk) for idx, chunk in enumerate(chunks)]
913
+ for future in as_completed(futures):
914
+ idx, result, exc = future.result()
915
+ if exc is not None:
916
+ print(
917
+ f"[graphify] chunk {idx + 1}/{total} failed: {exc}",
918
+ file=sys.stderr,
919
+ )
920
+ merged["failed_chunks"] += 1
921
+ continue
922
+ assert result is not None
923
+ _merge_into(merged, result)
924
+ if callable(on_chunk_done):
925
+ on_chunk_done(idx, total, result)
926
+
927
+ # Loud failure summary — surface chunk failures at end so they're never
928
+ # buried mid-log. Exit 0 preserved for caller compatibility; the
929
+ # summary block makes the problem visible.
930
+ if merged["failed_chunks"] > 0:
931
+ print(
932
+ f"[graphify] WARNING: {merged['failed_chunks']}/{total} semantic chunk(s) failed"
933
+ " — see errors above. Partial results returned.",
934
+ file=sys.stderr,
935
+ )
936
+ return merged
937
+
938
+
939
+ def _merge_into(merged: dict, result: dict) -> None:
940
+ """Append a chunk result into the running merged accumulator."""
941
+ merged["nodes"].extend(result.get("nodes", []))
942
+ merged["edges"].extend(result.get("edges", []))
943
+ merged["hyperedges"].extend(result.get("hyperedges", []))
944
+ merged["input_tokens"] += result.get("input_tokens", 0)
945
+ merged["output_tokens"] += result.get("output_tokens", 0)
946
+
947
+
948
+ def _call_llm(prompt: str, *, backend: str, max_tokens: int = 200) -> str:
949
+ """Send a plain-text prompt to `backend` and return the model's text reply.
950
+
951
+ Used by lightweight callers (e.g. `graphify.dedup` LLM tiebreaker) that
952
+ don't need the full extraction prompt or JSON-shaped output. Mirrors the
953
+ backend dispatch logic of `extract_files_direct` but skips the
954
+ `_EXTRACTION_SYSTEM` prompt and JSON parsing.
955
+
956
+ Previously `graphify.dedup` imported a `_call_llm` symbol that did not
957
+ exist in this module, so the LLM tiebreaker silently no-op'd on
958
+ `ImportError` (F-038). Adding the function here re-enables it.
959
+ """
960
+ if backend not in BACKENDS:
961
+ raise ValueError(f"Unknown backend {backend!r}")
962
+ cfg = BACKENDS[backend]
963
+ key = _get_backend_api_key(backend)
964
+ if not key and backend == "ollama":
965
+ ollama_url = os.environ.get("OLLAMA_BASE_URL", cfg.get("base_url", ""))
966
+ _validate_ollama_base_url(ollama_url)
967
+ key = "ollama"
968
+ if not key and backend not in ("bedrock", "claude-cli"):
969
+ raise ValueError(
970
+ f"No API key for backend '{backend}'. Set {_format_backend_env_keys(backend)}."
971
+ )
972
+ mdl = _default_model_for_backend(backend)
973
+
974
+ if backend == "claude":
975
+ try:
976
+ import anthropic
977
+ except ImportError as exc:
978
+ raise ImportError("anthropic package required for claude backend") from exc
979
+ client = anthropic.Anthropic(api_key=key)
980
+ resp = client.messages.create(
981
+ model=mdl,
982
+ max_tokens=max_tokens,
983
+ messages=[{"role": "user", "content": prompt}],
984
+ )
985
+ return resp.content[0].text if resp.content else ""
986
+
987
+ if backend == "claude-cli":
988
+ import shutil, subprocess
989
+ if shutil.which("claude") is None:
990
+ raise RuntimeError("Claude Code CLI not found on $PATH")
991
+ proc = subprocess.run(
992
+ ["claude", "-p", "--output-format", "json", "--no-session-persistence"],
993
+ input=prompt,
994
+ capture_output=True,
995
+ text=True,
996
+ encoding="utf-8", # Force UTF-8 — prevents UnicodeEncodeError on Windows cp1252
997
+ timeout=600,
998
+ check=False,
999
+ )
1000
+ if proc.returncode != 0:
1001
+ raise RuntimeError(f"claude -p exited {proc.returncode}: {proc.stderr.strip()[:500]}")
1002
+ try:
1003
+ envelope = json.loads(proc.stdout)
1004
+ except json.JSONDecodeError as exc:
1005
+ raise RuntimeError(f"claude -p produced unparseable JSON envelope: {exc}") from exc
1006
+ return envelope.get("result", "")
1007
+
1008
+ if backend == "bedrock":
1009
+ try:
1010
+ import boto3
1011
+ except ImportError as exc:
1012
+ raise ImportError("boto3 required for bedrock backend") from exc
1013
+ region = os.environ.get("AWS_REGION") or os.environ.get("AWS_DEFAULT_REGION") or "us-east-1"
1014
+ profile = os.environ.get("AWS_PROFILE")
1015
+ session = boto3.Session(profile_name=profile, region_name=region)
1016
+ client = session.client("bedrock-runtime")
1017
+ resp = client.converse(
1018
+ modelId=mdl,
1019
+ messages=[{"role": "user", "content": [{"text": prompt}]}],
1020
+ inferenceConfig={"maxTokens": max_tokens, "temperature": 0},
1021
+ )
1022
+ return resp.get("output", {}).get("message", {}).get("content", [{}])[0].get("text", "")
1023
+
1024
+ # OpenAI-compatible (kimi, openai, gemini, ollama)
1025
+ try:
1026
+ from openai import OpenAI
1027
+ except ImportError as exc:
1028
+ raise ImportError("openai package required for this backend") from exc
1029
+ client = OpenAI(api_key=key, base_url=cfg["base_url"])
1030
+ kwargs: dict = {
1031
+ "model": mdl,
1032
+ "messages": [{"role": "user", "content": prompt}],
1033
+ "max_completion_tokens": max_tokens,
1034
+ }
1035
+ temperature = cfg.get("temperature", 0)
1036
+ if temperature is not None:
1037
+ kwargs["temperature"] = temperature
1038
+ if cfg.get("reasoning_effort"):
1039
+ kwargs["reasoning_effort"] = cfg["reasoning_effort"]
1040
+ if "moonshot" in cfg["base_url"]:
1041
+ kwargs["extra_body"] = {"thinking": {"type": "disabled"}}
1042
+ resp = client.chat.completions.create(**kwargs)
1043
+ if not resp.choices or resp.choices[0].message is None:
1044
+ raise ValueError("LLM returned empty or filtered response")
1045
+ return resp.choices[0].message.content or ""
1046
+
1047
+
1048
+ def estimate_cost(backend: str, input_tokens: int, output_tokens: int) -> float:
1049
+ """Estimate USD cost for a given token count using published pricing."""
1050
+ if backend not in BACKENDS:
1051
+ return 0.0
1052
+ p = BACKENDS[backend]["pricing"]
1053
+ return (input_tokens * p["input"] + output_tokens * p["output"]) / 1_000_000
1054
+
1055
+
1056
+ def _validate_ollama_base_url(url: str) -> None:
1057
+ """Warn (do not raise) if OLLAMA_BASE_URL looks unsafe.
1058
+
1059
+ Sending an entire corpus to a non-loopback http:// endpoint silently leaks
1060
+ proprietary code; we surface a visible stderr warning instead of failing
1061
+ closed (some users genuinely run Ollama on a LAN host they trust).
1062
+ """
1063
+ try:
1064
+ from urllib.parse import urlparse
1065
+ parsed = urlparse(url)
1066
+ except Exception:
1067
+ print(
1068
+ f"[graphify] WARNING: OLLAMA_BASE_URL={url!r} is not a parseable URL.",
1069
+ file=sys.stderr,
1070
+ )
1071
+ return
1072
+ if parsed.scheme not in ("http", "https"):
1073
+ print(
1074
+ f"[graphify] WARNING: OLLAMA_BASE_URL has unexpected scheme {parsed.scheme!r}; "
1075
+ "expected http or https.",
1076
+ file=sys.stderr,
1077
+ )
1078
+ return
1079
+ host = (parsed.hostname or "").lower()
1080
+ is_loopback = host in ("localhost", "127.0.0.1", "::1") or host.startswith("127.")
1081
+ if not is_loopback:
1082
+ scheme_note = " (UNENCRYPTED)" if parsed.scheme == "http" else ""
1083
+ print(
1084
+ f"[graphify] WARNING: OLLAMA_BASE_URL points to non-loopback host {host!r}{scheme_note}. "
1085
+ "Your full corpus will be sent to that endpoint. "
1086
+ "Set OLLAMA_BASE_URL=http://localhost:11434/v1 to keep extraction local.",
1087
+ file=sys.stderr,
1088
+ )
1089
+
1090
+
1091
+ def detect_backend() -> str | None:
1092
+ """Return the name of whichever backend has an API key set, or None.
1093
+
1094
+ Priority: gemini → kimi → claude → openai → bedrock → ollama (last, opt-in).
1095
+
1096
+ Ollama is intentionally checked LAST so a paid API key (Anthropic/OpenAI/etc.)
1097
+ is never silently shadowed by an incidental OLLAMA_BASE_URL in the environment
1098
+ — see security finding F-002/F-029. Setting OLLAMA_BASE_URL alongside a paid
1099
+ key now keeps you on the paid backend; remove the paid key (or pass
1100
+ --backend ollama explicitly) to route to the local model.
1101
+ """
1102
+ for backend in ("gemini", "kimi", "claude", "openai", "deepseek"):
1103
+ if _get_backend_api_key(backend):
1104
+ return backend
1105
+ if os.environ.get("AWS_PROFILE") or os.environ.get("AWS_REGION") or os.environ.get("AWS_DEFAULT_REGION"):
1106
+ return "bedrock"
1107
+ ollama_url = os.environ.get("OLLAMA_BASE_URL")
1108
+ if ollama_url:
1109
+ _validate_ollama_base_url(ollama_url)
1110
+ return "ollama"
1111
+ return None