ccjk 14.2.2 → 15.0.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 (528) hide show
  1. package/LICENSE +1 -1
  2. package/README.md +58 -341
  3. package/dist/cli.js +59 -0
  4. package/dist/cli.js.map +1 -0
  5. package/dist/commands/detect.js +15 -0
  6. package/dist/commands/detect.js.map +1 -0
  7. package/dist/commands/doctor.js +68 -0
  8. package/dist/commands/doctor.js.map +1 -0
  9. package/dist/commands/git-install.js +50 -0
  10. package/dist/commands/git-install.js.map +1 -0
  11. package/dist/commands/init.js +102 -0
  12. package/dist/commands/init.js.map +1 -0
  13. package/dist/commands/mcp.js +66 -0
  14. package/dist/commands/mcp.js.map +1 -0
  15. package/dist/commands/menu.js +33 -0
  16. package/dist/commands/menu.js.map +1 -0
  17. package/dist/core/detect.js +24 -0
  18. package/dist/core/detect.js.map +1 -0
  19. package/dist/core/lint.js +49 -0
  20. package/dist/core/lint.js.map +1 -0
  21. package/dist/core/mcp.js +41 -0
  22. package/dist/core/mcp.js.map +1 -0
  23. package/dist/core/paths.js +9 -0
  24. package/dist/core/paths.js.map +1 -0
  25. package/dist/core/providers.js +53 -0
  26. package/dist/core/providers.js.map +1 -0
  27. package/dist/core/settings.js +31 -0
  28. package/dist/core/settings.js.map +1 -0
  29. package/dist/core/slash-templates.js +56 -0
  30. package/dist/core/slash-templates.js.map +1 -0
  31. package/dist/core/tools.js +27 -0
  32. package/dist/core/tools.js.map +1 -0
  33. package/package.json +43 -164
  34. package/README.HONEST.md +0 -176
  35. package/README.en.md +0 -67
  36. package/README.ja.md +0 -67
  37. package/README.ko.md +0 -67
  38. package/README.zh-CN.md +0 -86
  39. package/bin/ccjk.mjs +0 -5
  40. package/bin/ccjk.ts +0 -222
  41. package/dist/chunks/agent-teams.mjs +0 -145
  42. package/dist/chunks/agent.mjs +0 -1439
  43. package/dist/chunks/agents.mjs +0 -3783
  44. package/dist/chunks/api-cli.mjs +0 -135
  45. package/dist/chunks/api-config-selector.mjs +0 -159
  46. package/dist/chunks/api-providers.mjs +0 -144
  47. package/dist/chunks/api.mjs +0 -115
  48. package/dist/chunks/auto-bootstrap.mjs +0 -358
  49. package/dist/chunks/auto-fixer.mjs +0 -95
  50. package/dist/chunks/auto-updater.mjs +0 -507
  51. package/dist/chunks/banner.mjs +0 -173
  52. package/dist/chunks/bash.mjs +0 -187
  53. package/dist/chunks/boost.mjs +0 -474
  54. package/dist/chunks/brain-config.mjs +0 -75
  55. package/dist/chunks/brain-status.mjs +0 -89
  56. package/dist/chunks/ccjk-agents.mjs +0 -416
  57. package/dist/chunks/ccjk-all.mjs +0 -1046
  58. package/dist/chunks/ccjk-config.mjs +0 -445
  59. package/dist/chunks/ccjk-hooks.mjs +0 -1074
  60. package/dist/chunks/ccjk-mcp.mjs +0 -763
  61. package/dist/chunks/ccjk-setup.mjs +0 -765
  62. package/dist/chunks/ccjk-skills.mjs +0 -518
  63. package/dist/chunks/ccr.mjs +0 -109
  64. package/dist/chunks/ccu.mjs +0 -40
  65. package/dist/chunks/check-updates.mjs +0 -117
  66. package/dist/chunks/claude-code-incremental-manager.mjs +0 -761
  67. package/dist/chunks/claude-config.mjs +0 -606
  68. package/dist/chunks/claude-config2.mjs +0 -62
  69. package/dist/chunks/claude-wrapper.mjs +0 -85
  70. package/dist/chunks/clavue-config.mjs +0 -1454
  71. package/dist/chunks/cleanup-migration.mjs +0 -20
  72. package/dist/chunks/cli-hook.mjs +0 -4096
  73. package/dist/chunks/cloud-sync.mjs +0 -29
  74. package/dist/chunks/code-type-resolver.mjs +0 -880
  75. package/dist/chunks/codex-config-switch.mjs +0 -452
  76. package/dist/chunks/codex-provider-manager.mjs +0 -238
  77. package/dist/chunks/codex-uninstaller.mjs +0 -404
  78. package/dist/chunks/codex.mjs +0 -2141
  79. package/dist/chunks/commands.mjs +0 -108
  80. package/dist/chunks/commands2.mjs +0 -421
  81. package/dist/chunks/commit.mjs +0 -140
  82. package/dist/chunks/completion.mjs +0 -517
  83. package/dist/chunks/config-consolidator.mjs +0 -172
  84. package/dist/chunks/config-switch.mjs +0 -334
  85. package/dist/chunks/config.mjs +0 -558
  86. package/dist/chunks/config2.mjs +0 -484
  87. package/dist/chunks/config3.mjs +0 -486
  88. package/dist/chunks/constants.mjs +0 -323
  89. package/dist/chunks/context-opt.mjs +0 -444
  90. package/dist/chunks/context.mjs +0 -974
  91. package/dist/chunks/dashboard.mjs +0 -481
  92. package/dist/chunks/doctor.mjs +0 -1301
  93. package/dist/chunks/eval.mjs +0 -502
  94. package/dist/chunks/evolution.mjs +0 -322
  95. package/dist/chunks/features.mjs +0 -715
  96. package/dist/chunks/fish.mjs +0 -181
  97. package/dist/chunks/fs-operations.mjs +0 -180
  98. package/dist/chunks/health-alerts.mjs +0 -830
  99. package/dist/chunks/help.mjs +0 -341
  100. package/dist/chunks/hook-installer.mjs +0 -48
  101. package/dist/chunks/impact.mjs +0 -651
  102. package/dist/chunks/index.mjs +0 -23
  103. package/dist/chunks/index10.mjs +0 -19
  104. package/dist/chunks/index11.mjs +0 -1171
  105. package/dist/chunks/index12.mjs +0 -218
  106. package/dist/chunks/index13.mjs +0 -679
  107. package/dist/chunks/index14.mjs +0 -1009
  108. package/dist/chunks/index15.mjs +0 -194
  109. package/dist/chunks/index2.mjs +0 -7637
  110. package/dist/chunks/index3.mjs +0 -171
  111. package/dist/chunks/index4.mjs +0 -26
  112. package/dist/chunks/index5.mjs +0 -19
  113. package/dist/chunks/index6.mjs +0 -19092
  114. package/dist/chunks/index7.mjs +0 -616
  115. package/dist/chunks/index8.mjs +0 -1602
  116. package/dist/chunks/index9.mjs +0 -5384
  117. package/dist/chunks/init.mjs +0 -1911
  118. package/dist/chunks/installer.mjs +0 -757
  119. package/dist/chunks/installer2.mjs +0 -103
  120. package/dist/chunks/interview.mjs +0 -2927
  121. package/dist/chunks/json-config.mjs +0 -60
  122. package/dist/chunks/linux.mjs +0 -3863
  123. package/dist/chunks/macos.mjs +0 -69
  124. package/dist/chunks/main.mjs +0 -635
  125. package/dist/chunks/manager.mjs +0 -1048
  126. package/dist/chunks/marketplace.mjs +0 -265
  127. package/dist/chunks/mcp-cli.mjs +0 -205
  128. package/dist/chunks/mcp-performance.mjs +0 -187
  129. package/dist/chunks/mcp.mjs +0 -667
  130. package/dist/chunks/memory-check.mjs +0 -2973
  131. package/dist/chunks/memory-paths.mjs +0 -259
  132. package/dist/chunks/memory-sync.mjs +0 -209
  133. package/dist/chunks/memory.mjs +0 -354
  134. package/dist/chunks/metrics-display.mjs +0 -153
  135. package/dist/chunks/monitor.mjs +0 -1856
  136. package/dist/chunks/notification.mjs +0 -1864
  137. package/dist/chunks/onboarding.mjs +0 -386
  138. package/dist/chunks/package.mjs +0 -3
  139. package/dist/chunks/paradigm.mjs +0 -74
  140. package/dist/chunks/permission-manager.mjs +0 -250
  141. package/dist/chunks/permissions.mjs +0 -265
  142. package/dist/chunks/persistence-manager.mjs +0 -801
  143. package/dist/chunks/persistence.mjs +0 -707
  144. package/dist/chunks/platform.mjs +0 -395
  145. package/dist/chunks/plugin.mjs +0 -1936
  146. package/dist/chunks/powershell.mjs +0 -213
  147. package/dist/chunks/prompts.mjs +0 -244
  148. package/dist/chunks/providers.mjs +0 -263
  149. package/dist/chunks/quick-actions.mjs +0 -335
  150. package/dist/chunks/quick-provider.mjs +0 -755
  151. package/dist/chunks/quick-setup.mjs +0 -421
  152. package/dist/chunks/remote.mjs +0 -497
  153. package/dist/chunks/research.mjs +0 -1904
  154. package/dist/chunks/rollback.mjs +0 -38
  155. package/dist/chunks/session-manager.mjs +0 -1371
  156. package/dist/chunks/session.mjs +0 -878
  157. package/dist/chunks/sessions.mjs +0 -106
  158. package/dist/chunks/silent-updater.mjs +0 -396
  159. package/dist/chunks/simple-config.mjs +0 -122
  160. package/dist/chunks/skill.mjs +0 -117
  161. package/dist/chunks/skill2.mjs +0 -9052
  162. package/dist/chunks/skills-sync.mjs +0 -1343
  163. package/dist/chunks/skills.mjs +0 -577
  164. package/dist/chunks/slash-commands.mjs +0 -208
  165. package/dist/chunks/smart-guide.mjs +0 -247
  166. package/dist/chunks/snapshot.mjs +0 -58
  167. package/dist/chunks/startup.mjs +0 -487
  168. package/dist/chunks/stats.mjs +0 -191
  169. package/dist/chunks/status.mjs +0 -471
  170. package/dist/chunks/team.mjs +0 -63
  171. package/dist/chunks/thinking.mjs +0 -626
  172. package/dist/chunks/trace.mjs +0 -57
  173. package/dist/chunks/uninstall.mjs +0 -852
  174. package/dist/chunks/update.mjs +0 -174
  175. package/dist/chunks/upgrade-manager.mjs +0 -204
  176. package/dist/chunks/upgrade.mjs +0 -133
  177. package/dist/chunks/version-checker.mjs +0 -891
  178. package/dist/chunks/vim.mjs +0 -903
  179. package/dist/chunks/windows.mjs +0 -14
  180. package/dist/chunks/workflows.mjs +0 -633
  181. package/dist/chunks/wsl.mjs +0 -129
  182. package/dist/chunks/zero-config.mjs +0 -871
  183. package/dist/chunks/zsh.mjs +0 -182
  184. package/dist/cli.d.mts +0 -1
  185. package/dist/cli.d.ts +0 -1
  186. package/dist/cli.mjs +0 -2684
  187. package/dist/i18n/locales/en/agent-teams.json +0 -18
  188. package/dist/i18n/locales/en/agentBrowser.json +0 -80
  189. package/dist/i18n/locales/en/agents.json +0 -135
  190. package/dist/i18n/locales/en/api.json +0 -63
  191. package/dist/i18n/locales/en/ccjk-agents.json +0 -33
  192. package/dist/i18n/locales/en/ccjk-all.json +0 -23
  193. package/dist/i18n/locales/en/ccjk-skills.json +0 -22
  194. package/dist/i18n/locales/en/ccjk.json +0 -276
  195. package/dist/i18n/locales/en/ccr.json +0 -65
  196. package/dist/i18n/locales/en/claude-md.json +0 -73
  197. package/dist/i18n/locales/en/cli.json +0 -148
  198. package/dist/i18n/locales/en/cloud-setup.json +0 -31
  199. package/dist/i18n/locales/en/cloud-sync.json +0 -147
  200. package/dist/i18n/locales/en/cloud.json +0 -40
  201. package/dist/i18n/locales/en/cloudPlugins.json +0 -118
  202. package/dist/i18n/locales/en/codex.json +0 -184
  203. package/dist/i18n/locales/en/cometix.json +0 -29
  204. package/dist/i18n/locales/en/common.json +0 -68
  205. package/dist/i18n/locales/en/config.json +0 -108
  206. package/dist/i18n/locales/en/configuration.json +0 -236
  207. package/dist/i18n/locales/en/context.json +0 -85
  208. package/dist/i18n/locales/en/dashboard.json +0 -78
  209. package/dist/i18n/locales/en/errors.json +0 -26
  210. package/dist/i18n/locales/en/evolution.json +0 -54
  211. package/dist/i18n/locales/en/hooks.json +0 -74
  212. package/dist/i18n/locales/en/hooksSync.json +0 -133
  213. package/dist/i18n/locales/en/installation.json +0 -83
  214. package/dist/i18n/locales/en/interview.json +0 -104
  215. package/dist/i18n/locales/en/language.json +0 -19
  216. package/dist/i18n/locales/en/lsp.json +0 -78
  217. package/dist/i18n/locales/en/marketplace.json +0 -116
  218. package/dist/i18n/locales/en/mcp.json +0 -180
  219. package/dist/i18n/locales/en/memory.json +0 -23
  220. package/dist/i18n/locales/en/menu.json +0 -299
  221. package/dist/i18n/locales/en/multi-config.json +0 -79
  222. package/dist/i18n/locales/en/notification.json +0 -307
  223. package/dist/i18n/locales/en/permissions.json +0 -95
  224. package/dist/i18n/locales/en/persistence.json +0 -127
  225. package/dist/i18n/locales/en/plugins.json +0 -146
  226. package/dist/i18n/locales/en/quick-actions.json +0 -78
  227. package/dist/i18n/locales/en/registry.json +0 -54
  228. package/dist/i18n/locales/en/remote.json +0 -93
  229. package/dist/i18n/locales/en/sandbox.json +0 -44
  230. package/dist/i18n/locales/en/setup.json +0 -44
  231. package/dist/i18n/locales/en/shencha.json +0 -14
  232. package/dist/i18n/locales/en/skills.json +0 -100
  233. package/dist/i18n/locales/en/skillsSync.json +0 -74
  234. package/dist/i18n/locales/en/smartGuide.json +0 -49
  235. package/dist/i18n/locales/en/stats.json +0 -20
  236. package/dist/i18n/locales/en/subagent.json +0 -69
  237. package/dist/i18n/locales/en/superpowers.json +0 -117
  238. package/dist/i18n/locales/en/team.json +0 -7
  239. package/dist/i18n/locales/en/thinking.json +0 -65
  240. package/dist/i18n/locales/en/tools.json +0 -42
  241. package/dist/i18n/locales/en/uninstall.json +0 -56
  242. package/dist/i18n/locales/en/updater.json +0 -29
  243. package/dist/i18n/locales/en/vim.json +0 -169
  244. package/dist/i18n/locales/en/workflow.json +0 -55
  245. package/dist/i18n/locales/en/workspace.json +0 -108
  246. package/dist/i18n/locales/zh-CN/agent-teams.json +0 -18
  247. package/dist/i18n/locales/zh-CN/agentBrowser.json +0 -80
  248. package/dist/i18n/locales/zh-CN/agents.json +0 -135
  249. package/dist/i18n/locales/zh-CN/api.json +0 -63
  250. package/dist/i18n/locales/zh-CN/ccjk-agents.json +0 -33
  251. package/dist/i18n/locales/zh-CN/ccjk-all.json +0 -23
  252. package/dist/i18n/locales/zh-CN/ccjk-skills.json +0 -22
  253. package/dist/i18n/locales/zh-CN/ccjk.json +0 -276
  254. package/dist/i18n/locales/zh-CN/ccr.json +0 -65
  255. package/dist/i18n/locales/zh-CN/claude-md.json +0 -73
  256. package/dist/i18n/locales/zh-CN/cli.json +0 -148
  257. package/dist/i18n/locales/zh-CN/cloud-setup.json +0 -31
  258. package/dist/i18n/locales/zh-CN/cloud-sync.json +0 -147
  259. package/dist/i18n/locales/zh-CN/cloud.json +0 -40
  260. package/dist/i18n/locales/zh-CN/cloudPlugins.json +0 -118
  261. package/dist/i18n/locales/zh-CN/codex.json +0 -184
  262. package/dist/i18n/locales/zh-CN/cometix.json +0 -29
  263. package/dist/i18n/locales/zh-CN/common.json +0 -68
  264. package/dist/i18n/locales/zh-CN/config.json +0 -108
  265. package/dist/i18n/locales/zh-CN/configuration.json +0 -234
  266. package/dist/i18n/locales/zh-CN/context.json +0 -85
  267. package/dist/i18n/locales/zh-CN/dashboard.json +0 -78
  268. package/dist/i18n/locales/zh-CN/errors.json +0 -26
  269. package/dist/i18n/locales/zh-CN/evolution.json +0 -54
  270. package/dist/i18n/locales/zh-CN/hooks.json +0 -74
  271. package/dist/i18n/locales/zh-CN/hooksSync.json +0 -133
  272. package/dist/i18n/locales/zh-CN/installation.json +0 -83
  273. package/dist/i18n/locales/zh-CN/interview.json +0 -104
  274. package/dist/i18n/locales/zh-CN/language.json +0 -19
  275. package/dist/i18n/locales/zh-CN/lsp.json +0 -78
  276. package/dist/i18n/locales/zh-CN/marketplace.json +0 -116
  277. package/dist/i18n/locales/zh-CN/mcp.json +0 -180
  278. package/dist/i18n/locales/zh-CN/memory.json +0 -23
  279. package/dist/i18n/locales/zh-CN/menu.json +0 -299
  280. package/dist/i18n/locales/zh-CN/multi-config.json +0 -79
  281. package/dist/i18n/locales/zh-CN/notification.json +0 -307
  282. package/dist/i18n/locales/zh-CN/permissions.json +0 -95
  283. package/dist/i18n/locales/zh-CN/persistence.json +0 -127
  284. package/dist/i18n/locales/zh-CN/plugins.json +0 -146
  285. package/dist/i18n/locales/zh-CN/quick-actions.json +0 -78
  286. package/dist/i18n/locales/zh-CN/registry.json +0 -54
  287. package/dist/i18n/locales/zh-CN/remote.json +0 -93
  288. package/dist/i18n/locales/zh-CN/sandbox.json +0 -44
  289. package/dist/i18n/locales/zh-CN/setup.json +0 -44
  290. package/dist/i18n/locales/zh-CN/shencha.json +0 -14
  291. package/dist/i18n/locales/zh-CN/skills.json +0 -100
  292. package/dist/i18n/locales/zh-CN/skillsSync.json +0 -74
  293. package/dist/i18n/locales/zh-CN/smartGuide.json +0 -49
  294. package/dist/i18n/locales/zh-CN/stats.json +0 -20
  295. package/dist/i18n/locales/zh-CN/subagent.json +0 -69
  296. package/dist/i18n/locales/zh-CN/superpowers.json +0 -117
  297. package/dist/i18n/locales/zh-CN/team.json +0 -7
  298. package/dist/i18n/locales/zh-CN/thinking.json +0 -65
  299. package/dist/i18n/locales/zh-CN/tools.json +0 -42
  300. package/dist/i18n/locales/zh-CN/uninstall.json +0 -56
  301. package/dist/i18n/locales/zh-CN/updater.json +0 -29
  302. package/dist/i18n/locales/zh-CN/vim.json +0 -169
  303. package/dist/i18n/locales/zh-CN/workflow.json +0 -55
  304. package/dist/i18n/locales/zh-CN/workspace.json +0 -108
  305. package/dist/index.d.mts +0 -5658
  306. package/dist/index.d.ts +0 -5658
  307. package/dist/index.mjs +0 -3732
  308. package/dist/shared/ccjk.5bEolFrk.mjs +0 -254
  309. package/dist/shared/ccjk.8oaxX4iR.mjs +0 -90
  310. package/dist/shared/ccjk.B2U7DsPy.mjs +0 -31
  311. package/dist/shared/ccjk.B2f-cwUP.mjs +0 -468
  312. package/dist/shared/ccjk.BAGoDD49.mjs +0 -36
  313. package/dist/shared/ccjk.BBtCGd_g.mjs +0 -899
  314. package/dist/shared/ccjk.BFQ7yr5S.mjs +0 -16
  315. package/dist/shared/ccjk.BLsIiTqO.mjs +0 -449
  316. package/dist/shared/ccjk.BXv8aYs1.mjs +0 -170
  317. package/dist/shared/ccjk.BnsY5WxD.mjs +0 -171
  318. package/dist/shared/ccjk.BoApaI4j.mjs +0 -28
  319. package/dist/shared/ccjk.Bq8TqZG_.mjs +0 -189
  320. package/dist/shared/ccjk.BtrioX1Z.mjs +0 -25
  321. package/dist/shared/ccjk.Bx_rmYfN.mjs +0 -69
  322. package/dist/shared/ccjk.BzPbSEP2.mjs +0 -115
  323. package/dist/shared/ccjk.C0WLUnFV.mjs +0 -293
  324. package/dist/shared/ccjk.C1hANZTu.mjs +0 -19
  325. package/dist/shared/ccjk.C2jHOZVP.mjs +0 -52
  326. package/dist/shared/ccjk.CNhnT6uQ.mjs +0 -636
  327. package/dist/shared/ccjk.COweQ1RR.mjs +0 -5
  328. package/dist/shared/ccjk.CfKKcvWy.mjs +0 -126
  329. package/dist/shared/ccjk.Cjgrln_h.mjs +0 -297
  330. package/dist/shared/ccjk.CoCHVXl3.mjs +0 -3951
  331. package/dist/shared/ccjk.CwGZSTAK.mjs +0 -319
  332. package/dist/shared/ccjk.CxpGa6MC.mjs +0 -2724
  333. package/dist/shared/ccjk.D-magaEx.mjs +0 -763
  334. package/dist/shared/ccjk.D0g2ABGg.mjs +0 -171
  335. package/dist/shared/ccjk.D6ycHbak.mjs +0 -270
  336. package/dist/shared/ccjk.D75wivnp.mjs +0 -142
  337. package/dist/shared/ccjk.DDL-4C-k.mjs +0 -100
  338. package/dist/shared/ccjk.DFRPtmK_.mjs +0 -75
  339. package/dist/shared/ccjk.DMV3x5Sd.mjs +0 -299
  340. package/dist/shared/ccjk.DZ2LLOa-.mjs +0 -2195
  341. package/dist/shared/ccjk.DbigonEQ.mjs +0 -698
  342. package/dist/shared/ccjk.DcMvE7lf.mjs +0 -618
  343. package/dist/shared/ccjk.DeWpAShp.mjs +0 -1828
  344. package/dist/shared/ccjk.DhJ1kyDR.mjs +0 -30
  345. package/dist/shared/ccjk.DlTXS9rP.mjs +0 -224
  346. package/dist/shared/ccjk.DopKzo3z.mjs +0 -305
  347. package/dist/shared/ccjk.DsZsc4LR.mjs +0 -1280
  348. package/dist/shared/ccjk.DuzJZlgj.mjs +0 -418
  349. package/dist/shared/ccjk.Dxgd2vjc.mjs +0 -444
  350. package/dist/shared/ccjk.J8YiPsOw.mjs +0 -259
  351. package/dist/shared/ccjk.KfSWcGlE.mjs +0 -38
  352. package/dist/shared/ccjk.L7yC58_i.mjs +0 -225
  353. package/dist/shared/ccjk.MwtjAULc.mjs +0 -1447
  354. package/dist/shared/ccjk.OJKHVSOb.mjs +0 -2005
  355. package/dist/shared/ccjk.OTnevPNE.mjs +0 -225
  356. package/dist/shared/ccjk.RyizuzOI.mjs +0 -21
  357. package/dist/shared/ccjk.T_cX87dY.mjs +0 -15
  358. package/dist/shared/ccjk.bQ7Dh1g4.mjs +0 -249
  359. package/dist/shared/ccjk.gDEDGD_t.mjs +0 -38
  360. package/dist/shared/ccjk.hoqrwWdN.mjs +0 -333
  361. package/dist/shared/ccjk.i_vn-9C3.mjs +0 -317
  362. package/dist/shared/ccjk.lG3ccFjm.mjs +0 -885
  363. package/dist/shared/ccjk.wLJHO0Af.mjs +0 -244
  364. package/dist/shared/ccjk.y-a_1vK4.mjs +0 -5127
  365. package/dist/templates/agents/README.md +0 -78
  366. package/dist/templates/agents/fullstack-developer.json +0 -70
  367. package/dist/templates/agents/go-expert.json +0 -69
  368. package/dist/templates/agents/index.json +0 -64
  369. package/dist/templates/agents/python-expert.json +0 -69
  370. package/dist/templates/agents/react-specialist.json +0 -69
  371. package/dist/templates/agents/testing-automation-expert.json +0 -70
  372. package/dist/templates/agents/typescript-architect.json +0 -69
  373. package/dist/templates/claude-code/common/settings.json +0 -109
  374. package/dist/templates/common/error-prevention.md +0 -267
  375. package/dist/templates/common/karpathy-baseline.md +0 -83
  376. package/dist/templates/common/output-styles/zh-CN/carmack-mode.md +0 -381
  377. package/dist/templates/common/output-styles/zh-CN/codex-rigor-mode.md +0 -114
  378. package/dist/templates/common/output-styles/zh-CN/dhh-mode.md +0 -265
  379. package/dist/templates/common/output-styles/zh-CN/evan-you-mode.md +0 -539
  380. package/dist/templates/common/output-styles/zh-CN/jobs-mode.md +0 -369
  381. package/dist/templates/common/output-styles/zh-CN/linus-mode.md +0 -135
  382. package/dist/templates/common/output-styles/zh-CN/uncle-bob-mode.md +0 -221
  383. package/dist/templates/common/workflow/continuousDelivery/en/continuous-delivery.md +0 -628
  384. package/dist/templates/common/workflow/continuousDelivery/zh-CN/continuous-delivery.md +0 -628
  385. package/dist/templates/common/workflow/essential/en/agents/ccjk-config-agent.md +0 -187
  386. package/dist/templates/common/workflow/essential/en/agents/ccjk-mcp-agent.md +0 -191
  387. package/dist/templates/common/workflow/essential/en/agents/ccjk-skill-agent.md +0 -249
  388. package/dist/templates/common/workflow/essential/en/agents/ccjk-workflow-agent.md +0 -277
  389. package/dist/templates/common/workflow/essential/en/agents/get-current-datetime.md +0 -29
  390. package/dist/templates/common/workflow/essential/en/agents/init-architect.md +0 -115
  391. package/dist/templates/common/workflow/essential/en/agents/ui-ux-designer.md +0 -91
  392. package/dist/templates/common/workflow/essential/en/feat.md +0 -92
  393. package/dist/templates/common/workflow/essential/en/goal.md +0 -147
  394. package/dist/templates/common/workflow/essential/en/init-project.md +0 -53
  395. package/dist/templates/common/workflow/essential/zh-CN/agents/get-current-datetime.md +0 -29
  396. package/dist/templates/common/workflow/essential/zh-CN/agents/init-architect.md +0 -115
  397. package/dist/templates/common/workflow/essential/zh-CN/agents/ui-ux-designer.md +0 -91
  398. package/dist/templates/common/workflow/essential/zh-CN/feat.md +0 -315
  399. package/dist/templates/common/workflow/essential/zh-CN/goal.md +0 -146
  400. package/dist/templates/common/workflow/essential/zh-CN/init-project.md +0 -53
  401. package/dist/templates/common/workflow/git/en/git-cleanBranches.md +0 -102
  402. package/dist/templates/common/workflow/git/en/git-commit.md +0 -205
  403. package/dist/templates/common/workflow/git/en/git-rollback.md +0 -90
  404. package/dist/templates/common/workflow/git/en/git-worktree.md +0 -276
  405. package/dist/templates/common/workflow/git/zh-CN/git-cleanBranches.md +0 -102
  406. package/dist/templates/common/workflow/git/zh-CN/git-commit.md +0 -205
  407. package/dist/templates/common/workflow/git/zh-CN/git-rollback.md +0 -90
  408. package/dist/templates/common/workflow/git/zh-CN/git-worktree.md +0 -276
  409. package/dist/templates/common/workflow/interview/en/interview.md +0 -67
  410. package/dist/templates/common/workflow/interview/zh-CN/interview.md +0 -67
  411. package/dist/templates/common/workflow/linearMethod/en/linear-method.md +0 -651
  412. package/dist/templates/common/workflow/linearMethod/zh-CN/linear-method.md +0 -752
  413. package/dist/templates/common/workflow/refactoringMaster/en/refactoring-master.md +0 -516
  414. package/dist/templates/common/workflow/refactoringMaster/zh-CN/refactoring-master.md +0 -812
  415. package/dist/templates/common/workflow/sixStep/en/workflow.md +0 -83
  416. package/dist/templates/common/workflow/sixStep/zh-CN/workflow.md +0 -359
  417. package/dist/templates/common/workflow/specFirstTDD/en/spec-first-tdd.md +0 -364
  418. package/dist/templates/common/workflow/specFirstTDD/zh-CN/spec-first-tdd.md +0 -366
  419. package/dist/templates/hooks/README.md +0 -212
  420. package/dist/templates/hooks/git-workflow-hooks.md +0 -551
  421. package/dist/templates/hooks/post-test/coverage.json +0 -21
  422. package/dist/templates/hooks/post-test/summary.json +0 -21
  423. package/dist/templates/hooks/post-test-coverage.md +0 -434
  424. package/dist/templates/hooks/pre-commit/eslint.json +0 -22
  425. package/dist/templates/hooks/pre-commit/prettier.json +0 -22
  426. package/dist/templates/hooks/pre-commit-black.md +0 -274
  427. package/dist/templates/hooks/pre-commit-eslint.md +0 -153
  428. package/dist/templates/hooks/pre-commit-gofmt.md +0 -284
  429. package/dist/templates/hooks/pre-commit-prettier.md +0 -212
  430. package/dist/templates/hooks/pre-commit-type-check.md +0 -377
  431. package/dist/templates/skills/ccjk-init.md +0 -154
  432. package/dist/templates/skills/ccjk-mcp-setup.md +0 -205
  433. package/dist/templates/skills/ccjk-troubleshoot.md +0 -228
  434. package/dist/templates/skills/django-patterns.md +0 -1016
  435. package/dist/templates/skills/git-workflow.md +0 -748
  436. package/dist/templates/skills/go-idioms.md +0 -963
  437. package/dist/templates/skills/index.json +0 -132
  438. package/dist/templates/skills/nextjs-optimization.md +0 -694
  439. package/dist/templates/skills/python-pep8.md +0 -852
  440. package/dist/templates/skills/react-patterns.md +0 -686
  441. package/dist/templates/skills/rust-patterns.md +0 -1057
  442. package/dist/templates/skills/security-best-practices.md +0 -1413
  443. package/dist/templates/skills/testing-best-practices.md +0 -1315
  444. package/dist/templates/skills/ts-best-practices.md +0 -354
  445. package/templates/agents/README.md +0 -78
  446. package/templates/agents/fullstack-developer.json +0 -70
  447. package/templates/agents/go-expert.json +0 -69
  448. package/templates/agents/index.json +0 -64
  449. package/templates/agents/python-expert.json +0 -69
  450. package/templates/agents/react-specialist.json +0 -69
  451. package/templates/agents/testing-automation-expert.json +0 -70
  452. package/templates/agents/typescript-architect.json +0 -69
  453. package/templates/claude-code/common/settings.json +0 -109
  454. package/templates/common/error-prevention.md +0 -267
  455. package/templates/common/karpathy-baseline.md +0 -83
  456. package/templates/common/output-styles/zh-CN/carmack-mode.md +0 -381
  457. package/templates/common/output-styles/zh-CN/codex-rigor-mode.md +0 -114
  458. package/templates/common/output-styles/zh-CN/dhh-mode.md +0 -265
  459. package/templates/common/output-styles/zh-CN/evan-you-mode.md +0 -539
  460. package/templates/common/output-styles/zh-CN/jobs-mode.md +0 -369
  461. package/templates/common/output-styles/zh-CN/linus-mode.md +0 -135
  462. package/templates/common/output-styles/zh-CN/uncle-bob-mode.md +0 -221
  463. package/templates/common/workflow/continuousDelivery/en/continuous-delivery.md +0 -628
  464. package/templates/common/workflow/continuousDelivery/zh-CN/continuous-delivery.md +0 -628
  465. package/templates/common/workflow/essential/en/agents/ccjk-config-agent.md +0 -187
  466. package/templates/common/workflow/essential/en/agents/ccjk-mcp-agent.md +0 -191
  467. package/templates/common/workflow/essential/en/agents/ccjk-skill-agent.md +0 -249
  468. package/templates/common/workflow/essential/en/agents/ccjk-workflow-agent.md +0 -277
  469. package/templates/common/workflow/essential/en/agents/get-current-datetime.md +0 -29
  470. package/templates/common/workflow/essential/en/agents/init-architect.md +0 -115
  471. package/templates/common/workflow/essential/en/agents/ui-ux-designer.md +0 -91
  472. package/templates/common/workflow/essential/en/feat.md +0 -92
  473. package/templates/common/workflow/essential/en/goal.md +0 -147
  474. package/templates/common/workflow/essential/en/init-project.md +0 -53
  475. package/templates/common/workflow/essential/zh-CN/agents/get-current-datetime.md +0 -29
  476. package/templates/common/workflow/essential/zh-CN/agents/init-architect.md +0 -115
  477. package/templates/common/workflow/essential/zh-CN/agents/ui-ux-designer.md +0 -91
  478. package/templates/common/workflow/essential/zh-CN/feat.md +0 -315
  479. package/templates/common/workflow/essential/zh-CN/goal.md +0 -146
  480. package/templates/common/workflow/essential/zh-CN/init-project.md +0 -53
  481. package/templates/common/workflow/git/en/git-cleanBranches.md +0 -102
  482. package/templates/common/workflow/git/en/git-commit.md +0 -205
  483. package/templates/common/workflow/git/en/git-rollback.md +0 -90
  484. package/templates/common/workflow/git/en/git-worktree.md +0 -276
  485. package/templates/common/workflow/git/zh-CN/git-cleanBranches.md +0 -102
  486. package/templates/common/workflow/git/zh-CN/git-commit.md +0 -205
  487. package/templates/common/workflow/git/zh-CN/git-rollback.md +0 -90
  488. package/templates/common/workflow/git/zh-CN/git-worktree.md +0 -276
  489. package/templates/common/workflow/interview/en/interview.md +0 -67
  490. package/templates/common/workflow/interview/zh-CN/interview.md +0 -67
  491. package/templates/common/workflow/linearMethod/en/linear-method.md +0 -651
  492. package/templates/common/workflow/linearMethod/zh-CN/linear-method.md +0 -752
  493. package/templates/common/workflow/refactoringMaster/en/refactoring-master.md +0 -516
  494. package/templates/common/workflow/refactoringMaster/zh-CN/refactoring-master.md +0 -812
  495. package/templates/common/workflow/sixStep/en/workflow.md +0 -83
  496. package/templates/common/workflow/sixStep/zh-CN/workflow.md +0 -359
  497. package/templates/common/workflow/specFirstTDD/en/spec-first-tdd.md +0 -364
  498. package/templates/common/workflow/specFirstTDD/zh-CN/spec-first-tdd.md +0 -366
  499. package/templates/hooks/README.md +0 -212
  500. package/templates/hooks/git-workflow-hooks.md +0 -551
  501. package/templates/hooks/post-test/coverage.json +0 -21
  502. package/templates/hooks/post-test/summary.json +0 -21
  503. package/templates/hooks/post-test-coverage.md +0 -434
  504. package/templates/hooks/pre-commit/eslint.json +0 -22
  505. package/templates/hooks/pre-commit/prettier.json +0 -22
  506. package/templates/hooks/pre-commit-black.md +0 -274
  507. package/templates/hooks/pre-commit-eslint.md +0 -153
  508. package/templates/hooks/pre-commit-gofmt.md +0 -284
  509. package/templates/hooks/pre-commit-prettier.md +0 -212
  510. package/templates/hooks/pre-commit-type-check.md +0 -377
  511. package/templates/skills/basic.hbs +0 -72
  512. package/templates/skills/ccjk-init.md +0 -154
  513. package/templates/skills/ccjk-mcp-setup.md +0 -205
  514. package/templates/skills/ccjk-troubleshoot.md +0 -228
  515. package/templates/skills/code-refactor.hbs +0 -133
  516. package/templates/skills/code-review.hbs +0 -141
  517. package/templates/skills/django-patterns.md +0 -1016
  518. package/templates/skills/git-workflow.md +0 -748
  519. package/templates/skills/go-idioms.md +0 -963
  520. package/templates/skills/index.json +0 -132
  521. package/templates/skills/nextjs-optimization.md +0 -694
  522. package/templates/skills/python-pep8.md +0 -852
  523. package/templates/skills/react-patterns.md +0 -686
  524. package/templates/skills/rust-patterns.md +0 -1057
  525. package/templates/skills/security-best-practices.md +0 -1413
  526. package/templates/skills/testing-best-practices.md +0 -1315
  527. package/templates/skills/ts-best-practices.md +0 -354
  528. package/templates/skills/type-fix.hbs +0 -132
