create-yonderclaw 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 (93) hide show
  1. package/LICENSE +44 -0
  2. package/README.md +288 -0
  3. package/bin/create-yonderclaw.mjs +43 -0
  4. package/docs/assets/favicon.png +0 -0
  5. package/docs/assets/metaclaw-banner.svg +86 -0
  6. package/docs/assets/qis-logo.png +0 -0
  7. package/docs/assets/yz-favicon.png +0 -0
  8. package/docs/assets/yz-logo.png +0 -0
  9. package/docs/index.html +1155 -0
  10. package/installer/assets/favicon.png +0 -0
  11. package/installer/auto-start.ts +330 -0
  12. package/installer/brand.ts +115 -0
  13. package/installer/core-scaffold.ts +448 -0
  14. package/installer/dashboard-generator.ts +657 -0
  15. package/installer/detect.ts +129 -0
  16. package/installer/index.ts +355 -0
  17. package/installer/module-loader.ts +412 -0
  18. package/installer/modules/boardroom/boardroom/client.ts.txt +201 -0
  19. package/installer/modules/boardroom/boardroom/db.ts.txt +322 -0
  20. package/installer/modules/boardroom/boardroom/meeting-agent.ts.txt +129 -0
  21. package/installer/modules/boardroom/boardroom/meeting-scheduler.ts.txt +194 -0
  22. package/installer/modules/boardroom/boardroom/server.ts.txt +473 -0
  23. package/installer/modules/boardroom/boardroom/start-boardroom.bat.txt +26 -0
  24. package/installer/modules/boardroom/boardroom/summons.ts.txt +76 -0
  25. package/installer/modules/boardroom/boardroom/turn-v2.ts.txt +172 -0
  26. package/installer/modules/boardroom/boardroom/turn.ts.txt +208 -0
  27. package/installer/modules/boardroom/boardroom/types.ts.txt +100 -0
  28. package/installer/modules/boardroom/metaclaw-module.json +35 -0
  29. package/installer/modules/boardroom/scripts/meeting-check.bat.txt +38 -0
  30. package/installer/modules/core/metaclaw-module.json +51 -0
  31. package/installer/modules/core/src/db.ts.txt +277 -0
  32. package/installer/modules/core/src/health-check.ts.txt +128 -0
  33. package/installer/modules/core/src/observability.ts.txt +20 -0
  34. package/installer/modules/core/src/safety.ts.txt +26 -0
  35. package/installer/modules/core/src/scan-capabilities.ts.txt +196 -0
  36. package/installer/modules/core/src/self-improve.ts.txt +48 -0
  37. package/installer/modules/core/src/self-update.ts.txt +345 -0
  38. package/installer/modules/core/src/sync-context.ts.txt +133 -0
  39. package/installer/modules/core/src/tasks.ts.txt +159 -0
  40. package/installer/modules/custom/metaclaw-module.json +15 -0
  41. package/installer/modules/custom/src/agent-custom.ts.txt +100 -0
  42. package/installer/modules/dashboard/metaclaw-module.json +23 -0
  43. package/installer/modules/dashboard/scripts/build-dashboard.cjs.txt +51 -0
  44. package/installer/modules/dashboard/src/update-dashboard.ts.txt +126 -0
  45. package/installer/modules/outreach/metaclaw-module.json +29 -0
  46. package/installer/modules/outreach/src/agent-outreach.ts.txt +193 -0
  47. package/installer/modules/outreach/src/inbox-agent.ts.txt +283 -0
  48. package/installer/modules/outreach/src/morning-report.ts.txt +124 -0
  49. package/installer/modules/research/metaclaw-module.json +15 -0
  50. package/installer/modules/research/src/agent-research.ts.txt +127 -0
  51. package/installer/modules/scheduler/metaclaw-module.json +27 -0
  52. package/installer/modules/scheduler/scripts/agent-cycle.bat.txt +85 -0
  53. package/installer/modules/scheduler/scripts/detect-session.bat.txt +41 -0
  54. package/installer/modules/scheduler/scripts/launch.bat.txt +120 -0
  55. package/installer/modules/scheduler/src/cron-manager.ts.txt +273 -0
  56. package/installer/modules/social/metaclaw-module.json +15 -0
  57. package/installer/modules/social/src/agent-social.ts.txt +110 -0
  58. package/installer/modules/support/metaclaw-module.json +15 -0
  59. package/installer/modules/support/src/agent-support.ts.txt +60 -0
  60. package/installer/modules/swarm/metaclaw-module.json +25 -0
  61. package/installer/modules/swarm/swarm/dht-client.ts.txt +376 -0
  62. package/installer/modules/swarm/swarm/relay-server.ts.txt +348 -0
  63. package/installer/modules/swarm/swarm/swarm-client.ts.txt +303 -0
  64. package/installer/modules/swarm/swarm/types.ts.txt +51 -0
  65. package/installer/modules/voice/metaclaw-module.json +16 -0
  66. package/installer/questionnaire.ts +277 -0
  67. package/installer/research.ts +258 -0
  68. package/installer/scaffold-from-config.ts +270 -0
  69. package/installer/task-generator.ts +324 -0
  70. package/installer/templates/agent-custom.ts.txt +100 -0
  71. package/installer/templates/agent-cycle.bat.txt +19 -0
  72. package/installer/templates/agent-outreach.ts.txt +193 -0
  73. package/installer/templates/agent-research.ts.txt +127 -0
  74. package/installer/templates/agent-social.ts.txt +110 -0
  75. package/installer/templates/agent-support.ts.txt +60 -0
  76. package/installer/templates/build-dashboard.cjs.txt +51 -0
  77. package/installer/templates/cron-manager.ts.txt +273 -0
  78. package/installer/templates/dashboard.html.txt +450 -0
  79. package/installer/templates/db.ts.txt +277 -0
  80. package/installer/templates/detect-session.bat.txt +41 -0
  81. package/installer/templates/health-check.ts.txt +128 -0
  82. package/installer/templates/inbox-agent.ts.txt +283 -0
  83. package/installer/templates/launch.bat.txt +120 -0
  84. package/installer/templates/morning-report.ts.txt +124 -0
  85. package/installer/templates/observability.ts.txt +20 -0
  86. package/installer/templates/safety.ts.txt +26 -0
  87. package/installer/templates/self-improve.ts.txt +48 -0
  88. package/installer/templates/self-update.ts.txt +345 -0
  89. package/installer/templates/state.json.txt +33 -0
  90. package/installer/templates/system-context.json.txt +33 -0
  91. package/installer/templates/update-dashboard.ts.txt +126 -0
  92. package/package.json +31 -0
  93. package/setup.bat +178 -0
