@hasna/skills 0.1.62 → 0.1.64

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 (541) hide show
  1. package/README.md +38 -12
  2. package/bin/index.js +15743 -21709
  3. package/bin/mcp.js +3866 -11522
  4. package/bin/migrate.js +281 -35
  5. package/bin/server.js +5805 -2682
  6. package/bin/worker.js +5280 -2388
  7. package/dist/cli/commands/publish.d.ts +2 -0
  8. package/dist/cli/commands/registry-reconcile.d.ts +2 -0
  9. package/dist/cli/components/App.d.ts +2 -1
  10. package/dist/cli/components/CategorySelect.d.ts +2 -1
  11. package/dist/cli/components/Header.d.ts +2 -1
  12. package/dist/cli/components/InstallProgress.d.ts +2 -1
  13. package/dist/cli/components/SearchView.d.ts +2 -1
  14. package/dist/cli/components/SkillSelect.d.ts +2 -1
  15. package/dist/index.d.ts +5 -2
  16. package/dist/index.js +5386 -13739
  17. package/dist/lib/agent-sync.d.ts +61 -6
  18. package/dist/lib/auth-store.d.ts +37 -0
  19. package/dist/lib/config.d.ts +51 -0
  20. package/dist/lib/home-adoption.d.ts +91 -0
  21. package/dist/lib/home-census.d.ts +26 -0
  22. package/dist/lib/home-migration.d.ts +60 -0
  23. package/dist/lib/native-storage.d.ts +1 -1
  24. package/dist/lib/portable-skills-files.d.ts +21 -1
  25. package/dist/lib/portable-skills-types.d.ts +46 -0
  26. package/dist/lib/portable-skills.d.ts +35 -6
  27. package/dist/lib/pull.d.ts +97 -0
  28. package/dist/lib/registry-reconcile.d.ts +114 -0
  29. package/dist/lib/registry.d.ts +7 -4
  30. package/dist/lib/remote-client.d.ts +124 -1
  31. package/dist/lib/remote-registry.d.ts +26 -0
  32. package/dist/lib/revision.d.ts +29 -0
  33. package/dist/lib/run-state.d.ts +5 -0
  34. package/dist/lib/skill-bundles.d.ts +54 -0
  35. package/dist/lib/skill-contract.d.ts +35 -0
  36. package/dist/lib/skill-hash.d.ts +77 -0
  37. package/dist/sdk/cancel.d.ts +30 -0
  38. package/dist/sdk/dispatcher.d.ts +40 -0
  39. package/dist/sdk/event-sink.d.ts +2 -0
  40. package/dist/sdk/events.d.ts +79 -0
  41. package/dist/sdk/execution/admission.d.ts +44 -0
  42. package/dist/sdk/execution/dispatchers/e2b.d.ts +17 -0
  43. package/dist/sdk/execution/dispatchers/ecs.d.ts +151 -0
  44. package/dist/sdk/execution/image-profile.d.ts +73 -0
  45. package/dist/sdk/execution/index.d.ts +15 -0
  46. package/dist/sdk/execution/receipts.d.ts +44 -0
  47. package/dist/sdk/execution/state-machine.d.ts +38 -0
  48. package/dist/sdk/execution/storage.d.ts +158 -0
  49. package/dist/sdk/execution/types.d.ts +130 -0
  50. package/dist/sdk/executor.d.ts +17 -0
  51. package/dist/sdk/governance-store.d.ts +156 -0
  52. package/dist/sdk/governance.d.ts +92 -0
  53. package/dist/sdk/index.d.ts +26 -0
  54. package/dist/sdk/index.js +49728 -0
  55. package/dist/sdk/offline.d.ts +16 -0
  56. package/dist/sdk/outputs.d.ts +71 -0
  57. package/dist/sdk/registry.d.ts +28 -0
  58. package/dist/sdk/runs.d.ts +229 -0
  59. package/dist/sdk/server.d.ts +35 -0
  60. package/dist/sdk/spend.d.ts +36 -0
  61. package/dist/sdk/storage.d.ts +25 -0
  62. package/dist/server/app.d.ts +42 -0
  63. package/dist/server/artifact-storage.d.ts +102 -0
  64. package/dist/server/auth.d.ts +5 -0
  65. package/dist/server/config.d.ts +50 -0
  66. package/dist/server/database-url.d.ts +42 -0
  67. package/dist/server/handlers.d.ts +3 -0
  68. package/dist/server/index.d.ts +2 -0
  69. package/dist/server/migrate.d.ts +13 -0
  70. package/dist/server/migrations-dir.d.ts +18 -0
  71. package/dist/server/redaction.d.ts +1 -0
  72. package/dist/server/registry.d.ts +5 -0
  73. package/dist/server/rows.d.ts +24 -0
  74. package/dist/server/skills-api.d.ts +170 -0
  75. package/dist/server/sqlite-store.d.ts +131 -0
  76. package/dist/server/store-fixtures.d.ts +25 -0
  77. package/dist/server/store.d.ts +170 -0
  78. package/dist/server/types.d.ts +337 -0
  79. package/dist/server/worker.d.ts +4 -0
  80. package/dist/storage.js +39 -2
  81. package/docs/skill-standard.md +211 -39
  82. package/migrations/postgres/0003_run_outputs_governance.sql +83 -0
  83. package/migrations/postgres/0004_hosted_pins.sql +28 -0
  84. package/migrations/postgres/0005_revision_tombstone_registry.sql +37 -0
  85. package/migrations/postgres/0005_tag_projection.sql +36 -0
  86. package/migrations/sqlite/0003_run_outputs_governance.sql +58 -0
  87. package/migrations/sqlite/0004_hosted_pins.sql +21 -0
  88. package/migrations/sqlite/0005_revision_tombstone_registry.sql +18 -0
  89. package/migrations/sqlite/0005_tag_projection.sql +25 -0
  90. package/package.json +12 -8
  91. package/schemas/skill.schema.json +181 -0
  92. package/agent-skills/README.md +0 -41
  93. package/agent-skills/fleet-package-rollout/SKILL.md +0 -169
  94. package/agent-skills/inbox/SKILL.md +0 -25
  95. package/agent-skills/inbox/scripts/inbox +0 -109
  96. package/agent-skills/inbox/tests/test_registered_sender_id.sh +0 -92
  97. package/agent-skills/inbox-monitor/SKILL.md +0 -41
  98. package/agent-skills/inbox-monitor/scripts/inbox_monitor.sh +0 -91
  99. package/agent-skills/inbox-monitor/scripts/test_inbox_monitor.sh +0 -71
  100. package/agent-skills/merge-pr/SKILL.md +0 -85
  101. package/agent-skills/merge-pr/references/merge-safety.md +0 -82
  102. package/agent-skills/merge-pr/scripts/merge_pr_guard.py +0 -694
  103. package/agent-skills/merge-pr/scripts/test_merge_pr_guard.py +0 -647
  104. package/agent-skills/merge-pr/tests/fixtures/multi-commit-synthesized.json +0 -28
  105. package/agent-skills/merge-pr/tests/fixtures/trailer-free-provider.json +0 -28
  106. package/agent-skills/skill-goal-execute/SKILL.md +0 -115
  107. package/agent-skills/skill-login/SKILL.md +0 -109
  108. package/agent-skills/skill-project-create/SKILL.md +0 -91
  109. package/agent-skills/skill-publish/SKILL.md +0 -254
  110. package/agent-skills/skill-publish/scripts/capture_registry.js +0 -47
  111. package/agent-skills/skill-publish/scripts/publish_with_git_head.sh +0 -143
  112. package/agent-skills/skill-publish/scripts/test_publish_with_git_head.sh +0 -231
  113. package/skills/_common/auth.ts +0 -45
  114. package/skills/_common/http-client.ts +0 -143
  115. package/skills/_common/index.ts +0 -26
  116. package/skills/_common/install.sh +0 -7
  117. package/skills/_common/installer.ts +0 -72
  118. package/skills/_common/skill-install.ts +0 -37
  119. package/skills/_common/vision.ts +0 -374
  120. package/skills/ad-creative-pack/SKILL.md +0 -55
  121. package/skills/ad-creative-pack/package.json +0 -10
  122. package/skills/analyze-data/CLAUDE.md +0 -16
  123. package/skills/analyze-data/SKILL.md +0 -112
  124. package/skills/analyze-data/package.json +0 -23
  125. package/skills/analyze-data/src/analysis.ts +0 -401
  126. package/skills/analyze-data/src/cli.ts +0 -66
  127. package/skills/analyze-data/src/formatters.ts +0 -235
  128. package/skills/analyze-data/src/index.ts +0 -74
  129. package/skills/analyze-data/src/logger.ts +0 -36
  130. package/skills/analyze-data/src/parsers.ts +0 -57
  131. package/skills/analyze-data/src/stats.ts +0 -151
  132. package/skills/analyze-data/src/types.ts +0 -85
  133. package/skills/analyze-data/tsconfig.json +0 -19
  134. package/skills/api-docs-portal/SKILL.md +0 -84
  135. package/skills/api-docs-portal/package.json +0 -35
  136. package/skills/api-docs-portal/src/index.ts +0 -919
  137. package/skills/api-docs-portal/tsconfig.json +0 -17
  138. package/skills/api-test-suite/CLAUDE.md +0 -19
  139. package/skills/api-test-suite/package.json +0 -27
  140. package/skills/api-test-suite/src/index.ts +0 -381
  141. package/skills/api-test-suite/tsconfig.json +0 -10
  142. package/skills/audio-extract/CLAUDE.md +0 -9
  143. package/skills/audio-extract/SKILL.md +0 -73
  144. package/skills/audio-extract/package.json +0 -23
  145. package/skills/audio-extract/src/index.ts +0 -323
  146. package/skills/audio-extract/tsconfig.json +0 -11
  147. package/skills/bio-sequence-tool/CLAUDE.md +0 -19
  148. package/skills/bio-sequence-tool/package.json +0 -27
  149. package/skills/bio-sequence-tool/src/index.ts +0 -85
  150. package/skills/bio-sequence-tool/tsconfig.json +0 -10
  151. package/skills/blog-article/CLAUDE.md +0 -12
  152. package/skills/blog-article/SKILL.md +0 -55
  153. package/skills/blog-article/package.json +0 -10
  154. package/skills/blog-article/tsconfig.json +0 -10
  155. package/skills/brand-assets/SKILL.md +0 -118
  156. package/skills/brand-assets/package.json +0 -35
  157. package/skills/brand-assets/src/cli.ts +0 -155
  158. package/skills/brand-assets/src/constants.ts +0 -8
  159. package/skills/brand-assets/src/extract.ts +0 -236
  160. package/skills/brand-assets/src/index.ts +0 -668
  161. package/skills/brand-assets/src/types.ts +0 -59
  162. package/skills/brand-assets/tsconfig.json +0 -17
  163. package/skills/brand-kit/SKILL.md +0 -54
  164. package/skills/brand-kit/package.json +0 -10
  165. package/skills/businessactivity/CLAUDE.md +0 -176
  166. package/skills/businessactivity/LICENSE +0 -192
  167. package/skills/businessactivity/README.md +0 -287
  168. package/skills/businessactivity/package.json +0 -25
  169. package/skills/businessactivity/scripts/publish.ts +0 -210
  170. package/skills/businessactivity/src/commands/activity.ts +0 -211
  171. package/skills/businessactivity/src/commands/function.ts +0 -227
  172. package/skills/businessactivity/src/commands/owner.ts +0 -193
  173. package/skills/businessactivity/src/commands/profile.ts +0 -121
  174. package/skills/businessactivity/src/commands/responsibility.ts +0 -264
  175. package/skills/businessactivity/src/commands/team.ts +0 -244
  176. package/skills/businessactivity/src/commands/workflow.ts +0 -359
  177. package/skills/businessactivity/src/index.ts +0 -3
  178. package/skills/businessactivity/src/lib/config.ts +0 -167
  179. package/skills/businessactivity/src/lib/output.ts +0 -76
  180. package/skills/businessactivity/src/lib/paths.ts +0 -79
  181. package/skills/businessactivity/src/lib/storage.ts +0 -95
  182. package/skills/businessactivity/src/types/index.ts +0 -86
  183. package/skills/businessactivity/tsconfig.json +0 -29
  184. package/skills/codefix/LICENSE +0 -192
  185. package/skills/codefix/README.md +0 -232
  186. package/skills/codefix/SKILL.md +0 -94
  187. package/skills/codefix/package.json +0 -21
  188. package/skills/codefix/src/fixers/batch.ts +0 -213
  189. package/skills/codefix/src/fixers/detector.ts +0 -160
  190. package/skills/codefix/src/fixers/index.ts +0 -7
  191. package/skills/codefix/src/fixers/runner.ts +0 -522
  192. package/skills/codefix/src/index-local.ts +0 -431
  193. package/skills/codefix/src/index.ts +0 -4
  194. package/skills/codefix/src/types.ts +0 -211
  195. package/skills/codefix/tsconfig.json +0 -15
  196. package/skills/commitpush/SKILL.md +0 -57
  197. package/skills/commitpush/package.json +0 -33
  198. package/skills/commitpush/src/index.ts +0 -34
  199. package/skills/commitpush/tsconfig.json +0 -17
  200. package/skills/commitpushpr/SKILL.md +0 -55
  201. package/skills/commitpushpr/package.json +0 -33
  202. package/skills/commitpushpr/src/index.ts +0 -34
  203. package/skills/commitpushpr/tsconfig.json +0 -17
  204. package/skills/compress-video/CLAUDE.md +0 -9
  205. package/skills/compress-video/SKILL.md +0 -79
  206. package/skills/compress-video/package.json +0 -23
  207. package/skills/compress-video/src/index.ts +0 -473
  208. package/skills/compress-video/tsconfig.json +0 -11
  209. package/skills/contract-review-report/SKILL.md +0 -52
  210. package/skills/contract-review-report/package.json +0 -10
  211. package/skills/customer-feedback-report/SKILL.md +0 -52
  212. package/skills/customer-feedback-report/package.json +0 -10
  213. package/skills/dashboard-builder/CLAUDE.md +0 -19
  214. package/skills/dashboard-builder/package.json +0 -29
  215. package/skills/dashboard-builder/src/index.ts +0 -150
  216. package/skills/dashboard-builder/tsconfig.json +0 -10
  217. package/skills/data-anonymizer/CLAUDE.md +0 -19
  218. package/skills/data-anonymizer/package.json +0 -27
  219. package/skills/data-anonymizer/src/index.ts +0 -183
  220. package/skills/data-anonymizer/tsconfig.json +0 -10
  221. package/skills/database-explorer/CLAUDE.md +0 -19
  222. package/skills/database-explorer/package.json +0 -29
  223. package/skills/database-explorer/src/index.ts +0 -95
  224. package/skills/database-explorer/tsconfig.json +0 -10
  225. package/skills/diff-viewer/CLAUDE.md +0 -19
  226. package/skills/diff-viewer/package.json +0 -30
  227. package/skills/diff-viewer/src/index.ts +0 -164
  228. package/skills/diff-viewer/tsconfig.json +0 -10
  229. package/skills/doc-read/SKILL.md +0 -45
  230. package/skills/doc-read/package.json +0 -29
  231. package/skills/doc-read/src/index.ts +0 -324
  232. package/skills/doc-read/tsconfig.json +0 -8
  233. package/skills/domainpurchase/LICENSE +0 -192
  234. package/skills/domainpurchase/SKILL.md +0 -29
  235. package/skills/domainpurchase/package.json +0 -30
  236. package/skills/domainpurchase/src/index.ts +0 -3
  237. package/skills/domainpurchase/tsconfig.json +0 -21
  238. package/skills/email-sequence/SKILL.md +0 -53
  239. package/skills/email-sequence/package.json +0 -10
  240. package/skills/experiment-power-calculator/CLAUDE.md +0 -19
  241. package/skills/experiment-power-calculator/package.json +0 -29
  242. package/skills/experiment-power-calculator/src/index.ts +0 -86
  243. package/skills/experiment-power-calculator/tsconfig.json +0 -10
  244. package/skills/extract-frames/CLAUDE.md +0 -19
  245. package/skills/extract-frames/package.json +0 -27
  246. package/skills/extract-frames/src/index.ts +0 -616
  247. package/skills/extract-frames/tsconfig.json +0 -10
  248. package/skills/file-organizer/CLAUDE.md +0 -19
  249. package/skills/file-organizer/package.json +0 -27
  250. package/skills/file-organizer/src/index.ts +0 -91
  251. package/skills/file-organizer/tsconfig.json +0 -10
  252. package/skills/folder-tree/CLAUDE.md +0 -19
  253. package/skills/folder-tree/package.json +0 -29
  254. package/skills/folder-tree/src/index.ts +0 -568
  255. package/skills/folder-tree/tsconfig.json +0 -10
  256. package/skills/form-filler/CLAUDE.md +0 -19
  257. package/skills/form-filler/package.json +0 -29
  258. package/skills/form-filler/src/index.ts +0 -81
  259. package/skills/form-filler/tsconfig.json +0 -10
  260. package/skills/generate-api-client/CLAUDE.md +0 -19
  261. package/skills/generate-api-client/package.json +0 -29
  262. package/skills/generate-api-client/src/generator.ts +0 -47
  263. package/skills/generate-api-client/src/index.ts +0 -92
  264. package/skills/generate-api-client/src/logger.ts +0 -34
  265. package/skills/generate-api-client/src/python-generator.ts +0 -245
  266. package/skills/generate-api-client/src/spec-loader.ts +0 -48
  267. package/skills/generate-api-client/src/type-mappers.ts +0 -79
  268. package/skills/generate-api-client/src/types.ts +0 -76
  269. package/skills/generate-api-client/src/typescript-generator.ts +0 -247
  270. package/skills/generate-api-client/tsconfig.json +0 -10
  271. package/skills/generate-chart/CLAUDE.md +0 -19
  272. package/skills/generate-chart/package.json +0 -27
  273. package/skills/generate-chart/src/index.ts +0 -510
  274. package/skills/generate-chart/tsconfig.json +0 -10
  275. package/skills/generate-dockerfile/CLAUDE.md +0 -19
  276. package/skills/generate-dockerfile/package.json +0 -27
  277. package/skills/generate-dockerfile/src/cli.ts +0 -78
  278. package/skills/generate-dockerfile/src/dockerfile-templates.ts +0 -392
  279. package/skills/generate-dockerfile/src/index.ts +0 -81
  280. package/skills/generate-dockerfile/src/logger.ts +0 -30
  281. package/skills/generate-dockerfile/src/project-detection.ts +0 -68
  282. package/skills/generate-dockerfile/src/support-files.ts +0 -171
  283. package/skills/generate-dockerfile/src/types.ts +0 -29
  284. package/skills/generate-dockerfile/tsconfig.json +0 -10
  285. package/skills/generate-env/CLAUDE.md +0 -19
  286. package/skills/generate-env/package.json +0 -29
  287. package/skills/generate-env/src/cli.ts +0 -85
  288. package/skills/generate-env/src/detection.ts +0 -161
  289. package/skills/generate-env/src/env-data.ts +0 -66
  290. package/skills/generate-env/src/generators.ts +0 -240
  291. package/skills/generate-env/src/index.ts +0 -120
  292. package/skills/generate-env/src/runtime.ts +0 -30
  293. package/skills/generate-env/src/types.ts +0 -32
  294. package/skills/generate-env/tsconfig.json +0 -10
  295. package/skills/generate-favicon/CLAUDE.md +0 -19
  296. package/skills/generate-favicon/package.json +0 -29
  297. package/skills/generate-favicon/src/index.ts +0 -421
  298. package/skills/generate-favicon/tsconfig.json +0 -10
  299. package/skills/generate-qrcode/CLAUDE.md +0 -19
  300. package/skills/generate-qrcode/package.json +0 -30
  301. package/skills/generate-qrcode/src/index.ts +0 -584
  302. package/skills/generate-qrcode/tsconfig.json +0 -10
  303. package/skills/generate-resume/CLAUDE.md +0 -19
  304. package/skills/generate-resume/package.json +0 -27
  305. package/skills/generate-resume/src/cli.ts +0 -157
  306. package/skills/generate-resume/src/index.ts +0 -178
  307. package/skills/generate-resume/src/parsers.ts +0 -95
  308. package/skills/generate-resume/src/renderers.ts +0 -538
  309. package/skills/generate-resume/src/security.ts +0 -39
  310. package/skills/generate-resume/src/types.ts +0 -86
  311. package/skills/generate-resume/tsconfig.json +0 -10
  312. package/skills/generate-sitemap/CLAUDE.md +0 -19
  313. package/skills/generate-sitemap/package.json +0 -27
  314. package/skills/generate-sitemap/src/index.ts +0 -626
  315. package/skills/generate-sitemap/tsconfig.json +0 -10
  316. package/skills/gif-maker/CLAUDE.md +0 -19
  317. package/skills/gif-maker/package.json +0 -30
  318. package/skills/gif-maker/src/index.ts +0 -600
  319. package/skills/gif-maker/tsconfig.json +0 -10
  320. package/skills/hook/LICENSE +0 -192
  321. package/skills/hook/README.md +0 -74
  322. package/skills/hook/SKILL.md +0 -85
  323. package/skills/hook/bunfig.toml +0 -5
  324. package/skills/hook/package.json +0 -28
  325. package/skills/hook/src/commands/create.ts +0 -112
  326. package/skills/hook/src/commands/events.ts +0 -37
  327. package/skills/hook/src/commands/validate.ts +0 -117
  328. package/skills/hook/src/index.ts +0 -118
  329. package/skills/hook/src/templates/root.ts +0 -196
  330. package/skills/hook/src/templates/source.ts +0 -647
  331. package/skills/hook/tsconfig.json +0 -18
  332. package/skills/http-server/CLAUDE.md +0 -19
  333. package/skills/http-server/package.json +0 -29
  334. package/skills/http-server/src/index.ts +0 -51
  335. package/skills/http-server/tsconfig.json +0 -10
  336. package/skills/implementation/LICENSE +0 -192
  337. package/skills/implementation/README.md +0 -53
  338. package/skills/implementation/SKILL.md +0 -57
  339. package/skills/implementation/bunfig.toml +0 -5
  340. package/skills/implementation/package.json +0 -28
  341. package/skills/implementation/src/commands/create.ts +0 -187
  342. package/skills/implementation/src/index.ts +0 -62
  343. package/skills/implementation/tsconfig.json +0 -18
  344. package/skills/implementation-plan/CLAUDE.md +0 -19
  345. package/skills/implementation-plan/package.json +0 -29
  346. package/skills/implementation-plan/src/index.ts +0 -520
  347. package/skills/implementation-plan/tsconfig.json +0 -10
  348. package/skills/implementation-todo/CLAUDE.md +0 -19
  349. package/skills/implementation-todo/package.json +0 -29
  350. package/skills/implementation-todo/src/index.ts +0 -429
  351. package/skills/implementation-todo/tsconfig.json +0 -10
  352. package/skills/invoice/.env.example +0 -3
  353. package/skills/invoice/CLAUDE.md +0 -31
  354. package/skills/invoice/LICENSE +0 -192
  355. package/skills/invoice/README.md +0 -70
  356. package/skills/invoice/package.json +0 -26
  357. package/skills/invoice/src/commands/companies.ts +0 -202
  358. package/skills/invoice/src/commands/config.ts +0 -132
  359. package/skills/invoice/src/commands/generate.ts +0 -177
  360. package/skills/invoice/src/commands/invoices.ts +0 -218
  361. package/skills/invoice/src/index.ts +0 -3
  362. package/skills/invoice/src/lib/api.ts +0 -124
  363. package/skills/invoice/src/lib/storage.ts +0 -171
  364. package/skills/invoice/src/types/index.ts +0 -86
  365. package/skills/invoice/src/utils/logger.ts +0 -33
  366. package/skills/invoice/src/utils/paths.ts +0 -25
  367. package/skills/invoice/tsconfig.json +0 -23
  368. package/skills/invoice-reconciliation/SKILL.md +0 -98
  369. package/skills/invoice-reconciliation/package.json +0 -36
  370. package/skills/invoice-reconciliation/src/index.ts +0 -743
  371. package/skills/invoice-reconciliation/tsconfig.json +0 -17
  372. package/skills/landing-page-pack/SKILL.md +0 -55
  373. package/skills/landing-page-pack/package.json +0 -10
  374. package/skills/latex-table-generator/CLAUDE.md +0 -19
  375. package/skills/latex-table-generator/package.json +0 -29
  376. package/skills/latex-table-generator/src/index.ts +0 -113
  377. package/skills/latex-table-generator/tsconfig.json +0 -10
  378. package/skills/logo-design/SKILL.md +0 -94
  379. package/skills/logo-design/package.json +0 -35
  380. package/skills/logo-design/src/cli.ts +0 -132
  381. package/skills/logo-design/src/constants.ts +0 -5
  382. package/skills/logo-design/src/docs.ts +0 -102
  383. package/skills/logo-design/src/geometry.ts +0 -324
  384. package/skills/logo-design/src/index.ts +0 -212
  385. package/skills/logo-design/src/palette.ts +0 -258
  386. package/skills/logo-design/src/types.ts +0 -50
  387. package/skills/logo-design/tsconfig.json +0 -17
  388. package/skills/lorem-generator/CLAUDE.md +0 -19
  389. package/skills/lorem-generator/package.json +0 -29
  390. package/skills/lorem-generator/src/index.ts +0 -59
  391. package/skills/lorem-generator/tsconfig.json +0 -10
  392. package/skills/managemcp/CLAUDE.md +0 -14
  393. package/skills/managemcp/README.md +0 -24
  394. package/skills/managemcp/package.json +0 -16
  395. package/skills/managemcp/src/index.ts +0 -3
  396. package/skills/managemcp/tsconfig.json +0 -27
  397. package/skills/markdown-validator/CLAUDE.md +0 -19
  398. package/skills/markdown-validator/package.json +0 -29
  399. package/skills/markdown-validator/src/index.ts +0 -92
  400. package/skills/markdown-validator/tsconfig.json +0 -10
  401. package/skills/market-research-report/SKILL.md +0 -51
  402. package/skills/market-research-report/package.json +0 -10
  403. package/skills/meeting-pack/SKILL.md +0 -52
  404. package/skills/meeting-pack/package.json +0 -10
  405. package/skills/merge-pdfs/CLAUDE.md +0 -19
  406. package/skills/merge-pdfs/package.json +0 -31
  407. package/skills/merge-pdfs/src/index.ts +0 -427
  408. package/skills/merge-pdfs/tsconfig.json +0 -10
  409. package/skills/migration-plan-pack/SKILL.md +0 -56
  410. package/skills/migration-plan-pack/package.json +0 -10
  411. package/skills/monitor/SKILL.md +0 -69
  412. package/skills/monitor/package.json +0 -33
  413. package/skills/monitor/src/index.ts +0 -34
  414. package/skills/monitor/tsconfig.json +0 -17
  415. package/skills/one-page-website/SKILL.md +0 -128
  416. package/skills/one-page-website/package.json +0 -34
  417. package/skills/one-page-website/src/design.ts +0 -336
  418. package/skills/one-page-website/src/docs.ts +0 -159
  419. package/skills/one-page-website/src/index.ts +0 -357
  420. package/skills/one-page-website/src/page.ts +0 -340
  421. package/skills/one-page-website/src/styles.ts +0 -508
  422. package/skills/one-page-website/src/types.ts +0 -78
  423. package/skills/one-page-website/tsconfig.json +0 -17
  424. package/skills/pdf-generate/CLAUDE.md +0 -19
  425. package/skills/pdf-generate/SKILL.md +0 -86
  426. package/skills/pdf-generate/package.json +0 -21
  427. package/skills/pdf-generate/src/cli.ts +0 -162
  428. package/skills/pdf-generate/src/html.ts +0 -84
  429. package/skills/pdf-generate/src/index.ts +0 -62
  430. package/skills/pdf-generate/src/markdown.ts +0 -27
  431. package/skills/pdf-generate/src/pdf-writer.ts +0 -78
  432. package/skills/pdf-generate/src/runtime.ts +0 -34
  433. package/skills/pdf-generate/src/security.ts +0 -37
  434. package/skills/pdf-generate/src/templates.ts +0 -311
  435. package/skills/pdf-generate/src/types.ts +0 -28
  436. package/skills/pdf-generate/tsconfig.json +0 -16
  437. package/skills/pdf-to-dataset/SKILL.md +0 -88
  438. package/skills/pdf-to-dataset/package.json +0 -37
  439. package/skills/pdf-to-dataset/src/index.ts +0 -790
  440. package/skills/pdf-to-dataset/tsconfig.json +0 -17
  441. package/skills/pdf-to-markdown/SKILL.md +0 -81
  442. package/skills/pdf-to-markdown/package.json +0 -35
  443. package/skills/pdf-to-markdown/src/index.ts +0 -694
  444. package/skills/pdf-to-markdown/tsconfig.json +0 -17
  445. package/skills/performance-audit-report/SKILL.md +0 -49
  446. package/skills/performance-audit-report/package.json +0 -10
  447. package/skills/pitch-deck/SKILL.md +0 -51
  448. package/skills/pitch-deck/package.json +0 -10
  449. package/skills/product-mockup/SKILL.md +0 -107
  450. package/skills/product-mockup/package.json +0 -32
  451. package/skills/product-mockup/src/cli.ts +0 -150
  452. package/skills/product-mockup/src/design.ts +0 -151
  453. package/skills/product-mockup/src/docs.ts +0 -134
  454. package/skills/product-mockup/src/index.ts +0 -182
  455. package/skills/product-mockup/src/render.ts +0 -407
  456. package/skills/product-mockup/src/types.ts +0 -66
  457. package/skills/product-mockup/tsconfig.json +0 -17
  458. package/skills/proposal-pack/SKILL.md +0 -53
  459. package/skills/proposal-pack/package.json +0 -10
  460. package/skills/read-csv/SKILL.md +0 -62
  461. package/skills/read-csv/package.json +0 -37
  462. package/skills/read-csv/src/index.ts +0 -356
  463. package/skills/read-csv/tsconfig.json +0 -17
  464. package/skills/read-excel/SKILL.md +0 -64
  465. package/skills/read-excel/package.json +0 -36
  466. package/skills/read-excel/src/index.ts +0 -266
  467. package/skills/read-excel/tsconfig.json +0 -17
  468. package/skills/regex-tester/CLAUDE.md +0 -19
  469. package/skills/regex-tester/package.json +0 -27
  470. package/skills/regex-tester/src/index.ts +0 -183
  471. package/skills/regex-tester/tsconfig.json +0 -10
  472. package/skills/repo-onboarding-report/SKILL.md +0 -52
  473. package/skills/repo-onboarding-report/package.json +0 -10
  474. package/skills/scancommitpr/SKILL.md +0 -178
  475. package/skills/scancommitpr/package.json +0 -34
  476. package/skills/scancommitpr/src/index.ts +0 -44
  477. package/skills/scancommitpr/tsconfig.json +0 -13
  478. package/skills/scancommitpush/SKILL.md +0 -174
  479. package/skills/scancommitpush/package.json +0 -32
  480. package/skills/scancommitpush/src/index.ts +0 -44
  481. package/skills/scancommitpush/tsconfig.json +0 -13
  482. package/skills/scientific-figure-check/CLAUDE.md +0 -19
  483. package/skills/scientific-figure-check/package.json +0 -29
  484. package/skills/scientific-figure-check/src/index.ts +0 -83
  485. package/skills/scientific-figure-check/tsconfig.json +0 -10
  486. package/skills/security-audit/CLAUDE.md +0 -19
  487. package/skills/security-audit/package.json +0 -27
  488. package/skills/security-audit/src/index.ts +0 -145
  489. package/skills/security-audit/tsconfig.json +0 -10
  490. package/skills/security-audit-report/SKILL.md +0 -52
  491. package/skills/security-audit-report/package.json +0 -10
  492. package/skills/seo-content-pack/SKILL.md +0 -54
  493. package/skills/seo-content-pack/package.json +0 -10
  494. package/skills/siteanalyze/SKILL.md +0 -25
  495. package/skills/siteanalyze/package.json +0 -27
  496. package/skills/siteanalyze/src/index.ts +0 -592
  497. package/skills/slide-deck-generator/SKILL.md +0 -93
  498. package/skills/slide-deck-generator/package.json +0 -38
  499. package/skills/slide-deck-generator/src/cli.ts +0 -133
  500. package/skills/slide-deck-generator/src/index.ts +0 -148
  501. package/skills/slide-deck-generator/src/model.ts +0 -307
  502. package/skills/slide-deck-generator/src/pptx.ts +0 -143
  503. package/skills/slide-deck-generator/src/render.ts +0 -248
  504. package/skills/slide-deck-generator/src/types.ts +0 -114
  505. package/skills/slide-deck-generator/src/utils.ts +0 -53
  506. package/skills/slide-deck-generator/tsconfig.json +0 -17
  507. package/skills/social-content-calendar/SKILL.md +0 -54
  508. package/skills/social-content-calendar/package.json +0 -10
  509. package/skills/split-pdf/CLAUDE.md +0 -19
  510. package/skills/split-pdf/package.json +0 -30
  511. package/skills/split-pdf/src/index.ts +0 -301
  512. package/skills/split-pdf/tsconfig.json +0 -10
  513. package/skills/statistical-test-selector/CLAUDE.md +0 -19
  514. package/skills/statistical-test-selector/package.json +0 -27
  515. package/skills/statistical-test-selector/src/index.ts +0 -75
  516. package/skills/statistical-test-selector/tsconfig.json +0 -10
  517. package/skills/test-suite-generator/SKILL.md +0 -51
  518. package/skills/test-suite-generator/package.json +0 -10
  519. package/skills/tmux-session/SKILL.md +0 -109
  520. package/skills/tmux-session/package.json +0 -33
  521. package/skills/tmux-session/src/index.ts +0 -34
  522. package/skills/tmux-session/tsconfig.json +0 -17
  523. package/skills/todos-plan/SKILL.md +0 -363
  524. package/skills/todos-plan/agents/openai.yaml +0 -4
  525. package/skills/todos-plan/package.json +0 -9
  526. package/skills/todos-plan/src/index.ts +0 -68
  527. package/skills/tsconfig.base.json +0 -12
  528. package/skills/validate-config/CLAUDE.md +0 -19
  529. package/skills/validate-config/package.json +0 -29
  530. package/skills/validate-config/src/index.ts +0 -56
  531. package/skills/validate-config/tsconfig.json +0 -10
  532. package/skills/video-downloader/CLAUDE.md +0 -19
  533. package/skills/video-downloader/package.json +0 -29
  534. package/skills/video-downloader/src/index.ts +0 -561
  535. package/skills/video-downloader/tsconfig.json +0 -10
  536. package/skills/video-highlight-pack/SKILL.md +0 -54
  537. package/skills/video-highlight-pack/package.json +0 -10
  538. package/skills/watermark/CLAUDE.md +0 -19
  539. package/skills/watermark/package.json +0 -32
  540. package/skills/watermark/src/index.ts +0 -587
  541. package/skills/watermark/tsconfig.json +0 -10
