@dotsetlabs/dotclaw 1.1.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 (170) hide show
  1. package/.env.example +54 -0
  2. package/LICENSE +21 -0
  3. package/README.md +111 -0
  4. package/config-examples/groups/global/CLAUDE.md +21 -0
  5. package/config-examples/groups/main/CLAUDE.md +47 -0
  6. package/config-examples/mount-allowlist.json +25 -0
  7. package/config-examples/plugin-http.json +18 -0
  8. package/config-examples/runtime.json +30 -0
  9. package/config-examples/tool-budgets.json +24 -0
  10. package/config-examples/tool-policy.json +51 -0
  11. package/container/.dockerignore +6 -0
  12. package/container/Dockerfile +74 -0
  13. package/container/agent-runner/package-lock.json +92 -0
  14. package/container/agent-runner/package.json +20 -0
  15. package/container/agent-runner/src/agent-config.ts +295 -0
  16. package/container/agent-runner/src/container-protocol.ts +73 -0
  17. package/container/agent-runner/src/daemon.ts +91 -0
  18. package/container/agent-runner/src/index.ts +1428 -0
  19. package/container/agent-runner/src/ipc.ts +321 -0
  20. package/container/agent-runner/src/memory.ts +336 -0
  21. package/container/agent-runner/src/prompt-packs.ts +341 -0
  22. package/container/agent-runner/src/tools.ts +1720 -0
  23. package/container/agent-runner/tsconfig.json +19 -0
  24. package/container/build.sh +23 -0
  25. package/container/skills/agent-browser.md +159 -0
  26. package/dist/admin-commands.d.ts +7 -0
  27. package/dist/admin-commands.d.ts.map +1 -0
  28. package/dist/admin-commands.js +87 -0
  29. package/dist/admin-commands.js.map +1 -0
  30. package/dist/agent-context.d.ts +42 -0
  31. package/dist/agent-context.d.ts.map +1 -0
  32. package/dist/agent-context.js +92 -0
  33. package/dist/agent-context.js.map +1 -0
  34. package/dist/agent-execution.d.ts +68 -0
  35. package/dist/agent-execution.d.ts.map +1 -0
  36. package/dist/agent-execution.js +169 -0
  37. package/dist/agent-execution.js.map +1 -0
  38. package/dist/agent-semaphore.d.ts +2 -0
  39. package/dist/agent-semaphore.d.ts.map +1 -0
  40. package/dist/agent-semaphore.js +52 -0
  41. package/dist/agent-semaphore.js.map +1 -0
  42. package/dist/behavior-config.d.ts +14 -0
  43. package/dist/behavior-config.d.ts.map +1 -0
  44. package/dist/behavior-config.js +52 -0
  45. package/dist/behavior-config.js.map +1 -0
  46. package/dist/cli.d.ts +3 -0
  47. package/dist/cli.d.ts.map +1 -0
  48. package/dist/cli.js +626 -0
  49. package/dist/cli.js.map +1 -0
  50. package/dist/config.d.ts +31 -0
  51. package/dist/config.d.ts.map +1 -0
  52. package/dist/config.js +38 -0
  53. package/dist/config.js.map +1 -0
  54. package/dist/container-protocol.d.ts +72 -0
  55. package/dist/container-protocol.d.ts.map +1 -0
  56. package/dist/container-protocol.js +3 -0
  57. package/dist/container-protocol.js.map +1 -0
  58. package/dist/container-runner.d.ts +59 -0
  59. package/dist/container-runner.d.ts.map +1 -0
  60. package/dist/container-runner.js +813 -0
  61. package/dist/container-runner.js.map +1 -0
  62. package/dist/cost.d.ts +9 -0
  63. package/dist/cost.d.ts.map +1 -0
  64. package/dist/cost.js +11 -0
  65. package/dist/cost.js.map +1 -0
  66. package/dist/dashboard.d.ts +58 -0
  67. package/dist/dashboard.d.ts.map +1 -0
  68. package/dist/dashboard.js +471 -0
  69. package/dist/dashboard.js.map +1 -0
  70. package/dist/db.d.ts +99 -0
  71. package/dist/db.d.ts.map +1 -0
  72. package/dist/db.js +423 -0
  73. package/dist/db.js.map +1 -0
  74. package/dist/error-messages.d.ts +17 -0
  75. package/dist/error-messages.d.ts.map +1 -0
  76. package/dist/error-messages.js +109 -0
  77. package/dist/error-messages.js.map +1 -0
  78. package/dist/index.d.ts +2 -0
  79. package/dist/index.d.ts.map +1 -0
  80. package/dist/index.js +2072 -0
  81. package/dist/index.js.map +1 -0
  82. package/dist/locks.d.ts +2 -0
  83. package/dist/locks.d.ts.map +1 -0
  84. package/dist/locks.js +26 -0
  85. package/dist/locks.js.map +1 -0
  86. package/dist/logger.d.ts +4 -0
  87. package/dist/logger.d.ts.map +1 -0
  88. package/dist/logger.js +15 -0
  89. package/dist/logger.js.map +1 -0
  90. package/dist/maintenance.d.ts +13 -0
  91. package/dist/maintenance.d.ts.map +1 -0
  92. package/dist/maintenance.js +151 -0
  93. package/dist/maintenance.js.map +1 -0
  94. package/dist/memory-embeddings.d.ts +13 -0
  95. package/dist/memory-embeddings.d.ts.map +1 -0
  96. package/dist/memory-embeddings.js +126 -0
  97. package/dist/memory-embeddings.js.map +1 -0
  98. package/dist/memory-recall.d.ts +8 -0
  99. package/dist/memory-recall.d.ts.map +1 -0
  100. package/dist/memory-recall.js +127 -0
  101. package/dist/memory-recall.js.map +1 -0
  102. package/dist/memory-store.d.ts +149 -0
  103. package/dist/memory-store.d.ts.map +1 -0
  104. package/dist/memory-store.js +787 -0
  105. package/dist/memory-store.js.map +1 -0
  106. package/dist/metrics.d.ts +12 -0
  107. package/dist/metrics.d.ts.map +1 -0
  108. package/dist/metrics.js +134 -0
  109. package/dist/metrics.js.map +1 -0
  110. package/dist/model-registry.d.ts +67 -0
  111. package/dist/model-registry.d.ts.map +1 -0
  112. package/dist/model-registry.js +230 -0
  113. package/dist/model-registry.js.map +1 -0
  114. package/dist/mount-security.d.ts +37 -0
  115. package/dist/mount-security.d.ts.map +1 -0
  116. package/dist/mount-security.js +284 -0
  117. package/dist/mount-security.js.map +1 -0
  118. package/dist/paths.d.ts +80 -0
  119. package/dist/paths.d.ts.map +1 -0
  120. package/dist/paths.js +149 -0
  121. package/dist/paths.js.map +1 -0
  122. package/dist/personalization.d.ts +6 -0
  123. package/dist/personalization.d.ts.map +1 -0
  124. package/dist/personalization.js +180 -0
  125. package/dist/personalization.js.map +1 -0
  126. package/dist/progress.d.ts +15 -0
  127. package/dist/progress.d.ts.map +1 -0
  128. package/dist/progress.js +92 -0
  129. package/dist/progress.js.map +1 -0
  130. package/dist/runtime-config.d.ts +227 -0
  131. package/dist/runtime-config.d.ts.map +1 -0
  132. package/dist/runtime-config.js +297 -0
  133. package/dist/runtime-config.js.map +1 -0
  134. package/dist/task-scheduler.d.ts +9 -0
  135. package/dist/task-scheduler.d.ts.map +1 -0
  136. package/dist/task-scheduler.js +195 -0
  137. package/dist/task-scheduler.js.map +1 -0
  138. package/dist/telegram-format.d.ts +3 -0
  139. package/dist/telegram-format.d.ts.map +1 -0
  140. package/dist/telegram-format.js +200 -0
  141. package/dist/telegram-format.js.map +1 -0
  142. package/dist/tool-budgets.d.ts +16 -0
  143. package/dist/tool-budgets.d.ts.map +1 -0
  144. package/dist/tool-budgets.js +83 -0
  145. package/dist/tool-budgets.js.map +1 -0
  146. package/dist/tool-policy.d.ts +18 -0
  147. package/dist/tool-policy.d.ts.map +1 -0
  148. package/dist/tool-policy.js +84 -0
  149. package/dist/tool-policy.js.map +1 -0
  150. package/dist/trace-writer.d.ts +39 -0
  151. package/dist/trace-writer.d.ts.map +1 -0
  152. package/dist/trace-writer.js +27 -0
  153. package/dist/trace-writer.js.map +1 -0
  154. package/dist/types.d.ts +81 -0
  155. package/dist/types.d.ts.map +1 -0
  156. package/dist/types.js +2 -0
  157. package/dist/types.js.map +1 -0
  158. package/dist/utils.d.ts +4 -0
  159. package/dist/utils.d.ts.map +1 -0
  160. package/dist/utils.js +30 -0
  161. package/dist/utils.js.map +1 -0
  162. package/launchd/com.dotclaw.plist +32 -0
  163. package/package.json +89 -0
  164. package/scripts/autotune.js +53 -0
  165. package/scripts/bootstrap.js +348 -0
  166. package/scripts/configure.js +200 -0
  167. package/scripts/doctor.js +164 -0
  168. package/scripts/init.js +209 -0
  169. package/scripts/install.sh +219 -0
  170. package/systemd/dotclaw.service +22 -0
