@heytherevibin/skillforge 0.2.1

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 (402) hide show
  1. package/CHANGELOG.md +16 -0
  2. package/CODE_OF_CONDUCT.md +34 -0
  3. package/CONTRIBUTING.md +38 -0
  4. package/LICENSE +21 -0
  5. package/README.md +337 -0
  6. package/RELEASING.md +93 -0
  7. package/SECURITY.md +31 -0
  8. package/STRATEGY.md +26 -0
  9. package/bin/cli.js +547 -0
  10. package/lib/packs.js +184 -0
  11. package/package.json +38 -0
  12. package/python/app/__init__.py +0 -0
  13. package/python/app/__pycache__/__init__.cpython-312.pyc +0 -0
  14. package/python/app/__pycache__/auth.cpython-312.pyc +0 -0
  15. package/python/app/__pycache__/main.cpython-312.pyc +0 -0
  16. package/python/app/auth.py +63 -0
  17. package/python/app/cli.py +78 -0
  18. package/python/app/db_paths.py +26 -0
  19. package/python/app/events_cli.py +175 -0
  20. package/python/app/main.py +647 -0
  21. package/python/app/materialize.py +138 -0
  22. package/python/app/mcp_server.py +610 -0
  23. package/python/app/route_cli.py +117 -0
  24. package/python/requirements-dev.txt +1 -0
  25. package/python/requirements.txt +7 -0
  26. package/python/tests/test_db_paths.py +41 -0
  27. package/skills/accessibility/SKILL.md +145 -0
  28. package/skills/agent-architecture-audit/SKILL.md +256 -0
  29. package/skills/agent-eval/SKILL.md +144 -0
  30. package/skills/agent-harness-construction/SKILL.md +72 -0
  31. package/skills/agent-introspection-debugging/SKILL.md +152 -0
  32. package/skills/agent-payment-x402/SKILL.md +224 -0
  33. package/skills/agent-sort/SKILL.md +214 -0
  34. package/skills/agentic-engineering/SKILL.md +62 -0
  35. package/skills/agentic-os/SKILL.md +386 -0
  36. package/skills/ai-first-engineering/SKILL.md +50 -0
  37. package/skills/ai-regression-testing/SKILL.md +384 -0
  38. package/skills/android-clean-architecture/SKILL.md +338 -0
  39. package/skills/angular-developer/SKILL.md +153 -0
  40. package/skills/angular-developer/references/angular-animations.md +160 -0
  41. package/skills/angular-developer/references/angular-aria.md +410 -0
  42. package/skills/angular-developer/references/cli.md +86 -0
  43. package/skills/angular-developer/references/component-harnesses.md +59 -0
  44. package/skills/angular-developer/references/component-styling.md +91 -0
  45. package/skills/angular-developer/references/components.md +117 -0
  46. package/skills/angular-developer/references/creating-services.md +97 -0
  47. package/skills/angular-developer/references/data-resolvers.md +69 -0
  48. package/skills/angular-developer/references/define-routes.md +67 -0
  49. package/skills/angular-developer/references/defining-providers.md +72 -0
  50. package/skills/angular-developer/references/di-fundamentals.md +120 -0
  51. package/skills/angular-developer/references/e2e-testing.md +56 -0
  52. package/skills/angular-developer/references/effects.md +83 -0
  53. package/skills/angular-developer/references/hierarchical-injectors.md +43 -0
  54. package/skills/angular-developer/references/host-elements.md +80 -0
  55. package/skills/angular-developer/references/injection-context.md +63 -0
  56. package/skills/angular-developer/references/inputs.md +101 -0
  57. package/skills/angular-developer/references/linked-signal.md +59 -0
  58. package/skills/angular-developer/references/loading-strategies.md +61 -0
  59. package/skills/angular-developer/references/mcp.md +108 -0
  60. package/skills/angular-developer/references/navigate-to-routes.md +69 -0
  61. package/skills/angular-developer/references/outputs.md +86 -0
  62. package/skills/angular-developer/references/reactive-forms.md +122 -0
  63. package/skills/angular-developer/references/rendering-strategies.md +44 -0
  64. package/skills/angular-developer/references/resource.md +77 -0
  65. package/skills/angular-developer/references/route-animations.md +56 -0
  66. package/skills/angular-developer/references/route-guards.md +52 -0
  67. package/skills/angular-developer/references/router-lifecycle.md +45 -0
  68. package/skills/angular-developer/references/router-testing.md +87 -0
  69. package/skills/angular-developer/references/show-routes-with-outlets.md +68 -0
  70. package/skills/angular-developer/references/signal-forms.md +795 -0
  71. package/skills/angular-developer/references/signals-overview.md +94 -0
  72. package/skills/angular-developer/references/tailwind-css.md +69 -0
  73. package/skills/angular-developer/references/template-driven-forms.md +114 -0
  74. package/skills/angular-developer/references/testing-fundamentals.md +65 -0
  75. package/skills/api-connector-builder/SKILL.md +120 -0
  76. package/skills/api-design/SKILL.md +522 -0
  77. package/skills/architecture-decision-records/SKILL.md +178 -0
  78. package/skills/article-writing/SKILL.md +78 -0
  79. package/skills/automation-audit-ops/SKILL.md +141 -0
  80. package/skills/autonomous-agent-harness/SKILL.md +272 -0
  81. package/skills/autonomous-loops/SKILL.md +609 -0
  82. package/skills/backend-patterns/SKILL.md +560 -0
  83. package/skills/benchmark/SKILL.md +92 -0
  84. package/skills/blueprint/SKILL.md +104 -0
  85. package/skills/browser-qa/SKILL.md +86 -0
  86. package/skills/bun-runtime/SKILL.md +83 -0
  87. package/skills/canary-watch/SKILL.md +98 -0
  88. package/skills/carrier-relationship-management/SKILL.md +211 -0
  89. package/skills/cisco-ios-patterns/SKILL.md +163 -0
  90. package/skills/ck/SKILL.md +147 -0
  91. package/skills/ck/commands/forget.mjs +44 -0
  92. package/skills/ck/commands/info.mjs +24 -0
  93. package/skills/ck/commands/init.mjs +143 -0
  94. package/skills/ck/commands/list.mjs +40 -0
  95. package/skills/ck/commands/migrate.mjs +202 -0
  96. package/skills/ck/commands/resume.mjs +36 -0
  97. package/skills/ck/commands/save.mjs +210 -0
  98. package/skills/ck/commands/shared.mjs +387 -0
  99. package/skills/ck/hooks/session-start.mjs +224 -0
  100. package/skills/claude-devfleet/SKILL.md +103 -0
  101. package/skills/click-path-audit/SKILL.md +244 -0
  102. package/skills/clickhouse-io/SKILL.md +438 -0
  103. package/skills/code-tour/SKILL.md +235 -0
  104. package/skills/codebase-onboarding/SKILL.md +232 -0
  105. package/skills/coding-standards/SKILL.md +548 -0
  106. package/skills/compose-multiplatform-patterns/SKILL.md +298 -0
  107. package/skills/connections-optimizer/SKILL.md +188 -0
  108. package/skills/content-engine/SKILL.md +126 -0
  109. package/skills/content-hash-cache-pattern/SKILL.md +160 -0
  110. package/skills/context-budget/SKILL.md +134 -0
  111. package/skills/continuous-agent-loop/SKILL.md +44 -0
  112. package/skills/continuous-learning/SKILL.md +129 -0
  113. package/skills/continuous-learning/config.json +18 -0
  114. package/skills/continuous-learning/evaluate-session.sh +69 -0
  115. package/skills/continuous-learning-v2/SKILL.md +358 -0
  116. package/skills/continuous-learning-v2/agents/observer-loop.sh +322 -0
  117. package/skills/continuous-learning-v2/agents/observer.md +198 -0
  118. package/skills/continuous-learning-v2/agents/session-guardian.sh +150 -0
  119. package/skills/continuous-learning-v2/agents/start-observer.sh +248 -0
  120. package/skills/continuous-learning-v2/config.json +8 -0
  121. package/skills/continuous-learning-v2/hooks/observe.sh +476 -0
  122. package/skills/continuous-learning-v2/scripts/detect-project.sh +288 -0
  123. package/skills/continuous-learning-v2/scripts/instinct-cli.py +1519 -0
  124. package/skills/continuous-learning-v2/scripts/lib/homunculus-dir.sh +31 -0
  125. package/skills/continuous-learning-v2/scripts/migrate-homunculus.sh +62 -0
  126. package/skills/continuous-learning-v2/scripts/test_parse_instinct.py +1018 -0
  127. package/skills/cost-aware-llm-pipeline/SKILL.md +182 -0
  128. package/skills/cost-tracking/SKILL.md +147 -0
  129. package/skills/council/SKILL.md +202 -0
  130. package/skills/cpp-coding-standards/SKILL.md +722 -0
  131. package/skills/cpp-testing/SKILL.md +323 -0
  132. package/skills/crosspost/SKILL.md +110 -0
  133. package/skills/csharp-testing/SKILL.md +320 -0
  134. package/skills/customer-billing-ops/SKILL.md +139 -0
  135. package/skills/customs-trade-compliance/SKILL.md +262 -0
  136. package/skills/dart-flutter-patterns/SKILL.md +562 -0
  137. package/skills/dashboard-builder/SKILL.md +108 -0
  138. package/skills/data-scraper-agent/SKILL.md +764 -0
  139. package/skills/database-migrations/SKILL.md +428 -0
  140. package/skills/deep-research/SKILL.md +158 -0
  141. package/skills/defi-amm-security/SKILL.md +166 -0
  142. package/skills/deployment-patterns/SKILL.md +426 -0
  143. package/skills/design-system/SKILL.md +81 -0
  144. package/skills/django-celery/SKILL.md +456 -0
  145. package/skills/django-patterns/SKILL.md +733 -0
  146. package/skills/django-security/SKILL.md +592 -0
  147. package/skills/django-tdd/SKILL.md +728 -0
  148. package/skills/django-verification/SKILL.md +468 -0
  149. package/skills/dmux-workflows/SKILL.md +190 -0
  150. package/skills/docker-patterns/SKILL.md +363 -0
  151. package/skills/documentation-lookup/SKILL.md +89 -0
  152. package/skills/dotnet-patterns/SKILL.md +320 -0
  153. package/skills/e2e-testing/SKILL.md +325 -0
  154. package/skills/email-ops/SKILL.md +120 -0
  155. package/skills/energy-procurement/SKILL.md +227 -0
  156. package/skills/enterprise-agent-ops/SKILL.md +49 -0
  157. package/skills/error-handling/SKILL.md +375 -0
  158. package/skills/eval-harness/SKILL.md +269 -0
  159. package/skills/evm-token-decimals/SKILL.md +130 -0
  160. package/skills/exa-search/SKILL.md +106 -0
  161. package/skills/fal-ai-media/SKILL.md +287 -0
  162. package/skills/fastapi-patterns/SKILL.md +327 -0
  163. package/skills/finance-billing-ops/SKILL.md +126 -0
  164. package/skills/flox-environments/SKILL.md +496 -0
  165. package/skills/flutter-dart-code-review/SKILL.md +434 -0
  166. package/skills/foundation-models-on-device/SKILL.md +243 -0
  167. package/skills/frontend-design-direction/SKILL.md +92 -0
  168. package/skills/frontend-patterns/SKILL.md +641 -0
  169. package/skills/frontend-slides/SKILL.md +183 -0
  170. package/skills/frontend-slides/STYLE_PRESETS.md +330 -0
  171. package/skills/frontend-slides/animation-patterns.md +122 -0
  172. package/skills/frontend-slides/html-template.md +419 -0
  173. package/skills/frontend-slides/scripts/export-pdf.sh +418 -0
  174. package/skills/frontend-slides/scripts/extract-pptx.py +96 -0
  175. package/skills/frontend-slides/viewport-base.css +153 -0
  176. package/skills/fsharp-testing/SKILL.md +279 -0
  177. package/skills/gan-style-harness/SKILL.md +278 -0
  178. package/skills/gateguard/SKILL.md +125 -0
  179. package/skills/git-workflow/SKILL.md +714 -0
  180. package/skills/github-ops/SKILL.md +143 -0
  181. package/skills/golang-patterns/SKILL.md +673 -0
  182. package/skills/golang-testing/SKILL.md +719 -0
  183. package/skills/google-workspace-ops/SKILL.md +94 -0
  184. package/skills/healthcare-cdss-patterns/SKILL.md +245 -0
  185. package/skills/healthcare-emr-patterns/SKILL.md +159 -0
  186. package/skills/healthcare-eval-harness/SKILL.md +207 -0
  187. package/skills/healthcare-phi-compliance/SKILL.md +145 -0
  188. package/skills/hermes-imports/SKILL.md +87 -0
  189. package/skills/hexagonal-architecture/SKILL.md +275 -0
  190. package/skills/hipaa-compliance/SKILL.md +78 -0
  191. package/skills/homelab-network-readiness/SKILL.md +169 -0
  192. package/skills/homelab-network-setup/SKILL.md +129 -0
  193. package/skills/homelab-pihole-dns/SKILL.md +274 -0
  194. package/skills/homelab-vlan-segmentation/SKILL.md +311 -0
  195. package/skills/homelab-wireguard-vpn/SKILL.md +305 -0
  196. package/skills/hookify-rules/SKILL.md +128 -0
  197. package/skills/inventory-demand-planning/SKILL.md +246 -0
  198. package/skills/investor-materials/SKILL.md +95 -0
  199. package/skills/investor-outreach/SKILL.md +90 -0
  200. package/skills/ios-icon-gen/SKILL.md +157 -0
  201. package/skills/ios-icon-gen/scripts/generate_icons.swift +258 -0
  202. package/skills/ios-icon-gen/scripts/iconify_gen.sh +235 -0
  203. package/skills/iterative-retrieval/SKILL.md +209 -0
  204. package/skills/java-coding-standards/SKILL.md +382 -0
  205. package/skills/jira-integration/SKILL.md +292 -0
  206. package/skills/jpa-patterns/SKILL.md +150 -0
  207. package/skills/knowledge-ops/SKILL.md +153 -0
  208. package/skills/kotlin-coroutines-flows/SKILL.md +283 -0
  209. package/skills/kotlin-exposed-patterns/SKILL.md +718 -0
  210. package/skills/kotlin-ktor-patterns/SKILL.md +688 -0
  211. package/skills/kotlin-patterns/SKILL.md +710 -0
  212. package/skills/kotlin-testing/SKILL.md +823 -0
  213. package/skills/laravel-patterns/SKILL.md +414 -0
  214. package/skills/laravel-plugin-discovery/SKILL.md +228 -0
  215. package/skills/laravel-security/SKILL.md +284 -0
  216. package/skills/laravel-tdd/SKILL.md +282 -0
  217. package/skills/laravel-verification/SKILL.md +178 -0
  218. package/skills/lead-intelligence/SKILL.md +320 -0
  219. package/skills/lead-intelligence/agents/enrichment-agent.md +85 -0
  220. package/skills/lead-intelligence/agents/mutual-mapper.md +75 -0
  221. package/skills/lead-intelligence/agents/outreach-drafter.md +98 -0
  222. package/skills/lead-intelligence/agents/signal-scorer.md +60 -0
  223. package/skills/liquid-glass-design/SKILL.md +279 -0
  224. package/skills/llm-trading-agent-security/SKILL.md +146 -0
  225. package/skills/logistics-exception-management/SKILL.md +221 -0
  226. package/skills/make-interfaces-feel-better/SKILL.md +151 -0
  227. package/skills/manim-video/SKILL.md +88 -0
  228. package/skills/manim-video/assets/network_graph_scene.py +52 -0
  229. package/skills/market-research/SKILL.md +74 -0
  230. package/skills/mcp-server-patterns/SKILL.md +68 -0
  231. package/skills/messages-ops/SKILL.md +103 -0
  232. package/skills/mle-workflow/SKILL.md +345 -0
  233. package/skills/motion-advanced/SKILL.md +596 -0
  234. package/skills/motion-foundations/SKILL.md +299 -0
  235. package/skills/motion-patterns/SKILL.md +435 -0
  236. package/skills/motion-ui/SKILL.md +574 -0
  237. package/skills/mysql-patterns/SKILL.md +411 -0
  238. package/skills/nanoclaw-repl/SKILL.md +32 -0
  239. package/skills/nestjs-patterns/SKILL.md +229 -0
  240. package/skills/netmiko-ssh-automation/SKILL.md +173 -0
  241. package/skills/network-bgp-diagnostics/SKILL.md +167 -0
  242. package/skills/network-config-validation/SKILL.md +210 -0
  243. package/skills/network-interface-health/SKILL.md +152 -0
  244. package/skills/nextjs-turbopack/SKILL.md +43 -0
  245. package/skills/nodejs-keccak256/SKILL.md +102 -0
  246. package/skills/nutrient-document-processing/SKILL.md +166 -0
  247. package/skills/nuxt4-patterns/SKILL.md +99 -0
  248. package/skills/openclaw-persona-forge/SKILL.md +288 -0
  249. package/skills/openclaw-persona-forge/gacha.py +224 -0
  250. package/skills/openclaw-persona-forge/gacha.sh +5 -0
  251. package/skills/openclaw-persona-forge/references/avatar-style.md +124 -0
  252. package/skills/openclaw-persona-forge/references/boundary-rules.md +53 -0
  253. package/skills/openclaw-persona-forge/references/error-handling.md +53 -0
  254. package/skills/openclaw-persona-forge/references/identity-tension.md +48 -0
  255. package/skills/openclaw-persona-forge/references/naming-system.md +39 -0
  256. package/skills/openclaw-persona-forge/references/output-template.md +166 -0
  257. package/skills/opensource-pipeline/SKILL.md +254 -0
  258. package/skills/perl-patterns/SKILL.md +503 -0
  259. package/skills/perl-security/SKILL.md +502 -0
  260. package/skills/perl-testing/SKILL.md +474 -0
  261. package/skills/plan-orchestrate/SKILL.md +253 -0
  262. package/skills/plankton-code-quality/SKILL.md +236 -0
  263. package/skills/postgres-patterns/SKILL.md +146 -0
  264. package/skills/product-capability/SKILL.md +140 -0
  265. package/skills/product-lens/SKILL.md +91 -0
  266. package/skills/production-audit/SKILL.md +206 -0
  267. package/skills/production-scheduling/SKILL.md +237 -0
  268. package/skills/project-flow-ops/SKILL.md +110 -0
  269. package/skills/prompt-optimizer/SKILL.md +398 -0
  270. package/skills/python-patterns/SKILL.md +749 -0
  271. package/skills/python-testing/SKILL.md +815 -0
  272. package/skills/pytorch-patterns/SKILL.md +395 -0
  273. package/skills/quality-nonconformance/SKILL.md +259 -0
  274. package/skills/quarkus-patterns/SKILL.md +721 -0
  275. package/skills/quarkus-security/SKILL.md +466 -0
  276. package/skills/quarkus-tdd/SKILL.md +810 -0
  277. package/skills/quarkus-verification/SKILL.md +478 -0
  278. package/skills/ralphinho-rfc-pipeline/SKILL.md +66 -0
  279. package/skills/redis-patterns/SKILL.md +402 -0
  280. package/skills/regex-vs-llm-structured-text/SKILL.md +219 -0
  281. package/skills/remotion-video-creation/SKILL.md +43 -0
  282. package/skills/remotion-video-creation/rules/3d.md +86 -0
  283. package/skills/remotion-video-creation/rules/animations.md +29 -0
  284. package/skills/remotion-video-creation/rules/assets/charts-bar-chart.tsx +173 -0
  285. package/skills/remotion-video-creation/rules/assets/text-animations-typewriter.tsx +100 -0
  286. package/skills/remotion-video-creation/rules/assets/text-animations-word-highlight.tsx +108 -0
  287. package/skills/remotion-video-creation/rules/assets.md +78 -0
  288. package/skills/remotion-video-creation/rules/audio.md +172 -0
  289. package/skills/remotion-video-creation/rules/calculate-metadata.md +104 -0
  290. package/skills/remotion-video-creation/rules/can-decode.md +75 -0
  291. package/skills/remotion-video-creation/rules/charts.md +58 -0
  292. package/skills/remotion-video-creation/rules/compositions.md +146 -0
  293. package/skills/remotion-video-creation/rules/display-captions.md +126 -0
  294. package/skills/remotion-video-creation/rules/extract-frames.md +229 -0
  295. package/skills/remotion-video-creation/rules/fonts.md +152 -0
  296. package/skills/remotion-video-creation/rules/get-audio-duration.md +58 -0
  297. package/skills/remotion-video-creation/rules/get-video-dimensions.md +68 -0
  298. package/skills/remotion-video-creation/rules/get-video-duration.md +58 -0
  299. package/skills/remotion-video-creation/rules/gifs.md +138 -0
  300. package/skills/remotion-video-creation/rules/images.md +130 -0
  301. package/skills/remotion-video-creation/rules/import-srt-captions.md +67 -0
  302. package/skills/remotion-video-creation/rules/lottie.md +67 -0
  303. package/skills/remotion-video-creation/rules/measuring-dom-nodes.md +34 -0
  304. package/skills/remotion-video-creation/rules/measuring-text.md +143 -0
  305. package/skills/remotion-video-creation/rules/sequencing.md +106 -0
  306. package/skills/remotion-video-creation/rules/tailwind.md +11 -0
  307. package/skills/remotion-video-creation/rules/text-animations.md +20 -0
  308. package/skills/remotion-video-creation/rules/timing.md +179 -0
  309. package/skills/remotion-video-creation/rules/transcribe-captions.md +19 -0
  310. package/skills/remotion-video-creation/rules/transitions.md +122 -0
  311. package/skills/remotion-video-creation/rules/trimming.md +52 -0
  312. package/skills/remotion-video-creation/rules/videos.md +171 -0
  313. package/skills/repo-scan/SKILL.md +78 -0
  314. package/skills/research-ops/SKILL.md +111 -0
  315. package/skills/returns-reverse-logistics/SKILL.md +239 -0
  316. package/skills/rules-distill/SKILL.md +263 -0
  317. package/skills/rules-distill/scripts/scan-rules.sh +58 -0
  318. package/skills/rules-distill/scripts/scan-skills.sh +129 -0
  319. package/skills/rust-patterns/SKILL.md +498 -0
  320. package/skills/rust-testing/SKILL.md +499 -0
  321. package/skills/safety-guard/SKILL.md +74 -0
  322. package/skills/santa-method/SKILL.md +306 -0
  323. package/skills/scientific-db-pubmed-database/SKILL.md +175 -0
  324. package/skills/scientific-db-uspto-database/SKILL.md +177 -0
  325. package/skills/scientific-pkg-gget/SKILL.md +166 -0
  326. package/skills/scientific-thinking-literature-review/SKILL.md +192 -0
  327. package/skills/scientific-thinking-scholar-evaluation/SKILL.md +160 -0
  328. package/skills/search-first/SKILL.md +181 -0
  329. package/skills/security-bounty-hunter/SKILL.md +99 -0
  330. package/skills/security-review/SKILL.md +502 -0
  331. package/skills/security-review/cloud-infrastructure-security.md +361 -0
  332. package/skills/seo/SKILL.md +153 -0
  333. package/skills/skill-comply/SKILL.md +57 -0
  334. package/skills/skill-comply/fixtures/compliant_trace.jsonl +5 -0
  335. package/skills/skill-comply/fixtures/noncompliant_trace.jsonl +3 -0
  336. package/skills/skill-comply/fixtures/tdd_spec.yaml +44 -0
  337. package/skills/skill-comply/prompts/classifier.md +24 -0
  338. package/skills/skill-comply/prompts/scenario_generator.md +62 -0
  339. package/skills/skill-comply/prompts/spec_generator.md +42 -0
  340. package/skills/skill-comply/pyproject.toml +15 -0
  341. package/skills/skill-comply/scripts/__init__.py +0 -0
  342. package/skills/skill-comply/scripts/classifier.py +85 -0
  343. package/skills/skill-comply/scripts/grader.py +124 -0
  344. package/skills/skill-comply/scripts/parser.py +107 -0
  345. package/skills/skill-comply/scripts/report.py +170 -0
  346. package/skills/skill-comply/scripts/run.py +127 -0
  347. package/skills/skill-comply/scripts/runner.py +186 -0
  348. package/skills/skill-comply/scripts/scenario_generator.py +70 -0
  349. package/skills/skill-comply/scripts/spec_generator.py +72 -0
  350. package/skills/skill-comply/scripts/utils.py +13 -0
  351. package/skills/skill-comply/tests/test_grader.py +197 -0
  352. package/skills/skill-comply/tests/test_parser.py +90 -0
  353. package/skills/skill-comply/tests/test_runner.py +172 -0
  354. package/skills/skill-scout/SKILL.md +139 -0
  355. package/skills/skill-stocktake/SKILL.md +193 -0
  356. package/skills/skill-stocktake/scripts/quick-diff.sh +87 -0
  357. package/skills/skill-stocktake/scripts/save-results.sh +56 -0
  358. package/skills/skill-stocktake/scripts/scan.sh +170 -0
  359. package/skills/social-graph-ranker/SKILL.md +153 -0
  360. package/skills/springboot-patterns/SKILL.md +313 -0
  361. package/skills/springboot-security/SKILL.md +271 -0
  362. package/skills/springboot-tdd/SKILL.md +157 -0
  363. package/skills/springboot-verification/SKILL.md +230 -0
  364. package/skills/strategic-compact/SKILL.md +129 -0
  365. package/skills/strategic-compact/suggest-compact.sh +54 -0
  366. package/skills/swift-actor-persistence/SKILL.md +142 -0
  367. package/skills/swift-concurrency-6-2/SKILL.md +216 -0
  368. package/skills/swift-protocol-di-testing/SKILL.md +189 -0
  369. package/skills/swiftui-patterns/SKILL.md +259 -0
  370. package/skills/tdd-workflow/SKILL.md +462 -0
  371. package/skills/team-builder/SKILL.md +166 -0
  372. package/skills/terminal-ops/SKILL.md +108 -0
  373. package/skills/tinystruct-patterns/SKILL.md +130 -0
  374. package/skills/tinystruct-patterns/references/architecture.md +77 -0
  375. package/skills/tinystruct-patterns/references/data-handling.md +35 -0
  376. package/skills/tinystruct-patterns/references/routing.md +57 -0
  377. package/skills/tinystruct-patterns/references/system-usage.md +74 -0
  378. package/skills/tinystruct-patterns/references/testing.md +59 -0
  379. package/skills/token-budget-advisor/SKILL.md +133 -0
  380. package/skills/ui-demo/SKILL.md +464 -0
  381. package/skills/ui-to-vue/SKILL.md +134 -0
  382. package/skills/unified-notifications-ops/SKILL.md +186 -0
  383. package/skills/verification-loop/SKILL.md +125 -0
  384. package/skills/video-editing/SKILL.md +309 -0
  385. package/skills/videodb/SKILL.md +373 -0
  386. package/skills/videodb/reference/api-reference.md +550 -0
  387. package/skills/videodb/reference/capture-reference.md +407 -0
  388. package/skills/videodb/reference/capture.md +101 -0
  389. package/skills/videodb/reference/editor.md +443 -0
  390. package/skills/videodb/reference/generative.md +331 -0
  391. package/skills/videodb/reference/rtstream-reference.md +564 -0
  392. package/skills/videodb/reference/rtstream.md +65 -0
  393. package/skills/videodb/reference/search.md +230 -0
  394. package/skills/videodb/reference/streaming.md +406 -0
  395. package/skills/videodb/reference/use-cases.md +118 -0
  396. package/skills/videodb/scripts/ws_listener.py +282 -0
  397. package/skills/visa-doc-translate/README.md +86 -0
  398. package/skills/visa-doc-translate/SKILL.md +117 -0
  399. package/skills/vite-patterns/SKILL.md +448 -0
  400. package/skills/windows-desktop-e2e/SKILL.md +787 -0
  401. package/skills/workspace-surface-audit/SKILL.md +124 -0
  402. package/skills/x-api/SKILL.md +233 -0
