@adhdev/daemon-core 0.9.52 → 0.9.54
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/commands/handler.d.ts +2 -0
- package/dist/git/git-commands.d.ts +86 -0
- package/dist/git/git-diff.d.ts +17 -0
- package/dist/git/git-executor.d.ts +34 -0
- package/dist/git/git-monitor.d.ts +57 -0
- package/dist/git/git-snapshot-store.d.ts +50 -0
- package/dist/git/git-status.d.ts +19 -0
- package/dist/git/git-summary.d.ts +10 -0
- package/dist/git/git-types.d.ts +113 -0
- package/dist/git/index.d.ts +14 -0
- package/dist/index.d.ts +2 -1
- package/dist/index.js +1611 -392
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +1584 -389
- package/dist/index.mjs.map +1 -1
- package/dist/shared-types.d.ts +7 -1
- package/dist/status/builders.d.ts +2 -0
- package/dist/status/snapshot.d.ts +2 -0
- package/node_modules/@adhdev/session-host-core/package.json +1 -1
- package/package.json +1 -1
- package/src/commands/chat-commands.ts +31 -4
- package/src/commands/handler.ts +9 -1
- package/src/config/chat-history.ts +11 -3
- package/src/git/git-commands.ts +385 -0
- package/src/git/git-diff.ts +303 -0
- package/src/git/git-executor.ts +268 -0
- package/src/git/git-monitor.ts +194 -0
- package/src/git/git-snapshot-store.ts +238 -0
- package/src/git/git-status.ts +193 -0
- package/src/git/git-summary.ts +43 -0
- package/src/git/git-types.ts +153 -0
- package/src/git/index.ts +72 -0
- package/src/index.ts +4 -0
- package/src/shared-types.ts +33 -1
- package/src/status/builders.ts +26 -4
- package/src/status/snapshot.ts +10 -2
package/dist/index.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;
|
|
@@ -1971,9 +1971,9 @@ function resolveCliSpawnPlan(options) {
|
|
|
1971
1971
|
const allArgs = [...spawnConfig.args, ...extraArgs];
|
|
1972
1972
|
let shellCmd;
|
|
1973
1973
|
let shellArgs;
|
|
1974
|
-
const useShellUnix = !isWin && (!!spawnConfig.shell || !
|
|
1974
|
+
const useShellUnix = !isWin && (!!spawnConfig.shell || !path14.isAbsolute(binaryPath) || isScriptBinary(binaryPath) || !looksLikeMachOOrElf(binaryPath));
|
|
1975
1975
|
const isCmdShim = isWin && /\.(cmd|bat)$/i.test(binaryPath);
|
|
1976
|
-
const useShellWin = !!spawnConfig.shell || isCmdShim || !
|
|
1976
|
+
const useShellWin = !!spawnConfig.shell || isCmdShim || !path14.isAbsolute(binaryPath) || isScriptBinary(binaryPath);
|
|
1977
1977
|
const useShell = isWin ? useShellWin : useShellUnix;
|
|
1978
1978
|
if (useShell) {
|
|
1979
1979
|
shellCmd = isWin ? "cmd.exe" : process.env.SHELL || "/bin/zsh";
|
|
@@ -2049,12 +2049,12 @@ function respondToCliTerminalQueries(options) {
|
|
|
2049
2049
|
}
|
|
2050
2050
|
return "";
|
|
2051
2051
|
}
|
|
2052
|
-
var os10,
|
|
2052
|
+
var os10, path14, import_session_host_core2;
|
|
2053
2053
|
var init_provider_cli_runtime = __esm({
|
|
2054
2054
|
"src/cli-adapters/provider-cli-runtime.ts"() {
|
|
2055
2055
|
"use strict";
|
|
2056
2056
|
os10 = __toESM(require("os"));
|
|
2057
|
-
|
|
2057
|
+
path14 = __toESM(require("path"));
|
|
2058
2058
|
import_session_host_core2 = require("@adhdev/session-host-core");
|
|
2059
2059
|
init_provider_cli_shared();
|
|
2060
2060
|
}
|
|
@@ -2854,7 +2854,7 @@ var init_provider_cli_adapter = __esm({
|
|
|
2854
2854
|
`[${this.cliType}] Waiting for interactive prompt: status=${status} stableMs=${stableMs} recentOutputMs=${recentlyOutput} screen=${JSON.stringify(summarizeCliTraceText(screenText, 220)).slice(0, 260)}`
|
|
2855
2855
|
);
|
|
2856
2856
|
}
|
|
2857
|
-
await new Promise((
|
|
2857
|
+
await new Promise((resolve15) => setTimeout(resolve15, 50));
|
|
2858
2858
|
}
|
|
2859
2859
|
const finalScreenText = this.terminalScreen.getText() || "";
|
|
2860
2860
|
LOG.warn(
|
|
@@ -4042,7 +4042,7 @@ var init_provider_cli_adapter = __esm({
|
|
|
4042
4042
|
const deadline = Date.now() + 1e4;
|
|
4043
4043
|
while (this.startupParseGate && Date.now() < deadline) {
|
|
4044
4044
|
this.resolveStartupState("send_wait");
|
|
4045
|
-
await new Promise((
|
|
4045
|
+
await new Promise((resolve15) => setTimeout(resolve15, 50));
|
|
4046
4046
|
}
|
|
4047
4047
|
}
|
|
4048
4048
|
if (!allowInterventionPrompt) {
|
|
@@ -4123,13 +4123,13 @@ var init_provider_cli_adapter = __esm({
|
|
|
4123
4123
|
}
|
|
4124
4124
|
this.responseEpoch += 1;
|
|
4125
4125
|
this.responseSettleIgnoreUntil = Date.now() + submitDelayMs + this.timeouts.outputSettle + 250;
|
|
4126
|
-
await new Promise((
|
|
4126
|
+
await new Promise((resolve15, reject) => {
|
|
4127
4127
|
let resolved = false;
|
|
4128
4128
|
const completion = {
|
|
4129
4129
|
resolveOnce: () => {
|
|
4130
4130
|
if (resolved) return;
|
|
4131
4131
|
resolved = true;
|
|
4132
|
-
|
|
4132
|
+
resolve15();
|
|
4133
4133
|
},
|
|
4134
4134
|
rejectOnce: (error) => {
|
|
4135
4135
|
if (resolved) return;
|
|
@@ -4291,17 +4291,17 @@ var init_provider_cli_adapter = __esm({
|
|
|
4291
4291
|
}
|
|
4292
4292
|
}
|
|
4293
4293
|
waitForStopped(timeoutMs) {
|
|
4294
|
-
return new Promise((
|
|
4294
|
+
return new Promise((resolve15) => {
|
|
4295
4295
|
const startedAt = Date.now();
|
|
4296
4296
|
const timer = setInterval(() => {
|
|
4297
4297
|
if (!this.ptyProcess || this.currentStatus === "stopped") {
|
|
4298
4298
|
clearInterval(timer);
|
|
4299
|
-
|
|
4299
|
+
resolve15(true);
|
|
4300
4300
|
return;
|
|
4301
4301
|
}
|
|
4302
4302
|
if (Date.now() - startedAt >= timeoutMs) {
|
|
4303
4303
|
clearInterval(timer);
|
|
4304
|
-
|
|
4304
|
+
resolve15(false);
|
|
4305
4305
|
}
|
|
4306
4306
|
}, 100);
|
|
4307
4307
|
});
|
|
@@ -4541,6 +4541,7 @@ __export(index_exports, {
|
|
|
4541
4541
|
DEFAULT_CDP_SCAN_INTERVAL_MS: () => DEFAULT_CDP_SCAN_INTERVAL_MS,
|
|
4542
4542
|
DEFAULT_CHAT_TAIL_RECENT_MESSAGE_GRACE_MS: () => DEFAULT_CHAT_TAIL_RECENT_MESSAGE_GRACE_MS,
|
|
4543
4543
|
DEFAULT_DAEMON_PORT: () => DEFAULT_DAEMON_PORT,
|
|
4544
|
+
DEFAULT_GIT_WORKSPACE_POLL_INTERVAL_MS: () => DEFAULT_GIT_WORKSPACE_POLL_INTERVAL_MS,
|
|
4544
4545
|
DEFAULT_MACHINE_RUNTIME_SUBSCRIPTION_INTERVAL_MS: () => DEFAULT_MACHINE_RUNTIME_SUBSCRIPTION_INTERVAL_MS,
|
|
4545
4546
|
DEFAULT_SESSION_HOST_APP_NAME: () => DEFAULT_SESSION_HOST_APP_NAME,
|
|
4546
4547
|
DEFAULT_SESSION_HOST_DIAGNOSTICS_SUBSCRIPTION_INTERVAL_MS: () => DEFAULT_SESSION_HOST_DIAGNOSTICS_SUBSCRIPTION_INTERVAL_MS,
|
|
@@ -4559,8 +4560,12 @@ __export(index_exports, {
|
|
|
4559
4560
|
DaemonCommandRouter: () => DaemonCommandRouter,
|
|
4560
4561
|
DaemonStatusReporter: () => DaemonStatusReporter,
|
|
4561
4562
|
DevServer: () => DevServer,
|
|
4563
|
+
GitCommandError: () => GitCommandError,
|
|
4564
|
+
GitWorkspaceMonitor: () => GitWorkspaceMonitor,
|
|
4562
4565
|
IdeProviderInstance: () => IdeProviderInstance,
|
|
4566
|
+
InMemoryGitSnapshotStore: () => InMemoryGitSnapshotStore,
|
|
4563
4567
|
LOG: () => LOG,
|
|
4568
|
+
MIN_GIT_WORKSPACE_POLL_INTERVAL_MS: () => MIN_GIT_WORKSPACE_POLL_INTERVAL_MS,
|
|
4564
4569
|
MIN_MACHINE_RUNTIME_SUBSCRIPTION_INTERVAL_MS: () => MIN_MACHINE_RUNTIME_SUBSCRIPTION_INTERVAL_MS,
|
|
4565
4570
|
MIN_SESSION_HOST_DIAGNOSTICS_SUBSCRIPTION_INTERVAL_MS: () => MIN_SESSION_HOST_DIAGNOSTICS_SUBSCRIPTION_INTERVAL_MS,
|
|
4566
4571
|
NodePtyTransportFactory: () => NodePtyTransportFactory,
|
|
@@ -4588,9 +4593,14 @@ __export(index_exports, {
|
|
|
4588
4593
|
buildUserChatMessage: () => buildUserChatMessage,
|
|
4589
4594
|
classifyHotChatSessionsForSubscriptionFlush: () => classifyHotChatSessionsForSubscriptionFlush,
|
|
4590
4595
|
clearDebugTrace: () => clearDebugTrace,
|
|
4596
|
+
compareGitSnapshots: () => compareGitSnapshots,
|
|
4591
4597
|
configureDebugTraceStore: () => configureDebugTraceStore,
|
|
4592
4598
|
connectCdpManager: () => connectCdpManager,
|
|
4593
4599
|
createDebugTraceStore: () => createDebugTraceStore,
|
|
4600
|
+
createDefaultGitCommandServices: () => createDefaultGitCommandServices,
|
|
4601
|
+
createGitCompactSummary: () => createGitCompactSummary,
|
|
4602
|
+
createGitSnapshotStore: () => createGitSnapshotStore,
|
|
4603
|
+
createGitWorkspaceMonitor: () => createGitWorkspaceMonitor,
|
|
4594
4604
|
createInteractionId: () => createInteractionId,
|
|
4595
4605
|
detectAllVersions: () => detectAllVersions,
|
|
4596
4606
|
detectCLIs: () => detectCLIs,
|
|
@@ -4605,6 +4615,9 @@ __export(index_exports, {
|
|
|
4605
4615
|
getCurrentDaemonLogPath: () => getCurrentDaemonLogPath,
|
|
4606
4616
|
getDaemonLogDir: () => getDaemonLogDir,
|
|
4607
4617
|
getDebugRuntimeConfig: () => getDebugRuntimeConfig,
|
|
4618
|
+
getGitDiffSummary: () => getGitDiffSummary,
|
|
4619
|
+
getGitFileDiff: () => getGitFileDiff,
|
|
4620
|
+
getGitRepoStatus: () => getGitRepoStatus,
|
|
4608
4621
|
getHostMemorySnapshot: () => getHostMemorySnapshot,
|
|
4609
4622
|
getLogLevel: () => getLogLevel,
|
|
4610
4623
|
getNpmExecOptions: () => getNpmExecOptions,
|
|
@@ -4616,6 +4629,7 @@ __export(index_exports, {
|
|
|
4616
4629
|
getSessionHostRecoveryLabel: () => getSessionHostRecoveryLabel,
|
|
4617
4630
|
getSessionHostSurfaceKind: () => getSessionHostSurfaceKind,
|
|
4618
4631
|
getWorkspaceState: () => getWorkspaceState,
|
|
4632
|
+
handleGitCommand: () => handleGitCommand,
|
|
4619
4633
|
hasCdpManager: () => hasCdpManager,
|
|
4620
4634
|
hashSignatureParts: () => hashSignatureParts,
|
|
4621
4635
|
initDaemonComponents: () => initDaemonComponents,
|
|
@@ -4624,9 +4638,11 @@ __export(index_exports, {
|
|
|
4624
4638
|
isBuiltinChatMessageKind: () => isBuiltinChatMessageKind,
|
|
4625
4639
|
isCdpConnected: () => isCdpConnected,
|
|
4626
4640
|
isExtensionInstalled: () => isExtensionInstalled,
|
|
4641
|
+
isGitCommandName: () => isGitCommandName,
|
|
4627
4642
|
isIdeRunning: () => isIdeRunning,
|
|
4628
4643
|
isManagedStatusWaiting: () => isManagedStatusWaiting,
|
|
4629
4644
|
isManagedStatusWorking: () => isManagedStatusWorking,
|
|
4645
|
+
isPathInside: () => isPathInside,
|
|
4630
4646
|
isSessionHostLiveRuntime: () => isSessionHostLiveRuntime,
|
|
4631
4647
|
isSessionHostRecoverySnapshot: () => isSessionHostRecoverySnapshot,
|
|
4632
4648
|
isSetupComplete: () => isSetupComplete,
|
|
@@ -4644,10 +4660,13 @@ __export(index_exports, {
|
|
|
4644
4660
|
normalizeChatMessageKind: () => normalizeChatMessageKind,
|
|
4645
4661
|
normalizeChatMessages: () => normalizeChatMessages,
|
|
4646
4662
|
normalizeChatTailActiveModal: () => normalizeChatTailActiveModal,
|
|
4663
|
+
normalizeGitOutput: () => normalizeGitOutput,
|
|
4664
|
+
normalizeGitWorkspaceSubscriptionParams: () => normalizeGitWorkspaceSubscriptionParams,
|
|
4647
4665
|
normalizeInputEnvelope: () => normalizeInputEnvelope,
|
|
4648
4666
|
normalizeManagedStatus: () => normalizeManagedStatus,
|
|
4649
4667
|
normalizeMessageParts: () => normalizeMessageParts,
|
|
4650
4668
|
normalizeSessionModalFields: () => normalizeSessionModalFields,
|
|
4669
|
+
parsePorcelainV2Status: () => parsePorcelainV2Status,
|
|
4651
4670
|
parseProviderSourceConfigUpdate: () => parseProviderSourceConfigUpdate,
|
|
4652
4671
|
partitionSessionHostDiagnosticsSessions: () => partitionSessionHostDiagnosticsSessions,
|
|
4653
4672
|
partitionSessionHostRecords: () => partitionSessionHostRecords,
|
|
@@ -4663,9 +4682,11 @@ __export(index_exports, {
|
|
|
4663
4682
|
resolveChatMessageKind: () => resolveChatMessageKind,
|
|
4664
4683
|
resolveCurrentGlobalInstallSurface: () => resolveCurrentGlobalInstallSurface,
|
|
4665
4684
|
resolveDebugRuntimeConfig: () => resolveDebugRuntimeConfig,
|
|
4685
|
+
resolveGitRepository: () => resolveGitRepository,
|
|
4666
4686
|
resolveSessionHostAppName: () => resolveSessionHostAppName,
|
|
4667
4687
|
resolveSessionHostAppNameResolution: () => resolveSessionHostAppNameResolution,
|
|
4668
4688
|
runAsyncBatch: () => runAsyncBatch,
|
|
4689
|
+
runGit: () => runGit,
|
|
4669
4690
|
saveConfig: () => saveConfig,
|
|
4670
4691
|
saveState: () => saveState,
|
|
4671
4692
|
setDebugRuntimeConfig: () => setDebugRuntimeConfig,
|
|
@@ -4676,23 +4697,1143 @@ __export(index_exports, {
|
|
|
4676
4697
|
shutdownDaemonComponents: () => shutdownDaemonComponents,
|
|
4677
4698
|
spawnDetachedDaemonUpgradeHelper: () => spawnDetachedDaemonUpgradeHelper,
|
|
4678
4699
|
startDaemonDevSupport: () => startDaemonDevSupport,
|
|
4700
|
+
summarizeGitStatus: () => summarizeGitStatus,
|
|
4679
4701
|
updateConfig: () => updateConfig,
|
|
4680
4702
|
upsertSavedProviderSession: () => upsertSavedProviderSession
|
|
4681
4703
|
});
|
|
4682
4704
|
module.exports = __toCommonJS(index_exports);
|
|
4705
|
+
|
|
4706
|
+
// src/git/git-executor.ts
|
|
4707
|
+
var import_node_child_process = require("child_process");
|
|
4708
|
+
var import_node_fs = require("fs");
|
|
4709
|
+
var import_promises = require("fs/promises");
|
|
4710
|
+
var path = __toESM(require("path"));
|
|
4711
|
+
var import_node_util = require("util");
|
|
4712
|
+
var execFileAsync = (0, import_node_util.promisify)(import_node_child_process.execFile);
|
|
4713
|
+
var DEFAULT_TIMEOUT_MS = 5e3;
|
|
4714
|
+
var DEFAULT_MAX_BUFFER = 1024 * 1024;
|
|
4715
|
+
var GitCommandError = class extends Error {
|
|
4716
|
+
reason;
|
|
4717
|
+
stdout;
|
|
4718
|
+
stderr;
|
|
4719
|
+
exitCode;
|
|
4720
|
+
signal;
|
|
4721
|
+
argv;
|
|
4722
|
+
cwd;
|
|
4723
|
+
constructor(reason, message, details = {}) {
|
|
4724
|
+
super(message);
|
|
4725
|
+
if (details.cause !== void 0) {
|
|
4726
|
+
this.cause = details.cause;
|
|
4727
|
+
}
|
|
4728
|
+
this.name = "GitCommandError";
|
|
4729
|
+
this.reason = reason;
|
|
4730
|
+
this.stdout = normalizeGitOutput(details.stdout);
|
|
4731
|
+
this.stderr = normalizeGitOutput(details.stderr);
|
|
4732
|
+
this.exitCode = details.exitCode;
|
|
4733
|
+
this.signal = details.signal;
|
|
4734
|
+
this.argv = details.argv ? [...details.argv] : void 0;
|
|
4735
|
+
this.cwd = details.cwd;
|
|
4736
|
+
}
|
|
4737
|
+
};
|
|
4738
|
+
async function resolveGitRepository(workspace, options = {}) {
|
|
4739
|
+
const normalizedWorkspace = await validateWorkspace(workspace);
|
|
4740
|
+
const result = await execGitRaw(normalizedWorkspace, ["rev-parse", "--show-toplevel"], options, {
|
|
4741
|
+
mapNotGitRepo: true
|
|
4742
|
+
});
|
|
4743
|
+
const repoRoot = path.resolve(result.stdout.trim());
|
|
4744
|
+
if (!repoRoot) {
|
|
4745
|
+
throw new GitCommandError("not_git_repo", "Git did not return a repository root", {
|
|
4746
|
+
stdout: result.stdout,
|
|
4747
|
+
stderr: result.stderr,
|
|
4748
|
+
argv: ["rev-parse", "--show-toplevel"],
|
|
4749
|
+
cwd: normalizedWorkspace
|
|
4750
|
+
});
|
|
4751
|
+
}
|
|
4752
|
+
return {
|
|
4753
|
+
workspace: normalizedWorkspace,
|
|
4754
|
+
repoRoot,
|
|
4755
|
+
isGitRepo: true
|
|
4756
|
+
};
|
|
4757
|
+
}
|
|
4758
|
+
async function runGit(repoOrWorkspace, argv, options = {}) {
|
|
4759
|
+
validateGitArgv(argv);
|
|
4760
|
+
const repo = typeof repoOrWorkspace === "string" ? await resolveGitRepository(repoOrWorkspace, options) : repoOrWorkspace;
|
|
4761
|
+
if (!repo.repoRoot || !repo.isGitRepo) {
|
|
4762
|
+
throw new GitCommandError("not_git_repo", "Workspace is not a Git repository", {
|
|
4763
|
+
argv,
|
|
4764
|
+
cwd: repo.workspace
|
|
4765
|
+
});
|
|
4766
|
+
}
|
|
4767
|
+
const cwd = options.cwd ? await validateWorkspace(options.cwd) : await validateWorkspace(repo.workspace);
|
|
4768
|
+
const canonicalRepoRoot = await (0, import_promises.realpath)(repo.repoRoot);
|
|
4769
|
+
const canonicalCwd = await (0, import_promises.realpath)(cwd);
|
|
4770
|
+
if (!isPathInside(canonicalRepoRoot, canonicalCwd)) {
|
|
4771
|
+
throw new GitCommandError("path_outside_repo", "Git cwd is outside the repository root", {
|
|
4772
|
+
argv,
|
|
4773
|
+
cwd
|
|
4774
|
+
});
|
|
4775
|
+
}
|
|
4776
|
+
return execGitRaw(cwd, argv, options);
|
|
4777
|
+
}
|
|
4778
|
+
function normalizeGitOutput(value) {
|
|
4779
|
+
if (typeof value === "string") return value.replace(/\r\n/g, "\n");
|
|
4780
|
+
if (Buffer.isBuffer(value)) return value.toString("utf8").replace(/\r\n/g, "\n");
|
|
4781
|
+
if (value == null) return "";
|
|
4782
|
+
return String(value).replace(/\r\n/g, "\n");
|
|
4783
|
+
}
|
|
4784
|
+
function isPathInside(parent, child) {
|
|
4785
|
+
const relative3 = path.relative(path.resolve(parent), path.resolve(child));
|
|
4786
|
+
return relative3 === "" || !relative3.startsWith("..") && !path.isAbsolute(relative3);
|
|
4787
|
+
}
|
|
4788
|
+
async function validateWorkspace(workspace) {
|
|
4789
|
+
if (typeof workspace !== "string" || workspace.length === 0 || workspace.includes("\0")) {
|
|
4790
|
+
throw new GitCommandError("invalid_args", "Workspace must be a non-empty path");
|
|
4791
|
+
}
|
|
4792
|
+
if (!path.isAbsolute(workspace)) {
|
|
4793
|
+
throw new GitCommandError("invalid_args", "Workspace must be an absolute path", { cwd: workspace });
|
|
4794
|
+
}
|
|
4795
|
+
const normalizedWorkspace = path.resolve(workspace);
|
|
4796
|
+
try {
|
|
4797
|
+
const info = await (0, import_promises.stat)(normalizedWorkspace);
|
|
4798
|
+
if (!info.isDirectory()) {
|
|
4799
|
+
throw new GitCommandError("invalid_args", "Workspace must be an existing directory", {
|
|
4800
|
+
cwd: normalizedWorkspace
|
|
4801
|
+
});
|
|
4802
|
+
}
|
|
4803
|
+
await (0, import_promises.access)(normalizedWorkspace, import_node_fs.constants.R_OK);
|
|
4804
|
+
} catch (error) {
|
|
4805
|
+
if (error instanceof GitCommandError) throw error;
|
|
4806
|
+
throw new GitCommandError("invalid_args", "Workspace must be an existing directory", {
|
|
4807
|
+
cwd: normalizedWorkspace,
|
|
4808
|
+
cause: error
|
|
4809
|
+
});
|
|
4810
|
+
}
|
|
4811
|
+
return normalizedWorkspace;
|
|
4812
|
+
}
|
|
4813
|
+
function validateGitArgv(argv) {
|
|
4814
|
+
if (!Array.isArray(argv) || argv.length === 0) {
|
|
4815
|
+
throw new GitCommandError("invalid_args", "Git argv must be a non-empty string array", { argv });
|
|
4816
|
+
}
|
|
4817
|
+
for (const arg of argv) {
|
|
4818
|
+
if (typeof arg !== "string" || arg.length === 0 || arg.includes("\0")) {
|
|
4819
|
+
throw new GitCommandError("invalid_args", "Git argv contains an invalid argument", { argv });
|
|
4820
|
+
}
|
|
4821
|
+
}
|
|
4822
|
+
if (argv.includes("-C") || argv.some((arg) => arg.startsWith("--git-dir") || arg.startsWith("--work-tree"))) {
|
|
4823
|
+
throw new GitCommandError("invalid_args", "Git argv contains unsafe repository override arguments", {
|
|
4824
|
+
argv
|
|
4825
|
+
});
|
|
4826
|
+
}
|
|
4827
|
+
}
|
|
4828
|
+
async function execGitRaw(cwd, argv, options, behavior = {}) {
|
|
4829
|
+
validateGitArgv(argv);
|
|
4830
|
+
try {
|
|
4831
|
+
const result = await execFileAsync("git", [...argv], {
|
|
4832
|
+
cwd,
|
|
4833
|
+
encoding: "utf8",
|
|
4834
|
+
timeout: options.timeoutMs ?? DEFAULT_TIMEOUT_MS,
|
|
4835
|
+
maxBuffer: options.maxBuffer ?? DEFAULT_MAX_BUFFER,
|
|
4836
|
+
windowsHide: true
|
|
4837
|
+
});
|
|
4838
|
+
return {
|
|
4839
|
+
stdout: normalizeGitOutput(result.stdout),
|
|
4840
|
+
stderr: normalizeGitOutput(result.stderr)
|
|
4841
|
+
};
|
|
4842
|
+
} catch (error) {
|
|
4843
|
+
throw mapExecError(error, cwd, argv, behavior);
|
|
4844
|
+
}
|
|
4845
|
+
}
|
|
4846
|
+
function mapExecError(error, cwd, argv, behavior) {
|
|
4847
|
+
const execError = error;
|
|
4848
|
+
const stdout = normalizeGitOutput(execError.stdout);
|
|
4849
|
+
const stderr = normalizeGitOutput(execError.stderr);
|
|
4850
|
+
const code = execError.code;
|
|
4851
|
+
const signal = execError.signal;
|
|
4852
|
+
const message = [stderr.trim(), execError.message].filter(Boolean).join("\n");
|
|
4853
|
+
if (code === "ENOENT") {
|
|
4854
|
+
return new GitCommandError("git_not_installed", "Git executable was not found", {
|
|
4855
|
+
stdout,
|
|
4856
|
+
stderr,
|
|
4857
|
+
exitCode: code,
|
|
4858
|
+
signal,
|
|
4859
|
+
argv,
|
|
4860
|
+
cwd,
|
|
4861
|
+
cause: error
|
|
4862
|
+
});
|
|
4863
|
+
}
|
|
4864
|
+
if (execError.killed || /timed out/i.test(execError.message)) {
|
|
4865
|
+
return new GitCommandError("timeout", "Git command timed out", {
|
|
4866
|
+
stdout,
|
|
4867
|
+
stderr,
|
|
4868
|
+
exitCode: code,
|
|
4869
|
+
signal,
|
|
4870
|
+
argv,
|
|
4871
|
+
cwd,
|
|
4872
|
+
cause: error
|
|
4873
|
+
});
|
|
4874
|
+
}
|
|
4875
|
+
if (behavior.mapNotGitRepo && /not a git repository/i.test(stderr + "\n" + execError.message)) {
|
|
4876
|
+
return new GitCommandError("not_git_repo", "Workspace is not a Git repository", {
|
|
4877
|
+
stdout,
|
|
4878
|
+
stderr,
|
|
4879
|
+
exitCode: code,
|
|
4880
|
+
signal,
|
|
4881
|
+
argv,
|
|
4882
|
+
cwd,
|
|
4883
|
+
cause: error
|
|
4884
|
+
});
|
|
4885
|
+
}
|
|
4886
|
+
return new GitCommandError("git_command_failed", message || "Git command failed", {
|
|
4887
|
+
stdout,
|
|
4888
|
+
stderr,
|
|
4889
|
+
exitCode: code,
|
|
4890
|
+
signal,
|
|
4891
|
+
argv,
|
|
4892
|
+
cwd,
|
|
4893
|
+
cause: error
|
|
4894
|
+
});
|
|
4895
|
+
}
|
|
4896
|
+
|
|
4897
|
+
// src/git/git-status.ts
|
|
4898
|
+
async function getGitRepoStatus(workspace, options = {}) {
|
|
4899
|
+
const lastCheckedAt = Date.now();
|
|
4900
|
+
try {
|
|
4901
|
+
const repo = await resolveGitRepository(workspace, options);
|
|
4902
|
+
const statusOutput = await runGit(repo, ["status", "--porcelain=v2", "--branch"], options);
|
|
4903
|
+
const parsed = parsePorcelainV2Status(statusOutput.stdout);
|
|
4904
|
+
const head = await readHead(repo, options);
|
|
4905
|
+
const stashCount = await readStashCount(repo, options);
|
|
4906
|
+
return {
|
|
4907
|
+
workspace: repo.workspace,
|
|
4908
|
+
repoRoot: repo.repoRoot,
|
|
4909
|
+
isGitRepo: true,
|
|
4910
|
+
branch: parsed.branch,
|
|
4911
|
+
headCommit: head.commit,
|
|
4912
|
+
headMessage: head.message,
|
|
4913
|
+
upstream: parsed.upstream,
|
|
4914
|
+
ahead: parsed.ahead,
|
|
4915
|
+
behind: parsed.behind,
|
|
4916
|
+
staged: parsed.staged,
|
|
4917
|
+
modified: parsed.modified,
|
|
4918
|
+
untracked: parsed.untracked,
|
|
4919
|
+
deleted: parsed.deleted,
|
|
4920
|
+
renamed: parsed.renamed,
|
|
4921
|
+
hasConflicts: parsed.conflictFiles.length > 0,
|
|
4922
|
+
conflictFiles: parsed.conflictFiles,
|
|
4923
|
+
stashCount,
|
|
4924
|
+
lastCheckedAt
|
|
4925
|
+
};
|
|
4926
|
+
} catch (error) {
|
|
4927
|
+
if (error instanceof GitCommandError) {
|
|
4928
|
+
return emptyStatus(workspace, lastCheckedAt, error);
|
|
4929
|
+
}
|
|
4930
|
+
return emptyStatus(
|
|
4931
|
+
workspace,
|
|
4932
|
+
lastCheckedAt,
|
|
4933
|
+
new GitCommandError("git_command_failed", "Failed to read Git status", { cause: error })
|
|
4934
|
+
);
|
|
4935
|
+
}
|
|
4936
|
+
}
|
|
4937
|
+
function parsePorcelainV2Status(output) {
|
|
4938
|
+
const parsed = {
|
|
4939
|
+
branch: null,
|
|
4940
|
+
upstream: null,
|
|
4941
|
+
ahead: 0,
|
|
4942
|
+
behind: 0,
|
|
4943
|
+
staged: 0,
|
|
4944
|
+
modified: 0,
|
|
4945
|
+
untracked: 0,
|
|
4946
|
+
deleted: 0,
|
|
4947
|
+
renamed: 0,
|
|
4948
|
+
conflictFiles: []
|
|
4949
|
+
};
|
|
4950
|
+
for (const line of output.split("\n")) {
|
|
4951
|
+
if (!line) continue;
|
|
4952
|
+
if (line.startsWith("# branch.head ")) {
|
|
4953
|
+
const branch = line.slice("# branch.head ".length).trim();
|
|
4954
|
+
parsed.branch = branch && branch !== "(detached)" ? branch : null;
|
|
4955
|
+
continue;
|
|
4956
|
+
}
|
|
4957
|
+
if (line.startsWith("# branch.upstream ")) {
|
|
4958
|
+
parsed.upstream = line.slice("# branch.upstream ".length).trim() || null;
|
|
4959
|
+
continue;
|
|
4960
|
+
}
|
|
4961
|
+
if (line.startsWith("# branch.ab ")) {
|
|
4962
|
+
const match = line.match(/\+(-?\d+)\s+-(-?\d+)/);
|
|
4963
|
+
if (match) {
|
|
4964
|
+
parsed.ahead = Number.parseInt(match[1] ?? "0", 10) || 0;
|
|
4965
|
+
parsed.behind = Number.parseInt(match[2] ?? "0", 10) || 0;
|
|
4966
|
+
}
|
|
4967
|
+
continue;
|
|
4968
|
+
}
|
|
4969
|
+
if (line.startsWith("? ")) {
|
|
4970
|
+
parsed.untracked += 1;
|
|
4971
|
+
continue;
|
|
4972
|
+
}
|
|
4973
|
+
if (line.startsWith("u ")) {
|
|
4974
|
+
const fields = line.split(" ");
|
|
4975
|
+
const filePath = fields.slice(10).join(" ");
|
|
4976
|
+
if (filePath) parsed.conflictFiles.push(filePath);
|
|
4977
|
+
continue;
|
|
4978
|
+
}
|
|
4979
|
+
if (line.startsWith("1 ") || line.startsWith("2 ")) {
|
|
4980
|
+
const fields = line.split(" ");
|
|
4981
|
+
const xy = fields[1] ?? "..";
|
|
4982
|
+
const indexStatus = xy[0] ?? ".";
|
|
4983
|
+
const worktreeStatus = xy[1] ?? ".";
|
|
4984
|
+
if (isStagedStatus(indexStatus)) parsed.staged += 1;
|
|
4985
|
+
if (worktreeStatus === "M" || worktreeStatus === "T") parsed.modified += 1;
|
|
4986
|
+
if (indexStatus === "D" || worktreeStatus === "D") parsed.deleted += 1;
|
|
4987
|
+
if (indexStatus === "R" || worktreeStatus === "R") parsed.renamed += 1;
|
|
4988
|
+
if (xy.includes("U")) {
|
|
4989
|
+
const filePath = fields.slice(line.startsWith("2 ") ? 9 : 8).join(" ").split(" ")[0] ?? "";
|
|
4990
|
+
if (filePath) parsed.conflictFiles.push(filePath);
|
|
4991
|
+
}
|
|
4992
|
+
}
|
|
4993
|
+
}
|
|
4994
|
+
parsed.conflictFiles = Array.from(new Set(parsed.conflictFiles));
|
|
4995
|
+
return parsed;
|
|
4996
|
+
}
|
|
4997
|
+
async function readHead(repo, options) {
|
|
4998
|
+
try {
|
|
4999
|
+
const result = await runGit(repo, ["log", "-1", "--pretty=%h%x00%s"], options);
|
|
5000
|
+
const text = result.stdout.trimEnd();
|
|
5001
|
+
if (!text) return { commit: null, message: null };
|
|
5002
|
+
const [commit, ...messageParts] = text.split("\0");
|
|
5003
|
+
return {
|
|
5004
|
+
commit: commit || null,
|
|
5005
|
+
message: messageParts.join("\0") || null
|
|
5006
|
+
};
|
|
5007
|
+
} catch {
|
|
5008
|
+
return { commit: null, message: null };
|
|
5009
|
+
}
|
|
5010
|
+
}
|
|
5011
|
+
async function readStashCount(repo, options) {
|
|
5012
|
+
try {
|
|
5013
|
+
const result = await runGit(repo, ["stash", "list", "--format=%gd"], options);
|
|
5014
|
+
return result.stdout.split("\n").filter((line) => line.trim().length > 0).length;
|
|
5015
|
+
} catch {
|
|
5016
|
+
return 0;
|
|
5017
|
+
}
|
|
5018
|
+
}
|
|
5019
|
+
function isStagedStatus(status) {
|
|
5020
|
+
return status !== "." && status !== "?" && status !== "U";
|
|
5021
|
+
}
|
|
5022
|
+
function emptyStatus(workspace, lastCheckedAt, error) {
|
|
5023
|
+
return {
|
|
5024
|
+
workspace,
|
|
5025
|
+
repoRoot: null,
|
|
5026
|
+
isGitRepo: false,
|
|
5027
|
+
branch: null,
|
|
5028
|
+
headCommit: null,
|
|
5029
|
+
headMessage: null,
|
|
5030
|
+
upstream: null,
|
|
5031
|
+
ahead: 0,
|
|
5032
|
+
behind: 0,
|
|
5033
|
+
staged: 0,
|
|
5034
|
+
modified: 0,
|
|
5035
|
+
untracked: 0,
|
|
5036
|
+
deleted: 0,
|
|
5037
|
+
renamed: 0,
|
|
5038
|
+
hasConflicts: false,
|
|
5039
|
+
conflictFiles: [],
|
|
5040
|
+
stashCount: 0,
|
|
5041
|
+
lastCheckedAt,
|
|
5042
|
+
error: error.stderr || error.message,
|
|
5043
|
+
reason: error.reason
|
|
5044
|
+
};
|
|
5045
|
+
}
|
|
5046
|
+
|
|
5047
|
+
// src/git/git-diff.ts
|
|
5048
|
+
var import_promises2 = require("fs/promises");
|
|
5049
|
+
var path2 = __toESM(require("path"));
|
|
5050
|
+
var DEFAULT_MAX_FILES = 200;
|
|
5051
|
+
var DEFAULT_MAX_BYTES = 2e5;
|
|
5052
|
+
async function getGitDiffSummary(workspace, options = {}) {
|
|
5053
|
+
const lastCheckedAt = Date.now();
|
|
5054
|
+
try {
|
|
5055
|
+
const repo = await resolveGitRepository(workspace, options);
|
|
5056
|
+
const repoRoot = repo.repoRoot;
|
|
5057
|
+
const [unstagedNameStatus, unstagedNumstat, stagedNameStatus, stagedNumstat, untracked] = await Promise.all([
|
|
5058
|
+
runGit(repo, ["diff", "--no-ext-diff", "--name-status"], { ...options, cwd: repoRoot }),
|
|
5059
|
+
runGit(repo, ["diff", "--no-ext-diff", "--numstat"], { ...options, cwd: repoRoot }),
|
|
5060
|
+
runGit(repo, ["diff", "--cached", "--no-ext-diff", "--name-status"], { ...options, cwd: repoRoot }),
|
|
5061
|
+
runGit(repo, ["diff", "--cached", "--no-ext-diff", "--numstat"], { ...options, cwd: repoRoot }),
|
|
5062
|
+
runGit(repo, ["ls-files", "--others", "--exclude-standard"], { ...options, cwd: repoRoot })
|
|
5063
|
+
]);
|
|
5064
|
+
const outputBytes = byteLength(
|
|
5065
|
+
unstagedNameStatus.stdout + unstagedNumstat.stdout + stagedNameStatus.stdout + stagedNumstat.stdout + untracked.stdout
|
|
5066
|
+
);
|
|
5067
|
+
const changes = [
|
|
5068
|
+
...combineDiffEntries(unstagedNameStatus.stdout, unstagedNumstat.stdout, false),
|
|
5069
|
+
...combineDiffEntries(stagedNameStatus.stdout, stagedNumstat.stdout, true),
|
|
5070
|
+
...parseUntrackedFiles(untracked.stdout)
|
|
5071
|
+
];
|
|
5072
|
+
const maxFiles = normalizePositiveInteger(options.maxFiles, DEFAULT_MAX_FILES);
|
|
5073
|
+
const maxBytes = normalizePositiveInteger(options.maxBytes, DEFAULT_MAX_BYTES);
|
|
5074
|
+
const files = changes.slice(0, maxFiles);
|
|
5075
|
+
const truncated = changes.length > files.length || outputBytes > maxBytes;
|
|
5076
|
+
return {
|
|
5077
|
+
workspace: repo.workspace,
|
|
5078
|
+
repoRoot,
|
|
5079
|
+
isGitRepo: true,
|
|
5080
|
+
files,
|
|
5081
|
+
totalInsertions: files.reduce((sum, file) => sum + file.insertions, 0),
|
|
5082
|
+
totalDeletions: files.reduce((sum, file) => sum + file.deletions, 0),
|
|
5083
|
+
truncated,
|
|
5084
|
+
lastCheckedAt
|
|
5085
|
+
};
|
|
5086
|
+
} catch (error) {
|
|
5087
|
+
const gitError = error instanceof GitCommandError ? error : new GitCommandError("git_command_failed", "Failed to read Git diff summary", { cause: error });
|
|
5088
|
+
return {
|
|
5089
|
+
workspace,
|
|
5090
|
+
repoRoot: null,
|
|
5091
|
+
isGitRepo: false,
|
|
5092
|
+
files: [],
|
|
5093
|
+
totalInsertions: 0,
|
|
5094
|
+
totalDeletions: 0,
|
|
5095
|
+
truncated: false,
|
|
5096
|
+
lastCheckedAt,
|
|
5097
|
+
error: gitError.stderr || gitError.message,
|
|
5098
|
+
reason: gitError.reason
|
|
5099
|
+
};
|
|
5100
|
+
}
|
|
5101
|
+
}
|
|
5102
|
+
async function getGitFileDiff(workspace, filePath, options = {}) {
|
|
5103
|
+
const lastCheckedAt = Date.now();
|
|
5104
|
+
const repo = await resolveGitRepository(workspace, options);
|
|
5105
|
+
const repoRoot = repo.repoRoot;
|
|
5106
|
+
const selected = await resolveRepoFilePath(repoRoot, filePath);
|
|
5107
|
+
const maxBytes = normalizePositiveInteger(options.maxBytes, DEFAULT_MAX_BYTES);
|
|
5108
|
+
const [unstaged, staged] = await Promise.all([
|
|
5109
|
+
runGit(repo, ["diff", "--no-ext-diff", "--", selected.relativePath], { ...options, cwd: repoRoot }),
|
|
5110
|
+
runGit(repo, ["diff", "--cached", "--no-ext-diff", "--", selected.relativePath], { ...options, cwd: repoRoot })
|
|
5111
|
+
]);
|
|
5112
|
+
let diff = [unstaged.stdout, staged.stdout].filter((part) => part.length > 0).join("\n");
|
|
5113
|
+
if (!diff) {
|
|
5114
|
+
const untracked = await runGit(repo, ["ls-files", "--others", "--exclude-standard", "--", selected.relativePath], {
|
|
5115
|
+
...options,
|
|
5116
|
+
cwd: repoRoot
|
|
5117
|
+
});
|
|
5118
|
+
const untrackedFiles = untracked.stdout.split("\n").filter(Boolean);
|
|
5119
|
+
if (untrackedFiles.includes(selected.relativePath)) {
|
|
5120
|
+
diff = await buildUntrackedDiff(selected.absolutePath, selected.relativePath, maxBytes + 1);
|
|
5121
|
+
}
|
|
5122
|
+
}
|
|
5123
|
+
const bounded = truncateText(diff, maxBytes);
|
|
5124
|
+
return {
|
|
5125
|
+
workspace: repo.workspace,
|
|
5126
|
+
repoRoot,
|
|
5127
|
+
isGitRepo: true,
|
|
5128
|
+
path: selected.relativePath,
|
|
5129
|
+
diff: bounded.text,
|
|
5130
|
+
truncated: bounded.truncated,
|
|
5131
|
+
lastCheckedAt
|
|
5132
|
+
};
|
|
5133
|
+
}
|
|
5134
|
+
function combineDiffEntries(nameStatusOutput, numstatOutput, staged) {
|
|
5135
|
+
const statusEntries = parseNameStatus(nameStatusOutput);
|
|
5136
|
+
const numstatEntries = parseNumstat(numstatOutput);
|
|
5137
|
+
return statusEntries.map((entry, index) => {
|
|
5138
|
+
const stats = numstatEntries[index];
|
|
5139
|
+
return {
|
|
5140
|
+
path: entry.path,
|
|
5141
|
+
oldPath: entry.oldPath,
|
|
5142
|
+
status: entry.status,
|
|
5143
|
+
staged,
|
|
5144
|
+
insertions: stats?.insertions ?? 0,
|
|
5145
|
+
deletions: stats?.deletions ?? 0,
|
|
5146
|
+
binary: stats?.binary || void 0
|
|
5147
|
+
};
|
|
5148
|
+
});
|
|
5149
|
+
}
|
|
5150
|
+
function parseNameStatus(output) {
|
|
5151
|
+
return output.split("\n").filter(Boolean).map((line) => {
|
|
5152
|
+
const fields = line.split(" ");
|
|
5153
|
+
const code = fields[0] ?? "";
|
|
5154
|
+
const statusLetter = code[0] ?? "M";
|
|
5155
|
+
if (statusLetter === "R") {
|
|
5156
|
+
return {
|
|
5157
|
+
oldPath: fields[1] ?? "",
|
|
5158
|
+
path: fields[2] ?? fields[1] ?? "",
|
|
5159
|
+
status: "renamed"
|
|
5160
|
+
};
|
|
5161
|
+
}
|
|
5162
|
+
if (statusLetter === "C") {
|
|
5163
|
+
return {
|
|
5164
|
+
oldPath: fields[1] ?? "",
|
|
5165
|
+
path: fields[2] ?? fields[1] ?? "",
|
|
5166
|
+
status: "copied"
|
|
5167
|
+
};
|
|
5168
|
+
}
|
|
5169
|
+
return {
|
|
5170
|
+
path: fields[1] ?? "",
|
|
5171
|
+
status: mapNameStatus(statusLetter)
|
|
5172
|
+
};
|
|
5173
|
+
}).filter((entry) => entry.path.length > 0);
|
|
5174
|
+
}
|
|
5175
|
+
function parseNumstat(output) {
|
|
5176
|
+
return output.split("\n").filter(Boolean).map((line) => {
|
|
5177
|
+
const fields = line.split(" ");
|
|
5178
|
+
const insertionsText = fields[0] ?? "0";
|
|
5179
|
+
const deletionsText = fields[1] ?? "0";
|
|
5180
|
+
const binary = insertionsText === "-" || deletionsText === "-";
|
|
5181
|
+
return {
|
|
5182
|
+
path: fields.slice(2).join(" "),
|
|
5183
|
+
insertions: binary ? 0 : Number.parseInt(insertionsText, 10) || 0,
|
|
5184
|
+
deletions: binary ? 0 : Number.parseInt(deletionsText, 10) || 0,
|
|
5185
|
+
binary
|
|
5186
|
+
};
|
|
5187
|
+
});
|
|
5188
|
+
}
|
|
5189
|
+
function parseUntrackedFiles(output) {
|
|
5190
|
+
return output.split("\n").filter(Boolean).map((filePath) => ({
|
|
5191
|
+
path: filePath,
|
|
5192
|
+
status: "untracked",
|
|
5193
|
+
staged: false,
|
|
5194
|
+
insertions: 0,
|
|
5195
|
+
deletions: 0
|
|
5196
|
+
}));
|
|
5197
|
+
}
|
|
5198
|
+
function mapNameStatus(status) {
|
|
5199
|
+
switch (status) {
|
|
5200
|
+
case "A":
|
|
5201
|
+
return "added";
|
|
5202
|
+
case "D":
|
|
5203
|
+
return "deleted";
|
|
5204
|
+
case "R":
|
|
5205
|
+
return "renamed";
|
|
5206
|
+
case "C":
|
|
5207
|
+
return "copied";
|
|
5208
|
+
case "U":
|
|
5209
|
+
return "conflict";
|
|
5210
|
+
case "M":
|
|
5211
|
+
case "T":
|
|
5212
|
+
default:
|
|
5213
|
+
return "modified";
|
|
5214
|
+
}
|
|
5215
|
+
}
|
|
5216
|
+
async function resolveRepoFilePath(repoRoot, filePath) {
|
|
5217
|
+
if (typeof filePath !== "string" || filePath.length === 0 || filePath.includes("\0")) {
|
|
5218
|
+
throw new GitCommandError("invalid_args", "File path must be a non-empty path");
|
|
5219
|
+
}
|
|
5220
|
+
const canonicalRepoRoot = await (0, import_promises2.realpath)(repoRoot).catch(() => path2.resolve(repoRoot));
|
|
5221
|
+
const absolutePath = path2.isAbsolute(filePath) ? path2.resolve(filePath) : path2.resolve(repoRoot, filePath);
|
|
5222
|
+
const checkPath = await (0, import_promises2.realpath)(absolutePath).catch(() => absolutePath);
|
|
5223
|
+
const relativeBase = isPathInside(canonicalRepoRoot, checkPath) ? canonicalRepoRoot : path2.resolve(repoRoot);
|
|
5224
|
+
if (!isPathInside(canonicalRepoRoot, checkPath) && !isPathInside(repoRoot, absolutePath)) {
|
|
5225
|
+
throw new GitCommandError("path_outside_repo", "Selected file path is outside the repository root", {
|
|
5226
|
+
cwd: repoRoot
|
|
5227
|
+
});
|
|
5228
|
+
}
|
|
5229
|
+
const relativePath = path2.relative(relativeBase, checkPath).split(path2.sep).join("/");
|
|
5230
|
+
if (!relativePath || relativePath.startsWith("..") || path2.isAbsolute(relativePath)) {
|
|
5231
|
+
throw new GitCommandError("path_outside_repo", "Selected file path is outside the repository root", {
|
|
5232
|
+
cwd: repoRoot
|
|
5233
|
+
});
|
|
5234
|
+
}
|
|
5235
|
+
return { absolutePath, relativePath };
|
|
5236
|
+
}
|
|
5237
|
+
async function buildUntrackedDiff(absolutePath, relativePath, readLimit) {
|
|
5238
|
+
const content = await (0, import_promises2.readFile)(absolutePath, "utf8");
|
|
5239
|
+
const limitedContent = content.length > readLimit ? content.slice(0, readLimit) : content;
|
|
5240
|
+
const lines = limitedContent.length > 0 ? limitedContent.split("\n") : [];
|
|
5241
|
+
const plusLines = lines.filter((line, index) => index < lines.length - 1 || line.length > 0).map((line) => `+${line}`).join("\n");
|
|
5242
|
+
const lineCount = plusLines ? plusLines.split("\n").length : 0;
|
|
5243
|
+
return [
|
|
5244
|
+
`diff --git a/${relativePath} b/${relativePath}`,
|
|
5245
|
+
"new file mode 100644",
|
|
5246
|
+
"index 0000000..0000000",
|
|
5247
|
+
"--- /dev/null",
|
|
5248
|
+
`+++ b/${relativePath}`,
|
|
5249
|
+
`@@ -0,0 +1,${lineCount} @@`,
|
|
5250
|
+
plusLines
|
|
5251
|
+
].filter((line) => line.length > 0).join("\n");
|
|
5252
|
+
}
|
|
5253
|
+
function truncateText(text, maxBytes) {
|
|
5254
|
+
if (byteLength(text) <= maxBytes) return { text, truncated: false };
|
|
5255
|
+
return { text: Buffer.from(text, "utf8").subarray(0, maxBytes).toString("utf8"), truncated: true };
|
|
5256
|
+
}
|
|
5257
|
+
function byteLength(text) {
|
|
5258
|
+
return Buffer.byteLength(text, "utf8");
|
|
5259
|
+
}
|
|
5260
|
+
function normalizePositiveInteger(value, fallback) {
|
|
5261
|
+
if (!Number.isFinite(value) || value == null || value <= 0) return fallback;
|
|
5262
|
+
return Math.floor(value);
|
|
5263
|
+
}
|
|
5264
|
+
|
|
5265
|
+
// src/git/git-summary.ts
|
|
5266
|
+
function countStatusChangedFiles(status) {
|
|
5267
|
+
const conflictCount = status.conflictFiles.length > 0 ? status.conflictFiles.length : status.hasConflicts ? 1 : 0;
|
|
5268
|
+
return status.staged + status.modified + status.untracked + status.deleted + status.renamed + conflictCount;
|
|
5269
|
+
}
|
|
5270
|
+
function createGitCompactSummary(status, diffSummary) {
|
|
5271
|
+
const statusChangedFiles = countStatusChangedFiles(status);
|
|
5272
|
+
const diffChangedFiles = diffSummary?.files.length ?? 0;
|
|
5273
|
+
const changedFiles = Math.max(statusChangedFiles, diffChangedFiles);
|
|
5274
|
+
const conflictCount = status.conflictFiles.length > 0 ? status.conflictFiles.length : status.hasConflicts ? 1 : 0;
|
|
5275
|
+
return {
|
|
5276
|
+
isGitRepo: status.isGitRepo,
|
|
5277
|
+
repoRoot: status.repoRoot,
|
|
5278
|
+
branch: status.branch,
|
|
5279
|
+
dirty: status.staged > 0 || status.modified > 0 || status.untracked > 0 || status.deleted > 0 || status.renamed > 0 || conflictCount > 0 || changedFiles > 0,
|
|
5280
|
+
changedFiles,
|
|
5281
|
+
ahead: status.ahead,
|
|
5282
|
+
behind: status.behind,
|
|
5283
|
+
hasConflicts: status.hasConflicts || conflictCount > 0,
|
|
5284
|
+
lastCheckedAt: Math.max(status.lastCheckedAt, diffSummary?.lastCheckedAt ?? status.lastCheckedAt),
|
|
5285
|
+
error: status.error ?? diffSummary?.error,
|
|
5286
|
+
reason: status.reason ?? diffSummary?.reason
|
|
5287
|
+
};
|
|
5288
|
+
}
|
|
5289
|
+
var summarizeGitStatus = createGitCompactSummary;
|
|
5290
|
+
|
|
5291
|
+
// src/git/git-snapshot-store.ts
|
|
5292
|
+
function normalizeCapacity(capacity) {
|
|
5293
|
+
return Math.max(1, Math.floor(capacity ?? 100));
|
|
5294
|
+
}
|
|
5295
|
+
function createEmptyDiffSummary(status) {
|
|
5296
|
+
return {
|
|
5297
|
+
workspace: status.workspace,
|
|
5298
|
+
repoRoot: status.repoRoot,
|
|
5299
|
+
isGitRepo: status.isGitRepo,
|
|
5300
|
+
files: [],
|
|
5301
|
+
totalInsertions: 0,
|
|
5302
|
+
totalDeletions: 0,
|
|
5303
|
+
truncated: false,
|
|
5304
|
+
lastCheckedAt: status.lastCheckedAt,
|
|
5305
|
+
error: status.error,
|
|
5306
|
+
reason: status.reason
|
|
5307
|
+
};
|
|
5308
|
+
}
|
|
5309
|
+
function changedFileKey(file) {
|
|
5310
|
+
return `${file.oldPath ?? ""}\0${file.path}`;
|
|
5311
|
+
}
|
|
5312
|
+
function uniqueSorted(values) {
|
|
5313
|
+
return Array.from(new Set(Array.from(values).filter(Boolean))).sort((a, b) => a.localeCompare(b));
|
|
5314
|
+
}
|
|
5315
|
+
function plural(count, singular, pluralText = `${singular}s`) {
|
|
5316
|
+
return count === 1 ? singular : pluralText;
|
|
5317
|
+
}
|
|
5318
|
+
function compareGitSnapshots(before, after) {
|
|
5319
|
+
const beforeFileKeys = new Set(before.diffSummary.files.map(changedFileKey));
|
|
5320
|
+
const changedAfterFiles = after.diffSummary.files.filter((file) => !beforeFileKeys.has(changedFileKey(file)));
|
|
5321
|
+
const addedFiles = [];
|
|
5322
|
+
const modifiedFiles = [];
|
|
5323
|
+
const deletedFiles = [];
|
|
5324
|
+
const renamedFiles = [];
|
|
5325
|
+
const untrackedFiles = [];
|
|
5326
|
+
const conflictFilesFromDiff = [];
|
|
5327
|
+
let totalInsertions = 0;
|
|
5328
|
+
let totalDeletions = 0;
|
|
5329
|
+
for (const file of changedAfterFiles) {
|
|
5330
|
+
totalInsertions += file.insertions;
|
|
5331
|
+
totalDeletions += file.deletions;
|
|
5332
|
+
switch (file.status) {
|
|
5333
|
+
case "added":
|
|
5334
|
+
case "copied":
|
|
5335
|
+
addedFiles.push(file.path);
|
|
5336
|
+
break;
|
|
5337
|
+
case "modified":
|
|
5338
|
+
modifiedFiles.push(file.path);
|
|
5339
|
+
break;
|
|
5340
|
+
case "deleted":
|
|
5341
|
+
deletedFiles.push(file.path);
|
|
5342
|
+
break;
|
|
5343
|
+
case "renamed":
|
|
5344
|
+
renamedFiles.push({ oldPath: file.oldPath ?? file.path, path: file.path });
|
|
5345
|
+
break;
|
|
5346
|
+
case "untracked":
|
|
5347
|
+
untrackedFiles.push(file.path);
|
|
5348
|
+
break;
|
|
5349
|
+
case "conflict":
|
|
5350
|
+
conflictFilesFromDiff.push(file.path);
|
|
5351
|
+
break;
|
|
5352
|
+
}
|
|
5353
|
+
}
|
|
5354
|
+
renamedFiles.sort((a, b) => `${a.oldPath}\0${a.path}`.localeCompare(`${b.oldPath}\0${b.path}`));
|
|
5355
|
+
const conflictFiles = uniqueSorted([...after.status.conflictFiles, ...conflictFilesFromDiff]);
|
|
5356
|
+
const changedFiles = changedAfterFiles.length;
|
|
5357
|
+
const hasConflicts = after.status.hasConflicts || conflictFiles.length > 0;
|
|
5358
|
+
const summaryParts = [];
|
|
5359
|
+
if (changedFiles > 0) summaryParts.push(`${changedFiles} ${plural(changedFiles, "file")} changed`);
|
|
5360
|
+
if (addedFiles.length > 0) summaryParts.push(`${addedFiles.length} added`);
|
|
5361
|
+
if (modifiedFiles.length > 0) summaryParts.push(`${modifiedFiles.length} modified`);
|
|
5362
|
+
if (deletedFiles.length > 0) summaryParts.push(`${deletedFiles.length} deleted`);
|
|
5363
|
+
if (renamedFiles.length > 0) summaryParts.push(`${renamedFiles.length} renamed`);
|
|
5364
|
+
if (untrackedFiles.length > 0) summaryParts.push(`${untrackedFiles.length} untracked`);
|
|
5365
|
+
if (hasConflicts) summaryParts.push(`${conflictFiles.length || 1} ${plural(conflictFiles.length || 1, "conflict")}`);
|
|
5366
|
+
return {
|
|
5367
|
+
beforeSnapshotId: before.id,
|
|
5368
|
+
afterSnapshotId: after.id,
|
|
5369
|
+
workspace: after.workspace,
|
|
5370
|
+
repoRoot: after.repoRoot,
|
|
5371
|
+
changedFiles,
|
|
5372
|
+
addedFiles: uniqueSorted(addedFiles),
|
|
5373
|
+
modifiedFiles: uniqueSorted(modifiedFiles),
|
|
5374
|
+
deletedFiles: uniqueSorted(deletedFiles),
|
|
5375
|
+
renamedFiles,
|
|
5376
|
+
untrackedFiles: uniqueSorted(untrackedFiles),
|
|
5377
|
+
conflictFiles,
|
|
5378
|
+
totalInsertions,
|
|
5379
|
+
totalDeletions,
|
|
5380
|
+
hasConflicts,
|
|
5381
|
+
currentStatus: after.status,
|
|
5382
|
+
summaryText: summaryParts.length > 0 ? summaryParts.join(", ") : "No file-set changes between snapshots."
|
|
5383
|
+
};
|
|
5384
|
+
}
|
|
5385
|
+
var InMemoryGitSnapshotStore = class {
|
|
5386
|
+
snapshots = /* @__PURE__ */ new Map();
|
|
5387
|
+
order = [];
|
|
5388
|
+
capacity;
|
|
5389
|
+
now;
|
|
5390
|
+
idPrefix;
|
|
5391
|
+
getStatusProvider;
|
|
5392
|
+
getDiffSummaryProvider;
|
|
5393
|
+
counter = 0;
|
|
5394
|
+
constructor(options = {}) {
|
|
5395
|
+
this.capacity = normalizeCapacity(options.capacity);
|
|
5396
|
+
this.now = options.now ?? Date.now;
|
|
5397
|
+
this.idPrefix = options.idPrefix ?? "git-snapshot";
|
|
5398
|
+
this.getStatusProvider = options.getStatus;
|
|
5399
|
+
this.getDiffSummaryProvider = options.getDiffSummary;
|
|
5400
|
+
}
|
|
5401
|
+
async create(input) {
|
|
5402
|
+
const getStatus = input.getStatus ?? this.getStatusProvider;
|
|
5403
|
+
if (!getStatus) {
|
|
5404
|
+
throw new Error("GitSnapshotStore requires an injected getStatus provider");
|
|
5405
|
+
}
|
|
5406
|
+
const status = await getStatus(input.workspace);
|
|
5407
|
+
const getDiffSummary = input.getDiffSummary ?? this.getDiffSummaryProvider;
|
|
5408
|
+
const diffSummary = getDiffSummary ? await getDiffSummary(input.workspace, status) : createEmptyDiffSummary(status);
|
|
5409
|
+
const createdAt = this.now();
|
|
5410
|
+
const id = `${this.idPrefix}-${createdAt}-${++this.counter}`;
|
|
5411
|
+
const snapshot = {
|
|
5412
|
+
id,
|
|
5413
|
+
workspace: input.workspace,
|
|
5414
|
+
repoRoot: status.repoRoot ?? input.workspace,
|
|
5415
|
+
sessionId: input.sessionId,
|
|
5416
|
+
turnId: input.turnId,
|
|
5417
|
+
reason: input.reason,
|
|
5418
|
+
status,
|
|
5419
|
+
diffSummary,
|
|
5420
|
+
createdAt
|
|
5421
|
+
};
|
|
5422
|
+
this.snapshots.set(id, snapshot);
|
|
5423
|
+
this.order.push(id);
|
|
5424
|
+
this.enforceCapacity();
|
|
5425
|
+
return snapshot;
|
|
5426
|
+
}
|
|
5427
|
+
get(id) {
|
|
5428
|
+
return this.snapshots.get(id);
|
|
5429
|
+
}
|
|
5430
|
+
compare(beforeSnapshotId, afterSnapshotId) {
|
|
5431
|
+
const before = this.snapshots.get(beforeSnapshotId);
|
|
5432
|
+
if (!before) throw new Error(`Unknown before snapshot: ${beforeSnapshotId}`);
|
|
5433
|
+
const after = this.snapshots.get(afterSnapshotId);
|
|
5434
|
+
if (!after) throw new Error(`Unknown after snapshot: ${afterSnapshotId}`);
|
|
5435
|
+
return compareGitSnapshots(before, after);
|
|
5436
|
+
}
|
|
5437
|
+
list(query = {}) {
|
|
5438
|
+
const limit = Math.max(1, Math.floor(query.limit ?? this.capacity));
|
|
5439
|
+
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);
|
|
5440
|
+
}
|
|
5441
|
+
clear() {
|
|
5442
|
+
this.snapshots.clear();
|
|
5443
|
+
this.order.splice(0, this.order.length);
|
|
5444
|
+
}
|
|
5445
|
+
enforceCapacity() {
|
|
5446
|
+
while (this.order.length > this.capacity) {
|
|
5447
|
+
const evictedId = this.order.shift();
|
|
5448
|
+
if (evictedId) this.snapshots.delete(evictedId);
|
|
5449
|
+
}
|
|
5450
|
+
}
|
|
5451
|
+
};
|
|
5452
|
+
function createGitSnapshotStore(options = {}) {
|
|
5453
|
+
return new InMemoryGitSnapshotStore(options);
|
|
5454
|
+
}
|
|
5455
|
+
|
|
5456
|
+
// src/git/git-monitor.ts
|
|
5457
|
+
var DEFAULT_GIT_WORKSPACE_POLL_INTERVAL_MS = 5e3;
|
|
5458
|
+
var MIN_GIT_WORKSPACE_POLL_INTERVAL_MS = 1e3;
|
|
5459
|
+
function defaultStatusProvider(workspace) {
|
|
5460
|
+
return getGitRepoStatus(workspace);
|
|
5461
|
+
}
|
|
5462
|
+
function defaultDiffSummaryProvider(workspace) {
|
|
5463
|
+
return getGitDiffSummary(workspace);
|
|
5464
|
+
}
|
|
5465
|
+
function normalizeIntervalMs(value, defaultIntervalMs, minIntervalMs) {
|
|
5466
|
+
const requested = Number.isFinite(value) ? Math.floor(value) : defaultIntervalMs;
|
|
5467
|
+
return Math.max(minIntervalMs, requested > 0 ? requested : defaultIntervalMs);
|
|
5468
|
+
}
|
|
5469
|
+
function normalizeGitWorkspaceSubscriptionParams(params, options = {}) {
|
|
5470
|
+
const minIntervalMs = Math.max(1, Math.floor(options.minIntervalMs ?? MIN_GIT_WORKSPACE_POLL_INTERVAL_MS));
|
|
5471
|
+
const defaultIntervalMs = Math.max(minIntervalMs, Math.floor(options.defaultIntervalMs ?? DEFAULT_GIT_WORKSPACE_POLL_INTERVAL_MS));
|
|
5472
|
+
return {
|
|
5473
|
+
workspace: params.workspace,
|
|
5474
|
+
includeDiffSummary: Boolean(params.includeDiffSummary),
|
|
5475
|
+
intervalMs: normalizeIntervalMs(params.intervalMs, defaultIntervalMs, minIntervalMs)
|
|
5476
|
+
};
|
|
5477
|
+
}
|
|
5478
|
+
var GitWorkspaceMonitor = class {
|
|
5479
|
+
getStatusProvider;
|
|
5480
|
+
getDiffSummaryProvider;
|
|
5481
|
+
now;
|
|
5482
|
+
minIntervalMs;
|
|
5483
|
+
defaultIntervalMs;
|
|
5484
|
+
keyPrefix;
|
|
5485
|
+
cache = /* @__PURE__ */ new Map();
|
|
5486
|
+
listeners = /* @__PURE__ */ new Set();
|
|
5487
|
+
seq = 0;
|
|
5488
|
+
constructor(options = {}) {
|
|
5489
|
+
this.getStatusProvider = options.getStatus ?? defaultStatusProvider;
|
|
5490
|
+
this.getDiffSummaryProvider = options.getDiffSummary ?? defaultDiffSummaryProvider;
|
|
5491
|
+
this.now = options.now ?? Date.now;
|
|
5492
|
+
this.minIntervalMs = Math.max(1, Math.floor(options.minIntervalMs ?? MIN_GIT_WORKSPACE_POLL_INTERVAL_MS));
|
|
5493
|
+
this.defaultIntervalMs = Math.max(
|
|
5494
|
+
this.minIntervalMs,
|
|
5495
|
+
Math.floor(options.defaultIntervalMs ?? DEFAULT_GIT_WORKSPACE_POLL_INTERVAL_MS)
|
|
5496
|
+
);
|
|
5497
|
+
this.keyPrefix = options.keyPrefix ?? "git";
|
|
5498
|
+
}
|
|
5499
|
+
async refresh(params) {
|
|
5500
|
+
const normalized = this.normalize(typeof params === "string" ? { workspace: params } : params);
|
|
5501
|
+
const status = await this.getStatusProvider(normalized.workspace);
|
|
5502
|
+
const diffSummary = normalized.includeDiffSummary ? await this.getDiffSummaryProvider(normalized.workspace, status) : void 0;
|
|
5503
|
+
const compactSummary = createGitCompactSummary(status, diffSummary);
|
|
5504
|
+
const timestamp = this.now();
|
|
5505
|
+
const seq = ++this.seq;
|
|
5506
|
+
const key = this.keyForWorkspace(normalized.workspace);
|
|
5507
|
+
const update = {
|
|
5508
|
+
topic: "workspace.git",
|
|
5509
|
+
key,
|
|
5510
|
+
workspace: normalized.workspace,
|
|
5511
|
+
status,
|
|
5512
|
+
diffSummary,
|
|
5513
|
+
seq,
|
|
5514
|
+
timestamp
|
|
5515
|
+
};
|
|
5516
|
+
const cacheEntry = {
|
|
5517
|
+
key,
|
|
5518
|
+
workspace: normalized.workspace,
|
|
5519
|
+
status,
|
|
5520
|
+
diffSummary,
|
|
5521
|
+
compactSummary,
|
|
5522
|
+
seq,
|
|
5523
|
+
timestamp
|
|
5524
|
+
};
|
|
5525
|
+
this.cache.set(normalized.workspace, cacheEntry);
|
|
5526
|
+
this.emit(update, cacheEntry);
|
|
5527
|
+
return update;
|
|
5528
|
+
}
|
|
5529
|
+
poll(params) {
|
|
5530
|
+
return this.refresh(params);
|
|
5531
|
+
}
|
|
5532
|
+
getCached(workspace) {
|
|
5533
|
+
return this.cache.get(workspace);
|
|
5534
|
+
}
|
|
5535
|
+
getCompactSummary(workspace) {
|
|
5536
|
+
return this.cache.get(workspace)?.compactSummary;
|
|
5537
|
+
}
|
|
5538
|
+
onUpdate(listener) {
|
|
5539
|
+
this.listeners.add(listener);
|
|
5540
|
+
return () => {
|
|
5541
|
+
this.listeners.delete(listener);
|
|
5542
|
+
};
|
|
5543
|
+
}
|
|
5544
|
+
createSubscription(params, listener) {
|
|
5545
|
+
const normalized = this.normalize(params);
|
|
5546
|
+
const scopedListener = listener ? (update, cacheEntry) => {
|
|
5547
|
+
if (update.workspace === normalized.workspace) listener(update, cacheEntry);
|
|
5548
|
+
} : void 0;
|
|
5549
|
+
const unsubscribe = scopedListener ? this.onUpdate(scopedListener) : () => void 0;
|
|
5550
|
+
return {
|
|
5551
|
+
params: normalized,
|
|
5552
|
+
refresh: () => this.refresh(normalized),
|
|
5553
|
+
getCached: () => this.getCached(normalized.workspace),
|
|
5554
|
+
dispose: unsubscribe
|
|
5555
|
+
};
|
|
5556
|
+
}
|
|
5557
|
+
normalize(params) {
|
|
5558
|
+
return normalizeGitWorkspaceSubscriptionParams(params, {
|
|
5559
|
+
defaultIntervalMs: this.defaultIntervalMs,
|
|
5560
|
+
minIntervalMs: this.minIntervalMs
|
|
5561
|
+
});
|
|
5562
|
+
}
|
|
5563
|
+
keyForWorkspace(workspace) {
|
|
5564
|
+
return `${this.keyPrefix}:${workspace}`;
|
|
5565
|
+
}
|
|
5566
|
+
emit(update, cacheEntry) {
|
|
5567
|
+
for (const listener of this.listeners) {
|
|
5568
|
+
listener(update, cacheEntry);
|
|
5569
|
+
}
|
|
5570
|
+
}
|
|
5571
|
+
};
|
|
5572
|
+
function createGitWorkspaceMonitor(options = {}) {
|
|
5573
|
+
return new GitWorkspaceMonitor(options);
|
|
5574
|
+
}
|
|
5575
|
+
|
|
5576
|
+
// src/git/git-commands.ts
|
|
5577
|
+
var path3 = __toESM(require("path"));
|
|
5578
|
+
var GIT_COMMAND_NAMES = /* @__PURE__ */ new Set([
|
|
5579
|
+
"git_status",
|
|
5580
|
+
"git_diff_summary",
|
|
5581
|
+
"git_diff_file",
|
|
5582
|
+
"git_snapshot_create",
|
|
5583
|
+
"git_snapshot_compare",
|
|
5584
|
+
"git_log",
|
|
5585
|
+
"git_checkpoint",
|
|
5586
|
+
"git_stash_push",
|
|
5587
|
+
"git_stash_pop",
|
|
5588
|
+
"git_checkout_files"
|
|
5589
|
+
]);
|
|
5590
|
+
var MUTATING_COMMAND_NAMES = /* @__PURE__ */ new Set([
|
|
5591
|
+
"git_checkpoint",
|
|
5592
|
+
"git_stash_push",
|
|
5593
|
+
"git_stash_pop",
|
|
5594
|
+
"git_checkout_files"
|
|
5595
|
+
]);
|
|
5596
|
+
var SNAPSHOT_REASONS = /* @__PURE__ */ new Set([
|
|
5597
|
+
"session_baseline",
|
|
5598
|
+
"before_user_input_dispatch",
|
|
5599
|
+
"before_agent_work",
|
|
5600
|
+
"after_agent_work",
|
|
5601
|
+
"manual"
|
|
5602
|
+
]);
|
|
5603
|
+
var FAILURE_REASONS = /* @__PURE__ */ new Set([
|
|
5604
|
+
"not_git_repo",
|
|
5605
|
+
"git_not_installed",
|
|
5606
|
+
"timeout",
|
|
5607
|
+
"path_outside_repo",
|
|
5608
|
+
"dirty_index_required",
|
|
5609
|
+
"conflict",
|
|
5610
|
+
"invalid_args",
|
|
5611
|
+
"git_command_failed"
|
|
5612
|
+
]);
|
|
5613
|
+
function failure(reason, error) {
|
|
5614
|
+
return { success: false, reason, error };
|
|
5615
|
+
}
|
|
5616
|
+
function serviceNotImplemented(command) {
|
|
5617
|
+
return failure("invalid_args", `${command} is not implemented: daemon-core Git service is not configured`);
|
|
5618
|
+
}
|
|
5619
|
+
var defaultSnapshotStore = createGitSnapshotStore({
|
|
5620
|
+
getStatus: (workspace) => getGitRepoStatus(workspace),
|
|
5621
|
+
getDiffSummary: (workspace) => getGitDiffSummary(workspace)
|
|
5622
|
+
});
|
|
5623
|
+
function createDefaultGitCommandServices() {
|
|
5624
|
+
return {
|
|
5625
|
+
getStatus: ({ workspace }) => getGitRepoStatus(workspace),
|
|
5626
|
+
getDiffSummary: ({ workspace }) => getGitDiffSummary(workspace),
|
|
5627
|
+
getDiffFile: ({ workspace, path: filePath }) => getGitFileDiff(workspace, filePath),
|
|
5628
|
+
createSnapshot: ({ workspace, reason, sessionId, turnId }) => defaultSnapshotStore.create({
|
|
5629
|
+
workspace,
|
|
5630
|
+
reason,
|
|
5631
|
+
sessionId,
|
|
5632
|
+
turnId
|
|
5633
|
+
}),
|
|
5634
|
+
compareSnapshots: ({ beforeSnapshotId, afterSnapshotId }) => defaultSnapshotStore.compare(beforeSnapshotId, afterSnapshotId),
|
|
5635
|
+
getLog: ({ workspace, limit, path: filePath, since, until }) => getGitLog(workspace, { limit, path: filePath, since, until })
|
|
5636
|
+
};
|
|
5637
|
+
}
|
|
5638
|
+
var defaultGitCommandServices = createDefaultGitCommandServices();
|
|
5639
|
+
function validateWorkspace2(args) {
|
|
5640
|
+
if (typeof args?.workspace !== "string") {
|
|
5641
|
+
return failure("invalid_args", "workspace must be a non-empty absolute path");
|
|
5642
|
+
}
|
|
5643
|
+
const workspace = args.workspace.trim();
|
|
5644
|
+
if (!workspace || !path3.isAbsolute(workspace)) {
|
|
5645
|
+
return failure("invalid_args", "workspace must be a non-empty absolute path");
|
|
5646
|
+
}
|
|
5647
|
+
return { workspace };
|
|
5648
|
+
}
|
|
5649
|
+
function validateRepoPath(args) {
|
|
5650
|
+
if (typeof args?.path !== "string" || !args.path.trim()) {
|
|
5651
|
+
return failure("invalid_args", "path must be a non-empty repository-relative path");
|
|
5652
|
+
}
|
|
5653
|
+
return { path: args.path.trim() };
|
|
5654
|
+
}
|
|
5655
|
+
function validateSnapshotId(args, key) {
|
|
5656
|
+
if (typeof args?.[key] !== "string" || !args[key].trim()) {
|
|
5657
|
+
return failure("invalid_args", `${key} must be a non-empty string`);
|
|
5658
|
+
}
|
|
5659
|
+
return args[key].trim();
|
|
5660
|
+
}
|
|
5661
|
+
function parseSnapshotReason(args) {
|
|
5662
|
+
if (args?.reason === void 0 || args?.reason === null || args?.reason === "") {
|
|
5663
|
+
return "manual";
|
|
5664
|
+
}
|
|
5665
|
+
if (typeof args.reason !== "string" || !SNAPSHOT_REASONS.has(args.reason)) {
|
|
5666
|
+
return failure("invalid_args", "reason must be a valid GitSnapshotReason");
|
|
5667
|
+
}
|
|
5668
|
+
return args.reason;
|
|
5669
|
+
}
|
|
5670
|
+
function optionalString(value) {
|
|
5671
|
+
return typeof value === "string" && value.trim() ? value.trim() : void 0;
|
|
5672
|
+
}
|
|
5673
|
+
function optionalBoolean(value) {
|
|
5674
|
+
return typeof value === "boolean" ? value : void 0;
|
|
5675
|
+
}
|
|
5676
|
+
function boundedLogLimit(value) {
|
|
5677
|
+
if (value === void 0 || value === null || value === "") return 50;
|
|
5678
|
+
const numeric = typeof value === "number" ? value : Number(value);
|
|
5679
|
+
if (!Number.isFinite(numeric)) return 50;
|
|
5680
|
+
return Math.max(1, Math.min(200, Math.floor(numeric)));
|
|
5681
|
+
}
|
|
5682
|
+
function failureReasonFromError(error) {
|
|
5683
|
+
return typeof error?.reason === "string" && FAILURE_REASONS.has(error.reason) ? error.reason : "git_command_failed";
|
|
5684
|
+
}
|
|
5685
|
+
async function runService(fn) {
|
|
5686
|
+
try {
|
|
5687
|
+
return await fn();
|
|
5688
|
+
} catch (error) {
|
|
5689
|
+
return failure(failureReasonFromError(error), error?.message || "Git command failed");
|
|
5690
|
+
}
|
|
5691
|
+
}
|
|
5692
|
+
function isGitCommandName(command) {
|
|
5693
|
+
return GIT_COMMAND_NAMES.has(command);
|
|
5694
|
+
}
|
|
5695
|
+
async function handleGitCommand(command, args, services = defaultGitCommandServices) {
|
|
5696
|
+
if (!isGitCommandName(command)) {
|
|
5697
|
+
return failure("invalid_args", `Unknown Git command: ${command}`);
|
|
5698
|
+
}
|
|
5699
|
+
if (MUTATING_COMMAND_NAMES.has(command)) {
|
|
5700
|
+
return failure("invalid_args", `${command} is not implemented in daemon-core read-only Git routing`);
|
|
5701
|
+
}
|
|
5702
|
+
const workspaceResult = validateWorkspace2(args);
|
|
5703
|
+
if ("success" in workspaceResult) return workspaceResult;
|
|
5704
|
+
const { workspace } = workspaceResult;
|
|
5705
|
+
switch (command) {
|
|
5706
|
+
case "git_status": {
|
|
5707
|
+
if (!services.getStatus) return serviceNotImplemented(command);
|
|
5708
|
+
const status = await runService(() => services.getStatus({ workspace }));
|
|
5709
|
+
return "success" in status ? status : { success: true, status };
|
|
5710
|
+
}
|
|
5711
|
+
case "git_diff_summary": {
|
|
5712
|
+
if (!services.getDiffSummary) return serviceNotImplemented(command);
|
|
5713
|
+
const diffSummary = await runService(() => services.getDiffSummary({ workspace, staged: optionalBoolean(args?.staged) }));
|
|
5714
|
+
return "success" in diffSummary ? diffSummary : { success: true, diffSummary };
|
|
5715
|
+
}
|
|
5716
|
+
case "git_diff_file": {
|
|
5717
|
+
if (!services.getDiffFile) return serviceNotImplemented(command);
|
|
5718
|
+
const pathResult = validateRepoPath(args);
|
|
5719
|
+
if (typeof pathResult !== "object" || "success" in pathResult) return pathResult;
|
|
5720
|
+
const diff = await runService(() => services.getDiffFile({
|
|
5721
|
+
workspace,
|
|
5722
|
+
path: pathResult.path,
|
|
5723
|
+
staged: optionalBoolean(args?.staged)
|
|
5724
|
+
}));
|
|
5725
|
+
return "success" in diff ? diff : { success: true, diff };
|
|
5726
|
+
}
|
|
5727
|
+
case "git_snapshot_create": {
|
|
5728
|
+
if (!services.createSnapshot) return serviceNotImplemented(command);
|
|
5729
|
+
const reason = parseSnapshotReason(args);
|
|
5730
|
+
if (typeof reason !== "string") return reason;
|
|
5731
|
+
const snapshot = await runService(() => services.createSnapshot({
|
|
5732
|
+
workspace,
|
|
5733
|
+
reason,
|
|
5734
|
+
sessionId: optionalString(args?.sessionId),
|
|
5735
|
+
turnId: optionalString(args?.turnId)
|
|
5736
|
+
}));
|
|
5737
|
+
return "success" in snapshot ? snapshot : { success: true, snapshot };
|
|
5738
|
+
}
|
|
5739
|
+
case "git_snapshot_compare": {
|
|
5740
|
+
if (!services.compareSnapshots) return serviceNotImplemented(command);
|
|
5741
|
+
const beforeSnapshotId = validateSnapshotId(args, "beforeSnapshotId");
|
|
5742
|
+
if (typeof beforeSnapshotId !== "string") return beforeSnapshotId;
|
|
5743
|
+
const afterSnapshotId = validateSnapshotId(args, "afterSnapshotId");
|
|
5744
|
+
if (typeof afterSnapshotId !== "string") return afterSnapshotId;
|
|
5745
|
+
const compare = await runService(() => services.compareSnapshots({ workspace, beforeSnapshotId, afterSnapshotId }));
|
|
5746
|
+
return "success" in compare ? compare : { success: true, compare };
|
|
5747
|
+
}
|
|
5748
|
+
case "git_log": {
|
|
5749
|
+
if (!services.getLog) {
|
|
5750
|
+
return failure("invalid_args", "git_log is not implemented: bounded daemon-core Git log service is not configured");
|
|
5751
|
+
}
|
|
5752
|
+
const log = await runService(() => services.getLog({
|
|
5753
|
+
workspace,
|
|
5754
|
+
limit: boundedLogLimit(args?.limit),
|
|
5755
|
+
path: optionalString(args?.path),
|
|
5756
|
+
since: optionalString(args?.since),
|
|
5757
|
+
until: optionalString(args?.until)
|
|
5758
|
+
}));
|
|
5759
|
+
return "success" in log ? log : { success: true, log };
|
|
5760
|
+
}
|
|
5761
|
+
default:
|
|
5762
|
+
return failure("invalid_args", `Unknown Git command: ${command}`);
|
|
5763
|
+
}
|
|
5764
|
+
}
|
|
5765
|
+
function formatOptionalGitLogRangeArg(flag, value) {
|
|
5766
|
+
return value ? [`${flag}=${value}`] : [];
|
|
5767
|
+
}
|
|
5768
|
+
async function getGitLog(workspace, options) {
|
|
5769
|
+
const lastCheckedAt = Date.now();
|
|
5770
|
+
const repo = await resolveGitRepository(workspace);
|
|
5771
|
+
const repoRoot = repo.repoRoot;
|
|
5772
|
+
const boundedLimit = Math.max(1, Math.min(200, Math.floor(options.limit || 50)));
|
|
5773
|
+
const selectedPath = options.path ? validateGitLogPath(repoRoot, options.path) : void 0;
|
|
5774
|
+
const result = await runGit(
|
|
5775
|
+
repo,
|
|
5776
|
+
[
|
|
5777
|
+
"log",
|
|
5778
|
+
`--max-count=${boundedLimit}`,
|
|
5779
|
+
"--format=%H%x00%an%x00%ae%x00%at%x00%ct%x00%s",
|
|
5780
|
+
...formatOptionalGitLogRangeArg("--since", options.since),
|
|
5781
|
+
...formatOptionalGitLogRangeArg("--until", options.until),
|
|
5782
|
+
"--",
|
|
5783
|
+
...selectedPath ? [selectedPath] : []
|
|
5784
|
+
],
|
|
5785
|
+
{ cwd: repoRoot }
|
|
5786
|
+
);
|
|
5787
|
+
const entries = result.stdout.split("\n").filter((line) => line.trim().length > 0).map((line) => {
|
|
5788
|
+
const [commit = "", authorName, authorEmail, authoredAt, committedAt, ...messageParts] = line.split("\0");
|
|
5789
|
+
return {
|
|
5790
|
+
commit,
|
|
5791
|
+
message: messageParts.join("\0"),
|
|
5792
|
+
authorName: authorName || void 0,
|
|
5793
|
+
authorEmail: authorEmail || void 0,
|
|
5794
|
+
authoredAt: authoredAt ? Number.parseInt(authoredAt, 10) * 1e3 : void 0,
|
|
5795
|
+
committedAt: committedAt ? Number.parseInt(committedAt, 10) * 1e3 : void 0
|
|
5796
|
+
};
|
|
5797
|
+
}).filter((entry) => entry.commit.length > 0);
|
|
5798
|
+
return {
|
|
5799
|
+
workspace: repo.workspace,
|
|
5800
|
+
repoRoot,
|
|
5801
|
+
isGitRepo: true,
|
|
5802
|
+
entries,
|
|
5803
|
+
limit: boundedLimit,
|
|
5804
|
+
truncated: entries.length >= boundedLimit,
|
|
5805
|
+
lastCheckedAt
|
|
5806
|
+
};
|
|
5807
|
+
}
|
|
5808
|
+
function validateGitLogPath(repoRoot, filePath) {
|
|
5809
|
+
if (!filePath.trim() || filePath.includes("\0")) {
|
|
5810
|
+
throw new GitCommandError("invalid_args", "path must be a non-empty repository-relative path");
|
|
5811
|
+
}
|
|
5812
|
+
if (path3.isAbsolute(filePath)) {
|
|
5813
|
+
throw new GitCommandError("invalid_args", "path must be repository-relative");
|
|
5814
|
+
}
|
|
5815
|
+
const normalized = path3.normalize(filePath).split(path3.sep).join("/");
|
|
5816
|
+
const absolutePath = path3.resolve(repoRoot, normalized);
|
|
5817
|
+
if (!isPathInside(repoRoot, absolutePath) || normalized.startsWith("../") || normalized === "..") {
|
|
5818
|
+
throw new GitCommandError("path_outside_repo", "Git log path is outside the repository root");
|
|
5819
|
+
}
|
|
5820
|
+
return normalized;
|
|
5821
|
+
}
|
|
5822
|
+
|
|
5823
|
+
// src/index.ts
|
|
4683
5824
|
init_config();
|
|
4684
5825
|
|
|
4685
5826
|
// src/config/workspaces.ts
|
|
4686
5827
|
var fs = __toESM(require("fs"));
|
|
4687
5828
|
var os = __toESM(require("os"));
|
|
4688
|
-
var
|
|
5829
|
+
var path4 = __toESM(require("path"));
|
|
4689
5830
|
var import_crypto2 = require("crypto");
|
|
4690
5831
|
var MAX_WORKSPACES = 50;
|
|
4691
5832
|
function expandPath(p) {
|
|
4692
5833
|
const t = (p || "").trim();
|
|
4693
5834
|
if (!t) return "";
|
|
4694
|
-
if (t.startsWith("~")) return
|
|
4695
|
-
return
|
|
5835
|
+
if (t.startsWith("~")) return path4.join(os.homedir(), t.slice(1).replace(/^\//, ""));
|
|
5836
|
+
return path4.resolve(t);
|
|
4696
5837
|
}
|
|
4697
5838
|
function validateWorkspacePath(absPath) {
|
|
4698
5839
|
try {
|
|
@@ -4706,7 +5847,7 @@ function validateWorkspacePath(absPath) {
|
|
|
4706
5847
|
}
|
|
4707
5848
|
}
|
|
4708
5849
|
function defaultWorkspaceLabel(absPath) {
|
|
4709
|
-
const base =
|
|
5850
|
+
const base = path4.basename(absPath) || absPath;
|
|
4710
5851
|
return base;
|
|
4711
5852
|
}
|
|
4712
5853
|
function getDefaultWorkspacePath(config) {
|
|
@@ -4797,9 +5938,9 @@ function resolveIdeLaunchWorkspace(args, config) {
|
|
|
4797
5938
|
return getDefaultWorkspacePath(config) || void 0;
|
|
4798
5939
|
}
|
|
4799
5940
|
function findWorkspaceByPath(config, rawPath) {
|
|
4800
|
-
const abs =
|
|
5941
|
+
const abs = path4.resolve(expandPath(rawPath));
|
|
4801
5942
|
if (!abs) return void 0;
|
|
4802
|
-
return (config.workspaces || []).find((w) =>
|
|
5943
|
+
return (config.workspaces || []).find((w) => path4.resolve(expandPath(w.path)) === abs);
|
|
4803
5944
|
}
|
|
4804
5945
|
function addWorkspaceEntry(config, rawPath, label, options) {
|
|
4805
5946
|
const abs = expandPath(rawPath);
|
|
@@ -4815,7 +5956,7 @@ function addWorkspaceEntry(config, rawPath, label, options) {
|
|
|
4815
5956
|
const v = validateWorkspacePath(abs);
|
|
4816
5957
|
if (!v.ok) return { error: v.error };
|
|
4817
5958
|
const list = [...config.workspaces || []];
|
|
4818
|
-
if (list.some((w) =>
|
|
5959
|
+
if (list.some((w) => path4.resolve(w.path) === abs)) {
|
|
4819
5960
|
return { error: "Workspace already in list" };
|
|
4820
5961
|
}
|
|
4821
5962
|
if (list.length >= MAX_WORKSPACES) {
|
|
@@ -4849,7 +5990,7 @@ function setDefaultWorkspaceId(config, id) {
|
|
|
4849
5990
|
}
|
|
4850
5991
|
|
|
4851
5992
|
// src/config/recent-activity.ts
|
|
4852
|
-
var
|
|
5993
|
+
var path5 = __toESM(require("path"));
|
|
4853
5994
|
|
|
4854
5995
|
// src/providers/summary-metadata.ts
|
|
4855
5996
|
function normalizeSummaryItem(item) {
|
|
@@ -4918,9 +6059,9 @@ var MAX_ACTIVITY = 30;
|
|
|
4918
6059
|
function normalizeWorkspace(workspace) {
|
|
4919
6060
|
if (!workspace) return "";
|
|
4920
6061
|
try {
|
|
4921
|
-
return
|
|
6062
|
+
return path5.resolve(expandPath(workspace));
|
|
4922
6063
|
} catch {
|
|
4923
|
-
return
|
|
6064
|
+
return path5.resolve(workspace);
|
|
4924
6065
|
}
|
|
4925
6066
|
}
|
|
4926
6067
|
function buildRecentActivityKey(entry) {
|
|
@@ -5088,14 +6229,14 @@ function markSessionSeen(state, sessionId, seenAt = Date.now(), completionMarker
|
|
|
5088
6229
|
}
|
|
5089
6230
|
|
|
5090
6231
|
// src/config/saved-sessions.ts
|
|
5091
|
-
var
|
|
6232
|
+
var path6 = __toESM(require("path"));
|
|
5092
6233
|
var MAX_SAVED_SESSIONS = 500;
|
|
5093
6234
|
function normalizeWorkspace2(workspace) {
|
|
5094
6235
|
if (!workspace) return "";
|
|
5095
6236
|
try {
|
|
5096
|
-
return
|
|
6237
|
+
return path6.resolve(expandPath(workspace));
|
|
5097
6238
|
} catch {
|
|
5098
|
-
return
|
|
6239
|
+
return path6.resolve(workspace);
|
|
5099
6240
|
}
|
|
5100
6241
|
}
|
|
5101
6242
|
function buildSavedProviderSessionKey(providerSessionId) {
|
|
@@ -5214,7 +6355,7 @@ function resetState() {
|
|
|
5214
6355
|
var import_child_process = require("child_process");
|
|
5215
6356
|
var import_fs3 = require("fs");
|
|
5216
6357
|
var import_os2 = require("os");
|
|
5217
|
-
var
|
|
6358
|
+
var path7 = __toESM(require("path"));
|
|
5218
6359
|
var BUILTIN_IDE_DEFINITIONS = [];
|
|
5219
6360
|
var registeredIDEs = /* @__PURE__ */ new Map();
|
|
5220
6361
|
function registerIDEDefinition(def) {
|
|
@@ -5233,9 +6374,9 @@ function getMergedDefinitions() {
|
|
|
5233
6374
|
function findCliCommand(command) {
|
|
5234
6375
|
const trimmed = String(command || "").trim();
|
|
5235
6376
|
if (!trimmed) return null;
|
|
5236
|
-
if (
|
|
5237
|
-
const candidate = trimmed.startsWith("~") ?
|
|
5238
|
-
const resolved =
|
|
6377
|
+
if (path7.isAbsolute(trimmed) || trimmed.includes("/") || trimmed.includes("\\") || trimmed.startsWith("~")) {
|
|
6378
|
+
const candidate = trimmed.startsWith("~") ? path7.join((0, import_os2.homedir)(), trimmed.slice(1)) : trimmed;
|
|
6379
|
+
const resolved = path7.isAbsolute(candidate) ? candidate : path7.resolve(candidate);
|
|
5239
6380
|
return (0, import_fs3.existsSync)(resolved) ? resolved : null;
|
|
5240
6381
|
}
|
|
5241
6382
|
try {
|
|
@@ -5263,7 +6404,7 @@ function getIdeVersion(cliCommand) {
|
|
|
5263
6404
|
function checkPathExists(paths) {
|
|
5264
6405
|
const home = (0, import_os2.homedir)();
|
|
5265
6406
|
for (const p of paths) {
|
|
5266
|
-
const normalized = p.startsWith("~") ?
|
|
6407
|
+
const normalized = p.startsWith("~") ? path7.join(home, p.slice(1)) : p;
|
|
5267
6408
|
if (normalized.includes("*")) {
|
|
5268
6409
|
const username = home.split(/[\\/]/).pop() || "";
|
|
5269
6410
|
const resolved = normalized.replace("*", username);
|
|
@@ -5321,7 +6462,7 @@ async function detectIDEs(providerLoader) {
|
|
|
5321
6462
|
// src/detection/cli-detector.ts
|
|
5322
6463
|
var import_child_process2 = require("child_process");
|
|
5323
6464
|
var os2 = __toESM(require("os"));
|
|
5324
|
-
var
|
|
6465
|
+
var path8 = __toESM(require("path"));
|
|
5325
6466
|
var import_fs4 = require("fs");
|
|
5326
6467
|
function parseVersion(raw) {
|
|
5327
6468
|
const match = raw.match(/v?(\d+\.\d+(?:\.\d+)?(?:-[a-zA-Z0-9.]+)?)/);
|
|
@@ -5334,36 +6475,36 @@ function shellQuote(value) {
|
|
|
5334
6475
|
function expandHome(value) {
|
|
5335
6476
|
const trimmed = value.trim();
|
|
5336
6477
|
if (!trimmed.startsWith("~")) return trimmed;
|
|
5337
|
-
return
|
|
6478
|
+
return path8.join(os2.homedir(), trimmed.slice(1));
|
|
5338
6479
|
}
|
|
5339
6480
|
function isExplicitCommandPath(command) {
|
|
5340
6481
|
const trimmed = command.trim();
|
|
5341
|
-
return
|
|
6482
|
+
return path8.isAbsolute(trimmed) || trimmed.includes("/") || trimmed.includes("\\") || trimmed.startsWith("~");
|
|
5342
6483
|
}
|
|
5343
6484
|
function resolveCommandPath(command) {
|
|
5344
6485
|
const trimmed = command.trim();
|
|
5345
6486
|
if (!trimmed) return null;
|
|
5346
6487
|
if (isExplicitCommandPath(trimmed)) {
|
|
5347
6488
|
const expanded = expandHome(trimmed);
|
|
5348
|
-
const candidate =
|
|
6489
|
+
const candidate = path8.isAbsolute(expanded) ? expanded : path8.resolve(expanded);
|
|
5349
6490
|
return (0, import_fs4.existsSync)(candidate) ? candidate : null;
|
|
5350
6491
|
}
|
|
5351
6492
|
return null;
|
|
5352
6493
|
}
|
|
5353
6494
|
function execAsync(cmd, timeoutMs = 5e3) {
|
|
5354
|
-
return new Promise((
|
|
6495
|
+
return new Promise((resolve15) => {
|
|
5355
6496
|
const child = (0, import_child_process2.exec)(cmd, {
|
|
5356
6497
|
encoding: "utf-8",
|
|
5357
6498
|
timeout: timeoutMs,
|
|
5358
6499
|
...process.platform === "win32" ? { windowsHide: true } : {}
|
|
5359
6500
|
}, (err, stdout) => {
|
|
5360
6501
|
if (err || !stdout?.trim()) {
|
|
5361
|
-
|
|
6502
|
+
resolve15(null);
|
|
5362
6503
|
} else {
|
|
5363
|
-
|
|
6504
|
+
resolve15(stdout.trim());
|
|
5364
6505
|
}
|
|
5365
6506
|
});
|
|
5366
|
-
child.on("error", () =>
|
|
6507
|
+
child.on("error", () => resolve15(null));
|
|
5367
6508
|
});
|
|
5368
6509
|
}
|
|
5369
6510
|
async function detectCLIs(providerLoader, options) {
|
|
@@ -5728,7 +6869,7 @@ var DaemonCdpManager = class {
|
|
|
5728
6869
|
* Returns multiple entries if multiple IDE windows are open on same port
|
|
5729
6870
|
*/
|
|
5730
6871
|
static listAllTargets(port) {
|
|
5731
|
-
return new Promise((
|
|
6872
|
+
return new Promise((resolve15) => {
|
|
5732
6873
|
const req = http.get(`http://127.0.0.1:${port}/json`, (res) => {
|
|
5733
6874
|
let data = "";
|
|
5734
6875
|
res.on("data", (chunk) => data += chunk.toString());
|
|
@@ -5744,16 +6885,16 @@ var DaemonCdpManager = class {
|
|
|
5744
6885
|
(t) => !isNonMain(t.title || "") && t.url?.includes("workbench.html") && !t.url?.includes("agent")
|
|
5745
6886
|
);
|
|
5746
6887
|
const fallbackPages = pages.filter((t) => !isNonMain(t.title || ""));
|
|
5747
|
-
|
|
6888
|
+
resolve15(mainPages.length > 0 ? mainPages : fallbackPages);
|
|
5748
6889
|
} catch {
|
|
5749
|
-
|
|
6890
|
+
resolve15([]);
|
|
5750
6891
|
}
|
|
5751
6892
|
});
|
|
5752
6893
|
});
|
|
5753
|
-
req.on("error", () =>
|
|
6894
|
+
req.on("error", () => resolve15([]));
|
|
5754
6895
|
req.setTimeout(2e3, () => {
|
|
5755
6896
|
req.destroy();
|
|
5756
|
-
|
|
6897
|
+
resolve15([]);
|
|
5757
6898
|
});
|
|
5758
6899
|
});
|
|
5759
6900
|
}
|
|
@@ -5793,7 +6934,7 @@ var DaemonCdpManager = class {
|
|
|
5793
6934
|
}
|
|
5794
6935
|
}
|
|
5795
6936
|
findTargetOnPort(port) {
|
|
5796
|
-
return new Promise((
|
|
6937
|
+
return new Promise((resolve15) => {
|
|
5797
6938
|
const req = http.get(`http://127.0.0.1:${port}/json`, (res) => {
|
|
5798
6939
|
let data = "";
|
|
5799
6940
|
res.on("data", (chunk) => data += chunk.toString());
|
|
@@ -5804,7 +6945,7 @@ var DaemonCdpManager = class {
|
|
|
5804
6945
|
(t) => (t.type === "page" || t.type === "browser" || t.type === "Page") && t.webSocketDebuggerUrl
|
|
5805
6946
|
);
|
|
5806
6947
|
if (pages.length === 0) {
|
|
5807
|
-
|
|
6948
|
+
resolve15(targets.find((t) => t.webSocketDebuggerUrl) || null);
|
|
5808
6949
|
return;
|
|
5809
6950
|
}
|
|
5810
6951
|
const titleFilteredPages = pages.filter((t) => !this.isNonMainTitle(t.title || ""));
|
|
@@ -5823,25 +6964,25 @@ var DaemonCdpManager = class {
|
|
|
5823
6964
|
this._targetId = selected.target.id;
|
|
5824
6965
|
}
|
|
5825
6966
|
this._pageTitle = selected.target.title || "";
|
|
5826
|
-
|
|
6967
|
+
resolve15(selected.target);
|
|
5827
6968
|
return;
|
|
5828
6969
|
}
|
|
5829
6970
|
if (previousTargetId) {
|
|
5830
6971
|
this.log(`[CDP] Target ${previousTargetId} not found in page list`);
|
|
5831
|
-
|
|
6972
|
+
resolve15(null);
|
|
5832
6973
|
return;
|
|
5833
6974
|
}
|
|
5834
6975
|
this._pageTitle = list[0]?.title || "";
|
|
5835
|
-
|
|
6976
|
+
resolve15(list[0]);
|
|
5836
6977
|
} catch {
|
|
5837
|
-
|
|
6978
|
+
resolve15(null);
|
|
5838
6979
|
}
|
|
5839
6980
|
});
|
|
5840
6981
|
});
|
|
5841
|
-
req.on("error", () =>
|
|
6982
|
+
req.on("error", () => resolve15(null));
|
|
5842
6983
|
req.setTimeout(2e3, () => {
|
|
5843
6984
|
req.destroy();
|
|
5844
|
-
|
|
6985
|
+
resolve15(null);
|
|
5845
6986
|
});
|
|
5846
6987
|
});
|
|
5847
6988
|
}
|
|
@@ -5852,7 +6993,7 @@ var DaemonCdpManager = class {
|
|
|
5852
6993
|
this.extensionProviders = providers;
|
|
5853
6994
|
}
|
|
5854
6995
|
connectToTarget(wsUrl) {
|
|
5855
|
-
return new Promise((
|
|
6996
|
+
return new Promise((resolve15) => {
|
|
5856
6997
|
this.ws = new import_ws.default(wsUrl);
|
|
5857
6998
|
this.ws.on("open", async () => {
|
|
5858
6999
|
this._connected = true;
|
|
@@ -5862,17 +7003,17 @@ var DaemonCdpManager = class {
|
|
|
5862
7003
|
}
|
|
5863
7004
|
this.connectBrowserWs().catch(() => {
|
|
5864
7005
|
});
|
|
5865
|
-
|
|
7006
|
+
resolve15(true);
|
|
5866
7007
|
});
|
|
5867
7008
|
this.ws.on("message", (data) => {
|
|
5868
7009
|
try {
|
|
5869
7010
|
const msg = JSON.parse(data.toString());
|
|
5870
7011
|
if (msg.id && this.pending.has(msg.id)) {
|
|
5871
|
-
const { resolve:
|
|
7012
|
+
const { resolve: resolve16, reject } = this.pending.get(msg.id);
|
|
5872
7013
|
this.pending.delete(msg.id);
|
|
5873
7014
|
this.failureCount = 0;
|
|
5874
7015
|
if (msg.error) reject(new Error(msg.error.message));
|
|
5875
|
-
else
|
|
7016
|
+
else resolve16(msg.result);
|
|
5876
7017
|
} else if (msg.method === "Runtime.executionContextCreated") {
|
|
5877
7018
|
this.contexts.add(msg.params.context.id);
|
|
5878
7019
|
} else if (msg.method === "Runtime.executionContextDestroyed") {
|
|
@@ -5895,7 +7036,7 @@ var DaemonCdpManager = class {
|
|
|
5895
7036
|
this.ws.on("error", (err) => {
|
|
5896
7037
|
this.log(`[CDP] WebSocket error: ${err.message}`);
|
|
5897
7038
|
this._connected = false;
|
|
5898
|
-
|
|
7039
|
+
resolve15(false);
|
|
5899
7040
|
});
|
|
5900
7041
|
});
|
|
5901
7042
|
}
|
|
@@ -5909,7 +7050,7 @@ var DaemonCdpManager = class {
|
|
|
5909
7050
|
return;
|
|
5910
7051
|
}
|
|
5911
7052
|
this.log(`[CDP] Connecting browser WS for target discovery...`);
|
|
5912
|
-
await new Promise((
|
|
7053
|
+
await new Promise((resolve15, reject) => {
|
|
5913
7054
|
this.browserWs = new import_ws.default(browserWsUrl);
|
|
5914
7055
|
this.browserWs.on("open", async () => {
|
|
5915
7056
|
this._browserConnected = true;
|
|
@@ -5919,16 +7060,16 @@ var DaemonCdpManager = class {
|
|
|
5919
7060
|
} catch (e) {
|
|
5920
7061
|
this.log(`[CDP] setDiscoverTargets failed: ${e.message}`);
|
|
5921
7062
|
}
|
|
5922
|
-
|
|
7063
|
+
resolve15();
|
|
5923
7064
|
});
|
|
5924
7065
|
this.browserWs.on("message", (data) => {
|
|
5925
7066
|
try {
|
|
5926
7067
|
const msg = JSON.parse(data.toString());
|
|
5927
7068
|
if (msg.id && this.browserPending.has(msg.id)) {
|
|
5928
|
-
const { resolve:
|
|
7069
|
+
const { resolve: resolve16, reject: reject2 } = this.browserPending.get(msg.id);
|
|
5929
7070
|
this.browserPending.delete(msg.id);
|
|
5930
7071
|
if (msg.error) reject2(new Error(msg.error.message));
|
|
5931
|
-
else
|
|
7072
|
+
else resolve16(msg.result);
|
|
5932
7073
|
}
|
|
5933
7074
|
} catch {
|
|
5934
7075
|
}
|
|
@@ -5948,31 +7089,31 @@ var DaemonCdpManager = class {
|
|
|
5948
7089
|
}
|
|
5949
7090
|
}
|
|
5950
7091
|
getBrowserWsUrl() {
|
|
5951
|
-
return new Promise((
|
|
7092
|
+
return new Promise((resolve15) => {
|
|
5952
7093
|
const req = http.get(`http://127.0.0.1:${this.port}/json/version`, (res) => {
|
|
5953
7094
|
let data = "";
|
|
5954
7095
|
res.on("data", (chunk) => data += chunk.toString());
|
|
5955
7096
|
res.on("end", () => {
|
|
5956
7097
|
try {
|
|
5957
7098
|
const info = JSON.parse(data);
|
|
5958
|
-
|
|
7099
|
+
resolve15(info.webSocketDebuggerUrl || null);
|
|
5959
7100
|
} catch {
|
|
5960
|
-
|
|
7101
|
+
resolve15(null);
|
|
5961
7102
|
}
|
|
5962
7103
|
});
|
|
5963
7104
|
});
|
|
5964
|
-
req.on("error", () =>
|
|
7105
|
+
req.on("error", () => resolve15(null));
|
|
5965
7106
|
req.setTimeout(3e3, () => {
|
|
5966
7107
|
req.destroy();
|
|
5967
|
-
|
|
7108
|
+
resolve15(null);
|
|
5968
7109
|
});
|
|
5969
7110
|
});
|
|
5970
7111
|
}
|
|
5971
7112
|
sendBrowser(method, params = {}, timeoutMs = 15e3) {
|
|
5972
|
-
return new Promise((
|
|
7113
|
+
return new Promise((resolve15, reject) => {
|
|
5973
7114
|
if (!this.browserWs || !this._browserConnected) return reject(new Error("Browser WS not connected"));
|
|
5974
7115
|
const id = this.browserMsgId++;
|
|
5975
|
-
this.browserPending.set(id, { resolve:
|
|
7116
|
+
this.browserPending.set(id, { resolve: resolve15, reject });
|
|
5976
7117
|
this.browserWs.send(JSON.stringify({ id, method, params }));
|
|
5977
7118
|
setTimeout(() => {
|
|
5978
7119
|
if (this.browserPending.has(id)) {
|
|
@@ -6012,11 +7153,11 @@ var DaemonCdpManager = class {
|
|
|
6012
7153
|
}
|
|
6013
7154
|
// ─── CDP Protocol ────────────────────────────────────────
|
|
6014
7155
|
sendInternal(method, params = {}, timeoutMs = 15e3) {
|
|
6015
|
-
return new Promise((
|
|
7156
|
+
return new Promise((resolve15, reject) => {
|
|
6016
7157
|
if (!this.ws || !this._connected) return reject(new Error("CDP not connected"));
|
|
6017
7158
|
if (this.ws.readyState !== import_ws.default.OPEN) return reject(new Error("WebSocket not open"));
|
|
6018
7159
|
const id = this.msgId++;
|
|
6019
|
-
this.pending.set(id, { resolve:
|
|
7160
|
+
this.pending.set(id, { resolve: resolve15, reject });
|
|
6020
7161
|
this.ws.send(JSON.stringify({ id, method, params }));
|
|
6021
7162
|
setTimeout(() => {
|
|
6022
7163
|
if (this.pending.has(id)) {
|
|
@@ -6265,7 +7406,7 @@ var DaemonCdpManager = class {
|
|
|
6265
7406
|
const browserWs = this.browserWs;
|
|
6266
7407
|
let msgId = this.browserMsgId;
|
|
6267
7408
|
const sendWs = (method, params = {}, sessionId) => {
|
|
6268
|
-
return new Promise((
|
|
7409
|
+
return new Promise((resolve15, reject) => {
|
|
6269
7410
|
const mid = msgId++;
|
|
6270
7411
|
this.browserMsgId = msgId;
|
|
6271
7412
|
const handler = (raw) => {
|
|
@@ -6274,7 +7415,7 @@ var DaemonCdpManager = class {
|
|
|
6274
7415
|
if (msg.id === mid) {
|
|
6275
7416
|
browserWs.removeListener("message", handler);
|
|
6276
7417
|
if (msg.error) reject(new Error(msg.error.message || JSON.stringify(msg.error)));
|
|
6277
|
-
else
|
|
7418
|
+
else resolve15(msg.result);
|
|
6278
7419
|
}
|
|
6279
7420
|
} catch {
|
|
6280
7421
|
}
|
|
@@ -6475,14 +7616,14 @@ var DaemonCdpManager = class {
|
|
|
6475
7616
|
if (!ws || ws.readyState !== import_ws.default.OPEN) {
|
|
6476
7617
|
throw new Error("CDP not connected");
|
|
6477
7618
|
}
|
|
6478
|
-
return new Promise((
|
|
7619
|
+
return new Promise((resolve15, reject) => {
|
|
6479
7620
|
const id = getNextId();
|
|
6480
7621
|
pendingMap.set(id, {
|
|
6481
7622
|
resolve: (result) => {
|
|
6482
7623
|
if (result?.result?.subtype === "error") {
|
|
6483
7624
|
reject(new Error(result.result.description));
|
|
6484
7625
|
} else {
|
|
6485
|
-
|
|
7626
|
+
resolve15(result?.result?.value);
|
|
6486
7627
|
}
|
|
6487
7628
|
},
|
|
6488
7629
|
reject
|
|
@@ -6514,10 +7655,10 @@ var DaemonCdpManager = class {
|
|
|
6514
7655
|
throw new Error("CDP not connected");
|
|
6515
7656
|
}
|
|
6516
7657
|
const sendViaSession = (method, params = {}) => {
|
|
6517
|
-
return new Promise((
|
|
7658
|
+
return new Promise((resolve15, reject) => {
|
|
6518
7659
|
const pendingMap = this._browserConnected ? this.browserPending : this.pending;
|
|
6519
7660
|
const id = this._browserConnected ? this.browserMsgId++ : this.msgId++;
|
|
6520
|
-
pendingMap.set(id, { resolve:
|
|
7661
|
+
pendingMap.set(id, { resolve: resolve15, reject });
|
|
6521
7662
|
ws.send(JSON.stringify({ id, sessionId, method, params }));
|
|
6522
7663
|
setTimeout(() => {
|
|
6523
7664
|
if (pendingMap.has(id)) {
|
|
@@ -7263,10 +8404,10 @@ ${cleanBody}`;
|
|
|
7263
8404
|
|
|
7264
8405
|
// src/config/chat-history.ts
|
|
7265
8406
|
var fs3 = __toESM(require("fs"));
|
|
7266
|
-
var
|
|
8407
|
+
var path10 = __toESM(require("path"));
|
|
7267
8408
|
var os5 = __toESM(require("os"));
|
|
7268
8409
|
init_chat_message_normalization();
|
|
7269
|
-
var HISTORY_DIR =
|
|
8410
|
+
var HISTORY_DIR = path10.join(os5.homedir(), ".adhdev", "history");
|
|
7270
8411
|
var RETAIN_DAYS = 30;
|
|
7271
8412
|
var SAVED_HISTORY_INDEX_VERSION = 1;
|
|
7272
8413
|
var SAVED_HISTORY_INDEX_FILE = ".saved-history-index.json";
|
|
@@ -7429,8 +8570,8 @@ function extractSavedHistorySessionIdFromFile(file) {
|
|
|
7429
8570
|
function buildSavedHistoryFileSignatureMap(dir, files) {
|
|
7430
8571
|
return new Map(files.map((file) => {
|
|
7431
8572
|
try {
|
|
7432
|
-
const
|
|
7433
|
-
return [file, `${file}:${
|
|
8573
|
+
const stat2 = fs3.statSync(path10.join(dir, file));
|
|
8574
|
+
return [file, `${file}:${stat2.size}:${Math.trunc(stat2.mtimeMs)}`];
|
|
7434
8575
|
} catch {
|
|
7435
8576
|
return [file, `${file}:missing`];
|
|
7436
8577
|
}
|
|
@@ -7440,7 +8581,7 @@ function buildSavedHistoryCacheSignature(files, fileSignatures) {
|
|
|
7440
8581
|
return files.map((file) => fileSignatures.get(file) || `${file}:missing`).join("|");
|
|
7441
8582
|
}
|
|
7442
8583
|
function getSavedHistoryIndexFilePath(dir) {
|
|
7443
|
-
return
|
|
8584
|
+
return path10.join(dir, SAVED_HISTORY_INDEX_FILE);
|
|
7444
8585
|
}
|
|
7445
8586
|
function getSavedHistoryIndexLockPath(dir) {
|
|
7446
8587
|
return `${getSavedHistoryIndexFilePath(dir)}${SAVED_HISTORY_INDEX_LOCK_SUFFIX}`;
|
|
@@ -7493,8 +8634,8 @@ function acquireSavedHistoryIndexLock(dir) {
|
|
|
7493
8634
|
} catch (error) {
|
|
7494
8635
|
if (error?.code !== "EEXIST") return null;
|
|
7495
8636
|
try {
|
|
7496
|
-
const
|
|
7497
|
-
if (Date.now() -
|
|
8637
|
+
const stat2 = fs3.statSync(lockPath);
|
|
8638
|
+
if (Date.now() - stat2.mtimeMs > SAVED_HISTORY_INDEX_LOCK_STALE_MS) {
|
|
7498
8639
|
fs3.rmSync(lockPath, { recursive: true, force: true });
|
|
7499
8640
|
continue;
|
|
7500
8641
|
}
|
|
@@ -7542,7 +8683,7 @@ function savePersistedSavedHistoryIndex(dir, entries) {
|
|
|
7542
8683
|
}
|
|
7543
8684
|
for (const file of Array.from(currentEntries.keys())) {
|
|
7544
8685
|
if (incomingFiles.has(file)) continue;
|
|
7545
|
-
if (!fs3.existsSync(
|
|
8686
|
+
if (!fs3.existsSync(path10.join(dir, file))) {
|
|
7546
8687
|
currentEntries.delete(file);
|
|
7547
8688
|
}
|
|
7548
8689
|
}
|
|
@@ -7557,8 +8698,8 @@ function invalidatePersistedSavedHistoryIndex(agentType, dir) {
|
|
|
7557
8698
|
}
|
|
7558
8699
|
function buildSavedHistoryIndexFileSignature(dir) {
|
|
7559
8700
|
try {
|
|
7560
|
-
const
|
|
7561
|
-
return `index:${
|
|
8701
|
+
const stat2 = fs3.statSync(getSavedHistoryIndexFilePath(dir));
|
|
8702
|
+
return `index:${stat2.size}:${Math.trunc(stat2.mtimeMs)}`;
|
|
7562
8703
|
} catch {
|
|
7563
8704
|
return "index:missing";
|
|
7564
8705
|
}
|
|
@@ -7568,8 +8709,8 @@ function historyDirectoryHasFilesNewerThanIndex(dir) {
|
|
|
7568
8709
|
const indexStat = fs3.statSync(getSavedHistoryIndexFilePath(dir));
|
|
7569
8710
|
const files = listHistoryFiles(dir);
|
|
7570
8711
|
for (const file of files) {
|
|
7571
|
-
const
|
|
7572
|
-
if (
|
|
8712
|
+
const stat2 = fs3.statSync(path10.join(dir, file));
|
|
8713
|
+
if (stat2.mtimeMs > indexStat.mtimeMs) return true;
|
|
7573
8714
|
}
|
|
7574
8715
|
return false;
|
|
7575
8716
|
} catch {
|
|
@@ -7578,14 +8719,14 @@ function historyDirectoryHasFilesNewerThanIndex(dir) {
|
|
|
7578
8719
|
}
|
|
7579
8720
|
function buildSavedHistoryFileSignature(dir, file) {
|
|
7580
8721
|
try {
|
|
7581
|
-
const
|
|
7582
|
-
return `${file}:${
|
|
8722
|
+
const stat2 = fs3.statSync(path10.join(dir, file));
|
|
8723
|
+
return `${file}:${stat2.size}:${Math.trunc(stat2.mtimeMs)}`;
|
|
7583
8724
|
} catch {
|
|
7584
8725
|
return `${file}:missing`;
|
|
7585
8726
|
}
|
|
7586
8727
|
}
|
|
7587
8728
|
function persistSavedHistoryFileSummaryEntry(agentType, dir, file, updater) {
|
|
7588
|
-
const filePath =
|
|
8729
|
+
const filePath = path10.join(dir, file);
|
|
7589
8730
|
const result = withLockedPersistedSavedHistoryIndex(dir, (entries) => {
|
|
7590
8731
|
const currentEntry = entries.get(file) || null;
|
|
7591
8732
|
const nextSummary = updater(currentEntry?.summary || null);
|
|
@@ -7658,7 +8799,7 @@ function updateSavedHistoryIndexForAppendedMessages(agentType, dir, file, histor
|
|
|
7658
8799
|
function computeSavedHistoryFileSummary(dir, file) {
|
|
7659
8800
|
const historySessionId = extractSavedHistorySessionIdFromFile(file);
|
|
7660
8801
|
if (!historySessionId) return null;
|
|
7661
|
-
const filePath =
|
|
8802
|
+
const filePath = path10.join(dir, file);
|
|
7662
8803
|
const content = fs3.readFileSync(filePath, "utf-8");
|
|
7663
8804
|
const lines = content.split("\n").filter(Boolean);
|
|
7664
8805
|
let messageCount = 0;
|
|
@@ -7745,7 +8886,7 @@ function computeSavedHistorySessionSummaries(agentType, dir, files, fileSignatur
|
|
|
7745
8886
|
const summaryBySessionId = /* @__PURE__ */ new Map();
|
|
7746
8887
|
const nextPersistedEntries = /* @__PURE__ */ new Map();
|
|
7747
8888
|
for (const file of files.slice().sort()) {
|
|
7748
|
-
const filePath =
|
|
8889
|
+
const filePath = path10.join(dir, file);
|
|
7749
8890
|
const signature = fileSignatures.get(file) || `${file}:missing`;
|
|
7750
8891
|
const cached = savedHistoryFileSummaryCache.get(filePath);
|
|
7751
8892
|
const persisted = persistedEntries.get(file);
|
|
@@ -7865,12 +9006,12 @@ var ChatHistoryWriter = class {
|
|
|
7865
9006
|
});
|
|
7866
9007
|
}
|
|
7867
9008
|
if (newMessages.length === 0) return;
|
|
7868
|
-
const dir =
|
|
9009
|
+
const dir = path10.join(HISTORY_DIR, this.sanitize(agentType));
|
|
7869
9010
|
fs3.mkdirSync(dir, { recursive: true });
|
|
7870
9011
|
const date = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
|
|
7871
9012
|
const filePrefix = effectiveHistoryKey ? `${this.sanitize(effectiveHistoryKey)}_` : "";
|
|
7872
9013
|
const fileName = `${filePrefix}${date}.jsonl`;
|
|
7873
|
-
const filePath =
|
|
9014
|
+
const filePath = path10.join(dir, fileName);
|
|
7874
9015
|
const lines = newMessages.map((m) => JSON.stringify(m)).join("\n") + "\n";
|
|
7875
9016
|
fs3.appendFileSync(filePath, lines, "utf-8");
|
|
7876
9017
|
updateSavedHistoryIndexForAppendedMessages(agentType, dir, fileName, effectiveHistoryKey, newMessages);
|
|
@@ -7961,11 +9102,11 @@ var ChatHistoryWriter = class {
|
|
|
7961
9102
|
const ws = String(workspace || "").trim();
|
|
7962
9103
|
if (!id || !ws) return;
|
|
7963
9104
|
try {
|
|
7964
|
-
const dir =
|
|
9105
|
+
const dir = path10.join(HISTORY_DIR, this.sanitize(agentType));
|
|
7965
9106
|
fs3.mkdirSync(dir, { recursive: true });
|
|
7966
9107
|
const date = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
|
|
7967
9108
|
const fileName = `${this.sanitize(id)}_${date}.jsonl`;
|
|
7968
|
-
const filePath =
|
|
9109
|
+
const filePath = path10.join(dir, fileName);
|
|
7969
9110
|
const record = {
|
|
7970
9111
|
ts: (/* @__PURE__ */ new Date()).toISOString(),
|
|
7971
9112
|
receivedAt: Date.now(),
|
|
@@ -8011,14 +9152,14 @@ var ChatHistoryWriter = class {
|
|
|
8011
9152
|
this.lastSeenCounts.set(toDedupKey, Math.max(fromCount, this.lastSeenCounts.get(toDedupKey) || 0));
|
|
8012
9153
|
this.lastSeenCounts.delete(fromDedupKey);
|
|
8013
9154
|
}
|
|
8014
|
-
const dir =
|
|
9155
|
+
const dir = path10.join(HISTORY_DIR, this.sanitize(agentType));
|
|
8015
9156
|
if (!fs3.existsSync(dir)) return;
|
|
8016
9157
|
const fromPrefix = `${this.sanitize(fromId)}_`;
|
|
8017
9158
|
const toPrefix = `${this.sanitize(toId)}_`;
|
|
8018
9159
|
const files = fs3.readdirSync(dir).filter((file) => file.startsWith(fromPrefix) && file.endsWith(".jsonl"));
|
|
8019
9160
|
for (const file of files) {
|
|
8020
|
-
const sourcePath =
|
|
8021
|
-
const targetPath =
|
|
9161
|
+
const sourcePath = path10.join(dir, file);
|
|
9162
|
+
const targetPath = path10.join(dir, `${toPrefix}${file.slice(fromPrefix.length)}`);
|
|
8022
9163
|
const sourceLines = fs3.readFileSync(sourcePath, "utf-8").split("\n").filter(Boolean);
|
|
8023
9164
|
const rewritten = sourceLines.map((line) => {
|
|
8024
9165
|
try {
|
|
@@ -8052,13 +9193,13 @@ var ChatHistoryWriter = class {
|
|
|
8052
9193
|
const sessionId = String(historySessionId || "").trim();
|
|
8053
9194
|
if (!sessionId) return;
|
|
8054
9195
|
try {
|
|
8055
|
-
const dir =
|
|
9196
|
+
const dir = path10.join(HISTORY_DIR, this.sanitize(agentType));
|
|
8056
9197
|
if (!fs3.existsSync(dir)) return;
|
|
8057
9198
|
const prefix = `${this.sanitize(sessionId)}_`;
|
|
8058
9199
|
const files = fs3.readdirSync(dir).filter((file) => file.startsWith(prefix) && file.endsWith(".jsonl")).sort();
|
|
8059
9200
|
const seen = /* @__PURE__ */ new Set();
|
|
8060
9201
|
for (const file of files) {
|
|
8061
|
-
const filePath =
|
|
9202
|
+
const filePath = path10.join(dir, file);
|
|
8062
9203
|
const lines = fs3.readFileSync(filePath, "utf-8").split("\n").filter(Boolean);
|
|
8063
9204
|
const next = [];
|
|
8064
9205
|
for (const line of lines) {
|
|
@@ -8112,13 +9253,13 @@ var ChatHistoryWriter = class {
|
|
|
8112
9253
|
const cutoff = Date.now() - RETAIN_DAYS * 24 * 60 * 60 * 1e3;
|
|
8113
9254
|
const agentDirs = fs3.readdirSync(HISTORY_DIR, { withFileTypes: true }).filter((d) => d.isDirectory());
|
|
8114
9255
|
for (const dir of agentDirs) {
|
|
8115
|
-
const dirPath =
|
|
9256
|
+
const dirPath = path10.join(HISTORY_DIR, dir.name);
|
|
8116
9257
|
const files = fs3.readdirSync(dirPath).filter((f) => f.endsWith(".jsonl") || f.endsWith(".terminal.log"));
|
|
8117
9258
|
let removedAny = false;
|
|
8118
9259
|
for (const file of files) {
|
|
8119
|
-
const filePath =
|
|
8120
|
-
const
|
|
8121
|
-
if (
|
|
9260
|
+
const filePath = path10.join(dirPath, file);
|
|
9261
|
+
const stat2 = fs3.statSync(filePath);
|
|
9262
|
+
if (stat2.mtimeMs < cutoff) {
|
|
8122
9263
|
fs3.unlinkSync(filePath);
|
|
8123
9264
|
removedAny = true;
|
|
8124
9265
|
}
|
|
@@ -8135,6 +9276,10 @@ var ChatHistoryWriter = class {
|
|
|
8135
9276
|
return name.replace(/[^a-zA-Z0-9_-]/g, "_");
|
|
8136
9277
|
}
|
|
8137
9278
|
};
|
|
9279
|
+
function normalizePaginationNumber(value, fallback, min) {
|
|
9280
|
+
const numeric = Number(value);
|
|
9281
|
+
return Number.isFinite(numeric) ? Math.max(min, numeric) : fallback;
|
|
9282
|
+
}
|
|
8138
9283
|
function pageHistoryRecords(agentType, records, offset = 0, limit = 30, excludeRecentCount = 0, historyBehavior) {
|
|
8139
9284
|
const allMessages = records.map((message) => sanitizeHistoryMessage(agentType, message)).filter(Boolean);
|
|
8140
9285
|
allMessages.sort((a, b) => a.receivedAt - b.receivedAt);
|
|
@@ -8148,9 +9293,12 @@ function pageHistoryRecords(agentType, records, offset = 0, limit = 30, excludeR
|
|
|
8148
9293
|
if (message.role !== "system") lastTurn = message;
|
|
8149
9294
|
}
|
|
8150
9295
|
const collapsed = collapseReplayAssistantTurns(chronological, historyBehavior);
|
|
8151
|
-
const boundedLimit =
|
|
8152
|
-
const boundedOffset =
|
|
8153
|
-
const boundedExclude = Math.
|
|
9296
|
+
const boundedLimit = normalizePaginationNumber(limit, 30, 1);
|
|
9297
|
+
const boundedOffset = normalizePaginationNumber(offset, 0, 0);
|
|
9298
|
+
const boundedExclude = Math.min(
|
|
9299
|
+
normalizePaginationNumber(excludeRecentCount, 0, 0),
|
|
9300
|
+
collapsed.length
|
|
9301
|
+
);
|
|
8154
9302
|
const endExclusive = Math.max(0, collapsed.length - boundedExclude - boundedOffset);
|
|
8155
9303
|
const startInclusive = Math.max(0, endExclusive - boundedLimit);
|
|
8156
9304
|
const sliced = collapsed.slice(startInclusive, endExclusive);
|
|
@@ -8159,13 +9307,13 @@ function pageHistoryRecords(agentType, records, offset = 0, limit = 30, excludeR
|
|
|
8159
9307
|
function readChatHistory(agentType, offset = 0, limit = 30, historySessionId, excludeRecentCount = 0, historyBehavior) {
|
|
8160
9308
|
try {
|
|
8161
9309
|
const sanitized = agentType.replace(/[^a-zA-Z0-9_-]/g, "_");
|
|
8162
|
-
const dir =
|
|
9310
|
+
const dir = path10.join(HISTORY_DIR, sanitized);
|
|
8163
9311
|
if (!fs3.existsSync(dir)) return { messages: [], hasMore: false };
|
|
8164
9312
|
const files = listHistoryFiles(dir, historySessionId);
|
|
8165
9313
|
const allMessages = [];
|
|
8166
9314
|
const seen = /* @__PURE__ */ new Set();
|
|
8167
9315
|
for (const file of files) {
|
|
8168
|
-
const filePath =
|
|
9316
|
+
const filePath = path10.join(dir, file);
|
|
8169
9317
|
const content = fs3.readFileSync(filePath, "utf-8");
|
|
8170
9318
|
const lines = content.trim().split("\n").filter(Boolean);
|
|
8171
9319
|
for (let i = 0; i < lines.length; i++) {
|
|
@@ -8189,7 +9337,7 @@ function readChatHistory(agentType, offset = 0, limit = 30, historySessionId, ex
|
|
|
8189
9337
|
function listSavedHistorySessions(agentType, options = {}, historyBehavior) {
|
|
8190
9338
|
try {
|
|
8191
9339
|
const sanitized = agentType.replace(/[^a-zA-Z0-9_-]/g, "_");
|
|
8192
|
-
const dir =
|
|
9340
|
+
const dir = path10.join(HISTORY_DIR, sanitized);
|
|
8193
9341
|
if (!fs3.existsSync(dir)) {
|
|
8194
9342
|
savedHistorySessionCache.delete(sanitized);
|
|
8195
9343
|
return { sessions: [], hasMore: false };
|
|
@@ -8250,11 +9398,11 @@ function listSavedHistorySessions(agentType, options = {}, historyBehavior) {
|
|
|
8250
9398
|
}
|
|
8251
9399
|
function readExistingSessionStartRecord(agentType, historySessionId) {
|
|
8252
9400
|
try {
|
|
8253
|
-
const dir =
|
|
9401
|
+
const dir = path10.join(HISTORY_DIR, agentType);
|
|
8254
9402
|
if (!fs3.existsSync(dir)) return null;
|
|
8255
9403
|
const files = listHistoryFiles(dir, historySessionId).sort();
|
|
8256
9404
|
for (const file of files) {
|
|
8257
|
-
const lines = fs3.readFileSync(
|
|
9405
|
+
const lines = fs3.readFileSync(path10.join(dir, file), "utf-8").split("\n").filter(Boolean);
|
|
8258
9406
|
for (const line of lines) {
|
|
8259
9407
|
try {
|
|
8260
9408
|
const parsed = JSON.parse(line);
|
|
@@ -8274,16 +9422,16 @@ function readExistingSessionStartRecord(agentType, historySessionId) {
|
|
|
8274
9422
|
function rewriteCanonicalSavedHistory(agentType, historySessionId, records) {
|
|
8275
9423
|
if (records.length === 0) return false;
|
|
8276
9424
|
try {
|
|
8277
|
-
const dir =
|
|
9425
|
+
const dir = path10.join(HISTORY_DIR, agentType);
|
|
8278
9426
|
fs3.mkdirSync(dir, { recursive: true });
|
|
8279
9427
|
const prefix = `${historySessionId.replace(/[^a-zA-Z0-9_-]/g, "_")}_`;
|
|
8280
9428
|
for (const file of fs3.readdirSync(dir)) {
|
|
8281
9429
|
if (file.startsWith(prefix) && file.endsWith(".jsonl")) {
|
|
8282
|
-
fs3.unlinkSync(
|
|
9430
|
+
fs3.unlinkSync(path10.join(dir, file));
|
|
8283
9431
|
}
|
|
8284
9432
|
}
|
|
8285
9433
|
const targetDate = new Date(records[records.length - 1].receivedAt || Date.now()).toISOString().slice(0, 10);
|
|
8286
|
-
const filePath =
|
|
9434
|
+
const filePath = path10.join(dir, `${prefix}${targetDate}.jsonl`);
|
|
8287
9435
|
fs3.writeFileSync(filePath, `${records.map((record) => JSON.stringify(record)).join("\n")}
|
|
8288
9436
|
`, "utf-8");
|
|
8289
9437
|
invalidatePersistedSavedHistoryIndex(agentType, dir);
|
|
@@ -10155,6 +11303,10 @@ function shouldIncludeSessionMetadata(profile) {
|
|
|
10155
11303
|
function shouldIncludeRuntimeMetadata(profile) {
|
|
10156
11304
|
return true;
|
|
10157
11305
|
}
|
|
11306
|
+
function getGitSummaryForWorkspace(workspace, options) {
|
|
11307
|
+
if (!workspace) return void 0;
|
|
11308
|
+
return options.getGitSummaryForWorkspace?.(workspace) || void 0;
|
|
11309
|
+
}
|
|
10158
11310
|
function findCdpManager(cdpManagers, key) {
|
|
10159
11311
|
const exact = cdpManagers.get(key);
|
|
10160
11312
|
if (exact) return exact.isConnected ? exact : null;
|
|
@@ -10210,6 +11362,8 @@ function buildIdeWorkspaceSession(state, cdpManagers, options) {
|
|
|
10210
11362
|
const controlValues = normalizeProviderStateControlValues(state.controlValues);
|
|
10211
11363
|
const includeSessionMetadata = shouldIncludeSessionMetadata(profile);
|
|
10212
11364
|
const includeSessionControls = shouldIncludeSessionControls(profile);
|
|
11365
|
+
const workspace = state.workspace || null;
|
|
11366
|
+
const git = getGitSummaryForWorkspace(workspace, options);
|
|
10213
11367
|
const title = activeChat?.title || state.name;
|
|
10214
11368
|
return {
|
|
10215
11369
|
id: state.instanceId || state.type,
|
|
@@ -10222,7 +11376,8 @@ function buildIdeWorkspaceSession(state, cdpManagers, options) {
|
|
|
10222
11376
|
activeModal: activeChat?.activeModal || null
|
|
10223
11377
|
}),
|
|
10224
11378
|
title,
|
|
10225
|
-
workspace
|
|
11379
|
+
workspace,
|
|
11380
|
+
...git && { git },
|
|
10226
11381
|
activeChat,
|
|
10227
11382
|
...summaryMetadata && { summaryMetadata },
|
|
10228
11383
|
...includeSessionMetadata && { capabilities: state.sessionCapabilities || IDE_SESSION_CAPABILITIES },
|
|
@@ -10243,6 +11398,8 @@ function buildExtensionAgentSession(parent, ext, options) {
|
|
|
10243
11398
|
const controlValues = normalizeProviderStateControlValues(ext.controlValues);
|
|
10244
11399
|
const includeSessionMetadata = shouldIncludeSessionMetadata(profile);
|
|
10245
11400
|
const includeSessionControls = shouldIncludeSessionControls(profile);
|
|
11401
|
+
const workspace = parent.workspace || null;
|
|
11402
|
+
const git = getGitSummaryForWorkspace(workspace, options);
|
|
10246
11403
|
return {
|
|
10247
11404
|
id: ext.instanceId || `${parent.instanceId}:${ext.type}`,
|
|
10248
11405
|
parentId: parent.instanceId || parent.type,
|
|
@@ -10255,7 +11412,8 @@ function buildExtensionAgentSession(parent, ext, options) {
|
|
|
10255
11412
|
activeModal: activeChat?.activeModal || null
|
|
10256
11413
|
}),
|
|
10257
11414
|
title: activeChat?.title || ext.name,
|
|
10258
|
-
workspace
|
|
11415
|
+
workspace,
|
|
11416
|
+
...git && { git },
|
|
10259
11417
|
activeChat,
|
|
10260
11418
|
...summaryMetadata && { summaryMetadata },
|
|
10261
11419
|
...includeSessionMetadata && { capabilities: ext.sessionCapabilities || EXTENSION_SESSION_CAPABILITIES },
|
|
@@ -10291,6 +11449,8 @@ function buildCliSession(state, options) {
|
|
|
10291
11449
|
const includeSessionMetadata = shouldIncludeSessionMetadata(profile);
|
|
10292
11450
|
const includeRuntimeMetadata = shouldIncludeRuntimeMetadata(profile);
|
|
10293
11451
|
const includeSessionControls = shouldIncludeSessionControls(profile);
|
|
11452
|
+
const workspace = state.workspace || null;
|
|
11453
|
+
const git = getGitSummaryForWorkspace(workspace, options);
|
|
10294
11454
|
return {
|
|
10295
11455
|
id: state.instanceId,
|
|
10296
11456
|
parentId: null,
|
|
@@ -10303,7 +11463,8 @@ function buildCliSession(state, options) {
|
|
|
10303
11463
|
activeModal: activeChat?.activeModal || null
|
|
10304
11464
|
}),
|
|
10305
11465
|
title: activeChat?.title || state.name,
|
|
10306
|
-
workspace
|
|
11466
|
+
workspace,
|
|
11467
|
+
...git && { git },
|
|
10307
11468
|
...includeRuntimeMetadata && {
|
|
10308
11469
|
runtimeKey: state.runtime?.runtimeKey,
|
|
10309
11470
|
runtimeDisplayName: state.runtime?.displayName,
|
|
@@ -10338,6 +11499,8 @@ function buildAcpSession(state, options) {
|
|
|
10338
11499
|
const controlValues = normalizeProviderStateControlValues(state.controlValues);
|
|
10339
11500
|
const includeSessionMetadata = shouldIncludeSessionMetadata(profile);
|
|
10340
11501
|
const includeSessionControls = shouldIncludeSessionControls(profile);
|
|
11502
|
+
const workspace = state.workspace || null;
|
|
11503
|
+
const git = getGitSummaryForWorkspace(workspace, options);
|
|
10341
11504
|
return {
|
|
10342
11505
|
id: state.instanceId,
|
|
10343
11506
|
parentId: null,
|
|
@@ -10349,7 +11512,8 @@ function buildAcpSession(state, options) {
|
|
|
10349
11512
|
activeModal: activeChat?.activeModal || null
|
|
10350
11513
|
}),
|
|
10351
11514
|
title: activeChat?.title || state.name,
|
|
10352
|
-
workspace
|
|
11515
|
+
workspace,
|
|
11516
|
+
...git && { git },
|
|
10353
11517
|
activeChat,
|
|
10354
11518
|
...summaryMetadata && { summaryMetadata },
|
|
10355
11519
|
...includeSessionMetadata && { capabilities: ACP_SESSION_CAPABILITIES },
|
|
@@ -10468,7 +11632,7 @@ function resolveLegacyProviderScript(fn, scriptName, params) {
|
|
|
10468
11632
|
// src/commands/chat-commands.ts
|
|
10469
11633
|
var fs4 = __toESM(require("fs"));
|
|
10470
11634
|
var os6 = __toESM(require("os"));
|
|
10471
|
-
var
|
|
11635
|
+
var path11 = __toESM(require("path"));
|
|
10472
11636
|
var import_node_crypto = require("crypto");
|
|
10473
11637
|
init_contracts();
|
|
10474
11638
|
|
|
@@ -11161,7 +12325,7 @@ function buildDebugBundleText(bundle) {
|
|
|
11161
12325
|
}
|
|
11162
12326
|
function getChatDebugBundleDir() {
|
|
11163
12327
|
const override = typeof process.env.ADHDEV_DEBUG_BUNDLE_DIR === "string" ? process.env.ADHDEV_DEBUG_BUNDLE_DIR.trim() : "";
|
|
11164
|
-
return override ||
|
|
12328
|
+
return override || path11.join(os6.homedir(), ".adhdev", "debug-bundles", "chat");
|
|
11165
12329
|
}
|
|
11166
12330
|
function safeBundleIdSegment(value, fallback) {
|
|
11167
12331
|
const normalized = String(value || fallback).trim().replace(/[^A-Za-z0-9_.-]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 80);
|
|
@@ -11194,7 +12358,7 @@ function storeChatDebugBundleOnDaemon(bundle, targetSessionId) {
|
|
|
11194
12358
|
const bundleId = createChatDebugBundleId(targetSessionId);
|
|
11195
12359
|
const dir = getChatDebugBundleDir();
|
|
11196
12360
|
fs4.mkdirSync(dir, { recursive: true });
|
|
11197
|
-
const savedPath =
|
|
12361
|
+
const savedPath = path11.join(dir, `${bundleId}.json`);
|
|
11198
12362
|
const json = `${JSON.stringify(bundle, null, 2)}
|
|
11199
12363
|
`;
|
|
11200
12364
|
fs4.writeFileSync(savedPath, json, { encoding: "utf8", mode: 384 });
|
|
@@ -11363,10 +12527,32 @@ function getStateLastSignature(state) {
|
|
|
11363
12527
|
if (!last) return "";
|
|
11364
12528
|
return `${last.role || ""}:${String(last.content || "").replace(/\s+/g, " ").trim()}`;
|
|
11365
12529
|
}
|
|
12530
|
+
function toNonNegativeNumber(value) {
|
|
12531
|
+
const numeric = Number(value ?? 0);
|
|
12532
|
+
return Number.isFinite(numeric) ? Math.max(0, numeric) : 0;
|
|
12533
|
+
}
|
|
12534
|
+
function getCliVisibleTranscriptCount(adapter) {
|
|
12535
|
+
const adapterStatus = adapter?.getStatus?.() || {};
|
|
12536
|
+
const adapterMessages = Array.isArray(adapterStatus.messages) ? adapterStatus.messages : [];
|
|
12537
|
+
let parsedRecord = null;
|
|
12538
|
+
if (typeof adapter?.getScriptParsedStatus === "function") {
|
|
12539
|
+
try {
|
|
12540
|
+
const parsed = parseMaybeJson(adapter.getScriptParsedStatus());
|
|
12541
|
+
parsedRecord = parsed && typeof parsed === "object" ? parsed : null;
|
|
12542
|
+
} catch {
|
|
12543
|
+
parsedRecord = null;
|
|
12544
|
+
}
|
|
12545
|
+
}
|
|
12546
|
+
const parsedMessages = Array.isArray(parsedRecord?.messages) ? parsedRecord.messages : [];
|
|
12547
|
+
if (!parsedRecord) return adapterMessages.length;
|
|
12548
|
+
const parsedIsProviderAuthoritative = parsedRecord.transcriptAuthority === "provider" || parsedRecord.coverage === "full";
|
|
12549
|
+
const shouldPreferAdapterMessages = !parsedIsProviderAuthoritative && adapterMessages.length > 0 && adapterMessages.length > parsedMessages.length;
|
|
12550
|
+
return shouldPreferAdapterMessages ? adapterMessages.length : parsedMessages.length;
|
|
12551
|
+
}
|
|
11366
12552
|
async function getStableExtensionBaseline(h) {
|
|
11367
12553
|
const first = await readExtensionChatState(h);
|
|
11368
12554
|
if (getStateMessageCount(first) > 0 || getStateLastSignature(first)) return first;
|
|
11369
|
-
await new Promise((
|
|
12555
|
+
await new Promise((resolve15) => setTimeout(resolve15, 150));
|
|
11370
12556
|
const second = await readExtensionChatState(h);
|
|
11371
12557
|
return getStateMessageCount(second) >= getStateMessageCount(first) ? second : first;
|
|
11372
12558
|
}
|
|
@@ -11374,7 +12560,7 @@ async function verifyExtensionSendObserved(h, before) {
|
|
|
11374
12560
|
const beforeCount = getStateMessageCount(before);
|
|
11375
12561
|
const beforeSignature = getStateLastSignature(before);
|
|
11376
12562
|
for (let attempt = 0; attempt < 12; attempt += 1) {
|
|
11377
|
-
await new Promise((
|
|
12563
|
+
await new Promise((resolve15) => setTimeout(resolve15, 250));
|
|
11378
12564
|
const state = await readExtensionChatState(h);
|
|
11379
12565
|
if (state?.status === "waiting_approval") return true;
|
|
11380
12566
|
const afterCount = getStateMessageCount(state);
|
|
@@ -11391,11 +12577,11 @@ async function handleChatHistory(h, args) {
|
|
|
11391
12577
|
const provider = h.getProvider(agentType);
|
|
11392
12578
|
const agentStr = provider?.type || agentType || getCurrentProviderType(h);
|
|
11393
12579
|
const transport = getTargetTransport(h, provider);
|
|
11394
|
-
|
|
11395
|
-
|
|
12580
|
+
const hasExplicitExcludeRecentCount = args?.excludeRecentCount !== void 0 && args?.excludeRecentCount !== null;
|
|
12581
|
+
let excludeRecentCount = toNonNegativeNumber(args?.excludeRecentCount);
|
|
12582
|
+
if (!hasExplicitExcludeRecentCount && isCliLikeTransport(transport)) {
|
|
11396
12583
|
const adapter = getTargetedCliAdapter(h, args, provider?.type);
|
|
11397
|
-
const
|
|
11398
|
-
const visibleCount = Array.isArray(status?.messages) ? status.messages.length : 0;
|
|
12584
|
+
const visibleCount = getCliVisibleTranscriptCount(adapter);
|
|
11399
12585
|
if (visibleCount > excludeRecentCount) excludeRecentCount = visibleCount;
|
|
11400
12586
|
}
|
|
11401
12587
|
const workspace = typeof args?.workspace === "string" ? args.workspace : typeof h.currentSession?.workspace === "string" ? h.currentSession.workspace : void 0;
|
|
@@ -12310,7 +13496,7 @@ async function handleResolveAction(h, args) {
|
|
|
12310
13496
|
|
|
12311
13497
|
// src/commands/cdp-commands.ts
|
|
12312
13498
|
var fs5 = __toESM(require("fs"));
|
|
12313
|
-
var
|
|
13499
|
+
var path12 = __toESM(require("path"));
|
|
12314
13500
|
var os7 = __toESM(require("os"));
|
|
12315
13501
|
var KEY_TO_VK = {
|
|
12316
13502
|
Backspace: 8,
|
|
@@ -12567,25 +13753,25 @@ function resolveSafePath(requestedPath) {
|
|
|
12567
13753
|
const inputPath = rawPath || ".";
|
|
12568
13754
|
const home = os7.homedir();
|
|
12569
13755
|
if (inputPath.startsWith("~")) {
|
|
12570
|
-
return
|
|
13756
|
+
return path12.resolve(path12.join(home, inputPath.slice(1)));
|
|
12571
13757
|
}
|
|
12572
13758
|
if (process.platform === "win32") {
|
|
12573
13759
|
const normalized = normalizeWindowsRequestedPath(inputPath);
|
|
12574
|
-
if (
|
|
12575
|
-
return
|
|
13760
|
+
if (path12.win32.isAbsolute(normalized)) {
|
|
13761
|
+
return path12.win32.normalize(normalized);
|
|
12576
13762
|
}
|
|
12577
|
-
return
|
|
13763
|
+
return path12.win32.resolve(normalized);
|
|
12578
13764
|
}
|
|
12579
|
-
if (
|
|
12580
|
-
return
|
|
13765
|
+
if (path12.isAbsolute(inputPath)) {
|
|
13766
|
+
return path12.normalize(inputPath);
|
|
12581
13767
|
}
|
|
12582
|
-
return
|
|
13768
|
+
return path12.resolve(inputPath);
|
|
12583
13769
|
}
|
|
12584
13770
|
function listDirectoryEntriesSafe(dirPath) {
|
|
12585
13771
|
const entries = fs5.readdirSync(dirPath, { withFileTypes: true });
|
|
12586
13772
|
const files = [];
|
|
12587
13773
|
for (const entry of entries) {
|
|
12588
|
-
const entryPath =
|
|
13774
|
+
const entryPath = path12.join(dirPath, entry.name);
|
|
12589
13775
|
try {
|
|
12590
13776
|
if (entry.isDirectory()) {
|
|
12591
13777
|
files.push({ name: entry.name, type: "directory" });
|
|
@@ -12601,11 +13787,11 @@ function listDirectoryEntriesSafe(dirPath) {
|
|
|
12601
13787
|
files.push({ name: entry.name, type: "file", size });
|
|
12602
13788
|
continue;
|
|
12603
13789
|
}
|
|
12604
|
-
const
|
|
13790
|
+
const stat2 = fs5.statSync(entryPath);
|
|
12605
13791
|
files.push({
|
|
12606
13792
|
name: entry.name,
|
|
12607
|
-
type:
|
|
12608
|
-
size:
|
|
13793
|
+
type: stat2.isDirectory() ? "directory" : "file",
|
|
13794
|
+
size: stat2.isFile() ? stat2.size : void 0
|
|
12609
13795
|
});
|
|
12610
13796
|
} catch {
|
|
12611
13797
|
}
|
|
@@ -12639,7 +13825,7 @@ async function handleFileRead(h, args) {
|
|
|
12639
13825
|
async function handleFileWrite(h, args) {
|
|
12640
13826
|
try {
|
|
12641
13827
|
const filePath = resolveSafePath(args?.path);
|
|
12642
|
-
fs5.mkdirSync(
|
|
13828
|
+
fs5.mkdirSync(path12.dirname(filePath), { recursive: true });
|
|
12643
13829
|
fs5.writeFileSync(filePath, args?.content || "", "utf-8");
|
|
12644
13830
|
return { success: true, path: filePath };
|
|
12645
13831
|
} catch (e) {
|
|
@@ -12988,7 +14174,7 @@ async function executeProviderScript(h, args, scriptName) {
|
|
|
12988
14174
|
const enterCount = cliCommand.enterCount || 1;
|
|
12989
14175
|
await adapter.writeRaw(cliCommand.text + "\r");
|
|
12990
14176
|
for (let i = 1; i < enterCount; i += 1) {
|
|
12991
|
-
await new Promise((
|
|
14177
|
+
await new Promise((resolve15) => setTimeout(resolve15, 50));
|
|
12992
14178
|
await adapter.writeRaw("\r");
|
|
12993
14179
|
}
|
|
12994
14180
|
}
|
|
@@ -13482,6 +14668,12 @@ var DaemonCommandHandler = class {
|
|
|
13482
14668
|
this._currentRoute = this.resolveRoute(args);
|
|
13483
14669
|
const startedAt = Date.now();
|
|
13484
14670
|
this.logCommandStart(cmd, args);
|
|
14671
|
+
let result;
|
|
14672
|
+
if (isGitCommandName(cmd)) {
|
|
14673
|
+
result = await handleGitCommand(cmd, args, this._ctx.gitCommandServices);
|
|
14674
|
+
this.logCommandEnd(cmd, result, startedAt);
|
|
14675
|
+
return result;
|
|
14676
|
+
}
|
|
13485
14677
|
const sessionScopedCommands = /* @__PURE__ */ new Set([
|
|
13486
14678
|
"read_chat",
|
|
13487
14679
|
"get_chat_debug_bundle",
|
|
@@ -13507,7 +14699,6 @@ var DaemonCommandHandler = class {
|
|
|
13507
14699
|
this.logCommandEnd(cmd, result2, startedAt);
|
|
13508
14700
|
return result2;
|
|
13509
14701
|
}
|
|
13510
|
-
let result;
|
|
13511
14702
|
if (!this._currentRoute.session && !this._currentRoute.managerKey && !this._currentRoute.providerType) {
|
|
13512
14703
|
const cdpCommands = ["send_chat", "read_chat", "list_chats", "new_chat", "switch_chat", "set_mode", "change_model", "set_thought_level", "resolve_action"];
|
|
13513
14704
|
if (cdpCommands.includes(cmd)) {
|
|
@@ -13658,7 +14849,7 @@ var DaemonCommandHandler = class {
|
|
|
13658
14849
|
try {
|
|
13659
14850
|
const http3 = await import("http");
|
|
13660
14851
|
const postData = JSON.stringify(body);
|
|
13661
|
-
const result = await new Promise((
|
|
14852
|
+
const result = await new Promise((resolve15, reject) => {
|
|
13662
14853
|
const req = http3.request({
|
|
13663
14854
|
hostname: "127.0.0.1",
|
|
13664
14855
|
port: 19280,
|
|
@@ -13670,9 +14861,9 @@ var DaemonCommandHandler = class {
|
|
|
13670
14861
|
res.on("data", (chunk) => data += chunk);
|
|
13671
14862
|
res.on("end", () => {
|
|
13672
14863
|
try {
|
|
13673
|
-
|
|
14864
|
+
resolve15(JSON.parse(data));
|
|
13674
14865
|
} catch {
|
|
13675
|
-
|
|
14866
|
+
resolve15({ raw: data });
|
|
13676
14867
|
}
|
|
13677
14868
|
});
|
|
13678
14869
|
});
|
|
@@ -13690,15 +14881,15 @@ var DaemonCommandHandler = class {
|
|
|
13690
14881
|
if (!providerType) return { success: false, error: "providerType required" };
|
|
13691
14882
|
try {
|
|
13692
14883
|
const http3 = await import("http");
|
|
13693
|
-
const result = await new Promise((
|
|
14884
|
+
const result = await new Promise((resolve15, reject) => {
|
|
13694
14885
|
http3.get(`http://127.0.0.1:19280/api/providers/${providerType}/${endpoint}`, (res) => {
|
|
13695
14886
|
let data = "";
|
|
13696
14887
|
res.on("data", (chunk) => data += chunk);
|
|
13697
14888
|
res.on("end", () => {
|
|
13698
14889
|
try {
|
|
13699
|
-
|
|
14890
|
+
resolve15(JSON.parse(data));
|
|
13700
14891
|
} catch {
|
|
13701
|
-
|
|
14892
|
+
resolve15({ raw: data });
|
|
13702
14893
|
}
|
|
13703
14894
|
});
|
|
13704
14895
|
}).on("error", reject);
|
|
@@ -13712,7 +14903,7 @@ var DaemonCommandHandler = class {
|
|
|
13712
14903
|
try {
|
|
13713
14904
|
const http3 = await import("http");
|
|
13714
14905
|
const postData = JSON.stringify(args || {});
|
|
13715
|
-
const result = await new Promise((
|
|
14906
|
+
const result = await new Promise((resolve15, reject) => {
|
|
13716
14907
|
const req = http3.request({
|
|
13717
14908
|
hostname: "127.0.0.1",
|
|
13718
14909
|
port: 19280,
|
|
@@ -13724,9 +14915,9 @@ var DaemonCommandHandler = class {
|
|
|
13724
14915
|
res.on("data", (chunk) => data += chunk);
|
|
13725
14916
|
res.on("end", () => {
|
|
13726
14917
|
try {
|
|
13727
|
-
|
|
14918
|
+
resolve15(JSON.parse(data));
|
|
13728
14919
|
} catch {
|
|
13729
|
-
|
|
14920
|
+
resolve15({ raw: data });
|
|
13730
14921
|
}
|
|
13731
14922
|
});
|
|
13732
14923
|
});
|
|
@@ -13743,7 +14934,7 @@ var DaemonCommandHandler = class {
|
|
|
13743
14934
|
|
|
13744
14935
|
// src/commands/cli-manager.ts
|
|
13745
14936
|
var os13 = __toESM(require("os"));
|
|
13746
|
-
var
|
|
14937
|
+
var path16 = __toESM(require("path"));
|
|
13747
14938
|
var crypto4 = __toESM(require("crypto"));
|
|
13748
14939
|
var import_fs5 = require("fs");
|
|
13749
14940
|
var import_child_process6 = require("child_process");
|
|
@@ -13753,7 +14944,7 @@ init_config();
|
|
|
13753
14944
|
|
|
13754
14945
|
// src/providers/cli-provider-instance.ts
|
|
13755
14946
|
var os12 = __toESM(require("os"));
|
|
13756
|
-
var
|
|
14947
|
+
var path15 = __toESM(require("path"));
|
|
13757
14948
|
var crypto3 = __toESM(require("crypto"));
|
|
13758
14949
|
var fs6 = __toESM(require("fs"));
|
|
13759
14950
|
var import_node_module = require("module");
|
|
@@ -13814,7 +15005,7 @@ function buildIncrementalHistoryAppendMessages(previousMessages, currentMessages
|
|
|
13814
15005
|
var CachedDatabaseSync = null;
|
|
13815
15006
|
function getDatabaseSync() {
|
|
13816
15007
|
if (CachedDatabaseSync) return CachedDatabaseSync;
|
|
13817
|
-
const requireFn = typeof require === "function" ? require : (0, import_node_module.createRequire)(
|
|
15008
|
+
const requireFn = typeof require === "function" ? require : (0, import_node_module.createRequire)(path15.join(process.cwd(), "__adhdev_sqlite_loader__.js"));
|
|
13818
15009
|
const sqliteModule = requireFn(`node:${"sqlite"}`);
|
|
13819
15010
|
CachedDatabaseSync = sqliteModule.DatabaseSync;
|
|
13820
15011
|
if (!CachedDatabaseSync) {
|
|
@@ -13852,7 +15043,7 @@ async function waitForCliAdapterReady(adapter, options) {
|
|
|
13852
15043
|
if (status === "stopped") {
|
|
13853
15044
|
throw new Error("CLI runtime stopped before it became ready");
|
|
13854
15045
|
}
|
|
13855
|
-
await new Promise((
|
|
15046
|
+
await new Promise((resolve15) => setTimeout(resolve15, pollMs));
|
|
13856
15047
|
}
|
|
13857
15048
|
throw new Error(`CLI runtime did not become ready within ${timeoutMs}ms`);
|
|
13858
15049
|
}
|
|
@@ -14203,7 +15394,7 @@ var CliProviderInstance = class {
|
|
|
14203
15394
|
const enterCount = cliCommand.enterCount || 1;
|
|
14204
15395
|
await this.adapter.writeRaw(cliCommand.text + "\r");
|
|
14205
15396
|
for (let i = 1; i < enterCount; i += 1) {
|
|
14206
|
-
await new Promise((
|
|
15397
|
+
await new Promise((resolve15) => setTimeout(resolve15, 50));
|
|
14207
15398
|
await this.adapter.writeRaw("\r");
|
|
14208
15399
|
}
|
|
14209
15400
|
}
|
|
@@ -15317,13 +16508,13 @@ var AcpProviderInstance = class {
|
|
|
15317
16508
|
}
|
|
15318
16509
|
this.currentStatus = "waiting_approval";
|
|
15319
16510
|
this.detectStatusTransition();
|
|
15320
|
-
const approved = await new Promise((
|
|
15321
|
-
this.permissionResolvers.push(
|
|
16511
|
+
const approved = await new Promise((resolve15) => {
|
|
16512
|
+
this.permissionResolvers.push(resolve15);
|
|
15322
16513
|
setTimeout(() => {
|
|
15323
|
-
const idx = this.permissionResolvers.indexOf(
|
|
16514
|
+
const idx = this.permissionResolvers.indexOf(resolve15);
|
|
15324
16515
|
if (idx >= 0) {
|
|
15325
16516
|
this.permissionResolvers.splice(idx, 1);
|
|
15326
|
-
|
|
16517
|
+
resolve15(false);
|
|
15327
16518
|
}
|
|
15328
16519
|
}, 3e5);
|
|
15329
16520
|
});
|
|
@@ -15898,11 +17089,11 @@ function shouldRestoreHostedRuntime(record, managerTag) {
|
|
|
15898
17089
|
// src/commands/cli-manager.ts
|
|
15899
17090
|
function isExplicitCommand(command) {
|
|
15900
17091
|
const trimmed = command.trim();
|
|
15901
|
-
return
|
|
17092
|
+
return path16.isAbsolute(trimmed) || trimmed.includes("/") || trimmed.includes("\\") || trimmed.startsWith("~");
|
|
15902
17093
|
}
|
|
15903
17094
|
function expandExecutable(command) {
|
|
15904
17095
|
const trimmed = command.trim();
|
|
15905
|
-
return trimmed.startsWith("~") ?
|
|
17096
|
+
return trimmed.startsWith("~") ? path16.join(os13.homedir(), trimmed.slice(1)) : trimmed;
|
|
15906
17097
|
}
|
|
15907
17098
|
function commandExists(command) {
|
|
15908
17099
|
const trimmed = command.trim();
|
|
@@ -16183,7 +17374,7 @@ var DaemonCliManager = class {
|
|
|
16183
17374
|
async startSession(cliType, workingDir, cliArgs, initialModel, options) {
|
|
16184
17375
|
const trimmed = (workingDir || "").trim();
|
|
16185
17376
|
if (!trimmed) throw new Error("working directory required");
|
|
16186
|
-
const resolvedDir = trimmed.startsWith("~") ? trimmed.replace(/^~/, os13.homedir()) :
|
|
17377
|
+
const resolvedDir = trimmed.startsWith("~") ? trimmed.replace(/^~/, os13.homedir()) : path16.resolve(trimmed);
|
|
16187
17378
|
const normalizedType = this.providerLoader.resolveAlias(cliType);
|
|
16188
17379
|
const rawProvider = this.providerLoader.getByAlias(cliType);
|
|
16189
17380
|
const provider = rawProvider ? this.providerLoader.resolve(normalizedType) || rawProvider : void 0;
|
|
@@ -16684,11 +17875,11 @@ Run 'adhdev doctor' for detailed diagnostics.`
|
|
|
16684
17875
|
var import_child_process7 = require("child_process");
|
|
16685
17876
|
var net = __toESM(require("net"));
|
|
16686
17877
|
var os15 = __toESM(require("os"));
|
|
16687
|
-
var
|
|
17878
|
+
var path18 = __toESM(require("path"));
|
|
16688
17879
|
|
|
16689
17880
|
// src/providers/provider-loader.ts
|
|
16690
17881
|
var fs7 = __toESM(require("fs"));
|
|
16691
|
-
var
|
|
17882
|
+
var path17 = __toESM(require("path"));
|
|
16692
17883
|
var os14 = __toESM(require("os"));
|
|
16693
17884
|
var chokidar = __toESM(require("chokidar"));
|
|
16694
17885
|
init_logger();
|
|
@@ -16953,7 +18144,7 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
16953
18144
|
try {
|
|
16954
18145
|
if (!fs7.existsSync(candidate) || !fs7.statSync(candidate).isDirectory()) return false;
|
|
16955
18146
|
return ["ide", "extension", "cli", "acp"].some(
|
|
16956
|
-
(category) => fs7.existsSync(
|
|
18147
|
+
(category) => fs7.existsSync(path17.join(candidate, category))
|
|
16957
18148
|
);
|
|
16958
18149
|
} catch {
|
|
16959
18150
|
return false;
|
|
@@ -16961,20 +18152,20 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
16961
18152
|
}
|
|
16962
18153
|
static hasProviderRootMarker(candidate) {
|
|
16963
18154
|
try {
|
|
16964
|
-
return fs7.existsSync(
|
|
18155
|
+
return fs7.existsSync(path17.join(candidate, _ProviderLoader.SIBLING_MARKER_FILE));
|
|
16965
18156
|
} catch {
|
|
16966
18157
|
return false;
|
|
16967
18158
|
}
|
|
16968
18159
|
}
|
|
16969
18160
|
detectDefaultUserDir() {
|
|
16970
|
-
const fallback =
|
|
18161
|
+
const fallback = path17.join(os14.homedir(), ".adhdev", "providers");
|
|
16971
18162
|
const envOptIn = process.env[_ProviderLoader.SIBLING_ENV_VAR] === "1";
|
|
16972
18163
|
const visited = /* @__PURE__ */ new Set();
|
|
16973
18164
|
for (const start of this.probeStarts) {
|
|
16974
|
-
let current =
|
|
18165
|
+
let current = path17.resolve(start);
|
|
16975
18166
|
while (!visited.has(current)) {
|
|
16976
18167
|
visited.add(current);
|
|
16977
|
-
const siblingCandidate =
|
|
18168
|
+
const siblingCandidate = path17.join(path17.dirname(current), _ProviderLoader.REPO_PROVIDER_DIRNAME);
|
|
16978
18169
|
if (_ProviderLoader.looksLikeProviderRoot(siblingCandidate)) {
|
|
16979
18170
|
const hasMarker = _ProviderLoader.hasProviderRootMarker(siblingCandidate);
|
|
16980
18171
|
if (envOptIn || hasMarker) {
|
|
@@ -16996,7 +18187,7 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
16996
18187
|
return { path: siblingCandidate, source };
|
|
16997
18188
|
}
|
|
16998
18189
|
}
|
|
16999
|
-
const parent =
|
|
18190
|
+
const parent = path17.dirname(current);
|
|
17000
18191
|
if (parent === current) break;
|
|
17001
18192
|
current = parent;
|
|
17002
18193
|
}
|
|
@@ -17006,11 +18197,11 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
17006
18197
|
constructor(options) {
|
|
17007
18198
|
this.logFn = options?.logFn || LOG.forComponent("Provider").asLogFn();
|
|
17008
18199
|
this.probeStarts = options?.probeStarts ?? [process.cwd(), __dirname];
|
|
17009
|
-
this.defaultProvidersDir =
|
|
18200
|
+
this.defaultProvidersDir = path17.join(os14.homedir(), ".adhdev", "providers");
|
|
17010
18201
|
const detected = this.detectDefaultUserDir();
|
|
17011
18202
|
this.userDir = detected.path;
|
|
17012
18203
|
this.userDirSource = detected.source;
|
|
17013
|
-
this.upstreamDir =
|
|
18204
|
+
this.upstreamDir = path17.join(this.defaultProvidersDir, ".upstream");
|
|
17014
18205
|
this.disableUpstream = false;
|
|
17015
18206
|
this.applySourceConfig({
|
|
17016
18207
|
userDir: options?.userDir,
|
|
@@ -17069,7 +18260,7 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
17069
18260
|
this.userDir = detected.path;
|
|
17070
18261
|
this.userDirSource = detected.source;
|
|
17071
18262
|
}
|
|
17072
|
-
this.upstreamDir =
|
|
18263
|
+
this.upstreamDir = path17.join(this.defaultProvidersDir, ".upstream");
|
|
17073
18264
|
this.disableUpstream = this.sourceMode === "no-upstream";
|
|
17074
18265
|
if (this.explicitProviderDir) {
|
|
17075
18266
|
this.log(`Config 'providerDir' applied: ${this.userDir}`);
|
|
@@ -17083,7 +18274,7 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
17083
18274
|
* Canonical provider directory shape for a given root.
|
|
17084
18275
|
*/
|
|
17085
18276
|
getProviderDir(root, category, type) {
|
|
17086
|
-
return
|
|
18277
|
+
return path17.join(root, category, type);
|
|
17087
18278
|
}
|
|
17088
18279
|
/**
|
|
17089
18280
|
* Canonical user override directory for a provider.
|
|
@@ -17110,7 +18301,7 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
17110
18301
|
resolveProviderFile(type, ...segments) {
|
|
17111
18302
|
const dir = this.findProviderDirInternal(type);
|
|
17112
18303
|
if (!dir) return null;
|
|
17113
|
-
return
|
|
18304
|
+
return path17.join(dir, ...segments);
|
|
17114
18305
|
}
|
|
17115
18306
|
/**
|
|
17116
18307
|
* Load all providers (3-tier priority)
|
|
@@ -17149,7 +18340,7 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
17149
18340
|
if (!fs7.existsSync(this.upstreamDir)) return false;
|
|
17150
18341
|
try {
|
|
17151
18342
|
return fs7.readdirSync(this.upstreamDir).some(
|
|
17152
|
-
(d) => fs7.statSync(
|
|
18343
|
+
(d) => fs7.statSync(path17.join(this.upstreamDir, d)).isDirectory()
|
|
17153
18344
|
);
|
|
17154
18345
|
} catch {
|
|
17155
18346
|
return false;
|
|
@@ -17646,8 +18837,8 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
17646
18837
|
resolved._resolvedScriptDir = entry.scriptDir;
|
|
17647
18838
|
resolved._resolvedScriptsSource = `compatibility:${entry.ideVersion}`;
|
|
17648
18839
|
if (providerDir) {
|
|
17649
|
-
const fullDir =
|
|
17650
|
-
resolved._resolvedScriptsPath = fs7.existsSync(
|
|
18840
|
+
const fullDir = path17.join(providerDir, entry.scriptDir);
|
|
18841
|
+
resolved._resolvedScriptsPath = fs7.existsSync(path17.join(fullDir, "scripts.js")) ? path17.join(fullDir, "scripts.js") : fullDir;
|
|
17651
18842
|
}
|
|
17652
18843
|
matched = true;
|
|
17653
18844
|
}
|
|
@@ -17662,8 +18853,8 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
17662
18853
|
resolved._resolvedScriptDir = base.defaultScriptDir;
|
|
17663
18854
|
resolved._resolvedScriptsSource = "defaultScriptDir:version_miss";
|
|
17664
18855
|
if (providerDir) {
|
|
17665
|
-
const fullDir =
|
|
17666
|
-
resolved._resolvedScriptsPath = fs7.existsSync(
|
|
18856
|
+
const fullDir = path17.join(providerDir, base.defaultScriptDir);
|
|
18857
|
+
resolved._resolvedScriptsPath = fs7.existsSync(path17.join(fullDir, "scripts.js")) ? path17.join(fullDir, "scripts.js") : fullDir;
|
|
17667
18858
|
}
|
|
17668
18859
|
}
|
|
17669
18860
|
resolved._versionWarning = `Version ${currentVersion} not in compatibility matrix. Using default scripts.`;
|
|
@@ -17680,8 +18871,8 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
17680
18871
|
resolved._resolvedScriptDir = dirOverride;
|
|
17681
18872
|
resolved._resolvedScriptsSource = `versions:${range}`;
|
|
17682
18873
|
if (providerDir) {
|
|
17683
|
-
const fullDir =
|
|
17684
|
-
resolved._resolvedScriptsPath = fs7.existsSync(
|
|
18874
|
+
const fullDir = path17.join(providerDir, dirOverride);
|
|
18875
|
+
resolved._resolvedScriptsPath = fs7.existsSync(path17.join(fullDir, "scripts.js")) ? path17.join(fullDir, "scripts.js") : fullDir;
|
|
17685
18876
|
}
|
|
17686
18877
|
}
|
|
17687
18878
|
} else if (override.scripts) {
|
|
@@ -17697,8 +18888,8 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
17697
18888
|
resolved._resolvedScriptDir = base.defaultScriptDir;
|
|
17698
18889
|
resolved._resolvedScriptsSource = "defaultScriptDir:no_version";
|
|
17699
18890
|
if (providerDir) {
|
|
17700
|
-
const fullDir =
|
|
17701
|
-
resolved._resolvedScriptsPath = fs7.existsSync(
|
|
18891
|
+
const fullDir = path17.join(providerDir, base.defaultScriptDir);
|
|
18892
|
+
resolved._resolvedScriptsPath = fs7.existsSync(path17.join(fullDir, "scripts.js")) ? path17.join(fullDir, "scripts.js") : fullDir;
|
|
17702
18893
|
}
|
|
17703
18894
|
}
|
|
17704
18895
|
}
|
|
@@ -17730,14 +18921,14 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
17730
18921
|
this.log(` [loadScriptsFromDir] ${type}: providerDir not found`);
|
|
17731
18922
|
return null;
|
|
17732
18923
|
}
|
|
17733
|
-
const dir =
|
|
18924
|
+
const dir = path17.join(providerDir, scriptDir);
|
|
17734
18925
|
if (!fs7.existsSync(dir)) {
|
|
17735
18926
|
this.log(` [loadScriptsFromDir] ${type}: dir not found: ${dir}`);
|
|
17736
18927
|
return null;
|
|
17737
18928
|
}
|
|
17738
18929
|
const cached = this.scriptsCache.get(dir);
|
|
17739
18930
|
if (cached) return cached;
|
|
17740
|
-
const scriptsJs =
|
|
18931
|
+
const scriptsJs = path17.join(dir, "scripts.js");
|
|
17741
18932
|
if (fs7.existsSync(scriptsJs)) {
|
|
17742
18933
|
try {
|
|
17743
18934
|
delete require.cache[require.resolve(scriptsJs)];
|
|
@@ -17779,7 +18970,7 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
17779
18970
|
return;
|
|
17780
18971
|
}
|
|
17781
18972
|
if (filePath.endsWith(".js") || filePath.endsWith(".json")) {
|
|
17782
|
-
this.log(`File changed: ${
|
|
18973
|
+
this.log(`File changed: ${path17.basename(filePath)}, reloading...`);
|
|
17783
18974
|
this.reload();
|
|
17784
18975
|
}
|
|
17785
18976
|
};
|
|
@@ -17834,7 +19025,7 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
17834
19025
|
}
|
|
17835
19026
|
const https = require("https");
|
|
17836
19027
|
const { execSync: execSync7 } = require("child_process");
|
|
17837
|
-
const metaPath =
|
|
19028
|
+
const metaPath = path17.join(this.upstreamDir, _ProviderLoader.META_FILE);
|
|
17838
19029
|
let prevEtag = "";
|
|
17839
19030
|
let prevTimestamp = 0;
|
|
17840
19031
|
try {
|
|
@@ -17851,7 +19042,7 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
17851
19042
|
return { updated: false };
|
|
17852
19043
|
}
|
|
17853
19044
|
try {
|
|
17854
|
-
const etag = await new Promise((
|
|
19045
|
+
const etag = await new Promise((resolve15, reject) => {
|
|
17855
19046
|
const options = {
|
|
17856
19047
|
method: "HEAD",
|
|
17857
19048
|
hostname: "github.com",
|
|
@@ -17869,7 +19060,7 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
17869
19060
|
headers: { "User-Agent": "adhdev-launcher" },
|
|
17870
19061
|
timeout: 1e4
|
|
17871
19062
|
}, (res2) => {
|
|
17872
|
-
|
|
19063
|
+
resolve15(res2.headers.etag || res2.headers["last-modified"] || "");
|
|
17873
19064
|
});
|
|
17874
19065
|
req2.on("error", reject);
|
|
17875
19066
|
req2.on("timeout", () => {
|
|
@@ -17878,7 +19069,7 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
17878
19069
|
});
|
|
17879
19070
|
req2.end();
|
|
17880
19071
|
} else {
|
|
17881
|
-
|
|
19072
|
+
resolve15(res.headers.etag || res.headers["last-modified"] || "");
|
|
17882
19073
|
}
|
|
17883
19074
|
});
|
|
17884
19075
|
req.on("error", reject);
|
|
@@ -17894,17 +19085,17 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
17894
19085
|
return { updated: false };
|
|
17895
19086
|
}
|
|
17896
19087
|
this.log("Downloading latest providers from GitHub...");
|
|
17897
|
-
const tmpTar =
|
|
17898
|
-
const tmpExtract =
|
|
19088
|
+
const tmpTar = path17.join(os14.tmpdir(), `adhdev-providers-${Date.now()}.tar.gz`);
|
|
19089
|
+
const tmpExtract = path17.join(os14.tmpdir(), `adhdev-providers-extract-${Date.now()}`);
|
|
17899
19090
|
await this.downloadFile(_ProviderLoader.GITHUB_TARBALL_URL, tmpTar);
|
|
17900
19091
|
fs7.mkdirSync(tmpExtract, { recursive: true });
|
|
17901
19092
|
execSync7(`tar -xzf "${tmpTar}" -C "${tmpExtract}"`, { timeout: 3e4 });
|
|
17902
19093
|
const extracted = fs7.readdirSync(tmpExtract);
|
|
17903
19094
|
const rootDir = extracted.find(
|
|
17904
|
-
(d) => fs7.statSync(
|
|
19095
|
+
(d) => fs7.statSync(path17.join(tmpExtract, d)).isDirectory() && d.startsWith("adhdev-providers")
|
|
17905
19096
|
);
|
|
17906
19097
|
if (!rootDir) throw new Error("Unexpected tarball structure");
|
|
17907
|
-
const sourceDir =
|
|
19098
|
+
const sourceDir = path17.join(tmpExtract, rootDir);
|
|
17908
19099
|
const backupDir = this.upstreamDir + ".bak";
|
|
17909
19100
|
if (fs7.existsSync(this.upstreamDir)) {
|
|
17910
19101
|
if (fs7.existsSync(backupDir)) fs7.rmSync(backupDir, { recursive: true, force: true });
|
|
@@ -17942,7 +19133,7 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
17942
19133
|
downloadFile(url, destPath) {
|
|
17943
19134
|
const https = require("https");
|
|
17944
19135
|
const http3 = require("http");
|
|
17945
|
-
return new Promise((
|
|
19136
|
+
return new Promise((resolve15, reject) => {
|
|
17946
19137
|
const doRequest = (reqUrl, redirectCount = 0) => {
|
|
17947
19138
|
if (redirectCount > 5) {
|
|
17948
19139
|
reject(new Error("Too many redirects"));
|
|
@@ -17962,7 +19153,7 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
17962
19153
|
res.pipe(ws);
|
|
17963
19154
|
ws.on("finish", () => {
|
|
17964
19155
|
ws.close();
|
|
17965
|
-
|
|
19156
|
+
resolve15();
|
|
17966
19157
|
});
|
|
17967
19158
|
ws.on("error", reject);
|
|
17968
19159
|
});
|
|
@@ -17979,8 +19170,8 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
17979
19170
|
copyDirRecursive(src, dest) {
|
|
17980
19171
|
fs7.mkdirSync(dest, { recursive: true });
|
|
17981
19172
|
for (const entry of fs7.readdirSync(src, { withFileTypes: true })) {
|
|
17982
|
-
const srcPath =
|
|
17983
|
-
const destPath =
|
|
19173
|
+
const srcPath = path17.join(src, entry.name);
|
|
19174
|
+
const destPath = path17.join(dest, entry.name);
|
|
17984
19175
|
if (entry.isDirectory()) {
|
|
17985
19176
|
this.copyDirRecursive(srcPath, destPath);
|
|
17986
19177
|
} else {
|
|
@@ -17991,7 +19182,7 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
17991
19182
|
/** .meta.json save */
|
|
17992
19183
|
writeMeta(metaPath, etag, timestamp) {
|
|
17993
19184
|
try {
|
|
17994
|
-
fs7.mkdirSync(
|
|
19185
|
+
fs7.mkdirSync(path17.dirname(metaPath), { recursive: true });
|
|
17995
19186
|
fs7.writeFileSync(metaPath, JSON.stringify({
|
|
17996
19187
|
etag,
|
|
17997
19188
|
timestamp,
|
|
@@ -18008,7 +19199,7 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
18008
19199
|
const scan = (d) => {
|
|
18009
19200
|
try {
|
|
18010
19201
|
for (const entry of fs7.readdirSync(d, { withFileTypes: true })) {
|
|
18011
|
-
if (entry.isDirectory()) scan(
|
|
19202
|
+
if (entry.isDirectory()) scan(path17.join(d, entry.name));
|
|
18012
19203
|
else if (entry.name === "provider.json") count++;
|
|
18013
19204
|
}
|
|
18014
19205
|
} catch {
|
|
@@ -18236,17 +19427,17 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
18236
19427
|
for (const root of searchRoots) {
|
|
18237
19428
|
if (!fs7.existsSync(root)) continue;
|
|
18238
19429
|
const candidate = this.getProviderDir(root, cat, type);
|
|
18239
|
-
if (fs7.existsSync(
|
|
18240
|
-
const catDir =
|
|
19430
|
+
if (fs7.existsSync(path17.join(candidate, "provider.json"))) return candidate;
|
|
19431
|
+
const catDir = path17.join(root, cat);
|
|
18241
19432
|
if (fs7.existsSync(catDir)) {
|
|
18242
19433
|
try {
|
|
18243
19434
|
for (const entry of fs7.readdirSync(catDir, { withFileTypes: true })) {
|
|
18244
19435
|
if (!entry.isDirectory()) continue;
|
|
18245
|
-
const jsonPath =
|
|
19436
|
+
const jsonPath = path17.join(catDir, entry.name, "provider.json");
|
|
18246
19437
|
if (fs7.existsSync(jsonPath)) {
|
|
18247
19438
|
try {
|
|
18248
19439
|
const data = JSON.parse(fs7.readFileSync(jsonPath, "utf-8"));
|
|
18249
|
-
if (data.type === type) return
|
|
19440
|
+
if (data.type === type) return path17.join(catDir, entry.name);
|
|
18250
19441
|
} catch {
|
|
18251
19442
|
}
|
|
18252
19443
|
}
|
|
@@ -18263,7 +19454,7 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
18263
19454
|
* (template substitution is NOT applied here — scripts.js handles that)
|
|
18264
19455
|
*/
|
|
18265
19456
|
buildScriptWrappersFromDir(dir) {
|
|
18266
|
-
const scriptsJs =
|
|
19457
|
+
const scriptsJs = path17.join(dir, "scripts.js");
|
|
18267
19458
|
if (fs7.existsSync(scriptsJs)) {
|
|
18268
19459
|
try {
|
|
18269
19460
|
delete require.cache[require.resolve(scriptsJs)];
|
|
@@ -18277,7 +19468,7 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
18277
19468
|
for (const file of fs7.readdirSync(dir)) {
|
|
18278
19469
|
if (!file.endsWith(".js")) continue;
|
|
18279
19470
|
const scriptName = toCamel(file.replace(".js", ""));
|
|
18280
|
-
const filePath =
|
|
19471
|
+
const filePath = path17.join(dir, file);
|
|
18281
19472
|
result[scriptName] = (...args) => {
|
|
18282
19473
|
try {
|
|
18283
19474
|
let content = fs7.readFileSync(filePath, "utf-8");
|
|
@@ -18337,7 +19528,7 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
18337
19528
|
}
|
|
18338
19529
|
const hasJson = entries.some((e) => e.name === "provider.json");
|
|
18339
19530
|
if (hasJson) {
|
|
18340
|
-
const jsonPath =
|
|
19531
|
+
const jsonPath = path17.join(d, "provider.json");
|
|
18341
19532
|
try {
|
|
18342
19533
|
const raw = fs7.readFileSync(jsonPath, "utf-8");
|
|
18343
19534
|
const mod = JSON.parse(raw);
|
|
@@ -18358,7 +19549,7 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
18358
19549
|
this.log(`\u26A0 Invalid provider at ${jsonPath}: ${validation.errors.join("; ")}`);
|
|
18359
19550
|
} else {
|
|
18360
19551
|
const hasCompatibility = Array.isArray(normalizedProvider.compatibility);
|
|
18361
|
-
const scriptsPath =
|
|
19552
|
+
const scriptsPath = path17.join(d, "scripts.js");
|
|
18362
19553
|
if (!hasCompatibility && fs7.existsSync(scriptsPath)) {
|
|
18363
19554
|
try {
|
|
18364
19555
|
delete require.cache[require.resolve(scriptsPath)];
|
|
@@ -18384,7 +19575,7 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
18384
19575
|
if (!entry.isDirectory()) continue;
|
|
18385
19576
|
if (entry.name.startsWith("_") || entry.name.startsWith(".")) continue;
|
|
18386
19577
|
if (excludeDirs && d === dir && excludeDirs.includes(entry.name)) continue;
|
|
18387
|
-
scan(
|
|
19578
|
+
scan(path17.join(d, entry.name));
|
|
18388
19579
|
}
|
|
18389
19580
|
}
|
|
18390
19581
|
};
|
|
@@ -18419,9 +19610,9 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
18419
19610
|
}
|
|
18420
19611
|
}
|
|
18421
19612
|
compareVersions(a, b) {
|
|
18422
|
-
const
|
|
18423
|
-
const pa =
|
|
18424
|
-
const pb =
|
|
19613
|
+
const normalize4 = (v) => v.split(/[-_+]/)[0].split(".").map((x) => parseInt(x, 10) || 0);
|
|
19614
|
+
const pa = normalize4(a);
|
|
19615
|
+
const pb = normalize4(b);
|
|
18425
19616
|
for (let i = 0; i < Math.max(pa.length, pb.length); i++) {
|
|
18426
19617
|
const va = pa[i] || 0;
|
|
18427
19618
|
const vb = pb[i] || 0;
|
|
@@ -18541,17 +19732,17 @@ async function findFreePort(ports) {
|
|
|
18541
19732
|
throw new Error("No free port found");
|
|
18542
19733
|
}
|
|
18543
19734
|
function checkPortFree(port) {
|
|
18544
|
-
return new Promise((
|
|
19735
|
+
return new Promise((resolve15) => {
|
|
18545
19736
|
const server = net.createServer();
|
|
18546
19737
|
server.unref();
|
|
18547
|
-
server.on("error", () =>
|
|
19738
|
+
server.on("error", () => resolve15(false));
|
|
18548
19739
|
server.listen(port, "127.0.0.1", () => {
|
|
18549
|
-
server.close(() =>
|
|
19740
|
+
server.close(() => resolve15(true));
|
|
18550
19741
|
});
|
|
18551
19742
|
});
|
|
18552
19743
|
}
|
|
18553
19744
|
async function isCdpActive(port) {
|
|
18554
|
-
return new Promise((
|
|
19745
|
+
return new Promise((resolve15) => {
|
|
18555
19746
|
const req = require("http").get(`http://127.0.0.1:${port}/json/version`, {
|
|
18556
19747
|
timeout: 2e3
|
|
18557
19748
|
}, (res) => {
|
|
@@ -18560,16 +19751,16 @@ async function isCdpActive(port) {
|
|
|
18560
19751
|
res.on("end", () => {
|
|
18561
19752
|
try {
|
|
18562
19753
|
const info = JSON.parse(data);
|
|
18563
|
-
|
|
19754
|
+
resolve15(!!info["WebKit-Version"] || !!info["Browser"]);
|
|
18564
19755
|
} catch {
|
|
18565
|
-
|
|
19756
|
+
resolve15(false);
|
|
18566
19757
|
}
|
|
18567
19758
|
});
|
|
18568
19759
|
});
|
|
18569
|
-
req.on("error", () =>
|
|
19760
|
+
req.on("error", () => resolve15(false));
|
|
18570
19761
|
req.on("timeout", () => {
|
|
18571
19762
|
req.destroy();
|
|
18572
|
-
|
|
19763
|
+
resolve15(false);
|
|
18573
19764
|
});
|
|
18574
19765
|
});
|
|
18575
19766
|
}
|
|
@@ -18709,8 +19900,8 @@ function detectCurrentWorkspace(ideId) {
|
|
|
18709
19900
|
const appNameMap = getMacAppIdentifiers();
|
|
18710
19901
|
const appName = appNameMap[ideId];
|
|
18711
19902
|
if (appName) {
|
|
18712
|
-
const storagePath =
|
|
18713
|
-
process.env.APPDATA ||
|
|
19903
|
+
const storagePath = path18.join(
|
|
19904
|
+
process.env.APPDATA || path18.join(os15.homedir(), "AppData", "Roaming"),
|
|
18714
19905
|
appName,
|
|
18715
19906
|
"storage.json"
|
|
18716
19907
|
);
|
|
@@ -18888,9 +20079,9 @@ init_logger();
|
|
|
18888
20079
|
|
|
18889
20080
|
// src/logging/command-log.ts
|
|
18890
20081
|
var fs8 = __toESM(require("fs"));
|
|
18891
|
-
var
|
|
20082
|
+
var path19 = __toESM(require("path"));
|
|
18892
20083
|
var os16 = __toESM(require("os"));
|
|
18893
|
-
var LOG_DIR2 = process.platform === "win32" ?
|
|
20084
|
+
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");
|
|
18894
20085
|
var MAX_FILE_SIZE = 5 * 1024 * 1024;
|
|
18895
20086
|
var MAX_DAYS = 7;
|
|
18896
20087
|
try {
|
|
@@ -18928,13 +20119,13 @@ function getDateStr2() {
|
|
|
18928
20119
|
return (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
|
|
18929
20120
|
}
|
|
18930
20121
|
var currentDate2 = getDateStr2();
|
|
18931
|
-
var currentFile =
|
|
20122
|
+
var currentFile = path19.join(LOG_DIR2, `commands-${currentDate2}.jsonl`);
|
|
18932
20123
|
var writeCount2 = 0;
|
|
18933
20124
|
function checkRotation() {
|
|
18934
20125
|
const today = getDateStr2();
|
|
18935
20126
|
if (today !== currentDate2) {
|
|
18936
20127
|
currentDate2 = today;
|
|
18937
|
-
currentFile =
|
|
20128
|
+
currentFile = path19.join(LOG_DIR2, `commands-${currentDate2}.jsonl`);
|
|
18938
20129
|
cleanOldFiles();
|
|
18939
20130
|
}
|
|
18940
20131
|
}
|
|
@@ -18948,7 +20139,7 @@ function cleanOldFiles() {
|
|
|
18948
20139
|
const dateMatch = file.match(/commands-(\d{4}-\d{2}-\d{2})/);
|
|
18949
20140
|
if (dateMatch && dateMatch[1] < cutoffStr) {
|
|
18950
20141
|
try {
|
|
18951
|
-
fs8.unlinkSync(
|
|
20142
|
+
fs8.unlinkSync(path19.join(LOG_DIR2, file));
|
|
18952
20143
|
} catch {
|
|
18953
20144
|
}
|
|
18954
20145
|
}
|
|
@@ -18958,8 +20149,8 @@ function cleanOldFiles() {
|
|
|
18958
20149
|
}
|
|
18959
20150
|
function checkSize() {
|
|
18960
20151
|
try {
|
|
18961
|
-
const
|
|
18962
|
-
if (
|
|
20152
|
+
const stat2 = fs8.statSync(currentFile);
|
|
20153
|
+
if (stat2.size > MAX_FILE_SIZE) {
|
|
18963
20154
|
const backup = currentFile.replace(".jsonl", ".1.jsonl");
|
|
18964
20155
|
try {
|
|
18965
20156
|
fs8.unlinkSync(backup);
|
|
@@ -19245,12 +20436,18 @@ function buildStatusSnapshot(options) {
|
|
|
19245
20436
|
const unreadSourceSessions = buildSessionEntries(
|
|
19246
20437
|
options.allStates,
|
|
19247
20438
|
options.cdpManagers,
|
|
19248
|
-
{
|
|
20439
|
+
{
|
|
20440
|
+
profile: "full",
|
|
20441
|
+
getGitSummaryForWorkspace: options.getGitSummaryForWorkspace
|
|
20442
|
+
}
|
|
19249
20443
|
);
|
|
19250
20444
|
const sessions = profile === "full" ? unreadSourceSessions : profile === "live" ? unreadSourceSessions.map(projectLiveSessionFromFull) : buildSessionEntries(
|
|
19251
20445
|
options.allStates,
|
|
19252
20446
|
options.cdpManagers,
|
|
19253
|
-
{
|
|
20447
|
+
{
|
|
20448
|
+
profile,
|
|
20449
|
+
getGitSummaryForWorkspace: options.getGitSummaryForWorkspace
|
|
20450
|
+
}
|
|
19254
20451
|
);
|
|
19255
20452
|
const sessionsById = new Map(sessions.map((session) => [session.id, session]));
|
|
19256
20453
|
for (const sourceSession of unreadSourceSessions) {
|
|
@@ -19344,13 +20541,13 @@ var import_child_process8 = require("child_process");
|
|
|
19344
20541
|
var import_child_process9 = require("child_process");
|
|
19345
20542
|
var fs9 = __toESM(require("fs"));
|
|
19346
20543
|
var os18 = __toESM(require("os"));
|
|
19347
|
-
var
|
|
20544
|
+
var path20 = __toESM(require("path"));
|
|
19348
20545
|
var UPGRADE_HELPER_ENV = "ADHDEV_DAEMON_UPGRADE_HELPER";
|
|
19349
20546
|
function getUpgradeLogPath() {
|
|
19350
20547
|
const home = os18.homedir();
|
|
19351
|
-
const dir =
|
|
20548
|
+
const dir = path20.join(home, ".adhdev");
|
|
19352
20549
|
fs9.mkdirSync(dir, { recursive: true });
|
|
19353
|
-
return
|
|
20550
|
+
return path20.join(dir, "daemon-upgrade.log");
|
|
19354
20551
|
}
|
|
19355
20552
|
function appendUpgradeLog(message) {
|
|
19356
20553
|
const line = `[${(/* @__PURE__ */ new Date()).toISOString()}] ${message}
|
|
@@ -19361,14 +20558,14 @@ function appendUpgradeLog(message) {
|
|
|
19361
20558
|
}
|
|
19362
20559
|
}
|
|
19363
20560
|
function resolveSiblingNpmInvocation(nodeExecutable, platform10 = process.platform) {
|
|
19364
|
-
const binDir =
|
|
20561
|
+
const binDir = path20.dirname(nodeExecutable);
|
|
19365
20562
|
if (platform10 === "win32") {
|
|
19366
|
-
const npmCliPath =
|
|
20563
|
+
const npmCliPath = path20.join(binDir, "node_modules", "npm", "bin", "npm-cli.js");
|
|
19367
20564
|
if (fs9.existsSync(npmCliPath)) {
|
|
19368
20565
|
return { executable: nodeExecutable, argsPrefix: [npmCliPath], execOptions: getNpmExecOptions(platform10) };
|
|
19369
20566
|
}
|
|
19370
20567
|
for (const candidate of ["npm.exe", "npm"]) {
|
|
19371
|
-
const candidatePath =
|
|
20568
|
+
const candidatePath = path20.join(binDir, candidate);
|
|
19372
20569
|
if (fs9.existsSync(candidatePath)) {
|
|
19373
20570
|
return { executable: candidatePath, argsPrefix: [], execOptions: getNpmExecOptions(platform10) };
|
|
19374
20571
|
}
|
|
@@ -19376,7 +20573,7 @@ function resolveSiblingNpmInvocation(nodeExecutable, platform10 = process.platfo
|
|
|
19376
20573
|
return { executable: nodeExecutable, argsPrefix: [npmCliPath], execOptions: getNpmExecOptions(platform10) };
|
|
19377
20574
|
}
|
|
19378
20575
|
for (const candidate of ["npm"]) {
|
|
19379
|
-
const candidatePath =
|
|
20576
|
+
const candidatePath = path20.join(binDir, candidate);
|
|
19380
20577
|
if (fs9.existsSync(candidatePath)) {
|
|
19381
20578
|
return { executable: candidatePath, argsPrefix: [], execOptions: getNpmExecOptions(platform10) };
|
|
19382
20579
|
}
|
|
@@ -19393,13 +20590,13 @@ function findCurrentPackageRoot(currentCliPath, packageName) {
|
|
|
19393
20590
|
let currentDir = resolvedPath;
|
|
19394
20591
|
try {
|
|
19395
20592
|
if (fs9.statSync(resolvedPath).isFile()) {
|
|
19396
|
-
currentDir =
|
|
20593
|
+
currentDir = path20.dirname(resolvedPath);
|
|
19397
20594
|
}
|
|
19398
20595
|
} catch {
|
|
19399
|
-
currentDir =
|
|
20596
|
+
currentDir = path20.dirname(resolvedPath);
|
|
19400
20597
|
}
|
|
19401
20598
|
while (true) {
|
|
19402
|
-
const packageJsonPath =
|
|
20599
|
+
const packageJsonPath = path20.join(currentDir, "package.json");
|
|
19403
20600
|
try {
|
|
19404
20601
|
if (fs9.existsSync(packageJsonPath)) {
|
|
19405
20602
|
const parsed = JSON.parse(fs9.readFileSync(packageJsonPath, "utf8"));
|
|
@@ -19410,7 +20607,7 @@ function findCurrentPackageRoot(currentCliPath, packageName) {
|
|
|
19410
20607
|
}
|
|
19411
20608
|
} catch {
|
|
19412
20609
|
}
|
|
19413
|
-
const parentDir =
|
|
20610
|
+
const parentDir = path20.dirname(currentDir);
|
|
19414
20611
|
if (parentDir === currentDir) {
|
|
19415
20612
|
return null;
|
|
19416
20613
|
}
|
|
@@ -19418,13 +20615,13 @@ function findCurrentPackageRoot(currentCliPath, packageName) {
|
|
|
19418
20615
|
}
|
|
19419
20616
|
}
|
|
19420
20617
|
function resolveInstallPrefixFromPackageRoot(packageRoot, packageName) {
|
|
19421
|
-
const nodeModulesDir = packageName.startsWith("@") ?
|
|
19422
|
-
if (
|
|
20618
|
+
const nodeModulesDir = packageName.startsWith("@") ? path20.dirname(path20.dirname(packageRoot)) : path20.dirname(packageRoot);
|
|
20619
|
+
if (path20.basename(nodeModulesDir) !== "node_modules") {
|
|
19423
20620
|
return null;
|
|
19424
20621
|
}
|
|
19425
|
-
const maybeLibDir =
|
|
19426
|
-
if (
|
|
19427
|
-
return
|
|
20622
|
+
const maybeLibDir = path20.dirname(nodeModulesDir);
|
|
20623
|
+
if (path20.basename(maybeLibDir) === "lib") {
|
|
20624
|
+
return path20.dirname(maybeLibDir);
|
|
19428
20625
|
}
|
|
19429
20626
|
return maybeLibDir;
|
|
19430
20627
|
}
|
|
@@ -19532,14 +20729,14 @@ async function waitForPidExit(pid, timeoutMs) {
|
|
|
19532
20729
|
while (Date.now() - start < timeoutMs) {
|
|
19533
20730
|
try {
|
|
19534
20731
|
process.kill(pid, 0);
|
|
19535
|
-
await new Promise((
|
|
20732
|
+
await new Promise((resolve15) => setTimeout(resolve15, 250));
|
|
19536
20733
|
} catch {
|
|
19537
20734
|
return;
|
|
19538
20735
|
}
|
|
19539
20736
|
}
|
|
19540
20737
|
}
|
|
19541
20738
|
function stopSessionHostProcesses(appName) {
|
|
19542
|
-
const pidFile =
|
|
20739
|
+
const pidFile = path20.join(os18.homedir(), ".adhdev", `${appName}-session-host.pid`);
|
|
19543
20740
|
try {
|
|
19544
20741
|
if (fs9.existsSync(pidFile)) {
|
|
19545
20742
|
const pid = Number.parseInt(fs9.readFileSync(pidFile, "utf8").trim(), 10);
|
|
@@ -19556,7 +20753,7 @@ function stopSessionHostProcesses(appName) {
|
|
|
19556
20753
|
}
|
|
19557
20754
|
}
|
|
19558
20755
|
function removeDaemonPidFile() {
|
|
19559
|
-
const pidFile =
|
|
20756
|
+
const pidFile = path20.join(os18.homedir(), ".adhdev", "daemon.pid");
|
|
19560
20757
|
try {
|
|
19561
20758
|
fs9.unlinkSync(pidFile);
|
|
19562
20759
|
} catch {
|
|
@@ -19567,7 +20764,7 @@ function cleanupStaleGlobalInstallDirs(pkgName, surface) {
|
|
|
19567
20764
|
const npmRoot = String(execNpmCommandSync(["root", "-g", ...prefixArgs], { encoding: "utf8" }, surface)).trim();
|
|
19568
20765
|
if (!npmRoot) return;
|
|
19569
20766
|
const npmPrefix = surface.installPrefix || String(execNpmCommandSync(["prefix", "-g", ...prefixArgs], { encoding: "utf8" }, surface)).trim();
|
|
19570
|
-
const binDir = process.platform === "win32" ? npmPrefix :
|
|
20767
|
+
const binDir = process.platform === "win32" ? npmPrefix : path20.join(npmPrefix, "bin");
|
|
19571
20768
|
const packageBaseName = pkgName.startsWith("@") ? pkgName.split("/")[1] : pkgName;
|
|
19572
20769
|
const binNames = /* @__PURE__ */ new Set([packageBaseName]);
|
|
19573
20770
|
if (pkgName === "@adhdev/daemon-standalone") {
|
|
@@ -19575,25 +20772,25 @@ function cleanupStaleGlobalInstallDirs(pkgName, surface) {
|
|
|
19575
20772
|
}
|
|
19576
20773
|
if (pkgName.startsWith("@")) {
|
|
19577
20774
|
const [scope, name] = pkgName.split("/");
|
|
19578
|
-
const scopeDir =
|
|
20775
|
+
const scopeDir = path20.join(npmRoot, scope);
|
|
19579
20776
|
if (!fs9.existsSync(scopeDir)) return;
|
|
19580
20777
|
for (const entry of fs9.readdirSync(scopeDir)) {
|
|
19581
20778
|
if (!entry.startsWith(`.${name}-`)) continue;
|
|
19582
|
-
fs9.rmSync(
|
|
19583
|
-
appendUpgradeLog(`Removed stale scoped staging dir: ${
|
|
20779
|
+
fs9.rmSync(path20.join(scopeDir, entry), { recursive: true, force: true });
|
|
20780
|
+
appendUpgradeLog(`Removed stale scoped staging dir: ${path20.join(scopeDir, entry)}`);
|
|
19584
20781
|
}
|
|
19585
20782
|
} else {
|
|
19586
20783
|
for (const entry of fs9.readdirSync(npmRoot)) {
|
|
19587
20784
|
if (!entry.startsWith(`.${pkgName}-`)) continue;
|
|
19588
|
-
fs9.rmSync(
|
|
19589
|
-
appendUpgradeLog(`Removed stale staging dir: ${
|
|
20785
|
+
fs9.rmSync(path20.join(npmRoot, entry), { recursive: true, force: true });
|
|
20786
|
+
appendUpgradeLog(`Removed stale staging dir: ${path20.join(npmRoot, entry)}`);
|
|
19590
20787
|
}
|
|
19591
20788
|
}
|
|
19592
20789
|
if (fs9.existsSync(binDir)) {
|
|
19593
20790
|
for (const entry of fs9.readdirSync(binDir)) {
|
|
19594
20791
|
if (!Array.from(binNames).some((name) => entry.startsWith(`.${name}-`))) continue;
|
|
19595
|
-
fs9.rmSync(
|
|
19596
|
-
appendUpgradeLog(`Removed stale bin staging entry: ${
|
|
20792
|
+
fs9.rmSync(path20.join(binDir, entry), { recursive: true, force: true });
|
|
20793
|
+
appendUpgradeLog(`Removed stale bin staging entry: ${path20.join(binDir, entry)}`);
|
|
19597
20794
|
}
|
|
19598
20795
|
}
|
|
19599
20796
|
}
|
|
@@ -19643,7 +20840,7 @@ async function runDaemonUpgradeHelper(payload) {
|
|
|
19643
20840
|
appendUpgradeLog(installOutput.trim());
|
|
19644
20841
|
}
|
|
19645
20842
|
if (process.platform === "win32") {
|
|
19646
|
-
await new Promise((
|
|
20843
|
+
await new Promise((resolve15) => setTimeout(resolve15, 500));
|
|
19647
20844
|
cleanupStaleGlobalInstallDirs(payload.packageName, installCommand.surface);
|
|
19648
20845
|
appendUpgradeLog("Post-install staging cleanup complete");
|
|
19649
20846
|
}
|
|
@@ -21037,7 +22234,7 @@ var ProviderStreamAdapter = class {
|
|
|
21037
22234
|
const beforeCount = this.messageCount(before);
|
|
21038
22235
|
const beforeSignature = this.lastMessageSignature(before);
|
|
21039
22236
|
for (let attempt = 0; attempt < 12; attempt += 1) {
|
|
21040
|
-
await new Promise((
|
|
22237
|
+
await new Promise((resolve15) => setTimeout(resolve15, 250));
|
|
21041
22238
|
let state;
|
|
21042
22239
|
try {
|
|
21043
22240
|
state = await this.readChat(evaluate);
|
|
@@ -21059,7 +22256,7 @@ var ProviderStreamAdapter = class {
|
|
|
21059
22256
|
if (this.messageCount(first) > 0 || this.lastMessageSignature(first)) {
|
|
21060
22257
|
return first;
|
|
21061
22258
|
}
|
|
21062
|
-
await new Promise((
|
|
22259
|
+
await new Promise((resolve15) => setTimeout(resolve15, 150));
|
|
21063
22260
|
const second = await this.readChat(evaluate);
|
|
21064
22261
|
return this.messageCount(second) >= this.messageCount(first) ? second : first;
|
|
21065
22262
|
}
|
|
@@ -21210,7 +22407,7 @@ var ProviderStreamAdapter = class {
|
|
|
21210
22407
|
if (typeof data.error === "string" && data.error.trim()) return false;
|
|
21211
22408
|
}
|
|
21212
22409
|
for (let attempt = 0; attempt < 6; attempt += 1) {
|
|
21213
|
-
await new Promise((
|
|
22410
|
+
await new Promise((resolve15) => setTimeout(resolve15, 250));
|
|
21214
22411
|
const state = await this.readChat(evaluate);
|
|
21215
22412
|
const title = this.getStateTitle(state);
|
|
21216
22413
|
if (this.titlesMatch(title, sessionId)) return true;
|
|
@@ -22071,11 +23268,11 @@ init_chat_message_normalization();
|
|
|
22071
23268
|
|
|
22072
23269
|
// src/providers/version-archive.ts
|
|
22073
23270
|
var fs11 = __toESM(require("fs"));
|
|
22074
|
-
var
|
|
23271
|
+
var path21 = __toESM(require("path"));
|
|
22075
23272
|
var os19 = __toESM(require("os"));
|
|
22076
23273
|
var import_child_process10 = require("child_process");
|
|
22077
23274
|
var import_os3 = require("os");
|
|
22078
|
-
var ARCHIVE_PATH =
|
|
23275
|
+
var ARCHIVE_PATH = path21.join(os19.homedir(), ".adhdev", "version-history.json");
|
|
22079
23276
|
var MAX_ENTRIES_PER_PROVIDER = 20;
|
|
22080
23277
|
var VersionArchive = class {
|
|
22081
23278
|
history = {};
|
|
@@ -22122,7 +23319,7 @@ var VersionArchive = class {
|
|
|
22122
23319
|
}
|
|
22123
23320
|
save() {
|
|
22124
23321
|
try {
|
|
22125
|
-
fs11.mkdirSync(
|
|
23322
|
+
fs11.mkdirSync(path21.dirname(ARCHIVE_PATH), { recursive: true });
|
|
22126
23323
|
fs11.writeFileSync(ARCHIVE_PATH, JSON.stringify(this.history, null, 2));
|
|
22127
23324
|
} catch {
|
|
22128
23325
|
}
|
|
@@ -22179,7 +23376,7 @@ function checkPathExists2(paths) {
|
|
|
22179
23376
|
for (const p of paths) {
|
|
22180
23377
|
if (p.includes("*")) {
|
|
22181
23378
|
const home = os19.homedir();
|
|
22182
|
-
const resolved = p.replace(/\*/g, home.split(
|
|
23379
|
+
const resolved = p.replace(/\*/g, home.split(path21.sep).pop() || "");
|
|
22183
23380
|
if (fs11.existsSync(resolved)) return resolved;
|
|
22184
23381
|
} else {
|
|
22185
23382
|
if (fs11.existsSync(p)) return p;
|
|
@@ -22189,7 +23386,7 @@ function checkPathExists2(paths) {
|
|
|
22189
23386
|
}
|
|
22190
23387
|
function getMacAppVersion(appPath) {
|
|
22191
23388
|
if ((0, import_os3.platform)() !== "darwin" || !appPath.endsWith(".app")) return null;
|
|
22192
|
-
const plistPath =
|
|
23389
|
+
const plistPath = path21.join(appPath, "Contents", "Info.plist");
|
|
22193
23390
|
if (!fs11.existsSync(plistPath)) return null;
|
|
22194
23391
|
const raw = runCommand(`/usr/libexec/PlistBuddy -c "Print CFBundleShortVersionString" "${plistPath}"`);
|
|
22195
23392
|
return raw || null;
|
|
@@ -22215,7 +23412,7 @@ async function detectAllVersions(loader, archive) {
|
|
|
22215
23412
|
const cliBin = provider.cli ? findBinary2(provider.cli) : null;
|
|
22216
23413
|
let resolvedBin = cliBin;
|
|
22217
23414
|
if (!resolvedBin && appPath && currentOs === "darwin") {
|
|
22218
|
-
const bundled =
|
|
23415
|
+
const bundled = path21.join(appPath, "Contents", "Resources", "app", "bin", provider.cli || "");
|
|
22219
23416
|
if (provider.cli && fs11.existsSync(bundled)) resolvedBin = bundled;
|
|
22220
23417
|
}
|
|
22221
23418
|
info.installed = !!(appPath || resolvedBin);
|
|
@@ -22256,7 +23453,7 @@ async function detectAllVersions(loader, archive) {
|
|
|
22256
23453
|
// src/daemon/dev-server.ts
|
|
22257
23454
|
var http2 = __toESM(require("http"));
|
|
22258
23455
|
var fs15 = __toESM(require("fs"));
|
|
22259
|
-
var
|
|
23456
|
+
var path25 = __toESM(require("path"));
|
|
22260
23457
|
init_config();
|
|
22261
23458
|
|
|
22262
23459
|
// src/daemon/scaffold-template.ts
|
|
@@ -22607,7 +23804,7 @@ init_logger();
|
|
|
22607
23804
|
|
|
22608
23805
|
// src/daemon/dev-cdp-handlers.ts
|
|
22609
23806
|
var fs12 = __toESM(require("fs"));
|
|
22610
|
-
var
|
|
23807
|
+
var path22 = __toESM(require("path"));
|
|
22611
23808
|
init_logger();
|
|
22612
23809
|
async function handleCdpEvaluate(ctx, req, res) {
|
|
22613
23810
|
const body = await ctx.readBody(req);
|
|
@@ -22786,17 +23983,17 @@ async function handleScriptHints(ctx, type, _req, res) {
|
|
|
22786
23983
|
return;
|
|
22787
23984
|
}
|
|
22788
23985
|
let scriptsPath = "";
|
|
22789
|
-
const directScripts =
|
|
23986
|
+
const directScripts = path22.join(dir, "scripts.js");
|
|
22790
23987
|
if (fs12.existsSync(directScripts)) {
|
|
22791
23988
|
scriptsPath = directScripts;
|
|
22792
23989
|
} else {
|
|
22793
|
-
const scriptsDir =
|
|
23990
|
+
const scriptsDir = path22.join(dir, "scripts");
|
|
22794
23991
|
if (fs12.existsSync(scriptsDir)) {
|
|
22795
23992
|
const versions = fs12.readdirSync(scriptsDir).filter((d) => {
|
|
22796
|
-
return fs12.statSync(
|
|
23993
|
+
return fs12.statSync(path22.join(scriptsDir, d)).isDirectory();
|
|
22797
23994
|
}).sort().reverse();
|
|
22798
23995
|
for (const ver of versions) {
|
|
22799
|
-
const p =
|
|
23996
|
+
const p = path22.join(scriptsDir, ver, "scripts.js");
|
|
22800
23997
|
if (fs12.existsSync(p)) {
|
|
22801
23998
|
scriptsPath = p;
|
|
22802
23999
|
break;
|
|
@@ -23625,7 +24822,7 @@ async function handleDomContext(ctx, type, req, res) {
|
|
|
23625
24822
|
|
|
23626
24823
|
// src/daemon/dev-cli-debug.ts
|
|
23627
24824
|
var fs13 = __toESM(require("fs"));
|
|
23628
|
-
var
|
|
24825
|
+
var path23 = __toESM(require("path"));
|
|
23629
24826
|
function slugifyFixtureName(value) {
|
|
23630
24827
|
const normalized = String(value || "").trim().toLowerCase().replace(/[^a-z0-9._-]+/g, "-").replace(/^-+|-+$/g, "");
|
|
23631
24828
|
return normalized || `fixture-${Date.now()}`;
|
|
@@ -23635,11 +24832,11 @@ function getCliFixtureDir(ctx, type) {
|
|
|
23635
24832
|
if (!providerDir) {
|
|
23636
24833
|
throw new Error(`Provider directory not found for '${type}'`);
|
|
23637
24834
|
}
|
|
23638
|
-
return
|
|
24835
|
+
return path23.join(providerDir, "fixtures");
|
|
23639
24836
|
}
|
|
23640
24837
|
function readCliFixture(ctx, type, name) {
|
|
23641
24838
|
const fixtureDir = getCliFixtureDir(ctx, type);
|
|
23642
|
-
const filePath =
|
|
24839
|
+
const filePath = path23.join(fixtureDir, `${name}.json`);
|
|
23643
24840
|
if (!fs13.existsSync(filePath)) {
|
|
23644
24841
|
throw new Error(`Fixture not found: ${filePath}`);
|
|
23645
24842
|
}
|
|
@@ -23808,7 +25005,7 @@ function getCliTargetBundle(ctx, type, instanceId) {
|
|
|
23808
25005
|
return { target, instance, adapter };
|
|
23809
25006
|
}
|
|
23810
25007
|
function sleep(ms) {
|
|
23811
|
-
return new Promise((
|
|
25008
|
+
return new Promise((resolve15) => setTimeout(resolve15, ms));
|
|
23812
25009
|
}
|
|
23813
25010
|
async function waitForCliReady(ctx, type, instanceId, timeoutMs) {
|
|
23814
25011
|
const startedAt = Date.now();
|
|
@@ -24106,7 +25303,7 @@ async function runCliAutoImplVerification(ctx, type, verification) {
|
|
|
24106
25303
|
return {
|
|
24107
25304
|
mode: "fixture_replay_suite",
|
|
24108
25305
|
pass: results.every((item) => item.pass),
|
|
24109
|
-
failures: results.flatMap((item) => item.failures.map((
|
|
25306
|
+
failures: results.flatMap((item) => item.failures.map((failure2) => `${item.fixtureName}: ${failure2}`)),
|
|
24110
25307
|
result: firstFailure.result,
|
|
24111
25308
|
assertions: firstFailure.assertions,
|
|
24112
25309
|
fixture: firstFailure.fixture,
|
|
@@ -24406,7 +25603,7 @@ async function handleCliFixtureCapture(ctx, req, res) {
|
|
|
24406
25603
|
},
|
|
24407
25604
|
notes: typeof body?.notes === "string" ? body.notes : void 0
|
|
24408
25605
|
};
|
|
24409
|
-
const filePath =
|
|
25606
|
+
const filePath = path23.join(fixtureDir, `${name}.json`);
|
|
24410
25607
|
fs13.writeFileSync(filePath, JSON.stringify(fixture, null, 2));
|
|
24411
25608
|
ctx.json(res, 200, {
|
|
24412
25609
|
saved: true,
|
|
@@ -24430,7 +25627,7 @@ async function handleCliFixtureList(ctx, type, _req, res) {
|
|
|
24430
25627
|
return;
|
|
24431
25628
|
}
|
|
24432
25629
|
const fixtures = fs13.readdirSync(fixtureDir).filter((file) => file.endsWith(".json")).sort((a, b) => b.localeCompare(a, void 0, { numeric: true, sensitivity: "base" })).map((file) => {
|
|
24433
|
-
const fullPath =
|
|
25630
|
+
const fullPath = path23.join(fixtureDir, file);
|
|
24434
25631
|
try {
|
|
24435
25632
|
const raw = JSON.parse(fs13.readFileSync(fullPath, "utf-8"));
|
|
24436
25633
|
return {
|
|
@@ -24566,7 +25763,7 @@ async function handleCliRaw(ctx, req, res) {
|
|
|
24566
25763
|
|
|
24567
25764
|
// src/daemon/dev-auto-implement.ts
|
|
24568
25765
|
var fs14 = __toESM(require("fs"));
|
|
24569
|
-
var
|
|
25766
|
+
var path24 = __toESM(require("path"));
|
|
24570
25767
|
var os20 = __toESM(require("os"));
|
|
24571
25768
|
function getAutoImplPid(ctx) {
|
|
24572
25769
|
const pid = ctx.autoImplProcess?.pid;
|
|
@@ -24616,22 +25813,22 @@ function getLatestScriptVersionDir(scriptsDir) {
|
|
|
24616
25813
|
if (!fs14.existsSync(scriptsDir)) return null;
|
|
24617
25814
|
const versions = fs14.readdirSync(scriptsDir).filter((d) => {
|
|
24618
25815
|
try {
|
|
24619
|
-
return fs14.statSync(
|
|
25816
|
+
return fs14.statSync(path24.join(scriptsDir, d)).isDirectory();
|
|
24620
25817
|
} catch {
|
|
24621
25818
|
return false;
|
|
24622
25819
|
}
|
|
24623
25820
|
}).sort((a, b) => b.localeCompare(a, void 0, { numeric: true, sensitivity: "base" }));
|
|
24624
25821
|
if (versions.length === 0) return null;
|
|
24625
|
-
return
|
|
25822
|
+
return path24.join(scriptsDir, versions[0]);
|
|
24626
25823
|
}
|
|
24627
25824
|
function resolveAutoImplWritableProviderDir(ctx, category, type, requestedDir) {
|
|
24628
|
-
const canonicalUserDir =
|
|
24629
|
-
const desiredDir = requestedDir ?
|
|
24630
|
-
const upstreamRoot =
|
|
24631
|
-
if (desiredDir === upstreamRoot || desiredDir.startsWith(`${upstreamRoot}${
|
|
25825
|
+
const canonicalUserDir = path24.resolve(ctx.providerLoader.getUserProviderDir(category, type));
|
|
25826
|
+
const desiredDir = requestedDir ? path24.resolve(requestedDir) : canonicalUserDir;
|
|
25827
|
+
const upstreamRoot = path24.resolve(ctx.providerLoader.getUpstreamDir());
|
|
25828
|
+
if (desiredDir === upstreamRoot || desiredDir.startsWith(`${upstreamRoot}${path24.sep}`)) {
|
|
24632
25829
|
return { dir: null, reason: `Refusing to write into upstream provider directory: ${desiredDir}` };
|
|
24633
25830
|
}
|
|
24634
|
-
if (
|
|
25831
|
+
if (path24.basename(desiredDir) !== type) {
|
|
24635
25832
|
return { dir: null, reason: `Requested writable provider directory must end with '${type}': ${desiredDir}` };
|
|
24636
25833
|
}
|
|
24637
25834
|
const sourceDir = ctx.findProviderDir(type);
|
|
@@ -24639,11 +25836,11 @@ function resolveAutoImplWritableProviderDir(ctx, category, type, requestedDir) {
|
|
|
24639
25836
|
return { dir: null, reason: `Provider source directory not found for '${type}'` };
|
|
24640
25837
|
}
|
|
24641
25838
|
if (!fs14.existsSync(desiredDir)) {
|
|
24642
|
-
fs14.mkdirSync(
|
|
25839
|
+
fs14.mkdirSync(path24.dirname(desiredDir), { recursive: true });
|
|
24643
25840
|
fs14.cpSync(sourceDir, desiredDir, { recursive: true });
|
|
24644
25841
|
ctx.log(`Auto-implement writable copy created: ${desiredDir}`);
|
|
24645
25842
|
}
|
|
24646
|
-
const providerJson =
|
|
25843
|
+
const providerJson = path24.join(desiredDir, "provider.json");
|
|
24647
25844
|
if (!fs14.existsSync(providerJson)) {
|
|
24648
25845
|
return { dir: null, reason: `provider.json not found in writable provider directory: ${desiredDir}` };
|
|
24649
25846
|
}
|
|
@@ -24654,13 +25851,13 @@ function loadAutoImplReferenceScripts(ctx, referenceType) {
|
|
|
24654
25851
|
const refDir = ctx.findProviderDir(referenceType);
|
|
24655
25852
|
if (!refDir || !fs14.existsSync(refDir)) return {};
|
|
24656
25853
|
const referenceScripts = {};
|
|
24657
|
-
const scriptsDir =
|
|
25854
|
+
const scriptsDir = path24.join(refDir, "scripts");
|
|
24658
25855
|
const latestDir = getLatestScriptVersionDir(scriptsDir);
|
|
24659
25856
|
if (!latestDir) return referenceScripts;
|
|
24660
25857
|
for (const file of fs14.readdirSync(latestDir)) {
|
|
24661
25858
|
if (!file.endsWith(".js")) continue;
|
|
24662
25859
|
try {
|
|
24663
|
-
referenceScripts[file] = fs14.readFileSync(
|
|
25860
|
+
referenceScripts[file] = fs14.readFileSync(path24.join(latestDir, file), "utf-8");
|
|
24664
25861
|
} catch {
|
|
24665
25862
|
}
|
|
24666
25863
|
}
|
|
@@ -24768,9 +25965,9 @@ async function handleAutoImplement(ctx, type, req, res) {
|
|
|
24768
25965
|
});
|
|
24769
25966
|
const referenceScripts = loadAutoImplReferenceScripts(ctx, resolvedReference);
|
|
24770
25967
|
const prompt = buildAutoImplPrompt(ctx, type, provider, providerDir, functions, domContext, referenceScripts, comment, resolvedReference, verification);
|
|
24771
|
-
const tmpDir =
|
|
25968
|
+
const tmpDir = path24.join(os20.tmpdir(), "adhdev-autoimpl");
|
|
24772
25969
|
if (!fs14.existsSync(tmpDir)) fs14.mkdirSync(tmpDir, { recursive: true });
|
|
24773
|
-
const promptFile =
|
|
25970
|
+
const promptFile = path24.join(tmpDir, `prompt-${type}-${Date.now()}.md`);
|
|
24774
25971
|
fs14.writeFileSync(promptFile, prompt, "utf-8");
|
|
24775
25972
|
ctx.log(`Auto-implement prompt written to ${promptFile} (${prompt.length} chars)`);
|
|
24776
25973
|
const agentProvider = ctx.providerLoader.resolve(agent) || ctx.providerLoader.getMeta(agent);
|
|
@@ -25202,7 +26399,7 @@ function buildAutoImplPrompt(ctx, type, provider, providerDir, functions, domCon
|
|
|
25202
26399
|
setMode: "set_mode.js"
|
|
25203
26400
|
};
|
|
25204
26401
|
const targetFileNames = new Set(functions.map((fn) => funcToFile[fn]).filter(Boolean));
|
|
25205
|
-
const scriptsDir =
|
|
26402
|
+
const scriptsDir = path24.join(providerDir, "scripts");
|
|
25206
26403
|
const latestScriptsDir = getLatestScriptVersionDir(scriptsDir);
|
|
25207
26404
|
if (latestScriptsDir) {
|
|
25208
26405
|
lines.push(`Scripts version directory: \`${latestScriptsDir}\``);
|
|
@@ -25213,7 +26410,7 @@ function buildAutoImplPrompt(ctx, type, provider, providerDir, functions, domCon
|
|
|
25213
26410
|
for (const file of fs14.readdirSync(latestScriptsDir)) {
|
|
25214
26411
|
if (file.endsWith(".js") && targetFileNames.has(file)) {
|
|
25215
26412
|
try {
|
|
25216
|
-
const content = fs14.readFileSync(
|
|
26413
|
+
const content = fs14.readFileSync(path24.join(latestScriptsDir, file), "utf-8");
|
|
25217
26414
|
lines.push(`### \`${file}\` \u270F\uFE0F EDIT`);
|
|
25218
26415
|
lines.push("```javascript");
|
|
25219
26416
|
lines.push(content);
|
|
@@ -25230,7 +26427,7 @@ function buildAutoImplPrompt(ctx, type, provider, providerDir, functions, domCon
|
|
|
25230
26427
|
lines.push("");
|
|
25231
26428
|
for (const file of refFiles) {
|
|
25232
26429
|
try {
|
|
25233
|
-
const content = fs14.readFileSync(
|
|
26430
|
+
const content = fs14.readFileSync(path24.join(latestScriptsDir, file), "utf-8");
|
|
25234
26431
|
lines.push(`### \`${file}\` \u{1F512}`);
|
|
25235
26432
|
lines.push("```javascript");
|
|
25236
26433
|
lines.push(content);
|
|
@@ -25271,10 +26468,10 @@ function buildAutoImplPrompt(ctx, type, provider, providerDir, functions, domCon
|
|
|
25271
26468
|
lines.push("");
|
|
25272
26469
|
}
|
|
25273
26470
|
}
|
|
25274
|
-
const docsDir =
|
|
26471
|
+
const docsDir = path24.join(providerDir, "../../docs");
|
|
25275
26472
|
const loadGuide = (name) => {
|
|
25276
26473
|
try {
|
|
25277
|
-
const p =
|
|
26474
|
+
const p = path24.join(docsDir, name);
|
|
25278
26475
|
if (fs14.existsSync(p)) return fs14.readFileSync(p, "utf-8");
|
|
25279
26476
|
} catch {
|
|
25280
26477
|
}
|
|
@@ -25511,7 +26708,7 @@ function buildCliAutoImplPrompt(ctx, type, provider, providerDir, functions, ref
|
|
|
25511
26708
|
parseApproval: "parse_approval.js"
|
|
25512
26709
|
};
|
|
25513
26710
|
const targetFileNames = new Set(functions.map((fn) => funcToFile[fn]).filter(Boolean));
|
|
25514
|
-
const scriptsDir =
|
|
26711
|
+
const scriptsDir = path24.join(providerDir, "scripts");
|
|
25515
26712
|
const latestScriptsDir = getLatestScriptVersionDir(scriptsDir);
|
|
25516
26713
|
if (latestScriptsDir) {
|
|
25517
26714
|
lines.push(`Scripts version directory: \`${latestScriptsDir}\``);
|
|
@@ -25523,7 +26720,7 @@ function buildCliAutoImplPrompt(ctx, type, provider, providerDir, functions, ref
|
|
|
25523
26720
|
if (!file.endsWith(".js")) continue;
|
|
25524
26721
|
if (!targetFileNames.has(file)) continue;
|
|
25525
26722
|
try {
|
|
25526
|
-
const content = fs14.readFileSync(
|
|
26723
|
+
const content = fs14.readFileSync(path24.join(latestScriptsDir, file), "utf-8");
|
|
25527
26724
|
lines.push(`### \`${file}\` \u270F\uFE0F EDIT`);
|
|
25528
26725
|
lines.push("```javascript");
|
|
25529
26726
|
lines.push(content);
|
|
@@ -25539,7 +26736,7 @@ function buildCliAutoImplPrompt(ctx, type, provider, providerDir, functions, ref
|
|
|
25539
26736
|
lines.push("");
|
|
25540
26737
|
for (const file of refFiles) {
|
|
25541
26738
|
try {
|
|
25542
|
-
const content = fs14.readFileSync(
|
|
26739
|
+
const content = fs14.readFileSync(path24.join(latestScriptsDir, file), "utf-8");
|
|
25543
26740
|
lines.push(`### \`${file}\` \u{1F512}`);
|
|
25544
26741
|
lines.push("```javascript");
|
|
25545
26742
|
lines.push(content);
|
|
@@ -25572,10 +26769,10 @@ function buildCliAutoImplPrompt(ctx, type, provider, providerDir, functions, ref
|
|
|
25572
26769
|
lines.push("");
|
|
25573
26770
|
}
|
|
25574
26771
|
}
|
|
25575
|
-
const docsDir =
|
|
26772
|
+
const docsDir = path24.join(providerDir, "../../docs");
|
|
25576
26773
|
const loadGuide = (name) => {
|
|
25577
26774
|
try {
|
|
25578
|
-
const p =
|
|
26775
|
+
const p = path24.join(docsDir, name);
|
|
25579
26776
|
if (fs14.existsSync(p)) return fs14.readFileSync(p, "utf-8");
|
|
25580
26777
|
} catch {
|
|
25581
26778
|
}
|
|
@@ -26022,8 +27219,8 @@ var DevServer = class _DevServer {
|
|
|
26022
27219
|
}
|
|
26023
27220
|
getEndpointList() {
|
|
26024
27221
|
return this.routes.map((r) => {
|
|
26025
|
-
const
|
|
26026
|
-
return `${r.method.padEnd(5)} ${
|
|
27222
|
+
const path26 = typeof r.pattern === "string" ? r.pattern : r.pattern.source.replace(/\\\//g, "/").replace(/\(\[.*?\]\+\)/g, ":type").replace(/[\^$]/g, "");
|
|
27223
|
+
return `${r.method.padEnd(5)} ${path26}`;
|
|
26027
27224
|
});
|
|
26028
27225
|
}
|
|
26029
27226
|
async start(port = DEV_SERVER_PORT) {
|
|
@@ -26054,15 +27251,15 @@ var DevServer = class _DevServer {
|
|
|
26054
27251
|
this.json(res, 500, { error: e.message });
|
|
26055
27252
|
}
|
|
26056
27253
|
});
|
|
26057
|
-
return new Promise((
|
|
27254
|
+
return new Promise((resolve15, reject) => {
|
|
26058
27255
|
this.server.listen(port, "127.0.0.1", () => {
|
|
26059
27256
|
this.log(`Dev server listening on http://127.0.0.1:${port}`);
|
|
26060
|
-
|
|
27257
|
+
resolve15();
|
|
26061
27258
|
});
|
|
26062
27259
|
this.server.on("error", (e) => {
|
|
26063
27260
|
if (e.code === "EADDRINUSE") {
|
|
26064
27261
|
this.log(`Port ${port} in use, skipping dev server`);
|
|
26065
|
-
|
|
27262
|
+
resolve15();
|
|
26066
27263
|
} else {
|
|
26067
27264
|
reject(e);
|
|
26068
27265
|
}
|
|
@@ -26144,20 +27341,20 @@ var DevServer = class _DevServer {
|
|
|
26144
27341
|
child.stderr?.on("data", (d) => {
|
|
26145
27342
|
stderr += d.toString().slice(0, 2e3);
|
|
26146
27343
|
});
|
|
26147
|
-
await new Promise((
|
|
27344
|
+
await new Promise((resolve15) => {
|
|
26148
27345
|
const timer = setTimeout(() => {
|
|
26149
27346
|
child.kill();
|
|
26150
|
-
|
|
27347
|
+
resolve15();
|
|
26151
27348
|
}, 3e3);
|
|
26152
27349
|
child.on("exit", () => {
|
|
26153
27350
|
clearTimeout(timer);
|
|
26154
|
-
|
|
27351
|
+
resolve15();
|
|
26155
27352
|
});
|
|
26156
27353
|
child.stdout?.once("data", () => {
|
|
26157
27354
|
setTimeout(() => {
|
|
26158
27355
|
child.kill();
|
|
26159
27356
|
clearTimeout(timer);
|
|
26160
|
-
|
|
27357
|
+
resolve15();
|
|
26161
27358
|
}, 500);
|
|
26162
27359
|
});
|
|
26163
27360
|
});
|
|
@@ -26311,12 +27508,12 @@ var DevServer = class _DevServer {
|
|
|
26311
27508
|
// ─── DevConsole SPA ───
|
|
26312
27509
|
getConsoleDistDir() {
|
|
26313
27510
|
const candidates = [
|
|
26314
|
-
|
|
26315
|
-
|
|
26316
|
-
|
|
27511
|
+
path25.resolve(__dirname, "../../web-devconsole/dist"),
|
|
27512
|
+
path25.resolve(__dirname, "../../../web-devconsole/dist"),
|
|
27513
|
+
path25.join(process.cwd(), "packages/web-devconsole/dist")
|
|
26317
27514
|
];
|
|
26318
27515
|
for (const dir of candidates) {
|
|
26319
|
-
if (fs15.existsSync(
|
|
27516
|
+
if (fs15.existsSync(path25.join(dir, "index.html"))) return dir;
|
|
26320
27517
|
}
|
|
26321
27518
|
return null;
|
|
26322
27519
|
}
|
|
@@ -26326,7 +27523,7 @@ var DevServer = class _DevServer {
|
|
|
26326
27523
|
this.json(res, 500, { error: "DevConsole not found. Run: npm run build -w packages/web-devconsole" });
|
|
26327
27524
|
return;
|
|
26328
27525
|
}
|
|
26329
|
-
const htmlPath =
|
|
27526
|
+
const htmlPath = path25.join(distDir, "index.html");
|
|
26330
27527
|
try {
|
|
26331
27528
|
const html = fs15.readFileSync(htmlPath, "utf-8");
|
|
26332
27529
|
res.writeHead(200, { "Content-Type": "text/html; charset=utf-8" });
|
|
@@ -26351,15 +27548,15 @@ var DevServer = class _DevServer {
|
|
|
26351
27548
|
this.json(res, 404, { error: "Not found" });
|
|
26352
27549
|
return;
|
|
26353
27550
|
}
|
|
26354
|
-
const safePath =
|
|
26355
|
-
const filePath =
|
|
27551
|
+
const safePath = path25.normalize(pathname).replace(/^\.\.\//, "");
|
|
27552
|
+
const filePath = path25.join(distDir, safePath);
|
|
26356
27553
|
if (!filePath.startsWith(distDir)) {
|
|
26357
27554
|
this.json(res, 403, { error: "Forbidden" });
|
|
26358
27555
|
return;
|
|
26359
27556
|
}
|
|
26360
27557
|
try {
|
|
26361
27558
|
const content = fs15.readFileSync(filePath);
|
|
26362
|
-
const ext =
|
|
27559
|
+
const ext = path25.extname(filePath);
|
|
26363
27560
|
const contentType = _DevServer.MIME_MAP[ext] || "application/octet-stream";
|
|
26364
27561
|
res.writeHead(200, { "Content-Type": contentType, "Cache-Control": "public, max-age=31536000, immutable" });
|
|
26365
27562
|
res.end(content);
|
|
@@ -26472,10 +27669,10 @@ var DevServer = class _DevServer {
|
|
|
26472
27669
|
const rel = prefix ? `${prefix}/${entry.name}` : entry.name;
|
|
26473
27670
|
if (entry.isDirectory()) {
|
|
26474
27671
|
files.push({ path: rel, size: 0, type: "dir" });
|
|
26475
|
-
scan(
|
|
27672
|
+
scan(path25.join(d, entry.name), rel);
|
|
26476
27673
|
} else {
|
|
26477
|
-
const
|
|
26478
|
-
files.push({ path: rel, size:
|
|
27674
|
+
const stat2 = fs15.statSync(path25.join(d, entry.name));
|
|
27675
|
+
files.push({ path: rel, size: stat2.size, type: "file" });
|
|
26479
27676
|
}
|
|
26480
27677
|
}
|
|
26481
27678
|
} catch {
|
|
@@ -26497,7 +27694,7 @@ var DevServer = class _DevServer {
|
|
|
26497
27694
|
this.json(res, 404, { error: `Provider directory not found: ${type}` });
|
|
26498
27695
|
return;
|
|
26499
27696
|
}
|
|
26500
|
-
const fullPath =
|
|
27697
|
+
const fullPath = path25.resolve(dir, path25.normalize(filePath));
|
|
26501
27698
|
if (!fullPath.startsWith(dir)) {
|
|
26502
27699
|
this.json(res, 403, { error: "Forbidden" });
|
|
26503
27700
|
return;
|
|
@@ -26522,14 +27719,14 @@ var DevServer = class _DevServer {
|
|
|
26522
27719
|
this.json(res, 404, { error: `Provider directory not found: ${type}` });
|
|
26523
27720
|
return;
|
|
26524
27721
|
}
|
|
26525
|
-
const fullPath =
|
|
27722
|
+
const fullPath = path25.resolve(dir, path25.normalize(filePath));
|
|
26526
27723
|
if (!fullPath.startsWith(dir)) {
|
|
26527
27724
|
this.json(res, 403, { error: "Forbidden" });
|
|
26528
27725
|
return;
|
|
26529
27726
|
}
|
|
26530
27727
|
try {
|
|
26531
27728
|
if (fs15.existsSync(fullPath)) fs15.copyFileSync(fullPath, fullPath + ".bak");
|
|
26532
|
-
fs15.mkdirSync(
|
|
27729
|
+
fs15.mkdirSync(path25.dirname(fullPath), { recursive: true });
|
|
26533
27730
|
fs15.writeFileSync(fullPath, content, "utf-8");
|
|
26534
27731
|
this.log(`File saved: ${fullPath} (${content.length} chars)`);
|
|
26535
27732
|
this.providerLoader.reload();
|
|
@@ -26546,7 +27743,7 @@ var DevServer = class _DevServer {
|
|
|
26546
27743
|
return;
|
|
26547
27744
|
}
|
|
26548
27745
|
for (const name of ["scripts.js", "provider.json"]) {
|
|
26549
|
-
const p =
|
|
27746
|
+
const p = path25.join(dir, name);
|
|
26550
27747
|
if (fs15.existsSync(p)) {
|
|
26551
27748
|
const source = fs15.readFileSync(p, "utf-8");
|
|
26552
27749
|
this.json(res, 200, { type, path: p, source, lines: source.split("\n").length });
|
|
@@ -26567,8 +27764,8 @@ var DevServer = class _DevServer {
|
|
|
26567
27764
|
this.json(res, 404, { error: `Provider not found: ${type}` });
|
|
26568
27765
|
return;
|
|
26569
27766
|
}
|
|
26570
|
-
const target = fs15.existsSync(
|
|
26571
|
-
const targetPath =
|
|
27767
|
+
const target = fs15.existsSync(path25.join(dir, "scripts.js")) ? "scripts.js" : "provider.json";
|
|
27768
|
+
const targetPath = path25.join(dir, target);
|
|
26572
27769
|
try {
|
|
26573
27770
|
if (fs15.existsSync(targetPath)) fs15.copyFileSync(targetPath, targetPath + ".bak");
|
|
26574
27771
|
fs15.writeFileSync(targetPath, source, "utf-8");
|
|
@@ -26660,14 +27857,14 @@ var DevServer = class _DevServer {
|
|
|
26660
27857
|
child.stderr?.on("data", (d) => {
|
|
26661
27858
|
stderr += d.toString();
|
|
26662
27859
|
});
|
|
26663
|
-
await new Promise((
|
|
27860
|
+
await new Promise((resolve15) => {
|
|
26664
27861
|
const timer = setTimeout(() => {
|
|
26665
27862
|
child.kill();
|
|
26666
|
-
|
|
27863
|
+
resolve15();
|
|
26667
27864
|
}, timeout);
|
|
26668
27865
|
child.on("exit", () => {
|
|
26669
27866
|
clearTimeout(timer);
|
|
26670
|
-
|
|
27867
|
+
resolve15();
|
|
26671
27868
|
});
|
|
26672
27869
|
});
|
|
26673
27870
|
const elapsed = Date.now() - start;
|
|
@@ -26715,7 +27912,7 @@ var DevServer = class _DevServer {
|
|
|
26715
27912
|
}
|
|
26716
27913
|
let targetDir;
|
|
26717
27914
|
targetDir = this.providerLoader.getUserProviderDir(category, type);
|
|
26718
|
-
const jsonPath =
|
|
27915
|
+
const jsonPath = path25.join(targetDir, "provider.json");
|
|
26719
27916
|
if (fs15.existsSync(jsonPath)) {
|
|
26720
27917
|
this.json(res, 409, { error: `Provider already exists at ${targetDir}`, path: targetDir });
|
|
26721
27918
|
return;
|
|
@@ -26727,8 +27924,8 @@ var DevServer = class _DevServer {
|
|
|
26727
27924
|
const createdFiles = ["provider.json"];
|
|
26728
27925
|
if (result.files) {
|
|
26729
27926
|
for (const [relPath, content] of Object.entries(result.files)) {
|
|
26730
|
-
const fullPath =
|
|
26731
|
-
fs15.mkdirSync(
|
|
27927
|
+
const fullPath = path25.join(targetDir, relPath);
|
|
27928
|
+
fs15.mkdirSync(path25.dirname(fullPath), { recursive: true });
|
|
26732
27929
|
fs15.writeFileSync(fullPath, content, "utf-8");
|
|
26733
27930
|
createdFiles.push(relPath);
|
|
26734
27931
|
}
|
|
@@ -26781,22 +27978,22 @@ var DevServer = class _DevServer {
|
|
|
26781
27978
|
if (!fs15.existsSync(scriptsDir)) return null;
|
|
26782
27979
|
const versions = fs15.readdirSync(scriptsDir).filter((d) => {
|
|
26783
27980
|
try {
|
|
26784
|
-
return fs15.statSync(
|
|
27981
|
+
return fs15.statSync(path25.join(scriptsDir, d)).isDirectory();
|
|
26785
27982
|
} catch {
|
|
26786
27983
|
return false;
|
|
26787
27984
|
}
|
|
26788
27985
|
}).sort((a, b) => b.localeCompare(a, void 0, { numeric: true, sensitivity: "base" }));
|
|
26789
27986
|
if (versions.length === 0) return null;
|
|
26790
|
-
return
|
|
27987
|
+
return path25.join(scriptsDir, versions[0]);
|
|
26791
27988
|
}
|
|
26792
27989
|
resolveAutoImplWritableProviderDir(category, type, requestedDir) {
|
|
26793
|
-
const canonicalUserDir =
|
|
26794
|
-
const desiredDir = requestedDir ?
|
|
26795
|
-
const upstreamRoot =
|
|
26796
|
-
if (desiredDir === upstreamRoot || desiredDir.startsWith(`${upstreamRoot}${
|
|
27990
|
+
const canonicalUserDir = path25.resolve(this.providerLoader.getUserProviderDir(category, type));
|
|
27991
|
+
const desiredDir = requestedDir ? path25.resolve(requestedDir) : canonicalUserDir;
|
|
27992
|
+
const upstreamRoot = path25.resolve(this.providerLoader.getUpstreamDir());
|
|
27993
|
+
if (desiredDir === upstreamRoot || desiredDir.startsWith(`${upstreamRoot}${path25.sep}`)) {
|
|
26797
27994
|
return { dir: null, reason: `Refusing to write into upstream provider directory: ${desiredDir}` };
|
|
26798
27995
|
}
|
|
26799
|
-
if (
|
|
27996
|
+
if (path25.basename(desiredDir) !== type) {
|
|
26800
27997
|
return { dir: null, reason: `Requested writable provider directory must end with '${type}': ${desiredDir}` };
|
|
26801
27998
|
}
|
|
26802
27999
|
const sourceDir = this.findProviderDir(type);
|
|
@@ -26804,11 +28001,11 @@ var DevServer = class _DevServer {
|
|
|
26804
28001
|
return { dir: null, reason: `Provider source directory not found for '${type}'` };
|
|
26805
28002
|
}
|
|
26806
28003
|
if (!fs15.existsSync(desiredDir)) {
|
|
26807
|
-
fs15.mkdirSync(
|
|
28004
|
+
fs15.mkdirSync(path25.dirname(desiredDir), { recursive: true });
|
|
26808
28005
|
fs15.cpSync(sourceDir, desiredDir, { recursive: true });
|
|
26809
28006
|
this.log(`Auto-implement writable copy created: ${desiredDir}`);
|
|
26810
28007
|
}
|
|
26811
|
-
const providerJson =
|
|
28008
|
+
const providerJson = path25.join(desiredDir, "provider.json");
|
|
26812
28009
|
if (!fs15.existsSync(providerJson)) {
|
|
26813
28010
|
return { dir: null, reason: `provider.json not found in writable provider directory: ${desiredDir}` };
|
|
26814
28011
|
}
|
|
@@ -26844,7 +28041,7 @@ var DevServer = class _DevServer {
|
|
|
26844
28041
|
setMode: "set_mode.js"
|
|
26845
28042
|
};
|
|
26846
28043
|
const targetFileNames = new Set(functions.map((fn) => funcToFile[fn]).filter(Boolean));
|
|
26847
|
-
const scriptsDir =
|
|
28044
|
+
const scriptsDir = path25.join(providerDir, "scripts");
|
|
26848
28045
|
const latestScriptsDir = this.getLatestScriptVersionDir(scriptsDir);
|
|
26849
28046
|
if (latestScriptsDir) {
|
|
26850
28047
|
lines.push(`Scripts version directory: \`${latestScriptsDir}\``);
|
|
@@ -26855,7 +28052,7 @@ var DevServer = class _DevServer {
|
|
|
26855
28052
|
for (const file of fs15.readdirSync(latestScriptsDir)) {
|
|
26856
28053
|
if (file.endsWith(".js") && targetFileNames.has(file)) {
|
|
26857
28054
|
try {
|
|
26858
|
-
const content = fs15.readFileSync(
|
|
28055
|
+
const content = fs15.readFileSync(path25.join(latestScriptsDir, file), "utf-8");
|
|
26859
28056
|
lines.push(`### \`${file}\` \u270F\uFE0F EDIT`);
|
|
26860
28057
|
lines.push("```javascript");
|
|
26861
28058
|
lines.push(content);
|
|
@@ -26872,7 +28069,7 @@ var DevServer = class _DevServer {
|
|
|
26872
28069
|
lines.push("");
|
|
26873
28070
|
for (const file of refFiles) {
|
|
26874
28071
|
try {
|
|
26875
|
-
const content = fs15.readFileSync(
|
|
28072
|
+
const content = fs15.readFileSync(path25.join(latestScriptsDir, file), "utf-8");
|
|
26876
28073
|
lines.push(`### \`${file}\` \u{1F512}`);
|
|
26877
28074
|
lines.push("```javascript");
|
|
26878
28075
|
lines.push(content);
|
|
@@ -26913,10 +28110,10 @@ var DevServer = class _DevServer {
|
|
|
26913
28110
|
lines.push("");
|
|
26914
28111
|
}
|
|
26915
28112
|
}
|
|
26916
|
-
const docsDir =
|
|
28113
|
+
const docsDir = path25.join(providerDir, "../../docs");
|
|
26917
28114
|
const loadGuide = (name) => {
|
|
26918
28115
|
try {
|
|
26919
|
-
const p =
|
|
28116
|
+
const p = path25.join(docsDir, name);
|
|
26920
28117
|
if (fs15.existsSync(p)) return fs15.readFileSync(p, "utf-8");
|
|
26921
28118
|
} catch {
|
|
26922
28119
|
}
|
|
@@ -27090,7 +28287,7 @@ var DevServer = class _DevServer {
|
|
|
27090
28287
|
parseApproval: "parse_approval.js"
|
|
27091
28288
|
};
|
|
27092
28289
|
const targetFileNames = new Set(functions.map((fn) => funcToFile[fn]).filter(Boolean));
|
|
27093
|
-
const scriptsDir =
|
|
28290
|
+
const scriptsDir = path25.join(providerDir, "scripts");
|
|
27094
28291
|
const latestScriptsDir = this.getLatestScriptVersionDir(scriptsDir);
|
|
27095
28292
|
if (latestScriptsDir) {
|
|
27096
28293
|
lines.push(`Scripts version directory: \`${latestScriptsDir}\``);
|
|
@@ -27102,7 +28299,7 @@ var DevServer = class _DevServer {
|
|
|
27102
28299
|
if (!file.endsWith(".js")) continue;
|
|
27103
28300
|
if (!targetFileNames.has(file)) continue;
|
|
27104
28301
|
try {
|
|
27105
|
-
const content = fs15.readFileSync(
|
|
28302
|
+
const content = fs15.readFileSync(path25.join(latestScriptsDir, file), "utf-8");
|
|
27106
28303
|
lines.push(`### \`${file}\` \u270F\uFE0F EDIT`);
|
|
27107
28304
|
lines.push("```javascript");
|
|
27108
28305
|
lines.push(content);
|
|
@@ -27118,7 +28315,7 @@ var DevServer = class _DevServer {
|
|
|
27118
28315
|
lines.push("");
|
|
27119
28316
|
for (const file of refFiles) {
|
|
27120
28317
|
try {
|
|
27121
|
-
const content = fs15.readFileSync(
|
|
28318
|
+
const content = fs15.readFileSync(path25.join(latestScriptsDir, file), "utf-8");
|
|
27122
28319
|
lines.push(`### \`${file}\` \u{1F512}`);
|
|
27123
28320
|
lines.push("```javascript");
|
|
27124
28321
|
lines.push(content);
|
|
@@ -27151,10 +28348,10 @@ var DevServer = class _DevServer {
|
|
|
27151
28348
|
lines.push("");
|
|
27152
28349
|
}
|
|
27153
28350
|
}
|
|
27154
|
-
const docsDir =
|
|
28351
|
+
const docsDir = path25.join(providerDir, "../../docs");
|
|
27155
28352
|
const loadGuide = (name) => {
|
|
27156
28353
|
try {
|
|
27157
|
-
const p =
|
|
28354
|
+
const p = path25.join(docsDir, name);
|
|
27158
28355
|
if (fs15.existsSync(p)) return fs15.readFileSync(p, "utf-8");
|
|
27159
28356
|
} catch {
|
|
27160
28357
|
}
|
|
@@ -27337,14 +28534,14 @@ data: ${JSON.stringify(msg.data)}
|
|
|
27337
28534
|
res.end(JSON.stringify(data, null, 2));
|
|
27338
28535
|
}
|
|
27339
28536
|
async readBody(req) {
|
|
27340
|
-
return new Promise((
|
|
28537
|
+
return new Promise((resolve15) => {
|
|
27341
28538
|
let body = "";
|
|
27342
28539
|
req.on("data", (chunk) => body += chunk);
|
|
27343
28540
|
req.on("end", () => {
|
|
27344
28541
|
try {
|
|
27345
|
-
|
|
28542
|
+
resolve15(JSON.parse(body));
|
|
27346
28543
|
} catch {
|
|
27347
|
-
|
|
28544
|
+
resolve15({});
|
|
27348
28545
|
}
|
|
27349
28546
|
});
|
|
27350
28547
|
});
|
|
@@ -27854,7 +29051,7 @@ async function waitForReady(endpoint, timeoutMs = STARTUP_TIMEOUT_MS) {
|
|
|
27854
29051
|
const deadline = Date.now() + timeoutMs;
|
|
27855
29052
|
while (Date.now() < deadline) {
|
|
27856
29053
|
if (await canConnect(endpoint)) return;
|
|
27857
|
-
await new Promise((
|
|
29054
|
+
await new Promise((resolve15) => setTimeout(resolve15, STARTUP_POLL_MS));
|
|
27858
29055
|
}
|
|
27859
29056
|
throw new Error(`Session host did not become ready within ${timeoutMs}ms`);
|
|
27860
29057
|
}
|
|
@@ -28032,10 +29229,10 @@ async function installExtension(ide, extension) {
|
|
|
28032
29229
|
const buffer = Buffer.from(await res.arrayBuffer());
|
|
28033
29230
|
const fs16 = await import("fs");
|
|
28034
29231
|
fs16.writeFileSync(vsixPath, buffer);
|
|
28035
|
-
return new Promise((
|
|
29232
|
+
return new Promise((resolve15) => {
|
|
28036
29233
|
const cmd = `"${ide.cliCommand}" --install-extension "${vsixPath}" --force`;
|
|
28037
29234
|
(0, import_child_process11.exec)(cmd, { timeout: 6e4 }, (error, _stdout, stderr) => {
|
|
28038
|
-
|
|
29235
|
+
resolve15({
|
|
28039
29236
|
extensionId: extension.id,
|
|
28040
29237
|
marketplaceId: extension.marketplaceId,
|
|
28041
29238
|
success: !error,
|
|
@@ -28048,11 +29245,11 @@ async function installExtension(ide, extension) {
|
|
|
28048
29245
|
} catch (e) {
|
|
28049
29246
|
}
|
|
28050
29247
|
}
|
|
28051
|
-
return new Promise((
|
|
29248
|
+
return new Promise((resolve15) => {
|
|
28052
29249
|
const cmd = `"${ide.cliCommand}" --install-extension ${extension.marketplaceId} --force`;
|
|
28053
29250
|
(0, import_child_process11.exec)(cmd, { timeout: 6e4 }, (error, stdout, stderr) => {
|
|
28054
29251
|
if (error) {
|
|
28055
|
-
|
|
29252
|
+
resolve15({
|
|
28056
29253
|
extensionId: extension.id,
|
|
28057
29254
|
marketplaceId: extension.marketplaceId,
|
|
28058
29255
|
success: false,
|
|
@@ -28060,7 +29257,7 @@ async function installExtension(ide, extension) {
|
|
|
28060
29257
|
error: stderr || error.message
|
|
28061
29258
|
});
|
|
28062
29259
|
} else {
|
|
28063
|
-
|
|
29260
|
+
resolve15({
|
|
28064
29261
|
extensionId: extension.id,
|
|
28065
29262
|
marketplaceId: extension.marketplaceId,
|
|
28066
29263
|
success: true,
|
|
@@ -28390,6 +29587,7 @@ async function shutdownDaemonComponents(components) {
|
|
|
28390
29587
|
DEFAULT_CDP_SCAN_INTERVAL_MS,
|
|
28391
29588
|
DEFAULT_CHAT_TAIL_RECENT_MESSAGE_GRACE_MS,
|
|
28392
29589
|
DEFAULT_DAEMON_PORT,
|
|
29590
|
+
DEFAULT_GIT_WORKSPACE_POLL_INTERVAL_MS,
|
|
28393
29591
|
DEFAULT_MACHINE_RUNTIME_SUBSCRIPTION_INTERVAL_MS,
|
|
28394
29592
|
DEFAULT_SESSION_HOST_APP_NAME,
|
|
28395
29593
|
DEFAULT_SESSION_HOST_DIAGNOSTICS_SUBSCRIPTION_INTERVAL_MS,
|
|
@@ -28408,8 +29606,12 @@ async function shutdownDaemonComponents(components) {
|
|
|
28408
29606
|
DaemonCommandRouter,
|
|
28409
29607
|
DaemonStatusReporter,
|
|
28410
29608
|
DevServer,
|
|
29609
|
+
GitCommandError,
|
|
29610
|
+
GitWorkspaceMonitor,
|
|
28411
29611
|
IdeProviderInstance,
|
|
29612
|
+
InMemoryGitSnapshotStore,
|
|
28412
29613
|
LOG,
|
|
29614
|
+
MIN_GIT_WORKSPACE_POLL_INTERVAL_MS,
|
|
28413
29615
|
MIN_MACHINE_RUNTIME_SUBSCRIPTION_INTERVAL_MS,
|
|
28414
29616
|
MIN_SESSION_HOST_DIAGNOSTICS_SUBSCRIPTION_INTERVAL_MS,
|
|
28415
29617
|
NodePtyTransportFactory,
|
|
@@ -28437,9 +29639,14 @@ async function shutdownDaemonComponents(components) {
|
|
|
28437
29639
|
buildUserChatMessage,
|
|
28438
29640
|
classifyHotChatSessionsForSubscriptionFlush,
|
|
28439
29641
|
clearDebugTrace,
|
|
29642
|
+
compareGitSnapshots,
|
|
28440
29643
|
configureDebugTraceStore,
|
|
28441
29644
|
connectCdpManager,
|
|
28442
29645
|
createDebugTraceStore,
|
|
29646
|
+
createDefaultGitCommandServices,
|
|
29647
|
+
createGitCompactSummary,
|
|
29648
|
+
createGitSnapshotStore,
|
|
29649
|
+
createGitWorkspaceMonitor,
|
|
28443
29650
|
createInteractionId,
|
|
28444
29651
|
detectAllVersions,
|
|
28445
29652
|
detectCLIs,
|
|
@@ -28454,6 +29661,9 @@ async function shutdownDaemonComponents(components) {
|
|
|
28454
29661
|
getCurrentDaemonLogPath,
|
|
28455
29662
|
getDaemonLogDir,
|
|
28456
29663
|
getDebugRuntimeConfig,
|
|
29664
|
+
getGitDiffSummary,
|
|
29665
|
+
getGitFileDiff,
|
|
29666
|
+
getGitRepoStatus,
|
|
28457
29667
|
getHostMemorySnapshot,
|
|
28458
29668
|
getLogLevel,
|
|
28459
29669
|
getNpmExecOptions,
|
|
@@ -28465,6 +29675,7 @@ async function shutdownDaemonComponents(components) {
|
|
|
28465
29675
|
getSessionHostRecoveryLabel,
|
|
28466
29676
|
getSessionHostSurfaceKind,
|
|
28467
29677
|
getWorkspaceState,
|
|
29678
|
+
handleGitCommand,
|
|
28468
29679
|
hasCdpManager,
|
|
28469
29680
|
hashSignatureParts,
|
|
28470
29681
|
initDaemonComponents,
|
|
@@ -28473,9 +29684,11 @@ async function shutdownDaemonComponents(components) {
|
|
|
28473
29684
|
isBuiltinChatMessageKind,
|
|
28474
29685
|
isCdpConnected,
|
|
28475
29686
|
isExtensionInstalled,
|
|
29687
|
+
isGitCommandName,
|
|
28476
29688
|
isIdeRunning,
|
|
28477
29689
|
isManagedStatusWaiting,
|
|
28478
29690
|
isManagedStatusWorking,
|
|
29691
|
+
isPathInside,
|
|
28479
29692
|
isSessionHostLiveRuntime,
|
|
28480
29693
|
isSessionHostRecoverySnapshot,
|
|
28481
29694
|
isSetupComplete,
|
|
@@ -28493,10 +29706,13 @@ async function shutdownDaemonComponents(components) {
|
|
|
28493
29706
|
normalizeChatMessageKind,
|
|
28494
29707
|
normalizeChatMessages,
|
|
28495
29708
|
normalizeChatTailActiveModal,
|
|
29709
|
+
normalizeGitOutput,
|
|
29710
|
+
normalizeGitWorkspaceSubscriptionParams,
|
|
28496
29711
|
normalizeInputEnvelope,
|
|
28497
29712
|
normalizeManagedStatus,
|
|
28498
29713
|
normalizeMessageParts,
|
|
28499
29714
|
normalizeSessionModalFields,
|
|
29715
|
+
parsePorcelainV2Status,
|
|
28500
29716
|
parseProviderSourceConfigUpdate,
|
|
28501
29717
|
partitionSessionHostDiagnosticsSessions,
|
|
28502
29718
|
partitionSessionHostRecords,
|
|
@@ -28512,9 +29728,11 @@ async function shutdownDaemonComponents(components) {
|
|
|
28512
29728
|
resolveChatMessageKind,
|
|
28513
29729
|
resolveCurrentGlobalInstallSurface,
|
|
28514
29730
|
resolveDebugRuntimeConfig,
|
|
29731
|
+
resolveGitRepository,
|
|
28515
29732
|
resolveSessionHostAppName,
|
|
28516
29733
|
resolveSessionHostAppNameResolution,
|
|
28517
29734
|
runAsyncBatch,
|
|
29735
|
+
runGit,
|
|
28518
29736
|
saveConfig,
|
|
28519
29737
|
saveState,
|
|
28520
29738
|
setDebugRuntimeConfig,
|
|
@@ -28525,6 +29743,7 @@ async function shutdownDaemonComponents(components) {
|
|
|
28525
29743
|
shutdownDaemonComponents,
|
|
28526
29744
|
spawnDetachedDaemonUpgradeHelper,
|
|
28527
29745
|
startDaemonDevSupport,
|
|
29746
|
+
summarizeGitStatus,
|
|
28528
29747
|
updateConfig,
|
|
28529
29748
|
upsertSavedProviderSession
|
|
28530
29749
|
});
|