clay-server 5.2.0-beta.4 → 5.2.0-beta.6
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/account-auth-socket.js +1 -0
- package/lib/builtin-mates.js +17 -14
- package/lib/canonical-clay-record-authority.js +15 -0
- package/lib/canonical-clay-scheduling-authority.js +19 -0
- package/lib/claude-hook-installer.js +1 -239
- package/lib/claude-jsonl-watcher.js +1 -204
- package/lib/clay-mate-chat-receipts.js +26 -0
- package/lib/clay-mate-chat.js +87 -0
- package/lib/clay-mate-knowledge-input.js +26 -0
- package/lib/clay-mate-knowledge.js +95 -0
- package/lib/clay-mate-lifecycle.js +95 -0
- package/lib/clay-product-control-input.js +33 -0
- package/lib/clay-product-control-tools.js +51 -0
- package/lib/clay-product-control.js +237 -0
- package/lib/clay-project-lifecycle.js +154 -0
- package/lib/clay-project-record-input.js +44 -0
- package/lib/clay-project-records.js +83 -0
- package/lib/clay-scheduling-input.js +21 -0
- package/lib/clay-scheduling-receipts.js +26 -0
- package/lib/clay-scheduling.js +119 -0
- package/lib/clay-screen-controls.js +96 -0
- package/lib/clay-skill-install.js +1 -33
- package/lib/clay-workspace-controls.js +83 -0
- package/lib/clay-workspace-input.js +17 -0
- package/lib/clay-workspace-receipts.js +26 -0
- package/lib/cli-sessions.js +1 -300
- package/lib/codex-defaults.js +1 -28
- package/lib/context-usage.js +3 -2
- package/lib/daemon-project-access.js +11 -0
- package/lib/daemon-project-lifecycle-callbacks.js +15 -0
- package/lib/daemon-project-lifecycle.js +262 -0
- package/lib/daemon-projects.js +1 -1
- package/lib/daemon.js +78 -276
- package/lib/default-ai-runtime.js +4 -8
- package/lib/email-mcp-server.js +1 -1
- package/lib/issues-service.js +29 -15
- package/lib/kiro-defaults.js +1 -22
- package/lib/knowledge-db-import.js +5 -4
- package/lib/knowledge-db-service.js +9 -6
- package/lib/knowledge-document-index.js +2 -1
- package/lib/knowledge-product-operations.js +46 -0
- package/lib/mate-creation-mcp-server.js +2 -0
- package/lib/mate-knowledge-canonical-access.js +10 -0
- package/lib/mate-knowledge-service.js +7 -4
- package/lib/mate-lifecycle-service.js +94 -0
- package/lib/mate-message-delivery.js +43 -0
- package/lib/mate-ready-creation.js +9 -1
- package/lib/mate-schedule-input.js +29 -0
- package/lib/mate-schedule-lifecycle.js +151 -0
- package/lib/mate-scheduling.js +103 -0
- package/lib/mates.js +4 -3
- package/lib/mcp-proxy.js +2 -32
- package/lib/mcp-query-bridge.js +1 -1
- package/lib/mcp-source-adapters.js +1 -91
- package/lib/mcp-source-context.js +1 -42
- package/lib/mcp-source-discovery.js +1 -169
- package/lib/mcp-source-plugins.js +1 -68
- package/lib/mcp-source-restrictions.js +1 -47
- package/lib/mcp-tool-policy.js +1 -26
- package/lib/notes-checklist.js +50 -0
- package/lib/notes.js +49 -3
- package/lib/os-user-diagnostics.js +2 -4
- package/lib/os-users.js +24 -70
- package/lib/project-admin-overview.js +51 -0
- package/lib/project-ask-user.js +4 -2
- package/lib/project-connection.js +8 -7
- package/lib/project-delegated-follow-up.js +2 -1
- package/lib/project-directory-claim.js +65 -0
- package/lib/project-file-operations.js +61 -0
- package/lib/project-filesystem.js +13 -87
- package/lib/project-full-access.js +23 -2
- package/lib/project-http.js +4 -4
- package/lib/project-knowledge.js +32 -18
- package/lib/project-lifecycle-operations.js +98 -0
- package/lib/project-lifecycle-process-witness.js +32 -0
- package/lib/project-lifecycle-runtime.js +50 -0
- package/lib/project-linux-access.js +22 -0
- package/lib/project-logs-canonical-clay.js +27 -0
- package/lib/project-logs-clay-query.js +16 -0
- package/lib/project-logs-schema.js +4 -2
- package/lib/project-logs-service.js +8 -7
- package/lib/project-logs.js +1 -0
- package/lib/project-loop.js +1 -0
- package/lib/project-mate-chat-control.js +55 -0
- package/lib/project-mate-creation-proposal.js +18 -3
- package/lib/project-mcp.js +2 -2
- package/lib/project-models.js +14 -31
- package/lib/project-notifications.js +74 -16
- package/lib/project-ownership.js +77 -0
- package/lib/project-pair-result-delivery.js +14 -3
- package/lib/project-pair-usage.js +12 -13
- package/lib/project-pending-message-queue.js +4 -1
- package/lib/project-product-control.js +87 -0
- package/lib/project-product-session-queue.js +46 -0
- package/lib/project-push-access.js +28 -0
- package/lib/project-scheduled-message-queue.js +30 -0
- package/lib/project-scheduled-messages.js +63 -64
- package/lib/project-scheduled-task-control.js +83 -0
- package/lib/project-scheduled-tasks.js +13 -2
- package/lib/project-scheduling-access.js +10 -0
- package/lib/project-session-actions.js +65 -0
- package/lib/project-session-delete.js +8 -1
- package/lib/project-session-github.js +47 -12
- package/lib/project-session-history-actions.js +167 -0
- package/lib/project-session-pair.js +1 -1
- package/lib/project-session-runtime-actions.js +64 -0
- package/lib/project-session-spawn.js +2 -3
- package/lib/project-session-vendor.js +55 -0
- package/lib/project-sessions.js +82 -267
- package/lib/project-user-message.js +31 -1
- package/lib/project-vendor-login.js +6 -36
- package/lib/project-workspace-operations.js +126 -0
- package/lib/project-workspace-query.js +9 -2
- package/lib/project.js +95 -3
- package/lib/public/app.js +1 -0
- package/lib/public/css/clay-tool-activity.css +51 -0
- package/lib/public/css/home-mate-creation.css +5 -0
- package/lib/public/css/messages.css +6 -2
- package/lib/public/css/overlays.css +4 -2
- package/lib/public/css/project-admin-overview.css +13 -0
- package/lib/public/css/session-folders.css +11 -0
- package/lib/public/css/session-github.css +3 -0
- package/lib/public/css/sticky-notes.css +61 -1
- package/lib/public/index.html +1 -1
- package/lib/public/modules/admin-settings-projects.js +6 -2
- package/lib/public/modules/app-connection.js +8 -1
- package/lib/public/modules/app-favicon.js +11 -2
- package/lib/public/modules/app-header.js +4 -2
- package/lib/public/modules/app-loop-ui.js +2 -0
- package/lib/public/modules/app-message-router.js +1 -1
- package/lib/public/modules/app-messages.js +54 -8
- package/lib/public/modules/app-notifications.js +1 -2
- package/lib/public/modules/app-panels.js +61 -123
- package/lib/public/modules/app-projects.js +5 -0
- package/lib/public/modules/app-rate-limit.js +7 -27
- package/lib/public/modules/chat-render-runtime.js +3 -0
- package/lib/public/modules/clay-owner-navigation.js +27 -0
- package/lib/public/modules/clay-tool-activity.js +140 -0
- package/lib/public/modules/clay-tool-presentation.js +338 -0
- package/lib/public/modules/command-palette.js +1 -1
- package/lib/public/modules/default-ai.js +11 -3
- package/lib/public/modules/home-debate-planning.js +5 -5
- package/lib/public/modules/home-mate-chat.js +8 -6
- package/lib/public/modules/home-mate-creation.js +73 -1
- package/lib/public/modules/mcp-connection-view.js +1 -1
- package/lib/public/modules/permission-control.js +5 -4
- package/lib/public/modules/personal-settings-dialog.js +7 -1
- package/lib/public/modules/project-access-recovery.js +17 -0
- package/lib/public/modules/project-admin-overview.js +21 -0
- package/lib/public/modules/scheduler.js +2 -0
- package/lib/public/modules/session-create-form.js +10 -10
- package/lib/public/modules/session-folder-layout.js +1 -1
- package/lib/public/modules/session-folder-view-menu.js +9 -0
- package/lib/public/modules/session-github.js +65 -8
- package/lib/public/modules/settings-defaults.js +27 -28
- package/lib/public/modules/sidebar-session-folders-ui.js +1 -1
- package/lib/public/modules/sticky-note-markdown.js +72 -6
- package/lib/public/modules/sticky-notes-actions.js +30 -0
- package/lib/public/modules/sticky-notes-browser.js +9 -2
- package/lib/public/modules/sticky-notes-card.js +23 -7
- package/lib/public/modules/sticky-notes-checklist.js +71 -0
- package/lib/public/modules/sticky-notes-editor.js +108 -44
- package/lib/public/modules/sticky-notes-shared.js +50 -2
- package/lib/public/modules/sticky-notes-state.js +66 -0
- package/lib/public/modules/sticky-notes.js +34 -51
- package/lib/public/modules/thinking-lifecycle.js +33 -3
- package/lib/public/modules/thinking-view.js +23 -1
- package/lib/public/modules/tools.js +36 -7
- package/lib/public/modules/tui-grab.js +1 -2
- package/lib/public/modules/user-settings-appearance.js +10 -3
- package/lib/public/modules/user-settings-editors.js +1 -1
- package/lib/public/modules/user-settings-layout.js +11 -2
- package/lib/public/modules/user-settings-preferences.js +6 -2
- package/lib/public/modules/user-settings-profile.js +12 -2
- package/lib/public/modules/user-settings.js +3 -2
- package/lib/public/modules/vendor-login-browser.js +5 -3
- package/lib/public/modules/vendor-login.js +2 -2
- package/lib/public/modules/vendor-priority.js +15 -1
- package/lib/public/muse-avatar.svg +4 -0
- package/lib/public/style.css +2 -0
- package/lib/safe-bash-commands.js +3 -45
- package/lib/scheduled-task-records.js +3 -1
- package/lib/scheduler.js +2 -0
- package/lib/sdk-bridge.js +334 -403
- package/lib/sdk-foreground-admission.js +16 -0
- package/lib/sdk-mcp-descriptors.js +2 -37
- package/lib/sdk-message-processor.js +52 -17
- package/lib/sdk-quota-snapshot.js +1 -1
- package/lib/sdk-response-recovery.js +1 -0
- package/lib/sdk-worker.js +2 -677
- package/lib/server-admin.js +63 -16
- package/lib/server-dm.js +1 -1
- package/lib/server-global-ws.js +10 -20
- package/lib/server-home-chat-events.js +7 -3
- package/lib/server-home-chat.js +4 -16
- package/lib/server-home-mate-creation.js +1 -0
- package/lib/server-home-mcp-consent.js +3 -3
- package/lib/server-mates.js +25 -67
- package/lib/server-owner-ui.js +77 -0
- package/lib/server-path-access.js +38 -0
- package/lib/server-project-removal.js +22 -0
- package/lib/server.js +100 -30
- package/lib/session-config-transition.js +45 -0
- package/lib/session-folders.js +7 -2
- package/lib/session-fork-history.js +21 -0
- package/lib/session-github.js +9 -2
- package/lib/session-hygiene.js +3 -35
- package/lib/session-permission-mode.js +4 -3
- package/lib/session-skill-scope.js +11 -0
- package/lib/session-visibility.js +5 -2
- package/lib/sessions.js +27 -89
- package/lib/terminal-manager.js +52 -0
- package/lib/tool-llm.js +1 -1
- package/lib/tui-transcript-index.js +1 -132
- package/lib/users-permissions.js +2 -8
- package/lib/users.js +4 -0
- package/lib/vendor-login-browser.js +1 -11
- package/lib/workspace-query-access.js +4 -1
- package/lib/ws-schema.js +8 -2
- package/lib/yoke/acp-agent-profiles.js +5 -3
- package/lib/yoke/adapters/antigravity.js +3 -14
- package/lib/yoke/adapters/claude-query-contract.js +9 -0
- package/lib/yoke/adapters/claude.js +54 -50
- package/lib/yoke/adapters/codex-query-contract.js +24 -0
- package/lib/yoke/adapters/codex.js +53 -111
- package/lib/yoke/adapters/kiro.js +3 -1
- package/lib/yoke/adapters/muse-query-contract.js +7 -0
- package/lib/yoke/adapters/muse.js +122 -0
- package/lib/yoke/auth-events.js +17 -0
- package/lib/yoke/claude-hook-installer.js +267 -0
- package/lib/yoke/claude-jsonl-watcher.js +204 -0
- package/lib/yoke/claude-maintenance.js +55 -0
- package/lib/yoke/claude-permission-patterns.js +53 -0
- package/lib/yoke/claude-response-recovery.js +155 -0
- package/lib/yoke/claude-transcript-hygiene.js +34 -0
- package/lib/yoke/claude-worker-startup.js +28 -0
- package/lib/yoke/clay-skill-install.js +33 -0
- package/lib/yoke/cli-sessions.js +300 -0
- package/lib/yoke/codex-app-server.js +7 -12
- package/lib/yoke/codex-idle-recovery.js +81 -1
- package/lib/yoke/codex-recovery-admission.js +164 -0
- package/lib/yoke/configuration.js +13 -0
- package/lib/yoke/discovery.js +70 -0
- package/lib/yoke/errors.js +8 -0
- package/lib/yoke/host-environment.js +7 -0
- package/lib/yoke/index.js +9 -51
- package/lib/yoke/interface.js +116 -0
- package/lib/yoke/kiro-acp-server.js +5 -5
- package/lib/yoke/legacy-sessions.js +89 -0
- package/lib/yoke/login-protocol.js +25 -0
- package/lib/yoke/maintenance.js +12 -0
- package/lib/yoke/mcp-proxy.js +32 -0
- package/lib/yoke/mcp-source-adapters.js +91 -0
- package/lib/yoke/mcp-source-context.js +42 -0
- package/lib/yoke/mcp-source-discovery.js +169 -0
- package/lib/yoke/mcp-source-plugins.js +68 -0
- package/lib/yoke/mcp-source-restrictions.js +47 -0
- package/lib/yoke/mcp-tool-policy-normalize.js +28 -0
- package/lib/yoke/model-preferences.js +6 -0
- package/lib/yoke/muse-artifacts.js +36 -0
- package/lib/yoke/muse-controls.js +50 -0
- package/lib/yoke/muse-input.js +64 -0
- package/lib/yoke/muse-items.js +157 -0
- package/lib/yoke/muse-policy.js +52 -0
- package/lib/yoke/muse-query.js +428 -0
- package/lib/yoke/muse-runtime.js +211 -0
- package/lib/yoke/muse-services.js +79 -0
- package/lib/yoke/muse-skills.js +79 -0
- package/lib/yoke/muse-turns.js +71 -0
- package/lib/yoke/options/acp.js +2 -0
- package/lib/yoke/options/antigravity.js +2 -0
- package/lib/yoke/options/claude.js +21 -0
- package/lib/yoke/options/codex-defaults.js +29 -0
- package/lib/yoke/options/codex-settings.js +21 -0
- package/lib/yoke/options/codex.js +6 -0
- package/lib/yoke/options/kiro-defaults.js +22 -0
- package/lib/yoke/options/kiro.js +5 -0
- package/lib/yoke/options/muse.js +5 -0
- package/lib/yoke/provider-contract.js +5 -0
- package/lib/yoke/providers/antigravity-executable.js +8 -0
- package/lib/yoke/providers/claude-executable.js +40 -0
- package/lib/yoke/providers/claude-model-descriptions.js +14 -0
- package/lib/yoke/providers/claude-process.js +97 -0
- package/lib/yoke/providers/claude-provision.js +75 -0
- package/lib/yoke/providers/codex-errors.js +8 -0
- package/lib/yoke/providers/muse-executable.js +17 -0
- package/lib/yoke/provisioning.js +6 -0
- package/lib/yoke/query-options.js +10 -0
- package/lib/yoke/response-recovery.js +41 -0
- package/lib/yoke/sdk-mcp-descriptors.js +37 -0
- package/lib/yoke/sdk-server-factory.js +7 -0
- package/lib/yoke/session-history.js +8 -0
- package/lib/yoke/session-tool-transport.js +34 -13
- package/lib/yoke/settings.js +23 -0
- package/lib/yoke/source-locations.js +4 -0
- package/lib/yoke/title-query.js +18 -7
- package/lib/yoke/tui-transcript-index.js +132 -0
- package/lib/yoke/usage.js +48 -0
- package/lib/yoke/user-input.js +13 -0
- package/lib/yoke/vendor-registry.js +81 -1
- package/package.json +3 -2
|
@@ -66,7 +66,7 @@ export function permissionStatusText(state, pending, autoSupported, autoVisible)
|
|
|
66
66
|
if (state.permissionMode === "plan") return "Plan workflow";
|
|
67
67
|
if (state.permissionMode === "acceptEdits") return "Auto-accept edits workflow";
|
|
68
68
|
if (state.permissionMode === "dontAsk") return "Don't ask workflow";
|
|
69
|
-
if (autoVisible && !autoSupported) return "Auto unavailable for this
|
|
69
|
+
if (autoVisible && !autoSupported) return "Auto unavailable for this session";
|
|
70
70
|
if (state.permissionMode === "auto" && !state.effectivePermissionMode) return "Auto selected · waiting for runtime";
|
|
71
71
|
if (state.permissionMode === "auto" && state.effectivePermissionMode !== "auto") {
|
|
72
72
|
return "Auto unavailable at runtime · using " + modeLabel(state.effectivePermissionMode);
|
|
@@ -91,7 +91,8 @@ export function renderPermissionControl(control, state) {
|
|
|
91
91
|
var projectSlug = state.projectSlug || "";
|
|
92
92
|
var sessionId = state.sessionId || null;
|
|
93
93
|
var pending = permissionPendingFor(projectSlug, sessionId);
|
|
94
|
-
var
|
|
94
|
+
var description = ((store.get("vendorInfo") || {})[state.vendor] || {}).configuration || {};
|
|
95
|
+
var autoVisible = description.auto === true || !!(state.permissionCapabilities && state.permissionCapabilities.auto === true);
|
|
95
96
|
var autoSupported = !!(state.permissionCapabilities && state.permissionCapabilities.auto === true);
|
|
96
97
|
var globallyForced = state.globalPermissionModeForced === true;
|
|
97
98
|
var connected = state.connected !== false && !!getWs() && getWs().readyState === 1;
|
|
@@ -114,7 +115,7 @@ export function renderPermissionControl(control, state) {
|
|
|
114
115
|
buttons[i].classList.toggle("pending", requested);
|
|
115
116
|
buttons[i].setAttribute("aria-pressed", selected ? "true" : "false");
|
|
116
117
|
buttons[i].setAttribute("aria-busy", requested ? "true" : "false");
|
|
117
|
-
buttons[i].title = unsupported ? "Auto permissions are unavailable for this
|
|
118
|
+
buttons[i].title = unsupported ? "Auto permissions are unavailable for this session." : buttonTitles[mode];
|
|
118
119
|
}
|
|
119
120
|
var status = control.querySelector(".session-permission-status");
|
|
120
121
|
if (status) {
|
|
@@ -138,7 +139,7 @@ export function bindPermissionControl(control, getState) {
|
|
|
138
139
|
var autoSupported = !!(state.permissionCapabilities && state.permissionCapabilities.auto === true);
|
|
139
140
|
if (state.visible === false || state.locked === true || state.globalPermissionModeForced === true || state.connected === false || store.get('connected') === false) return;
|
|
140
141
|
if (!state.projectSlug || state.projectSlug !== store.get('currentSlug') || !state.sessionId) return;
|
|
141
|
-
if (mode === "auto" &&
|
|
142
|
+
if (mode === "auto" && !autoSupported) return;
|
|
142
143
|
sendPermissionMode(state.projectSlug, state.sessionId, mode);
|
|
143
144
|
});
|
|
144
145
|
}
|
|
@@ -17,7 +17,13 @@ export function preparePersonalConnectionDialog(overlay, inline) {
|
|
|
17
17
|
if (label && input) label.htmlFor = input.id;
|
|
18
18
|
});
|
|
19
19
|
enhanceSettingsSelects(overlay);
|
|
20
|
-
|
|
20
|
+
var fields = Array.from(overlay.querySelectorAll('input,select,textarea'));
|
|
21
|
+
function value(field) {return field.type === 'checkbox' ? field.checked : field.value;}
|
|
22
|
+
var baseline = fields.map(value);
|
|
23
|
+
function markDirty() {
|
|
24
|
+
dirty = fields.some(function (field, index) {return value(field) !== baseline[index];});
|
|
25
|
+
if (inline) store.set({personalEmailDirty:dirty});
|
|
26
|
+
}
|
|
21
27
|
overlay.addEventListener('input', markDirty);
|
|
22
28
|
overlay.addEventListener('change', markDirty);
|
|
23
29
|
var unsubscribe = inline ? store.subscribe(function (state, previousState) {
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { store } from './store.js';
|
|
2
|
+
|
|
3
|
+
// Hard navigation destroys detached panels, cached transcripts and sockets.
|
|
4
|
+
// Clear the rendered document first so revoked content cannot linger while the
|
|
5
|
+
// replacement page is loading or when that request fails.
|
|
6
|
+
export function leaveRevokedProject(url) {
|
|
7
|
+
store.set({ activeSessionId: null, activeProjectSlug: null, sessionActivatedProjectSlug: null, sessions: [], splitPanes: null });
|
|
8
|
+
document.body.replaceChildren();
|
|
9
|
+
window.location.replace(url || "/");
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export function reconnectDestination(info, slug) {
|
|
13
|
+
if (!slug || !info || !Array.isArray(info.projects)) return null;
|
|
14
|
+
var project = info.projects.find(function (item) { return item.slug === slug; });
|
|
15
|
+
if (!project) return "/";
|
|
16
|
+
return project.contentAccess === false ? "/p/" + encodeURIComponent(slug) + "/" : null;
|
|
17
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
// This page never opens a project socket or loads project content modules.
|
|
2
|
+
var tabs = Array.from(document.querySelectorAll('[role="tab"]'));
|
|
3
|
+
function select(tab) {
|
|
4
|
+
tabs.forEach(function (item) {
|
|
5
|
+
var active = item === tab;
|
|
6
|
+
item.setAttribute("aria-selected", String(active));
|
|
7
|
+
item.tabIndex = active ? 0 : -1;
|
|
8
|
+
document.getElementById(item.getAttribute("aria-controls")).hidden = !active;
|
|
9
|
+
});
|
|
10
|
+
}
|
|
11
|
+
tabs.forEach(function (tab, index) {
|
|
12
|
+
tab.addEventListener("click", function () { select(tab); });
|
|
13
|
+
tab.addEventListener("keydown", function (event) {
|
|
14
|
+
if (["ArrowLeft", "ArrowRight", "Home", "End"].indexOf(event.key) === -1) return;
|
|
15
|
+
event.preventDefault();
|
|
16
|
+
var target = event.key === "Home" ? tabs[0] : event.key === "End" ? tabs[tabs.length - 1] : tabs[(index + (event.key === "ArrowRight" ? 1 : tabs.length - 1)) % tabs.length];
|
|
17
|
+
select(target);
|
|
18
|
+
target.focus();
|
|
19
|
+
});
|
|
20
|
+
});
|
|
21
|
+
select(tabs[0]);
|
|
@@ -784,6 +784,8 @@ function renderModelTab(bodyEl, rec) {
|
|
|
784
784
|
}
|
|
785
785
|
|
|
786
786
|
var opts = {
|
|
787
|
+
effortLevels: ((store.get("vendorInfo") || {})[store.get("currentVendor")] || {}).effortLevels || [],
|
|
788
|
+
configuration: ((store.get("vendorInfo") || {})[store.get("currentVendor")] || {}).configuration || {},
|
|
787
789
|
models: store.get('currentModels') || [],
|
|
788
790
|
currentModel: settings.model || "",
|
|
789
791
|
currentMode: settings.permissionMode || "default",
|
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
import { store } from './store.js';
|
|
9
9
|
import { iconHtml, refreshIcons } from './icons.js';
|
|
10
10
|
import { VENDOR_AVATARS, VENDOR_NAMES, VENDOR_ORDER, isExperimentalVendor } from './app-rendering.js';
|
|
11
|
+
import { sortVendorEntries } from './vendor-priority.js';
|
|
11
12
|
import { startNewSession } from './sidebar-sessions.js';
|
|
12
13
|
import { closeMobileSheet } from './sidebar-mobile.js';
|
|
13
14
|
import {
|
|
@@ -15,20 +16,19 @@ import {
|
|
|
15
16
|
beginSessionCreate, closeSessionCreate, chooseVendor, setCreateMenu, submitSessionCreate, submitMateSessionCreate, saveProjectDefault, retryOptions
|
|
16
17
|
} from './session-create.js';
|
|
17
18
|
|
|
18
|
-
//
|
|
19
|
-
//
|
|
19
|
+
// Installed providers first, each group in the established priority order,
|
|
20
|
+
// followed by unknown providers in server order. Installed state is the
|
|
20
21
|
// server's, per user; the dropdown never invents or hardcodes availability.
|
|
21
22
|
function vendorEntries(options) {
|
|
22
23
|
var byId = {};
|
|
23
24
|
options.vendors.forEach(function (v) { byId[v.id] = v; });
|
|
24
25
|
var ids = VENDOR_ORDER.slice();
|
|
25
26
|
options.vendors.forEach(function (v) { if (ids.indexOf(v.id) === -1) ids.push(v.id); });
|
|
26
|
-
return ids.map(function (id) {
|
|
27
|
+
return sortVendorEntries(ids.map(function (id) {
|
|
27
28
|
var known = byId[id];
|
|
28
29
|
return { id: id, name: VENDOR_NAMES[id] || (known && known.displayName) || id, installed: !!(known && known.installed) };
|
|
29
|
-
});
|
|
30
|
+
}));
|
|
30
31
|
}
|
|
31
|
-
|
|
32
32
|
function vendorLabel(id) {
|
|
33
33
|
return VENDOR_NAMES[id] || id;
|
|
34
34
|
}
|
|
@@ -69,7 +69,6 @@ function focusCreateRow(folderId) {
|
|
|
69
69
|
if (target && !target.disabled) { target.focus({ preventScroll: true }); return; }
|
|
70
70
|
}
|
|
71
71
|
}
|
|
72
|
-
|
|
73
72
|
function prefersReducedMotion() {
|
|
74
73
|
return typeof window !== "undefined" && window.matchMedia && window.matchMedia("(prefers-reduced-motion: reduce)").matches;
|
|
75
74
|
}
|
|
@@ -381,7 +380,8 @@ function paintRow(root) {
|
|
|
381
380
|
}
|
|
382
381
|
placeMenu(root);
|
|
383
382
|
if (form.menuOpen && form.menuFocus && root.getClientRects().length) {
|
|
384
|
-
var
|
|
383
|
+
var entry = entries[form.menuIndex || 0];
|
|
384
|
+
var first = entry && root.querySelector('[data-focus-key="item:' + encodeURIComponent(entry.id) + '"]');
|
|
385
385
|
if (first) { first.focus({ preventScroll: true }); store.set({ sessionCreate: Object.assign({}, createState(), { menuFocus: false }) }); }
|
|
386
386
|
}
|
|
387
387
|
}
|
|
@@ -406,14 +406,14 @@ function renderMenu(entries, form, options, installed) {
|
|
|
406
406
|
menu.className = "session-create-menu";
|
|
407
407
|
menu.setAttribute("role", "menu");
|
|
408
408
|
menu.setAttribute("aria-label", "Providers");
|
|
409
|
-
entries.forEach(function (entry
|
|
409
|
+
entries.forEach(function (entry) {
|
|
410
410
|
var row = document.createElement("div");
|
|
411
411
|
row.className = "session-create-menu-provider";
|
|
412
412
|
var html = '<img src="' + (VENDOR_AVATARS[entry.id] || VENDOR_AVATARS.claude) + '" class="session-create-icon" alt="">' +
|
|
413
413
|
'<span class="session-create-menu-name"></span>' +
|
|
414
414
|
(entry.installed && isExperimentalVendor(entry.id) ? '<span class="vendor-experimental-badge" aria-label="Experimental integration" title="Experimental integration; not yet validated through direct use testing">🧪</span>' : "") +
|
|
415
415
|
(entry.installed ? (options.projectDefault === entry.id ? '<span class="session-create-menu-note">Default</span>' : "") : '<span class="session-create-menu-note">Not installed</span>');
|
|
416
|
-
var item = menuItem("item:" +
|
|
416
|
+
var item = menuItem("item:" + encodeURIComponent(entry.id), (entry.installed ? "" : "unavailable ") + (entry.id === form.vendor ? "selected" : ""), html, function () {
|
|
417
417
|
if (entry.installed) { chooseVendor(entry.id); var live = createState(); store.set({ sessionCreate: Object.assign({}, live, { focusKey: "vendor", wantFocus: true }) }); }
|
|
418
418
|
}, entry.installed ? "New " + entry.name + " session" : entry.name + " is not installed");
|
|
419
419
|
item.querySelector(".session-create-menu-name").textContent = entry.name;
|
|
@@ -423,7 +423,7 @@ function renderMenu(entries, form, options, installed) {
|
|
|
423
423
|
row.appendChild(item);
|
|
424
424
|
if (entry.installed && options.canSetProjectDefault && options.projectDefault !== entry.id) {
|
|
425
425
|
var savingThis = form.defaultSaving && form.defaultVendor === entry.id;
|
|
426
|
-
var setDefault = menuItem("default:" +
|
|
426
|
+
var setDefault = menuItem("default:" + encodeURIComponent(entry.id), "session-create-default-btn", "<span></span>", function () { saveProjectDefault(entry.id); }, "Set " + entry.name + " as the project default");
|
|
427
427
|
setDefault.firstChild.textContent = savingThis ? "Saving" : "Set default";
|
|
428
428
|
setDefault.disabled = !!form.defaultSaving;
|
|
429
429
|
row.appendChild(setDefault);
|
|
@@ -9,7 +9,7 @@ export var FAVORITES_ID = "favorites";
|
|
|
9
9
|
export var UNFILED_ID = "unfiled";
|
|
10
10
|
|
|
11
11
|
export function defaultFolderState() {
|
|
12
|
-
return { folders: [], assignments: {}, favorites: [], orders: {}, collapsed: {}, view: { sort: "activity", direction: "desc" } };
|
|
12
|
+
return { folders: [], assignments: {}, favorites: [], orders: {}, collapsed: {}, view: { sort: "activity", direction: "desc", showDateHeadings: true } };
|
|
13
13
|
}
|
|
14
14
|
|
|
15
15
|
export function sortUnits(units, view, order) {
|
|
@@ -78,6 +78,15 @@ export function paintViewMenu() {
|
|
|
78
78
|
note.textContent = "Drag sessions to arrange them. Favorites keep their own order.";
|
|
79
79
|
menu.appendChild(note);
|
|
80
80
|
}
|
|
81
|
+
var dateToggle = document.createElement("button");
|
|
82
|
+
dateToggle.type = "button";
|
|
83
|
+
dateToggle.className = "session-folder-view-toggle";
|
|
84
|
+
dateToggle.dataset.focusKey = "showDateHeadings";
|
|
85
|
+
dateToggle.setAttribute("role", "switch");
|
|
86
|
+
dateToggle.setAttribute("aria-checked", String(view.showDateHeadings !== false));
|
|
87
|
+
dateToggle.innerHTML = '<span>Show date headings</span><span class="session-folder-view-toggle-track" aria-hidden="true"><span class="session-folder-view-toggle-thumb"></span></span>';
|
|
88
|
+
dateToggle.addEventListener("click", function () { sendViewPatch({ showDateHeadings: view.showDateHeadings === false }); });
|
|
89
|
+
menu.appendChild(dateToggle);
|
|
81
90
|
if (focusKey) {
|
|
82
91
|
var target = menu.querySelector('[data-focus-key="' + focusKey + '"]') || menu.querySelector(".session-folder-radio.selected");
|
|
83
92
|
if (target) target.focus();
|
|
@@ -46,6 +46,28 @@ function compactGithubWork(links, sessionRow) {
|
|
|
46
46
|
var latestPr = links.find(function (link) { return link.kind === 'pr'; });
|
|
47
47
|
return [latestLinear, latestIssue, latestPr].filter(Boolean);
|
|
48
48
|
}
|
|
49
|
+
function personalScope() {
|
|
50
|
+
return String(store.get('currentSlug') || '') + '\u0000' + String(store.get('myUserId') || 'default');
|
|
51
|
+
}
|
|
52
|
+
function ensurePersonalScope() {
|
|
53
|
+
var scope = personalScope();
|
|
54
|
+
if (store.get('githubPersonalReviewScope') !== scope) store.set({ githubPersonalReviewScope: scope, githubPersonalReview: {} });
|
|
55
|
+
return scope;
|
|
56
|
+
}
|
|
57
|
+
function sessionIdentifier(session) {
|
|
58
|
+
return String(session && (session._githubSessionId || session.id || session.localId) || '');
|
|
59
|
+
}
|
|
60
|
+
function personalReviewState(session, link) {
|
|
61
|
+
var scope = ensurePersonalScope();
|
|
62
|
+
var key = scope + '\u0000' + (sessionIdentifier(session) || String(link._githubSessionId || '')) + '\u0000' + String(link.url || '').toLowerCase();
|
|
63
|
+
return (store.get('githubPersonalReview') || {})[key] || link.personalReviewState || '';
|
|
64
|
+
}
|
|
65
|
+
function prReviewStatus(link) {
|
|
66
|
+
if (link.review === 'CHANGES_REQUESTED') return { icon: 'message-square-warning', label: 'Changes requested', className: 'github-review-changes' };
|
|
67
|
+
if (link.personalReviewState === 'requested') return { icon: 'user-round-check', label: 'Review requested from you', className: 'github-review-requested' };
|
|
68
|
+
if (link.review === 'APPROVED') return { icon: 'badge-check', label: 'Approved', className: 'github-review-approved' };
|
|
69
|
+
return null;
|
|
70
|
+
}
|
|
49
71
|
export function githubWorkMarkup(session, detailed, expanded, sessionRow) {
|
|
50
72
|
var links = orderedGithubWork(session);
|
|
51
73
|
if (!links.length) return '';
|
|
@@ -56,13 +78,17 @@ export function githubWorkMarkup(session, detailed, expanded, sessionRow) {
|
|
|
56
78
|
return anchor(link.url, description, LINEAR_MARK + '<span class="linear-work-id">' + escapeHtml(link.identifier) + '</span><span class="linear-work-title">' + escapeHtml(link.title) + '</span><span class="linear-work-state"><span class="linear-work-state-full">' + escapeHtml(link.stateName) + '</span><span class="linear-work-state-compact" aria-hidden="true">' + escapeHtml(compactLinearState(link.stateName)) + '</span></span>', 'session-github-link session-linear-link');
|
|
57
79
|
}
|
|
58
80
|
var state = ['open', 'closed', 'merged', 'draft'].indexOf(link.state) >= 0 ? link.state : 'unknown';
|
|
59
|
-
var
|
|
60
|
-
var
|
|
61
|
-
var
|
|
81
|
+
var reviewLink = Object.assign({}, link, { personalReviewState: personalReviewState(session, link) });
|
|
82
|
+
var reviewStatus = link.kind === 'pr' && state === 'open' ? prReviewStatus(reviewLink) : null;
|
|
83
|
+
var icon = link.kind === 'pr' ? (state === 'merged' ? 'git-merge' : state === 'closed' ? 'git-pull-request-closed' : state === 'draft' ? 'git-pull-request-draft' : reviewStatus ? reviewStatus.icon : 'git-pull-request') : (state === 'closed' ? 'circle-check' : 'circle-dot');
|
|
84
|
+
var statusLabel = reviewStatus ? reviewStatus.label : (state === 'merged' ? 'Merged' : state === 'closed' ? 'Closed' : state === 'draft' ? 'Draft' : state === 'open' ? 'Open' : 'Unknown');
|
|
85
|
+
var description = link.repository + ' · ' + label(link) + ' · ' + link.title + ' · ' + statusLabel + (link.checkedAt ? ' · Checked ' + new Date(link.checkedAt).toLocaleString() : '') + (link.stale ? ' (last known status; refresh unavailable)' : '');
|
|
86
|
+
var statusMarkup = '<span class="github-work-status' + (reviewStatus ? ' ' + reviewStatus.className : '') + '" title="' + escapeHtml(statusLabel) + '" aria-label="' + escapeHtml(statusLabel) + '">' + iconHtml(icon) + '</span>';
|
|
87
|
+
var html = anchor(link.url, description, iconHtml('github', 'github-work-brand') + statusMarkup + '<span><span class="github-work-kind">' + (link.kind === 'pr' ? 'PR ' : 'Issue ') + '</span>#' + escapeHtml(String(link.number)) + '</span>', 'session-github-link github-kind-' + (link.kind === 'pr' ? 'pr' : 'issue') + ' github-state-' + state);
|
|
62
88
|
if (expanded) html = '<span class="github-work-entry">' + html + '<span class="github-work-entry-title">' + escapeHtml(link.title || '') + '</span><span class="github-work-entry-meta">' + escapeHtml(link.repository + ' · ' + state + (link.stale ? ' · Last known status' : '')) + '</span></span>';
|
|
63
89
|
if (detailed && link.kind === 'pr') {
|
|
64
90
|
var actions = anchor(link.url + '/files', 'View PR changes on GitHub', 'Changes', 'github-work-action') +
|
|
65
|
-
anchor(link.url + '#pullrequestreview', 'View PR reviews on GitHub',
|
|
91
|
+
anchor(link.url + '#pullrequestreview', 'View PR reviews on GitHub', 'Reviews', 'github-work-action');
|
|
66
92
|
var checks = '';
|
|
67
93
|
(link.checks || []).forEach(function (check) {
|
|
68
94
|
if (/^https:\/\//i.test(check.url)) checks += anchor(check.url, check.name + ': ' + check.state, '<span class="github-work-check-name">' + escapeHtml(check.name) + '</span><span class="github-work-check-state">' + escapeHtml(check.state.toLowerCase()) + '</span>', 'github-work-action github-work-check');
|
|
@@ -76,6 +102,28 @@ export function githubWorkMarkup(session, detailed, expanded, sessionRow) {
|
|
|
76
102
|
return html;
|
|
77
103
|
}).join('') + (!detailed && !expanded && links.length > displayed.length ? '<button type="button" class="github-work-more" aria-label="Show all ' + links.length + ' linked ' + (links.some(function (item) { return item.provider === 'linear'; }) ? 'work items' : 'GitHub items') + '" aria-haspopup="dialog" aria-expanded="false" data-work-session="' + escapeHtml(String(session.id || session.localId || '')) + '" data-work-primary="' + escapeHtml(JSON.stringify(session.workPrimary || {})) + '" data-github-links="' + escapeHtml(JSON.stringify(safeLinks(session))) + '">+' + (links.length - displayed.length) + '</button>' : '') + '</span>';
|
|
78
104
|
}
|
|
105
|
+
export function applyGithubPersonalReviewStatus(message) {
|
|
106
|
+
var state = store.snap();
|
|
107
|
+
if (!message || (message.projectSlug && message.projectSlug !== state.currentSlug) || (message.accountId && message.accountId !== state.myUserId)) return;
|
|
108
|
+
var refresh = state.githubWorkRefresh || {};
|
|
109
|
+
if (message.requestId && refresh.requestId && message.requestId !== refresh.requestId) return;
|
|
110
|
+
var updates = message.personalReview || {};
|
|
111
|
+
var scope = ensurePersonalScope();
|
|
112
|
+
var personal = Object.assign({}, store.get('githubPersonalReview') || {});
|
|
113
|
+
var sessionId = String(message.sessionId);
|
|
114
|
+
Object.keys(updates).forEach(function (url) {
|
|
115
|
+
var status = updates[url];
|
|
116
|
+
if (status === 'requested' || status === 'clear') personal[scope + '\u0000' + sessionId + '\u0000' + url.toLowerCase()] = status;
|
|
117
|
+
});
|
|
118
|
+
store.set({ githubPersonalReview: personal });
|
|
119
|
+
var sessions = store.get('githubWorkSessions') || [];
|
|
120
|
+
sessions.forEach(function (session) {
|
|
121
|
+
if (String(session.localId) !== sessionId && String(session.id) !== sessionId) return;
|
|
122
|
+
document.querySelectorAll('[data-github-session-id="' + sessionIdentifier(session) + '"] .session-work-links-slot').forEach(function (slot) { slot.innerHTML = githubWorkMarkup(session, false, false, true); });
|
|
123
|
+
});
|
|
124
|
+
syncGithubSessions(sessions);
|
|
125
|
+
refreshIcons();
|
|
126
|
+
}
|
|
79
127
|
export function appendGithubWork(row, session, title) {
|
|
80
128
|
var html = githubWorkMarkup(session, false, false, true);
|
|
81
129
|
bindGithubWorkPopover();
|
|
@@ -94,6 +142,7 @@ export function appendGithubWork(row, session, title) {
|
|
|
94
142
|
}
|
|
95
143
|
export function syncGithubSessions(sessions) {
|
|
96
144
|
bindGithubWorkPopover();
|
|
145
|
+
ensurePersonalScope();
|
|
97
146
|
store.set({ githubWorkSessions: sessions || [], githubWorkProject: store.get('currentSlug') });
|
|
98
147
|
var active = (sessions || []).find(function (session) { return session.active; });
|
|
99
148
|
var title = document.getElementById('header-title');
|
|
@@ -132,15 +181,16 @@ export function refreshGithubWork() {
|
|
|
132
181
|
if (previous.key === key && Date.now() - previous.at < 60000) return;
|
|
133
182
|
var ws = getWs();
|
|
134
183
|
if (!ws || ws.readyState !== 1) return;
|
|
135
|
-
|
|
136
|
-
|
|
184
|
+
var requestId = 'github-refresh-' + Date.now() + '-' + Math.random().toString(36).slice(2);
|
|
185
|
+
store.set({ githubWorkRefresh: { key: key, at: Date.now(), requestId: requestId } });
|
|
186
|
+
ws.send(JSON.stringify({ type: 'session_github_refresh', sessionIds: ids, requestId: requestId, projectSlug: store.get('currentSlug'), accountId: store.get('myUserId') || null }));
|
|
137
187
|
var linearIds = ids.filter(function (id) { return (store.get('githubWorkSessions') || []).some(function (item) { return item.id === id && (item.linearLinks || []).length; }); });
|
|
138
188
|
if (linearIds.length) ws.send(JSON.stringify({ type: 'session_linear_refresh', sessionIds: linearIds }));
|
|
139
189
|
}
|
|
140
190
|
|
|
141
191
|
export function resetGithubWork() {
|
|
142
192
|
closeGithubWorkPopover();
|
|
143
|
-
store.set({ githubWorkSessions: [], githubWorkProject: null, githubWorkRefresh: null, workPrimaryPending: null });
|
|
193
|
+
store.set({ githubWorkSessions: [], githubWorkProject: null, githubWorkRefresh: null, githubPersonalReview: {}, workPrimaryPending: null });
|
|
144
194
|
var header = document.getElementById('header-github-links');
|
|
145
195
|
if (header) header.remove();
|
|
146
196
|
}
|
|
@@ -218,7 +268,8 @@ function bindGithubWorkPopover() {
|
|
|
218
268
|
popup.dataset.sessionId = button.dataset.workSession || '';
|
|
219
269
|
var primary;
|
|
220
270
|
try { primary = JSON.parse(button.dataset.workPrimary || '{}'); } catch (error) { primary = {}; }
|
|
221
|
-
|
|
271
|
+
var popupLinks = links.map(function (link) { return Object.assign({}, link, { _githubSessionId: popup.dataset.sessionId }); });
|
|
272
|
+
popup.innerHTML = '<strong>' + workTitle + '</strong>' + primaryWorkPopover(popupLinks, primary, popup.dataset.sessionId, githubWorkMarkup);
|
|
222
273
|
document.body.appendChild(popup);
|
|
223
274
|
mountGithubWorkPopover(popup, button);
|
|
224
275
|
button.setAttribute('aria-expanded', 'true');
|
|
@@ -238,3 +289,9 @@ function bindGithubWorkPopover() {
|
|
|
238
289
|
if (state.currentSlug !== previous.currentSlug || state.activeSessionId !== previous.activeSessionId || state.dmMode !== previous.dmMode) closeGithubWorkPopover();
|
|
239
290
|
});
|
|
240
291
|
}
|
|
292
|
+
store.subscribe(function (state, previous) {
|
|
293
|
+
if (state.currentSlug !== previous.currentSlug || state.myUserId !== previous.myUserId) {
|
|
294
|
+
var scope = personalScope();
|
|
295
|
+
if (state.githubPersonalReviewScope !== scope) store.set({ githubPersonalReviewScope: scope, githubPersonalReview: {} });
|
|
296
|
+
}
|
|
297
|
+
});
|
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
// Used by both server-settings.js and project-settings.js
|
|
3
3
|
|
|
4
4
|
export var MODE_OPTIONS = [
|
|
5
|
-
{ value: "default", label: "Default", desc: "
|
|
6
|
-
{ value: "plan", label: "Plan", desc: "
|
|
7
|
-
{ value: "acceptEdits", label: "Auto-accept edits", desc: "File edits are applied automatically.
|
|
5
|
+
{ value: "default", label: "Default", desc: "The agent asks for permission before running tools and editing files." },
|
|
6
|
+
{ value: "plan", label: "Plan", desc: "The agent creates a plan first and asks for approval before making changes." },
|
|
7
|
+
{ value: "acceptEdits", label: "Auto-accept edits", desc: "File edits are applied automatically. The agent still asks before running commands." },
|
|
8
8
|
];
|
|
9
9
|
|
|
10
10
|
export var EFFORT_LEVELS = [
|
|
@@ -16,29 +16,17 @@ export var EFFORT_LEVELS = [
|
|
|
16
16
|
|
|
17
17
|
export var THINKING_OPTIONS = [
|
|
18
18
|
{ value: "disabled", label: "Off", desc: "Disable extended thinking." },
|
|
19
|
-
{ value: "adaptive", label: "Adaptive", desc: "
|
|
19
|
+
{ value: "adaptive", label: "Adaptive", desc: "The agent decides when to use extended thinking." },
|
|
20
20
|
{ value: "budget", label: "Budget", desc: "Set a token budget for extended thinking." },
|
|
21
21
|
];
|
|
22
22
|
|
|
23
|
-
export var MODEL_DESCRIPTIONS = {
|
|
24
|
-
"default": "Automatically selects the best model for the task.",
|
|
25
|
-
"sonnet": "Fast and capable. Great balance of speed and intelligence.",
|
|
26
|
-
"haiku": "Fastest model. Best for quick tasks and simple questions.",
|
|
27
|
-
"opus": "Most powerful model. Best for complex reasoning and analysis.",
|
|
28
|
-
};
|
|
29
|
-
|
|
30
23
|
export function getModelDesc(model) {
|
|
31
|
-
|
|
32
|
-
var lower = (model.value || model).toLowerCase();
|
|
33
|
-
for (var key in MODEL_DESCRIPTIONS) {
|
|
34
|
-
if (lower.indexOf(key) !== -1) return MODEL_DESCRIPTIONS[key];
|
|
35
|
-
}
|
|
36
|
-
return "";
|
|
24
|
+
return model && typeof model === "object" && typeof model.description === "string" ? model.description : "";
|
|
37
25
|
}
|
|
38
26
|
|
|
27
|
+
// Compatibility name for the retired beta control; model metadata owns support.
|
|
39
28
|
export function isSonnetModel(model) {
|
|
40
|
-
|
|
41
|
-
return model.toLowerCase().indexOf("sonnet") !== -1;
|
|
29
|
+
return !!(model && typeof model === "object" && model.supportsBetaContext === true);
|
|
42
30
|
}
|
|
43
31
|
|
|
44
32
|
// --- Render functions ---
|
|
@@ -75,7 +63,7 @@ export function renderModelList(prefix, opts) {
|
|
|
75
63
|
nameSpan.textContent = label;
|
|
76
64
|
item.appendChild(nameSpan);
|
|
77
65
|
|
|
78
|
-
var desc = getModelDesc(
|
|
66
|
+
var desc = getModelDesc(m);
|
|
79
67
|
if (desc) {
|
|
80
68
|
var descSpan = document.createElement("span");
|
|
81
69
|
descSpan.className = "settings-model-desc";
|
|
@@ -106,7 +94,9 @@ export function renderModeList(prefix, opts) {
|
|
|
106
94
|
var currentMode = opts.currentMode || "default";
|
|
107
95
|
listEl.innerHTML = "";
|
|
108
96
|
|
|
109
|
-
|
|
97
|
+
var modes = (opts.configuration || {}).permissionModes || [];
|
|
98
|
+
if (listEl.parentElement) listEl.parentElement.style.display = modes.length ? "" : "none";
|
|
99
|
+
for (var i = 0; i < modes.length; i++) {
|
|
110
100
|
(function (opt) {
|
|
111
101
|
var item = document.createElement("div");
|
|
112
102
|
item.className = "settings-model-item" + (opt.value === currentMode ? " active" : "");
|
|
@@ -129,7 +119,7 @@ export function renderModeList(prefix, opts) {
|
|
|
129
119
|
});
|
|
130
120
|
|
|
131
121
|
listEl.appendChild(item);
|
|
132
|
-
})(
|
|
122
|
+
})(modes[i]);
|
|
133
123
|
}
|
|
134
124
|
}
|
|
135
125
|
|
|
@@ -143,7 +133,12 @@ export function renderEffortBar(prefix, opts) {
|
|
|
143
133
|
var currentEffort = opts.currentEffort || "medium";
|
|
144
134
|
bar.innerHTML = "";
|
|
145
135
|
|
|
146
|
-
|
|
136
|
+
var levels = opts.effortLevels || [];
|
|
137
|
+
var model = (opts.models || []).find(function (item) { return item.value === opts.currentModel; });
|
|
138
|
+
if (model && model.supportsEffort === false) levels = [];
|
|
139
|
+
else if (model && Array.isArray(model.supportedEffortLevels)) levels = model.supportedEffortLevels;
|
|
140
|
+
if (bar.parentElement) bar.parentElement.style.display = levels.length ? "" : "none";
|
|
141
|
+
for (var i = 0; i < levels.length; i++) {
|
|
147
142
|
(function (lvl) {
|
|
148
143
|
var btn = document.createElement("button");
|
|
149
144
|
btn.className = "settings-btn-option" + (lvl.value === currentEffort ? " active" : "");
|
|
@@ -156,7 +151,7 @@ export function renderEffortBar(prefix, opts) {
|
|
|
156
151
|
btn.classList.add("active");
|
|
157
152
|
});
|
|
158
153
|
bar.appendChild(btn);
|
|
159
|
-
})(EFFORT_LEVELS[i]);
|
|
154
|
+
})({ value: levels[i], desc: (EFFORT_LEVELS.find(function (item) { return item.value === levels[i]; }) || {}).desc || "" });
|
|
160
155
|
}
|
|
161
156
|
}
|
|
162
157
|
|
|
@@ -173,7 +168,10 @@ export function renderThinkingBar(prefix, opts) {
|
|
|
173
168
|
var budgetInput = document.getElementById(prefix + "-thinking-budget");
|
|
174
169
|
bar.innerHTML = "";
|
|
175
170
|
|
|
176
|
-
|
|
171
|
+
var thinking = (opts.configuration || {}).thinking;
|
|
172
|
+
if (bar.parentElement) bar.parentElement.style.display = thinking ? "" : "none";
|
|
173
|
+
var thinkingOptions = thinking ? THINKING_OPTIONS.filter(function(opt) { return thinking.options.indexOf(opt.value) >= 0; }) : [];
|
|
174
|
+
for (var i = 0; i < thinkingOptions.length; i++) {
|
|
177
175
|
(function (opt) {
|
|
178
176
|
var btn = document.createElement("button");
|
|
179
177
|
btn.className = "settings-btn-option" + (opt.value === currentThinking ? " active" : "");
|
|
@@ -191,10 +189,10 @@ export function renderThinkingBar(prefix, opts) {
|
|
|
191
189
|
if (budgetRow) budgetRow.style.display = opt.value === "budget" ? "" : "none";
|
|
192
190
|
});
|
|
193
191
|
bar.appendChild(btn);
|
|
194
|
-
})(
|
|
192
|
+
})(thinkingOptions[i]);
|
|
195
193
|
}
|
|
196
194
|
|
|
197
|
-
if (budgetRow) budgetRow.style.display = currentThinking === "budget" ? "" : "none";
|
|
195
|
+
if (budgetRow) budgetRow.style.display = thinking && currentThinking === "budget" ? "" : "none";
|
|
198
196
|
if (budgetInput) {
|
|
199
197
|
budgetInput.value = currentBudget;
|
|
200
198
|
budgetInput.addEventListener("change", function () {
|
|
@@ -212,7 +210,8 @@ export function renderBetaCard(prefix, opts) {
|
|
|
212
210
|
var model = opts.overrideModel || opts.currentModel || "";
|
|
213
211
|
var card = document.getElementById(prefix + "-beta-card");
|
|
214
212
|
if (card) {
|
|
215
|
-
|
|
213
|
+
var descriptor = (opts.models || []).find(function(item) { return item.value === model; });
|
|
214
|
+
card.style.display = isSonnetModel(descriptor) ? "" : "none";
|
|
216
215
|
}
|
|
217
216
|
|
|
218
217
|
var toggle = document.getElementById(prefix + "-beta-1m");
|
|
@@ -353,7 +353,7 @@ function renderSection(section, ctx, kind) {
|
|
|
353
353
|
body.appendChild(empty);
|
|
354
354
|
}
|
|
355
355
|
var view = currentFolderState().view;
|
|
356
|
-
var dateGroups = isFavorites ? null : groupUnitsByDate(section.units, view.sort, view.direction);
|
|
356
|
+
var dateGroups = isFavorites || view.showDateHeadings === false ? null : groupUnitsByDate(section.units, view.sort, view.direction);
|
|
357
357
|
if (dateGroups) {
|
|
358
358
|
for (var g = 0; g < dateGroups.length; g++) {
|
|
359
359
|
var ids = groupRootSessionIds(dateGroups[g].units);
|
|
@@ -6,7 +6,32 @@ export function getTitle(text) {
|
|
|
6
6
|
return idx === -1 ? text : text.substring(0, idx);
|
|
7
7
|
}
|
|
8
8
|
|
|
9
|
-
function
|
|
9
|
+
function checklistFence(line) {
|
|
10
|
+
var match = line.match(/^\s*(\x60{3,}|~{3,})/);
|
|
11
|
+
return match ? match[1].charAt(0) : null;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export function getChecklistItems(text) {
|
|
15
|
+
var lines = (text || "").split("\n").slice(1);
|
|
16
|
+
var items = [];
|
|
17
|
+
var fence = null;
|
|
18
|
+
var occurrences = Object.create(null);
|
|
19
|
+
for (var i = 0; i < lines.length; i++) {
|
|
20
|
+
var line = lines[i];
|
|
21
|
+
var nextFence = checklistFence(line);
|
|
22
|
+
if (nextFence) {
|
|
23
|
+
fence = fence === nextFence ? null : (fence || nextFence);
|
|
24
|
+
continue;
|
|
25
|
+
}
|
|
26
|
+
if (fence || !line.trim() || /^\s*#{1,6}\s/.test(line)) continue;
|
|
27
|
+
var occurrence = occurrences[line] || 0;
|
|
28
|
+
occurrences[line] = occurrence + 1;
|
|
29
|
+
items.push({ index: i, text: line, key: line + "\u0000" + occurrence });
|
|
30
|
+
}
|
|
31
|
+
return items;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function formatInline(text, preserveChecks) {
|
|
10
35
|
var escaped = text
|
|
11
36
|
.replace(/&/g, "&")
|
|
12
37
|
.replace(/</g, "<")
|
|
@@ -17,18 +42,59 @@ function formatInline(text) {
|
|
|
17
42
|
.replace(/(?<!\*)\*(?!\*)(.+?)(?<!\*)\*(?!\*)/g, "<em>$1</em>")
|
|
18
43
|
.replace(/`([^`]+)`/g, "<code>$1</code>")
|
|
19
44
|
.replace(/~~(.+?)~~/g, "<del>$1</del>")
|
|
20
|
-
.replace(/^(?:-\s*)?\[[xX]\]/gm, '<span class="sn-check checked" role="checkbox" aria-checked="true" tabindex="0" contenteditable="false">✓</span>')
|
|
21
|
-
.replace(/^(?:-\s*)?\[ \]/gm, '<span class="sn-check" role="checkbox" aria-checked="false" tabindex="0" contenteditable="false">☐</span>')
|
|
45
|
+
.replace(preserveChecks ? /(?!x)x^/ : /^(?:-\s*)?\[[xX]\]/gm, '<span class="sn-check checked" role="checkbox" aria-checked="true" tabindex="0" contenteditable="false">✓</span>')
|
|
46
|
+
.replace(preserveChecks ? /(?!x)x^/ : /^(?:-\s*)?\[ \]/gm, '<span class="sn-check" role="checkbox" aria-checked="false" tabindex="0" contenteditable="false">☐</span>')
|
|
22
47
|
.replace(/\n/g, "<br>");
|
|
23
48
|
}
|
|
24
49
|
|
|
25
|
-
export function renderMiniMarkdown(text) {
|
|
50
|
+
export function renderMiniMarkdown(text, options) {
|
|
26
51
|
if (!text) return "";
|
|
52
|
+
options = options || {};
|
|
27
53
|
var lines = text.split("\n");
|
|
28
54
|
var title = lines[0];
|
|
29
55
|
var body = lines.slice(1).join("\n");
|
|
30
|
-
var html = '<div class="sn-title">' + formatInline(title) + "</div>";
|
|
31
|
-
if (body.trim())
|
|
56
|
+
var html = '<div class="sn-title">' + formatInline(title, options.checklistMode) + "</div>";
|
|
57
|
+
if (body.trim()) {
|
|
58
|
+
if (options.checklistMode) {
|
|
59
|
+
var checklistLines = body.split("\n");
|
|
60
|
+
var checklistHtml = [];
|
|
61
|
+
var inCode = false;
|
|
62
|
+
var fenceChar = null;
|
|
63
|
+
var occurrences = Object.create(null);
|
|
64
|
+
for (var i = 0; i < checklistLines.length; i++) {
|
|
65
|
+
var line = checklistLines[i];
|
|
66
|
+
var lineFence = checklistFence(line);
|
|
67
|
+
if (lineFence) {
|
|
68
|
+
fenceChar = fenceChar === lineFence ? null : (fenceChar || lineFence);
|
|
69
|
+
inCode = !!fenceChar;
|
|
70
|
+
checklistHtml.push(formatInline(line, true));
|
|
71
|
+
if (i < checklistLines.length - 1) checklistHtml.push("<br>");
|
|
72
|
+
continue;
|
|
73
|
+
}
|
|
74
|
+
var task = !inCode && line.trim() && !/^\s*#{1,6}\s/.test(line);
|
|
75
|
+
if (task) {
|
|
76
|
+
var markerMatch = line.match(/^\s*(?:[-*+]\s+)?\[([ xX])\]\s*(.*)$/);
|
|
77
|
+
var checked = markerMatch ? markerMatch[1].toLowerCase() === "x" : false;
|
|
78
|
+
var content = markerMatch ? markerMatch[2] : line;
|
|
79
|
+
var occurrence = occurrences[line] || 0;
|
|
80
|
+
occurrences[line] = occurrence + 1;
|
|
81
|
+
var checklistKey = line + "\u0000" + occurrence;
|
|
82
|
+
var stored = options.checklistState && options.checklistState[checklistKey];
|
|
83
|
+
if (stored === undefined && Array.isArray(options.checklistState)) stored = options.checklistState[i];
|
|
84
|
+
if (stored !== undefined) {
|
|
85
|
+
checked = stored === true;
|
|
86
|
+
}
|
|
87
|
+
checklistHtml.push('<span class="sn-check' + (checked ? ' checked' : '') + '" data-checklist-index="' + i + '" data-checklist-key="' + encodeURIComponent(checklistKey) + '" role="checkbox" aria-checked="' + (checked ? 'true' : 'false') + '" tabindex="0" contenteditable="false">' + (checked ? "✓" : "☐") + "</span>" + formatInline(content));
|
|
88
|
+
} else {
|
|
89
|
+
checklistHtml.push(formatInline(line, !!inCode));
|
|
90
|
+
}
|
|
91
|
+
if (i < checklistLines.length - 1) checklistHtml.push("<br>");
|
|
92
|
+
}
|
|
93
|
+
html += checklistHtml.join("");
|
|
94
|
+
} else {
|
|
95
|
+
html += formatInline(body);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
32
98
|
return html;
|
|
33
99
|
}
|
|
34
100
|
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { getNoteUiState, clearNoteTextTimer, setNoteUiState } from './sticky-notes-shared.js';
|
|
2
|
+
import { checklistDraftText } from './sticky-notes-checklist.js';
|
|
3
|
+
import { mutateChecklist } from './sticky-notes-state.js';
|
|
4
|
+
import { confirmSettingsAction } from './server-settings-state.js';
|
|
5
|
+
|
|
6
|
+
export function requestChecklistMode(id) {
|
|
7
|
+
var ui = getNoteUiState(id);
|
|
8
|
+
if (ui.pending.length) return;
|
|
9
|
+
if (ui.checklistMode) { mutateChecklist(id, { checklistMode: false }); return; }
|
|
10
|
+
var text = ui.text;
|
|
11
|
+
var canonical = ui.canonical;
|
|
12
|
+
function convert() {
|
|
13
|
+
var current = getNoteUiState(id);
|
|
14
|
+
if (current.text !== text || current.canonical.text !== canonical.text || current.canonical.updatedAt !== canonical.updatedAt) {
|
|
15
|
+
setNoteUiState(id, { error: 'The note changed. Review its contents and try again.' }); return;
|
|
16
|
+
}
|
|
17
|
+
clearNoteTextTimer(id);
|
|
18
|
+
mutateChecklist(id, { checklistConvert: true, checklistSource: canonical.text, checklistVersion: canonical.updatedAt });
|
|
19
|
+
}
|
|
20
|
+
if (text.trim() || (canonical.text || '').trim()) {
|
|
21
|
+
confirmSettingsAction('Switching to a checklist will delete all existing contents and completion marks. Continue with an empty checklist?', 'Delete contents and create checklist', convert);
|
|
22
|
+
} else convert();
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export function closeHumanNote(id, fallback) {
|
|
26
|
+
var ui = getNoteUiState(id, fallback);
|
|
27
|
+
if (ui.pending.length) { setNoteUiState(id, { error: 'Wait for the current save before closing.' }); return; }
|
|
28
|
+
clearNoteTextTimer(id);
|
|
29
|
+
mutateChecklist(id, { humanClose: true, expectedText: ui.canonical.text, expectedVersion: ui.canonical.updatedAt, draftText: ui.checklistMode ? checklistDraftText(ui) : ui.text });
|
|
30
|
+
}
|