@@ -1,1864 +0,0 @@
1
- import a from './index5.mjs';
2
- import { i as inquirer } from './index6.mjs';
3
- import { i18n } from './index2.mjs';
4
- import { m as maskToken, a as isValidTokenFormat, c as generateDeviceToken, d as decryptToken, e as encryptToken, f as getDeviceInfo, i as isDeviceBound, g as getBindingStatus, u as unbindDevice, b as bindDevice, s as sendNotification } from '../shared/ccjk.DcMvE7lf.mjs';
5
- import { exec } from 'node:child_process';
6
- import * as fs from 'node:fs';
7
- import fs__default from 'node:fs';
8
- import * as os from 'node:os';
9
- import os__default from 'node:os';
10
- import * as path from 'node:path';
11
- import path__default from 'node:path';
12
- import process__default from 'node:process';
13
- import { promisify } from 'node:util';
14
- import { writeFileAtomic } from './fs-operations.mjs';
15
- import { p as parse } from '../shared/ccjk.BBtCGd_g.mjs';
16
- import { stringify } from './index3.mjs';
17
- import { CLOUD_ENDPOINTS } from './constants.mjs';
18
- import '../shared/ccjk.BAGoDD49.mjs';
19
- import 'node:readline';
20
- import 'stream';
21
- import 'node:tty';
22
- import 'node:async_hooks';
23
- import '../shared/ccjk.Cjgrln_h.mjs';
24
- import 'tty';
25
- import 'fs';
26
- import 'child_process';
27
- import 'node:crypto';
28
- import 'buffer';
29
- import 'string_decoder';
30
- import 'node:url';
31
- import '../shared/ccjk.bQ7Dh1g4.mjs';
32
- import '../shared/ccjk.D0g2ABGg.mjs';
33
- import '../shared/ccjk.D6ycHbak.mjs';
34
- import 'node:buffer';
35
- import 'node:fs/promises';
36
-
37
- const execAsync = promisify(exec);
38
- const DEFAULT_CONFIG = {
39
- shortcutName: "ClaudeNotify",
40
- barkUrl: "",
41
- preferLocal: true,
42
- smartNotify: true,
43
- fallbackToBark: true
44
- };
45
- const CONFIG_DIR = path.join(os.homedir(), ".ccjk");
46
- const CONFIG_FILE = path.join(CONFIG_DIR, "notification-config.json");
47
- const TEMP_NOTIFICATION_FILE = "/tmp/ccjk-notification.json";
48
- class LocalNotificationService {
49
- config;
50
- constructor(config) {
51
- this.config = { ...DEFAULT_CONFIG, ...config };
52
- }
53
- // ==========================================================================
54
- // Screen Lock Detection
55
- // ==========================================================================
56
- /**
57
- * Check if the macOS screen is locked
58
- *
59
- * Uses Python with Quartz framework to detect screen lock status.
60
- *
61
- * @returns true if screen is locked, false otherwise
62
- */
63
- async isScreenLocked() {
64
- if (process__default.platform !== "darwin") {
65
- return false;
66
- }
67
- try {
68
- const pythonScript = `
69
- import Quartz
70
- session_dict = Quartz.CGSessionCopyCurrentDictionary()
71
- if session_dict:
72
- locked = session_dict.get('CGSSessionScreenIsLocked', False)
73
- print('true' if locked else 'false')
74
- else:
75
- print('false')
76
- `;
77
- const { stdout } = await execAsync(`python3 -c "${pythonScript}"`, {
78
- timeout: 5e3
79
- });
80
- return stdout.trim().toLowerCase() === "true";
81
- } catch (error) {
82
- console.error("Failed to detect screen lock status:", error);
83
- return false;
84
- }
85
- }
86
- // ==========================================================================
87
- // macOS Shortcut Notification
88
- // ==========================================================================
89
- /**
90
- * Send notification via macOS Shortcuts
91
- *
92
- * Creates a JSON file with notification data and runs the specified shortcut.
93
- * The shortcut should be configured to read the JSON and display a notification.
94
- *
95
- * @param shortcutName - Name of the macOS Shortcut to run
96
- * @param options - Notification options
97
- */
98
- async sendShortcutNotification(shortcutName, options) {
99
- if (process__default.platform !== "darwin") {
100
- throw new Error("macOS Shortcuts are only available on macOS");
101
- }
102
- const notificationData = {
103
- title: options.title,
104
- body: options.body,
105
- sound: options.sound !== false,
106
- url: options.url || "",
107
- group: options.group || "ccjk",
108
- timestamp: (/* @__PURE__ */ new Date()).toISOString()
109
- };
110
- writeFileAtomic(TEMP_NOTIFICATION_FILE, JSON.stringify(notificationData, null, 2), "utf-8");
111
- try {
112
- await execAsync(`shortcuts run "${shortcutName}" --input-path "${TEMP_NOTIFICATION_FILE}"`, {
113
- timeout: 3e4
114
- // 30 second timeout
115
- });
116
- } finally {
117
- try {
118
- if (fs.existsSync(TEMP_NOTIFICATION_FILE)) {
119
- fs.unlinkSync(TEMP_NOTIFICATION_FILE);
120
- }
121
- } catch {
122
- }
123
- }
124
- }
125
- // ==========================================================================
126
- // Bark Push Notification
127
- // ==========================================================================
128
- /**
129
- * Send notification via Bark push service
130
- *
131
- * Bark is an iOS app that allows sending push notifications via HTTP API.
132
- * API format: https://api.day.app/YOUR_KEY/title/body
133
- *
134
- * @param barkUrl - Bark API URL (e.g., https://api.day.app/YOUR_KEY)
135
- * @param options - Notification options
136
- */
137
- async sendBarkNotification(barkUrl, options) {
138
- if (!barkUrl) {
139
- throw new Error("Bark URL is not configured");
140
- }
141
- const encodedTitle = encodeURIComponent(options.title);
142
- const encodedBody = encodeURIComponent(options.body);
143
- const params = new URLSearchParams();
144
- if (options.sound !== false) {
145
- params.append("sound", "default");
146
- }
147
- if (options.url) {
148
- params.append("url", options.url);
149
- }
150
- if (options.group) {
151
- params.append("group", options.group);
152
- }
153
- if (options.icon) {
154
- params.append("icon", options.icon);
155
- }
156
- const baseUrl = barkUrl.endsWith("/") ? barkUrl.slice(0, -1) : barkUrl;
157
- let fullUrl = `${baseUrl}/${encodedTitle}/${encodedBody}`;
158
- const queryString = params.toString();
159
- if (queryString) {
160
- fullUrl += `?${queryString}`;
161
- }
162
- try {
163
- await execAsync(`curl -s -o /dev/null -w "%{http_code}" "${fullUrl}"`, {
164
- timeout: 1e4
165
- });
166
- } catch (error) {
167
- throw new Error(`Failed to send Bark notification: ${error}`);
168
- }
169
- }
170
- // ==========================================================================
171
- // Smart Notification
172
- // ==========================================================================
173
- /**
174
- * Smart notification - automatically choose notification method
175
- *
176
- * Logic:
177
- * 1. If screen is unlocked and preferLocal is true, use macOS Shortcut
178
- * 2. If screen is locked or shortcut fails, use Bark
179
- * 3. If both fail, throw error
180
- *
181
- * @param options - Notification options
182
- * @returns Notification result
183
- */
184
- async smartNotify(options) {
185
- const isLocked = await this.isScreenLocked();
186
- if (!isLocked && this.config.preferLocal && this.config.shortcutName) {
187
- try {
188
- await this.sendShortcutNotification(this.config.shortcutName, options);
189
- return {
190
- success: true,
191
- method: "shortcut"
192
- };
193
- } catch (error) {
194
- if (this.config.fallbackToBark && this.config.barkUrl) {
195
- try {
196
- await this.sendBarkNotification(this.config.barkUrl, options);
197
- return {
198
- success: true,
199
- method: "bark"
200
- };
201
- } catch (barkError) {
202
- return {
203
- success: false,
204
- method: "none",
205
- error: `Shortcut failed: ${error}. Bark also failed: ${barkError}`
206
- };
207
- }
208
- }
209
- return {
210
- success: false,
211
- method: "none",
212
- error: `Shortcut notification failed: ${error}`
213
- };
214
- }
215
- }
216
- if (this.config.barkUrl) {
217
- try {
218
- await this.sendBarkNotification(this.config.barkUrl, options);
219
- return {
220
- success: true,
221
- method: "bark"
222
- };
223
- } catch (error) {
224
- return {
225
- success: false,
226
- method: "none",
227
- error: `Bark notification failed: ${error}`
228
- };
229
- }
230
- }
231
- if (this.config.shortcutName) {
232
- try {
233
- await this.sendShortcutNotification(this.config.shortcutName, options);
234
- return {
235
- success: true,
236
- method: "shortcut"
237
- };
238
- } catch (error) {
239
- return {
240
- success: false,
241
- method: "none",
242
- error: `Shortcut notification failed: ${error}`
243
- };
244
- }
245
- }
246
- return {
247
- success: false,
248
- method: "none",
249
- error: "No notification method configured"
250
- };
251
- }
252
- // ==========================================================================
253
- // Configuration Management
254
- // ==========================================================================
255
- /**
256
- * Update service configuration
257
- *
258
- * @param config - Partial configuration to update
259
- */
260
- updateConfig(config) {
261
- this.config = { ...this.config, ...config };
262
- }
263
- /**
264
- * Get current configuration
265
- *
266
- * @returns Current configuration
267
- */
268
- getConfig() {
269
- return { ...this.config };
270
- }
271
- }
272
- async function loadLocalNotificationConfig() {
273
- try {
274
- if (!fs.existsSync(CONFIG_FILE)) {
275
- return { ...DEFAULT_CONFIG };
276
- }
277
- const content = fs.readFileSync(CONFIG_FILE, "utf-8");
278
- const config = JSON.parse(content);
279
- return {
280
- ...DEFAULT_CONFIG,
281
- ...config
282
- };
283
- } catch (error) {
284
- console.error("Failed to load local notification config:", error);
285
- return { ...DEFAULT_CONFIG };
286
- }
287
- }
288
- async function saveLocalNotificationConfig(config) {
289
- try {
290
- if (!fs.existsSync(CONFIG_DIR)) {
291
- fs.mkdirSync(CONFIG_DIR, { recursive: true });
292
- }
293
- const existingConfig = await loadLocalNotificationConfig();
294
- const newConfig = { ...existingConfig, ...config };
295
- writeFileAtomic(CONFIG_FILE, JSON.stringify(newConfig, null, 2));
296
- } catch (error) {
297
- throw new Error(`Failed to save local notification config: ${error}`);
298
- }
299
- }
300
- let serviceInstance = null;
301
- async function getLocalNotificationService() {
302
- if (!serviceInstance) {
303
- const config = await loadLocalNotificationConfig();
304
- serviceInstance = new LocalNotificationService(config);
305
- }
306
- return serviceInstance;
307
- }
308
- async function isShortcutsAvailable() {
309
- if (process__default.platform !== "darwin") {
310
- return false;
311
- }
312
- try {
313
- await execAsync("which shortcuts", { timeout: 5e3 });
314
- return true;
315
- } catch {
316
- return false;
317
- }
318
- }
319
- async function listShortcuts() {
320
- if (process__default.platform !== "darwin") {
321
- return [];
322
- }
323
- try {
324
- const { stdout } = await execAsync("shortcuts list", { timeout: 1e4 });
325
- return stdout.split("\n").map((line) => line.trim()).filter((line) => line.length > 0);
326
- } catch {
327
- return [];
328
- }
329
- }
330
- function isValidBarkUrl(url) {
331
- if (!url) {
332
- return false;
333
- }
334
- try {
335
- const parsed = new URL(url);
336
- return parsed.protocol === "https:" || parsed.protocol === "http:";
337
- } catch {
338
- return false;
339
- }
340
- }
341
-
342
- const DEFAULT_NOTIFICATION_CONFIG = {
343
- enabled: false,
344
- deviceToken: "",
345
- threshold: 10,
346
- // 10 minutes
347
- cloudEndpoint: `${CLOUD_ENDPOINTS.REMOTE.BASE_URL}/api/v1`,
348
- channels: {},
349
- quietHours: {
350
- enabled: false,
351
- startHour: 22,
352
- endHour: 8
353
- }
354
- };
355
- function validateNotificationConfig(config) {
356
- const errors = [];
357
- const warnings = [];
358
- if (config.threshold !== void 0) {
359
- if (config.threshold < 1) {
360
- errors.push({
361
- field: "threshold",
362
- message: "Threshold must be at least 1 minute",
363
- code: "THRESHOLD_TOO_LOW"
364
- });
365
- }
366
- if (config.threshold > 1440) {
367
- warnings.push("Threshold is set to more than 24 hours");
368
- }
369
- }
370
- if (config.channels?.feishu?.enabled) {
371
- if (!config.channels.feishu.webhookUrl) {
372
- errors.push({
373
- field: "channels.feishu.webhookUrl",
374
- message: "Feishu webhook URL is required when enabled",
375
- code: "FEISHU_WEBHOOK_REQUIRED"
376
- });
377
- } else if (!config.channels.feishu.webhookUrl.startsWith("https://")) {
378
- errors.push({
379
- field: "channels.feishu.webhookUrl",
380
- message: "Feishu webhook URL must use HTTPS",
381
- code: "FEISHU_WEBHOOK_INVALID"
382
- });
383
- }
384
- }
385
- if (config.channels?.wechat?.enabled) {
386
- if (!config.channels.wechat.corpId) {
387
- errors.push({
388
- field: "channels.wechat.corpId",
389
- message: "WeChat Work Corp ID is required when enabled",
390
- code: "WECHAT_CORPID_REQUIRED"
391
- });
392
- }
393
- if (!config.channels.wechat.agentId) {
394
- errors.push({
395
- field: "channels.wechat.agentId",
396
- message: "WeChat Work Agent ID is required when enabled",
397
- code: "WECHAT_AGENTID_REQUIRED"
398
- });
399
- }
400
- if (!config.channels.wechat.secret) {
401
- errors.push({
402
- field: "channels.wechat.secret",
403
- message: "WeChat Work Secret is required when enabled",
404
- code: "WECHAT_SECRET_REQUIRED"
405
- });
406
- }
407
- }
408
- if (config.channels?.email?.enabled) {
409
- if (!config.channels.email.address) {
410
- errors.push({
411
- field: "channels.email.address",
412
- message: "Email address is required when enabled",
413
- code: "EMAIL_ADDRESS_REQUIRED"
414
- });
415
- } else if (!/^[^\s@]+@[^\s@][^\s.@]*\.[^\s@]+$/.test(config.channels.email.address)) {
416
- errors.push({
417
- field: "channels.email.address",
418
- message: "Invalid email address format",
419
- code: "EMAIL_ADDRESS_INVALID"
420
- });
421
- }
422
- }
423
- if (config.channels?.sms?.enabled) {
424
- if (!config.channels.sms.phone) {
425
- errors.push({
426
- field: "channels.sms.phone",
427
- message: "Phone number is required when enabled",
428
- code: "SMS_PHONE_REQUIRED"
429
- });
430
- } else if (!/^\d{10,15}$/.test(config.channels.sms.phone.replace(/\D/g, ""))) {
431
- errors.push({
432
- field: "channels.sms.phone",
433
- message: "Invalid phone number format",
434
- code: "SMS_PHONE_INVALID"
435
- });
436
- }
437
- }
438
- if (config.quietHours?.enabled) {
439
- if (config.quietHours.startHour < 0 || config.quietHours.startHour > 23) {
440
- errors.push({
441
- field: "quietHours.startHour",
442
- message: "Start hour must be between 0 and 23",
443
- code: "QUIET_HOURS_INVALID"
444
- });
445
- }
446
- if (config.quietHours.endHour < 0 || config.quietHours.endHour > 23) {
447
- errors.push({
448
- field: "quietHours.endHour",
449
- message: "End hour must be between 0 and 23",
450
- code: "QUIET_HOURS_INVALID"
451
- });
452
- }
453
- }
454
- return {
455
- valid: errors.length === 0,
456
- errors,
457
- warnings
458
- };
459
- }
460
-
461
- const CCJK_CONFIG_DIR = path__default.join(os__default.homedir(), ".ccjk");
462
- const CONFIG_FILE_PATH = path__default.join(CCJK_CONFIG_DIR, "config.toml");
463
- const SECRETS_FILE_PATH = path__default.join(CCJK_CONFIG_DIR, ".notification-secrets");
464
- async function loadNotificationConfig() {
465
- try {
466
- if (!fs__default.existsSync(CCJK_CONFIG_DIR)) {
467
- fs__default.mkdirSync(CCJK_CONFIG_DIR, { recursive: true });
468
- }
469
- if (!fs__default.existsSync(CONFIG_FILE_PATH)) {
470
- return { ...DEFAULT_NOTIFICATION_CONFIG };
471
- }
472
- const configContent = fs__default.readFileSync(CONFIG_FILE_PATH, "utf-8");
473
- const config = parse(configContent);
474
- const notificationConfig = config.notification;
475
- if (!notificationConfig) {
476
- return { ...DEFAULT_NOTIFICATION_CONFIG };
477
- }
478
- const deviceToken = await loadDeviceToken();
479
- const quietHoursConfig = notificationConfig.quietHours || {};
480
- const defaultQuietHours = DEFAULT_NOTIFICATION_CONFIG.quietHours || {
481
- enabled: false,
482
- startHour: 22,
483
- endHour: 8,
484
- timezone: "local"
485
- };
486
- return {
487
- ...DEFAULT_NOTIFICATION_CONFIG,
488
- ...notificationConfig,
489
- deviceToken: deviceToken || notificationConfig.deviceToken || "",
490
- channels: {
491
- ...DEFAULT_NOTIFICATION_CONFIG.channels,
492
- ...notificationConfig.channels
493
- },
494
- quietHours: {
495
- enabled: quietHoursConfig.enabled ?? defaultQuietHours.enabled,
496
- startHour: quietHoursConfig.startHour ?? defaultQuietHours.startHour,
497
- endHour: quietHoursConfig.endHour ?? defaultQuietHours.endHour,
498
- timezone: quietHoursConfig.timezone ?? defaultQuietHours.timezone
499
- }
500
- };
501
- } catch (error) {
502
- console.error("Failed to load notification config:", error);
503
- return { ...DEFAULT_NOTIFICATION_CONFIG };
504
- }
505
- }
506
- async function loadDeviceToken() {
507
- try {
508
- if (!fs__default.existsSync(SECRETS_FILE_PATH)) {
509
- return null;
510
- }
511
- const secretsContent = fs__default.readFileSync(SECRETS_FILE_PATH, "utf-8");
512
- const secrets = JSON.parse(secretsContent);
513
- if (!secrets.deviceToken) {
514
- return null;
515
- }
516
- const decryptedToken = decryptToken(secrets.deviceToken);
517
- return decryptedToken;
518
- } catch {
519
- return null;
520
- }
521
- }
522
- async function saveNotificationConfig(config) {
523
- try {
524
- if (!fs__default.existsSync(CCJK_CONFIG_DIR)) {
525
- fs__default.mkdirSync(CCJK_CONFIG_DIR, { recursive: true });
526
- }
527
- let existingConfig = {};
528
- if (fs__default.existsSync(CONFIG_FILE_PATH)) {
529
- const configContent = fs__default.readFileSync(CONFIG_FILE_PATH, "utf-8");
530
- existingConfig = parse(configContent);
531
- }
532
- const notificationConfig = { ...config };
533
- if (notificationConfig.deviceToken) {
534
- await saveDeviceToken(notificationConfig.deviceToken);
535
- delete notificationConfig.deviceToken;
536
- }
537
- existingConfig.notification = {
538
- ...existingConfig.notification || {},
539
- ...notificationConfig
540
- };
541
- const tomlContent = stringify(existingConfig);
542
- writeFileAtomic(CONFIG_FILE_PATH, tomlContent);
543
- } catch (error) {
544
- throw new Error(`Failed to save notification config: ${error}`);
545
- }
546
- }
547
- async function saveDeviceToken(token) {
548
- try {
549
- const encryptedToken = encryptToken(token);
550
- let secrets = {};
551
- if (fs__default.existsSync(SECRETS_FILE_PATH)) {
552
- const secretsContent = fs__default.readFileSync(SECRETS_FILE_PATH, "utf-8");
553
- secrets = JSON.parse(secretsContent);
554
- }
555
- secrets.deviceToken = encryptedToken;
556
- secrets.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
557
- writeFileAtomic(SECRETS_FILE_PATH, JSON.stringify(secrets, null, 2), {
558
- encoding: "utf-8",
559
- mode: 384
560
- // Owner read/write only
561
- });
562
- } catch (error) {
563
- throw new Error(`Failed to save device token: ${error}`);
564
- }
565
- }
566
- async function initializeNotificationConfig() {
567
- const existingConfig = await loadNotificationConfig();
568
- if (!existingConfig.deviceToken || !isValidTokenFormat(existingConfig.deviceToken)) {
569
- existingConfig.deviceToken = generateDeviceToken();
570
- await saveNotificationConfig(existingConfig);
571
- }
572
- return existingConfig;
573
- }
574
- async function updateNotificationConfig(updates) {
575
- const currentConfig = await loadNotificationConfig();
576
- const updatesQuietHours = updates.quietHours || {};
577
- const currentQuietHours = currentConfig.quietHours || {
578
- enabled: false,
579
- startHour: 22,
580
- endHour: 8,
581
- timezone: "local"
582
- };
583
- const newConfig = {
584
- ...currentConfig,
585
- ...updates,
586
- channels: {
587
- ...currentConfig.channels,
588
- ...updates.channels
589
- },
590
- quietHours: {
591
- enabled: updatesQuietHours.enabled ?? currentQuietHours.enabled,
592
- startHour: updatesQuietHours.startHour ?? currentQuietHours.startHour,
593
- endHour: updatesQuietHours.endHour ?? currentQuietHours.endHour,
594
- timezone: updatesQuietHours.timezone ?? currentQuietHours.timezone
595
- }
596
- };
597
- await saveNotificationConfig(newConfig);
598
- return newConfig;
599
- }
600
- async function enableChannel(channel, config) {
601
- const currentConfig = await loadNotificationConfig();
602
- currentConfig.channels[channel] = {
603
- ...config,
604
- enabled: true
605
- };
606
- await saveNotificationConfig(currentConfig);
607
- }
608
- async function disableChannel(channel) {
609
- const currentConfig = await loadNotificationConfig();
610
- if (currentConfig.channels[channel]) {
611
- currentConfig.channels[channel].enabled = false;
612
- await saveNotificationConfig(currentConfig);
613
- }
614
- }
615
- async function getEnabledChannels() {
616
- const config = await loadNotificationConfig();
617
- const enabledChannels = [];
618
- if (config.channels.feishu?.enabled) {
619
- enabledChannels.push("feishu");
620
- }
621
- if (config.channels.wechat?.enabled) {
622
- enabledChannels.push("wechat");
623
- }
624
- if (config.channels.email?.enabled) {
625
- enabledChannels.push("email");
626
- }
627
- if (config.channels.sms?.enabled) {
628
- enabledChannels.push("sms");
629
- }
630
- return enabledChannels;
631
- }
632
- async function validateCurrentConfig() {
633
- const config = await loadNotificationConfig();
634
- return validateNotificationConfig(config);
635
- }
636
- async function getConfigSummary() {
637
- const config = await loadNotificationConfig();
638
- const enabledChannels = await getEnabledChannels();
639
- return {
640
- enabled: config.enabled,
641
- deviceToken: maskToken(config.deviceToken),
642
- threshold: config.threshold,
643
- enabledChannels,
644
- quietHours: {
645
- enabled: config.quietHours?.enabled || false,
646
- hours: config.quietHours?.enabled ? `${config.quietHours.startHour}:00 - ${config.quietHours.endHour}:00` : void 0
647
- }
648
- };
649
- }
650
- const THRESHOLD_OPTIONS = [
651
- { value: 5, label: "5 minutes" },
652
- { value: 10, label: "10 minutes" },
653
- { value: 15, label: "15 minutes" },
654
- { value: 30, label: "30 minutes" },
655
- { value: 60, label: "1 hour" }
656
- ];
657
- async function setThreshold(minutes) {
658
- if (minutes < 1) {
659
- throw new Error("Threshold must be at least 1 minute");
660
- }
661
- await updateNotificationConfig({ threshold: minutes });
662
- }
663
- async function enableNotifications() {
664
- await updateNotificationConfig({ enabled: true });
665
- }
666
- async function disableNotifications() {
667
- await updateNotificationConfig({ enabled: false });
668
- }
669
-
670
- const DEFAULT_CLOUD_ENDPOINT = `${CLOUD_ENDPOINTS.REMOTE.BASE_URL}/api/v1`;
671
- const REQUEST_TIMEOUT = 3e4;
672
- const POLL_TIMEOUT = 6e4;
673
- class CloudClient {
674
- static instance = null;
675
- endpoint = DEFAULT_CLOUD_ENDPOINT;
676
- deviceToken = "";
677
- isPolling = false;
678
- pollAbortController = null;
679
- constructor() {
680
- }
681
- /**
682
- * Get the singleton instance
683
- */
684
- static getInstance() {
685
- if (!CloudClient.instance) {
686
- CloudClient.instance = new CloudClient();
687
- }
688
- return CloudClient.instance;
689
- }
690
- /**
691
- * Initialize the cloud client
692
- */
693
- async initialize() {
694
- const config = await loadNotificationConfig();
695
- this.endpoint = config.cloudEndpoint || DEFAULT_CLOUD_ENDPOINT;
696
- this.deviceToken = config.deviceToken;
697
- }
698
- /**
699
- * Set the cloud endpoint
700
- */
701
- setEndpoint(endpoint) {
702
- this.endpoint = endpoint;
703
- }
704
- /**
705
- * Set the device token
706
- */
707
- setDeviceToken(token) {
708
- this.deviceToken = token;
709
- }
710
- // ==========================================================================
711
- // Device Registration
712
- // ==========================================================================
713
- /**
714
- * Register this device with the cloud service
715
- */
716
- async registerDevice(name) {
717
- const deviceInfo = getDeviceInfo();
718
- const config = await loadNotificationConfig();
719
- const channelsArray = this.convertChannelsToArray(config.channels);
720
- const request = {
721
- name: name || deviceInfo.name,
722
- platform: deviceInfo.platform,
723
- version: "1.0.0",
724
- // Static version for cloud client
725
- config: {
726
- channels: channelsArray,
727
- threshold: config.threshold
728
- }
729
- };
730
- const response = await this.request(
731
- "/device/register",
732
- {
733
- method: "POST",
734
- body: JSON.stringify(request)
735
- }
736
- );
737
- if (response.success && response.data) {
738
- await updateNotificationConfig({
739
- deviceToken: response.data.token
740
- });
741
- this.deviceToken = response.data.token;
742
- return response.data;
743
- }
744
- throw new Error(response.error || "Failed to register device");
745
- }
746
- /**
747
- * Get device info from cloud service
748
- */
749
- async getDeviceInfo() {
750
- const response = await this.request(
751
- "/device/info",
752
- { method: "GET" }
753
- );
754
- if (response.success && response.data) {
755
- return response.data;
756
- }
757
- throw new Error(response.error || "Failed to get device info");
758
- }
759
- /**
760
- * Update device channels on cloud service
761
- */
762
- async updateChannels(channels) {
763
- const channelsArray = this.convertChannelsToArray(channels);
764
- const response = await this.request(
765
- "/device/channels",
766
- {
767
- method: "PUT",
768
- body: JSON.stringify({ channels: channelsArray })
769
- }
770
- );
771
- if (!response.success) {
772
- throw new Error(response.error || "Failed to update channels");
773
- }
774
- }
775
- // ==========================================================================
776
- // Notification Sending
777
- // ==========================================================================
778
- /**
779
- * Send a notification through the cloud service
780
- */
781
- async sendNotification(message, channels) {
782
- const config = await loadNotificationConfig();
783
- const targetChannels = channels || this.getEnabledChannelsFromConfig(config.channels);
784
- if (targetChannels.length === 0) {
785
- return [];
786
- }
787
- const title = message.title || this.generateTitle(message.type);
788
- const body = this.generateBody(message);
789
- const response = await this.request(
790
- "/notify",
791
- {
792
- method: "POST",
793
- body: JSON.stringify({
794
- type: message.type,
795
- title,
796
- body,
797
- task: message.task,
798
- channels: targetChannels,
799
- actions: message.actions,
800
- priority: message.priority
801
- })
802
- }
803
- );
804
- if (response.success && response.data) {
805
- return response.data.results;
806
- }
807
- return targetChannels.map((channel) => ({
808
- success: false,
809
- channel,
810
- sentAt: /* @__PURE__ */ new Date(),
811
- error: response.error || "Failed to send notification"
812
- }));
813
- }
814
- /**
815
- * Send a test notification
816
- */
817
- async sendTestNotification() {
818
- const response = await this.request(
819
- "/notify/test",
820
- { method: "POST" }
821
- );
822
- if (response.success && response.data) {
823
- return response.data.results;
824
- }
825
- throw new Error(response.error || "Failed to send test notification");
826
- }
827
- // ==========================================================================
828
- // Reply Polling
829
- // ==========================================================================
830
- /**
831
- * Start polling for replies
832
- *
833
- * @param onReply - Callback when a reply is received
834
- * @param onError - Callback when an error occurs
835
- */
836
- startPolling(onReply, onError) {
837
- if (this.isPolling) {
838
- return;
839
- }
840
- this.isPolling = true;
841
- this.pollLoop(onReply, onError);
842
- }
843
- /**
844
- * Stop polling for replies
845
- */
846
- stopPolling() {
847
- this.isPolling = false;
848
- if (this.pollAbortController) {
849
- this.pollAbortController.abort();
850
- this.pollAbortController = null;
851
- }
852
- }
853
- /**
854
- * Poll loop for replies
855
- */
856
- async pollLoop(onReply, onError) {
857
- while (this.isPolling) {
858
- try {
859
- const reply = await this.pollForReply();
860
- if (reply) {
861
- onReply(reply);
862
- }
863
- } catch (error) {
864
- if (error instanceof Error && error.name === "AbortError") {
865
- break;
866
- }
867
- onError?.(error instanceof Error ? error : new Error(String(error)));
868
- await this.sleep(5e3);
869
- }
870
- }
871
- }
872
- /**
873
- * Poll for a single reply (long-polling)
874
- */
875
- async pollForReply() {
876
- this.pollAbortController = new AbortController();
877
- try {
878
- const response = await this.request(
879
- "/reply/poll",
880
- {
881
- method: "GET",
882
- signal: this.pollAbortController.signal,
883
- timeout: POLL_TIMEOUT
884
- }
885
- );
886
- if (response.success && response.data?.reply) {
887
- return {
888
- ...response.data.reply,
889
- timestamp: new Date(response.data.reply.timestamp)
890
- };
891
- }
892
- return null;
893
- } finally {
894
- this.pollAbortController = null;
895
- }
896
- }
897
- /**
898
- * Get reply for a specific notification
899
- */
900
- async getReply(notificationId) {
901
- const response = await this.request(
902
- `/reply/${notificationId}`,
903
- { method: "GET" }
904
- );
905
- if (response.success && response.data?.reply) {
906
- return {
907
- ...response.data.reply,
908
- timestamp: new Date(response.data.reply.timestamp)
909
- };
910
- }
911
- return null;
912
- }
913
- // ==========================================================================
914
- // HTTP Request Helper
915
- // ==========================================================================
916
- /**
917
- * Make an HTTP request to the cloud service
918
- */
919
- async request(path, options) {
920
- const url = `${this.endpoint}${path}`;
921
- const timeout = options.timeout || REQUEST_TIMEOUT;
922
- const timeoutController = new AbortController();
923
- const timeoutId = setTimeout(() => timeoutController.abort(), timeout);
924
- try {
925
- const response = await fetch(url, {
926
- method: options.method,
927
- headers: {
928
- "Content-Type": "application/json",
929
- "X-Device-Token": this.deviceToken
930
- },
931
- body: options.body,
932
- signal: options.signal || timeoutController.signal
933
- });
934
- clearTimeout(timeoutId);
935
- const data = await response.json();
936
- if (!response.ok) {
937
- return {
938
- success: false,
939
- error: data.error || `HTTP ${response.status}: ${response.statusText}`,
940
- code: data.code
941
- };
942
- }
943
- return data;
944
- } catch (error) {
945
- clearTimeout(timeoutId);
946
- if (error instanceof Error) {
947
- if (error.name === "AbortError") {
948
- throw error;
949
- }
950
- return {
951
- success: false,
952
- error: error.message,
953
- code: "NETWORK_ERROR"
954
- };
955
- }
956
- return {
957
- success: false,
958
- error: String(error),
959
- code: "UNKNOWN_ERROR"
960
- };
961
- }
962
- }
963
- // ==========================================================================
964
- // Utility Methods
965
- // ==========================================================================
966
- /**
967
- * Get enabled channels from config
968
- */
969
- getEnabledChannelsFromConfig(channels) {
970
- const enabledChannels = [];
971
- for (const [name, channelConfig] of Object.entries(channels)) {
972
- if (channelConfig?.enabled) {
973
- enabledChannels.push(name);
974
- }
975
- }
976
- return enabledChannels;
977
- }
978
- /**
979
- * Sleep for a specified duration
980
- */
981
- sleep(ms) {
982
- return new Promise((resolve) => setTimeout(resolve, ms));
983
- }
984
- /**
985
- * Convert channels from object format to array format
986
- *
987
- * Converts from: { feishu: { enabled: true, webhookUrl: "..." } }
988
- * To: [{ type: "feishu", enabled: true, config: { webhookUrl: "..." } }]
989
- */
990
- convertChannelsToArray(channels) {
991
- const result = [];
992
- for (const [channelType, channelData] of Object.entries(channels)) {
993
- if (channelData && typeof channelData === "object") {
994
- const { enabled, ...config } = channelData;
995
- result.push({
996
- type: channelType,
997
- enabled: Boolean(enabled),
998
- config
999
- });
1000
- }
1001
- }
1002
- return result;
1003
- }
1004
- /**
1005
- * Generate notification title based on type
1006
- */
1007
- generateTitle(type) {
1008
- const titles = {
1009
- task_started: "Task Started",
1010
- task_progress: "Task Progress",
1011
- task_completed: "Task Completed",
1012
- task_failed: "Task Failed",
1013
- task_cancelled: "Task Cancelled",
1014
- system: "System Notification"
1015
- };
1016
- return titles[type] || "Notification";
1017
- }
1018
- /**
1019
- * Generate notification body from message
1020
- */
1021
- generateBody(message) {
1022
- const { task } = message;
1023
- const lines = [];
1024
- lines.push(`**Task**: ${task.description}`);
1025
- lines.push(`**Status**: ${task.status}`);
1026
- if (task.duration) {
1027
- const minutes = Math.floor(task.duration / 6e4);
1028
- const seconds = Math.floor(task.duration % 6e4 / 1e3);
1029
- lines.push(`**Duration**: ${minutes}m ${seconds}s`);
1030
- }
1031
- if (task.result) {
1032
- lines.push(`**Result**: ${task.result}`);
1033
- }
1034
- if (task.error) {
1035
- lines.push(`**Error**: ${task.error}`);
1036
- }
1037
- return lines.join("\n");
1038
- }
1039
- /**
1040
- * Reset the singleton instance (for testing)
1041
- */
1042
- static resetInstance() {
1043
- if (CloudClient.instance) {
1044
- CloudClient.instance.stopPolling();
1045
- CloudClient.instance = null;
1046
- }
1047
- }
1048
- }
1049
-
1050
- async function notificationCommand(action = "menu", args) {
1051
- switch (action) {
1052
- case "config":
1053
- case "configure":
1054
- await runConfigWizard();
1055
- break;
1056
- case "status":
1057
- await showStatus();
1058
- break;
1059
- case "test":
1060
- await sendTestNotification();
1061
- break;
1062
- case "enable":
1063
- await enableNotifications();
1064
- console.log(a.green(`\u2705 ${i18n.t("notification:status.enabled")}`));
1065
- break;
1066
- case "disable":
1067
- await disableNotifications();
1068
- console.log(a.yellow(`\u23F8\uFE0F ${i18n.t("notification:status.disabled")}`));
1069
- break;
1070
- case "channels":
1071
- await manageChannels();
1072
- break;
1073
- case "threshold":
1074
- await configureThreshold();
1075
- break;
1076
- case "bind":
1077
- console.log(a.yellow(i18n.t("notification:cloud.migrateToRemoteSetup")));
1078
- await handleBind(args?.[0]);
1079
- break;
1080
- case "unbind":
1081
- await handleUnbind();
1082
- break;
1083
- case "cloud-status":
1084
- await showCloudStatus();
1085
- break;
1086
- case "local-config":
1087
- await configureLocalNotification();
1088
- break;
1089
- case "local-test":
1090
- await testLocalNotification();
1091
- break;
1092
- case "menu":
1093
- default:
1094
- await showNotificationMenu();
1095
- break;
1096
- }
1097
- }
1098
- async function showNotificationMenu() {
1099
- const config = await loadNotificationConfig();
1100
- const enabledChannels = await getEnabledChannels();
1101
- const cloudBound = isDeviceBound();
1102
- console.log("");
1103
- console.log(a.bold.cyan(i18n.t("notification:menu.title")));
1104
- console.log("");
1105
- const statusText = config.enabled ? a.green(i18n.t("notification:status.enabled")) : a.yellow(i18n.t("notification:status.disabled"));
1106
- console.log(` ${a.dim(i18n.t("notification:menu.statusLabel"))} ${statusText}`);
1107
- const cloudStatusText = cloudBound ? a.green(i18n.t("notification:cloud.bound")) : a.yellow(i18n.t("notification:cloud.notBound"));
1108
- console.log(` ${a.dim(i18n.t("notification:cloud.statusLabel"))} ${cloudStatusText}`);
1109
- if (enabledChannels.length > 0) {
1110
- const channelNames = enabledChannels.map((ch) => i18n.t(`notification:channels.${ch}`)).join(", ");
1111
- console.log(` ${a.dim(i18n.t("notification:menu.channelsLabel"))} ${channelNames}`);
1112
- } else {
1113
- console.log(` ${a.dim(i18n.t("notification:menu.channelsLabel"))} ${a.yellow(i18n.t("notification:channels.noChannels"))}`);
1114
- }
1115
- console.log(` ${a.dim(i18n.t("notification:menu.thresholdLabel"))} ${config.threshold} ${i18n.t("notification:config.threshold.minutes", { count: config.threshold })}`);
1116
- console.log("");
1117
- const choices = [];
1118
- if (!cloudBound) {
1119
- choices.push({ name: `\u{1F517} ${i18n.t("notification:cloud.bindDevice")}`, value: "bind" });
1120
- } else {
1121
- choices.push({ name: `\u2601\uFE0F ${i18n.t("notification:cloud.viewStatus")}`, value: "cloud-status" });
1122
- }
1123
- choices.push({
1124
- name: config.enabled ? `\u23F8\uFE0F ${i18n.t("notification:menu.disable")}` : `\u25B6\uFE0F ${i18n.t("notification:menu.enable")}`,
1125
- value: config.enabled ? "disable" : "enable"
1126
- });
1127
- choices.push(
1128
- { name: `\u2699\uFE0F ${i18n.t("notification:menu.configWizard")}`, value: "config" },
1129
- { name: `\u{1F4F1} ${i18n.t("notification:menu.manageChannels")}`, value: "channels" },
1130
- { name: `\u{1F514} ${i18n.t("notification:local.menuTitle")}`, value: "local-config" },
1131
- { name: `\u23F1\uFE0F ${i18n.t("notification:menu.setThreshold")}`, value: "threshold" },
1132
- { name: `\u{1F4CA} ${i18n.t("notification:menu.viewStatus")}`, value: "status" },
1133
- { name: `\u{1F9EA} ${i18n.t("notification:menu.sendTest")}`, value: "test" }
1134
- );
1135
- if (cloudBound) {
1136
- choices.push({ name: `\u{1F513} ${i18n.t("notification:cloud.unbindDevice")}`, value: "unbind" });
1137
- }
1138
- choices.push({ name: `\u2190 ${i18n.t("notification:menu.back")}`, value: "back" });
1139
- const { action } = await inquirer.prompt([{
1140
- type: "list",
1141
- name: "action",
1142
- message: i18n.t("notification:menu.selectAction"),
1143
- choices
1144
- }]);
1145
- if (action === "back") {
1146
- return;
1147
- }
1148
- await notificationCommand(action);
1149
- }
1150
- async function runConfigWizard() {
1151
- console.log("");
1152
- console.log(a.bold.cyan(i18n.t("notification:config.wizard.title")));
1153
- console.log(a.dim(i18n.t("notification:config.wizard.welcome")));
1154
- console.log("");
1155
- console.log(a.yellow(i18n.t("notification:config.wizard.step1")));
1156
- const config = await initializeNotificationConfig();
1157
- console.log(a.green(i18n.t("notification:config.wizard.tokenGenerated", { token: maskToken(config.deviceToken) })));
1158
- console.log("");
1159
- console.log(a.yellow(i18n.t("notification:config.wizard.step2")));
1160
- const channels = await selectChannels();
1161
- console.log("");
1162
- if (channels.length > 0) {
1163
- console.log(a.yellow(i18n.t("notification:config.wizard.step3")));
1164
- for (const channel of channels) {
1165
- await configureChannel(channel);
1166
- }
1167
- console.log("");
1168
- }
1169
- console.log(a.yellow(i18n.t("notification:config.wizard.step4")));
1170
- await configureThreshold();
1171
- console.log("");
1172
- console.log(a.yellow(i18n.t("notification:config.wizard.step5")));
1173
- await updateNotificationConfig({ enabled: true });
1174
- const { shouldTest } = await inquirer.prompt([{
1175
- type: "confirm",
1176
- name: "shouldTest",
1177
- message: "\u662F\u5426\u53D1\u9001\u6D4B\u8BD5\u901A\u77E5?",
1178
- default: true
1179
- }]);
1180
- if (shouldTest) {
1181
- await sendTestNotification();
1182
- }
1183
- console.log("");
1184
- console.log(a.bold.green(i18n.t("notification:config.wizard.complete")));
1185
- console.log("");
1186
- }
1187
- async function selectChannels() {
1188
- const choices = [
1189
- { name: `\u{1F4F1} ${i18n.t("notification:channels.feishu")}`, value: "feishu" },
1190
- { name: `\u{1F4AC} ${i18n.t("notification:channels.wechat")}`, value: "wechat" },
1191
- { name: `\u{1F4E7} ${i18n.t("notification:channels.email")}`, value: "email" },
1192
- { name: `\u{1F4F2} ${i18n.t("notification:channels.sms")}`, value: "sms" }
1193
- ];
1194
- const selected = [];
1195
- for (const choice of choices) {
1196
- const { enable } = await inquirer.prompt([{
1197
- type: "confirm",
1198
- name: "enable",
1199
- message: `\u542F\u7528 ${choice.name}?`,
1200
- default: false
1201
- }]);
1202
- if (enable) {
1203
- selected.push(choice.value);
1204
- }
1205
- }
1206
- return selected;
1207
- }
1208
- async function configureChannel(channel) {
1209
- console.log("");
1210
- console.log(a.green(`\u914D\u7F6E ${i18n.t(`notification:channels.${channel}`)}:`));
1211
- switch (channel) {
1212
- case "feishu":
1213
- await configureFeishu();
1214
- break;
1215
- case "wechat":
1216
- await configureWechat();
1217
- break;
1218
- case "email":
1219
- await configureEmail();
1220
- break;
1221
- case "sms":
1222
- await configureSms();
1223
- break;
1224
- }
1225
- }
1226
- async function configureFeishu() {
1227
- const { webhookUrl } = await inquirer.prompt([{
1228
- type: "input",
1229
- name: "webhookUrl",
1230
- message: i18n.t("notification:feishu.webhookUrl"),
1231
- validate: (value) => {
1232
- if (!value.startsWith("https://")) {
1233
- return i18n.t("notification:errors.invalidWebhook");
1234
- }
1235
- return true;
1236
- }
1237
- }]);
1238
- const { secret } = await inquirer.prompt([{
1239
- type: "input",
1240
- name: "secret",
1241
- message: `${i18n.t("notification:feishu.secret")} (\u53EF\u9009\uFF0C\u76F4\u63A5\u56DE\u8F66\u8DF3\u8FC7):`
1242
- }]);
1243
- const config = {
1244
- enabled: true,
1245
- webhookUrl,
1246
- ...secret && { secret }
1247
- };
1248
- await enableChannel("feishu", config);
1249
- console.log(a.green(`\u2705 ${i18n.t("notification:channels.feishu")} ${i18n.t("notification:status.configured")}`));
1250
- }
1251
- async function configureWechat() {
1252
- const { corpId } = await inquirer.prompt([{
1253
- type: "input",
1254
- name: "corpId",
1255
- message: i18n.t("notification:wechat.corpId"),
1256
- validate: (value) => !!value || i18n.t("notification:errors.invalidWebhook")
1257
- }]);
1258
- const { agentId } = await inquirer.prompt([{
1259
- type: "input",
1260
- name: "agentId",
1261
- message: i18n.t("notification:wechat.agentId"),
1262
- validate: (value) => !!value || i18n.t("notification:errors.invalidWebhook")
1263
- }]);
1264
- const { secret } = await inquirer.prompt([{
1265
- type: "input",
1266
- name: "secret",
1267
- message: i18n.t("notification:wechat.secret"),
1268
- validate: (value) => !!value || i18n.t("notification:errors.invalidWebhook")
1269
- }]);
1270
- const config = {
1271
- enabled: true,
1272
- corpId,
1273
- agentId,
1274
- secret
1275
- };
1276
- await enableChannel("wechat", config);
1277
- console.log(a.green(`\u2705 ${i18n.t("notification:channels.wechat")} ${i18n.t("notification:status.configured")}`));
1278
- }
1279
- async function configureEmail() {
1280
- const { address } = await inquirer.prompt([{
1281
- type: "input",
1282
- name: "address",
1283
- message: i18n.t("notification:email.address"),
1284
- validate: (value) => {
1285
- if (!/^[^\s@]+@[^\s@][^\s.@]*\.[^\s@]+$/.test(value)) {
1286
- return i18n.t("notification:errors.invalidEmail");
1287
- }
1288
- return true;
1289
- }
1290
- }]);
1291
- const config = {
1292
- enabled: true,
1293
- address
1294
- };
1295
- await enableChannel("email", config);
1296
- console.log(a.green(`\u2705 ${i18n.t("notification:channels.email")} ${i18n.t("notification:status.configured")}`));
1297
- }
1298
- async function configureSms() {
1299
- const { phone } = await inquirer.prompt([{
1300
- type: "input",
1301
- name: "phone",
1302
- message: i18n.t("notification:sms.phone"),
1303
- validate: (value) => {
1304
- if (!/^\d{10,15}$/.test(value.replace(/\D/g, ""))) {
1305
- return i18n.t("notification:errors.invalidPhone");
1306
- }
1307
- return true;
1308
- }
1309
- }]);
1310
- const { countryCode } = await inquirer.prompt([{
1311
- type: "input",
1312
- name: "countryCode",
1313
- message: i18n.t("notification:sms.countryCode"),
1314
- default: "+86"
1315
- }]);
1316
- const config = {
1317
- enabled: true,
1318
- phone,
1319
- countryCode
1320
- };
1321
- await enableChannel("sms", config);
1322
- console.log(a.green(`\u2705 ${i18n.t("notification:channels.sms")} ${i18n.t("notification:status.configured")}`));
1323
- }
1324
- async function manageChannels() {
1325
- const enabledChannels = await getEnabledChannels();
1326
- console.log("");
1327
- console.log(a.bold.cyan(i18n.t("notification:channels.title")));
1328
- console.log("");
1329
- if (enabledChannels.length === 0) {
1330
- console.log(a.yellow(i18n.t("notification:channels.noChannels")));
1331
- } else {
1332
- console.log(i18n.t("notification:channels.enabledCount", { count: enabledChannels.length }));
1333
- for (const channel of enabledChannels) {
1334
- console.log(` \u2705 ${i18n.t(`notification:channels.${channel}`)}`);
1335
- }
1336
- }
1337
- console.log("");
1338
- const { action } = await inquirer.prompt([{
1339
- type: "list",
1340
- name: "action",
1341
- message: "\u9009\u62E9\u64CD\u4F5C:",
1342
- choices: [
1343
- { name: "\u2795 \u6DFB\u52A0\u6E20\u9053", value: "add" },
1344
- { name: "\u2796 \u79FB\u9664\u6E20\u9053", value: "remove" },
1345
- { name: "\u2190 \u8FD4\u56DE", value: "back" }
1346
- ]
1347
- }]);
1348
- if (action === "back") {
1349
- return;
1350
- }
1351
- if (action === "add") {
1352
- const allChannels = ["feishu", "wechat", "email", "sms"];
1353
- const availableChannels = allChannels.filter((ch) => !enabledChannels.includes(ch));
1354
- if (availableChannels.length === 0) {
1355
- console.log(a.yellow("\u6240\u6709\u6E20\u9053\u90FD\u5DF2\u542F\u7528"));
1356
- return;
1357
- }
1358
- const { channel } = await inquirer.prompt([{
1359
- type: "list",
1360
- name: "channel",
1361
- message: "\u9009\u62E9\u8981\u6DFB\u52A0\u7684\u6E20\u9053:",
1362
- choices: availableChannels.map((ch) => ({
1363
- name: i18n.t(`notification:channels.${ch}`),
1364
- value: ch
1365
- }))
1366
- }]);
1367
- await configureChannel(channel);
1368
- } else if (action === "remove") {
1369
- if (enabledChannels.length === 0) {
1370
- console.log(a.yellow("\u6CA1\u6709\u5DF2\u542F\u7528\u7684\u6E20\u9053"));
1371
- return;
1372
- }
1373
- const { channel } = await inquirer.prompt([{
1374
- type: "list",
1375
- name: "channel",
1376
- message: "\u9009\u62E9\u8981\u79FB\u9664\u7684\u6E20\u9053:",
1377
- choices: enabledChannels.map((ch) => ({
1378
- name: i18n.t(`notification:channels.${ch}`),
1379
- value: ch
1380
- }))
1381
- }]);
1382
- await disableChannel(channel);
1383
- console.log(a.green(`\u2705 \u5DF2\u79FB\u9664 ${i18n.t(`notification:channels.${channel}`)}`));
1384
- }
1385
- }
1386
- async function configureThreshold() {
1387
- const config = await loadNotificationConfig();
1388
- console.log("");
1389
- console.log(a.dim(i18n.t("notification:config.threshold.description")));
1390
- console.log("");
1391
- const { threshold } = await inquirer.prompt([{
1392
- type: "list",
1393
- name: "threshold",
1394
- message: i18n.t("notification:config.threshold.title"),
1395
- choices: [
1396
- ...THRESHOLD_OPTIONS.map((opt) => ({
1397
- name: opt.label,
1398
- value: opt.value
1399
- })),
1400
- { name: i18n.t("notification:config.threshold.custom"), value: -1 }
1401
- ],
1402
- default: config.threshold
1403
- }]);
1404
- let finalThreshold = threshold;
1405
- if (threshold === -1) {
1406
- const { customValue } = await inquirer.prompt([{
1407
- type: "input",
1408
- name: "customValue",
1409
- message: "\u8F93\u5165\u81EA\u5B9A\u4E49\u9608\u503C\uFF08\u5206\u949F\uFF09:",
1410
- validate: (value) => {
1411
- const num = Number.parseInt(value, 10);
1412
- if (Number.isNaN(num) || num < 1) {
1413
- return "\u8BF7\u8F93\u5165\u5927\u4E8E 0 \u7684\u6570\u5B57";
1414
- }
1415
- return true;
1416
- }
1417
- }]);
1418
- finalThreshold = Number.parseInt(customValue, 10);
1419
- }
1420
- await setThreshold(finalThreshold);
1421
- console.log(a.green(`\u2705 \u9608\u503C\u5DF2\u8BBE\u7F6E\u4E3A ${finalThreshold} \u5206\u949F`));
1422
- }
1423
- async function showStatus() {
1424
- const summary = await getConfigSummary();
1425
- const validation = await validateCurrentConfig();
1426
- console.log("");
1427
- console.log(a.bold.cyan("\u{1F4CA} \u901A\u77E5\u7CFB\u7EDF\u72B6\u6001"));
1428
- console.log("");
1429
- const statusIcon = summary.enabled ? "\u2705" : "\u23F8\uFE0F";
1430
- const statusText = summary.enabled ? a.green(i18n.t("notification:status.enabled")) : a.yellow(i18n.t("notification:status.disabled"));
1431
- console.log(` ${statusIcon} \u72B6\u6001: ${statusText}`);
1432
- console.log(` \u{1F511} \u8BBE\u5907\u4EE4\u724C: ${a.dim(summary.deviceToken)}`);
1433
- console.log(` \u23F1\uFE0F \u9608\u503C: ${summary.threshold} \u5206\u949F`);
1434
- console.log("");
1435
- console.log(a.bold(" \u{1F4F1} \u901A\u77E5\u6E20\u9053:"));
1436
- if (summary.enabledChannels.length === 0) {
1437
- console.log(` ${a.yellow(i18n.t("notification:channels.noChannels"))}`);
1438
- } else {
1439
- for (const channel of summary.enabledChannels) {
1440
- console.log(` \u2705 ${i18n.t(`notification:channels.${channel}`)}`);
1441
- }
1442
- }
1443
- if (summary.quietHours.enabled) {
1444
- console.log("");
1445
- console.log(` \u{1F319} \u514D\u6253\u6270: ${summary.quietHours.hours}`);
1446
- }
1447
- if (!validation.valid) {
1448
- console.log("");
1449
- console.log(a.bold.red(" \u26A0\uFE0F \u914D\u7F6E\u95EE\u9898:"));
1450
- for (const error of validation.errors) {
1451
- console.log(` \u274C ${error.message}`);
1452
- }
1453
- }
1454
- if (validation.warnings.length > 0) {
1455
- console.log("");
1456
- console.log(a.bold.yellow(" \u26A0\uFE0F \u8B66\u544A:"));
1457
- for (const warning of validation.warnings) {
1458
- console.log(` \u26A0\uFE0F ${warning}`);
1459
- }
1460
- }
1461
- console.log("");
1462
- }
1463
- async function sendTestNotification() {
1464
- const enabledChannels = await getEnabledChannels();
1465
- if (enabledChannels.length === 0) {
1466
- console.log(a.yellow(i18n.t("notification:errors.noChannels")));
1467
- return;
1468
- }
1469
- console.log("");
1470
- console.log(a.green(i18n.t("notification:test.sending")));
1471
- try {
1472
- const client = CloudClient.getInstance();
1473
- await client.initialize();
1474
- const results = await client.sendTestNotification();
1475
- console.log("");
1476
- let hasSuccess = false;
1477
- let hasFailure = false;
1478
- for (const result of results) {
1479
- const channelName = i18n.t(`notification:channels.${result.channel}`);
1480
- if (result.success) {
1481
- console.log(a.green(`\u2705 ${channelName}: ${i18n.t("notification:test.success")}`));
1482
- hasSuccess = true;
1483
- } else {
1484
- console.log(a.red(`\u274C ${channelName}: ${result.error || i18n.t("notification:test.failed")}`));
1485
- hasFailure = true;
1486
- }
1487
- }
1488
- console.log("");
1489
- if (hasSuccess) {
1490
- console.log(a.dim(i18n.t("notification:test.checkDevice")));
1491
- }
1492
- if (hasFailure) {
1493
- console.log(a.yellow(i18n.t("notification:test.partialFailure")));
1494
- }
1495
- } catch (error) {
1496
- console.log("");
1497
- console.log(a.red(`\u274C ${i18n.t("notification:errors.sendFailed")}`));
1498
- if (error instanceof Error) {
1499
- console.log(a.dim(error.message));
1500
- }
1501
- console.log("");
1502
- console.log(a.yellow(i18n.t("notification:test.troubleshooting")));
1503
- console.log(a.dim(` 1. ${i18n.t("notification:test.checkConnection")}`));
1504
- console.log(a.dim(` 2. ${i18n.t("notification:test.checkConfig")}`));
1505
- console.log(a.dim(` 3. ${i18n.t("notification:test.checkToken")}`));
1506
- }
1507
- console.log("");
1508
- }
1509
- async function handleBind(code) {
1510
- console.log("");
1511
- console.log(a.bold.cyan(i18n.t("notification:cloud.bindTitle")));
1512
- console.log("");
1513
- if (isDeviceBound()) {
1514
- console.log(a.yellow(i18n.t("notification:cloud.alreadyBound")));
1515
- console.log("");
1516
- const { confirmRebind } = await inquirer.prompt([{
1517
- type: "confirm",
1518
- name: "confirmRebind",
1519
- message: i18n.t("notification:cloud.confirmRebind"),
1520
- default: false
1521
- }]);
1522
- if (!confirmRebind) {
1523
- return;
1524
- }
1525
- unbindDevice();
1526
- }
1527
- let bindingCode = code;
1528
- if (!bindingCode) {
1529
- console.log(a.dim(i18n.t("notification:cloud.bindInstructions")));
1530
- console.log("");
1531
- const { inputCode } = await inquirer.prompt([{
1532
- type: "input",
1533
- name: "inputCode",
1534
- message: i18n.t("notification:cloud.enterCode"),
1535
- validate: (value) => {
1536
- if (!value || value.trim().length === 0) {
1537
- return i18n.t("notification:cloud.codeRequired");
1538
- }
1539
- if (value.trim().length < 4) {
1540
- return i18n.t("notification:cloud.codeInvalid");
1541
- }
1542
- return true;
1543
- }
1544
- }]);
1545
- bindingCode = inputCode.trim();
1546
- }
1547
- console.log("");
1548
- console.log(a.green(i18n.t("notification:cloud.binding")));
1549
- try {
1550
- const result = await bindDevice(bindingCode);
1551
- if (result.success) {
1552
- console.log("");
1553
- console.log(a.green(`\u2705 ${i18n.t("notification:cloud.bindSuccess")}`));
1554
- console.log("");
1555
- console.log(a.dim(i18n.t("notification:cloud.deviceId", { id: result.data?.deviceId || "N/A" })));
1556
- console.log("");
1557
- const { sendTest } = await inquirer.prompt([{
1558
- type: "confirm",
1559
- name: "sendTest",
1560
- message: i18n.t("notification:cloud.sendTestAfterBind"),
1561
- default: true
1562
- }]);
1563
- if (sendTest) {
1564
- await sendCloudTestNotification();
1565
- }
1566
- } else {
1567
- console.log("");
1568
- console.log(a.red(`\u274C ${i18n.t("notification:cloud.bindFailed")}`));
1569
- console.log(a.dim(result.error || i18n.t("notification:cloud.unknownError")));
1570
- console.log("");
1571
- console.log(a.yellow(i18n.t("notification:cloud.bindTroubleshooting")));
1572
- console.log(a.dim(` 1. ${i18n.t("notification:cloud.checkCode")}`));
1573
- console.log(a.dim(` 2. ${i18n.t("notification:cloud.checkExpiry")}`));
1574
- console.log(a.dim(` 3. ${i18n.t("notification:cloud.checkNetwork")}`));
1575
- }
1576
- } catch (error) {
1577
- console.log("");
1578
- console.log(a.red(`\u274C ${i18n.t("notification:cloud.bindError")}`));
1579
- if (error instanceof Error) {
1580
- console.log(a.dim(error.message));
1581
- }
1582
- }
1583
- console.log("");
1584
- }
1585
- async function handleUnbind() {
1586
- console.log("");
1587
- if (!isDeviceBound()) {
1588
- console.log(a.yellow(i18n.t("notification:cloud.notBoundYet")));
1589
- console.log("");
1590
- return;
1591
- }
1592
- const { confirmUnbind } = await inquirer.prompt([{
1593
- type: "confirm",
1594
- name: "confirmUnbind",
1595
- message: i18n.t("notification:cloud.confirmUnbind"),
1596
- default: false
1597
- }]);
1598
- if (!confirmUnbind) {
1599
- console.log(a.dim(i18n.t("notification:cloud.unbindCancelled")));
1600
- console.log("");
1601
- return;
1602
- }
1603
- unbindDevice();
1604
- console.log(a.green(`\u2705 ${i18n.t("notification:cloud.unbindSuccess")}`));
1605
- console.log("");
1606
- }
1607
- async function showCloudStatus() {
1608
- console.log("");
1609
- console.log(a.bold.cyan(i18n.t("notification:cloud.statusTitle")));
1610
- console.log("");
1611
- const status = await getBindingStatus();
1612
- if (!status.bound) {
1613
- console.log(` ${a.yellow("\u26A0\uFE0F")} ${i18n.t("notification:cloud.notBound")}`);
1614
- console.log("");
1615
- console.log(a.dim(i18n.t("notification:cloud.bindHint")));
1616
- console.log("");
1617
- return;
1618
- }
1619
- console.log(` ${a.green("\u2705")} ${i18n.t("notification:cloud.bound")}`);
1620
- console.log("");
1621
- if (status.deviceId) {
1622
- console.log(` ${a.dim(i18n.t("notification:cloud.deviceIdLabel"))} ${status.deviceId}`);
1623
- }
1624
- if (status.deviceInfo) {
1625
- console.log(` ${a.dim(i18n.t("notification:cloud.deviceNameLabel"))} ${status.deviceInfo.name}`);
1626
- console.log(` ${a.dim(i18n.t("notification:cloud.platformLabel"))} ${status.deviceInfo.platform}`);
1627
- }
1628
- if (status.lastUsed) {
1629
- const lastUsedDate = new Date(status.lastUsed);
1630
- console.log(` ${a.dim(i18n.t("notification:cloud.lastUsedLabel"))} ${lastUsedDate.toLocaleString()}`);
1631
- }
1632
- console.log("");
1633
- }
1634
- async function sendCloudTestNotification() {
1635
- console.log("");
1636
- console.log(a.green(i18n.t("notification:cloud.sendingTest")));
1637
- try {
1638
- const result = await sendNotification({
1639
- title: i18n.t("notification:cloud.testTitle"),
1640
- body: i18n.t("notification:cloud.testBody"),
1641
- type: "success"
1642
- });
1643
- if (result.success) {
1644
- console.log(a.green(`\u2705 ${i18n.t("notification:cloud.testSuccess")}`));
1645
- console.log(a.dim(i18n.t("notification:cloud.checkPhone")));
1646
- } else {
1647
- console.log(a.red(`\u274C ${i18n.t("notification:cloud.testFailed")}`));
1648
- console.log(a.dim(result.error || i18n.t("notification:cloud.unknownError")));
1649
- }
1650
- } catch (error) {
1651
- console.log(a.red(`\u274C ${i18n.t("notification:cloud.testError")}`));
1652
- if (error instanceof Error) {
1653
- console.log(a.dim(error.message));
1654
- }
1655
- }
1656
- console.log("");
1657
- }
1658
- async function configureLocalNotification() {
1659
- const config = await loadLocalNotificationConfig();
1660
- const shortcutsAvailable = await isShortcutsAvailable();
1661
- console.log("");
1662
- console.log(a.bold.cyan(i18n.t("notification:local.title")));
1663
- console.log(a.dim(i18n.t("notification:local.description")));
1664
- console.log("");
1665
- console.log(a.bold(i18n.t("notification:local.currentStatus")));
1666
- if (shortcutsAvailable) {
1667
- const shortcutsStatus = config.shortcutName ? a.green(i18n.t("notification:status.enabled")) : a.yellow(i18n.t("notification:status.disabled"));
1668
- console.log(` \u{1F34E} ${i18n.t("notification:local.shortcuts.name")}: ${shortcutsStatus}`);
1669
- if (config.shortcutName) {
1670
- console.log(` ${a.dim(i18n.t("notification:local.shortcuts.currentShortcut", { name: config.shortcutName }))}`);
1671
- }
1672
- } else {
1673
- console.log(` \u{1F34E} ${i18n.t("notification:local.shortcuts.name")}: ${a.dim(i18n.t("notification:local.shortcuts.notAvailable"))}`);
1674
- }
1675
- const barkStatus = config.barkUrl ? a.green(i18n.t("notification:status.enabled")) : a.yellow(i18n.t("notification:status.disabled"));
1676
- console.log(` \u{1F4F1} ${i18n.t("notification:local.bark.name")}: ${barkStatus}`);
1677
- if (config.barkUrl) {
1678
- console.log(` ${a.dim(i18n.t("notification:local.bark.currentServer", { url: config.barkUrl }))}`);
1679
- }
1680
- console.log("");
1681
- const choices = [];
1682
- if (shortcutsAvailable) {
1683
- choices.push({
1684
- name: config.shortcutName ? `\u{1F34E} ${i18n.t("notification:local.shortcuts.configure")}` : `\u{1F34E} ${i18n.t("notification:local.shortcuts.enable")}`,
1685
- value: "shortcuts"
1686
- });
1687
- }
1688
- choices.push({
1689
- name: config.barkUrl ? `\u{1F4F1} ${i18n.t("notification:local.bark.configure")}` : `\u{1F4F1} ${i18n.t("notification:local.bark.enable")}`,
1690
- value: "bark"
1691
- });
1692
- choices.push(
1693
- { name: `\u{1F9EA} ${i18n.t("notification:local.testLocal")}`, value: "test" },
1694
- { name: `\u2190 ${i18n.t("notification:menu.back")}`, value: "back" }
1695
- );
1696
- const { action } = await inquirer.prompt([{
1697
- type: "list",
1698
- name: "action",
1699
- message: i18n.t("notification:menu.selectAction"),
1700
- choices
1701
- }]);
1702
- if (action === "back") {
1703
- return;
1704
- }
1705
- switch (action) {
1706
- case "shortcuts":
1707
- await configureShortcuts();
1708
- break;
1709
- case "bark":
1710
- await configureBark();
1711
- break;
1712
- case "test":
1713
- await testLocalNotification();
1714
- break;
1715
- }
1716
- }
1717
- async function configureShortcuts() {
1718
- console.log("");
1719
- console.log(a.bold.cyan(i18n.t("notification:local.shortcuts.title")));
1720
- console.log(a.dim(i18n.t("notification:local.shortcuts.description")));
1721
- console.log("");
1722
- console.log(a.dim(i18n.t("notification:local.shortcuts.scanning")));
1723
- const shortcuts = await listShortcuts();
1724
- if (shortcuts.length === 0) {
1725
- console.log(a.yellow(i18n.t("notification:local.shortcuts.noShortcuts")));
1726
- console.log(a.dim(i18n.t("notification:local.shortcuts.createHint")));
1727
- console.log("");
1728
- return;
1729
- }
1730
- console.log(a.green(i18n.t("notification:local.shortcuts.found", { count: shortcuts.length })));
1731
- console.log("");
1732
- const { shortcutName } = await inquirer.prompt([{
1733
- type: "list",
1734
- name: "shortcutName",
1735
- message: i18n.t("notification:local.shortcuts.selectShortcut"),
1736
- choices: [
1737
- ...shortcuts.map((s) => ({ name: s, value: s })),
1738
- { name: i18n.t("notification:local.shortcuts.enterManually"), value: "__manual__" },
1739
- { name: i18n.t("notification:local.shortcuts.disable"), value: "__disable__" }
1740
- ]
1741
- }]);
1742
- if (shortcutName === "__disable__") {
1743
- await saveLocalNotificationConfig({ shortcutName: "" });
1744
- console.log(a.yellow(`\u23F8\uFE0F ${i18n.t("notification:local.shortcuts.disabled")}`));
1745
- return;
1746
- }
1747
- let finalShortcutName = shortcutName;
1748
- if (shortcutName === "__manual__") {
1749
- const { manualName } = await inquirer.prompt([{
1750
- type: "input",
1751
- name: "manualName",
1752
- message: i18n.t("notification:local.shortcuts.enterName"),
1753
- validate: (value) => !!value.trim() || i18n.t("notification:errors.required")
1754
- }]);
1755
- finalShortcutName = manualName.trim();
1756
- }
1757
- await saveLocalNotificationConfig({ shortcutName: finalShortcutName });
1758
- console.log(a.green(`\u2705 ${i18n.t("notification:local.shortcuts.configured", { name: finalShortcutName })}`));
1759
- const { shouldTest } = await inquirer.prompt([{
1760
- type: "confirm",
1761
- name: "shouldTest",
1762
- message: i18n.t("notification:local.shortcuts.testNow"),
1763
- default: true
1764
- }]);
1765
- if (shouldTest) {
1766
- await testShortcutsNotification(finalShortcutName);
1767
- }
1768
- }
1769
- async function configureBark() {
1770
- console.log("");
1771
- console.log(a.bold.cyan(i18n.t("notification:local.bark.title")));
1772
- console.log(a.dim(i18n.t("notification:local.bark.description")));
1773
- console.log("");
1774
- const config = await loadLocalNotificationConfig();
1775
- const { action } = await inquirer.prompt([{
1776
- type: "list",
1777
- name: "action",
1778
- message: i18n.t("notification:menu.selectAction"),
1779
- choices: [
1780
- { name: i18n.t("notification:local.bark.configureServer"), value: "configure" },
1781
- { name: i18n.t("notification:local.bark.disable"), value: "disable" },
1782
- { name: `\u2190 ${i18n.t("notification:menu.back")}`, value: "back" }
1783
- ]
1784
- }]);
1785
- if (action === "back") {
1786
- return;
1787
- }
1788
- if (action === "disable") {
1789
- await saveLocalNotificationConfig({ barkUrl: "" });
1790
- console.log(a.yellow(`\u23F8\uFE0F ${i18n.t("notification:local.bark.disabled")}`));
1791
- return;
1792
- }
1793
- const { barkUrl } = await inquirer.prompt([{
1794
- type: "input",
1795
- name: "barkUrl",
1796
- message: i18n.t("notification:local.bark.enterUrl"),
1797
- default: config.barkUrl || "https://api.day.app/your-key",
1798
- validate: (value) => {
1799
- if (!isValidBarkUrl(value)) {
1800
- return i18n.t("notification:local.bark.invalidUrl");
1801
- }
1802
- return true;
1803
- }
1804
- }]);
1805
- await saveLocalNotificationConfig({ barkUrl });
1806
- console.log(a.green(`\u2705 ${i18n.t("notification:local.bark.configured")}`));
1807
- const { shouldTest } = await inquirer.prompt([{
1808
- type: "confirm",
1809
- name: "shouldTest",
1810
- message: i18n.t("notification:local.bark.testNow"),
1811
- default: true
1812
- }]);
1813
- if (shouldTest) {
1814
- await testBarkNotification(barkUrl);
1815
- }
1816
- }
1817
- async function testLocalNotification() {
1818
- const config = await loadLocalNotificationConfig();
1819
- console.log("");
1820
- console.log(a.green(i18n.t("notification:local.testing")));
1821
- console.log("");
1822
- let hasAnyEnabled = false;
1823
- if (config.shortcutName) {
1824
- hasAnyEnabled = true;
1825
- await testShortcutsNotification(config.shortcutName);
1826
- }
1827
- if (config.barkUrl) {
1828
- hasAnyEnabled = true;
1829
- await testBarkNotification(config.barkUrl);
1830
- }
1831
- if (!hasAnyEnabled) {
1832
- console.log(a.yellow(i18n.t("notification:local.noLocalEnabled")));
1833
- console.log(a.dim(i18n.t("notification:local.configureFirst")));
1834
- }
1835
- console.log("");
1836
- }
1837
- async function testShortcutsNotification(shortcutName) {
1838
- console.log(a.dim(`${i18n.t("notification:local.shortcuts.testing", { name: shortcutName })}...`));
1839
- try {
1840
- const service = await getLocalNotificationService();
1841
- await service.sendShortcutNotification(shortcutName, {
1842
- title: i18n.t("notification:local.testTitle"),
1843
- body: i18n.t("notification:local.testBody")
1844
- });
1845
- console.log(a.green(`\u2705 ${i18n.t("notification:local.shortcuts.name")}: ${i18n.t("notification:test.success")}`));
1846
- } catch (error) {
1847
- console.log(a.red(`\u274C ${i18n.t("notification:local.shortcuts.name")}: ${error instanceof Error ? error.message : i18n.t("notification:test.failed")}`));
1848
- }
1849
- }
1850
- async function testBarkNotification(barkUrl) {
1851
- console.log(a.dim(`${i18n.t("notification:local.bark.testing")}...`));
1852
- try {
1853
- const service = await getLocalNotificationService();
1854
- await service.sendBarkNotification(barkUrl, {
1855
- title: i18n.t("notification:local.testTitle"),
1856
- body: i18n.t("notification:local.testBody")
1857
- });
1858
- console.log(a.green(`\u2705 ${i18n.t("notification:local.bark.name")}: ${i18n.t("notification:test.success")}`));
1859
- } catch (error) {
1860
- console.log(a.red(`\u274C ${i18n.t("notification:local.bark.name")}: ${error instanceof Error ? error.message : i18n.t("notification:test.failed")}`));
1861
- }
1862
- }
1863
-
1864
- export { notificationCommand };