turtlecode 0.1.1 → 0.1.3
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/bin/cli.mjs +39 -3
- package/package.json +1 -1
package/bin/cli.mjs
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
import { createServer, request as httpRequest } from "node:http"
|
|
4
|
-
import { readFileSync, existsSync, statSync } from "node:fs"
|
|
4
|
+
import { readFileSync, existsSync, statSync, mkdirSync } from "node:fs"
|
|
5
5
|
import { join, extname, dirname, resolve } from "node:path"
|
|
6
6
|
import { fileURLToPath } from "node:url"
|
|
7
7
|
import { exec, spawn } from "node:child_process"
|
|
8
|
+
import { homedir } from "node:os"
|
|
8
9
|
|
|
9
10
|
const root = join(dirname(fileURLToPath(import.meta.url)), "..", "assets")
|
|
10
11
|
|
|
@@ -49,6 +50,23 @@ function encode(str) {
|
|
|
49
50
|
return Buffer.from(str).toString("base64").replace(/\+/g, "-").replace(/\//g, "_").replace(/=/g, "")
|
|
50
51
|
}
|
|
51
52
|
|
|
53
|
+
// Extract directory from base64-encoded path segment, returns { pathname, directory }
|
|
54
|
+
function extractDir(path) {
|
|
55
|
+
const match = path.match(/^\/([A-Za-z0-9_-]{10,})(\/.*)?$/)
|
|
56
|
+
if (!match) return { pathname: path }
|
|
57
|
+
|
|
58
|
+
const encoded = match[1]
|
|
59
|
+
const rest = match[2] || "/"
|
|
60
|
+
|
|
61
|
+
try {
|
|
62
|
+
const normalized = encoded.replace(/-/g, "+").replace(/_/g, "/")
|
|
63
|
+
const decoded = Buffer.from(normalized, "base64").toString("utf-8")
|
|
64
|
+
return { pathname: rest, directory: decoded }
|
|
65
|
+
} catch {
|
|
66
|
+
return { pathname: path }
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
52
70
|
function probe(origin) {
|
|
53
71
|
return new Promise((ok) => {
|
|
54
72
|
const req = httpRequest(origin, { method: "HEAD", timeout: 1000 }, (res) => {
|
|
@@ -130,6 +148,16 @@ if (!existsSync(join(root, "index.html"))) {
|
|
|
130
148
|
|
|
131
149
|
const spawned = await boot(backend.origin)
|
|
132
150
|
|
|
151
|
+
// Ensure ~/.turtlecode exists for new project creation
|
|
152
|
+
const projectsDir = join(homedir(), ".turtlecode")
|
|
153
|
+
if (!existsSync(projectsDir)) {
|
|
154
|
+
try {
|
|
155
|
+
mkdirSync(projectsDir, { recursive: true })
|
|
156
|
+
} catch {
|
|
157
|
+
// Ignore errors (permissions, etc.) - backend will handle them
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
|
|
133
161
|
// Determine whether a request should be proxied to the backend.
|
|
134
162
|
// Static assets are served directly; browser navigation gets the SPA
|
|
135
163
|
// index.html; everything else (API calls, SSE, etc.) is proxied.
|
|
@@ -150,9 +178,13 @@ function shouldProxy(req, file) {
|
|
|
150
178
|
|
|
151
179
|
function proxy(req, res) {
|
|
152
180
|
const url = new URL(req.url, `http://localhost:${port}`)
|
|
153
|
-
const target = `${backend.origin}${url.pathname}${url.search}`
|
|
154
181
|
|
|
182
|
+
// Extract directory from base64 path segment and add header for backend
|
|
183
|
+
const { pathname, directory } = extractDir(url.pathname)
|
|
155
184
|
const headers = { ...req.headers, host: backend.host }
|
|
185
|
+
if (directory) headers["x-opencode-directory"] = directory
|
|
186
|
+
|
|
187
|
+
const target = `${backend.origin}${pathname}${url.search}`
|
|
156
188
|
|
|
157
189
|
const proxyReq = httpRequest(target, { method: req.method, headers }, (proxyRes) => {
|
|
158
190
|
res.writeHead(proxyRes.statusCode, proxyRes.headers)
|
|
@@ -200,9 +232,13 @@ const server = createServer((req, res) => {
|
|
|
200
232
|
// Handle WebSocket upgrade (used by PTY terminal connections)
|
|
201
233
|
server.on("upgrade", (req, socket, head) => {
|
|
202
234
|
const url = new URL(req.url, `http://localhost:${port}`)
|
|
203
|
-
|
|
235
|
+
|
|
236
|
+
// Extract directory from base64 path segment and add header (same logic as proxy function)
|
|
237
|
+
const { pathname, directory } = extractDir(url.pathname)
|
|
204
238
|
const headers = { ...req.headers, host: backend.host }
|
|
239
|
+
if (directory) headers["x-opencode-directory"] = directory
|
|
205
240
|
|
|
241
|
+
const target = `${backend.origin}${pathname}${url.search}`
|
|
206
242
|
const proxyReq = httpRequest(target, { method: "GET", headers })
|
|
207
243
|
|
|
208
244
|
proxyReq.on("upgrade", (proxyRes, proxySocket, proxyHead) => {
|