@takimcizgisi/ajan 0.2.5 → 0.3.0

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.

Potentially problematic release.


This version of @takimcizgisi/ajan might be problematic. Click here for more details.

Files changed (71) hide show
  1. package/LICENSE +227 -674
  2. package/README.md +243 -305
  3. package/ajan-logo.txt +2 -0
  4. package/dist/config/configManager.js +122 -19
  5. package/dist/config/types.d.ts +37 -0
  6. package/dist/core/agent.d.ts +1 -1
  7. package/dist/core/agent.js +25 -4
  8. package/dist/discord/presence.d.ts +65 -0
  9. package/dist/discord/presence.js +401 -0
  10. package/dist/engine/llama.d.ts +5 -0
  11. package/dist/engine/llama.js +19 -5
  12. package/dist/engine/modelManager.d.ts +0 -1
  13. package/dist/engine/modelManager.js +0 -8
  14. package/dist/index.d.ts +1 -0
  15. package/dist/index.js +1 -0
  16. package/dist/service.js +0 -1
  17. package/dist/tools/playground.d.ts +4 -0
  18. package/dist/tools/playground.js +125 -0
  19. package/dist/tools/registry.d.ts +0 -1
  20. package/dist/tools/registry.js +5 -4
  21. package/dist/tools/taskComplete.js +16 -4
  22. package/dist/tools/terminal.js +12 -12
  23. package/dist/utils/paths.d.ts +1 -0
  24. package/dist/utils/paths.js +29 -11
  25. package/package.json +78 -106
  26. package/scripts/build-vscode.mjs +28 -0
  27. package/scripts/ensure-tgz.mjs +27 -0
  28. package/scripts/install-vscode.mjs +236 -0
  29. package/scripts/release.mjs +19 -0
  30. package/scripts/smoke-new-tools.ts +79 -0
  31. package/scripts/smoke-tools.ts +201 -0
  32. package/src/vscode/LICENSE +674 -0
  33. package/src/vscode/README.md +54 -0
  34. package/src/vscode/media/assets/Anton.ttf +0 -0
  35. package/src/vscode/media/chat.js +634 -0
  36. package/src/vscode/media/style.css +767 -0
  37. package/src/vscode/out/extension.js +598 -0
  38. package/src/vscode/package.json +243 -0
  39. package/dist/cli/index.d.ts +0 -2
  40. package/dist/cli/index.js +0 -741
  41. package/dist/cli/tui.d.ts +0 -145
  42. package/dist/cli/tui.js +0 -1003
  43. package/dist/electron/main.d.ts +0 -1
  44. package/dist/electron/main.js +0 -364
  45. package/dist/electron/preload.d.ts +0 -1
  46. package/dist/electron/preload.js +0 -67
  47. package/dist/utils/clipboard.d.ts +0 -2
  48. package/dist/utils/clipboard.js +0 -40
  49. package/dist/utils/lock.d.ts +0 -12
  50. package/dist/utils/lock.js +0 -68
  51. package/dist/utils/sacGuard.d.ts +0 -4
  52. package/dist/utils/sacGuard.js +0 -47
  53. package/dist/utils/spinner.d.ts +0 -10
  54. package/dist/utils/spinner.js +0 -32
  55. package/src/gui/assets/image/logo.svg +0 -1
  56. package/src/gui/assets/image/opencode.svg +0 -18
  57. package/src/gui/css/style.css +0 -430
  58. package/src/gui/html/chat.html +0 -34
  59. package/src/gui/html/downloads.html +0 -11
  60. package/src/gui/html/hakkinda.html +0 -26
  61. package/src/gui/html/index.html +0 -82
  62. package/src/gui/html/projects.html +0 -12
  63. package/src/gui/html/settings.html +0 -4
  64. package/src/gui/js/app.js +0 -197
  65. package/src/gui/js/chat.js +0 -434
  66. package/src/gui/js/downloads.js +0 -172
  67. package/src/gui/js/hakkinda.js +0 -16
  68. package/src/gui/js/projects.js +0 -113
  69. package/src/gui/js/settings.js +0 -177
  70. /package/src/{gui/assets/image → vscode/media/assets}/AJAN_LOGO.svg +0 -0
  71. /package/src/{gui/assets/image → vscode/media/assets}/ajan.png +0 -0
