openwolf 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (112) hide show
  1. package/LICENSE +663 -0
  2. package/README.md +232 -0
  3. package/dist/bin/openwolf.js +10 -0
  4. package/dist/bin/openwolf.js.map +1 -0
  5. package/dist/dashboard/assets/AISuggestions-DzE-DQkR.js +1 -0
  6. package/dist/dashboard/assets/ActivityTimeline-DGVjujnt.js +1 -0
  7. package/dist/dashboard/assets/AnatomyBrowser-S-2rmYtw.js +1 -0
  8. package/dist/dashboard/assets/BugLog-CG2zDHJc.js +1 -0
  9. package/dist/dashboard/assets/CerebrumViewer-Dlgoy69U.js +1 -0
  10. package/dist/dashboard/assets/CronStatus-DxUF1iW_.js +1 -0
  11. package/dist/dashboard/assets/DesignQC-BGXn_aq8.js +1 -0
  12. package/dist/dashboard/assets/MemoryViewer-CGqkTyvQ.js +1 -0
  13. package/dist/dashboard/assets/ProjectOverview-DlFhu69i.js +1 -0
  14. package/dist/dashboard/assets/TokenUsage-DDsQiVIq.js +68 -0
  15. package/dist/dashboard/assets/index-CzK9GUjV.css +1 -0
  16. package/dist/dashboard/assets/index-PYeNGjkN.js +52 -0
  17. package/dist/dashboard/index.html +16 -0
  18. package/dist/hooks/post-read.js +68 -0
  19. package/dist/hooks/post-write.js +502 -0
  20. package/dist/hooks/pre-read.js +79 -0
  21. package/dist/hooks/pre-write.js +120 -0
  22. package/dist/hooks/session-start.js +76 -0
  23. package/dist/hooks/shared.js +613 -0
  24. package/dist/hooks/stop.js +146 -0
  25. package/dist/src/buglog/bug-matcher.js +3 -0
  26. package/dist/src/buglog/bug-matcher.js.map +1 -0
  27. package/dist/src/buglog/bug-tracker.js +81 -0
  28. package/dist/src/buglog/bug-tracker.js.map +1 -0
  29. package/dist/src/cli/bug-cmd.js +28 -0
  30. package/dist/src/cli/bug-cmd.js.map +1 -0
  31. package/dist/src/cli/cron-cmd.js +106 -0
  32. package/dist/src/cli/cron-cmd.js.map +1 -0
  33. package/dist/src/cli/daemon-cmd.js +177 -0
  34. package/dist/src/cli/daemon-cmd.js.map +1 -0
  35. package/dist/src/cli/dashboard.js +84 -0
  36. package/dist/src/cli/dashboard.js.map +1 -0
  37. package/dist/src/cli/designqc-cmd.js +31 -0
  38. package/dist/src/cli/designqc-cmd.js.map +1 -0
  39. package/dist/src/cli/index.js +149 -0
  40. package/dist/src/cli/index.js.map +1 -0
  41. package/dist/src/cli/init.js +506 -0
  42. package/dist/src/cli/init.js.map +1 -0
  43. package/dist/src/cli/registry.js +93 -0
  44. package/dist/src/cli/registry.js.map +1 -0
  45. package/dist/src/cli/scan.js +39 -0
  46. package/dist/src/cli/scan.js.map +1 -0
  47. package/dist/src/cli/status.js +85 -0
  48. package/dist/src/cli/status.js.map +1 -0
  49. package/dist/src/cli/update.js +414 -0
  50. package/dist/src/cli/update.js.map +1 -0
  51. package/dist/src/daemon/cron-engine.js +300 -0
  52. package/dist/src/daemon/cron-engine.js.map +1 -0
  53. package/dist/src/daemon/file-watcher.js +53 -0
  54. package/dist/src/daemon/file-watcher.js.map +1 -0
  55. package/dist/src/daemon/health.js +23 -0
  56. package/dist/src/daemon/health.js.map +1 -0
  57. package/dist/src/daemon/wolf-daemon.js +294 -0
  58. package/dist/src/daemon/wolf-daemon.js.map +1 -0
  59. package/dist/src/designqc/designqc-capture.js +235 -0
  60. package/dist/src/designqc/designqc-capture.js.map +1 -0
  61. package/dist/src/designqc/designqc-engine.js +141 -0
  62. package/dist/src/designqc/designqc-engine.js.map +1 -0
  63. package/dist/src/designqc/designqc-types.js +5 -0
  64. package/dist/src/designqc/designqc-types.js.map +1 -0
  65. package/dist/src/hooks/post-read.js +69 -0
  66. package/dist/src/hooks/post-read.js.map +1 -0
  67. package/dist/src/hooks/post-write.js +503 -0
  68. package/dist/src/hooks/post-write.js.map +1 -0
  69. package/dist/src/hooks/pre-read.js +80 -0
  70. package/dist/src/hooks/pre-read.js.map +1 -0
  71. package/dist/src/hooks/pre-write.js +121 -0
  72. package/dist/src/hooks/pre-write.js.map +1 -0
  73. package/dist/src/hooks/session-start.js +77 -0
  74. package/dist/src/hooks/session-start.js.map +1 -0
  75. package/dist/src/hooks/shared.js +614 -0
  76. package/dist/src/hooks/shared.js.map +1 -0
  77. package/dist/src/hooks/stop.js +147 -0
  78. package/dist/src/hooks/stop.js.map +1 -0
  79. package/dist/src/scanner/anatomy-scanner.js +260 -0
  80. package/dist/src/scanner/anatomy-scanner.js.map +1 -0
  81. package/dist/src/scanner/description-extractor.js +1007 -0
  82. package/dist/src/scanner/description-extractor.js.map +1 -0
  83. package/dist/src/scanner/project-root.js +42 -0
  84. package/dist/src/scanner/project-root.js.map +1 -0
  85. package/dist/src/tracker/token-estimator.js +20 -0
  86. package/dist/src/tracker/token-estimator.js.map +1 -0
  87. package/dist/src/tracker/token-ledger.js +45 -0
  88. package/dist/src/tracker/token-ledger.js.map +1 -0
  89. package/dist/src/tracker/waste-detector.js +101 -0
  90. package/dist/src/tracker/waste-detector.js.map +1 -0
  91. package/dist/src/utils/fs-safe.js +74 -0
  92. package/dist/src/utils/fs-safe.js.map +1 -0
  93. package/dist/src/utils/logger.js +48 -0
  94. package/dist/src/utils/logger.js.map +1 -0
  95. package/dist/src/utils/paths.js +23 -0
  96. package/dist/src/utils/paths.js.map +1 -0
  97. package/dist/src/utils/platform.js +14 -0
  98. package/dist/src/utils/platform.js.map +1 -0
  99. package/package.json +77 -0
  100. package/src/templates/OPENWOLF.md +135 -0
  101. package/src/templates/anatomy.md +5 -0
  102. package/src/templates/buglog.json +4 -0
  103. package/src/templates/cerebrum.md +22 -0
  104. package/src/templates/claude-md-snippet.md +5 -0
  105. package/src/templates/claude-rules-openwolf.md +15 -0
  106. package/src/templates/config.json +73 -0
  107. package/src/templates/cron-manifest.json +97 -0
  108. package/src/templates/cron-state.json +7 -0
  109. package/src/templates/identity.md +9 -0
  110. package/src/templates/memory.md +4 -0
  111. package/src/templates/reframe-frameworks.md +597 -0
  112. package/src/templates/token-ledger.json +21 -0
