@adhdev/daemon-core 0.9.52 → 0.9.54
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/commands/handler.d.ts +2 -0
- package/dist/git/git-commands.d.ts +86 -0
- package/dist/git/git-diff.d.ts +17 -0
- package/dist/git/git-executor.d.ts +34 -0
- package/dist/git/git-monitor.d.ts +57 -0
- package/dist/git/git-snapshot-store.d.ts +50 -0
- package/dist/git/git-status.d.ts +19 -0
- package/dist/git/git-summary.d.ts +10 -0
- package/dist/git/git-types.d.ts +113 -0
- package/dist/git/index.d.ts +14 -0
- package/dist/index.d.ts +2 -1
- package/dist/index.js +1611 -392
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +1584 -389
- package/dist/index.mjs.map +1 -1
- package/dist/shared-types.d.ts +7 -1
- package/dist/status/builders.d.ts +2 -0
- package/dist/status/snapshot.d.ts +2 -0
- package/node_modules/@adhdev/session-host-core/package.json +1 -1
- package/package.json +1 -1
- package/src/commands/chat-commands.ts +31 -4
- package/src/commands/handler.ts +9 -1
- package/src/config/chat-history.ts +11 -3
- package/src/git/git-commands.ts +385 -0
- package/src/git/git-diff.ts +303 -0
- package/src/git/git-executor.ts +268 -0
- package/src/git/git-monitor.ts +194 -0
- package/src/git/git-snapshot-store.ts +238 -0
- package/src/git/git-status.ts +193 -0
- package/src/git/git-summary.ts +43 -0
- package/src/git/git-types.ts +153 -0
- package/src/git/index.ts +72 -0
- package/src/index.ts +4 -0
- package/src/shared-types.ts +33 -1
- package/src/status/builders.ts +26 -4
- package/src/status/snapshot.ts +10 -2
package/dist/index.mjs
CHANGED
|
@@ -265,7 +265,7 @@ var init_config = __esm({
|
|
|
265
265
|
|
|
266
266
|
// src/logging/logger.ts
|
|
267
267
|
import * as fs2 from "fs";
|
|
268
|
-
import * as
|
|
268
|
+
import * as path9 from "path";
|
|
269
269
|
import * as os4 from "os";
|
|
270
270
|
function setLogLevel(level) {
|
|
271
271
|
currentLevel = level;
|
|
@@ -281,13 +281,13 @@ function getDaemonLogDir() {
|
|
|
281
281
|
return LOG_DIR;
|
|
282
282
|
}
|
|
283
283
|
function getCurrentDaemonLogPath(date = /* @__PURE__ */ new Date()) {
|
|
284
|
-
return
|
|
284
|
+
return path9.join(LOG_DIR, `daemon-${date.toISOString().slice(0, 10)}.log`);
|
|
285
285
|
}
|
|
286
286
|
function checkDateRotation() {
|
|
287
287
|
const today = getDateStr();
|
|
288
288
|
if (today !== currentDate) {
|
|
289
289
|
currentDate = today;
|
|
290
|
-
currentLogFile =
|
|
290
|
+
currentLogFile = path9.join(LOG_DIR, `daemon-${currentDate}.log`);
|
|
291
291
|
cleanOldLogs();
|
|
292
292
|
}
|
|
293
293
|
}
|
|
@@ -301,7 +301,7 @@ function cleanOldLogs() {
|
|
|
301
301
|
const dateMatch = file.match(/daemon-(\d{4}-\d{2}-\d{2})/);
|
|
302
302
|
if (dateMatch && dateMatch[1] < cutoffStr) {
|
|
303
303
|
try {
|
|
304
|
-
fs2.unlinkSync(
|
|
304
|
+
fs2.unlinkSync(path9.join(LOG_DIR, file));
|
|
305
305
|
} catch {
|
|
306
306
|
}
|
|
307
307
|
}
|
|
@@ -311,8 +311,8 @@ function cleanOldLogs() {
|
|
|
311
311
|
}
|
|
312
312
|
function rotateSizeIfNeeded() {
|
|
313
313
|
try {
|
|
314
|
-
const
|
|
315
|
-
if (
|
|
314
|
+
const stat2 = fs2.statSync(currentLogFile);
|
|
315
|
+
if (stat2.size > MAX_LOG_SIZE) {
|
|
316
316
|
const backup = currentLogFile.replace(".log", ".1.log");
|
|
317
317
|
try {
|
|
318
318
|
fs2.unlinkSync(backup);
|
|
@@ -424,7 +424,7 @@ var init_logger = __esm({
|
|
|
424
424
|
LEVEL_NUM = { debug: 0, info: 1, warn: 2, error: 3 };
|
|
425
425
|
LEVEL_LABEL = { debug: "DBG", info: "INF", warn: "WRN", error: "ERR" };
|
|
426
426
|
currentLevel = "info";
|
|
427
|
-
LOG_DIR = process.platform === "win32" ?
|
|
427
|
+
LOG_DIR = process.platform === "win32" ? path9.join(process.env.LOCALAPPDATA || process.env.APPDATA || path9.join(os4.homedir(), "AppData", "Local"), "adhdev", "logs") : process.platform === "darwin" ? path9.join(os4.homedir(), "Library", "Logs", "adhdev") : path9.join(os4.homedir(), ".local", "share", "adhdev", "logs");
|
|
428
428
|
MAX_LOG_SIZE = 5 * 1024 * 1024;
|
|
429
429
|
MAX_LOG_DAYS = 7;
|
|
430
430
|
try {
|
|
@@ -432,16 +432,16 @@ var init_logger = __esm({
|
|
|
432
432
|
} catch {
|
|
433
433
|
}
|
|
434
434
|
currentDate = getDateStr();
|
|
435
|
-
currentLogFile =
|
|
435
|
+
currentLogFile = path9.join(LOG_DIR, `daemon-${currentDate}.log`);
|
|
436
436
|
cleanOldLogs();
|
|
437
437
|
try {
|
|
438
|
-
const oldLog =
|
|
438
|
+
const oldLog = path9.join(LOG_DIR, "daemon.log");
|
|
439
439
|
if (fs2.existsSync(oldLog)) {
|
|
440
|
-
const
|
|
441
|
-
const oldDate =
|
|
442
|
-
fs2.renameSync(oldLog,
|
|
440
|
+
const stat2 = fs2.statSync(oldLog);
|
|
441
|
+
const oldDate = stat2.mtime.toISOString().slice(0, 10);
|
|
442
|
+
fs2.renameSync(oldLog, path9.join(LOG_DIR, `daemon-${oldDate}.log`));
|
|
443
443
|
}
|
|
444
|
-
const oldLogBackup =
|
|
444
|
+
const oldLogBackup = path9.join(LOG_DIR, "daemon.log.old");
|
|
445
445
|
if (fs2.existsSync(oldLogBackup)) {
|
|
446
446
|
fs2.unlinkSync(oldLogBackup);
|
|
447
447
|
}
|
|
@@ -473,7 +473,7 @@ var init_logger = __esm({
|
|
|
473
473
|
}
|
|
474
474
|
};
|
|
475
475
|
interceptorInstalled = false;
|
|
476
|
-
LOG_PATH =
|
|
476
|
+
LOG_PATH = path9.join(LOG_DIR, `daemon-${getDateStr()}.log`);
|
|
477
477
|
}
|
|
478
478
|
});
|
|
479
479
|
|
|
@@ -1380,8 +1380,8 @@ var init_pty_transport = __esm({
|
|
|
1380
1380
|
if (cwd) {
|
|
1381
1381
|
try {
|
|
1382
1382
|
const fs16 = __require("fs");
|
|
1383
|
-
const
|
|
1384
|
-
if (!
|
|
1383
|
+
const stat2 = fs16.statSync(cwd);
|
|
1384
|
+
if (!stat2.isDirectory()) cwd = os8.homedir();
|
|
1385
1385
|
} catch {
|
|
1386
1386
|
cwd = os8.homedir();
|
|
1387
1387
|
}
|
|
@@ -1401,7 +1401,7 @@ var init_pty_transport = __esm({
|
|
|
1401
1401
|
|
|
1402
1402
|
// src/cli-adapters/provider-cli-shared.ts
|
|
1403
1403
|
import * as os9 from "os";
|
|
1404
|
-
import * as
|
|
1404
|
+
import * as path13 from "path";
|
|
1405
1405
|
import { execSync as execSync3 } from "child_process";
|
|
1406
1406
|
function stripAnsi(str) {
|
|
1407
1407
|
return str.replace(/\x1B\][^\x07]*\x07/g, "").replace(/\x1B\][\s\S]*?\x1B\\/g, "").replace(/\x1B[P^_X][\s\S]*?(?:\x07|\x1B\\)/g, "").replace(/\x1B\[\d*[A-HJKSTfG]/g, " ").replace(/\x1B(?:[@-Z\\-_]|\[[0-?]*[ -/]*[@-~])/g, "").replace(/ +/g, " ");
|
|
@@ -1466,9 +1466,9 @@ function buildCliScreenSnapshot(text) {
|
|
|
1466
1466
|
function findBinary(name) {
|
|
1467
1467
|
const trimmed = String(name || "").trim();
|
|
1468
1468
|
if (!trimmed) return trimmed;
|
|
1469
|
-
const expanded = trimmed.startsWith("~") ?
|
|
1470
|
-
if (
|
|
1471
|
-
return
|
|
1469
|
+
const expanded = trimmed.startsWith("~") ? path13.join(os9.homedir(), trimmed.slice(1)) : trimmed;
|
|
1470
|
+
if (path13.isAbsolute(expanded) || expanded.includes("/") || expanded.includes("\\")) {
|
|
1471
|
+
return path13.isAbsolute(expanded) ? expanded : path13.resolve(expanded);
|
|
1472
1472
|
}
|
|
1473
1473
|
const isWin = os9.platform() === "win32";
|
|
1474
1474
|
try {
|
|
@@ -1484,7 +1484,7 @@ function findBinary(name) {
|
|
|
1484
1484
|
}
|
|
1485
1485
|
}
|
|
1486
1486
|
function isScriptBinary(binaryPath) {
|
|
1487
|
-
if (!
|
|
1487
|
+
if (!path13.isAbsolute(binaryPath)) return false;
|
|
1488
1488
|
try {
|
|
1489
1489
|
const fs16 = __require("fs");
|
|
1490
1490
|
const resolved = fs16.realpathSync(binaryPath);
|
|
@@ -1500,7 +1500,7 @@ function isScriptBinary(binaryPath) {
|
|
|
1500
1500
|
}
|
|
1501
1501
|
}
|
|
1502
1502
|
function looksLikeMachOOrElf(filePath) {
|
|
1503
|
-
if (!
|
|
1503
|
+
if (!path13.isAbsolute(filePath)) return false;
|
|
1504
1504
|
try {
|
|
1505
1505
|
const fs16 = __require("fs");
|
|
1506
1506
|
const resolved = fs16.realpathSync(filePath);
|
|
@@ -1961,7 +1961,7 @@ var init_provider_cli_config = __esm({
|
|
|
1961
1961
|
|
|
1962
1962
|
// src/cli-adapters/provider-cli-runtime.ts
|
|
1963
1963
|
import * as os10 from "os";
|
|
1964
|
-
import * as
|
|
1964
|
+
import * as path14 from "path";
|
|
1965
1965
|
import { DEFAULT_SESSION_HOST_COLS, DEFAULT_SESSION_HOST_ROWS } from "@adhdev/session-host-core";
|
|
1966
1966
|
function resolveCliSpawnPlan(options) {
|
|
1967
1967
|
const { provider, runtimeSettings, workingDir, extraArgs } = options;
|
|
@@ -1972,9 +1972,9 @@ function resolveCliSpawnPlan(options) {
|
|
|
1972
1972
|
const allArgs = [...spawnConfig.args, ...extraArgs];
|
|
1973
1973
|
let shellCmd;
|
|
1974
1974
|
let shellArgs;
|
|
1975
|
-
const useShellUnix = !isWin && (!!spawnConfig.shell || !
|
|
1975
|
+
const useShellUnix = !isWin && (!!spawnConfig.shell || !path14.isAbsolute(binaryPath) || isScriptBinary(binaryPath) || !looksLikeMachOOrElf(binaryPath));
|
|
1976
1976
|
const isCmdShim = isWin && /\.(cmd|bat)$/i.test(binaryPath);
|
|
1977
|
-
const useShellWin = !!spawnConfig.shell || isCmdShim || !
|
|
1977
|
+
const useShellWin = !!spawnConfig.shell || isCmdShim || !path14.isAbsolute(binaryPath) || isScriptBinary(binaryPath);
|
|
1978
1978
|
const useShell = isWin ? useShellWin : useShellUnix;
|
|
1979
1979
|
if (useShell) {
|
|
1980
1980
|
shellCmd = isWin ? "cmd.exe" : process.env.SHELL || "/bin/zsh";
|
|
@@ -2851,7 +2851,7 @@ var init_provider_cli_adapter = __esm({
|
|
|
2851
2851
|
`[${this.cliType}] Waiting for interactive prompt: status=${status} stableMs=${stableMs} recentOutputMs=${recentlyOutput} screen=${JSON.stringify(summarizeCliTraceText(screenText, 220)).slice(0, 260)}`
|
|
2852
2852
|
);
|
|
2853
2853
|
}
|
|
2854
|
-
await new Promise((
|
|
2854
|
+
await new Promise((resolve15) => setTimeout(resolve15, 50));
|
|
2855
2855
|
}
|
|
2856
2856
|
const finalScreenText = this.terminalScreen.getText() || "";
|
|
2857
2857
|
LOG.warn(
|
|
@@ -4039,7 +4039,7 @@ var init_provider_cli_adapter = __esm({
|
|
|
4039
4039
|
const deadline = Date.now() + 1e4;
|
|
4040
4040
|
while (this.startupParseGate && Date.now() < deadline) {
|
|
4041
4041
|
this.resolveStartupState("send_wait");
|
|
4042
|
-
await new Promise((
|
|
4042
|
+
await new Promise((resolve15) => setTimeout(resolve15, 50));
|
|
4043
4043
|
}
|
|
4044
4044
|
}
|
|
4045
4045
|
if (!allowInterventionPrompt) {
|
|
@@ -4120,13 +4120,13 @@ var init_provider_cli_adapter = __esm({
|
|
|
4120
4120
|
}
|
|
4121
4121
|
this.responseEpoch += 1;
|
|
4122
4122
|
this.responseSettleIgnoreUntil = Date.now() + submitDelayMs + this.timeouts.outputSettle + 250;
|
|
4123
|
-
await new Promise((
|
|
4123
|
+
await new Promise((resolve15, reject) => {
|
|
4124
4124
|
let resolved = false;
|
|
4125
4125
|
const completion = {
|
|
4126
4126
|
resolveOnce: () => {
|
|
4127
4127
|
if (resolved) return;
|
|
4128
4128
|
resolved = true;
|
|
4129
|
-
|
|
4129
|
+
resolve15();
|
|
4130
4130
|
},
|
|
4131
4131
|
rejectOnce: (error) => {
|
|
4132
4132
|
if (resolved) return;
|
|
@@ -4288,17 +4288,17 @@ var init_provider_cli_adapter = __esm({
|
|
|
4288
4288
|
}
|
|
4289
4289
|
}
|
|
4290
4290
|
waitForStopped(timeoutMs) {
|
|
4291
|
-
return new Promise((
|
|
4291
|
+
return new Promise((resolve15) => {
|
|
4292
4292
|
const startedAt = Date.now();
|
|
4293
4293
|
const timer = setInterval(() => {
|
|
4294
4294
|
if (!this.ptyProcess || this.currentStatus === "stopped") {
|
|
4295
4295
|
clearInterval(timer);
|
|
4296
|
-
|
|
4296
|
+
resolve15(true);
|
|
4297
4297
|
return;
|
|
4298
4298
|
}
|
|
4299
4299
|
if (Date.now() - startedAt >= timeoutMs) {
|
|
4300
4300
|
clearInterval(timer);
|
|
4301
|
-
|
|
4301
|
+
resolve15(false);
|
|
4302
4302
|
}
|
|
4303
4303
|
}, 100);
|
|
4304
4304
|
});
|
|
@@ -4524,20 +4524,1137 @@ var init_provider_cli_adapter = __esm({
|
|
|
4524
4524
|
}
|
|
4525
4525
|
});
|
|
4526
4526
|
|
|
4527
|
+
// src/git/git-executor.ts
|
|
4528
|
+
import { execFile } from "child_process";
|
|
4529
|
+
import { constants } from "fs";
|
|
4530
|
+
import { access, realpath, stat } from "fs/promises";
|
|
4531
|
+
import * as path from "path";
|
|
4532
|
+
import { promisify } from "util";
|
|
4533
|
+
var execFileAsync = promisify(execFile);
|
|
4534
|
+
var DEFAULT_TIMEOUT_MS = 5e3;
|
|
4535
|
+
var DEFAULT_MAX_BUFFER = 1024 * 1024;
|
|
4536
|
+
var GitCommandError = class extends Error {
|
|
4537
|
+
reason;
|
|
4538
|
+
stdout;
|
|
4539
|
+
stderr;
|
|
4540
|
+
exitCode;
|
|
4541
|
+
signal;
|
|
4542
|
+
argv;
|
|
4543
|
+
cwd;
|
|
4544
|
+
constructor(reason, message, details = {}) {
|
|
4545
|
+
super(message);
|
|
4546
|
+
if (details.cause !== void 0) {
|
|
4547
|
+
this.cause = details.cause;
|
|
4548
|
+
}
|
|
4549
|
+
this.name = "GitCommandError";
|
|
4550
|
+
this.reason = reason;
|
|
4551
|
+
this.stdout = normalizeGitOutput(details.stdout);
|
|
4552
|
+
this.stderr = normalizeGitOutput(details.stderr);
|
|
4553
|
+
this.exitCode = details.exitCode;
|
|
4554
|
+
this.signal = details.signal;
|
|
4555
|
+
this.argv = details.argv ? [...details.argv] : void 0;
|
|
4556
|
+
this.cwd = details.cwd;
|
|
4557
|
+
}
|
|
4558
|
+
};
|
|
4559
|
+
async function resolveGitRepository(workspace, options = {}) {
|
|
4560
|
+
const normalizedWorkspace = await validateWorkspace(workspace);
|
|
4561
|
+
const result = await execGitRaw(normalizedWorkspace, ["rev-parse", "--show-toplevel"], options, {
|
|
4562
|
+
mapNotGitRepo: true
|
|
4563
|
+
});
|
|
4564
|
+
const repoRoot = path.resolve(result.stdout.trim());
|
|
4565
|
+
if (!repoRoot) {
|
|
4566
|
+
throw new GitCommandError("not_git_repo", "Git did not return a repository root", {
|
|
4567
|
+
stdout: result.stdout,
|
|
4568
|
+
stderr: result.stderr,
|
|
4569
|
+
argv: ["rev-parse", "--show-toplevel"],
|
|
4570
|
+
cwd: normalizedWorkspace
|
|
4571
|
+
});
|
|
4572
|
+
}
|
|
4573
|
+
return {
|
|
4574
|
+
workspace: normalizedWorkspace,
|
|
4575
|
+
repoRoot,
|
|
4576
|
+
isGitRepo: true
|
|
4577
|
+
};
|
|
4578
|
+
}
|
|
4579
|
+
async function runGit(repoOrWorkspace, argv, options = {}) {
|
|
4580
|
+
validateGitArgv(argv);
|
|
4581
|
+
const repo = typeof repoOrWorkspace === "string" ? await resolveGitRepository(repoOrWorkspace, options) : repoOrWorkspace;
|
|
4582
|
+
if (!repo.repoRoot || !repo.isGitRepo) {
|
|
4583
|
+
throw new GitCommandError("not_git_repo", "Workspace is not a Git repository", {
|
|
4584
|
+
argv,
|
|
4585
|
+
cwd: repo.workspace
|
|
4586
|
+
});
|
|
4587
|
+
}
|
|
4588
|
+
const cwd = options.cwd ? await validateWorkspace(options.cwd) : await validateWorkspace(repo.workspace);
|
|
4589
|
+
const canonicalRepoRoot = await realpath(repo.repoRoot);
|
|
4590
|
+
const canonicalCwd = await realpath(cwd);
|
|
4591
|
+
if (!isPathInside(canonicalRepoRoot, canonicalCwd)) {
|
|
4592
|
+
throw new GitCommandError("path_outside_repo", "Git cwd is outside the repository root", {
|
|
4593
|
+
argv,
|
|
4594
|
+
cwd
|
|
4595
|
+
});
|
|
4596
|
+
}
|
|
4597
|
+
return execGitRaw(cwd, argv, options);
|
|
4598
|
+
}
|
|
4599
|
+
function normalizeGitOutput(value) {
|
|
4600
|
+
if (typeof value === "string") return value.replace(/\r\n/g, "\n");
|
|
4601
|
+
if (Buffer.isBuffer(value)) return value.toString("utf8").replace(/\r\n/g, "\n");
|
|
4602
|
+
if (value == null) return "";
|
|
4603
|
+
return String(value).replace(/\r\n/g, "\n");
|
|
4604
|
+
}
|
|
4605
|
+
function isPathInside(parent, child) {
|
|
4606
|
+
const relative3 = path.relative(path.resolve(parent), path.resolve(child));
|
|
4607
|
+
return relative3 === "" || !relative3.startsWith("..") && !path.isAbsolute(relative3);
|
|
4608
|
+
}
|
|
4609
|
+
async function validateWorkspace(workspace) {
|
|
4610
|
+
if (typeof workspace !== "string" || workspace.length === 0 || workspace.includes("\0")) {
|
|
4611
|
+
throw new GitCommandError("invalid_args", "Workspace must be a non-empty path");
|
|
4612
|
+
}
|
|
4613
|
+
if (!path.isAbsolute(workspace)) {
|
|
4614
|
+
throw new GitCommandError("invalid_args", "Workspace must be an absolute path", { cwd: workspace });
|
|
4615
|
+
}
|
|
4616
|
+
const normalizedWorkspace = path.resolve(workspace);
|
|
4617
|
+
try {
|
|
4618
|
+
const info = await stat(normalizedWorkspace);
|
|
4619
|
+
if (!info.isDirectory()) {
|
|
4620
|
+
throw new GitCommandError("invalid_args", "Workspace must be an existing directory", {
|
|
4621
|
+
cwd: normalizedWorkspace
|
|
4622
|
+
});
|
|
4623
|
+
}
|
|
4624
|
+
await access(normalizedWorkspace, constants.R_OK);
|
|
4625
|
+
} catch (error) {
|
|
4626
|
+
if (error instanceof GitCommandError) throw error;
|
|
4627
|
+
throw new GitCommandError("invalid_args", "Workspace must be an existing directory", {
|
|
4628
|
+
cwd: normalizedWorkspace,
|
|
4629
|
+
cause: error
|
|
4630
|
+
});
|
|
4631
|
+
}
|
|
4632
|
+
return normalizedWorkspace;
|
|
4633
|
+
}
|
|
4634
|
+
function validateGitArgv(argv) {
|
|
4635
|
+
if (!Array.isArray(argv) || argv.length === 0) {
|
|
4636
|
+
throw new GitCommandError("invalid_args", "Git argv must be a non-empty string array", { argv });
|
|
4637
|
+
}
|
|
4638
|
+
for (const arg of argv) {
|
|
4639
|
+
if (typeof arg !== "string" || arg.length === 0 || arg.includes("\0")) {
|
|
4640
|
+
throw new GitCommandError("invalid_args", "Git argv contains an invalid argument", { argv });
|
|
4641
|
+
}
|
|
4642
|
+
}
|
|
4643
|
+
if (argv.includes("-C") || argv.some((arg) => arg.startsWith("--git-dir") || arg.startsWith("--work-tree"))) {
|
|
4644
|
+
throw new GitCommandError("invalid_args", "Git argv contains unsafe repository override arguments", {
|
|
4645
|
+
argv
|
|
4646
|
+
});
|
|
4647
|
+
}
|
|
4648
|
+
}
|
|
4649
|
+
async function execGitRaw(cwd, argv, options, behavior = {}) {
|
|
4650
|
+
validateGitArgv(argv);
|
|
4651
|
+
try {
|
|
4652
|
+
const result = await execFileAsync("git", [...argv], {
|
|
4653
|
+
cwd,
|
|
4654
|
+
encoding: "utf8",
|
|
4655
|
+
timeout: options.timeoutMs ?? DEFAULT_TIMEOUT_MS,
|
|
4656
|
+
maxBuffer: options.maxBuffer ?? DEFAULT_MAX_BUFFER,
|
|
4657
|
+
windowsHide: true
|
|
4658
|
+
});
|
|
4659
|
+
return {
|
|
4660
|
+
stdout: normalizeGitOutput(result.stdout),
|
|
4661
|
+
stderr: normalizeGitOutput(result.stderr)
|
|
4662
|
+
};
|
|
4663
|
+
} catch (error) {
|
|
4664
|
+
throw mapExecError(error, cwd, argv, behavior);
|
|
4665
|
+
}
|
|
4666
|
+
}
|
|
4667
|
+
function mapExecError(error, cwd, argv, behavior) {
|
|
4668
|
+
const execError = error;
|
|
4669
|
+
const stdout = normalizeGitOutput(execError.stdout);
|
|
4670
|
+
const stderr = normalizeGitOutput(execError.stderr);
|
|
4671
|
+
const code = execError.code;
|
|
4672
|
+
const signal = execError.signal;
|
|
4673
|
+
const message = [stderr.trim(), execError.message].filter(Boolean).join("\n");
|
|
4674
|
+
if (code === "ENOENT") {
|
|
4675
|
+
return new GitCommandError("git_not_installed", "Git executable was not found", {
|
|
4676
|
+
stdout,
|
|
4677
|
+
stderr,
|
|
4678
|
+
exitCode: code,
|
|
4679
|
+
signal,
|
|
4680
|
+
argv,
|
|
4681
|
+
cwd,
|
|
4682
|
+
cause: error
|
|
4683
|
+
});
|
|
4684
|
+
}
|
|
4685
|
+
if (execError.killed || /timed out/i.test(execError.message)) {
|
|
4686
|
+
return new GitCommandError("timeout", "Git command timed out", {
|
|
4687
|
+
stdout,
|
|
4688
|
+
stderr,
|
|
4689
|
+
exitCode: code,
|
|
4690
|
+
signal,
|
|
4691
|
+
argv,
|
|
4692
|
+
cwd,
|
|
4693
|
+
cause: error
|
|
4694
|
+
});
|
|
4695
|
+
}
|
|
4696
|
+
if (behavior.mapNotGitRepo && /not a git repository/i.test(stderr + "\n" + execError.message)) {
|
|
4697
|
+
return new GitCommandError("not_git_repo", "Workspace is not a Git repository", {
|
|
4698
|
+
stdout,
|
|
4699
|
+
stderr,
|
|
4700
|
+
exitCode: code,
|
|
4701
|
+
signal,
|
|
4702
|
+
argv,
|
|
4703
|
+
cwd,
|
|
4704
|
+
cause: error
|
|
4705
|
+
});
|
|
4706
|
+
}
|
|
4707
|
+
return new GitCommandError("git_command_failed", message || "Git command failed", {
|
|
4708
|
+
stdout,
|
|
4709
|
+
stderr,
|
|
4710
|
+
exitCode: code,
|
|
4711
|
+
signal,
|
|
4712
|
+
argv,
|
|
4713
|
+
cwd,
|
|
4714
|
+
cause: error
|
|
4715
|
+
});
|
|
4716
|
+
}
|
|
4717
|
+
|
|
4718
|
+
// src/git/git-status.ts
|
|
4719
|
+
async function getGitRepoStatus(workspace, options = {}) {
|
|
4720
|
+
const lastCheckedAt = Date.now();
|
|
4721
|
+
try {
|
|
4722
|
+
const repo = await resolveGitRepository(workspace, options);
|
|
4723
|
+
const statusOutput = await runGit(repo, ["status", "--porcelain=v2", "--branch"], options);
|
|
4724
|
+
const parsed = parsePorcelainV2Status(statusOutput.stdout);
|
|
4725
|
+
const head = await readHead(repo, options);
|
|
4726
|
+
const stashCount = await readStashCount(repo, options);
|
|
4727
|
+
return {
|
|
4728
|
+
workspace: repo.workspace,
|
|
4729
|
+
repoRoot: repo.repoRoot,
|
|
4730
|
+
isGitRepo: true,
|
|
4731
|
+
branch: parsed.branch,
|
|
4732
|
+
headCommit: head.commit,
|
|
4733
|
+
headMessage: head.message,
|
|
4734
|
+
upstream: parsed.upstream,
|
|
4735
|
+
ahead: parsed.ahead,
|
|
4736
|
+
behind: parsed.behind,
|
|
4737
|
+
staged: parsed.staged,
|
|
4738
|
+
modified: parsed.modified,
|
|
4739
|
+
untracked: parsed.untracked,
|
|
4740
|
+
deleted: parsed.deleted,
|
|
4741
|
+
renamed: parsed.renamed,
|
|
4742
|
+
hasConflicts: parsed.conflictFiles.length > 0,
|
|
4743
|
+
conflictFiles: parsed.conflictFiles,
|
|
4744
|
+
stashCount,
|
|
4745
|
+
lastCheckedAt
|
|
4746
|
+
};
|
|
4747
|
+
} catch (error) {
|
|
4748
|
+
if (error instanceof GitCommandError) {
|
|
4749
|
+
return emptyStatus(workspace, lastCheckedAt, error);
|
|
4750
|
+
}
|
|
4751
|
+
return emptyStatus(
|
|
4752
|
+
workspace,
|
|
4753
|
+
lastCheckedAt,
|
|
4754
|
+
new GitCommandError("git_command_failed", "Failed to read Git status", { cause: error })
|
|
4755
|
+
);
|
|
4756
|
+
}
|
|
4757
|
+
}
|
|
4758
|
+
function parsePorcelainV2Status(output) {
|
|
4759
|
+
const parsed = {
|
|
4760
|
+
branch: null,
|
|
4761
|
+
upstream: null,
|
|
4762
|
+
ahead: 0,
|
|
4763
|
+
behind: 0,
|
|
4764
|
+
staged: 0,
|
|
4765
|
+
modified: 0,
|
|
4766
|
+
untracked: 0,
|
|
4767
|
+
deleted: 0,
|
|
4768
|
+
renamed: 0,
|
|
4769
|
+
conflictFiles: []
|
|
4770
|
+
};
|
|
4771
|
+
for (const line of output.split("\n")) {
|
|
4772
|
+
if (!line) continue;
|
|
4773
|
+
if (line.startsWith("# branch.head ")) {
|
|
4774
|
+
const branch = line.slice("# branch.head ".length).trim();
|
|
4775
|
+
parsed.branch = branch && branch !== "(detached)" ? branch : null;
|
|
4776
|
+
continue;
|
|
4777
|
+
}
|
|
4778
|
+
if (line.startsWith("# branch.upstream ")) {
|
|
4779
|
+
parsed.upstream = line.slice("# branch.upstream ".length).trim() || null;
|
|
4780
|
+
continue;
|
|
4781
|
+
}
|
|
4782
|
+
if (line.startsWith("# branch.ab ")) {
|
|
4783
|
+
const match = line.match(/\+(-?\d+)\s+-(-?\d+)/);
|
|
4784
|
+
if (match) {
|
|
4785
|
+
parsed.ahead = Number.parseInt(match[1] ?? "0", 10) || 0;
|
|
4786
|
+
parsed.behind = Number.parseInt(match[2] ?? "0", 10) || 0;
|
|
4787
|
+
}
|
|
4788
|
+
continue;
|
|
4789
|
+
}
|
|
4790
|
+
if (line.startsWith("? ")) {
|
|
4791
|
+
parsed.untracked += 1;
|
|
4792
|
+
continue;
|
|
4793
|
+
}
|
|
4794
|
+
if (line.startsWith("u ")) {
|
|
4795
|
+
const fields = line.split(" ");
|
|
4796
|
+
const filePath = fields.slice(10).join(" ");
|
|
4797
|
+
if (filePath) parsed.conflictFiles.push(filePath);
|
|
4798
|
+
continue;
|
|
4799
|
+
}
|
|
4800
|
+
if (line.startsWith("1 ") || line.startsWith("2 ")) {
|
|
4801
|
+
const fields = line.split(" ");
|
|
4802
|
+
const xy = fields[1] ?? "..";
|
|
4803
|
+
const indexStatus = xy[0] ?? ".";
|
|
4804
|
+
const worktreeStatus = xy[1] ?? ".";
|
|
4805
|
+
if (isStagedStatus(indexStatus)) parsed.staged += 1;
|
|
4806
|
+
if (worktreeStatus === "M" || worktreeStatus === "T") parsed.modified += 1;
|
|
4807
|
+
if (indexStatus === "D" || worktreeStatus === "D") parsed.deleted += 1;
|
|
4808
|
+
if (indexStatus === "R" || worktreeStatus === "R") parsed.renamed += 1;
|
|
4809
|
+
if (xy.includes("U")) {
|
|
4810
|
+
const filePath = fields.slice(line.startsWith("2 ") ? 9 : 8).join(" ").split(" ")[0] ?? "";
|
|
4811
|
+
if (filePath) parsed.conflictFiles.push(filePath);
|
|
4812
|
+
}
|
|
4813
|
+
}
|
|
4814
|
+
}
|
|
4815
|
+
parsed.conflictFiles = Array.from(new Set(parsed.conflictFiles));
|
|
4816
|
+
return parsed;
|
|
4817
|
+
}
|
|
4818
|
+
async function readHead(repo, options) {
|
|
4819
|
+
try {
|
|
4820
|
+
const result = await runGit(repo, ["log", "-1", "--pretty=%h%x00%s"], options);
|
|
4821
|
+
const text = result.stdout.trimEnd();
|
|
4822
|
+
if (!text) return { commit: null, message: null };
|
|
4823
|
+
const [commit, ...messageParts] = text.split("\0");
|
|
4824
|
+
return {
|
|
4825
|
+
commit: commit || null,
|
|
4826
|
+
message: messageParts.join("\0") || null
|
|
4827
|
+
};
|
|
4828
|
+
} catch {
|
|
4829
|
+
return { commit: null, message: null };
|
|
4830
|
+
}
|
|
4831
|
+
}
|
|
4832
|
+
async function readStashCount(repo, options) {
|
|
4833
|
+
try {
|
|
4834
|
+
const result = await runGit(repo, ["stash", "list", "--format=%gd"], options);
|
|
4835
|
+
return result.stdout.split("\n").filter((line) => line.trim().length > 0).length;
|
|
4836
|
+
} catch {
|
|
4837
|
+
return 0;
|
|
4838
|
+
}
|
|
4839
|
+
}
|
|
4840
|
+
function isStagedStatus(status) {
|
|
4841
|
+
return status !== "." && status !== "?" && status !== "U";
|
|
4842
|
+
}
|
|
4843
|
+
function emptyStatus(workspace, lastCheckedAt, error) {
|
|
4844
|
+
return {
|
|
4845
|
+
workspace,
|
|
4846
|
+
repoRoot: null,
|
|
4847
|
+
isGitRepo: false,
|
|
4848
|
+
branch: null,
|
|
4849
|
+
headCommit: null,
|
|
4850
|
+
headMessage: null,
|
|
4851
|
+
upstream: null,
|
|
4852
|
+
ahead: 0,
|
|
4853
|
+
behind: 0,
|
|
4854
|
+
staged: 0,
|
|
4855
|
+
modified: 0,
|
|
4856
|
+
untracked: 0,
|
|
4857
|
+
deleted: 0,
|
|
4858
|
+
renamed: 0,
|
|
4859
|
+
hasConflicts: false,
|
|
4860
|
+
conflictFiles: [],
|
|
4861
|
+
stashCount: 0,
|
|
4862
|
+
lastCheckedAt,
|
|
4863
|
+
error: error.stderr || error.message,
|
|
4864
|
+
reason: error.reason
|
|
4865
|
+
};
|
|
4866
|
+
}
|
|
4867
|
+
|
|
4868
|
+
// src/git/git-diff.ts
|
|
4869
|
+
import { readFile, realpath as realpath2 } from "fs/promises";
|
|
4870
|
+
import * as path2 from "path";
|
|
4871
|
+
var DEFAULT_MAX_FILES = 200;
|
|
4872
|
+
var DEFAULT_MAX_BYTES = 2e5;
|
|
4873
|
+
async function getGitDiffSummary(workspace, options = {}) {
|
|
4874
|
+
const lastCheckedAt = Date.now();
|
|
4875
|
+
try {
|
|
4876
|
+
const repo = await resolveGitRepository(workspace, options);
|
|
4877
|
+
const repoRoot = repo.repoRoot;
|
|
4878
|
+
const [unstagedNameStatus, unstagedNumstat, stagedNameStatus, stagedNumstat, untracked] = await Promise.all([
|
|
4879
|
+
runGit(repo, ["diff", "--no-ext-diff", "--name-status"], { ...options, cwd: repoRoot }),
|
|
4880
|
+
runGit(repo, ["diff", "--no-ext-diff", "--numstat"], { ...options, cwd: repoRoot }),
|
|
4881
|
+
runGit(repo, ["diff", "--cached", "--no-ext-diff", "--name-status"], { ...options, cwd: repoRoot }),
|
|
4882
|
+
runGit(repo, ["diff", "--cached", "--no-ext-diff", "--numstat"], { ...options, cwd: repoRoot }),
|
|
4883
|
+
runGit(repo, ["ls-files", "--others", "--exclude-standard"], { ...options, cwd: repoRoot })
|
|
4884
|
+
]);
|
|
4885
|
+
const outputBytes = byteLength(
|
|
4886
|
+
unstagedNameStatus.stdout + unstagedNumstat.stdout + stagedNameStatus.stdout + stagedNumstat.stdout + untracked.stdout
|
|
4887
|
+
);
|
|
4888
|
+
const changes = [
|
|
4889
|
+
...combineDiffEntries(unstagedNameStatus.stdout, unstagedNumstat.stdout, false),
|
|
4890
|
+
...combineDiffEntries(stagedNameStatus.stdout, stagedNumstat.stdout, true),
|
|
4891
|
+
...parseUntrackedFiles(untracked.stdout)
|
|
4892
|
+
];
|
|
4893
|
+
const maxFiles = normalizePositiveInteger(options.maxFiles, DEFAULT_MAX_FILES);
|
|
4894
|
+
const maxBytes = normalizePositiveInteger(options.maxBytes, DEFAULT_MAX_BYTES);
|
|
4895
|
+
const files = changes.slice(0, maxFiles);
|
|
4896
|
+
const truncated = changes.length > files.length || outputBytes > maxBytes;
|
|
4897
|
+
return {
|
|
4898
|
+
workspace: repo.workspace,
|
|
4899
|
+
repoRoot,
|
|
4900
|
+
isGitRepo: true,
|
|
4901
|
+
files,
|
|
4902
|
+
totalInsertions: files.reduce((sum, file) => sum + file.insertions, 0),
|
|
4903
|
+
totalDeletions: files.reduce((sum, file) => sum + file.deletions, 0),
|
|
4904
|
+
truncated,
|
|
4905
|
+
lastCheckedAt
|
|
4906
|
+
};
|
|
4907
|
+
} catch (error) {
|
|
4908
|
+
const gitError = error instanceof GitCommandError ? error : new GitCommandError("git_command_failed", "Failed to read Git diff summary", { cause: error });
|
|
4909
|
+
return {
|
|
4910
|
+
workspace,
|
|
4911
|
+
repoRoot: null,
|
|
4912
|
+
isGitRepo: false,
|
|
4913
|
+
files: [],
|
|
4914
|
+
totalInsertions: 0,
|
|
4915
|
+
totalDeletions: 0,
|
|
4916
|
+
truncated: false,
|
|
4917
|
+
lastCheckedAt,
|
|
4918
|
+
error: gitError.stderr || gitError.message,
|
|
4919
|
+
reason: gitError.reason
|
|
4920
|
+
};
|
|
4921
|
+
}
|
|
4922
|
+
}
|
|
4923
|
+
async function getGitFileDiff(workspace, filePath, options = {}) {
|
|
4924
|
+
const lastCheckedAt = Date.now();
|
|
4925
|
+
const repo = await resolveGitRepository(workspace, options);
|
|
4926
|
+
const repoRoot = repo.repoRoot;
|
|
4927
|
+
const selected = await resolveRepoFilePath(repoRoot, filePath);
|
|
4928
|
+
const maxBytes = normalizePositiveInteger(options.maxBytes, DEFAULT_MAX_BYTES);
|
|
4929
|
+
const [unstaged, staged] = await Promise.all([
|
|
4930
|
+
runGit(repo, ["diff", "--no-ext-diff", "--", selected.relativePath], { ...options, cwd: repoRoot }),
|
|
4931
|
+
runGit(repo, ["diff", "--cached", "--no-ext-diff", "--", selected.relativePath], { ...options, cwd: repoRoot })
|
|
4932
|
+
]);
|
|
4933
|
+
let diff = [unstaged.stdout, staged.stdout].filter((part) => part.length > 0).join("\n");
|
|
4934
|
+
if (!diff) {
|
|
4935
|
+
const untracked = await runGit(repo, ["ls-files", "--others", "--exclude-standard", "--", selected.relativePath], {
|
|
4936
|
+
...options,
|
|
4937
|
+
cwd: repoRoot
|
|
4938
|
+
});
|
|
4939
|
+
const untrackedFiles = untracked.stdout.split("\n").filter(Boolean);
|
|
4940
|
+
if (untrackedFiles.includes(selected.relativePath)) {
|
|
4941
|
+
diff = await buildUntrackedDiff(selected.absolutePath, selected.relativePath, maxBytes + 1);
|
|
4942
|
+
}
|
|
4943
|
+
}
|
|
4944
|
+
const bounded = truncateText(diff, maxBytes);
|
|
4945
|
+
return {
|
|
4946
|
+
workspace: repo.workspace,
|
|
4947
|
+
repoRoot,
|
|
4948
|
+
isGitRepo: true,
|
|
4949
|
+
path: selected.relativePath,
|
|
4950
|
+
diff: bounded.text,
|
|
4951
|
+
truncated: bounded.truncated,
|
|
4952
|
+
lastCheckedAt
|
|
4953
|
+
};
|
|
4954
|
+
}
|
|
4955
|
+
function combineDiffEntries(nameStatusOutput, numstatOutput, staged) {
|
|
4956
|
+
const statusEntries = parseNameStatus(nameStatusOutput);
|
|
4957
|
+
const numstatEntries = parseNumstat(numstatOutput);
|
|
4958
|
+
return statusEntries.map((entry, index) => {
|
|
4959
|
+
const stats = numstatEntries[index];
|
|
4960
|
+
return {
|
|
4961
|
+
path: entry.path,
|
|
4962
|
+
oldPath: entry.oldPath,
|
|
4963
|
+
status: entry.status,
|
|
4964
|
+
staged,
|
|
4965
|
+
insertions: stats?.insertions ?? 0,
|
|
4966
|
+
deletions: stats?.deletions ?? 0,
|
|
4967
|
+
binary: stats?.binary || void 0
|
|
4968
|
+
};
|
|
4969
|
+
});
|
|
4970
|
+
}
|
|
4971
|
+
function parseNameStatus(output) {
|
|
4972
|
+
return output.split("\n").filter(Boolean).map((line) => {
|
|
4973
|
+
const fields = line.split(" ");
|
|
4974
|
+
const code = fields[0] ?? "";
|
|
4975
|
+
const statusLetter = code[0] ?? "M";
|
|
4976
|
+
if (statusLetter === "R") {
|
|
4977
|
+
return {
|
|
4978
|
+
oldPath: fields[1] ?? "",
|
|
4979
|
+
path: fields[2] ?? fields[1] ?? "",
|
|
4980
|
+
status: "renamed"
|
|
4981
|
+
};
|
|
4982
|
+
}
|
|
4983
|
+
if (statusLetter === "C") {
|
|
4984
|
+
return {
|
|
4985
|
+
oldPath: fields[1] ?? "",
|
|
4986
|
+
path: fields[2] ?? fields[1] ?? "",
|
|
4987
|
+
status: "copied"
|
|
4988
|
+
};
|
|
4989
|
+
}
|
|
4990
|
+
return {
|
|
4991
|
+
path: fields[1] ?? "",
|
|
4992
|
+
status: mapNameStatus(statusLetter)
|
|
4993
|
+
};
|
|
4994
|
+
}).filter((entry) => entry.path.length > 0);
|
|
4995
|
+
}
|
|
4996
|
+
function parseNumstat(output) {
|
|
4997
|
+
return output.split("\n").filter(Boolean).map((line) => {
|
|
4998
|
+
const fields = line.split(" ");
|
|
4999
|
+
const insertionsText = fields[0] ?? "0";
|
|
5000
|
+
const deletionsText = fields[1] ?? "0";
|
|
5001
|
+
const binary = insertionsText === "-" || deletionsText === "-";
|
|
5002
|
+
return {
|
|
5003
|
+
path: fields.slice(2).join(" "),
|
|
5004
|
+
insertions: binary ? 0 : Number.parseInt(insertionsText, 10) || 0,
|
|
5005
|
+
deletions: binary ? 0 : Number.parseInt(deletionsText, 10) || 0,
|
|
5006
|
+
binary
|
|
5007
|
+
};
|
|
5008
|
+
});
|
|
5009
|
+
}
|
|
5010
|
+
function parseUntrackedFiles(output) {
|
|
5011
|
+
return output.split("\n").filter(Boolean).map((filePath) => ({
|
|
5012
|
+
path: filePath,
|
|
5013
|
+
status: "untracked",
|
|
5014
|
+
staged: false,
|
|
5015
|
+
insertions: 0,
|
|
5016
|
+
deletions: 0
|
|
5017
|
+
}));
|
|
5018
|
+
}
|
|
5019
|
+
function mapNameStatus(status) {
|
|
5020
|
+
switch (status) {
|
|
5021
|
+
case "A":
|
|
5022
|
+
return "added";
|
|
5023
|
+
case "D":
|
|
5024
|
+
return "deleted";
|
|
5025
|
+
case "R":
|
|
5026
|
+
return "renamed";
|
|
5027
|
+
case "C":
|
|
5028
|
+
return "copied";
|
|
5029
|
+
case "U":
|
|
5030
|
+
return "conflict";
|
|
5031
|
+
case "M":
|
|
5032
|
+
case "T":
|
|
5033
|
+
default:
|
|
5034
|
+
return "modified";
|
|
5035
|
+
}
|
|
5036
|
+
}
|
|
5037
|
+
async function resolveRepoFilePath(repoRoot, filePath) {
|
|
5038
|
+
if (typeof filePath !== "string" || filePath.length === 0 || filePath.includes("\0")) {
|
|
5039
|
+
throw new GitCommandError("invalid_args", "File path must be a non-empty path");
|
|
5040
|
+
}
|
|
5041
|
+
const canonicalRepoRoot = await realpath2(repoRoot).catch(() => path2.resolve(repoRoot));
|
|
5042
|
+
const absolutePath = path2.isAbsolute(filePath) ? path2.resolve(filePath) : path2.resolve(repoRoot, filePath);
|
|
5043
|
+
const checkPath = await realpath2(absolutePath).catch(() => absolutePath);
|
|
5044
|
+
const relativeBase = isPathInside(canonicalRepoRoot, checkPath) ? canonicalRepoRoot : path2.resolve(repoRoot);
|
|
5045
|
+
if (!isPathInside(canonicalRepoRoot, checkPath) && !isPathInside(repoRoot, absolutePath)) {
|
|
5046
|
+
throw new GitCommandError("path_outside_repo", "Selected file path is outside the repository root", {
|
|
5047
|
+
cwd: repoRoot
|
|
5048
|
+
});
|
|
5049
|
+
}
|
|
5050
|
+
const relativePath = path2.relative(relativeBase, checkPath).split(path2.sep).join("/");
|
|
5051
|
+
if (!relativePath || relativePath.startsWith("..") || path2.isAbsolute(relativePath)) {
|
|
5052
|
+
throw new GitCommandError("path_outside_repo", "Selected file path is outside the repository root", {
|
|
5053
|
+
cwd: repoRoot
|
|
5054
|
+
});
|
|
5055
|
+
}
|
|
5056
|
+
return { absolutePath, relativePath };
|
|
5057
|
+
}
|
|
5058
|
+
async function buildUntrackedDiff(absolutePath, relativePath, readLimit) {
|
|
5059
|
+
const content = await readFile(absolutePath, "utf8");
|
|
5060
|
+
const limitedContent = content.length > readLimit ? content.slice(0, readLimit) : content;
|
|
5061
|
+
const lines = limitedContent.length > 0 ? limitedContent.split("\n") : [];
|
|
5062
|
+
const plusLines = lines.filter((line, index) => index < lines.length - 1 || line.length > 0).map((line) => `+${line}`).join("\n");
|
|
5063
|
+
const lineCount = plusLines ? plusLines.split("\n").length : 0;
|
|
5064
|
+
return [
|
|
5065
|
+
`diff --git a/${relativePath} b/${relativePath}`,
|
|
5066
|
+
"new file mode 100644",
|
|
5067
|
+
"index 0000000..0000000",
|
|
5068
|
+
"--- /dev/null",
|
|
5069
|
+
`+++ b/${relativePath}`,
|
|
5070
|
+
`@@ -0,0 +1,${lineCount} @@`,
|
|
5071
|
+
plusLines
|
|
5072
|
+
].filter((line) => line.length > 0).join("\n");
|
|
5073
|
+
}
|
|
5074
|
+
function truncateText(text, maxBytes) {
|
|
5075
|
+
if (byteLength(text) <= maxBytes) return { text, truncated: false };
|
|
5076
|
+
return { text: Buffer.from(text, "utf8").subarray(0, maxBytes).toString("utf8"), truncated: true };
|
|
5077
|
+
}
|
|
5078
|
+
function byteLength(text) {
|
|
5079
|
+
return Buffer.byteLength(text, "utf8");
|
|
5080
|
+
}
|
|
5081
|
+
function normalizePositiveInteger(value, fallback) {
|
|
5082
|
+
if (!Number.isFinite(value) || value == null || value <= 0) return fallback;
|
|
5083
|
+
return Math.floor(value);
|
|
5084
|
+
}
|
|
5085
|
+
|
|
5086
|
+
// src/git/git-summary.ts
|
|
5087
|
+
function countStatusChangedFiles(status) {
|
|
5088
|
+
const conflictCount = status.conflictFiles.length > 0 ? status.conflictFiles.length : status.hasConflicts ? 1 : 0;
|
|
5089
|
+
return status.staged + status.modified + status.untracked + status.deleted + status.renamed + conflictCount;
|
|
5090
|
+
}
|
|
5091
|
+
function createGitCompactSummary(status, diffSummary) {
|
|
5092
|
+
const statusChangedFiles = countStatusChangedFiles(status);
|
|
5093
|
+
const diffChangedFiles = diffSummary?.files.length ?? 0;
|
|
5094
|
+
const changedFiles = Math.max(statusChangedFiles, diffChangedFiles);
|
|
5095
|
+
const conflictCount = status.conflictFiles.length > 0 ? status.conflictFiles.length : status.hasConflicts ? 1 : 0;
|
|
5096
|
+
return {
|
|
5097
|
+
isGitRepo: status.isGitRepo,
|
|
5098
|
+
repoRoot: status.repoRoot,
|
|
5099
|
+
branch: status.branch,
|
|
5100
|
+
dirty: status.staged > 0 || status.modified > 0 || status.untracked > 0 || status.deleted > 0 || status.renamed > 0 || conflictCount > 0 || changedFiles > 0,
|
|
5101
|
+
changedFiles,
|
|
5102
|
+
ahead: status.ahead,
|
|
5103
|
+
behind: status.behind,
|
|
5104
|
+
hasConflicts: status.hasConflicts || conflictCount > 0,
|
|
5105
|
+
lastCheckedAt: Math.max(status.lastCheckedAt, diffSummary?.lastCheckedAt ?? status.lastCheckedAt),
|
|
5106
|
+
error: status.error ?? diffSummary?.error,
|
|
5107
|
+
reason: status.reason ?? diffSummary?.reason
|
|
5108
|
+
};
|
|
5109
|
+
}
|
|
5110
|
+
var summarizeGitStatus = createGitCompactSummary;
|
|
5111
|
+
|
|
5112
|
+
// src/git/git-snapshot-store.ts
|
|
5113
|
+
function normalizeCapacity(capacity) {
|
|
5114
|
+
return Math.max(1, Math.floor(capacity ?? 100));
|
|
5115
|
+
}
|
|
5116
|
+
function createEmptyDiffSummary(status) {
|
|
5117
|
+
return {
|
|
5118
|
+
workspace: status.workspace,
|
|
5119
|
+
repoRoot: status.repoRoot,
|
|
5120
|
+
isGitRepo: status.isGitRepo,
|
|
5121
|
+
files: [],
|
|
5122
|
+
totalInsertions: 0,
|
|
5123
|
+
totalDeletions: 0,
|
|
5124
|
+
truncated: false,
|
|
5125
|
+
lastCheckedAt: status.lastCheckedAt,
|
|
5126
|
+
error: status.error,
|
|
5127
|
+
reason: status.reason
|
|
5128
|
+
};
|
|
5129
|
+
}
|
|
5130
|
+
function changedFileKey(file) {
|
|
5131
|
+
return `${file.oldPath ?? ""}\0${file.path}`;
|
|
5132
|
+
}
|
|
5133
|
+
function uniqueSorted(values) {
|
|
5134
|
+
return Array.from(new Set(Array.from(values).filter(Boolean))).sort((a, b) => a.localeCompare(b));
|
|
5135
|
+
}
|
|
5136
|
+
function plural(count, singular, pluralText = `${singular}s`) {
|
|
5137
|
+
return count === 1 ? singular : pluralText;
|
|
5138
|
+
}
|
|
5139
|
+
function compareGitSnapshots(before, after) {
|
|
5140
|
+
const beforeFileKeys = new Set(before.diffSummary.files.map(changedFileKey));
|
|
5141
|
+
const changedAfterFiles = after.diffSummary.files.filter((file) => !beforeFileKeys.has(changedFileKey(file)));
|
|
5142
|
+
const addedFiles = [];
|
|
5143
|
+
const modifiedFiles = [];
|
|
5144
|
+
const deletedFiles = [];
|
|
5145
|
+
const renamedFiles = [];
|
|
5146
|
+
const untrackedFiles = [];
|
|
5147
|
+
const conflictFilesFromDiff = [];
|
|
5148
|
+
let totalInsertions = 0;
|
|
5149
|
+
let totalDeletions = 0;
|
|
5150
|
+
for (const file of changedAfterFiles) {
|
|
5151
|
+
totalInsertions += file.insertions;
|
|
5152
|
+
totalDeletions += file.deletions;
|
|
5153
|
+
switch (file.status) {
|
|
5154
|
+
case "added":
|
|
5155
|
+
case "copied":
|
|
5156
|
+
addedFiles.push(file.path);
|
|
5157
|
+
break;
|
|
5158
|
+
case "modified":
|
|
5159
|
+
modifiedFiles.push(file.path);
|
|
5160
|
+
break;
|
|
5161
|
+
case "deleted":
|
|
5162
|
+
deletedFiles.push(file.path);
|
|
5163
|
+
break;
|
|
5164
|
+
case "renamed":
|
|
5165
|
+
renamedFiles.push({ oldPath: file.oldPath ?? file.path, path: file.path });
|
|
5166
|
+
break;
|
|
5167
|
+
case "untracked":
|
|
5168
|
+
untrackedFiles.push(file.path);
|
|
5169
|
+
break;
|
|
5170
|
+
case "conflict":
|
|
5171
|
+
conflictFilesFromDiff.push(file.path);
|
|
5172
|
+
break;
|
|
5173
|
+
}
|
|
5174
|
+
}
|
|
5175
|
+
renamedFiles.sort((a, b) => `${a.oldPath}\0${a.path}`.localeCompare(`${b.oldPath}\0${b.path}`));
|
|
5176
|
+
const conflictFiles = uniqueSorted([...after.status.conflictFiles, ...conflictFilesFromDiff]);
|
|
5177
|
+
const changedFiles = changedAfterFiles.length;
|
|
5178
|
+
const hasConflicts = after.status.hasConflicts || conflictFiles.length > 0;
|
|
5179
|
+
const summaryParts = [];
|
|
5180
|
+
if (changedFiles > 0) summaryParts.push(`${changedFiles} ${plural(changedFiles, "file")} changed`);
|
|
5181
|
+
if (addedFiles.length > 0) summaryParts.push(`${addedFiles.length} added`);
|
|
5182
|
+
if (modifiedFiles.length > 0) summaryParts.push(`${modifiedFiles.length} modified`);
|
|
5183
|
+
if (deletedFiles.length > 0) summaryParts.push(`${deletedFiles.length} deleted`);
|
|
5184
|
+
if (renamedFiles.length > 0) summaryParts.push(`${renamedFiles.length} renamed`);
|
|
5185
|
+
if (untrackedFiles.length > 0) summaryParts.push(`${untrackedFiles.length} untracked`);
|
|
5186
|
+
if (hasConflicts) summaryParts.push(`${conflictFiles.length || 1} ${plural(conflictFiles.length || 1, "conflict")}`);
|
|
5187
|
+
return {
|
|
5188
|
+
beforeSnapshotId: before.id,
|
|
5189
|
+
afterSnapshotId: after.id,
|
|
5190
|
+
workspace: after.workspace,
|
|
5191
|
+
repoRoot: after.repoRoot,
|
|
5192
|
+
changedFiles,
|
|
5193
|
+
addedFiles: uniqueSorted(addedFiles),
|
|
5194
|
+
modifiedFiles: uniqueSorted(modifiedFiles),
|
|
5195
|
+
deletedFiles: uniqueSorted(deletedFiles),
|
|
5196
|
+
renamedFiles,
|
|
5197
|
+
untrackedFiles: uniqueSorted(untrackedFiles),
|
|
5198
|
+
conflictFiles,
|
|
5199
|
+
totalInsertions,
|
|
5200
|
+
totalDeletions,
|
|
5201
|
+
hasConflicts,
|
|
5202
|
+
currentStatus: after.status,
|
|
5203
|
+
summaryText: summaryParts.length > 0 ? summaryParts.join(", ") : "No file-set changes between snapshots."
|
|
5204
|
+
};
|
|
5205
|
+
}
|
|
5206
|
+
var InMemoryGitSnapshotStore = class {
|
|
5207
|
+
snapshots = /* @__PURE__ */ new Map();
|
|
5208
|
+
order = [];
|
|
5209
|
+
capacity;
|
|
5210
|
+
now;
|
|
5211
|
+
idPrefix;
|
|
5212
|
+
getStatusProvider;
|
|
5213
|
+
getDiffSummaryProvider;
|
|
5214
|
+
counter = 0;
|
|
5215
|
+
constructor(options = {}) {
|
|
5216
|
+
this.capacity = normalizeCapacity(options.capacity);
|
|
5217
|
+
this.now = options.now ?? Date.now;
|
|
5218
|
+
this.idPrefix = options.idPrefix ?? "git-snapshot";
|
|
5219
|
+
this.getStatusProvider = options.getStatus;
|
|
5220
|
+
this.getDiffSummaryProvider = options.getDiffSummary;
|
|
5221
|
+
}
|
|
5222
|
+
async create(input) {
|
|
5223
|
+
const getStatus = input.getStatus ?? this.getStatusProvider;
|
|
5224
|
+
if (!getStatus) {
|
|
5225
|
+
throw new Error("GitSnapshotStore requires an injected getStatus provider");
|
|
5226
|
+
}
|
|
5227
|
+
const status = await getStatus(input.workspace);
|
|
5228
|
+
const getDiffSummary = input.getDiffSummary ?? this.getDiffSummaryProvider;
|
|
5229
|
+
const diffSummary = getDiffSummary ? await getDiffSummary(input.workspace, status) : createEmptyDiffSummary(status);
|
|
5230
|
+
const createdAt = this.now();
|
|
5231
|
+
const id = `${this.idPrefix}-${createdAt}-${++this.counter}`;
|
|
5232
|
+
const snapshot = {
|
|
5233
|
+
id,
|
|
5234
|
+
workspace: input.workspace,
|
|
5235
|
+
repoRoot: status.repoRoot ?? input.workspace,
|
|
5236
|
+
sessionId: input.sessionId,
|
|
5237
|
+
turnId: input.turnId,
|
|
5238
|
+
reason: input.reason,
|
|
5239
|
+
status,
|
|
5240
|
+
diffSummary,
|
|
5241
|
+
createdAt
|
|
5242
|
+
};
|
|
5243
|
+
this.snapshots.set(id, snapshot);
|
|
5244
|
+
this.order.push(id);
|
|
5245
|
+
this.enforceCapacity();
|
|
5246
|
+
return snapshot;
|
|
5247
|
+
}
|
|
5248
|
+
get(id) {
|
|
5249
|
+
return this.snapshots.get(id);
|
|
5250
|
+
}
|
|
5251
|
+
compare(beforeSnapshotId, afterSnapshotId) {
|
|
5252
|
+
const before = this.snapshots.get(beforeSnapshotId);
|
|
5253
|
+
if (!before) throw new Error(`Unknown before snapshot: ${beforeSnapshotId}`);
|
|
5254
|
+
const after = this.snapshots.get(afterSnapshotId);
|
|
5255
|
+
if (!after) throw new Error(`Unknown after snapshot: ${afterSnapshotId}`);
|
|
5256
|
+
return compareGitSnapshots(before, after);
|
|
5257
|
+
}
|
|
5258
|
+
list(query = {}) {
|
|
5259
|
+
const limit = Math.max(1, Math.floor(query.limit ?? this.capacity));
|
|
5260
|
+
return this.order.map((id) => this.snapshots.get(id)).filter((snapshot) => Boolean(snapshot)).filter((snapshot) => !query.workspace || snapshot.workspace === query.workspace).filter((snapshot) => !query.sessionId || snapshot.sessionId === query.sessionId).slice(-limit);
|
|
5261
|
+
}
|
|
5262
|
+
clear() {
|
|
5263
|
+
this.snapshots.clear();
|
|
5264
|
+
this.order.splice(0, this.order.length);
|
|
5265
|
+
}
|
|
5266
|
+
enforceCapacity() {
|
|
5267
|
+
while (this.order.length > this.capacity) {
|
|
5268
|
+
const evictedId = this.order.shift();
|
|
5269
|
+
if (evictedId) this.snapshots.delete(evictedId);
|
|
5270
|
+
}
|
|
5271
|
+
}
|
|
5272
|
+
};
|
|
5273
|
+
function createGitSnapshotStore(options = {}) {
|
|
5274
|
+
return new InMemoryGitSnapshotStore(options);
|
|
5275
|
+
}
|
|
5276
|
+
|
|
5277
|
+
// src/git/git-monitor.ts
|
|
5278
|
+
var DEFAULT_GIT_WORKSPACE_POLL_INTERVAL_MS = 5e3;
|
|
5279
|
+
var MIN_GIT_WORKSPACE_POLL_INTERVAL_MS = 1e3;
|
|
5280
|
+
function defaultStatusProvider(workspace) {
|
|
5281
|
+
return getGitRepoStatus(workspace);
|
|
5282
|
+
}
|
|
5283
|
+
function defaultDiffSummaryProvider(workspace) {
|
|
5284
|
+
return getGitDiffSummary(workspace);
|
|
5285
|
+
}
|
|
5286
|
+
function normalizeIntervalMs(value, defaultIntervalMs, minIntervalMs) {
|
|
5287
|
+
const requested = Number.isFinite(value) ? Math.floor(value) : defaultIntervalMs;
|
|
5288
|
+
return Math.max(minIntervalMs, requested > 0 ? requested : defaultIntervalMs);
|
|
5289
|
+
}
|
|
5290
|
+
function normalizeGitWorkspaceSubscriptionParams(params, options = {}) {
|
|
5291
|
+
const minIntervalMs = Math.max(1, Math.floor(options.minIntervalMs ?? MIN_GIT_WORKSPACE_POLL_INTERVAL_MS));
|
|
5292
|
+
const defaultIntervalMs = Math.max(minIntervalMs, Math.floor(options.defaultIntervalMs ?? DEFAULT_GIT_WORKSPACE_POLL_INTERVAL_MS));
|
|
5293
|
+
return {
|
|
5294
|
+
workspace: params.workspace,
|
|
5295
|
+
includeDiffSummary: Boolean(params.includeDiffSummary),
|
|
5296
|
+
intervalMs: normalizeIntervalMs(params.intervalMs, defaultIntervalMs, minIntervalMs)
|
|
5297
|
+
};
|
|
5298
|
+
}
|
|
5299
|
+
var GitWorkspaceMonitor = class {
|
|
5300
|
+
getStatusProvider;
|
|
5301
|
+
getDiffSummaryProvider;
|
|
5302
|
+
now;
|
|
5303
|
+
minIntervalMs;
|
|
5304
|
+
defaultIntervalMs;
|
|
5305
|
+
keyPrefix;
|
|
5306
|
+
cache = /* @__PURE__ */ new Map();
|
|
5307
|
+
listeners = /* @__PURE__ */ new Set();
|
|
5308
|
+
seq = 0;
|
|
5309
|
+
constructor(options = {}) {
|
|
5310
|
+
this.getStatusProvider = options.getStatus ?? defaultStatusProvider;
|
|
5311
|
+
this.getDiffSummaryProvider = options.getDiffSummary ?? defaultDiffSummaryProvider;
|
|
5312
|
+
this.now = options.now ?? Date.now;
|
|
5313
|
+
this.minIntervalMs = Math.max(1, Math.floor(options.minIntervalMs ?? MIN_GIT_WORKSPACE_POLL_INTERVAL_MS));
|
|
5314
|
+
this.defaultIntervalMs = Math.max(
|
|
5315
|
+
this.minIntervalMs,
|
|
5316
|
+
Math.floor(options.defaultIntervalMs ?? DEFAULT_GIT_WORKSPACE_POLL_INTERVAL_MS)
|
|
5317
|
+
);
|
|
5318
|
+
this.keyPrefix = options.keyPrefix ?? "git";
|
|
5319
|
+
}
|
|
5320
|
+
async refresh(params) {
|
|
5321
|
+
const normalized = this.normalize(typeof params === "string" ? { workspace: params } : params);
|
|
5322
|
+
const status = await this.getStatusProvider(normalized.workspace);
|
|
5323
|
+
const diffSummary = normalized.includeDiffSummary ? await this.getDiffSummaryProvider(normalized.workspace, status) : void 0;
|
|
5324
|
+
const compactSummary = createGitCompactSummary(status, diffSummary);
|
|
5325
|
+
const timestamp = this.now();
|
|
5326
|
+
const seq = ++this.seq;
|
|
5327
|
+
const key = this.keyForWorkspace(normalized.workspace);
|
|
5328
|
+
const update = {
|
|
5329
|
+
topic: "workspace.git",
|
|
5330
|
+
key,
|
|
5331
|
+
workspace: normalized.workspace,
|
|
5332
|
+
status,
|
|
5333
|
+
diffSummary,
|
|
5334
|
+
seq,
|
|
5335
|
+
timestamp
|
|
5336
|
+
};
|
|
5337
|
+
const cacheEntry = {
|
|
5338
|
+
key,
|
|
5339
|
+
workspace: normalized.workspace,
|
|
5340
|
+
status,
|
|
5341
|
+
diffSummary,
|
|
5342
|
+
compactSummary,
|
|
5343
|
+
seq,
|
|
5344
|
+
timestamp
|
|
5345
|
+
};
|
|
5346
|
+
this.cache.set(normalized.workspace, cacheEntry);
|
|
5347
|
+
this.emit(update, cacheEntry);
|
|
5348
|
+
return update;
|
|
5349
|
+
}
|
|
5350
|
+
poll(params) {
|
|
5351
|
+
return this.refresh(params);
|
|
5352
|
+
}
|
|
5353
|
+
getCached(workspace) {
|
|
5354
|
+
return this.cache.get(workspace);
|
|
5355
|
+
}
|
|
5356
|
+
getCompactSummary(workspace) {
|
|
5357
|
+
return this.cache.get(workspace)?.compactSummary;
|
|
5358
|
+
}
|
|
5359
|
+
onUpdate(listener) {
|
|
5360
|
+
this.listeners.add(listener);
|
|
5361
|
+
return () => {
|
|
5362
|
+
this.listeners.delete(listener);
|
|
5363
|
+
};
|
|
5364
|
+
}
|
|
5365
|
+
createSubscription(params, listener) {
|
|
5366
|
+
const normalized = this.normalize(params);
|
|
5367
|
+
const scopedListener = listener ? (update, cacheEntry) => {
|
|
5368
|
+
if (update.workspace === normalized.workspace) listener(update, cacheEntry);
|
|
5369
|
+
} : void 0;
|
|
5370
|
+
const unsubscribe = scopedListener ? this.onUpdate(scopedListener) : () => void 0;
|
|
5371
|
+
return {
|
|
5372
|
+
params: normalized,
|
|
5373
|
+
refresh: () => this.refresh(normalized),
|
|
5374
|
+
getCached: () => this.getCached(normalized.workspace),
|
|
5375
|
+
dispose: unsubscribe
|
|
5376
|
+
};
|
|
5377
|
+
}
|
|
5378
|
+
normalize(params) {
|
|
5379
|
+
return normalizeGitWorkspaceSubscriptionParams(params, {
|
|
5380
|
+
defaultIntervalMs: this.defaultIntervalMs,
|
|
5381
|
+
minIntervalMs: this.minIntervalMs
|
|
5382
|
+
});
|
|
5383
|
+
}
|
|
5384
|
+
keyForWorkspace(workspace) {
|
|
5385
|
+
return `${this.keyPrefix}:${workspace}`;
|
|
5386
|
+
}
|
|
5387
|
+
emit(update, cacheEntry) {
|
|
5388
|
+
for (const listener of this.listeners) {
|
|
5389
|
+
listener(update, cacheEntry);
|
|
5390
|
+
}
|
|
5391
|
+
}
|
|
5392
|
+
};
|
|
5393
|
+
function createGitWorkspaceMonitor(options = {}) {
|
|
5394
|
+
return new GitWorkspaceMonitor(options);
|
|
5395
|
+
}
|
|
5396
|
+
|
|
5397
|
+
// src/git/git-commands.ts
|
|
5398
|
+
import * as path3 from "path";
|
|
5399
|
+
var GIT_COMMAND_NAMES = /* @__PURE__ */ new Set([
|
|
5400
|
+
"git_status",
|
|
5401
|
+
"git_diff_summary",
|
|
5402
|
+
"git_diff_file",
|
|
5403
|
+
"git_snapshot_create",
|
|
5404
|
+
"git_snapshot_compare",
|
|
5405
|
+
"git_log",
|
|
5406
|
+
"git_checkpoint",
|
|
5407
|
+
"git_stash_push",
|
|
5408
|
+
"git_stash_pop",
|
|
5409
|
+
"git_checkout_files"
|
|
5410
|
+
]);
|
|
5411
|
+
var MUTATING_COMMAND_NAMES = /* @__PURE__ */ new Set([
|
|
5412
|
+
"git_checkpoint",
|
|
5413
|
+
"git_stash_push",
|
|
5414
|
+
"git_stash_pop",
|
|
5415
|
+
"git_checkout_files"
|
|
5416
|
+
]);
|
|
5417
|
+
var SNAPSHOT_REASONS = /* @__PURE__ */ new Set([
|
|
5418
|
+
"session_baseline",
|
|
5419
|
+
"before_user_input_dispatch",
|
|
5420
|
+
"before_agent_work",
|
|
5421
|
+
"after_agent_work",
|
|
5422
|
+
"manual"
|
|
5423
|
+
]);
|
|
5424
|
+
var FAILURE_REASONS = /* @__PURE__ */ new Set([
|
|
5425
|
+
"not_git_repo",
|
|
5426
|
+
"git_not_installed",
|
|
5427
|
+
"timeout",
|
|
5428
|
+
"path_outside_repo",
|
|
5429
|
+
"dirty_index_required",
|
|
5430
|
+
"conflict",
|
|
5431
|
+
"invalid_args",
|
|
5432
|
+
"git_command_failed"
|
|
5433
|
+
]);
|
|
5434
|
+
function failure(reason, error) {
|
|
5435
|
+
return { success: false, reason, error };
|
|
5436
|
+
}
|
|
5437
|
+
function serviceNotImplemented(command) {
|
|
5438
|
+
return failure("invalid_args", `${command} is not implemented: daemon-core Git service is not configured`);
|
|
5439
|
+
}
|
|
5440
|
+
var defaultSnapshotStore = createGitSnapshotStore({
|
|
5441
|
+
getStatus: (workspace) => getGitRepoStatus(workspace),
|
|
5442
|
+
getDiffSummary: (workspace) => getGitDiffSummary(workspace)
|
|
5443
|
+
});
|
|
5444
|
+
function createDefaultGitCommandServices() {
|
|
5445
|
+
return {
|
|
5446
|
+
getStatus: ({ workspace }) => getGitRepoStatus(workspace),
|
|
5447
|
+
getDiffSummary: ({ workspace }) => getGitDiffSummary(workspace),
|
|
5448
|
+
getDiffFile: ({ workspace, path: filePath }) => getGitFileDiff(workspace, filePath),
|
|
5449
|
+
createSnapshot: ({ workspace, reason, sessionId, turnId }) => defaultSnapshotStore.create({
|
|
5450
|
+
workspace,
|
|
5451
|
+
reason,
|
|
5452
|
+
sessionId,
|
|
5453
|
+
turnId
|
|
5454
|
+
}),
|
|
5455
|
+
compareSnapshots: ({ beforeSnapshotId, afterSnapshotId }) => defaultSnapshotStore.compare(beforeSnapshotId, afterSnapshotId),
|
|
5456
|
+
getLog: ({ workspace, limit, path: filePath, since, until }) => getGitLog(workspace, { limit, path: filePath, since, until })
|
|
5457
|
+
};
|
|
5458
|
+
}
|
|
5459
|
+
var defaultGitCommandServices = createDefaultGitCommandServices();
|
|
5460
|
+
function validateWorkspace2(args) {
|
|
5461
|
+
if (typeof args?.workspace !== "string") {
|
|
5462
|
+
return failure("invalid_args", "workspace must be a non-empty absolute path");
|
|
5463
|
+
}
|
|
5464
|
+
const workspace = args.workspace.trim();
|
|
5465
|
+
if (!workspace || !path3.isAbsolute(workspace)) {
|
|
5466
|
+
return failure("invalid_args", "workspace must be a non-empty absolute path");
|
|
5467
|
+
}
|
|
5468
|
+
return { workspace };
|
|
5469
|
+
}
|
|
5470
|
+
function validateRepoPath(args) {
|
|
5471
|
+
if (typeof args?.path !== "string" || !args.path.trim()) {
|
|
5472
|
+
return failure("invalid_args", "path must be a non-empty repository-relative path");
|
|
5473
|
+
}
|
|
5474
|
+
return { path: args.path.trim() };
|
|
5475
|
+
}
|
|
5476
|
+
function validateSnapshotId(args, key) {
|
|
5477
|
+
if (typeof args?.[key] !== "string" || !args[key].trim()) {
|
|
5478
|
+
return failure("invalid_args", `${key} must be a non-empty string`);
|
|
5479
|
+
}
|
|
5480
|
+
return args[key].trim();
|
|
5481
|
+
}
|
|
5482
|
+
function parseSnapshotReason(args) {
|
|
5483
|
+
if (args?.reason === void 0 || args?.reason === null || args?.reason === "") {
|
|
5484
|
+
return "manual";
|
|
5485
|
+
}
|
|
5486
|
+
if (typeof args.reason !== "string" || !SNAPSHOT_REASONS.has(args.reason)) {
|
|
5487
|
+
return failure("invalid_args", "reason must be a valid GitSnapshotReason");
|
|
5488
|
+
}
|
|
5489
|
+
return args.reason;
|
|
5490
|
+
}
|
|
5491
|
+
function optionalString(value) {
|
|
5492
|
+
return typeof value === "string" && value.trim() ? value.trim() : void 0;
|
|
5493
|
+
}
|
|
5494
|
+
function optionalBoolean(value) {
|
|
5495
|
+
return typeof value === "boolean" ? value : void 0;
|
|
5496
|
+
}
|
|
5497
|
+
function boundedLogLimit(value) {
|
|
5498
|
+
if (value === void 0 || value === null || value === "") return 50;
|
|
5499
|
+
const numeric = typeof value === "number" ? value : Number(value);
|
|
5500
|
+
if (!Number.isFinite(numeric)) return 50;
|
|
5501
|
+
return Math.max(1, Math.min(200, Math.floor(numeric)));
|
|
5502
|
+
}
|
|
5503
|
+
function failureReasonFromError(error) {
|
|
5504
|
+
return typeof error?.reason === "string" && FAILURE_REASONS.has(error.reason) ? error.reason : "git_command_failed";
|
|
5505
|
+
}
|
|
5506
|
+
async function runService(fn) {
|
|
5507
|
+
try {
|
|
5508
|
+
return await fn();
|
|
5509
|
+
} catch (error) {
|
|
5510
|
+
return failure(failureReasonFromError(error), error?.message || "Git command failed");
|
|
5511
|
+
}
|
|
5512
|
+
}
|
|
5513
|
+
function isGitCommandName(command) {
|
|
5514
|
+
return GIT_COMMAND_NAMES.has(command);
|
|
5515
|
+
}
|
|
5516
|
+
async function handleGitCommand(command, args, services = defaultGitCommandServices) {
|
|
5517
|
+
if (!isGitCommandName(command)) {
|
|
5518
|
+
return failure("invalid_args", `Unknown Git command: ${command}`);
|
|
5519
|
+
}
|
|
5520
|
+
if (MUTATING_COMMAND_NAMES.has(command)) {
|
|
5521
|
+
return failure("invalid_args", `${command} is not implemented in daemon-core read-only Git routing`);
|
|
5522
|
+
}
|
|
5523
|
+
const workspaceResult = validateWorkspace2(args);
|
|
5524
|
+
if ("success" in workspaceResult) return workspaceResult;
|
|
5525
|
+
const { workspace } = workspaceResult;
|
|
5526
|
+
switch (command) {
|
|
5527
|
+
case "git_status": {
|
|
5528
|
+
if (!services.getStatus) return serviceNotImplemented(command);
|
|
5529
|
+
const status = await runService(() => services.getStatus({ workspace }));
|
|
5530
|
+
return "success" in status ? status : { success: true, status };
|
|
5531
|
+
}
|
|
5532
|
+
case "git_diff_summary": {
|
|
5533
|
+
if (!services.getDiffSummary) return serviceNotImplemented(command);
|
|
5534
|
+
const diffSummary = await runService(() => services.getDiffSummary({ workspace, staged: optionalBoolean(args?.staged) }));
|
|
5535
|
+
return "success" in diffSummary ? diffSummary : { success: true, diffSummary };
|
|
5536
|
+
}
|
|
5537
|
+
case "git_diff_file": {
|
|
5538
|
+
if (!services.getDiffFile) return serviceNotImplemented(command);
|
|
5539
|
+
const pathResult = validateRepoPath(args);
|
|
5540
|
+
if (typeof pathResult !== "object" || "success" in pathResult) return pathResult;
|
|
5541
|
+
const diff = await runService(() => services.getDiffFile({
|
|
5542
|
+
workspace,
|
|
5543
|
+
path: pathResult.path,
|
|
5544
|
+
staged: optionalBoolean(args?.staged)
|
|
5545
|
+
}));
|
|
5546
|
+
return "success" in diff ? diff : { success: true, diff };
|
|
5547
|
+
}
|
|
5548
|
+
case "git_snapshot_create": {
|
|
5549
|
+
if (!services.createSnapshot) return serviceNotImplemented(command);
|
|
5550
|
+
const reason = parseSnapshotReason(args);
|
|
5551
|
+
if (typeof reason !== "string") return reason;
|
|
5552
|
+
const snapshot = await runService(() => services.createSnapshot({
|
|
5553
|
+
workspace,
|
|
5554
|
+
reason,
|
|
5555
|
+
sessionId: optionalString(args?.sessionId),
|
|
5556
|
+
turnId: optionalString(args?.turnId)
|
|
5557
|
+
}));
|
|
5558
|
+
return "success" in snapshot ? snapshot : { success: true, snapshot };
|
|
5559
|
+
}
|
|
5560
|
+
case "git_snapshot_compare": {
|
|
5561
|
+
if (!services.compareSnapshots) return serviceNotImplemented(command);
|
|
5562
|
+
const beforeSnapshotId = validateSnapshotId(args, "beforeSnapshotId");
|
|
5563
|
+
if (typeof beforeSnapshotId !== "string") return beforeSnapshotId;
|
|
5564
|
+
const afterSnapshotId = validateSnapshotId(args, "afterSnapshotId");
|
|
5565
|
+
if (typeof afterSnapshotId !== "string") return afterSnapshotId;
|
|
5566
|
+
const compare = await runService(() => services.compareSnapshots({ workspace, beforeSnapshotId, afterSnapshotId }));
|
|
5567
|
+
return "success" in compare ? compare : { success: true, compare };
|
|
5568
|
+
}
|
|
5569
|
+
case "git_log": {
|
|
5570
|
+
if (!services.getLog) {
|
|
5571
|
+
return failure("invalid_args", "git_log is not implemented: bounded daemon-core Git log service is not configured");
|
|
5572
|
+
}
|
|
5573
|
+
const log = await runService(() => services.getLog({
|
|
5574
|
+
workspace,
|
|
5575
|
+
limit: boundedLogLimit(args?.limit),
|
|
5576
|
+
path: optionalString(args?.path),
|
|
5577
|
+
since: optionalString(args?.since),
|
|
5578
|
+
until: optionalString(args?.until)
|
|
5579
|
+
}));
|
|
5580
|
+
return "success" in log ? log : { success: true, log };
|
|
5581
|
+
}
|
|
5582
|
+
default:
|
|
5583
|
+
return failure("invalid_args", `Unknown Git command: ${command}`);
|
|
5584
|
+
}
|
|
5585
|
+
}
|
|
5586
|
+
function formatOptionalGitLogRangeArg(flag, value) {
|
|
5587
|
+
return value ? [`${flag}=${value}`] : [];
|
|
5588
|
+
}
|
|
5589
|
+
async function getGitLog(workspace, options) {
|
|
5590
|
+
const lastCheckedAt = Date.now();
|
|
5591
|
+
const repo = await resolveGitRepository(workspace);
|
|
5592
|
+
const repoRoot = repo.repoRoot;
|
|
5593
|
+
const boundedLimit = Math.max(1, Math.min(200, Math.floor(options.limit || 50)));
|
|
5594
|
+
const selectedPath = options.path ? validateGitLogPath(repoRoot, options.path) : void 0;
|
|
5595
|
+
const result = await runGit(
|
|
5596
|
+
repo,
|
|
5597
|
+
[
|
|
5598
|
+
"log",
|
|
5599
|
+
`--max-count=${boundedLimit}`,
|
|
5600
|
+
"--format=%H%x00%an%x00%ae%x00%at%x00%ct%x00%s",
|
|
5601
|
+
...formatOptionalGitLogRangeArg("--since", options.since),
|
|
5602
|
+
...formatOptionalGitLogRangeArg("--until", options.until),
|
|
5603
|
+
"--",
|
|
5604
|
+
...selectedPath ? [selectedPath] : []
|
|
5605
|
+
],
|
|
5606
|
+
{ cwd: repoRoot }
|
|
5607
|
+
);
|
|
5608
|
+
const entries = result.stdout.split("\n").filter((line) => line.trim().length > 0).map((line) => {
|
|
5609
|
+
const [commit = "", authorName, authorEmail, authoredAt, committedAt, ...messageParts] = line.split("\0");
|
|
5610
|
+
return {
|
|
5611
|
+
commit,
|
|
5612
|
+
message: messageParts.join("\0"),
|
|
5613
|
+
authorName: authorName || void 0,
|
|
5614
|
+
authorEmail: authorEmail || void 0,
|
|
5615
|
+
authoredAt: authoredAt ? Number.parseInt(authoredAt, 10) * 1e3 : void 0,
|
|
5616
|
+
committedAt: committedAt ? Number.parseInt(committedAt, 10) * 1e3 : void 0
|
|
5617
|
+
};
|
|
5618
|
+
}).filter((entry) => entry.commit.length > 0);
|
|
5619
|
+
return {
|
|
5620
|
+
workspace: repo.workspace,
|
|
5621
|
+
repoRoot,
|
|
5622
|
+
isGitRepo: true,
|
|
5623
|
+
entries,
|
|
5624
|
+
limit: boundedLimit,
|
|
5625
|
+
truncated: entries.length >= boundedLimit,
|
|
5626
|
+
lastCheckedAt
|
|
5627
|
+
};
|
|
5628
|
+
}
|
|
5629
|
+
function validateGitLogPath(repoRoot, filePath) {
|
|
5630
|
+
if (!filePath.trim() || filePath.includes("\0")) {
|
|
5631
|
+
throw new GitCommandError("invalid_args", "path must be a non-empty repository-relative path");
|
|
5632
|
+
}
|
|
5633
|
+
if (path3.isAbsolute(filePath)) {
|
|
5634
|
+
throw new GitCommandError("invalid_args", "path must be repository-relative");
|
|
5635
|
+
}
|
|
5636
|
+
const normalized = path3.normalize(filePath).split(path3.sep).join("/");
|
|
5637
|
+
const absolutePath = path3.resolve(repoRoot, normalized);
|
|
5638
|
+
if (!isPathInside(repoRoot, absolutePath) || normalized.startsWith("../") || normalized === "..") {
|
|
5639
|
+
throw new GitCommandError("path_outside_repo", "Git log path is outside the repository root");
|
|
5640
|
+
}
|
|
5641
|
+
return normalized;
|
|
5642
|
+
}
|
|
5643
|
+
|
|
4527
5644
|
// src/index.ts
|
|
4528
5645
|
init_config();
|
|
4529
5646
|
|
|
4530
5647
|
// src/config/workspaces.ts
|
|
4531
5648
|
import * as fs from "fs";
|
|
4532
5649
|
import * as os from "os";
|
|
4533
|
-
import * as
|
|
5650
|
+
import * as path4 from "path";
|
|
4534
5651
|
import { randomUUID as randomUUID2 } from "crypto";
|
|
4535
5652
|
var MAX_WORKSPACES = 50;
|
|
4536
5653
|
function expandPath(p) {
|
|
4537
5654
|
const t = (p || "").trim();
|
|
4538
5655
|
if (!t) return "";
|
|
4539
|
-
if (t.startsWith("~")) return
|
|
4540
|
-
return
|
|
5656
|
+
if (t.startsWith("~")) return path4.join(os.homedir(), t.slice(1).replace(/^\//, ""));
|
|
5657
|
+
return path4.resolve(t);
|
|
4541
5658
|
}
|
|
4542
5659
|
function validateWorkspacePath(absPath) {
|
|
4543
5660
|
try {
|
|
@@ -4551,7 +5668,7 @@ function validateWorkspacePath(absPath) {
|
|
|
4551
5668
|
}
|
|
4552
5669
|
}
|
|
4553
5670
|
function defaultWorkspaceLabel(absPath) {
|
|
4554
|
-
const base =
|
|
5671
|
+
const base = path4.basename(absPath) || absPath;
|
|
4555
5672
|
return base;
|
|
4556
5673
|
}
|
|
4557
5674
|
function getDefaultWorkspacePath(config) {
|
|
@@ -4642,9 +5759,9 @@ function resolveIdeLaunchWorkspace(args, config) {
|
|
|
4642
5759
|
return getDefaultWorkspacePath(config) || void 0;
|
|
4643
5760
|
}
|
|
4644
5761
|
function findWorkspaceByPath(config, rawPath) {
|
|
4645
|
-
const abs =
|
|
5762
|
+
const abs = path4.resolve(expandPath(rawPath));
|
|
4646
5763
|
if (!abs) return void 0;
|
|
4647
|
-
return (config.workspaces || []).find((w) =>
|
|
5764
|
+
return (config.workspaces || []).find((w) => path4.resolve(expandPath(w.path)) === abs);
|
|
4648
5765
|
}
|
|
4649
5766
|
function addWorkspaceEntry(config, rawPath, label, options) {
|
|
4650
5767
|
const abs = expandPath(rawPath);
|
|
@@ -4660,7 +5777,7 @@ function addWorkspaceEntry(config, rawPath, label, options) {
|
|
|
4660
5777
|
const v = validateWorkspacePath(abs);
|
|
4661
5778
|
if (!v.ok) return { error: v.error };
|
|
4662
5779
|
const list = [...config.workspaces || []];
|
|
4663
|
-
if (list.some((w) =>
|
|
5780
|
+
if (list.some((w) => path4.resolve(w.path) === abs)) {
|
|
4664
5781
|
return { error: "Workspace already in list" };
|
|
4665
5782
|
}
|
|
4666
5783
|
if (list.length >= MAX_WORKSPACES) {
|
|
@@ -4694,7 +5811,7 @@ function setDefaultWorkspaceId(config, id) {
|
|
|
4694
5811
|
}
|
|
4695
5812
|
|
|
4696
5813
|
// src/config/recent-activity.ts
|
|
4697
|
-
import * as
|
|
5814
|
+
import * as path5 from "path";
|
|
4698
5815
|
|
|
4699
5816
|
// src/providers/summary-metadata.ts
|
|
4700
5817
|
function normalizeSummaryItem(item) {
|
|
@@ -4763,9 +5880,9 @@ var MAX_ACTIVITY = 30;
|
|
|
4763
5880
|
function normalizeWorkspace(workspace) {
|
|
4764
5881
|
if (!workspace) return "";
|
|
4765
5882
|
try {
|
|
4766
|
-
return
|
|
5883
|
+
return path5.resolve(expandPath(workspace));
|
|
4767
5884
|
} catch {
|
|
4768
|
-
return
|
|
5885
|
+
return path5.resolve(workspace);
|
|
4769
5886
|
}
|
|
4770
5887
|
}
|
|
4771
5888
|
function buildRecentActivityKey(entry) {
|
|
@@ -4933,14 +6050,14 @@ function markSessionSeen(state, sessionId, seenAt = Date.now(), completionMarker
|
|
|
4933
6050
|
}
|
|
4934
6051
|
|
|
4935
6052
|
// src/config/saved-sessions.ts
|
|
4936
|
-
import * as
|
|
6053
|
+
import * as path6 from "path";
|
|
4937
6054
|
var MAX_SAVED_SESSIONS = 500;
|
|
4938
6055
|
function normalizeWorkspace2(workspace) {
|
|
4939
6056
|
if (!workspace) return "";
|
|
4940
6057
|
try {
|
|
4941
|
-
return
|
|
6058
|
+
return path6.resolve(expandPath(workspace));
|
|
4942
6059
|
} catch {
|
|
4943
|
-
return
|
|
6060
|
+
return path6.resolve(workspace);
|
|
4944
6061
|
}
|
|
4945
6062
|
}
|
|
4946
6063
|
function buildSavedProviderSessionKey(providerSessionId) {
|
|
@@ -5059,7 +6176,7 @@ function resetState() {
|
|
|
5059
6176
|
import { execSync } from "child_process";
|
|
5060
6177
|
import { existsSync as existsSync4 } from "fs";
|
|
5061
6178
|
import { platform, homedir as homedir3 } from "os";
|
|
5062
|
-
import * as
|
|
6179
|
+
import * as path7 from "path";
|
|
5063
6180
|
var BUILTIN_IDE_DEFINITIONS = [];
|
|
5064
6181
|
var registeredIDEs = /* @__PURE__ */ new Map();
|
|
5065
6182
|
function registerIDEDefinition(def) {
|
|
@@ -5078,9 +6195,9 @@ function getMergedDefinitions() {
|
|
|
5078
6195
|
function findCliCommand(command) {
|
|
5079
6196
|
const trimmed = String(command || "").trim();
|
|
5080
6197
|
if (!trimmed) return null;
|
|
5081
|
-
if (
|
|
5082
|
-
const candidate = trimmed.startsWith("~") ?
|
|
5083
|
-
const resolved =
|
|
6198
|
+
if (path7.isAbsolute(trimmed) || trimmed.includes("/") || trimmed.includes("\\") || trimmed.startsWith("~")) {
|
|
6199
|
+
const candidate = trimmed.startsWith("~") ? path7.join(homedir3(), trimmed.slice(1)) : trimmed;
|
|
6200
|
+
const resolved = path7.isAbsolute(candidate) ? candidate : path7.resolve(candidate);
|
|
5084
6201
|
return existsSync4(resolved) ? resolved : null;
|
|
5085
6202
|
}
|
|
5086
6203
|
try {
|
|
@@ -5108,7 +6225,7 @@ function getIdeVersion(cliCommand) {
|
|
|
5108
6225
|
function checkPathExists(paths) {
|
|
5109
6226
|
const home = homedir3();
|
|
5110
6227
|
for (const p of paths) {
|
|
5111
|
-
const normalized = p.startsWith("~") ?
|
|
6228
|
+
const normalized = p.startsWith("~") ? path7.join(home, p.slice(1)) : p;
|
|
5112
6229
|
if (normalized.includes("*")) {
|
|
5113
6230
|
const username = home.split(/[\\/]/).pop() || "";
|
|
5114
6231
|
const resolved = normalized.replace("*", username);
|
|
@@ -5166,7 +6283,7 @@ async function detectIDEs(providerLoader) {
|
|
|
5166
6283
|
// src/detection/cli-detector.ts
|
|
5167
6284
|
import { exec } from "child_process";
|
|
5168
6285
|
import * as os2 from "os";
|
|
5169
|
-
import * as
|
|
6286
|
+
import * as path8 from "path";
|
|
5170
6287
|
import { existsSync as existsSync5 } from "fs";
|
|
5171
6288
|
function parseVersion(raw) {
|
|
5172
6289
|
const match = raw.match(/v?(\d+\.\d+(?:\.\d+)?(?:-[a-zA-Z0-9.]+)?)/);
|
|
@@ -5179,36 +6296,36 @@ function shellQuote(value) {
|
|
|
5179
6296
|
function expandHome(value) {
|
|
5180
6297
|
const trimmed = value.trim();
|
|
5181
6298
|
if (!trimmed.startsWith("~")) return trimmed;
|
|
5182
|
-
return
|
|
6299
|
+
return path8.join(os2.homedir(), trimmed.slice(1));
|
|
5183
6300
|
}
|
|
5184
6301
|
function isExplicitCommandPath(command) {
|
|
5185
6302
|
const trimmed = command.trim();
|
|
5186
|
-
return
|
|
6303
|
+
return path8.isAbsolute(trimmed) || trimmed.includes("/") || trimmed.includes("\\") || trimmed.startsWith("~");
|
|
5187
6304
|
}
|
|
5188
6305
|
function resolveCommandPath(command) {
|
|
5189
6306
|
const trimmed = command.trim();
|
|
5190
6307
|
if (!trimmed) return null;
|
|
5191
6308
|
if (isExplicitCommandPath(trimmed)) {
|
|
5192
6309
|
const expanded = expandHome(trimmed);
|
|
5193
|
-
const candidate =
|
|
6310
|
+
const candidate = path8.isAbsolute(expanded) ? expanded : path8.resolve(expanded);
|
|
5194
6311
|
return existsSync5(candidate) ? candidate : null;
|
|
5195
6312
|
}
|
|
5196
6313
|
return null;
|
|
5197
6314
|
}
|
|
5198
6315
|
function execAsync(cmd, timeoutMs = 5e3) {
|
|
5199
|
-
return new Promise((
|
|
6316
|
+
return new Promise((resolve15) => {
|
|
5200
6317
|
const child = exec(cmd, {
|
|
5201
6318
|
encoding: "utf-8",
|
|
5202
6319
|
timeout: timeoutMs,
|
|
5203
6320
|
...process.platform === "win32" ? { windowsHide: true } : {}
|
|
5204
6321
|
}, (err, stdout) => {
|
|
5205
6322
|
if (err || !stdout?.trim()) {
|
|
5206
|
-
|
|
6323
|
+
resolve15(null);
|
|
5207
6324
|
} else {
|
|
5208
|
-
|
|
6325
|
+
resolve15(stdout.trim());
|
|
5209
6326
|
}
|
|
5210
6327
|
});
|
|
5211
|
-
child.on("error", () =>
|
|
6328
|
+
child.on("error", () => resolve15(null));
|
|
5212
6329
|
});
|
|
5213
6330
|
}
|
|
5214
6331
|
async function detectCLIs(providerLoader, options) {
|
|
@@ -5573,7 +6690,7 @@ var DaemonCdpManager = class {
|
|
|
5573
6690
|
* Returns multiple entries if multiple IDE windows are open on same port
|
|
5574
6691
|
*/
|
|
5575
6692
|
static listAllTargets(port) {
|
|
5576
|
-
return new Promise((
|
|
6693
|
+
return new Promise((resolve15) => {
|
|
5577
6694
|
const req = http.get(`http://127.0.0.1:${port}/json`, (res) => {
|
|
5578
6695
|
let data = "";
|
|
5579
6696
|
res.on("data", (chunk) => data += chunk.toString());
|
|
@@ -5589,16 +6706,16 @@ var DaemonCdpManager = class {
|
|
|
5589
6706
|
(t) => !isNonMain(t.title || "") && t.url?.includes("workbench.html") && !t.url?.includes("agent")
|
|
5590
6707
|
);
|
|
5591
6708
|
const fallbackPages = pages.filter((t) => !isNonMain(t.title || ""));
|
|
5592
|
-
|
|
6709
|
+
resolve15(mainPages.length > 0 ? mainPages : fallbackPages);
|
|
5593
6710
|
} catch {
|
|
5594
|
-
|
|
6711
|
+
resolve15([]);
|
|
5595
6712
|
}
|
|
5596
6713
|
});
|
|
5597
6714
|
});
|
|
5598
|
-
req.on("error", () =>
|
|
6715
|
+
req.on("error", () => resolve15([]));
|
|
5599
6716
|
req.setTimeout(2e3, () => {
|
|
5600
6717
|
req.destroy();
|
|
5601
|
-
|
|
6718
|
+
resolve15([]);
|
|
5602
6719
|
});
|
|
5603
6720
|
});
|
|
5604
6721
|
}
|
|
@@ -5638,7 +6755,7 @@ var DaemonCdpManager = class {
|
|
|
5638
6755
|
}
|
|
5639
6756
|
}
|
|
5640
6757
|
findTargetOnPort(port) {
|
|
5641
|
-
return new Promise((
|
|
6758
|
+
return new Promise((resolve15) => {
|
|
5642
6759
|
const req = http.get(`http://127.0.0.1:${port}/json`, (res) => {
|
|
5643
6760
|
let data = "";
|
|
5644
6761
|
res.on("data", (chunk) => data += chunk.toString());
|
|
@@ -5649,7 +6766,7 @@ var DaemonCdpManager = class {
|
|
|
5649
6766
|
(t) => (t.type === "page" || t.type === "browser" || t.type === "Page") && t.webSocketDebuggerUrl
|
|
5650
6767
|
);
|
|
5651
6768
|
if (pages.length === 0) {
|
|
5652
|
-
|
|
6769
|
+
resolve15(targets.find((t) => t.webSocketDebuggerUrl) || null);
|
|
5653
6770
|
return;
|
|
5654
6771
|
}
|
|
5655
6772
|
const titleFilteredPages = pages.filter((t) => !this.isNonMainTitle(t.title || ""));
|
|
@@ -5668,25 +6785,25 @@ var DaemonCdpManager = class {
|
|
|
5668
6785
|
this._targetId = selected.target.id;
|
|
5669
6786
|
}
|
|
5670
6787
|
this._pageTitle = selected.target.title || "";
|
|
5671
|
-
|
|
6788
|
+
resolve15(selected.target);
|
|
5672
6789
|
return;
|
|
5673
6790
|
}
|
|
5674
6791
|
if (previousTargetId) {
|
|
5675
6792
|
this.log(`[CDP] Target ${previousTargetId} not found in page list`);
|
|
5676
|
-
|
|
6793
|
+
resolve15(null);
|
|
5677
6794
|
return;
|
|
5678
6795
|
}
|
|
5679
6796
|
this._pageTitle = list[0]?.title || "";
|
|
5680
|
-
|
|
6797
|
+
resolve15(list[0]);
|
|
5681
6798
|
} catch {
|
|
5682
|
-
|
|
6799
|
+
resolve15(null);
|
|
5683
6800
|
}
|
|
5684
6801
|
});
|
|
5685
6802
|
});
|
|
5686
|
-
req.on("error", () =>
|
|
6803
|
+
req.on("error", () => resolve15(null));
|
|
5687
6804
|
req.setTimeout(2e3, () => {
|
|
5688
6805
|
req.destroy();
|
|
5689
|
-
|
|
6806
|
+
resolve15(null);
|
|
5690
6807
|
});
|
|
5691
6808
|
});
|
|
5692
6809
|
}
|
|
@@ -5697,7 +6814,7 @@ var DaemonCdpManager = class {
|
|
|
5697
6814
|
this.extensionProviders = providers;
|
|
5698
6815
|
}
|
|
5699
6816
|
connectToTarget(wsUrl) {
|
|
5700
|
-
return new Promise((
|
|
6817
|
+
return new Promise((resolve15) => {
|
|
5701
6818
|
this.ws = new WebSocket(wsUrl);
|
|
5702
6819
|
this.ws.on("open", async () => {
|
|
5703
6820
|
this._connected = true;
|
|
@@ -5707,17 +6824,17 @@ var DaemonCdpManager = class {
|
|
|
5707
6824
|
}
|
|
5708
6825
|
this.connectBrowserWs().catch(() => {
|
|
5709
6826
|
});
|
|
5710
|
-
|
|
6827
|
+
resolve15(true);
|
|
5711
6828
|
});
|
|
5712
6829
|
this.ws.on("message", (data) => {
|
|
5713
6830
|
try {
|
|
5714
6831
|
const msg = JSON.parse(data.toString());
|
|
5715
6832
|
if (msg.id && this.pending.has(msg.id)) {
|
|
5716
|
-
const { resolve:
|
|
6833
|
+
const { resolve: resolve16, reject } = this.pending.get(msg.id);
|
|
5717
6834
|
this.pending.delete(msg.id);
|
|
5718
6835
|
this.failureCount = 0;
|
|
5719
6836
|
if (msg.error) reject(new Error(msg.error.message));
|
|
5720
|
-
else
|
|
6837
|
+
else resolve16(msg.result);
|
|
5721
6838
|
} else if (msg.method === "Runtime.executionContextCreated") {
|
|
5722
6839
|
this.contexts.add(msg.params.context.id);
|
|
5723
6840
|
} else if (msg.method === "Runtime.executionContextDestroyed") {
|
|
@@ -5740,7 +6857,7 @@ var DaemonCdpManager = class {
|
|
|
5740
6857
|
this.ws.on("error", (err) => {
|
|
5741
6858
|
this.log(`[CDP] WebSocket error: ${err.message}`);
|
|
5742
6859
|
this._connected = false;
|
|
5743
|
-
|
|
6860
|
+
resolve15(false);
|
|
5744
6861
|
});
|
|
5745
6862
|
});
|
|
5746
6863
|
}
|
|
@@ -5754,7 +6871,7 @@ var DaemonCdpManager = class {
|
|
|
5754
6871
|
return;
|
|
5755
6872
|
}
|
|
5756
6873
|
this.log(`[CDP] Connecting browser WS for target discovery...`);
|
|
5757
|
-
await new Promise((
|
|
6874
|
+
await new Promise((resolve15, reject) => {
|
|
5758
6875
|
this.browserWs = new WebSocket(browserWsUrl);
|
|
5759
6876
|
this.browserWs.on("open", async () => {
|
|
5760
6877
|
this._browserConnected = true;
|
|
@@ -5764,16 +6881,16 @@ var DaemonCdpManager = class {
|
|
|
5764
6881
|
} catch (e) {
|
|
5765
6882
|
this.log(`[CDP] setDiscoverTargets failed: ${e.message}`);
|
|
5766
6883
|
}
|
|
5767
|
-
|
|
6884
|
+
resolve15();
|
|
5768
6885
|
});
|
|
5769
6886
|
this.browserWs.on("message", (data) => {
|
|
5770
6887
|
try {
|
|
5771
6888
|
const msg = JSON.parse(data.toString());
|
|
5772
6889
|
if (msg.id && this.browserPending.has(msg.id)) {
|
|
5773
|
-
const { resolve:
|
|
6890
|
+
const { resolve: resolve16, reject: reject2 } = this.browserPending.get(msg.id);
|
|
5774
6891
|
this.browserPending.delete(msg.id);
|
|
5775
6892
|
if (msg.error) reject2(new Error(msg.error.message));
|
|
5776
|
-
else
|
|
6893
|
+
else resolve16(msg.result);
|
|
5777
6894
|
}
|
|
5778
6895
|
} catch {
|
|
5779
6896
|
}
|
|
@@ -5793,31 +6910,31 @@ var DaemonCdpManager = class {
|
|
|
5793
6910
|
}
|
|
5794
6911
|
}
|
|
5795
6912
|
getBrowserWsUrl() {
|
|
5796
|
-
return new Promise((
|
|
6913
|
+
return new Promise((resolve15) => {
|
|
5797
6914
|
const req = http.get(`http://127.0.0.1:${this.port}/json/version`, (res) => {
|
|
5798
6915
|
let data = "";
|
|
5799
6916
|
res.on("data", (chunk) => data += chunk.toString());
|
|
5800
6917
|
res.on("end", () => {
|
|
5801
6918
|
try {
|
|
5802
6919
|
const info = JSON.parse(data);
|
|
5803
|
-
|
|
6920
|
+
resolve15(info.webSocketDebuggerUrl || null);
|
|
5804
6921
|
} catch {
|
|
5805
|
-
|
|
6922
|
+
resolve15(null);
|
|
5806
6923
|
}
|
|
5807
6924
|
});
|
|
5808
6925
|
});
|
|
5809
|
-
req.on("error", () =>
|
|
6926
|
+
req.on("error", () => resolve15(null));
|
|
5810
6927
|
req.setTimeout(3e3, () => {
|
|
5811
6928
|
req.destroy();
|
|
5812
|
-
|
|
6929
|
+
resolve15(null);
|
|
5813
6930
|
});
|
|
5814
6931
|
});
|
|
5815
6932
|
}
|
|
5816
6933
|
sendBrowser(method, params = {}, timeoutMs = 15e3) {
|
|
5817
|
-
return new Promise((
|
|
6934
|
+
return new Promise((resolve15, reject) => {
|
|
5818
6935
|
if (!this.browserWs || !this._browserConnected) return reject(new Error("Browser WS not connected"));
|
|
5819
6936
|
const id = this.browserMsgId++;
|
|
5820
|
-
this.browserPending.set(id, { resolve:
|
|
6937
|
+
this.browserPending.set(id, { resolve: resolve15, reject });
|
|
5821
6938
|
this.browserWs.send(JSON.stringify({ id, method, params }));
|
|
5822
6939
|
setTimeout(() => {
|
|
5823
6940
|
if (this.browserPending.has(id)) {
|
|
@@ -5857,11 +6974,11 @@ var DaemonCdpManager = class {
|
|
|
5857
6974
|
}
|
|
5858
6975
|
// ─── CDP Protocol ────────────────────────────────────────
|
|
5859
6976
|
sendInternal(method, params = {}, timeoutMs = 15e3) {
|
|
5860
|
-
return new Promise((
|
|
6977
|
+
return new Promise((resolve15, reject) => {
|
|
5861
6978
|
if (!this.ws || !this._connected) return reject(new Error("CDP not connected"));
|
|
5862
6979
|
if (this.ws.readyState !== WebSocket.OPEN) return reject(new Error("WebSocket not open"));
|
|
5863
6980
|
const id = this.msgId++;
|
|
5864
|
-
this.pending.set(id, { resolve:
|
|
6981
|
+
this.pending.set(id, { resolve: resolve15, reject });
|
|
5865
6982
|
this.ws.send(JSON.stringify({ id, method, params }));
|
|
5866
6983
|
setTimeout(() => {
|
|
5867
6984
|
if (this.pending.has(id)) {
|
|
@@ -6110,7 +7227,7 @@ var DaemonCdpManager = class {
|
|
|
6110
7227
|
const browserWs = this.browserWs;
|
|
6111
7228
|
let msgId = this.browserMsgId;
|
|
6112
7229
|
const sendWs = (method, params = {}, sessionId) => {
|
|
6113
|
-
return new Promise((
|
|
7230
|
+
return new Promise((resolve15, reject) => {
|
|
6114
7231
|
const mid = msgId++;
|
|
6115
7232
|
this.browserMsgId = msgId;
|
|
6116
7233
|
const handler = (raw) => {
|
|
@@ -6119,7 +7236,7 @@ var DaemonCdpManager = class {
|
|
|
6119
7236
|
if (msg.id === mid) {
|
|
6120
7237
|
browserWs.removeListener("message", handler);
|
|
6121
7238
|
if (msg.error) reject(new Error(msg.error.message || JSON.stringify(msg.error)));
|
|
6122
|
-
else
|
|
7239
|
+
else resolve15(msg.result);
|
|
6123
7240
|
}
|
|
6124
7241
|
} catch {
|
|
6125
7242
|
}
|
|
@@ -6320,14 +7437,14 @@ var DaemonCdpManager = class {
|
|
|
6320
7437
|
if (!ws || ws.readyState !== WebSocket.OPEN) {
|
|
6321
7438
|
throw new Error("CDP not connected");
|
|
6322
7439
|
}
|
|
6323
|
-
return new Promise((
|
|
7440
|
+
return new Promise((resolve15, reject) => {
|
|
6324
7441
|
const id = getNextId();
|
|
6325
7442
|
pendingMap.set(id, {
|
|
6326
7443
|
resolve: (result) => {
|
|
6327
7444
|
if (result?.result?.subtype === "error") {
|
|
6328
7445
|
reject(new Error(result.result.description));
|
|
6329
7446
|
} else {
|
|
6330
|
-
|
|
7447
|
+
resolve15(result?.result?.value);
|
|
6331
7448
|
}
|
|
6332
7449
|
},
|
|
6333
7450
|
reject
|
|
@@ -6359,10 +7476,10 @@ var DaemonCdpManager = class {
|
|
|
6359
7476
|
throw new Error("CDP not connected");
|
|
6360
7477
|
}
|
|
6361
7478
|
const sendViaSession = (method, params = {}) => {
|
|
6362
|
-
return new Promise((
|
|
7479
|
+
return new Promise((resolve15, reject) => {
|
|
6363
7480
|
const pendingMap = this._browserConnected ? this.browserPending : this.pending;
|
|
6364
7481
|
const id = this._browserConnected ? this.browserMsgId++ : this.msgId++;
|
|
6365
|
-
pendingMap.set(id, { resolve:
|
|
7482
|
+
pendingMap.set(id, { resolve: resolve15, reject });
|
|
6366
7483
|
ws.send(JSON.stringify({ id, sessionId, method, params }));
|
|
6367
7484
|
setTimeout(() => {
|
|
6368
7485
|
if (pendingMap.has(id)) {
|
|
@@ -7109,9 +8226,9 @@ ${cleanBody}`;
|
|
|
7109
8226
|
// src/config/chat-history.ts
|
|
7110
8227
|
init_chat_message_normalization();
|
|
7111
8228
|
import * as fs3 from "fs";
|
|
7112
|
-
import * as
|
|
8229
|
+
import * as path10 from "path";
|
|
7113
8230
|
import * as os5 from "os";
|
|
7114
|
-
var HISTORY_DIR =
|
|
8231
|
+
var HISTORY_DIR = path10.join(os5.homedir(), ".adhdev", "history");
|
|
7115
8232
|
var RETAIN_DAYS = 30;
|
|
7116
8233
|
var SAVED_HISTORY_INDEX_VERSION = 1;
|
|
7117
8234
|
var SAVED_HISTORY_INDEX_FILE = ".saved-history-index.json";
|
|
@@ -7274,8 +8391,8 @@ function extractSavedHistorySessionIdFromFile(file) {
|
|
|
7274
8391
|
function buildSavedHistoryFileSignatureMap(dir, files) {
|
|
7275
8392
|
return new Map(files.map((file) => {
|
|
7276
8393
|
try {
|
|
7277
|
-
const
|
|
7278
|
-
return [file, `${file}:${
|
|
8394
|
+
const stat2 = fs3.statSync(path10.join(dir, file));
|
|
8395
|
+
return [file, `${file}:${stat2.size}:${Math.trunc(stat2.mtimeMs)}`];
|
|
7279
8396
|
} catch {
|
|
7280
8397
|
return [file, `${file}:missing`];
|
|
7281
8398
|
}
|
|
@@ -7285,7 +8402,7 @@ function buildSavedHistoryCacheSignature(files, fileSignatures) {
|
|
|
7285
8402
|
return files.map((file) => fileSignatures.get(file) || `${file}:missing`).join("|");
|
|
7286
8403
|
}
|
|
7287
8404
|
function getSavedHistoryIndexFilePath(dir) {
|
|
7288
|
-
return
|
|
8405
|
+
return path10.join(dir, SAVED_HISTORY_INDEX_FILE);
|
|
7289
8406
|
}
|
|
7290
8407
|
function getSavedHistoryIndexLockPath(dir) {
|
|
7291
8408
|
return `${getSavedHistoryIndexFilePath(dir)}${SAVED_HISTORY_INDEX_LOCK_SUFFIX}`;
|
|
@@ -7338,8 +8455,8 @@ function acquireSavedHistoryIndexLock(dir) {
|
|
|
7338
8455
|
} catch (error) {
|
|
7339
8456
|
if (error?.code !== "EEXIST") return null;
|
|
7340
8457
|
try {
|
|
7341
|
-
const
|
|
7342
|
-
if (Date.now() -
|
|
8458
|
+
const stat2 = fs3.statSync(lockPath);
|
|
8459
|
+
if (Date.now() - stat2.mtimeMs > SAVED_HISTORY_INDEX_LOCK_STALE_MS) {
|
|
7343
8460
|
fs3.rmSync(lockPath, { recursive: true, force: true });
|
|
7344
8461
|
continue;
|
|
7345
8462
|
}
|
|
@@ -7387,7 +8504,7 @@ function savePersistedSavedHistoryIndex(dir, entries) {
|
|
|
7387
8504
|
}
|
|
7388
8505
|
for (const file of Array.from(currentEntries.keys())) {
|
|
7389
8506
|
if (incomingFiles.has(file)) continue;
|
|
7390
|
-
if (!fs3.existsSync(
|
|
8507
|
+
if (!fs3.existsSync(path10.join(dir, file))) {
|
|
7391
8508
|
currentEntries.delete(file);
|
|
7392
8509
|
}
|
|
7393
8510
|
}
|
|
@@ -7402,8 +8519,8 @@ function invalidatePersistedSavedHistoryIndex(agentType, dir) {
|
|
|
7402
8519
|
}
|
|
7403
8520
|
function buildSavedHistoryIndexFileSignature(dir) {
|
|
7404
8521
|
try {
|
|
7405
|
-
const
|
|
7406
|
-
return `index:${
|
|
8522
|
+
const stat2 = fs3.statSync(getSavedHistoryIndexFilePath(dir));
|
|
8523
|
+
return `index:${stat2.size}:${Math.trunc(stat2.mtimeMs)}`;
|
|
7407
8524
|
} catch {
|
|
7408
8525
|
return "index:missing";
|
|
7409
8526
|
}
|
|
@@ -7413,8 +8530,8 @@ function historyDirectoryHasFilesNewerThanIndex(dir) {
|
|
|
7413
8530
|
const indexStat = fs3.statSync(getSavedHistoryIndexFilePath(dir));
|
|
7414
8531
|
const files = listHistoryFiles(dir);
|
|
7415
8532
|
for (const file of files) {
|
|
7416
|
-
const
|
|
7417
|
-
if (
|
|
8533
|
+
const stat2 = fs3.statSync(path10.join(dir, file));
|
|
8534
|
+
if (stat2.mtimeMs > indexStat.mtimeMs) return true;
|
|
7418
8535
|
}
|
|
7419
8536
|
return false;
|
|
7420
8537
|
} catch {
|
|
@@ -7423,14 +8540,14 @@ function historyDirectoryHasFilesNewerThanIndex(dir) {
|
|
|
7423
8540
|
}
|
|
7424
8541
|
function buildSavedHistoryFileSignature(dir, file) {
|
|
7425
8542
|
try {
|
|
7426
|
-
const
|
|
7427
|
-
return `${file}:${
|
|
8543
|
+
const stat2 = fs3.statSync(path10.join(dir, file));
|
|
8544
|
+
return `${file}:${stat2.size}:${Math.trunc(stat2.mtimeMs)}`;
|
|
7428
8545
|
} catch {
|
|
7429
8546
|
return `${file}:missing`;
|
|
7430
8547
|
}
|
|
7431
8548
|
}
|
|
7432
8549
|
function persistSavedHistoryFileSummaryEntry(agentType, dir, file, updater) {
|
|
7433
|
-
const filePath =
|
|
8550
|
+
const filePath = path10.join(dir, file);
|
|
7434
8551
|
const result = withLockedPersistedSavedHistoryIndex(dir, (entries) => {
|
|
7435
8552
|
const currentEntry = entries.get(file) || null;
|
|
7436
8553
|
const nextSummary = updater(currentEntry?.summary || null);
|
|
@@ -7503,7 +8620,7 @@ function updateSavedHistoryIndexForAppendedMessages(agentType, dir, file, histor
|
|
|
7503
8620
|
function computeSavedHistoryFileSummary(dir, file) {
|
|
7504
8621
|
const historySessionId = extractSavedHistorySessionIdFromFile(file);
|
|
7505
8622
|
if (!historySessionId) return null;
|
|
7506
|
-
const filePath =
|
|
8623
|
+
const filePath = path10.join(dir, file);
|
|
7507
8624
|
const content = fs3.readFileSync(filePath, "utf-8");
|
|
7508
8625
|
const lines = content.split("\n").filter(Boolean);
|
|
7509
8626
|
let messageCount = 0;
|
|
@@ -7590,7 +8707,7 @@ function computeSavedHistorySessionSummaries(agentType, dir, files, fileSignatur
|
|
|
7590
8707
|
const summaryBySessionId = /* @__PURE__ */ new Map();
|
|
7591
8708
|
const nextPersistedEntries = /* @__PURE__ */ new Map();
|
|
7592
8709
|
for (const file of files.slice().sort()) {
|
|
7593
|
-
const filePath =
|
|
8710
|
+
const filePath = path10.join(dir, file);
|
|
7594
8711
|
const signature = fileSignatures.get(file) || `${file}:missing`;
|
|
7595
8712
|
const cached = savedHistoryFileSummaryCache.get(filePath);
|
|
7596
8713
|
const persisted = persistedEntries.get(file);
|
|
@@ -7710,12 +8827,12 @@ var ChatHistoryWriter = class {
|
|
|
7710
8827
|
});
|
|
7711
8828
|
}
|
|
7712
8829
|
if (newMessages.length === 0) return;
|
|
7713
|
-
const dir =
|
|
8830
|
+
const dir = path10.join(HISTORY_DIR, this.sanitize(agentType));
|
|
7714
8831
|
fs3.mkdirSync(dir, { recursive: true });
|
|
7715
8832
|
const date = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
|
|
7716
8833
|
const filePrefix = effectiveHistoryKey ? `${this.sanitize(effectiveHistoryKey)}_` : "";
|
|
7717
8834
|
const fileName = `${filePrefix}${date}.jsonl`;
|
|
7718
|
-
const filePath =
|
|
8835
|
+
const filePath = path10.join(dir, fileName);
|
|
7719
8836
|
const lines = newMessages.map((m) => JSON.stringify(m)).join("\n") + "\n";
|
|
7720
8837
|
fs3.appendFileSync(filePath, lines, "utf-8");
|
|
7721
8838
|
updateSavedHistoryIndexForAppendedMessages(agentType, dir, fileName, effectiveHistoryKey, newMessages);
|
|
@@ -7806,11 +8923,11 @@ var ChatHistoryWriter = class {
|
|
|
7806
8923
|
const ws = String(workspace || "").trim();
|
|
7807
8924
|
if (!id || !ws) return;
|
|
7808
8925
|
try {
|
|
7809
|
-
const dir =
|
|
8926
|
+
const dir = path10.join(HISTORY_DIR, this.sanitize(agentType));
|
|
7810
8927
|
fs3.mkdirSync(dir, { recursive: true });
|
|
7811
8928
|
const date = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
|
|
7812
8929
|
const fileName = `${this.sanitize(id)}_${date}.jsonl`;
|
|
7813
|
-
const filePath =
|
|
8930
|
+
const filePath = path10.join(dir, fileName);
|
|
7814
8931
|
const record = {
|
|
7815
8932
|
ts: (/* @__PURE__ */ new Date()).toISOString(),
|
|
7816
8933
|
receivedAt: Date.now(),
|
|
@@ -7856,14 +8973,14 @@ var ChatHistoryWriter = class {
|
|
|
7856
8973
|
this.lastSeenCounts.set(toDedupKey, Math.max(fromCount, this.lastSeenCounts.get(toDedupKey) || 0));
|
|
7857
8974
|
this.lastSeenCounts.delete(fromDedupKey);
|
|
7858
8975
|
}
|
|
7859
|
-
const dir =
|
|
8976
|
+
const dir = path10.join(HISTORY_DIR, this.sanitize(agentType));
|
|
7860
8977
|
if (!fs3.existsSync(dir)) return;
|
|
7861
8978
|
const fromPrefix = `${this.sanitize(fromId)}_`;
|
|
7862
8979
|
const toPrefix = `${this.sanitize(toId)}_`;
|
|
7863
8980
|
const files = fs3.readdirSync(dir).filter((file) => file.startsWith(fromPrefix) && file.endsWith(".jsonl"));
|
|
7864
8981
|
for (const file of files) {
|
|
7865
|
-
const sourcePath =
|
|
7866
|
-
const targetPath =
|
|
8982
|
+
const sourcePath = path10.join(dir, file);
|
|
8983
|
+
const targetPath = path10.join(dir, `${toPrefix}${file.slice(fromPrefix.length)}`);
|
|
7867
8984
|
const sourceLines = fs3.readFileSync(sourcePath, "utf-8").split("\n").filter(Boolean);
|
|
7868
8985
|
const rewritten = sourceLines.map((line) => {
|
|
7869
8986
|
try {
|
|
@@ -7897,13 +9014,13 @@ var ChatHistoryWriter = class {
|
|
|
7897
9014
|
const sessionId = String(historySessionId || "").trim();
|
|
7898
9015
|
if (!sessionId) return;
|
|
7899
9016
|
try {
|
|
7900
|
-
const dir =
|
|
9017
|
+
const dir = path10.join(HISTORY_DIR, this.sanitize(agentType));
|
|
7901
9018
|
if (!fs3.existsSync(dir)) return;
|
|
7902
9019
|
const prefix = `${this.sanitize(sessionId)}_`;
|
|
7903
9020
|
const files = fs3.readdirSync(dir).filter((file) => file.startsWith(prefix) && file.endsWith(".jsonl")).sort();
|
|
7904
9021
|
const seen = /* @__PURE__ */ new Set();
|
|
7905
9022
|
for (const file of files) {
|
|
7906
|
-
const filePath =
|
|
9023
|
+
const filePath = path10.join(dir, file);
|
|
7907
9024
|
const lines = fs3.readFileSync(filePath, "utf-8").split("\n").filter(Boolean);
|
|
7908
9025
|
const next = [];
|
|
7909
9026
|
for (const line of lines) {
|
|
@@ -7957,13 +9074,13 @@ var ChatHistoryWriter = class {
|
|
|
7957
9074
|
const cutoff = Date.now() - RETAIN_DAYS * 24 * 60 * 60 * 1e3;
|
|
7958
9075
|
const agentDirs = fs3.readdirSync(HISTORY_DIR, { withFileTypes: true }).filter((d) => d.isDirectory());
|
|
7959
9076
|
for (const dir of agentDirs) {
|
|
7960
|
-
const dirPath =
|
|
9077
|
+
const dirPath = path10.join(HISTORY_DIR, dir.name);
|
|
7961
9078
|
const files = fs3.readdirSync(dirPath).filter((f) => f.endsWith(".jsonl") || f.endsWith(".terminal.log"));
|
|
7962
9079
|
let removedAny = false;
|
|
7963
9080
|
for (const file of files) {
|
|
7964
|
-
const filePath =
|
|
7965
|
-
const
|
|
7966
|
-
if (
|
|
9081
|
+
const filePath = path10.join(dirPath, file);
|
|
9082
|
+
const stat2 = fs3.statSync(filePath);
|
|
9083
|
+
if (stat2.mtimeMs < cutoff) {
|
|
7967
9084
|
fs3.unlinkSync(filePath);
|
|
7968
9085
|
removedAny = true;
|
|
7969
9086
|
}
|
|
@@ -7980,6 +9097,10 @@ var ChatHistoryWriter = class {
|
|
|
7980
9097
|
return name.replace(/[^a-zA-Z0-9_-]/g, "_");
|
|
7981
9098
|
}
|
|
7982
9099
|
};
|
|
9100
|
+
function normalizePaginationNumber(value, fallback, min) {
|
|
9101
|
+
const numeric = Number(value);
|
|
9102
|
+
return Number.isFinite(numeric) ? Math.max(min, numeric) : fallback;
|
|
9103
|
+
}
|
|
7983
9104
|
function pageHistoryRecords(agentType, records, offset = 0, limit = 30, excludeRecentCount = 0, historyBehavior) {
|
|
7984
9105
|
const allMessages = records.map((message) => sanitizeHistoryMessage(agentType, message)).filter(Boolean);
|
|
7985
9106
|
allMessages.sort((a, b) => a.receivedAt - b.receivedAt);
|
|
@@ -7993,9 +9114,12 @@ function pageHistoryRecords(agentType, records, offset = 0, limit = 30, excludeR
|
|
|
7993
9114
|
if (message.role !== "system") lastTurn = message;
|
|
7994
9115
|
}
|
|
7995
9116
|
const collapsed = collapseReplayAssistantTurns(chronological, historyBehavior);
|
|
7996
|
-
const boundedLimit =
|
|
7997
|
-
const boundedOffset =
|
|
7998
|
-
const boundedExclude = Math.
|
|
9117
|
+
const boundedLimit = normalizePaginationNumber(limit, 30, 1);
|
|
9118
|
+
const boundedOffset = normalizePaginationNumber(offset, 0, 0);
|
|
9119
|
+
const boundedExclude = Math.min(
|
|
9120
|
+
normalizePaginationNumber(excludeRecentCount, 0, 0),
|
|
9121
|
+
collapsed.length
|
|
9122
|
+
);
|
|
7999
9123
|
const endExclusive = Math.max(0, collapsed.length - boundedExclude - boundedOffset);
|
|
8000
9124
|
const startInclusive = Math.max(0, endExclusive - boundedLimit);
|
|
8001
9125
|
const sliced = collapsed.slice(startInclusive, endExclusive);
|
|
@@ -8004,13 +9128,13 @@ function pageHistoryRecords(agentType, records, offset = 0, limit = 30, excludeR
|
|
|
8004
9128
|
function readChatHistory(agentType, offset = 0, limit = 30, historySessionId, excludeRecentCount = 0, historyBehavior) {
|
|
8005
9129
|
try {
|
|
8006
9130
|
const sanitized = agentType.replace(/[^a-zA-Z0-9_-]/g, "_");
|
|
8007
|
-
const dir =
|
|
9131
|
+
const dir = path10.join(HISTORY_DIR, sanitized);
|
|
8008
9132
|
if (!fs3.existsSync(dir)) return { messages: [], hasMore: false };
|
|
8009
9133
|
const files = listHistoryFiles(dir, historySessionId);
|
|
8010
9134
|
const allMessages = [];
|
|
8011
9135
|
const seen = /* @__PURE__ */ new Set();
|
|
8012
9136
|
for (const file of files) {
|
|
8013
|
-
const filePath =
|
|
9137
|
+
const filePath = path10.join(dir, file);
|
|
8014
9138
|
const content = fs3.readFileSync(filePath, "utf-8");
|
|
8015
9139
|
const lines = content.trim().split("\n").filter(Boolean);
|
|
8016
9140
|
for (let i = 0; i < lines.length; i++) {
|
|
@@ -8034,7 +9158,7 @@ function readChatHistory(agentType, offset = 0, limit = 30, historySessionId, ex
|
|
|
8034
9158
|
function listSavedHistorySessions(agentType, options = {}, historyBehavior) {
|
|
8035
9159
|
try {
|
|
8036
9160
|
const sanitized = agentType.replace(/[^a-zA-Z0-9_-]/g, "_");
|
|
8037
|
-
const dir =
|
|
9161
|
+
const dir = path10.join(HISTORY_DIR, sanitized);
|
|
8038
9162
|
if (!fs3.existsSync(dir)) {
|
|
8039
9163
|
savedHistorySessionCache.delete(sanitized);
|
|
8040
9164
|
return { sessions: [], hasMore: false };
|
|
@@ -8095,11 +9219,11 @@ function listSavedHistorySessions(agentType, options = {}, historyBehavior) {
|
|
|
8095
9219
|
}
|
|
8096
9220
|
function readExistingSessionStartRecord(agentType, historySessionId) {
|
|
8097
9221
|
try {
|
|
8098
|
-
const dir =
|
|
9222
|
+
const dir = path10.join(HISTORY_DIR, agentType);
|
|
8099
9223
|
if (!fs3.existsSync(dir)) return null;
|
|
8100
9224
|
const files = listHistoryFiles(dir, historySessionId).sort();
|
|
8101
9225
|
for (const file of files) {
|
|
8102
|
-
const lines = fs3.readFileSync(
|
|
9226
|
+
const lines = fs3.readFileSync(path10.join(dir, file), "utf-8").split("\n").filter(Boolean);
|
|
8103
9227
|
for (const line of lines) {
|
|
8104
9228
|
try {
|
|
8105
9229
|
const parsed = JSON.parse(line);
|
|
@@ -8119,16 +9243,16 @@ function readExistingSessionStartRecord(agentType, historySessionId) {
|
|
|
8119
9243
|
function rewriteCanonicalSavedHistory(agentType, historySessionId, records) {
|
|
8120
9244
|
if (records.length === 0) return false;
|
|
8121
9245
|
try {
|
|
8122
|
-
const dir =
|
|
9246
|
+
const dir = path10.join(HISTORY_DIR, agentType);
|
|
8123
9247
|
fs3.mkdirSync(dir, { recursive: true });
|
|
8124
9248
|
const prefix = `${historySessionId.replace(/[^a-zA-Z0-9_-]/g, "_")}_`;
|
|
8125
9249
|
for (const file of fs3.readdirSync(dir)) {
|
|
8126
9250
|
if (file.startsWith(prefix) && file.endsWith(".jsonl")) {
|
|
8127
|
-
fs3.unlinkSync(
|
|
9251
|
+
fs3.unlinkSync(path10.join(dir, file));
|
|
8128
9252
|
}
|
|
8129
9253
|
}
|
|
8130
9254
|
const targetDate = new Date(records[records.length - 1].receivedAt || Date.now()).toISOString().slice(0, 10);
|
|
8131
|
-
const filePath =
|
|
9255
|
+
const filePath = path10.join(dir, `${prefix}${targetDate}.jsonl`);
|
|
8132
9256
|
fs3.writeFileSync(filePath, `${records.map((record) => JSON.stringify(record)).join("\n")}
|
|
8133
9257
|
`, "utf-8");
|
|
8134
9258
|
invalidatePersistedSavedHistoryIndex(agentType, dir);
|
|
@@ -10000,6 +11124,10 @@ function shouldIncludeSessionMetadata(profile) {
|
|
|
10000
11124
|
function shouldIncludeRuntimeMetadata(profile) {
|
|
10001
11125
|
return true;
|
|
10002
11126
|
}
|
|
11127
|
+
function getGitSummaryForWorkspace(workspace, options) {
|
|
11128
|
+
if (!workspace) return void 0;
|
|
11129
|
+
return options.getGitSummaryForWorkspace?.(workspace) || void 0;
|
|
11130
|
+
}
|
|
10003
11131
|
function findCdpManager(cdpManagers, key) {
|
|
10004
11132
|
const exact = cdpManagers.get(key);
|
|
10005
11133
|
if (exact) return exact.isConnected ? exact : null;
|
|
@@ -10055,6 +11183,8 @@ function buildIdeWorkspaceSession(state, cdpManagers, options) {
|
|
|
10055
11183
|
const controlValues = normalizeProviderStateControlValues(state.controlValues);
|
|
10056
11184
|
const includeSessionMetadata = shouldIncludeSessionMetadata(profile);
|
|
10057
11185
|
const includeSessionControls = shouldIncludeSessionControls(profile);
|
|
11186
|
+
const workspace = state.workspace || null;
|
|
11187
|
+
const git = getGitSummaryForWorkspace(workspace, options);
|
|
10058
11188
|
const title = activeChat?.title || state.name;
|
|
10059
11189
|
return {
|
|
10060
11190
|
id: state.instanceId || state.type,
|
|
@@ -10067,7 +11197,8 @@ function buildIdeWorkspaceSession(state, cdpManagers, options) {
|
|
|
10067
11197
|
activeModal: activeChat?.activeModal || null
|
|
10068
11198
|
}),
|
|
10069
11199
|
title,
|
|
10070
|
-
workspace
|
|
11200
|
+
workspace,
|
|
11201
|
+
...git && { git },
|
|
10071
11202
|
activeChat,
|
|
10072
11203
|
...summaryMetadata && { summaryMetadata },
|
|
10073
11204
|
...includeSessionMetadata && { capabilities: state.sessionCapabilities || IDE_SESSION_CAPABILITIES },
|
|
@@ -10088,6 +11219,8 @@ function buildExtensionAgentSession(parent, ext, options) {
|
|
|
10088
11219
|
const controlValues = normalizeProviderStateControlValues(ext.controlValues);
|
|
10089
11220
|
const includeSessionMetadata = shouldIncludeSessionMetadata(profile);
|
|
10090
11221
|
const includeSessionControls = shouldIncludeSessionControls(profile);
|
|
11222
|
+
const workspace = parent.workspace || null;
|
|
11223
|
+
const git = getGitSummaryForWorkspace(workspace, options);
|
|
10091
11224
|
return {
|
|
10092
11225
|
id: ext.instanceId || `${parent.instanceId}:${ext.type}`,
|
|
10093
11226
|
parentId: parent.instanceId || parent.type,
|
|
@@ -10100,7 +11233,8 @@ function buildExtensionAgentSession(parent, ext, options) {
|
|
|
10100
11233
|
activeModal: activeChat?.activeModal || null
|
|
10101
11234
|
}),
|
|
10102
11235
|
title: activeChat?.title || ext.name,
|
|
10103
|
-
workspace
|
|
11236
|
+
workspace,
|
|
11237
|
+
...git && { git },
|
|
10104
11238
|
activeChat,
|
|
10105
11239
|
...summaryMetadata && { summaryMetadata },
|
|
10106
11240
|
...includeSessionMetadata && { capabilities: ext.sessionCapabilities || EXTENSION_SESSION_CAPABILITIES },
|
|
@@ -10136,6 +11270,8 @@ function buildCliSession(state, options) {
|
|
|
10136
11270
|
const includeSessionMetadata = shouldIncludeSessionMetadata(profile);
|
|
10137
11271
|
const includeRuntimeMetadata = shouldIncludeRuntimeMetadata(profile);
|
|
10138
11272
|
const includeSessionControls = shouldIncludeSessionControls(profile);
|
|
11273
|
+
const workspace = state.workspace || null;
|
|
11274
|
+
const git = getGitSummaryForWorkspace(workspace, options);
|
|
10139
11275
|
return {
|
|
10140
11276
|
id: state.instanceId,
|
|
10141
11277
|
parentId: null,
|
|
@@ -10148,7 +11284,8 @@ function buildCliSession(state, options) {
|
|
|
10148
11284
|
activeModal: activeChat?.activeModal || null
|
|
10149
11285
|
}),
|
|
10150
11286
|
title: activeChat?.title || state.name,
|
|
10151
|
-
workspace
|
|
11287
|
+
workspace,
|
|
11288
|
+
...git && { git },
|
|
10152
11289
|
...includeRuntimeMetadata && {
|
|
10153
11290
|
runtimeKey: state.runtime?.runtimeKey,
|
|
10154
11291
|
runtimeDisplayName: state.runtime?.displayName,
|
|
@@ -10183,6 +11320,8 @@ function buildAcpSession(state, options) {
|
|
|
10183
11320
|
const controlValues = normalizeProviderStateControlValues(state.controlValues);
|
|
10184
11321
|
const includeSessionMetadata = shouldIncludeSessionMetadata(profile);
|
|
10185
11322
|
const includeSessionControls = shouldIncludeSessionControls(profile);
|
|
11323
|
+
const workspace = state.workspace || null;
|
|
11324
|
+
const git = getGitSummaryForWorkspace(workspace, options);
|
|
10186
11325
|
return {
|
|
10187
11326
|
id: state.instanceId,
|
|
10188
11327
|
parentId: null,
|
|
@@ -10194,7 +11333,8 @@ function buildAcpSession(state, options) {
|
|
|
10194
11333
|
activeModal: activeChat?.activeModal || null
|
|
10195
11334
|
}),
|
|
10196
11335
|
title: activeChat?.title || state.name,
|
|
10197
|
-
workspace
|
|
11336
|
+
workspace,
|
|
11337
|
+
...git && { git },
|
|
10198
11338
|
activeChat,
|
|
10199
11339
|
...summaryMetadata && { summaryMetadata },
|
|
10200
11340
|
...includeSessionMetadata && { capabilities: ACP_SESSION_CAPABILITIES },
|
|
@@ -10314,7 +11454,7 @@ function resolveLegacyProviderScript(fn, scriptName, params) {
|
|
|
10314
11454
|
init_contracts();
|
|
10315
11455
|
import * as fs4 from "fs";
|
|
10316
11456
|
import * as os6 from "os";
|
|
10317
|
-
import * as
|
|
11457
|
+
import * as path11 from "path";
|
|
10318
11458
|
import { randomUUID as randomUUID4 } from "crypto";
|
|
10319
11459
|
|
|
10320
11460
|
// src/providers/provider-input-support.ts
|
|
@@ -11006,7 +12146,7 @@ function buildDebugBundleText(bundle) {
|
|
|
11006
12146
|
}
|
|
11007
12147
|
function getChatDebugBundleDir() {
|
|
11008
12148
|
const override = typeof process.env.ADHDEV_DEBUG_BUNDLE_DIR === "string" ? process.env.ADHDEV_DEBUG_BUNDLE_DIR.trim() : "";
|
|
11009
|
-
return override ||
|
|
12149
|
+
return override || path11.join(os6.homedir(), ".adhdev", "debug-bundles", "chat");
|
|
11010
12150
|
}
|
|
11011
12151
|
function safeBundleIdSegment(value, fallback) {
|
|
11012
12152
|
const normalized = String(value || fallback).trim().replace(/[^A-Za-z0-9_.-]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 80);
|
|
@@ -11039,7 +12179,7 @@ function storeChatDebugBundleOnDaemon(bundle, targetSessionId) {
|
|
|
11039
12179
|
const bundleId = createChatDebugBundleId(targetSessionId);
|
|
11040
12180
|
const dir = getChatDebugBundleDir();
|
|
11041
12181
|
fs4.mkdirSync(dir, { recursive: true });
|
|
11042
|
-
const savedPath =
|
|
12182
|
+
const savedPath = path11.join(dir, `${bundleId}.json`);
|
|
11043
12183
|
const json = `${JSON.stringify(bundle, null, 2)}
|
|
11044
12184
|
`;
|
|
11045
12185
|
fs4.writeFileSync(savedPath, json, { encoding: "utf8", mode: 384 });
|
|
@@ -11208,10 +12348,32 @@ function getStateLastSignature(state) {
|
|
|
11208
12348
|
if (!last) return "";
|
|
11209
12349
|
return `${last.role || ""}:${String(last.content || "").replace(/\s+/g, " ").trim()}`;
|
|
11210
12350
|
}
|
|
12351
|
+
function toNonNegativeNumber(value) {
|
|
12352
|
+
const numeric = Number(value ?? 0);
|
|
12353
|
+
return Number.isFinite(numeric) ? Math.max(0, numeric) : 0;
|
|
12354
|
+
}
|
|
12355
|
+
function getCliVisibleTranscriptCount(adapter) {
|
|
12356
|
+
const adapterStatus = adapter?.getStatus?.() || {};
|
|
12357
|
+
const adapterMessages = Array.isArray(adapterStatus.messages) ? adapterStatus.messages : [];
|
|
12358
|
+
let parsedRecord = null;
|
|
12359
|
+
if (typeof adapter?.getScriptParsedStatus === "function") {
|
|
12360
|
+
try {
|
|
12361
|
+
const parsed = parseMaybeJson(adapter.getScriptParsedStatus());
|
|
12362
|
+
parsedRecord = parsed && typeof parsed === "object" ? parsed : null;
|
|
12363
|
+
} catch {
|
|
12364
|
+
parsedRecord = null;
|
|
12365
|
+
}
|
|
12366
|
+
}
|
|
12367
|
+
const parsedMessages = Array.isArray(parsedRecord?.messages) ? parsedRecord.messages : [];
|
|
12368
|
+
if (!parsedRecord) return adapterMessages.length;
|
|
12369
|
+
const parsedIsProviderAuthoritative = parsedRecord.transcriptAuthority === "provider" || parsedRecord.coverage === "full";
|
|
12370
|
+
const shouldPreferAdapterMessages = !parsedIsProviderAuthoritative && adapterMessages.length > 0 && adapterMessages.length > parsedMessages.length;
|
|
12371
|
+
return shouldPreferAdapterMessages ? adapterMessages.length : parsedMessages.length;
|
|
12372
|
+
}
|
|
11211
12373
|
async function getStableExtensionBaseline(h) {
|
|
11212
12374
|
const first = await readExtensionChatState(h);
|
|
11213
12375
|
if (getStateMessageCount(first) > 0 || getStateLastSignature(first)) return first;
|
|
11214
|
-
await new Promise((
|
|
12376
|
+
await new Promise((resolve15) => setTimeout(resolve15, 150));
|
|
11215
12377
|
const second = await readExtensionChatState(h);
|
|
11216
12378
|
return getStateMessageCount(second) >= getStateMessageCount(first) ? second : first;
|
|
11217
12379
|
}
|
|
@@ -11219,7 +12381,7 @@ async function verifyExtensionSendObserved(h, before) {
|
|
|
11219
12381
|
const beforeCount = getStateMessageCount(before);
|
|
11220
12382
|
const beforeSignature = getStateLastSignature(before);
|
|
11221
12383
|
for (let attempt = 0; attempt < 12; attempt += 1) {
|
|
11222
|
-
await new Promise((
|
|
12384
|
+
await new Promise((resolve15) => setTimeout(resolve15, 250));
|
|
11223
12385
|
const state = await readExtensionChatState(h);
|
|
11224
12386
|
if (state?.status === "waiting_approval") return true;
|
|
11225
12387
|
const afterCount = getStateMessageCount(state);
|
|
@@ -11236,11 +12398,11 @@ async function handleChatHistory(h, args) {
|
|
|
11236
12398
|
const provider = h.getProvider(agentType);
|
|
11237
12399
|
const agentStr = provider?.type || agentType || getCurrentProviderType(h);
|
|
11238
12400
|
const transport = getTargetTransport(h, provider);
|
|
11239
|
-
|
|
11240
|
-
|
|
12401
|
+
const hasExplicitExcludeRecentCount = args?.excludeRecentCount !== void 0 && args?.excludeRecentCount !== null;
|
|
12402
|
+
let excludeRecentCount = toNonNegativeNumber(args?.excludeRecentCount);
|
|
12403
|
+
if (!hasExplicitExcludeRecentCount && isCliLikeTransport(transport)) {
|
|
11241
12404
|
const adapter = getTargetedCliAdapter(h, args, provider?.type);
|
|
11242
|
-
const
|
|
11243
|
-
const visibleCount = Array.isArray(status?.messages) ? status.messages.length : 0;
|
|
12405
|
+
const visibleCount = getCliVisibleTranscriptCount(adapter);
|
|
11244
12406
|
if (visibleCount > excludeRecentCount) excludeRecentCount = visibleCount;
|
|
11245
12407
|
}
|
|
11246
12408
|
const workspace = typeof args?.workspace === "string" ? args.workspace : typeof h.currentSession?.workspace === "string" ? h.currentSession.workspace : void 0;
|
|
@@ -12155,7 +13317,7 @@ async function handleResolveAction(h, args) {
|
|
|
12155
13317
|
|
|
12156
13318
|
// src/commands/cdp-commands.ts
|
|
12157
13319
|
import * as fs5 from "fs";
|
|
12158
|
-
import * as
|
|
13320
|
+
import * as path12 from "path";
|
|
12159
13321
|
import * as os7 from "os";
|
|
12160
13322
|
var KEY_TO_VK = {
|
|
12161
13323
|
Backspace: 8,
|
|
@@ -12412,25 +13574,25 @@ function resolveSafePath(requestedPath) {
|
|
|
12412
13574
|
const inputPath = rawPath || ".";
|
|
12413
13575
|
const home = os7.homedir();
|
|
12414
13576
|
if (inputPath.startsWith("~")) {
|
|
12415
|
-
return
|
|
13577
|
+
return path12.resolve(path12.join(home, inputPath.slice(1)));
|
|
12416
13578
|
}
|
|
12417
13579
|
if (process.platform === "win32") {
|
|
12418
13580
|
const normalized = normalizeWindowsRequestedPath(inputPath);
|
|
12419
|
-
if (
|
|
12420
|
-
return
|
|
13581
|
+
if (path12.win32.isAbsolute(normalized)) {
|
|
13582
|
+
return path12.win32.normalize(normalized);
|
|
12421
13583
|
}
|
|
12422
|
-
return
|
|
13584
|
+
return path12.win32.resolve(normalized);
|
|
12423
13585
|
}
|
|
12424
|
-
if (
|
|
12425
|
-
return
|
|
13586
|
+
if (path12.isAbsolute(inputPath)) {
|
|
13587
|
+
return path12.normalize(inputPath);
|
|
12426
13588
|
}
|
|
12427
|
-
return
|
|
13589
|
+
return path12.resolve(inputPath);
|
|
12428
13590
|
}
|
|
12429
13591
|
function listDirectoryEntriesSafe(dirPath) {
|
|
12430
13592
|
const entries = fs5.readdirSync(dirPath, { withFileTypes: true });
|
|
12431
13593
|
const files = [];
|
|
12432
13594
|
for (const entry of entries) {
|
|
12433
|
-
const entryPath =
|
|
13595
|
+
const entryPath = path12.join(dirPath, entry.name);
|
|
12434
13596
|
try {
|
|
12435
13597
|
if (entry.isDirectory()) {
|
|
12436
13598
|
files.push({ name: entry.name, type: "directory" });
|
|
@@ -12446,11 +13608,11 @@ function listDirectoryEntriesSafe(dirPath) {
|
|
|
12446
13608
|
files.push({ name: entry.name, type: "file", size });
|
|
12447
13609
|
continue;
|
|
12448
13610
|
}
|
|
12449
|
-
const
|
|
13611
|
+
const stat2 = fs5.statSync(entryPath);
|
|
12450
13612
|
files.push({
|
|
12451
13613
|
name: entry.name,
|
|
12452
|
-
type:
|
|
12453
|
-
size:
|
|
13614
|
+
type: stat2.isDirectory() ? "directory" : "file",
|
|
13615
|
+
size: stat2.isFile() ? stat2.size : void 0
|
|
12454
13616
|
});
|
|
12455
13617
|
} catch {
|
|
12456
13618
|
}
|
|
@@ -12484,7 +13646,7 @@ async function handleFileRead(h, args) {
|
|
|
12484
13646
|
async function handleFileWrite(h, args) {
|
|
12485
13647
|
try {
|
|
12486
13648
|
const filePath = resolveSafePath(args?.path);
|
|
12487
|
-
fs5.mkdirSync(
|
|
13649
|
+
fs5.mkdirSync(path12.dirname(filePath), { recursive: true });
|
|
12488
13650
|
fs5.writeFileSync(filePath, args?.content || "", "utf-8");
|
|
12489
13651
|
return { success: true, path: filePath };
|
|
12490
13652
|
} catch (e) {
|
|
@@ -12833,7 +13995,7 @@ async function executeProviderScript(h, args, scriptName) {
|
|
|
12833
13995
|
const enterCount = cliCommand.enterCount || 1;
|
|
12834
13996
|
await adapter.writeRaw(cliCommand.text + "\r");
|
|
12835
13997
|
for (let i = 1; i < enterCount; i += 1) {
|
|
12836
|
-
await new Promise((
|
|
13998
|
+
await new Promise((resolve15) => setTimeout(resolve15, 50));
|
|
12837
13999
|
await adapter.writeRaw("\r");
|
|
12838
14000
|
}
|
|
12839
14001
|
}
|
|
@@ -13327,6 +14489,12 @@ var DaemonCommandHandler = class {
|
|
|
13327
14489
|
this._currentRoute = this.resolveRoute(args);
|
|
13328
14490
|
const startedAt = Date.now();
|
|
13329
14491
|
this.logCommandStart(cmd, args);
|
|
14492
|
+
let result;
|
|
14493
|
+
if (isGitCommandName(cmd)) {
|
|
14494
|
+
result = await handleGitCommand(cmd, args, this._ctx.gitCommandServices);
|
|
14495
|
+
this.logCommandEnd(cmd, result, startedAt);
|
|
14496
|
+
return result;
|
|
14497
|
+
}
|
|
13330
14498
|
const sessionScopedCommands = /* @__PURE__ */ new Set([
|
|
13331
14499
|
"read_chat",
|
|
13332
14500
|
"get_chat_debug_bundle",
|
|
@@ -13352,7 +14520,6 @@ var DaemonCommandHandler = class {
|
|
|
13352
14520
|
this.logCommandEnd(cmd, result2, startedAt);
|
|
13353
14521
|
return result2;
|
|
13354
14522
|
}
|
|
13355
|
-
let result;
|
|
13356
14523
|
if (!this._currentRoute.session && !this._currentRoute.managerKey && !this._currentRoute.providerType) {
|
|
13357
14524
|
const cdpCommands = ["send_chat", "read_chat", "list_chats", "new_chat", "switch_chat", "set_mode", "change_model", "set_thought_level", "resolve_action"];
|
|
13358
14525
|
if (cdpCommands.includes(cmd)) {
|
|
@@ -13503,7 +14670,7 @@ var DaemonCommandHandler = class {
|
|
|
13503
14670
|
try {
|
|
13504
14671
|
const http3 = await import("http");
|
|
13505
14672
|
const postData = JSON.stringify(body);
|
|
13506
|
-
const result = await new Promise((
|
|
14673
|
+
const result = await new Promise((resolve15, reject) => {
|
|
13507
14674
|
const req = http3.request({
|
|
13508
14675
|
hostname: "127.0.0.1",
|
|
13509
14676
|
port: 19280,
|
|
@@ -13515,9 +14682,9 @@ var DaemonCommandHandler = class {
|
|
|
13515
14682
|
res.on("data", (chunk) => data += chunk);
|
|
13516
14683
|
res.on("end", () => {
|
|
13517
14684
|
try {
|
|
13518
|
-
|
|
14685
|
+
resolve15(JSON.parse(data));
|
|
13519
14686
|
} catch {
|
|
13520
|
-
|
|
14687
|
+
resolve15({ raw: data });
|
|
13521
14688
|
}
|
|
13522
14689
|
});
|
|
13523
14690
|
});
|
|
@@ -13535,15 +14702,15 @@ var DaemonCommandHandler = class {
|
|
|
13535
14702
|
if (!providerType) return { success: false, error: "providerType required" };
|
|
13536
14703
|
try {
|
|
13537
14704
|
const http3 = await import("http");
|
|
13538
|
-
const result = await new Promise((
|
|
14705
|
+
const result = await new Promise((resolve15, reject) => {
|
|
13539
14706
|
http3.get(`http://127.0.0.1:19280/api/providers/${providerType}/${endpoint}`, (res) => {
|
|
13540
14707
|
let data = "";
|
|
13541
14708
|
res.on("data", (chunk) => data += chunk);
|
|
13542
14709
|
res.on("end", () => {
|
|
13543
14710
|
try {
|
|
13544
|
-
|
|
14711
|
+
resolve15(JSON.parse(data));
|
|
13545
14712
|
} catch {
|
|
13546
|
-
|
|
14713
|
+
resolve15({ raw: data });
|
|
13547
14714
|
}
|
|
13548
14715
|
});
|
|
13549
14716
|
}).on("error", reject);
|
|
@@ -13557,7 +14724,7 @@ var DaemonCommandHandler = class {
|
|
|
13557
14724
|
try {
|
|
13558
14725
|
const http3 = await import("http");
|
|
13559
14726
|
const postData = JSON.stringify(args || {});
|
|
13560
|
-
const result = await new Promise((
|
|
14727
|
+
const result = await new Promise((resolve15, reject) => {
|
|
13561
14728
|
const req = http3.request({
|
|
13562
14729
|
hostname: "127.0.0.1",
|
|
13563
14730
|
port: 19280,
|
|
@@ -13569,9 +14736,9 @@ var DaemonCommandHandler = class {
|
|
|
13569
14736
|
res.on("data", (chunk) => data += chunk);
|
|
13570
14737
|
res.on("end", () => {
|
|
13571
14738
|
try {
|
|
13572
|
-
|
|
14739
|
+
resolve15(JSON.parse(data));
|
|
13573
14740
|
} catch {
|
|
13574
|
-
|
|
14741
|
+
resolve15({ raw: data });
|
|
13575
14742
|
}
|
|
13576
14743
|
});
|
|
13577
14744
|
});
|
|
@@ -13589,7 +14756,7 @@ var DaemonCommandHandler = class {
|
|
|
13589
14756
|
// src/commands/cli-manager.ts
|
|
13590
14757
|
init_provider_cli_adapter();
|
|
13591
14758
|
import * as os13 from "os";
|
|
13592
|
-
import * as
|
|
14759
|
+
import * as path16 from "path";
|
|
13593
14760
|
import * as crypto4 from "crypto";
|
|
13594
14761
|
import { existsSync as existsSync10 } from "fs";
|
|
13595
14762
|
import { execFileSync } from "child_process";
|
|
@@ -13599,7 +14766,7 @@ init_config();
|
|
|
13599
14766
|
// src/providers/cli-provider-instance.ts
|
|
13600
14767
|
init_contracts();
|
|
13601
14768
|
import * as os12 from "os";
|
|
13602
|
-
import * as
|
|
14769
|
+
import * as path15 from "path";
|
|
13603
14770
|
import * as crypto3 from "crypto";
|
|
13604
14771
|
import * as fs6 from "fs";
|
|
13605
14772
|
import { createRequire } from "module";
|
|
@@ -13659,7 +14826,7 @@ function buildIncrementalHistoryAppendMessages(previousMessages, currentMessages
|
|
|
13659
14826
|
var CachedDatabaseSync = null;
|
|
13660
14827
|
function getDatabaseSync() {
|
|
13661
14828
|
if (CachedDatabaseSync) return CachedDatabaseSync;
|
|
13662
|
-
const requireFn = typeof __require === "function" ? __require : createRequire(
|
|
14829
|
+
const requireFn = typeof __require === "function" ? __require : createRequire(path15.join(process.cwd(), "__adhdev_sqlite_loader__.js"));
|
|
13663
14830
|
const sqliteModule = requireFn(`node:${"sqlite"}`);
|
|
13664
14831
|
CachedDatabaseSync = sqliteModule.DatabaseSync;
|
|
13665
14832
|
if (!CachedDatabaseSync) {
|
|
@@ -13697,7 +14864,7 @@ async function waitForCliAdapterReady(adapter, options) {
|
|
|
13697
14864
|
if (status === "stopped") {
|
|
13698
14865
|
throw new Error("CLI runtime stopped before it became ready");
|
|
13699
14866
|
}
|
|
13700
|
-
await new Promise((
|
|
14867
|
+
await new Promise((resolve15) => setTimeout(resolve15, pollMs));
|
|
13701
14868
|
}
|
|
13702
14869
|
throw new Error(`CLI runtime did not become ready within ${timeoutMs}ms`);
|
|
13703
14870
|
}
|
|
@@ -14048,7 +15215,7 @@ var CliProviderInstance = class {
|
|
|
14048
15215
|
const enterCount = cliCommand.enterCount || 1;
|
|
14049
15216
|
await this.adapter.writeRaw(cliCommand.text + "\r");
|
|
14050
15217
|
for (let i = 1; i < enterCount; i += 1) {
|
|
14051
|
-
await new Promise((
|
|
15218
|
+
await new Promise((resolve15) => setTimeout(resolve15, 50));
|
|
14052
15219
|
await this.adapter.writeRaw("\r");
|
|
14053
15220
|
}
|
|
14054
15221
|
}
|
|
@@ -15167,13 +16334,13 @@ var AcpProviderInstance = class {
|
|
|
15167
16334
|
}
|
|
15168
16335
|
this.currentStatus = "waiting_approval";
|
|
15169
16336
|
this.detectStatusTransition();
|
|
15170
|
-
const approved = await new Promise((
|
|
15171
|
-
this.permissionResolvers.push(
|
|
16337
|
+
const approved = await new Promise((resolve15) => {
|
|
16338
|
+
this.permissionResolvers.push(resolve15);
|
|
15172
16339
|
setTimeout(() => {
|
|
15173
|
-
const idx = this.permissionResolvers.indexOf(
|
|
16340
|
+
const idx = this.permissionResolvers.indexOf(resolve15);
|
|
15174
16341
|
if (idx >= 0) {
|
|
15175
16342
|
this.permissionResolvers.splice(idx, 1);
|
|
15176
|
-
|
|
16343
|
+
resolve15(false);
|
|
15177
16344
|
}
|
|
15178
16345
|
}, 3e5);
|
|
15179
16346
|
});
|
|
@@ -15748,11 +16915,11 @@ function shouldRestoreHostedRuntime(record, managerTag) {
|
|
|
15748
16915
|
// src/commands/cli-manager.ts
|
|
15749
16916
|
function isExplicitCommand(command) {
|
|
15750
16917
|
const trimmed = command.trim();
|
|
15751
|
-
return
|
|
16918
|
+
return path16.isAbsolute(trimmed) || trimmed.includes("/") || trimmed.includes("\\") || trimmed.startsWith("~");
|
|
15752
16919
|
}
|
|
15753
16920
|
function expandExecutable(command) {
|
|
15754
16921
|
const trimmed = command.trim();
|
|
15755
|
-
return trimmed.startsWith("~") ?
|
|
16922
|
+
return trimmed.startsWith("~") ? path16.join(os13.homedir(), trimmed.slice(1)) : trimmed;
|
|
15756
16923
|
}
|
|
15757
16924
|
function commandExists(command) {
|
|
15758
16925
|
const trimmed = command.trim();
|
|
@@ -16033,7 +17200,7 @@ var DaemonCliManager = class {
|
|
|
16033
17200
|
async startSession(cliType, workingDir, cliArgs, initialModel, options) {
|
|
16034
17201
|
const trimmed = (workingDir || "").trim();
|
|
16035
17202
|
if (!trimmed) throw new Error("working directory required");
|
|
16036
|
-
const resolvedDir = trimmed.startsWith("~") ? trimmed.replace(/^~/, os13.homedir()) :
|
|
17203
|
+
const resolvedDir = trimmed.startsWith("~") ? trimmed.replace(/^~/, os13.homedir()) : path16.resolve(trimmed);
|
|
16037
17204
|
const normalizedType = this.providerLoader.resolveAlias(cliType);
|
|
16038
17205
|
const rawProvider = this.providerLoader.getByAlias(cliType);
|
|
16039
17206
|
const provider = rawProvider ? this.providerLoader.resolve(normalizedType) || rawProvider : void 0;
|
|
@@ -16534,11 +17701,11 @@ Run 'adhdev doctor' for detailed diagnostics.`
|
|
|
16534
17701
|
import { execSync as execSync4, spawn as spawn2 } from "child_process";
|
|
16535
17702
|
import * as net from "net";
|
|
16536
17703
|
import * as os15 from "os";
|
|
16537
|
-
import * as
|
|
17704
|
+
import * as path18 from "path";
|
|
16538
17705
|
|
|
16539
17706
|
// src/providers/provider-loader.ts
|
|
16540
17707
|
import * as fs7 from "fs";
|
|
16541
|
-
import * as
|
|
17708
|
+
import * as path17 from "path";
|
|
16542
17709
|
import * as os14 from "os";
|
|
16543
17710
|
import * as chokidar from "chokidar";
|
|
16544
17711
|
init_logger();
|
|
@@ -16803,7 +17970,7 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
16803
17970
|
try {
|
|
16804
17971
|
if (!fs7.existsSync(candidate) || !fs7.statSync(candidate).isDirectory()) return false;
|
|
16805
17972
|
return ["ide", "extension", "cli", "acp"].some(
|
|
16806
|
-
(category) => fs7.existsSync(
|
|
17973
|
+
(category) => fs7.existsSync(path17.join(candidate, category))
|
|
16807
17974
|
);
|
|
16808
17975
|
} catch {
|
|
16809
17976
|
return false;
|
|
@@ -16811,20 +17978,20 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
16811
17978
|
}
|
|
16812
17979
|
static hasProviderRootMarker(candidate) {
|
|
16813
17980
|
try {
|
|
16814
|
-
return fs7.existsSync(
|
|
17981
|
+
return fs7.existsSync(path17.join(candidate, _ProviderLoader.SIBLING_MARKER_FILE));
|
|
16815
17982
|
} catch {
|
|
16816
17983
|
return false;
|
|
16817
17984
|
}
|
|
16818
17985
|
}
|
|
16819
17986
|
detectDefaultUserDir() {
|
|
16820
|
-
const fallback =
|
|
17987
|
+
const fallback = path17.join(os14.homedir(), ".adhdev", "providers");
|
|
16821
17988
|
const envOptIn = process.env[_ProviderLoader.SIBLING_ENV_VAR] === "1";
|
|
16822
17989
|
const visited = /* @__PURE__ */ new Set();
|
|
16823
17990
|
for (const start of this.probeStarts) {
|
|
16824
|
-
let current =
|
|
17991
|
+
let current = path17.resolve(start);
|
|
16825
17992
|
while (!visited.has(current)) {
|
|
16826
17993
|
visited.add(current);
|
|
16827
|
-
const siblingCandidate =
|
|
17994
|
+
const siblingCandidate = path17.join(path17.dirname(current), _ProviderLoader.REPO_PROVIDER_DIRNAME);
|
|
16828
17995
|
if (_ProviderLoader.looksLikeProviderRoot(siblingCandidate)) {
|
|
16829
17996
|
const hasMarker = _ProviderLoader.hasProviderRootMarker(siblingCandidate);
|
|
16830
17997
|
if (envOptIn || hasMarker) {
|
|
@@ -16846,7 +18013,7 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
16846
18013
|
return { path: siblingCandidate, source };
|
|
16847
18014
|
}
|
|
16848
18015
|
}
|
|
16849
|
-
const parent =
|
|
18016
|
+
const parent = path17.dirname(current);
|
|
16850
18017
|
if (parent === current) break;
|
|
16851
18018
|
current = parent;
|
|
16852
18019
|
}
|
|
@@ -16856,11 +18023,11 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
16856
18023
|
constructor(options) {
|
|
16857
18024
|
this.logFn = options?.logFn || LOG.forComponent("Provider").asLogFn();
|
|
16858
18025
|
this.probeStarts = options?.probeStarts ?? [process.cwd(), __dirname];
|
|
16859
|
-
this.defaultProvidersDir =
|
|
18026
|
+
this.defaultProvidersDir = path17.join(os14.homedir(), ".adhdev", "providers");
|
|
16860
18027
|
const detected = this.detectDefaultUserDir();
|
|
16861
18028
|
this.userDir = detected.path;
|
|
16862
18029
|
this.userDirSource = detected.source;
|
|
16863
|
-
this.upstreamDir =
|
|
18030
|
+
this.upstreamDir = path17.join(this.defaultProvidersDir, ".upstream");
|
|
16864
18031
|
this.disableUpstream = false;
|
|
16865
18032
|
this.applySourceConfig({
|
|
16866
18033
|
userDir: options?.userDir,
|
|
@@ -16919,7 +18086,7 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
16919
18086
|
this.userDir = detected.path;
|
|
16920
18087
|
this.userDirSource = detected.source;
|
|
16921
18088
|
}
|
|
16922
|
-
this.upstreamDir =
|
|
18089
|
+
this.upstreamDir = path17.join(this.defaultProvidersDir, ".upstream");
|
|
16923
18090
|
this.disableUpstream = this.sourceMode === "no-upstream";
|
|
16924
18091
|
if (this.explicitProviderDir) {
|
|
16925
18092
|
this.log(`Config 'providerDir' applied: ${this.userDir}`);
|
|
@@ -16933,7 +18100,7 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
16933
18100
|
* Canonical provider directory shape for a given root.
|
|
16934
18101
|
*/
|
|
16935
18102
|
getProviderDir(root, category, type) {
|
|
16936
|
-
return
|
|
18103
|
+
return path17.join(root, category, type);
|
|
16937
18104
|
}
|
|
16938
18105
|
/**
|
|
16939
18106
|
* Canonical user override directory for a provider.
|
|
@@ -16960,7 +18127,7 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
16960
18127
|
resolveProviderFile(type, ...segments) {
|
|
16961
18128
|
const dir = this.findProviderDirInternal(type);
|
|
16962
18129
|
if (!dir) return null;
|
|
16963
|
-
return
|
|
18130
|
+
return path17.join(dir, ...segments);
|
|
16964
18131
|
}
|
|
16965
18132
|
/**
|
|
16966
18133
|
* Load all providers (3-tier priority)
|
|
@@ -16999,7 +18166,7 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
16999
18166
|
if (!fs7.existsSync(this.upstreamDir)) return false;
|
|
17000
18167
|
try {
|
|
17001
18168
|
return fs7.readdirSync(this.upstreamDir).some(
|
|
17002
|
-
(d) => fs7.statSync(
|
|
18169
|
+
(d) => fs7.statSync(path17.join(this.upstreamDir, d)).isDirectory()
|
|
17003
18170
|
);
|
|
17004
18171
|
} catch {
|
|
17005
18172
|
return false;
|
|
@@ -17496,8 +18663,8 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
17496
18663
|
resolved._resolvedScriptDir = entry.scriptDir;
|
|
17497
18664
|
resolved._resolvedScriptsSource = `compatibility:${entry.ideVersion}`;
|
|
17498
18665
|
if (providerDir) {
|
|
17499
|
-
const fullDir =
|
|
17500
|
-
resolved._resolvedScriptsPath = fs7.existsSync(
|
|
18666
|
+
const fullDir = path17.join(providerDir, entry.scriptDir);
|
|
18667
|
+
resolved._resolvedScriptsPath = fs7.existsSync(path17.join(fullDir, "scripts.js")) ? path17.join(fullDir, "scripts.js") : fullDir;
|
|
17501
18668
|
}
|
|
17502
18669
|
matched = true;
|
|
17503
18670
|
}
|
|
@@ -17512,8 +18679,8 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
17512
18679
|
resolved._resolvedScriptDir = base.defaultScriptDir;
|
|
17513
18680
|
resolved._resolvedScriptsSource = "defaultScriptDir:version_miss";
|
|
17514
18681
|
if (providerDir) {
|
|
17515
|
-
const fullDir =
|
|
17516
|
-
resolved._resolvedScriptsPath = fs7.existsSync(
|
|
18682
|
+
const fullDir = path17.join(providerDir, base.defaultScriptDir);
|
|
18683
|
+
resolved._resolvedScriptsPath = fs7.existsSync(path17.join(fullDir, "scripts.js")) ? path17.join(fullDir, "scripts.js") : fullDir;
|
|
17517
18684
|
}
|
|
17518
18685
|
}
|
|
17519
18686
|
resolved._versionWarning = `Version ${currentVersion} not in compatibility matrix. Using default scripts.`;
|
|
@@ -17530,8 +18697,8 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
17530
18697
|
resolved._resolvedScriptDir = dirOverride;
|
|
17531
18698
|
resolved._resolvedScriptsSource = `versions:${range}`;
|
|
17532
18699
|
if (providerDir) {
|
|
17533
|
-
const fullDir =
|
|
17534
|
-
resolved._resolvedScriptsPath = fs7.existsSync(
|
|
18700
|
+
const fullDir = path17.join(providerDir, dirOverride);
|
|
18701
|
+
resolved._resolvedScriptsPath = fs7.existsSync(path17.join(fullDir, "scripts.js")) ? path17.join(fullDir, "scripts.js") : fullDir;
|
|
17535
18702
|
}
|
|
17536
18703
|
}
|
|
17537
18704
|
} else if (override.scripts) {
|
|
@@ -17547,8 +18714,8 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
17547
18714
|
resolved._resolvedScriptDir = base.defaultScriptDir;
|
|
17548
18715
|
resolved._resolvedScriptsSource = "defaultScriptDir:no_version";
|
|
17549
18716
|
if (providerDir) {
|
|
17550
|
-
const fullDir =
|
|
17551
|
-
resolved._resolvedScriptsPath = fs7.existsSync(
|
|
18717
|
+
const fullDir = path17.join(providerDir, base.defaultScriptDir);
|
|
18718
|
+
resolved._resolvedScriptsPath = fs7.existsSync(path17.join(fullDir, "scripts.js")) ? path17.join(fullDir, "scripts.js") : fullDir;
|
|
17552
18719
|
}
|
|
17553
18720
|
}
|
|
17554
18721
|
}
|
|
@@ -17580,14 +18747,14 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
17580
18747
|
this.log(` [loadScriptsFromDir] ${type}: providerDir not found`);
|
|
17581
18748
|
return null;
|
|
17582
18749
|
}
|
|
17583
|
-
const dir =
|
|
18750
|
+
const dir = path17.join(providerDir, scriptDir);
|
|
17584
18751
|
if (!fs7.existsSync(dir)) {
|
|
17585
18752
|
this.log(` [loadScriptsFromDir] ${type}: dir not found: ${dir}`);
|
|
17586
18753
|
return null;
|
|
17587
18754
|
}
|
|
17588
18755
|
const cached = this.scriptsCache.get(dir);
|
|
17589
18756
|
if (cached) return cached;
|
|
17590
|
-
const scriptsJs =
|
|
18757
|
+
const scriptsJs = path17.join(dir, "scripts.js");
|
|
17591
18758
|
if (fs7.existsSync(scriptsJs)) {
|
|
17592
18759
|
try {
|
|
17593
18760
|
delete __require.cache[__require.resolve(scriptsJs)];
|
|
@@ -17629,7 +18796,7 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
17629
18796
|
return;
|
|
17630
18797
|
}
|
|
17631
18798
|
if (filePath.endsWith(".js") || filePath.endsWith(".json")) {
|
|
17632
|
-
this.log(`File changed: ${
|
|
18799
|
+
this.log(`File changed: ${path17.basename(filePath)}, reloading...`);
|
|
17633
18800
|
this.reload();
|
|
17634
18801
|
}
|
|
17635
18802
|
};
|
|
@@ -17684,7 +18851,7 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
17684
18851
|
}
|
|
17685
18852
|
const https = __require("https");
|
|
17686
18853
|
const { execSync: execSync7 } = __require("child_process");
|
|
17687
|
-
const metaPath =
|
|
18854
|
+
const metaPath = path17.join(this.upstreamDir, _ProviderLoader.META_FILE);
|
|
17688
18855
|
let prevEtag = "";
|
|
17689
18856
|
let prevTimestamp = 0;
|
|
17690
18857
|
try {
|
|
@@ -17701,7 +18868,7 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
17701
18868
|
return { updated: false };
|
|
17702
18869
|
}
|
|
17703
18870
|
try {
|
|
17704
|
-
const etag = await new Promise((
|
|
18871
|
+
const etag = await new Promise((resolve15, reject) => {
|
|
17705
18872
|
const options = {
|
|
17706
18873
|
method: "HEAD",
|
|
17707
18874
|
hostname: "github.com",
|
|
@@ -17719,7 +18886,7 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
17719
18886
|
headers: { "User-Agent": "adhdev-launcher" },
|
|
17720
18887
|
timeout: 1e4
|
|
17721
18888
|
}, (res2) => {
|
|
17722
|
-
|
|
18889
|
+
resolve15(res2.headers.etag || res2.headers["last-modified"] || "");
|
|
17723
18890
|
});
|
|
17724
18891
|
req2.on("error", reject);
|
|
17725
18892
|
req2.on("timeout", () => {
|
|
@@ -17728,7 +18895,7 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
17728
18895
|
});
|
|
17729
18896
|
req2.end();
|
|
17730
18897
|
} else {
|
|
17731
|
-
|
|
18898
|
+
resolve15(res.headers.etag || res.headers["last-modified"] || "");
|
|
17732
18899
|
}
|
|
17733
18900
|
});
|
|
17734
18901
|
req.on("error", reject);
|
|
@@ -17744,17 +18911,17 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
17744
18911
|
return { updated: false };
|
|
17745
18912
|
}
|
|
17746
18913
|
this.log("Downloading latest providers from GitHub...");
|
|
17747
|
-
const tmpTar =
|
|
17748
|
-
const tmpExtract =
|
|
18914
|
+
const tmpTar = path17.join(os14.tmpdir(), `adhdev-providers-${Date.now()}.tar.gz`);
|
|
18915
|
+
const tmpExtract = path17.join(os14.tmpdir(), `adhdev-providers-extract-${Date.now()}`);
|
|
17749
18916
|
await this.downloadFile(_ProviderLoader.GITHUB_TARBALL_URL, tmpTar);
|
|
17750
18917
|
fs7.mkdirSync(tmpExtract, { recursive: true });
|
|
17751
18918
|
execSync7(`tar -xzf "${tmpTar}" -C "${tmpExtract}"`, { timeout: 3e4 });
|
|
17752
18919
|
const extracted = fs7.readdirSync(tmpExtract);
|
|
17753
18920
|
const rootDir = extracted.find(
|
|
17754
|
-
(d) => fs7.statSync(
|
|
18921
|
+
(d) => fs7.statSync(path17.join(tmpExtract, d)).isDirectory() && d.startsWith("adhdev-providers")
|
|
17755
18922
|
);
|
|
17756
18923
|
if (!rootDir) throw new Error("Unexpected tarball structure");
|
|
17757
|
-
const sourceDir =
|
|
18924
|
+
const sourceDir = path17.join(tmpExtract, rootDir);
|
|
17758
18925
|
const backupDir = this.upstreamDir + ".bak";
|
|
17759
18926
|
if (fs7.existsSync(this.upstreamDir)) {
|
|
17760
18927
|
if (fs7.existsSync(backupDir)) fs7.rmSync(backupDir, { recursive: true, force: true });
|
|
@@ -17792,7 +18959,7 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
17792
18959
|
downloadFile(url, destPath) {
|
|
17793
18960
|
const https = __require("https");
|
|
17794
18961
|
const http3 = __require("http");
|
|
17795
|
-
return new Promise((
|
|
18962
|
+
return new Promise((resolve15, reject) => {
|
|
17796
18963
|
const doRequest = (reqUrl, redirectCount = 0) => {
|
|
17797
18964
|
if (redirectCount > 5) {
|
|
17798
18965
|
reject(new Error("Too many redirects"));
|
|
@@ -17812,7 +18979,7 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
17812
18979
|
res.pipe(ws);
|
|
17813
18980
|
ws.on("finish", () => {
|
|
17814
18981
|
ws.close();
|
|
17815
|
-
|
|
18982
|
+
resolve15();
|
|
17816
18983
|
});
|
|
17817
18984
|
ws.on("error", reject);
|
|
17818
18985
|
});
|
|
@@ -17829,8 +18996,8 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
17829
18996
|
copyDirRecursive(src, dest) {
|
|
17830
18997
|
fs7.mkdirSync(dest, { recursive: true });
|
|
17831
18998
|
for (const entry of fs7.readdirSync(src, { withFileTypes: true })) {
|
|
17832
|
-
const srcPath =
|
|
17833
|
-
const destPath =
|
|
18999
|
+
const srcPath = path17.join(src, entry.name);
|
|
19000
|
+
const destPath = path17.join(dest, entry.name);
|
|
17834
19001
|
if (entry.isDirectory()) {
|
|
17835
19002
|
this.copyDirRecursive(srcPath, destPath);
|
|
17836
19003
|
} else {
|
|
@@ -17841,7 +19008,7 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
17841
19008
|
/** .meta.json save */
|
|
17842
19009
|
writeMeta(metaPath, etag, timestamp) {
|
|
17843
19010
|
try {
|
|
17844
|
-
fs7.mkdirSync(
|
|
19011
|
+
fs7.mkdirSync(path17.dirname(metaPath), { recursive: true });
|
|
17845
19012
|
fs7.writeFileSync(metaPath, JSON.stringify({
|
|
17846
19013
|
etag,
|
|
17847
19014
|
timestamp,
|
|
@@ -17858,7 +19025,7 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
17858
19025
|
const scan = (d) => {
|
|
17859
19026
|
try {
|
|
17860
19027
|
for (const entry of fs7.readdirSync(d, { withFileTypes: true })) {
|
|
17861
|
-
if (entry.isDirectory()) scan(
|
|
19028
|
+
if (entry.isDirectory()) scan(path17.join(d, entry.name));
|
|
17862
19029
|
else if (entry.name === "provider.json") count++;
|
|
17863
19030
|
}
|
|
17864
19031
|
} catch {
|
|
@@ -18086,17 +19253,17 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
18086
19253
|
for (const root of searchRoots) {
|
|
18087
19254
|
if (!fs7.existsSync(root)) continue;
|
|
18088
19255
|
const candidate = this.getProviderDir(root, cat, type);
|
|
18089
|
-
if (fs7.existsSync(
|
|
18090
|
-
const catDir =
|
|
19256
|
+
if (fs7.existsSync(path17.join(candidate, "provider.json"))) return candidate;
|
|
19257
|
+
const catDir = path17.join(root, cat);
|
|
18091
19258
|
if (fs7.existsSync(catDir)) {
|
|
18092
19259
|
try {
|
|
18093
19260
|
for (const entry of fs7.readdirSync(catDir, { withFileTypes: true })) {
|
|
18094
19261
|
if (!entry.isDirectory()) continue;
|
|
18095
|
-
const jsonPath =
|
|
19262
|
+
const jsonPath = path17.join(catDir, entry.name, "provider.json");
|
|
18096
19263
|
if (fs7.existsSync(jsonPath)) {
|
|
18097
19264
|
try {
|
|
18098
19265
|
const data = JSON.parse(fs7.readFileSync(jsonPath, "utf-8"));
|
|
18099
|
-
if (data.type === type) return
|
|
19266
|
+
if (data.type === type) return path17.join(catDir, entry.name);
|
|
18100
19267
|
} catch {
|
|
18101
19268
|
}
|
|
18102
19269
|
}
|
|
@@ -18113,7 +19280,7 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
18113
19280
|
* (template substitution is NOT applied here — scripts.js handles that)
|
|
18114
19281
|
*/
|
|
18115
19282
|
buildScriptWrappersFromDir(dir) {
|
|
18116
|
-
const scriptsJs =
|
|
19283
|
+
const scriptsJs = path17.join(dir, "scripts.js");
|
|
18117
19284
|
if (fs7.existsSync(scriptsJs)) {
|
|
18118
19285
|
try {
|
|
18119
19286
|
delete __require.cache[__require.resolve(scriptsJs)];
|
|
@@ -18127,7 +19294,7 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
18127
19294
|
for (const file of fs7.readdirSync(dir)) {
|
|
18128
19295
|
if (!file.endsWith(".js")) continue;
|
|
18129
19296
|
const scriptName = toCamel(file.replace(".js", ""));
|
|
18130
|
-
const filePath =
|
|
19297
|
+
const filePath = path17.join(dir, file);
|
|
18131
19298
|
result[scriptName] = (...args) => {
|
|
18132
19299
|
try {
|
|
18133
19300
|
let content = fs7.readFileSync(filePath, "utf-8");
|
|
@@ -18187,7 +19354,7 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
18187
19354
|
}
|
|
18188
19355
|
const hasJson = entries.some((e) => e.name === "provider.json");
|
|
18189
19356
|
if (hasJson) {
|
|
18190
|
-
const jsonPath =
|
|
19357
|
+
const jsonPath = path17.join(d, "provider.json");
|
|
18191
19358
|
try {
|
|
18192
19359
|
const raw = fs7.readFileSync(jsonPath, "utf-8");
|
|
18193
19360
|
const mod = JSON.parse(raw);
|
|
@@ -18208,7 +19375,7 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
18208
19375
|
this.log(`\u26A0 Invalid provider at ${jsonPath}: ${validation.errors.join("; ")}`);
|
|
18209
19376
|
} else {
|
|
18210
19377
|
const hasCompatibility = Array.isArray(normalizedProvider.compatibility);
|
|
18211
|
-
const scriptsPath =
|
|
19378
|
+
const scriptsPath = path17.join(d, "scripts.js");
|
|
18212
19379
|
if (!hasCompatibility && fs7.existsSync(scriptsPath)) {
|
|
18213
19380
|
try {
|
|
18214
19381
|
delete __require.cache[__require.resolve(scriptsPath)];
|
|
@@ -18234,7 +19401,7 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
18234
19401
|
if (!entry.isDirectory()) continue;
|
|
18235
19402
|
if (entry.name.startsWith("_") || entry.name.startsWith(".")) continue;
|
|
18236
19403
|
if (excludeDirs && d === dir && excludeDirs.includes(entry.name)) continue;
|
|
18237
|
-
scan(
|
|
19404
|
+
scan(path17.join(d, entry.name));
|
|
18238
19405
|
}
|
|
18239
19406
|
}
|
|
18240
19407
|
};
|
|
@@ -18269,9 +19436,9 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
18269
19436
|
}
|
|
18270
19437
|
}
|
|
18271
19438
|
compareVersions(a, b) {
|
|
18272
|
-
const
|
|
18273
|
-
const pa =
|
|
18274
|
-
const pb =
|
|
19439
|
+
const normalize4 = (v) => v.split(/[-_+]/)[0].split(".").map((x) => parseInt(x, 10) || 0);
|
|
19440
|
+
const pa = normalize4(a);
|
|
19441
|
+
const pb = normalize4(b);
|
|
18275
19442
|
for (let i = 0; i < Math.max(pa.length, pb.length); i++) {
|
|
18276
19443
|
const va = pa[i] || 0;
|
|
18277
19444
|
const vb = pb[i] || 0;
|
|
@@ -18391,17 +19558,17 @@ async function findFreePort(ports) {
|
|
|
18391
19558
|
throw new Error("No free port found");
|
|
18392
19559
|
}
|
|
18393
19560
|
function checkPortFree(port) {
|
|
18394
|
-
return new Promise((
|
|
19561
|
+
return new Promise((resolve15) => {
|
|
18395
19562
|
const server = net.createServer();
|
|
18396
19563
|
server.unref();
|
|
18397
|
-
server.on("error", () =>
|
|
19564
|
+
server.on("error", () => resolve15(false));
|
|
18398
19565
|
server.listen(port, "127.0.0.1", () => {
|
|
18399
|
-
server.close(() =>
|
|
19566
|
+
server.close(() => resolve15(true));
|
|
18400
19567
|
});
|
|
18401
19568
|
});
|
|
18402
19569
|
}
|
|
18403
19570
|
async function isCdpActive(port) {
|
|
18404
|
-
return new Promise((
|
|
19571
|
+
return new Promise((resolve15) => {
|
|
18405
19572
|
const req = __require("http").get(`http://127.0.0.1:${port}/json/version`, {
|
|
18406
19573
|
timeout: 2e3
|
|
18407
19574
|
}, (res) => {
|
|
@@ -18410,16 +19577,16 @@ async function isCdpActive(port) {
|
|
|
18410
19577
|
res.on("end", () => {
|
|
18411
19578
|
try {
|
|
18412
19579
|
const info = JSON.parse(data);
|
|
18413
|
-
|
|
19580
|
+
resolve15(!!info["WebKit-Version"] || !!info["Browser"]);
|
|
18414
19581
|
} catch {
|
|
18415
|
-
|
|
19582
|
+
resolve15(false);
|
|
18416
19583
|
}
|
|
18417
19584
|
});
|
|
18418
19585
|
});
|
|
18419
|
-
req.on("error", () =>
|
|
19586
|
+
req.on("error", () => resolve15(false));
|
|
18420
19587
|
req.on("timeout", () => {
|
|
18421
19588
|
req.destroy();
|
|
18422
|
-
|
|
19589
|
+
resolve15(false);
|
|
18423
19590
|
});
|
|
18424
19591
|
});
|
|
18425
19592
|
}
|
|
@@ -18559,8 +19726,8 @@ function detectCurrentWorkspace(ideId) {
|
|
|
18559
19726
|
const appNameMap = getMacAppIdentifiers();
|
|
18560
19727
|
const appName = appNameMap[ideId];
|
|
18561
19728
|
if (appName) {
|
|
18562
|
-
const storagePath =
|
|
18563
|
-
process.env.APPDATA ||
|
|
19729
|
+
const storagePath = path18.join(
|
|
19730
|
+
process.env.APPDATA || path18.join(os15.homedir(), "AppData", "Roaming"),
|
|
18564
19731
|
appName,
|
|
18565
19732
|
"storage.json"
|
|
18566
19733
|
);
|
|
@@ -18738,9 +19905,9 @@ init_logger();
|
|
|
18738
19905
|
|
|
18739
19906
|
// src/logging/command-log.ts
|
|
18740
19907
|
import * as fs8 from "fs";
|
|
18741
|
-
import * as
|
|
19908
|
+
import * as path19 from "path";
|
|
18742
19909
|
import * as os16 from "os";
|
|
18743
|
-
var LOG_DIR2 = process.platform === "win32" ?
|
|
19910
|
+
var LOG_DIR2 = process.platform === "win32" ? path19.join(process.env.LOCALAPPDATA || process.env.APPDATA || path19.join(os16.homedir(), "AppData", "Local"), "adhdev", "logs") : process.platform === "darwin" ? path19.join(os16.homedir(), "Library", "Logs", "adhdev") : path19.join(os16.homedir(), ".local", "share", "adhdev", "logs");
|
|
18744
19911
|
var MAX_FILE_SIZE = 5 * 1024 * 1024;
|
|
18745
19912
|
var MAX_DAYS = 7;
|
|
18746
19913
|
try {
|
|
@@ -18778,13 +19945,13 @@ function getDateStr2() {
|
|
|
18778
19945
|
return (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
|
|
18779
19946
|
}
|
|
18780
19947
|
var currentDate2 = getDateStr2();
|
|
18781
|
-
var currentFile =
|
|
19948
|
+
var currentFile = path19.join(LOG_DIR2, `commands-${currentDate2}.jsonl`);
|
|
18782
19949
|
var writeCount2 = 0;
|
|
18783
19950
|
function checkRotation() {
|
|
18784
19951
|
const today = getDateStr2();
|
|
18785
19952
|
if (today !== currentDate2) {
|
|
18786
19953
|
currentDate2 = today;
|
|
18787
|
-
currentFile =
|
|
19954
|
+
currentFile = path19.join(LOG_DIR2, `commands-${currentDate2}.jsonl`);
|
|
18788
19955
|
cleanOldFiles();
|
|
18789
19956
|
}
|
|
18790
19957
|
}
|
|
@@ -18798,7 +19965,7 @@ function cleanOldFiles() {
|
|
|
18798
19965
|
const dateMatch = file.match(/commands-(\d{4}-\d{2}-\d{2})/);
|
|
18799
19966
|
if (dateMatch && dateMatch[1] < cutoffStr) {
|
|
18800
19967
|
try {
|
|
18801
|
-
fs8.unlinkSync(
|
|
19968
|
+
fs8.unlinkSync(path19.join(LOG_DIR2, file));
|
|
18802
19969
|
} catch {
|
|
18803
19970
|
}
|
|
18804
19971
|
}
|
|
@@ -18808,8 +19975,8 @@ function cleanOldFiles() {
|
|
|
18808
19975
|
}
|
|
18809
19976
|
function checkSize() {
|
|
18810
19977
|
try {
|
|
18811
|
-
const
|
|
18812
|
-
if (
|
|
19978
|
+
const stat2 = fs8.statSync(currentFile);
|
|
19979
|
+
if (stat2.size > MAX_FILE_SIZE) {
|
|
18813
19980
|
const backup = currentFile.replace(".jsonl", ".1.jsonl");
|
|
18814
19981
|
try {
|
|
18815
19982
|
fs8.unlinkSync(backup);
|
|
@@ -19095,12 +20262,18 @@ function buildStatusSnapshot(options) {
|
|
|
19095
20262
|
const unreadSourceSessions = buildSessionEntries(
|
|
19096
20263
|
options.allStates,
|
|
19097
20264
|
options.cdpManagers,
|
|
19098
|
-
{
|
|
20265
|
+
{
|
|
20266
|
+
profile: "full",
|
|
20267
|
+
getGitSummaryForWorkspace: options.getGitSummaryForWorkspace
|
|
20268
|
+
}
|
|
19099
20269
|
);
|
|
19100
20270
|
const sessions = profile === "full" ? unreadSourceSessions : profile === "live" ? unreadSourceSessions.map(projectLiveSessionFromFull) : buildSessionEntries(
|
|
19101
20271
|
options.allStates,
|
|
19102
20272
|
options.cdpManagers,
|
|
19103
|
-
{
|
|
20273
|
+
{
|
|
20274
|
+
profile,
|
|
20275
|
+
getGitSummaryForWorkspace: options.getGitSummaryForWorkspace
|
|
20276
|
+
}
|
|
19104
20277
|
);
|
|
19105
20278
|
const sessionsById = new Map(sessions.map((session) => [session.id, session]));
|
|
19106
20279
|
for (const sourceSession of unreadSourceSessions) {
|
|
@@ -19194,13 +20367,13 @@ import { execFileSync as execFileSync2 } from "child_process";
|
|
|
19194
20367
|
import { spawn as spawn3 } from "child_process";
|
|
19195
20368
|
import * as fs9 from "fs";
|
|
19196
20369
|
import * as os18 from "os";
|
|
19197
|
-
import * as
|
|
20370
|
+
import * as path20 from "path";
|
|
19198
20371
|
var UPGRADE_HELPER_ENV = "ADHDEV_DAEMON_UPGRADE_HELPER";
|
|
19199
20372
|
function getUpgradeLogPath() {
|
|
19200
20373
|
const home = os18.homedir();
|
|
19201
|
-
const dir =
|
|
20374
|
+
const dir = path20.join(home, ".adhdev");
|
|
19202
20375
|
fs9.mkdirSync(dir, { recursive: true });
|
|
19203
|
-
return
|
|
20376
|
+
return path20.join(dir, "daemon-upgrade.log");
|
|
19204
20377
|
}
|
|
19205
20378
|
function appendUpgradeLog(message) {
|
|
19206
20379
|
const line = `[${(/* @__PURE__ */ new Date()).toISOString()}] ${message}
|
|
@@ -19211,14 +20384,14 @@ function appendUpgradeLog(message) {
|
|
|
19211
20384
|
}
|
|
19212
20385
|
}
|
|
19213
20386
|
function resolveSiblingNpmInvocation(nodeExecutable, platform10 = process.platform) {
|
|
19214
|
-
const binDir =
|
|
20387
|
+
const binDir = path20.dirname(nodeExecutable);
|
|
19215
20388
|
if (platform10 === "win32") {
|
|
19216
|
-
const npmCliPath =
|
|
20389
|
+
const npmCliPath = path20.join(binDir, "node_modules", "npm", "bin", "npm-cli.js");
|
|
19217
20390
|
if (fs9.existsSync(npmCliPath)) {
|
|
19218
20391
|
return { executable: nodeExecutable, argsPrefix: [npmCliPath], execOptions: getNpmExecOptions(platform10) };
|
|
19219
20392
|
}
|
|
19220
20393
|
for (const candidate of ["npm.exe", "npm"]) {
|
|
19221
|
-
const candidatePath =
|
|
20394
|
+
const candidatePath = path20.join(binDir, candidate);
|
|
19222
20395
|
if (fs9.existsSync(candidatePath)) {
|
|
19223
20396
|
return { executable: candidatePath, argsPrefix: [], execOptions: getNpmExecOptions(platform10) };
|
|
19224
20397
|
}
|
|
@@ -19226,7 +20399,7 @@ function resolveSiblingNpmInvocation(nodeExecutable, platform10 = process.platfo
|
|
|
19226
20399
|
return { executable: nodeExecutable, argsPrefix: [npmCliPath], execOptions: getNpmExecOptions(platform10) };
|
|
19227
20400
|
}
|
|
19228
20401
|
for (const candidate of ["npm"]) {
|
|
19229
|
-
const candidatePath =
|
|
20402
|
+
const candidatePath = path20.join(binDir, candidate);
|
|
19230
20403
|
if (fs9.existsSync(candidatePath)) {
|
|
19231
20404
|
return { executable: candidatePath, argsPrefix: [], execOptions: getNpmExecOptions(platform10) };
|
|
19232
20405
|
}
|
|
@@ -19243,13 +20416,13 @@ function findCurrentPackageRoot(currentCliPath, packageName) {
|
|
|
19243
20416
|
let currentDir = resolvedPath;
|
|
19244
20417
|
try {
|
|
19245
20418
|
if (fs9.statSync(resolvedPath).isFile()) {
|
|
19246
|
-
currentDir =
|
|
20419
|
+
currentDir = path20.dirname(resolvedPath);
|
|
19247
20420
|
}
|
|
19248
20421
|
} catch {
|
|
19249
|
-
currentDir =
|
|
20422
|
+
currentDir = path20.dirname(resolvedPath);
|
|
19250
20423
|
}
|
|
19251
20424
|
while (true) {
|
|
19252
|
-
const packageJsonPath =
|
|
20425
|
+
const packageJsonPath = path20.join(currentDir, "package.json");
|
|
19253
20426
|
try {
|
|
19254
20427
|
if (fs9.existsSync(packageJsonPath)) {
|
|
19255
20428
|
const parsed = JSON.parse(fs9.readFileSync(packageJsonPath, "utf8"));
|
|
@@ -19260,7 +20433,7 @@ function findCurrentPackageRoot(currentCliPath, packageName) {
|
|
|
19260
20433
|
}
|
|
19261
20434
|
} catch {
|
|
19262
20435
|
}
|
|
19263
|
-
const parentDir =
|
|
20436
|
+
const parentDir = path20.dirname(currentDir);
|
|
19264
20437
|
if (parentDir === currentDir) {
|
|
19265
20438
|
return null;
|
|
19266
20439
|
}
|
|
@@ -19268,13 +20441,13 @@ function findCurrentPackageRoot(currentCliPath, packageName) {
|
|
|
19268
20441
|
}
|
|
19269
20442
|
}
|
|
19270
20443
|
function resolveInstallPrefixFromPackageRoot(packageRoot, packageName) {
|
|
19271
|
-
const nodeModulesDir = packageName.startsWith("@") ?
|
|
19272
|
-
if (
|
|
20444
|
+
const nodeModulesDir = packageName.startsWith("@") ? path20.dirname(path20.dirname(packageRoot)) : path20.dirname(packageRoot);
|
|
20445
|
+
if (path20.basename(nodeModulesDir) !== "node_modules") {
|
|
19273
20446
|
return null;
|
|
19274
20447
|
}
|
|
19275
|
-
const maybeLibDir =
|
|
19276
|
-
if (
|
|
19277
|
-
return
|
|
20448
|
+
const maybeLibDir = path20.dirname(nodeModulesDir);
|
|
20449
|
+
if (path20.basename(maybeLibDir) === "lib") {
|
|
20450
|
+
return path20.dirname(maybeLibDir);
|
|
19278
20451
|
}
|
|
19279
20452
|
return maybeLibDir;
|
|
19280
20453
|
}
|
|
@@ -19382,14 +20555,14 @@ async function waitForPidExit(pid, timeoutMs) {
|
|
|
19382
20555
|
while (Date.now() - start < timeoutMs) {
|
|
19383
20556
|
try {
|
|
19384
20557
|
process.kill(pid, 0);
|
|
19385
|
-
await new Promise((
|
|
20558
|
+
await new Promise((resolve15) => setTimeout(resolve15, 250));
|
|
19386
20559
|
} catch {
|
|
19387
20560
|
return;
|
|
19388
20561
|
}
|
|
19389
20562
|
}
|
|
19390
20563
|
}
|
|
19391
20564
|
function stopSessionHostProcesses(appName) {
|
|
19392
|
-
const pidFile =
|
|
20565
|
+
const pidFile = path20.join(os18.homedir(), ".adhdev", `${appName}-session-host.pid`);
|
|
19393
20566
|
try {
|
|
19394
20567
|
if (fs9.existsSync(pidFile)) {
|
|
19395
20568
|
const pid = Number.parseInt(fs9.readFileSync(pidFile, "utf8").trim(), 10);
|
|
@@ -19406,7 +20579,7 @@ function stopSessionHostProcesses(appName) {
|
|
|
19406
20579
|
}
|
|
19407
20580
|
}
|
|
19408
20581
|
function removeDaemonPidFile() {
|
|
19409
|
-
const pidFile =
|
|
20582
|
+
const pidFile = path20.join(os18.homedir(), ".adhdev", "daemon.pid");
|
|
19410
20583
|
try {
|
|
19411
20584
|
fs9.unlinkSync(pidFile);
|
|
19412
20585
|
} catch {
|
|
@@ -19417,7 +20590,7 @@ function cleanupStaleGlobalInstallDirs(pkgName, surface) {
|
|
|
19417
20590
|
const npmRoot = String(execNpmCommandSync(["root", "-g", ...prefixArgs], { encoding: "utf8" }, surface)).trim();
|
|
19418
20591
|
if (!npmRoot) return;
|
|
19419
20592
|
const npmPrefix = surface.installPrefix || String(execNpmCommandSync(["prefix", "-g", ...prefixArgs], { encoding: "utf8" }, surface)).trim();
|
|
19420
|
-
const binDir = process.platform === "win32" ? npmPrefix :
|
|
20593
|
+
const binDir = process.platform === "win32" ? npmPrefix : path20.join(npmPrefix, "bin");
|
|
19421
20594
|
const packageBaseName = pkgName.startsWith("@") ? pkgName.split("/")[1] : pkgName;
|
|
19422
20595
|
const binNames = /* @__PURE__ */ new Set([packageBaseName]);
|
|
19423
20596
|
if (pkgName === "@adhdev/daemon-standalone") {
|
|
@@ -19425,25 +20598,25 @@ function cleanupStaleGlobalInstallDirs(pkgName, surface) {
|
|
|
19425
20598
|
}
|
|
19426
20599
|
if (pkgName.startsWith("@")) {
|
|
19427
20600
|
const [scope, name] = pkgName.split("/");
|
|
19428
|
-
const scopeDir =
|
|
20601
|
+
const scopeDir = path20.join(npmRoot, scope);
|
|
19429
20602
|
if (!fs9.existsSync(scopeDir)) return;
|
|
19430
20603
|
for (const entry of fs9.readdirSync(scopeDir)) {
|
|
19431
20604
|
if (!entry.startsWith(`.${name}-`)) continue;
|
|
19432
|
-
fs9.rmSync(
|
|
19433
|
-
appendUpgradeLog(`Removed stale scoped staging dir: ${
|
|
20605
|
+
fs9.rmSync(path20.join(scopeDir, entry), { recursive: true, force: true });
|
|
20606
|
+
appendUpgradeLog(`Removed stale scoped staging dir: ${path20.join(scopeDir, entry)}`);
|
|
19434
20607
|
}
|
|
19435
20608
|
} else {
|
|
19436
20609
|
for (const entry of fs9.readdirSync(npmRoot)) {
|
|
19437
20610
|
if (!entry.startsWith(`.${pkgName}-`)) continue;
|
|
19438
|
-
fs9.rmSync(
|
|
19439
|
-
appendUpgradeLog(`Removed stale staging dir: ${
|
|
20611
|
+
fs9.rmSync(path20.join(npmRoot, entry), { recursive: true, force: true });
|
|
20612
|
+
appendUpgradeLog(`Removed stale staging dir: ${path20.join(npmRoot, entry)}`);
|
|
19440
20613
|
}
|
|
19441
20614
|
}
|
|
19442
20615
|
if (fs9.existsSync(binDir)) {
|
|
19443
20616
|
for (const entry of fs9.readdirSync(binDir)) {
|
|
19444
20617
|
if (!Array.from(binNames).some((name) => entry.startsWith(`.${name}-`))) continue;
|
|
19445
|
-
fs9.rmSync(
|
|
19446
|
-
appendUpgradeLog(`Removed stale bin staging entry: ${
|
|
20618
|
+
fs9.rmSync(path20.join(binDir, entry), { recursive: true, force: true });
|
|
20619
|
+
appendUpgradeLog(`Removed stale bin staging entry: ${path20.join(binDir, entry)}`);
|
|
19447
20620
|
}
|
|
19448
20621
|
}
|
|
19449
20622
|
}
|
|
@@ -19493,7 +20666,7 @@ async function runDaemonUpgradeHelper(payload) {
|
|
|
19493
20666
|
appendUpgradeLog(installOutput.trim());
|
|
19494
20667
|
}
|
|
19495
20668
|
if (process.platform === "win32") {
|
|
19496
|
-
await new Promise((
|
|
20669
|
+
await new Promise((resolve15) => setTimeout(resolve15, 500));
|
|
19497
20670
|
cleanupStaleGlobalInstallDirs(payload.packageName, installCommand.surface);
|
|
19498
20671
|
appendUpgradeLog("Post-install staging cleanup complete");
|
|
19499
20672
|
}
|
|
@@ -20887,7 +22060,7 @@ var ProviderStreamAdapter = class {
|
|
|
20887
22060
|
const beforeCount = this.messageCount(before);
|
|
20888
22061
|
const beforeSignature = this.lastMessageSignature(before);
|
|
20889
22062
|
for (let attempt = 0; attempt < 12; attempt += 1) {
|
|
20890
|
-
await new Promise((
|
|
22063
|
+
await new Promise((resolve15) => setTimeout(resolve15, 250));
|
|
20891
22064
|
let state;
|
|
20892
22065
|
try {
|
|
20893
22066
|
state = await this.readChat(evaluate);
|
|
@@ -20909,7 +22082,7 @@ var ProviderStreamAdapter = class {
|
|
|
20909
22082
|
if (this.messageCount(first) > 0 || this.lastMessageSignature(first)) {
|
|
20910
22083
|
return first;
|
|
20911
22084
|
}
|
|
20912
|
-
await new Promise((
|
|
22085
|
+
await new Promise((resolve15) => setTimeout(resolve15, 150));
|
|
20913
22086
|
const second = await this.readChat(evaluate);
|
|
20914
22087
|
return this.messageCount(second) >= this.messageCount(first) ? second : first;
|
|
20915
22088
|
}
|
|
@@ -21060,7 +22233,7 @@ var ProviderStreamAdapter = class {
|
|
|
21060
22233
|
if (typeof data.error === "string" && data.error.trim()) return false;
|
|
21061
22234
|
}
|
|
21062
22235
|
for (let attempt = 0; attempt < 6; attempt += 1) {
|
|
21063
|
-
await new Promise((
|
|
22236
|
+
await new Promise((resolve15) => setTimeout(resolve15, 250));
|
|
21064
22237
|
const state = await this.readChat(evaluate);
|
|
21065
22238
|
const title = this.getStateTitle(state);
|
|
21066
22239
|
if (this.titlesMatch(title, sessionId)) return true;
|
|
@@ -21921,11 +23094,11 @@ init_chat_message_normalization();
|
|
|
21921
23094
|
|
|
21922
23095
|
// src/providers/version-archive.ts
|
|
21923
23096
|
import * as fs11 from "fs";
|
|
21924
|
-
import * as
|
|
23097
|
+
import * as path21 from "path";
|
|
21925
23098
|
import * as os19 from "os";
|
|
21926
23099
|
import { execSync as execSync5 } from "child_process";
|
|
21927
23100
|
import { platform as platform8 } from "os";
|
|
21928
|
-
var ARCHIVE_PATH =
|
|
23101
|
+
var ARCHIVE_PATH = path21.join(os19.homedir(), ".adhdev", "version-history.json");
|
|
21929
23102
|
var MAX_ENTRIES_PER_PROVIDER = 20;
|
|
21930
23103
|
var VersionArchive = class {
|
|
21931
23104
|
history = {};
|
|
@@ -21972,7 +23145,7 @@ var VersionArchive = class {
|
|
|
21972
23145
|
}
|
|
21973
23146
|
save() {
|
|
21974
23147
|
try {
|
|
21975
|
-
fs11.mkdirSync(
|
|
23148
|
+
fs11.mkdirSync(path21.dirname(ARCHIVE_PATH), { recursive: true });
|
|
21976
23149
|
fs11.writeFileSync(ARCHIVE_PATH, JSON.stringify(this.history, null, 2));
|
|
21977
23150
|
} catch {
|
|
21978
23151
|
}
|
|
@@ -22029,7 +23202,7 @@ function checkPathExists2(paths) {
|
|
|
22029
23202
|
for (const p of paths) {
|
|
22030
23203
|
if (p.includes("*")) {
|
|
22031
23204
|
const home = os19.homedir();
|
|
22032
|
-
const resolved = p.replace(/\*/g, home.split(
|
|
23205
|
+
const resolved = p.replace(/\*/g, home.split(path21.sep).pop() || "");
|
|
22033
23206
|
if (fs11.existsSync(resolved)) return resolved;
|
|
22034
23207
|
} else {
|
|
22035
23208
|
if (fs11.existsSync(p)) return p;
|
|
@@ -22039,7 +23212,7 @@ function checkPathExists2(paths) {
|
|
|
22039
23212
|
}
|
|
22040
23213
|
function getMacAppVersion(appPath) {
|
|
22041
23214
|
if (platform8() !== "darwin" || !appPath.endsWith(".app")) return null;
|
|
22042
|
-
const plistPath =
|
|
23215
|
+
const plistPath = path21.join(appPath, "Contents", "Info.plist");
|
|
22043
23216
|
if (!fs11.existsSync(plistPath)) return null;
|
|
22044
23217
|
const raw = runCommand(`/usr/libexec/PlistBuddy -c "Print CFBundleShortVersionString" "${plistPath}"`);
|
|
22045
23218
|
return raw || null;
|
|
@@ -22065,7 +23238,7 @@ async function detectAllVersions(loader, archive) {
|
|
|
22065
23238
|
const cliBin = provider.cli ? findBinary2(provider.cli) : null;
|
|
22066
23239
|
let resolvedBin = cliBin;
|
|
22067
23240
|
if (!resolvedBin && appPath && currentOs === "darwin") {
|
|
22068
|
-
const bundled =
|
|
23241
|
+
const bundled = path21.join(appPath, "Contents", "Resources", "app", "bin", provider.cli || "");
|
|
22069
23242
|
if (provider.cli && fs11.existsSync(bundled)) resolvedBin = bundled;
|
|
22070
23243
|
}
|
|
22071
23244
|
info.installed = !!(appPath || resolvedBin);
|
|
@@ -22106,7 +23279,7 @@ async function detectAllVersions(loader, archive) {
|
|
|
22106
23279
|
// src/daemon/dev-server.ts
|
|
22107
23280
|
import * as http2 from "http";
|
|
22108
23281
|
import * as fs15 from "fs";
|
|
22109
|
-
import * as
|
|
23282
|
+
import * as path25 from "path";
|
|
22110
23283
|
init_config();
|
|
22111
23284
|
|
|
22112
23285
|
// src/daemon/scaffold-template.ts
|
|
@@ -22458,7 +23631,7 @@ init_logger();
|
|
|
22458
23631
|
// src/daemon/dev-cdp-handlers.ts
|
|
22459
23632
|
init_logger();
|
|
22460
23633
|
import * as fs12 from "fs";
|
|
22461
|
-
import * as
|
|
23634
|
+
import * as path22 from "path";
|
|
22462
23635
|
async function handleCdpEvaluate(ctx, req, res) {
|
|
22463
23636
|
const body = await ctx.readBody(req);
|
|
22464
23637
|
const { expression, timeout, ideType } = body;
|
|
@@ -22636,17 +23809,17 @@ async function handleScriptHints(ctx, type, _req, res) {
|
|
|
22636
23809
|
return;
|
|
22637
23810
|
}
|
|
22638
23811
|
let scriptsPath = "";
|
|
22639
|
-
const directScripts =
|
|
23812
|
+
const directScripts = path22.join(dir, "scripts.js");
|
|
22640
23813
|
if (fs12.existsSync(directScripts)) {
|
|
22641
23814
|
scriptsPath = directScripts;
|
|
22642
23815
|
} else {
|
|
22643
|
-
const scriptsDir =
|
|
23816
|
+
const scriptsDir = path22.join(dir, "scripts");
|
|
22644
23817
|
if (fs12.existsSync(scriptsDir)) {
|
|
22645
23818
|
const versions = fs12.readdirSync(scriptsDir).filter((d) => {
|
|
22646
|
-
return fs12.statSync(
|
|
23819
|
+
return fs12.statSync(path22.join(scriptsDir, d)).isDirectory();
|
|
22647
23820
|
}).sort().reverse();
|
|
22648
23821
|
for (const ver of versions) {
|
|
22649
|
-
const p =
|
|
23822
|
+
const p = path22.join(scriptsDir, ver, "scripts.js");
|
|
22650
23823
|
if (fs12.existsSync(p)) {
|
|
22651
23824
|
scriptsPath = p;
|
|
22652
23825
|
break;
|
|
@@ -23475,7 +24648,7 @@ async function handleDomContext(ctx, type, req, res) {
|
|
|
23475
24648
|
|
|
23476
24649
|
// src/daemon/dev-cli-debug.ts
|
|
23477
24650
|
import * as fs13 from "fs";
|
|
23478
|
-
import * as
|
|
24651
|
+
import * as path23 from "path";
|
|
23479
24652
|
function slugifyFixtureName(value) {
|
|
23480
24653
|
const normalized = String(value || "").trim().toLowerCase().replace(/[^a-z0-9._-]+/g, "-").replace(/^-+|-+$/g, "");
|
|
23481
24654
|
return normalized || `fixture-${Date.now()}`;
|
|
@@ -23485,11 +24658,11 @@ function getCliFixtureDir(ctx, type) {
|
|
|
23485
24658
|
if (!providerDir) {
|
|
23486
24659
|
throw new Error(`Provider directory not found for '${type}'`);
|
|
23487
24660
|
}
|
|
23488
|
-
return
|
|
24661
|
+
return path23.join(providerDir, "fixtures");
|
|
23489
24662
|
}
|
|
23490
24663
|
function readCliFixture(ctx, type, name) {
|
|
23491
24664
|
const fixtureDir = getCliFixtureDir(ctx, type);
|
|
23492
|
-
const filePath =
|
|
24665
|
+
const filePath = path23.join(fixtureDir, `${name}.json`);
|
|
23493
24666
|
if (!fs13.existsSync(filePath)) {
|
|
23494
24667
|
throw new Error(`Fixture not found: ${filePath}`);
|
|
23495
24668
|
}
|
|
@@ -23658,7 +24831,7 @@ function getCliTargetBundle(ctx, type, instanceId) {
|
|
|
23658
24831
|
return { target, instance, adapter };
|
|
23659
24832
|
}
|
|
23660
24833
|
function sleep(ms) {
|
|
23661
|
-
return new Promise((
|
|
24834
|
+
return new Promise((resolve15) => setTimeout(resolve15, ms));
|
|
23662
24835
|
}
|
|
23663
24836
|
async function waitForCliReady(ctx, type, instanceId, timeoutMs) {
|
|
23664
24837
|
const startedAt = Date.now();
|
|
@@ -23956,7 +25129,7 @@ async function runCliAutoImplVerification(ctx, type, verification) {
|
|
|
23956
25129
|
return {
|
|
23957
25130
|
mode: "fixture_replay_suite",
|
|
23958
25131
|
pass: results.every((item) => item.pass),
|
|
23959
|
-
failures: results.flatMap((item) => item.failures.map((
|
|
25132
|
+
failures: results.flatMap((item) => item.failures.map((failure2) => `${item.fixtureName}: ${failure2}`)),
|
|
23960
25133
|
result: firstFailure.result,
|
|
23961
25134
|
assertions: firstFailure.assertions,
|
|
23962
25135
|
fixture: firstFailure.fixture,
|
|
@@ -24256,7 +25429,7 @@ async function handleCliFixtureCapture(ctx, req, res) {
|
|
|
24256
25429
|
},
|
|
24257
25430
|
notes: typeof body?.notes === "string" ? body.notes : void 0
|
|
24258
25431
|
};
|
|
24259
|
-
const filePath =
|
|
25432
|
+
const filePath = path23.join(fixtureDir, `${name}.json`);
|
|
24260
25433
|
fs13.writeFileSync(filePath, JSON.stringify(fixture, null, 2));
|
|
24261
25434
|
ctx.json(res, 200, {
|
|
24262
25435
|
saved: true,
|
|
@@ -24280,7 +25453,7 @@ async function handleCliFixtureList(ctx, type, _req, res) {
|
|
|
24280
25453
|
return;
|
|
24281
25454
|
}
|
|
24282
25455
|
const fixtures = fs13.readdirSync(fixtureDir).filter((file) => file.endsWith(".json")).sort((a, b) => b.localeCompare(a, void 0, { numeric: true, sensitivity: "base" })).map((file) => {
|
|
24283
|
-
const fullPath =
|
|
25456
|
+
const fullPath = path23.join(fixtureDir, file);
|
|
24284
25457
|
try {
|
|
24285
25458
|
const raw = JSON.parse(fs13.readFileSync(fullPath, "utf-8"));
|
|
24286
25459
|
return {
|
|
@@ -24416,7 +25589,7 @@ async function handleCliRaw(ctx, req, res) {
|
|
|
24416
25589
|
|
|
24417
25590
|
// src/daemon/dev-auto-implement.ts
|
|
24418
25591
|
import * as fs14 from "fs";
|
|
24419
|
-
import * as
|
|
25592
|
+
import * as path24 from "path";
|
|
24420
25593
|
import * as os20 from "os";
|
|
24421
25594
|
function getAutoImplPid(ctx) {
|
|
24422
25595
|
const pid = ctx.autoImplProcess?.pid;
|
|
@@ -24466,22 +25639,22 @@ function getLatestScriptVersionDir(scriptsDir) {
|
|
|
24466
25639
|
if (!fs14.existsSync(scriptsDir)) return null;
|
|
24467
25640
|
const versions = fs14.readdirSync(scriptsDir).filter((d) => {
|
|
24468
25641
|
try {
|
|
24469
|
-
return fs14.statSync(
|
|
25642
|
+
return fs14.statSync(path24.join(scriptsDir, d)).isDirectory();
|
|
24470
25643
|
} catch {
|
|
24471
25644
|
return false;
|
|
24472
25645
|
}
|
|
24473
25646
|
}).sort((a, b) => b.localeCompare(a, void 0, { numeric: true, sensitivity: "base" }));
|
|
24474
25647
|
if (versions.length === 0) return null;
|
|
24475
|
-
return
|
|
25648
|
+
return path24.join(scriptsDir, versions[0]);
|
|
24476
25649
|
}
|
|
24477
25650
|
function resolveAutoImplWritableProviderDir(ctx, category, type, requestedDir) {
|
|
24478
|
-
const canonicalUserDir =
|
|
24479
|
-
const desiredDir = requestedDir ?
|
|
24480
|
-
const upstreamRoot =
|
|
24481
|
-
if (desiredDir === upstreamRoot || desiredDir.startsWith(`${upstreamRoot}${
|
|
25651
|
+
const canonicalUserDir = path24.resolve(ctx.providerLoader.getUserProviderDir(category, type));
|
|
25652
|
+
const desiredDir = requestedDir ? path24.resolve(requestedDir) : canonicalUserDir;
|
|
25653
|
+
const upstreamRoot = path24.resolve(ctx.providerLoader.getUpstreamDir());
|
|
25654
|
+
if (desiredDir === upstreamRoot || desiredDir.startsWith(`${upstreamRoot}${path24.sep}`)) {
|
|
24482
25655
|
return { dir: null, reason: `Refusing to write into upstream provider directory: ${desiredDir}` };
|
|
24483
25656
|
}
|
|
24484
|
-
if (
|
|
25657
|
+
if (path24.basename(desiredDir) !== type) {
|
|
24485
25658
|
return { dir: null, reason: `Requested writable provider directory must end with '${type}': ${desiredDir}` };
|
|
24486
25659
|
}
|
|
24487
25660
|
const sourceDir = ctx.findProviderDir(type);
|
|
@@ -24489,11 +25662,11 @@ function resolveAutoImplWritableProviderDir(ctx, category, type, requestedDir) {
|
|
|
24489
25662
|
return { dir: null, reason: `Provider source directory not found for '${type}'` };
|
|
24490
25663
|
}
|
|
24491
25664
|
if (!fs14.existsSync(desiredDir)) {
|
|
24492
|
-
fs14.mkdirSync(
|
|
25665
|
+
fs14.mkdirSync(path24.dirname(desiredDir), { recursive: true });
|
|
24493
25666
|
fs14.cpSync(sourceDir, desiredDir, { recursive: true });
|
|
24494
25667
|
ctx.log(`Auto-implement writable copy created: ${desiredDir}`);
|
|
24495
25668
|
}
|
|
24496
|
-
const providerJson =
|
|
25669
|
+
const providerJson = path24.join(desiredDir, "provider.json");
|
|
24497
25670
|
if (!fs14.existsSync(providerJson)) {
|
|
24498
25671
|
return { dir: null, reason: `provider.json not found in writable provider directory: ${desiredDir}` };
|
|
24499
25672
|
}
|
|
@@ -24504,13 +25677,13 @@ function loadAutoImplReferenceScripts(ctx, referenceType) {
|
|
|
24504
25677
|
const refDir = ctx.findProviderDir(referenceType);
|
|
24505
25678
|
if (!refDir || !fs14.existsSync(refDir)) return {};
|
|
24506
25679
|
const referenceScripts = {};
|
|
24507
|
-
const scriptsDir =
|
|
25680
|
+
const scriptsDir = path24.join(refDir, "scripts");
|
|
24508
25681
|
const latestDir = getLatestScriptVersionDir(scriptsDir);
|
|
24509
25682
|
if (!latestDir) return referenceScripts;
|
|
24510
25683
|
for (const file of fs14.readdirSync(latestDir)) {
|
|
24511
25684
|
if (!file.endsWith(".js")) continue;
|
|
24512
25685
|
try {
|
|
24513
|
-
referenceScripts[file] = fs14.readFileSync(
|
|
25686
|
+
referenceScripts[file] = fs14.readFileSync(path24.join(latestDir, file), "utf-8");
|
|
24514
25687
|
} catch {
|
|
24515
25688
|
}
|
|
24516
25689
|
}
|
|
@@ -24618,9 +25791,9 @@ async function handleAutoImplement(ctx, type, req, res) {
|
|
|
24618
25791
|
});
|
|
24619
25792
|
const referenceScripts = loadAutoImplReferenceScripts(ctx, resolvedReference);
|
|
24620
25793
|
const prompt = buildAutoImplPrompt(ctx, type, provider, providerDir, functions, domContext, referenceScripts, comment, resolvedReference, verification);
|
|
24621
|
-
const tmpDir =
|
|
25794
|
+
const tmpDir = path24.join(os20.tmpdir(), "adhdev-autoimpl");
|
|
24622
25795
|
if (!fs14.existsSync(tmpDir)) fs14.mkdirSync(tmpDir, { recursive: true });
|
|
24623
|
-
const promptFile =
|
|
25796
|
+
const promptFile = path24.join(tmpDir, `prompt-${type}-${Date.now()}.md`);
|
|
24624
25797
|
fs14.writeFileSync(promptFile, prompt, "utf-8");
|
|
24625
25798
|
ctx.log(`Auto-implement prompt written to ${promptFile} (${prompt.length} chars)`);
|
|
24626
25799
|
const agentProvider = ctx.providerLoader.resolve(agent) || ctx.providerLoader.getMeta(agent);
|
|
@@ -25052,7 +26225,7 @@ function buildAutoImplPrompt(ctx, type, provider, providerDir, functions, domCon
|
|
|
25052
26225
|
setMode: "set_mode.js"
|
|
25053
26226
|
};
|
|
25054
26227
|
const targetFileNames = new Set(functions.map((fn) => funcToFile[fn]).filter(Boolean));
|
|
25055
|
-
const scriptsDir =
|
|
26228
|
+
const scriptsDir = path24.join(providerDir, "scripts");
|
|
25056
26229
|
const latestScriptsDir = getLatestScriptVersionDir(scriptsDir);
|
|
25057
26230
|
if (latestScriptsDir) {
|
|
25058
26231
|
lines.push(`Scripts version directory: \`${latestScriptsDir}\``);
|
|
@@ -25063,7 +26236,7 @@ function buildAutoImplPrompt(ctx, type, provider, providerDir, functions, domCon
|
|
|
25063
26236
|
for (const file of fs14.readdirSync(latestScriptsDir)) {
|
|
25064
26237
|
if (file.endsWith(".js") && targetFileNames.has(file)) {
|
|
25065
26238
|
try {
|
|
25066
|
-
const content = fs14.readFileSync(
|
|
26239
|
+
const content = fs14.readFileSync(path24.join(latestScriptsDir, file), "utf-8");
|
|
25067
26240
|
lines.push(`### \`${file}\` \u270F\uFE0F EDIT`);
|
|
25068
26241
|
lines.push("```javascript");
|
|
25069
26242
|
lines.push(content);
|
|
@@ -25080,7 +26253,7 @@ function buildAutoImplPrompt(ctx, type, provider, providerDir, functions, domCon
|
|
|
25080
26253
|
lines.push("");
|
|
25081
26254
|
for (const file of refFiles) {
|
|
25082
26255
|
try {
|
|
25083
|
-
const content = fs14.readFileSync(
|
|
26256
|
+
const content = fs14.readFileSync(path24.join(latestScriptsDir, file), "utf-8");
|
|
25084
26257
|
lines.push(`### \`${file}\` \u{1F512}`);
|
|
25085
26258
|
lines.push("```javascript");
|
|
25086
26259
|
lines.push(content);
|
|
@@ -25121,10 +26294,10 @@ function buildAutoImplPrompt(ctx, type, provider, providerDir, functions, domCon
|
|
|
25121
26294
|
lines.push("");
|
|
25122
26295
|
}
|
|
25123
26296
|
}
|
|
25124
|
-
const docsDir =
|
|
26297
|
+
const docsDir = path24.join(providerDir, "../../docs");
|
|
25125
26298
|
const loadGuide = (name) => {
|
|
25126
26299
|
try {
|
|
25127
|
-
const p =
|
|
26300
|
+
const p = path24.join(docsDir, name);
|
|
25128
26301
|
if (fs14.existsSync(p)) return fs14.readFileSync(p, "utf-8");
|
|
25129
26302
|
} catch {
|
|
25130
26303
|
}
|
|
@@ -25361,7 +26534,7 @@ function buildCliAutoImplPrompt(ctx, type, provider, providerDir, functions, ref
|
|
|
25361
26534
|
parseApproval: "parse_approval.js"
|
|
25362
26535
|
};
|
|
25363
26536
|
const targetFileNames = new Set(functions.map((fn) => funcToFile[fn]).filter(Boolean));
|
|
25364
|
-
const scriptsDir =
|
|
26537
|
+
const scriptsDir = path24.join(providerDir, "scripts");
|
|
25365
26538
|
const latestScriptsDir = getLatestScriptVersionDir(scriptsDir);
|
|
25366
26539
|
if (latestScriptsDir) {
|
|
25367
26540
|
lines.push(`Scripts version directory: \`${latestScriptsDir}\``);
|
|
@@ -25373,7 +26546,7 @@ function buildCliAutoImplPrompt(ctx, type, provider, providerDir, functions, ref
|
|
|
25373
26546
|
if (!file.endsWith(".js")) continue;
|
|
25374
26547
|
if (!targetFileNames.has(file)) continue;
|
|
25375
26548
|
try {
|
|
25376
|
-
const content = fs14.readFileSync(
|
|
26549
|
+
const content = fs14.readFileSync(path24.join(latestScriptsDir, file), "utf-8");
|
|
25377
26550
|
lines.push(`### \`${file}\` \u270F\uFE0F EDIT`);
|
|
25378
26551
|
lines.push("```javascript");
|
|
25379
26552
|
lines.push(content);
|
|
@@ -25389,7 +26562,7 @@ function buildCliAutoImplPrompt(ctx, type, provider, providerDir, functions, ref
|
|
|
25389
26562
|
lines.push("");
|
|
25390
26563
|
for (const file of refFiles) {
|
|
25391
26564
|
try {
|
|
25392
|
-
const content = fs14.readFileSync(
|
|
26565
|
+
const content = fs14.readFileSync(path24.join(latestScriptsDir, file), "utf-8");
|
|
25393
26566
|
lines.push(`### \`${file}\` \u{1F512}`);
|
|
25394
26567
|
lines.push("```javascript");
|
|
25395
26568
|
lines.push(content);
|
|
@@ -25422,10 +26595,10 @@ function buildCliAutoImplPrompt(ctx, type, provider, providerDir, functions, ref
|
|
|
25422
26595
|
lines.push("");
|
|
25423
26596
|
}
|
|
25424
26597
|
}
|
|
25425
|
-
const docsDir =
|
|
26598
|
+
const docsDir = path24.join(providerDir, "../../docs");
|
|
25426
26599
|
const loadGuide = (name) => {
|
|
25427
26600
|
try {
|
|
25428
|
-
const p =
|
|
26601
|
+
const p = path24.join(docsDir, name);
|
|
25429
26602
|
if (fs14.existsSync(p)) return fs14.readFileSync(p, "utf-8");
|
|
25430
26603
|
} catch {
|
|
25431
26604
|
}
|
|
@@ -25872,8 +27045,8 @@ var DevServer = class _DevServer {
|
|
|
25872
27045
|
}
|
|
25873
27046
|
getEndpointList() {
|
|
25874
27047
|
return this.routes.map((r) => {
|
|
25875
|
-
const
|
|
25876
|
-
return `${r.method.padEnd(5)} ${
|
|
27048
|
+
const path26 = typeof r.pattern === "string" ? r.pattern : r.pattern.source.replace(/\\\//g, "/").replace(/\(\[.*?\]\+\)/g, ":type").replace(/[\^$]/g, "");
|
|
27049
|
+
return `${r.method.padEnd(5)} ${path26}`;
|
|
25877
27050
|
});
|
|
25878
27051
|
}
|
|
25879
27052
|
async start(port = DEV_SERVER_PORT) {
|
|
@@ -25904,15 +27077,15 @@ var DevServer = class _DevServer {
|
|
|
25904
27077
|
this.json(res, 500, { error: e.message });
|
|
25905
27078
|
}
|
|
25906
27079
|
});
|
|
25907
|
-
return new Promise((
|
|
27080
|
+
return new Promise((resolve15, reject) => {
|
|
25908
27081
|
this.server.listen(port, "127.0.0.1", () => {
|
|
25909
27082
|
this.log(`Dev server listening on http://127.0.0.1:${port}`);
|
|
25910
|
-
|
|
27083
|
+
resolve15();
|
|
25911
27084
|
});
|
|
25912
27085
|
this.server.on("error", (e) => {
|
|
25913
27086
|
if (e.code === "EADDRINUSE") {
|
|
25914
27087
|
this.log(`Port ${port} in use, skipping dev server`);
|
|
25915
|
-
|
|
27088
|
+
resolve15();
|
|
25916
27089
|
} else {
|
|
25917
27090
|
reject(e);
|
|
25918
27091
|
}
|
|
@@ -25994,20 +27167,20 @@ var DevServer = class _DevServer {
|
|
|
25994
27167
|
child.stderr?.on("data", (d) => {
|
|
25995
27168
|
stderr += d.toString().slice(0, 2e3);
|
|
25996
27169
|
});
|
|
25997
|
-
await new Promise((
|
|
27170
|
+
await new Promise((resolve15) => {
|
|
25998
27171
|
const timer = setTimeout(() => {
|
|
25999
27172
|
child.kill();
|
|
26000
|
-
|
|
27173
|
+
resolve15();
|
|
26001
27174
|
}, 3e3);
|
|
26002
27175
|
child.on("exit", () => {
|
|
26003
27176
|
clearTimeout(timer);
|
|
26004
|
-
|
|
27177
|
+
resolve15();
|
|
26005
27178
|
});
|
|
26006
27179
|
child.stdout?.once("data", () => {
|
|
26007
27180
|
setTimeout(() => {
|
|
26008
27181
|
child.kill();
|
|
26009
27182
|
clearTimeout(timer);
|
|
26010
|
-
|
|
27183
|
+
resolve15();
|
|
26011
27184
|
}, 500);
|
|
26012
27185
|
});
|
|
26013
27186
|
});
|
|
@@ -26161,12 +27334,12 @@ var DevServer = class _DevServer {
|
|
|
26161
27334
|
// ─── DevConsole SPA ───
|
|
26162
27335
|
getConsoleDistDir() {
|
|
26163
27336
|
const candidates = [
|
|
26164
|
-
|
|
26165
|
-
|
|
26166
|
-
|
|
27337
|
+
path25.resolve(__dirname, "../../web-devconsole/dist"),
|
|
27338
|
+
path25.resolve(__dirname, "../../../web-devconsole/dist"),
|
|
27339
|
+
path25.join(process.cwd(), "packages/web-devconsole/dist")
|
|
26167
27340
|
];
|
|
26168
27341
|
for (const dir of candidates) {
|
|
26169
|
-
if (fs15.existsSync(
|
|
27342
|
+
if (fs15.existsSync(path25.join(dir, "index.html"))) return dir;
|
|
26170
27343
|
}
|
|
26171
27344
|
return null;
|
|
26172
27345
|
}
|
|
@@ -26176,7 +27349,7 @@ var DevServer = class _DevServer {
|
|
|
26176
27349
|
this.json(res, 500, { error: "DevConsole not found. Run: npm run build -w packages/web-devconsole" });
|
|
26177
27350
|
return;
|
|
26178
27351
|
}
|
|
26179
|
-
const htmlPath =
|
|
27352
|
+
const htmlPath = path25.join(distDir, "index.html");
|
|
26180
27353
|
try {
|
|
26181
27354
|
const html = fs15.readFileSync(htmlPath, "utf-8");
|
|
26182
27355
|
res.writeHead(200, { "Content-Type": "text/html; charset=utf-8" });
|
|
@@ -26201,15 +27374,15 @@ var DevServer = class _DevServer {
|
|
|
26201
27374
|
this.json(res, 404, { error: "Not found" });
|
|
26202
27375
|
return;
|
|
26203
27376
|
}
|
|
26204
|
-
const safePath =
|
|
26205
|
-
const filePath =
|
|
27377
|
+
const safePath = path25.normalize(pathname).replace(/^\.\.\//, "");
|
|
27378
|
+
const filePath = path25.join(distDir, safePath);
|
|
26206
27379
|
if (!filePath.startsWith(distDir)) {
|
|
26207
27380
|
this.json(res, 403, { error: "Forbidden" });
|
|
26208
27381
|
return;
|
|
26209
27382
|
}
|
|
26210
27383
|
try {
|
|
26211
27384
|
const content = fs15.readFileSync(filePath);
|
|
26212
|
-
const ext =
|
|
27385
|
+
const ext = path25.extname(filePath);
|
|
26213
27386
|
const contentType = _DevServer.MIME_MAP[ext] || "application/octet-stream";
|
|
26214
27387
|
res.writeHead(200, { "Content-Type": contentType, "Cache-Control": "public, max-age=31536000, immutable" });
|
|
26215
27388
|
res.end(content);
|
|
@@ -26322,10 +27495,10 @@ var DevServer = class _DevServer {
|
|
|
26322
27495
|
const rel = prefix ? `${prefix}/${entry.name}` : entry.name;
|
|
26323
27496
|
if (entry.isDirectory()) {
|
|
26324
27497
|
files.push({ path: rel, size: 0, type: "dir" });
|
|
26325
|
-
scan(
|
|
27498
|
+
scan(path25.join(d, entry.name), rel);
|
|
26326
27499
|
} else {
|
|
26327
|
-
const
|
|
26328
|
-
files.push({ path: rel, size:
|
|
27500
|
+
const stat2 = fs15.statSync(path25.join(d, entry.name));
|
|
27501
|
+
files.push({ path: rel, size: stat2.size, type: "file" });
|
|
26329
27502
|
}
|
|
26330
27503
|
}
|
|
26331
27504
|
} catch {
|
|
@@ -26347,7 +27520,7 @@ var DevServer = class _DevServer {
|
|
|
26347
27520
|
this.json(res, 404, { error: `Provider directory not found: ${type}` });
|
|
26348
27521
|
return;
|
|
26349
27522
|
}
|
|
26350
|
-
const fullPath =
|
|
27523
|
+
const fullPath = path25.resolve(dir, path25.normalize(filePath));
|
|
26351
27524
|
if (!fullPath.startsWith(dir)) {
|
|
26352
27525
|
this.json(res, 403, { error: "Forbidden" });
|
|
26353
27526
|
return;
|
|
@@ -26372,14 +27545,14 @@ var DevServer = class _DevServer {
|
|
|
26372
27545
|
this.json(res, 404, { error: `Provider directory not found: ${type}` });
|
|
26373
27546
|
return;
|
|
26374
27547
|
}
|
|
26375
|
-
const fullPath =
|
|
27548
|
+
const fullPath = path25.resolve(dir, path25.normalize(filePath));
|
|
26376
27549
|
if (!fullPath.startsWith(dir)) {
|
|
26377
27550
|
this.json(res, 403, { error: "Forbidden" });
|
|
26378
27551
|
return;
|
|
26379
27552
|
}
|
|
26380
27553
|
try {
|
|
26381
27554
|
if (fs15.existsSync(fullPath)) fs15.copyFileSync(fullPath, fullPath + ".bak");
|
|
26382
|
-
fs15.mkdirSync(
|
|
27555
|
+
fs15.mkdirSync(path25.dirname(fullPath), { recursive: true });
|
|
26383
27556
|
fs15.writeFileSync(fullPath, content, "utf-8");
|
|
26384
27557
|
this.log(`File saved: ${fullPath} (${content.length} chars)`);
|
|
26385
27558
|
this.providerLoader.reload();
|
|
@@ -26396,7 +27569,7 @@ var DevServer = class _DevServer {
|
|
|
26396
27569
|
return;
|
|
26397
27570
|
}
|
|
26398
27571
|
for (const name of ["scripts.js", "provider.json"]) {
|
|
26399
|
-
const p =
|
|
27572
|
+
const p = path25.join(dir, name);
|
|
26400
27573
|
if (fs15.existsSync(p)) {
|
|
26401
27574
|
const source = fs15.readFileSync(p, "utf-8");
|
|
26402
27575
|
this.json(res, 200, { type, path: p, source, lines: source.split("\n").length });
|
|
@@ -26417,8 +27590,8 @@ var DevServer = class _DevServer {
|
|
|
26417
27590
|
this.json(res, 404, { error: `Provider not found: ${type}` });
|
|
26418
27591
|
return;
|
|
26419
27592
|
}
|
|
26420
|
-
const target = fs15.existsSync(
|
|
26421
|
-
const targetPath =
|
|
27593
|
+
const target = fs15.existsSync(path25.join(dir, "scripts.js")) ? "scripts.js" : "provider.json";
|
|
27594
|
+
const targetPath = path25.join(dir, target);
|
|
26422
27595
|
try {
|
|
26423
27596
|
if (fs15.existsSync(targetPath)) fs15.copyFileSync(targetPath, targetPath + ".bak");
|
|
26424
27597
|
fs15.writeFileSync(targetPath, source, "utf-8");
|
|
@@ -26510,14 +27683,14 @@ var DevServer = class _DevServer {
|
|
|
26510
27683
|
child.stderr?.on("data", (d) => {
|
|
26511
27684
|
stderr += d.toString();
|
|
26512
27685
|
});
|
|
26513
|
-
await new Promise((
|
|
27686
|
+
await new Promise((resolve15) => {
|
|
26514
27687
|
const timer = setTimeout(() => {
|
|
26515
27688
|
child.kill();
|
|
26516
|
-
|
|
27689
|
+
resolve15();
|
|
26517
27690
|
}, timeout);
|
|
26518
27691
|
child.on("exit", () => {
|
|
26519
27692
|
clearTimeout(timer);
|
|
26520
|
-
|
|
27693
|
+
resolve15();
|
|
26521
27694
|
});
|
|
26522
27695
|
});
|
|
26523
27696
|
const elapsed = Date.now() - start;
|
|
@@ -26565,7 +27738,7 @@ var DevServer = class _DevServer {
|
|
|
26565
27738
|
}
|
|
26566
27739
|
let targetDir;
|
|
26567
27740
|
targetDir = this.providerLoader.getUserProviderDir(category, type);
|
|
26568
|
-
const jsonPath =
|
|
27741
|
+
const jsonPath = path25.join(targetDir, "provider.json");
|
|
26569
27742
|
if (fs15.existsSync(jsonPath)) {
|
|
26570
27743
|
this.json(res, 409, { error: `Provider already exists at ${targetDir}`, path: targetDir });
|
|
26571
27744
|
return;
|
|
@@ -26577,8 +27750,8 @@ var DevServer = class _DevServer {
|
|
|
26577
27750
|
const createdFiles = ["provider.json"];
|
|
26578
27751
|
if (result.files) {
|
|
26579
27752
|
for (const [relPath, content] of Object.entries(result.files)) {
|
|
26580
|
-
const fullPath =
|
|
26581
|
-
fs15.mkdirSync(
|
|
27753
|
+
const fullPath = path25.join(targetDir, relPath);
|
|
27754
|
+
fs15.mkdirSync(path25.dirname(fullPath), { recursive: true });
|
|
26582
27755
|
fs15.writeFileSync(fullPath, content, "utf-8");
|
|
26583
27756
|
createdFiles.push(relPath);
|
|
26584
27757
|
}
|
|
@@ -26631,22 +27804,22 @@ var DevServer = class _DevServer {
|
|
|
26631
27804
|
if (!fs15.existsSync(scriptsDir)) return null;
|
|
26632
27805
|
const versions = fs15.readdirSync(scriptsDir).filter((d) => {
|
|
26633
27806
|
try {
|
|
26634
|
-
return fs15.statSync(
|
|
27807
|
+
return fs15.statSync(path25.join(scriptsDir, d)).isDirectory();
|
|
26635
27808
|
} catch {
|
|
26636
27809
|
return false;
|
|
26637
27810
|
}
|
|
26638
27811
|
}).sort((a, b) => b.localeCompare(a, void 0, { numeric: true, sensitivity: "base" }));
|
|
26639
27812
|
if (versions.length === 0) return null;
|
|
26640
|
-
return
|
|
27813
|
+
return path25.join(scriptsDir, versions[0]);
|
|
26641
27814
|
}
|
|
26642
27815
|
resolveAutoImplWritableProviderDir(category, type, requestedDir) {
|
|
26643
|
-
const canonicalUserDir =
|
|
26644
|
-
const desiredDir = requestedDir ?
|
|
26645
|
-
const upstreamRoot =
|
|
26646
|
-
if (desiredDir === upstreamRoot || desiredDir.startsWith(`${upstreamRoot}${
|
|
27816
|
+
const canonicalUserDir = path25.resolve(this.providerLoader.getUserProviderDir(category, type));
|
|
27817
|
+
const desiredDir = requestedDir ? path25.resolve(requestedDir) : canonicalUserDir;
|
|
27818
|
+
const upstreamRoot = path25.resolve(this.providerLoader.getUpstreamDir());
|
|
27819
|
+
if (desiredDir === upstreamRoot || desiredDir.startsWith(`${upstreamRoot}${path25.sep}`)) {
|
|
26647
27820
|
return { dir: null, reason: `Refusing to write into upstream provider directory: ${desiredDir}` };
|
|
26648
27821
|
}
|
|
26649
|
-
if (
|
|
27822
|
+
if (path25.basename(desiredDir) !== type) {
|
|
26650
27823
|
return { dir: null, reason: `Requested writable provider directory must end with '${type}': ${desiredDir}` };
|
|
26651
27824
|
}
|
|
26652
27825
|
const sourceDir = this.findProviderDir(type);
|
|
@@ -26654,11 +27827,11 @@ var DevServer = class _DevServer {
|
|
|
26654
27827
|
return { dir: null, reason: `Provider source directory not found for '${type}'` };
|
|
26655
27828
|
}
|
|
26656
27829
|
if (!fs15.existsSync(desiredDir)) {
|
|
26657
|
-
fs15.mkdirSync(
|
|
27830
|
+
fs15.mkdirSync(path25.dirname(desiredDir), { recursive: true });
|
|
26658
27831
|
fs15.cpSync(sourceDir, desiredDir, { recursive: true });
|
|
26659
27832
|
this.log(`Auto-implement writable copy created: ${desiredDir}`);
|
|
26660
27833
|
}
|
|
26661
|
-
const providerJson =
|
|
27834
|
+
const providerJson = path25.join(desiredDir, "provider.json");
|
|
26662
27835
|
if (!fs15.existsSync(providerJson)) {
|
|
26663
27836
|
return { dir: null, reason: `provider.json not found in writable provider directory: ${desiredDir}` };
|
|
26664
27837
|
}
|
|
@@ -26694,7 +27867,7 @@ var DevServer = class _DevServer {
|
|
|
26694
27867
|
setMode: "set_mode.js"
|
|
26695
27868
|
};
|
|
26696
27869
|
const targetFileNames = new Set(functions.map((fn) => funcToFile[fn]).filter(Boolean));
|
|
26697
|
-
const scriptsDir =
|
|
27870
|
+
const scriptsDir = path25.join(providerDir, "scripts");
|
|
26698
27871
|
const latestScriptsDir = this.getLatestScriptVersionDir(scriptsDir);
|
|
26699
27872
|
if (latestScriptsDir) {
|
|
26700
27873
|
lines.push(`Scripts version directory: \`${latestScriptsDir}\``);
|
|
@@ -26705,7 +27878,7 @@ var DevServer = class _DevServer {
|
|
|
26705
27878
|
for (const file of fs15.readdirSync(latestScriptsDir)) {
|
|
26706
27879
|
if (file.endsWith(".js") && targetFileNames.has(file)) {
|
|
26707
27880
|
try {
|
|
26708
|
-
const content = fs15.readFileSync(
|
|
27881
|
+
const content = fs15.readFileSync(path25.join(latestScriptsDir, file), "utf-8");
|
|
26709
27882
|
lines.push(`### \`${file}\` \u270F\uFE0F EDIT`);
|
|
26710
27883
|
lines.push("```javascript");
|
|
26711
27884
|
lines.push(content);
|
|
@@ -26722,7 +27895,7 @@ var DevServer = class _DevServer {
|
|
|
26722
27895
|
lines.push("");
|
|
26723
27896
|
for (const file of refFiles) {
|
|
26724
27897
|
try {
|
|
26725
|
-
const content = fs15.readFileSync(
|
|
27898
|
+
const content = fs15.readFileSync(path25.join(latestScriptsDir, file), "utf-8");
|
|
26726
27899
|
lines.push(`### \`${file}\` \u{1F512}`);
|
|
26727
27900
|
lines.push("```javascript");
|
|
26728
27901
|
lines.push(content);
|
|
@@ -26763,10 +27936,10 @@ var DevServer = class _DevServer {
|
|
|
26763
27936
|
lines.push("");
|
|
26764
27937
|
}
|
|
26765
27938
|
}
|
|
26766
|
-
const docsDir =
|
|
27939
|
+
const docsDir = path25.join(providerDir, "../../docs");
|
|
26767
27940
|
const loadGuide = (name) => {
|
|
26768
27941
|
try {
|
|
26769
|
-
const p =
|
|
27942
|
+
const p = path25.join(docsDir, name);
|
|
26770
27943
|
if (fs15.existsSync(p)) return fs15.readFileSync(p, "utf-8");
|
|
26771
27944
|
} catch {
|
|
26772
27945
|
}
|
|
@@ -26940,7 +28113,7 @@ var DevServer = class _DevServer {
|
|
|
26940
28113
|
parseApproval: "parse_approval.js"
|
|
26941
28114
|
};
|
|
26942
28115
|
const targetFileNames = new Set(functions.map((fn) => funcToFile[fn]).filter(Boolean));
|
|
26943
|
-
const scriptsDir =
|
|
28116
|
+
const scriptsDir = path25.join(providerDir, "scripts");
|
|
26944
28117
|
const latestScriptsDir = this.getLatestScriptVersionDir(scriptsDir);
|
|
26945
28118
|
if (latestScriptsDir) {
|
|
26946
28119
|
lines.push(`Scripts version directory: \`${latestScriptsDir}\``);
|
|
@@ -26952,7 +28125,7 @@ var DevServer = class _DevServer {
|
|
|
26952
28125
|
if (!file.endsWith(".js")) continue;
|
|
26953
28126
|
if (!targetFileNames.has(file)) continue;
|
|
26954
28127
|
try {
|
|
26955
|
-
const content = fs15.readFileSync(
|
|
28128
|
+
const content = fs15.readFileSync(path25.join(latestScriptsDir, file), "utf-8");
|
|
26956
28129
|
lines.push(`### \`${file}\` \u270F\uFE0F EDIT`);
|
|
26957
28130
|
lines.push("```javascript");
|
|
26958
28131
|
lines.push(content);
|
|
@@ -26968,7 +28141,7 @@ var DevServer = class _DevServer {
|
|
|
26968
28141
|
lines.push("");
|
|
26969
28142
|
for (const file of refFiles) {
|
|
26970
28143
|
try {
|
|
26971
|
-
const content = fs15.readFileSync(
|
|
28144
|
+
const content = fs15.readFileSync(path25.join(latestScriptsDir, file), "utf-8");
|
|
26972
28145
|
lines.push(`### \`${file}\` \u{1F512}`);
|
|
26973
28146
|
lines.push("```javascript");
|
|
26974
28147
|
lines.push(content);
|
|
@@ -27001,10 +28174,10 @@ var DevServer = class _DevServer {
|
|
|
27001
28174
|
lines.push("");
|
|
27002
28175
|
}
|
|
27003
28176
|
}
|
|
27004
|
-
const docsDir =
|
|
28177
|
+
const docsDir = path25.join(providerDir, "../../docs");
|
|
27005
28178
|
const loadGuide = (name) => {
|
|
27006
28179
|
try {
|
|
27007
|
-
const p =
|
|
28180
|
+
const p = path25.join(docsDir, name);
|
|
27008
28181
|
if (fs15.existsSync(p)) return fs15.readFileSync(p, "utf-8");
|
|
27009
28182
|
} catch {
|
|
27010
28183
|
}
|
|
@@ -27187,14 +28360,14 @@ data: ${JSON.stringify(msg.data)}
|
|
|
27187
28360
|
res.end(JSON.stringify(data, null, 2));
|
|
27188
28361
|
}
|
|
27189
28362
|
async readBody(req) {
|
|
27190
|
-
return new Promise((
|
|
28363
|
+
return new Promise((resolve15) => {
|
|
27191
28364
|
let body = "";
|
|
27192
28365
|
req.on("data", (chunk) => body += chunk);
|
|
27193
28366
|
req.on("end", () => {
|
|
27194
28367
|
try {
|
|
27195
|
-
|
|
28368
|
+
resolve15(JSON.parse(body));
|
|
27196
28369
|
} catch {
|
|
27197
|
-
|
|
28370
|
+
resolve15({});
|
|
27198
28371
|
}
|
|
27199
28372
|
});
|
|
27200
28373
|
});
|
|
@@ -27709,7 +28882,7 @@ async function waitForReady(endpoint, timeoutMs = STARTUP_TIMEOUT_MS) {
|
|
|
27709
28882
|
const deadline = Date.now() + timeoutMs;
|
|
27710
28883
|
while (Date.now() < deadline) {
|
|
27711
28884
|
if (await canConnect(endpoint)) return;
|
|
27712
|
-
await new Promise((
|
|
28885
|
+
await new Promise((resolve15) => setTimeout(resolve15, STARTUP_POLL_MS));
|
|
27713
28886
|
}
|
|
27714
28887
|
throw new Error(`Session host did not become ready within ${timeoutMs}ms`);
|
|
27715
28888
|
}
|
|
@@ -27887,10 +29060,10 @@ async function installExtension(ide, extension) {
|
|
|
27887
29060
|
const buffer = Buffer.from(await res.arrayBuffer());
|
|
27888
29061
|
const fs16 = await import("fs");
|
|
27889
29062
|
fs16.writeFileSync(vsixPath, buffer);
|
|
27890
|
-
return new Promise((
|
|
29063
|
+
return new Promise((resolve15) => {
|
|
27891
29064
|
const cmd = `"${ide.cliCommand}" --install-extension "${vsixPath}" --force`;
|
|
27892
29065
|
exec2(cmd, { timeout: 6e4 }, (error, _stdout, stderr) => {
|
|
27893
|
-
|
|
29066
|
+
resolve15({
|
|
27894
29067
|
extensionId: extension.id,
|
|
27895
29068
|
marketplaceId: extension.marketplaceId,
|
|
27896
29069
|
success: !error,
|
|
@@ -27903,11 +29076,11 @@ async function installExtension(ide, extension) {
|
|
|
27903
29076
|
} catch (e) {
|
|
27904
29077
|
}
|
|
27905
29078
|
}
|
|
27906
|
-
return new Promise((
|
|
29079
|
+
return new Promise((resolve15) => {
|
|
27907
29080
|
const cmd = `"${ide.cliCommand}" --install-extension ${extension.marketplaceId} --force`;
|
|
27908
29081
|
exec2(cmd, { timeout: 6e4 }, (error, stdout, stderr) => {
|
|
27909
29082
|
if (error) {
|
|
27910
|
-
|
|
29083
|
+
resolve15({
|
|
27911
29084
|
extensionId: extension.id,
|
|
27912
29085
|
marketplaceId: extension.marketplaceId,
|
|
27913
29086
|
success: false,
|
|
@@ -27915,7 +29088,7 @@ async function installExtension(ide, extension) {
|
|
|
27915
29088
|
error: stderr || error.message
|
|
27916
29089
|
});
|
|
27917
29090
|
} else {
|
|
27918
|
-
|
|
29091
|
+
resolve15({
|
|
27919
29092
|
extensionId: extension.id,
|
|
27920
29093
|
marketplaceId: extension.marketplaceId,
|
|
27921
29094
|
success: true,
|
|
@@ -28244,6 +29417,7 @@ export {
|
|
|
28244
29417
|
DEFAULT_CDP_SCAN_INTERVAL_MS,
|
|
28245
29418
|
DEFAULT_CHAT_TAIL_RECENT_MESSAGE_GRACE_MS,
|
|
28246
29419
|
DEFAULT_DAEMON_PORT,
|
|
29420
|
+
DEFAULT_GIT_WORKSPACE_POLL_INTERVAL_MS,
|
|
28247
29421
|
DEFAULT_MACHINE_RUNTIME_SUBSCRIPTION_INTERVAL_MS,
|
|
28248
29422
|
DEFAULT_SESSION_HOST_APP_NAME,
|
|
28249
29423
|
DEFAULT_SESSION_HOST_DIAGNOSTICS_SUBSCRIPTION_INTERVAL_MS,
|
|
@@ -28262,8 +29436,12 @@ export {
|
|
|
28262
29436
|
DaemonCommandRouter,
|
|
28263
29437
|
DaemonStatusReporter,
|
|
28264
29438
|
DevServer,
|
|
29439
|
+
GitCommandError,
|
|
29440
|
+
GitWorkspaceMonitor,
|
|
28265
29441
|
IdeProviderInstance,
|
|
29442
|
+
InMemoryGitSnapshotStore,
|
|
28266
29443
|
LOG,
|
|
29444
|
+
MIN_GIT_WORKSPACE_POLL_INTERVAL_MS,
|
|
28267
29445
|
MIN_MACHINE_RUNTIME_SUBSCRIPTION_INTERVAL_MS,
|
|
28268
29446
|
MIN_SESSION_HOST_DIAGNOSTICS_SUBSCRIPTION_INTERVAL_MS,
|
|
28269
29447
|
NodePtyTransportFactory,
|
|
@@ -28291,9 +29469,14 @@ export {
|
|
|
28291
29469
|
buildUserChatMessage,
|
|
28292
29470
|
classifyHotChatSessionsForSubscriptionFlush,
|
|
28293
29471
|
clearDebugTrace,
|
|
29472
|
+
compareGitSnapshots,
|
|
28294
29473
|
configureDebugTraceStore,
|
|
28295
29474
|
connectCdpManager,
|
|
28296
29475
|
createDebugTraceStore,
|
|
29476
|
+
createDefaultGitCommandServices,
|
|
29477
|
+
createGitCompactSummary,
|
|
29478
|
+
createGitSnapshotStore,
|
|
29479
|
+
createGitWorkspaceMonitor,
|
|
28297
29480
|
createInteractionId,
|
|
28298
29481
|
detectAllVersions,
|
|
28299
29482
|
detectCLIs,
|
|
@@ -28308,6 +29491,9 @@ export {
|
|
|
28308
29491
|
getCurrentDaemonLogPath,
|
|
28309
29492
|
getDaemonLogDir,
|
|
28310
29493
|
getDebugRuntimeConfig,
|
|
29494
|
+
getGitDiffSummary,
|
|
29495
|
+
getGitFileDiff,
|
|
29496
|
+
getGitRepoStatus,
|
|
28311
29497
|
getHostMemorySnapshot,
|
|
28312
29498
|
getLogLevel,
|
|
28313
29499
|
getNpmExecOptions,
|
|
@@ -28319,6 +29505,7 @@ export {
|
|
|
28319
29505
|
getSessionHostRecoveryLabel,
|
|
28320
29506
|
getSessionHostSurfaceKind,
|
|
28321
29507
|
getWorkspaceState,
|
|
29508
|
+
handleGitCommand,
|
|
28322
29509
|
hasCdpManager,
|
|
28323
29510
|
hashSignatureParts,
|
|
28324
29511
|
initDaemonComponents,
|
|
@@ -28327,9 +29514,11 @@ export {
|
|
|
28327
29514
|
isBuiltinChatMessageKind,
|
|
28328
29515
|
isCdpConnected,
|
|
28329
29516
|
isExtensionInstalled,
|
|
29517
|
+
isGitCommandName,
|
|
28330
29518
|
isIdeRunning,
|
|
28331
29519
|
isManagedStatusWaiting,
|
|
28332
29520
|
isManagedStatusWorking,
|
|
29521
|
+
isPathInside,
|
|
28333
29522
|
isSessionHostLiveRuntime,
|
|
28334
29523
|
isSessionHostRecoverySnapshot,
|
|
28335
29524
|
isSetupComplete,
|
|
@@ -28347,10 +29536,13 @@ export {
|
|
|
28347
29536
|
normalizeChatMessageKind,
|
|
28348
29537
|
normalizeChatMessages,
|
|
28349
29538
|
normalizeChatTailActiveModal,
|
|
29539
|
+
normalizeGitOutput,
|
|
29540
|
+
normalizeGitWorkspaceSubscriptionParams,
|
|
28350
29541
|
normalizeInputEnvelope,
|
|
28351
29542
|
normalizeManagedStatus,
|
|
28352
29543
|
normalizeMessageParts,
|
|
28353
29544
|
normalizeSessionModalFields,
|
|
29545
|
+
parsePorcelainV2Status,
|
|
28354
29546
|
parseProviderSourceConfigUpdate,
|
|
28355
29547
|
partitionSessionHostDiagnosticsSessions,
|
|
28356
29548
|
partitionSessionHostRecords,
|
|
@@ -28366,9 +29558,11 @@ export {
|
|
|
28366
29558
|
resolveChatMessageKind,
|
|
28367
29559
|
resolveCurrentGlobalInstallSurface,
|
|
28368
29560
|
resolveDebugRuntimeConfig,
|
|
29561
|
+
resolveGitRepository,
|
|
28369
29562
|
resolveSessionHostAppName,
|
|
28370
29563
|
resolveSessionHostAppNameResolution,
|
|
28371
29564
|
runAsyncBatch,
|
|
29565
|
+
runGit,
|
|
28372
29566
|
saveConfig,
|
|
28373
29567
|
saveState,
|
|
28374
29568
|
setDebugRuntimeConfig,
|
|
@@ -28379,6 +29573,7 @@ export {
|
|
|
28379
29573
|
shutdownDaemonComponents,
|
|
28380
29574
|
spawnDetachedDaemonUpgradeHelper,
|
|
28381
29575
|
startDaemonDevSupport,
|
|
29576
|
+
summarizeGitStatus,
|
|
28382
29577
|
updateConfig,
|
|
28383
29578
|
upsertSavedProviderSession
|
|
28384
29579
|
};
|