@adhdev/daemon-core 0.9.53 → 0.9.55
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/boot/daemon-lifecycle.d.ts +5 -0
- package/dist/cli-adapters/provider-cli-adapter.d.ts +1 -0
- package/dist/cli-adapters/provider-cli-config.d.ts +1 -0
- package/dist/cli-adapters/provider-cli-shared.d.ts +2 -0
- package/dist/commands/handler.d.ts +7 -0
- package/dist/git/git-commands.d.ts +139 -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 +16 -0
- package/dist/git/turn-snapshot-tracker.d.ts +16 -0
- package/dist/index.d.ts +2 -1
- package/dist/index.js +1772 -386
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +1744 -383
- package/dist/index.mjs.map +1 -1
- package/dist/providers/contracts.d.ts +2 -0
- 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/boot/daemon-lifecycle.ts +6 -0
- package/src/cli-adapters/provider-cli-adapter.ts +19 -0
- package/src/cli-adapters/provider-cli-config.d.ts +1 -0
- package/src/cli-adapters/provider-cli-config.ts +2 -0
- package/src/cli-adapters/provider-cli-shared.d.ts +2 -0
- package/src/cli-adapters/provider-cli-shared.ts +2 -0
- package/src/commands/handler.ts +25 -1
- package/src/git/git-commands.ts +582 -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 +154 -0
- package/src/git/index.ts +75 -0
- package/src/git/turn-snapshot-tracker.ts +31 -0
- package/src/index.ts +4 -0
- package/src/providers/contracts.d.ts +8 -0
- package/src/providers/contracts.ts +2 -0
- package/src/providers/provider-schema.ts +1 -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.js
CHANGED
|
@@ -283,13 +283,13 @@ function getDaemonLogDir() {
|
|
|
283
283
|
return LOG_DIR;
|
|
284
284
|
}
|
|
285
285
|
function getCurrentDaemonLogPath(date = /* @__PURE__ */ new Date()) {
|
|
286
|
-
return
|
|
286
|
+
return path9.join(LOG_DIR, `daemon-${date.toISOString().slice(0, 10)}.log`);
|
|
287
287
|
}
|
|
288
288
|
function checkDateRotation() {
|
|
289
289
|
const today = getDateStr();
|
|
290
290
|
if (today !== currentDate) {
|
|
291
291
|
currentDate = today;
|
|
292
|
-
currentLogFile =
|
|
292
|
+
currentLogFile = path9.join(LOG_DIR, `daemon-${currentDate}.log`);
|
|
293
293
|
cleanOldLogs();
|
|
294
294
|
}
|
|
295
295
|
}
|
|
@@ -303,7 +303,7 @@ function cleanOldLogs() {
|
|
|
303
303
|
const dateMatch = file.match(/daemon-(\d{4}-\d{2}-\d{2})/);
|
|
304
304
|
if (dateMatch && dateMatch[1] < cutoffStr) {
|
|
305
305
|
try {
|
|
306
|
-
fs2.unlinkSync(
|
|
306
|
+
fs2.unlinkSync(path9.join(LOG_DIR, file));
|
|
307
307
|
} catch {
|
|
308
308
|
}
|
|
309
309
|
}
|
|
@@ -313,8 +313,8 @@ function cleanOldLogs() {
|
|
|
313
313
|
}
|
|
314
314
|
function rotateSizeIfNeeded() {
|
|
315
315
|
try {
|
|
316
|
-
const
|
|
317
|
-
if (
|
|
316
|
+
const stat2 = fs2.statSync(currentLogFile);
|
|
317
|
+
if (stat2.size > MAX_LOG_SIZE) {
|
|
318
318
|
const backup = currentLogFile.replace(".log", ".1.log");
|
|
319
319
|
try {
|
|
320
320
|
fs2.unlinkSync(backup);
|
|
@@ -419,17 +419,17 @@ function installGlobalInterceptor() {
|
|
|
419
419
|
writeToFile(`Log file: ${currentLogFile}`);
|
|
420
420
|
writeToFile(`Log level: ${currentLevel}`);
|
|
421
421
|
}
|
|
422
|
-
var fs2,
|
|
422
|
+
var fs2, path9, os4, LEVEL_NUM, LEVEL_LABEL, currentLevel, LOG_DIR, MAX_LOG_SIZE, MAX_LOG_DAYS, currentDate, currentLogFile, writeCount, RING_BUFFER_SIZE, ringBuffer, origConsoleLog, origConsoleError, origConsoleWarn, LOG, interceptorInstalled, LOG_PATH;
|
|
423
423
|
var init_logger = __esm({
|
|
424
424
|
"src/logging/logger.ts"() {
|
|
425
425
|
"use strict";
|
|
426
426
|
fs2 = __toESM(require("fs"));
|
|
427
|
-
|
|
427
|
+
path9 = __toESM(require("path"));
|
|
428
428
|
os4 = __toESM(require("os"));
|
|
429
429
|
LEVEL_NUM = { debug: 0, info: 1, warn: 2, error: 3 };
|
|
430
430
|
LEVEL_LABEL = { debug: "DBG", info: "INF", warn: "WRN", error: "ERR" };
|
|
431
431
|
currentLevel = "info";
|
|
432
|
-
LOG_DIR = process.platform === "win32" ?
|
|
432
|
+
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");
|
|
433
433
|
MAX_LOG_SIZE = 5 * 1024 * 1024;
|
|
434
434
|
MAX_LOG_DAYS = 7;
|
|
435
435
|
try {
|
|
@@ -437,16 +437,16 @@ var init_logger = __esm({
|
|
|
437
437
|
} catch {
|
|
438
438
|
}
|
|
439
439
|
currentDate = getDateStr();
|
|
440
|
-
currentLogFile =
|
|
440
|
+
currentLogFile = path9.join(LOG_DIR, `daemon-${currentDate}.log`);
|
|
441
441
|
cleanOldLogs();
|
|
442
442
|
try {
|
|
443
|
-
const oldLog =
|
|
443
|
+
const oldLog = path9.join(LOG_DIR, "daemon.log");
|
|
444
444
|
if (fs2.existsSync(oldLog)) {
|
|
445
|
-
const
|
|
446
|
-
const oldDate =
|
|
447
|
-
fs2.renameSync(oldLog,
|
|
445
|
+
const stat2 = fs2.statSync(oldLog);
|
|
446
|
+
const oldDate = stat2.mtime.toISOString().slice(0, 10);
|
|
447
|
+
fs2.renameSync(oldLog, path9.join(LOG_DIR, `daemon-${oldDate}.log`));
|
|
448
448
|
}
|
|
449
|
-
const oldLogBackup =
|
|
449
|
+
const oldLogBackup = path9.join(LOG_DIR, "daemon.log.old");
|
|
450
450
|
if (fs2.existsSync(oldLogBackup)) {
|
|
451
451
|
fs2.unlinkSync(oldLogBackup);
|
|
452
452
|
}
|
|
@@ -478,7 +478,7 @@ var init_logger = __esm({
|
|
|
478
478
|
}
|
|
479
479
|
};
|
|
480
480
|
interceptorInstalled = false;
|
|
481
|
-
LOG_PATH =
|
|
481
|
+
LOG_PATH = path9.join(LOG_DIR, `daemon-${getDateStr()}.log`);
|
|
482
482
|
}
|
|
483
483
|
});
|
|
484
484
|
|
|
@@ -1382,8 +1382,8 @@ var init_pty_transport = __esm({
|
|
|
1382
1382
|
if (cwd) {
|
|
1383
1383
|
try {
|
|
1384
1384
|
const fs16 = require("fs");
|
|
1385
|
-
const
|
|
1386
|
-
if (!
|
|
1385
|
+
const stat2 = fs16.statSync(cwd);
|
|
1386
|
+
if (!stat2.isDirectory()) cwd = os8.homedir();
|
|
1387
1387
|
} catch {
|
|
1388
1388
|
cwd = os8.homedir();
|
|
1389
1389
|
}
|
|
@@ -1465,9 +1465,9 @@ function buildCliScreenSnapshot(text) {
|
|
|
1465
1465
|
function findBinary(name) {
|
|
1466
1466
|
const trimmed = String(name || "").trim();
|
|
1467
1467
|
if (!trimmed) return trimmed;
|
|
1468
|
-
const expanded = trimmed.startsWith("~") ?
|
|
1469
|
-
if (
|
|
1470
|
-
return
|
|
1468
|
+
const expanded = trimmed.startsWith("~") ? path13.join(os9.homedir(), trimmed.slice(1)) : trimmed;
|
|
1469
|
+
if (path13.isAbsolute(expanded) || expanded.includes("/") || expanded.includes("\\")) {
|
|
1470
|
+
return path13.isAbsolute(expanded) ? expanded : path13.resolve(expanded);
|
|
1471
1471
|
}
|
|
1472
1472
|
const isWin = os9.platform() === "win32";
|
|
1473
1473
|
try {
|
|
@@ -1483,7 +1483,7 @@ function findBinary(name) {
|
|
|
1483
1483
|
}
|
|
1484
1484
|
}
|
|
1485
1485
|
function isScriptBinary(binaryPath) {
|
|
1486
|
-
if (!
|
|
1486
|
+
if (!path13.isAbsolute(binaryPath)) return false;
|
|
1487
1487
|
try {
|
|
1488
1488
|
const fs16 = require("fs");
|
|
1489
1489
|
const resolved = fs16.realpathSync(binaryPath);
|
|
@@ -1499,7 +1499,7 @@ function isScriptBinary(binaryPath) {
|
|
|
1499
1499
|
}
|
|
1500
1500
|
}
|
|
1501
1501
|
function looksLikeMachOOrElf(filePath) {
|
|
1502
|
-
if (!
|
|
1502
|
+
if (!path13.isAbsolute(filePath)) return false;
|
|
1503
1503
|
try {
|
|
1504
1504
|
const fs16 = require("fs");
|
|
1505
1505
|
const resolved = fs16.realpathSync(filePath);
|
|
@@ -1649,12 +1649,12 @@ function normalizeCliProviderForRuntime(raw) {
|
|
|
1649
1649
|
}
|
|
1650
1650
|
};
|
|
1651
1651
|
}
|
|
1652
|
-
var os9,
|
|
1652
|
+
var os9, path13, import_child_process4, buildCliSpawnEnv, COMMON_COMPARABLE_WRAP_WORDS;
|
|
1653
1653
|
var init_provider_cli_shared = __esm({
|
|
1654
1654
|
"src/cli-adapters/provider-cli-shared.ts"() {
|
|
1655
1655
|
"use strict";
|
|
1656
1656
|
os9 = __toESM(require("os"));
|
|
1657
|
-
|
|
1657
|
+
path13 = __toESM(require("path"));
|
|
1658
1658
|
import_child_process4 = require("child_process");
|
|
1659
1659
|
init_spawn_env();
|
|
1660
1660
|
buildCliSpawnEnv = import_session_host_core.sanitizeSpawnEnv;
|
|
@@ -1942,6 +1942,7 @@ function resolveCliAdapterConfig(provider) {
|
|
|
1942
1942
|
sendDelayMs: typeof provider.sendDelayMs === "number" ? Math.max(0, provider.sendDelayMs) : 0,
|
|
1943
1943
|
sendKey: typeof provider.sendKey === "string" && provider.sendKey.length > 0 ? provider.sendKey : "\r",
|
|
1944
1944
|
submitStrategy: provider.submitStrategy === "immediate" ? "immediate" : "wait_for_echo",
|
|
1945
|
+
requirePromptEchoBeforeSubmit: provider.requirePromptEchoBeforeSubmit === true,
|
|
1945
1946
|
providerResolutionMeta: {
|
|
1946
1947
|
type: provider.type,
|
|
1947
1948
|
name: provider.name,
|
|
@@ -1971,9 +1972,9 @@ function resolveCliSpawnPlan(options) {
|
|
|
1971
1972
|
const allArgs = [...spawnConfig.args, ...extraArgs];
|
|
1972
1973
|
let shellCmd;
|
|
1973
1974
|
let shellArgs;
|
|
1974
|
-
const useShellUnix = !isWin && (!!spawnConfig.shell || !
|
|
1975
|
+
const useShellUnix = !isWin && (!!spawnConfig.shell || !path14.isAbsolute(binaryPath) || isScriptBinary(binaryPath) || !looksLikeMachOOrElf(binaryPath));
|
|
1975
1976
|
const isCmdShim = isWin && /\.(cmd|bat)$/i.test(binaryPath);
|
|
1976
|
-
const useShellWin = !!spawnConfig.shell || isCmdShim || !
|
|
1977
|
+
const useShellWin = !!spawnConfig.shell || isCmdShim || !path14.isAbsolute(binaryPath) || isScriptBinary(binaryPath);
|
|
1977
1978
|
const useShell = isWin ? useShellWin : useShellUnix;
|
|
1978
1979
|
if (useShell) {
|
|
1979
1980
|
shellCmd = isWin ? "cmd.exe" : process.env.SHELL || "/bin/zsh";
|
|
@@ -2049,12 +2050,12 @@ function respondToCliTerminalQueries(options) {
|
|
|
2049
2050
|
}
|
|
2050
2051
|
return "";
|
|
2051
2052
|
}
|
|
2052
|
-
var os10,
|
|
2053
|
+
var os10, path14, import_session_host_core2;
|
|
2053
2054
|
var init_provider_cli_runtime = __esm({
|
|
2054
2055
|
"src/cli-adapters/provider-cli-runtime.ts"() {
|
|
2055
2056
|
"use strict";
|
|
2056
2057
|
os10 = __toESM(require("os"));
|
|
2057
|
-
|
|
2058
|
+
path14 = __toESM(require("path"));
|
|
2058
2059
|
import_session_host_core2 = require("@adhdev/session-host-core");
|
|
2059
2060
|
init_provider_cli_shared();
|
|
2060
2061
|
}
|
|
@@ -2207,6 +2208,7 @@ var init_provider_cli_adapter = __esm({
|
|
|
2207
2208
|
this.sendDelayMs = resolvedConfig.sendDelayMs;
|
|
2208
2209
|
this.sendKey = resolvedConfig.sendKey;
|
|
2209
2210
|
this.submitStrategy = resolvedConfig.submitStrategy;
|
|
2211
|
+
this.requirePromptEchoBeforeSubmit = resolvedConfig.requirePromptEchoBeforeSubmit;
|
|
2210
2212
|
this.providerResolutionMeta = resolvedConfig.providerResolutionMeta;
|
|
2211
2213
|
this.cliScripts = provider.scripts || {};
|
|
2212
2214
|
const scriptNames = listCliScriptNames(this.cliScripts);
|
|
@@ -2503,6 +2505,7 @@ var init_provider_cli_adapter = __esm({
|
|
|
2503
2505
|
sendDelayMs;
|
|
2504
2506
|
sendKey;
|
|
2505
2507
|
submitStrategy;
|
|
2508
|
+
requirePromptEchoBeforeSubmit;
|
|
2506
2509
|
static SCRIPT_STATUS_DEBOUNCE_MS = 3e3;
|
|
2507
2510
|
/** Inject CLI scripts after construction (e.g. when resolved by ProviderLoader) */
|
|
2508
2511
|
setCliScripts(scripts) {
|
|
@@ -2854,7 +2857,7 @@ var init_provider_cli_adapter = __esm({
|
|
|
2854
2857
|
`[${this.cliType}] Waiting for interactive prompt: status=${status} stableMs=${stableMs} recentOutputMs=${recentlyOutput} screen=${JSON.stringify(summarizeCliTraceText(screenText, 220)).slice(0, 260)}`
|
|
2855
2858
|
);
|
|
2856
2859
|
}
|
|
2857
|
-
await new Promise((
|
|
2860
|
+
await new Promise((resolve15) => setTimeout(resolve15, 50));
|
|
2858
2861
|
}
|
|
2859
2862
|
const finalScreenText = this.terminalScreen.getText() || "";
|
|
2860
2863
|
LOG.warn(
|
|
@@ -4023,6 +4026,22 @@ var init_provider_cli_adapter = __esm({
|
|
|
4023
4026
|
}
|
|
4024
4027
|
}
|
|
4025
4028
|
if (elapsed >= state.maxEchoWaitMs) {
|
|
4029
|
+
const diagnostic = {
|
|
4030
|
+
elapsed,
|
|
4031
|
+
maxEchoWaitMs: state.maxEchoWaitMs,
|
|
4032
|
+
submitDelayMs: state.submitDelayMs,
|
|
4033
|
+
promptSnippet: state.normalizedPromptSnippet,
|
|
4034
|
+
requirePromptEchoBeforeSubmit: this.requirePromptEchoBeforeSubmit,
|
|
4035
|
+
screenText: summarizeCliTraceText(screenText, 1e3)
|
|
4036
|
+
};
|
|
4037
|
+
this.recordTrace("submit_echo_missing", diagnostic);
|
|
4038
|
+
if (this.requirePromptEchoBeforeSubmit) {
|
|
4039
|
+
const message = `${this.cliName} prompt echo was not observed on the PTY screen before submit`;
|
|
4040
|
+
LOG.warn("CLI", `[${this.cliType}] ${message} elapsed=${elapsed}ms maxEchoWaitMs=${state.maxEchoWaitMs} screen=${JSON.stringify(diagnostic.screenText).slice(0, 240)}`);
|
|
4041
|
+
completion.rejectOnce(new Error(message));
|
|
4042
|
+
return;
|
|
4043
|
+
}
|
|
4044
|
+
LOG.warn("CLI", `[${this.cliType}] prompt echo was not observed before submit; sending submit key anyway elapsed=${elapsed}ms maxEchoWaitMs=${state.maxEchoWaitMs}`);
|
|
4026
4045
|
this.submitSendKey(state, completion);
|
|
4027
4046
|
return;
|
|
4028
4047
|
}
|
|
@@ -4042,7 +4061,7 @@ var init_provider_cli_adapter = __esm({
|
|
|
4042
4061
|
const deadline = Date.now() + 1e4;
|
|
4043
4062
|
while (this.startupParseGate && Date.now() < deadline) {
|
|
4044
4063
|
this.resolveStartupState("send_wait");
|
|
4045
|
-
await new Promise((
|
|
4064
|
+
await new Promise((resolve15) => setTimeout(resolve15, 50));
|
|
4046
4065
|
}
|
|
4047
4066
|
}
|
|
4048
4067
|
if (!allowInterventionPrompt) {
|
|
@@ -4123,13 +4142,13 @@ var init_provider_cli_adapter = __esm({
|
|
|
4123
4142
|
}
|
|
4124
4143
|
this.responseEpoch += 1;
|
|
4125
4144
|
this.responseSettleIgnoreUntil = Date.now() + submitDelayMs + this.timeouts.outputSettle + 250;
|
|
4126
|
-
await new Promise((
|
|
4145
|
+
await new Promise((resolve15, reject) => {
|
|
4127
4146
|
let resolved = false;
|
|
4128
4147
|
const completion = {
|
|
4129
4148
|
resolveOnce: () => {
|
|
4130
4149
|
if (resolved) return;
|
|
4131
4150
|
resolved = true;
|
|
4132
|
-
|
|
4151
|
+
resolve15();
|
|
4133
4152
|
},
|
|
4134
4153
|
rejectOnce: (error) => {
|
|
4135
4154
|
if (resolved) return;
|
|
@@ -4291,17 +4310,17 @@ var init_provider_cli_adapter = __esm({
|
|
|
4291
4310
|
}
|
|
4292
4311
|
}
|
|
4293
4312
|
waitForStopped(timeoutMs) {
|
|
4294
|
-
return new Promise((
|
|
4313
|
+
return new Promise((resolve15) => {
|
|
4295
4314
|
const startedAt = Date.now();
|
|
4296
4315
|
const timer = setInterval(() => {
|
|
4297
4316
|
if (!this.ptyProcess || this.currentStatus === "stopped") {
|
|
4298
4317
|
clearInterval(timer);
|
|
4299
|
-
|
|
4318
|
+
resolve15(true);
|
|
4300
4319
|
return;
|
|
4301
4320
|
}
|
|
4302
4321
|
if (Date.now() - startedAt >= timeoutMs) {
|
|
4303
4322
|
clearInterval(timer);
|
|
4304
|
-
|
|
4323
|
+
resolve15(false);
|
|
4305
4324
|
}
|
|
4306
4325
|
}, 100);
|
|
4307
4326
|
});
|
|
@@ -4487,6 +4506,7 @@ var init_provider_cli_adapter = __esm({
|
|
|
4487
4506
|
sendDelayMs: this.sendDelayMs,
|
|
4488
4507
|
sendKey: this.sendKey,
|
|
4489
4508
|
submitStrategy: this.submitStrategy,
|
|
4509
|
+
requirePromptEchoBeforeSubmit: this.requirePromptEchoBeforeSubmit,
|
|
4490
4510
|
submitPendingUntil: this.submitPendingUntil,
|
|
4491
4511
|
responseSettleIgnoreUntil: this.responseSettleIgnoreUntil,
|
|
4492
4512
|
resizeSuppressUntil: this.resizeSuppressUntil,
|
|
@@ -4541,6 +4561,7 @@ __export(index_exports, {
|
|
|
4541
4561
|
DEFAULT_CDP_SCAN_INTERVAL_MS: () => DEFAULT_CDP_SCAN_INTERVAL_MS,
|
|
4542
4562
|
DEFAULT_CHAT_TAIL_RECENT_MESSAGE_GRACE_MS: () => DEFAULT_CHAT_TAIL_RECENT_MESSAGE_GRACE_MS,
|
|
4543
4563
|
DEFAULT_DAEMON_PORT: () => DEFAULT_DAEMON_PORT,
|
|
4564
|
+
DEFAULT_GIT_WORKSPACE_POLL_INTERVAL_MS: () => DEFAULT_GIT_WORKSPACE_POLL_INTERVAL_MS,
|
|
4544
4565
|
DEFAULT_MACHINE_RUNTIME_SUBSCRIPTION_INTERVAL_MS: () => DEFAULT_MACHINE_RUNTIME_SUBSCRIPTION_INTERVAL_MS,
|
|
4545
4566
|
DEFAULT_SESSION_HOST_APP_NAME: () => DEFAULT_SESSION_HOST_APP_NAME,
|
|
4546
4567
|
DEFAULT_SESSION_HOST_DIAGNOSTICS_SUBSCRIPTION_INTERVAL_MS: () => DEFAULT_SESSION_HOST_DIAGNOSTICS_SUBSCRIPTION_INTERVAL_MS,
|
|
@@ -4559,8 +4580,12 @@ __export(index_exports, {
|
|
|
4559
4580
|
DaemonCommandRouter: () => DaemonCommandRouter,
|
|
4560
4581
|
DaemonStatusReporter: () => DaemonStatusReporter,
|
|
4561
4582
|
DevServer: () => DevServer,
|
|
4583
|
+
GitCommandError: () => GitCommandError,
|
|
4584
|
+
GitWorkspaceMonitor: () => GitWorkspaceMonitor,
|
|
4562
4585
|
IdeProviderInstance: () => IdeProviderInstance,
|
|
4586
|
+
InMemoryGitSnapshotStore: () => InMemoryGitSnapshotStore,
|
|
4563
4587
|
LOG: () => LOG,
|
|
4588
|
+
MIN_GIT_WORKSPACE_POLL_INTERVAL_MS: () => MIN_GIT_WORKSPACE_POLL_INTERVAL_MS,
|
|
4564
4589
|
MIN_MACHINE_RUNTIME_SUBSCRIPTION_INTERVAL_MS: () => MIN_MACHINE_RUNTIME_SUBSCRIPTION_INTERVAL_MS,
|
|
4565
4590
|
MIN_SESSION_HOST_DIAGNOSTICS_SUBSCRIPTION_INTERVAL_MS: () => MIN_SESSION_HOST_DIAGNOSTICS_SUBSCRIPTION_INTERVAL_MS,
|
|
4566
4591
|
NodePtyTransportFactory: () => NodePtyTransportFactory,
|
|
@@ -4569,6 +4594,7 @@ __export(index_exports, {
|
|
|
4569
4594
|
ProviderLoader: () => ProviderLoader,
|
|
4570
4595
|
STANDALONE_CDP_SCAN_INTERVAL_MS: () => STANDALONE_CDP_SCAN_INTERVAL_MS,
|
|
4571
4596
|
SessionHostPtyTransportFactory: () => SessionHostPtyTransportFactory,
|
|
4597
|
+
TurnSnapshotTracker: () => TurnSnapshotTracker,
|
|
4572
4598
|
VersionArchive: () => VersionArchive,
|
|
4573
4599
|
appendRecentActivity: () => appendRecentActivity,
|
|
4574
4600
|
buildAssistantChatMessage: () => buildAssistantChatMessage,
|
|
@@ -4588,9 +4614,14 @@ __export(index_exports, {
|
|
|
4588
4614
|
buildUserChatMessage: () => buildUserChatMessage,
|
|
4589
4615
|
classifyHotChatSessionsForSubscriptionFlush: () => classifyHotChatSessionsForSubscriptionFlush,
|
|
4590
4616
|
clearDebugTrace: () => clearDebugTrace,
|
|
4617
|
+
compareGitSnapshots: () => compareGitSnapshots,
|
|
4591
4618
|
configureDebugTraceStore: () => configureDebugTraceStore,
|
|
4592
4619
|
connectCdpManager: () => connectCdpManager,
|
|
4593
4620
|
createDebugTraceStore: () => createDebugTraceStore,
|
|
4621
|
+
createDefaultGitCommandServices: () => createDefaultGitCommandServices,
|
|
4622
|
+
createGitCompactSummary: () => createGitCompactSummary,
|
|
4623
|
+
createGitSnapshotStore: () => createGitSnapshotStore,
|
|
4624
|
+
createGitWorkspaceMonitor: () => createGitWorkspaceMonitor,
|
|
4594
4625
|
createInteractionId: () => createInteractionId,
|
|
4595
4626
|
detectAllVersions: () => detectAllVersions,
|
|
4596
4627
|
detectCLIs: () => detectCLIs,
|
|
@@ -4605,6 +4636,9 @@ __export(index_exports, {
|
|
|
4605
4636
|
getCurrentDaemonLogPath: () => getCurrentDaemonLogPath,
|
|
4606
4637
|
getDaemonLogDir: () => getDaemonLogDir,
|
|
4607
4638
|
getDebugRuntimeConfig: () => getDebugRuntimeConfig,
|
|
4639
|
+
getGitDiffSummary: () => getGitDiffSummary,
|
|
4640
|
+
getGitFileDiff: () => getGitFileDiff,
|
|
4641
|
+
getGitRepoStatus: () => getGitRepoStatus,
|
|
4608
4642
|
getHostMemorySnapshot: () => getHostMemorySnapshot,
|
|
4609
4643
|
getLogLevel: () => getLogLevel,
|
|
4610
4644
|
getNpmExecOptions: () => getNpmExecOptions,
|
|
@@ -4616,6 +4650,7 @@ __export(index_exports, {
|
|
|
4616
4650
|
getSessionHostRecoveryLabel: () => getSessionHostRecoveryLabel,
|
|
4617
4651
|
getSessionHostSurfaceKind: () => getSessionHostSurfaceKind,
|
|
4618
4652
|
getWorkspaceState: () => getWorkspaceState,
|
|
4653
|
+
handleGitCommand: () => handleGitCommand,
|
|
4619
4654
|
hasCdpManager: () => hasCdpManager,
|
|
4620
4655
|
hashSignatureParts: () => hashSignatureParts,
|
|
4621
4656
|
initDaemonComponents: () => initDaemonComponents,
|
|
@@ -4624,9 +4659,11 @@ __export(index_exports, {
|
|
|
4624
4659
|
isBuiltinChatMessageKind: () => isBuiltinChatMessageKind,
|
|
4625
4660
|
isCdpConnected: () => isCdpConnected,
|
|
4626
4661
|
isExtensionInstalled: () => isExtensionInstalled,
|
|
4662
|
+
isGitCommandName: () => isGitCommandName,
|
|
4627
4663
|
isIdeRunning: () => isIdeRunning,
|
|
4628
4664
|
isManagedStatusWaiting: () => isManagedStatusWaiting,
|
|
4629
4665
|
isManagedStatusWorking: () => isManagedStatusWorking,
|
|
4666
|
+
isPathInside: () => isPathInside,
|
|
4630
4667
|
isSessionHostLiveRuntime: () => isSessionHostLiveRuntime,
|
|
4631
4668
|
isSessionHostRecoverySnapshot: () => isSessionHostRecoverySnapshot,
|
|
4632
4669
|
isSetupComplete: () => isSetupComplete,
|
|
@@ -4644,10 +4681,13 @@ __export(index_exports, {
|
|
|
4644
4681
|
normalizeChatMessageKind: () => normalizeChatMessageKind,
|
|
4645
4682
|
normalizeChatMessages: () => normalizeChatMessages,
|
|
4646
4683
|
normalizeChatTailActiveModal: () => normalizeChatTailActiveModal,
|
|
4684
|
+
normalizeGitOutput: () => normalizeGitOutput,
|
|
4685
|
+
normalizeGitWorkspaceSubscriptionParams: () => normalizeGitWorkspaceSubscriptionParams,
|
|
4647
4686
|
normalizeInputEnvelope: () => normalizeInputEnvelope,
|
|
4648
4687
|
normalizeManagedStatus: () => normalizeManagedStatus,
|
|
4649
4688
|
normalizeMessageParts: () => normalizeMessageParts,
|
|
4650
4689
|
normalizeSessionModalFields: () => normalizeSessionModalFields,
|
|
4690
|
+
parsePorcelainV2Status: () => parsePorcelainV2Status,
|
|
4651
4691
|
parseProviderSourceConfigUpdate: () => parseProviderSourceConfigUpdate,
|
|
4652
4692
|
partitionSessionHostDiagnosticsSessions: () => partitionSessionHostDiagnosticsSessions,
|
|
4653
4693
|
partitionSessionHostRecords: () => partitionSessionHostRecords,
|
|
@@ -4663,9 +4703,11 @@ __export(index_exports, {
|
|
|
4663
4703
|
resolveChatMessageKind: () => resolveChatMessageKind,
|
|
4664
4704
|
resolveCurrentGlobalInstallSurface: () => resolveCurrentGlobalInstallSurface,
|
|
4665
4705
|
resolveDebugRuntimeConfig: () => resolveDebugRuntimeConfig,
|
|
4706
|
+
resolveGitRepository: () => resolveGitRepository,
|
|
4666
4707
|
resolveSessionHostAppName: () => resolveSessionHostAppName,
|
|
4667
4708
|
resolveSessionHostAppNameResolution: () => resolveSessionHostAppNameResolution,
|
|
4668
4709
|
runAsyncBatch: () => runAsyncBatch,
|
|
4710
|
+
runGit: () => runGit,
|
|
4669
4711
|
saveConfig: () => saveConfig,
|
|
4670
4712
|
saveState: () => saveState,
|
|
4671
4713
|
setDebugRuntimeConfig: () => setDebugRuntimeConfig,
|
|
@@ -4676,23 +4718,1304 @@ __export(index_exports, {
|
|
|
4676
4718
|
shutdownDaemonComponents: () => shutdownDaemonComponents,
|
|
4677
4719
|
spawnDetachedDaemonUpgradeHelper: () => spawnDetachedDaemonUpgradeHelper,
|
|
4678
4720
|
startDaemonDevSupport: () => startDaemonDevSupport,
|
|
4721
|
+
summarizeGitStatus: () => summarizeGitStatus,
|
|
4679
4722
|
updateConfig: () => updateConfig,
|
|
4680
4723
|
upsertSavedProviderSession: () => upsertSavedProviderSession
|
|
4681
4724
|
});
|
|
4682
4725
|
module.exports = __toCommonJS(index_exports);
|
|
4726
|
+
|
|
4727
|
+
// src/git/git-executor.ts
|
|
4728
|
+
var import_node_child_process = require("child_process");
|
|
4729
|
+
var import_node_fs = require("fs");
|
|
4730
|
+
var import_promises = require("fs/promises");
|
|
4731
|
+
var path = __toESM(require("path"));
|
|
4732
|
+
var import_node_util = require("util");
|
|
4733
|
+
var execFileAsync = (0, import_node_util.promisify)(import_node_child_process.execFile);
|
|
4734
|
+
var DEFAULT_TIMEOUT_MS = 5e3;
|
|
4735
|
+
var DEFAULT_MAX_BUFFER = 1024 * 1024;
|
|
4736
|
+
var GitCommandError = class extends Error {
|
|
4737
|
+
reason;
|
|
4738
|
+
stdout;
|
|
4739
|
+
stderr;
|
|
4740
|
+
exitCode;
|
|
4741
|
+
signal;
|
|
4742
|
+
argv;
|
|
4743
|
+
cwd;
|
|
4744
|
+
constructor(reason, message, details = {}) {
|
|
4745
|
+
super(message);
|
|
4746
|
+
if (details.cause !== void 0) {
|
|
4747
|
+
this.cause = details.cause;
|
|
4748
|
+
}
|
|
4749
|
+
this.name = "GitCommandError";
|
|
4750
|
+
this.reason = reason;
|
|
4751
|
+
this.stdout = normalizeGitOutput(details.stdout);
|
|
4752
|
+
this.stderr = normalizeGitOutput(details.stderr);
|
|
4753
|
+
this.exitCode = details.exitCode;
|
|
4754
|
+
this.signal = details.signal;
|
|
4755
|
+
this.argv = details.argv ? [...details.argv] : void 0;
|
|
4756
|
+
this.cwd = details.cwd;
|
|
4757
|
+
}
|
|
4758
|
+
};
|
|
4759
|
+
async function resolveGitRepository(workspace, options = {}) {
|
|
4760
|
+
const normalizedWorkspace = await validateWorkspace(workspace);
|
|
4761
|
+
const result = await execGitRaw(normalizedWorkspace, ["rev-parse", "--show-toplevel"], options, {
|
|
4762
|
+
mapNotGitRepo: true
|
|
4763
|
+
});
|
|
4764
|
+
const repoRoot = path.resolve(result.stdout.trim());
|
|
4765
|
+
if (!repoRoot) {
|
|
4766
|
+
throw new GitCommandError("not_git_repo", "Git did not return a repository root", {
|
|
4767
|
+
stdout: result.stdout,
|
|
4768
|
+
stderr: result.stderr,
|
|
4769
|
+
argv: ["rev-parse", "--show-toplevel"],
|
|
4770
|
+
cwd: normalizedWorkspace
|
|
4771
|
+
});
|
|
4772
|
+
}
|
|
4773
|
+
return {
|
|
4774
|
+
workspace: normalizedWorkspace,
|
|
4775
|
+
repoRoot,
|
|
4776
|
+
isGitRepo: true
|
|
4777
|
+
};
|
|
4778
|
+
}
|
|
4779
|
+
async function runGit(repoOrWorkspace, argv, options = {}) {
|
|
4780
|
+
validateGitArgv(argv);
|
|
4781
|
+
const repo = typeof repoOrWorkspace === "string" ? await resolveGitRepository(repoOrWorkspace, options) : repoOrWorkspace;
|
|
4782
|
+
if (!repo.repoRoot || !repo.isGitRepo) {
|
|
4783
|
+
throw new GitCommandError("not_git_repo", "Workspace is not a Git repository", {
|
|
4784
|
+
argv,
|
|
4785
|
+
cwd: repo.workspace
|
|
4786
|
+
});
|
|
4787
|
+
}
|
|
4788
|
+
const cwd = options.cwd ? await validateWorkspace(options.cwd) : await validateWorkspace(repo.workspace);
|
|
4789
|
+
const canonicalRepoRoot = await (0, import_promises.realpath)(repo.repoRoot);
|
|
4790
|
+
const canonicalCwd = await (0, import_promises.realpath)(cwd);
|
|
4791
|
+
if (!isPathInside(canonicalRepoRoot, canonicalCwd)) {
|
|
4792
|
+
throw new GitCommandError("path_outside_repo", "Git cwd is outside the repository root", {
|
|
4793
|
+
argv,
|
|
4794
|
+
cwd
|
|
4795
|
+
});
|
|
4796
|
+
}
|
|
4797
|
+
return execGitRaw(cwd, argv, options);
|
|
4798
|
+
}
|
|
4799
|
+
function normalizeGitOutput(value) {
|
|
4800
|
+
if (typeof value === "string") return value.replace(/\r\n/g, "\n");
|
|
4801
|
+
if (Buffer.isBuffer(value)) return value.toString("utf8").replace(/\r\n/g, "\n");
|
|
4802
|
+
if (value == null) return "";
|
|
4803
|
+
return String(value).replace(/\r\n/g, "\n");
|
|
4804
|
+
}
|
|
4805
|
+
function isPathInside(parent, child) {
|
|
4806
|
+
const relative3 = path.relative(path.resolve(parent), path.resolve(child));
|
|
4807
|
+
return relative3 === "" || !relative3.startsWith("..") && !path.isAbsolute(relative3);
|
|
4808
|
+
}
|
|
4809
|
+
async function validateWorkspace(workspace) {
|
|
4810
|
+
if (typeof workspace !== "string" || workspace.length === 0 || workspace.includes("\0")) {
|
|
4811
|
+
throw new GitCommandError("invalid_args", "Workspace must be a non-empty path");
|
|
4812
|
+
}
|
|
4813
|
+
if (!path.isAbsolute(workspace)) {
|
|
4814
|
+
throw new GitCommandError("invalid_args", "Workspace must be an absolute path", { cwd: workspace });
|
|
4815
|
+
}
|
|
4816
|
+
const normalizedWorkspace = path.resolve(workspace);
|
|
4817
|
+
try {
|
|
4818
|
+
const info = await (0, import_promises.stat)(normalizedWorkspace);
|
|
4819
|
+
if (!info.isDirectory()) {
|
|
4820
|
+
throw new GitCommandError("invalid_args", "Workspace must be an existing directory", {
|
|
4821
|
+
cwd: normalizedWorkspace
|
|
4822
|
+
});
|
|
4823
|
+
}
|
|
4824
|
+
await (0, import_promises.access)(normalizedWorkspace, import_node_fs.constants.R_OK);
|
|
4825
|
+
} catch (error) {
|
|
4826
|
+
if (error instanceof GitCommandError) throw error;
|
|
4827
|
+
throw new GitCommandError("invalid_args", "Workspace must be an existing directory", {
|
|
4828
|
+
cwd: normalizedWorkspace,
|
|
4829
|
+
cause: error
|
|
4830
|
+
});
|
|
4831
|
+
}
|
|
4832
|
+
return normalizedWorkspace;
|
|
4833
|
+
}
|
|
4834
|
+
function validateGitArgv(argv) {
|
|
4835
|
+
if (!Array.isArray(argv) || argv.length === 0) {
|
|
4836
|
+
throw new GitCommandError("invalid_args", "Git argv must be a non-empty string array", { argv });
|
|
4837
|
+
}
|
|
4838
|
+
for (const arg of argv) {
|
|
4839
|
+
if (typeof arg !== "string" || arg.length === 0 || arg.includes("\0")) {
|
|
4840
|
+
throw new GitCommandError("invalid_args", "Git argv contains an invalid argument", { argv });
|
|
4841
|
+
}
|
|
4842
|
+
}
|
|
4843
|
+
if (argv.includes("-C") || argv.some((arg) => arg.startsWith("--git-dir") || arg.startsWith("--work-tree"))) {
|
|
4844
|
+
throw new GitCommandError("invalid_args", "Git argv contains unsafe repository override arguments", {
|
|
4845
|
+
argv
|
|
4846
|
+
});
|
|
4847
|
+
}
|
|
4848
|
+
}
|
|
4849
|
+
async function execGitRaw(cwd, argv, options, behavior = {}) {
|
|
4850
|
+
validateGitArgv(argv);
|
|
4851
|
+
try {
|
|
4852
|
+
const result = await execFileAsync("git", [...argv], {
|
|
4853
|
+
cwd,
|
|
4854
|
+
encoding: "utf8",
|
|
4855
|
+
timeout: options.timeoutMs ?? DEFAULT_TIMEOUT_MS,
|
|
4856
|
+
maxBuffer: options.maxBuffer ?? DEFAULT_MAX_BUFFER,
|
|
4857
|
+
windowsHide: true
|
|
4858
|
+
});
|
|
4859
|
+
return {
|
|
4860
|
+
stdout: normalizeGitOutput(result.stdout),
|
|
4861
|
+
stderr: normalizeGitOutput(result.stderr)
|
|
4862
|
+
};
|
|
4863
|
+
} catch (error) {
|
|
4864
|
+
throw mapExecError(error, cwd, argv, behavior);
|
|
4865
|
+
}
|
|
4866
|
+
}
|
|
4867
|
+
function mapExecError(error, cwd, argv, behavior) {
|
|
4868
|
+
const execError = error;
|
|
4869
|
+
const stdout = normalizeGitOutput(execError.stdout);
|
|
4870
|
+
const stderr = normalizeGitOutput(execError.stderr);
|
|
4871
|
+
const code = execError.code;
|
|
4872
|
+
const signal = execError.signal;
|
|
4873
|
+
const message = [stderr.trim(), execError.message].filter(Boolean).join("\n");
|
|
4874
|
+
if (code === "ENOENT") {
|
|
4875
|
+
return new GitCommandError("git_not_installed", "Git executable was not found", {
|
|
4876
|
+
stdout,
|
|
4877
|
+
stderr,
|
|
4878
|
+
exitCode: code,
|
|
4879
|
+
signal,
|
|
4880
|
+
argv,
|
|
4881
|
+
cwd,
|
|
4882
|
+
cause: error
|
|
4883
|
+
});
|
|
4884
|
+
}
|
|
4885
|
+
if (execError.killed || /timed out/i.test(execError.message)) {
|
|
4886
|
+
return new GitCommandError("timeout", "Git command timed out", {
|
|
4887
|
+
stdout,
|
|
4888
|
+
stderr,
|
|
4889
|
+
exitCode: code,
|
|
4890
|
+
signal,
|
|
4891
|
+
argv,
|
|
4892
|
+
cwd,
|
|
4893
|
+
cause: error
|
|
4894
|
+
});
|
|
4895
|
+
}
|
|
4896
|
+
if (behavior.mapNotGitRepo && /not a git repository/i.test(stderr + "\n" + execError.message)) {
|
|
4897
|
+
return new GitCommandError("not_git_repo", "Workspace is not a Git repository", {
|
|
4898
|
+
stdout,
|
|
4899
|
+
stderr,
|
|
4900
|
+
exitCode: code,
|
|
4901
|
+
signal,
|
|
4902
|
+
argv,
|
|
4903
|
+
cwd,
|
|
4904
|
+
cause: error
|
|
4905
|
+
});
|
|
4906
|
+
}
|
|
4907
|
+
return new GitCommandError("git_command_failed", message || "Git command failed", {
|
|
4908
|
+
stdout,
|
|
4909
|
+
stderr,
|
|
4910
|
+
exitCode: code,
|
|
4911
|
+
signal,
|
|
4912
|
+
argv,
|
|
4913
|
+
cwd,
|
|
4914
|
+
cause: error
|
|
4915
|
+
});
|
|
4916
|
+
}
|
|
4917
|
+
|
|
4918
|
+
// src/git/git-status.ts
|
|
4919
|
+
async function getGitRepoStatus(workspace, options = {}) {
|
|
4920
|
+
const lastCheckedAt = Date.now();
|
|
4921
|
+
try {
|
|
4922
|
+
const repo = await resolveGitRepository(workspace, options);
|
|
4923
|
+
const statusOutput = await runGit(repo, ["status", "--porcelain=v2", "--branch"], options);
|
|
4924
|
+
const parsed = parsePorcelainV2Status(statusOutput.stdout);
|
|
4925
|
+
const head = await readHead(repo, options);
|
|
4926
|
+
const stashCount = await readStashCount(repo, options);
|
|
4927
|
+
return {
|
|
4928
|
+
workspace: repo.workspace,
|
|
4929
|
+
repoRoot: repo.repoRoot,
|
|
4930
|
+
isGitRepo: true,
|
|
4931
|
+
branch: parsed.branch,
|
|
4932
|
+
headCommit: head.commit,
|
|
4933
|
+
headMessage: head.message,
|
|
4934
|
+
upstream: parsed.upstream,
|
|
4935
|
+
ahead: parsed.ahead,
|
|
4936
|
+
behind: parsed.behind,
|
|
4937
|
+
staged: parsed.staged,
|
|
4938
|
+
modified: parsed.modified,
|
|
4939
|
+
untracked: parsed.untracked,
|
|
4940
|
+
deleted: parsed.deleted,
|
|
4941
|
+
renamed: parsed.renamed,
|
|
4942
|
+
hasConflicts: parsed.conflictFiles.length > 0,
|
|
4943
|
+
conflictFiles: parsed.conflictFiles,
|
|
4944
|
+
stashCount,
|
|
4945
|
+
lastCheckedAt
|
|
4946
|
+
};
|
|
4947
|
+
} catch (error) {
|
|
4948
|
+
if (error instanceof GitCommandError) {
|
|
4949
|
+
return emptyStatus(workspace, lastCheckedAt, error);
|
|
4950
|
+
}
|
|
4951
|
+
return emptyStatus(
|
|
4952
|
+
workspace,
|
|
4953
|
+
lastCheckedAt,
|
|
4954
|
+
new GitCommandError("git_command_failed", "Failed to read Git status", { cause: error })
|
|
4955
|
+
);
|
|
4956
|
+
}
|
|
4957
|
+
}
|
|
4958
|
+
function parsePorcelainV2Status(output) {
|
|
4959
|
+
const parsed = {
|
|
4960
|
+
branch: null,
|
|
4961
|
+
upstream: null,
|
|
4962
|
+
ahead: 0,
|
|
4963
|
+
behind: 0,
|
|
4964
|
+
staged: 0,
|
|
4965
|
+
modified: 0,
|
|
4966
|
+
untracked: 0,
|
|
4967
|
+
deleted: 0,
|
|
4968
|
+
renamed: 0,
|
|
4969
|
+
conflictFiles: []
|
|
4970
|
+
};
|
|
4971
|
+
for (const line of output.split("\n")) {
|
|
4972
|
+
if (!line) continue;
|
|
4973
|
+
if (line.startsWith("# branch.head ")) {
|
|
4974
|
+
const branch = line.slice("# branch.head ".length).trim();
|
|
4975
|
+
parsed.branch = branch && branch !== "(detached)" ? branch : null;
|
|
4976
|
+
continue;
|
|
4977
|
+
}
|
|
4978
|
+
if (line.startsWith("# branch.upstream ")) {
|
|
4979
|
+
parsed.upstream = line.slice("# branch.upstream ".length).trim() || null;
|
|
4980
|
+
continue;
|
|
4981
|
+
}
|
|
4982
|
+
if (line.startsWith("# branch.ab ")) {
|
|
4983
|
+
const match = line.match(/\+(-?\d+)\s+-(-?\d+)/);
|
|
4984
|
+
if (match) {
|
|
4985
|
+
parsed.ahead = Number.parseInt(match[1] ?? "0", 10) || 0;
|
|
4986
|
+
parsed.behind = Number.parseInt(match[2] ?? "0", 10) || 0;
|
|
4987
|
+
}
|
|
4988
|
+
continue;
|
|
4989
|
+
}
|
|
4990
|
+
if (line.startsWith("? ")) {
|
|
4991
|
+
parsed.untracked += 1;
|
|
4992
|
+
continue;
|
|
4993
|
+
}
|
|
4994
|
+
if (line.startsWith("u ")) {
|
|
4995
|
+
const fields = line.split(" ");
|
|
4996
|
+
const filePath = fields.slice(10).join(" ");
|
|
4997
|
+
if (filePath) parsed.conflictFiles.push(filePath);
|
|
4998
|
+
continue;
|
|
4999
|
+
}
|
|
5000
|
+
if (line.startsWith("1 ") || line.startsWith("2 ")) {
|
|
5001
|
+
const fields = line.split(" ");
|
|
5002
|
+
const xy = fields[1] ?? "..";
|
|
5003
|
+
const indexStatus = xy[0] ?? ".";
|
|
5004
|
+
const worktreeStatus = xy[1] ?? ".";
|
|
5005
|
+
if (isStagedStatus(indexStatus)) parsed.staged += 1;
|
|
5006
|
+
if (worktreeStatus === "M" || worktreeStatus === "T") parsed.modified += 1;
|
|
5007
|
+
if (indexStatus === "D" || worktreeStatus === "D") parsed.deleted += 1;
|
|
5008
|
+
if (indexStatus === "R" || worktreeStatus === "R") parsed.renamed += 1;
|
|
5009
|
+
if (xy.includes("U")) {
|
|
5010
|
+
const filePath = fields.slice(line.startsWith("2 ") ? 9 : 8).join(" ").split(" ")[0] ?? "";
|
|
5011
|
+
if (filePath) parsed.conflictFiles.push(filePath);
|
|
5012
|
+
}
|
|
5013
|
+
}
|
|
5014
|
+
}
|
|
5015
|
+
parsed.conflictFiles = Array.from(new Set(parsed.conflictFiles));
|
|
5016
|
+
return parsed;
|
|
5017
|
+
}
|
|
5018
|
+
async function readHead(repo, options) {
|
|
5019
|
+
try {
|
|
5020
|
+
const result = await runGit(repo, ["log", "-1", "--pretty=%h%x00%s"], options);
|
|
5021
|
+
const text = result.stdout.trimEnd();
|
|
5022
|
+
if (!text) return { commit: null, message: null };
|
|
5023
|
+
const [commit, ...messageParts] = text.split("\0");
|
|
5024
|
+
return {
|
|
5025
|
+
commit: commit || null,
|
|
5026
|
+
message: messageParts.join("\0") || null
|
|
5027
|
+
};
|
|
5028
|
+
} catch {
|
|
5029
|
+
return { commit: null, message: null };
|
|
5030
|
+
}
|
|
5031
|
+
}
|
|
5032
|
+
async function readStashCount(repo, options) {
|
|
5033
|
+
try {
|
|
5034
|
+
const result = await runGit(repo, ["stash", "list", "--format=%gd"], options);
|
|
5035
|
+
return result.stdout.split("\n").filter((line) => line.trim().length > 0).length;
|
|
5036
|
+
} catch {
|
|
5037
|
+
return 0;
|
|
5038
|
+
}
|
|
5039
|
+
}
|
|
5040
|
+
function isStagedStatus(status) {
|
|
5041
|
+
return status !== "." && status !== "?" && status !== "U";
|
|
5042
|
+
}
|
|
5043
|
+
function emptyStatus(workspace, lastCheckedAt, error) {
|
|
5044
|
+
return {
|
|
5045
|
+
workspace,
|
|
5046
|
+
repoRoot: null,
|
|
5047
|
+
isGitRepo: false,
|
|
5048
|
+
branch: null,
|
|
5049
|
+
headCommit: null,
|
|
5050
|
+
headMessage: null,
|
|
5051
|
+
upstream: null,
|
|
5052
|
+
ahead: 0,
|
|
5053
|
+
behind: 0,
|
|
5054
|
+
staged: 0,
|
|
5055
|
+
modified: 0,
|
|
5056
|
+
untracked: 0,
|
|
5057
|
+
deleted: 0,
|
|
5058
|
+
renamed: 0,
|
|
5059
|
+
hasConflicts: false,
|
|
5060
|
+
conflictFiles: [],
|
|
5061
|
+
stashCount: 0,
|
|
5062
|
+
lastCheckedAt,
|
|
5063
|
+
error: error.stderr || error.message,
|
|
5064
|
+
reason: error.reason
|
|
5065
|
+
};
|
|
5066
|
+
}
|
|
5067
|
+
|
|
5068
|
+
// src/git/git-diff.ts
|
|
5069
|
+
var import_promises2 = require("fs/promises");
|
|
5070
|
+
var path2 = __toESM(require("path"));
|
|
5071
|
+
var DEFAULT_MAX_FILES = 200;
|
|
5072
|
+
var DEFAULT_MAX_BYTES = 2e5;
|
|
5073
|
+
async function getGitDiffSummary(workspace, options = {}) {
|
|
5074
|
+
const lastCheckedAt = Date.now();
|
|
5075
|
+
try {
|
|
5076
|
+
const repo = await resolveGitRepository(workspace, options);
|
|
5077
|
+
const repoRoot = repo.repoRoot;
|
|
5078
|
+
const [unstagedNameStatus, unstagedNumstat, stagedNameStatus, stagedNumstat, untracked] = await Promise.all([
|
|
5079
|
+
runGit(repo, ["diff", "--no-ext-diff", "--name-status"], { ...options, cwd: repoRoot }),
|
|
5080
|
+
runGit(repo, ["diff", "--no-ext-diff", "--numstat"], { ...options, cwd: repoRoot }),
|
|
5081
|
+
runGit(repo, ["diff", "--cached", "--no-ext-diff", "--name-status"], { ...options, cwd: repoRoot }),
|
|
5082
|
+
runGit(repo, ["diff", "--cached", "--no-ext-diff", "--numstat"], { ...options, cwd: repoRoot }),
|
|
5083
|
+
runGit(repo, ["ls-files", "--others", "--exclude-standard"], { ...options, cwd: repoRoot })
|
|
5084
|
+
]);
|
|
5085
|
+
const outputBytes = byteLength(
|
|
5086
|
+
unstagedNameStatus.stdout + unstagedNumstat.stdout + stagedNameStatus.stdout + stagedNumstat.stdout + untracked.stdout
|
|
5087
|
+
);
|
|
5088
|
+
const changes = [
|
|
5089
|
+
...combineDiffEntries(unstagedNameStatus.stdout, unstagedNumstat.stdout, false),
|
|
5090
|
+
...combineDiffEntries(stagedNameStatus.stdout, stagedNumstat.stdout, true),
|
|
5091
|
+
...parseUntrackedFiles(untracked.stdout)
|
|
5092
|
+
];
|
|
5093
|
+
const maxFiles = normalizePositiveInteger(options.maxFiles, DEFAULT_MAX_FILES);
|
|
5094
|
+
const maxBytes = normalizePositiveInteger(options.maxBytes, DEFAULT_MAX_BYTES);
|
|
5095
|
+
const files = changes.slice(0, maxFiles);
|
|
5096
|
+
const truncated = changes.length > files.length || outputBytes > maxBytes;
|
|
5097
|
+
return {
|
|
5098
|
+
workspace: repo.workspace,
|
|
5099
|
+
repoRoot,
|
|
5100
|
+
isGitRepo: true,
|
|
5101
|
+
files,
|
|
5102
|
+
totalInsertions: files.reduce((sum, file) => sum + file.insertions, 0),
|
|
5103
|
+
totalDeletions: files.reduce((sum, file) => sum + file.deletions, 0),
|
|
5104
|
+
truncated,
|
|
5105
|
+
lastCheckedAt
|
|
5106
|
+
};
|
|
5107
|
+
} catch (error) {
|
|
5108
|
+
const gitError = error instanceof GitCommandError ? error : new GitCommandError("git_command_failed", "Failed to read Git diff summary", { cause: error });
|
|
5109
|
+
return {
|
|
5110
|
+
workspace,
|
|
5111
|
+
repoRoot: null,
|
|
5112
|
+
isGitRepo: false,
|
|
5113
|
+
files: [],
|
|
5114
|
+
totalInsertions: 0,
|
|
5115
|
+
totalDeletions: 0,
|
|
5116
|
+
truncated: false,
|
|
5117
|
+
lastCheckedAt,
|
|
5118
|
+
error: gitError.stderr || gitError.message,
|
|
5119
|
+
reason: gitError.reason
|
|
5120
|
+
};
|
|
5121
|
+
}
|
|
5122
|
+
}
|
|
5123
|
+
async function getGitFileDiff(workspace, filePath, options = {}) {
|
|
5124
|
+
const lastCheckedAt = Date.now();
|
|
5125
|
+
const repo = await resolveGitRepository(workspace, options);
|
|
5126
|
+
const repoRoot = repo.repoRoot;
|
|
5127
|
+
const selected = await resolveRepoFilePath(repoRoot, filePath);
|
|
5128
|
+
const maxBytes = normalizePositiveInteger(options.maxBytes, DEFAULT_MAX_BYTES);
|
|
5129
|
+
const [unstaged, staged] = await Promise.all([
|
|
5130
|
+
runGit(repo, ["diff", "--no-ext-diff", "--", selected.relativePath], { ...options, cwd: repoRoot }),
|
|
5131
|
+
runGit(repo, ["diff", "--cached", "--no-ext-diff", "--", selected.relativePath], { ...options, cwd: repoRoot })
|
|
5132
|
+
]);
|
|
5133
|
+
let diff = [unstaged.stdout, staged.stdout].filter((part) => part.length > 0).join("\n");
|
|
5134
|
+
if (!diff) {
|
|
5135
|
+
const untracked = await runGit(repo, ["ls-files", "--others", "--exclude-standard", "--", selected.relativePath], {
|
|
5136
|
+
...options,
|
|
5137
|
+
cwd: repoRoot
|
|
5138
|
+
});
|
|
5139
|
+
const untrackedFiles = untracked.stdout.split("\n").filter(Boolean);
|
|
5140
|
+
if (untrackedFiles.includes(selected.relativePath)) {
|
|
5141
|
+
diff = await buildUntrackedDiff(selected.absolutePath, selected.relativePath, maxBytes + 1);
|
|
5142
|
+
}
|
|
5143
|
+
}
|
|
5144
|
+
const bounded = truncateText(diff, maxBytes);
|
|
5145
|
+
return {
|
|
5146
|
+
workspace: repo.workspace,
|
|
5147
|
+
repoRoot,
|
|
5148
|
+
isGitRepo: true,
|
|
5149
|
+
path: selected.relativePath,
|
|
5150
|
+
diff: bounded.text,
|
|
5151
|
+
truncated: bounded.truncated,
|
|
5152
|
+
lastCheckedAt
|
|
5153
|
+
};
|
|
5154
|
+
}
|
|
5155
|
+
function combineDiffEntries(nameStatusOutput, numstatOutput, staged) {
|
|
5156
|
+
const statusEntries = parseNameStatus(nameStatusOutput);
|
|
5157
|
+
const numstatEntries = parseNumstat(numstatOutput);
|
|
5158
|
+
return statusEntries.map((entry, index) => {
|
|
5159
|
+
const stats = numstatEntries[index];
|
|
5160
|
+
return {
|
|
5161
|
+
path: entry.path,
|
|
5162
|
+
oldPath: entry.oldPath,
|
|
5163
|
+
status: entry.status,
|
|
5164
|
+
staged,
|
|
5165
|
+
insertions: stats?.insertions ?? 0,
|
|
5166
|
+
deletions: stats?.deletions ?? 0,
|
|
5167
|
+
binary: stats?.binary || void 0
|
|
5168
|
+
};
|
|
5169
|
+
});
|
|
5170
|
+
}
|
|
5171
|
+
function parseNameStatus(output) {
|
|
5172
|
+
return output.split("\n").filter(Boolean).map((line) => {
|
|
5173
|
+
const fields = line.split(" ");
|
|
5174
|
+
const code = fields[0] ?? "";
|
|
5175
|
+
const statusLetter = code[0] ?? "M";
|
|
5176
|
+
if (statusLetter === "R") {
|
|
5177
|
+
return {
|
|
5178
|
+
oldPath: fields[1] ?? "",
|
|
5179
|
+
path: fields[2] ?? fields[1] ?? "",
|
|
5180
|
+
status: "renamed"
|
|
5181
|
+
};
|
|
5182
|
+
}
|
|
5183
|
+
if (statusLetter === "C") {
|
|
5184
|
+
return {
|
|
5185
|
+
oldPath: fields[1] ?? "",
|
|
5186
|
+
path: fields[2] ?? fields[1] ?? "",
|
|
5187
|
+
status: "copied"
|
|
5188
|
+
};
|
|
5189
|
+
}
|
|
5190
|
+
return {
|
|
5191
|
+
path: fields[1] ?? "",
|
|
5192
|
+
status: mapNameStatus(statusLetter)
|
|
5193
|
+
};
|
|
5194
|
+
}).filter((entry) => entry.path.length > 0);
|
|
5195
|
+
}
|
|
5196
|
+
function parseNumstat(output) {
|
|
5197
|
+
return output.split("\n").filter(Boolean).map((line) => {
|
|
5198
|
+
const fields = line.split(" ");
|
|
5199
|
+
const insertionsText = fields[0] ?? "0";
|
|
5200
|
+
const deletionsText = fields[1] ?? "0";
|
|
5201
|
+
const binary = insertionsText === "-" || deletionsText === "-";
|
|
5202
|
+
return {
|
|
5203
|
+
path: fields.slice(2).join(" "),
|
|
5204
|
+
insertions: binary ? 0 : Number.parseInt(insertionsText, 10) || 0,
|
|
5205
|
+
deletions: binary ? 0 : Number.parseInt(deletionsText, 10) || 0,
|
|
5206
|
+
binary
|
|
5207
|
+
};
|
|
5208
|
+
});
|
|
5209
|
+
}
|
|
5210
|
+
function parseUntrackedFiles(output) {
|
|
5211
|
+
return output.split("\n").filter(Boolean).map((filePath) => ({
|
|
5212
|
+
path: filePath,
|
|
5213
|
+
status: "untracked",
|
|
5214
|
+
staged: false,
|
|
5215
|
+
insertions: 0,
|
|
5216
|
+
deletions: 0
|
|
5217
|
+
}));
|
|
5218
|
+
}
|
|
5219
|
+
function mapNameStatus(status) {
|
|
5220
|
+
switch (status) {
|
|
5221
|
+
case "A":
|
|
5222
|
+
return "added";
|
|
5223
|
+
case "D":
|
|
5224
|
+
return "deleted";
|
|
5225
|
+
case "R":
|
|
5226
|
+
return "renamed";
|
|
5227
|
+
case "C":
|
|
5228
|
+
return "copied";
|
|
5229
|
+
case "U":
|
|
5230
|
+
return "conflict";
|
|
5231
|
+
case "M":
|
|
5232
|
+
case "T":
|
|
5233
|
+
default:
|
|
5234
|
+
return "modified";
|
|
5235
|
+
}
|
|
5236
|
+
}
|
|
5237
|
+
async function resolveRepoFilePath(repoRoot, filePath) {
|
|
5238
|
+
if (typeof filePath !== "string" || filePath.length === 0 || filePath.includes("\0")) {
|
|
5239
|
+
throw new GitCommandError("invalid_args", "File path must be a non-empty path");
|
|
5240
|
+
}
|
|
5241
|
+
const canonicalRepoRoot = await (0, import_promises2.realpath)(repoRoot).catch(() => path2.resolve(repoRoot));
|
|
5242
|
+
const absolutePath = path2.isAbsolute(filePath) ? path2.resolve(filePath) : path2.resolve(repoRoot, filePath);
|
|
5243
|
+
const checkPath = await (0, import_promises2.realpath)(absolutePath).catch(() => absolutePath);
|
|
5244
|
+
const relativeBase = isPathInside(canonicalRepoRoot, checkPath) ? canonicalRepoRoot : path2.resolve(repoRoot);
|
|
5245
|
+
if (!isPathInside(canonicalRepoRoot, checkPath) && !isPathInside(repoRoot, absolutePath)) {
|
|
5246
|
+
throw new GitCommandError("path_outside_repo", "Selected file path is outside the repository root", {
|
|
5247
|
+
cwd: repoRoot
|
|
5248
|
+
});
|
|
5249
|
+
}
|
|
5250
|
+
const relativePath = path2.relative(relativeBase, checkPath).split(path2.sep).join("/");
|
|
5251
|
+
if (!relativePath || relativePath.startsWith("..") || path2.isAbsolute(relativePath)) {
|
|
5252
|
+
throw new GitCommandError("path_outside_repo", "Selected file path is outside the repository root", {
|
|
5253
|
+
cwd: repoRoot
|
|
5254
|
+
});
|
|
5255
|
+
}
|
|
5256
|
+
return { absolutePath, relativePath };
|
|
5257
|
+
}
|
|
5258
|
+
async function buildUntrackedDiff(absolutePath, relativePath, readLimit) {
|
|
5259
|
+
const content = await (0, import_promises2.readFile)(absolutePath, "utf8");
|
|
5260
|
+
const limitedContent = content.length > readLimit ? content.slice(0, readLimit) : content;
|
|
5261
|
+
const lines = limitedContent.length > 0 ? limitedContent.split("\n") : [];
|
|
5262
|
+
const plusLines = lines.filter((line, index) => index < lines.length - 1 || line.length > 0).map((line) => `+${line}`).join("\n");
|
|
5263
|
+
const lineCount = plusLines ? plusLines.split("\n").length : 0;
|
|
5264
|
+
return [
|
|
5265
|
+
`diff --git a/${relativePath} b/${relativePath}`,
|
|
5266
|
+
"new file mode 100644",
|
|
5267
|
+
"index 0000000..0000000",
|
|
5268
|
+
"--- /dev/null",
|
|
5269
|
+
`+++ b/${relativePath}`,
|
|
5270
|
+
`@@ -0,0 +1,${lineCount} @@`,
|
|
5271
|
+
plusLines
|
|
5272
|
+
].filter((line) => line.length > 0).join("\n");
|
|
5273
|
+
}
|
|
5274
|
+
function truncateText(text, maxBytes) {
|
|
5275
|
+
if (byteLength(text) <= maxBytes) return { text, truncated: false };
|
|
5276
|
+
return { text: Buffer.from(text, "utf8").subarray(0, maxBytes).toString("utf8"), truncated: true };
|
|
5277
|
+
}
|
|
5278
|
+
function byteLength(text) {
|
|
5279
|
+
return Buffer.byteLength(text, "utf8");
|
|
5280
|
+
}
|
|
5281
|
+
function normalizePositiveInteger(value, fallback) {
|
|
5282
|
+
if (!Number.isFinite(value) || value == null || value <= 0) return fallback;
|
|
5283
|
+
return Math.floor(value);
|
|
5284
|
+
}
|
|
5285
|
+
|
|
5286
|
+
// src/git/git-summary.ts
|
|
5287
|
+
function countStatusChangedFiles(status) {
|
|
5288
|
+
const conflictCount = status.conflictFiles.length > 0 ? status.conflictFiles.length : status.hasConflicts ? 1 : 0;
|
|
5289
|
+
return status.staged + status.modified + status.untracked + status.deleted + status.renamed + conflictCount;
|
|
5290
|
+
}
|
|
5291
|
+
function createGitCompactSummary(status, diffSummary) {
|
|
5292
|
+
const statusChangedFiles = countStatusChangedFiles(status);
|
|
5293
|
+
const diffChangedFiles = diffSummary?.files.length ?? 0;
|
|
5294
|
+
const changedFiles = Math.max(statusChangedFiles, diffChangedFiles);
|
|
5295
|
+
const conflictCount = status.conflictFiles.length > 0 ? status.conflictFiles.length : status.hasConflicts ? 1 : 0;
|
|
5296
|
+
return {
|
|
5297
|
+
isGitRepo: status.isGitRepo,
|
|
5298
|
+
repoRoot: status.repoRoot,
|
|
5299
|
+
branch: status.branch,
|
|
5300
|
+
dirty: status.staged > 0 || status.modified > 0 || status.untracked > 0 || status.deleted > 0 || status.renamed > 0 || conflictCount > 0 || changedFiles > 0,
|
|
5301
|
+
changedFiles,
|
|
5302
|
+
ahead: status.ahead,
|
|
5303
|
+
behind: status.behind,
|
|
5304
|
+
hasConflicts: status.hasConflicts || conflictCount > 0,
|
|
5305
|
+
lastCheckedAt: Math.max(status.lastCheckedAt, diffSummary?.lastCheckedAt ?? status.lastCheckedAt),
|
|
5306
|
+
error: status.error ?? diffSummary?.error,
|
|
5307
|
+
reason: status.reason ?? diffSummary?.reason
|
|
5308
|
+
};
|
|
5309
|
+
}
|
|
5310
|
+
var summarizeGitStatus = createGitCompactSummary;
|
|
5311
|
+
|
|
5312
|
+
// src/git/git-snapshot-store.ts
|
|
5313
|
+
function normalizeCapacity(capacity) {
|
|
5314
|
+
return Math.max(1, Math.floor(capacity ?? 100));
|
|
5315
|
+
}
|
|
5316
|
+
function createEmptyDiffSummary(status) {
|
|
5317
|
+
return {
|
|
5318
|
+
workspace: status.workspace,
|
|
5319
|
+
repoRoot: status.repoRoot,
|
|
5320
|
+
isGitRepo: status.isGitRepo,
|
|
5321
|
+
files: [],
|
|
5322
|
+
totalInsertions: 0,
|
|
5323
|
+
totalDeletions: 0,
|
|
5324
|
+
truncated: false,
|
|
5325
|
+
lastCheckedAt: status.lastCheckedAt,
|
|
5326
|
+
error: status.error,
|
|
5327
|
+
reason: status.reason
|
|
5328
|
+
};
|
|
5329
|
+
}
|
|
5330
|
+
function changedFileKey(file) {
|
|
5331
|
+
return `${file.oldPath ?? ""}\0${file.path}`;
|
|
5332
|
+
}
|
|
5333
|
+
function uniqueSorted(values) {
|
|
5334
|
+
return Array.from(new Set(Array.from(values).filter(Boolean))).sort((a, b) => a.localeCompare(b));
|
|
5335
|
+
}
|
|
5336
|
+
function plural(count, singular, pluralText = `${singular}s`) {
|
|
5337
|
+
return count === 1 ? singular : pluralText;
|
|
5338
|
+
}
|
|
5339
|
+
function compareGitSnapshots(before, after) {
|
|
5340
|
+
const beforeFileKeys = new Set(before.diffSummary.files.map(changedFileKey));
|
|
5341
|
+
const changedAfterFiles = after.diffSummary.files.filter((file) => !beforeFileKeys.has(changedFileKey(file)));
|
|
5342
|
+
const addedFiles = [];
|
|
5343
|
+
const modifiedFiles = [];
|
|
5344
|
+
const deletedFiles = [];
|
|
5345
|
+
const renamedFiles = [];
|
|
5346
|
+
const untrackedFiles = [];
|
|
5347
|
+
const conflictFilesFromDiff = [];
|
|
5348
|
+
let totalInsertions = 0;
|
|
5349
|
+
let totalDeletions = 0;
|
|
5350
|
+
for (const file of changedAfterFiles) {
|
|
5351
|
+
totalInsertions += file.insertions;
|
|
5352
|
+
totalDeletions += file.deletions;
|
|
5353
|
+
switch (file.status) {
|
|
5354
|
+
case "added":
|
|
5355
|
+
case "copied":
|
|
5356
|
+
addedFiles.push(file.path);
|
|
5357
|
+
break;
|
|
5358
|
+
case "modified":
|
|
5359
|
+
modifiedFiles.push(file.path);
|
|
5360
|
+
break;
|
|
5361
|
+
case "deleted":
|
|
5362
|
+
deletedFiles.push(file.path);
|
|
5363
|
+
break;
|
|
5364
|
+
case "renamed":
|
|
5365
|
+
renamedFiles.push({ oldPath: file.oldPath ?? file.path, path: file.path });
|
|
5366
|
+
break;
|
|
5367
|
+
case "untracked":
|
|
5368
|
+
untrackedFiles.push(file.path);
|
|
5369
|
+
break;
|
|
5370
|
+
case "conflict":
|
|
5371
|
+
conflictFilesFromDiff.push(file.path);
|
|
5372
|
+
break;
|
|
5373
|
+
}
|
|
5374
|
+
}
|
|
5375
|
+
renamedFiles.sort((a, b) => `${a.oldPath}\0${a.path}`.localeCompare(`${b.oldPath}\0${b.path}`));
|
|
5376
|
+
const conflictFiles = uniqueSorted([...after.status.conflictFiles, ...conflictFilesFromDiff]);
|
|
5377
|
+
const changedFiles = changedAfterFiles.length;
|
|
5378
|
+
const hasConflicts = after.status.hasConflicts || conflictFiles.length > 0;
|
|
5379
|
+
const summaryParts = [];
|
|
5380
|
+
if (changedFiles > 0) summaryParts.push(`${changedFiles} ${plural(changedFiles, "file")} changed`);
|
|
5381
|
+
if (addedFiles.length > 0) summaryParts.push(`${addedFiles.length} added`);
|
|
5382
|
+
if (modifiedFiles.length > 0) summaryParts.push(`${modifiedFiles.length} modified`);
|
|
5383
|
+
if (deletedFiles.length > 0) summaryParts.push(`${deletedFiles.length} deleted`);
|
|
5384
|
+
if (renamedFiles.length > 0) summaryParts.push(`${renamedFiles.length} renamed`);
|
|
5385
|
+
if (untrackedFiles.length > 0) summaryParts.push(`${untrackedFiles.length} untracked`);
|
|
5386
|
+
if (hasConflicts) summaryParts.push(`${conflictFiles.length || 1} ${plural(conflictFiles.length || 1, "conflict")}`);
|
|
5387
|
+
return {
|
|
5388
|
+
beforeSnapshotId: before.id,
|
|
5389
|
+
afterSnapshotId: after.id,
|
|
5390
|
+
workspace: after.workspace,
|
|
5391
|
+
repoRoot: after.repoRoot,
|
|
5392
|
+
changedFiles,
|
|
5393
|
+
addedFiles: uniqueSorted(addedFiles),
|
|
5394
|
+
modifiedFiles: uniqueSorted(modifiedFiles),
|
|
5395
|
+
deletedFiles: uniqueSorted(deletedFiles),
|
|
5396
|
+
renamedFiles,
|
|
5397
|
+
untrackedFiles: uniqueSorted(untrackedFiles),
|
|
5398
|
+
conflictFiles,
|
|
5399
|
+
totalInsertions,
|
|
5400
|
+
totalDeletions,
|
|
5401
|
+
hasConflicts,
|
|
5402
|
+
currentStatus: after.status,
|
|
5403
|
+
summaryText: summaryParts.length > 0 ? summaryParts.join(", ") : "No file-set changes between snapshots."
|
|
5404
|
+
};
|
|
5405
|
+
}
|
|
5406
|
+
var InMemoryGitSnapshotStore = class {
|
|
5407
|
+
snapshots = /* @__PURE__ */ new Map();
|
|
5408
|
+
order = [];
|
|
5409
|
+
capacity;
|
|
5410
|
+
now;
|
|
5411
|
+
idPrefix;
|
|
5412
|
+
getStatusProvider;
|
|
5413
|
+
getDiffSummaryProvider;
|
|
5414
|
+
counter = 0;
|
|
5415
|
+
constructor(options = {}) {
|
|
5416
|
+
this.capacity = normalizeCapacity(options.capacity);
|
|
5417
|
+
this.now = options.now ?? Date.now;
|
|
5418
|
+
this.idPrefix = options.idPrefix ?? "git-snapshot";
|
|
5419
|
+
this.getStatusProvider = options.getStatus;
|
|
5420
|
+
this.getDiffSummaryProvider = options.getDiffSummary;
|
|
5421
|
+
}
|
|
5422
|
+
async create(input) {
|
|
5423
|
+
const getStatus = input.getStatus ?? this.getStatusProvider;
|
|
5424
|
+
if (!getStatus) {
|
|
5425
|
+
throw new Error("GitSnapshotStore requires an injected getStatus provider");
|
|
5426
|
+
}
|
|
5427
|
+
const status = await getStatus(input.workspace);
|
|
5428
|
+
const getDiffSummary = input.getDiffSummary ?? this.getDiffSummaryProvider;
|
|
5429
|
+
const diffSummary = getDiffSummary ? await getDiffSummary(input.workspace, status) : createEmptyDiffSummary(status);
|
|
5430
|
+
const createdAt = this.now();
|
|
5431
|
+
const id = `${this.idPrefix}-${createdAt}-${++this.counter}`;
|
|
5432
|
+
const snapshot = {
|
|
5433
|
+
id,
|
|
5434
|
+
workspace: input.workspace,
|
|
5435
|
+
repoRoot: status.repoRoot ?? input.workspace,
|
|
5436
|
+
sessionId: input.sessionId,
|
|
5437
|
+
turnId: input.turnId,
|
|
5438
|
+
reason: input.reason,
|
|
5439
|
+
status,
|
|
5440
|
+
diffSummary,
|
|
5441
|
+
createdAt
|
|
5442
|
+
};
|
|
5443
|
+
this.snapshots.set(id, snapshot);
|
|
5444
|
+
this.order.push(id);
|
|
5445
|
+
this.enforceCapacity();
|
|
5446
|
+
return snapshot;
|
|
5447
|
+
}
|
|
5448
|
+
get(id) {
|
|
5449
|
+
return this.snapshots.get(id);
|
|
5450
|
+
}
|
|
5451
|
+
compare(beforeSnapshotId, afterSnapshotId) {
|
|
5452
|
+
const before = this.snapshots.get(beforeSnapshotId);
|
|
5453
|
+
if (!before) throw new Error(`Unknown before snapshot: ${beforeSnapshotId}`);
|
|
5454
|
+
const after = this.snapshots.get(afterSnapshotId);
|
|
5455
|
+
if (!after) throw new Error(`Unknown after snapshot: ${afterSnapshotId}`);
|
|
5456
|
+
return compareGitSnapshots(before, after);
|
|
5457
|
+
}
|
|
5458
|
+
list(query = {}) {
|
|
5459
|
+
const limit = Math.max(1, Math.floor(query.limit ?? this.capacity));
|
|
5460
|
+
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);
|
|
5461
|
+
}
|
|
5462
|
+
clear() {
|
|
5463
|
+
this.snapshots.clear();
|
|
5464
|
+
this.order.splice(0, this.order.length);
|
|
5465
|
+
}
|
|
5466
|
+
enforceCapacity() {
|
|
5467
|
+
while (this.order.length > this.capacity) {
|
|
5468
|
+
const evictedId = this.order.shift();
|
|
5469
|
+
if (evictedId) this.snapshots.delete(evictedId);
|
|
5470
|
+
}
|
|
5471
|
+
}
|
|
5472
|
+
};
|
|
5473
|
+
function createGitSnapshotStore(options = {}) {
|
|
5474
|
+
return new InMemoryGitSnapshotStore(options);
|
|
5475
|
+
}
|
|
5476
|
+
|
|
5477
|
+
// src/git/git-monitor.ts
|
|
5478
|
+
var DEFAULT_GIT_WORKSPACE_POLL_INTERVAL_MS = 5e3;
|
|
5479
|
+
var MIN_GIT_WORKSPACE_POLL_INTERVAL_MS = 1e3;
|
|
5480
|
+
function defaultStatusProvider(workspace) {
|
|
5481
|
+
return getGitRepoStatus(workspace);
|
|
5482
|
+
}
|
|
5483
|
+
function defaultDiffSummaryProvider(workspace) {
|
|
5484
|
+
return getGitDiffSummary(workspace);
|
|
5485
|
+
}
|
|
5486
|
+
function normalizeIntervalMs(value, defaultIntervalMs, minIntervalMs) {
|
|
5487
|
+
const requested = Number.isFinite(value) ? Math.floor(value) : defaultIntervalMs;
|
|
5488
|
+
return Math.max(minIntervalMs, requested > 0 ? requested : defaultIntervalMs);
|
|
5489
|
+
}
|
|
5490
|
+
function normalizeGitWorkspaceSubscriptionParams(params, options = {}) {
|
|
5491
|
+
const minIntervalMs = Math.max(1, Math.floor(options.minIntervalMs ?? MIN_GIT_WORKSPACE_POLL_INTERVAL_MS));
|
|
5492
|
+
const defaultIntervalMs = Math.max(minIntervalMs, Math.floor(options.defaultIntervalMs ?? DEFAULT_GIT_WORKSPACE_POLL_INTERVAL_MS));
|
|
5493
|
+
return {
|
|
5494
|
+
workspace: params.workspace,
|
|
5495
|
+
includeDiffSummary: Boolean(params.includeDiffSummary),
|
|
5496
|
+
intervalMs: normalizeIntervalMs(params.intervalMs, defaultIntervalMs, minIntervalMs)
|
|
5497
|
+
};
|
|
5498
|
+
}
|
|
5499
|
+
var GitWorkspaceMonitor = class {
|
|
5500
|
+
getStatusProvider;
|
|
5501
|
+
getDiffSummaryProvider;
|
|
5502
|
+
now;
|
|
5503
|
+
minIntervalMs;
|
|
5504
|
+
defaultIntervalMs;
|
|
5505
|
+
keyPrefix;
|
|
5506
|
+
cache = /* @__PURE__ */ new Map();
|
|
5507
|
+
listeners = /* @__PURE__ */ new Set();
|
|
5508
|
+
seq = 0;
|
|
5509
|
+
constructor(options = {}) {
|
|
5510
|
+
this.getStatusProvider = options.getStatus ?? defaultStatusProvider;
|
|
5511
|
+
this.getDiffSummaryProvider = options.getDiffSummary ?? defaultDiffSummaryProvider;
|
|
5512
|
+
this.now = options.now ?? Date.now;
|
|
5513
|
+
this.minIntervalMs = Math.max(1, Math.floor(options.minIntervalMs ?? MIN_GIT_WORKSPACE_POLL_INTERVAL_MS));
|
|
5514
|
+
this.defaultIntervalMs = Math.max(
|
|
5515
|
+
this.minIntervalMs,
|
|
5516
|
+
Math.floor(options.defaultIntervalMs ?? DEFAULT_GIT_WORKSPACE_POLL_INTERVAL_MS)
|
|
5517
|
+
);
|
|
5518
|
+
this.keyPrefix = options.keyPrefix ?? "git";
|
|
5519
|
+
}
|
|
5520
|
+
async refresh(params) {
|
|
5521
|
+
const normalized = this.normalize(typeof params === "string" ? { workspace: params } : params);
|
|
5522
|
+
const status = await this.getStatusProvider(normalized.workspace);
|
|
5523
|
+
const diffSummary = normalized.includeDiffSummary ? await this.getDiffSummaryProvider(normalized.workspace, status) : void 0;
|
|
5524
|
+
const compactSummary = createGitCompactSummary(status, diffSummary);
|
|
5525
|
+
const timestamp = this.now();
|
|
5526
|
+
const seq = ++this.seq;
|
|
5527
|
+
const key = this.keyForWorkspace(normalized.workspace);
|
|
5528
|
+
const update = {
|
|
5529
|
+
topic: "workspace.git",
|
|
5530
|
+
key,
|
|
5531
|
+
workspace: normalized.workspace,
|
|
5532
|
+
status,
|
|
5533
|
+
diffSummary,
|
|
5534
|
+
seq,
|
|
5535
|
+
timestamp
|
|
5536
|
+
};
|
|
5537
|
+
const cacheEntry = {
|
|
5538
|
+
key,
|
|
5539
|
+
workspace: normalized.workspace,
|
|
5540
|
+
status,
|
|
5541
|
+
diffSummary,
|
|
5542
|
+
compactSummary,
|
|
5543
|
+
seq,
|
|
5544
|
+
timestamp
|
|
5545
|
+
};
|
|
5546
|
+
this.cache.set(normalized.workspace, cacheEntry);
|
|
5547
|
+
this.emit(update, cacheEntry);
|
|
5548
|
+
return update;
|
|
5549
|
+
}
|
|
5550
|
+
poll(params) {
|
|
5551
|
+
return this.refresh(params);
|
|
5552
|
+
}
|
|
5553
|
+
getCached(workspace) {
|
|
5554
|
+
return this.cache.get(workspace);
|
|
5555
|
+
}
|
|
5556
|
+
getCompactSummary(workspace) {
|
|
5557
|
+
return this.cache.get(workspace)?.compactSummary;
|
|
5558
|
+
}
|
|
5559
|
+
onUpdate(listener) {
|
|
5560
|
+
this.listeners.add(listener);
|
|
5561
|
+
return () => {
|
|
5562
|
+
this.listeners.delete(listener);
|
|
5563
|
+
};
|
|
5564
|
+
}
|
|
5565
|
+
createSubscription(params, listener) {
|
|
5566
|
+
const normalized = this.normalize(params);
|
|
5567
|
+
const scopedListener = listener ? (update, cacheEntry) => {
|
|
5568
|
+
if (update.workspace === normalized.workspace) listener(update, cacheEntry);
|
|
5569
|
+
} : void 0;
|
|
5570
|
+
const unsubscribe = scopedListener ? this.onUpdate(scopedListener) : () => void 0;
|
|
5571
|
+
return {
|
|
5572
|
+
params: normalized,
|
|
5573
|
+
refresh: () => this.refresh(normalized),
|
|
5574
|
+
getCached: () => this.getCached(normalized.workspace),
|
|
5575
|
+
dispose: unsubscribe
|
|
5576
|
+
};
|
|
5577
|
+
}
|
|
5578
|
+
normalize(params) {
|
|
5579
|
+
return normalizeGitWorkspaceSubscriptionParams(params, {
|
|
5580
|
+
defaultIntervalMs: this.defaultIntervalMs,
|
|
5581
|
+
minIntervalMs: this.minIntervalMs
|
|
5582
|
+
});
|
|
5583
|
+
}
|
|
5584
|
+
keyForWorkspace(workspace) {
|
|
5585
|
+
return `${this.keyPrefix}:${workspace}`;
|
|
5586
|
+
}
|
|
5587
|
+
emit(update, cacheEntry) {
|
|
5588
|
+
for (const listener of this.listeners) {
|
|
5589
|
+
listener(update, cacheEntry);
|
|
5590
|
+
}
|
|
5591
|
+
}
|
|
5592
|
+
};
|
|
5593
|
+
function createGitWorkspaceMonitor(options = {}) {
|
|
5594
|
+
return new GitWorkspaceMonitor(options);
|
|
5595
|
+
}
|
|
5596
|
+
|
|
5597
|
+
// src/git/git-commands.ts
|
|
5598
|
+
var path3 = __toESM(require("path"));
|
|
5599
|
+
var GIT_COMMAND_NAMES = /* @__PURE__ */ new Set([
|
|
5600
|
+
"git_status",
|
|
5601
|
+
"git_diff_summary",
|
|
5602
|
+
"git_diff_file",
|
|
5603
|
+
"git_snapshot_create",
|
|
5604
|
+
"git_snapshot_compare",
|
|
5605
|
+
"git_log",
|
|
5606
|
+
"git_checkpoint",
|
|
5607
|
+
"git_stash_push",
|
|
5608
|
+
"git_stash_pop",
|
|
5609
|
+
"git_checkout_files",
|
|
5610
|
+
"git_remote_url"
|
|
5611
|
+
]);
|
|
5612
|
+
var SNAPSHOT_REASONS = /* @__PURE__ */ new Set([
|
|
5613
|
+
"session_baseline",
|
|
5614
|
+
"before_user_input_dispatch",
|
|
5615
|
+
"before_agent_work",
|
|
5616
|
+
"after_agent_work",
|
|
5617
|
+
"manual"
|
|
5618
|
+
]);
|
|
5619
|
+
var FAILURE_REASONS = /* @__PURE__ */ new Set([
|
|
5620
|
+
"not_git_repo",
|
|
5621
|
+
"git_not_installed",
|
|
5622
|
+
"timeout",
|
|
5623
|
+
"path_outside_repo",
|
|
5624
|
+
"dirty_index_required",
|
|
5625
|
+
"conflict",
|
|
5626
|
+
"invalid_args",
|
|
5627
|
+
"git_command_failed"
|
|
5628
|
+
]);
|
|
5629
|
+
function failure(reason, error) {
|
|
5630
|
+
return { success: false, reason, error };
|
|
5631
|
+
}
|
|
5632
|
+
function serviceNotImplemented(command) {
|
|
5633
|
+
return failure("invalid_args", `${command} is not implemented: daemon-core Git service is not configured`);
|
|
5634
|
+
}
|
|
5635
|
+
var defaultSnapshotStore = createGitSnapshotStore({
|
|
5636
|
+
getStatus: (workspace) => getGitRepoStatus(workspace),
|
|
5637
|
+
getDiffSummary: (workspace) => getGitDiffSummary(workspace)
|
|
5638
|
+
});
|
|
5639
|
+
function createDefaultGitCommandServices() {
|
|
5640
|
+
return {
|
|
5641
|
+
getStatus: ({ workspace }) => getGitRepoStatus(workspace),
|
|
5642
|
+
getDiffSummary: ({ workspace }) => getGitDiffSummary(workspace),
|
|
5643
|
+
getDiffFile: ({ workspace, path: filePath }) => getGitFileDiff(workspace, filePath),
|
|
5644
|
+
createSnapshot: ({ workspace, reason, sessionId, turnId }) => defaultSnapshotStore.create({
|
|
5645
|
+
workspace,
|
|
5646
|
+
reason,
|
|
5647
|
+
sessionId,
|
|
5648
|
+
turnId
|
|
5649
|
+
}),
|
|
5650
|
+
compareSnapshots: ({ beforeSnapshotId, afterSnapshotId }) => defaultSnapshotStore.compare(beforeSnapshotId, afterSnapshotId),
|
|
5651
|
+
getLog: ({ workspace, limit, path: filePath, since, until }) => getGitLog(workspace, { limit, path: filePath, since, until }),
|
|
5652
|
+
checkpoint: async ({ workspace, message, includeUntracked = false }) => gitCheckpoint(workspace, message, includeUntracked),
|
|
5653
|
+
stashPush: async ({ workspace, message, includeUntracked = false }) => gitStashPush(workspace, message, includeUntracked),
|
|
5654
|
+
stashPop: async ({ workspace, stashRef }) => gitStashPop(workspace, stashRef),
|
|
5655
|
+
checkoutFiles: async ({ workspace, paths }) => gitCheckoutFiles(workspace, paths),
|
|
5656
|
+
getRemoteUrl: async ({ workspace, remote = "origin" }) => gitGetRemoteUrl(workspace, remote)
|
|
5657
|
+
};
|
|
5658
|
+
}
|
|
5659
|
+
var defaultGitCommandServices = createDefaultGitCommandServices();
|
|
5660
|
+
function validateWorkspace2(args) {
|
|
5661
|
+
if (typeof args?.workspace !== "string") {
|
|
5662
|
+
return failure("invalid_args", "workspace must be a non-empty absolute path");
|
|
5663
|
+
}
|
|
5664
|
+
const workspace = args.workspace.trim();
|
|
5665
|
+
if (!workspace || !path3.isAbsolute(workspace)) {
|
|
5666
|
+
return failure("invalid_args", "workspace must be a non-empty absolute path");
|
|
5667
|
+
}
|
|
5668
|
+
return { workspace };
|
|
5669
|
+
}
|
|
5670
|
+
function validateRepoPath(args) {
|
|
5671
|
+
if (typeof args?.path !== "string" || !args.path.trim()) {
|
|
5672
|
+
return failure("invalid_args", "path must be a non-empty repository-relative path");
|
|
5673
|
+
}
|
|
5674
|
+
return { path: args.path.trim() };
|
|
5675
|
+
}
|
|
5676
|
+
function validateSnapshotId(args, key) {
|
|
5677
|
+
if (typeof args?.[key] !== "string" || !args[key].trim()) {
|
|
5678
|
+
return failure("invalid_args", `${key} must be a non-empty string`);
|
|
5679
|
+
}
|
|
5680
|
+
return args[key].trim();
|
|
5681
|
+
}
|
|
5682
|
+
function parseSnapshotReason(args) {
|
|
5683
|
+
if (args?.reason === void 0 || args?.reason === null || args?.reason === "") {
|
|
5684
|
+
return "manual";
|
|
5685
|
+
}
|
|
5686
|
+
if (typeof args.reason !== "string" || !SNAPSHOT_REASONS.has(args.reason)) {
|
|
5687
|
+
return failure("invalid_args", "reason must be a valid GitSnapshotReason");
|
|
5688
|
+
}
|
|
5689
|
+
return args.reason;
|
|
5690
|
+
}
|
|
5691
|
+
function optionalString(value) {
|
|
5692
|
+
return typeof value === "string" && value.trim() ? value.trim() : void 0;
|
|
5693
|
+
}
|
|
5694
|
+
function optionalBoolean(value) {
|
|
5695
|
+
return typeof value === "boolean" ? value : void 0;
|
|
5696
|
+
}
|
|
5697
|
+
function boundedLogLimit(value) {
|
|
5698
|
+
if (value === void 0 || value === null || value === "") return 50;
|
|
5699
|
+
const numeric = typeof value === "number" ? value : Number(value);
|
|
5700
|
+
if (!Number.isFinite(numeric)) return 50;
|
|
5701
|
+
return Math.max(1, Math.min(200, Math.floor(numeric)));
|
|
5702
|
+
}
|
|
5703
|
+
function failureReasonFromError(error) {
|
|
5704
|
+
return typeof error?.reason === "string" && FAILURE_REASONS.has(error.reason) ? error.reason : "git_command_failed";
|
|
5705
|
+
}
|
|
5706
|
+
async function runService(fn) {
|
|
5707
|
+
try {
|
|
5708
|
+
return await fn();
|
|
5709
|
+
} catch (error) {
|
|
5710
|
+
return failure(failureReasonFromError(error), error?.message || "Git command failed");
|
|
5711
|
+
}
|
|
5712
|
+
}
|
|
5713
|
+
function isGitCommandName(command) {
|
|
5714
|
+
return GIT_COMMAND_NAMES.has(command);
|
|
5715
|
+
}
|
|
5716
|
+
async function handleGitCommand(command, args, services = defaultGitCommandServices) {
|
|
5717
|
+
if (!isGitCommandName(command)) {
|
|
5718
|
+
return failure("invalid_args", `Unknown Git command: ${command}`);
|
|
5719
|
+
}
|
|
5720
|
+
const workspaceResult = validateWorkspace2(args);
|
|
5721
|
+
if ("success" in workspaceResult) return workspaceResult;
|
|
5722
|
+
const { workspace } = workspaceResult;
|
|
5723
|
+
switch (command) {
|
|
5724
|
+
case "git_status": {
|
|
5725
|
+
if (!services.getStatus) return serviceNotImplemented(command);
|
|
5726
|
+
const status = await runService(() => services.getStatus({ workspace }));
|
|
5727
|
+
return "success" in status ? status : { success: true, status };
|
|
5728
|
+
}
|
|
5729
|
+
case "git_diff_summary": {
|
|
5730
|
+
if (!services.getDiffSummary) return serviceNotImplemented(command);
|
|
5731
|
+
const diffSummary = await runService(() => services.getDiffSummary({ workspace, staged: optionalBoolean(args?.staged) }));
|
|
5732
|
+
return "success" in diffSummary ? diffSummary : { success: true, diffSummary };
|
|
5733
|
+
}
|
|
5734
|
+
case "git_diff_file": {
|
|
5735
|
+
if (!services.getDiffFile) return serviceNotImplemented(command);
|
|
5736
|
+
const pathResult = validateRepoPath(args);
|
|
5737
|
+
if (typeof pathResult !== "object" || "success" in pathResult) return pathResult;
|
|
5738
|
+
const diff = await runService(() => services.getDiffFile({
|
|
5739
|
+
workspace,
|
|
5740
|
+
path: pathResult.path,
|
|
5741
|
+
staged: optionalBoolean(args?.staged)
|
|
5742
|
+
}));
|
|
5743
|
+
return "success" in diff ? diff : { success: true, diff };
|
|
5744
|
+
}
|
|
5745
|
+
case "git_snapshot_create": {
|
|
5746
|
+
if (!services.createSnapshot) return serviceNotImplemented(command);
|
|
5747
|
+
const reason = parseSnapshotReason(args);
|
|
5748
|
+
if (typeof reason !== "string") return reason;
|
|
5749
|
+
const snapshot = await runService(() => services.createSnapshot({
|
|
5750
|
+
workspace,
|
|
5751
|
+
reason,
|
|
5752
|
+
sessionId: optionalString(args?.sessionId),
|
|
5753
|
+
turnId: optionalString(args?.turnId)
|
|
5754
|
+
}));
|
|
5755
|
+
return "success" in snapshot ? snapshot : { success: true, snapshot };
|
|
5756
|
+
}
|
|
5757
|
+
case "git_snapshot_compare": {
|
|
5758
|
+
if (!services.compareSnapshots) return serviceNotImplemented(command);
|
|
5759
|
+
const beforeSnapshotId = validateSnapshotId(args, "beforeSnapshotId");
|
|
5760
|
+
if (typeof beforeSnapshotId !== "string") return beforeSnapshotId;
|
|
5761
|
+
const afterSnapshotId = validateSnapshotId(args, "afterSnapshotId");
|
|
5762
|
+
if (typeof afterSnapshotId !== "string") return afterSnapshotId;
|
|
5763
|
+
const compare = await runService(() => services.compareSnapshots({ workspace, beforeSnapshotId, afterSnapshotId }));
|
|
5764
|
+
return "success" in compare ? compare : { success: true, compare };
|
|
5765
|
+
}
|
|
5766
|
+
case "git_log": {
|
|
5767
|
+
if (!services.getLog) {
|
|
5768
|
+
return failure("invalid_args", "git_log is not implemented: bounded daemon-core Git log service is not configured");
|
|
5769
|
+
}
|
|
5770
|
+
const log = await runService(() => services.getLog({
|
|
5771
|
+
workspace,
|
|
5772
|
+
limit: boundedLogLimit(args?.limit),
|
|
5773
|
+
path: optionalString(args?.path),
|
|
5774
|
+
since: optionalString(args?.since),
|
|
5775
|
+
until: optionalString(args?.until)
|
|
5776
|
+
}));
|
|
5777
|
+
return "success" in log ? log : { success: true, log };
|
|
5778
|
+
}
|
|
5779
|
+
case "git_checkpoint": {
|
|
5780
|
+
if (!services.checkpoint) return serviceNotImplemented(command);
|
|
5781
|
+
const msg = validateMutatingMessage(args?.message);
|
|
5782
|
+
if (typeof msg !== "string") return msg;
|
|
5783
|
+
const includeUntracked = Boolean(args?.includeUntracked);
|
|
5784
|
+
const checkpoint = await runService(() => services.checkpoint({ workspace, message: msg, includeUntracked }));
|
|
5785
|
+
return "success" in checkpoint ? checkpoint : { success: true, checkpoint };
|
|
5786
|
+
}
|
|
5787
|
+
case "git_stash_push": {
|
|
5788
|
+
if (!services.stashPush) return serviceNotImplemented(command);
|
|
5789
|
+
const msg = validateMutatingMessage(args?.message);
|
|
5790
|
+
if (typeof msg !== "string") return msg;
|
|
5791
|
+
const includeUntracked = Boolean(args?.includeUntracked);
|
|
5792
|
+
const stash = await runService(() => services.stashPush({ workspace, message: msg, includeUntracked }));
|
|
5793
|
+
return "success" in stash ? stash : { success: true, stash };
|
|
5794
|
+
}
|
|
5795
|
+
case "git_stash_pop": {
|
|
5796
|
+
if (!services.stashPop) return serviceNotImplemented(command);
|
|
5797
|
+
const stashRef = optionalString(args?.stashRef);
|
|
5798
|
+
if (stashRef !== void 0 && !/^stash@\{\d+\}$/.test(stashRef)) {
|
|
5799
|
+
return failure("invalid_args", "stashRef must match stash@{N} format");
|
|
5800
|
+
}
|
|
5801
|
+
const popResult = await runService(() => services.stashPop({ workspace, stashRef }));
|
|
5802
|
+
if (popResult !== void 0 && "success" in popResult) return popResult;
|
|
5803
|
+
return { success: true, stashPopped: true };
|
|
5804
|
+
}
|
|
5805
|
+
case "git_checkout_files": {
|
|
5806
|
+
if (!services.checkoutFiles) return serviceNotImplemented(command);
|
|
5807
|
+
const paths = args?.paths;
|
|
5808
|
+
if (!Array.isArray(paths) || paths.length === 0) {
|
|
5809
|
+
return failure("invalid_args", "paths must be a non-empty array");
|
|
5810
|
+
}
|
|
5811
|
+
if (paths.length > 50) {
|
|
5812
|
+
return failure("invalid_args", "paths array exceeds maximum of 50 entries");
|
|
5813
|
+
}
|
|
5814
|
+
const checkoutResult = await runService(() => services.checkoutFiles({ workspace, paths }));
|
|
5815
|
+
return "success" in checkoutResult ? checkoutResult : { success: true, checkedOut: checkoutResult.checkedOut };
|
|
5816
|
+
}
|
|
5817
|
+
case "git_remote_url": {
|
|
5818
|
+
if (!services.getRemoteUrl) return serviceNotImplemented(command);
|
|
5819
|
+
const remote = typeof args?.remote === "string" && args.remote.trim() ? args.remote.trim() : "origin";
|
|
5820
|
+
const remoteResult = await runService(() => services.getRemoteUrl({ workspace, remote }));
|
|
5821
|
+
if ("success" in remoteResult) return remoteResult;
|
|
5822
|
+
return { success: true, remoteUrl: remoteResult.remoteUrl, remote: remoteResult.remote };
|
|
5823
|
+
}
|
|
5824
|
+
default:
|
|
5825
|
+
return failure("invalid_args", `Unknown Git command: ${command}`);
|
|
5826
|
+
}
|
|
5827
|
+
}
|
|
5828
|
+
function validateMutatingMessage(value) {
|
|
5829
|
+
if (typeof value !== "string" || !value.trim()) {
|
|
5830
|
+
return failure("invalid_args", "message must be a non-empty string");
|
|
5831
|
+
}
|
|
5832
|
+
const msg = value.trim();
|
|
5833
|
+
if (msg.length > 200) {
|
|
5834
|
+
return failure("invalid_args", "message must be 200 characters or fewer");
|
|
5835
|
+
}
|
|
5836
|
+
return msg;
|
|
5837
|
+
}
|
|
5838
|
+
async function gitCheckpoint(workspace, message, includeUntracked) {
|
|
5839
|
+
const repo = await resolveGitRepository(workspace);
|
|
5840
|
+
const repoRoot = repo.repoRoot;
|
|
5841
|
+
const statusResult = await getGitRepoStatus(workspace);
|
|
5842
|
+
if (statusResult.hasConflicts) {
|
|
5843
|
+
throw new GitCommandError("conflict", "Repository has conflicts \u2014 resolve before checkpointing");
|
|
5844
|
+
}
|
|
5845
|
+
const addArgs = includeUntracked ? ["-A"] : ["-u"];
|
|
5846
|
+
await runGit(repo, ["add", ...addArgs], { cwd: repoRoot });
|
|
5847
|
+
const fullMsg = `adhdev: checkpoint ${message}`;
|
|
5848
|
+
let commitSha;
|
|
5849
|
+
try {
|
|
5850
|
+
await runGit(repo, ["commit", "-m", fullMsg], { cwd: repoRoot });
|
|
5851
|
+
const revResult = await runGit(repo, ["rev-parse", "HEAD"], { cwd: repoRoot });
|
|
5852
|
+
commitSha = revResult.stdout.trim();
|
|
5853
|
+
} catch (err) {
|
|
5854
|
+
const output = (err?.stdout || "") + (err?.stderr || "");
|
|
5855
|
+
if (/nothing to commit/i.test(output)) {
|
|
5856
|
+
throw new GitCommandError("git_command_failed", "Nothing to commit");
|
|
5857
|
+
}
|
|
5858
|
+
throw err;
|
|
5859
|
+
}
|
|
5860
|
+
return {
|
|
5861
|
+
workspace: repo.workspace,
|
|
5862
|
+
repoRoot,
|
|
5863
|
+
isGitRepo: true,
|
|
5864
|
+
commit: commitSha,
|
|
5865
|
+
message: fullMsg,
|
|
5866
|
+
lastCheckedAt: Date.now()
|
|
5867
|
+
};
|
|
5868
|
+
}
|
|
5869
|
+
async function gitStashPush(workspace, message, includeUntracked) {
|
|
5870
|
+
const repo = await resolveGitRepository(workspace);
|
|
5871
|
+
const repoRoot = repo.repoRoot;
|
|
5872
|
+
const stashArgs = ["stash", "push", "-m", message];
|
|
5873
|
+
if (includeUntracked) stashArgs.push("--include-untracked");
|
|
5874
|
+
const result = await runGit(repo, stashArgs, { cwd: repoRoot });
|
|
5875
|
+
if (/No local changes to save/i.test(result.stdout + result.stderr)) {
|
|
5876
|
+
throw new GitCommandError("git_command_failed", "Nothing to stash");
|
|
5877
|
+
}
|
|
5878
|
+
return {
|
|
5879
|
+
workspace: repo.workspace,
|
|
5880
|
+
repoRoot,
|
|
5881
|
+
isGitRepo: true,
|
|
5882
|
+
stashRef: "stash@{0}",
|
|
5883
|
+
message,
|
|
5884
|
+
lastCheckedAt: Date.now()
|
|
5885
|
+
};
|
|
5886
|
+
}
|
|
5887
|
+
async function gitStashPop(workspace, stashRef) {
|
|
5888
|
+
const repo = await resolveGitRepository(workspace);
|
|
5889
|
+
const repoRoot = repo.repoRoot;
|
|
5890
|
+
const popArgs = stashRef ? ["stash", "pop", stashRef] : ["stash", "pop"];
|
|
5891
|
+
await runGit(repo, popArgs, { cwd: repoRoot });
|
|
5892
|
+
}
|
|
5893
|
+
async function gitCheckoutFiles(workspace, paths) {
|
|
5894
|
+
const repo = await resolveGitRepository(workspace);
|
|
5895
|
+
const repoRoot = repo.repoRoot;
|
|
5896
|
+
const normalizedPaths = [];
|
|
5897
|
+
for (const p of paths) {
|
|
5898
|
+
if (typeof p !== "string" || !p.trim() || p.includes("\0")) {
|
|
5899
|
+
throw new GitCommandError("invalid_args", `Invalid path: ${String(p)}`);
|
|
5900
|
+
}
|
|
5901
|
+
if (path3.isAbsolute(p)) {
|
|
5902
|
+
throw new GitCommandError("invalid_args", `Path must be repository-relative, not absolute: ${p}`);
|
|
5903
|
+
}
|
|
5904
|
+
const normalized = path3.normalize(p.trim()).split(path3.sep).join("/");
|
|
5905
|
+
if (normalized.startsWith("../") || normalized === "..") {
|
|
5906
|
+
throw new GitCommandError("path_outside_repo", `Path is outside repository root: ${p}`);
|
|
5907
|
+
}
|
|
5908
|
+
const absolutePath = path3.resolve(repoRoot, normalized);
|
|
5909
|
+
if (!isPathInside(repoRoot, absolutePath)) {
|
|
5910
|
+
throw new GitCommandError("path_outside_repo", `Path is outside repository root: ${p}`);
|
|
5911
|
+
}
|
|
5912
|
+
normalizedPaths.push(normalized);
|
|
5913
|
+
}
|
|
5914
|
+
await runGit(repo, ["checkout", "--", ...normalizedPaths], { cwd: repoRoot });
|
|
5915
|
+
return { checkedOut: normalizedPaths };
|
|
5916
|
+
}
|
|
5917
|
+
async function gitGetRemoteUrl(workspace, remote) {
|
|
5918
|
+
const repo = await resolveGitRepository(workspace);
|
|
5919
|
+
const result = await runGit(repo, ["remote", "get-url", remote], { cwd: repo.repoRoot });
|
|
5920
|
+
const remoteUrl = result.stdout.trim();
|
|
5921
|
+
if (!remoteUrl) {
|
|
5922
|
+
throw new GitCommandError("git_command_failed", `Remote '${remote}' has no URL`);
|
|
5923
|
+
}
|
|
5924
|
+
return { remoteUrl, remote };
|
|
5925
|
+
}
|
|
5926
|
+
function formatOptionalGitLogRangeArg(flag, value) {
|
|
5927
|
+
return value ? [`${flag}=${value}`] : [];
|
|
5928
|
+
}
|
|
5929
|
+
async function getGitLog(workspace, options) {
|
|
5930
|
+
const lastCheckedAt = Date.now();
|
|
5931
|
+
const repo = await resolveGitRepository(workspace);
|
|
5932
|
+
const repoRoot = repo.repoRoot;
|
|
5933
|
+
const boundedLimit = Math.max(1, Math.min(200, Math.floor(options.limit || 50)));
|
|
5934
|
+
const selectedPath = options.path ? validateGitLogPath(repoRoot, options.path) : void 0;
|
|
5935
|
+
const result = await runGit(
|
|
5936
|
+
repo,
|
|
5937
|
+
[
|
|
5938
|
+
"log",
|
|
5939
|
+
`--max-count=${boundedLimit}`,
|
|
5940
|
+
"--format=%H%x00%an%x00%ae%x00%at%x00%ct%x00%s",
|
|
5941
|
+
...formatOptionalGitLogRangeArg("--since", options.since),
|
|
5942
|
+
...formatOptionalGitLogRangeArg("--until", options.until),
|
|
5943
|
+
"--",
|
|
5944
|
+
...selectedPath ? [selectedPath] : []
|
|
5945
|
+
],
|
|
5946
|
+
{ cwd: repoRoot }
|
|
5947
|
+
);
|
|
5948
|
+
const entries = result.stdout.split("\n").filter((line) => line.trim().length > 0).map((line) => {
|
|
5949
|
+
const [commit = "", authorName, authorEmail, authoredAt, committedAt, ...messageParts] = line.split("\0");
|
|
5950
|
+
return {
|
|
5951
|
+
commit,
|
|
5952
|
+
message: messageParts.join("\0"),
|
|
5953
|
+
authorName: authorName || void 0,
|
|
5954
|
+
authorEmail: authorEmail || void 0,
|
|
5955
|
+
authoredAt: authoredAt ? Number.parseInt(authoredAt, 10) * 1e3 : void 0,
|
|
5956
|
+
committedAt: committedAt ? Number.parseInt(committedAt, 10) * 1e3 : void 0
|
|
5957
|
+
};
|
|
5958
|
+
}).filter((entry) => entry.commit.length > 0);
|
|
5959
|
+
return {
|
|
5960
|
+
workspace: repo.workspace,
|
|
5961
|
+
repoRoot,
|
|
5962
|
+
isGitRepo: true,
|
|
5963
|
+
entries,
|
|
5964
|
+
limit: boundedLimit,
|
|
5965
|
+
truncated: entries.length >= boundedLimit,
|
|
5966
|
+
lastCheckedAt
|
|
5967
|
+
};
|
|
5968
|
+
}
|
|
5969
|
+
function validateGitLogPath(repoRoot, filePath) {
|
|
5970
|
+
if (!filePath.trim() || filePath.includes("\0")) {
|
|
5971
|
+
throw new GitCommandError("invalid_args", "path must be a non-empty repository-relative path");
|
|
5972
|
+
}
|
|
5973
|
+
if (path3.isAbsolute(filePath)) {
|
|
5974
|
+
throw new GitCommandError("invalid_args", "path must be repository-relative");
|
|
5975
|
+
}
|
|
5976
|
+
const normalized = path3.normalize(filePath).split(path3.sep).join("/");
|
|
5977
|
+
const absolutePath = path3.resolve(repoRoot, normalized);
|
|
5978
|
+
if (!isPathInside(repoRoot, absolutePath) || normalized.startsWith("../") || normalized === "..") {
|
|
5979
|
+
throw new GitCommandError("path_outside_repo", "Git log path is outside the repository root");
|
|
5980
|
+
}
|
|
5981
|
+
return normalized;
|
|
5982
|
+
}
|
|
5983
|
+
|
|
5984
|
+
// src/git/turn-snapshot-tracker.ts
|
|
5985
|
+
var BUSY_STATUSES = /* @__PURE__ */ new Set(["streaming", "waiting_approval"]);
|
|
5986
|
+
var TERMINAL_STATUSES = /* @__PURE__ */ new Set(["idle", "error"]);
|
|
5987
|
+
var TurnSnapshotTracker = class {
|
|
5988
|
+
lastStatus = /* @__PURE__ */ new Map();
|
|
5989
|
+
onTurnCompleted;
|
|
5990
|
+
constructor(onTurnCompleted) {
|
|
5991
|
+
this.onTurnCompleted = onTurnCompleted;
|
|
5992
|
+
}
|
|
5993
|
+
record(sessionId, status, workspace) {
|
|
5994
|
+
const prev = this.lastStatus.get(sessionId);
|
|
5995
|
+
this.lastStatus.set(sessionId, status);
|
|
5996
|
+
if (workspace && prev && BUSY_STATUSES.has(prev) && TERMINAL_STATUSES.has(status)) {
|
|
5997
|
+
this.onTurnCompleted({ sessionId, workspace });
|
|
5998
|
+
}
|
|
5999
|
+
}
|
|
6000
|
+
forget(sessionId) {
|
|
6001
|
+
this.lastStatus.delete(sessionId);
|
|
6002
|
+
}
|
|
6003
|
+
};
|
|
6004
|
+
|
|
6005
|
+
// src/index.ts
|
|
4683
6006
|
init_config();
|
|
4684
6007
|
|
|
4685
6008
|
// src/config/workspaces.ts
|
|
4686
6009
|
var fs = __toESM(require("fs"));
|
|
4687
6010
|
var os = __toESM(require("os"));
|
|
4688
|
-
var
|
|
6011
|
+
var path4 = __toESM(require("path"));
|
|
4689
6012
|
var import_crypto2 = require("crypto");
|
|
4690
6013
|
var MAX_WORKSPACES = 50;
|
|
4691
6014
|
function expandPath(p) {
|
|
4692
6015
|
const t = (p || "").trim();
|
|
4693
6016
|
if (!t) return "";
|
|
4694
|
-
if (t.startsWith("~")) return
|
|
4695
|
-
return
|
|
6017
|
+
if (t.startsWith("~")) return path4.join(os.homedir(), t.slice(1).replace(/^\//, ""));
|
|
6018
|
+
return path4.resolve(t);
|
|
4696
6019
|
}
|
|
4697
6020
|
function validateWorkspacePath(absPath) {
|
|
4698
6021
|
try {
|
|
@@ -4706,7 +6029,7 @@ function validateWorkspacePath(absPath) {
|
|
|
4706
6029
|
}
|
|
4707
6030
|
}
|
|
4708
6031
|
function defaultWorkspaceLabel(absPath) {
|
|
4709
|
-
const base =
|
|
6032
|
+
const base = path4.basename(absPath) || absPath;
|
|
4710
6033
|
return base;
|
|
4711
6034
|
}
|
|
4712
6035
|
function getDefaultWorkspacePath(config) {
|
|
@@ -4797,9 +6120,9 @@ function resolveIdeLaunchWorkspace(args, config) {
|
|
|
4797
6120
|
return getDefaultWorkspacePath(config) || void 0;
|
|
4798
6121
|
}
|
|
4799
6122
|
function findWorkspaceByPath(config, rawPath) {
|
|
4800
|
-
const abs =
|
|
6123
|
+
const abs = path4.resolve(expandPath(rawPath));
|
|
4801
6124
|
if (!abs) return void 0;
|
|
4802
|
-
return (config.workspaces || []).find((w) =>
|
|
6125
|
+
return (config.workspaces || []).find((w) => path4.resolve(expandPath(w.path)) === abs);
|
|
4803
6126
|
}
|
|
4804
6127
|
function addWorkspaceEntry(config, rawPath, label, options) {
|
|
4805
6128
|
const abs = expandPath(rawPath);
|
|
@@ -4815,7 +6138,7 @@ function addWorkspaceEntry(config, rawPath, label, options) {
|
|
|
4815
6138
|
const v = validateWorkspacePath(abs);
|
|
4816
6139
|
if (!v.ok) return { error: v.error };
|
|
4817
6140
|
const list = [...config.workspaces || []];
|
|
4818
|
-
if (list.some((w) =>
|
|
6141
|
+
if (list.some((w) => path4.resolve(w.path) === abs)) {
|
|
4819
6142
|
return { error: "Workspace already in list" };
|
|
4820
6143
|
}
|
|
4821
6144
|
if (list.length >= MAX_WORKSPACES) {
|
|
@@ -4849,7 +6172,7 @@ function setDefaultWorkspaceId(config, id) {
|
|
|
4849
6172
|
}
|
|
4850
6173
|
|
|
4851
6174
|
// src/config/recent-activity.ts
|
|
4852
|
-
var
|
|
6175
|
+
var path5 = __toESM(require("path"));
|
|
4853
6176
|
|
|
4854
6177
|
// src/providers/summary-metadata.ts
|
|
4855
6178
|
function normalizeSummaryItem(item) {
|
|
@@ -4918,9 +6241,9 @@ var MAX_ACTIVITY = 30;
|
|
|
4918
6241
|
function normalizeWorkspace(workspace) {
|
|
4919
6242
|
if (!workspace) return "";
|
|
4920
6243
|
try {
|
|
4921
|
-
return
|
|
6244
|
+
return path5.resolve(expandPath(workspace));
|
|
4922
6245
|
} catch {
|
|
4923
|
-
return
|
|
6246
|
+
return path5.resolve(workspace);
|
|
4924
6247
|
}
|
|
4925
6248
|
}
|
|
4926
6249
|
function buildRecentActivityKey(entry) {
|
|
@@ -5088,14 +6411,14 @@ function markSessionSeen(state, sessionId, seenAt = Date.now(), completionMarker
|
|
|
5088
6411
|
}
|
|
5089
6412
|
|
|
5090
6413
|
// src/config/saved-sessions.ts
|
|
5091
|
-
var
|
|
6414
|
+
var path6 = __toESM(require("path"));
|
|
5092
6415
|
var MAX_SAVED_SESSIONS = 500;
|
|
5093
6416
|
function normalizeWorkspace2(workspace) {
|
|
5094
6417
|
if (!workspace) return "";
|
|
5095
6418
|
try {
|
|
5096
|
-
return
|
|
6419
|
+
return path6.resolve(expandPath(workspace));
|
|
5097
6420
|
} catch {
|
|
5098
|
-
return
|
|
6421
|
+
return path6.resolve(workspace);
|
|
5099
6422
|
}
|
|
5100
6423
|
}
|
|
5101
6424
|
function buildSavedProviderSessionKey(providerSessionId) {
|
|
@@ -5214,7 +6537,7 @@ function resetState() {
|
|
|
5214
6537
|
var import_child_process = require("child_process");
|
|
5215
6538
|
var import_fs3 = require("fs");
|
|
5216
6539
|
var import_os2 = require("os");
|
|
5217
|
-
var
|
|
6540
|
+
var path7 = __toESM(require("path"));
|
|
5218
6541
|
var BUILTIN_IDE_DEFINITIONS = [];
|
|
5219
6542
|
var registeredIDEs = /* @__PURE__ */ new Map();
|
|
5220
6543
|
function registerIDEDefinition(def) {
|
|
@@ -5233,9 +6556,9 @@ function getMergedDefinitions() {
|
|
|
5233
6556
|
function findCliCommand(command) {
|
|
5234
6557
|
const trimmed = String(command || "").trim();
|
|
5235
6558
|
if (!trimmed) return null;
|
|
5236
|
-
if (
|
|
5237
|
-
const candidate = trimmed.startsWith("~") ?
|
|
5238
|
-
const resolved =
|
|
6559
|
+
if (path7.isAbsolute(trimmed) || trimmed.includes("/") || trimmed.includes("\\") || trimmed.startsWith("~")) {
|
|
6560
|
+
const candidate = trimmed.startsWith("~") ? path7.join((0, import_os2.homedir)(), trimmed.slice(1)) : trimmed;
|
|
6561
|
+
const resolved = path7.isAbsolute(candidate) ? candidate : path7.resolve(candidate);
|
|
5239
6562
|
return (0, import_fs3.existsSync)(resolved) ? resolved : null;
|
|
5240
6563
|
}
|
|
5241
6564
|
try {
|
|
@@ -5263,7 +6586,7 @@ function getIdeVersion(cliCommand) {
|
|
|
5263
6586
|
function checkPathExists(paths) {
|
|
5264
6587
|
const home = (0, import_os2.homedir)();
|
|
5265
6588
|
for (const p of paths) {
|
|
5266
|
-
const normalized = p.startsWith("~") ?
|
|
6589
|
+
const normalized = p.startsWith("~") ? path7.join(home, p.slice(1)) : p;
|
|
5267
6590
|
if (normalized.includes("*")) {
|
|
5268
6591
|
const username = home.split(/[\\/]/).pop() || "";
|
|
5269
6592
|
const resolved = normalized.replace("*", username);
|
|
@@ -5321,7 +6644,7 @@ async function detectIDEs(providerLoader) {
|
|
|
5321
6644
|
// src/detection/cli-detector.ts
|
|
5322
6645
|
var import_child_process2 = require("child_process");
|
|
5323
6646
|
var os2 = __toESM(require("os"));
|
|
5324
|
-
var
|
|
6647
|
+
var path8 = __toESM(require("path"));
|
|
5325
6648
|
var import_fs4 = require("fs");
|
|
5326
6649
|
function parseVersion(raw) {
|
|
5327
6650
|
const match = raw.match(/v?(\d+\.\d+(?:\.\d+)?(?:-[a-zA-Z0-9.]+)?)/);
|
|
@@ -5334,36 +6657,36 @@ function shellQuote(value) {
|
|
|
5334
6657
|
function expandHome(value) {
|
|
5335
6658
|
const trimmed = value.trim();
|
|
5336
6659
|
if (!trimmed.startsWith("~")) return trimmed;
|
|
5337
|
-
return
|
|
6660
|
+
return path8.join(os2.homedir(), trimmed.slice(1));
|
|
5338
6661
|
}
|
|
5339
6662
|
function isExplicitCommandPath(command) {
|
|
5340
6663
|
const trimmed = command.trim();
|
|
5341
|
-
return
|
|
6664
|
+
return path8.isAbsolute(trimmed) || trimmed.includes("/") || trimmed.includes("\\") || trimmed.startsWith("~");
|
|
5342
6665
|
}
|
|
5343
6666
|
function resolveCommandPath(command) {
|
|
5344
6667
|
const trimmed = command.trim();
|
|
5345
6668
|
if (!trimmed) return null;
|
|
5346
6669
|
if (isExplicitCommandPath(trimmed)) {
|
|
5347
6670
|
const expanded = expandHome(trimmed);
|
|
5348
|
-
const candidate =
|
|
6671
|
+
const candidate = path8.isAbsolute(expanded) ? expanded : path8.resolve(expanded);
|
|
5349
6672
|
return (0, import_fs4.existsSync)(candidate) ? candidate : null;
|
|
5350
6673
|
}
|
|
5351
6674
|
return null;
|
|
5352
6675
|
}
|
|
5353
6676
|
function execAsync(cmd, timeoutMs = 5e3) {
|
|
5354
|
-
return new Promise((
|
|
6677
|
+
return new Promise((resolve15) => {
|
|
5355
6678
|
const child = (0, import_child_process2.exec)(cmd, {
|
|
5356
6679
|
encoding: "utf-8",
|
|
5357
6680
|
timeout: timeoutMs,
|
|
5358
6681
|
...process.platform === "win32" ? { windowsHide: true } : {}
|
|
5359
6682
|
}, (err, stdout) => {
|
|
5360
6683
|
if (err || !stdout?.trim()) {
|
|
5361
|
-
|
|
6684
|
+
resolve15(null);
|
|
5362
6685
|
} else {
|
|
5363
|
-
|
|
6686
|
+
resolve15(stdout.trim());
|
|
5364
6687
|
}
|
|
5365
6688
|
});
|
|
5366
|
-
child.on("error", () =>
|
|
6689
|
+
child.on("error", () => resolve15(null));
|
|
5367
6690
|
});
|
|
5368
6691
|
}
|
|
5369
6692
|
async function detectCLIs(providerLoader, options) {
|
|
@@ -5728,7 +7051,7 @@ var DaemonCdpManager = class {
|
|
|
5728
7051
|
* Returns multiple entries if multiple IDE windows are open on same port
|
|
5729
7052
|
*/
|
|
5730
7053
|
static listAllTargets(port) {
|
|
5731
|
-
return new Promise((
|
|
7054
|
+
return new Promise((resolve15) => {
|
|
5732
7055
|
const req = http.get(`http://127.0.0.1:${port}/json`, (res) => {
|
|
5733
7056
|
let data = "";
|
|
5734
7057
|
res.on("data", (chunk) => data += chunk.toString());
|
|
@@ -5744,16 +7067,16 @@ var DaemonCdpManager = class {
|
|
|
5744
7067
|
(t) => !isNonMain(t.title || "") && t.url?.includes("workbench.html") && !t.url?.includes("agent")
|
|
5745
7068
|
);
|
|
5746
7069
|
const fallbackPages = pages.filter((t) => !isNonMain(t.title || ""));
|
|
5747
|
-
|
|
7070
|
+
resolve15(mainPages.length > 0 ? mainPages : fallbackPages);
|
|
5748
7071
|
} catch {
|
|
5749
|
-
|
|
7072
|
+
resolve15([]);
|
|
5750
7073
|
}
|
|
5751
7074
|
});
|
|
5752
7075
|
});
|
|
5753
|
-
req.on("error", () =>
|
|
7076
|
+
req.on("error", () => resolve15([]));
|
|
5754
7077
|
req.setTimeout(2e3, () => {
|
|
5755
7078
|
req.destroy();
|
|
5756
|
-
|
|
7079
|
+
resolve15([]);
|
|
5757
7080
|
});
|
|
5758
7081
|
});
|
|
5759
7082
|
}
|
|
@@ -5793,7 +7116,7 @@ var DaemonCdpManager = class {
|
|
|
5793
7116
|
}
|
|
5794
7117
|
}
|
|
5795
7118
|
findTargetOnPort(port) {
|
|
5796
|
-
return new Promise((
|
|
7119
|
+
return new Promise((resolve15) => {
|
|
5797
7120
|
const req = http.get(`http://127.0.0.1:${port}/json`, (res) => {
|
|
5798
7121
|
let data = "";
|
|
5799
7122
|
res.on("data", (chunk) => data += chunk.toString());
|
|
@@ -5804,7 +7127,7 @@ var DaemonCdpManager = class {
|
|
|
5804
7127
|
(t) => (t.type === "page" || t.type === "browser" || t.type === "Page") && t.webSocketDebuggerUrl
|
|
5805
7128
|
);
|
|
5806
7129
|
if (pages.length === 0) {
|
|
5807
|
-
|
|
7130
|
+
resolve15(targets.find((t) => t.webSocketDebuggerUrl) || null);
|
|
5808
7131
|
return;
|
|
5809
7132
|
}
|
|
5810
7133
|
const titleFilteredPages = pages.filter((t) => !this.isNonMainTitle(t.title || ""));
|
|
@@ -5823,25 +7146,25 @@ var DaemonCdpManager = class {
|
|
|
5823
7146
|
this._targetId = selected.target.id;
|
|
5824
7147
|
}
|
|
5825
7148
|
this._pageTitle = selected.target.title || "";
|
|
5826
|
-
|
|
7149
|
+
resolve15(selected.target);
|
|
5827
7150
|
return;
|
|
5828
7151
|
}
|
|
5829
7152
|
if (previousTargetId) {
|
|
5830
7153
|
this.log(`[CDP] Target ${previousTargetId} not found in page list`);
|
|
5831
|
-
|
|
7154
|
+
resolve15(null);
|
|
5832
7155
|
return;
|
|
5833
7156
|
}
|
|
5834
7157
|
this._pageTitle = list[0]?.title || "";
|
|
5835
|
-
|
|
7158
|
+
resolve15(list[0]);
|
|
5836
7159
|
} catch {
|
|
5837
|
-
|
|
7160
|
+
resolve15(null);
|
|
5838
7161
|
}
|
|
5839
7162
|
});
|
|
5840
7163
|
});
|
|
5841
|
-
req.on("error", () =>
|
|
7164
|
+
req.on("error", () => resolve15(null));
|
|
5842
7165
|
req.setTimeout(2e3, () => {
|
|
5843
7166
|
req.destroy();
|
|
5844
|
-
|
|
7167
|
+
resolve15(null);
|
|
5845
7168
|
});
|
|
5846
7169
|
});
|
|
5847
7170
|
}
|
|
@@ -5852,7 +7175,7 @@ var DaemonCdpManager = class {
|
|
|
5852
7175
|
this.extensionProviders = providers;
|
|
5853
7176
|
}
|
|
5854
7177
|
connectToTarget(wsUrl) {
|
|
5855
|
-
return new Promise((
|
|
7178
|
+
return new Promise((resolve15) => {
|
|
5856
7179
|
this.ws = new import_ws.default(wsUrl);
|
|
5857
7180
|
this.ws.on("open", async () => {
|
|
5858
7181
|
this._connected = true;
|
|
@@ -5862,17 +7185,17 @@ var DaemonCdpManager = class {
|
|
|
5862
7185
|
}
|
|
5863
7186
|
this.connectBrowserWs().catch(() => {
|
|
5864
7187
|
});
|
|
5865
|
-
|
|
7188
|
+
resolve15(true);
|
|
5866
7189
|
});
|
|
5867
7190
|
this.ws.on("message", (data) => {
|
|
5868
7191
|
try {
|
|
5869
7192
|
const msg = JSON.parse(data.toString());
|
|
5870
7193
|
if (msg.id && this.pending.has(msg.id)) {
|
|
5871
|
-
const { resolve:
|
|
7194
|
+
const { resolve: resolve16, reject } = this.pending.get(msg.id);
|
|
5872
7195
|
this.pending.delete(msg.id);
|
|
5873
7196
|
this.failureCount = 0;
|
|
5874
7197
|
if (msg.error) reject(new Error(msg.error.message));
|
|
5875
|
-
else
|
|
7198
|
+
else resolve16(msg.result);
|
|
5876
7199
|
} else if (msg.method === "Runtime.executionContextCreated") {
|
|
5877
7200
|
this.contexts.add(msg.params.context.id);
|
|
5878
7201
|
} else if (msg.method === "Runtime.executionContextDestroyed") {
|
|
@@ -5895,7 +7218,7 @@ var DaemonCdpManager = class {
|
|
|
5895
7218
|
this.ws.on("error", (err) => {
|
|
5896
7219
|
this.log(`[CDP] WebSocket error: ${err.message}`);
|
|
5897
7220
|
this._connected = false;
|
|
5898
|
-
|
|
7221
|
+
resolve15(false);
|
|
5899
7222
|
});
|
|
5900
7223
|
});
|
|
5901
7224
|
}
|
|
@@ -5909,7 +7232,7 @@ var DaemonCdpManager = class {
|
|
|
5909
7232
|
return;
|
|
5910
7233
|
}
|
|
5911
7234
|
this.log(`[CDP] Connecting browser WS for target discovery...`);
|
|
5912
|
-
await new Promise((
|
|
7235
|
+
await new Promise((resolve15, reject) => {
|
|
5913
7236
|
this.browserWs = new import_ws.default(browserWsUrl);
|
|
5914
7237
|
this.browserWs.on("open", async () => {
|
|
5915
7238
|
this._browserConnected = true;
|
|
@@ -5919,16 +7242,16 @@ var DaemonCdpManager = class {
|
|
|
5919
7242
|
} catch (e) {
|
|
5920
7243
|
this.log(`[CDP] setDiscoverTargets failed: ${e.message}`);
|
|
5921
7244
|
}
|
|
5922
|
-
|
|
7245
|
+
resolve15();
|
|
5923
7246
|
});
|
|
5924
7247
|
this.browserWs.on("message", (data) => {
|
|
5925
7248
|
try {
|
|
5926
7249
|
const msg = JSON.parse(data.toString());
|
|
5927
7250
|
if (msg.id && this.browserPending.has(msg.id)) {
|
|
5928
|
-
const { resolve:
|
|
7251
|
+
const { resolve: resolve16, reject: reject2 } = this.browserPending.get(msg.id);
|
|
5929
7252
|
this.browserPending.delete(msg.id);
|
|
5930
7253
|
if (msg.error) reject2(new Error(msg.error.message));
|
|
5931
|
-
else
|
|
7254
|
+
else resolve16(msg.result);
|
|
5932
7255
|
}
|
|
5933
7256
|
} catch {
|
|
5934
7257
|
}
|
|
@@ -5948,31 +7271,31 @@ var DaemonCdpManager = class {
|
|
|
5948
7271
|
}
|
|
5949
7272
|
}
|
|
5950
7273
|
getBrowserWsUrl() {
|
|
5951
|
-
return new Promise((
|
|
7274
|
+
return new Promise((resolve15) => {
|
|
5952
7275
|
const req = http.get(`http://127.0.0.1:${this.port}/json/version`, (res) => {
|
|
5953
7276
|
let data = "";
|
|
5954
7277
|
res.on("data", (chunk) => data += chunk.toString());
|
|
5955
7278
|
res.on("end", () => {
|
|
5956
7279
|
try {
|
|
5957
7280
|
const info = JSON.parse(data);
|
|
5958
|
-
|
|
7281
|
+
resolve15(info.webSocketDebuggerUrl || null);
|
|
5959
7282
|
} catch {
|
|
5960
|
-
|
|
7283
|
+
resolve15(null);
|
|
5961
7284
|
}
|
|
5962
7285
|
});
|
|
5963
7286
|
});
|
|
5964
|
-
req.on("error", () =>
|
|
7287
|
+
req.on("error", () => resolve15(null));
|
|
5965
7288
|
req.setTimeout(3e3, () => {
|
|
5966
7289
|
req.destroy();
|
|
5967
|
-
|
|
7290
|
+
resolve15(null);
|
|
5968
7291
|
});
|
|
5969
7292
|
});
|
|
5970
7293
|
}
|
|
5971
7294
|
sendBrowser(method, params = {}, timeoutMs = 15e3) {
|
|
5972
|
-
return new Promise((
|
|
7295
|
+
return new Promise((resolve15, reject) => {
|
|
5973
7296
|
if (!this.browserWs || !this._browserConnected) return reject(new Error("Browser WS not connected"));
|
|
5974
7297
|
const id = this.browserMsgId++;
|
|
5975
|
-
this.browserPending.set(id, { resolve:
|
|
7298
|
+
this.browserPending.set(id, { resolve: resolve15, reject });
|
|
5976
7299
|
this.browserWs.send(JSON.stringify({ id, method, params }));
|
|
5977
7300
|
setTimeout(() => {
|
|
5978
7301
|
if (this.browserPending.has(id)) {
|
|
@@ -6012,11 +7335,11 @@ var DaemonCdpManager = class {
|
|
|
6012
7335
|
}
|
|
6013
7336
|
// ─── CDP Protocol ────────────────────────────────────────
|
|
6014
7337
|
sendInternal(method, params = {}, timeoutMs = 15e3) {
|
|
6015
|
-
return new Promise((
|
|
7338
|
+
return new Promise((resolve15, reject) => {
|
|
6016
7339
|
if (!this.ws || !this._connected) return reject(new Error("CDP not connected"));
|
|
6017
7340
|
if (this.ws.readyState !== import_ws.default.OPEN) return reject(new Error("WebSocket not open"));
|
|
6018
7341
|
const id = this.msgId++;
|
|
6019
|
-
this.pending.set(id, { resolve:
|
|
7342
|
+
this.pending.set(id, { resolve: resolve15, reject });
|
|
6020
7343
|
this.ws.send(JSON.stringify({ id, method, params }));
|
|
6021
7344
|
setTimeout(() => {
|
|
6022
7345
|
if (this.pending.has(id)) {
|
|
@@ -6265,7 +7588,7 @@ var DaemonCdpManager = class {
|
|
|
6265
7588
|
const browserWs = this.browserWs;
|
|
6266
7589
|
let msgId = this.browserMsgId;
|
|
6267
7590
|
const sendWs = (method, params = {}, sessionId) => {
|
|
6268
|
-
return new Promise((
|
|
7591
|
+
return new Promise((resolve15, reject) => {
|
|
6269
7592
|
const mid = msgId++;
|
|
6270
7593
|
this.browserMsgId = msgId;
|
|
6271
7594
|
const handler = (raw) => {
|
|
@@ -6274,7 +7597,7 @@ var DaemonCdpManager = class {
|
|
|
6274
7597
|
if (msg.id === mid) {
|
|
6275
7598
|
browserWs.removeListener("message", handler);
|
|
6276
7599
|
if (msg.error) reject(new Error(msg.error.message || JSON.stringify(msg.error)));
|
|
6277
|
-
else
|
|
7600
|
+
else resolve15(msg.result);
|
|
6278
7601
|
}
|
|
6279
7602
|
} catch {
|
|
6280
7603
|
}
|
|
@@ -6475,14 +7798,14 @@ var DaemonCdpManager = class {
|
|
|
6475
7798
|
if (!ws || ws.readyState !== import_ws.default.OPEN) {
|
|
6476
7799
|
throw new Error("CDP not connected");
|
|
6477
7800
|
}
|
|
6478
|
-
return new Promise((
|
|
7801
|
+
return new Promise((resolve15, reject) => {
|
|
6479
7802
|
const id = getNextId();
|
|
6480
7803
|
pendingMap.set(id, {
|
|
6481
7804
|
resolve: (result) => {
|
|
6482
7805
|
if (result?.result?.subtype === "error") {
|
|
6483
7806
|
reject(new Error(result.result.description));
|
|
6484
7807
|
} else {
|
|
6485
|
-
|
|
7808
|
+
resolve15(result?.result?.value);
|
|
6486
7809
|
}
|
|
6487
7810
|
},
|
|
6488
7811
|
reject
|
|
@@ -6514,10 +7837,10 @@ var DaemonCdpManager = class {
|
|
|
6514
7837
|
throw new Error("CDP not connected");
|
|
6515
7838
|
}
|
|
6516
7839
|
const sendViaSession = (method, params = {}) => {
|
|
6517
|
-
return new Promise((
|
|
7840
|
+
return new Promise((resolve15, reject) => {
|
|
6518
7841
|
const pendingMap = this._browserConnected ? this.browserPending : this.pending;
|
|
6519
7842
|
const id = this._browserConnected ? this.browserMsgId++ : this.msgId++;
|
|
6520
|
-
pendingMap.set(id, { resolve:
|
|
7843
|
+
pendingMap.set(id, { resolve: resolve15, reject });
|
|
6521
7844
|
ws.send(JSON.stringify({ id, sessionId, method, params }));
|
|
6522
7845
|
setTimeout(() => {
|
|
6523
7846
|
if (pendingMap.has(id)) {
|
|
@@ -7263,10 +8586,10 @@ ${cleanBody}`;
|
|
|
7263
8586
|
|
|
7264
8587
|
// src/config/chat-history.ts
|
|
7265
8588
|
var fs3 = __toESM(require("fs"));
|
|
7266
|
-
var
|
|
8589
|
+
var path10 = __toESM(require("path"));
|
|
7267
8590
|
var os5 = __toESM(require("os"));
|
|
7268
8591
|
init_chat_message_normalization();
|
|
7269
|
-
var HISTORY_DIR =
|
|
8592
|
+
var HISTORY_DIR = path10.join(os5.homedir(), ".adhdev", "history");
|
|
7270
8593
|
var RETAIN_DAYS = 30;
|
|
7271
8594
|
var SAVED_HISTORY_INDEX_VERSION = 1;
|
|
7272
8595
|
var SAVED_HISTORY_INDEX_FILE = ".saved-history-index.json";
|
|
@@ -7429,8 +8752,8 @@ function extractSavedHistorySessionIdFromFile(file) {
|
|
|
7429
8752
|
function buildSavedHistoryFileSignatureMap(dir, files) {
|
|
7430
8753
|
return new Map(files.map((file) => {
|
|
7431
8754
|
try {
|
|
7432
|
-
const
|
|
7433
|
-
return [file, `${file}:${
|
|
8755
|
+
const stat2 = fs3.statSync(path10.join(dir, file));
|
|
8756
|
+
return [file, `${file}:${stat2.size}:${Math.trunc(stat2.mtimeMs)}`];
|
|
7434
8757
|
} catch {
|
|
7435
8758
|
return [file, `${file}:missing`];
|
|
7436
8759
|
}
|
|
@@ -7440,7 +8763,7 @@ function buildSavedHistoryCacheSignature(files, fileSignatures) {
|
|
|
7440
8763
|
return files.map((file) => fileSignatures.get(file) || `${file}:missing`).join("|");
|
|
7441
8764
|
}
|
|
7442
8765
|
function getSavedHistoryIndexFilePath(dir) {
|
|
7443
|
-
return
|
|
8766
|
+
return path10.join(dir, SAVED_HISTORY_INDEX_FILE);
|
|
7444
8767
|
}
|
|
7445
8768
|
function getSavedHistoryIndexLockPath(dir) {
|
|
7446
8769
|
return `${getSavedHistoryIndexFilePath(dir)}${SAVED_HISTORY_INDEX_LOCK_SUFFIX}`;
|
|
@@ -7493,8 +8816,8 @@ function acquireSavedHistoryIndexLock(dir) {
|
|
|
7493
8816
|
} catch (error) {
|
|
7494
8817
|
if (error?.code !== "EEXIST") return null;
|
|
7495
8818
|
try {
|
|
7496
|
-
const
|
|
7497
|
-
if (Date.now() -
|
|
8819
|
+
const stat2 = fs3.statSync(lockPath);
|
|
8820
|
+
if (Date.now() - stat2.mtimeMs > SAVED_HISTORY_INDEX_LOCK_STALE_MS) {
|
|
7498
8821
|
fs3.rmSync(lockPath, { recursive: true, force: true });
|
|
7499
8822
|
continue;
|
|
7500
8823
|
}
|
|
@@ -7542,7 +8865,7 @@ function savePersistedSavedHistoryIndex(dir, entries) {
|
|
|
7542
8865
|
}
|
|
7543
8866
|
for (const file of Array.from(currentEntries.keys())) {
|
|
7544
8867
|
if (incomingFiles.has(file)) continue;
|
|
7545
|
-
if (!fs3.existsSync(
|
|
8868
|
+
if (!fs3.existsSync(path10.join(dir, file))) {
|
|
7546
8869
|
currentEntries.delete(file);
|
|
7547
8870
|
}
|
|
7548
8871
|
}
|
|
@@ -7557,8 +8880,8 @@ function invalidatePersistedSavedHistoryIndex(agentType, dir) {
|
|
|
7557
8880
|
}
|
|
7558
8881
|
function buildSavedHistoryIndexFileSignature(dir) {
|
|
7559
8882
|
try {
|
|
7560
|
-
const
|
|
7561
|
-
return `index:${
|
|
8883
|
+
const stat2 = fs3.statSync(getSavedHistoryIndexFilePath(dir));
|
|
8884
|
+
return `index:${stat2.size}:${Math.trunc(stat2.mtimeMs)}`;
|
|
7562
8885
|
} catch {
|
|
7563
8886
|
return "index:missing";
|
|
7564
8887
|
}
|
|
@@ -7568,8 +8891,8 @@ function historyDirectoryHasFilesNewerThanIndex(dir) {
|
|
|
7568
8891
|
const indexStat = fs3.statSync(getSavedHistoryIndexFilePath(dir));
|
|
7569
8892
|
const files = listHistoryFiles(dir);
|
|
7570
8893
|
for (const file of files) {
|
|
7571
|
-
const
|
|
7572
|
-
if (
|
|
8894
|
+
const stat2 = fs3.statSync(path10.join(dir, file));
|
|
8895
|
+
if (stat2.mtimeMs > indexStat.mtimeMs) return true;
|
|
7573
8896
|
}
|
|
7574
8897
|
return false;
|
|
7575
8898
|
} catch {
|
|
@@ -7578,14 +8901,14 @@ function historyDirectoryHasFilesNewerThanIndex(dir) {
|
|
|
7578
8901
|
}
|
|
7579
8902
|
function buildSavedHistoryFileSignature(dir, file) {
|
|
7580
8903
|
try {
|
|
7581
|
-
const
|
|
7582
|
-
return `${file}:${
|
|
8904
|
+
const stat2 = fs3.statSync(path10.join(dir, file));
|
|
8905
|
+
return `${file}:${stat2.size}:${Math.trunc(stat2.mtimeMs)}`;
|
|
7583
8906
|
} catch {
|
|
7584
8907
|
return `${file}:missing`;
|
|
7585
8908
|
}
|
|
7586
8909
|
}
|
|
7587
8910
|
function persistSavedHistoryFileSummaryEntry(agentType, dir, file, updater) {
|
|
7588
|
-
const filePath =
|
|
8911
|
+
const filePath = path10.join(dir, file);
|
|
7589
8912
|
const result = withLockedPersistedSavedHistoryIndex(dir, (entries) => {
|
|
7590
8913
|
const currentEntry = entries.get(file) || null;
|
|
7591
8914
|
const nextSummary = updater(currentEntry?.summary || null);
|
|
@@ -7658,7 +8981,7 @@ function updateSavedHistoryIndexForAppendedMessages(agentType, dir, file, histor
|
|
|
7658
8981
|
function computeSavedHistoryFileSummary(dir, file) {
|
|
7659
8982
|
const historySessionId = extractSavedHistorySessionIdFromFile(file);
|
|
7660
8983
|
if (!historySessionId) return null;
|
|
7661
|
-
const filePath =
|
|
8984
|
+
const filePath = path10.join(dir, file);
|
|
7662
8985
|
const content = fs3.readFileSync(filePath, "utf-8");
|
|
7663
8986
|
const lines = content.split("\n").filter(Boolean);
|
|
7664
8987
|
let messageCount = 0;
|
|
@@ -7745,7 +9068,7 @@ function computeSavedHistorySessionSummaries(agentType, dir, files, fileSignatur
|
|
|
7745
9068
|
const summaryBySessionId = /* @__PURE__ */ new Map();
|
|
7746
9069
|
const nextPersistedEntries = /* @__PURE__ */ new Map();
|
|
7747
9070
|
for (const file of files.slice().sort()) {
|
|
7748
|
-
const filePath =
|
|
9071
|
+
const filePath = path10.join(dir, file);
|
|
7749
9072
|
const signature = fileSignatures.get(file) || `${file}:missing`;
|
|
7750
9073
|
const cached = savedHistoryFileSummaryCache.get(filePath);
|
|
7751
9074
|
const persisted = persistedEntries.get(file);
|
|
@@ -7865,12 +9188,12 @@ var ChatHistoryWriter = class {
|
|
|
7865
9188
|
});
|
|
7866
9189
|
}
|
|
7867
9190
|
if (newMessages.length === 0) return;
|
|
7868
|
-
const dir =
|
|
9191
|
+
const dir = path10.join(HISTORY_DIR, this.sanitize(agentType));
|
|
7869
9192
|
fs3.mkdirSync(dir, { recursive: true });
|
|
7870
9193
|
const date = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
|
|
7871
9194
|
const filePrefix = effectiveHistoryKey ? `${this.sanitize(effectiveHistoryKey)}_` : "";
|
|
7872
9195
|
const fileName = `${filePrefix}${date}.jsonl`;
|
|
7873
|
-
const filePath =
|
|
9196
|
+
const filePath = path10.join(dir, fileName);
|
|
7874
9197
|
const lines = newMessages.map((m) => JSON.stringify(m)).join("\n") + "\n";
|
|
7875
9198
|
fs3.appendFileSync(filePath, lines, "utf-8");
|
|
7876
9199
|
updateSavedHistoryIndexForAppendedMessages(agentType, dir, fileName, effectiveHistoryKey, newMessages);
|
|
@@ -7961,11 +9284,11 @@ var ChatHistoryWriter = class {
|
|
|
7961
9284
|
const ws = String(workspace || "").trim();
|
|
7962
9285
|
if (!id || !ws) return;
|
|
7963
9286
|
try {
|
|
7964
|
-
const dir =
|
|
9287
|
+
const dir = path10.join(HISTORY_DIR, this.sanitize(agentType));
|
|
7965
9288
|
fs3.mkdirSync(dir, { recursive: true });
|
|
7966
9289
|
const date = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
|
|
7967
9290
|
const fileName = `${this.sanitize(id)}_${date}.jsonl`;
|
|
7968
|
-
const filePath =
|
|
9291
|
+
const filePath = path10.join(dir, fileName);
|
|
7969
9292
|
const record = {
|
|
7970
9293
|
ts: (/* @__PURE__ */ new Date()).toISOString(),
|
|
7971
9294
|
receivedAt: Date.now(),
|
|
@@ -8011,14 +9334,14 @@ var ChatHistoryWriter = class {
|
|
|
8011
9334
|
this.lastSeenCounts.set(toDedupKey, Math.max(fromCount, this.lastSeenCounts.get(toDedupKey) || 0));
|
|
8012
9335
|
this.lastSeenCounts.delete(fromDedupKey);
|
|
8013
9336
|
}
|
|
8014
|
-
const dir =
|
|
9337
|
+
const dir = path10.join(HISTORY_DIR, this.sanitize(agentType));
|
|
8015
9338
|
if (!fs3.existsSync(dir)) return;
|
|
8016
9339
|
const fromPrefix = `${this.sanitize(fromId)}_`;
|
|
8017
9340
|
const toPrefix = `${this.sanitize(toId)}_`;
|
|
8018
9341
|
const files = fs3.readdirSync(dir).filter((file) => file.startsWith(fromPrefix) && file.endsWith(".jsonl"));
|
|
8019
9342
|
for (const file of files) {
|
|
8020
|
-
const sourcePath =
|
|
8021
|
-
const targetPath =
|
|
9343
|
+
const sourcePath = path10.join(dir, file);
|
|
9344
|
+
const targetPath = path10.join(dir, `${toPrefix}${file.slice(fromPrefix.length)}`);
|
|
8022
9345
|
const sourceLines = fs3.readFileSync(sourcePath, "utf-8").split("\n").filter(Boolean);
|
|
8023
9346
|
const rewritten = sourceLines.map((line) => {
|
|
8024
9347
|
try {
|
|
@@ -8052,13 +9375,13 @@ var ChatHistoryWriter = class {
|
|
|
8052
9375
|
const sessionId = String(historySessionId || "").trim();
|
|
8053
9376
|
if (!sessionId) return;
|
|
8054
9377
|
try {
|
|
8055
|
-
const dir =
|
|
9378
|
+
const dir = path10.join(HISTORY_DIR, this.sanitize(agentType));
|
|
8056
9379
|
if (!fs3.existsSync(dir)) return;
|
|
8057
9380
|
const prefix = `${this.sanitize(sessionId)}_`;
|
|
8058
9381
|
const files = fs3.readdirSync(dir).filter((file) => file.startsWith(prefix) && file.endsWith(".jsonl")).sort();
|
|
8059
9382
|
const seen = /* @__PURE__ */ new Set();
|
|
8060
9383
|
for (const file of files) {
|
|
8061
|
-
const filePath =
|
|
9384
|
+
const filePath = path10.join(dir, file);
|
|
8062
9385
|
const lines = fs3.readFileSync(filePath, "utf-8").split("\n").filter(Boolean);
|
|
8063
9386
|
const next = [];
|
|
8064
9387
|
for (const line of lines) {
|
|
@@ -8112,13 +9435,13 @@ var ChatHistoryWriter = class {
|
|
|
8112
9435
|
const cutoff = Date.now() - RETAIN_DAYS * 24 * 60 * 60 * 1e3;
|
|
8113
9436
|
const agentDirs = fs3.readdirSync(HISTORY_DIR, { withFileTypes: true }).filter((d) => d.isDirectory());
|
|
8114
9437
|
for (const dir of agentDirs) {
|
|
8115
|
-
const dirPath =
|
|
9438
|
+
const dirPath = path10.join(HISTORY_DIR, dir.name);
|
|
8116
9439
|
const files = fs3.readdirSync(dirPath).filter((f) => f.endsWith(".jsonl") || f.endsWith(".terminal.log"));
|
|
8117
9440
|
let removedAny = false;
|
|
8118
9441
|
for (const file of files) {
|
|
8119
|
-
const filePath =
|
|
8120
|
-
const
|
|
8121
|
-
if (
|
|
9442
|
+
const filePath = path10.join(dirPath, file);
|
|
9443
|
+
const stat2 = fs3.statSync(filePath);
|
|
9444
|
+
if (stat2.mtimeMs < cutoff) {
|
|
8122
9445
|
fs3.unlinkSync(filePath);
|
|
8123
9446
|
removedAny = true;
|
|
8124
9447
|
}
|
|
@@ -8166,13 +9489,13 @@ function pageHistoryRecords(agentType, records, offset = 0, limit = 30, excludeR
|
|
|
8166
9489
|
function readChatHistory(agentType, offset = 0, limit = 30, historySessionId, excludeRecentCount = 0, historyBehavior) {
|
|
8167
9490
|
try {
|
|
8168
9491
|
const sanitized = agentType.replace(/[^a-zA-Z0-9_-]/g, "_");
|
|
8169
|
-
const dir =
|
|
9492
|
+
const dir = path10.join(HISTORY_DIR, sanitized);
|
|
8170
9493
|
if (!fs3.existsSync(dir)) return { messages: [], hasMore: false };
|
|
8171
9494
|
const files = listHistoryFiles(dir, historySessionId);
|
|
8172
9495
|
const allMessages = [];
|
|
8173
9496
|
const seen = /* @__PURE__ */ new Set();
|
|
8174
9497
|
for (const file of files) {
|
|
8175
|
-
const filePath =
|
|
9498
|
+
const filePath = path10.join(dir, file);
|
|
8176
9499
|
const content = fs3.readFileSync(filePath, "utf-8");
|
|
8177
9500
|
const lines = content.trim().split("\n").filter(Boolean);
|
|
8178
9501
|
for (let i = 0; i < lines.length; i++) {
|
|
@@ -8196,7 +9519,7 @@ function readChatHistory(agentType, offset = 0, limit = 30, historySessionId, ex
|
|
|
8196
9519
|
function listSavedHistorySessions(agentType, options = {}, historyBehavior) {
|
|
8197
9520
|
try {
|
|
8198
9521
|
const sanitized = agentType.replace(/[^a-zA-Z0-9_-]/g, "_");
|
|
8199
|
-
const dir =
|
|
9522
|
+
const dir = path10.join(HISTORY_DIR, sanitized);
|
|
8200
9523
|
if (!fs3.existsSync(dir)) {
|
|
8201
9524
|
savedHistorySessionCache.delete(sanitized);
|
|
8202
9525
|
return { sessions: [], hasMore: false };
|
|
@@ -8257,11 +9580,11 @@ function listSavedHistorySessions(agentType, options = {}, historyBehavior) {
|
|
|
8257
9580
|
}
|
|
8258
9581
|
function readExistingSessionStartRecord(agentType, historySessionId) {
|
|
8259
9582
|
try {
|
|
8260
|
-
const dir =
|
|
9583
|
+
const dir = path10.join(HISTORY_DIR, agentType);
|
|
8261
9584
|
if (!fs3.existsSync(dir)) return null;
|
|
8262
9585
|
const files = listHistoryFiles(dir, historySessionId).sort();
|
|
8263
9586
|
for (const file of files) {
|
|
8264
|
-
const lines = fs3.readFileSync(
|
|
9587
|
+
const lines = fs3.readFileSync(path10.join(dir, file), "utf-8").split("\n").filter(Boolean);
|
|
8265
9588
|
for (const line of lines) {
|
|
8266
9589
|
try {
|
|
8267
9590
|
const parsed = JSON.parse(line);
|
|
@@ -8281,16 +9604,16 @@ function readExistingSessionStartRecord(agentType, historySessionId) {
|
|
|
8281
9604
|
function rewriteCanonicalSavedHistory(agentType, historySessionId, records) {
|
|
8282
9605
|
if (records.length === 0) return false;
|
|
8283
9606
|
try {
|
|
8284
|
-
const dir =
|
|
9607
|
+
const dir = path10.join(HISTORY_DIR, agentType);
|
|
8285
9608
|
fs3.mkdirSync(dir, { recursive: true });
|
|
8286
9609
|
const prefix = `${historySessionId.replace(/[^a-zA-Z0-9_-]/g, "_")}_`;
|
|
8287
9610
|
for (const file of fs3.readdirSync(dir)) {
|
|
8288
9611
|
if (file.startsWith(prefix) && file.endsWith(".jsonl")) {
|
|
8289
|
-
fs3.unlinkSync(
|
|
9612
|
+
fs3.unlinkSync(path10.join(dir, file));
|
|
8290
9613
|
}
|
|
8291
9614
|
}
|
|
8292
9615
|
const targetDate = new Date(records[records.length - 1].receivedAt || Date.now()).toISOString().slice(0, 10);
|
|
8293
|
-
const filePath =
|
|
9616
|
+
const filePath = path10.join(dir, `${prefix}${targetDate}.jsonl`);
|
|
8294
9617
|
fs3.writeFileSync(filePath, `${records.map((record) => JSON.stringify(record)).join("\n")}
|
|
8295
9618
|
`, "utf-8");
|
|
8296
9619
|
invalidatePersistedSavedHistoryIndex(agentType, dir);
|
|
@@ -10162,6 +11485,10 @@ function shouldIncludeSessionMetadata(profile) {
|
|
|
10162
11485
|
function shouldIncludeRuntimeMetadata(profile) {
|
|
10163
11486
|
return true;
|
|
10164
11487
|
}
|
|
11488
|
+
function getGitSummaryForWorkspace(workspace, options) {
|
|
11489
|
+
if (!workspace) return void 0;
|
|
11490
|
+
return options.getGitSummaryForWorkspace?.(workspace) || void 0;
|
|
11491
|
+
}
|
|
10165
11492
|
function findCdpManager(cdpManagers, key) {
|
|
10166
11493
|
const exact = cdpManagers.get(key);
|
|
10167
11494
|
if (exact) return exact.isConnected ? exact : null;
|
|
@@ -10217,6 +11544,8 @@ function buildIdeWorkspaceSession(state, cdpManagers, options) {
|
|
|
10217
11544
|
const controlValues = normalizeProviderStateControlValues(state.controlValues);
|
|
10218
11545
|
const includeSessionMetadata = shouldIncludeSessionMetadata(profile);
|
|
10219
11546
|
const includeSessionControls = shouldIncludeSessionControls(profile);
|
|
11547
|
+
const workspace = state.workspace || null;
|
|
11548
|
+
const git = getGitSummaryForWorkspace(workspace, options);
|
|
10220
11549
|
const title = activeChat?.title || state.name;
|
|
10221
11550
|
return {
|
|
10222
11551
|
id: state.instanceId || state.type,
|
|
@@ -10229,7 +11558,8 @@ function buildIdeWorkspaceSession(state, cdpManagers, options) {
|
|
|
10229
11558
|
activeModal: activeChat?.activeModal || null
|
|
10230
11559
|
}),
|
|
10231
11560
|
title,
|
|
10232
|
-
workspace
|
|
11561
|
+
workspace,
|
|
11562
|
+
...git && { git },
|
|
10233
11563
|
activeChat,
|
|
10234
11564
|
...summaryMetadata && { summaryMetadata },
|
|
10235
11565
|
...includeSessionMetadata && { capabilities: state.sessionCapabilities || IDE_SESSION_CAPABILITIES },
|
|
@@ -10250,6 +11580,8 @@ function buildExtensionAgentSession(parent, ext, options) {
|
|
|
10250
11580
|
const controlValues = normalizeProviderStateControlValues(ext.controlValues);
|
|
10251
11581
|
const includeSessionMetadata = shouldIncludeSessionMetadata(profile);
|
|
10252
11582
|
const includeSessionControls = shouldIncludeSessionControls(profile);
|
|
11583
|
+
const workspace = parent.workspace || null;
|
|
11584
|
+
const git = getGitSummaryForWorkspace(workspace, options);
|
|
10253
11585
|
return {
|
|
10254
11586
|
id: ext.instanceId || `${parent.instanceId}:${ext.type}`,
|
|
10255
11587
|
parentId: parent.instanceId || parent.type,
|
|
@@ -10262,7 +11594,8 @@ function buildExtensionAgentSession(parent, ext, options) {
|
|
|
10262
11594
|
activeModal: activeChat?.activeModal || null
|
|
10263
11595
|
}),
|
|
10264
11596
|
title: activeChat?.title || ext.name,
|
|
10265
|
-
workspace
|
|
11597
|
+
workspace,
|
|
11598
|
+
...git && { git },
|
|
10266
11599
|
activeChat,
|
|
10267
11600
|
...summaryMetadata && { summaryMetadata },
|
|
10268
11601
|
...includeSessionMetadata && { capabilities: ext.sessionCapabilities || EXTENSION_SESSION_CAPABILITIES },
|
|
@@ -10298,6 +11631,8 @@ function buildCliSession(state, options) {
|
|
|
10298
11631
|
const includeSessionMetadata = shouldIncludeSessionMetadata(profile);
|
|
10299
11632
|
const includeRuntimeMetadata = shouldIncludeRuntimeMetadata(profile);
|
|
10300
11633
|
const includeSessionControls = shouldIncludeSessionControls(profile);
|
|
11634
|
+
const workspace = state.workspace || null;
|
|
11635
|
+
const git = getGitSummaryForWorkspace(workspace, options);
|
|
10301
11636
|
return {
|
|
10302
11637
|
id: state.instanceId,
|
|
10303
11638
|
parentId: null,
|
|
@@ -10310,7 +11645,8 @@ function buildCliSession(state, options) {
|
|
|
10310
11645
|
activeModal: activeChat?.activeModal || null
|
|
10311
11646
|
}),
|
|
10312
11647
|
title: activeChat?.title || state.name,
|
|
10313
|
-
workspace
|
|
11648
|
+
workspace,
|
|
11649
|
+
...git && { git },
|
|
10314
11650
|
...includeRuntimeMetadata && {
|
|
10315
11651
|
runtimeKey: state.runtime?.runtimeKey,
|
|
10316
11652
|
runtimeDisplayName: state.runtime?.displayName,
|
|
@@ -10345,6 +11681,8 @@ function buildAcpSession(state, options) {
|
|
|
10345
11681
|
const controlValues = normalizeProviderStateControlValues(state.controlValues);
|
|
10346
11682
|
const includeSessionMetadata = shouldIncludeSessionMetadata(profile);
|
|
10347
11683
|
const includeSessionControls = shouldIncludeSessionControls(profile);
|
|
11684
|
+
const workspace = state.workspace || null;
|
|
11685
|
+
const git = getGitSummaryForWorkspace(workspace, options);
|
|
10348
11686
|
return {
|
|
10349
11687
|
id: state.instanceId,
|
|
10350
11688
|
parentId: null,
|
|
@@ -10356,7 +11694,8 @@ function buildAcpSession(state, options) {
|
|
|
10356
11694
|
activeModal: activeChat?.activeModal || null
|
|
10357
11695
|
}),
|
|
10358
11696
|
title: activeChat?.title || state.name,
|
|
10359
|
-
workspace
|
|
11697
|
+
workspace,
|
|
11698
|
+
...git && { git },
|
|
10360
11699
|
activeChat,
|
|
10361
11700
|
...summaryMetadata && { summaryMetadata },
|
|
10362
11701
|
...includeSessionMetadata && { capabilities: ACP_SESSION_CAPABILITIES },
|
|
@@ -10475,7 +11814,7 @@ function resolveLegacyProviderScript(fn, scriptName, params) {
|
|
|
10475
11814
|
// src/commands/chat-commands.ts
|
|
10476
11815
|
var fs4 = __toESM(require("fs"));
|
|
10477
11816
|
var os6 = __toESM(require("os"));
|
|
10478
|
-
var
|
|
11817
|
+
var path11 = __toESM(require("path"));
|
|
10479
11818
|
var import_node_crypto = require("crypto");
|
|
10480
11819
|
init_contracts();
|
|
10481
11820
|
|
|
@@ -11168,7 +12507,7 @@ function buildDebugBundleText(bundle) {
|
|
|
11168
12507
|
}
|
|
11169
12508
|
function getChatDebugBundleDir() {
|
|
11170
12509
|
const override = typeof process.env.ADHDEV_DEBUG_BUNDLE_DIR === "string" ? process.env.ADHDEV_DEBUG_BUNDLE_DIR.trim() : "";
|
|
11171
|
-
return override ||
|
|
12510
|
+
return override || path11.join(os6.homedir(), ".adhdev", "debug-bundles", "chat");
|
|
11172
12511
|
}
|
|
11173
12512
|
function safeBundleIdSegment(value, fallback) {
|
|
11174
12513
|
const normalized = String(value || fallback).trim().replace(/[^A-Za-z0-9_.-]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 80);
|
|
@@ -11201,7 +12540,7 @@ function storeChatDebugBundleOnDaemon(bundle, targetSessionId) {
|
|
|
11201
12540
|
const bundleId = createChatDebugBundleId(targetSessionId);
|
|
11202
12541
|
const dir = getChatDebugBundleDir();
|
|
11203
12542
|
fs4.mkdirSync(dir, { recursive: true });
|
|
11204
|
-
const savedPath =
|
|
12543
|
+
const savedPath = path11.join(dir, `${bundleId}.json`);
|
|
11205
12544
|
const json = `${JSON.stringify(bundle, null, 2)}
|
|
11206
12545
|
`;
|
|
11207
12546
|
fs4.writeFileSync(savedPath, json, { encoding: "utf8", mode: 384 });
|
|
@@ -11395,7 +12734,7 @@ function getCliVisibleTranscriptCount(adapter) {
|
|
|
11395
12734
|
async function getStableExtensionBaseline(h) {
|
|
11396
12735
|
const first = await readExtensionChatState(h);
|
|
11397
12736
|
if (getStateMessageCount(first) > 0 || getStateLastSignature(first)) return first;
|
|
11398
|
-
await new Promise((
|
|
12737
|
+
await new Promise((resolve15) => setTimeout(resolve15, 150));
|
|
11399
12738
|
const second = await readExtensionChatState(h);
|
|
11400
12739
|
return getStateMessageCount(second) >= getStateMessageCount(first) ? second : first;
|
|
11401
12740
|
}
|
|
@@ -11403,7 +12742,7 @@ async function verifyExtensionSendObserved(h, before) {
|
|
|
11403
12742
|
const beforeCount = getStateMessageCount(before);
|
|
11404
12743
|
const beforeSignature = getStateLastSignature(before);
|
|
11405
12744
|
for (let attempt = 0; attempt < 12; attempt += 1) {
|
|
11406
|
-
await new Promise((
|
|
12745
|
+
await new Promise((resolve15) => setTimeout(resolve15, 250));
|
|
11407
12746
|
const state = await readExtensionChatState(h);
|
|
11408
12747
|
if (state?.status === "waiting_approval") return true;
|
|
11409
12748
|
const afterCount = getStateMessageCount(state);
|
|
@@ -12339,7 +13678,7 @@ async function handleResolveAction(h, args) {
|
|
|
12339
13678
|
|
|
12340
13679
|
// src/commands/cdp-commands.ts
|
|
12341
13680
|
var fs5 = __toESM(require("fs"));
|
|
12342
|
-
var
|
|
13681
|
+
var path12 = __toESM(require("path"));
|
|
12343
13682
|
var os7 = __toESM(require("os"));
|
|
12344
13683
|
var KEY_TO_VK = {
|
|
12345
13684
|
Backspace: 8,
|
|
@@ -12596,25 +13935,25 @@ function resolveSafePath(requestedPath) {
|
|
|
12596
13935
|
const inputPath = rawPath || ".";
|
|
12597
13936
|
const home = os7.homedir();
|
|
12598
13937
|
if (inputPath.startsWith("~")) {
|
|
12599
|
-
return
|
|
13938
|
+
return path12.resolve(path12.join(home, inputPath.slice(1)));
|
|
12600
13939
|
}
|
|
12601
13940
|
if (process.platform === "win32") {
|
|
12602
13941
|
const normalized = normalizeWindowsRequestedPath(inputPath);
|
|
12603
|
-
if (
|
|
12604
|
-
return
|
|
13942
|
+
if (path12.win32.isAbsolute(normalized)) {
|
|
13943
|
+
return path12.win32.normalize(normalized);
|
|
12605
13944
|
}
|
|
12606
|
-
return
|
|
13945
|
+
return path12.win32.resolve(normalized);
|
|
12607
13946
|
}
|
|
12608
|
-
if (
|
|
12609
|
-
return
|
|
13947
|
+
if (path12.isAbsolute(inputPath)) {
|
|
13948
|
+
return path12.normalize(inputPath);
|
|
12610
13949
|
}
|
|
12611
|
-
return
|
|
13950
|
+
return path12.resolve(inputPath);
|
|
12612
13951
|
}
|
|
12613
13952
|
function listDirectoryEntriesSafe(dirPath) {
|
|
12614
13953
|
const entries = fs5.readdirSync(dirPath, { withFileTypes: true });
|
|
12615
13954
|
const files = [];
|
|
12616
13955
|
for (const entry of entries) {
|
|
12617
|
-
const entryPath =
|
|
13956
|
+
const entryPath = path12.join(dirPath, entry.name);
|
|
12618
13957
|
try {
|
|
12619
13958
|
if (entry.isDirectory()) {
|
|
12620
13959
|
files.push({ name: entry.name, type: "directory" });
|
|
@@ -12630,11 +13969,11 @@ function listDirectoryEntriesSafe(dirPath) {
|
|
|
12630
13969
|
files.push({ name: entry.name, type: "file", size });
|
|
12631
13970
|
continue;
|
|
12632
13971
|
}
|
|
12633
|
-
const
|
|
13972
|
+
const stat2 = fs5.statSync(entryPath);
|
|
12634
13973
|
files.push({
|
|
12635
13974
|
name: entry.name,
|
|
12636
|
-
type:
|
|
12637
|
-
size:
|
|
13975
|
+
type: stat2.isDirectory() ? "directory" : "file",
|
|
13976
|
+
size: stat2.isFile() ? stat2.size : void 0
|
|
12638
13977
|
});
|
|
12639
13978
|
} catch {
|
|
12640
13979
|
}
|
|
@@ -12668,7 +14007,7 @@ async function handleFileRead(h, args) {
|
|
|
12668
14007
|
async function handleFileWrite(h, args) {
|
|
12669
14008
|
try {
|
|
12670
14009
|
const filePath = resolveSafePath(args?.path);
|
|
12671
|
-
fs5.mkdirSync(
|
|
14010
|
+
fs5.mkdirSync(path12.dirname(filePath), { recursive: true });
|
|
12672
14011
|
fs5.writeFileSync(filePath, args?.content || "", "utf-8");
|
|
12673
14012
|
return { success: true, path: filePath };
|
|
12674
14013
|
} catch (e) {
|
|
@@ -13017,7 +14356,7 @@ async function executeProviderScript(h, args, scriptName) {
|
|
|
13017
14356
|
const enterCount = cliCommand.enterCount || 1;
|
|
13018
14357
|
await adapter.writeRaw(cliCommand.text + "\r");
|
|
13019
14358
|
for (let i = 1; i < enterCount; i += 1) {
|
|
13020
|
-
await new Promise((
|
|
14359
|
+
await new Promise((resolve15) => setTimeout(resolve15, 50));
|
|
13021
14360
|
await adapter.writeRaw("\r");
|
|
13022
14361
|
}
|
|
13023
14362
|
}
|
|
@@ -13511,6 +14850,12 @@ var DaemonCommandHandler = class {
|
|
|
13511
14850
|
this._currentRoute = this.resolveRoute(args);
|
|
13512
14851
|
const startedAt = Date.now();
|
|
13513
14852
|
this.logCommandStart(cmd, args);
|
|
14853
|
+
let result;
|
|
14854
|
+
if (isGitCommandName(cmd)) {
|
|
14855
|
+
result = await handleGitCommand(cmd, args, this._ctx.gitCommandServices);
|
|
14856
|
+
this.logCommandEnd(cmd, result, startedAt);
|
|
14857
|
+
return result;
|
|
14858
|
+
}
|
|
13514
14859
|
const sessionScopedCommands = /* @__PURE__ */ new Set([
|
|
13515
14860
|
"read_chat",
|
|
13516
14861
|
"get_chat_debug_bundle",
|
|
@@ -13536,7 +14881,6 @@ var DaemonCommandHandler = class {
|
|
|
13536
14881
|
this.logCommandEnd(cmd, result2, startedAt);
|
|
13537
14882
|
return result2;
|
|
13538
14883
|
}
|
|
13539
|
-
let result;
|
|
13540
14884
|
if (!this._currentRoute.session && !this._currentRoute.managerKey && !this._currentRoute.providerType) {
|
|
13541
14885
|
const cdpCommands = ["send_chat", "read_chat", "list_chats", "new_chat", "switch_chat", "set_mode", "change_model", "set_thought_level", "resolve_action"];
|
|
13542
14886
|
if (cdpCommands.includes(cmd)) {
|
|
@@ -13545,6 +14889,16 @@ var DaemonCommandHandler = class {
|
|
|
13545
14889
|
return result;
|
|
13546
14890
|
}
|
|
13547
14891
|
}
|
|
14892
|
+
if (cmd === "send_chat" && this._ctx.onBeforeSendChat) {
|
|
14893
|
+
const sessionId = this._currentRoute.session?.sessionId;
|
|
14894
|
+
const workspace = sessionId ? this._ctx.instanceManager?.getInstance(sessionId)?.getState?.()?.workspace : void 0;
|
|
14895
|
+
if (workspace && sessionId) {
|
|
14896
|
+
try {
|
|
14897
|
+
this._ctx.onBeforeSendChat({ workspace, sessionId });
|
|
14898
|
+
} catch {
|
|
14899
|
+
}
|
|
14900
|
+
}
|
|
14901
|
+
}
|
|
13548
14902
|
try {
|
|
13549
14903
|
result = await this.dispatch(cmd, args);
|
|
13550
14904
|
this.logCommandEnd(cmd, result, startedAt);
|
|
@@ -13687,7 +15041,7 @@ var DaemonCommandHandler = class {
|
|
|
13687
15041
|
try {
|
|
13688
15042
|
const http3 = await import("http");
|
|
13689
15043
|
const postData = JSON.stringify(body);
|
|
13690
|
-
const result = await new Promise((
|
|
15044
|
+
const result = await new Promise((resolve15, reject) => {
|
|
13691
15045
|
const req = http3.request({
|
|
13692
15046
|
hostname: "127.0.0.1",
|
|
13693
15047
|
port: 19280,
|
|
@@ -13699,9 +15053,9 @@ var DaemonCommandHandler = class {
|
|
|
13699
15053
|
res.on("data", (chunk) => data += chunk);
|
|
13700
15054
|
res.on("end", () => {
|
|
13701
15055
|
try {
|
|
13702
|
-
|
|
15056
|
+
resolve15(JSON.parse(data));
|
|
13703
15057
|
} catch {
|
|
13704
|
-
|
|
15058
|
+
resolve15({ raw: data });
|
|
13705
15059
|
}
|
|
13706
15060
|
});
|
|
13707
15061
|
});
|
|
@@ -13719,15 +15073,15 @@ var DaemonCommandHandler = class {
|
|
|
13719
15073
|
if (!providerType) return { success: false, error: "providerType required" };
|
|
13720
15074
|
try {
|
|
13721
15075
|
const http3 = await import("http");
|
|
13722
|
-
const result = await new Promise((
|
|
15076
|
+
const result = await new Promise((resolve15, reject) => {
|
|
13723
15077
|
http3.get(`http://127.0.0.1:19280/api/providers/${providerType}/${endpoint}`, (res) => {
|
|
13724
15078
|
let data = "";
|
|
13725
15079
|
res.on("data", (chunk) => data += chunk);
|
|
13726
15080
|
res.on("end", () => {
|
|
13727
15081
|
try {
|
|
13728
|
-
|
|
15082
|
+
resolve15(JSON.parse(data));
|
|
13729
15083
|
} catch {
|
|
13730
|
-
|
|
15084
|
+
resolve15({ raw: data });
|
|
13731
15085
|
}
|
|
13732
15086
|
});
|
|
13733
15087
|
}).on("error", reject);
|
|
@@ -13741,7 +15095,7 @@ var DaemonCommandHandler = class {
|
|
|
13741
15095
|
try {
|
|
13742
15096
|
const http3 = await import("http");
|
|
13743
15097
|
const postData = JSON.stringify(args || {});
|
|
13744
|
-
const result = await new Promise((
|
|
15098
|
+
const result = await new Promise((resolve15, reject) => {
|
|
13745
15099
|
const req = http3.request({
|
|
13746
15100
|
hostname: "127.0.0.1",
|
|
13747
15101
|
port: 19280,
|
|
@@ -13753,9 +15107,9 @@ var DaemonCommandHandler = class {
|
|
|
13753
15107
|
res.on("data", (chunk) => data += chunk);
|
|
13754
15108
|
res.on("end", () => {
|
|
13755
15109
|
try {
|
|
13756
|
-
|
|
15110
|
+
resolve15(JSON.parse(data));
|
|
13757
15111
|
} catch {
|
|
13758
|
-
|
|
15112
|
+
resolve15({ raw: data });
|
|
13759
15113
|
}
|
|
13760
15114
|
});
|
|
13761
15115
|
});
|
|
@@ -13772,7 +15126,7 @@ var DaemonCommandHandler = class {
|
|
|
13772
15126
|
|
|
13773
15127
|
// src/commands/cli-manager.ts
|
|
13774
15128
|
var os13 = __toESM(require("os"));
|
|
13775
|
-
var
|
|
15129
|
+
var path16 = __toESM(require("path"));
|
|
13776
15130
|
var crypto4 = __toESM(require("crypto"));
|
|
13777
15131
|
var import_fs5 = require("fs");
|
|
13778
15132
|
var import_child_process6 = require("child_process");
|
|
@@ -13782,7 +15136,7 @@ init_config();
|
|
|
13782
15136
|
|
|
13783
15137
|
// src/providers/cli-provider-instance.ts
|
|
13784
15138
|
var os12 = __toESM(require("os"));
|
|
13785
|
-
var
|
|
15139
|
+
var path15 = __toESM(require("path"));
|
|
13786
15140
|
var crypto3 = __toESM(require("crypto"));
|
|
13787
15141
|
var fs6 = __toESM(require("fs"));
|
|
13788
15142
|
var import_node_module = require("module");
|
|
@@ -13843,7 +15197,7 @@ function buildIncrementalHistoryAppendMessages(previousMessages, currentMessages
|
|
|
13843
15197
|
var CachedDatabaseSync = null;
|
|
13844
15198
|
function getDatabaseSync() {
|
|
13845
15199
|
if (CachedDatabaseSync) return CachedDatabaseSync;
|
|
13846
|
-
const requireFn = typeof require === "function" ? require : (0, import_node_module.createRequire)(
|
|
15200
|
+
const requireFn = typeof require === "function" ? require : (0, import_node_module.createRequire)(path15.join(process.cwd(), "__adhdev_sqlite_loader__.js"));
|
|
13847
15201
|
const sqliteModule = requireFn(`node:${"sqlite"}`);
|
|
13848
15202
|
CachedDatabaseSync = sqliteModule.DatabaseSync;
|
|
13849
15203
|
if (!CachedDatabaseSync) {
|
|
@@ -13881,7 +15235,7 @@ async function waitForCliAdapterReady(adapter, options) {
|
|
|
13881
15235
|
if (status === "stopped") {
|
|
13882
15236
|
throw new Error("CLI runtime stopped before it became ready");
|
|
13883
15237
|
}
|
|
13884
|
-
await new Promise((
|
|
15238
|
+
await new Promise((resolve15) => setTimeout(resolve15, pollMs));
|
|
13885
15239
|
}
|
|
13886
15240
|
throw new Error(`CLI runtime did not become ready within ${timeoutMs}ms`);
|
|
13887
15241
|
}
|
|
@@ -14232,7 +15586,7 @@ var CliProviderInstance = class {
|
|
|
14232
15586
|
const enterCount = cliCommand.enterCount || 1;
|
|
14233
15587
|
await this.adapter.writeRaw(cliCommand.text + "\r");
|
|
14234
15588
|
for (let i = 1; i < enterCount; i += 1) {
|
|
14235
|
-
await new Promise((
|
|
15589
|
+
await new Promise((resolve15) => setTimeout(resolve15, 50));
|
|
14236
15590
|
await this.adapter.writeRaw("\r");
|
|
14237
15591
|
}
|
|
14238
15592
|
}
|
|
@@ -15346,13 +16700,13 @@ var AcpProviderInstance = class {
|
|
|
15346
16700
|
}
|
|
15347
16701
|
this.currentStatus = "waiting_approval";
|
|
15348
16702
|
this.detectStatusTransition();
|
|
15349
|
-
const approved = await new Promise((
|
|
15350
|
-
this.permissionResolvers.push(
|
|
16703
|
+
const approved = await new Promise((resolve15) => {
|
|
16704
|
+
this.permissionResolvers.push(resolve15);
|
|
15351
16705
|
setTimeout(() => {
|
|
15352
|
-
const idx = this.permissionResolvers.indexOf(
|
|
16706
|
+
const idx = this.permissionResolvers.indexOf(resolve15);
|
|
15353
16707
|
if (idx >= 0) {
|
|
15354
16708
|
this.permissionResolvers.splice(idx, 1);
|
|
15355
|
-
|
|
16709
|
+
resolve15(false);
|
|
15356
16710
|
}
|
|
15357
16711
|
}, 3e5);
|
|
15358
16712
|
});
|
|
@@ -15927,11 +17281,11 @@ function shouldRestoreHostedRuntime(record, managerTag) {
|
|
|
15927
17281
|
// src/commands/cli-manager.ts
|
|
15928
17282
|
function isExplicitCommand(command) {
|
|
15929
17283
|
const trimmed = command.trim();
|
|
15930
|
-
return
|
|
17284
|
+
return path16.isAbsolute(trimmed) || trimmed.includes("/") || trimmed.includes("\\") || trimmed.startsWith("~");
|
|
15931
17285
|
}
|
|
15932
17286
|
function expandExecutable(command) {
|
|
15933
17287
|
const trimmed = command.trim();
|
|
15934
|
-
return trimmed.startsWith("~") ?
|
|
17288
|
+
return trimmed.startsWith("~") ? path16.join(os13.homedir(), trimmed.slice(1)) : trimmed;
|
|
15935
17289
|
}
|
|
15936
17290
|
function commandExists(command) {
|
|
15937
17291
|
const trimmed = command.trim();
|
|
@@ -16212,7 +17566,7 @@ var DaemonCliManager = class {
|
|
|
16212
17566
|
async startSession(cliType, workingDir, cliArgs, initialModel, options) {
|
|
16213
17567
|
const trimmed = (workingDir || "").trim();
|
|
16214
17568
|
if (!trimmed) throw new Error("working directory required");
|
|
16215
|
-
const resolvedDir = trimmed.startsWith("~") ? trimmed.replace(/^~/, os13.homedir()) :
|
|
17569
|
+
const resolvedDir = trimmed.startsWith("~") ? trimmed.replace(/^~/, os13.homedir()) : path16.resolve(trimmed);
|
|
16216
17570
|
const normalizedType = this.providerLoader.resolveAlias(cliType);
|
|
16217
17571
|
const rawProvider = this.providerLoader.getByAlias(cliType);
|
|
16218
17572
|
const provider = rawProvider ? this.providerLoader.resolve(normalizedType) || rawProvider : void 0;
|
|
@@ -16713,11 +18067,11 @@ Run 'adhdev doctor' for detailed diagnostics.`
|
|
|
16713
18067
|
var import_child_process7 = require("child_process");
|
|
16714
18068
|
var net = __toESM(require("net"));
|
|
16715
18069
|
var os15 = __toESM(require("os"));
|
|
16716
|
-
var
|
|
18070
|
+
var path18 = __toESM(require("path"));
|
|
16717
18071
|
|
|
16718
18072
|
// src/providers/provider-loader.ts
|
|
16719
18073
|
var fs7 = __toESM(require("fs"));
|
|
16720
|
-
var
|
|
18074
|
+
var path17 = __toESM(require("path"));
|
|
16721
18075
|
var os14 = __toESM(require("os"));
|
|
16722
18076
|
var chokidar = __toESM(require("chokidar"));
|
|
16723
18077
|
init_logger();
|
|
@@ -16780,6 +18134,7 @@ var KNOWN_PROVIDER_FIELDS = /* @__PURE__ */ new Set([
|
|
|
16780
18134
|
"sendDelayMs",
|
|
16781
18135
|
"sendKey",
|
|
16782
18136
|
"submitStrategy",
|
|
18137
|
+
"requirePromptEchoBeforeSubmit",
|
|
16783
18138
|
"timeouts",
|
|
16784
18139
|
"disableUpstream"
|
|
16785
18140
|
]);
|
|
@@ -16982,7 +18337,7 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
16982
18337
|
try {
|
|
16983
18338
|
if (!fs7.existsSync(candidate) || !fs7.statSync(candidate).isDirectory()) return false;
|
|
16984
18339
|
return ["ide", "extension", "cli", "acp"].some(
|
|
16985
|
-
(category) => fs7.existsSync(
|
|
18340
|
+
(category) => fs7.existsSync(path17.join(candidate, category))
|
|
16986
18341
|
);
|
|
16987
18342
|
} catch {
|
|
16988
18343
|
return false;
|
|
@@ -16990,20 +18345,20 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
16990
18345
|
}
|
|
16991
18346
|
static hasProviderRootMarker(candidate) {
|
|
16992
18347
|
try {
|
|
16993
|
-
return fs7.existsSync(
|
|
18348
|
+
return fs7.existsSync(path17.join(candidate, _ProviderLoader.SIBLING_MARKER_FILE));
|
|
16994
18349
|
} catch {
|
|
16995
18350
|
return false;
|
|
16996
18351
|
}
|
|
16997
18352
|
}
|
|
16998
18353
|
detectDefaultUserDir() {
|
|
16999
|
-
const fallback =
|
|
18354
|
+
const fallback = path17.join(os14.homedir(), ".adhdev", "providers");
|
|
17000
18355
|
const envOptIn = process.env[_ProviderLoader.SIBLING_ENV_VAR] === "1";
|
|
17001
18356
|
const visited = /* @__PURE__ */ new Set();
|
|
17002
18357
|
for (const start of this.probeStarts) {
|
|
17003
|
-
let current =
|
|
18358
|
+
let current = path17.resolve(start);
|
|
17004
18359
|
while (!visited.has(current)) {
|
|
17005
18360
|
visited.add(current);
|
|
17006
|
-
const siblingCandidate =
|
|
18361
|
+
const siblingCandidate = path17.join(path17.dirname(current), _ProviderLoader.REPO_PROVIDER_DIRNAME);
|
|
17007
18362
|
if (_ProviderLoader.looksLikeProviderRoot(siblingCandidate)) {
|
|
17008
18363
|
const hasMarker = _ProviderLoader.hasProviderRootMarker(siblingCandidate);
|
|
17009
18364
|
if (envOptIn || hasMarker) {
|
|
@@ -17025,7 +18380,7 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
17025
18380
|
return { path: siblingCandidate, source };
|
|
17026
18381
|
}
|
|
17027
18382
|
}
|
|
17028
|
-
const parent =
|
|
18383
|
+
const parent = path17.dirname(current);
|
|
17029
18384
|
if (parent === current) break;
|
|
17030
18385
|
current = parent;
|
|
17031
18386
|
}
|
|
@@ -17035,11 +18390,11 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
17035
18390
|
constructor(options) {
|
|
17036
18391
|
this.logFn = options?.logFn || LOG.forComponent("Provider").asLogFn();
|
|
17037
18392
|
this.probeStarts = options?.probeStarts ?? [process.cwd(), __dirname];
|
|
17038
|
-
this.defaultProvidersDir =
|
|
18393
|
+
this.defaultProvidersDir = path17.join(os14.homedir(), ".adhdev", "providers");
|
|
17039
18394
|
const detected = this.detectDefaultUserDir();
|
|
17040
18395
|
this.userDir = detected.path;
|
|
17041
18396
|
this.userDirSource = detected.source;
|
|
17042
|
-
this.upstreamDir =
|
|
18397
|
+
this.upstreamDir = path17.join(this.defaultProvidersDir, ".upstream");
|
|
17043
18398
|
this.disableUpstream = false;
|
|
17044
18399
|
this.applySourceConfig({
|
|
17045
18400
|
userDir: options?.userDir,
|
|
@@ -17098,7 +18453,7 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
17098
18453
|
this.userDir = detected.path;
|
|
17099
18454
|
this.userDirSource = detected.source;
|
|
17100
18455
|
}
|
|
17101
|
-
this.upstreamDir =
|
|
18456
|
+
this.upstreamDir = path17.join(this.defaultProvidersDir, ".upstream");
|
|
17102
18457
|
this.disableUpstream = this.sourceMode === "no-upstream";
|
|
17103
18458
|
if (this.explicitProviderDir) {
|
|
17104
18459
|
this.log(`Config 'providerDir' applied: ${this.userDir}`);
|
|
@@ -17112,7 +18467,7 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
17112
18467
|
* Canonical provider directory shape for a given root.
|
|
17113
18468
|
*/
|
|
17114
18469
|
getProviderDir(root, category, type) {
|
|
17115
|
-
return
|
|
18470
|
+
return path17.join(root, category, type);
|
|
17116
18471
|
}
|
|
17117
18472
|
/**
|
|
17118
18473
|
* Canonical user override directory for a provider.
|
|
@@ -17139,7 +18494,7 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
17139
18494
|
resolveProviderFile(type, ...segments) {
|
|
17140
18495
|
const dir = this.findProviderDirInternal(type);
|
|
17141
18496
|
if (!dir) return null;
|
|
17142
|
-
return
|
|
18497
|
+
return path17.join(dir, ...segments);
|
|
17143
18498
|
}
|
|
17144
18499
|
/**
|
|
17145
18500
|
* Load all providers (3-tier priority)
|
|
@@ -17178,7 +18533,7 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
17178
18533
|
if (!fs7.existsSync(this.upstreamDir)) return false;
|
|
17179
18534
|
try {
|
|
17180
18535
|
return fs7.readdirSync(this.upstreamDir).some(
|
|
17181
|
-
(d) => fs7.statSync(
|
|
18536
|
+
(d) => fs7.statSync(path17.join(this.upstreamDir, d)).isDirectory()
|
|
17182
18537
|
);
|
|
17183
18538
|
} catch {
|
|
17184
18539
|
return false;
|
|
@@ -17675,8 +19030,8 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
17675
19030
|
resolved._resolvedScriptDir = entry.scriptDir;
|
|
17676
19031
|
resolved._resolvedScriptsSource = `compatibility:${entry.ideVersion}`;
|
|
17677
19032
|
if (providerDir) {
|
|
17678
|
-
const fullDir =
|
|
17679
|
-
resolved._resolvedScriptsPath = fs7.existsSync(
|
|
19033
|
+
const fullDir = path17.join(providerDir, entry.scriptDir);
|
|
19034
|
+
resolved._resolvedScriptsPath = fs7.existsSync(path17.join(fullDir, "scripts.js")) ? path17.join(fullDir, "scripts.js") : fullDir;
|
|
17680
19035
|
}
|
|
17681
19036
|
matched = true;
|
|
17682
19037
|
}
|
|
@@ -17691,8 +19046,8 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
17691
19046
|
resolved._resolvedScriptDir = base.defaultScriptDir;
|
|
17692
19047
|
resolved._resolvedScriptsSource = "defaultScriptDir:version_miss";
|
|
17693
19048
|
if (providerDir) {
|
|
17694
|
-
const fullDir =
|
|
17695
|
-
resolved._resolvedScriptsPath = fs7.existsSync(
|
|
19049
|
+
const fullDir = path17.join(providerDir, base.defaultScriptDir);
|
|
19050
|
+
resolved._resolvedScriptsPath = fs7.existsSync(path17.join(fullDir, "scripts.js")) ? path17.join(fullDir, "scripts.js") : fullDir;
|
|
17696
19051
|
}
|
|
17697
19052
|
}
|
|
17698
19053
|
resolved._versionWarning = `Version ${currentVersion} not in compatibility matrix. Using default scripts.`;
|
|
@@ -17709,8 +19064,8 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
17709
19064
|
resolved._resolvedScriptDir = dirOverride;
|
|
17710
19065
|
resolved._resolvedScriptsSource = `versions:${range}`;
|
|
17711
19066
|
if (providerDir) {
|
|
17712
|
-
const fullDir =
|
|
17713
|
-
resolved._resolvedScriptsPath = fs7.existsSync(
|
|
19067
|
+
const fullDir = path17.join(providerDir, dirOverride);
|
|
19068
|
+
resolved._resolvedScriptsPath = fs7.existsSync(path17.join(fullDir, "scripts.js")) ? path17.join(fullDir, "scripts.js") : fullDir;
|
|
17714
19069
|
}
|
|
17715
19070
|
}
|
|
17716
19071
|
} else if (override.scripts) {
|
|
@@ -17726,8 +19081,8 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
17726
19081
|
resolved._resolvedScriptDir = base.defaultScriptDir;
|
|
17727
19082
|
resolved._resolvedScriptsSource = "defaultScriptDir:no_version";
|
|
17728
19083
|
if (providerDir) {
|
|
17729
|
-
const fullDir =
|
|
17730
|
-
resolved._resolvedScriptsPath = fs7.existsSync(
|
|
19084
|
+
const fullDir = path17.join(providerDir, base.defaultScriptDir);
|
|
19085
|
+
resolved._resolvedScriptsPath = fs7.existsSync(path17.join(fullDir, "scripts.js")) ? path17.join(fullDir, "scripts.js") : fullDir;
|
|
17731
19086
|
}
|
|
17732
19087
|
}
|
|
17733
19088
|
}
|
|
@@ -17759,14 +19114,14 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
17759
19114
|
this.log(` [loadScriptsFromDir] ${type}: providerDir not found`);
|
|
17760
19115
|
return null;
|
|
17761
19116
|
}
|
|
17762
|
-
const dir =
|
|
19117
|
+
const dir = path17.join(providerDir, scriptDir);
|
|
17763
19118
|
if (!fs7.existsSync(dir)) {
|
|
17764
19119
|
this.log(` [loadScriptsFromDir] ${type}: dir not found: ${dir}`);
|
|
17765
19120
|
return null;
|
|
17766
19121
|
}
|
|
17767
19122
|
const cached = this.scriptsCache.get(dir);
|
|
17768
19123
|
if (cached) return cached;
|
|
17769
|
-
const scriptsJs =
|
|
19124
|
+
const scriptsJs = path17.join(dir, "scripts.js");
|
|
17770
19125
|
if (fs7.existsSync(scriptsJs)) {
|
|
17771
19126
|
try {
|
|
17772
19127
|
delete require.cache[require.resolve(scriptsJs)];
|
|
@@ -17808,7 +19163,7 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
17808
19163
|
return;
|
|
17809
19164
|
}
|
|
17810
19165
|
if (filePath.endsWith(".js") || filePath.endsWith(".json")) {
|
|
17811
|
-
this.log(`File changed: ${
|
|
19166
|
+
this.log(`File changed: ${path17.basename(filePath)}, reloading...`);
|
|
17812
19167
|
this.reload();
|
|
17813
19168
|
}
|
|
17814
19169
|
};
|
|
@@ -17863,7 +19218,7 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
17863
19218
|
}
|
|
17864
19219
|
const https = require("https");
|
|
17865
19220
|
const { execSync: execSync7 } = require("child_process");
|
|
17866
|
-
const metaPath =
|
|
19221
|
+
const metaPath = path17.join(this.upstreamDir, _ProviderLoader.META_FILE);
|
|
17867
19222
|
let prevEtag = "";
|
|
17868
19223
|
let prevTimestamp = 0;
|
|
17869
19224
|
try {
|
|
@@ -17880,7 +19235,7 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
17880
19235
|
return { updated: false };
|
|
17881
19236
|
}
|
|
17882
19237
|
try {
|
|
17883
|
-
const etag = await new Promise((
|
|
19238
|
+
const etag = await new Promise((resolve15, reject) => {
|
|
17884
19239
|
const options = {
|
|
17885
19240
|
method: "HEAD",
|
|
17886
19241
|
hostname: "github.com",
|
|
@@ -17898,7 +19253,7 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
17898
19253
|
headers: { "User-Agent": "adhdev-launcher" },
|
|
17899
19254
|
timeout: 1e4
|
|
17900
19255
|
}, (res2) => {
|
|
17901
|
-
|
|
19256
|
+
resolve15(res2.headers.etag || res2.headers["last-modified"] || "");
|
|
17902
19257
|
});
|
|
17903
19258
|
req2.on("error", reject);
|
|
17904
19259
|
req2.on("timeout", () => {
|
|
@@ -17907,7 +19262,7 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
17907
19262
|
});
|
|
17908
19263
|
req2.end();
|
|
17909
19264
|
} else {
|
|
17910
|
-
|
|
19265
|
+
resolve15(res.headers.etag || res.headers["last-modified"] || "");
|
|
17911
19266
|
}
|
|
17912
19267
|
});
|
|
17913
19268
|
req.on("error", reject);
|
|
@@ -17923,17 +19278,17 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
17923
19278
|
return { updated: false };
|
|
17924
19279
|
}
|
|
17925
19280
|
this.log("Downloading latest providers from GitHub...");
|
|
17926
|
-
const tmpTar =
|
|
17927
|
-
const tmpExtract =
|
|
19281
|
+
const tmpTar = path17.join(os14.tmpdir(), `adhdev-providers-${Date.now()}.tar.gz`);
|
|
19282
|
+
const tmpExtract = path17.join(os14.tmpdir(), `adhdev-providers-extract-${Date.now()}`);
|
|
17928
19283
|
await this.downloadFile(_ProviderLoader.GITHUB_TARBALL_URL, tmpTar);
|
|
17929
19284
|
fs7.mkdirSync(tmpExtract, { recursive: true });
|
|
17930
19285
|
execSync7(`tar -xzf "${tmpTar}" -C "${tmpExtract}"`, { timeout: 3e4 });
|
|
17931
19286
|
const extracted = fs7.readdirSync(tmpExtract);
|
|
17932
19287
|
const rootDir = extracted.find(
|
|
17933
|
-
(d) => fs7.statSync(
|
|
19288
|
+
(d) => fs7.statSync(path17.join(tmpExtract, d)).isDirectory() && d.startsWith("adhdev-providers")
|
|
17934
19289
|
);
|
|
17935
19290
|
if (!rootDir) throw new Error("Unexpected tarball structure");
|
|
17936
|
-
const sourceDir =
|
|
19291
|
+
const sourceDir = path17.join(tmpExtract, rootDir);
|
|
17937
19292
|
const backupDir = this.upstreamDir + ".bak";
|
|
17938
19293
|
if (fs7.existsSync(this.upstreamDir)) {
|
|
17939
19294
|
if (fs7.existsSync(backupDir)) fs7.rmSync(backupDir, { recursive: true, force: true });
|
|
@@ -17971,7 +19326,7 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
17971
19326
|
downloadFile(url, destPath) {
|
|
17972
19327
|
const https = require("https");
|
|
17973
19328
|
const http3 = require("http");
|
|
17974
|
-
return new Promise((
|
|
19329
|
+
return new Promise((resolve15, reject) => {
|
|
17975
19330
|
const doRequest = (reqUrl, redirectCount = 0) => {
|
|
17976
19331
|
if (redirectCount > 5) {
|
|
17977
19332
|
reject(new Error("Too many redirects"));
|
|
@@ -17991,7 +19346,7 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
17991
19346
|
res.pipe(ws);
|
|
17992
19347
|
ws.on("finish", () => {
|
|
17993
19348
|
ws.close();
|
|
17994
|
-
|
|
19349
|
+
resolve15();
|
|
17995
19350
|
});
|
|
17996
19351
|
ws.on("error", reject);
|
|
17997
19352
|
});
|
|
@@ -18008,8 +19363,8 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
18008
19363
|
copyDirRecursive(src, dest) {
|
|
18009
19364
|
fs7.mkdirSync(dest, { recursive: true });
|
|
18010
19365
|
for (const entry of fs7.readdirSync(src, { withFileTypes: true })) {
|
|
18011
|
-
const srcPath =
|
|
18012
|
-
const destPath =
|
|
19366
|
+
const srcPath = path17.join(src, entry.name);
|
|
19367
|
+
const destPath = path17.join(dest, entry.name);
|
|
18013
19368
|
if (entry.isDirectory()) {
|
|
18014
19369
|
this.copyDirRecursive(srcPath, destPath);
|
|
18015
19370
|
} else {
|
|
@@ -18020,7 +19375,7 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
18020
19375
|
/** .meta.json save */
|
|
18021
19376
|
writeMeta(metaPath, etag, timestamp) {
|
|
18022
19377
|
try {
|
|
18023
|
-
fs7.mkdirSync(
|
|
19378
|
+
fs7.mkdirSync(path17.dirname(metaPath), { recursive: true });
|
|
18024
19379
|
fs7.writeFileSync(metaPath, JSON.stringify({
|
|
18025
19380
|
etag,
|
|
18026
19381
|
timestamp,
|
|
@@ -18037,7 +19392,7 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
18037
19392
|
const scan = (d) => {
|
|
18038
19393
|
try {
|
|
18039
19394
|
for (const entry of fs7.readdirSync(d, { withFileTypes: true })) {
|
|
18040
|
-
if (entry.isDirectory()) scan(
|
|
19395
|
+
if (entry.isDirectory()) scan(path17.join(d, entry.name));
|
|
18041
19396
|
else if (entry.name === "provider.json") count++;
|
|
18042
19397
|
}
|
|
18043
19398
|
} catch {
|
|
@@ -18265,17 +19620,17 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
18265
19620
|
for (const root of searchRoots) {
|
|
18266
19621
|
if (!fs7.existsSync(root)) continue;
|
|
18267
19622
|
const candidate = this.getProviderDir(root, cat, type);
|
|
18268
|
-
if (fs7.existsSync(
|
|
18269
|
-
const catDir =
|
|
19623
|
+
if (fs7.existsSync(path17.join(candidate, "provider.json"))) return candidate;
|
|
19624
|
+
const catDir = path17.join(root, cat);
|
|
18270
19625
|
if (fs7.existsSync(catDir)) {
|
|
18271
19626
|
try {
|
|
18272
19627
|
for (const entry of fs7.readdirSync(catDir, { withFileTypes: true })) {
|
|
18273
19628
|
if (!entry.isDirectory()) continue;
|
|
18274
|
-
const jsonPath =
|
|
19629
|
+
const jsonPath = path17.join(catDir, entry.name, "provider.json");
|
|
18275
19630
|
if (fs7.existsSync(jsonPath)) {
|
|
18276
19631
|
try {
|
|
18277
19632
|
const data = JSON.parse(fs7.readFileSync(jsonPath, "utf-8"));
|
|
18278
|
-
if (data.type === type) return
|
|
19633
|
+
if (data.type === type) return path17.join(catDir, entry.name);
|
|
18279
19634
|
} catch {
|
|
18280
19635
|
}
|
|
18281
19636
|
}
|
|
@@ -18292,7 +19647,7 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
18292
19647
|
* (template substitution is NOT applied here — scripts.js handles that)
|
|
18293
19648
|
*/
|
|
18294
19649
|
buildScriptWrappersFromDir(dir) {
|
|
18295
|
-
const scriptsJs =
|
|
19650
|
+
const scriptsJs = path17.join(dir, "scripts.js");
|
|
18296
19651
|
if (fs7.existsSync(scriptsJs)) {
|
|
18297
19652
|
try {
|
|
18298
19653
|
delete require.cache[require.resolve(scriptsJs)];
|
|
@@ -18306,7 +19661,7 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
18306
19661
|
for (const file of fs7.readdirSync(dir)) {
|
|
18307
19662
|
if (!file.endsWith(".js")) continue;
|
|
18308
19663
|
const scriptName = toCamel(file.replace(".js", ""));
|
|
18309
|
-
const filePath =
|
|
19664
|
+
const filePath = path17.join(dir, file);
|
|
18310
19665
|
result[scriptName] = (...args) => {
|
|
18311
19666
|
try {
|
|
18312
19667
|
let content = fs7.readFileSync(filePath, "utf-8");
|
|
@@ -18366,7 +19721,7 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
18366
19721
|
}
|
|
18367
19722
|
const hasJson = entries.some((e) => e.name === "provider.json");
|
|
18368
19723
|
if (hasJson) {
|
|
18369
|
-
const jsonPath =
|
|
19724
|
+
const jsonPath = path17.join(d, "provider.json");
|
|
18370
19725
|
try {
|
|
18371
19726
|
const raw = fs7.readFileSync(jsonPath, "utf-8");
|
|
18372
19727
|
const mod = JSON.parse(raw);
|
|
@@ -18387,7 +19742,7 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
18387
19742
|
this.log(`\u26A0 Invalid provider at ${jsonPath}: ${validation.errors.join("; ")}`);
|
|
18388
19743
|
} else {
|
|
18389
19744
|
const hasCompatibility = Array.isArray(normalizedProvider.compatibility);
|
|
18390
|
-
const scriptsPath =
|
|
19745
|
+
const scriptsPath = path17.join(d, "scripts.js");
|
|
18391
19746
|
if (!hasCompatibility && fs7.existsSync(scriptsPath)) {
|
|
18392
19747
|
try {
|
|
18393
19748
|
delete require.cache[require.resolve(scriptsPath)];
|
|
@@ -18413,7 +19768,7 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
18413
19768
|
if (!entry.isDirectory()) continue;
|
|
18414
19769
|
if (entry.name.startsWith("_") || entry.name.startsWith(".")) continue;
|
|
18415
19770
|
if (excludeDirs && d === dir && excludeDirs.includes(entry.name)) continue;
|
|
18416
|
-
scan(
|
|
19771
|
+
scan(path17.join(d, entry.name));
|
|
18417
19772
|
}
|
|
18418
19773
|
}
|
|
18419
19774
|
};
|
|
@@ -18448,9 +19803,9 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
18448
19803
|
}
|
|
18449
19804
|
}
|
|
18450
19805
|
compareVersions(a, b) {
|
|
18451
|
-
const
|
|
18452
|
-
const pa =
|
|
18453
|
-
const pb =
|
|
19806
|
+
const normalize4 = (v) => v.split(/[-_+]/)[0].split(".").map((x) => parseInt(x, 10) || 0);
|
|
19807
|
+
const pa = normalize4(a);
|
|
19808
|
+
const pb = normalize4(b);
|
|
18454
19809
|
for (let i = 0; i < Math.max(pa.length, pb.length); i++) {
|
|
18455
19810
|
const va = pa[i] || 0;
|
|
18456
19811
|
const vb = pb[i] || 0;
|
|
@@ -18570,17 +19925,17 @@ async function findFreePort(ports) {
|
|
|
18570
19925
|
throw new Error("No free port found");
|
|
18571
19926
|
}
|
|
18572
19927
|
function checkPortFree(port) {
|
|
18573
|
-
return new Promise((
|
|
19928
|
+
return new Promise((resolve15) => {
|
|
18574
19929
|
const server = net.createServer();
|
|
18575
19930
|
server.unref();
|
|
18576
|
-
server.on("error", () =>
|
|
19931
|
+
server.on("error", () => resolve15(false));
|
|
18577
19932
|
server.listen(port, "127.0.0.1", () => {
|
|
18578
|
-
server.close(() =>
|
|
19933
|
+
server.close(() => resolve15(true));
|
|
18579
19934
|
});
|
|
18580
19935
|
});
|
|
18581
19936
|
}
|
|
18582
19937
|
async function isCdpActive(port) {
|
|
18583
|
-
return new Promise((
|
|
19938
|
+
return new Promise((resolve15) => {
|
|
18584
19939
|
const req = require("http").get(`http://127.0.0.1:${port}/json/version`, {
|
|
18585
19940
|
timeout: 2e3
|
|
18586
19941
|
}, (res) => {
|
|
@@ -18589,16 +19944,16 @@ async function isCdpActive(port) {
|
|
|
18589
19944
|
res.on("end", () => {
|
|
18590
19945
|
try {
|
|
18591
19946
|
const info = JSON.parse(data);
|
|
18592
|
-
|
|
19947
|
+
resolve15(!!info["WebKit-Version"] || !!info["Browser"]);
|
|
18593
19948
|
} catch {
|
|
18594
|
-
|
|
19949
|
+
resolve15(false);
|
|
18595
19950
|
}
|
|
18596
19951
|
});
|
|
18597
19952
|
});
|
|
18598
|
-
req.on("error", () =>
|
|
19953
|
+
req.on("error", () => resolve15(false));
|
|
18599
19954
|
req.on("timeout", () => {
|
|
18600
19955
|
req.destroy();
|
|
18601
|
-
|
|
19956
|
+
resolve15(false);
|
|
18602
19957
|
});
|
|
18603
19958
|
});
|
|
18604
19959
|
}
|
|
@@ -18738,8 +20093,8 @@ function detectCurrentWorkspace(ideId) {
|
|
|
18738
20093
|
const appNameMap = getMacAppIdentifiers();
|
|
18739
20094
|
const appName = appNameMap[ideId];
|
|
18740
20095
|
if (appName) {
|
|
18741
|
-
const storagePath =
|
|
18742
|
-
process.env.APPDATA ||
|
|
20096
|
+
const storagePath = path18.join(
|
|
20097
|
+
process.env.APPDATA || path18.join(os15.homedir(), "AppData", "Roaming"),
|
|
18743
20098
|
appName,
|
|
18744
20099
|
"storage.json"
|
|
18745
20100
|
);
|
|
@@ -18917,9 +20272,9 @@ init_logger();
|
|
|
18917
20272
|
|
|
18918
20273
|
// src/logging/command-log.ts
|
|
18919
20274
|
var fs8 = __toESM(require("fs"));
|
|
18920
|
-
var
|
|
20275
|
+
var path19 = __toESM(require("path"));
|
|
18921
20276
|
var os16 = __toESM(require("os"));
|
|
18922
|
-
var LOG_DIR2 = process.platform === "win32" ?
|
|
20277
|
+
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");
|
|
18923
20278
|
var MAX_FILE_SIZE = 5 * 1024 * 1024;
|
|
18924
20279
|
var MAX_DAYS = 7;
|
|
18925
20280
|
try {
|
|
@@ -18957,13 +20312,13 @@ function getDateStr2() {
|
|
|
18957
20312
|
return (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
|
|
18958
20313
|
}
|
|
18959
20314
|
var currentDate2 = getDateStr2();
|
|
18960
|
-
var currentFile =
|
|
20315
|
+
var currentFile = path19.join(LOG_DIR2, `commands-${currentDate2}.jsonl`);
|
|
18961
20316
|
var writeCount2 = 0;
|
|
18962
20317
|
function checkRotation() {
|
|
18963
20318
|
const today = getDateStr2();
|
|
18964
20319
|
if (today !== currentDate2) {
|
|
18965
20320
|
currentDate2 = today;
|
|
18966
|
-
currentFile =
|
|
20321
|
+
currentFile = path19.join(LOG_DIR2, `commands-${currentDate2}.jsonl`);
|
|
18967
20322
|
cleanOldFiles();
|
|
18968
20323
|
}
|
|
18969
20324
|
}
|
|
@@ -18977,7 +20332,7 @@ function cleanOldFiles() {
|
|
|
18977
20332
|
const dateMatch = file.match(/commands-(\d{4}-\d{2}-\d{2})/);
|
|
18978
20333
|
if (dateMatch && dateMatch[1] < cutoffStr) {
|
|
18979
20334
|
try {
|
|
18980
|
-
fs8.unlinkSync(
|
|
20335
|
+
fs8.unlinkSync(path19.join(LOG_DIR2, file));
|
|
18981
20336
|
} catch {
|
|
18982
20337
|
}
|
|
18983
20338
|
}
|
|
@@ -18987,8 +20342,8 @@ function cleanOldFiles() {
|
|
|
18987
20342
|
}
|
|
18988
20343
|
function checkSize() {
|
|
18989
20344
|
try {
|
|
18990
|
-
const
|
|
18991
|
-
if (
|
|
20345
|
+
const stat2 = fs8.statSync(currentFile);
|
|
20346
|
+
if (stat2.size > MAX_FILE_SIZE) {
|
|
18992
20347
|
const backup = currentFile.replace(".jsonl", ".1.jsonl");
|
|
18993
20348
|
try {
|
|
18994
20349
|
fs8.unlinkSync(backup);
|
|
@@ -19274,12 +20629,18 @@ function buildStatusSnapshot(options) {
|
|
|
19274
20629
|
const unreadSourceSessions = buildSessionEntries(
|
|
19275
20630
|
options.allStates,
|
|
19276
20631
|
options.cdpManagers,
|
|
19277
|
-
{
|
|
20632
|
+
{
|
|
20633
|
+
profile: "full",
|
|
20634
|
+
getGitSummaryForWorkspace: options.getGitSummaryForWorkspace
|
|
20635
|
+
}
|
|
19278
20636
|
);
|
|
19279
20637
|
const sessions = profile === "full" ? unreadSourceSessions : profile === "live" ? unreadSourceSessions.map(projectLiveSessionFromFull) : buildSessionEntries(
|
|
19280
20638
|
options.allStates,
|
|
19281
20639
|
options.cdpManagers,
|
|
19282
|
-
{
|
|
20640
|
+
{
|
|
20641
|
+
profile,
|
|
20642
|
+
getGitSummaryForWorkspace: options.getGitSummaryForWorkspace
|
|
20643
|
+
}
|
|
19283
20644
|
);
|
|
19284
20645
|
const sessionsById = new Map(sessions.map((session) => [session.id, session]));
|
|
19285
20646
|
for (const sourceSession of unreadSourceSessions) {
|
|
@@ -19373,13 +20734,13 @@ var import_child_process8 = require("child_process");
|
|
|
19373
20734
|
var import_child_process9 = require("child_process");
|
|
19374
20735
|
var fs9 = __toESM(require("fs"));
|
|
19375
20736
|
var os18 = __toESM(require("os"));
|
|
19376
|
-
var
|
|
20737
|
+
var path20 = __toESM(require("path"));
|
|
19377
20738
|
var UPGRADE_HELPER_ENV = "ADHDEV_DAEMON_UPGRADE_HELPER";
|
|
19378
20739
|
function getUpgradeLogPath() {
|
|
19379
20740
|
const home = os18.homedir();
|
|
19380
|
-
const dir =
|
|
20741
|
+
const dir = path20.join(home, ".adhdev");
|
|
19381
20742
|
fs9.mkdirSync(dir, { recursive: true });
|
|
19382
|
-
return
|
|
20743
|
+
return path20.join(dir, "daemon-upgrade.log");
|
|
19383
20744
|
}
|
|
19384
20745
|
function appendUpgradeLog(message) {
|
|
19385
20746
|
const line = `[${(/* @__PURE__ */ new Date()).toISOString()}] ${message}
|
|
@@ -19390,14 +20751,14 @@ function appendUpgradeLog(message) {
|
|
|
19390
20751
|
}
|
|
19391
20752
|
}
|
|
19392
20753
|
function resolveSiblingNpmInvocation(nodeExecutable, platform10 = process.platform) {
|
|
19393
|
-
const binDir =
|
|
20754
|
+
const binDir = path20.dirname(nodeExecutable);
|
|
19394
20755
|
if (platform10 === "win32") {
|
|
19395
|
-
const npmCliPath =
|
|
20756
|
+
const npmCliPath = path20.join(binDir, "node_modules", "npm", "bin", "npm-cli.js");
|
|
19396
20757
|
if (fs9.existsSync(npmCliPath)) {
|
|
19397
20758
|
return { executable: nodeExecutable, argsPrefix: [npmCliPath], execOptions: getNpmExecOptions(platform10) };
|
|
19398
20759
|
}
|
|
19399
20760
|
for (const candidate of ["npm.exe", "npm"]) {
|
|
19400
|
-
const candidatePath =
|
|
20761
|
+
const candidatePath = path20.join(binDir, candidate);
|
|
19401
20762
|
if (fs9.existsSync(candidatePath)) {
|
|
19402
20763
|
return { executable: candidatePath, argsPrefix: [], execOptions: getNpmExecOptions(platform10) };
|
|
19403
20764
|
}
|
|
@@ -19405,7 +20766,7 @@ function resolveSiblingNpmInvocation(nodeExecutable, platform10 = process.platfo
|
|
|
19405
20766
|
return { executable: nodeExecutable, argsPrefix: [npmCliPath], execOptions: getNpmExecOptions(platform10) };
|
|
19406
20767
|
}
|
|
19407
20768
|
for (const candidate of ["npm"]) {
|
|
19408
|
-
const candidatePath =
|
|
20769
|
+
const candidatePath = path20.join(binDir, candidate);
|
|
19409
20770
|
if (fs9.existsSync(candidatePath)) {
|
|
19410
20771
|
return { executable: candidatePath, argsPrefix: [], execOptions: getNpmExecOptions(platform10) };
|
|
19411
20772
|
}
|
|
@@ -19422,13 +20783,13 @@ function findCurrentPackageRoot(currentCliPath, packageName) {
|
|
|
19422
20783
|
let currentDir = resolvedPath;
|
|
19423
20784
|
try {
|
|
19424
20785
|
if (fs9.statSync(resolvedPath).isFile()) {
|
|
19425
|
-
currentDir =
|
|
20786
|
+
currentDir = path20.dirname(resolvedPath);
|
|
19426
20787
|
}
|
|
19427
20788
|
} catch {
|
|
19428
|
-
currentDir =
|
|
20789
|
+
currentDir = path20.dirname(resolvedPath);
|
|
19429
20790
|
}
|
|
19430
20791
|
while (true) {
|
|
19431
|
-
const packageJsonPath =
|
|
20792
|
+
const packageJsonPath = path20.join(currentDir, "package.json");
|
|
19432
20793
|
try {
|
|
19433
20794
|
if (fs9.existsSync(packageJsonPath)) {
|
|
19434
20795
|
const parsed = JSON.parse(fs9.readFileSync(packageJsonPath, "utf8"));
|
|
@@ -19439,7 +20800,7 @@ function findCurrentPackageRoot(currentCliPath, packageName) {
|
|
|
19439
20800
|
}
|
|
19440
20801
|
} catch {
|
|
19441
20802
|
}
|
|
19442
|
-
const parentDir =
|
|
20803
|
+
const parentDir = path20.dirname(currentDir);
|
|
19443
20804
|
if (parentDir === currentDir) {
|
|
19444
20805
|
return null;
|
|
19445
20806
|
}
|
|
@@ -19447,13 +20808,13 @@ function findCurrentPackageRoot(currentCliPath, packageName) {
|
|
|
19447
20808
|
}
|
|
19448
20809
|
}
|
|
19449
20810
|
function resolveInstallPrefixFromPackageRoot(packageRoot, packageName) {
|
|
19450
|
-
const nodeModulesDir = packageName.startsWith("@") ?
|
|
19451
|
-
if (
|
|
20811
|
+
const nodeModulesDir = packageName.startsWith("@") ? path20.dirname(path20.dirname(packageRoot)) : path20.dirname(packageRoot);
|
|
20812
|
+
if (path20.basename(nodeModulesDir) !== "node_modules") {
|
|
19452
20813
|
return null;
|
|
19453
20814
|
}
|
|
19454
|
-
const maybeLibDir =
|
|
19455
|
-
if (
|
|
19456
|
-
return
|
|
20815
|
+
const maybeLibDir = path20.dirname(nodeModulesDir);
|
|
20816
|
+
if (path20.basename(maybeLibDir) === "lib") {
|
|
20817
|
+
return path20.dirname(maybeLibDir);
|
|
19457
20818
|
}
|
|
19458
20819
|
return maybeLibDir;
|
|
19459
20820
|
}
|
|
@@ -19561,14 +20922,14 @@ async function waitForPidExit(pid, timeoutMs) {
|
|
|
19561
20922
|
while (Date.now() - start < timeoutMs) {
|
|
19562
20923
|
try {
|
|
19563
20924
|
process.kill(pid, 0);
|
|
19564
|
-
await new Promise((
|
|
20925
|
+
await new Promise((resolve15) => setTimeout(resolve15, 250));
|
|
19565
20926
|
} catch {
|
|
19566
20927
|
return;
|
|
19567
20928
|
}
|
|
19568
20929
|
}
|
|
19569
20930
|
}
|
|
19570
20931
|
function stopSessionHostProcesses(appName) {
|
|
19571
|
-
const pidFile =
|
|
20932
|
+
const pidFile = path20.join(os18.homedir(), ".adhdev", `${appName}-session-host.pid`);
|
|
19572
20933
|
try {
|
|
19573
20934
|
if (fs9.existsSync(pidFile)) {
|
|
19574
20935
|
const pid = Number.parseInt(fs9.readFileSync(pidFile, "utf8").trim(), 10);
|
|
@@ -19585,7 +20946,7 @@ function stopSessionHostProcesses(appName) {
|
|
|
19585
20946
|
}
|
|
19586
20947
|
}
|
|
19587
20948
|
function removeDaemonPidFile() {
|
|
19588
|
-
const pidFile =
|
|
20949
|
+
const pidFile = path20.join(os18.homedir(), ".adhdev", "daemon.pid");
|
|
19589
20950
|
try {
|
|
19590
20951
|
fs9.unlinkSync(pidFile);
|
|
19591
20952
|
} catch {
|
|
@@ -19596,7 +20957,7 @@ function cleanupStaleGlobalInstallDirs(pkgName, surface) {
|
|
|
19596
20957
|
const npmRoot = String(execNpmCommandSync(["root", "-g", ...prefixArgs], { encoding: "utf8" }, surface)).trim();
|
|
19597
20958
|
if (!npmRoot) return;
|
|
19598
20959
|
const npmPrefix = surface.installPrefix || String(execNpmCommandSync(["prefix", "-g", ...prefixArgs], { encoding: "utf8" }, surface)).trim();
|
|
19599
|
-
const binDir = process.platform === "win32" ? npmPrefix :
|
|
20960
|
+
const binDir = process.platform === "win32" ? npmPrefix : path20.join(npmPrefix, "bin");
|
|
19600
20961
|
const packageBaseName = pkgName.startsWith("@") ? pkgName.split("/")[1] : pkgName;
|
|
19601
20962
|
const binNames = /* @__PURE__ */ new Set([packageBaseName]);
|
|
19602
20963
|
if (pkgName === "@adhdev/daemon-standalone") {
|
|
@@ -19604,25 +20965,25 @@ function cleanupStaleGlobalInstallDirs(pkgName, surface) {
|
|
|
19604
20965
|
}
|
|
19605
20966
|
if (pkgName.startsWith("@")) {
|
|
19606
20967
|
const [scope, name] = pkgName.split("/");
|
|
19607
|
-
const scopeDir =
|
|
20968
|
+
const scopeDir = path20.join(npmRoot, scope);
|
|
19608
20969
|
if (!fs9.existsSync(scopeDir)) return;
|
|
19609
20970
|
for (const entry of fs9.readdirSync(scopeDir)) {
|
|
19610
20971
|
if (!entry.startsWith(`.${name}-`)) continue;
|
|
19611
|
-
fs9.rmSync(
|
|
19612
|
-
appendUpgradeLog(`Removed stale scoped staging dir: ${
|
|
20972
|
+
fs9.rmSync(path20.join(scopeDir, entry), { recursive: true, force: true });
|
|
20973
|
+
appendUpgradeLog(`Removed stale scoped staging dir: ${path20.join(scopeDir, entry)}`);
|
|
19613
20974
|
}
|
|
19614
20975
|
} else {
|
|
19615
20976
|
for (const entry of fs9.readdirSync(npmRoot)) {
|
|
19616
20977
|
if (!entry.startsWith(`.${pkgName}-`)) continue;
|
|
19617
|
-
fs9.rmSync(
|
|
19618
|
-
appendUpgradeLog(`Removed stale staging dir: ${
|
|
20978
|
+
fs9.rmSync(path20.join(npmRoot, entry), { recursive: true, force: true });
|
|
20979
|
+
appendUpgradeLog(`Removed stale staging dir: ${path20.join(npmRoot, entry)}`);
|
|
19619
20980
|
}
|
|
19620
20981
|
}
|
|
19621
20982
|
if (fs9.existsSync(binDir)) {
|
|
19622
20983
|
for (const entry of fs9.readdirSync(binDir)) {
|
|
19623
20984
|
if (!Array.from(binNames).some((name) => entry.startsWith(`.${name}-`))) continue;
|
|
19624
|
-
fs9.rmSync(
|
|
19625
|
-
appendUpgradeLog(`Removed stale bin staging entry: ${
|
|
20985
|
+
fs9.rmSync(path20.join(binDir, entry), { recursive: true, force: true });
|
|
20986
|
+
appendUpgradeLog(`Removed stale bin staging entry: ${path20.join(binDir, entry)}`);
|
|
19626
20987
|
}
|
|
19627
20988
|
}
|
|
19628
20989
|
}
|
|
@@ -19672,7 +21033,7 @@ async function runDaemonUpgradeHelper(payload) {
|
|
|
19672
21033
|
appendUpgradeLog(installOutput.trim());
|
|
19673
21034
|
}
|
|
19674
21035
|
if (process.platform === "win32") {
|
|
19675
|
-
await new Promise((
|
|
21036
|
+
await new Promise((resolve15) => setTimeout(resolve15, 500));
|
|
19676
21037
|
cleanupStaleGlobalInstallDirs(payload.packageName, installCommand.surface);
|
|
19677
21038
|
appendUpgradeLog("Post-install staging cleanup complete");
|
|
19678
21039
|
}
|
|
@@ -21066,7 +22427,7 @@ var ProviderStreamAdapter = class {
|
|
|
21066
22427
|
const beforeCount = this.messageCount(before);
|
|
21067
22428
|
const beforeSignature = this.lastMessageSignature(before);
|
|
21068
22429
|
for (let attempt = 0; attempt < 12; attempt += 1) {
|
|
21069
|
-
await new Promise((
|
|
22430
|
+
await new Promise((resolve15) => setTimeout(resolve15, 250));
|
|
21070
22431
|
let state;
|
|
21071
22432
|
try {
|
|
21072
22433
|
state = await this.readChat(evaluate);
|
|
@@ -21088,7 +22449,7 @@ var ProviderStreamAdapter = class {
|
|
|
21088
22449
|
if (this.messageCount(first) > 0 || this.lastMessageSignature(first)) {
|
|
21089
22450
|
return first;
|
|
21090
22451
|
}
|
|
21091
|
-
await new Promise((
|
|
22452
|
+
await new Promise((resolve15) => setTimeout(resolve15, 150));
|
|
21092
22453
|
const second = await this.readChat(evaluate);
|
|
21093
22454
|
return this.messageCount(second) >= this.messageCount(first) ? second : first;
|
|
21094
22455
|
}
|
|
@@ -21239,7 +22600,7 @@ var ProviderStreamAdapter = class {
|
|
|
21239
22600
|
if (typeof data.error === "string" && data.error.trim()) return false;
|
|
21240
22601
|
}
|
|
21241
22602
|
for (let attempt = 0; attempt < 6; attempt += 1) {
|
|
21242
|
-
await new Promise((
|
|
22603
|
+
await new Promise((resolve15) => setTimeout(resolve15, 250));
|
|
21243
22604
|
const state = await this.readChat(evaluate);
|
|
21244
22605
|
const title = this.getStateTitle(state);
|
|
21245
22606
|
if (this.titlesMatch(title, sessionId)) return true;
|
|
@@ -22100,11 +23461,11 @@ init_chat_message_normalization();
|
|
|
22100
23461
|
|
|
22101
23462
|
// src/providers/version-archive.ts
|
|
22102
23463
|
var fs11 = __toESM(require("fs"));
|
|
22103
|
-
var
|
|
23464
|
+
var path21 = __toESM(require("path"));
|
|
22104
23465
|
var os19 = __toESM(require("os"));
|
|
22105
23466
|
var import_child_process10 = require("child_process");
|
|
22106
23467
|
var import_os3 = require("os");
|
|
22107
|
-
var ARCHIVE_PATH =
|
|
23468
|
+
var ARCHIVE_PATH = path21.join(os19.homedir(), ".adhdev", "version-history.json");
|
|
22108
23469
|
var MAX_ENTRIES_PER_PROVIDER = 20;
|
|
22109
23470
|
var VersionArchive = class {
|
|
22110
23471
|
history = {};
|
|
@@ -22151,7 +23512,7 @@ var VersionArchive = class {
|
|
|
22151
23512
|
}
|
|
22152
23513
|
save() {
|
|
22153
23514
|
try {
|
|
22154
|
-
fs11.mkdirSync(
|
|
23515
|
+
fs11.mkdirSync(path21.dirname(ARCHIVE_PATH), { recursive: true });
|
|
22155
23516
|
fs11.writeFileSync(ARCHIVE_PATH, JSON.stringify(this.history, null, 2));
|
|
22156
23517
|
} catch {
|
|
22157
23518
|
}
|
|
@@ -22208,7 +23569,7 @@ function checkPathExists2(paths) {
|
|
|
22208
23569
|
for (const p of paths) {
|
|
22209
23570
|
if (p.includes("*")) {
|
|
22210
23571
|
const home = os19.homedir();
|
|
22211
|
-
const resolved = p.replace(/\*/g, home.split(
|
|
23572
|
+
const resolved = p.replace(/\*/g, home.split(path21.sep).pop() || "");
|
|
22212
23573
|
if (fs11.existsSync(resolved)) return resolved;
|
|
22213
23574
|
} else {
|
|
22214
23575
|
if (fs11.existsSync(p)) return p;
|
|
@@ -22218,7 +23579,7 @@ function checkPathExists2(paths) {
|
|
|
22218
23579
|
}
|
|
22219
23580
|
function getMacAppVersion(appPath) {
|
|
22220
23581
|
if ((0, import_os3.platform)() !== "darwin" || !appPath.endsWith(".app")) return null;
|
|
22221
|
-
const plistPath =
|
|
23582
|
+
const plistPath = path21.join(appPath, "Contents", "Info.plist");
|
|
22222
23583
|
if (!fs11.existsSync(plistPath)) return null;
|
|
22223
23584
|
const raw = runCommand(`/usr/libexec/PlistBuddy -c "Print CFBundleShortVersionString" "${plistPath}"`);
|
|
22224
23585
|
return raw || null;
|
|
@@ -22244,7 +23605,7 @@ async function detectAllVersions(loader, archive) {
|
|
|
22244
23605
|
const cliBin = provider.cli ? findBinary2(provider.cli) : null;
|
|
22245
23606
|
let resolvedBin = cliBin;
|
|
22246
23607
|
if (!resolvedBin && appPath && currentOs === "darwin") {
|
|
22247
|
-
const bundled =
|
|
23608
|
+
const bundled = path21.join(appPath, "Contents", "Resources", "app", "bin", provider.cli || "");
|
|
22248
23609
|
if (provider.cli && fs11.existsSync(bundled)) resolvedBin = bundled;
|
|
22249
23610
|
}
|
|
22250
23611
|
info.installed = !!(appPath || resolvedBin);
|
|
@@ -22285,7 +23646,7 @@ async function detectAllVersions(loader, archive) {
|
|
|
22285
23646
|
// src/daemon/dev-server.ts
|
|
22286
23647
|
var http2 = __toESM(require("http"));
|
|
22287
23648
|
var fs15 = __toESM(require("fs"));
|
|
22288
|
-
var
|
|
23649
|
+
var path25 = __toESM(require("path"));
|
|
22289
23650
|
init_config();
|
|
22290
23651
|
|
|
22291
23652
|
// src/daemon/scaffold-template.ts
|
|
@@ -22636,7 +23997,7 @@ init_logger();
|
|
|
22636
23997
|
|
|
22637
23998
|
// src/daemon/dev-cdp-handlers.ts
|
|
22638
23999
|
var fs12 = __toESM(require("fs"));
|
|
22639
|
-
var
|
|
24000
|
+
var path22 = __toESM(require("path"));
|
|
22640
24001
|
init_logger();
|
|
22641
24002
|
async function handleCdpEvaluate(ctx, req, res) {
|
|
22642
24003
|
const body = await ctx.readBody(req);
|
|
@@ -22815,17 +24176,17 @@ async function handleScriptHints(ctx, type, _req, res) {
|
|
|
22815
24176
|
return;
|
|
22816
24177
|
}
|
|
22817
24178
|
let scriptsPath = "";
|
|
22818
|
-
const directScripts =
|
|
24179
|
+
const directScripts = path22.join(dir, "scripts.js");
|
|
22819
24180
|
if (fs12.existsSync(directScripts)) {
|
|
22820
24181
|
scriptsPath = directScripts;
|
|
22821
24182
|
} else {
|
|
22822
|
-
const scriptsDir =
|
|
24183
|
+
const scriptsDir = path22.join(dir, "scripts");
|
|
22823
24184
|
if (fs12.existsSync(scriptsDir)) {
|
|
22824
24185
|
const versions = fs12.readdirSync(scriptsDir).filter((d) => {
|
|
22825
|
-
return fs12.statSync(
|
|
24186
|
+
return fs12.statSync(path22.join(scriptsDir, d)).isDirectory();
|
|
22826
24187
|
}).sort().reverse();
|
|
22827
24188
|
for (const ver of versions) {
|
|
22828
|
-
const p =
|
|
24189
|
+
const p = path22.join(scriptsDir, ver, "scripts.js");
|
|
22829
24190
|
if (fs12.existsSync(p)) {
|
|
22830
24191
|
scriptsPath = p;
|
|
22831
24192
|
break;
|
|
@@ -23654,7 +25015,7 @@ async function handleDomContext(ctx, type, req, res) {
|
|
|
23654
25015
|
|
|
23655
25016
|
// src/daemon/dev-cli-debug.ts
|
|
23656
25017
|
var fs13 = __toESM(require("fs"));
|
|
23657
|
-
var
|
|
25018
|
+
var path23 = __toESM(require("path"));
|
|
23658
25019
|
function slugifyFixtureName(value) {
|
|
23659
25020
|
const normalized = String(value || "").trim().toLowerCase().replace(/[^a-z0-9._-]+/g, "-").replace(/^-+|-+$/g, "");
|
|
23660
25021
|
return normalized || `fixture-${Date.now()}`;
|
|
@@ -23664,11 +25025,11 @@ function getCliFixtureDir(ctx, type) {
|
|
|
23664
25025
|
if (!providerDir) {
|
|
23665
25026
|
throw new Error(`Provider directory not found for '${type}'`);
|
|
23666
25027
|
}
|
|
23667
|
-
return
|
|
25028
|
+
return path23.join(providerDir, "fixtures");
|
|
23668
25029
|
}
|
|
23669
25030
|
function readCliFixture(ctx, type, name) {
|
|
23670
25031
|
const fixtureDir = getCliFixtureDir(ctx, type);
|
|
23671
|
-
const filePath =
|
|
25032
|
+
const filePath = path23.join(fixtureDir, `${name}.json`);
|
|
23672
25033
|
if (!fs13.existsSync(filePath)) {
|
|
23673
25034
|
throw new Error(`Fixture not found: ${filePath}`);
|
|
23674
25035
|
}
|
|
@@ -23837,7 +25198,7 @@ function getCliTargetBundle(ctx, type, instanceId) {
|
|
|
23837
25198
|
return { target, instance, adapter };
|
|
23838
25199
|
}
|
|
23839
25200
|
function sleep(ms) {
|
|
23840
|
-
return new Promise((
|
|
25201
|
+
return new Promise((resolve15) => setTimeout(resolve15, ms));
|
|
23841
25202
|
}
|
|
23842
25203
|
async function waitForCliReady(ctx, type, instanceId, timeoutMs) {
|
|
23843
25204
|
const startedAt = Date.now();
|
|
@@ -24135,7 +25496,7 @@ async function runCliAutoImplVerification(ctx, type, verification) {
|
|
|
24135
25496
|
return {
|
|
24136
25497
|
mode: "fixture_replay_suite",
|
|
24137
25498
|
pass: results.every((item) => item.pass),
|
|
24138
|
-
failures: results.flatMap((item) => item.failures.map((
|
|
25499
|
+
failures: results.flatMap((item) => item.failures.map((failure2) => `${item.fixtureName}: ${failure2}`)),
|
|
24139
25500
|
result: firstFailure.result,
|
|
24140
25501
|
assertions: firstFailure.assertions,
|
|
24141
25502
|
fixture: firstFailure.fixture,
|
|
@@ -24435,7 +25796,7 @@ async function handleCliFixtureCapture(ctx, req, res) {
|
|
|
24435
25796
|
},
|
|
24436
25797
|
notes: typeof body?.notes === "string" ? body.notes : void 0
|
|
24437
25798
|
};
|
|
24438
|
-
const filePath =
|
|
25799
|
+
const filePath = path23.join(fixtureDir, `${name}.json`);
|
|
24439
25800
|
fs13.writeFileSync(filePath, JSON.stringify(fixture, null, 2));
|
|
24440
25801
|
ctx.json(res, 200, {
|
|
24441
25802
|
saved: true,
|
|
@@ -24459,7 +25820,7 @@ async function handleCliFixtureList(ctx, type, _req, res) {
|
|
|
24459
25820
|
return;
|
|
24460
25821
|
}
|
|
24461
25822
|
const fixtures = fs13.readdirSync(fixtureDir).filter((file) => file.endsWith(".json")).sort((a, b) => b.localeCompare(a, void 0, { numeric: true, sensitivity: "base" })).map((file) => {
|
|
24462
|
-
const fullPath =
|
|
25823
|
+
const fullPath = path23.join(fixtureDir, file);
|
|
24463
25824
|
try {
|
|
24464
25825
|
const raw = JSON.parse(fs13.readFileSync(fullPath, "utf-8"));
|
|
24465
25826
|
return {
|
|
@@ -24595,7 +25956,7 @@ async function handleCliRaw(ctx, req, res) {
|
|
|
24595
25956
|
|
|
24596
25957
|
// src/daemon/dev-auto-implement.ts
|
|
24597
25958
|
var fs14 = __toESM(require("fs"));
|
|
24598
|
-
var
|
|
25959
|
+
var path24 = __toESM(require("path"));
|
|
24599
25960
|
var os20 = __toESM(require("os"));
|
|
24600
25961
|
function getAutoImplPid(ctx) {
|
|
24601
25962
|
const pid = ctx.autoImplProcess?.pid;
|
|
@@ -24645,22 +26006,22 @@ function getLatestScriptVersionDir(scriptsDir) {
|
|
|
24645
26006
|
if (!fs14.existsSync(scriptsDir)) return null;
|
|
24646
26007
|
const versions = fs14.readdirSync(scriptsDir).filter((d) => {
|
|
24647
26008
|
try {
|
|
24648
|
-
return fs14.statSync(
|
|
26009
|
+
return fs14.statSync(path24.join(scriptsDir, d)).isDirectory();
|
|
24649
26010
|
} catch {
|
|
24650
26011
|
return false;
|
|
24651
26012
|
}
|
|
24652
26013
|
}).sort((a, b) => b.localeCompare(a, void 0, { numeric: true, sensitivity: "base" }));
|
|
24653
26014
|
if (versions.length === 0) return null;
|
|
24654
|
-
return
|
|
26015
|
+
return path24.join(scriptsDir, versions[0]);
|
|
24655
26016
|
}
|
|
24656
26017
|
function resolveAutoImplWritableProviderDir(ctx, category, type, requestedDir) {
|
|
24657
|
-
const canonicalUserDir =
|
|
24658
|
-
const desiredDir = requestedDir ?
|
|
24659
|
-
const upstreamRoot =
|
|
24660
|
-
if (desiredDir === upstreamRoot || desiredDir.startsWith(`${upstreamRoot}${
|
|
26018
|
+
const canonicalUserDir = path24.resolve(ctx.providerLoader.getUserProviderDir(category, type));
|
|
26019
|
+
const desiredDir = requestedDir ? path24.resolve(requestedDir) : canonicalUserDir;
|
|
26020
|
+
const upstreamRoot = path24.resolve(ctx.providerLoader.getUpstreamDir());
|
|
26021
|
+
if (desiredDir === upstreamRoot || desiredDir.startsWith(`${upstreamRoot}${path24.sep}`)) {
|
|
24661
26022
|
return { dir: null, reason: `Refusing to write into upstream provider directory: ${desiredDir}` };
|
|
24662
26023
|
}
|
|
24663
|
-
if (
|
|
26024
|
+
if (path24.basename(desiredDir) !== type) {
|
|
24664
26025
|
return { dir: null, reason: `Requested writable provider directory must end with '${type}': ${desiredDir}` };
|
|
24665
26026
|
}
|
|
24666
26027
|
const sourceDir = ctx.findProviderDir(type);
|
|
@@ -24668,11 +26029,11 @@ function resolveAutoImplWritableProviderDir(ctx, category, type, requestedDir) {
|
|
|
24668
26029
|
return { dir: null, reason: `Provider source directory not found for '${type}'` };
|
|
24669
26030
|
}
|
|
24670
26031
|
if (!fs14.existsSync(desiredDir)) {
|
|
24671
|
-
fs14.mkdirSync(
|
|
26032
|
+
fs14.mkdirSync(path24.dirname(desiredDir), { recursive: true });
|
|
24672
26033
|
fs14.cpSync(sourceDir, desiredDir, { recursive: true });
|
|
24673
26034
|
ctx.log(`Auto-implement writable copy created: ${desiredDir}`);
|
|
24674
26035
|
}
|
|
24675
|
-
const providerJson =
|
|
26036
|
+
const providerJson = path24.join(desiredDir, "provider.json");
|
|
24676
26037
|
if (!fs14.existsSync(providerJson)) {
|
|
24677
26038
|
return { dir: null, reason: `provider.json not found in writable provider directory: ${desiredDir}` };
|
|
24678
26039
|
}
|
|
@@ -24683,13 +26044,13 @@ function loadAutoImplReferenceScripts(ctx, referenceType) {
|
|
|
24683
26044
|
const refDir = ctx.findProviderDir(referenceType);
|
|
24684
26045
|
if (!refDir || !fs14.existsSync(refDir)) return {};
|
|
24685
26046
|
const referenceScripts = {};
|
|
24686
|
-
const scriptsDir =
|
|
26047
|
+
const scriptsDir = path24.join(refDir, "scripts");
|
|
24687
26048
|
const latestDir = getLatestScriptVersionDir(scriptsDir);
|
|
24688
26049
|
if (!latestDir) return referenceScripts;
|
|
24689
26050
|
for (const file of fs14.readdirSync(latestDir)) {
|
|
24690
26051
|
if (!file.endsWith(".js")) continue;
|
|
24691
26052
|
try {
|
|
24692
|
-
referenceScripts[file] = fs14.readFileSync(
|
|
26053
|
+
referenceScripts[file] = fs14.readFileSync(path24.join(latestDir, file), "utf-8");
|
|
24693
26054
|
} catch {
|
|
24694
26055
|
}
|
|
24695
26056
|
}
|
|
@@ -24797,9 +26158,9 @@ async function handleAutoImplement(ctx, type, req, res) {
|
|
|
24797
26158
|
});
|
|
24798
26159
|
const referenceScripts = loadAutoImplReferenceScripts(ctx, resolvedReference);
|
|
24799
26160
|
const prompt = buildAutoImplPrompt(ctx, type, provider, providerDir, functions, domContext, referenceScripts, comment, resolvedReference, verification);
|
|
24800
|
-
const tmpDir =
|
|
26161
|
+
const tmpDir = path24.join(os20.tmpdir(), "adhdev-autoimpl");
|
|
24801
26162
|
if (!fs14.existsSync(tmpDir)) fs14.mkdirSync(tmpDir, { recursive: true });
|
|
24802
|
-
const promptFile =
|
|
26163
|
+
const promptFile = path24.join(tmpDir, `prompt-${type}-${Date.now()}.md`);
|
|
24803
26164
|
fs14.writeFileSync(promptFile, prompt, "utf-8");
|
|
24804
26165
|
ctx.log(`Auto-implement prompt written to ${promptFile} (${prompt.length} chars)`);
|
|
24805
26166
|
const agentProvider = ctx.providerLoader.resolve(agent) || ctx.providerLoader.getMeta(agent);
|
|
@@ -25231,7 +26592,7 @@ function buildAutoImplPrompt(ctx, type, provider, providerDir, functions, domCon
|
|
|
25231
26592
|
setMode: "set_mode.js"
|
|
25232
26593
|
};
|
|
25233
26594
|
const targetFileNames = new Set(functions.map((fn) => funcToFile[fn]).filter(Boolean));
|
|
25234
|
-
const scriptsDir =
|
|
26595
|
+
const scriptsDir = path24.join(providerDir, "scripts");
|
|
25235
26596
|
const latestScriptsDir = getLatestScriptVersionDir(scriptsDir);
|
|
25236
26597
|
if (latestScriptsDir) {
|
|
25237
26598
|
lines.push(`Scripts version directory: \`${latestScriptsDir}\``);
|
|
@@ -25242,7 +26603,7 @@ function buildAutoImplPrompt(ctx, type, provider, providerDir, functions, domCon
|
|
|
25242
26603
|
for (const file of fs14.readdirSync(latestScriptsDir)) {
|
|
25243
26604
|
if (file.endsWith(".js") && targetFileNames.has(file)) {
|
|
25244
26605
|
try {
|
|
25245
|
-
const content = fs14.readFileSync(
|
|
26606
|
+
const content = fs14.readFileSync(path24.join(latestScriptsDir, file), "utf-8");
|
|
25246
26607
|
lines.push(`### \`${file}\` \u270F\uFE0F EDIT`);
|
|
25247
26608
|
lines.push("```javascript");
|
|
25248
26609
|
lines.push(content);
|
|
@@ -25259,7 +26620,7 @@ function buildAutoImplPrompt(ctx, type, provider, providerDir, functions, domCon
|
|
|
25259
26620
|
lines.push("");
|
|
25260
26621
|
for (const file of refFiles) {
|
|
25261
26622
|
try {
|
|
25262
|
-
const content = fs14.readFileSync(
|
|
26623
|
+
const content = fs14.readFileSync(path24.join(latestScriptsDir, file), "utf-8");
|
|
25263
26624
|
lines.push(`### \`${file}\` \u{1F512}`);
|
|
25264
26625
|
lines.push("```javascript");
|
|
25265
26626
|
lines.push(content);
|
|
@@ -25300,10 +26661,10 @@ function buildAutoImplPrompt(ctx, type, provider, providerDir, functions, domCon
|
|
|
25300
26661
|
lines.push("");
|
|
25301
26662
|
}
|
|
25302
26663
|
}
|
|
25303
|
-
const docsDir =
|
|
26664
|
+
const docsDir = path24.join(providerDir, "../../docs");
|
|
25304
26665
|
const loadGuide = (name) => {
|
|
25305
26666
|
try {
|
|
25306
|
-
const p =
|
|
26667
|
+
const p = path24.join(docsDir, name);
|
|
25307
26668
|
if (fs14.existsSync(p)) return fs14.readFileSync(p, "utf-8");
|
|
25308
26669
|
} catch {
|
|
25309
26670
|
}
|
|
@@ -25540,7 +26901,7 @@ function buildCliAutoImplPrompt(ctx, type, provider, providerDir, functions, ref
|
|
|
25540
26901
|
parseApproval: "parse_approval.js"
|
|
25541
26902
|
};
|
|
25542
26903
|
const targetFileNames = new Set(functions.map((fn) => funcToFile[fn]).filter(Boolean));
|
|
25543
|
-
const scriptsDir =
|
|
26904
|
+
const scriptsDir = path24.join(providerDir, "scripts");
|
|
25544
26905
|
const latestScriptsDir = getLatestScriptVersionDir(scriptsDir);
|
|
25545
26906
|
if (latestScriptsDir) {
|
|
25546
26907
|
lines.push(`Scripts version directory: \`${latestScriptsDir}\``);
|
|
@@ -25552,7 +26913,7 @@ function buildCliAutoImplPrompt(ctx, type, provider, providerDir, functions, ref
|
|
|
25552
26913
|
if (!file.endsWith(".js")) continue;
|
|
25553
26914
|
if (!targetFileNames.has(file)) continue;
|
|
25554
26915
|
try {
|
|
25555
|
-
const content = fs14.readFileSync(
|
|
26916
|
+
const content = fs14.readFileSync(path24.join(latestScriptsDir, file), "utf-8");
|
|
25556
26917
|
lines.push(`### \`${file}\` \u270F\uFE0F EDIT`);
|
|
25557
26918
|
lines.push("```javascript");
|
|
25558
26919
|
lines.push(content);
|
|
@@ -25568,7 +26929,7 @@ function buildCliAutoImplPrompt(ctx, type, provider, providerDir, functions, ref
|
|
|
25568
26929
|
lines.push("");
|
|
25569
26930
|
for (const file of refFiles) {
|
|
25570
26931
|
try {
|
|
25571
|
-
const content = fs14.readFileSync(
|
|
26932
|
+
const content = fs14.readFileSync(path24.join(latestScriptsDir, file), "utf-8");
|
|
25572
26933
|
lines.push(`### \`${file}\` \u{1F512}`);
|
|
25573
26934
|
lines.push("```javascript");
|
|
25574
26935
|
lines.push(content);
|
|
@@ -25601,10 +26962,10 @@ function buildCliAutoImplPrompt(ctx, type, provider, providerDir, functions, ref
|
|
|
25601
26962
|
lines.push("");
|
|
25602
26963
|
}
|
|
25603
26964
|
}
|
|
25604
|
-
const docsDir =
|
|
26965
|
+
const docsDir = path24.join(providerDir, "../../docs");
|
|
25605
26966
|
const loadGuide = (name) => {
|
|
25606
26967
|
try {
|
|
25607
|
-
const p =
|
|
26968
|
+
const p = path24.join(docsDir, name);
|
|
25608
26969
|
if (fs14.existsSync(p)) return fs14.readFileSync(p, "utf-8");
|
|
25609
26970
|
} catch {
|
|
25610
26971
|
}
|
|
@@ -26051,8 +27412,8 @@ var DevServer = class _DevServer {
|
|
|
26051
27412
|
}
|
|
26052
27413
|
getEndpointList() {
|
|
26053
27414
|
return this.routes.map((r) => {
|
|
26054
|
-
const
|
|
26055
|
-
return `${r.method.padEnd(5)} ${
|
|
27415
|
+
const path26 = typeof r.pattern === "string" ? r.pattern : r.pattern.source.replace(/\\\//g, "/").replace(/\(\[.*?\]\+\)/g, ":type").replace(/[\^$]/g, "");
|
|
27416
|
+
return `${r.method.padEnd(5)} ${path26}`;
|
|
26056
27417
|
});
|
|
26057
27418
|
}
|
|
26058
27419
|
async start(port = DEV_SERVER_PORT) {
|
|
@@ -26083,15 +27444,15 @@ var DevServer = class _DevServer {
|
|
|
26083
27444
|
this.json(res, 500, { error: e.message });
|
|
26084
27445
|
}
|
|
26085
27446
|
});
|
|
26086
|
-
return new Promise((
|
|
27447
|
+
return new Promise((resolve15, reject) => {
|
|
26087
27448
|
this.server.listen(port, "127.0.0.1", () => {
|
|
26088
27449
|
this.log(`Dev server listening on http://127.0.0.1:${port}`);
|
|
26089
|
-
|
|
27450
|
+
resolve15();
|
|
26090
27451
|
});
|
|
26091
27452
|
this.server.on("error", (e) => {
|
|
26092
27453
|
if (e.code === "EADDRINUSE") {
|
|
26093
27454
|
this.log(`Port ${port} in use, skipping dev server`);
|
|
26094
|
-
|
|
27455
|
+
resolve15();
|
|
26095
27456
|
} else {
|
|
26096
27457
|
reject(e);
|
|
26097
27458
|
}
|
|
@@ -26173,20 +27534,20 @@ var DevServer = class _DevServer {
|
|
|
26173
27534
|
child.stderr?.on("data", (d) => {
|
|
26174
27535
|
stderr += d.toString().slice(0, 2e3);
|
|
26175
27536
|
});
|
|
26176
|
-
await new Promise((
|
|
27537
|
+
await new Promise((resolve15) => {
|
|
26177
27538
|
const timer = setTimeout(() => {
|
|
26178
27539
|
child.kill();
|
|
26179
|
-
|
|
27540
|
+
resolve15();
|
|
26180
27541
|
}, 3e3);
|
|
26181
27542
|
child.on("exit", () => {
|
|
26182
27543
|
clearTimeout(timer);
|
|
26183
|
-
|
|
27544
|
+
resolve15();
|
|
26184
27545
|
});
|
|
26185
27546
|
child.stdout?.once("data", () => {
|
|
26186
27547
|
setTimeout(() => {
|
|
26187
27548
|
child.kill();
|
|
26188
27549
|
clearTimeout(timer);
|
|
26189
|
-
|
|
27550
|
+
resolve15();
|
|
26190
27551
|
}, 500);
|
|
26191
27552
|
});
|
|
26192
27553
|
});
|
|
@@ -26340,12 +27701,12 @@ var DevServer = class _DevServer {
|
|
|
26340
27701
|
// ─── DevConsole SPA ───
|
|
26341
27702
|
getConsoleDistDir() {
|
|
26342
27703
|
const candidates = [
|
|
26343
|
-
|
|
26344
|
-
|
|
26345
|
-
|
|
27704
|
+
path25.resolve(__dirname, "../../web-devconsole/dist"),
|
|
27705
|
+
path25.resolve(__dirname, "../../../web-devconsole/dist"),
|
|
27706
|
+
path25.join(process.cwd(), "packages/web-devconsole/dist")
|
|
26346
27707
|
];
|
|
26347
27708
|
for (const dir of candidates) {
|
|
26348
|
-
if (fs15.existsSync(
|
|
27709
|
+
if (fs15.existsSync(path25.join(dir, "index.html"))) return dir;
|
|
26349
27710
|
}
|
|
26350
27711
|
return null;
|
|
26351
27712
|
}
|
|
@@ -26355,7 +27716,7 @@ var DevServer = class _DevServer {
|
|
|
26355
27716
|
this.json(res, 500, { error: "DevConsole not found. Run: npm run build -w packages/web-devconsole" });
|
|
26356
27717
|
return;
|
|
26357
27718
|
}
|
|
26358
|
-
const htmlPath =
|
|
27719
|
+
const htmlPath = path25.join(distDir, "index.html");
|
|
26359
27720
|
try {
|
|
26360
27721
|
const html = fs15.readFileSync(htmlPath, "utf-8");
|
|
26361
27722
|
res.writeHead(200, { "Content-Type": "text/html; charset=utf-8" });
|
|
@@ -26380,15 +27741,15 @@ var DevServer = class _DevServer {
|
|
|
26380
27741
|
this.json(res, 404, { error: "Not found" });
|
|
26381
27742
|
return;
|
|
26382
27743
|
}
|
|
26383
|
-
const safePath =
|
|
26384
|
-
const filePath =
|
|
27744
|
+
const safePath = path25.normalize(pathname).replace(/^\.\.\//, "");
|
|
27745
|
+
const filePath = path25.join(distDir, safePath);
|
|
26385
27746
|
if (!filePath.startsWith(distDir)) {
|
|
26386
27747
|
this.json(res, 403, { error: "Forbidden" });
|
|
26387
27748
|
return;
|
|
26388
27749
|
}
|
|
26389
27750
|
try {
|
|
26390
27751
|
const content = fs15.readFileSync(filePath);
|
|
26391
|
-
const ext =
|
|
27752
|
+
const ext = path25.extname(filePath);
|
|
26392
27753
|
const contentType = _DevServer.MIME_MAP[ext] || "application/octet-stream";
|
|
26393
27754
|
res.writeHead(200, { "Content-Type": contentType, "Cache-Control": "public, max-age=31536000, immutable" });
|
|
26394
27755
|
res.end(content);
|
|
@@ -26501,10 +27862,10 @@ var DevServer = class _DevServer {
|
|
|
26501
27862
|
const rel = prefix ? `${prefix}/${entry.name}` : entry.name;
|
|
26502
27863
|
if (entry.isDirectory()) {
|
|
26503
27864
|
files.push({ path: rel, size: 0, type: "dir" });
|
|
26504
|
-
scan(
|
|
27865
|
+
scan(path25.join(d, entry.name), rel);
|
|
26505
27866
|
} else {
|
|
26506
|
-
const
|
|
26507
|
-
files.push({ path: rel, size:
|
|
27867
|
+
const stat2 = fs15.statSync(path25.join(d, entry.name));
|
|
27868
|
+
files.push({ path: rel, size: stat2.size, type: "file" });
|
|
26508
27869
|
}
|
|
26509
27870
|
}
|
|
26510
27871
|
} catch {
|
|
@@ -26526,7 +27887,7 @@ var DevServer = class _DevServer {
|
|
|
26526
27887
|
this.json(res, 404, { error: `Provider directory not found: ${type}` });
|
|
26527
27888
|
return;
|
|
26528
27889
|
}
|
|
26529
|
-
const fullPath =
|
|
27890
|
+
const fullPath = path25.resolve(dir, path25.normalize(filePath));
|
|
26530
27891
|
if (!fullPath.startsWith(dir)) {
|
|
26531
27892
|
this.json(res, 403, { error: "Forbidden" });
|
|
26532
27893
|
return;
|
|
@@ -26551,14 +27912,14 @@ var DevServer = class _DevServer {
|
|
|
26551
27912
|
this.json(res, 404, { error: `Provider directory not found: ${type}` });
|
|
26552
27913
|
return;
|
|
26553
27914
|
}
|
|
26554
|
-
const fullPath =
|
|
27915
|
+
const fullPath = path25.resolve(dir, path25.normalize(filePath));
|
|
26555
27916
|
if (!fullPath.startsWith(dir)) {
|
|
26556
27917
|
this.json(res, 403, { error: "Forbidden" });
|
|
26557
27918
|
return;
|
|
26558
27919
|
}
|
|
26559
27920
|
try {
|
|
26560
27921
|
if (fs15.existsSync(fullPath)) fs15.copyFileSync(fullPath, fullPath + ".bak");
|
|
26561
|
-
fs15.mkdirSync(
|
|
27922
|
+
fs15.mkdirSync(path25.dirname(fullPath), { recursive: true });
|
|
26562
27923
|
fs15.writeFileSync(fullPath, content, "utf-8");
|
|
26563
27924
|
this.log(`File saved: ${fullPath} (${content.length} chars)`);
|
|
26564
27925
|
this.providerLoader.reload();
|
|
@@ -26575,7 +27936,7 @@ var DevServer = class _DevServer {
|
|
|
26575
27936
|
return;
|
|
26576
27937
|
}
|
|
26577
27938
|
for (const name of ["scripts.js", "provider.json"]) {
|
|
26578
|
-
const p =
|
|
27939
|
+
const p = path25.join(dir, name);
|
|
26579
27940
|
if (fs15.existsSync(p)) {
|
|
26580
27941
|
const source = fs15.readFileSync(p, "utf-8");
|
|
26581
27942
|
this.json(res, 200, { type, path: p, source, lines: source.split("\n").length });
|
|
@@ -26596,8 +27957,8 @@ var DevServer = class _DevServer {
|
|
|
26596
27957
|
this.json(res, 404, { error: `Provider not found: ${type}` });
|
|
26597
27958
|
return;
|
|
26598
27959
|
}
|
|
26599
|
-
const target = fs15.existsSync(
|
|
26600
|
-
const targetPath =
|
|
27960
|
+
const target = fs15.existsSync(path25.join(dir, "scripts.js")) ? "scripts.js" : "provider.json";
|
|
27961
|
+
const targetPath = path25.join(dir, target);
|
|
26601
27962
|
try {
|
|
26602
27963
|
if (fs15.existsSync(targetPath)) fs15.copyFileSync(targetPath, targetPath + ".bak");
|
|
26603
27964
|
fs15.writeFileSync(targetPath, source, "utf-8");
|
|
@@ -26689,14 +28050,14 @@ var DevServer = class _DevServer {
|
|
|
26689
28050
|
child.stderr?.on("data", (d) => {
|
|
26690
28051
|
stderr += d.toString();
|
|
26691
28052
|
});
|
|
26692
|
-
await new Promise((
|
|
28053
|
+
await new Promise((resolve15) => {
|
|
26693
28054
|
const timer = setTimeout(() => {
|
|
26694
28055
|
child.kill();
|
|
26695
|
-
|
|
28056
|
+
resolve15();
|
|
26696
28057
|
}, timeout);
|
|
26697
28058
|
child.on("exit", () => {
|
|
26698
28059
|
clearTimeout(timer);
|
|
26699
|
-
|
|
28060
|
+
resolve15();
|
|
26700
28061
|
});
|
|
26701
28062
|
});
|
|
26702
28063
|
const elapsed = Date.now() - start;
|
|
@@ -26744,7 +28105,7 @@ var DevServer = class _DevServer {
|
|
|
26744
28105
|
}
|
|
26745
28106
|
let targetDir;
|
|
26746
28107
|
targetDir = this.providerLoader.getUserProviderDir(category, type);
|
|
26747
|
-
const jsonPath =
|
|
28108
|
+
const jsonPath = path25.join(targetDir, "provider.json");
|
|
26748
28109
|
if (fs15.existsSync(jsonPath)) {
|
|
26749
28110
|
this.json(res, 409, { error: `Provider already exists at ${targetDir}`, path: targetDir });
|
|
26750
28111
|
return;
|
|
@@ -26756,8 +28117,8 @@ var DevServer = class _DevServer {
|
|
|
26756
28117
|
const createdFiles = ["provider.json"];
|
|
26757
28118
|
if (result.files) {
|
|
26758
28119
|
for (const [relPath, content] of Object.entries(result.files)) {
|
|
26759
|
-
const fullPath =
|
|
26760
|
-
fs15.mkdirSync(
|
|
28120
|
+
const fullPath = path25.join(targetDir, relPath);
|
|
28121
|
+
fs15.mkdirSync(path25.dirname(fullPath), { recursive: true });
|
|
26761
28122
|
fs15.writeFileSync(fullPath, content, "utf-8");
|
|
26762
28123
|
createdFiles.push(relPath);
|
|
26763
28124
|
}
|
|
@@ -26810,22 +28171,22 @@ var DevServer = class _DevServer {
|
|
|
26810
28171
|
if (!fs15.existsSync(scriptsDir)) return null;
|
|
26811
28172
|
const versions = fs15.readdirSync(scriptsDir).filter((d) => {
|
|
26812
28173
|
try {
|
|
26813
|
-
return fs15.statSync(
|
|
28174
|
+
return fs15.statSync(path25.join(scriptsDir, d)).isDirectory();
|
|
26814
28175
|
} catch {
|
|
26815
28176
|
return false;
|
|
26816
28177
|
}
|
|
26817
28178
|
}).sort((a, b) => b.localeCompare(a, void 0, { numeric: true, sensitivity: "base" }));
|
|
26818
28179
|
if (versions.length === 0) return null;
|
|
26819
|
-
return
|
|
28180
|
+
return path25.join(scriptsDir, versions[0]);
|
|
26820
28181
|
}
|
|
26821
28182
|
resolveAutoImplWritableProviderDir(category, type, requestedDir) {
|
|
26822
|
-
const canonicalUserDir =
|
|
26823
|
-
const desiredDir = requestedDir ?
|
|
26824
|
-
const upstreamRoot =
|
|
26825
|
-
if (desiredDir === upstreamRoot || desiredDir.startsWith(`${upstreamRoot}${
|
|
28183
|
+
const canonicalUserDir = path25.resolve(this.providerLoader.getUserProviderDir(category, type));
|
|
28184
|
+
const desiredDir = requestedDir ? path25.resolve(requestedDir) : canonicalUserDir;
|
|
28185
|
+
const upstreamRoot = path25.resolve(this.providerLoader.getUpstreamDir());
|
|
28186
|
+
if (desiredDir === upstreamRoot || desiredDir.startsWith(`${upstreamRoot}${path25.sep}`)) {
|
|
26826
28187
|
return { dir: null, reason: `Refusing to write into upstream provider directory: ${desiredDir}` };
|
|
26827
28188
|
}
|
|
26828
|
-
if (
|
|
28189
|
+
if (path25.basename(desiredDir) !== type) {
|
|
26829
28190
|
return { dir: null, reason: `Requested writable provider directory must end with '${type}': ${desiredDir}` };
|
|
26830
28191
|
}
|
|
26831
28192
|
const sourceDir = this.findProviderDir(type);
|
|
@@ -26833,11 +28194,11 @@ var DevServer = class _DevServer {
|
|
|
26833
28194
|
return { dir: null, reason: `Provider source directory not found for '${type}'` };
|
|
26834
28195
|
}
|
|
26835
28196
|
if (!fs15.existsSync(desiredDir)) {
|
|
26836
|
-
fs15.mkdirSync(
|
|
28197
|
+
fs15.mkdirSync(path25.dirname(desiredDir), { recursive: true });
|
|
26837
28198
|
fs15.cpSync(sourceDir, desiredDir, { recursive: true });
|
|
26838
28199
|
this.log(`Auto-implement writable copy created: ${desiredDir}`);
|
|
26839
28200
|
}
|
|
26840
|
-
const providerJson =
|
|
28201
|
+
const providerJson = path25.join(desiredDir, "provider.json");
|
|
26841
28202
|
if (!fs15.existsSync(providerJson)) {
|
|
26842
28203
|
return { dir: null, reason: `provider.json not found in writable provider directory: ${desiredDir}` };
|
|
26843
28204
|
}
|
|
@@ -26873,7 +28234,7 @@ var DevServer = class _DevServer {
|
|
|
26873
28234
|
setMode: "set_mode.js"
|
|
26874
28235
|
};
|
|
26875
28236
|
const targetFileNames = new Set(functions.map((fn) => funcToFile[fn]).filter(Boolean));
|
|
26876
|
-
const scriptsDir =
|
|
28237
|
+
const scriptsDir = path25.join(providerDir, "scripts");
|
|
26877
28238
|
const latestScriptsDir = this.getLatestScriptVersionDir(scriptsDir);
|
|
26878
28239
|
if (latestScriptsDir) {
|
|
26879
28240
|
lines.push(`Scripts version directory: \`${latestScriptsDir}\``);
|
|
@@ -26884,7 +28245,7 @@ var DevServer = class _DevServer {
|
|
|
26884
28245
|
for (const file of fs15.readdirSync(latestScriptsDir)) {
|
|
26885
28246
|
if (file.endsWith(".js") && targetFileNames.has(file)) {
|
|
26886
28247
|
try {
|
|
26887
|
-
const content = fs15.readFileSync(
|
|
28248
|
+
const content = fs15.readFileSync(path25.join(latestScriptsDir, file), "utf-8");
|
|
26888
28249
|
lines.push(`### \`${file}\` \u270F\uFE0F EDIT`);
|
|
26889
28250
|
lines.push("```javascript");
|
|
26890
28251
|
lines.push(content);
|
|
@@ -26901,7 +28262,7 @@ var DevServer = class _DevServer {
|
|
|
26901
28262
|
lines.push("");
|
|
26902
28263
|
for (const file of refFiles) {
|
|
26903
28264
|
try {
|
|
26904
|
-
const content = fs15.readFileSync(
|
|
28265
|
+
const content = fs15.readFileSync(path25.join(latestScriptsDir, file), "utf-8");
|
|
26905
28266
|
lines.push(`### \`${file}\` \u{1F512}`);
|
|
26906
28267
|
lines.push("```javascript");
|
|
26907
28268
|
lines.push(content);
|
|
@@ -26942,10 +28303,10 @@ var DevServer = class _DevServer {
|
|
|
26942
28303
|
lines.push("");
|
|
26943
28304
|
}
|
|
26944
28305
|
}
|
|
26945
|
-
const docsDir =
|
|
28306
|
+
const docsDir = path25.join(providerDir, "../../docs");
|
|
26946
28307
|
const loadGuide = (name) => {
|
|
26947
28308
|
try {
|
|
26948
|
-
const p =
|
|
28309
|
+
const p = path25.join(docsDir, name);
|
|
26949
28310
|
if (fs15.existsSync(p)) return fs15.readFileSync(p, "utf-8");
|
|
26950
28311
|
} catch {
|
|
26951
28312
|
}
|
|
@@ -27119,7 +28480,7 @@ var DevServer = class _DevServer {
|
|
|
27119
28480
|
parseApproval: "parse_approval.js"
|
|
27120
28481
|
};
|
|
27121
28482
|
const targetFileNames = new Set(functions.map((fn) => funcToFile[fn]).filter(Boolean));
|
|
27122
|
-
const scriptsDir =
|
|
28483
|
+
const scriptsDir = path25.join(providerDir, "scripts");
|
|
27123
28484
|
const latestScriptsDir = this.getLatestScriptVersionDir(scriptsDir);
|
|
27124
28485
|
if (latestScriptsDir) {
|
|
27125
28486
|
lines.push(`Scripts version directory: \`${latestScriptsDir}\``);
|
|
@@ -27131,7 +28492,7 @@ var DevServer = class _DevServer {
|
|
|
27131
28492
|
if (!file.endsWith(".js")) continue;
|
|
27132
28493
|
if (!targetFileNames.has(file)) continue;
|
|
27133
28494
|
try {
|
|
27134
|
-
const content = fs15.readFileSync(
|
|
28495
|
+
const content = fs15.readFileSync(path25.join(latestScriptsDir, file), "utf-8");
|
|
27135
28496
|
lines.push(`### \`${file}\` \u270F\uFE0F EDIT`);
|
|
27136
28497
|
lines.push("```javascript");
|
|
27137
28498
|
lines.push(content);
|
|
@@ -27147,7 +28508,7 @@ var DevServer = class _DevServer {
|
|
|
27147
28508
|
lines.push("");
|
|
27148
28509
|
for (const file of refFiles) {
|
|
27149
28510
|
try {
|
|
27150
|
-
const content = fs15.readFileSync(
|
|
28511
|
+
const content = fs15.readFileSync(path25.join(latestScriptsDir, file), "utf-8");
|
|
27151
28512
|
lines.push(`### \`${file}\` \u{1F512}`);
|
|
27152
28513
|
lines.push("```javascript");
|
|
27153
28514
|
lines.push(content);
|
|
@@ -27180,10 +28541,10 @@ var DevServer = class _DevServer {
|
|
|
27180
28541
|
lines.push("");
|
|
27181
28542
|
}
|
|
27182
28543
|
}
|
|
27183
|
-
const docsDir =
|
|
28544
|
+
const docsDir = path25.join(providerDir, "../../docs");
|
|
27184
28545
|
const loadGuide = (name) => {
|
|
27185
28546
|
try {
|
|
27186
|
-
const p =
|
|
28547
|
+
const p = path25.join(docsDir, name);
|
|
27187
28548
|
if (fs15.existsSync(p)) return fs15.readFileSync(p, "utf-8");
|
|
27188
28549
|
} catch {
|
|
27189
28550
|
}
|
|
@@ -27366,14 +28727,14 @@ data: ${JSON.stringify(msg.data)}
|
|
|
27366
28727
|
res.end(JSON.stringify(data, null, 2));
|
|
27367
28728
|
}
|
|
27368
28729
|
async readBody(req) {
|
|
27369
|
-
return new Promise((
|
|
28730
|
+
return new Promise((resolve15) => {
|
|
27370
28731
|
let body = "";
|
|
27371
28732
|
req.on("data", (chunk) => body += chunk);
|
|
27372
28733
|
req.on("end", () => {
|
|
27373
28734
|
try {
|
|
27374
|
-
|
|
28735
|
+
resolve15(JSON.parse(body));
|
|
27375
28736
|
} catch {
|
|
27376
|
-
|
|
28737
|
+
resolve15({});
|
|
27377
28738
|
}
|
|
27378
28739
|
});
|
|
27379
28740
|
});
|
|
@@ -27883,7 +29244,7 @@ async function waitForReady(endpoint, timeoutMs = STARTUP_TIMEOUT_MS) {
|
|
|
27883
29244
|
const deadline = Date.now() + timeoutMs;
|
|
27884
29245
|
while (Date.now() < deadline) {
|
|
27885
29246
|
if (await canConnect(endpoint)) return;
|
|
27886
|
-
await new Promise((
|
|
29247
|
+
await new Promise((resolve15) => setTimeout(resolve15, STARTUP_POLL_MS));
|
|
27887
29248
|
}
|
|
27888
29249
|
throw new Error(`Session host did not become ready within ${timeoutMs}ms`);
|
|
27889
29250
|
}
|
|
@@ -28061,10 +29422,10 @@ async function installExtension(ide, extension) {
|
|
|
28061
29422
|
const buffer = Buffer.from(await res.arrayBuffer());
|
|
28062
29423
|
const fs16 = await import("fs");
|
|
28063
29424
|
fs16.writeFileSync(vsixPath, buffer);
|
|
28064
|
-
return new Promise((
|
|
29425
|
+
return new Promise((resolve15) => {
|
|
28065
29426
|
const cmd = `"${ide.cliCommand}" --install-extension "${vsixPath}" --force`;
|
|
28066
29427
|
(0, import_child_process11.exec)(cmd, { timeout: 6e4 }, (error, _stdout, stderr) => {
|
|
28067
|
-
|
|
29428
|
+
resolve15({
|
|
28068
29429
|
extensionId: extension.id,
|
|
28069
29430
|
marketplaceId: extension.marketplaceId,
|
|
28070
29431
|
success: !error,
|
|
@@ -28077,11 +29438,11 @@ async function installExtension(ide, extension) {
|
|
|
28077
29438
|
} catch (e) {
|
|
28078
29439
|
}
|
|
28079
29440
|
}
|
|
28080
|
-
return new Promise((
|
|
29441
|
+
return new Promise((resolve15) => {
|
|
28081
29442
|
const cmd = `"${ide.cliCommand}" --install-extension ${extension.marketplaceId} --force`;
|
|
28082
29443
|
(0, import_child_process11.exec)(cmd, { timeout: 6e4 }, (error, stdout, stderr) => {
|
|
28083
29444
|
if (error) {
|
|
28084
|
-
|
|
29445
|
+
resolve15({
|
|
28085
29446
|
extensionId: extension.id,
|
|
28086
29447
|
marketplaceId: extension.marketplaceId,
|
|
28087
29448
|
success: false,
|
|
@@ -28089,7 +29450,7 @@ async function installExtension(ide, extension) {
|
|
|
28089
29450
|
error: stderr || error.message
|
|
28090
29451
|
});
|
|
28091
29452
|
} else {
|
|
28092
|
-
|
|
29453
|
+
resolve15({
|
|
28093
29454
|
extensionId: extension.id,
|
|
28094
29455
|
marketplaceId: extension.marketplaceId,
|
|
28095
29456
|
success: true,
|
|
@@ -28293,6 +29654,7 @@ async function initDaemonComponents(config) {
|
|
|
28293
29654
|
providerLoader,
|
|
28294
29655
|
instanceManager,
|
|
28295
29656
|
sessionRegistry,
|
|
29657
|
+
gitCommandServices: createDefaultGitCommandServices(),
|
|
28296
29658
|
onProviderSettingChanged: async (providerType) => {
|
|
28297
29659
|
await refreshProviderAvailability(providerType);
|
|
28298
29660
|
config.onStatusChange?.();
|
|
@@ -28300,7 +29662,8 @@ async function initDaemonComponents(config) {
|
|
|
28300
29662
|
onProviderSourceConfigChanged: async () => {
|
|
28301
29663
|
await refreshProviderAvailability();
|
|
28302
29664
|
config.onStatusChange?.();
|
|
28303
|
-
}
|
|
29665
|
+
},
|
|
29666
|
+
onBeforeSendChat: config.onBeforeSendChat
|
|
28304
29667
|
});
|
|
28305
29668
|
agentStreamManager = new DaemonAgentStreamManager(
|
|
28306
29669
|
LOG.forComponent("AgentStream").asLogFn(),
|
|
@@ -28419,6 +29782,7 @@ async function shutdownDaemonComponents(components) {
|
|
|
28419
29782
|
DEFAULT_CDP_SCAN_INTERVAL_MS,
|
|
28420
29783
|
DEFAULT_CHAT_TAIL_RECENT_MESSAGE_GRACE_MS,
|
|
28421
29784
|
DEFAULT_DAEMON_PORT,
|
|
29785
|
+
DEFAULT_GIT_WORKSPACE_POLL_INTERVAL_MS,
|
|
28422
29786
|
DEFAULT_MACHINE_RUNTIME_SUBSCRIPTION_INTERVAL_MS,
|
|
28423
29787
|
DEFAULT_SESSION_HOST_APP_NAME,
|
|
28424
29788
|
DEFAULT_SESSION_HOST_DIAGNOSTICS_SUBSCRIPTION_INTERVAL_MS,
|
|
@@ -28437,8 +29801,12 @@ async function shutdownDaemonComponents(components) {
|
|
|
28437
29801
|
DaemonCommandRouter,
|
|
28438
29802
|
DaemonStatusReporter,
|
|
28439
29803
|
DevServer,
|
|
29804
|
+
GitCommandError,
|
|
29805
|
+
GitWorkspaceMonitor,
|
|
28440
29806
|
IdeProviderInstance,
|
|
29807
|
+
InMemoryGitSnapshotStore,
|
|
28441
29808
|
LOG,
|
|
29809
|
+
MIN_GIT_WORKSPACE_POLL_INTERVAL_MS,
|
|
28442
29810
|
MIN_MACHINE_RUNTIME_SUBSCRIPTION_INTERVAL_MS,
|
|
28443
29811
|
MIN_SESSION_HOST_DIAGNOSTICS_SUBSCRIPTION_INTERVAL_MS,
|
|
28444
29812
|
NodePtyTransportFactory,
|
|
@@ -28447,6 +29815,7 @@ async function shutdownDaemonComponents(components) {
|
|
|
28447
29815
|
ProviderLoader,
|
|
28448
29816
|
STANDALONE_CDP_SCAN_INTERVAL_MS,
|
|
28449
29817
|
SessionHostPtyTransportFactory,
|
|
29818
|
+
TurnSnapshotTracker,
|
|
28450
29819
|
VersionArchive,
|
|
28451
29820
|
appendRecentActivity,
|
|
28452
29821
|
buildAssistantChatMessage,
|
|
@@ -28466,9 +29835,14 @@ async function shutdownDaemonComponents(components) {
|
|
|
28466
29835
|
buildUserChatMessage,
|
|
28467
29836
|
classifyHotChatSessionsForSubscriptionFlush,
|
|
28468
29837
|
clearDebugTrace,
|
|
29838
|
+
compareGitSnapshots,
|
|
28469
29839
|
configureDebugTraceStore,
|
|
28470
29840
|
connectCdpManager,
|
|
28471
29841
|
createDebugTraceStore,
|
|
29842
|
+
createDefaultGitCommandServices,
|
|
29843
|
+
createGitCompactSummary,
|
|
29844
|
+
createGitSnapshotStore,
|
|
29845
|
+
createGitWorkspaceMonitor,
|
|
28472
29846
|
createInteractionId,
|
|
28473
29847
|
detectAllVersions,
|
|
28474
29848
|
detectCLIs,
|
|
@@ -28483,6 +29857,9 @@ async function shutdownDaemonComponents(components) {
|
|
|
28483
29857
|
getCurrentDaemonLogPath,
|
|
28484
29858
|
getDaemonLogDir,
|
|
28485
29859
|
getDebugRuntimeConfig,
|
|
29860
|
+
getGitDiffSummary,
|
|
29861
|
+
getGitFileDiff,
|
|
29862
|
+
getGitRepoStatus,
|
|
28486
29863
|
getHostMemorySnapshot,
|
|
28487
29864
|
getLogLevel,
|
|
28488
29865
|
getNpmExecOptions,
|
|
@@ -28494,6 +29871,7 @@ async function shutdownDaemonComponents(components) {
|
|
|
28494
29871
|
getSessionHostRecoveryLabel,
|
|
28495
29872
|
getSessionHostSurfaceKind,
|
|
28496
29873
|
getWorkspaceState,
|
|
29874
|
+
handleGitCommand,
|
|
28497
29875
|
hasCdpManager,
|
|
28498
29876
|
hashSignatureParts,
|
|
28499
29877
|
initDaemonComponents,
|
|
@@ -28502,9 +29880,11 @@ async function shutdownDaemonComponents(components) {
|
|
|
28502
29880
|
isBuiltinChatMessageKind,
|
|
28503
29881
|
isCdpConnected,
|
|
28504
29882
|
isExtensionInstalled,
|
|
29883
|
+
isGitCommandName,
|
|
28505
29884
|
isIdeRunning,
|
|
28506
29885
|
isManagedStatusWaiting,
|
|
28507
29886
|
isManagedStatusWorking,
|
|
29887
|
+
isPathInside,
|
|
28508
29888
|
isSessionHostLiveRuntime,
|
|
28509
29889
|
isSessionHostRecoverySnapshot,
|
|
28510
29890
|
isSetupComplete,
|
|
@@ -28522,10 +29902,13 @@ async function shutdownDaemonComponents(components) {
|
|
|
28522
29902
|
normalizeChatMessageKind,
|
|
28523
29903
|
normalizeChatMessages,
|
|
28524
29904
|
normalizeChatTailActiveModal,
|
|
29905
|
+
normalizeGitOutput,
|
|
29906
|
+
normalizeGitWorkspaceSubscriptionParams,
|
|
28525
29907
|
normalizeInputEnvelope,
|
|
28526
29908
|
normalizeManagedStatus,
|
|
28527
29909
|
normalizeMessageParts,
|
|
28528
29910
|
normalizeSessionModalFields,
|
|
29911
|
+
parsePorcelainV2Status,
|
|
28529
29912
|
parseProviderSourceConfigUpdate,
|
|
28530
29913
|
partitionSessionHostDiagnosticsSessions,
|
|
28531
29914
|
partitionSessionHostRecords,
|
|
@@ -28541,9 +29924,11 @@ async function shutdownDaemonComponents(components) {
|
|
|
28541
29924
|
resolveChatMessageKind,
|
|
28542
29925
|
resolveCurrentGlobalInstallSurface,
|
|
28543
29926
|
resolveDebugRuntimeConfig,
|
|
29927
|
+
resolveGitRepository,
|
|
28544
29928
|
resolveSessionHostAppName,
|
|
28545
29929
|
resolveSessionHostAppNameResolution,
|
|
28546
29930
|
runAsyncBatch,
|
|
29931
|
+
runGit,
|
|
28547
29932
|
saveConfig,
|
|
28548
29933
|
saveState,
|
|
28549
29934
|
setDebugRuntimeConfig,
|
|
@@ -28554,6 +29939,7 @@ async function shutdownDaemonComponents(components) {
|
|
|
28554
29939
|
shutdownDaemonComponents,
|
|
28555
29940
|
spawnDetachedDaemonUpgradeHelper,
|
|
28556
29941
|
startDaemonDevSupport,
|
|
29942
|
+
summarizeGitStatus,
|
|
28557
29943
|
updateConfig,
|
|
28558
29944
|
upsertSavedProviderSession
|
|
28559
29945
|
});
|