@@ -0,0 +1,341 @@
1
+ import fs from 'fs';
2
+ import path from 'path';
3
+ import { z } from 'zod';
4
+
5
+ const PROMPT_PACK_SCHEMA = z.object({
6
+ name: z.string(),
7
+ version: z.string(),
8
+ behavior: z.string(),
9
+ instructions: z.string(),
10
+ demos: z.array(z.object({
11
+ input: z.string(),
12
+ output: z.any()
13
+ })).default([]),
14
+ metric: z.object({
15
+ name: z.string(),
16
+ model: z.string(),
17
+ score: z.number()
18
+ }).optional(),
19
+ metadata: z.record(z.string(), z.any()).optional()
20
+ });
21
+
22
+ export type PromptPack = z.infer<typeof PROMPT_PACK_SCHEMA>;
23
+
24
+ export type PromptPackSource = 'group' | 'global';
25
+
26
+ export type PromptPackLoadResult = {
27
+ pack: PromptPack;
28
+ source: PromptPackSource;
29
+ isCanary?: boolean;
30
+ };
31
+
32
+ function readPromptPack(filePath: string, behavior: string): PromptPack | null {
33
+ if (!fs.existsSync(filePath)) return null;
34
+ try {
35
+ const raw = JSON.parse(fs.readFileSync(filePath, 'utf-8'));
36
+ const parsed = PROMPT_PACK_SCHEMA.parse(raw);
37
+ if (parsed.behavior !== behavior) return null;
38
+ return parsed;
39
+ } catch {
40
+ return null;
41
+ }
42
+ }
43
+
44
+ function clampRate(rate: number): number {
45
+ if (!Number.isFinite(rate)) return 0;
46
+ if (rate > 1) return Math.min(rate / 100, 1);
47
+ return Math.max(0, Math.min(rate, 1));
48
+ }
49
+
50
+ function shouldUseCanary(rate: number): boolean {
51
+ if (rate <= 0) return false;
52
+ if (rate >= 1) return true;
53
+ return Math.random() < rate;
54
+ }
55
+
56
+ function getCanaryRate(pack: PromptPack, fallbackRate: number): number {
57
+ const percent = pack.metadata?.canaryPercent;
58
+ if (typeof percent === 'number') {
59
+ return clampRate(percent / 100);
60
+ }
61
+ return clampRate(fallbackRate);
62
+ }
63
+
64
+ export function loadPromptPack(params: {
65
+ behavior: string;
66
+ groupDir: string;
67
+ globalDir?: string;
68
+ extraDirs?: string[];
69
+ }): PromptPackLoadResult | null {
70
+ const filenames = [`${params.behavior}.json`];
71
+ const searchDirs: Array<{ dir: string; source: PromptPackSource }> = [
72
+ { dir: path.join(params.groupDir, 'prompts'), source: 'group' }
73
+ ];
74
+ if (params.extraDirs) {
75
+ for (const extraDir of params.extraDirs) {
76
+ searchDirs.push({ dir: extraDir, source: 'global' });
77
+ }
78
+ }
79
+ if (params.globalDir) {
80
+ searchDirs.push({ dir: path.join(params.globalDir, 'prompts'), source: 'global' });
81
+ }
82
+
83
+ for (const { dir, source } of searchDirs) {
84
+ for (const filename of filenames) {
85
+ const filePath = path.join(dir, filename);
86
+ const pack = readPromptPack(filePath, params.behavior);
87
+ if (pack) return { pack, source };
88
+ }
89
+ }
90
+
91
+ return null;
92
+ }
93
+
94
+ export function loadPromptPackWithCanary(params: {
95
+ behavior: string;
96
+ groupDir: string;
97
+ globalDir?: string;
98
+ sharedDir?: string;
99
+ canaryRate: number;
100
+ }): PromptPackLoadResult | null {
101
+ const groupPack = readPromptPack(path.join(params.groupDir, 'prompts', `${params.behavior}.json`), params.behavior);
102
+ if (groupPack) return { pack: groupPack, source: 'group' };
103
+
104
+ if (params.globalDir) {
105
+ const globalPack = readPromptPack(path.join(params.globalDir, 'prompts', `${params.behavior}.json`), params.behavior);
106
+ if (globalPack) return { pack: globalPack, source: 'global' };
107
+ }
108
+
109
+ if (params.sharedDir) {
110
+ const canaryPath = path.join(params.sharedDir, `${params.behavior}.canary.json`);
111
+ const sharedPath = path.join(params.sharedDir, `${params.behavior}.json`);
112
+ const canaryPack = readPromptPack(canaryPath, params.behavior);
113
+ const sharedPack = readPromptPack(sharedPath, params.behavior);
114
+
115
+ if (canaryPack && !sharedPack) {
116
+ return { pack: canaryPack, source: 'global', isCanary: true };
117
+ }
118
+
119
+ if (canaryPack) {
120
+ const rate = getCanaryRate(canaryPack, params.canaryRate);
121
+ if (shouldUseCanary(rate)) {
122
+ return { pack: canaryPack, source: 'global', isCanary: true };
123
+ }
124
+ }
125
+
126
+ if (sharedPack) return { pack: sharedPack, source: 'global', isCanary: false };
127
+ }
128
+
129
+ return null;
130
+ }
131
+
132
+ export function formatTaskExtractionPack(params: {
133
+ pack: PromptPack;
134
+ maxDemos: number;
135
+ maxChars: number;
136
+ }): string {
137
+ const instructions = params.pack.instructions.trim();
138
+ const demos = params.pack.demos.slice(0, params.maxDemos);
139
+
140
+ const demoLines = demos.map((demo) => {
141
+ const output = demo.output === null ? 'null' : JSON.stringify(demo.output);
142
+ return `Input: ${demo.input}\nOutput: ${output}`;
143
+ });
144
+
145
+ const block = [
146
+ 'Task Extraction Guidelines (Autotune):',
147
+ instructions,
148
+ demoLines.length > 0 ? `Examples:\n${demoLines.join('\n\n')}` : ''
149
+ ].filter(Boolean).join('\n\n');
150
+
151
+ if (block.length <= params.maxChars) return block;
152
+
153
+ // Truncate demos if block exceeds max size
154
+ let trimmed = ['Task Extraction Guidelines (Autotune):', instructions].join('\n\n');
155
+ if (trimmed.length > params.maxChars) {
156
+ return trimmed.slice(0, params.maxChars);
157
+ }
158
+
159
+ for (const demo of demoLines) {
160
+ const candidate = `${trimmed}\n\nExamples:\n${demo}`;
161
+ if (candidate.length > params.maxChars) break;
162
+ trimmed = candidate;
163
+ }
164
+
165
+ return trimmed;
166
+ }
167
+
168
+ export function formatResponseQualityPack(params: {
169
+ pack: PromptPack;
170
+ maxDemos: number;
171
+ maxChars: number;
172
+ }): string {
173
+ const instructions = params.pack.instructions.trim();
174
+ const demos = params.pack.demos.slice(0, params.maxDemos);
175
+
176
+ const demoLines = demos.map((demo) => {
177
+ const output = demo.output === null ? 'null' : JSON.stringify(demo.output);
178
+ return `Input: ${demo.input}\nOutput: ${output}`;
179
+ });
180
+
181
+ const block = [
182
+ 'Response Quality Guidelines (Autotune):',
183
+ instructions,
184
+ demoLines.length > 0 ? `Examples:\n${demoLines.join('\n\n')}` : ''
185
+ ].filter(Boolean).join('\n\n');
186
+
187
+ if (block.length <= params.maxChars) return block;
188
+
189
+ let trimmed = ['Response Quality Guidelines (Autotune):', instructions].join('\n\n');
190
+ if (trimmed.length > params.maxChars) {
191
+ return trimmed.slice(0, params.maxChars);
192
+ }
193
+
194
+ for (const demo of demoLines) {
195
+ const candidate = `${trimmed}\n\nExamples:\n${demo}`;
196
+ if (candidate.length > params.maxChars) break;
197
+ trimmed = candidate;
198
+ }
199
+
200
+ return trimmed;
201
+ }
202
+
203
+ export function formatToolCallingPack(params: {
204
+ pack: PromptPack;
205
+ maxDemos: number;
206
+ maxChars: number;
207
+ }): string {
208
+ const instructions = params.pack.instructions.trim();
209
+ const demos = params.pack.demos.slice(0, params.maxDemos);
210
+
211
+ const demoLines = demos.map((demo) => {
212
+ const output = demo.output === null ? 'null' : JSON.stringify(demo.output);
213
+ return `Input: ${demo.input}\nOutput: ${output}`;
214
+ });
215
+
216
+ const block = [
217
+ 'Tool Calling Guidelines (Autotune):',
218
+ instructions,
219
+ demoLines.length > 0 ? `Examples:\n${demoLines.join('\n\n')}` : ''
220
+ ].filter(Boolean).join('\n\n');
221
+
222
+ if (block.length <= params.maxChars) return block;
223
+
224
+ let trimmed = ['Tool Calling Guidelines (Autotune):', instructions].join('\n\n');
225
+ if (trimmed.length > params.maxChars) {
226
+ return trimmed.slice(0, params.maxChars);
227
+ }
228
+
229
+ for (const demo of demoLines) {
230
+ const candidate = `${trimmed}\n\nExamples:\n${demo}`;
231
+ if (candidate.length > params.maxChars) break;
232
+ trimmed = candidate;
233
+ }
234
+
235
+ return trimmed;
236
+ }
237
+
238
+ export function formatToolOutcomePack(params: {
239
+ pack: PromptPack;
240
+ maxDemos: number;
241
+ maxChars: number;
242
+ }): string {
243
+ const instructions = params.pack.instructions.trim();
244
+ const demos = params.pack.demos.slice(0, params.maxDemos);
245
+
246
+ const demoLines = demos.map((demo) => {
247
+ const output = demo.output === null ? 'null' : JSON.stringify(demo.output);
248
+ return `Input: ${demo.input}\nOutput: ${output}`;
249
+ });
250
+
251
+ const block = [
252
+ 'Tool Outcome Guidelines (Autotune):',
253
+ instructions,
254
+ demoLines.length > 0 ? `Examples:\n${demoLines.join('\n\n')}` : ''
255
+ ].filter(Boolean).join('\n\n');
256
+
257
+ if (block.length <= params.maxChars) return block;
258
+
259
+ let trimmed = ['Tool Outcome Guidelines (Autotune):', instructions].join('\n\n');
260
+ if (trimmed.length > params.maxChars) {
261
+ return trimmed.slice(0, params.maxChars);
262
+ }
263
+
264
+ for (const demo of demoLines) {
265
+ const candidate = `${trimmed}\n\nExamples:\n${demo}`;
266
+ if (candidate.length > params.maxChars) break;
267
+ trimmed = candidate;
268
+ }
269
+
270
+ return trimmed;
271
+ }
272
+
273
+ export function formatMemoryPolicyPack(params: {
274
+ pack: PromptPack;
275
+ maxDemos: number;
276
+ maxChars: number;
277
+ }): string {
278
+ const instructions = params.pack.instructions.trim();
279
+ const demos = params.pack.demos.slice(0, params.maxDemos);
280
+
281
+ const demoLines = demos.map((demo) => {
282
+ const output = demo.output === null ? 'null' : JSON.stringify(demo.output);
283
+ return `Input: ${demo.input}\nOutput: ${output}`;
284
+ });
285
+
286
+ const block = [
287
+ 'Memory Policy Guidelines (Autotune):',
288
+ instructions,
289
+ demoLines.length > 0 ? `Examples:\n${demoLines.join('\n\n')}` : ''
290
+ ].filter(Boolean).join('\n\n');
291
+
292
+ if (block.length <= params.maxChars) return block;
293
+
294
+ let trimmed = ['Memory Policy Guidelines (Autotune):', instructions].join('\n\n');
295
+ if (trimmed.length > params.maxChars) {
296
+ return trimmed.slice(0, params.maxChars);
297
+ }
298
+
299
+ for (const demo of demoLines) {
300
+ const candidate = `${trimmed}\n\nExamples:\n${demo}`;
301
+ if (candidate.length > params.maxChars) break;
302
+ trimmed = candidate;
303
+ }
304
+
305
+ return trimmed;
306
+ }
307
+
308
+ export function formatMemoryRecallPack(params: {
309
+ pack: PromptPack;
310
+ maxDemos: number;
311
+ maxChars: number;
312
+ }): string {
313
+ const instructions = params.pack.instructions.trim();
314
+ const demos = params.pack.demos.slice(0, params.maxDemos);
315
+
316
+ const demoLines = demos.map((demo) => {
317
+ const output = demo.output === null ? 'null' : JSON.stringify(demo.output);
318
+ return `Input: ${demo.input}\nOutput: ${output}`;
319
+ });
320
+
321
+ const block = [
322
+ 'Memory Recall Guidelines (Autotune):',
323
+ instructions,
324
+ demoLines.length > 0 ? `Examples:\n${demoLines.join('\n\n')}` : ''
325
+ ].filter(Boolean).join('\n\n');
326
+
327
+ if (block.length <= params.maxChars) return block;
328
+
329
+ let trimmed = ['Memory Recall Guidelines (Autotune):', instructions].join('\n\n');
330
+ if (trimmed.length > params.maxChars) {
331
+ return trimmed.slice(0, params.maxChars);
332
+ }
333
+
334
+ for (const demo of demoLines) {
335
+ const candidate = `${trimmed}\n\nExamples:\n${demo}`;
336
+ if (candidate.length > params.maxChars) break;
337
+ trimmed = candidate;
338
+ }
339
+
340
+ return trimmed;
341
+ }