@@ -0,0 +1,634 @@
1
+ /* AJAN AI — WebView istemci mantığı (VSCode teması + AJAN markası) */
2
+ (function () {
3
+ "use strict";
4
+
5
+ const vscode = acquireVsCodeApi();
6
+
7
+ const $ = (sel) => document.querySelector(sel);
8
+
9
+ const chatLogs = $("#chat-logs");
10
+ const chatInput = $("#chat-input");
11
+ const chatForm = $("#chat-form");
12
+ const sendBtn = $("#chat-send-btn");
13
+ const stopBtn = $("#chat-stop-btn");
14
+ const modelSelect = $("#model-select");
15
+ const statusDot = $("#ui-status-dot");
16
+ const statusText = $("#ui-status-text");
17
+ const statusMeta = $("#status-meta");
18
+ const loadBar = $("#load-bar");
19
+ const loadFill = $("#load-fill");
20
+ const loadText = $("#load-text");
21
+ const chatLogo = $("#chat-logo-wrap");
22
+ const chatPanel = $("#chat-panel");
23
+ const settingsPanel = $("#settings-panel");
24
+ const btnToggleSS = $("#btn-toggle-ss");
25
+ const btnNewChat = $("#btn-new-chat");
26
+ const btnPlayground = $("#btn-playground");
27
+ const btnRefreshModels = $("#btn-refresh-models");
28
+ const toast = $("#toast");
29
+
30
+ let active = false;
31
+ let currentAssistantEl = null;
32
+ let currentThinkingEl = null;
33
+ let chatMessages = [];
34
+
35
+ // ── Yardımcılar ──
36
+ let stickToBottom = true;
37
+
38
+ function isNearBottom() {
39
+ if (!chatLogs) return true;
40
+ return chatLogs.scrollHeight - chatLogs.scrollTop - chatLogs.clientHeight <= 3;
41
+ }
42
+
43
+ function scrollToBottom() {
44
+ if (!stickToBottom) return;
45
+ requestAnimationFrame(() => {
46
+ if (chatLogs && stickToBottom && isNearBottom()) chatLogs.scrollTop = chatLogs.scrollHeight;
47
+ });
48
+ }
49
+
50
+ function scrollReset() {
51
+ stickToBottom = true;
52
+ }
53
+
54
+ // ` **bold** *italic* ~~strike~~ --> inline HTML
55
+ function formatInline(text) {
56
+ let s = escapeHTML(text);
57
+ s = s.replace(/`([^`]+)`/g, '<code class="inline-code">$1</code>');
58
+ s = s.replace(/\*\*([^*]+)\*\*/g, "<strong>$1</strong>");
59
+ s = s.replace(/(^|[^*])\*([^*]+)\*/g, "$1<em>$2</em>");
60
+ s = s.replace(/~~([^~]+)~~/g, "<del>$1</del>");
61
+ return s;
62
+ }
63
+
64
+ function escapeHTML(str) {
65
+ const map = { "&": "&amp;", "<": "&lt;", ">": "&gt;", "'": "&#39;", '"': "&quot;" };
66
+ return str.replace(/[&<>'"]/g, (c) => map[c] || c);
67
+ }
68
+
69
+ function showToast(msg, type) {
70
+ toast.textContent = msg;
71
+ toast.className = "toast show " + (type || "");
72
+ clearTimeout(showToast._t);
73
+ showToast._t = setTimeout(() => toast.classList.remove("show"), 3200);
74
+ }
75
+
76
+ function setStatus(kind, text, meta) {
77
+ statusDot.className = "status-dot " + kind;
78
+ statusText.textContent = text;
79
+ if (statusMeta) statusMeta.textContent = meta || "";
80
+ }
81
+
82
+ function setActive(v) {
83
+ active = v;
84
+ sendBtn.disabled = v;
85
+ chatInput.disabled = v;
86
+ stopBtn.style.display = v ? "flex" : "none";
87
+ sendBtn.style.display = v ? "none" : "flex";
88
+ if (!v) chatInput.focus();
89
+ }
90
+
91
+ function setBusyUI(v) {
92
+ setActive(v);
93
+ setStatus(v ? "busy" : "ok", v ? "Çalışıyor…" : "Hazır");
94
+ }
95
+
96
+ function updateLogoVisibility() {
97
+ if (!chatLogo) return;
98
+ chatLogo.style.display = chatMessages.length > 0 ? "none" : "block";
99
+ }
100
+
101
+ // ── Mesajlar ──
102
+ function appendMessage(sender, text, extraClass) {
103
+ const wrapper = document.createElement("div");
104
+ wrapper.className = "msg msg-" + sender + (extraClass ? " " + extraClass : "");
105
+ const label = sender === "user" ? "SİZ" : "AJAN";
106
+ wrapper.innerHTML =
107
+ '<div class="msg-bubble"><span class="msg-label">' + label + "</span><span>" + formatInline(text) + "</span></div>";
108
+ chatLogs.appendChild(wrapper);
109
+ scrollToBottom();
110
+ return wrapper;
111
+ }
112
+
113
+ function appendRaw(sender, html, extraClass) {
114
+ const wrapper = document.createElement("div");
115
+ wrapper.className = "msg msg-" + sender + (extraClass ? " " + extraClass : "");
116
+ wrapper.innerHTML = '<div class="msg-bubble">' + html + "</div>";
117
+ chatLogs.appendChild(wrapper);
118
+ scrollToBottom();
119
+ return wrapper;
120
+ }
121
+
122
+ let assistantBuffer = "";
123
+ function startAssistantBlock() {
124
+ const wrapper = document.createElement("div");
125
+ wrapper.className = "msg msg-ai";
126
+ wrapper.innerHTML =
127
+ '<div class="msg-bubble"><span class="msg-label">AJAN</span><span class="assistant-text"></span></div>';
128
+ chatLogs.appendChild(wrapper);
129
+ currentAssistantEl = wrapper.querySelector(".assistant-text");
130
+ assistantBuffer = "";
131
+ scrollToBottom();
132
+ }
133
+
134
+ function appendToAssistant(text) {
135
+ if (!currentAssistantEl) startAssistantBlock();
136
+ if (currentAssistantEl) {
137
+ assistantBuffer += text;
138
+ currentAssistantEl.innerHTML = formatInline(assistantBuffer);
139
+ }
140
+ scrollToBottom();
141
+ }
142
+
143
+ function finalizeAssistant() {
144
+ if (currentAssistantEl) {
145
+ chatMessages.push({ kind: "assistant", text: assistantBuffer });
146
+ saveCurrentSession();
147
+ }
148
+ assistantBuffer = "";
149
+ currentAssistantEl = null;
150
+ }
151
+
152
+ let thinkingUserToggled = false;
153
+ function showThinking() {
154
+ if (currentThinkingEl) return;
155
+ const el = appendRaw(
156
+ "ai",
157
+ '<div class="think-block">' +
158
+ '<div class="think-header" role="button" tabindex="0">' +
159
+ '<span class="think-label">Düşünce…</span>' +
160
+ '<span class="think-arrow" aria-hidden="true">▸</span>' +
161
+ "</div>" +
162
+ '<div class="think-body"><span class="think-text"></span></div>' +
163
+ "</div>",
164
+ "msg-think think-collapsed"
165
+ );
166
+ if (el) {
167
+ currentThinkingEl = el.querySelector(".think-text");
168
+ const header = el.querySelector(".think-header");
169
+ thinkingUserToggled = false;
170
+ header.addEventListener("click", () => {
171
+ const collapsed = el.classList.toggle("think-collapsed");
172
+ thinkingUserToggled = true;
173
+ const arrow = el.querySelector(".think-arrow");
174
+ if (arrow) arrow.textContent = collapsed ? "▸" : "▾";
175
+ });
176
+ }
177
+ scrollToBottom();
178
+ }
179
+
180
+ function appendThinking(text) {
181
+ if (!currentThinkingEl) showThinking();
182
+ if (currentThinkingEl) currentThinkingEl.textContent += text;
183
+ scrollToBottom();
184
+ }
185
+
186
+ function hideThinking() {
187
+ if (currentThinkingEl) {
188
+ chatMessages.push({ kind: "thought", text: currentThinkingEl.textContent || "" });
189
+ saveCurrentSession();
190
+ }
191
+ currentThinkingEl = null;
192
+ const thinkBlocks = chatLogs ? chatLogs.querySelectorAll(".msg-think .think-block") : [];
193
+ const last = thinkBlocks.length > 0 ? thinkBlocks[thinkBlocks.length - 1].closest(".msg-think") : null;
194
+ if (last && !thinkingUserToggled) {
195
+ last.classList.add("think-collapsed");
196
+ const arrow = last.querySelector(".think-arrow");
197
+ if (arrow) arrow.textContent = "▸";
198
+ }
199
+ }
200
+
201
+ function showToolCall(name) {
202
+ appendRaw("ai", '<div class="tool-status">⚙️ ' + escapeHTML(name) + " çalıştırılıyor…</div>", "msg-tool");
203
+ chatMessages.push({ kind: "tool", name, state: "running", startedAt: Date.now() });
204
+ }
205
+
206
+ function showContinueRound() {
207
+ appendRaw("ai", '<div class="tool-status">⏭ AJAN devam etmeyi seçti (continue:true)…</div>', "msg-tool");
208
+ }
209
+
210
+ function showToolResult(name, ok, output) {
211
+ const truncated = output && output.length > 500 ? output.slice(0, 500) + "\n… (kesildi)" : output || "";
212
+ const toolEls = chatLogs.querySelectorAll(".msg-tool");
213
+ const lastToolEl = toolEls[toolEls.length - 1];
214
+ if (lastToolEl) {
215
+ const statusClass = ok ? "ok" : "err";
216
+ const icon = ok ? "✅" : "❌";
217
+ const bubble = lastToolEl.querySelector(".msg-bubble");
218
+ if (bubble) {
219
+ bubble.innerHTML =
220
+ '<div class="tool-status ' +
221
+ statusClass +
222
+ '">' +
223
+ icon +
224
+ " " +
225
+ escapeHTML(name) +
226
+ "</div><div class='tool-output'>" +
227
+ escapeHTML(truncated) +
228
+ "</div>";
229
+ }
230
+ }
231
+ for (let i = chatMessages.length - 1; i >= 0; i--) {
232
+ const m = chatMessages[i];
233
+ if (m && m.kind === "tool" && m.name === name && m.state === "running") {
234
+ m.state = ok ? "done" : "error";
235
+ m.elapsed = Date.now() - (m.startedAt || Date.now());
236
+ m.output = truncated;
237
+ break;
238
+ }
239
+ }
240
+ saveCurrentSession();
241
+ }
242
+
243
+ // ── Oturum kaydetme ──
244
+ let currentSessionId = null;
245
+ function saveCurrentSession() {
246
+ const meaningful = chatMessages.filter((m) => m.kind !== "info");
247
+ if (meaningful.length === 0) return;
248
+ if (!currentSessionId) currentSessionId = String(Date.now());
249
+ const now = new Date().toISOString();
250
+ const firstUser = chatMessages.find((m) => m.kind === "user");
251
+ const title = firstUser && firstUser.text ? firstUser.text.split("\n")[0].slice(0, 32) : "Yeni Sohbet";
252
+ vscode.postMessage({
253
+ type: "session-save",
254
+ session: {
255
+ id: currentSessionId,
256
+ title,
257
+ mode: "agent",
258
+ createdAt: now,
259
+ updatedAt: now,
260
+ history: [],
261
+ messages: meaningful,
262
+ todos: []
263
+ }
264
+ });
265
+ }
266
+
267
+ function newChat() {
268
+ currentSessionId = null;
269
+ chatMessages = [];
270
+ if (chatLogs) chatLogs.innerHTML = "";
271
+ scrollReset();
272
+ updateLogoVisibility();
273
+ vscode.postMessage({ type: "new-chat" });
274
+ chatInput.focus();
275
+ }
276
+
277
+ // ── Gönder ──
278
+ function sendMessage() {
279
+ const text = chatInput.value.trim();
280
+ if (!text || active) return;
281
+
282
+ chatMessages.push({ kind: "user", text });
283
+ appendMessage("user", text);
284
+ chatInput.value = "";
285
+
286
+ setBusyUI(true);
287
+ scrollReset();
288
+ updateLogoVisibility();
289
+
290
+ vscode.postMessage({ type: "send", text, modelId: modelSelect.value || undefined });
291
+ }
292
+
293
+ // ── Durum ──
294
+ function renderModels(models, modelInfo) {
295
+ if (!models || !modelSelect) return;
296
+ modelSelect.innerHTML = "";
297
+ for (const m of models) {
298
+ const opt = document.createElement("option");
299
+ opt.value = m.model.id;
300
+ opt.textContent = m.model.name + (m.active || m.model.id === (modelInfo && modelInfo.modelId) ? " ★" : "");
301
+ if (m.active || m.model.id === (modelInfo && modelInfo.modelId)) opt.selected = true;
302
+ modelSelect.appendChild(opt);
303
+ }
304
+ if (models.length === 0) {
305
+ const opt = document.createElement("option");
306
+ opt.value = "";
307
+ opt.textContent = "Model yok";
308
+ modelSelect.appendChild(opt);
309
+ }
310
+ renderModelsList(models, modelInfo);
311
+ }
312
+
313
+ function renderModelsList(models, modelInfo) {
314
+ const list = $("#models-list");
315
+ if (!list) return;
316
+ if (!models || models.length === 0) {
317
+ list.innerHTML = '<div class="empty-hint">Kurulu/model bulunamadı. Listeyi yenilemeyi deneyin.</div>';
318
+ return;
319
+ }
320
+ list.innerHTML = "";
321
+ for (const m of models) {
322
+ const card = document.createElement("div");
323
+ card.className = "model-card" + (m.active ? " active" : "");
324
+ const statusTxt = m.active
325
+ ? "Aktif"
326
+ : m.installed
327
+ ? "Kurulu"
328
+ : "Kurulu değil";
329
+ const statusClass = m.active ? "active" : m.installed ? "installed" : "";
330
+ card.innerHTML =
331
+ '<div class="model-card-header"><div class="model-name">' +
332
+ escapeHTML(m.model.name) +
333
+ (m.active ? '<span class="act-icon">★</span>' : "") +
334
+ '</div><span class="model-status ' +
335
+ statusClass +
336
+ '">' +
337
+ statusTxt +
338
+ "</span></div>" +
339
+ '<div class="model-desc">' +
340
+ escapeHTML(m.model.description || "") +
341
+ "</div>" +
342
+ '<div class="model-actions">' +
343
+ (m.active
344
+ ? ""
345
+ : m.installed
346
+ ? '<button class="btn btn-sm" data-act="use" data-id="' + m.model.id + '">Kullan</button><button class="btn btn-sm btn-danger" data-act="remove" data-id="' + m.model.id + '">Kaldır</button>'
347
+ : '<button class="btn btn-sm btn-outline" data-act="install" data-id="' + m.model.id + '">Kur</button>') +
348
+ "</div>";
349
+ list.appendChild(card);
350
+ }
351
+ list.querySelectorAll("[data-act]").forEach((btn) => {
352
+ btn.addEventListener("click", () => {
353
+ const act = btn.dataset.act;
354
+ const id = btn.dataset.id;
355
+ btn.disabled = true;
356
+ btn.textContent = "İşleniyor…";
357
+ vscode.postMessage({ type: "model-" + act, id });
358
+ });
359
+ });
360
+ }
361
+
362
+ function renderSessions(sessions) {
363
+ const list = $("#sessions-list");
364
+ if (!list) return;
365
+ if (!sessions || sessions.length === 0) {
366
+ list.innerHTML = '<div class="empty-hint">Henüz kayıtlı oturum yok.</div>';
367
+ return;
368
+ }
369
+ list.innerHTML = "";
370
+ for (const s of sessions.slice(0, 30)) {
371
+ const item = document.createElement("div");
372
+ item.className = "session-item";
373
+ item.innerHTML =
374
+ '<span class="session-title">' + escapeHTML(s.title || "Yeni Sohbet") + '</span><span class="session-date">' + escapeHTML((s.updatedAt || "").slice(0, 10)) + "</span>";
375
+ item.addEventListener("click", () => vscode.postMessage({ type: "session-load", id: s.id }));
376
+ list.appendChild(item);
377
+ }
378
+ }
379
+
380
+ function renderState(state) {
381
+ const payload = state.payload || state;
382
+ if (payload.config) {
383
+ const cfg = payload.config;
384
+ const temp = cfg.session && typeof cfg.session.temperature === "number" ? cfg.session.temperature : "";
385
+ const maxSteps = cfg.maxSteps || "";
386
+ const tempEl = $("#cfg-temperature");
387
+ const stepsEl = $("#cfg-maxsteps");
388
+ if (tempEl && tempEl.value !== String(temp)) tempEl.value = temp;
389
+ if (stepsEl && stepsEl.value !== String(maxSteps)) stepsEl.value = maxSteps;
390
+ }
391
+ if (payload.models) renderModels(payload.models, payload.modelInfo);
392
+ if (payload.sessions) renderSessions(payload.sessions);
393
+ if (payload.modelInfo) {
394
+ const name = payload.modelInfo.name && payload.modelInfo.name !== "Bilinmeyen" ? payload.modelInfo.name : "Model seçili değil";
395
+ const kvModel = $("#kv-model");
396
+ if (kvModel) kvModel.textContent = name;
397
+ }
398
+ if (payload.cwd) {
399
+ const kvCwd = $("#kv-cwd");
400
+ if (kvCwd) kvCwd.textContent = payload.cwd;
401
+ }
402
+ if (payload.gpu && Array.isArray(payload.gpu)) {
403
+ const kvGpu = $("#kv-gpu");
404
+ if (kvGpu) kvGpu.textContent = payload.gpu.length > 0 ? payload.gpu.join(", ") : "algılanamadı";
405
+ }
406
+ if (payload.status) renderStatus(payload.status);
407
+ }
408
+
409
+ function renderStatus(status) {
410
+ if (status) {
411
+ const meta = [];
412
+ if (status.model) meta.push(status.model);
413
+ if (status.context) {
414
+ const pct = Math.min(100, Math.round((status.context.usedTokens / status.context.contextSize) * 100));
415
+ meta.push("bağlam %" + pct);
416
+ }
417
+ if (status.active) {
418
+ setStatus("busy", "Çalışıyor…", meta.join(" · "));
419
+ } else {
420
+ const cwdShort = status.cwd ? status.cwd.split(/[\\/]/).pop() : "";
421
+ setStatus("ok", "Hazır", meta.concat(cwdShort ? ["dizin: " + cwdShort] : []).join(" · "));
422
+ }
423
+ const kvContext = $("#kv-context");
424
+ if (kvContext && status.context && status.context.contextSize > 0) {
425
+ kvContext.textContent =
426
+ Math.min(100, Math.round((status.context.usedTokens / status.context.contextSize) * 100)) + "% (" + status.context.usedTokens + " token)";
427
+ }
428
+ }
429
+ }
430
+
431
+ // ── Mesaj yönlendirme ──
432
+ window.addEventListener("message", (event) => {
433
+ const msg = event.data;
434
+ if (!msg || typeof msg !== "object") return;
435
+
436
+ switch (msg.type) {
437
+ case "state":
438
+ renderState(msg);
439
+ break;
440
+ case "sessions":
441
+ renderSessions(msg.sessions);
442
+ break;
443
+ case "status":
444
+ renderStatus(msg);
445
+ break;
446
+ case "model-result":
447
+ showToast(msg.ok ? "Model işlemi tamamlandı" : "Hata: " + (msg.error || "bilinmeyen"), msg.ok ? "ok" : "err");
448
+ break;
449
+ case "model-refresh-result":
450
+ showToast(msg.ok ? "Model listesi güncellendi (" + (msg.count || 0) + " model)" : "Hata: " + (msg.error || ""), msg.ok ? "ok" : "err");
451
+ break;
452
+ case "session-loaded":
453
+ if (msg.ok && msg.data) {
454
+ currentSessionId = msg.data.id;
455
+ chatMessages = (msg.data.messages || []).slice();
456
+ chatLogs.innerHTML = "";
457
+ for (const m of chatMessages) {
458
+ switch (m.kind) {
459
+ case "user":
460
+ appendMessage("user", m.text || "");
461
+ break;
462
+ case "assistant":
463
+ appendMessage("ai", m.text || "");
464
+ break;
465
+ case "thought": {
466
+ const tEl = appendRaw(
467
+ "ai",
468
+ '<div class="think-block">' +
469
+ '<div class="think-header" role="button" tabindex="0">' +
470
+ '<span class="think-label">Düşünce</span>' +
471
+ '<span class="think-arrow" aria-hidden="true">▸</span>' +
472
+ "</div>" +
473
+ '<div class="think-body"><span>' + formatInline(m.text || "") + "</span></div>" +
474
+ "</div>",
475
+ "msg-think think-collapsed"
476
+ );
477
+ const hdr = tEl ? tEl.querySelector(".think-header") : null;
478
+ if (hdr) {
479
+ hdr.addEventListener("click", () => {
480
+ const collapsed = tEl.classList.toggle("think-collapsed");
481
+ const arrow = tEl.querySelector(".think-arrow");
482
+ if (arrow) arrow.textContent = collapsed ? "▸" : "▾";
483
+ });
484
+ }
485
+ break;
486
+ }
487
+ case "tool": {
488
+ const cls = m.state === "done" ? "ok" : m.state === "error" ? "err" : "";
489
+ const icon = m.state === "done" ? "✅" : m.state === "error" ? "❌" : "⚙️";
490
+ const out = m.output && m.output.length > 500 ? m.output.slice(0, 500) + "\n… (kesildi)" : m.output || "";
491
+ appendRaw("ai", '<div class="tool-status ' + cls + '">' + icon + " " + escapeHTML(m.name || "") + "</div>" + (out ? '<div class="tool-output">' + escapeHTML(out) + "</div>" : ""), "msg-tool");
492
+ break;
493
+ }
494
+ }
495
+ }
496
+ updateLogoVisibility();
497
+ } else {
498
+ showToast("Oturum yüklenemedi", "err");
499
+ }
500
+ break;
501
+ case "session-saved":
502
+ break;
503
+ case "new-chat-ok":
504
+ break;
505
+ case "busy":
506
+ setBusyUI(!!msg.active);
507
+ break;
508
+ case "found":
509
+ if (!msg.ok && msg.error) {
510
+ appendMessage("ai", "⚠️ " + msg.error);
511
+ chatMessages.push({ kind: "assistant", text: "⚠️ " + msg.error });
512
+ }
513
+ setActive(false);
514
+ setStatus("ok", "Hazır");
515
+ break;
516
+ case "agent:text-chunk":
517
+ if (currentThinkingEl) hideThinking();
518
+ appendToAssistant(msg.text);
519
+ break;
520
+ case "agent:thinking-chunk":
521
+ appendThinking(msg.text);
522
+ setStatus("busy", "düşünüyor…", statusMeta ? statusMeta.textContent : "");
523
+ break;
524
+ case "agent:tool-call":
525
+ hideThinking();
526
+ showToolCall(msg.name || "araç");
527
+ setStatus("busy", "araç çalışıyor: " + (msg.name || ""), statusMeta ? statusMeta.textContent : "");
528
+ break;
529
+ case "agent:tool-result":
530
+ showToolResult(msg.name || "", !!msg.ok, msg.output || "");
531
+ break;
532
+ case "agent:step-start": {
533
+ if ((msg.step || 1) > 1) showContinueRound();
534
+ break;
535
+ }
536
+ case "agent:load-progress":
537
+ loadBar.style.display = "flex";
538
+ loadFill.style.width = (msg.pct || 0) + "%";
539
+ loadText.textContent = "Model yükleniyor… %" + (msg.pct || 0);
540
+ setStatus("busy", "Model yükleniyor… %" + (msg.pct || 0));
541
+ break;
542
+ case "agent:load-complete":
543
+ loadBar.style.display = "none";
544
+ setStatus("ok", "Model hazır");
545
+ break;
546
+ case "agent:complete": {
547
+ finalizeAssistant();
548
+ hideThinking();
549
+ setBusyUI(false);
550
+ break;
551
+ }
552
+ case "agent:error":
553
+ loadBar.style.display = "none";
554
+ hideThinking();
555
+ finalizeAssistant();
556
+ setActive(false);
557
+ setStatus("err", "Hata");
558
+ showToast(msg.message || "Bilinmeyen hata", "err");
559
+ break;
560
+ case "command":
561
+ switch (msg.command) {
562
+ case "new-chat":
563
+ newChat();
564
+ break;
565
+ case "stop":
566
+ vscode.postMessage({ type: "abort" });
567
+ setActive(false);
568
+ setStatus("ok", "Durduruldu");
569
+ break;
570
+ case "refresh-models":
571
+ vscode.postMessage({ type: "get-state" });
572
+ break;
573
+ case "config-changed":
574
+ vscode.postMessage({ type: "get-state" });
575
+ break;
576
+ }
577
+ break;
578
+ case "playground-opened":
579
+ showToast("Test alanı hazır: " + (msg.path || ".ajan"));
580
+ break;
581
+ case "error":
582
+ setStatus("err", "Hata");
583
+ showToast(msg.message || "Bilinmeyen hata", "err");
584
+ break;
585
+ }
586
+ });
587
+
588
+ // ── Olay bağlama ──
589
+ chatForm.addEventListener("submit", (e) => {
590
+ e.preventDefault();
591
+ sendMessage();
592
+ });
593
+ stopBtn.addEventListener("click", () => vscode.postMessage({ type: "abort" }));
594
+ btnNewChat.addEventListener("click", newChat);
595
+ btnPlayground.addEventListener("click", () => vscode.postMessage({ type: "open-playground" }));
596
+
597
+ chatLogs.addEventListener("scroll", () => {
598
+ stickToBottom = isNearBottom();
599
+ });
600
+
601
+ btnToggleSS.addEventListener("click", () => {
602
+ const showSettings = settingsPanel.style.display !== "none";
603
+ settingsPanel.style.display = showSettings ? "none" : "flex";
604
+ chatPanel.style.display = showSettings ? "flex" : "none";
605
+ if (!showSettings) {
606
+ vscode.postMessage({ type: "get-state" });
607
+ }
608
+ });
609
+
610
+ btnRefreshModels.addEventListener("click", () => vscode.postMessage({ type: "model-refresh" }));
611
+
612
+ [$("#cfg-temperature"), $("#cfg-maxsteps")].forEach((el) => {
613
+ if (!el) return;
614
+ el.addEventListener("change", () => {
615
+ const patch = {};
616
+ if (el === $("#cfg-temperature")) patch.session = { temperature: parseFloat(el.value) };
617
+ if (el === $("#cfg-maxsteps")) patch.maxSteps = parseInt(el.value, 10);
618
+ vscode.postMessage({ type: "set-config", patch });
619
+ });
620
+ });
621
+
622
+ chatInput.addEventListener("keydown", (e) => {
623
+ if (e.key === "Enter" && !e.shiftKey) {
624
+ e.preventDefault();
625
+ sendMessage();
626
+ }
627
+ });
628
+
629
+ // ── Başlangıç ──
630
+ // "ready" mesajı panel tarafında tek bir get-state isteğine dönüşür
631
+ // (models, sessions, status, context hepsi tek state mesajında gelir)
632
+ vscode.postMessage({ type: "ready" });
633
+ chatInput.focus();
634
+ })();