create-metaclaw 3.3.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 (92) hide show
  1. package/LICENSE +44 -0
  2. package/README.md +282 -0
  3. package/docs/assets/favicon.png +0 -0
  4. package/docs/assets/metaclaw-banner.svg +86 -0
  5. package/docs/assets/qis-logo.png +0 -0
  6. package/docs/assets/yz-favicon.png +0 -0
  7. package/docs/assets/yz-logo.png +0 -0
  8. package/docs/index.html +895 -0
  9. package/installer/assets/favicon.png +0 -0
  10. package/installer/auto-start.ts +330 -0
  11. package/installer/brand.ts +115 -0
  12. package/installer/core-scaffold.ts +448 -0
  13. package/installer/dashboard-generator.ts +657 -0
  14. package/installer/detect.ts +129 -0
  15. package/installer/index.ts +355 -0
  16. package/installer/module-loader.ts +412 -0
  17. package/installer/modules/boardroom/boardroom/client.ts.txt +201 -0
  18. package/installer/modules/boardroom/boardroom/db.ts.txt +322 -0
  19. package/installer/modules/boardroom/boardroom/meeting-agent.ts.txt +129 -0
  20. package/installer/modules/boardroom/boardroom/meeting-scheduler.ts.txt +194 -0
  21. package/installer/modules/boardroom/boardroom/server.ts.txt +473 -0
  22. package/installer/modules/boardroom/boardroom/start-boardroom.bat.txt +26 -0
  23. package/installer/modules/boardroom/boardroom/summons.ts.txt +76 -0
  24. package/installer/modules/boardroom/boardroom/turn-v2.ts.txt +172 -0
  25. package/installer/modules/boardroom/boardroom/turn.ts.txt +208 -0
  26. package/installer/modules/boardroom/boardroom/types.ts.txt +100 -0
  27. package/installer/modules/boardroom/metaclaw-module.json +35 -0
  28. package/installer/modules/boardroom/scripts/meeting-check.bat.txt +38 -0
  29. package/installer/modules/core/metaclaw-module.json +51 -0
  30. package/installer/modules/core/src/db.ts.txt +277 -0
  31. package/installer/modules/core/src/health-check.ts.txt +128 -0
  32. package/installer/modules/core/src/observability.ts.txt +20 -0
  33. package/installer/modules/core/src/safety.ts.txt +26 -0
  34. package/installer/modules/core/src/scan-capabilities.ts.txt +196 -0
  35. package/installer/modules/core/src/self-improve.ts.txt +48 -0
  36. package/installer/modules/core/src/self-update.ts.txt +345 -0
  37. package/installer/modules/core/src/sync-context.ts.txt +133 -0
  38. package/installer/modules/core/src/tasks.ts.txt +159 -0
  39. package/installer/modules/custom/metaclaw-module.json +15 -0
  40. package/installer/modules/custom/src/agent-custom.ts.txt +100 -0
  41. package/installer/modules/dashboard/metaclaw-module.json +23 -0
  42. package/installer/modules/dashboard/scripts/build-dashboard.cjs.txt +51 -0
  43. package/installer/modules/dashboard/src/update-dashboard.ts.txt +126 -0
  44. package/installer/modules/outreach/metaclaw-module.json +29 -0
  45. package/installer/modules/outreach/src/agent-outreach.ts.txt +193 -0
  46. package/installer/modules/outreach/src/inbox-agent.ts.txt +283 -0
  47. package/installer/modules/outreach/src/morning-report.ts.txt +124 -0
  48. package/installer/modules/research/metaclaw-module.json +15 -0
  49. package/installer/modules/research/src/agent-research.ts.txt +127 -0
  50. package/installer/modules/scheduler/metaclaw-module.json +27 -0
  51. package/installer/modules/scheduler/scripts/agent-cycle.bat.txt +85 -0
  52. package/installer/modules/scheduler/scripts/detect-session.bat.txt +41 -0
  53. package/installer/modules/scheduler/scripts/launch.bat.txt +120 -0
  54. package/installer/modules/scheduler/src/cron-manager.ts.txt +273 -0
  55. package/installer/modules/social/metaclaw-module.json +15 -0
  56. package/installer/modules/social/src/agent-social.ts.txt +110 -0
  57. package/installer/modules/support/metaclaw-module.json +15 -0
  58. package/installer/modules/support/src/agent-support.ts.txt +60 -0
  59. package/installer/modules/swarm/metaclaw-module.json +25 -0
  60. package/installer/modules/swarm/swarm/dht-client.ts.txt +376 -0
  61. package/installer/modules/swarm/swarm/relay-server.ts.txt +348 -0
  62. package/installer/modules/swarm/swarm/swarm-client.ts.txt +303 -0
  63. package/installer/modules/swarm/swarm/types.ts.txt +51 -0
  64. package/installer/modules/voice/metaclaw-module.json +16 -0
  65. package/installer/questionnaire.ts +277 -0
  66. package/installer/research.ts +258 -0
  67. package/installer/scaffold-from-config.ts +270 -0
  68. package/installer/task-generator.ts +324 -0
  69. package/installer/templates/agent-custom.ts.txt +100 -0
  70. package/installer/templates/agent-cycle.bat.txt +19 -0
  71. package/installer/templates/agent-outreach.ts.txt +193 -0
  72. package/installer/templates/agent-research.ts.txt +127 -0
  73. package/installer/templates/agent-social.ts.txt +110 -0
  74. package/installer/templates/agent-support.ts.txt +60 -0
  75. package/installer/templates/build-dashboard.cjs.txt +51 -0
  76. package/installer/templates/cron-manager.ts.txt +273 -0
  77. package/installer/templates/dashboard.html.txt +450 -0
  78. package/installer/templates/db.ts.txt +277 -0
  79. package/installer/templates/detect-session.bat.txt +41 -0
  80. package/installer/templates/health-check.ts.txt +128 -0
  81. package/installer/templates/inbox-agent.ts.txt +283 -0
  82. package/installer/templates/launch.bat.txt +120 -0
  83. package/installer/templates/morning-report.ts.txt +124 -0
  84. package/installer/templates/observability.ts.txt +20 -0
  85. package/installer/templates/safety.ts.txt +26 -0
  86. package/installer/templates/self-improve.ts.txt +48 -0
  87. package/installer/templates/self-update.ts.txt +345 -0
  88. package/installer/templates/state.json.txt +33 -0
  89. package/installer/templates/system-context.json.txt +33 -0
  90. package/installer/templates/update-dashboard.ts.txt +126 -0
  91. package/package.json +31 -0
  92. package/setup.bat +178 -0
