@skylandnpm/octopus-proxy 0.1.67 → 0.1.69

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.
@@ -7819,12 +7819,16 @@ import { join as join16 } from "node:path";
7819
7819
  // src/workspace-diff.ts
7820
7820
  import { execFile as execFile2 } from "node:child_process";
7821
7821
  import { promisify as promisify2 } from "node:util";
7822
- import { realpath } from "node:fs/promises";
7822
+ import { realpath, stat as stat3 } from "node:fs/promises";
7823
7823
  import { relative, resolve } from "node:path";
7824
7824
  var execute = promisify2(execFile2);
7825
7825
  var MAX_PATCH = 256 * 1024;
7826
7826
  var MAX_TOTAL = 1024 * 1024;
7827
- async function workspaceDiff(workspace, project) {
7827
+ var MAX_LINES = 2e3;
7828
+ async function workspaceDiff(workspace, project, page = {}) {
7829
+ const offset = page.paged ? page.offset ?? 0 : 0;
7830
+ const limit = page.paged ? page.limit ?? 20 : 200;
7831
+ if (!Number.isSafeInteger(offset) || offset < 0 || !Number.isSafeInteger(limit) || limit < 1 || limit > 200) throw new Error("Invalid diff page");
7828
7832
  const root = await workspace.root(project);
7829
7833
  const git = async (...args) => (await execute("git", ["--no-optional-locks", "-c", "core.quotePath=false", ...args], {
7830
7834
  cwd: root,
@@ -7868,13 +7872,8 @@ async function workspaceDiff(workspace, project) {
7868
7872
  if (!base) throw new Error("\u65E0\u6CD5\u8BFB\u53D6 Git \u6BD4\u8F83\u57FA\u51C6");
7869
7873
  const files = [];
7870
7874
  let bytes = 0;
7871
- for (const entry of entries.slice(0, 200)) {
7875
+ for (const entry of entries.slice(offset, offset + limit)) {
7872
7876
  const change = { ...entry, patch: "", additions: 0, deletions: 0 };
7873
- if (bytes >= MAX_TOTAL) {
7874
- change.notice = "\u53D8\u66F4\u8F83\u591A\uFF0C\u672A\u52A0\u8F7D\u6B64\u6587\u4EF6\u5185\u5BB9";
7875
- files.push(change);
7876
- continue;
7877
- }
7878
7877
  try {
7879
7878
  if (entry.status === "??") {
7880
7879
  const read = await workspace.read(project, entry.file, 0, MAX_PATCH);
@@ -7891,16 +7890,30 @@ ${lines.map((line) => `+${line}`).join("\n")}
7891
7890
  `;
7892
7891
  }
7893
7892
  } else {
7894
- change.patch = await git("diff", "--no-ext-diff", "--no-textconv", "--no-renames", "--no-color", "--relative", "--unified=3", base, "--", entry.file);
7895
- change.binary = change.patch.includes("Binary files ");
7896
- if (Buffer.byteLength(change.patch) > MAX_PATCH) {
7897
- change.patch = "";
7898
- change.notice = "\u5DEE\u5F02\u8FC7\u5927\uFF0C\u8BF7\u5728\u672C\u5730 Git \u67E5\u770B";
7893
+ let currentSize = 0, baseSize = 0;
7894
+ try {
7895
+ currentSize = (await stat3(await workspace.path(project, entry.file))).size;
7896
+ } catch (error) {
7897
+ if (error.code !== "ENOENT") throw error;
7898
+ }
7899
+ try {
7900
+ baseSize = Number((await git("cat-file", "-s", `${base}:${prefix ? `${prefix}/` : ""}${entry.file}`)).trim());
7901
+ } catch {
7902
+ }
7903
+ if (Math.max(currentSize, baseSize) > MAX_PATCH) change.notice = "\u6587\u4EF6\u8D85\u8FC7 256 KiB\uFF0C\u672A\u52A0\u8F7D\u5DEE\u5F02\uFF0C\u8BF7\u5728\u6587\u4EF6\u9762\u677F\u6216\u672C\u5730 Git \u67E5\u770B";
7904
+ else {
7905
+ change.patch = await git("diff", "--no-ext-diff", "--no-textconv", "--no-renames", "--no-color", "--relative", "--unified=3", base, "--", entry.file);
7906
+ change.binary = change.patch.includes("Binary files ");
7899
7907
  }
7900
7908
  }
7901
7909
  } catch (error) {
7902
7910
  change.notice = error instanceof Error ? error.message.slice(0, 250) : "\u65E0\u6CD5\u52A0\u8F7D\u6587\u4EF6\u5DEE\u5F02";
7903
7911
  }
7912
+ if (Buffer.byteLength(change.patch) > MAX_PATCH || change.patch.split("\n").length > MAX_LINES) {
7913
+ change.patch = "";
7914
+ change.notice = "\u5DEE\u5F02\u8D85\u8FC7 256 KiB \u6216 2000 \u884C\uFF0C\u672A\u52A0\u8F7D\u5DEE\u5F02\uFF0C\u8BF7\u5728\u672C\u5730 Git \u67E5\u770B";
7915
+ }
7916
+ if (bytes + Buffer.byteLength(change.patch) > MAX_TOTAL) break;
7904
7917
  let inHunk = false;
7905
7918
  for (const line of change.patch.split("\n")) {
7906
7919
  if (line.startsWith("@@ ")) inHunk = true;
@@ -7910,12 +7923,13 @@ ${lines.map((line) => `+${line}`).join("\n")}
7910
7923
  bytes += Buffer.byteLength(change.patch);
7911
7924
  files.push(change);
7912
7925
  }
7913
- return { scope: "workspace", files, total: entries.length, truncated: entries.length > 200 || files.some((file) => file.notice), directory: prefix || ".", capturedAt: Date.now() };
7926
+ const nextOffset = offset + files.length < entries.length ? offset + files.length : void 0;
7927
+ return { scope: "workspace", files, total: entries.length, nextOffset, truncated: nextOffset !== void 0 || files.some((file) => file.notice), directory: prefix || ".", capturedAt: Date.now() };
7914
7928
  }
7915
7929
 
7916
7930
  // src/workspace.ts
7917
7931
  import { constants } from "node:fs";
7918
- import { mkdir as mkdir2, open as open2, readdir, realpath as realpath2, stat as stat3, link, unlink as unlink3 } from "node:fs/promises";
7932
+ import { mkdir as mkdir2, open as open2, readdir, realpath as realpath2, stat as stat4, link, unlink as unlink3 } from "node:fs/promises";
7919
7933
  import { basename, dirname, extname, isAbsolute as isAbsolute2, relative as relative2, resolve as resolve2, sep } from "node:path";
7920
7934
  import { createHash as createHash2 } from "node:crypto";
7921
7935
  var mimeOf = (name) => ({ ".png": "image/png", ".jpg": "image/jpeg", ".jpeg": "image/jpeg", ".gif": "image/gif", ".webp": "image/webp", ".svg": "image/svg+xml", ".md": "text/markdown", ".txt": "text/plain", ".json": "application/json", ".pdf": "application/pdf" })[extname(name).toLowerCase()] ?? "application/octet-stream";
@@ -7950,7 +7964,7 @@ var Workspace = class {
7950
7964
  const name = relative2(await this.root(id), resolve2(full, e.name));
7951
7965
  try {
7952
7966
  const safe = await this.path(id, name);
7953
- const info = await stat3(safe);
7967
+ const info = await stat4(safe);
7954
7968
  return { name: e.name, path: name, type: info.isDirectory() ? "directory" : "file", size: info.size };
7955
7969
  } catch {
7956
7970
  return null;
@@ -8047,7 +8061,7 @@ var Workspace = class {
8047
8061
 
8048
8062
  // src/uploads.ts
8049
8063
  import { constants as constants2 } from "node:fs";
8050
- import { open as open3, readdir as readdir2, unlink as unlink4, stat as stat4 } from "node:fs/promises";
8064
+ import { open as open3, readdir as readdir2, unlink as unlink4, stat as stat5 } from "node:fs/promises";
8051
8065
  import { basename as basename2, dirname as dirname3, join as join4 } from "node:path";
8052
8066
  import { createHash as createHash3, randomUUID as randomUUID4 } from "node:crypto";
8053
8067
 
@@ -8106,7 +8120,7 @@ var Uploads = class {
8106
8120
  if (!u || u.projectId !== projectId) throw new Error("Upload not found in this project");
8107
8121
  if (u.state === "pending" && u.offset === u.size) {
8108
8122
  try {
8109
- await stat4(u.temp);
8123
+ await stat5(u.temp);
8110
8124
  } catch (e) {
8111
8125
  if (e.code !== "ENOENT") throw e;
8112
8126
  const target = await this.workspace.path(projectId, u.destination);
@@ -8131,7 +8145,7 @@ var Uploads = class {
8131
8145
  } else destination = `${String(input.directory ?? ".")}/${name}`;
8132
8146
  const dest = await this.workspace.path(projectId, destination, true);
8133
8147
  try {
8134
- await stat4(dest);
8148
+ await stat5(dest);
8135
8149
  throw new Error("Destination exists; rename the file");
8136
8150
  } catch (e) {
8137
8151
  if (e.code !== "ENOENT") throw e;
@@ -8446,6 +8460,43 @@ var Journal = class {
8446
8460
  };
8447
8461
 
8448
8462
  // src/session-history.ts
8463
+ var PAGE_BYTES = 2 * 1024 * 1024;
8464
+ var FRAGMENT_BYTES = 1024 * 1024;
8465
+ var jsonBytes = (value) => Buffer.byteLength(JSON.stringify(value));
8466
+ function historyFragments(message) {
8467
+ if (jsonBytes(message) <= PAGE_BYTES || !message.parts?.length) return [message];
8468
+ const groups = [];
8469
+ let parts = [], bytes = jsonBytes({ ...message, parts: [] });
8470
+ for (const [offset, part] of message.parts.entries()) {
8471
+ const size = jsonBytes(part) + 1;
8472
+ if (parts.length && bytes + size > FRAGMENT_BYTES) {
8473
+ groups.push({ offset: offset - parts.length, parts });
8474
+ parts = [];
8475
+ bytes = jsonBytes({ ...message, parts: [] });
8476
+ }
8477
+ parts.push(part);
8478
+ bytes += size;
8479
+ }
8480
+ if (parts.length) groups.push({ offset: message.parts.length - parts.length, parts });
8481
+ return groups.map((group, index) => {
8482
+ const info = { ...message.info, id: `${message.info?.id}:claw-part:${group.offset}`, continuationOf: message.info?.id };
8483
+ if (index < groups.length - 1) {
8484
+ delete info.status;
8485
+ delete info.durationMs;
8486
+ delete info.error;
8487
+ if (info.time && typeof info.time === "object") {
8488
+ const time = { ...info.time };
8489
+ delete time.completed;
8490
+ info.time = time;
8491
+ }
8492
+ }
8493
+ return { ...message, info, parts: group.parts };
8494
+ });
8495
+ }
8496
+ function boundedPage(messages) {
8497
+ if (jsonBytes(messages) > PAGE_BYTES) throw new Error("History content exceeds the 2 MiB page limit; view this item in the host coding tool");
8498
+ return messages;
8499
+ }
8449
8500
  function timestamp(message) {
8450
8501
  const info = message.info ?? {};
8451
8502
  const time = info.time && typeof info.time === "object" ? info.time : {};
@@ -8482,15 +8533,15 @@ function pageHistory(input, payload) {
8482
8533
  if (payload.limit === void 0) return input;
8483
8534
  const limit = Number(payload.limit);
8484
8535
  if (!Number.isInteger(limit) || limit < 1 || limit > 100) throw new Error("Invalid history page limit");
8485
- const ordered = orderedHistory(input);
8536
+ const ordered = orderedHistory(input).flatMap(historyFragments);
8486
8537
  if (payload.after !== void 0) {
8487
8538
  if (typeof payload.after !== "string") throw new Error("Invalid history cursor");
8488
8539
  const anchor = ordered.findIndex((message) => message.info?.id === payload.after);
8489
8540
  if (anchor < 0) throw new Error("History cursor expired; refresh conversation");
8490
8541
  const start2 = anchor + (payload.includeAnchor === true ? 0 : 1);
8491
8542
  let end2 = Math.min(ordered.length, start2 + limit);
8492
- while (end2 > start2 + 1 && Buffer.byteLength(JSON.stringify(ordered.slice(start2, end2))) > 2 * 1024 * 1024) end2--;
8493
- const messages2 = ordered.slice(start2, end2);
8543
+ while (end2 > start2 + 1 && jsonBytes(ordered.slice(start2, end2)) > PAGE_BYTES) end2--;
8544
+ const messages2 = boundedPage(ordered.slice(start2, end2));
8494
8545
  return {
8495
8546
  messages: messages2,
8496
8547
  hasMore: start2 > 0,
@@ -8506,15 +8557,15 @@ function pageHistory(input, payload) {
8506
8557
  if (end < 0) throw new Error("History cursor expired; refresh conversation");
8507
8558
  }
8508
8559
  let start = Math.max(0, end - limit);
8509
- while (start < end - 1 && Buffer.byteLength(JSON.stringify(ordered.slice(start, end))) > 2 * 1024 * 1024) start++;
8510
- const messages = ordered.slice(start, end);
8560
+ while (start < end - 1 && jsonBytes(ordered.slice(start, end)) > PAGE_BYTES) start++;
8561
+ const messages = boundedPage(ordered.slice(start, end));
8511
8562
  return { messages, hasMore: start > 0, nextBefore: start > 0 ? String(messages[0]?.info?.id) : null };
8512
8563
  }
8513
8564
 
8514
8565
  // src/artifacts.ts
8515
8566
  import { createHash as createHash5 } from "node:crypto";
8516
8567
  import { join as join6 } from "node:path";
8517
- import { readFile as readFile4, writeFile as writeFile3, mkdir as mkdir4, stat as stat5 } from "node:fs/promises";
8568
+ import { readFile as readFile4, writeFile as writeFile3, mkdir as mkdir4, stat as stat6 } from "node:fs/promises";
8518
8569
  var Artifacts = class {
8519
8570
  constructor(workspace, directory, emit) {
8520
8571
  this.workspace = workspace;
@@ -8538,6 +8589,12 @@ var Artifacts = class {
8538
8589
  scan(project) {
8539
8590
  return this.serial(project, () => this.scanUnlocked(project));
8540
8591
  }
8592
+ async scanPage(project, offset = 0, limit = 20) {
8593
+ if (!Number.isSafeInteger(offset) || offset < 0 || !Number.isSafeInteger(limit) || limit < 1 || limit > 200) throw new Error("Invalid artifact page");
8594
+ const all = (await this.scan(project)).sort((a, b) => a.path < b.path ? -1 : a.path > b.path ? 1 : 0);
8595
+ const items = all.slice(offset, offset + limit).map((item) => ({ ...item, revisions: item.revisions.slice(-1) }));
8596
+ return { items, total: all.length, nextOffset: offset + items.length < all.length ? offset + items.length : void 0 };
8597
+ }
8541
8598
  async scanUnlocked(project) {
8542
8599
  await this.workspace.root(project);
8543
8600
  const index = await readJson(this.index(project)) ?? {}, seen = /* @__PURE__ */ new Set();
@@ -8586,7 +8643,7 @@ var Artifacts = class {
8586
8643
  }
8587
8644
  for (const item of Object.values(index)) if (!seen.has(item.path) && !item.revisions.at(-1)?.deleted) {
8588
8645
  try {
8589
- await stat5(await this.workspace.path(project, item.path));
8646
+ await stat6(await this.workspace.path(project, item.path));
8590
8647
  } catch (e) {
8591
8648
  if (e.code === "ENOENT") {
8592
8649
  item.revisions.push({ hash: "", timestamp: (/* @__PURE__ */ new Date()).toISOString(), deleted: true });
@@ -8597,7 +8654,7 @@ var Artifacts = class {
8597
8654
  }
8598
8655
  if (changed) {
8599
8656
  await atomicJson(this.index(project), index);
8600
- this.emit(project, "artifacts.updated", Object.values(index));
8657
+ this.emit(project, "artifacts.updated", { total: Object.keys(index).length });
8601
8658
  }
8602
8659
  return Object.values(index);
8603
8660
  }
@@ -8608,6 +8665,14 @@ var Artifacts = class {
8608
8665
  if (!/^[a-f0-9]{64}$/.test(hash) || !(await this.history(project, path)).some((r) => r.hash === hash)) throw new Error("Unknown revision");
8609
8666
  return readFile4(join6(this.directory, project, "blobs", hash), "utf8");
8610
8667
  }
8668
+ async preview(project, path, hash) {
8669
+ if (!/^[a-f0-9]{64}$/.test(hash) || !(await this.history(project, path)).some((r) => r.hash === hash)) throw new Error("Unknown revision");
8670
+ const blob = join6(this.directory, project, "blobs", hash);
8671
+ if ((await stat6(blob)).size > 256 * 1024) return { content: "", notice: "\u6587\u4EF6\u8D85\u8FC7 256 KiB\uFF0C\u5DF2\u8DF3\u8FC7\u9884\u89C8\uFF0C\u8BF7\u5728\u6587\u4EF6\u9762\u677F\u6216\u672C\u5730\u67E5\u770B\u3002" };
8672
+ const content = await readFile4(blob, "utf8");
8673
+ if (content.split("\n").length > 2e3) return { content: "", notice: "\u6587\u4EF6\u8D85\u8FC7 2000 \u884C\uFF0C\u5DF2\u8DF3\u8FC7\u9884\u89C8\uFF0C\u8BF7\u5728\u6587\u4EF6\u9762\u677F\u6216\u672C\u5730\u67E5\u770B\u3002" };
8674
+ return { content };
8675
+ }
8611
8676
  associate(project, path, sessionId) {
8612
8677
  return this.serial(project, () => this.associateUnlocked(project, path, sessionId));
8613
8678
  }
@@ -8629,7 +8694,7 @@ import { TLSSocket, createSecureContext } from "node:tls";
8629
8694
 
8630
8695
  // src/host-auth.ts
8631
8696
  import { spawn } from "node:child_process";
8632
- import { chmod as chmod3, mkdir as mkdir5, rename as rename3, stat as stat6, unlink as unlink5 } from "node:fs/promises";
8697
+ import { chmod as chmod3, mkdir as mkdir5, rename as rename3, stat as stat7, unlink as unlink5 } from "node:fs/promises";
8633
8698
  import { userInfo, platform as platform2 } from "node:os";
8634
8699
  import { randomUUID as randomUUID6 } from "node:crypto";
8635
8700
  import { join as join7 } from "node:path";
@@ -8644,8 +8709,8 @@ async function ensureHostAuth(stateDirectory) {
8644
8709
  if (system !== "darwin" && system !== "linux") throw new Error("Host authentication is supported only on macOS and Linux");
8645
8710
  const mac = system === "darwin";
8646
8711
  const source = fileURLToPath2(new URL(mac ? "../native/auth-macos.m" : "../native/auth-linux.c", import.meta.url));
8647
- const sourceInfo = await stat6(source);
8648
- const existing = await stat6(target).catch(() => null);
8712
+ const sourceInfo = await stat7(source);
8713
+ const existing = await stat7(target).catch(() => null);
8649
8714
  if (existing?.isFile() && existing.mtimeMs >= sourceInfo.mtimeMs && (existing.mode & 63) === 0) return target;
8650
8715
  const temporary = `${target}.${randomUUID6()}`;
8651
8716
  const args = mac ? ["-O2", "-framework", "Foundation", "-framework", "OpenDirectory", source, "-o", target] : ["-O2", source, "-o", temporary, "-lpam"];
@@ -9130,7 +9195,11 @@ var SecureChat = class {
9130
9195
  if (this.sessions.get(id) !== session || !session.authenticated || !this.devices.has(session.deviceKey)) throw new Error("Device authorization revoked or session closed");
9131
9196
  return this.dispatch(command, id);
9132
9197
  }, id);
9133
- if (this.sessions.get(id) === session && session.authenticated && this.devices.has(session.deviceKey)) sendJson(session.tls, response);
9198
+ if (this.sessions.get(id) === session && session.authenticated && this.devices.has(session.deviceKey)) {
9199
+ if (Buffer.byteLength(JSON.stringify(response)) > MAX_PLAINTEXT) {
9200
+ sendJson(session.tls, { type: "response", id: command.id, botId: command.botId, status: "failed", error: "Operation result exceeds the 3 MiB secure message limit; request a smaller page" });
9201
+ } else sendJson(session.tls, response);
9202
+ }
9134
9203
  }
9135
9204
  closeSession(id) {
9136
9205
  const session = this.sessions.get(id);
@@ -13618,7 +13687,7 @@ function createAdapter(runtime, workspace, uploads, emit) {
13618
13687
  }
13619
13688
 
13620
13689
  // src/project-registry.ts
13621
- import { realpath as realpath6, readFile as readFile9, stat as stat7 } from "node:fs/promises";
13690
+ import { realpath as realpath6, readFile as readFile9, stat as stat8 } from "node:fs/promises";
13622
13691
  import { isAbsolute as isAbsolute4 } from "node:path";
13623
13692
  import { isDeepStrictEqual } from "node:util";
13624
13693
  var ProjectMutationSchema = ProjectSchema.extend({
@@ -13706,7 +13775,7 @@ var ProjectRegistry = class {
13706
13775
  const raw = await this.readCurrent();
13707
13776
  const directory = expandHome(parsed.directory);
13708
13777
  if (!isAbsolute4(directory)) throw new Error("\u9879\u76EE\u76EE\u5F55\u5FC5\u987B\u662F Proxy \u4E3B\u673A\u4E0A\u7684\u7EDD\u5BF9\u8DEF\u5F84");
13709
- const info = await stat7(directory).catch(() => void 0);
13778
+ const info = await stat8(directory).catch(() => void 0);
13710
13779
  if (!info?.isDirectory()) throw new Error(`\u9879\u76EE\u76EE\u5F55\u4E0D\u5B58\u5728\u6216\u4E0D\u662F\u76EE\u5F55\uFF1A${directory}`);
13711
13780
  const canonical = await realpath6(directory);
13712
13781
  if (this.config.projects.some((project2) => project2.id === parsed.id)) throw new Error(`\u9879\u76EE ID \u5DF2\u5B58\u5728\uFF1A${parsed.id}`);
@@ -13725,7 +13794,7 @@ var ProjectRegistry = class {
13725
13794
  if (index < 0) throw new Error(`\u672A\u77E5\u6388\u6743\u9879\u76EE\uFF1A${parsed.id}`);
13726
13795
  const directory = expandHome(parsed.directory);
13727
13796
  if (!isAbsolute4(directory)) throw new Error("\u9879\u76EE\u76EE\u5F55\u5FC5\u987B\u662F Proxy \u4E3B\u673A\u4E0A\u7684\u7EDD\u5BF9\u8DEF\u5F84");
13728
- const info = await stat7(directory).catch(() => void 0);
13797
+ const info = await stat8(directory).catch(() => void 0);
13729
13798
  if (!info?.isDirectory()) throw new Error(`\u9879\u76EE\u76EE\u5F55\u4E0D\u5B58\u5728\u6216\u4E0D\u662F\u76EE\u5F55\uFF1A${directory}`);
13730
13799
  const canonical = await realpath6(directory);
13731
13800
  for (const project of this.config.projects) {
@@ -13756,7 +13825,7 @@ var ProjectRegistry = class {
13756
13825
 
13757
13826
  // src/terminal.ts
13758
13827
  import { randomUUID as randomUUID17 } from "node:crypto";
13759
- import { access as access2, stat as stat9 } from "node:fs/promises";
13828
+ import { access as access2, stat as stat10 } from "node:fs/promises";
13760
13829
  import { constants as constants5 } from "node:fs";
13761
13830
  import { platform as platform3, userInfo as userInfo3 } from "node:os";
13762
13831
  import { delimiter } from "node:path";
@@ -13764,7 +13833,7 @@ import * as pty from "node-pty";
13764
13833
 
13765
13834
  // src/terminal-support.ts
13766
13835
  import { createRequire } from "node:module";
13767
- import { access, chmod as chmod4, stat as stat8 } from "node:fs/promises";
13836
+ import { access, chmod as chmod4, stat as stat9 } from "node:fs/promises";
13768
13837
  import { constants as constants4 } from "node:fs";
13769
13838
  import { dirname as dirname6, resolve as resolve4 } from "node:path";
13770
13839
  var require2 = createRequire(import.meta.url);
@@ -13774,7 +13843,7 @@ function terminalHelperPath() {
13774
13843
  return resolve4(dirname6(utilsPath), native.dir, "spawn-helper");
13775
13844
  }
13776
13845
  async function prepareTerminalHelper(path, fix) {
13777
- const info = await stat8(path);
13846
+ const info = await stat9(path);
13778
13847
  if (!info.isFile()) throw new Error(`\u7EC8\u7AEF\u8F85\u52A9\u7A0B\u5E8F\u4E0D\u662F\u666E\u901A\u6587\u4EF6\uFF1A${path}`);
13779
13848
  try {
13780
13849
  await access(path, constants4.X_OK);
@@ -13833,7 +13902,7 @@ var TerminalManager = class {
13833
13902
  const count = [...this.terminals.values()].filter((t) => t.owner === owner).length;
13834
13903
  if (count >= 8) throw new Error("Terminal limit reached");
13835
13904
  const cwd = await this.workspace.path(project, typeof p.cwd === "string" ? p.cwd : ".");
13836
- if (!(await stat9(cwd)).isDirectory()) throw new Error(`\u7EC8\u7AEF\u5DE5\u4F5C\u76EE\u5F55\u4E0D\u662F\u76EE\u5F55\uFF1A${cwd}`);
13905
+ if (!(await stat10(cwd)).isDirectory()) throw new Error(`\u7EC8\u7AEF\u5DE5\u4F5C\u76EE\u5F55\u4E0D\u662F\u76EE\u5F55\uFF1A${cwd}`);
13837
13906
  const shell = process.env.SHELL || (platform3() === "darwin" ? "/bin/zsh" : "/bin/sh");
13838
13907
  try {
13839
13908
  await access2(shell, constants5.X_OK);
@@ -13964,7 +14033,7 @@ import { randomBytes as randomBytes2, randomUUID as randomUUID19 } from "node:cr
13964
14033
  import { fileURLToPath as fileURLToPath5 } from "node:url";
13965
14034
 
13966
14035
  // src/remote-native.ts
13967
- import { chmod as chmod5, mkdir as mkdir9, readFile as readFile10, rename as rename5, rm as rm3, stat as stat10, writeFile as writeFile7 } from "node:fs/promises";
14036
+ import { chmod as chmod5, mkdir as mkdir9, readFile as readFile10, rename as rename5, rm as rm3, stat as stat11, writeFile as writeFile7 } from "node:fs/promises";
13968
14037
  import { join as join14 } from "node:path";
13969
14038
  import { fileURLToPath as fileURLToPath4 } from "node:url";
13970
14039
  import { createHash as createHash10, randomUUID as randomUUID18 } from "node:crypto";
@@ -13975,7 +14044,7 @@ async function ensureRemoteHelper(stateDirectory, adapter = RemotePlatformRegist
13975
14044
  const target = join14(stateDirectory, "octopus-remote-desktop");
13976
14045
  const stamp = `${target}.sha256`;
13977
14046
  const fingerprint = createHash10("sha256").update(await readFile10(source)).update(JSON.stringify([adapter.context.platform, adapter.context.arch, build.flags])).digest("hex");
13978
- const existing = await stat10(target).catch(() => void 0);
14047
+ const existing = await stat11(target).catch(() => void 0);
13979
14048
  if (existing?.isFile() && (existing.mode & 63) === 0 && await readFile10(stamp, "utf8").catch(() => "") === fingerprint) return target;
13980
14049
  const temporary = `${target}.${randomUUID18()}`, temporaryStamp = `${temporary}.sha256`;
13981
14050
  const args = build.args(source, temporary);
@@ -14224,7 +14293,7 @@ import { platform as platform5 } from "node:os";
14224
14293
  import { isDeepStrictEqual as isDeepStrictEqual2 } from "node:util";
14225
14294
 
14226
14295
  // src/node-resolution.ts
14227
- import { realpath as realpath7, stat as stat11 } from "node:fs/promises";
14296
+ import { realpath as realpath7, stat as stat12 } from "node:fs/promises";
14228
14297
  import { execFile as execFile7 } from "node:child_process";
14229
14298
  import { promisify as promisify7 } from "node:util";
14230
14299
  import { join as join15 } from "node:path";
@@ -14279,7 +14348,7 @@ async function resolveCommandOnPath(name, extraDirs = []) {
14279
14348
  for (const dir of new Set(dirs)) {
14280
14349
  const full = join15(dir, name);
14281
14350
  try {
14282
- const info = await stat11(full);
14351
+ const info = await stat12(full);
14283
14352
  if (info.isFile() && info.mode & 73) return full;
14284
14353
  } catch {
14285
14354
  }
@@ -14489,7 +14558,7 @@ async function runDaemon(configPath, authenticate = verifyHostPassword) {
14489
14558
  workspace.project(project);
14490
14559
  if (c.operation === "workspace.list") return p.paged === true ? workspace.listPage(project, String(p.path ?? "."), p.cursor === void 0 ? "" : p.cursor, p.limit === void 0 ? 200 : Number(p.limit)) : workspace.list(project, String(p.path ?? "."));
14491
14560
  if (c.operation === "workspace.read") return workspace.read(project, String(p.path), Number(p.offset ?? 0), Number(p.length ?? 512 * 1024));
14492
- if (c.operation === "workspace.diff") return workspaceDiff(workspace, project);
14561
+ if (c.operation === "workspace.diff") return workspaceDiff(workspace, project, { paged: p.paged === true, offset: Number(p.offset ?? 0), limit: Number(p.limit ?? 20) });
14493
14562
  if (c.operation === "workspace.search") return workspace.search(project, String(p.query));
14494
14563
  if (c.operation === "workspace.write") return workspace.write(project, String(p.path), String(p.content), String(p.expectedHash));
14495
14564
  if (c.operation === "uploads.init") {
@@ -14503,9 +14572,9 @@ async function runDaemon(configPath, authenticate = verifyHostPassword) {
14503
14572
  if (c.operation === "uploads.chunk") return uploads.chunk(project, String(p.id), Number(p.offset), String(p.data));
14504
14573
  if (c.operation === "uploads.complete") return uploads.complete(project, String(p.id));
14505
14574
  if (c.operation === "uploads.cancel") return uploads.cancel(project, String(p.id));
14506
- if (c.operation === "artifacts.list") return artifacts.scan(project);
14575
+ if (c.operation === "artifacts.list") return p.paged === true ? artifacts.scanPage(project, Number(p.offset ?? 0), Number(p.limit ?? 20)) : artifacts.scan(project);
14507
14576
  if (c.operation === "artifacts.history") return artifacts.history(project, String(p.path));
14508
- if (c.operation === "artifacts.read") return artifacts.read(project, String(p.path), String(p.hash));
14577
+ if (c.operation === "artifacts.read") return p.preview === true ? artifacts.preview(project, String(p.path), String(p.hash)) : artifacts.read(project, String(p.path), String(p.hash));
14509
14578
  if (c.operation === "artifacts.associate") {
14510
14579
  if (!c.sessionId) throw new Error("Session required");
14511
14580
  await adapter.session(project, c.sessionId);
package/dist/cli.js CHANGED
@@ -35,7 +35,7 @@ import {
35
35
  supportedPlatform,
36
36
  systemdUnitPath,
37
37
  toolSearchDirs
38
- } from "./chunk-4CKW4ICE.js";
38
+ } from "./chunk-IKWSVBPJ.js";
39
39
  import {
40
40
  DESKTOP_PERMISSION_GUIDANCE,
41
41
  PlatformDesktop,
package/dist/main.js CHANGED
@@ -2,7 +2,7 @@
2
2
  import {
3
3
  ConfigError,
4
4
  runDaemon
5
- } from "./chunk-4CKW4ICE.js";
5
+ } from "./chunk-IKWSVBPJ.js";
6
6
  import "./chunk-OTKNRBZ7.js";
7
7
 
8
8
  // src/main.ts
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@skylandnpm/octopus-proxy",
3
- "version": "0.1.67",
3
+ "version": "0.1.69",
4
4
  "type": "module",
5
5
  "description": "Octopus host proxy: OpenCode, Codex, ZCode and Pi adapters with service installer CLI",
6
6
  "bin": {