devez-vibe 1.6.35 → 1.6.36

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
@@ -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, 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";
@@ -2681,9 +2681,101 @@ async function transcriptCwd(id) {
2681
2681
 
2682
2682
  /** The cwd to read `id`'s transcript with: the one the transcript itself records,
2683
2683
  * 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
- }
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
+ }
2687
2779
 
2688
2780
  async function dispatch(method, params = {}) {
2689
2781
  if (method === "model/list") return loadModelCatalog(params);
@@ -2842,24 +2934,12 @@ async function dispatch(method, params = {}) {
2842
2934
  usage,
2843
2935
  tokenUsage,
2844
2936
  };
2845
- }
2846
- if (method === "session/list") {
2847
- const found = await listSessions({
2848
- dir: params.cwd,
2849
- limit: params.limit || 100,
2850
- offset: params.offset || 0,
2851
- includeProgrammatic: true,
2852
- });
2853
- return {
2854
- data: found.map((session) => ({
2855
- id: visibleSession(session.sessionId),
2856
- name: session.customTitle || undefined,
2857
- preview: session.summary || session.firstPrompt || "Untitled Claude session",
2858
- cwd: session.cwd || params.cwd || "",
2859
- updatedAt: Math.floor((session.lastModified || 0) / 1000),
2860
- })),
2861
- nextCursor: null,
2862
- };
2937
+ }
2938
+ if (method === "session/list") {
2939
+ return {
2940
+ data: await claudeSessionList(params),
2941
+ nextCursor: null,
2942
+ };
2863
2943
  }
2864
2944
  if (method === "session/history") {
2865
2945
  const id = liveSessionId(params.sessionId);
@@ -2938,8 +3018,19 @@ async function dispatch(method, params = {}) {
2938
3018
  throw new Error(`지원하지 않는 Claude 브리지 메서드: ${method}`);
2939
3019
  }
2940
3020
 
2941
- async function runSelfTest() {
2942
- if (permissionMode("dontAsk") !== "dontAsk"
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"
2943
3034
  || permissionMode("not-a-mode", "auto") !== "auto") {
2944
3035
  throw new Error("Claude permission mode self-test failed");
2945
3036
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "devez-vibe",
3
- "version": "1.6.35",
3
+ "version": "1.6.36",
4
4
  "description": "Stable terminal UI for Codex and Claude Agent SDK",
5
5
  "keywords": [
6
6
  "codex",