@donotdev/cli 0.0.19 → 0.0.21

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 (128) hide show
  1. package/README.md +31 -0
  2. package/dependencies-matrix.json +205 -50
  3. package/dist/bin/commands/agent-setup.js +2 -2
  4. package/dist/bin/commands/build.js +6 -6
  5. package/dist/bin/commands/bump.js +495 -70
  6. package/dist/bin/commands/cacheout.js +6 -6
  7. package/dist/bin/commands/coach.js +6 -6
  8. package/dist/bin/commands/create-app.js +24 -16
  9. package/dist/bin/commands/create-project.js +114 -18
  10. package/dist/bin/commands/db.js +142136 -0
  11. package/dist/bin/commands/deploy.js +354 -126
  12. package/dist/bin/commands/dev.js +6 -6
  13. package/dist/bin/commands/doctor.js +140 -33
  14. package/dist/bin/commands/emu.js +6 -6
  15. package/dist/bin/commands/format.js +6 -6
  16. package/dist/bin/commands/get-demo.js +11 -6
  17. package/dist/bin/commands/make-admin.js +14210 -13770
  18. package/dist/bin/commands/preview.js +6 -6
  19. package/dist/bin/commands/seed.js +142426 -0
  20. package/dist/bin/commands/setup-cicd.js +8904 -0
  21. package/dist/bin/commands/setup.js +259 -212
  22. package/dist/bin/commands/staging.js +361 -127
  23. package/dist/bin/commands/sync-secrets.js +55 -33
  24. package/dist/bin/commands/type-check.js +16 -10
  25. package/dist/bin/commands/wai.js +6 -6
  26. package/dist/bin/dndev.js +194 -188
  27. package/dist/bin/donotdev.js +139 -189
  28. package/dist/index.js +468 -144
  29. package/package.json +1 -1
  30. package/templates/app-demo/.env.example +1 -0
  31. package/templates/{root-consumer → app-demo}/entities/ExampleEntity.ts.example +15 -9
  32. package/templates/app-demo/index.html.example +1 -1
  33. package/templates/app-demo/public/apple-touch-icon.png.example +0 -0
  34. package/templates/app-demo/public/favicon.svg.example +1 -0
  35. package/templates/app-demo/public/icon-192x192.png.example +0 -0
  36. package/templates/app-demo/public/icon-512x512.png.example +0 -0
  37. package/templates/app-demo/src/App.tsx.example +3 -1
  38. package/templates/app-demo/src/config/app.ts.example +1 -0
  39. package/templates/app-demo/src/entities/booking.ts.example +75 -0
  40. package/templates/app-demo/src/entities/onboarding.ts.example +160 -0
  41. package/templates/app-demo/src/entities/product.ts.example +12 -0
  42. package/templates/app-demo/src/entities/quote.ts.example +70 -0
  43. package/templates/app-demo/src/pages/ChangelogPage.tsx.example +28 -1
  44. package/templates/app-demo/src/pages/ConditionalFormPage.tsx.example +88 -0
  45. package/templates/app-demo/src/pages/DashboardPage.tsx.example +2 -0
  46. package/templates/app-demo/src/pages/HomePage.tsx.example +355 -2
  47. package/templates/app-demo/src/pages/OnboardingPage.tsx.example +47 -0
  48. package/templates/app-demo/src/pages/PricingPage.tsx.example +28 -1
  49. package/templates/app-demo/src/pages/ProductsPage.tsx.example +2 -0
  50. package/templates/app-demo/src/pages/ProfilePage.tsx.example +2 -0
  51. package/templates/app-demo/src/pages/SettingsPage.tsx.example +2 -0
  52. package/templates/app-demo/src/pages/ShowcaseDetailPage.tsx.example +22 -16
  53. package/templates/app-demo/src/pages/ShowcasePage.tsx.example +3 -1
  54. package/templates/app-demo/src/pages/components/ComponentRenderer.tsx.example +147 -51
  55. package/templates/app-demo/src/pages/components/ComponentsData.tsx.example +103 -21
  56. package/templates/app-demo/src/pages/components/componentConfig.ts.example +139 -59
  57. package/templates/app-demo/src/pages/legal/LegalPage.tsx.example +12 -1
  58. package/templates/app-demo/src/pages/legal/PrivacyPage.tsx.example +10 -1
  59. package/templates/app-demo/src/pages/legal/TermsPage.tsx.example +10 -1
  60. package/templates/app-demo/src/themes.css.example +289 -77
  61. package/templates/app-demo/stats.html.example +4949 -0
  62. package/templates/app-dndev/index.html.example +164 -0
  63. package/templates/app-dndev/public/logo.svg.example +1 -0
  64. package/templates/app-dndev/public/manifest.json.example +10 -0
  65. package/templates/app-dndev/src/App.tsx.example +35 -0
  66. package/templates/app-dndev/src/components/CockpitLayout.css.example +181 -0
  67. package/templates/app-dndev/src/components/CockpitLayout.tsx.example +209 -0
  68. package/templates/app-dndev/src/components/Kanban.css.example +385 -0
  69. package/templates/app-dndev/src/components/ModeToggle.tsx.example +32 -0
  70. package/templates/app-dndev/src/components/OverlaySlot.tsx.example +68 -0
  71. package/templates/app-dndev/src/components/TerminalPanel.css.example +228 -0
  72. package/templates/app-dndev/src/components/TerminalPanel.tsx.example +714 -0
  73. package/templates/app-dndev/src/components/markdown-prose.css.example +49 -0
  74. package/templates/app-dndev/src/components/phases/CaptainLog.tsx.example +107 -0
  75. package/templates/app-dndev/src/components/phases/ContextTabs.tsx.example +352 -0
  76. package/templates/app-dndev/src/components/phases/PhaseCard.tsx.example +126 -0
  77. package/templates/app-dndev/src/components/phases/PhaseDetail.tsx.example +147 -0
  78. package/templates/app-dndev/src/components/phases/ReviewPanel.tsx.example +115 -0
  79. package/templates/app-dndev/src/components/phases/phaseData.ts.example +366 -0
  80. package/templates/app-dndev/src/config/app.ts.example +103 -0
  81. package/templates/app-dndev/src/config/commands.ts.example +171 -0
  82. package/templates/app-dndev/src/config/legal.ts.example +170 -0
  83. package/templates/app-dndev/src/config/providers.ts.example +7 -0
  84. package/templates/app-dndev/src/globals.css.example +10 -0
  85. package/templates/app-dndev/src/hooks/useDndevFile.ts.example +144 -0
  86. package/templates/app-dndev/src/main.tsx.example +21 -0
  87. package/templates/app-dndev/src/pages/BoardPage.tsx.example +640 -0
  88. package/templates/app-dndev/src/pages/GrillPage.tsx.example +658 -0
  89. package/templates/app-dndev/src/pages/HomePage.tsx.example +347 -0
  90. package/templates/app-dndev/src/pages/NotFoundPage.tsx.example +33 -0
  91. package/templates/app-dndev/src/pages/PhasesPage.tsx.example +137 -0
  92. package/templates/app-dndev/src/pages/SettingsPage.tsx.example +64 -0
  93. package/templates/app-dndev/src/pages/legal/LegalNoticePage.tsx.example +75 -0
  94. package/templates/app-dndev/src/pages/legal/PrivacyPage.tsx.example +69 -0
  95. package/templates/app-dndev/src/pages/legal/TermsPage.tsx.example +71 -0
  96. package/templates/app-dndev/src/stores/dndevStore.ts.example +386 -0
  97. package/templates/app-dndev/src/themes.css.example +161 -0
  98. package/templates/app-dndev/terminal-sidecar.cjs.example +341 -0
  99. package/templates/app-dndev/tsconfig.json.example +9 -0
  100. package/templates/app-dndev/vite.config.ts.example +24 -0
  101. package/templates/app-vite/index.html.example +1 -1
  102. package/templates/functions-supabase/supabase/functions/.env.example +0 -2
  103. package/templates/root-consumer/.claude/commands/grill.md.example +86 -8
  104. package/templates/root-consumer/.dndev.secrets.example +32 -0
  105. package/templates/root-consumer/.gitignore.example +3 -0
  106. package/templates/root-consumer/AI.md.example +4 -0
  107. package/templates/root-consumer/entities/index.ts.example +2 -5
  108. package/templates/root-consumer/guides/dndev/COMPONENTS_ATOMIC.md.example +4 -0
  109. package/templates/root-consumer/guides/dndev/ENV_SETUP.md.example +23 -20
  110. package/templates/root-consumer/guides/dndev/INDEX.md.example +1 -0
  111. package/templates/root-consumer/guides/dndev/SETUP_BILLING.md.example +3 -7
  112. package/templates/root-consumer/guides/dndev/SETUP_CICD.md.example +115 -0
  113. package/templates/root-consumer/guides/dndev/SETUP_CRUD.md.example +41 -0
  114. package/templates/root-consumer/guides/dndev/SETUP_SUPABASE.md.example +13 -18
  115. package/templates/root-consumer/guides/dndev/SETUP_VERCEL.md.example +17 -12
  116. package/templates/root-consumer/guides/wai-way/WAI_WAY_CLI.md.example +185 -251
  117. package/templates/root-consumer/guides/wai-way/agents/extractor.md.example +26 -8
  118. package/templates/root-consumer/guides/wai-way/blueprints/0_brainstorm.md.example +66 -49
  119. package/templates/root-consumer/guides/wai-way/blueprints/1_scaffold.md.example +6 -5
  120. package/templates/root-consumer/guides/wai-way/blueprints/2_entities.md.example +9 -9
  121. package/templates/root-consumer/guides/wai-way/blueprints/3_compose.md.example +1 -1
  122. package/templates/root-consumer/guides/wai-way/blueprints/4_configure.md.example +7 -6
  123. package/templates/root-consumer/guides/wai-way/context_map.json.example +51 -20
  124. package/templates/root-consumer/guides/wai-way/hld_template.md.example +138 -0
  125. package/templates/root-consumer/guides/wai-way/lld_template.md.example +103 -0
  126. package/templates/root-consumer/guides/wai-way/prd_template.md.example +140 -0
  127. /package/templates/{root-consumer → app-demo}/entities/Contact.ts.example +0 -0
  128. /package/templates/{root-consumer → app-demo}/entities/demo.ts.example +0 -0
