Compare commits
2
Commits
opencode-2-0
...
node-pty
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0a53f8e084 | ||
|
|
6f5b2f786e |
@@ -365,6 +365,7 @@
|
|||||||
"jsonc-parser": "3.3.1",
|
"jsonc-parser": "3.3.1",
|
||||||
"mime-types": "3.0.2",
|
"mime-types": "3.0.2",
|
||||||
"minimatch": "10.0.3",
|
"minimatch": "10.0.3",
|
||||||
|
"node-pty": "1.1.0",
|
||||||
"open": "10.1.2",
|
"open": "10.1.2",
|
||||||
"opentui-spinner": "0.0.6",
|
"opentui-spinner": "0.0.6",
|
||||||
"partial-json": "0.1.7",
|
"partial-json": "0.1.7",
|
||||||
@@ -575,8 +576,9 @@
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
"trustedDependencies": [
|
"trustedDependencies": [
|
||||||
"electron",
|
|
||||||
"esbuild",
|
"esbuild",
|
||||||
|
"node-pty",
|
||||||
|
"electron",
|
||||||
"web-tree-sitter",
|
"web-tree-sitter",
|
||||||
"tree-sitter-bash",
|
"tree-sitter-bash",
|
||||||
],
|
],
|
||||||
@@ -3813,6 +3815,8 @@
|
|||||||
|
|
||||||
"node-mock-http": ["node-mock-http@1.0.4", "", {}, "sha512-8DY+kFsDkNXy1sJglUfuODx1/opAGJGyrTuFqEoN90oRc2Vk0ZbD4K2qmKXBBEhZQzdKHIVfEJpDU8Ak2NJEvQ=="],
|
"node-mock-http": ["node-mock-http@1.0.4", "", {}, "sha512-8DY+kFsDkNXy1sJglUfuODx1/opAGJGyrTuFqEoN90oRc2Vk0ZbD4K2qmKXBBEhZQzdKHIVfEJpDU8Ak2NJEvQ=="],
|
||||||
|
|
||||||
|
"node-pty": ["node-pty@1.1.0", "", { "dependencies": { "node-addon-api": "^7.1.0" } }, "sha512-20JqtutY6JPXTUnL0ij1uad7Qe1baT46lyolh2sSENDd4sTzKZ4nmAFkeAARDKwmlLjPx6XKRlwRUxwjOy+lUg=="],
|
||||||
|
|
||||||
"node-releases": ["node-releases@2.0.27", "", {}, "sha512-nmh3lCkYZ3grZvqcCH+fjmQ7X+H0OeZgP40OierEaAptX4XofMh5kwNbWh7lBduUzCcV/8kZ+NDLCwm2iorIlA=="],
|
"node-releases": ["node-releases@2.0.27", "", {}, "sha512-nmh3lCkYZ3grZvqcCH+fjmQ7X+H0OeZgP40OierEaAptX4XofMh5kwNbWh7lBduUzCcV/8kZ+NDLCwm2iorIlA=="],
|
||||||
|
|
||||||
"nopt": ["nopt@9.0.0", "", { "dependencies": { "abbrev": "^4.0.0" }, "bin": { "nopt": "bin/nopt.js" } }, "sha512-Zhq3a+yFKrYwSBluL4H9XP3m3y5uvQkB/09CwDruCiRmR/UJYnn9W4R48ry0uGC70aeTPKLynBtscP9efFFcPw=="],
|
"nopt": ["nopt@9.0.0", "", { "dependencies": { "abbrev": "^4.0.0" }, "bin": { "nopt": "bin/nopt.js" } }, "sha512-Zhq3a+yFKrYwSBluL4H9XP3m3y5uvQkB/09CwDruCiRmR/UJYnn9W4R48ry0uGC70aeTPKLynBtscP9efFFcPw=="],
|
||||||
|
|||||||
@@ -11,6 +11,7 @@
|
|||||||
"dev:web": "bun --cwd packages/app dev",
|
"dev:web": "bun --cwd packages/app dev",
|
||||||
"dev:storybook": "bun --cwd packages/storybook storybook",
|
"dev:storybook": "bun --cwd packages/storybook storybook",
|
||||||
"typecheck": "bun turbo typecheck",
|
"typecheck": "bun turbo typecheck",
|
||||||
|
"postinstall": "bun run --cwd packages/opencode fix-node-pty",
|
||||||
"prepare": "husky",
|
"prepare": "husky",
|
||||||
"random": "echo 'Random script'",
|
"random": "echo 'Random script'",
|
||||||
"hello": "echo 'Hello World!'",
|
"hello": "echo 'Hello World!'",
|
||||||
@@ -98,6 +99,7 @@
|
|||||||
},
|
},
|
||||||
"trustedDependencies": [
|
"trustedDependencies": [
|
||||||
"esbuild",
|
"esbuild",
|
||||||
|
"node-pty",
|
||||||
"protobufjs",
|
"protobufjs",
|
||||||
"tree-sitter",
|
"tree-sitter",
|
||||||
"tree-sitter-bash",
|
"tree-sitter-bash",
|
||||||
|
|||||||
@@ -9,6 +9,7 @@
|
|||||||
"typecheck": "tsgo --noEmit",
|
"typecheck": "tsgo --noEmit",
|
||||||
"test": "bun test --timeout 30000 registry",
|
"test": "bun test --timeout 30000 registry",
|
||||||
"build": "bun run script/build.ts",
|
"build": "bun run script/build.ts",
|
||||||
|
"fix-node-pty": "bun run script/fix-node-pty.ts",
|
||||||
"dev": "bun run --conditions=browser ./src/index.ts",
|
"dev": "bun run --conditions=browser ./src/index.ts",
|
||||||
"random": "echo 'Random script updated at $(date)' && echo 'Change queued successfully' && echo 'Another change made' && echo 'Yet another change' && echo 'One more change' && echo 'Final change' && echo 'Another final change' && echo 'Yet another final change'",
|
"random": "echo 'Random script updated at $(date)' && echo 'Change queued successfully' && echo 'Another change made' && echo 'Yet another change' && echo 'One more change' && echo 'Final change' && echo 'Another final change' && echo 'Yet another final change'",
|
||||||
"clean": "echo 'Cleaning up...' && rm -rf node_modules dist",
|
"clean": "echo 'Cleaning up...' && rm -rf node_modules dist",
|
||||||
@@ -30,6 +31,11 @@
|
|||||||
"bun": "./src/storage/db.bun.ts",
|
"bun": "./src/storage/db.bun.ts",
|
||||||
"node": "./src/storage/db.node.ts",
|
"node": "./src/storage/db.node.ts",
|
||||||
"default": "./src/storage/db.bun.ts"
|
"default": "./src/storage/db.bun.ts"
|
||||||
|
},
|
||||||
|
"#pty": {
|
||||||
|
"bun": "./src/pty/pty.bun.ts",
|
||||||
|
"node": "./src/pty/pty.node.ts",
|
||||||
|
"default": "./src/pty/pty.bun.ts"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
@@ -129,6 +135,7 @@
|
|||||||
"jsonc-parser": "3.3.1",
|
"jsonc-parser": "3.3.1",
|
||||||
"mime-types": "3.0.2",
|
"mime-types": "3.0.2",
|
||||||
"minimatch": "10.0.3",
|
"minimatch": "10.0.3",
|
||||||
|
"node-pty": "1.1.0",
|
||||||
"open": "10.1.2",
|
"open": "10.1.2",
|
||||||
"opentui-spinner": "0.0.6",
|
"opentui-spinner": "0.0.6",
|
||||||
"partial-json": "0.1.7",
|
"partial-json": "0.1.7",
|
||||||
|
|||||||
@@ -45,7 +45,7 @@ await Bun.build({
|
|||||||
entrypoints: ["./src/node.ts"],
|
entrypoints: ["./src/node.ts"],
|
||||||
outdir: "./dist",
|
outdir: "./dist",
|
||||||
format: "esm",
|
format: "esm",
|
||||||
external: ["jsonc-parser"],
|
external: ["jsonc-parser", "node-pty"],
|
||||||
define: {
|
define: {
|
||||||
OPENCODE_MIGRATIONS: JSON.stringify(migrations),
|
OPENCODE_MIGRATIONS: JSON.stringify(migrations),
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -0,0 +1,28 @@
|
|||||||
|
#!/usr/bin/env bun
|
||||||
|
|
||||||
|
import fs from "fs/promises"
|
||||||
|
import path from "path"
|
||||||
|
import { fileURLToPath } from "url"
|
||||||
|
|
||||||
|
const __filename = fileURLToPath(import.meta.url)
|
||||||
|
const __dirname = path.dirname(__filename)
|
||||||
|
const dir = path.resolve(__dirname, "..")
|
||||||
|
|
||||||
|
if (process.platform !== "win32") {
|
||||||
|
const root = path.join(dir, "node_modules", "node-pty", "prebuilds")
|
||||||
|
const dirs = await fs.readdir(root, { withFileTypes: true }).catch(() => [])
|
||||||
|
const files = dirs.filter((x) => x.isDirectory()).map((x) => path.join(root, x.name, "spawn-helper"))
|
||||||
|
const result = await Promise.all(
|
||||||
|
files.map(async (file) => {
|
||||||
|
const stat = await fs.stat(file).catch(() => undefined)
|
||||||
|
if (!stat) return
|
||||||
|
if ((stat.mode & 0o111) === 0o111) return
|
||||||
|
await fs.chmod(file, stat.mode | 0o755)
|
||||||
|
return file
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
const fixed = result.filter(Boolean)
|
||||||
|
if (fixed.length) {
|
||||||
|
console.log(`fixed node-pty permissions for ${fixed.length} helper${fixed.length === 1 ? "" : "s"}`)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
import { BusEvent } from "@/bus/bus-event"
|
import { BusEvent } from "@/bus/bus-event"
|
||||||
import { Bus } from "@/bus"
|
import { Bus } from "@/bus"
|
||||||
import { type IPty } from "bun-pty"
|
import type { Proc } from "#pty"
|
||||||
import z from "zod"
|
import z from "zod"
|
||||||
import { Identifier } from "../id/id"
|
import { Identifier } from "../id/id"
|
||||||
import { Log } from "../util/log"
|
import { Log } from "../util/log"
|
||||||
@@ -35,10 +35,7 @@ export namespace Pty {
|
|||||||
return out
|
return out
|
||||||
}
|
}
|
||||||
|
|
||||||
const pty = lazy(async () => {
|
const pty = lazy(() => import("#pty"))
|
||||||
const { spawn } = await import("bun-pty")
|
|
||||||
return spawn
|
|
||||||
})
|
|
||||||
|
|
||||||
export const Info = z
|
export const Info = z
|
||||||
.object({
|
.object({
|
||||||
@@ -85,7 +82,7 @@ export namespace Pty {
|
|||||||
|
|
||||||
interface ActiveSession {
|
interface ActiveSession {
|
||||||
info: Info
|
info: Info
|
||||||
process: IPty
|
process: Proc
|
||||||
buffer: string
|
buffer: string
|
||||||
bufferCursor: number
|
bufferCursor: number
|
||||||
cursor: number
|
cursor: number
|
||||||
@@ -144,7 +141,7 @@ export namespace Pty {
|
|||||||
}
|
}
|
||||||
log.info("creating session", { id, cmd: command, args, cwd })
|
log.info("creating session", { id, cmd: command, args, cwd })
|
||||||
|
|
||||||
const spawn = await pty()
|
const { spawn } = await pty()
|
||||||
const ptyProcess = spawn(command, args, {
|
const ptyProcess = spawn(command, args, {
|
||||||
name: "xterm-256color",
|
name: "xterm-256color",
|
||||||
cwd,
|
cwd,
|
||||||
|
|||||||
@@ -0,0 +1,26 @@
|
|||||||
|
import { spawn as create } from "bun-pty"
|
||||||
|
import type { Opts, Proc } from "./pty"
|
||||||
|
|
||||||
|
export type { Disp, Exit, Opts, Proc } from "./pty"
|
||||||
|
|
||||||
|
export function spawn(file: string, args: string[], opts: Opts): Proc {
|
||||||
|
const pty = create(file, args, opts)
|
||||||
|
return {
|
||||||
|
pid: pty.pid,
|
||||||
|
onData(listener) {
|
||||||
|
return pty.onData(listener)
|
||||||
|
},
|
||||||
|
onExit(listener) {
|
||||||
|
return pty.onExit(listener)
|
||||||
|
},
|
||||||
|
write(data) {
|
||||||
|
pty.write(data)
|
||||||
|
},
|
||||||
|
resize(cols, rows) {
|
||||||
|
pty.resize(cols, rows)
|
||||||
|
},
|
||||||
|
kill(signal) {
|
||||||
|
pty.kill(signal)
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
import * as pty from "node-pty"
|
||||||
|
import type { Opts, Proc } from "./pty"
|
||||||
|
|
||||||
|
export type { Disp, Exit, Opts, Proc } from "./pty"
|
||||||
|
|
||||||
|
export function spawn(file: string, args: string[], opts: Opts): Proc {
|
||||||
|
const proc = pty.spawn(file, args, opts)
|
||||||
|
return {
|
||||||
|
pid: proc.pid,
|
||||||
|
onData(listener) {
|
||||||
|
return proc.onData(listener)
|
||||||
|
},
|
||||||
|
onExit(listener) {
|
||||||
|
return proc.onExit(listener)
|
||||||
|
},
|
||||||
|
write(data) {
|
||||||
|
proc.write(data)
|
||||||
|
},
|
||||||
|
resize(cols, rows) {
|
||||||
|
proc.resize(cols, rows)
|
||||||
|
},
|
||||||
|
kill(signal) {
|
||||||
|
proc.kill(signal)
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
export type Disp = {
|
||||||
|
dispose(): void
|
||||||
|
}
|
||||||
|
|
||||||
|
export type Exit = {
|
||||||
|
exitCode: number
|
||||||
|
signal?: number | string
|
||||||
|
}
|
||||||
|
|
||||||
|
export type Opts = {
|
||||||
|
name: string
|
||||||
|
cols?: number
|
||||||
|
rows?: number
|
||||||
|
cwd?: string
|
||||||
|
env?: Record<string, string>
|
||||||
|
}
|
||||||
|
|
||||||
|
export type Proc = {
|
||||||
|
pid: number
|
||||||
|
onData(listener: (data: string) => void): Disp
|
||||||
|
onExit(listener: (event: Exit) => void): Disp
|
||||||
|
write(data: string): void
|
||||||
|
resize(cols: number, rows: number): void
|
||||||
|
kill(signal?: string): void
|
||||||
|
}
|
||||||
@@ -25,7 +25,7 @@ import { WorkspaceContext } from "../control-plane/workspace-context"
|
|||||||
import { WorkspaceRouterMiddleware } from "../control-plane/workspace-router-middleware"
|
import { WorkspaceRouterMiddleware } from "../control-plane/workspace-router-middleware"
|
||||||
import { ProjectRoutes } from "./routes/project"
|
import { ProjectRoutes } from "./routes/project"
|
||||||
import { SessionRoutes } from "./routes/session"
|
import { SessionRoutes } from "./routes/session"
|
||||||
// import { PtyRoutes } from "./routes/pty"
|
import { PtyRoutes } from "./routes/pty"
|
||||||
import { McpRoutes } from "./routes/mcp"
|
import { McpRoutes } from "./routes/mcp"
|
||||||
import { FileRoutes } from "./routes/file"
|
import { FileRoutes } from "./routes/file"
|
||||||
import { ConfigRoutes } from "./routes/config"
|
import { ConfigRoutes } from "./routes/config"
|
||||||
@@ -559,7 +559,7 @@ export namespace Server {
|
|||||||
})
|
})
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
// .route("/pty", PtyRoutes(ws.upgradeWebSocket))
|
.route("/pty", PtyRoutes(ws.upgradeWebSocket))
|
||||||
.all("/*", async (c) => {
|
.all("/*", async (c) => {
|
||||||
const path = c.req.path
|
const path = c.req.path
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user