openwolf-enhanced 1.9.3

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 (127) hide show
  1. package/CHANGELOG.md +386 -0
  2. package/LICENSE +663 -0
  3. package/NOTICE +48 -0
  4. package/README.md +283 -0
  5. package/dist/bin/openwolf.js +10 -0
  6. package/dist/bin/openwolf.js.map +1 -0
  7. package/dist/dashboard/assets/AISuggestions-DHXOgHMM.js +9 -0
  8. package/dist/dashboard/assets/ActivityTimeline-BXLwacZV.js +1 -0
  9. package/dist/dashboard/assets/AnatomyBrowser-CUyC8M2I.js +1 -0
  10. package/dist/dashboard/assets/BugLog-Bxvy1sPW.js +1 -0
  11. package/dist/dashboard/assets/CerebrumViewer-DCySVmzA.js +1 -0
  12. package/dist/dashboard/assets/CronStatus-BA4fmQX3.js +1 -0
  13. package/dist/dashboard/assets/DesignQC-BhNEKryS.js +1 -0
  14. package/dist/dashboard/assets/MemoryViewer-0y9lsDUO.js +1 -0
  15. package/dist/dashboard/assets/ProjectOverview-CC51rVRe.js +1 -0
  16. package/dist/dashboard/assets/StatusBadge-4NJI_F2G.js +1 -0
  17. package/dist/dashboard/assets/TokenUsage-7pCxlnCX.js +55 -0
  18. package/dist/dashboard/assets/index-4O5rk-qB.css +2 -0
  19. package/dist/dashboard/assets/index-jfgWxxsn.js +13 -0
  20. package/dist/dashboard/assets/utils-BqE_aDxV.js +1 -0
  21. package/dist/dashboard/index.html +16 -0
  22. package/dist/hooks/post-read.js +85 -0
  23. package/dist/hooks/post-write.js +520 -0
  24. package/dist/hooks/pre-read.js +107 -0
  25. package/dist/hooks/pre-write.js +120 -0
  26. package/dist/hooks/session-start.js +76 -0
  27. package/dist/hooks/shared.js +0 -0
  28. package/dist/hooks/stop.js +219 -0
  29. package/dist/src/buglog/bug-matcher.js +3 -0
  30. package/dist/src/buglog/bug-matcher.js.map +1 -0
  31. package/dist/src/buglog/bug-tracker.js +89 -0
  32. package/dist/src/buglog/bug-tracker.js.map +1 -0
  33. package/dist/src/cli/bug-cmd.js +31 -0
  34. package/dist/src/cli/bug-cmd.js.map +1 -0
  35. package/dist/src/cli/cron-cmd.js +107 -0
  36. package/dist/src/cli/cron-cmd.js.map +1 -0
  37. package/dist/src/cli/daemon-cmd.js +180 -0
  38. package/dist/src/cli/daemon-cmd.js.map +1 -0
  39. package/dist/src/cli/dashboard.js +88 -0
  40. package/dist/src/cli/dashboard.js.map +1 -0
  41. package/dist/src/cli/designqc-cmd.js +31 -0
  42. package/dist/src/cli/designqc-cmd.js.map +1 -0
  43. package/dist/src/cli/doctor-cmd.js +94 -0
  44. package/dist/src/cli/doctor-cmd.js.map +1 -0
  45. package/dist/src/cli/index.js +158 -0
  46. package/dist/src/cli/index.js.map +1 -0
  47. package/dist/src/cli/init.js +493 -0
  48. package/dist/src/cli/init.js.map +1 -0
  49. package/dist/src/cli/registry.js +93 -0
  50. package/dist/src/cli/registry.js.map +1 -0
  51. package/dist/src/cli/scan.js +39 -0
  52. package/dist/src/cli/scan.js.map +1 -0
  53. package/dist/src/cli/status.js +98 -0
  54. package/dist/src/cli/status.js.map +1 -0
  55. package/dist/src/cli/update.js +435 -0
  56. package/dist/src/cli/update.js.map +1 -0
  57. package/dist/src/daemon/cron-engine.js +321 -0
  58. package/dist/src/daemon/cron-engine.js.map +1 -0
  59. package/dist/src/daemon/file-watcher.js +64 -0
  60. package/dist/src/daemon/file-watcher.js.map +1 -0
  61. package/dist/src/daemon/health.js +23 -0
  62. package/dist/src/daemon/health.js.map +1 -0
  63. package/dist/src/daemon/wolf-daemon.js +440 -0
  64. package/dist/src/daemon/wolf-daemon.js.map +1 -0
  65. package/dist/src/designqc/designqc-capture.js +278 -0
  66. package/dist/src/designqc/designqc-capture.js.map +1 -0
  67. package/dist/src/designqc/designqc-engine.js +159 -0
  68. package/dist/src/designqc/designqc-engine.js.map +1 -0
  69. package/dist/src/designqc/designqc-types.js +5 -0
  70. package/dist/src/designqc/designqc-types.js.map +1 -0
  71. package/dist/src/hooks/post-read.js +86 -0
  72. package/dist/src/hooks/post-read.js.map +1 -0
  73. package/dist/src/hooks/post-write.js +521 -0
  74. package/dist/src/hooks/post-write.js.map +1 -0
  75. package/dist/src/hooks/pre-read.js +108 -0
  76. package/dist/src/hooks/pre-read.js.map +1 -0
  77. package/dist/src/hooks/pre-write.js +121 -0
  78. package/dist/src/hooks/pre-write.js.map +1 -0
  79. package/dist/src/hooks/session-start.js +77 -0
  80. package/dist/src/hooks/session-start.js.map +1 -0
  81. package/dist/src/hooks/shared.js +0 -0
  82. package/dist/src/hooks/shared.js.map +1 -0
  83. package/dist/src/hooks/stop.js +220 -0
  84. package/dist/src/hooks/stop.js.map +1 -0
  85. package/dist/src/scanner/anatomy-scanner.js +278 -0
  86. package/dist/src/scanner/anatomy-scanner.js.map +1 -0
  87. package/dist/src/scanner/description-extractor.js +1007 -0
  88. package/dist/src/scanner/description-extractor.js.map +1 -0
  89. package/dist/src/scanner/project-root.js +52 -0
  90. package/dist/src/scanner/project-root.js.map +1 -0
  91. package/dist/src/tracker/token-estimator.js +20 -0
  92. package/dist/src/tracker/token-estimator.js.map +1 -0
  93. package/dist/src/tracker/token-ledger.js +55 -0
  94. package/dist/src/tracker/token-ledger.js.map +1 -0
  95. package/dist/src/tracker/waste-detector.js +101 -0
  96. package/dist/src/tracker/waste-detector.js.map +1 -0
  97. package/dist/src/utils/dashboard-auth.js +50 -0
  98. package/dist/src/utils/dashboard-auth.js.map +1 -0
  99. package/dist/src/utils/fs-safe.js +135 -0
  100. package/dist/src/utils/fs-safe.js.map +1 -0
  101. package/dist/src/utils/hooks-deploy.js +70 -0
  102. package/dist/src/utils/hooks-deploy.js.map +1 -0
  103. package/dist/src/utils/logger.js +48 -0
  104. package/dist/src/utils/logger.js.map +1 -0
  105. package/dist/src/utils/maintenance.js +385 -0
  106. package/dist/src/utils/maintenance.js.map +1 -0
  107. package/dist/src/utils/paths.js +23 -0
  108. package/dist/src/utils/paths.js.map +1 -0
  109. package/dist/src/utils/platform.js +14 -0
  110. package/dist/src/utils/platform.js.map +1 -0
  111. package/dist/src/utils/seed.js +61 -0
  112. package/dist/src/utils/seed.js.map +1 -0
  113. package/package.json +82 -0
  114. package/src/templates/OPENWOLF.md +147 -0
  115. package/src/templates/STATUS.md +48 -0
  116. package/src/templates/anatomy.md +5 -0
  117. package/src/templates/buglog.json +4 -0
  118. package/src/templates/cerebrum.md +22 -0
  119. package/src/templates/claude-md-snippet.md +5 -0
  120. package/src/templates/claude-rules-openwolf.md +17 -0
  121. package/src/templates/config.json +83 -0
  122. package/src/templates/cron-manifest.json +97 -0
  123. package/src/templates/cron-state.json +7 -0
  124. package/src/templates/identity.md +9 -0
  125. package/src/templates/memory.md +4 -0
  126. package/src/templates/reframe-frameworks.md +597 -0
  127. package/src/templates/token-ledger.json +21 -0