package/lib/packs.js ADDED
@@ -0,0 +1,184 @@
1
+ /**
2
+ * Skill pack installer.
3
+ *
4
+ * A "pack" is any git repo containing a skillforge.json manifest at the root:
5
+ * {
6
+ * "name": "my-pack",
7
+ * "version": "1.0.0",
8
+ * "skills": ["skill-one", "skill-two"] // folder names relative to repo root
9
+ * }
10
+ *
11
+ * Packs are git-cloned to ~/.skillforge/packs/<source-hash>/ and their
12
+ * declared skill folders are symlinked into ~/.skillforge/skills/.
13
+ * This means uninstall just removes the symlinks + the cached clone,
14
+ * and updates are a single `git pull`.
15
+ */
16
+ const path = require('path');
17
+ const fs = require('fs');
18
+ const crypto = require('crypto');
19
+ const { spawnSync } = require('child_process');
20
+ const os = require('os');
21
+
22
+ const CONFIG_DIR = path.join(os.homedir(), '.skillforge');
23
+ const PACKS_DIR = path.join(CONFIG_DIR, 'packs');
24
+ const USER_SKILLS_DIR = path.join(CONFIG_DIR, 'skills');
25
+ const PACK_REGISTRY = path.join(CONFIG_DIR, 'packs.json');
26
+
27
+ function ensureDirs() {
28
+ fs.mkdirSync(PACKS_DIR, { recursive: true });
29
+ fs.mkdirSync(USER_SKILLS_DIR, { recursive: true });
30
+ }
31
+
32
+ function loadRegistry() {
33
+ if (!fs.existsSync(PACK_REGISTRY)) return {};
34
+ try { return JSON.parse(fs.readFileSync(PACK_REGISTRY, 'utf8')); }
35
+ catch { return {}; }
36
+ }
37
+
38
+ function saveRegistry(reg) {
39
+ fs.writeFileSync(PACK_REGISTRY, JSON.stringify(reg, null, 2));
40
+ }
41
+
42
+ function normalizeSource(source) {
43
+ // Accept "user/repo", "https://github.com/user/repo", "git@github.com:user/repo.git", or a local path
44
+ if (source.startsWith('http://') || source.startsWith('https://') || source.startsWith('git@')) {
45
+ return { type: 'git', url: source };
46
+ }
47
+ if (source.startsWith('./') || source.startsWith('/') || source.startsWith('~')) {
48
+ return { type: 'local', path: source.replace(/^~/, os.homedir()) };
49
+ }
50
+ // user/repo shorthand → github
51
+ if (/^[\w.-]+\/[\w.-]+$/.test(source)) {
52
+ return { type: 'git', url: `https://github.com/${source}` };
53
+ }
54
+ throw new Error(`Cannot interpret source: ${source}`);
55
+ }
56
+
57
+ function sourceKey(src) {
58
+ return crypto.createHash('sha1').update(JSON.stringify(src)).digest('hex').slice(0, 10);
59
+ }
60
+
61
+ function readManifest(packDir) {
62
+ const mf = path.join(packDir, 'skillforge.json');
63
+ if (!fs.existsSync(mf)) {
64
+ throw new Error(`No skillforge.json found at ${packDir}. A skill pack must have a manifest at its root.`);
65
+ }
66
+ const m = JSON.parse(fs.readFileSync(mf, 'utf8'));
67
+ if (!m.name || !Array.isArray(m.skills)) {
68
+ throw new Error('skillforge.json must have "name" (string) and "skills" (array of folder names)');
69
+ }
70
+ return m;
71
+ }
72
+
73
+ function validateSkills(packDir, manifest) {
74
+ const errors = [];
75
+ for (const s of manifest.skills) {
76
+ const skillPath = path.join(packDir, s);
77
+ if (!fs.existsSync(skillPath)) errors.push(`Listed skill "${s}" not found in pack`);
78
+ else if (!fs.existsSync(path.join(skillPath, 'SKILL.md'))) errors.push(`"${s}" has no SKILL.md`);
79
+ }
80
+ if (errors.length) throw new Error('Pack validation failed:\n - ' + errors.join('\n - '));
81
+ }
82
+
83
+ function linkSkills(packDir, manifest, packKey) {
84
+ const linked = [];
85
+ for (const s of manifest.skills) {
86
+ const target = path.join(USER_SKILLS_DIR, s);
87
+ if (fs.existsSync(target)) {
88
+ const stat = fs.lstatSync(target);
89
+ if (stat.isSymbolicLink()) {
90
+ // Existing pack symlink — overwrite (re-install case)
91
+ fs.unlinkSync(target);
92
+ } else {
93
+ throw new Error(`A skill folder named "${s}" already exists in user skills (not from a pack). Remove it first or rename your pack's skill.`);
94
+ }
95
+ }
96
+ fs.symlinkSync(path.join(packDir, s), target, 'dir');
97
+ linked.push(s);
98
+ }
99
+ return linked;
100
+ }
101
+
102
+ function unlinkSkills(skills) {
103
+ const removed = [];
104
+ for (const s of skills) {
105
+ const target = path.join(USER_SKILLS_DIR, s);
106
+ if (fs.existsSync(target)) {
107
+ const stat = fs.lstatSync(target);
108
+ if (stat.isSymbolicLink()) {
109
+ fs.unlinkSync(target);
110
+ removed.push(s);
111
+ }
112
+ }
113
+ }
114
+ return removed;
115
+ }
116
+
117
+ function installPack(source) {
118
+ ensureDirs();
119
+ const src = normalizeSource(source);
120
+ const key = sourceKey(src);
121
+ const packDir = path.join(PACKS_DIR, key);
122
+
123
+ if (src.type === 'git') {
124
+ if (fs.existsSync(packDir)) {
125
+ // Already cloned — update instead
126
+ const r = spawnSync('git', ['-C', packDir, 'pull', '--ff-only', '--quiet'], { stdio: 'inherit' });
127
+ if (r.status !== 0) throw new Error('git pull failed');
128
+ } else {
129
+ const r = spawnSync('git', ['clone', '--depth', '1', '--quiet', src.url, packDir], { stdio: 'inherit' });
130
+ if (r.status !== 0) throw new Error(`git clone failed for ${src.url}`);
131
+ }
132
+ } else {
133
+ // Local path — symlink the pack dir itself
134
+ if (fs.existsSync(packDir)) fs.rmSync(packDir, { recursive: true, force: true });
135
+ fs.symlinkSync(src.path, packDir, 'dir');
136
+ }
137
+
138
+ const manifest = readManifest(packDir);
139
+ validateSkills(packDir, manifest);
140
+ const linked = linkSkills(packDir, manifest, key);
141
+
142
+ const reg = loadRegistry();
143
+ reg[manifest.name] = {
144
+ source,
145
+ key,
146
+ version: manifest.version || 'unknown',
147
+ skills: linked,
148
+ installed_at: new Date().toISOString(),
149
+ };
150
+ saveRegistry(reg);
151
+ return { name: manifest.name, skills: linked, version: manifest.version };
152
+ }
153
+
154
+ function uninstallPack(name) {
155
+ ensureDirs();
156
+ const reg = loadRegistry();
157
+ const entry = reg[name];
158
+ if (!entry) throw new Error(`No installed pack named "${name}"`);
159
+ const removed = unlinkSkills(entry.skills);
160
+ const packDir = path.join(PACKS_DIR, entry.key);
161
+ if (fs.existsSync(packDir)) {
162
+ const stat = fs.lstatSync(packDir);
163
+ if (stat.isSymbolicLink()) fs.unlinkSync(packDir);
164
+ else fs.rmSync(packDir, { recursive: true, force: true });
165
+ }
166
+ delete reg[name];
167
+ saveRegistry(reg);
168
+ return { name, removed };
169
+ }
170
+
171
+ function listPacks() {
172
+ ensureDirs();
173
+ const reg = loadRegistry();
174
+ return Object.entries(reg).map(([name, e]) => ({ name, ...e }));
175
+ }
176
+
177
+ function updatePack(name) {
178
+ const reg = loadRegistry();
179
+ const entry = reg[name];
180
+ if (!entry) throw new Error(`No installed pack named "${name}"`);
181
+ return installPack(entry.source); // re-runs git pull + relinks
182
+ }
183
+
184
+ module.exports = { installPack, uninstallPack, listPacks, updatePack };
package/package.json ADDED
@@ -0,0 +1,38 @@
1
+ {
2
+ "name": "@heytherevibin/skillforge",
3
+ "version": "0.2.1",
4
+ "description": "Skill orchestration for Claude: hybrid embedding and router-based routing, MCP and HTTP servers, per-user learning, and a large bundled SKILL.md catalog.",
5
+ "keywords": [
6
+ "claude",
7
+ "skills",
8
+ "agent",
9
+ "orchestrator",
10
+ "anthropic",
11
+ "llm",
12
+ "routing"
13
+ ],
14
+ "license": "MIT",
15
+ "bin": {
16
+ "skillforge": "bin/cli.js"
17
+ },
18
+ "files": [
19
+ "bin/",
20
+ "lib/",
21
+ "python/",
22
+ "skills/",
23
+ "README.md",
24
+ "CHANGELOG.md",
25
+ "STRATEGY.md",
26
+ "LICENSE",
27
+ "RELEASING.md",
28
+ "SECURITY.md",
29
+ "CONTRIBUTING.md",
30
+ "CODE_OF_CONDUCT.md"
31
+ ],
32
+ "engines": {
33
+ "node": ">=18.0.0"
34
+ },
35
+ "scripts": {
36
+ "test": "node bin/cli.js --help"
37
+ }
38
+ }
File without changes
@@ -0,0 +1,63 @@
1
+ """
2
+ Bearer-token auth and per-user namespacing.
3
+
4
+ Single-user mode (default): no token required, all state goes to user_id=''.
5
+ Multi-user mode: set SKILLFORGE_AUTH_TOKENS env var to a JSON map of
6
+ {"token-value": "user-id"}. Requests must send Authorization: Bearer <token>.
7
+ The resolved user_id is then used to scope sessions, weights, and events.
8
+
9
+ This keeps the architecture single-process (one SQLite, one router instance)
10
+ while letting each user have isolated learning state.
11
+ """
12
+ from __future__ import annotations
13
+
14
+ import json
15
+ import os
16
+ from typing import Optional
17
+
18
+ from fastapi import HTTPException, Request
19
+
20
+
21
+ # ---- Token registry ----
22
+
23
+ def _load_tokens() -> dict[str, str]:
24
+ """Read SKILLFORGE_AUTH_TOKENS env (JSON: {token: user_id})."""
25
+ raw = os.getenv("SKILLFORGE_AUTH_TOKENS", "").strip()
26
+ if not raw:
27
+ return {}
28
+ try:
29
+ m = json.loads(raw)
30
+ if not isinstance(m, dict):
31
+ print("[skillforge] SKILLFORGE_AUTH_TOKENS must be a JSON object")
32
+ return {}
33
+ return {str(k): str(v) for k, v in m.items()}
34
+ except json.JSONDecodeError:
35
+ print("[skillforge] SKILLFORGE_AUTH_TOKENS is not valid JSON, ignoring")
36
+ return {}
37
+
38
+
39
+ _TOKENS = _load_tokens()
40
+ _AUTH_REQUIRED = bool(_TOKENS)
41
+
42
+
43
+ def auth_enabled() -> bool:
44
+ return _AUTH_REQUIRED
45
+
46
+
47
+ def resolve_user(request: Request) -> str:
48
+ """Get user_id from a request.
49
+
50
+ - If auth is not configured (single-user mode): returns ''.
51
+ - If auth is configured: extracts bearer token, returns mapped user_id,
52
+ or raises 401.
53
+ """
54
+ if not _AUTH_REQUIRED:
55
+ return ""
56
+ header = request.headers.get("authorization", "")
57
+ if not header.lower().startswith("bearer "):
58
+ raise HTTPException(status_code=401, detail="Missing bearer token")
59
+ token = header[7:].strip()
60
+ user_id = _TOKENS.get(token)
61
+ if not user_id:
62
+ raise HTTPException(status_code=401, detail="Invalid token")
63
+ return user_id
@@ -0,0 +1,78 @@
1
+ """Dev harness: terminal client for POST /chat (requires `skillforge start` + API key)."""
2
+ import argparse
3
+ import json
4
+ import sys
5
+ import uuid
6
+
7
+ import httpx
8
+
9
+
10
+ def main():
11
+ ap = argparse.ArgumentParser()
12
+ ap.add_argument("--url", default="http://localhost:8000")
13
+ args = ap.parse_args()
14
+
15
+ session_id = str(uuid.uuid4())
16
+ conversation = []
17
+ print(f"\nskillforge chat — session {session_id[:8]}")
18
+ print("Commands: 'exit' to quit, 'reset' for new session\n")
19
+
20
+ while True:
21
+ try:
22
+ prompt = input("you ▸ ").strip()
23
+ except (EOFError, KeyboardInterrupt):
24
+ print()
25
+ break
26
+ if not prompt:
27
+ continue
28
+ if prompt == "exit":
29
+ break
30
+ if prompt == "reset":
31
+ session_id = str(uuid.uuid4())
32
+ conversation = []
33
+ print(f"[new session: {session_id[:8]}]\n")
34
+ continue
35
+
36
+ full = []
37
+ picked = []
38
+ try:
39
+ with httpx.stream(
40
+ "POST",
41
+ f"{args.url}/chat",
42
+ json={"prompt": prompt, "session_id": session_id, "conversation": conversation},
43
+ timeout=120.0,
44
+ ) as r:
45
+ if r.status_code != 200:
46
+ print(f"[error {r.status_code}] {r.read().decode()}")
47
+ continue
48
+ print("claude ▸ ", end="", flush=True)
49
+ for line in r.iter_lines():
50
+ if not line.startswith("data: "):
51
+ continue
52
+ try:
53
+ data = json.loads(line[6:])
54
+ except json.JSONDecodeError:
55
+ continue
56
+ if "delta" in data:
57
+ sys.stdout.write(data["delta"])
58
+ sys.stdout.flush()
59
+ full.append(data["delta"])
60
+ elif "done" in data:
61
+ picked = data.get("picked", [])
62
+ elif "error" in data:
63
+ print(f"\n[stream error] {data['error']}")
64
+ except httpx.HTTPError as e:
65
+ print(f"\n[connection error] {e}")
66
+ print("Is the server running? Try: skillforge start")
67
+ continue
68
+
69
+ print()
70
+ if picked:
71
+ print(f" \033[2m↳ skills used: {', '.join(picked)}\033[0m")
72
+ print()
73
+ conversation.append({"role": "user", "content": prompt})
74
+ conversation.append({"role": "assistant", "content": "".join(full)})
75
+
76
+
77
+ if __name__ == "__main__":
78
+ main()
@@ -0,0 +1,26 @@
1
+ """Orchestrator SQLite path resolution (stdlib only — safe for lightweight tests)."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import os
6
+ from pathlib import Path
7
+
8
+
9
+ def global_db_path() -> Path:
10
+ return Path(
11
+ os.getenv("SKILLFORGE_DB_PATH", str(Path.home() / ".skillforge" / "data" / "orchestrator.db"))
12
+ )
13
+
14
+
15
+ def resolve_orchestrator_db(project_root: str | None) -> Path:
16
+ """SQLite file: ``<project>/.skillforge/orchestrator.db`` when project_root is set, else global path.
17
+
18
+ If ``project_root`` is empty, falls back to env ``SKILLFORGE_PROJECT_ROOT``, then global.
19
+ """
20
+ pr = (project_root or "").strip()
21
+ if not pr:
22
+ pr = os.getenv("SKILLFORGE_PROJECT_ROOT", "").strip()
23
+ if pr:
24
+ root = Path(pr).expanduser().resolve()
25
+ return root / ".skillforge" / "orchestrator.db"
26
+ return global_db_path()
@@ -0,0 +1,175 @@
1
+ """Print routing/events from Skillforge SQLite (terminal observability)."""
2
+ from __future__ import annotations
3
+
4
+ import argparse
5
+ import json
6
+ import sqlite3
7
+ import time
8
+ from pathlib import Path
9
+
10
+ from app.db_paths import resolve_orchestrator_db
11
+
12
+
13
+ def _format_route_line(ts: float, sid: str | None, prev: dict, verbose: bool) -> str:
14
+ tstr = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(ts))
15
+ picked = prev.get("picked")
16
+ sid12 = (sid or "-")[:12]
17
+ base = f"{tstr} route session={sid12:12} picked={picked}"
18
+ ms = prev.get("route_ms")
19
+ if ms is not None:
20
+ base += f" {ms}ms"
21
+ if prev.get("rerouted"):
22
+ base += " reroute"
23
+ if verbose:
24
+ prompt = (prev.get("prompt") or "")[:120].replace("\n", " ")
25
+ reason = (prev.get("reasoning") or "")[:100].replace("\n", " ")
26
+ if prompt:
27
+ base += f'\n prompt: {prompt}{"…" if len(str(prev.get("prompt") or "")) > 120 else ""}'
28
+ if reason:
29
+ base += f'\n why: {reason}'
30
+ return base
31
+
32
+
33
+ def _print_row(ts: float, sid: str | None, et: str | None, payload: str | None, verbose: bool) -> None:
34
+ prev = json.loads(payload) if payload else {}
35
+ if et == "route" and isinstance(prev, dict):
36
+ print(_format_route_line(ts, sid, prev, verbose))
37
+ return
38
+ extra = ""
39
+ if et == "feedback" and isinstance(prev, dict):
40
+ extra = f" skill={prev.get('skill')} thumbs={prev.get('thumbs')}"
41
+ tstr = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(ts))
42
+ print(f"{tstr} {et or '?'} session={sid or '-':12}{extra}")
43
+
44
+
45
+ def _print_snapshot(
46
+ con: sqlite3.Connection,
47
+ user_id: str,
48
+ recent_minutes: float,
49
+ *,
50
+ db_path: Path | None = None,
51
+ ) -> None:
52
+ """Usage totals + recently active sessions (routes), for live CLI."""
53
+ since = time.time() - recent_minutes * 60.0
54
+ cur = con.execute(
55
+ "SELECT skill_name, uses, referenced FROM skill_weights WHERE user_id = ? AND uses > 0 "
56
+ "ORDER BY uses DESC LIMIT 12",
57
+ (user_id,),
58
+ )
59
+ usage = cur.fetchall()
60
+ cur = con.execute(
61
+ """
62
+ SELECT session_id, MAX(ts) AS mt
63
+ FROM events
64
+ WHERE ts >= ? AND event_type = 'route' AND user_id = ?
65
+ GROUP BY session_id
66
+ ORDER BY mt DESC
67
+ LIMIT 15
68
+ """,
69
+ (since, user_id),
70
+ )
71
+ sessions = cur.fetchall()
72
+ line = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())
73
+ print(f"── [{line}] skillforge live ──")
74
+ if db_path is not None:
75
+ print(f" SQLite: {db_path}")
76
+ if usage:
77
+ ubits = [f"{n} uses={u} ref={r}" for n, u, r in usage]
78
+ print(" Top skills:", "; ".join(ubits))
79
+ else:
80
+ print(" Top skills: (no route stats yet for this user_id)")
81
+ if sessions:
82
+ short = [f"{(s or '-')[:10]}…" if s and len(s) > 10 else (s or "-") for s, _ in sessions]
83
+ print(f" Active sessions (routes in last {int(recent_minutes)}m): {len(sessions)} —", ", ".join(short))
84
+ else:
85
+ print(f" Active sessions: none in last {int(recent_minutes)}m")
86
+ print("── new events ──")
87
+
88
+
89
+ def main() -> None:
90
+ ap = argparse.ArgumentParser(
91
+ description="Skillforge event log (SQLite). Use --watch for realtime usage + routes."
92
+ )
93
+ ap.add_argument("--limit", type=int, default=40)
94
+ ap.add_argument("--watch", action="store_true", help="Poll for new rows (default interval 2s)")
95
+ ap.add_argument("--poll", type=float, default=2.0, help="Seconds between polls in --watch mode")
96
+ ap.add_argument(
97
+ "--summary-every",
98
+ type=float,
99
+ default=15.0,
100
+ metavar="SEC",
101
+ help="In --watch mode, re-print usage snapshot every SEC seconds (0 = only at start)",
102
+ )
103
+ ap.add_argument(
104
+ "--recent-minutes",
105
+ type=float,
106
+ default=60.0,
107
+ help="Window for 'active sessions' in snapshots (default 60)",
108
+ )
109
+ ap.add_argument(
110
+ "--user",
111
+ default="",
112
+ help="Logical user id for stats/sessions (matches MCP SKILLFORGE_MCP_USER_ID / HTTP user). Default empty.",
113
+ )
114
+ ap.add_argument(
115
+ "--project-root",
116
+ default="",
117
+ help="Workspace root — reads <root>/.skillforge/orchestrator.db. Default: env SKILLFORGE_PROJECT_ROOT or global DB.",
118
+ )
119
+ ap.add_argument("-v", "--verbose", action="store_true", help="More detail on route lines")
120
+ args = ap.parse_args()
121
+
122
+ pr = (args.project_root or "").strip() or None
123
+ db_path = resolve_orchestrator_db(pr)
124
+
125
+ if not db_path.exists():
126
+ print("No database yet — run skillforge mcp or skillforge start first (or route once with this project_root).")
127
+ print(f" Expected: {db_path}")
128
+ return
129
+
130
+ if args.watch:
131
+ con = sqlite3.connect(str(db_path))
132
+ row = con.execute("SELECT COALESCE(MAX(ts), 0) FROM events").fetchone()
133
+ con.close()
134
+ last_max = float(row[0]) if row else 0.0
135
+ summary_every = args.summary_every
136
+ next_summary = time.monotonic()
137
+ first = True
138
+ try:
139
+ while True:
140
+ now_m = time.monotonic()
141
+ if first or (summary_every > 0 and now_m >= next_summary):
142
+ con = sqlite3.connect(str(db_path))
143
+ _print_snapshot(con, args.user, args.recent_minutes, db_path=db_path)
144
+ con.close()
145
+ first = False
146
+ next_summary = now_m + summary_every
147
+ con = sqlite3.connect(str(db_path))
148
+ cur = con.execute(
149
+ "SELECT ts, session_id, event_type, payload FROM events WHERE ts > ? ORDER BY ts ASC",
150
+ (last_max,),
151
+ )
152
+ rows = cur.fetchall()
153
+ con.close()
154
+ for ts, sid, et, pay in rows:
155
+ _print_row(ts, sid, et, pay, args.verbose)
156
+ last_max = max(last_max, float(ts))
157
+ time.sleep(max(0.5, args.poll))
158
+ except KeyboardInterrupt:
159
+ print()
160
+ else:
161
+ con = sqlite3.connect(str(db_path))
162
+ _print_snapshot(con, args.user, args.recent_minutes, db_path=db_path)
163
+ cur = con.execute(
164
+ "SELECT ts, session_id, event_type, payload FROM events ORDER BY ts DESC LIMIT ?",
165
+ (args.limit,),
166
+ )
167
+ rows = cur.fetchall()
168
+ con.close()
169
+ print("── recent events (newest first) ──")
170
+ for ts, sid, et, pay in rows:
171
+ _print_row(ts, sid, et, pay, args.verbose)
172
+
173
+
174
+ if __name__ == "__main__":
175
+ main()