@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.
- package/package.json +1 -1
- package/public/apple-touch-icon-180x180.png +0 -0
- package/public/assets/{main-CSlDZj4f.js → main-crtt5pqm.js} +82 -80
- package/public/index.html +1 -1
- package/public/sw.js +1 -1
- package/public/ui-version.json +1 -1
- package/dist/integrations/github/bot-signature.js +0 -11
- package/dist/integrations/github/git-ops.js +0 -133
- package/dist/integrations/github/github-types.js +0 -1
- package/dist/integrations/github/job-runner.js +0 -608
- package/dist/integrations/github/octokit.js +0 -58
- package/dist/integrations/github/sanitize-webhook.js +0 -42
- package/dist/integrations/github/webhook-verify.js +0 -21
- package/dist/integrations/github/workspace-context.js +0 -10
- package/dist/integrations/github/worktree-context.js +0 -15
- package/dist/opencode/request-context.js +0 -39
- package/dist/opencode/worktree-directory.js +0 -42
- package/dist/opencode-config-template/README.md +0 -32
- package/dist/opencode-config-template/opencode.jsonc +0 -3
- package/dist/opencode-config-template/plugin/codenomad.ts +0 -40
- package/dist/opencode-config-template/plugin/lib/background-process.ts +0 -160
- package/dist/opencode-config-template/plugin/lib/client.ts +0 -165
- package/dist/server/routes/github-plugin.js +0 -215
- package/dist/server/routes/github-webhook.js +0 -32
- package/scripts/copy-auth-pages.mjs +0 -22
- package/scripts/copy-opencode-config.mjs +0 -61
- package/scripts/copy-ui-dist.mjs +0 -21
- package/src/api-types.ts +0 -326
- package/src/auth/auth-store.ts +0 -175
- package/src/auth/http-auth.ts +0 -38
- package/src/auth/manager.ts +0 -163
- package/src/auth/password-hash.ts +0 -49
- package/src/auth/session-manager.ts +0 -23
- package/src/auth/token-manager.ts +0 -32
- package/src/background-processes/manager.ts +0 -519
- package/src/bin.ts +0 -29
- package/src/config/binaries.ts +0 -192
- package/src/config/location.ts +0 -78
- package/src/config/schema.ts +0 -104
- package/src/config/store.ts +0 -244
- package/src/events/bus.ts +0 -45
- package/src/filesystem/__tests__/search-cache.test.ts +0 -61
- package/src/filesystem/browser.ts +0 -353
- package/src/filesystem/search-cache.ts +0 -66
- package/src/filesystem/search.ts +0 -184
- package/src/index.ts +0 -540
- package/src/launcher.ts +0 -177
- package/src/loader.ts +0 -21
- package/src/logger.ts +0 -133
- package/src/opencode-config.ts +0 -31
- package/src/plugins/channel.ts +0 -55
- package/src/plugins/handlers.ts +0 -36
- package/src/releases/dev-release-monitor.ts +0 -118
- package/src/releases/release-monitor.ts +0 -149
- package/src/server/http-server.ts +0 -693
- package/src/server/network-addresses.ts +0 -75
- package/src/server/routes/auth-pages/login.html +0 -134
- package/src/server/routes/auth-pages/token.html +0 -93
- package/src/server/routes/auth.ts +0 -164
- package/src/server/routes/background-processes.ts +0 -85
- package/src/server/routes/config.ts +0 -76
- package/src/server/routes/events.ts +0 -61
- package/src/server/routes/filesystem.ts +0 -54
- package/src/server/routes/meta.ts +0 -58
- package/src/server/routes/plugin.ts +0 -75
- package/src/server/routes/storage.ts +0 -66
- package/src/server/routes/workspaces.ts +0 -113
- package/src/server/routes/worktrees.ts +0 -195
- package/src/server/tls.ts +0 -283
- package/src/storage/instance-store.ts +0 -64
- package/src/ui/__tests__/remote-ui.test.ts +0 -58
- package/src/ui/remote-ui.ts +0 -571
- package/src/workspaces/git-worktrees.ts +0 -241
- package/src/workspaces/instance-events.ts +0 -226
- package/src/workspaces/manager.ts +0 -493
- package/src/workspaces/opencode-auth.ts +0 -22
- package/src/workspaces/runtime.ts +0 -428
- package/src/workspaces/worktree-map.ts +0 -129
- 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}`)
|
package/scripts/copy-ui-dist.mjs
DELETED
|
@@ -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
|
-
}
|