devez-vibe 1.3.20 → 1.3.22

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/LICENSE CHANGED
@@ -1,33 +1,33 @@
1
- DevezCode source code license
2
-
3
- The MIT License below applies only to the DevezCode source code and to files
4
- that are not listed in the exception below.
5
-
6
- Exceptions:
7
-
8
- * `Resources/Images/FileTypes/` and `Resources/Licenses/` are Microsoft Visual
9
- Studio Image Library materials, subject to the included Microsoft terms.
10
- * `Resources/Images/ShellPresets/` contains third-party brand assets, subject
11
- to their respective owners' terms.
12
-
13
- MIT License
14
-
15
- Copyright (c) 2026 DevezCode contributors
16
-
17
- Permission is hereby granted, free of charge, to any person obtaining a copy
18
- of this software and associated documentation files (the "Software"), to deal
19
- in the Software without restriction, including without limitation the rights
20
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
21
- copies of the Software, and to permit persons to whom the Software is
22
- furnished to do so, subject to the following conditions:
23
-
24
- The above copyright notice and this permission notice shall be included in all
25
- copies or substantial portions of the Software.
26
-
27
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
28
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
29
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
30
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
31
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
32
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
33
- SOFTWARE.
1
+ DevezCode source code license
2
+
3
+ The MIT License below applies only to the DevezCode source code and to files
4
+ that are not listed in the exception below.
5
+
6
+ Exceptions:
7
+
8
+ * `Resources/Images/FileTypes/` and `Resources/Licenses/` are Microsoft Visual
9
+ Studio Image Library materials, subject to the included Microsoft terms.
10
+ * `Resources/Images/ShellPresets/` contains third-party brand assets, subject
11
+ to their respective owners' terms.
12
+
13
+ MIT License
14
+
15
+ Copyright (c) 2026 DevezCode contributors
16
+
17
+ Permission is hereby granted, free of charge, to any person obtaining a copy
18
+ of this software and associated documentation files (the "Software"), to deal
19
+ in the Software without restriction, including without limitation the rights
20
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
21
+ copies of the Software, and to permit persons to whom the Software is
22
+ furnished to do so, subject to the following conditions:
23
+
24
+ The above copyright notice and this permission notice shall be included in all
25
+ copies or substantial portions of the Software.
26
+
27
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
28
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
29
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
30
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
31
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
32
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
33
+ SOFTWARE.
package/bin/dvz.exe CHANGED
Binary file
@@ -3,20 +3,20 @@
3
3
  import { randomUUID } from "node:crypto";
4
4
  import { spawn } from "node:child_process";
5
5
  import { createReadStream } from "node:fs";
6
- import { mkdir, readdir, readFile, writeFile } from "node:fs/promises";
6
+ import { mkdir, readdir, readFile, writeFile } from "node:fs/promises";
7
7
  import { homedir } from "node:os";
8
- import { dirname, join } from "node:path";
8
+ import { dirname, join } from "node:path";
9
9
  import { createInterface } from "node:readline";
10
10
  import {
11
11
  deleteSession,
12
12
  forkSession,
13
- getSessionInfo,
14
- getSessionMessages,
15
- filterEscalatingDefaultMode,
16
- listSessions,
17
- resolveSettings,
18
- startup,
19
- } from "@anthropic-ai/claude-agent-sdk";
13
+ getSessionInfo,
14
+ getSessionMessages,
15
+ filterEscalatingDefaultMode,
16
+ listSessions,
17
+ resolveSettings,
18
+ startup,
19
+ } from "@anthropic-ai/claude-agent-sdk";
20
20
 
21
21
  const VERSION = process.env.DEVEZ_VIBE_VERSION || "dev";
22
22
  const sessions = new Map();
@@ -171,7 +171,7 @@ function compactClaudeModelName(model) {
171
171
  return fallback || clean(model.displayName || model.resolvedModel || model.value);
172
172
  }
173
173
 
174
- function catalogEntry(model, defaultResolvedModel) {
174
+ function catalogEntry(model, defaultResolvedModel) {
175
175
  const value = String(model.value || "");
176
176
  const resolved = String(model.resolvedModel || value);
177
177
  const efforts = model.supportsEffort && Array.isArray(model.supportedEffortLevels)
@@ -183,9 +183,9 @@ function catalogEntry(model, defaultResolvedModel) {
183
183
  model: visibleModel(value),
184
184
  displayName: compactClaudeModelName(model),
185
185
  defaultReasoningEffort: efforts.includes("high") ? "high" : efforts.at(-1) || "",
186
- supportedReasoningEfforts: efforts.map((reasoningEffort) => ({ reasoningEffort })),
187
- supportsAutoMode: Boolean(model.supportsAutoMode),
188
- isDefault: Boolean(defaultResolvedModel) && resolved === defaultResolvedModel,
186
+ supportedReasoningEfforts: efforts.map((reasoningEffort) => ({ reasoningEffort })),
187
+ supportsAutoMode: Boolean(model.supportsAutoMode),
188
+ isDefault: Boolean(defaultResolvedModel) && resolved === defaultResolvedModel,
189
189
  ...(contextWindow > 0 ? { contextWindow } : {}),
190
190
  };
191
191
  }
@@ -298,14 +298,14 @@ function adoptSessionId(session, incoming) {
298
298
  });
299
299
  }
300
300
 
301
- const PERMISSION_MODES = [
302
- "default",
303
- "acceptEdits",
304
- "plan",
305
- "auto",
306
- "dontAsk",
307
- "bypassPermissions",
308
- ];
301
+ const PERMISSION_MODES = [
302
+ "default",
303
+ "acceptEdits",
304
+ "plan",
305
+ "auto",
306
+ "dontAsk",
307
+ "bypassPermissions",
308
+ ];
309
309
 
