@neuralnomads/codenomad-dev 0.10.3-dev-20260213-ba418a85 → 0.10.3-dev-20260213-e9f281a6

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.
Files changed (79) hide show
  1. package/package.json +1 -1
  2. package/public/apple-touch-icon-180x180.png +0 -0
  3. package/public/assets/{main-CSlDZj4f.js → main-crtt5pqm.js} +82 -80
  4. package/public/index.html +1 -1
  5. package/public/sw.js +1 -1
  6. package/public/ui-version.json +1 -1
  7. package/dist/integrations/github/bot-signature.js +0 -11
  8. package/dist/integrations/github/git-ops.js +0 -133
  9. package/dist/integrations/github/github-types.js +0 -1
  10. package/dist/integrations/github/job-runner.js +0 -608
  11. package/dist/integrations/github/octokit.js +0 -58
  12. package/dist/integrations/github/sanitize-webhook.js +0 -42
  13. package/dist/integrations/github/webhook-verify.js +0 -21
  14. package/dist/integrations/github/workspace-context.js +0 -10
  15. package/dist/integrations/github/worktree-context.js +0 -15
  16. package/dist/opencode/request-context.js +0 -39
  17. package/dist/opencode/worktree-directory.js +0 -42
  18. package/dist/opencode-config-template/README.md +0 -32
  19. package/dist/opencode-config-template/opencode.jsonc +0 -3
  20. package/dist/opencode-config-template/plugin/codenomad.ts +0 -40
  21. package/dist/opencode-config-template/plugin/lib/background-process.ts +0 -160
  22. package/dist/opencode-config-template/plugin/lib/client.ts +0 -165
  23. package/dist/server/routes/github-plugin.js +0 -215
  24. package/dist/server/routes/github-webhook.js +0 -32
  25. package/scripts/copy-auth-pages.mjs +0 -22
  26. package/scripts/copy-opencode-config.mjs +0 -61
  27. package/scripts/copy-ui-dist.mjs +0 -21
  28. package/src/api-types.ts +0 -326
  29. package/src/auth/auth-store.ts +0 -175
  30. package/src/auth/http-auth.ts +0 -38
  31. package/src/auth/manager.ts +0 -163
  32. package/src/auth/password-hash.ts +0 -49
  33. package/src/auth/session-manager.ts +0 -23
  34. package/src/auth/token-manager.ts +0 -32
  35. package/src/background-processes/manager.ts +0 -519
  36. package/src/bin.ts +0 -29
  37. package/src/config/binaries.ts +0 -192
  38. package/src/config/location.ts +0 -78
  39. package/src/config/schema.ts +0 -104
  40. package/src/config/store.ts +0 -244
  41. package/src/events/bus.ts +0 -45
  42. package/src/filesystem/__tests__/search-cache.test.ts +0 -61
  43. package/src/filesystem/browser.ts +0 -353
  44. package/src/filesystem/search-cache.ts +0 -66
  45. package/src/filesystem/search.ts +0 -184
  46. package/src/index.ts +0 -540
  47. package/src/launcher.ts +0 -177
  48. package/src/loader.ts +0 -21
  49. package/src/logger.ts +0 -133
  50. package/src/opencode-config.ts +0 -31
  51. package/src/plugins/channel.ts +0 -55
  52. package/src/plugins/handlers.ts +0 -36
  53. package/src/releases/dev-release-monitor.ts +0 -118
  54. package/src/releases/release-monitor.ts +0 -149
  55. package/src/server/http-server.ts +0 -693
  56. package/src/server/network-addresses.ts +0 -75
  57. package/src/server/routes/auth-pages/login.html +0 -134
  58. package/src/server/routes/auth-pages/token.html +0 -93
  59. package/src/server/routes/auth.ts +0 -164
  60. package/src/server/routes/background-processes.ts +0 -85
  61. package/src/server/routes/config.ts +0 -76
  62. package/src/server/routes/events.ts +0 -61
  63. package/src/server/routes/filesystem.ts +0 -54
  64. package/src/server/routes/meta.ts +0 -58
  65. package/src/server/routes/plugin.ts +0 -75
  66. package/src/server/routes/storage.ts +0 -66
  67. package/src/server/routes/workspaces.ts +0 -113
  68. package/src/server/routes/worktrees.ts +0 -195
  69. package/src/server/tls.ts +0 -283
  70. package/src/storage/instance-store.ts +0 -64
  71. package/src/ui/__tests__/remote-ui.test.ts +0 -58
  72. package/src/ui/remote-ui.ts +0 -571
  73. package/src/workspaces/git-worktrees.ts +0 -241
  74. package/src/workspaces/instance-events.ts +0 -226
  75. package/src/workspaces/manager.ts +0 -493
  76. package/src/workspaces/opencode-auth.ts +0 -22
  77. package/src/workspaces/runtime.ts +0 -428
  78. package/src/workspaces/worktree-map.ts +0 -129
  79. package/tsconfig.json +0 -17
