@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
@@ -1,743 +0,0 @@
1
- #!/usr/bin/env bun
2
-
3
- import { mkdir, readFile, stat, writeFile } from "fs/promises";
4
- import { join, resolve } from "path";
5
-
6
- const VERSION = "0.1.0";
7
-
8
- type Bucket =
9
- | "matched"
10
- | "short-paid"
11
- | "over-paid"
12
- | "duplicate-payment"
13
- | "unpaid-invoice"
14
- | "orphan-payment";
15
-
16
- interface CliOptions {
17
- invoices?: string;
18
- payments?: string;
19
- output: string;
20
- tolerance: number;
21
- currency: string;
22
- json: boolean;
23
- }
24
-
25
- interface SourceRow {
26
- index: number;
27
- raw: Record<string, string>;
28
- id: string;
29
- key: string;
30
- amount: number | null;
31
- date: string;
32
- party: string;
33
- }
34
-
35
- interface ColumnMap {
36
- id: string | null;
37
- amount: string | null;
38
- date: string | null;
39
- party: string | null;
40
- }
41
-
42
- interface ResultRow {
43
- [column: string]: string;
44
- invoice_id: string;
45
- status: Bucket;
46
- invoice_amount: string;
47
- paid_amount: string;
48
- difference: string;
49
- payment_count: string;
50
- invoice_date: string;
51
- payment_date: string;
52
- party: string;
53
- note: string;
54
- }
55
-
56
- interface Anomaly {
57
- type: string;
58
- invoiceId: string | null;
59
- detail: string;
60
- rows?: number[];
61
- }
62
-
63
- interface Summary {
64
- generatedAt: string;
65
- currency: string;
66
- tolerance: number;
67
- inputs: {
68
- invoices: string | null;
69
- payments: string | null;
70
- invoiceColumns: ColumnMap;
71
- paymentColumns: ColumnMap;
72
- invoiceRows: number;
73
- paymentRows: number;
74
- };
75
- buckets: Record<Bucket, { count: number; invoiced: number; paid: number; difference: number }>;
76
- totals: {
77
- invoiced: number;
78
- paid: number;
79
- difference: number;
80
- matchRate: number;
81
- };
82
- anomalyCount: number;
83
- outputDir: string;
84
- files: string[];
85
- }
86
-
87
- /* ------------------------------------------------------------------ *
88
- * dependency loading
89
- * ------------------------------------------------------------------ */
90
-
91
- type ParseFn = (input: string, options: Record<string, unknown>) => Array<Record<string, string>>;
92
- type StringifyFn = (rows: Array<Record<string, string>>, options: { header: boolean; columns: string[] }) => string;
93
-
94
- async function loadCsvParse(): Promise<ParseFn> {
95
- try {
96
- return (await import("csv-parse/sync")).parse as unknown as ParseFn;
97
- } catch {
98
- throw new Error("Missing dependency 'csv-parse'. Run bun install in this skill directory.");
99
- }
100
- }
101
-
102
- async function loadCsvStringify(): Promise<StringifyFn> {
103
- try {
104
- return (await import("csv-stringify/sync")).stringify as unknown as StringifyFn;
105
- } catch {
106
- throw new Error("Missing dependency 'csv-stringify'. Run bun install in this skill directory.");
107
- }
108
- }
109
-
110
- /* ------------------------------------------------------------------ *
111
- * CLI
112
- * ------------------------------------------------------------------ */
113
-
114
- function printHelp(): void {
115
- console.log(`invoice-reconciliation v${VERSION}
116
-
117
- USAGE:
118
- invoice-reconciliation --invoices <invoices.csv> --payments <payments.csv> [options]
119
-
120
- OPTIONS:
121
- --invoices <path> CSV export of invoices (required)
122
- --payments <path> CSV export of payments (required)
123
- -o, --output <dir> Output directory (default: ./reconciliation)
124
- -t, --tolerance <n> Amount tolerance for an exact match (default: 0.01)
125
- -c, --currency <code> Currency label used in reports (default: USD)
126
- --json Print the summary as JSON on stdout
127
- --help Show this help message
128
- --version Show the current version
129
-
130
- COLUMN DETECTION:
131
- Invoice id invoice_id, invoice, invoice_no, invoice_number, id, number,
132
- reference, ref, bill_id, doc_number
133
- Amount amount, total, amount_due, invoice_amount, paid_amount, value,
134
- gross, balance, sum
135
- Date date, paid_at, payment_date, invoice_date, issue_date, due_date,
136
- created_at, posted_at
137
- Party customer, client, vendor, supplier, account, payer, company
138
-
139
- OUTPUT FILES:
140
- matched.csv Invoices whose payments settle within the tolerance
141
- discrepancies.csv Short-paid, over-paid, unpaid, duplicate, and orphan rows
142
- anomalies.json Structured anomaly list (duplicates, unparseable amounts...)
143
- summary.json Bucket counts and totals
144
-
145
- EXAMPLES:
146
- invoice-reconciliation --invoices ./invoices.csv --payments ./payments.csv
147
- invoice-reconciliation --invoices ./inv.csv --payments ./pay.csv --tolerance 1 --json
148
- `);
149
- }
150
-
151
- function parseArgs(argv: string[]): CliOptions {
152
- const options: CliOptions = {
153
- output: "./reconciliation",
154
- tolerance: 0.01,
155
- currency: "USD",
156
- json: false,
157
- };
158
-
159
- for (let i = 0; i < argv.length; i += 1) {
160
- const arg = argv[i];
161
- switch (arg) {
162
- case "--help":
163
- case "-h":
164
- printHelp();
165
- process.exit(0);
166
- case "--version":
167
- case "-v":
168
- console.log(VERSION);
169
- process.exit(0);
170
- case "--invoices":
171
- case "-i":
172
- options.invoices = argv[++i];
173
- break;
174
- case "--payments":
175
- case "-p":
176
- options.payments = argv[++i];
177
- break;
178
- case "--output":
179
- case "-o":
180
- options.output = argv[++i] ?? options.output;
181
- break;
182
- case "--tolerance":
183
- case "-t": {
184
- const value = Number.parseFloat(argv[++i] ?? "");
185
- if (!Number.isFinite(value) || value < 0) throw new Error(`Invalid --tolerance value: ${argv[i]}`);
186
- options.tolerance = value;
187
- break;
188
- }
189
- case "--currency":
190
- case "-c":
191
- options.currency = (argv[++i] ?? options.currency).toUpperCase();
192
- break;
193
- case "--json":
194
- options.json = true;
195
- break;
196
- default:
197
- if (arg.startsWith("-")) throw new Error(`Unknown option: ${arg}`);
198
- if (!options.invoices) {
199
- options.invoices = arg;
200
- break;
201
- }
202
- if (!options.payments) {
203
- options.payments = arg;
204
- break;
205
- }
206
- throw new Error(`Unexpected argument: ${arg}`);
207
- }
208
- }
209
-
210
- if (!options.invoices) throw new Error("Missing required --invoices <path> argument");
211
- if (!options.payments) throw new Error("Missing required --payments <path> argument");
212
- return options;
213
- }
214
-
215
- /* ------------------------------------------------------------------ *
216
- * column detection + parsing
217
- * ------------------------------------------------------------------ */
218
-
219
- const ID_CANDIDATES = [
220
- "invoice_id",
221
- "invoiceid",
222
- "invoice_no",
223
- "invoice_number",
224
- "invoicenumber",
225
- "invoice",
226
- "bill_id",
227
- "doc_number",
228
- "document_number",
229
- "reference",
230
- "ref",
231
- "number",
232
- "id",
233
- ];
234
-
235
- const AMOUNT_CANDIDATES = [
236
- "amount_due",
237
- "amount_paid",
238
- "paid_amount",
239
- "invoice_amount",
240
- "payment_amount",
241
- "amount",
242
- "total",
243
- "total_amount",
244
- "grand_total",
245
- "gross",
246
- "balance",
247
- "value",
248
- "sum",
249
- ];
250
-
251
- const DATE_CANDIDATES = [
252
- "paid_at",
253
- "payment_date",
254
- "paid_on",
255
- "invoice_date",
256
- "issue_date",
257
- "issued_at",
258
- "due_date",
259
- "posted_at",
260
- "created_at",
261
- "date",
262
- ];
263
-
264
- const PARTY_CANDIDATES = [
265
- "customer",
266
- "customer_name",
267
- "client",
268
- "vendor",
269
- "supplier",
270
- "payer",
271
- "account",
272
- "company",
273
- "counterparty",
274
- ];
275
-
276
- function normalizeKey(value: string): string {
277
- return value.trim().toLowerCase().replace(/[^a-z0-9]+/gu, "_").replace(/^_+|_+$/gu, "");
278
- }
279
-
280
- function pickColumn(headers: string[], candidates: string[]): string | null {
281
- const normalized = new Map(headers.map((header) => [normalizeKey(header), header]));
282
- for (const candidate of candidates) {
283
- const hit = normalized.get(candidate);
284
- if (hit) return hit;
285
- }
286
- // Fall back to a partial match (e.g. "customer_invoice_id" -> id candidates).
287
- for (const candidate of candidates) {
288
- for (const [key, header] of normalized) {
289
- if (key.includes(candidate)) return header;
290
- }
291
- }
292
- return null;
293
- }
294
-
295
- function detectColumns(headers: string[]): ColumnMap {
296
- return {
297
- id: pickColumn(headers, ID_CANDIDATES),
298
- amount: pickColumn(headers, AMOUNT_CANDIDATES),
299
- date: pickColumn(headers, DATE_CANDIDATES),
300
- party: pickColumn(headers, PARTY_CANDIDATES),
301
- };
302
- }
303
-
304
- function parseAmount(value: string | undefined): number | null {
305
- if (value === undefined) return null;
306
- let text = value.trim();
307
- if (text === "") return null;
308
-
309
- let negative = false;
310
- if (/^\(.*\)$/u.test(text)) {
311
- negative = true;
312
- text = text.slice(1, -1);
313
- }
314
- text = text.replace(/[^0-9.,\-+]/gu, "").trim();
315
- if (text === "") return null;
316
-
317
- const lastComma = text.lastIndexOf(",");
318
- const lastDot = text.lastIndexOf(".");
319
- if (lastComma > -1 && lastDot > -1) {
320
- // The right-most separator is the decimal separator.
321
- if (lastComma > lastDot) text = text.replace(/\./gu, "").replace(",", ".");
322
- else text = text.replace(/,/gu, "");
323
- } else if (lastComma > -1) {
324
- const decimals = text.length - lastComma - 1;
325
- text = decimals === 3 ? text.replace(/,/gu, "") : text.replace(",", ".");
326
- }
327
-
328
- const parsed = Number(text);
329
- if (!Number.isFinite(parsed)) return null;
330
- return negative ? -parsed : parsed;
331
- }
332
-
333
- function matchKey(value: string): string {
334
- return value.trim().toLowerCase().replace(/\s+/gu, "");
335
- }
336
-
337
- function round(value: number): number {
338
- return Math.round(value * 100) / 100;
339
- }
340
-
341
- function money(value: number): string {
342
- return value.toFixed(2);
343
- }
344
-
345
- async function readCsv(path: string, label: string): Promise<Array<Record<string, string>>> {
346
- let fileStat;
347
- try {
348
- fileStat = await stat(path);
349
- } catch {
350
- throw new Error(`Cannot read ${label} CSV: ${path}`);
351
- }
352
- if (!fileStat.isFile()) throw new Error(`${label} path is not a file: ${path}`);
353
-
354
- const text = await readFile(path, "utf8");
355
- if (text.trim() === "") throw new Error(`${label} CSV is empty: ${path}`);
356
-
357
- const parse = await loadCsvParse();
358
- let rows: Array<Record<string, string>>;
359
- try {
360
- rows = parse(text.replace(/^/u, ""), {
361
- columns: true,
362
- skip_empty_lines: true,
363
- relax_column_count: true,
364
- trim: true,
365
- bom: true,
366
- });
367
- } catch (error) {
368
- const message = error instanceof Error ? error.message : String(error);
369
- throw new Error(`Failed to parse ${label} CSV (${path}): ${message}`);
370
- }
371
-
372
- if (rows.length === 0) throw new Error(`${label} CSV has a header but no rows: ${path}`);
373
- return rows;
374
- }
375
-
376
- function toSourceRows(
377
- rows: Array<Record<string, string>>,
378
- columns: ColumnMap,
379
- label: string,
380
- anomalies: Anomaly[],
381
- ): SourceRow[] {
382
- if (!columns.id) {
383
- throw new Error(
384
- `Could not find an invoice id column in the ${label} CSV. ` +
385
- `Looked for: ${ID_CANDIDATES.slice(0, 6).join(", ")}...`,
386
- );
387
- }
388
- if (!columns.amount) {
389
- throw new Error(
390
- `Could not find an amount column in the ${label} CSV. ` +
391
- `Looked for: ${AMOUNT_CANDIDATES.slice(0, 6).join(", ")}...`,
392
- );
393
- }
394
-
395
- const out: SourceRow[] = [];
396
- rows.forEach((raw, index) => {
397
- const id = (raw[columns.id!] ?? "").trim();
398
- const amount = parseAmount(raw[columns.amount!]);
399
- const rowNumber = index + 2; // header is line 1
400
-
401
- if (id === "") {
402
- anomalies.push({
403
- type: "missing-id",
404
- invoiceId: null,
405
- detail: `${label} row ${rowNumber} has no value in column "${columns.id}" and was skipped.`,
406
- rows: [rowNumber],
407
- });
408
- return;
409
- }
410
- if (amount === null) {
411
- anomalies.push({
412
- type: "unparseable-amount",
413
- invoiceId: id,
414
- detail: `${label} row ${rowNumber} has an unparseable amount ("${raw[columns.amount!] ?? ""}") in column "${columns.amount}"; treated as 0.`,
415
- rows: [rowNumber],
416
- });
417
- }
418
-
419
- out.push({
420
- index: rowNumber,
421
- raw,
422
- id,
423
- key: matchKey(id),
424
- amount,
425
- date: columns.date ? (raw[columns.date] ?? "").trim() : "",
426
- party: columns.party ? (raw[columns.party] ?? "").trim() : "",
427
- });
428
- });
429
-
430
- return out;
431
- }
432
-
433
- /* ------------------------------------------------------------------ *
434
- * reconciliation
435
- * ------------------------------------------------------------------ */
436
-
437
- const BUCKETS: Bucket[] = [
438
- "matched",
439
- "short-paid",
440
- "over-paid",
441
- "duplicate-payment",
442
- "unpaid-invoice",
443
- "orphan-payment",
444
- ];
445
-
446
- function reconcile(
447
- invoices: SourceRow[],
448
- payments: SourceRow[],
449
- tolerance: number,
450
- anomalies: Anomaly[],
451
- ): ResultRow[] {
452
- const paymentsByKey = new Map<string, SourceRow[]>();
453
- for (const payment of payments) {
454
- const bucket = paymentsByKey.get(payment.key);
455
- if (bucket) bucket.push(payment);
456
- else paymentsByKey.set(payment.key, [payment]);
457
- }
458
-
459
- const invoicesByKey = new Map<string, SourceRow[]>();
460
- for (const invoice of invoices) {
461
- const bucket = invoicesByKey.get(invoice.key);
462
- if (bucket) bucket.push(invoice);
463
- else invoicesByKey.set(invoice.key, [invoice]);
464
- }
465
-
466
- for (const group of invoicesByKey.values()) {
467
- if (group.length > 1) {
468
- anomalies.push({
469
- type: "duplicate-invoice-row",
470
- invoiceId: group[0].id,
471
- detail: `Invoice id "${group[0].id}" appears on ${group.length} invoice rows (${group.map((row) => row.index).join(", ")}); amounts were summed.`,
472
- rows: group.map((row) => row.index),
473
- });
474
- }
475
- }
476
-
477
- const results: ResultRow[] = [];
478
- const usedPaymentKeys = new Set<string>();
479
-
480
- for (const [key, group] of invoicesByKey) {
481
- const invoiceAmount = round(group.reduce((sum, row) => sum + (row.amount ?? 0), 0));
482
- const matches = paymentsByKey.get(key) ?? [];
483
- usedPaymentKeys.add(key);
484
-
485
- const paidAmount = round(matches.reduce((sum, row) => sum + (row.amount ?? 0), 0));
486
- const difference = round(paidAmount - invoiceAmount);
487
- const first = group[0];
488
-
489
- if (matches.length > 1) {
490
- const exactDuplicates = new Map<string, SourceRow[]>();
491
- for (const payment of matches) {
492
- const signature = `${money(payment.amount ?? 0)}|${payment.date}`;
493
- const bucket = exactDuplicates.get(signature);
494
- if (bucket) bucket.push(payment);
495
- else exactDuplicates.set(signature, [payment]);
496
- }
497
- for (const [signature, bucket] of exactDuplicates) {
498
- if (bucket.length > 1) {
499
- anomalies.push({
500
- type: "identical-payment-rows",
501
- invoiceId: first.id,
502
- detail: `Invoice "${first.id}" has ${bucket.length} identical payment rows (${signature.replace("|", " on ")}) at rows ${bucket.map((row) => row.index).join(", ")}.`,
503
- rows: bucket.map((row) => row.index),
504
- });
505
- }
506
- }
507
- anomalies.push({
508
- type: "multiple-payments",
509
- invoiceId: first.id,
510
- detail: `Invoice "${first.id}" was paid by ${matches.length} payment rows totalling ${money(paidAmount)} against ${money(invoiceAmount)}.`,
511
- rows: matches.map((row) => row.index),
512
- });
513
- }
514
-
515
- let status: Bucket;
516
- let note: string;
517
- if (matches.length === 0) {
518
- status = "unpaid-invoice";
519
- note = "No payment row matched this invoice id.";
520
- } else if (matches.length > 1) {
521
- status = "duplicate-payment";
522
- note =
523
- Math.abs(difference) <= tolerance
524
- ? `${matches.length} payments settle the invoice exactly; confirm they are instalments, not duplicates.`
525
- : `${matches.length} payments differ from the invoice by ${money(difference)}.`;
526
- } else if (Math.abs(difference) <= tolerance) {
527
- status = "matched";
528
- note = "Paid within tolerance.";
529
- } else if (difference < 0) {
530
- status = "short-paid";
531
- note = `Underpaid by ${money(Math.abs(difference))}.`;
532
- } else {
533
- status = "over-paid";
534
- note = `Overpaid by ${money(difference)}.`;
535
- }
536
-
537
- results.push({
538
- invoice_id: first.id,
539
- status,
540
- invoice_amount: money(invoiceAmount),
541
- paid_amount: money(paidAmount),
542
- difference: money(difference),
543
- payment_count: String(matches.length),
544
- invoice_date: first.date,
545
- payment_date: matches.map((row) => row.date).filter(Boolean).join(" | "),
546
- party: first.party || matches.find((row) => row.party)?.party || "",
547
- note,
548
- });
549
- }
550
-
551
- for (const [key, group] of paymentsByKey) {
552
- if (usedPaymentKeys.has(key)) continue;
553
- const paidAmount = round(group.reduce((sum, row) => sum + (row.amount ?? 0), 0));
554
- const first = group[0];
555
- anomalies.push({
556
- type: "orphan-payment",
557
- invoiceId: first.id,
558
- detail: `Payment id "${first.id}" (${money(paidAmount)}) has no matching invoice row.`,
559
- rows: group.map((row) => row.index),
560
- });
561
- results.push({
562
- invoice_id: first.id,
563
- status: "orphan-payment",
564
- invoice_amount: money(0),
565
- paid_amount: money(paidAmount),
566
- difference: money(paidAmount),
567
- payment_count: String(group.length),
568
- invoice_date: "",
569
- payment_date: group.map((row) => row.date).filter(Boolean).join(" | "),
570
- party: first.party,
571
- note: "No invoice row matched this payment id.",
572
- });
573
- }
574
-
575
- results.sort((a, b) => {
576
- if (a.status !== b.status) return BUCKETS.indexOf(a.status) - BUCKETS.indexOf(b.status);
577
- return a.invoice_id.localeCompare(b.invoice_id);
578
- });
579
-
580
- return results;
581
- }
582
-
583
- /* ------------------------------------------------------------------ *
584
- * output
585
- * ------------------------------------------------------------------ */
586
-
587
- const RESULT_COLUMNS = [
588
- "invoice_id",
589
- "status",
590
- "invoice_amount",
591
- "paid_amount",
592
- "difference",
593
- "payment_count",
594
- "invoice_date",
595
- "payment_date",
596
- "party",
597
- "note",
598
- ];
599
-
600
- function summarize(results: ResultRow[]): Summary["buckets"] {
601
- const buckets = {} as Summary["buckets"];
602
- for (const bucket of BUCKETS) buckets[bucket] = { count: 0, invoiced: 0, paid: 0, difference: 0 };
603
-
604
- for (const row of results) {
605
- const entry = buckets[row.status];
606
- entry.count += 1;
607
- entry.invoiced = round(entry.invoiced + Number(row.invoice_amount));
608
- entry.paid = round(entry.paid + Number(row.paid_amount));
609
- entry.difference = round(entry.difference + Number(row.difference));
610
- }
611
- return buckets;
612
- }
613
-
614
- function padRight(value: string, width: number): string {
615
- return value.length >= width ? value : value + " ".repeat(width - value.length);
616
- }
617
-
618
- function padLeft(value: string, width: number): string {
619
- return value.length >= width ? value : " ".repeat(width - value.length) + value;
620
- }
621
-
622
- function printSummaryTable(summary: Summary): void {
623
- const header = ["bucket", "count", "invoiced", "paid", "difference"];
624
- const rows = BUCKETS.map((bucket) => {
625
- const entry = summary.buckets[bucket];
626
- return [bucket, String(entry.count), money(entry.invoiced), money(entry.paid), money(entry.difference)];
627
- });
628
- rows.push([
629
- "TOTAL",
630
- String(BUCKETS.reduce((sum, bucket) => sum + summary.buckets[bucket].count, 0)),
631
- money(summary.totals.invoiced),
632
- money(summary.totals.paid),
633
- money(summary.totals.difference),
634
- ]);
635
-
636
- const widths = header.map((label, column) =>
637
- Math.max(label.length, ...rows.map((row) => row[column].length)),
638
- );
639
-
640
- const line = (cells: string[]) =>
641
- ` ${cells
642
- .map((cell, column) => (column === 0 ? padRight(cell, widths[column]) : padLeft(cell, widths[column])))
643
- .join(" ")}`;
644
-
645
- console.log(line(header));
646
- console.log(` ${widths.map((width) => "-".repeat(width)).join(" ")}`);
647
- for (const row of rows.slice(0, -1)) console.log(line(row));
648
- console.log(` ${widths.map((width) => "-".repeat(width)).join(" ")}`);
649
- console.log(line(rows[rows.length - 1]));
650
- }
651
-
652
- /* ------------------------------------------------------------------ *
653
- * main
654
- * ------------------------------------------------------------------ */
655
-
656
- async function main(): Promise<void> {
657
- const options = parseArgs(process.argv.slice(2));
658
- const invoicesPath = resolve(options.invoices!);
659
- const paymentsPath = resolve(options.payments!);
660
- const outputDir = resolve(options.output);
661
-
662
- const anomalies: Anomaly[] = [];
663
-
664
- const invoiceRaw = await readCsv(invoicesPath, "invoices");
665
- const paymentRaw = await readCsv(paymentsPath, "payments");
666
-
667
- const invoiceColumns = detectColumns(Object.keys(invoiceRaw[0]));
668
- const paymentColumns = detectColumns(Object.keys(paymentRaw[0]));
669
-
670
- const invoices = toSourceRows(invoiceRaw, invoiceColumns, "invoices", anomalies);
671
- const payments = toSourceRows(paymentRaw, paymentColumns, "payments", anomalies);
672
-
673
- const results = reconcile(invoices, payments, options.tolerance, anomalies);
674
- const buckets = summarize(results);
675
-
676
- const invoiced = round(BUCKETS.reduce((sum, bucket) => sum + buckets[bucket].invoiced, 0));
677
- const paid = round(BUCKETS.reduce((sum, bucket) => sum + buckets[bucket].paid, 0));
678
- const totalRows = results.length || 1;
679
-
680
- const summary: Summary = {
681
- generatedAt: new Date().toISOString(),
682
- currency: options.currency,
683
- tolerance: options.tolerance,
684
- inputs: {
685
- invoices: invoicesPath,
686
- payments: paymentsPath,
687
- invoiceColumns,
688
- paymentColumns,
689
- invoiceRows: invoices.length,
690
- paymentRows: payments.length,
691
- },
692
- buckets,
693
- totals: {
694
- invoiced,
695
- paid,
696
- difference: round(paid - invoiced),
697
- matchRate: Math.round((buckets.matched.count / totalRows) * 1000) / 1000,
698
- },
699
- anomalyCount: anomalies.length,
700
- outputDir,
701
- files: [],
702
- };
703
-
704
- const stringify = await loadCsvStringify();
705
- await mkdir(outputDir, { recursive: true });
706
-
707
- const matched = results.filter((row) => row.status === "matched");
708
- const discrepancies = results.filter((row) => row.status !== "matched");
709
-
710
- const files: string[] = [];
711
- const write = async (name: string, content: string) => {
712
- await writeFile(join(outputDir, name), content, "utf8");
713
- files.push(name);
714
- };
715
-
716
- await write("matched.csv", stringify(matched, { header: true, columns: RESULT_COLUMNS }));
717
- await write("discrepancies.csv", stringify(discrepancies, { header: true, columns: RESULT_COLUMNS }));
718
- await write("anomalies.json", `${JSON.stringify({ count: anomalies.length, anomalies }, null, 2)}\n`);
719
-
720
- summary.files = [...files, "summary.json"];
721
- await writeFile(join(outputDir, "summary.json"), `${JSON.stringify(summary, null, 2)}\n`, "utf8");
722
-
723
- if (options.json) {
724
- process.stdout.write(`${JSON.stringify({ ...summary, anomalies }, null, 2)}\n`);
725
- return;
726
- }
727
-
728
- console.log(`invoice-reconciliation (${summary.currency}, tolerance ${options.tolerance})`);
729
- console.log(` invoices ${invoicesPath} (${invoices.length} rows, id="${invoiceColumns.id}", amount="${invoiceColumns.amount}")`);
730
- console.log(` payments ${paymentsPath} (${payments.length} rows, id="${paymentColumns.id}", amount="${paymentColumns.amount}")`);
731
- console.log("");
732
- printSummaryTable(summary);
733
- console.log("");
734
- console.log(` match rate ${(summary.totals.matchRate * 100).toFixed(1)}% anomalies ${anomalies.length}`);
735
- console.log(` output ${outputDir}`);
736
- console.log(` files ${summary.files.join(", ")}`);
737
- }
738
-
739
- main().catch((error) => {
740
- const message = error instanceof Error ? error.message : String(error);
741
- process.stderr.write(`invoice-reconciliation: ${message}\n`);
742
- process.exit(1);
743
- });