micro-models-agent 2.28.0 → 2.29.1

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/CHANGELOG.md CHANGED
@@ -4,6 +4,80 @@ All notable changes to Micro Models Agent (MMA) will be documented in this file.
4
4
 
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/), and this project adheres to [Semantic Versioning](https://semver.org/).
6
6
 
7
+ ## [2.29.1] - 2026-10-07
8
+
9
+ Agent-written capability drafts (`define_capability`) are now quality-gated and
10
+ tidy: the handler body is syntax-checked before it is written, a load failure is
11
+ reported back to the model with the real error (and the broken file is discarded),
12
+ and the generated file is normalized instead of dumped verbatim.
13
+
14
+ ### Added
15
+
16
+ - **Draft syntax check** (`src/modules/plugins/drafts.ts`): `validateDraftCode` parses the handler body via `Bun.Transpiler` (no execution; skipped outside Bun); `validateDraftSpec` rejects a broken body before anything is written to disk.
17
+ - **Load-failure feedback** (`src/tools/define-capability.ts`, `src/modules/plugins/draft-host.ts`): after approval, if the draft fails to load, the tool returns `success:false` with the loader's error message (`draft.capability_load_failed`), discards the broken file, and hints the model to fix and retry. `DraftHost.lastError(name)` exposes the reason.
18
+ - **Cleaner generated files** (`normalizeDraftCode`, `renderDraft`): CRLF→LF, common-indent removal, blank-line collapse, trailing-whitespace trim, final newline, and 2-space indenting of the handler body.
19
+ - **Richer tool contract** (`define_capability` description): the handler returns `{ output, success? }`; `ctx`/`args` fields; no imports or top-level code; syntax-check and load-rollback behavior.
20
+
21
+ ### Changed
22
+
23
+ - **`mma plugins drafts approve`** (`src/cli/plugin-commands.ts`): on load failures prints each reason, not just the count.
24
+
25
+ ## [2.29.0] - 2026-10-07
26
+
27
+ The plugin system stops being "an anonymous object in an array": a plugin is now a
28
+ registered entity with author, version, description, declared permissions and a
29
+ visible on/off switch. `mma web` gets a **Plugins** sidebar tab with live toggles
30
+ and a details popup; a plugin that fails to load is now visible instead of
31
+ silently missing.
32
+
33
+ ### Added
34
+
35
+ - **Agent-written capability drafts** (`src/modules/plugins/drafts.ts`, `draft-host.ts`, `src/tools/define-capability.ts`): the `define_capability` tool writes a capability into `.mma/plugins/drafts/<name>.ts` and asks the user for permission with the full code shown. A draft is **inert until approved** - the catalog is not read at all without a marker (`.mma/plugins/.drafts-approved`, project-scoped and outside the catalog so the plugin scan never sees it). After approval the capability is registered live (`plugin__<name>__<name>` tool, `plugin:<name>` tag), and it reaches already-open `mma web` sessions. Declared `permissions` are required - an empty declaration would make the consent prompt a lie. `plugins.maxDrafts` (default 10) caps the drafts per project with LRU eviction; `mma plugins drafts [approve|revoke]` and a startup warning cover the pending state.
36
+ - **`[PLUGIN CAPABILITIES]` prompt block** (`src/modules/plugins/capabilities-block.ts`): lists the tools installed plugins contributed and states that `define_capability` exists. Omitted when the tool set is narrowed by an allowlist (onboarding), where the tool is unavailable anyway.
37
+ - **Plugin tools** (`src/modules/plugins/tools.ts`, `AgentPlugin.getToolDefinitions()`): a plugin can add its own tools to the harness. Definitions enter the registry under `plugin__<plugin>__<tool>` (same convention as `mcp__<server>__<tool>`), get a `plugin:<name>` tag and `alwaysOn: true` by default so `enable_tools` cannot hide them; the core fills `provides.tools`, which the sidebar popup, `mma plugins list` and `mma plugins show` already read. Toggling a plugin with tools resets the provider prompt cache - the details popup says so instead of hiding it.
38
+ - **Live plugin reload** (`src/modules/plugins/reload.ts`, `manager.ts`, `loader.ts`): edits to a plugin file are picked up without restarting the process - unload (`onUnload`), drop the `require` cache, read again. Available as `mma plugins reload`, `/plugins reload`, `POST /api/reload/plugins`, and a "reload plugins" button in Settings > Plugins. Skills reload the same way, so a skill written at runtime is loadable in the same turn.
39
+ - **`onUnload` hook** on `AgentPlugin`: release servers, timers and sockets when a plugin goes away. Without it a reload leaks - `examples/plugins/web-ui` starts an HTTP server in `onSessionStart`, and copies used to accumulate across `/reload`.
40
+ - **`PluginManager` owns its source catalogs** (`setSourceDirs`, set at bootstrap): CLI, REPL and the web all call `reload()` and none of them knows the paths. `/reload` unloads the old plugins and clears the cache before rebuilding bootstrap, so nothing outlives it.
41
+ - **`ToolRegistry.upsert` / `ToolRegistry.unregister`** (`src/tools/registry.ts`): for tool sets owned by an external source and changed at runtime. `register` still throws on a duplicate - a core duplicate is a startup bug.
42
+
43
+ ### Fixed
44
+
45
+ - **Plugin reload never reached an already-running web session**: `reload` replaced the plugin in the main manager only, so a session runner kept the old instance - its hooks and its tools stayed on the pre-edit code until the process restarted. The main manager now broadcasts the new instance (and removals) to managers sharing its gate; a manager that adopted someone else's gate never broadcasts, so a runner's own execution plugin cannot leak into the main agent.
46
+ - **A cloned registry looked like a name collision**: `buildRunnerRegistry` copies definitions into a session registry, and the copy carried no ownership record, so the plugin's contribution was rejected as "name already taken by the harness" - the stale copy kept serving calls and reload could not update it. Ownership is now read from the `plugin:<name>` tag, which survives cloning; it also lets a disabled plugin's tools be cleaned out of a session registry.
47
+ - **A plugin tool without `success` looked failed**: `ToolResult.success` is required, and plugins are usually plain JS, so `{output}` produced an apparently failed tool card and no `success` in the log. The plugin handler result is normalized (missing `success` means success, non-string `output` is stringified), and a definition without `handler` is rejected at registration with a readable warning instead of failing at call time with `tool.handler is not a function`.
48
+ - **Light theme rendered every toggle as off**: `body.light .toggle` outranked `.toggle.on` on specificity, so enabled toggles showed the disabled colour app-wide (settings included).
49
+ - **Plugin code edits were ignored until a process restart**: `/reload` rebuilt bootstrap but nothing invalidated the `require` cache. Verified experimentally before fixing: cache invalidation works under Bun for `.ts` and `.js`, but under Node only for `.js` (Node caches transpiled `.ts` separately). Such files are counted in `ReloadReport.staleTs` and the UI/CLI say a restart is needed rather than reporting a reload that did not change anything.
50
+ - **A deleted plugin file left the plugin registered**: reloading a catalog now drops plugins whose file disappeared.
51
+
52
+ ### Changed
53
+
54
+ - **Plugin metadata** (`src/modules/types.ts`, `src/modules/plugins/records.ts`): optional `description`, `author`, `homepage`, `permissions`, `provides` on `AgentPlugin`. All optional on purpose - missing metadata is a warning, never a load error, so the 8-line plugin and both `examples/plugins` keep working. Hard validation only on `name`.
55
+ - **`PluginRecord` read model** (`records.ts`): the single source for CLI, REPL and web. `PluginManager.getRecords()` (cached, invalidated on any change) plus `getFailures()` returning `PluginLoadFailure[]` - a plugin that throws on import was previously indistinguishable from a missing one.
56
+ - **Live enable/disable** (`config.plugins.disabled`, new `plugins.json` domain): `mma plugins enable|disable <name>`, `/plugins enable|disable <name>`, `POST /api/plugins/:name {enabled}`, and a toggle per row in the sidebar tab and the settings panel. No restart, no `reconfigure`. All paths write through `setConfigValue`, so they cannot drift.
57
+ - **Plugins sidebar tab** (`assets/js/sidebar/plugins.ts`, `Alt+6`): row list with glyph/name/version/author, a live toggle, one dim description line, and load failures as their own rows. Details open in the existing nested `#subOverlay` (same pattern as the LSP info dialog) - description, author, version, homepage, absolute path with copy, provided tools/hooks as chips, declared permissions with an explicit "declaration, not enforcement" note, and metadata warnings.
58
+ - **Plugin SDK exports** (`src/index.ts`): `AgentPlugin`, `HostBridge`, `HostBridgeSubmitOptions`, `TurnSummary`, `PluginRecord`, `PLUGIN_PERMISSIONS` are now exported from the package root; third-party plugins no longer have to duck-type the contract.
59
+ - **`mma plugins show <name>` / `/plugins show <name>`**: per-plugin details in the terminal, same content as the web popup.
60
+ - **CLI/REPL listing rewrite**: both share one formatter (`src/modules/plugins/format.ts`) and now show author, permissions, description and load failures.
61
+ - **`GET /api/plugins`** (`webui/settings/settings-api.ts`): returns `{plugins: PluginRecord[], failures, mcp}`. `enabled` is the real flag instead of a hardcoded `true`; every other field is additive.
62
+ - **`WebPluginManager`** (`webui/state.ts`): widened to `getRecords`/`getFailures`/`setEnabled`/`reload`; `PluginManager` satisfies it structurally. The redundant narrow `WebPluginInfo` view is gone.
63
+ - **`PluginLoader.loadFromDir`** returns `LoadReport {loaded, skipped, failed}` instead of `void` and stamps `plugin.path` on each plugin.
64
+ - **`subdialog.ts`** resolves its overlay nodes lazily instead of at import time; an import-time capture silently no-ops when the overlay is not in the DOM yet.
65
+ - **Sidebar tab icons**: `map`/`stethoscope`/`puzzle` were too dense to read at 17px and are replaced with `layout-grid`/`code`/`plug`.
66
+ - **`POST /api/reload/plugins`** is a separate action namespace, not `POST /api/plugins/reload` - `reload` is a legal plugin name, and exact-first matching would have made such a plugin impossible to toggle.
67
+ - **Internals**: `PluginManager` was over the 300-line rule at 316; hook dispatching moved to `src/modules/plugins/dispatch.ts`.
68
+ - **Plugin tool contribution and per-session registry clones** (`attachToolRegistry` / `detachToolRegistry` / `shareGateWith`): the manager owns the set of tool registries it feeds (main plus one per live web session), and per-session plugin managers share the **deny-list object** with the main one. Before this, a web toggle only affected the main agent - hooks and (now) tools of a disabled plugin kept running in session runners. The deny-list is mutated in place (replacing the object would leave runners on the old set), `getRecords()` is validated against the shared `gate.version`, and stopping a runner calls `dispose()` so the manager does not keep a dead registry and keep writing tools into it.
69
+ - **A plugin tool set is all-or-nothing**: a name already taken by the harness or another plugin, a malformed definition, a duplicate name after sanitization, or a `getToolDefinitions()` that throws rejects the plugin's **whole** contribution (logged as a warning, shown by `mma plugins show <name>` / `/plugins show`). A half-installed tool set is worse than none - the model would see one of three tools and could not tell why the others were missing. Hooks stay live.
70
+
71
+ ### Removed
72
+
73
+ - **`sessionIsolation.isolatePlugins`**: declared in the config type, defaults and `/config` registry, but read nowhere in `src/`. Dead switch removed so the registry has one enable/disable mechanism. No behaviour change.
74
+
75
+ ### Known limits (documented, not fixed)
76
+
77
+ - **Draft approval does not cross processes.** The approval is a marker file, the loaded code lives in process memory: `mma plugins drafts revoke` from a terminal unloads the drafts in *that* process, and a running `mma web` only notices on restart or `POST /api/reload/plugins` (same in the other direction). Inside one process (the `define_capability` tool, the Plugins tab) it is live. Verified in a live run.
78
+ - Disabling a plugin stops its hooks and tool contributions but does **not** undo the module import that already ran, and `permissions` is a declaration shown to the user rather than enforcement. Real isolation and code trust remain open work (see `docs/specs/2026-09-28-production-readiness-design.md`, P1).
79
+ - Approving a draft is still a decision, not a boundary: the code runs in the agent process with the harness's own reach (fs, network, `bash`). Real isolation and code trust remain open work (see `docs/specs/2026-09-28-production-readiness-design.md`, P1).
80
+
7
81
  ## [2.28.0] - 2026-10-07
8
82
 
9
83
  Tool-produced images (browser screenshots, `attach_image`) are now visible in the
@@ -1 +1 @@
1
- import{msgs as D,inp as g,connStatus as L,setIcon as x,icon as T}from"./js/dom.js";import{api as z,token as A}from"./js/api.js";import{I18N as J,t as i,loadI18n as Q}from"./js/i18n.js";import{tabs as l,session as f,settings as u,hooks as C}from"./js/store.js";import{routeState as X,mergeUsage as G,storeSnapshot as k,applyCounters as R}from"./js/state-sync.js";import{onText as K,onReasoning as V,onMeta as Y,onPhase as Z,onToolStart as $,onToolEnd as ee,onTurnEnd as te,onErrorEvent as se,onCommandOutput as ne,onLog as oe,onPlan as ae,onQuestion as ie,onRetract as re,showEmptyFeed as w,renderPlan as de,renderUsage as _,renderEnvironment as ce,renderWorkspace as le,feedHasContent as fe,loadHistory as ue}from"./js/feed.js";import{openTab as P,updateTabName as pe,renderSessionsDropdown as h,reflectBusy as be,loadSessions as q,loadCommands as me,setTabStatus as p,reconcileTabStatuses as ge}from"./js/session/tabs.js";import{renderSelectors as S,renderSettings as we,loadConfig as he,loadModels as Se,loadProviders as ve,loadMemory as ye,loadSkills as Ie,loadPlugins as Ee,applyTheme as Le,currentTheme as xe,applyFontSize as Te,setConnStatus as v,setStaleBar as B}from"./js/settings.js";import{initRail as Ae,setPlan as N,railEvent as Ce,applyRailI18n as ke}from"./js/rail.js";import{initSidebar as Re,sidebarSessionChanged as _e,sidebarMapState as Pe,sidebarTraceEvent as y,sidebarTurnEnd as qe,sidebarBusy as M,sidebarMapIndicator as Be,sidebarPullLog as Ne,sidebarSessionId as Me,setSessionLoading as He,sidebarLspState as Ue,sidebarLspEvent as Fe,applySidebarI18n as H,initFiles as We,sidebarFilesState as Oe,sidebarFilesChanged as U}from"./js/sidebar.js";import{insertIntoDraft as je}from"./js/session/composer.js";document.querySelectorAll("[data-collapse]").forEach(s=>{const e=s.querySelector(".arrow");e&&(e.textContent="",e.appendChild(T("chevron-down"))),s.addEventListener("click",()=>{const o=s.nextElementSibling;if(!o)return;const a=o.classList.toggle("collapsed");s.setAttribute("aria-expanded",a?"false":"true");const r=s.querySelector(".arrow");r&&(r.textContent="",r.appendChild(T(a?"chevron-right":"chevron-down")))})});const b=document.getElementById("toggleSidebar");b&&(b.addEventListener("click",()=>{const s=document.body.classList.toggle("sb-open");b.setAttribute("aria-expanded",s?"true":"false")}),document.addEventListener("keydown",s=>{if(s.key!=="Escape"||!document.body.classList.contains("sb-open"))return;const e=document.activeElement?String(document.activeElement.tagName):"";e==="TEXTAREA"||e==="INPUT"||(document.body.classList.remove("sb-open"),b.setAttribute("aria-expanded","false"))}));let I=-1;function m(){const s=l.tabs.find(r=>r.id===l.activeTabId)||null,e=s&&s.state||{};f.host=e;const o=e.sessionId||s&&s.id||null;f.activeSessionId=o,l.tabs.length||w(),de(e.plan),N(f.busy&&e?e.plan:null),_(e),typeof e.contextWindow=="number"&&u.config&&u.config.contextWindow!==e.contextWindow&&(u.config.contextWindow=e.contextWindow,S()),ce(e),Pe(e),Be(e),Ue(),Oe(e);const a=typeof e.filesRevision=="number"?e.filesRevision:void 0;if(a!==void 0&&a!==I){const r=I===-1;I=a,!r&&a>0&&U()}_e(o),le(e),h(),He(!1),B(!!e.i18nStale)}function De(s){const e=X(s);be(),ge(),s.state&&typeof s.state.sessionId=="string"&&pe(s.state.sessionId,s.state.sessionName),e&&m()}async function F(s){const e=s?"/api/state?session="+encodeURIComponent(s):"/api/state",o=await z(e);return o.ok&&o.data?o.data:null}async function W(s){const e=l.tabs.find(a=>a.id===s);if(!e)return;if(e.state){l.activeTabId===s&&m();return}const o=await F(s);o&&(k(o.state),l.activeTabId===s&&(R(o),m()))}async function O(){const s=l.activeTabId,e=await F(s);if(!e||l.activeTabId!==s)return;const o=e.state;!s&&o&&o.sessionId&&!l.tabs.some(a=>a.id===o.sessionId)&&P(o.sessionId,o.sessionName||String(o.sessionId),"session",!1),k(o),R(e),m()}C.ensureTabState=W;function ze(){for(const e of l.tabs)e.kind==="session"&&(e.state=null,W(e.id));O(),q();const s=l.tabs.find(e=>e.id===l.activeTabId);s&&s.kind==="session"&&!fe(s.feed)&&(s.historyLoaded=!1,ue(s))}function Je(){const s="/events"+(A?"?token="+encodeURIComponent(A):""),e=new EventSource(s);let o=!1;e.onopen=()=>{o&&(o=!1,v(!1),ze())},e.onerror=t=>{t&&typeof t.data=="string"||(o=!0,v(!0))};const a=t=>{try{return JSON.parse(t.data)}catch{return null}},r=t=>!t.sessionId||t.sessionId===Me(),c=[["text",t=>K(t.chunk||"",t.sessionId)],["meta",t=>Y(t.chunk||"",t.sessionId,t.kind)],["reasoning",t=>V(t.chunk||"",t.sessionId)],["phase",t=>Z(t.phase,t.sessionId)],["tool_start",$],["tool_end",ee],["plan",ae],["question",ie],["turn_end",t=>{te(t),r(t)&&(qe(t.turnSeq),M(!1),Ne())}],["log",oe],["retract",t=>re(t.reason||"",t.sessionId)]];for(const[t,n]of c)e.addEventListener(t,d=>{const E=a(d);E&&n(E)});for(const t of["tool_start","tool_end","text","plan"])e.addEventListener(t,n=>{const d=a(n);d&&(t==="plan"?N(d):Ce(t,d.name))});for(const t of["text","reasoning","phase","tool_start","plan"])e.addEventListener(t,n=>{const d=a(n);d&&d.sessionId&&p(d.sessionId,"working")});e.addEventListener("question",t=>{const n=a(t);n&&n.sessionId&&p(n.sessionId,"waiting")}),e.addEventListener("turn_end",t=>{const n=a(t);n&&n.sessionId&&p(n.sessionId,n.success===!1?"failed":"idle")});for(const t of["tool_start","tool_end","phase","plan","question","meta","log","retract","index"])e.addEventListener(t,n=>{const d=a(n);d&&r(d)&&y(t,d)});e.addEventListener("text",t=>{const n=a(t);n&&r(n)&&y("text",n)}),e.addEventListener("lsp",t=>{const n=a(t);n&&Fe(n)}),e.addEventListener("files",()=>U()),e.addEventListener("command",t=>{const n=a(t);n&&typeof n.text=="string"&&ne(n.text,n.sessionId)}),e.addEventListener("state",t=>{const n=a(t);n&&(M(!!n.busy),De(n))}),e.addEventListener("sessions",t=>{const n=a(t);n&&Array.isArray(n.sessions)&&(f.sessions=n.sessions,h())}),e.addEventListener("usage",t=>{const n=a(t);if(!n||!n.usage||typeof n.usage!="object")return;const d=n.usageSessionId||n.sessionId||null;G(d,n.usage)&&_(f.host)}),e.addEventListener("error",t=>{if(!t.data)return;const n=a(t);n&&(n.sessionId&&p(n.sessionId,"failed"),se(n),y("error",n))})}function j(){document.documentElement.lang=J.locale;const s=(r,c)=>{const t=document.getElementById(r);t&&(t.textContent=c)};s("planHeaderLabel",i("web.sidebar.plan")),s("usageHeaderLabel",i("web.sidebar.session")+" · "+i("web.sidebar.usage")),s("envHeaderLabel",i("web.sidebar.env")),s("settingsTitle",i("web.settings.title")),s("sessActiveHeader",i("web.sessions.active")),s("sessRecentHeader",i("web.sessions.recent")),s("hintEnter",i("web.input.enter")),s("hintShift",i("web.input.shift_enter")),s("hintEsc",i("web.input.esc")),s("hintAttach",i("web.input.attach"));const e={newChat:["plus",i("web.topbar.new_chat")],sessBtn:["menu",i("web.topbar.all_sessions")],toggleSidebar:["panel",i("web.topbar.sidebar")],openSettings:["settings",i("web.topbar.settings")],attachBtn:["image",i("web.attach.title")],closeSettings:["x",i("web.topbar.close")],sessNew:["plus",i("web.sessions.new")],sessRefresh:["refresh",i("web.sessions.refresh")],sessPrev:["chevron-left",i("web.sessbar.prev")],sessNext:["chevron-right",i("web.sessbar.next")],sessClose:["x",i("web.topbar.close")]};Object.keys(e).forEach(r=>{const c=document.getElementById(r);if(!c)return;const[t,n]=e[r];x(c,t,r==="closeSettings"||r==="sessNew"||r==="sessRefresh"?n:null),c.title=n,c.setAttribute("aria-label",n)});const o=document.getElementById("settingsIcon");o&&x(o,"settings",null),g&&(g.placeholder=i("web.input.placeholder"),g.setAttribute("aria-label",i("web.input.placeholder"))),document.querySelectorAll("#setMenu .mi").forEach(r=>{const c=r.dataset.p;c&&(r.textContent=i("web.settings."+c))});const a=document.getElementById("setSearch");a&&(a.setAttribute("placeholder",i("web.settings.search_placeholder")),a.setAttribute("aria-label",i("web.settings.search_placeholder"))),document.querySelectorAll(".content-col .panel").forEach(r=>{const c=r.querySelector("h3"),t=r.id.replace(/^p-/,"");c&&t&&(c.textContent=i("web.settings."+t))}),S(),h(),ke(),H(),D.querySelector(".empty")&&w(),L&&!L.hidden&&v(!0),B(void 0,!0)}async function Qe(){const s=new URLSearchParams(location.search).get("session");if(window.MmaSetup)try{if(await window.MmaSetup.maybeOpen())return}catch{}await Q(),await me(),Le(xe()),Te(),j(),w(),S(),we(),await he(),Ae(u.config&&u.config.ui?u.config.ui.activityRail:void 0),Re(),H(),We({insertPath:e=>je("`"+e+"` ")}),await Se(),await ve(),await q(),await ye(),await Ie(),await Ee();try{await O()}catch(e){console.error("initial refresh failed",e)}if(s){const e=f.sessions.find(o=>o.id===s);e&&P(s,e.name||String(s),"session",!0)}Je()}C.applyStaticI18n=j,Qe();
1
+ import{msgs as D,inp as g,connStatus as L,setIcon as x,icon as T}from"./js/dom.js";import{api as z,token as A}from"./js/api.js";import{I18N as J,t as a,loadI18n as Q}from"./js/i18n.js";import{tabs as l,session as f,settings as u,hooks as C}from"./js/store.js";import{routeState as X,mergeUsage as G,storeSnapshot as k,applyCounters as R}from"./js/state-sync.js";import{onText as K,onReasoning as V,onMeta as Y,onPhase as Z,onToolStart as $,onToolEnd as ee,onTurnEnd as te,onErrorEvent as se,onCommandOutput as ne,onLog as oe,onPlan as ie,onQuestion as ae,onRetract as re,showEmptyFeed as w,renderPlan as de,renderUsage as P,renderEnvironment as ce,renderWorkspace as le,feedHasContent as fe,loadHistory as ue}from"./js/feed.js";import{openTab as _,updateTabName as be,renderSessionsDropdown as h,reflectBusy as pe,loadSessions as q,loadCommands as me,setTabStatus as b,reconcileTabStatuses as ge}from"./js/session/tabs.js";import{renderSelectors as S,renderSettings as we,loadConfig as he,loadModels as Se,loadProviders as ve,loadMemory as ye,loadSkills as Ie,loadPlugins as Ee,applyTheme as Le,currentTheme as xe,applyFontSize as Te,setConnStatus as v,setStaleBar as B}from"./js/settings.js";import{initRail as Ae,setPlan as N,railEvent as Ce,applyRailI18n as ke}from"./js/rail.js";import{initSidebar as Re,sidebarSessionChanged as Pe,sidebarMapState as _e,sidebarTraceEvent as y,sidebarTurnEnd as qe,sidebarBusy as M,sidebarMapIndicator as Be,sidebarPullLog as Ne,sidebarSessionId as Me,setSessionLoading as He,sidebarLspState as Ue,sidebarLspEvent as Fe,applySidebarI18n as H,initFiles as We,sidebarFilesState as Oe,sidebarFilesChanged as U,sidebarPluginsState as je,sidebarPluginsEvent as De}from"./js/sidebar.js";import{insertIntoDraft as ze}from"./js/session/composer.js";document.querySelectorAll("[data-collapse]").forEach(s=>{const e=s.querySelector(".arrow");e&&(e.textContent="",e.appendChild(T("chevron-down"))),s.addEventListener("click",()=>{const o=s.nextElementSibling;if(!o)return;const i=o.classList.toggle("collapsed");s.setAttribute("aria-expanded",i?"false":"true");const r=s.querySelector(".arrow");r&&(r.textContent="",r.appendChild(T(i?"chevron-right":"chevron-down")))})});const p=document.getElementById("toggleSidebar");p&&(p.addEventListener("click",()=>{const s=document.body.classList.toggle("sb-open");p.setAttribute("aria-expanded",s?"true":"false")}),document.addEventListener("keydown",s=>{if(s.key!=="Escape"||!document.body.classList.contains("sb-open"))return;const e=document.activeElement?String(document.activeElement.tagName):"";e==="TEXTAREA"||e==="INPUT"||(document.body.classList.remove("sb-open"),p.setAttribute("aria-expanded","false"))}));let I=-1;function m(){const s=l.tabs.find(r=>r.id===l.activeTabId)||null,e=s&&s.state||{};f.host=e;const o=e.sessionId||s&&s.id||null;f.activeSessionId=o,l.tabs.length||w(),de(e.plan),N(f.busy&&e?e.plan:null),P(e),typeof e.contextWindow=="number"&&u.config&&u.config.contextWindow!==e.contextWindow&&(u.config.contextWindow=e.contextWindow,S()),ce(e),_e(e),Be(e),Ue(),Oe(e),je();const i=typeof e.filesRevision=="number"?e.filesRevision:void 0;if(i!==void 0&&i!==I){const r=I===-1;I=i,!r&&i>0&&U()}Pe(o),le(e),h(),He(!1),B(!!e.i18nStale)}function Je(s){const e=X(s);pe(),ge(),s.state&&typeof s.state.sessionId=="string"&&be(s.state.sessionId,s.state.sessionName),e&&m()}async function F(s){const e=s?"/api/state?session="+encodeURIComponent(s):"/api/state",o=await z(e);return o.ok&&o.data?o.data:null}async function W(s){const e=l.tabs.find(i=>i.id===s);if(!e)return;if(e.state){l.activeTabId===s&&m();return}const o=await F(s);o&&(k(o.state),l.activeTabId===s&&(R(o),m()))}async function O(){const s=l.activeTabId,e=await F(s);if(!e||l.activeTabId!==s)return;const o=e.state;!s&&o&&o.sessionId&&!l.tabs.some(i=>i.id===o.sessionId)&&_(o.sessionId,o.sessionName||String(o.sessionId),"session",!1),k(o),R(e),m()}C.ensureTabState=W;function Qe(){for(const e of l.tabs)e.kind==="session"&&(e.state=null,W(e.id));O(),q();const s=l.tabs.find(e=>e.id===l.activeTabId);s&&s.kind==="session"&&!fe(s.feed)&&(s.historyLoaded=!1,ue(s))}function Xe(){const s="/events"+(A?"?token="+encodeURIComponent(A):""),e=new EventSource(s);let o=!1;e.onopen=()=>{o&&(o=!1,v(!1),Qe())},e.onerror=t=>{t&&typeof t.data=="string"||(o=!0,v(!0))};const i=t=>{try{return JSON.parse(t.data)}catch{return null}},r=t=>!t.sessionId||t.sessionId===Me(),c=[["text",t=>K(t.chunk||"",t.sessionId)],["meta",t=>Y(t.chunk||"",t.sessionId,t.kind)],["reasoning",t=>V(t.chunk||"",t.sessionId)],["phase",t=>Z(t.phase,t.sessionId)],["tool_start",$],["tool_end",ee],["plan",ie],["question",ae],["turn_end",t=>{te(t),r(t)&&(qe(t.turnSeq),M(!1),Ne())}],["log",oe],["retract",t=>re(t.reason||"",t.sessionId)]];for(const[t,n]of c)e.addEventListener(t,d=>{const E=i(d);E&&n(E)});for(const t of["tool_start","tool_end","text","plan"])e.addEventListener(t,n=>{const d=i(n);d&&(t==="plan"?N(d):Ce(t,d.name))});for(const t of["text","reasoning","phase","tool_start","plan"])e.addEventListener(t,n=>{const d=i(n);d&&d.sessionId&&b(d.sessionId,"working")});e.addEventListener("question",t=>{const n=i(t);n&&n.sessionId&&b(n.sessionId,"waiting")}),e.addEventListener("turn_end",t=>{const n=i(t);n&&n.sessionId&&b(n.sessionId,n.success===!1?"failed":"idle")});for(const t of["tool_start","tool_end","phase","plan","question","meta","log","retract","index"])e.addEventListener(t,n=>{const d=i(n);d&&r(d)&&y(t,d)});e.addEventListener("text",t=>{const n=i(t);n&&r(n)&&y("text",n)}),e.addEventListener("lsp",t=>{const n=i(t);n&&Fe(n)}),e.addEventListener("files",()=>U()),e.addEventListener("plugins",()=>De()),e.addEventListener("command",t=>{const n=i(t);n&&typeof n.text=="string"&&ne(n.text,n.sessionId)}),e.addEventListener("state",t=>{const n=i(t);n&&(M(!!n.busy),Je(n))}),e.addEventListener("sessions",t=>{const n=i(t);n&&Array.isArray(n.sessions)&&(f.sessions=n.sessions,h())}),e.addEventListener("usage",t=>{const n=i(t);if(!n||!n.usage||typeof n.usage!="object")return;const d=n.usageSessionId||n.sessionId||null;G(d,n.usage)&&P(f.host)}),e.addEventListener("error",t=>{if(!t.data)return;const n=i(t);n&&(n.sessionId&&b(n.sessionId,"failed"),se(n),y("error",n))})}function j(){document.documentElement.lang=J.locale;const s=(r,c)=>{const t=document.getElementById(r);t&&(t.textContent=c)};s("planHeaderLabel",a("web.sidebar.plan")),s("usageHeaderLabel",a("web.sidebar.session")+" · "+a("web.sidebar.usage")),s("envHeaderLabel",a("web.sidebar.env")),s("settingsTitle",a("web.settings.title")),s("sessActiveHeader",a("web.sessions.active")),s("sessRecentHeader",a("web.sessions.recent")),s("hintEnter",a("web.input.enter")),s("hintShift",a("web.input.shift_enter")),s("hintEsc",a("web.input.esc")),s("hintAttach",a("web.input.attach"));const e={newChat:["plus",a("web.topbar.new_chat")],sessBtn:["menu",a("web.topbar.all_sessions")],toggleSidebar:["panel",a("web.topbar.sidebar")],openSettings:["settings",a("web.topbar.settings")],attachBtn:["image",a("web.attach.title")],closeSettings:["x",a("web.topbar.close")],sessNew:["plus",a("web.sessions.new")],sessRefresh:["refresh",a("web.sessions.refresh")],sessPrev:["chevron-left",a("web.sessbar.prev")],sessNext:["chevron-right",a("web.sessbar.next")],sessClose:["x",a("web.topbar.close")]};Object.keys(e).forEach(r=>{const c=document.getElementById(r);if(!c)return;const[t,n]=e[r];x(c,t,r==="closeSettings"||r==="sessNew"||r==="sessRefresh"?n:null),c.title=n,c.setAttribute("aria-label",n)});const o=document.getElementById("settingsIcon");o&&x(o,"settings",null),g&&(g.placeholder=a("web.input.placeholder"),g.setAttribute("aria-label",a("web.input.placeholder"))),document.querySelectorAll("#setMenu .mi").forEach(r=>{const c=r.dataset.p;c&&(r.textContent=a("web.settings."+c))});const i=document.getElementById("setSearch");i&&(i.setAttribute("placeholder",a("web.settings.search_placeholder")),i.setAttribute("aria-label",a("web.settings.search_placeholder"))),document.querySelectorAll(".content-col .panel").forEach(r=>{const c=r.querySelector("h3"),t=r.id.replace(/^p-/,"");c&&t&&(c.textContent=a("web.settings."+t))}),S(),h(),ke(),H(),D.querySelector(".empty")&&w(),L&&!L.hidden&&v(!0),B(void 0,!0)}async function Ge(){const s=new URLSearchParams(location.search).get("session");if(window.MmaSetup)try{if(await window.MmaSetup.maybeOpen())return}catch{}await Q(),await me(),Le(xe()),Te(),j(),w(),S(),we(),await he(),Ae(u.config&&u.config.ui?u.config.ui.activityRail:void 0),Re(),H(),We({insertPath:e=>ze("`"+e+"` ")}),await Se(),await ve(),await q(),await ye(),await Ie(),await Ee();try{await O()}catch(e){console.error("initial refresh failed",e)}if(s){const e=f.sessions.find(o=>o.id===s);e&&_(s,e.name||String(s),"session",!0)}Xe()}C.applyStaticI18n=j,Ge();
@@ -120,6 +120,10 @@
120
120
  <span class="sb-ico" data-icon="files" aria-hidden="true"></span>
121
121
  <span class="sb-dot" aria-hidden="true"></span>
122
122
  </button>
123
+ <button class="sb-tab" type="button" role="tab" data-tab="plugins" aria-selected="false" aria-controls="pane-plugins" title="Plugins">
124
+ <span class="sb-ico" data-icon="plugins" aria-hidden="true"></span>
125
+ <span class="sb-dot" aria-hidden="true"></span>
126
+ </button>
123
127
  </div>
124
128
  <div class="sb-name" id="sbName"><span class="sb-ico" data-icon="session" aria-hidden="true"></span><span id="sbNameText">Session</span></div>
125
129
 
@@ -158,6 +162,12 @@
158
162
  </div>
159
163
  </div>
160
164
 
165
+ <div class="sb-pane" id="pane-plugins" role="tabpanel" data-pane="plugins" hidden>
166
+ <div class="sec map-sec">
167
+ <div class="sec-body" id="pluginsBody"></div>
168
+ </div>
169
+ </div>
170
+
161
171
  <div class="sb-pane" id="pane-files" role="tabpanel" data-pane="files" hidden>
162
172
  <div class="files-tree" id="filesTree"></div>
163
173
  <div class="files-detail" id="filesDetail" hidden>
@@ -1 +1 @@
1
- export const msgs=document.getElementById("msgs"),inp=document.getElementById("inp"),tabstripEl=document.getElementById("tabstrip"),planEl=document.getElementById("plan"),planCountEl=document.getElementById("planCount"),usageEl=document.getElementById("usage"),envEl=document.getElementById("env"),wsLine=document.getElementById("wsLine"),saveIndicator=document.getElementById("saveIndicator"),attachStrip=document.getElementById("attachStrip"),attachErr=document.getElementById("attachErr"),imgPicker=document.getElementById("imgPicker"),connStatus=document.getElementById("connStatus"),staleBar=document.getElementById("staleBar"),liveEl=document.getElementById("live"),sendBtn=document.getElementById("sendBtn");export function announce(e){!liveEl||!e||(liveEl.textContent="",setTimeout(()=>{liveEl.textContent=e},30))}export function el(e,a,t){const n=document.createElement(e);return a&&(n.className=a),t!=null&&(n.textContent=String(t)),n}let i=null,s=!1;function p(){return i||(i=el("div","ctip"),i.setAttribute("role","tooltip"),document.body.appendChild(i)),i}function c(){i&&i.classList.remove("show")}function h(){s||(s=!0,window.addEventListener("scroll",c,!0),window.addEventListener("resize",c))}export function attachTooltip(e,a){const t=()=>{const n=p();n.replaceChildren(a()),n.classList.add("show");const o=e.getBoundingClientRect(),r=n.getBoundingClientRect();let d=o.left+o.width/2-r.width/2;d=Math.max(6,Math.min(d,window.innerWidth-r.width-6));let l=o.top-r.height-7;l<6&&(l=o.bottom+7),n.style.left=d+"px",n.style.top=l+"px"};e.addEventListener("mouseenter",t),e.addEventListener("mouseleave",c),e.addEventListener("focus",t),e.addEventListener("blur",c),h()}export const SVG_NS="http://www.w3.org/2000/svg",ICONS={plus:[["path",{d:"M5 12h14"}],["path",{d:"M12 5v14"}]],menu:[["line",{x1:4,y1:6,x2:20,y2:6}],["line",{x1:4,y1:12,x2:20,y2:12}],["line",{x1:4,y1:18,x2:20,y2:18}]],settings:[["path",{d:"M12.22 2h-.44a2 2 0 0 0-2 2v.18a2 2 0 0 1-1 1.73l-.43.25a2 2 0 0 1-2 0l-.15-.08a2 2 0 0 0-2.73.73l-.22.38a2 2 0 0 0 .73 2.73l.15.1a2 2 0 0 1 1 1.72v.51a2 2 0 0 1-1 1.74l-.15.09a2 2 0 0 0-.73 2.73l.22.38a2 2 0 0 0 2.73.73l.15-.08a2 2 0 0 1 2 0l.43.25a2 2 0 0 1 1 1.73V20a2 2 0 0 0 2 2h.44a2 2 0 0 0 2-2v-.18a2 2 0 0 1 1-1.73l.43-.25a2 2 0 0 1 2 0l.15.08a2 2 0 0 0 2.73-.73l.22-.39a2 2 0 0 0-.73-2.73l-.15-.08a2 2 0 0 1-1-1.74v-.5a2 2 0 0 1 1-1.74l.15-.09a2 2 0 0 0 .73-2.73l-.22-.38a2 2 0 0 0-2.73-.73l-.15.08a2 2 0 0 1-2 0l-.43-.25a2 2 0 0 1-1-1.73V4a2 2 0 0 0-2-2z"}],["circle",{cx:12,cy:12,r:3}]],image:[["rect",{width:18,height:18,x:3,y:3,rx:2,ry:2}],["circle",{cx:9,cy:9,r:2}],["path",{d:"m21 15-3.086-3.086a2 2 0 0 0-2.828 0L6 21"}]],x:[["path",{d:"M18 6 6 18"}],["path",{d:"m6 6 12 12"}]],trash:[["path",{d:"M3 6h18"}],["path",{d:"M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6"}],["path",{d:"M8 6V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2"}],["line",{x1:10,y1:11,x2:10,y2:17}],["line",{x1:14,y1:11,x2:14,y2:17}]],refresh:[["path",{d:"M3 12a9 9 0 0 1 9-9 9.75 9.75 0 0 1 6.74 2.74L21 8"}],["path",{d:"M21 3v5h-5"}],["path",{d:"M21 12a9 9 0 0 1-9 9 9.75 9.75 0 0 1-6.74-2.74L3 16"}],["path",{d:"M8 21H3v-5"}]],"chevron-down":[["path",{d:"m6 9 6 6 6-6"}]],"chevron-left":[["path",{d:"m15 18-6-6 6-6"}]],"chevron-right":[["path",{d:"m9 18 6-6-6-6"}]],search:[["circle",{cx:11,cy:11,r:8}],["path",{d:"m21 21-4.3-4.3"}]],"list-checks":[["path",{d:"m3 17 2 2 4-4"}],["path",{d:"m3 7 2 2 4-4"}],["path",{d:"M13 6h8"}],["path",{d:"M13 12h8"}],["path",{d:"M13 18h8"}]],map:[["path",{d:"M14.106 5.553a2 2 0 0 0 1.788 0l3.659-1.83A1 1 0 0 1 21 4.619v12.764a1 1 0 0 1-.553.894l-4.553 2.277a2 2 0 0 1-1.788 0l-4.212-2.106a2 2 0 0 0-1.788 0l-3.659 1.83A1 1 0 0 1 3 19.381V6.618a1 1 0 0 1 .553-.894l4.553-2.277a2 2 0 0 1 1.788 0z"}],["path",{d:"M15 5.764v15"}],["path",{d:"M9 3.236v15"}]],activity:[["path",{d:"M22 12h-2.48a2 2 0 0 0-1.93 1.46l-2.35 8.36a.25.25 0 0 1-.48 0L9.24 2.18a.25.25 0 0 0-.48 0l-2.35 8.36A2 2 0 0 1 4.49 12H2"}]],"arrow-up":[["path",{d:"M12 19V5"}],["path",{d:"m5 12 7-7 7 7"}]],panel:[["rect",{width:18,height:18,x:3,y:3,rx:2,ry:2}],["line",{x1:15,y1:3,x2:15,y2:21}]],square:[["rect",{width:14,height:14,x:5,y:5,rx:2}]],copy:[["rect",{width:14,height:14,x:8,y:8,rx:2,ry:2}],["path",{d:"M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2"}]],check:[["path",{d:"M20 6 9 17l-5-5"}]],info:[["circle",{cx:12,cy:12,r:10}],["path",{d:"M12 16v-4"}],["path",{d:"M12 8h.01"}]],stethoscope:[["path",{d:"M11 2v2"}],["path",{d:"M5 2v2"}],["path",{d:"M5 3H4a2 2 0 0 0-2 2v4a6 6 0 0 0 12 0V5a2 2 0 0 0-2-2h-1"}],["path",{d:"M8 15a6 6 0 0 0 12 0v-3"}],["circle",{cx:20,cy:10,r:2}]],"folder-tree":[["path",{d:"M20 10a1 1 0 0 0 1-1V6a1 1 0 0 0-1-1h-2.5a1 1 0 0 1-.8-.4l-.9-1.2A1 1 0 0 0 15 3h-2a1 1 0 0 0-1 1v5a1 1 0 0 0 1 1Z"}],["path",{d:"M20 21a1 1 0 0 0 1-1v-3a1 1 0 0 0-1-1h-2.9a1 1 0 0 1-.88-.55l-.42-.85a1 1 0 0 0-.9-.6H13a1 1 0 0 0-1 1v5a1 1 0 0 0 1 1Z"}],["path",{d:"M3 5a2 2 0 0 1 2-2h3"}],["path",{d:"M3 3v13a3 3 0 0 0 3 3h4"}]],folder:[["path",{d:"M20 20a2 2 0 0 0 2-2V8a2 2 0 0 0-2-2h-7.9a2 2 0 0 1-1.69-.9L9.6 3.9A2 2 0 0 0 7.93 3H4a2 2 0 0 0-2 2v13a2 2 0 0 0 2 2Z"}]],file:[["path",{d:"M15 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V7Z"}],["path",{d:"M14 2v4a2 2 0 0 0 2 2h4"}]],paperclip:[["path",{d:"m21.44 11.05-9.19 9.19a6 6 0 0 1-8.49-8.49l8.57-8.57A4 4 0 1 1 18 8.84l-8.59 8.57a2 2 0 0 1-2.83-2.83l8.49-8.48"}]]};export function icon(e,a){const t=document.createElementNS(SVG_NS,"svg");return t.setAttribute("viewBox","0 0 24 24"),t.setAttribute("fill","none"),t.setAttribute("stroke","currentColor"),t.setAttribute("stroke-width","2"),t.setAttribute("stroke-linecap","round"),t.setAttribute("stroke-linejoin","round"),t.setAttribute("aria-hidden","true"),t.setAttribute("focusable","false"),t.setAttribute("class","svg-icon"+(a?" "+a:"")),(ICONS[e]||[]).forEach(([n,o])=>{const r=document.createElementNS(SVG_NS,n);Object.keys(o).forEach(d=>r.setAttribute(d,String(o[d]))),t.appendChild(r)}),t}export function setIcon(e,a,t){return e?(e.textContent="",e.appendChild(icon(a)),t!=null&&e.appendChild(el("span","",t)),e):null}export function makeToggle(e,a){const t=el("button","toggle"+(e?" on":""));return t.type="button",t.setAttribute("role","switch"),t.setAttribute("aria-checked",e?"true":"false"),t.addEventListener("click",()=>{const n=!t.classList.contains("on");a(n)&&(t.classList.toggle("on",n),t.setAttribute("aria-checked",n?"true":"false"))}),t}export function link(e,a,t){const n=el("button","linkbtn"+(a?" "+a:""),e);return n.type="button",n.addEventListener("click",t),n}export function inlineTextNodes(e){const a=document.createDocumentFragment();return String(e??"").replace(/^-\s*/,"").split("**").forEach((n,o)=>{if(n!=="")if(o%2===1){const r=document.createElement("b");r.textContent=n,a.appendChild(r)}else a.appendChild(document.createTextNode(n))}),a}
1
+ export const msgs=document.getElementById("msgs"),inp=document.getElementById("inp"),tabstripEl=document.getElementById("tabstrip"),planEl=document.getElementById("plan"),planCountEl=document.getElementById("planCount"),usageEl=document.getElementById("usage"),envEl=document.getElementById("env"),wsLine=document.getElementById("wsLine"),saveIndicator=document.getElementById("saveIndicator"),attachStrip=document.getElementById("attachStrip"),attachErr=document.getElementById("attachErr"),imgPicker=document.getElementById("imgPicker"),connStatus=document.getElementById("connStatus"),staleBar=document.getElementById("staleBar"),liveEl=document.getElementById("live"),sendBtn=document.getElementById("sendBtn");export function announce(e){!liveEl||!e||(liveEl.textContent="",setTimeout(()=>{liveEl.textContent=e},30))}export function el(e,a,t){const n=document.createElement(e);return a&&(n.className=a),t!=null&&(n.textContent=String(t)),n}let i=null,s=!1;function h(){return i||(i=el("div","ctip"),i.setAttribute("role","tooltip"),document.body.appendChild(i)),i}function c(){i&&i.classList.remove("show")}function p(){s||(s=!0,window.addEventListener("scroll",c,!0),window.addEventListener("resize",c))}export function attachTooltip(e,a){const t=()=>{const n=h();n.replaceChildren(a()),n.classList.add("show");const o=e.getBoundingClientRect(),r=n.getBoundingClientRect();let d=o.left+o.width/2-r.width/2;d=Math.max(6,Math.min(d,window.innerWidth-r.width-6));let l=o.top-r.height-7;l<6&&(l=o.bottom+7),n.style.left=d+"px",n.style.top=l+"px"};e.addEventListener("mouseenter",t),e.addEventListener("mouseleave",c),e.addEventListener("focus",t),e.addEventListener("blur",c),p()}export const SVG_NS="http://www.w3.org/2000/svg",ICONS={plus:[["path",{d:"M5 12h14"}],["path",{d:"M12 5v14"}]],menu:[["line",{x1:4,y1:6,x2:20,y2:6}],["line",{x1:4,y1:12,x2:20,y2:12}],["line",{x1:4,y1:18,x2:20,y2:18}]],settings:[["path",{d:"M12.22 2h-.44a2 2 0 0 0-2 2v.18a2 2 0 0 1-1 1.73l-.43.25a2 2 0 0 1-2 0l-.15-.08a2 2 0 0 0-2.73.73l-.22.38a2 2 0 0 0 .73 2.73l.15.1a2 2 0 0 1 1 1.72v.51a2 2 0 0 1-1 1.74l-.15.09a2 2 0 0 0-.73 2.73l.22.38a2 2 0 0 0 2.73.73l.15-.08a2 2 0 0 1 2 0l.43.25a2 2 0 0 1 1 1.73V20a2 2 0 0 0 2 2h.44a2 2 0 0 0 2-2v-.18a2 2 0 0 1 1-1.73l.43-.25a2 2 0 0 1 2 0l.15.08a2 2 0 0 0 2.73-.73l.22-.39a2 2 0 0 0-.73-2.73l-.15-.08a2 2 0 0 1-1-1.74v-.5a2 2 0 0 1 1-1.74l.15-.09a2 2 0 0 0 .73-2.73l-.22-.38a2 2 0 0 0-2.73-.73l-.15.08a2 2 0 0 1-2 0l-.43-.25a2 2 0 0 1-1-1.73V4a2 2 0 0 0-2-2z"}],["circle",{cx:12,cy:12,r:3}]],image:[["rect",{width:18,height:18,x:3,y:3,rx:2,ry:2}],["circle",{cx:9,cy:9,r:2}],["path",{d:"m21 15-3.086-3.086a2 2 0 0 0-2.828 0L6 21"}]],x:[["path",{d:"M18 6 6 18"}],["path",{d:"m6 6 12 12"}]],trash:[["path",{d:"M3 6h18"}],["path",{d:"M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6"}],["path",{d:"M8 6V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2"}],["line",{x1:10,y1:11,x2:10,y2:17}],["line",{x1:14,y1:11,x2:14,y2:17}]],refresh:[["path",{d:"M3 12a9 9 0 0 1 9-9 9.75 9.75 0 0 1 6.74 2.74L21 8"}],["path",{d:"M21 3v5h-5"}],["path",{d:"M21 12a9 9 0 0 1-9 9 9.75 9.75 0 0 1-6.74-2.74L3 16"}],["path",{d:"M8 21H3v-5"}]],"chevron-down":[["path",{d:"m6 9 6 6 6-6"}]],"chevron-left":[["path",{d:"m15 18-6-6 6-6"}]],"chevron-right":[["path",{d:"m9 18 6-6-6-6"}]],search:[["circle",{cx:11,cy:11,r:8}],["path",{d:"m21 21-4.3-4.3"}]],"list-checks":[["path",{d:"m3 17 2 2 4-4"}],["path",{d:"m3 7 2 2 4-4"}],["path",{d:"M13 6h8"}],["path",{d:"M13 12h8"}],["path",{d:"M13 18h8"}]],"layout-grid":[["rect",{width:7,height:7,x:3,y:3,rx:1}],["rect",{width:7,height:7,x:14,y:3,rx:1}],["rect",{width:7,height:7,x:14,y:14,rx:1}],["rect",{width:7,height:7,x:3,y:14,rx:1}]],code:[["path",{d:"m16 18 6-6-6-6"}],["path",{d:"m8 6-6 6 6 6"}]],plug:[["path",{d:"M12 22v-5"}],["path",{d:"M9 8V2"}],["path",{d:"M15 8V2"}],["path",{d:"M18 8v5a6 6 0 0 1-12 0V8Z"}]],activity:[["path",{d:"M22 12h-2.48a2 2 0 0 0-1.93 1.46l-2.35 8.36a.25.25 0 0 1-.48 0L9.24 2.18a.25.25 0 0 0-.48 0l-2.35 8.36A2 2 0 0 1 4.49 12H2"}]],"arrow-up":[["path",{d:"M12 19V5"}],["path",{d:"m5 12 7-7 7 7"}]],panel:[["rect",{width:18,height:18,x:3,y:3,rx:2,ry:2}],["line",{x1:15,y1:3,x2:15,y2:21}]],square:[["rect",{width:14,height:14,x:5,y:5,rx:2}]],copy:[["rect",{width:14,height:14,x:8,y:8,rx:2,ry:2}],["path",{d:"M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2"}]],check:[["path",{d:"M20 6 9 17l-5-5"}]],info:[["circle",{cx:12,cy:12,r:10}],["path",{d:"M12 16v-4"}],["path",{d:"M12 8h.01"}]],"folder-tree":[["path",{d:"M20 10a1 1 0 0 0 1-1V6a1 1 0 0 0-1-1h-2.5a1 1 0 0 1-.8-.4l-.9-1.2A1 1 0 0 0 15 3h-2a1 1 0 0 0-1 1v5a1 1 0 0 0 1 1Z"}],["path",{d:"M20 21a1 1 0 0 0 1-1v-3a1 1 0 0 0-1-1h-2.9a1 1 0 0 1-.88-.55l-.42-.85a1 1 0 0 0-.9-.6H13a1 1 0 0 0-1 1v5a1 1 0 0 0 1 1Z"}],["path",{d:"M3 5a2 2 0 0 1 2-2h3"}],["path",{d:"M3 3v13a3 3 0 0 0 3 3h4"}]],folder:[["path",{d:"M20 20a2 2 0 0 0 2-2V8a2 2 0 0 0-2-2h-7.9a2 2 0 0 1-1.69-.9L9.6 3.9A2 2 0 0 0 7.93 3H4a2 2 0 0 0-2 2v13a2 2 0 0 0 2 2Z"}]],file:[["path",{d:"M15 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V7Z"}],["path",{d:"M14 2v4a2 2 0 0 0 2 2h4"}]],paperclip:[["path",{d:"m21.44 11.05-9.19 9.19a6 6 0 0 1-8.49-8.49l8.57-8.57A4 4 0 1 1 18 8.84l-8.59 8.57a2 2 0 0 1-2.83-2.83l8.49-8.48"}]]};export function icon(e,a){const t=document.createElementNS(SVG_NS,"svg");return t.setAttribute("viewBox","0 0 24 24"),t.setAttribute("fill","none"),t.setAttribute("stroke","currentColor"),t.setAttribute("stroke-width","2"),t.setAttribute("stroke-linecap","round"),t.setAttribute("stroke-linejoin","round"),t.setAttribute("aria-hidden","true"),t.setAttribute("focusable","false"),t.setAttribute("class","svg-icon"+(a?" "+a:"")),(ICONS[e]||[]).forEach(([n,o])=>{const r=document.createElementNS(SVG_NS,n);Object.keys(o).forEach(d=>r.setAttribute(d,String(o[d]))),t.appendChild(r)}),t}export function setIcon(e,a,t){return e?(e.textContent="",e.appendChild(icon(a)),t!=null&&e.appendChild(el("span","",t)),e):null}export function makeToggle(e,a){const t=el("button","toggle"+(e?" on":""));return t.type="button",t.setAttribute("role","switch"),t.setAttribute("aria-checked",e?"true":"false"),t.addEventListener("click",()=>{const n=!t.classList.contains("on");a(n)&&(t.classList.toggle("on",n),t.setAttribute("aria-checked",n?"true":"false"))}),t}export function link(e,a,t){const n=el("button","linkbtn"+(a?" "+a:""),e);return n.type="button",n.addEventListener("click",t),n}export function inlineTextNodes(e){const a=document.createDocumentFragment();return String(e??"").replace(/^-\s*/,"").split("**").forEach((n,o)=>{if(n!=="")if(o%2===1){const r=document.createElement("b");r.textContent=n,a.appendChild(r)}else a.appendChild(document.createTextNode(n))}),a}
@@ -1 +1 @@
1
- import{el as a,makeToggle as g}from"../dom.js";import{tagsEditor as b,checkboxEditor as p,tableEditor as w}from"./editors.js";export function validateJson(i){const e=String(i??"").trim();if(!e)return{ok:!1,error:"required"};try{return JSON.parse(e),{ok:!0}}catch(s){return{ok:!1,error:s instanceof Error?s.message:"invalid JSON"}}}function u(i,e){const s=a("input");return s.setAttribute("aria-label",i),s.value=e,s}function m(i,e,s){const l=s.optionsSource==="providers"?e.providerOptions||[]:e.modelOptions||[],t=typeof i=="string"?i:"";if(!l.length){const o=u(e.label,t);return o.addEventListener("change",()=>e.post(o.value)),o}const n=a("select");n.setAttribute("aria-label",e.label);const c=a("option","",e.emptyLabel||"—");c.value="",n.appendChild(c);const d=new Set([""]);if(l.forEach(o=>{if(d.has(o))return;d.add(o);const y=a("option","",o);y.value=o,o===t&&(y.selected=!0),n.appendChild(y)}),t&&!d.has(t)){const o=a("option","",t);o.value=t,o.selected=!0,n.appendChild(o)}return n.value=t||"",n.addEventListener("change",()=>e.post(n.value)),n}export function controlFor(i,e,s){if(i.readOnly){const t=a("span","val dim",e==null?"—":String(e));return e!=null&&(t.title=String(e)),t}if(i.valueType==="bool")return g(!!e,t=>(s.post(t),!0));if(i.valueType==="enum"){const t=a("select");return t.setAttribute("aria-label",s.label),(i.enum||[]).forEach(n=>{const c=a("option","",s.enumLabel(n));c.value=n,n===e&&(c.selected=!0),t.appendChild(c)}),t.addEventListener("change",()=>s.post(t.value)),t}if(i.valueType==="int"){const t=u(s.label,e==null?"":String(e));return t.type="number",i.min!=null&&(t.min=String(i.min)),i.max!=null&&(t.max=String(i.max)),i.step!=null&&(t.step=String(i.step)),t.addEventListener("change",()=>s.post(t.value)),t}if(i.valueType==="share"){const t=u(s.label,e==null?"":Math.round(Number(e)*100)+"%");return t.addEventListener("change",()=>s.post(t.value)),t}const r=i.editor;if(r&&r.kind==="select")return m(e,s,r);if(r&&r.kind==="tags"&&(i.valueType==="list"||i.valueType==="json"))return b(e,s,r);if(r&&r.kind==="checkboxes")return p(e,s,r);if(r&&r.kind==="table")return w(e,s,r);if(i.valueType==="list"){const t=Array.isArray(e)?e.join(", "):e==null?"":String(e),n=u(s.label,t);return n.placeholder="a, b, c",n.addEventListener("change",()=>s.post(n.value)),n}if(i.valueType==="json"){const t=a("div","jsonctl"),n=a("textarea");n.setAttribute("aria-label",s.label),n.rows=3,n.value=e==null?"":JSON.stringify(e,null,2);const c=a("div","json-err");return c.hidden=!0,n.addEventListener("input",()=>{const d=validateJson(n.value);c.hidden=d.ok,c.textContent=d.ok?"":String(d.error||"invalid JSON")}),n.addEventListener("change",()=>{validateJson(n.value).ok?s.post(n.value.trim()):n.focus()}),t.appendChild(n),t.appendChild(c),t}const l=u(s.label,e==null?"":String(e));return l.addEventListener("change",()=>s.post(l.value)),l}export const PANEL_SECTIONS={general:[{id:"general.interface",titleKey:"web.settings.sec.general.interface",keys:["locale","ui.verbosity"]},{id:"general.agent",titleKey:"web.settings.sec.general.agent",descKey:"web.settings.sec.general.agent.desc",keys:["maxToolIterations","stuckThreshold","autoPlan","execution.autoAdvance"]},{id:"general.provider",titleKey:"web.settings.sec.general.provider",keys:["provider.fallback"]}],model:[{id:"model.tuning",titleKey:"web.settings.sec.model.tuning",descKey:"web.settings.sec.model.tuning.desc",keys:["provider.maxCompletionTokens","modelLoad.autoLoad","modelLoad.flashAttention","modelLoad.evalBatchSize","modelLoad.offloadKvCacheToGpu"]},{id:"model.capabilities",titleKey:"web.settings.sec.model.capabilities",descKey:"web.settings.sec.model.capabilities.desc",keys:["modelCapabilities"]}],context:[{id:"context.window",titleKey:"web.settings.sec.context.window",descKey:"web.settings.sec.context.window.desc",keys:["contextWindow","contextBudget.systemPrompt","contextBudget.responseReserve"]},{id:"context.compaction",titleKey:"web.settings.sec.context.compaction",descKey:"web.settings.sec.context.compaction.desc",keys:["contextBudget.compactionThreshold","contextBudget.compactionMinLoad","contextBudget.policy","contextBudget.compactionSummary","contextBudget.overflowCooldown","contextBudget.toolResultKeep","contextBudget.calibrationWarmup","contextBudget.ratioFloor"]},{id:"context.instructions",titleKey:"web.settings.sec.context.instructions",descKey:"web.settings.sec.context.instructions.desc",keys:["instructions.summarize"]},{id:"context.indexer",titleKey:"web.settings.sec.context.indexer",descKey:"web.settings.sec.context.indexer.desc",keys:["indexer.maxFiles","indexer.respectGitignore","indexer.mapTokenBudget"]},{id:"context.log",titleKey:"web.settings.sec.context.log",descKey:"web.settings.sec.context.log.desc",keys:["contextLog.enabled","contextLog.redact"]}],reasoning:[{id:"reasoning.display",titleKey:"web.settings.sec.reasoning.display",keys:["showReasoning"]},{id:"reasoning.effort",titleKey:"web.settings.sec.reasoning.effort",descKey:"web.settings.sec.reasoning.effort.desc",keys:["reasoning.mode","reasoning.min","reasoning.max","reasoning.baseline","reasoning.overrideCooldown"]}],agent:[{id:"agent.moe",titleKey:"web.settings.sec.agent.moe",descKey:"web.settings.sec.agent.moe.desc",keys:["moe.enabled","moe.maxReplanCycles","orchestrator.model","orchestrator.provider","orchestrator.contextWindow","experts"]},{id:"agent.critic",titleKey:"web.settings.sec.agent.critic",descKey:"web.settings.sec.agent.critic.desc",keys:["critic.enabled","critic.model","critic.provider","critic.tools","critic.maxCalls","critic.maxRepairCycles","critic.timeoutMs"]},{id:"agent.tools",titleKey:"web.settings.sec.agent.tools",descKey:"web.settings.sec.agent.tools.desc",keys:["tools.enableOnDemand","tools.defaultTags","tools.grepEngine","skills.budget"]},{id:"agent.subagent",titleKey:"web.settings.sec.agent.subagent",descKey:"web.settings.sec.agent.subagent.desc",keys:["subagent.resultMode","subagent.maxSummaryChars","subagent.maxParallelChunkQueries","subagent.stableSystemPrompt","subagent.timeoutMs"]},{id:"agent.hallucination",titleKey:"web.settings.sec.agent.hallucination",descKey:"web.settings.sec.agent.hallucination.desc",keys:["hallucination.judge.enabled"]}],network:[{id:"network.web",titleKey:"web.settings.sec.network.web",descKey:"web.settings.sec.network.web.desc",keys:["webSearch.enabled"]},{id:"network.error",titleKey:"web.settings.sec.network.error",descKey:"web.settings.sec.network.error.desc",keys:["errorWebSearch.enabled","errorWebSearch.threshold","errorWebSearch.maxResults","errorWebSearch.maxQueryChars","errorWebSearch.maxSearchesPerSession","errorWebSearch.requestTimeoutMs"]}],browser:[{id:"browser.main",titleKey:"web.settings.sec.browser.main",keys:["browser.enabled","browser.headless"]},{id:"browser.limits",titleKey:"web.settings.sec.browser.limits",descKey:"web.settings.sec.browser.limits.desc",keys:["browser.maxElements","browser.maxContentChars","browser.maxConsoleEntries","browser.maxConsoleLineChars"]},{id:"browser.viewport",titleKey:"web.settings.sec.browser.viewport",keys:["browser.viewportWidth","browser.viewportHeight","browser.navigationTimeout"]}],sessions:[{id:"sessions.main",titleKey:"web.settings.sec.sessions.main",descKey:"web.settings.sec.sessions.main.desc",keys:["session.autoSave","session.autoName","session.maxSessions","session.isolateMemory"]},{id:"sessions.isolation",titleKey:"web.settings.sec.sessions.isolation",descKey:"web.settings.sec.sessions.isolation.desc",keys:["sessionIsolation.enabled","sessionIsolation.isolatePlugins","sessionIsolation.isolateTempFiles"]}],ui:[{id:"ui.chat",titleKey:"web.settings.sec.ui.chat",descKey:"web.settings.sec.ui.chat.desc",keys:["ui.fontSize","ui.activityRail","ui.spinner","ui.showContextStats","ui.showCompaction"]},{id:"ui.images",titleKey:"web.settings.sec.ui.images",descKey:"web.settings.sec.ui.images.desc",keys:["images.maxCount","images.maxBytes"]}],security:[{id:"security.switches",titleKey:"web.settings.sec.security.switches",descKey:"web.settings.sec.security.switches.desc",keys:["security.enabled","security.bash.enabled","security.bash.blockDangerousFlags","security.paths.enabled","security.contentScan.enabled","security.network.enabled","security.sessionEncryption.enabled"]},{id:"security.limits",titleKey:"web.settings.sec.security.limits",descKey:"web.settings.sec.security.limits.desc",keys:["security.maxRecursionDepth","security.maxFileOperations","security.rateLimits.maxRequestsPerMinute","security.rateLimits.maxParallelTasks","security.network.requestTimeout","security.network.maxResponseSize"]},{id:"security.bash",titleKey:"web.settings.sec.security.bash",descKey:"web.settings.sec.security.bash.desc",keys:["security.bash.blacklist","security.bash.whitelist","security.bash.dangerousFlags","security.bash.dangerousOperators"]},{id:"security.paths",titleKey:"web.settings.sec.security.paths",descKey:"web.settings.sec.security.paths.desc",keys:["security.paths.denied","security.paths.allowed"]},{id:"security.network",titleKey:"web.settings.sec.security.network",descKey:"web.settings.sec.security.network.desc",keys:["security.network.deniedDomains","security.network.allowedDomains"]},{id:"security.scan",titleKey:"web.settings.sec.security.scan",descKey:"web.settings.sec.security.scan.desc",keys:["security.contentScan.dangerousPatterns"]},{id:"security.audit",titleKey:"web.settings.sec.security.audit",descKey:"web.settings.sec.security.audit.desc",keys:["security.auditNotifier.enabled","security.auditNotifier.filePath","security.auditNotifier.webhookUrl","security.auditNotifier.webhookTimeout","security.auditNotifier.minSeverity","security.auditNotifier.maxRetries","security.auditNotifier.eventTypes"]},{id:"security.encryption",titleKey:"web.settings.sec.security.encryption",descKey:"web.settings.sec.security.encryption.desc",keys:["security.sessionEncryption.encryptHistory","security.sessionEncryption.encryptSessionLog","security.sessionEncryption.keyPath"]}],advanced:[{id:"advanced.diagnostics",titleKey:"web.settings.sec.advanced.diagnostics",descKey:"web.settings.sec.advanced.diagnostics.desc",keys:["logLevel","version"]},{id:"advanced.retry",titleKey:"web.settings.sec.advanced.retry",descKey:"web.settings.sec.advanced.retry.desc",keys:["retry.maxRetries","retry.baseDelay","retry.maxDelay","retry.maxStreamRetries","retry.noDataTimeoutMs"]},{id:"advanced.service",titleKey:"web.settings.sec.advanced.service",descKey:"web.settings.sec.advanced.service.desc",keys:["pricing.enabled","pricing.overrides","updater.enabled","updater.checkOnStart","updater.autoInstall","updater.intervalMs"]}],plugins:[{id:"plugins.lsp",titleKey:"web.settings.sec.plugins.lsp",descKey:"web.settings.sec.plugins.lsp.desc",keys:["lsp.enabled","lsp.offline"]}]};export function keyToPanel(){const i=new Map;for(const[e,s]of Object.entries(PANEL_SECTIONS))for(const r of s)for(const l of r.keys)i.set(l,e);return i}
1
+ import{el as a,makeToggle as g}from"../dom.js";import{tagsEditor as b,checkboxEditor as p,tableEditor as w}from"./editors.js";export function validateJson(i){const e=String(i??"").trim();if(!e)return{ok:!1,error:"required"};try{return JSON.parse(e),{ok:!0}}catch(s){return{ok:!1,error:s instanceof Error?s.message:"invalid JSON"}}}function u(i,e){const s=a("input");return s.setAttribute("aria-label",i),s.value=e,s}function m(i,e,s){const l=s.optionsSource==="providers"?e.providerOptions||[]:e.modelOptions||[],t=typeof i=="string"?i:"";if(!l.length){const o=u(e.label,t);return o.addEventListener("change",()=>e.post(o.value)),o}const n=a("select");n.setAttribute("aria-label",e.label);const c=a("option","",e.emptyLabel||"—");c.value="",n.appendChild(c);const d=new Set([""]);if(l.forEach(o=>{if(d.has(o))return;d.add(o);const y=a("option","",o);y.value=o,o===t&&(y.selected=!0),n.appendChild(y)}),t&&!d.has(t)){const o=a("option","",t);o.value=t,o.selected=!0,n.appendChild(o)}return n.value=t||"",n.addEventListener("change",()=>e.post(n.value)),n}export function controlFor(i,e,s){if(i.readOnly){const t=a("span","val dim",e==null?"—":String(e));return e!=null&&(t.title=String(e)),t}if(i.valueType==="bool")return g(!!e,t=>(s.post(t),!0));if(i.valueType==="enum"){const t=a("select");return t.setAttribute("aria-label",s.label),(i.enum||[]).forEach(n=>{const c=a("option","",s.enumLabel(n));c.value=n,n===e&&(c.selected=!0),t.appendChild(c)}),t.addEventListener("change",()=>s.post(t.value)),t}if(i.valueType==="int"){const t=u(s.label,e==null?"":String(e));return t.type="number",i.min!=null&&(t.min=String(i.min)),i.max!=null&&(t.max=String(i.max)),i.step!=null&&(t.step=String(i.step)),t.addEventListener("change",()=>s.post(t.value)),t}if(i.valueType==="share"){const t=u(s.label,e==null?"":Math.round(Number(e)*100)+"%");return t.addEventListener("change",()=>s.post(t.value)),t}const r=i.editor;if(r&&r.kind==="select")return m(e,s,r);if(r&&r.kind==="tags"&&(i.valueType==="list"||i.valueType==="json"))return b(e,s,r);if(r&&r.kind==="checkboxes")return p(e,s,r);if(r&&r.kind==="table")return w(e,s,r);if(i.valueType==="list"){const t=Array.isArray(e)?e.join(", "):e==null?"":String(e),n=u(s.label,t);return n.placeholder="a, b, c",n.addEventListener("change",()=>s.post(n.value)),n}if(i.valueType==="json"){const t=a("div","jsonctl"),n=a("textarea");n.setAttribute("aria-label",s.label),n.rows=3,n.value=e==null?"":JSON.stringify(e,null,2);const c=a("div","json-err");return c.hidden=!0,n.addEventListener("input",()=>{const d=validateJson(n.value);c.hidden=d.ok,c.textContent=d.ok?"":String(d.error||"invalid JSON")}),n.addEventListener("change",()=>{validateJson(n.value).ok?s.post(n.value.trim()):n.focus()}),t.appendChild(n),t.appendChild(c),t}const l=u(s.label,e==null?"":String(e));return l.addEventListener("change",()=>s.post(l.value)),l}export const PANEL_SECTIONS={general:[{id:"general.interface",titleKey:"web.settings.sec.general.interface",keys:["locale","ui.verbosity"]},{id:"general.agent",titleKey:"web.settings.sec.general.agent",descKey:"web.settings.sec.general.agent.desc",keys:["maxToolIterations","stuckThreshold","autoPlan","execution.autoAdvance"]},{id:"general.provider",titleKey:"web.settings.sec.general.provider",keys:["provider.fallback"]}],model:[{id:"model.tuning",titleKey:"web.settings.sec.model.tuning",descKey:"web.settings.sec.model.tuning.desc",keys:["provider.maxCompletionTokens","modelLoad.autoLoad","modelLoad.flashAttention","modelLoad.evalBatchSize","modelLoad.offloadKvCacheToGpu"]},{id:"model.capabilities",titleKey:"web.settings.sec.model.capabilities",descKey:"web.settings.sec.model.capabilities.desc",keys:["modelCapabilities"]}],context:[{id:"context.window",titleKey:"web.settings.sec.context.window",descKey:"web.settings.sec.context.window.desc",keys:["contextWindow","contextBudget.systemPrompt","contextBudget.responseReserve"]},{id:"context.compaction",titleKey:"web.settings.sec.context.compaction",descKey:"web.settings.sec.context.compaction.desc",keys:["contextBudget.compactionThreshold","contextBudget.compactionMinLoad","contextBudget.policy","contextBudget.compactionSummary","contextBudget.overflowCooldown","contextBudget.toolResultKeep","contextBudget.calibrationWarmup","contextBudget.ratioFloor"]},{id:"context.instructions",titleKey:"web.settings.sec.context.instructions",descKey:"web.settings.sec.context.instructions.desc",keys:["instructions.summarize"]},{id:"context.indexer",titleKey:"web.settings.sec.context.indexer",descKey:"web.settings.sec.context.indexer.desc",keys:["indexer.maxFiles","indexer.respectGitignore","indexer.mapTokenBudget"]},{id:"context.log",titleKey:"web.settings.sec.context.log",descKey:"web.settings.sec.context.log.desc",keys:["contextLog.enabled","contextLog.redact"]}],reasoning:[{id:"reasoning.display",titleKey:"web.settings.sec.reasoning.display",keys:["showReasoning"]},{id:"reasoning.effort",titleKey:"web.settings.sec.reasoning.effort",descKey:"web.settings.sec.reasoning.effort.desc",keys:["reasoning.mode","reasoning.min","reasoning.max","reasoning.baseline","reasoning.overrideCooldown"]}],agent:[{id:"agent.moe",titleKey:"web.settings.sec.agent.moe",descKey:"web.settings.sec.agent.moe.desc",keys:["moe.enabled","moe.maxReplanCycles","orchestrator.model","orchestrator.provider","orchestrator.contextWindow","experts"]},{id:"agent.critic",titleKey:"web.settings.sec.agent.critic",descKey:"web.settings.sec.agent.critic.desc",keys:["critic.enabled","critic.model","critic.provider","critic.tools","critic.maxCalls","critic.maxRepairCycles","critic.timeoutMs"]},{id:"agent.tools",titleKey:"web.settings.sec.agent.tools",descKey:"web.settings.sec.agent.tools.desc",keys:["tools.enableOnDemand","tools.defaultTags","tools.grepEngine","skills.budget"]},{id:"agent.subagent",titleKey:"web.settings.sec.agent.subagent",descKey:"web.settings.sec.agent.subagent.desc",keys:["subagent.resultMode","subagent.maxSummaryChars","subagent.maxParallelChunkQueries","subagent.stableSystemPrompt","subagent.timeoutMs"]},{id:"agent.hallucination",titleKey:"web.settings.sec.agent.hallucination",descKey:"web.settings.sec.agent.hallucination.desc",keys:["hallucination.judge.enabled"]}],network:[{id:"network.web",titleKey:"web.settings.sec.network.web",descKey:"web.settings.sec.network.web.desc",keys:["webSearch.enabled"]},{id:"network.error",titleKey:"web.settings.sec.network.error",descKey:"web.settings.sec.network.error.desc",keys:["errorWebSearch.enabled","errorWebSearch.threshold","errorWebSearch.maxResults","errorWebSearch.maxQueryChars","errorWebSearch.maxSearchesPerSession","errorWebSearch.requestTimeoutMs"]}],browser:[{id:"browser.main",titleKey:"web.settings.sec.browser.main",keys:["browser.enabled","browser.headless"]},{id:"browser.limits",titleKey:"web.settings.sec.browser.limits",descKey:"web.settings.sec.browser.limits.desc",keys:["browser.maxElements","browser.maxContentChars","browser.maxConsoleEntries","browser.maxConsoleLineChars"]},{id:"browser.viewport",titleKey:"web.settings.sec.browser.viewport",keys:["browser.viewportWidth","browser.viewportHeight","browser.navigationTimeout"]}],sessions:[{id:"sessions.main",titleKey:"web.settings.sec.sessions.main",descKey:"web.settings.sec.sessions.main.desc",keys:["session.autoSave","session.autoName","session.maxSessions","session.isolateMemory"]},{id:"sessions.isolation",titleKey:"web.settings.sec.sessions.isolation",descKey:"web.settings.sec.sessions.isolation.desc",keys:["sessionIsolation.enabled","sessionIsolation.isolatePlugins","sessionIsolation.isolateTempFiles"]}],ui:[{id:"ui.chat",titleKey:"web.settings.sec.ui.chat",descKey:"web.settings.sec.ui.chat.desc",keys:["ui.fontSize","ui.activityRail","ui.spinner","ui.showContextStats","ui.showCompaction"]},{id:"ui.images",titleKey:"web.settings.sec.ui.images",descKey:"web.settings.sec.ui.images.desc",keys:["images.maxCount","images.maxBytes"]}],security:[{id:"security.switches",titleKey:"web.settings.sec.security.switches",descKey:"web.settings.sec.security.switches.desc",keys:["security.enabled","security.bash.enabled","security.bash.blockDangerousFlags","security.paths.enabled","security.contentScan.enabled","security.network.enabled","security.sessionEncryption.enabled"]},{id:"security.limits",titleKey:"web.settings.sec.security.limits",descKey:"web.settings.sec.security.limits.desc",keys:["security.maxRecursionDepth","security.maxFileOperations","security.rateLimits.maxRequestsPerMinute","security.rateLimits.maxParallelTasks","security.network.requestTimeout","security.network.maxResponseSize"]},{id:"security.bash",titleKey:"web.settings.sec.security.bash",descKey:"web.settings.sec.security.bash.desc",keys:["security.bash.blacklist","security.bash.whitelist","security.bash.dangerousFlags","security.bash.dangerousOperators"]},{id:"security.paths",titleKey:"web.settings.sec.security.paths",descKey:"web.settings.sec.security.paths.desc",keys:["security.paths.denied","security.paths.allowed"]},{id:"security.network",titleKey:"web.settings.sec.security.network",descKey:"web.settings.sec.security.network.desc",keys:["security.network.deniedDomains","security.network.allowedDomains"]},{id:"security.scan",titleKey:"web.settings.sec.security.scan",descKey:"web.settings.sec.security.scan.desc",keys:["security.contentScan.dangerousPatterns"]},{id:"security.audit",titleKey:"web.settings.sec.security.audit",descKey:"web.settings.sec.security.audit.desc",keys:["security.auditNotifier.enabled","security.auditNotifier.filePath","security.auditNotifier.webhookUrl","security.auditNotifier.webhookTimeout","security.auditNotifier.minSeverity","security.auditNotifier.maxRetries","security.auditNotifier.eventTypes"]},{id:"security.encryption",titleKey:"web.settings.sec.security.encryption",descKey:"web.settings.sec.security.encryption.desc",keys:["security.sessionEncryption.encryptHistory","security.sessionEncryption.encryptSessionLog","security.sessionEncryption.keyPath"]}],advanced:[{id:"advanced.diagnostics",titleKey:"web.settings.sec.advanced.diagnostics",descKey:"web.settings.sec.advanced.diagnostics.desc",keys:["logLevel","version"]},{id:"advanced.retry",titleKey:"web.settings.sec.advanced.retry",descKey:"web.settings.sec.advanced.retry.desc",keys:["retry.maxRetries","retry.baseDelay","retry.maxDelay","retry.maxStreamRetries","retry.noDataTimeoutMs"]},{id:"advanced.service",titleKey:"web.settings.sec.advanced.service",descKey:"web.settings.sec.advanced.service.desc",keys:["pricing.enabled","pricing.overrides","updater.enabled","updater.checkOnStart","updater.autoInstall","updater.intervalMs"]}],plugins:[{id:"plugins.registry",titleKey:"web.settings.sec.plugins.registry",descKey:"web.settings.sec.plugins.registry.desc",keys:["plugins.disabled","plugins.maxDrafts"]},{id:"plugins.lsp",titleKey:"web.settings.sec.plugins.lsp",descKey:"web.settings.sec.plugins.lsp.desc",keys:["lsp.enabled","lsp.offline"]}]};export function keyToPanel(){const i=new Map;for(const[e,s]of Object.entries(PANEL_SECTIONS))for(const r of s)for(const l of r.keys)i.set(l,e);return i}
@@ -1 +1 @@
1
- import{el as i,icon as T,link as k,inlineTextNodes as q,makeToggle as J}from"../dom.js";import{api as w}from"../api.js";import{t as s}from"../i18n.js";import{settings as l,getPath as D,THEME_KEY as N}from"../store.js";import{setIndicator as C}from"../dialog.js";import{controlFor as U,PANEL_SECTIONS as E}from"./controls.js";import{postConfig as j}from"./write.js";import{openSubDialog as O,closeSubDialog as _}from"./subdialog.js";import{mcpLiteralField as v,providerInput as x,providerSelect as H,providerCheck as P}from"./form.js";export function configLabel(e){const n="config.key."+e.key,t=s(n);return t===n?e.key:t}export function enumLabel(e){const n="config.enum."+e,t=s(n);return t===n?e:t}export function defFor(e){return l.registry.find(n=>n.key===e)||null}export function row(e,n,t){const d=i("div","row"),o=i("div","row-label");if(o.appendChild(i("span","row-name",e)),t&&o.appendChild(i("span","row-desc",t)),d.appendChild(o),typeof n=="string"){const a=i("span","val",n);a.title=n,d.appendChild(a)}else n&&d.appendChild(n);return d}export function descFor(e){const n="config.desc."+e,t=s(n);return t===n?"":t}function B(){const e=l.providers||{},n=l.config&&l.config.provider||{},d=(Array.isArray(e.entries)&&e.entries.length?e.entries:Array.isArray(n.entries)?n.entries:[]).map(a=>a.label||a.type).filter(a=>!!a),o=e.active||n.active;return o&&d.indexOf(o)===-1&&d.unshift(o),d}function Y(e,n){const t=e.readOnly&&e.value!==void 0?e.value:l.config?D(l.config,n):void 0;return U(e,t,{label:configLabel(e),enumLabel,emptyLabel:s("config.enum.none"),modelOptions:l.models,providerOptions:B(),fieldLabel:d=>{const o="config.field."+d,a=s(o);return a===o?d:a},post:d=>{j(n,d,!1)}})}function z(e){const n=i("div","settings-section"),t=i("div","sec-head");if(t.appendChild(i("span","sec-title",s(e.titleKey))),n.appendChild(t),e.descKey){const o=s(e.descKey);o!==e.descKey&&n.appendChild(i("div","sec-desc",o))}const d=i("div","sec-body");return e.keys.forEach(o=>{const a=defFor(o);a&&d.appendChild(row(configLabel(a),Y(a,o),descFor(a.key)))}),n.appendChild(d),n}export function renderSections(e,n){const t=document.querySelector('[data-panel="'+e+'"]');t&&n.forEach(d=>t.appendChild(z(d)))}export function renderPanel(e){const n=document.querySelector('[data-panel="'+e+'"]');n&&(n.textContent="",renderSections(e,E[e]||[]))}export function settingsSection(e){const n=i("div","settings-section"),t=i("div","sec-head");t.appendChild(i("span","sec-title",s(e))),n.appendChild(t);const d=i("div","sec-body");return n.appendChild(d),{el:n,head:t,body:d}}export function chip(e,n,t){const d=i("button","chip"+(n?" "+n:""),e);return d.type="button",d.addEventListener("click",t),d}export function placeholderFor(e,n){const t=i("div","placeholder");return e===void 0?t.textContent=s("web.settings.loading"):t.textContent=n,t}export function groupHeader(e,n){const t=i("div","row");return t.appendChild(i("span","val accent",e)),n!=null&&t.appendChild(i("span","val dim",String(n))),t}export function currentTheme(){return localStorage.getItem(N)||"auto"}function I(){const e=document.querySelector('[data-panel="ui"]');if(!e)return;e.textContent="";const n=i("span","seg");["dark","light","auto"].forEach(r=>{const p=i("button",currentTheme()===r?"on":"",r);p.type="button",p.setAttribute("aria-pressed",currentTheme()===r?"true":"false"),p.addEventListener("click",()=>{n.querySelectorAll("button").forEach(u=>{u.classList.remove("on"),u.setAttribute("aria-pressed","false")}),p.classList.add("on"),p.setAttribute("aria-pressed","true"),applyTheme(r)}),n.appendChild(p)});const t=i("div","settings-section"),d=i("div","sec-head");d.appendChild(i("span","sec-title",s("web.settings.sec.ui.theme"))),t.appendChild(d);const o=s("web.settings.sec.ui.theme.desc");o!=="web.settings.sec.ui.theme.desc"&&t.appendChild(i("div","sec-desc",o));const a=i("div","sec-body");a.appendChild(row(s("web.settings.theme"),n)),t.appendChild(a),e.appendChild(t),renderSections("ui",E.ui||[])}export function applyTheme(e){localStorage.setItem(N,e);const n=e==="light"||e==="auto"&&window.matchMedia&&window.matchMedia("(prefers-color-scheme: light)").matches;document.body.classList.toggle("light",!!n),I()}window.matchMedia&&window.matchMedia("(prefers-color-scheme: light)").addEventListener("change",()=>{currentTheme()==="auto"&&applyTheme("auto")});function G(){const e=document.querySelector('[data-panel="security"]');if(!e)return;e.textContent="",renderSections("security",E.security||[]);const n=i("div","settings-section"),t=i("div","sec-head");t.appendChild(i("span","sec-title",s("web.settings.sec.security.access"))),n.appendChild(t);const d=i("div","sec-body");d.appendChild(row(s("web.settings.web_token"),i("span","val dim",l.webToken||s("web.settings.web_token_none")),s("config.desc.webToken")));const o=i("div","placeholder");o.appendChild(i("span","tag",s("web.settings.terminal_tag"))),o.appendChild(document.createTextNode(" "+s("web.settings.security_note"))),d.appendChild(o),n.appendChild(d),e.appendChild(n)}const Q=["conventions","decisions","errors","facts"];function V(){const e=i("div","pform"),n=i("div","pform-grid"),t=i("select");t.setAttribute("aria-label",s("web.settings.memory_category")),Q.forEach(a=>t.appendChild(i("option","",a))),t.value="facts",n.appendChild(v(s("web.settings.memory_category"),t)),e.appendChild(n);const d=i("textarea");d.rows=5,d.placeholder=s("web.settings.new_memory"),d.value="",e.appendChild(v(s("web.settings.new_memory"),d));const o=i("div","pform-actions");o.appendChild(k(s("web.settings.save"),"",async()=>{const a=d.value.trim();if(!a){d.focus();return}const r=await w("/api/memory",{method:"POST",body:{category:t.value,text:a}});r.ok&&r.data&&r.data.ok?(_(),await loadMemory()):C(s("web.settings.add_failed"),!0)})),o.appendChild(k(s("web.settings.cancel"),"dim",()=>_())),e.appendChild(o),O(s("web.settings.memory_add_title"),e,()=>F())}function F(){const e=document.querySelector('[data-panel="memory"]');if(!e)return;if(e.textContent="",l.memory===void 0||l.memory===null){e.appendChild(placeholderFor(l.memory,s("web.settings.memory_unavailable")));return}const n=l.memory,t=i("button","sec-add");t.type="button",t.appendChild(T("plus")),t.appendChild(i("span","",s("web.settings.add"))),t.addEventListener("click",()=>V());const d=i("div","sec-head");d.appendChild(i("span","sec-title",s("web.settings.sec.memory.add"))),d.appendChild(t);const o=i("div","settings-section");o.appendChild(d),e.appendChild(o);const a=i("input","searchbox");a.placeholder=s("web.settings.search_memory"),a.setAttribute("aria-label",s("web.settings.search_memory")),e.appendChild(a);const r=i("div","settings-list");e.appendChild(r);const p=(h,g)=>{const c=i("div","mem-cat");return c.appendChild(i("span","",h)),g!=null&&c.appendChild(i("span","n",String(g))),c},u=(h,g)=>{const c=i("div","mem-entry"),m=i("span","mem-text");return m.appendChild(q(String(h??""))),m.title=String(h??""),c.appendChild(m),g&&c.appendChild(k(s("web.settings.forget"),"mem-del",g)),c},b=()=>{r.textContent="";const h=a.value.trim().toLowerCase();let g=!1;(n.categories||[]).forEach(m=>{const f=(m.entries||[]).filter(y=>!h||String(y.text).toLowerCase().indexOf(h)!==-1);f.length&&(g=!0,r.appendChild(p(m.name,f.length)),f.forEach(y=>{r.appendChild(u(y.text,async()=>{(await w("/api/memory/"+encodeURIComponent(m.name)+"/"+y.n,{method:"DELETE"})).ok?await loadMemory():C(s("web.settings.forget_failed"),!0)}))}))});const c=Object.entries(n.preferences||{});if(c.length&&!h&&(g=!0,r.appendChild(p(s("web.settings.preferences"),c.length)),c.forEach(([m,f])=>{r.appendChild(u(m+" = "+f))})),!g){const m=i("div","placeholder");m.textContent=h?s("web.settings.no_matches"):s("web.settings.no_memory"),r.appendChild(m)}};a.addEventListener("input",b),b()}function M(){const e=document.querySelector('[data-panel="skills"]');if(!e)return;if(e.textContent="",l.skills===void 0||l.skills===null){e.appendChild(placeholderFor(l.skills,s("web.settings.skills_unavailable")));return}if(!l.skills.length){const t=i("div","placeholder");t.textContent=s("web.settings.no_skills"),e.appendChild(t);return}const n=i("div","settings-list");l.skills.forEach(t=>{const d=i("div","skill-item"),o=i("div","skill-head");o.appendChild(i("span",t.enabled?"g":"dim",t.enabled?"✓":"○"));const a=i("span","name",t.name);if(a.title=t.name,o.appendChild(a),o.appendChild(i("span","st",t.enabled?s("web.settings.enabled"):s("web.settings.available"))),d.appendChild(o),t.source){const r=i("div","skill-src",t.source);r.title=t.source,d.appendChild(r)}n.appendChild(d)}),e.appendChild(n)}function S(){const e=document.querySelector('[data-panel="plugins"]');if(!e)return;if(e.textContent="",l.pluginsData===void 0||l.pluginsData===null){e.appendChild(placeholderFor(l.pluginsData,s("web.settings.plugins_unavailable")));return}const n=l.pluginsData,t=i("div","settings-list");if(t.appendChild(groupHeader(s("web.settings.plugins_header"),(n.plugins||[]).length)),!(n.plugins||[]).length){const a=i("div","placeholder");a.textContent=s("web.settings.no_plugins"),t.appendChild(a)}(n.plugins||[]).forEach(a=>{const r=i("div","list-line");r.appendChild(i("span","g","✓"));const p=i("span","name",a.name);if(p.title=a.name,r.appendChild(p),a.version&&r.appendChild(i("span","src","v"+a.version)),a.source){const u=i("span","src",a.source);u.title=a.source,r.appendChild(u)}a.builtin&&r.appendChild(i("span","src",s("web.settings.builtin"))),r.appendChild(i("span","st",a.enabled===!1?s("web.settings.disabled"):s("web.settings.enabled"))),t.appendChild(r)});const d=i("div","settings-note");d.textContent=s("web.settings.plugins_note"),t.appendChild(d),t.appendChild(groupHeader(s("web.settings.mcp_servers"),(n.mcp||[]).length));const o=i("button","sec-add");if(o.type="button",o.appendChild(T("plus")),o.appendChild(i("span","",s("web.settings.mcp_add"))),o.addEventListener("click",()=>R("add",null)),t.appendChild(o),!(n.mcp||[]).length){const a=i("div","placeholder");a.textContent=s("web.settings.no_mcp"),t.appendChild(a)}if((n.mcp||[]).forEach(a=>{const r=i("div","list-line"),p=a.status!=="disabled",u=J(p,h=>{w("/api/mcp/"+encodeURIComponent(a.id||a.name),{method:"POST",body:{enabled:h}}).then(async g=>{g.ok&&g.data&&g.data.ok?(C(s("web.settings.mcp_saved"),!1),await loadPlugins()):C(s("web.settings.save_failed"),!0)})});u.title=p?s("web.settings.mcp_disable"):s("web.settings.mcp_enable"),u.setAttribute("aria-label",u.title),r.appendChild(u);const b=i("span","name",a.name);b.title=a.name,r.appendChild(b),r.appendChild(i("span","st",a.status||"—")),r.appendChild(chip(s("web.settings.edit"),"",()=>R("edit",a))),r.appendChild(chip(s("web.settings.delete"),"danger",async()=>{const h=await w("/api/mcp/"+encodeURIComponent(a.id||a.name),{method:"DELETE"});h.ok&&h.data&&h.data.ok?(C(s("web.settings.mcp_saved"),!1),await loadPlugins()):C(h.data&&h.data.error||s("web.settings.delete_failed"),!0)})),t.appendChild(r)}),l.mcpForm&&t.appendChild(K()),(n.mcp||[]).length){const a=i("div","settings-note");a.textContent=s("web.settings.mcp_note"),t.appendChild(a)}Z(t),e.appendChild(t),renderSections("plugins",E.plugins||[])}function K(){const e=l.mcpForm&&l.mcpForm.mode||"add",n=l.mcpForm&&l.mcpForm.entry||{},t=i("div","pform"),d=i("div","pform-grid"),o=x(n.name||"","text","my-server"),a=H(["stdio","sse","http"],n.transport||"stdio"),r=x(n.command||"","text","npx"),p=x(n.url||"","text","https://…");d.appendChild(v("name",o)),d.appendChild(v("transport",a)),d.appendChild(v("command",r)),d.appendChild(v("url",p)),t.appendChild(d);const u=i("details","pform-adv");u.appendChild(i("summary","",s("web.settings.provider_advanced")));const b=x(n.args?JSON.stringify(n.args):"","text",'["--stdio"]'),h=x(n.timeout!=null?String(n.timeout):"","number","30000"),g=P(n.enabled!==!1);u.appendChild(v("args (JSON)",b)),u.appendChild(v("timeout (ms)",h));const c=Array.isArray(n.envKeys)?n.envKeys:[],m=Array.isArray(n.headerKeys)?n.headerKeys:[],f=i("textarea");f.placeholder=c.length?"stored: "+c.join(", ")+" — blank keeps":'{"TOKEN": "…"}';const y=i("textarea");y.placeholder=m.length?"stored: "+m.join(", ")+" — blank keeps":'{"Authorization": "…"}',u.appendChild(v("env (JSON)",f)),u.appendChild(v("headers (JSON)",y)),u.appendChild(v("enabled",g)),t.appendChild(u);const L={name:o,transport:a,command:r,url:p,args:b,timeout:h,env:f,headers:y,enabled:g},A=i("div","pform-actions");return A.appendChild(k(s("web.settings.save"),"",()=>{X(L,e,n)})),A.appendChild(k(s("web.settings.cancel"),"dim",()=>_())),t.appendChild(A),t}function R(e,n){l.mcpForm={mode:e,entry:n||null},O(s(e==="edit"?"web.settings.mcp_edit_title":"web.settings.mcp_add"),K(),()=>{l.mcpForm=null,S(),loadPlugins()})}function W(e){const n=e.trim();if(!n)return{present:!1,value:null};let t=null;try{t=JSON.parse(n)}catch{return{present:!0,value:null}}return!t||typeof t!="object"||Array.isArray(t)?{present:!0,value:null}:Object.values(t).every(d=>typeof d=="string")?{present:!0,value:t}:{present:!0,value:null}}async function X(e,n,t){const d=e.name.value.trim(),o=e.transport.value||"stdio",a=e.command.value.trim(),r=e.url.value.trim();if(!d||(o==="stdio"?!a:!r)){C(s("web.settings.mcp_required"),!0);return}const p={name:d,transport:o};a&&(p.command=a),r&&(p.url=r);const u=e.args.value.trim();if(u){let c=null;try{c=JSON.parse(u)}catch{c=null}if(!Array.isArray(c)||!c.every(m=>typeof m=="string")){C(s("web.settings.mcp_invalid"),!0);return}p.args=c}for(const c of["env","headers"]){const m=W(e[c].value);if(m.present&&!m.value){C(s("web.settings.mcp_invalid"),!0);return}m.present&&(p[c]=m.value)}const b=e.timeout.value.trim();if(b){const c=Number(b);if(!Number.isInteger(c)||c<1e3||c>3e5){C(s("web.settings.mcp_invalid"),!0);return}p.timeout=c}p.enabled=e.enabled.checked;const h=n==="edit"?"/api/mcp/"+encodeURIComponent(t.id||t.name):"/api/mcp",g=await w(h,{method:n==="edit"?"PUT":"POST",body:p});g.ok&&g.data&&g.data.ok?(C(s("web.settings.mcp_saved"),!1),_()):C(g.data&&g.data.error||s("web.settings.save_failed"),!0)}function Z(e){const n=l.lsp;if(e.appendChild(groupHeader(s("web.settings.lsp_servers"),Array.isArray(n)?n.length:null)),n==null){e.appendChild(placeholderFor(n,s("web.settings.lsp_unavailable")));return}if(!n.length){const t=i("div","placeholder");t.textContent=s("web.settings.no_lsp"),e.appendChild(t)}if(n.forEach(t=>{const d=i("div","list-line");d.appendChild(i("span",t.enabled?"g":"dim",t.enabled?"✓":"○"));const o=i("span","name",t.lang);o.title=t.lang,d.appendChild(o);const a=[t.command,t.timeout!=null?t.timeout+" ms":null].filter(Boolean).join(" · ");a&&d.appendChild(i("span","src",a)),d.appendChild(i("span","st",t.enabled?s("web.settings.enabled"):s("web.settings.disabled"))),d.appendChild(chip(s("web.settings.edit"),"",()=>$(t))),e.appendChild(d)}),n.length){const t=i("div","settings-note");t.textContent=s("web.settings.lsp_note"),e.appendChild(t)}}function $(e){l.lspForm={lang:e.lang,entry:e},O(e.lang,ee(),()=>{l.lspForm=null,S(),loadLsp()})}function ee(){const e=l.lspForm&&l.lspForm.entry||{},n=l.lspForm&&l.lspForm.lang||e.lang||"",t=i("div","pform"),d=i("div","pform-grid"),o=x(e.command||"","text","npx"),a=x(e.timeout!=null?String(e.timeout):"","number","30000"),r=P(e.enabled!==!1);d.appendChild(v("command",o)),d.appendChild(v("timeout (ms)",a)),d.appendChild(v("enabled",r)),t.appendChild(d);const p=i("textarea");p.value=e.args?JSON.stringify(e.args):"",p.placeholder='["--stdio"]',t.appendChild(v("args (JSON)",p));const u=i("div","pform-actions");return u.appendChild(k(s("web.settings.save"),"",async()=>{const b={},h=o.value.trim();h&&(b.command=h);const g=a.value.trim();if(g){const f=Number(g);if(!Number.isInteger(f)||f<1e3||f>3e5){C(s("web.settings.provider_invalid"),!0);return}b.timeout=f}const c=p.value.trim();if(c){let f=null;try{f=JSON.parse(c)}catch{f=null}if(!Array.isArray(f)||!f.every(y=>typeof y=="string")){C(s("web.settings.provider_invalid"),!0);return}b.args=f}b.enabled=r.checked;const m=await w("/api/lsp/"+encodeURIComponent(n),{method:"PUT",body:b});m.ok&&m.data&&m.data.ok?(C(s("web.settings.mcp_saved"),!1),_()):C(m.data&&m.data.error||s("web.settings.save_failed"),!0)})),u.appendChild(k(s("web.settings.cancel"),"dim",()=>_())),t.appendChild(u),t}export async function loadLsp(){const e=await w("/api/lsp");l.lsp=e.ok&&e.data&&Array.isArray(e.data.servers)?e.data.servers:null,S()}export async function loadMemory(){const e=await w("/api/memory");l.memory=e.ok&&e.data?e.data:null,F()}export async function loadSkills(){const e=await w("/api/skills");l.skills=e.ok&&e.data&&Array.isArray(e.data.skills)?e.data.skills:null,M()}export async function loadPlugins(){const e=await w("/api/plugins");l.pluginsData=e.ok&&e.data?{plugins:e.data.plugins||[],mcp:e.data.mcp||[]}:null,S()}export{I as renderUiPanel,F as renderMemoryPanel,M as renderSkillsPanel,S as renderPluginsPanel,G as renderSecurityPanel};
1
+ import{el as i,icon as O,link as k,inlineTextNodes as q,makeToggle as L}from"../dom.js";import{api as y}from"../api.js";import{t as a}from"../i18n.js";import{settings as l,getPath as J,THEME_KEY as P}from"../store.js";import{setIndicator as b}from"../dialog.js";import{controlFor as U,PANEL_SECTIONS as E}from"./controls.js";import{postConfig as j}from"./write.js";import{openSubDialog as T,closeSubDialog as x}from"./subdialog.js";import{mcpLiteralField as v,providerInput as _,providerSelect as H,providerCheck as I}from"./form.js";export function configLabel(e){const n="config.key."+e.key,t=a(n);return t===n?e.key:t}export function enumLabel(e){const n="config.enum."+e,t=a(n);return t===n?e:t}export function defFor(e){return l.registry.find(n=>n.key===e)||null}export function row(e,n,t){const s=i("div","row"),o=i("div","row-label");if(o.appendChild(i("span","row-name",e)),t&&o.appendChild(i("span","row-desc",t)),s.appendChild(o),typeof n=="string"){const r=i("span","val",n);r.title=n,s.appendChild(r)}else n&&s.appendChild(n);return s}export function descFor(e){const n="config.desc."+e,t=a(n);return t===n?"":t}function B(){const e=l.providers||{},n=l.config&&l.config.provider||{},s=(Array.isArray(e.entries)&&e.entries.length?e.entries:Array.isArray(n.entries)?n.entries:[]).map(r=>r.label||r.type).filter(r=>!!r),o=e.active||n.active;return o&&s.indexOf(o)===-1&&s.unshift(o),s}function Y(e,n){const t=e.readOnly&&e.value!==void 0?e.value:l.config?J(l.config,n):void 0;return U(e,t,{label:configLabel(e),enumLabel,emptyLabel:a("config.enum.none"),modelOptions:l.models,providerOptions:B(),fieldLabel:s=>{const o="config.field."+s,r=a(o);return r===o?s:r},post:s=>{j(n,s,!1)}})}function z(e){const n=i("div","settings-section"),t=i("div","sec-head");if(t.appendChild(i("span","sec-title",a(e.titleKey))),n.appendChild(t),e.descKey){const o=a(e.descKey);o!==e.descKey&&n.appendChild(i("div","sec-desc",o))}const s=i("div","sec-body");return e.keys.forEach(o=>{const r=defFor(o);r&&s.appendChild(row(configLabel(r),Y(r,o),descFor(r.key)))}),n.appendChild(s),n}export function renderSections(e,n){const t=document.querySelector('[data-panel="'+e+'"]');t&&n.forEach(s=>t.appendChild(z(s)))}export function renderPanel(e){const n=document.querySelector('[data-panel="'+e+'"]');n&&(n.textContent="",renderSections(e,E[e]||[]))}export function settingsSection(e){const n=i("div","settings-section"),t=i("div","sec-head");t.appendChild(i("span","sec-title",a(e))),n.appendChild(t);const s=i("div","sec-body");return n.appendChild(s),{el:n,head:t,body:s}}export function chip(e,n,t){const s=i("button","chip"+(n?" "+n:""),e);return s.type="button",s.addEventListener("click",t),s}export function placeholderFor(e,n){const t=i("div","placeholder");return e===void 0?t.textContent=a("web.settings.loading"):t.textContent=n,t}export function groupHeader(e,n){const t=i("div","row");return t.appendChild(i("span","val accent",e)),n!=null&&t.appendChild(i("span","val dim",String(n))),t}export function currentTheme(){return localStorage.getItem(P)||"auto"}function M(){const e=document.querySelector('[data-panel="ui"]');if(!e)return;e.textContent="";const n=i("span","seg");["dark","light","auto"].forEach(d=>{const p=i("button",currentTheme()===d?"on":"",d);p.type="button",p.setAttribute("aria-pressed",currentTheme()===d?"true":"false"),p.addEventListener("click",()=>{n.querySelectorAll("button").forEach(g=>{g.classList.remove("on"),g.setAttribute("aria-pressed","false")}),p.classList.add("on"),p.setAttribute("aria-pressed","true"),applyTheme(d)}),n.appendChild(p)});const t=i("div","settings-section"),s=i("div","sec-head");s.appendChild(i("span","sec-title",a("web.settings.sec.ui.theme"))),t.appendChild(s);const o=a("web.settings.sec.ui.theme.desc");o!=="web.settings.sec.ui.theme.desc"&&t.appendChild(i("div","sec-desc",o));const r=i("div","sec-body");r.appendChild(row(a("web.settings.theme"),n)),t.appendChild(r),e.appendChild(t),renderSections("ui",E.ui||[])}export function applyTheme(e){localStorage.setItem(P,e);const n=e==="light"||e==="auto"&&window.matchMedia&&window.matchMedia("(prefers-color-scheme: light)").matches;document.body.classList.toggle("light",!!n),M()}window.matchMedia&&window.matchMedia("(prefers-color-scheme: light)").addEventListener("change",()=>{currentTheme()==="auto"&&applyTheme("auto")});function G(){const e=document.querySelector('[data-panel="security"]');if(!e)return;e.textContent="",renderSections("security",E.security||[]);const n=i("div","settings-section"),t=i("div","sec-head");t.appendChild(i("span","sec-title",a("web.settings.sec.security.access"))),n.appendChild(t);const s=i("div","sec-body");s.appendChild(row(a("web.settings.web_token"),i("span","val dim",l.webToken||a("web.settings.web_token_none")),a("config.desc.webToken")));const o=i("div","placeholder");o.appendChild(i("span","tag",a("web.settings.terminal_tag"))),o.appendChild(document.createTextNode(" "+a("web.settings.security_note"))),s.appendChild(o),n.appendChild(s),e.appendChild(n)}const Q=["conventions","decisions","errors","facts"];function V(){const e=i("div","pform"),n=i("div","pform-grid"),t=i("select");t.setAttribute("aria-label",a("web.settings.memory_category")),Q.forEach(r=>t.appendChild(i("option","",r))),t.value="facts",n.appendChild(v(a("web.settings.memory_category"),t)),e.appendChild(n);const s=i("textarea");s.rows=5,s.placeholder=a("web.settings.new_memory"),s.value="",e.appendChild(v(a("web.settings.new_memory"),s));const o=i("div","pform-actions");o.appendChild(k(a("web.settings.save"),"",async()=>{const r=s.value.trim();if(!r){s.focus();return}const d=await y("/api/memory",{method:"POST",body:{category:t.value,text:r}});d.ok&&d.data&&d.data.ok?(x(),await loadMemory()):b(a("web.settings.add_failed"),!0)})),o.appendChild(k(a("web.settings.cancel"),"dim",()=>x())),e.appendChild(o),T(a("web.settings.memory_add_title"),e,()=>N())}function N(){const e=document.querySelector('[data-panel="memory"]');if(!e)return;if(e.textContent="",l.memory===void 0||l.memory===null){e.appendChild(placeholderFor(l.memory,a("web.settings.memory_unavailable")));return}const n=l.memory,t=i("button","sec-add");t.type="button",t.appendChild(O("plus")),t.appendChild(i("span","",a("web.settings.add"))),t.addEventListener("click",()=>V());const s=i("div","sec-head");s.appendChild(i("span","sec-title",a("web.settings.sec.memory.add"))),s.appendChild(t);const o=i("div","settings-section");o.appendChild(s),e.appendChild(o);const r=i("input","searchbox");r.placeholder=a("web.settings.search_memory"),r.setAttribute("aria-label",a("web.settings.search_memory")),e.appendChild(r);const d=i("div","settings-list");e.appendChild(d);const p=(f,u)=>{const c=i("div","mem-cat");return c.appendChild(i("span","",f)),u!=null&&c.appendChild(i("span","n",String(u))),c},g=(f,u)=>{const c=i("div","mem-entry"),m=i("span","mem-text");return m.appendChild(q(String(f??""))),m.title=String(f??""),c.appendChild(m),u&&c.appendChild(k(a("web.settings.forget"),"mem-del",u)),c},h=()=>{d.textContent="";const f=r.value.trim().toLowerCase();let u=!1;(n.categories||[]).forEach(m=>{const C=(m.entries||[]).filter(w=>!f||String(w.text).toLowerCase().indexOf(f)!==-1);C.length&&(u=!0,d.appendChild(p(m.name,C.length)),C.forEach(w=>{d.appendChild(g(w.text,async()=>{(await y("/api/memory/"+encodeURIComponent(m.name)+"/"+w.n,{method:"DELETE"})).ok?await loadMemory():b(a("web.settings.forget_failed"),!0)}))}))});const c=Object.entries(n.preferences||{});if(c.length&&!f&&(u=!0,d.appendChild(p(a("web.settings.preferences"),c.length)),c.forEach(([m,C])=>{d.appendChild(g(m+" = "+C))})),!u){const m=i("div","placeholder");m.textContent=f?a("web.settings.no_matches"):a("web.settings.no_memory"),d.appendChild(m)}};r.addEventListener("input",h),h()}function D(){const e=document.querySelector('[data-panel="skills"]');if(!e)return;if(e.textContent="",l.skills===void 0||l.skills===null){e.appendChild(placeholderFor(l.skills,a("web.settings.skills_unavailable")));return}if(!l.skills.length){const t=i("div","placeholder");t.textContent=a("web.settings.no_skills"),e.appendChild(t);return}const n=i("div","settings-list");l.skills.forEach(t=>{const s=i("div","skill-item"),o=i("div","skill-head");o.appendChild(i("span",t.enabled?"g":"dim",t.enabled?"✓":"○"));const r=i("span","name",t.name);if(r.title=t.name,o.appendChild(r),o.appendChild(i("span","st",t.enabled?a("web.settings.enabled"):a("web.settings.available"))),s.appendChild(o),t.source){const d=i("div","skill-src",t.source);d.title=t.source,s.appendChild(d)}n.appendChild(s)}),e.appendChild(n)}async function W(){b(a("web.plugins.reloading"),!1);const e=await y("/api/reload/plugins",{method:"POST"});if(!e.ok||!e.data||e.data.ok!==!0){b(a("web.plugins.reload_failed"),!0);return}const n=e.data.reload||{},t=n.plugins||{},s=n.skills||{},o=[a("web.plugins.reload_done",{loaded:String(t.loaded??0),unloaded:String(t.unloaded??0),failed:String(t.failed??0)})];(Number(s.added)>0||Number(s.removed)>0)&&o.push(a("web.plugins.reload_skills",{added:String(s.added??0),removed:String(s.removed??0)})),b(o.join(" · "),Number(t.failed)>0),Number(t.staleTs)>0&&b(a("web.plugins.reload_stale",{count:String(t.staleTs)}),!0),await loadPlugins()}async function X(e,n){const t=await y("/api/plugins/"+encodeURIComponent(e),{method:"POST",body:{enabled:n}});if(!t.ok||!t.data||t.data.ok!==!0){b(a("web.plugins.toggle_failed"),!0);return}l.pluginsData={plugins:t.data.plugins||[],mcp:l.pluginsData&&l.pluginsData.mcp||[]},S()}function S(){const e=document.querySelector('[data-panel="plugins"]');if(!e)return;if(e.textContent="",l.pluginsData===void 0||l.pluginsData===null){e.appendChild(placeholderFor(l.pluginsData,a("web.settings.plugins_unavailable")));return}const n=l.pluginsData,t=i("div","settings-list");if(t.appendChild(groupHeader(a("web.settings.plugins_header"),(n.plugins||[]).length)),!(n.plugins||[]).length){const d=i("div","placeholder");d.textContent=a("web.settings.no_plugins"),t.appendChild(d)}(n.plugins||[]).forEach(d=>{const p=i("div","list-line");p.appendChild(i("span","g",d.enabled===!1?"–":"✓"));const g=i("span","name",d.name);if(g.title=d.name,p.appendChild(g),d.version&&p.appendChild(i("span","src","v"+d.version)),d.source){const h=i("span","src",d.source);h.title=d.source,p.appendChild(h)}d.builtin&&p.appendChild(i("span","src",a("web.settings.builtin"))),p.appendChild(L(d.enabled!==!1,()=>{X(d.name,d.enabled===!1)})),t.appendChild(p)});const s=i("div","settings-note");s.textContent=a("web.settings.plugins_note"),t.appendChild(s);const o=i("button","sec-add");o.type="button",o.appendChild(O("refresh")),o.appendChild(i("span","",a("web.plugins.reload"))),o.addEventListener("click",()=>{W()}),t.appendChild(o),t.appendChild(groupHeader(a("web.settings.mcp_servers"),(n.mcp||[]).length));const r=i("button","sec-add");if(r.type="button",r.appendChild(O("plus")),r.appendChild(i("span","",a("web.settings.mcp_add"))),r.addEventListener("click",()=>R("add",null)),t.appendChild(r),!(n.mcp||[]).length){const d=i("div","placeholder");d.textContent=a("web.settings.no_mcp"),t.appendChild(d)}if((n.mcp||[]).forEach(d=>{const p=i("div","list-line"),g=d.status!=="disabled",h=L(g,u=>{y("/api/mcp/"+encodeURIComponent(d.id||d.name),{method:"POST",body:{enabled:u}}).then(async c=>{c.ok&&c.data&&c.data.ok?(b(a("web.settings.mcp_saved"),!1),await loadPlugins()):b(a("web.settings.save_failed"),!0)})});h.title=g?a("web.settings.mcp_disable"):a("web.settings.mcp_enable"),h.setAttribute("aria-label",h.title),p.appendChild(h);const f=i("span","name",d.name);f.title=d.name,p.appendChild(f),p.appendChild(i("span","st",d.status||"—")),p.appendChild(chip(a("web.settings.edit"),"",()=>R("edit",d))),p.appendChild(chip(a("web.settings.delete"),"danger",async()=>{const u=await y("/api/mcp/"+encodeURIComponent(d.id||d.name),{method:"DELETE"});u.ok&&u.data&&u.data.ok?(b(a("web.settings.mcp_saved"),!1),await loadPlugins()):b(u.data&&u.data.error||a("web.settings.delete_failed"),!0)})),t.appendChild(p)}),l.mcpForm&&t.appendChild(K()),(n.mcp||[]).length){const d=i("div","settings-note");d.textContent=a("web.settings.mcp_note"),t.appendChild(d)}ee(t),e.appendChild(t),renderSections("plugins",E.plugins||[])}function K(){const e=l.mcpForm&&l.mcpForm.mode||"add",n=l.mcpForm&&l.mcpForm.entry||{},t=i("div","pform"),s=i("div","pform-grid"),o=_(n.name||"","text","my-server"),r=H(["stdio","sse","http"],n.transport||"stdio"),d=_(n.command||"","text","npx"),p=_(n.url||"","text","https://…");s.appendChild(v("name",o)),s.appendChild(v("transport",r)),s.appendChild(v("command",d)),s.appendChild(v("url",p)),t.appendChild(s);const g=i("details","pform-adv");g.appendChild(i("summary","",a("web.settings.provider_advanced")));const h=_(n.args?JSON.stringify(n.args):"","text",'["--stdio"]'),f=_(n.timeout!=null?String(n.timeout):"","number","30000"),u=I(n.enabled!==!1);g.appendChild(v("args (JSON)",h)),g.appendChild(v("timeout (ms)",f));const c=Array.isArray(n.envKeys)?n.envKeys:[],m=Array.isArray(n.headerKeys)?n.headerKeys:[],C=i("textarea");C.placeholder=c.length?"stored: "+c.join(", ")+" — blank keeps":'{"TOKEN": "…"}';const w=i("textarea");w.placeholder=m.length?"stored: "+m.join(", ")+" — blank keeps":'{"Authorization": "…"}',g.appendChild(v("env (JSON)",C)),g.appendChild(v("headers (JSON)",w)),g.appendChild(v("enabled",u)),t.appendChild(g);const F={name:o,transport:r,command:d,url:p,args:h,timeout:f,env:C,headers:w,enabled:u},A=i("div","pform-actions");return A.appendChild(k(a("web.settings.save"),"",()=>{$(F,e,n)})),A.appendChild(k(a("web.settings.cancel"),"dim",()=>x())),t.appendChild(A),t}function R(e,n){l.mcpForm={mode:e,entry:n||null},T(a(e==="edit"?"web.settings.mcp_edit_title":"web.settings.mcp_add"),K(),()=>{l.mcpForm=null,S(),loadPlugins()})}function Z(e){const n=e.trim();if(!n)return{present:!1,value:null};let t=null;try{t=JSON.parse(n)}catch{return{present:!0,value:null}}return!t||typeof t!="object"||Array.isArray(t)?{present:!0,value:null}:Object.values(t).every(s=>typeof s=="string")?{present:!0,value:t}:{present:!0,value:null}}async function $(e,n,t){const s=e.name.value.trim(),o=e.transport.value||"stdio",r=e.command.value.trim(),d=e.url.value.trim();if(!s||(o==="stdio"?!r:!d)){b(a("web.settings.mcp_required"),!0);return}const p={name:s,transport:o};r&&(p.command=r),d&&(p.url=d);const g=e.args.value.trim();if(g){let c=null;try{c=JSON.parse(g)}catch{c=null}if(!Array.isArray(c)||!c.every(m=>typeof m=="string")){b(a("web.settings.mcp_invalid"),!0);return}p.args=c}for(const c of["env","headers"]){const m=Z(e[c].value);if(m.present&&!m.value){b(a("web.settings.mcp_invalid"),!0);return}m.present&&(p[c]=m.value)}const h=e.timeout.value.trim();if(h){const c=Number(h);if(!Number.isInteger(c)||c<1e3||c>3e5){b(a("web.settings.mcp_invalid"),!0);return}p.timeout=c}p.enabled=e.enabled.checked;const f=n==="edit"?"/api/mcp/"+encodeURIComponent(t.id||t.name):"/api/mcp",u=await y(f,{method:n==="edit"?"PUT":"POST",body:p});u.ok&&u.data&&u.data.ok?(b(a("web.settings.mcp_saved"),!1),x()):b(u.data&&u.data.error||a("web.settings.save_failed"),!0)}function ee(e){const n=l.lsp;if(e.appendChild(groupHeader(a("web.settings.lsp_servers"),Array.isArray(n)?n.length:null)),n==null){e.appendChild(placeholderFor(n,a("web.settings.lsp_unavailable")));return}if(!n.length){const t=i("div","placeholder");t.textContent=a("web.settings.no_lsp"),e.appendChild(t)}if(n.forEach(t=>{const s=i("div","list-line");s.appendChild(i("span",t.enabled?"g":"dim",t.enabled?"✓":"○"));const o=i("span","name",t.lang);o.title=t.lang,s.appendChild(o);const r=[t.command,t.timeout!=null?t.timeout+" ms":null].filter(Boolean).join(" · ");r&&s.appendChild(i("span","src",r)),s.appendChild(i("span","st",t.enabled?a("web.settings.enabled"):a("web.settings.disabled"))),s.appendChild(chip(a("web.settings.edit"),"",()=>te(t))),e.appendChild(s)}),n.length){const t=i("div","settings-note");t.textContent=a("web.settings.lsp_note"),e.appendChild(t)}}function te(e){l.lspForm={lang:e.lang,entry:e},T(e.lang,ne(),()=>{l.lspForm=null,S(),loadLsp()})}function ne(){const e=l.lspForm&&l.lspForm.entry||{},n=l.lspForm&&l.lspForm.lang||e.lang||"",t=i("div","pform"),s=i("div","pform-grid"),o=_(e.command||"","text","npx"),r=_(e.timeout!=null?String(e.timeout):"","number","30000"),d=I(e.enabled!==!1);s.appendChild(v("command",o)),s.appendChild(v("timeout (ms)",r)),s.appendChild(v("enabled",d)),t.appendChild(s);const p=i("textarea");p.value=e.args?JSON.stringify(e.args):"",p.placeholder='["--stdio"]',t.appendChild(v("args (JSON)",p));const g=i("div","pform-actions");return g.appendChild(k(a("web.settings.save"),"",async()=>{const h={},f=o.value.trim();f&&(h.command=f);const u=r.value.trim();if(u){const C=Number(u);if(!Number.isInteger(C)||C<1e3||C>3e5){b(a("web.settings.provider_invalid"),!0);return}h.timeout=C}const c=p.value.trim();if(c){let C=null;try{C=JSON.parse(c)}catch{C=null}if(!Array.isArray(C)||!C.every(w=>typeof w=="string")){b(a("web.settings.provider_invalid"),!0);return}h.args=C}h.enabled=d.checked;const m=await y("/api/lsp/"+encodeURIComponent(n),{method:"PUT",body:h});m.ok&&m.data&&m.data.ok?(b(a("web.settings.mcp_saved"),!1),x()):b(m.data&&m.data.error||a("web.settings.save_failed"),!0)})),g.appendChild(k(a("web.settings.cancel"),"dim",()=>x())),t.appendChild(g),t}export async function loadLsp(){const e=await y("/api/lsp");l.lsp=e.ok&&e.data&&Array.isArray(e.data.servers)?e.data.servers:null,S()}export async function loadMemory(){const e=await y("/api/memory");l.memory=e.ok&&e.data?e.data:null,N()}export async function loadSkills(){const e=await y("/api/skills");l.skills=e.ok&&e.data&&Array.isArray(e.data.skills)?e.data.skills:null,D()}export async function loadPlugins(){const e=await y("/api/plugins");l.pluginsData=e.ok&&e.data?{plugins:e.data.plugins||[],mcp:e.data.mcp||[]}:null,S()}export{M as renderUiPanel,N as renderMemoryPanel,D as renderSkillsPanel,S as renderPluginsPanel,G as renderSecurityPanel};
@@ -1 +1 @@
1
- import{icon as m}from"../dom.js";import{session as g}from"../store.js";import{t as f}from"../i18n.js";import{sb as e,TABS as a,ICON_NAME as b,paneEl as B,mqMobile as S,readStored as h,storeTab as v}from"./state.js";import{collapseDetail as d,renderList as u,renderDetail as x}from"./trace.js";import{sidebarMapState as y,sidebarMapIndicator as I}from"./map.js";import{renderLsp as E,sidebarLspState as p}from"./lsp.js";import{renderFilesTree as T,refreshFilesTree as k}from"./files.js";export function setSidebarTab(n,i=!0){a.includes(n)||(n="session"),i&&v(n);const t=n==="trace"&&S()?"session":n;t!==e.active&&d(),e.active=t,a.forEach(r=>{const s=B(r);s&&(s.hidden=r!==t);const l=e.el&&e.el.querySelector('.sb-tab[data-tab="'+r+'"]');if(l){const c=r===t;l.classList.toggle("on",c),l.setAttribute("aria-selected",c?"true":"false")}}),e.nameTextEl&&(e.nameTextEl.textContent=f("web.sidebar.tab_"+t));const o=e.nameEl&&e.nameEl.querySelector(".sb-ico");o&&(o.textContent="",o.appendChild(m(b[t]))),t==="lsp"&&p(),t==="files"&&T()}export function sidebarBusy(n){const i=e.el&&e.el.querySelector('.sb-tab[data-tab="trace"]');i&&(i.dataset.indicator=n?"live":"")}export function applySidebarI18n(){if(e.el){if(a.forEach(n=>{const i=e.el?.querySelector('.sb-tab[data-tab="'+n+'"]');if(i){const t=f("web.sidebar.tab_"+n);i.title=t,i.setAttribute("aria-label",t)}}),setSidebarTab(e.active,!1),u(),e.selected){const n=e.trace.find(i=>i.id===e.selected);n&&x(n)}y(g.host),E(),k()}}export function initSidebar(){if(e.el||(e.el=document.querySelector(".sb"),!e.el))return;const n=e.el;e.nameEl=document.getElementById("sbName"),e.nameTextEl=document.getElementById("sbNameText"),e.mapEl=document.getElementById("mapBody"),e.lspEl=document.getElementById("lspBody"),e.listEl=document.getElementById("traceList"),e.detailEl=document.getElementById("traceDetail"),e.detailGlyph=document.getElementById("detailGlyph"),e.detailTitle=document.getElementById("detailTitle"),e.detailBody=document.getElementById("detailBody"),e.detailClose=document.getElementById("detailClose"),e.detailClose&&e.detailClose.addEventListener("click",d),n.querySelectorAll(".sb-tab .sb-ico").forEach(t=>{const o=t.closest(".sb-tab")?.dataset.tab||"session";t.textContent="",t.appendChild(m(b[o]))}),n.querySelectorAll(".sb-tab").forEach(t=>{t.addEventListener("click",()=>setSidebarTab(t.dataset.tab||"session")),t.addEventListener("keydown",o=>{if(o.key!=="ArrowLeft"&&o.key!=="ArrowRight")return;o.preventDefault();const r=a.indexOf(t.dataset.tab||"session"),s=a[(r+(o.key==="ArrowRight"?1:a.length-1))%a.length];setSidebarTab(s);const l=n.querySelector('.sb-tab[data-tab="'+s+'"]');l&&l.focus()})}),document.addEventListener("keydown",t=>{if(!t.altKey||!["1","2","3","4","5"].includes(t.key))return;const o=document.activeElement?String(document.activeElement.tagName):"";o==="INPUT"||o==="TEXTAREA"||(t.preventDefault(),setSidebarTab(a[Number(t.key)-1]))}),document.addEventListener("keydown",t=>{t.key==="Escape"&&e.selected&&d()});const i=h();setSidebarTab(i&&a.includes(i)?i:"session"),u()}export{y as sidebarMapState,I as sidebarMapIndicator,E as renderLsp,p as sidebarLspState};
1
+ import{icon as m}from"../dom.js";import{session as g}from"../store.js";import{t as f}from"../i18n.js";import{sb as e,TABS as r,ICON_NAME as u,paneEl as B,mqMobile as S,readStored as h,storeTab as I}from"./state.js";import{collapseDetail as d,renderList as b,renderDetail as v}from"./trace.js";import{sidebarMapState as y,sidebarMapIndicator as x}from"./map.js";import{renderLsp as p,sidebarLspState as E}from"./lsp.js";import{renderFilesTree as T,refreshFilesTree as k}from"./files.js";import{renderPlugins as A,sidebarPluginsState as L}from"./plugins.js";export function setSidebarTab(n,i=!0){r.includes(n)||(n="session"),i&&I(n);const t=n==="trace"&&S()?"session":n;t!==e.active&&d(),e.active=t,r.forEach(a=>{const s=B(a);s&&(s.hidden=a!==t);const l=e.el&&e.el.querySelector('.sb-tab[data-tab="'+a+'"]');if(l){const c=a===t;l.classList.toggle("on",c),l.setAttribute("aria-selected",c?"true":"false")}}),e.nameTextEl&&(e.nameTextEl.textContent=f("web.sidebar.tab_"+t));const o=e.nameEl&&e.nameEl.querySelector(".sb-ico");o&&(o.textContent="",o.appendChild(m(u[t]))),t==="lsp"&&E(),t==="files"&&T(),t==="plugins"&&L()}export function sidebarBusy(n){const i=e.el&&e.el.querySelector('.sb-tab[data-tab="trace"]');i&&(i.dataset.indicator=n?"live":"")}export function applySidebarI18n(){if(e.el){if(r.forEach(n=>{const i=e.el?.querySelector('.sb-tab[data-tab="'+n+'"]');if(i){const t=f("web.sidebar.tab_"+n);i.title=t,i.setAttribute("aria-label",t)}}),setSidebarTab(e.active,!1),b(),e.selected){const n=e.trace.find(i=>i.id===e.selected);n&&v(n)}y(g.host),p(),k(),A()}}export function initSidebar(){if(e.el||(e.el=document.querySelector(".sb"),!e.el))return;const n=e.el;e.nameEl=document.getElementById("sbName"),e.nameTextEl=document.getElementById("sbNameText"),e.mapEl=document.getElementById("mapBody"),e.lspEl=document.getElementById("lspBody"),e.plugins.bodyEl=document.getElementById("pluginsBody"),e.listEl=document.getElementById("traceList"),e.detailEl=document.getElementById("traceDetail"),e.detailGlyph=document.getElementById("detailGlyph"),e.detailTitle=document.getElementById("detailTitle"),e.detailBody=document.getElementById("detailBody"),e.detailClose=document.getElementById("detailClose"),e.detailClose&&e.detailClose.addEventListener("click",d),n.querySelectorAll(".sb-tab .sb-ico").forEach(t=>{const o=t.closest(".sb-tab")?.dataset.tab||"session";t.textContent="",t.appendChild(m(u[o]))}),n.querySelectorAll(".sb-tab").forEach(t=>{t.addEventListener("click",()=>setSidebarTab(t.dataset.tab||"session")),t.addEventListener("keydown",o=>{if(o.key!=="ArrowLeft"&&o.key!=="ArrowRight")return;o.preventDefault();const a=r.indexOf(t.dataset.tab||"session"),s=r[(a+(o.key==="ArrowRight"?1:r.length-1))%r.length];setSidebarTab(s);const l=n.querySelector('.sb-tab[data-tab="'+s+'"]');l&&l.focus()})}),document.addEventListener("keydown",t=>{if(!t.altKey||!["1","2","3","4","5","6"].includes(t.key))return;const o=document.activeElement?String(document.activeElement.tagName):"";o==="INPUT"||o==="TEXTAREA"||(t.preventDefault(),setSidebarTab(r[Number(t.key)-1]))}),document.addEventListener("keydown",t=>{t.key==="Escape"&&e.selected&&d()});const i=h();setSidebarTab(i&&r.includes(i)?i:"session"),b()}export{y as sidebarMapState,x as sidebarMapIndicator,p as renderLsp,E as sidebarLspState};
@@ -0,0 +1 @@
1
+ import{el as t,icon as _,makeToggle as b}from"../dom.js";import{api as m}from"../api.js";import{t as l}from"../i18n.js";import{setIndicator as C}from"../dialog.js";import{openSubDialog as P}from"../subdialog.js";import{sb as p}from"./state.js";let u=null;function R(n){return n.enabled?n.warnings?.length?["⚠","warn"]:["✓","ok"]:["–","dim"]}function E(n){const i=document.createDocumentFragment();return n.version&&i.appendChild(t("span","plg-ver","v"+String(n.version))),n.author&&(n.version&&i.appendChild(document.createTextNode(" · ")),i.appendChild(t("span","plg-author",String(n.author)))),i}function L(n){const i=t("div","plg-row"),[e,a]=R(n);i.appendChild(t("span","plg-g "+a,e)),i.appendChild(t("span","plg-name",n.name)),i.appendChild(E(n)),v(n)&&i.appendChild(t("span","plg-badges",v(n)));const s=b(!!n.enabled,d=>(w(n.name,d),!1));return s.title=l(n.enabled?"web.plugins.disable":"web.plugins.enable"),s.setAttribute("aria-label",l(n.enabled?"web.plugins.disable":"web.plugins.enable")),i.appendChild(s),i.addEventListener("click",()=>openPluginDialog(n)),i}function v(n){const i=[];return n.draft?i.push(l("web.plugins.badge_draft")):n.builtin?i.push(l("web.plugins.badge_builtin")):n.source&&i.push(String(n.source)),i.join(" · ")}async function w(n,i){const e=await m("/api/plugins/"+encodeURIComponent(n),{method:"POST",body:{enabled:i}});if(!e.ok||!e.data||e.data.ok!==!0){const a=e.data&&e.data.error||String(e.status);C(a==="not_found"?l("cli.plugins.not_found",{name:n}):l("web.plugins.toggle_failed"),!0);return}k(e.data),renderPlugins(),u?.()}function k(n){const i=n.plugins||[];p.plugins.records=i,p.plugins.failures=n.failures||[]}function T(n){const i=String(n.description||"").trim();return i?t("div","plg-desc",i.length>90?i.slice(0,89)+"…":i):null}function j(n){const i=p.plugins.records,e=i.filter(r=>!r.enabled).length,a=p.plugins.failures.length,s=i.length-e,d=[l("web.plugins.summary",{active:String(s),off:String(e)})];a>0&&d.push(l("web.plugins.failed_count",{count:String(a)})),n.appendChild(t("div","plg-summary",d.join(" · ")))}function D(n){for(const i of p.plugins.failures){const e=t("div","plg-row plg-broken");e.appendChild(t("span","plg-g fail","✗")),e.appendChild(t("span","plg-name",String(i.entry||i.path||"?"))),e.appendChild(t("span","plg-meta",String(i.message||""))),n.appendChild(e)}}export function renderPlugins(){const n=p.plugins.bodyEl;if(!n)return;if(n.textContent="",p.plugins.unavailable){n.appendChild(t("div","fdim",l("web.plugins.unavailable")));return}if(!p.plugins.loaded){n.appendChild(t("div","fdim",l("web.plugins.loading")));return}j(n);const i=p.plugins.records;i.length===0&&p.plugins.failures.length===0&&n.appendChild(t("div","fdim",l("web.plugins.empty")));const e=i.sort((a,s)=>+!!a.builtin-+!!s.builtin);for(const a of e){n.appendChild(L(a));const s=T(a);s&&n.appendChild(s)}D(n)}export function openPluginDialog(n){const i=t("div","plg-info");u=()=>A(i,n),u(),P(String(n.name),i,()=>{u=null})}function g(n,i){const e=t("div","kv");return e.appendChild(t("span","dim",n)),e.appendChild(t("b","",i)),e}function I(n){const i=t("a","plg-link");return i.href=n,i.textContent=n,i.target="_blank",i.rel="noopener noreferrer",i}function N(n){const i=t("div","lsp-install");i.appendChild(t("code","lsp-cmd",n));const e=t("button","linkbtn lsp-copy");return e.type="button",e.title=l("web.plugins.copy_path"),e.setAttribute("aria-label",l("web.plugins.copy_path")),e.appendChild(_("copy")),e.addEventListener("click",()=>{navigator.clipboard&&navigator.clipboard.writeText(n).then(()=>C(l("web.plugins.copied"),!1)).catch(()=>{})}),i.appendChild(e),i}function S(n,i){if(i.length===0)return null;const e=t("div","plg-chips");e.appendChild(t("span","dim",n));for(const a of i)e.appendChild(t("span","plg-tag",a));return e}function A(n,i){n.textContent="";const e=t("div","kv");e.appendChild(t("span","dim",l("web.plugins.state"))),e.appendChild(t("b","",l(i.enabled?"cli.plugins.on":"cli.plugins.off")+" · "+(i.source||"builtin"))),n.appendChild(e);const a=t("div","kv lsp-toggle");a.appendChild(t("span","dim",l("web.plugins.switch_enabled")));const s=b(!!i.enabled,o=>(w(i.name,o),!1));if(s.title=l("web.plugins.switch_enabled"),a.appendChild(s),n.appendChild(a),n.appendChild(t("div","plg-desc-block",String(i.description||l("web.plugins.no_description")))),i.author&&n.appendChild(g(l("cli.plugins.author"),String(i.author))),i.version&&n.appendChild(g(l("web.plugins.version"),"v"+String(i.version))),i.homepage){const o=t("div","kv");o.appendChild(t("span","dim",l("cli.plugins.homepage"))),o.appendChild(I(String(i.homepage))),n.appendChild(o)}const d=i.provides||{},r=S(l("web.plugins.tools"),d.tools||[]),c=S(l("web.plugins.hooks"),d.hooks||[]);r&&n.appendChild(r),c&&n.appendChild(c),(d.tools||[]).length>0&&n.appendChild(t("div","plg-hint",l("web.plugins.cache_note")));const h=i.permissions||[];n.appendChild(h.length>0?g(l("cli.plugins.perms_label"),h.join(", ")):t("div","plg-hint",l("web.plugins.permissions_none"))),n.appendChild(t("div","plg-hint",l("web.plugins.permissions_hint")));const f=i.warnings||[];if(f.length>0){n.appendChild(t("div","plg-warn-title",l("web.plugins.warnings")));for(const o of f)n.appendChild(t("div","plg-hint warn",String(o)))}i.path&&n.appendChild(N(String(i.path)))}export function sidebarPluginsState(){p.active!=="plugins"||p.plugins.unavailable||p.plugins.loaded||y()}async function y(){const n=await m("/api/plugins");if(!n.ok||!n.data){p.plugins.unavailable=!0,p.plugins.loaded=!0,renderPlugins();return}p.plugins.unavailable=!1,p.plugins.loaded=!0,k(n.data),renderPlugins()}export function sidebarPluginsEvent(){p.active==="plugins"&&y()}
@@ -1 +1 @@
1
- export const TAB_KEY="mma-sidebar-tab",TABS=["session","map","trace","lsp","files"],ICON_NAME={session:"list-checks",map:"map",trace:"activity",lsp:"stethoscope",files:"folder-tree"},TRACE_CAP=500,MAX_OUTPUT_CHARS=2e4,sb={el:null,nameEl:null,nameTextEl:null,mapEl:null,listEl:null,detailEl:null,detailGlyph:null,detailTitle:null,detailBody:null,detailClose:null,lspEl:null,active:"session",trace:[],selected:null,turn:0,seq:0,logCursor:null,logPulling:!1,nodeById:new Map,callIndex:new Map,headerByTurn:new Map,textEntry:null,lspDiag:null,lspFlags:null,lspProbing:!1,lspLoaded:!1,lspUnavailable:!1,reindexing:!1,postResolved:!1,reindexError:!1,files:{treeEl:null,detailEl:null,detailTitleEl:null,detailBodyEl:null,detailAttachEl:null,expanded:new Set,listings:new Map,selectedPath:null}};export function paneEl(l){return document.getElementById("pane-"+l)}export function mqMobile(){return typeof window<"u"&&window.matchMedia?window.matchMedia("(max-width: 760px)").matches:!1}export function readStored(){try{return localStorage.getItem(TAB_KEY)}catch{return null}}export function storeTab(l){try{localStorage.setItem(TAB_KEY,l)}catch{}}
1
+ export const TAB_KEY="mma-sidebar-tab",TABS=["session","map","trace","lsp","files","plugins"],ICON_NAME={session:"list-checks",map:"layout-grid",trace:"activity",lsp:"code",files:"folder-tree",plugins:"plug"},TRACE_CAP=500,MAX_OUTPUT_CHARS=2e4,sb={el:null,nameEl:null,nameTextEl:null,mapEl:null,listEl:null,detailEl:null,detailGlyph:null,detailTitle:null,detailBody:null,detailClose:null,lspEl:null,active:"session",trace:[],selected:null,turn:0,seq:0,logCursor:null,logPulling:!1,nodeById:new Map,callIndex:new Map,headerByTurn:new Map,textEntry:null,lspDiag:null,lspFlags:null,lspProbing:!1,lspLoaded:!1,lspUnavailable:!1,reindexing:!1,postResolved:!1,reindexError:!1,files:{treeEl:null,detailEl:null,detailTitleEl:null,detailBodyEl:null,detailAttachEl:null,expanded:new Set,listings:new Map,selectedPath:null},plugins:{bodyEl:null,records:[],failures:[],loaded:!1,unavailable:!1}};export function paneEl(l){return document.getElementById("pane-"+l)}export function mqMobile(){return typeof window<"u"&&window.matchMedia?window.matchMedia("(max-width: 760px)").matches:!1}export function readStored(){try{return localStorage.getItem(TAB_KEY)}catch{return null}}export function storeTab(l){try{localStorage.setItem(TAB_KEY,l)}catch{}}
@@ -1 +1 @@
1
- export*from"./sidebar/core.js";export*from"./sidebar/trace.js";export*from"./sidebar/map.js";export*from"./sidebar/lsp.js";export*from"./sidebar/files.js";
1
+ export*from"./sidebar/core.js";export*from"./sidebar/trace.js";export*from"./sidebar/map.js";export*from"./sidebar/lsp.js";export*from"./sidebar/files.js";export*from"./sidebar/plugins.js";
@@ -1 +1 @@
1
- import{trapTab as r}from"./dialog.js";const t=document.getElementById("subOverlay"),o=document.getElementById("subHost"),a=document.getElementById("subTitle"),l=document.getElementById("closeSub");let n=null,s=null;export function isSubDialogOpen(){return!!t&&t.classList.contains("open")}export function openSubDialog(e,i,c){!t||!o||(n=document.activeElement,s=c||null,a.textContent=e,o.textContent="",o.appendChild(i),t.classList.add("open"),setTimeout(()=>{const u=o.querySelector("input, select, textarea");u&&u.focus()},0))}export function closeSubDialog(){if(!isSubDialogOpen()||!t)return;t.classList.remove("open");const e=s;s=null,n&&n.focus&&n.focus(),n=null,e&&e()}t&&(l&&l.addEventListener("click",closeSubDialog),t.addEventListener("click",e=>{e.stopPropagation(),e.target===t&&closeSubDialog()}),t.addEventListener("keydown",e=>r(t,e)));
1
+ import{trapTab as d}from"./dialog.js";function c(){return{overlay:document.getElementById("subOverlay"),host:document.getElementById("subHost"),title:document.getElementById("subTitle"),close:document.getElementById("closeSub")}}const a=new WeakSet;function f(t){if(a.has(t))return;a.add(t),t.querySelector("#closeSub")?.addEventListener("click",closeSubDialog),t.addEventListener("click",e=>{e.stopPropagation(),e.target===t&&closeSubDialog()}),t.addEventListener("keydown",e=>d(t,e))}let o=null,i=null;export function isSubDialogOpen(){const t=c().overlay;return!!t&&t.classList.contains("open")}export function openSubDialog(t,n,e){const{overlay:l,host:s,title:u}=c();!l||!s||(f(l),o=document.activeElement,i=e||null,u&&(u.textContent=t),s.textContent="",s.appendChild(n),l.classList.add("open"),setTimeout(()=>{const r=s.querySelector("input, select, textarea");r&&r.focus()},0))}export function closeSubDialog(){const{overlay:t}=c();if(!t||!t.classList.contains("open"))return;t.classList.remove("open");const n=i;i=null,o&&o.focus&&o.focus(),o=null,n&&n()}