create-walle 0.9.25 → 0.9.26

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 (179) hide show
  1. package/README.md +8 -0
  2. package/bin/create-walle.js +815 -45
  3. package/package.json +2 -2
  4. package/template/bin/ctm-dev-cleanup.js +90 -4
  5. package/template/bin/ctm-launch.sh +49 -1
  6. package/template/bin/dev.sh +45 -1
  7. package/template/bin/ensure-stable-node.js +132 -0
  8. package/template/bin/install-service.sh +9 -0
  9. package/template/claude-task-manager/api-prompts.js +899 -119
  10. package/template/claude-task-manager/approval-agent.js +360 -40
  11. package/template/claude-task-manager/bin/ctm-disclaim.c +42 -0
  12. package/template/claude-task-manager/bin/ctm-hotkey.swift +67 -81
  13. package/template/claude-task-manager/bin/ctm-screen-auth.swift +37 -0
  14. package/template/claude-task-manager/bin/install-hotkey.sh +97 -49
  15. package/template/claude-task-manager/bin/restart-ctm.sh +14 -0
  16. package/template/claude-task-manager/db.js +399 -48
  17. package/template/claude-task-manager/docs/approval-hook-sandbox.md +84 -0
  18. package/template/claude-task-manager/docs/codex-app-server-approvals.md +72 -0
  19. package/template/claude-task-manager/docs/codex-native-sandbox.md +47 -0
  20. package/template/claude-task-manager/docs/prompt-editing-tree-design.md +18 -1
  21. package/template/claude-task-manager/lib/approval-hook.js +200 -0
  22. package/template/claude-task-manager/lib/approval-self-adapt.js +1 -0
  23. package/template/claude-task-manager/lib/auth-rules.js +11 -0
  24. package/template/claude-task-manager/lib/background-llm.js +32 -4
  25. package/template/claude-task-manager/lib/codesign-identity.js +140 -0
  26. package/template/claude-task-manager/lib/codex-app-server-client.js +119 -0
  27. package/template/claude-task-manager/lib/codex-approval-bridge.js +118 -0
  28. package/template/claude-task-manager/lib/codex-history-terminal-renderer.js +571 -0
  29. package/template/claude-task-manager/lib/codex-paths.js +73 -0
  30. package/template/claude-task-manager/lib/codex-rollout-snapshot.js +164 -0
  31. package/template/claude-task-manager/lib/codex-rollout-tail.js +72 -0
  32. package/template/claude-task-manager/lib/codex-sandbox-args.js +47 -0
  33. package/template/claude-task-manager/lib/coding-agent-models.js +118 -71
  34. package/template/claude-task-manager/lib/command-targets.js +163 -0
  35. package/template/claude-task-manager/lib/conversation-tail-merge.js +61 -19
  36. package/template/claude-task-manager/lib/db-owner-worker-client.js +29 -1
  37. package/template/claude-task-manager/lib/escalation-review.js +80 -3
  38. package/template/claude-task-manager/lib/flow-control.js +52 -0
  39. package/template/claude-task-manager/lib/fs-watcher.js +24 -15
  40. package/template/claude-task-manager/lib/ingest-cooldown.js +68 -0
  41. package/template/claude-task-manager/lib/jsonl-conversation-parser.js +8 -4
  42. package/template/claude-task-manager/lib/launchd-recovery.js +92 -0
  43. package/template/claude-task-manager/lib/microsoft-dev-tunnel-setup.js +207 -52
  44. package/template/claude-task-manager/lib/mobile-push-store.js +7 -0
  45. package/template/claude-task-manager/lib/model-overview-brain-fallback.js +102 -1
  46. package/template/claude-task-manager/lib/model-overview-cache.js +1 -0
  47. package/template/claude-task-manager/lib/oauth-proxy-supervisor.js +2 -1
  48. package/template/claude-task-manager/lib/perf-tracker.js +29 -2
  49. package/template/claude-task-manager/lib/permission-match.js +146 -16
  50. package/template/claude-task-manager/lib/project-slug.js +33 -0
  51. package/template/claude-task-manager/lib/prompt-intent.js +51 -4
  52. package/template/claude-task-manager/lib/read-pool-client.js +48 -3
  53. package/template/claude-task-manager/lib/real-node.js +73 -0
  54. package/template/claude-task-manager/lib/runtime-work-registry.js +131 -14
  55. package/template/claude-task-manager/lib/session-content-backfill.js +24 -5
  56. package/template/claude-task-manager/lib/session-diagnostics-batch.js +87 -0
  57. package/template/claude-task-manager/lib/session-history.js +5 -7
  58. package/template/claude-task-manager/lib/session-host-manager.js +19 -0
  59. package/template/claude-task-manager/lib/session-jobs.js +6 -0
  60. package/template/claude-task-manager/lib/session-message-response-cache.js +89 -0
  61. package/template/claude-task-manager/lib/session-messages-page.js +211 -0
  62. package/template/claude-task-manager/lib/session-messages-projection.js +170 -0
  63. package/template/claude-task-manager/lib/session-standup.js +8 -0
  64. package/template/claude-task-manager/lib/session-timeline-summary.js +16 -2
  65. package/template/claude-task-manager/lib/session-token-usage.js +30 -8
  66. package/template/claude-task-manager/lib/session-workspace-binding.js +29 -15
  67. package/template/claude-task-manager/lib/storage-migration.js +2 -1
  68. package/template/claude-task-manager/lib/transcript-store.js +179 -12
  69. package/template/claude-task-manager/lib/walle-ctm-history.js +298 -11
  70. package/template/claude-task-manager/lib/walle-permission-reply.js +49 -0
  71. package/template/claude-task-manager/lib/walle-session-cache.js +22 -1
  72. package/template/claude-task-manager/lib/walle-supervisor.js +42 -3
  73. package/template/claude-task-manager/package.json +5 -2
  74. package/template/claude-task-manager/prompt-harvest.js +31 -11
  75. package/template/claude-task-manager/providers/claude-code.js +29 -1
  76. package/template/claude-task-manager/providers/codex.js +13 -1
  77. package/template/claude-task-manager/public/css/setup.css +11 -0
  78. package/template/claude-task-manager/public/css/walle-session.css +132 -4
  79. package/template/claude-task-manager/public/css/walle.css +89 -0
  80. package/template/claude-task-manager/public/icon-16.png +0 -0
  81. package/template/claude-task-manager/public/icon-32.png +0 -0
  82. package/template/claude-task-manager/public/icon-512.png +0 -0
  83. package/template/claude-task-manager/public/index.html +2483 -165
  84. package/template/claude-task-manager/public/js/activation-render-check.js +55 -0
  85. package/template/claude-task-manager/public/js/flow-control-policy.js +52 -0
  86. package/template/claude-task-manager/public/js/message-renderer.js +60 -1
  87. package/template/claude-task-manager/public/js/prompts.js +13 -1
  88. package/template/claude-task-manager/public/js/session-status-precedence.js +9 -3
  89. package/template/claude-task-manager/public/js/setup.js +54 -10
  90. package/template/claude-task-manager/public/js/stream-resize-policy.js +80 -0
  91. package/template/claude-task-manager/public/js/stream-view.js +78 -0
  92. package/template/claude-task-manager/public/js/terminal-reconciler.js +52 -2
  93. package/template/claude-task-manager/public/js/tool-state.js +155 -0
  94. package/template/claude-task-manager/public/js/walle-session.js +887 -326
  95. package/template/claude-task-manager/public/js/walle.js +306 -195
  96. package/template/claude-task-manager/public/m/app.css +1 -0
  97. package/template/claude-task-manager/public/m/app.js +33 -3
  98. package/template/claude-task-manager/queue-engine.js +45 -1
  99. package/template/claude-task-manager/server.js +3367 -540
  100. package/template/claude-task-manager/workers/approval-blocklist.js +130 -17
  101. package/template/claude-task-manager/workers/db-owner-worker.js +31 -1
  102. package/template/claude-task-manager/workers/read-pool-worker.js +92 -5
  103. package/template/claude-task-manager/workers/session-host-process.js +10 -0
  104. package/template/claude-task-manager/workers/state-detectors/codex.js +58 -7
  105. package/template/package.json +2 -3
  106. package/template/shared/icons/AppIcon-ctm.icns +0 -0
  107. package/template/shared/icons/AppIcon-walle.icns +0 -0
  108. package/template/wall-e/agent.js +139 -18
  109. package/template/wall-e/api-walle.js +201 -22
  110. package/template/wall-e/bin/train-gemma-e4b-tooluse.js +1981 -0
  111. package/template/wall-e/brain.js +1049 -39
  112. package/template/wall-e/chat.js +427 -86
  113. package/template/wall-e/coding/acceptance-contract.js +26 -1
  114. package/template/wall-e/coding/action-memory-policy.js +353 -0
  115. package/template/wall-e/coding/action-memory-store.js +814 -0
  116. package/template/wall-e/coding/initial-messages.js +197 -0
  117. package/template/wall-e/coding/no-progress-guard.js +327 -0
  118. package/template/wall-e/coding/permission-service.js +88 -22
  119. package/template/wall-e/coding/session-workspaces.js +81 -0
  120. package/template/wall-e/coding/shell-sandbox.js +124 -0
  121. package/template/wall-e/coding/stream-processor.js +63 -2
  122. package/template/wall-e/coding/tool-execution-controller.js +14 -1
  123. package/template/wall-e/coding/tool-registry.js +1 -1
  124. package/template/wall-e/coding/transcript-writer.js +3 -0
  125. package/template/wall-e/coding-orchestrator.js +636 -35
  126. package/template/wall-e/coding-prompts.js +51 -2
  127. package/template/wall-e/docs/model-routing-policy.md +59 -0
  128. package/template/wall-e/docs/walle-shell-sandbox.md +61 -0
  129. package/template/wall-e/extraction/knowledge-extractor.js +76 -23
  130. package/template/wall-e/http/chat-api.js +30 -12
  131. package/template/wall-e/http/model-admin.js +93 -1
  132. package/template/wall-e/lib/background-lanes.js +133 -0
  133. package/template/wall-e/lib/boot-profile.js +11 -0
  134. package/template/wall-e/lib/brain-owner-worker-client.js +324 -0
  135. package/template/wall-e/lib/brain-read-pool-client.js +311 -0
  136. package/template/wall-e/lib/diagnostics-flags.js +87 -0
  137. package/template/wall-e/lib/event-loop-monitor.js +74 -3
  138. package/template/wall-e/lib/mcp-integration.js +7 -1
  139. package/template/wall-e/lib/real-node.js +98 -0
  140. package/template/wall-e/lib/runtime-health.js +206 -0
  141. package/template/wall-e/lib/runtime-worker-pool.js +101 -0
  142. package/template/wall-e/lib/scheduler-worker-jobs.js +231 -0
  143. package/template/wall-e/lib/scheduler.js +446 -17
  144. package/template/wall-e/lib/service-health.js +61 -2
  145. package/template/wall-e/lib/service-readiness.js +258 -0
  146. package/template/wall-e/lib/usage.js +152 -0
  147. package/template/wall-e/lib/worker-thread-pool.js +389 -0
  148. package/template/wall-e/llm/client.js +81 -4
  149. package/template/wall-e/llm/default-fallback.js +54 -8
  150. package/template/wall-e/llm/mlx.js +536 -73
  151. package/template/wall-e/llm/mlx.plugin.json +1 -1
  152. package/template/wall-e/llm/ollama.js +342 -43
  153. package/template/wall-e/llm/provider-error.js +18 -1
  154. package/template/wall-e/llm/provider-health-state.js +176 -0
  155. package/template/wall-e/llm/routing-policy.js +796 -0
  156. package/template/wall-e/llm/supported-models.js +5 -0
  157. package/template/wall-e/loops/tasks.js +60 -14
  158. package/template/wall-e/loops/think.js +89 -24
  159. package/template/wall-e/mcp-server.js +192 -28
  160. package/template/wall-e/server.js +32 -7
  161. package/template/wall-e/skills/script-skill-runner.js +8 -1
  162. package/template/wall-e/skills/skill-planner.js +64 -1
  163. package/template/wall-e/tools/builtin-middleware.js +67 -2
  164. package/template/wall-e/tools/local-tools.js +116 -26
  165. package/template/wall-e/tools/permission-checker.js +52 -4
  166. package/template/wall-e/tools/permission-rules.js +36 -0
  167. package/template/wall-e/tools/shell-analyzer.js +46 -1
  168. package/template/wall-e/training/gemma-e4b-qlora.js +314 -0
  169. package/template/wall-e/training/real-trajectory-miner.js +2617 -0
  170. package/template/wall-e/training/replay-eval-analysis.js +151 -0
  171. package/template/wall-e/training/run-shell-command-selector.js +277 -0
  172. package/template/wall-e/training/tool-sft-dataset.js +312 -0
  173. package/template/wall-e/training/tool-sft-renderers.js +144 -0
  174. package/template/wall-e/training/tool-trace-harvester.js +1440 -0
  175. package/template/wall-e/training/trajectory-action-selector.js +364 -0
  176. package/template/wall-e/weather-runtime.js +232 -0
  177. package/template/wall-e/workers/brain-owner-worker.js +162 -0
  178. package/template/wall-e/workers/brain-read-worker.js +148 -0
  179. package/template/wall-e/workers/runtime-worker.js +145 -0
