devez-vibe 1.7.9 → 1.7.11
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 +106 -4
- package/package.json +2 -2
package/bin/dvz.exe
CHANGED
|
Binary file
|
|
@@ -2854,6 +2854,86 @@ async function readableCwd(id, cwd) {
|
|
|
2854
2854
|
return await transcriptCwd(id) || cwd;
|
|
2855
2855
|
}
|
|
2856
2856
|
|
|
2857
|
+
const transcriptPaths = new Map();
|
|
2858
|
+
|
|
2859
|
+
/** Locate `id`'s transcript file under any project folder. */
|
|
2860
|
+
async function transcriptPath(id) {
|
|
2861
|
+
const cached = transcriptPaths.get(id);
|
|
2862
|
+
if (cached && existsSync(cached)) return cached;
|
|
2863
|
+
let entries;
|
|
2864
|
+
try {
|
|
2865
|
+
entries = await readdir(claudeProjectsDir(), { withFileTypes: true });
|
|
2866
|
+
} catch {
|
|
2867
|
+
return null;
|
|
2868
|
+
}
|
|
2869
|
+
for (const entry of entries) {
|
|
2870
|
+
if (!entry.isDirectory()) continue;
|
|
2871
|
+
const path = join(claudeProjectsDir(), entry.name, `${id}.jsonl`);
|
|
2872
|
+
if (existsSync(path)) {
|
|
2873
|
+
transcriptPaths.set(id, path);
|
|
2874
|
+
return path;
|
|
2875
|
+
}
|
|
2876
|
+
}
|
|
2877
|
+
return null;
|
|
2878
|
+
}
|
|
2879
|
+
|
|
2880
|
+
/**
|
|
2881
|
+
* The conversation a transcript records, in file order. The SDK's own reader
|
|
2882
|
+
* walks the parentUuid chain backwards from the tail, and a compaction boundary
|
|
2883
|
+
* has no parent, so everything said before the last compaction silently drops
|
|
2884
|
+
* out of a resumed session's history. Reading the file directly keeps the whole
|
|
2885
|
+
* conversation. A resume can re-append earlier messages under their original
|
|
2886
|
+
* uuids, so each uuid's first appearance wins.
|
|
2887
|
+
*/
|
|
2888
|
+
function transcriptEntries(raw) {
|
|
2889
|
+
const messages = [];
|
|
2890
|
+
const seen = new Set();
|
|
2891
|
+
for (const line of raw.split("\n")) {
|
|
2892
|
+
let entry;
|
|
2893
|
+
try {
|
|
2894
|
+
entry = JSON.parse(line);
|
|
2895
|
+
} catch {
|
|
2896
|
+
continue;
|
|
2897
|
+
}
|
|
2898
|
+
if (!entry || typeof entry !== "object" || entry.isSidechain) continue;
|
|
2899
|
+
if (entry.type !== "user" && entry.type !== "assistant" && entry.type !== "system") continue;
|
|
2900
|
+
if (typeof entry.uuid === "string" && entry.uuid) {
|
|
2901
|
+
if (seen.has(entry.uuid)) continue;
|
|
2902
|
+
seen.add(entry.uuid);
|
|
2903
|
+
}
|
|
2904
|
+
messages.push(entry);
|
|
2905
|
+
}
|
|
2906
|
+
return messages;
|
|
2907
|
+
}
|
|
2908
|
+
|
|
2909
|
+
async function transcriptMessagesAt(path) {
|
|
2910
|
+
let raw;
|
|
2911
|
+
try {
|
|
2912
|
+
raw = await readFile(path, "utf8");
|
|
2913
|
+
} catch {
|
|
2914
|
+
return [];
|
|
2915
|
+
}
|
|
2916
|
+
return transcriptEntries(raw);
|
|
2917
|
+
}
|
|
2918
|
+
|
|
2919
|
+
/** Every message of `id`'s conversation: the transcript file when it exists,
|
|
2920
|
+
* the SDK's reader for sessions that left none behind. */
|
|
2921
|
+
async function sessionMessages(id, cwd) {
|
|
2922
|
+
const path = await transcriptPath(id);
|
|
2923
|
+
if (path) {
|
|
2924
|
+
const messages = await transcriptMessagesAt(path);
|
|
2925
|
+
if (messages.length) return messages;
|
|
2926
|
+
}
|
|
2927
|
+
try {
|
|
2928
|
+
return await getSessionMessages(id, {
|
|
2929
|
+
dir: await readableCwd(id, cwd),
|
|
2930
|
+
includeSystemMessages: true,
|
|
2931
|
+
});
|
|
2932
|
+
} catch {
|
|
2933
|
+
return [];
|
|
2934
|
+
}
|
|
2935
|
+
}
|
|
2936
|
+
|
|
2857
2937
|
function sameCwd(left, right) {
|
|
2858
2938
|
if (!left || !right) return !left && !right;
|
|
2859
2939
|
const normalize = (value) => value.replaceAll("\\", "/").replace(/\/$/, "");
|
|
@@ -2902,7 +2982,7 @@ async function transcriptSessions(cwd) {
|
|
|
2902
2982
|
const id = file.name.slice(0, -".jsonl".length);
|
|
2903
2983
|
try {
|
|
2904
2984
|
const [messages, metadata] = await Promise.all([
|
|
2905
|
-
|
|
2985
|
+
transcriptMessagesAt(path),
|
|
2906
2986
|
stat(path),
|
|
2907
2987
|
]);
|
|
2908
2988
|
if (!messages.length) continue;
|
|
@@ -3054,7 +3134,7 @@ async function dispatch(method, params = {}) {
|
|
|
3054
3134
|
const id = liveSessionId(params.sessionId);
|
|
3055
3135
|
const existing = sessions.get(id);
|
|
3056
3136
|
if (existing) {
|
|
3057
|
-
const messages = await
|
|
3137
|
+
const messages = await sessionMessages(id, existing.cwd);
|
|
3058
3138
|
if (!existing.tasks.size) existing.tasks = historyState(messages).tasks;
|
|
3059
3139
|
return {
|
|
3060
3140
|
id,
|
|
@@ -3072,7 +3152,7 @@ async function dispatch(method, params = {}) {
|
|
|
3072
3152
|
// The transcript itself decides whether there is anything to resume:
|
|
3073
3153
|
// getSessionInfo only sees sessions the CLI indexed, and a bridge-run session
|
|
3074
3154
|
// whose transcript is intact can be missing from that index.
|
|
3075
|
-
const messages = await
|
|
3155
|
+
const messages = await sessionMessages(id, params.cwd);
|
|
3076
3156
|
if (!messages.length) throw new Error(`Claude 세션을 찾을 수 없습니다: ${id}`);
|
|
3077
3157
|
const info = await getSessionInfo(id, { dir });
|
|
3078
3158
|
const lastModel = [...messages].reverse().find((message) => message.type === "assistant")?.message?.model;
|
|
@@ -3109,7 +3189,7 @@ async function dispatch(method, params = {}) {
|
|
|
3109
3189
|
}
|
|
3110
3190
|
if (method === "session/history") {
|
|
3111
3191
|
const id = liveSessionId(params.sessionId);
|
|
3112
|
-
const messages = await
|
|
3192
|
+
const messages = await sessionMessages(id, params.cwd);
|
|
3113
3193
|
return { data: historyTurns(messages), nextCursor: null };
|
|
3114
3194
|
}
|
|
3115
3195
|
if (method === "session/prompt") return startPrompt(params);
|
|
@@ -3249,6 +3329,28 @@ async function runSelfTest() {
|
|
|
3249
3329
|
if (!equivalentCwd || preview !== "세션 목록 질문") {
|
|
3250
3330
|
throw new Error(`Claude session list self-test failed: ${JSON.stringify({ equivalentCwd, preview })}`);
|
|
3251
3331
|
}
|
|
3332
|
+
// A compacted transcript keeps every turn on disk; the reader must return the
|
|
3333
|
+
// pre-compaction turns, skip resume-replayed duplicates and sidechains, and
|
|
3334
|
+
// leave the summary itself to the history filter.
|
|
3335
|
+
const compactedTranscript = [
|
|
3336
|
+
JSON.stringify({ type: "user", uuid: "before-compact", message: { role: "user", content: "compact 이전 질문" } }),
|
|
3337
|
+
JSON.stringify({ type: "assistant", uuid: "before-compact-answer", message: { role: "assistant", model: "claude-opus-5", content: [{ type: "text", text: "이전 답변." }] } }),
|
|
3338
|
+
JSON.stringify({ type: "attachment", uuid: "attachment-noise" }),
|
|
3339
|
+
JSON.stringify({ type: "system", subtype: "compact_boundary", uuid: "compact-1", parentUuid: null }),
|
|
3340
|
+
JSON.stringify({ type: "user", uuid: "compact-summary", isCompactSummary: true, message: { role: "user", content: "This session is being continued from a previous conversation." } }),
|
|
3341
|
+
JSON.stringify({ type: "user", uuid: "before-compact", message: { role: "user", content: "재개가 다시 적은 복사본" } }),
|
|
3342
|
+
JSON.stringify({ type: "user", uuid: "sidechain-user", isSidechain: true, message: { role: "user", content: "subagent" } }),
|
|
3343
|
+
"not json",
|
|
3344
|
+
JSON.stringify({ type: "user", uuid: "after-compact", message: { role: "user", content: "compact 이후 질문" } }),
|
|
3345
|
+
JSON.stringify({ type: "assistant", uuid: "after-compact-answer", message: { role: "assistant", model: "claude-opus-5", content: [{ type: "text", text: "이후 답변." }] } }),
|
|
3346
|
+
].join("\n");
|
|
3347
|
+
const restored = transcriptEntries(compactedTranscript);
|
|
3348
|
+
const restoredPrompts = historyTurns(restored)
|
|
3349
|
+
.map((turn) => turn.items.find((item) => item.type === "userMessage")?.content?.[0]?.text);
|
|
3350
|
+
if (restored.length !== 6
|
|
3351
|
+
|| JSON.stringify(restoredPrompts) !== JSON.stringify(["compact 이전 질문", "compact 이후 질문"])) {
|
|
3352
|
+
throw new Error(`Claude compacted transcript self-test failed: ${JSON.stringify({ restored: restored.length, restoredPrompts })}`);
|
|
3353
|
+
}
|
|
3252
3354
|
const latestOptions = makeOptions({ cwd: process.cwd(), permissionMode: "plan" }, "00000000-0000-4000-8000-000000000000");
|
|
3253
3355
|
if (latestOptions.permissionMode !== BOOTSTRAP_PERMISSION_MODE
|
|
3254
3356
|
|| latestOptions.perTaskStopAffordance !== true
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "devez-vibe",
|
|
3
|
-
"version": "1.7.
|
|
3
|
+
"version": "1.7.11",
|
|
4
4
|
"description": "Stable terminal UI for Codex and Claude Agent SDK",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"codex",
|
|
@@ -41,6 +41,6 @@
|
|
|
41
41
|
"postinstall": "node install-skills.mjs"
|
|
42
42
|
},
|
|
43
43
|
"dependencies": {
|
|
44
|
-
"@anthropic-ai/claude-agent-sdk": "0.3.
|
|
44
|
+
"@anthropic-ai/claude-agent-sdk": "0.3.258"
|
|
45
45
|
}
|
|
46
46
|
}
|