offsite 0.0.63 → 0.0.64

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.
@@ -301,6 +301,7 @@ function findCodex() {
301
301
  var AppServer = class {
302
302
  home;
303
303
  threads = /* @__PURE__ */ new Map();
304
+ agents = /* @__PURE__ */ new Map();
304
305
  child;
305
306
  waiting = /* @__PURE__ */ new Map();
306
307
  ready;
@@ -417,9 +418,16 @@ var AppServer = class {
417
418
  }
418
419
  const params = message.params ?? {};
419
420
  const listener = typeof params.threadId === "string" ? this.threads.get(params.threadId) : void 0;
421
+ const root = this.rootOf(params.threadId);
422
+ const owner = root === void 0 ? void 0 : this.threads.get(root);
423
+ if (root !== void 0) this.linkAgents(root, params.item);
420
424
  if (message.id !== void 0) {
421
- if (listener === void 0) this.replyError(message.id, `offsite does not handle ${message.method}`);
422
- else listener.request(message.id, message.method, params);
425
+ if (owner === void 0) this.replyError(message.id, `offsite does not handle ${message.method}`);
426
+ else owner.request(message.id, message.method, params);
427
+ return;
428
+ }
429
+ if (message.method === "serverRequest/resolved") {
430
+ owner?.notify(message.method, params);
423
431
  return;
424
432
  }
425
433
  if (message.method === "account/rateLimits/updated") {
@@ -428,6 +436,14 @@ var AppServer = class {
428
436
  }
429
437
  listener?.notify(message.method, params);
430
438
  }
439
+ rootOf(threadId) {
440
+ if (typeof threadId !== "string") return;
441
+ return this.threads.has(threadId) ? threadId : this.agents.get(threadId);
442
+ }
443
+ linkAgents(root, item) {
444
+ if (item?.type === "subAgentActivity") this.agents.set(item.agentThreadId, root);
445
+ if (item?.type === "collabAgentToolCall") for (const agent of item.receiverThreadIds) this.agents.set(agent, root);
446
+ }
431
447
  armIdleTimer() {
432
448
  clearTimeout(this.idleTimer);
433
449
  this.idleTimer = setTimeout(() => {
@@ -1748,7 +1764,13 @@ function fold(text) {
1748
1764
  return folded.length === 1 ? folded : character;
1749
1765
  }).toLowerCase();
1750
1766
  }
1767
+ function exactPhrase(query) {
1768
+ const phrase = /^"([^"]+)"$/.exec(query.trim())?.[1].trim();
1769
+ return phrase === void 0 || phrase === "" ? null : phrase;
1770
+ }
1751
1771
  function searchWords(query) {
1772
+ const phrase = exactPhrase(query);
1773
+ if (phrase !== null) return [fold(phrase)];
1752
1774
  return fold(query).replace(/^["'`]+|["'`]+$/g, "").split(/\s+/).filter(Boolean);
1753
1775
  }
1754
1776
  function hasSearchableWord(query) {
@@ -1763,6 +1785,28 @@ function isWordStart(text, index) {
1763
1785
  function isWordEnd(text, end) {
1764
1786
  return end >= text.length || !alphanumeric.test(text[end]) || isWordStart(text, end);
1765
1787
  }
1788
+ function mergeRanges(ranges) {
1789
+ const merged = [];
1790
+ for (const range of [...ranges].sort((a, b) => a.start - b.start)) {
1791
+ const last = merged.at(-1);
1792
+ if (last !== void 0 && range.start <= last.end) last.end = Math.max(last.end, range.end);
1793
+ else merged.push({ ...range });
1794
+ }
1795
+ return merged;
1796
+ }
1797
+ function exactRanges(folded, phrase) {
1798
+ const ranges = [];
1799
+ for (let index = folded.indexOf(phrase); index !== -1; index = folded.indexOf(phrase, index + 1)) {
1800
+ const end = index + phrase.length;
1801
+ const joinedBefore = alphanumeric.test(phrase[0]) && alphanumeric.test(folded[index - 1] ?? "");
1802
+ const joinedAfter = alphanumeric.test(phrase[phrase.length - 1]) && alphanumeric.test(folded[end] ?? "");
1803
+ if (!joinedBefore && !joinedAfter) ranges.push({
1804
+ start: index,
1805
+ end
1806
+ });
1807
+ }
1808
+ return mergeRanges(ranges);
1809
+ }
1766
1810
  function findWord(text, folded, word) {
1767
1811
  let quality = 0;
1768
1812
  let at = -1;
@@ -1782,6 +1826,13 @@ function matchMessage(query, text) {
1782
1826
  const words = searchWords(query);
1783
1827
  if (words.length === 0) return null;
1784
1828
  const folded = fold(text);
1829
+ if (exactPhrase(query) !== null) {
1830
+ const range = exactRanges(folded, words[0]).at(0);
1831
+ return range === void 0 ? null : {
1832
+ quality: 1,
1833
+ offset: range.start
1834
+ };
1835
+ }
1785
1836
  let quality = 1;
1786
1837
  let offset = text.length;
1787
1838
  for (const word of words) {
@@ -2223,7 +2274,10 @@ async function openCodeSessions(paths) {
2223
2274
  directory,
2224
2275
  parentID: null,
2225
2276
  limit: PAGE
2226
- } : { cursor });
2277
+ } : {
2278
+ limit: PAGE,
2279
+ cursor
2280
+ });
2227
2281
  found.push(...page.data);
2228
2282
  cursor = page.data.length === PAGE ? page.cursor.next ?? null : null;
2229
2283
  } while (cursor !== null);
@@ -2360,6 +2414,7 @@ async function allMessages(client, sessionId) {
2360
2414
  order: "asc"
2361
2415
  } : {
2362
2416
  sessionID: sessionId,
2417
+ limit: PAGE,
2363
2418
  cursor
2364
2419
  });
2365
2420
  messages.push(...page.data);
@@ -2903,10 +2958,12 @@ function readProjectFile(cwd, file) {
2903
2958
  content: data.toString("utf8")
2904
2959
  };
2905
2960
  }
2906
- function writeProjectFile(cwd, file, content) {
2961
+ function writeProjectFile(cwd, file, content, base) {
2907
2962
  const full = resolveProjectFile(cwd, file);
2908
2963
  if (!statSync(full).isFile()) throw new Error(`${file} is not a file`);
2964
+ if (base !== null && readFileSync(full, "utf8") !== base) return false;
2909
2965
  writeFileSync(full, content);
2966
+ return true;
2910
2967
  }
2911
2968
  function createProjectEntry(cwd, file, folder) {
2912
2969
  const full = resolveNewProjectPath(cwd, file);
@@ -3172,7 +3229,12 @@ async function gitRepos(cwd) {
3172
3229
  }
3173
3230
  async function commit(cwd, message, andPush) {
3174
3231
  const text = message.trim() === "" ? await commitMessage(cwd, false) : message;
3175
- await git(cwd, ["add", "--all"]);
3232
+ await git(cwd, [
3233
+ "add",
3234
+ "--all",
3235
+ "--",
3236
+ "."
3237
+ ]);
3176
3238
  await git(cwd, [
3177
3239
  "commit",
3178
3240
  "--message",
@@ -3371,7 +3433,9 @@ async function gitStatus(cwd) {
3371
3433
  "--no-optional-locks",
3372
3434
  "status",
3373
3435
  "--porcelain=v2",
3374
- "--branch"
3436
+ "--branch",
3437
+ "--",
3438
+ "."
3375
3439
  ]);
3376
3440
  const status = {
3377
3441
  branch: null,
@@ -3427,14 +3491,16 @@ async function repoDiff(repo, prefix) {
3427
3491
  await diffBase(repo),
3428
3492
  "--no-color",
3429
3493
  "--no-ext-diff",
3494
+ "--relative",
3430
3495
  `--src-prefix=a/${prefix}`,
3431
3496
  `--dst-prefix=b/${prefix}`
3432
3497
  ]);
3433
3498
  const added = (await git(repo, [
3434
3499
  "ls-files",
3435
3500
  "--others",
3436
- "--exclude-standard"
3437
- ])).stdout.split("\n").filter(Boolean).slice(0, UNTRACKED_LIMIT).map((file) => newFilePatch(repo, file, prefix));
3501
+ "--exclude-standard",
3502
+ "-z"
3503
+ ])).stdout.split("\0").filter(Boolean).slice(0, UNTRACKED_LIMIT).map((file) => newFilePatch(repo, file, prefix));
3438
3504
  return [tracked.stdout, ...added].join("");
3439
3505
  }
3440
3506
  async function diffBase(repo) {
@@ -5852,7 +5918,8 @@ async function claudeMessages(sessionId, dir) {
5852
5918
  });
5853
5919
  }
5854
5920
  async function claudeCandidates(query) {
5855
- const words = searchWords(query).filter((word) => word.length >= 3 && !/["\\]/.test(word));
5921
+ const phrase = exactPhrase(query);
5922
+ const words = phrase !== null ? [JSON.stringify(phrase).slice(1, -1)] : searchWords(query).filter((word) => word.length >= 3 && !/["\\]/.test(word));
5856
5923
  if (words.length === 0) return null;
5857
5924
  try {
5858
5925
  const lists = await Promise.all(words.map((word) => sessionsWith(word)));
@@ -5885,7 +5952,7 @@ async function sessionsWith(word) {
5885
5952
  })).stdout.split("\n").filter(Boolean).map((file) => path.basename(file, ".jsonl"));
5886
5953
  }
5887
5954
  async function searchCodex(query, sessions) {
5888
- const longest = [...searchWords(query)].sort((a, b) => b.length - a.length)[0];
5955
+ const longest = exactPhrase(query) ?? [...searchWords(query)].sort((a, b) => b.length - a.length)[0];
5889
5956
  const known = new Map(sessions.map((session) => [session.id, session]));
5890
5957
  const found = (await codexSearch(longest)).filter((result) => known.has(result.thread.id)).sort((a, b) => b.thread.updatedAt - a.thread.updatedAt);
5891
5958
  const verified = await readAndMatch(query, found.slice(0, CODEX_READ_LIMIT).map((result) => ({ id: result.thread.id })), codexMessages);
@@ -6155,7 +6222,7 @@ async function showFile(cwd, ref, file) {
6155
6222
  const output = await git(cwd, [
6156
6223
  "cat-file",
6157
6224
  "blob",
6158
- `${ref}:${file}`
6225
+ `${ref}:./${file}`
6159
6226
  ]);
6160
6227
  if (output.stdout.length > SHOW_LIMIT || output.stdout.includes("\0")) return null;
6161
6228
  return output.stdout;
@@ -6188,6 +6255,7 @@ async function commitFiles(cwd, hash, parent) {
6188
6255
  "--name-status",
6189
6256
  "-M",
6190
6257
  "-z",
6258
+ "--relative",
6191
6259
  parent ?? (await git(cwd, [
6192
6260
  "hash-object",
6193
6261
  "-t",
@@ -6271,7 +6339,7 @@ async function runAction(cwd, action) {
6271
6339
  await git(cwd, [
6272
6340
  "update-index",
6273
6341
  "--cacheinfo",
6274
- `${entry.stdout.split(" ")[0]},${hash},${action.path}`
6342
+ `${entry.stdout.split(" ")[0]},${hash},${await repoPrefix(cwd)}${action.path}`
6275
6343
  ]);
6276
6344
  return;
6277
6345
  }
@@ -6311,7 +6379,12 @@ async function runAction(cwd, action) {
6311
6379
  return;
6312
6380
  }
6313
6381
  if (action.kind === "commit") {
6314
- if (action.all) await git(cwd, ["add", "--all"]);
6382
+ if (action.all) await git(cwd, [
6383
+ "add",
6384
+ "--all",
6385
+ "--",
6386
+ "."
6387
+ ]);
6315
6388
  await git(cwd, [
6316
6389
  "commit",
6317
6390
  ...action.amend ? ["--amend"] : [],
@@ -6365,6 +6438,9 @@ async function network(cwd, args) {
6365
6438
  throw gitError(error);
6366
6439
  }
6367
6440
  }
6441
+ async function repoPrefix(cwd) {
6442
+ return (await git(cwd, ["rev-parse", "--show-prefix"])).stdout.trim();
6443
+ }
6368
6444
  async function repoChanges(cwd) {
6369
6445
  const output = await git(cwd, [
6370
6446
  "--no-optional-locks",
@@ -6372,8 +6448,11 @@ async function repoChanges(cwd) {
6372
6448
  "--porcelain=v2",
6373
6449
  "--branch",
6374
6450
  "--untracked-files=all",
6375
- "-z"
6451
+ "-z",
6452
+ "--",
6453
+ "."
6376
6454
  ]);
6455
+ const prefix = await repoPrefix(cwd);
6377
6456
  const repo = {
6378
6457
  head: null,
6379
6458
  branch: null,
@@ -6396,19 +6475,19 @@ async function repoChanges(cwd) {
6396
6475
  repo.behind = -Number(fields[3]);
6397
6476
  }
6398
6477
  if (fields[0] === "?") repo.changes.push({
6399
- path: tokens[index].slice(2),
6478
+ path: tokens[index].slice(2 + prefix.length),
6400
6479
  from: null,
6401
6480
  status: "U"
6402
6481
  });
6403
6482
  if (fields[0] === "u") repo.merge.push({
6404
- path: fields.slice(10).join(" "),
6483
+ path: fields.slice(10).join(" ").slice(prefix.length),
6405
6484
  from: null,
6406
6485
  status: "!"
6407
6486
  });
6408
6487
  if (fields[0] === "1" || fields[0] === "2") {
6409
6488
  const renamed = fields[0] === "2";
6410
- const file = fields.slice(renamed ? 9 : 8).join(" ");
6411
- const from = renamed ? tokens[index + 1] : null;
6489
+ const file = fields.slice(renamed ? 9 : 8).join(" ").slice(prefix.length);
6490
+ const from = renamed ? tokens[index + 1].slice(prefix.length) : null;
6412
6491
  if (fields[1][0] !== ".") repo.staged.push({
6413
6492
  path: file,
6414
6493
  from,
@@ -7518,10 +7597,7 @@ const handlers = {
7518
7597
  "files.list": (params) => listFiles(projectPath(params.projectId)),
7519
7598
  "files.entries": (params) => listEntries(projectPath(params.projectId)),
7520
7599
  "files.read": (params) => readProjectFile(projectPath(params.projectId), params.path),
7521
- "files.write": (params) => {
7522
- writeProjectFile(projectPath(params.projectId), params.path, params.content);
7523
- return null;
7524
- },
7600
+ "files.write": (params) => writeProjectFile(projectPath(params.projectId), params.path, params.content, params.base),
7525
7601
  "files.create": (params) => {
7526
7602
  createProjectEntry(projectPath(params.projectId), params.path, params.folder);
7527
7603
  return null;
@@ -8626,6 +8702,11 @@ async function forward(site, target, request, response) {
8626
8702
  const kind = rewriteKind(incoming, request);
8627
8703
  response.statusCode = status;
8628
8704
  copyHeaders(incoming, response, kind !== null);
8705
+ if (kind === "html") {
8706
+ response.removeHeader("last-modified");
8707
+ response.removeHeader("expires");
8708
+ response.setHeader("cache-control", "no-store, no-transform");
8709
+ }
8629
8710
  const location = incoming.headers.location;
8630
8711
  if (location !== void 0) {
8631
8712
  const next = URL.parse(location, target);