beast-agent 2.6.1 → 2.6.3
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/package.json +1 -1
- package/src/agent/engine.js +6 -1
- package/src/agent/gittools.js +276 -0
- package/src/agent/perception.js +4 -0
- package/src/agent/repomap.js +265 -0
- package/src/agent/tools.js +16 -0
- package/src/agent/xlsx.js +474 -0
- package/src/agent/xlsxtools.js +235 -0
- package/src/main.js +34 -7
- package/src/renderer/index.html +1 -1
- package/src/renderer/renderer.js +10 -3
- package/src/renderer/style.css +8 -9
|
@@ -0,0 +1,235 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
/* Excel araç katmanı: xlsx_read / xlsx_write / xlsx_edit.
|
|
4
|
+
Motor: src/agent/xlsx.js (sıfır bağımlılık — zip + minimal OOXML).
|
|
5
|
+
edit akışı tüm çalışma kitabını okuyup değiştirerek yeniden YAZAR;
|
|
6
|
+
formüller önbellek değerlerine dönüşür (araç açıklamasında belirtilir). */
|
|
7
|
+
|
|
8
|
+
const fs = require('fs');
|
|
9
|
+
const path = require('path');
|
|
10
|
+
const engine = require('./xlsx');
|
|
11
|
+
|
|
12
|
+
const MAX_OUT_ROWS = 500;
|
|
13
|
+
const MAX_OUT_CHARS = 120000;
|
|
14
|
+
|
|
15
|
+
function asRows(v) {
|
|
16
|
+
if (!Array.isArray(v)) return null;
|
|
17
|
+
return v;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/* ---------- xlsx_read ---------- */
|
|
21
|
+
async function xlsxRead(args, ctx) {
|
|
22
|
+
const p = path.resolve(String((ctx && ctx.cwd) || '.'), String(args.path || ''));
|
|
23
|
+
if (!fs.existsSync(p)) return { ok: false, error: 'dosya bulunamadı: ' + p };
|
|
24
|
+
if (!/\.xlsx$/i.test(p)) return { ok: false, error: 'yalnızca .xlsx okunur — .xls (eski biçim) değil' };
|
|
25
|
+
let book;
|
|
26
|
+
try {
|
|
27
|
+
book = engine.read(p);
|
|
28
|
+
} catch (e) {
|
|
29
|
+
return { ok: false, error: String((e && e.message) || e) };
|
|
30
|
+
}
|
|
31
|
+
const sheetArg = args.sheet == null ? null : String(args.sheet);
|
|
32
|
+
let sheet = sheetArg == null ? book[0] : book.find((s) => s.name.toLowerCase() === sheetArg.toLowerCase());
|
|
33
|
+
if (!sheet && sheetArg != null && /^\d+$/.test(sheetArg)) sheet = book[Number(sheetArg) - 1];
|
|
34
|
+
if (!sheet) return { ok: false, error: 'sayfa yok: ' + sheetArg, sheets: book.map((s) => s.name) };
|
|
35
|
+
|
|
36
|
+
let rows = sheet.rows;
|
|
37
|
+
const total = rows.length;
|
|
38
|
+
const offset = Math.max(1, Math.floor(Number(args.offset) || 1));
|
|
39
|
+
|
|
40
|
+
/* header_row: true → 1. satır anahtar; satırlar objeye çevrilir.
|
|
41
|
+
offset sayfa satırına karşılık gelir (1 = başlık satırı dahil başlangıç). */
|
|
42
|
+
if (args.header_row !== false && total > 0) {
|
|
43
|
+
const headRaw = sheet.rows[0] || [];
|
|
44
|
+
const head = headRaw.map((h, i) => (String(h == null ? '' : h).trim() || 'kolon' + (i + 1)));
|
|
45
|
+
const start = Math.max(2, offset); /* veri 2. satırdan başlar */
|
|
46
|
+
const body = sheet.rows.slice(start - 1, start - 1 + Math.min(MAX_OUT_ROWS, Math.max(1, Math.floor(Number(args.limit) || MAX_OUT_ROWS))));
|
|
47
|
+
const outRows = body.map((r) => {
|
|
48
|
+
const o = {};
|
|
49
|
+
head.forEach((h, i) => {
|
|
50
|
+
o[h] = r[i] === undefined ? '' : r[i];
|
|
51
|
+
});
|
|
52
|
+
return o;
|
|
53
|
+
});
|
|
54
|
+
const endRow = start - 1 + body.length;
|
|
55
|
+
return {
|
|
56
|
+
ok: true,
|
|
57
|
+
sheet: sheet.name,
|
|
58
|
+
totalRows: total,
|
|
59
|
+
offset: start,
|
|
60
|
+
headers: head,
|
|
61
|
+
rows: outRows,
|
|
62
|
+
...(endRow < total ? { note: `satır ${endRow + 1}-${total} için offset=${endRow + 1} ile devam et` } : {}),
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
const limit = Math.min(MAX_OUT_ROWS, Math.max(1, Math.floor(Number(args.limit) || MAX_OUT_ROWS)));
|
|
67
|
+
rows = rows.slice(offset - 1, offset - 1 + limit);
|
|
68
|
+
const text = JSON.stringify(rows);
|
|
69
|
+
return {
|
|
70
|
+
ok: true,
|
|
71
|
+
sheet: sheet.name,
|
|
72
|
+
totalRows: total,
|
|
73
|
+
offset,
|
|
74
|
+
rows,
|
|
75
|
+
...(total > offset - 1 + rows.length ? { note: `satır ${offset + rows.length}+ için offset ile devam et` } : {}),
|
|
76
|
+
...(text.length > MAX_OUT_CHARS ? { warning: 'çıktı büyük — limit/offset ile parçala' } : {}),
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/* ---------- xlsx_write ---------- */
|
|
81
|
+
async function xlsxWrite(args, ctx) {
|
|
82
|
+
const p = path.resolve(String((ctx && ctx.cwd) || '.'), String(args.path || ''));
|
|
83
|
+
if (!/\.xlsx$/i.test(p)) return { ok: false, error: 'dosya adı .xlsx ile bitmeli' };
|
|
84
|
+
const sheets = Array.isArray(args.sheets) ? args.sheets : null;
|
|
85
|
+
if (!sheets || !sheets.length) return { ok: false, error: 'sheets gerekli: [{ name, rows }] — rows dizi-dizisi ya da obje-dizisi olabilir' };
|
|
86
|
+
let buf;
|
|
87
|
+
try {
|
|
88
|
+
buf = engine.write(sheets);
|
|
89
|
+
} catch (e) {
|
|
90
|
+
return { ok: false, error: 'xlsx üretilemedi: ' + String((e && e.message) || e) };
|
|
91
|
+
}
|
|
92
|
+
fs.mkdirSync(path.dirname(p), { recursive: true });
|
|
93
|
+
if (fs.existsSync(p) && args.overwrite === false) return { ok: false, error: 'dosya zaten var ve overwrite:false' };
|
|
94
|
+
fs.writeFileSync(p, buf);
|
|
95
|
+
return {
|
|
96
|
+
ok: true,
|
|
97
|
+
path: p,
|
|
98
|
+
bytes: buf.length,
|
|
99
|
+
sheets: sheets.map((s, i) => ({ name: (s && s.name) || 'Sheet' + (i + 1), rows: Array.isArray(s && s.rows) ? s.rows.length : 0 })),
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/* ---------- xlsx_edit ---------- */
|
|
104
|
+
async function xlsxEdit(args, ctx) {
|
|
105
|
+
const p = path.resolve(String((ctx && ctx.cwd) || '.'), String(args.path || ''));
|
|
106
|
+
if (!fs.existsSync(p)) return { ok: false, error: 'dosya bulunamadı: ' + p };
|
|
107
|
+
if (!/\.xlsx$/i.test(p)) return { ok: false, error: 'yalnızca .xlsx düzenlenir' };
|
|
108
|
+
const hasUpdates = Array.isArray(args.updates) && args.updates.length > 0;
|
|
109
|
+
const hasAppend = Array.isArray(args.append_rows) && args.append_rows.length > 0;
|
|
110
|
+
if (!hasUpdates && !hasAppend) return { ok: false, error: 'updates ([{cell, value}]) ya da append_rows ([[...],...]) gerekli' };
|
|
111
|
+
|
|
112
|
+
let book;
|
|
113
|
+
try {
|
|
114
|
+
book = engine.read(p);
|
|
115
|
+
} catch (e) {
|
|
116
|
+
return { ok: false, error: String((e && e.message) || e) };
|
|
117
|
+
}
|
|
118
|
+
const sheetArg = args.sheet == null ? null : String(args.sheet);
|
|
119
|
+
let sheet = sheetArg == null ? book[0] : book.find((s) => s.name.toLowerCase() === sheetArg.toLowerCase());
|
|
120
|
+
if (!sheet && sheetArg != null && /^\d+$/.test(sheetArg)) sheet = book[Number(sheetArg) - 1];
|
|
121
|
+
if (!sheet) return { ok: false, error: 'sayfa yok: ' + sheetArg, sheets: book.map((s) => s.name) };
|
|
122
|
+
|
|
123
|
+
const rows = sheet.rows;
|
|
124
|
+
let changed = 0;
|
|
125
|
+
|
|
126
|
+
if (hasUpdates) {
|
|
127
|
+
for (const u of args.updates.slice(0, 2000)) {
|
|
128
|
+
let r = null;
|
|
129
|
+
if (u && typeof u.cell === 'string') r = engine.refToCell(u.cell);
|
|
130
|
+
if (!r && u && Number.isFinite(u.row) && Number.isFinite(u.col)) r = { row: Math.floor(u.row), col: Math.floor(u.col) };
|
|
131
|
+
if (!r || r.row < 1 || r.col < 1) return { ok: false, error: 'geçersiz hücre: ' + JSON.stringify(u).slice(0, 60) };
|
|
132
|
+
while (rows.length < r.row) rows.push([]);
|
|
133
|
+
const row = rows[r.row - 1];
|
|
134
|
+
while (row.length < r.col) row.push('');
|
|
135
|
+
row[r.col - 1] = u.value === undefined ? '' : u.value;
|
|
136
|
+
changed++;
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
if (hasAppend) {
|
|
140
|
+
const head = (rows[0] || []).map((h) => String(h == null ? '' : h).trim());
|
|
141
|
+
for (const r of args.append_rows.slice(0, 2000)) {
|
|
142
|
+
if (r && typeof r === 'object' && !Array.isArray(r) && !(r instanceof Date)) {
|
|
143
|
+
/* obje satırı: ilk satırdaki başlıklara göre sütunlanır */
|
|
144
|
+
rows.push(head.map((h) => (h && r[h] !== undefined ? r[h] : '')));
|
|
145
|
+
} else {
|
|
146
|
+
rows.push(Array.isArray(r) ? r : [r]);
|
|
147
|
+
}
|
|
148
|
+
changed++;
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
const buf = engine.write(book.map((s) => ({ name: s.name, rows: s.rows })));
|
|
153
|
+
fs.writeFileSync(p, buf);
|
|
154
|
+
return { ok: true, path: p, sheet: sheet.name, changed, totalRows: rows.length };
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
const definitions = [
|
|
158
|
+
{
|
|
159
|
+
type: 'function',
|
|
160
|
+
function: {
|
|
161
|
+
name: 'xlsx_read',
|
|
162
|
+
description:
|
|
163
|
+
'Read an .xlsx workbook: returns sheet rows as JSON. Default: first sheet, first row treated as headers (rows become objects). Use `sheet` (name or 1-based index) for other sheets, `header_row: false` for raw arrays, `offset`/`limit` to paginate big sheets. Dates come back as ISO strings.',
|
|
164
|
+
parameters: {
|
|
165
|
+
type: 'object',
|
|
166
|
+
properties: {
|
|
167
|
+
path: { type: 'string', description: 'Path to the .xlsx file' },
|
|
168
|
+
sheet: { type: 'string', description: 'Sheet name or 1-based index (default: first sheet)' },
|
|
169
|
+
header_row: { type: 'boolean', description: 'Treat first row as headers (default true)' },
|
|
170
|
+
offset: { type: 'number', description: '1-based start row (default 1)' },
|
|
171
|
+
limit: { type: 'number', description: 'Max rows returned (default 500)' },
|
|
172
|
+
},
|
|
173
|
+
required: ['path'],
|
|
174
|
+
},
|
|
175
|
+
},
|
|
176
|
+
},
|
|
177
|
+
{
|
|
178
|
+
type: 'function',
|
|
179
|
+
function: {
|
|
180
|
+
name: 'xlsx_write',
|
|
181
|
+
description:
|
|
182
|
+
'Create or overwrite an .xlsx file. sheets: [{ name, rows }] where rows is an array of arrays (mixed primitives; Date → date cell) OR an array of objects (keys become the header row). Returns file path and size.',
|
|
183
|
+
parameters: {
|
|
184
|
+
type: 'object',
|
|
185
|
+
properties: {
|
|
186
|
+
path: { type: 'string', description: 'Target .xlsx path' },
|
|
187
|
+
sheets: {
|
|
188
|
+
type: 'array',
|
|
189
|
+
description: 'Sheets to write',
|
|
190
|
+
items: {
|
|
191
|
+
type: 'object',
|
|
192
|
+
properties: {
|
|
193
|
+
name: { type: 'string' },
|
|
194
|
+
rows: { type: 'array', description: 'Array of arrays or array of objects' },
|
|
195
|
+
},
|
|
196
|
+
required: ['rows'],
|
|
197
|
+
},
|
|
198
|
+
},
|
|
199
|
+
},
|
|
200
|
+
required: ['path', 'sheets'],
|
|
201
|
+
},
|
|
202
|
+
},
|
|
203
|
+
},
|
|
204
|
+
{
|
|
205
|
+
type: 'function',
|
|
206
|
+
function: {
|
|
207
|
+
name: 'xlsx_edit',
|
|
208
|
+
description:
|
|
209
|
+
'Edit an existing .xlsx in place: update cells (updates: [{cell: "B2", value}]) and/or append rows (append_rows: [[...], ...]) to a sheet, rewriting the file with all sheets intact. NOTE: formulas are replaced by their cached values (recalculate by opening in Excel).',
|
|
210
|
+
parameters: {
|
|
211
|
+
type: 'object',
|
|
212
|
+
properties: {
|
|
213
|
+
path: { type: 'string', description: 'Path to the .xlsx file' },
|
|
214
|
+
sheet: { type: 'string', description: 'Sheet name or 1-based index (default: first sheet)' },
|
|
215
|
+
updates: {
|
|
216
|
+
type: 'array',
|
|
217
|
+
description: 'Cell updates',
|
|
218
|
+
items: {
|
|
219
|
+
type: 'object',
|
|
220
|
+
properties: {
|
|
221
|
+
cell: { type: 'string', description: 'Cell ref like "B2"' },
|
|
222
|
+
value: { description: 'New value (string/number/boolean)' },
|
|
223
|
+
},
|
|
224
|
+
required: ['cell'],
|
|
225
|
+
},
|
|
226
|
+
},
|
|
227
|
+
append_rows: { type: 'array', description: 'Rows to append at the end' },
|
|
228
|
+
},
|
|
229
|
+
required: ['path'],
|
|
230
|
+
},
|
|
231
|
+
},
|
|
232
|
+
},
|
|
233
|
+
];
|
|
234
|
+
|
|
235
|
+
module.exports = { definitions, handlers: { xlsx_read: xlsxRead, xlsx_write: xlsxWrite, xlsx_edit: xlsxEdit } };
|
package/src/main.js
CHANGED
|
@@ -2053,7 +2053,8 @@ function botToolSet(cfg) {
|
|
|
2053
2053
|
}
|
|
2054
2054
|
if (s.email) { set.add('email_list'); set.add('email_read'); set.add('email_send'); }
|
|
2055
2055
|
if (s.run_command) {
|
|
2056
|
-
for (const t of ['run_command', 'python_run', 'read_file', 'write_file', 'list_dir', 'computer_look', 'computer_act'
|
|
2056
|
+
for (const t of ['run_command', 'python_run', 'read_file', 'write_file', 'list_dir', 'computer_look', 'computer_act',
|
|
2057
|
+
'git_commit', 'git_diff_review', 'git_pr_create', 'repo_map', 'repo_symbols', 'xlsx_read', 'xlsx_write', 'xlsx_edit']) set.add(t);
|
|
2057
2058
|
}
|
|
2058
2059
|
if (s.memory) { set.add('memory_write'); set.add('user_write'); set.add('memory_search'); set.add('memory_hygiene'); }
|
|
2059
2060
|
if (s.kb) { set.add('kb_search'); set.add('kb_add'); }
|
|
@@ -6381,9 +6382,9 @@ function empatiLlmCompose(prompt) {
|
|
|
6381
6382
|
KENDİSİNİN attığını bilir — aynı oturum, kesintisiz bağlam. */
|
|
6382
6383
|
const PROACTIVE_MARK = '🫡 *Beast proaktif:*';
|
|
6383
6384
|
|
|
6384
|
-
/* bildirimin ALTINA YAZILAN KAYNAK
|
|
6385
|
-
|
|
6386
|
-
|
|
6385
|
+
/* bildirimin ALTINA YAZILAN KAYNAK — desktop chat + Discord için MARKDOWN
|
|
6386
|
+
başlık-linki: kullanıcı ham URL görmez, haber başlığına tıklayınca açılır.
|
|
6387
|
+
URL yoksa kaynak adı düz yazılır. TEK SATIR kuralı korunur. */
|
|
6387
6388
|
function empatiSourceLine(ev) {
|
|
6388
6389
|
if (!ev) return '';
|
|
6389
6390
|
const oneLine = (s) =>
|
|
@@ -6392,7 +6393,29 @@ function empatiSourceLine(ev) {
|
|
|
6392
6393
|
const cap = (s, max) =>
|
|
6393
6394
|
oneLine(s).length > max ? oneLine(s).slice(0, max - ELLIPSIS.length) + ELLIPSIS : oneLine(s);
|
|
6394
6395
|
const url = oneLine(ev.url);
|
|
6395
|
-
if (/^https?:\/\//i.test(url))
|
|
6396
|
+
if (/^https?:\/\//i.test(url)) {
|
|
6397
|
+
/* markdown linki bozmasın: başlıktaki köşeli parantezler silinir, URL'deki
|
|
6398
|
+
')' kaçırılır (mdInline linki ilk ')'da keser) */
|
|
6399
|
+
const title =
|
|
6400
|
+
oneLine(ev.title || ev.source || '').replace(/[[\]]/g, ' ').replace(/\s{2,}/g, ' ').trim() || 'kaynak';
|
|
6401
|
+
return '🔗 [' + cap(title, 80) + '](' + url.replace(/\)/g, '%29') + ')';
|
|
6402
|
+
}
|
|
6403
|
+
const src = oneLine(ev.source);
|
|
6404
|
+
return src ? '🔗 kaynak: ' + cap(src, 80) : '';
|
|
6405
|
+
}
|
|
6406
|
+
|
|
6407
|
+
/* WhatsApp/Telegram düz metin sürümü: bu kanallar [başlık](url) render etmez —
|
|
6408
|
+
link TIKLANABİLMEK İÇİN ham URL olmalı. Kısaltılan URL kırık link olur;
|
|
6409
|
+
o yüzden burada link tam uzunlukta tek satır gider. */
|
|
6410
|
+
function empatiSourceLinePlain(ev) {
|
|
6411
|
+
if (!ev) return '';
|
|
6412
|
+
const oneLine = (s) =>
|
|
6413
|
+
String(s || '').replace(/\s*\n+\s*/g, ' ').replace(/\s{2,}/g, ' ').trim();
|
|
6414
|
+
const url = oneLine(ev.url);
|
|
6415
|
+
if (/^https?:\/\//i.test(url)) return '🔗 ' + url;
|
|
6416
|
+
const ELLIPSIS = '...';
|
|
6417
|
+
const cap = (s, max) =>
|
|
6418
|
+
oneLine(s).length > max ? oneLine(s).slice(0, max - ELLIPSIS.length) + ELLIPSIS : oneLine(s);
|
|
6396
6419
|
const src = oneLine(ev.source);
|
|
6397
6420
|
return src ? '🔗 kaynak: ' + cap(src, 80) : '';
|
|
6398
6421
|
}
|
|
@@ -6502,8 +6525,12 @@ function empatiDesktopSid() {
|
|
|
6502
6525
|
Hiçbir entegrasyon yazılamazsa masaüstü chat UI (toast) kalır. */
|
|
6503
6526
|
function empatiNotify(text, ev) {
|
|
6504
6527
|
const cfg = empatiCfg();
|
|
6528
|
+
/* desktop + Discord: başlık-linki (markdown); WA/TG: ham URL (tıklanabilir
|
|
6529
|
+
olması için şart) — kanallar kendi biçimini alır */
|
|
6505
6530
|
const src = empatiSourceLine(ev);
|
|
6531
|
+
const srcPlain = empatiSourceLinePlain(ev);
|
|
6506
6532
|
const out = PROACTIVE_MARK + '\n' + text + (src ? '\n' + src : '');
|
|
6533
|
+
const outPlain = PROACTIVE_MARK + '\n' + text + (srcPlain ? '\n' + srcPlain : '');
|
|
6507
6534
|
const inject = empatiInjectText(ev, out);
|
|
6508
6535
|
const senders = [];
|
|
6509
6536
|
const tryWa = () => {
|
|
@@ -6512,7 +6539,7 @@ function empatiNotify(text, ev) {
|
|
|
6512
6539
|
if (own && wa && wa.connected) {
|
|
6513
6540
|
const jid = own + '@s.whatsapp.net';
|
|
6514
6541
|
senders.push(() =>
|
|
6515
|
-
Promise.resolve(sendWaSafe(jid,
|
|
6542
|
+
Promise.resolve(sendWaSafe(jid, outPlain))
|
|
6516
6543
|
.then(() => empatiInjectToSession(ensureWaSession(jid), inject))
|
|
6517
6544
|
.catch(() => {})
|
|
6518
6545
|
);
|
|
@@ -6524,7 +6551,7 @@ function empatiNotify(text, ev) {
|
|
|
6524
6551
|
if (tg && tg.connected) {
|
|
6525
6552
|
for (const id of tgOwnerIds()) {
|
|
6526
6553
|
senders.push(() =>
|
|
6527
|
-
Promise.resolve(sendTgSafe(id,
|
|
6554
|
+
Promise.resolve(sendTgSafe(id, outPlain))
|
|
6528
6555
|
.then(() => empatiInjectToSession(ensureTgSession(String(id)), inject))
|
|
6529
6556
|
.catch(() => {})
|
|
6530
6557
|
);
|
package/src/renderer/index.html
CHANGED
|
@@ -50,7 +50,6 @@
|
|
|
50
50
|
<button id="storeBtn" title="Skills Store" data-i18n-title="tipStore"><svg viewBox="0 0 24 24" width="15" height="15" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M4 7h16l-1.3 12.1a2 2 0 0 1-2 1.9H7.3a2 2 0 0 1-2-1.9L4 7z"/><path d="M8 10V6a4 4 0 0 1 8 0v4"/></svg></button>
|
|
51
51
|
<button id="gitBtn" title="GitHub Trending" data-i18n-title="tipGithub"><svg viewBox="0 0 24 24" width="15" height="15" fill="currentColor" aria-hidden="true"><path d="M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12"/></svg></button>
|
|
52
52
|
<button id="ideBtn" title="IDE Modu" data-i18n-title="tipIde"><svg viewBox="0 0 24 24" width="15" height="15" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M8 6l-5 6 5 6"/><path d="M16 6l5 6-5 6"/><path d="M13.5 4l-3 16"/></svg></button>
|
|
53
|
-
<button id="studioBtn" title="Beast Studio — video yapma/düzenleme" data-i18n-title="tipStudio"><svg viewBox="0 0 24 24" width="15" height="15" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="2" y="6" width="13" height="12" rx="2"/><path d="M15 10l7-4v12l-7-4"/></svg></button>
|
|
54
53
|
<span id="netDot" class="net-on" title="İnternet: bağlı" data-i18n-title="tipNet"><svg viewBox="0 0 24 24" width="15" height="15" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M2 8.82a15 15 0 0 1 20 0"/><path d="M5 12.85a10 10 0 0 1 14 0"/><path d="M8.53 16.11a6 6 0 0 1 6.95 0"/><line x1="12" y1="20" x2="12.01" y2="20"/><line class="net-slash" x1="4" y1="4" x2="20" y2="20"/></svg></span>
|
|
55
54
|
</div>
|
|
56
55
|
</aside>
|
|
@@ -82,6 +81,7 @@
|
|
|
82
81
|
<div id="cfgList" class="dd-list"></div>
|
|
83
82
|
</div>
|
|
84
83
|
</div>
|
|
84
|
+
<button id="studioBtn" class="dd-btn dd-icon-btn" title="Beast Studio — video yapma/düzenleme" data-i18n-title="tipStudio"><svg viewBox="0 0 24 24" width="15" height="15" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="2" y="6" width="13" height="12" rx="2"/><path d="M15 10l7-4v12l-7-4"/></svg></button>
|
|
85
85
|
<button id="railBtn" class="dd-btn dd-icon-btn" title="Paralel Ajan Konsolu" data-i18n-title="tipRail">▤</button>
|
|
86
86
|
<button id="watchBtn" class="dd-btn dd-icon-btn" title="İzleyiciler (Watchers)" data-i18n-title="tipWatch">◎</button>
|
|
87
87
|
<button id="cronBtn" class="dd-btn dd-icon-btn" title="Cron Görevler" data-i18n-title="tipCron">⏱︎</button>
|
package/src/renderer/renderer.js
CHANGED
|
@@ -667,6 +667,12 @@ function argSummary(name, args) {
|
|
|
667
667
|
if (name === 'glob') return String(args.pattern || '');
|
|
668
668
|
if (name === 'list_dir') return String(args.path || '.');
|
|
669
669
|
if (name === 'memory_write' || name === 'user_write') return String(args.text || '').slice(0, 80);
|
|
670
|
+
if (name === 'git_commit') return String(args.message || '').slice(0, 100);
|
|
671
|
+
if (name === 'git_diff_review') return args.staged ? '--staged' : String(args.ref || 'working tree');
|
|
672
|
+
if (name === 'git_pr_create') return String(args.title || '').slice(0, 100);
|
|
673
|
+
if (name === 'repo_map') return String(args.path || '.');
|
|
674
|
+
if (name === 'repo_symbols') return String(args.query || '').slice(0, 60) || '.';
|
|
675
|
+
if (name === 'xlsx_read' || name === 'xlsx_write' || name === 'xlsx_edit') return String(args.path || '');
|
|
670
676
|
return JSON.stringify(args).slice(0, 100);
|
|
671
677
|
} catch {
|
|
672
678
|
return '';
|
|
@@ -4893,9 +4899,10 @@ function onEvent(ev) {
|
|
|
4893
4899
|
return;
|
|
4894
4900
|
}
|
|
4895
4901
|
if (ev.type === 'install-progress') { updateInstallPct(ev); return; }
|
|
4896
|
-
/* EMPATİ LOOP: proaktif bildirim (masaüstü) + sekme canlı yenileme
|
|
4902
|
+
/* EMPATİ LOOP: proaktif bildirim (masaüstü) + sekme canlı yenileme.
|
|
4903
|
+
Toast'ta yalnız haber başlığı — link/markdown kalabalığı chat mesajında. */
|
|
4897
4904
|
if (ev.type === 'proactive') {
|
|
4898
|
-
toast('🫡 ' + (ev.
|
|
4905
|
+
toast('🫡 ' + (ev.title || ev.text || ''));
|
|
4899
4906
|
return;
|
|
4900
4907
|
}
|
|
4901
4908
|
if (ev.type === 'empati') {
|
|
@@ -5445,7 +5452,7 @@ function applyState() {
|
|
|
5445
5452
|
els.thinkBtnLabel.innerHTML =
|
|
5446
5453
|
'<svg viewBox="0 0 24 24" width="15" height="15" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M9.5 2A2.5 2.5 0 0 0 7 4.5v.55A3.5 3.5 0 0 0 4.5 8.5c0 .74.23 1.43.62 2A3.5 3.5 0 0 0 4 13.5 3.5 3.5 0 0 0 7 16.95v.55A2.5 2.5 0 0 0 9.5 20a2.5 2.5 0 0 0 2.5-2.5v-13A2.5 2.5 0 0 0 9.5 2z"/><path d="M14.5 2A2.5 2.5 0 0 1 17 4.5v.55a3.5 3.5 0 0 1 2.5 3.45c0 .74-.23 1.43-.62 2a3.5 3.5 0 0 1 1.12 3 3.5 3.5 0 0 1-3 3.45v.55A2.5 2.5 0 0 1 14.5 20 2.5 2.5 0 0 1 12 17.5v-13A2.5 2.5 0 0 1 14.5 2z"/></svg>';
|
|
5447
5454
|
renderModelMenu();
|
|
5448
|
-
}
|
|
5455
|
+
}
|
|
5449
5456
|
|
|
5450
5457
|
/* düşünme (reasoning) seviyesi picker — gerçek API değerleri */
|
|
5451
5458
|
const THINK_UI_LEVELS = [
|
package/src/renderer/style.css
CHANGED
|
@@ -185,8 +185,7 @@ body {
|
|
|
185
185
|
#langBtn,
|
|
186
186
|
#storeBtn,
|
|
187
187
|
#gitBtn,
|
|
188
|
-
#ideBtn
|
|
189
|
-
#studioBtn {
|
|
188
|
+
#ideBtn {
|
|
190
189
|
background: none;
|
|
191
190
|
border: none;
|
|
192
191
|
color: var(--muted);
|
|
@@ -204,18 +203,18 @@ body {
|
|
|
204
203
|
#langBtn:hover,
|
|
205
204
|
#storeBtn:hover,
|
|
206
205
|
#gitBtn:hover,
|
|
207
|
-
#ideBtn:hover
|
|
208
|
-
#studioBtn:hover { background: var(--panel2); color: var(--text); }
|
|
206
|
+
#ideBtn:hover { background: var(--panel2); color: var(--text); }
|
|
209
207
|
#gearBtn:focus,
|
|
210
208
|
#themeBtn:focus,
|
|
211
209
|
#langBtn:focus,
|
|
212
210
|
#storeBtn:focus,
|
|
213
211
|
#gitBtn:focus,
|
|
214
|
-
#ideBtn:focus
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
212
|
+
#ideBtn:focus { outline: none; }
|
|
213
|
+
/* aktif mod rozeti: IDE tuşu basılıyken vurgulanır */
|
|
214
|
+
#ideBtn.on { color: var(--accent); background: var(--panel2); }
|
|
215
|
+
|
|
216
|
+
/* Studio tuşu artık topbar'da (dd-btn dd-icon-btn) — aktif rozet diğer topbar ikonlarıyla aynı */
|
|
217
|
+
#studioBtn.on { background: var(--accent-dim); color: var(--accent); }
|
|
219
218
|
|
|
220
219
|
/* model refresh butonu — çekerken döner */
|
|
221
220
|
#modelRefreshBtn.spin { opacity: .7; pointer-events: none; }
|