micro-models-agent 2.26.0 → 2.29.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +103 -0
- package/dist/assets/js/feed/core.js +1 -1
- package/dist/assets/js/feed/history.js +1 -1
- package/dist/assets/js/feed/image-card.js +1 -0
- package/dist/assets/js/feed/stream.js +1 -1
- package/dist/assets/js/feed/turn.js +4 -4
- package/dist/assets/js/format.js +2 -2
- package/dist/assets/js/lightbox.js +1 -0
- package/dist/assets/js/settings/controls.js +1 -1
- package/dist/assets/js/settings/editors.js +1 -1
- package/dist/assets/js/settings/panels.js +1 -1
- package/dist/assets/styles.css +1 -1
- package/dist/i18n/en.json +1 -1
- package/dist/i18n/ru.json +1 -1
- package/dist/main.js +321 -321
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,109 @@ 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.0] - 2026-10-07
|
|
8
|
+
|
|
9
|
+
The plugin system stops being "an anonymous object in an array": a plugin is now a
|
|
10
|
+
registered entity with author, version, description, declared permissions and a
|
|
11
|
+
visible on/off switch. `mma web` gets a **Plugins** sidebar tab with live toggles
|
|
12
|
+
and a details popup; a plugin that fails to load is now visible instead of
|
|
13
|
+
silently missing.
|
|
14
|
+
|
|
15
|
+
### Added
|
|
16
|
+
|
|
17
|
+
- **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.
|
|
18
|
+
- **`[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.
|
|
19
|
+
- **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.
|
|
20
|
+
- **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.
|
|
21
|
+
- **`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`.
|
|
22
|
+
- **`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.
|
|
23
|
+
- **`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.
|
|
24
|
+
|
|
25
|
+
### Fixed
|
|
26
|
+
|
|
27
|
+
- **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.
|
|
28
|
+
- **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.
|
|
29
|
+
- **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`.
|
|
30
|
+
- **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).
|
|
31
|
+
- **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.
|
|
32
|
+
- **A deleted plugin file left the plugin registered**: reloading a catalog now drops plugins whose file disappeared.
|
|
33
|
+
|
|
34
|
+
### Changed
|
|
35
|
+
|
|
36
|
+
- **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`.
|
|
37
|
+
- **`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.
|
|
38
|
+
- **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.
|
|
39
|
+
- **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.
|
|
40
|
+
- **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.
|
|
41
|
+
- **`mma plugins show <name>` / `/plugins show <name>`**: per-plugin details in the terminal, same content as the web popup.
|
|
42
|
+
- **CLI/REPL listing rewrite**: both share one formatter (`src/modules/plugins/format.ts`) and now show author, permissions, description and load failures.
|
|
43
|
+
- **`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.
|
|
44
|
+
- **`WebPluginManager`** (`webui/state.ts`): widened to `getRecords`/`getFailures`/`setEnabled`/`reload`; `PluginManager` satisfies it structurally. The redundant narrow `WebPluginInfo` view is gone.
|
|
45
|
+
- **`PluginLoader.loadFromDir`** returns `LoadReport {loaded, skipped, failed}` instead of `void` and stamps `plugin.path` on each plugin.
|
|
46
|
+
- **`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.
|
|
47
|
+
- **Sidebar tab icons**: `map`/`stethoscope`/`puzzle` were too dense to read at 17px and are replaced with `layout-grid`/`code`/`plug`.
|
|
48
|
+
- **`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.
|
|
49
|
+
- **Internals**: `PluginManager` was over the 300-line rule at 316; hook dispatching moved to `src/modules/plugins/dispatch.ts`.
|
|
50
|
+
- **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.
|
|
51
|
+
- **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.
|
|
52
|
+
|
|
53
|
+
### Removed
|
|
54
|
+
|
|
55
|
+
- **`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.
|
|
56
|
+
|
|
57
|
+
### Known limits (documented, not fixed)
|
|
58
|
+
|
|
59
|
+
- **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.
|
|
60
|
+
- 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).
|
|
61
|
+
- 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).
|
|
62
|
+
|
|
63
|
+
## [2.28.0] - 2026-10-07
|
|
64
|
+
|
|
65
|
+
Tool-produced images (browser screenshots, `attach_image`) are now visible in the
|
|
66
|
+
`mma web` feed — a thumbnail with a full-screen lightbox — and survive reload via
|
|
67
|
+
per-session persistence with rotation. The old static placeholder card that never
|
|
68
|
+
filled is gone.
|
|
69
|
+
|
|
70
|
+
### Added
|
|
71
|
+
|
|
72
|
+
- **Tool images in the web feed** (`src/modules/webui/assets/js/lightbox.ts`, `feed/image-card.ts`, `feed/turn.ts`, `feed/history.ts`): `browser` screenshots and `attach_image` render as lazy thumbnails; click opens a lightbox (Esc/backdrop close, "open in a new tab", "copy link"). Shown in every verbosity, including quiet.
|
|
73
|
+
- **Persistence + replay** (`src/modules/session/image-store.ts`, `src/core/session-logger.ts`): full-size assets are written to `<sessionDir>/images/` and served via `GET /api/sessions/:id/images/:name`; history replay renders the same thumbnails. When a file was evicted by rotation, the card shows a muted "image removed (rotation)".
|
|
74
|
+
- **Rotation** (`images.maxCount` default 30, `images.maxBytes` default 100 MB in `src/config/registry-extra.ts`): oldest images are evicted first; both keys in `/config` and Web UI settings (UI → Tool images). Labels `config.key.images.*` (en+ru).
|
|
75
|
+
- **Delivery contract** (`src/tools/types.ts`, `src/core/types.ts`): `ToolResult.imageFiles`/`imageRefs`, `ToolEvent.imageRefs`/`images`, and `tool_result.images` in `session.jsonl`.
|
|
76
|
+
|
|
77
|
+
### Changed
|
|
78
|
+
|
|
79
|
+
- **`attach_image`** (`src/tools/attach-image.ts`): returns the image via `result.images` (unified path with the browser tool) instead of queueing it directly on the context manager.
|
|
80
|
+
- **SSE `tool_end`** (`src/modules/webui/session/forward.ts`): carries an `images` URL list; for an encrypted session (no disk write) it falls back to inline data URLs for live view.
|
|
81
|
+
- **Browser screenshots for text-only models** (`src/tools/browser.ts`): the screenshot is always produced and delivered to the web feed; a non-vision model still receives the text note.
|
|
82
|
+
|
|
83
|
+
### Removed
|
|
84
|
+
|
|
85
|
+
- **Static screenshot placeholder** (`src/modules/webui/assets/js/feed/turn.ts`): the misleading "screenshot" card that was created on every `browser`/`attach_image` call and never filled.
|
|
86
|
+
|
|
87
|
+
## [2.27.0] - 2026-10-07
|
|
88
|
+
|
|
89
|
+
MoE is now usable out of the box: `moe.enabled: true` starts on the active
|
|
90
|
+
model instead of silently falling back when no planner model is set, the
|
|
91
|
+
planner keys are configurable from `/config` and Web UI, and model/provider
|
|
92
|
+
references render as dropdowns instead of free-text/JSON fields.
|
|
93
|
+
|
|
94
|
+
### Added
|
|
95
|
+
|
|
96
|
+
- **Orchestrator config keys** (`src/config/registry-extra.ts`): `orchestrator.model`, `orchestrator.provider`, `orchestrator.contextWindow` (domain `provider`). Previously reachable only by hand-editing `config.json`; now in `/config`, `mma config set` and Web UI settings (Agent → Mixture of experts).
|
|
97
|
+
- **Dynamic `select` editor** (`src/config/registry.ts`, `src/modules/webui/assets/js/settings/{controls,editors}.ts`): `ConfigEditorSpec.kind: "select"` with `optionsSource: "models" | "providers"` renders a dropdown fed by the live model/provider lists, with text-input fallback when the list is unavailable. Applied to `critic.model`, `orchestrator.model` and the `experts[*].model` table column.
|
|
98
|
+
- **`resolveProviderRef`** (`src/modules/providers/resolve-ref.ts`): resolves a provider name (`provider.entries[]` label/type) to its entry.
|
|
99
|
+
- **Per-expert models** (`src/modules/execution/expert-provider.ts`): `experts[*].model` now takes effect — an expert whose model differs from the active one runs on a dedicated provider built on the active provider (`buildManagedProvider`); a matching/empty model reuses the shared provider, a build error fails open. Applies both to MoE subtasks and to the `subagent` tool called directly with `expert_tag`.
|
|
100
|
+
|
|
101
|
+
### Changed
|
|
102
|
+
|
|
103
|
+
- **Shared managed-provider builder** (`src/modules/providers/managed.ts`): the ProviderManager-based builder (per-entry contextWindow/retry/rateLimits + failover) is extracted and reused by the MoE orchestrator, the critic and per-expert providers instead of being duplicated in three places.
|
|
104
|
+
|
|
105
|
+
- **MoE default-model fallback** (`src/llm/orchestrator.ts`, `src/core/agent-moe.ts`): `OrchestratorClient` reuses the active agent provider when `orchestrator.model` is unset, and builds a dedicated provider on the active provider when `orchestrator.model` differs — so enabling MoE no longer requires hand-configuring a planner model.
|
|
106
|
+
- **`critic.provider` / `orchestrator.provider`** (`src/config/types.ts`, `src/modules/critic/provider.ts`): accept a provider name string (reference) as well as a full `ProviderConfig`; the Web UI shows a provider dropdown.
|
|
107
|
+
- **`ConfigKeyDef.allowEmpty`** (`src/config/registry.ts`): optional string keys accept an empty value (clears to unset), so a dropdown can restore "use active".
|
|
108
|
+
- **Cert MoE scenarios** (`src/modules/certification/scenarios.ts`): dropped the `orchestrator: { model: "" }` override that disabled MoE and let the file-level checks pass without ever exercising the MoE path.
|
|
109
|
+
|
|
7
110
|
## [2.26.0] - 2026-10-07
|
|
8
111
|
|
|
9
112
|
Web UI polish: the sidebar now has a fixed width with the detail panel on the
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{msgs as s,el as i,setIcon as C}from"../dom.js";import{t as l,pluralCount as w}from"../i18n.js";import{feed as o,tabs as a}from"../store.js";import{formatMs as x,verbosity as T}from"../format.js";import{copyText as v}from"../../md.js";export function mdOpts(t){return{copyLabel:l("web.code.copy"),copiedLabel:l("web.code.copied"),copyFailedLabel:l("web.code.copy_failed"),animate:t===!0}}export function buildThinkBlock(t,e){const n=i("div","think"+(e===!1?"":" live")),r=i("button","think-h");r.type="button",r.setAttribute("aria-expanded","false"),r.appendChild(i("span","g","✦")),r.appendChild(i("span","lab",l("web.action.thinking"))),t&&r.appendChild(i("span","dur",""));const d=i("span","tog");C(d,"chevron-right",l("web.action.show")),r.appendChild(d);const p=i("div","think-body hidden");return n.appendChild(r),n.appendChild(p),{wrap:n,head:r,body:p}}export function copyAction(t,e){const n=i("button","act-btn",l(e));return n.type="button",n.addEventListener("click",()=>{v(t).then(r=>{n.textContent=r?"✓ "+l("web.code.copied"):"⚠ "+l("web.code.copy_failed"),window.setTimeout(()=>{n.textContent=l(e)},1400)})}),n}export function appendActionsRow(t,e,n){const r=String(e??""),d=String(n??"");if(!t||!r.trim()&&!d.trim())return;const p=i("div","msg-actions");r.trim()&&p.appendChild(copyAction(r,"web.msg.copy")),d.trim()&&p.appendChild(copyAction(d,"web.msg.copy_md")),appendTo(t,p)}export function insertAfter(t,e){t&&t.parentNode?t.parentNode.insertBefore(e,t.nextSibling):appendTo(liveFeed(),e)}function b(){const t=i("div","empty");return t.appendChild(i("span","g","✦")),t.appendChild(document.createTextNode(" "+l("web.empty.title"))),t.appendChild(document.createElement("br")),t.appendChild(i("span","hint",l("web.empty.hint"))),t}export function makeFeed(){const t=i("div","feed");return t.appendChild(b()),t}export function showEmptyFeed(){s.replaceChildren(b()),u=!0,f(),syncUrl()}export function clearFeed(t){if(!t)return;t.replaceChildren(b()),u=!0,f();const e=a.tabs.find(n=>n.feed===t);e&&(e.planCard=null),t===activeFeed()&&scroll()}export function activeFeed(){const t=a.tabs.find(e=>e.id===a.activeTabId);return t?t.feed:null}export function liveFeed(){const t=a.tabs.find(e=>e.id===a.liveTabId)||a.tabs.find(e=>e.id===a.activeTabId);return t?t.feed:null}export function feedForEvent(t){if(t){const e=a.tabs.find(n=>n.id===t);if(e)return e.feed}return liveFeed()}function h(){return s.scrollHeight-s.scrollTop-s.clientHeight<140}let u=!0;export function scroll(t){t||u||h()?(s.scrollTop=s.scrollHeight,u=!0,f()):m()}export function scrollToBottom(t){if(u=!0,f(),t&&typeof s.scrollTo=="function")try{s.scrollTo({top:s.scrollHeight,behavior:"smooth"});return}catch{}s.scrollTop=s.scrollHeight}export function isFollowing(){return u}export function feedHasContent(t){return!!t.querySelector(".u, .md, .ans, .code, .act, .think, .metaln, .errline, .sysline, .detail")}export function syncUrl(){const t=new URL(location.href),e=a.tabs.find(n=>n.id===a.activeTabId);e&&e.kind==="session"?t.searchParams.set("session",e.id):t.searchParams.delete("session"),history.replaceState(null,"",t)}let c=null;function g(){if(c)return c;const t=document.querySelector(".chat");return t?(c=i("button","to-latest"),c.type="button",c.hidden=!0,c.addEventListener("click",()=>scrollToBottom(!0)),t.appendChild(c),c):null}function m(){const t=g();t&&(t.textContent="↓ "+l("web.scroll.latest"),t.hidden=!1,s.classList.add("unfollowed"))}function f(){c&&(c.hidden=!0),s.classList.remove("unfollowed")}s
|
|
1
|
+
import{msgs as s,el as i,setIcon as C}from"../dom.js";import{t as l,pluralCount as w}from"../i18n.js";import{feed as o,tabs as a}from"../store.js";import{formatMs as x,verbosity as T}from"../format.js";import{copyText as v}from"../../md.js";export function mdOpts(t){return{copyLabel:l("web.code.copy"),copiedLabel:l("web.code.copied"),copyFailedLabel:l("web.code.copy_failed"),animate:t===!0}}export function buildThinkBlock(t,e){const n=i("div","think"+(e===!1?"":" live")),r=i("button","think-h");r.type="button",r.setAttribute("aria-expanded","false"),r.appendChild(i("span","g","✦")),r.appendChild(i("span","lab",l("web.action.thinking"))),t&&r.appendChild(i("span","dur",""));const d=i("span","tog");C(d,"chevron-right",l("web.action.show")),r.appendChild(d);const p=i("div","think-body hidden");return n.appendChild(r),n.appendChild(p),{wrap:n,head:r,body:p}}export function copyAction(t,e){const n=i("button","act-btn",l(e));return n.type="button",n.addEventListener("click",()=>{v(t).then(r=>{n.textContent=r?"✓ "+l("web.code.copied"):"⚠ "+l("web.code.copy_failed"),window.setTimeout(()=>{n.textContent=l(e)},1400)})}),n}export function appendActionsRow(t,e,n){const r=String(e??""),d=String(n??"");if(!t||!r.trim()&&!d.trim())return;const p=i("div","msg-actions");r.trim()&&p.appendChild(copyAction(r,"web.msg.copy")),d.trim()&&p.appendChild(copyAction(d,"web.msg.copy_md")),appendTo(t,p)}export function insertAfter(t,e){t&&t.parentNode?t.parentNode.insertBefore(e,t.nextSibling):appendTo(liveFeed(),e)}function b(){const t=i("div","empty");return t.appendChild(i("span","g","✦")),t.appendChild(document.createTextNode(" "+l("web.empty.title"))),t.appendChild(document.createElement("br")),t.appendChild(i("span","hint",l("web.empty.hint"))),t}export function makeFeed(){const t=i("div","feed");return t.appendChild(b()),t}export function showEmptyFeed(){s.replaceChildren(b()),u=!0,f(),syncUrl()}export function clearFeed(t){if(!t)return;t.replaceChildren(b()),u=!0,f();const e=a.tabs.find(n=>n.feed===t);e&&(e.planCard=null),t===activeFeed()&&scroll()}export function activeFeed(){const t=a.tabs.find(e=>e.id===a.activeTabId);return t?t.feed:null}export function liveFeed(){const t=a.tabs.find(e=>e.id===a.liveTabId)||a.tabs.find(e=>e.id===a.activeTabId);return t?t.feed:null}export function feedForEvent(t){if(t){const e=a.tabs.find(n=>n.id===t);if(e)return e.feed}return liveFeed()}function h(){return s.scrollHeight-s.scrollTop-s.clientHeight<140}let u=!0;export function scroll(t){t||u||h()?(s.scrollTop=s.scrollHeight,u=!0,f()):m()}export function scrollToBottom(t){if(u=!0,f(),t&&typeof s.scrollTo=="function")try{s.scrollTo({top:s.scrollHeight,behavior:"smooth"});return}catch{}s.scrollTop=s.scrollHeight}export function isFollowing(){return u}export function feedHasContent(t){return!!t.querySelector(".u, .md, .ans, .code, .act, .think, .metaln, .errline, .sysline, .detail")}export function syncUrl(){const t=new URL(location.href),e=a.tabs.find(n=>n.id===a.activeTabId);e&&e.kind==="session"?t.searchParams.set("session",e.id):t.searchParams.delete("session"),history.replaceState(null,"",t)}let c=null;function g(){if(c)return c;const t=document.querySelector(".chat");return t?(c=i("button","to-latest"),c.type="button",c.hidden=!0,c.addEventListener("click",()=>scrollToBottom(!0)),t.appendChild(c),c):null}function m(){const t=g();t&&(t.textContent="↓ "+l("web.scroll.latest"),t.hidden=!1,s.classList.add("unfollowed"))}function f(){c&&(c.hidden=!0),s.classList.remove("unfollowed")}s?.addEventListener("scroll",()=>{const t=h();u=t,s.classList.toggle("scrolled",s.scrollTop>24),t?f():liveFeed()&&feedHasContent(liveFeed())&&m()});export function appendTo(t,e){return t&&(t.appendChild(e),t===activeFeed()&&scroll()),e}export function clearEmpty(t){const e=t&&t.querySelector(".empty");e&&e.remove()}export function clearBusy(t){if(o.busyTimer&&(clearInterval(o.busyTimer),o.busyTimer=null),t=t||liveFeed(),!t)return;const e=t.querySelector(".busy");e&&e.remove()}export function showBusy(t){if(t=t||liveFeed(),!t||o.curMd||o.curThink||(clearEmpty(t),t.querySelector(".busy")))return;o.busyTimer&&(clearInterval(o.busyTimer),o.busyTimer=null);const e=i("div","busy");e.appendChild(i("span","spin","✦")),e.appendChild(i("span","lab",l("web.action.thinking")));const n=i("span","busytime","· 0s");e.appendChild(n),e.appendChild(i("span","","· "+l("web.input.esc"))),appendTo(t,e);const r=Date.now();o.busyTimer=setInterval(()=>{if(!e.parentNode){clearInterval(o.busyTimer),o.busyTimer=null;return}n.textContent="· "+Math.round((Date.now()-r)/1e3)+"s"},1e3)}export function flushRun(){if(o.runCount<=0){y();return}if(T()==="quiet"&&o.runReconOnly&&o.runFails===0&&o.runCount>1){const t=o.runNodes.slice();t.forEach(r=>r.classList.add("fold-out")),window.setTimeout(()=>t.forEach(r=>r.remove()),160);const e=i("div","grouped");e.appendChild(i("span","pipe","│"));const n=x(o.runDuration);e.appendChild(document.createTextNode(" "+w("web.action.actions",o.runCount)+" ✓"+(n?" · "+n:""))),appendTo(liveFeed(),e)}y()}function y(){o.runCount=0,o.runFails=0,o.runReconOnly=!0,o.runNodes=[],o.runDuration=0}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{el as
|
|
1
|
+
import{el as a}from"../dom.js";import{t as n}from"../i18n.js";import{categoryOf as c,labelOf as f,argText as u,formatMs as C}from"../format.js";import{renderMarkdown as m}from"../../md.js";import{api as g}from"../api.js";import{imageCard as k}from"./image-card.js";import{feedHasContent as r,clearEmpty as x,scrollToBottom as h,activeFeed as v,liveFeed as w,mdOpts as A,buildThinkBlock as I,appendActionsRow as L}from"./core.js";function T(i,e){const s=String(e??"");if(!s.trim())return;const o=m(i,s,A());L(i,o.innerText||o.textContent||"",s)}function H(i,e){const{wrap:s,body:o}=I(!1,!1);o.textContent=e==null?"":String(e),i.appendChild(s)}function F(i,e,s){const o=a("div","act "+c(e.name));o.appendChild(a("span","g","◇")),o.appendChild(a("span","lab",f(e.name)));const l=u(e.args);l&&(o.appendChild(a("span","sep","·")),o.appendChild(a("span","args",l)));const t=a("span","ok","");o.appendChild(t),i.appendChild(o),e.toolCallId&&s.set(e.toolCallId,t)}function S(i,e,s){const o=C(e.duration),l=(e.success?" ✓":" ✗")+(o?" "+o:""),t=e.toolCallId?s.get(e.toolCallId):null;if(t)t.textContent=l,e.success||t.classList.add("fail"),s.delete(e.toolCallId);else{const d=a("div","act "+c(e.tool));d.appendChild(a("span","g","↳")),d.appendChild(a("span","lab",f(e.tool))),d.appendChild(a("span","ok"+(e.success?"":" fail"),l)),i.appendChild(d)}if(e.success&&Array.isArray(e.images)&&e.images.length)for(const d of e.images){const p=k(String(e.tool||""),String(d));p&&i.appendChild(p)}}function B(i,e){const s=new Map;e.forEach(o=>{if(!(!o||typeof o.kind!="string"))switch(o.kind){case"user":i.appendChild(a("div","u",o.text||""));break;case"assistant":T(i,o.text||"");break;case"reasoning":H(i,o.text||"");break;case"tool_call":F(i,o,s);break;case"tool_result":S(i,o,s);break;case"plan":o.text&&i.appendChild(a("div","sysline","▸ "+o.text));break;case"context":o.text&&i.appendChild(a("div","detail","↳ "+o.text));break;case"error":i.appendChild(a("div","errline","✗ "+(o.text||"")));break;case"system":o.text&&i.appendChild(a("div","sysline",o.text));break}})}export async function loadHistory(i){if(!i||i.historyLoaded||i.historyLoading)return{gone:!!i.dead};i.historyLoading=!0;const e=a("div","detail",n("web.history.loading"));r(i.feed)||(x(i.feed),i.feed.appendChild(e));const s=await g("/api/sessions/"+encodeURIComponent(i.id)+"/history");if(i.historyLoading=!1,e.remove(),i.historyLoaded=!0,i.historyFailed=!1,!s.ok||!s.data||!Array.isArray(s.data.history))return s.status===404?{gone:!0}:(i.historyFailed=!0,r(i.feed)||i.feed.appendChild(a("div","detail",n("web.history.unavailable"))),{gone:!1});r(i.feed)||(B(i.feed,s.data.history),s.data.history.length||i.feed.appendChild(a("div","detail",n("web.history.empty"))),i.feed===v()?h():i.feed===w()&&h())}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{el as r}from"../dom.js";import{t as d}from"../i18n.js";import{openLightbox as o}from"../lightbox.js";function c(e){return e==="attach_image"?d("web.card.attached_image"):d("web.card.browser_viewport")}function m(e,t){e.className="imgcard-missing",e.replaceChildren(),e.appendChild(document.createTextNode("◧ "+d("web.card.image_removed"))),e.appendChild(r("div","cap",t))}export function imageCard(e,t){if(!t)return null;const a=c(e),n=r("div","imgcard"),i=document.createElement("img");return i.className="imgthumb",i.alt="",i.loading="lazy",i.src=t,i.addEventListener("error",()=>m(n,a)),i.addEventListener("click",()=>o(t,a)),n.appendChild(i),n.appendChild(r("div","cap",a)),n}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{msgs as g,el as w,setIcon as k}from"../dom.js";import{t as v}from"../i18n.js";import{feed as t}from"../store.js";import{verbosity as y}from"../format.js";import{mountMarkdown as b}from"../../md.js";import{activeFeed as l,feedForEvent as d,clearBusy as f,clearEmpty as x,flushRun as M,showBusy as R,appendTo as m,scroll as a,mdOpts as A,buildThinkBlock as F}from"./core.js";let s="",c=null,p=!1;function h(){if(p=!1,!s||!t.curMd){s="",c=null;return}const n=s,o=c;s="",c=null,t.curMd.write(n),o&&o===l()&&a()}function L(){p||(p=!0,typeof window<"u"&&typeof window.requestAnimationFrame=="function"?window.requestAnimationFrame(h):h())}export function finishMd(){h(),t.curMd&&(t.curMd.root.classList.remove("streaming"),t.curMd.end(),t.curMd=null),t.curText=null}export function onText(n,o){const e=d(o);f(e),e&&(x(e),t.curThink&&finishThink(),t.curText==null&&(M(),t.curText="",t.curMd=b(e,A(!0)),t.curMd.root.classList.add("streaming"),t.turnRoots.push(t.curMd.root)),t.curText+=n,t.turnMd+=n,c&&c!==e&&h(),c=e,s+=n,L())}export function finishThink(){if(t.curThink&&(t.curThink.wrap&&t.curThink.wrap.classList.remove("live"),t.curThink.startedAt)){const n=t.curThink.head.querySelector(".dur");n&&(n.textContent="· "+((Date.now()-t.curThink.startedAt)/1e3).toFixed(1)+"s")}t.curThink=null}export function onReasoning(n,o){const e=d(o);if(f(e),!!e){if(x(e),finishMd(),!t.curThink){M();const{wrap:r,head:i,body:u}=F(!0);m(e,r),t.curThink={wrap:r,head:i,body:u,startedAt:Date.now()}}t.curThink.body.textContent+=n,e===l()&&a()}}export function onMeta(n,o,e){if(e==="tool"&&y()==="quiet")return;const r=d(o);f(r);const i=(n||"").trim();if(!r||!i)return;x(r),finishMd();const u=i.indexOf("⚠")!==-1||i.indexOf("✗")!==-1;m(r,w("div",u?"metaln warn":"metaln",i)),r===l()&&a()}export function onRetract(n,o){const e=d(o);if(!e)return;f(e);const r=t.curMd?t.curMd.root:null,i=!!r||t.curText!=null&&t.curText!=="",u=t.curText?t.curText.length:0;if(finishMd(),finishThink(),r){const T=t.turnRoots.indexOf(r);T!==-1&&t.turnRoots.splice(T,1),r.remove()}u>0&&(t.turnMd=t.turnMd.slice(0,Math.max(0,t.turnMd.length-u))),i&&(n&&m(e,w("div","metaln",n)),e===l()&&a())}export function onPhase(n,o){const e=d(o);n==="thinking"?R(e):f(e)}g
|
|
1
|
+
import{msgs as g,el as w,setIcon as k}from"../dom.js";import{t as v}from"../i18n.js";import{feed as t}from"../store.js";import{verbosity as y}from"../format.js";import{mountMarkdown as b}from"../../md.js";import{activeFeed as l,feedForEvent as d,clearBusy as f,clearEmpty as x,flushRun as M,showBusy as R,appendTo as m,scroll as a,mdOpts as A,buildThinkBlock as F}from"./core.js";let s="",c=null,p=!1;function h(){if(p=!1,!s||!t.curMd){s="",c=null;return}const n=s,o=c;s="",c=null,t.curMd.write(n),o&&o===l()&&a()}function L(){p||(p=!0,typeof window<"u"&&typeof window.requestAnimationFrame=="function"?window.requestAnimationFrame(h):h())}export function finishMd(){h(),t.curMd&&(t.curMd.root.classList.remove("streaming"),t.curMd.end(),t.curMd=null),t.curText=null}export function onText(n,o){const e=d(o);f(e),e&&(x(e),t.curThink&&finishThink(),t.curText==null&&(M(),t.curText="",t.curMd=b(e,A(!0)),t.curMd.root.classList.add("streaming"),t.turnRoots.push(t.curMd.root)),t.curText+=n,t.turnMd+=n,c&&c!==e&&h(),c=e,s+=n,L())}export function finishThink(){if(t.curThink&&(t.curThink.wrap&&t.curThink.wrap.classList.remove("live"),t.curThink.startedAt)){const n=t.curThink.head.querySelector(".dur");n&&(n.textContent="· "+((Date.now()-t.curThink.startedAt)/1e3).toFixed(1)+"s")}t.curThink=null}export function onReasoning(n,o){const e=d(o);if(f(e),!!e){if(x(e),finishMd(),!t.curThink){M();const{wrap:r,head:i,body:u}=F(!0);m(e,r),t.curThink={wrap:r,head:i,body:u,startedAt:Date.now()}}t.curThink.body.textContent+=n,e===l()&&a()}}export function onMeta(n,o,e){if(e==="tool"&&y()==="quiet")return;const r=d(o);f(r);const i=(n||"").trim();if(!r||!i)return;x(r),finishMd();const u=i.indexOf("⚠")!==-1||i.indexOf("✗")!==-1;m(r,w("div",u?"metaln warn":"metaln",i)),r===l()&&a()}export function onRetract(n,o){const e=d(o);if(!e)return;f(e);const r=t.curMd?t.curMd.root:null,i=!!r||t.curText!=null&&t.curText!=="",u=t.curText?t.curText.length:0;if(finishMd(),finishThink(),r){const T=t.turnRoots.indexOf(r);T!==-1&&t.turnRoots.splice(T,1),r.remove()}u>0&&(t.turnMd=t.turnMd.slice(0,Math.max(0,t.turnMd.length-u))),i&&(n&&m(e,w("div","metaln",n)),e===l()&&a())}export function onPhase(n,o){const e=d(o);n==="thinking"?R(e):f(e)}g?.addEventListener("click",n=>{const e=n.target.closest(".think-h");if(!e)return;const r=e.nextElementSibling;if(!r)return;const i=r.classList.toggle("hidden");e.setAttribute("aria-expanded",i?"false":"true");const u=e.querySelector(".tog");u&&k(u,i?"chevron-right":"chevron-down",v(i?"web.action.show":"web.action.hide"))});
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import{el as r,icon as w,announce as g}from"../dom.js";import{t as
|
|
2
|
-
`).length>12){
|
|
1
|
+
import{el as r,icon as w,announce as g}from"../dom.js";import{t as d,pluralCount as _}from"../i18n.js";import{feed as c,tabs as k,session as m}from"../store.js";import{FILE_TOOLS as x,OPENABLE_TOOLS as F,LINK_TOOLS as B,categoryOf as y,labelOf as I,argText as U,formatMs as S,verbosity as b,firstOutputLine as L}from"../format.js";import{copyText as q}from"../../md.js";import{imageCard as P}from"./image-card.js";import{activeFeed as O,liveFeed as j,feedForEvent as a,clearBusy as T,clearEmpty as N,appendTo as h,insertAfter as E,appendActionsRow as D,flushRun as $}from"./core.js";import{finishMd as M,finishThink as R}from"./stream.js";export function onToolStart(e){const n=a(e.sessionId);if(T(n),!n)return;N(n),M(),R(),c.pendingArgs.set(e.toolCallId,e.args||{});const o=r("div","act "+y(e.name));o.appendChild(r("span","g","◇")),o.appendChild(r("span","lab",I(e.name)));const s=U(e.args);s&&(o.appendChild(r("span","sep","·")),o.appendChild(r("span","args",s)));const i=r("span","ok","");o.appendChild(i),o.classList.add("running"),h(n,o),c.toolNodes.set(e.toolCallId,{status:i,line:o}),y(e.name)!=="recon"&&(c.runReconOnly=!1),c.runCount++}function A(e,n){if(typeof n!="string"||!n)return;const o=r("div","toolout"),s=r("div","code");if(s.textContent=n,o.appendChild(s),n.length>600||n.split(`
|
|
2
|
+
`).length>12){o.classList.add("collapsed");const p="▸ "+_("web.tool.output",n.length),l=r("span","more",p);l.addEventListener("click",()=>{const u=o.classList.toggle("collapsed");l.textContent=u?p:"▾ "+d("web.tool.collapse")}),o.appendChild(l)}const t=e&&e.parentNode?null:j();e&&e.parentNode?e.parentNode.insertBefore(o,e.nextSibling):h(t,o)}function K(e){if(typeof e!="string"||!e)return null;try{const n=new URL(e,location.href);if(n.protocol==="http:"||n.protocol==="https:"||n.protocol==="file:")return n.href}catch{return null}return null}function z(e){const n=String(e??"").replace(/\\/g,"/");try{const o=m&&m.host&&m.host.workspace?String(m.host.workspace).replace(/\\/g,"/").replace(/\/+$/,""):"";if(o&&(n===o||n.indexOf(o+"/")===0)){const s=n===o?"":n.slice(o.length+1);if(s)return s}}catch{}return n}function C(e,n,o,s){const i=a(o);if(!i)return null;if(x.indexOf(e)!==-1){const t=n.path||n.file||n.dir;if(!t)return null;const p=z(t),l=r("div","filerow "+y(e));if(l.appendChild(r("span","g","◇")),l.appendChild(r("span","lab",I(e))),l.appendChild(r("span","sep"," · ")),F.indexOf(e)!==-1){const f=r("a","path",p||String(t));f.href="/api/file?path="+encodeURIComponent(String(t)),f.target="_blank",f.rel="noopener noreferrer",f.title=d("web.card.open_title")+" · "+String(t),l.appendChild(f)}else{const f=r("span","tail",p||String(t));f.title=String(t),l.appendChild(f)}const u=r("button","copy-btn");return u.type="button",u.title=d("web.card.copy_title"),u.setAttribute("aria-label",d("web.card.copy_title")),u.appendChild(w("copy")),u.addEventListener("click",()=>{q(String(t)).then(f=>{if(u.replaceChildren(w(f?"check":"copy")),!f){const v=l.querySelector(".st");v&&(v.textContent=" ⚠")}window.setTimeout(()=>u.replaceChildren(w("copy")),1400)})}),l.appendChild(u),l.appendChild(r("span","st",s===!1?" ✗":s===!0?" ✓":"")),s===!1&&(l.dataset.fail="1"),/\.drawio(\.xml)?$/i.test(String(t))&&b()==="verbose"&&l.appendChild(r("span","detail","↳ "+d("web.card.drawio_hint"))),h(i,l),l}if(B.indexOf(e)!==-1&&n.url){const t=r("div","linkline");t.appendChild(document.createTextNode("↳ "));const p=K(n.url);if(p){const l=r("a","",n.url);l.href=p,l.target="_blank",l.rel="noopener noreferrer",t.appendChild(l);try{const u=new URL(p).hostname;u&&t.appendChild(r("span","dom"," · "+u))}catch{}}else t.appendChild(r("span","",n.url));return h(i,t),t}return null}function G(e){if(!e.success||!Array.isArray(e.images)||!e.images.length)return;const n=a(e.sessionId);if(n)for(const o of e.images){const s=P(String(e.name||""),String(o));s&&h(n,s)}}export function onToolEnd(e){H(e),G(e)}function H(e){const n=c.toolNodes.get(e.toolCallId),o=n?n.line:null;if(n){n.line.classList.remove("running");const t=S(e.durationMs);n.status.textContent=e.success?" ✓"+(t?" "+t:""):" ✗"+(t?" "+t:""),e.success||(n.status.classList.add("fail"),c.runFails++,c.runReconOnly=!1)}c.toolNodes.delete(e.toolCallId);const s=c.pendingArgs.get(e.toolCallId)||{};c.pendingArgs.delete(e.toolCallId);const i=s.path||s.file||s.dir;if(x.indexOf(e.name)!==-1&&i){if(o&&o.parentNode&&o.remove(),b()==="quiet"){if(e.success){const p=C(e.name,s,e.sessionId,e.success);p&&c.runNodes.push(p),c.runDuration+=typeof e.durationMs=="number"?e.durationMs:0}else{const p=C(e.name,s,e.sessionId,e.success),l=L(e.output);l&&E(p||o,r("div","detail","↳ "+l)),p&&c.runNodes.push(p)}return}const t=C(e.name,s,e.sessionId,e.success);A(t||o,e.output);return}if(b()==="quiet"){if(e.success){o&&c.runNodes.push(o);const t=C(e.name,s,e.sessionId,e.success);t&&c.runNodes.push(t),c.runDuration+=typeof e.durationMs=="number"?e.durationMs:0}else{const t=L(e.output);t&&E(o,r("div","detail","↳ "+t))}return}e.success&&C(e.name,s,e.sessionId,e.success),A(o,e.output)}export function onTurnEnd(e){m.busy=!1;const n=a(e.sessionId);T(n),R(),M(),$(),c.toolNodes.forEach(i=>{i&&i.line&&n&&i.line.parentNode===n&&i.line.classList.remove("running")});const o=k.tabs.find(i=>i.id===e.sessionId);if(o&&(o.planCard=null),!n){resetTurnText();return}if(e.success===!1)e.interrupted?(h(n,r("div","warnline","⚠ "+d("web.turn.stopped"))),g(d("web.turn.stopped"))):(h(n,r("div","errline","✗ "+d("web.turn.failed"))),g(d("web.turn.failed")));else{const i=[];typeof e.toolCalls=="number"&&e.toolCalls>0&&i.push(d("web.turn.tools",{count:e.toolCalls})),typeof e.durationMs=="number"&&i.push(S(e.durationMs)),i.length&&h(n,r("div","metric","⟡ "+i.join(" · "))),g(d("web.turn.end",{count:e.toolCalls||0}))}const s=c.turnRoots.map(i=>i.innerText||i.textContent||"").join(`
|
|
3
3
|
|
|
4
|
-
`);D(n,s,c.turnMd),resetTurnText()}export function resetTurnText(){c.turnMd="",c.turnRoots=[]}export function onErrorEvent(e){if(!e||!e.error)return;const n=
|
|
5
|
-
`).forEach(s=>
|
|
4
|
+
`);D(n,s,c.turnMd),resetTurnText()}export function resetTurnText(){c.turnMd="",c.turnRoots=[]}export function onErrorEvent(e){if(!e||!e.error)return;const n=a(e.sessionId);n&&h(n,r("div","errline","✗ "+e.error)),g(String(e.error))}export function onCommandOutput(e,n){const o=a(n)||O();o&&(N(o),String(e).split(`
|
|
5
|
+
`).forEach(s=>h(o,r("div","cmdout",s))))}export function onLog(e){if(!e||typeof e.text!="string"||!e.text||e.diagnostic&&b()!=="verbose")return;const n=a(e.sessionId)||O();if(!n)return;const o=e.level,s=o==="error"?"errline":o==="warn"?"warnline":"detail",i=o==="error"?"✗ ":o==="warn"?"⚠ ":"↳ ",t=r("div",s);t.textContent=i+e.text,h(n,t),(o==="error"||o==="warn")&&g(e.text)}
|
package/dist/assets/js/format.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{t as c}from"./i18n.js";import{settings as f}from"./store.js";export const CATEGORIES={recon:["read_file","list_dir","glob","grep","file_info","project_map","chunk_query","web_search","web_fetch","history","recall","process_list","process_log"],mutate:["write_file","edit_file","create_dir","delete_file","move_file","attach_image"],execute:["bash","process_kill","pipeline_run","browser","download_file","subagent","mcp_call"],meta:["plan","plan_step","todo","verify","lsp_check","enable_tools","set_thinking","load_skill","remember"]},FILE_TOOLS=["read_file","write_file","edit_file","list_dir","delete_file","move_file","file_info"],OPENABLE_TOOLS=["read_file","write_file","edit_file","file_info"],
|
|
2
|
-
`)){const r=t.trim();if(r)return r.length>200?r.slice(0,197)+"…":r}return""}export function matchesQuery(e,t){const r=String(t??"").trim().toLowerCase();return r?String(e??"").toLowerCase().indexOf(r)!==-1:!0}export function relTime(e){if(!e)return"";const t=Date.now()-new Date(e).getTime();if(!isFinite(t)||t<0)return"";const r=Math.floor(t/6e4);if(r<1)return"now";if(r<60)return r+"m";const
|
|
1
|
+
import{t as c}from"./i18n.js";import{settings as f}from"./store.js";export const CATEGORIES={recon:["read_file","list_dir","glob","grep","file_info","project_map","chunk_query","web_search","web_fetch","history","recall","process_list","process_log"],mutate:["write_file","edit_file","create_dir","delete_file","move_file","attach_image"],execute:["bash","process_kill","pipeline_run","browser","download_file","subagent","mcp_call"],meta:["plan","plan_step","todo","verify","lsp_check","enable_tools","set_thinking","load_skill","remember"]},FILE_TOOLS=["read_file","write_file","edit_file","list_dir","delete_file","move_file","file_info"],OPENABLE_TOOLS=["read_file","write_file","edit_file","file_info"],LINK_TOOLS=["web_fetch","download_file"];export function categoryOf(e){for(const t of Object.keys(CATEGORIES))if(CATEGORIES[t].indexOf(e)!==-1)return t;return"meta"}export function labelOf(e){const t="tool.friendly."+e,r=c(t);if(r!==t)return r;const n=String(e).replace(/_/g," ");return n.charAt(0).toUpperCase()+n.slice(1)}export function argText(e){if(!e||typeof e!="object")return"";const t=e,r=["path","file","dir","command","query","url","pattern","name","id","text","prompt"];for(const i of r)if(typeof t[i]=="string"&&t[i])return t[i];const n=Object.keys(t);if(!n.length)return"";const o=t[n[0]];if(typeof o=="string")return o;if(typeof o=="number"||typeof o=="boolean")return String(o);try{const i=JSON.stringify(e);return i==="{}"?"":i.slice(0,120)}catch{return""}}export function formatMs(e){return typeof e!="number"||!isFinite(e)?"":e>=1e3?(e/1e3).toFixed(1)+"s":Math.round(e)+"ms"}export function verbosity(){const e=f.config&&f.config.ui||{};return e.verbosity?e.verbosity:e.verbose?"verbose":"quiet"}export function firstOutputLine(e){if(typeof e!="string"||!e)return"";for(const t of e.split(`
|
|
2
|
+
`)){const r=t.trim();if(r)return r.length>200?r.slice(0,197)+"…":r}return""}export function matchesQuery(e,t){const r=String(t??"").trim().toLowerCase();return r?String(e??"").toLowerCase().indexOf(r)!==-1:!0}export function relTime(e){if(!e)return"";const t=Date.now()-new Date(e).getTime();if(!isFinite(t)||t<0)return"";const r=Math.floor(t/6e4);if(r<1)return"now";if(r<60)return r+"m";const n=Math.floor(r/60);return n<24?n+"h":Math.floor(n/24)+"d"}export function fmtTokens(e){return e>=1e3?(e/1e3).toFixed(1)+"K":String(e)}export function contextLabel(){const e=f.config&&f.config.contextWindow||0;return e?Math.round(e/1024)+"K":"—"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{el as r}from"./dom.js";import{t as c}from"./i18n.js";import{setIndicator as f,trapTab as h}from"./dialog.js";import{copyText as g}from"../md.js";let t=null,n=null,p=null,l=null,a=null,u=null;function m(){const e=r("div","lightbox");e.hidden=!0,e.setAttribute("role","dialog"),e.setAttribute("aria-modal","true");const o=r("button","lb-close","✕");o.type="button",o.title=c("web.lightbox.close"),o.setAttribute("aria-label",c("web.lightbox.close"));const d=r("figure","lb-figure");n=document.createElement("img"),n.className="lb-img",n.alt="",d.appendChild(n),p=r("figcaption","lb-cap"),d.appendChild(p);const b=r("div","lb-actions");return l=r("a","lb-open"),l.textContent=c("web.lightbox.open_tab"),l.target="_blank",l.rel="noopener noreferrer",a=r("button","lb-copy",c("web.lightbox.copy")),a.type="button",b.appendChild(l),b.appendChild(a),e.appendChild(o),e.appendChild(d),e.appendChild(b),o.addEventListener("click",closeLightbox),e.addEventListener("click",i=>{i.target===e&&closeLightbox()}),e.addEventListener("keydown",i=>{if(i.key==="Escape"){i.stopPropagation(),closeLightbox();return}h(e,i)}),a.addEventListener("click",()=>{const i=l?.href||"";g(i).then(s=>f(c("web.lightbox.copied"),!s))}),document.body.appendChild(e),e}export function openLightbox(e,o){if(!e||(t||(t=m()),!n||!p||!l||!a))return;n.src=e,p.textContent=o||"",p.hidden=!o,l.href=e,a.textContent=c("web.lightbox.copy"),u=document.activeElement,t.hidden=!1,t.classList.add("open");const d=t.querySelector(".lb-close");d&&d.focus()}export function closeLightbox(){!t||t.hidden||(t.hidden=!0,t.classList.remove("open"),n&&n.removeAttribute("src"),u&&u.focus&&u.focus(),u=null)}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{el as c,makeToggle as y}from"../dom.js";import{tagsEditor as u,checkboxEditor as g,tableEditor as b}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 l(i,e){const s=c("input");return s.setAttribute("aria-label",i),s.value=e,s}export function controlFor(i,e,s){if(i.readOnly){const t=c("span","val dim",e==null?"—":String(e));return e!=null&&(t.title=String(e)),t}if(i.valueType==="bool")return y(!!e,t=>(s.post(t),!0));if(i.valueType==="enum"){const t=c("select");return t.setAttribute("aria-label",s.label),(i.enum||[]).forEach(n=>{const o=c("option","",s.enumLabel(n));o.value=n,n===e&&(o.selected=!0),t.appendChild(o)}),t.addEventListener("change",()=>s.post(t.value)),t}if(i.valueType==="int"){const t=l(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=l(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==="tags"&&(i.valueType==="list"||i.valueType==="json"))return u(e,s,r);if(r&&r.kind==="checkboxes")return g(e,s,r);if(r&&r.kind==="table")return b(e,s,r);if(i.valueType==="list"){const t=Array.isArray(e)?e.join(", "):e==null?"":String(e),n=l(s.label,t);return n.placeholder="a, b, c",n.addEventListener("change",()=>s.post(n.value)),n}if(i.valueType==="json"){const t=c("div","jsonctl"),n=c("textarea");n.setAttribute("aria-label",s.label),n.rows=3,n.value=e==null?"":JSON.stringify(e,null,2);const o=c("div","json-err");return o.hidden=!0,n.addEventListener("input",()=>{const d=validateJson(n.value);o.hidden=d.ok,o.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(o),t}const a=l(s.label,e==null?"":String(e));return a.addEventListener("change",()=>s.post(a.value)),a}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","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"]}],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 a of r.keys)i.set(a,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.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 l}from"../dom.js";import{t as
|
|
1
|
+
import{el as l}from"../dom.js";import{t as q}from"../i18n.js";export function tagsEditor(f,i,A){const r=Array.isArray(f)?f.map(String):[],u=l("div","tagsctl ctl-block"),d=l("div","tags-list"),k=()=>i.post(JSON.stringify(r)),s=()=>{d.textContent="",r.forEach((o,O)=>{const $=l("span","tag-chip"),g=l("span","tag-text",o);g.title=o,$.appendChild(g);const E=l("button","tag-rm linkbtn","✕");E.type="button",E.setAttribute("aria-label",`${i.label}: remove ${o}`),E.addEventListener("click",()=>{r.splice(O,1),k(),s()}),$.appendChild(E),d.appendChild($)}),r.length||d.appendChild(l("span","tags-empty",i.emptyLabel||"—"))};s(),u.appendChild(d);const y=l("div","tags-add"),c=l("input");c.type="text",c.placeholder=A.placeholder||"…",c.setAttribute("aria-label",i.label);const C=()=>{const o=c.value.trim();if(!o||r.includes(o)){c.select();return}r.push(o),k(),s(),c.value="",c.focus()};c.addEventListener("keydown",o=>{o.key==="Enter"&&(o.preventDefault(),C())}),y.appendChild(c);const b=l("button","tags-plus linkbtn","+");return b.type="button",b.setAttribute("aria-label",`${i.label}: add`),b.addEventListener("click",C),y.appendChild(b),u.appendChild(y),u}export function checkboxEditor(f,i,A){const r=new Set(Array.isArray(f)?f.map(String):[]),u=l("div","checksctl ctl-block");return(A.options||[]).forEach(d=>{const k=l("label","check-line"),s=l("input");s.type="checkbox",s.checked=r.has(d),s.addEventListener("change",()=>{s.checked?r.add(d):r.delete(d),i.post(JSON.stringify([...r]))}),k.appendChild(s),k.appendChild(l("span","",i.enumLabel?i.enumLabel(d):d)),u.appendChild(k)}),u}export function tableEditor(f,i,A){const r=A.columns||[],u=r[0],d=r.slice(1),k=f&&typeof f=="object"&&!Array.isArray(f)?f:{},s=Object.entries(k).map(([e,t])=>({name:e,val:t&&typeof t=="object"?{...t}:{},error:""})),y=l("div","tablectl ctl-block"),c=l("div","table-head");r.forEach(e=>c.appendChild(l("span","table-th",i.fieldLabel(e.key)))),y.appendChild(c);const C=l("div","table-body"),b=l("div","json-err");b.hidden=!0;const o=e=>e.array===!0,O=e=>e===void 0||e===""||Array.isArray(e)&&e.length===0,$=()=>{const e={};for(const t of s){if(!t.name)return{ok:!1,reason:"empty name"};if(e[t.name]!==void 0)return{ok:!1,reason:`duplicate: ${t.name}`};const a={};for(const n of d){const p=t.val[n.key];if(!(n.optional&&O(p))){if(!n.optional&&O(p))return{ok:!1,reason:`${t.name}: ${i.fieldLabel(n.key)}`};if(n.type==="number"){const S=Number(p);if(!Number.isFinite(S)||S<0)return{ok:!1,reason:`${t.name}: ${i.fieldLabel(n.key)}`};a[n.key]=S}else n.type==="bool"?p===!0&&(a[n.key]=!0):a[n.key]=o(n)?p:String(p)}}e[t.name]=a}return{ok:!0,value:e}},g=()=>{const e=$();return e.ok?(b.hidden=!0,b.textContent="",i.post(JSON.stringify(e.value)),!0):(b.hidden=!1,b.textContent=q("web.settings.table_invalid",{field:e.reason||""}),!1)},E=(e,t,a)=>{if(t.type==="bool")a.checked?e.val[t.key]=!0:delete e.val[t.key];else if(t.type==="number"){const n=a.value.trim();n===""?delete e.val[t.key]:e.val[t.key]=Number(n)}else{const n=a.value.trim();n===""?delete e.val[t.key]:e.val[t.key]=o(t)?n.split(",").map(p=>p.trim()).filter(Boolean):n}},F=(e,t)=>{const a=e.val[t.key];if(t.optionsSource){const S=t.optionsSource==="providers"?i.providerOptions||[]:i.modelOptions||[],L=a==null?"":String(a),h=l("select"),D=l("option","","—");D.value="",h.appendChild(D);const J=new Set([""]);if(S.forEach(m=>{if(J.has(m))return;J.add(m);const w=l("option","",m);w.value=m,m===L&&(w.selected=!0),h.appendChild(w)}),L&&!J.has(L)){const m=l("option","",L);m.value=L,m.selected=!0,h.appendChild(m)}return h.value=L||"",h.setAttribute("aria-label",`${e.name}: ${i.fieldLabel(t.key)}`),h.addEventListener("change",()=>{h.value?e.val[t.key]=h.value:delete e.val[t.key],g()}),h}const n=l("input");return t.type==="bool"?(n.type="checkbox",n.checked=a===!0):t.type==="number"?(n.type="number",n.value=a==null?"":String(a)):(n.type="text",n.value=Array.isArray(a)?a.join(", "):a==null?"":String(a)),n.setAttribute("aria-label",`${e.name}: ${i.fieldLabel(t.key)}`),n.addEventListener("change",()=>{E(e,t,n),g()}),n},j=()=>{C.textContent="",s.forEach(e=>{const t=l("div","table-row");t.dataset.key=e.name;const a=l("input");a.type="text",a.value=e.name,a.placeholder=i.fieldLabel(u.key),a.setAttribute("aria-label",i.fieldLabel(u.key)),a.addEventListener("change",()=>{e.name=a.value.trim(),g()&&(t.dataset.key=e.name)}),t.appendChild(a),d.forEach(p=>t.appendChild(F(e,p)));const n=l("button","table-rm linkbtn","✕");n.type="button",n.setAttribute("aria-label",`${i.label}: remove ${e.name}`),n.addEventListener("click",()=>{s.splice(s.indexOf(e),1),g()&&j()}),t.appendChild(n),C.appendChild(t)})};j(),y.appendChild(C),y.appendChild(b);const I=l("div","table-add"),v=l("input");v.type="text",v.placeholder=i.fieldLabel(u.key),v.setAttribute("aria-label",`${i.label}: new ${i.fieldLabel(u.key)}`);const B=()=>{const e=v.value.trim();if(!e||s.some(p=>p.name===e)){v.select();return}const t={};s.push({name:e,val:t,error:""}),v.value="",j();const a=C.lastElementChild,n=a&&a.querySelectorAll("input,select")[1];n&&n.focus()};v.addEventListener("keydown",e=>{e.key==="Enter"&&(e.preventDefault(),B())}),I.appendChild(v);const N=l("button","table-plus linkbtn","+");return N.type="button",N.setAttribute("aria-label",`${i.label}: add`),N.addEventListener("click",B),I.appendChild(N),y.appendChild(I),y}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{el as i,icon as O,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 F,closeSubDialog as x}from"./subdialog.js";import{mcpLiteralField as v,providerInput as _,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 a=i("div","row"),o=i("div","row-label");if(o.appendChild(i("span","row-name",e)),t&&o.appendChild(i("span","row-desc",t)),a.appendChild(o),typeof n=="string"){const d=i("span","val",n);d.title=n,a.appendChild(d)}else n&&a.appendChild(n);return a}export function descFor(e){const n="config.desc."+e,t=s(n);return t===n?"":t}function B(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"),fieldLabel:a=>{const o="config.field."+a,d=s(o);return d===o?a:d},post:a=>{j(n,a,!1)}})}function Y(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 a=i("div","sec-body");return e.keys.forEach(o=>{const d=defFor(o);d&&a.appendChild(row(configLabel(d),B(d,o),descFor(d.key)))}),n.appendChild(a),n}export function renderSections(e,n){const t=document.querySelector('[data-panel="'+e+'"]');t&&n.forEach(a=>t.appendChild(Y(a)))}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 a=i("div","sec-body");return n.appendChild(a),{el:n,head:t,body:a}}export function chip(e,n,t){const a=i("button","chip"+(n?" "+n:""),e);return a.type="button",a.addEventListener("click",t),a}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"),a=i("div","sec-head");a.appendChild(i("span","sec-title",s("web.settings.sec.ui.theme"))),t.appendChild(a);const o=s("web.settings.sec.ui.theme.desc");o!=="web.settings.sec.ui.theme.desc"&&t.appendChild(i("div","sec-desc",o));const d=i("div","sec-body");d.appendChild(row(s("web.settings.theme"),n)),t.appendChild(d),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 z(){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 a=i("div","sec-body");a.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"))),a.appendChild(o),n.appendChild(a),e.appendChild(n)}const G=["conventions","decisions","errors","facts"];function Q(){const e=i("div","pform"),n=i("div","pform-grid"),t=i("select");t.setAttribute("aria-label",s("web.settings.memory_category")),G.forEach(d=>t.appendChild(i("option","",d))),t.value="facts",n.appendChild(v(s("web.settings.memory_category"),t)),e.appendChild(n);const a=i("textarea");a.rows=5,a.placeholder=s("web.settings.new_memory"),a.value="",e.appendChild(v(s("web.settings.new_memory"),a));const o=i("div","pform-actions");o.appendChild(k(s("web.settings.save"),"",async()=>{const d=a.value.trim();if(!d){a.focus();return}const r=await w("/api/memory",{method:"POST",body:{category:t.value,text:d}});r.ok&&r.data&&r.data.ok?(x(),await loadMemory()):C(s("web.settings.add_failed"),!0)})),o.appendChild(k(s("web.settings.cancel"),"dim",()=>x())),e.appendChild(o),F(s("web.settings.memory_add_title"),e,()=>L())}function L(){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(O("plus")),t.appendChild(i("span","",s("web.settings.add"))),t.addEventListener("click",()=>Q());const a=i("div","sec-head");a.appendChild(i("span","sec-title",s("web.settings.sec.memory.add"))),a.appendChild(t);const o=i("div","settings-section");o.appendChild(a),e.appendChild(o);const d=i("input","searchbox");d.placeholder=s("web.settings.search_memory"),d.setAttribute("aria-label",s("web.settings.search_memory")),e.appendChild(d);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=d.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)}};d.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 a=i("div","skill-item"),o=i("div","skill-head");o.appendChild(i("span",t.enabled?"g":"dim",t.enabled?"✓":"○"));const d=i("span","name",t.name);if(d.title=t.name,o.appendChild(d),o.appendChild(i("span","st",t.enabled?s("web.settings.enabled"):s("web.settings.available"))),a.appendChild(o),t.source){const r=i("div","skill-src",t.source);r.title=t.source,a.appendChild(r)}n.appendChild(a)}),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 d=i("div","placeholder");d.textContent=s("web.settings.no_plugins"),t.appendChild(d)}(n.plugins||[]).forEach(d=>{const r=i("div","list-line");r.appendChild(i("span","g","✓"));const p=i("span","name",d.name);if(p.title=d.name,r.appendChild(p),d.version&&r.appendChild(i("span","src","v"+d.version)),d.source){const u=i("span","src",d.source);u.title=d.source,r.appendChild(u)}d.builtin&&r.appendChild(i("span","src",s("web.settings.builtin"))),r.appendChild(i("span","st",d.enabled===!1?s("web.settings.disabled"):s("web.settings.enabled"))),t.appendChild(r)});const a=i("div","settings-note");a.textContent=s("web.settings.plugins_note"),t.appendChild(a),t.appendChild(groupHeader(s("web.settings.mcp_servers"),(n.mcp||[]).length));const o=i("button","sec-add");if(o.type="button",o.appendChild(O("plus")),o.appendChild(i("span","",s("web.settings.mcp_add"))),o.addEventListener("click",()=>R("add",null)),t.appendChild(o),!(n.mcp||[]).length){const d=i("div","placeholder");d.textContent=s("web.settings.no_mcp"),t.appendChild(d)}if((n.mcp||[]).forEach(d=>{const r=i("div","list-line"),p=d.status!=="disabled",u=J(p,h=>{w("/api/mcp/"+encodeURIComponent(d.id||d.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",d.name);b.title=d.name,r.appendChild(b),r.appendChild(i("span","st",d.status||"—")),r.appendChild(chip(s("web.settings.edit"),"",()=>R("edit",d))),r.appendChild(chip(s("web.settings.delete"),"danger",async()=>{const h=await w("/api/mcp/"+encodeURIComponent(d.id||d.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 d=i("div","settings-note");d.textContent=s("web.settings.mcp_note"),t.appendChild(d)}X(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"),a=i("div","pform-grid"),o=_(n.name||"","text","my-server"),d=H(["stdio","sse","http"],n.transport||"stdio"),r=_(n.command||"","text","npx"),p=_(n.url||"","text","https://…");a.appendChild(v("name",o)),a.appendChild(v("transport",d)),a.appendChild(v("command",r)),a.appendChild(v("url",p)),t.appendChild(a);const u=i("details","pform-adv");u.appendChild(i("summary","",s("web.settings.provider_advanced")));const b=_(n.args?JSON.stringify(n.args):"","text",'["--stdio"]'),h=_(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 T={name:o,transport:d,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"),"",()=>{W(T,e,n)})),A.appendChild(k(s("web.settings.cancel"),"dim",()=>x())),t.appendChild(A),t}function R(e,n){l.mcpForm={mode:e,entry:n||null},F(s(e==="edit"?"web.settings.mcp_edit_title":"web.settings.mcp_add"),K(),()=>{l.mcpForm=null,S(),loadPlugins()})}function V(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(a=>typeof a=="string")?{present:!0,value:t}:{present:!0,value:null}}async function W(e,n,t){const a=e.name.value.trim(),o=e.transport.value||"stdio",d=e.command.value.trim(),r=e.url.value.trim();if(!a||(o==="stdio"?!d:!r)){C(s("web.settings.mcp_required"),!0);return}const p={name:a,transport:o};d&&(p.command=d),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=V(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),x()):C(g.data&&g.data.error||s("web.settings.save_failed"),!0)}function X(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 a=i("div","list-line");a.appendChild(i("span",t.enabled?"g":"dim",t.enabled?"✓":"○"));const o=i("span","name",t.lang);o.title=t.lang,a.appendChild(o);const d=[t.command,t.timeout!=null?t.timeout+" ms":null].filter(Boolean).join(" · ");d&&a.appendChild(i("span","src",d)),a.appendChild(i("span","st",t.enabled?s("web.settings.enabled"):s("web.settings.disabled"))),a.appendChild(chip(s("web.settings.edit"),"",()=>Z(t))),e.appendChild(a)}),n.length){const t=i("div","settings-note");t.textContent=s("web.settings.lsp_note"),e.appendChild(t)}}function Z(e){l.lspForm={lang:e.lang,entry:e},F(e.lang,$(),()=>{l.lspForm=null,S(),loadLsp()})}function $(){const e=l.lspForm&&l.lspForm.entry||{},n=l.lspForm&&l.lspForm.lang||e.lang||"",t=i("div","pform"),a=i("div","pform-grid"),o=_(e.command||"","text","npx"),d=_(e.timeout!=null?String(e.timeout):"","number","30000"),r=P(e.enabled!==!1);a.appendChild(v("command",o)),a.appendChild(v("timeout (ms)",d)),a.appendChild(v("enabled",r)),t.appendChild(a);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=d.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),x()):C(m.data&&m.data.error||s("web.settings.save_failed"),!0)})),u.appendChild(k(s("web.settings.cancel"),"dim",()=>x())),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,L()}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,L as renderMemoryPanel,M as renderSkillsPanel,S as renderPluginsPanel,z as renderSecurityPanel};
|
|
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};
|