package/bin/migrate.js CHANGED
@@ -59,8 +59,10 @@ function resolveServerConfig(env = process.env) {
59
59
  artifactBucket: env.HASNA_SKILLS_S3_BUCKET || env.SKILLS_S3_BUCKET || undefined,
60
60
  artifactPrefix: normalizePrefix(env.HASNA_SKILLS_S3_PREFIX || env.SKILLS_S3_PREFIX || "skills/artifacts"),
61
61
  inlineWorker: env.HASNA_SKILLS_INLINE_WORKER === "1",
62
+ bundleSigningKey: env.HASNA_SKILLS_API_SIGNING_KEY || env.HASNA_SKILLS_SIGNING_KEY || undefined,
62
63
  requestBodyLimitBytes: parsePositiveInt(env.HASNA_SKILLS_REQUEST_BODY_LIMIT_BYTES, 1e6),
63
64
  skillBundleLimitBytes: parsePositiveInt(env.HASNA_SKILLS_BUNDLE_LIMIT_BYTES, 25000000),
65
+ tombstoneWindowMs: parsePositiveInt(env.HASNA_SKILLS_TOMBSTONE_WINDOW_MS, 7 * 24 * 60 * 60 * 1000),
64
66
  publicBaseUrl: (env.SKILLS_PUBLIC_BASE_URL || localOrigin(host, port)).replace(/\/+$/, ""),
65
67
  nodeEnv,
66
68
  allowEphemeralStore: env.HASNA_SKILLS_ALLOW_EPHEMERAL_STORE === "1"
@@ -273,6 +275,7 @@ var ANY_SEGMENT_EXCLUDES = new Set([
273
275
  ".docker"
274
276
  ]);
275
277
  var ROOT_EXCLUDES = new Set(["dist", "build", ".turbo"]);
278
+ var TOOL_SIDECAR_FILENAMES = new Set([".hasna-skills.json"]);
276
279
  var CREDENTIAL_FILENAMES = new Set([
277
280
  ".npmrc",
278
281
  ".pypirc",
@@ -412,6 +415,7 @@ function rowToRun(row) {
412
415
  ...typeof row.idempotency_key === "string" ? { idempotencyKey: row.idempotency_key } : {},
413
416
  correlationId: String(row.correlation_id),
414
417
  costCents: Number(row.cost_cents ?? 0),
418
+ leaseGeneration: Number(row.lease_generation ?? 0),
415
419
  ...typeof row.output_type === "string" ? { outputType: row.output_type } : {},
416
420
  ...typeof row.output_preview === "string" ? { outputPreview: row.output_preview } : {},
417
421
  ...typeof row.error_code === "string" ? { errorCode: row.error_code } : {},
@@ -443,6 +447,8 @@ function rowToArtifact(row) {
443
447
  storageKind: String(row.storage_kind),
444
448
  ...typeof row.storage_key === "string" ? { storageKey: row.storage_key } : {},
445
449
  ...typeof row.body_text === "string" ? { bodyText: row.body_text } : {},
450
+ visibility: String(row.visibility ?? "private") === "public" ? "public" : "private",
451
+ ...row.expires_at ? { expiresAt: dateString(row.expires_at) } : {},
446
452
  createdAt: dateString(row.created_at)
447
453
  };
448
454
  }
@@ -462,7 +468,20 @@ function rowToSkill(row) {
462
468
  ...row.bundle_byte_size === null || row.bundle_byte_size === undefined ? {} : { bundleByteSize: Number(row.bundle_byte_size) },
463
469
  ...typeof row.published_by_user_id === "string" ? { publishedByUserId: row.published_by_user_id } : {},
464
470
  createdAt: dateString(row.created_at),
465
- updatedAt: dateString(row.updated_at)
471
+ updatedAt: dateString(row.updated_at),
472
+ revisionId: String(row.revision_id ?? ""),
473
+ revisionNumber: Number(row.revision_number ?? 0),
474
+ ...row.tombstoned_at ? { tombstonedAt: dateString(row.tombstoned_at) } : {},
475
+ ...row.tombstone_purge_after ? { tombstonePurgeAfter: dateString(row.tombstone_purge_after) } : {}
476
+ };
477
+ }
478
+ function rowToPin(row) {
479
+ return {
480
+ orgId: String(row.org_id),
481
+ principal: String(row.principal),
482
+ slug: String(row.slug),
483
+ pinnedAt: dateString(row.pinned_at),
484
+ metadata: parseJsonObject(row.metadata_json)
466
485
  };
467
486
  }
468
487
  function rowToSkillBundle(row) {
@@ -514,9 +533,61 @@ function dateString(value) {
514
533
  return String(value);
515
534
  }
516
535
 
536
+ // src/server/types.ts
537
+ class StaleLeaseGenerationError extends Error {
538
+ runId;
539
+ expectedGeneration;
540
+ currentGeneration;
541
+ status;
542
+ constructor(runId2, expectedGeneration, currentGeneration, status) {
543
+ super(`late transition rejected for run ${runId2}: expected lease_generation ${expectedGeneration}, ` + `current ${currentGeneration} (status ${status})`);
544
+ this.name = "StaleLeaseGenerationError";
545
+ this.runId = runId2;
546
+ this.expectedGeneration = expectedGeneration;
547
+ this.currentGeneration = currentGeneration;
548
+ this.status = status;
549
+ }
550
+ }
551
+
552
+ class SkillRevisionConflictError extends Error {
553
+ slug;
554
+ expectedRevisionId;
555
+ currentRevisionId;
556
+ constructor(slug, expectedRevisionId, currentRevisionId) {
557
+ super(`revision conflict for '${slug}': expected revision ${expectedRevisionId ?? "(none)"}, ` + `current is ${currentRevisionId ?? "(none)"}. Refused rather than silently overwriting a newer revision.`);
558
+ this.name = "SkillRevisionConflictError";
559
+ this.slug = slug;
560
+ this.expectedRevisionId = expectedRevisionId;
561
+ this.currentRevisionId = currentRevisionId;
562
+ }
563
+ }
564
+
565
+ // src/lib/revision.ts
566
+ import { createHash as createHash2 } from "crypto";
567
+ function revisionIdOf(content) {
568
+ const canonical = JSON.stringify({
569
+ slug: content.slug,
570
+ displayName: content.displayName,
571
+ description: content.description,
572
+ category: content.category,
573
+ tags: content.tags,
574
+ source: content.source,
575
+ kind: content.kind,
576
+ version: content.version ?? null,
577
+ skillMd: content.skillMd ?? null,
578
+ bundleSha256: content.bundleSha256 ?? null,
579
+ bundleByteSize: content.bundleByteSize ?? null
580
+ });
581
+ return createHash2("sha256").update(canonical).digest("hex");
582
+ }
583
+ function revisionIdOfRecord(record) {
584
+ return revisionIdOf(record);
585
+ }
586
+
517
587
  // src/server/sqlite-store.ts
518
588
  var CLAIM_ATTEMPTS = 8;
519
589
  var CLAIMABLE_STATUSES = ["queued", "retrying"];
590
+ var NO_REVISION_SENTINEL = "0000000000000000000000000000000000000000000000000000000000000000";
520
591
  var LAST_USED_RESOLUTION_MS = 60000;
521
592
 
522
593
  class SqliteSkillsStore {
@@ -536,12 +607,24 @@ class SqliteSkillsStore {
536
607
  if (options.migrate !== false) {
537
608
  applySqliteMigrations(this.db, options.migrationsDir);
538
609
  }
610
+ this.backfillLegacyRevisions();
539
611
  this.backend = {
540
612
  kind: "sqlite",
541
613
  durable: !inMemory,
542
614
  label: inMemory ? "sqlite (in-memory)" : `sqlite (${path})`
543
615
  };
544
616
  }
617
+ backfillLegacyRevisions() {
618
+ const rows = this.all("SELECT * FROM skills_registry WHERE revision_id = ''", []);
619
+ for (const row of rows) {
620
+ const record = rowToSkill(row);
621
+ this.db.run("UPDATE skills_registry SET revision_id = ? WHERE org_id = ? AND slug = ?", [
622
+ revisionIdOfRecord(record),
623
+ record.orgId,
624
+ record.slug
625
+ ]);
626
+ }
627
+ }
545
628
  get database() {
546
629
  return this.db;
547
630
  }
@@ -648,7 +731,8 @@ class SqliteSkillsStore {
648
731
  const id = String(candidate.id);
649
732
  const now = nowIso();
650
733
  const result = this.db.run(`UPDATE skills_runs
651
- SET status = 'running', started_at = COALESCE(started_at, ?), locked_by = ?, locked_at = ?
734
+ SET status = 'running', started_at = COALESCE(started_at, ?), locked_by = ?, locked_at = ?,
735
+ lease_generation = lease_generation + 1
652
736
  WHERE id = ? AND status IN (${CLAIMABLE_STATUSES.map(() => "?").join(", ")})`, [now, workerId, now, id, ...CLAIMABLE_STATUSES]);
653
737
  if (result.changes !== 1) {
654
738
  this.db.exec("ROLLBACK");
@@ -687,6 +771,33 @@ class SqliteSkillsStore {
687
771
  ]);
688
772
  return row ? rowToRun(row) : null;
689
773
  }
774
+ async transitionRun(id, patch, expectedGeneration) {
775
+ const current = this.get("SELECT * FROM skills_runs WHERE id = ? LIMIT 1", [id]);
776
+ if (!current)
777
+ return null;
778
+ const stored = rowToRun(current);
779
+ if (stored.leaseGeneration !== expectedGeneration) {
780
+ throw new StaleLeaseGenerationError(id, expectedGeneration, stored.leaseGeneration, stored.status);
781
+ }
782
+ const run = { ...stored, ...patch };
783
+ const row = this.get(`UPDATE skills_runs
784
+ SET status = ?, output_type = ?, output_preview = ?, error_code = ?, error_message = ?, started_at = ?, completed_at = ?,
785
+ lease_generation = ?
786
+ WHERE id = ? AND lease_generation = ?
787
+ RETURNING *`, [
788
+ run.status,
789
+ run.outputType ?? null,
790
+ run.outputPreview ?? null,
791
+ run.errorCode ?? null,
792
+ run.errorMessage ?? null,
793
+ run.startedAt ?? null,
794
+ run.completedAt ?? null,
795
+ run.leaseGeneration,
796
+ id,
797
+ expectedGeneration
798
+ ]);
799
+ return row ? rowToRun(row) : null;
800
+ }
690
801
  async appendLog(id, orgId, level, message) {
691
802
  const row = this.get(`INSERT INTO skills_run_logs (run_id, org_id, sequence, level, message, created_at)
692
803
  VALUES (?, ?, (SELECT COALESCE(MAX(sequence), 0) + 1 FROM skills_run_logs WHERE run_id = ?), ?, ?, ?)
@@ -700,8 +811,8 @@ class SqliteSkillsStore {
700
811
  ORDER BY l.sequence ASC`, [principal.orgId, id]).map(rowToLog);
701
812
  }
702
813
  async addArtifact(artifact) {
703
- const row = this.get(`INSERT INTO skills_artifacts (id, run_id, org_id, file_name, relative_path, content_type, byte_size, sha256, storage_kind, storage_key, body_text, created_at)
704
- VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
814
+ const row = this.get(`INSERT INTO skills_artifacts (id, run_id, org_id, file_name, relative_path, content_type, byte_size, sha256, storage_kind, storage_key, body_text, visibility, expires_at, created_at)
815
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
705
816
  RETURNING *`, [
706
817
  artifact.id,
707
818
  artifact.runId,
@@ -714,6 +825,8 @@ class SqliteSkillsStore {
714
825
  artifact.storageKind,
715
826
  artifact.storageKey ?? null,
716
827
  artifact.bodyText ?? null,
828
+ artifact.visibility,
829
+ artifact.expiresAt ?? null,
717
830
  nowIso()
718
831
  ]);
719
832
  return rowToArtifact(row);
@@ -735,8 +848,29 @@ class SqliteSkillsStore {
735
848
  const orgId = input.principal.orgId;
736
849
  const now = nowIso();
737
850
  return this.db.transaction(() => {
738
- const previous = this.get("SELECT bundle_sha256 FROM skills_registry WHERE org_id = ? AND slug = ?", [orgId, input.slug]);
851
+ const previous = this.get("SELECT revision_id, revision_number, bundle_sha256, bundle_byte_size, skill_md, tombstoned_at FROM skills_registry WHERE org_id = ? AND slug = ?", [orgId, input.slug]);
739
852
  const previousSha = typeof previous?.bundle_sha256 === "string" ? previous.bundle_sha256 : null;
853
+ const previousRevisionId = typeof previous?.revision_id === "string" && previous.revision_id ? previous.revision_id : null;
854
+ const tombstoned = previous?.tombstoned_at != null;
855
+ const carriedSkillMd = typeof input.skillMd === "string" ? input.skillMd : typeof previous?.skill_md === "string" ? previous.skill_md : null;
856
+ if (previous && !tombstoned && input.expectedRevisionId !== previousRevisionId) {
857
+ throw new SkillRevisionConflictError(input.slug, input.expectedRevisionId, previousRevisionId);
858
+ }
859
+ const carriedSha = input.bundle?.sha256 ?? previousSha;
860
+ const carriedSize = input.bundle?.byteSize ?? (previous?.bundle_byte_size == null ? null : Number(previous.bundle_byte_size));
861
+ const revisionId = revisionIdOfRecord({
862
+ slug: input.slug,
863
+ displayName: input.displayName,
864
+ description: input.description,
865
+ category: input.category,
866
+ tags: input.tags,
867
+ source: input.source,
868
+ kind: input.kind,
869
+ ...input.version ? { version: input.version } : {},
870
+ ...carriedSkillMd ? { skillMd: carriedSkillMd } : {},
871
+ ...carriedSha ? { bundleSha256: carriedSha } : {},
872
+ ...carriedSize === null || carriedSize === undefined ? {} : { bundleByteSize: carriedSize }
873
+ });
740
874
  if (input.bundle) {
741
875
  this.db.run(`INSERT INTO skills_bundles (org_id, sha256, byte_size, content_type, storage_kind, storage_key, body_blob, created_at)
742
876
  VALUES (?, ?, ?, ?, ?, ?, ?, ?)
@@ -757,8 +891,8 @@ class SqliteSkillsStore {
757
891
  ]);
758
892
  }
759
893
  const row = this.get(`INSERT INTO skills_registry (org_id, slug, display_name, description, category, tags_json, source, kind, version, skill_md,
760
- bundle_sha256, bundle_byte_size, published_by_user_id, created_at, updated_at)
761
- VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
894
+ bundle_sha256, bundle_byte_size, published_by_user_id, revision_id, revision_number, created_at, updated_at)
895
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, 1, ?, ?)
762
896
  ON CONFLICT (org_id, slug) DO UPDATE SET
763
897
  display_name = excluded.display_name,
764
898
  description = excluded.description,
@@ -776,7 +910,16 @@ class SqliteSkillsStore {
776
910
  bundle_sha256 = COALESCE(excluded.bundle_sha256, skills_registry.bundle_sha256),
777
911
  bundle_byte_size = COALESCE(excluded.bundle_byte_size, skills_registry.bundle_byte_size),
778
912
  published_by_user_id = excluded.published_by_user_id,
913
+ revision_id = excluded.revision_id,
914
+ -- Current + 1, not the inserted 1: on the update path the ACTUAL row's
915
+ -- counter is the truth (it may have advanced since the pre-read, which is
916
+ -- exactly what the WHERE guard below detects).
917
+ revision_number = skills_registry.revision_number + 1,
918
+ tombstoned_at = NULL,
919
+ tombstone_purge_after = NULL,
779
920
  updated_at = excluded.updated_at
921
+ WHERE skills_registry.tombstoned_at IS NOT NULL
922
+ OR skills_registry.revision_id = ?
780
923
  RETURNING *`, [
781
924
  orgId,
782
925
  input.slug,
@@ -787,62 +930,165 @@ class SqliteSkillsStore {
787
930
  input.source,
788
931
  input.kind,
789
932
  input.version ?? null,
790
- input.skillMd ?? null,
933
+ carriedSkillMd,
791
934
  input.bundle?.sha256 ?? null,
792
935
  input.bundle?.byteSize ?? null,
793
936
  input.principal.userId,
937
+ revisionId,
938
+ now,
794
939
  now,
795
- now
940
+ input.expectedRevisionId ?? NO_REVISION_SENTINEL
796
941
  ]);
942
+ if (!row) {
943
+ const current = this.get("SELECT revision_id FROM skills_registry WHERE org_id = ? AND slug = ?", [orgId, input.slug]);
944
+ const currentId = typeof current?.revision_id === "string" ? current.revision_id : null;
945
+ throw new SkillRevisionConflictError(input.slug, input.expectedRevisionId, currentId);
946
+ }
797
947
  if (previousSha && input.bundle && previousSha !== input.bundle.sha256)
798
948
  this.collectOrphanBundle(orgId, previousSha);
949
+ this.db.run("DELETE FROM skills_tags WHERE org_id = ? AND slug = ?", [orgId, input.slug]);
950
+ const insertTag = this.db.prepare("INSERT OR IGNORE INTO skills_tags (org_id, slug, tag) VALUES (?, ?, ?)");
951
+ for (const tag of input.tags) {
952
+ if (!tag.trim())
953
+ continue;
954
+ insertTag.run(orgId, input.slug, tag);
955
+ }
799
956
  return rowToSkill(row);
800
957
  })();
801
958
  }
802
959
  async listSkills(principal) {
803
- return this.all("SELECT * FROM skills_registry WHERE org_id = ? ORDER BY slug ASC", [principal.orgId]).map(rowToSkill);
960
+ await this.purgeExpiredTombstones(principal);
961
+ return this.all("SELECT * FROM skills_registry WHERE org_id = ? AND tombstoned_at IS NULL ORDER BY slug ASC", [principal.orgId]).map(rowToSkill);
804
962
  }
805
963
  async getSkill(principal, slug) {
806
964
  const row = this.get("SELECT * FROM skills_registry WHERE org_id = ? AND slug = ? LIMIT 1", [principal.orgId, slug]);
807
965
  return row ? rowToSkill(row) : null;
808
966
  }
809
- async updateSkill(principal, slug, patch) {
967
+ async updateSkill(principal, slug, patch, expectedRevisionId) {
810
968
  const current = await this.getSkill(principal, slug);
811
- if (!current)
969
+ if (!current || current.tombstonedAt)
812
970
  return null;
971
+ if (expectedRevisionId !== current.revisionId) {
972
+ throw new SkillRevisionConflictError(slug, expectedRevisionId, current.revisionId);
973
+ }
813
974
  const next = { ...current, ...patch };
814
- const row = this.get(`UPDATE skills_registry
815
- SET display_name = ?, description = ?, category = ?, tags_json = ?, kind = ?, version = ?, skill_md = ?, updated_at = ?
816
- WHERE org_id = ? AND slug = ?
817
- RETURNING *`, [
818
- next.displayName,
819
- next.description,
820
- next.category,
821
- JSON.stringify(next.tags),
822
- next.kind,
823
- next.version ?? null,
824
- next.skillMd ?? null,
825
- nowIso(),
826
- principal.orgId,
827
- slug
828
- ]);
829
- return row ? rowToSkill(row) : null;
975
+ return this.db.transaction(() => {
976
+ const revisionId = revisionIdOfRecord(next);
977
+ const row = this.get(`UPDATE skills_registry
978
+ SET display_name = ?, description = ?, category = ?, tags_json = ?, kind = ?, version = ?, skill_md = ?,
979
+ revision_id = ?, revision_number = revision_number + 1, updated_at = ?
980
+ WHERE org_id = ? AND slug = ? AND tombstoned_at IS NULL AND revision_id = ?
981
+ RETURNING *`, [
982
+ next.displayName,
983
+ next.description,
984
+ next.category,
985
+ JSON.stringify(next.tags),
986
+ next.kind,
987
+ next.version ?? null,
988
+ next.skillMd ?? null,
989
+ revisionId,
990
+ nowIso(),
991
+ principal.orgId,
992
+ slug,
993
+ current.revisionId
994
+ ]);
995
+ if (!row) {
996
+ const nowRow = this.get("SELECT revision_id, tombstoned_at FROM skills_registry WHERE org_id = ? AND slug = ? LIMIT 1", [
997
+ principal.orgId,
998
+ slug
999
+ ]);
1000
+ if (nowRow && nowRow.tombstoned_at == null) {
1001
+ const currentId = typeof nowRow.revision_id === "string" ? nowRow.revision_id : null;
1002
+ throw new SkillRevisionConflictError(slug, expectedRevisionId, currentId);
1003
+ }
1004
+ return null;
1005
+ }
1006
+ this.db.run("DELETE FROM skills_tags WHERE org_id = ? AND slug = ?", [principal.orgId, slug]);
1007
+ const insertTag = this.db.prepare("INSERT OR IGNORE INTO skills_tags (org_id, slug, tag) VALUES (?, ?, ?)");
1008
+ for (const tag of next.tags) {
1009
+ if (!tag.trim())
1010
+ continue;
1011
+ insertTag.run(principal.orgId, slug, tag);
1012
+ }
1013
+ return rowToSkill(row);
1014
+ })();
830
1015
  }
831
- async deleteSkill(principal, slug) {
1016
+ async deleteSkill(principal, slug, tombstoneWindowMs) {
832
1017
  return this.db.transaction(() => {
833
- const existing = this.get("SELECT bundle_sha256 FROM skills_registry WHERE org_id = ? AND slug = ?", [principal.orgId, slug]);
1018
+ const existing = this.get("SELECT tombstoned_at FROM skills_registry WHERE org_id = ? AND slug = ?", [principal.orgId, slug]);
834
1019
  if (!existing)
835
- return false;
836
- this.db.run("DELETE FROM skills_registry WHERE org_id = ? AND slug = ?", [principal.orgId, slug]);
837
- if (typeof existing.bundle_sha256 === "string")
838
- this.collectOrphanBundle(principal.orgId, existing.bundle_sha256);
839
- return true;
1020
+ return null;
1021
+ if (existing.tombstoned_at != null) {
1022
+ const row2 = this.get("SELECT * FROM skills_registry WHERE org_id = ? AND slug = ? LIMIT 1", [principal.orgId, slug]);
1023
+ return rowToSkill(row2);
1024
+ }
1025
+ const tombstonedAt = nowIso();
1026
+ const purgeAfter = new Date(Date.now() + tombstoneWindowMs).toISOString();
1027
+ const row = this.get(`UPDATE skills_registry
1028
+ SET tombstoned_at = ?, tombstone_purge_after = ?, updated_at = ?
1029
+ WHERE org_id = ? AND slug = ?
1030
+ RETURNING *`, [tombstonedAt, purgeAfter, tombstonedAt, principal.orgId, slug]);
1031
+ return rowToSkill(row);
1032
+ })();
1033
+ }
1034
+ async purgeExpiredTombstones(principal) {
1035
+ return this.db.transaction(() => {
1036
+ const now = nowIso();
1037
+ const expired = this.all("SELECT * FROM skills_registry WHERE org_id = ? AND tombstoned_at IS NOT NULL AND tombstone_purge_after <= ?", [principal.orgId, now]);
1038
+ const purged = [];
1039
+ for (const row of expired) {
1040
+ const record = rowToSkill(row);
1041
+ this.db.run("DELETE FROM skills_registry WHERE org_id = ? AND slug = ?", [principal.orgId, record.slug]);
1042
+ this.db.run("DELETE FROM skills_tags WHERE org_id = ? AND slug = ?", [principal.orgId, record.slug]);
1043
+ if (record.bundleSha256)
1044
+ this.collectOrphanBundle(principal.orgId, record.bundleSha256);
1045
+ purged.push(record);
1046
+ }
1047
+ return purged;
840
1048
  })();
841
1049
  }
842
1050
  async getSkillBundle(principal, sha256) {
843
1051
  const row = this.get("SELECT * FROM skills_bundles WHERE org_id = ? AND sha256 = ? LIMIT 1", [principal.orgId, sha256]);
844
1052
  return row ? rowToSkillBundle(row) : null;
845
1053
  }
1054
+ async pinSkill(principal, slug, metadata = {}) {
1055
+ const row = this.get(`INSERT INTO skills_pins (org_id, principal, slug, pinned_at, metadata_json)
1056
+ VALUES (?, ?, ?, ?, ?)
1057
+ ON CONFLICT (org_id, principal, slug) DO UPDATE SET
1058
+ pinned_at = excluded.pinned_at,
1059
+ metadata_json = excluded.metadata_json
1060
+ RETURNING *`, [principal.orgId, principal.apiKeyId, slug, nowIso(), JSON.stringify(metadata)]);
1061
+ return rowToPin(row);
1062
+ }
1063
+ async unpinSkill(principal, slug) {
1064
+ const result = this.db.run("DELETE FROM skills_pins WHERE org_id = ? AND principal = ? AND slug = ?", [principal.orgId, principal.apiKeyId, slug]);
1065
+ return result.changes > 0;
1066
+ }
1067
+ async listPins(principal) {
1068
+ return this.all("SELECT * FROM skills_pins WHERE org_id = ? AND principal = ? ORDER BY slug ASC", [principal.orgId, principal.apiKeyId]).map(rowToPin);
1069
+ }
1070
+ async listTags(principal) {
1071
+ await this.purgeExpiredTombstones(principal);
1072
+ return this.all("SELECT DISTINCT tag FROM skills_tags WHERE org_id = ? ORDER BY tag ASC", [principal.orgId]).map((row) => String(row.tag));
1073
+ }
1074
+ async listSkillsByTag(principal, tag) {
1075
+ await this.purgeExpiredTombstones(principal);
1076
+ return this.all(`SELECT s.* FROM skills_registry s
1077
+ JOIN skills_tags t ON t.org_id = s.org_id AND t.slug = s.slug
1078
+ WHERE t.org_id = ? AND t.tag = ? AND s.tombstoned_at IS NULL
1079
+ ORDER BY s.slug ASC`, [principal.orgId, tag]).map(rowToSkill);
1080
+ }
1081
+ async listPinsByTag(principal, tag) {
1082
+ await this.purgeExpiredTombstones(principal);
1083
+ return this.all(`SELECT p.* FROM skills_pins p
1084
+ JOIN skills_tags t ON t.org_id = p.org_id AND t.slug = p.slug
1085
+ JOIN skills_registry s ON s.org_id = p.org_id AND s.slug = p.slug
1086
+ WHERE p.org_id = ? AND p.principal = ? AND t.tag = ? AND s.tombstoned_at IS NULL
1087
+ ORDER BY p.slug ASC`, [principal.orgId, principal.apiKeyId, tag]).map(rowToPin);
1088
+ }
1089
+ async listPublishedSlugs(principal) {
1090
+ return this.all("SELECT slug FROM skills_registry WHERE org_id = ? AND tombstoned_at IS NULL ORDER BY slug ASC", [principal.orgId]).map((row) => String(row.slug));
1091
+ }
846
1092
  collectOrphanBundle(orgId, sha256) {
847
1093
  const referenced = this.get("SELECT 1 AS present FROM skills_registry WHERE org_id = ? AND bundle_sha256 = ? LIMIT 1", [orgId, sha256]);
848
1094
  if (referenced)