@@ -0,0 +1,341 @@
1
+ /**
2
+ * @fileoverview Terminal sidecar — real PTY via node-pty + WebSocket.
3
+ * Runs under Node (not Bun) to guarantee node-pty native addon works.
4
+ *
5
+ * @description Self-contained process: owns a WebSocket server + PTY lifecycle.
6
+ * Spawned by DndevPlugin.js with: spawn('node', [thisFile], { cwd: appRoot })
7
+ *
8
+ * Protocol (JSON over WebSocket):
9
+ * Client → Server: start, input, resize, kill
10
+ * Server → Client: started, output, exit, error
11
+ *
12
+ * @env {string} TERMINAL_PORT - WebSocket port (default: 24681)
13
+ * @env {string} TERMINAL_CWD - Working directory for shells (default: process.cwd())
14
+ * @env {string} TERMINAL_SHELL - Override shell binary (e.g. 'pwsh.exe', 'zsh')
15
+ */
16
+
17
+ 'use strict';
18
+
19
+ const path = require('path');
20
+ const { createRequire } = require('module');
21
+
22
+ const appRequire = createRequire(path.join(__dirname, 'package.json'));
23
+ const pty = appRequire('node-pty');
24
+ const { WebSocketServer } = appRequire('ws');
25
+
26
+ // ============================================================================
27
+ // SHELL CONFIG — override via env TERMINAL_SHELL or edit defaults below
28
+ // ============================================================================
29
+
30
+ /**
31
+ * Resolve the shell binary to spawn.
32
+ * Priority: TERMINAL_SHELL env > platform default
33
+ *
34
+ * Platform defaults:
35
+ * Windows → wsl.exe (Linux shell inside Windows via WSL)
36
+ * macOS → zsh
37
+ * Linux → $SHELL or bash
38
+ * @returns {string} Shell binary path or name
39
+ */
40
+ function resolveShell() {
41
+ if (process.env.TERMINAL_SHELL) return process.env.TERMINAL_SHELL;
42
+
43
+ if (process.platform === 'win32') {
44
+ // Default: WSL (Linux shell inside Windows)
45
+ // To use PowerShell instead, uncomment ONE of:
46
+ // return 'pwsh.exe'; // PowerShell 7+ (recommended)
47
+ // return 'powershell.exe'; // Windows PowerShell 5.1 (legacy)
48
+ return 'wsl.exe';
49
+ }
50
+
51
+ return process.env.SHELL || '/bin/bash';
52
+ }
53
+
54
+ /**
55
+ * Build a clean env for the child shell.
56
+ * Strips node/bun/turbo internals. On Windows, ensures HOME/SHELL aren't 'undefined'.
57
+ * @returns {Record<string, string>}
58
+ */
59
+ function buildCleanEnv() {
60
+ const cleanEnv = Object.fromEntries(
61
+ Object.entries(process.env).filter(([k, v]) =>
62
+ v !== undefined &&
63
+ !k.startsWith('NODE_CHANNEL') &&
64
+ !k.startsWith('TURBO_') &&
65
+ !k.startsWith('BUN_') &&
66
+ k !== 'NODE_OPTIONS' &&
67
+ k !== 'FORCE_COLOR'
68
+ )
69
+ );
70
+ cleanEnv.FORCE_COLOR = '1';
71
+ cleanEnv.TERM = 'xterm-256color';
72
+
73
+ // Windows: HOME and SHELL don't exist natively — set sane defaults
74
+ if (process.platform === 'win32') {
75
+ if (!cleanEnv.HOME) cleanEnv.HOME = cleanEnv.USERPROFILE || '';
76
+ if (!cleanEnv.SHELL) delete cleanEnv.SHELL;
77
+ }
78
+
79
+ return cleanEnv;
80
+ }
81
+
82
+ /**
83
+ * Resolve cwd for the shell.
84
+ * IMPORTANT: cwd is passed to node-pty's spawn(), which runs on the host OS.
85
+ * On Windows, this MUST be a native Windows path (e.g. C:\ws\dndev).
86
+ * WSL automatically maps the Windows cwd to /mnt/c/... inside the Linux shell.
87
+ * @returns {string} Working directory path (native OS path)
88
+ */
89
+ function resolveCwd() {
90
+ const cwd = process.env.TERMINAL_CWD;
91
+ if (!cwd) {
92
+ throw new Error('TERMINAL_CWD env is required — set it in DndevPlugin.js');
93
+ }
94
+ return cwd;
95
+ }
96
+
97
+ /**
98
+ * Validate a tab name — prevents log injection and memory abuse.
99
+ * @param {unknown} tab
100
+ * @returns {boolean}
101
+ */
102
+ function isValidTab(tab) {
103
+ return typeof tab === 'string' && tab.length > 0 && tab.length <= 64 && /^[\w-]+$/.test(tab);
104
+ }
105
+
106
+ /**
107
+ * Clamp cols/rows to safe integer ranges for node-pty.
108
+ * @param {unknown} value
109
+ * @param {number} fallback
110
+ * @param {number} [min=1]
111
+ * @param {number} [max=500]
112
+ * @returns {number}
113
+ */
114
+ function clampDimension(value, fallback, min = 1, max = 500) {
115
+ const n = typeof value === 'number' ? Math.floor(value) : fallback;
116
+ return Math.max(min, Math.min(max, n));
117
+ }
118
+
119
+ // ============================================================================
120
+ // CRASH GUARD — auto-respawn on immediate PTY death (ConPTY race condition)
121
+ // ============================================================================
122
+
123
+ /** @type {number} If PTY dies within this window, treat as crash */
124
+ const CRASH_THRESHOLD_MS = 3000;
125
+ /** @type {number} Max auto-respawn retries per tab */
126
+ const MAX_RETRIES = 2;
127
+ /** @type {Map<string, { count: number }>} Track crash retries per tab */
128
+ const spawnAttempts = new Map();
129
+ /** @type {Set<string>} Tabs killed intentionally — suppress duplicate onExit broadcast */
130
+ const killedTabs = new Set();
131
+ /** @type {Set<string>} Tabs with a pending crash-guard respawn timer */
132
+ const pendingRespawns = new Set();
133
+
134
+ // ============================================================================
135
+ // INIT
136
+ // ============================================================================
137
+
138
+ // Guard: node-pty requires real Node, not Bun
139
+ if (typeof globalThis.Bun !== 'undefined') {
140
+ console.error('[sidecar] FATAL: running under Bun — node-pty requires real Node. execPath=' + process.execPath);
141
+ process.exit(1);
142
+ }
143
+
144
+ const PORT = parseInt(process.env.TERMINAL_PORT || '24681', 10);
145
+ if (!Number.isFinite(PORT) || PORT < 1 || PORT > 65535) {
146
+ console.error(`[sidecar] FATAL: invalid TERMINAL_PORT: ${process.env.TERMINAL_PORT}`);
147
+ process.exit(1);
148
+ }
149
+
150
+ console.error('[sidecar] Node ' + process.version + ' pid=' + process.pid);
151
+
152
+ /** @type {Map<string, import('node-pty').IPty>} Active PTY processes by tab id */
153
+ const ptys = new Map();
154
+ const wss = new WebSocketServer({ port: PORT });
155
+
156
+ /**
157
+ * Broadcast a JSON message to all connected WebSocket clients.
158
+ * @param {Record<string, unknown>} msg
159
+ */
160
+ function broadcast(msg) {
161
+ const data = JSON.stringify(msg);
162
+ for (const client of wss.clients) {
163
+ if (client.readyState === 1) client.send(data);
164
+ }
165
+ }
166
+
167
+ /**
168
+ * Spawn a PTY for the given tab. Handles crash-respawn internally.
169
+ * Wrapped in try/catch so failures in the setTimeout retry path don't crash the sidecar.
170
+ * @param {string} tab - Tab identifier
171
+ * @param {number} cols - Terminal columns
172
+ * @param {number} rows - Terminal rows
173
+ */
174
+ function spawnPty(tab, cols, rows) {
175
+ try {
176
+ const shell = resolveShell();
177
+ const cleanEnv = buildCleanEnv();
178
+ const cwd = resolveCwd();
179
+ const safeCols = clampDimension(cols, 120);
180
+ const safeRows = clampDimension(rows, 30);
181
+
182
+ console.error(`[sidecar] spawning: ${shell} cwd=${cwd} cols=${safeCols} rows=${safeRows}`);
183
+
184
+ const p = pty.spawn(shell, [], {
185
+ name: 'xterm-256color',
186
+ cols: safeCols,
187
+ rows: safeRows,
188
+ cwd,
189
+ env: cleanEnv,
190
+ });
191
+
192
+ const spawnedAt = Date.now();
193
+ console.error(`[sidecar] PTY "${tab}" spawned: pid=${p.pid}`);
194
+ ptys.set(tab, p);
195
+ broadcast({ type: 'started', tab });
196
+
197
+ p.onData((data) => {
198
+ broadcast({ type: 'output', tab, data });
199
+ });
200
+
201
+ p.onExit(({ exitCode, signal }) => {
202
+ console.error(`[sidecar] PTY "${tab}" exited: code=${exitCode} signal=${signal} pid=${p.pid}`);
203
+ ptys.delete(tab);
204
+
205
+ // If killed intentionally via 'kill' command, the handler already broadcast 'exit'
206
+ if (killedTabs.has(tab)) {
207
+ killedTabs.delete(tab);
208
+ return;
209
+ }
210
+
211
+ const livedMs = Date.now() - spawnedAt;
212
+
213
+ // Crash guard: if the PTY died almost instantly, auto-respawn
214
+ if (livedMs < CRASH_THRESHOLD_MS && exitCode !== 0) {
215
+ const attempts = spawnAttempts.get(tab) || { count: 0 };
216
+ attempts.count++;
217
+ spawnAttempts.set(tab, attempts);
218
+
219
+ if (attempts.count <= MAX_RETRIES) {
220
+ console.error(`[sidecar] PTY "${tab}" crashed after ${livedMs}ms — auto-respawn ${attempts.count}/${MAX_RETRIES}`);
221
+ pendingRespawns.add(tab);
222
+ setTimeout(() => {
223
+ pendingRespawns.delete(tab);
224
+ // If client already reconnected during the delay, skip
225
+ if (ptys.has(tab)) return;
226
+ spawnPty(tab, safeCols, safeRows);
227
+ }, 300);
228
+ return;
229
+ }
230
+ console.error(`[sidecar] PTY "${tab}" exhausted ${MAX_RETRIES} retries — giving up`);
231
+ }
232
+
233
+ // Normal exit or retries exhausted — notify client
234
+ spawnAttempts.delete(tab);
235
+ broadcast({ type: 'exit', tab, code: exitCode });
236
+ });
237
+ } catch (err) {
238
+ console.error(`[sidecar] PTY "${tab}" spawn failed:`, err.message);
239
+ ptys.delete(tab);
240
+ spawnAttempts.delete(tab);
241
+ broadcast({ type: 'error', tab, message: `Spawn failed: ${err.message}` });
242
+ }
243
+ }
244
+
245
+ // ============================================================================
246
+ // WEBSOCKET SERVER
247
+ // ============================================================================
248
+
249
+ wss.on('connection', (ws) => {
250
+ // Tell new client about already-running tabs
251
+ for (const tab of ptys.keys()) {
252
+ ws.send(JSON.stringify({ type: 'started', tab }));
253
+ }
254
+
255
+ ws.on('message', (raw) => {
256
+ try {
257
+ const msg = JSON.parse(raw.toString());
258
+
259
+ // Validate tab name on all messages that carry one
260
+ if (msg.tab !== undefined && !isValidTab(msg.tab)) return;
261
+
262
+ switch (msg.type) {
263
+ case 'start': {
264
+ if (ptys.has(msg.tab)) {
265
+ ws.send(JSON.stringify({ type: 'started', tab: msg.tab }));
266
+ return;
267
+ }
268
+ // If crash guard is about to respawn, let client take over instead
269
+ if (pendingRespawns.has(msg.tab)) {
270
+ pendingRespawns.delete(msg.tab);
271
+ }
272
+ spawnAttempts.delete(msg.tab);
273
+ spawnPty(
274
+ msg.tab,
275
+ clampDimension(msg.cols, 120),
276
+ clampDimension(msg.rows, 30),
277
+ );
278
+ break;
279
+ }
280
+ case 'input':
281
+ ptys.get(msg.tab)?.write(msg.data);
282
+ break;
283
+ case 'resize': {
284
+ const p = ptys.get(msg.tab);
285
+ if (p) {
286
+ p.resize(
287
+ clampDimension(msg.cols, 80),
288
+ clampDimension(msg.rows, 24),
289
+ );
290
+ }
291
+ break;
292
+ }
293
+ case 'kill': {
294
+ const p = ptys.get(msg.tab);
295
+ if (p) {
296
+ killedTabs.add(msg.tab);
297
+ p.kill();
298
+ ptys.delete(msg.tab);
299
+ }
300
+ spawnAttempts.delete(msg.tab);
301
+ broadcast({ type: 'exit', tab: msg.tab, code: -1 });
302
+ break;
303
+ }
304
+ }
305
+ } catch (err) {
306
+ console.error('[sidecar] message error:', err.message);
307
+ }
308
+ });
309
+ });
310
+
311
+ wss.on('listening', () => {
312
+ const msg = `[dndev] terminal ready on ws://localhost:${PORT}`;
313
+ console.log(msg);
314
+ if (process.send) process.send({ type: 'ready', port: PORT });
315
+ });
316
+
317
+ wss.on('error', (err) => {
318
+ console.error('[sidecar] ws server error:', err.message);
319
+ if (err.code === 'EADDRINUSE') {
320
+ console.error(`[sidecar] port ${PORT} in use — exiting (DndevPlugin will retry)`);
321
+ process.exit(1);
322
+ }
323
+ });
324
+
325
+ // ============================================================================
326
+ // CLEANUP
327
+ // ============================================================================
328
+
329
+ function cleanup() {
330
+ for (const [, p] of ptys) {
331
+ try { p.kill(); } catch { /* already dead */ }
332
+ }
333
+ ptys.clear();
334
+ wss.close(() => process.exit(0));
335
+ // Fallback if wss.close hangs
336
+ setTimeout(() => process.exit(0), 1000);
337
+ }
338
+
339
+ process.on('SIGTERM', cleanup);
340
+ process.on('SIGINT', cleanup);
341
+ process.on('disconnect', cleanup);
@@ -0,0 +1,9 @@
1
+ {
2
+ "extends": "../../tsconfig.json",
3
+ "compilerOptions": {
4
+ "baseUrl": ".",
5
+ "types": ["node", "vite/client"]
6
+ },
7
+ "include": ["src/**/*", "vite.config.ts"],
8
+ "exclude": ["node_modules", "dist"]
9
+ }
@@ -0,0 +1,24 @@
1
+ import { defineViteConfig } from '@donotdev/core/vite';
2
+ import { appConfig } from './src/config/app';
3
+
4
+ export default defineViteConfig({
5
+ appConfig,
6
+ dndev: true,
7
+ debug: false,
8
+ optimizeDeps: {
9
+ include: [
10
+ '@dnd-kit/core',
11
+ '@dnd-kit/sortable',
12
+ '@dnd-kit/utilities',
13
+ 'react-markdown',
14
+ 'remark-gfm'
15
+ ],
16
+ },
17
+ server: {
18
+ port: 3174,
19
+ https: false,
20
+ watch: {
21
+ ignored: ['**/.dndev/**'],
22
+ },
23
+ },
24
+ });
@@ -43,7 +43,7 @@
43
43
  box-sizing: border-box;
