botrun-horse 2.31.0 → 2.34.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (664) hide show
  1. package/bin/bh.mjs +37 -170
  2. package/bin/commands/help.mjs +30 -30
  3. package/{lib/flows → modules/_core}/draft-writing.mjs +1 -1
  4. package/{lib/flows → modules/_core}/gemini-ask.mjs +1 -1
  5. package/{lib/flows → modules/_core}/legal-ask.mjs +4 -4
  6. package/{lib/flows → modules/_core}/openai-agent.mjs +2 -2
  7. package/{lib/flows → modules/_core}/openrouter-ask.mjs +1 -1
  8. package/{bin/commands/dag-cmd.mjs → modules/dag/command.mjs} +2 -2
  9. package/modules/dag/index.mjs +30 -0
  10. package/{bin/commands/db-cmd.mjs → modules/db/command.mjs} +3 -3
  11. package/modules/db/index.mjs +26 -0
  12. package/modules/discover.mjs +43 -0
  13. package/{bin/commands/doc.mjs → modules/doc/command.mjs} +5 -5
  14. package/modules/doc/index.mjs +55 -0
  15. package/{lib/doc/index.mjs → modules/doc/ingest.mjs} +1 -1
  16. package/{lib → modules}/doc/office2text.mjs +1 -1
  17. package/{lib → modules}/doc/pdf2text.mjs +1 -1
  18. package/{lib → modules}/doc/split.mjs +1 -1
  19. package/{bin/commands/gemini.mjs → modules/gemini/command.mjs} +3 -3
  20. package/modules/gemini/index.mjs +41 -0
  21. package/modules/imagen/command.mjs +117 -0
  22. package/modules/imagen/imagen-client.mjs +239 -0
  23. package/modules/imagen/index.mjs +60 -0
  24. package/modules/imagen/server.mjs +133 -0
  25. package/{bin/commands/legal.mjs → modules/legal/command.mjs} +5 -5
  26. package/modules/legal/index.mjs +56 -0
  27. package/{bin/commands/nchc.mjs → modules/nchc/command.mjs} +4 -4
  28. package/modules/nchc/index.mjs +48 -0
  29. package/modules/ocr/index.mjs +17 -0
  30. package/{bin/commands/openrouter.mjs → modules/openrouter/command.mjs} +5 -5
  31. package/modules/openrouter/index.mjs +49 -0
  32. package/modules/portal/index.mjs +17 -0
  33. package/{bin/commands/search.mjs → modules/search/command.mjs} +3 -3
  34. package/modules/search/index.mjs +23 -0
  35. package/{lib/search/index.mjs → modules/search/search-lib.mjs} +1 -1
  36. package/{bin/commands/skill.mjs → modules/skill/command.mjs} +8 -8
  37. package/modules/skill/index.mjs +35 -0
  38. package/{lib/prompt → modules/skill}/prompt-search.mjs +1 -1
  39. package/{lib/prompt → modules/skill}/prompt-store.mjs +7 -5
  40. package/modules/skill/prompts/zero-framework/address-matching.md +22 -0
  41. package/modules/skill/prompts/zero-framework/data-integrity.md +15 -0
  42. package/modules/skill/prompts/zero-framework/data-reasonability.md +17 -0
  43. package/modules/skill/prompts/zero-framework/gemini-image-gen.md +20 -0
  44. package/modules/skill/prompts/zero-framework/html-report.md +15 -0
  45. package/{bin/commands/writing.mjs → modules/writing/command.mjs} +3 -3
  46. package/{lib → modules}/writing/generate.mjs +2 -2
  47. package/modules/writing/index.mjs +38 -0
  48. package/package.json +3 -1
  49. package/parallel-dag-todo-list/imagen-module.md +51 -0
  50. package/bin/commands/schema.mjs +0 -254
  51. package/botrun-c/.claude/skills/DOCX/351/226/261/350/256/200/346/212/200/350/203/275/SKILL.md +0 -103
  52. package/botrun-c/.claude/skills/DOCX/351/226/261/350/256/200/346/212/200/350/203/275/scripts/docx-to-markdown.mjs +0 -206
  53. package/botrun-c/.claude/skills/GitHub/346/212/200/350/203/275/SKILL.md +0 -1093
  54. package/botrun-c/.claude/skills/GitHub/346/212/200/350/203/275/scripts/github-branch.mjs +0 -73
  55. package/botrun-c/.claude/skills/GitHub/346/212/200/350/203/275/scripts/github-branches.mjs +0 -77
  56. package/botrun-c/.claude/skills/GitHub/346/212/200/350/203/275/scripts/github-checkout.mjs +0 -72
  57. package/botrun-c/.claude/skills/GitHub/346/212/200/350/203/275/scripts/github-clone.mjs +0 -72
  58. package/botrun-c/.claude/skills/GitHub/346/212/200/350/203/275/scripts/github-commit.mjs +0 -75
  59. package/botrun-c/.claude/skills/GitHub/346/212/200/350/203/275/scripts/github-delete-branch.mjs +0 -75
  60. package/botrun-c/.claude/skills/GitHub/346/212/200/350/203/275/scripts/github-delete-file.mjs +0 -72
  61. package/botrun-c/.claude/skills/GitHub/346/212/200/350/203/275/scripts/github-diff.mjs +0 -80
  62. package/botrun-c/.claude/skills/GitHub/346/212/200/350/203/275/scripts/github-list-tree.mjs +0 -336
  63. package/botrun-c/.claude/skills/GitHub/346/212/200/350/203/275/scripts/github-list.mjs +0 -199
  64. package/botrun-c/.claude/skills/GitHub/346/212/200/350/203/275/scripts/github-merge.mjs +0 -86
  65. package/botrun-c/.claude/skills/GitHub/346/212/200/350/203/275/scripts/github-move.mjs +0 -75
  66. package/botrun-c/.claude/skills/GitHub/346/212/200/350/203/275/scripts/github-pr-create.mjs +0 -81
  67. package/botrun-c/.claude/skills/GitHub/346/212/200/350/203/275/scripts/github-pr-list.mjs +0 -74
  68. package/botrun-c/.claude/skills/GitHub/346/212/200/350/203/275/scripts/github-pr-merge.mjs +0 -83
  69. package/botrun-c/.claude/skills/GitHub/346/212/200/350/203/275/scripts/github-pr-view.mjs +0 -71
  70. package/botrun-c/.claude/skills/GitHub/346/212/200/350/203/275/scripts/github-push.mjs +0 -71
  71. package/botrun-c/.claude/skills/GitHub/346/212/200/350/203/275/scripts/github-read.mjs +0 -277
  72. package/botrun-c/.claude/skills/GitHub/346/212/200/350/203/275/scripts/github-search.mjs +0 -370
  73. package/botrun-c/.claude/skills/GitHub/346/212/200/350/203/275/scripts/github-stash.mjs +0 -116
  74. package/botrun-c/.claude/skills/GitHub/346/212/200/350/203/275/scripts/github-sync.mjs +0 -71
  75. package/botrun-c/.claude/skills/GitHub/346/212/200/350/203/275/scripts/github-write.mjs +0 -74
  76. package/botrun-c/.claude/skills/GitHub/346/212/200/350/203/275/scripts/lib/path-validator.mjs +0 -167
  77. package/botrun-c/.claude/skills/GoogleDrive/346/212/200/350/203/275/SKILL.md +0 -605
  78. package/botrun-c/.claude/skills/GoogleDrive/346/212/200/350/203/275/scripts/gdrive-create.mjs +0 -127
  79. package/botrun-c/.claude/skills/GoogleDrive/346/212/200/350/203/275/scripts/gdrive-delete.mjs +0 -77
  80. package/botrun-c/.claude/skills/GoogleDrive/346/212/200/350/203/275/scripts/gdrive-diff.mjs +0 -87
  81. package/botrun-c/.claude/skills/GoogleDrive/346/212/200/350/203/275/scripts/gdrive-history.mjs +0 -99
  82. package/botrun-c/.claude/skills/GoogleDrive/346/212/200/350/203/275/scripts/gdrive-list.mjs +0 -174
  83. package/botrun-c/.claude/skills/GoogleDrive/346/212/200/350/203/275/scripts/gdrive-read.mjs +0 -214
  84. package/botrun-c/.claude/skills/GoogleDrive/346/212/200/350/203/275/scripts/gdrive-restore.mjs +0 -75
  85. package/botrun-c/.claude/skills/GoogleDrive/346/212/200/350/203/275/scripts/gdrive-search.mjs +0 -270
  86. package/botrun-c/.claude/skills/GoogleDrive/346/212/200/350/203/275/scripts/gdrive-sync-back.mjs +0 -155
  87. package/botrun-c/.claude/skills/GoogleDrive/346/212/200/350/203/275/scripts/gdrive-update.mjs +0 -100
  88. package/botrun-c/.claude/skills/HTML/347/224/237/346/210/220/346/212/200/350/203/275/SKILL.md +0 -414
  89. package/botrun-c/.claude/skills/HTML/347/224/237/346/210/220/346/212/200/350/203/275/scripts/create-project.mjs +0 -91
  90. package/botrun-c/.claude/skills/HTML/347/224/237/346/210/220/346/212/200/350/203/275/scripts/finalize-project.mjs +0 -162
  91. package/botrun-c/.claude/skills/PDF/346/212/200/350/203/275/SKILL.md +0 -206
  92. package/botrun-c/.claude/skills/PDF/346/212/200/350/203/275/scripts/package.json +0 -19
  93. package/botrun-c/.claude/skills/PDF/346/212/200/350/203/275/scripts/pdf-analyze.mjs +0 -309
  94. package/botrun-c/.claude/skills/PDF/346/212/200/350/203/275/scripts/pdf-compress.mjs +0 -315
  95. package/botrun-c/.claude/skills/PDF/346/212/200/350/203/275/scripts/pdf-split.mjs +0 -275
  96. package/botrun-c/.claude/skills/PDF/346/212/200/350/203/275/scripts/pdf-to-text.mjs +0 -336
  97. package/botrun-c/.claude/skills/PDF/346/212/200/350/203/275/scripts/test-pdf-scripts.mjs +0 -491
  98. package/botrun-c/.claude/skills/docx-to-markdown/SKILL.md +0 -76
  99. package/botrun-c/.claude/skills/docx-to-markdown/scripts/convert_docx.py +0 -183
  100. package/botrun-c/.claude/skills/gcp-coord-ml-ocr/SKILL.md +0 -133
  101. package/botrun-c/.claude/skills/gcp-coord-ml-ocr/scripts/ocr_processor.py +0 -381
  102. package/botrun-c/.claude/skills/gemini-transcribe/SKILL.md +0 -115
  103. package/botrun-c/.claude/skills/gemini-transcribe/scripts/transcribe.py +0 -499
  104. package/botrun-c/.claude/skills/nchc-transcribe/SKILL.md +0 -131
  105. package/botrun-c/.claude/skills/nchc-transcribe/scripts/transcribe.py +0 -522
  106. package/botrun-c/.claude/skills/p320-moj-review/SKILL.md +0 -200
  107. package/botrun-c/.claude/skills/p320-moj-review/references/guideline.md +0 -118
  108. package/botrun-c/.claude/skills/pdf-multimodal-processor/SKILL.md +0 -186
  109. package/botrun-c/.claude/skills/pdf-multimodal-processor/scripts/process_pdf.py +0 -515
  110. package/botrun-c/.claude/skills/ripgrep/346/220/234/345/260/213/346/212/200/350/203/275/SKILL.md +0 -81
  111. package/botrun-c/.claude/skills/ripgrep/346/220/234/345/260/213/346/212/200/350/203/275/scripts/package.json +0 -13
  112. package/botrun-c/.claude/skills/ripgrep/346/220/234/345/260/213/346/212/200/350/203/275/scripts/secure-search.mjs +0 -232
  113. package/botrun-c/.claude/skills/top100/351/240/230/350/242/226/351/240/220/346/270/254/346/212/200/350/203/275/SKILL.md +0 -518
  114. package/botrun-c/.claude/skills//345/216/273/350/255/230/345/210/245/346/212/200/350/203/275/SKILL.md +0 -125
  115. package/botrun-c/.claude/skills//345/233/236/346/206/266/346/212/200/350/203/275/SKILL.md +0 -123
  116. package/botrun-c/.claude/skills//345/233/236/346/206/266/346/212/200/350/203/275/scripts/recall.mjs +0 -339
  117. package/botrun-c/.claude/skills//345/234/226/347/211/207/347/224/237/346/210/220/346/212/200/350/203/275/SKILL.md +0 -156
  118. package/botrun-c/.claude/skills//345/234/226/347/211/207/347/224/237/346/210/220/346/212/200/350/203/275/scripts/__tests__/utils.test.mjs +0 -139
  119. package/botrun-c/.claude/skills//345/234/226/347/211/207/347/224/237/346/210/220/346/212/200/350/203/275/scripts/constants.mjs +0 -40
  120. package/botrun-c/.claude/skills//345/234/226/347/211/207/347/224/237/346/210/220/346/212/200/350/203/275/scripts/gcs-uploader.mjs +0 -195
  121. package/botrun-c/.claude/skills//345/234/226/347/211/207/347/224/237/346/210/220/346/212/200/350/203/275/scripts/gemini-image-client.mjs +0 -307
  122. package/botrun-c/.claude/skills//345/234/226/347/211/207/347/224/237/346/210/220/346/212/200/350/203/275/scripts/generate-image.mjs +0 -103
  123. package/botrun-c/.claude/skills//345/234/226/347/211/207/347/224/237/346/210/220/346/212/200/350/203/275/scripts/image-session-manager.mjs +0 -219
  124. package/botrun-c/.claude/skills//345/234/226/347/211/207/347/224/237/346/210/220/346/212/200/350/203/275/scripts/output-formatter.mjs +0 -209
  125. package/botrun-c/.claude/skills//345/234/226/347/211/207/347/224/237/346/210/220/346/212/200/350/203/275/scripts/package.json +0 -20
  126. package/botrun-c/.claude/skills//345/234/226/347/211/207/347/224/237/346/210/220/346/212/200/350/203/275/scripts/utils.mjs +0 -115
  127. package/botrun-c/.claude/skills//345/244/232/346/250/241/346/205/213/351/226/261/350/256/200/346/212/200/350/203/275/SKILL.md +0 -86
  128. package/botrun-c/.claude/skills//345/244/232/346/250/241/346/205/213/351/226/261/350/256/200/346/212/200/350/203/275/scripts/multimodal-read.mjs +0 -304
  129. package/botrun-c/.claude/skills//345/244/232/346/250/241/346/205/213/351/226/261/350/256/200/346/212/200/350/203/275/scripts/package.json +0 -17
  130. package/botrun-c/.claude/skills//345/255/265/345/214/226/346/212/200/350/203/275/SKILL.md +0 -131
  131. package/botrun-c/.claude/skills//345/255/265/345/214/226/346/212/200/350/203/275/scripts/skill-manager.mjs +0 -542
  132. package/botrun-c/.claude/skills//346/234/203/350/255/260/350/250/230/351/214/204/346/212/200/350/203/275/SKILL.md +0 -127
  133. package/botrun-c/.claude/skills//347/233/256/351/214/204/345/210/227/350/241/250/346/212/200/350/203/275/SKILL.md +0 -53
  134. package/botrun-c/.claude/skills//347/233/256/351/214/204/345/210/227/350/241/250/346/212/200/350/203/275/scripts/package.json +0 -13
  135. package/botrun-c/.claude/skills//347/233/256/351/214/204/345/210/227/350/241/250/346/212/200/350/203/275/scripts/tree-view.mjs +0 -149
  136. package/botrun-c/.claude/skills//347/264/224/346/226/207/345/255/227/345/244/232/346/252/224/346/241/210/350/256/200/345/217/226/346/212/200/350/203/275/SKILL.md +0 -82
  137. package/botrun-c/.claude/skills//347/264/224/346/226/207/345/255/227/345/244/232/346/252/224/346/241/210/350/256/200/345/217/226/346/212/200/350/203/275/scripts/package.json +0 -16
  138. package/botrun-c/.claude/skills//347/264/224/346/226/207/345/255/227/345/244/232/346/252/224/346/241/210/350/256/200/345/217/226/346/212/200/350/203/275/scripts/secure-read.mjs +0 -260
  139. package/botrun-c/.claude/skills//347/266/262/350/267/257/346/220/234/345/260/213/346/212/200/350/203/275/SKILL.md +0 -156
  140. package/botrun-c/.claude/skills//347/266/262/350/267/257/346/220/234/345/260/213/346/212/200/350/203/275/scripts/package.json +0 -16
  141. package/botrun-c/.claude/skills//347/266/262/350/267/257/346/220/234/345/260/213/346/212/200/350/203/275/scripts/search.js +0 -139
  142. package/botrun-c/.claude/skills//347/266/262/350/267/257/346/220/234/345/260/213/346/212/200/350/203/275/scripts/search.mjs +0 -272
  143. package/botrun-c/.claude/skills//347/266/262/350/267/257/346/220/234/345/260/213/346/212/200/350/203/275/scripts/search.ts +0 -166
  144. package/botrun-c/.claude/skills//350/250/230/346/206/266/346/212/200/350/203/275/SKILL.md +0 -114
  145. package/botrun-c/.claude/skills//350/250/230/346/206/266/346/212/200/350/203/275/scripts/remember.mjs +0 -159
  146. package/botrun-c/.claude/skills//350/250/230/346/206/266/346/212/200/350/203/275/scripts/test-advanced.mjs +0 -342
  147. package/botrun-c/.claude/skills//350/250/230/346/206/266/346/212/200/350/203/275/scripts/test.mjs +0 -430
  148. package/botrun-c/.claude/skills//350/252/236/351/237/263/350/275/211/346/226/207/345/255/227/346/212/200/350/203/275/SKILL.md +0 -30
  149. package/botrun-c/.claude/skills//350/252/236/351/237/263/350/275/211/346/226/207/345/255/227/346/212/200/350/203/275/scripts/package.json +0 -13
  150. package/botrun-c/.claude/skills//350/252/236/351/237/263/350/275/211/346/226/207/345/255/227/346/212/200/350/203/275/scripts/transcribe.mjs +0 -294
  151. package/botrun-c/.claude/skills//351/233/266/345/271/273/350/246/272/350/255/211/346/230/216/346/212/200/350/203/275/SKILL.md +0 -338
  152. package/botrun-c/.dockerignore +0 -131
  153. package/botrun-c/.dockeroptimize +0 -13
  154. package/botrun-c/.firebase/hosting.b3V0.cache +0 -30
  155. package/botrun-c/.firebaserc +0 -5
  156. package/botrun-c/.gcloudignore +0 -56
  157. package/botrun-c/.ruby-version +0 -1
  158. package/botrun-c/CHANGELOG.md +0 -224
  159. package/botrun-c/Dockerfile.gcp +0 -365
  160. package/botrun-c/Dockerfile.slim +0 -195
  161. package/botrun-c/Gemfile +0 -8
  162. package/botrun-c/Gemfile.lock +0 -233
  163. package/botrun-c/LOCAL-DEVELOPMENT-GUIDE.md +0 -393
  164. package/botrun-c/PLAN.md +0 -131
  165. package/botrun-c/README.md +0 -129
  166. package/botrun-c/TODO-CAPACITOR-INTEGRATION.md +0 -482
  167. package/botrun-c/VERIFICATION.md +0 -121
  168. package/botrun-c/admin/RATE_LIMIT_MANAGEMENT.md +0 -312
  169. package/botrun-c/admin/README.md +0 -338
  170. package/botrun-c/admin/botrun-billing-report-1765235244038.csv +0 -22
  171. package/botrun-c/admin/botrun-billing-report-1765235323089.csv +0 -22
  172. package/botrun-c/admin/botrun-dashboard-1765235244039.html +0 -278
  173. package/botrun-c/admin/botrun-dashboard-1765235323089.html +0 -278
  174. package/botrun-c/admin/botrun-timeseries-074xGzIKWyfKTBt1NMIj9lxi5mO2-1765235244039.html +0 -161
  175. package/botrun-c/admin/botrun-timeseries-074xGzIKWyfKTBt1NMIj9lxi5mO2-1765235323090.html +0 -161
  176. package/botrun-c/admin/check-billing.ts +0 -48
  177. package/botrun-c/admin/count-all-users.ts +0 -65
  178. package/botrun-c/admin/generate-analytics-report.ts +0 -188
  179. package/botrun-c/admin/jest.config.ts +0 -43
  180. package/botrun-c/admin/lib/__tests__/formatters.test.ts +0 -264
  181. package/botrun-c/admin/lib/__tests__/mocks/firebase.mock.ts +0 -112
  182. package/botrun-c/admin/lib/__tests__/services/UserService.test.ts +0 -83
  183. package/botrun-c/admin/lib/__tests__/user-resolver.test.ts +0 -439
  184. package/botrun-c/admin/lib/analyzers/BillingAnalyticsService.ts +0 -242
  185. package/botrun-c/admin/lib/analyzers/CsvExporter.ts +0 -263
  186. package/botrun-c/admin/lib/analyzers/HtmlChartGenerator.ts +0 -530
  187. package/botrun-c/admin/lib/analyzers/SpikeAnalyzer.ts +0 -608
  188. package/botrun-c/admin/lib/analyzers/TimeSeriesAnalyzer.ts +0 -344
  189. package/botrun-c/admin/lib/cli/CLIBootstrapper.ts +0 -40
  190. package/botrun-c/admin/lib/commands/AbstractCommand.ts +0 -69
  191. package/botrun-c/admin/lib/commands/AnalyticsCommand.ts +0 -215
  192. package/botrun-c/admin/lib/commands/ListCommand.ts +0 -85
  193. package/botrun-c/admin/lib/commands/QueryCommand.ts +0 -81
  194. package/botrun-c/admin/lib/commands/SpikeCommand.ts +0 -83
  195. package/botrun-c/admin/lib/domain/User.ts +0 -38
  196. package/botrun-c/admin/lib/firebase.ts +0 -92
  197. package/botrun-c/admin/lib/firestore-safe.ts +0 -105
  198. package/botrun-c/admin/lib/formatters.ts +0 -154
  199. package/botrun-c/admin/lib/rate-limit-detailed.ts +0 -355
  200. package/botrun-c/admin/lib/rate-limit.ts +0 -286
  201. package/botrun-c/admin/lib/repositories/UserRepository.ts +0 -104
  202. package/botrun-c/admin/lib/services/UserService.ts +0 -108
  203. package/botrun-c/admin/lib/types.ts +0 -56
  204. package/botrun-c/admin/lib/user-resolver.ts +0 -275
  205. package/botrun-c/admin/manage-auth-domains.js +0 -178
  206. package/botrun-c/admin/migrate-plan-free.sh +0 -64
  207. package/botrun-c/admin/package-lock.json +0 -5656
  208. package/botrun-c/admin/package.json +0 -28
  209. package/botrun-c/admin/rate-limit.sh +0 -55
  210. package/botrun-c/admin/remove-custom-limits.ts +0 -75
  211. package/botrun-c/admin/reset-rate.sh +0 -70
  212. package/botrun-c/admin/reset-trial.sh +0 -68
  213. package/botrun-c/admin/seed-trial-data.sh +0 -38
  214. package/botrun-c/admin/trial.sh +0 -55
  215. package/botrun-c/admin/tsconfig.json +0 -20
  216. package/botrun-c/admin/users-cli.py +0 -298
  217. package/botrun-c/admin/users.sh +0 -12
  218. package/botrun-c/admin/users.ts +0 -1321
  219. package/botrun-c/api/admin-tools/check-whitelist.mjs.migration-bak +0 -74
  220. package/botrun-c/api/admin-tools/create-user.mjs +0 -92
  221. package/botrun-c/api/admin-tools/create-user.mjs.migration-bak +0 -92
  222. package/botrun-c/api/admin-tools/firebase-auth-domains-v2.py +0 -287
  223. package/botrun-c/api/admin-tools/firebase-auth-domains-v2.py.migration-bak +0 -287
  224. package/botrun-c/api/admin-tools/init-firestore.mjs +0 -75
  225. package/botrun-c/api/admin-tools/init-firestore.mjs.migration-bak +0 -101
  226. package/botrun-c/api/admin-tools/list-users.mjs +0 -43
  227. package/botrun-c/api/admin-tools/list-users.mjs.migration-bak +0 -43
  228. package/botrun-c/api/admin-tools/manage-authorized-domains.ts +0 -255
  229. package/botrun-c/api/admin-tools/manage-authorized-domains.ts.migration-bak +0 -255
  230. package/botrun-c/api/admin-tools/setup-custom-claims.ts.migration-bak +0 -155
  231. package/botrun-c/api/admin-tools/test-claims.mjs +0 -69
  232. package/botrun-c/api/admin-tools/test-claims.mjs.migration-bak +0 -69
  233. package/botrun-c/api/admin-tools/update-service-urls-gcloud.mjs +0 -72
  234. package/botrun-c/api/admin-tools/update-service-urls-gcloud.mjs.migration-bak +0 -72
  235. package/botrun-c/api/admin-tools/update-service-urls-to-lb.mjs +0 -159
  236. package/botrun-c/api/admin-tools/update-service-urls-to-lb.mjs.migration-bak +0 -159
  237. package/botrun-c/api/admin-tools/update-service-urls.mjs +0 -82
  238. package/botrun-c/api/admin-tools/update-service-urls.mjs.migration-bak +0 -82
  239. package/botrun-c/api/package-lock.json +0 -5031
  240. package/botrun-c/api/package.json +0 -63
  241. package/botrun-c/api/pnpm-lock.yaml +0 -4157
  242. package/botrun-c/api/rate-limit-export-1763620678737.csv +0 -79
  243. package/botrun-c/api/scripts/README-migrate-plan-free.md +0 -197
  244. package/botrun-c/api/scripts/check-users.ts +0 -45
  245. package/botrun-c/api/scripts/delete-firestore-docs.js +0 -43
  246. package/botrun-c/api/scripts/dump-subscriptions.ts +0 -395
  247. package/botrun-c/api/scripts/list-all-users.ts +0 -65
  248. package/botrun-c/api/scripts/migrate-plan-free-rpd-16to32.ts +0 -262
  249. package/botrun-c/api/scripts/migrate-plan-names-to-lite-max.ts +0 -269
  250. package/botrun-c/api/scripts/query-user-info.ts +0 -304
  251. package/botrun-c/api/scripts/reset-rate-limit.ts +0 -206
  252. package/botrun-c/api/scripts/reset-trial-subscription.ts +0 -166
  253. package/botrun-c/api/scripts/rollback-plan-names-from-lite-max.ts +0 -139
  254. package/botrun-c/api/scripts/seed-rate-limit-test-data.ts +0 -114
  255. package/botrun-c/api/scripts/seed-subscription-test-data.ts +0 -173
  256. package/botrun-c/api/scripts/test-rate-limit-message.ts +0 -108
  257. package/botrun-c/api/test-billing-write.ts +0 -103
  258. package/botrun-c/api/test-billing.ts +0 -81
  259. package/botrun-c/api/test-chat-upload.sh +0 -162
  260. package/botrun-c/api/test-nchc-whisper.ts +0 -87
  261. package/botrun-c/api/test-skills-loading.js +0 -77
  262. package/botrun-c/api/test-skills-symlink.js +0 -118
  263. package/botrun-c/api/test-upload-multimodal.sh +0 -167
  264. package/botrun-c/api/tsconfig.json +0 -27
  265. package/botrun-c/api/verify-form-2-1.mjs +0 -229
  266. package/botrun-c/api/vitest.config.ts +0 -9
  267. package/botrun-c/appium-capabilities.json +0 -20
  268. package/botrun-c/cors.json +0 -26
  269. package/botrun-c/delete-old.sh +0 -44
  270. package/botrun-c/design/google-drive/01-architecture.md +0 -186
  271. package/botrun-c/design/google-drive/02-api-design.md +0 -314
  272. package/botrun-c/design/google-drive/03-frontend-design.md +0 -278
  273. package/botrun-c/design/google-drive/04-skill-design.md +0 -384
  274. package/botrun-c/design/google-drive/05-test-plan.md +0 -507
  275. package/botrun-c/design/google-drive/README.md +0 -32
  276. package/botrun-c/dev/mcp-token-calculator/README.md +0 -92
  277. package/botrun-c/dev/mcp-token-calculator/RESULTS.md +0 -188
  278. package/botrun-c/dev/mcp-token-calculator/calculate-current-tokens.ts +0 -369
  279. package/botrun-c/dev/mcp-token-calculator/calculate-mcp-tokens.ts +0 -464
  280. package/botrun-c/dev/mcp-token-calculator/optimization-proposals.ts +0 -316
  281. package/botrun-c/dev/mcp-token-calculator/package-lock.json +0 -599
  282. package/botrun-c/dev/mcp-token-calculator/package.json +0 -22
  283. package/botrun-c/dev/mcp-token-calculator/test-all-schemas.ts +0 -314
  284. package/botrun-c/dev/mcp-token-calculator/test-schema-correctness.ts +0 -221
  285. package/botrun-c/dev/mcp-token-calculator/verify-optimization.ts +0 -159
  286. package/botrun-c/fastlane/ANDROID-DEPLOYMENT-SETUP.md +0 -825
  287. package/botrun-c/fastlane/IOS-DEPLOYMENT-SETUP.md +0 -431
  288. package/botrun-c/fastlane/Pluginfile +0 -5
  289. package/botrun-c/fastlane/QUICK-START.md +0 -133
  290. package/botrun-c/fastlane/README.md +0 -424
  291. package/botrun-c/fastlane/RUBY-SETUP.md +0 -449
  292. package/botrun-c/fastlane/android/Appfile +0 -11
  293. package/botrun-c/fastlane/android/Fastfile +0 -240
  294. package/botrun-c/firebase.json +0 -46
  295. package/botrun-c/firestore-init-data.json +0 -40
  296. package/botrun-c/firestore.indexes.json +0 -55
  297. package/botrun-c/firestore.rules +0 -53
  298. package/botrun-c/fix-codex-permissions.sh +0 -56
  299. package/botrun-c/gcs-lifecycle-30day-retention.json +0 -12
  300. package/botrun-c/html-architecture/architecture/deployment.html +0 -664
  301. package/botrun-c/html-architecture/architecture/index.html +0 -309
  302. package/botrun-c/html-architecture/architecture/styles.css +0 -500
  303. package/botrun-c/html-architecture/architecture/system-components.html +0 -538
  304. package/botrun-c/html-architecture/architecture/user-flow.html +0 -370
  305. package/botrun-c/mobile-android/FIREBASE-AUTH-SETUP.md +0 -302
  306. package/botrun-c/mobile-android/WSL-ANDROID-SETUP.md +0 -252
  307. package/botrun-c/mobile-android/android/app/build.gradle +0 -75
  308. package/botrun-c/mobile-android/android/app/capacitor.build.gradle +0 -31
  309. package/botrun-c/mobile-android/android/app/proguard-rules.pro +0 -21
  310. package/botrun-c/mobile-android/android/build.gradle +0 -29
  311. package/botrun-c/mobile-android/android/capacitor.settings.gradle +0 -42
  312. package/botrun-c/mobile-android/android/gradle/wrapper/gradle-wrapper.jar +0 -0
  313. package/botrun-c/mobile-android/android/gradle/wrapper/gradle-wrapper.properties +0 -7
  314. package/botrun-c/mobile-android/android/gradle.properties +0 -22
  315. package/botrun-c/mobile-android/android/gradlew +0 -252
  316. package/botrun-c/mobile-android/android/gradlew.bat +0 -94
  317. package/botrun-c/mobile-android/android/settings.gradle +0 -5
  318. package/botrun-c/mobile-android/android/variables.gradle +0 -16
  319. package/botrun-c/mobile-android/capacitor.config.ts +0 -44
  320. package/botrun-c/mobile-android/fastlane/Appfile +0 -11
  321. package/botrun-c/mobile-android/fastlane/Fastfile +0 -202
  322. package/botrun-c/mobile-android/fastlane/README.md +0 -96
  323. package/botrun-c/mobile-android/google-services.json.template +0 -39
  324. package/botrun-c/mobile-android/package.json +0 -32
  325. package/botrun-c/mobile-android/resources/icon.png +0 -0
  326. package/botrun-c/mobile-android/tsconfig.json +0 -15
  327. package/botrun-c/mobile-ios/.ruby-version +0 -1
  328. package/botrun-c/mobile-ios/BUILD-LOG.md +0 -82
  329. package/botrun-c/mobile-ios/Gemfile +0 -4
  330. package/botrun-c/mobile-ios/Gemfile.lock +0 -299
  331. package/botrun-c/mobile-ios/GoogleService-Info.plist.template +0 -34
  332. package/botrun-c/mobile-ios/IOS-PERMISSIONS.md +0 -80
  333. package/botrun-c/mobile-ios/QUICK-START.md +0 -189
  334. package/botrun-c/mobile-ios/README.md +0 -231
  335. package/botrun-c/mobile-ios/capacitor.config.ts +0 -46
  336. package/botrun-c/mobile-ios/fastlane/Fastfile +0 -326
  337. package/botrun-c/mobile-ios/fastlane/README.md +0 -88
  338. package/botrun-c/mobile-ios/ios/App/App/App.entitlements +0 -10
  339. package/botrun-c/mobile-ios/ios/App/App/AppDelegate.swift +0 -49
  340. package/botrun-c/mobile-ios/ios/App/App/Assets.xcassets/AppIcon.appiconset/AppIcon-512@2x.png +0 -0
  341. package/botrun-c/mobile-ios/ios/App/App/Assets.xcassets/AppIcon.appiconset/Contents.json +0 -14
  342. package/botrun-c/mobile-ios/ios/App/App/Assets.xcassets/Contents.json +0 -6
  343. package/botrun-c/mobile-ios/ios/App/App/Assets.xcassets/Splash.imageset/Contents.json +0 -56
  344. package/botrun-c/mobile-ios/ios/App/App/Assets.xcassets/Splash.imageset/Default@1x~universal~anyany-dark.png +0 -0
  345. package/botrun-c/mobile-ios/ios/App/App/Assets.xcassets/Splash.imageset/Default@1x~universal~anyany.png +0 -0
  346. package/botrun-c/mobile-ios/ios/App/App/Assets.xcassets/Splash.imageset/Default@2x~universal~anyany-dark.png +0 -0
  347. package/botrun-c/mobile-ios/ios/App/App/Assets.xcassets/Splash.imageset/Default@2x~universal~anyany.png +0 -0
  348. package/botrun-c/mobile-ios/ios/App/App/Assets.xcassets/Splash.imageset/Default@3x~universal~anyany-dark.png +0 -0
  349. package/botrun-c/mobile-ios/ios/App/App/Assets.xcassets/Splash.imageset/Default@3x~universal~anyany.png +0 -0
  350. package/botrun-c/mobile-ios/ios/App/App/Assets.xcassets/Splash.imageset/splash-2732x2732-1.png +0 -0
  351. package/botrun-c/mobile-ios/ios/App/App/Assets.xcassets/Splash.imageset/splash-2732x2732-2.png +0 -0
  352. package/botrun-c/mobile-ios/ios/App/App/Assets.xcassets/Splash.imageset/splash-2732x2732.png +0 -0
  353. package/botrun-c/mobile-ios/ios/App/App/Base.lproj/LaunchScreen.storyboard +0 -32
  354. package/botrun-c/mobile-ios/ios/App/App/Base.lproj/Main.storyboard +0 -19
  355. package/botrun-c/mobile-ios/ios/App/App/Info.plist +0 -72
  356. package/botrun-c/mobile-ios/ios/App/App.xcodeproj/project.pbxproj +0 -446
  357. package/botrun-c/mobile-ios/ios/App/App.xcodeproj/xcshareddata/xcschemes/App.xcscheme +0 -78
  358. package/botrun-c/mobile-ios/ios/App/App.xcworkspace/contents.xcworkspacedata +0 -10
  359. package/botrun-c/mobile-ios/ios/App/App.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist +0 -8
  360. package/botrun-c/mobile-ios/ios/App/Podfile +0 -52
  361. package/botrun-c/mobile-ios/ios/App/Podfile.lock +0 -205
  362. package/botrun-c/mobile-ios/ios/App/add_plist.rb +0 -30
  363. package/botrun-c/mobile-ios/ios/App/fix_plist_path.rb +0 -22
  364. package/botrun-c/mobile-ios/package.json +0 -29
  365. package/botrun-c/mobile-ios/resources/icon.png +0 -0
  366. package/botrun-c/mobile-ios/run-simulator.sh +0 -34
  367. package/botrun-c/mobile-ios/screenshot-after-clean-rebuild.png +0 -0
  368. package/botrun-c/mobile-ios/screenshot-final-version.png +0 -0
  369. package/botrun-c/mobile-ios/screenshot-simulator.png +0 -0
  370. package/botrun-c/mobile-ios/screenshot-version-1009.png +0 -0
  371. package/botrun-c/mobile-ios/screenshot-with-version.png +0 -0
  372. package/botrun-c/mobile-ios/screenshot-working.png +0 -0
  373. package/botrun-c/mobile-ios/setup-ios.sh +0 -106
  374. package/botrun-c/mobile-ios/tsconfig.json +0 -16
  375. package/botrun-c/org-policy-allow-all-users.yaml +0 -3
  376. package/botrun-c/package.json +0 -68
  377. package/botrun-c/pnpm-lock.yaml +0 -10198
  378. package/botrun-c/pnpm-workspace.yaml +0 -6
  379. package/botrun-c/prompts/BOTRUN-1.md +0 -13
  380. package/botrun-c/prompts/BOTRUN-2.md +0 -70
  381. package/botrun-c/prompts/BOTRUN-3.md +0 -139
  382. package/botrun-c/prototypes/firestore-gax-debug/package-lock.json +0 -1204
  383. package/botrun-c/prototypes/firestore-gax-debug/package.json +0 -12
  384. package/botrun-c/prototypes/firestore-gax-debug/pnpm-workspace.yaml +0 -2
  385. package/botrun-c/prototypes/firestore-gax-debug/test.js +0 -98
  386. package/botrun-c/prototypes/taiwan-haiku/README.md +0 -93
  387. package/botrun-c/prototypes/taiwan-haiku/index.ts +0 -139
  388. package/botrun-c/prototypes/taiwan-haiku/package.json +0 -23
  389. package/botrun-c/prototypes/taiwan-haiku/pnpm-lock.yaml +0 -730
  390. package/botrun-c/prototypes/taiwan-haiku/test-vertex-direct.ts +0 -83
  391. package/botrun-c/prototypes/taiwan-haiku/tsconfig.json +0 -18
  392. package/botrun-c/prototypes/web-search/FINDINGS-STAGE-1.md +0 -48
  393. package/botrun-c/prototypes/web-search/README.md +0 -46
  394. package/botrun-c/prototypes/web-search/VERIFICATION-REPORT.md +0 -310
  395. package/botrun-c/prototypes/web-search/package-lock.json +0 -595
  396. package/botrun-c/prototypes/web-search/package.json +0 -18
  397. package/botrun-c/prototypes/web-search/stage-1.1-basic-connection.js +0 -123
  398. package/botrun-c/prototypes/web-search/stage-1.2-with-websearch.js +0 -154
  399. package/botrun-c/prototypes/web-search/stage-1.3-search-query.js +0 -192
  400. package/botrun-c/prototypes/web-search/stage-2-agent-sdk-websearch.js +0 -265
  401. package/botrun-c/runtime-scripts/env-detect.sh +0 -64
  402. package/botrun-c/scripts/github-collaborator-manager.sh +0 -297
  403. package/botrun-c/scripts/github-collaborator-manager.ts +0 -325
  404. package/botrun-c/scripts/manage-collaborators.sh +0 -91
  405. package/botrun-c/scripts/setup-secrets.sh +0 -202
  406. package/botrun-c/scripts/stress-test-17-users.sh +0 -113
  407. package/botrun-c/scripts/stress-test-api.sh +0 -119
  408. package/botrun-c/scripts/stress-test-full-report.sh +0 -385
  409. package/botrun-c/specs/infra-vm/design.md +0 -0
  410. package/botrun-c/specs/share-skill/design.md +0 -1146
  411. package/botrun-c/specs/share-skill/tasks.md +0 -444
  412. package/botrun-c/stress-test-results/20260121-162630/config.json +0 -7
  413. package/botrun-c/stress-test-results/20260121-162630/user-1-status.txt +0 -1
  414. package/botrun-c/stress-test-results/20260121-162630/user-1-timing.txt +0 -1
  415. package/botrun-c/stress-test-results/20260121-162630/user-1.json +0 -2
  416. package/botrun-c/stress-test-results/20260121-162646/config.json +0 -7
  417. package/botrun-c/stress-test-results/20260121-162646/user-1-status.txt +0 -1
  418. package/botrun-c/stress-test-results/20260121-162646/user-1-timing.txt +0 -1
  419. package/botrun-c/stress-test-results/20260121-162646/user-1.json +0 -2
  420. package/botrun-c/stress-test-results/20260121-162646/user-10-status.txt +0 -1
  421. package/botrun-c/stress-test-results/20260121-162646/user-10-timing.txt +0 -1
  422. package/botrun-c/stress-test-results/20260121-162646/user-10.json +0 -2
  423. package/botrun-c/stress-test-results/20260121-162646/user-11-status.txt +0 -1
  424. package/botrun-c/stress-test-results/20260121-162646/user-11-timing.txt +0 -1
  425. package/botrun-c/stress-test-results/20260121-162646/user-11.json +0 -2
  426. package/botrun-c/stress-test-results/20260121-162646/user-12-status.txt +0 -1
  427. package/botrun-c/stress-test-results/20260121-162646/user-12-timing.txt +0 -1
  428. package/botrun-c/stress-test-results/20260121-162646/user-12.json +0 -2
  429. package/botrun-c/stress-test-results/20260121-162646/user-13-status.txt +0 -1
  430. package/botrun-c/stress-test-results/20260121-162646/user-13-timing.txt +0 -1
  431. package/botrun-c/stress-test-results/20260121-162646/user-13.json +0 -2
  432. package/botrun-c/stress-test-results/20260121-162646/user-14-status.txt +0 -1
  433. package/botrun-c/stress-test-results/20260121-162646/user-14-timing.txt +0 -1
  434. package/botrun-c/stress-test-results/20260121-162646/user-14.json +0 -2
  435. package/botrun-c/stress-test-results/20260121-162646/user-15-status.txt +0 -1
  436. package/botrun-c/stress-test-results/20260121-162646/user-15-timing.txt +0 -1
  437. package/botrun-c/stress-test-results/20260121-162646/user-15.json +0 -2
  438. package/botrun-c/stress-test-results/20260121-162646/user-16-status.txt +0 -1
  439. package/botrun-c/stress-test-results/20260121-162646/user-16-timing.txt +0 -1
  440. package/botrun-c/stress-test-results/20260121-162646/user-16.json +0 -2
  441. package/botrun-c/stress-test-results/20260121-162646/user-17-status.txt +0 -1
  442. package/botrun-c/stress-test-results/20260121-162646/user-17-timing.txt +0 -1
  443. package/botrun-c/stress-test-results/20260121-162646/user-17.json +0 -2
  444. package/botrun-c/stress-test-results/20260121-162646/user-2-status.txt +0 -1
  445. package/botrun-c/stress-test-results/20260121-162646/user-2-timing.txt +0 -1
  446. package/botrun-c/stress-test-results/20260121-162646/user-2.json +0 -2
  447. package/botrun-c/stress-test-results/20260121-162646/user-3-status.txt +0 -1
  448. package/botrun-c/stress-test-results/20260121-162646/user-3-timing.txt +0 -1
  449. package/botrun-c/stress-test-results/20260121-162646/user-3.json +0 -2
  450. package/botrun-c/stress-test-results/20260121-162646/user-4-status.txt +0 -1
  451. package/botrun-c/stress-test-results/20260121-162646/user-4-timing.txt +0 -1
  452. package/botrun-c/stress-test-results/20260121-162646/user-4.json +0 -2
  453. package/botrun-c/stress-test-results/20260121-162646/user-5-status.txt +0 -1
  454. package/botrun-c/stress-test-results/20260121-162646/user-5-timing.txt +0 -1
  455. package/botrun-c/stress-test-results/20260121-162646/user-5.json +0 -2
  456. package/botrun-c/stress-test-results/20260121-162646/user-6-status.txt +0 -1
  457. package/botrun-c/stress-test-results/20260121-162646/user-6-timing.txt +0 -1
  458. package/botrun-c/stress-test-results/20260121-162646/user-6.json +0 -2
  459. package/botrun-c/stress-test-results/20260121-162646/user-7-status.txt +0 -1
  460. package/botrun-c/stress-test-results/20260121-162646/user-7-timing.txt +0 -1
  461. package/botrun-c/stress-test-results/20260121-162646/user-7.json +0 -2
  462. package/botrun-c/stress-test-results/20260121-162646/user-8-status.txt +0 -1
  463. package/botrun-c/stress-test-results/20260121-162646/user-8-timing.txt +0 -1
  464. package/botrun-c/stress-test-results/20260121-162646/user-8.json +0 -2
  465. package/botrun-c/stress-test-results/20260121-162646/user-9-status.txt +0 -1
  466. package/botrun-c/stress-test-results/20260121-162646/user-9-timing.txt +0 -1
  467. package/botrun-c/stress-test-results/20260121-162646/user-9.json +0 -2
  468. package/botrun-c/stress-test-results/20260121-163148/REPORT.html +0 -344
  469. package/botrun-c/stress-test-results/20260121-163148/REPORT.md +0 -93
  470. package/botrun-c/stress-test-results/20260121-163148/REPORT.pdf +0 -0
  471. package/botrun-c/stress-test-results/20260121-163148/config.json +0 -7
  472. package/botrun-c/stress-test-results/20260121-163148/summary.json +0 -26
  473. package/botrun-c/stress-test-results/20260121-163148/user-1-status.txt +0 -1
  474. package/botrun-c/stress-test-results/20260121-163148/user-1-timing.txt +0 -1
  475. package/botrun-c/stress-test-results/20260121-163148/user-1.json +0 -206
  476. package/botrun-c/stress-test-results/20260121-163148/user-10-status.txt +0 -1
  477. package/botrun-c/stress-test-results/20260121-163148/user-10-timing.txt +0 -1
  478. package/botrun-c/stress-test-results/20260121-163148/user-10.json +0 -110
  479. package/botrun-c/stress-test-results/20260121-163148/user-11-status.txt +0 -1
  480. package/botrun-c/stress-test-results/20260121-163148/user-11-timing.txt +0 -1
  481. package/botrun-c/stress-test-results/20260121-163148/user-11.json +0 -104
  482. package/botrun-c/stress-test-results/20260121-163148/user-12-status.txt +0 -1
  483. package/botrun-c/stress-test-results/20260121-163148/user-12-timing.txt +0 -1
  484. package/botrun-c/stress-test-results/20260121-163148/user-12.json +0 -98
  485. package/botrun-c/stress-test-results/20260121-163148/user-13-status.txt +0 -1
  486. package/botrun-c/stress-test-results/20260121-163148/user-13-timing.txt +0 -1
  487. package/botrun-c/stress-test-results/20260121-163148/user-13.json +0 -68
  488. package/botrun-c/stress-test-results/20260121-163148/user-14-status.txt +0 -1
  489. package/botrun-c/stress-test-results/20260121-163148/user-14-timing.txt +0 -1
  490. package/botrun-c/stress-test-results/20260121-163148/user-14.json +0 -116
  491. package/botrun-c/stress-test-results/20260121-163148/user-15-status.txt +0 -1
  492. package/botrun-c/stress-test-results/20260121-163148/user-15-timing.txt +0 -1
  493. package/botrun-c/stress-test-results/20260121-163148/user-15.json +0 -131
  494. package/botrun-c/stress-test-results/20260121-163148/user-16-status.txt +0 -1
  495. package/botrun-c/stress-test-results/20260121-163148/user-16-timing.txt +0 -1
  496. package/botrun-c/stress-test-results/20260121-163148/user-16.json +0 -110
  497. package/botrun-c/stress-test-results/20260121-163148/user-17-status.txt +0 -1
  498. package/botrun-c/stress-test-results/20260121-163148/user-17-timing.txt +0 -1
  499. package/botrun-c/stress-test-results/20260121-163148/user-17.json +0 -116
  500. package/botrun-c/stress-test-results/20260121-163148/user-2-status.txt +0 -1
  501. package/botrun-c/stress-test-results/20260121-163148/user-2-timing.txt +0 -1
  502. package/botrun-c/stress-test-results/20260121-163148/user-2.json +0 -98
  503. package/botrun-c/stress-test-results/20260121-163148/user-3-status.txt +0 -1
  504. package/botrun-c/stress-test-results/20260121-163148/user-3-timing.txt +0 -1
  505. package/botrun-c/stress-test-results/20260121-163148/user-3.json +0 -62
  506. package/botrun-c/stress-test-results/20260121-163148/user-4-status.txt +0 -1
  507. package/botrun-c/stress-test-results/20260121-163148/user-4-timing.txt +0 -1
  508. package/botrun-c/stress-test-results/20260121-163148/user-4.json +0 -113
  509. package/botrun-c/stress-test-results/20260121-163148/user-5-status.txt +0 -1
  510. package/botrun-c/stress-test-results/20260121-163148/user-5-timing.txt +0 -1
  511. package/botrun-c/stress-test-results/20260121-163148/user-5.json +0 -83
  512. package/botrun-c/stress-test-results/20260121-163148/user-6-status.txt +0 -1
  513. package/botrun-c/stress-test-results/20260121-163148/user-6-timing.txt +0 -1
  514. package/botrun-c/stress-test-results/20260121-163148/user-6.json +0 -125
  515. package/botrun-c/stress-test-results/20260121-163148/user-7-status.txt +0 -1
  516. package/botrun-c/stress-test-results/20260121-163148/user-7-timing.txt +0 -1
  517. package/botrun-c/stress-test-results/20260121-163148/user-7.json +0 -62
  518. package/botrun-c/stress-test-results/20260121-163148/user-8-status.txt +0 -1
  519. package/botrun-c/stress-test-results/20260121-163148/user-8-timing.txt +0 -1
  520. package/botrun-c/stress-test-results/20260121-163148/user-8.json +0 -41
  521. package/botrun-c/stress-test-results/20260121-163148/user-9-status.txt +0 -1
  522. package/botrun-c/stress-test-results/20260121-163148/user-9-timing.txt +0 -1
  523. package/botrun-c/stress-test-results/20260121-163148/user-9.json +0 -53
  524. package/botrun-c/test-merge.md +0 -1
  525. package/botrun-c/version.txt +0 -1
  526. package/botrun-c/web/.version +0 -1
  527. package/botrun-c/web/ALLOW-PUBLIC-ACCESS.md +0 -57
  528. package/botrun-c/web/FINAL-SETUP-STEPS.md +0 -71
  529. package/botrun-c/web/FIREBASE-MANUAL-STEPS.md +0 -41
  530. package/botrun-c/web/QUICK-SETUP-HELPER.md +0 -79
  531. package/botrun-c/web/README.md +0 -162
  532. package/botrun-c/web/__tests__/image-extractor.test.ts +0 -147
  533. package/botrun-c/web/__tests__/useGitHub.test.ts +0 -245
  534. package/botrun-c/web/app/favicon.ico +0 -0
  535. package/botrun-c/web/app/globals.css +0 -215
  536. package/botrun-c/web/app/image-preview/page.tsx +0 -213
  537. package/botrun-c/web/app/layout.tsx +0 -46
  538. package/botrun-c/web/app/page.tsx +0 -45
  539. package/botrun-c/web/components/CapacitorProvider.tsx +0 -43
  540. package/botrun-c/web/components/ChatPage.tsx +0 -1736
  541. package/botrun-c/web/components/ConversationList.tsx +0 -237
  542. package/botrun-c/web/components/ConversationListItem.tsx +0 -121
  543. package/botrun-c/web/components/LoginPage.tsx +0 -212
  544. package/botrun-c/web/components/Providers.tsx +0 -12
  545. package/botrun-c/web/components/StatusBarProvider.tsx +0 -16
  546. package/botrun-c/web/components/attachment-preview.tsx +0 -193
  547. package/botrun-c/web/components/botrun-incubator/BotrunIncubator.tsx +0 -266
  548. package/botrun-c/web/components/botrun-incubator/index.ts +0 -1
  549. package/botrun-c/web/components/chat-input.tsx +0 -1251
  550. package/botrun-c/web/components/chat-message.tsx +0 -598
  551. package/botrun-c/web/components/drop-zone.tsx +0 -143
  552. package/botrun-c/web/components/gdrive/gdrive-add-dialog.tsx +0 -254
  553. package/botrun-c/web/components/gdrive/gdrive-drawer.tsx +0 -236
  554. package/botrun-c/web/components/gdrive/gdrive-selector.tsx +0 -226
  555. package/botrun-c/web/components/gdrive/index.ts +0 -7
  556. package/botrun-c/web/components/generated-image-card.tsx +0 -363
  557. package/botrun-c/web/components/github/GitHubConnect.tsx +0 -366
  558. package/botrun-c/web/components/github/index.ts +0 -2
  559. package/botrun-c/web/components/import-skill-dialog.tsx +0 -208
  560. package/botrun-c/web/components/scroll-to-bottom-button.tsx +0 -90
  561. package/botrun-c/web/components/share-skill-dialog.tsx +0 -175
  562. package/botrun-c/web/components/skills-editor.tsx +0 -443
  563. package/botrun-c/web/components/skills-manager-drawer.tsx +0 -586
  564. package/botrun-c/web/components/smart-button-group.tsx +0 -132
  565. package/botrun-c/web/config/smart-buttons.ts +0 -295
  566. package/botrun-c/web/config/welcome-messages.ts +0 -29
  567. package/botrun-c/web/contexts/AuthContext.tsx +0 -220
  568. package/botrun-c/web/hooks/use-toast.ts +0 -187
  569. package/botrun-c/web/hooks/useAppStoreUpdate.ts +0 -356
  570. package/botrun-c/web/hooks/useAppVersion.ts +0 -113
  571. package/botrun-c/web/hooks/useAttachments.ts +0 -269
  572. package/botrun-c/web/hooks/useAuthToken.ts +0 -59
  573. package/botrun-c/web/hooks/useAutoWelcome.ts +0 -89
  574. package/botrun-c/web/hooks/useCapacitorPlatform.ts +0 -113
  575. package/botrun-c/web/hooks/useCapawesomeLiveUpdate.ts +0 -149
  576. package/botrun-c/web/hooks/useClaudeModel.ts +0 -118
  577. package/botrun-c/web/hooks/useConversation.ts +0 -115
  578. package/botrun-c/web/hooks/useConversations.ts +0 -235
  579. package/botrun-c/web/hooks/useGdriveFolders.ts +0 -199
  580. package/botrun-c/web/hooks/useGdriveSync.ts +0 -107
  581. package/botrun-c/web/hooks/useGitHub.ts +0 -409
  582. package/botrun-c/web/hooks/useScrollToBottom.ts +0 -150
  583. package/botrun-c/web/hooks/useStatusBar.ts +0 -42
  584. package/botrun-c/web/hooks/useUserPlan.ts +0 -153
  585. package/botrun-c/web/lib/api-config.ts +0 -162
  586. package/botrun-c/web/lib/api-url.ts +0 -62
  587. package/botrun-c/web/lib/api.ts +0 -105
  588. package/botrun-c/web/lib/attachment-utils.ts +0 -168
  589. package/botrun-c/web/lib/build-version.ts +0 -11
  590. package/botrun-c/web/lib/clipboard-utils.ts +0 -199
  591. package/botrun-c/web/lib/constants.ts +0 -62
  592. package/botrun-c/web/lib/conversation-storage.ts +0 -324
  593. package/botrun-c/web/lib/firebase-capacitor.ts +0 -135
  594. package/botrun-c/web/lib/firebase.ts +0 -137
  595. package/botrun-c/web/lib/firestore-auth.ts +0 -61
  596. package/botrun-c/web/lib/firestore-auth.ts.migration-bak +0 -319
  597. package/botrun-c/web/lib/image-extractor.ts +0 -156
  598. package/botrun-c/web/lib/path-utils.ts +0 -48
  599. package/botrun-c/web/lib/rehype-del-to-mark.ts +0 -19
  600. package/botrun-c/web/lib/upload-service.ts +0 -326
  601. package/botrun-c/web/lib/utils.ts +0 -6
  602. package/botrun-c/web/next.config.js +0 -49
  603. package/botrun-c/web/package-lock.json +0 -6711
  604. package/botrun-c/web/package.json +0 -63
  605. package/botrun-c/web/postcss.config.js +0 -6
  606. package/botrun-c/web/public/apple_icon.png +0 -0
  607. package/botrun-c/web/public/google_icon.png +0 -0
  608. package/botrun-c/web/public/logo-48-small.png +0 -0
  609. package/botrun-c/web/public/logo-48.png +0 -0
  610. package/botrun-c/web/scripts/generate-version.js +0 -36
  611. package/botrun-c/web/scripts/update-build-version.js +0 -41
  612. package/botrun-c/web/tailwind.config.ts +0 -80
  613. package/botrun-c/web/test-welcome-message.mjs +0 -115
  614. package/botrun-c/web/tsconfig.json +0 -42
  615. package/botrun-c/web/types/agent.ts +0 -6
  616. package/botrun-c/web/types/attachment.ts +0 -39
  617. package/botrun-c/web/types/conversation.ts +0 -68
  618. package/botrun-c/web/types/flutter.d.ts +0 -6
  619. package/botrun-c/web/types/project.ts +0 -41
  620. package/botrun-c/web/types/skills.ts +0 -13
  621. package/botrun-c/web//350/250/272/346/226/267-Skills-/345/211/215/347/253/257/351/241/257/347/244/272/345/225/217/351/241/214.md +0 -83
  622. package/lib/writing/index.mjs +0 -5
  623. /package/{lib/core → modules/_core}/adapters/base.mjs +0 -0
  624. /package/{lib/core → modules/_core}/adapters/claude.mjs +0 -0
  625. /package/{lib/core → modules/_core}/adapters/gemini-api.mjs +0 -0
  626. /package/{lib/core → modules/_core}/adapters/gemini-shared.mjs +0 -0
  627. /package/{lib/core → modules/_core}/adapters/gemini-vertex.mjs +0 -0
  628. /package/{lib/core → modules/_core}/adapters/local.mjs +0 -0
  629. /package/{lib/core → modules/_core}/adapters/nchc.mjs +0 -0
  630. /package/{lib/core → modules/_core}/adapters/openai-shared.mjs +0 -0
  631. /package/{lib/core → modules/_core}/adapters/openrouter.mjs +0 -0
  632. /package/{lib/core → modules/_core}/ai-cache.mjs +0 -0
  633. /package/{lib/core → modules/_core}/ai-router.mjs +0 -0
  634. /package/{lib/core → modules/_core}/cli-utils.mjs +0 -0
  635. /package/{lib/core → modules/_core}/dag.mjs +0 -0
  636. /package/{lib/core → modules/_core}/db.mjs +0 -0
  637. /package/{lib/core → modules/_core}/env.mjs +0 -0
  638. /package/{lib/flows → modules/_core}/hatch-portal.mjs +0 -0
  639. /package/{lib/core → modules/_core}/llm.mjs +0 -0
  640. /package/{lib/flows → modules/_core}/opencode-agent.mjs +0 -0
  641. /package/{lib/core → modules/_core}/paths.mjs +0 -0
  642. /package/{lib/core → modules/_core}/proxy.mjs +0 -0
  643. /package/{lib/flows → modules/_core}/review-doc.mjs +0 -0
  644. /package/{lib → modules/_core}/tools/fs-tools.mjs +0 -0
  645. /package/{lib → modules/_core}/tools/index.mjs +0 -0
  646. /package/{lib/core → modules/_core}/watermelon.mjs +0 -0
  647. /package/{lib/ocr/index.mjs → modules/ocr/ocr-lib.mjs} +0 -0
  648. /package/{lib → modules}/portal/hatch.mjs +0 -0
  649. /package/{lib/portal/index.mjs → modules/portal/portal-lib.mjs} +0 -0
  650. /package/{lib → modules}/search/crawler.mjs +0 -0
  651. /package/{lib/prompt → modules/skill}/prompts/zero-framework/coding.md +0 -0
  652. /package/{lib/prompt → modules/skill}/prompts/zero-framework/fullstack.md +0 -0
  653. /package/{lib/prompt → modules/skill}/prompts/zero-framework/gemini-search-cli.md +0 -0
  654. /package/{lib/prompt → modules/skill}/prompts/zero-framework/search.md +0 -0
  655. /package/{lib/prompt → modules/skill}/prompts/zero-framework/segment.md +0 -0
  656. /package/{lib/prompt → modules/skill}/prompts/zero-framework/slice.md +0 -0
  657. /package/{lib/prompt → modules/skill}/prompts/zero-framework/smart-cache.md +0 -0
  658. /package/{lib/prompt → modules/skill}/prompts/zero-framework/trigram-search.md +0 -0
  659. /package/{lib/prompt → modules/skill}/prompts/zero-framework/tts-format.md +0 -0
  660. /package/{lib/prompt → modules/skill}/prompts/zero-framework/watermelon-sqlite.md +0 -0
  661. /package/{lib → modules}/writing/generators/nstc-generators.mjs +0 -0
  662. /package/{lib → modules}/writing/generators/nstc-top5.mjs +0 -0
  663. /package/{lib → modules}/writing/layouts/nstc-layout.mjs +0 -0
  664. /package/{lib → modules}/writing/renderer.mjs +0 -0
