devez-vibe 1.6.36 → 1.6.37
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 +216 -124
- package/package.json +41 -41
package/bin/dvz.exe
CHANGED
|
Binary file
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
import { randomUUID } from "node:crypto";
|
|
4
4
|
import { spawn } from "node:child_process";
|
|
5
5
|
import { createReadStream, existsSync, readdirSync } from "node:fs";
|
|
6
|
-
import { mkdir, readdir, readFile, stat, writeFile } from "node:fs/promises";
|
|
6
|
+
import { mkdir, readdir, readFile, stat, writeFile } from "node:fs/promises";
|
|
7
7
|
import { homedir } from "node:os";
|
|
8
8
|
import { dirname, join } from "node:path";
|
|
9
9
|
import { createInterface } from "node:readline";
|
|
@@ -29,6 +29,7 @@ const modelCatalogs = new Map();
|
|
|
29
29
|
const CLAUDE_MODEL_ORDER = ["fable", "opus", "sonnet", "haiku"];
|
|
30
30
|
const OPUS_48_MODEL = "claude-opus-4-8";
|
|
31
31
|
const CLAUDE_EFFORT_LEVELS = ["low", "medium", "high", "xhigh", "max"];
|
|
32
|
+
const CLAUDE_TASK_TOOLS = ["TaskCreate", "TaskGet", "TaskUpdate", "TaskList"];
|
|
32
33
|
let nextHostRequest = 1;
|
|
33
34
|
|
|
34
35
|
class AsyncQueue {
|
|
@@ -575,6 +576,12 @@ function makeOptions(params, sessionId, resume) {
|
|
|
575
576
|
},
|
|
576
577
|
skills: "all",
|
|
577
578
|
tools: { type: "preset", preset: "claude_code" },
|
|
579
|
+
// Task tools left the default surface in SDK 0.3.233. Listing them here
|
|
580
|
+
// keeps the plan panel available without replacing the Claude Code preset.
|
|
581
|
+
allowedTools: [...CLAUDE_TASK_TOOLS],
|
|
582
|
+
// DevezVibe keeps per-task controls available through Claude's TaskStop
|
|
583
|
+
// tool, so a turn interrupt must not tear down independent background work.
|
|
584
|
+
perTaskStopAffordance: true,
|
|
578
585
|
systemPrompt: {
|
|
579
586
|
type: "preset",
|
|
580
587
|
preset: "claude_code",
|
|
@@ -662,6 +669,13 @@ async function requestToolPermission(toolName, input, permission) {
|
|
|
662
669
|
return { behavior: "deny", message: questionFallbackMessage(questions) };
|
|
663
670
|
}
|
|
664
671
|
}
|
|
672
|
+
// Esc on the host cancels the question outright. Claude Code stops the turn
|
|
673
|
+
// there, so the tool must not be handed an empty answer set: that reads as a
|
|
674
|
+
// successful call and the model keeps talking about a question nobody
|
|
675
|
+
// answered. The host sends its own interrupt right behind this reply.
|
|
676
|
+
if (response?.cancelled) {
|
|
677
|
+
return { behavior: "deny", message: "사용자가 질문을 취소하고 작업을 중단했습니다." };
|
|
678
|
+
}
|
|
665
679
|
const answers = {};
|
|
666
680
|
for (let index = 0; index < questions.length; index += 1) {
|
|
667
681
|
const selected = response?.answers?.[`q${index}`]?.answers;
|
|
@@ -1062,6 +1076,7 @@ async function createSession(params, resumeId) {
|
|
|
1062
1076
|
subagents: new Map(),
|
|
1063
1077
|
knownSubagents: new Map(),
|
|
1064
1078
|
hiddenSubagentTasks: new Set(),
|
|
1079
|
+
ambientSubagentTasks: new Set(),
|
|
1065
1080
|
subagentPulse: null,
|
|
1066
1081
|
lastContextUsage: null,
|
|
1067
1082
|
lastContextWindow: 0,
|
|
@@ -1359,7 +1374,7 @@ function processAssistant(session, message) {
|
|
|
1359
1374
|
function processToolUse(session, block) {
|
|
1360
1375
|
const name = block.name || "Tool";
|
|
1361
1376
|
const input = block.input || {};
|
|
1362
|
-
if (name
|
|
1377
|
+
if (CLAUDE_TASK_TOOLS.includes(name)) {
|
|
1363
1378
|
updatePlanFromToolUse(session, name, block.id, input);
|
|
1364
1379
|
session.tools.set(block.id, { name, input, suppressed: true });
|
|
1365
1380
|
return;
|
|
@@ -1689,7 +1704,8 @@ function upsertStructuredSubagent(session, message) {
|
|
|
1689
1704
|
const taskId = firstLine(message.task_id || "", 80);
|
|
1690
1705
|
const toolUseId = firstLine(message.tool_use_id || "", 80);
|
|
1691
1706
|
const subagentType = firstLine(message.subagent_type || "", 40);
|
|
1692
|
-
if (taskId && session.hiddenSubagentTasks?.has(taskId)
|
|
1707
|
+
if (taskId && (session.hiddenSubagentTasks?.has(taskId)
|
|
1708
|
+
|| session.ambientSubagentTasks?.has(taskId))) return null;
|
|
1693
1709
|
const byTool = toolUseId && findSubagent(session, toolUseId);
|
|
1694
1710
|
const byTask = taskId && findSubagent(session, taskId);
|
|
1695
1711
|
let running = byTool || byTask;
|
|
@@ -1743,7 +1759,13 @@ function upsertStructuredSubagent(session, message) {
|
|
|
1743
1759
|
function finishStructuredSubagent(session, message, kind, text) {
|
|
1744
1760
|
const taskId = firstLine(message.task_id || "", 80);
|
|
1745
1761
|
const toolUseId = firstLine(message.tool_use_id || "", 80);
|
|
1746
|
-
const
|
|
1762
|
+
const wasTranscriptHidden = taskId
|
|
1763
|
+
? session.hiddenSubagentTasks?.delete(taskId) === true
|
|
1764
|
+
: false;
|
|
1765
|
+
const wasAmbient = taskId
|
|
1766
|
+
? session.ambientSubagentTasks?.delete(taskId) === true
|
|
1767
|
+
: false;
|
|
1768
|
+
const wasHidden = wasTranscriptHidden || wasAmbient;
|
|
1747
1769
|
const running = (toolUseId && findSubagent(session, toolUseId))
|
|
1748
1770
|
|| (taskId && findSubagent(session, taskId));
|
|
1749
1771
|
if (!running) return wasHidden;
|
|
@@ -1754,13 +1776,24 @@ function finishStructuredSubagent(session, message, kind, text) {
|
|
|
1754
1776
|
}
|
|
1755
1777
|
|
|
1756
1778
|
function syncBackgroundSubagents(session, tasks) {
|
|
1757
|
-
const
|
|
1779
|
+
const snapshot = Array.isArray(tasks) ? tasks : [];
|
|
1780
|
+
session.ambientSubagentTasks = new Set(snapshot
|
|
1781
|
+
.filter((task) => task?.ambient === true)
|
|
1782
|
+
.map((task) => firstLine(task?.task_id || "", 80))
|
|
1783
|
+
.filter(Boolean));
|
|
1784
|
+
const live = snapshot.filter((task) => {
|
|
1758
1785
|
const taskId = firstLine(task?.task_id || "", 80);
|
|
1759
|
-
return
|
|
1786
|
+
return task?.ambient !== true
|
|
1787
|
+
&& (!taskId || !session.hiddenSubagentTasks?.has(taskId));
|
|
1760
1788
|
});
|
|
1761
1789
|
const liveIds = new Set(live.map((task) => firstLine(task?.task_id || "", 80)).filter(Boolean));
|
|
1762
1790
|
let changed = false;
|
|
1763
1791
|
for (const [id, running] of session.subagents) {
|
|
1792
|
+
if (running.taskId && session.ambientSubagentTasks.has(running.taskId)) {
|
|
1793
|
+
session.subagents.delete(id);
|
|
1794
|
+
changed = true;
|
|
1795
|
+
continue;
|
|
1796
|
+
}
|
|
1764
1797
|
if (!running.background || !running.taskId || liveIds.has(running.taskId)) continue;
|
|
1765
1798
|
session.subagents.delete(id);
|
|
1766
1799
|
changed = true;
|
|
@@ -1799,12 +1832,14 @@ function syncBackgroundSubagents(session, tasks) {
|
|
|
1799
1832
|
|
|
1800
1833
|
function processSubagentSystemMessage(session, message) {
|
|
1801
1834
|
if (message.subtype === "task_started") {
|
|
1802
|
-
if (message.skip_transcript === true) {
|
|
1835
|
+
if (message.skip_transcript === true || message.ambient === true) {
|
|
1803
1836
|
const taskId = firstLine(message.task_id || "", 80);
|
|
1804
1837
|
const toolUseId = firstLine(message.tool_use_id || "", 80);
|
|
1805
1838
|
if (taskId) {
|
|
1806
|
-
|
|
1807
|
-
|
|
1839
|
+
const hidden = message.ambient === true
|
|
1840
|
+
? (session.ambientSubagentTasks ||= new Set())
|
|
1841
|
+
: (session.hiddenSubagentTasks ||= new Set());
|
|
1842
|
+
hidden.add(taskId);
|
|
1808
1843
|
}
|
|
1809
1844
|
const running = (toolUseId && findSubagent(session, toolUseId))
|
|
1810
1845
|
|| (taskId && findSubagent(session, taskId));
|
|
@@ -1853,6 +1888,10 @@ function processSubagentSystemMessage(session, message) {
|
|
|
1853
1888
|
return true;
|
|
1854
1889
|
}
|
|
1855
1890
|
if (message.subtype === "task_notification") {
|
|
1891
|
+
if (message.ambient === true && message.task_id) {
|
|
1892
|
+
session.ambientSubagentTasks ||= new Set();
|
|
1893
|
+
session.ambientSubagentTasks.add(firstLine(message.task_id, 80));
|
|
1894
|
+
}
|
|
1856
1895
|
const status = firstLine(message.status || "completed", 40);
|
|
1857
1896
|
return finishStructuredSubagent(
|
|
1858
1897
|
session,
|
|
@@ -1961,6 +2000,7 @@ function clearSubagents(session) {
|
|
|
1961
2000
|
const changed = session.subagents.size > 0;
|
|
1962
2001
|
session.subagents.clear();
|
|
1963
2002
|
session.hiddenSubagentTasks?.clear();
|
|
2003
|
+
session.ambientSubagentTasks?.clear();
|
|
1964
2004
|
if (session.subagentPulse) {
|
|
1965
2005
|
clearInterval(session.subagentPulse);
|
|
1966
2006
|
session.subagentPulse = null;
|
|
@@ -2547,7 +2587,7 @@ function historyState(messages) {
|
|
|
2547
2587
|
tasks.set(`pending:${block.id}`, { id: `pending:${block.id}`, subject: block.input?.subject || "작업", status: "pending", turnId: turn.id });
|
|
2548
2588
|
} else if (block.name === "TaskUpdate") {
|
|
2549
2589
|
applyTaskUpdate(tasks, block.input || {}, turn.id, undefined, messageTime(message));
|
|
2550
|
-
} else if (!["TaskList", "AskUserQuestion"].includes(block.name)) turn.items.push(pending.item);
|
|
2590
|
+
} else if (!["TaskGet", "TaskList", "AskUserQuestion"].includes(block.name)) turn.items.push(pending.item);
|
|
2551
2591
|
}
|
|
2552
2592
|
}
|
|
2553
2593
|
} else if (message.type === "user") {
|
|
@@ -2681,101 +2721,101 @@ async function transcriptCwd(id) {
|
|
|
2681
2721
|
|
|
2682
2722
|
/** The cwd to read `id`'s transcript with: the one the transcript itself records,
|
|
2683
2723
|
* falling back to the host's when no transcript is on disk. */
|
|
2684
|
-
async function readableCwd(id, cwd) {
|
|
2685
|
-
return await transcriptCwd(id) || cwd;
|
|
2686
|
-
}
|
|
2687
|
-
|
|
2688
|
-
function sameCwd(left, right) {
|
|
2689
|
-
if (!left || !right) return !left && !right;
|
|
2690
|
-
const normalize = (value) => value.replaceAll("\\", "/").replace(/\/$/, "");
|
|
2691
|
-
const normalizedLeft = normalize(left);
|
|
2692
|
-
const normalizedRight = normalize(right);
|
|
2693
|
-
return process.platform === "win32"
|
|
2694
|
-
? normalizedLeft.toLowerCase() === normalizedRight.toLowerCase()
|
|
2695
|
-
: normalizedLeft === normalizedRight;
|
|
2696
|
-
}
|
|
2697
|
-
|
|
2698
|
-
function transcriptPreview(messages) {
|
|
2699
|
-
const prompt = historyTurns(messages)
|
|
2700
|
-
.flatMap((turn) => turn.items || [])
|
|
2701
|
-
.find((item) => item.type === "userMessage");
|
|
2702
|
-
return prompt?.content?.find((item) => item.type === "text")?.text || "Untitled Claude session";
|
|
2703
|
-
}
|
|
2704
|
-
|
|
2705
|
-
async function transcriptSessions(cwd) {
|
|
2706
|
-
if (!cwd) return [];
|
|
2707
|
-
let projects;
|
|
2708
|
-
try {
|
|
2709
|
-
projects = await readdir(claudeProjectsDir(), { withFileTypes: true });
|
|
2710
|
-
} catch {
|
|
2711
|
-
return [];
|
|
2712
|
-
}
|
|
2713
|
-
const rows = new Map();
|
|
2714
|
-
for (const project of projects) {
|
|
2715
|
-
if (!project.isDirectory()) continue;
|
|
2716
|
-
const dir = join(claudeProjectsDir(), project.name);
|
|
2717
|
-
let files;
|
|
2718
|
-
try {
|
|
2719
|
-
files = await readdir(dir, { withFileTypes: true });
|
|
2720
|
-
} catch {
|
|
2721
|
-
continue;
|
|
2722
|
-
}
|
|
2723
|
-
for (const file of files) {
|
|
2724
|
-
if (!file.isFile() || !/^[0-9a-f-]{36}\.jsonl$/i.test(file.name)) continue;
|
|
2725
|
-
const path = join(dir, file.name);
|
|
2726
|
-
let recordedCwd;
|
|
2727
|
-
try {
|
|
2728
|
-
recordedCwd = await readTranscriptCwd(path);
|
|
2729
|
-
} catch {
|
|
2730
|
-
continue;
|
|
2731
|
-
}
|
|
2732
|
-
if (!recordedCwd || (cwd && !sameCwd(recordedCwd, cwd))) continue;
|
|
2733
|
-
const id = file.name.slice(0, -".jsonl".length);
|
|
2734
|
-
try {
|
|
2735
|
-
const [messages, metadata] = await Promise.all([
|
|
2736
|
-
getSessionMessages(id, { dir: recordedCwd, includeSystemMessages: true }),
|
|
2737
|
-
stat(path),
|
|
2738
|
-
]);
|
|
2739
|
-
if (!messages.length) continue;
|
|
2740
|
-
const row = {
|
|
2741
|
-
id: visibleSession(id),
|
|
2742
|
-
preview: transcriptPreview(messages),
|
|
2743
|
-
cwd: recordedCwd,
|
|
2744
|
-
updatedAt: Math.floor(metadata.mtimeMs / 1000),
|
|
2745
|
-
};
|
|
2746
|
-
const previous = rows.get(row.id);
|
|
2747
|
-
if (!previous || row.updatedAt >= previous.updatedAt) rows.set(row.id, row);
|
|
2748
|
-
} catch {
|
|
2749
|
-
continue;
|
|
2750
|
-
}
|
|
2751
|
-
}
|
|
2752
|
-
}
|
|
2753
|
-
return [...rows.values()];
|
|
2754
|
-
}
|
|
2755
|
-
|
|
2756
|
-
async function claudeSessionList(params) {
|
|
2757
|
-
const offset = params.offset || 0;
|
|
2758
|
-
const limit = params.limit || 100;
|
|
2759
|
-
const found = await listSessions({
|
|
2760
|
-
dir: params.cwd,
|
|
2761
|
-
limit: offset + limit,
|
|
2762
|
-
offset: 0,
|
|
2763
|
-
includeProgrammatic: true,
|
|
2764
|
-
});
|
|
2765
|
-
const rows = new Map(found.map((session) => [visibleSession(session.sessionId), {
|
|
2766
|
-
id: visibleSession(session.sessionId),
|
|
2767
|
-
name: session.customTitle || undefined,
|
|
2768
|
-
preview: session.summary || session.firstPrompt || "Untitled Claude session",
|
|
2769
|
-
cwd: session.cwd || params.cwd || "",
|
|
2770
|
-
updatedAt: Math.floor((session.lastModified || 0) / 1000),
|
|
2771
|
-
}]));
|
|
2772
|
-
for (const row of await transcriptSessions(params.cwd)) {
|
|
2773
|
-
if (!rows.has(row.id)) rows.set(row.id, row);
|
|
2774
|
-
}
|
|
2775
|
-
return [...rows.values()]
|
|
2776
|
-
.sort((left, right) => right.updatedAt - left.updatedAt)
|
|
2777
|
-
.slice(offset, offset + limit);
|
|
2778
|
-
}
|
|
2724
|
+
async function readableCwd(id, cwd) {
|
|
2725
|
+
return await transcriptCwd(id) || cwd;
|
|
2726
|
+
}
|
|
2727
|
+
|
|
2728
|
+
function sameCwd(left, right) {
|
|
2729
|
+
if (!left || !right) return !left && !right;
|
|
2730
|
+
const normalize = (value) => value.replaceAll("\\", "/").replace(/\/$/, "");
|
|
2731
|
+
const normalizedLeft = normalize(left);
|
|
2732
|
+
const normalizedRight = normalize(right);
|
|
2733
|
+
return process.platform === "win32"
|
|
2734
|
+
? normalizedLeft.toLowerCase() === normalizedRight.toLowerCase()
|
|
2735
|
+
: normalizedLeft === normalizedRight;
|
|
2736
|
+
}
|
|
2737
|
+
|
|
2738
|
+
function transcriptPreview(messages) {
|
|
2739
|
+
const prompt = historyTurns(messages)
|
|
2740
|
+
.flatMap((turn) => turn.items || [])
|
|
2741
|
+
.find((item) => item.type === "userMessage");
|
|
2742
|
+
return prompt?.content?.find((item) => item.type === "text")?.text || "Untitled Claude session";
|
|
2743
|
+
}
|
|
2744
|
+
|
|
2745
|
+
async function transcriptSessions(cwd) {
|
|
2746
|
+
if (!cwd) return [];
|
|
2747
|
+
let projects;
|
|
2748
|
+
try {
|
|
2749
|
+
projects = await readdir(claudeProjectsDir(), { withFileTypes: true });
|
|
2750
|
+
} catch {
|
|
2751
|
+
return [];
|
|
2752
|
+
}
|
|
2753
|
+
const rows = new Map();
|
|
2754
|
+
for (const project of projects) {
|
|
2755
|
+
if (!project.isDirectory()) continue;
|
|
2756
|
+
const dir = join(claudeProjectsDir(), project.name);
|
|
2757
|
+
let files;
|
|
2758
|
+
try {
|
|
2759
|
+
files = await readdir(dir, { withFileTypes: true });
|
|
2760
|
+
} catch {
|
|
2761
|
+
continue;
|
|
2762
|
+
}
|
|
2763
|
+
for (const file of files) {
|
|
2764
|
+
if (!file.isFile() || !/^[0-9a-f-]{36}\.jsonl$/i.test(file.name)) continue;
|
|
2765
|
+
const path = join(dir, file.name);
|
|
2766
|
+
let recordedCwd;
|
|
2767
|
+
try {
|
|
2768
|
+
recordedCwd = await readTranscriptCwd(path);
|
|
2769
|
+
} catch {
|
|
2770
|
+
continue;
|
|
2771
|
+
}
|
|
2772
|
+
if (!recordedCwd || (cwd && !sameCwd(recordedCwd, cwd))) continue;
|
|
2773
|
+
const id = file.name.slice(0, -".jsonl".length);
|
|
2774
|
+
try {
|
|
2775
|
+
const [messages, metadata] = await Promise.all([
|
|
2776
|
+
getSessionMessages(id, { dir: recordedCwd, includeSystemMessages: true }),
|
|
2777
|
+
stat(path),
|
|
2778
|
+
]);
|
|
2779
|
+
if (!messages.length) continue;
|
|
2780
|
+
const row = {
|
|
2781
|
+
id: visibleSession(id),
|
|
2782
|
+
preview: transcriptPreview(messages),
|
|
2783
|
+
cwd: recordedCwd,
|
|
2784
|
+
updatedAt: Math.floor(metadata.mtimeMs / 1000),
|
|
2785
|
+
};
|
|
2786
|
+
const previous = rows.get(row.id);
|
|
2787
|
+
if (!previous || row.updatedAt >= previous.updatedAt) rows.set(row.id, row);
|
|
2788
|
+
} catch {
|
|
2789
|
+
continue;
|
|
2790
|
+
}
|
|
2791
|
+
}
|
|
2792
|
+
}
|
|
2793
|
+
return [...rows.values()];
|
|
2794
|
+
}
|
|
2795
|
+
|
|
2796
|
+
async function claudeSessionList(params) {
|
|
2797
|
+
const offset = params.offset || 0;
|
|
2798
|
+
const limit = params.limit || 100;
|
|
2799
|
+
const found = await listSessions({
|
|
2800
|
+
dir: params.cwd,
|
|
2801
|
+
limit: offset + limit,
|
|
2802
|
+
offset: 0,
|
|
2803
|
+
includeProgrammatic: true,
|
|
2804
|
+
});
|
|
2805
|
+
const rows = new Map(found.map((session) => [visibleSession(session.sessionId), {
|
|
2806
|
+
id: visibleSession(session.sessionId),
|
|
2807
|
+
name: session.customTitle || undefined,
|
|
2808
|
+
preview: session.summary || session.firstPrompt || "Untitled Claude session",
|
|
2809
|
+
cwd: session.cwd || params.cwd || "",
|
|
2810
|
+
updatedAt: Math.floor((session.lastModified || 0) / 1000),
|
|
2811
|
+
}]));
|
|
2812
|
+
for (const row of await transcriptSessions(params.cwd)) {
|
|
2813
|
+
if (!rows.has(row.id)) rows.set(row.id, row);
|
|
2814
|
+
}
|
|
2815
|
+
return [...rows.values()]
|
|
2816
|
+
.sort((left, right) => right.updatedAt - left.updatedAt)
|
|
2817
|
+
.slice(offset, offset + limit);
|
|
2818
|
+
}
|
|
2779
2819
|
|
|
2780
2820
|
async function dispatch(method, params = {}) {
|
|
2781
2821
|
if (method === "model/list") return loadModelCatalog(params);
|
|
@@ -2934,12 +2974,12 @@ async function dispatch(method, params = {}) {
|
|
|
2934
2974
|
usage,
|
|
2935
2975
|
tokenUsage,
|
|
2936
2976
|
};
|
|
2937
|
-
}
|
|
2938
|
-
if (method === "session/list") {
|
|
2939
|
-
return {
|
|
2940
|
-
data: await claudeSessionList(params),
|
|
2941
|
-
nextCursor: null,
|
|
2942
|
-
};
|
|
2977
|
+
}
|
|
2978
|
+
if (method === "session/list") {
|
|
2979
|
+
return {
|
|
2980
|
+
data: await claudeSessionList(params),
|
|
2981
|
+
nextCursor: null,
|
|
2982
|
+
};
|
|
2943
2983
|
}
|
|
2944
2984
|
if (method === "session/history") {
|
|
2945
2985
|
const id = liveSessionId(params.sessionId);
|
|
@@ -3018,22 +3058,37 @@ async function dispatch(method, params = {}) {
|
|
|
3018
3058
|
throw new Error(`지원하지 않는 Claude 브리지 메서드: ${method}`);
|
|
3019
3059
|
}
|
|
3020
3060
|
|
|
3021
|
-
async function runSelfTest() {
|
|
3022
|
-
const equivalentCwd = process.platform === "win32"
|
|
3023
|
-
? sameCwd("D:\\Repo", "d:/repo/")
|
|
3024
|
-
: sameCwd("/tmp/repo", "/tmp/repo/");
|
|
3025
|
-
const preview = transcriptPreview([{
|
|
3026
|
-
type: "user",
|
|
3027
|
-
uuid: "session-list-prompt",
|
|
3028
|
-
message: { content: "세션 목록 질문" },
|
|
3029
|
-
}]);
|
|
3030
|
-
if (!equivalentCwd || preview !== "세션 목록 질문") {
|
|
3031
|
-
throw new Error(`Claude session list self-test failed: ${JSON.stringify({ equivalentCwd, preview })}`);
|
|
3032
|
-
}
|
|
3033
|
-
if (permissionMode("dontAsk") !== "dontAsk"
|
|
3061
|
+
async function runSelfTest() {
|
|
3062
|
+
const equivalentCwd = process.platform === "win32"
|
|
3063
|
+
? sameCwd("D:\\Repo", "d:/repo/")
|
|
3064
|
+
: sameCwd("/tmp/repo", "/tmp/repo/");
|
|
3065
|
+
const preview = transcriptPreview([{
|
|
3066
|
+
type: "user",
|
|
3067
|
+
uuid: "session-list-prompt",
|
|
3068
|
+
message: { content: "세션 목록 질문" },
|
|
3069
|
+
}]);
|
|
3070
|
+
if (!equivalentCwd || preview !== "세션 목록 질문") {
|
|
3071
|
+
throw new Error(`Claude session list self-test failed: ${JSON.stringify({ equivalentCwd, preview })}`);
|
|
3072
|
+
}
|
|
3073
|
+
if (permissionMode("dontAsk") !== "dontAsk"
|
|
3034
3074
|
|| permissionMode("not-a-mode", "auto") !== "auto") {
|
|
3035
3075
|
throw new Error("Claude permission mode self-test failed");
|
|
3036
3076
|
}
|
|
3077
|
+
const latestOptions = makeOptions({ cwd: process.cwd() }, "00000000-0000-4000-8000-000000000000");
|
|
3078
|
+
if (latestOptions.perTaskStopAffordance !== true
|
|
3079
|
+
|| CLAUDE_TASK_TOOLS.some((tool) => !latestOptions.allowedTools.includes(tool))) {
|
|
3080
|
+
throw new Error(`Claude latest SDK options self-test failed: ${JSON.stringify(latestOptions.allowedTools)}`);
|
|
3081
|
+
}
|
|
3082
|
+
const lookupSession = {
|
|
3083
|
+
turn: { id: "task-get-turn" },
|
|
3084
|
+
tools: new Map(),
|
|
3085
|
+
tasks: new Map(),
|
|
3086
|
+
planCreatePending: false,
|
|
3087
|
+
};
|
|
3088
|
+
processToolUse(lookupSession, { id: "task-get", name: "TaskGet", input: { taskId: "1" } });
|
|
3089
|
+
if (lookupSession.tools.get("task-get")?.suppressed !== true) {
|
|
3090
|
+
throw new Error("Claude TaskGet transcript suppression self-test failed");
|
|
3091
|
+
}
|
|
3037
3092
|
const pluginCatalog = buildClaudePluginCatalog(
|
|
3038
3093
|
[{ id: "cloudflare@official", enabled: true, scope: "user" }],
|
|
3039
3094
|
[{
|
|
@@ -3474,6 +3529,7 @@ async function runSelfTest() {
|
|
|
3474
3529
|
subagents: new Map(),
|
|
3475
3530
|
knownSubagents: new Map(),
|
|
3476
3531
|
hiddenSubagentTasks: new Set(),
|
|
3532
|
+
ambientSubagentTasks: new Set(),
|
|
3477
3533
|
subagentPulse: null,
|
|
3478
3534
|
};
|
|
3479
3535
|
processSubagentSystemMessage(structuredSession, {
|
|
@@ -3595,6 +3651,42 @@ async function runSelfTest() {
|
|
|
3595
3651
|
summary: "Hidden task finished",
|
|
3596
3652
|
});
|
|
3597
3653
|
|
|
3654
|
+
processSubagentSystemMessage(structuredSession, {
|
|
3655
|
+
type: "system",
|
|
3656
|
+
subtype: "task_started",
|
|
3657
|
+
task_id: "agent-ambient",
|
|
3658
|
+
tool_use_id: "toolu_ambient",
|
|
3659
|
+
task_type: "agent",
|
|
3660
|
+
subagent_type: "Explore",
|
|
3661
|
+
description: "Refresh housekeeping",
|
|
3662
|
+
ambient: true,
|
|
3663
|
+
});
|
|
3664
|
+
processSubagentSystemMessage(structuredSession, {
|
|
3665
|
+
type: "system",
|
|
3666
|
+
subtype: "background_tasks_changed",
|
|
3667
|
+
tasks: [{
|
|
3668
|
+
task_id: "agent-ambient",
|
|
3669
|
+
task_type: "agent",
|
|
3670
|
+
description: "Refresh housekeeping",
|
|
3671
|
+
ambient: true,
|
|
3672
|
+
}],
|
|
3673
|
+
});
|
|
3674
|
+
if (structuredSession.subagents.size !== 0
|
|
3675
|
+
|| !structuredSession.ambientSubagentTasks.has("agent-ambient")) {
|
|
3676
|
+
throw new Error("Claude ambient task was shown as a subagent row");
|
|
3677
|
+
}
|
|
3678
|
+
processSubagentSystemMessage(structuredSession, {
|
|
3679
|
+
type: "system",
|
|
3680
|
+
subtype: "task_notification",
|
|
3681
|
+
task_id: "agent-ambient",
|
|
3682
|
+
status: "completed",
|
|
3683
|
+
summary: "Ambient task finished",
|
|
3684
|
+
ambient: true,
|
|
3685
|
+
});
|
|
3686
|
+
if (structuredSession.ambientSubagentTasks.size !== 0) {
|
|
3687
|
+
throw new Error("Claude ambient task completion did not clear hidden state");
|
|
3688
|
+
}
|
|
3689
|
+
|
|
3598
3690
|
processSubagentSystemMessage(structuredSession, {
|
|
3599
3691
|
type: "system",
|
|
3600
3692
|
subtype: "task_started",
|
package/package.json
CHANGED
|
@@ -1,41 +1,41 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "devez-vibe",
|
|
3
|
-
"version": "1.6.
|
|
4
|
-
"description": "Stable terminal UI for Codex and Claude Agent SDK",
|
|
5
|
-
"keywords": [
|
|
6
|
-
"codex",
|
|
7
|
-
"cli",
|
|
8
|
-
"tui",
|
|
9
|
-
"terminal",
|
|
10
|
-
"app-server",
|
|
11
|
-
"claude-agent-sdk"
|
|
12
|
-
],
|
|
13
|
-
"homepage": "https://github.com/MrHoje/Devez-vibe#readme",
|
|
14
|
-
"bugs": "https://github.com/MrHoje/Devez-vibe/issues",
|
|
15
|
-
"repository": {
|
|
16
|
-
"type": "git",
|
|
17
|
-
"url": "git+https://github.com/MrHoje/Devez-vibe.git"
|
|
18
|
-
},
|
|
19
|
-
"license": "MIT",
|
|
20
|
-
"bin": {
|
|
21
|
-
"dvz": "bin/dvz.exe"
|
|
22
|
-
},
|
|
23
|
-
"files": [
|
|
24
|
-
"bin/dvz.exe",
|
|
25
|
-
"bridge/claude-agent-sdk-bridge.mjs",
|
|
26
|
-
"README.md",
|
|
27
|
-
"LICENSE"
|
|
28
|
-
],
|
|
29
|
-
"os": [
|
|
30
|
-
"win32"
|
|
31
|
-
],
|
|
32
|
-
"cpu": [
|
|
33
|
-
"x64"
|
|
34
|
-
],
|
|
35
|
-
"engines": {
|
|
36
|
-
"node": ">=18"
|
|
37
|
-
},
|
|
38
|
-
"dependencies": {
|
|
39
|
-
"@anthropic-ai/claude-agent-sdk": "0.3.
|
|
40
|
-
}
|
|
41
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"name": "devez-vibe",
|
|
3
|
+
"version": "1.6.37",
|
|
4
|
+
"description": "Stable terminal UI for Codex and Claude Agent SDK",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"codex",
|
|
7
|
+
"cli",
|
|
8
|
+
"tui",
|
|
9
|
+
"terminal",
|
|
10
|
+
"app-server",
|
|
11
|
+
"claude-agent-sdk"
|
|
12
|
+
],
|
|
13
|
+
"homepage": "https://github.com/MrHoje/Devez-vibe#readme",
|
|
14
|
+
"bugs": "https://github.com/MrHoje/Devez-vibe/issues",
|
|
15
|
+
"repository": {
|
|
16
|
+
"type": "git",
|
|
17
|
+
"url": "git+https://github.com/MrHoje/Devez-vibe.git"
|
|
18
|
+
},
|
|
19
|
+
"license": "MIT",
|
|
20
|
+
"bin": {
|
|
21
|
+
"dvz": "bin/dvz.exe"
|
|
22
|
+
},
|
|
23
|
+
"files": [
|
|
24
|
+
"bin/dvz.exe",
|
|
25
|
+
"bridge/claude-agent-sdk-bridge.mjs",
|
|
26
|
+
"README.md",
|
|
27
|
+
"LICENSE"
|
|
28
|
+
],
|
|
29
|
+
"os": [
|
|
30
|
+
"win32"
|
|
31
|
+
],
|
|
32
|
+
"cpu": [
|
|
33
|
+
"x64"
|
|
34
|
+
],
|
|
35
|
+
"engines": {
|
|
36
|
+
"node": ">=18"
|
|
37
|
+
},
|
|
38
|
+
"dependencies": {
|
|
39
|
+
"@anthropic-ai/claude-agent-sdk": "0.3.247"
|
|
40
|
+
}
|
|
41
|
+
}
|