jinzd-ai-cli 0.4.206 → 0.4.208
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/{batch-6PORMJWT.js → batch-3T44NFLG.js} +2 -2
- package/dist/{chunk-QQYSZMET.js → chunk-2OVMMSGQ.js} +3 -3
- package/dist/{chunk-2WV6AGHM.js → chunk-J22B3OSQ.js} +1 -1
- package/dist/{chunk-QNUVZO5X.js → chunk-KV4GYNEA.js} +1 -1
- package/dist/{chunk-KJHMRAJU.js → chunk-P7JY3SWA.js} +1 -1
- package/dist/{chunk-BQIV4ZQT.js → chunk-QDY72ABW.js} +1 -1
- package/dist/{chunk-KOU4KX7J.js → chunk-TD7JEHCR.js} +2 -2
- package/dist/{chunk-TW47X5AO.js → chunk-TM4MS63K.js} +1 -1
- package/dist/{chunk-SFCNFX42.js → chunk-VWYUB22Y.js} +1 -1
- package/dist/{ci-AYMV66P3.js → ci-6QWBVRJX.js} +2 -2
- package/dist/{constants-NHGTSHKT.js → constants-SZTQNN7K.js} +1 -1
- package/dist/{doctor-cli-WKH7T4AW.js → doctor-cli-I2Y2YR4V.js} +4 -4
- package/dist/electron-server.js +5 -8
- package/dist/{hub-6R3M3NTC.js → hub-XVPFBODB.js} +1 -1
- package/dist/index.js +90 -88
- package/dist/{run-tests-5F2OBWIK.js → run-tests-D5SNUBYX.js} +2 -2
- package/dist/{run-tests-NBCA4KEG.js → run-tests-HZ2CRCTZ.js} +1 -1
- package/dist/{server-LDPQ3DLK.js → server-4EFTRFTN.js} +10 -13
- package/dist/{server-37EXC4EB.js → server-PVKLPRUP.js} +4 -4
- package/dist/{task-orchestrator-2DTDVCMR.js → task-orchestrator-2A5VCFLS.js} +4 -4
- package/dist/{usage-SZWZFX3T.js → usage-Q24E5636.js} +2 -2
- package/dist/web/client/actions.js +84 -0
- package/dist/web/client/app.js +20 -202
- package/dist/web/client/index.html +26 -41
- package/dist/web/client/sw.js +1 -1
- package/dist/web/client/templates.js +188 -0
- package/package.json +1 -1
|
@@ -3,13 +3,13 @@ import {
|
|
|
3
3
|
ToolRegistry,
|
|
4
4
|
googleSearchContext,
|
|
5
5
|
truncateOutput
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-2OVMMSGQ.js";
|
|
7
7
|
import "./chunk-T2NL5ZIA.js";
|
|
8
8
|
import "./chunk-BXP6YZ2P.js";
|
|
9
|
-
import "./chunk-
|
|
9
|
+
import "./chunk-VWYUB22Y.js";
|
|
10
10
|
import {
|
|
11
11
|
runTool
|
|
12
|
-
} from "./chunk-
|
|
12
|
+
} from "./chunk-J22B3OSQ.js";
|
|
13
13
|
import {
|
|
14
14
|
getDangerLevel,
|
|
15
15
|
runLeanAgentLoop
|
|
@@ -17,7 +17,7 @@ import {
|
|
|
17
17
|
import "./chunk-TZQHYZKT.js";
|
|
18
18
|
import {
|
|
19
19
|
SUBAGENT_ALLOWED_TOOLS
|
|
20
|
-
} from "./chunk-
|
|
20
|
+
} from "./chunk-KV4GYNEA.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-TM4MS63K.js";
|
|
12
12
|
import "./chunk-TZQHYZKT.js";
|
|
13
|
-
import "./chunk-
|
|
13
|
+
import "./chunk-KV4GYNEA.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
|
+
btn.addEventListener('click', () => {
|
|
718
719
|
navigator.clipboard.writeText(block.textContent || '');
|
|
719
|
-
btn.textContent = '
|
|
720
|
-
setTimeout(() => btn.textContent = '
|
|
721
|
-
};
|
|
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 {}
|
|
@@ -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
|
}
|
|
@@ -36,7 +36,7 @@
|
|
|
36
36
|
<p id="auth-subtitle" class="text-sm text-base-content/60 mt-1">Sign in to continue</p>
|
|
37
37
|
</div>
|
|
38
38
|
<div id="auth-error" class="alert alert-error text-sm mb-4 hidden"></div>
|
|
39
|
-
<form id="auth-form"
|
|
39
|
+
<form id="auth-form" >
|
|
40
40
|
<div class="form-control mb-3">
|
|
41
41
|
<label class="label"><span class="label-text">Username</span></label>
|
|
42
42
|
<input id="auth-username" type="text" class="input input-bordered w-full" placeholder="username" autocomplete="username" required minlength="2" maxlength="32">
|
|
@@ -48,7 +48,7 @@
|
|
|
48
48
|
<button id="auth-submit" type="submit" class="btn btn-primary w-full">Sign In</button>
|
|
49
49
|
</form>
|
|
50
50
|
<div class="text-center mt-4">
|
|
51
|
-
<button id="auth-toggle" class="btn btn-ghost btn-sm"
|
|
51
|
+
<button id="auth-toggle" class="btn btn-ghost btn-sm" data-action="toggle-auth-mode" type="button">
|
|
52
52
|
Don't have an account? <span class="text-primary">Register</span>
|
|
53
53
|
</button>
|
|
54
54
|
</div>
|
|
@@ -76,18 +76,18 @@
|
|
|
76
76
|
<div class="dropdown dropdown-end">
|
|
77
77
|
<div tabindex="0" role="button" class="btn btn-sm btn-ghost">🎨</div>
|
|
78
78
|
<ul tabindex="0" class="dropdown-content menu bg-base-200 rounded-box z-10 w-40 p-2 shadow-lg border border-base-content/10">
|
|
79
|
-
<li><a
|
|
80
|
-
<li><a
|
|
81
|
-
<li><a
|
|
82
|
-
<li><a
|
|
83
|
-
<li><a
|
|
84
|
-
<li><a
|
|
85
|
-
<li><a
|
|
86
|
-
<li><a
|
|
79
|
+
<li><a data-theme-choice="dark">🌙 Dark</a></li>
|
|
80
|
+
<li><a data-theme-choice="night">🌃 Night</a></li>
|
|
81
|
+
<li><a data-theme-choice="dim">🌑 Dim</a></li>
|
|
82
|
+
<li><a data-theme-choice="synthwave">🎵 Synthwave</a></li>
|
|
83
|
+
<li><a data-theme-choice="cyberpunk">🤖 Cyberpunk</a></li>
|
|
84
|
+
<li><a data-theme-choice="light">☀️ Light</a></li>
|
|
85
|
+
<li><a data-theme-choice="cupcake">🧁 Cupcake</a></li>
|
|
86
|
+
<li><a data-theme-choice="nord">❄️ Nord</a></li>
|
|
87
87
|
</ul>
|
|
88
88
|
</div>
|
|
89
89
|
<!-- Enable Auth button (shown when no users registered) -->
|
|
90
|
-
<button id="btn-enable-auth" class="btn btn-sm btn-ghost hidden" title="Enable multi-user auth"
|
|
90
|
+
<button id="btn-enable-auth" class="btn btn-sm btn-ghost hidden" title="Enable multi-user auth" data-action="show-enable-auth">👤 Enable Auth</button>
|
|
91
91
|
<!-- User menu (shown when authenticated) -->
|
|
92
92
|
<div id="user-menu" class="dropdown dropdown-end hidden">
|
|
93
93
|
<div tabindex="0" role="button" class="btn btn-sm btn-ghost gap-1">
|
|
@@ -95,7 +95,7 @@
|
|
|
95
95
|
</div>
|
|
96
96
|
<ul tabindex="0" class="dropdown-content menu bg-base-200 rounded-box z-10 w-40 p-2 shadow-lg border border-base-content/10">
|
|
97
97
|
<li><a id="user-label" class="text-sm font-semibold pointer-events-none"></a></li>
|
|
98
|
-
<li><a
|
|
98
|
+
<li><a data-action="logout">🚪 Logout</a></li>
|
|
99
99
|
</ul>
|
|
100
100
|
</div>
|
|
101
101
|
</div>
|
|
@@ -119,16 +119,16 @@
|
|
|
119
119
|
<div id="tab-sessions" class="sidebar-tab-content flex flex-col flex-1 overflow-hidden">
|
|
120
120
|
<div class="p-2 border-b border-base-content/10 flex items-center justify-between gap-1">
|
|
121
121
|
<input id="session-search" type="text" class="input input-xs input-bordered flex-1 min-w-0" placeholder="Search...">
|
|
122
|
-
<button id="btn-batch-select" class="btn btn-xs btn-ghost flex-shrink-0" title="Select multiple"
|
|
122
|
+
<button id="btn-batch-select" class="btn btn-xs btn-ghost flex-shrink-0" title="Select multiple" data-action="toggle-batch-select">☑</button>
|
|
123
123
|
<button id="btn-new-session" class="btn btn-xs btn-primary btn-outline flex-shrink-0 whitespace-nowrap" title="New session">+ New</button>
|
|
124
124
|
</div>
|
|
125
125
|
<!-- Batch action bar (hidden by default) -->
|
|
126
126
|
<div id="batch-bar" class="hidden px-2 py-1 border-b border-base-content/10 flex items-center gap-1 bg-base-300 text-xs">
|
|
127
127
|
<span class="batch-count opacity-60">0 selected</span>
|
|
128
128
|
<span class="flex-1"></span>
|
|
129
|
-
<button class="btn btn-xs btn-ghost"
|
|
130
|
-
<button class="btn btn-xs btn-error btn-outline"
|
|
131
|
-
<button class="btn btn-xs btn-ghost"
|
|
129
|
+
<button class="btn btn-xs btn-ghost" data-action="select-all-sessions">All</button>
|
|
130
|
+
<button class="btn btn-xs btn-error btn-outline" data-action="batch-delete-selected">🗑 Delete</button>
|
|
131
|
+
<button class="btn btn-xs btn-ghost" data-action="toggle-batch-select">Cancel</button>
|
|
132
132
|
</div>
|
|
133
133
|
<div id="session-list" class="flex-1 overflow-y-auto p-2 flex flex-col gap-1 text-sm">
|
|
134
134
|
<div class="text-xs opacity-40 text-center py-4">No sessions yet</div>
|
|
@@ -216,8 +216,8 @@
|
|
|
216
216
|
<label class="flex items-center gap-2 text-xs cursor-pointer">
|
|
217
217
|
<input id="hub-lanes" type="checkbox" class="checkbox checkbox-xs"> Lanes view (one column per agent)
|
|
218
218
|
</label>
|
|
219
|
-
<button id="hub-start-btn" class="btn btn-primary btn-sm w-full"
|
|
220
|
-
<button id="hub-abort-btn" class="btn btn-error btn-outline btn-xs w-full hidden"
|
|
219
|
+
<button id="hub-start-btn" class="btn btn-primary btn-sm w-full" data-action="start-hub">🏛 Start discussion</button>
|
|
220
|
+
<button id="hub-abort-btn" class="btn btn-error btn-outline btn-xs w-full hidden" data-action="abort-hub">⏹ Stop</button>
|
|
221
221
|
<div id="hub-status" class="text-xs opacity-60"></div>
|
|
222
222
|
</div>
|
|
223
223
|
</div>
|
|
@@ -225,7 +225,7 @@
|
|
|
225
225
|
<!-- Sidebar resize handle -->
|
|
226
226
|
<div id="sidebar-resize" class="sidebar-resize-handle" title="Drag to resize sidebar"></div>
|
|
227
227
|
<!-- Sidebar backdrop (mobile overlay) -->
|
|
228
|
-
<div id="sidebar-backdrop" class="sidebar-backdrop hidden"
|
|
228
|
+
<div id="sidebar-backdrop" class="sidebar-backdrop hidden" data-action="close-sidebar"></div>
|
|
229
229
|
|
|
230
230
|
<!-- Chat Area -->
|
|
231
231
|
<div class="flex-1 flex flex-col overflow-hidden">
|
|
@@ -293,9 +293,9 @@
|
|
|
293
293
|
<div class="flex items-center justify-between mb-3">
|
|
294
294
|
<h3 class="font-bold text-lg">📝 Prompt Templates</h3>
|
|
295
295
|
<div class="flex gap-1">
|
|
296
|
-
<button class="btn btn-xs btn-ghost"
|
|
297
|
-
<button class="btn btn-xs btn-ghost"
|
|
298
|
-
<button class="btn btn-xs btn-ghost"
|
|
296
|
+
<button class="btn btn-xs btn-ghost" data-action="import-templates" title="Import">📥 Import</button>
|
|
297
|
+
<button class="btn btn-xs btn-ghost" data-action="export-templates" title="Export">📤 Export</button>
|
|
298
|
+
<button class="btn btn-xs btn-ghost" data-action="show-add-template" title="New template">+ New</button>
|
|
299
299
|
</div>
|
|
300
300
|
</div>
|
|
301
301
|
|
|
@@ -305,8 +305,8 @@
|
|
|
305
305
|
<textarea id="tpl-content" class="textarea textarea-bordered w-full text-sm mb-2" rows="4" placeholder="Prompt content..."></textarea>
|
|
306
306
|
<input id="tpl-tags" type="text" class="input input-sm input-bordered w-full mb-2" placeholder="Tags (comma-separated, optional)">
|
|
307
307
|
<div class="flex gap-2 justify-end">
|
|
308
|
-
<button class="btn btn-sm btn-ghost"
|
|
309
|
-
<button class="btn btn-sm btn-primary"
|
|
308
|
+
<button class="btn btn-sm btn-ghost" data-action="cancel-template-form">Cancel</button>
|
|
309
|
+
<button class="btn btn-sm btn-primary" data-action="save-template-form">Save</button>
|
|
310
310
|
</div>
|
|
311
311
|
<input type="hidden" id="tpl-edit-id">
|
|
312
312
|
</div>
|
|
@@ -339,22 +339,7 @@
|
|
|
339
339
|
</dialog>
|
|
340
340
|
|
|
341
341
|
<script src="app.js"></script>
|
|
342
|
-
<script>
|
|
343
|
-
|
|
344
|
-
// 'sw-updated' (and triggers controllerchange) when it takes over; we
|
|
345
|
-
// reload once so the user never gets stuck on a stale index.html/app.js
|
|
346
|
-
// after upgrading aicli. index.html/app.js are also network-only in sw.js.
|
|
347
|
-
if ('serviceWorker' in navigator) {
|
|
348
|
-
let swReloaded = false;
|
|
349
|
-
const reloadOnce = () => { if (!swReloaded) { swReloaded = true; location.reload(); } };
|
|
350
|
-
navigator.serviceWorker.addEventListener('message', (e) => {
|
|
351
|
-
if (e.data && e.data.type === 'sw-updated') reloadOnce();
|
|
352
|
-
});
|
|
353
|
-
navigator.serviceWorker.addEventListener('controllerchange', reloadOnce);
|
|
354
|
-
navigator.serviceWorker.register('sw.js').then((reg) => {
|
|
355
|
-
reg.update();
|
|
356
|
-
}).catch(() => {});
|
|
357
|
-
}
|
|
358
|
-
</script>
|
|
342
|
+
<script src="templates.js"></script>
|
|
343
|
+
<script src="actions.js"></script>
|
|
359
344
|
</body>
|
|
360
345
|
</html>
|
package/dist/web/client/sw.js
CHANGED
|
@@ -16,7 +16,7 @@ const CACHE_NAME = 'aicli-v3';
|
|
|
16
16
|
// HTML/JS that must always be fresh — never served from the SW cache, so an
|
|
17
17
|
// upgraded server is reflected on the very next load. Other assets (vendored
|
|
18
18
|
// CSS/JS, icons) are large + content-stable and fine to cache.
|
|
19
|
-
const NEVER_CACHE = new Set(['/', '/index.html', '/app.js']);
|
|
19
|
+
const NEVER_CACHE = new Set(['/', '/index.html', '/app.js', '/templates.js', '/actions.js']);
|
|
20
20
|
|
|
21
21
|
// App shell to precache (offline-capable startup). Deliberately EXCLUDES the
|
|
22
22
|
// always-fresh HTML/JS in NEVER_CACHE — only large content-stable assets.
|