create-walle 0.9.11 → 0.9.13

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 (167) hide show
  1. package/README.md +3 -3
  2. package/package.json +2 -2
  3. package/template/bin/dev.sh +7 -1
  4. package/template/bin/setup.js +53 -9
  5. package/template/bin/sync-images.js +53 -0
  6. package/template/builder-journal.md +17 -0
  7. package/template/claude-task-manager/api-prompts.js +98 -13
  8. package/template/claude-task-manager/api-reviews.js +82 -5
  9. package/template/claude-task-manager/db.js +32 -5
  10. package/template/claude-task-manager/docs/session-capture-foundation-design.md +1273 -0
  11. package/template/claude-task-manager/lib/claude-desktop-sessions.js +696 -0
  12. package/template/claude-task-manager/lib/coding-agent-models.js +49 -1
  13. package/template/claude-task-manager/lib/session-capture.js +421 -0
  14. package/template/claude-task-manager/lib/session-history.js +135 -15
  15. package/template/claude-task-manager/lib/session-jobs.js +10 -5
  16. package/template/claude-task-manager/lib/session-stream.js +87 -19
  17. package/template/claude-task-manager/lib/setup-provider-config.js +115 -0
  18. package/template/claude-task-manager/lib/walle-ctm-history.js +72 -0
  19. package/template/claude-task-manager/lib/walle-session-context.js +61 -0
  20. package/template/claude-task-manager/lib/walle-transcript.js +176 -0
  21. package/template/claude-task-manager/public/css/setup.css +35 -8
  22. package/template/claude-task-manager/public/css/walle-session.css +56 -0
  23. package/template/claude-task-manager/public/css/walle.css +120 -0
  24. package/template/claude-task-manager/public/index.html +814 -181
  25. package/template/claude-task-manager/public/js/message-renderer.js +148 -19
  26. package/template/claude-task-manager/public/js/reviews.js +120 -62
  27. package/template/claude-task-manager/public/js/setup.js +75 -31
  28. package/template/claude-task-manager/public/js/stream-view.js +115 -55
  29. package/template/claude-task-manager/public/js/walle-session.js +84 -2
  30. package/template/claude-task-manager/public/js/walle.js +308 -54
  31. package/template/claude-task-manager/server.js +1092 -146
  32. package/template/claude-task-manager/session-integrity.js +181 -54
  33. package/template/claude-task-manager/session-utils.js +123 -41
  34. package/template/claude-task-manager/workers/state-detectors/codex.js +5 -2
  35. package/template/package.json +1 -1
  36. package/template/wall-e/adapters/ctm.js +39 -18
  37. package/template/wall-e/agent-runners/contract.js +17 -0
  38. package/template/wall-e/agent-runners/index.js +22 -0
  39. package/template/wall-e/agent-runtime/harness.js +212 -0
  40. package/template/wall-e/agent-runtime/index.js +8 -0
  41. package/template/wall-e/agent-runtime/registry.js +67 -0
  42. package/template/wall-e/agent-runtime/session-store.js +179 -0
  43. package/template/wall-e/agent-runtime/spawn.js +208 -0
  44. package/template/wall-e/api-walle.js +174 -7
  45. package/template/wall-e/brain.js +266 -28
  46. package/template/wall-e/channels/policy.js +88 -0
  47. package/template/wall-e/channels/registry.js +15 -1
  48. package/template/wall-e/channels/reply-dispatcher.js +70 -0
  49. package/template/wall-e/channels/session-bindings.js +51 -0
  50. package/template/wall-e/chat/code-review-context.js +29 -0
  51. package/template/wall-e/chat.js +188 -42
  52. package/template/wall-e/coding/acp-adapter.js +188 -0
  53. package/template/wall-e/coding/agent-catalog.js +129 -0
  54. package/template/wall-e/coding/compaction-service.js +247 -0
  55. package/template/wall-e/coding/execution-trace.js +3 -0
  56. package/template/wall-e/coding/instruction-service.js +224 -0
  57. package/template/wall-e/coding/model-message.js +67 -0
  58. package/template/wall-e/coding/permission-rules-store.js +111 -0
  59. package/template/wall-e/coding/permission-service.js +266 -0
  60. package/template/wall-e/coding/prompt-bundle.js +67 -0
  61. package/template/wall-e/coding/prompt-runtime.js +243 -0
  62. package/template/wall-e/coding/provider-transform.js +188 -0
  63. package/template/wall-e/coding/runtime-mode.js +132 -0
  64. package/template/wall-e/coding/snapshot-service.js +155 -0
  65. package/template/wall-e/coding/stream-processor.js +268 -0
  66. package/template/wall-e/coding/task-tool.js +255 -0
  67. package/template/wall-e/coding/tool-registry.js +361 -0
  68. package/template/wall-e/coding/transcript-writer.js +143 -0
  69. package/template/wall-e/coding/workspace-replay.js +324 -0
  70. package/template/wall-e/coding-context.js +4 -22
  71. package/template/wall-e/coding-orchestrator.js +307 -18
  72. package/template/wall-e/coding-prompts.js +44 -3
  73. package/template/wall-e/context/context-builder.js +43 -1
  74. package/template/wall-e/context/topic-matcher.js +1 -1
  75. package/template/wall-e/eval/agent-runner.js +59 -13
  76. package/template/wall-e/eval/benchmarks/memory-retrieval.json +155 -57
  77. package/template/wall-e/eval/benchmarks.js +100 -16
  78. package/template/wall-e/eval/eval-orchestrator.js +218 -8
  79. package/template/wall-e/eval/harvester.js +62 -5
  80. package/template/wall-e/eval/head-to-head.js +23 -2
  81. package/template/wall-e/eval/humaneval-adapter.js +30 -5
  82. package/template/wall-e/eval/livecodebench-adapter.js +29 -5
  83. package/template/wall-e/eval/manifest.js +186 -0
  84. package/template/wall-e/eval/run-agent-benchmarks.js +66 -2
  85. package/template/wall-e/eval/session-retrieval-benchmark.js +150 -0
  86. package/template/wall-e/eval/session-transcripts.js +57 -4
  87. package/template/wall-e/eval/swebench-adapter.js +109 -3
  88. package/template/wall-e/evaluation/agent-router.js +53 -1
  89. package/template/wall-e/evaluation/coding-quorum.js +48 -1
  90. package/template/wall-e/evaluation/router.js +4 -2
  91. package/template/wall-e/evaluation/tier-selector.js +11 -1
  92. package/template/wall-e/extraction/contradiction.js +2 -2
  93. package/template/wall-e/extraction/indexer.js +2 -1
  94. package/template/wall-e/extraction/knowledge-extractor.js +2 -2
  95. package/template/wall-e/hooks/cli.js +92 -0
  96. package/template/wall-e/hooks/discovery.js +119 -0
  97. package/template/wall-e/hooks/index.js +7 -0
  98. package/template/wall-e/hooks/manifest.js +55 -0
  99. package/template/wall-e/hooks/runtime.js +84 -0
  100. package/template/wall-e/hooks/session-memory.js +225 -0
  101. package/template/wall-e/http/auth.js +6 -2
  102. package/template/wall-e/http/chat-api.js +54 -8
  103. package/template/wall-e/integrations/claude-plugin/hooks/hooks.json +27 -0
  104. package/template/wall-e/integrations/claude-plugin/hooks/walle-precompact-hook.sh +5 -0
  105. package/template/wall-e/integrations/claude-plugin/hooks/walle-stop-hook.sh +5 -0
  106. package/template/wall-e/integrations/codex-plugin/hooks/walle-hook.sh +7 -0
  107. package/template/wall-e/integrations/codex-plugin/hooks.json +37 -0
  108. package/template/wall-e/listening/calendar.js +3 -1
  109. package/template/wall-e/llm/client.js +64 -10
  110. package/template/wall-e/llm/google.js +39 -5
  111. package/template/wall-e/llm/ollama.js +1 -1
  112. package/template/wall-e/llm/ollama.plugin.json +1 -1
  113. package/template/wall-e/llm/provider-availability.js +10 -0
  114. package/template/wall-e/llm/provider-error.js +269 -0
  115. package/template/wall-e/llm/tool-adapter.js +48 -12
  116. package/template/wall-e/loops/boot.js +2 -1
  117. package/template/wall-e/loops/initiative.js +2 -2
  118. package/template/wall-e/loops/tasks.js +8 -47
  119. package/template/wall-e/loops/workspace-prompts.js +20 -0
  120. package/template/wall-e/mcp-server.js +442 -1
  121. package/template/wall-e/memory/session-ingest-service.js +159 -0
  122. package/template/wall-e/memory/source-indexer.js +289 -0
  123. package/template/wall-e/plugins/discovery.js +83 -0
  124. package/template/wall-e/plugins/manifest-loader.js +50 -10
  125. package/template/wall-e/plugins/manifest-schema.js +69 -0
  126. package/template/wall-e/plugins/model-catalog.js +55 -0
  127. package/template/wall-e/prompts/coding/base.txt +2 -0
  128. package/template/wall-e/prompts/coding/deepseek.txt +1 -0
  129. package/template/wall-e/prompts/coding/memory-protocol.md +9 -0
  130. package/template/wall-e/prompts/coding/plan.txt +1 -0
  131. package/template/wall-e/runtime/execution-trace.js +220 -0
  132. package/template/wall-e/security/audit.js +266 -0
  133. package/template/wall-e/security/ssrf.js +236 -0
  134. package/template/wall-e/session-files.js +303 -0
  135. package/template/wall-e/skills/_bundled/slack-backfill/SKILL.md +3 -0
  136. package/template/wall-e/skills/_bundled/slack-sync/SKILL.md +3 -0
  137. package/template/wall-e/skills/internal-skill-registry.js +2 -2
  138. package/template/wall-e/skills/script-skill-runner.js +143 -0
  139. package/template/wall-e/skills/skill-executor.js +5 -6
  140. package/template/wall-e/skills/skill-fallback.js +3 -1
  141. package/template/wall-e/skills/skill-harness-registry.js +7 -8
  142. package/template/wall-e/skills/skill-planner.js +52 -4
  143. package/template/wall-e/skills/slack-ingest.js +11 -3
  144. package/template/wall-e/sources/base.js +90 -0
  145. package/template/wall-e/sources/builtin.js +33 -0
  146. package/template/wall-e/sources/claude-code-jsonl.js +78 -0
  147. package/template/wall-e/sources/codex-jsonl.js +125 -0
  148. package/template/wall-e/sources/coding-session-utils.js +117 -0
  149. package/template/wall-e/sources/contract-suite.js +59 -0
  150. package/template/wall-e/sources/gemini-jsonl.js +85 -0
  151. package/template/wall-e/sources/index.js +9 -0
  152. package/template/wall-e/sources/jsonl-utils.js +181 -0
  153. package/template/wall-e/sources/record-types.js +252 -0
  154. package/template/wall-e/sources/registry.js +92 -0
  155. package/template/wall-e/sources/transforms.js +100 -0
  156. package/template/wall-e/sources/walle-jsonl.js +108 -0
  157. package/template/wall-e/tools/coding-middleware.js +31 -1
  158. package/template/wall-e/tools/file-tracker.js +25 -1
  159. package/template/wall-e/tools/local-tools.js +75 -47
  160. package/template/wall-e/tools/session-sharing.js +68 -1
  161. package/template/wall-e/tools/shell-analyzer.js +1 -1
  162. package/template/wall-e/tools/shell-policy.js +47 -0
  163. package/template/wall-e/tools/snapshot.js +42 -0
  164. package/template/wall-e/training/harvester.js +62 -5
  165. package/template/wall-e/utils/repair.js +253 -1
  166. package/template/website/index.html +3 -3
  167. package/template/wall-e/skills/_bundled/slack-mentions/.watched-threads.json +0 -18
