@jonit-dev/night-watch-cli 1.8.10-beta.1 → 1.8.10-beta.2

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 (235) hide show
  1. package/dist/cli.js +2309 -1313
  2. package/dist/web/assets/index-BUgI2S1s.js +406 -0
  3. package/dist/web/assets/index-CkdLFBd7.js +406 -0
  4. package/dist/web/assets/index-RMfswANB.css +1 -0
  5. package/dist/web/index.html +2 -2
  6. package/package.json +1 -1
  7. package/dist/cli.d.ts +0 -3
  8. package/dist/cli.d.ts.map +0 -1
  9. package/dist/cli.js.map +0 -1
  10. package/dist/commands/analytics.d.ts +0 -14
  11. package/dist/commands/analytics.d.ts.map +0 -1
  12. package/dist/commands/analytics.js +0 -69
  13. package/dist/commands/analytics.js.map +0 -1
  14. package/dist/commands/audit.d.ts +0 -19
  15. package/dist/commands/audit.d.ts.map +0 -1
  16. package/dist/commands/audit.js +0 -144
  17. package/dist/commands/audit.js.map +0 -1
  18. package/dist/commands/board.d.ts +0 -9
  19. package/dist/commands/board.d.ts.map +0 -1
  20. package/dist/commands/board.js +0 -702
  21. package/dist/commands/board.js.map +0 -1
  22. package/dist/commands/cancel.d.ts +0 -46
  23. package/dist/commands/cancel.d.ts.map +0 -1
  24. package/dist/commands/cancel.js +0 -239
  25. package/dist/commands/cancel.js.map +0 -1
  26. package/dist/commands/cron.d.ts +0 -8
  27. package/dist/commands/cron.d.ts.map +0 -1
  28. package/dist/commands/cron.js +0 -134
  29. package/dist/commands/cron.js.map +0 -1
  30. package/dist/commands/dashboard/tab-actions.d.ts +0 -10
  31. package/dist/commands/dashboard/tab-actions.d.ts.map +0 -1
  32. package/dist/commands/dashboard/tab-actions.js +0 -247
  33. package/dist/commands/dashboard/tab-actions.js.map +0 -1
  34. package/dist/commands/dashboard/tab-config.d.ts +0 -21
  35. package/dist/commands/dashboard/tab-config.d.ts.map +0 -1
  36. package/dist/commands/dashboard/tab-config.js +0 -873
  37. package/dist/commands/dashboard/tab-config.js.map +0 -1
  38. package/dist/commands/dashboard/tab-logs.d.ts +0 -10
  39. package/dist/commands/dashboard/tab-logs.d.ts.map +0 -1
  40. package/dist/commands/dashboard/tab-logs.js +0 -202
  41. package/dist/commands/dashboard/tab-logs.js.map +0 -1
  42. package/dist/commands/dashboard/tab-schedules.d.ts +0 -21
  43. package/dist/commands/dashboard/tab-schedules.d.ts.map +0 -1
  44. package/dist/commands/dashboard/tab-schedules.js +0 -320
  45. package/dist/commands/dashboard/tab-schedules.js.map +0 -1
  46. package/dist/commands/dashboard/tab-status.d.ts +0 -32
  47. package/dist/commands/dashboard/tab-status.d.ts.map +0 -1
  48. package/dist/commands/dashboard/tab-status.js +0 -424
  49. package/dist/commands/dashboard/tab-status.js.map +0 -1
  50. package/dist/commands/dashboard/types.d.ts +0 -42
  51. package/dist/commands/dashboard/types.d.ts.map +0 -1
  52. package/dist/commands/dashboard/types.js +0 -5
  53. package/dist/commands/dashboard/types.js.map +0 -1
  54. package/dist/commands/dashboard.d.ts +0 -11
  55. package/dist/commands/dashboard.d.ts.map +0 -1
  56. package/dist/commands/dashboard.js +0 -242
  57. package/dist/commands/dashboard.js.map +0 -1
  58. package/dist/commands/doctor.d.ts +0 -16
  59. package/dist/commands/doctor.d.ts.map +0 -1
  60. package/dist/commands/doctor.js +0 -195
  61. package/dist/commands/doctor.js.map +0 -1
  62. package/dist/commands/history.d.ts +0 -7
  63. package/dist/commands/history.d.ts.map +0 -1
  64. package/dist/commands/history.js +0 -49
  65. package/dist/commands/history.js.map +0 -1
  66. package/dist/commands/init.d.ts +0 -45
  67. package/dist/commands/init.d.ts.map +0 -1
  68. package/dist/commands/init.js +0 -777
  69. package/dist/commands/init.js.map +0 -1
  70. package/dist/commands/install.d.ts +0 -65
  71. package/dist/commands/install.d.ts.map +0 -1
  72. package/dist/commands/install.js +0 -405
  73. package/dist/commands/install.js.map +0 -1
  74. package/dist/commands/logs.d.ts +0 -15
  75. package/dist/commands/logs.d.ts.map +0 -1
  76. package/dist/commands/logs.js +0 -155
  77. package/dist/commands/logs.js.map +0 -1
  78. package/dist/commands/merge.d.ts +0 -26
  79. package/dist/commands/merge.d.ts.map +0 -1
  80. package/dist/commands/merge.js +0 -159
  81. package/dist/commands/merge.js.map +0 -1
  82. package/dist/commands/notify.d.ts +0 -7
  83. package/dist/commands/notify.d.ts.map +0 -1
  84. package/dist/commands/notify.js +0 -43
  85. package/dist/commands/notify.js.map +0 -1
  86. package/dist/commands/plan.d.ts +0 -19
  87. package/dist/commands/plan.d.ts.map +0 -1
  88. package/dist/commands/plan.js +0 -88
  89. package/dist/commands/plan.js.map +0 -1
  90. package/dist/commands/prd-state.d.ts +0 -12
  91. package/dist/commands/prd-state.d.ts.map +0 -1
  92. package/dist/commands/prd-state.js +0 -47
  93. package/dist/commands/prd-state.js.map +0 -1
  94. package/dist/commands/prd.d.ts +0 -18
  95. package/dist/commands/prd.d.ts.map +0 -1
  96. package/dist/commands/prd.js +0 -363
  97. package/dist/commands/prd.js.map +0 -1
  98. package/dist/commands/prds.d.ts +0 -13
  99. package/dist/commands/prds.d.ts.map +0 -1
  100. package/dist/commands/prds.js +0 -194
  101. package/dist/commands/prds.js.map +0 -1
  102. package/dist/commands/prs.d.ts +0 -14
  103. package/dist/commands/prs.d.ts.map +0 -1
  104. package/dist/commands/prs.js +0 -104
  105. package/dist/commands/prs.js.map +0 -1
  106. package/dist/commands/qa.d.ts +0 -34
  107. package/dist/commands/qa.d.ts.map +0 -1
  108. package/dist/commands/qa.js +0 -214
  109. package/dist/commands/qa.js.map +0 -1
  110. package/dist/commands/queue.d.ts +0 -8
  111. package/dist/commands/queue.d.ts.map +0 -1
  112. package/dist/commands/queue.js +0 -376
  113. package/dist/commands/queue.js.map +0 -1
  114. package/dist/commands/resolve.d.ts +0 -26
  115. package/dist/commands/resolve.d.ts.map +0 -1
  116. package/dist/commands/resolve.js +0 -186
  117. package/dist/commands/resolve.js.map +0 -1
  118. package/dist/commands/retry.d.ts +0 -9
  119. package/dist/commands/retry.d.ts.map +0 -1
  120. package/dist/commands/retry.js +0 -71
  121. package/dist/commands/retry.js.map +0 -1
  122. package/dist/commands/review.d.ts +0 -82
  123. package/dist/commands/review.d.ts.map +0 -1
  124. package/dist/commands/review.js +0 -479
  125. package/dist/commands/review.js.map +0 -1
  126. package/dist/commands/run.d.ts +0 -73
  127. package/dist/commands/run.d.ts.map +0 -1
  128. package/dist/commands/run.js +0 -509
  129. package/dist/commands/run.js.map +0 -1
  130. package/dist/commands/serve.d.ts +0 -19
  131. package/dist/commands/serve.d.ts.map +0 -1
  132. package/dist/commands/serve.js +0 -142
  133. package/dist/commands/serve.js.map +0 -1
  134. package/dist/commands/shared/env-builder.d.ts +0 -49
  135. package/dist/commands/shared/env-builder.d.ts.map +0 -1
  136. package/dist/commands/shared/env-builder.js +0 -150
  137. package/dist/commands/shared/env-builder.js.map +0 -1
  138. package/dist/commands/slice.d.ts +0 -35
  139. package/dist/commands/slice.d.ts.map +0 -1
  140. package/dist/commands/slice.js +0 -316
  141. package/dist/commands/slice.js.map +0 -1
  142. package/dist/commands/state.d.ts +0 -8
  143. package/dist/commands/state.d.ts.map +0 -1
  144. package/dist/commands/state.js +0 -54
  145. package/dist/commands/state.js.map +0 -1
  146. package/dist/commands/status.d.ts +0 -14
  147. package/dist/commands/status.d.ts.map +0 -1
  148. package/dist/commands/status.js +0 -297
  149. package/dist/commands/status.js.map +0 -1
  150. package/dist/commands/summary.d.ts +0 -14
  151. package/dist/commands/summary.d.ts.map +0 -1
  152. package/dist/commands/summary.js +0 -193
  153. package/dist/commands/summary.js.map +0 -1
  154. package/dist/commands/uninstall.d.ts +0 -25
  155. package/dist/commands/uninstall.d.ts.map +0 -1
  156. package/dist/commands/uninstall.js +0 -134
  157. package/dist/commands/uninstall.js.map +0 -1
  158. package/dist/commands/update.d.ts +0 -22
  159. package/dist/commands/update.d.ts.map +0 -1
  160. package/dist/commands/update.js +0 -90
  161. package/dist/commands/update.js.map +0 -1
  162. package/dist/web/assets/index-2JY0x_Ij.js +0 -381
  163. package/dist/web/assets/index-3h8pgmqL.css +0 -1
  164. package/dist/web/assets/index-B-wbyZq7.js +0 -386
  165. package/dist/web/assets/index-B1BnOpiO.css +0 -1
  166. package/dist/web/assets/index-B3CnV08_.js +0 -365
  167. package/dist/web/assets/index-B5QjuFh9.css +0 -1
  168. package/dist/web/assets/index-B8FW2ecQ.js +0 -370
  169. package/dist/web/assets/index-BFxPiKyy.js +0 -381
  170. package/dist/web/assets/index-BGqNh_Da.js +0 -365
  171. package/dist/web/assets/index-BIONU0qz.css +0 -1
  172. package/dist/web/assets/index-B_l_3wnA.js +0 -370
  173. package/dist/web/assets/index-Ba-4YvTQ.js +0 -365
  174. package/dist/web/assets/index-Bbb4-39N.js +0 -370
  175. package/dist/web/assets/index-BdgdShEN.js +0 -365
  176. package/dist/web/assets/index-BhiC4Z-G.js +0 -381
  177. package/dist/web/assets/index-BjhCFjZi.js +0 -381
  178. package/dist/web/assets/index-BlRxmrnQ.css +0 -1
  179. package/dist/web/assets/index-BqwbXsHS.js +0 -365
  180. package/dist/web/assets/index-BsC7RT48.css +0 -1
  181. package/dist/web/assets/index-Bvh8XI8_.js +0 -370
  182. package/dist/web/assets/index-C01r2ymn.js +0 -381
  183. package/dist/web/assets/index-C51Rbsmk.js +0 -381
  184. package/dist/web/assets/index-C7lMNxRE.js +0 -370
  185. package/dist/web/assets/index-CJLObgsn.js +0 -386
  186. package/dist/web/assets/index-CLuRf7Zt.js +0 -381
  187. package/dist/web/assets/index-CM3xFd3e.css +0 -1
  188. package/dist/web/assets/index-CNkBtDK7.js +0 -370
  189. package/dist/web/assets/index-CPQbZ1BL.css +0 -1
  190. package/dist/web/assets/index-CTy5dUDU.css +0 -1
  191. package/dist/web/assets/index-CU15COKs.js +0 -370
  192. package/dist/web/assets/index-CiRJZI4z.js +0 -386
  193. package/dist/web/assets/index-Cp7RYjoy.css +0 -1
  194. package/dist/web/assets/index-CvPkZOWT.js +0 -381
  195. package/dist/web/assets/index-CvUk-33B.css +0 -1
  196. package/dist/web/assets/index-Cvmj-oF6.css +0 -1
  197. package/dist/web/assets/index-CxE5iQVO.js +0 -381
  198. package/dist/web/assets/index-D7lZQpFV.js +0 -365
  199. package/dist/web/assets/index-DAyP4GOi.css +0 -1
  200. package/dist/web/assets/index-DCG0n8Kg.js +0 -386
  201. package/dist/web/assets/index-DEEI8cyF.css +0 -1
  202. package/dist/web/assets/index-DF99BowV.js +0 -381
  203. package/dist/web/assets/index-DGWsvFj6.css +0 -1
  204. package/dist/web/assets/index-DGpU39Cp.css +0 -1
  205. package/dist/web/assets/index-DI4kFgOi.js +0 -370
  206. package/dist/web/assets/index-DIyTcPw5.css +0 -1
  207. package/dist/web/assets/index-DTsfDC7m.js +0 -381
  208. package/dist/web/assets/index-DcgNAi4A.js +0 -386
  209. package/dist/web/assets/index-DgOAgkZy.css +0 -1
  210. package/dist/web/assets/index-DnHkqbOa.js +0 -386
  211. package/dist/web/assets/index-DnR7Idcf.css +0 -1
  212. package/dist/web/assets/index-DpVirMEe.css +0 -1
  213. package/dist/web/assets/index-DsYIWZ86.css +0 -1
  214. package/dist/web/assets/index-DtrDkci5.js +0 -381
  215. package/dist/web/assets/index-DyjIth5M.js +0 -386
  216. package/dist/web/assets/index-FwIKfHPL.css +0 -1
  217. package/dist/web/assets/index-IKrZymWk.css +0 -1
  218. package/dist/web/assets/index-MA6fM0ab.js +0 -381
  219. package/dist/web/assets/index-N_QxaSEg.css +0 -1
  220. package/dist/web/assets/index-OcU-0TCQ.css +0 -1
  221. package/dist/web/assets/index-OyhrmG-L.js +0 -381
  222. package/dist/web/assets/index-SQlBKu_s.js +0 -386
  223. package/dist/web/assets/index-Sv2B60J4.js +0 -370
  224. package/dist/web/assets/index-Vgyivb5u.js +0 -365
  225. package/dist/web/assets/index-ZABWMEZR.js +0 -381
  226. package/dist/web/assets/index-ZE5lOeJp.js +0 -386
  227. package/dist/web/assets/index-aCHmkAcJ.css +0 -1
  228. package/dist/web/assets/index-bFijnpuU.js +0 -381
  229. package/dist/web/assets/index-bUPZgSoZ.css +0 -1
  230. package/dist/web/assets/index-mz1VIYsP.css +0 -1
  231. package/dist/web/assets/index-oOp_MFeE.js +0 -376
  232. package/dist/web/assets/index-rfU713Zm.js +0 -386
  233. package/dist/web/assets/index-tuNH9gmb.js +0 -448
  234. package/dist/web/assets/index-viSwHyDD.js +0 -365
  235. package/dist/web/assets/index-yKEQysks.js +0 -365
