botrun-horse 2.30.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} +46 -9
  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 +28 -11
  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/gemini-search-cli.md +10 -0
  45. package/modules/skill/prompts/zero-framework/html-report.md +15 -0
  46. package/modules/skill/prompts/zero-framework/smart-cache.md +10 -0
  47. package/modules/skill/prompts/zero-framework/trigram-search.md +12 -0
  48. package/modules/skill/prompts/zero-framework/tts-format.md +6 -0
  49. package/modules/skill/prompts/zero-framework/watermelon-sqlite.md +8 -0
  50. package/{bin/commands/writing.mjs → modules/writing/command.mjs} +3 -3
  51. package/{lib → modules}/writing/generate.mjs +2 -2
  52. package/modules/writing/index.mjs +38 -0
  53. package/package.json +3 -1
  54. package/parallel-dag-todo-list/imagen-module.md +51 -0
  55. package/bin/commands/schema.mjs +0 -254
  56. package/botrun-c/.claude/skills/DOCX/351/226/261/350/256/200/346/212/200/350/203/275/SKILL.md +0 -103
  57. 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
  58. package/botrun-c/.claude/skills/GitHub/346/212/200/350/203/275/SKILL.md +0 -1093
  59. package/botrun-c/.claude/skills/GitHub/346/212/200/350/203/275/scripts/github-branch.mjs +0 -73
  60. package/botrun-c/.claude/skills/GitHub/346/212/200/350/203/275/scripts/github-branches.mjs +0 -77
  61. package/botrun-c/.claude/skills/GitHub/346/212/200/350/203/275/scripts/github-checkout.mjs +0 -72
  62. package/botrun-c/.claude/skills/GitHub/346/212/200/350/203/275/scripts/github-clone.mjs +0 -72
  63. package/botrun-c/.claude/skills/GitHub/346/212/200/350/203/275/scripts/github-commit.mjs +0 -75
  64. package/botrun-c/.claude/skills/GitHub/346/212/200/350/203/275/scripts/github-delete-branch.mjs +0 -75
  65. package/botrun-c/.claude/skills/GitHub/346/212/200/350/203/275/scripts/github-delete-file.mjs +0 -72
  66. package/botrun-c/.claude/skills/GitHub/346/212/200/350/203/275/scripts/github-diff.mjs +0 -80
  67. package/botrun-c/.claude/skills/GitHub/346/212/200/350/203/275/scripts/github-list-tree.mjs +0 -336
  68. package/botrun-c/.claude/skills/GitHub/346/212/200/350/203/275/scripts/github-list.mjs +0 -199
  69. package/botrun-c/.claude/skills/GitHub/346/212/200/350/203/275/scripts/github-merge.mjs +0 -86
  70. package/botrun-c/.claude/skills/GitHub/346/212/200/350/203/275/scripts/github-move.mjs +0 -75
  71. package/botrun-c/.claude/skills/GitHub/346/212/200/350/203/275/scripts/github-pr-create.mjs +0 -81
  72. package/botrun-c/.claude/skills/GitHub/346/212/200/350/203/275/scripts/github-pr-list.mjs +0 -74
  73. package/botrun-c/.claude/skills/GitHub/346/212/200/350/203/275/scripts/github-pr-merge.mjs +0 -83
  74. package/botrun-c/.claude/skills/GitHub/346/212/200/350/203/275/scripts/github-pr-view.mjs +0 -71
  75. package/botrun-c/.claude/skills/GitHub/346/212/200/350/203/275/scripts/github-push.mjs +0 -71
  76. package/botrun-c/.claude/skills/GitHub/346/212/200/350/203/275/scripts/github-read.mjs +0 -277
  77. package/botrun-c/.claude/skills/GitHub/346/212/200/350/203/275/scripts/github-search.mjs +0 -370
  78. package/botrun-c/.claude/skills/GitHub/346/212/200/350/203/275/scripts/github-stash.mjs +0 -116
  79. package/botrun-c/.claude/skills/GitHub/346/212/200/350/203/275/scripts/github-sync.mjs +0 -71
  80. package/botrun-c/.claude/skills/GitHub/346/212/200/350/203/275/scripts/github-write.mjs +0 -74
  81. package/botrun-c/.claude/skills/GitHub/346/212/200/350/203/275/scripts/lib/path-validator.mjs +0 -167
  82. package/botrun-c/.claude/skills/GoogleDrive/346/212/200/350/203/275/SKILL.md +0 -605
  83. package/botrun-c/.claude/skills/GoogleDrive/346/212/200/350/203/275/scripts/gdrive-create.mjs +0 -127
  84. package/botrun-c/.claude/skills/GoogleDrive/346/212/200/350/203/275/scripts/gdrive-delete.mjs +0 -77
  85. package/botrun-c/.claude/skills/GoogleDrive/346/212/200/350/203/275/scripts/gdrive-diff.mjs +0 -87
  86. package/botrun-c/.claude/skills/GoogleDrive/346/212/200/350/203/275/scripts/gdrive-history.mjs +0 -99
  87. package/botrun-c/.claude/skills/GoogleDrive/346/212/200/350/203/275/scripts/gdrive-list.mjs +0 -174
  88. package/botrun-c/.claude/skills/GoogleDrive/346/212/200/350/203/275/scripts/gdrive-read.mjs +0 -214
  89. package/botrun-c/.claude/skills/GoogleDrive/346/212/200/350/203/275/scripts/gdrive-restore.mjs +0 -75
  90. package/botrun-c/.claude/skills/GoogleDrive/346/212/200/350/203/275/scripts/gdrive-search.mjs +0 -270
  91. package/botrun-c/.claude/skills/GoogleDrive/346/212/200/350/203/275/scripts/gdrive-sync-back.mjs +0 -155
  92. package/botrun-c/.claude/skills/GoogleDrive/346/212/200/350/203/275/scripts/gdrive-update.mjs +0 -100
  93. package/botrun-c/.claude/skills/HTML/347/224/237/346/210/220/346/212/200/350/203/275/SKILL.md +0 -414
  94. package/botrun-c/.claude/skills/HTML/347/224/237/346/210/220/346/212/200/350/203/275/scripts/create-project.mjs +0 -91
  95. package/botrun-c/.claude/skills/HTML/347/224/237/346/210/220/346/212/200/350/203/275/scripts/finalize-project.mjs +0 -162
  96. package/botrun-c/.claude/skills/PDF/346/212/200/350/203/275/SKILL.md +0 -206
  97. package/botrun-c/.claude/skills/PDF/346/212/200/350/203/275/scripts/package.json +0 -19
  98. package/botrun-c/.claude/skills/PDF/346/212/200/350/203/275/scripts/pdf-analyze.mjs +0 -309
  99. package/botrun-c/.claude/skills/PDF/346/212/200/350/203/275/scripts/pdf-compress.mjs +0 -315
  100. package/botrun-c/.claude/skills/PDF/346/212/200/350/203/275/scripts/pdf-split.mjs +0 -275
  101. package/botrun-c/.claude/skills/PDF/346/212/200/350/203/275/scripts/pdf-to-text.mjs +0 -336
  102. package/botrun-c/.claude/skills/PDF/346/212/200/350/203/275/scripts/test-pdf-scripts.mjs +0 -491
  103. package/botrun-c/.claude/skills/docx-to-markdown/SKILL.md +0 -76
  104. package/botrun-c/.claude/skills/docx-to-markdown/scripts/convert_docx.py +0 -183
  105. package/botrun-c/.claude/skills/gcp-coord-ml-ocr/SKILL.md +0 -133
  106. package/botrun-c/.claude/skills/gcp-coord-ml-ocr/scripts/ocr_processor.py +0 -381
  107. package/botrun-c/.claude/skills/gemini-transcribe/SKILL.md +0 -115
  108. package/botrun-c/.claude/skills/gemini-transcribe/scripts/transcribe.py +0 -499
  109. package/botrun-c/.claude/skills/nchc-transcribe/SKILL.md +0 -131
  110. package/botrun-c/.claude/skills/nchc-transcribe/scripts/transcribe.py +0 -522
  111. package/botrun-c/.claude/skills/p320-moj-review/SKILL.md +0 -200
  112. package/botrun-c/.claude/skills/p320-moj-review/references/guideline.md +0 -118
  113. package/botrun-c/.claude/skills/pdf-multimodal-processor/SKILL.md +0 -186
  114. package/botrun-c/.claude/skills/pdf-multimodal-processor/scripts/process_pdf.py +0 -515
  115. package/botrun-c/.claude/skills/ripgrep/346/220/234/345/260/213/346/212/200/350/203/275/SKILL.md +0 -81
  116. package/botrun-c/.claude/skills/ripgrep/346/220/234/345/260/213/346/212/200/350/203/275/scripts/package.json +0 -13
  117. package/botrun-c/.claude/skills/ripgrep/346/220/234/345/260/213/346/212/200/350/203/275/scripts/secure-search.mjs +0 -232
  118. 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
  119. package/botrun-c/.claude/skills//345/216/273/350/255/230/345/210/245/346/212/200/350/203/275/SKILL.md +0 -125
  120. package/botrun-c/.claude/skills//345/233/236/346/206/266/346/212/200/350/203/275/SKILL.md +0 -123
  121. package/botrun-c/.claude/skills//345/233/236/346/206/266/346/212/200/350/203/275/scripts/recall.mjs +0 -339
  122. 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
  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/__tests__/utils.test.mjs +0 -139
  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/constants.mjs +0 -40
  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/gcs-uploader.mjs +0 -195
  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/gemini-image-client.mjs +0 -307
  127. 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
  128. 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
  129. 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
  130. 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
  131. 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
  132. 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
  133. 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
  134. 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
  135. package/botrun-c/.claude/skills//345/255/265/345/214/226/346/212/200/350/203/275/SKILL.md +0 -131
  136. package/botrun-c/.claude/skills//345/255/265/345/214/226/346/212/200/350/203/275/scripts/skill-manager.mjs +0 -542
  137. 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
  138. 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
  139. 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
  140. 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
  141. 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
  142. 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
  143. 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
  144. 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
  145. 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
  146. 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
  147. 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
  148. 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
  149. package/botrun-c/.claude/skills//350/250/230/346/206/266/346/212/200/350/203/275/SKILL.md +0 -114
  150. package/botrun-c/.claude/skills//350/250/230/346/206/266/346/212/200/350/203/275/scripts/remember.mjs +0 -159
  151. package/botrun-c/.claude/skills//350/250/230/346/206/266/346/212/200/350/203/275/scripts/test-advanced.mjs +0 -342
  152. package/botrun-c/.claude/skills//350/250/230/346/206/266/346/212/200/350/203/275/scripts/test.mjs +0 -430
  153. 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
  154. 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
  155. 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
  156. 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
  157. package/botrun-c/.dockerignore +0 -131
  158. package/botrun-c/.dockeroptimize +0 -13
  159. package/botrun-c/.firebase/hosting.b3V0.cache +0 -30
  160. package/botrun-c/.firebaserc +0 -5
  161. package/botrun-c/.gcloudignore +0 -56
  162. package/botrun-c/.ruby-version +0 -1
  163. package/botrun-c/CHANGELOG.md +0 -224
  164. package/botrun-c/Dockerfile.gcp +0 -365
  165. package/botrun-c/Dockerfile.slim +0 -195
  166. package/botrun-c/Gemfile +0 -8
  167. package/botrun-c/Gemfile.lock +0 -233
  168. package/botrun-c/LOCAL-DEVELOPMENT-GUIDE.md +0 -393
  169. package/botrun-c/PLAN.md +0 -131
  170. package/botrun-c/README.md +0 -129
  171. package/botrun-c/TODO-CAPACITOR-INTEGRATION.md +0 -482
  172. package/botrun-c/VERIFICATION.md +0 -121
  173. package/botrun-c/admin/RATE_LIMIT_MANAGEMENT.md +0 -312
  174. package/botrun-c/admin/README.md +0 -338
  175. package/botrun-c/admin/botrun-billing-report-1765235244038.csv +0 -22
  176. package/botrun-c/admin/botrun-billing-report-1765235323089.csv +0 -22
  177. package/botrun-c/admin/botrun-dashboard-1765235244039.html +0 -278
  178. package/botrun-c/admin/botrun-dashboard-1765235323089.html +0 -278
  179. package/botrun-c/admin/botrun-timeseries-074xGzIKWyfKTBt1NMIj9lxi5mO2-1765235244039.html +0 -161
  180. package/botrun-c/admin/botrun-timeseries-074xGzIKWyfKTBt1NMIj9lxi5mO2-1765235323090.html +0 -161
  181. package/botrun-c/admin/check-billing.ts +0 -48
  182. package/botrun-c/admin/count-all-users.ts +0 -65
  183. package/botrun-c/admin/generate-analytics-report.ts +0 -188
  184. package/botrun-c/admin/jest.config.ts +0 -43
  185. package/botrun-c/admin/lib/__tests__/formatters.test.ts +0 -264
  186. package/botrun-c/admin/lib/__tests__/mocks/firebase.mock.ts +0 -112
  187. package/botrun-c/admin/lib/__tests__/services/UserService.test.ts +0 -83
  188. package/botrun-c/admin/lib/__tests__/user-resolver.test.ts +0 -439
  189. package/botrun-c/admin/lib/analyzers/BillingAnalyticsService.ts +0 -242
  190. package/botrun-c/admin/lib/analyzers/CsvExporter.ts +0 -263
  191. package/botrun-c/admin/lib/analyzers/HtmlChartGenerator.ts +0 -530
  192. package/botrun-c/admin/lib/analyzers/SpikeAnalyzer.ts +0 -608
  193. package/botrun-c/admin/lib/analyzers/TimeSeriesAnalyzer.ts +0 -344
  194. package/botrun-c/admin/lib/cli/CLIBootstrapper.ts +0 -40
  195. package/botrun-c/admin/lib/commands/AbstractCommand.ts +0 -69
  196. package/botrun-c/admin/lib/commands/AnalyticsCommand.ts +0 -215
  197. package/botrun-c/admin/lib/commands/ListCommand.ts +0 -85
  198. package/botrun-c/admin/lib/commands/QueryCommand.ts +0 -81
  199. package/botrun-c/admin/lib/commands/SpikeCommand.ts +0 -83
  200. package/botrun-c/admin/lib/domain/User.ts +0 -38
  201. package/botrun-c/admin/lib/firebase.ts +0 -92
  202. package/botrun-c/admin/lib/firestore-safe.ts +0 -105
  203. package/botrun-c/admin/lib/formatters.ts +0 -154
  204. package/botrun-c/admin/lib/rate-limit-detailed.ts +0 -355
  205. package/botrun-c/admin/lib/rate-limit.ts +0 -286
  206. package/botrun-c/admin/lib/repositories/UserRepository.ts +0 -104
  207. package/botrun-c/admin/lib/services/UserService.ts +0 -108
  208. package/botrun-c/admin/lib/types.ts +0 -56
  209. package/botrun-c/admin/lib/user-resolver.ts +0 -275
  210. package/botrun-c/admin/manage-auth-domains.js +0 -178
  211. package/botrun-c/admin/migrate-plan-free.sh +0 -64
  212. package/botrun-c/admin/package-lock.json +0 -5656
  213. package/botrun-c/admin/package.json +0 -28
  214. package/botrun-c/admin/rate-limit.sh +0 -55
  215. package/botrun-c/admin/remove-custom-limits.ts +0 -75
  216. package/botrun-c/admin/reset-rate.sh +0 -70
  217. package/botrun-c/admin/reset-trial.sh +0 -68
  218. package/botrun-c/admin/seed-trial-data.sh +0 -38
  219. package/botrun-c/admin/trial.sh +0 -55
  220. package/botrun-c/admin/tsconfig.json +0 -20
  221. package/botrun-c/admin/users-cli.py +0 -298
  222. package/botrun-c/admin/users.sh +0 -12
  223. package/botrun-c/admin/users.ts +0 -1321
  224. package/botrun-c/api/admin-tools/check-whitelist.mjs.migration-bak +0 -74
  225. package/botrun-c/api/admin-tools/create-user.mjs +0 -92
  226. package/botrun-c/api/admin-tools/create-user.mjs.migration-bak +0 -92
  227. package/botrun-c/api/admin-tools/firebase-auth-domains-v2.py +0 -287
  228. package/botrun-c/api/admin-tools/firebase-auth-domains-v2.py.migration-bak +0 -287
  229. package/botrun-c/api/admin-tools/init-firestore.mjs +0 -75
  230. package/botrun-c/api/admin-tools/init-firestore.mjs.migration-bak +0 -101
  231. package/botrun-c/api/admin-tools/list-users.mjs +0 -43
  232. package/botrun-c/api/admin-tools/list-users.mjs.migration-bak +0 -43
  233. package/botrun-c/api/admin-tools/manage-authorized-domains.ts +0 -255
  234. package/botrun-c/api/admin-tools/manage-authorized-domains.ts.migration-bak +0 -255
  235. package/botrun-c/api/admin-tools/setup-custom-claims.ts.migration-bak +0 -155
  236. package/botrun-c/api/admin-tools/test-claims.mjs +0 -69
  237. package/botrun-c/api/admin-tools/test-claims.mjs.migration-bak +0 -69
  238. package/botrun-c/api/admin-tools/update-service-urls-gcloud.mjs +0 -72
  239. package/botrun-c/api/admin-tools/update-service-urls-gcloud.mjs.migration-bak +0 -72
  240. package/botrun-c/api/admin-tools/update-service-urls-to-lb.mjs +0 -159
  241. package/botrun-c/api/admin-tools/update-service-urls-to-lb.mjs.migration-bak +0 -159
  242. package/botrun-c/api/admin-tools/update-service-urls.mjs +0 -82
  243. package/botrun-c/api/admin-tools/update-service-urls.mjs.migration-bak +0 -82
  244. package/botrun-c/api/package-lock.json +0 -5031
  245. package/botrun-c/api/package.json +0 -63
  246. package/botrun-c/api/pnpm-lock.yaml +0 -4157
  247. package/botrun-c/api/rate-limit-export-1763620678737.csv +0 -79
  248. package/botrun-c/api/scripts/README-migrate-plan-free.md +0 -197
  249. package/botrun-c/api/scripts/check-users.ts +0 -45
  250. package/botrun-c/api/scripts/delete-firestore-docs.js +0 -43
  251. package/botrun-c/api/scripts/dump-subscriptions.ts +0 -395
  252. package/botrun-c/api/scripts/list-all-users.ts +0 -65
  253. package/botrun-c/api/scripts/migrate-plan-free-rpd-16to32.ts +0 -262
  254. package/botrun-c/api/scripts/migrate-plan-names-to-lite-max.ts +0 -269
  255. package/botrun-c/api/scripts/query-user-info.ts +0 -304
  256. package/botrun-c/api/scripts/reset-rate-limit.ts +0 -206
  257. package/botrun-c/api/scripts/reset-trial-subscription.ts +0 -166
  258. package/botrun-c/api/scripts/rollback-plan-names-from-lite-max.ts +0 -139
  259. package/botrun-c/api/scripts/seed-rate-limit-test-data.ts +0 -114
  260. package/botrun-c/api/scripts/seed-subscription-test-data.ts +0 -173
  261. package/botrun-c/api/scripts/test-rate-limit-message.ts +0 -108
  262. package/botrun-c/api/test-billing-write.ts +0 -103
  263. package/botrun-c/api/test-billing.ts +0 -81
  264. package/botrun-c/api/test-chat-upload.sh +0 -162
  265. package/botrun-c/api/test-nchc-whisper.ts +0 -87
  266. package/botrun-c/api/test-skills-loading.js +0 -77
  267. package/botrun-c/api/test-skills-symlink.js +0 -118
  268. package/botrun-c/api/test-upload-multimodal.sh +0 -167
  269. package/botrun-c/api/tsconfig.json +0 -27
  270. package/botrun-c/api/verify-form-2-1.mjs +0 -229
  271. package/botrun-c/api/vitest.config.ts +0 -9
  272. package/botrun-c/appium-capabilities.json +0 -20
  273. package/botrun-c/cors.json +0 -26
  274. package/botrun-c/delete-old.sh +0 -44
  275. package/botrun-c/design/google-drive/01-architecture.md +0 -186
  276. package/botrun-c/design/google-drive/02-api-design.md +0 -314
  277. package/botrun-c/design/google-drive/03-frontend-design.md +0 -278
  278. package/botrun-c/design/google-drive/04-skill-design.md +0 -384
  279. package/botrun-c/design/google-drive/05-test-plan.md +0 -507
  280. package/botrun-c/design/google-drive/README.md +0 -32
  281. package/botrun-c/dev/mcp-token-calculator/README.md +0 -92
  282. package/botrun-c/dev/mcp-token-calculator/RESULTS.md +0 -188
  283. package/botrun-c/dev/mcp-token-calculator/calculate-current-tokens.ts +0 -369
  284. package/botrun-c/dev/mcp-token-calculator/calculate-mcp-tokens.ts +0 -464
  285. package/botrun-c/dev/mcp-token-calculator/optimization-proposals.ts +0 -316
  286. package/botrun-c/dev/mcp-token-calculator/package-lock.json +0 -599
  287. package/botrun-c/dev/mcp-token-calculator/package.json +0 -22
  288. package/botrun-c/dev/mcp-token-calculator/test-all-schemas.ts +0 -314
  289. package/botrun-c/dev/mcp-token-calculator/test-schema-correctness.ts +0 -221
  290. package/botrun-c/dev/mcp-token-calculator/verify-optimization.ts +0 -159
  291. package/botrun-c/fastlane/ANDROID-DEPLOYMENT-SETUP.md +0 -825
  292. package/botrun-c/fastlane/IOS-DEPLOYMENT-SETUP.md +0 -431
  293. package/botrun-c/fastlane/Pluginfile +0 -5
  294. package/botrun-c/fastlane/QUICK-START.md +0 -133
  295. package/botrun-c/fastlane/README.md +0 -424
  296. package/botrun-c/fastlane/RUBY-SETUP.md +0 -449
  297. package/botrun-c/fastlane/android/Appfile +0 -11
  298. package/botrun-c/fastlane/android/Fastfile +0 -240
  299. package/botrun-c/firebase.json +0 -46
  300. package/botrun-c/firestore-init-data.json +0 -40
  301. package/botrun-c/firestore.indexes.json +0 -55
  302. package/botrun-c/firestore.rules +0 -53
  303. package/botrun-c/fix-codex-permissions.sh +0 -56
  304. package/botrun-c/gcs-lifecycle-30day-retention.json +0 -12
  305. package/botrun-c/html-architecture/architecture/deployment.html +0 -664
  306. package/botrun-c/html-architecture/architecture/index.html +0 -309
  307. package/botrun-c/html-architecture/architecture/styles.css +0 -500
  308. package/botrun-c/html-architecture/architecture/system-components.html +0 -538
  309. package/botrun-c/html-architecture/architecture/user-flow.html +0 -370
  310. package/botrun-c/mobile-android/FIREBASE-AUTH-SETUP.md +0 -302
  311. package/botrun-c/mobile-android/WSL-ANDROID-SETUP.md +0 -252
  312. package/botrun-c/mobile-android/android/app/build.gradle +0 -75
  313. package/botrun-c/mobile-android/android/app/capacitor.build.gradle +0 -31
  314. package/botrun-c/mobile-android/android/app/proguard-rules.pro +0 -21
  315. package/botrun-c/mobile-android/android/build.gradle +0 -29
  316. package/botrun-c/mobile-android/android/capacitor.settings.gradle +0 -42
  317. package/botrun-c/mobile-android/android/gradle/wrapper/gradle-wrapper.jar +0 -0
  318. package/botrun-c/mobile-android/android/gradle/wrapper/gradle-wrapper.properties +0 -7
  319. package/botrun-c/mobile-android/android/gradle.properties +0 -22
  320. package/botrun-c/mobile-android/android/gradlew +0 -252
  321. package/botrun-c/mobile-android/android/gradlew.bat +0 -94
  322. package/botrun-c/mobile-android/android/settings.gradle +0 -5
  323. package/botrun-c/mobile-android/android/variables.gradle +0 -16
  324. package/botrun-c/mobile-android/capacitor.config.ts +0 -44
  325. package/botrun-c/mobile-android/fastlane/Appfile +0 -11
  326. package/botrun-c/mobile-android/fastlane/Fastfile +0 -202
  327. package/botrun-c/mobile-android/fastlane/README.md +0 -96
  328. package/botrun-c/mobile-android/google-services.json.template +0 -39
  329. package/botrun-c/mobile-android/package.json +0 -32
  330. package/botrun-c/mobile-android/resources/icon.png +0 -0
  331. package/botrun-c/mobile-android/tsconfig.json +0 -15
  332. package/botrun-c/mobile-ios/.ruby-version +0 -1
  333. package/botrun-c/mobile-ios/BUILD-LOG.md +0 -82
  334. package/botrun-c/mobile-ios/Gemfile +0 -4
  335. package/botrun-c/mobile-ios/Gemfile.lock +0 -299
  336. package/botrun-c/mobile-ios/GoogleService-Info.plist.template +0 -34
  337. package/botrun-c/mobile-ios/IOS-PERMISSIONS.md +0 -80
  338. package/botrun-c/mobile-ios/QUICK-START.md +0 -189
  339. package/botrun-c/mobile-ios/README.md +0 -231
  340. package/botrun-c/mobile-ios/capacitor.config.ts +0 -46
  341. package/botrun-c/mobile-ios/fastlane/Fastfile +0 -326
  342. package/botrun-c/mobile-ios/fastlane/README.md +0 -88
  343. package/botrun-c/mobile-ios/ios/App/App/App.entitlements +0 -10
  344. package/botrun-c/mobile-ios/ios/App/App/AppDelegate.swift +0 -49
  345. package/botrun-c/mobile-ios/ios/App/App/Assets.xcassets/AppIcon.appiconset/AppIcon-512@2x.png +0 -0
  346. package/botrun-c/mobile-ios/ios/App/App/Assets.xcassets/AppIcon.appiconset/Contents.json +0 -14
  347. package/botrun-c/mobile-ios/ios/App/App/Assets.xcassets/Contents.json +0 -6
  348. package/botrun-c/mobile-ios/ios/App/App/Assets.xcassets/Splash.imageset/Contents.json +0 -56
  349. package/botrun-c/mobile-ios/ios/App/App/Assets.xcassets/Splash.imageset/Default@1x~universal~anyany-dark.png +0 -0
  350. package/botrun-c/mobile-ios/ios/App/App/Assets.xcassets/Splash.imageset/Default@1x~universal~anyany.png +0 -0
  351. package/botrun-c/mobile-ios/ios/App/App/Assets.xcassets/Splash.imageset/Default@2x~universal~anyany-dark.png +0 -0
  352. package/botrun-c/mobile-ios/ios/App/App/Assets.xcassets/Splash.imageset/Default@2x~universal~anyany.png +0 -0
  353. package/botrun-c/mobile-ios/ios/App/App/Assets.xcassets/Splash.imageset/Default@3x~universal~anyany-dark.png +0 -0
  354. package/botrun-c/mobile-ios/ios/App/App/Assets.xcassets/Splash.imageset/Default@3x~universal~anyany.png +0 -0
  355. package/botrun-c/mobile-ios/ios/App/App/Assets.xcassets/Splash.imageset/splash-2732x2732-1.png +0 -0
  356. package/botrun-c/mobile-ios/ios/App/App/Assets.xcassets/Splash.imageset/splash-2732x2732-2.png +0 -0
  357. package/botrun-c/mobile-ios/ios/App/App/Assets.xcassets/Splash.imageset/splash-2732x2732.png +0 -0
  358. package/botrun-c/mobile-ios/ios/App/App/Base.lproj/LaunchScreen.storyboard +0 -32
  359. package/botrun-c/mobile-ios/ios/App/App/Base.lproj/Main.storyboard +0 -19
  360. package/botrun-c/mobile-ios/ios/App/App/Info.plist +0 -72
  361. package/botrun-c/mobile-ios/ios/App/App.xcodeproj/project.pbxproj +0 -446
  362. package/botrun-c/mobile-ios/ios/App/App.xcodeproj/xcshareddata/xcschemes/App.xcscheme +0 -78
  363. package/botrun-c/mobile-ios/ios/App/App.xcworkspace/contents.xcworkspacedata +0 -10
  364. package/botrun-c/mobile-ios/ios/App/App.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist +0 -8
  365. package/botrun-c/mobile-ios/ios/App/Podfile +0 -52
  366. package/botrun-c/mobile-ios/ios/App/Podfile.lock +0 -205
  367. package/botrun-c/mobile-ios/ios/App/add_plist.rb +0 -30
  368. package/botrun-c/mobile-ios/ios/App/fix_plist_path.rb +0 -22
  369. package/botrun-c/mobile-ios/package.json +0 -29
  370. package/botrun-c/mobile-ios/resources/icon.png +0 -0
  371. package/botrun-c/mobile-ios/run-simulator.sh +0 -34
  372. package/botrun-c/mobile-ios/screenshot-after-clean-rebuild.png +0 -0
  373. package/botrun-c/mobile-ios/screenshot-final-version.png +0 -0
  374. package/botrun-c/mobile-ios/screenshot-simulator.png +0 -0
  375. package/botrun-c/mobile-ios/screenshot-version-1009.png +0 -0
  376. package/botrun-c/mobile-ios/screenshot-with-version.png +0 -0
  377. package/botrun-c/mobile-ios/screenshot-working.png +0 -0
  378. package/botrun-c/mobile-ios/setup-ios.sh +0 -106
  379. package/botrun-c/mobile-ios/tsconfig.json +0 -16
  380. package/botrun-c/org-policy-allow-all-users.yaml +0 -3
  381. package/botrun-c/package.json +0 -68
  382. package/botrun-c/pnpm-lock.yaml +0 -10198
  383. package/botrun-c/pnpm-workspace.yaml +0 -6
  384. package/botrun-c/prompts/BOTRUN-1.md +0 -13
  385. package/botrun-c/prompts/BOTRUN-2.md +0 -70
  386. package/botrun-c/prompts/BOTRUN-3.md +0 -139
  387. package/botrun-c/prototypes/firestore-gax-debug/package-lock.json +0 -1204
  388. package/botrun-c/prototypes/firestore-gax-debug/package.json +0 -12
  389. package/botrun-c/prototypes/firestore-gax-debug/pnpm-workspace.yaml +0 -2
  390. package/botrun-c/prototypes/firestore-gax-debug/test.js +0 -98
  391. package/botrun-c/prototypes/taiwan-haiku/README.md +0 -93
  392. package/botrun-c/prototypes/taiwan-haiku/index.ts +0 -139
  393. package/botrun-c/prototypes/taiwan-haiku/package.json +0 -23
  394. package/botrun-c/prototypes/taiwan-haiku/pnpm-lock.yaml +0 -730
  395. package/botrun-c/prototypes/taiwan-haiku/test-vertex-direct.ts +0 -83
  396. package/botrun-c/prototypes/taiwan-haiku/tsconfig.json +0 -18
  397. package/botrun-c/prototypes/web-search/FINDINGS-STAGE-1.md +0 -48
  398. package/botrun-c/prototypes/web-search/README.md +0 -46
  399. package/botrun-c/prototypes/web-search/VERIFICATION-REPORT.md +0 -310
  400. package/botrun-c/prototypes/web-search/package-lock.json +0 -595
  401. package/botrun-c/prototypes/web-search/package.json +0 -18
  402. package/botrun-c/prototypes/web-search/stage-1.1-basic-connection.js +0 -123
  403. package/botrun-c/prototypes/web-search/stage-1.2-with-websearch.js +0 -154
  404. package/botrun-c/prototypes/web-search/stage-1.3-search-query.js +0 -192
  405. package/botrun-c/prototypes/web-search/stage-2-agent-sdk-websearch.js +0 -265
  406. package/botrun-c/runtime-scripts/env-detect.sh +0 -64
  407. package/botrun-c/scripts/github-collaborator-manager.sh +0 -297
  408. package/botrun-c/scripts/github-collaborator-manager.ts +0 -325
  409. package/botrun-c/scripts/manage-collaborators.sh +0 -91
  410. package/botrun-c/scripts/setup-secrets.sh +0 -202
  411. package/botrun-c/scripts/stress-test-17-users.sh +0 -113
  412. package/botrun-c/scripts/stress-test-api.sh +0 -119
  413. package/botrun-c/scripts/stress-test-full-report.sh +0 -385
  414. package/botrun-c/specs/infra-vm/design.md +0 -0
  415. package/botrun-c/specs/share-skill/design.md +0 -1146
  416. package/botrun-c/specs/share-skill/tasks.md +0 -444
  417. package/botrun-c/stress-test-results/20260121-162630/config.json +0 -7
  418. package/botrun-c/stress-test-results/20260121-162630/user-1-status.txt +0 -1
  419. package/botrun-c/stress-test-results/20260121-162630/user-1-timing.txt +0 -1
  420. package/botrun-c/stress-test-results/20260121-162630/user-1.json +0 -2
  421. package/botrun-c/stress-test-results/20260121-162646/config.json +0 -7
  422. package/botrun-c/stress-test-results/20260121-162646/user-1-status.txt +0 -1
  423. package/botrun-c/stress-test-results/20260121-162646/user-1-timing.txt +0 -1
  424. package/botrun-c/stress-test-results/20260121-162646/user-1.json +0 -2
  425. package/botrun-c/stress-test-results/20260121-162646/user-10-status.txt +0 -1
  426. package/botrun-c/stress-test-results/20260121-162646/user-10-timing.txt +0 -1
  427. package/botrun-c/stress-test-results/20260121-162646/user-10.json +0 -2
  428. package/botrun-c/stress-test-results/20260121-162646/user-11-status.txt +0 -1
  429. package/botrun-c/stress-test-results/20260121-162646/user-11-timing.txt +0 -1
  430. package/botrun-c/stress-test-results/20260121-162646/user-11.json +0 -2
  431. package/botrun-c/stress-test-results/20260121-162646/user-12-status.txt +0 -1
  432. package/botrun-c/stress-test-results/20260121-162646/user-12-timing.txt +0 -1
  433. package/botrun-c/stress-test-results/20260121-162646/user-12.json +0 -2
  434. package/botrun-c/stress-test-results/20260121-162646/user-13-status.txt +0 -1
  435. package/botrun-c/stress-test-results/20260121-162646/user-13-timing.txt +0 -1
  436. package/botrun-c/stress-test-results/20260121-162646/user-13.json +0 -2
  437. package/botrun-c/stress-test-results/20260121-162646/user-14-status.txt +0 -1
  438. package/botrun-c/stress-test-results/20260121-162646/user-14-timing.txt +0 -1
  439. package/botrun-c/stress-test-results/20260121-162646/user-14.json +0 -2
  440. package/botrun-c/stress-test-results/20260121-162646/user-15-status.txt +0 -1
  441. package/botrun-c/stress-test-results/20260121-162646/user-15-timing.txt +0 -1
  442. package/botrun-c/stress-test-results/20260121-162646/user-15.json +0 -2
  443. package/botrun-c/stress-test-results/20260121-162646/user-16-status.txt +0 -1
  444. package/botrun-c/stress-test-results/20260121-162646/user-16-timing.txt +0 -1
  445. package/botrun-c/stress-test-results/20260121-162646/user-16.json +0 -2
  446. package/botrun-c/stress-test-results/20260121-162646/user-17-status.txt +0 -1
  447. package/botrun-c/stress-test-results/20260121-162646/user-17-timing.txt +0 -1
  448. package/botrun-c/stress-test-results/20260121-162646/user-17.json +0 -2
  449. package/botrun-c/stress-test-results/20260121-162646/user-2-status.txt +0 -1
  450. package/botrun-c/stress-test-results/20260121-162646/user-2-timing.txt +0 -1
  451. package/botrun-c/stress-test-results/20260121-162646/user-2.json +0 -2
  452. package/botrun-c/stress-test-results/20260121-162646/user-3-status.txt +0 -1
  453. package/botrun-c/stress-test-results/20260121-162646/user-3-timing.txt +0 -1
  454. package/botrun-c/stress-test-results/20260121-162646/user-3.json +0 -2
  455. package/botrun-c/stress-test-results/20260121-162646/user-4-status.txt +0 -1
  456. package/botrun-c/stress-test-results/20260121-162646/user-4-timing.txt +0 -1
  457. package/botrun-c/stress-test-results/20260121-162646/user-4.json +0 -2
  458. package/botrun-c/stress-test-results/20260121-162646/user-5-status.txt +0 -1
  459. package/botrun-c/stress-test-results/20260121-162646/user-5-timing.txt +0 -1
  460. package/botrun-c/stress-test-results/20260121-162646/user-5.json +0 -2
  461. package/botrun-c/stress-test-results/20260121-162646/user-6-status.txt +0 -1
  462. package/botrun-c/stress-test-results/20260121-162646/user-6-timing.txt +0 -1
  463. package/botrun-c/stress-test-results/20260121-162646/user-6.json +0 -2
  464. package/botrun-c/stress-test-results/20260121-162646/user-7-status.txt +0 -1
  465. package/botrun-c/stress-test-results/20260121-162646/user-7-timing.txt +0 -1
  466. package/botrun-c/stress-test-results/20260121-162646/user-7.json +0 -2
  467. package/botrun-c/stress-test-results/20260121-162646/user-8-status.txt +0 -1
  468. package/botrun-c/stress-test-results/20260121-162646/user-8-timing.txt +0 -1
  469. package/botrun-c/stress-test-results/20260121-162646/user-8.json +0 -2
  470. package/botrun-c/stress-test-results/20260121-162646/user-9-status.txt +0 -1
  471. package/botrun-c/stress-test-results/20260121-162646/user-9-timing.txt +0 -1
  472. package/botrun-c/stress-test-results/20260121-162646/user-9.json +0 -2
  473. package/botrun-c/stress-test-results/20260121-163148/REPORT.html +0 -344
  474. package/botrun-c/stress-test-results/20260121-163148/REPORT.md +0 -93
  475. package/botrun-c/stress-test-results/20260121-163148/REPORT.pdf +0 -0
  476. package/botrun-c/stress-test-results/20260121-163148/config.json +0 -7
  477. package/botrun-c/stress-test-results/20260121-163148/summary.json +0 -26
  478. package/botrun-c/stress-test-results/20260121-163148/user-1-status.txt +0 -1
  479. package/botrun-c/stress-test-results/20260121-163148/user-1-timing.txt +0 -1
  480. package/botrun-c/stress-test-results/20260121-163148/user-1.json +0 -206
  481. package/botrun-c/stress-test-results/20260121-163148/user-10-status.txt +0 -1
  482. package/botrun-c/stress-test-results/20260121-163148/user-10-timing.txt +0 -1
  483. package/botrun-c/stress-test-results/20260121-163148/user-10.json +0 -110
  484. package/botrun-c/stress-test-results/20260121-163148/user-11-status.txt +0 -1
  485. package/botrun-c/stress-test-results/20260121-163148/user-11-timing.txt +0 -1
  486. package/botrun-c/stress-test-results/20260121-163148/user-11.json +0 -104
  487. package/botrun-c/stress-test-results/20260121-163148/user-12-status.txt +0 -1
  488. package/botrun-c/stress-test-results/20260121-163148/user-12-timing.txt +0 -1
  489. package/botrun-c/stress-test-results/20260121-163148/user-12.json +0 -98
  490. package/botrun-c/stress-test-results/20260121-163148/user-13-status.txt +0 -1
  491. package/botrun-c/stress-test-results/20260121-163148/user-13-timing.txt +0 -1
  492. package/botrun-c/stress-test-results/20260121-163148/user-13.json +0 -68
  493. package/botrun-c/stress-test-results/20260121-163148/user-14-status.txt +0 -1
  494. package/botrun-c/stress-test-results/20260121-163148/user-14-timing.txt +0 -1
  495. package/botrun-c/stress-test-results/20260121-163148/user-14.json +0 -116
  496. package/botrun-c/stress-test-results/20260121-163148/user-15-status.txt +0 -1
  497. package/botrun-c/stress-test-results/20260121-163148/user-15-timing.txt +0 -1
  498. package/botrun-c/stress-test-results/20260121-163148/user-15.json +0 -131
  499. package/botrun-c/stress-test-results/20260121-163148/user-16-status.txt +0 -1
  500. package/botrun-c/stress-test-results/20260121-163148/user-16-timing.txt +0 -1
  501. package/botrun-c/stress-test-results/20260121-163148/user-16.json +0 -110
  502. package/botrun-c/stress-test-results/20260121-163148/user-17-status.txt +0 -1
  503. package/botrun-c/stress-test-results/20260121-163148/user-17-timing.txt +0 -1
  504. package/botrun-c/stress-test-results/20260121-163148/user-17.json +0 -116
  505. package/botrun-c/stress-test-results/20260121-163148/user-2-status.txt +0 -1
  506. package/botrun-c/stress-test-results/20260121-163148/user-2-timing.txt +0 -1
  507. package/botrun-c/stress-test-results/20260121-163148/user-2.json +0 -98
  508. package/botrun-c/stress-test-results/20260121-163148/user-3-status.txt +0 -1
  509. package/botrun-c/stress-test-results/20260121-163148/user-3-timing.txt +0 -1
  510. package/botrun-c/stress-test-results/20260121-163148/user-3.json +0 -62
  511. package/botrun-c/stress-test-results/20260121-163148/user-4-status.txt +0 -1
  512. package/botrun-c/stress-test-results/20260121-163148/user-4-timing.txt +0 -1
  513. package/botrun-c/stress-test-results/20260121-163148/user-4.json +0 -113
  514. package/botrun-c/stress-test-results/20260121-163148/user-5-status.txt +0 -1
  515. package/botrun-c/stress-test-results/20260121-163148/user-5-timing.txt +0 -1
  516. package/botrun-c/stress-test-results/20260121-163148/user-5.json +0 -83
  517. package/botrun-c/stress-test-results/20260121-163148/user-6-status.txt +0 -1
  518. package/botrun-c/stress-test-results/20260121-163148/user-6-timing.txt +0 -1
  519. package/botrun-c/stress-test-results/20260121-163148/user-6.json +0 -125
  520. package/botrun-c/stress-test-results/20260121-163148/user-7-status.txt +0 -1
  521. package/botrun-c/stress-test-results/20260121-163148/user-7-timing.txt +0 -1
  522. package/botrun-c/stress-test-results/20260121-163148/user-7.json +0 -62
  523. package/botrun-c/stress-test-results/20260121-163148/user-8-status.txt +0 -1
  524. package/botrun-c/stress-test-results/20260121-163148/user-8-timing.txt +0 -1
  525. package/botrun-c/stress-test-results/20260121-163148/user-8.json +0 -41
  526. package/botrun-c/stress-test-results/20260121-163148/user-9-status.txt +0 -1
  527. package/botrun-c/stress-test-results/20260121-163148/user-9-timing.txt +0 -1
  528. package/botrun-c/stress-test-results/20260121-163148/user-9.json +0 -53
  529. package/botrun-c/test-merge.md +0 -1
  530. package/botrun-c/version.txt +0 -1
  531. package/botrun-c/web/.version +0 -1
  532. package/botrun-c/web/ALLOW-PUBLIC-ACCESS.md +0 -57
  533. package/botrun-c/web/FINAL-SETUP-STEPS.md +0 -71
  534. package/botrun-c/web/FIREBASE-MANUAL-STEPS.md +0 -41
  535. package/botrun-c/web/QUICK-SETUP-HELPER.md +0 -79
  536. package/botrun-c/web/README.md +0 -162
  537. package/botrun-c/web/__tests__/image-extractor.test.ts +0 -147
  538. package/botrun-c/web/__tests__/useGitHub.test.ts +0 -245
  539. package/botrun-c/web/app/favicon.ico +0 -0
  540. package/botrun-c/web/app/globals.css +0 -215
  541. package/botrun-c/web/app/image-preview/page.tsx +0 -213
  542. package/botrun-c/web/app/layout.tsx +0 -46
  543. package/botrun-c/web/app/page.tsx +0 -45
  544. package/botrun-c/web/components/CapacitorProvider.tsx +0 -43
  545. package/botrun-c/web/components/ChatPage.tsx +0 -1736
  546. package/botrun-c/web/components/ConversationList.tsx +0 -237
  547. package/botrun-c/web/components/ConversationListItem.tsx +0 -121
  548. package/botrun-c/web/components/LoginPage.tsx +0 -212
  549. package/botrun-c/web/components/Providers.tsx +0 -12
  550. package/botrun-c/web/components/StatusBarProvider.tsx +0 -16
  551. package/botrun-c/web/components/attachment-preview.tsx +0 -193
  552. package/botrun-c/web/components/botrun-incubator/BotrunIncubator.tsx +0 -266
  553. package/botrun-c/web/components/botrun-incubator/index.ts +0 -1
  554. package/botrun-c/web/components/chat-input.tsx +0 -1251
  555. package/botrun-c/web/components/chat-message.tsx +0 -598
  556. package/botrun-c/web/components/drop-zone.tsx +0 -143
  557. package/botrun-c/web/components/gdrive/gdrive-add-dialog.tsx +0 -254
  558. package/botrun-c/web/components/gdrive/gdrive-drawer.tsx +0 -236
  559. package/botrun-c/web/components/gdrive/gdrive-selector.tsx +0 -226
  560. package/botrun-c/web/components/gdrive/index.ts +0 -7
  561. package/botrun-c/web/components/generated-image-card.tsx +0 -363
  562. package/botrun-c/web/components/github/GitHubConnect.tsx +0 -366
  563. package/botrun-c/web/components/github/index.ts +0 -2
  564. package/botrun-c/web/components/import-skill-dialog.tsx +0 -208
  565. package/botrun-c/web/components/scroll-to-bottom-button.tsx +0 -90
  566. package/botrun-c/web/components/share-skill-dialog.tsx +0 -175
  567. package/botrun-c/web/components/skills-editor.tsx +0 -443
  568. package/botrun-c/web/components/skills-manager-drawer.tsx +0 -586
  569. package/botrun-c/web/components/smart-button-group.tsx +0 -132
  570. package/botrun-c/web/config/smart-buttons.ts +0 -295
  571. package/botrun-c/web/config/welcome-messages.ts +0 -29
  572. package/botrun-c/web/contexts/AuthContext.tsx +0 -220
  573. package/botrun-c/web/hooks/use-toast.ts +0 -187
  574. package/botrun-c/web/hooks/useAppStoreUpdate.ts +0 -356
  575. package/botrun-c/web/hooks/useAppVersion.ts +0 -113
  576. package/botrun-c/web/hooks/useAttachments.ts +0 -269
  577. package/botrun-c/web/hooks/useAuthToken.ts +0 -59
  578. package/botrun-c/web/hooks/useAutoWelcome.ts +0 -89
  579. package/botrun-c/web/hooks/useCapacitorPlatform.ts +0 -113
  580. package/botrun-c/web/hooks/useCapawesomeLiveUpdate.ts +0 -149
  581. package/botrun-c/web/hooks/useClaudeModel.ts +0 -118
  582. package/botrun-c/web/hooks/useConversation.ts +0 -115
  583. package/botrun-c/web/hooks/useConversations.ts +0 -235
  584. package/botrun-c/web/hooks/useGdriveFolders.ts +0 -199
  585. package/botrun-c/web/hooks/useGdriveSync.ts +0 -107
  586. package/botrun-c/web/hooks/useGitHub.ts +0 -409
  587. package/botrun-c/web/hooks/useScrollToBottom.ts +0 -150
  588. package/botrun-c/web/hooks/useStatusBar.ts +0 -42
  589. package/botrun-c/web/hooks/useUserPlan.ts +0 -153
  590. package/botrun-c/web/lib/api-config.ts +0 -162
  591. package/botrun-c/web/lib/api-url.ts +0 -62
  592. package/botrun-c/web/lib/api.ts +0 -105
  593. package/botrun-c/web/lib/attachment-utils.ts +0 -168
  594. package/botrun-c/web/lib/build-version.ts +0 -11
  595. package/botrun-c/web/lib/clipboard-utils.ts +0 -199
  596. package/botrun-c/web/lib/constants.ts +0 -62
  597. package/botrun-c/web/lib/conversation-storage.ts +0 -324
  598. package/botrun-c/web/lib/firebase-capacitor.ts +0 -135
  599. package/botrun-c/web/lib/firebase.ts +0 -137
  600. package/botrun-c/web/lib/firestore-auth.ts +0 -61
  601. package/botrun-c/web/lib/firestore-auth.ts.migration-bak +0 -319
  602. package/botrun-c/web/lib/image-extractor.ts +0 -156
  603. package/botrun-c/web/lib/path-utils.ts +0 -48
  604. package/botrun-c/web/lib/rehype-del-to-mark.ts +0 -19
  605. package/botrun-c/web/lib/upload-service.ts +0 -326
  606. package/botrun-c/web/lib/utils.ts +0 -6
  607. package/botrun-c/web/next.config.js +0 -49
  608. package/botrun-c/web/package-lock.json +0 -6711
  609. package/botrun-c/web/package.json +0 -63
  610. package/botrun-c/web/postcss.config.js +0 -6
  611. package/botrun-c/web/public/apple_icon.png +0 -0
  612. package/botrun-c/web/public/google_icon.png +0 -0
  613. package/botrun-c/web/public/logo-48-small.png +0 -0
  614. package/botrun-c/web/public/logo-48.png +0 -0
  615. package/botrun-c/web/scripts/generate-version.js +0 -36
  616. package/botrun-c/web/scripts/update-build-version.js +0 -41
  617. package/botrun-c/web/tailwind.config.ts +0 -80
  618. package/botrun-c/web/test-welcome-message.mjs +0 -115
  619. package/botrun-c/web/tsconfig.json +0 -42
  620. package/botrun-c/web/types/agent.ts +0 -6
  621. package/botrun-c/web/types/attachment.ts +0 -39
  622. package/botrun-c/web/types/conversation.ts +0 -68
  623. package/botrun-c/web/types/flutter.d.ts +0 -6
  624. package/botrun-c/web/types/project.ts +0 -41
  625. package/botrun-c/web/types/skills.ts +0 -13
  626. 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
  627. package/lib/writing/index.mjs +0 -5
  628. /package/{lib/core → modules/_core}/adapters/base.mjs +0 -0
  629. /package/{lib/core → modules/_core}/adapters/claude.mjs +0 -0
  630. /package/{lib/core → modules/_core}/adapters/gemini-api.mjs +0 -0
  631. /package/{lib/core → modules/_core}/adapters/gemini-shared.mjs +0 -0
  632. /package/{lib/core → modules/_core}/adapters/gemini-vertex.mjs +0 -0
  633. /package/{lib/core → modules/_core}/adapters/local.mjs +0 -0
  634. /package/{lib/core → modules/_core}/adapters/nchc.mjs +0 -0
  635. /package/{lib/core → modules/_core}/adapters/openai-shared.mjs +0 -0
  636. /package/{lib/core → modules/_core}/adapters/openrouter.mjs +0 -0
  637. /package/{lib/core → modules/_core}/ai-cache.mjs +0 -0
  638. /package/{lib/core → modules/_core}/ai-router.mjs +0 -0
  639. /package/{lib/core → modules/_core}/cli-utils.mjs +0 -0
  640. /package/{lib/core → modules/_core}/dag.mjs +0 -0
  641. /package/{lib/core → modules/_core}/db.mjs +0 -0
  642. /package/{lib/core → modules/_core}/env.mjs +0 -0
  643. /package/{lib/flows → modules/_core}/hatch-portal.mjs +0 -0
  644. /package/{lib/core → modules/_core}/llm.mjs +0 -0
  645. /package/{lib/flows → modules/_core}/opencode-agent.mjs +0 -0
  646. /package/{lib/core → modules/_core}/paths.mjs +0 -0
  647. /package/{lib/core → modules/_core}/proxy.mjs +0 -0
  648. /package/{lib/flows → modules/_core}/review-doc.mjs +0 -0
  649. /package/{lib → modules/_core}/tools/fs-tools.mjs +0 -0
  650. /package/{lib → modules/_core}/tools/index.mjs +0 -0
  651. /package/{lib/core → modules/_core}/watermelon.mjs +0 -0
  652. /package/{lib/ocr/index.mjs → modules/ocr/ocr-lib.mjs} +0 -0
  653. /package/{lib → modules}/portal/hatch.mjs +0 -0
  654. /package/{lib/portal/index.mjs → modules/portal/portal-lib.mjs} +0 -0
  655. /package/{lib → modules}/search/crawler.mjs +0 -0
  656. /package/{lib/prompt → modules/skill}/prompts/zero-framework/coding.md +0 -0
  657. /package/{lib/prompt → modules/skill}/prompts/zero-framework/fullstack.md +0 -0
  658. /package/{lib/prompt → modules/skill}/prompts/zero-framework/search.md +0 -0
  659. /package/{lib/prompt → modules/skill}/prompts/zero-framework/segment.md +0 -0
  660. /package/{lib/prompt → modules/skill}/prompts/zero-framework/slice.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);