@@ -0,0 +1,361 @@
1
+ 'use strict';
2
+
3
+ class ToolRegistry {
4
+ constructor({
5
+ builtinTools = [],
6
+ middleware = null,
7
+ localTools = null,
8
+ mcpClient = null,
9
+ skillRunner = null,
10
+ agentCatalog = null,
11
+ taskTool = null,
12
+ taskRunner = null,
13
+ agentRuntime = null,
14
+ brain = null,
15
+ transcript = null,
16
+ projectRoot = process.cwd(),
17
+ enableTaskTool = false,
18
+ specialHandlers = {},
19
+ } = {}) {
20
+ this.middleware = middleware || null;
21
+ this.localTools = localTools || null;
22
+ this.mcpClient = mcpClient || null;
23
+ this.skillRunner = skillRunner || null;
24
+ this.taskTool = taskTool || null;
25
+ this.bridgeToolTargets = new Map();
26
+ if (!this.taskTool && enableTaskTool) {
27
+ const { AgentCatalog } = require('./agent-catalog');
28
+ const { TaskTool } = require('./task-tool');
29
+ this.taskTool = new TaskTool({
30
+ agentCatalog: agentCatalog || new AgentCatalog({ projectRoot }),
31
+ runner: taskRunner,
32
+ agentRuntime,
33
+ brain,
34
+ transcript,
35
+ });
36
+ }
37
+ this.specialHandlers = { ...specialHandlers };
38
+ this.tools = new Map();
39
+ for (const tool of builtinTools || []) {
40
+ this.register(tool.name, tool);
41
+ }
42
+ }
43
+
44
+ register(name, definition = {}) {
45
+ if (!name) throw new Error('tool name is required');
46
+ const normalized = normalizeDefinition({ name, ...definition });
47
+ this.tools.set(name, normalized);
48
+ return normalized;
49
+ }
50
+
51
+ async getDefinitions(ctx = {}) {
52
+ const merged = new Map();
53
+ for (const [name, def] of this.tools) merged.set(name, normalizeDefinition(def));
54
+ if (this.middleware?.getRegisteredTools) {
55
+ for (const [name, def] of Object.entries(this.middleware.getRegisteredTools())) {
56
+ merged.set(name, normalizeDefinition({ name, ...def }));
57
+ }
58
+ }
59
+ for (const bridge of await this._bridgeDefinitions(ctx)) {
60
+ if (!merged.has(bridge.name)) merged.set(bridge.name, bridge);
61
+ }
62
+
63
+ let definitions = [...merged.values()].map(publicDefinition);
64
+ if (this.middleware?.run) {
65
+ definitions = await this.middleware.run('tool.definitions', ctx, definitions);
66
+ }
67
+ return definitions;
68
+ }
69
+
70
+ async execute(name, args = {}, ctx = {}) {
71
+ if (this.specialHandlers[name]) {
72
+ return this.specialHandlers[name](args, ctx);
73
+ }
74
+
75
+ const middlewareTool = this.middleware?.getRegisteredTools?.()[name];
76
+ if (middlewareTool) {
77
+ if (typeof middlewareTool.execute !== 'function') {
78
+ return invalidTool(name, 'Registered tool has no execute function');
79
+ }
80
+ return middlewareTool.execute(args, ctx);
81
+ }
82
+
83
+ const registered = this.tools.get(name);
84
+ if (registered?.execute) {
85
+ return registered.execute(args, ctx);
86
+ }
87
+
88
+ if (name === 'mcp_call' && this.mcpClient?.callTool) {
89
+ return this._callMcpTool(args.server || '', args.tool, args.arguments || {}, ctx);
90
+ }
91
+ const bridgeTarget = this.bridgeToolTargets.get(name);
92
+ if (bridgeTarget?.type === 'mcp' && this.mcpClient?.callTool) {
93
+ return this._callMcpTool(bridgeTarget.server, bridgeTarget.tool, args, ctx);
94
+ }
95
+ if (bridgeTarget?.type === 'skill') {
96
+ return this._runSkill(bridgeTarget.name, args, ctx);
97
+ }
98
+ if (name === 'skill' && this.skillRunner) {
99
+ return this._runSkill(args.name, args.arguments || {}, ctx);
100
+ }
101
+ if (name === 'task' && this.taskTool) {
102
+ return this.taskTool.execute(args, ctx);
103
+ }
104
+
105
+ const local = this.localTools || safeLocalTools();
106
+ if (local?.executeLocalTool) {
107
+ const result = await local.executeLocalTool(name, args);
108
+ if (result !== null && result !== undefined) return result;
109
+ }
110
+ return invalidTool(name, `Unknown tool: ${name}`);
111
+ }
112
+
113
+ async _bridgeDefinitions() {
114
+ this.bridgeToolTargets.clear();
115
+ const definitions = [];
116
+ if (this.mcpClient) {
117
+ definitions.push(normalizeDefinition({
118
+ name: 'mcp_call',
119
+ description: 'Call an MCP tool by server and tool name.',
120
+ input_schema: {
121
+ type: 'object',
122
+ properties: {
123
+ server: { type: 'string' },
124
+ tool: { type: 'string' },
125
+ arguments: { type: 'object' },
126
+ },
127
+ required: ['server', 'tool'],
128
+ },
129
+ }));
130
+ const tools = await this._listMcpTools();
131
+ for (const tool of tools) {
132
+ const publicName = uniqueBridgeName('mcp', tool.server, tool.name, definitions, this.bridgeToolTargets);
133
+ this.bridgeToolTargets.set(publicName, {
134
+ type: 'mcp',
135
+ server: tool.server || '',
136
+ tool: tool.name,
137
+ });
138
+ definitions.push(normalizeDefinition({
139
+ name: publicName,
140
+ description: bridgeDescription('MCP', tool.server, tool.name, tool.description),
141
+ input_schema: tool.input_schema,
142
+ }));
143
+ }
144
+ }
145
+ if (this.skillRunner) {
146
+ definitions.push(normalizeDefinition({
147
+ name: 'skill',
148
+ description: 'Run a Wall-E skill by name with JSON arguments.',
149
+ input_schema: {
150
+ type: 'object',
151
+ properties: {
152
+ name: { type: 'string' },
153
+ arguments: { type: 'object' },
154
+ },
155
+ required: ['name'],
156
+ },
157
+ }));
158
+ const skills = await this._listSkills();
159
+ for (const skill of skills) {
160
+ const publicName = uniqueBridgeName('skill', '', skill.name, definitions, this.bridgeToolTargets);
161
+ this.bridgeToolTargets.set(publicName, {
162
+ type: 'skill',
163
+ name: skill.name,
164
+ });
165
+ definitions.push(normalizeDefinition({
166
+ name: publicName,
167
+ description: bridgeDescription('Skill', '', skill.name, skill.description),
168
+ input_schema: skill.input_schema,
169
+ }));
170
+ }
171
+ }
172
+ if (this.taskTool) {
173
+ definitions.push(normalizeDefinition(this.taskTool.definition()));
174
+ }
175
+ return definitions;
176
+ }
177
+
178
+ async _listMcpTools() {
179
+ const client = this.mcpClient;
180
+ if (!client) return [];
181
+ try {
182
+ if (typeof client.listTools === 'function') {
183
+ return normalizeMcpToolList(await client.listTools());
184
+ }
185
+ if (typeof client.getTools === 'function') {
186
+ return normalizeMcpToolList(await client.getTools());
187
+ }
188
+ } catch {}
189
+ return [];
190
+ }
191
+
192
+ async _listSkills() {
193
+ const runner = this.skillRunner;
194
+ if (!runner) return [];
195
+ try {
196
+ const raw = typeof runner.listSkills === 'function'
197
+ ? await runner.listSkills()
198
+ : typeof runner.getSkills === 'function'
199
+ ? await runner.getSkills()
200
+ : Array.isArray(runner.skills)
201
+ ? runner.skills
202
+ : [];
203
+ return normalizeSkillList(raw);
204
+ } catch {}
205
+ return [];
206
+ }
207
+
208
+ _callMcpTool(server, tool, args, ctx) {
209
+ if (!this.mcpClient?.callTool) return invalidTool(tool, 'MCP client has no callTool function');
210
+ if (server) return this.mcpClient.callTool(server, tool, args || {}, ctx);
211
+ return this.mcpClient.callTool(tool, args || {}, ctx);
212
+ }
213
+
214
+ _runSkill(name, args, ctx) {
215
+ if (!this.skillRunner) return invalidTool(name, 'Skill runner is not configured');
216
+ if (typeof this.skillRunner === 'function') {
217
+ return this.skillRunner({ name, arguments: args || {} }, ctx);
218
+ }
219
+ if (typeof this.skillRunner.run === 'function') {
220
+ return this.skillRunner.run(name, args || {}, ctx);
221
+ }
222
+ if (typeof this.skillRunner.execute === 'function') {
223
+ return this.skillRunner.execute({ name, arguments: args || {} }, ctx);
224
+ }
225
+ return invalidTool(name, 'Skill runner has no execute function');
226
+ }
227
+ }
228
+
229
+ function normalizeDefinition(def = {}) {
230
+ const inputSchema = def.input_schema || def.parameters || {
231
+ type: 'object',
232
+ properties: {},
233
+ };
234
+ return {
235
+ ...def,
236
+ name: def.name,
237
+ description: def.description || '',
238
+ input_schema: inputSchema,
239
+ };
240
+ }
241
+
242
+ function publicDefinition(def = {}) {
243
+ return {
244
+ name: def.name,
245
+ description: def.description || '',
246
+ input_schema: def.input_schema || def.parameters || { type: 'object', properties: {} },
247
+ };
248
+ }
249
+
250
+ function invalidTool(name, message) {
251
+ return {
252
+ error: message,
253
+ invalid: true,
254
+ tool: name,
255
+ };
256
+ }
257
+
258
+ function normalizeMcpToolList(raw) {
259
+ const out = [];
260
+ for (const item of flattenToolList(raw)) {
261
+ const name = item.tool || item.name;
262
+ if (!name) continue;
263
+ out.push({
264
+ server: item.server || item.serverName || '',
265
+ name,
266
+ description: item.description || '',
267
+ input_schema: schemaFrom(item),
268
+ });
269
+ }
270
+ return out;
271
+ }
272
+
273
+ function normalizeSkillList(raw) {
274
+ return flattenToolList(raw).map((item) => ({
275
+ name: item.name,
276
+ description: item.description || '',
277
+ input_schema: schemaFrom(item),
278
+ })).filter((item) => item.name);
279
+ }
280
+
281
+ function flattenToolList(raw, inheritedServer = '') {
282
+ if (!raw) return [];
283
+ if (Array.isArray(raw)) {
284
+ return raw.flatMap((item) => flattenToolList(item, inheritedServer));
285
+ }
286
+ if (raw.tools && Array.isArray(raw.tools)) {
287
+ const server = raw.server || raw.serverName || raw.name || inheritedServer;
288
+ return raw.tools.flatMap((tool) => flattenToolList({ ...tool, server: tool.server || server }, server));
289
+ }
290
+ if (raw.result?.tools) return flattenToolList(raw.result.tools, inheritedServer);
291
+ if (raw.servers && typeof raw.servers === 'object') return flattenToolList(raw.servers, inheritedServer);
292
+ if (typeof raw === 'object' && !raw.name && !raw.tool && !raw.inputSchema && !raw.input_schema && !raw.parameters) {
293
+ const rows = [];
294
+ for (const [server, value] of Object.entries(raw)) {
295
+ rows.push(...flattenToolList(value, server));
296
+ }
297
+ return rows;
298
+ }
299
+ return [{ ...raw, server: raw.server || inheritedServer }];
300
+ }
301
+
302
+ function schemaFrom(item = {}) {
303
+ return item.input_schema || item.inputSchema || item.parameters || {
304
+ type: 'object',
305
+ properties: {},
306
+ };
307
+ }
308
+
309
+ function bridgeDescription(kind, server, name, description) {
310
+ const prefix = server ? `${kind} ${server}.${name}` : `${kind} ${name}`;
311
+ return description ? `${prefix}: ${description}` : prefix;
312
+ }
313
+
314
+ function uniqueBridgeName(prefix, server, name, definitions, targets) {
315
+ const base = compactToolName(`${prefix}${server ? `__${server}` : ''}__${name}`);
316
+ const used = new Set([
317
+ ...definitions.map((definition) => definition.name),
318
+ ...targets.keys(),
319
+ ]);
320
+ if (!used.has(base)) return base;
321
+ const hash = shortHash(`${prefix}:${server}:${name}`);
322
+ return compactToolName(`${base}__${hash}`);
323
+ }
324
+
325
+ function compactToolName(value) {
326
+ const cleaned = String(value || '')
327
+ .replace(/[^A-Za-z0-9_]+/g, '_')
328
+ .replace(/^_+|_+$/g, '')
329
+ .replace(/_{3,}/g, '__')
330
+ || 'tool';
331
+ if (cleaned.length <= 64) return cleaned;
332
+ const hash = shortHash(cleaned);
333
+ return `${cleaned.slice(0, 55)}_${hash}`;
334
+ }
335
+
336
+ function shortHash(value) {
337
+ let hash = 5381;
338
+ const text = String(value || '');
339
+ for (let i = 0; i < text.length; i++) {
340
+ hash = ((hash << 5) + hash) ^ text.charCodeAt(i);
341
+ }
342
+ return (hash >>> 0).toString(36).slice(0, 8);
343
+ }
344
+
345
+ function safeLocalTools() {
346
+ try {
347
+ return require('../tools/local-tools');
348
+ } catch {
349
+ return null;
350
+ }
351
+ }
352
+
353
+ module.exports = {
354
+ ToolRegistry,
355
+ normalizeDefinition,
356
+ publicDefinition,
357
+ invalidTool,
358
+ normalizeMcpToolList,
359
+ normalizeSkillList,
360
+ compactToolName,
361
+ };
@@ -0,0 +1,143 @@
1
+ 'use strict';
2
+
3
+ const crypto = require('node:crypto');
4
+ const os = require('node:os');
5
+ const { WorkspaceReplay } = require('./workspace-replay');
6
+
7
+ const VERSION = 'walle-jsonl-v1';
8
+
9
+ class CodingTranscript {
10
+ constructor({
11
+ sessionId,
12
+ replay = null,
13
+ cwd = '',
14
+ chatSessionId = '',
15
+ label = '',
16
+ modelId = '',
17
+ modelProvider = '',
18
+ runtimeMode = '',
19
+ agent = '',
20
+ mode = '',
21
+ now = () => new Date().toISOString(),
22
+ } = {}) {
23
+ if (!sessionId) throw new Error('sessionId is required');
24
+ this.sessionId = sessionId;
25
+ this.replay = replay || new WorkspaceReplay({ now });
26
+ this.defaults = { cwd, chatSessionId, label, modelId, modelProvider, runtimeMode, agent, mode };
27
+ this.now = now;
28
+ this._sessions = new Set();
29
+ }
30
+
31
+ ensureSession(opts = {}) {
32
+ const sessionId = opts.sessionId || this.sessionId;
33
+ if (this._sessions.has(sessionId)) return null;
34
+ this._sessions.add(sessionId);
35
+ return this.replay.appendRecord(sessionId, {
36
+ type: 'session_meta',
37
+ provider: 'walle',
38
+ version: VERSION,
39
+ sessionId,
40
+ chatSessionId: opts.chatSessionId || this.defaults.chatSessionId || '',
41
+ cwd: opts.cwd || this.defaults.cwd || '',
42
+ label: opts.label || this.defaults.label || '',
43
+ modelId: opts.modelId || this.defaults.modelId || '',
44
+ modelProvider: opts.modelProvider || this.defaults.modelProvider || '',
45
+ runtimeMode: opts.runtimeMode || this.defaults.runtimeMode || '',
46
+ agent: opts.agent || this.defaults.agent || '',
47
+ mode: opts.mode || this.defaults.mode || '',
48
+ hostname: os.hostname(),
49
+ uuid: newUuid(),
50
+ timestamp: opts.timestamp || this.now(),
51
+ });
52
+ }
53
+
54
+ append(record = {}) {
55
+ const sessionId = record.sessionId || this.sessionId;
56
+ this.ensureSession({ sessionId, cwd: record.cwd || this.defaults.cwd });
57
+ return this.replay.appendRecord(sessionId, normalizeRecord({
58
+ sessionId,
59
+ cwd: this.defaults.cwd,
60
+ timestamp: this.now(),
61
+ ...record,
62
+ }));
63
+ }
64
+
65
+ appendPart(arg, partType, data, opts = {}) {
66
+ if (arguments.length === 1 && arg && typeof arg === 'object') {
67
+ const record = arg;
68
+ const sessionId = record.sessionId || this.sessionId;
69
+ this.ensureSession({ sessionId, cwd: record.cwd || this.defaults.cwd });
70
+ return this.append({
71
+ type: 'walle_part',
72
+ ...record,
73
+ sessionId,
74
+ cwd: record.cwd || this.defaults.cwd,
75
+ chatSessionId: record.chatSessionId || this.defaults.chatSessionId,
76
+ partType: record.partType || 'event',
77
+ data: record.data || {},
78
+ });
79
+ }
80
+ const sessionId = arg || this.sessionId;
81
+ this.ensureSession({ sessionId, cwd: opts.cwd || this.defaults.cwd });
82
+ return this.replay.appendPart(sessionId, partType || 'event', data || {}, {
83
+ cwd: opts.cwd || this.defaults.cwd,
84
+ chatSessionId: opts.chatSessionId || this.defaults.chatSessionId,
85
+ parentUuid: opts.parentUuid || null,
86
+ });
87
+ }
88
+
89
+ appendUserMessage(text, opts = {}) {
90
+ return this.append(messageRecord('user', text, opts, this));
91
+ }
92
+
93
+ appendAssistantMessage(text, opts = {}) {
94
+ const record = messageRecord('assistant', text, opts, this);
95
+ record.modelId = opts.model || opts.modelId || this.defaults.modelId || '';
96
+ record.modelProvider = opts.provider || opts.modelProvider || this.defaults.modelProvider || '';
97
+ record.tokens = opts.tokens || {};
98
+ record.cost = Number.isFinite(opts.cost) ? opts.cost : null;
99
+ return this.append(record);
100
+ }
101
+ }
102
+
103
+ function createCodingTranscript(opts = {}) {
104
+ if (opts.transcript) return opts.transcript;
105
+ if (opts.persistTranscript === false) return null;
106
+ return new CodingTranscript(opts);
107
+ }
108
+
109
+ function normalizeRecord(record = {}) {
110
+ return {
111
+ provider: 'walle',
112
+ version: VERSION,
113
+ uuid: record.uuid || newUuid(),
114
+ timestamp: record.timestamp || new Date().toISOString(),
115
+ ...record,
116
+ };
117
+ }
118
+
119
+ function messageRecord(role, text, opts = {}, transcript) {
120
+ const sessionId = opts.sessionId || transcript.sessionId;
121
+ return normalizeRecord({
122
+ type: role,
123
+ sessionId,
124
+ chatSessionId: opts.chatSessionId || transcript.defaults.chatSessionId || '',
125
+ parentUuid: opts.parentUuid || null,
126
+ cwd: opts.cwd || transcript.defaults.cwd || '',
127
+ message: {
128
+ role,
129
+ content: [{ type: 'text', text: String(text || '') }],
130
+ },
131
+ });
132
+ }
133
+
134
+ function newUuid() {
135
+ return crypto.randomUUID ? crypto.randomUUID() : crypto.randomBytes(16).toString('hex');
136
+ }
137
+
138
+ module.exports = {
139
+ VERSION,
140
+ CodingTranscript,
141
+ createCodingTranscript,
142
+ normalizeRecord,
143
+ };