@@ -0,0 +1,345 @@
1
+ /**
2
+ * Self-Update Module — keeps the agent's knowledge and config current
3
+ * Auto-generated by MetaClaw Installer v3.3.0
4
+ *
5
+ * Responsibilities:
6
+ * 1. Periodic memory consolidation (update CLAUDE.md, SOUL.md with learnings)
7
+ * 2. Prompt optimization (Generator→Reflector→Curator loop)
8
+ * 3. Metrics rollup and reporting
9
+ * 4. Detect when context is getting stale and trigger refresh
10
+ * 5. Log rotation and cleanup
11
+ *
12
+ * Schedule: configurable via config table (default: every 6 hours)
13
+ */
14
+
15
+ import { query } from "@anthropic-ai/claude-agent-sdk";
16
+ import type { SDKResultMessage, SDKResultSuccess } from "@anthropic-ai/claude-agent-sdk";
17
+ import fs from "fs";
18
+ import path from "path";
19
+ import { fileURLToPath } from "url";
20
+ import { getDb, getConfig, setConfig, getTodayMetrics, recordAction } from "./db.js";
21
+ import { log } from "./observability.js";
22
+ import { getCurrentPrompt, savePromptVersion, shouldOptimize } from "./self-improve.js";
23
+
24
+ const __dirname = path.dirname(fileURLToPath(import.meta.url));
25
+ const PROJECT_DIR = path.join(__dirname, "..");
26
+
27
+ // Default update interval: 6 hours (in milliseconds)
28
+ const DEFAULT_UPDATE_INTERVAL_MS = 6 * 60 * 60 * 1000;
29
+
30
+ /**
31
+ * Check if a self-update cycle is due and run it if so.
32
+ * Called at the start of every agent run.
33
+ */
34
+ export async function runSelfUpdate(): Promise<void> {
35
+ const db = getDb();
36
+ const lastUpdate = getConfig("last_self_update");
37
+ const intervalMs = parseInt(getConfig("self_update_interval_ms") || String(DEFAULT_UPDATE_INTERVAL_MS));
38
+
39
+ if (lastUpdate) {
40
+ const elapsed = Date.now() - new Date(lastUpdate).getTime();
41
+ if (elapsed < intervalMs) {
42
+ return; // Not due yet
43
+ }
44
+ }
45
+
46
+ log("info", "self_update.start", {});
47
+ console.log("[Self-Update] Running periodic maintenance...");
48
+
49
+ try {
50
+ // 1. Regenerate dashboard data
51
+ regenerateDashboard();
52
+
53
+ // 2. Consolidate metrics into CLAUDE.md
54
+ await updateClaudeMd();
55
+
56
+ // 3. Run prompt optimization if enough data
57
+ await optimizePrompts();
58
+
59
+ // 4. Rotate old logs
60
+ rotateOldLogs();
61
+
62
+ // 5. Update heartbeat
63
+ updateHeartbeat();
64
+
65
+ // 6. Update SESSION.md with current state
66
+ updateSessionState();
67
+
68
+ // Record completion
69
+ setConfig("last_self_update", new Date().toISOString());
70
+ log("info", "self_update.complete", {});
71
+ console.log("[Self-Update] Complete.");
72
+ } catch (err) {
73
+ const msg = err instanceof Error ? err.message : String(err);
74
+ log("error", "self_update.failed", { error: msg });
75
+ console.error("[Self-Update] Failed: " + msg);
76
+ }
77
+ }
78
+
79
+ /**
80
+ * Update CLAUDE.md with latest metrics and learnings.
81
+ */
82
+ async function updateClaudeMd(): Promise<void> {
83
+ const claudeMdPath = path.join(PROJECT_DIR, "CLAUDE.md");
84
+ if (!fs.existsSync(claudeMdPath)) return;
85
+
86
+ const currentContent = fs.readFileSync(claudeMdPath, "utf-8");
87
+
88
+ // Gather metrics from last 7 days
89
+ const db = getDb();
90
+ const weekMetrics = db.prepare(`
91
+ SELECT
92
+ SUM(actions_taken) as total_actions,
93
+ SUM(actions_succeeded) as total_succeeded,
94
+ SUM(actions_failed) as total_failed,
95
+ SUM(total_cost_usd) as total_cost,
96
+ COUNT(*) as days_active
97
+ FROM daily_metrics
98
+ WHERE date > date('now', '-7 days')
99
+ `).get() as any;
100
+
101
+ // Get prompt performance
102
+ const promptStats = db.prepare(`
103
+ SELECT prompt_type, version, avg_score, total_runs
104
+ FROM prompt_versions
105
+ WHERE is_active = 1
106
+ ORDER BY prompt_type
107
+ `).all() as any[];
108
+
109
+ // Build the metrics section
110
+ const metricsSection = [
111
+ "",
112
+ "## Latest Metrics (auto-updated)",
113
+ "Last updated: " + new Date().toISOString().slice(0, 16),
114
+ "",
115
+ weekMetrics ? [
116
+ "### Last 7 Days",
117
+ "- Actions: " + (weekMetrics.total_actions || 0),
118
+ "- Success rate: " + (weekMetrics.total_actions > 0 ? ((weekMetrics.total_succeeded / weekMetrics.total_actions) * 100).toFixed(1) + "%" : "N/A"),
119
+ "- Cost: $" + (weekMetrics.total_cost || 0).toFixed(2),
120
+ "- Days active: " + (weekMetrics.days_active || 0),
121
+ ].join("\n") : "No metrics yet.",
122
+ "",
123
+ promptStats.length > 0 ? [
124
+ "### Prompt Performance",
125
+ ...promptStats.map((p: any) => "- " + p.prompt_type + " v" + p.version + ": avg " + (p.avg_score || 0).toFixed(1) + "/10 (" + p.total_runs + " runs)"),
126
+ ].join("\n") : "",
127
+ ].join("\n");
128
+
129
+ // Replace or append metrics section
130
+ const metricsMarker = "## Latest Metrics (auto-updated)";
131
+ if (currentContent.includes(metricsMarker)) {
132
+ // Replace existing metrics section (from marker to next ## or end)
133
+ const before = currentContent.split(metricsMarker)[0];
134
+ const afterMatch = currentContent.split(metricsMarker)[1]?.match(/\n## [^L]/);
135
+ const after = afterMatch ? currentContent.split(metricsMarker)[1].slice(afterMatch.index!) : "";
136
+ fs.writeFileSync(claudeMdPath, before + metricsSection + after);
137
+ } else {
138
+ // Append
139
+ fs.writeFileSync(claudeMdPath, currentContent + "\n" + metricsSection);
140
+ }
141
+
142
+ log("info", "self_update.claude_md_updated", {});
143
+ }
144
+
145
+ /**
146
+ * Run the Curator — optimize prompts based on performance data.
147
+ * Only runs when shouldOptimize() returns true (every 30 runs).
148
+ */
149
+ async function optimizePrompts(): Promise<void> {
150
+ const db = getDb();
151
+
152
+ // Get all prompt types that need optimization
153
+ const promptTypes = db.prepare(
154
+ "SELECT DISTINCT prompt_type FROM prompt_versions WHERE is_active = 1"
155
+ ).all() as any[];
156
+
157
+ for (const { prompt_type } of promptTypes) {
158
+ if (!shouldOptimize(prompt_type)) continue;
159
+
160
+ const current = getCurrentPrompt(prompt_type);
161
+ if (!current) continue;
162
+
163
+ // Get recent performance data
164
+ const recentActions = db.prepare(`
165
+ SELECT status, details, cost_usd
166
+ FROM action_log
167
+ WHERE action_type LIKE '%${prompt_type}%'
168
+ ORDER BY created_at DESC
169
+ LIMIT 50
170
+ `).all() as any[];
171
+
172
+ const successRate = recentActions.length > 0
173
+ ? recentActions.filter((a: any) => a.status === "success").length / recentActions.length
174
+ : 0;
175
+
176
+ // Only optimize if success rate is below 90%
177
+ if (successRate > 0.9) {
178
+ log("info", "self_update.skip_optimize", { prompt_type, successRate });
179
+ continue;
180
+ }
181
+
182
+ log("info", "self_update.optimizing_prompt", { prompt_type, successRate });
183
+
184
+ try {
185
+ // Ask Claude to improve the prompt
186
+ const optimizePrompt = [
187
+ "You are a prompt optimization expert. Analyze this prompt and its performance data, then produce an improved version.",
188
+ "",
189
+ "CURRENT PROMPT:",
190
+ current,
191
+ "",
192
+ "PERFORMANCE DATA:",
193
+ "- Success rate: " + (successRate * 100).toFixed(1) + "%",
194
+ "- Total recent runs: " + recentActions.length,
195
+ "- Common failure details: " + recentActions.filter((a: any) => a.status === "error").map((a: any) => a.details).filter(Boolean).slice(0, 5).join("; "),
196
+ "",
197
+ "RULES:",
198
+ "- Change ONE thing at a time (so we can measure impact)",
199
+ "- Keep the same structure and format",
200
+ "- Focus on the biggest failure mode",
201
+ "- The improved prompt must be directly usable (no meta-commentary)",
202
+ "",
203
+ "Output ONLY the improved prompt text. Nothing else.",
204
+ ].join("\n");
205
+
206
+ let improvedPrompt = "";
207
+ const stream = query({
208
+ prompt: optimizePrompt,
209
+ options: { allowedTools: [], maxTurns: 1, model: "claude-sonnet-4-6" },
210
+ });
211
+
212
+ for await (const message of stream) {
213
+ if (message.type === "assistant") {
214
+ const msg = message as any;
215
+ if (msg.message?.content) {
216
+ for (const block of msg.message.content) {
217
+ if (block.type === "text") improvedPrompt += block.text;
218
+ }
219
+ }
220
+ }
221
+ }
222
+
223
+ if (improvedPrompt.trim()) {
224
+ savePromptVersion(prompt_type, improvedPrompt.trim(), "curator");
225
+ log("info", "self_update.prompt_optimized", { prompt_type });
226
+ }
227
+ } catch (err) {
228
+ log("error", "self_update.optimize_failed", { prompt_type, error: String(err) });
229
+ }
230
+ }
231
+ }
232
+
233
+ /**
234
+ * Rotate logs older than 30 days.
235
+ */
236
+ function rotateOldLogs(): void {
237
+ const logsDir = path.join(PROJECT_DIR, "data", "logs");
238
+ if (!fs.existsSync(logsDir)) return;
239
+
240
+ const thirtyDaysAgo = new Date();
241
+ thirtyDaysAgo.setDate(thirtyDaysAgo.getDate() - 30);
242
+
243
+ const files = fs.readdirSync(logsDir);
244
+ let rotated = 0;
245
+
246
+ for (const file of files) {
247
+ if (!file.endsWith(".jsonl")) continue;
248
+ const filePath = path.join(logsDir, file);
249
+ const stats = fs.statSync(filePath);
250
+ if (stats.mtime < thirtyDaysAgo) {
251
+ fs.unlinkSync(filePath);
252
+ rotated++;
253
+ }
254
+ }
255
+
256
+ if (rotated > 0) {
257
+ log("info", "self_update.logs_rotated", { count: rotated });
258
+ }
259
+ }
260
+
261
+ /**
262
+ * Update HEARTBEAT.md with last run timestamp.
263
+ */
264
+ function updateHeartbeat(): void {
265
+ const heartbeatPath = path.join(PROJECT_DIR, "HEARTBEAT.md");
266
+ if (!fs.existsSync(heartbeatPath)) return;
267
+
268
+ let content = fs.readFileSync(heartbeatPath, "utf-8");
269
+ const now = new Date().toISOString().slice(0, 16);
270
+
271
+ if (content.includes("Last run:")) {
272
+ content = content.replace(/Last run:.*/, "Last run: " + now);
273
+ } else {
274
+ content += "\nLast run: " + now;
275
+ }
276
+
277
+ fs.writeFileSync(heartbeatPath, content);
278
+ }
279
+
280
+ /**
281
+ * Regenerate dashboard.json for the HTML dashboard.
282
+ */
283
+ function regenerateDashboard(): void {
284
+ try {
285
+ const { execSync } = require("child_process");
286
+ execSync("npx tsx src/update-dashboard.ts", { cwd: PROJECT_DIR, stdio: "pipe", timeout: 15000 });
287
+ log("info", "self_update.dashboard_regenerated", {});
288
+ } catch {
289
+ // Non-critical — dashboard will update on next manual run
290
+ }
291
+ }
292
+
293
+ /**
294
+ * Update SESSION.md with current agent state.
295
+ */
296
+ function updateSessionState(): void {
297
+ const sessionPath = path.join(PROJECT_DIR, "SESSION.md");
298
+ const db = getDb();
299
+ const now = new Date().toISOString().slice(0, 16);
300
+
301
+ const metrics = db.prepare("SELECT * FROM daily_metrics ORDER BY date DESC LIMIT 7").all() as any[];
302
+ const totalActions = metrics.reduce((s: number, m: any) => s + (m.actions_taken || 0), 0);
303
+ const totalCost = metrics.reduce((s: number, m: any) => s + (m.total_cost_usd || 0), 0);
304
+ const breaker = db.prepare("SELECT state, reason FROM circuit_breaker WHERE name = 'main'").get() as any;
305
+
306
+ const promptInfo = db.prepare(
307
+ "SELECT version, avg_score, total_runs FROM prompt_versions WHERE is_active = 1 ORDER BY version DESC LIMIT 1"
308
+ ).get() as any;
309
+
310
+ const content = [
311
+ "# Agent Session State",
312
+ "> Auto-updated: " + now,
313
+ "",
314
+ "## Health",
315
+ "- Circuit breaker: " + (breaker?.state || "closed").toUpperCase(),
316
+ breaker?.reason ? "- Reason: " + breaker.reason : "",
317
+ "",
318
+ "## Last 7 Days",
319
+ "- Total actions: " + totalActions,
320
+ "- Total cost: $" + totalCost.toFixed(2),
321
+ ...metrics.map((m: any) => "- " + m.date + ": " + m.actions_taken + " actions, $" + (m.total_cost_usd || 0).toFixed(4)),
322
+ "",
323
+ "## Self-Improvement",
324
+ promptInfo ? "- Current prompt: v" + promptInfo.version + " (avg score: " + (promptInfo.avg_score || 0).toFixed(1) + "/10, " + promptInfo.total_runs + " runs)" : "- Prompt: v1 (default)",
325
+ "- Next optimization: run #" + (promptInfo ? Math.ceil((promptInfo.total_runs + 1) / 30) * 30 : 30),
326
+ ].filter(Boolean).join("\n");
327
+
328
+ fs.writeFileSync(sessionPath, content);
329
+ log("info", "self_update.session_updated", {});
330
+ }
331
+
332
+ /**
333
+ * Force a self-update cycle (for manual trigger).
334
+ */
335
+ export async function forceSelfUpdate(): Promise<void> {
336
+ setConfig("last_self_update", "2000-01-01T00:00:00Z");
337
+ await runSelfUpdate();
338
+ }
339
+
340
+ // --- CLI Entry Point ---
341
+ if (process.argv[1]?.includes("self-update")) {
342
+ getDb();
343
+ console.log("Forcing self-update cycle...\n");
344
+ forceSelfUpdate().then(() => process.exit(0));
345
+ }
@@ -0,0 +1,33 @@
1
+ {
2
+ "version": "1.0.0",
3
+ "initialized_at": "__TIMESTAMP__",
4
+ "days_operational": 0,
5
+ "agent_name": "__AGENT_NAME__",
6
+ "template": "__CLAW_TYPE__",
7
+ "operator": "",
8
+
9
+ "metrics": {
10
+ "sessions_completed": 0,
11
+ "tasks_completed": 0,
12
+ "tasks_failed": 0,
13
+ "error_rate": 0
14
+ },
15
+
16
+ "platforms": {},
17
+
18
+ "active_strategies": [],
19
+ "killed_strategies": [],
20
+
21
+ "current_focus": "Initial setup — read CLAUDE.md and SOUL.md",
22
+ "next_priority_action": "Run npm run status to verify systems, then introduce yourself to operator",
23
+
24
+ "system_context": {
25
+ "what_works": [],
26
+ "what_doesnt_work": [],
27
+ "core_rules": [],
28
+ "top_issues": [],
29
+ "last_self_eval": null
30
+ },
31
+
32
+ "session_notes": []
33
+ }
@@ -0,0 +1,33 @@
1
+ {
2
+ "lastUpdated": "__TIMESTAMP__",
3
+
4
+ "campaignStats": {
5
+ "totalActions": 0,
6
+ "totalSucceeded": 0,
7
+ "totalFailed": 0,
8
+ "successRate": "0%"
9
+ },
10
+
11
+ "coreRules": [
12
+ "Read state.json at the START of every session",
13
+ "Update state.json at the END of every session",
14
+ "Self-update runs AFTER tasks, never before",
15
+ "Never create one-off scripts — use existing tools",
16
+ "Produce at least 1 tangible output per cycle"
17
+ ],
18
+
19
+ "whatWorks": [],
20
+ "whatDoesntWork": [],
21
+
22
+ "topObjections": [],
23
+
24
+ "latestStrategyInsight": "",
25
+
26
+ "processNotes": [
27
+ "Cron agent needs SPECIFIC numbered instructions — not goals",
28
+ "Email > Dashboard for operator communication",
29
+ "next_priority_action in state.json bridges main session and cron agent"
30
+ ],
31
+
32
+ "lastSelfEval": null
33
+ }
@@ -0,0 +1,126 @@
1
+ /**
2
+ * Dashboard Data Generator — universal for all Claws
3
+ * Reads all DB tables and writes dashboard.json for the HTML dashboard.
4
+ * Auto-generated by MetaClaw Installer v3.3.0
5
+ *
6
+ * Run: npm run dashboard
7
+ * Also called by self-update module automatically.
8
+ */
9
+
10
+ import Database from "better-sqlite3";
11
+ import fs from "fs";
12
+ import path from "path";
13
+ import { fileURLToPath } from "url";
14
+
15
+ const __dirname = path.dirname(fileURLToPath(import.meta.url));
16
+ const DB_PATH = path.join(__dirname, "..", "data", "claw.db");
17
+ const LOG_DIR = path.join(__dirname, "..", "data", "logs");
18
+ const OUTPUT = path.join(__dirname, "..", "data", "dashboard.json");
19
+
20
+ function main() {
21
+ if (!fs.existsSync(DB_PATH)) {
22
+ console.log("No database found. Run the agent first.");
23
+ return;
24
+ }
25
+
26
+ const db = new Database(DB_PATH);
27
+ db.pragma("journal_mode = WAL");
28
+
29
+ const now = new Date();
30
+ const today = now.toISOString().slice(0, 10);
31
+
32
+ // Today's metrics
33
+ const todayMetrics = db.prepare("SELECT * FROM daily_metrics WHERE date = ?").get(today) as any || {
34
+ actions_taken: 0, actions_succeeded: 0, actions_failed: 0, total_cost_usd: 0, total_tokens: 0
35
+ };
36
+
37
+ // Circuit breaker
38
+ const circuitBreaker = db.prepare("SELECT * FROM circuit_breaker WHERE name = 'main'").get() as any || { state: 'closed' };
39
+
40
+ // Safety config (from config table)
41
+ let safetyConfig = { maxActionsPerDay: 50, maxActionsPerHour: 10 };
42
+ try {
43
+ const raw = db.prepare("SELECT value FROM config WHERE key = 'safety_config'").get() as any;
44
+ if (raw) safetyConfig = JSON.parse(raw.value);
45
+ } catch {}
46
+
47
+ // Prompt version info
48
+ let promptVersion = null;
49
+ try {
50
+ promptVersion = db.prepare(
51
+ "SELECT version, avg_score, total_runs, created_by FROM prompt_versions WHERE is_active = 1 ORDER BY version DESC LIMIT 1"
52
+ ).get() as any;
53
+ } catch {}
54
+
55
+ // Recent actions
56
+ const recentActions = db.prepare(
57
+ "SELECT action_type, target, status, cost_usd, created_at FROM action_log ORDER BY created_at DESC LIMIT 20"
58
+ ).all() as any[];
59
+
60
+ // Self-improvement info
61
+ let selfImprovement: any = {};
62
+ try {
63
+ const lastUpdate = db.prepare("SELECT value FROM config WHERE key = 'last_self_update'").get() as any;
64
+ const interval = db.prepare("SELECT value FROM config WHERE key = 'self_update_interval_ms'").get() as any;
65
+ const totalVersions = db.prepare("SELECT COUNT(*) as cnt FROM prompt_versions").get() as any;
66
+ const currentVersion = db.prepare(
67
+ "SELECT total_runs FROM prompt_versions WHERE is_active = 1 ORDER BY version DESC LIMIT 1"
68
+ ).get() as any;
69
+
70
+ selfImprovement = {
71
+ last_update: lastUpdate?.value || null,
72
+ interval_hours: interval ? Math.round(parseInt(interval.value) / 3600000) : 6,
73
+ total_versions: totalVersions?.cnt || 1,
74
+ next_optimize_at: currentVersion ? "run #" + (Math.ceil((currentVersion.total_runs + 1) / 30) * 30) : "run #30",
75
+ };
76
+ } catch {}
77
+
78
+ // Log stats
79
+ const logFile = path.join(LOG_DIR, "agent-" + today + ".jsonl");
80
+ let logStats = { total: 0, errors: 0, warnings: 0 };
81
+ if (fs.existsSync(logFile)) {
82
+ const lines = fs.readFileSync(logFile, "utf-8").trim().split("\n").filter(Boolean);
83
+ logStats.total = lines.length;
84
+ for (const line of lines) {
85
+ try {
86
+ const entry = JSON.parse(line);
87
+ if (entry.level === "error") logStats.errors++;
88
+ if (entry.level === "warn") logStats.warnings++;
89
+ } catch {}
90
+ }
91
+ }
92
+
93
+ // All-time metrics
94
+ const allMetrics = db.prepare("SELECT * FROM daily_metrics ORDER BY date DESC LIMIT 7").all() as any[];
95
+ const totalCost = allMetrics.reduce((sum: number, m: any) => sum + ((m.total_cost_usd as number) || 0), 0);
96
+
97
+ // Suppression count
98
+ let suppressionCount = 0;
99
+ try {
100
+ suppressionCount = (db.prepare("SELECT COUNT(*) as cnt FROM suppression_list").get() as any).cnt;
101
+ } catch {}
102
+
103
+ // Build dashboard data
104
+ const dashboard = {
105
+ generated_at: now.toISOString(),
106
+ agent_name: "__AGENT_NAME__",
107
+ claw_type: "__CLAW_TYPE__",
108
+
109
+ today_metrics: todayMetrics,
110
+ circuit_breaker: circuitBreaker,
111
+ safety_config: safetyConfig,
112
+ prompt_version: promptVersion,
113
+ recent_actions: recentActions,
114
+ self_improvement: selfImprovement,
115
+ logs: logStats,
116
+ suppression_count: suppressionCount,
117
+ total_cost: Math.round(totalCost * 100) / 100,
118
+ daily_metrics: allMetrics,
119
+ };
120
+
121
+ fs.mkdirSync(path.dirname(OUTPUT), { recursive: true });
122
+ fs.writeFileSync(OUTPUT, JSON.stringify(dashboard, null, 2));
123
+ console.log("Dashboard data written to " + OUTPUT);
124
+ }
125
+
126
+ main();
package/package.json ADDED
@@ -0,0 +1,31 @@
1
+ {
2
+ "name": "create-yonderclaw",
3
+ "version": "1.0.0",
4
+ "description": "YonderClaw — Autonomous AI Agent Platform by Yonder Zenith LLC",
5
+ "type": "module",
6
+ "bin": {
7
+ "create-yonderclaw": "bin/create-yonderclaw.mjs"
8
+ },
9
+ "scripts": {
10
+ "start": "tsx installer/index.ts",
11
+ "create": "tsx installer/index.ts"
12
+ },
13
+ "author": "Yonder Zenith LLC",
14
+ "license": "MIT",
15
+ "dependencies": {
16
+ "@anthropic-ai/claude-agent-sdk": "^0.2.77",
17
+ "@clack/prompts": "^1.1.0",
18
+ "@types/better-sqlite3": "^7.6.13",
19
+ "@types/figlet": "^1.7.0",
20
+ "@types/gradient-string": "^1.1.6",
21
+ "better-sqlite3": "^12.8.0",
22
+ "chalk": "^5.6.2",
23
+ "figlet": "^1.11.0",
24
+ "gradient-string": "^3.0.0",
25
+ "hyperswarm": "^4.17.0",
26
+ "listr2": "^10.2.1",
27
+ "ora": "^9.3.0",
28
+ "tsx": "^4.21.0",
29
+ "typescript": "^5.9.3"
30
+ }
31
+ }