@@ -0,0 +1,448 @@
1
+ /**
2
+ * MetaClaw Core Scaffold
3
+ *
4
+ * Every Claw gets these built-in best practices automatically.
5
+ * Uses template files from installer/templates/ to avoid nested backtick issues.
6
+ */
7
+
8
+ import fs from "fs";
9
+ import path from "path";
10
+ import { fileURLToPath } from "url";
11
+ import type { ClawConfig } from "./research.js";
12
+ import type { SystemInfo } from "./detect.js";
13
+ import { generateDashboard } from "./dashboard-generator.js";
14
+
15
+ const __dirname = path.dirname(fileURLToPath(import.meta.url));
16
+ const TEMPLATES_DIR = path.join(__dirname, "templates");
17
+
18
+ function readTemplate(name: string): string {
19
+ return fs.readFileSync(path.join(TEMPLATES_DIR, name), "utf-8");
20
+ }
21
+
22
+ /**
23
+ * Generate the full project scaffolding for any Claw type.
24
+ */
25
+ export function scaffoldProject(
26
+ projectDir: string,
27
+ config: ClawConfig,
28
+ systemInfo: SystemInfo
29
+ ): void {
30
+ // Create directory structure
31
+ const dirs = ["src", "src/tools", "data", "data/logs", "scripts"];
32
+ for (const dir of dirs) {
33
+ fs.mkdirSync(path.join(projectDir, dir), { recursive: true });
34
+ }
35
+
36
+ // Write all core files
37
+ writePackageJson(projectDir, config);
38
+ writeClaudeMd(projectDir, config);
39
+ writeSoulMd(projectDir, config);
40
+ writeHeartbeatMd(projectDir, config);
41
+ writeGitignore(projectDir);
42
+ writeEnvExample(projectDir, config);
43
+
44
+ // Copy template files (universal modules)
45
+ fs.writeFileSync(path.join(projectDir, "src", "db.ts"), readTemplate("db.ts.txt"));
46
+ fs.writeFileSync(path.join(projectDir, "src", "observability.ts"), readTemplate("observability.ts.txt"));
47
+ fs.writeFileSync(path.join(projectDir, "src", "self-improve.ts"), readTemplate("self-improve.ts.txt"));
48
+
49
+ // Dashboard — CUSTOM generated based on claw type
50
+ const sessionName = config.name.toLowerCase().replace(/[^a-z0-9]/g, "-");
51
+ const dashboardHtml = generateDashboard(
52
+ config.name,
53
+ config.template,
54
+ (config as any).answers || {},
55
+ config.rawResearch
56
+ );
57
+ fs.writeFileSync(path.join(projectDir, "dashboard.html"), dashboardHtml);
58
+
59
+ // Copy favicon for dashboard branding
60
+ const faviconSrc = path.join(TEMPLATES_DIR, "..", "assets", "favicon.png");
61
+ if (fs.existsSync(faviconSrc)) {
62
+ fs.copyFileSync(faviconSrc, path.join(projectDir, "favicon.png"));
63
+ }
64
+
65
+ const dashboardTs = readTemplate("update-dashboard.ts.txt")
66
+ .replace(/__AGENT_NAME__/g, config.name)
67
+ .replace(/__CLAW_TYPE__/g, config.template);
68
+ fs.writeFileSync(path.join(projectDir, "src", "update-dashboard.ts"), dashboardTs);
69
+
70
+ // Safety — needs config substitution
71
+ const safetyContent = readTemplate("safety.ts.txt").replace(
72
+ "__SAFETY_CONFIG__",
73
+ JSON.stringify({
74
+ maxActionsPerDay: (config.safety as any)?.maxActionsPerDay || 50,
75
+ maxActionsPerHour: (config.safety as any)?.maxActionsPerHour || 10,
76
+ circuitBreakerThreshold: (config.safety as any)?.circuitBreakerThreshold || 0.05,
77
+ }, null, 2)
78
+ );
79
+ fs.writeFileSync(path.join(projectDir, "src", "safety.ts"), safetyContent);
80
+
81
+ // Self-update module (universal)
82
+ fs.writeFileSync(path.join(projectDir, "src", "self-update.ts"), readTemplate("self-update.ts.txt"));
83
+
84
+ // Health check module
85
+ fs.writeFileSync(path.join(projectDir, "src", "health-check.ts"), readTemplate("health-check.ts.txt"));
86
+
87
+ // Cron manager — with variable substitution
88
+ const selfUpdateMinutes = ((config as any).selfUpdateIntervalHours || 6) * 60;
89
+ const cronManager = readTemplate("cron-manager.ts.txt")
90
+ .replace(/__AGENT_NAME__/g, config.name)
91
+ .replace(/__SESSION_NAME__/g, sessionName)
92
+ .replace(/__SELF_UPDATE_INTERVAL__/g, String(selfUpdateMinutes));
93
+ fs.writeFileSync(path.join(projectDir, "src", "cron-manager.ts"), cronManager);
94
+
95
+ // system-context.json — learning accumulation (Outreach pattern)
96
+ const sysCtx = readTemplate("system-context.json.txt")
97
+ .replace(/__TIMESTAMP__/g, new Date().toISOString());
98
+ fs.writeFileSync(path.join(projectDir, "data", "system-context.json"), sysCtx);
99
+
100
+ // build-dashboard.cjs — inline data baking for offline dashboards (AXIOM pattern)
101
+ fs.mkdirSync(path.join(projectDir, "scripts"), { recursive: true });
102
+ fs.writeFileSync(path.join(projectDir, "scripts", "build-dashboard.cjs"), readTemplate("build-dashboard.cjs.txt"));
103
+
104
+ // Agent cycle .bat — specific numbered instructions for cron agent (AXIOM pattern)
105
+ const cycleBat = readTemplate("agent-cycle.bat.txt")
106
+ .replace(/__AGENT_NAME__/g, config.name)
107
+ .replace(/__PROJECT_DIR__/g, projectDir);
108
+ fs.writeFileSync(path.join(projectDir, "scripts", "agent-cycle.bat"), cycleBat);
109
+
110
+ // AI Inbox Agent — 8-category classifier (Outreach pattern)
111
+ const inboxAgent = readTemplate("inbox-agent.ts.txt").replace(/__AGENT_NAME__/g, config.name);
112
+ fs.writeFileSync(path.join(projectDir, "src", "inbox-agent.ts"), inboxAgent);
113
+
114
+ // Morning report email (AXIOM pattern — email is the lifeline)
115
+ const morningReport = readTemplate("morning-report.ts.txt").replace(/__AGENT_NAME__/g, config.name);
116
+ fs.writeFileSync(path.join(projectDir, "src", "morning-report.ts"), morningReport);
117
+
118
+ // VIP emails list (empty — operator fills in)
119
+ fs.writeFileSync(path.join(projectDir, "data", "vip-emails.json"), "[]");
120
+
121
+ // Main agent entry point (template-specific)
122
+ writeAgentFromTemplate(projectDir, config);
123
+
124
+ // Save initial prompt version to DB-init script
125
+ writePromptInit(projectDir, config);
126
+
127
+ // Launch.bat — correct session directory handling
128
+ const encodedPath = projectDir.replace(/[:/\\]/g, "-").replace(/^-/, "");
129
+ const launchBat = readTemplate("launch.bat.txt")
130
+ .replace(/__AGENT_NAME__/g, config.name)
131
+ .replace(/__PROJECT_DIR__/g, projectDir)
132
+ .replace(/__ENCODED_PATH__/g, encodedPath)
133
+ .replace(/__SESSION_NAME__/g, sessionName);
134
+ fs.writeFileSync(path.join(projectDir, "scripts", "launch.bat"), launchBat);
135
+
136
+ // Desktop launcher (opens in its own window)
137
+ const desktopLauncher = [
138
+ "@echo off",
139
+ `start "${config.name}" cmd /k "cd /d ""${projectDir}"" && scripts\\launch.bat"`,
140
+ ].join("\r\n");
141
+ fs.writeFileSync(path.join(projectDir, `Launch ${config.name}.bat`), desktopLauncher);
142
+
143
+ // Dashboard opener (app mode)
144
+ const dashUrl = path.join(projectDir, "dashboard.html").replace(/\\/g, "/");
145
+ const dashOpener = [
146
+ "@echo off",
147
+ `cd /d "${projectDir}"`,
148
+ `call npx tsx src/update-dashboard.ts 2>nul`,
149
+ `if exist "C:\\Program Files (x86)\\Microsoft\\Edge\\Application\\msedge.exe" (`,
150
+ ` start "" "C:\\Program Files (x86)\\Microsoft\\Edge\\Application\\msedge.exe" --app="file:///${dashUrl}" --window-size=1400,900`,
151
+ `) else if exist "C:\\Program Files\\Microsoft\\Edge\\Application\\msedge.exe" (`,
152
+ ` start "" "C:\\Program Files\\Microsoft\\Edge\\Application\\msedge.exe" --app="file:///${dashUrl}" --window-size=1400,900`,
153
+ `) else (`,
154
+ ` start "" "${path.join(projectDir, "dashboard.html")}"`,
155
+ `)`,
156
+ ].join("\r\n");
157
+ fs.writeFileSync(path.join(projectDir, "scripts", "open-dashboard.bat"), dashOpener);
158
+
159
+ // state.json — shared brain between sessions (AXIOM + Outreach pattern)
160
+ const stateJson = readTemplate("state.json.txt")
161
+ .replace(/__AGENT_NAME__/g, config.name)
162
+ .replace(/__CLAW_TYPE__/g, config.template)
163
+ .replace(/__TIMESTAMP__/g, new Date().toISOString());
164
+ fs.writeFileSync(path.join(projectDir, "data", "state.json"), stateJson);
165
+
166
+ // Save research output if available
167
+ if (config.rawResearch) {
168
+ fs.writeFileSync(path.join(projectDir, "data", "research-output.md"), config.rawResearch);
169
+ }
170
+
171
+ // Write init config script
172
+ const updateIntervalMs = ((config as any).selfUpdateIntervalHours || 6) * 60 * 60 * 1000;
173
+ const initConfigContent = [
174
+ '// Initialize config — run once after npm install',
175
+ 'import { getDb, setConfig } from "./db.js";',
176
+ "getDb();",
177
+ 'setConfig("self_update_interval_ms", "' + updateIntervalMs + '");',
178
+ 'setConfig("agent_name", ' + JSON.stringify(config.name) + ');',
179
+ 'setConfig("template", ' + JSON.stringify(config.template) + ');',
180
+ 'setConfig("created_at", new Date().toISOString());',
181
+ 'console.log("Config initialized.");',
182
+ ].join("\n");
183
+ fs.writeFileSync(path.join(projectDir, "src", "init-config.ts"), initConfigContent);
184
+ }
185
+
186
+ function writePackageJson(dir: string, config: ClawConfig) {
187
+ const pkg = {
188
+ name: config.name,
189
+ version: "1.0.0",
190
+ type: "module",
191
+ description: `${config.template} agent — built by MetaClaw v3.3.0`,
192
+ scripts: {
193
+ start: "tsx src/agent.ts",
194
+ "dry-run": "tsx src/agent.ts --dry-run",
195
+ status: "tsx src/agent.ts --status",
196
+ dashboard: "tsx src/update-dashboard.ts && node scripts/build-dashboard.cjs",
197
+ "self-update": "tsx src/self-update.ts",
198
+ "health-check": "tsx src/health-check.ts",
199
+ crons: "tsx src/cron-manager.ts",
200
+ "crons-setup": "tsx src/cron-manager.ts setup",
201
+ "crons-list": "tsx src/cron-manager.ts list",
202
+ "check-inbox": "tsx src/inbox-agent.ts",
203
+ "morning-report": "tsx src/morning-report.ts",
204
+ init: "tsx src/init-config.ts && tsx src/init-prompts.ts",
205
+ postinstall: "npm run init",
206
+ test: "echo 'Tests not yet configured'",
207
+ },
208
+ dependencies: {
209
+ "@anthropic-ai/claude-agent-sdk": "latest",
210
+ "@types/better-sqlite3": "latest",
211
+ "better-sqlite3": "latest",
212
+ "nodemailer": "latest",
213
+ "imapflow": "latest",
214
+ "mailparser": "latest",
215
+ tsx: "latest",
216
+ typescript: "latest",
217
+ },
218
+ };
219
+ fs.writeFileSync(path.join(dir, "package.json"), JSON.stringify(pkg, null, 2));
220
+ }
221
+
222
+ function writeClaudeMd(dir: string, config: ClawConfig) {
223
+ const content = [
224
+ `# ${config.name}`,
225
+ `Generated by MetaClaw Installer v3.3.0 | Yonder Zenith LLC`,
226
+ "",
227
+ "## FIRST LAUNCH INSTRUCTIONS",
228
+ "If this is your first time starting, do the following:",
229
+ "1. Run `npm run status` to verify all systems are operational",
230
+ "2. Run `npm run health-check` to verify system health",
231
+ "3. Run `npm run crons-list` to verify scheduled tasks are active",
232
+ "4. Run `npm run dashboard` to generate the Command Center dashboard",
233
+ "5. Introduce yourself to the user — tell them your name, what you do, and what commands are available",
234
+ "6. Ask the user how they want to proceed",
235
+ "",
236
+ `## Who You Are`,
237
+ `You are ${config.name}, an autonomous AI agent.`,
238
+ `Type: ${config.template}`,
239
+ "",
240
+ "## Your System Prompt",
241
+ config.systemPrompt,
242
+ "",
243
+ "## Commands",
244
+ "```bash",
245
+ "npm start # Run the agent",
246
+ "npm run dry-run # Test without external actions",
247
+ "npm run status # View metrics + safety status",
248
+ "npm run dashboard # Regenerate Command Center data",
249
+ "npm run self-update # Force a self-improvement cycle",
250
+ "npm run health-check # Run system health check",
251
+ "npm run crons-setup # Set up scheduled tasks",
252
+ "npm run crons-list # List active scheduled tasks",
253
+ "```",
254
+ "",
255
+ "## Scripts",
256
+ "- `scripts/launch.bat` — Launch this agent in Claude Code (resumes session)",
257
+ "- `scripts/open-dashboard.bat` — Open Command Center in app mode",
258
+ "- `Launch " + config.name + ".bat` — Quick launcher (opens in own window)",
259
+ "",
260
+ "## State Management (CRITICAL)",
261
+ "Read `data/state.json` at the START of every session. This is your shared brain.",
262
+ "The `next_priority_action` field tells you what to do next.",
263
+ "Update state.json at the END of every session with what you accomplished.",
264
+ "Pattern: READ state first → DO work → WRITE state last.",
265
+ "",
266
+ "## Two-Agent Architecture",
267
+ "You may run in two modes:",
268
+ "1. **Main session** (Claude Code CLI, full context, interactive) — for strategy, complex tasks, operator chat",
269
+ "2. **Cron agent** (Agent SDK, Sonnet, 30 turns, no context) — for scheduled automated tasks",
270
+ "The cron agent reads state.json and follows explicit instructions. It cannot reason about strategy.",
271
+ "When setting `next_priority_action`, be SPECIFIC — the cron agent needs exact steps, not goals.",
272
+ "",
273
+ "## Self-Improvement",
274
+ "You use the Generator-Reflector-Curator pattern.",
275
+ "Prompt versions tracked in database. A/B testing after 30 completions.",
276
+ "Self-update runs AFTER tasks, never before.",
277
+ "",
278
+ "## Principles",
279
+ "Read SOUL.md for your core principles. Never violate them.",
280
+ "",
281
+ "## Dashboard",
282
+ "Open dashboard.html in browser (or scripts/open-dashboard.bat for app mode).",
283
+ "Run `npm run dashboard` to update data.",
284
+ ].join("\n");
285
+ fs.writeFileSync(path.join(dir, "CLAUDE.md"), content);
286
+ }
287
+
288
+ function writeSoulMd(dir: string, config: ClawConfig) {
289
+ const content = [
290
+ `# ${config.name} — Identity`,
291
+ "",
292
+ "## Core Principles (never override these)",
293
+ "1. I verify my outputs before presenting them as final.",
294
+ "2. I acknowledge uncertainty rather than fabricating confidence.",
295
+ "3. I prefer well-established approaches over novel untested ones.",
296
+ "4. I break complex tasks into verifiable sub-tasks.",
297
+ "5. I explain my reasoning so humans can audit my decisions.",
298
+ "6. When I detect I'm in a failure loop, I stop and request help.",
299
+ "7. I never take irreversible actions without confirmation.",
300
+ "8. I track the cost and impact of every action I take.",
301
+ "",
302
+ "## System Prompt",
303
+ config.systemPrompt,
304
+ ].join("\n");
305
+ fs.writeFileSync(path.join(dir, "SOUL.md"), content);
306
+ }
307
+
308
+ function writeHeartbeatMd(dir: string, config: ClawConfig) {
309
+ const content = [
310
+ "# Heartbeat Checklist",
311
+ `Schedule: ${config.schedule.description}`,
312
+ "",
313
+ "On each heartbeat:",
314
+ "1. Check circuit breaker status - if OPEN, log and skip",
315
+ "2. Check rate limits - if at capacity, log and skip",
316
+ "3. Run pending tasks (follow-ups, inbox checks, scheduled work)",
317
+ "4. Record metrics (actions taken, cost, success rate)",
318
+ "5. If self-improvement cycle is due, run reflection",
319
+ "6. Report status to logs",
320
+ ].join("\n");
321
+ fs.writeFileSync(path.join(dir, "HEARTBEAT.md"), content);
322
+ }
323
+
324
+ function writeAgentFromTemplate(dir: string, config: ClawConfig) {
325
+ // Map template ID to template file
326
+ const templateMap: Record<string, string> = {
327
+ outreach: "agent-outreach.ts.txt",
328
+ research: "agent-research.ts.txt",
329
+ support: "agent-support.ts.txt",
330
+ social: "agent-social.ts.txt",
331
+ custom: "agent-custom.ts.txt",
332
+ };
333
+
334
+ const templateFile = templateMap[config.template] || "agent-custom.ts.txt";
335
+ let content = readTemplate(templateFile);
336
+
337
+ // Substitute all template variables
338
+ const sessionName = config.name.toLowerCase().replace(/[^a-z0-9]/g, "-");
339
+ const systemPromptEscaped = config.systemPrompt.replace(/\\/g, "\\\\").replace(/`/g, "\\`").replace(/\$/g, "\\$");
340
+
341
+ content = content.replace(/__AGENT_NAME__/g, config.name);
342
+ content = content.replace(/__SESSION_NAME__/g, sessionName);
343
+ content = content.replace(/__SYSTEM_PROMPT__/g, systemPromptEscaped);
344
+
345
+ fs.writeFileSync(path.join(dir, "src", "agent.ts"), content);
346
+ }
347
+
348
+ function writePromptInit(dir: string, config: ClawConfig) {
349
+ // Create a script that seeds the initial prompt version into the DB
350
+ const content = [
351
+ '// Initialize prompt versions — run once after npm install',
352
+ 'import { getDb } from "./db.js";',
353
+ "",
354
+ "const db = getDb();",
355
+ "const promptType = " + JSON.stringify(config.template) + ";",
356
+ "const content = " + JSON.stringify(config.systemPrompt) + ";",
357
+ "",
358
+ 'const existing = db.prepare("SELECT 1 FROM prompt_versions WHERE prompt_type = ?").get(promptType);',
359
+ "if (!existing) {",
360
+ ' db.prepare("INSERT INTO prompt_versions (prompt_type, version, content, created_by) VALUES (?, 1, ?, ?)").run(promptType, content, "installer");',
361
+ ' console.log("Initial prompt version seeded for " + promptType);',
362
+ "} else {",
363
+ ' console.log("Prompt version already exists for " + promptType);',
364
+ "}",
365
+ ].join("\n");
366
+ fs.writeFileSync(path.join(dir, "src", "init-prompts.ts"), content);
367
+ }
368
+
369
+ // Keep old function as fallback
370
+ function writeMainAgent(dir: string, config: ClawConfig) {
371
+ const systemPromptEscaped = JSON.stringify(config.systemPrompt);
372
+ const content = [
373
+ "/**",
374
+ ` * ${config.name} - Main Agent`,
375
+ ` * Template: ${config.template}`,
376
+ " * Generated by MetaClaw Installer v3.3.0",
377
+ " */",
378
+ "",
379
+ 'import { query } from "@anthropic-ai/claude-agent-sdk";',
380
+ 'import type { SDKResultMessage, SDKResultSuccess, SDKAssistantMessage, Options } from "@anthropic-ai/claude-agent-sdk";',
381
+ 'import { getDb, recordAction, getTodayMetrics, getCircuitBreaker } from "./db.js";',
382
+ 'import { checkCanAct, SAFETY_CONFIG } from "./safety.js";',
383
+ 'import { log } from "./observability.js";',
384
+ 'import { recordOutcome, shouldOptimize, getCurrentPrompt } from "./self-improve.js";',
385
+ "",
386
+ 'const DRY_RUN = process.argv.includes("--dry-run");',
387
+ 'const STATUS = process.argv.includes("--status");',
388
+ "",
389
+ "if (STATUS) {",
390
+ " getDb();",
391
+ " const metrics = getTodayMetrics();",
392
+ ' const breaker = getCircuitBreaker("main");',
393
+ ` console.log("${config.name} Status");`,
394
+ ' console.log("=".repeat(40));',
395
+ ' console.log("Circuit breaker:", breaker?.state?.toUpperCase() || "CLOSED");',
396
+ ' console.log("Today:", metrics ? metrics.actions_taken + " actions, $" + (metrics.total_cost_usd || 0).toFixed(4) + " cost" : "No activity");',
397
+ " process.exit(0);",
398
+ "}",
399
+ "",
400
+ "async function main() {",
401
+ " getDb();",
402
+ ` console.log("${config.name}" + (DRY_RUN ? " (DRY RUN)" : ""));`,
403
+ "",
404
+ " const safety = checkCanAct();",
405
+ " if (!safety.allowed) {",
406
+ ' console.log("BLOCKED: " + safety.reason);',
407
+ " process.exit(0);",
408
+ " }",
409
+ "",
410
+ ` const systemPrompt = getCurrentPrompt("main") || ${systemPromptEscaped};`,
411
+ "",
412
+ ' log("info", "agent.start", { dryRun: DRY_RUN });',
413
+ "",
414
+ " // TODO: Implement your agent logic here",
415
+ ' console.log("Agent ready. Configure your logic in src/agent.ts");',
416
+ "}",
417
+ "",
418
+ "main().catch(err => {",
419
+ ' log("error", "agent.crash", { error: err.message });',
420
+ ' console.error("Error:", err.message);',
421
+ " process.exit(1);",
422
+ "});",
423
+ ].join("\n");
424
+ fs.writeFileSync(path.join(dir, "src", "agent.ts"), content);
425
+ }
426
+
427
+ function writeGitignore(dir: string) {
428
+ fs.writeFileSync(path.join(dir, ".gitignore"), [
429
+ "node_modules/", "dist/", "data/", "*.db", "*.db-shm", "*.db-wal", ".env", ".env.*",
430
+ ].join("\n") + "\n");
431
+ }
432
+
433
+ function writeEnvExample(dir: string, config: ClawConfig) {
434
+ const lines = [
435
+ "# MetaClaw Agent Configuration",
436
+ "# Copy to .env and fill in your values",
437
+ "",
438
+ "# ANTHROPIC_API_KEY=sk-ant-... (optional if using Claude Max login)",
439
+ ];
440
+ if (config.tools.some(t => t.includes("gmail"))) {
441
+ lines.push("# GMAIL_USER=you@gmail.com");
442
+ lines.push("# GMAIL_APP_PASSWORD=xxxx xxxx xxxx xxxx");
443
+ }
444
+ if (config.tools.includes("gptzero")) {
445
+ lines.push("# GPTZERO_API_KEY=...");
446
+ }
447
+ fs.writeFileSync(path.join(dir, ".env.example"), lines.join("\n") + "\n");
448
+ }