@dsh-electron/dsh-plugin-multi-root-workspace 0.1.4 → 0.1.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.en.md +19 -2
- package/CHANGELOG.md +19 -2
- package/README.en.md +17 -13
- package/README.md +16 -14
- package/cordis.patch.yml +4 -0
- package/lib/client.js +320 -18
- package/lib/client.js.map +1 -1
- package/lib/{command-DyOWujPo.js → command-CTdNvwt1.js} +107 -6
- package/lib/command.js +1 -1
- package/lib/{compat-PNEKXGa6.js → compat-B6ZqbQBy.js} +23 -3
- package/lib/compat.js +1 -1
- package/lib/index.js +5 -5
- package/lib/{instructions-Cn1Jj5Xi.js → instructions-DfzN-wVf.js} +106 -26
- package/lib/instructions.js +1 -1
- package/lib/lsp.js +38 -0
- package/lib/method-wrapper-Zc-JlDP3.js +51 -0
- package/lib/sandbox-BRXl_FpF.js +132 -0
- package/lib/sandbox.js +1 -1
- package/lib/scope.js +12 -6
- package/lib/session-directory-BLOstut1.js +9 -0
- package/lib/tool-context-CpgIFcCB.js +6 -0
- package/lib/types/client/RootFileTree.d.ts +12 -0
- package/lib/types/client/WorkspaceFoldersAction.d.ts +3 -0
- package/lib/types/client/index.d.ts +13 -2
- package/lib/types/client/locales.d.ts +14 -0
- package/lib/types/client/styles.d.ts +1 -1
- package/lib/types/compat/client-icons.d.ts +1 -1
- package/lib/types/compat/client-session.d.ts +2 -0
- package/lib/types/compat/dsh-version.d.ts +5 -3
- package/lib/types/compat/instruction-overlap.d.ts +7 -0
- package/lib/types/compat/session-directory.d.ts +4 -0
- package/lib/types/compat/tool-context.d.ts +9 -0
- package/lib/types/compat/tool-result.d.ts +1 -1
- package/lib/types/compat/workspace-files.d.ts +5 -0
- package/lib/types/contract.d.ts +24 -5
- package/lib/types/index.d.ts +2 -2
- package/lib/types/lsp.d.ts +4 -0
- package/lib/types/method-wrapper.d.ts +2 -0
- package/lib/types/panel-files.d.ts +3 -0
- package/lib/types/sandbox.d.ts +2 -11
- package/lib/types/scope.d.ts +3 -0
- package/lib/types/windows-profile.d.ts +13 -0
- package/lib/types/windows-runner.d.ts +1 -0
- package/lib/types/workspace-files.d.ts +4 -0
- package/lib/types/workspace-routing.d.ts +11 -0
- package/lib/{sandbox-D8Fw95FM.js → windows-profile-CiFsFYIV.js} +64 -138
- package/lib/windows-runner.js +68 -0
- package/lib/workspace-files.js +68 -0
- package/package.json +90 -47
package/lib/client.js
CHANGED
|
@@ -44,6 +44,12 @@ window.__ModuleLoader__.load({
|
|
|
44
44
|
if (typeof current === "string" && current !== "") return current;
|
|
45
45
|
return mainViewSessionId(snapshot.byId);
|
|
46
46
|
}
|
|
47
|
+
/** Observe native catalog changes when this surface provides a subscribable store. */
|
|
48
|
+
function subscribeSessions(sessions, listener) {
|
|
49
|
+
if (sessions === null || typeof sessions !== "object") return () => {};
|
|
50
|
+
const list = sessions.list;
|
|
51
|
+
return typeof list?.subscribe === "function" ? list.subscribe(listener) : () => {};
|
|
52
|
+
}
|
|
47
53
|
/**
|
|
48
54
|
* The list snapshot, when the service actually exposes one.
|
|
49
55
|
*
|
|
@@ -1111,6 +1117,7 @@ window.__ModuleLoader__.load({
|
|
|
1111
1117
|
}
|
|
1112
1118
|
const anyString = /^[\s\S]{0,}$/;
|
|
1113
1119
|
const number$1 = /^-?\d+(?:\.\d+)?$/;
|
|
1120
|
+
const boolean$1 = /^(?:true|false)$/i;
|
|
1114
1121
|
const lowercase = /^[^A-Z]*$/;
|
|
1115
1122
|
const uppercase = /^[^a-z]*$/;
|
|
1116
1123
|
//#endregion
|
|
@@ -1898,6 +1905,24 @@ window.__ModuleLoader__.load({
|
|
|
1898
1905
|
$ZodCheckNumberFormat.init(inst, def);
|
|
1899
1906
|
$ZodNumber.init(inst, def);
|
|
1900
1907
|
});
|
|
1908
|
+
const $ZodBoolean = /*@__PURE__*/ $constructor("$ZodBoolean", (inst, def) => {
|
|
1909
|
+
$ZodType.init(inst, def);
|
|
1910
|
+
inst._zod.pattern = boolean$1;
|
|
1911
|
+
inst._zod.parse = (payload, _ctx) => {
|
|
1912
|
+
if (def.coerce) try {
|
|
1913
|
+
payload.value = Boolean(payload.value);
|
|
1914
|
+
} catch (_) {}
|
|
1915
|
+
const input = payload.value;
|
|
1916
|
+
if (typeof input === "boolean") return payload;
|
|
1917
|
+
payload.issues.push({
|
|
1918
|
+
expected: "boolean",
|
|
1919
|
+
code: "invalid_type",
|
|
1920
|
+
input,
|
|
1921
|
+
inst
|
|
1922
|
+
});
|
|
1923
|
+
return payload;
|
|
1924
|
+
};
|
|
1925
|
+
});
|
|
1901
1926
|
const $ZodUnknown = /*@__PURE__*/ $constructor("$ZodUnknown", (inst, def) => {
|
|
1902
1927
|
$ZodType.init(inst, def);
|
|
1903
1928
|
inst._zod.parse = (payload) => payload;
|
|
@@ -3340,6 +3365,13 @@ window.__ModuleLoader__.load({
|
|
|
3340
3365
|
});
|
|
3341
3366
|
}
|
|
3342
3367
|
// @__NO_SIDE_EFFECTS__
|
|
3368
|
+
function _boolean(Class, params) {
|
|
3369
|
+
return new Class({
|
|
3370
|
+
type: "boolean",
|
|
3371
|
+
...normalizeParams(params)
|
|
3372
|
+
});
|
|
3373
|
+
}
|
|
3374
|
+
// @__NO_SIDE_EFFECTS__
|
|
3343
3375
|
function _unknown(Class) {
|
|
3344
3376
|
return new Class({ type: "unknown" });
|
|
3345
3377
|
}
|
|
@@ -4118,6 +4150,9 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
4118
4150
|
if (rest.length) json.allOf = [...json.allOf ?? [], ...rest.map((m) => ({ multipleOf: m }))];
|
|
4119
4151
|
}
|
|
4120
4152
|
};
|
|
4153
|
+
const booleanProcessor = (_schema, _ctx, json, _params) => {
|
|
4154
|
+
json.type = "boolean";
|
|
4155
|
+
};
|
|
4121
4156
|
const neverProcessor = (_schema, _ctx, json, _params) => {
|
|
4122
4157
|
json.not = {};
|
|
4123
4158
|
};
|
|
@@ -4865,6 +4900,14 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
4865
4900
|
function int(params) {
|
|
4866
4901
|
return /* @__PURE__ */ _int(ZodNumberFormat, params);
|
|
4867
4902
|
}
|
|
4903
|
+
const ZodBoolean = /*@__PURE__*/ $constructor("ZodBoolean", (inst, def) => {
|
|
4904
|
+
$ZodBoolean.init(inst, def);
|
|
4905
|
+
ZodType.init(inst, def);
|
|
4906
|
+
inst._zod.processJSONSchema = (ctx, json, params) => booleanProcessor(inst, ctx, json, params);
|
|
4907
|
+
});
|
|
4908
|
+
function boolean(params) {
|
|
4909
|
+
return /* @__PURE__ */ _boolean(ZodBoolean, params);
|
|
4910
|
+
}
|
|
4868
4911
|
const ZodUnknown = /*@__PURE__*/ $constructor("ZodUnknown", (inst, def) => {
|
|
4869
4912
|
$ZodUnknown.init(inst, def);
|
|
4870
4913
|
ZodType.init(inst, def);
|
|
@@ -5208,8 +5251,9 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
5208
5251
|
* - **One shape per endpoint.** {@link PanelResponseMap} is the single mapping
|
|
5209
5252
|
* from endpoint to response type, so the panel cannot silently decode one
|
|
5210
5253
|
* endpoint's answer as another's. `reveal` answers with
|
|
5211
|
-
* {@link RevealedView};
|
|
5212
|
-
* {@link RootsView}
|
|
5254
|
+
* {@link RevealedView}; root-management endpoints answer with
|
|
5255
|
+
* {@link RootsView}, and browsing returns {@link FilesView} or {@link FilePreview}.
|
|
5256
|
+
* The host builds those answers in `command.ts` and the
|
|
5213
5257
|
* panel parses them here — one definition, two consumers.
|
|
5214
5258
|
* - **Runtime validation at the boundary.** The payload arrives from a browser
|
|
5215
5259
|
* and the answer arrives from the host; neither is trusted to match the
|
|
@@ -5266,10 +5310,47 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
5266
5310
|
const rootsViewSchema = object({
|
|
5267
5311
|
primaryRoot: string(),
|
|
5268
5312
|
primaryName: string().optional(),
|
|
5313
|
+
effectiveCwd: string().optional(),
|
|
5269
5314
|
roots: array(rootViewSchema),
|
|
5270
5315
|
unavailable: string().optional()
|
|
5271
5316
|
});
|
|
5272
5317
|
const revealedViewSchema = object({ revealed: string() });
|
|
5318
|
+
const filesViewSchema = object({
|
|
5319
|
+
path: string(),
|
|
5320
|
+
entries: array(object({
|
|
5321
|
+
name: string().min(1).refine((name) => name !== "." && name !== ".." && !/[\\/]/.test(name) && !name.includes(String.fromCharCode(0))),
|
|
5322
|
+
type: _enum([
|
|
5323
|
+
"file",
|
|
5324
|
+
"directory",
|
|
5325
|
+
"other"
|
|
5326
|
+
])
|
|
5327
|
+
})),
|
|
5328
|
+
truncated: boolean()
|
|
5329
|
+
});
|
|
5330
|
+
const filePreviewSchema = object({
|
|
5331
|
+
text: string(),
|
|
5332
|
+
eof: boolean()
|
|
5333
|
+
});
|
|
5334
|
+
function parseFilesView(value) {
|
|
5335
|
+
const parsed = filesViewSchema.safeParse(value);
|
|
5336
|
+
return parsed.success ? {
|
|
5337
|
+
ok: true,
|
|
5338
|
+
value: parsed.data
|
|
5339
|
+
} : {
|
|
5340
|
+
ok: false,
|
|
5341
|
+
message: firstIssue(parsed.error)
|
|
5342
|
+
};
|
|
5343
|
+
}
|
|
5344
|
+
function parseFilePreview(value) {
|
|
5345
|
+
const parsed = filePreviewSchema.safeParse(value);
|
|
5346
|
+
return parsed.success ? {
|
|
5347
|
+
ok: true,
|
|
5348
|
+
value: parsed.data
|
|
5349
|
+
} : {
|
|
5350
|
+
ok: false,
|
|
5351
|
+
message: firstIssue(parsed.error)
|
|
5352
|
+
};
|
|
5353
|
+
}
|
|
5273
5354
|
const errorViewSchema = object({
|
|
5274
5355
|
code: string(),
|
|
5275
5356
|
message: string(),
|
|
@@ -5292,6 +5373,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
5292
5373
|
value: {
|
|
5293
5374
|
primaryRoot: view.primaryRoot,
|
|
5294
5375
|
...view.primaryName === void 0 ? {} : { primaryName: view.primaryName },
|
|
5376
|
+
...view.effectiveCwd === void 0 ? {} : { effectiveCwd: view.effectiveCwd },
|
|
5295
5377
|
roots: view.roots.map(narrowRootView),
|
|
5296
5378
|
...view.unavailable === void 0 ? {} : { unavailable: view.unavailable }
|
|
5297
5379
|
}
|
|
@@ -5360,15 +5442,22 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
5360
5442
|
const NS = "multiRootWorkspace";
|
|
5361
5443
|
/** Chinese copy (the canonical shape). */
|
|
5362
5444
|
const zh = {
|
|
5445
|
+
"files.browse": "浏览文件",
|
|
5446
|
+
"files.reload": "刷新文件树",
|
|
5447
|
+
"files.empty": "目录为空",
|
|
5448
|
+
"files.truncated": "条目过多,列表已截断",
|
|
5449
|
+
"files.previewTruncated": "仅显示前 200 行",
|
|
5363
5450
|
"action.label": "工作区目录",
|
|
5364
5451
|
"action.title": "管理本会话的附属工作目录",
|
|
5365
5452
|
"panel.title": "工作区目录",
|
|
5366
5453
|
"panel.subtitle": "主目录和附加目录遵循当前沙箱模式;workspace-write 可写,read-only 下都不可写。",
|
|
5367
|
-
"panel.primary": "
|
|
5368
|
-
"panel.primaryNote": "
|
|
5454
|
+
"panel.primary": "主根",
|
|
5455
|
+
"panel.primaryNote": "会话原始项目,不可移除",
|
|
5456
|
+
"panel.cwd": "当前执行目录",
|
|
5457
|
+
"panel.cwdNote": "切换目录不会增加授权",
|
|
5369
5458
|
"panel.additional": "附属工作目录",
|
|
5370
5459
|
"panel.empty": "还没有附属工作目录。",
|
|
5371
|
-
"panel.emptyHint": "添加后,Agent
|
|
5460
|
+
"panel.emptyHint": "添加后,Agent 可在同一会话中读写该目录,受限 shell 和终端同步生效。",
|
|
5372
5461
|
"panel.noSession": "当前没有活动会话",
|
|
5373
5462
|
"panel.loading": "正在读取…",
|
|
5374
5463
|
"panel.retry": "重试",
|
|
@@ -5412,15 +5501,22 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
5412
5501
|
};
|
|
5413
5502
|
/** English copy, pinned to the Chinese key set. */
|
|
5414
5503
|
const en = {
|
|
5504
|
+
"files.browse": "Browse files",
|
|
5505
|
+
"files.reload": "Refresh files",
|
|
5506
|
+
"files.empty": "Empty directory",
|
|
5507
|
+
"files.truncated": "More entries were omitted",
|
|
5508
|
+
"files.previewTruncated": "Showing the first 200 lines",
|
|
5415
5509
|
"action.label": "Folders",
|
|
5416
5510
|
"action.title": "Manage this session's secondary working directories",
|
|
5417
5511
|
"panel.title": "Workspace folders",
|
|
5418
5512
|
"panel.subtitle": "The primary and additional folders follow the current sandbox mode: writable in workspace-write and read-only in read-only.",
|
|
5419
|
-
"panel.primary": "Primary
|
|
5420
|
-
"panel.primaryNote": "
|
|
5513
|
+
"panel.primary": "Primary root",
|
|
5514
|
+
"panel.primaryNote": "The session's original project; it cannot be removed",
|
|
5515
|
+
"panel.cwd": "Current working directory",
|
|
5516
|
+
"panel.cwdNote": "Changing directory does not grant access",
|
|
5421
5517
|
"panel.additional": "Secondary working directories",
|
|
5422
5518
|
"panel.empty": "No secondary working directories yet.",
|
|
5423
|
-
"panel.emptyHint": "Once added, the agent can use the folder in this session
|
|
5519
|
+
"panel.emptyHint": "Once added, the agent can use the folder in this session, including confined shells and terminals.",
|
|
5424
5520
|
"panel.noSession": "No active session",
|
|
5425
5521
|
"panel.loading": "Loading…",
|
|
5426
5522
|
"panel.retry": "Retry",
|
|
@@ -5517,7 +5613,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
5517
5613
|
* @throws {PanelError} `panel/bad-response` when the value is not that shape.
|
|
5518
5614
|
*/
|
|
5519
5615
|
function expectShape(endpoint, value) {
|
|
5520
|
-
const parsed = endpoint === "reveal" ? parseRevealedView(value) : parseRootsView(value);
|
|
5616
|
+
const parsed = endpoint === "reveal" ? parseRevealedView(value) : endpoint === "files" ? parseFilesView(value) : endpoint === "readFile" ? parseFilePreview(value) : parseRootsView(value);
|
|
5521
5617
|
if (!parsed.ok) throw new PanelError("panel/bad-response", parsed.message);
|
|
5522
5618
|
return parsed.value;
|
|
5523
5619
|
}
|
|
@@ -5893,6 +5989,11 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
5893
5989
|
border-radius: 16px;
|
|
5894
5990
|
}
|
|
5895
5991
|
|
|
5992
|
+
.mrfw-fileTree { flex-basis: 100%; min-width: 0; }
|
|
5993
|
+
.mrfw-fileLevel { list-style: none; padding-left: 16px; margin: 4px 0; }
|
|
5994
|
+
.mrfw-fileEntry { display: block; border: 0; background: transparent; color: var(--dsw-alias-label-primary); font: inherit; text-align: left; cursor: pointer; padding: 4px; overflow-wrap: anywhere; }
|
|
5995
|
+
.mrfw-fileEntry:focus-visible { outline: 1px solid var(--dsw-alias-brand-primary); }
|
|
5996
|
+
.mrfw-filePreview { max-height: 320px; overflow: auto; padding: 8px; background: var(--dsw-alias-bg-layer-1); color: var(--dsw-alias-label-primary); font-size: 12px; }
|
|
5896
5997
|
.mrfw-actions .mrfw-iconBtn {
|
|
5897
5998
|
width: 32px;
|
|
5898
5999
|
}
|
|
@@ -5935,6 +6036,149 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
5935
6036
|
const IconPlus = icon("IconPlusOutline16", "IconPlusOutlineRegular");
|
|
5936
6037
|
const IconTrash = icon("IconTrashOutline16", "IconTrashOutlineRegular");
|
|
5937
6038
|
//#endregion
|
|
6039
|
+
//#region src/client/RootFileTree.tsx
|
|
6040
|
+
/** Lazy additional-root tree and bounded text previews; requests carry a session and exact root. */
|
|
6041
|
+
function RootFileTree(props) {
|
|
6042
|
+
const [open, setOpen] = (0, react.useState)(false);
|
|
6043
|
+
const [generation, setGeneration] = (0, react.useState)(0);
|
|
6044
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
6045
|
+
className: "mrfw-fileTree",
|
|
6046
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
6047
|
+
className: "mrfw-btn mrfw-btnGhost",
|
|
6048
|
+
type: "button",
|
|
6049
|
+
"aria-expanded": open,
|
|
6050
|
+
onClick: () => {
|
|
6051
|
+
setOpen((value) => !value);
|
|
6052
|
+
},
|
|
6053
|
+
children: props.t("files.browse")
|
|
6054
|
+
}), open && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
6055
|
+
className: "mrfw-btn mrfw-btnGhost",
|
|
6056
|
+
type: "button",
|
|
6057
|
+
onClick: () => {
|
|
6058
|
+
setGeneration((value) => value + 1);
|
|
6059
|
+
},
|
|
6060
|
+
children: props.t("files.reload")
|
|
6061
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Directory, {
|
|
6062
|
+
...props,
|
|
6063
|
+
path: "."
|
|
6064
|
+
}, generation)] })]
|
|
6065
|
+
});
|
|
6066
|
+
}
|
|
6067
|
+
function Directory(props) {
|
|
6068
|
+
const [listing, setListing] = (0, react.useState)();
|
|
6069
|
+
const [error, setError] = (0, react.useState)();
|
|
6070
|
+
(0, react.useEffect)(() => {
|
|
6071
|
+
let active = true;
|
|
6072
|
+
setListing(void 0);
|
|
6073
|
+
setError(void 0);
|
|
6074
|
+
const session = props.sessionId();
|
|
6075
|
+
if (session === void 0) {
|
|
6076
|
+
setError(props.t("panel.noSession"));
|
|
6077
|
+
return;
|
|
6078
|
+
}
|
|
6079
|
+
props.panel.call("files", {
|
|
6080
|
+
sessionId: session,
|
|
6081
|
+
entry: props.entry,
|
|
6082
|
+
path: props.path
|
|
6083
|
+
}).then((value) => {
|
|
6084
|
+
if (active && props.sessionId() === session) setListing(value);
|
|
6085
|
+
}, (failure) => {
|
|
6086
|
+
if (active) setError(failure instanceof Error ? failure.message : String(failure));
|
|
6087
|
+
});
|
|
6088
|
+
return () => {
|
|
6089
|
+
active = false;
|
|
6090
|
+
};
|
|
6091
|
+
}, [
|
|
6092
|
+
props.panel,
|
|
6093
|
+
props.entry,
|
|
6094
|
+
props.path,
|
|
6095
|
+
props.sessionId,
|
|
6096
|
+
props.t
|
|
6097
|
+
]);
|
|
6098
|
+
if (error !== void 0) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
6099
|
+
className: "mrfw-alert",
|
|
6100
|
+
role: "alert",
|
|
6101
|
+
children: error
|
|
6102
|
+
});
|
|
6103
|
+
if (listing === void 0) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
6104
|
+
className: "mrfw-note",
|
|
6105
|
+
children: props.t("panel.loading")
|
|
6106
|
+
});
|
|
6107
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("ul", {
|
|
6108
|
+
className: "mrfw-fileLevel",
|
|
6109
|
+
children: [
|
|
6110
|
+
listing.entries.length === 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("li", {
|
|
6111
|
+
className: "mrfw-note",
|
|
6112
|
+
children: props.t("files.empty")
|
|
6113
|
+
}),
|
|
6114
|
+
[...listing.entries].sort((a, b) => Number(b.type === "directory") - Number(a.type === "directory") || a.name.localeCompare(b.name, void 0, { numeric: true })).map((entry) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(FileEntry, {
|
|
6115
|
+
...props,
|
|
6116
|
+
path: props.path === "." ? entry.name : `${props.path}/${entry.name}`,
|
|
6117
|
+
name: entry.name,
|
|
6118
|
+
kind: entry.type
|
|
6119
|
+
}, entry.name)),
|
|
6120
|
+
listing.truncated && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("li", {
|
|
6121
|
+
className: "mrfw-note",
|
|
6122
|
+
children: props.t("files.truncated")
|
|
6123
|
+
})
|
|
6124
|
+
]
|
|
6125
|
+
});
|
|
6126
|
+
}
|
|
6127
|
+
function FileEntry(props) {
|
|
6128
|
+
const [open, setOpen] = (0, react.useState)(false);
|
|
6129
|
+
const [preview, setPreview] = (0, react.useState)();
|
|
6130
|
+
const [error, setError] = (0, react.useState)();
|
|
6131
|
+
const epoch = (0, react.useRef)(0);
|
|
6132
|
+
(0, react.useEffect)(() => () => {
|
|
6133
|
+
epoch.current += 1;
|
|
6134
|
+
}, []);
|
|
6135
|
+
const toggle = async () => {
|
|
6136
|
+
setOpen(!open);
|
|
6137
|
+
const current = ++epoch.current;
|
|
6138
|
+
if (open || props.kind !== "file") return;
|
|
6139
|
+
setPreview(void 0);
|
|
6140
|
+
setError(void 0);
|
|
6141
|
+
const session = props.sessionId();
|
|
6142
|
+
if (session === void 0) {
|
|
6143
|
+
setError(props.t("panel.noSession"));
|
|
6144
|
+
return;
|
|
6145
|
+
}
|
|
6146
|
+
try {
|
|
6147
|
+
const value = await props.panel.call("readFile", {
|
|
6148
|
+
sessionId: session,
|
|
6149
|
+
entry: props.entry,
|
|
6150
|
+
path: props.path
|
|
6151
|
+
});
|
|
6152
|
+
if (current === epoch.current && props.sessionId() === session) setPreview(value);
|
|
6153
|
+
} catch (failure) {
|
|
6154
|
+
if (current === epoch.current) setError(failure instanceof Error ? failure.message : String(failure));
|
|
6155
|
+
}
|
|
6156
|
+
};
|
|
6157
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("li", { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
|
|
6158
|
+
className: "mrfw-fileEntry",
|
|
6159
|
+
type: "button",
|
|
6160
|
+
disabled: props.kind === "other",
|
|
6161
|
+
"aria-expanded": open,
|
|
6162
|
+
onClick: () => {
|
|
6163
|
+
toggle();
|
|
6164
|
+
},
|
|
6165
|
+
children: [props.kind === "directory" ? open ? "▾ " : "▸ " : "", props.name]
|
|
6166
|
+
}), open && (props.kind === "directory" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Directory, { ...props }) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_jsx_runtime.Fragment, { children: error !== void 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
6167
|
+
role: "alert",
|
|
6168
|
+
className: "mrfw-alert",
|
|
6169
|
+
children: error
|
|
6170
|
+
}) : preview === void 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
6171
|
+
className: "mrfw-note",
|
|
6172
|
+
children: props.t("panel.loading")
|
|
6173
|
+
}) : /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("pre", {
|
|
6174
|
+
className: "mrfw-filePreview",
|
|
6175
|
+
children: preview.text
|
|
6176
|
+
}), !preview.eof && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
6177
|
+
className: "mrfw-note",
|
|
6178
|
+
children: props.t("files.previewTruncated")
|
|
6179
|
+
})] }) }))] });
|
|
6180
|
+
}
|
|
6181
|
+
//#endregion
|
|
5938
6182
|
//#region src/client/WorkspaceFoldersAction.tsx
|
|
5939
6183
|
/**
|
|
5940
6184
|
* The Workspace Folders panel: one sidebar footer action that opens a dialog
|
|
@@ -6029,10 +6273,10 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
6029
6273
|
const [open, setOpen] = (0, react.useState)(false);
|
|
6030
6274
|
const rail = props.wide === false;
|
|
6031
6275
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
6032
|
-
className: rail ? "mrfw-triggerRow mrfw-railRow" : "mrfw-triggerRow",
|
|
6276
|
+
className: props.compact ? "mrfw-fileLauncher" : rail ? "mrfw-triggerRow mrfw-railRow" : "mrfw-triggerRow",
|
|
6033
6277
|
children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
|
|
6034
6278
|
type: "button",
|
|
6035
|
-
className: rail ? "mrfw-trigger mrfw-triggerRail" : "mrfw-trigger",
|
|
6279
|
+
className: props.compact ? "mrfw-btn mrfw-btnGhost" : rail ? "mrfw-trigger mrfw-triggerRail" : "mrfw-trigger",
|
|
6036
6280
|
title: props.t("action.title"),
|
|
6037
6281
|
"aria-haspopup": "dialog",
|
|
6038
6282
|
"aria-expanded": open,
|
|
@@ -6156,7 +6400,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
6156
6400
|
}));
|
|
6157
6401
|
try {
|
|
6158
6402
|
const view = await panel.call("list", base);
|
|
6159
|
-
if (!mounted.current || epoch !== requestEpoch.current) return;
|
|
6403
|
+
if (!mounted.current || epoch !== requestEpoch.current || props.sessionId?.() !== base.sessionId) return;
|
|
6160
6404
|
setState({
|
|
6161
6405
|
view,
|
|
6162
6406
|
error: void 0,
|
|
@@ -6164,7 +6408,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
6164
6408
|
noSession: false
|
|
6165
6409
|
});
|
|
6166
6410
|
} catch (error) {
|
|
6167
|
-
if (!mounted.current || epoch !== requestEpoch.current) return;
|
|
6411
|
+
if (!mounted.current || epoch !== requestEpoch.current || props.sessionId?.() !== base.sessionId) return;
|
|
6168
6412
|
setState({
|
|
6169
6413
|
view: void 0,
|
|
6170
6414
|
error: asPanelError(error),
|
|
@@ -6176,6 +6420,28 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
6176
6420
|
(0, react.useEffect)(() => {
|
|
6177
6421
|
refresh();
|
|
6178
6422
|
}, [refresh]);
|
|
6423
|
+
(0, react.useEffect)(() => {
|
|
6424
|
+
let previous = props.sessionId?.();
|
|
6425
|
+
return props.subscribeSession?.(() => {
|
|
6426
|
+
const current = props.sessionId?.();
|
|
6427
|
+
if (current === previous) return;
|
|
6428
|
+
previous = current;
|
|
6429
|
+
requestEpoch.current += 1;
|
|
6430
|
+
setState({
|
|
6431
|
+
view: void 0,
|
|
6432
|
+
error: void 0,
|
|
6433
|
+
busy: false,
|
|
6434
|
+
noSession: current === void 0
|
|
6435
|
+
});
|
|
6436
|
+
setMenuFor(void 0);
|
|
6437
|
+
setAliasFor(void 0);
|
|
6438
|
+
refresh();
|
|
6439
|
+
});
|
|
6440
|
+
}, [
|
|
6441
|
+
props.subscribeSession,
|
|
6442
|
+
props.sessionId,
|
|
6443
|
+
refresh
|
|
6444
|
+
]);
|
|
6179
6445
|
/**
|
|
6180
6446
|
* Submit one change to the host and adopt the view it answers with.
|
|
6181
6447
|
* @returns whether the host accepted it (the caller decides whether to clear
|
|
@@ -6204,7 +6470,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
6204
6470
|
...base,
|
|
6205
6471
|
...payload
|
|
6206
6472
|
});
|
|
6207
|
-
if (!mounted.current || epoch !== requestEpoch.current) return false;
|
|
6473
|
+
if (!mounted.current || epoch !== requestEpoch.current || props.sessionId?.() !== base.sessionId) return false;
|
|
6208
6474
|
setState({
|
|
6209
6475
|
view,
|
|
6210
6476
|
error: void 0,
|
|
@@ -6213,7 +6479,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
6213
6479
|
});
|
|
6214
6480
|
return true;
|
|
6215
6481
|
} catch (error) {
|
|
6216
|
-
if (!mounted.current || epoch !== requestEpoch.current) return false;
|
|
6482
|
+
if (!mounted.current || epoch !== requestEpoch.current || props.sessionId?.() !== base.sessionId) return false;
|
|
6217
6483
|
setState((previous) => ({
|
|
6218
6484
|
...previous,
|
|
6219
6485
|
error: asPanelError(error),
|
|
@@ -6277,14 +6543,14 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
6277
6543
|
...base,
|
|
6278
6544
|
entry: entryOf(root)
|
|
6279
6545
|
});
|
|
6280
|
-
if (!mounted.current || epoch !== requestEpoch.current) return;
|
|
6546
|
+
if (!mounted.current || epoch !== requestEpoch.current || props.sessionId?.() !== base.sessionId) return;
|
|
6281
6547
|
setState((previous) => ({
|
|
6282
6548
|
...previous,
|
|
6283
6549
|
error: void 0,
|
|
6284
6550
|
busy: false
|
|
6285
6551
|
}));
|
|
6286
6552
|
} catch (error) {
|
|
6287
|
-
if (!mounted.current || epoch !== requestEpoch.current) return;
|
|
6553
|
+
if (!mounted.current || epoch !== requestEpoch.current || props.sessionId?.() !== base.sessionId) return;
|
|
6288
6554
|
setState((previous) => ({
|
|
6289
6555
|
...previous,
|
|
6290
6556
|
error: asPanelError(error),
|
|
@@ -6394,6 +6660,22 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
6394
6660
|
})
|
|
6395
6661
|
})]
|
|
6396
6662
|
}),
|
|
6663
|
+
state.view?.effectiveCwd !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
|
|
6664
|
+
className: "mrfw-section",
|
|
6665
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
6666
|
+
className: "mrfw-sectionTitleRow",
|
|
6667
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
6668
|
+
className: "mrfw-sectionTitle",
|
|
6669
|
+
children: t("panel.cwd")
|
|
6670
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
6671
|
+
className: "mrfw-sectionNote",
|
|
6672
|
+
children: t("panel.cwdNote")
|
|
6673
|
+
})]
|
|
6674
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
6675
|
+
className: "mrfw-rootPath",
|
|
6676
|
+
children: state.view.effectiveCwd
|
|
6677
|
+
})]
|
|
6678
|
+
}),
|
|
6397
6679
|
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
|
|
6398
6680
|
className: "mrfw-section",
|
|
6399
6681
|
children: [
|
|
@@ -6533,7 +6815,13 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
6533
6815
|
children: t("panel.aliasCancel")
|
|
6534
6816
|
})
|
|
6535
6817
|
]
|
|
6536
|
-
}) : null
|
|
6818
|
+
}) : null,
|
|
6819
|
+
root.state === "available" && panel !== void 0 && props.sessionId !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(RootFileTree, {
|
|
6820
|
+
panel,
|
|
6821
|
+
entry: entryOf(root),
|
|
6822
|
+
sessionId: props.sessionId,
|
|
6823
|
+
t
|
|
6824
|
+
})
|
|
6537
6825
|
]
|
|
6538
6826
|
}, key);
|
|
6539
6827
|
})
|
|
@@ -6631,6 +6919,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
6631
6919
|
return await workspace.pickDirectory();
|
|
6632
6920
|
};
|
|
6633
6921
|
const sessionId = () => currentSessionIdOf(readService(ctx, "sessions"));
|
|
6922
|
+
const subscribeSession = (listener) => subscribeSessions(readService(ctx, "sessions"), listener);
|
|
6634
6923
|
const t = ctx.locale.bind(NS);
|
|
6635
6924
|
ctx.slots.inject("sidebar.footer.action", () => ctx.slots.register({
|
|
6636
6925
|
name: "sidebar.footer.action",
|
|
@@ -6644,10 +6933,23 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
|
|
|
6644
6933
|
panel,
|
|
6645
6934
|
pickDirectory,
|
|
6646
6935
|
sessionId,
|
|
6936
|
+
subscribeSession,
|
|
6647
6937
|
t,
|
|
6648
6938
|
...wide === void 0 ? {} : { wide }
|
|
6649
6939
|
});
|
|
6650
6940
|
}));
|
|
6941
|
+
ctx.slots.inject("sidebar.right.tab.files.actions", () => ctx.slots.register({
|
|
6942
|
+
name: "sidebar.right.tab.files.actions",
|
|
6943
|
+
id: SLOT_ID,
|
|
6944
|
+
order: 50
|
|
6945
|
+
}, () => (0, react.createElement)(WorkspaceFoldersAction, {
|
|
6946
|
+
panel,
|
|
6947
|
+
pickDirectory,
|
|
6948
|
+
sessionId,
|
|
6949
|
+
subscribeSession,
|
|
6950
|
+
t,
|
|
6951
|
+
compact: true
|
|
6952
|
+
})));
|
|
6651
6953
|
}
|
|
6652
6954
|
/**
|
|
6653
6955
|
* Read one optional service by name.
|