devez-vibe 1.2.17 → 1.2.19
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 +124 -26
- package/package.json +1 -1
package/bin/dvz.exe
CHANGED
|
Binary file
|
|
@@ -884,7 +884,25 @@ function prepareTaskPlanForCreate(tasks, subject) {
|
|
|
884
884
|
if (numberedTaskIndex(subject) === 1) tasks.clear();
|
|
885
885
|
}
|
|
886
886
|
|
|
887
|
-
|
|
887
|
+
// 한 단계에 걸린 시간은 진행 중으로 바뀐 순간과 완료된 순간의 차이다. 기록에는
|
|
888
|
+
// 항목마다 시각이 남으므로, 다시 읽을 때도 같은 방식으로 되살릴 수 있다.
|
|
889
|
+
function markTaskStatus(task, status, at) {
|
|
890
|
+
if (task.status !== status && at != null) {
|
|
891
|
+
if (status === "in_progress") {
|
|
892
|
+
task.startedAt = task.startedAt ?? at;
|
|
893
|
+
} else if (status === "completed" && task.startedAt != null) {
|
|
894
|
+
task.elapsedMs = Math.max(0, at - task.startedAt);
|
|
895
|
+
}
|
|
896
|
+
}
|
|
897
|
+
task.status = status;
|
|
898
|
+
}
|
|
899
|
+
|
|
900
|
+
function messageTime(message) {
|
|
901
|
+
const parsed = Date.parse(message?.timestamp || "");
|
|
902
|
+
return Number.isNaN(parsed) ? null : parsed;
|
|
903
|
+
}
|
|
904
|
+
|
|
905
|
+
function applyTaskUpdate(tasks, input, turnId, onIntermediate, at) {
|
|
888
906
|
const task = tasks.get(String(input.taskId));
|
|
889
907
|
if (!task) return false;
|
|
890
908
|
if (input.subject) task.subject = input.subject;
|
|
@@ -900,11 +918,11 @@ function applyTaskUpdate(tasks, input, turnId, onIntermediate) {
|
|
|
900
918
|
const previous = entries[index];
|
|
901
919
|
if (previous.status === "completed") continue;
|
|
902
920
|
if (previous.status !== "in_progress") {
|
|
903
|
-
previous
|
|
921
|
+
markTaskStatus(previous, "in_progress", at);
|
|
904
922
|
previous.turnId = turnId;
|
|
905
923
|
onIntermediate?.();
|
|
906
924
|
}
|
|
907
|
-
previous
|
|
925
|
+
markTaskStatus(previous, "completed", at);
|
|
908
926
|
previous.turnId = turnId;
|
|
909
927
|
onIntermediate?.();
|
|
910
928
|
}
|
|
@@ -912,19 +930,19 @@ function applyTaskUpdate(tasks, input, turnId, onIntermediate) {
|
|
|
912
930
|
for (let index = 0; index < entries.length; index++) {
|
|
913
931
|
const other = entries[index];
|
|
914
932
|
if (other === task || other.status !== "in_progress") continue;
|
|
915
|
-
other
|
|
933
|
+
markTaskStatus(other, index < targetIndex ? "completed" : "pending", at);
|
|
916
934
|
other.turnId = turnId;
|
|
917
935
|
onIntermediate?.();
|
|
918
936
|
}
|
|
919
937
|
|
|
920
938
|
if (status === "completed" && task.status !== "in_progress" && task.status !== "completed") {
|
|
921
|
-
task
|
|
939
|
+
markTaskStatus(task, "in_progress", at);
|
|
922
940
|
task.turnId = turnId;
|
|
923
941
|
onIntermediate?.();
|
|
924
942
|
}
|
|
925
|
-
task
|
|
943
|
+
markTaskStatus(task, status, at);
|
|
926
944
|
} else if (status) {
|
|
927
|
-
task
|
|
945
|
+
markTaskStatus(task, status, at);
|
|
928
946
|
}
|
|
929
947
|
task.turnId = turnId;
|
|
930
948
|
return true;
|
|
@@ -955,7 +973,7 @@ function updatePlanFromToolUse(session, name, toolUseId, input) {
|
|
|
955
973
|
return;
|
|
956
974
|
} else if (name === "TaskUpdate") {
|
|
957
975
|
session.planCreatePending = false;
|
|
958
|
-
applyTaskUpdate(session.tasks, input, turnId, () => emitPlan(session));
|
|
976
|
+
applyTaskUpdate(session.tasks, input, turnId, () => emitPlan(session), Date.now());
|
|
959
977
|
}
|
|
960
978
|
if (name === "TaskUpdate") emitPlan(session);
|
|
961
979
|
}
|
|
@@ -1559,14 +1577,20 @@ function historyState(messages) {
|
|
|
1559
1577
|
continue;
|
|
1560
1578
|
}
|
|
1561
1579
|
turn.synthetic = false;
|
|
1562
|
-
if (!turn.model && message.message?.model) {
|
|
1563
|
-
turn.model = visibleModel(message.message.model);
|
|
1564
|
-
const prompt = turn.items.find((item) => item.type === "userMessage");
|
|
1565
|
-
if (prompt) prompt.model = turn.model;
|
|
1566
|
-
}
|
|
1567
|
-
|
|
1568
|
-
|
|
1569
|
-
|
|
1580
|
+
if (!turn.model && message.message?.model) {
|
|
1581
|
+
turn.model = visibleModel(message.message.model);
|
|
1582
|
+
const prompt = turn.items.find((item) => item.type === "userMessage");
|
|
1583
|
+
if (prompt) prompt.model = turn.model;
|
|
1584
|
+
}
|
|
1585
|
+
const prompt = turn.items.find((item) => item.type === "userMessage");
|
|
1586
|
+
const historyTurn = { koreanRequest: isKoreanPrompt(prompt?.content) };
|
|
1587
|
+
for (const block of blocks) {
|
|
1588
|
+
if (block.type === "text") {
|
|
1589
|
+
const visible = normalizeProgressText(historyTurn, block.text);
|
|
1590
|
+
if (!visible.trim() && String(block.text || "").trim()) continue;
|
|
1591
|
+
turn.items.push({ id: `${message.uuid}-text`, type: "agentMessage", text: visible, provider: "Claude" });
|
|
1592
|
+
}
|
|
1593
|
+
else if (block.type === "thinking") turn.items.push({ id: `${message.uuid}-thinking`, type: "reasoning", summary: [block.thinking || ""] });
|
|
1570
1594
|
else if (block.type === "tool_use") {
|
|
1571
1595
|
const pending = { name: block.name, input: block.input || {}, item: toolItem({}, block.id, block.name, block.input || {}) };
|
|
1572
1596
|
tools.set(block.id, pending);
|
|
@@ -1574,7 +1598,7 @@ function historyState(messages) {
|
|
|
1574
1598
|
prepareTaskPlanForCreate(tasks, block.input?.subject);
|
|
1575
1599
|
tasks.set(`pending:${block.id}`, { id: `pending:${block.id}`, subject: block.input?.subject || "작업", status: "pending", turnId: turn.id });
|
|
1576
1600
|
} else if (block.name === "TaskUpdate") {
|
|
1577
|
-
applyTaskUpdate(tasks, block.input || {}, turn.id);
|
|
1601
|
+
applyTaskUpdate(tasks, block.input || {}, turn.id, undefined, messageTime(message));
|
|
1578
1602
|
} else if (!["TaskList", "AskUserQuestion"].includes(block.name)) turn.items.push(pending.item);
|
|
1579
1603
|
}
|
|
1580
1604
|
}
|
|
@@ -1594,7 +1618,19 @@ function historyState(messages) {
|
|
|
1594
1618
|
} else if (pending.name === "TaskList" && Array.isArray(message.tool_use_result?.tasks)) {
|
|
1595
1619
|
const known = new Map(tasks);
|
|
1596
1620
|
tasks.clear();
|
|
1597
|
-
for (const task of message.tool_use_result.tasks)
|
|
1621
|
+
for (const task of message.tool_use_result.tasks) {
|
|
1622
|
+
const previous = known.get(String(task.id));
|
|
1623
|
+
tasks.set(String(task.id), {
|
|
1624
|
+
id: String(task.id),
|
|
1625
|
+
subject: task.subject || "작업",
|
|
1626
|
+
status: task.status || "pending",
|
|
1627
|
+
turnId: previous?.turnId ?? turn.id,
|
|
1628
|
+
// A listing restates the plan; it does not re-run it, so the
|
|
1629
|
+
// timings already measured for these steps have to survive it.
|
|
1630
|
+
startedAt: previous?.startedAt,
|
|
1631
|
+
elapsedMs: previous?.elapsedMs,
|
|
1632
|
+
});
|
|
1633
|
+
}
|
|
1598
1634
|
const current = latestTaskPlan(tasks);
|
|
1599
1635
|
tasks.clear();
|
|
1600
1636
|
for (const [id, task] of current) tasks.set(id, task);
|
|
@@ -1611,7 +1647,14 @@ function historyState(messages) {
|
|
|
1611
1647
|
}
|
|
1612
1648
|
if (turn && tasks.size) {
|
|
1613
1649
|
const text = [...tasks.values()].map((task, index) => `${task.status === "completed" ? "✓" : task.status === "in_progress" ? "▸" : "□"} ${numberedTaskSubject(task.subject, index)}`).join("\n");
|
|
1614
|
-
|
|
1650
|
+
// The text alone cannot say how long a step took, so the measured times ride
|
|
1651
|
+
// alongside it and the restored plan shows its total instead of zero.
|
|
1652
|
+
const steps = [...tasks.values()].map((task, index) => ({
|
|
1653
|
+
step: numberedTaskSubject(task.subject, index),
|
|
1654
|
+
status: task.status || "pending",
|
|
1655
|
+
elapsedMs: task.elapsedMs ?? null,
|
|
1656
|
+
}));
|
|
1657
|
+
turn.items.push({ id: "claude-plan-latest", type: "plan", text, steps });
|
|
1615
1658
|
}
|
|
1616
1659
|
return {
|
|
1617
1660
|
tasks,
|
|
@@ -1900,13 +1943,54 @@ async function runSelfTest() {
|
|
|
1900
1943
|
content: [{ type: "tool_use", id, name, input }],
|
|
1901
1944
|
},
|
|
1902
1945
|
});
|
|
1903
|
-
const taskResult = (uuid, id, toolUseResult, content) => ({
|
|
1904
|
-
type: "user",
|
|
1905
|
-
uuid,
|
|
1906
|
-
message: { role: "user", content: [{ type: "tool_result", tool_use_id: id, content }] },
|
|
1907
|
-
tool_use_result: toolUseResult,
|
|
1908
|
-
});
|
|
1909
|
-
const
|
|
1946
|
+
const taskResult = (uuid, id, toolUseResult, content) => ({
|
|
1947
|
+
type: "user",
|
|
1948
|
+
uuid,
|
|
1949
|
+
message: { role: "user", content: [{ type: "tool_result", tool_use_id: id, content }] },
|
|
1950
|
+
tool_use_result: toolUseResult,
|
|
1951
|
+
});
|
|
1952
|
+
const resumedProgress = historyTurns([
|
|
1953
|
+
user("progress-user", "환자 변경 동기화를 수정해"),
|
|
1954
|
+
{
|
|
1955
|
+
type: "assistant",
|
|
1956
|
+
uuid: "progress-assistant",
|
|
1957
|
+
message: {
|
|
1958
|
+
role: "assistant",
|
|
1959
|
+
model: "claude-opus-5",
|
|
1960
|
+
content: [
|
|
1961
|
+
{ type: "text", text: "Now hook the patient-change event in CvForm." },
|
|
1962
|
+
{ type: "tool_use", id: "progress-read", name: "Read", input: { file_path: "CvForm.cs" } },
|
|
1963
|
+
],
|
|
1964
|
+
},
|
|
1965
|
+
},
|
|
1966
|
+
taskResult("progress-result", "progress-read", { content: "ok" }, "ok"),
|
|
1967
|
+
{
|
|
1968
|
+
type: "assistant",
|
|
1969
|
+
uuid: "progress-assistant-2",
|
|
1970
|
+
message: {
|
|
1971
|
+
role: "assistant",
|
|
1972
|
+
model: "claude-opus-5",
|
|
1973
|
+
content: [
|
|
1974
|
+
{ type: "text", text: "Now the Lab-side receiver." },
|
|
1975
|
+
{ type: "tool_use", id: "progress-read-2", name: "Read", input: { file_path: "LabReceiver.cs" } },
|
|
1976
|
+
],
|
|
1977
|
+
},
|
|
1978
|
+
},
|
|
1979
|
+
taskResult("progress-result-2", "progress-read-2", { content: "ok" }, "ok"),
|
|
1980
|
+
assistant("progress-final", "claude-opus-5", "환자 변경 동기화를 수정했습니다."),
|
|
1981
|
+
]);
|
|
1982
|
+
const resumedProgressText = resumedProgress[0]?.items
|
|
1983
|
+
.filter((item) => item.type === "agentMessage")
|
|
1984
|
+
.map((item) => item.text);
|
|
1985
|
+
const englishNowText = historyTurns([
|
|
1986
|
+
user("english-user", "Start the answer with Now"),
|
|
1987
|
+
assistant("english-assistant", "claude-opus-5", "Now the answer starts."),
|
|
1988
|
+
])[0]?.items.find((item) => item.type === "agentMessage")?.text;
|
|
1989
|
+
if (JSON.stringify(resumedProgressText) !== JSON.stringify(["환자 변경 동기화를 수정했습니다."])
|
|
1990
|
+
|| englishNowText !== "Now the answer starts.") {
|
|
1991
|
+
throw new Error(`Claude resumed progress normalization self-test failed: ${JSON.stringify({ resumedProgressText, englishNowText })}`);
|
|
1992
|
+
}
|
|
1993
|
+
const taskMessages = [user("plan", "작업을 진행해")];
|
|
1910
1994
|
for (let index = 1; index <= 6; index++) {
|
|
1911
1995
|
const id = String(24 + index);
|
|
1912
1996
|
const toolId = `create-${id}`;
|
|
@@ -1937,6 +2021,20 @@ async function runSelfTest() {
|
|
|
1937
2021
|
|| [...restoredTasks.values()].filter((task) => task.status === "in_progress").length !== 1) {
|
|
1938
2022
|
throw new Error(`Claude sequential task update self-test failed: ${JSON.stringify([...restoredTasks])}`);
|
|
1939
2023
|
}
|
|
2024
|
+
// Each transcript record is stamped, so a step's own run is the span between
|
|
2025
|
+
// the update that started it and the one that closed it.
|
|
2026
|
+
const at = (message, timestamp) => ({ ...message, timestamp });
|
|
2027
|
+
const timedMessages = [
|
|
2028
|
+
at(user("timed", "작업을 진행해"), "2026-08-07T01:00:00.000Z"),
|
|
2029
|
+
at(taskUse("timed-create-use", "timed-create", "TaskCreate", { subject: "1. 확인" }), "2026-08-07T01:00:01.000Z"),
|
|
2030
|
+
at(taskResult("timed-create-result", "timed-create", { task: { id: "t1", subject: "1. 확인" } }, "Task #t1 created successfully: 1. 확인"), "2026-08-07T01:00:02.000Z"),
|
|
2031
|
+
at(taskUse("timed-start", "timed-start", "TaskUpdate", { taskId: "t1", status: "in_progress" }), "2026-08-07T01:00:03.000Z"),
|
|
2032
|
+
at(taskUse("timed-done", "timed-done", "TaskUpdate", { taskId: "t1", status: "completed" }), "2026-08-07T01:00:09.000Z"),
|
|
2033
|
+
];
|
|
2034
|
+
const timedPlan = historyState(timedMessages).turns.at(-1)?.items.find((item) => item.type === "plan");
|
|
2035
|
+
if (timedPlan?.steps?.[0]?.elapsedMs !== 6000 || timedPlan.steps[0].status !== "completed") {
|
|
2036
|
+
throw new Error(`Claude plan step timing self-test failed: ${JSON.stringify(timedPlan)}`);
|
|
2037
|
+
}
|
|
1940
2038
|
const skippedTasks = new Map([
|
|
1941
2039
|
["1", { id: "1", subject: "1. 조사", status: "pending" }],
|
|
1942
2040
|
["2", { id: "2", subject: "2. 분석", status: "pending" }],
|