310
310
  function permissionMode(requested, fallback = "default") {
311
311
  const mode = String(requested || "");
@@ -314,173 +314,173 @@ function permissionMode(requested, fallback = "default") {
314
314
 
315
315
  // Moves a live session onto a mode the badge picked. A rejected mode — policy
316
316
  // disables bypass, say — leaves the session on the one it already had.
317
- async function applyPermissionMode(session, requested) {
318
- const mode = permissionMode(requested, session.permissionMode || "default");
319
- if (mode === session.permissionMode) return null;
320
- try {
321
- await session.query.setPermissionMode(mode);
322
- session.permissionMode = mode;
323
- return null;
324
- } catch (error) {
325
- return error?.message || String(error);
326
- }
327
- }
328
-
329
- async function claudePermissionStatus(params) {
330
- const resolved = await resolveSettings({
331
- cwd: params.cwd || process.cwd(),
332
- settingSources: ["user", "project", "local"],
333
- });
334
- const effective = filterEscalatingDefaultMode(resolved);
335
- const permissions = effective.permissions || {};
336
- const bypassAccepted = effective.skipDangerousModePermissionPrompt === true
337
- || effective.bypassPermissionsModeAccepted === true;
338
- const bypassAvailable = permissions.disableBypassPermissionsMode !== "disable" && bypassAccepted;
339
- const autoDisabled = effective.disableAutoMode === "disable";
340
- let defaultMode = permissionMode(permissions.defaultMode);
341
- if ((defaultMode === "bypassPermissions" && !bypassAvailable)
342
- || (defaultMode === "auto" && autoDisabled)) defaultMode = "default";
343
- const rules = [];
344
- const directories = [];
345
- for (const source of resolved.sources) {
346
- const sourcePermissions = source.settings?.permissions || {};
347
- for (const behavior of ["allow", "ask", "deny"]) {
348
- for (const rule of Array.isArray(sourcePermissions[behavior])
349
- ? sourcePermissions[behavior]
350
- : []) {
351
- rules.push({
352
- behavior,
353
- rule: String(rule),
354
- source: source.source,
355
- path: source.path || null,
356
- mutable: ["user", "project", "local"].includes(source.source),
357
- });
358
- }
359
- }
360
- for (const directory of Array.isArray(sourcePermissions.additionalDirectories)
361
- ? sourcePermissions.additionalDirectories
362
- : []) {
363
- directories.push({
364
- directory: String(directory),
365
- source: source.source,
366
- path: source.path || null,
367
- mutable: ["user", "project", "local"].includes(source.source),
368
- });
369
- }
370
- }
371
- const denials = [...sessions.values()]
372
- .filter((session) => session.cwd === (params.cwd || process.cwd()))
373
- .flatMap((session) => session.permissionDenials || [])
374
- .slice(-20)
375
- .reverse();
376
- return {
377
- defaultMode,
378
- bypassAvailable,
379
- autoDisabled,
380
- rulesLocked: effective.allowManagedPermissionRulesOnly === true,
381
- rules,
382
- directories,
383
- denials,
384
- };
385
- }
386
-
387
- function permissionSettingsPath(cwd, destination) {
388
- if (destination === "user") {
389
- return join(process.env.CLAUDE_CONFIG_DIR || join(homedir(), ".claude"), "settings.json");
390
- }
391
- if (destination === "project") return join(cwd, ".claude", "settings.json");
392
- if (destination === "local") return join(cwd, ".claude", "settings.local.json");
393
- throw new Error(`지원하지 않는 Claude 권한 설정 범위: ${destination}`);
394
- }
395
-
396
- async function updateClaudePermission(params) {
397
- const cwd = params.cwd || process.cwd();
398
- const status = await claudePermissionStatus({ cwd });
399
- if (status.rulesLocked) {
400
- throw new Error("관리 정책에서 사용자·프로젝트 권한 규칙 변경을 비활성화했습니다.");
401
- }
402
- const destination = String(params.destination || "project");
403
- const path = permissionSettingsPath(cwd, destination);
404
- let settings = {};
405
- try {
406
- settings = JSON.parse(await readFile(path, "utf8"));
407
- } catch (error) {
408
- if (error?.code !== "ENOENT") throw error;
409
- }
410
- if (!settings || typeof settings !== "object" || Array.isArray(settings)) settings = {};
411
- if (!settings.permissions || typeof settings.permissions !== "object"
412
- || Array.isArray(settings.permissions)) settings.permissions = {};
413
-
414
- const action = String(params.action || "");
415
- const behavior = String(params.behavior || "");
416
- const key = behavior === "directory" ? "additionalDirectories" : behavior;
417
- if (!["allow", "ask", "deny", "additionalDirectories"].includes(key)) {
418
- throw new Error(`지원하지 않는 Claude 권한 규칙 종류: ${behavior}`);
419
- }
420
- const value = String(params.value || "").trim();
421
- if (!value) throw new Error("빈 Claude 권한 규칙은 저장할 수 없습니다.");
422
- const values = Array.isArray(settings.permissions[key])
423
- ? settings.permissions[key].map(String)
424
- : [];
425
- if (action === "add" && !values.includes(value)) values.push(value);
426
- else if (action === "remove") {
427
- const index = values.indexOf(value);
428
- if (index >= 0) values.splice(index, 1);
429
- } else if (action !== "add") {
430
- throw new Error(`지원하지 않는 Claude 권한 규칙 작업: ${action}`);
431
- }
432
- settings.permissions[key] = values;
433
- await mkdir(dirname(path), { recursive: true });
434
- await writeFile(path, `${JSON.stringify(settings, null, 2)}\n`, "utf8");
435
- return claudePermissionStatus({ cwd });
436
- }
437
-
438
- async function setClaudeAutoModeDisabled(params) {
439
- const cwd = params.cwd || process.cwd();
440
- const path = permissionSettingsPath(cwd, "user");
441
- let settings = {};
442
- try {
443
- settings = JSON.parse(await readFile(path, "utf8"));
444
- } catch (error) {
445
- if (error?.code !== "ENOENT") throw error;
446
- }
447
- if (!settings || typeof settings !== "object" || Array.isArray(settings)) settings = {};
448
- if (params.disabled === false) delete settings.disableAutoMode;
449
- else settings.disableAutoMode = "disable";
450
- await mkdir(dirname(path), { recursive: true });
451
- await writeFile(path, `${JSON.stringify(settings, null, 2)}\n`, "utf8");
452
- return claudePermissionStatus({ cwd });
453
- }
454
-
455
- async function retryClaudePermission(params) {
456
- const session = lookupSession(params.sessionId);
457
- if (!session) throw new Error("재시도할 Claude 세션을 찾을 수 없습니다.");
458
- const tool = String(params.tool || "tool");
459
- const input = params.input && typeof params.input === "object" ? params.input : {};
460
- const previousMode = session.permissionMode;
461
- return startPrompt({
462
- sessionId: session.id,
463
- permissionMode: previousMode === "auto" ? "default" : previousMode,
464
- restorePermissionMode: previousMode === "auto" ? "auto" : null,
465
- input: [{
466
- type: "text",
467
- text: [
468
- `The user selected the denied ${tool} action in /permissions and asked to retry it.`,
469
- "Retry that action now. A manual permission prompt will be shown before it runs.",
470
- `Original tool input: ${JSON.stringify(input)}`,
471
- ].join("\n"),
472
- }],
473
- });
474
- }
317
+ async function applyPermissionMode(session, requested) {
318
+ const mode = permissionMode(requested, session.permissionMode || "default");
319
+ if (mode === session.permissionMode) return null;
320
+ try {
321
+ await session.query.setPermissionMode(mode);
322
+ session.permissionMode = mode;
323
+ return null;
324
+ } catch (error) {
325
+ return error?.message || String(error);
326
+ }
327
+ }
328
+
329
+ async function claudePermissionStatus(params) {
330
+ const resolved = await resolveSettings({
331
+ cwd: params.cwd || process.cwd(),
332
+ settingSources: ["user", "project", "local"],
333
+ });
334
+ const effective = filterEscalatingDefaultMode(resolved);
335
+ const permissions = effective.permissions || {};
336
+ const bypassAccepted = effective.skipDangerousModePermissionPrompt === true
337
+ || effective.bypassPermissionsModeAccepted === true;
338
+ const bypassAvailable = permissions.disableBypassPermissionsMode !== "disable" && bypassAccepted;
339
+ const autoDisabled = effective.disableAutoMode === "disable";
340
+ let defaultMode = permissionMode(permissions.defaultMode);
341
+ if ((defaultMode === "bypassPermissions" && !bypassAvailable)
342
+ || (defaultMode === "auto" && autoDisabled)) defaultMode = "default";
343
+ const rules = [];
344
+ const directories = [];
345
+ for (const source of resolved.sources) {
346
+ const sourcePermissions = source.settings?.permissions || {};
347
+ for (const behavior of ["allow", "ask", "deny"]) {
348
+ for (const rule of Array.isArray(sourcePermissions[behavior])
349
+ ? sourcePermissions[behavior]
350
+ : []) {
351
+ rules.push({
352
+ behavior,
353
+ rule: String(rule),
354
+ source: source.source,
355
+ path: source.path || null,
356
+ mutable: ["user", "project", "local"].includes(source.source),
357
+ });
358
+ }
359
+ }
360
+ for (const directory of Array.isArray(sourcePermissions.additionalDirectories)
361
+ ? sourcePermissions.additionalDirectories
362
+ : []) {
363
+ directories.push({
364
+ directory: String(directory),
365
+ source: source.source,
366
+ path: source.path || null,
367
+ mutable: ["user", "project", "local"].includes(source.source),
368
+ });
369
+ }
370
+ }
371
+ const denials = [...sessions.values()]
372
+ .filter((session) => session.cwd === (params.cwd || process.cwd()))
373
+ .flatMap((session) => session.permissionDenials || [])
374
+ .slice(-20)
375
+ .reverse();
376
+ return {
377
+ defaultMode,
378
+ bypassAvailable,
379
+ autoDisabled,
380
+ rulesLocked: effective.allowManagedPermissionRulesOnly === true,
381
+ rules,
382
+ directories,
383
+ denials,
384
+ };
385
+ }
386
+
387
+ function permissionSettingsPath(cwd, destination) {
388
+ if (destination === "user") {
389
+ return join(process.env.CLAUDE_CONFIG_DIR || join(homedir(), ".claude"), "settings.json");
390
+ }
391
+ if (destination === "project") return join(cwd, ".claude", "settings.json");
392
+ if (destination === "local") return join(cwd, ".claude", "settings.local.json");
393
+ throw new Error(`지원하지 않는 Claude 권한 설정 범위: ${destination}`);
394
+ }
395
+
396
+ async function updateClaudePermission(params) {
397
+ const cwd = params.cwd || process.cwd();
398
+ const status = await claudePermissionStatus({ cwd });
399
+ if (status.rulesLocked) {
400
+ throw new Error("관리 정책에서 사용자·프로젝트 권한 규칙 변경을 비활성화했습니다.");
401
+ }
402
+ const destination = String(params.destination || "project");
403
+ const path = permissionSettingsPath(cwd, destination);
404
+ let settings = {};
405
+ try {
406
+ settings = JSON.parse(await readFile(path, "utf8"));
407
+ } catch (error) {
408
+ if (error?.code !== "ENOENT") throw error;
409
+ }
410
+ if (!settings || typeof settings !== "object" || Array.isArray(settings)) settings = {};
411
+ if (!settings.permissions || typeof settings.permissions !== "object"
412
+ || Array.isArray(settings.permissions)) settings.permissions = {};
413
+
414
+ const action = String(params.action || "");
415
+ const behavior = String(params.behavior || "");
416
+ const key = behavior === "directory" ? "additionalDirectories" : behavior;
417
+ if (!["allow", "ask", "deny", "additionalDirectories"].includes(key)) {
418
+ throw new Error(`지원하지 않는 Claude 권한 규칙 종류: ${behavior}`);
419
+ }
420
+ const value = String(params.value || "").trim();
421
+ if (!value) throw new Error("빈 Claude 권한 규칙은 저장할 수 없습니다.");
422
+ const values = Array.isArray(settings.permissions[key])
423
+ ? settings.permissions[key].map(String)
424
+ : [];
425
+ if (action === "add" && !values.includes(value)) values.push(value);
426
+ else if (action === "remove") {
427
+ const index = values.indexOf(value);
428
+ if (index >= 0) values.splice(index, 1);
429
+ } else if (action !== "add") {
430
+ throw new Error(`지원하지 않는 Claude 권한 규칙 작업: ${action}`);
431
+ }
432
+ settings.permissions[key] = values;
433
+ await mkdir(dirname(path), { recursive: true });
434
+ await writeFile(path, `${JSON.stringify(settings, null, 2)}\n`, "utf8");
435
+ return claudePermissionStatus({ cwd });
436
+ }
437
+
438
+ async function setClaudeAutoModeDisabled(params) {
439
+ const cwd = params.cwd || process.cwd();
440
+ const path = permissionSettingsPath(cwd, "user");
441
+ let settings = {};
442
+ try {
443
+ settings = JSON.parse(await readFile(path, "utf8"));
444
+ } catch (error) {
445
+ if (error?.code !== "ENOENT") throw error;
446
+ }
447
+ if (!settings || typeof settings !== "object" || Array.isArray(settings)) settings = {};
448
+ if (params.disabled === false) delete settings.disableAutoMode;
449
+ else settings.disableAutoMode = "disable";
450
+ await mkdir(dirname(path), { recursive: true });
451
+ await writeFile(path, `${JSON.stringify(settings, null, 2)}\n`, "utf8");
452
+ return claudePermissionStatus({ cwd });
453
+ }
454
+
455
+ async function retryClaudePermission(params) {
456
+ const session = lookupSession(params.sessionId);
457
+ if (!session) throw new Error("재시도할 Claude 세션을 찾을 수 없습니다.");
458
+ const tool = String(params.tool || "tool");
459
+ const input = params.input && typeof params.input === "object" ? params.input : {};
460
+ const previousMode = session.permissionMode;
461
+ return startPrompt({
462
+ sessionId: session.id,
463
+ permissionMode: previousMode === "auto" ? "default" : previousMode,
464
+ restorePermissionMode: previousMode === "auto" ? "auto" : null,
465
+ input: [{
466
+ type: "text",
467
+ text: [
468
+ `The user selected the denied ${tool} action in /permissions and asked to retry it.`,
469
+ "Retry that action now. A manual permission prompt will be shown before it runs.",
470
+ `Original tool input: ${JSON.stringify(input)}`,
471
+ ].join("\n"),
472
+ }],
473
+ });
474
+ }
475
475
 
476
476
  function makeOptions(params, sessionId, resume) {
477
477
  const options = {
478
478
  cwd: params.cwd || process.cwd(),
479
479
  includePartialMessages: true,
480
- permissionMode: permissionMode(params.permissionMode),
481
- // Not a mode, a capability: the SDK refuses `bypassPermissions` outright
482
- // unless the session was started with this. The UI exposes it only after
483
- // Claude's resolved settings and acknowledgement make the mode available.
480
+ permissionMode: permissionMode(params.permissionMode),
481
+ // Not a mode, a capability: the SDK refuses `bypassPermissions` outright
482
+ // unless the session was started with this. The UI exposes it only after
483
+ // Claude's resolved settings and acknowledgement make the mode available.
484
484
  allowDangerouslySkipPermissions: true,
485
485
  enableFileCheckpointing: true,
486
486
  persistSession: true,
@@ -506,7 +506,7 @@ function makeOptions(params, sessionId, resume) {
506
506
  return options;
507
507
  }
508
508
 
509
- async function startAgentQuery(prompt, options) {
509
+ async function startAgentQuery(prompt, options) {
510
510
  const warm = await startup({ options });
511
511
  try {
512
512
  return warm.query(prompt);
@@ -514,29 +514,29 @@ async function startAgentQuery(prompt, options) {
514
514
  warm.close();
515
515
  throw error;
516
516
  }
517
- }
518
-
519
- function permissionSuggestionLabel(suggestions) {
520
- if (!Array.isArray(suggestions) || !suggestions.length) return null;
521
- const rules = suggestions.flatMap((suggestion) =>
522
- Array.isArray(suggestion.rules)
523
- ? suggestion.rules.map((rule) => rule.ruleContent
524
- ? `${rule.toolName}(${rule.ruleContent})`
525
- : String(rule.toolName || ""))
526
- : []);
527
- const directories = suggestions.flatMap((suggestion) =>
528
- Array.isArray(suggestion.directories) ? suggestion.directories.map(String) : []);
529
- const values = [...new Set([...rules, ...directories].filter(Boolean))];
530
- const destinations = new Set(suggestions.map((suggestion) => suggestion.destination));
531
- const scope = destinations.has("userSettings")
532
- ? "모든 프로젝트에서"
533
- : destinations.has("projectSettings") || destinations.has("localSettings")
534
- ? "이 프로젝트에서"
535
- : "이번 세션에서";
536
- return values.length
537
- ? `${scope} 항상 허용: ${values.join(", ")}`
538
- : `${scope} 다시 묻지 않기`;
539
- }
517
+ }
518
+
519
+ function permissionSuggestionLabel(suggestions) {
520
+ if (!Array.isArray(suggestions) || !suggestions.length) return null;
521
+ const rules = suggestions.flatMap((suggestion) =>
522
+ Array.isArray(suggestion.rules)
523
+ ? suggestion.rules.map((rule) => rule.ruleContent
524
+ ? `${rule.toolName}(${rule.ruleContent})`
525
+ : String(rule.toolName || ""))
526
+ : []);
527
+ const directories = suggestions.flatMap((suggestion) =>
528
+ Array.isArray(suggestion.directories) ? suggestion.directories.map(String) : []);
529
+ const values = [...new Set([...rules, ...directories].filter(Boolean))];
530
+ const destinations = new Set(suggestions.map((suggestion) => suggestion.destination));
531
+ const scope = destinations.has("userSettings")
532
+ ? "모든 프로젝트에서"
533
+ : destinations.has("projectSettings") || destinations.has("localSettings")
534
+ ? "이 프로젝트에서"
535
+ : "이번 세션에서";
536
+ return values.length
537
+ ? `${scope} 항상 허용: ${values.join(", ")}`
538
+ : `${scope} 다시 묻지 않기`;
539
+ }
540
540
 
541
541
  async function requestToolPermission(toolName, input, permission) {
542
542
  if (toolName === "AskUserQuestion") {
@@ -586,43 +586,43 @@ async function requestToolPermission(toolName, input, permission) {
586
586
  return { behavior: "allow", updatedInput: { ...input, answers } };
587
587
  }
588
588
 
589
- // Claude calls this callback only after its selected mode and permission rules
590
- // decide that a human answer is needed. Forward every such request to the host;
591
- // auto-allowing the ordinary cases here would silently defeat default/auto mode.
592
- const planApproval = toolName === "ExitPlanMode";
593
- const persistentApprovalLabel = permissionSuggestionLabel(permission.suggestions);
594
- const common = {
595
- claudePermission: true,
596
- title: permission.title || permission.displayName,
597
- persistentApprovalLabel,
598
- };
599
-
600
- let method = "item/permissions/requestApproval";
601
- let params = {
602
- ...common,
603
- reason: permission.decisionReason || permission.description || permission.title,
604
- permissions: { tool: toolName, blockedPath: permission.blockedPath },
605
- };
606
- if (planApproval) {
607
- params = {
608
- ...common,
609
- reason: input.plan || permission.description || "계획대로 진행할까요?",
610
- permissions: { tool: toolName },
611
- };
612
- } else if (toolName === "Bash") {
613
- method = "item/commandExecution/requestApproval";
614
- params = {
615
- ...common,
616
- command: input.command || "command",
617
- cwd: input.cwd,
618
- reason: permission.decisionReason || permission.description,
589
+ // Claude calls this callback only after its selected mode and permission rules
590
+ // decide that a human answer is needed. Forward every such request to the host;
591
+ // auto-allowing the ordinary cases here would silently defeat default/auto mode.
592
+ const planApproval = toolName === "ExitPlanMode";
593
+ const persistentApprovalLabel = permissionSuggestionLabel(permission.suggestions);
594
+ const common = {
595
+ claudePermission: true,
596
+ title: permission.title || permission.displayName,
597
+ persistentApprovalLabel,
598
+ };
599
+
600
+ let method = "item/permissions/requestApproval";
601
+ let params = {
602
+ ...common,
603
+ reason: permission.decisionReason || permission.description || permission.title,
604
+ permissions: { tool: toolName, blockedPath: permission.blockedPath },
605
+ };
606
+ if (planApproval) {
607
+ params = {
608
+ ...common,
609
+ reason: input.plan || permission.description || "계획대로 진행할까요?",
610
+ permissions: { tool: toolName },
611
+ };
612
+ } else if (toolName === "Bash") {
613
+ method = "item/commandExecution/requestApproval";
614
+ params = {
615
+ ...common,
616
+ command: input.command || "command",
617
+ cwd: input.cwd,
618
+ reason: permission.decisionReason || permission.description,
619
619
  };
620
620
  } else if (["Edit", "Write", "NotebookEdit"].includes(toolName)) {
621
- method = "item/fileChange/requestApproval";
622
- params = {
623
- ...common,
624
- grantRoot: permission.blockedPath || input.file_path || input.notebook_path,
625
- reason: permission.decisionReason || permission.description,
621
+ method = "item/fileChange/requestApproval";
622
+ params = {
623
+ ...common,
624
+ grantRoot: permission.blockedPath || input.file_path || input.notebook_path,
625
+ reason: permission.decisionReason || permission.description,
626
626
  };
627
627
  }
628
628
  const response = await hostRequest(method, params, permission.signal);
@@ -800,7 +800,7 @@ async function claudePluginDetail(params) {
800
800
  };
801
801
  }
802
802
 
803
- async function claudeSkills(params) {
803
+ async function claudeSkills(params) {
804
804
  const installed = await runClaudeJson(params, ["plugin", "list", "--json"]);
805
805
  const skills = [];
806
806
  for (const plugin of Array.isArray(installed) ? installed : []) {
@@ -817,48 +817,48 @@ async function claudeSkills(params) {
817
817
  }
818
818
  } catch { /* Plugins do not have to provide skills. */ }
819
819
  }
820
- return { data: [{ cwd: params.cwd || process.cwd(), skills }] };
821
- }
822
-
823
- function claudeMcpStatusValue(statuses) {
824
- return {
825
- data: (Array.isArray(statuses) ? statuses : []).map((server) => ({
826
- name: String(server?.name || "MCP"),
827
- serverInfo: server?.serverInfo
828
- ? {
829
- title: String(server.serverInfo.name || server.name || "MCP"),
830
- version: String(server.serverInfo.version || ""),
831
- }
832
- : null,
833
- tools: Object.fromEntries(
834
- (Array.isArray(server?.tools) ? server.tools : [])
835
- .filter((tool) => tool?.name)
836
- .map((tool) => [String(tool.name), tool]),
837
- ),
838
- resources: [],
839
- authStatus: server?.status === "needs-auth"
840
- ? "notLoggedIn"
841
- : server?.status === "connected"
842
- ? "unsupported"
843
- : String(server?.status || "unknown"),
844
- status: String(server?.status || "unknown"),
845
- ...(server?.error ? { error: String(server.error) } : {}),
846
- })),
847
- };
848
- }
849
-
850
- async function claudeMcpStatus(params) {
851
- const session = lookupSession(params.threadId || params.sessionId);
852
- if (!session) {
853
- return {
854
- data: [],
855
- unavailableReason: "Claude 세션이 아직 시작되지 않았습니다.",
856
- };
857
- }
858
- return claudeMcpStatusValue(await session.query.mcpServerStatus());
859
- }
860
-
861
- function isQuestionDeliveryError(error) {
820
+ return { data: [{ cwd: params.cwd || process.cwd(), skills }] };
821
+ }
822
+
823
+ function claudeMcpStatusValue(statuses) {
824
+ return {
825
+ data: (Array.isArray(statuses) ? statuses : []).map((server) => ({
826
+ name: String(server?.name || "MCP"),
827
+ serverInfo: server?.serverInfo
828
+ ? {
829
+ title: String(server.serverInfo.name || server.name || "MCP"),
830
+ version: String(server.serverInfo.version || ""),
831
+ }
832
+ : null,
833
+ tools: Object.fromEntries(
834
+ (Array.isArray(server?.tools) ? server.tools : [])
835
+ .filter((tool) => tool?.name)
836
+ .map((tool) => [String(tool.name), tool]),
837
+ ),
838
+ resources: [],
839
+ authStatus: server?.status === "needs-auth"
840
+ ? "notLoggedIn"
841
+ : server?.status === "connected"
842
+ ? "unsupported"
843
+ : String(server?.status || "unknown"),
844
+ status: String(server?.status || "unknown"),
845
+ ...(server?.error ? { error: String(server.error) } : {}),
846
+ })),
847
+ };
848
+ }
849
+
850
+ async function claudeMcpStatus(params) {
851
+ const session = lookupSession(params.threadId || params.sessionId);
852
+ if (!session) {
853
+ return {
854
+ data: [],
855
+ unavailableReason: "Claude 세션이 아직 시작되지 않았습니다.",
856
+ };
857
+ }
858
+ return claudeMcpStatusValue(await session.query.mcpServerStatus());
859
+ }
860
+
861
+ function isQuestionDeliveryError(error) {
862
862
  return error?.code === -32700
863
863
  || String(error?.message || error).includes("사용자 입력 화면에 전달하지 못했습니다");
864
864
  }
@@ -895,8 +895,8 @@ async function createSession(params, resumeId) {
895
895
  turnSequence: 1,
896
896
  itemSequence: 1,
897
897
  streamBlocks: new Map(),
898
- tools: new Map(),
899
- permissionDenials: [],
898
+ tools: new Map(),
899
+ permissionDenials: [],
900
900
  tasks: new Map(),
901
901
  planCreatePending: false,
902
902
  subagents: new Map(),
@@ -1802,16 +1802,16 @@ function toolOutput(content, structured) {
1802
1802
  return content == null ? "" : JSON.stringify(content, null, 2);
1803
1803
  }
1804
1804
 
1805
- async function processResult(session, message) {
1806
- if (!session.turn) return;
1807
- for (const denial of Array.isArray(message.permission_denials) ? message.permission_denials : []) {
1808
- rememberPermissionDenial(session, {
1809
- tool: denial.tool_name,
1810
- toolUseId: denial.tool_use_id,
1811
- input: denial.tool_input,
1812
- });
1813
- }
1814
- const interrupted = session.turn.interruptRequested === true;
1805
+ async function processResult(session, message) {
1806
+ if (!session.turn) return;
1807
+ for (const denial of Array.isArray(message.permission_denials) ? message.permission_denials : []) {
1808
+ rememberPermissionDenial(session, {
1809
+ tool: denial.tool_name,
1810
+ toolUseId: denial.tool_use_id,
1811
+ input: denial.tool_input,
1812
+ });
1813
+ }
1814
+ const interrupted = session.turn.interruptRequested === true;
1815
1815
  const totals = [...Object.values(message.modelUsage || {})].reduce((sum, usage) => ({
1816
1816
  inputTokens: sum.inputTokens + Number(usage.inputTokens || 0) + Number(usage.cacheReadInputTokens || 0) + Number(usage.cacheCreationInputTokens || 0),
1817
1817
  cachedInputTokens: sum.cachedInputTokens + Number(usage.cacheReadInputTokens || 0),
@@ -1830,42 +1830,42 @@ async function processResult(session, message) {
1830
1830
  modelContextWindow: totals.contextWindow || session.lastContextWindow || undefined,
1831
1831
  },
1832
1832
  });
1833
- const error = message.is_error && !interrupted
1833
+ const error = message.is_error && !interrupted
1834
1834
  ? { message: message.errors?.join("\n") || message.stop_reason || "Claude 실행 실패" }
1835
1835
  : null;
1836
- finishTurn(session, error, message.duration_ms);
1837
- if (session.restorePermissionMode) {
1838
- const restore = session.restorePermissionMode;
1839
- session.restorePermissionMode = null;
1840
- await applyPermissionMode(session, restore);
1841
- }
1836
+ finishTurn(session, error, message.duration_ms);
1837
+ if (session.restorePermissionMode) {
1838
+ const restore = session.restorePermissionMode;
1839
+ session.restorePermissionMode = null;
1840
+ await applyPermissionMode(session, restore);
1841
+ }
1842
1842
  notify("claude/account/updated", {
1843
1843
  threadId: session.id,
1844
1844
  account: await safeAccount(session.query),
1845
1845
  usage: await safeUsage(session.query),
1846
1846
  });
1847
- await runPendingPrompt(session);
1848
- }
1849
-
1850
- function rememberPermissionDenial(session, denial) {
1851
- const toolUseId = String(denial.toolUseId || "");
1852
- const existing = toolUseId
1853
- ? session.permissionDenials.find((candidate) => candidate.toolUseId === toolUseId)
1854
- : null;
1855
- if (existing) {
1856
- existing.tool = String(denial.tool || existing.tool || "Tool");
1857
- existing.reason = String(denial.reason || existing.reason || "");
1858
- if (denial.input && typeof denial.input === "object") existing.input = denial.input;
1859
- return;
1860
- }
1861
- session.permissionDenials.push({
1862
- tool: String(denial.tool || "Tool"),
1863
- toolUseId,
1864
- reason: String(denial.reason || ""),
1865
- input: denial.input && typeof denial.input === "object" ? denial.input : {},
1866
- });
1867
- if (session.permissionDenials.length > 20) session.permissionDenials.shift();
1868
- }
1847
+ await runPendingPrompt(session);
1848
+ }
1849
+
1850
+ function rememberPermissionDenial(session, denial) {
1851
+ const toolUseId = String(denial.toolUseId || "");
1852
+ const existing = toolUseId
1853
+ ? session.permissionDenials.find((candidate) => candidate.toolUseId === toolUseId)
1854
+ : null;
1855
+ if (existing) {
1856
+ existing.tool = String(denial.tool || existing.tool || "Tool");
1857
+ existing.reason = String(denial.reason || existing.reason || "");
1858
+ if (denial.input && typeof denial.input === "object") existing.input = denial.input;
1859
+ return;
1860
+ }
1861
+ session.permissionDenials.push({
1862
+ tool: String(denial.tool || "Tool"),
1863
+ toolUseId,
1864
+ reason: String(denial.reason || ""),
1865
+ input: denial.input && typeof denial.input === "object" ? denial.input : {},
1866
+ });
1867
+ if (session.permissionDenials.length > 20) session.permissionDenials.shift();
1868
+ }
1869
1869
 
1870
1870
  // The turn that was waiting starts on its own, so the host sees it exactly like a
1871
1871
  // prompt sent the moment the previous turn ended.
@@ -1908,16 +1908,16 @@ async function consume(session) {
1908
1908
  await processStreamEvent(session, message);
1909
1909
  } else if (message.type === "assistant") processAssistant(session, message);
1910
1910
  else if (message.type === "user") processUser(session, message);
1911
- else if (message.type === "result") await processResult(session, message);
1912
- else if (message.type === "system" && message.subtype === "compact_boundary") {
1913
- notify("thread/compacted", { threadId: session.id });
1914
- } else if (message.type === "system" && message.subtype === "permission_denied") {
1915
- rememberPermissionDenial(session, {
1916
- tool: message.tool_name,
1917
- toolUseId: message.tool_use_id,
1918
- reason: message.decision_reason || message.decision_reason_type,
1919
- });
1920
- } else if (message.type === "rate_limit_event") {
1911
+ else if (message.type === "result") await processResult(session, message);
1912
+ else if (message.type === "system" && message.subtype === "compact_boundary") {
1913
+ notify("thread/compacted", { threadId: session.id });
1914
+ } else if (message.type === "system" && message.subtype === "permission_denied") {
1915
+ rememberPermissionDenial(session, {
1916
+ tool: message.tool_name,
1917
+ toolUseId: message.tool_use_id,
1918
+ reason: message.decision_reason || message.decision_reason_type,
1919
+ });
1920
+ } else if (message.type === "rate_limit_event") {
1921
1921
  notify("claude/account/updated", { threadId: session.id, rateLimitInfo: message.rate_limit_info });
1922
1922
  } else if (message.type === "system" && message.subtype === "api_retry") {
1923
1923
  notify("warning", { threadId: session.id, provider: "Claude", message: `Claude API 재시도 ${message.attempt}/${message.max_retries}` });
@@ -1993,19 +1993,19 @@ async function runPrompt(session, params) {
1993
1993
  await session.query.applyFlagSettings({ effortLevel: effort });
1994
1994
  }
1995
1995
  session.effort = effort;
1996
- const permissionRejection = await applyPermissionMode(session, params.permissionMode);
1997
- if (permissionRejection) {
1998
- notify("claude/permissionMode/rejected", {
1999
- threadId: visibleSession(session.id),
2000
- permissionMode: params.permissionMode,
2001
- effectivePermissionMode: session.permissionMode,
2002
- message: permissionRejection,
2003
- });
2004
- }
2005
- if (params.restorePermissionMode) {
2006
- session.restorePermissionMode = permissionMode(params.restorePermissionMode);
2007
- }
2008
- const content = await inputContent(params.input, params.handoffContext);
1996
+ const permissionRejection = await applyPermissionMode(session, params.permissionMode);
1997
+ if (permissionRejection) {
1998
+ notify("claude/permissionMode/rejected", {
1999
+ threadId: visibleSession(session.id),
2000
+ permissionMode: params.permissionMode,
2001
+ effectivePermissionMode: session.permissionMode,
2002
+ message: permissionRejection,
2003
+ });
2004
+ }
2005
+ if (params.restorePermissionMode) {
2006
+ session.restorePermissionMode = permissionMode(params.restorePermissionMode);
2007
+ }
2008
+ const content = await inputContent(params.input, params.handoffContext);
2009
2009
  const turnId = beginTurn(session, params.input);
2010
2010
  session.queue.push({
2011
2011
  type: "user",
@@ -2274,10 +2274,10 @@ async function readableCwd(id, cwd) {
2274
2274
  return await transcriptCwd(id) || cwd;
2275
2275
  }
2276
2276
 
2277
- async function dispatch(method, params = {}) {
2278
- if (method === "model/list") return loadModelCatalog(params);
2279
- if (method === "mcpServerStatus/list") return claudeMcpStatus(params);
2280
- if (method === "plugin/list") return claudePluginCatalog(params);
2277
+ async function dispatch(method, params = {}) {
2278
+ if (method === "model/list") return loadModelCatalog(params);
2279
+ if (method === "mcpServerStatus/list") return claudeMcpStatus(params);
2280
+ if (method === "plugin/list") return claudePluginCatalog(params);
2281
2281
  if (method === "plugin/installed") return claudePluginCatalog(params, true);
2282
2282
  if (method === "plugin/read") return claudePluginDetail(params);
2283
2283
  if (method === "plugin/install") {
@@ -2327,24 +2327,24 @@ async function dispatch(method, params = {}) {
2327
2327
  }
2328
2328
  if (method === "skills/list") return claudeSkills(params);
2329
2329
  if (method === "app/list") return { data: [] };
2330
- if (method === "plugin/reload") {
2331
- return { message: "Claude 플러그인 설정을 다시 읽었습니다. 새 대화부터 적용됩니다." };
2332
- }
2333
- if (method === "permissions/status") return claudePermissionStatus(params);
2334
- if (method === "permissions/update") return updateClaudePermission(params);
2335
- if (method === "permissions/auto-mode") return setClaudeAutoModeDisabled(params);
2336
- if (method === "permissions/retry") return retryClaudePermission(params);
2337
- if (method === "session/permissionMode") {
2338
- const session = lookupSession(params.sessionId);
2339
- // A session that has not started yet picks the mode up from its first turn.
2340
- if (!session) return { permissionMode: permissionMode(params.permissionMode) };
2341
- session.restorePermissionMode = null;
2342
- const rejection = await applyPermissionMode(session, params.permissionMode);
2343
- return {
2344
- permissionMode: session.permissionMode,
2345
- ...(rejection ? { rejection } : {}),
2346
- };
2347
- }
2330
+ if (method === "plugin/reload") {
2331
+ return { message: "Claude 플러그인 설정을 다시 읽었습니다. 새 대화부터 적용됩니다." };
2332
+ }
2333
+ if (method === "permissions/status") return claudePermissionStatus(params);
2334
+ if (method === "permissions/update") return updateClaudePermission(params);
2335
+ if (method === "permissions/auto-mode") return setClaudeAutoModeDisabled(params);
2336
+ if (method === "permissions/retry") return retryClaudePermission(params);
2337
+ if (method === "session/permissionMode") {
2338
+ const session = lookupSession(params.sessionId);
2339
+ // A session that has not started yet picks the mode up from its first turn.
2340
+ if (!session) return { permissionMode: permissionMode(params.permissionMode) };
2341
+ session.restorePermissionMode = null;
2342
+ const rejection = await applyPermissionMode(session, params.permissionMode);
2343
+ return {
2344
+ permissionMode: session.permissionMode,
2345
+ ...(rejection ? { rejection } : {}),
2346
+ };
2347
+ }
2348
2348
  if (method === "session/start") {
2349
2349
  const { session, account, usage } = await createSession(params);
2350
2350
  return {
@@ -2497,12 +2497,12 @@ async function dispatch(method, params = {}) {
2497
2497
  throw new Error(`지원하지 않는 Claude 브리지 메서드: ${method}`);
2498
2498
  }
2499
2499
 
2500
- async function runSelfTest() {
2501
- if (permissionMode("dontAsk") !== "dontAsk"
2502
- || permissionMode("not-a-mode", "auto") !== "auto") {
2503
- throw new Error("Claude permission mode self-test failed");
2504
- }
2505
- const pluginCatalog = buildClaudePluginCatalog(
2500
+ async function runSelfTest() {
2501
+ if (permissionMode("dontAsk") !== "dontAsk"
2502
+ || permissionMode("not-a-mode", "auto") !== "auto") {
2503
+ throw new Error("Claude permission mode self-test failed");
2504
+ }
2505
+ const pluginCatalog = buildClaudePluginCatalog(
2506
2506
  [{ id: "cloudflare@official", enabled: true, scope: "user" }],
2507
2507
  [{
2508
2508
  pluginId: "cloudflare@official",
@@ -2513,29 +2513,29 @@ async function runSelfTest() {
2513
2513
  [{ name: "official", installLocation: "/tmp/official" }],
2514
2514
  );
2515
2515
  const plugin = pluginCatalog.marketplaces[0]?.plugins[0];
2516
- if (plugin?.id !== "cloudflare@official"
2516
+ if (plugin?.id !== "cloudflare@official"
2517
2517
  || plugin?.name !== "cloudflare@official"
2518
2518
  || plugin?.interface?.displayName !== "cloudflare"
2519
2519
  || plugin?.installed !== true
2520
2520
  || plugin?.enabled !== true) {
2521
- throw new Error(`Claude plugin catalogue self-test failed: ${JSON.stringify(pluginCatalog)}`);
2522
- }
2523
- const mcpStatus = claudeMcpStatusValue([
2524
- {
2525
- name: "context7",
2526
- status: "connected",
2527
- serverInfo: { name: "Context7", version: "1.0.0" },
2528
- tools: [{ name: "resolve" }, { name: "docs" }],
2529
- },
2530
- { name: "figma", status: "needs-auth", tools: [] },
2531
- ]).data;
2532
- if (mcpStatus[0]?.name !== "context7"
2533
- || Object.keys(mcpStatus[0]?.tools || {}).length !== 2
2534
- || mcpStatus[0]?.status !== "connected"
2535
- || mcpStatus[1]?.authStatus !== "notLoggedIn") {
2536
- throw new Error(`Claude MCP status self-test failed: ${JSON.stringify(mcpStatus)}`);
2537
- }
2538
- const user = (uuid, text) => ({
2521
+ throw new Error(`Claude plugin catalogue self-test failed: ${JSON.stringify(pluginCatalog)}`);
2522
+ }
2523
+ const mcpStatus = claudeMcpStatusValue([
2524
+ {
2525
+ name: "context7",
2526
+ status: "connected",
2527
+ serverInfo: { name: "Context7", version: "1.0.0" },
2528
+ tools: [{ name: "resolve" }, { name: "docs" }],
2529
+ },
2530
+ { name: "figma", status: "needs-auth", tools: [] },
2531
+ ]).data;
2532
+ if (mcpStatus[0]?.name !== "context7"
2533
+ || Object.keys(mcpStatus[0]?.tools || {}).length !== 2
2534
+ || mcpStatus[0]?.status !== "connected"
2535
+ || mcpStatus[1]?.authStatus !== "notLoggedIn") {
2536
+ throw new Error(`Claude MCP status self-test failed: ${JSON.stringify(mcpStatus)}`);
2537
+ }
2538
+ const user = (uuid, text) => ({
2539
2539
  type: "user",
2540
2540
  uuid,
2541
2541
  message: { role: "user", content: [{ type: "text", text }] },
package/package.json CHANGED
@@ -1,41 +1,41 @@
1
- {
2
- "name": "devez-vibe",
3
- "version": "1.3.20",
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.223"
40
- }
41
- }
1
+ {
2
+ "name": "devez-vibe",
3
+ "version": "1.3.22",
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.223"
40
+ }
41
+ }