@@ -1,777 +0,0 @@
1
- #!/usr/bin/env node
2
- import fs from 'fs';
3
- import path from 'path';
4
- import { execSync } from 'child_process';
5
- import { fileURLToPath } from 'url';
6
- import { dirname, join } from 'path';
7
- import * as readline from 'readline';
8
- import { BUILT_IN_PRESET_IDS, CONFIG_FILE_NAME, DEFAULT_PRD_DIR, LOG_DIR, checkGhCli, checkGitRepo, checkNodeVersion, checkProviderCli, createBoardProvider, createTable, detectProviders, getDefaultConfig, getProjectName, header, info, label, loadConfig, step, success, error as uiError, warn, } from '@night-watch/core';
9
- // Get templates directory path.
10
- // Walk up from __dirname to find the package root (the directory that contains
11
- // a package.json AND a templates/ folder). This works whether the code runs
12
- // from the TypeScript source tree (src/commands/), the compiled dist tree
13
- // (dist/commands/), or as a single esbuild bundle (dist/).
14
- const __filename = fileURLToPath(import.meta.url);
15
- const __dirname = dirname(__filename);
16
- function findTemplatesDir(startDir) {
17
- let d = startDir;
18
- for (let i = 0; i < 8; i++) {
19
- const candidate = join(d, 'templates');
20
- if (fs.existsSync(candidate) && fs.statSync(candidate).isDirectory()) {
21
- return candidate;
22
- }
23
- d = dirname(d);
24
- }
25
- return join(startDir, 'templates'); // fallback
26
- }
27
- const TEMPLATES_DIR = findTemplatesDir(__dirname);
28
- const NW_SKILLS = [
29
- 'nw-create-prd',
30
- 'nw-add-issue',
31
- 'nw-run',
32
- 'nw-slice',
33
- 'nw-board-sync',
34
- 'nw-review',
35
- ];
36
- function hasPlaywrightDependency(cwd) {
37
- const packageJsonPath = path.join(cwd, 'package.json');
38
- if (!fs.existsSync(packageJsonPath)) {
39
- return false;
40
- }
41
- try {
42
- const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf-8'));
43
- return Boolean(packageJson.dependencies?.['@playwright/test'] ||
44
- packageJson.dependencies?.playwright ||
45
- packageJson.devDependencies?.['@playwright/test'] ||
46
- packageJson.devDependencies?.playwright);
47
- }
48
- catch {
49
- return false;
50
- }
51
- }
52
- function detectPlaywright(cwd) {
53
- if (hasPlaywrightDependency(cwd)) {
54
- return true;
55
- }
56
- if (fs.existsSync(path.join(cwd, 'node_modules', '.bin', 'playwright'))) {
57
- return true;
58
- }
59
- try {
60
- execSync('playwright --version', {
61
- cwd,
62
- encoding: 'utf-8',
63
- stdio: ['pipe', 'pipe', 'pipe'],
64
- timeout: 1500,
65
- });
66
- return true;
67
- }
68
- catch {
69
- return false;
70
- }
71
- }
72
- function resolvePlaywrightInstallCommand(cwd) {
73
- if (fs.existsSync(path.join(cwd, 'pnpm-lock.yaml'))) {
74
- return 'pnpm add -D @playwright/test';
75
- }
76
- if (fs.existsSync(path.join(cwd, 'yarn.lock'))) {
77
- return 'yarn add -D @playwright/test';
78
- }
79
- return 'npm install -D @playwright/test';
80
- }
81
- function promptYesNo(question, defaultNo = true) {
82
- if (!process.stdin.isTTY || !process.stdout.isTTY) {
83
- return Promise.resolve(false);
84
- }
85
- return new Promise((resolve) => {
86
- const rl = readline.createInterface({
87
- input: process.stdin,
88
- output: process.stdout,
89
- });
90
- const suffix = defaultNo ? ' [y/N]: ' : ' [Y/n]: ';
91
- rl.question(`${question}${suffix}`, (answer) => {
92
- rl.close();
93
- const normalized = answer.trim().toLowerCase();
94
- if (normalized === '') {
95
- resolve(!defaultNo);
96
- return;
97
- }
98
- resolve(normalized === 'y' || normalized === 'yes');
99
- });
100
- });
101
- }
102
- export function isInteractiveInitSession() {
103
- return Boolean(process.stdin.isTTY && process.stdout.isTTY);
104
- }
105
- export function chooseProviderForNonInteractive(providers) {
106
- if (providers.includes('claude')) {
107
- return 'claude';
108
- }
109
- return providers[0];
110
- }
111
- export function getGitHubRemoteStatus(cwd) {
112
- try {
113
- const remoteUrl = execSync('git remote get-url origin', {
114
- cwd,
115
- encoding: 'utf-8',
116
- stdio: ['pipe', 'pipe', 'pipe'],
117
- }).trim();
118
- return {
119
- hasGitHubRemote: remoteUrl.includes('github.com'),
120
- remoteUrl: remoteUrl || null,
121
- };
122
- }
123
- catch {
124
- return {
125
- hasGitHubRemote: false,
126
- remoteUrl: null,
127
- };
128
- }
129
- }
130
- function installPlaywrightForQa(cwd) {
131
- try {
132
- const installCmd = resolvePlaywrightInstallCommand(cwd);
133
- execSync(installCmd, {
134
- cwd,
135
- encoding: 'utf-8',
136
- stdio: ['pipe', 'pipe', 'pipe'],
137
- });
138
- execSync('npx playwright install chromium', {
139
- cwd,
140
- encoding: 'utf-8',
141
- stdio: ['pipe', 'pipe', 'pipe'],
142
- });
143
- return true;
144
- }
145
- catch {
146
- return false;
147
- }
148
- }
149
- /**
150
- * Get the default branch name for the repository
151
- */
152
- export function getDefaultBranch(cwd) {
153
- const getRefTimestamp = (ref) => {
154
- try {
155
- const timestamp = execSync(`git log -1 --format=%ct ${ref}`, {
156
- encoding: 'utf-8',
157
- cwd,
158
- stdio: ['pipe', 'pipe', 'pipe'],
159
- }).trim();
160
- const parsed = parseInt(timestamp, 10);
161
- return Number.isNaN(parsed) ? null : parsed;
162
- }
163
- catch {
164
- return null;
165
- }
166
- };
167
- const getBranchLatestTimestamp = (branch) => {
168
- const refs = [`refs/remotes/origin/${branch}`, `refs/heads/${branch}`];
169
- let latest = null;
170
- for (const ref of refs) {
171
- const timestamp = getRefTimestamp(ref);
172
- if (timestamp !== null && (latest === null || timestamp > latest)) {
173
- latest = timestamp;
174
- }
175
- }
176
- return latest;
177
- };
178
- try {
179
- // If both main and master exist, use whichever has the newest tip commit
180
- const mainTimestamp = getBranchLatestTimestamp('main');
181
- const masterTimestamp = getBranchLatestTimestamp('master');
182
- if (mainTimestamp !== null && masterTimestamp !== null) {
183
- return mainTimestamp >= masterTimestamp ? 'main' : 'master';
184
- }
185
- if (mainTimestamp !== null) {
186
- return 'main';
187
- }
188
- if (masterTimestamp !== null) {
189
- return 'master';
190
- }
191
- // Fallback to origin/HEAD when neither main nor master exists
192
- const remoteRef = execSync('git symbolic-ref refs/remotes/origin/HEAD 2>/dev/null || echo ""', {
193
- encoding: 'utf-8',
194
- cwd,
195
- stdio: ['pipe', 'pipe', 'pipe'],
196
- }).trim();
197
- if (remoteRef) {
198
- // Extract branch name from refs/remotes/origin/HEAD -> refs/remotes/origin/main
199
- const match = remoteRef.match(/refs\/remotes\/origin\/(.+)/);
200
- if (match) {
201
- return match[1];
202
- }
203
- }
204
- // Default to main
205
- return 'main';
206
- }
207
- catch {
208
- return 'main';
209
- }
210
- }
211
- /**
212
- * Prompt user to select a provider from available options
213
- */
214
- function promptProviderSelection(providers) {
215
- return new Promise((resolve, reject) => {
216
- const rl = readline.createInterface({
217
- input: process.stdin,
218
- output: process.stdout,
219
- });
220
- console.log('\nMultiple AI providers detected:');
221
- providers.forEach((p, i) => {
222
- console.log(` ${i + 1}. ${p}`);
223
- });
224
- rl.question('\nSelect a provider (enter number): ', (answer) => {
225
- rl.close();
226
- const selection = parseInt(answer.trim(), 10);
227
- if (isNaN(selection) || selection < 1 || selection > providers.length) {
228
- reject(new Error('Invalid selection. Please run init again and select a valid number.'));
229
- return;
230
- }
231
- resolve(providers[selection - 1]);
232
- });
233
- });
234
- }
235
- /**
236
- * Create directory if it doesn't exist
237
- */
238
- function ensureDir(dirPath) {
239
- if (!fs.existsSync(dirPath)) {
240
- fs.mkdirSync(dirPath, { recursive: true });
241
- }
242
- }
243
- export function buildInitConfig(params) {
244
- const defaults = getDefaultConfig();
245
- return {
246
- $schema: 'https://json-schema.org/schema',
247
- projectName: params.projectName,
248
- defaultBranch: params.defaultBranch,
249
- prdDir: params.prdDir,
250
- maxRuntime: defaults.maxRuntime,
251
- reviewerMaxRuntime: defaults.reviewerMaxRuntime,
252
- branchPrefix: defaults.branchPrefix,
253
- branchPatterns: [...defaults.branchPatterns],
254
- minReviewScore: defaults.minReviewScore,
255
- maxLogSize: defaults.maxLogSize,
256
- cronSchedule: defaults.cronSchedule,
257
- reviewerSchedule: defaults.reviewerSchedule,
258
- scheduleBundleId: defaults.scheduleBundleId ?? 'always-on',
259
- cronScheduleOffset: defaults.cronScheduleOffset,
260
- schedulingPriority: defaults.schedulingPriority,
261
- maxRetries: defaults.maxRetries,
262
- reviewerMaxRetries: defaults.reviewerMaxRetries,
263
- reviewerMaxPrsPerRun: defaults.reviewerMaxPrsPerRun,
264
- reviewerRetryDelay: defaults.reviewerRetryDelay,
265
- provider: params.provider,
266
- providerLabel: '',
267
- executorEnabled: defaults.executorEnabled ?? true,
268
- reviewerEnabled: params.reviewerEnabled,
269
- providerEnv: { ...defaults.providerEnv },
270
- notifications: {
271
- ...defaults.notifications,
272
- webhooks: [...(defaults.notifications?.webhooks ?? [])],
273
- },
274
- prdPriority: [...defaults.prdPriority],
275
- roadmapScanner: { ...defaults.roadmapScanner },
276
- templatesDir: defaults.templatesDir,
277
- boardProvider: { ...defaults.boardProvider },
278
- autoMerge: defaults.autoMerge,
279
- autoMergeMethod: defaults.autoMergeMethod,
280
- fallbackOnRateLimit: defaults.fallbackOnRateLimit,
281
- claudeModel: defaults.claudeModel,
282
- qa: {
283
- ...defaults.qa,
284
- branchPatterns: [...defaults.qa.branchPatterns],
285
- },
286
- audit: { ...defaults.audit },
287
- analytics: { ...defaults.analytics },
288
- merger: { ...defaults.merger },
289
- prResolver: { ...defaults.prResolver },
290
- jobProviders: { ...defaults.jobProviders },
291
- queue: {
292
- ...defaults.queue,
293
- priority: { ...defaults.queue.priority },
294
- },
295
- };
296
- }
297
- /**
298
- * Resolve a template path with per-file fallback.
299
- * If customTemplatesDir is non-null and the file exists there, return custom path.
300
- * Otherwise return the bundled template path.
301
- */
302
- export function resolveTemplatePath(templateName, customTemplatesDir, bundledTemplatesDir) {
303
- if (customTemplatesDir !== null) {
304
- const customPath = join(customTemplatesDir, templateName);
305
- if (fs.existsSync(customPath)) {
306
- return { path: customPath, source: 'custom' };
307
- }
308
- }
309
- return { path: join(bundledTemplatesDir, templateName), source: 'bundled' };
310
- }
311
- /**
312
- * Copy and process template file
313
- */
314
- function processTemplate(templateName, targetPath, replacements, force, sourcePath, source) {
315
- // Skip if exists and not forcing
316
- if (fs.existsSync(targetPath) && !force) {
317
- console.log(` Skipped (exists): ${targetPath}`);
318
- return { created: false, source: source ?? 'bundled' };
319
- }
320
- const templatePath = sourcePath ?? join(TEMPLATES_DIR, templateName);
321
- const resolvedSource = source ?? 'bundled';
322
- let content = fs.readFileSync(templatePath, 'utf-8');
323
- // Replace placeholders
324
- for (const [key, value] of Object.entries(replacements)) {
325
- content = content.replaceAll(key, value);
326
- }
327
- fs.writeFileSync(targetPath, content);
328
- console.log(` Created: ${targetPath} (${resolvedSource})`);
329
- return { created: true, source: resolvedSource };
330
- }
331
- /**
332
- * Ensure Night Watch entries are in .gitignore
333
- */
334
- function addToGitignore(cwd) {
335
- const gitignorePath = path.join(cwd, '.gitignore');
336
- const entries = [
337
- {
338
- pattern: '/logs/',
339
- label: '/logs/',
340
- check: (c) => c.includes('/logs/') || /^logs\//m.test(c),
341
- },
342
- {
343
- pattern: CONFIG_FILE_NAME,
344
- label: CONFIG_FILE_NAME,
345
- check: (c) => c.includes(CONFIG_FILE_NAME),
346
- },
347
- { pattern: '*.claim', label: '*.claim', check: (c) => c.includes('*.claim') },
348
- ];
349
- if (!fs.existsSync(gitignorePath)) {
350
- const lines = ['# Night Watch', ...entries.map((e) => e.pattern), ''];
351
- fs.writeFileSync(gitignorePath, lines.join('\n'));
352
- console.log(` Created: ${gitignorePath} (with Night Watch entries)`);
353
- return;
354
- }
355
- const content = fs.readFileSync(gitignorePath, 'utf-8');
356
- const missing = entries.filter((e) => !e.check(content));
357
- if (missing.length === 0) {
358
- console.log(` Skipped (exists): Night Watch entries in .gitignore`);
359
- return;
360
- }
361
- const additions = missing.map((e) => e.pattern).join('\n');
362
- const newContent = content.trimEnd() + '\n\n# Night Watch\n' + additions + '\n';
363
- fs.writeFileSync(gitignorePath, newContent);
364
- console.log(` Updated: ${gitignorePath} (added ${missing.map((e) => e.label).join(', ')})`);
365
- }
366
- function installSkills(cwd, provider, force, templatesDir) {
367
- const skillsTemplatesDir = path.join(templatesDir, 'skills');
368
- if (!fs.existsSync(skillsTemplatesDir)) {
369
- return { location: '', installed: 0, skipped: 0, type: 'none' };
370
- }
371
- const isClaudeProvider = provider === 'claude' || provider.startsWith('claude');
372
- const isCodexProvider = provider === 'codex';
373
- const claudeDir = path.join(cwd, '.claude');
374
- if (isClaudeProvider || fs.existsSync(claudeDir)) {
375
- ensureDir(claudeDir);
376
- const skillsDir = path.join(claudeDir, 'skills');
377
- ensureDir(skillsDir);
378
- let installed = 0;
379
- let skipped = 0;
380
- for (const skillName of NW_SKILLS) {
381
- const templateFile = path.join(skillsTemplatesDir, `${skillName}.md`);
382
- if (!fs.existsSync(templateFile))
383
- continue;
384
- const skillDir = path.join(skillsDir, skillName);
385
- ensureDir(skillDir);
386
- const target = path.join(skillDir, 'SKILL.md');
387
- if (fs.existsSync(target) && !force) {
388
- skipped++;
389
- continue;
390
- }
391
- fs.copyFileSync(templateFile, target);
392
- installed++;
393
- }
394
- return { location: '.claude/skills/', installed, skipped, type: 'claude' };
395
- }
396
- if (isCodexProvider) {
397
- const agentsFile = path.join(cwd, 'AGENTS.md');
398
- const blockFile = path.join(skillsTemplatesDir, '_codex-block.md');
399
- if (!fs.existsSync(blockFile)) {
400
- return { location: '', installed: 0, skipped: 0, type: 'none' };
401
- }
402
- const block = fs.readFileSync(blockFile, 'utf-8');
403
- const marker = '## Night Watch Skills';
404
- if (!fs.existsSync(agentsFile)) {
405
- fs.writeFileSync(agentsFile, block);
406
- return { location: 'AGENTS.md', installed: NW_SKILLS.length, skipped: 0, type: 'codex' };
407
- }
408
- const existing = fs.readFileSync(agentsFile, 'utf-8');
409
- if (existing.includes(marker)) {
410
- if (!force) {
411
- return { location: 'AGENTS.md', installed: 0, skipped: NW_SKILLS.length, type: 'codex' };
412
- }
413
- const withoutSection = existing.replace(/\n\n## Night Watch Skills[\s\S]*$/, '');
414
- fs.writeFileSync(agentsFile, withoutSection + '\n\n' + block);
415
- }
416
- else {
417
- fs.appendFileSync(agentsFile, '\n\n' + block);
418
- }
419
- return { location: 'AGENTS.md', installed: NW_SKILLS.length, skipped: 0, type: 'codex' };
420
- }
421
- return { location: '', installed: 0, skipped: 0, type: 'none' };
422
- }
423
- /**
424
- * Main init command implementation
425
- */
426
- export function initCommand(program) {
427
- program
428
- .command('init')
429
- .description('Initialize night-watch in the current project')
430
- .option('-f, --force', 'Overwrite existing configuration')
431
- .option('-d, --prd-dir <path>', 'Path to PRD directory')
432
- .option('-p, --provider <name>', 'AI provider to use (claude or codex)')
433
- .option('--no-reviewer', 'Disable reviewer cron job')
434
- .action(async (options) => {
435
- const cwd = process.cwd();
436
- const force = options.force || false;
437
- const prdDir = options.prdDir || DEFAULT_PRD_DIR;
438
- const totalSteps = 14;
439
- const interactive = isInteractiveInitSession();
440
- console.log();
441
- header('Night Watch CLI - Initializing');
442
- // Step 1: Verify Node.js version
443
- step(1, totalSteps, 'Checking Node.js version...');
444
- const nodeCheck = checkNodeVersion(22);
445
- if (!nodeCheck.passed) {
446
- uiError(nodeCheck.message);
447
- process.exit(1);
448
- }
449
- success(nodeCheck.message);
450
- // Step 2: Verify git repository
451
- step(2, totalSteps, 'Checking git repository...');
452
- const gitCheck = checkGitRepo(cwd);
453
- if (!gitCheck.passed) {
454
- uiError(gitCheck.message);
455
- console.log('Please run this command from the root of a git repository.');
456
- process.exit(1);
457
- }
458
- success(gitCheck.message);
459
- // Step 3: Detect AI providers
460
- step(3, totalSteps, 'Detecting AI providers...');
461
- let selectedProvider;
462
- if (options.provider) {
463
- // Validate provider flag
464
- if (!BUILT_IN_PRESET_IDS.includes(options.provider)) {
465
- uiError(`Invalid provider "${options.provider}".`);
466
- console.log(`Valid providers: ${BUILT_IN_PRESET_IDS.join(', ')}`);
467
- process.exit(1);
468
- }
469
- selectedProvider = options.provider;
470
- const providerCheck = checkProviderCli(selectedProvider);
471
- if (!providerCheck.passed) {
472
- uiError(providerCheck.message);
473
- console.log(`Install the ${selectedProvider} CLI or rerun with --provider ${detectProviders()[0] ?? 'claude'}.`);
474
- process.exit(1);
475
- }
476
- info(`Using provider from flag: ${selectedProvider}`);
477
- }
478
- else {
479
- // Auto-detect providers
480
- const detectedProviders = detectProviders();
481
- if (detectedProviders.length === 0) {
482
- uiError('No AI provider CLI found.');
483
- console.log('\nPlease install one of the following:');
484
- console.log(' - Claude CLI: https://docs.anthropic.com/en/docs/claude-cli');
485
- console.log(' - Codex CLI: https://github.com/openai/codex');
486
- process.exit(1);
487
- }
488
- else if (detectedProviders.length === 1) {
489
- selectedProvider = detectedProviders[0];
490
- info(`Auto-detected provider: ${selectedProvider}`);
491
- }
492
- else {
493
- if (!interactive) {
494
- selectedProvider = chooseProviderForNonInteractive(detectedProviders);
495
- info(`Multiple providers detected in a non-interactive shell; defaulting to ${selectedProvider}. Use --provider to override.`);
496
- }
497
- else {
498
- try {
499
- selectedProvider = await promptProviderSelection(detectedProviders);
500
- info(`Selected provider: ${selectedProvider}`);
501
- }
502
- catch (err) {
503
- uiError(`${err instanceof Error ? err.message : String(err)}`);
504
- process.exit(1);
505
- }
506
- }
507
- }
508
- }
509
- // Step 4: Check optional GitHub integration prerequisites
510
- step(4, totalSteps, 'Checking GitHub integration prerequisites...');
511
- const remoteStatus = getGitHubRemoteStatus(cwd);
512
- const ghCheck = checkGhCli();
513
- const ghAuthenticated = ghCheck.passed;
514
- if (!remoteStatus.hasGitHubRemote) {
515
- info('No GitHub remote detected. Board setup will be skipped for now.');
516
- }
517
- else if (!ghAuthenticated) {
518
- warn(`${ghCheck.message}. Board setup will be skipped during init.`);
519
- }
520
- else {
521
- success(ghCheck.message);
522
- }
523
- // Step 5: Detect test frameworks for QA bootstrap
524
- step(5, totalSteps, 'Detecting test frameworks...');
525
- const playwrightDetected = detectPlaywright(cwd);
526
- let playwrightStatus = playwrightDetected ? 'detected' : 'not installed';
527
- if (playwrightDetected) {
528
- info('Playwright: detected');
529
- }
530
- else {
531
- info('Playwright: not found');
532
- const installPlaywright = await promptYesNo('Install Playwright for QA now?', true);
533
- if (installPlaywright) {
534
- if (installPlaywrightForQa(cwd)) {
535
- playwrightStatus = 'installed during init';
536
- success('Installed Playwright test runner and Chromium browser.');
537
- }
538
- else {
539
- playwrightStatus = 'install failed';
540
- console.warn(' Warning: Failed to install Playwright automatically. You can install it later.');
541
- }
542
- }
543
- else {
544
- info('Skipping Playwright install. QA can auto-install during execution if enabled.');
545
- }
546
- }
547
- // Set reviewerEnabled from flag (default: true, --no-reviewer sets to false)
548
- const reviewerEnabled = options.reviewer !== false;
549
- // Gather project information
550
- const projectName = getProjectName(cwd);
551
- const defaultBranch = getDefaultBranch(cwd);
552
- // Display project configuration
553
- header('Project Configuration');
554
- label('Project', projectName);
555
- label('Default branch', defaultBranch);
556
- label('Provider', selectedProvider);
557
- label('Reviewer', reviewerEnabled ? 'Enabled' : 'Disabled');
558
- console.log();
559
- // Define replacements for templates
560
- const replacements = {
561
- '${PROJECT_DIR}': cwd,
562
- '${PROJECT_NAME}': projectName,
563
- '${DEFAULT_BRANCH}': defaultBranch,
564
- };
565
- // Step 6: Create PRD directory structure
566
- step(6, totalSteps, 'Creating PRD directory structure...');
567
- const prdDirPath = path.join(cwd, prdDir);
568
- const doneDirPath = path.join(prdDirPath, 'done');
569
- ensureDir(doneDirPath);
570
- success(`Created ${prdDirPath}/`);
571
- success(`Created ${doneDirPath}/`);
572
- // Step 7: Create logs directory
573
- step(7, totalSteps, 'Creating logs directory...');
574
- const logsPath = path.join(cwd, LOG_DIR);
575
- ensureDir(logsPath);
576
- success(`Created ${logsPath}/`);
577
- // Add /logs/ to .gitignore
578
- addToGitignore(cwd);
579
- // Step 8: Create instructions directory and copy templates
580
- step(8, totalSteps, 'Creating instructions directory...');
581
- const instructionsDir = path.join(cwd, 'instructions');
582
- ensureDir(instructionsDir);
583
- success(`Created ${instructionsDir}/`);
584
- // Load existing config (if present) to get templatesDir
585
- const existingConfig = loadConfig(cwd);
586
- const customTemplatesDirPath = path.join(cwd, existingConfig.templatesDir);
587
- const customTemplatesDir = fs.existsSync(customTemplatesDirPath)
588
- ? customTemplatesDirPath
589
- : null;
590
- // Track template sources for summary
591
- const templateSources = [];
592
- // Copy executor.md template
593
- const nwResolution = resolveTemplatePath('executor.md', customTemplatesDir, TEMPLATES_DIR);
594
- const nwResult = processTemplate('executor.md', path.join(instructionsDir, 'executor.md'), replacements, force, nwResolution.path, nwResolution.source);
595
- templateSources.push({ name: 'executor.md', source: nwResult.source });
596
- // Copy prd-executor.md template
597
- const peResolution = resolveTemplatePath('prd-executor.md', customTemplatesDir, TEMPLATES_DIR);
598
- const peResult = processTemplate('prd-executor.md', path.join(instructionsDir, 'prd-executor.md'), replacements, force, peResolution.path, peResolution.source);
599
- templateSources.push({ name: 'prd-executor.md', source: peResult.source });
600
- // Copy pr-reviewer.md template
601
- const prResolution = resolveTemplatePath('pr-reviewer.md', customTemplatesDir, TEMPLATES_DIR);
602
- const prResult = processTemplate('pr-reviewer.md', path.join(instructionsDir, 'pr-reviewer.md'), replacements, force, prResolution.path, prResolution.source);
603
- templateSources.push({ name: 'pr-reviewer.md', source: prResult.source });
604
- // Copy qa.md template
605
- const qaResolution = resolveTemplatePath('qa.md', customTemplatesDir, TEMPLATES_DIR);
606
- const qaResult = processTemplate('qa.md', path.join(instructionsDir, 'qa.md'), replacements, force, qaResolution.path, qaResolution.source);
607
- templateSources.push({ name: 'qa.md', source: qaResult.source });
608
- // Copy audit.md template
609
- const auditResolution = resolveTemplatePath('audit.md', customTemplatesDir, TEMPLATES_DIR);
610
- const auditResult = processTemplate('audit.md', path.join(instructionsDir, 'audit.md'), replacements, force, auditResolution.path, auditResolution.source);
611
- templateSources.push({ name: 'audit.md', source: auditResult.source });
612
- // Copy prd-creator.md template
613
- const plannerResolution = resolveTemplatePath('prd-creator.md', customTemplatesDir, TEMPLATES_DIR);
614
- const plannerResult = processTemplate('prd-creator.md', path.join(instructionsDir, 'prd-creator.md'), replacements, force, plannerResolution.path, plannerResolution.source);
615
- templateSources.push({ name: 'prd-creator.md', source: plannerResult.source });
616
- // Step 9: Create config file
617
- step(9, totalSteps, 'Creating configuration file...');
618
- const configPath = path.join(cwd, CONFIG_FILE_NAME);
619
- if (fs.existsSync(configPath) && !force) {
620
- console.log(` Skipped (exists): ${configPath}`);
621
- }
622
- else {
623
- const config = buildInitConfig({
624
- projectName,
625
- defaultBranch,
626
- provider: selectedProvider,
627
- reviewerEnabled,
628
- prdDir,
629
- });
630
- fs.writeFileSync(configPath, JSON.stringify(config, null, 2) + '\n');
631
- success(`Created ${configPath}`);
632
- }
633
- // Step 10: Create GitHub Project board (only when repo has a GitHub remote)
634
- step(10, totalSteps, 'Setting up GitHub Project board...');
635
- const existingRaw = JSON.parse(fs.readFileSync(configPath, 'utf-8'));
636
- const existingBoard = existingRaw.boardProvider;
637
- let boardSetupStatus = 'Skipped';
638
- if (existingBoard?.projectNumber && !force) {
639
- boardSetupStatus = `Already configured (#${existingBoard.projectNumber})`;
640
- info(`Board already configured (#${existingBoard.projectNumber}), skipping.`);
641
- }
642
- else {
643
- if (!remoteStatus.hasGitHubRemote) {
644
- boardSetupStatus = 'Skipped (no GitHub remote)';
645
- info('No GitHub remote detected — skipping board setup. Run `night-watch board setup` manually.');
646
- }
647
- else if (!ghAuthenticated) {
648
- boardSetupStatus = 'Skipped (gh auth required)';
649
- info('GitHub CLI is not authenticated — run `gh auth login`, then `night-watch board setup`.');
650
- }
651
- else {
652
- try {
653
- const provider = createBoardProvider({ enabled: true, provider: 'github' }, cwd);
654
- const boardTitle = `${projectName} Night Watch`;
655
- const board = await provider.setupBoard(boardTitle);
656
- // Update the config file with the projectNumber
657
- const rawConfig = JSON.parse(fs.readFileSync(configPath, 'utf-8'));
658
- rawConfig.boardProvider = {
659
- enabled: true,
660
- provider: 'github',
661
- projectNumber: board.number,
662
- };
663
- fs.writeFileSync(configPath, JSON.stringify(rawConfig, null, 2) + '\n');
664
- boardSetupStatus = `Created (#${board.number})`;
665
- success(`GitHub Project board "${boardTitle}" ready (#${board.number})`);
666
- }
667
- catch (boardErr) {
668
- boardSetupStatus = 'Failed (manual setup required)';
669
- console.warn(` Warning: Could not set up GitHub Project board: ${boardErr instanceof Error ? boardErr.message : String(boardErr)}`);
670
- info('Run `night-watch board setup` to create the board manually.');
671
- }
672
- }
673
- }
674
- // Step 11: Sync Night Watch labels to GitHub
675
- step(11, totalSteps, 'Syncing Night Watch labels to GitHub...');
676
- let labelSyncStatus = 'Skipped';
677
- if (!remoteStatus.hasGitHubRemote || !ghAuthenticated) {
678
- labelSyncStatus = !remoteStatus.hasGitHubRemote
679
- ? 'Skipped (no GitHub remote)'
680
- : 'Skipped (gh auth required)';
681
- info('Skipping label sync (no GitHub remote or gh not authenticated).');
682
- }
683
- else {
684
- try {
685
- const { NIGHT_WATCH_LABELS } = await import('@night-watch/core');
686
- let created = 0;
687
- for (const label of NIGHT_WATCH_LABELS) {
688
- try {
689
- execSync(`gh label create "${label.name}" --description "${label.description}" --color "${label.color}" --force`, { cwd, encoding: 'utf-8', stdio: ['pipe', 'pipe', 'pipe'] });
690
- created++;
691
- }
692
- catch {
693
- // Label creation is best-effort
694
- }
695
- }
696
- labelSyncStatus = `Synced ${created}/${NIGHT_WATCH_LABELS.length} labels`;
697
- success(`Synced ${created}/${NIGHT_WATCH_LABELS.length} labels to GitHub`);
698
- }
699
- catch (labelErr) {
700
- labelSyncStatus = 'Failed';
701
- warn(`Could not sync labels: ${labelErr instanceof Error ? labelErr.message : String(labelErr)}`);
702
- }
703
- }
704
- // Step 12: Register in global registry
705
- step(12, totalSteps, 'Registering project in global registry...');
706
- try {
707
- const { registerProject } = await import('@night-watch/core');
708
- const entry = registerProject(cwd);
709
- success(`Registered as "${entry.name}" in global registry`);
710
- }
711
- catch (regErr) {
712
- console.warn(` Warning: Could not register in global registry: ${regErr instanceof Error ? regErr.message : String(regErr)}`);
713
- }
714
- // Step 13: Install AI skills
715
- step(13, totalSteps, 'Installing Night Watch skills...');
716
- const skillsResult = installSkills(cwd, selectedProvider, force, TEMPLATES_DIR);
717
- if (skillsResult.installed > 0) {
718
- success(`Installed ${skillsResult.installed} skills to ${skillsResult.location}`);
719
- for (const skillName of NW_SKILLS) {
720
- console.log(` /${skillName}`);
721
- }
722
- }
723
- else if (skillsResult.skipped > 0) {
724
- info(`Skills already installed (use --force to overwrite)`);
725
- }
726
- else if (skillsResult.type === 'none') {
727
- info('No compatible AI skills directory detected — skipping.');
728
- }
729
- // Print summary
730
- step(14, totalSteps, 'Initialization complete!');
731
- // Summary with table
732
- header('Initialization Complete');
733
- const filesTable = createTable({ head: ['Created Files', ''] });
734
- filesTable.push(['PRD Directory', `${prdDir}/done/`]);
735
- filesTable.push(['Logs Directory', `${LOG_DIR}/`]);
736
- filesTable.push(['Instructions', `instructions/executor.md (${templateSources[0].source})`]);
737
- filesTable.push(['', `instructions/prd-executor.md (${templateSources[1].source})`]);
738
- filesTable.push(['', `instructions/pr-reviewer.md (${templateSources[2].source})`]);
739
- filesTable.push(['', `instructions/qa.md (${templateSources[3].source})`]);
740
- filesTable.push(['', `instructions/audit.md (${templateSources[4].source})`]);
741
- filesTable.push(['', `instructions/prd-creator.md (${templateSources[5].source})`]);
742
- filesTable.push(['Config File', CONFIG_FILE_NAME]);
743
- filesTable.push(['Board Setup', boardSetupStatus]);
744
- filesTable.push(['Label Sync', labelSyncStatus]);
745
- filesTable.push(['Global Registry', '~/.night-watch/projects.json']);
746
- let skillsSummary;
747
- if (skillsResult.installed > 0) {
748
- skillsSummary = `${skillsResult.installed} skills → ${skillsResult.location}`;
749
- }
750
- else if (skillsResult.skipped > 0) {
751
- skillsSummary = `Already installed (${skillsResult.location})`;
752
- }
753
- else {
754
- skillsSummary = 'Skipped';
755
- }
756
- filesTable.push(['Skills', skillsSummary]);
757
- console.log(filesTable.toString());
758
- // Configuration summary
759
- header('Configuration');
760
- label('Provider', selectedProvider);
761
- label('Reviewer', reviewerEnabled ? 'Enabled' : 'Disabled');
762
- label('Playwright', playwrightStatus);
763
- console.log();
764
- // Next steps
765
- header('Next Steps');
766
- info(`1. Add your PRD files to ${prdDir}/`);
767
- info('2. Run `night-watch install` to set up cron jobs');
768
- info('3. Run `night-watch doctor` to verify the full setup');
769
- info('4. Or run `night-watch run` to execute PRDs manually');
770
- if (skillsResult.installed > 0) {
771
- info(`5. Use /nw-create-prd, /nw-run, /nw-add-issue and more in your AI assistant`);
772
- }
773
- console.log();
774
- });
775
- }
776
- export default initCommand;
777
- //# sourceMappingURL=init.js.map