@@ -1,1321 +0,0 @@
1
- #!/usr/bin/env tsx
2
- /**
3
- * 波特人 Users CLI - 統一使用者管理工具
4
- *
5
- * 管理 Rate Limit、訂閱、使用者資訊等
6
- *
7
- * 注意:請透過 users-cli.sh 執行此腳本,以確保正確的環境變數設定
8
- */
9
-
10
- import { Command } from 'commander';
11
- import { initializeFirebase, getFirestore, getAuth } from './lib/firebase.js';
12
- import { resolveUser } from './lib/user-resolver.js';
13
- import { formatJSON, exportCSV, formatProgressBar, formatDate } from './lib/formatters.js';
14
- import { safeDeleteBatch, getUserRateLimitCounterIds } from './lib/firestore-safe.js';
15
-
16
- // 初始化 Firebase
17
- initializeFirebase();
18
-
19
- const program = new Command();
20
-
21
- program
22
- .name('users-cli')
23
- .description('波特人使用者管理 CLI - 管理 Rate Limit、訂閱、使用者資訊')
24
- .version('1.0.0');
25
-
26
- // ============================================================================
27
- // subscription-stats 命令 - 查詢真實方案分佈和成本統計
28
- // ============================================================================
29
-
30
- program
31
- .command('subscription-stats')
32
- .description('查詢使用者方案分佈和成本統計(基於真實 Token 使用量)')
33
- .action(async () => {
34
- try {
35
- const db = getFirestore();
36
- const auth = getAuth();
37
-
38
- console.log('\n📊 查詢真實方案分佈...\n');
39
-
40
- // 1. 查詢所有使用者
41
- const allUsers = [];
42
- let pageToken = undefined;
43
- do {
44
- const result = await auth.listUsers(1000, pageToken);
45
- allUsers.push(...result.users);
46
- pageToken = result.pageToken;
47
- } while (pageToken);
48
-
49
- console.log(`✅ 找到 ${allUsers.length} 位使用者\n`);
50
-
51
- // 2. 查詢訂閱資訊和 Token 使用量
52
- const planStats = new Map<string, { count: number; totalTokens: number; users: any[] }>();
53
- let totalTokens = 0;
54
- let userWithData = 0;
55
-
56
- for (const user of allUsers) {
57
- try {
58
- const subDoc = await db.collection('user_subscriptions').doc(user.uid).get();
59
- const plan = subDoc.exists ? (subDoc.data()?.plan || 'Lite') : 'Lite';
60
-
61
- // 查詢 rate_limit_counters 取得 Token 使用量
62
- const counterDocs = await db
63
- .collection('rate_limit_counters')
64
- .where('userId', '==', user.uid)
65
- .get();
66
-
67
- let userTokens = 0;
68
- counterDocs.forEach(doc => {
69
- const data = doc.data();
70
- if (data.tokensUsed) userTokens += data.tokensUsed;
71
- });
72
-
73
- if (userTokens > 0) userWithData++;
74
- totalTokens += userTokens;
75
-
76
- const existing = planStats.get(plan) || { count: 0, totalTokens: 0, users: [] };
77
- existing.count++;
78
- existing.totalTokens += userTokens;
79
- existing.users.push({
80
- email: user.email || 'Unknown',
81
- tokens: userTokens
82
- });
83
- planStats.set(plan, existing);
84
- } catch (error) {
85
- // 忽略查詢錯誤
86
- }
87
- }
88
-
89
- // 3. 列印統計結果
90
- console.log('════════════════════════════════════════════════════════════');
91
- console.log('📋 方案分佈統計(基於 user_subscriptions)');
92
- console.log('════════════════════════════════════════════════════════════\n');
93
-
94
- let totalCostUSD = 0;
95
- Array.from(planStats.entries())
96
- .sort((a, b) => b[1].count - a[1].count)
97
- .forEach(([plan, data]) => {
98
- const tokensMT = (data.totalTokens / 1000000).toFixed(2);
99
- const costUSD = (data.totalTokens / 1000000) * 5; // 1M tokens = $5
100
- totalCostUSD += costUSD;
101
-
102
- console.log(`📌 ${plan} 方案`);
103
- console.log(` 使用者數: ${data.count} 位`);
104
- console.log(` 總 Token: ${tokensMT}M (${data.totalTokens.toLocaleString()})`);
105
- console.log(` 預估成本: $${costUSD.toFixed(2)} USD`);
106
- console.log(` 平均每使用者: ${(data.totalTokens / data.count / 1000000).toFixed(4)}M tokens, $${(costUSD / data.count).toFixed(2)}`);
107
- console.log('');
108
- });
109
-
110
- console.log('════════════════════════════════════════════════════════════');
111
- console.log('📈 總體統計');
112
- console.log('════════════════════════════════════════════════════════════\n');
113
-
114
- console.log(`總使用者數: ${allUsers.length}`);
115
- console.log(`有 Token 使用的使用者: ${userWithData} (${((userWithData / allUsers.length) * 100).toFixed(1)}%)`);
116
- console.log(`總 Token 使用量: ${(totalTokens / 1000000).toFixed(2)}M (${totalTokens.toLocaleString()})`);
117
- console.log(`總預估成本: $${totalCostUSD.toFixed(2)} USD`);
118
- console.log(`平均每使用者成本: $${(totalCostUSD / allUsers.length).toFixed(2)}`);
119
- console.log(`平均每活躍使用者: $${(totalCostUSD / (userWithData || 1)).toFixed(2)}`);
120
- console.log('');
121
-
122
- // 4. 計算日均成本(過去 7 天)
123
- const dailyAvg = totalCostUSD / 7;
124
- console.log('💰 過去 7 天成本評估');
125
- console.log(` 總成本: $${totalCostUSD.toFixed(2)}`);
126
- console.log(` 日均成本: $${dailyAvg.toFixed(2)}/日`);
127
- console.log(` 小時均成本: $${(dailyAvg / 24).toFixed(4)}/小時\n`);
128
-
129
- } catch (error: any) {
130
- console.error('❌ 執行失敗:', error.message);
131
- process.exit(1);
132
- }
133
- });
134
-
135
- // ============================================================================
136
- // list 命令 - 列出使用者
137
- // ============================================================================
138
-
139
- const listCommand = program
140
- .command('list')
141
- .description('列出使用者資訊');
142
-
143
- listCommand
144
- .option('--auth', '列出所有 Firebase Auth 使用者')
145
- .option('--firestore', '列出 Firestore users collection 使用者')
146
- .option('--rate-limit', '列出有 rate limit 記錄的使用者')
147
- .option('--subscription', '列出有訂閱記錄的使用者')
148
- .option('--export <format>', '匯出格式 (csv|json)')
149
- .action(async (options) => {
150
- try {
151
- if (options.auth) {
152
- // 列出 Firebase Auth 使用者
153
- console.log('📋 列出所有 Firebase Auth 使用者...\n');
154
- const auth = getAuth();
155
- const listResult = await auth.listUsers(1000);
156
-
157
- console.log(`找到 ${listResult.users.length} 位使用者:\n`);
158
- listResult.users.forEach((user, index) => {
159
- console.log(`${index + 1}. ${user.email || '(無 email)'}`);
160
- console.log(` UID: ${user.uid}`);
161
- console.log(` 建立時間: ${user.metadata.creationTime}`);
162
- console.log(` 最後登入: ${user.metadata.lastSignInTime || '從未登入'}`);
163
- console.log('');
164
- });
165
- } else if (options.firestore) {
166
- // 列出 Firestore users collection
167
- console.log('📊 列出 Firestore users collection 使用者...\n');
168
- const db = getFirestore();
169
- const snapshot = await db.collection('users').get();
170
-
171
- if (snapshot.empty) {
172
- console.log('❌ users collection 是空的!');
173
- return;
174
- }
175
-
176
- console.log(`✅ 找到 ${snapshot.size} 個使用者文件\n`);
177
- snapshot.forEach(doc => {
178
- const data = doc.data();
179
- console.log(`👤 User ID: ${doc.id}`);
180
- console.log(` Email: ${data.email || 'N/A'}`);
181
- console.log(` Display Name: ${data.displayName || 'N/A'}`);
182
- console.log(` Plan: ${data.plan || 'Lite (預設)'}`);
183
- console.log('');
184
- });
185
- } else {
186
- console.log('請指定選項: --auth, --firestore, --rate-limit, 或 --subscription');
187
- console.log('使用 --help 查看詳細說明');
188
- }
189
- } catch (error) {
190
- console.error('❌ 執行失敗:', error);
191
- process.exit(1);
192
- }
193
- });
194
-
195
- // ============================================================================
196
- // query 命令 - 查詢單一使用者
197
- // ============================================================================
198
-
199
- program
200
- .command('query')
201
- .description('查詢單一使用者的完整資訊(訂閱 + Rate Limit)')
202
- .argument('<email-or-uid>', '使用者 email 或 UID')
203
- .option('--json', '以 JSON 格式輸出')
204
- .action(async (emailOrUid, options) => {
205
- try {
206
- console.log('🔍 正在查詢使用者資訊...\n');
207
-
208
- // 解析使用者
209
- const user = await resolveUser(emailOrUid);
210
- console.log(`✅ 找到使用者: ${user.email || user.uid}\n`);
211
-
212
- const db = getFirestore();
213
-
214
- // 查詢訂閱
215
- console.log('==================================================');
216
- console.log('📋 訂閱資訊');
217
- console.log('==================================================\n');
218
-
219
- const subDoc = await db.collection('user_subscriptions').doc(user.uid).get();
220
- if (subDoc.exists) {
221
- const subData = subDoc.data();
222
- if (options.json) {
223
- console.log(JSON.stringify(subData, null, 2));
224
- } else {
225
- console.log(`狀態: ${subData?.status}`);
226
- console.log(`方案: ${subData?.plan}`);
227
- console.log(`試用開始: ${subData?.trialStartDate?.toDate?.() || 'N/A'}`);
228
- console.log(`試用結束: ${subData?.trialEndDate?.toDate?.() || 'N/A'}`);
229
- }
230
- } else {
231
- console.log('❌ 沒有訂閱記錄');
232
- }
233
-
234
- // 查詢 Rate Limit
235
- console.log('\n==================================================');
236
- console.log('🔒 Rate Limit 狀態');
237
- console.log('==================================================\n');
238
-
239
- const counterIds = await getUserRateLimitCounterIds(user.uid);
240
- if (counterIds.length > 0) {
241
- console.log(`找到 ${counterIds.length} 個計數器記錄:`);
242
- counterIds.forEach(id => console.log(` - ${id}`));
243
- } else {
244
- console.log('❌ 沒有 Rate Limit 記錄');
245
- }
246
-
247
- console.log('\n==================================================\n');
248
-
249
- } catch (error: any) {
250
- console.error('❌ 執行失敗:', error.message);
251
- process.exit(1);
252
- }
253
- });
254
-
255
- // ============================================================================
256
- // rate-limit 命令
257
- // ============================================================================
258
-
259
- const rateLimitCommand = program
260
- .command('rate-limit')
261
- .description('Rate Limit 管理');
262
-
263
- rateLimitCommand
264
- .command('list')
265
- .description('列出所有使用者的 Rate Limit 狀態')
266
- .option('--detailed', '顯示詳細資訊(包含 plan、custom limits)')
267
- .option('--export <format>', '匯出格式 (csv)')
268
- .action(async (options) => {
269
- if (options.detailed) {
270
- // 使用新的詳細列表功能
271
- try {
272
- const { getAllDetailedStatuses, displayDetailedStatus } = await import('./lib/rate-limit-detailed.js');
273
-
274
- console.log('🔍 載入所有使用者的詳細 Rate Limit 狀態...\n');
275
-
276
- const statuses = await getAllDetailedStatuses();
277
-
278
- if (statuses.length === 0) {
279
- console.log('📭 目前沒有任何使用者');
280
- return;
281
- }
282
-
283
- console.log(`✅ 找到 ${statuses.length} 位使用者\n`);
284
-
285
- statuses.forEach(status => {
286
- displayDetailedStatus(status);
287
- });
288
-
289
- // 如果有匯出選項,產生 CSV
290
- if (options.export === 'csv') {
291
- const { exportToCSV } = await import('./lib/rate-limit-detailed.js');
292
- const { writeFileSync } = await import('fs');
293
- const { execSync } = await import('child_process');
294
-
295
- const csv = exportToCSV(statuses);
296
- const filename = `rate-limit-detailed-${Date.now()}.csv`;
297
- writeFileSync(filename, csv);
298
-
299
- console.log(`\n✅ CSV 已匯出: ${filename}`);
300
- console.log('📂 正在開啟檔案...\n');
301
-
302
- try {
303
- execSync(`open "${filename}"`);
304
- } catch (error) {
305
- console.log('⚠️ 無法自動開啟檔案,請手動開啟');
306
- }
307
- }
308
- } catch (error) {
309
- console.error('❌ 執行失敗:', error);
310
- process.exit(1);
311
- }
312
- } else {
313
- // 使用舊的列表功能
314
- const {
315
- getAllUserIds,
316
- getUserStatus,
317
- displayUserStatus,
318
- displaySummary,
319
- saveAndOpenCSV,
320
- } = await import('./lib/rate-limit.js');
321
-
322
- try {
323
- // 取得所有使用者 ID
324
- const userIds = await getAllUserIds();
325
-
326
- if (userIds.length === 0) {
327
- console.log('📭 目前沒有任何使用者有 Rate Limit 記錄');
328
- return;
329
- }
330
-
331
- console.log(`\n找到 ${userIds.length} 位使用者\n`);
332
-
333
- // 取得並顯示每個使用者的狀態
334
- const statuses = [];
335
-
336
- for (const userId of userIds) {
337
- const status = await getUserStatus(userId);
338
- statuses.push(status);
339
- displayUserStatus(status);
340
- }
341
-
342
- // 顯示統計摘要
343
- displaySummary(statuses);
344
- console.log(`\n${'='.repeat(60)}\n`);
345
-
346
- // 如果有匯出選項,產生 CSV
347
- if (options.export === 'csv') {
348
- await saveAndOpenCSV(statuses);
349
- }
350
- } catch (error) {
351
- console.error('❌ 執行失敗:', error);
352
- process.exit(1);
353
- }
354
- }
355
- });
356
-
357
- rateLimitCommand
358
- .command('query')
359
- .description('查詢特定使用者的 Rate Limit 狀態')
360
- .argument('<email-or-uid>', '使用者 email 或 UID')
361
- .option('--detailed', '顯示詳細資訊(包含 plan、custom limits、當前值)')
362
- .action(async (emailOrUid, options) => {
363
- if (options.detailed) {
364
- // 使用新的詳細查詢功能
365
- try {
366
- const { getDetailedRateLimitStatus, displayDetailedStatus } = await import('./lib/rate-limit-detailed.js');
367
- const user = await resolveUser(emailOrUid);
368
- const status = await getDetailedRateLimitStatus(user.uid);
369
- displayDetailedStatus(status);
370
- } catch (error: any) {
371
- console.error('❌ 執行失敗:', error.message);
372
- process.exit(1);
373
- }
374
- } else {
375
- // 使用舊的查詢方式
376
- console.log('🔍 查詢 Rate Limit 狀態...\n');
377
- const { execSync } = await import('child_process');
378
- execSync(`tsx ../api/scripts/query-user-info.ts ${emailOrUid}`, {
379
- stdio: 'inherit',
380
- cwd: __dirname
381
- });
382
- }
383
- });
384
-
385
- rateLimitCommand
386
- .command('reset')
387
- .description('重置特定使用者的 Rate Limit')
388
- .argument('<email-or-uid>', '使用者 email 或 UID')
389
- .action(async (emailOrUid) => {
390
- try {
391
- console.log('🔄 正在重置 Rate Limit...\n');
392
-
393
- // 解析使用者
394
- const user = await resolveUser(emailOrUid);
395
- console.log(`✅ 找到使用者: ${user.email || user.uid}`);
396
- console.log(`👤 UID: ${user.uid}\n`);
397
-
398
- // 取得所有計數器
399
- const counterIds = await getUserRateLimitCounterIds(user.uid);
400
-
401
- if (counterIds.length === 0) {
402
- console.log('✅ 此使用者沒有任何 Rate Limit 記錄\n');
403
- return;
404
- }
405
-
406
- console.log(`找到 ${counterIds.length} 個計數器:\n`);
407
- counterIds.forEach(id => console.log(` 🗑️ ${id}`));
408
-
409
- console.log(`\n🗑️ 準備刪除 ${counterIds.length} 個計數器...\n`);
410
-
411
- // 使用安全刪除(避開 google-gax 問題)
412
- const result = await safeDeleteBatch('rate_limit_counters', counterIds);
413
-
414
- console.log(`\n✅ Rate Limit 已成功清除!`);
415
- console.log(`📊 成功: ${result.success}, 失敗: ${result.failed}\n`);
416
- console.log('🎉 使用者現在可以重新開始使用服務\n');
417
-
418
- } catch (error: any) {
419
- console.error('❌ 執行失敗:', error.message);
420
- process.exit(1);
421
- }
422
- });
423
-
424
- rateLimitCommand
425
- .command('set-custom')
426
- .description('設定特定使用者的自訂 Rate Limit')
427
- .argument('<email-or-uid>', '使用者 email 或 UID')
428
- .option('--rpm <number>', 'RPM (每分鐘請求數) 限制')
429
- .option('--tpm <number>', 'TPM (每分鐘 Token 數) 限制')
430
- .option('--rpd <number>', 'RPD (每日請求數) 限制')
431
- .action(async (emailOrUid, options) => {
432
- try {
433
- console.log('⚙️ 正在設定自訂 Rate Limit...\n');
434
-
435
- // 解析使用者
436
- const user = await resolveUser(emailOrUid);
437
- console.log(`✅ 找到使用者: ${user.email || user.uid}`);
438
- console.log(`👤 UID: ${user.uid}\n`);
439
-
440
- // 建構自訂限制物件
441
- const customLimits: any = {};
442
- if (options.rpm) customLimits.rpm = parseInt(options.rpm, 10);
443
- if (options.tpm) customLimits.tpm = parseInt(options.tpm, 10);
444
- if (options.rpd) customLimits.rpd = parseInt(options.rpd, 10);
445
-
446
- if (Object.keys(customLimits).length === 0) {
447
- console.error('❌ 請至少指定一個限制值 (--rpm, --tpm, 或 --rpd)');
448
- process.exit(1);
449
- }
450
-
451
- console.log('📝 設定的自訂限制:');
452
- if (customLimits.rpm) console.log(` RPM: ${customLimits.rpm}`);
453
- if (customLimits.tpm) console.log(` TPM: ${customLimits.tpm}`);
454
- if (customLimits.rpd) console.log(` RPD: ${customLimits.rpd}`);
455
- console.log('');
456
-
457
- // 使用新的 setCustomLimits 函數
458
- const { setCustomLimits } = await import('./lib/rate-limit-detailed.js');
459
- await setCustomLimits(user.uid, customLimits);
460
-
461
- console.log('✅ 自訂限制已成功設定!\n');
462
- console.log('📌 注意事項:');
463
- console.log(' - 此設定會覆寫該使用者的方案預設限制');
464
- console.log(' - 自訂限制在下次 API 請求時生效');
465
- console.log(' - 若要移除自訂限制,請使用: rate-limit remove-custom\n');
466
-
467
- } catch (error: any) {
468
- console.error('❌ 執行失敗:', error.message);
469
- process.exit(1);
470
- }
471
- });
472
-
473
- rateLimitCommand
474
- .command('remove-custom')
475
- .description('移除特定使用者的自訂 Rate Limit(恢復為方案預設值)')
476
- .argument('<email-or-uid>', '使用者 email 或 UID')
477
- .action(async (emailOrUid) => {
478
- try {
479
- console.log('🗑️ 正在移除自訂 Rate Limit...\n');
480
-
481
- // 解析使用者
482
- const user = await resolveUser(emailOrUid);
483
- console.log(`✅ 找到使用者: ${user.email || user.uid}`);
484
- console.log(`👤 UID: ${user.uid}\n`);
485
-
486
- // 先顯示目前的自訂限制(如果有)
487
- const { getDetailedRateLimitStatus } = await import('./lib/rate-limit-detailed.js');
488
- const status = await getDetailedRateLimitStatus(user.uid);
489
-
490
- if (!status.hasCustomLimits) {
491
- console.log('✅ 此使用者沒有自訂限制,無需移除\n');
492
- return;
493
- }
494
-
495
- console.log('⚠️ 目前的自訂限制:');
496
- if (status.customLimits?.rpm !== undefined) {
497
- console.log(` RPM: ${status.customLimits.rpm}`);
498
- }
499
- if (status.customLimits?.tpm !== undefined) {
500
- console.log(` TPM: ${status.customLimits.tpm}`);
501
- }
502
- if (status.customLimits?.rpd !== undefined) {
503
- console.log(` RPD: ${status.customLimits.rpd}`);
504
- }
505
- console.log('');
506
-
507
- // 移除自訂限制
508
- const { removeCustomLimits } = await import('./lib/rate-limit-detailed.js');
509
- await removeCustomLimits(user.uid);
510
-
511
- console.log('✅ 自訂限制已成功移除!\n');
512
- console.log('📌 結果:');
513
- console.log(` 使用者現在使用 ${status.plan} 的預設限制:`);
514
- console.log(` - RPM: ${status.planDefaults.rpm}`);
515
- console.log(` - TPM: ${status.planDefaults.tpm}`);
516
- console.log(` - RPD: ${status.planDefaults.rpd}\n`);
517
-
518
- } catch (error: any) {
519
- console.error('❌ 執行失敗:', error.message);
520
- process.exit(1);
521
- }
522
- });
523
-
524
- rateLimitCommand
525
- .command('set-counter')
526
- .description('設定特定使用者的計數器值(危險操作!僅供測試)')
527
- .argument('<email-or-uid>', '使用者 email 或 UID')
528
- .option('--rpm <number>', '設定 RPM 計數器值')
529
- .option('--tpm <number>', '設定 TPM 計數器值')
530
- .option('--rpd <number>', '設定 RPD 計數器值')
531
- .action(async (emailOrUid, options) => {
532
- try {
533
- console.log('⚠️ 設定計數器值(危險操作)\n');
534
-
535
- // 解析使用者
536
- const user = await resolveUser(emailOrUid);
537
- console.log(`✅ 找到使用者: ${user.email || user.uid}`);
538
- console.log(`👤 UID: ${user.uid}\n`);
539
-
540
- const { setCounterValue } = await import('./lib/rate-limit-detailed.js');
541
-
542
- let updated = 0;
543
-
544
- if (options.rpm !== undefined) {
545
- const value = parseInt(options.rpm, 10);
546
- console.log(`📝 設定 RPM 計數器 = ${value}`);
547
- await setCounterValue(user.uid, 'rpm', value);
548
- updated++;
549
- }
550
-
551
- if (options.tpm !== undefined) {
552
- const value = parseInt(options.tpm, 10);
553
- console.log(`📝 設定 TPM 計數器 = ${value}`);
554
- await setCounterValue(user.uid, 'tpm', value);
555
- updated++;
556
- }
557
-
558
- if (options.rpd !== undefined) {
559
- const value = parseInt(options.rpd, 10);
560
- console.log(`📝 設定 RPD 計數器 = ${value}`);
561
- await setCounterValue(user.uid, 'rpd', value);
562
- updated++;
563
- }
564
-
565
- if (updated === 0) {
566
- console.error('\n❌ 請至少指定一個計數器值 (--rpm, --tpm, 或 --rpd)');
567
- process.exit(1);
568
- }
569
-
570
- console.log(`\n✅ 已成功設定 ${updated} 個計數器!\n`);
571
- console.log('⚠️ 警告:此操作直接修改計數器,僅供測試使用\n');
572
-
573
- } catch (error: any) {
574
- console.error('❌ 執行失敗:', error.message);
575
- process.exit(1);
576
- }
577
- });
578
-
579
- rateLimitCommand
580
- .command('export')
581
- .description('快速匯出所有使用者的詳細 Rate Limit 資訊為 CSV')
582
- .action(async () => {
583
- try {
584
- console.log('📊 匯出所有使用者的 Rate Limit 資訊...\n');
585
-
586
- const { getAllDetailedStatuses, exportToCSV } = await import('./lib/rate-limit-detailed.js');
587
- const { writeFileSync } = await import('fs');
588
- const { execSync } = await import('child_process');
589
-
590
- console.log('🔍 載入使用者資料...');
591
- const statuses = await getAllDetailedStatuses();
592
-
593
- if (statuses.length === 0) {
594
- console.log('📭 目前沒有任何使用者\n');
595
- return;
596
- }
597
-
598
- console.log(`✅ 找到 ${statuses.length} 位使用者\n`);
599
-
600
- const csv = exportToCSV(statuses);
601
- const filename = `rate-limit-export-${Date.now()}.csv`;
602
- writeFileSync(filename, csv);
603
-
604
- console.log(`✅ CSV 已匯出: ${filename}`);
605
- console.log(`📊 包含欄位:`);
606
- console.log(` - 基本資訊: Email, UID, Plan`);
607
- console.log(` - Plan 預設限制: RPM, TPM, RPD`);
608
- console.log(` - 自訂限制: Custom RPM/TPM/RPD`);
609
- console.log(` - 實際生效限制: Effective RPM/TPM/RPD`);
610
- console.log(` - 當前使用量: Current RPM/TPM/RPD`);
611
- console.log(` - 使用率百分比\n`);
612
-
613
- console.log('📂 正在開啟檔案...\n');
614
-
615
- try {
616
- execSync(`open "${filename}"`);
617
- } catch (error) {
618
- console.log('⚠️ 無法自動開啟檔案,請手動開啟');
619
- }
620
-
621
- } catch (error: any) {
622
- console.error('❌ 執行失敗:', error.message);
623
- process.exit(1);
624
- }
625
- });
626
-
627
- // ============================================================================
628
- // subscription 命令
629
- // ============================================================================
630
-
631
- const subscriptionCommand = program
632
- .command('subscription')
633
- .description('訂閱管理');
634
-
635
- subscriptionCommand
636
- .command('list')
637
- .description('列出所有使用者的訂閱狀態')
638
- .option('--export <format>', '匯出格式 (csv)')
639
- .action(async (options) => {
640
- console.log('📊 列出所有訂閱狀態...\n');
641
-
642
- const { execSync } = await import('child_process');
643
- execSync('tsx ../api/scripts/dump-subscriptions.ts', {
644
- stdio: 'inherit',
645
- cwd: __dirname
646
- });
647
- });
648
-
649
- subscriptionCommand
650
- .command('query')
651
- .description('查詢特定使用者的訂閱狀態')
652
- .argument('<email-or-uid>', '使用者 email 或 UID')
653
- .action(async (emailOrUid) => {
654
- try {
655
- console.log('🔍 查詢訂閱狀態...\n');
656
-
657
- const user = await resolveUser(emailOrUid);
658
- const db = getFirestore();
659
- const subDoc = await db.collection('user_subscriptions').doc(user.uid).get();
660
-
661
- if (!subDoc.exists) {
662
- console.log('❌ 此使用者沒有訂閱記錄\n');
663
- return;
664
- }
665
-
666
- const data = subDoc.data();
667
- console.log('📋 訂閱資訊:');
668
- console.log(` 狀態: ${data?.status}`);
669
- console.log(` 方案: ${data?.plan}`);
670
- console.log(` 試用開始: ${data?.trialStartDate?.toDate?.()}`);
671
- console.log(` 試用結束: ${data?.trialEndDate?.toDate?.()}\n`);
672
-
673
- } catch (error: any) {
674
- console.error('❌ 執行失敗:', error.message);
675
- process.exit(1);
676
- }
677
- });
678
-
679
- subscriptionCommand
680
- .command('set-expiry')
681
- .description('設定使用者的試用期結束日期(用於測試過期功能)')
682
- .argument('<email-or-uid>', '使用者 email 或 UID')
683
- .argument('<date>', '過期日期 (格式: YYYY-MM-DD 或 yesterday/today/tomorrow)')
684
- .action(async (emailOrUid, dateStr) => {
685
- try {
686
- console.log('⚙️ 正在設定試用期結束日期...\n');
687
-
688
- const user = await resolveUser(emailOrUid);
689
- console.log(`✅ 找到使用者: ${user.email || user.uid}`);
690
- console.log(`👤 UID: ${user.uid}\n`);
691
-
692
- const db = getFirestore();
693
- const subRef = db.collection('user_subscriptions').doc(user.uid);
694
- const subDoc = await subRef.get();
695
-
696
- // 解析日期
697
- let targetDate: Date;
698
- const today = new Date();
699
- today.setHours(0, 0, 0, 0);
700
-
701
- if (dateStr === 'yesterday') {
702
- targetDate = new Date(today);
703
- targetDate.setDate(targetDate.getDate() - 1);
704
- } else if (dateStr === 'today') {
705
- targetDate = new Date(today);
706
- } else if (dateStr === 'tomorrow') {
707
- targetDate = new Date(today);
708
- targetDate.setDate(targetDate.getDate() + 1);
709
- } else {
710
- // 嘗試解析 YYYY-MM-DD 格式
711
- const parsed = new Date(dateStr);
712
- if (isNaN(parsed.getTime())) {
713
- console.error(`❌ 無效的日期格式: ${dateStr}`);
714
- console.error(' 支援格式: YYYY-MM-DD, yesterday, today, tomorrow');
715
- process.exit(1);
716
- }
717
- targetDate = parsed;
718
- }
719
-
720
- // 設定結束時間為當天 23:59:59
721
- targetDate.setHours(23, 59, 59, 999);
722
-
723
- if (subDoc.exists) {
724
- const data = subDoc.data();
725
- console.log('📋 目前訂閱資訊:');
726
- console.log(` 狀態: ${data?.status}`);
727
- console.log(` 方案: ${data?.plan}`);
728
- console.log(` 試用結束: ${data?.trialEndDate?.toDate?.() || 'N/A'}\n`);
729
-
730
- // 更新試用結束日期,並根據新日期自動調整狀態
731
- const now = new Date();
732
- const newStatus = targetDate > now ? 'active' : 'expired';
733
-
734
- await subRef.update({
735
- trialEndDate: targetDate,
736
- status: newStatus,
737
- updatedAt: new Date(),
738
- });
739
-
740
- if (data?.status !== newStatus) {
741
- console.log(`🔄 狀態已從 ${data?.status} 改為 ${newStatus}`);
742
- }
743
- } else {
744
- // 如果沒有訂閱記錄,建立 trial 訂閱
745
- const trialStart = new Date(targetDate);
746
- trialStart.setDate(trialStart.getDate() - 14); // 假設 14 天前開始
747
-
748
- await subRef.set({
749
- userId: user.uid,
750
- plan: 'Lite',
751
- status: 'trial',
752
- trialStartDate: trialStart,
753
- trialEndDate: targetDate,
754
- createdAt: new Date(),
755
- updatedAt: new Date(),
756
- });
757
- console.log('📝 已建立新的試用訂閱記錄\n');
758
- }
759
-
760
- console.log(`✅ 試用期結束日期已設定為: ${targetDate.toISOString()}`);
761
-
762
- // 判斷是否過期
763
- const now = new Date();
764
- if (targetDate < now) {
765
- console.log(`⚠️ 注意:此日期已過期!使用者將被視為試用期結束。\n`);
766
- } else {
767
- const daysLeft = Math.ceil((targetDate.getTime() - now.getTime()) / (1000 * 60 * 60 * 24));
768
- console.log(`📅 距離過期還有 ${daysLeft} 天\n`);
769
- }
770
-
771
- } catch (error: any) {
772
- console.error('❌ 執行失敗:', error.message);
773
- process.exit(1);
774
- }
775
- });
776
-
777
- subscriptionCommand
778
- .command('extend')
779
- .description('延長使用者的訂閱期限')
780
- .argument('<email-or-uid>', '使用者 email 或 UID')
781
- .argument('<duration>', '延長時間 (例如: 2y=2年, 6m=6個月, 30d=30天)')
782
- .action(async (emailOrUid, duration) => {
783
- try {
784
- console.log('📅 正在延長訂閱期限...\n');
785
-
786
- // 解析延長時間
787
- const match = duration.match(/^(\d+)(y|m|d)$/i);
788
- if (!match) {
789
- console.error(`❌ 無效的時間格式: ${duration}`);
790
- console.error(' 支援格式: 2y (2年), 6m (6個月), 30d (30天)');
791
- process.exit(1);
792
- }
793
-
794
- const amount = parseInt(match[1], 10);
795
- const unit = match[2].toLowerCase();
796
-
797
- const user = await resolveUser(emailOrUid);
798
- console.log(`✅ 找到使用者: ${user.email || user.uid}`);
799
- console.log(`👤 UID: ${user.uid}\n`);
800
-
801
- const db = getFirestore();
802
- const subRef = db.collection('user_subscriptions').doc(user.uid);
803
- const subDoc = await subRef.get();
804
-
805
- // 計算新的結束日期
806
- const now = new Date();
807
- let baseDate: Date;
808
-
809
- if (subDoc.exists) {
810
- const data = subDoc.data();
811
- console.log('📋 目前訂閱資訊:');
812
- console.log(` 狀態: ${data?.status}`);
813
- console.log(` 方案: ${data?.plan}`);
814
-
815
- // 取得目前結束日期
816
- const currentEndDate = data?.subscriptionEndDate?.toDate?.() || data?.trialEndDate?.toDate?.();
817
- if (currentEndDate) {
818
- console.log(` 目前到期: ${currentEndDate.toLocaleDateString('zh-TW')}`);
819
- }
820
- console.log('');
821
-
822
- // 從目前結束日期或今天開始計算(取較晚者)
823
- baseDate = currentEndDate && currentEndDate > now ? currentEndDate : now;
824
- } else {
825
- baseDate = now;
826
- }
827
-
828
- // 計算新結束日期
829
- const newEndDate = new Date(baseDate);
830
- switch (unit) {
831
- case 'y':
832
- newEndDate.setFullYear(newEndDate.getFullYear() + amount);
833
- break;
834
- case 'm':
835
- newEndDate.setMonth(newEndDate.getMonth() + amount);
836
- break;
837
- case 'd':
838
- newEndDate.setDate(newEndDate.getDate() + amount);
839
- break;
840
- }
841
- newEndDate.setHours(23, 59, 59, 999);
842
-
843
- // 更新或建立訂閱
844
- const updateData = {
845
- subscriptionEndDate: newEndDate,
846
- status: 'active',
847
- updatedAt: now,
848
- };
849
-
850
- if (subDoc.exists) {
851
- await subRef.update(updateData);
852
- } else {
853
- await subRef.set({
854
- userId: user.uid,
855
- plan: 'Lite',
856
- subscriptionStartDate: now,
857
- createdAt: now,
858
- ...updateData,
859
- });
860
- }
861
-
862
- const unitNames: Record<string, string> = { y: '年', m: '個月', d: '天' };
863
- console.log(`✅ 訂閱已延長 ${amount} ${unitNames[unit]}`);
864
- console.log(`📅 新的到期日: ${newEndDate.toLocaleDateString('zh-TW')}`);
865
-
866
- const daysLeft = Math.ceil((newEndDate.getTime() - now.getTime()) / (1000 * 60 * 60 * 24));
867
- console.log(`⏳ 距離到期還有 ${daysLeft} 天\n`);
868
-
869
- } catch (error: any) {
870
- console.error('❌ 執行失敗:', error.message);
871
- process.exit(1);
872
- }
873
- });
874
-
875
- subscriptionCommand
876
- .command('reset-trial')
877
- .description('重置使用者的試用期訂閱')
878
- .argument('<email-or-uid>', '使用者 email 或 UID')
879
- .action(async (emailOrUid) => {
880
- try {
881
- console.log('🔄 正在重置試用期...\n');
882
-
883
- const user = await resolveUser(emailOrUid);
884
- const db = getFirestore();
885
-
886
- const subDoc = await db.collection('user_subscriptions').doc(user.uid).get();
887
-
888
- if (subDoc.exists) {
889
- console.log('📋 目前訂閱資訊:');
890
- const data = subDoc.data();
891
- console.log(` 狀態: ${data?.status}`);
892
- console.log(` 方案: ${data?.plan}\n`);
893
- }
894
-
895
- console.log('🗑️ 刪除訂閱記錄...');
896
- await db.collection('user_subscriptions').doc(user.uid).delete();
897
-
898
- console.log('\n✅ 訂閱記錄已成功刪除!');
899
- console.log('\n🎉 使用者下次使用時將自動建立新的 14 天試用期\n');
900
-
901
- } catch (error: any) {
902
- console.error('❌ 執行失敗:', error.message);
903
- process.exit(1);
904
- }
905
- });
906
-
907
- // ============================================================================
908
- // migrate 命令
909
- // ============================================================================
910
-
911
- const migrateCommand = program
912
- .command('migrate')
913
- .description('資料遷移工具');
914
-
915
- migrateCommand
916
- .command('plan-free-rpd')
917
- .description('遷移 Lite 方案的 RPD 限制(舊稱 plan-free)')
918
- .action(async () => {
919
- console.log('🔄 執行 Lite 方案 RPD 遷移...\n');
920
-
921
- const { execSync } = await import('child_process');
922
- execSync('tsx ../api/scripts/migrate-plan-free-rpd.ts', {
923
- stdio: 'inherit',
924
- cwd: __dirname
925
- });
926
- });
927
-
928
- // ============================================================================
929
- // plan 命令 - Plan 管理
930
- // ============================================================================
931
-
932
- const planCommand = program
933
- .command('plan')
934
- .description('使用者方案管理');
935
-
936
- planCommand
937
- .command('set')
938
- .description('設定特定使用者的方案')
939
- .argument('<email-or-uid>', '使用者 email 或 UID')
940
- .argument('<plan>', '方案類型 (Lite | Max-1 | Max-2)')
941
- .action(async (emailOrUid, plan) => {
942
- try {
943
- console.log('⚙️ 正在設定使用者方案...\n');
944
-
945
- // 驗證方案類型
946
- const validPlans = ['Lite', 'Max-1', 'Max-2'];
947
- if (!validPlans.includes(plan)) {
948
- console.error(`❌ 無效的方案類型: ${plan}`);
949
- console.error(` 有效方案: ${validPlans.join(', ')}`);
950
- process.exit(1);
951
- }
952
-
953
- // 解析使用者
954
- const user = await resolveUser(emailOrUid);
955
- console.log(`✅ 找到使用者: ${user.email || user.uid}`);
956
- console.log(`👤 UID: ${user.uid}\n`);
957
-
958
- const db = getFirestore();
959
-
960
- // 1. 更新 user_subscriptions/{userId}
961
- const subRef = db.collection('user_subscriptions').doc(user.uid);
962
- const subDoc = await subRef.get();
963
-
964
- if (subDoc.exists) {
965
- console.log('📋 目前訂閱資訊:');
966
- const data = subDoc.data();
967
- console.log(` 狀態: ${data?.status}`);
968
- console.log(` 方案: ${data?.plan}\n`);
969
-
970
- // 更新方案,保留其他欄位
971
- await subRef.update({
972
- plan: plan,
973
- updatedAt: new Date(),
974
- });
975
- console.log(`✅ user_subscriptions 已更新為: ${plan}`);
976
- } else {
977
- // 如果沒有訂閱記錄,建立 active 訂閱
978
- const now = new Date();
979
- await subRef.set({
980
- userId: user.uid,
981
- plan: plan,
982
- status: 'active',
983
- subscriptionStartDate: now,
984
- createdAt: now,
985
- updatedAt: now,
986
- });
987
- console.log(`✅ 已建立新的 active 訂閱,方案: ${plan}`);
988
- }
989
-
990
- // 2. 更新 users/{userId} 的 plan 欄位(如果存在)
991
- const userRef = db.collection('users').doc(user.uid);
992
- const userDoc = await userRef.get();
993
-
994
- if (userDoc.exists) {
995
- await userRef.update({
996
- plan: plan,
997
- });
998
- console.log(`✅ users collection 的 plan 欄位已更新為: ${plan}\n`);
999
- } else {
1000
- console.log(`⚠️ users/{userId} 文件不存在,跳過更新\n`);
1001
- }
1002
-
1003
- console.log('🎉 方案設定完成!\n');
1004
- console.log('📌 注意事項:');
1005
- console.log(' - 新的 Rate Limit 將在下次 API 請求時生效');
1006
- console.log(' - 若要查看方案限制,請參考 Rate Limit Plans:');
1007
- console.log(' * Lite: RPM=6, TPM=200K, RPD=32');
1008
- console.log(' * Max-1: RPM=6, TPM=600K, RPD=111');
1009
- console.log(' * Max-2: RPM=6, TPM=600K, RPD=450\n');
1010
-
1011
- } catch (error: any) {
1012
- console.error('❌ 執行失敗:', error.message);
1013
- process.exit(1);
1014
- }
1015
- });
1016
-
1017
- planCommand
1018
- .command('get')
1019
- .description('查詢特定使用者的方案')
1020
- .argument('<email-or-uid>', '使用者 email 或 UID')
1021
- .action(async (emailOrUid) => {
1022
- try {
1023
- console.log('🔍 查詢使用者方案...\n');
1024
-
1025
- const user = await resolveUser(emailOrUid);
1026
- const db = getFirestore();
1027
-
1028
- console.log(`✅ 使用者: ${user.email || user.uid}`);
1029
- console.log(`👤 UID: ${user.uid}\n`);
1030
-
1031
- // 查詢 user_subscriptions
1032
- const subDoc = await db.collection('user_subscriptions').doc(user.uid).get();
1033
-
1034
- if (subDoc.exists) {
1035
- const data = subDoc.data();
1036
- console.log('📋 訂閱資訊 (user_subscriptions):');
1037
- console.log(` 方案: ${data?.plan}`);
1038
- console.log(` 狀態: ${data?.status}`);
1039
- if (data?.trialStartDate) {
1040
- console.log(` 試用開始: ${data.trialStartDate.toDate?.()}`);
1041
- }
1042
- if (data?.trialEndDate) {
1043
- console.log(` 試用結束: ${data.trialEndDate.toDate?.()}`);
1044
- }
1045
- if (data?.subscriptionStartDate) {
1046
- console.log(` 訂閱開始: ${data.subscriptionStartDate.toDate?.()}`);
1047
- }
1048
- console.log('');
1049
- } else {
1050
- console.log('❌ 沒有訂閱記錄\n');
1051
- }
1052
-
1053
- // 查詢 users collection
1054
- const userDoc = await db.collection('users').doc(user.uid).get();
1055
- if (userDoc.exists) {
1056
- const userData = userDoc.data();
1057
- console.log('👤 使用者資訊 (users):');
1058
- console.log(` Email: ${userData?.email || 'N/A'}`);
1059
- console.log(` Display Name: ${userData?.displayName || 'N/A'}`);
1060
- console.log(` Plan: ${userData?.plan || 'Lite (預設)'}\n`);
1061
- } else {
1062
- console.log('⚠️ users/{userId} 文件不存在\n');
1063
- }
1064
-
1065
- } catch (error: any) {
1066
- console.error('❌ 執行失敗:', error.message);
1067
- process.exit(1);
1068
- }
1069
- });
1070
-
1071
- // ============================================================================
1072
- // batch 命令 - 批次建立使用者
1073
- // ============================================================================
1074
-
1075
- const batchCommand = program
1076
- .command('batch')
1077
- .description('批次使用者管理(適用於機關組織大量新增)');
1078
-
1079
- batchCommand
1080
- .command('provision')
1081
- .description('批次建立或更新使用者(自動建立不存在的使用者)')
1082
- .argument('<emails...>', 'Email 清單(空格分隔)或使用 --file 指定檔案')
1083
- .option('-p, --plan <plan>', '方案類型 (Lite | Max-1 | Max-2)', 'Lite')
1084
- .option('-e, --expiry <date>', '過期日期 (YYYY-MM-DD)', '2030-01-01')
1085
- .option('-f, --file <path>', '從檔案讀取 Email 清單(每行一個 Email)')
1086
- .action(async (emailArgs: string[], options) => {
1087
- try {
1088
- console.log('🚀 批次建立/更新使用者...\n');
1089
-
1090
- // 驗證方案類型
1091
- const validPlans = ['Lite', 'Max-1', 'Max-2'];
1092
- if (!validPlans.includes(options.plan)) {
1093
- console.error(`❌ 無效的方案類型: ${options.plan}`);
1094
- console.error(` 有效方案: ${validPlans.join(', ')}`);
1095
- process.exit(1);
1096
- }
1097
-
1098
- // 解析過期日期
1099
- const expiryDate = new Date(options.expiry);
1100
- if (isNaN(expiryDate.getTime())) {
1101
- console.error(`❌ 無效的日期格式: ${options.expiry}`);
1102
- console.error(' 支援格式: YYYY-MM-DD');
1103
- process.exit(1);
1104
- }
1105
- expiryDate.setHours(23, 59, 59, 999);
1106
-
1107
- // 收集 Email 清單
1108
- let emails: string[] = [];
1109
-
1110
- // 從檔案讀取
1111
- if (options.file) {
1112
- const { readFileSync } = await import('fs');
1113
- const content = readFileSync(options.file, 'utf-8');
1114
- const fileEmails = content
1115
- .split('\n')
1116
- .map(line => line.trim())
1117
- .filter(line => line && line.includes('@'));
1118
- emails.push(...fileEmails);
1119
- console.log(`📂 從檔案讀取 ${fileEmails.length} 個 Email\n`);
1120
- }
1121
-
1122
- // 從命令列參數讀取
1123
- if (emailArgs.length > 0) {
1124
- // 支援逗號分隔的格式
1125
- for (const arg of emailArgs) {
1126
- const argEmails = arg.split(',').map(e => e.trim()).filter(e => e);
1127
- emails.push(...argEmails);
1128
- }
1129
- }
1130
-
1131
- // 去除重複
1132
- emails = [...new Set(emails)];
1133
-
1134
- if (emails.length === 0) {
1135
- console.error('❌ 沒有提供任何 Email');
1136
- console.error(' 用法: batch provision email1@example.com email2@example.com');
1137
- console.error(' 或: batch provision --file emails.txt');
1138
- process.exit(1);
1139
- }
1140
-
1141
- console.log(`📋 準備處理 ${emails.length} 個使用者`);
1142
- console.log(`📦 方案: ${options.plan}`);
1143
- console.log(`📅 過期日期: ${expiryDate.toLocaleDateString('zh-TW')}\n`);
1144
- console.log('─'.repeat(60) + '\n');
1145
-
1146
- // 執行批次建立
1147
- const { batchProvisionUsers } = await import('./lib/user-resolver.js');
1148
- const results = await batchProvisionUsers(emails, options.plan, expiryDate);
1149
-
1150
- // 統計結果
1151
- const succeeded = results.filter(r => r.success);
1152
- const failed = results.filter(r => !r.success);
1153
- const created = results.filter(r => r.created);
1154
- const updated = succeeded.filter(r => !r.created);
1155
-
1156
- console.log('\n' + '─'.repeat(60));
1157
- console.log('\n📊 執行結果:\n');
1158
-
1159
- if (created.length > 0) {
1160
- console.log(`✨ 新建立 ${created.length} 位使用者:`);
1161
- created.forEach(r => console.log(` + ${r.email}`));
1162
- console.log('');
1163
- }
1164
-
1165
- if (updated.length > 0) {
1166
- console.log(`🔄 更新 ${updated.length} 位既有使用者:`);
1167
- updated.forEach(r => console.log(` ✓ ${r.email}`));
1168
- console.log('');
1169
- }
1170
-
1171
- if (failed.length > 0) {
1172
- console.log(`❌ 失敗 ${failed.length} 個:`);
1173
- failed.forEach(r => console.log(` ✗ ${r.email}: ${r.error}`));
1174
- console.log('');
1175
- }
1176
-
1177
- console.log('─'.repeat(60));
1178
- console.log(`\n🎉 完成!成功: ${succeeded.length}, 失敗: ${failed.length}\n`);
1179
-
1180
- if (created.length > 0) {
1181
- console.log('📌 注意事項:');
1182
- console.log(' - 新建立的使用者需透過「Google 登入」或「重設密碼」來啟用帳號');
1183
- console.log(' - 建議通知使用者使用 Google 帳號登入波特人\n');
1184
- }
1185
-
1186
- } catch (error: any) {
1187
- console.error('❌ 執行失敗:', error.message);
1188
- process.exit(1);
1189
- }
1190
- });
1191
-
1192
- batchCommand
1193
- .command('list-pending')
1194
- .description('列出尚未註冊的內部人員 Email(從指定清單比對)')
1195
- .argument('<emails...>', 'Email 清單')
1196
- .action(async (emailArgs: string[]) => {
1197
- try {
1198
- console.log('🔍 檢查使用者註冊狀態...\n');
1199
-
1200
- const { resolveUser } = await import('./lib/user-resolver.js');
1201
-
1202
- let emails: string[] = [];
1203
- for (const arg of emailArgs) {
1204
- const argEmails = arg.split(',').map(e => e.trim()).filter(e => e && e.includes('@'));
1205
- emails.push(...argEmails);
1206
- }
1207
- emails = [...new Set(emails)];
1208
-
1209
- const registered: string[] = [];
1210
- const notRegistered: string[] = [];
1211
-
1212
- for (const email of emails) {
1213
- try {
1214
- await resolveUser(email);
1215
- registered.push(email);
1216
- } catch {
1217
- notRegistered.push(email);
1218
- }
1219
- }
1220
-
1221
- console.log(`✅ 已註冊 (${registered.length}):`);
1222
- registered.forEach(e => console.log(` ${e}`));
1223
-
1224
- console.log(`\n❌ 尚未註冊 (${notRegistered.length}):`);
1225
- notRegistered.forEach(e => console.log(` ${e}`));
1226
-
1227
- console.log('\n💡 提示: 使用 batch provision 可自動建立尚未註冊的使用者\n');
1228
-
1229
- } catch (error: any) {
1230
- console.error('❌ 執行失敗:', error.message);
1231
- process.exit(1);
1232
- }
1233
- });
1234
-
1235
- // ============================================================================
1236
- // analytics 命令 - 生成使用者分析報告
1237
- // ============================================================================
1238
-
1239
- const analyticsCommand = program
1240
- .command('analytics')
1241
- .description('生成使用者分析報告(成本、使用量、時間序列分析)');
1242
-
1243
- analyticsCommand
1244
- .option('--days <number>', '分析天數(7/30/90)', '7')
1245
- .option('--format <format>', '輸出格式(csv/html/both)', 'both')
1246
- .option('--output <path>', '輸出目錄', process.cwd())
1247
- .action(async (options) => {
1248
- try {
1249
- const { AnalyticsCommand } = await import('./lib/commands/AnalyticsCommand.js');
1250
- const analyticsCmd = new AnalyticsCommand();
1251
- await analyticsCmd.execute(options);
1252
- } catch (error: any) {
1253
- console.error('❌ 執行失敗:', error.message);
1254
- process.exit(1);
1255
- }
1256
- });
1257
-
1258
- // ============================================================================
1259
- // spike 命令 - Token 爆量分析
1260
- // ============================================================================
1261
-
1262
- const spikeCommand = program
1263
- .command('spike')
1264
- .description('分析特定日期的 Token 爆量情況(UTC+8)');
1265
-
1266
- spikeCommand
1267
- .option('--date <date>', '分析日期(格式:YYYY-MM-DD)')
1268
- .option('--format <format>', '輸出格式(text/json/both)', 'text')
1269
- .option('--output <path>', '輸出目錄', process.cwd())
1270
- .action(async (options) => {
1271
- try {
1272
- const { SpikeCommand } = await import('./lib/commands/SpikeCommand.js');
1273
- const spikeCmd = new SpikeCommand();
1274
- await spikeCmd.execute(options);
1275
- } catch (error: any) {
1276
- console.error('❌ 執行失敗:', error.message);
1277
- process.exit(1);
1278
- }
1279
- });
1280
-
1281
- // ============================================================================
1282
- // seed 命令
1283
- // ============================================================================
1284
-
1285
- const seedCommand = program
1286
- .command('seed')
1287
- .description('建立測試資料(開發用)');
1288
-
1289
- seedCommand
1290
- .option('--rate-limit', '建立 rate limit 測試資料')
1291
- .option('--subscription', '建立訂閱測試資料')
1292
- .action(async (options) => {
1293
- const { execSync } = await import('child_process');
1294
-
1295
- if (options.rateLimit) {
1296
- console.log('🌱 建立 Rate Limit 測試資料...\n');
1297
- execSync('tsx ../api/scripts/seed-rate-limit-test-data.ts', {
1298
- stdio: 'inherit',
1299
- cwd: __dirname
1300
- });
1301
- }
1302
-
1303
- if (options.subscription) {
1304
- console.log('🌱 建立訂閱測試資料...\n');
1305
- execSync('tsx ../api/scripts/seed-subscription-test-data.ts', {
1306
- stdio: 'inherit',
1307
- cwd: __dirname
1308
- });
1309
- }
1310
-
1311
- if (!options.rateLimit && !options.subscription) {
1312
- console.log('請指定選項: --rate-limit 或 --subscription');
1313
- console.log('使用 --help 查看詳細說明');
1314
- }
1315
- });
1316
-
1317
- // ============================================================================
1318
- // 執行
1319
- // ============================================================================
1320
-
1321
- program.parse(process.argv);