@deepseek-insight/dsi 0.5.19 → 0.5.20
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/.agents/skills/dsi-ov-setup/SKILL.md +114 -0
- package/bin/dsi.mjs +62 -2
- package/build/client/_app/immutable/assets/{2.Da1CnqbG.css → 2.Dk-hwaP_.css} +1 -1
- package/build/client/_app/immutable/chunks/CodI3RGj.js +1 -0
- package/build/client/_app/immutable/chunks/{CLNDb8QN.js → CxmtCU9s.js} +1 -1
- package/build/client/_app/immutable/chunks/DKDzTags.js +2 -0
- package/build/client/_app/immutable/chunks/{Dv2f6AVG.js → azDKH4zi.js} +1 -1
- package/build/client/_app/immutable/chunks/qIBjcgkE.js +1 -0
- package/build/client/_app/immutable/entry/{app.C8CwtYTr.js → app.CqYGeqRv.js} +2 -2
- package/build/client/_app/immutable/entry/start.CIXiL_7f.js +1 -0
- package/build/client/_app/immutable/nodes/{0.VWq3h0rH.js → 0.u99aBgpL.js} +1 -1
- package/build/client/_app/immutable/nodes/{1.Dnl1P2aB.js → 1.qcRcZCY6.js} +1 -1
- package/build/client/_app/immutable/nodes/2.GgqfB5rv.js +171 -0
- package/build/client/_app/version.json +1 -1
- package/build/handler.js +4 -4
- package/build/index.js +4 -4
- package/build/server/chunks/chunks/{app-config.svelte.js-rN4N5yAI.js → app-config.svelte.js-CFb4kaFl.js} +7 -3
- package/build/server/chunks/chunks/{db.js-DbbYS9o8.js → db.js-9wP1ySFv.js} +2 -2
- package/build/server/chunks/chunks/{db2.js-BQWa7bEG.js → db2.js-B_Un4Zvq.js} +7 -5
- package/build/server/chunks/chunks/{dsh-connection.js-CpcCtA42.js → dsh-connection.js-CwL9I98w.js} +4 -3
- package/build/server/chunks/chunks/{git-probe.js-CvkToKO4.js → git-probe.js-C7z6xDzg.js} +3 -3
- package/build/server/chunks/chunks/{insight-config.js-Dw_Qi0fO.js → insight-config.js-COS9LOWZ.js} +13 -4
- package/build/server/chunks/chunks/{internal.js-BDS_h7zE.js → internal.js-Bf2uRIVS.js} +2 -2
- package/build/server/chunks/chunks/{permission-state.js-yvwUSnug.js → permission-state.js-BoJAoWqi.js} +18 -15
- package/build/server/chunks/chunks/settings-home.js-CqnqJVOu.js +9 -0
- package/build/server/chunks/chunks/settings-home2.js-f75-B6RI.js +102 -0
- package/build/server/chunks/chunks/{state.js-eZmA7eF7.js → state.js-OWX1K3Yj.js} +2 -2
- package/build/server/chunks/chunks/{watcher.js-C97Xyorx.js → watcher.js-Dc9hzRLI.js} +4 -4
- package/build/server/chunks/entries/endpoints/api/a2a/_id_/{_server.ts.js-Cqh1iqgu.js → _server.ts.js-0rfV7w20.js} +4 -3
- package/build/server/chunks/entries/endpoints/api/a2a/{_server.ts.js-DNKD4rZu.js → _server.ts.js-DX0DUIja.js} +6 -5
- package/build/server/chunks/entries/endpoints/api/a2a/register/{_server.ts.js-CJ-FwkrZ.js → _server.ts.js-zB-V9Naa.js} +6 -5
- package/build/server/chunks/entries/endpoints/api/config/{_server.ts.js-CMM4kYVx.js → _server.ts.js-Bo4VgIna.js} +5 -3
- package/build/server/chunks/entries/endpoints/api/dsh/directory/{_server.ts.js-epVplzwB.js → _server.ts.js-_Wc4NU0Q.js} +4 -3
- package/build/server/chunks/entries/endpoints/api/dsh/pick-directory/{_server.ts.js-bXHb97gT.js → _server.ts.js-CvoINUYy.js} +4 -3
- package/build/server/chunks/entries/endpoints/api/dsh/presets/{_server.ts.js-BNOHhtzy.js → _server.ts.js-B4UwZ8nd.js} +4 -3
- package/build/server/chunks/entries/endpoints/api/dsh/session/_sessionId_/attachment/{_server.ts.js-BBi6jeVj.js → _server.ts.js-Hml2J0Bq.js} +4 -3
- package/build/server/chunks/entries/endpoints/api/dsh/session/_sessionId_/cancel/{_server.ts.js-N0nKPuqL.js → _server.ts.js-CsZ2u8cs.js} +4 -3
- package/build/server/chunks/entries/endpoints/api/dsh/session/_sessionId_/catalog/{_server.ts.js-VGFCPAbs.js → _server.ts.js-BhF1Nzig.js} +4 -3
- package/build/server/chunks/entries/endpoints/api/dsh/session/_sessionId_/command/{_server.ts.js-na_sUb0Z.js → _server.ts.js-BGXjV_Ak.js} +4 -3
- package/build/server/chunks/entries/endpoints/api/dsh/session/_sessionId_/events/{_server.ts.js-CeNf028P.js → _server.ts.js-BF4vBIja.js} +5 -4
- package/build/server/chunks/entries/endpoints/api/dsh/session/_sessionId_/fork/{_server.ts.js-DfqO-GO4.js → _server.ts.js-B2OwrEQD.js} +4 -3
- package/build/server/chunks/entries/endpoints/api/dsh/session/_sessionId_/goal/{_server.ts.js-Dj9GYNl7.js → _server.ts.js-DboY_7cp.js} +4 -3
- package/build/server/chunks/entries/endpoints/api/dsh/session/_sessionId_/history/{_server.ts.js-DqShsRl9.js → _server.ts.js-BpioYdnc.js} +4 -3
- package/build/server/chunks/entries/endpoints/api/dsh/session/_sessionId_/models/{_server.ts.js-BQSBUf70.js → _server.ts.js-CLrgUoq0.js} +4 -3
- package/build/server/chunks/entries/endpoints/api/dsh/session/_sessionId_/path/{_server.ts.js-CeCKDyKB.js → _server.ts.js-BlZr_mA6.js} +3 -2
- package/build/server/chunks/entries/endpoints/api/dsh/session/_sessionId_/permission/{_server.ts.js-CadTCNUJ.js → _server.ts.js-BiU_IgYD.js} +4 -3
- package/build/server/chunks/entries/endpoints/api/dsh/session/_sessionId_/prompt/{_server.ts.js-BXzgi8xX.js → _server.ts.js-FV-4ougZ.js} +4 -3
- package/build/server/chunks/entries/endpoints/api/dsh/session/_sessionId_/rename/{_server.ts.js-BfD5FXiL.js → _server.ts.js-ChxB0XU5.js} +4 -3
- package/build/server/chunks/entries/endpoints/api/dsh/session/_sessionId_/respond/{_server.ts.js-CiDPC9TY.js → _server.ts.js-DkSydg_X.js} +4 -3
- package/build/server/chunks/entries/endpoints/api/dsh/session/_sessionId_/select-model/{_server.ts.js-DGcZgN96.js → _server.ts.js-Wbuf-vse.js} +4 -3
- package/build/server/chunks/entries/endpoints/api/dsh/sessions/{_server.ts.js-DnU1CCOw.js → _server.ts.js-B-BfCKKL.js} +4 -3
- package/build/server/chunks/entries/endpoints/api/dsh/workspace-file/{_server.ts.js-BZ0UV1n2.js → _server.ts.js-fKfv5g19.js} +4 -3
- package/build/server/chunks/entries/endpoints/api/dsh/workspace-file-bytes/{_server.ts.js-lxLpuPFL.js → _server.ts.js-DZpRzvas.js} +4 -3
- package/build/server/chunks/entries/endpoints/api/dsh/workspace-tree/{_server.ts.js-Cw3vl704.js → _server.ts.js-Hn5-fnsU.js} +4 -3
- package/build/server/chunks/entries/endpoints/api/dsh/workspaces/{_server.ts.js-KKnR2UO4.js → _server.ts.js-CtPDRjV7.js} +4 -3
- package/build/server/chunks/entries/endpoints/api/dsh/workspaces/_workspaceId_/delete/{_server.ts.js-I1eSZn60.js → _server.ts.js-DOp3nIcK.js} +4 -3
- package/build/server/chunks/entries/endpoints/api/dsh/workspaces/_workspaceId_/rename/{_server.ts.js-B0zqAKnV.js → _server.ts.js-DiwcZfK9.js} +4 -3
- package/build/server/chunks/entries/endpoints/api/prompts/_id_/{_server.ts.js-C-QN0enK.js → _server.ts.js-SoNSMvWj.js} +4 -3
- package/build/server/chunks/entries/endpoints/api/prompts/{_server.ts.js-CwTGUPIp.js → _server.ts.js-DIZiiHk-.js} +12 -4
- package/build/server/chunks/entries/endpoints/api/prompts/use/{_server.ts.js-Bvotxm37.js → _server.ts.js-CbsUk0fk.js} +4 -3
- package/build/server/chunks/entries/endpoints/api/settings/{_server.ts.js-CRRLXk0y.js → _server.ts.js-DCeIpzKT.js} +3 -2
- package/build/server/chunks/entries/endpoints/api/settings-home/file/_server.ts.js-C1gSFX1P.js +68 -0
- package/build/server/chunks/entries/endpoints/api/settings-home/file-write/_server.ts.js-Dx0glK_q.js +68 -0
- package/build/server/chunks/entries/endpoints/api/settings-home/tree/_server.ts.js-CAmn2SKB.js +61 -0
- package/build/server/chunks/entries/endpoints/api/workspace/file-write/{_server.ts.js-DY_NDlYl.js → _server.ts.js-Blw1UFX2.js} +6 -5
- package/build/server/chunks/entries/endpoints/api/workspace/git-events/{_server.ts.js-DHEaymrG.js → _server.ts.js-yflU8VH2.js} +6 -5
- package/build/server/chunks/entries/endpoints/api/workspace/git-file-head/{_server.ts.js-AQgNkfCV.js → _server.ts.js-q9jXuJ1p.js} +10 -18
- package/build/server/chunks/entries/endpoints/api/workspace/git-map/{_server.ts.js-C9vxPbB3.js → _server.ts.js-YjwnbPfG.js} +12 -20
- package/build/server/chunks/entries/endpoints/api/workspace/git-status/{_server.ts.js-BlMRR11v.js → _server.ts.js-DRQay15h.js} +12 -20
- package/build/server/chunks/entries/endpoints/api/workspace/write-gate/_server.ts.js-BiCzLyNH.js +54 -0
- package/build/server/chunks/entries/pages/{_error.svelte.js-DIRRk8AK.js → _error.svelte.js-DkmmDHjP.js} +3 -3
- package/build/server/chunks/entries/pages/{_page.server.ts.js-ze2dUhXW.js → _page.server.ts.js-BHW1mzYQ.js} +3 -3
- package/build/server/chunks/entries/pages/{_page.svelte.js-CYT_NWww.js → _page.svelte.js-BSt3-Adz.js} +993 -532
- package/build/server/chunks/{handler-jvQdYpdY.js → handler-CEAxnB4f.js} +3 -3
- package/build/server/chunks/{index.js-BGLJR092.js → index.js-B-3rUYGC.js} +2 -2
- package/build/server/chunks/{manifest.js-CIb6Wm5j.js → manifest.js--ZDTDlzU.js} +71 -43
- package/build/server/chunks/nodes/{0.js-CQ3k21rg.js → 0.js-BQXxAZac.js} +2 -2
- package/build/server/chunks/nodes/{1.js-NI6SZ6un.js → 1.js-DMcugevB.js} +3 -3
- package/build/server/chunks/nodes/{2.js-BG_HkTrm.js → 2.js-BrT7uCAN.js} +9 -8
- package/package.json +2 -2
- package/template/.dsi/config.json +2 -2
- package/template/.dsi/prompts.sqlite +0 -0
- package/template/.dsi/settings.yaml +2 -1
- package/build/client/_app/immutable/chunks/BeeAmuEs.js +0 -2
- package/build/client/_app/immutable/chunks/BgF4MPCH.js +0 -1
- package/build/client/_app/immutable/chunks/h_AAZIXW.js +0 -1
- package/build/client/_app/immutable/entry/start.CCr7WSxA.js +0 -1
- package/build/client/_app/immutable/nodes/2.0fqLf_Nw.js +0 -170
|
@@ -1,13 +1,13 @@
|
|
|
1
|
-
import { c as onDestroy } from '../../chunks/internal.js-
|
|
2
|
-
import { V as head, y as derived, X as bind_props, W as escape_html, Y as attr, Z as attr_style, _ as attr_class, x as setContext, $ as spread_props, a0 as attributes, a1 as clsx, a2 as ensure_array_like, a3 as element, J as getContext, a4 as stringify, a5 as html,
|
|
1
|
+
import { c as onDestroy } from '../../chunks/internal.js-Bf2uRIVS.js';
|
|
2
|
+
import { V as head, y as derived, X as bind_props, W as escape_html, Y as attr, Z as attr_style, _ as attr_class, x as setContext, $ as spread_props, a0 as attributes, a1 as clsx, a2 as ensure_array_like, a3 as element, J as getContext, a4 as stringify, a5 as html, F as run, a6 as props_id } from '../../chunks/server.js-11-pxAWV.js';
|
|
3
3
|
import { U as UI_LOCALES } from '../../chunks/config.js-iG_1bK3r.js';
|
|
4
4
|
import { m as mergeEntries, c as collapseSystemPromptEntries, t as truncate } from '../../chunks/dsh-events.js-BtDxaV6Q.js';
|
|
5
5
|
import { p as parseA2aSignature, m as mintA2aId, b as buildDeliveredText } from '../../chunks/a2a-protocol.js-C77mVg2Q.js';
|
|
6
|
-
import { b as applyKnobEvent, E as EMPTY_KNOBS, r as resolvePermission, l as localPermission, c as presetLabel, d as presetDescription } from '../../chunks/permission-state.js-
|
|
6
|
+
import { b as applyKnobEvent, E as EMPTY_KNOBS, r as resolvePermission, l as localPermission, c as presetLabel, d as presetDescription } from '../../chunks/permission-state.js-BoJAoWqi.js';
|
|
7
7
|
import { D as DEFAULT_IMAGE_LIMITS } from '../../chunks/image-limits.js-CUdJ0f7r.js';
|
|
8
|
-
import { a as appConfig, t as textPreviewOf, b as triggerMode, g as getTrigger, p as previewSegments, i as isValidTagWord, s as searchKey, c as shouldRecordPrompt } from '../../chunks/app-config.svelte.js-
|
|
8
|
+
import { a as appConfig, t as textPreviewOf, b as triggerMode, g as getTrigger, p as previewSegments, i as isValidTagWord, s as searchKey, c as shouldRecordPrompt } from '../../chunks/app-config.svelte.js-CFb4kaFl.js';
|
|
9
9
|
import { c as getLocale } from '../../chunks/runtime.js-BPLc5RLR.js';
|
|
10
|
-
import { p as page, a as afterNavigate, t, r as replaceState, c as currentLocale } from '../../chunks/state.js-
|
|
10
|
+
import { p as page, a as afterNavigate, t, r as replaceState, c as currentLocale } from '../../chunks/state.js-OWX1K3Yj.js';
|
|
11
11
|
import 'yaml';
|
|
12
12
|
import 'html-to-image';
|
|
13
13
|
import hljs from 'highlight.js/lib/core';
|
|
@@ -1535,6 +1535,34 @@ var fileeyeexternalchange3 = ((inputs = {}, options = {}) => {
|
|
|
1535
1535
|
return en_fileeyeexternalchange3();
|
|
1536
1536
|
});
|
|
1537
1537
|
//#endregion
|
|
1538
|
+
//#region src/lib/paraglide/messages/fileeyenewfile3.js
|
|
1539
|
+
/** @typedef {import('../runtime.js').LocalizedString} LocalizedString */
|
|
1540
|
+
/** @typedef {{}} Fileeyenewfile3Inputs */
|
|
1541
|
+
var en_fileeyenewfile3 = () => {
|
|
1542
|
+
return `New file — nothing committed to diff against yet`;
|
|
1543
|
+
};
|
|
1544
|
+
var zh_fileeyenewfile3 = () => {
|
|
1545
|
+
return `新文件——尚无已提交版本可供对比`;
|
|
1546
|
+
};
|
|
1547
|
+
var id_fileeyenewfile3 = () => {
|
|
1548
|
+
return `Berkas baru — belum ada versi terkommit untuk dibandingkan`;
|
|
1549
|
+
};
|
|
1550
|
+
/**
|
|
1551
|
+
* | output |
|
|
1552
|
+
* | --- |
|
|
1553
|
+
* | "New file — nothing committed to diff against yet" |
|
|
1554
|
+
*
|
|
1555
|
+
* @param {Fileeyenewfile3Inputs} inputs
|
|
1556
|
+
* @param {{ locale?: "en" | "zh" | "id" }} options
|
|
1557
|
+
* @returns {LocalizedString}
|
|
1558
|
+
*/
|
|
1559
|
+
var fileeyenewfile3 = ((inputs = {}, options = {}) => {
|
|
1560
|
+
const locale = options.locale ?? getLocale();
|
|
1561
|
+
if (locale === "zh") return zh_fileeyenewfile3();
|
|
1562
|
+
if (locale === "id") return id_fileeyenewfile3();
|
|
1563
|
+
return en_fileeyenewfile3();
|
|
1564
|
+
});
|
|
1565
|
+
//#endregion
|
|
1538
1566
|
//#region src/lib/paraglide/messages/fileeyetogglelabel3.js
|
|
1539
1567
|
/** @typedef {import('../runtime.js').LocalizedString} LocalizedString */
|
|
1540
1568
|
/** @typedef {{}} Fileeyetogglelabel3Inputs */
|
|
@@ -6747,7 +6775,7 @@ function AppSidebar($$renderer, $$props) {
|
|
|
6747
6775
|
* page (OCI ownership split); the gutter just reports mousedown, and the
|
|
6748
6776
|
* single width clamp lives in sidebar-prefs (clampSidebarWidth).
|
|
6749
6777
|
*/
|
|
6750
|
-
let { profile = null, collapsed = false, width =
|
|
6778
|
+
let { profile = null, collapsed = false, width = 400, embedded = false, currentSessionId, paneledSessionIds = [], captureContainer = null, onToggleCollapse} = $$props;
|
|
6751
6779
|
let filter = loadSessionFilter(profile);
|
|
6752
6780
|
if (collapsed) {
|
|
6753
6781
|
$$renderer.push("<!--[0-->");
|
|
@@ -8092,7 +8120,10 @@ function PromptManagerSearch($$renderer, $$props) {
|
|
|
8092
8120
|
* (the host owns the 300ms debounce + refresh).
|
|
8093
8121
|
*/
|
|
8094
8122
|
let { value = "", oninput } = $$props;
|
|
8095
|
-
$$renderer.push(`<
|
|
8123
|
+
$$renderer.push(`<textarea data-svelte="PromptManagerSearch" class="mgr-search svelte-w3lpt8" rows="2"${attr("placeholder", t(searchprompts1))}>`);
|
|
8124
|
+
const $$body = escape_html(value);
|
|
8125
|
+
if ($$body) $$renderer.push(`${$$body}`);
|
|
8126
|
+
$$renderer.push(`</textarea>`);
|
|
8096
8127
|
bind_props($$props, { value });
|
|
8097
8128
|
});
|
|
8098
8129
|
}
|
|
@@ -8472,15 +8503,8 @@ function blockBounds(panels, idx, facts) {
|
|
|
8472
8503
|
let i = idx;
|
|
8473
8504
|
while (i > 0 && panels[i - 1].kind === "workspace-file") i--;
|
|
8474
8505
|
const head = panels[i - 1];
|
|
8475
|
-
|
|
8476
|
-
if (
|
|
8477
|
-
else if (head !== void 0 && head.kind === "workspace-explorer" && fileBelongsTo(at, head)) explorerIdx = i - 1;
|
|
8478
|
-
if (explorerIdx >= 0) {
|
|
8479
|
-
const explorer = panels[explorerIdx];
|
|
8480
|
-
const family = explorer.kind === "workspace-explorer" ? unitOf(panels, explorer.sessionId, facts) : null;
|
|
8481
|
-
if (family !== null && explorerIdx > family[0] && explorerIdx <= family[1]) return family;
|
|
8482
|
-
return explorerUnit(panels, explorerIdx);
|
|
8483
|
-
}
|
|
8506
|
+
if (at.kind === "workspace-explorer") return explorerUnit(panels, idx);
|
|
8507
|
+
if (head !== void 0 && head.kind === "workspace-explorer" && fileBelongsTo(at, head)) return explorerUnit(panels, i - 1);
|
|
8484
8508
|
return [idx, idx];
|
|
8485
8509
|
}
|
|
8486
8510
|
if (at.kind !== "injected-doc") return [idx, idx];
|
|
@@ -8532,29 +8556,10 @@ function unitOf(panels, sessionId, facts) {
|
|
|
8532
8556
|
end = i;
|
|
8533
8557
|
continue;
|
|
8534
8558
|
}
|
|
8535
|
-
if (p.kind === "workspace-explorer" && familySessions.has(p.sessionId)) {
|
|
8536
|
-
const wsUnit = explorerUnit(panels, i);
|
|
8537
|
-
end = wsUnit[1];
|
|
8538
|
-
i = wsUnit[1];
|
|
8539
|
-
continue;
|
|
8540
|
-
}
|
|
8541
8559
|
break;
|
|
8542
8560
|
}
|
|
8543
8561
|
return [start, end];
|
|
8544
8562
|
}
|
|
8545
|
-
/**
|
|
8546
|
-
* Insert index for AFTER-SOURCE placement (the fork child, 2026-09-01):
|
|
8547
|
-
* directly below the panel showing `sourceSessionId` — the source keeps
|
|
8548
|
-
* its slot, the newcomer takes the next one. The family clamp mirrors
|
|
8549
|
-
* the Focused Slot's, downward: the slot rides PAST the source's whole
|
|
8550
|
-
* family unit, so a fork never wedges between a spawner and its pinned
|
|
8551
|
-
* children (I2 — families stay contiguous). Null when the source holds
|
|
8552
|
-
* no panel; the caller falls back to its own default placement.
|
|
8553
|
-
*/
|
|
8554
|
-
function afterSourceSlot(panels, sourceSessionId, facts) {
|
|
8555
|
-
const unit = unitOf(panels, sourceSessionId, facts);
|
|
8556
|
-
return unit === null ? null : unit[1] + 1;
|
|
8557
|
-
}
|
|
8558
8563
|
//#endregion
|
|
8559
8564
|
//#region src/lib/services/conversation/injected-shelf.ts
|
|
8560
8565
|
/** The synthetic shelf name for the conversation's system prompt (ADR D7)
|
|
@@ -8792,7 +8797,7 @@ function panelHeaderLabel(panel) {
|
|
|
8792
8797
|
if (panel.kind === "prompt-manager") return MANAGER_ROW_TITLE;
|
|
8793
8798
|
if (panel.kind === "settings-editor") return SETTINGS_ROW_TITLE[panel.target];
|
|
8794
8799
|
if (panel.kind === "injected-doc") return injectedDocTitle(panel.displayPath);
|
|
8795
|
-
if (panel.kind === "workspace-explorer") return workspaceExplorerTitle(panel.root);
|
|
8800
|
+
if (panel.kind === "workspace-explorer") return panel.title ?? workspaceExplorerTitle(panel.root);
|
|
8796
8801
|
if (panel.kind === "workspace-file") return workspaceFileTitle(panel.path);
|
|
8797
8802
|
}
|
|
8798
8803
|
/** Open-panel session ids — floor membership for display facts AND the
|
|
@@ -8830,31 +8835,21 @@ function panelRowsFor(input) {
|
|
|
8830
8835
|
canMoveUp: index > 0,
|
|
8831
8836
|
canMoveDown: index < panels.length - 1
|
|
8832
8837
|
};
|
|
8833
|
-
if (p.kind === "workspace-explorer" || p.kind === "workspace-file") {
|
|
8834
|
-
|
|
8835
|
-
|
|
8836
|
-
|
|
8837
|
-
|
|
8838
|
-
|
|
8839
|
-
|
|
8840
|
-
|
|
8841
|
-
|
|
8842
|
-
|
|
8843
|
-
|
|
8844
|
-
|
|
8845
|
-
|
|
8846
|
-
|
|
8847
|
-
|
|
8848
|
-
runningDescendants: 0,
|
|
8849
|
-
kind: "panel",
|
|
8850
|
-
parentSessionId: parent,
|
|
8851
|
-
fork: false,
|
|
8852
|
-
wsChild: true,
|
|
8853
|
-
spawnerTitle: null,
|
|
8854
|
-
canMoveUp: false,
|
|
8855
|
-
canMoveDown: false
|
|
8856
|
-
};
|
|
8857
|
-
}
|
|
8838
|
+
if (p.kind === "workspace-explorer" || p.kind === "workspace-file") return {
|
|
8839
|
+
panel: p,
|
|
8840
|
+
title: p.kind === "workspace-file" ? workspaceFileTitle(p.path) : p.title ?? workspaceExplorerTitle(p.root),
|
|
8841
|
+
workspace: null,
|
|
8842
|
+
dead: false,
|
|
8843
|
+
running: false,
|
|
8844
|
+
depth: 0,
|
|
8845
|
+
runningDescendants: 0,
|
|
8846
|
+
kind: "panel",
|
|
8847
|
+
parentSessionId: null,
|
|
8848
|
+
fork: false,
|
|
8849
|
+
spawnerTitle: null,
|
|
8850
|
+
canMoveUp: movePanelLineage(panels, p.id, "up", moveFacts) !== null,
|
|
8851
|
+
canMoveDown: movePanelLineage(panels, p.id, "down", moveFacts) !== null
|
|
8852
|
+
};
|
|
8858
8853
|
if (p.kind === "injected-doc") return {
|
|
8859
8854
|
panel: p,
|
|
8860
8855
|
title: injectedDocTitle(p.displayPath),
|
|
@@ -9029,33 +9024,14 @@ function parseCommand(text) {
|
|
|
9029
9024
|
}
|
|
9030
9025
|
case "/promptmanager":
|
|
9031
9026
|
case "/dsisettings":
|
|
9032
|
-
case "/dshsettings":
|
|
9033
|
-
|
|
9034
|
-
|
|
9035
|
-
|
|
9036
|
-
|
|
9037
|
-
|
|
9038
|
-
|
|
9039
|
-
|
|
9040
|
-
addPanel: true
|
|
9041
|
-
};
|
|
9042
|
-
case "/loadinjected": {
|
|
9043
|
-
if (args === "" || args === "?") return {
|
|
9044
|
-
type: "loadinjected",
|
|
9045
|
-
args
|
|
9046
|
-
};
|
|
9047
|
-
const m = /^(\S+)(?:\s+(--add))?$/.exec(args);
|
|
9048
|
-
if (m === null || m[1].toLowerCase() === "--add") return {
|
|
9049
|
-
type: "loadinjected",
|
|
9050
|
-
args
|
|
9051
|
-
};
|
|
9052
|
-
return {
|
|
9053
|
-
type: "loadinjected",
|
|
9054
|
-
args: "",
|
|
9055
|
-
filename: m[1],
|
|
9056
|
-
...m[2] !== void 0 ? { addPanel: true } : {}
|
|
9057
|
-
};
|
|
9058
|
-
}
|
|
9027
|
+
case "/dshsettings": return {
|
|
9028
|
+
type: token.slice(1),
|
|
9029
|
+
args
|
|
9030
|
+
};
|
|
9031
|
+
case "/loadinjected": return {
|
|
9032
|
+
type: "loadinjected",
|
|
9033
|
+
args
|
|
9034
|
+
};
|
|
9059
9035
|
default: return null;
|
|
9060
9036
|
}
|
|
9061
9037
|
}
|
|
@@ -9098,6 +9074,7 @@ function commandHelpTopic(text) {
|
|
|
9098
9074
|
if (trimmed.startsWith("@")) return /^@\S+\s+\?$/.test(trimmed) ? "mention" : null;
|
|
9099
9075
|
const command = parseCommand(trimmed);
|
|
9100
9076
|
if (command === null || command.type === "mention") return null;
|
|
9077
|
+
if (command.type === "loadinjected") return null;
|
|
9101
9078
|
return command.args === "?" ? command.type : null;
|
|
9102
9079
|
}
|
|
9103
9080
|
/** The help card copy, per topic. Preset names mirror the shipped
|
|
@@ -9165,66 +9142,30 @@ var COMMAND_HELP = {
|
|
|
9165
9142
|
]
|
|
9166
9143
|
},
|
|
9167
9144
|
promptmanager: {
|
|
9168
|
-
usage: "/promptmanager
|
|
9169
|
-
summary: "
|
|
9170
|
-
params: [
|
|
9171
|
-
name: "--add",
|
|
9172
|
-
description: "Open the manager in a NEW panel placed to the RIGHT of the current panel and SELECT it (the documented divergence from /new --add: the fresh manager is the thing to read, so it takes the caret)."
|
|
9173
|
-
}],
|
|
9145
|
+
usage: "/promptmanager",
|
|
9146
|
+
summary: "Aims the prompts manager panel: if one is already open it takes the focus; otherwise it opens in a NEW panel to the right of this conversation — and takes the focus. Nothing you have open is ever replaced.",
|
|
9147
|
+
params: [],
|
|
9174
9148
|
examples: [{
|
|
9175
9149
|
line: "/promptmanager",
|
|
9176
|
-
description: "The prompts manager
|
|
9177
|
-
}, {
|
|
9178
|
-
line: "/promptmanager --add",
|
|
9179
|
-
description: "The prompts manager opens in a panel to the right — and is focused."
|
|
9150
|
+
description: "The prompts manager panel comes forward — opened beside this conversation if it was closed."
|
|
9180
9151
|
}]
|
|
9181
9152
|
},
|
|
9182
9153
|
dsisettings: {
|
|
9183
|
-
usage: "/dsisettings
|
|
9184
|
-
summary: "
|
|
9185
|
-
params: [
|
|
9186
|
-
name: "--add",
|
|
9187
|
-
description: "Open the editor in a NEW panel placed to the RIGHT of the current panel and SELECT it (the same divergence as /promptmanager --add: the fresh editor is the thing to read)."
|
|
9188
|
-
}],
|
|
9154
|
+
usage: "/dsisettings",
|
|
9155
|
+
summary: "Aims the DSI settings home explorer (~/.dsi, titled “DSI - Settings”): the open explorer takes the focus; otherwise a NEW explorer opens to the right of this conversation, selected. settings.yaml opens as a tab and stays editable; saves are YAML-checked on read.",
|
|
9156
|
+
params: [],
|
|
9189
9157
|
examples: [{
|
|
9190
9158
|
line: "/dsisettings",
|
|
9191
|
-
description: "The DSI settings
|
|
9192
|
-
}, {
|
|
9193
|
-
line: "/dsisettings --add",
|
|
9194
|
-
description: "The DSI settings editor opens in a panel to the right — and is focused."
|
|
9159
|
+
description: "The DSI settings explorer comes forward — opened beside this conversation if it was closed."
|
|
9195
9160
|
}]
|
|
9196
9161
|
},
|
|
9197
9162
|
dshsettings: {
|
|
9198
|
-
usage: "/dshsettings
|
|
9199
|
-
summary: "
|
|
9200
|
-
params: [
|
|
9201
|
-
name: "--add",
|
|
9202
|
-
description: "Open the editor in a NEW panel placed to the RIGHT of the current panel and SELECT it (the same divergence as /promptmanager --add)."
|
|
9203
|
-
}],
|
|
9163
|
+
usage: "/dshsettings",
|
|
9164
|
+
summary: "Aims the harness settings home explorer (~/.dsh, titled “DSH - Settings”): the open explorer takes the focus; otherwise a NEW explorer opens to the right of this conversation, selected. settings.yaml opens as a tab and stays editable; the running harness picks edits up through its own file watcher.",
|
|
9165
|
+
params: [],
|
|
9204
9166
|
examples: [{
|
|
9205
9167
|
line: "/dshsettings",
|
|
9206
|
-
description: "The DSH settings
|
|
9207
|
-
}, {
|
|
9208
|
-
line: "/dshsettings --add",
|
|
9209
|
-
description: "The DSH settings editor opens in a panel to the right — and is focused."
|
|
9210
|
-
}]
|
|
9211
|
-
},
|
|
9212
|
-
loadinjected: {
|
|
9213
|
-
usage: "/loadinjected <filename.md> [--add]",
|
|
9214
|
-
summary: "Re-opens a document this conversation already received — the system prompt or an injected instructions file — as a READ-ONLY panel showing what the model actually saw (the logged payload, never the live file). Default: it replaces this panel. With --add: it opens in a NEW panel BELOW this conversation — the document belongs to it — and takes the focus.",
|
|
9215
|
-
params: [{
|
|
9216
|
-
name: "<filename.md>",
|
|
9217
|
-
description: "Which document to open — a shelf name like AGENTS.md or system-prompt.md. An exact name matches first; a bare basename works when it is unambiguous."
|
|
9218
|
-
}, {
|
|
9219
|
-
name: "--add",
|
|
9220
|
-
description: "Open the document in a NEW panel placed BELOW this conversation’s panel and SELECT it (a document child of this conversation — maroon in the sidebar)."
|
|
9221
|
-
}],
|
|
9222
|
-
examples: [{
|
|
9223
|
-
line: "/loadinjected AGENTS.md",
|
|
9224
|
-
description: "Re-open the injected AGENTS.md in place of this panel."
|
|
9225
|
-
}, {
|
|
9226
|
-
line: "/loadinjected AGENTS.md --add",
|
|
9227
|
-
description: "Re-open AGENTS.md in a panel below this conversation — and focus it."
|
|
9168
|
+
description: "The DSH settings explorer comes forward — opened beside this conversation if it was closed."
|
|
9228
9169
|
}]
|
|
9229
9170
|
},
|
|
9230
9171
|
permission: {
|
|
@@ -9299,12 +9240,6 @@ var MENU_GESTURES = [
|
|
|
9299
9240
|
seed: "/dshsettings ",
|
|
9300
9241
|
description: COMMAND_HELP.dshsettings.summary
|
|
9301
9242
|
},
|
|
9302
|
-
{
|
|
9303
|
-
name: "loadinjected",
|
|
9304
|
-
display: "/loadinjected",
|
|
9305
|
-
seed: "/loadinjected ",
|
|
9306
|
-
description: COMMAND_HELP.loadinjected.summary
|
|
9307
|
-
},
|
|
9308
9243
|
{
|
|
9309
9244
|
name: "@mention",
|
|
9310
9245
|
display: "@mention",
|
|
@@ -14493,8 +14428,8 @@ async function executeCommand(command, ctx, onNote) {
|
|
|
14493
14428
|
if (command.type === "permission") return runPermissionLine(`/permission${command.args === "" ? "" : " " + command.args}`, ctx, onNote);
|
|
14494
14429
|
if (command.type === "workspace") return runWorkspaceLine(command.wsPath, command.wsName, ctx, onNote);
|
|
14495
14430
|
if (command.type === "mention") return runMention(command.sessionId ?? "", command.args, command.a2aId, ctx, onNote);
|
|
14496
|
-
if (command.type === "promptmanager") return runPromptManager(command.args,
|
|
14497
|
-
if (command.type === "dsisettings" || command.type === "dshsettings") return runSettingsEditor(command.type === "dsisettings" ? "dsi" : "dsh", "/" + command.type, command.args,
|
|
14431
|
+
if (command.type === "promptmanager") return runPromptManager(command.args, ctx, onNote);
|
|
14432
|
+
if (command.type === "dsisettings" || command.type === "dshsettings") return runSettingsEditor(command.type === "dsisettings" ? "dsi" : "dsh", "/" + command.type, command.args, ctx, onNote);
|
|
14498
14433
|
if (command.type === "loadinjected") return runLoadInjected(command.filename, command.addPanel === true, ctx, onNote);
|
|
14499
14434
|
if (command.args !== "") {
|
|
14500
14435
|
const usage = "usage: /new [@agent] [workspace] [--add]";
|
|
@@ -14609,19 +14544,16 @@ async function executeCommand(command, ctx, onNote) {
|
|
|
14609
14544
|
}
|
|
14610
14545
|
}
|
|
14611
14546
|
/**
|
|
14612
|
-
* /promptmanager (2026-09-
|
|
14613
|
-
* prompts manager
|
|
14614
|
-
*
|
|
14615
|
-
*
|
|
14616
|
-
*
|
|
14617
|
-
*
|
|
14618
|
-
* keepSelection, the newcomer takes the focus — it is the
|
|
14619
|
-
* thing the operator is about to read)
|
|
14620
|
-
* No wire call — the manager content talks to /api/prompts itself.
|
|
14547
|
+
* /promptmanager (re-pointed 2026-09-17, ADR The Focus Command D1/D2): AIM
|
|
14548
|
+
* the prompts manager panel from the composer — the floor's add path
|
|
14549
|
+
* FOCUSES the already-open manager (one live manager, D3) or opens a NEW
|
|
14550
|
+
* one right of this session's panel, selected. The bare successor-swap and
|
|
14551
|
+
* the --add flag are retired; the floor never replaces a panel for this
|
|
14552
|
+
* command. No wire call — the manager content talks to /api/prompts itself.
|
|
14621
14553
|
*/
|
|
14622
|
-
async function runPromptManager(args,
|
|
14554
|
+
async function runPromptManager(args, ctx, onNote) {
|
|
14623
14555
|
if (args !== "") {
|
|
14624
|
-
const usage = "usage: /promptmanager
|
|
14556
|
+
const usage = "usage: /promptmanager";
|
|
14625
14557
|
onNote?.(false, usage);
|
|
14626
14558
|
return {
|
|
14627
14559
|
ok: false,
|
|
@@ -14636,20 +14568,9 @@ async function runPromptManager(args, addPanel, ctx, onNote) {
|
|
|
14636
14568
|
note
|
|
14637
14569
|
};
|
|
14638
14570
|
}
|
|
14639
|
-
if (
|
|
14640
|
-
|
|
14641
|
-
|
|
14642
|
-
})) {
|
|
14643
|
-
const note = "/promptmanager: the floor is not mounted";
|
|
14644
|
-
onNote?.(false, note);
|
|
14645
|
-
return {
|
|
14646
|
-
ok: false,
|
|
14647
|
-
note
|
|
14648
|
-
};
|
|
14649
|
-
}
|
|
14650
|
-
return { ok: true };
|
|
14651
|
-
}
|
|
14652
|
-
if (!replacePanelFromRegistry(ctx.panelId)) {
|
|
14571
|
+
if (!addPanelFromSidebar({
|
|
14572
|
+
afterSessionId: ctx.sessionId
|
|
14573
|
+
})) {
|
|
14653
14574
|
const note = "/promptmanager: the floor is not mounted";
|
|
14654
14575
|
onNote?.(false, note);
|
|
14655
14576
|
return {
|
|
@@ -14660,16 +14581,18 @@ async function runPromptManager(args, addPanel, ctx, onNote) {
|
|
|
14660
14581
|
return { ok: true };
|
|
14661
14582
|
}
|
|
14662
14583
|
/**
|
|
14663
|
-
* /dsisettings and /dshsettings (
|
|
14664
|
-
*
|
|
14665
|
-
*
|
|
14666
|
-
*
|
|
14667
|
-
*
|
|
14668
|
-
*
|
|
14584
|
+
* /dsisettings and /dshsettings (re-pointed by The Settings Tree ADR,
|
|
14585
|
+
* 2026-09-18, D2; aimed 2026-09-17, The Focus Command ADR D1): open a
|
|
14586
|
+
* SESSION-LESS workspace-explorer over the settings HOME folder (~/.dsi |
|
|
14587
|
+
* ~/.dsh), titled — one runner for both commands; the command name carries
|
|
14588
|
+
* the home. The floor's add path dedupes by root, so a repeat FOCUSES the
|
|
14589
|
+
* open home panel; the successor-swap and the --add flag are retired. No
|
|
14590
|
+
* wire call — the explorer content talks to the DSI-local
|
|
14591
|
+
* /api/settings-home routes itself.
|
|
14669
14592
|
*/
|
|
14670
|
-
async function runSettingsEditor(
|
|
14593
|
+
async function runSettingsEditor(home, commandName, args, ctx, onNote) {
|
|
14671
14594
|
if (args !== "") {
|
|
14672
|
-
const usage = "usage: " + commandName
|
|
14595
|
+
const usage = "usage: " + commandName;
|
|
14673
14596
|
onNote?.(false, usage);
|
|
14674
14597
|
return {
|
|
14675
14598
|
ok: false,
|
|
@@ -14684,20 +14607,9 @@ async function runSettingsEditor(target, commandName, args, addPanel, ctx, onNot
|
|
|
14684
14607
|
note
|
|
14685
14608
|
};
|
|
14686
14609
|
}
|
|
14687
|
-
if (
|
|
14688
|
-
|
|
14689
|
-
|
|
14690
|
-
})) {
|
|
14691
|
-
const note = commandName + ": the floor is not mounted";
|
|
14692
|
-
onNote?.(false, note);
|
|
14693
|
-
return {
|
|
14694
|
-
ok: false,
|
|
14695
|
-
note
|
|
14696
|
-
};
|
|
14697
|
-
}
|
|
14698
|
-
return { ok: true };
|
|
14699
|
-
}
|
|
14700
|
-
if (!replacePanelFromRegistry(ctx.panelId)) {
|
|
14610
|
+
if (!addPanelFromSidebar({
|
|
14611
|
+
afterSessionId: ctx.sessionId
|
|
14612
|
+
})) {
|
|
14701
14613
|
const note = commandName + ": the floor is not mounted";
|
|
14702
14614
|
onNote?.(false, note);
|
|
14703
14615
|
return {
|
|
@@ -14708,25 +14620,28 @@ async function runSettingsEditor(target, commandName, args, addPanel, ctx, onNot
|
|
|
14708
14620
|
return { ok: true };
|
|
14709
14621
|
}
|
|
14710
14622
|
/**
|
|
14711
|
-
* /loadinjected
|
|
14712
|
-
* D2
|
|
14713
|
-
*
|
|
14714
|
-
*
|
|
14715
|
-
*
|
|
14716
|
-
*
|
|
14717
|
-
*
|
|
14718
|
-
*
|
|
14719
|
-
*
|
|
14720
|
-
*
|
|
14623
|
+
* /loadinjected — INTERNAL command (2026-09-17, The Retired Typed Command
|
|
14624
|
+
* ADR D1/D2; ex-/loadinjected <filename.md> [--add], The Loadinjected ADR
|
|
14625
|
+
* D2-D6): the shelf button composes it via the parser's
|
|
14626
|
+
* loadinjectedCommand() constructor — the typed surface is retired.
|
|
14627
|
+
* filename present (the constructor's shape) → resolve as the
|
|
14628
|
+
* Loadinjected ADR built it: member resolution rides the injected-shelf
|
|
14629
|
+
* selector over ctx.entries — exact displayPath first, then a unique
|
|
14630
|
+
* basename; the executor never re-implements it (D4). --add → a NEW
|
|
14631
|
+
* panel BELOW this conversation's panel, selected (D3); bare → replaces
|
|
14632
|
+
* the panel it ran in (D4). Dedupe→focus is the FLOOR handler's D5
|
|
14633
|
+
* policy — the executor never pre-checks it (D6: one write path).
|
|
14634
|
+
* filename absent (every TYPED shape) → the D2 retirement note pointing
|
|
14635
|
+
* at the InjectedShelfButton — honest, never a silent unknown-command.
|
|
14721
14636
|
* No wire call — the payload is the record the panel reads at mount.
|
|
14722
14637
|
*/
|
|
14723
14638
|
async function runLoadInjected(filename, addPanel, ctx, onNote) {
|
|
14724
14639
|
if (filename === void 0) {
|
|
14725
|
-
const
|
|
14726
|
-
onNote?.(false,
|
|
14640
|
+
const note = "/loadinjected retired — open injected documents with the Injected button on the conversation anchor";
|
|
14641
|
+
onNote?.(false, note);
|
|
14727
14642
|
return {
|
|
14728
14643
|
ok: false,
|
|
14729
|
-
note
|
|
14644
|
+
note
|
|
14730
14645
|
};
|
|
14731
14646
|
}
|
|
14732
14647
|
if (ctx.panelId == null) {
|
|
@@ -15503,23 +15418,42 @@ function deriveSessionStats(entries) {
|
|
|
15503
15418
|
* no module state. Imports only the parser primitives; the compiler is
|
|
15504
15419
|
* table-testable precisely because its whole surface is this function.
|
|
15505
15420
|
*/
|
|
15506
|
-
/** Is this trimmed line an instruction? (parseCommand-known or `?`.)
|
|
15507
|
-
|
|
15508
|
-
|
|
15421
|
+
/** Is this trimmed line an instruction? (parseCommand-known or `?`.)
|
|
15422
|
+
* Under `slash` (the typed-run flag, ADR The Typed Run D2) a leading-`/`
|
|
15423
|
+
* line is ALWAYS a boundary — even when parseCommand returns null — so
|
|
15424
|
+
* one unknown `/token` line feeds as its own one-line send. */
|
|
15425
|
+
function isInstruction(line, slash = false) {
|
|
15426
|
+
return parseCommand(line) !== null || line.startsWith("?") || slash && line.startsWith("/");
|
|
15509
15427
|
}
|
|
15510
15428
|
/** Close the mention's message at the first blank line, the next
|
|
15511
15429
|
* instruction line, or the end of the row — whichever comes first. */
|
|
15512
|
-
function messageEndsAt(lines, from) {
|
|
15430
|
+
function messageEndsAt(lines, from, slash = false) {
|
|
15513
15431
|
let j = from;
|
|
15514
|
-
while (j < lines.length && lines[j] !== "" && !isInstruction(lines[j])) j += 1;
|
|
15432
|
+
while (j < lines.length && lines[j] !== "" && !isInstruction(lines[j], slash)) j += 1;
|
|
15515
15433
|
return j;
|
|
15516
15434
|
}
|
|
15517
15435
|
/**
|
|
15436
|
+
* Is this draft a TYPED RUN? (ADR The Typed Run 2026-09-16, D1.) Pure:
|
|
15437
|
+
* true only when EVERY non-blank line is directive — starts with `/`
|
|
15438
|
+
* (command-or-skill attempt), `@` (mention), or `?` (shelf lookup) —
|
|
15439
|
+
* and there are at least TWO non-blank lines. Prose, mixed prose+slash
|
|
15440
|
+
* drafts, and every single-line draft fail and take today's whole-draft
|
|
15441
|
+
* path unchanged. Blank lines never count and never break the match;
|
|
15442
|
+
* per-line trim (same as the compiler) absorbs CRLF. No I/O, no
|
|
15443
|
+
* reactivity — table-testable like compileRow.
|
|
15444
|
+
*/
|
|
15445
|
+
function isTypedRun(text) {
|
|
15446
|
+
const directives = text.split("\n").map((l) => l.trim()).filter((l) => l !== "");
|
|
15447
|
+
if (directives.length < 2) return false;
|
|
15448
|
+
return directives.every((l) => l.startsWith("/") || l.startsWith("@") || l.startsWith("?"));
|
|
15449
|
+
}
|
|
15450
|
+
/**
|
|
15518
15451
|
* Compile a saved row's text into sections. Pure: the same text always
|
|
15519
15452
|
* yields the same records; blank-only input yields an empty list (the
|
|
15520
15453
|
* runner refuses an empty compile at start — no fetch fires, Wave 2).
|
|
15521
15454
|
*/
|
|
15522
|
-
function compileRow(text) {
|
|
15455
|
+
function compileRow(text, opts = {}) {
|
|
15456
|
+
const slash = opts.slashBoundaries === true;
|
|
15523
15457
|
const lines = text.split("\n").map((l) => l.trim());
|
|
15524
15458
|
const sections = [];
|
|
15525
15459
|
let i = 0;
|
|
@@ -15532,7 +15466,7 @@ function compileRow(text) {
|
|
|
15532
15466
|
const command = parseCommand(line);
|
|
15533
15467
|
if (command !== null) {
|
|
15534
15468
|
if (command.type === "mention") {
|
|
15535
|
-
const end = messageEndsAt(lines, i + 1);
|
|
15469
|
+
const end = messageEndsAt(lines, i + 1, slash);
|
|
15536
15470
|
const tail = lines.slice(i + 1, end);
|
|
15537
15471
|
const messageLines = command.args === "" ? tail : [command.args, ...tail];
|
|
15538
15472
|
sections.push({
|
|
@@ -15565,8 +15499,18 @@ function compileRow(text) {
|
|
|
15565
15499
|
i += 1;
|
|
15566
15500
|
continue;
|
|
15567
15501
|
}
|
|
15502
|
+
if (slash && line.startsWith("/")) {
|
|
15503
|
+
sections.push({
|
|
15504
|
+
kind: "send-block",
|
|
15505
|
+
display: line,
|
|
15506
|
+
sendText: line,
|
|
15507
|
+
lineCount: 1
|
|
15508
|
+
});
|
|
15509
|
+
i += 1;
|
|
15510
|
+
continue;
|
|
15511
|
+
}
|
|
15568
15512
|
let end = i + 1;
|
|
15569
|
-
while (end < lines.length && !isInstruction(lines[end])) end += 1;
|
|
15513
|
+
while (end < lines.length && !isInstruction(lines[end], slash)) end += 1;
|
|
15570
15514
|
const block = lines.slice(i, end);
|
|
15571
15515
|
while (block.length > 0 && block[0] === "") block.shift();
|
|
15572
15516
|
while (block.length > 0 && block[block.length - 1] === "") block.pop();
|
|
@@ -15648,7 +15592,7 @@ function start(row, ctx, opts = {}) {
|
|
|
15648
15592
|
...state,
|
|
15649
15593
|
note: "a macro is already running — abort it first"
|
|
15650
15594
|
};
|
|
15651
|
-
const sections = compileRow(row.text);
|
|
15595
|
+
const sections = compileRow(row.text, row.id === -1 ? { slashBoundaries: true } : {});
|
|
15652
15596
|
if (sections.length === 0) return {
|
|
15653
15597
|
...idleState(),
|
|
15654
15598
|
phase: "failed",
|
|
@@ -16209,6 +16153,13 @@ function ConversationPanel($$renderer, $$props) {
|
|
|
16209
16153
|
* sends flow through sendPrompt so the /use record guard lives in ONE
|
|
16210
16154
|
* place (Suggest Strip ADR D5 contract, byte-identical). */
|
|
16211
16155
|
async function onsubmit(text, images) {
|
|
16156
|
+
if (isTypedRun(text)) {
|
|
16157
|
+
startMacro({
|
|
16158
|
+
text,
|
|
16159
|
+
id: -1
|
|
16160
|
+
}, false);
|
|
16161
|
+
return true;
|
|
16162
|
+
}
|
|
16212
16163
|
const command = parseCommand(text);
|
|
16213
16164
|
if (command !== null) {
|
|
16214
16165
|
let bannered = false;
|
|
@@ -16779,13 +16730,8 @@ function WorkspaceExplorerButtons($$renderer, $$props) {
|
|
|
16779
16730
|
function WorkspaceExplorerToolbar($$renderer, $$props) {
|
|
16780
16731
|
$$renderer.component(($$renderer) => {
|
|
16781
16732
|
let columnEl = null;
|
|
16782
|
-
let {
|
|
16783
|
-
$$renderer.push(`<div data-svelte="WorkspaceExplorerToolbar" class="explorer-toolbar svelte-b18z79" data-testid="explorer-toolbar"
|
|
16784
|
-
if (showTabs) {
|
|
16785
|
-
$$renderer.push("<!--[0-->");
|
|
16786
|
-
$$renderer.push(`<div class="tabs svelte-b18z79" role="tablist" data-testid="explorer-tabs"><button role="tab"${attr_class("tab svelte-b18z79", void 0, { "active": activeTab === "explorer" })}${attr("aria-selected", activeTab === "explorer")} data-testid="git-tab-explorer">${escape_html(t(giteyetabexplorer3))}</button> <button role="tab"${attr_class("tab svelte-b18z79", void 0, { "active": activeTab === "changes" })}${attr("aria-selected", activeTab === "changes")} data-testid="git-tab-changes">${escape_html(t(giteyetabchanges3))}</button></div>`);
|
|
16787
|
-
} else $$renderer.push("<!--[-1-->");
|
|
16788
|
-
$$renderer.push(`<!--]--> `);
|
|
16733
|
+
let { activeTab = "explorer"} = $$props;
|
|
16734
|
+
$$renderer.push(`<div data-svelte="WorkspaceExplorerToolbar" class="explorer-toolbar svelte-b18z79" data-testid="explorer-toolbar"><div class="tabs svelte-b18z79" role="tablist" data-testid="explorer-tabs"><button role="tab"${attr_class("tab svelte-b18z79", void 0, { "active": activeTab === "explorer" })}${attr("aria-selected", activeTab === "explorer")} data-testid="git-tab-explorer">${escape_html(t(giteyetabexplorer3))}</button> <button role="tab"${attr_class("tab svelte-b18z79", void 0, { "active": activeTab === "changes" })}${attr("aria-selected", activeTab === "changes")} data-testid="git-tab-changes">${escape_html(t(giteyetabchanges3))}</button></div> `);
|
|
16789
16735
|
WorkspaceExplorerButtons($$renderer, {
|
|
16790
16736
|
container: columnEl});
|
|
16791
16737
|
$$renderer.push(`<!----></div>`);
|
|
@@ -16827,8 +16773,15 @@ var workspacePanelCopy = {
|
|
|
16827
16773
|
save: "Save",
|
|
16828
16774
|
/** Save button label while the delegated turn is unanswered. */
|
|
16829
16775
|
saving: "Saving…",
|
|
16776
|
+
/** Failure line when the save turn is refused. */
|
|
16777
|
+
saveFailed: "Save failed",
|
|
16830
16778
|
/** Post-receipt note — the receipt is acceptance, not proof of bytes. */
|
|
16831
|
-
stale: "Saved — refresh to confirm the written file"
|
|
16779
|
+
stale: "Saved — refresh to confirm the written file",
|
|
16780
|
+
/** Failure line when the file read refuses. */
|
|
16781
|
+
loadFailed: "Could not read this file",
|
|
16782
|
+
/** Suffix when the fetched page stops before the file's end. */
|
|
16783
|
+
truncated: " — first page only"
|
|
16784
|
+
},
|
|
16832
16785
|
common: {
|
|
16833
16786
|
/** Canvas-copy button tooltip — captures the whole panel column. */
|
|
16834
16787
|
copyColumn: "Copy panel column as image (Shift+Click to save)"
|
|
@@ -17477,82 +17430,44 @@ function WorkspaceExplorerChanges($$renderer, $$props) {
|
|
|
17477
17430
|
});
|
|
17478
17431
|
}
|
|
17479
17432
|
//#endregion
|
|
17480
|
-
//#region src/lib/components/panels/
|
|
17481
|
-
function
|
|
17433
|
+
//#region src/lib/components/panels/WorkspaceExplorer.svelte
|
|
17434
|
+
function WorkspaceExplorer($$renderer, $$props) {
|
|
17482
17435
|
$$renderer.component(($$renderer) => {
|
|
17483
|
-
|
|
17484
|
-
|
|
17485
|
-
|
|
17486
|
-
|
|
17487
|
-
|
|
17488
|
-
|
|
17489
|
-
|
|
17490
|
-
*
|
|
17491
|
-
|
|
17492
|
-
|
|
17493
|
-
|
|
17494
|
-
|
|
17495
|
-
|
|
17496
|
-
for (const [name, flag] of Object.entries(rootMap.repos)) if (flag) out.push(name);
|
|
17497
|
-
return out;
|
|
17498
|
-
});
|
|
17499
|
-
const showTabs = derived(() => changesRepos().length > 0);
|
|
17500
|
-
/** Root-relative paths reported changed by git-status — the Explorer
|
|
17501
|
-
* tree tints these file rows red, the same contract as the Changes rows. */
|
|
17502
|
-
const changedPaths = derived(() => {
|
|
17503
|
-
const out = /* @__PURE__ */ new Set();
|
|
17504
|
-
for (const [repoRel, st] of Object.entries(changesStatuses)) {
|
|
17505
|
-
if (st.kind !== "ready") continue;
|
|
17506
|
-
for (const f of st.files) out.add(repoRel === "" ? f.path : repoRel + "/" + f.path);
|
|
17507
|
-
}
|
|
17508
|
-
return out;
|
|
17509
|
-
});
|
|
17510
|
-
/** Every ancestor directory of a changed path — a parent of a changed
|
|
17511
|
-
* file is highlighted exactly like a repo row (bold + #FF4500). */
|
|
17512
|
-
const changedDirs = derived(() => {
|
|
17513
|
-
const out = /* @__PURE__ */ new Set();
|
|
17514
|
-
for (const p of changedPaths()) {
|
|
17515
|
-
const parts = p.split("/");
|
|
17516
|
-
parts.pop();
|
|
17517
|
-
let cur = "";
|
|
17518
|
-
for (const part of parts) {
|
|
17519
|
-
cur = cur === "" ? part : cur + "/" + part;
|
|
17520
|
-
out.add(cur);
|
|
17521
|
-
}
|
|
17522
|
-
}
|
|
17523
|
-
return out;
|
|
17524
|
-
});
|
|
17525
|
-
let pulseSource = null;
|
|
17526
|
-
function closePulse() {
|
|
17527
|
-
pulseSource?.close();
|
|
17528
|
-
pulseSource = null;
|
|
17529
|
-
}
|
|
17530
|
-
onDestroy(closePulse);
|
|
17531
|
-
$$renderer.push(`<div data-svelte="WorkspaceExplorerPanel" class="explorer svelte-v4uero" data-testid="workspace-explorer">`);
|
|
17436
|
+
/**
|
|
17437
|
+
* WorkspaceExplorer — the explorer/changes tab strip + scroll body
|
|
17438
|
+
* (extracted 2026-09-13 from WorkspaceExplorerPanel's markup, same
|
|
17439
|
+
* extraction series as Tree and Changes). Presentation only: every
|
|
17440
|
+
* value arrives as a prop, every intent leaves as a callback — the
|
|
17441
|
+
* panel keeps all state, fetches, and persistence.
|
|
17442
|
+
*
|
|
17443
|
+
* Layout contract: .explorer is the toolbar's absolute ANCHOR and must
|
|
17444
|
+
* never scroll itself; the scroll lives on .tree-scroll so the toolbar
|
|
17445
|
+
* stays pinned (the toolbar-scrolls-away bug).
|
|
17446
|
+
*/
|
|
17447
|
+
let { root, activeTab, levels, expanded, repoMaps, changedPaths, changedDirs, changesRepos, changesStatuses, collapsedRepos} = $$props;
|
|
17448
|
+
$$renderer.push(`<div data-svelte="WorkspaceExplorer" class="explorer svelte-1l3v1je">`);
|
|
17532
17449
|
WorkspaceExplorerToolbar($$renderer, {
|
|
17533
|
-
|
|
17534
|
-
showTabs: showTabs(),
|
|
17535
|
-
activeTab: activeTab()});
|
|
17450
|
+
activeTab});
|
|
17536
17451
|
$$renderer.push(`<!----> `);
|
|
17537
|
-
if (activeTab
|
|
17452
|
+
if (activeTab === "changes") {
|
|
17538
17453
|
$$renderer.push("<!--[0-->");
|
|
17539
|
-
$$renderer.push(`<div class="changes svelte-
|
|
17454
|
+
$$renderer.push(`<div class="changes svelte-1l3v1je" data-testid="git-changes"><div class="tree-scroll svelte-1l3v1je">`);
|
|
17540
17455
|
WorkspaceExplorerChanges($$renderer, {
|
|
17541
17456
|
root,
|
|
17542
|
-
changesRepos
|
|
17457
|
+
changesRepos,
|
|
17543
17458
|
changesStatuses,
|
|
17544
17459
|
collapsedRepos: collapsedRepos ?? []});
|
|
17545
17460
|
$$renderer.push(`<!----></div></div>`);
|
|
17546
17461
|
} else {
|
|
17547
17462
|
$$renderer.push("<!--[-1-->");
|
|
17548
|
-
$$renderer.push(`<div class="tree-scroll svelte-
|
|
17463
|
+
$$renderer.push(`<div class="tree-scroll svelte-1l3v1je">`);
|
|
17549
17464
|
WorkspaceExplorerTree($$renderer, {
|
|
17550
17465
|
root,
|
|
17551
17466
|
levels,
|
|
17552
17467
|
expanded,
|
|
17553
17468
|
repoMaps,
|
|
17554
|
-
changedPaths
|
|
17555
|
-
changedDirs
|
|
17469
|
+
changedPaths,
|
|
17470
|
+
changedDirs});
|
|
17556
17471
|
$$renderer.push(`<!----></div>`);
|
|
17557
17472
|
}
|
|
17558
17473
|
$$renderer.push(`<!--]--></div>`);
|
|
@@ -17563,16 +17478,16 @@ function WorkspaceExplorerPanel($$renderer, $$props) {
|
|
|
17563
17478
|
function WorkspaceFileToolbar($$renderer, $$props) {
|
|
17564
17479
|
$$renderer.component(($$renderer) => {
|
|
17565
17480
|
let columnEl = null;
|
|
17566
|
-
let { dirty, saveState = "idle", stale = false, staleNote = "", hasTabs = false, tab = "preview", view = "edit", showToggle = false, diffDisabled = false, readonly = false, onviewchange, onsave } = $$props;
|
|
17567
|
-
$$renderer.push(`<div data-svelte="WorkspaceFileToolbar" class="file-toolbar svelte-cqlxfy"
|
|
17568
|
-
if (
|
|
17481
|
+
let { dirty, saveState = "idle", stale = false, staleNote = "", hasTabs = false, tab = "preview", view = "edit", showToggle = false, diffDisabled = false, readonly = false, onviewchange, onsave, path } = $$props;
|
|
17482
|
+
$$renderer.push(`<div data-svelte="WorkspaceFileToolbar" class="file-toolbar svelte-cqlxfy"><span class="path svelte-cqlxfy"${attr("title", path)}>${escape_html(path)}</span> `);
|
|
17483
|
+
if (showToggle) {
|
|
17569
17484
|
$$renderer.push("<!--[0-->");
|
|
17570
|
-
$$renderer.push(`<
|
|
17485
|
+
$$renderer.push(`<div class="seg-group svelte-cqlxfy" role="group"${attr("aria-label", t(fileeyetogglelabel3))} data-testid="file-view-toggle"><button type="button"${attr_class("seg left svelte-cqlxfy", void 0, { "on": view === "edit" })}${attr("aria-pressed", view === "edit")} data-testid="file-view-edit">${escape_html(t(fileeyeedit2))}</button> <button type="button"${attr_class("seg right svelte-cqlxfy", void 0, { "on": view === "diff" })}${attr("disabled", diffDisabled, true)}${attr("aria-pressed", view === "diff")} data-testid="file-view-diff">${escape_html(t(fileeyediff2))}</button></div>`);
|
|
17571
17486
|
} else $$renderer.push("<!--[-1-->");
|
|
17572
17487
|
$$renderer.push(`<!--]--> `);
|
|
17573
|
-
if (
|
|
17488
|
+
if (!readonly) {
|
|
17574
17489
|
$$renderer.push("<!--[0-->");
|
|
17575
|
-
$$renderer.push(`<
|
|
17490
|
+
$$renderer.push(`<button type="button" class="save-btn svelte-cqlxfy" data-testid="file-save"${attr("disabled", !dirty || saveState === "saving" || view === "diff", true)}>${escape_html(saveState === "saving" ? workspacePanelCopy.file.saving : workspacePanelCopy.file.save)}</button>`);
|
|
17576
17491
|
} else $$renderer.push("<!--[-1-->");
|
|
17577
17492
|
$$renderer.push(`<!--]--> `);
|
|
17578
17493
|
if (dirty) {
|
|
@@ -17594,7 +17509,7 @@ function WorkspaceFileToolbar($$renderer, $$props) {
|
|
|
17594
17509
|
$$renderer.push("<!--[0-->");
|
|
17595
17510
|
$$renderer.push(`<div class="tabs svelte-cqlxfy" role="tablist"><button role="tab"${attr("aria-selected", tab === "preview")} data-testid="tab-preview"${attr_class("svelte-cqlxfy", void 0, { "active": tab === "preview" })}>${escape_html(workspacePanelCopy.file.preview)}</button> <button role="tab"${attr("aria-selected", tab === "edit")} data-testid="tab-edit"${attr_class("svelte-cqlxfy", void 0, { "active": tab === "edit" })}>${escape_html(workspacePanelCopy.file.edit)}</button></div>`);
|
|
17596
17511
|
} else $$renderer.push("<!--[-1-->");
|
|
17597
|
-
$$renderer.push(`<!--]--> <span
|
|
17512
|
+
$$renderer.push(`<!--]--> <span class="copy-slot svelte-cqlxfy">`);
|
|
17598
17513
|
CanvasCopyButton($$renderer, {
|
|
17599
17514
|
container: columnEl,
|
|
17600
17515
|
title: workspacePanelCopy.common.copyColumn,
|
|
@@ -17605,6 +17520,105 @@ function WorkspaceFileToolbar($$renderer, $$props) {
|
|
|
17605
17520
|
});
|
|
17606
17521
|
}
|
|
17607
17522
|
//#endregion
|
|
17523
|
+
//#region src/lib/components/panels/WorkspaceFile.svelte
|
|
17524
|
+
function WorkspaceFile($$renderer, $$props) {
|
|
17525
|
+
$$renderer.component(($$renderer) => {
|
|
17526
|
+
/**
|
|
17527
|
+
* WorkspaceFile — the file body's view switch (extracted 2026-09-13
|
|
17528
|
+
* from WorkspaceFilePanel's markup, same extraction series as the
|
|
17529
|
+
* explorer components). Presentation only: every value arrives as a
|
|
17530
|
+
* prop, every intent leaves as a callback — the panel keeps the text
|
|
17531
|
+
* state, the Monaco lifecycle, and the save logic.
|
|
17532
|
+
*
|
|
17533
|
+
* Layout contract (the height fix that shipped with this extraction):
|
|
17534
|
+
* .file-panel fills its column (height: 100%) and NEVER scrolls
|
|
17535
|
+
* itself (overflow: hidden) — the scroll lives on .file-scroll for
|
|
17536
|
+
* the content views that need it (image, markdown preview). The
|
|
17537
|
+
* editor/iframe hosts take flex: 1 with min-height: 0 so the Monaco
|
|
17538
|
+
* editor sizes to the remaining space and scrolls INTERNALLY; the
|
|
17539
|
+
* old overflow:auto container made the hosts content-sized and the
|
|
17540
|
+
* page-level scrollbar stole the height.
|
|
17541
|
+
*/
|
|
17542
|
+
let { tab = void 0, dirty, fullPath, saveState, fileStale, staleNote, hasTabs, activeView, showToggle, diffDisabled, readonly, onViewChange, onSave, saveError, saveFailedNote, loadingNote, loadFailedNote, truncatedNote, newFileNote, phase, errorCode, title, isImage, bytesSrc, isHtml, text, isMarkdown, noHead, eof, editorHost = null, diffHost = null } = $$props;
|
|
17543
|
+
let $$settled = true;
|
|
17544
|
+
let $$inner_renderer;
|
|
17545
|
+
function $$render_inner($$renderer) {
|
|
17546
|
+
$$renderer.push(`<div data-svelte="WorkspaceFile" class="file-panel svelte-1ewqqbd">`);
|
|
17547
|
+
WorkspaceFileToolbar($$renderer, {
|
|
17548
|
+
dirty,
|
|
17549
|
+
path: fullPath,
|
|
17550
|
+
saveState,
|
|
17551
|
+
stale: fileStale,
|
|
17552
|
+
staleNote,
|
|
17553
|
+
hasTabs,
|
|
17554
|
+
view: activeView,
|
|
17555
|
+
showToggle,
|
|
17556
|
+
diffDisabled,
|
|
17557
|
+
readonly,
|
|
17558
|
+
onviewchange: onViewChange,
|
|
17559
|
+
onsave: onSave,
|
|
17560
|
+
get tab() {
|
|
17561
|
+
return tab;
|
|
17562
|
+
},
|
|
17563
|
+
set tab($$value) {
|
|
17564
|
+
tab = $$value;
|
|
17565
|
+
$$settled = false;
|
|
17566
|
+
}
|
|
17567
|
+
});
|
|
17568
|
+
$$renderer.push(`<!----> `);
|
|
17569
|
+
if (saveState === "failed") {
|
|
17570
|
+
$$renderer.push("<!--[0-->");
|
|
17571
|
+
$$renderer.push(`<p class="note fail svelte-1ewqqbd" data-testid="file-save-failed">${escape_html(saveFailedNote)}${escape_html(saveError ? " — " + saveError : "")}</p>`);
|
|
17572
|
+
} else $$renderer.push("<!--[-1-->");
|
|
17573
|
+
$$renderer.push(`<!--]--> `);
|
|
17574
|
+
if (phase === "loading") {
|
|
17575
|
+
$$renderer.push("<!--[0-->");
|
|
17576
|
+
$$renderer.push(`<p class="note svelte-1ewqqbd">${escape_html(loadingNote)}</p>`);
|
|
17577
|
+
} else if (phase === "failed") {
|
|
17578
|
+
$$renderer.push("<!--[1-->");
|
|
17579
|
+
$$renderer.push(`<p class="note fail svelte-1ewqqbd" data-testid="file-failed">${escape_html(loadFailedNote)} (${escape_html(errorCode)})</p>`);
|
|
17580
|
+
} else if (isImage) {
|
|
17581
|
+
$$renderer.push("<!--[2-->");
|
|
17582
|
+
$$renderer.push(`<div class="file-scroll svelte-1ewqqbd"><img class="img-preview svelte-1ewqqbd" data-testid="file-image"${attr("src", bytesSrc)}${attr("alt", title)}/></div>`);
|
|
17583
|
+
} else if (isHtml && tab === "preview") {
|
|
17584
|
+
$$renderer.push("<!--[3-->");
|
|
17585
|
+
$$renderer.push(`<iframe class="html-frame svelte-1ewqqbd" data-testid="file-html-frame" sandbox=""${attr("srcdoc", text ?? "")}${attr("title", title)}></iframe>`);
|
|
17586
|
+
} else if (activeView === "diff") {
|
|
17587
|
+
$$renderer.push("<!--[4-->");
|
|
17588
|
+
if (noHead) {
|
|
17589
|
+
$$renderer.push("<!--[0-->");
|
|
17590
|
+
$$renderer.push(`<p class="note svelte-1ewqqbd" data-testid="file-diff-new-file">${escape_html(newFileNote)}</p>`);
|
|
17591
|
+
} else $$renderer.push("<!--[-1-->");
|
|
17592
|
+
$$renderer.push(`<!--]--> <div class="file-editor-host svelte-1ewqqbd" data-testid="file-diff-view"></div>`);
|
|
17593
|
+
} else if (isMarkdown && tab === "preview") {
|
|
17594
|
+
$$renderer.push("<!--[5-->");
|
|
17595
|
+
$$renderer.push(`<div class="file-scroll svelte-1ewqqbd">`);
|
|
17596
|
+
MarkdownPanel($$renderer, { content: text ?? "" });
|
|
17597
|
+
$$renderer.push(`<!----></div>`);
|
|
17598
|
+
} else {
|
|
17599
|
+
$$renderer.push("<!--[-1-->");
|
|
17600
|
+
if (!eof) {
|
|
17601
|
+
$$renderer.push("<!--[0-->");
|
|
17602
|
+
$$renderer.push(`<p class="note svelte-1ewqqbd">${escape_html(truncatedNote)}</p>`);
|
|
17603
|
+
} else $$renderer.push("<!--[-1-->");
|
|
17604
|
+
$$renderer.push(`<!--]--> <div class="file-editor-host svelte-1ewqqbd"></div>`);
|
|
17605
|
+
}
|
|
17606
|
+
$$renderer.push(`<!--]--></div>`);
|
|
17607
|
+
}
|
|
17608
|
+
do {
|
|
17609
|
+
$$settled = true;
|
|
17610
|
+
$$inner_renderer = $$renderer.copy();
|
|
17611
|
+
$$render_inner($$inner_renderer);
|
|
17612
|
+
} while (!$$settled);
|
|
17613
|
+
$$renderer.subsume($$inner_renderer);
|
|
17614
|
+
bind_props($$props, {
|
|
17615
|
+
tab,
|
|
17616
|
+
editorHost,
|
|
17617
|
+
diffHost
|
|
17618
|
+
});
|
|
17619
|
+
});
|
|
17620
|
+
}
|
|
17621
|
+
//#endregion
|
|
17608
17622
|
//#region src/lib/components/panels/WorkspaceFilePanel.svelte
|
|
17609
17623
|
function WorkspaceFilePanel($$renderer, $$props) {
|
|
17610
17624
|
$$renderer.component(($$renderer) => {
|
|
@@ -17631,23 +17645,31 @@ function WorkspaceFilePanel($$renderer, $$props) {
|
|
|
17631
17645
|
* outside-workspace, too-large, not-text, not-regular-file.
|
|
17632
17646
|
*/
|
|
17633
17647
|
/** The read receipt (api/dsh/workspace-file body, DshWorkspaceFileText). */
|
|
17634
|
-
let { path, view = "edit", onviewchange} = $$props;
|
|
17648
|
+
let { sessionId, path, root, view = "edit", onviewchange, onclose } = $$props;
|
|
17635
17649
|
let viewOverride = null;
|
|
17636
17650
|
const activeView = derived(() => viewOverride ?? view);
|
|
17637
17651
|
let tab = "preview";
|
|
17652
|
+
let phase = "loading";
|
|
17653
|
+
let errorCode = null;
|
|
17654
|
+
let text = null;
|
|
17655
|
+
let eof = true;
|
|
17638
17656
|
/** Dirty = the edit buffer differs from the baseline. */
|
|
17639
17657
|
let dirty = false;
|
|
17640
17658
|
/** The delegated save's progress (ADR D4): idle → saving → saved /
|
|
17641
17659
|
* failed; a further edit re-arms the button from any state. */
|
|
17642
17660
|
let saveState = "idle";
|
|
17661
|
+
let saveError = null;
|
|
17643
17662
|
/** Index Pulse: an external change landed on disk while a draft exists
|
|
17644
17663
|
* in the buffer — surfaced as a visible note; the draft is kept. */
|
|
17645
17664
|
let fileStale = false;
|
|
17665
|
+
let noHead = false;
|
|
17666
|
+
let diffHost = null;
|
|
17646
17667
|
/** Toggle intent: bridge the click, then hand the choice to the owner. */
|
|
17647
17668
|
function setView(next) {
|
|
17648
17669
|
viewOverride = next;
|
|
17649
17670
|
onviewchange?.(next);
|
|
17650
17671
|
}
|
|
17672
|
+
let editorHost = null;
|
|
17651
17673
|
const isMarkdown = derived(() => path.toLowerCase().endsWith(".md"));
|
|
17652
17674
|
/** HTML documents preview like markdown (two tabs): the preview tab
|
|
17653
17675
|
* mounts a SANDBOXED iframe (srcdoc, no scripts — a read-only render
|
|
@@ -17655,6 +17677,36 @@ function WorkspaceFilePanel($$renderer, $$props) {
|
|
|
17655
17677
|
* every text file (2026-09-10). */
|
|
17656
17678
|
const isHtml = derived(() => /\.html?$/.test(path.toLowerCase()));
|
|
17657
17679
|
const hasTabs = derived(() => isMarkdown() || isHtml());
|
|
17680
|
+
/** Image extensions preview through /api/dsh/workspace-file-bytes with
|
|
17681
|
+
* an <img> element — READ-ONLY by nature (no tabs, no edit buffer);
|
|
17682
|
+
* `read` refuses binaries workspace-file/not-text (2026-09-10). */
|
|
17683
|
+
const IMAGE_EXT = [
|
|
17684
|
+
"png",
|
|
17685
|
+
"jpg",
|
|
17686
|
+
"jpeg",
|
|
17687
|
+
"gif",
|
|
17688
|
+
"webp",
|
|
17689
|
+
"svg",
|
|
17690
|
+
"bmp",
|
|
17691
|
+
"ico",
|
|
17692
|
+
"avif"
|
|
17693
|
+
];
|
|
17694
|
+
const isImage = derived(() => IMAGE_EXT.includes(path.split(".").pop()?.toLowerCase() ?? ""));
|
|
17695
|
+
const bytesSrc = derived(() => "/api/dsh/workspace-file-bytes?sessionId=" + encodeURIComponent(sessionId) + "&path=" + encodeURIComponent(path));
|
|
17696
|
+
const title = derived(() => path.split("/").filter((p) => p.length > 0).pop() ?? path);
|
|
17697
|
+
/** The FULL display path (root + relative path) — the toolbar's
|
|
17698
|
+
* left-side readout (the SettingsHomeToolbar pattern), with the
|
|
17699
|
+
* same tilde discipline: the operator's home directory collapses
|
|
17700
|
+
* to `~` before anything hits the screen. The homedir is derived
|
|
17701
|
+
* from the config store's server homedir truth (the settingsHomes
|
|
17702
|
+
* roots, The Settings Tree ADR D2) — never guessed client-side. */
|
|
17703
|
+
const fullPath = derived(() => {
|
|
17704
|
+
const full = root.replace(/\/+$/, "") + "/" + path.replace(/^\/+/, "");
|
|
17705
|
+
const dsi = appConfig().settingsHomes.dsi;
|
|
17706
|
+
const marker = dsi.lastIndexOf("/.dsi");
|
|
17707
|
+
const homeDir = marker > 0 ? dsi.slice(0, marker) : null;
|
|
17708
|
+
return homeDir !== null && full.startsWith(homeDir + "/") ? "~" + full.slice(homeDir.length) : full;
|
|
17709
|
+
});
|
|
17658
17710
|
/** The DIRECT save (The File Eye ADR D4): POST the buffer to the
|
|
17659
17711
|
* gated write route; the written receipt advances the baseline so
|
|
17660
17712
|
* dirty clears — bytes on disk, not an agent's promise. */
|
|
@@ -17662,33 +17714,59 @@ function WorkspaceFilePanel($$renderer, $$props) {
|
|
|
17662
17714
|
let $$settled = true;
|
|
17663
17715
|
let $$inner_renderer;
|
|
17664
17716
|
function $$render_inner($$renderer) {
|
|
17665
|
-
$$renderer.push(`<div data-svelte="WorkspaceFilePanel"
|
|
17666
|
-
|
|
17717
|
+
$$renderer.push(`<div data-svelte="WorkspaceFilePanel" data-testid="workspace-file-panel"${attr("data-file-path", path)} class="file-body svelte-1pgc8hn">`);
|
|
17718
|
+
WorkspaceFile($$renderer, {
|
|
17667
17719
|
dirty,
|
|
17720
|
+
fullPath: fullPath(),
|
|
17668
17721
|
saveState,
|
|
17669
|
-
|
|
17722
|
+
fileStale,
|
|
17670
17723
|
staleNote: t(fileeyeexternalchange3),
|
|
17671
17724
|
hasTabs: hasTabs(),
|
|
17672
|
-
|
|
17725
|
+
activeView: activeView(),
|
|
17673
17726
|
showToggle: false,
|
|
17674
17727
|
diffDisabled: dirty,
|
|
17675
17728
|
readonly: false,
|
|
17676
|
-
|
|
17677
|
-
|
|
17729
|
+
onViewChange: setView,
|
|
17730
|
+
onSave: save,
|
|
17731
|
+
saveError,
|
|
17732
|
+
saveFailedNote: workspacePanelCopy.file.saveFailed,
|
|
17733
|
+
loadingNote: workspacePanelCopy.explorer.loading,
|
|
17734
|
+
loadFailedNote: workspacePanelCopy.file.loadFailed,
|
|
17735
|
+
truncatedNote: workspacePanelCopy.file.truncated,
|
|
17736
|
+
newFileNote: t(fileeyenewfile3),
|
|
17737
|
+
phase,
|
|
17738
|
+
errorCode,
|
|
17739
|
+
title: title(),
|
|
17740
|
+
isImage: isImage(),
|
|
17741
|
+
bytesSrc: bytesSrc(),
|
|
17742
|
+
isHtml: isHtml(),
|
|
17743
|
+
text,
|
|
17744
|
+
isMarkdown: isMarkdown(),
|
|
17745
|
+
noHead,
|
|
17746
|
+
eof,
|
|
17678
17747
|
get tab() {
|
|
17679
17748
|
return tab;
|
|
17680
17749
|
},
|
|
17681
17750
|
set tab($$value) {
|
|
17682
17751
|
tab = $$value;
|
|
17683
17752
|
$$settled = false;
|
|
17753
|
+
},
|
|
17754
|
+
get editorHost() {
|
|
17755
|
+
return editorHost;
|
|
17756
|
+
},
|
|
17757
|
+
set editorHost($$value) {
|
|
17758
|
+
editorHost = $$value;
|
|
17759
|
+
$$settled = false;
|
|
17760
|
+
},
|
|
17761
|
+
get diffHost() {
|
|
17762
|
+
return diffHost;
|
|
17763
|
+
},
|
|
17764
|
+
set diffHost($$value) {
|
|
17765
|
+
diffHost = $$value;
|
|
17766
|
+
$$settled = false;
|
|
17684
17767
|
}
|
|
17685
17768
|
});
|
|
17686
|
-
$$renderer.push(
|
|
17687
|
-
$$renderer.push("<!--[-1-->");
|
|
17688
|
-
$$renderer.push(`<!--]--> `);
|
|
17689
|
-
$$renderer.push("<!--[0-->");
|
|
17690
|
-
$$renderer.push(`<p class="note svelte-1pgc8hn">${escape_html(workspacePanelCopy.explorer.loading)}</p>`);
|
|
17691
|
-
$$renderer.push(`<!--]--></div>`);
|
|
17769
|
+
$$renderer.push(`<!----></div>`);
|
|
17692
17770
|
}
|
|
17693
17771
|
do {
|
|
17694
17772
|
$$settled = true;
|
|
@@ -17699,27 +17777,457 @@ function WorkspaceFilePanel($$renderer, $$props) {
|
|
|
17699
17777
|
});
|
|
17700
17778
|
}
|
|
17701
17779
|
//#endregion
|
|
17702
|
-
//#region src/lib/components/panels/
|
|
17703
|
-
function
|
|
17780
|
+
//#region src/lib/components/panels/SettingsHomeToolbar.svelte
|
|
17781
|
+
function SettingsHomeToolbar($$renderer, $$props) {
|
|
17704
17782
|
$$renderer.component(($$renderer) => {
|
|
17705
|
-
|
|
17706
|
-
|
|
17707
|
-
|
|
17708
|
-
|
|
17709
|
-
|
|
17710
|
-
|
|
17783
|
+
let columnEl = null;
|
|
17784
|
+
let { fullPath, dirty, saving} = $$props;
|
|
17785
|
+
$$renderer.push(`<div data-svelte="SettingsHomeToolbar" class="bar svelte-9whorb"><span class="path svelte-9whorb"${attr("title", fullPath)}>${escape_html(fullPath)}</span> `);
|
|
17786
|
+
if (dirty) {
|
|
17787
|
+
$$renderer.push("<!--[0-->");
|
|
17788
|
+
$$renderer.push(`<span class="dirty svelte-9whorb" data-testid="settings-home-dirty">●</span>`);
|
|
17789
|
+
} else $$renderer.push("<!--[-1-->");
|
|
17790
|
+
$$renderer.push(`<!--]--> <button class="save svelte-9whorb"${attr("disabled", !dirty || saving, true)}>${escape_html(t(save))}</button> <span class="copy-slot svelte-9whorb">`);
|
|
17791
|
+
CanvasCopyButton($$renderer, {
|
|
17792
|
+
container: columnEl,
|
|
17793
|
+
title: workspacePanelCopy.common.copyColumn,
|
|
17794
|
+
size: 12
|
|
17795
|
+
});
|
|
17796
|
+
$$renderer.push(`<!----></span></div>`);
|
|
17797
|
+
});
|
|
17798
|
+
}
|
|
17799
|
+
//#endregion
|
|
17800
|
+
//#region src/lib/components/panels/SettingsHomeFile.svelte
|
|
17801
|
+
function SettingsHomeFile($$renderer, $$props) {
|
|
17802
|
+
$$renderer.component(($$renderer) => {
|
|
17803
|
+
/**
|
|
17804
|
+
* SettingsHomeFile — The Settings Tree ADR (2026-09-18, D2): the file
|
|
17805
|
+
* body of a settings-home explorer tab. Edits ride the DSI-local
|
|
17806
|
+
* /api/settings-home plane: load, edit, save, with an honest dirty
|
|
17807
|
+
* indicator. Deliberately NOT the WorkspaceFilePanel — that surface is
|
|
17808
|
+
* session-scoped and git-faced, and a settings home has neither a
|
|
17809
|
+
* session nor git guarantees.
|
|
17810
|
+
*
|
|
17811
|
+
* The editor itself IS the shared lazy Monaco seam (settings-monaco.ts,
|
|
17812
|
+
* createTextEditor) — the RCA of 2026-09-18 ("The Home Tab That Lost Its
|
|
17813
|
+
* Colors") records why the first cut shipped a textarea: the seam was
|
|
17814
|
+
* never named in the ADR's file map. No component imports monaco-editor
|
|
17815
|
+
* directly; the dynamic import keeps the lazy chunk (monaco-lazy-chunk
|
|
17816
|
+
* build gate). Language is guessed from the file extension.
|
|
17817
|
+
*/
|
|
17818
|
+
let { home, path } = $$props;
|
|
17819
|
+
let loaded = false;
|
|
17820
|
+
let saving = false;
|
|
17821
|
+
const dirty = derived(() => loaded);
|
|
17822
|
+
/** Full path for display, tilde-abbreviated: the home root (server
|
|
17823
|
+
* homedir truth via /api/config, The Settings Tree ADR 2026-09-18
|
|
17824
|
+
* D2) joined with the home-relative `path` prop, then the operator's
|
|
17825
|
+
* home directory collapses to `~` — the readout never exposes the
|
|
17826
|
+
* real home path to the wire/screen. A $derived so a late config
|
|
17827
|
+
* load re-renders the toolbar's path readout. */
|
|
17828
|
+
const fullPath = derived(() => {
|
|
17829
|
+
const root = appConfig().settingsHomes[home];
|
|
17830
|
+
const full = root.endsWith("/") ? root + path : root + "/" + path;
|
|
17831
|
+
const marker = full.indexOf(home === "dsi" ? "/.dsi/" : "/.dsh/");
|
|
17832
|
+
return marker > 0 ? "~" + full.slice(marker) : full;
|
|
17833
|
+
});
|
|
17834
|
+
$$renderer.push(`<div data-svelte="SettingsHomeFile" class="home-file svelte-bq960k" data-testid="settings-home-file">`);
|
|
17835
|
+
SettingsHomeToolbar($$renderer, {
|
|
17836
|
+
fullPath: fullPath(),
|
|
17837
|
+
dirty: dirty(),
|
|
17838
|
+
saving});
|
|
17839
|
+
$$renderer.push(`<!----> `);
|
|
17840
|
+
$$renderer.push("<!--[-1-->");
|
|
17841
|
+
$$renderer.push(`<!--]--> <div class="editor-host svelte-bq960k" data-testid="settings-home-editor"></div></div>`);
|
|
17842
|
+
});
|
|
17843
|
+
}
|
|
17844
|
+
//#endregion
|
|
17845
|
+
//#region src/lib/components/panels/WorkspaceFileTabs.svelte
|
|
17846
|
+
function WorkspaceFileTabs($$renderer, $$props) {
|
|
17847
|
+
$$renderer.component(($$renderer) => {
|
|
17848
|
+
/**
|
|
17849
|
+
* WorkspaceFileTabs — the Explorer Layout's tab strip + file container
|
|
17850
|
+
* (ADR 2026-09-17 D3/D5, extracted from day one per the ADR's §7
|
|
17851
|
+
* give-up: the panel must not grow into the new monolith).
|
|
17852
|
+
*
|
|
17853
|
+
* PRESENTATION ONLY (Module Communication Map): the open-tab list, the
|
|
17854
|
+
* active path, and every fetch arrive as PROPS from the owning
|
|
17855
|
+
* WorkspaceExplorerPanel; the only things leaving are INTENT callbacks
|
|
17856
|
+
* — onActivate (focus an open tab), onClose (the per-tab [x]). The
|
|
17857
|
+
* content region is the parent's children snippet, so the panel hosts
|
|
17858
|
+
* WorkspaceFile itself and this component never fetches.
|
|
17859
|
+
*
|
|
17860
|
+
* A closed panel drops the tabs with it (D5) — nothing here persists.
|
|
17861
|
+
*/
|
|
17862
|
+
/** One open file tab — the panel's component state, deduped by path. */
|
|
17863
|
+
/** Root-relative path — identity within the panel's tab list. */
|
|
17864
|
+
let { tabs, activePath, children } = $$props;
|
|
17865
|
+
/** Tab label — the leaf name; the full root-relative path rides the
|
|
17866
|
+
* title attribute (ADR D5). */
|
|
17867
|
+
function leaf(path) {
|
|
17868
|
+
const idx = path.lastIndexOf("/");
|
|
17869
|
+
return idx === -1 ? path : path.slice(idx + 1);
|
|
17870
|
+
}
|
|
17871
|
+
$$renderer.push(`<div data-svelte="WorkspaceFileTabs" class="file-tabs svelte-1hdf0bx" data-testid="workspace-file-tabs">`);
|
|
17872
|
+
if (tabs.length > 0) {
|
|
17873
|
+
$$renderer.push("<!--[0-->");
|
|
17874
|
+
$$renderer.push(`<div class="strip svelte-1hdf0bx" role="tablist" data-testid="workspace-file-tabstrip"><!--[-->`);
|
|
17875
|
+
const each_array = ensure_array_like(tabs);
|
|
17876
|
+
for (let $$index = 0, $$length = each_array.length; $$index < $$length; $$index++) {
|
|
17877
|
+
let tab = each_array[$$index];
|
|
17878
|
+
$$renderer.push(`<button type="button" role="tab"${attr_class("tab svelte-1hdf0bx", void 0, { "active": tab.path === activePath })}${attr("data-testid", `workspace-file-tab-${stringify(tab.path)}`)}${attr("title", tab.path)}${attr("aria-selected", tab.path === activePath)}><span class="label svelte-1hdf0bx">${escape_html(leaf(tab.path))}</span> <span role="button" tabindex="-1" class="close svelte-1hdf0bx"${attr("data-testid", `workspace-file-tabclose-${stringify(tab.path)}`)}${attr("aria-label", t(close))}${attr("title", t(close))}>×</span></button>`);
|
|
17879
|
+
}
|
|
17880
|
+
$$renderer.push(`<!--]--></div> <div class="body svelte-1hdf0bx">`);
|
|
17881
|
+
children($$renderer);
|
|
17882
|
+
$$renderer.push(`<!----></div>`);
|
|
17883
|
+
} else {
|
|
17884
|
+
$$renderer.push("<!--[-1-->");
|
|
17885
|
+
$$renderer.push(`<div class="empty svelte-1hdf0bx" data-testid="workspace-file-tabs-empty"></div>`);
|
|
17886
|
+
}
|
|
17887
|
+
$$renderer.push(`<!--]--></div>`);
|
|
17888
|
+
});
|
|
17889
|
+
}
|
|
17890
|
+
//#endregion
|
|
17891
|
+
//#region src/lib/components/panels/ResizeGutter.svelte
|
|
17892
|
+
function ResizeGutter($$renderer, $$props) {
|
|
17893
|
+
$$renderer.component(($$renderer) => {
|
|
17894
|
+
/**
|
|
17895
|
+
* ResizeGutter — the 6px draggable seam after every panel (Panel Floor
|
|
17896
|
+
* W3 task 3.2, ADR-0006 R8; OCI port, every-panel-has-a-right-gutter
|
|
17897
|
+
* rule — with individual resize (2026-08-28) each gutter owns its
|
|
17898
|
+
* OWN panel's width, so the rule now just means no panel is the
|
|
17899
|
+
* only one without a seam).
|
|
17711
17900
|
*
|
|
17712
17901
|
* The gutter does not resize anything itself — mousedown reports
|
|
17713
17902
|
* (event, index) upward through the panel registry (the ONLY
|
|
17714
17903
|
* leaf→root action channel, commitment 2), and the workspace route
|
|
17715
17904
|
* (the single drag owner) snapshots widths and runs the individual /
|
|
17716
17905
|
* proportional math on window mousemove.
|
|
17906
|
+
*
|
|
17907
|
+
* The Explorer Layout (ADR 2026-09-17 D4): an OPTIONAL onDragStart
|
|
17908
|
+
* owner prop — when given, the mousedown fires IT instead of the
|
|
17909
|
+
* registry import and the calling component is the drag owner (the
|
|
17910
|
+
* gutter instance lives inside one component, so no leaf→root hop is
|
|
17911
|
+
* needed). When absent, the floor path above runs verbatim — every
|
|
17912
|
+
* existing call site is untouched.
|
|
17717
17913
|
*/
|
|
17718
|
-
let { index } = $$props;
|
|
17914
|
+
let { index, onDragStart } = $$props;
|
|
17719
17915
|
$$renderer.push(`<button data-svelte="ResizeGutter" type="button" class="gutter svelte-gujdub"${attr("data-testid", `panel-gutter-${stringify(index)}`)}${attr("aria-label", t(resizepanel1))}${attr("title", t(dragresize1))}></button>`);
|
|
17720
17916
|
});
|
|
17721
17917
|
}
|
|
17722
17918
|
//#endregion
|
|
17919
|
+
//#region src/lib/utils/panel-prefs.ts
|
|
17920
|
+
/** localStorage base key — one JSON blob `{ panels, selectedPanelId, panelWidth, zoom }`.
|
|
17921
|
+
* A workspace profile (`?profile=…` on the URL) suffixes EVERY dsi-* key
|
|
17922
|
+
* (see storage-profile.ts): the default desk lives under `dsi-panels`,
|
|
17923
|
+
* profile `widi` under `dsi-panels_widi`. */
|
|
17924
|
+
var PANEL_PREFS_KEY = "dsi-panels";
|
|
17925
|
+
/**
|
|
17926
|
+
* The storage key for a workspace profile.
|
|
17927
|
+
* @param profile sanitized profile segment, or null/undefined for the
|
|
17928
|
+
* default desk (`dsi-panels`).
|
|
17929
|
+
*/
|
|
17930
|
+
function panelPrefsKey(profile) {
|
|
17931
|
+
return dsiKey(PANEL_PREFS_KEY, profile);
|
|
17932
|
+
}
|
|
17933
|
+
var PANEL_WORKSPACE_FILE_MAX_WIDTH = 1436;
|
|
17934
|
+
/** The single treePct bound site — sanitize a stored or dragged value
|
|
17935
|
+
* into [TREE_PCT_MIN, TREE_PCT_MAX]; junk (non-finite) falls back to
|
|
17936
|
+
* TREE_PCT_DEFAULT. Mirrors clampPanelZoom's discipline. */
|
|
17937
|
+
function clampTreePct(pct) {
|
|
17938
|
+
if (typeof pct !== "number" || !Number.isFinite(pct)) return 30;
|
|
17939
|
+
return Math.max(15, Math.min(70, Math.round(pct)));
|
|
17940
|
+
}
|
|
17941
|
+
/**
|
|
17942
|
+
* The single panel-width bound site — load-side sanitizing, gutter drags,
|
|
17943
|
+
* and the width slider all route through here. Bounds read the config
|
|
17944
|
+
* store (layout load has landed them before any mount; defaults before).
|
|
17945
|
+
*/
|
|
17946
|
+
function clampPanelWidth(width, kind) {
|
|
17947
|
+
const { minWidth, maxWidth } = appConfig().panel;
|
|
17948
|
+
if (kind === "workspace-explorer") return Math.max(520, Math.min(PANEL_WORKSPACE_FILE_MAX_WIDTH, width));
|
|
17949
|
+
if (kind === "workspace-file") return Math.max(520, Math.min(PANEL_WORKSPACE_FILE_MAX_WIDTH, width));
|
|
17950
|
+
return Math.max(minWidth, Math.min(maxWidth, width));
|
|
17951
|
+
}
|
|
17952
|
+
/** The single zoom bound site — load-side sanitizing and the zoom slider. */
|
|
17953
|
+
function clampPanelZoom(zoom) {
|
|
17954
|
+
const { minZoom, maxZoom } = appConfig().panel;
|
|
17955
|
+
return Math.max(minZoom, Math.min(maxZoom, zoom));
|
|
17956
|
+
}
|
|
17957
|
+
/** Config-driven default width (clamped through the single bound site). */
|
|
17958
|
+
function defaultPanelWidth() {
|
|
17959
|
+
return clampPanelWidth(appConfig().panel.defaultWidth);
|
|
17960
|
+
}
|
|
17961
|
+
/**
|
|
17962
|
+
* Clamp a stored explorer `expanded` list to sane paths (Workspace
|
|
17963
|
+
* Explorer restore): non-string members drop and a repeated path keeps
|
|
17964
|
+
* its FIRST occurrence — the tree treats `expanded` as a set of
|
|
17965
|
+
* root-relative directories, and a duplicate would double-render a row.
|
|
17966
|
+
*/
|
|
17967
|
+
function clampExpanded(value) {
|
|
17968
|
+
if (!Array.isArray(value)) return [];
|
|
17969
|
+
const seen = /* @__PURE__ */ new Set();
|
|
17970
|
+
const out = [];
|
|
17971
|
+
for (const member of value) {
|
|
17972
|
+
if (typeof member !== "string" || seen.has(member)) continue;
|
|
17973
|
+
seen.add(member);
|
|
17974
|
+
out.push(member);
|
|
17975
|
+
}
|
|
17976
|
+
return out;
|
|
17977
|
+
}
|
|
17978
|
+
/** Persisted defaults when nothing (usable) is stored. */
|
|
17979
|
+
function defaultPanelPrefs() {
|
|
17980
|
+
return {
|
|
17981
|
+
panels: [],
|
|
17982
|
+
selectedPanelId: null,
|
|
17983
|
+
panelWidth: defaultPanelWidth(),
|
|
17984
|
+
zoom: 1,
|
|
17985
|
+
treePct: 30
|
|
17986
|
+
};
|
|
17987
|
+
}
|
|
17988
|
+
/**
|
|
17989
|
+
* Hard shape check for a stored panel entry (the parse boundary).
|
|
17990
|
+
* KIND (2026-09-06, ADR D6): absent or 'conversation' is the legacy shape —
|
|
17991
|
+
* `sessionId` required; 'prompt-manager' carries no session fields;
|
|
17992
|
+
* 'injected-doc' (Loadinjected ADR D2) requires non-empty `sourceSessionId`
|
|
17993
|
+
* + `displayPath` — the dedupe key. Any other kind value is hard junk
|
|
17994
|
+
* (entry drops). `agentPreset` and `width`
|
|
17995
|
+
* may be absent (defaulted later); `agentPreset` when present must be
|
|
17996
|
+
* string|null, `width` when present must be a finite number. Unknown
|
|
17997
|
+
* extra keys are fine — they survive sanitizing.
|
|
17998
|
+
*/
|
|
17999
|
+
function isPanelEntry(value) {
|
|
18000
|
+
if (value === null || typeof value !== "object") return false;
|
|
18001
|
+
const entry = value;
|
|
18002
|
+
if (typeof entry.id !== "string" || entry.id.length === 0) return false;
|
|
18003
|
+
if (entry.kind !== void 0 && entry.kind !== "conversation" && entry.kind !== "prompt-manager" && entry.kind !== "settings-editor" && entry.kind !== "injected-doc" && entry.kind !== "workspace-explorer" && entry.kind !== "workspace-file") return false;
|
|
18004
|
+
if (entry.kind === "settings-editor" && entry.target !== "dsi" && entry.target !== "dsh") return false;
|
|
18005
|
+
if (entry.kind === "workspace-explorer") {
|
|
18006
|
+
if (entry.sessionId !== null && (typeof entry.sessionId !== "string" || entry.sessionId.length === 0)) return false;
|
|
18007
|
+
if (entry.sessionId === null && entry.home !== "dsi" && entry.home !== "dsh") return false;
|
|
18008
|
+
}
|
|
18009
|
+
if (entry.kind === "workspace-file") {
|
|
18010
|
+
if (typeof entry.sessionId !== "string" || entry.sessionId.length === 0) return false;
|
|
18011
|
+
}
|
|
18012
|
+
if (entry.kind === "workspace-explorer" && typeof entry.root !== "string") return false;
|
|
18013
|
+
if (entry.kind === "workspace-file") {
|
|
18014
|
+
if (typeof entry.path !== "string" || entry.path.length === 0) return false;
|
|
18015
|
+
}
|
|
18016
|
+
if (entry.kind === "injected-doc") {
|
|
18017
|
+
if (typeof entry.sourceSessionId !== "string" || entry.sourceSessionId.length === 0) return false;
|
|
18018
|
+
if (typeof entry.displayPath !== "string" || entry.displayPath.length === 0) return false;
|
|
18019
|
+
}
|
|
18020
|
+
if (entry.kind !== "prompt-manager" && entry.kind !== "settings-editor" && entry.kind !== "injected-doc" && entry.kind !== "workspace-explorer" && entry.kind !== "workspace-file") {
|
|
18021
|
+
if (typeof entry.sessionId !== "string" || entry.sessionId.length === 0) return false;
|
|
18022
|
+
if (entry.agentPreset !== void 0 && typeof entry.agentPreset !== "string" && entry.agentPreset !== null) return false;
|
|
18023
|
+
}
|
|
18024
|
+
if (entry.width !== void 0 && (typeof entry.width !== "number" || !Number.isFinite(entry.width))) return false;
|
|
18025
|
+
return true;
|
|
18026
|
+
}
|
|
18027
|
+
/** Drop hard-junk entries; default missing keys; clamp widths. Unknown
|
|
18028
|
+
* keys on surviving entries pass through untouched.
|
|
18029
|
+
*
|
|
18030
|
+
* Duplicate ids (2026-08-24 crash fix): a corrupted blob carrying the
|
|
18031
|
+
* same panel-N twice would reach the keyed each in SidebarOpenPanels
|
|
18032
|
+
* and crash Svelte (each_key_duplicate) at render — the each's key is
|
|
18033
|
+
* the panel id. Duplicates drop to the FIRST occurrence (order is the
|
|
18034
|
+
* floor's left-to-right truth); a selectedPanelId left dangling by the
|
|
18035
|
+
* dedupe re-sanitizes to the first panel in loadPanelPrefs. */
|
|
18036
|
+
function sanitizePanels(raw) {
|
|
18037
|
+
if (!Array.isArray(raw)) return [];
|
|
18038
|
+
const seen = /* @__PURE__ */ new Set();
|
|
18039
|
+
return raw.filter((entry) => isPanelEntry(entry)).map((entry) => {
|
|
18040
|
+
const kindDefault = entry.kind === "workspace-explorer" ? 850 : entry.kind === "workspace-file" ? 850 : defaultPanelWidth();
|
|
18041
|
+
const width = clampPanelWidth(typeof entry.width === "number" && Number.isFinite(entry.width) ? entry.width : kindDefault, entry.kind);
|
|
18042
|
+
if (entry.kind === "prompt-manager") return {
|
|
18043
|
+
id: entry.id,
|
|
18044
|
+
kind: "prompt-manager",
|
|
18045
|
+
width
|
|
18046
|
+
};
|
|
18047
|
+
if (entry.kind === "settings-editor") return {
|
|
18048
|
+
id: entry.id,
|
|
18049
|
+
kind: "settings-editor",
|
|
18050
|
+
target: entry.target,
|
|
18051
|
+
width
|
|
18052
|
+
};
|
|
18053
|
+
if (entry.kind === "injected-doc") return {
|
|
18054
|
+
id: entry.id,
|
|
18055
|
+
kind: "injected-doc",
|
|
18056
|
+
sourceSessionId: entry.sourceSessionId,
|
|
18057
|
+
displayPath: entry.displayPath,
|
|
18058
|
+
width
|
|
18059
|
+
};
|
|
18060
|
+
if (entry.kind === "workspace-explorer") {
|
|
18061
|
+
const home = entry.home === "dsi" || entry.home === "dsh" ? entry.home : void 0;
|
|
18062
|
+
return {
|
|
18063
|
+
id: entry.id,
|
|
18064
|
+
kind: "workspace-explorer",
|
|
18065
|
+
sessionId: entry.sessionId ?? null,
|
|
18066
|
+
root: entry.root,
|
|
18067
|
+
...typeof entry.title === "string" && entry.title.length > 0 ? { title: entry.title } : {},
|
|
18068
|
+
...home !== void 0 ? { home } : {},
|
|
18069
|
+
expanded: clampExpanded(entry.expanded),
|
|
18070
|
+
tab: entry.tab === "changes" ? "changes" : "explorer",
|
|
18071
|
+
collapsedRepos: clampExpanded(entry.collapsedRepos),
|
|
18072
|
+
openTabs: clampExpanded(entry.openTabs),
|
|
18073
|
+
activeFile: typeof entry.activeFile === "string" ? entry.activeFile : null,
|
|
18074
|
+
width
|
|
18075
|
+
};
|
|
18076
|
+
}
|
|
18077
|
+
if (entry.kind === "workspace-file") return {
|
|
18078
|
+
id: entry.id,
|
|
18079
|
+
kind: "workspace-file",
|
|
18080
|
+
sessionId: entry.sessionId,
|
|
18081
|
+
path: entry.path,
|
|
18082
|
+
explorerPanelId: typeof entry.explorerPanelId === "string" && entry.explorerPanelId.length > 0 ? entry.explorerPanelId : null,
|
|
18083
|
+
view: entry.view === "diff" ? "diff" : "edit",
|
|
18084
|
+
width
|
|
18085
|
+
};
|
|
18086
|
+
return {
|
|
18087
|
+
...entry,
|
|
18088
|
+
id: entry.id,
|
|
18089
|
+
kind: "conversation",
|
|
18090
|
+
sessionId: entry.sessionId,
|
|
18091
|
+
agentPreset: entry.agentPreset ?? null,
|
|
18092
|
+
width
|
|
18093
|
+
};
|
|
18094
|
+
}).filter((entry) => {
|
|
18095
|
+
if (seen.has(entry.id)) return false;
|
|
18096
|
+
seen.add(entry.id);
|
|
18097
|
+
return true;
|
|
18098
|
+
});
|
|
18099
|
+
}
|
|
18100
|
+
/**
|
|
18101
|
+
* Read the workspace state from localStorage.
|
|
18102
|
+
* @param profile sanitized workspace profile (null/omitted = default desk).
|
|
18103
|
+
* @returns stored state when parseable (sanitized), defaults when absent,
|
|
18104
|
+
* junk, or SSR. A `selectedPanelId` pointing at a missing panel
|
|
18105
|
+
* sanitizes to the first panel's id (null when no panels remain).
|
|
18106
|
+
*/
|
|
18107
|
+
function loadPanelPrefs(profile) {
|
|
18108
|
+
if (typeof localStorage === "undefined") return defaultPanelPrefs();
|
|
18109
|
+
try {
|
|
18110
|
+
const raw = localStorage.getItem(panelPrefsKey(profile));
|
|
18111
|
+
if (!raw) return defaultPanelPrefs();
|
|
18112
|
+
const parsed = JSON.parse(raw);
|
|
18113
|
+
if (parsed === null || typeof parsed !== "object") return defaultPanelPrefs();
|
|
18114
|
+
if (!Array.isArray(parsed.panels)) return defaultPanelPrefs();
|
|
18115
|
+
const panels = sanitizePanels(parsed.panels);
|
|
18116
|
+
const panelWidth = typeof parsed.panelWidth === "number" && Number.isFinite(parsed.panelWidth) ? clampPanelWidth(parsed.panelWidth) : defaultPanelWidth();
|
|
18117
|
+
const zoom = typeof parsed.zoom === "number" && Number.isFinite(parsed.zoom) ? clampPanelZoom(parsed.zoom) : 1;
|
|
18118
|
+
const treePct = typeof parsed.treePct === "number" && Number.isFinite(parsed.treePct) ? clampTreePct(parsed.treePct) : 30;
|
|
18119
|
+
return {
|
|
18120
|
+
panels,
|
|
18121
|
+
selectedPanelId: typeof parsed.selectedPanelId === "string" && panels.some((panel) => panel.id === parsed.selectedPanelId) ? parsed.selectedPanelId : panels[0]?.id ?? null,
|
|
18122
|
+
panelWidth,
|
|
18123
|
+
zoom,
|
|
18124
|
+
treePct
|
|
18125
|
+
};
|
|
18126
|
+
} catch {
|
|
18127
|
+
return defaultPanelPrefs();
|
|
18128
|
+
}
|
|
18129
|
+
}
|
|
18130
|
+
//#endregion
|
|
18131
|
+
//#region src/lib/components/panels/WorkspaceExplorerPanel.svelte
|
|
18132
|
+
function WorkspaceExplorerPanel($$renderer, $$props) {
|
|
18133
|
+
$$renderer.component(($$renderer) => {
|
|
18134
|
+
let { sessionId, root, home, expanded, onToggle, onOpenFile, onCollapseAll, tab = "explorer", onTabChange, collapsedRepos, onToggleRepo, onCollapseAllRepos, treePct = 30, onTreePctChange, pendingOpenFile = null, onPendingOpenConsumed, openTabs = [], activeFile = null, onOpenTab, onCloseTab, onActivateTab } = $$props;
|
|
18135
|
+
/** Rel path → level state. Key '' is the root level. */
|
|
18136
|
+
let levels = {};
|
|
18137
|
+
let repoMaps = {};
|
|
18138
|
+
const activeTab = derived(() => tab);
|
|
18139
|
+
let changesStatuses = {};
|
|
18140
|
+
/** Repos under the workspace root, as rel paths ('' first when the root
|
|
18141
|
+
* is one). Empty until the root probe answers. The tab strip is
|
|
18142
|
+
* unconditional (Always Tabs D1) — this list drives ROWS, not tabs. */
|
|
18143
|
+
const changesRepos = derived(() => {
|
|
18144
|
+
const rootMap = repoMaps[""];
|
|
18145
|
+
if (!rootMap) return [];
|
|
18146
|
+
const out = [];
|
|
18147
|
+
if (rootMap.rootIsRepo) out.push("");
|
|
18148
|
+
for (const [name, flag] of Object.entries(rootMap.repos)) if (flag) out.push(name);
|
|
18149
|
+
return out;
|
|
18150
|
+
});
|
|
18151
|
+
/** Root-relative paths reported changed by git-status — the Explorer
|
|
18152
|
+
* tree tints these file rows red, the same contract as the Changes rows. */
|
|
18153
|
+
const changedPaths = derived(() => {
|
|
18154
|
+
const out = /* @__PURE__ */ new Set();
|
|
18155
|
+
for (const [repoRel, st] of Object.entries(changesStatuses)) {
|
|
18156
|
+
if (st.kind !== "ready") continue;
|
|
18157
|
+
for (const f of st.files) out.add(repoRel === "" ? f.path : repoRel + "/" + f.path);
|
|
18158
|
+
}
|
|
18159
|
+
return out;
|
|
18160
|
+
});
|
|
18161
|
+
/** Every ancestor directory of a changed path — a parent of a changed
|
|
18162
|
+
* file is highlighted exactly like a repo row (bold + #FF4500). */
|
|
18163
|
+
const changedDirs = derived(() => {
|
|
18164
|
+
const out = /* @__PURE__ */ new Set();
|
|
18165
|
+
for (const p of changedPaths()) {
|
|
18166
|
+
const parts = p.split("/");
|
|
18167
|
+
parts.pop();
|
|
18168
|
+
let cur = "";
|
|
18169
|
+
for (const part of parts) {
|
|
18170
|
+
cur = cur === "" ? part : cur + "/" + part;
|
|
18171
|
+
out.add(cur);
|
|
18172
|
+
}
|
|
18173
|
+
}
|
|
18174
|
+
return out;
|
|
18175
|
+
});
|
|
18176
|
+
let pulseSource = null;
|
|
18177
|
+
function closePulse() {
|
|
18178
|
+
pulseSource?.close();
|
|
18179
|
+
pulseSource = null;
|
|
18180
|
+
}
|
|
18181
|
+
onDestroy(closePulse);
|
|
18182
|
+
function startSplitDrag(event) {}
|
|
18183
|
+
const splitPct = derived(() => clampTreePct(treePct));
|
|
18184
|
+
$$renderer.push(`<div data-svelte="WorkspaceExplorerPanel" data-testid="workspace-explorer" class="split svelte-v4uero"${attr_style(`--tree-basis: ${stringify(splitPct())}%; --file-basis: ${stringify(100 - splitPct())}%`)}>`);
|
|
18185
|
+
WorkspaceExplorer($$renderer, {
|
|
18186
|
+
root,
|
|
18187
|
+
activeTab: activeTab(),
|
|
18188
|
+
levels,
|
|
18189
|
+
expanded,
|
|
18190
|
+
repoMaps,
|
|
18191
|
+
changedPaths: changedPaths(),
|
|
18192
|
+
changedDirs: changedDirs(),
|
|
18193
|
+
changesRepos: changesRepos(),
|
|
18194
|
+
changesStatuses,
|
|
18195
|
+
collapsedRepos});
|
|
18196
|
+
$$renderer.push(`<!----> `);
|
|
18197
|
+
ResizeGutter($$renderer, {
|
|
18198
|
+
index: 0,
|
|
18199
|
+
onDragStart: startSplitDrag
|
|
18200
|
+
});
|
|
18201
|
+
$$renderer.push(`<!----> `);
|
|
18202
|
+
WorkspaceFileTabs($$renderer, {
|
|
18203
|
+
tabs: openTabs.map((p) => ({ path: p })),
|
|
18204
|
+
activePath: activeFile,
|
|
18205
|
+
children: ($$renderer) => {
|
|
18206
|
+
if (activeFile !== null) {
|
|
18207
|
+
$$renderer.push("<!--[0-->");
|
|
18208
|
+
if (home !== void 0) {
|
|
18209
|
+
$$renderer.push("<!--[0-->");
|
|
18210
|
+
SettingsHomeFile($$renderer, {
|
|
18211
|
+
home,
|
|
18212
|
+
path: activeFile
|
|
18213
|
+
});
|
|
18214
|
+
} else if (sessionId !== null) {
|
|
18215
|
+
$$renderer.push("<!--[1-->");
|
|
18216
|
+
WorkspaceFilePanel($$renderer, {
|
|
18217
|
+
sessionId,
|
|
18218
|
+
path: activeFile,
|
|
18219
|
+
root,
|
|
18220
|
+
onclose: () => {}
|
|
18221
|
+
});
|
|
18222
|
+
} else $$renderer.push("<!--[-1-->");
|
|
18223
|
+
$$renderer.push(`<!--]-->`);
|
|
18224
|
+
} else $$renderer.push("<!--[-1-->");
|
|
18225
|
+
$$renderer.push(`<!--]-->`);
|
|
18226
|
+
}});
|
|
18227
|
+
$$renderer.push(`<!----></div>`);
|
|
18228
|
+
});
|
|
18229
|
+
}
|
|
18230
|
+
//#endregion
|
|
17723
18231
|
//#region src/lib/components/panels/PanelsZoom.svelte
|
|
17724
18232
|
function PanelsZoom($$renderer, $$props) {
|
|
17725
18233
|
$$renderer.component(($$renderer) => {
|
|
@@ -17971,197 +18479,6 @@ function EmptyFloor($$renderer, $$props) {
|
|
|
17971
18479
|
});
|
|
17972
18480
|
}
|
|
17973
18481
|
//#endregion
|
|
17974
|
-
//#region src/lib/utils/panel-prefs.ts
|
|
17975
|
-
/** localStorage base key — one JSON blob `{ panels, selectedPanelId, panelWidth, zoom }`.
|
|
17976
|
-
* A workspace profile (`?profile=…` on the URL) suffixes EVERY dsi-* key
|
|
17977
|
-
* (see storage-profile.ts): the default desk lives under `dsi-panels`,
|
|
17978
|
-
* profile `widi` under `dsi-panels_widi`. */
|
|
17979
|
-
var PANEL_PREFS_KEY = "dsi-panels";
|
|
17980
|
-
/**
|
|
17981
|
-
* The storage key for a workspace profile.
|
|
17982
|
-
* @param profile sanitized profile segment, or null/undefined for the
|
|
17983
|
-
* default desk (`dsi-panels`).
|
|
17984
|
-
*/
|
|
17985
|
-
function panelPrefsKey(profile) {
|
|
17986
|
-
return dsiKey(PANEL_PREFS_KEY, profile);
|
|
17987
|
-
}
|
|
17988
|
-
var PANEL_WORKSPACE_FILE_MAX_WIDTH = 1436;
|
|
17989
|
-
/**
|
|
17990
|
-
* The single panel-width bound site — load-side sanitizing, gutter drags,
|
|
17991
|
-
* and the width slider all route through here. Bounds read the config
|
|
17992
|
-
* store (layout load has landed them before any mount; defaults before).
|
|
17993
|
-
*/
|
|
17994
|
-
function clampPanelWidth(width, kind) {
|
|
17995
|
-
const { minWidth, maxWidth } = appConfig().panel;
|
|
17996
|
-
if (kind === "workspace-explorer") return Math.max(280, Math.min(maxWidth, width));
|
|
17997
|
-
if (kind === "workspace-file") return Math.max(850, Math.min(PANEL_WORKSPACE_FILE_MAX_WIDTH, width));
|
|
17998
|
-
return Math.max(minWidth, Math.min(maxWidth, width));
|
|
17999
|
-
}
|
|
18000
|
-
/** The single zoom bound site — load-side sanitizing and the zoom slider. */
|
|
18001
|
-
function clampPanelZoom(zoom) {
|
|
18002
|
-
const { minZoom, maxZoom } = appConfig().panel;
|
|
18003
|
-
return Math.max(minZoom, Math.min(maxZoom, zoom));
|
|
18004
|
-
}
|
|
18005
|
-
/** Config-driven default width (clamped through the single bound site). */
|
|
18006
|
-
function defaultPanelWidth() {
|
|
18007
|
-
return clampPanelWidth(appConfig().panel.defaultWidth);
|
|
18008
|
-
}
|
|
18009
|
-
/**
|
|
18010
|
-
* Clamp a stored explorer `expanded` list to sane paths (Workspace
|
|
18011
|
-
* Explorer restore): non-string members drop and a repeated path keeps
|
|
18012
|
-
* its FIRST occurrence — the tree treats `expanded` as a set of
|
|
18013
|
-
* root-relative directories, and a duplicate would double-render a row.
|
|
18014
|
-
*/
|
|
18015
|
-
function clampExpanded(value) {
|
|
18016
|
-
if (!Array.isArray(value)) return [];
|
|
18017
|
-
const seen = /* @__PURE__ */ new Set();
|
|
18018
|
-
const out = [];
|
|
18019
|
-
for (const member of value) {
|
|
18020
|
-
if (typeof member !== "string" || seen.has(member)) continue;
|
|
18021
|
-
seen.add(member);
|
|
18022
|
-
out.push(member);
|
|
18023
|
-
}
|
|
18024
|
-
return out;
|
|
18025
|
-
}
|
|
18026
|
-
/** Persisted defaults when nothing (usable) is stored. */
|
|
18027
|
-
function defaultPanelPrefs() {
|
|
18028
|
-
return {
|
|
18029
|
-
panels: [],
|
|
18030
|
-
selectedPanelId: null,
|
|
18031
|
-
panelWidth: defaultPanelWidth(),
|
|
18032
|
-
zoom: 1
|
|
18033
|
-
};
|
|
18034
|
-
}
|
|
18035
|
-
/**
|
|
18036
|
-
* Hard shape check for a stored panel entry (the parse boundary).
|
|
18037
|
-
* KIND (2026-09-06, ADR D6): absent or 'conversation' is the legacy shape —
|
|
18038
|
-
* `sessionId` required; 'prompt-manager' carries no session fields;
|
|
18039
|
-
* 'injected-doc' (Loadinjected ADR D2) requires non-empty `sourceSessionId`
|
|
18040
|
-
* + `displayPath` — the dedupe key. Any other kind value is hard junk
|
|
18041
|
-
* (entry drops). `agentPreset` and `width`
|
|
18042
|
-
* may be absent (defaulted later); `agentPreset` when present must be
|
|
18043
|
-
* string|null, `width` when present must be a finite number. Unknown
|
|
18044
|
-
* extra keys are fine — they survive sanitizing.
|
|
18045
|
-
*/
|
|
18046
|
-
function isPanelEntry(value) {
|
|
18047
|
-
if (value === null || typeof value !== "object") return false;
|
|
18048
|
-
const entry = value;
|
|
18049
|
-
if (typeof entry.id !== "string" || entry.id.length === 0) return false;
|
|
18050
|
-
if (entry.kind !== void 0 && entry.kind !== "conversation" && entry.kind !== "prompt-manager" && entry.kind !== "settings-editor" && entry.kind !== "injected-doc" && entry.kind !== "workspace-explorer" && entry.kind !== "workspace-file") return false;
|
|
18051
|
-
if (entry.kind === "settings-editor" && entry.target !== "dsi" && entry.target !== "dsh") return false;
|
|
18052
|
-
if (entry.kind === "workspace-explorer" || entry.kind === "workspace-file") {
|
|
18053
|
-
if (typeof entry.sessionId !== "string" || entry.sessionId.length === 0) return false;
|
|
18054
|
-
}
|
|
18055
|
-
if (entry.kind === "workspace-explorer" && typeof entry.root !== "string") return false;
|
|
18056
|
-
if (entry.kind === "workspace-file") {
|
|
18057
|
-
if (typeof entry.path !== "string" || entry.path.length === 0) return false;
|
|
18058
|
-
}
|
|
18059
|
-
if (entry.kind === "injected-doc") {
|
|
18060
|
-
if (typeof entry.sourceSessionId !== "string" || entry.sourceSessionId.length === 0) return false;
|
|
18061
|
-
if (typeof entry.displayPath !== "string" || entry.displayPath.length === 0) return false;
|
|
18062
|
-
}
|
|
18063
|
-
if (entry.kind !== "prompt-manager" && entry.kind !== "settings-editor" && entry.kind !== "injected-doc" && entry.kind !== "workspace-explorer" && entry.kind !== "workspace-file") {
|
|
18064
|
-
if (typeof entry.sessionId !== "string" || entry.sessionId.length === 0) return false;
|
|
18065
|
-
if (entry.agentPreset !== void 0 && typeof entry.agentPreset !== "string" && entry.agentPreset !== null) return false;
|
|
18066
|
-
}
|
|
18067
|
-
if (entry.width !== void 0 && (typeof entry.width !== "number" || !Number.isFinite(entry.width))) return false;
|
|
18068
|
-
return true;
|
|
18069
|
-
}
|
|
18070
|
-
/** Drop hard-junk entries; default missing keys; clamp widths. Unknown
|
|
18071
|
-
* keys on surviving entries pass through untouched.
|
|
18072
|
-
*
|
|
18073
|
-
* Duplicate ids (2026-08-24 crash fix): a corrupted blob carrying the
|
|
18074
|
-
* same panel-N twice would reach the keyed each in SidebarOpenPanels
|
|
18075
|
-
* and crash Svelte (each_key_duplicate) at render — the each's key is
|
|
18076
|
-
* the panel id. Duplicates drop to the FIRST occurrence (order is the
|
|
18077
|
-
* floor's left-to-right truth); a selectedPanelId left dangling by the
|
|
18078
|
-
* dedupe re-sanitizes to the first panel in loadPanelPrefs. */
|
|
18079
|
-
function sanitizePanels(raw) {
|
|
18080
|
-
if (!Array.isArray(raw)) return [];
|
|
18081
|
-
const seen = /* @__PURE__ */ new Set();
|
|
18082
|
-
return raw.filter((entry) => isPanelEntry(entry)).map((entry) => {
|
|
18083
|
-
const kindDefault = entry.kind === "workspace-explorer" ? 280 : entry.kind === "workspace-file" ? 860 : defaultPanelWidth();
|
|
18084
|
-
const width = clampPanelWidth(typeof entry.width === "number" && Number.isFinite(entry.width) ? entry.width : kindDefault, entry.kind);
|
|
18085
|
-
if (entry.kind === "prompt-manager") return {
|
|
18086
|
-
id: entry.id,
|
|
18087
|
-
kind: "prompt-manager",
|
|
18088
|
-
width
|
|
18089
|
-
};
|
|
18090
|
-
if (entry.kind === "settings-editor") return {
|
|
18091
|
-
id: entry.id,
|
|
18092
|
-
kind: "settings-editor",
|
|
18093
|
-
target: entry.target,
|
|
18094
|
-
width
|
|
18095
|
-
};
|
|
18096
|
-
if (entry.kind === "injected-doc") return {
|
|
18097
|
-
id: entry.id,
|
|
18098
|
-
kind: "injected-doc",
|
|
18099
|
-
sourceSessionId: entry.sourceSessionId,
|
|
18100
|
-
displayPath: entry.displayPath,
|
|
18101
|
-
width
|
|
18102
|
-
};
|
|
18103
|
-
if (entry.kind === "workspace-explorer") return {
|
|
18104
|
-
id: entry.id,
|
|
18105
|
-
kind: "workspace-explorer",
|
|
18106
|
-
sessionId: entry.sessionId,
|
|
18107
|
-
root: entry.root,
|
|
18108
|
-
expanded: clampExpanded(entry.expanded),
|
|
18109
|
-
tab: entry.tab === "changes" ? "changes" : "explorer",
|
|
18110
|
-
collapsedRepos: clampExpanded(entry.collapsedRepos),
|
|
18111
|
-
width
|
|
18112
|
-
};
|
|
18113
|
-
if (entry.kind === "workspace-file") return {
|
|
18114
|
-
id: entry.id,
|
|
18115
|
-
kind: "workspace-file",
|
|
18116
|
-
sessionId: entry.sessionId,
|
|
18117
|
-
path: entry.path,
|
|
18118
|
-
explorerPanelId: typeof entry.explorerPanelId === "string" && entry.explorerPanelId.length > 0 ? entry.explorerPanelId : null,
|
|
18119
|
-
view: entry.view === "diff" ? "diff" : "edit",
|
|
18120
|
-
width
|
|
18121
|
-
};
|
|
18122
|
-
return {
|
|
18123
|
-
...entry,
|
|
18124
|
-
id: entry.id,
|
|
18125
|
-
kind: "conversation",
|
|
18126
|
-
sessionId: entry.sessionId,
|
|
18127
|
-
agentPreset: entry.agentPreset ?? null,
|
|
18128
|
-
width
|
|
18129
|
-
};
|
|
18130
|
-
}).filter((entry) => {
|
|
18131
|
-
if (seen.has(entry.id)) return false;
|
|
18132
|
-
seen.add(entry.id);
|
|
18133
|
-
return true;
|
|
18134
|
-
});
|
|
18135
|
-
}
|
|
18136
|
-
/**
|
|
18137
|
-
* Read the workspace state from localStorage.
|
|
18138
|
-
* @param profile sanitized workspace profile (null/omitted = default desk).
|
|
18139
|
-
* @returns stored state when parseable (sanitized), defaults when absent,
|
|
18140
|
-
* junk, or SSR. A `selectedPanelId` pointing at a missing panel
|
|
18141
|
-
* sanitizes to the first panel's id (null when no panels remain).
|
|
18142
|
-
*/
|
|
18143
|
-
function loadPanelPrefs(profile) {
|
|
18144
|
-
if (typeof localStorage === "undefined") return defaultPanelPrefs();
|
|
18145
|
-
try {
|
|
18146
|
-
const raw = localStorage.getItem(panelPrefsKey(profile));
|
|
18147
|
-
if (!raw) return defaultPanelPrefs();
|
|
18148
|
-
const parsed = JSON.parse(raw);
|
|
18149
|
-
if (parsed === null || typeof parsed !== "object") return defaultPanelPrefs();
|
|
18150
|
-
if (!Array.isArray(parsed.panels)) return defaultPanelPrefs();
|
|
18151
|
-
const panels = sanitizePanels(parsed.panels);
|
|
18152
|
-
const panelWidth = typeof parsed.panelWidth === "number" && Number.isFinite(parsed.panelWidth) ? clampPanelWidth(parsed.panelWidth) : defaultPanelWidth();
|
|
18153
|
-
const zoom = typeof parsed.zoom === "number" && Number.isFinite(parsed.zoom) ? clampPanelZoom(parsed.zoom) : 1;
|
|
18154
|
-
return {
|
|
18155
|
-
panels,
|
|
18156
|
-
selectedPanelId: typeof parsed.selectedPanelId === "string" && panels.some((panel) => panel.id === parsed.selectedPanelId) ? parsed.selectedPanelId : panels[0]?.id ?? null,
|
|
18157
|
-
panelWidth,
|
|
18158
|
-
zoom
|
|
18159
|
-
};
|
|
18160
|
-
} catch {
|
|
18161
|
-
return defaultPanelPrefs();
|
|
18162
|
-
}
|
|
18163
|
-
}
|
|
18164
|
-
//#endregion
|
|
18165
18482
|
//#region src/lib/components/panels/control-bar/ControlBar.svelte
|
|
18166
18483
|
function ControlBar($$renderer, $$props) {
|
|
18167
18484
|
$$renderer.component(($$renderer) => {
|
|
@@ -18281,25 +18598,26 @@ function loadSidebarPrefs(profile) {
|
|
|
18281
18598
|
}
|
|
18282
18599
|
}
|
|
18283
18600
|
/**
|
|
18284
|
-
* The open workspace explorer for a
|
|
18285
|
-
* dedupe key: ONE explorer per
|
|
18286
|
-
*
|
|
18287
|
-
*
|
|
18601
|
+
* The open workspace explorer for a workspace ROOT — The Shared Tree ADR
|
|
18602
|
+
* (2026-09-17) D1's dedupe key: ONE explorer per ROOT across ALL sessions,
|
|
18603
|
+
* so a chip click on any session sharing the root FOCUSES instead of
|
|
18604
|
+
* adding (a duplicate is a bug, not a feature). The retired per-session
|
|
18605
|
+
* key ("two sessions sharing one workspace hold distinct explorers",
|
|
18606
|
+
* Workspace Explorer D4) produced N byte-identical trees for N sessions.
|
|
18288
18607
|
*/
|
|
18289
|
-
function findWorkspaceExplorerPanel(panels,
|
|
18290
|
-
return panels.find((p) => p.kind === "workspace-explorer" && p.
|
|
18608
|
+
function findWorkspaceExplorerPanel(panels, root) {
|
|
18609
|
+
return panels.find((p) => p.kind === "workspace-explorer" && p.root === root);
|
|
18291
18610
|
}
|
|
18292
18611
|
/**
|
|
18293
|
-
* The explorer's slot (
|
|
18294
|
-
*
|
|
18295
|
-
*
|
|
18296
|
-
*
|
|
18297
|
-
*
|
|
18298
|
-
*
|
|
18299
|
-
* conversation, so there is no source anchor to honor).
|
|
18612
|
+
* The explorer's slot (The Shared Tree ADR 2026-09-17, D3): the FOCUSED
|
|
18613
|
+
* slot — the explorer is NOT a lineage child; a workspace tree has no
|
|
18614
|
+
* parent session, only an opener. The retired after-source rule
|
|
18615
|
+
* (Workspace Explorer D3, "Parent → explorer → file") interposed the
|
|
18616
|
+
* panel inside a conversation's family unit — the family clamp inside
|
|
18617
|
+
* focusedInsertionSlot still keeps any real family unsplit.
|
|
18300
18618
|
*/
|
|
18301
|
-
function workspaceExplorerSlot(panels,
|
|
18302
|
-
return
|
|
18619
|
+
function workspaceExplorerSlot(panels, selectedIndex, facts) {
|
|
18620
|
+
return focusedInsertionSlot(panels, selectedIndex, facts.parentOf);
|
|
18303
18621
|
}
|
|
18304
18622
|
/**
|
|
18305
18623
|
* Insert-before-focused slot (operator spec, 2026-08-31): a fresh panel
|
|
@@ -18444,9 +18762,8 @@ function _page($$renderer, $$props) {
|
|
|
18444
18762
|
/** A workspace-explorer floor slot (Workspace Explorer W3 task 3.2,
|
|
18445
18763
|
* ADR D2/D4): the LIVE tree over the session's workspace root.
|
|
18446
18764
|
* expanded starts empty — F5 restore refills it from the blob.
|
|
18447
|
-
* Width = the
|
|
18448
|
-
*
|
|
18449
|
-
* space; the gutter drag grows it like any panel. */
|
|
18765
|
+
* Width = the WIDE file band, unconditionally (The Settings Tree
|
|
18766
|
+
* ADR 2026-09-18 D1: the explorer layout is the only layout). */
|
|
18450
18767
|
function makeWorkspaceExplorerPanel(sessionId, root) {
|
|
18451
18768
|
return {
|
|
18452
18769
|
id: nextPanelId(),
|
|
@@ -18454,20 +18771,43 @@ function _page($$renderer, $$props) {
|
|
|
18454
18771
|
sessionId,
|
|
18455
18772
|
root,
|
|
18456
18773
|
expanded: [],
|
|
18457
|
-
width: clampPanelWidth(
|
|
18774
|
+
width: clampPanelWidth(850, "workspace-explorer")
|
|
18458
18775
|
};
|
|
18459
18776
|
}
|
|
18460
|
-
/** Chip click action (
|
|
18461
|
-
*
|
|
18462
|
-
*
|
|
18463
|
-
*
|
|
18777
|
+
/** Chip click action (The Shared Tree ADR 2026-09-17, D2): ONE
|
|
18778
|
+
* explorer per WORKSPACE root across ALL sessions — a click on any
|
|
18779
|
+
* session sharing the root FOCUSES the open explorer (dedupe
|
|
18780
|
+
* key = root, D1); a fresh root lands at the focused slot (D3,
|
|
18781
|
+
* non-lineage — the explorer is not a lineage child). sessionId
|
|
18782
|
+
* stays in the signature (the chip supplies it) and rides the fresh
|
|
18783
|
+
* panel as PROVENANCE (D4), never as identity. */
|
|
18464
18784
|
function openWorkspaceExplorer(sessionId, workspace) {
|
|
18465
|
-
const open = findWorkspaceExplorerPanel(panels,
|
|
18785
|
+
const open = findWorkspaceExplorerPanel(panels, workspace);
|
|
18466
18786
|
if (open) {
|
|
18467
18787
|
selectedPanelId = open.id;
|
|
18468
18788
|
return;
|
|
18469
18789
|
}
|
|
18470
|
-
insertPanel(makeWorkspaceExplorerPanel(sessionId, workspace), workspaceExplorerSlot(panels,
|
|
18790
|
+
insertPanel(makeWorkspaceExplorerPanel(sessionId, workspace), workspaceExplorerSlot(panels, selectedIndex(), moveFacts()));
|
|
18791
|
+
}
|
|
18792
|
+
/** The open explorer for a session's workspace (The Shared Tree D1):
|
|
18793
|
+
* matched by ROOT across sessions — the panel's provenance sessionId
|
|
18794
|
+
* is not the key. */
|
|
18795
|
+
function sessionWorkspaceExplorer(sessionId) {
|
|
18796
|
+
const root = panelWorkspaceFor(sessionId);
|
|
18797
|
+
return root === null ? void 0 : findWorkspaceExplorerPanel(panels, root);
|
|
18798
|
+
}
|
|
18799
|
+
/** Explorer tree intents (Module Communication Map): the panel emits
|
|
18800
|
+
* toggle/open-file; the owner mutates expanded (the persisted part) —
|
|
18801
|
+
* the levels cache stays component-local. File open is W4's wiring. */
|
|
18802
|
+
function toggleExplorerPath(panelId, path) {
|
|
18803
|
+
const idx = panels.findIndex((p) => p.id === panelId);
|
|
18804
|
+
if (idx < 0 || panels[idx].kind !== "workspace-explorer") return;
|
|
18805
|
+
const explorer = panels[idx];
|
|
18806
|
+
const next = explorer.expanded.includes(path) ? explorer.expanded.filter((p) => p !== path) : [...explorer.expanded, path];
|
|
18807
|
+
panels = panels.with(idx, {
|
|
18808
|
+
...explorer,
|
|
18809
|
+
expanded: next
|
|
18810
|
+
});
|
|
18471
18811
|
}
|
|
18472
18812
|
/** Explorer collapse-all intent (Module Communication Map): the panel
|
|
18473
18813
|
* emits; the owner empties the expanded list (the persisted part) —
|
|
@@ -18480,6 +18820,79 @@ function _page($$renderer, $$props) {
|
|
|
18480
18820
|
expanded: []
|
|
18481
18821
|
});
|
|
18482
18822
|
}
|
|
18823
|
+
/** Git Eye tab intent (2026-09-12 operator request): the active tab is
|
|
18824
|
+
* PERSISTED on the entry — a hard reload restores it (supersedes the
|
|
18825
|
+
* ADR D5 remount-Explorer clause, amendment logged). */
|
|
18826
|
+
function setExplorerTab(panelId, tab) {
|
|
18827
|
+
const idx = panels.findIndex((p) => p.id === panelId);
|
|
18828
|
+
if (idx < 0 || panels[idx].kind !== "workspace-explorer") return;
|
|
18829
|
+
panels = panels.with(idx, {
|
|
18830
|
+
...panels[idx],
|
|
18831
|
+
tab
|
|
18832
|
+
});
|
|
18833
|
+
}
|
|
18834
|
+
/** Explorer Layout tabs (amendment 2026-09-16): the tab list and the
|
|
18835
|
+
* active tab are OWNER-PERSISTED entry facts — panel-prefs saves the
|
|
18836
|
+
* blob, so a hard reload restores the open tabs exactly like
|
|
18837
|
+
* expanded/tab/collapsedRepos. The file tabs die with the panel (D5). */
|
|
18838
|
+
function openExplorerTab(panelId, path) {
|
|
18839
|
+
const idx = panels.findIndex((p) => p.id === panelId);
|
|
18840
|
+
if (idx < 0 || panels[idx].kind !== "workspace-explorer") return;
|
|
18841
|
+
const ex = panels[idx];
|
|
18842
|
+
const tabs = ex.openTabs ?? [];
|
|
18843
|
+
const openTabs = tabs.includes(path) ? tabs : [...tabs, path];
|
|
18844
|
+
panels = panels.with(idx, {
|
|
18845
|
+
...ex,
|
|
18846
|
+
openTabs,
|
|
18847
|
+
activeFile: path
|
|
18848
|
+
});
|
|
18849
|
+
}
|
|
18850
|
+
function closeExplorerTab(panelId, path) {
|
|
18851
|
+
const idx = panels.findIndex((p) => p.id === panelId);
|
|
18852
|
+
if (idx < 0 || panels[idx].kind !== "workspace-explorer") return;
|
|
18853
|
+
const ex = panels[idx];
|
|
18854
|
+
const tabs = ex.openTabs ?? [];
|
|
18855
|
+
const closedAt = tabs.indexOf(path);
|
|
18856
|
+
if (closedAt === -1) return;
|
|
18857
|
+
const openTabs = tabs.filter((p) => p !== path);
|
|
18858
|
+
const activeFile = ex.activeFile === path ? openTabs.length === 0 ? null : openTabs[Math.max(0, closedAt - 1)] : ex.activeFile ?? null;
|
|
18859
|
+
panels = panels.with(idx, {
|
|
18860
|
+
...ex,
|
|
18861
|
+
openTabs,
|
|
18862
|
+
activeFile
|
|
18863
|
+
});
|
|
18864
|
+
}
|
|
18865
|
+
function activateExplorerTab(panelId, path) {
|
|
18866
|
+
const idx = panels.findIndex((p) => p.id === panelId);
|
|
18867
|
+
if (idx < 0 || panels[idx].kind !== "workspace-explorer") return;
|
|
18868
|
+
const ex = panels[idx];
|
|
18869
|
+
if (!(ex.openTabs ?? []).includes(path)) return;
|
|
18870
|
+
panels = panels.with(idx, {
|
|
18871
|
+
...ex,
|
|
18872
|
+
activeFile: path
|
|
18873
|
+
});
|
|
18874
|
+
}
|
|
18875
|
+
/** The Explorer Layout drag settle (ADR D4): one DESK fact on the
|
|
18876
|
+
* route — the split is desk state, persisted with the floor blob,
|
|
18877
|
+
* NOT per entry. The panel already clamped; clamp again at the
|
|
18878
|
+
* single bound site for defense in depth. */
|
|
18879
|
+
function setExplorerTreePct(_panelId, pct) {
|
|
18880
|
+
treePct = clampTreePct(pct);
|
|
18881
|
+
}
|
|
18882
|
+
/** Git Eye repo-collapse intent (2026-09-13): the collapsed repo set is
|
|
18883
|
+
* PERSISTED on the entry — a hard reload restores it (the explorer-tab
|
|
18884
|
+
* pattern). Default is EXPANDED: an absent/empty list collapses nothing. */
|
|
18885
|
+
function toggleExplorerRepo(panelId, repoRel) {
|
|
18886
|
+
const idx = panels.findIndex((p) => p.id === panelId);
|
|
18887
|
+
if (idx < 0 || panels[idx].kind !== "workspace-explorer") return;
|
|
18888
|
+
const explorer = panels[idx];
|
|
18889
|
+
const prev = explorer.collapsedRepos ?? [];
|
|
18890
|
+
const next = prev.includes(repoRel) ? prev.filter((r) => r !== repoRel) : [...prev, repoRel];
|
|
18891
|
+
panels = panels.with(idx, {
|
|
18892
|
+
...explorer,
|
|
18893
|
+
collapsedRepos: next
|
|
18894
|
+
});
|
|
18895
|
+
}
|
|
18483
18896
|
/** Git Eye collapse-all-repos intent (2026-09-13): on the Changes tab
|
|
18484
18897
|
* the toolbar's collapse-all collapses EVERY known repo — persisted
|
|
18485
18898
|
* like the single-repo toggle, so a hard reload restores it. */
|
|
@@ -18504,9 +18917,20 @@ function _page($$renderer, $$props) {
|
|
|
18504
18917
|
});
|
|
18505
18918
|
}
|
|
18506
18919
|
/** The file panel's root (the copy fallback): its explorer's root
|
|
18507
|
-
* when open
|
|
18920
|
+
* when open (Shared Tree D1 — root-keyed, any session's explorer),
|
|
18921
|
+
* else the session's workspace from the spine/cold rows. */
|
|
18508
18922
|
function filePanelRoot(sessionId) {
|
|
18509
|
-
return
|
|
18923
|
+
return sessionWorkspaceExplorer(sessionId)?.root ?? panelWorkspaceFor(sessionId) ?? "";
|
|
18924
|
+
}
|
|
18925
|
+
/** Tree file-click action (The Settings Tree ADR 2026-09-18 D1: the
|
|
18926
|
+
* explorer layout is the ONLY layout — the retired floor-file branch
|
|
18927
|
+
* of the 2026-09-17 ADR is gone). The intent publishes to the
|
|
18928
|
+
* session's explorer, which opens/focuses a tab. No open explorer
|
|
18929
|
+
* ⇒ the intent drops (the browsing surface that opens files IS the
|
|
18930
|
+
* explorer; the floor keeps conversations only). */
|
|
18931
|
+
function openWorkspaceFile(sessionId, path) {
|
|
18932
|
+
const host = sessionWorkspaceExplorer(sessionId);
|
|
18933
|
+
if (host) publishFileIntent(host.id, path);
|
|
18510
18934
|
}
|
|
18511
18935
|
const seedData = page.data;
|
|
18512
18936
|
const seedCold = seedData && typeof seedData.sessionId === "string" && Array.isArray(seedData.entries) ? {
|
|
@@ -18527,6 +18951,7 @@ function _page($$renderer, $$props) {
|
|
|
18527
18951
|
const initialPrefs = loadPanelPrefs(activeProfile);
|
|
18528
18952
|
let panelWidth = initialPrefs.panelWidth;
|
|
18529
18953
|
let zoom = clampPanelZoom(initialPrefs.zoom);
|
|
18954
|
+
let treePct = clampTreePct(initialPrefs.treePct);
|
|
18530
18955
|
let panels = seededInitially ? [makePanel(seedSessionId(), seedCold?.agentPreset ?? null)] : initialPrefs.panels;
|
|
18531
18956
|
syncPanelIdSeq(panels);
|
|
18532
18957
|
let selectedPanelId = seededInitially ? panels[0]?.id ?? null : initialPrefs.selectedPanelId;
|
|
@@ -18537,6 +18962,20 @@ function _page($$renderer, $$props) {
|
|
|
18537
18962
|
let loupePanelId = null;
|
|
18538
18963
|
/** Runtime cold-load results per sessionId (dual fetch results). */
|
|
18539
18964
|
let coldCache = {};
|
|
18965
|
+
let pendingFileIntents = {};
|
|
18966
|
+
let fileIntentSeq = 0;
|
|
18967
|
+
/** Publish a file intent to an explorer panel and focus it. */
|
|
18968
|
+
function publishFileIntent(explorerId, path) {
|
|
18969
|
+
pendingFileIntents[explorerId] = {
|
|
18970
|
+
path,
|
|
18971
|
+
nonce: ++fileIntentSeq
|
|
18972
|
+
};
|
|
18973
|
+
selectedPanelId = explorerId;
|
|
18974
|
+
}
|
|
18975
|
+
/** The panel consumed intent nonce N — clear exactly that publish. */
|
|
18976
|
+
function consumeFileIntent(explorerId, nonce) {
|
|
18977
|
+
if (pendingFileIntents[explorerId]?.nonce === nonce) pendingFileIntents[explorerId] = null;
|
|
18978
|
+
}
|
|
18540
18979
|
if (seededInitially && seedCold !== void 0 && seedData !== void 0) coldCache = {
|
|
18541
18980
|
...coldCache,
|
|
18542
18981
|
[seedData.sessionId]: seedCold
|
|
@@ -18601,7 +19040,7 @@ function _page($$renderer, $$props) {
|
|
|
18601
19040
|
if (opts.family !== false && root.kind === "workspace-explorer") {
|
|
18602
19041
|
for (const p of panels) if (p.kind === "workspace-file" && (p.explorerPanelId === root.id || p.explorerPanelId === null && p.sessionId === root.sessionId)) doomedPanelIds.add(p.id);
|
|
18603
19042
|
}
|
|
18604
|
-
panels = panels.filter((p) => p.id !== root.id && !doomedPanelIds.has(p.id) && (p.kind === "conversation" ? !doomed.has(p.sessionId) : !("sessionId" in p) || opts.family !== false && !doomed.has(p.sessionId)));
|
|
19043
|
+
panels = panels.filter((p) => p.id !== root.id && !doomedPanelIds.has(p.id) && (p.kind === "conversation" ? !doomed.has(p.sessionId) : !("sessionId" in p) || p.sessionId === null || opts.family !== false && !doomed.has(p.sessionId)));
|
|
18605
19044
|
if (selectedPanelId !== null && !panels.some((p) => p.id === selectedPanelId)) selectedPanelId = panels[Math.min(idx, panels.length - 1)]?.id ?? null;
|
|
18606
19045
|
clearLoupeIfGone();
|
|
18607
19046
|
}
|
|
@@ -18848,11 +19287,31 @@ function _page($$renderer, $$props) {
|
|
|
18848
19287
|
WorkspaceExplorerPanel($$renderer, {
|
|
18849
19288
|
sessionId: panel.sessionId,
|
|
18850
19289
|
root: panel.root,
|
|
19290
|
+
home: panel.home,
|
|
18851
19291
|
expanded: panel.expanded,
|
|
18852
19292
|
tab: panel.tab ?? "explorer",
|
|
19293
|
+
onToggle: (path) => toggleExplorerPath(panel.id, path),
|
|
19294
|
+
onOpenFile: (path) => {
|
|
19295
|
+
if (panel.home !== void 0) {
|
|
19296
|
+
openExplorerTab(panel.id, path);
|
|
19297
|
+
return;
|
|
19298
|
+
}
|
|
19299
|
+
if (panel.sessionId !== null) openWorkspaceFile(panel.sessionId, path);
|
|
19300
|
+
},
|
|
18853
19301
|
onCollapseAll: () => collapseExplorerPaths(panel.id),
|
|
19302
|
+
onTabChange: (tab) => setExplorerTab(panel.id, tab),
|
|
18854
19303
|
collapsedRepos: panel.collapsedRepos ?? [],
|
|
18855
|
-
|
|
19304
|
+
onToggleRepo: (repoRel) => toggleExplorerRepo(panel.id, repoRel),
|
|
19305
|
+
onCollapseAllRepos: (repos) => collapseExplorerRepos(panel.id, repos),
|
|
19306
|
+
treePct,
|
|
19307
|
+
onTreePctChange: (pct) => setExplorerTreePct(panel.id, pct),
|
|
19308
|
+
pendingOpenFile: pendingFileIntents[panel.id] ?? null,
|
|
19309
|
+
onPendingOpenConsumed: (nonce) => consumeFileIntent(panel.id, nonce),
|
|
19310
|
+
openTabs: panel.openTabs ?? [],
|
|
19311
|
+
activeFile: panel.activeFile ?? null,
|
|
19312
|
+
onOpenTab: (path) => openExplorerTab(panel.id, path),
|
|
19313
|
+
onCloseTab: (path) => closeExplorerTab(panel.id, path),
|
|
19314
|
+
onActivateTab: (path) => activateExplorerTab(panel.id, path)
|
|
18856
19315
|
});
|
|
18857
19316
|
} else if (panel.kind === "workspace-file") {
|
|
18858
19317
|
$$renderer.push("<!--[4-->");
|
|
@@ -18861,7 +19320,9 @@ function _page($$renderer, $$props) {
|
|
|
18861
19320
|
path: panel.path,
|
|
18862
19321
|
root: filePanelRoot(panel.sessionId),
|
|
18863
19322
|
view: panel.view ?? "edit",
|
|
18864
|
-
onviewchange: (v) => setFileView(panel.id, v)
|
|
19323
|
+
onviewchange: (v) => setFileView(panel.id, v),
|
|
19324
|
+
onclose: () => removePanel(panel.id)
|
|
19325
|
+
});
|
|
18865
19326
|
} else if (panel.kind === "conversation") {
|
|
18866
19327
|
$$renderer.push("<!--[5-->");
|
|
18867
19328
|
const p = panel;
|
|
@@ -19023,4 +19484,4 @@ function _page($$renderer, $$props) {
|
|
|
19023
19484
|
}
|
|
19024
19485
|
|
|
19025
19486
|
export { _page as default };
|
|
19026
|
-
//# sourceMappingURL=_page.svelte.js-
|
|
19487
|
+
//# sourceMappingURL=_page.svelte.js-BSt3-Adz.js.map
|