shraga 0.1.29 → 0.1.30

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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "shraga",
3
- "version": "0.1.29",
3
+ "version": "0.1.30",
4
4
  "description": "The teammate you delegate coding to — a self-hostable, multi-user AI coding agent web UI (Claude Code, with a pluggable engine seam).",
5
5
  "type": "module",
6
6
  "main": "./src/index.ts",
@@ -198,7 +198,10 @@ export async function runSchedule(
198
198
  // reaches nobody: the agent reports the failure in prose, its own turn succeeds, the run is stored
199
199
  // `ok`, and the failure notifier never fires. Track the tool_result of the task's OWN Bash call and
200
200
  // fail the run with it, so a broken scheduled script alerts like a `job` does.
201
- const taskBashToolUseIds = new Set<string>();
201
+ // Correlation is by toolUseId, decided at tool_result time: `tool_use` is yielded at
202
+ // content_block_start, when the input is still EMPTY (it streams in afterwards as `tool_use_input`),
203
+ // so matching the command there matches nothing.
204
+ const toolUses = new Map<string, { tool: string; input: unknown }>();
202
205
  let bashFailure: string | undefined;
203
206
 
204
207
  onEvent({ type: 'schedule:run_started', scheduleId: schedule.id, sessionId, at: now });
@@ -208,7 +211,7 @@ export async function runSchedule(
208
211
  status = 'ok';
209
212
  error = undefined;
210
213
  bashFailure = undefined;
211
- taskBashToolUseIds.clear();
214
+ toolUses.clear();
212
215
  try {
213
216
  for await (const ev of streamChat({
214
217
  prompt,
@@ -226,12 +229,20 @@ export async function runSchedule(
226
229
  } else if (ev.type === 'tool_use') {
227
230
  if (assistantText) { assistantBlocks.push({ type: 'text', text: assistantText }); assistantText = ''; }
228
231
  assistantBlocks.push({ type: 'tool_use', tool: ev.tool, toolUseId: ev.toolUseId, input: ev.input });
229
- if (allowedCmd && ev.tool === 'Bash' && (ev.input as any)?.command === allowedCmd) taskBashToolUseIds.add(ev.toolUseId);
232
+ toolUses.set(ev.toolUseId, { tool: ev.tool, input: ev.input });
233
+ } else if (ev.type === 'tool_use_input') {
234
+ // The tool's real input arrives here, after the block opened — keep both the persisted
235
+ // block and the correlation map in sync, else the transcript shows an empty `{}` call.
236
+ const entry = toolUses.get(ev.toolUseId);
237
+ if (entry) entry.input = ev.input;
238
+ const block = assistantBlocks.find((b) => b.type === 'tool_use' && b.toolUseId === ev.toolUseId) as any;
239
+ if (block) block.input = ev.input;
230
240
  } else if (ev.type === 'thinking_delta') {
231
241
  producedThinking = true;
232
242
  } else if (ev.type === 'tool_result') {
233
243
  assistantBlocks.push({ type: 'tool_result', toolUseId: ev.toolUseId, output: ev.output });
234
- if (ev.isError && taskBashToolUseIds.has(ev.toolUseId)) bashFailure = ev.output;
244
+ const use = toolUses.get(ev.toolUseId);
245
+ if (ev.isError && allowedCmd && use?.tool === 'Bash' && (use.input as any)?.command === allowedCmd) bashFailure = ev.output;
235
246
  } else if (ev.type === 'done') {
236
247
  break;
237
248
  } else if (ev.type === 'error') {