@@ -0,0 +1,294 @@
1
+ import * as fs from "node:fs";
2
+ import * as path from "node:path";
3
+ import { fileURLToPath } from "node:url";
4
+ import express from "express";
5
+ import { WebSocketServer, WebSocket } from "ws";
6
+ import { findProjectRoot } from "../scanner/project-root.js";
7
+ import { readJSON, writeJSON } from "../utils/fs-safe.js";
8
+ import { Logger } from "../utils/logger.js";
9
+ import { CronEngine } from "./cron-engine.js";
10
+ import { startFileWatcher } from "./file-watcher.js";
11
+ const __filename = fileURLToPath(import.meta.url);
12
+ const __dirname = path.dirname(__filename);
13
+ // Prefer explicit OPENWOLF_PROJECT_ROOT env (set by CLI commands) over cwd detection
14
+ const projectRoot = process.env.OPENWOLF_PROJECT_ROOT || findProjectRoot();
15
+ const wolfDir = path.join(projectRoot, ".wolf");
16
+ const config = readJSON(path.join(wolfDir, "config.json"), {
17
+ openwolf: {
18
+ daemon: { port: 18790, log_level: "info" },
19
+ dashboard: { enabled: true, port: 18791 },
20
+ cron: { enabled: true, heartbeat_interval_minutes: 30 },
21
+ },
22
+ });
23
+ const logger = new Logger(path.join(wolfDir, "daemon.log"), config.openwolf.daemon.log_level);
24
+ const startTime = Date.now();
25
+ const wsClients = new Set();
26
+ // Express server
27
+ const app = express();
28
+ app.use(express.json());
29
+ // Serve dashboard static files
30
+ // In dist: dist/src/daemon/wolf-daemon.js → ../../../dist/dashboard/
31
+ const dashboardDir = path.resolve(__dirname, "..", "..", "..", "dist", "dashboard");
32
+ if (fs.existsSync(dashboardDir)) {
33
+ app.use(express.static(dashboardDir));
34
+ }
35
+ // Detect project metadata
36
+ function detectProjectMeta() {
37
+ let name = path.basename(projectRoot);
38
+ let description = "";
39
+ // Try package.json
40
+ try {
41
+ const pkg = JSON.parse(fs.readFileSync(path.join(projectRoot, "package.json"), "utf-8"));
42
+ if (pkg.name)
43
+ name = pkg.name;
44
+ if (pkg.description)
45
+ description = pkg.description;
46
+ }
47
+ catch { }
48
+ // Try Cargo.toml for name if not found
49
+ if (name === path.basename(projectRoot)) {
50
+ try {
51
+ const cargo = fs.readFileSync(path.join(projectRoot, "Cargo.toml"), "utf-8");
52
+ const nameMatch = cargo.match(/^name\s*=\s*"([^"]+)"/m);
53
+ if (nameMatch)
54
+ name = nameMatch[1];
55
+ }
56
+ catch { }
57
+ }
58
+ // If no description, try cerebrum.md project description
59
+ if (!description) {
60
+ try {
61
+ const cerebrum = fs.readFileSync(path.join(wolfDir, "cerebrum.md"), "utf-8");
62
+ const descMatch = cerebrum.match(/\*\*Project:\*\*\s*(.+)/);
63
+ if (descMatch)
64
+ description = descMatch[1].trim();
65
+ }
66
+ catch { }
67
+ }
68
+ // If still no description, try README first paragraph
69
+ if (!description) {
70
+ for (const readme of ["README.md", "readme.md", "README.rst"]) {
71
+ try {
72
+ const content = fs.readFileSync(path.join(projectRoot, readme), "utf-8");
73
+ const lines = content.split("\n");
74
+ for (const line of lines) {
75
+ const trimmed = line.trim();
76
+ if (trimmed && !trimmed.startsWith("#") && !trimmed.startsWith("!") && !trimmed.startsWith("=") && !trimmed.startsWith("-") && !trimmed.startsWith("<") && !trimmed.startsWith("[") && !trimmed.startsWith("```") && trimmed.length > 10) {
77
+ description = trimmed.length > 200 ? trimmed.slice(0, 200) + "…" : trimmed;
78
+ break;
79
+ }
80
+ }
81
+ if (description)
82
+ break;
83
+ }
84
+ catch { }
85
+ }
86
+ }
87
+ return { name, description };
88
+ }
89
+ const projectMeta = detectProjectMeta();
90
+ // API routes
91
+ app.get("/api/health", (_req, res) => {
92
+ const cronState = readJSON(path.join(wolfDir, "cron-state.json"), { engine_status: "unknown", last_heartbeat: null, dead_letter_queue: [] });
93
+ const cronManifest = readJSON(path.join(wolfDir, "cron-manifest.json"), { tasks: [] });
94
+ const taskCount = Array.isArray(cronManifest.tasks) ? cronManifest.tasks.length : 0;
95
+ res.json({
96
+ status: "healthy",
97
+ uptime_seconds: Math.floor((Date.now() - startTime) / 1000),
98
+ last_heartbeat: cronState.last_heartbeat,
99
+ tasks: taskCount,
100
+ dead_letters: cronState.dead_letter_queue.length,
101
+ });
102
+ });
103
+ app.get("/api/project", (_req, res) => {
104
+ res.json({
105
+ name: projectMeta.name,
106
+ description: projectMeta.description,
107
+ root: projectRoot,
108
+ });
109
+ });
110
+ app.get("/api/files", (_req, res) => {
111
+ const files = {};
112
+ const wolfFiles = [
113
+ "OPENWOLF.md", "identity.md", "cerebrum.md", "memory.md", "anatomy.md",
114
+ "config.json", "token-ledger.json", "buglog.json",
115
+ "cron-manifest.json", "cron-state.json",
116
+ "designqc-report.json",
117
+ ];
118
+ for (const file of wolfFiles) {
119
+ try {
120
+ files[file] = fs.readFileSync(path.join(wolfDir, file), "utf-8");
121
+ }
122
+ catch {
123
+ files[file] = "";
124
+ }
125
+ }
126
+ // Also try suggestions.json
127
+ try {
128
+ files["suggestions.json"] = fs.readFileSync(path.join(wolfDir, "suggestions.json"), "utf-8");
129
+ }
130
+ catch {
131
+ files["suggestions.json"] = "";
132
+ }
133
+ res.json(files);
134
+ });
135
+ app.get("/api/designqc-report", (_req, res) => {
136
+ const report = readJSON(path.join(wolfDir, "designqc-report.json"), null);
137
+ res.json(report);
138
+ });
139
+ // Trigger a cron task by ID
140
+ app.post("/api/cron/run/:taskId", (req, res) => {
141
+ const { taskId } = req.params;
142
+ if (!cronEngine) {
143
+ res.status(503).json({ error: "Cron engine not running" });
144
+ return;
145
+ }
146
+ cronEngine.runTask(taskId).then(() => {
147
+ res.json({ status: "ok", task_id: taskId });
148
+ }).catch((err) => {
149
+ res.status(500).json({ error: String(err) });
150
+ });
151
+ });
152
+ // SPA fallback
153
+ app.get("/{*path}", (_req, res) => {
154
+ const indexPath = path.join(dashboardDir, "index.html");
155
+ if (fs.existsSync(indexPath)) {
156
+ res.sendFile(indexPath);
157
+ }
158
+ else {
159
+ res.status(404).json({ error: "Dashboard not built. Run: pnpm build:dashboard" });
160
+ }
161
+ });
162
+ // Start HTTP server
163
+ const port = config.openwolf.dashboard.port;
164
+ const server = app.listen(port, () => {
165
+ logger.info(`Dashboard server listening on port ${port}`);
166
+ });
167
+ // WebSocket server
168
+ const wss = new WebSocketServer({ server });
169
+ wss.on("connection", (ws) => {
170
+ wsClients.add(ws);
171
+ logger.info("WebSocket client connected");
172
+ ws.on("message", (data) => {
173
+ try {
174
+ const msg = JSON.parse(data.toString());
175
+ handleDashboardCommand(msg);
176
+ }
177
+ catch {
178
+ logger.warn("Invalid WebSocket message received");
179
+ }
180
+ });
181
+ ws.on("close", () => {
182
+ wsClients.delete(ws);
183
+ });
184
+ // Send initial state
185
+ broadcast({ type: "daemon_started", timestamp: new Date().toISOString() });
186
+ });
187
+ function broadcast(msg) {
188
+ const data = JSON.stringify(msg);
189
+ for (const client of wsClients) {
190
+ if (client.readyState === WebSocket.OPEN) {
191
+ client.send(data);
192
+ }
193
+ }
194
+ }
195
+ function handleDashboardCommand(msg) {
196
+ switch (msg.type) {
197
+ case "trigger_task":
198
+ if (msg.task_id && cronEngine) {
199
+ cronEngine.runTask(msg.task_id).catch((err) => {
200
+ logger.error(`Manual task trigger failed: ${err}`);
201
+ });
202
+ }
203
+ break;
204
+ case "retry_dead_letter":
205
+ if (msg.task_id) {
206
+ const statePath = path.join(wolfDir, "cron-state.json");
207
+ const state = readJSON(statePath, {
208
+ dead_letter_queue: [],
209
+ });
210
+ state.dead_letter_queue = state.dead_letter_queue.filter((d) => d.task_id !== msg.task_id);
211
+ writeJSON(statePath, state);
212
+ }
213
+ break;
214
+ case "force_scan":
215
+ if (cronEngine) {
216
+ cronEngine.runTask("anatomy-rescan").catch((err) => {
217
+ logger.error(`Force scan failed: ${err}`);
218
+ });
219
+ }
220
+ break;
221
+ case "request_full_state":
222
+ // Send all files
223
+ try {
224
+ const files = {};
225
+ const wolfFiles = [
226
+ "OPENWOLF.md", "identity.md", "cerebrum.md", "memory.md", "anatomy.md",
227
+ "config.json", "token-ledger.json", "buglog.json",
228
+ "cron-manifest.json", "cron-state.json",
229
+ "designqc-report.json",
230
+ ];
231
+ for (const file of wolfFiles) {
232
+ try {
233
+ files[file] = fs.readFileSync(path.join(wolfDir, file), "utf-8");
234
+ }
235
+ catch {
236
+ files[file] = "";
237
+ }
238
+ }
239
+ broadcast({ type: "full_state", files, timestamp: new Date().toISOString() });
240
+ }
241
+ catch (err) {
242
+ logger.error(`Full state request failed: ${err}`);
243
+ }
244
+ break;
245
+ }
246
+ }
247
+ // Cron engine
248
+ let cronEngine = null;
249
+ if (config.openwolf.cron.enabled) {
250
+ cronEngine = new CronEngine(wolfDir, projectRoot, logger, broadcast);
251
+ cronEngine.start();
252
+ }
253
+ // File watcher
254
+ startFileWatcher(wolfDir, logger, broadcast);
255
+ // Health heartbeat
256
+ const heartbeatInterval = config.openwolf.cron.heartbeat_interval_minutes * 60 * 1000;
257
+ const heartbeatTimer = setInterval(() => {
258
+ const statePath = path.join(wolfDir, "cron-state.json");
259
+ const state = readJSON(statePath, {});
260
+ state.last_heartbeat = new Date().toISOString();
261
+ writeJSON(statePath, state);
262
+ broadcast({ type: "health", status: "healthy", uptime: Math.floor((Date.now() - startTime) / 1000) });
263
+ }, heartbeatInterval);
264
+ // Update cron-state to running
265
+ const cronStatePath = path.join(wolfDir, "cron-state.json");
266
+ const cronState = readJSON(cronStatePath, {});
267
+ cronState.engine_status = "running";
268
+ cronState.last_heartbeat = new Date().toISOString();
269
+ writeJSON(cronStatePath, cronState);
270
+ logger.info("OpenWolf daemon started");
271
+ // Graceful shutdown
272
+ function shutdown() {
273
+ logger.info("Daemon shutting down...");
274
+ broadcast({ type: "daemon_stopping", timestamp: new Date().toISOString() });
275
+ clearInterval(heartbeatTimer);
276
+ if (cronEngine)
277
+ cronEngine.stop();
278
+ const state = readJSON(cronStatePath, {});
279
+ state.engine_status = "stopped";
280
+ writeJSON(cronStatePath, state);
281
+ for (const client of wsClients) {
282
+ client.close();
283
+ }
284
+ wsClients.clear();
285
+ server.close(() => {
286
+ logger.info("Daemon stopped");
287
+ process.exit(0);
288
+ });
289
+ // Force exit after 5s
290
+ setTimeout(() => process.exit(0), 5000);
291
+ }
292
+ process.on("SIGTERM", shutdown);
293
+ process.on("SIGINT", shutdown);
294
+ //# sourceMappingURL=wolf-daemon.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"wolf-daemon.js","sourceRoot":"","sources":["../../../src/daemon/wolf-daemon.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,235 @@
1
+ import * as fs from "node:fs";
2
+ import * as path from "node:path";
3
+ import * as http from "node:http";
4
+ import { execSync, spawn } from "node:child_process";
5
+ export function findChromePath(configPath) {
6
+ if (configPath && fs.existsSync(configPath))
7
+ return configPath;
8
+ if (process.platform === "win32") {
9
+ const candidates = [
10
+ path.join(process.env["PROGRAMFILES"] || "C:\\Program Files", "Google\\Chrome\\Application\\chrome.exe"),
11
+ path.join(process.env["PROGRAMFILES(X86)"] || "C:\\Program Files (x86)", "Google\\Chrome\\Application\\chrome.exe"),
12
+ path.join(process.env["LOCALAPPDATA"] || "", "Google\\Chrome\\Application\\chrome.exe"),
13
+ path.join(process.env["PROGRAMFILES(X86)"] || "C:\\Program Files (x86)", "Microsoft\\Edge\\Application\\msedge.exe"),
14
+ path.join(process.env["PROGRAMFILES"] || "C:\\Program Files", "Microsoft\\Edge\\Application\\msedge.exe"),
15
+ ];
16
+ for (const c of candidates) {
17
+ if (fs.existsSync(c))
18
+ return c;
19
+ }
20
+ try {
21
+ const r = execSync("where chrome", { encoding: "utf-8", stdio: ["pipe", "pipe", "ignore"] }).trim();
22
+ if (r)
23
+ return r.split("\n")[0].trim();
24
+ }
25
+ catch { }
26
+ try {
27
+ const r = execSync("where msedge", { encoding: "utf-8", stdio: ["pipe", "pipe", "ignore"] }).trim();
28
+ if (r)
29
+ return r.split("\n")[0].trim();
30
+ }
31
+ catch { }
32
+ }
33
+ else if (process.platform === "darwin") {
34
+ for (const c of [
35
+ "/Applications/Google Chrome.app/Contents/MacOS/Google Chrome",
36
+ "/Applications/Chromium.app/Contents/MacOS/Chromium",
37
+ ]) {
38
+ if (fs.existsSync(c))
39
+ return c;
40
+ }
41
+ }
42
+ else {
43
+ try {
44
+ return execSync("which google-chrome || which chromium || which chromium-browser", {
45
+ encoding: "utf-8", stdio: ["pipe", "pipe", "ignore"],
46
+ }).trim().split("\n")[0];
47
+ }
48
+ catch { }
49
+ }
50
+ throw new Error("Chrome/Edge not found. Install Chrome or set designqc.chrome_path in .wolf/config.json");
51
+ }
52
+ /**
53
+ * Capture a full page as sectioned viewport-height screenshots.
54
+ * Returns multiple screenshots — one per "fold" of the page.
55
+ * This gives Claude focused views of each section without one massive image.
56
+ */
57
+ export async function captureRouteSectioned(page, url, viewport, outputDir, quality, maxWidth) {
58
+ const scale = maxWidth < viewport.width ? maxWidth / viewport.width : 1;
59
+ const captureWidth = Math.round(viewport.width * scale);
60
+ const captureHeight = Math.round(viewport.height * scale);
61
+ await page.setViewport({ width: captureWidth, height: captureHeight });
62
+ await page.goto(url, { waitUntil: "networkidle2", timeout: 30_000 });
63
+ await new Promise((r) => setTimeout(r, 1500));
64
+ // Get full page height
65
+ const fullHeight = await page.evaluate(() => document.documentElement.scrollHeight);
66
+ const route = new URL(url).pathname;
67
+ const safeName = route.replace(/\//g, "_").replace(/^_/, "") || "root";
68
+ const screenshots = [];
69
+ const sectionHeight = captureHeight;
70
+ const totalSections = Math.ceil(fullHeight / sectionHeight);
71
+ // Cap at 8 sections (~20K tokens) to avoid runaway costs
72
+ const maxSections = Math.min(totalSections, 8);
73
+ for (let i = 0; i < maxSections; i++) {
74
+ const y = i * sectionHeight;
75
+ // Scroll to position
76
+ await page.evaluate((scrollY) => window.scrollTo(0, scrollY), y);
77
+ await new Promise((r) => setTimeout(r, 500));
78
+ const screenshotBuffer = await page.screenshot({
79
+ fullPage: false,
80
+ type: "jpeg",
81
+ quality,
82
+ });
83
+ const sectionLabel = i === 0 ? "top" : i === maxSections - 1 ? "bottom" : `section${i + 1}`;
84
+ const fileName = `${safeName}_${viewport.name}_${sectionLabel}.jpg`;
85
+ const filePath = path.join(outputDir, fileName);
86
+ fs.writeFileSync(filePath, screenshotBuffer);
87
+ screenshots.push({ route, viewport, path: filePath });
88
+ }
89
+ return screenshots;
90
+ }
91
+ export function detectRoutes(projectRoot) {
92
+ const routes = ["/"];
93
+ const dirs = [
94
+ path.join(projectRoot, "pages"),
95
+ path.join(projectRoot, "app"),
96
+ path.join(projectRoot, "src", "pages"),
97
+ path.join(projectRoot, "src", "app"),
98
+ ].filter((d) => fs.existsSync(d));
99
+ for (const dir of dirs) {
100
+ try {
101
+ const files = fs.readdirSync(dir, { recursive: true });
102
+ for (const file of files) {
103
+ const f = String(file).replace(/\\/g, "/");
104
+ if (f.includes("api/") || f.includes("_") || f.includes("layout."))
105
+ continue;
106
+ if (f.endsWith(".tsx") || f.endsWith(".jsx") || f.endsWith(".ts") || f.endsWith(".js")) {
107
+ let route = "/" + f
108
+ .replace(/\.(tsx|jsx|ts|js)$/, "")
109
+ .replace(/\/index$/, "")
110
+ .replace(/\/page$/, "");
111
+ if (route === "/")
112
+ continue;
113
+ routes.push(route);
114
+ }
115
+ }
116
+ }
117
+ catch { }
118
+ }
119
+ return [...new Set(routes)].slice(0, 10);
120
+ }
121
+ export async function probePort(port) {
122
+ return new Promise((resolve) => {
123
+ const req = http.get(`http://localhost:${port}`, () => resolve(true));
124
+ req.on("error", () => resolve(false));
125
+ req.setTimeout(2000, () => { req.destroy(); resolve(false); });
126
+ });
127
+ }
128
+ /**
129
+ * Try to find a running dev server on common ports.
130
+ */
131
+ export async function detectDevServer() {
132
+ const commonPorts = [3000, 3001, 5173, 5174, 4321, 8080, 8000, 4200];
133
+ for (const port of commonPorts) {
134
+ if (await probePort(port)) {
135
+ return { url: `http://localhost:${port}`, port };
136
+ }
137
+ }
138
+ return null;
139
+ }
140
+ /**
141
+ * Detect the dev command from package.json.
142
+ * Returns { command, port } or null.
143
+ */
144
+ export function detectDevCommand(projectRoot) {
145
+ const pkgPath = path.join(projectRoot, "package.json");
146
+ if (!fs.existsSync(pkgPath))
147
+ return null;
148
+ try {
149
+ const pkg = JSON.parse(fs.readFileSync(pkgPath, "utf-8"));
150
+ const scripts = pkg.scripts || {};
151
+ // Priority order: dev, start, serve
152
+ for (const key of ["dev", "start", "serve"]) {
153
+ if (scripts[key]) {
154
+ // Try to detect port from the script
155
+ const portMatch = scripts[key].match(/-p\s+(\d+)|--port\s+(\d+)|PORT=(\d+)/);
156
+ let port = 3000;
157
+ if (portMatch) {
158
+ port = parseInt(portMatch[1] || portMatch[2] || portMatch[3], 10);
159
+ }
160
+ else if (scripts[key].includes("vite")) {
161
+ port = 5173;
162
+ }
163
+ else if (scripts[key].includes("next")) {
164
+ port = 3000;
165
+ }
166
+ else if (scripts[key].includes("astro")) {
167
+ port = 4321;
168
+ }
169
+ else if (scripts[key].includes("angular") || scripts[key].includes("ng serve")) {
170
+ port = 4200;
171
+ }
172
+ // Determine package manager
173
+ let runner = "npm run";
174
+ if (fs.existsSync(path.join(projectRoot, "pnpm-lock.yaml")))
175
+ runner = "pnpm";
176
+ else if (fs.existsSync(path.join(projectRoot, "yarn.lock")))
177
+ runner = "yarn";
178
+ else if (fs.existsSync(path.join(projectRoot, "bun.lockb")))
179
+ runner = "bun run";
180
+ return { command: `${runner} ${key}`, expectedPort: port };
181
+ }
182
+ }
183
+ }
184
+ catch { }
185
+ return null;
186
+ }
187
+ /**
188
+ * Start the dev server, wait for it to be ready, return the process handle.
189
+ * Caller is responsible for killing the process.
190
+ */
191
+ export async function startDevServer(projectRoot) {
192
+ const devCmd = detectDevCommand(projectRoot);
193
+ if (!devCmd) {
194
+ console.error(" No dev script found in package.json (looked for: dev, start, serve)");
195
+ return null;
196
+ }
197
+ console.log(` Starting dev server: ${devCmd.command}`);
198
+ const proc = spawn(devCmd.command, {
199
+ cwd: projectRoot,
200
+ shell: true,
201
+ stdio: ["ignore", "pipe", "pipe"],
202
+ windowsHide: true,
203
+ });
204
+ // Wait for server to be ready (poll port)
205
+ const port = devCmd.expectedPort;
206
+ const maxWait = 30_000;
207
+ const start = Date.now();
208
+ let ready = false;
209
+ while (Date.now() - start < maxWait) {
210
+ // Check if process died
211
+ if (proc.exitCode !== null) {
212
+ console.error(` Dev server exited with code ${proc.exitCode}`);
213
+ return null;
214
+ }
215
+ if (await probePort(port)) {
216
+ ready = true;
217
+ break;
218
+ }
219
+ await new Promise((r) => setTimeout(r, 1000));
220
+ }
221
+ if (!ready) {
222
+ // Try nearby ports in case the detected port was wrong
223
+ for (const p of [3000, 3001, 5173, 5174, 4321, 8080]) {
224
+ if (p !== port && await probePort(p)) {
225
+ console.log(` Server responded on port ${p} (expected ${port})`);
226
+ return { proc, url: `http://localhost:${p}`, port: p };
227
+ }
228
+ }
229
+ console.error(` Dev server did not respond on port ${port} within ${maxWait / 1000}s`);
230
+ proc.kill();
231
+ return null;
232
+ }
233
+ return { proc, url: `http://localhost:${port}`, port };
234
+ }
235
+ //# sourceMappingURL=designqc-capture.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"designqc-capture.js","sourceRoot":"","sources":["../../../src/designqc/designqc-capture.ts"],"names":[],"mappings":"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"}