devez-vibe 1.2.0 → 1.2.2
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 +83 -9
- package/package.json +1 -1
package/bin/dvz.exe
CHANGED
|
Binary file
|
|
@@ -104,6 +104,21 @@ function applyClaudeExecutable(options, params) {
|
|
|
104
104
|
options.pathToClaudeCodeExecutable = executable;
|
|
105
105
|
}
|
|
106
106
|
|
|
107
|
+
// The SDK model list carries no window size, so the status line would stay
|
|
108
|
+
// blank until a turn reports one — and a fresh session has no turn yet. Claude
|
|
109
|
+
// ships a 200k window, and the `[1m]` variants a 1M one.
|
|
110
|
+
function claudeContextWindow(...names) {
|
|
111
|
+
const oneMillion = names.some((name) => String(name || "").includes("[1m]"));
|
|
112
|
+
return oneMillion ? 1_000_000 : 200_000;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
function capabilityContextWindow(capabilities, ...names) {
|
|
116
|
+
const reported = Number(capabilities?.contextWindow || capabilities?.contextWindowSize || 0);
|
|
117
|
+
return reported > 0
|
|
118
|
+
? reported
|
|
119
|
+
: claudeContextWindow(...names, capabilities?.value, capabilities?.resolvedModel);
|
|
120
|
+
}
|
|
121
|
+
|
|
107
122
|
function modelCapabilities(models, model) {
|
|
108
123
|
const value = stripClaudeModel(model);
|
|
109
124
|
return models.find((candidate) => candidate.value === value || candidate.resolvedModel === value)
|
|
@@ -145,7 +160,7 @@ function catalogEntry(model, defaultResolvedModel) {
|
|
|
145
160
|
const efforts = model.supportsEffort && Array.isArray(model.supportedEffortLevels)
|
|
146
161
|
? model.supportedEffortLevels
|
|
147
162
|
: [];
|
|
148
|
-
const contextWindow =
|
|
163
|
+
const contextWindow = capabilityContextWindow(model, value, resolved);
|
|
149
164
|
return {
|
|
150
165
|
id: visibleModel(resolved),
|
|
151
166
|
model: visibleModel(value),
|
|
@@ -251,17 +266,46 @@ function adoptSessionId(session, incoming) {
|
|
|
251
266
|
sessionAliases.set(previous, real);
|
|
252
267
|
session.id = real;
|
|
253
268
|
sessions.set(real, session);
|
|
254
|
-
notify("
|
|
269
|
+
notify("claude/session/rebound", {
|
|
255
270
|
threadId: visibleSession(previous),
|
|
256
271
|
newThreadId: visibleSession(real),
|
|
257
272
|
});
|
|
258
273
|
}
|
|
259
274
|
|
|
275
|
+
const PERMISSION_MODES = ["default", "acceptEdits", "plan", "auto", "bypassPermissions"];
|
|
276
|
+
|
|
277
|
+
function permissionMode(requested, fallback = "default") {
|
|
278
|
+
const mode = String(requested || "");
|
|
279
|
+
return PERMISSION_MODES.includes(mode) ? mode : fallback;
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
// Moves a live session onto a mode the badge picked. A rejected mode — policy
|
|
283
|
+
// disables bypass, say — leaves the session on the one it already had.
|
|
284
|
+
async function applyPermissionMode(session, requested) {
|
|
285
|
+
const mode = permissionMode(requested, session.permissionMode || "default");
|
|
286
|
+
if (mode === session.permissionMode) return;
|
|
287
|
+
try {
|
|
288
|
+
await session.query.setPermissionMode(mode);
|
|
289
|
+
session.permissionMode = mode;
|
|
290
|
+
} catch (error) {
|
|
291
|
+
notify("claude/permissionMode/rejected", {
|
|
292
|
+
threadId: visibleSession(session.id),
|
|
293
|
+
permissionMode: mode,
|
|
294
|
+
message: error?.message || String(error),
|
|
295
|
+
});
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
|
|
260
299
|
function makeOptions(params, sessionId, resume) {
|
|
261
300
|
const options = {
|
|
262
301
|
cwd: params.cwd || process.cwd(),
|
|
263
302
|
includePartialMessages: true,
|
|
264
|
-
permissionMode:
|
|
303
|
+
permissionMode: permissionMode(params.permissionMode),
|
|
304
|
+
// Not a mode, a capability: the SDK refuses `bypassPermissions` outright
|
|
305
|
+
// unless the session was started with this. Devez Vibe already auto-allows
|
|
306
|
+
// tools through `canUseTool`, so allowing the mode to be *reachable* grants
|
|
307
|
+
// nothing the session did not already have.
|
|
308
|
+
allowDangerouslySkipPermissions: true,
|
|
265
309
|
enableFileCheckpointing: true,
|
|
266
310
|
persistSession: true,
|
|
267
311
|
settingSources: ["user", "project", "local"],
|
|
@@ -326,9 +370,13 @@ async function requestToolPermission(toolName, input, permission) {
|
|
|
326
370
|
return { behavior: "allow", updatedInput: { ...input, answers } };
|
|
327
371
|
}
|
|
328
372
|
|
|
373
|
+
// Plan mode only means anything if leaving it is the user's call — the CLI
|
|
374
|
+
// shows the plan and waits. The blanket allow below would answer for them.
|
|
375
|
+
const planApproval = toolName === "ExitPlanMode";
|
|
376
|
+
|
|
329
377
|
// Devez Vibe runs in its existing full-access profile. Claude's callback is
|
|
330
378
|
// still kept so AskUserQuestion and explicit user-authored ask rules reach UI.
|
|
331
|
-
if (!permission.matchedAskRule) {
|
|
379
|
+
if (!permission.matchedAskRule && !planApproval) {
|
|
332
380
|
return { behavior: "allow", updatedInput: input };
|
|
333
381
|
}
|
|
334
382
|
|
|
@@ -337,7 +385,12 @@ async function requestToolPermission(toolName, input, permission) {
|
|
|
337
385
|
reason: permission.decisionReason || permission.description || permission.title,
|
|
338
386
|
permissions: { tool: toolName, blockedPath: permission.blockedPath },
|
|
339
387
|
};
|
|
340
|
-
if (
|
|
388
|
+
if (planApproval) {
|
|
389
|
+
params = {
|
|
390
|
+
reason: input.plan || permission.description || "계획대로 진행할까요?",
|
|
391
|
+
permissions: { tool: toolName },
|
|
392
|
+
};
|
|
393
|
+
} else if (toolName === "Bash") {
|
|
341
394
|
method = "item/commandExecution/requestApproval";
|
|
342
395
|
params = {
|
|
343
396
|
command: input.command || "command",
|
|
@@ -372,6 +425,7 @@ async function createSession(params, resumeId) {
|
|
|
372
425
|
cwd: params.cwd || process.cwd(),
|
|
373
426
|
model: visibleModel(params.model),
|
|
374
427
|
effort: params.effort || "",
|
|
428
|
+
permissionMode: permissionMode(params.permissionMode),
|
|
375
429
|
models: [],
|
|
376
430
|
queue,
|
|
377
431
|
query: null,
|
|
@@ -476,7 +530,7 @@ function historyTokenUsage(messages, models, model) {
|
|
|
476
530
|
}
|
|
477
531
|
if (!counted) return null;
|
|
478
532
|
const capabilities = modelCapabilities(models, model);
|
|
479
|
-
const contextWindow =
|
|
533
|
+
const contextWindow = capabilityContextWindow(capabilities, model);
|
|
480
534
|
return {
|
|
481
535
|
total,
|
|
482
536
|
...(last ? { last } : {}),
|
|
@@ -535,8 +589,10 @@ function processAssistant(session, message) {
|
|
|
535
589
|
session.models,
|
|
536
590
|
message.message?.model || session.model,
|
|
537
591
|
);
|
|
538
|
-
session.lastContextWindow =
|
|
539
|
-
capabilities
|
|
592
|
+
session.lastContextWindow = capabilityContextWindow(
|
|
593
|
+
capabilities,
|
|
594
|
+
message.message?.model,
|
|
595
|
+
session.model,
|
|
540
596
|
);
|
|
541
597
|
const content = Array.isArray(message.message?.content) ? message.message.content : [];
|
|
542
598
|
for (const block of content) {
|
|
@@ -861,7 +917,9 @@ async function processResult(session, message) {
|
|
|
861
917
|
tokenUsage: {
|
|
862
918
|
total: totals,
|
|
863
919
|
...(session.lastContextUsage ? { last: session.lastContextUsage } : {}),
|
|
864
|
-
|
|
920
|
+
// `modelUsage` reports the window the turn actually ran under, so it wins
|
|
921
|
+
// over the size guessed from the model name.
|
|
922
|
+
modelContextWindow: totals.contextWindow || session.lastContextWindow || undefined,
|
|
865
923
|
},
|
|
866
924
|
});
|
|
867
925
|
const error = message.is_error && !interrupted
|
|
@@ -994,6 +1052,7 @@ async function runPrompt(session, params) {
|
|
|
994
1052
|
await session.query.applyFlagSettings({ effortLevel: effort });
|
|
995
1053
|
}
|
|
996
1054
|
session.effort = effort;
|
|
1055
|
+
await applyPermissionMode(session, params.permissionMode);
|
|
997
1056
|
const turnId = `claude-turn-${session.turnSequence++}-${randomUUID()}`;
|
|
998
1057
|
session.turn = { id: turnId, sawStreamText: false };
|
|
999
1058
|
session.lastContextUsage = null;
|
|
@@ -1116,6 +1175,13 @@ function historyTurns(messages) {
|
|
|
1116
1175
|
|
|
1117
1176
|
async function dispatch(method, params = {}) {
|
|
1118
1177
|
if (method === "model/list") return loadModelCatalog(params);
|
|
1178
|
+
if (method === "session/permissionMode") {
|
|
1179
|
+
const session = lookupSession(params.sessionId);
|
|
1180
|
+
// A session that has not started yet picks the mode up from its first turn.
|
|
1181
|
+
if (!session) return { permissionMode: permissionMode(params.permissionMode) };
|
|
1182
|
+
await applyPermissionMode(session, params.permissionMode);
|
|
1183
|
+
return { permissionMode: session.permissionMode };
|
|
1184
|
+
}
|
|
1119
1185
|
if (method === "session/start") {
|
|
1120
1186
|
const { session, account, usage } = await createSession(params);
|
|
1121
1187
|
return {
|
|
@@ -1300,6 +1366,14 @@ function runSelfTest() {
|
|
|
1300
1366
|
if (usage.totalTokens !== 68_802 || usage.inputTokens !== 68_502) {
|
|
1301
1367
|
throw new Error(`Claude usage self-test failed: ${JSON.stringify(usage)}`);
|
|
1302
1368
|
}
|
|
1369
|
+
const windows = [
|
|
1370
|
+
catalogEntry({ value: "opus[1m]", resolvedModel: "claude-opus-5[1m]" }, "").contextWindow,
|
|
1371
|
+
catalogEntry({ value: "sonnet", resolvedModel: "claude-sonnet-5" }, "").contextWindow,
|
|
1372
|
+
catalogEntry({ value: "haiku", resolvedModel: "x", contextWindow: 300_000 }, "").contextWindow,
|
|
1373
|
+
];
|
|
1374
|
+
if (windows.join(",") !== "1000000,200000,300000") {
|
|
1375
|
+
throw new Error(`Claude context window self-test failed: ${windows.join(",")}`);
|
|
1376
|
+
}
|
|
1303
1377
|
process.stdout.write("Claude bridge self-test passed\n");
|
|
1304
1378
|
}
|
|
1305
1379
|
|