jinzd-ai-cli 0.4.205 → 0.4.207
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/README.md +1 -1
- package/dist/{batch-RBPABHS7.js → batch-6PORMJWT.js} +2 -2
- package/dist/{chunk-XIYSFN4U.js → chunk-2WV6AGHM.js} +1 -1
- package/dist/{chunk-43H3D2PK.js → chunk-BQIV4ZQT.js} +1 -1
- package/dist/{chunk-JVYH66N2.js → chunk-KJHMRAJU.js} +1 -1
- package/dist/{chunk-ZSC4YLEJ.js → chunk-KOU4KX7J.js} +2 -2
- package/dist/{chunk-UZISJ3KZ.js → chunk-QMXC327F.js} +3 -3
- package/dist/{chunk-3RET7PL7.js → chunk-QNUVZO5X.js} +1 -1
- package/dist/{chunk-43MWRT2C.js → chunk-QQYSZMET.js} +20 -17
- package/dist/{chunk-VOV2PWZU.js → chunk-SFCNFX42.js} +1 -1
- package/dist/{chunk-TZ7SNVSG.js → chunk-TW47X5AO.js} +1 -1
- package/dist/{chunk-SMFRJCXB.js → chunk-XPBEJB27.js} +8 -1
- package/dist/{ci-ABE74AXH.js → ci-AYMV66P3.js} +9 -9
- package/dist/{constants-GMQMJRIO.js → constants-NHGTSHKT.js} +1 -1
- package/dist/{doctor-cli-M5PPO3L3.js → doctor-cli-WKH7T4AW.js} +6 -6
- package/dist/electron-server.js +46 -41
- package/dist/{hub-NCU5JNCK.js → hub-6R3M3NTC.js} +1 -1
- package/dist/index.js +102 -98
- package/dist/{run-tests-ZFAEFEYK.js → run-tests-5F2OBWIK.js} +2 -2
- package/dist/{run-tests-FGRWBNVF.js → run-tests-NBCA4KEG.js} +1 -1
- package/dist/{server-RKP7JRRE.js → server-37EXC4EB.js} +5 -5
- package/dist/{server-ML6ZL3J5.js → server-L2MXWYF7.js} +26 -26
- package/dist/{task-orchestrator-LJP5XZSC.js → task-orchestrator-2DTDVCMR.js} +5 -5
- package/dist/{usage-YX2235W5.js → usage-SZWZFX3T.js} +2 -2
- package/dist/web/client/actions.js +84 -0
- package/dist/web/client/app.js +23 -205
- package/dist/web/client/index.html +27 -42
- package/dist/web/client/sw.js +1 -1
- package/dist/web/client/templates.js +188 -0
- package/package.json +1 -1
|
@@ -1,21 +1,21 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
ToolRegistry
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-QQYSZMET.js";
|
|
5
5
|
import "./chunk-T2NL5ZIA.js";
|
|
6
6
|
import "./chunk-BXP6YZ2P.js";
|
|
7
|
-
import "./chunk-
|
|
7
|
+
import "./chunk-SFCNFX42.js";
|
|
8
8
|
import {
|
|
9
9
|
runTool
|
|
10
|
-
} from "./chunk-
|
|
10
|
+
} from "./chunk-2WV6AGHM.js";
|
|
11
11
|
import {
|
|
12
12
|
getDangerLevel,
|
|
13
13
|
schemaToJsonSchema
|
|
14
|
-
} from "./chunk-
|
|
14
|
+
} from "./chunk-XPBEJB27.js";
|
|
15
15
|
import "./chunk-TZQHYZKT.js";
|
|
16
16
|
import {
|
|
17
17
|
VERSION
|
|
18
|
-
} from "./chunk-
|
|
18
|
+
} from "./chunk-QNUVZO5X.js";
|
|
19
19
|
import "./chunk-4BKXL7SM.js";
|
|
20
20
|
import "./chunk-TB4W4Y4T.js";
|
|
21
21
|
import "./chunk-KHYD3WXE.js";
|
|
@@ -19,7 +19,7 @@ import {
|
|
|
19
19
|
loadDevState,
|
|
20
20
|
persistToolRound,
|
|
21
21
|
setupProxy
|
|
22
|
-
} from "./chunk-
|
|
22
|
+
} from "./chunk-KOU4KX7J.js";
|
|
23
23
|
import {
|
|
24
24
|
ToolExecutor,
|
|
25
25
|
ToolRegistry,
|
|
@@ -38,10 +38,10 @@ import {
|
|
|
38
38
|
spawnAgentContext,
|
|
39
39
|
truncateOutput,
|
|
40
40
|
undoStack
|
|
41
|
-
} from "./chunk-
|
|
41
|
+
} from "./chunk-QQYSZMET.js";
|
|
42
42
|
import "./chunk-T2NL5ZIA.js";
|
|
43
43
|
import "./chunk-BXP6YZ2P.js";
|
|
44
|
-
import "./chunk-
|
|
44
|
+
import "./chunk-SFCNFX42.js";
|
|
45
45
|
import {
|
|
46
46
|
SessionManager,
|
|
47
47
|
getContentText
|
|
@@ -52,10 +52,10 @@ import {
|
|
|
52
52
|
} from "./chunk-E44DTERW.js";
|
|
53
53
|
import {
|
|
54
54
|
ProviderRegistry
|
|
55
|
-
} from "./chunk-
|
|
55
|
+
} from "./chunk-QMXC327F.js";
|
|
56
56
|
import {
|
|
57
57
|
runTool
|
|
58
|
-
} from "./chunk-
|
|
58
|
+
} from "./chunk-2WV6AGHM.js";
|
|
59
59
|
import {
|
|
60
60
|
CONTENT_ONLY_STREAM_REMINDER,
|
|
61
61
|
TEE_FINAL_USER_NUDGE,
|
|
@@ -71,10 +71,10 @@ import {
|
|
|
71
71
|
stripOuterCodeFence,
|
|
72
72
|
stripToolCallReminder,
|
|
73
73
|
teeStreamErrorSummary
|
|
74
|
-
} from "./chunk-
|
|
74
|
+
} from "./chunk-XPBEJB27.js";
|
|
75
75
|
import {
|
|
76
76
|
ConfigManager
|
|
77
|
-
} from "./chunk-
|
|
77
|
+
} from "./chunk-TW47X5AO.js";
|
|
78
78
|
import "./chunk-TZQHYZKT.js";
|
|
79
79
|
import {
|
|
80
80
|
AGENTIC_BEHAVIOR_GUIDELINE,
|
|
@@ -94,7 +94,7 @@ import {
|
|
|
94
94
|
SKILLS_DIR_NAME,
|
|
95
95
|
VERSION,
|
|
96
96
|
buildUserIdentityPrompt
|
|
97
|
-
} from "./chunk-
|
|
97
|
+
} from "./chunk-QNUVZO5X.js";
|
|
98
98
|
import {
|
|
99
99
|
formatGitContextForPrompt,
|
|
100
100
|
getGitContext,
|
|
@@ -106,7 +106,9 @@ import "./chunk-KHYD3WXE.js";
|
|
|
106
106
|
import "./chunk-SLSWPBK3.js";
|
|
107
107
|
import "./chunk-O6UFCEUZ.js";
|
|
108
108
|
import "./chunk-CKH4KQ4E.js";
|
|
109
|
-
import
|
|
109
|
+
import {
|
|
110
|
+
atomicWriteFileSync
|
|
111
|
+
} from "./chunk-IW3Q7AE5.js";
|
|
110
112
|
|
|
111
113
|
// src/web/server.ts
|
|
112
114
|
import express from "express";
|
|
@@ -346,7 +348,7 @@ var ToolExecutorWeb = class _ToolExecutorWeb {
|
|
|
346
348
|
}
|
|
347
349
|
}
|
|
348
350
|
this.sendToolCallStart(call);
|
|
349
|
-
if (this.sessionAutoApprove &&
|
|
351
|
+
if (this.sessionAutoApprove && dangerLevel === "write") {
|
|
350
352
|
try {
|
|
351
353
|
const rawContent = await runTool(tool, call.arguments, call.name);
|
|
352
354
|
const content = truncateOutput(rawContent, call.name);
|
|
@@ -1176,7 +1178,7 @@ Try: /compact to reduce context, /clear to reset, or switch to a larger-context
|
|
|
1176
1178
|
try {
|
|
1177
1179
|
mkdirSync(dirname(pendingTeeSave), { recursive: true });
|
|
1178
1180
|
const bodyToSave = stripOuterCodeFence(content);
|
|
1179
|
-
|
|
1181
|
+
atomicWriteFileSync(pendingTeeSave, bodyToSave);
|
|
1180
1182
|
undoStack.push(pendingTeeSave, `save_last_response (deferred): ${pendingTeeSave}`);
|
|
1181
1183
|
const lines = bodyToSave.split("\n").length;
|
|
1182
1184
|
this.send({ type: "info", message: `\u2705 Saved (from reply): ${pendingTeeSave} (${lines} lines, ${bodyToSave.length} chars)` });
|
|
@@ -1351,7 +1353,7 @@ ${summaryContent}`,
|
|
|
1351
1353
|
let summary;
|
|
1352
1354
|
try {
|
|
1353
1355
|
mkdirSync(dirname(saveToFile), { recursive: true });
|
|
1354
|
-
fileStream = createWriteStream(saveToFile
|
|
1356
|
+
fileStream = createWriteStream(saveToFile);
|
|
1355
1357
|
const teeSystemPrompt = stripToolCallReminder(systemPrompt ?? "") + CONTENT_ONLY_STREAM_REMINDER;
|
|
1356
1358
|
const teeExtraMessages = extraMessages.length > 0 ? [...extraMessages, { role: "user", content: TEE_FINAL_USER_NUDGE }] : [{ role: "user", content: TEE_FINAL_USER_NUDGE }];
|
|
1357
1359
|
const chatRequest = {
|
|
@@ -1391,7 +1393,7 @@ ${summaryContent}`,
|
|
|
1391
1393
|
fullContent = "";
|
|
1392
1394
|
} else {
|
|
1393
1395
|
if (verdict.kind === "salvaged" || verdict.kind === "fallback") {
|
|
1394
|
-
|
|
1396
|
+
atomicWriteFileSync(saveToFile, verdict.content);
|
|
1395
1397
|
fullContent = verdict.content;
|
|
1396
1398
|
}
|
|
1397
1399
|
summary = verdict.summary;
|
|
@@ -1843,7 +1845,7 @@ ${activated.meta.description || ""}` });
|
|
|
1843
1845
|
this.send({ type: "info", message: "\u{1F512} Auto-approve disabled \u2014 confirmations restored for this session." });
|
|
1844
1846
|
} else {
|
|
1845
1847
|
this.toolExecutor.sessionAutoApprove = true;
|
|
1846
|
-
this.send({ type: "info", message: "\u26A1 YOLO mode ON \u2014
|
|
1848
|
+
this.send({ type: "info", message: "\u26A1 YOLO mode ON \u2014 write tools auto-approved; destructive tools still require confirmation.\nUse /yolo off to re-enable write confirmations." });
|
|
1847
1849
|
}
|
|
1848
1850
|
break;
|
|
1849
1851
|
}
|
|
@@ -2456,7 +2458,7 @@ ${undoResults.map((r) => ` \u2022 ${r}`).join("\n")}` });
|
|
|
2456
2458
|
case "test": {
|
|
2457
2459
|
this.send({ type: "info", message: "\u{1F9EA} Running tests..." });
|
|
2458
2460
|
try {
|
|
2459
|
-
const { executeTests } = await import("./run-tests-
|
|
2461
|
+
const { executeTests } = await import("./run-tests-5F2OBWIK.js");
|
|
2460
2462
|
const argStr = args.join(" ").trim();
|
|
2461
2463
|
let testArgs = {};
|
|
2462
2464
|
if (argStr) {
|
|
@@ -3526,12 +3528,9 @@ async function startWebServer(options = {}) {
|
|
|
3526
3528
|
"Content-Security-Policy",
|
|
3527
3529
|
[
|
|
3528
3530
|
"default-src 'self'",
|
|
3529
|
-
//
|
|
3530
|
-
//
|
|
3531
|
-
|
|
3532
|
-
// CSP violation in the console). localhost dev/admin tool — the
|
|
3533
|
-
// unsafe-inline XSS surface is acceptable under that threat model.
|
|
3534
|
-
"script-src 'self' 'unsafe-inline'",
|
|
3531
|
+
// Inline event handlers and startup scripts live in app.js, so script
|
|
3532
|
+
// execution stays locked to same-origin files only.
|
|
3533
|
+
"script-src 'self'",
|
|
3535
3534
|
"style-src 'self' 'unsafe-inline'",
|
|
3536
3535
|
"img-src 'self' data: blob:",
|
|
3537
3536
|
"font-src 'self' data:",
|
|
@@ -3891,7 +3890,7 @@ async function startWebServer(options = {}) {
|
|
|
3891
3890
|
handlers.set(tabId, handler);
|
|
3892
3891
|
clearPreAuthTimer();
|
|
3893
3892
|
console.log(` \u2713 User registered & connected: ${username} (tab: ${tabId.slice(0, 12)})`);
|
|
3894
|
-
ws.send(JSON.stringify({ type: "auth_result", success: true,
|
|
3893
|
+
ws.send(JSON.stringify({ type: "auth_result", success: true, username }));
|
|
3895
3894
|
return;
|
|
3896
3895
|
}
|
|
3897
3896
|
if (action === "token") {
|
|
@@ -3907,7 +3906,7 @@ async function startWebServer(options = {}) {
|
|
|
3907
3906
|
handlers.set(tabId, handler);
|
|
3908
3907
|
clearPreAuthTimer();
|
|
3909
3908
|
console.log(` \u2713 Token auth: ${verifiedUser} (tab: ${tabId.slice(0, 12)})`);
|
|
3910
|
-
ws.send(JSON.stringify({ type: "auth_result", success: true,
|
|
3909
|
+
ws.send(JSON.stringify({ type: "auth_result", success: true, username: verifiedUser }));
|
|
3911
3910
|
return;
|
|
3912
3911
|
}
|
|
3913
3912
|
if (action === "login") {
|
|
@@ -3922,7 +3921,7 @@ async function startWebServer(options = {}) {
|
|
|
3922
3921
|
handlers.set(tabId, handler);
|
|
3923
3922
|
clearPreAuthTimer();
|
|
3924
3923
|
console.log(` \u2713 User logged in: ${username} (tab: ${tabId.slice(0, 12)})`);
|
|
3925
|
-
ws.send(JSON.stringify({ type: "auth_result", success: true,
|
|
3924
|
+
ws.send(JSON.stringify({ type: "auth_result", success: true, username }));
|
|
3926
3925
|
return;
|
|
3927
3926
|
}
|
|
3928
3927
|
ws.send(JSON.stringify({ type: "auth_result", success: false, error: "Unknown auth action" }));
|
|
@@ -3948,9 +3947,10 @@ async function startWebServer(options = {}) {
|
|
|
3948
3947
|
});
|
|
3949
3948
|
ws.on("close", () => {
|
|
3950
3949
|
clearPreAuthTimer();
|
|
3951
|
-
|
|
3950
|
+
const wasTracked = handlers.has(tabId);
|
|
3952
3951
|
if (handler) handler.onDisconnect();
|
|
3953
|
-
handlers.delete(tabId);
|
|
3952
|
+
if (wasTracked) handlers.delete(tabId);
|
|
3953
|
+
console.log(` \u2717 Tab disconnected: ${tabId.slice(0, 12)} (total: ${handlers.size})`);
|
|
3954
3954
|
});
|
|
3955
3955
|
ws.on("error", (err) => {
|
|
3956
3956
|
console.error(` WebSocket error: ${err.message}`);
|
|
@@ -3,21 +3,21 @@ import {
|
|
|
3
3
|
ToolRegistry,
|
|
4
4
|
googleSearchContext,
|
|
5
5
|
truncateOutput
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-QQYSZMET.js";
|
|
7
7
|
import "./chunk-T2NL5ZIA.js";
|
|
8
8
|
import "./chunk-BXP6YZ2P.js";
|
|
9
|
-
import "./chunk-
|
|
9
|
+
import "./chunk-SFCNFX42.js";
|
|
10
10
|
import {
|
|
11
11
|
runTool
|
|
12
|
-
} from "./chunk-
|
|
12
|
+
} from "./chunk-2WV6AGHM.js";
|
|
13
13
|
import {
|
|
14
14
|
getDangerLevel,
|
|
15
15
|
runLeanAgentLoop
|
|
16
|
-
} from "./chunk-
|
|
16
|
+
} from "./chunk-XPBEJB27.js";
|
|
17
17
|
import "./chunk-TZQHYZKT.js";
|
|
18
18
|
import {
|
|
19
19
|
SUBAGENT_ALLOWED_TOOLS
|
|
20
|
-
} from "./chunk-
|
|
20
|
+
} from "./chunk-QNUVZO5X.js";
|
|
21
21
|
import "./chunk-4BKXL7SM.js";
|
|
22
22
|
import "./chunk-TB4W4Y4T.js";
|
|
23
23
|
import "./chunk-KHYD3WXE.js";
|
|
@@ -8,9 +8,9 @@ import {
|
|
|
8
8
|
} from "./chunk-E44DTERW.js";
|
|
9
9
|
import {
|
|
10
10
|
ConfigManager
|
|
11
|
-
} from "./chunk-
|
|
11
|
+
} from "./chunk-TW47X5AO.js";
|
|
12
12
|
import "./chunk-TZQHYZKT.js";
|
|
13
|
-
import "./chunk-
|
|
13
|
+
import "./chunk-QNUVZO5X.js";
|
|
14
14
|
import "./chunk-IW3Q7AE5.js";
|
|
15
15
|
|
|
16
16
|
// src/cli/usage.ts
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Declarative Web UI actions and startup hooks.
|
|
3
|
+
* Kept separate from app.js so static and dynamic UI markup can avoid inline handlers.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
function handleDeclarativeAction(action, el) {
|
|
7
|
+
switch (action) {
|
|
8
|
+
case 'toggle-auth-mode': toggleAuthMode(); break;
|
|
9
|
+
case 'show-enable-auth': showEnableAuthDialog(); break;
|
|
10
|
+
case 'logout': handleLogout(); break;
|
|
11
|
+
case 'toggle-batch-select': toggleBatchSelect(); break;
|
|
12
|
+
case 'select-all-sessions': selectAllSessions(); break;
|
|
13
|
+
case 'batch-delete-selected': batchDeleteSelected(); break;
|
|
14
|
+
case 'start-hub': window.startHub(); break;
|
|
15
|
+
case 'abort-hub': window.abortHub(); break;
|
|
16
|
+
case 'close-sidebar': closeSidebar(); break;
|
|
17
|
+
case 'import-templates': importTemplates(); break;
|
|
18
|
+
case 'export-templates': exportTemplates(); break;
|
|
19
|
+
case 'show-add-template': showAddTemplate(); break;
|
|
20
|
+
case 'cancel-template-form': cancelTemplateForm(); break;
|
|
21
|
+
case 'save-template-form': saveTemplateForm(); break;
|
|
22
|
+
case 'confirm-response': window.respondConfirm(el.dataset.requestId, el.dataset.approved === 'true'); break;
|
|
23
|
+
case 'batch-confirm-response': window.respondBatchConfirm(el.dataset.requestId, el); break;
|
|
24
|
+
case 'batch-deny-response': window.respondBatchDeny(el.dataset.requestId, el); break;
|
|
25
|
+
case 'ask-user-response': window.respondAskUser(el.dataset.requestId); break;
|
|
26
|
+
case 'auto-pause-response': window.respondAutoPause(el.dataset.requestId, el.dataset.pauseAction); break;
|
|
27
|
+
case 'use-template': useTemplate(el.closest('[data-tpl-id]')?.dataset.tplId); break;
|
|
28
|
+
case 'edit-template': editTemplate(el.closest('[data-tpl-id]')?.dataset.tplId); break;
|
|
29
|
+
case 'delete-template': deleteTemplate(el.closest('[data-tpl-id]')?.dataset.tplId); break;
|
|
30
|
+
case 'insert-file-ref': insertFileRef(el.dataset.filePath || ''); break;
|
|
31
|
+
case 'show-full-preview':
|
|
32
|
+
if (el.previousElementSibling) el.previousElementSibling.style.maxHeight = 'none';
|
|
33
|
+
el.remove();
|
|
34
|
+
break;
|
|
35
|
+
case 'load-session': send({ type: 'command', name: 'session', args: ['load', el.dataset.sessionId] }); break;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
document.addEventListener('click', (event) => {
|
|
40
|
+
const themeEl = event.target.closest('[data-theme-choice]');
|
|
41
|
+
if (themeEl) {
|
|
42
|
+
event.preventDefault();
|
|
43
|
+
window.setTheme(themeEl.dataset.themeChoice);
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
const actionEl = event.target.closest('[data-action]');
|
|
48
|
+
if (!actionEl) return;
|
|
49
|
+
event.preventDefault();
|
|
50
|
+
handleDeclarativeAction(actionEl.dataset.action, actionEl);
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
document.addEventListener('keydown', (event) => {
|
|
54
|
+
if (event.key !== 'Enter') return;
|
|
55
|
+
const actionEl = event.target.closest('[data-enter-action]');
|
|
56
|
+
if (!actionEl) return;
|
|
57
|
+
event.preventDefault();
|
|
58
|
+
handleDeclarativeAction(actionEl.dataset.enterAction, actionEl);
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
document.getElementById('auth-form')?.addEventListener('submit', handleAuth);
|
|
62
|
+
|
|
63
|
+
function registerServiceWorker() {
|
|
64
|
+
// Self-updating service worker (v0.4.159). A new SW postMessages
|
|
65
|
+
// 'sw-updated' (and triggers controllerchange) when it takes over; reload
|
|
66
|
+
// once so users do not stay on stale index.html/app.js after an upgrade.
|
|
67
|
+
if (!('serviceWorker' in navigator)) return;
|
|
68
|
+
let swReloaded = false;
|
|
69
|
+
const reloadOnce = () => {
|
|
70
|
+
if (!swReloaded) {
|
|
71
|
+
swReloaded = true;
|
|
72
|
+
location.reload();
|
|
73
|
+
}
|
|
74
|
+
};
|
|
75
|
+
navigator.serviceWorker.addEventListener('message', (e) => {
|
|
76
|
+
if (e.data && e.data.type === 'sw-updated') reloadOnce();
|
|
77
|
+
});
|
|
78
|
+
navigator.serviceWorker.addEventListener('controllerchange', reloadOnce);
|
|
79
|
+
navigator.serviceWorker.register('sw.js').then((reg) => {
|
|
80
|
+
reg.update();
|
|
81
|
+
}).catch(() => {});
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
registerServiceWorker();
|
package/dist/web/client/app.js
CHANGED
|
@@ -336,8 +336,8 @@ function handleConfirmRequest(msg) {
|
|
|
336
336
|
</div>
|
|
337
337
|
${msg.diff ? `<div class="confirm-diff w-full">${renderDiffHtml(msg.diff)}</div>` : ''}
|
|
338
338
|
<div class="flex gap-2 mt-2">
|
|
339
|
-
<button class="btn btn-success btn-sm btn-outline"
|
|
340
|
-
<button class="btn btn-error btn-sm btn-outline"
|
|
339
|
+
<button class="btn btn-success btn-sm btn-outline" data-action="confirm-response" data-request-id="${msg.requestId}" data-approved="true">✓ Approve</button>
|
|
340
|
+
<button class="btn btn-error btn-sm btn-outline" data-action="confirm-response" data-request-id="${msg.requestId}" data-approved="false">✗ Deny</button>
|
|
341
341
|
</div>
|
|
342
342
|
`;
|
|
343
343
|
messagesEl.appendChild(el);
|
|
@@ -363,8 +363,8 @@ function handleBatchConfirmRequest(msg) {
|
|
|
363
363
|
</div>
|
|
364
364
|
<div class="w-full my-1">${fileListHtml}</div>
|
|
365
365
|
<div class="flex gap-2 mt-2">
|
|
366
|
-
<button class="btn btn-success btn-sm btn-outline"
|
|
367
|
-
<button class="btn btn-error btn-sm btn-outline"
|
|
366
|
+
<button class="btn btn-success btn-sm btn-outline" data-action="batch-confirm-response" data-request-id="${msg.requestId}">✓ Approve Selected</button>
|
|
367
|
+
<button class="btn btn-error btn-sm btn-outline" data-action="batch-deny-response" data-request-id="${msg.requestId}">✗ Reject All</button>
|
|
368
368
|
</div>
|
|
369
369
|
`;
|
|
370
370
|
messagesEl.appendChild(el);
|
|
@@ -383,8 +383,8 @@ function handleAskUserRequest(msg) {
|
|
|
383
383
|
<input type="text" id="ask-input-${msg.requestId}"
|
|
384
384
|
class="input input-sm input-bordered flex-1"
|
|
385
385
|
placeholder="Your answer..."
|
|
386
|
-
|
|
387
|
-
<button class="btn btn-primary btn-sm"
|
|
386
|
+
data-enter-action="ask-user-response" data-request-id="${msg.requestId}">
|
|
387
|
+
<button class="btn btn-primary btn-sm" data-action="ask-user-response" data-request-id="${msg.requestId}">Send</button>
|
|
388
388
|
</div>
|
|
389
389
|
`;
|
|
390
390
|
messagesEl.appendChild(el);
|
|
@@ -407,12 +407,12 @@ function handleAutoPauseRequest(msg) {
|
|
|
407
407
|
<input type="text" id="pause-input-${msg.requestId}"
|
|
408
408
|
class="input input-sm input-bordered flex-1"
|
|
409
409
|
placeholder="Optional: redirect AI with a new instruction..."
|
|
410
|
-
|
|
410
|
+
data-enter-action="auto-pause-response" data-request-id="${msg.requestId}" data-pause-action="redirect">
|
|
411
411
|
</div>
|
|
412
412
|
<div class="flex gap-2">
|
|
413
|
-
<button class="btn btn-success btn-sm flex-1"
|
|
414
|
-
<button class="btn btn-primary btn-sm flex-1"
|
|
415
|
-
<button class="btn btn-error btn-sm flex-1"
|
|
413
|
+
<button class="btn btn-success btn-sm flex-1" data-action="auto-pause-response" data-request-id="${msg.requestId}" data-pause-action="continue">▶ Continue</button>
|
|
414
|
+
<button class="btn btn-primary btn-sm flex-1" data-action="auto-pause-response" data-request-id="${msg.requestId}" data-pause-action="redirect">↪ Redirect</button>
|
|
415
|
+
<button class="btn btn-error btn-sm flex-1" data-action="auto-pause-response" data-request-id="${msg.requestId}" data-pause-action="stop">⏹ Stop</button>
|
|
416
416
|
</div>
|
|
417
417
|
`;
|
|
418
418
|
messagesEl.appendChild(el);
|
|
@@ -666,6 +666,7 @@ window.setTheme = function(theme) {
|
|
|
666
666
|
|
|
667
667
|
// ── UI helpers ─────────────────────────────────────────────────────
|
|
668
668
|
|
|
669
|
+
|
|
669
670
|
function createAssistantMessage() {
|
|
670
671
|
const el = document.createElement('div');
|
|
671
672
|
el.className = 'msg-assistant';
|
|
@@ -714,11 +715,11 @@ function renderMarkdown(el, text) {
|
|
|
714
715
|
const btn = document.createElement('button');
|
|
715
716
|
btn.className = 'copy-code-btn btn btn-ghost btn-xs';
|
|
716
717
|
btn.textContent = '📋 Copy';
|
|
717
|
-
btn.
|
|
718
|
-
navigator.clipboard.writeText(block.textContent || '');
|
|
719
|
-
btn.textContent = '
|
|
720
|
-
setTimeout(() => btn.textContent = '
|
|
721
|
-
};
|
|
718
|
+
btn.addEventListener('click', () => {
|
|
719
|
+
navigator.clipboard.writeText(block.textContent || '');
|
|
720
|
+
btn.textContent = 'Copied';
|
|
721
|
+
setTimeout(() => btn.textContent = 'Copy', 1500);
|
|
722
|
+
});
|
|
722
723
|
pre.style.position = 'relative';
|
|
723
724
|
pre.appendChild(btn);
|
|
724
725
|
}
|
|
@@ -1920,12 +1921,12 @@ function addImageToPreview(file) {
|
|
|
1920
1921
|
<img src="${reader.result}" class="rounded max-h-16 max-w-[100px] object-contain border border-base-content/20" alt="${escapeHtml(file.name)}">
|
|
1921
1922
|
<button class="btn btn-xs btn-circle btn-error absolute -top-1 -right-1 opacity-80" title="Remove">✕</button>
|
|
1922
1923
|
`;
|
|
1923
|
-
thumb.querySelector('button').
|
|
1924
|
+
thumb.querySelector('button').addEventListener('click', () => {
|
|
1924
1925
|
const idx = pendingImages.findIndex(img => img.name === file.name && img.data === base64);
|
|
1925
1926
|
if (idx >= 0) pendingImages.splice(idx, 1);
|
|
1926
1927
|
thumb.remove();
|
|
1927
1928
|
if (pendingImages.length === 0) imagePreviewArea.classList.add('hidden');
|
|
1928
|
-
};
|
|
1929
|
+
});
|
|
1929
1930
|
imagePreviewArea.appendChild(thumb);
|
|
1930
1931
|
imagePreviewArea.classList.remove('hidden');
|
|
1931
1932
|
};
|
|
@@ -1991,189 +1992,6 @@ function handleMemoryContent(msg) {
|
|
|
1991
1992
|
|
|
1992
1993
|
// ── Prompt Templates ───────────────────────────────────────────────
|
|
1993
1994
|
|
|
1994
|
-
const TEMPLATES_KEY = 'aicli-templates';
|
|
1995
|
-
|
|
1996
|
-
function loadTemplates() {
|
|
1997
|
-
try {
|
|
1998
|
-
return JSON.parse(localStorage.getItem(TEMPLATES_KEY) || '[]');
|
|
1999
|
-
} catch { return []; }
|
|
2000
|
-
}
|
|
2001
|
-
|
|
2002
|
-
function saveTemplatesToStorage(templates) {
|
|
2003
|
-
localStorage.setItem(TEMPLATES_KEY, JSON.stringify(templates));
|
|
2004
|
-
}
|
|
2005
|
-
|
|
2006
|
-
function openTemplatesModal() {
|
|
2007
|
-
const modal = document.getElementById('templates-modal');
|
|
2008
|
-
if (!modal) return;
|
|
2009
|
-
cancelTemplateForm();
|
|
2010
|
-
renderTemplateList();
|
|
2011
|
-
document.getElementById('template-search').value = '';
|
|
2012
|
-
modal.showModal();
|
|
2013
|
-
}
|
|
2014
|
-
|
|
2015
|
-
function renderTemplateList(filter) {
|
|
2016
|
-
const listEl = document.getElementById('template-list');
|
|
2017
|
-
if (!listEl) return;
|
|
2018
|
-
const templates = loadTemplates();
|
|
2019
|
-
const q = (filter || '').toLowerCase();
|
|
2020
|
-
const filtered = q
|
|
2021
|
-
? templates.filter(t => t.name.toLowerCase().includes(q) || (t.tags || []).some(tag => tag.toLowerCase().includes(q)) || t.content.toLowerCase().includes(q))
|
|
2022
|
-
: templates;
|
|
2023
|
-
|
|
2024
|
-
if (filtered.length === 0) {
|
|
2025
|
-
listEl.innerHTML = `<div class="template-empty">${q ? 'No matching templates' : 'No templates yet. Click + New to create one.'}</div>`;
|
|
2026
|
-
return;
|
|
2027
|
-
}
|
|
2028
|
-
|
|
2029
|
-
listEl.innerHTML = filtered.map(t => {
|
|
2030
|
-
const preview = t.content.length > 80 ? t.content.slice(0, 80) + '...' : t.content;
|
|
2031
|
-
const tagsHtml = (t.tags || []).map(tag => `<span class="template-item-tag">${escapeHtml(tag)}</span>`).join('');
|
|
2032
|
-
return `
|
|
2033
|
-
<div class="template-item" data-tpl-id="${t.id}" onclick="useTemplate('${t.id}')">
|
|
2034
|
-
<div class="template-item-body">
|
|
2035
|
-
<div class="template-item-name">${escapeHtml(t.name)}</div>
|
|
2036
|
-
<div class="template-item-preview">${escapeHtml(preview)}</div>
|
|
2037
|
-
${tagsHtml ? `<div class="template-item-tags">${tagsHtml}</div>` : ''}
|
|
2038
|
-
</div>
|
|
2039
|
-
<div class="template-item-actions">
|
|
2040
|
-
<button class="btn btn-xs btn-ghost" onclick="event.stopPropagation(); editTemplate('${t.id}')" title="Edit">✏️</button>
|
|
2041
|
-
<button class="btn btn-xs btn-ghost" onclick="event.stopPropagation(); deleteTemplate('${t.id}')" title="Delete">🗑️</button>
|
|
2042
|
-
</div>
|
|
2043
|
-
</div>`;
|
|
2044
|
-
}).join('');
|
|
2045
|
-
}
|
|
2046
|
-
|
|
2047
|
-
function useTemplate(id) {
|
|
2048
|
-
const templates = loadTemplates();
|
|
2049
|
-
const tpl = templates.find(t => t.id === id);
|
|
2050
|
-
if (!tpl) return;
|
|
2051
|
-
userInput.value = tpl.content;
|
|
2052
|
-
userInput.focus();
|
|
2053
|
-
userInput.style.height = 'auto';
|
|
2054
|
-
userInput.style.height = Math.min(userInput.scrollHeight, 200) + 'px';
|
|
2055
|
-
document.getElementById('templates-modal')?.close();
|
|
2056
|
-
}
|
|
2057
|
-
|
|
2058
|
-
function showAddTemplate() {
|
|
2059
|
-
const form = document.getElementById('template-form');
|
|
2060
|
-
form.classList.remove('hidden');
|
|
2061
|
-
document.getElementById('tpl-edit-id').value = '';
|
|
2062
|
-
document.getElementById('tpl-name').value = '';
|
|
2063
|
-
document.getElementById('tpl-content').value = '';
|
|
2064
|
-
document.getElementById('tpl-tags').value = '';
|
|
2065
|
-
document.getElementById('tpl-name').focus();
|
|
2066
|
-
}
|
|
2067
|
-
|
|
2068
|
-
function editTemplate(id) {
|
|
2069
|
-
const templates = loadTemplates();
|
|
2070
|
-
const tpl = templates.find(t => t.id === id);
|
|
2071
|
-
if (!tpl) return;
|
|
2072
|
-
const form = document.getElementById('template-form');
|
|
2073
|
-
form.classList.remove('hidden');
|
|
2074
|
-
document.getElementById('tpl-edit-id').value = tpl.id;
|
|
2075
|
-
document.getElementById('tpl-name').value = tpl.name;
|
|
2076
|
-
document.getElementById('tpl-content').value = tpl.content;
|
|
2077
|
-
document.getElementById('tpl-tags').value = (tpl.tags || []).join(', ');
|
|
2078
|
-
document.getElementById('tpl-name').focus();
|
|
2079
|
-
}
|
|
2080
|
-
|
|
2081
|
-
function cancelTemplateForm() {
|
|
2082
|
-
document.getElementById('template-form')?.classList.add('hidden');
|
|
2083
|
-
}
|
|
2084
|
-
|
|
2085
|
-
function saveTemplateForm() {
|
|
2086
|
-
const name = document.getElementById('tpl-name').value.trim();
|
|
2087
|
-
const content = document.getElementById('tpl-content').value.trim();
|
|
2088
|
-
const tagsRaw = document.getElementById('tpl-tags').value.trim();
|
|
2089
|
-
const editId = document.getElementById('tpl-edit-id').value;
|
|
2090
|
-
|
|
2091
|
-
if (!name || !content) return;
|
|
2092
|
-
|
|
2093
|
-
const tags = tagsRaw ? tagsRaw.split(',').map(s => s.trim()).filter(Boolean) : [];
|
|
2094
|
-
const templates = loadTemplates();
|
|
2095
|
-
|
|
2096
|
-
if (editId) {
|
|
2097
|
-
const idx = templates.findIndex(t => t.id === editId);
|
|
2098
|
-
if (idx >= 0) {
|
|
2099
|
-
templates[idx].name = name;
|
|
2100
|
-
templates[idx].content = content;
|
|
2101
|
-
templates[idx].tags = tags;
|
|
2102
|
-
}
|
|
2103
|
-
} else {
|
|
2104
|
-
templates.unshift({
|
|
2105
|
-
id: 'tpl-' + Date.now().toString(36) + Math.random().toString(36).slice(2, 6),
|
|
2106
|
-
name,
|
|
2107
|
-
content,
|
|
2108
|
-
tags,
|
|
2109
|
-
createdAt: new Date().toISOString(),
|
|
2110
|
-
});
|
|
2111
|
-
}
|
|
2112
|
-
|
|
2113
|
-
saveTemplatesToStorage(templates);
|
|
2114
|
-
cancelTemplateForm();
|
|
2115
|
-
renderTemplateList();
|
|
2116
|
-
}
|
|
2117
|
-
|
|
2118
|
-
function deleteTemplate(id) {
|
|
2119
|
-
const templates = loadTemplates().filter(t => t.id !== id);
|
|
2120
|
-
saveTemplatesToStorage(templates);
|
|
2121
|
-
renderTemplateList(document.getElementById('template-search')?.value);
|
|
2122
|
-
}
|
|
2123
|
-
|
|
2124
|
-
function exportTemplates() {
|
|
2125
|
-
const templates = loadTemplates();
|
|
2126
|
-
if (templates.length === 0) return;
|
|
2127
|
-
const blob = new Blob([JSON.stringify(templates, null, 2)], { type: 'application/json' });
|
|
2128
|
-
const url = URL.createObjectURL(blob);
|
|
2129
|
-
const a = document.createElement('a');
|
|
2130
|
-
a.href = url;
|
|
2131
|
-
a.download = `aicli-templates-${new Date().toISOString().slice(0, 10)}.json`;
|
|
2132
|
-
a.click();
|
|
2133
|
-
URL.revokeObjectURL(url);
|
|
2134
|
-
}
|
|
2135
|
-
|
|
2136
|
-
function importTemplates() {
|
|
2137
|
-
const input = document.createElement('input');
|
|
2138
|
-
input.type = 'file';
|
|
2139
|
-
input.accept = '.json';
|
|
2140
|
-
input.onchange = () => {
|
|
2141
|
-
const file = input.files[0];
|
|
2142
|
-
if (!file) return;
|
|
2143
|
-
const reader = new FileReader();
|
|
2144
|
-
reader.onload = () => {
|
|
2145
|
-
try {
|
|
2146
|
-
const imported = JSON.parse(reader.result);
|
|
2147
|
-
if (!Array.isArray(imported)) throw new Error('Not an array');
|
|
2148
|
-
const existing = loadTemplates();
|
|
2149
|
-
const existingIds = new Set(existing.map(t => t.id));
|
|
2150
|
-
let added = 0;
|
|
2151
|
-
for (const t of imported) {
|
|
2152
|
-
if (t.id && t.name && t.content && !existingIds.has(t.id)) {
|
|
2153
|
-
existing.push(t);
|
|
2154
|
-
added++;
|
|
2155
|
-
}
|
|
2156
|
-
}
|
|
2157
|
-
saveTemplatesToStorage(existing);
|
|
2158
|
-
renderTemplateList();
|
|
2159
|
-
addInfoMessage(`📥 Imported ${added} template(s).`);
|
|
2160
|
-
} catch {
|
|
2161
|
-
addErrorMessage('Failed to import templates: invalid JSON format.');
|
|
2162
|
-
}
|
|
2163
|
-
};
|
|
2164
|
-
reader.readAsText(file);
|
|
2165
|
-
};
|
|
2166
|
-
input.click();
|
|
2167
|
-
}
|
|
2168
|
-
|
|
2169
|
-
// Template button + search binding
|
|
2170
|
-
document.getElementById('btn-templates')?.addEventListener('click', openTemplatesModal);
|
|
2171
|
-
document.getElementById('template-search')?.addEventListener('input', (e) => {
|
|
2172
|
-
renderTemplateList(e.target.value);
|
|
2173
|
-
});
|
|
2174
|
-
|
|
2175
|
-
// ── File Tree ──────────────────────────────────────────────────────
|
|
2176
|
-
|
|
2177
1995
|
const fileTreeEl = document.getElementById('file-tree');
|
|
2178
1996
|
const fileTreeCwdEl = document.getElementById('file-tree-cwd');
|
|
2179
1997
|
const btnFileTreeRefresh = document.getElementById('btn-file-tree-refresh');
|
|
@@ -2324,10 +2142,10 @@ async function previewFileInChat(filePath) {
|
|
|
2324
2142
|
<div class="flex items-center gap-2 mb-1">
|
|
2325
2143
|
<span class="text-xs font-semibold opacity-70">📄 ${escapeHtml(filePath)}</span>
|
|
2326
2144
|
<span class="badge badge-ghost badge-xs">${sizeKb} KB</span>
|
|
2327
|
-
<button class="btn btn-xs btn-ghost ml-auto opacity-50"
|
|
2145
|
+
<button class="btn btn-xs btn-ghost ml-auto opacity-50" data-action="insert-file-ref" data-file-path="${escapeHtml(filePath)}">Insert @ref</button>
|
|
2328
2146
|
</div>
|
|
2329
2147
|
<pre style="max-height:300px"><code class="language-${escapeHtml(ext)}">${escapeHtml(data.content)}</code></pre>
|
|
2330
|
-
<button class="btn btn-xs btn-ghost mt-1 opacity-50 text-xs"
|
|
2148
|
+
<button class="btn btn-xs btn-ghost mt-1 opacity-50 text-xs" data-action="show-full-preview">▼ Show all</button>
|
|
2331
2149
|
`;
|
|
2332
2150
|
el.querySelectorAll('pre code').forEach(block => {
|
|
2333
2151
|
try { hljs.highlightElement(block); } catch {}
|
|
@@ -2805,8 +2623,8 @@ async function handleAuth(event) {
|
|
|
2805
2623
|
}
|
|
2806
2624
|
}
|
|
2807
2625
|
|
|
2808
|
-
// Legacy WS auth_result handler — kept for
|
|
2809
|
-
//
|
|
2626
|
+
// Legacy WS auth_result handler — kept for flows that still hit the WS auth path.
|
|
2627
|
+
// The server no longer echoes tokens; auth state is carried by httpOnly cookie.
|
|
2810
2628
|
function handleAuthResult(msg) {
|
|
2811
2629
|
const errorEl = document.getElementById('auth-error');
|
|
2812
2630
|
const submitBtn = document.getElementById('auth-submit');
|
|
@@ -3308,7 +3126,7 @@ function hubDone(msg) {
|
|
|
3308
3126
|
document.getElementById('hub-abort-btn').classList.add('hidden');
|
|
3309
3127
|
const status = document.getElementById('hub-status');
|
|
3310
3128
|
if (msg.saved && msg.sessionId) {
|
|
3311
|
-
status.innerHTML = `Saved. <a class="link link-primary"
|
|
3129
|
+
status.innerHTML = `Saved. <a class="link link-primary" data-action="load-session" data-session-id="${msg.sessionId}">Open session</a>`;
|
|
3312
3130
|
} else {
|
|
3313
3131
|
status.textContent = msg.saved ? 'Saved to history.' : 'Done (not saved).';
|
|
3314
3132
|
}
|