@neuralnomads/codenomad-dev 0.15.0-dev-20260511-efe3f505 → 0.15.0-dev-20260512-cf88dc06
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/dist/filesystem/browser.js +21 -0
- package/dist/opencode-plugin/codenomad-opencode-plugin.tgz +0 -0
- package/dist/opencode-plugin.js +146 -0
- package/dist/opencode-plugin.test.js +28 -0
- package/dist/server/routes/filesystem.js +13 -0
- package/dist/server/routes/workspaces.js +2 -1
- package/dist/workspaces/__tests__/spawn.test.js +26 -8
- package/dist/workspaces/manager.js +8 -5
- package/dist/workspaces/spawn.js +35 -9
- package/package.json +3 -3
- package/public/assets/{ChangesTab-DGWzwppj.js → ChangesTab-WiAkKpjs.js} +2 -2
- package/public/assets/{DiffToolbar-dXDVyXwL.js → DiffToolbar-CszYc-5e.js} +1 -1
- package/public/assets/{FilesTab-IN-3vEym.js → FilesTab-DZa2lrGN.js} +2 -2
- package/public/assets/{GitChangesTab-yhDvCETZ.js → GitChangesTab-nr_mljFy.js} +2 -2
- package/public/assets/{SplitFilePanel-01YOnTOG.js → SplitFilePanel-BnKNINzw.js} +1 -1
- package/public/assets/{StatusTab-CI5m-66G.js → StatusTab-Bcw2TwXQ.js} +1 -1
- package/public/assets/{align-justify-DRTNZj9A.js → align-justify-CK6TIjhy.js} +1 -1
- package/public/assets/{bundle-full-D0o5M_wa.js → bundle-full-B0SERoqg.js} +1 -1
- package/public/assets/{diff-viewer-jXMkhi-L.js → diff-viewer-ES729gix.js} +1 -1
- package/public/assets/{index-Be11ZFEb.js → index-BIX31nDN.js} +1 -1
- package/public/assets/index-BcPnhqOk.js +1 -0
- package/public/assets/index-Bo2Zanex.js +2 -0
- package/public/assets/index-C2gIF7lT.css +1 -0
- package/public/assets/index-CQtJQxmF.js +1 -0
- package/public/assets/{index-Cb-FGBAx.js → index-CfI4uv3o.js} +1 -1
- package/public/assets/index-D9Iccxfo.js +1 -0
- package/public/assets/index-D9lYBPix.js +1 -0
- package/public/assets/index-Dir_tpmw.js +1 -0
- package/public/assets/index-HmgXZSSj.js +1 -0
- package/public/assets/{loading-BNcShOZ7.js → loading-W5eAwT4B.js} +1 -1
- package/public/assets/main-CuHfodsk.js +62 -0
- package/public/assets/{markdown-BO-eqU7M.js → markdown-BudrGEV0.js} +3 -3
- package/public/assets/{monaco-viewer-CUKSC3oL.js → monaco-viewer-B3iAKbO0.js} +1 -1
- package/public/assets/{tool-call-B2LR4TW4.js → tool-call-BsJm3dsD.js} +3 -3
- package/public/assets/{unified-picker-hHK-At_1.js → unified-picker-DBntm5nO.js} +1 -1
- package/public/assets/{wrap-text-y6UsswWF.js → wrap-text-DL9Owbno.js} +1 -1
- package/public/index.html +4 -4
- package/public/loading.html +4 -4
- package/public/sw.js +1 -1
- package/dist/opencode-config/README.md +0 -32
- package/dist/opencode-config/opencode.jsonc +0 -3
- package/dist/opencode-config/package-lock.json +0 -380
- package/dist/opencode-config/package.json +0 -9
- package/dist/opencode-config/plugin/codenomad.ts +0 -62
- package/dist/opencode-config/plugin/lib/background-process.ts +0 -265
- package/dist/opencode-config/plugin/lib/client.ts +0 -133
- package/dist/opencode-config/plugin/lib/request.ts +0 -214
- package/dist/opencode-config.js +0 -26
- package/public/assets/index-BBdin4zl.css +0 -1
- package/public/assets/index-CNG3sDWM.js +0 -1
- package/public/assets/index-CZr9LwXP.js +0 -1
- package/public/assets/index-CfmQyy0c.js +0 -1
- package/public/assets/index-CmWJRIhG.js +0 -1
- package/public/assets/index-Cpe_O_IY.js +0 -1
- package/public/assets/index-PvzRwXKl.js +0 -2
- package/public/assets/index-fZ-H5e-Q.js +0 -1
- package/public/assets/main-CkAUlWH0.js +0 -62
|
@@ -3,6 +3,7 @@ import os from "os";
|
|
|
3
3
|
import path from "path";
|
|
4
4
|
import { WINDOWS_DRIVES_ROOT, } from "../api-types";
|
|
5
5
|
const WINDOWS_DRIVE_LETTERS = Array.from({ length: 26 }, (_, i) => String.fromCharCode(65 + i));
|
|
6
|
+
const MAX_READABLE_FILE_BYTES = 5 * 1024 * 1024;
|
|
6
7
|
export class FileSystemBrowser {
|
|
7
8
|
constructor(options) {
|
|
8
9
|
this.root = path.resolve(options.rootDir);
|
|
@@ -64,6 +65,26 @@ export class FileSystemBrowser {
|
|
|
64
65
|
const resolved = this.toRestrictedAbsolute(relativePath);
|
|
65
66
|
return fs.readFileSync(resolved, "utf-8");
|
|
66
67
|
}
|
|
68
|
+
readFileBase64(relativePath) {
|
|
69
|
+
if (this.unrestricted) {
|
|
70
|
+
throw new Error("readFileBase64 is not available in unrestricted mode");
|
|
71
|
+
}
|
|
72
|
+
const resolved = this.toRestrictedAbsolute(relativePath);
|
|
73
|
+
return fs.readFileSync(resolved).toString("base64");
|
|
74
|
+
}
|
|
75
|
+
readFileContent(targetPath, options) {
|
|
76
|
+
const encoding = options?.encoding ?? "utf-8";
|
|
77
|
+
const resolved = this.unrestricted ? this.resolveUnrestrictedPath(targetPath) : this.toRestrictedAbsolute(targetPath);
|
|
78
|
+
const stats = fs.statSync(resolved);
|
|
79
|
+
if (!stats.isFile()) {
|
|
80
|
+
throw new Error("Selected path is not a file");
|
|
81
|
+
}
|
|
82
|
+
if (stats.size > MAX_READABLE_FILE_BYTES) {
|
|
83
|
+
throw new Error("Selected file is too large to attach");
|
|
84
|
+
}
|
|
85
|
+
const contents = encoding === "base64" ? fs.readFileSync(resolved).toString("base64") : fs.readFileSync(resolved, "utf-8");
|
|
86
|
+
return { path: targetPath, contents, encoding };
|
|
87
|
+
}
|
|
67
88
|
listRestrictedWithMetadata(relativePath, includeFiles) {
|
|
68
89
|
const normalizedPath = this.normalizeRelativePath(relativePath);
|
|
69
90
|
const absolutePath = this.toRestrictedAbsolute(normalizedPath);
|
|
Binary file
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
import { existsSync, readdirSync } from "fs";
|
|
2
|
+
import path from "path";
|
|
3
|
+
import { fileURLToPath, pathToFileURL } from "url";
|
|
4
|
+
import { createLogger } from "./logger";
|
|
5
|
+
const log = createLogger({ component: "opencode-plugin" });
|
|
6
|
+
const pluginPackageName = "@codenomad/codenomad-opencode-plugin";
|
|
7
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
8
|
+
const __dirname = path.dirname(__filename);
|
|
9
|
+
const resourcesPath = process.resourcesPath;
|
|
10
|
+
const devPluginEntry = path.resolve(__dirname, "../../opencode-plugin/plugin/codenomad.ts");
|
|
11
|
+
const prodPluginDirs = [
|
|
12
|
+
resourcesPath ? path.resolve(resourcesPath, "opencode-plugin") : undefined,
|
|
13
|
+
resourcesPath ? path.resolve(resourcesPath, "server/dist/opencode-plugin") : undefined,
|
|
14
|
+
path.resolve(__dirname, "opencode-plugin"),
|
|
15
|
+
].filter((dir) => Boolean(dir));
|
|
16
|
+
const isDevBuild = Boolean(process.env.CODENOMAD_DEV ??
|
|
17
|
+
process.env.CLI_UI_DEV_SERVER ??
|
|
18
|
+
process.env.VITE_DEV_SERVER_URL ??
|
|
19
|
+
process.env.ELECTRON_RENDERER_URL);
|
|
20
|
+
const isSourceRun = path.basename(__dirname) === "src" && existsSync(devPluginEntry);
|
|
21
|
+
export function getCodeNomadPluginUrl() {
|
|
22
|
+
if (isDevBuild || isSourceRun) {
|
|
23
|
+
if (!existsSync(devPluginEntry)) {
|
|
24
|
+
throw new Error(`CodeNomad OpenCode plugin entry missing at ${devPluginEntry}`);
|
|
25
|
+
}
|
|
26
|
+
log.debug({ pluginEntry: devPluginEntry }, "Using OpenCode plugin source directly (dev mode)");
|
|
27
|
+
return pathToFileURL(devPluginEntry).href;
|
|
28
|
+
}
|
|
29
|
+
for (const dir of prodPluginDirs) {
|
|
30
|
+
const tarball = findPluginTarball(dir);
|
|
31
|
+
if (tarball) {
|
|
32
|
+
return toNpmFileSpecifier(tarball);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
throw new Error(`CodeNomad OpenCode plugin package missing in ${prodPluginDirs.join(", ")}`);
|
|
36
|
+
}
|
|
37
|
+
export function buildOpencodeConfigContent(existingContent, pluginUrl) {
|
|
38
|
+
const config = existingContent?.trim() ? parseJsoncObject(existingContent) : {};
|
|
39
|
+
const existingPlugins = normalizePluginEntries(config.plugin);
|
|
40
|
+
if (!existingPlugins.includes(pluginUrl)) {
|
|
41
|
+
existingPlugins.push(pluginUrl);
|
|
42
|
+
}
|
|
43
|
+
return JSON.stringify({
|
|
44
|
+
"$schema": typeof config["$schema"] === "string" ? config["$schema"] : "https://opencode.ai/config.json",
|
|
45
|
+
...config,
|
|
46
|
+
plugin: existingPlugins,
|
|
47
|
+
}, null, 2);
|
|
48
|
+
}
|
|
49
|
+
export function resolveExistingOpencodeConfigContent(userEnvironment) {
|
|
50
|
+
const userValue = normalizeConfigContentValue(userEnvironment.OPENCODE_CONFIG_CONTENT);
|
|
51
|
+
if (userValue) {
|
|
52
|
+
return userValue;
|
|
53
|
+
}
|
|
54
|
+
return normalizeConfigContentValue(process.env.OPENCODE_CONFIG_CONTENT);
|
|
55
|
+
}
|
|
56
|
+
function toNpmFileSpecifier(filePath) {
|
|
57
|
+
return `${pluginPackageName}@file:${filePath.replace(/\\/g, "/")}`;
|
|
58
|
+
}
|
|
59
|
+
function findPluginTarball(dir) {
|
|
60
|
+
if (!existsSync(dir)) {
|
|
61
|
+
return null;
|
|
62
|
+
}
|
|
63
|
+
const tarballs = readdirSync(dir)
|
|
64
|
+
.filter((name) => name.endsWith(".tgz"))
|
|
65
|
+
.sort();
|
|
66
|
+
return tarballs.length > 0 ? path.resolve(dir, tarballs[tarballs.length - 1]) : null;
|
|
67
|
+
}
|
|
68
|
+
function normalizeConfigContentValue(value) {
|
|
69
|
+
return typeof value === "string" && value.trim().length > 0 ? value : undefined;
|
|
70
|
+
}
|
|
71
|
+
function parseJsoncObject(content) {
|
|
72
|
+
try {
|
|
73
|
+
const parsed = JSON.parse(stripJsonc(content));
|
|
74
|
+
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
75
|
+
throw new Error("OPENCODE_CONFIG_CONTENT must be a JSON object");
|
|
76
|
+
}
|
|
77
|
+
return parsed;
|
|
78
|
+
}
|
|
79
|
+
catch (error) {
|
|
80
|
+
const reason = error instanceof Error ? error.message : String(error);
|
|
81
|
+
throw new Error(`Failed to parse OPENCODE_CONFIG_CONTENT: ${reason}`);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
function normalizePluginEntries(value) {
|
|
85
|
+
if (value === undefined) {
|
|
86
|
+
return [];
|
|
87
|
+
}
|
|
88
|
+
if (typeof value === "string") {
|
|
89
|
+
return [value];
|
|
90
|
+
}
|
|
91
|
+
if (Array.isArray(value) && value.every((item) => typeof item === "string")) {
|
|
92
|
+
return [...value];
|
|
93
|
+
}
|
|
94
|
+
throw new Error("OPENCODE_CONFIG_CONTENT plugin field must be a string or string array");
|
|
95
|
+
}
|
|
96
|
+
function stripJsonc(input) {
|
|
97
|
+
let output = "";
|
|
98
|
+
let inString = false;
|
|
99
|
+
let escape = false;
|
|
100
|
+
for (let index = 0; index < input.length; index += 1) {
|
|
101
|
+
const char = input[index];
|
|
102
|
+
const next = input[index + 1];
|
|
103
|
+
if (escape) {
|
|
104
|
+
output += char;
|
|
105
|
+
escape = false;
|
|
106
|
+
continue;
|
|
107
|
+
}
|
|
108
|
+
if (char === "\\" && inString) {
|
|
109
|
+
output += char;
|
|
110
|
+
escape = true;
|
|
111
|
+
continue;
|
|
112
|
+
}
|
|
113
|
+
if (char === '"') {
|
|
114
|
+
output += char;
|
|
115
|
+
inString = !inString;
|
|
116
|
+
continue;
|
|
117
|
+
}
|
|
118
|
+
if (!inString && char === "/" && next === "/") {
|
|
119
|
+
while (index < input.length && input[index] !== "\n") {
|
|
120
|
+
index += 1;
|
|
121
|
+
}
|
|
122
|
+
output += "\n";
|
|
123
|
+
continue;
|
|
124
|
+
}
|
|
125
|
+
if (!inString && char === "/" && next === "*") {
|
|
126
|
+
index += 2;
|
|
127
|
+
while (index < input.length && !(input[index] === "*" && input[index + 1] === "/")) {
|
|
128
|
+
output += input[index] === "\n" ? "\n" : "";
|
|
129
|
+
index += 1;
|
|
130
|
+
}
|
|
131
|
+
index += 1;
|
|
132
|
+
continue;
|
|
133
|
+
}
|
|
134
|
+
if (!inString && char === ",") {
|
|
135
|
+
let lookahead = index + 1;
|
|
136
|
+
while (lookahead < input.length && /\s/.test(input[lookahead])) {
|
|
137
|
+
lookahead += 1;
|
|
138
|
+
}
|
|
139
|
+
if (input[lookahead] === "}" || input[lookahead] === "]") {
|
|
140
|
+
continue;
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
output += char;
|
|
144
|
+
}
|
|
145
|
+
return output;
|
|
146
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import assert from "node:assert/strict";
|
|
2
|
+
import { describe, it } from "node:test";
|
|
3
|
+
import { buildOpencodeConfigContent } from "./opencode-plugin";
|
|
4
|
+
describe("buildOpencodeConfigContent", () => {
|
|
5
|
+
it("creates config content with the CodeNomad plugin", () => {
|
|
6
|
+
const content = buildOpencodeConfigContent(undefined, "file:///plugin.tgz");
|
|
7
|
+
assert.deepEqual(JSON.parse(content), {
|
|
8
|
+
"$schema": "https://opencode.ai/config.json",
|
|
9
|
+
plugin: ["file:///plugin.tgz"],
|
|
10
|
+
});
|
|
11
|
+
});
|
|
12
|
+
it("merges with existing JSONC content", () => {
|
|
13
|
+
const content = buildOpencodeConfigContent(`{
|
|
14
|
+
// user plugin
|
|
15
|
+
"plugin": ["npm:user-plugin",],
|
|
16
|
+
"model": "test-model",
|
|
17
|
+
}`, "file:///plugin.tgz");
|
|
18
|
+
assert.deepEqual(JSON.parse(content), {
|
|
19
|
+
"$schema": "https://opencode.ai/config.json",
|
|
20
|
+
plugin: ["npm:user-plugin", "file:///plugin.tgz"],
|
|
21
|
+
model: "test-model",
|
|
22
|
+
});
|
|
23
|
+
});
|
|
24
|
+
it("does not duplicate the CodeNomad plugin", () => {
|
|
25
|
+
const content = buildOpencodeConfigContent('{"plugin":["file:///plugin.tgz"]}', "file:///plugin.tgz");
|
|
26
|
+
assert.deepEqual(JSON.parse(content).plugin, ["file:///plugin.tgz"]);
|
|
27
|
+
});
|
|
28
|
+
});
|
|
@@ -7,6 +7,10 @@ const FilesystemCreateFolderSchema = z.object({
|
|
|
7
7
|
parentPath: z.string().optional(),
|
|
8
8
|
name: z.string(),
|
|
9
9
|
});
|
|
10
|
+
const FilesystemFileContentQuerySchema = z.object({
|
|
11
|
+
path: z.string(),
|
|
12
|
+
encoding: z.enum(["utf-8", "base64"]).optional(),
|
|
13
|
+
});
|
|
10
14
|
export function registerFilesystemRoutes(app, deps) {
|
|
11
15
|
app.get("/api/filesystem", async (request, reply) => {
|
|
12
16
|
const query = FilesystemQuerySchema.parse(request.query ?? {});
|
|
@@ -40,4 +44,13 @@ export function registerFilesystemRoutes(app, deps) {
|
|
|
40
44
|
reply.code(400).type("text/plain").send(error.message);
|
|
41
45
|
}
|
|
42
46
|
});
|
|
47
|
+
app.get("/api/filesystem/files/content", async (request, reply) => {
|
|
48
|
+
const query = FilesystemFileContentQuerySchema.parse(request.query ?? {});
|
|
49
|
+
try {
|
|
50
|
+
return deps.fileSystemBrowser.readFileContent(query.path, { encoding: query.encoding });
|
|
51
|
+
}
|
|
52
|
+
catch (error) {
|
|
53
|
+
reply.code(400).type("text/plain").send(error.message);
|
|
54
|
+
}
|
|
55
|
+
});
|
|
43
56
|
}
|
|
@@ -18,6 +18,7 @@ const WorkspaceFilesQuerySchema = z.object({
|
|
|
18
18
|
});
|
|
19
19
|
const WorkspaceFileContentQuerySchema = z.object({
|
|
20
20
|
path: z.string(),
|
|
21
|
+
encoding: z.enum(["utf-8", "base64"]).optional(),
|
|
21
22
|
});
|
|
22
23
|
const WorkspaceFileContentBodySchema = z.object({
|
|
23
24
|
contents: z.string(),
|
|
@@ -107,7 +108,7 @@ export function registerWorkspaceRoutes(app, deps) {
|
|
|
107
108
|
app.get("/api/workspaces/:id/files/content", async (request, reply) => {
|
|
108
109
|
try {
|
|
109
110
|
const query = WorkspaceFileContentQuerySchema.parse(request.query ?? {});
|
|
110
|
-
return deps.workspaceManager.readFile(request.params.id, query.path);
|
|
111
|
+
return deps.workspaceManager.readFile(request.params.id, query.path, { encoding: query.encoding });
|
|
111
112
|
}
|
|
112
113
|
catch (error) {
|
|
113
114
|
return handleWorkspaceError(error, reply);
|
|
@@ -34,12 +34,12 @@ describe("buildWindowsSpawnSpec", () => {
|
|
|
34
34
|
const spec = buildWindowsSpawnSpec(String.raw `\\wsl.localhost\Ubuntu\home\dev\.opencode\bin\opencode`, ["serve", "--port", "0"], {
|
|
35
35
|
cwd: String.raw `\\wsl.localhost\Ubuntu\home\dev\workspace`,
|
|
36
36
|
env: {
|
|
37
|
-
|
|
37
|
+
OPENCODE_CONFIG_CONTENT: JSON.stringify({ plugin: ["file:///C:/Users/dev/AppData/Roaming/CodeNomad/plugin.tgz"] }),
|
|
38
38
|
CODENOMAD_INSTANCE_ID: "workspace-123",
|
|
39
39
|
OPENCODE_SERVER_BASE_URL: "https://127.0.0.1:4321/workspaces/workspace-123/worktrees/root/instance",
|
|
40
40
|
OPENCODE_SERVER_PASSWORD: "secret",
|
|
41
41
|
},
|
|
42
|
-
propagateEnvKeys: ["
|
|
42
|
+
propagateEnvKeys: ["OPENCODE_CONFIG_CONTENT", "CODENOMAD_INSTANCE_ID", "OPENCODE_SERVER_BASE_URL", "OPENCODE_SERVER_PASSWORD"],
|
|
43
43
|
});
|
|
44
44
|
assert.equal(spec.command, "wsl.exe");
|
|
45
45
|
assert.deepEqual(spec.args, [
|
|
@@ -54,17 +54,35 @@ describe("buildWindowsSpawnSpec", () => {
|
|
|
54
54
|
"0",
|
|
55
55
|
]);
|
|
56
56
|
assert.equal(spec.cwd, undefined);
|
|
57
|
-
assert.equal(spec.env?.WSLENV, "
|
|
57
|
+
assert.equal(spec.env?.WSLENV, "OPENCODE_CONFIG_CONTENT:CODENOMAD_INSTANCE_ID:OPENCODE_SERVER_BASE_URL:OPENCODE_SERVER_PASSWORD");
|
|
58
58
|
});
|
|
59
|
-
it("
|
|
59
|
+
it("preserves non-path OPENCODE_CONFIG_CONTENT WSLENV entries", () => {
|
|
60
60
|
const spec = buildWindowsSpawnSpec(String.raw `\\wsl.localhost\Ubuntu\home\dev\.opencode\bin\opencode`, ["serve"], {
|
|
61
61
|
env: {
|
|
62
|
-
|
|
63
|
-
WSLENV: "
|
|
62
|
+
OPENCODE_CONFIG_CONTENT: JSON.stringify({ plugin: ["file:///C:/Users/dev/AppData/Roaming/CodeNomad/plugin.tgz"] }),
|
|
63
|
+
WSLENV: "OPENCODE_CONFIG_CONTENT:CODENOMAD_INSTANCE_ID/u",
|
|
64
64
|
},
|
|
65
|
-
propagateEnvKeys: ["
|
|
65
|
+
propagateEnvKeys: ["OPENCODE_CONFIG_CONTENT", "CODENOMAD_INSTANCE_ID"],
|
|
66
66
|
});
|
|
67
|
-
assert.equal(spec.env?.WSLENV, "
|
|
67
|
+
assert.equal(spec.env?.WSLENV, "OPENCODE_CONFIG_CONTENT:CODENOMAD_INSTANCE_ID/u");
|
|
68
|
+
});
|
|
69
|
+
it("rewrites packaged plugin paths for WSL before launching", () => {
|
|
70
|
+
const spec = buildWindowsSpawnSpec(String.raw `\\wsl.localhost\Ubuntu\home\dev\.opencode\bin\opencode`, ["serve"], {
|
|
71
|
+
env: {
|
|
72
|
+
OPENCODE_CONFIG_CONTENT: JSON.stringify({
|
|
73
|
+
plugin: [
|
|
74
|
+
"@codenomad/codenomad-opencode-plugin@file:C:/Users/dev/AppData/Roaming/CodeNomad/codenomad-opencode-plugin.tgz",
|
|
75
|
+
],
|
|
76
|
+
}),
|
|
77
|
+
},
|
|
78
|
+
propagateEnvKeys: ["OPENCODE_CONFIG_CONTENT"],
|
|
79
|
+
});
|
|
80
|
+
assert.equal(spec.command, "wsl.exe");
|
|
81
|
+
assert.equal(spec.env?.CODENOMAD_OPENCODE_PLUGIN_WSL_PATH, String.raw `C:\Users\dev\AppData\Roaming\CodeNomad\codenomad-opencode-plugin.tgz`);
|
|
82
|
+
assert.match(spec.env?.OPENCODE_CONFIG_CONTENT ?? "", /__CODENOMAD_OPENCODE_PLUGIN_WSL_PATH__/);
|
|
83
|
+
assert.equal(spec.env?.WSLENV, "OPENCODE_CONFIG_CONTENT:CODENOMAD_OPENCODE_PLUGIN_WSL_PATH/p");
|
|
84
|
+
assert.deepEqual(spec.args.slice(0, 4), ["--distribution", "Ubuntu", "--exec", "sh"]);
|
|
85
|
+
assert.match(spec.args[5] ?? "", /CODENOMAD_OPENCODE_PLUGIN_WSL_PATH/);
|
|
68
86
|
});
|
|
69
87
|
it("propagates inherited known path variables even when they are not explicitly requested", () => {
|
|
70
88
|
const spec = buildWindowsSpawnSpec(String.raw `\\wsl.localhost\Ubuntu\home\dev\.opencode\bin\opencode`, ["serve"], {
|
|
@@ -5,7 +5,7 @@ import { FileSystemBrowser } from "../filesystem/browser";
|
|
|
5
5
|
import { searchWorkspaceFiles } from "../filesystem/search";
|
|
6
6
|
import { clearWorkspaceSearchCache } from "../filesystem/search-cache";
|
|
7
7
|
import { WorkspaceRuntime } from "./runtime";
|
|
8
|
-
import {
|
|
8
|
+
import { buildOpencodeConfigContent, getCodeNomadPluginUrl, resolveExistingOpencodeConfigContent, } from "../opencode-plugin.js";
|
|
9
9
|
import { OPENCODE_SERVER_BASE_URL_ENV, buildOpencodeBasicAuthHeader, OPENCODE_SERVER_PASSWORD_ENV, OPENCODE_SERVER_USERNAME_ENV, resolveOpencodeServerAuth, } from "./opencode-auth";
|
|
10
10
|
const STARTUP_STABILITY_DELAY_MS = 1500;
|
|
11
11
|
export class WorkspaceManager {
|
|
@@ -14,7 +14,7 @@ export class WorkspaceManager {
|
|
|
14
14
|
this.workspaces = new Map();
|
|
15
15
|
this.opencodeAuth = new Map();
|
|
16
16
|
this.runtime = new WorkspaceRuntime(this.options.eventBus, this.options.logger);
|
|
17
|
-
this.
|
|
17
|
+
this.codeNomadPluginUrl = getCodeNomadPluginUrl();
|
|
18
18
|
}
|
|
19
19
|
list() {
|
|
20
20
|
return Array.from(this.workspaces.values());
|
|
@@ -37,14 +37,16 @@ export class WorkspaceManager {
|
|
|
37
37
|
const workspace = this.requireWorkspace(workspaceId);
|
|
38
38
|
return searchWorkspaceFiles(workspace.path, query, options);
|
|
39
39
|
}
|
|
40
|
-
readFile(workspaceId, relativePath) {
|
|
40
|
+
readFile(workspaceId, relativePath, options) {
|
|
41
41
|
const workspace = this.requireWorkspace(workspaceId);
|
|
42
42
|
const browser = new FileSystemBrowser({ rootDir: workspace.path });
|
|
43
|
-
const
|
|
43
|
+
const encoding = options?.encoding ?? "utf-8";
|
|
44
|
+
const contents = encoding === "base64" ? browser.readFileBase64(relativePath) : browser.readFile(relativePath);
|
|
44
45
|
return {
|
|
45
46
|
workspaceId,
|
|
46
47
|
relativePath,
|
|
47
48
|
contents,
|
|
49
|
+
encoding,
|
|
48
50
|
};
|
|
49
51
|
}
|
|
50
52
|
writeFile(workspaceId, relativePath, contents) {
|
|
@@ -77,6 +79,7 @@ export class WorkspaceManager {
|
|
|
77
79
|
const serverConfig = this.options.settings.getOwner("config", "server");
|
|
78
80
|
const envVars = serverConfig?.environmentVariables;
|
|
79
81
|
const userEnvironment = envVars && typeof envVars === "object" && !Array.isArray(envVars) ? envVars : {};
|
|
82
|
+
const opencodeConfigContent = buildOpencodeConfigContent(resolveExistingOpencodeConfigContent(userEnvironment), this.codeNomadPluginUrl);
|
|
80
83
|
const serverBaseUrl = this.options.getServerBaseUrl();
|
|
81
84
|
const normalizedServerBaseUrl = serverBaseUrl.replace(/\/+$/, "");
|
|
82
85
|
const { username: opencodeUsername, password: opencodePassword } = resolveOpencodeServerAuth({
|
|
@@ -90,7 +93,7 @@ export class WorkspaceManager {
|
|
|
90
93
|
this.opencodeAuth.set(id, { username: opencodeUsername, password: opencodePassword, authorization });
|
|
91
94
|
const environment = {
|
|
92
95
|
...userEnvironment,
|
|
93
|
-
|
|
96
|
+
OPENCODE_CONFIG_CONTENT: opencodeConfigContent,
|
|
94
97
|
CODENOMAD_INSTANCE_ID: id,
|
|
95
98
|
CODENOMAD_BASE_URL: serverBaseUrl,
|
|
96
99
|
...(this.options.nodeExtraCaCertsPath ? { NODE_EXTRA_CA_CERTS: this.options.nodeExtraCaCertsPath } : {}),
|
package/dist/workspaces/spawn.js
CHANGED
|
@@ -4,7 +4,11 @@ export const WINDOWS_CMD_EXTENSIONS = new Set([".cmd", ".bat"]);
|
|
|
4
4
|
export const WINDOWS_POWERSHELL_EXTENSIONS = new Set([".ps1"]);
|
|
5
5
|
const VERSION_REGEX = /([0-9]+\.[0-9]+\.[0-9A-Za-z.-]+)/;
|
|
6
6
|
const WSL_UNC_PATH_REGEX = /^\\\\wsl(?:\.localhost|\$)\\([^\\/]+)(?:[\\/](.*))?$/i;
|
|
7
|
-
const
|
|
7
|
+
const CODENOMAD_PLUGIN_PACKAGE_NAME = "@codenomad/codenomad-opencode-plugin";
|
|
8
|
+
const WSL_PLUGIN_PATH_ENV = "CODENOMAD_OPENCODE_PLUGIN_WSL_PATH";
|
|
9
|
+
const WSL_PLUGIN_PATH_PLACEHOLDER = "__CODENOMAD_OPENCODE_PLUGIN_WSL_PATH__";
|
|
10
|
+
const CODENOMAD_PLUGIN_FILE_SPEC_REGEX = new RegExp(`(${escapeRegex(CODENOMAD_PLUGIN_PACKAGE_NAME)}@file:)([A-Za-z]:[^"\\r\\n]+?\\.tgz)`);
|
|
11
|
+
const WSL_PATH_ENV_KEYS = new Set(["NODE_EXTRA_CA_CERTS", WSL_PLUGIN_PATH_ENV]);
|
|
8
12
|
export function parseWslUncPath(input) {
|
|
9
13
|
const normalized = input.trim().replace(/\//g, "\\");
|
|
10
14
|
const match = normalized.match(WSL_UNC_PATH_REGEX);
|
|
@@ -129,16 +133,18 @@ export function probeBinaryVersion(binaryPath) {
|
|
|
129
133
|
}
|
|
130
134
|
function buildWslSpawnSpec(wslPath, args, options) {
|
|
131
135
|
const workingDirectory = options.cwd ? resolveWslWorkingDirectory(options.cwd, wslPath.distro) : undefined;
|
|
136
|
+
const env = buildWslEnvironment(options.env, options.propagateEnvKeys);
|
|
137
|
+
const shouldTranslatePluginPath = Boolean(env?.[WSL_PLUGIN_PATH_ENV]);
|
|
132
138
|
if (options.cwd && !workingDirectory) {
|
|
133
139
|
throw new Error(`Unable to translate workspace folder for WSL binary in distro "${wslPath.distro}": ${options.cwd}`);
|
|
134
140
|
}
|
|
135
141
|
const wslArgs = ["--distribution", wslPath.distro];
|
|
136
|
-
const shouldWrapWithShell = Boolean(options.wslPidMarker) || workingDirectory?.kind === "windows";
|
|
142
|
+
const shouldWrapWithShell = Boolean(options.wslPidMarker) || workingDirectory?.kind === "windows" || shouldTranslatePluginPath;
|
|
137
143
|
if (!shouldWrapWithShell && workingDirectory?.kind === "linux") {
|
|
138
144
|
wslArgs.push("--cd", workingDirectory.path);
|
|
139
145
|
}
|
|
140
146
|
if (shouldWrapWithShell) {
|
|
141
|
-
const launchScript = buildWslLaunchScript(workingDirectory ?? undefined, options.wslPidMarker);
|
|
147
|
+
const launchScript = buildWslLaunchScript(workingDirectory ?? undefined, options.wslPidMarker, shouldTranslatePluginPath);
|
|
142
148
|
wslArgs.push("--exec", "sh", "-lc", launchScript, "codenomad-wsl-launch");
|
|
143
149
|
if (workingDirectory) {
|
|
144
150
|
wslArgs.push(workingDirectory.path);
|
|
@@ -152,11 +158,11 @@ function buildWslSpawnSpec(wslPath, args, options) {
|
|
|
152
158
|
command: "wsl.exe",
|
|
153
159
|
args: wslArgs,
|
|
154
160
|
options: {},
|
|
155
|
-
env
|
|
161
|
+
env,
|
|
156
162
|
wsl: { distro: wslPath.distro, pidMarker: options.wslPidMarker },
|
|
157
163
|
};
|
|
158
164
|
}
|
|
159
|
-
function buildWslLaunchScript(workingDirectory, pidMarker) {
|
|
165
|
+
function buildWslLaunchScript(workingDirectory, pidMarker, translatePluginPath) {
|
|
160
166
|
const steps = [];
|
|
161
167
|
if (pidMarker) {
|
|
162
168
|
steps.push(`printf '%s%s\\n' '${pidMarker}' "$$"`);
|
|
@@ -169,6 +175,9 @@ function buildWslLaunchScript(workingDirectory, pidMarker) {
|
|
|
169
175
|
steps.push('cd "$(wslpath -au "$1")"');
|
|
170
176
|
steps.push("shift");
|
|
171
177
|
}
|
|
178
|
+
if (translatePluginPath) {
|
|
179
|
+
steps.push(`if [ -n "$${WSL_PLUGIN_PATH_ENV}" ] && [ -n "$OPENCODE_CONFIG_CONTENT" ]; then escaped_plugin_path=$(printf '%s' "$${WSL_PLUGIN_PATH_ENV}" | sed 's/[\\&|]/\\\\&/g'); OPENCODE_CONFIG_CONTENT=$(printf '%s' "$OPENCODE_CONFIG_CONTENT" | sed "s|${WSL_PLUGIN_PATH_PLACEHOLDER}|$escaped_plugin_path|g"); export OPENCODE_CONFIG_CONTENT; unset ${WSL_PLUGIN_PATH_ENV}; fi`);
|
|
180
|
+
}
|
|
172
181
|
steps.push('exec "$@"');
|
|
173
182
|
return steps.join(" && ");
|
|
174
183
|
}
|
|
@@ -186,14 +195,15 @@ function buildWslEnvironment(env, propagateEnvKeys) {
|
|
|
186
195
|
if (!env) {
|
|
187
196
|
return env;
|
|
188
197
|
}
|
|
198
|
+
const next = { ...env };
|
|
199
|
+
rewriteOpencodePluginPathForWsl(next);
|
|
189
200
|
const keysToPropagate = Array.from(new Set([
|
|
190
|
-
...(propagateEnvKeys ?? []).filter((key) =>
|
|
191
|
-
...Array.from(WSL_PATH_ENV_KEYS).filter((key) =>
|
|
201
|
+
...(propagateEnvKeys ?? []).filter((key) => next[key] !== undefined),
|
|
202
|
+
...Array.from(WSL_PATH_ENV_KEYS).filter((key) => next[key] !== undefined),
|
|
192
203
|
]));
|
|
193
204
|
if (keysToPropagate.length === 0) {
|
|
194
|
-
return
|
|
205
|
+
return next;
|
|
195
206
|
}
|
|
196
|
-
const next = { ...env };
|
|
197
207
|
const entries = (next.WSLENV ?? "").split(":").filter((entry) => entry.length > 0);
|
|
198
208
|
const byName = new Map(entries.map((entry) => [entry.split("/")[0] ?? entry, entry]));
|
|
199
209
|
for (const key of keysToPropagate) {
|
|
@@ -207,6 +217,19 @@ function buildWslEnvironment(env, propagateEnvKeys) {
|
|
|
207
217
|
next.WSLENV = Array.from(byName.values()).join(":");
|
|
208
218
|
return next;
|
|
209
219
|
}
|
|
220
|
+
function rewriteOpencodePluginPathForWsl(env) {
|
|
221
|
+
const content = env.OPENCODE_CONFIG_CONTENT;
|
|
222
|
+
if (!content) {
|
|
223
|
+
return;
|
|
224
|
+
}
|
|
225
|
+
const match = content.match(CODENOMAD_PLUGIN_FILE_SPEC_REGEX);
|
|
226
|
+
const hostPath = match?.[2];
|
|
227
|
+
if (!hostPath) {
|
|
228
|
+
return;
|
|
229
|
+
}
|
|
230
|
+
env.OPENCODE_CONFIG_CONTENT = content.replace(hostPath, WSL_PLUGIN_PATH_PLACEHOLDER);
|
|
231
|
+
env[WSL_PLUGIN_PATH_ENV] = path.win32.normalize(hostPath);
|
|
232
|
+
}
|
|
210
233
|
function ensureWslenvEntry(entry, requiresPathTranslation) {
|
|
211
234
|
if (!requiresPathTranslation) {
|
|
212
235
|
return entry;
|
|
@@ -217,3 +240,6 @@ function ensureWslenvEntry(entry, requiresPathTranslation) {
|
|
|
217
240
|
}
|
|
218
241
|
return rawFlags.length > 0 ? `${name}/${rawFlags}p` : `${name}/p`;
|
|
219
242
|
}
|
|
243
|
+
function escapeRegex(input) {
|
|
244
|
+
return input.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
245
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@neuralnomads/codenomad-dev",
|
|
3
|
-
"version": "0.15.0-dev-
|
|
3
|
+
"version": "0.15.0-dev-20260512-cf88dc06",
|
|
4
4
|
"description": "CodeNomad Server",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": {
|
|
@@ -17,10 +17,10 @@
|
|
|
17
17
|
"codenomad": "dist/bin.js"
|
|
18
18
|
},
|
|
19
19
|
"scripts": {
|
|
20
|
-
"build": "npm run build:ui && npm run prepare-ui && tsc -p tsconfig.json && node ./scripts/copy-auth-pages.mjs && npm run prepare-
|
|
20
|
+
"build": "npm run build:ui && npm run prepare-ui && tsc -p tsconfig.json && node ./scripts/copy-auth-pages.mjs && npm run prepare-plugin",
|
|
21
21
|
"build:ui": "npm run build --prefix ../ui",
|
|
22
22
|
"prepare-ui": "node ./scripts/copy-ui-dist.mjs",
|
|
23
|
-
"prepare-
|
|
23
|
+
"prepare-plugin": "node ./scripts/package-opencode-plugin.mjs",
|
|
24
24
|
"dev": "cross-env CODENOMAD_DEV=1 CODENOMAD_SERVER_PASSWORD=codenomad-dev CLI_UI_DEV_SERVER=http://localhost:3000 CLI_HTTPS=false CLI_HTTP=true tsx src/index.ts",
|
|
25
25
|
"typecheck": "tsc --noEmit -p tsconfig.json"
|
|
26
26
|
},
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["assets/monaco-viewer-
|
|
2
|
-
import{_ as K}from"./index-
|
|
1
|
+
const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["assets/monaco-viewer-B3iAKbO0.js","assets/git-diff-vendor-CSgooKT_.js","assets/fast-diff-vendor-DgdwVvTQ.js","assets/highlight-vendor-8FKMu9os.js","assets/git-diff-vendor-HAZkIolJ.css"])))=>i.map(i=>d[i]);
|
|
2
|
+
import{_ as K}from"./index-Bo2Zanex.js";import{m as B,t as g,i as a,d as w,a as z,f as N}from"./monaco-viewer-B3iAKbO0.js";import{c as f,n as c,a as L,F,S as W,z as j,A as q}from"./git-diff-vendor-CSgooKT_.js";import{D as G}from"./DiffToolbar-CszYc-5e.js";import{S as H}from"./SplitFilePanel-BnKNINzw.js";import"./fast-diff-vendor-DgdwVvTQ.js";import"./highlight-vendor-8FKMu9os.js";import"./main-CuHfodsk.js";import"./align-justify-CK6TIjhy.js";import"./wrap-text-DL9Owbno.js";var J=g('<div class="file-viewer-panel flex-1"><div class="file-viewer-content file-viewer-content--monaco">'),T=g("<div class=file-viewer-empty><span class=file-viewer-empty-text>"),Q=g('<div class="p-3 text-xs text-secondary">'),E=g("<div><div class=file-list-item-content><div class=file-list-item-path><span class=file-path-text></span></div><div class=file-list-item-stats><span class=file-list-item-additions>+</span><span class=file-list-item-deletions>-"),U=g("<span class=files-tab-selected-path><span class=file-path-text>"),X=g('<div class=files-tab-stats style="flex:0 0 auto"><span class="files-tab-stat files-tab-stat-additions"><span class=files-tab-stat-value>+</span></span><span class="files-tab-stat files-tab-stat-deletions"><span class=files-tab-stat-value>-'),Y=g("<div style=margin-left:auto>");const Z=q(()=>K(()=>import("./monaco-viewer-B3iAKbO0.js").then(e=>e.ad),__vite__mapDeps([0,1,2,3,4])).then(e=>({default:e.MonacoDiffViewer}))),ce=e=>{const M=f(()=>e.activeSessionId()),S=f(()=>!!(M()&&M()!=="info")),D=f(()=>S()?e.activeSessionDiffs():null),m=f(()=>{const n=D();return Array.isArray(n)?[...n].sort((i,l)=>String(i.file||"").localeCompare(String(l.file||""))):[]}),R=f(()=>m().reduce((n,i)=>(n.additions+=typeof i.additions=="number"?i.additions:0,n.deletions+=typeof i.deletions=="number"?i.deletions:0,n),{additions:0,deletions:0})),I=f(()=>{const n=m();return n.length===0?null:n.reduce((i,l)=>{const v=typeof(i==null?void 0:i.additions)=="number"?i.additions:0,y=typeof(i==null?void 0:i.deletions)=="number"?i.deletions:0,x=v+y,k=typeof(l==null?void 0:l.additions)=="number"?l.additions:0,t=typeof(l==null?void 0:l.deletions)=="number"?l.deletions:0,r=k+t;return r>x?l:r<x?i:String(l.file||"").localeCompare(String((i==null?void 0:i.file)||""))<0?l:i},n[0])}),P=f(()=>{const n=e.selectedFile(),i=m();if(n){const l=i.find(v=>v.file===n);if(l)return l}return I()}),O=f(()=>`${e.instanceId}:${S()?M():"no-session"}`),V=f(()=>{if(!S())return e.t("instanceShell.sessionChanges.noSessionSelected");const n=D();return n===void 0?e.t("instanceShell.sessionChanges.loading"):!Array.isArray(n)||n.length===0?e.t("instanceShell.sessionChanges.empty"):e.t("instanceShell.filesShell.viewerEmpty")}),A=f(()=>{const n=P();return n!=null&&n.file?String(n.file):e.t("instanceShell.rightPanel.tabs.changes")});return B(()=>{const n=m(),i=R(),l=P(),v=()=>(()=>{var t=J(),r=t.firstChild;return a(r,c(W,{get when(){return l&&S()&&n.length>0?l:null},get fallback(){return(()=>{var d=T(),s=d.firstChild;return a(s,V),d})()},children:d=>c(j,{get fallback(){return(()=>{var s=T(),u=s.firstChild;return a(u,()=>e.t("instanceInfo.loading")),s})()},get children(){return c(Z,{get scopeKey(){return O()},get path(){return String(d().file||"")},get patch(){return String(d().patch||"")},get viewMode(){return e.diffViewMode()},get contextMode(){return e.diffContextMode()},get wordWrap(){return e.diffWordWrapMode()}})}})})),t})(),y=()=>(()=>{var t=Q();return a(t,V),t})();return c(H,{get header(){return[(()=>{var t=U(),r=t.firstChild;return a(r,A),L(()=>w(t,"title",A())),t})(),(()=>{var t=X(),r=t.firstChild,d=r.firstChild;d.firstChild;var s=r.nextSibling,u=s.firstChild;return u.firstChild,a(d,()=>i.additions,null),a(u,()=>i.deletions,null),t})(),(()=>{var t=Y();return a(t,c(G,{get viewMode(){return e.diffViewMode()},get contextMode(){return e.diffContextMode()},get wordWrapMode(){return e.diffWordWrapMode()},get onViewModeChange(){return e.onViewModeChange},get onContextModeChange(){return e.onContextModeChange},get onWordWrapModeChange(){return e.onWordWrapModeChange}})),t})()]},list:{panel:()=>c(W,{get when(){return n.length>0},get fallback(){return y()},get children(){return c(F,{each:n,children:t=>(()=>{var r=E(),d=r.firstChild,s=d.firstChild,u=s.firstChild,b=s.nextSibling,h=b.firstChild;h.firstChild;var C=h.nextSibling;return C.firstChild,r.$$click=()=>{e.onSelectFile(t.file,e.isPhoneLayout())},a(u,()=>t.file),a(h,()=>t.additions,null),a(C,()=>t.deletions,null),L(o=>{var _=`file-list-item ${(l==null?void 0:l.file)===t.file?"file-list-item-active":""}`,$=t.file;return _!==o.e&&z(r,o.e=_),$!==o.t&&w(s,"title",o.t=$),o},{e:void 0,t:void 0}),r})()})}}),overlay:()=>c(W,{get when(){return n.length>0},get fallback(){return y()},get children(){return c(F,{each:n,children:t=>(()=>{var r=E(),d=r.firstChild,s=d.firstChild,u=s.firstChild,b=s.nextSibling,h=b.firstChild;h.firstChild;var C=h.nextSibling;return C.firstChild,r.$$click=()=>{e.onSelectFile(t.file,!0)},a(u,()=>t.file),a(h,()=>t.additions,null),a(C,()=>t.deletions,null),L(o=>{var _=`file-list-item ${(l==null?void 0:l.file)===t.file?"file-list-item-active":""}`,$=t.file,p=t.file;return _!==o.e&&z(r,o.e=_),$!==o.t&&w(r,"title",o.t=$),p!==o.a&&w(s,"title",o.a=p),o},{e:void 0,t:void 0,a:void 0}),r})()})}})},get viewer(){return v()},get listOpen(){return e.listOpen()},get onToggleList(){return e.onToggleList},get splitWidth(){return e.splitWidth()},get onResizeMouseDown(){return e.onResizeMouseDown},get onResizeTouchStart(){return e.onResizeTouchStart},get isPhoneLayout(){return e.isPhoneLayout()},get overlayAriaLabel(){return e.t("instanceShell.rightPanel.tabs.changes")}})})};N(["click"]);export{ce as default};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{t as g,i as c,m as W,d as i,a as S,f as C}from"./monaco-viewer-
|
|
1
|
+
import{t as g,i as c,m as W,d as i,a as S,f as C}from"./monaco-viewer-B3iAKbO0.js";import{u as T}from"./index-Bo2Zanex.js";import{n as o,m as $,a as V}from"./git-diff-vendor-CSgooKT_.js";import{I as U,S as A,N as I}from"./main-CuHfodsk.js";import{A as N}from"./align-justify-CK6TIjhy.js";import{W as D}from"./wrap-text-DL9Owbno.js";const E=[["path",{d:"M12 22v-6",key:"6o8u61"}],["path",{d:"M12 8V2",key:"1wkif3"}],["path",{d:"M4 12H2",key:"rhcxmi"}],["path",{d:"M10 12H8",key:"s88cx1"}],["path",{d:"M16 12h-2",key:"10asgb"}],["path",{d:"M22 12h-2",key:"14jgyd"}],["path",{d:"m15 19-3 3-3-3",key:"11eu04"}],["path",{d:"m15 5-3-3-3 3",key:"itvq4r"}]],F=t=>o(U,$(t,{name:"UnfoldVertical",iconNode:E}));var H=g("<div class=file-viewer-toolbar><button type=button class=file-viewer-toolbar-icon-button></button><button type=button class=file-viewer-toolbar-icon-button></button><button type=button>");const B=t=>{const{t:a}=T(),d=()=>t.viewMode==="split"?"unified":"split",s=()=>t.contextMode==="collapsed"?"expanded":"collapsed",f=()=>t.wordWrapMode==="on"?"off":"on",h=()=>d()==="split"?a("instanceShell.diff.switchToSplit"):a("instanceShell.diff.switchToUnified"),v=()=>s()==="collapsed"?a("instanceShell.diff.hideUnchanged"):a("instanceShell.diff.showFull"),u=()=>f()==="on"?a("instanceShell.diff.enableWordWrap"):a("instanceShell.diff.disableWordWrap");return(()=>{var b=H(),n=b.firstChild,l=n.nextSibling,r=l.nextSibling;return n.$$click=()=>t.onViewModeChange(d()),c(n,(()=>{var e=W(()=>d()==="split");return()=>e()?o(A,{class:"h-4 w-4","aria-hidden":"true"}):o(N,{class:"h-4 w-4","aria-hidden":"true"})})()),l.$$click=()=>t.onContextModeChange(s()),c(l,(()=>{var e=W(()=>s()==="collapsed");return()=>e()?o(I,{class:"h-4 w-4","aria-hidden":"true"}):o(F,{class:"h-4 w-4","aria-hidden":"true"})})()),r.$$click=()=>t.onWordWrapModeChange(f()),c(r,o(D,{class:"h-4 w-4","aria-hidden":"true"})),V(e=>{var m=h(),w=h(),M=v(),p=v(),x=`file-viewer-toolbar-icon-button${t.wordWrapMode==="on"?" active":""}`,k=u(),y=u();return m!==e.e&&i(n,"aria-label",e.e=m),w!==e.t&&i(n,"title",e.t=w),M!==e.a&&i(l,"aria-label",e.a=M),p!==e.o&&i(l,"title",e.o=p),x!==e.i&&S(r,e.i=x),k!==e.n&&i(r,"aria-label",e.n=k),y!==e.s&&i(r,"title",e.s=y),e},{e:void 0,t:void 0,a:void 0,o:void 0,i:void 0,n:void 0,s:void 0}),b})()};C(["click"]);export{B as D};
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["assets/monaco-viewer-
|
|
2
|
-
import{_ as G}from"./index-
|
|
1
|
+
const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["assets/monaco-viewer-B3iAKbO0.js","assets/git-diff-vendor-CSgooKT_.js","assets/fast-diff-vendor-DgdwVvTQ.js","assets/highlight-vendor-8FKMu9os.js","assets/git-diff-vendor-HAZkIolJ.css"])))=>i.map(i=>d[i]);
|
|
2
|
+
import{_ as G}from"./index-Bo2Zanex.js";import{Z as J,m,t as h,i as s,d as u,a as C,u as U,f as X}from"./monaco-viewer-B3iAKbO0.js";import{n as o,m as Y,d as A,b as P,c as $,S as g,a as w,z as p,A as ee,F as te}from"./git-diff-vendor-CSgooKT_.js";import{S as le}from"./SplitFilePanel-BnKNINzw.js";import{I as ne,R as K,M as re,O as ae,C as ie,e as se,P as oe}from"./main-CuHfodsk.js";import{W as ce}from"./wrap-text-DL9Owbno.js";import"./fast-diff-vendor-DgdwVvTQ.js";import"./highlight-vendor-8FKMu9os.js";const de=[["path",{d:"M19 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h11l5 5v11a2 2 0 0 1-2 2z",key:"1owoqh"}],["polyline",{points:"17 21 17 13 7 13 7 21",key:"1md35c"}],["polyline",{points:"7 3 7 8 15 8",key:"8nz8an"}]],he=e=>o(ne,Y(e,{name:"Save",iconNode:de}));var ue=h('<div class="px-2 py-2 border-b border-base"><div class=selector-input-group><div class="flex items-center gap-2 px-3 text-muted"></div><input type=text class=selector-input>'),ve=h("<div class=file-list-header><span class=file-list-title></span><span class=file-list-count>"),O=h('<div class="p-3 text-xs text-secondary">'),fe=h("<div class=file-list-item><div class=file-list-item-content><div class=file-list-item-path><span class=file-path-text>.."),ge=h('<div class="p-3 text-xs text-error">'),we=h('<div><div class=file-list-item-content><div class=file-list-item-path><span class=file-path-text></span></div><div class="flex items-center gap-2 shrink-0"><div class=file-list-item-stats><span class="text-[10px] text-secondary"></span></div><button type=button class=git-change-row-action>'),k=h("<div class=file-viewer-empty><span class=file-viewer-empty-text>"),Se=h('<div class="file-viewer-panel flex-1"><div>'),be=h('<div class="h-full outline-none"tabindex=0>'),me=h("<span>"),$e=h("<div class=files-tab-stats><span class=files-tab-stat><span class=files-tab-selected-path><span class=file-path-text>"),ye=h("<button type=button style=margin-inline-start:auto>"),_e=h("<button type=button>"),q=h("<button type=button class=files-header-icon-button>"),Ce=h("<span class=text-error>");const ke=ee(()=>G(()=>import("./monaco-viewer-B3iAKbO0.js").then(e=>e.ae),__vite__mapDeps([0,1,2,3,4])).then(e=>({default:e.MonacoFileViewer})));function xe(e){return e?/\.(md|markdown|mdown|mkdn)$/i.test(e):!1}const Ie=e=>{const[E,L]=A(""),{isDark:N}=J(),[Q,M]=A(!1);let S;P(()=>{e.browserPath(),L("")});const H=$(()=>[...e.browserEntries()||[]].sort((i,d)=>{const l=i.type==="directory"?0:1,t=d.type==="directory"?0:1;return l!==t?l-t:String(i.name||"").localeCompare(String(d.name||""))})),W=$(()=>E().trim().toLowerCase()),x=$(()=>{const n=W(),i=H();return n?i.filter(d=>String(d.name||"").toLowerCase().includes(n)):i}),y=()=>e.browserLoading()&&e.browserEntries()===null,Z=()=>W()?e.t("instanceShell.filesShell.search.empty"):e.t("instanceShell.filesShell.listEmpty"),_=$(()=>xe(e.browserSelectedPath())),b=$(()=>_()&&Q());P(()=>{_()||M(!1)});const D=()=>{const n=e.browserSelectedContent();n!=null&&e.onSave(n)},j=async(n,i)=>{i==null||i.stopPropagation();const d=await se(n);oe({message:d?e.t("instanceShell.filesShell.toast.copyPathSuccess"):e.t("instanceShell.filesShell.toast.copyPathError"),variant:d?"success":"error"})};P(()=>{b()&&requestAnimationFrame(()=>S==null?void 0:S.focus())});const T=()=>[(()=>{var n=ue(),i=n.firstChild,d=i.firstChild,l=d.nextSibling;return s(d,o(ae,{class:"w-4 h-4"})),l.$$input=t=>L(t.currentTarget.value),w(t=>{var a=e.t("instanceShell.filesShell.search.placeholder"),r=e.t("instanceShell.filesShell.search.ariaLabel");return a!==t.e&&u(l,"placeholder",t.e=a),r!==t.t&&u(l,"aria-label",t.t=r),t},{e:void 0,t:void 0}),w(()=>l.value=E()),n})(),(()=>{var n=ve(),i=n.firstChild,d=i.nextSibling;return s(i,()=>e.t("instanceShell.filesShell.fileListTitle")),s(d,()=>x().length),n})(),o(g,{get when(){return e.parentPath()},children:n=>(()=>{var i=fe(),d=i.firstChild,l=d.firstChild;return i.$$click=()=>e.onLoadEntries(n()),w(()=>u(l,"title",n())),i})()}),o(g,{get when(){return y()},get children(){var n=O();return s(n,()=>e.t("instanceInfo.loading")),n}}),o(g,{get when(){return m(()=>!e.browserError()&&!y())()&&x().length>0},get fallback(){return m(()=>!y())()?m(()=>!!e.browserError())()?(()=>{var n=ge();return s(n,()=>e.browserError()),n})():(()=>{var n=O();return s(n,Z),n})():void 0},get children(){return o(te,{get each(){return x()},children:n=>(()=>{var i=we(),d=i.firstChild,l=d.firstChild,t=l.firstChild,a=l.nextSibling,r=a.firstChild,c=r.firstChild,f=r.nextSibling;return i.$$click=()=>{if(n.type==="directory"){e.onLoadEntries(n.path);return}e.onRequestOpenFile(n.path)},s(t,()=>n.name),s(c,()=>n.type),f.$$click=v=>void j(n.path,v),s(f,o(ie,{class:"w-3 h-3"})),w(v=>{var F=`file-list-item ${e.browserSelectedPath()===n.path?"file-list-item-active":""}`,z=n.path,I=n.path,R=e.t("instanceShell.filesShell.actions.copyPath"),V=e.t("instanceShell.filesShell.actions.copyPath");return F!==v.e&&C(i,v.e=F),z!==v.t&&u(i,"title",v.t=z),I!==v.a&&u(l,"title",v.a=I),R!==v.o&&u(f,"title",v.o=R),V!==v.i&&u(f,"aria-label",v.i=V),v},{e:void 0,t:void 0,a:void 0,o:void 0,i:void 0}),i})()})}})],B=n=>{!(n.ctrlKey||n.metaKey)||n.key.toLowerCase()!=="s"||e.browserSelectedSaving()||!e.browserSelectedDirty()||(n.preventDefault(),D())};return m(()=>{const n=()=>e.browserSelectedPath()||e.browserPath(),i=()=>y()?e.t("instanceInfo.loading"):e.t("instanceShell.filesShell.viewerEmpty"),d=()=>(()=>{var l=Se(),t=l.firstChild;return s(t,o(g,{get when(){return e.browserSelectedLoading()},get fallback(){return o(g,{get when(){return e.browserSelectedError()},get fallback(){return o(g,{get when(){return m(()=>!!(e.browserSelectedPath()&&e.browserSelectedContent()!==null))()?{path:e.browserSelectedPath(),content:e.browserSelectedContent()}:null},get fallback(){return(()=>{var a=k(),r=a.firstChild;return s(r,i),a})()},children:a=>o(g,{get when(){return b()},get fallback(){return o(p,{get fallback(){return(()=>{var r=k(),c=r.firstChild;return s(c,()=>e.t("instanceInfo.loading")),r})()},get children(){return o(ke,{get scopeKey(){return e.scopeKey()},get path(){return a().path},get content(){return a().content},get wordWrap(){return e.wordWrapMode()},get onSave(){return e.onSave},get onContentChange(){return e.onContentChange}})}})},get children(){var r=be();r.$$mousedown=()=>S==null?void 0:S.focus(),r.$$keydown=B;var c=S;return typeof c=="function"?U(c,r):S=r,s(r,o(re,{get part(){return{type:"text",text:a().content}},get isDark(){return N()},escapeRawHtml:!0})),r}})})},children:a=>(()=>{var r=k(),c=r.firstChild;return s(c,a),r})()})},get children(){var a=k(),r=a.firstChild;return s(r,()=>e.t("instanceInfo.loading")),a}})),w(()=>C(t,b()?"file-viewer-content":"file-viewer-content file-viewer-content--monaco")),l})();return o(le,{get header(){return[(()=>{var l=$e(),t=l.firstChild,a=t.firstChild,r=a.firstChild;return s(r,n),s(l,o(g,{get when(){return e.browserLoading()},get children(){var c=me();return s(c,()=>e.t("instanceInfo.loading")),c}}),null),s(l,o(g,{get when(){return e.browserError()},children:c=>(()=>{var f=Ce();return s(f,c),f})()}),null),w(()=>u(a,"title",n())),l})(),(()=>{var l=ye();return l.$$click=()=>_()&&M(t=>!t),s(l,(()=>{var t=m(()=>!!b());return()=>t()?e.t("instanceShell.filesShell.showSource"):e.t("instanceShell.filesShell.previewMarkdown")})()),w(t=>{var a=`file-viewer-toolbar-button${b()?" active":""}`,r=!_();return a!==t.e&&C(l,t.e=a),r!==t.t&&(l.disabled=t.t=r),t},{e:void 0,t:void 0}),l})(),(()=>{var l=_e();return l.$$click=()=>e.onWordWrapModeChange(e.wordWrapMode()==="on"?"off":"on"),s(l,o(ce,{class:"h-4 w-4"})),w(t=>{var a=`file-viewer-toolbar-icon-button${e.wordWrapMode()==="on"?" active":""}`,r=e.wordWrapMode()==="on"?e.t("instanceShell.filesShell.disableWordWrap"):e.t("instanceShell.filesShell.enableWordWrap"),c=e.wordWrapMode()==="on"?e.t("instanceShell.filesShell.disableWordWrap"):e.t("instanceShell.filesShell.enableWordWrap"),f=b();return a!==t.e&&C(l,t.e=a),r!==t.t&&u(l,"title",t.t=r),c!==t.a&&u(l,"aria-label",t.a=c),f!==t.o&&(l.disabled=t.o=f),t},{e:void 0,t:void 0,a:void 0,o:void 0}),l})(),(()=>{var l=q();return l.$$click=D,s(l,o(g,{get when(){return e.browserSelectedSaving()},get fallback(){return o(he,{class:"h-4 w-4"})},get children(){return o(K,{class:"h-4 w-4 animate-spin"})}})),w(t=>{var a=e.t("instanceShell.rightPanel.actions.save")||"Save (Ctrl+S)",r=e.t("instanceShell.rightPanel.actions.save")||"Save",c=e.browserSelectedSaving()||!e.browserSelectedDirty();return a!==t.e&&u(l,"title",t.e=a),r!==t.t&&u(l,"aria-label",t.t=r),c!==t.a&&(l.disabled=t.a=c),t},{e:void 0,t:void 0,a:void 0}),l})(),(()=>{var l=q();return l.$$click=()=>e.onRefresh(),s(l,o(K,{get class(){return`h-4 w-4${e.browserLoading()?" animate-spin":""}`}})),w(t=>{var a=e.t("instanceShell.rightPanel.actions.refresh"),r=e.t("instanceShell.rightPanel.actions.refresh"),c=e.browserLoading();return a!==t.e&&u(l,"title",t.e=a),r!==t.t&&u(l,"aria-label",t.t=r),c!==t.a&&(l.disabled=t.a=c),t},{e:void 0,t:void 0,a:void 0}),l})()]},list:{panel:()=>o(T,{}),overlay:()=>o(T,{})},get viewer(){return d()},get listOpen(){return e.listOpen()},get onToggleList(){return e.onToggleList},get splitWidth(){return e.splitWidth()},get onResizeMouseDown(){return e.onResizeMouseDown},get onResizeTouchStart(){return e.onResizeTouchStart},get isPhoneLayout(){return e.isPhoneLayout()},get overlayAriaLabel(){return e.t("instanceShell.rightPanel.tabs.files")}})})};X(["input","click","keydown","mousedown"]);export{Ie as default};
|