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 +1167 -941
- package/dist/index.js.map +28 -25
- package/dist/node-launch.js.map +2 -2
- package/package.json +3 -2
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 =
|
|
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
|
-
|
|
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
|
-
|
|
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",
|
|
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:
|
|
33773
|
+
local: buildLocalAgentOptions(stored.workingDir)
|
|
33742
33774
|
}), AGENT_CREATE_TIMEOUT_MS, "Agent.resume");
|
|
33743
33775
|
} catch (err) {
|
|
33744
|
-
|
|
33745
|
-
process.stderr.write(`[${new Date().toISOString()}] role:${context5.role} daemon-resume-fallback] ${
|
|
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:
|
|
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
|
-
|
|
83890
|
-
|
|
83891
|
-
|
|
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
|
|
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
|
|
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((
|
|
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
|
-
|
|
85026
|
+
resolve4(true);
|
|
85769
85027
|
return;
|
|
85770
85028
|
}
|
|
85771
85029
|
elapsed3 += interval;
|
|
85772
85030
|
if (elapsed3 >= ms) {
|
|
85773
85031
|
clearInterval(timer);
|
|
85774
|
-
|
|
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
|
|
85067
|
+
import { gunzipSync, gzipSync } from "node:zlib";
|
|
85810
85068
|
function encodeOutput(plain) {
|
|
85811
|
-
const compressed =
|
|
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
|
|
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 =
|
|
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((
|
|
86335
|
-
const t = setTimeout(
|
|
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((
|
|
86348
|
-
const t = setTimeout(
|
|
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
|
|
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((
|
|
86486
|
-
|
|
86487
|
-
|
|
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
|
-
|
|
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
|
|
86612
|
-
if (!
|
|
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:
|
|
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
|
|
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
|
|
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((
|
|
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
|
|
86379
|
+
const resolve4 = this._waiter;
|
|
87122
86380
|
this._waiter = null;
|
|
87123
|
-
|
|
86381
|
+
resolve4();
|
|
87124
86382
|
}
|
|
87125
86383
|
}
|
|
87126
86384
|
_waitForData() {
|
|
87127
|
-
return new Promise((
|
|
87128
|
-
this._waiter =
|
|
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((
|
|
87184
|
-
this._idleResolve =
|
|
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
|
|
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((
|
|
86773
|
+
await new Promise((resolve4) => {
|
|
87516
86774
|
const timeout3 = setTimeout(() => {
|
|
87517
86775
|
this.childProcess.kill("SIGKILL");
|
|
87518
|
-
|
|
86776
|
+
resolve4();
|
|
87519
86777
|
}, 5000);
|
|
87520
86778
|
this.childProcess.once("exit", () => {
|
|
87521
86779
|
clearTimeout(timeout3);
|
|
87522
|
-
|
|
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 =
|
|
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((
|
|
88162
|
+
return new Promise((resolve4) => {
|
|
88905
88163
|
const check3 = () => {
|
|
88906
88164
|
if (!flushInProgress)
|
|
88907
|
-
|
|
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/
|
|
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
|
|
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(
|
|
89089
|
-
const lastDot =
|
|
88886
|
+
function isBinaryFile(path4) {
|
|
88887
|
+
const lastDot = path4.lastIndexOf(".");
|
|
89090
88888
|
if (lastDot === -1)
|
|
89091
88889
|
return false;
|
|
89092
|
-
return BINARY_EXTENSIONS.has(
|
|
88890
|
+
return BINARY_EXTENSIONS.has(path4.slice(lastDot).toLowerCase());
|
|
89093
88891
|
}
|
|
89094
88892
|
function gzipPlainText(text) {
|
|
89095
|
-
return
|
|
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(() =>
|
|
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 =
|
|
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
|
|
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
|
|
89590
|
+
await mkdir9(dirname9(absolutePath), { recursive: true });
|
|
89354
89591
|
}
|
|
89355
|
-
await
|
|
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
|
|
89417
|
-
await
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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
|
-
|
|
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
|
|
94429
|
-
import { join as
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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
|
|
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
|
|
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
|
|
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
|
|
94557
|
-
import { join as
|
|
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(
|
|
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
|
|
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(
|
|
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(
|
|
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
|
|
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 =
|
|
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,
|
|
95154
|
-
if (!
|
|
95383
|
+
function getElementAtPath(obj, path5) {
|
|
95384
|
+
if (!path5)
|
|
95155
95385
|
return obj;
|
|
95156
|
-
return
|
|
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(
|
|
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(
|
|
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,
|
|
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 = [...
|
|
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(
|
|
95861
|
+
function toDotPath(path5) {
|
|
95632
95862
|
const segs = [];
|
|
95633
|
-
for (const seg of
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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
|
|
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
|
|
108156
|
+
await fs12.access(p);
|
|
107931
108157
|
},
|
|
107932
108158
|
mkdir: async (p, options) => {
|
|
107933
|
-
await
|
|
108159
|
+
await fs12.mkdir(p, options);
|
|
107934
108160
|
},
|
|
107935
108161
|
writeFile: async (p, content, encoding) => {
|
|
107936
|
-
await
|
|
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 =
|
|
108276
|
-
const toolPath =
|
|
108277
|
-
const handoffToolPath =
|
|
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=
|
|
109058
|
+
//# debugId=0F49F7F33D425EFB64756E2164756E21
|