@@ -0,0 +1,151 @@
1
+ 'use strict';
2
+
3
+ function summarizeActionMemoryReplayEval(rows = [], {
4
+ maxBadCopies = 0,
5
+ maxRegressions = 0,
6
+ minNetPassDelta = 1,
7
+ allowSameRowCopies = false,
8
+ } = {}) {
9
+ const normalizedRows = Array.isArray(rows) ? rows : [];
10
+ const counters = {
11
+ total: normalizedRows.length,
12
+ baselinePass: 0,
13
+ finalPass: 0,
14
+ rescuedCount: 0,
15
+ regressionCount: 0,
16
+ acceptedSelectionCount: 0,
17
+ selectedExactCount: 0,
18
+ selectedTargetCount: 0,
19
+ badCopyCount: 0,
20
+ sameRowCopyCount: 0,
21
+ byLane: {},
22
+ byTool: {},
23
+ };
24
+
25
+ for (const row of normalizedRows) {
26
+ const baselinePass = Boolean(row.baselineScore?.pass);
27
+ const finalPass = Boolean(row.score?.pass);
28
+ const selection = row.actionMemorySelection || null;
29
+ const oracle = row.actionMemoryOracle || null;
30
+ const accepted = Boolean(selection?.accepted);
31
+ const selectedExact = Boolean(oracle?.selectedExact);
32
+ const selectedTarget = Boolean(oracle?.selectedTarget);
33
+ const sameRowCopy = Boolean(accepted && selection?.sourceRowId && row.id && selection.sourceRowId === row.id);
34
+ const badCopy = Boolean(accepted && oracle && !selectedTarget);
35
+ const rescued = Boolean(!baselinePass && finalPass);
36
+ const regression = Boolean(baselinePass && !finalPass);
37
+
38
+ if (baselinePass) counters.baselinePass += 1;
39
+ if (finalPass) counters.finalPass += 1;
40
+ if (rescued) counters.rescuedCount += 1;
41
+ if (regression) counters.regressionCount += 1;
42
+ if (accepted) counters.acceptedSelectionCount += 1;
43
+ if (selectedExact) counters.selectedExactCount += 1;
44
+ if (selectedTarget) counters.selectedTargetCount += 1;
45
+ if (badCopy) counters.badCopyCount += 1;
46
+ if (sameRowCopy) counters.sameRowCopyCount += 1;
47
+
48
+ incrementGroup(counters.byLane, row.lane || 'unknown', {
49
+ baselinePass,
50
+ finalPass,
51
+ rescued,
52
+ regression,
53
+ accepted,
54
+ badCopy,
55
+ sameRowCopy,
56
+ });
57
+ incrementGroup(counters.byTool, row.expected?.tool || 'unknown', {
58
+ baselinePass,
59
+ finalPass,
60
+ rescued,
61
+ regression,
62
+ accepted,
63
+ badCopy,
64
+ sameRowCopy,
65
+ });
66
+ }
67
+
68
+ counters.baselinePassRate = rate(counters.baselinePass, counters.total);
69
+ counters.finalPassRate = rate(counters.finalPass, counters.total);
70
+ counters.acceptedSelectionRate = rate(counters.acceptedSelectionCount, counters.total);
71
+ counters.selectedExactRate = rate(counters.selectedExactCount, counters.acceptedSelectionCount);
72
+ counters.selectedTargetRate = rate(counters.selectedTargetCount, counters.acceptedSelectionCount);
73
+ counters.badCopyRate = rate(counters.badCopyCount, counters.acceptedSelectionCount);
74
+ counters.sameRowCopyRate = rate(counters.sameRowCopyCount, counters.acceptedSelectionCount);
75
+ counters.netPassDelta = counters.finalPass - counters.baselinePass;
76
+ counters.promotionGate = buildPromotionGate(counters, {
77
+ maxBadCopies,
78
+ maxRegressions,
79
+ minNetPassDelta,
80
+ allowSameRowCopies,
81
+ });
82
+ return counters;
83
+ }
84
+
85
+ function incrementGroup(groups, key, values) {
86
+ if (!groups[key]) {
87
+ groups[key] = {
88
+ total: 0,
89
+ baselinePass: 0,
90
+ finalPass: 0,
91
+ rescued: 0,
92
+ regressions: 0,
93
+ acceptedSelections: 0,
94
+ badCopies: 0,
95
+ sameRowCopies: 0,
96
+ };
97
+ }
98
+ const group = groups[key];
99
+ group.total += 1;
100
+ if (values.baselinePass) group.baselinePass += 1;
101
+ if (values.finalPass) group.finalPass += 1;
102
+ if (values.rescued) group.rescued += 1;
103
+ if (values.regression) group.regressions += 1;
104
+ if (values.accepted) group.acceptedSelections += 1;
105
+ if (values.badCopy) group.badCopies += 1;
106
+ if (values.sameRowCopy) group.sameRowCopies += 1;
107
+ }
108
+
109
+ function buildPromotionGate(report, {
110
+ maxBadCopies = 0,
111
+ maxRegressions = 0,
112
+ minNetPassDelta = 1,
113
+ allowSameRowCopies = false,
114
+ } = {}) {
115
+ const checks = [
116
+ {
117
+ name: 'netPassDelta',
118
+ actual: report.netPassDelta,
119
+ minimum: minNetPassDelta,
120
+ ok: report.netPassDelta >= minNetPassDelta,
121
+ },
122
+ {
123
+ name: 'badCopyCount',
124
+ actual: report.badCopyCount,
125
+ maximum: maxBadCopies,
126
+ ok: report.badCopyCount <= maxBadCopies,
127
+ },
128
+ {
129
+ name: 'regressionCount',
130
+ actual: report.regressionCount,
131
+ maximum: maxRegressions,
132
+ ok: report.regressionCount <= maxRegressions,
133
+ },
134
+ {
135
+ name: 'sameRowCopyCount',
136
+ actual: report.sameRowCopyCount,
137
+ maximum: allowSameRowCopies ? null : 0,
138
+ ok: allowSameRowCopies || report.sameRowCopyCount === 0,
139
+ },
140
+ ];
141
+ const failed = checks.filter((check) => !check.ok);
142
+ return { ok: failed.length === 0, checks, failed };
143
+ }
144
+
145
+ function rate(numerator, denominator) {
146
+ return denominator ? Number((numerator / denominator).toFixed(4)) : 0;
147
+ }
148
+
149
+ module.exports = {
150
+ summarizeActionMemoryReplayEval,
151
+ };
@@ -0,0 +1,277 @@
1
+ 'use strict';
2
+
3
+ const COMMAND_JSON_RE = /"command"\s*:\s*"((?:\\.|[^"\\])*)"/g;
4
+
5
+ function buildRunShellCommandCandidates(example = {}, {
6
+ maxCandidates = 12,
7
+ actionMemoryStore = null,
8
+ memoryLimit = 50,
9
+ } = {}) {
10
+ const candidates = [];
11
+ const add = (command, source, reason = null, extra = {}) => {
12
+ const value = normalizeCommand(command);
13
+ if (!value) return;
14
+ if (candidates.some((candidate) => candidate.command === value)) return;
15
+ candidates.push({
16
+ id: `cmd_${candidates.length + 1}`,
17
+ command: value,
18
+ source,
19
+ reason,
20
+ ...extra,
21
+ });
22
+ };
23
+
24
+ for (const command of example.labels?.verification_commands || []) add(command, 'task_memory', 'trajectory_verification');
25
+
26
+ const userContent = (example.messages || [])
27
+ .filter((message) => message.role === 'user')
28
+ .map((message) => message.content || '')
29
+ .join('\n');
30
+ for (const command of parseRememberedCommands(userContent, 'remembered task commands')) add(command, 'prompt_task_memory', 'prompt_memory');
31
+ for (const command of parseRememberedCommands(userContent, 'remembered workflow commands')) add(command, 'prompt_workflow_memory', 'prompt_memory');
32
+ for (const command of extractJsonCommandStrings(userContent)) add(command, 'prompt_state', 'json_command');
33
+
34
+ for (const message of example.messages || []) {
35
+ if (message.role !== 'assistant' || !Array.isArray(message.tool_calls)) continue;
36
+ for (const call of message.tool_calls) {
37
+ const name = call.function?.name || call.name;
38
+ if (name !== 'run_shell') continue;
39
+ const args = parseToolArguments(call.function?.arguments || call.arguments || call.input || {});
40
+ add(args.command, 'history', 'assistant_tool_call');
41
+ }
42
+ }
43
+
44
+ for (const candidate of loadRunShellActionMemoryCandidates(example, { actionMemoryStore, limit: memoryLimit })) {
45
+ add(
46
+ candidate.input?.command || candidate.input?.cmd,
47
+ 'action_memory',
48
+ 'action_memory_candidate',
49
+ {
50
+ memoryEntryId: candidate.id,
51
+ score: candidate.score,
52
+ memoryReasons: candidate.reasons || [],
53
+ sourceRowId: candidate.sourceRowId,
54
+ sourceSessionId: candidate.sourceSessionId,
55
+ sourceToolCallId: candidate.sourceToolCallId,
56
+ }
57
+ );
58
+ }
59
+
60
+ return candidates.slice(0, maxCandidates);
61
+ }
62
+
63
+ function selectRunShellCommandCandidate(example = {}, candidates = []) {
64
+ const values = candidates.map((candidate) => candidate.command).filter(Boolean);
65
+ if (!values.length) return null;
66
+
67
+ const recent = extractRecentShellCommands(example);
68
+ const successfulRecent = new Set(recent
69
+ .filter((item) => /tool_result|passed|success/i.test(item.status || ''))
70
+ .map((item) => normalizeCommand(item.command)));
71
+ const lastRecent = recent.at(-1)?.command || null;
72
+ const lastIndex = values.findIndex((command) => commandsEquivalent(command, lastRecent));
73
+
74
+ if (lastIndex >= 0 && lastIndex + 1 < values.length) {
75
+ const next = values.slice(lastIndex + 1).find((command) => !successfulRecent.has(normalizeCommand(command)));
76
+ if (next) return annotateSelection(candidates, next, 'after_last_recent_command');
77
+ }
78
+
79
+ if (hasOpaqueRunShellFailure(example) && values.length > 1) {
80
+ if (candidates[0]?.source === 'action_memory') {
81
+ return annotateSelection(candidates, values[0], 'top_action_memory_after_opaque_shell_failure');
82
+ }
83
+ return annotateSelection(candidates, values[1], 'after_opaque_shell_failure');
84
+ }
85
+
86
+ const firstUnrun = values.find((command) => !successfulRecent.has(normalizeCommand(command)));
87
+ if (firstUnrun) return annotateSelection(candidates, firstUnrun, 'first_unrun_memory_command');
88
+
89
+ return annotateSelection(candidates, values[0], 'first_memory_command');
90
+ }
91
+
92
+ function scoreRunShellCommandCandidates(expectedCommand = '', candidates = [], selection = null) {
93
+ const expected = normalizeCommand(expectedCommand);
94
+ const index = candidates.findIndex((candidate) => commandsEquivalent(candidate.command, expected));
95
+ const selectedIndex = selection?.command
96
+ ? candidates.findIndex((candidate) => commandsEquivalent(candidate.command, selection.command))
97
+ : -1;
98
+ return {
99
+ expectedPresent: index >= 0,
100
+ expectedRank: index >= 0 ? index + 1 : null,
101
+ expectedTop1: index === 0,
102
+ expectedTop3: index >= 0 && index < 3,
103
+ selectedRank: selectedIndex >= 0 ? selectedIndex + 1 : null,
104
+ selectedExpected: index >= 0 && selectedIndex === index,
105
+ candidateCount: candidates.length,
106
+ };
107
+ }
108
+
109
+ function applyRunShellCommandSelection(example = {}, prediction = null, {
110
+ maxCandidates = 12,
111
+ actionMemoryStore = null,
112
+ memoryLimit = 50,
113
+ } = {}) {
114
+ if (!prediction || prediction.name !== 'run_shell') return { prediction, selection: null, candidates: [] };
115
+ const candidates = buildRunShellCommandCandidates(example, { maxCandidates, actionMemoryStore, memoryLimit });
116
+ const selection = selectRunShellCommandCandidate(example, candidates);
117
+ if (!selection?.command) return { prediction, selection, candidates };
118
+ return {
119
+ prediction: {
120
+ ...prediction,
121
+ input: {
122
+ ...(prediction.input || {}),
123
+ command: selection.command,
124
+ },
125
+ },
126
+ selection,
127
+ candidates,
128
+ };
129
+ }
130
+
131
+ function loadRunShellActionMemoryCandidates(example = {}, {
132
+ actionMemoryStore = null,
133
+ limit = 50,
134
+ } = {}) {
135
+ if (!actionMemoryStore || typeof actionMemoryStore.searchActionMemoryCandidates !== 'function') return [];
136
+ try {
137
+ return actionMemoryStore.searchActionMemoryCandidates({
138
+ context: runShellActionContext(example),
139
+ toolName: 'run_shell',
140
+ prediction: { name: 'run_shell', input: {} },
141
+ limit,
142
+ });
143
+ } catch {
144
+ return [];
145
+ }
146
+ }
147
+
148
+ function runShellActionContext(example = {}) {
149
+ const userContent = (example.messages || [])
150
+ .filter((message) => message.role === 'user')
151
+ .map((message) => message.content || '')
152
+ .join('\n');
153
+ return {
154
+ familyId: example.labels?.workflow_family_id || null,
155
+ repo: example.labels?.workflow_repo || null,
156
+ intent: example.labels?.workflow_intent || null,
157
+ intendedTool: 'run_shell',
158
+ sequence: firstLineValue(userContent, 'tool sequence') || null,
159
+ lastTool: firstLineValue(userContent, 'last tool')?.split(/\s+/)[0] || null,
160
+ taskText: userContent.split(/\nCurrent Wall-E state:/)[0].replace(/^Task:\s*/i, '').trim(),
161
+ };
162
+ }
163
+
164
+ function extractRecentShellCommands(example = {}) {
165
+ const out = [];
166
+ const userContent = (example.messages || [])
167
+ .filter((message) => message.role === 'user')
168
+ .map((message) => message.content || '')
169
+ .join('\n');
170
+
171
+ const recentLine = userContent.split('\n').find((line) => /^\s*-\s*recent shell commands:/i.test(line));
172
+ if (recentLine) {
173
+ const raw = recentLine.replace(/^\s*-\s*recent shell commands:\s*/i, '');
174
+ for (const part of raw.split(/,\s+(?=(tool_result|tool_error|verification_failed|timeout|not_run|passed|failed):)/i)) {
175
+ const match = part.match(/^\s*([a-z_]+):\s*([\s\S]+)$/i);
176
+ if (match) out.push({ status: match[1], command: normalizeCommand(match[2]) });
177
+ }
178
+ }
179
+
180
+ const jsonCommands = extractJsonCommandStrings(userContent);
181
+ for (const command of jsonCommands) {
182
+ if (!out.some((item) => commandsEquivalent(item.command, command))) out.push({ status: 'unknown', command });
183
+ }
184
+ return out.filter((item) => item.command);
185
+ }
186
+
187
+ function hasOpaqueRunShellFailure(example = {}) {
188
+ const userContent = (example.messages || [])
189
+ .filter((message) => message.role === 'user')
190
+ .map((message) => message.content || '')
191
+ .join('\n');
192
+ if (!/known failures:\s*[^-\n]*run_shell tool error/i.test(userContent)) return false;
193
+ return extractRecentShellCommands(example).length === 0;
194
+ }
195
+
196
+ function parseRememberedCommands(text = '', label = '') {
197
+ const line = String(text || '').split('\n').find((item) => item.toLowerCase().includes(`${label.toLowerCase()}:`));
198
+ if (!line) return [];
199
+ const value = line.replace(new RegExp(`^\\s*-\\s*${escapeRegExp(label)}:\\s*`, 'i'), '');
200
+ return splitCommandList(value);
201
+ }
202
+
203
+ function firstLineValue(text = '', label = '') {
204
+ const re = new RegExp(`^\\s*-\\s*${escapeRegExp(label)}:\\s*(.+)$`, 'im');
205
+ const match = String(text || '').match(re);
206
+ return match ? match[1].trim() : null;
207
+ }
208
+
209
+ function splitCommandList(value = '') {
210
+ return String(value || '')
211
+ .split(/,\s+(?=(?:[a-zA-Z0-9_./~-]+|cd |git |npm |node |rg |sed |swiftc |codesign |find |python|pytest|pnpm|yarn))/)
212
+ .map(normalizeCommand)
213
+ .filter(Boolean);
214
+ }
215
+
216
+ function extractJsonCommandStrings(text = '') {
217
+ const out = [];
218
+ for (const match of String(text || '').matchAll(COMMAND_JSON_RE)) {
219
+ try {
220
+ out.push(JSON.parse(`"${match[1]}"`));
221
+ } catch {
222
+ out.push(match[1]);
223
+ }
224
+ }
225
+ return out.map(normalizeCommand).filter(Boolean);
226
+ }
227
+
228
+ function annotateSelection(candidates = [], command = '', reason = '') {
229
+ const candidate = candidates.find((item) => item.command === command) || null;
230
+ return {
231
+ id: candidate?.id || null,
232
+ command,
233
+ source: candidate?.source || null,
234
+ reason,
235
+ memoryEntryId: candidate?.memoryEntryId || null,
236
+ score: candidate?.score,
237
+ memoryReasons: candidate?.memoryReasons || [],
238
+ sourceRowId: candidate?.sourceRowId,
239
+ sourceSessionId: candidate?.sourceSessionId,
240
+ sourceToolCallId: candidate?.sourceToolCallId,
241
+ };
242
+ }
243
+
244
+ function parseToolArguments(value) {
245
+ if (!value) return {};
246
+ if (typeof value === 'object') return value;
247
+ try {
248
+ return JSON.parse(String(value));
249
+ } catch {
250
+ return {};
251
+ }
252
+ }
253
+
254
+ function commandsEquivalent(left, right) {
255
+ return normalizeCommand(left) === normalizeCommand(right);
256
+ }
257
+
258
+ function normalizeCommand(command) {
259
+ return String(command || '').replace(/\r\n/g, '\n').replace(/[ \t]+/g, ' ').trim();
260
+ }
261
+
262
+ function escapeRegExp(value = '') {
263
+ return String(value).replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
264
+ }
265
+
266
+ module.exports = {
267
+ applyRunShellCommandSelection,
268
+ buildRunShellCommandCandidates,
269
+ commandsEquivalent,
270
+ extractRecentShellCommands,
271
+ hasOpaqueRunShellFailure,
272
+ loadRunShellActionMemoryCandidates,
273
+ normalizeCommand,
274
+ runShellActionContext,
275
+ scoreRunShellCommandCandidates,
276
+ selectRunShellCommandCandidate,
277
+ };