@jonit-dev/night-watch-cli 1.7.18 → 1.7.20

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 (274) hide show
  1. package/bin/night-watch.mjs +1 -1
  2. package/dist/src/cli.js +13 -4
  3. package/dist/src/cli.js.map +1 -1
  4. package/dist/src/server/index.d.ts.map +1 -1
  5. package/dist/src/server/index.js +14 -22
  6. package/dist/src/server/index.js.map +1 -1
  7. package/dist/src/slack/client.d.ts +4 -0
  8. package/dist/src/slack/client.d.ts.map +1 -1
  9. package/dist/src/slack/client.js +6 -0
  10. package/dist/src/slack/client.js.map +1 -1
  11. package/dist/src/slack/interaction-listener.d.ts +2 -3
  12. package/dist/src/slack/interaction-listener.d.ts.map +1 -1
  13. package/dist/src/slack/interaction-listener.js +30 -14
  14. package/dist/src/slack/interaction-listener.js.map +1 -1
  15. package/dist/src/storage/repositories/sqlite/agent-persona-repository.js +1 -1
  16. package/dist/src/storage/repositories/sqlite/agent-persona-repository.js.map +1 -1
  17. package/package.json +1 -1
  18. package/web/dist/assets/index-DOzZY27d.js +473 -0
  19. package/web/dist/assets/index-w6Q6gxCS.css +1 -0
  20. package/web/dist/index.html +2 -2
  21. package/dist/board/factory.d.ts +0 -3
  22. package/dist/board/factory.d.ts.map +0 -1
  23. package/dist/board/factory.js +0 -10
  24. package/dist/board/factory.js.map +0 -1
  25. package/dist/board/providers/github-graphql.d.ts +0 -16
  26. package/dist/board/providers/github-graphql.d.ts.map +0 -1
  27. package/dist/board/providers/github-graphql.js +0 -43
  28. package/dist/board/providers/github-graphql.js.map +0 -1
  29. package/dist/board/providers/github-projects.d.ts +0 -51
  30. package/dist/board/providers/github-projects.d.ts.map +0 -1
  31. package/dist/board/providers/github-projects.js +0 -672
  32. package/dist/board/providers/github-projects.js.map +0 -1
  33. package/dist/board/types.d.ts +0 -60
  34. package/dist/board/types.d.ts.map +0 -1
  35. package/dist/board/types.js +0 -4
  36. package/dist/board/types.js.map +0 -1
  37. package/dist/cli.d.ts +0 -3
  38. package/dist/cli.d.ts.map +0 -1
  39. package/dist/cli.js +0 -80
  40. package/dist/cli.js.map +0 -1
  41. package/dist/commands/board.d.ts +0 -9
  42. package/dist/commands/board.d.ts.map +0 -1
  43. package/dist/commands/board.js +0 -294
  44. package/dist/commands/board.js.map +0 -1
  45. package/dist/commands/cancel.d.ts +0 -46
  46. package/dist/commands/cancel.d.ts.map +0 -1
  47. package/dist/commands/cancel.js +0 -241
  48. package/dist/commands/cancel.js.map +0 -1
  49. package/dist/commands/dashboard/tab-actions.d.ts +0 -10
  50. package/dist/commands/dashboard/tab-actions.d.ts.map +0 -1
  51. package/dist/commands/dashboard/tab-actions.js +0 -245
  52. package/dist/commands/dashboard/tab-actions.js.map +0 -1
  53. package/dist/commands/dashboard/tab-config.d.ts +0 -21
  54. package/dist/commands/dashboard/tab-config.d.ts.map +0 -1
  55. package/dist/commands/dashboard/tab-config.js +0 -829
  56. package/dist/commands/dashboard/tab-config.js.map +0 -1
  57. package/dist/commands/dashboard/tab-logs.d.ts +0 -10
  58. package/dist/commands/dashboard/tab-logs.d.ts.map +0 -1
  59. package/dist/commands/dashboard/tab-logs.js +0 -178
  60. package/dist/commands/dashboard/tab-logs.js.map +0 -1
  61. package/dist/commands/dashboard/tab-schedules.d.ts +0 -21
  62. package/dist/commands/dashboard/tab-schedules.d.ts.map +0 -1
  63. package/dist/commands/dashboard/tab-schedules.js +0 -304
  64. package/dist/commands/dashboard/tab-schedules.js.map +0 -1
  65. package/dist/commands/dashboard/tab-status.d.ts +0 -32
  66. package/dist/commands/dashboard/tab-status.d.ts.map +0 -1
  67. package/dist/commands/dashboard/tab-status.js +0 -421
  68. package/dist/commands/dashboard/tab-status.js.map +0 -1
  69. package/dist/commands/dashboard/types.d.ts +0 -43
  70. package/dist/commands/dashboard/types.d.ts.map +0 -1
  71. package/dist/commands/dashboard/types.js +0 -5
  72. package/dist/commands/dashboard/types.js.map +0 -1
  73. package/dist/commands/dashboard.d.ts +0 -11
  74. package/dist/commands/dashboard.d.ts.map +0 -1
  75. package/dist/commands/dashboard.js +0 -239
  76. package/dist/commands/dashboard.js.map +0 -1
  77. package/dist/commands/doctor.d.ts +0 -16
  78. package/dist/commands/doctor.d.ts.map +0 -1
  79. package/dist/commands/doctor.js +0 -202
  80. package/dist/commands/doctor.js.map +0 -1
  81. package/dist/commands/history.d.ts +0 -7
  82. package/dist/commands/history.d.ts.map +0 -1
  83. package/dist/commands/history.js +0 -56
  84. package/dist/commands/history.js.map +0 -1
  85. package/dist/commands/init.d.ts +0 -25
  86. package/dist/commands/init.d.ts.map +0 -1
  87. package/dist/commands/init.js +0 -534
  88. package/dist/commands/init.js.map +0 -1
  89. package/dist/commands/install.d.ts +0 -48
  90. package/dist/commands/install.d.ts.map +0 -1
  91. package/dist/commands/install.js +0 -303
  92. package/dist/commands/install.js.map +0 -1
  93. package/dist/commands/logs.d.ts +0 -15
  94. package/dist/commands/logs.d.ts.map +0 -1
  95. package/dist/commands/logs.js +0 -104
  96. package/dist/commands/logs.js.map +0 -1
  97. package/dist/commands/prd-state.d.ts +0 -12
  98. package/dist/commands/prd-state.d.ts.map +0 -1
  99. package/dist/commands/prd-state.js +0 -47
  100. package/dist/commands/prd-state.js.map +0 -1
  101. package/dist/commands/prd.d.ts +0 -24
  102. package/dist/commands/prd.d.ts.map +0 -1
  103. package/dist/commands/prd.js +0 -283
  104. package/dist/commands/prd.js.map +0 -1
  105. package/dist/commands/prds.d.ts +0 -13
  106. package/dist/commands/prds.d.ts.map +0 -1
  107. package/dist/commands/prds.js +0 -196
  108. package/dist/commands/prds.js.map +0 -1
  109. package/dist/commands/prs.d.ts +0 -14
  110. package/dist/commands/prs.d.ts.map +0 -1
  111. package/dist/commands/prs.js +0 -106
  112. package/dist/commands/prs.js.map +0 -1
  113. package/dist/commands/qa.d.ts +0 -30
  114. package/dist/commands/qa.d.ts.map +0 -1
  115. package/dist/commands/qa.js +0 -159
  116. package/dist/commands/qa.js.map +0 -1
  117. package/dist/commands/retry.d.ts +0 -9
  118. package/dist/commands/retry.d.ts.map +0 -1
  119. package/dist/commands/retry.js +0 -72
  120. package/dist/commands/retry.js.map +0 -1
  121. package/dist/commands/review.d.ts +0 -35
  122. package/dist/commands/review.d.ts.map +0 -1
  123. package/dist/commands/review.js +0 -252
  124. package/dist/commands/review.js.map +0 -1
  125. package/dist/commands/run.d.ts +0 -61
  126. package/dist/commands/run.d.ts.map +0 -1
  127. package/dist/commands/run.js +0 -364
  128. package/dist/commands/run.js.map +0 -1
  129. package/dist/commands/serve.d.ts +0 -7
  130. package/dist/commands/serve.d.ts.map +0 -1
  131. package/dist/commands/serve.js +0 -27
  132. package/dist/commands/serve.js.map +0 -1
  133. package/dist/commands/slice.d.ts +0 -26
  134. package/dist/commands/slice.d.ts.map +0 -1
  135. package/dist/commands/slice.js +0 -175
  136. package/dist/commands/slice.js.map +0 -1
  137. package/dist/commands/state.d.ts +0 -8
  138. package/dist/commands/state.d.ts.map +0 -1
  139. package/dist/commands/state.js +0 -56
  140. package/dist/commands/state.js.map +0 -1
  141. package/dist/commands/status.d.ts +0 -14
  142. package/dist/commands/status.d.ts.map +0 -1
  143. package/dist/commands/status.js +0 -147
  144. package/dist/commands/status.js.map +0 -1
  145. package/dist/commands/uninstall.d.ts +0 -25
  146. package/dist/commands/uninstall.d.ts.map +0 -1
  147. package/dist/commands/uninstall.js +0 -141
  148. package/dist/commands/uninstall.js.map +0 -1
  149. package/dist/commands/update.d.ts +0 -21
  150. package/dist/commands/update.d.ts.map +0 -1
  151. package/dist/commands/update.js +0 -87
  152. package/dist/commands/update.js.map +0 -1
  153. package/dist/config.d.ts +0 -23
  154. package/dist/config.d.ts.map +0 -1
  155. package/dist/config.js +0 -601
  156. package/dist/config.js.map +0 -1
  157. package/dist/constants.d.ts +0 -59
  158. package/dist/constants.d.ts.map +0 -1
  159. package/dist/constants.js +0 -110
  160. package/dist/constants.js.map +0 -1
  161. package/dist/server/index.d.ts +0 -23
  162. package/dist/server/index.d.ts.map +0 -1
  163. package/dist/server/index.js +0 -1074
  164. package/dist/server/index.js.map +0 -1
  165. package/dist/storage/json-state-migrator.d.ts +0 -24
  166. package/dist/storage/json-state-migrator.d.ts.map +0 -1
  167. package/dist/storage/json-state-migrator.js +0 -197
  168. package/dist/storage/json-state-migrator.js.map +0 -1
  169. package/dist/storage/repositories/index.d.ts +0 -23
  170. package/dist/storage/repositories/index.d.ts.map +0 -1
  171. package/dist/storage/repositories/index.js +0 -37
  172. package/dist/storage/repositories/index.js.map +0 -1
  173. package/dist/storage/repositories/interfaces.d.ts +0 -37
  174. package/dist/storage/repositories/interfaces.d.ts.map +0 -1
  175. package/dist/storage/repositories/interfaces.js +0 -6
  176. package/dist/storage/repositories/interfaces.js.map +0 -1
  177. package/dist/storage/repositories/sqlite/execution-history-repository.d.ts +0 -21
  178. package/dist/storage/repositories/sqlite/execution-history-repository.d.ts.map +0 -1
  179. package/dist/storage/repositories/sqlite/execution-history-repository.js +0 -94
  180. package/dist/storage/repositories/sqlite/execution-history-repository.js.map +0 -1
  181. package/dist/storage/repositories/sqlite/prd-state-repository.d.ts +0 -17
  182. package/dist/storage/repositories/sqlite/prd-state-repository.d.ts.map +0 -1
  183. package/dist/storage/repositories/sqlite/prd-state-repository.js +0 -74
  184. package/dist/storage/repositories/sqlite/prd-state-repository.js.map +0 -1
  185. package/dist/storage/repositories/sqlite/project-registry-repository.d.ts +0 -16
  186. package/dist/storage/repositories/sqlite/project-registry-repository.d.ts.map +0 -1
  187. package/dist/storage/repositories/sqlite/project-registry-repository.js +0 -34
  188. package/dist/storage/repositories/sqlite/project-registry-repository.js.map +0 -1
  189. package/dist/storage/repositories/sqlite/roadmap-state-repository.d.ts +0 -14
  190. package/dist/storage/repositories/sqlite/roadmap-state-repository.d.ts.map +0 -1
  191. package/dist/storage/repositories/sqlite/roadmap-state-repository.js +0 -47
  192. package/dist/storage/repositories/sqlite/roadmap-state-repository.js.map +0 -1
  193. package/dist/storage/sqlite/client.d.ts +0 -23
  194. package/dist/storage/sqlite/client.d.ts.map +0 -1
  195. package/dist/storage/sqlite/client.js +0 -47
  196. package/dist/storage/sqlite/client.js.map +0 -1
  197. package/dist/storage/sqlite/migrations.d.ts +0 -11
  198. package/dist/storage/sqlite/migrations.d.ts.map +0 -1
  199. package/dist/storage/sqlite/migrations.js +0 -57
  200. package/dist/storage/sqlite/migrations.js.map +0 -1
  201. package/dist/templates/prd-template.d.ts +0 -11
  202. package/dist/templates/prd-template.d.ts.map +0 -1
  203. package/dist/templates/prd-template.js +0 -166
  204. package/dist/templates/prd-template.js.map +0 -1
  205. package/dist/templates/slicer-prompt.d.ts +0 -54
  206. package/dist/templates/slicer-prompt.d.ts.map +0 -1
  207. package/dist/templates/slicer-prompt.js +0 -163
  208. package/dist/templates/slicer-prompt.js.map +0 -1
  209. package/dist/types.d.ts +0 -123
  210. package/dist/types.d.ts.map +0 -1
  211. package/dist/types.js +0 -5
  212. package/dist/types.js.map +0 -1
  213. package/dist/utils/checks.d.ts +0 -55
  214. package/dist/utils/checks.d.ts.map +0 -1
  215. package/dist/utils/checks.js +0 -246
  216. package/dist/utils/checks.js.map +0 -1
  217. package/dist/utils/config-writer.d.ts +0 -16
  218. package/dist/utils/config-writer.d.ts.map +0 -1
  219. package/dist/utils/config-writer.js +0 -45
  220. package/dist/utils/config-writer.js.map +0 -1
  221. package/dist/utils/crontab.d.ts +0 -62
  222. package/dist/utils/crontab.d.ts.map +0 -1
  223. package/dist/utils/crontab.js +0 -168
  224. package/dist/utils/crontab.js.map +0 -1
  225. package/dist/utils/execution-history.d.ts +0 -54
  226. package/dist/utils/execution-history.d.ts.map +0 -1
  227. package/dist/utils/execution-history.js +0 -80
  228. package/dist/utils/execution-history.js.map +0 -1
  229. package/dist/utils/github.d.ts +0 -40
  230. package/dist/utils/github.d.ts.map +0 -1
  231. package/dist/utils/github.js +0 -126
  232. package/dist/utils/github.js.map +0 -1
  233. package/dist/utils/notify.d.ts +0 -63
  234. package/dist/utils/notify.d.ts.map +0 -1
  235. package/dist/utils/notify.js +0 -264
  236. package/dist/utils/notify.js.map +0 -1
  237. package/dist/utils/prd-states.d.ts +0 -16
  238. package/dist/utils/prd-states.d.ts.map +0 -1
  239. package/dist/utils/prd-states.js +0 -28
  240. package/dist/utils/prd-states.js.map +0 -1
  241. package/dist/utils/registry.d.ts +0 -44
  242. package/dist/utils/registry.d.ts.map +0 -1
  243. package/dist/utils/registry.js +0 -86
  244. package/dist/utils/registry.js.map +0 -1
  245. package/dist/utils/roadmap-parser.d.ts +0 -45
  246. package/dist/utils/roadmap-parser.d.ts.map +0 -1
  247. package/dist/utils/roadmap-parser.js +0 -136
  248. package/dist/utils/roadmap-parser.js.map +0 -1
  249. package/dist/utils/roadmap-scanner.d.ts +0 -92
  250. package/dist/utils/roadmap-scanner.d.ts.map +0 -1
  251. package/dist/utils/roadmap-scanner.js +0 -349
  252. package/dist/utils/roadmap-scanner.js.map +0 -1
  253. package/dist/utils/roadmap-state.d.ts +0 -90
  254. package/dist/utils/roadmap-state.d.ts.map +0 -1
  255. package/dist/utils/roadmap-state.js +0 -154
  256. package/dist/utils/roadmap-state.js.map +0 -1
  257. package/dist/utils/script-result.d.ts +0 -12
  258. package/dist/utils/script-result.d.ts.map +0 -1
  259. package/dist/utils/script-result.js +0 -46
  260. package/dist/utils/script-result.js.map +0 -1
  261. package/dist/utils/shell.d.ts +0 -27
  262. package/dist/utils/shell.d.ts.map +0 -1
  263. package/dist/utils/shell.js +0 -64
  264. package/dist/utils/shell.js.map +0 -1
  265. package/dist/utils/status-data.d.ts +0 -148
  266. package/dist/utils/status-data.d.ts.map +0 -1
  267. package/dist/utils/status-data.js +0 -593
  268. package/dist/utils/status-data.js.map +0 -1
  269. package/dist/utils/ui.d.ts +0 -55
  270. package/dist/utils/ui.d.ts.map +0 -1
  271. package/dist/utils/ui.js +0 -121
  272. package/dist/utils/ui.js.map +0 -1
  273. package/web/dist/assets/index-BtxQU4oX.css +0 -1
  274. package/web/dist/assets/index-D3awZ0gS.js +0 -473