@@ -1,215 +0,0 @@
1
- import path from "path";
2
- import { z } from "zod";
3
- import { getGitHubWorkspaceContext } from "../../integrations/github/workspace-context";
4
- import { getGitHubWorktreeContext } from "../../integrations/github/worktree-context";
5
- import { createInstallationOctokit, getInstallationToken } from "../../integrations/github/octokit";
6
- import { gitCurrentBranch, gitIsClean, gitPushHead } from "../../integrations/github/git-ops";
7
- import { listWorktrees, resolveRepoRoot } from "../../workspaces/git-worktrees";
8
- import { sanitizeGitHubWebhookPayload } from "../../integrations/github/sanitize-webhook";
9
- import { appendCodeNomadBotSignature } from "../../integrations/github/bot-signature";
10
- const AddReactionSchema = z.object({
11
- op: z.literal("add_reaction"),
12
- commentId: z.number().int().positive(),
13
- content: z.enum(["eyes", "rocket", "+1", "-1", "laugh", "confused", "heart", "hooray"]),
14
- });
15
- const PostIssueCommentSchema = z.object({
16
- op: z.literal("post_issue_comment"),
17
- issueNumber: z.number().int().positive(),
18
- body: z.string().min(1),
19
- });
20
- const PublishPrSchema = z.object({
21
- op: z.literal("publish_pr"),
22
- directory: z.string().min(1),
23
- title: z.string().min(1),
24
- body: z.string().optional(),
25
- base: z.string().optional(),
26
- draft: z.boolean().optional(),
27
- });
28
- const ListIssueCommentsSchema = z.object({
29
- op: z.literal("list_issue_comments"),
30
- issueNumber: z.number().int().positive(),
31
- });
32
- const GitHubToolSchema = z.discriminatedUnion("op", [
33
- AddReactionSchema,
34
- PostIssueCommentSchema,
35
- PublishPrSchema,
36
- ListIssueCommentsSchema,
37
- ]);
38
- export function registerGitHubPluginRoutes(app, deps) {
39
- app.post("/workspaces/:id/plugin/integrations/github", async (request, reply) => {
40
- const workspaceId = request.params.id;
41
- const workspace = deps.workspaceManager.get(workspaceId);
42
- if (!workspace) {
43
- reply.code(404);
44
- return { error: "Workspace not found" };
45
- }
46
- const context = getGitHubWorkspaceContext(workspaceId);
47
- if (!context) {
48
- reply.code(400);
49
- return { error: "Workspace is not configured for GitHub" };
50
- }
51
- const gh = deps.configStore.get().integrations?.github;
52
- if (!gh?.enabled || !gh.appId || !gh.privateKeyPath) {
53
- reply.code(400);
54
- return { error: "GitHub integration is not configured" };
55
- }
56
- let parsed;
57
- try {
58
- parsed = GitHubToolSchema.parse(request.body ?? {});
59
- }
60
- catch (error) {
61
- reply.code(400);
62
- return { error: error instanceof Error ? error.message : "Invalid GitHub tool request" };
63
- }
64
- const installationId = context.installationId;
65
- const token = await getInstallationToken({ appId: gh.appId, privateKeyPath: gh.privateKeyPath }, installationId);
66
- const octokit = createInstallationOctokit({ appId: gh.appId, privateKeyPath: gh.privateKeyPath }, installationId);
67
- const owner = context.owner;
68
- const repo = context.repo;
69
- const defaultBase = context.defaultBranch;
70
- try {
71
- if (parsed.op === "add_reaction") {
72
- const reaction = await octokit.request("POST /repos/{owner}/{repo}/issues/comments/{comment_id}/reactions", {
73
- owner,
74
- repo,
75
- comment_id: parsed.commentId,
76
- content: parsed.content,
77
- headers: { accept: "application/vnd.github+json" },
78
- });
79
- return { ok: true, op: "add_reaction", data: sanitizeGitHubWebhookPayload(reaction.data) };
80
- }
81
- if (parsed.op === "post_issue_comment") {
82
- const body = appendCodeNomadBotSignature(parsed.body);
83
- const res = await octokit.request("POST /repos/{owner}/{repo}/issues/{issue_number}/comments", {
84
- owner,
85
- repo,
86
- issue_number: parsed.issueNumber,
87
- body,
88
- });
89
- return { ok: true, op: "post_issue_comment", url: res.data?.html_url, data: sanitizeGitHubWebhookPayload(res.data) };
90
- }
91
- if (parsed.op === "list_issue_comments") {
92
- const all = [];
93
- let page = 1;
94
- const perPage = 100;
95
- while (true) {
96
- const res = await octokit.request("GET /repos/{owner}/{repo}/issues/{issue_number}/comments", {
97
- owner,
98
- repo,
99
- issue_number: parsed.issueNumber,
100
- per_page: perPage,
101
- page,
102
- });
103
- const items = Array.isArray(res.data) ? res.data : [];
104
- for (const item of items) {
105
- all.push({
106
- id: item.id,
107
- html_url: item.html_url,
108
- user: {
109
- login: item?.user?.login,
110
- type: item?.user?.type,
111
- },
112
- created_at: item.created_at,
113
- updated_at: item.updated_at,
114
- body: item.body,
115
- });
116
- }
117
- if (items.length < perPage)
118
- break;
119
- page += 1;
120
- if (page > 50)
121
- break;
122
- }
123
- return { ok: true, op: "list_issue_comments", data: all };
124
- }
125
- if (parsed.op === "publish_pr") {
126
- let base = parsed.base ?? defaultBase;
127
- const absDir = path.resolve(parsed.directory);
128
- const workspaceRoot = path.resolve(workspace.path);
129
- const rel = path.relative(workspaceRoot, absDir);
130
- if (rel === "" || (!rel.startsWith("..") && !path.isAbsolute(rel))) {
131
- // ok
132
- }
133
- else {
134
- reply.code(400);
135
- return { error: "Invalid directory" };
136
- }
137
- // If base isn't provided, prefer a worktree-specific default base for this run.
138
- if (!parsed.base) {
139
- try {
140
- const { repoRoot, isGitRepo } = await resolveRepoRoot(workspace.path, deps.logger);
141
- if (isGitRepo) {
142
- const worktrees = await listWorktrees({ repoRoot, workspaceFolder: workspace.path, logger: deps.logger });
143
- const match = worktrees.find((wt) => path.resolve(wt.directory) === absDir);
144
- if (match) {
145
- const ctx = getGitHubWorktreeContext(workspaceId, match.slug);
146
- if (ctx?.publishBase) {
147
- base = ctx.publishBase;
148
- }
149
- }
150
- }
151
- }
152
- catch {
153
- // best-effort
154
- }
155
- }
156
- const branch = await gitCurrentBranch(absDir);
157
- if (!branch) {
158
- reply.code(400);
159
- return { error: "No current branch" };
160
- }
161
- const clean = await gitIsClean(absDir);
162
- if (!clean) {
163
- reply.code(400);
164
- return { error: "Working tree has uncommitted changes" };
165
- }
166
- await gitPushHead({ cwd: absDir, remoteUrl: context.repoUrl, branch, token });
167
- let prUrl;
168
- let prNumber;
169
- let pr;
170
- try {
171
- const created = await octokit.request("POST /repos/{owner}/{repo}/pulls", {
172
- owner,
173
- repo,
174
- title: parsed.title,
175
- body: parsed.body ? appendCodeNomadBotSignature(parsed.body) : undefined,
176
- head: branch,
177
- base,
178
- draft: parsed.draft ?? false,
179
- });
180
- prUrl = created.data?.html_url;
181
- prNumber = created.data?.number;
182
- pr = created.data;
183
- }
184
- catch (error) {
185
- // If a PR already exists for this head, surface the existing PR.
186
- const status = error?.status;
187
- if (status === 422) {
188
- const head = `${owner}:${branch}`;
189
- const existing = await octokit.request("GET /repos/{owner}/{repo}/pulls", {
190
- owner,
191
- repo,
192
- state: "open",
193
- head,
194
- });
195
- const first = Array.isArray(existing.data) ? existing.data[0] : null;
196
- prUrl = first?.html_url;
197
- prNumber = first?.number;
198
- pr = first;
199
- }
200
- else {
201
- throw error;
202
- }
203
- }
204
- return { ok: true, op: "publish_pr", branch, url: prUrl, number: prNumber, base, data: sanitizeGitHubWebhookPayload(pr) };
205
- }
206
- reply.code(400);
207
- return { error: "Unknown operation" };
208
- }
209
- catch (error) {
210
- deps.logger.error({ err: error, workspaceId, op: parsed?.op }, "GitHub tool call failed");
211
- reply.code(500);
212
- return { error: error instanceof Error ? error.message : "GitHub operation failed" };
213
- }
214
- });
215
- }
@@ -1,32 +0,0 @@
1
- import { GitHubJobRunner } from "../../integrations/github/job-runner";
2
- export function registerGitHubWebhookRoutes(app, deps) {
3
- // Ensure info-level GitHub lifecycle logs are visible at CLI_LOG_LEVEL=info.
4
- const log = deps.logger.child({ component: "app", module: "github" });
5
- const runner = new GitHubJobRunner({
6
- workspaceManager: deps.workspaceManager,
7
- configStore: deps.configStore,
8
- eventBus: deps.eventBus,
9
- logger: log,
10
- });
11
- app.register(async (instance) => {
12
- instance.addContentTypeParser("application/json", { parseAs: "buffer" }, (_req, body, done) => done(null, body));
13
- instance.post("/integrations/github/webhook", async (request, reply) => {
14
- const event = request.headers["x-github-event"] ?? "";
15
- const delivery = request.headers["x-github-delivery"] ?? "";
16
- const signature = request.headers["x-hub-signature-256"] ?? undefined;
17
- const body = request.body;
18
- if (!Buffer.isBuffer(body)) {
19
- reply.code(400).type("text/plain").send("Expected raw JSON body");
20
- return;
21
- }
22
- log.info({ event, deliveryId: delivery }, "GitHub webhook received");
23
- runner.enqueue({
24
- deliveryId: delivery,
25
- event,
26
- signature,
27
- body,
28
- });
29
- reply.code(202).send({ ok: true });
30
- });
31
- });
32
- }
@@ -1,22 +0,0 @@
1
- #!/usr/bin/env node
2
- import { cpSync, existsSync, mkdirSync, rmSync } from "fs"
3
- import path from "path"
4
- import { fileURLToPath } from "url"
5
-
6
- const __filename = fileURLToPath(import.meta.url)
7
- const __dirname = path.dirname(__filename)
8
- const cliRoot = path.resolve(__dirname, "..")
9
-
10
- const sourceDir = path.resolve(cliRoot, "src/server/routes/auth-pages")
11
- const targetDir = path.resolve(cliRoot, "dist/server/routes/auth-pages")
12
-
13
- if (!existsSync(sourceDir)) {
14
- console.error(`[copy-auth-pages] Missing auth pages at ${sourceDir}`)
15
- process.exit(1)
16
- }
17
-
18
- rmSync(targetDir, { recursive: true, force: true })
19
- mkdirSync(targetDir, { recursive: true })
20
- cpSync(sourceDir, targetDir, { recursive: true })
21
-
22
- console.log(`[copy-auth-pages] Copied ${sourceDir} -> ${targetDir}`)
@@ -1,61 +0,0 @@
1
- #!/usr/bin/env node
2
- import { spawnSync } from "child_process"
3
- import { cpSync, existsSync, mkdirSync, rmSync } from "fs"
4
- import path from "path"
5
- import { fileURLToPath } from "url"
6
-
7
- const __filename = fileURLToPath(import.meta.url)
8
- const __dirname = path.dirname(__filename)
9
- const cliRoot = path.resolve(__dirname, "..")
10
- const sourceDir = path.resolve(cliRoot, "../opencode-config")
11
- const targetDir = path.resolve(cliRoot, "dist/opencode-config")
12
- const nodeModulesDir = path.resolve(sourceDir, "node_modules")
13
- const selfLinkDir = path.resolve(nodeModulesDir, "@codenomad", "opencode-config")
14
- const npmExecPath = process.env.npm_execpath
15
- const npmNodeExecPath = process.env.npm_node_execpath
16
-
17
- if (!existsSync(sourceDir)) {
18
- console.error(`[copy-opencode-config] Missing source directory at ${sourceDir}`)
19
- process.exit(1)
20
- }
21
-
22
- if (!existsSync(nodeModulesDir)) {
23
- console.log(`[copy-opencode-config] Installing opencode-config dependencies in ${sourceDir}`)
24
-
25
- const npmArgs = [
26
- "install",
27
- "--prefix",
28
- sourceDir,
29
- "--omit=dev",
30
- "--ignore-scripts",
31
- "--fund=false",
32
- "--audit=false",
33
- "--package-lock=false",
34
- "--workspaces=false",
35
- ]
36
-
37
- const env = { ...process.env, npm_config_workspaces: "false" }
38
-
39
- const npmCli = npmExecPath && npmNodeExecPath ? [npmNodeExecPath, [npmExecPath, ...npmArgs]] : null
40
- const result = npmCli
41
- ? spawnSync(npmCli[0], npmCli[1], { cwd: sourceDir, stdio: "inherit", env })
42
- : spawnSync("npm", npmArgs, { cwd: sourceDir, stdio: "inherit", env, shell: process.platform === "win32" })
43
-
44
- if (result.status !== 0) {
45
- if (result.error) {
46
- console.error("[copy-opencode-config] npm install failed to start", result.error)
47
- }
48
- console.error("[copy-opencode-config] Failed to install opencode-config dependencies")
49
- process.exit(result.status ?? 1)
50
- }
51
- }
52
-
53
- // npm can create a self-referential link for scoped packages on Windows.
54
- // That link causes recursive copies (ELOOP) during bundling.
55
- rmSync(selfLinkDir, { recursive: true, force: true })
56
-
57
- rmSync(targetDir, { recursive: true, force: true })
58
- mkdirSync(path.dirname(targetDir), { recursive: true })
59
- cpSync(sourceDir, targetDir, { recursive: true })
60
-
61
- console.log(`[copy-opencode-config] Copied ${sourceDir} -> ${targetDir}`)
@@ -1,21 +0,0 @@
1
- #!/usr/bin/env node
2
- import { cpSync, existsSync, mkdirSync, rmSync } from "fs"
3
- import path from "path"
4
- import { fileURLToPath } from "url"
5
-
6
- const __filename = fileURLToPath(import.meta.url)
7
- const __dirname = path.dirname(__filename)
8
- const cliRoot = path.resolve(__dirname, "..")
9
- const uiDistDir = path.resolve(cliRoot, "../ui/src/renderer/dist")
10
- const targetDir = path.resolve(cliRoot, "public")
11
-
12
- if (!existsSync(uiDistDir)) {
13
- console.error(`[copy-ui-dist] Expected UI build artifacts at ${uiDistDir}. Run the UI build before bundling the CLI.`)
14
- process.exit(1)
15
- }
16
-
17
- rmSync(targetDir, { recursive: true, force: true })
18
- mkdirSync(targetDir, { recursive: true })
19
- cpSync(uiDistDir, targetDir, { recursive: true })
20
-
21
- console.log(`[copy-ui-dist] Copied UI bundle from ${uiDistDir} -> ${targetDir}`)
package/src/api-types.ts DELETED
@@ -1,326 +0,0 @@
1
- import type {
2
- AgentModelSelection,
3
- AgentModelSelections,
4
- ConfigFile,
5
- ModelPreference,
6
- OpenCodeBinary,
7
- Preferences,
8
- RecentFolder,
9
- } from "./config/schema"
10
-
11
- /**
12
- * Canonical HTTP/SSE contract for the CLI server.
13
- * These types are consumed by both the CLI implementation and any UI clients.
14
- */
15
-
16
- export type WorkspaceStatus = "starting" | "ready" | "stopped" | "error"
17
-
18
- export interface WorkspaceDescriptor {
19
- id: string
20
- /** Absolute path on the server host. */
21
- path: string
22
- name?: string
23
- status: WorkspaceStatus
24
- /** PID/port are populated when the workspace is running. */
25
- pid?: number
26
- port?: number
27
- /** Canonical proxy path the CLI exposes for this instance. */
28
- proxyPath: string
29
- /** Identifier of the binary resolved from config. */
30
- binaryId: string
31
- binaryLabel: string
32
- binaryVersion?: string
33
- createdAt: string
34
- updatedAt: string
35
- /** Present when `status` is "error". */
36
- error?: string
37
- }
38
-
39
- export interface WorkspaceCreateRequest {
40
- path: string
41
- name?: string
42
- }
43
-
44
- export type WorkspaceCreateResponse = WorkspaceDescriptor
45
- export type WorkspaceListResponse = WorkspaceDescriptor[]
46
- export type WorkspaceDetailResponse = WorkspaceDescriptor
47
-
48
- export interface WorkspaceDeleteResponse {
49
- id: string
50
- status: WorkspaceStatus
51
- }
52
-
53
- export type WorktreeKind = "root" | "worktree"
54
-
55
- export interface WorktreeDescriptor {
56
- /** Stable identifier used by CodeNomad + clients ("root" for repo root). */
57
- slug: string
58
- /** Absolute directory path on the server host. */
59
- directory: string
60
- kind: WorktreeKind
61
- /** Optional VCS branch name when available. */
62
- branch?: string
63
- }
64
-
65
- export interface WorktreeListResponse {
66
- worktrees: WorktreeDescriptor[]
67
- /** True when the workspace folder resolves to a Git repository. */
68
- isGitRepo?: boolean
69
- }
70
-
71
- export interface WorktreeCreateRequest {
72
- slug: string
73
- /** Optional branch name (defaults to slug). */
74
- branch?: string
75
- }
76
-
77
- export interface WorktreeMap {
78
- version: 1
79
- /** Default worktree to use for new sessions and as fallback. */
80
- defaultWorktreeSlug: string
81
- /** Mapping of *parent* session IDs to a worktree slug. */
82
- parentSessionWorktreeSlug: Record<string, string>
83
- }
84
-
85
- export type LogLevel = "debug" | "info" | "warn" | "error"
86
-
87
- export interface WorkspaceLogEntry {
88
- workspaceId: string
89
- timestamp: string
90
- level: LogLevel
91
- message: string
92
- }
93
-
94
- export interface FileSystemEntry {
95
- name: string
96
- /** Path relative to the CLI server root ("." represents the root itself). */
97
- path: string
98
- /** Absolute path when available (unrestricted listings). */
99
- absolutePath?: string
100
- type: "file" | "directory"
101
- size?: number
102
- /** ISO timestamp of last modification when available. */
103
- modifiedAt?: string
104
- }
105
-
106
- export type FileSystemScope = "restricted" | "unrestricted"
107
- export type FileSystemPathKind = "relative" | "absolute" | "drives"
108
-
109
- export interface FileSystemListingMetadata {
110
- scope: FileSystemScope
111
- /** Canonical identifier of the current view ("." for restricted roots, absolute paths otherwise). */
112
- currentPath: string
113
- /** Optional parent path if navigation upward is allowed. */
114
- parentPath?: string
115
- /** Absolute path representing the root or origin point for this listing. */
116
- rootPath: string
117
- /** Absolute home directory of the CLI host (useful defaults for unrestricted mode). */
118
- homePath: string
119
- /** Human-friendly label for the current path. */
120
- displayPath: string
121
- /** Indicates whether entry paths are relative, absolute, or represent drive roots. */
122
- pathKind: FileSystemPathKind
123
- }
124
-
125
- export interface FileSystemListResponse {
126
- entries: FileSystemEntry[]
127
- metadata: FileSystemListingMetadata
128
- }
129
-
130
- export interface FileSystemCreateFolderRequest {
131
- /**
132
- * Path identifier for the currently browsed directory.
133
- * Matches the `path` parameter used for `/api/filesystem`.
134
- */
135
- parentPath?: string
136
- /** Single folder name (no separators). */
137
- name: string
138
- }
139
-
140
- export interface FileSystemCreateFolderResponse {
141
- /**
142
- * Path identifier that can be passed back to `/api/filesystem` to browse the new folder.
143
- * Relative for restricted listings, absolute for unrestricted.
144
- */
145
- path: string
146
- /** Absolute folder path on the server host. */
147
- absolutePath: string
148
- }
149
-
150
- export const WINDOWS_DRIVES_ROOT = "__drives__"
151
-
152
- export interface WorkspaceFileResponse {
153
- workspaceId: string
154
- relativePath: string
155
- /** UTF-8 file contents; binary files should be base64 encoded by the caller. */
156
- contents: string
157
- }
158
-
159
- export type WorkspaceFileSearchResponse = FileSystemEntry[]
160
-
161
- export interface InstanceData {
162
- messageHistory: string[]
163
- agentModelSelections: AgentModelSelection
164
- }
165
-
166
- export type InstanceStreamStatus = "connecting" | "connected" | "error" | "disconnected"
167
-
168
- export interface InstanceStreamEvent {
169
- type: string
170
- properties?: Record<string, unknown>
171
- [key: string]: unknown
172
- }
173
-
174
- export interface BinaryRecord {
175
- id: string
176
- path: string
177
- label: string
178
- version?: string
179
-
180
- /** Indicates that this binary will be picked when workspaces omit an explicit choice. */
181
- isDefault: boolean
182
- lastValidatedAt?: string
183
- validationError?: string
184
- }
185
-
186
- export type AppConfig = ConfigFile
187
- export type AppConfigResponse = AppConfig
188
- export type AppConfigUpdateRequest = Partial<AppConfig>
189
-
190
- export interface BinaryListResponse {
191
- binaries: BinaryRecord[]
192
- }
193
-
194
- export interface BinaryCreateRequest {
195
- path: string
196
- label?: string
197
- makeDefault?: boolean
198
- }
199
-
200
- export interface BinaryUpdateRequest {
201
- label?: string
202
- makeDefault?: boolean
203
- }
204
-
205
- export interface BinaryValidationResult {
206
- valid: boolean
207
- version?: string
208
- error?: string
209
- }
210
-
211
- export type WorkspaceEventType =
212
- | "workspace.created"
213
- | "workspace.started"
214
- | "workspace.error"
215
- | "workspace.stopped"
216
- | "workspace.log"
217
- | "config.appChanged"
218
- | "config.binariesChanged"
219
- | "instance.dataChanged"
220
- | "instance.event"
221
- | "instance.eventStatus"
222
-
223
- export type WorkspaceEventPayload =
224
- | { type: "workspace.created"; workspace: WorkspaceDescriptor }
225
- | { type: "workspace.started"; workspace: WorkspaceDescriptor }
226
- | { type: "workspace.error"; workspace: WorkspaceDescriptor }
227
- | { type: "workspace.stopped"; workspaceId: string }
228
- | { type: "workspace.log"; entry: WorkspaceLogEntry }
229
- | { type: "config.appChanged"; config: AppConfig }
230
- | { type: "config.binariesChanged"; binaries: BinaryRecord[] }
231
- | { type: "instance.dataChanged"; instanceId: string; data: InstanceData }
232
- | { type: "instance.event"; instanceId: string; event: InstanceStreamEvent }
233
- | { type: "instance.eventStatus"; instanceId: string; status: InstanceStreamStatus; reason?: string }
234
-
235
- export interface NetworkAddress {
236
- ip: string
237
- family: "ipv4" | "ipv6"
238
- scope: "external" | "internal" | "loopback"
239
- /** Remote URL using the server's remote protocol/port for this IP. */
240
- remoteUrl: string
241
- }
242
-
243
- export interface LatestReleaseInfo {
244
- version: string
245
- tag: string
246
- url: string
247
- channel: "stable" | "dev"
248
- publishedAt?: string
249
- notes?: string
250
- }
251
-
252
- export interface UiMeta {
253
- version?: string
254
- source: "bundled" | "downloaded" | "previous" | "override" | "dev-proxy" | "missing"
255
- }
256
-
257
- export interface SupportMeta {
258
- supported: boolean
259
- message?: string
260
- minServerVersion?: string
261
- latestServerVersion?: string
262
- latestServerUrl?: string
263
- }
264
-
265
- export interface ServerMeta {
266
- /** URL desktop apps should use to connect (prefers loopback HTTP when enabled). */
267
- localUrl: string
268
- /** URL remote clients should use (prefers HTTPS when enabled). */
269
- remoteUrl?: string
270
- /** SSE endpoint advertised to clients (`/api/events` by default). */
271
- eventsUrl: string
272
- /** Host the server is bound to (e.g., 127.0.0.1 or 0.0.0.0). */
273
- host: string
274
- /** Listening mode derived from host binding. */
275
- listeningMode: "local" | "all"
276
- /** Actual local port in use after binding. */
277
- localPort: number
278
- /** Actual remote port in use after binding (when remoteUrl is set). */
279
- remotePort?: number
280
- /** Display label for the host (e.g., hostname or friendly name). */
281
- hostLabel: string
282
- /** Absolute path of the filesystem root exposed to clients. */
283
- workspaceRoot: string
284
- /** Reachable addresses for this server, external first. */
285
- addresses: NetworkAddress[]
286
- serverVersion?: string
287
- ui?: UiMeta
288
- support?: SupportMeta
289
- /** Optional update info (dev channel only). */
290
- update?: LatestReleaseInfo | null
291
- }
292
-
293
- export type BackgroundProcessStatus = "running" | "stopped" | "error"
294
-
295
- export interface BackgroundProcess {
296
- id: string
297
- workspaceId: string
298
- title: string
299
- command: string
300
- cwd: string
301
- status: BackgroundProcessStatus
302
- pid?: number
303
- startedAt: string
304
- stoppedAt?: string
305
- exitCode?: number
306
- outputSizeBytes?: number
307
- }
308
-
309
- export interface BackgroundProcessListResponse {
310
- processes: BackgroundProcess[]
311
- }
312
-
313
- export interface BackgroundProcessOutputResponse {
314
- id: string
315
- content: string
316
- truncated: boolean
317
- sizeBytes: number
318
- }
319
-
320
- export type {
321
- Preferences,
322
- ModelPreference,
323
- AgentModelSelections,
324
- RecentFolder,
325
- OpenCodeBinary,
326
- }