chatroom-cli 1.64.0 → 1.65.1

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/index.js CHANGED
@@ -33370,7 +33370,8 @@ var exports_cursor_sdk_package = {};
33370
33370
  __export(exports_cursor_sdk_package, {
33371
33371
  importBundledCursorSdk: () => importBundledCursorSdk,
33372
33372
  getBundledCursorSdkVersion: () => getBundledCursorSdkVersion,
33373
- formatCursorSdkLoadError: () => formatCursorSdkLoadError
33373
+ formatCursorSdkLoadError: () => formatCursorSdkLoadError,
33374
+ formatCursorSdkError: () => formatCursorSdkError
33374
33375
  });
33375
33376
  import { existsSync as existsSync2, readFileSync as readFileSync4 } from "node:fs";
33376
33377
  import { createRequire as createRequire4 } from "node:module";
@@ -33435,11 +33436,20 @@ function getBundledCursorSdkVersion(moduleRef = import.meta.url) {
33435
33436
  const entryPath = require3.resolve("@cursor/sdk", { paths: [chatroomCliRoot] });
33436
33437
  return readInstalledSdkVersion2(entryPath);
33437
33438
  }
33439
+ function formatCursorSdkError(err) {
33440
+ if (err instanceof Error) {
33441
+ const sdkErr = err;
33442
+ const code2 = sdkErr.code ? `[${sdkErr.code}] ` : "";
33443
+ const name = sdkErr.name && sdkErr.name !== "Error" ? `${sdkErr.name}: ` : "";
33444
+ return `${name}${code2}${err.message}`.trim();
33445
+ }
33446
+ return String(err);
33447
+ }
33438
33448
  function formatCursorSdkLoadError(err) {
33439
33449
  if (err instanceof CursorSdkPackageError) {
33440
33450
  return err.message;
33441
33451
  }
33442
- const message = err instanceof Error ? err.message : String(err);
33452
+ const message = formatCursorSdkError(err);
33443
33453
  const chunkMatch = message.match(/(\d+)\.index\.js/);
33444
33454
  if (chunkMatch) {
33445
33455
  return `@cursor/sdk installation is incomplete (missing ${chunkMatch[1]}.index.js). ${REINSTALL_HINT2}`;
@@ -33483,6 +33493,11 @@ var init_cursor_sdk_stream_adapter = __esm(() => {
33483
33493
  break;
33484
33494
  case "tool_call": {
33485
33495
  this.flushText();
33496
+ if (message.status === "error") {
33497
+ const detail = message.result !== undefined ? JSON.stringify(message.result) : "no result";
33498
+ this.writeLine(formatAgentLogLine(this.logPrefix, "tool-error", `${message.name} (${message.call_id}): ${detail}`));
33499
+ break;
33500
+ }
33486
33501
  const bashCmd = extractBashCommandFromToolInput(message.name, message.args);
33487
33502
  if (bashCmd !== null) {
33488
33503
  this.writeLine(formatAgentLogLine(this.logPrefix, BASH_TOOL_KIND, formatBashRunningPayload(bashCmd)));
@@ -33491,9 +33506,11 @@ var init_cursor_sdk_stream_adapter = __esm(() => {
33491
33506
  this.writeLine(formatAgentLogLine(this.logPrefix, `tool: ${message.call_id} ${message.name} ${JSON.stringify({ status: message.status, args: message.args })}`));
33492
33507
  break;
33493
33508
  }
33494
- case "status":
33495
- this.writeLine(formatAgentLogLine(this.logPrefix, `status: ${message.status}`));
33509
+ case "status": {
33510
+ const payload = message.message ? `${message.status}: ${message.message}` : message.status;
33511
+ this.writeLine(formatAgentLogLine(this.logPrefix, "status", payload));
33496
33512
  break;
33513
+ }
33497
33514
  case "thinking":
33498
33515
  this.writeLine(formatAgentLogLine(this.logPrefix, "thinking", message.text));
33499
33516
  break;
@@ -33502,8 +33519,16 @@ var init_cursor_sdk_stream_adapter = __esm(() => {
33502
33519
  this.writeLine(formatAgentLogLine(this.logPrefix, "system: init"));
33503
33520
  }
33504
33521
  break;
33505
- default:
33522
+ case "task":
33523
+ this.writeLine(formatAgentLogLine(this.logPrefix, "task", [message.status, message.text].filter(Boolean).join(": ")));
33506
33524
  break;
33525
+ default: {
33526
+ const unknown = message;
33527
+ if (unknown.type) {
33528
+ this.writeLine(formatAgentLogLine(this.logPrefix, "stream", `unhandled type: ${unknown.type}`));
33529
+ }
33530
+ break;
33531
+ }
33507
33532
  }
33508
33533
  }
33509
33534
  flushPendingOutput() {
@@ -33604,8 +33629,14 @@ function waitForResumeOrAbort2(session2) {
33604
33629
  function resolveModelId(model) {
33605
33630
  return model ? resolveCursorSdkModel(model) : DEFAULT_MODEL;
33606
33631
  }
33632
+ function buildLocalAgentOptions(cwd) {
33633
+ return {
33634
+ cwd,
33635
+ settingSources: []
33636
+ };
33637
+ }
33607
33638
  function writeSpawnError2(logPrefix, err, emitLogLine) {
33608
- const line = formatAgentLogLine(logPrefix, "spawn-error", formatCursorSdkLoadError(err));
33639
+ const line = formatAgentLogLine(logPrefix, "spawn-error", formatCursorSdkError(err));
33609
33640
  process.stderr.write(`${line}
33610
33641
  `);
33611
33642
  emitLogLine?.(line);
@@ -33724,6 +33755,7 @@ var init_cursor_sdk_agent_service = __esm(() => {
33724
33755
  const keeper = this.spawnKeeper(options.workingDir);
33725
33756
  const pid = keeper.pid;
33726
33757
  const context5 = options.context;
33758
+ const logPrefix = buildAgentLogPrefix("cursor-sdk", context5);
33727
33759
  const agentName = stored.agentName;
33728
33760
  const modelId = resolveModelId(options.model ?? stored.model);
33729
33761
  const systemPrompt = options.systemPrompt ? `${NO_SUBAGENT_DIRECTIVE2}
@@ -33738,11 +33770,11 @@ ${options.prompt}`;
33738
33770
  agent = await withTimeout(Agent.resume(stored.harnessSessionId, {
33739
33771
  apiKey,
33740
33772
  model: { id: modelId },
33741
- local: { cwd: stored.workingDir, settingSources: [] }
33773
+ local: buildLocalAgentOptions(stored.workingDir)
33742
33774
  }), AGENT_CREATE_TIMEOUT_MS, "Agent.resume");
33743
33775
  } catch (err) {
33744
- const reason = err instanceof Error ? err.message : String(err);
33745
- process.stderr.write(`[${new Date().toISOString()}] role:${context5.role} daemon-resume-fallback] ${reason} — cold spawning
33776
+ writeSpawnError2(logPrefix, err);
33777
+ process.stderr.write(`[${new Date().toISOString()}] role:${context5.role} daemon-resume-fallback] ${formatCursorSdkError(err)} — cold spawning
33746
33778
  `);
33747
33779
  keeper.kill();
33748
33780
  this.deleteProcess(pid);
@@ -33990,6 +34022,7 @@ ${deferredResume}` : deferredResume;
33990
34022
  const keeper = this.spawnKeeper(options.workingDir);
33991
34023
  const pid = keeper.pid;
33992
34024
  const context5 = options.context;
34025
+ const logPrefix = buildAgentLogPrefix("cursor-sdk", context5);
33993
34026
  const agentName = buildAgentName(context5);
33994
34027
  const modelId = resolveModelId(options.model);
33995
34028
  const systemPrompt = options.systemPrompt ? `${NO_SUBAGENT_DIRECTIVE2}
@@ -34005,9 +34038,10 @@ ${options.prompt}`;
34005
34038
  apiKey,
34006
34039
  name: agentName,
34007
34040
  model: { id: modelId, params: [{ id: "fast", value: "false" }] },
34008
- local: { cwd: options.workingDir, settingSources: [] }
34041
+ local: buildLocalAgentOptions(options.workingDir)
34009
34042
  }), AGENT_CREATE_TIMEOUT_MS, "Agent.create");
34010
34043
  } catch (err) {
34044
+ writeSpawnError2(logPrefix, err);
34011
34045
  keeper.kill();
34012
34046
  this.deleteProcess(pid);
34013
34047
  throw err;
@@ -36119,6 +36153,8 @@ function isClassifiableHarnessLogLine(line) {
36119
36153
  return false;
36120
36154
  if (line.includes("agent_end]"))
36121
36155
  return true;
36156
+ if (line.includes("spawn-error]"))
36157
+ return true;
36122
36158
  if (line.includes(" error]"))
36123
36159
  return true;
36124
36160
  if (line.includes(" run-error]"))
@@ -36165,7 +36201,9 @@ var init_terminal_provider_error = __esm(() => {
36165
36201
  FATAL_HARNESS_PHRASES = [
36166
36202
  "failed to load model",
36167
36203
  "model loading was stopped",
36168
- "insufficient system resources"
36204
+ "insufficient system resources",
36205
+ "sandboxing is not supported",
36206
+ "disable local.sandboxoptions.enabled"
36169
36207
  ];
36170
36208
  QUOTA_PHRASES = [
36171
36209
  "usagelimit",
@@ -79757,7 +79795,6 @@ var init_errorCodes = __esm(() => {
79757
79795
  TEAM_REQUIRED: "TEAM_REQUIRED",
79758
79796
  CONFIGURATION_ERROR: "CONFIGURATION_ERROR",
79759
79797
  PARTICIPANT_NOT_FOUND: "PARTICIPANT_NOT_FOUND",
79760
- CONTEXT_NO_HANDOFF_SINCE_LAST_CONTEXT: "CONTEXT_NO_HANDOFF_SINCE_LAST_CONTEXT",
79761
79798
  CONTEXT_NOT_FOUND: "CONTEXT_NOT_FOUND",
79762
79799
  CONTEXT_RESTRICTED: "CONTEXT_RESTRICTED",
79763
79800
  INVALID_ROLE: "INVALID_ROLE",
@@ -79836,7 +79873,6 @@ var init_errorCodes = __esm(() => {
79836
79873
  BACKEND_ERROR_CODES.FEATURE_DISABLED
79837
79874
  ];
79838
79875
  NON_FATAL_ERROR_CODES = [
79839
- BACKEND_ERROR_CODES.CONTEXT_NO_HANDOFF_SINCE_LAST_CONTEXT,
79840
79876
  BACKEND_ERROR_CODES.CONTEXT_NOT_FOUND,
79841
79877
  BACKEND_ERROR_CODES.CONTEXT_RESTRICTED,
79842
79878
  BACKEND_ERROR_CODES.BACKLOG_ITEM_NOT_FOUND,
@@ -83695,21 +83731,6 @@ function handleContextError(err) {
83695
83731
  } else if (err._tag === "EmptyContent") {
83696
83732
  console.error(`❌ Context content cannot be empty`);
83697
83733
  process.exit(1);
83698
- } else if (err._tag === "ContextNoHandoffSinceLast") {
83699
- const { content, createdAt, createdBy } = err.existingContext;
83700
- console.error(`❌ Cannot create new context: no handoff sent since last context was created.`);
83701
- console.error(`
83702
- \uD83D\uDCCC Current Context (resume from here):`);
83703
- console.error(` Created by: ${sanitizeForTerminal(createdBy)}`);
83704
- console.error(` Created at: ${new Date(createdAt).toLocaleString()}`);
83705
- console.error(` Content:`);
83706
- const safeContent = sanitizeForTerminal(content);
83707
- console.error(safeContent.split(`
83708
- `).map((l) => ` ${l}`).join(`
83709
- `));
83710
- console.error(`
83711
- \uD83D\uDCA1 Send a handoff first, then create a new context.`);
83712
- process.exit(1);
83713
83734
  } else if (err._tag === "ReadContextFailed") {
83714
83735
  console.error(`❌ Failed to read context: ${sanitizeUnknownForTerminal(err.cause.message)}`);
83715
83736
  process.exit(1);
@@ -83885,19 +83906,10 @@ var readContextEffect = (chatroomId, options) => exports_Effect.gen(function* ()
83885
83906
  content: options.content,
83886
83907
  role: options.role,
83887
83908
  triggerMessageId: options.triggerMessageId
83888
- }).pipe(exports_Effect.catchAll((cause3) => {
83889
- const errData = cause3.data;
83890
- if (errData?.code === "CONTEXT_NO_HANDOFF_SINCE_LAST_CONTEXT" && errData.existingContext) {
83891
- return exports_Effect.fail({
83892
- _tag: "ContextNoHandoffSinceLast",
83893
- existingContext: errData.existingContext
83894
- });
83895
- }
83896
- return exports_Effect.fail({
83897
- _tag: "NewContextFailed",
83898
- cause: cause3
83899
- });
83900
- }));
83909
+ }).pipe(exports_Effect.catchAll((cause3) => exports_Effect.fail({
83910
+ _tag: "NewContextFailed",
83911
+ cause: cause3
83912
+ })));
83901
83913
  yield* exports_Effect.sync(() => {
83902
83914
  console.log(`✅ Context created successfully`);
83903
83915
  console.log(` Context ID: ${contextId}`);
@@ -84692,765 +84704,6 @@ var init_daemon_services = __esm(() => {
84692
84704
  };
84693
84705
  });
84694
84706
 
84695
- // src/commands/machine/daemon-start/utils.ts
84696
- function formatTimestamp() {
84697
- return new Date().toISOString().replace("T", " ").substring(0, 19);
84698
- }
84699
-
84700
- // src/infrastructure/services/workspace/dir-listing-content-hash.ts
84701
- import { createHash as createHash2 } from "node:crypto";
84702
- function computeDirListingContentHash(listing) {
84703
- const payload = {
84704
- entries: listing.entries,
84705
- truncated: listing.truncated,
84706
- totalCount: listing.totalCount
84707
- };
84708
- return createHash2("md5").update(JSON.stringify(payload)).digest("hex");
84709
- }
84710
- var init_dir_listing_content_hash = () => {};
84711
-
84712
- // src/infrastructure/services/workspace/workspace-path-security.ts
84713
- import { realpath as realpath2 } from "node:fs/promises";
84714
- import { basename, dirname as dirname8, isAbsolute, relative, resolve as resolve4, sep } from "node:path";
84715
- import { gunzipSync } from "node:zlib";
84716
- function validateRelativePathSegments(filePath) {
84717
- if (filePath.includes("\x00"))
84718
- return { ok: false, error: "Invalid file path" };
84719
- if (filePath.includes(".."))
84720
- return { ok: false, error: "Invalid file path" };
84721
- if (filePath.startsWith("/"))
84722
- return { ok: false, error: "Invalid file path" };
84723
- return { ok: true };
84724
- }
84725
- function isPathInsideRoot(workspaceRoot, targetPath) {
84726
- const rel = relative(workspaceRoot, targetPath);
84727
- if (rel === "")
84728
- return true;
84729
- if (rel.startsWith("..") || rel.includes(`..${sep}`))
84730
- return false;
84731
- if (isAbsolute(rel))
84732
- return false;
84733
- return true;
84734
- }
84735
- async function resolvePathWithinWorkspace(workingDir, filePath) {
84736
- const basic = validateRelativePathSegments(filePath);
84737
- if (!basic.ok)
84738
- return basic;
84739
- let workspaceRoot;
84740
- try {
84741
- workspaceRoot = await realpath2(resolve4(workingDir));
84742
- } catch {
84743
- return { ok: false, error: "Working directory not found" };
84744
- }
84745
- const candidate = resolve4(workspaceRoot, filePath);
84746
- if (!isPathInsideRoot(workspaceRoot, candidate)) {
84747
- return { ok: false, error: "Path escapes workspace" };
84748
- }
84749
- try {
84750
- const resolved = await realpath2(candidate);
84751
- if (!isPathInsideRoot(workspaceRoot, resolved)) {
84752
- return { ok: false, error: "Path escapes workspace" };
84753
- }
84754
- return { ok: true, absolutePath: resolved };
84755
- } catch (err) {
84756
- const code2 = err?.code;
84757
- if (code2 !== "ENOENT") {
84758
- return { ok: false, error: "Invalid file path" };
84759
- }
84760
- const parent = dirname8(candidate);
84761
- if (parent === workspaceRoot || isPathInsideRoot(workspaceRoot, parent)) {
84762
- try {
84763
- const parentReal = await realpath2(parent);
84764
- if (!isPathInsideRoot(workspaceRoot, parentReal)) {
84765
- return { ok: false, error: "Path escapes workspace" };
84766
- }
84767
- const resolved = resolve4(parentReal, basename(candidate));
84768
- if (!isPathInsideRoot(workspaceRoot, resolved)) {
84769
- return { ok: false, error: "Path escapes workspace" };
84770
- }
84771
- return { ok: true, absolutePath: resolved };
84772
- } catch {
84773
- return { ok: true, absolutePath: candidate };
84774
- }
84775
- }
84776
- return { ok: false, error: "Path escapes workspace" };
84777
- }
84778
- }
84779
- function gunzipBase64Payload(base64, maxBytes) {
84780
- let compressed;
84781
- try {
84782
- compressed = Buffer.from(base64, "base64");
84783
- } catch {
84784
- return { ok: false, errorMessage: "Missing file data" };
84785
- }
84786
- if (compressed.length > maxBytes * 10) {
84787
- return { ok: false, errorMessage: "File content too large" };
84788
- }
84789
- try {
84790
- const content = gunzipSync(compressed, { maxOutputLength: maxBytes });
84791
- if (content.length > maxBytes) {
84792
- return { ok: false, errorMessage: "File content too large" };
84793
- }
84794
- return { ok: true, content };
84795
- } catch {
84796
- return { ok: false, errorMessage: "File content too large" };
84797
- }
84798
- }
84799
- var init_workspace_path_security = () => {};
84800
-
84801
- // src/infrastructure/services/workspace/workspace-visibility-policy.ts
84802
- import { exec as exec2, spawn as spawn4 } from "node:child_process";
84803
- import { promisify as promisify2 } from "node:util";
84804
- function isAlwaysExcludedDirName(name) {
84805
- return ALWAYS_EXCLUDE_DIR_NAMES.has(name);
84806
- }
84807
- function isSecretPath(relativePath) {
84808
- const normalized = relativePath.replace(/\\/g, "/");
84809
- return SECRET_PATH_PATTERNS.some((pattern2) => pattern2.test(normalized));
84810
- }
84811
- function hasExcludedDirSegment(relativePath) {
84812
- const segments = relativePath.split("/");
84813
- return segments.some((segment) => isAlwaysExcludedDirName(segment));
84814
- }
84815
- function isPathVisible(relativePath) {
84816
- if (!relativePath)
84817
- return true;
84818
- return !isSecretPath(relativePath) && !hasExcludedDirSegment(relativePath);
84819
- }
84820
- function isPathContentReadable(relativePath) {
84821
- return isPathVisible(relativePath);
84822
- }
84823
- async function isGitRepo2(rootDir) {
84824
- try {
84825
- const { stdout } = await execAsync2("git rev-parse --is-inside-work-tree", {
84826
- cwd: rootDir,
84827
- env: { ...process.env, GIT_TERMINAL_PROMPT: "0", GIT_PAGER: "cat", NO_COLOR: "1" },
84828
- maxBuffer: 1024 * 1024
84829
- });
84830
- return stdout.trim() === "true";
84831
- } catch {
84832
- return false;
84833
- }
84834
- }
84835
- async function filterGitIgnored(rootDir, relativePaths) {
84836
- if (relativePaths.length === 0)
84837
- return new Set;
84838
- const inRepo = await isGitRepo2(rootDir);
84839
- if (!inRepo)
84840
- return new Set;
84841
- try {
84842
- const stdout = await new Promise((resolve5, reject) => {
84843
- const child = spawn4("git", ["check-ignore", "--stdin", "-z"], {
84844
- cwd: rootDir,
84845
- env: { ...process.env, GIT_TERMINAL_PROMPT: "0", GIT_PAGER: "cat", NO_COLOR: "1" }
84846
- });
84847
- let output = "";
84848
- child.stdout.on("data", (chunk2) => {
84849
- output += chunk2.toString();
84850
- });
84851
- child.on("error", reject);
84852
- child.on("close", () => resolve5(output));
84853
- child.stdin.write(relativePaths.join(`
84854
- `));
84855
- child.stdin.end();
84856
- });
84857
- const ignored = new Set;
84858
- if (!stdout)
84859
- return ignored;
84860
- for (const entry of stdout.split("\x00")) {
84861
- const trimmed = entry.trim();
84862
- if (trimmed)
84863
- ignored.add(trimmed);
84864
- }
84865
- return ignored;
84866
- } catch {
84867
- return new Set;
84868
- }
84869
- }
84870
- var execAsync2, ALWAYS_EXCLUDE_DIR_NAMES, SECRET_PATH_PATTERNS;
84871
- var init_workspace_visibility_policy = __esm(() => {
84872
- execAsync2 = promisify2(exec2);
84873
- ALWAYS_EXCLUDE_DIR_NAMES = new Set([
84874
- "node_modules",
84875
- ".git",
84876
- "dist",
84877
- "build",
84878
- ".next",
84879
- "coverage",
84880
- "__pycache__",
84881
- ".turbo",
84882
- ".cache",
84883
- ".tmp",
84884
- "tmp",
84885
- "_generated",
84886
- ".vercel"
84887
- ]);
84888
- SECRET_PATH_PATTERNS = [
84889
- /^\.env$/,
84890
- /^\.env\./,
84891
- /\.pem$/,
84892
- /\.key$/,
84893
- /id_rsa$/,
84894
- /credentials\.json$/,
84895
- /^secrets(\/|$)/,
84896
- /^\.aws(\/|$)/
84897
- ];
84898
- });
84899
-
84900
- // src/infrastructure/services/workspace/dir-listing-scanner.ts
84901
- import { promises as fsPromises } from "node:fs";
84902
- import path3 from "node:path";
84903
- async function listDirectory(rootDir, dirPath, options) {
84904
- const maxEntries = options?.maxEntries ?? DEFAULT_MAX_ENTRIES;
84905
- const scannedAt = Date.now();
84906
- const absDir = dirPath ? path3.join(rootDir, dirPath) : rootDir;
84907
- const resolvedRoot = path3.resolve(rootDir);
84908
- const resolvedDir = path3.resolve(absDir);
84909
- if (!isPathInsideRoot(resolvedRoot, resolvedDir)) {
84910
- return { dirPath, entries: [], scannedAt, truncated: false, totalCount: 0 };
84911
- }
84912
- let dirents;
84913
- try {
84914
- dirents = await fsPromises.readdir(absDir, { withFileTypes: true });
84915
- } catch {
84916
- return { dirPath, entries: [], scannedAt, truncated: false, totalCount: 0 };
84917
- }
84918
- const candidates = [];
84919
- for (const ent of dirents) {
84920
- if (isAlwaysExcludedDirName(ent.name))
84921
- continue;
84922
- const relativePath = dirPath ? `${dirPath}/${ent.name}` : ent.name;
84923
- if (!isPathVisible(relativePath))
84924
- continue;
84925
- if (ent.isDirectory()) {
84926
- candidates.push({ name: ent.name, path: relativePath, type: "directory" });
84927
- } else if (ent.isFile()) {
84928
- let size11;
84929
- try {
84930
- const st = await fsPromises.stat(path3.join(absDir, ent.name));
84931
- size11 = st.size;
84932
- } catch {}
84933
- candidates.push({ name: ent.name, path: relativePath, type: "file", size: size11 });
84934
- }
84935
- }
84936
- const ignored = await filterGitIgnored(rootDir, candidates.map((c) => c.path));
84937
- const visible = candidates.filter((c) => !ignored.has(c.path));
84938
- visible.sort((a, b) => {
84939
- if (a.type === "directory" && b.type === "file")
84940
- return -1;
84941
- if (a.type === "file" && b.type === "directory")
84942
- return 1;
84943
- return a.name.localeCompare(b.name, undefined, { sensitivity: "base" });
84944
- });
84945
- const totalCount = visible.length;
84946
- const truncated = totalCount > maxEntries;
84947
- const entries2 = visible.slice(0, maxEntries);
84948
- return { dirPath, entries: entries2, scannedAt, truncated, totalCount };
84949
- }
84950
- var DEFAULT_MAX_ENTRIES = 500;
84951
- var init_dir_listing_scanner = __esm(() => {
84952
- init_workspace_path_security();
84953
- init_workspace_visibility_policy();
84954
- });
84955
-
84956
- // src/infrastructure/services/workspace/dir-listing-sync.ts
84957
- import { gzipSync } from "node:zlib";
84958
- function listingCacheKey(workingDir, dirPath) {
84959
- return `${workingDir}\x00${dirPath}`;
84960
- }
84961
- async function scanDirListingForSync(workingDir, dirPath) {
84962
- const listing = await listDirectory(workingDir, dirPath);
84963
- const dataHash = computeDirListingContentHash(listing);
84964
- const cacheKey = listingCacheKey(workingDir, dirPath);
84965
- if (lastSyncedContentHash.get(cacheKey) === dataHash)
84966
- return null;
84967
- const json = JSON.stringify(listing);
84968
- return {
84969
- dirPath,
84970
- data: { compression: "gzip", content: gzipSync(Buffer.from(json)).toString("base64") },
84971
- dataHash,
84972
- scannedAt: listing.scannedAt,
84973
- truncated: listing.truncated,
84974
- totalCount: listing.totalCount
84975
- };
84976
- }
84977
- async function scanDirListingsWithConcurrency(workingDir, dirPaths) {
84978
- const items = [];
84979
- let index = 0;
84980
- async function worker() {
84981
- while (index < dirPaths.length) {
84982
- const currentIndex = index;
84983
- index += 1;
84984
- const dirPath = dirPaths[currentIndex];
84985
- if (dirPath === undefined)
84986
- continue;
84987
- const item = await scanDirListingForSync(workingDir, dirPath);
84988
- if (item)
84989
- items.push(item);
84990
- }
84991
- }
84992
- const workerCount = Math.min(SCAN_CONCURRENCY, dirPaths.length);
84993
- await Promise.all(Array.from({ length: workerCount }, () => worker()));
84994
- return items;
84995
- }
84996
- function markItemsSynced(workingDir, items) {
84997
- for (const item of items) {
84998
- lastSyncedContentHash.set(listingCacheKey(workingDir, item.dirPath), item.dataHash);
84999
- }
85000
- }
85001
- async function syncDirListingToBackend(session2, workingDir, dirPath) {
85002
- const item = await scanDirListingForSync(workingDir, dirPath);
85003
- if (!item)
85004
- return;
85005
- await session2.backend.mutation(api.workspaceFiles.syncDirListingV2, {
85006
- sessionId: session2.sessionId,
85007
- machineId: session2.machineId,
85008
- workingDir,
85009
- dirPath: item.dirPath,
85010
- data: item.data,
85011
- dataHash: item.dataHash,
85012
- scannedAt: item.scannedAt,
85013
- truncated: item.truncated,
85014
- totalCount: item.totalCount
85015
- });
85016
- markItemsSynced(workingDir, [item]);
85017
- }
85018
- async function syncDirListingsToBackend(session2, workingDir, dirPaths) {
85019
- const unique = [...new Set(dirPaths)];
85020
- if (unique.length === 0)
85021
- return;
85022
- if (unique.length === 1) {
85023
- const dirPath = unique[0];
85024
- if (dirPath !== undefined) {
85025
- await syncDirListingToBackend(session2, workingDir, dirPath);
85026
- }
85027
- return;
85028
- }
85029
- const items = await scanDirListingsWithConcurrency(workingDir, unique);
85030
- if (items.length === 0)
85031
- return;
85032
- for (let i2 = 0;i2 < items.length; i2 += MAX_BATCH_SIZE) {
85033
- const chunk2 = items.slice(i2, i2 + MAX_BATCH_SIZE);
85034
- await session2.backend.mutation(api.workspaceFiles.syncDirListingV2Batch, {
85035
- sessionId: session2.sessionId,
85036
- machineId: session2.machineId,
85037
- workingDir,
85038
- items: chunk2
85039
- });
85040
- markItemsSynced(workingDir, chunk2);
85041
- }
85042
- }
85043
- var MAX_BATCH_SIZE = 25, SCAN_CONCURRENCY = 4, lastSyncedContentHash;
85044
- var init_dir_listing_sync = __esm(() => {
85045
- init_dir_listing_content_hash();
85046
- init_dir_listing_scanner();
85047
- init_api3();
85048
- lastSyncedContentHash = new Map;
85049
- });
85050
-
85051
- // src/infrastructure/services/workspace/workspace-file-search.ts
85052
- import { promises as fsPromises2 } from "node:fs";
85053
- import path4 from "node:path";
85054
- async function searchWorkspaceFiles(rootDir, query, options) {
85055
- const maxResults = options?.maxResults ?? DEFAULT_MAX_RESULTS;
85056
- const scannedAt = Date.now();
85057
- const normalizedQuery = query.trim().toLowerCase();
85058
- const matches = [];
85059
- let visitedDirs = 0;
85060
- let truncated = false;
85061
- async function visitDir(relDir) {
85062
- if (visitedDirs >= MAX_VISIT_DIRS || matches.length >= maxResults) {
85063
- truncated = true;
85064
- return;
85065
- }
85066
- visitedDirs++;
85067
- const absDir = relDir ? path4.join(rootDir, relDir) : rootDir;
85068
- let dirents;
85069
- try {
85070
- dirents = await fsPromises2.readdir(absDir, { withFileTypes: true });
85071
- } catch {
85072
- return;
85073
- }
85074
- const fileCandidates = [];
85075
- const subdirs = [];
85076
- for (const ent of dirents) {
85077
- if (isAlwaysExcludedDirName(ent.name))
85078
- continue;
85079
- const relativePath = relDir ? `${relDir}/${ent.name}` : ent.name;
85080
- if (!isPathVisible(relativePath))
85081
- continue;
85082
- if (ent.isDirectory()) {
85083
- subdirs.push(relativePath);
85084
- } else if (ent.isFile()) {
85085
- fileCandidates.push(relativePath);
85086
- }
85087
- }
85088
- const ignored = await filterGitIgnored(rootDir, fileCandidates);
85089
- for (const filePath of fileCandidates) {
85090
- if (ignored.has(filePath))
85091
- continue;
85092
- const fileName = path4.basename(filePath).toLowerCase();
85093
- if (normalizedQuery === "" || fileName.includes(normalizedQuery)) {
85094
- matches.push({ path: filePath, type: "file" });
85095
- if (matches.length >= maxResults) {
85096
- truncated = true;
85097
- return;
85098
- }
85099
- }
85100
- }
85101
- for (const sub of subdirs) {
85102
- if (matches.length >= maxResults || visitedDirs >= MAX_VISIT_DIRS) {
85103
- truncated = true;
85104
- return;
85105
- }
85106
- await visitDir(sub);
85107
- }
85108
- }
85109
- await visitDir("");
85110
- return {
85111
- query,
85112
- entries: matches,
85113
- scannedAt,
85114
- truncated,
85115
- totalCount: matches.length
85116
- };
85117
- }
85118
- var DEFAULT_MAX_RESULTS = 300, MAX_VISIT_DIRS = 2000;
85119
- var init_workspace_file_search = __esm(() => {
85120
- init_workspace_visibility_policy();
85121
- });
85122
-
85123
- // src/commands/machine/daemon-start/dir-listing-subscription.ts
85124
- import { createHash as createHash3 } from "node:crypto";
85125
- import { gzipSync as gzipSync2 } from "node:zlib";
85126
- function logSubscriptionWarn(label, err) {
85127
- console.warn(`[${formatTimestamp()}] ⚠️ ${label}: ${getErrorMessage2(err)}`);
85128
- }
85129
- async function uploadDirListing(session2, workingDir, dirPath) {
85130
- await syncDirListingToBackend(session2, workingDir, dirPath);
85131
- await session2.backend.mutation(api.workspaceFiles.fulfillDirListingRequest, {
85132
- sessionId: session2.sessionId,
85133
- machineId: session2.machineId,
85134
- workingDir,
85135
- dirPath
85136
- });
85137
- }
85138
- async function uploadFileSearch(session2, workingDir, query) {
85139
- const result = await searchWorkspaceFiles(workingDir, query);
85140
- const json = JSON.stringify(result);
85141
- const dataHash = createHash3("md5").update(json).digest("hex");
85142
- const compressed = gzipSync2(Buffer.from(json)).toString("base64");
85143
- await session2.backend.mutation(api.workspaceFiles.syncFileSearchV2, {
85144
- sessionId: session2.sessionId,
85145
- machineId: session2.machineId,
85146
- workingDir,
85147
- query,
85148
- data: { compression: "gzip", content: compressed },
85149
- dataHash,
85150
- scannedAt: result.scannedAt,
85151
- truncated: result.truncated,
85152
- totalCount: result.totalCount
85153
- });
85154
- await session2.backend.mutation(api.workspaceFiles.fulfillFileSearchRequest, {
85155
- sessionId: session2.sessionId,
85156
- machineId: session2.machineId,
85157
- workingDir,
85158
- query
85159
- });
85160
- }
85161
- var fulfillDirListingRequestsEffect = (session2, requests) => exports_Effect.gen(function* () {
85162
- for (const request2 of requests) {
85163
- yield* exports_Effect.catchAll(exports_Effect.gen(function* () {
85164
- const start3 = Date.now();
85165
- yield* exports_Effect.tryPromise(() => uploadDirListing(session2, request2.workingDir, request2.dirPath));
85166
- console.log(`[${formatTimestamp()}] \uD83D\uDCC2 Dir listing fulfilled: ${request2.workingDir}/${request2.dirPath || "(root)"} (${Date.now() - start3}ms)`);
85167
- }), (err) => {
85168
- logSubscriptionWarn(`Dir listing failed for ${request2.workingDir}/${request2.dirPath}`, err);
85169
- return exports_Effect.void;
85170
- });
85171
- }
85172
- }), fulfillFileSearchRequestsEffect = (session2, requests) => exports_Effect.gen(function* () {
85173
- for (const request2 of requests) {
85174
- yield* exports_Effect.catchAll(exports_Effect.gen(function* () {
85175
- const start3 = Date.now();
85176
- yield* exports_Effect.tryPromise(() => uploadFileSearch(session2, request2.workingDir, request2.query));
85177
- console.log(`[${formatTimestamp()}] \uD83D\uDD0D File search fulfilled: ${request2.workingDir} query="${request2.query}" (${Date.now() - start3}ms)`);
85178
- }), (err) => {
85179
- logSubscriptionWarn(`File search failed for ${request2.workingDir}`, err);
85180
- return exports_Effect.void;
85181
- });
85182
- }
85183
- }), startDirListingSubscriptionEffect = (wsClient2) => exports_Effect.gen(function* () {
85184
- const session2 = yield* DaemonSessionService;
85185
- let processingDir = false;
85186
- let processingSearch = false;
85187
- const unsubDir = wsClient2.onUpdate(api.workspaceFiles.getPendingDirListingRequests, { sessionId: session2.sessionId, machineId: session2.machineId }, (requests) => {
85188
- if (!requests?.length || processingDir)
85189
- return;
85190
- processingDir = true;
85191
- exports_Effect.runPromise(fulfillDirListingRequestsEffect(session2, requests)).catch((err) => {
85192
- logSubscriptionWarn("Dir listing subscription processing failed", err);
85193
- }).finally(() => {
85194
- processingDir = false;
85195
- });
85196
- }, (err) => {
85197
- logSubscriptionWarn("Dir listing subscription error", err);
85198
- });
85199
- const unsubSearch = wsClient2.onUpdate(api.workspaceFiles.getPendingFileSearchRequests, { sessionId: session2.sessionId, machineId: session2.machineId }, (requests) => {
85200
- if (!requests?.length || processingSearch)
85201
- return;
85202
- processingSearch = true;
85203
- exports_Effect.runPromise(fulfillFileSearchRequestsEffect(session2, requests)).catch((err) => {
85204
- logSubscriptionWarn("File search subscription processing failed", err);
85205
- }).finally(() => {
85206
- processingSearch = false;
85207
- });
85208
- }, (err) => {
85209
- logSubscriptionWarn("File search subscription error", err);
85210
- });
85211
- console.log(`[${formatTimestamp()}] \uD83D\uDCC2 Dir listing subscription started (reactive)`);
85212
- return {
85213
- stop: () => {
85214
- unsubDir();
85215
- unsubSearch();
85216
- console.log(`[${formatTimestamp()}] \uD83D\uDCC2 Dir listing subscription stopped`);
85217
- }
85218
- };
85219
- });
85220
- var init_dir_listing_subscription = __esm(() => {
85221
- init_esm();
85222
- init_daemon_services();
85223
- init_api3();
85224
- init_dir_listing_sync();
85225
- init_workspace_file_search();
85226
- init_convex_error();
85227
- });
85228
-
85229
- // src/infrastructure/services/workspace/workspace-fs-watch-paths.ts
85230
- function parentDirPath(relativePath) {
85231
- const normalized = relativePath.replace(/\\/g, "/");
85232
- const idx = normalized.lastIndexOf("/");
85233
- return idx === -1 ? "" : normalized.slice(0, idx);
85234
- }
85235
- function shouldIgnoreWatchRelativePath(relativePath) {
85236
- const normalized = relativePath.replace(/\\/g, "/").replace(/\/+$/, "");
85237
- if (!normalized || normalized === ".")
85238
- return false;
85239
- return hasExcludedDirSegment(normalized);
85240
- }
85241
- function dirsToRefreshForEvent(relativePath, isDirectory = false) {
85242
- const normalized = relativePath.replace(/\\/g, "/").replace(/\/+$/, "");
85243
- if (!normalized || normalized === ".")
85244
- return [""];
85245
- const dirs = new Set;
85246
- dirs.add(parentDirPath(normalized));
85247
- if (isDirectory)
85248
- dirs.add(normalized);
85249
- return [...dirs];
85250
- }
85251
- function filterDirsByActiveSet(dirs, activeDirPaths) {
85252
- return dirs.filter((d) => activeDirPaths.has(d));
85253
- }
85254
- var init_workspace_fs_watch_paths = __esm(() => {
85255
- init_workspace_visibility_policy();
85256
- });
85257
-
85258
- // src/infrastructure/services/workspace/workspace-fs-watcher.ts
85259
- import { watch } from "node:fs";
85260
- import path5 from "node:path";
85261
- function isRecursiveWatchPlatform() {
85262
- return process.platform === "darwin" || process.platform === "win32";
85263
- }
85264
- function normalizeFilename(filename) {
85265
- if (filename == null)
85266
- return null;
85267
- const value = typeof filename === "string" ? filename : filename.toString();
85268
- if (!value || value === "." || value === "..")
85269
- return null;
85270
- return value.replace(/\\/g, "/");
85271
- }
85272
- function createWorkspaceFsWatcher(options) {
85273
- const absWorkingDir = path5.resolve(options.workingDir);
85274
- const debounceMs = options.debounceMs ?? DEFAULT_DEBOUNCE_MS;
85275
- let activeDirPaths = new Set(options.activeDirPaths);
85276
- let stopped = false;
85277
- let debounceTimer = null;
85278
- const pendingDirs = new Set;
85279
- let rootWatcher = null;
85280
- const dirWatchers = new Map;
85281
- const scheduleFlush = () => {
85282
- if (debounceTimer)
85283
- clearTimeout(debounceTimer);
85284
- debounceTimer = setTimeout(() => {
85285
- debounceTimer = null;
85286
- if (pendingDirs.size === 0)
85287
- return;
85288
- const dirs = [...pendingDirs];
85289
- pendingDirs.clear();
85290
- Promise.resolve(options.onRefreshDirs(dirs));
85291
- }, debounceMs);
85292
- debounceTimer.unref?.();
85293
- };
85294
- const enqueueDirs = (dirs) => {
85295
- for (const dir of dirs)
85296
- pendingDirs.add(dir);
85297
- scheduleFlush();
85298
- };
85299
- const handleRelativePath = (relativePath, isDirectory = false) => {
85300
- if (stopped)
85301
- return;
85302
- if (shouldIgnoreWatchRelativePath(relativePath))
85303
- return;
85304
- const toRefresh = filterDirsByActiveSet(dirsToRefreshForEvent(relativePath, isDirectory), activeDirPaths);
85305
- if (toRefresh.length > 0)
85306
- enqueueDirs(toRefresh);
85307
- };
85308
- const onWatchEvent = (watchedDirPath, filename) => {
85309
- const normalizedFilename = normalizeFilename(filename);
85310
- if (!normalizedFilename)
85311
- return;
85312
- let relativePath;
85313
- if (isRecursiveWatchPlatform()) {
85314
- relativePath = normalizedFilename;
85315
- } else if (watchedDirPath === "") {
85316
- relativePath = normalizedFilename;
85317
- } else {
85318
- relativePath = `${watchedDirPath}/${normalizedFilename}`;
85319
- }
85320
- const isDirectory = relativePath.endsWith("/");
85321
- handleRelativePath(relativePath.replace(/\/+$/, ""), isDirectory);
85322
- };
85323
- const closePerDirWatchers = () => {
85324
- for (const watcher of dirWatchers.values())
85325
- watcher.close();
85326
- dirWatchers.clear();
85327
- };
85328
- const startPerDirWatch = (dirPath) => {
85329
- if (dirPath === "" || dirWatchers.has(dirPath))
85330
- return;
85331
- const absDir = path5.join(absWorkingDir, dirPath);
85332
- const watcher = watch(absDir, (_eventType, filename) => {
85333
- onWatchEvent(dirPath, filename);
85334
- });
85335
- dirWatchers.set(dirPath, watcher);
85336
- };
85337
- const rewirePerDirWatches = () => {
85338
- const wanted = new Set;
85339
- for (const dirPath of activeDirPaths) {
85340
- if (dirPath !== "")
85341
- wanted.add(dirPath);
85342
- }
85343
- for (const [dirPath, watcher] of dirWatchers) {
85344
- if (!wanted.has(dirPath)) {
85345
- watcher.close();
85346
- dirWatchers.delete(dirPath);
85347
- }
85348
- }
85349
- for (const dirPath of wanted) {
85350
- if (!dirWatchers.has(dirPath))
85351
- startPerDirWatch(dirPath);
85352
- }
85353
- };
85354
- const startWatching = () => {
85355
- if (isRecursiveWatchPlatform()) {
85356
- rootWatcher = watch(absWorkingDir, { recursive: true }, (_eventType, filename) => {
85357
- onWatchEvent("", filename);
85358
- });
85359
- return;
85360
- }
85361
- rootWatcher = watch(absWorkingDir, (_eventType, filename) => {
85362
- onWatchEvent("", filename);
85363
- });
85364
- rewirePerDirWatches();
85365
- };
85366
- startWatching();
85367
- return {
85368
- updateActiveDirPaths: (paths) => {
85369
- activeDirPaths = new Set(paths);
85370
- if (!isRecursiveWatchPlatform() && !stopped) {
85371
- rewirePerDirWatches();
85372
- }
85373
- },
85374
- stop: () => {
85375
- stopped = true;
85376
- if (debounceTimer) {
85377
- clearTimeout(debounceTimer);
85378
- debounceTimer = null;
85379
- }
85380
- rootWatcher?.close();
85381
- rootWatcher = null;
85382
- closePerDirWatchers();
85383
- pendingDirs.clear();
85384
- }
85385
- };
85386
- }
85387
- var DEFAULT_DEBOUNCE_MS = 400;
85388
- var init_workspace_fs_watcher = __esm(() => {
85389
- init_workspace_fs_watch_paths();
85390
- });
85391
-
85392
- // src/commands/machine/daemon-start/dir-listing-watch-subscription.ts
85393
- var startDirListingWatchSubscriptionEffect = (wsClient2) => exports_Effect.gen(function* () {
85394
- const session2 = yield* DaemonSessionService;
85395
- const watchers = new Map;
85396
- const applyTargets = (targets) => {
85397
- const nextWorkingDirs = new Set(targets.map((t) => t.workingDir));
85398
- for (const [workingDir, handle] of watchers) {
85399
- if (!nextWorkingDirs.has(workingDir)) {
85400
- handle.stop();
85401
- watchers.delete(workingDir);
85402
- }
85403
- }
85404
- for (const target of targets) {
85405
- const activeSet = new Set(target.activeDirPaths);
85406
- const existing = watchers.get(target.workingDir);
85407
- if (existing) {
85408
- existing.updateActiveDirPaths(activeSet);
85409
- continue;
85410
- }
85411
- const handle = createWorkspaceFsWatcher({
85412
- workingDir: target.workingDir,
85413
- activeDirPaths: activeSet,
85414
- onRefreshDirs: async (dirPaths) => {
85415
- try {
85416
- await syncDirListingsToBackend(session2, target.workingDir, dirPaths);
85417
- } catch (err) {
85418
- console.warn(`[${formatTimestamp()}] ⚠️ FS watch sync failed for ${target.workingDir}: ${getErrorMessage2(err)}`);
85419
- }
85420
- }
85421
- });
85422
- watchers.set(target.workingDir, handle);
85423
- }
85424
- };
85425
- let stopped = false;
85426
- const unsub = wsClient2.onUpdate(api.workspaceFiles.listDirListingWatchTargets, { sessionId: session2.sessionId, machineId: session2.machineId }, (targets) => {
85427
- if (stopped)
85428
- return;
85429
- applyTargets(targets ?? []);
85430
- }, (err) => {
85431
- console.warn(`[${formatTimestamp()}] ⚠️ Dir listing watch subscription error: ${getErrorMessage2(err)}`);
85432
- });
85433
- console.log(`[${formatTimestamp()}] \uD83D\uDC41️ Dir listing FS watch subscription started`);
85434
- return {
85435
- stop: () => {
85436
- stopped = true;
85437
- unsub();
85438
- for (const handle of watchers.values())
85439
- handle.stop();
85440
- watchers.clear();
85441
- console.log(`[${formatTimestamp()}] \uD83D\uDC41️ Dir listing FS watch subscription stopped`);
85442
- }
85443
- };
85444
- });
85445
- var init_dir_listing_watch_subscription = __esm(() => {
85446
- init_esm();
85447
- init_daemon_services();
85448
- init_api3();
85449
- init_dir_listing_sync();
85450
- init_workspace_fs_watcher();
85451
- init_convex_error();
85452
- });
85453
-
85454
84707
  // src/events/daemon/agent/on-request-start-agent.ts
85455
84708
  function notifyAgentStartFailed(backend2, opts) {
85456
84709
  backend2.mutation(api.machines.emitAgentStartFailed, opts).catch((err) => {
@@ -85550,8 +84803,13 @@ var init_on_request_stop_agent = __esm(() => {
85550
84803
  init_stop_agent();
85551
84804
  });
85552
84805
 
84806
+ // src/commands/machine/daemon-start/utils.ts
84807
+ function formatTimestamp() {
84808
+ return new Date().toISOString().replace("T", " ").substring(0, 19);
84809
+ }
84810
+
85553
84811
  // src/commands/machine/daemon-start/handlers/orphan-tracker.ts
85554
- import { createHash as createHash4 } from "node:crypto";
84812
+ import { createHash as createHash2 } from "node:crypto";
85555
84813
  import {
85556
84814
  appendFileSync,
85557
84815
  existsSync as existsSync5,
@@ -85565,7 +84823,7 @@ import { homedir as homedir5 } from "node:os";
85565
84823
  import { join as join15 } from "node:path";
85566
84824
  function getUrlHash() {
85567
84825
  const url2 = getConvexUrl();
85568
- return createHash4("sha256").update(url2).digest("hex").substring(0, 8);
84826
+ return createHash2("sha256").update(url2).digest("hex").substring(0, 8);
85569
84827
  }
85570
84828
  function getChildPidsFilePath() {
85571
84829
  const dir = join15(homedir5(), ".chatroom");
@@ -85759,19 +85017,19 @@ class ProcessManager {
85759
85017
  this.pendingStops.clear();
85760
85018
  }
85761
85019
  waitForExit(runId, ms) {
85762
- return new Promise((resolve5) => {
85020
+ return new Promise((resolve4) => {
85763
85021
  const interval = 100;
85764
85022
  let elapsed3 = 0;
85765
85023
  const timer = setInterval(() => {
85766
85024
  if (!this.runningProcesses.has(runId)) {
85767
85025
  clearInterval(timer);
85768
- resolve5(true);
85026
+ resolve4(true);
85769
85027
  return;
85770
85028
  }
85771
85029
  elapsed3 += interval;
85772
85030
  if (elapsed3 >= ms) {
85773
85031
  clearInterval(timer);
85774
- resolve5(false);
85032
+ resolve4(false);
85775
85033
  }
85776
85034
  }, interval);
85777
85035
  });
@@ -85806,9 +85064,9 @@ var init_killer = __esm(() => {
85806
85064
  });
85807
85065
 
85808
85066
  // ../../services/backend/src/output-encoding.ts
85809
- import { gunzipSync as gunzipSync2, gzipSync as gzipSync3 } from "node:zlib";
85067
+ import { gunzipSync, gzipSync } from "node:zlib";
85810
85068
  function encodeOutput(plain) {
85811
- const compressed = gzipSync3(Buffer.from(plain, "utf-8"));
85069
+ const compressed = gzipSync(Buffer.from(plain, "utf-8"));
85812
85070
  return {
85813
85071
  compression: "gzip",
85814
85072
  content: compressed.toString("base64")
@@ -85986,7 +85244,7 @@ var init_output_store = __esm(() => {
85986
85244
  });
85987
85245
 
85988
85246
  // src/commands/machine/daemon-start/handlers/process/spawner.ts
85989
- import { spawn as spawn5 } from "node:child_process";
85247
+ import { spawn as spawn4 } from "node:child_process";
85990
85248
  async function flushTailV2(deps, tracked, force = false) {
85991
85249
  if (!force && !isRunLogObserved(tracked.runId))
85992
85250
  return;
@@ -86069,7 +85327,7 @@ async function spawnCommandProcess(deps, event, commandKey) {
86069
85327
  tempDirReady = true;
86070
85328
  }
86071
85329
  const store = createOutputStore(runIdStr);
86072
- const child = spawn5("sh", ["-c", script], {
85330
+ const child = spawn4("sh", ["-c", script], {
86073
85331
  cwd: workingDir,
86074
85332
  env: buildChatroomSpawnEnv(deps.convexUrl),
86075
85333
  stdio: ["ignore", "pipe", "pipe"],
@@ -86331,8 +85589,8 @@ var init_command_runner = __esm(() => {
86331
85589
  }).catch((err) => {
86332
85590
  console.warn(`[${formatTimestamp()}] ⚠️ Failed to mark run as killed on shutdown: ${getErrorMessage2(err)}`);
86333
85591
  })));
86334
- yield* exports_Effect.promise(() => new Promise((resolve5) => {
86335
- const t = setTimeout(resolve5, 3000);
85592
+ yield* exports_Effect.promise(() => new Promise((resolve4) => {
85593
+ const t = setTimeout(resolve4, 3000);
86336
85594
  t.unref?.();
86337
85595
  }));
86338
85596
  for (const [, tracked] of trackedEntries) {
@@ -86344,8 +85602,8 @@ var init_command_runner = __esm(() => {
86344
85602
  clearTrackedPids();
86345
85603
  yield* exports_Effect.promise(() => Promise.race([
86346
85604
  statusUpdates,
86347
- new Promise((resolve5) => {
86348
- const t = setTimeout(resolve5, 2000);
85605
+ new Promise((resolve4) => {
85606
+ const t = setTimeout(resolve4, 2000);
86349
85607
  t.unref?.();
86350
85608
  })
86351
85609
  ]));
@@ -86473,7 +85731,7 @@ var init_git = __esm(() => {
86473
85731
  });
86474
85732
 
86475
85733
  // src/infrastructure/local-actions/execute-local-action.ts
86476
- import { exec as exec3 } from "node:child_process";
85734
+ import { exec as exec2 } from "node:child_process";
86477
85735
  import { access as access3 } from "node:fs/promises";
86478
85736
  function escapeShellArg(arg) {
86479
85737
  return `"${arg.replace(/"/g, "\\\"")}"`;
@@ -86482,14 +85740,14 @@ function resolveWhichCommand(name) {
86482
85740
  return process.platform === "win32" ? `where ${name}` : `which ${name}`;
86483
85741
  }
86484
85742
  function isCliAvailable(cliName) {
86485
- return new Promise((resolve5) => {
86486
- exec3(resolveWhichCommand(cliName), (err) => {
86487
- resolve5(!err);
85743
+ return new Promise((resolve4) => {
85744
+ exec2(resolveWhichCommand(cliName), (err) => {
85745
+ resolve4(!err);
86488
85746
  });
86489
85747
  });
86490
85748
  }
86491
85749
  function execFireAndForget(command, logTag) {
86492
- exec3(command, (err) => {
85750
+ exec2(command, (err) => {
86493
85751
  if (err) {
86494
85752
  console.warn(`[${logTag}] exec failed: ${err.message}`);
86495
85753
  }
@@ -86608,10 +85866,10 @@ var init_local_actions = __esm(() => {
86608
85866
  import { execFileSync } from "node:child_process";
86609
85867
  function runPicker(command, args2) {
86610
85868
  try {
86611
- const path6 = execFileSync(command, args2, { encoding: "utf8", timeout: 300000 }).trim();
86612
- if (!path6)
85869
+ const path3 = execFileSync(command, args2, { encoding: "utf8", timeout: 300000 }).trim();
85870
+ if (!path3)
86613
85871
  return { success: false, error: "No folder selected" };
86614
- return { success: true, path: path6 };
85872
+ return { success: true, path: path3 };
86615
85873
  } catch (error) {
86616
85874
  const exitCode = typeof error === "object" && error !== null && "status" in error ? error.status : null;
86617
85875
  if (exitCode === 1)
@@ -86653,13 +85911,13 @@ function pickFolderDialog() {
86653
85911
  var init_pick_folder = () => {};
86654
85912
 
86655
85913
  // src/commands/machine/pid.ts
86656
- import { createHash as createHash5 } from "node:crypto";
85914
+ import { createHash as createHash3 } from "node:crypto";
86657
85915
  import { existsSync as existsSync6, readFileSync as readFileSync8, writeFileSync as writeFileSync4, unlinkSync as unlinkSync2, mkdirSync as mkdirSync5 } from "node:fs";
86658
85916
  import { homedir as homedir6 } from "node:os";
86659
85917
  import { join as join17 } from "node:path";
86660
85918
  function getUrlHash2() {
86661
85919
  const url2 = getConvexUrl();
86662
- return createHash5("sha256").update(url2).digest("hex").substring(0, 8);
85920
+ return createHash3("sha256").update(url2).digest("hex").substring(0, 8);
86663
85921
  }
86664
85922
  function getPidFileName() {
86665
85923
  return `daemon-${getUrlHash2()}.pid`;
@@ -86752,7 +86010,7 @@ async function waitForLockOrTimeout(deadline, intervalMs, sleep5) {
86752
86010
  async function acquireLockWithRetry(options) {
86753
86011
  const intervalMs = options?.intervalMs ?? LOCK_RETRY_INTERVAL_MS;
86754
86012
  const maxWaitMs = options?.maxWaitMs ?? LOCK_RETRY_MAX_WAIT_MS;
86755
- const sleep5 = options?.sleep ?? ((ms) => new Promise((resolve5) => setTimeout(resolve5, ms)));
86013
+ const sleep5 = options?.sleep ?? ((ms) => new Promise((resolve4) => setTimeout(resolve4, ms)));
86756
86014
  const deadline = Date.now() + maxWaitMs;
86757
86015
  if (await waitForLockOrTimeout(deadline, intervalMs, sleep5)) {
86758
86016
  return true;
@@ -87118,14 +86376,14 @@ var init_sse_event_buffer = __esm(() => {
87118
86376
  }
87119
86377
  _wake() {
87120
86378
  if (this._waiter) {
87121
- const resolve5 = this._waiter;
86379
+ const resolve4 = this._waiter;
87122
86380
  this._waiter = null;
87123
- resolve5();
86381
+ resolve4();
87124
86382
  }
87125
86383
  }
87126
86384
  _waitForData() {
87127
- return new Promise((resolve5) => {
87128
- this._waiter = resolve5;
86385
+ return new Promise((resolve4) => {
86386
+ this._waiter = resolve4;
87129
86387
  });
87130
86388
  }
87131
86389
  [Symbol.asyncIterator]() {
@@ -87180,8 +86438,8 @@ class OpencodeSdkSession {
87180
86438
  async prompt(input) {
87181
86439
  if (this.closed)
87182
86440
  throw new Error("Session is closed");
87183
- const idlePromise = new Promise((resolve5) => {
87184
- this._idleResolve = resolve5;
86441
+ const idlePromise = new Promise((resolve4) => {
86442
+ this._idleResolve = resolve4;
87185
86443
  });
87186
86444
  const IDLE_TIMEOUT_MS = 300000;
87187
86445
  const timeoutPromise = new Promise((_, reject) => {
@@ -87265,7 +86523,7 @@ var init_opencode_session = __esm(() => {
87265
86523
  });
87266
86524
 
87267
86525
  // src/infrastructure/harnesses/opencode-sdk/opencode-harness.ts
87268
- import { spawn as spawn6 } from "node:child_process";
86526
+ import { spawn as spawn5 } from "node:child_process";
87269
86527
  function harnessEventSessionId(event) {
87270
86528
  const p = event.properties;
87271
86529
  if (!p)
@@ -87512,14 +86770,14 @@ class OpencodeSdkHarness {
87512
86770
  }
87513
86771
  this.sessionListeners.clear();
87514
86772
  this.childProcess.kill("SIGTERM");
87515
- await new Promise((resolve5) => {
86773
+ await new Promise((resolve4) => {
87516
86774
  const timeout3 = setTimeout(() => {
87517
86775
  this.childProcess.kill("SIGKILL");
87518
- resolve5();
86776
+ resolve4();
87519
86777
  }, 5000);
87520
86778
  this.childProcess.once("exit", () => {
87521
86779
  clearTimeout(timeout3);
87522
- resolve5();
86780
+ resolve4();
87523
86781
  });
87524
86782
  });
87525
86783
  }
@@ -87539,7 +86797,7 @@ class OpencodeSdkHarness {
87539
86797
  }
87540
86798
  }
87541
86799
  var OPENCODE_COMMAND3 = "opencode", SERVE_STARTUP_TIMEOUT_MS2 = 1e4, startOpencodeSdkHarness = async (config3) => {
87542
- const childProcess = spawn6(OPENCODE_COMMAND3, ["serve", "--print-logs"], {
86800
+ const childProcess = spawn5(OPENCODE_COMMAND3, ["serve", "--print-logs"], {
87543
86801
  cwd: config3.workingDir,
87544
86802
  stdio: ["pipe", "pipe", "pipe"],
87545
86803
  shell: false,
@@ -88901,10 +88159,10 @@ class BufferedJournalFactory {
88901
88159
  const waitForInProgress = () => {
88902
88160
  if (!flushInProgress)
88903
88161
  return Promise.resolve();
88904
- return new Promise((resolve5) => {
88162
+ return new Promise((resolve4) => {
88905
88163
  const check3 = () => {
88906
88164
  if (!flushInProgress)
88907
- resolve5();
88165
+ resolve4();
88908
88166
  else
88909
88167
  setTimeout(check3, 10);
88910
88168
  };
@@ -89072,9 +88330,549 @@ var init_assert_registered_working_dir = __esm(() => {
89072
88330
  init_workspace_cache();
89073
88331
  });
89074
88332
 
89075
- // src/commands/machine/daemon-start/file-content-fulfillment.ts
88333
+ // src/infrastructure/services/workspace/workspace-path-security.ts
88334
+ import { realpath as realpath2 } from "node:fs/promises";
88335
+ import { basename, dirname as dirname8, isAbsolute, relative, resolve as resolve4, sep } from "node:path";
88336
+ import { gunzipSync as gunzipSync2 } from "node:zlib";
88337
+ function validateRelativePathSegments(filePath) {
88338
+ if (filePath.includes("\x00"))
88339
+ return { ok: false, error: "Invalid file path" };
88340
+ if (filePath.includes(".."))
88341
+ return { ok: false, error: "Invalid file path" };
88342
+ if (filePath.startsWith("/"))
88343
+ return { ok: false, error: "Invalid file path" };
88344
+ return { ok: true };
88345
+ }
88346
+ function isPathInsideRoot(workspaceRoot, targetPath) {
88347
+ const rel = relative(workspaceRoot, targetPath);
88348
+ if (rel === "")
88349
+ return true;
88350
+ if (rel.startsWith("..") || rel.includes(`..${sep}`))
88351
+ return false;
88352
+ if (isAbsolute(rel))
88353
+ return false;
88354
+ return true;
88355
+ }
88356
+ async function resolvePathWithinWorkspace(workingDir, filePath) {
88357
+ const basic = validateRelativePathSegments(filePath);
88358
+ if (!basic.ok)
88359
+ return basic;
88360
+ let workspaceRoot;
88361
+ try {
88362
+ workspaceRoot = await realpath2(resolve4(workingDir));
88363
+ } catch {
88364
+ return { ok: false, error: "Working directory not found" };
88365
+ }
88366
+ const candidate = resolve4(workspaceRoot, filePath);
88367
+ if (!isPathInsideRoot(workspaceRoot, candidate)) {
88368
+ return { ok: false, error: "Path escapes workspace" };
88369
+ }
88370
+ try {
88371
+ const resolved = await realpath2(candidate);
88372
+ if (!isPathInsideRoot(workspaceRoot, resolved)) {
88373
+ return { ok: false, error: "Path escapes workspace" };
88374
+ }
88375
+ return { ok: true, absolutePath: resolved };
88376
+ } catch (err) {
88377
+ const code2 = err?.code;
88378
+ if (code2 !== "ENOENT") {
88379
+ return { ok: false, error: "Invalid file path" };
88380
+ }
88381
+ const parent = dirname8(candidate);
88382
+ if (parent === workspaceRoot || isPathInsideRoot(workspaceRoot, parent)) {
88383
+ try {
88384
+ const parentReal = await realpath2(parent);
88385
+ if (!isPathInsideRoot(workspaceRoot, parentReal)) {
88386
+ return { ok: false, error: "Path escapes workspace" };
88387
+ }
88388
+ const resolved = resolve4(parentReal, basename(candidate));
88389
+ if (!isPathInsideRoot(workspaceRoot, resolved)) {
88390
+ return { ok: false, error: "Path escapes workspace" };
88391
+ }
88392
+ return { ok: true, absolutePath: resolved };
88393
+ } catch {
88394
+ return { ok: true, absolutePath: candidate };
88395
+ }
88396
+ }
88397
+ return { ok: false, error: "Path escapes workspace" };
88398
+ }
88399
+ }
88400
+ function gunzipBase64Payload(base64, maxBytes) {
88401
+ let compressed;
88402
+ try {
88403
+ compressed = Buffer.from(base64, "base64");
88404
+ } catch {
88405
+ return { ok: false, errorMessage: "Missing file data" };
88406
+ }
88407
+ if (compressed.length > maxBytes * 10) {
88408
+ return { ok: false, errorMessage: "File content too large" };
88409
+ }
88410
+ try {
88411
+ const content = gunzipSync2(compressed, { maxOutputLength: maxBytes });
88412
+ if (content.length > maxBytes) {
88413
+ return { ok: false, errorMessage: "File content too large" };
88414
+ }
88415
+ return { ok: true, content };
88416
+ } catch {
88417
+ return { ok: false, errorMessage: "File content too large" };
88418
+ }
88419
+ }
88420
+ var init_workspace_path_security = () => {};
88421
+
88422
+ // ../../node_modules/.pnpm/ignore@7.0.5/node_modules/ignore/index.js
88423
+ var require_ignore = __commonJS((exports, module) => {
88424
+ function makeArray(subject) {
88425
+ return Array.isArray(subject) ? subject : [subject];
88426
+ }
88427
+ var UNDEFINED = undefined;
88428
+ var EMPTY = "";
88429
+ var SPACE = " ";
88430
+ var ESCAPE = "\\";
88431
+ var REGEX_TEST_BLANK_LINE = /^\s+$/;
88432
+ var REGEX_INVALID_TRAILING_BACKSLASH = /(?:[^\\]|^)\\$/;
88433
+ var REGEX_REPLACE_LEADING_EXCAPED_EXCLAMATION = /^\\!/;
88434
+ var REGEX_REPLACE_LEADING_EXCAPED_HASH = /^\\#/;
88435
+ var REGEX_SPLITALL_CRLF = /\r?\n/g;
88436
+ var REGEX_TEST_INVALID_PATH = /^\.{0,2}\/|^\.{1,2}$/;
88437
+ var REGEX_TEST_TRAILING_SLASH = /\/$/;
88438
+ var SLASH = "/";
88439
+ var TMP_KEY_IGNORE = "node-ignore";
88440
+ if (typeof Symbol !== "undefined") {
88441
+ TMP_KEY_IGNORE = Symbol.for("node-ignore");
88442
+ }
88443
+ var KEY_IGNORE = TMP_KEY_IGNORE;
88444
+ var define = (object, key, value) => {
88445
+ Object.defineProperty(object, key, { value });
88446
+ return value;
88447
+ };
88448
+ var REGEX_REGEXP_RANGE = /([0-z])-([0-z])/g;
88449
+ var RETURN_FALSE = () => false;
88450
+ var sanitizeRange = (range) => range.replace(REGEX_REGEXP_RANGE, (match17, from, to) => from.charCodeAt(0) <= to.charCodeAt(0) ? match17 : EMPTY);
88451
+ var cleanRangeBackSlash = (slashes) => {
88452
+ const { length: length2 } = slashes;
88453
+ return slashes.slice(0, length2 - length2 % 2);
88454
+ };
88455
+ var REPLACERS = [
88456
+ [
88457
+ /^\uFEFF/,
88458
+ () => EMPTY
88459
+ ],
88460
+ [
88461
+ /((?:\\\\)*?)(\\?\s+)$/,
88462
+ (_, m1, m2) => m1 + (m2.indexOf("\\") === 0 ? SPACE : EMPTY)
88463
+ ],
88464
+ [
88465
+ /(\\+?)\s/g,
88466
+ (_, m1) => {
88467
+ const { length: length2 } = m1;
88468
+ return m1.slice(0, length2 - length2 % 2) + SPACE;
88469
+ }
88470
+ ],
88471
+ [
88472
+ /[\\$.|*+(){^]/g,
88473
+ (match17) => `\\${match17}`
88474
+ ],
88475
+ [
88476
+ /(?!\\)\?/g,
88477
+ () => "[^/]"
88478
+ ],
88479
+ [
88480
+ /^\//,
88481
+ () => "^"
88482
+ ],
88483
+ [
88484
+ /\//g,
88485
+ () => "\\/"
88486
+ ],
88487
+ [
88488
+ /^\^*\\\*\\\*\\\//,
88489
+ () => "^(?:.*\\/)?"
88490
+ ],
88491
+ [
88492
+ /^(?=[^^])/,
88493
+ function startingReplacer() {
88494
+ return !/\/(?!$)/.test(this) ? "(?:^|\\/)" : "^";
88495
+ }
88496
+ ],
88497
+ [
88498
+ /\\\/\\\*\\\*(?=\\\/|$)/g,
88499
+ (_, index, str) => index + 6 < str.length ? "(?:\\/[^\\/]+)*" : "\\/.+"
88500
+ ],
88501
+ [
88502
+ /(^|[^\\]+)(\\\*)+(?=.+)/g,
88503
+ (_, p1, p2) => {
88504
+ const unescaped = p2.replace(/\\\*/g, "[^\\/]*");
88505
+ return p1 + unescaped;
88506
+ }
88507
+ ],
88508
+ [
88509
+ /\\\\\\(?=[$.|*+(){^])/g,
88510
+ () => ESCAPE
88511
+ ],
88512
+ [
88513
+ /\\\\/g,
88514
+ () => ESCAPE
88515
+ ],
88516
+ [
88517
+ /(\\)?\[([^\]/]*?)(\\*)($|\])/g,
88518
+ (match17, leadEscape, range, endEscape, close2) => leadEscape === ESCAPE ? `\\[${range}${cleanRangeBackSlash(endEscape)}${close2}` : close2 === "]" ? endEscape.length % 2 === 0 ? `[${sanitizeRange(range)}${endEscape}]` : "[]" : "[]"
88519
+ ],
88520
+ [
88521
+ /(?:[^*])$/,
88522
+ (match17) => /\/$/.test(match17) ? `${match17}$` : `${match17}(?=$|\\/$)`
88523
+ ]
88524
+ ];
88525
+ var REGEX_REPLACE_TRAILING_WILDCARD = /(^|\\\/)?\\\*$/;
88526
+ var MODE_IGNORE = "regex";
88527
+ var MODE_CHECK_IGNORE = "checkRegex";
88528
+ var UNDERSCORE = "_";
88529
+ var TRAILING_WILD_CARD_REPLACERS = {
88530
+ [MODE_IGNORE](_, p1) {
88531
+ const prefix = p1 ? `${p1}[^/]+` : "[^/]*";
88532
+ return `${prefix}(?=$|\\/$)`;
88533
+ },
88534
+ [MODE_CHECK_IGNORE](_, p1) {
88535
+ const prefix = p1 ? `${p1}[^/]*` : "[^/]*";
88536
+ return `${prefix}(?=$|\\/$)`;
88537
+ }
88538
+ };
88539
+ var makeRegexPrefix = (pattern2) => REPLACERS.reduce((prev, [matcher, replacer]) => prev.replace(matcher, replacer.bind(pattern2)), pattern2);
88540
+ var isString3 = (subject) => typeof subject === "string";
88541
+ var checkPattern = (pattern2) => pattern2 && isString3(pattern2) && !REGEX_TEST_BLANK_LINE.test(pattern2) && !REGEX_INVALID_TRAILING_BACKSLASH.test(pattern2) && pattern2.indexOf("#") !== 0;
88542
+ var splitPattern = (pattern2) => pattern2.split(REGEX_SPLITALL_CRLF).filter(Boolean);
88543
+
88544
+ class IgnoreRule {
88545
+ constructor(pattern2, mark2, body, ignoreCase, negative, prefix) {
88546
+ this.pattern = pattern2;
88547
+ this.mark = mark2;
88548
+ this.negative = negative;
88549
+ define(this, "body", body);
88550
+ define(this, "ignoreCase", ignoreCase);
88551
+ define(this, "regexPrefix", prefix);
88552
+ }
88553
+ get regex() {
88554
+ const key = UNDERSCORE + MODE_IGNORE;
88555
+ if (this[key]) {
88556
+ return this[key];
88557
+ }
88558
+ return this._make(MODE_IGNORE, key);
88559
+ }
88560
+ get checkRegex() {
88561
+ const key = UNDERSCORE + MODE_CHECK_IGNORE;
88562
+ if (this[key]) {
88563
+ return this[key];
88564
+ }
88565
+ return this._make(MODE_CHECK_IGNORE, key);
88566
+ }
88567
+ _make(mode, key) {
88568
+ const str = this.regexPrefix.replace(REGEX_REPLACE_TRAILING_WILDCARD, TRAILING_WILD_CARD_REPLACERS[mode]);
88569
+ const regex = this.ignoreCase ? new RegExp(str, "i") : new RegExp(str);
88570
+ return define(this, key, regex);
88571
+ }
88572
+ }
88573
+ var createRule = ({
88574
+ pattern: pattern2,
88575
+ mark: mark2
88576
+ }, ignoreCase) => {
88577
+ let negative = false;
88578
+ let body = pattern2;
88579
+ if (body.indexOf("!") === 0) {
88580
+ negative = true;
88581
+ body = body.substr(1);
88582
+ }
88583
+ body = body.replace(REGEX_REPLACE_LEADING_EXCAPED_EXCLAMATION, "!").replace(REGEX_REPLACE_LEADING_EXCAPED_HASH, "#");
88584
+ const regexPrefix = makeRegexPrefix(body);
88585
+ return new IgnoreRule(pattern2, mark2, body, ignoreCase, negative, regexPrefix);
88586
+ };
88587
+
88588
+ class RuleManager {
88589
+ constructor(ignoreCase) {
88590
+ this._ignoreCase = ignoreCase;
88591
+ this._rules = [];
88592
+ }
88593
+ _add(pattern2) {
88594
+ if (pattern2 && pattern2[KEY_IGNORE]) {
88595
+ this._rules = this._rules.concat(pattern2._rules._rules);
88596
+ this._added = true;
88597
+ return;
88598
+ }
88599
+ if (isString3(pattern2)) {
88600
+ pattern2 = {
88601
+ pattern: pattern2
88602
+ };
88603
+ }
88604
+ if (checkPattern(pattern2.pattern)) {
88605
+ const rule = createRule(pattern2, this._ignoreCase);
88606
+ this._added = true;
88607
+ this._rules.push(rule);
88608
+ }
88609
+ }
88610
+ add(pattern2) {
88611
+ this._added = false;
88612
+ makeArray(isString3(pattern2) ? splitPattern(pattern2) : pattern2).forEach(this._add, this);
88613
+ return this._added;
88614
+ }
88615
+ test(path3, checkUnignored, mode) {
88616
+ let ignored = false;
88617
+ let unignored = false;
88618
+ let matchedRule;
88619
+ this._rules.forEach((rule) => {
88620
+ const { negative } = rule;
88621
+ if (unignored === negative && ignored !== unignored || negative && !ignored && !unignored && !checkUnignored) {
88622
+ return;
88623
+ }
88624
+ const matched = rule[mode].test(path3);
88625
+ if (!matched) {
88626
+ return;
88627
+ }
88628
+ ignored = !negative;
88629
+ unignored = negative;
88630
+ matchedRule = negative ? UNDEFINED : rule;
88631
+ });
88632
+ const ret = {
88633
+ ignored,
88634
+ unignored
88635
+ };
88636
+ if (matchedRule) {
88637
+ ret.rule = matchedRule;
88638
+ }
88639
+ return ret;
88640
+ }
88641
+ }
88642
+ var throwError = (message, Ctor) => {
88643
+ throw new Ctor(message);
88644
+ };
88645
+ var checkPath = (path3, originalPath, doThrow) => {
88646
+ if (!isString3(path3)) {
88647
+ return doThrow(`path must be a string, but got \`${originalPath}\``, TypeError);
88648
+ }
88649
+ if (!path3) {
88650
+ return doThrow(`path must not be empty`, TypeError);
88651
+ }
88652
+ if (checkPath.isNotRelative(path3)) {
88653
+ const r = "`path.relative()`d";
88654
+ return doThrow(`path should be a ${r} string, but got "${originalPath}"`, RangeError);
88655
+ }
88656
+ return true;
88657
+ };
88658
+ var isNotRelative = (path3) => REGEX_TEST_INVALID_PATH.test(path3);
88659
+ checkPath.isNotRelative = isNotRelative;
88660
+ checkPath.convert = (p) => p;
88661
+
88662
+ class Ignore {
88663
+ constructor({
88664
+ ignorecase = true,
88665
+ ignoreCase = ignorecase,
88666
+ allowRelativePaths = false
88667
+ } = {}) {
88668
+ define(this, KEY_IGNORE, true);
88669
+ this._rules = new RuleManager(ignoreCase);
88670
+ this._strictPathCheck = !allowRelativePaths;
88671
+ this._initCache();
88672
+ }
88673
+ _initCache() {
88674
+ this._ignoreCache = Object.create(null);
88675
+ this._testCache = Object.create(null);
88676
+ }
88677
+ add(pattern2) {
88678
+ if (this._rules.add(pattern2)) {
88679
+ this._initCache();
88680
+ }
88681
+ return this;
88682
+ }
88683
+ addPattern(pattern2) {
88684
+ return this.add(pattern2);
88685
+ }
88686
+ _test(originalPath, cache, checkUnignored, slices) {
88687
+ const path3 = originalPath && checkPath.convert(originalPath);
88688
+ checkPath(path3, originalPath, this._strictPathCheck ? throwError : RETURN_FALSE);
88689
+ return this._t(path3, cache, checkUnignored, slices);
88690
+ }
88691
+ checkIgnore(path3) {
88692
+ if (!REGEX_TEST_TRAILING_SLASH.test(path3)) {
88693
+ return this.test(path3);
88694
+ }
88695
+ const slices = path3.split(SLASH).filter(Boolean);
88696
+ slices.pop();
88697
+ if (slices.length) {
88698
+ const parent = this._t(slices.join(SLASH) + SLASH, this._testCache, true, slices);
88699
+ if (parent.ignored) {
88700
+ return parent;
88701
+ }
88702
+ }
88703
+ return this._rules.test(path3, false, MODE_CHECK_IGNORE);
88704
+ }
88705
+ _t(path3, cache, checkUnignored, slices) {
88706
+ if (path3 in cache) {
88707
+ return cache[path3];
88708
+ }
88709
+ if (!slices) {
88710
+ slices = path3.split(SLASH).filter(Boolean);
88711
+ }
88712
+ slices.pop();
88713
+ if (!slices.length) {
88714
+ return cache[path3] = this._rules.test(path3, checkUnignored, MODE_IGNORE);
88715
+ }
88716
+ const parent = this._t(slices.join(SLASH) + SLASH, cache, checkUnignored, slices);
88717
+ return cache[path3] = parent.ignored ? parent : this._rules.test(path3, checkUnignored, MODE_IGNORE);
88718
+ }
88719
+ ignores(path3) {
88720
+ return this._test(path3, this._ignoreCache, false).ignored;
88721
+ }
88722
+ createFilter() {
88723
+ return (path3) => !this.ignores(path3);
88724
+ }
88725
+ filter(paths) {
88726
+ return makeArray(paths).filter(this.createFilter());
88727
+ }
88728
+ test(path3) {
88729
+ return this._test(path3, this._testCache, true);
88730
+ }
88731
+ }
88732
+ var factory2 = (options) => new Ignore(options);
88733
+ var isPathValid = (path3) => checkPath(path3 && checkPath.convert(path3), path3, RETURN_FALSE);
88734
+ var setupWindows = () => {
88735
+ const makePosix = (str) => /^\\\\\?\\/.test(str) || /["<>|\u0000-\u001F]+/u.test(str) ? str : str.replace(/\\/g, "/");
88736
+ checkPath.convert = makePosix;
88737
+ const REGEX_TEST_WINDOWS_PATH_ABSOLUTE = /^[a-z]:\//i;
88738
+ checkPath.isNotRelative = (path3) => REGEX_TEST_WINDOWS_PATH_ABSOLUTE.test(path3) || isNotRelative(path3);
88739
+ };
88740
+ if (typeof process !== "undefined" && process.platform === "win32") {
88741
+ setupWindows();
88742
+ }
88743
+ module.exports = factory2;
88744
+ factory2.default = factory2;
88745
+ module.exports.isPathValid = isPathValid;
88746
+ define(module.exports, Symbol.for("setupWindows"), setupWindows);
88747
+ });
88748
+
88749
+ // src/infrastructure/services/workspace/workspace-ignore.ts
89076
88750
  import { readFile as readFile7 } from "node:fs/promises";
89077
- import { gzipSync as gzipSync4 } from "node:zlib";
88751
+ import path3 from "node:path";
88752
+ async function loadWorkspaceIgnore(rootDir) {
88753
+ const ig = import_ignore.default();
88754
+ for (const name of IGNORE_FILES) {
88755
+ try {
88756
+ const content = await readFile7(path3.join(rootDir, name), "utf-8");
88757
+ ig.add(content);
88758
+ } catch {}
88759
+ }
88760
+ return ig;
88761
+ }
88762
+ function isPathIgnoredByRules(ig, relativePath) {
88763
+ const normalized = relativePath.replace(/\\/g, "/");
88764
+ return ig.ignores(normalized);
88765
+ }
88766
+ var import_ignore, IGNORE_FILES;
88767
+ var init_workspace_ignore = __esm(() => {
88768
+ import_ignore = __toESM(require_ignore(), 1);
88769
+ IGNORE_FILES = [".gitignore", ".cursorignore"];
88770
+ });
88771
+
88772
+ // src/infrastructure/services/workspace/workspace-visibility-policy.ts
88773
+ import { spawn as spawn6 } from "node:child_process";
88774
+ function isAlwaysExcludedDirName(name) {
88775
+ return ALWAYS_EXCLUDE_DIR_NAMES.has(name);
88776
+ }
88777
+ function isSecretPath(relativePath) {
88778
+ const normalized = relativePath.replace(/\\/g, "/");
88779
+ return SECRET_PATH_PATTERNS.some((pattern2) => pattern2.test(normalized));
88780
+ }
88781
+ function hasExcludedDirSegment(relativePath) {
88782
+ const segments = relativePath.split("/");
88783
+ return segments.some((segment) => isAlwaysExcludedDirName(segment));
88784
+ }
88785
+ function isPathVisible(relativePath) {
88786
+ if (!relativePath)
88787
+ return true;
88788
+ return !isSecretPath(relativePath) && !hasExcludedDirSegment(relativePath);
88789
+ }
88790
+ function isPathContentReadable(relativePath) {
88791
+ return isPathVisible(relativePath);
88792
+ }
88793
+ async function filterIgnoredPaths(rootDir, relativePaths) {
88794
+ if (relativePaths.length === 0)
88795
+ return new Set;
88796
+ const inRepo = await isGitRepo(rootDir);
88797
+ if (inRepo)
88798
+ return filterGitIgnored(rootDir, relativePaths);
88799
+ const ig = await loadWorkspaceIgnore(rootDir);
88800
+ const ignored = new Set;
88801
+ for (const p of relativePaths) {
88802
+ if (isPathIgnoredByRules(ig, p))
88803
+ ignored.add(p);
88804
+ }
88805
+ return ignored;
88806
+ }
88807
+ async function filterGitIgnored(rootDir, relativePaths) {
88808
+ if (relativePaths.length === 0)
88809
+ return new Set;
88810
+ const inRepo = await isGitRepo(rootDir);
88811
+ if (!inRepo)
88812
+ return new Set;
88813
+ try {
88814
+ const stdout = await new Promise((resolve5, reject) => {
88815
+ const child = spawn6("git", ["check-ignore", "--stdin", "-z"], {
88816
+ cwd: rootDir,
88817
+ env: { ...process.env, GIT_TERMINAL_PROMPT: "0", GIT_PAGER: "cat", NO_COLOR: "1" }
88818
+ });
88819
+ let output = "";
88820
+ child.stdout.on("data", (chunk2) => {
88821
+ output += chunk2.toString();
88822
+ });
88823
+ child.on("error", reject);
88824
+ child.on("close", () => resolve5(output));
88825
+ child.stdin.write(relativePaths.join(`
88826
+ `));
88827
+ child.stdin.end();
88828
+ });
88829
+ const ignored = new Set;
88830
+ if (!stdout)
88831
+ return ignored;
88832
+ for (const entry of stdout.split("\x00")) {
88833
+ const trimmed = entry.trim();
88834
+ if (trimmed)
88835
+ ignored.add(trimmed);
88836
+ }
88837
+ return ignored;
88838
+ } catch {
88839
+ return new Set;
88840
+ }
88841
+ }
88842
+ var ALWAYS_EXCLUDE_DIR_NAMES, SECRET_PATH_PATTERNS;
88843
+ var init_workspace_visibility_policy = __esm(() => {
88844
+ init_workspace_ignore();
88845
+ init_git_reader();
88846
+ ALWAYS_EXCLUDE_DIR_NAMES = new Set([
88847
+ "node_modules",
88848
+ ".git",
88849
+ "dist",
88850
+ "build",
88851
+ ".next",
88852
+ "coverage",
88853
+ "__pycache__",
88854
+ ".turbo",
88855
+ ".cache",
88856
+ ".tmp",
88857
+ "tmp",
88858
+ "_generated",
88859
+ ".vercel"
88860
+ ]);
88861
+ SECRET_PATH_PATTERNS = [
88862
+ /^\.env$/,
88863
+ /^\.env\./,
88864
+ /\.pem$/,
88865
+ /\.key$/,
88866
+ /id_rsa$/,
88867
+ /credentials\.json$/,
88868
+ /^secrets(\/|$)/,
88869
+ /^\.aws(\/|$)/
88870
+ ];
88871
+ });
88872
+
88873
+ // src/commands/machine/daemon-start/file-content-fulfillment.ts
88874
+ import { readFile as readFile8 } from "node:fs/promises";
88875
+ import { gzipSync as gzipSync2 } from "node:zlib";
89078
88876
  function getErrorCause(error) {
89079
88877
  if (typeof error === "object" && error !== null && "cause" in error && error.cause !== undefined) {
89080
88878
  return error.cause;
@@ -89085,14 +88883,14 @@ function isENOENT(error) {
89085
88883
  const cause3 = getErrorCause(error);
89086
88884
  return typeof cause3 === "object" && cause3 !== null && "code" in cause3 && cause3.code === "ENOENT";
89087
88885
  }
89088
- function isBinaryFile(path6) {
89089
- const lastDot = path6.lastIndexOf(".");
88886
+ function isBinaryFile(path4) {
88887
+ const lastDot = path4.lastIndexOf(".");
89090
88888
  if (lastDot === -1)
89091
88889
  return false;
89092
- return BINARY_EXTENSIONS.has(path6.slice(lastDot).toLowerCase());
88890
+ return BINARY_EXTENSIONS.has(path4.slice(lastDot).toLowerCase());
89093
88891
  }
89094
88892
  function gzipPlainText(text) {
89095
- return gzipSync4(Buffer.from(text)).toString("base64");
88893
+ return gzipSync2(Buffer.from(text)).toString("base64");
89096
88894
  }
89097
88895
  function fulfillGzippedContentEffect(session2, workingDir, filePath, plainText, truncated) {
89098
88896
  return exports_Effect.catchAll(exports_Effect.tryPromise(() => session2.backend.mutation(api.workspaceFiles.fulfillFileContentV2, {
@@ -89191,7 +88989,7 @@ var init_file_content_fulfillment = __esm(() => {
89191
88989
  console.log(`[${formatTimestamp()}] \uD83D\uDCC4 File content blocked: ${filePath} [secret] (${elapsed4}ms)`);
89192
88990
  continue;
89193
88991
  }
89194
- const readOutcome = yield* exports_Effect.catchAll(exports_Effect.tryPromise(() => readFile7(absolutePath)).pipe(exports_Effect.map((buffer) => {
88992
+ const readOutcome = yield* exports_Effect.catchAll(exports_Effect.tryPromise(() => readFile8(absolutePath)).pipe(exports_Effect.map((buffer) => {
89195
88993
  if (buffer.length > MAX_CONTENT_BYTES) {
89196
88994
  return {
89197
88995
  kind: "ok",
@@ -89214,7 +89012,7 @@ var init_file_content_fulfillment = __esm(() => {
89214
89012
  continue;
89215
89013
  }
89216
89014
  const { content, truncated } = readOutcome.kind === "ok" ? readOutcome : { content: readOutcome.content, truncated: readOutcome.truncated };
89217
- const compressed = gzipSync4(Buffer.from(content));
89015
+ const compressed = gzipSync2(Buffer.from(content));
89218
89016
  const contentCompressed = compressed.toString("base64");
89219
89017
  yield* exports_Effect.catchAll(exports_Effect.tryPromise(() => session2.backend.mutation(api.workspaceFiles.fulfillFileContentV2, {
89220
89018
  sessionId: session2.sessionId,
@@ -89268,15 +89066,476 @@ var init_file_content_subscription = __esm(() => {
89268
89066
  init_convex_error();
89269
89067
  });
89270
89068
 
89069
+ // src/infrastructure/services/workspace/file-tree-data-hash.ts
89070
+ import { createHash as createHash4 } from "node:crypto";
89071
+ function computeFileTreeDataHash(tree) {
89072
+ return createHash4("md5").update(JSON.stringify(tree)).digest("hex");
89073
+ }
89074
+ var init_file_tree_data_hash = () => {};
89075
+
89076
+ // src/infrastructure/services/workspace/file-tree-partition.ts
89077
+ import { createHash as createHash5 } from "node:crypto";
89078
+ import { gzipSync as gzipSync3 } from "node:zlib";
89079
+ function computeShardDataHash(payload) {
89080
+ return createHash5("md5").update(JSON.stringify(payload)).digest("hex");
89081
+ }
89082
+ function shardIdForPath(path4) {
89083
+ const slash = path4.indexOf("/");
89084
+ return slash === -1 ? "__root__" : path4.slice(0, slash);
89085
+ }
89086
+ function shouldUseV3Upload(tree) {
89087
+ return Buffer.byteLength(JSON.stringify(tree), "utf8") > MAX_TREE_JSON_BYTES;
89088
+ }
89089
+ function childShardId(path4, parentShardId) {
89090
+ if (parentShardId === "__root__") {
89091
+ return shardIdForPath(path4);
89092
+ }
89093
+ if (path4 === parentShardId) {
89094
+ return parentShardId;
89095
+ }
89096
+ const prefix = `${parentShardId}/`;
89097
+ if (!path4.startsWith(prefix)) {
89098
+ return parentShardId;
89099
+ }
89100
+ const remainder = path4.slice(prefix.length);
89101
+ const slash = remainder.indexOf("/");
89102
+ return slash === -1 ? parentShardId : `${parentShardId}/${remainder.slice(0, slash)}`;
89103
+ }
89104
+ function groupEntriesByShardId(entries2, parentShardId) {
89105
+ const groups = new Map;
89106
+ for (const entry of entries2) {
89107
+ const shardId = parentShardId === "__root__" ? shardIdForPath(entry.path) : childShardId(entry.path, parentShardId);
89108
+ const group = groups.get(shardId) ?? [];
89109
+ group.push(entry);
89110
+ groups.set(shardId, group);
89111
+ }
89112
+ return groups;
89113
+ }
89114
+ function buildPreparedShard(shardId, payload) {
89115
+ const compressed = gzipSync3(Buffer.from(JSON.stringify(payload))).toString("base64");
89116
+ return {
89117
+ shardId,
89118
+ payload,
89119
+ dataHash: computeShardDataHash(payload),
89120
+ entryCount: payload.entries.length,
89121
+ data: { compression: "gzip", content: compressed }
89122
+ };
89123
+ }
89124
+ function prepareShardGroup(entries2, shardId, tree) {
89125
+ const payload = {
89126
+ entries: entries2,
89127
+ scannedAt: tree.scannedAt,
89128
+ rootDir: tree.rootDir
89129
+ };
89130
+ const compressed = gzipSync3(Buffer.from(JSON.stringify(payload))).toString("base64");
89131
+ if (Buffer.byteLength(compressed, "utf8") <= MAX_SHARD_JSON_BYTES) {
89132
+ return [buildPreparedShard(shardId, payload)];
89133
+ }
89134
+ const subgroups = groupEntriesByShardId(entries2, shardId);
89135
+ if (subgroups.size <= 1) {
89136
+ return [buildPreparedShard(shardId, payload)];
89137
+ }
89138
+ const shards = [];
89139
+ for (const [subId, subEntries] of subgroups) {
89140
+ shards.push(...prepareShardGroup(subEntries, subId, tree));
89141
+ }
89142
+ return shards;
89143
+ }
89144
+ function partitionFileTree(tree) {
89145
+ const topGroups = groupEntriesByShardId(tree.entries, "__root__");
89146
+ const shards = [];
89147
+ for (const [shardId, entries2] of topGroups) {
89148
+ shards.push(...prepareShardGroup(entries2, shardId, tree));
89149
+ }
89150
+ return shards;
89151
+ }
89152
+ var MAX_TREE_JSON_BYTES, MAX_SHARD_JSON_BYTES, MAX_SHARD_BATCH_SIZE = 8;
89153
+ var init_file_tree_partition = __esm(() => {
89154
+ MAX_TREE_JSON_BYTES = 900 * 1024;
89155
+ MAX_SHARD_JSON_BYTES = 800 * 1024;
89156
+ });
89157
+
89158
+ // src/infrastructure/services/workspace/workspace-file-walk.ts
89159
+ import { promises as fsPromises } from "node:fs";
89160
+ import path4 from "node:path";
89161
+ async function walkWorkspaceFiles(rootDir, options) {
89162
+ const maxFilePaths = options?.maxFilePaths ?? 1e4;
89163
+ const filePaths = [];
89164
+ let truncated = false;
89165
+ const inRepo = await isGitRepo(rootDir);
89166
+ const parsedIgnore = inRepo ? null : await loadWorkspaceIgnore(rootDir);
89167
+ async function isIgnored(relativePath) {
89168
+ if (inRepo) {
89169
+ const ignored = await filterIgnoredPaths(rootDir, [relativePath]);
89170
+ return ignored.has(relativePath);
89171
+ }
89172
+ return parsedIgnore !== null && isPathIgnoredByRules(parsedIgnore, relativePath);
89173
+ }
89174
+ async function visitDir(relDir) {
89175
+ if (truncated || filePaths.length >= maxFilePaths) {
89176
+ truncated = true;
89177
+ return;
89178
+ }
89179
+ const absDir = relDir ? path4.join(rootDir, relDir) : rootDir;
89180
+ let dirents;
89181
+ try {
89182
+ dirents = await fsPromises.readdir(absDir, { withFileTypes: true });
89183
+ } catch {
89184
+ return;
89185
+ }
89186
+ for (const ent of dirents) {
89187
+ if (truncated || filePaths.length >= maxFilePaths) {
89188
+ truncated = true;
89189
+ return;
89190
+ }
89191
+ if (isAlwaysExcludedDirName(ent.name))
89192
+ continue;
89193
+ const relativePath = relDir ? `${relDir}/${ent.name}` : ent.name;
89194
+ if (!isPathVisible(relativePath))
89195
+ continue;
89196
+ if (ent.isDirectory()) {
89197
+ if (await isIgnored(relativePath))
89198
+ continue;
89199
+ await visitDir(relativePath);
89200
+ } else if (ent.isFile()) {
89201
+ if (await isIgnored(relativePath))
89202
+ continue;
89203
+ filePaths.push(relativePath);
89204
+ if (filePaths.length >= maxFilePaths)
89205
+ truncated = true;
89206
+ }
89207
+ }
89208
+ }
89209
+ await visitDir("");
89210
+ return { filePaths, truncated };
89211
+ }
89212
+ var init_workspace_file_walk = __esm(() => {
89213
+ init_workspace_ignore();
89214
+ init_workspace_visibility_policy();
89215
+ init_git_reader();
89216
+ });
89217
+
89218
+ // src/infrastructure/services/workspace/file-tree-scanner.ts
89219
+ async function scanFileTree(rootDir, options) {
89220
+ const maxEntries = options?.maxEntries ?? DEFAULT_MAX_ENTRIES;
89221
+ const scannedAt = Date.now();
89222
+ const walk = await walkWorkspaceFiles(rootDir, { maxFilePaths: maxEntries });
89223
+ const filteredPaths = walk.filePaths.filter((p) => !isExcluded(p));
89224
+ const entries2 = buildEntries(filteredPaths, maxEntries);
89225
+ return {
89226
+ entries: entries2,
89227
+ scannedAt,
89228
+ rootDir
89229
+ };
89230
+ }
89231
+ function isExcluded(filePath) {
89232
+ return hasExcludedDirSegment(filePath);
89233
+ }
89234
+ function buildEntries(filePaths, maxEntries) {
89235
+ const directories = new Set;
89236
+ for (const filePath of filePaths) {
89237
+ const parts2 = filePath.split("/");
89238
+ for (let i2 = 1;i2 < parts2.length; i2++) {
89239
+ directories.add(parts2.slice(0, i2).join("/"));
89240
+ }
89241
+ }
89242
+ const entries2 = [];
89243
+ const sortedDirs = Array.from(directories).sort();
89244
+ for (const dir of sortedDirs) {
89245
+ if (entries2.length >= maxEntries)
89246
+ break;
89247
+ entries2.push({ path: dir, type: "directory" });
89248
+ }
89249
+ const sortedFiles = filePaths.slice().sort();
89250
+ for (const file of sortedFiles) {
89251
+ if (entries2.length >= maxEntries)
89252
+ break;
89253
+ entries2.push({ path: file, type: "file" });
89254
+ }
89255
+ return entries2;
89256
+ }
89257
+ var DEFAULT_MAX_ENTRIES = 1e4;
89258
+ var init_file_tree_scanner = __esm(() => {
89259
+ init_workspace_file_walk();
89260
+ init_workspace_visibility_policy();
89261
+ });
89262
+
89263
+ // src/infrastructure/services/workspace/file-tree-v3-upload.ts
89264
+ async function uploadFileTreeV3(session2, workingDir, tree, syncGeneration) {
89265
+ const shards = partitionFileTree(tree);
89266
+ const shardIds = [];
89267
+ for (let i2 = 0;i2 < shards.length; i2 += MAX_SHARD_BATCH_SIZE) {
89268
+ const batch = shards.slice(i2, i2 + MAX_SHARD_BATCH_SIZE);
89269
+ await session2.backend.mutation(api.workspaceFiles.syncFileTreeShardV3Batch, {
89270
+ sessionId: session2.sessionId,
89271
+ machineId: session2.machineId,
89272
+ workingDir,
89273
+ syncGeneration,
89274
+ items: batch.map((s) => ({
89275
+ shardId: s.shardId,
89276
+ data: s.data,
89277
+ dataHash: s.dataHash,
89278
+ scannedAt: tree.scannedAt,
89279
+ entryCount: s.entryCount
89280
+ }))
89281
+ });
89282
+ for (const s of batch)
89283
+ shardIds.push(s.shardId);
89284
+ }
89285
+ await session2.backend.mutation(api.workspaceFiles.syncFileTreeManifestV3, {
89286
+ sessionId: session2.sessionId,
89287
+ machineId: session2.machineId,
89288
+ workingDir,
89289
+ syncGeneration,
89290
+ shardIds,
89291
+ totalEntryCount: tree.entries.length,
89292
+ complete: true,
89293
+ scannedAt: tree.scannedAt
89294
+ });
89295
+ return { shardIds, totalEntryCount: tree.entries.length };
89296
+ }
89297
+ var init_file_tree_v3_upload = __esm(() => {
89298
+ init_file_tree_partition();
89299
+ init_api3();
89300
+ });
89301
+
89302
+ // src/infrastructure/services/workspace/workspace-sync-diff.ts
89303
+ function diffPathIndexes(previous, next4) {
89304
+ const added = [];
89305
+ const removed = [];
89306
+ const typeChanged = [];
89307
+ const prev = previous ?? {};
89308
+ for (const [path5, type] of Object.entries(next4)) {
89309
+ if (!(path5 in prev)) {
89310
+ added.push(path5);
89311
+ } else if (prev[path5] !== type) {
89312
+ typeChanged.push(path5);
89313
+ }
89314
+ }
89315
+ for (const path5 of Object.keys(prev)) {
89316
+ if (!(path5 in next4)) {
89317
+ removed.push(path5);
89318
+ }
89319
+ }
89320
+ added.sort();
89321
+ removed.sort();
89322
+ typeChanged.sort();
89323
+ return { added, removed, typeChanged };
89324
+ }
89325
+ function formatPathDiffSummary(diff8) {
89326
+ return `+${diff8.added.length} added, -${diff8.removed.length} removed${diff8.typeChanged.length > 0 ? `, ~${diff8.typeChanged.length} type-changed` : ""}`;
89327
+ }
89328
+
89329
+ // src/infrastructure/services/workspace/workspace-sync-queue.ts
89330
+ function queueKey(machineId, workingDir) {
89331
+ return `${machineId}\x00${workingDir}`;
89332
+ }
89333
+ function getOrCreateState(key) {
89334
+ let state = queues.get(key);
89335
+ if (!state) {
89336
+ state = { running: false, trailing: false, drainPromise: null };
89337
+ queues.set(key, state);
89338
+ }
89339
+ return state;
89340
+ }
89341
+ async function enqueueFileTreeSync(machineId, workingDir, task) {
89342
+ const key = queueKey(machineId, workingDir);
89343
+ const state = getOrCreateState(key);
89344
+ if (state.running) {
89345
+ state.trailing = true;
89346
+ return state.drainPromise ?? Promise.resolve();
89347
+ }
89348
+ const run3 = async () => {
89349
+ state.running = true;
89350
+ try {
89351
+ do {
89352
+ state.trailing = false;
89353
+ await task();
89354
+ } while (state.trailing);
89355
+ } finally {
89356
+ state.running = false;
89357
+ state.trailing = false;
89358
+ if (!state.trailing) {
89359
+ queues.delete(key);
89360
+ }
89361
+ }
89362
+ };
89363
+ state.drainPromise = run3();
89364
+ return state.drainPromise;
89365
+ }
89366
+ var queues;
89367
+ var init_workspace_sync_queue = __esm(() => {
89368
+ queues = new Map;
89369
+ });
89370
+
89371
+ // src/infrastructure/services/workspace/workspace-sync-state.ts
89372
+ import { createHash as createHash6, randomUUID as randomUUID6 } from "node:crypto";
89373
+ import * as fs11 from "node:fs/promises";
89374
+ import { homedir as homedir7 } from "node:os";
89375
+ import { join as join18 } from "node:path";
89376
+ function workspaceKeyFor(workingDir) {
89377
+ const normalized = normalizeWorkingDirForLookup(workingDir);
89378
+ return createHash6("sha256").update(normalized).digest("hex").slice(0, 16);
89379
+ }
89380
+ function buildPathIndex(entries2) {
89381
+ const paths = {};
89382
+ for (const entry of entries2) {
89383
+ paths[entry.path] = entry.type;
89384
+ }
89385
+ return paths;
89386
+ }
89387
+ function manifestPath(machineId, workingDir) {
89388
+ const key = workspaceKeyFor(workingDir);
89389
+ return join18(SYNC_STATE_DIR, machineId, key, "manifest.json");
89390
+ }
89391
+ async function ensureDir(filePath) {
89392
+ await fs11.mkdir(join18(filePath, ".."), { recursive: true, mode: 448 });
89393
+ }
89394
+ async function loadWorkspaceSyncManifest(machineId, workingDir) {
89395
+ try {
89396
+ const content = await fs11.readFile(manifestPath(machineId, workingDir), "utf-8");
89397
+ return JSON.parse(content);
89398
+ } catch (error) {
89399
+ if (error.code === "ENOENT")
89400
+ return null;
89401
+ return null;
89402
+ }
89403
+ }
89404
+ async function saveWorkspaceSyncManifest(manifest) {
89405
+ const filePath = manifestPath(manifest.machineId, manifest.workingDir);
89406
+ const tempPath = `${filePath}.tmp`;
89407
+ await ensureDir(filePath);
89408
+ const content = JSON.stringify(manifest, null, 2);
89409
+ await fs11.writeFile(tempPath, content, { mode: 384 });
89410
+ await fs11.rename(tempPath, filePath);
89411
+ }
89412
+ function createManifestFromTree(args2) {
89413
+ return {
89414
+ version: SYNC_STATE_VERSION,
89415
+ machineId: args2.machineId,
89416
+ workingDir: normalizeWorkingDirForLookup(args2.workingDir),
89417
+ syncGeneration: randomUUID6(),
89418
+ completedAt: Date.now(),
89419
+ scanner: args2.scanner,
89420
+ dataHash: args2.dataHash,
89421
+ totalEntryCount: args2.tree.entries.length,
89422
+ paths: buildPathIndex(args2.tree.entries)
89423
+ };
89424
+ }
89425
+ var SYNC_STATE_VERSION = "1", SYNC_STATE_DIR;
89426
+ var init_workspace_sync_state = __esm(() => {
89427
+ SYNC_STATE_DIR = join18(homedir7(), ".chatroom", "sync-state");
89428
+ });
89429
+
89430
+ // src/commands/machine/daemon-start/file-tree-subscription.ts
89431
+ import { gzipSync as gzipSync4 } from "node:zlib";
89432
+ function logSubscriptionWarn(label, err) {
89433
+ console.warn(`[${formatTimestamp()}] ⚠️ ${label}: ${getErrorMessage2(err)}`);
89434
+ }
89435
+ async function syncScannedFileTree(session2, normalizedWorkingDir, tree, dataHash, syncGeneration) {
89436
+ if (shouldUseV3Upload(tree)) {
89437
+ await uploadFileTreeV3(session2, normalizedWorkingDir, tree, syncGeneration);
89438
+ return;
89439
+ }
89440
+ const treeJson = JSON.stringify(tree);
89441
+ const compressed = gzipSync4(Buffer.from(treeJson)).toString("base64");
89442
+ await session2.backend.mutation(api.workspaceFiles.syncFileTreeV2, {
89443
+ sessionId: session2.sessionId,
89444
+ machineId: session2.machineId,
89445
+ workingDir: normalizedWorkingDir,
89446
+ data: { compression: "gzip", content: compressed },
89447
+ dataHash,
89448
+ scannedAt: tree.scannedAt
89449
+ });
89450
+ }
89451
+ async function uploadFileTree(session2, workingDir) {
89452
+ const normalizedWorkingDir = normalizeWorkingDirForLookup(workingDir);
89453
+ const previousManifest = await loadWorkspaceSyncManifest(session2.machineId, normalizedWorkingDir);
89454
+ const tree = await scanFileTree(normalizedWorkingDir);
89455
+ const dataHash = computeFileTreeDataHash(tree);
89456
+ if (previousManifest?.dataHash === dataHash) {
89457
+ await session2.backend.mutation(api.workspaceFiles.fulfillFileTreeRequest, {
89458
+ sessionId: session2.sessionId,
89459
+ machineId: session2.machineId,
89460
+ workingDir: normalizedWorkingDir
89461
+ });
89462
+ console.log(`[${formatTimestamp()}] \uD83C\uDF33 File tree unchanged, skipped upload: ${normalizedWorkingDir}`);
89463
+ return;
89464
+ }
89465
+ const pathDiff = diffPathIndexes(previousManifest?.paths, buildPathIndex(tree.entries));
89466
+ if (previousManifest) {
89467
+ console.log(`[${formatTimestamp()}] \uD83C\uDF33 File tree diff: ${formatPathDiffSummary(pathDiff)} (${normalizedWorkingDir})`);
89468
+ }
89469
+ const scanner = await isGitRepo(normalizedWorkingDir) ? "git" : "filesystem";
89470
+ const manifest = createManifestFromTree({
89471
+ machineId: session2.machineId,
89472
+ workingDir: normalizedWorkingDir,
89473
+ scanner,
89474
+ dataHash,
89475
+ tree
89476
+ });
89477
+ await syncScannedFileTree(session2, normalizedWorkingDir, tree, dataHash, manifest.syncGeneration);
89478
+ await session2.backend.mutation(api.workspaceFiles.fulfillFileTreeRequest, {
89479
+ sessionId: session2.sessionId,
89480
+ machineId: session2.machineId,
89481
+ workingDir: normalizedWorkingDir
89482
+ });
89483
+ await saveWorkspaceSyncManifest(manifest);
89484
+ }
89485
+ var startFileTreeSubscriptionEffect = (wsClient2) => exports_Effect.gen(function* () {
89486
+ const session2 = yield* DaemonSessionService;
89487
+ const unsubscribe = wsClient2.onUpdate(api.workspaceFiles.getPendingFileTreeRequests, { sessionId: session2.sessionId, machineId: session2.machineId }, (requests) => {
89488
+ if (!requests?.length)
89489
+ return;
89490
+ const uniqueDirs = [
89491
+ ...new Set(requests.map((r) => normalizeWorkingDirForLookup(r.workingDir)))
89492
+ ];
89493
+ for (const workingDir of uniqueDirs) {
89494
+ const normalized = normalizeWorkingDirForLookup(workingDir);
89495
+ enqueueFileTreeSync(session2.machineId, normalized, () => {
89496
+ const start3 = Date.now();
89497
+ return uploadFileTree(session2, normalized).then(() => {
89498
+ console.log(`[${formatTimestamp()}] \uD83C\uDF33 File tree fulfilled: ${normalized} (${Date.now() - start3}ms)`);
89499
+ }).catch((err) => {
89500
+ logSubscriptionWarn(`File tree failed for ${normalized}`, err);
89501
+ });
89502
+ }).catch((err) => {
89503
+ logSubscriptionWarn("File tree queue drain failed", err);
89504
+ });
89505
+ }
89506
+ }, (err) => {
89507
+ logSubscriptionWarn("File tree subscription error", err);
89508
+ });
89509
+ console.log(`[${formatTimestamp()}] \uD83C\uDF33 File tree subscription started (reactive)`);
89510
+ return {
89511
+ stop: () => {
89512
+ unsubscribe();
89513
+ console.log(`[${formatTimestamp()}] \uD83C\uDF33 File tree subscription stopped`);
89514
+ }
89515
+ };
89516
+ });
89517
+ var init_file_tree_subscription = __esm(() => {
89518
+ init_esm();
89519
+ init_daemon_services();
89520
+ init_api3();
89521
+ init_git_reader();
89522
+ init_file_tree_data_hash();
89523
+ init_file_tree_partition();
89524
+ init_file_tree_scanner();
89525
+ init_file_tree_v3_upload();
89526
+ init_workspace_sync_queue();
89527
+ init_workspace_sync_state();
89528
+ init_convex_error();
89529
+ });
89530
+
89271
89531
  // src/commands/machine/daemon-start/file-write-errors.ts
89272
89532
  function unsupportedFileWriteOperationMessage(operation) {
89273
89533
  return `Unsupported file write operation "${operation}". ` + "Please upgrade chatroom-cli to the latest version and restart the machine daemon " + "(e.g. npm install -g chatroom-cli@latest).";
89274
89534
  }
89275
89535
 
89276
89536
  // src/commands/machine/daemon-start/file-write-fulfillment.ts
89277
- import { access as access4, mkdir as mkdir8, rename as rename4, rm as rm2, writeFile as writeFile7 } from "node:fs/promises";
89537
+ import { access as access4, mkdir as mkdir9, rename as rename5, rm as rm3, writeFile as writeFile8 } from "node:fs/promises";
89278
89538
  import { dirname as dirname9 } from "node:path";
89279
- import { gzipSync as gzipSync5 } from "node:zlib";
89280
89539
  function isTerminalFileWriteError(errorMessage) {
89281
89540
  const terminalMessages = new Set([
89282
89541
  "Invalid file path",
@@ -89296,28 +89555,6 @@ function isTerminalFileWriteError(errorMessage) {
89296
89555
  return true;
89297
89556
  return terminalMessages.has(errorMessage);
89298
89557
  }
89299
- function parentDirPath2(filePath) {
89300
- const idx = filePath.lastIndexOf("/");
89301
- return idx === -1 ? "" : filePath.slice(0, idx);
89302
- }
89303
- async function syncParentDirListingAfterWrite(session2, workingDir, filePath) {
89304
- const dirPath = parentDirPath2(filePath);
89305
- const listing = await listDirectory(workingDir, dirPath);
89306
- const json = JSON.stringify(listing);
89307
- const dataHash = computeDirListingContentHash(listing);
89308
- const compressed = gzipSync5(Buffer.from(json)).toString("base64");
89309
- await session2.backend.mutation(api.workspaceFiles.syncDirListingV2, {
89310
- sessionId: session2.sessionId,
89311
- machineId: session2.machineId,
89312
- workingDir,
89313
- dirPath,
89314
- data: { compression: "gzip", content: compressed },
89315
- dataHash,
89316
- scannedAt: listing.scannedAt,
89317
- truncated: listing.truncated,
89318
- totalCount: listing.totalCount
89319
- });
89320
- }
89321
89558
  async function completeWriteRequest(session2, requestId, result) {
89322
89559
  await session2.backend.mutation(api.workspaceFiles.completeFileWriteRequest, {
89323
89560
  sessionId: session2.sessionId,
@@ -89350,9 +89587,9 @@ async function validateWriteOperation(operation, absolutePath) {
89350
89587
  }
89351
89588
  async function writePayloadToDisk(absolutePath, operation, content) {
89352
89589
  if (operation === "create") {
89353
- await mkdir8(dirname9(absolutePath), { recursive: true });
89590
+ await mkdir9(dirname9(absolutePath), { recursive: true });
89354
89591
  }
89355
- await writeFile7(absolutePath, content);
89592
+ await writeFile8(absolutePath, content);
89356
89593
  }
89357
89594
  async function fulfillOneFileWriteRequest(session2, request2) {
89358
89595
  const startTime = Date.now();
@@ -89413,12 +89650,8 @@ async function fulfillOneFileWriteRequest(session2, request2) {
89413
89650
  });
89414
89651
  return;
89415
89652
  }
89416
- await mkdir8(dirname9(targetResolved.absolutePath), { recursive: true });
89417
- await rename4(resolved.absolutePath, targetResolved.absolutePath);
89418
- await syncParentDirListingAfterWrite(session2, workingDir, filePath);
89419
- if (parentDirPath2(filePath) !== parentDirPath2(request2.targetFilePath)) {
89420
- await syncParentDirListingAfterWrite(session2, workingDir, request2.targetFilePath);
89421
- }
89653
+ await mkdir9(dirname9(targetResolved.absolutePath), { recursive: true });
89654
+ await rename5(resolved.absolutePath, targetResolved.absolutePath);
89422
89655
  await completeWriteRequest(session2, request2._id, { status: "done" });
89423
89656
  const elapsed4 = Date.now() - startTime;
89424
89657
  console.log(`[${formatTimestamp()}] ✏️ File rename fulfilled: ${filePath} → ${request2.targetFilePath} (${elapsed4}ms)`);
@@ -89433,8 +89666,7 @@ async function fulfillOneFileWriteRequest(session2, request2) {
89433
89666
  });
89434
89667
  return;
89435
89668
  }
89436
- await mkdir8(resolved.absolutePath, { recursive: true });
89437
- await syncParentDirListingAfterWrite(session2, workingDir, filePath);
89669
+ await mkdir9(resolved.absolutePath, { recursive: true });
89438
89670
  await completeWriteRequest(session2, request2._id, { status: "done" });
89439
89671
  const elapsed4 = Date.now() - startTime;
89440
89672
  console.log(`[${formatTimestamp()}] ✏️ Directory mkdir fulfilled: ${filePath} (${elapsed4}ms)`);
@@ -89456,8 +89688,7 @@ async function fulfillOneFileWriteRequest(session2, request2) {
89456
89688
  });
89457
89689
  return;
89458
89690
  }
89459
- await rm2(resolved.absolutePath, { recursive: true, force: false });
89460
- await syncParentDirListingAfterWrite(session2, workingDir, filePath);
89691
+ await rm3(resolved.absolutePath, { recursive: true, force: false });
89461
89692
  await completeWriteRequest(session2, request2._id, { status: "done" });
89462
89693
  const elapsed4 = Date.now() - startTime;
89463
89694
  console.log(`[${formatTimestamp()}] ✏️ File delete fulfilled: ${filePath} (${elapsed4}ms)`);
@@ -89487,7 +89718,6 @@ async function fulfillOneFileWriteRequest(session2, request2) {
89487
89718
  return;
89488
89719
  }
89489
89720
  await writePayloadToDisk(resolved.absolutePath, operation, payload.content);
89490
- await syncParentDirListingAfterWrite(session2, workingDir, filePath);
89491
89721
  await completeWriteRequest(session2, request2._id, { status: "done" });
89492
89722
  const elapsed3 = Date.now() - startTime;
89493
89723
  console.log(`[${formatTimestamp()}] ✏️ File write fulfilled: ${filePath} (${operation}, ${(payload.content.length / 1024).toFixed(1)}KB, ${elapsed3}ms)`);
@@ -89510,8 +89740,6 @@ var init_file_write_fulfillment = __esm(() => {
89510
89740
  init_daemon_services();
89511
89741
  init_api3();
89512
89742
  init_assert_registered_working_dir();
89513
- init_dir_listing_content_hash();
89514
- init_dir_listing_scanner();
89515
89743
  init_workspace_path_security();
89516
89744
  MAX_CONTENT_BYTES2 = 512 * 1024;
89517
89745
  fulfillFileWriteRequestsEffect = exports_Effect.gen(function* () {
@@ -89567,7 +89795,7 @@ var init_file_write_subscription = __esm(() => {
89567
89795
  });
89568
89796
 
89569
89797
  // src/infrastructure/git/git-state-pipeline.ts
89570
- import { createHash as createHash6 } from "node:crypto";
89798
+ import { createHash as createHash7 } from "node:crypto";
89571
89799
 
89572
89800
  class GitStatePipeline {
89573
89801
  fields;
@@ -89599,7 +89827,7 @@ class GitStatePipeline {
89599
89827
  const raw = values3.get(field.key) ?? field.defaultValue;
89600
89828
  hashInput[field.key] = field.toHashable(raw);
89601
89829
  }
89602
- return createHash6("md5").update(JSON.stringify(hashInput)).digest("hex");
89830
+ return createHash7("md5").update(JSON.stringify(hashInput)).digest("hex");
89603
89831
  }
89604
89832
  toMutationArgs(values3, slim) {
89605
89833
  const args2 = {};
@@ -89929,7 +90157,7 @@ var init_git_heartbeat = __esm(() => {
89929
90157
  });
89930
90158
 
89931
90159
  // src/commands/machine/daemon-start/git-subscription.ts
89932
- import { gzipSync as gzipSync6 } from "node:zlib";
90160
+ import { gzipSync as gzipSync5 } from "node:zlib";
89933
90161
  function extractDiffStatFromShowOutput(content) {
89934
90162
  for (const line of content.split(`
89935
90163
  `)) {
@@ -89944,7 +90172,7 @@ async function processFullDiff(deps, req) {
89944
90172
  if (result.status === "available" || result.status === "truncated") {
89945
90173
  const diffStatResult = await getDiffStat(req.workingDir);
89946
90174
  const diffStat = diffStatResult.status === "available" ? diffStatResult.diffStat : { filesChanged: 0, insertions: 0, deletions: 0 };
89947
- const compressed = gzipSync6(Buffer.from(result.content));
90175
+ const compressed = gzipSync5(Buffer.from(result.content));
89948
90176
  const diffContentCompressed = compressed.toString("base64");
89949
90177
  await deps.backend.mutation(api.workspaces.upsertFullDiffV2, {
89950
90178
  sessionId: deps.sessionId,
@@ -89956,7 +90184,7 @@ async function processFullDiff(deps, req) {
89956
90184
  });
89957
90185
  console.log(`[${formatTimestamp()}] \uD83D\uDCC4 Full diff pushed: ${req.workingDir} (${diffStat.filesChanged} files, ${(Buffer.byteLength(result.content) / 1024).toFixed(1)}KB → ${(compressed.length / 1024).toFixed(1)}KB gzip, ${result.truncated ? "truncated" : "complete"})`);
89958
90186
  } else {
89959
- const emptyCompressed = gzipSync6(Buffer.from("")).toString("base64");
90187
+ const emptyCompressed = gzipSync5(Buffer.from("")).toString("base64");
89960
90188
  await deps.backend.mutation(api.workspaces.upsertFullDiffV2, {
89961
90189
  sessionId: deps.sessionId,
89962
90190
  machineId: deps.machineId,
@@ -90057,7 +90285,7 @@ async function processCommitDetail(deps, req) {
90057
90285
  ]);
90058
90286
  await upsertCommitDetailResult(deps, req, result, metadata);
90059
90287
  if (result.status === "available" || result.status === "truncated") {
90060
- const compressed = gzipSync6(Buffer.from(result.content));
90288
+ const compressed = gzipSync5(Buffer.from(result.content));
90061
90289
  console.log(`[${formatTimestamp()}] \uD83D\uDD0D Commit detail pushed: ${req.sha.slice(0, 7)} in ${req.workingDir} (${(Buffer.byteLength(result.content) / 1024).toFixed(1)}KB → ${(compressed.length / 1024).toFixed(1)}KB gzip)`);
90062
90290
  }
90063
90291
  }
@@ -90088,7 +90316,7 @@ async function upsertCommitDetailResult(deps, req, result, metadata) {
90088
90316
  return;
90089
90317
  }
90090
90318
  const diffStat = extractDiffStatFromShowOutput(result.content);
90091
- const compressed = gzipSync6(Buffer.from(result.content));
90319
+ const compressed = gzipSync5(Buffer.from(result.content));
90092
90320
  const diffContentCompressed = compressed.toString("base64");
90093
90321
  await deps.backend.mutation(api.workspaces.upsertCommitDetailV2, {
90094
90322
  ...baseArgs,
@@ -90535,7 +90763,7 @@ var init_crash_loop_tracker = __esm(() => {
90535
90763
  });
90536
90764
 
90537
90765
  // ../../services/backend/src/domain/entities/participant.ts
90538
- var NATIVE_WAITING_ACTION = "native:waiting", NATIVE_TASK_INJECTED_ACTION = "native:task-injected", NATIVE_HANDOFF_REMINDER = "Reminder: Use the handoff command to send your response to the team.", ONLINE_OR_STARTING_STATUSES;
90766
+ var PARTICIPANT_EXITED_ACTION = "exited", NATIVE_WAITING_ACTION = "native:waiting", NATIVE_TASK_INJECTED_ACTION = "native:task-injected", NATIVE_HANDOFF_REMINDER = "Reminder: Use the handoff command to send your response to the team.", ONLINE_OR_STARTING_STATUSES;
90539
90767
  var init_participant = __esm(() => {
90540
90768
  ONLINE_OR_STARTING_STATUSES = new Set([
90541
90769
  "agent.waiting",
@@ -90638,7 +90866,10 @@ function isNativeInjectableAliveRunning(task) {
90638
90866
  function isInjectableNativeAction(action) {
90639
90867
  if (action == null)
90640
90868
  return true;
90641
- return action === NATIVE_WAITING_ACTION;
90869
+ return action === NATIVE_WAITING_ACTION || action === PARTICIPANT_EXITED_ACTION;
90870
+ }
90871
+ function isNativePendingRedeliveryAfterRelease(task) {
90872
+ return task.status === "pending" && task.participant?.lastSeenAction === NATIVE_TASK_INJECTED_ACTION;
90642
90873
  }
90643
90874
  function isNativeIdleAfterTaskComplete(participant) {
90644
90875
  return participant.lastSeenAction === NATIVE_TASK_INJECTED_ACTION && participant.lastStatus === "task.completed";
@@ -90704,9 +90935,10 @@ function shouldDeliverNativeTask(task, opts) {
90704
90935
  return false;
90705
90936
  if (!opts.harnessSessionId)
90706
90937
  return false;
90707
- if (opts.ledger.isDelivered(task.taskId, opts.harnessSessionId))
90938
+ if (opts.ledger.isDelivered(task.taskId, opts.harnessSessionId) && task.status !== "pending") {
90708
90939
  return false;
90709
- return isInjectableNativeAction(task.participant?.lastSeenAction) || isNativeIdleAfterTaskComplete(task.participant ?? {}) || isNativeAcknowledgedInjectionRetry(task);
90940
+ }
90941
+ return isInjectableNativeAction(task.participant?.lastSeenAction) || isNativeIdleAfterTaskComplete(task.participant ?? {}) || isNativeAcknowledgedInjectionRetry(task) || isNativePendingRedeliveryAfterRelease(task);
90710
90942
  }
90711
90943
  function buildNativeInjectionPrompt(params) {
90712
90944
  const { taskDeliveryOutput, augmentationMode } = params;
@@ -91208,6 +91440,7 @@ var init_classify_resume_storm_reason = __esm(() => {
91208
91440
  /unauthorized/i,
91209
91441
  /unauthenticated/i,
91210
91442
  /authentication failed/i,
91443
+ /authentication error/i,
91211
91444
  /invalid.{0,24}api.{0,12}key/i,
91212
91445
  /api key.{0,20}(invalid|missing|expired)/i
91213
91446
  ]
@@ -91228,10 +91461,7 @@ var init_classify_resume_storm_reason = __esm(() => {
91228
91461
  ]
91229
91462
  }
91230
91463
  ];
91231
- PERMANENT_FAILURE_REASONS = new Set([
91232
- "auth_error",
91233
- "config_error"
91234
- ]);
91464
+ PERMANENT_FAILURE_REASONS = new Set(["config_error"]);
91235
91465
  });
91236
91466
 
91237
91467
  // src/domain/agent-lifecycle/policies/abort-resume-storm.ts
@@ -94425,17 +94655,17 @@ var init_jsonc = __esm(() => {
94425
94655
  });
94426
94656
 
94427
94657
  // src/infrastructure/services/workspace/workspace-resolver.ts
94428
- import { readFile as readFile8, readdir, stat as stat3 } from "node:fs/promises";
94429
- import { join as join18, basename as basename2, resolve as resolve5 } from "node:path";
94658
+ import { readFile as readFile10, readdir, stat as stat3 } from "node:fs/promises";
94659
+ import { join as join19, basename as basename2, resolve as resolve5 } from "node:path";
94430
94660
  async function resolveGlobPatternStar(rootDir, cleaned) {
94431
- const parentDir = join18(rootDir, cleaned.slice(0, -2));
94661
+ const parentDir = join19(rootDir, cleaned.slice(0, -2));
94432
94662
  try {
94433
94663
  const entries2 = await readdir(parentDir, { withFileTypes: true });
94434
94664
  const dirs = [];
94435
94665
  for (const entry of entries2) {
94436
94666
  if (!entry.isDirectory())
94437
94667
  continue;
94438
- const dirPath = join18(parentDir, entry.name);
94668
+ const dirPath = join19(parentDir, entry.name);
94439
94669
  if (resolve5(dirPath).startsWith(resolve5(rootDir))) {
94440
94670
  dirs.push(dirPath);
94441
94671
  }
@@ -94446,7 +94676,7 @@ async function resolveGlobPatternStar(rootDir, cleaned) {
94446
94676
  }
94447
94677
  }
94448
94678
  async function resolveLiteralPath(rootDir, cleaned) {
94449
- const dir = join18(rootDir, cleaned);
94679
+ const dir = join19(rootDir, cleaned);
94450
94680
  try {
94451
94681
  if (!resolve5(dir).startsWith(resolve5(rootDir)))
94452
94682
  return [];
@@ -94466,7 +94696,7 @@ async function resolveGlobPattern(rootDir, pattern2) {
94466
94696
  }
94467
94697
  async function readPackageJson(dir) {
94468
94698
  try {
94469
- const content = await readFile8(join18(dir, "package.json"), "utf-8");
94699
+ const content = await readFile10(join19(dir, "package.json"), "utf-8");
94470
94700
  const pkg = JSON.parse(content);
94471
94701
  return {
94472
94702
  name: pkg.name || basename2(dir),
@@ -94478,7 +94708,7 @@ async function readPackageJson(dir) {
94478
94708
  }
94479
94709
  async function readPnpmWorkspacePatterns(rootDir) {
94480
94710
  try {
94481
- const content = await readFile8(join18(rootDir, "pnpm-workspace.yaml"), "utf-8");
94711
+ const content = await readFile10(join19(rootDir, "pnpm-workspace.yaml"), "utf-8");
94482
94712
  const patterns = [];
94483
94713
  let inPackages = false;
94484
94714
  for (const line of content.split(`
@@ -94505,7 +94735,7 @@ async function readPnpmWorkspacePatterns(rootDir) {
94505
94735
  }
94506
94736
  async function readPackageJsonWorkspacePatterns(rootDir) {
94507
94737
  try {
94508
- const content = await readFile8(join18(rootDir, "package.json"), "utf-8");
94738
+ const content = await readFile10(join19(rootDir, "package.json"), "utf-8");
94509
94739
  const pkg = JSON.parse(content);
94510
94740
  if (!pkg.workspaces)
94511
94741
  return [];
@@ -94553,12 +94783,12 @@ async function resolveSubWorkspaces(rootDir, pm) {
94553
94783
  var init_workspace_resolver = () => {};
94554
94784
 
94555
94785
  // src/infrastructure/services/workspace/command-discovery.ts
94556
- import { access as access5, readFile as readFile9 } from "node:fs/promises";
94557
- import { join as join19, relative as relative2, basename as basename3 } from "node:path";
94786
+ import { access as access5, readFile as readFile11 } from "node:fs/promises";
94787
+ import { join as join20, relative as relative2, basename as basename3 } from "node:path";
94558
94788
  async function detectPackageManager(workingDir) {
94559
94789
  for (const { file, manager } of LOCKFILE_MAP) {
94560
94790
  try {
94561
- await access5(join19(workingDir, file));
94791
+ await access5(join20(workingDir, file));
94562
94792
  return manager;
94563
94793
  } catch {}
94564
94794
  }
@@ -94602,7 +94832,7 @@ function isValidScriptEntry(name, script) {
94602
94832
  }
94603
94833
  async function readJsonFile(filePath, label) {
94604
94834
  try {
94605
- const content = await readFile9(filePath, "utf-8");
94835
+ const content = await readFile11(filePath, "utf-8");
94606
94836
  return parseJsonc2(content);
94607
94837
  } catch (error) {
94608
94838
  if (error.code !== "ENOENT") {
@@ -94627,7 +94857,7 @@ function collectRootScriptCommands(scripts, pm, scriptPrefix, rootSw) {
94627
94857
  }
94628
94858
  async function readRootPackageJson(workingDir, pm, scriptPrefix) {
94629
94859
  let rootPackageName = basename3(workingDir);
94630
- const pkg = await readJsonFile(join19(workingDir, "package.json"), "root package.json");
94860
+ const pkg = await readJsonFile(join20(workingDir, "package.json"), "root package.json");
94631
94861
  if (!pkg)
94632
94862
  return { commands: [], rootPackageName };
94633
94863
  if (pkg.name)
@@ -94643,7 +94873,7 @@ async function readRootPackageJson(workingDir, pm, scriptPrefix) {
94643
94873
  }
94644
94874
  async function readTurboJson(workingDir, _turboPrefix, _rootSubWorkspace) {
94645
94875
  const turboTaskNames = [];
94646
- const turbo = await readJsonFile(join19(workingDir, "turbo.json"), "turbo.json");
94876
+ const turbo = await readJsonFile(join20(workingDir, "turbo.json"), "turbo.json");
94647
94877
  if (!turbo?.tasks || typeof turbo.tasks !== "object")
94648
94878
  return turboTaskNames;
94649
94879
  for (const taskName of Object.keys(turbo.tasks)) {
@@ -94712,14 +94942,14 @@ var init_command_discovery = __esm(() => {
94712
94942
  });
94713
94943
 
94714
94944
  // src/commands/machine/daemon-start/command-sync-heartbeat.ts
94715
- import { createHash as createHash7 } from "node:crypto";
94945
+ import { createHash as createHash8 } from "node:crypto";
94716
94946
  var pushCommandsEffect, pushSingleWorkspaceCommandsEffect = (workingDir) => exports_Effect.gen(function* () {
94717
94947
  const session2 = yield* DaemonSessionService;
94718
94948
  const mutable2 = yield* DaemonMutableStateService;
94719
94949
  const lastPushedGitState = yield* exports_Ref.get(mutable2.lastPushedGitState);
94720
94950
  const commands = yield* exports_Effect.promise(() => discoverCommands(workingDir));
94721
94951
  const stateKey = `commands:${session2.machineId}::${workingDir}`;
94722
- const commandsHash = createHash7("md5").update(JSON.stringify(commands)).digest("hex");
94952
+ const commandsHash = createHash8("md5").update(JSON.stringify(commands)).digest("hex");
94723
94953
  if (lastPushedGitState.get(stateKey) === commandsHash) {
94724
94954
  return;
94725
94955
  }
@@ -95150,10 +95380,10 @@ function assignProp(target, prop, value) {
95150
95380
  configurable: true
95151
95381
  });
95152
95382
  }
95153
- function getElementAtPath(obj, path6) {
95154
- if (!path6)
95383
+ function getElementAtPath(obj, path5) {
95384
+ if (!path5)
95155
95385
  return obj;
95156
- return path6.reduce((acc, key) => acc?.[key], obj);
95386
+ return path5.reduce((acc, key) => acc?.[key], obj);
95157
95387
  }
95158
95388
  function promiseAllObject(promisesObj) {
95159
95389
  const keys5 = Object.keys(promisesObj);
@@ -95399,11 +95629,11 @@ function aborted(x, startIndex = 0) {
95399
95629
  }
95400
95630
  return false;
95401
95631
  }
95402
- function prefixIssues(path6, issues) {
95632
+ function prefixIssues(path5, issues) {
95403
95633
  return issues.map((iss) => {
95404
95634
  var _a2;
95405
95635
  (_a2 = iss).path ?? (_a2.path = []);
95406
- iss.path.unshift(path6);
95636
+ iss.path.unshift(path5);
95407
95637
  return iss;
95408
95638
  });
95409
95639
  }
@@ -95588,7 +95818,7 @@ function treeifyError(error, _mapper) {
95588
95818
  return issue2.message;
95589
95819
  };
95590
95820
  const result = { errors: [] };
95591
- const processError = (error2, path6 = []) => {
95821
+ const processError = (error2, path5 = []) => {
95592
95822
  var _a2, _b2;
95593
95823
  for (const issue2 of error2.issues) {
95594
95824
  if (issue2.code === "invalid_union" && issue2.errors.length) {
@@ -95598,7 +95828,7 @@ function treeifyError(error, _mapper) {
95598
95828
  } else if (issue2.code === "invalid_element") {
95599
95829
  processError({ issues: issue2.issues }, issue2.path);
95600
95830
  } else {
95601
- const fullpath = [...path6, ...issue2.path];
95831
+ const fullpath = [...path5, ...issue2.path];
95602
95832
  if (fullpath.length === 0) {
95603
95833
  result.errors.push(mapper(issue2));
95604
95834
  continue;
@@ -95628,9 +95858,9 @@ function treeifyError(error, _mapper) {
95628
95858
  processError(error);
95629
95859
  return result;
95630
95860
  }
95631
- function toDotPath(path6) {
95861
+ function toDotPath(path5) {
95632
95862
  const segs = [];
95633
- for (const seg of path6) {
95863
+ for (const seg of path5) {
95634
95864
  if (typeof seg === "number")
95635
95865
  segs.push(`[${seg}]`);
95636
95866
  else if (typeof seg === "symbol")
@@ -107531,8 +107761,6 @@ var init_command_loop = __esm(() => {
107531
107761
  init_featureFlags();
107532
107762
  init_reliability();
107533
107763
  init_esm();
107534
- init_dir_listing_subscription();
107535
- init_dir_listing_watch_subscription();
107536
107764
  init_api3();
107537
107765
  init_on_request_start_agent();
107538
107766
  init_on_request_stop_agent();
@@ -107545,6 +107773,7 @@ var init_command_loop = __esm(() => {
107545
107773
  init_daemon_services();
107546
107774
  init_start_subscriptions();
107547
107775
  init_file_content_subscription();
107776
+ init_file_tree_subscription();
107548
107777
  init_file_write_subscription();
107549
107778
  init_git_heartbeat();
107550
107779
  init_git_subscription();
@@ -107588,8 +107817,7 @@ var init_command_loop = __esm(() => {
107588
107817
  let gitSubscriptionHandle = null;
107589
107818
  let fileContentSubscriptionHandle = null;
107590
107819
  let fileWriteSubscriptionHandle = null;
107591
- let dirListingSubscriptionHandle = null;
107592
- let dirListingWatchSubscriptionHandle = null;
107820
+ let fileTreeSubscriptionHandle = null;
107593
107821
  let workspaceListSubscriptionHandle = null;
107594
107822
  let observedSyncSubscriptionHandle = null;
107595
107823
  let logObserverSubscriptionHandle = null;
@@ -107654,8 +107882,7 @@ var init_command_loop = __esm(() => {
107654
107882
  gitSubscriptionHandle?.stop();
107655
107883
  fileContentSubscriptionHandle?.stop();
107656
107884
  fileWriteSubscriptionHandle?.stop();
107657
- dirListingSubscriptionHandle?.stop();
107658
- dirListingWatchSubscriptionHandle?.stop();
107885
+ fileTreeSubscriptionHandle?.stop();
107659
107886
  workspaceListSubscriptionHandle?.stop();
107660
107887
  observedSyncSubscriptionHandle?.stop();
107661
107888
  taskMonitorHandle?.stop();
@@ -107700,8 +107927,7 @@ var init_command_loop = __esm(() => {
107700
107927
  gitSubscriptionHandle = yield* startGitRequestSubscriptionEffect(wsClient2);
107701
107928
  fileContentSubscriptionHandle = yield* startFileContentSubscriptionEffect(wsClient2);
107702
107929
  fileWriteSubscriptionHandle = yield* startFileWriteSubscriptionEffect(wsClient2);
107703
- dirListingSubscriptionHandle = yield* startDirListingSubscriptionEffect(wsClient2);
107704
- dirListingWatchSubscriptionHandle = yield* startDirListingWatchSubscriptionEffect(wsClient2);
107930
+ fileTreeSubscriptionHandle = yield* startFileTreeSubscriptionEffect(wsClient2);
107705
107931
  workspaceListSubscriptionHandle = yield* startWorkspaceListSubscriptionEffect(wsClient2);
107706
107932
  observedSyncSubscriptionHandle = yield* startObservedSyncSubscriptionEffect(wsClient2);
107707
107933
  const taskMonitorHandle = yield* startTaskMonitorEffect(wsClient2);
@@ -107902,7 +108128,7 @@ __export(exports_opencode_install, {
107902
108128
  installTool: () => installTool
107903
108129
  });
107904
108130
  import * as os2 from "os";
107905
- import * as path6 from "path";
108131
+ import * as path5 from "path";
107906
108132
  async function isChatroomInstalledDefault() {
107907
108133
  try {
107908
108134
  const { execSync: execSync3 } = await import("child_process");
@@ -107914,7 +108140,7 @@ async function isChatroomInstalledDefault() {
107914
108140
  }
107915
108141
  async function createDefaultDeps18() {
107916
108142
  const client4 = await getConvexClient();
107917
- const fs11 = await import("fs/promises");
108143
+ const fs12 = await import("fs/promises");
107918
108144
  return {
107919
108145
  backend: {
107920
108146
  mutation: (endpoint, args2) => client4.mutation(endpoint, args2),
@@ -107927,13 +108153,13 @@ async function createDefaultDeps18() {
107927
108153
  },
107928
108154
  fs: {
107929
108155
  access: async (p) => {
107930
- await fs11.access(p);
108156
+ await fs12.access(p);
107931
108157
  },
107932
108158
  mkdir: async (p, options) => {
107933
- await fs11.mkdir(p, options);
108159
+ await fs12.mkdir(p, options);
107934
108160
  },
107935
108161
  writeFile: async (p, content, encoding) => {
107936
- await fs11.writeFile(p, content, encoding);
108162
+ await fs12.writeFile(p, content, encoding);
107937
108163
  }
107938
108164
  },
107939
108165
  isChatroomInstalled: isChatroomInstalledDefault
@@ -108272,9 +108498,9 @@ After logging in, try this command again.\`;
108272
108498
  const fsService = yield* OpenCodeInstallFsService;
108273
108499
  const { checkExisting = true } = options;
108274
108500
  const homeDir = os2.homedir();
108275
- const toolDir = path6.join(homeDir, ".config", "opencode", "tool");
108276
- const toolPath = path6.join(toolDir, "chatroom.ts");
108277
- const handoffToolPath = path6.join(toolDir, "chatroom-handoff.ts");
108501
+ const toolDir = path5.join(homeDir, ".config", "opencode", "tool");
108502
+ const toolPath = path5.join(toolDir, "chatroom.ts");
108503
+ const handoffToolPath = path5.join(toolDir, "chatroom-handoff.ts");
108278
108504
  if (checkExisting) {
108279
108505
  const existingFiles = [];
108280
108506
  const toolExists = yield* fsService.access(toolPath);
@@ -108829,4 +109055,4 @@ program2.hook("preAction", async (_thisCommand, actionCommand) => {
108829
109055
  });
108830
109056
  program2.parse();
108831
109057
 
108832
- //# debugId=E351FE352EFBDC8D64756E2164756E21
109058
+ //# debugId=0F49F7F33D425EFB64756E2164756E21