jinzd-ai-cli 0.1.73 → 0.1.75
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/dist/{chunk-FEYESHOP.js → chunk-KDXXHXYU.js} +4 -2
- package/dist/{chunk-ABXJS3XB.js → chunk-MD2SRFU4.js} +14 -2
- package/dist/index.js +8 -13
- package/dist/{run-tests-MYRF47LA.js → run-tests-D5RGQY6A.js} +1 -1
- package/dist/{server-AAP2OMDQ.js → server-4ZYMNPYO.js} +56 -29
- package/dist/web/client/app.js +41 -30
- package/dist/web/client/style.css +29 -4
- package/package.json +1 -1
|
@@ -8,7 +8,7 @@ import { platform } from "os";
|
|
|
8
8
|
import chalk from "chalk";
|
|
9
9
|
|
|
10
10
|
// src/core/constants.ts
|
|
11
|
-
var VERSION = "0.1.
|
|
11
|
+
var VERSION = "0.1.75";
|
|
12
12
|
var APP_NAME = "ai-cli";
|
|
13
13
|
var CONFIG_DIR_NAME = ".aicli";
|
|
14
14
|
var CONFIG_FILE_NAME = "config.json";
|
|
@@ -75,9 +75,11 @@ var CONTEXT_PRESSURE_THRESHOLD = 0.8;
|
|
|
75
75
|
var TEST_TIMEOUT = 3e5;
|
|
76
76
|
var AGENTIC_BEHAVIOR_GUIDELINE = `# Important Behavioral Guidelines
|
|
77
77
|
|
|
78
|
-
**
|
|
78
|
+
**Respond appropriately to the user's intent \u2014 do NOT over-react**:
|
|
79
|
+
- For **greetings and casual chat** (e.g., "hello", "hi", "hey", "\u4F60\u597D", "what's up"): respond naturally with a friendly greeting. Do NOT use any tools. Do NOT explore directories, read files, or start any project work. Just chat.
|
|
79
80
|
- When the user asks you to "read", "understand", "review", "analyze", "examine", or "look at" files or a project, your task is only to **read and summarize**, then wait for the user's next instruction. Do not automatically start executing tasks described in the project.
|
|
80
81
|
- Only begin using write/execute tools when the user **explicitly requests** an action (e.g., "generate", "create", "modify", "run", "start", etc.).
|
|
82
|
+
- Project context files (CLAUDE.md, AICLI.md) provide background information about the project. They are NOT instructions to start working. Only use them as reference when the user asks a project-related question or task.
|
|
81
83
|
- If you are unsure about the user's intent, use the ask_user tool to confirm with the user, rather than assuming and executing on your own.`;
|
|
82
84
|
var AUTHOR = "Jin Zhengdong";
|
|
83
85
|
var AUTHOR_EMAIL = "zhengdong.jin@gmail.com";
|
|
@@ -16,7 +16,7 @@ import {
|
|
|
16
16
|
SUBAGENT_MAX_ROUNDS_LIMIT,
|
|
17
17
|
VERSION,
|
|
18
18
|
runTestsTool
|
|
19
|
-
} from "./chunk-
|
|
19
|
+
} from "./chunk-KDXXHXYU.js";
|
|
20
20
|
|
|
21
21
|
// src/config/config-manager.ts
|
|
22
22
|
import { readFileSync, writeFileSync, existsSync, mkdirSync } from "fs";
|
|
@@ -5405,6 +5405,17 @@ var SkillManager = class {
|
|
|
5405
5405
|
}
|
|
5406
5406
|
};
|
|
5407
5407
|
|
|
5408
|
+
// src/core/proxy.ts
|
|
5409
|
+
async function setupProxy(configProxy) {
|
|
5410
|
+
const proxyUrl = process.env.HTTPS_PROXY ?? process.env.HTTP_PROXY ?? process.env.https_proxy ?? process.env.http_proxy ?? configProxy;
|
|
5411
|
+
if (!proxyUrl) return;
|
|
5412
|
+
try {
|
|
5413
|
+
const { ProxyAgent, setGlobalDispatcher } = await import("undici");
|
|
5414
|
+
setGlobalDispatcher(new ProxyAgent({ uri: proxyUrl }));
|
|
5415
|
+
} catch {
|
|
5416
|
+
}
|
|
5417
|
+
}
|
|
5418
|
+
|
|
5408
5419
|
// src/repl/dev-state.ts
|
|
5409
5420
|
import { existsSync as existsSync14, readFileSync as readFileSync8, writeFileSync as writeFileSync7, unlinkSync as unlinkSync2, mkdirSync as mkdirSync8 } from "fs";
|
|
5410
5421
|
import { join as join10 } from "path";
|
|
@@ -5722,5 +5733,6 @@ export {
|
|
|
5722
5733
|
loadDevState,
|
|
5723
5734
|
clearDevState,
|
|
5724
5735
|
McpManager,
|
|
5725
|
-
SkillManager
|
|
5736
|
+
SkillManager,
|
|
5737
|
+
setupProxy
|
|
5726
5738
|
};
|
package/dist/index.js
CHANGED
|
@@ -30,11 +30,12 @@ import {
|
|
|
30
30
|
runHook,
|
|
31
31
|
saveDevState,
|
|
32
32
|
sessionHasMeaningfulContent,
|
|
33
|
+
setupProxy,
|
|
33
34
|
spawnAgentContext,
|
|
34
35
|
theme,
|
|
35
36
|
truncateOutput,
|
|
36
37
|
undoStack
|
|
37
|
-
} from "./chunk-
|
|
38
|
+
} from "./chunk-MD2SRFU4.js";
|
|
38
39
|
import {
|
|
39
40
|
AGENTIC_BEHAVIOR_GUIDELINE,
|
|
40
41
|
AUTHOR,
|
|
@@ -54,7 +55,7 @@ import {
|
|
|
54
55
|
REPO_URL,
|
|
55
56
|
SKILLS_DIR_NAME,
|
|
56
57
|
VERSION
|
|
57
|
-
} from "./chunk-
|
|
58
|
+
} from "./chunk-KDXXHXYU.js";
|
|
58
59
|
|
|
59
60
|
// src/index.ts
|
|
60
61
|
import { program } from "commander";
|
|
@@ -1903,7 +1904,7 @@ ${hint}` : "")
|
|
|
1903
1904
|
description: "Run project tests and show structured report",
|
|
1904
1905
|
usage: "/test [command|filter]",
|
|
1905
1906
|
async execute(args, _ctx) {
|
|
1906
|
-
const { executeTests } = await import("./run-tests-
|
|
1907
|
+
const { executeTests } = await import("./run-tests-D5RGQY6A.js");
|
|
1907
1908
|
const argStr = args.join(" ").trim();
|
|
1908
1909
|
let testArgs = {};
|
|
1909
1910
|
if (argStr) {
|
|
@@ -5290,7 +5291,7 @@ program.command("web").description("Start Web UI server with browser-based chat
|
|
|
5290
5291
|
console.error("Error: Invalid port number. Must be between 1 and 65535.");
|
|
5291
5292
|
process.exit(1);
|
|
5292
5293
|
}
|
|
5293
|
-
const { startWebServer } = await import("./server-
|
|
5294
|
+
const { startWebServer } = await import("./server-4ZYMNPYO.js");
|
|
5294
5295
|
await startWebServer({ port, host: options.host });
|
|
5295
5296
|
});
|
|
5296
5297
|
program.command("sessions").description("List recent conversation sessions").action(async () => {
|
|
@@ -5314,15 +5315,6 @@ program.command("sessions").description("List recent conversation sessions").act
|
|
|
5314
5315
|
console.log();
|
|
5315
5316
|
});
|
|
5316
5317
|
program.parse();
|
|
5317
|
-
async function setupProxy(configProxy) {
|
|
5318
|
-
const proxyUrl = process.env.HTTPS_PROXY ?? process.env.HTTP_PROXY ?? process.env.https_proxy ?? process.env.http_proxy ?? configProxy;
|
|
5319
|
-
if (!proxyUrl) return;
|
|
5320
|
-
try {
|
|
5321
|
-
const { ProxyAgent, setGlobalDispatcher } = await import("undici");
|
|
5322
|
-
setGlobalDispatcher(new ProxyAgent({ uri: proxyUrl }));
|
|
5323
|
-
} catch {
|
|
5324
|
-
}
|
|
5325
|
-
}
|
|
5326
5318
|
async function readStdin() {
|
|
5327
5319
|
if (process.stdin.isTTY) return "";
|
|
5328
5320
|
return new Promise((resolve3, reject) => {
|
|
@@ -5525,3 +5517,6 @@ Provider '${options.provider}' is not configured. Run: ai-cli config
|
|
|
5525
5517
|
});
|
|
5526
5518
|
await repl.start();
|
|
5527
5519
|
}
|
|
5520
|
+
export {
|
|
5521
|
+
setupProxy
|
|
5522
|
+
};
|
|
@@ -19,11 +19,13 @@ import {
|
|
|
19
19
|
loadDevState,
|
|
20
20
|
renderDiff,
|
|
21
21
|
runHook,
|
|
22
|
+
setupProxy,
|
|
22
23
|
spawnAgentContext,
|
|
23
24
|
truncateOutput
|
|
24
|
-
} from "./chunk-
|
|
25
|
+
} from "./chunk-MD2SRFU4.js";
|
|
25
26
|
import {
|
|
26
27
|
AGENTIC_BEHAVIOR_GUIDELINE,
|
|
28
|
+
CONTEXT_FILE_CANDIDATES,
|
|
27
29
|
DEFAULT_MAX_TOKENS,
|
|
28
30
|
MCP_PROJECT_CONFIG_NAME,
|
|
29
31
|
MEMORY_FILE_NAME,
|
|
@@ -32,13 +34,13 @@ import {
|
|
|
32
34
|
PLAN_MODE_SYSTEM_ADDON,
|
|
33
35
|
SKILLS_DIR_NAME,
|
|
34
36
|
VERSION
|
|
35
|
-
} from "./chunk-
|
|
37
|
+
} from "./chunk-KDXXHXYU.js";
|
|
36
38
|
|
|
37
39
|
// src/web/server.ts
|
|
38
40
|
import express from "express";
|
|
39
41
|
import { createServer } from "http";
|
|
40
42
|
import { WebSocketServer } from "ws";
|
|
41
|
-
import { join as join3, dirname, resolve } from "path";
|
|
43
|
+
import { join as join3, dirname, resolve as resolve2 } from "path";
|
|
42
44
|
import { existsSync as existsSync4, readFileSync as readFileSync4 } from "fs";
|
|
43
45
|
|
|
44
46
|
// src/web/tool-executor-web.ts
|
|
@@ -71,31 +73,31 @@ var ToolExecutorWeb = class {
|
|
|
71
73
|
}
|
|
72
74
|
/** Resolve a pending confirm from client response */
|
|
73
75
|
resolveConfirm(requestId, approved) {
|
|
74
|
-
const
|
|
75
|
-
if (
|
|
76
|
+
const resolve3 = this.pendingConfirms.get(requestId);
|
|
77
|
+
if (resolve3) {
|
|
76
78
|
this.pendingConfirms.delete(requestId);
|
|
77
79
|
this.confirming = false;
|
|
78
|
-
|
|
80
|
+
resolve3(approved);
|
|
79
81
|
}
|
|
80
82
|
}
|
|
81
83
|
/** Resolve a pending batch confirm from client response */
|
|
82
84
|
resolveBatchConfirm(requestId, decision) {
|
|
83
|
-
const
|
|
84
|
-
if (
|
|
85
|
+
const resolve3 = this.pendingBatchConfirms.get(requestId);
|
|
86
|
+
if (resolve3) {
|
|
85
87
|
this.pendingBatchConfirms.delete(requestId);
|
|
86
88
|
this.confirming = false;
|
|
87
89
|
if (decision === "all" || decision === "none") {
|
|
88
|
-
|
|
90
|
+
resolve3(decision);
|
|
89
91
|
} else {
|
|
90
|
-
|
|
92
|
+
resolve3(new Set(decision));
|
|
91
93
|
}
|
|
92
94
|
}
|
|
93
95
|
}
|
|
94
96
|
/** Cancel all pending confirms (e.g., on disconnect) */
|
|
95
97
|
cancelAll() {
|
|
96
|
-
for (const
|
|
98
|
+
for (const resolve3 of this.pendingConfirms.values()) resolve3(false);
|
|
97
99
|
this.pendingConfirms.clear();
|
|
98
|
-
for (const
|
|
100
|
+
for (const resolve3 of this.pendingBatchConfirms.values()) resolve3("none");
|
|
99
101
|
this.pendingBatchConfirms.clear();
|
|
100
102
|
this.confirming = false;
|
|
101
103
|
}
|
|
@@ -164,8 +166,8 @@ var ToolExecutorWeb = class {
|
|
|
164
166
|
diff: this.getDiffPreview(call)
|
|
165
167
|
};
|
|
166
168
|
this.send(msg);
|
|
167
|
-
return new Promise((
|
|
168
|
-
this.pendingConfirms.set(requestId,
|
|
169
|
+
return new Promise((resolve3) => {
|
|
170
|
+
this.pendingConfirms.set(requestId, resolve3);
|
|
169
171
|
});
|
|
170
172
|
}
|
|
171
173
|
/** WebSocket-based batch confirm */
|
|
@@ -184,8 +186,8 @@ var ToolExecutorWeb = class {
|
|
|
184
186
|
files
|
|
185
187
|
};
|
|
186
188
|
this.send(msg);
|
|
187
|
-
return new Promise((
|
|
188
|
-
this.pendingBatchConfirms.set(requestId,
|
|
189
|
+
return new Promise((resolve3) => {
|
|
190
|
+
this.pendingBatchConfirms.set(requestId, resolve3);
|
|
189
191
|
});
|
|
190
192
|
}
|
|
191
193
|
async execute(call) {
|
|
@@ -387,7 +389,7 @@ function loadMemoryContent(configDir) {
|
|
|
387
389
|
|
|
388
390
|
// src/web/session-handler.ts
|
|
389
391
|
import { existsSync as existsSync3, readFileSync as readFileSync3 } from "fs";
|
|
390
|
-
import { join as join2 } from "path";
|
|
392
|
+
import { join as join2, resolve } from "path";
|
|
391
393
|
var MAX_TOOL_ROUNDS = 25;
|
|
392
394
|
var FREE_ROUND_TOOLS = /* @__PURE__ */ new Set(["write_todos"]);
|
|
393
395
|
var MAX_CONSECUTIVE_FREE_ROUNDS = 5;
|
|
@@ -488,10 +490,10 @@ var SessionHandler = class {
|
|
|
488
490
|
return;
|
|
489
491
|
}
|
|
490
492
|
case "ask_user_response": {
|
|
491
|
-
const
|
|
492
|
-
if (
|
|
493
|
+
const resolve3 = this.pendingAskUser.get(msg.requestId);
|
|
494
|
+
if (resolve3) {
|
|
493
495
|
this.pendingAskUser.delete(msg.requestId);
|
|
494
|
-
|
|
496
|
+
resolve3(msg.answer);
|
|
495
497
|
}
|
|
496
498
|
return;
|
|
497
499
|
}
|
|
@@ -508,7 +510,7 @@ var SessionHandler = class {
|
|
|
508
510
|
onDisconnect() {
|
|
509
511
|
this.toolExecutor.cancelAll();
|
|
510
512
|
if (this.abortController) this.abortController.abort();
|
|
511
|
-
for (const
|
|
513
|
+
for (const resolve3 of this.pendingAskUser.values()) resolve3(null);
|
|
512
514
|
this.pendingAskUser.clear();
|
|
513
515
|
this.sessions.save();
|
|
514
516
|
}
|
|
@@ -962,19 +964,43 @@ Tokens: in=${this.sessionTokenUsage.inputTokens} out=${this.sessionTokenUsage.ou
|
|
|
962
964
|
}
|
|
963
965
|
return defs;
|
|
964
966
|
}
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
967
|
+
/**
|
|
968
|
+
* Find first matching context file in a directory.
|
|
969
|
+
*/
|
|
970
|
+
findContextFile(dir) {
|
|
971
|
+
for (const name of CONTEXT_FILE_CANDIDATES) {
|
|
972
|
+
const fullPath = join2(dir, name);
|
|
970
973
|
try {
|
|
971
974
|
if (existsSync3(fullPath)) {
|
|
972
|
-
|
|
975
|
+
const content = readFileSync3(fullPath, "utf-8").trim();
|
|
976
|
+
if (content) return content;
|
|
973
977
|
}
|
|
974
978
|
} catch {
|
|
975
979
|
}
|
|
976
980
|
}
|
|
977
|
-
return
|
|
981
|
+
return null;
|
|
982
|
+
}
|
|
983
|
+
/**
|
|
984
|
+
* Load hierarchical context files (same as CLI):
|
|
985
|
+
* 1. Global: ~/.aicli/AICLI.md or CLAUDE.md
|
|
986
|
+
* 2. Project: <git-root>/AICLI.md or CLAUDE.md
|
|
987
|
+
* 3. Subdir: <cwd>/AICLI.md or CLAUDE.md (only if cwd ≠ project root)
|
|
988
|
+
*/
|
|
989
|
+
loadContextFiles() {
|
|
990
|
+
const parts = [];
|
|
991
|
+
const cwd = process.cwd();
|
|
992
|
+
const configDir = this.config.getConfigDir();
|
|
993
|
+
const globalCtx = this.findContextFile(configDir);
|
|
994
|
+
if (globalCtx) parts.push(globalCtx);
|
|
995
|
+
const gitRoot = getGitRoot(cwd);
|
|
996
|
+
const projectRoot = gitRoot ?? cwd;
|
|
997
|
+
const projectCtx = this.findContextFile(projectRoot);
|
|
998
|
+
if (projectCtx) parts.push(projectCtx);
|
|
999
|
+
if (resolve(cwd) !== resolve(projectRoot)) {
|
|
1000
|
+
const localCtx = this.findContextFile(cwd);
|
|
1001
|
+
if (localCtx) parts.push(localCtx);
|
|
1002
|
+
}
|
|
1003
|
+
return parts.length > 0 ? parts.join("\n\n---\n\n") : void 0;
|
|
978
1004
|
}
|
|
979
1005
|
};
|
|
980
1006
|
|
|
@@ -988,7 +1014,7 @@ function getModuleDir() {
|
|
|
988
1014
|
}
|
|
989
1015
|
} catch {
|
|
990
1016
|
}
|
|
991
|
-
return
|
|
1017
|
+
return resolve2(".");
|
|
992
1018
|
}
|
|
993
1019
|
async function startWebServer(options = {}) {
|
|
994
1020
|
const port = options.port ?? 3e3;
|
|
@@ -996,6 +1022,7 @@ async function startWebServer(options = {}) {
|
|
|
996
1022
|
console.log(`\u{1F916} ai-cli Web UI v${VERSION}`);
|
|
997
1023
|
console.log(` Initializing...`);
|
|
998
1024
|
const config = new ConfigManager();
|
|
1025
|
+
await setupProxy(config.get("proxy"));
|
|
999
1026
|
const providers = new ProviderRegistry();
|
|
1000
1027
|
const sessions = new SessionManager(config);
|
|
1001
1028
|
const toolRegistry = new ToolRegistry();
|
package/dist/web/client/app.js
CHANGED
|
@@ -139,20 +139,22 @@ function handleResponseDone(msg) {
|
|
|
139
139
|
}
|
|
140
140
|
|
|
141
141
|
function handleToolCallStart(msg) {
|
|
142
|
-
const
|
|
143
|
-
: msg.dangerLevel === 'write' ? '
|
|
142
|
+
const levelBorder = msg.dangerLevel === 'destructive' ? 'tool-border-destructive'
|
|
143
|
+
: msg.dangerLevel === 'write' ? 'tool-border-write' : 'tool-border-safe';
|
|
144
144
|
const levelIcon = msg.dangerLevel === 'destructive' ? '⚠'
|
|
145
145
|
: msg.dangerLevel === 'write' ? '✎' : '⚙';
|
|
146
|
+
const levelBadge = msg.dangerLevel === 'destructive' ? 'badge-error'
|
|
147
|
+
: msg.dangerLevel === 'write' ? 'badge-warning' : 'badge-info';
|
|
146
148
|
|
|
147
149
|
const el = document.createElement('div');
|
|
148
150
|
el.id = `tool-${msg.callId}`;
|
|
149
|
-
el.className = `tool-card
|
|
151
|
+
el.className = `tool-card ${levelBorder} my-1`;
|
|
150
152
|
el.innerHTML = `
|
|
151
|
-
<div class="flex items-center gap-2 w-full">
|
|
152
|
-
<span class="
|
|
153
|
-
<span class="
|
|
153
|
+
<div class="flex items-center gap-2 w-full mb-1">
|
|
154
|
+
<span class="badge ${levelBadge} badge-sm gap-1">${levelIcon} ${escapeHtml(msg.toolName)}</span>
|
|
155
|
+
<span class="text-xs opacity-50">${msg.round}/${msg.totalRounds}</span>
|
|
154
156
|
</div>
|
|
155
|
-
<div class="tool-args
|
|
157
|
+
<div class="tool-args w-full">${formatToolArgs(msg.args)}</div>
|
|
156
158
|
`;
|
|
157
159
|
messagesEl.appendChild(el);
|
|
158
160
|
scrollToBottom();
|
|
@@ -172,14 +174,17 @@ function handleToolCallResult(msg) {
|
|
|
172
174
|
function handleConfirmRequest(msg) {
|
|
173
175
|
const isDestructive = msg.dangerLevel === 'destructive';
|
|
174
176
|
const el = document.createElement('div');
|
|
175
|
-
el.className = `
|
|
177
|
+
el.className = `confirm-card ${isDestructive ? 'tool-border-destructive' : 'tool-border-write'} my-1`;
|
|
176
178
|
el.setAttribute('data-request-id', msg.requestId);
|
|
177
179
|
el.innerHTML = `
|
|
178
|
-
<div class="
|
|
180
|
+
<div class="flex items-center gap-2 mb-2">
|
|
181
|
+
<span class="badge ${isDestructive ? 'badge-error' : 'badge-warning'} badge-sm">${isDestructive ? '⚠ DESTRUCTIVE' : '✎ Write'}</span>
|
|
182
|
+
<span class="text-sm font-semibold">${escapeHtml(msg.toolName)}</span>
|
|
183
|
+
</div>
|
|
179
184
|
${msg.diff ? `<div class="confirm-diff w-full">${escapeHtml(msg.diff)}</div>` : ''}
|
|
180
|
-
<div class="flex gap-2 mt-
|
|
181
|
-
<button class="btn btn-success btn-sm" onclick="respondConfirm('${msg.requestId}', true)">✓ Approve</button>
|
|
182
|
-
<button class="btn btn-error btn-sm" onclick="respondConfirm('${msg.requestId}', false)">✗ Deny</button>
|
|
185
|
+
<div class="flex gap-2 mt-2">
|
|
186
|
+
<button class="btn btn-success btn-sm btn-outline" onclick="respondConfirm('${msg.requestId}', true)">✓ Approve</button>
|
|
187
|
+
<button class="btn btn-error btn-sm btn-outline" onclick="respondConfirm('${msg.requestId}', false)">✗ Deny</button>
|
|
183
188
|
</div>
|
|
184
189
|
`;
|
|
185
190
|
messagesEl.appendChild(el);
|
|
@@ -188,7 +193,7 @@ function handleConfirmRequest(msg) {
|
|
|
188
193
|
|
|
189
194
|
function handleBatchConfirmRequest(msg) {
|
|
190
195
|
const el = document.createElement('div');
|
|
191
|
-
el.className = '
|
|
196
|
+
el.className = 'confirm-card tool-border-write my-1 batch-confirm';
|
|
192
197
|
el.setAttribute('data-request-id', msg.requestId);
|
|
193
198
|
|
|
194
199
|
const fileListHtml = msg.files.map(f => `
|
|
@@ -199,11 +204,14 @@ function handleBatchConfirmRequest(msg) {
|
|
|
199
204
|
`).join('');
|
|
200
205
|
|
|
201
206
|
el.innerHTML = `
|
|
202
|
-
<div class="
|
|
207
|
+
<div class="flex items-center gap-2 mb-2">
|
|
208
|
+
<span class="badge badge-warning badge-sm">✎ Batch writes</span>
|
|
209
|
+
<span class="text-sm">${msg.files.length} files</span>
|
|
210
|
+
</div>
|
|
203
211
|
<div class="w-full my-1">${fileListHtml}</div>
|
|
204
|
-
<div class="flex gap-2 mt-
|
|
205
|
-
<button class="btn btn-success btn-sm" onclick="respondBatchConfirm('${msg.requestId}', this)">✓ Approve Selected</button>
|
|
206
|
-
<button class="btn btn-error btn-sm" onclick="respondBatchDeny('${msg.requestId}', this)">✗ Reject All</button>
|
|
212
|
+
<div class="flex gap-2 mt-2">
|
|
213
|
+
<button class="btn btn-success btn-sm btn-outline" onclick="respondBatchConfirm('${msg.requestId}', this)">✓ Approve Selected</button>
|
|
214
|
+
<button class="btn btn-error btn-sm btn-outline" onclick="respondBatchDeny('${msg.requestId}', this)">✗ Reject All</button>
|
|
207
215
|
</div>
|
|
208
216
|
`;
|
|
209
217
|
messagesEl.appendChild(el);
|
|
@@ -212,10 +220,13 @@ function handleBatchConfirmRequest(msg) {
|
|
|
212
220
|
|
|
213
221
|
function handleAskUserRequest(msg) {
|
|
214
222
|
const el = document.createElement('div');
|
|
215
|
-
el.className = '
|
|
223
|
+
el.className = 'confirm-card tool-border-safe my-1';
|
|
216
224
|
el.innerHTML = `
|
|
217
|
-
<div class="
|
|
218
|
-
|
|
225
|
+
<div class="flex items-center gap-2 mb-2">
|
|
226
|
+
<span class="badge badge-info badge-sm">❓ Question</span>
|
|
227
|
+
</div>
|
|
228
|
+
<div class="text-sm mb-2">${escapeHtml(msg.question)}</div>
|
|
229
|
+
<div class="flex gap-2 w-full">
|
|
219
230
|
<input type="text" id="ask-input-${msg.requestId}"
|
|
220
231
|
class="input input-sm input-bordered flex-1"
|
|
221
232
|
placeholder="Your answer..."
|
|
@@ -287,8 +298,8 @@ window.respondConfirm = function(requestId, approved) {
|
|
|
287
298
|
send({ type: 'confirm_response', requestId, approved });
|
|
288
299
|
const el = document.querySelector(`[data-request-id="${requestId}"]`);
|
|
289
300
|
if (el) {
|
|
290
|
-
el.className = `
|
|
291
|
-
el.innerHTML = `<span class="text-sm">${approved ? '✓ Approved' : '✗ Denied'}</span>`;
|
|
301
|
+
el.className = `confirm-card ${approved ? 'tool-border-safe' : 'tool-border-destructive'} my-1 opacity-60`;
|
|
302
|
+
el.innerHTML = `<span class="text-sm ${approved ? 'text-success' : 'text-error'}">${approved ? '✓ Approved' : '✗ Denied'}</span>`;
|
|
292
303
|
}
|
|
293
304
|
};
|
|
294
305
|
|
|
@@ -305,24 +316,24 @@ window.respondBatchConfirm = function(requestId, btn) {
|
|
|
305
316
|
} else {
|
|
306
317
|
send({ type: 'batch_confirm_response', requestId, decision: selected });
|
|
307
318
|
}
|
|
308
|
-
dialog.className = '
|
|
309
|
-
dialog.innerHTML = `<span class="text-sm">✓ Approved ${selected.length}/${checks.length} files</span>`;
|
|
319
|
+
dialog.className = 'confirm-card tool-border-safe my-1 opacity-60';
|
|
320
|
+
dialog.innerHTML = `<span class="text-sm text-success">✓ Approved ${selected.length}/${checks.length} files</span>`;
|
|
310
321
|
};
|
|
311
322
|
|
|
312
323
|
window.respondBatchDeny = function(requestId, btn) {
|
|
313
324
|
send({ type: 'batch_confirm_response', requestId, decision: 'none' });
|
|
314
325
|
const dialog = btn.closest('.batch-confirm');
|
|
315
|
-
dialog.className = '
|
|
316
|
-
dialog.innerHTML = `<span class="text-sm">✗ All rejected</span>`;
|
|
326
|
+
dialog.className = 'confirm-card tool-border-destructive my-1 opacity-60';
|
|
327
|
+
dialog.innerHTML = `<span class="text-sm text-error">✗ All rejected</span>`;
|
|
317
328
|
};
|
|
318
329
|
|
|
319
330
|
window.respondAskUser = function(requestId) {
|
|
320
331
|
const input = document.getElementById(`ask-input-${requestId}`);
|
|
321
332
|
const answer = input ? input.value : '';
|
|
322
333
|
send({ type: 'ask_user_response', requestId, answer: answer || null });
|
|
323
|
-
const dialog = input?.closest('.
|
|
334
|
+
const dialog = input?.closest('.confirm-card');
|
|
324
335
|
if (dialog) {
|
|
325
|
-
dialog.className = '
|
|
336
|
+
dialog.className = 'confirm-card tool-border-safe my-1 opacity-60';
|
|
326
337
|
dialog.innerHTML = `<span class="text-sm">↪ ${escapeHtml(answer || '(cancelled)')}</span>`;
|
|
327
338
|
}
|
|
328
339
|
};
|
|
@@ -360,8 +371,8 @@ function addInfoMessage(text) {
|
|
|
360
371
|
|
|
361
372
|
function addErrorMessage(text) {
|
|
362
373
|
const el = document.createElement('div');
|
|
363
|
-
el.className = '
|
|
364
|
-
el.innerHTML = `<span
|
|
374
|
+
el.className = 'error-message my-1';
|
|
375
|
+
el.innerHTML = `<span class="text-error text-sm">⚠ ${escapeHtml(text)}</span>`;
|
|
365
376
|
messagesEl.appendChild(el);
|
|
366
377
|
scrollToBottom();
|
|
367
378
|
}
|
|
@@ -110,16 +110,25 @@
|
|
|
110
110
|
50% { opacity: 0; }
|
|
111
111
|
}
|
|
112
112
|
|
|
113
|
-
/* ── Tool call cards
|
|
113
|
+
/* ── Tool call cards (base-colored with left border) ── */
|
|
114
114
|
.tool-card {
|
|
115
|
+
background: oklch(var(--b2));
|
|
116
|
+
border-radius: 0.5rem;
|
|
117
|
+
padding: 0.75rem 1rem;
|
|
115
118
|
font-size: 0.85rem;
|
|
119
|
+
border-left: 3px solid transparent;
|
|
116
120
|
}
|
|
121
|
+
.tool-border-safe { border-left-color: oklch(var(--in)); }
|
|
122
|
+
.tool-border-write { border-left-color: oklch(var(--wa)); }
|
|
123
|
+
.tool-border-destructive { border-left-color: oklch(var(--er)); }
|
|
124
|
+
|
|
117
125
|
.tool-card .tool-args {
|
|
118
126
|
white-space: pre-wrap;
|
|
119
127
|
max-height: 100px;
|
|
120
128
|
overflow-y: auto;
|
|
121
129
|
font-size: 0.8rem;
|
|
122
|
-
opacity: 0.
|
|
130
|
+
opacity: 0.65;
|
|
131
|
+
line-height: 1.5;
|
|
123
132
|
}
|
|
124
133
|
.tool-card .tool-result-content {
|
|
125
134
|
white-space: pre-wrap;
|
|
@@ -128,12 +137,20 @@
|
|
|
128
137
|
font-size: 0.8rem;
|
|
129
138
|
}
|
|
130
139
|
|
|
131
|
-
/* ── Confirm
|
|
140
|
+
/* ── Confirm / ask-user card ────────────────────────── */
|
|
141
|
+
.confirm-card {
|
|
142
|
+
background: oklch(var(--b2));
|
|
143
|
+
border-radius: 0.5rem;
|
|
144
|
+
padding: 0.75rem 1rem;
|
|
145
|
+
border-left: 3px solid transparent;
|
|
146
|
+
}
|
|
147
|
+
|
|
132
148
|
.confirm-diff {
|
|
133
149
|
background: oklch(var(--b3));
|
|
150
|
+
color: oklch(var(--bc));
|
|
134
151
|
padding: 0.5rem;
|
|
135
152
|
border-radius: 0.375rem;
|
|
136
|
-
font-family: 'Fira Code', 'Consolas', monospace;
|
|
153
|
+
font-family: 'Fira Code', 'JetBrains Mono', 'Consolas', monospace;
|
|
137
154
|
font-size: 0.78rem;
|
|
138
155
|
white-space: pre-wrap;
|
|
139
156
|
max-height: 200px;
|
|
@@ -141,6 +158,14 @@
|
|
|
141
158
|
margin-bottom: 0.5rem;
|
|
142
159
|
}
|
|
143
160
|
|
|
161
|
+
/* ── Error message ──────────────────────────────────── */
|
|
162
|
+
.error-message {
|
|
163
|
+
background: oklch(var(--er) / 0.1);
|
|
164
|
+
border-left: 3px solid oklch(var(--er));
|
|
165
|
+
border-radius: 0.5rem;
|
|
166
|
+
padding: 0.5rem 1rem;
|
|
167
|
+
}
|
|
168
|
+
|
|
144
169
|
/* ── Thinking block ─────────────────────────────────── */
|
|
145
170
|
.thinking-block summary {
|
|
146
171
|
cursor: pointer;
|