@@ -0,0 +1,440 @@
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 { ensureDashboardToken, tokenMatches } from "../utils/dashboard-auth.js";
9
+ import { Logger } from "../utils/logger.js";
10
+ import { CronEngine } from "./cron-engine.js";
11
+ import { startFileWatcher } from "./file-watcher.js";
12
+ import { DesignQCEngine } from "../designqc/designqc-engine.js";
13
+ import { DEFAULT_VIEWPORTS } from "../designqc/designqc-types.js";
14
+ import { getRegisteredProjects } from "../cli/registry.js";
15
+ const __filename = fileURLToPath(import.meta.url);
16
+ const __dirname = path.dirname(__filename);
17
+ // Prefer explicit OPENWOLF_PROJECT_ROOT env (set by CLI commands) over cwd detection.
18
+ // projectRoot/wolfDir are mutable so /api/switch can hot-reload another project in place.
19
+ // The dashboard token, by contrast, is per-daemon (not re-read on switch) so an authenticated
20
+ // dashboard session survives a project switch.
21
+ let projectRoot = process.env.OPENWOLF_PROJECT_ROOT || findProjectRoot();
22
+ let wolfDir = path.join(projectRoot, ".wolf");
23
+ const config = readJSON(path.join(wolfDir, "config.json"), {
24
+ openwolf: {
25
+ daemon: { port: 18790, log_level: "info" },
26
+ dashboard: { enabled: true, port: 18791 },
27
+ cron: { enabled: true, heartbeat_interval_minutes: 30 },
28
+ },
29
+ });
30
+ // Per-project dashboard token, required on every /api/* request and WS connection.
31
+ const dashboardToken = ensureDashboardToken(wolfDir);
32
+ const logger = new Logger(path.join(wolfDir, "daemon.log"), config.openwolf.daemon.log_level);
33
+ const startTime = Date.now();
34
+ const wsClients = new Set();
35
+ // Files served to the dashboard on demand (via /api/files and full_state broadcasts).
36
+ const WOLF_BROADCAST_FILES = [
37
+ "OPENWOLF.md", "identity.md", "cerebrum.md", "memory.md", "anatomy.md",
38
+ "config.json", "token-ledger.json", "buglog.json",
39
+ "cron-manifest.json", "cron-state.json",
40
+ "designqc-report.json",
41
+ ];
42
+ // Read a .wolf file for delivery to the dashboard, trimming the largest ones so a
43
+ // multi-MB token-ledger.json isn't shipped in full over HTTP/WS on every connect.
44
+ // The dashboard only needs lifetime aggregates + recent sessions, so we keep the
45
+ // last 50 sessions when the file is large.
46
+ function readWolfFileForDashboard(file) {
47
+ let raw;
48
+ try {
49
+ raw = fs.readFileSync(path.join(wolfDir, file), "utf-8");
50
+ }
51
+ catch {
52
+ return "";
53
+ }
54
+ if (file === "token-ledger.json" && raw.length > 256 * 1024) {
55
+ try {
56
+ const led = JSON.parse(raw);
57
+ if (Array.isArray(led.sessions) && led.sessions.length > 50) {
58
+ led.sessions = led.sessions.slice(-50);
59
+ led._trimmed_for_dashboard = true;
60
+ }
61
+ return JSON.stringify(led);
62
+ }
63
+ catch {
64
+ return raw;
65
+ }
66
+ }
67
+ return raw;
68
+ }
69
+ // Express server
70
+ const app = express();
71
+ app.use(express.json());
72
+ // Serve dashboard static files (unauthenticated so the page can load and read its token).
73
+ // In dist: dist/src/daemon/wolf-daemon.js → ../../../dist/dashboard/
74
+ const dashboardDir = path.resolve(__dirname, "..", "..", "..", "dist", "dashboard");
75
+ if (fs.existsSync(dashboardDir)) {
76
+ app.use(express.static(dashboardDir));
77
+ }
78
+ // Require the dashboard token on every /api/* call (header or ?token=). Blocks drive-by
79
+ // requests from a page in the user's browser or another local user (upstream #30/#34).
80
+ app.use("/api", (req, res, next) => {
81
+ const provided = req.headers["x-openwolf-token"] || req.query.token || "";
82
+ if (!tokenMatches(provided, dashboardToken)) {
83
+ res.status(401).json({ error: "unauthorized" });
84
+ return;
85
+ }
86
+ next();
87
+ });
88
+ // Detect project metadata
89
+ function detectProjectMeta() {
90
+ let name = path.basename(projectRoot);
91
+ let description = "";
92
+ // Try package.json
93
+ try {
94
+ const pkg = JSON.parse(fs.readFileSync(path.join(projectRoot, "package.json"), "utf-8"));
95
+ if (pkg.name)
96
+ name = pkg.name;
97
+ if (pkg.description)
98
+ description = pkg.description;
99
+ }
100
+ catch { }
101
+ // Try Cargo.toml for name if not found
102
+ if (name === path.basename(projectRoot)) {
103
+ try {
104
+ const cargo = fs.readFileSync(path.join(projectRoot, "Cargo.toml"), "utf-8");
105
+ const nameMatch = cargo.match(/^name\s*=\s*"([^"]+)"/m);
106
+ if (nameMatch)
107
+ name = nameMatch[1];
108
+ }
109
+ catch { }
110
+ }
111
+ // If no description, try cerebrum.md project description
112
+ if (!description) {
113
+ try {
114
+ const cerebrum = fs.readFileSync(path.join(wolfDir, "cerebrum.md"), "utf-8");
115
+ const descMatch = cerebrum.match(/\*\*Project:\*\*\s*(.+)/);
116
+ if (descMatch)
117
+ description = descMatch[1].trim();
118
+ }
119
+ catch { }
120
+ }
121
+ // If still no description, try README first paragraph
122
+ if (!description) {
123
+ for (const readme of ["README.md", "readme.md", "README.rst"]) {
124
+ try {
125
+ const content = fs.readFileSync(path.join(projectRoot, readme), "utf-8");
126
+ const lines = content.split("\n");
127
+ for (const line of lines) {
128
+ const trimmed = line.trim();
129
+ if (trimmed && !trimmed.startsWith("#") && !trimmed.startsWith("!") && !trimmed.startsWith("=") && !trimmed.startsWith("-") && !trimmed.startsWith("<") && !trimmed.startsWith("[") && !trimmed.startsWith("```") && trimmed.length > 10) {
130
+ description = trimmed.length > 200 ? trimmed.slice(0, 200) + "…" : trimmed;
131
+ break;
132
+ }
133
+ }
134
+ if (description)
135
+ break;
136
+ }
137
+ catch { }
138
+ }
139
+ }
140
+ return { name, description };
141
+ }
142
+ let projectMeta = detectProjectMeta();
143
+ // API routes
144
+ app.get("/api/config", (_req, res) => {
145
+ res.json({ hasApiKey: !!process.env.ANTHROPIC_API_KEY });
146
+ });
147
+ app.get("/api/projects", (_req, res) => {
148
+ res.json(getRegisteredProjects(true));
149
+ });
150
+ app.post("/api/switch", (req, res) => {
151
+ const { root } = (req.body ?? {});
152
+ if (!root || !fs.existsSync(path.join(root, ".wolf"))) {
153
+ res.status(400).json({ error: "Invalid project root" });
154
+ return;
155
+ }
156
+ // Only switch to a project that's actually registered — don't let an authenticated request
157
+ // point the daemon at an arbitrary directory on disk that happens to contain a .wolf/.
158
+ const isRegistered = getRegisteredProjects(true).some((p) => path.resolve(p.root) === path.resolve(root));
159
+ if (!isRegistered) {
160
+ res.status(403).json({ error: "Not a registered OpenWolf project" });
161
+ return;
162
+ }
163
+ if (root === projectRoot) {
164
+ res.status(400).json({ error: "Already on this project" });
165
+ return;
166
+ }
167
+ res.json({ ok: true });
168
+ // Hot-reload in place — no process restart, existing (authenticated) WS clients are kept.
169
+ setImmediate(() => switchProject(root));
170
+ });
171
+ app.get("/api/health", (_req, res) => {
172
+ const cronState = readJSON(path.join(wolfDir, "cron-state.json"), { engine_status: "unknown", last_heartbeat: null, dead_letter_queue: [] });
173
+ const cronManifest = readJSON(path.join(wolfDir, "cron-manifest.json"), { tasks: [] });
174
+ const taskCount = Array.isArray(cronManifest.tasks) ? cronManifest.tasks.length : 0;
175
+ res.json({
176
+ status: "healthy",
177
+ uptime_seconds: Math.floor((Date.now() - startTime) / 1000),
178
+ last_heartbeat: cronState.last_heartbeat,
179
+ tasks: taskCount,
180
+ dead_letters: Array.isArray(cronState.dead_letter_queue) ? cronState.dead_letter_queue.length : 0,
181
+ });
182
+ });
183
+ app.get("/api/project", (_req, res) => {
184
+ res.json({
185
+ name: projectMeta.name,
186
+ description: projectMeta.description,
187
+ root: projectRoot,
188
+ });
189
+ });
190
+ app.get("/api/files", (_req, res) => {
191
+ const files = {};
192
+ for (const file of WOLF_BROADCAST_FILES) {
193
+ files[file] = readWolfFileForDashboard(file);
194
+ }
195
+ // Also try suggestions.json
196
+ try {
197
+ files["suggestions.json"] = fs.readFileSync(path.join(wolfDir, "suggestions.json"), "utf-8");
198
+ }
199
+ catch {
200
+ files["suggestions.json"] = "";
201
+ }
202
+ res.json(files);
203
+ });
204
+ app.get("/api/designqc-report", (_req, res) => {
205
+ const report = readJSON(path.join(wolfDir, "designqc-report.json"), null);
206
+ res.json(report);
207
+ });
208
+ // Serve a Design QC capture image so the dashboard can show thumbnails/lightbox
209
+ // instead of bare filenames. Under /api → already behind the dashboard-token gate
210
+ // (which also accepts ?token=, so an <img src> can authenticate). Path-safe.
211
+ app.get("/api/designqc/capture/:file", (req, res) => {
212
+ const capturesDir = path.join(wolfDir, "designqc-captures");
213
+ const safe = path.basename(req.params.file); // strip any traversal
214
+ const filePath = path.join(capturesDir, safe);
215
+ if (!filePath.startsWith(capturesDir + path.sep) || !fs.existsSync(filePath)) {
216
+ res.status(404).json({ error: "capture not found" });
217
+ return;
218
+ }
219
+ const ext = path.extname(safe).toLowerCase();
220
+ const type = ext === ".png" ? "image/png" : ext === ".webp" ? "image/webp" : "image/jpeg";
221
+ res.setHeader("Content-Type", type);
222
+ res.setHeader("Cache-Control", "no-cache");
223
+ // The capture lives under .wolf/ (a dotdir); Express 5's sendFile defaults to
224
+ // dotfiles:"ignore" and would 404 the whole path. Allow it explicitly.
225
+ res.sendFile(filePath, { dotfiles: "allow" });
226
+ });
227
+ // Manually trigger a Design QC capture (works on a deployed URL, not just localhost — #4, bug 4).
228
+ app.post("/api/designqc/run", (req, res) => {
229
+ const dc = config.openwolf.designqc ?? {};
230
+ const engine = new DesignQCEngine(wolfDir, projectRoot, {
231
+ devServerUrl: req.body?.url || undefined,
232
+ viewports: dc.viewports || DEFAULT_VIEWPORTS,
233
+ maxScreenshots: dc.max_screenshots || 16,
234
+ chromePath: dc.chrome_path ?? undefined,
235
+ quality: 70,
236
+ maxWidth: 1200,
237
+ });
238
+ res.setTimeout(120_000);
239
+ engine.capture()
240
+ .then((result) => res.json({ status: "ok", screenshots: result.screenshots.length, total_size_kb: result.totalSizeKB }))
241
+ .catch((err) => {
242
+ logger.error(`DesignQC run failed: ${err}`);
243
+ res.status(500).json({ error: String(err) });
244
+ });
245
+ });
246
+ // Trigger a cron task by ID
247
+ app.post("/api/cron/run/:taskId", (req, res) => {
248
+ const { taskId } = req.params;
249
+ if (!cronEngine) {
250
+ res.status(503).json({ error: "Cron engine not running" });
251
+ return;
252
+ }
253
+ // Return 202 immediately — the task runs in the background; results arrive via the
254
+ // WebSocket / file-watcher. A failure is broadcast as task_error (upstream #4, bug 1).
255
+ res.status(202).json({ status: "accepted", task_id: taskId });
256
+ cronEngine.runTask(taskId).catch((err) => {
257
+ logger.error(`Manual task trigger failed for ${taskId}: ${err}`);
258
+ broadcast({ type: "task_error", task_id: taskId, error: String(err) });
259
+ });
260
+ });
261
+ // SPA fallback
262
+ app.get("/{*path}", (_req, res) => {
263
+ const indexPath = path.join(dashboardDir, "index.html");
264
+ if (fs.existsSync(indexPath)) {
265
+ res.sendFile(indexPath);
266
+ }
267
+ else {
268
+ res.status(404).json({ error: "Dashboard not built. Run: pnpm build:dashboard" });
269
+ }
270
+ });
271
+ // Start HTTP server
272
+ const port = config.openwolf.dashboard.port;
273
+ // Bind to loopback by default so the dashboard isn't exposed on the network (upstream #30).
274
+ const host = config.openwolf.dashboard.host || "127.0.0.1";
275
+ const server = app.listen(port, host, () => {
276
+ logger.info(`Dashboard server listening on ${host}:${port}`);
277
+ });
278
+ // WebSocket server. Reject the upgrade before it completes if the token is missing/wrong,
279
+ // so an unauthenticated client never establishes a connection at all.
280
+ const wss = new WebSocketServer({
281
+ server,
282
+ verifyClient: (info, cb) => {
283
+ let t = "";
284
+ try {
285
+ t = new URL(info.req.url || "", "http://localhost").searchParams.get("token") || "";
286
+ }
287
+ catch { /* reject */ }
288
+ if (tokenMatches(t, dashboardToken))
289
+ cb(true);
290
+ else
291
+ cb(false, 401, "unauthorized");
292
+ },
293
+ });
294
+ wss.on("connection", (ws) => {
295
+ wsClients.add(ws);
296
+ logger.info("WebSocket client connected");
297
+ ws.on("message", (data) => {
298
+ try {
299
+ const msg = JSON.parse(data.toString());
300
+ handleDashboardCommand(msg);
301
+ }
302
+ catch {
303
+ logger.warn("Invalid WebSocket message received");
304
+ }
305
+ });
306
+ ws.on("close", () => {
307
+ wsClients.delete(ws);
308
+ });
309
+ // Send initial state
310
+ broadcast({ type: "daemon_started", timestamp: new Date().toISOString() });
311
+ });
312
+ function broadcast(msg) {
313
+ const data = JSON.stringify(msg);
314
+ for (const client of wsClients) {
315
+ if (client.readyState === WebSocket.OPEN) {
316
+ client.send(data);
317
+ }
318
+ }
319
+ }
320
+ function handleDashboardCommand(msg) {
321
+ switch (msg.type) {
322
+ case "trigger_task":
323
+ if (msg.task_id && cronEngine) {
324
+ cronEngine.runTask(msg.task_id).catch((err) => {
325
+ logger.error(`Manual task trigger failed: ${err}`);
326
+ });
327
+ }
328
+ break;
329
+ case "retry_dead_letter":
330
+ if (msg.task_id) {
331
+ const statePath = path.join(wolfDir, "cron-state.json");
332
+ const state = readJSON(statePath, {
333
+ dead_letter_queue: [],
334
+ });
335
+ state.dead_letter_queue = state.dead_letter_queue.filter((d) => d.task_id !== msg.task_id);
336
+ writeJSON(statePath, state);
337
+ }
338
+ break;
339
+ case "force_scan":
340
+ if (cronEngine) {
341
+ cronEngine.runTask("anatomy-rescan").catch((err) => {
342
+ logger.error(`Force scan failed: ${err}`);
343
+ });
344
+ }
345
+ break;
346
+ case "request_full_state":
347
+ // Send all files
348
+ try {
349
+ const files = {};
350
+ for (const file of WOLF_BROADCAST_FILES) {
351
+ files[file] = readWolfFileForDashboard(file);
352
+ }
353
+ broadcast({ type: "full_state", files, timestamp: new Date().toISOString() });
354
+ }
355
+ catch (err) {
356
+ logger.error(`Full state request failed: ${err}`);
357
+ }
358
+ break;
359
+ }
360
+ }
361
+ // Cron engine
362
+ let cronEngine = null;
363
+ if (config.openwolf.cron.enabled) {
364
+ cronEngine = new CronEngine(wolfDir, projectRoot, logger, broadcast);
365
+ cronEngine.start();
366
+ }
367
+ // File watcher
368
+ let fileWatcher = startFileWatcher(wolfDir, logger, broadcast);
369
+ // Hot-switch to another registered project without restarting the process (#4, bug 7).
370
+ // The dashboard token is unchanged, so already-connected clients stay authenticated.
371
+ function switchProject(newRoot) {
372
+ logger.info(`Switching project to: ${newRoot}`);
373
+ // Stop the current subsystems.
374
+ if (cronEngine) {
375
+ cronEngine.stop();
376
+ cronEngine = null;
377
+ }
378
+ fileWatcher.close();
379
+ // Swap the mutable project bindings.
380
+ projectRoot = newRoot;
381
+ wolfDir = path.join(newRoot, ".wolf");
382
+ projectMeta = detectProjectMeta();
383
+ // Restart subsystems for the new project.
384
+ if (config.openwolf.cron.enabled) {
385
+ cronEngine = new CronEngine(wolfDir, projectRoot, logger, broadcast);
386
+ cronEngine.start();
387
+ }
388
+ fileWatcher = startFileWatcher(wolfDir, logger, broadcast);
389
+ // Mark the new project as running.
390
+ const statePath = path.join(wolfDir, "cron-state.json");
391
+ const state = readJSON(statePath, {});
392
+ state.engine_status = "running";
393
+ state.last_heartbeat = new Date().toISOString();
394
+ writeJSON(statePath, state);
395
+ // Push the new project's state to all connected dashboard clients (trimmed via the helper).
396
+ const files = {};
397
+ for (const file of WOLF_BROADCAST_FILES)
398
+ files[file] = readWolfFileForDashboard(file);
399
+ broadcast({ type: "project_switched", project: { name: projectMeta.name, root: projectRoot }, files });
400
+ }
401
+ // Health heartbeat
402
+ const heartbeatInterval = config.openwolf.cron.heartbeat_interval_minutes * 60 * 1000;
403
+ const heartbeatTimer = setInterval(() => {
404
+ const statePath = path.join(wolfDir, "cron-state.json");
405
+ const state = readJSON(statePath, {});
406
+ state.last_heartbeat = new Date().toISOString();
407
+ writeJSON(statePath, state);
408
+ broadcast({ type: "health", status: "healthy", uptime: Math.floor((Date.now() - startTime) / 1000) });
409
+ }, heartbeatInterval);
410
+ // Update cron-state to running
411
+ const cronStatePath = path.join(wolfDir, "cron-state.json");
412
+ const cronState = readJSON(cronStatePath, {});
413
+ cronState.engine_status = "running";
414
+ cronState.last_heartbeat = new Date().toISOString();
415
+ writeJSON(cronStatePath, cronState);
416
+ logger.info("OpenWolf daemon started");
417
+ // Graceful shutdown
418
+ function shutdown() {
419
+ logger.info("Daemon shutting down...");
420
+ broadcast({ type: "daemon_stopping", timestamp: new Date().toISOString() });
421
+ clearInterval(heartbeatTimer);
422
+ if (cronEngine)
423
+ cronEngine.stop();
424
+ const state = readJSON(cronStatePath, {});
425
+ state.engine_status = "stopped";
426
+ writeJSON(cronStatePath, state);
427
+ for (const client of wsClients) {
428
+ client.close();
429
+ }
430
+ wsClients.clear();
431
+ server.close(() => {
432
+ logger.info("Daemon stopped");
433
+ process.exit(0);
434
+ });
435
+ // Force exit after 5s
436
+ setTimeout(() => process.exit(0), 5000);
437
+ }
438
+ process.on("SIGTERM", shutdown);
439
+ process.on("SIGINT", shutdown);
440
+ //# 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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"}