clay-server 3.3.0-beta.1 → 3.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.
- package/lib/git-cli.js +370 -0
- package/lib/git-session-attribution.js +219 -0
- package/lib/project-connection.js +1 -15
- package/lib/project-email.js +0 -61
- package/lib/project-http.js +104 -1
- package/lib/project-sessions.js +1 -11
- package/lib/project-user-message.js +2 -0
- package/lib/project.js +18 -5
- package/lib/public/app.js +14 -2
- package/lib/public/css/filebrowser.css +320 -0
- package/lib/public/css/git-panel.css +424 -0
- package/lib/public/css/input.css +0 -3
- package/lib/public/index.html +12 -15
- package/lib/public/modules/app-messages.js +1 -5
- package/lib/public/modules/context-sources.js +0 -90
- package/lib/public/modules/filebrowser.js +135 -21
- package/lib/public/modules/git-panel.js +456 -0
- package/lib/public/modules/input.js +8 -0
- package/lib/public/modules/markdown-slides.js +292 -0
- package/lib/public/modules/mate-sidebar.js +0 -7
- package/lib/public/modules/sidebar.js +42 -0
- package/lib/public/modules/tool-palette.js +1 -2
- package/lib/public/style.css +1 -0
- package/lib/sdk-bridge.js +46 -5
- package/lib/sdk-message-processor.js +26 -2
- package/lib/sessions.js +1 -1
- package/lib/yoke/adapters/claude.js +43 -17
- package/lib/yoke/index.js +19 -0
- package/package.json +1 -1
package/lib/project-email.js
CHANGED
|
@@ -9,31 +9,6 @@ var smtp = require("./smtp");
|
|
|
9
9
|
var { CONFIG_DIR } = require("./config");
|
|
10
10
|
|
|
11
11
|
var AUDIT_LOG_PATH = path.join(CONFIG_DIR, "email-audit.jsonl");
|
|
12
|
-
var EMAIL_DEFAULTS_DIR = path.join(CONFIG_DIR, "email-defaults");
|
|
13
|
-
|
|
14
|
-
// --- Project-level email defaults ---
|
|
15
|
-
// Stores which email accounts should be auto-enabled for every new session.
|
|
16
|
-
|
|
17
|
-
function loadEmailDefaults(slug) {
|
|
18
|
-
try {
|
|
19
|
-
var filePath = path.join(EMAIL_DEFAULTS_DIR, slug + ".json");
|
|
20
|
-
var data = JSON.parse(fs.readFileSync(filePath, "utf8"));
|
|
21
|
-
return data.accounts || [];
|
|
22
|
-
} catch (e) {
|
|
23
|
-
return [];
|
|
24
|
-
}
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
function saveEmailDefaults(slug, accountIds) {
|
|
28
|
-
try {
|
|
29
|
-
fs.mkdirSync(EMAIL_DEFAULTS_DIR, { recursive: true });
|
|
30
|
-
var filePath = path.join(EMAIL_DEFAULTS_DIR, slug + ".json");
|
|
31
|
-
fs.writeFileSync(filePath, JSON.stringify({ accounts: accountIds }), "utf8");
|
|
32
|
-
} catch (e) {
|
|
33
|
-
console.error("[email] Failed to save defaults:", e.message);
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
|
-
|
|
37
12
|
// --- Audit log (Server SMTP only) ---
|
|
38
13
|
|
|
39
14
|
function appendAuditLog(entry) {
|
|
@@ -185,7 +160,6 @@ function formatTimeAgo(date) {
|
|
|
185
160
|
function attachEmail(ctx) {
|
|
186
161
|
var slug = ctx.slug;
|
|
187
162
|
var send = ctx.send;
|
|
188
|
-
var sendTo = ctx.sendTo;
|
|
189
163
|
var clients = ctx.clients;
|
|
190
164
|
var loadContextSources = ctx.loadContextSources;
|
|
191
165
|
var getUserIdForWs = ctx.getUserIdForWs;
|
|
@@ -327,17 +301,6 @@ function attachEmail(ctx) {
|
|
|
327
301
|
}
|
|
328
302
|
}
|
|
329
303
|
}
|
|
330
|
-
// Fallback: if no session-level sources found, check project email defaults
|
|
331
|
-
if (result.length === 0) {
|
|
332
|
-
var defaults = loadEmailDefaults(slug);
|
|
333
|
-
for (var di = 0; di < defaults.length; di++) {
|
|
334
|
-
var dec = emailAccounts.getAccountDecrypted(userId, defaults[di]);
|
|
335
|
-
if (dec && !seen[dec.id]) {
|
|
336
|
-
seen[dec.id] = true;
|
|
337
|
-
result.push(dec);
|
|
338
|
-
}
|
|
339
|
-
}
|
|
340
|
-
}
|
|
341
304
|
return result;
|
|
342
305
|
}
|
|
343
306
|
|
|
@@ -376,28 +339,6 @@ function attachEmail(ctx) {
|
|
|
376
339
|
};
|
|
377
340
|
}
|
|
378
341
|
|
|
379
|
-
function handleEmailMessage(ws, msg) {
|
|
380
|
-
if (msg.type === "email_defaults_get") {
|
|
381
|
-
var defaults = loadEmailDefaults(slug);
|
|
382
|
-
sendTo(ws, { type: "email_defaults", accounts: defaults });
|
|
383
|
-
return true;
|
|
384
|
-
}
|
|
385
|
-
if (msg.type === "email_defaults_save") {
|
|
386
|
-
var accountIds = msg.accounts || [];
|
|
387
|
-
saveEmailDefaults(slug, accountIds);
|
|
388
|
-
// Broadcast to all clients on this project
|
|
389
|
-
var _defMsg = JSON.stringify({ type: "email_defaults", accounts: accountIds });
|
|
390
|
-
for (var c of clients) { if (c.readyState === 1) c.send(_defMsg); }
|
|
391
|
-
return true;
|
|
392
|
-
}
|
|
393
|
-
return false;
|
|
394
|
-
}
|
|
395
|
-
|
|
396
|
-
// Get default email account IDs for new sessions
|
|
397
|
-
function getEmailDefaults() {
|
|
398
|
-
return loadEmailDefaults(slug);
|
|
399
|
-
}
|
|
400
|
-
|
|
401
342
|
function destroy() {
|
|
402
343
|
if (pollTimer) {
|
|
403
344
|
clearInterval(pollTimer);
|
|
@@ -421,10 +362,8 @@ function attachEmail(ctx) {
|
|
|
421
362
|
}
|
|
422
363
|
|
|
423
364
|
return {
|
|
424
|
-
handleEmailMessage: handleEmailMessage,
|
|
425
365
|
getEmailContext: getEmailContext,
|
|
426
366
|
getCheckedEmailAccounts: getCheckedEmailAccounts,
|
|
427
|
-
getEmailDefaults: getEmailDefaults,
|
|
428
367
|
createMcpDeps: createMcpDeps,
|
|
429
368
|
hasEmailCapability: hasEmailCapability,
|
|
430
369
|
destroy: destroy,
|
package/lib/project-http.js
CHANGED
|
@@ -5,6 +5,7 @@ var crypto = require("crypto");
|
|
|
5
5
|
var { execFileSync, spawn } = require("child_process");
|
|
6
6
|
var { fsAsUser } = require("./os-users");
|
|
7
7
|
var usersModule = require("./users");
|
|
8
|
+
var gitCli = require("./git-cli");
|
|
8
9
|
|
|
9
10
|
var IMAGE_EXTS = new Set([".png", ".jpg", ".jpeg", ".gif", ".webp", ".svg", ".bmp", ".ico"]);
|
|
10
11
|
var MIME_TYPES = {
|
|
@@ -47,6 +48,7 @@ function attachHTTP(ctx) {
|
|
|
47
48
|
var slug = ctx.slug;
|
|
48
49
|
var project = ctx.project;
|
|
49
50
|
var sm = ctx.sm;
|
|
51
|
+
var gitAttribution = ctx.gitAttribution;
|
|
50
52
|
var send = ctx.send;
|
|
51
53
|
var imagesDir = ctx.imagesDir;
|
|
52
54
|
var osUsers = ctx.osUsers;
|
|
@@ -643,7 +645,108 @@ function attachHTTP(ctx) {
|
|
|
643
645
|
return true;
|
|
644
646
|
}
|
|
645
647
|
|
|
646
|
-
// Git
|
|
648
|
+
// Git panel status and actions
|
|
649
|
+
var isGitPanelRequest = urlPath === "/api/git/status" ||
|
|
650
|
+
urlPath === "/api/git/action" || urlPath.indexOf("/api/git/file-diff?") === 0 ||
|
|
651
|
+
urlPath.indexOf("/api/git/session-diff?") === 0;
|
|
652
|
+
if (isGitPanelRequest && usersModule.isMultiUser()) {
|
|
653
|
+
var gitRequestUser = req._clayUser;
|
|
654
|
+
var gitPermissions = gitRequestUser ? usersModule.getEffectivePermissions(gitRequestUser, osUsers) : null;
|
|
655
|
+
if (!gitPermissions || !gitPermissions.fileBrowser) {
|
|
656
|
+
res.writeHead(403, { "Content-Type": "application/json" });
|
|
657
|
+
res.end('{"error":"Git access is not permitted"}');
|
|
658
|
+
return true;
|
|
659
|
+
}
|
|
660
|
+
}
|
|
661
|
+
|
|
662
|
+
if (req.method === "GET" && urlPath === "/api/git/status") {
|
|
663
|
+
var gitUserInfo = getOsUserInfoForReq(req);
|
|
664
|
+
try {
|
|
665
|
+
var gitStatus = gitCli.getStatus(cwd, gitUserInfo);
|
|
666
|
+
if (gitAttribution) {
|
|
667
|
+
var visibleGitSessions = sm.sessions;
|
|
668
|
+
if (usersModule.isMultiUser() && req._clayUser) {
|
|
669
|
+
visibleGitSessions = new Map();
|
|
670
|
+
sm.sessions.forEach(function (session, id) {
|
|
671
|
+
if (usersModule.canAccessSession(req._clayUser.id, session, { visibility: "public" })) {
|
|
672
|
+
visibleGitSessions.set(id, session);
|
|
673
|
+
}
|
|
674
|
+
});
|
|
675
|
+
}
|
|
676
|
+
gitAttribution.decorateStatus(gitStatus, visibleGitSessions);
|
|
677
|
+
}
|
|
678
|
+
res.writeHead(200, { "Content-Type": "application/json", "Cache-Control": "no-store" });
|
|
679
|
+
res.end(JSON.stringify(gitStatus));
|
|
680
|
+
} catch (e) {
|
|
681
|
+
res.writeHead(500, { "Content-Type": "application/json" });
|
|
682
|
+
res.end(JSON.stringify({ error: e.message || "Unable to read Git status" }));
|
|
683
|
+
}
|
|
684
|
+
return true;
|
|
685
|
+
}
|
|
686
|
+
|
|
687
|
+
if (req.method === "GET" && urlPath.indexOf("/api/git/file-diff?") === 0) {
|
|
688
|
+
var gitDiffParams = new URLSearchParams(urlPath.slice(urlPath.indexOf("?")));
|
|
689
|
+
var gitDiffPath = gitDiffParams.get("path");
|
|
690
|
+
if (!gitDiffPath) {
|
|
691
|
+
res.writeHead(400, { "Content-Type": "application/json" });
|
|
692
|
+
res.end('{"error":"Missing file path"}');
|
|
693
|
+
return true;
|
|
694
|
+
}
|
|
695
|
+
try {
|
|
696
|
+
var gitDiffResult = gitCli.getFileDiff(cwd, gitDiffPath, getOsUserInfoForReq(req));
|
|
697
|
+
res.writeHead(200, { "Content-Type": "application/json", "Cache-Control": "no-store" });
|
|
698
|
+
res.end(JSON.stringify(gitDiffResult));
|
|
699
|
+
} catch (e) {
|
|
700
|
+
res.writeHead(400, { "Content-Type": "application/json" });
|
|
701
|
+
res.end(JSON.stringify({ error: e.message || "Unable to read file diff" }));
|
|
702
|
+
}
|
|
703
|
+
return true;
|
|
704
|
+
}
|
|
705
|
+
|
|
706
|
+
if (req.method === "GET" && urlPath.indexOf("/api/git/session-diff?") === 0) {
|
|
707
|
+
var sessionDiffParams = new URLSearchParams(urlPath.slice(urlPath.indexOf("?")));
|
|
708
|
+
var sessionDiffKey = sessionDiffParams.get("session");
|
|
709
|
+
var sessionDiffPath = sessionDiffParams.get("path");
|
|
710
|
+
if (!gitAttribution || !sessionDiffKey || !sessionDiffPath) {
|
|
711
|
+
res.writeHead(400, { "Content-Type": "application/json" });
|
|
712
|
+
res.end('{"error":"Missing session comparison"}');
|
|
713
|
+
return true;
|
|
714
|
+
}
|
|
715
|
+
try {
|
|
716
|
+
var requestedSessionVisible = false;
|
|
717
|
+
sm.sessions.forEach(function (session) {
|
|
718
|
+
var key = session.cliSessionId || ("local:" + session.localId);
|
|
719
|
+
if (key !== sessionDiffKey) return;
|
|
720
|
+
requestedSessionVisible = !usersModule.isMultiUser() ||
|
|
721
|
+
(req._clayUser && usersModule.canAccessSession(req._clayUser.id, session, { visibility: "public" }));
|
|
722
|
+
});
|
|
723
|
+
if (!requestedSessionVisible) throw new Error("Session comparison is unavailable");
|
|
724
|
+
var sessionDiff = gitAttribution.getSessionBaselineDiff(sessionDiffKey, sessionDiffPath, getOsUserInfoForReq(req));
|
|
725
|
+
res.writeHead(200, { "Content-Type": "application/json", "Cache-Control": "no-store" });
|
|
726
|
+
res.end(JSON.stringify(sessionDiff));
|
|
727
|
+
} catch (e) {
|
|
728
|
+
res.writeHead(400, { "Content-Type": "application/json" });
|
|
729
|
+
res.end(JSON.stringify({ error: e.message || "Unable to compare session changes" }));
|
|
730
|
+
}
|
|
731
|
+
return true;
|
|
732
|
+
}
|
|
733
|
+
|
|
734
|
+
if (req.method === "POST" && urlPath === "/api/git/action") {
|
|
735
|
+
var gitActionUserInfo = getOsUserInfoForReq(req);
|
|
736
|
+
parseJsonBody(req).then(function (body) {
|
|
737
|
+
return gitCli.runAction(cwd, body, gitActionUserInfo);
|
|
738
|
+
}).then(function (output) {
|
|
739
|
+
var updatedStatus = gitCli.getStatus(cwd, gitActionUserInfo);
|
|
740
|
+
res.writeHead(200, { "Content-Type": "application/json", "Cache-Control": "no-store" });
|
|
741
|
+
res.end(JSON.stringify({ ok: true, output: output, status: updatedStatus }));
|
|
742
|
+
}).catch(function (err) {
|
|
743
|
+
res.writeHead(400, { "Content-Type": "application/json" });
|
|
744
|
+
res.end(JSON.stringify({ error: err.userMessage || err.message || "Git action failed" }));
|
|
745
|
+
});
|
|
746
|
+
return true;
|
|
747
|
+
}
|
|
748
|
+
|
|
749
|
+
// Legacy dirty check used by the Ralph Loop flow
|
|
647
750
|
if (req.method === "GET" && urlPath === "/api/git-dirty") {
|
|
648
751
|
try {
|
|
649
752
|
var out = execFileSync("git", ["status", "--porcelain"], { cwd: cwd, encoding: "utf8", timeout: 5000 });
|
package/lib/project-sessions.js
CHANGED
|
@@ -104,7 +104,6 @@ function attachSessions(ctx) {
|
|
|
104
104
|
var getLatestVersion = ctx.getLatestVersion;
|
|
105
105
|
var setLatestVersion = ctx.setLatestVersion;
|
|
106
106
|
var loadContextSources = ctx.loadContextSources;
|
|
107
|
-
var saveContextSources = ctx.saveContextSources;
|
|
108
107
|
|
|
109
108
|
// Resolve the active user's Claude open-mode preference ('gui' or 'tui').
|
|
110
109
|
// Multi-user mode reads per-user storage; single-user mode falls back to
|
|
@@ -516,7 +515,7 @@ function attachSessions(ctx) {
|
|
|
516
515
|
// Reuse an existing blank GUI session instead of stacking another
|
|
517
516
|
// one. A vendor-less blank is acceptable: nothing has happened in it,
|
|
518
517
|
// so stamping the requested vendor is equivalent to a fresh create.
|
|
519
|
-
var reusable = sm.findReusableBlankSession({
|
|
518
|
+
var reusable = msg.forceNew === true ? null : sm.findReusableBlankSession({
|
|
520
519
|
vendor: sessionOpts.vendor || null,
|
|
521
520
|
ownerId: sessionOpts.ownerId || null,
|
|
522
521
|
});
|
|
@@ -542,15 +541,6 @@ function attachSessions(ctx) {
|
|
|
542
541
|
}
|
|
543
542
|
send({ type: "last_vendor", vendor: msg.vendor });
|
|
544
543
|
}
|
|
545
|
-
// Apply project-level email defaults to new session
|
|
546
|
-
if (typeof ctx._email === "object" && ctx._email.getEmailDefaults) {
|
|
547
|
-
var emailDefaults = ctx._email.getEmailDefaults();
|
|
548
|
-
if (emailDefaults.length > 0) {
|
|
549
|
-
var defaultSources = emailDefaults.map(function (id) { return "email:" + id; });
|
|
550
|
-
saveContextSources(slug, newSess.localId, defaultSources);
|
|
551
|
-
sendTo(ws, { type: "context_sources_state", active: defaultSources });
|
|
552
|
-
}
|
|
553
|
-
}
|
|
554
544
|
var nsPresKey = ws._clayUser ? ws._clayUser.id : "_default";
|
|
555
545
|
if (!ws._clayPane) userPresence.setPresence(slug, nsPresKey, newSess.localId, null);
|
|
556
546
|
if (usersModule.isMultiUser() && !ws._clayPane) {
|
|
@@ -57,6 +57,7 @@ function attachUserMessage(ctx) {
|
|
|
57
57
|
var imagesDir = ctx.imagesDir;
|
|
58
58
|
|
|
59
59
|
var onProcessingChanged = ctx.onProcessingChanged;
|
|
60
|
+
var gitAttribution = ctx.gitAttribution;
|
|
60
61
|
|
|
61
62
|
var _loop = ctx._loop;
|
|
62
63
|
var browserState = ctx.browserState;
|
|
@@ -293,6 +294,7 @@ function attachUserMessage(ctx) {
|
|
|
293
294
|
|
|
294
295
|
var session = getSessionForWs(ws);
|
|
295
296
|
if (!session) return true;
|
|
297
|
+
if (gitAttribution) gitAttribution.beginTurn(session);
|
|
296
298
|
|
|
297
299
|
// Bind vendor to session on first message (if not already set)
|
|
298
300
|
if (!session.vendor && msg.vendor) {
|
package/lib/project.js
CHANGED
|
@@ -3,6 +3,7 @@ var path = require("path");
|
|
|
3
3
|
var os = require("os");
|
|
4
4
|
var crypto = require("crypto");
|
|
5
5
|
var { createSessionManager } = require("./sessions");
|
|
6
|
+
var { attachGitSessionAttribution } = require("./git-session-attribution");
|
|
6
7
|
var { createSDKBridge, createMessageQueue } = require("./sdk-bridge");
|
|
7
8
|
var { createTerminalManager } = require("./terminal-manager");
|
|
8
9
|
var { createNotesManager } = require("./notes");
|
|
@@ -172,7 +173,9 @@ function createProjectContext(opts) {
|
|
|
172
173
|
// --- YOKE adapters (multi-vendor, lazy init) ---
|
|
173
174
|
var _yokeState = yoke.createAdapters({ cwd: cwd, slug: slug, osUsers: osUsers });
|
|
174
175
|
var adapters = _yokeState.adapters;
|
|
175
|
-
|
|
176
|
+
// A new project has no remembered vendor. Select the first installed
|
|
177
|
+
// provider by the shared Claude -> Codex -> Kiro preference order.
|
|
178
|
+
var defaultVendor = yoke.resolveDefaultVendor(adapters);
|
|
176
179
|
var adapter = adapters[defaultVendor] || null;
|
|
177
180
|
|
|
178
181
|
// Browser MCP server runs in-process via createSdkMcpServer (no child process spawn).
|
|
@@ -399,6 +402,7 @@ function createProjectContext(opts) {
|
|
|
399
402
|
var stopAllDirWatches = _fileWatch.stopAllDirWatches;
|
|
400
403
|
|
|
401
404
|
// --- Session manager ---
|
|
405
|
+
var _gitAttribution = null;
|
|
402
406
|
var sm = createSessionManager({
|
|
403
407
|
cwd: cwd,
|
|
404
408
|
send: send,
|
|
@@ -417,7 +421,17 @@ function createProjectContext(opts) {
|
|
|
417
421
|
fn(ws, filterFn);
|
|
418
422
|
}
|
|
419
423
|
},
|
|
420
|
-
onSessionDone:
|
|
424
|
+
onSessionDone: function (session) {
|
|
425
|
+
if (_gitAttribution) _gitAttribution.finishTurn(session);
|
|
426
|
+
onSessionDone();
|
|
427
|
+
},
|
|
428
|
+
});
|
|
429
|
+
_gitAttribution = attachGitSessionAttribution({
|
|
430
|
+
cwd: cwd,
|
|
431
|
+
getOsUserInfoForSession: function (session) {
|
|
432
|
+
var linuxUser = getLinuxUserForSession(session);
|
|
433
|
+
return linuxUser ? resolveOsUserInfo(linuxUser) : null;
|
|
434
|
+
},
|
|
421
435
|
});
|
|
422
436
|
sm.availableVendors = Object.keys(adapters);
|
|
423
437
|
sm.defaultVendor = defaultVendor;
|
|
@@ -1152,9 +1166,6 @@ function createProjectContext(opts) {
|
|
|
1152
1166
|
return;
|
|
1153
1167
|
}
|
|
1154
1168
|
|
|
1155
|
-
// --- Email defaults (project-level) ---
|
|
1156
|
-
if (_email.handleEmailMessage(ws, msg)) return;
|
|
1157
|
-
|
|
1158
1169
|
// --- MCP bridge (remote MCP servers via extension) ---
|
|
1159
1170
|
if (_mcp.handleMcpMessage(ws, msg)) return;
|
|
1160
1171
|
|
|
@@ -1408,6 +1419,7 @@ function createProjectContext(opts) {
|
|
|
1408
1419
|
saveImageFile: saveImageFile,
|
|
1409
1420
|
imagesDir: imagesDir,
|
|
1410
1421
|
onProcessingChanged: onProcessingChanged,
|
|
1422
|
+
gitAttribution: _gitAttribution,
|
|
1411
1423
|
_loop: _loop,
|
|
1412
1424
|
browserState: browserState,
|
|
1413
1425
|
sendExtensionCommandAny: sendExtensionCommandAny,
|
|
@@ -1619,6 +1631,7 @@ function createProjectContext(opts) {
|
|
|
1619
1631
|
slug: slug,
|
|
1620
1632
|
project: title || project,
|
|
1621
1633
|
sm: sm,
|
|
1634
|
+
gitAttribution: _gitAttribution,
|
|
1622
1635
|
send: send,
|
|
1623
1636
|
imagesDir: imagesDir,
|
|
1624
1637
|
osUsers: osUsers,
|
package/lib/public/app.js
CHANGED
|
@@ -25,8 +25,9 @@ import { initNotifications, showDoneNotification, playDoneSound, isNotifAlertEna
|
|
|
25
25
|
import { initInput, clearPendingImages, handleInputSync, autoResize, builtinCommands, sendMessage, hasSendableContent, setScheduleBtnDisabled, setScheduleDelayMs, clearScheduleDelay } from './modules/input.js';
|
|
26
26
|
import { initQrCode, triggerShare } from './modules/qrcode.js';
|
|
27
27
|
import { initFileBrowser, loadRootDirectory, refreshTree, handleFsList, handleFsRead, handleDirChanged, refreshIfOpen, handleFileChanged, handleFileHistory, handleGitDiff, handleFileAt, getPendingNavigate, closeFileViewer, resetFileBrowser } from './modules/filebrowser.js';
|
|
28
|
+
import { initGitPanel } from './modules/git-panel.js';
|
|
28
29
|
import { initTerminal, openTerminal, closeTerminal, resetTerminals, handleTermList, handleTermCreated, handleTermOutput, handleTermResized, handleTermExited, handleTermClosed, sendTerminalCommand } from './modules/terminal.js';
|
|
29
|
-
import { initContextSources,
|
|
30
|
+
import { initContextSources, updateTerminalList, updateBrowserTabList, handleContextSourcesState, getActiveSources, hasActiveSources } from './modules/context-sources.js';
|
|
30
31
|
import { initStickyNotes, handleNotesList, handleNoteCreated, handleNoteUpdated, handleNoteDeleted, openArchive, closeArchive, isArchiveOpen, hideNotes, showNotes, isNotesVisible, createNote } from './modules/sticky-notes.js';
|
|
31
32
|
import { initTheme, getThemeColor, getComputedVar, onThemeChange, getCurrentTheme, getChatLayout } from './modules/theme.js';
|
|
32
33
|
import { initTools, resetToolState, saveToolState, restoreToolState, renderAskUserQuestion, markAskUserAnswered, renderPermissionRequest, markPermissionResolved, markPermissionCancelled, renderElicitationRequest, markElicitationResolved, renderPlanBanner, renderPlanCard, handleTodoWrite, handleTaskCreate, handleTaskUpdate, startThinking, appendThinking, stopThinking, resetThinkingGroup, createToolItem, updateToolExecuting, updateToolResult, markAllToolsDone, addTurnMeta, resetTurnMetaCost, enableMainInput, getTools, getPlanContent, setPlanContent, isPlanFilePath, getTodoTools, updateSubagentActivity, addSubagentToolEntry, markSubagentDone, updateSubagentProgress, initSubagentStop, closeToolGroup, removeToolFromGroup } from './modules/tools.js';
|
|
@@ -324,6 +325,13 @@ import { initDebate, handleDebatePreparing, handleDebateStarted, handleDebateRes
|
|
|
324
325
|
currentFullText: "",
|
|
325
326
|
matePreThinkingEl: null,
|
|
326
327
|
// panels
|
|
328
|
+
fileViewerFullscreen: false,
|
|
329
|
+
markdownSlidesActive: false,
|
|
330
|
+
markdownSlideIndex: 0,
|
|
331
|
+
markdownSlideCount: 0,
|
|
332
|
+
markdownSlideLevel: 1,
|
|
333
|
+
markdownSlidePreferredLevel: 1,
|
|
334
|
+
markdownSlideLevelExplicit: false,
|
|
327
335
|
currentModel: "",
|
|
328
336
|
currentModels: [],
|
|
329
337
|
// Project's last-used vendor; seeds the sidebar's "New session" button.
|
|
@@ -875,6 +883,8 @@ import { initDebate, handleDebatePreparing, handleDebateStarted, handleDebateRes
|
|
|
875
883
|
if (!_perms.fileBrowser) {
|
|
876
884
|
var fbBtn = document.getElementById("file-browser-btn");
|
|
877
885
|
if (fbBtn) fbBtn.style.display = "none";
|
|
886
|
+
var gitBtn = document.getElementById("git-sidebar-btn");
|
|
887
|
+
if (gitBtn) gitBtn.style.display = "none";
|
|
878
888
|
}
|
|
879
889
|
if (!_perms.skills) {
|
|
880
890
|
var sBtn = document.getElementById("skills-btn");
|
|
@@ -963,6 +973,7 @@ import { initDebate, handleDebatePreparing, handleDebateStarted, handleDebateRes
|
|
|
963
973
|
fileTreeEl: $("file-tree"),
|
|
964
974
|
fileViewerEl: $("file-viewer"),
|
|
965
975
|
});
|
|
976
|
+
initGitPanel();
|
|
966
977
|
|
|
967
978
|
// --- Terminal ---
|
|
968
979
|
initTerminal({
|
|
@@ -1047,8 +1058,10 @@ import { initDebate, handleDebatePreparing, handleDebateStarted, handleDebateRes
|
|
|
1047
1058
|
|
|
1048
1059
|
// Close archive / scheduler panel when switching to other sidebar panels
|
|
1049
1060
|
var fileBrowserBtn = $("file-browser-btn");
|
|
1061
|
+
var gitSidebarBtn = $("git-sidebar-btn");
|
|
1050
1062
|
var terminalSidebarBtn = $("terminal-sidebar-btn");
|
|
1051
1063
|
if (fileBrowserBtn) fileBrowserBtn.addEventListener("click", function () { if (isArchiveOpen()) closeArchive(); if (isSchedulerOpen()) closeScheduler(); });
|
|
1064
|
+
if (gitSidebarBtn) gitSidebarBtn.addEventListener("click", function () { if (isArchiveOpen()) closeArchive(); if (isSchedulerOpen()) closeScheduler(); });
|
|
1052
1065
|
if (terminalSidebarBtn) terminalSidebarBtn.addEventListener("click", function () { if (isArchiveOpen()) closeArchive(); if (isSchedulerOpen()) closeScheduler(); });
|
|
1053
1066
|
|
|
1054
1067
|
// --- Ralph Loop UI (delegated to app-loop-ui.js + app-loop-wizard.js) ---
|
|
@@ -1114,7 +1127,6 @@ import { initDebate, handleDebatePreparing, handleDebateStarted, handleDebateRes
|
|
|
1114
1127
|
|
|
1115
1128
|
// --- MCP Servers ---
|
|
1116
1129
|
initMcp();
|
|
1117
|
-
initEmailDefaultsModal();
|
|
1118
1130
|
|
|
1119
1131
|
// --- Skills ---
|
|
1120
1132
|
initSkills();
|