devez-vibe 1.9.58 → 1.9.59

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/bin/dvz.exe CHANGED
Binary file
@@ -2686,8 +2686,9 @@ function resumeBackgroundSubagent(session, toolUseId, pending, result) {
2686
2686
  if (existing) return true;
2687
2687
  const known = session.knownSubagents.get(taskId);
2688
2688
  const input = pending?.input || {};
2689
+ // 끝난 줄과 같은 id로 돌아와야 호스트가 같은 작업의 idle 줄과 실행 줄을 함께 세우지 않는다.
2689
2690
  const running = {
2690
- id: toolUseId,
2691
+ id: known?.rowId || toolUseId,
2691
2692
  toolUseId,
2692
2693
  taskId,
2693
2694
  background: true,
@@ -2697,8 +2698,9 @@ function resumeBackgroundSubagent(session, toolUseId, pending, result) {
2697
2698
  startedAt: Date.now(),
2698
2699
  lastSeenAt: Date.now(),
2699
2700
  };
2700
- session.subagents.set(toolUseId, running);
2701
+ session.subagents.set(running.id, running);
2701
2702
  session.knownSubagents.set(taskId, {
2703
+ rowId: running.id,
2702
2704
  name: running.name,
2703
2705
  description: running.description,
2704
2706
  backgroundTask: false,
@@ -2777,6 +2779,8 @@ function upsertStructuredSubagent(session, message) {
2777
2779
  }
2778
2780
  if (toolUseId) running.toolUseId = toolUseId;
2779
2781
  if (taskId) running.taskId = taskId;
2782
+ const runId = firstLine(message.run_id || "", 80);
2783
+ if (runId && !isLateRun(running, runId)) running.runId = runId;
2780
2784
  // 스크립트 Monitor는 local_bash 작업으로 와서 스냅숏 이름이 Bash가 된다.
2781
2785
  if (session.tools?.get(toolUseId)?.name === "Monitor") running.name = "Monitor";
2782
2786
  const parentTaskId = firstLine(message.parent_task_id || "", 80);
@@ -2786,10 +2790,12 @@ function upsertStructuredSubagent(session, message) {
2786
2790
  if (subagentType || isSubagentTaskType(message.task_type)) running.backgroundTask = false;
2787
2791
  running.lastSeenAt = Date.now();
2788
2792
  if (running.taskId) {
2793
+ const known = session.knownSubagents.get(running.taskId);
2789
2794
  session.knownSubagents.set(running.taskId, {
2790
2795
  rowId: running.id,
2791
2796
  name: running.name,
2792
- description: running.description,
2797
+ // 진행 요약으로 바뀐 설명이 아니라 호출 설명을 기억해, 다시 실행된 줄이 그 설명으로 돌아오게 한다.
2798
+ description: known?.description || running.description,
2793
2799
  backgroundTask: running.backgroundTask === true,
2794
2800
  });
2795
2801
  }
@@ -2800,6 +2806,12 @@ function hasLiveChildren(session, taskId) {
2800
2806
  return !!taskId && [...session.subagents.values()].some((agent) => agent.parentTaskId === taskId);
2801
2807
  }
2802
2808
 
2809
+ // 같은 작업의 실행 id는 열린 순서대로 문자열 정렬된다. 지금 행보다 앞선 실행의
2810
+ // 통지는 늦게 도착한 것이라 새 실행의 행을 지우면 안 된다.
2811
+ function isLateRun(running, runId) {
2812
+ return Boolean(runId && running.runId && runId < running.runId);
2813
+ }
2814
+
2803
2815
  function finishStructuredSubagent(session, message) {
2804
2816
  const taskId = firstLine(message.task_id || "", 80);
2805
2817
  const toolUseId = firstLine(message.tool_use_id || "", 80);
@@ -2814,7 +2826,8 @@ function finishStructuredSubagent(session, message) {
2814
2826
  || (taskId && findSubagent(session, taskId));
2815
2827
  if (!running) return wasHidden;
2816
2828
  // 자기 백그라운드 명령을 기다리며 멈춘 에이전트는 그 명령이 끝나면 다시 돌므로 행을 남긴다.
2817
- if (hasLiveChildren(session, running.taskId)) return true;
2829
+ if (hasLiveChildren(session, running.taskId)
2830
+ || isLateRun(running, firstLine(message.run_id || "", 80))) return true;
2818
2831
  session.subagents.delete(running.id);
2819
2832
  emitSubagents(session);
2820
2833
  return true;
@@ -3129,6 +3142,7 @@ function taskNotifications(message) {
3129
3142
  toolUseId: notificationTag(body, "tool-use-id"),
3130
3143
  status: notificationTag(body, "status"),
3131
3144
  summary: notificationTag(body, "summary"),
3145
+ runId: firstLine(message.origin?.runId || "", 80),
3132
3146
  });
3133
3147
  }
3134
3148
  return notifications;
@@ -3156,7 +3170,8 @@ function finishNotifiedSubagents(session, notifications) {
3156
3170
  .find((agent) => agent.background && agent.name === name);
3157
3171
  }
3158
3172
  }
3159
- if (!running) continue;
3173
+ if (!running || isLateRun(running, notification.runId)
3174
+ || hasLiveChildren(session, running.taskId)) continue;
3160
3175
  session.subagents.delete(running.id);
3161
3176
  emitSubagents(session);
3162
3177
  }
@@ -6010,8 +6025,10 @@ async function runSelfTest() {
6010
6025
  message: { content: [{ type: "tool_result", tool_use_id: "toolu_2", content: "resumed" }] },
6011
6026
  tool_use_result: { success: true, resumedAgentId: "agent-1" },
6012
6027
  });
6013
- const resumed = lifecycleSession.subagents.get("toolu_2");
6014
- if (!resumed?.background || resumed.taskId !== "agent-1" || resumed.name !== "Explore") {
6028
+ // 재개된 줄은 끝난 줄과 같은 id(처음 Agent 호출 id)로 돌아오고, SendMessage 호출 id로도 찾힌다.
6029
+ const resumed = lifecycleSession.subagents.get("toolu_1");
6030
+ if (!resumed?.background || resumed.taskId !== "agent-1" || resumed.name !== "Explore"
6031
+ || findSubagent(lifecycleSession, "toolu_2") !== resumed) {
6015
6032
  throw new Error(`Claude resumed subagent self-test failed: ${JSON.stringify(resumed)}`);
6016
6033
  }
6017
6034
  finishTurn(lifecycleSession, null, 1);
@@ -6161,36 +6178,56 @@ async function runSelfTest() {
6161
6178
  }
6162
6179
  clearSubagents(nestedSession);
6163
6180
  // 자기 백그라운드 명령을 기다리며 멈춘 에이전트는 그 명령이 도는 동안 행을 지킨다.
6164
- processSubagentSystemMessage(nestedSession, {
6165
- type: "system",
6166
- subtype: "task_started",
6167
- task_id: "agent-wait",
6168
- tool_use_id: "toolu_wait",
6169
- task_type: "local_agent",
6170
- subagent_type: "general-purpose",
6171
- });
6172
- nestedSession.subagents.get("toolu_wait").background = true;
6181
+ // SDK 순서(접수 결과, task_started, 스냅숏, task_updated·task_notification, 스냅숏,
6182
+ // XML 통지)를 그대로 재생하고, 다시 실행된 뒤 늦게 온 첫 실행 통지도 무시한다.
6173
6183
  const waitSnapshot = (tasks) => processSubagentSystemMessage(nestedSession, {
6174
6184
  type: "system",
6175
6185
  subtype: "background_tasks_changed",
6176
6186
  tasks,
6177
6187
  });
6178
- waitSnapshot([{ task_id: "shell-wait", task_type: "local_bash", description: "sleep 300", parent_task_id: "agent-wait" }]);
6179
- processSubagentSystemMessage(nestedSession, {
6188
+ const waitStructured = (subtype, extra) => processSubagentSystemMessage(nestedSession, {
6180
6189
  type: "system",
6181
- subtype: "task_notification",
6190
+ subtype,
6182
6191
  task_id: "agent-wait",
6183
- status: "completed",
6192
+ ...extra,
6184
6193
  });
6194
+ const waitXml = (runId) => finishNotifiedSubagents(nestedSession, taskNotifications({
6195
+ origin: { kind: "task-notification", runId },
6196
+ message: { content: [{ type: "text", text: "<task-notification><task-id>agent-wait</task-id><status>completed</status><summary>Agent \"general-purpose\" finished</summary></task-notification>" }] },
6197
+ }));
6198
+ const agentRow = { task_id: "agent-wait", task_type: "local_agent", description: "wait" };
6199
+ const shellRow = { task_id: "shell-wait", task_type: "local_bash", description: "sleep 300", parent_task_id: "agent-wait" };
6200
+ startSubagent(nestedSession, { id: "toolu_wait", input: { description: "대기", subagent_type: "general-purpose" } });
6201
+ keepBackgroundSubagent(nestedSession, "toolu_wait", { isAsync: true, agentId: "agent-wait" });
6202
+ waitStructured("task_started", { tool_use_id: "toolu_wait", task_type: "local_agent", is_backgrounded: true, run_id: "r1" });
6203
+ waitSnapshot([agentRow, shellRow]);
6204
+ waitStructured("task_updated", { patch: { status: "completed" } });
6205
+ waitStructured("task_notification", { status: "completed", run_id: "r1" });
6206
+ waitSnapshot([shellRow]);
6207
+ waitXml("r1");
6185
6208
  const waitingKept = nestedSession.subagents.has("toolu_wait");
6186
6209
  waitSnapshot([]);
6187
- if (!waitingKept || nestedSession.subagents.size !== 0) {
6188
- throw new Error(`Claude waiting subagent self-test failed: ${waitingKept} ${nestedSession.subagents.size}`);
6210
+ const settledAfterChild = !nestedSession.subagents.has("toolu_wait");
6211
+ waitStructured("task_started", { task_type: "local_agent", is_backgrounded: true, run_id: "r2" });
6212
+ waitXml("r1");
6213
+ const keptAgainstLate = nestedSession.subagents.has("toolu_wait");
6214
+ waitStructured("task_notification", { status: "completed", run_id: "r2" });
6215
+ if (!waitingKept || !settledAfterChild || !keptAgainstLate || nestedSession.subagents.size !== 0) {
6216
+ throw new Error(`Claude waiting subagent self-test failed: ${waitingKept} ${settledAfterChild} ${keptAgainstLate} ${nestedSession.subagents.size}`);
6189
6217
  }
6190
6218
  clearSubagents(nestedSession);
6191
6219
  // 끝난 뒤 SDK가 같은 작업을 다시 돌리면 설명 없는 새 줄이 아니라 같은 줄로 돌아온다.
6192
6220
  startSubagent(nestedSession, { id: "toolu_again", input: { description: "3분 대기", subagent_type: "general-purpose" } });
6193
6221
  keepBackgroundSubagent(nestedSession, "toolu_again", { isAsync: true, agentId: "agent-again" });
6222
+ // 진행 요약이 설명을 바꿔도 다시 실행된 줄은 호출 설명으로 돌아온다.
6223
+ for (let tick = 0; tick < 2; tick += 1) {
6224
+ processSubagentSystemMessage(nestedSession, {
6225
+ type: "system",
6226
+ subtype: "task_progress",
6227
+ task_id: "agent-again",
6228
+ summary: "로그를 살피는 중",
6229
+ });
6230
+ }
6194
6231
  waitSnapshot([]);
6195
6232
  processSubagentSystemMessage(nestedSession, {
6196
6233
  type: "system",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "devez-vibe",
3
- "version": "1.9.58",
3
+ "version": "1.9.59",
4
4
  "type": "module",
5
5
  "description": "Stable terminal UI for Codex and Claude Agent SDK",
6
6
  "keywords": [