mixdog 1.3.2 → 1.3.3

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 (171) hide show
  1. package/package.json +7 -7
  2. package/scripts/verify-runtime-dependency-versions.mjs +158 -0
  3. package/src/agents/reviewer/AGENT.md +5 -7
  4. package/src/agents/reviewer/agent.json +1 -1
  5. package/src/defaults/shipped-history.json +4 -0
  6. package/src/defaults/skills/browser-use/SKILL.md +6 -3
  7. package/src/defaults/skills/local-provider/SKILL.md +33 -6
  8. package/src/rules/lead/LEAD.md +5 -8
  9. package/src/rules/shared/45-destructive.md +5 -1
  10. package/src/rules/shared/60-verification.md +6 -4
  11. package/src/runtime/agent/orchestrator/providers/anthropic-api-request.mjs +4 -1
  12. package/src/runtime/agent/orchestrator/providers/anthropic-max-tokens.mjs +38 -11
  13. package/src/runtime/agent/orchestrator/providers/anthropic-messages.mjs +15 -3
  14. package/src/runtime/agent/orchestrator/providers/anthropic-oauth-client-version.mjs +1 -1
  15. package/src/runtime/agent/orchestrator/providers/anthropic-oauth.mjs +17 -4
  16. package/src/runtime/agent/orchestrator/providers/anthropic.mjs +14 -1
  17. package/src/runtime/agent/orchestrator/providers/cursor-client-version.mjs +1 -1
  18. package/src/runtime/agent/orchestrator/providers/custom-provider-config.mjs +14 -1
  19. package/src/runtime/agent/orchestrator/providers/grok-client-version.mjs +1 -1
  20. package/src/runtime/agent/orchestrator/providers/registry.mjs +10 -0
  21. package/src/runtime/agent/orchestrator/providers/wire-gateway.mjs +13 -1
  22. package/src/runtime/agent/orchestrator/runtime-core/goal-runtime.mjs +5 -0
  23. package/src/runtime/agent/orchestrator/runtime-core/goal-turns.mjs +10 -1
  24. package/src/runtime/agent/orchestrator/runtime-core/tool-catalog.mjs +40 -5
  25. package/src/runtime/agent/orchestrator/runtime-core/tool-defs.mjs +32 -11
  26. package/src/runtime/agent/orchestrator/runtime-core/workflow.mjs +6 -3
  27. package/src/runtime/agent/orchestrator/session/agent-loop.mjs +1 -1
  28. package/src/runtime/agent/orchestrator/session/agent-room.d.mts +13 -0
  29. package/src/runtime/agent/orchestrator/session/agent-room.mjs +68 -12
  30. package/src/runtime/agent/orchestrator/session/compact/continuation.mjs +15 -6
  31. package/src/runtime/agent/orchestrator/session/compact/execution-tail.mjs +31 -8
  32. package/src/runtime/agent/orchestrator/session/compact/messages.mjs +44 -0
  33. package/src/runtime/agent/orchestrator/session/compact/runner.mjs +117 -19
  34. package/src/runtime/agent/orchestrator/session/compact/text-utils.mjs +1 -1
  35. package/src/runtime/agent/orchestrator/session/compact/user-message-kind.mjs +3 -0
  36. package/src/runtime/agent/orchestrator/session/human-gate/delegation.mjs +147 -137
  37. package/src/runtime/agent/orchestrator/session/human-gate/gate.mjs +37 -74
  38. package/src/runtime/agent/orchestrator/session/human-gate/requests.mjs +0 -2
  39. package/src/runtime/agent/orchestrator/session/human-gate/run-policy.mjs +2 -2
  40. package/src/runtime/agent/orchestrator/session/loop/fresh-context.mjs +13 -7
  41. package/src/runtime/agent/orchestrator/session/loop/loop-state.mjs +5 -0
  42. package/src/runtime/agent/orchestrator/session/loop/no-tool-turn/continuation.mjs +2 -0
  43. package/src/runtime/agent/orchestrator/session/loop/no-tool-turn/empty-nudge.mjs +1 -1
  44. package/src/runtime/agent/orchestrator/session/loop/no-tool-turn/output-limit.mjs +62 -13
  45. package/src/runtime/agent/orchestrator/session/loop/no-tool-turn.mjs +22 -6
  46. package/src/runtime/agent/orchestrator/session/loop/send-phase.mjs +7 -0
  47. package/src/runtime/agent/orchestrator/session/loop/tool-exec/before-hook.mjs +12 -20
  48. package/src/runtime/agent/orchestrator/session/loop/tool-exec/call-prep.mjs +5 -0
  49. package/src/runtime/agent/orchestrator/session/loop/tool-exec/dispatch.mjs +11 -5
  50. package/src/runtime/agent/orchestrator/session/manager/agent-listing-notice.mjs +102 -0
  51. package/src/runtime/agent/orchestrator/session/manager/ask-queue.mjs +2 -0
  52. package/src/runtime/agent/orchestrator/session/manager/ask-session.mjs +13 -1
  53. package/src/runtime/agent/orchestrator/session/manager/ask-turn-execute.mjs +24 -15
  54. package/src/runtime/agent/orchestrator/session/manager/ask-turn-prepare.mjs +8 -0
  55. package/src/runtime/agent/orchestrator/session/manager/ask-turn-steering-drain.mjs +1 -0
  56. package/src/runtime/agent/orchestrator/session/manager/idle-cleanup.mjs +32 -1
  57. package/src/runtime/agent/orchestrator/session/manager/orchestration-mode-switch-notice.mjs +17 -1
  58. package/src/runtime/agent/orchestrator/session/manager/pending-message-entry.mjs +6 -0
  59. package/src/runtime/agent/orchestrator/session/manager/prompt-utils.mjs +36 -0
  60. package/src/runtime/agent/orchestrator/session/manager/session-crud.mjs +28 -9
  61. package/src/runtime/agent/orchestrator/session/manager/session-prompt-composition.mjs +1 -1
  62. package/src/runtime/agent/orchestrator/session/manager/session-record.mjs +7 -5
  63. package/src/runtime/agent/orchestrator/session/manager/session-tool-surface.mjs +7 -3
  64. package/src/runtime/agent/orchestrator/session/pre-send-compact.mjs +10 -1
  65. package/src/runtime/agent/orchestrator/session/routine-result.mjs +7 -4
  66. package/src/runtime/agent/orchestrator/session/runtime-user-context.mjs +3 -1
  67. package/src/runtime/agent/orchestrator/session/send-with-recovery.mjs +11 -2
  68. package/src/runtime/agent/orchestrator/session/store/sweep/stale-sweep.mjs +5 -4
  69. package/src/runtime/agent/orchestrator/session/store/sweep/sub-agent-retention.mjs +140 -0
  70. package/src/runtime/agent/orchestrator/session/store/sweep/sweep-plan.mjs +5 -0
  71. package/src/runtime/agent/orchestrator/session/store/sweep/sweep-record.mjs +7 -2
  72. package/src/runtime/agent/orchestrator/session/store/sweep/sweep-row.mjs +13 -0
  73. package/src/runtime/agent/orchestrator/session/store-summary-catalog.mjs +76 -0
  74. package/src/runtime/agent/orchestrator/session/store-summary-reader.mjs +33 -1
  75. package/src/runtime/agent/orchestrator/session/store-summary-visibility.d.mts +5 -0
  76. package/src/runtime/agent/orchestrator/session/store-summary-visibility.mjs +37 -0
  77. package/src/runtime/agent/orchestrator/session/store.mjs +1 -0
  78. package/src/runtime/agent/orchestrator/tools/builtin/advisory-lock.mjs +18 -7
  79. package/src/runtime/agent/orchestrator/tools/builtin/bash-tool/backgrounded-result.mjs +2 -0
  80. package/src/runtime/agent/orchestrator/tools/builtin/git-command-tool.mjs +127 -20
  81. package/src/runtime/agent/orchestrator/tools/builtin/git-worktree-tool.mjs +557 -0
  82. package/src/runtime/agent/orchestrator/tools/builtin/lib/shell-job-records.mjs +6 -0
  83. package/src/runtime/agent/orchestrator/tools/builtin/shell-jobs.mjs +8 -2
  84. package/src/runtime/attachments/legacy-office.mjs +110 -0
  85. package/src/runtime/attachments/prompt-restore.mjs +70 -0
  86. package/src/runtime/attachments/store.mjs +60 -3
  87. package/src/runtime/effort-judge/judge-client.mjs +61 -14
  88. package/src/runtime/effort-judge/model-install.mjs +34 -2
  89. package/src/runtime/memory/lib/memory-chunk-quality.mjs +14 -2
  90. package/src/runtime/office/portable/portable-soffice.mjs +132 -30
  91. package/src/runtime/shared/agent-avatar-sprites.mjs +23 -8
  92. package/src/runtime/shared/agent-avatar.mjs +3 -2
  93. package/src/runtime/shared/agent-room-host.d.mts +31 -0
  94. package/src/runtime/shared/agent-room-host.mjs +58 -0
  95. package/src/runtime/shared/bot-hops.mjs +16 -11
  96. package/src/runtime/shared/redact-directories.mjs +18 -0
  97. package/src/runtime/shared/remove-directory.mjs +28 -0
  98. package/src/runtime/shared/session-sidebar-host.d.mts +11 -2
  99. package/src/runtime/shared/session-sidebar-host.mjs +16 -3
  100. package/src/runtime/shared/tool-execution-contract.mjs +4 -0
  101. package/src/runtime/shared/tool-work-units.mjs +12 -9
  102. package/src/runtime/shared/turn-snapshot.mjs +233 -122
  103. package/src/runtime/shared/user-data-guard.mjs +51 -19
  104. package/src/runtime/shared/worktrees/activity-gate.mjs +209 -227
  105. package/src/runtime/shared/worktrees/contract.mjs +11 -3
  106. package/src/runtime/shared/worktrees/maintenance.mjs +11 -2
  107. package/src/runtime/shared/worktrees/manager.mjs +419 -52
  108. package/src/runtime/shared/worktrees/registry.mjs +3 -1
  109. package/src/runtime/shared/worktrees/tool-host.mjs +39 -0
  110. package/src/runtime/tidy/process.mjs +41 -8
  111. package/src/runtime/tidy/resolve.mjs +10 -7
  112. package/src/session-runtime/agent-home-delivery.mjs +73 -91
  113. package/src/session-runtime/agent-profile-changes.mjs +16 -0
  114. package/src/session-runtime/agent-room-delivery.mjs +2 -63
  115. package/src/session-runtime/agent-task-sessions.mjs +194 -64
  116. package/src/session-runtime/boot/apis.mjs +3 -0
  117. package/src/session-runtime/boot/facade.mjs +5 -6
  118. package/src/session-runtime/boot/tools.mjs +21 -1
  119. package/src/session-runtime/held-requests.mjs +20 -25
  120. package/src/session-runtime/internal-tool-executor/workspace-tools.mjs +5 -22
  121. package/src/session-runtime/model-recency.mjs +1 -0
  122. package/src/session-runtime/provider-models/row-hydration.mjs +8 -1
  123. package/src/session-runtime/quick-model-rows/model-meta.mjs +2 -0
  124. package/src/session-runtime/quick-model-rows/provider-rows.mjs +7 -1
  125. package/src/session-runtime/runtime-review-api.mjs +4 -1
  126. package/src/session-runtime/services/agent-tool/job-views/agent-list.mjs +34 -19
  127. package/src/session-runtime/services/agent-tool/spawn-flow/job-start.mjs +3 -0
  128. package/src/session-runtime/services/provider-admin.mjs +12 -2
  129. package/src/session-runtime/services/worktree-access.mjs +27 -0
  130. package/src/session-runtime/session-hooks.mjs +9 -17
  131. package/src/session-runtime/settings-builtin-tools-api.mjs +2 -0
  132. package/src/session-runtime/setup-tool/executor.mjs +4 -0
  133. package/src/session-runtime/setup-tool/settings-contract.mjs +3 -0
  134. package/src/session-runtime/tool-policy/agent-profile-fold.mjs +98 -14
  135. package/src/session-runtime/tool-policy/policy-stage.mjs +23 -5
  136. package/src/session-runtime/tool-policy-refresh.mjs +1 -0
  137. package/src/session-runtime/tool-surface.mjs +9 -5
  138. package/src/session-runtime/turn/session-ops.mjs +8 -0
  139. package/src/session-runtime/turn/turn-run.mjs +5 -1
  140. package/src/session-runtime/workflow-agents-api/agent-editor.mjs +10 -2
  141. package/src/session-runtime/workflow-agents-api/agent-route.mjs +39 -17
  142. package/src/session-runtime/workspace/transition-steps.mjs +1 -18
  143. package/src/session-runtime/workspace/transitions.mjs +279 -67
  144. package/src/session-runtime/workspace/worktree-tool.mjs +194 -0
  145. package/src/standalone/daemon-lag-profiler.mjs +3 -1
  146. package/src/standalone/daemon-session-control.mjs +140 -23
  147. package/src/standalone/daemon-telemetry.mjs +9 -0
  148. package/src/standalone/daemon.mjs +5 -0
  149. package/src/standalone/local-session-runtime.mjs +11 -2
  150. package/src/standalone/session-protocol.mjs +1 -0
  151. package/src/standalone/session-runtime-inline-host/boot-loaders.mjs +2 -0
  152. package/src/standalone/session-service/agent-route-follow.mjs +69 -0
  153. package/src/standalone/session-service/session-calls/session-turns.mjs +33 -4
  154. package/src/standalone/session-service.mjs +10 -0
  155. package/src/standalone/session-tool-output.mjs +1 -0
  156. package/src/standalone/staged-import.mjs +47 -0
  157. package/src/tui/App.jsx +2 -0
  158. package/src/tui/app/message-selector.mjs +15 -2
  159. package/src/tui/app/model-options.mjs +16 -2
  160. package/src/tui/app/model-picker.mjs +2 -1
  161. package/src/tui/app/route-pickers.mjs +3 -1
  162. package/src/tui/dist/index.mjs +92 -40
  163. package/src/tui/paste-attachments.mjs +0 -1
  164. package/src/tui/paste-text-policy.mjs +4 -5
  165. package/src/tui/session/agent-job-feed/execution-delivery.mjs +4 -1
  166. package/src/tui/session/notice-surface.mjs +3 -0
  167. package/src/tui/session/session-api/intake/abort.mjs +33 -17
  168. package/src/tui/session/session-api/intake/rewind.mjs +39 -4
  169. package/src/tui/session/session-api/routes-agent-definitions.mjs +1 -0
  170. package/src/tui/session/tool-approval.mjs +11 -48
  171. package/src/session-runtime/room-member-gate.mjs +0 -61
