@dev-anywhere/proxy 0.1.1 → 0.1.2

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/serve.js CHANGED
@@ -2060,7 +2060,7 @@ function terminateSessionByOwnership(deps, sessionId) {
2060
2060
  }
2061
2061
 
2062
2062
  // src/serve/clipboard-image-upload.ts
2063
- import { mkdirSync as mkdirSync4, writeFileSync as writeFileSync4 } from "fs";
2063
+ import { existsSync as existsSync5, mkdirSync as mkdirSync4, readFileSync as readFileSync5, statSync, writeFileSync as writeFileSync4 } from "fs";
2064
2064
  import { isAbsolute as isAbsolute3, join as join5, relative, resolve } from "path";
2065
2065
  import { nanoid as nanoid3 } from "nanoid";
2066
2066
  var MAX_CLIPBOARD_IMAGE_BYTES = 10 * 1024 * 1024;
@@ -2093,15 +2093,50 @@ function decodeBase64Image(dataBase64) {
2093
2093
  }
2094
2094
  return buffer;
2095
2095
  }
2096
- function resolveSessionClipboardDir(dataDir, sessionId) {
2097
- const root = resolve(dataDir);
2098
- const uploadDir = resolve(root, sessionId, "clipboard");
2096
+ function resolveChildDir(rootPath, ...segments) {
2097
+ const root = resolve(rootPath);
2098
+ const uploadDir = resolve(root, ...segments);
2099
2099
  const relativePath = relative(root, uploadDir);
2100
2100
  if (!relativePath || relativePath.startsWith("..") || isAbsolute3(relativePath)) {
2101
2101
  throw new Error("\u4F1A\u8BDD\u8DEF\u5F84\u65E0\u6548");
2102
2102
  }
2103
2103
  return uploadDir;
2104
2104
  }
2105
+ function resolveSessionClipboardDir(dataDir, sessionId) {
2106
+ return resolveChildDir(dataDir, sessionId, "clipboard");
2107
+ }
2108
+ function normalizeGitignoreLine(line) {
2109
+ return line.trim().replace(/^\/+/, "").replace(/\/+$/, "");
2110
+ }
2111
+ function ensureProjectClipboardIgnored(cwd) {
2112
+ const gitignorePath = join5(cwd, ".gitignore");
2113
+ if (!existsSync5(gitignorePath)) return;
2114
+ try {
2115
+ const current = readFileSync5(gitignorePath, "utf-8");
2116
+ const alreadyIgnored = current.split(/\r?\n/).some((line) => normalizeGitignoreLine(line) === ".dev-anywhere");
2117
+ if (alreadyIgnored) return;
2118
+ const separator = current.length > 0 && !current.endsWith("\n") ? "\n" : "";
2119
+ writeFileSync4(gitignorePath, `${current}${separator}.dev-anywhere/
2120
+ `);
2121
+ } catch {
2122
+ }
2123
+ }
2124
+ function trySaveProjectClipboardImage(options) {
2125
+ if (!options.cwd) return null;
2126
+ try {
2127
+ const cwd = resolve(options.cwd);
2128
+ if (!statSync(cwd).isDirectory()) return null;
2129
+ const clipboardRoot = resolve(cwd, ".dev-anywhere", "clipboard");
2130
+ const uploadDir = resolveChildDir(clipboardRoot, options.sessionId);
2131
+ const path = join5(uploadDir, options.fileName);
2132
+ mkdirSync4(uploadDir, { recursive: true });
2133
+ writeFileSync4(path, options.buffer, { mode: 384 });
2134
+ ensureProjectClipboardIgnored(cwd);
2135
+ return { success: true, path: relative(cwd, path) };
2136
+ } catch {
2137
+ return null;
2138
+ }
2139
+ }
2105
2140
  function saveClipboardImageUpload(request, options = {}) {
2106
2141
  const extension = IMAGE_EXTENSIONS.get(request.mimeType);
2107
2142
  if (!extension) {
@@ -2113,12 +2148,19 @@ function saveClipboardImageUpload(request, options = {}) {
2113
2148
  };
2114
2149
  }
2115
2150
  try {
2116
- const dataDir = options.dataDir ?? DATA_DIR;
2117
- const uploadDir = resolveSessionClipboardDir(dataDir, request.sessionId);
2118
2151
  const buffer = decodeBase64Image(request.dataBase64);
2119
2152
  const now = options.now ?? Date.now;
2120
2153
  const suffix = options.randomSuffix?.() ?? nanoid3(6);
2121
2154
  const fileName = `pasted-${formatTimestamp(now())}-${suffix}.${extension}`;
2155
+ const projectResult = trySaveProjectClipboardImage({
2156
+ cwd: options.cwd,
2157
+ sessionId: request.sessionId,
2158
+ fileName,
2159
+ buffer
2160
+ });
2161
+ if (projectResult) return projectResult;
2162
+ const dataDir = options.dataDir ?? DATA_DIR;
2163
+ const uploadDir = resolveSessionClipboardDir(dataDir, request.sessionId);
2122
2164
  const path = join5(uploadDir, fileName);
2123
2165
  mkdirSync4(uploadDir, { recursive: true });
2124
2166
  writeFileSync4(path, buffer, { mode: 384 });
@@ -2226,12 +2268,17 @@ var RelayInputHandlers = class {
2226
2268
  serviceLogger.warn({ sessionId }, "Clipboard image upload rejected: session not found");
2227
2269
  return;
2228
2270
  }
2229
- const result = saveClipboardImageUpload({
2230
- sessionId,
2231
- mimeType: typeof msg.mimeType === "string" ? msg.mimeType : "",
2232
- dataBase64: typeof msg.dataBase64 === "string" ? msg.dataBase64 : "",
2233
- fileName: typeof msg.fileName === "string" ? msg.fileName : void 0
2234
- });
2271
+ const result = saveClipboardImageUpload(
2272
+ {
2273
+ sessionId,
2274
+ mimeType: typeof msg.mimeType === "string" ? msg.mimeType : "",
2275
+ dataBase64: typeof msg.dataBase64 === "string" ? msg.dataBase64 : "",
2276
+ fileName: typeof msg.fileName === "string" ? msg.fileName : void 0
2277
+ },
2278
+ {
2279
+ cwd: session.cwd
2280
+ }
2281
+ );
2235
2282
  this.deps.relayConnection.sendRaw(
2236
2283
  JSON.stringify({
2237
2284
  type: "clipboard_image_upload_response",
@@ -2441,14 +2488,14 @@ var RelayPermissionHandlers = class {
2441
2488
 
2442
2489
  // src/serve/relay-resource-handlers.ts
2443
2490
  import { homedir as homedir4 } from "os";
2444
- import { accessSync, constants, statSync } from "fs";
2491
+ import { accessSync, constants, statSync as statSync2 } from "fs";
2445
2492
  function errorMessage(err) {
2446
2493
  return err instanceof Error ? err.message : String(err);
2447
2494
  }
2448
2495
  function validateExecutablePath(path) {
2449
2496
  const normalized = path.trim();
2450
2497
  if (!normalized.startsWith("/")) throw new Error("CLI \u8DEF\u5F84\u5FC5\u987B\u662F\u7EDD\u5BF9\u8DEF\u5F84");
2451
- const stat2 = statSync(normalized);
2498
+ const stat2 = statSync2(normalized);
2452
2499
  if (!stat2.isFile()) throw new Error("CLI \u8DEF\u5F84\u4E0D\u662F\u53EF\u6267\u884C\u6587\u4EF6");
2453
2500
  accessSync(normalized, constants.X_OK);
2454
2501
  return normalized;
@@ -2557,7 +2604,7 @@ var RelayResourceHandlers = class {
2557
2604
  };
2558
2605
 
2559
2606
  // src/serve/relay-session-create-handler.ts
2560
- import { rmSync, statSync as statSync2 } from "fs";
2607
+ import { rmSync, statSync as statSync3 } from "fs";
2561
2608
  import { isAbsolute as isAbsolute4 } from "path";
2562
2609
  import { nanoid as nanoid4 } from "nanoid";
2563
2610
 
@@ -2852,7 +2899,7 @@ function validateSessionCwd(cwd) {
2852
2899
  return { message: "\u5DE5\u4F5C\u76EE\u5F55\u5FC5\u987B\u662F\u7EDD\u5BF9\u8DEF\u5F84", code: ControlErrorCode.INVALID_PATH };
2853
2900
  }
2854
2901
  try {
2855
- const stat2 = statSync2(trimmed);
2902
+ const stat2 = statSync3(trimmed);
2856
2903
  return stat2.isDirectory() ? null : { message: "\u5DE5\u4F5C\u76EE\u5F55\u4E0D\u662F\u76EE\u5F55", code: ControlErrorCode.PATH_NOT_DIRECTORY };
2857
2904
  } catch (err) {
2858
2905
  return {
@@ -3648,7 +3695,7 @@ function touchSessionActivity(sessionManager, relay, sessionId, now = Date.now()
3648
3695
 
3649
3696
  // src/serve/service-files.ts
3650
3697
  import { execSync } from "child_process";
3651
- import { existsSync as existsSync5, readFileSync as readFileSync5, unlinkSync as unlinkSync2 } from "fs";
3698
+ import { existsSync as existsSync6, readFileSync as readFileSync6, unlinkSync as unlinkSync2 } from "fs";
3652
3699
  import { hostname } from "os";
3653
3700
  import { connect as connect2 } from "net";
3654
3701
  function tryConnectSocket(sockPath) {
@@ -3667,7 +3714,7 @@ function isProcessAlive(pid) {
3667
3714
  }
3668
3715
  }
3669
3716
  async function cleanupStaleResources() {
3670
- if (existsSync5(SOCK_PATH)) {
3717
+ if (existsSync6(SOCK_PATH)) {
3671
3718
  const existing = await tryConnectSocket(SOCK_PATH);
3672
3719
  if (existing) {
3673
3720
  existing.destroy();
@@ -3679,8 +3726,8 @@ async function cleanupStaleResources() {
3679
3726
  unlinkSync2(SOCK_PATH);
3680
3727
  serviceLogger.info("Removed stale socket file");
3681
3728
  }
3682
- if (existsSync5(PID_PATH)) {
3683
- const pidStr = readFileSync5(PID_PATH, "utf-8").trim();
3729
+ if (existsSync6(PID_PATH)) {
3730
+ const pidStr = readFileSync6(PID_PATH, "utf-8").trim();
3684
3731
  const pid = parseInt(pidStr, 10);
3685
3732
  if (!isNaN(pid) && isProcessAlive(pid)) {
3686
3733
  const msg = `Another service is already running with PID ${pid}`;
@@ -4055,7 +4102,7 @@ function handleTerminalConnection(socket, deps) {
4055
4102
 
4056
4103
  // src/serve/hook-registry.ts
4057
4104
  import { createHash, randomBytes } from "crypto";
4058
- import { existsSync as existsSync6, mkdirSync as mkdirSync5, readFileSync as readFileSync6, renameSync as renameSync2, writeFileSync as writeFileSync5 } from "fs";
4105
+ import { existsSync as existsSync7, mkdirSync as mkdirSync5, readFileSync as readFileSync7, renameSync as renameSync2, writeFileSync as writeFileSync5 } from "fs";
4059
4106
  import { dirname as dirname4 } from "path";
4060
4107
  import { z } from "zod";
4061
4108
  var PersistedHookSessionBindingSchema = z.object({
@@ -4116,10 +4163,10 @@ var HookRegistry = class {
4116
4163
  }
4117
4164
  }
4118
4165
  load() {
4119
- if (!this.persistPath || !existsSync6(this.persistPath)) return;
4166
+ if (!this.persistPath || !existsSync7(this.persistPath)) return;
4120
4167
  try {
4121
4168
  const parsed = PersistedHookRegistrySchema.parse(
4122
- JSON.parse(readFileSync6(this.persistPath, "utf8"))
4169
+ JSON.parse(readFileSync7(this.persistPath, "utf8"))
4123
4170
  );
4124
4171
  this.bindingsBySession.clear();
4125
4172
  for (const binding of parsed.bindings) {