devez-vibe 1.2.9 → 1.2.10
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 +0 -0
- package/bridge/claude-agent-sdk-bridge.mjs +110 -40
- package/package.json +1 -1
package/bin/dvz.exe
CHANGED
|
Binary file
|
|
@@ -438,9 +438,10 @@ async function createSession(params, resumeId) {
|
|
|
438
438
|
turnSequence: 1,
|
|
439
439
|
itemSequence: 1,
|
|
440
440
|
streamBlocks: new Map(),
|
|
441
|
-
tools: new Map(),
|
|
442
|
-
tasks: new Map(),
|
|
443
|
-
|
|
441
|
+
tools: new Map(),
|
|
442
|
+
tasks: new Map(),
|
|
443
|
+
planCreatePending: false,
|
|
444
|
+
subagents: new Map(),
|
|
444
445
|
knownSubagents: new Map(),
|
|
445
446
|
lastContextUsage: null,
|
|
446
447
|
lastContextWindow: 0,
|
|
@@ -546,7 +547,7 @@ function emitOpeningNotice(session) {
|
|
|
546
547
|
// Windows rounds larger timer delays up to the next scheduler slice. Ten
|
|
547
548
|
// milliseconds lands near one terminal frame instead of visibly stepping at ~30ms.
|
|
548
549
|
const SMOOTH_TEXT_INTERVAL_MS = 10;
|
|
549
|
-
const SMOOTH_TEXT_TARGET_FRAMES =
|
|
550
|
+
const SMOOTH_TEXT_TARGET_FRAMES = 10;
|
|
550
551
|
const SMOOTH_TEXT_MAX_GRAPHEMES = 24;
|
|
551
552
|
const graphemeSegmenter = typeof Intl.Segmenter === "function"
|
|
552
553
|
? new Intl.Segmenter(undefined, { granularity: "grapheme" })
|
|
@@ -581,10 +582,21 @@ class SmoothTextStream {
|
|
|
581
582
|
this.waiters = [];
|
|
582
583
|
}
|
|
583
584
|
|
|
584
|
-
push(text) {
|
|
585
|
-
this.pending += text;
|
|
586
|
-
|
|
587
|
-
}
|
|
585
|
+
push(text) {
|
|
586
|
+
this.pending += text;
|
|
587
|
+
this.schedule();
|
|
588
|
+
}
|
|
589
|
+
|
|
590
|
+
schedule() {
|
|
591
|
+
if (this.timer != null) return;
|
|
592
|
+
// Wait one visual frame before the first drain. Claude often sends several
|
|
593
|
+
// tiny deltas back-to-back; batching them removes the uneven one-character
|
|
594
|
+
// jumps while keeping added latency below one frame.
|
|
595
|
+
this.timer = setTimeout(() => {
|
|
596
|
+
this.timer = null;
|
|
597
|
+
this.drain();
|
|
598
|
+
}, this.intervalMs);
|
|
599
|
+
}
|
|
588
600
|
|
|
589
601
|
drain() {
|
|
590
602
|
if (!this.pending) {
|
|
@@ -593,14 +605,13 @@ class SmoothTextStream {
|
|
|
593
605
|
return;
|
|
594
606
|
}
|
|
595
607
|
const { chunk, rest } = takeSmoothTextChunk(this.pending);
|
|
596
|
-
this.pending = rest;
|
|
597
|
-
this.emit(chunk);
|
|
598
|
-
if (this.pending) {
|
|
599
|
-
this.
|
|
600
|
-
} else {
|
|
601
|
-
this.
|
|
602
|
-
|
|
603
|
-
}
|
|
608
|
+
this.pending = rest;
|
|
609
|
+
this.emit(chunk);
|
|
610
|
+
if (this.pending) {
|
|
611
|
+
this.schedule();
|
|
612
|
+
} else {
|
|
613
|
+
for (const resolve of this.waiters.splice(0)) resolve();
|
|
614
|
+
}
|
|
604
615
|
}
|
|
605
616
|
|
|
606
617
|
finish() {
|
|
@@ -780,7 +791,7 @@ function processAssistant(session, message) {
|
|
|
780
791
|
}
|
|
781
792
|
}
|
|
782
793
|
|
|
783
|
-
function processToolUse(session, block) {
|
|
794
|
+
function processToolUse(session, block) {
|
|
784
795
|
const name = block.name || "Tool";
|
|
785
796
|
const input = block.input || {};
|
|
786
797
|
if (name === "TaskCreate" || name === "TaskUpdate" || name === "TaskList") {
|
|
@@ -788,11 +799,13 @@ function processToolUse(session, block) {
|
|
|
788
799
|
session.tools.set(block.id, { name, input, suppressed: true });
|
|
789
800
|
return;
|
|
790
801
|
}
|
|
791
|
-
if (name === "AskUserQuestion") {
|
|
792
|
-
session
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
802
|
+
if (name === "AskUserQuestion") {
|
|
803
|
+
flushPendingPlan(session);
|
|
804
|
+
session.tools.set(block.id, { name, input, suppressed: true });
|
|
805
|
+
return;
|
|
806
|
+
}
|
|
807
|
+
flushPendingPlan(session);
|
|
808
|
+
const item = toolItem(session, block.id, name, input);
|
|
796
809
|
session.tools.set(block.id, { name, input, item });
|
|
797
810
|
emitItem(session, "started", item);
|
|
798
811
|
if (SUBAGENT_TOOLS.includes(name)) startSubagent(session, block);
|
|
@@ -898,21 +911,30 @@ function latestTaskPlan(tasks) {
|
|
|
898
911
|
return new Map(entries.slice(start));
|
|
899
912
|
}
|
|
900
913
|
|
|
901
|
-
function updatePlanFromToolUse(session, name, toolUseId, input) {
|
|
914
|
+
function updatePlanFromToolUse(session, name, toolUseId, input) {
|
|
902
915
|
const turnId = session.turn?.id;
|
|
903
916
|
if (name === "TaskCreate") {
|
|
904
917
|
prepareTaskPlanForCreate(session.tasks, input.subject);
|
|
905
|
-
session.tasks.set(`pending:${toolUseId}`, {
|
|
918
|
+
session.tasks.set(`pending:${toolUseId}`, {
|
|
906
919
|
id: `pending:${toolUseId}`,
|
|
907
920
|
subject: input.subject || input.description || "작업",
|
|
908
921
|
status: "pending",
|
|
909
|
-
turnId,
|
|
910
|
-
});
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
}
|
|
914
|
-
|
|
915
|
-
|
|
922
|
+
turnId,
|
|
923
|
+
});
|
|
924
|
+
session.planCreatePending = true;
|
|
925
|
+
return;
|
|
926
|
+
} else if (name === "TaskUpdate") {
|
|
927
|
+
session.planCreatePending = false;
|
|
928
|
+
applyTaskUpdate(session.tasks, input, turnId, () => emitPlan(session));
|
|
929
|
+
}
|
|
930
|
+
if (name === "TaskUpdate") emitPlan(session);
|
|
931
|
+
}
|
|
932
|
+
|
|
933
|
+
function flushPendingPlan(session) {
|
|
934
|
+
if (!session.planCreatePending) return;
|
|
935
|
+
session.planCreatePending = false;
|
|
936
|
+
emitPlan(session);
|
|
937
|
+
}
|
|
916
938
|
|
|
917
939
|
function updatePlanFromToolResult(session, pending, message) {
|
|
918
940
|
const value = message.tool_use_result;
|
|
@@ -1325,8 +1347,9 @@ async function runPendingPrompt(session) {
|
|
|
1325
1347
|
}
|
|
1326
1348
|
}
|
|
1327
1349
|
|
|
1328
|
-
function finishTurn(session, error, durationMs) {
|
|
1329
|
-
if (!session.turn) return;
|
|
1350
|
+
function finishTurn(session, error, durationMs) {
|
|
1351
|
+
if (!session.turn) return;
|
|
1352
|
+
flushPendingPlan(session);
|
|
1330
1353
|
flushSmoothStreams(session);
|
|
1331
1354
|
clearForegroundSubagents(session);
|
|
1332
1355
|
const turn = { id: session.turn.id, status: error ? "failed" : "completed" };
|
|
@@ -1913,9 +1936,53 @@ async function runSelfTest() {
|
|
|
1913
1936
|
}
|
|
1914
1937
|
prepareTaskPlanForCreate(restoredTasks, "7. 추가 작업");
|
|
1915
1938
|
if (restoredTasks.size !== 6) throw new Error("Claude appended task unexpectedly reset the plan");
|
|
1916
|
-
prepareTaskPlanForCreate(restoredTasks, "1. 새 작업");
|
|
1917
|
-
if (restoredTasks.size !== 0) throw new Error("Claude new task plan did not reset the previous plan");
|
|
1918
|
-
const
|
|
1939
|
+
prepareTaskPlanForCreate(restoredTasks, "1. 새 작업");
|
|
1940
|
+
if (restoredTasks.size !== 0) throw new Error("Claude new task plan did not reset the previous plan");
|
|
1941
|
+
const batchedPlanSession = {
|
|
1942
|
+
id: "batched-plan-self-test",
|
|
1943
|
+
turn: { id: "batched-plan-turn" },
|
|
1944
|
+
tasks: new Map(),
|
|
1945
|
+
planCreatePending: false,
|
|
1946
|
+
};
|
|
1947
|
+
const batchedPlanCaptured = [];
|
|
1948
|
+
const batchedPlanWrite = process.stdout.write;
|
|
1949
|
+
process.stdout.write = (chunk) => {
|
|
1950
|
+
batchedPlanCaptured.push(String(chunk));
|
|
1951
|
+
return true;
|
|
1952
|
+
};
|
|
1953
|
+
try {
|
|
1954
|
+
for (let index = 1; index <= 3; index++) {
|
|
1955
|
+
const toolUseId = `batched-create-${index}`;
|
|
1956
|
+
const subject = `${index}. 작업 ${index}`;
|
|
1957
|
+
updatePlanFromToolUse(batchedPlanSession, "TaskCreate", toolUseId, { subject });
|
|
1958
|
+
updatePlanFromToolResult(
|
|
1959
|
+
batchedPlanSession,
|
|
1960
|
+
{ name: "TaskCreate", toolUseId },
|
|
1961
|
+
{ tool_use_result: { task: { id: String(index), subject } } },
|
|
1962
|
+
);
|
|
1963
|
+
}
|
|
1964
|
+
updatePlanFromToolUse(
|
|
1965
|
+
batchedPlanSession,
|
|
1966
|
+
"TaskUpdate",
|
|
1967
|
+
"batched-update-1",
|
|
1968
|
+
{ taskId: "1", status: "in_progress" },
|
|
1969
|
+
);
|
|
1970
|
+
} finally {
|
|
1971
|
+
process.stdout.write = batchedPlanWrite;
|
|
1972
|
+
}
|
|
1973
|
+
const batchedPlanEvents = batchedPlanCaptured
|
|
1974
|
+
.join("")
|
|
1975
|
+
.trim()
|
|
1976
|
+
.split("\n")
|
|
1977
|
+
.filter(Boolean)
|
|
1978
|
+
.map((line) => JSON.parse(line))
|
|
1979
|
+
.filter((event) => event.method === "turn/plan/updated");
|
|
1980
|
+
if (batchedPlanEvents.length !== 1
|
|
1981
|
+
|| batchedPlanEvents[0].params?.plan?.length !== 3
|
|
1982
|
+
|| batchedPlanEvents[0].params.plan[0]?.status !== "inProgress") {
|
|
1983
|
+
throw new Error(`Claude batched plan self-test failed: ${JSON.stringify(batchedPlanEvents)}`);
|
|
1984
|
+
}
|
|
1985
|
+
const usage = tokenBreakdown({
|
|
1919
1986
|
input_tokens: 2,
|
|
1920
1987
|
cache_read_input_tokens: 68_000,
|
|
1921
1988
|
cache_creation_input_tokens: 500,
|
|
@@ -2127,10 +2194,13 @@ async function runSelfTest() {
|
|
|
2127
2194
|
throw new Error(`Claude Korean progress normalization self-test failed: ${JSON.stringify(languageEvents)}`);
|
|
2128
2195
|
}
|
|
2129
2196
|
const smoothText = "Claude가 👨👩👧👦 한 문장을 한꺼번에 보내도 부드럽게 표시합니다.";
|
|
2130
|
-
const emitted = [];
|
|
2131
|
-
const smooth = new SmoothTextStream((chunk) => emitted.push(chunk), 0);
|
|
2132
|
-
smooth.push(smoothText);
|
|
2133
|
-
|
|
2197
|
+
const emitted = [];
|
|
2198
|
+
const smooth = new SmoothTextStream((chunk) => emitted.push(chunk), 0);
|
|
2199
|
+
smooth.push(smoothText);
|
|
2200
|
+
if (emitted.length !== 0) {
|
|
2201
|
+
throw new Error(`Claude smooth stream did not batch its first frame: ${JSON.stringify(emitted)}`);
|
|
2202
|
+
}
|
|
2203
|
+
await smooth.finish();
|
|
2134
2204
|
if (emitted.length < 2 || emitted.join("") !== smoothText) {
|
|
2135
2205
|
throw new Error(`Claude smooth stream self-test failed: ${JSON.stringify(emitted)}`);
|
|
2136
2206
|
}
|