devez-vibe 1.6.57 → 1.6.59
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 +122 -59
- package/package.json +46 -46
package/bin/dvz.exe
CHANGED
|
Binary file
|
|
@@ -357,34 +357,57 @@ function adoptSessionId(session, incoming) {
|
|
|
357
357
|
});
|
|
358
358
|
}
|
|
359
359
|
|
|
360
|
-
const
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
"plan",
|
|
364
|
-
"auto",
|
|
365
|
-
"dontAsk",
|
|
366
|
-
"bypassPermissions",
|
|
367
|
-
];
|
|
360
|
+
const BOOTSTRAP_PERMISSION_MODE = "default";
|
|
361
|
+
const PREFERRED_PERMISSION_MODE = "bypassPermissions";
|
|
362
|
+
const FALLBACK_PERMISSION_MODE = "auto";
|
|
368
363
|
|
|
369
|
-
function
|
|
370
|
-
|
|
371
|
-
return PERMISSION_MODES.includes(mode) ? mode : fallback;
|
|
364
|
+
function permissionError(error) {
|
|
365
|
+
return error?.message || String(error);
|
|
372
366
|
}
|
|
373
367
|
|
|
374
|
-
//
|
|
375
|
-
//
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
if (
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
session.permissionMode = mode;
|
|
368
|
+
// No tool-capable turn is admitted until the SDK has confirmed bypass mode or,
|
|
369
|
+
// when policy rejects it, confirmed auto mode. A double rejection fails the
|
|
370
|
+
// session instead of silently continuing in the bootstrap default mode.
|
|
371
|
+
async function applyPermissionMode(session) {
|
|
372
|
+
if (session.permissionModeVerified
|
|
373
|
+
&& (session.permissionMode === PREFERRED_PERMISSION_MODE
|
|
374
|
+
|| (session.bypassUnavailable && session.permissionMode === FALLBACK_PERMISSION_MODE))) {
|
|
382
375
|
return null;
|
|
376
|
+
}
|
|
377
|
+
if (!session.bypassUnavailable) {
|
|
378
|
+
try {
|
|
379
|
+
await session.query.setPermissionMode(PREFERRED_PERMISSION_MODE);
|
|
380
|
+
session.permissionMode = PREFERRED_PERMISSION_MODE;
|
|
381
|
+
session.permissionModeVerified = true;
|
|
382
|
+
return null;
|
|
383
|
+
} catch (error) {
|
|
384
|
+
session.bypassUnavailable = true;
|
|
385
|
+
session.bypassRejection = permissionError(error);
|
|
386
|
+
}
|
|
387
|
+
}
|
|
388
|
+
try {
|
|
389
|
+
await session.query.setPermissionMode(FALLBACK_PERMISSION_MODE);
|
|
390
|
+
session.permissionMode = FALLBACK_PERMISSION_MODE;
|
|
391
|
+
session.permissionModeVerified = true;
|
|
392
|
+
return session.bypassRejection;
|
|
383
393
|
} catch (error) {
|
|
384
|
-
|
|
394
|
+
session.permissionModeVerified = false;
|
|
395
|
+
throw new Error(
|
|
396
|
+
`Claude bypass 모드가 거부되었고 auto 폴백도 적용하지 못했습니다: ${permissionError(error)}`,
|
|
397
|
+
);
|
|
385
398
|
}
|
|
386
399
|
}
|
|
387
400
|
|
|
401
|
+
function notifyPermissionFallback(session, rejection) {
|
|
402
|
+
if (!rejection) return;
|
|
403
|
+
notify("claude/permissionMode/rejected", {
|
|
404
|
+
threadId: visibleSession(session.id),
|
|
405
|
+
permissionMode: PREFERRED_PERMISSION_MODE,
|
|
406
|
+
effectivePermissionMode: FALLBACK_PERMISSION_MODE,
|
|
407
|
+
message: `Bypass 모드를 사용할 수 없어 auto 모드로 실행합니다: ${rejection}`,
|
|
408
|
+
});
|
|
409
|
+
}
|
|
410
|
+
|
|
388
411
|
async function claudePermissionStatus(params) {
|
|
389
412
|
const resolved = await resolveSettings({
|
|
390
413
|
cwd: params.cwd || process.cwd(),
|
|
@@ -396,9 +419,7 @@ async function claudePermissionStatus(params) {
|
|
|
396
419
|
|| effective.bypassPermissionsModeAccepted === true;
|
|
397
420
|
const bypassAvailable = permissions.disableBypassPermissionsMode !== "disable" && bypassAccepted;
|
|
398
421
|
const autoDisabled = effective.disableAutoMode === "disable";
|
|
399
|
-
|
|
400
|
-
if ((defaultMode === "bypassPermissions" && !bypassAvailable)
|
|
401
|
-
|| (defaultMode === "auto" && autoDisabled)) defaultMode = "default";
|
|
422
|
+
const defaultMode = bypassAvailable ? PREFERRED_PERMISSION_MODE : FALLBACK_PERMISSION_MODE;
|
|
402
423
|
const rules = [];
|
|
403
424
|
const directories = [];
|
|
404
425
|
for (const source of resolved.sources) {
|
|
@@ -516,16 +537,14 @@ async function retryClaudePermission(params) {
|
|
|
516
537
|
if (!session) throw new Error("재시도할 Claude 세션을 찾을 수 없습니다.");
|
|
517
538
|
const tool = String(params.tool || "tool");
|
|
518
539
|
const input = params.input && typeof params.input === "object" ? params.input : {};
|
|
519
|
-
const previousMode = session.permissionMode;
|
|
520
540
|
return startPrompt({
|
|
521
541
|
sessionId: session.id,
|
|
522
|
-
permissionMode:
|
|
523
|
-
restorePermissionMode: previousMode === "auto" ? "auto" : null,
|
|
542
|
+
permissionMode: session.permissionMode,
|
|
524
543
|
input: [{
|
|
525
544
|
type: "text",
|
|
526
545
|
text: [
|
|
527
546
|
`The user selected the denied ${tool} action in /permissions and asked to retry it.`,
|
|
528
|
-
|
|
547
|
+
`Retry that action now under ${session.permissionMode} mode.`,
|
|
529
548
|
`Original tool input: ${JSON.stringify(input)}`,
|
|
530
549
|
].join("\n"),
|
|
531
550
|
}],
|
|
@@ -566,10 +585,11 @@ function makeOptions(params, sessionId, resume) {
|
|
|
566
585
|
const options = {
|
|
567
586
|
cwd: params.cwd || process.cwd(),
|
|
568
587
|
includePartialMessages: true,
|
|
569
|
-
|
|
570
|
-
//
|
|
571
|
-
|
|
572
|
-
//
|
|
588
|
+
// Initialization performs no tool work. The bridge verifies bypass or its
|
|
589
|
+
// auto fallback immediately afterwards and before exposing the session.
|
|
590
|
+
permissionMode: BOOTSTRAP_PERMISSION_MODE,
|
|
591
|
+
// Not a mode, a capability: the SDK refuses the preferred bypass transition
|
|
592
|
+
// outright unless the session was initialized with this allowance.
|
|
573
593
|
allowDangerouslySkipPermissions: true,
|
|
574
594
|
enableFileCheckpointing: true,
|
|
575
595
|
persistSession: true,
|
|
@@ -1137,7 +1157,10 @@ async function createSession(params, resumeId) {
|
|
|
1137
1157
|
cwd: params.cwd || process.cwd(),
|
|
1138
1158
|
model: visibleModel(params.model),
|
|
1139
1159
|
effort: params.effort || "",
|
|
1140
|
-
permissionMode:
|
|
1160
|
+
permissionMode: BOOTSTRAP_PERMISSION_MODE,
|
|
1161
|
+
permissionModeVerified: false,
|
|
1162
|
+
bypassUnavailable: false,
|
|
1163
|
+
bypassRejection: null,
|
|
1141
1164
|
models: [],
|
|
1142
1165
|
queue,
|
|
1143
1166
|
query: null,
|
|
@@ -1181,8 +1204,10 @@ async function createSession(params, resumeId) {
|
|
|
1181
1204
|
});
|
|
1182
1205
|
session.consumer = consumer;
|
|
1183
1206
|
let initialization;
|
|
1207
|
+
let permissionRejection;
|
|
1184
1208
|
try {
|
|
1185
1209
|
initialization = await agentQuery.initializationResult();
|
|
1210
|
+
permissionRejection = await applyPermissionMode(session);
|
|
1186
1211
|
} catch (error) {
|
|
1187
1212
|
sessions.delete(id);
|
|
1188
1213
|
queue.close();
|
|
@@ -1190,6 +1215,7 @@ async function createSession(params, resumeId) {
|
|
|
1190
1215
|
await Promise.race([consumer, new Promise((resolve) => setTimeout(resolve, 1000))]);
|
|
1191
1216
|
throw error;
|
|
1192
1217
|
}
|
|
1218
|
+
notifyPermissionFallback(session, permissionRejection);
|
|
1193
1219
|
session.models = Array.isArray(initialization.models) ? initialization.models : [];
|
|
1194
1220
|
const capabilities = modelCapabilities(session.models, params.model);
|
|
1195
1221
|
// A resumed session can only name its model as the resolved id the transcript
|
|
@@ -2332,11 +2358,6 @@ async function processResult(session, message) {
|
|
|
2332
2358
|
? { message: message.errors?.join("\n") || message.stop_reason || "Claude 실행 실패" }
|
|
2333
2359
|
: null;
|
|
2334
2360
|
finishTurn(session, error, message.duration_ms);
|
|
2335
|
-
if (session.restorePermissionMode) {
|
|
2336
|
-
const restore = session.restorePermissionMode;
|
|
2337
|
-
session.restorePermissionMode = null;
|
|
2338
|
-
await applyPermissionMode(session, restore);
|
|
2339
|
-
}
|
|
2340
2361
|
notify("claude/account/updated", {
|
|
2341
2362
|
threadId: session.id,
|
|
2342
2363
|
account: await safeAccount(session.query),
|
|
@@ -2569,6 +2590,9 @@ async function runPrompt(session, params) {
|
|
|
2569
2590
|
const model = stripClaudeModel(params.model);
|
|
2570
2591
|
await session.query.setModel(model);
|
|
2571
2592
|
session.model = visibleModel(params.model);
|
|
2593
|
+
// Model switches can change which permission modes policy accepts. Recheck
|
|
2594
|
+
// the preferred/fallback pair before admitting the turn.
|
|
2595
|
+
session.permissionModeVerified = false;
|
|
2572
2596
|
}
|
|
2573
2597
|
session.steerPending = 0;
|
|
2574
2598
|
const effort = supportedEffort(modelCapabilities(session.models, params.model || session.model), params.effort);
|
|
@@ -2576,18 +2600,8 @@ async function runPrompt(session, params) {
|
|
|
2576
2600
|
await session.query.applyFlagSettings({ effortLevel: effort });
|
|
2577
2601
|
}
|
|
2578
2602
|
session.effort = effort;
|
|
2579
|
-
const permissionRejection = await applyPermissionMode(session
|
|
2580
|
-
|
|
2581
|
-
notify("claude/permissionMode/rejected", {
|
|
2582
|
-
threadId: visibleSession(session.id),
|
|
2583
|
-
permissionMode: params.permissionMode,
|
|
2584
|
-
effectivePermissionMode: session.permissionMode,
|
|
2585
|
-
message: permissionRejection,
|
|
2586
|
-
});
|
|
2587
|
-
}
|
|
2588
|
-
if (params.restorePermissionMode) {
|
|
2589
|
-
session.restorePermissionMode = permissionMode(params.restorePermissionMode);
|
|
2590
|
-
}
|
|
2603
|
+
const permissionRejection = await applyPermissionMode(session);
|
|
2604
|
+
notifyPermissionFallback(session, permissionRejection);
|
|
2591
2605
|
const content = await inputContent(params.input, params.handoffContext);
|
|
2592
2606
|
const turnId = beginTurn(session, params.input);
|
|
2593
2607
|
session.queue.push({
|
|
@@ -3032,10 +3046,9 @@ async function dispatch(method, params = {}) {
|
|
|
3032
3046
|
if (method === "permissions/retry") return retryClaudePermission(params);
|
|
3033
3047
|
if (method === "session/permissionMode") {
|
|
3034
3048
|
const session = lookupSession(params.sessionId);
|
|
3035
|
-
|
|
3036
|
-
|
|
3037
|
-
session
|
|
3038
|
-
const rejection = await applyPermissionMode(session, params.permissionMode);
|
|
3049
|
+
if (!session) return { permissionMode: PREFERRED_PERMISSION_MODE };
|
|
3050
|
+
const rejection = await applyPermissionMode(session);
|
|
3051
|
+
notifyPermissionFallback(session, rejection);
|
|
3039
3052
|
return {
|
|
3040
3053
|
permissionMode: session.permissionMode,
|
|
3041
3054
|
...(rejection ? { rejection } : {}),
|
|
@@ -3203,7 +3216,54 @@ async function dispatch(method, params = {}) {
|
|
|
3203
3216
|
throw new Error(`지원하지 않는 Claude 브리지 메서드: ${method}`);
|
|
3204
3217
|
}
|
|
3205
3218
|
|
|
3219
|
+
async function runPermissionModeSelfTest() {
|
|
3220
|
+
const fakeSession = (setPermissionMode) => ({
|
|
3221
|
+
id: "permission-mode-self-test",
|
|
3222
|
+
permissionMode: BOOTSTRAP_PERMISSION_MODE,
|
|
3223
|
+
permissionModeVerified: false,
|
|
3224
|
+
bypassUnavailable: false,
|
|
3225
|
+
bypassRejection: null,
|
|
3226
|
+
query: { setPermissionMode },
|
|
3227
|
+
});
|
|
3228
|
+
|
|
3229
|
+
const preferredCalls = [];
|
|
3230
|
+
const preferred = fakeSession(async (mode) => preferredCalls.push(mode));
|
|
3231
|
+
const preferredRejection = await applyPermissionMode(preferred);
|
|
3232
|
+
if (preferredRejection !== null
|
|
3233
|
+
|| preferred.permissionMode !== PREFERRED_PERMISSION_MODE
|
|
3234
|
+
|| preferredCalls.join(",") !== PREFERRED_PERMISSION_MODE) {
|
|
3235
|
+
throw new Error(`Claude bypass permission self-test failed: ${JSON.stringify(preferredCalls)}`);
|
|
3236
|
+
}
|
|
3237
|
+
|
|
3238
|
+
const fallbackCalls = [];
|
|
3239
|
+
const fallback = fakeSession(async (mode) => {
|
|
3240
|
+
fallbackCalls.push(mode);
|
|
3241
|
+
if (mode === PREFERRED_PERMISSION_MODE) throw new Error("organization policy");
|
|
3242
|
+
});
|
|
3243
|
+
const fallbackRejection = await applyPermissionMode(fallback);
|
|
3244
|
+
await applyPermissionMode(fallback);
|
|
3245
|
+
if (fallbackRejection !== "organization policy"
|
|
3246
|
+
|| fallback.permissionMode !== FALLBACK_PERMISSION_MODE
|
|
3247
|
+
|| fallbackCalls.join(",") !== `${PREFERRED_PERMISSION_MODE},${FALLBACK_PERMISSION_MODE}`) {
|
|
3248
|
+
throw new Error(`Claude auto fallback self-test failed: ${JSON.stringify(fallbackCalls)}`);
|
|
3249
|
+
}
|
|
3250
|
+
|
|
3251
|
+
const rejected = fakeSession(async (mode) => {
|
|
3252
|
+
throw new Error(`${mode} rejected`);
|
|
3253
|
+
});
|
|
3254
|
+
let doubleRejection = "";
|
|
3255
|
+
try {
|
|
3256
|
+
await applyPermissionMode(rejected);
|
|
3257
|
+
} catch (error) {
|
|
3258
|
+
doubleRejection = permissionError(error);
|
|
3259
|
+
}
|
|
3260
|
+
if (!doubleRejection.includes("auto 폴백도 적용하지 못했습니다")) {
|
|
3261
|
+
throw new Error(`Claude permission double rejection self-test failed: ${doubleRejection}`);
|
|
3262
|
+
}
|
|
3263
|
+
}
|
|
3264
|
+
|
|
3206
3265
|
async function runSelfTest() {
|
|
3266
|
+
await runPermissionModeSelfTest();
|
|
3207
3267
|
const equivalentCwd = process.platform === "win32"
|
|
3208
3268
|
? sameCwd("D:\\Repo", "d:/repo/")
|
|
3209
3269
|
: sameCwd("/tmp/repo", "/tmp/repo/");
|
|
@@ -3215,12 +3275,9 @@ async function runSelfTest() {
|
|
|
3215
3275
|
if (!equivalentCwd || preview !== "세션 목록 질문") {
|
|
3216
3276
|
throw new Error(`Claude session list self-test failed: ${JSON.stringify({ equivalentCwd, preview })}`);
|
|
3217
3277
|
}
|
|
3218
|
-
|
|
3219
|
-
|
|
3220
|
-
|
|
3221
|
-
}
|
|
3222
|
-
const latestOptions = makeOptions({ cwd: process.cwd() }, "00000000-0000-4000-8000-000000000000");
|
|
3223
|
-
if (latestOptions.perTaskStopAffordance !== true
|
|
3278
|
+
const latestOptions = makeOptions({ cwd: process.cwd(), permissionMode: "plan" }, "00000000-0000-4000-8000-000000000000");
|
|
3279
|
+
if (latestOptions.permissionMode !== BOOTSTRAP_PERMISSION_MODE
|
|
3280
|
+
|| latestOptions.perTaskStopAffordance !== true
|
|
3224
3281
|
|| CLAUDE_TASK_TOOLS.some((tool) => !latestOptions.allowedTools.includes(tool))) {
|
|
3225
3282
|
throw new Error(`Claude latest SDK options self-test failed: ${JSON.stringify(latestOptions.allowedTools)}`);
|
|
3226
3283
|
}
|
|
@@ -4231,6 +4288,12 @@ async function runSelfTest() {
|
|
|
4231
4288
|
process.stdout.write("Claude bridge self-test passed\n");
|
|
4232
4289
|
}
|
|
4233
4290
|
|
|
4291
|
+
if (process.argv.includes("--permission-mode-self-test")) {
|
|
4292
|
+
await runPermissionModeSelfTest();
|
|
4293
|
+
process.stdout.write("권한 모드 자체 점검 통과\n");
|
|
4294
|
+
process.exit(0);
|
|
4295
|
+
}
|
|
4296
|
+
|
|
4234
4297
|
if (process.argv.includes("--self-test")) {
|
|
4235
4298
|
await runSelfTest();
|
|
4236
4299
|
process.exit(0);
|
package/package.json
CHANGED
|
@@ -1,46 +1,46 @@
|
|
|
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
|
-
"install-skills.mjs",
|
|
27
|
-
"skills/luna-loop/",
|
|
28
|
-
"README.md",
|
|
29
|
-
"LICENSE"
|
|
30
|
-
],
|
|
31
|
-
"os": [
|
|
32
|
-
"win32"
|
|
33
|
-
],
|
|
34
|
-
"cpu": [
|
|
35
|
-
"x64"
|
|
36
|
-
],
|
|
37
|
-
"engines": {
|
|
38
|
-
"node": ">=18"
|
|
39
|
-
},
|
|
40
|
-
"scripts": {
|
|
41
|
-
"postinstall": "node install-skills.mjs"
|
|
42
|
-
},
|
|
43
|
-
"dependencies": {
|
|
44
|
-
"@anthropic-ai/claude-agent-sdk": "0.3.
|
|
45
|
-
}
|
|
46
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"name": "devez-vibe",
|
|
3
|
+
"version": "1.6.59",
|
|
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
|
+
"install-skills.mjs",
|
|
27
|
+
"skills/luna-loop/",
|
|
28
|
+
"README.md",
|
|
29
|
+
"LICENSE"
|
|
30
|
+
],
|
|
31
|
+
"os": [
|
|
32
|
+
"win32"
|
|
33
|
+
],
|
|
34
|
+
"cpu": [
|
|
35
|
+
"x64"
|
|
36
|
+
],
|
|
37
|
+
"engines": {
|
|
38
|
+
"node": ">=18"
|
|
39
|
+
},
|
|
40
|
+
"scripts": {
|
|
41
|
+
"postinstall": "node install-skills.mjs"
|
|
42
|
+
},
|
|
43
|
+
"dependencies": {
|
|
44
|
+
"@anthropic-ai/claude-agent-sdk": "0.3.251"
|
|
45
|
+
}
|
|
46
|
+
}
|