@@ -1,13 +1,17 @@
1
1
  // Message selector ("jump back to a previous message"): rewind the
2
2
  // conversation to just before a user prompt and hand its text back for
3
3
  // editing. Idle-only — a live turn must be interrupted first.
4
+ import { restorableAttachmentsFromPrompt } from '../../../../runtime/attachments/prompt-restore.mjs';
4
5
  import { promptHistoryWithout } from '../../prompt-history.mjs';
6
+ import { hydrateTolerantly } from './abort.mjs';
5
7
 
6
8
  export function createRewindAction(bag) {
7
9
  const { runtime, getState, set, flushEmitImmediate, replaceItems, syncContextStats } = bag;
8
10
 
9
11
  return {
10
- rewindToItem: async (itemId) => {
12
+ // `restoreFiles: false` is a composer that cannot hold PDF/Office file
13
+ // parts (the terminal one): a prompt carrying any is refused untouched.
14
+ rewindToItem: async (itemId, { restoreFiles = true } = {}) => {
11
15
  const target = String(itemId ?? '').trim();
12
16
  if (!target) return null;
13
17
  if (getState().busy || getState().commandBusy) return null;
@@ -19,8 +23,31 @@ export function createRewindAction(bag) {
19
23
  if (!text) return null;
20
24
  set({ commandBusy: true });
21
25
  try {
22
- const rewound = await runtime.rewindMessages?.({ text });
23
- if (!rewound) return null;
26
+ // Matched by the row's stable message id (the stored prompt is the
27
+ // expanded text); rows without one fall back to the text.
28
+ const messageId = String(items[index]?.messageId || '');
29
+ const rewindOptions = { text, ...(messageId ? { messageId } : {}) };
30
+ // Resolve the prompt and build the whole restore payload BEFORE any
31
+ // history changes: a refusal or an attachment read error then leaves the
32
+ // model history and the transcript both untouched.
33
+ const preview = await runtime.rewindMessages?.({ ...rewindOptions, dryRun: true });
34
+ if (!preview) return null;
35
+ // The stored prompt's attachment references become the restore payload
36
+ // the abort/queue restores use (pastedTexts / pastedImages / file parts).
37
+ const content = preview.message?.content;
38
+ if (!restoreFiles && Array.isArray(content) && content.some((part) => part?.type === 'file')) {
39
+ throw new Error(
40
+ 'this message has PDF/Office attachments the terminal composer cannot restore; edit it in the desktop app'
41
+ );
42
+ }
43
+ const refs = restorableAttachmentsFromPrompt(content, text);
44
+ const attachments = hydrateTolerantly(refs.pastedImages, refs.pastedTexts, content);
45
+ // Refused when the history changed since the preview.
46
+ const rewound = await runtime.rewindMessages?.({
47
+ ...rewindOptions,
48
+ ...(preview.historyMarker ? { expectedHistoryMarker: preview.historyMarker } : {}),
49
+ });
50
+ if (!rewound) throw new Error('the conversation changed; select the message again');
24
51
  set({
25
52
  items: replaceItems(items.slice(0, index), {
26
53
  preserveSpill: true,
@@ -36,7 +63,15 @@ export function createRewindAction(bag) {
36
63
  syncContextStats({ allowEstimated: true });
37
64
  set({ stats: { ...getState().stats } });
38
65
  flushEmitImmediate?.();
39
- return { text, removed: items.length - index, messages: rewound.removed };
66
+ return {
67
+ text,
68
+ removed: items.length - index,
69
+ messages: rewound.removed,
70
+ ...(attachments.pastedImages ? { pastedImages: attachments.pastedImages } : {}),
71
+ ...(attachments.pastedTexts ? { pastedTexts: attachments.pastedTexts } : {}),
72
+ ...(attachments.content ? { content: attachments.content } : {}),
73
+ ...(attachments.notice ? { notice: attachments.notice } : {}),
74
+ };
40
75
  } finally {
41
76
  set({ commandBusy: false });
42
77
  }
@@ -55,6 +55,7 @@ export function createAgentDefinitionApi(runtime) {
55
55
  saveLeadAgentBody: async (text) => runtime.saveLeadAgentBody?.(text) ?? '',
56
56
  getLeadStatus: () =>
57
57
  runtime.getLeadStatus?.() ?? { created: null, name: '', avatar: null, homeChatted: false, route: null },
58
+ getLeadHomeRoute: () => runtime.getLeadHomeRoute?.() ?? null,
58
59
  saveLeadIdentity: async (payload) => runtime.saveLeadIdentity?.(payload) ?? null,
59
60
  setLeadCreated: async (created, description) => runtime.setLeadCreated?.(created, description) ?? null,
60
61
  saveAgentDefinition: async (payload, options) => runtime.saveAgentDefinition?.(payload, options) ?? null,
@@ -96,17 +96,14 @@ export function createToolApproval({ getState, set, nextId, getDisposed, timeout
96
96
  // Settle one entry: drop its timeout, then hand the waiter its answer. The
97
97
  // resolve stays guarded — a waiter whose caller already went away must never
98
98
  // take the rest of the queue down with it.
99
- function settleToolApproval(entry, approved, reason, answers, reply, extra, device = '', forwarded = false) {
99
+ function settleToolApproval(entry, approved, reason, answers, reply, extra, device = '') {
100
100
  if (entry?.timer) clearTimeout(entry.timer);
101
101
  const result = { approved, reason };
102
102
  if (answers !== undefined) result.answers = answers;
103
103
  if (reply !== undefined) result.reply = reply;
104
- // A human-kind request answers with its canonical response (never a value),
105
- // judged against what the answering place offered: this queue's own view,
106
- // or — answered on its copy — the full request the copy already narrowed.
107
- const answered = forwarded ? entry?.full || entry?.request : entry?.request;
108
- if (answered?.remember) {
109
- Object.assign(result, normalizeHumanResponse(answered, approved, extra));
104
+ // A human-kind request answers with its canonical response (never a value).
105
+ if (entry?.request?.remember) {
106
+ Object.assign(result, normalizeHumanResponse(entry.request, approved, extra));
110
107
  if (device) result.device = device;
111
108
  }
112
109
  if (extra?.timedOut === true) result.timedOut = true;
@@ -120,28 +117,15 @@ export function createToolApproval({ getState, set, nextId, getDisposed, timeout
120
117
  * owner had already settled it. */
121
118
  function forwardToOwner(entry, approved, reason, device, answers, reply, extra) {
122
119
  try {
123
- return entry.mirror.answer(approved, reason, device, answers, reply, onlyOffered(entry.request, extra)) === true;
120
+ return entry.mirror.answer(approved, reason, device, answers, reply, extra) === true;
124
121
  } catch {
125
122
  return false;
126
123
  }
127
124
  }
128
- /** `request` as this session shows it: a remembering scope is offered only
129
- * in the one session the request names for it (`rememberAt`, the bot's own
130
- * chat); everywhere else — and when it names none — it asks once. */
131
- function viewFor(request) {
132
- if (!Array.isArray(request?.remember) || request.remember.length <= 1) return request;
133
- const here = ownSessionId();
134
- return here && request.rememberAt === here ? request : { ...request, remember: ['once'] };
135
- }
136
- /** `extra` without a remember scope `view` did not offer. */
137
- function onlyOffered(view, extra) {
138
- if (!extra || extra.remember === undefined) return extra;
139
- return (view?.remember || ['once']).includes(extra.remember) ? extra : { ...extra, remember: 'once' };
140
- }
141
125
  function offerDelegatedApproval(delegated) {
142
126
  if (getDisposed() || delegated.sessionId !== ownSessionId()) return;
143
127
  if (activeToolApproval?.id === delegated.id || toolApprovalQueue.some((entry) => entry.id === delegated.id)) return;
144
- toolApprovalQueue.push({ id: delegated.id, request: viewFor(delegated.request), mirror: delegated, timer: null });
128
+ toolApprovalQueue.push({ id: delegated.id, request: delegated.request, mirror: delegated, timer: null });
145
129
  presentNextToolApproval();
146
130
  }
147
131
  function withdrawDelegatedCopy(id, result) {
@@ -183,8 +167,7 @@ export function createToolApproval({ getState, set, nextId, getDisposed, timeout
183
167
  device = '',
184
168
  answers = undefined,
185
169
  reply = undefined,
186
- extra = undefined,
187
- { forwarded = false } = {}
170
+ extra = undefined
188
171
  ) {
189
172
  const targetId = String(id || '');
190
173
  if (activeToolApproval && activeToolApproval.id === targetId) {
@@ -200,16 +183,7 @@ export function createToolApproval({ getState, set, nextId, getDisposed, timeout
200
183
  if (entry.mirror) {
201
184
  accepted = forwardToOwner(entry, approved, reason, device, answers, reply, extra);
202
185
  } else {
203
- settleToolApproval(
204
- entry,
205
- approved === true,
206
- String(reason || ''),
207
- answers,
208
- reply,
209
- extra,
210
- String(device || ''),
211
- forwarded
212
- );
186
+ settleToolApproval(entry, approved === true, String(reason || ''), answers, reply, extra, String(device || ''));
213
187
  }
214
188
  presentNextToolApproval();
215
189
  return accepted;
@@ -218,16 +192,7 @@ export function createToolApproval({ getState, set, nextId, getDisposed, timeout
218
192
  if (index >= 0) {
219
193
  const [entry] = toolApprovalQueue.splice(index, 1);
220
194
  if (entry.mirror) return forwardToOwner(entry, approved, reason, device, answers, reply, extra);
221
- settleToolApproval(
222
- entry,
223
- approved === true,
224
- String(reason || ''),
225
- answers,
226
- reply,
227
- extra,
228
- String(device || ''),
229
- forwarded
230
- );
195
+ settleToolApproval(entry, approved === true, String(reason || ''), answers, reply, extra, String(device || ''));
231
196
  return true;
232
197
  }
233
198
  return false;
@@ -265,9 +230,7 @@ export function createToolApproval({ getState, set, nextId, getDisposed, timeout
265
230
  full.chain = surface.chain;
266
231
  full.surfaceSessionId = surface.sessionId;
267
232
  }
268
- // `request` is what this session shows (and accepts answers against);
269
- // `full` what the copy in the top-level chat is made from.
270
- const entry = { id, request: viewFor(full), full, resolve, timer: null, delegated: Boolean(surface) };
233
+ const entry = { id, request: full, resolve, timer: null, delegated: Boolean(surface) };
271
234
  toolApprovalQueue.push(entry);
272
235
  armToolApprovalTimeout(entry);
273
236
  presentNextToolApproval();
@@ -277,7 +240,7 @@ export function createToolApproval({ getState, set, nextId, getDisposed, timeout
277
240
  sessionId: surface.sessionId,
278
241
  request: full,
279
242
  answer: (approved, reason, device, answers, reply, extra) =>
280
- finishToolApproval(id, approved, reason, device, answers, reply, extra, { forwarded: true }),
243
+ finishToolApproval(id, approved, reason, device, answers, reply, extra),
281
244
  });
282
245
  }
283
246
  });
@@ -1,61 +0,0 @@
1
- // A group-room member's tool calls (session/agent-room.mjs). Reads run freely;
2
- // anything that can change files or state asks the user through the ordinary
3
- // approval flow, whatever the agent's own permission or hook rules say — even
4
- // an agent that normally runs auto-approved. A hook's deny still wins.
5
- // Opening a task session (`session create`) runs as freely as in the agent's
6
- // home thread: it changes nothing itself, and the task session is the user's
7
- // own coding Lead, whose every side effect follows its usual approval rules.
8
- import { analyzeShellCommandEffects } from '../runtime/agent/orchestrator/tools/builtin/shell-analysis.mjs';
9
-
10
- const READ_ONLY_TOOLS = new Set([
11
- 'read',
12
- 'grep',
13
- 'glob',
14
- 'find',
15
- 'list',
16
- 'code_graph',
17
- 'load_tool',
18
- 'skill',
19
- 'Skill',
20
- 'recall',
21
- 'search_memories',
22
- 'web_search',
23
- 'web_fetch',
24
- 'local_fetch',
25
- 'image_fetch',
26
- 'ask_user',
27
- ]);
28
-
29
- export const ROOM_APPROVAL_REASON = 'Group-room members need your approval before changing anything.';
30
-
31
- /** Whether `name(args)` only reads: a read-only tool, or a shell command whose
32
- * every stage the shell analysis classifies as non-mutating. */
33
- export async function isReadOnlyRoomCall({ name, args, cwd }, analyze = analyzeShellCommandEffects) {
34
- if (READ_ONLY_TOOLS.has(name)) return true;
35
- if (name !== 'shell' || typeof args?.command !== 'string') return false;
36
- try {
37
- return (await analyze(args.command, cwd))?.mutationMode === 'none';
38
- } catch {
39
- return false;
40
- }
41
- }
42
-
43
- /** Whether `name(args)` opens a task session (session create). */
44
- export function isTaskSessionCreate({ name, args }) {
45
- return (
46
- name === 'session' &&
47
- String(args?.action ?? '')
48
- .trim()
49
- .toLowerCase() === 'create'
50
- );
51
- }
52
-
53
- /** The PreToolUse decision for a room member's call: the hook's own `decision`
54
- * when it denies, the call only reads, or it opens a task session; otherwise
55
- * an approval ask that keeps any rewrite the hook made. */
56
- export async function roomMemberToolDecision(call, decision, analyze) {
57
- const action = String(decision?.action || decision?.decision || '').toLowerCase();
58
- if (action === 'deny' || action === 'block') return decision;
59
- if (isTaskSessionCreate(call) || (await isReadOnlyRoomCall(call, analyze))) return decision;
60
- return { ...(decision && typeof decision === 'object' ? decision : {}), action: 'ask', reason: ROOM_APPROVAL_REASON };
61
- }