44
44
  }
45
45
  body {
46
- font-family: 'Inter', var(--font-family, ui-sans-serif, system-ui, -apple-system, sans-serif);
46
+ font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Helvetica Neue', Arial, sans-serif;
47
47
  line-height: 1.5;
48
48
  -webkit-font-smoothing: antialiased;
49
49
  -moz-osx-font-smoothing: grayscale;
@@ -4,10 +4,8 @@
4
4
  # Get these from: https://supabase.com/dashboard > your project > Settings
5
5
  #
6
6
  # Secret key: Settings > API > service_role key (or "Secret key" on new projects)
7
- # DB URL: Settings > Database > Connection string > URI
8
7
  #
9
8
  # These are SERVER-SIDE ONLY. Never expose in client code.
10
9
  # =============================================================================
11
10
 
12
11
  SUPABASE_SECRET_KEY=
13
- SUPABASE_DB_URL=
@@ -16,15 +16,93 @@ Evaluate for:
16
16
  - Missing or incorrect TypeScript types
17
17
  - @donotdev component usage without `lookup_symbol` verification
18
18
 
19
- Output format — structured critique, one item per line:
20
- ```
21
- [BLOCKER] <file>:<line> — <problem>
22
- [WARN] <file>:<line> — <problem>
23
- [NOTE] <file>:<line> — <problem>
24
- ```
25
-
26
19
  Rules:
27
20
  - NEVER suggest fixes. Report problems only.
28
21
  - NEVER skip BLOCKER items to be polite.
29
22
  - If there are no issues at a severity level, omit that level entirely.
30
- - End with a one-line verdict: SHIP / DO NOT SHIP.
23
+ - **Quality > quantity. 15 real issues >>> 60 padded items.**
24
+
25
+ ## Output — 3-step lifecycle
26
+
27
+ The grill report is a **living queue**. Each run cleans up resolved items, archives them, then appends new findings.
28
+
29
+ ### Step 1 — Clean up + archive
30
+
31
+ Read existing `.dndev/grill-report.json`. If it exists and has items:
32
+
33
+ 1. Separate items into **resolved** (`status` = `fixed`, `resolved`, or `rejected`) and **surviving** (`pending`, `fixing`, or any other status).
34
+ 2. Append a history entry to `.dndev/grill-history.json` (read existing array or start with `[]`):
35
+ ```json
36
+ {
37
+ "date": "<now ISO>",
38
+ "gitSha": "<short git HEAD>",
39
+ "target": "<previous report target>",
40
+ "verdict": "<previous report verdict>",
41
+ "blockers": <previous blocker count>,
42
+ "warnings": <previous warning count>,
43
+ "notes": <previous note count>,
44
+ "total": <previous items.length>,
45
+ "resolved": <resolved count>,
46
+ "carried": <surviving count>
47
+ }
48
+ ```
49
+ 3. Keep the surviving items — they carry over into the updated report.
50
+
51
+ If no existing report or no items, skip this step.
52
+
53
+ ### Step 2 — Scan
54
+
55
+ Produce new findings from the target files. **Deduplicate** against surviving items from Step 1: if a new finding matches an existing item on `file` + `line` + `issue` (fuzzy match on issue text), skip it.
56
+
57
+ ### Step 3 — Write report
58
+
59
+ Merge surviving items from Step 1 + new findings from Step 2. Re-number `id` fields sequentially starting at 1. Write to `.dndev/grill-report.json`:
60
+
61
+ ```json
62
+ {
63
+ "generated": "<now ISO>",
64
+ "gitSha": "<short git HEAD>",
65
+ "target": "<description of what was reviewed>",
66
+ "verdict": "SHIP" | "DO NOT SHIP",
67
+ "items": [
68
+ {
69
+ "id": 1,
70
+ "severity": "blocker" | "warn" | "note",
71
+ "file": "src/pages/Foo.tsx",
72
+ "line": 42,
73
+ "issue": "Short description of the problem",
74
+ "context": "Optional: why this matters, what could go wrong",
75
+ "category": "security" | "architecture" | "edge-case" | "types" | "dead-code" | "consistency" | "dx" | "docs" | "performance",
76
+ "status": "pending",
77
+ "verified": true
78
+ }
79
+ ]
80
+ }
81
+ ```
82
+
83
+ Verdict is based on the **merged** items (carried + new). If any blocker exists → DO NOT SHIP.
84
+
85
+ ### Field rules
86
+
87
+ - `gitSha` — Run `git rev-parse --short HEAD`. Required.
88
+ - `verified` — Always `true` in final output.
89
+ - New items always get `status: "pending"`. Carried items keep their existing status.
90
+
91
+ ### Fixing findings
92
+
93
+ When asked to fix grill findings (not during a scan — during a separate fix request):
94
+
95
+ 1. Apply the code fix.
96
+ 2. Update `.dndev/grill-report.json`: set `status: "fixed"` on each resolved item.
97
+ 3. Set `lastReviewed` to current ISO timestamp.
98
+
99
+ This ensures the report reflects reality. Next grill run archives fixed items to history.
100
+
101
+ ### General rules
102
+
103
+ - NEVER suggest fixes. Report problems only — during a scan.
104
+ - NEVER skip BLOCKER items.
105
+ - **Quality > quantity. 15 real issues >>> 60 padded items** (for new findings — carried items don't count toward this cap).
106
+ - Group by file, sort by line number.
107
+ - After writing, print: `Cleaned N resolved items → history. Carried M items. Added K new findings. Total: T items.`
108
+ - Print verdict: SHIP / DO NOT SHIP.
@@ -0,0 +1,32 @@
1
+ # ─────────────────────────────────────────────────────────────────────────────
2
+ # .dndev.secrets — All secret keys in one place
3
+ # ─────────────────────────────────────────────────────────────────────────────
4
+ #
5
+ # This file is gitignored. Copy from .dndev.secrets.example and fill in values.
6
+ # Resolution order: process.env (CI) → .dndev.secrets (local) → legacy paths
7
+ #
8
+ # For public config (VITE_*, NEXT_PUBLIC_*), use apps/<app>/.env instead.
9
+ # For Firebase service account, keep service-account-key.json as-is.
10
+ #
11
+
12
+ {{#vercel}}
13
+ # ── Vercel ──────────────────────────────────────────────────────────────────
14
+ # Get from: https://vercel.com/account/tokens
15
+ VERCEL_TOKEN=
16
+
17
+ {{/vercel}}
18
+ {{#supabase}}
19
+ # ── Supabase ────────────────────────────────────────────────────────────────
20
+ # Secret key: https://supabase.com/dashboard → Settings → API → service_role key
21
+ # Access token: https://supabase.com/dashboard/account/tokens (needed for DB migrations)
22
+ SUPABASE_SECRET_KEY=
23
+ SUPABASE_ACCESS_TOKEN=
24
+
25
+ {{/supabase}}
26
+ {{#stripe}}
27
+ # ── Stripe ──────────────────────────────────────────────────────────────────
28
+ # Get from: https://dashboard.stripe.com/apikeys (secret key)
29
+ # https://dashboard.stripe.com/webhooks (webhook secret)
30
+ STRIPE_SECRET_KEY=
31
+ STRIPE_WEBHOOK_SECRET=
32
+ {{/stripe}}
@@ -20,6 +20,9 @@ stats.html
20
20
  # Note: .env.local and .env.*.local are gitignored (local overrides)
21
21
  # .env.production.local is gitignored (production secrets)
22
22
 
23
+ # Centralized secrets file (all secret keys in one place)
24
+ .dndev.secrets
25
+
23
26
  # IDE files
24
27
  .vscode/*
25
28
  !.vscode/extensions.json
@@ -88,6 +88,10 @@ Run `dndev --help` for the full command list.
88
88
  - **RTL safe** — use `start`/`end`, never `left`/`right`
89
89
  - **Import order** — React → vendors → @donotdev → relative
90
90
  - **Import convention** — always `@donotdev/<pkg>` top-level, never sub-paths
91
+ - **NO native HTML elements** — never use `<div>`, `<span>`, `<p>`, `<h1-6>`, `<button>`, `<a>`, `<input>`, `<textarea>`, `<select>`, `<form>`, `<table>`, `<ul>`, `<ol>`, `<li>`, `<img>`, `<section>`, `<nav>`, `<header>`, `<footer>` in @donotdev files. Use framework components: Stack, Card, Text, Button, Link, TextInput, Select, Form, DataTable, List, Image, Section, Navigation, Header, Footer. See `get_guide("COMPONENTS_ATOMIC")`
92
+ - **NO custom CSS** — never create `.css`, `.module.css`, `.scss`, `.sass`, or `.less` files. All styling is done through framework component props, variant tokens, and theme configuration
93
+ - **NO custom components** — never create files in `components/`. Compose pages using framework components only. If a component is missing, say what you need and STOP
94
+ - **NO inventing props** — only use props returned by `lookup_symbol()`. Common hallucination traps that DO NOT exist: `size`, `tone`, `color`, `padding`, `margin`, `spacing`, `columns`, `background`, `fields`
91
95
  - **Framework-first** — if something's missing, say what and stop
92
96
  - **No .md file creation** — never create documentation/analysis/summary .md files unless explicitly asked. Session notes go in `.dndev/`
93
97
  - **Follow existing patterns** — the scaffolded files ARE your documentation
@@ -2,17 +2,14 @@
2
2
  * @fileoverview Entity Exports
3
3
  *
4
4
  * Export all your entities from here for easy importing.
5
+ * See entities/examples/ for reference entity definitions.
5
6
  *
6
7
  * USAGE:
7
8
  * ```tsx
8
- * import { contactEntity, productEntity } from '../entities';
9
+ * import { customerEntity } from '../entities';
9
10
  * ```
10
11
  */
11
12
 
12
- // Scaffolded examples — rename or replace with your own entities:
13
- export { contactEntity } from './Contact';
14
- export { productEntity } from './ExampleEntity';
15
-
16
13
  // Add your entities:
17
14
  // export { customerEntity } from './Customer';
18
15
  // export { orderEntity } from './Order';
@@ -38,6 +38,7 @@ These are the only ways one should handle layout to get to quick results functio
38
38
  - **ActionButton** - Button with async action handling and loading states.
39
39
  - **FileButton** - Button that triggers file input selection.
40
40
  - **PortalButton** - Button that opens content in a portal overlay.
41
+ - **ButtonGroup** - Visual grouping of buttons with joined borders. Supports horizontal/vertical orientation, variant propagation, and items-based API.
41
42
 
42
43
  ---
43
44
 
@@ -53,6 +54,7 @@ These are the only ways one should handle layout to get to quick results functio
53
54
  - **Combobox** - Searchable combobox with autocomplete functionality.
54
55
  - **Switch** - Toggle switch component.
55
56
  - **Slider** - Range slider for numeric input.
57
+ - **ColorPicker** - Color selection with preset swatch grid, native color input, and ARIA radiogroup pattern. Built-in palettes: basic, material, pastel.
56
58
 
57
59
  ---
58
60
 
@@ -76,6 +78,7 @@ These are the only ways one should handle layout to get to quick results functio
76
78
  - **Pagination** - Accessible pagination with page number generation and ellipsis.
77
79
  - **Command** - Command palette component for keyboard navigation and search.
78
80
  - **CommandDialog** - Command palette dialog optimized for Cmd+K navigation.
81
+ - **TreeView** - Hierarchical tree component with WAI-ARIA TreeView pattern. Supports expand/collapse, single/multi selection, keyboard navigation, type-ahead search, and connector lines.
79
82
 
80
83
  ---
81
84
 
@@ -110,6 +113,7 @@ These are the only ways one should handle layout to get to quick results functio
110
113
  - **Portal** - Portal component for rendering outside DOM hierarchy.
111
114
  - **VisuallyHidden** - Screen reader-only content component.
112
115
  - **Slot** - Slot component for composition patterns.
116
+ - **SkipLink** - Accessibility skip-to-content links, visible only on keyboard focus. Supports multiple targets with smooth scroll and focus management.
113
117
 
114
118
  ---
115
119