@@ -1,829 +0,0 @@
1
- /**
2
- * Config tab for the dashboard TUI
3
- * Allows viewing and editing all configuration fields
4
- */
5
- import blessed from "blessed";
6
- import { VALID_PROVIDERS } from "../../constants.js";
7
- import { saveConfig } from "../../utils/config-writer.js";
8
- import { performUninstall } from "../uninstall.js";
9
- import { performInstall } from "../install.js";
10
- const SENSITIVE_PATTERNS = /TOKEN|KEY|SECRET|PASSWORD/i;
11
- const WEBHOOK_TYPES = ["slack", "discord", "telegram"];
12
- const NOTIFICATION_EVENTS = [
13
- "run_started",
14
- "run_succeeded",
15
- "run_failed",
16
- "run_timeout",
17
- "review_completed",
18
- "pr_auto_merged",
19
- "rate_limit_fallback",
20
- "qa_completed",
21
- ];
22
- /**
23
- * GLM-5 default provider environment configuration
24
- */
25
- const GLM5_DEFAULTS = {
26
- ANTHROPIC_BASE_URL: "https://api.z.ai/api/anthropic",
27
- API_TIMEOUT_MS: "3000000",
28
- ANTHROPIC_DEFAULT_OPUS_MODEL: "glm-5",
29
- ANTHROPIC_DEFAULT_SONNET_MODEL: "glm-5",
30
- };
31
- export const CONFIG_FIELDS = [
32
- { key: "provider", label: "Provider", type: "enum", options: [...VALID_PROVIDERS] },
33
- { key: "reviewerEnabled", label: "Reviewer Enabled", type: "boolean" },
34
- { key: "defaultBranch", label: "Default Branch", type: "string" },
35
- { key: "prdDir", label: "PRD Directory", type: "string" },
36
- { key: "branchPrefix", label: "Branch Prefix", type: "string" },
37
- { key: "branchPatterns", label: "Branch Patterns", type: "string[]" },
38
- { key: "cronSchedule", label: "Executor Schedule", type: "string" },
39
- { key: "reviewerSchedule", label: "Reviewer Schedule", type: "string" },
40
- {
41
- key: "maxRuntime", label: "Max Runtime (s)", type: "number",
42
- validate: (v) => { const n = parseInt(v, 10); return isNaN(n) || n <= 0 ? "Must be a positive integer" : null; },
43
- },
44
- {
45
- key: "reviewerMaxRuntime", label: "Reviewer Max Runtime (s)", type: "number",
46
- validate: (v) => { const n = parseInt(v, 10); return isNaN(n) || n <= 0 ? "Must be a positive integer" : null; },
47
- },
48
- {
49
- key: "minReviewScore", label: "Min Review Score", type: "number",
50
- validate: (v) => { const n = parseInt(v, 10); return isNaN(n) || n < 0 || n > 100 ? "Must be 0-100" : null; },
51
- },
52
- {
53
- key: "maxLogSize", label: "Max Log Size (bytes)", type: "number",
54
- validate: (v) => { const n = parseInt(v, 10); return isNaN(n) || n <= 0 ? "Must be a positive integer" : null; },
55
- },
56
- { key: "providerEnv", label: "Provider Env Vars", type: "keyvalue" },
57
- { key: "notifications", label: "Notifications", type: "webhooks" },
58
- ];
59
- function maskValue(key, value) {
60
- if (SENSITIVE_PATTERNS.test(key) && value.length > 6) {
61
- return value.slice(0, 3) + "***" + value.slice(-3);
62
- }
63
- return value;
64
- }
65
- function formatFieldValue(config, field) {
66
- const value = config[field.key];
67
- if (field.type === "string[]" && Array.isArray(value)) {
68
- return value.join(", ");
69
- }
70
- if (field.type === "keyvalue") {
71
- const env = value;
72
- const count = Object.keys(env).length;
73
- return count > 0 ? `${count} variable(s) set` : "(none)";
74
- }
75
- if (field.type === "webhooks") {
76
- const notif = value;
77
- return notif.webhooks.length > 0 ? `${notif.webhooks.length} webhook(s)` : "(none)";
78
- }
79
- return String(value);
80
- }
81
- /**
82
- * Create the Config editor tab
83
- */
84
- export function createConfigTab() {
85
- const container = blessed.box({
86
- top: 0,
87
- left: 0,
88
- width: "100%",
89
- height: "100%",
90
- hidden: true,
91
- });
92
- const configList = blessed.list({
93
- top: 0,
94
- left: 0,
95
- width: "100%",
96
- height: "100%-3",
97
- border: { type: "line" },
98
- label: "[ Configuration ]",
99
- tags: true,
100
- scrollable: true,
101
- alwaysScroll: true,
102
- scrollbar: { style: { bg: "blue" } },
103
- style: {
104
- border: { fg: "cyan" },
105
- selected: { bg: "blue", fg: "white" },
106
- item: { fg: "white" },
107
- },
108
- keys: true,
109
- vi: false,
110
- mouse: false,
111
- interactive: true,
112
- });
113
- const statusBar = blessed.box({
114
- bottom: 0,
115
- left: 0,
116
- width: "100%",
117
- height: 3,
118
- border: { type: "line" },
119
- tags: true,
120
- style: { border: { fg: "white" } },
121
- content: "",
122
- });
123
- container.append(configList);
124
- container.append(statusBar);
125
- const pendingChanges = {};
126
- let currentConfig = null;
127
- function buildListItems(config) {
128
- return CONFIG_FIELDS.map((field) => {
129
- const hasChange = field.key in pendingChanges;
130
- const value = hasChange
131
- ? formatFieldValue({ ...config, ...pendingChanges }, field)
132
- : formatFieldValue(config, field);
133
- const marker = hasChange ? " {yellow-fg}*{/yellow-fg}" : "";
134
- const editHint = field.type === "keyvalue" || field.type === "webhooks" ? " {#888888-fg}(Enter to manage){/#888888-fg}" : "";
135
- return ` ${field.label}: ${value}${marker}${editHint}`;
136
- });
137
- }
138
- function updateStatusBar() {
139
- const changeCount = Object.keys(pendingChanges).length;
140
- if (changeCount > 0) {
141
- statusBar.setContent(` {yellow-fg}${changeCount} unsaved change(s){/yellow-fg} | s:Save & Apply u:Undo All`);
142
- }
143
- else {
144
- statusBar.setContent(" No pending changes");
145
- }
146
- }
147
- function refreshList(config) {
148
- configList.setItems(buildListItems(config));
149
- updateStatusBar();
150
- }
151
- // ── Key-Value Editor (providerEnv) ──────────────────────────────────────
152
- function showKeyValueEditor(ctx, config) {
153
- const currentEnv = {
154
- ...(config.providerEnv || {}),
155
- ...(pendingChanges.providerEnv || {}),
156
- };
157
- // If pendingChanges has providerEnv, use it entirely; otherwise merge from config
158
- const editableEnv = pendingChanges.providerEnv
159
- ? { ...pendingChanges.providerEnv }
160
- : { ...currentEnv };
161
- function buildItems() {
162
- const entries = Object.entries(editableEnv);
163
- if (entries.length === 0)
164
- return [" (no variables set)"];
165
- return entries.map(([k, v]) => ` ${k} = ${maskValue(k, v)}`);
166
- }
167
- const kvList = blessed.list({
168
- top: "center",
169
- left: "center",
170
- width: "70%",
171
- height: Math.min(Object.keys(editableEnv).length + 4, 20),
172
- border: { type: "line" },
173
- label: "[ Provider Env Vars | a:Add Enter:Edit d:Delete Esc:Done ]",
174
- tags: true,
175
- style: {
176
- border: { fg: "cyan" },
177
- selected: { bg: "blue", fg: "white" },
178
- item: { fg: "white" },
179
- },
180
- keys: true,
181
- vi: false,
182
- interactive: true,
183
- });
184
- kvList.setItems(buildItems());
185
- ctx.setEditing(true);
186
- ctx.screen.append(kvList);
187
- kvList.focus();
188
- ctx.screen.render();
189
- function refreshKvList() {
190
- kvList.setItems(buildItems());
191
- kvList.height = Math.min(Object.keys(editableEnv).length + 4, 20);
192
- ctx.screen.render();
193
- }
194
- function promptTextbox(label, initialValue, cb) {
195
- const input = blessed.textbox({
196
- top: "center",
197
- left: "center",
198
- width: "50%",
199
- height: 3,
200
- border: { type: "line" },
201
- label: `[ ${label} ]`,
202
- tags: true,
203
- style: { border: { fg: "yellow" }, fg: "white" },
204
- inputOnFocus: true,
205
- });
206
- ctx.screen.append(input);
207
- input.setValue(initialValue);
208
- input.focus();
209
- ctx.screen.render();
210
- input.on("submit", (value) => {
211
- input.destroy();
212
- cb(value.trim());
213
- });
214
- input.on("cancel", () => {
215
- input.destroy();
216
- cb(null);
217
- });
218
- }
219
- kvList.key(["a"], () => {
220
- promptTextbox("Variable Name", "", (key) => {
221
- if (!key) {
222
- kvList.focus();
223
- ctx.screen.render();
224
- return;
225
- }
226
- promptTextbox(`Value for ${key}`, "", (value) => {
227
- if (value !== null) {
228
- editableEnv[key] = value;
229
- pendingChanges.providerEnv = { ...editableEnv };
230
- refreshKvList();
231
- }
232
- kvList.focus();
233
- ctx.screen.render();
234
- });
235
- });
236
- });
237
- kvList.key(["enter"], () => {
238
- const keys = Object.keys(editableEnv);
239
- if (keys.length === 0)
240
- return;
241
- const idx = kvList.selected;
242
- if (idx < 0 || idx >= keys.length)
243
- return;
244
- const selectedKey = keys[idx];
245
- promptTextbox(`Edit ${selectedKey}`, editableEnv[selectedKey], (value) => {
246
- if (value !== null) {
247
- editableEnv[selectedKey] = value;
248
- pendingChanges.providerEnv = { ...editableEnv };
249
- refreshKvList();
250
- }
251
- kvList.focus();
252
- ctx.screen.render();
253
- });
254
- });
255
- kvList.key(["d"], () => {
256
- const keys = Object.keys(editableEnv);
257
- if (keys.length === 0)
258
- return;
259
- const idx = kvList.selected;
260
- if (idx < 0 || idx >= keys.length)
261
- return;
262
- const selectedKey = keys[idx];
263
- delete editableEnv[selectedKey];
264
- pendingChanges.providerEnv = { ...editableEnv };
265
- refreshKvList();
266
- });
267
- kvList.key(["escape"], () => {
268
- kvList.destroy();
269
- ctx.setEditing(false);
270
- if (currentConfig)
271
- refreshList(currentConfig);
272
- configList.focus();
273
- ctx.screen.render();
274
- });
275
- }
276
- // ── Webhook Editor (notifications) ──────────────────────────────────────
277
- function showWebhookEditor(ctx, config) {
278
- const currentNotif = pendingChanges.notifications
279
- ? pendingChanges.notifications
280
- : config.notifications;
281
- const editableWebhooks = currentNotif.webhooks.map((w) => ({ ...w, events: [...w.events] }));
282
- function buildItems() {
283
- if (editableWebhooks.length === 0)
284
- return [" (no webhooks configured)"];
285
- return editableWebhooks.map((w) => {
286
- const identifier = w.type === "telegram"
287
- ? `token:${maskValue("TOKEN", w.botToken || "")}`
288
- : (w.url ? maskValue("URL", w.url) : "no url");
289
- return ` [${w.type}] ${identifier} events: ${w.events.length}`;
290
- });
291
- }
292
- const whList = blessed.list({
293
- top: "center",
294
- left: "center",
295
- width: "70%",
296
- height: Math.min(editableWebhooks.length + 4, 20),
297
- border: { type: "line" },
298
- label: "[ Webhooks | a:Add Enter:Edit d:Delete Esc:Done ]",
299
- tags: true,
300
- style: {
301
- border: { fg: "cyan" },
302
- selected: { bg: "blue", fg: "white" },
303
- item: { fg: "white" },
304
- },
305
- keys: true,
306
- vi: false,
307
- interactive: true,
308
- });
309
- whList.setItems(buildItems());
310
- ctx.setEditing(true);
311
- ctx.screen.append(whList);
312
- whList.focus();
313
- ctx.screen.render();
314
- function refreshWhList() {
315
- whList.setItems(buildItems());
316
- whList.height = Math.min(editableWebhooks.length + 4, 20);
317
- ctx.screen.render();
318
- }
319
- function stageWebhookChanges() {
320
- pendingChanges.notifications = { webhooks: editableWebhooks.map((w) => ({ ...w, events: [...w.events] })) };
321
- }
322
- function promptTextbox(label, initialValue, cb) {
323
- const input = blessed.textbox({
324
- top: "center",
325
- left: "center",
326
- width: "50%",
327
- height: 3,
328
- border: { type: "line" },
329
- label: `[ ${label} ]`,
330
- tags: true,
331
- style: { border: { fg: "yellow" }, fg: "white" },
332
- inputOnFocus: true,
333
- });
334
- ctx.screen.append(input);
335
- input.setValue(initialValue);
336
- input.focus();
337
- ctx.screen.render();
338
- input.on("submit", (value) => { input.destroy(); cb(value.trim()); });
339
- input.on("cancel", () => { input.destroy(); cb(null); });
340
- }
341
- function selectType(cb) {
342
- const typeList = blessed.list({
343
- top: "center",
344
- left: "center",
345
- width: 30,
346
- height: WEBHOOK_TYPES.length + 2,
347
- border: { type: "line" },
348
- label: "[ Webhook Type ]",
349
- tags: true,
350
- style: { border: { fg: "yellow" }, selected: { bg: "blue", fg: "white" }, item: { fg: "white" } },
351
- keys: true,
352
- vi: false,
353
- interactive: true,
354
- });
355
- typeList.setItems(WEBHOOK_TYPES);
356
- ctx.screen.append(typeList);
357
- typeList.focus();
358
- ctx.screen.render();
359
- typeList.on("select", (_item, index) => {
360
- typeList.destroy();
361
- cb(WEBHOOK_TYPES[index]);
362
- });
363
- typeList.key(["escape"], () => { typeList.destroy(); cb(null); });
364
- }
365
- function selectEvents(current, cb) {
366
- const selected = new Set(current);
367
- const evList = blessed.list({
368
- top: "center",
369
- left: "center",
370
- width: 40,
371
- height: NOTIFICATION_EVENTS.length + 3,
372
- border: { type: "line" },
373
- label: "[ Events | Space:Toggle Enter:Done ]",
374
- tags: true,
375
- style: { border: { fg: "yellow" }, selected: { bg: "blue", fg: "white" }, item: { fg: "white" } },
376
- keys: true,
377
- vi: false,
378
- interactive: true,
379
- });
380
- function renderEvents() {
381
- evList.setItems(NOTIFICATION_EVENTS.map((e) => ` ${selected.has(e) ? "[x]" : "[ ]"} ${e}`));
382
- }
383
- renderEvents();
384
- ctx.screen.append(evList);
385
- evList.focus();
386
- ctx.screen.render();
387
- evList.key(["space"], () => {
388
- const idx = evList.selected;
389
- if (idx >= 0 && idx < NOTIFICATION_EVENTS.length) {
390
- const ev = NOTIFICATION_EVENTS[idx];
391
- if (selected.has(ev))
392
- selected.delete(ev);
393
- else
394
- selected.add(ev);
395
- renderEvents();
396
- evList.select(idx);
397
- ctx.screen.render();
398
- }
399
- });
400
- evList.key(["enter"], () => {
401
- evList.destroy();
402
- cb([...selected]);
403
- });
404
- evList.key(["escape"], () => { evList.destroy(); cb(null); });
405
- }
406
- function addWebhookWizard() {
407
- selectType((type) => {
408
- if (!type) {
409
- whList.focus();
410
- ctx.screen.render();
411
- return;
412
- }
413
- const webhook = { type, events: [...NOTIFICATION_EVENTS] };
414
- const askCredentials = (done) => {
415
- if (type === "telegram") {
416
- promptTextbox("Bot Token", "", (botToken) => {
417
- if (botToken === null) {
418
- done(false);
419
- return;
420
- }
421
- webhook.botToken = botToken;
422
- promptTextbox("Chat ID", "", (chatId) => {
423
- if (chatId === null) {
424
- done(false);
425
- return;
426
- }
427
- webhook.chatId = chatId;
428
- done(true);
429
- });
430
- });
431
- }
432
- else {
433
- promptTextbox("Webhook URL", "", (url) => {
434
- if (url === null) {
435
- done(false);
436
- return;
437
- }
438
- webhook.url = url;
439
- done(true);
440
- });
441
- }
442
- };
443
- askCredentials((ok) => {
444
- if (!ok) {
445
- whList.focus();
446
- ctx.screen.render();
447
- return;
448
- }
449
- selectEvents(webhook.events, (events) => {
450
- if (events === null) {
451
- whList.focus();
452
- ctx.screen.render();
453
- return;
454
- }
455
- webhook.events = events;
456
- editableWebhooks.push(webhook);
457
- stageWebhookChanges();
458
- refreshWhList();
459
- whList.focus();
460
- ctx.screen.render();
461
- });
462
- });
463
- });
464
- }
465
- function editWebhook(idx) {
466
- const webhook = editableWebhooks[idx];
467
- selectType((type) => {
468
- if (type === null) {
469
- whList.focus();
470
- ctx.screen.render();
471
- return;
472
- }
473
- webhook.type = type;
474
- const askCredentials = (done) => {
475
- if (type === "telegram") {
476
- promptTextbox("Bot Token", webhook.botToken || "", (botToken) => {
477
- if (botToken === null) {
478
- done(false);
479
- return;
480
- }
481
- webhook.botToken = botToken;
482
- webhook.url = undefined;
483
- promptTextbox("Chat ID", webhook.chatId || "", (chatId) => {
484
- if (chatId === null) {
485
- done(false);
486
- return;
487
- }
488
- webhook.chatId = chatId;
489
- done(true);
490
- });
491
- });
492
- }
493
- else {
494
- promptTextbox("Webhook URL", webhook.url || "", (url) => {
495
- if (url === null) {
496
- done(false);
497
- return;
498
- }
499
- webhook.url = url;
500
- webhook.botToken = undefined;
501
- webhook.chatId = undefined;
502
- done(true);
503
- });
504
- }
505
- };
506
- askCredentials((ok) => {
507
- if (!ok) {
508
- whList.focus();
509
- ctx.screen.render();
510
- return;
511
- }
512
- selectEvents(webhook.events, (events) => {
513
- if (events === null) {
514
- whList.focus();
515
- ctx.screen.render();
516
- return;
517
- }
518
- webhook.events = events;
519
- stageWebhookChanges();
520
- refreshWhList();
521
- whList.focus();
522
- ctx.screen.render();
523
- });
524
- });
525
- });
526
- }
527
- whList.key(["a"], () => addWebhookWizard());
528
- whList.key(["enter"], () => {
529
- if (editableWebhooks.length === 0)
530
- return;
531
- const idx = whList.selected;
532
- if (idx >= 0 && idx < editableWebhooks.length) {
533
- editWebhook(idx);
534
- }
535
- });
536
- whList.key(["d"], () => {
537
- if (editableWebhooks.length === 0)
538
- return;
539
- const idx = whList.selected;
540
- if (idx >= 0 && idx < editableWebhooks.length) {
541
- editableWebhooks.splice(idx, 1);
542
- stageWebhookChanges();
543
- refreshWhList();
544
- }
545
- });
546
- whList.key(["escape"], () => {
547
- whList.destroy();
548
- ctx.setEditing(false);
549
- if (currentConfig)
550
- refreshList(currentConfig);
551
- configList.focus();
552
- ctx.screen.render();
553
- });
554
- }
555
- // ── GLM-5 Quick Setup ──────────────────────────────────────────────────
556
- function showGlm5Setup(ctx) {
557
- const inputBox = blessed.textbox({
558
- top: "center",
559
- left: "center",
560
- width: "60%",
561
- height: 3,
562
- border: { type: "line" },
563
- label: "[ GLM-5 Quick Setup: Enter API Key ]",
564
- tags: true,
565
- style: { border: { fg: "cyan" }, fg: "white" },
566
- inputOnFocus: true,
567
- });
568
- ctx.setEditing(true);
569
- ctx.screen.append(inputBox);
570
- inputBox.setValue("");
571
- inputBox.focus();
572
- ctx.screen.render();
573
- inputBox.on("submit", (value) => {
574
- const apiKey = value.trim();
575
- inputBox.destroy();
576
- ctx.setEditing(false);
577
- if (!apiKey) {
578
- ctx.showMessage("No API key provided", "error");
579
- configList.focus();
580
- ctx.screen.render();
581
- return;
582
- }
583
- pendingChanges.providerEnv = {
584
- ANTHROPIC_API_KEY: apiKey,
585
- ANTHROPIC_AUTH_TOKEN: apiKey,
586
- ...GLM5_DEFAULTS,
587
- };
588
- ctx.showMessage("GLM-5 configured. Press s to save.", "success");
589
- if (currentConfig)
590
- refreshList(currentConfig);
591
- configList.focus();
592
- ctx.screen.render();
593
- });
594
- inputBox.on("cancel", () => {
595
- inputBox.destroy();
596
- ctx.setEditing(false);
597
- configList.focus();
598
- ctx.screen.render();
599
- });
600
- }
601
- // ── Standard Editor ─────────────────────────────────────────────────────
602
- function showEditor(ctx, field, config) {
603
- if (field.type === "keyvalue") {
604
- showKeyValueEditor(ctx, config);
605
- return;
606
- }
607
- if (field.type === "webhooks") {
608
- showWebhookEditor(ctx, config);
609
- return;
610
- }
611
- const currentValue = field.key in pendingChanges
612
- ? String(pendingChanges[field.key])
613
- : formatFieldValue(config, field);
614
- if (field.type === "enum" || field.type === "boolean") {
615
- const options = field.type === "boolean" ? ["true", "false"] : (field.options || []);
616
- const selectorList = blessed.list({
617
- top: "center",
618
- left: "center",
619
- width: Math.max(30, ...options.map((o) => o.length + 6)),
620
- height: options.length + 2,
621
- border: { type: "line" },
622
- label: `[ ${field.label} ]`,
623
- tags: true,
624
- style: {
625
- border: { fg: "cyan" },
626
- selected: { bg: "blue", fg: "white" },
627
- item: { fg: "white" },
628
- },
629
- keys: true,
630
- vi: false,
631
- interactive: true,
632
- });
633
- selectorList.setItems(options);
634
- // Pre-select current value
635
- const currentIdx = options.indexOf(currentValue);
636
- if (currentIdx >= 0) {
637
- selectorList.select(currentIdx);
638
- }
639
- ctx.setEditing(true);
640
- ctx.screen.append(selectorList);
641
- selectorList.focus();
642
- ctx.screen.render();
643
- selectorList.on("select", (_item, index) => {
644
- const selected = options[index];
645
- if (field.type === "boolean") {
646
- pendingChanges[field.key] = selected === "true";
647
- }
648
- else {
649
- pendingChanges[field.key] = selected;
650
- }
651
- selectorList.destroy();
652
- ctx.setEditing(false);
653
- refreshList(config);
654
- configList.focus();
655
- ctx.screen.render();
656
- });
657
- selectorList.key(["escape"], () => {
658
- selectorList.destroy();
659
- ctx.setEditing(false);
660
- configList.focus();
661
- ctx.screen.render();
662
- });
663
- return;
664
- }
665
- // Text input for string, number, string[]
666
- const inputBox = blessed.textbox({
667
- top: "center",
668
- left: "center",
669
- width: "60%",
670
- height: 3,
671
- border: { type: "line" },
672
- label: `[ ${field.label} ]`,
673
- tags: true,
674
- style: {
675
- border: { fg: "cyan" },
676
- fg: "white",
677
- },
678
- inputOnFocus: true,
679
- });
680
- ctx.setEditing(true);
681
- ctx.screen.append(inputBox);
682
- inputBox.setValue(currentValue);
683
- inputBox.focus();
684
- ctx.screen.render();
685
- inputBox.on("submit", (value) => {
686
- // Validate
687
- if (field.validate) {
688
- const error = field.validate(value);
689
- if (error) {
690
- ctx.showMessage(error, "error");
691
- inputBox.destroy();
692
- ctx.setEditing(false);
693
- configList.focus();
694
- ctx.screen.render();
695
- return;
696
- }
697
- }
698
- // Apply value
699
- if (field.type === "number") {
700
- pendingChanges[field.key] = parseInt(value, 10);
701
- }
702
- else if (field.type === "string[]") {
703
- pendingChanges[field.key] = value.split(",").map((s) => s.trim()).filter((s) => s.length > 0);
704
- }
705
- else {
706
- pendingChanges[field.key] = value;
707
- }
708
- inputBox.destroy();
709
- ctx.setEditing(false);
710
- refreshList(config);
711
- configList.focus();
712
- ctx.screen.render();
713
- });
714
- inputBox.on("cancel", () => {
715
- inputBox.destroy();
716
- ctx.setEditing(false);
717
- configList.focus();
718
- ctx.screen.render();
719
- });
720
- }
721
- let activeKeyHandlers = [];
722
- let activeCtx = null;
723
- function bindKeys(ctx) {
724
- const handlers = [
725
- [["enter"], () => {
726
- const idx = configList.selected;
727
- if (idx === undefined || idx < 0 || idx >= CONFIG_FIELDS.length)
728
- return;
729
- const field = CONFIG_FIELDS[idx];
730
- if (currentConfig) {
731
- showEditor(ctx, field, currentConfig);
732
- }
733
- }],
734
- [["s"], () => {
735
- if (Object.keys(pendingChanges).length === 0) {
736
- ctx.showMessage("No changes to save", "info");
737
- return;
738
- }
739
- // Save config
740
- const result = saveConfig(ctx.projectDir, pendingChanges);
741
- if (!result.success) {
742
- ctx.showMessage(`Save failed: ${result.error}`, "error");
743
- return;
744
- }
745
- // Check if schedules changed - reinstall cron
746
- const scheduleChanged = "cronSchedule" in pendingChanges ||
747
- "reviewerSchedule" in pendingChanges ||
748
- "reviewerEnabled" in pendingChanges;
749
- if (scheduleChanged) {
750
- performUninstall(ctx.projectDir, { keepLogs: true });
751
- const newConfig = ctx.reloadConfig();
752
- const installResult = performInstall(ctx.projectDir, newConfig);
753
- if (!installResult.success) {
754
- ctx.showMessage(`Config saved but cron reinstall failed: ${installResult.error}`, "error");
755
- }
756
- else {
757
- ctx.showMessage("Config saved & cron reinstalled", "success");
758
- }
759
- }
760
- else {
761
- ctx.showMessage("Config saved", "success");
762
- }
763
- // Reload config
764
- currentConfig = ctx.reloadConfig();
765
- // Clear pending
766
- for (const key of Object.keys(pendingChanges)) {
767
- delete pendingChanges[key];
768
- }
769
- refreshList(currentConfig);
770
- ctx.screen.render();
771
- }],
772
- [["u"], () => {
773
- for (const key of Object.keys(pendingChanges)) {
774
- delete pendingChanges[key];
775
- }
776
- if (currentConfig) {
777
- refreshList(currentConfig);
778
- }
779
- ctx.showMessage("Changes undone", "info");
780
- ctx.screen.render();
781
- }],
782
- [["g"], () => {
783
- showGlm5Setup(ctx);
784
- }],
785
- ];
786
- for (const [keys, handler] of handlers) {
787
- ctx.screen.key(keys, handler);
788
- }
789
- activeKeyHandlers = handlers;
790
- }
791
- function unbindKeys(ctx) {
792
- for (const [keys, handler] of activeKeyHandlers) {
793
- for (const key of keys) {
794
- ctx.screen.unkey(key, handler);
795
- }
796
- }
797
- activeKeyHandlers = [];
798
- }
799
- return {
800
- name: "Config",
801
- container,
802
- activate(ctx) {
803
- ctx.setFooter(" \u2191\u2193:Navigate Enter:Edit g:GLM-5 Setup s:Save u:Undo q:Quit");
804
- currentConfig = ctx.config;
805
- refreshList(currentConfig);
806
- configList.focus();
807
- activeCtx = ctx;
808
- bindKeys(ctx);
809
- ctx.screen.render();
810
- },
811
- deactivate() {
812
- if (activeCtx) {
813
- unbindKeys(activeCtx);
814
- activeCtx = null;
815
- }
816
- },
817
- refresh(ctx) {
818
- // Only refresh if no pending changes (don't overwrite user edits)
819
- if (Object.keys(pendingChanges).length === 0) {
820
- currentConfig = ctx.config;
821
- refreshList(currentConfig);
822
- }
823
- },
824
- destroy() {
825
- // Nothing to clean up
826
- },
827
- };
828
- }
829
- //# sourceMappingURL=tab-config.js.map