@adhdev/daemon-core 0.9.53 → 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 +1575 -385
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +1548 -382
- 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/handler.ts +9 -1
- 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
|
}
|
|
@@ -8166,13 +9307,13 @@ function pageHistoryRecords(agentType, records, offset = 0, limit = 30, excludeR
|
|
|
8166
9307
|
function readChatHistory(agentType, offset = 0, limit = 30, historySessionId, excludeRecentCount = 0, historyBehavior) {
|
|
8167
9308
|
try {
|
|
8168
9309
|
const sanitized = agentType.replace(/[^a-zA-Z0-9_-]/g, "_");
|
|
8169
|
-
const dir =
|
|
9310
|
+
const dir = path10.join(HISTORY_DIR, sanitized);
|
|
8170
9311
|
if (!fs3.existsSync(dir)) return { messages: [], hasMore: false };
|
|
8171
9312
|
const files = listHistoryFiles(dir, historySessionId);
|
|
8172
9313
|
const allMessages = [];
|
|
8173
9314
|
const seen = /* @__PURE__ */ new Set();
|
|
8174
9315
|
for (const file of files) {
|
|
8175
|
-
const filePath =
|
|
9316
|
+
const filePath = path10.join(dir, file);
|
|
8176
9317
|
const content = fs3.readFileSync(filePath, "utf-8");
|
|
8177
9318
|
const lines = content.trim().split("\n").filter(Boolean);
|
|
8178
9319
|
for (let i = 0; i < lines.length; i++) {
|
|
@@ -8196,7 +9337,7 @@ function readChatHistory(agentType, offset = 0, limit = 30, historySessionId, ex
|
|
|
8196
9337
|
function listSavedHistorySessions(agentType, options = {}, historyBehavior) {
|
|
8197
9338
|
try {
|
|
8198
9339
|
const sanitized = agentType.replace(/[^a-zA-Z0-9_-]/g, "_");
|
|
8199
|
-
const dir =
|
|
9340
|
+
const dir = path10.join(HISTORY_DIR, sanitized);
|
|
8200
9341
|
if (!fs3.existsSync(dir)) {
|
|
8201
9342
|
savedHistorySessionCache.delete(sanitized);
|
|
8202
9343
|
return { sessions: [], hasMore: false };
|
|
@@ -8257,11 +9398,11 @@ function listSavedHistorySessions(agentType, options = {}, historyBehavior) {
|
|
|
8257
9398
|
}
|
|
8258
9399
|
function readExistingSessionStartRecord(agentType, historySessionId) {
|
|
8259
9400
|
try {
|
|
8260
|
-
const dir =
|
|
9401
|
+
const dir = path10.join(HISTORY_DIR, agentType);
|
|
8261
9402
|
if (!fs3.existsSync(dir)) return null;
|
|
8262
9403
|
const files = listHistoryFiles(dir, historySessionId).sort();
|
|
8263
9404
|
for (const file of files) {
|
|
8264
|
-
const lines = fs3.readFileSync(
|
|
9405
|
+
const lines = fs3.readFileSync(path10.join(dir, file), "utf-8").split("\n").filter(Boolean);
|
|
8265
9406
|
for (const line of lines) {
|
|
8266
9407
|
try {
|
|
8267
9408
|
const parsed = JSON.parse(line);
|
|
@@ -8281,16 +9422,16 @@ function readExistingSessionStartRecord(agentType, historySessionId) {
|
|
|
8281
9422
|
function rewriteCanonicalSavedHistory(agentType, historySessionId, records) {
|
|
8282
9423
|
if (records.length === 0) return false;
|
|
8283
9424
|
try {
|
|
8284
|
-
const dir =
|
|
9425
|
+
const dir = path10.join(HISTORY_DIR, agentType);
|
|
8285
9426
|
fs3.mkdirSync(dir, { recursive: true });
|
|
8286
9427
|
const prefix = `${historySessionId.replace(/[^a-zA-Z0-9_-]/g, "_")}_`;
|
|
8287
9428
|
for (const file of fs3.readdirSync(dir)) {
|
|
8288
9429
|
if (file.startsWith(prefix) && file.endsWith(".jsonl")) {
|
|
8289
|
-
fs3.unlinkSync(
|
|
9430
|
+
fs3.unlinkSync(path10.join(dir, file));
|
|
8290
9431
|
}
|
|
8291
9432
|
}
|
|
8292
9433
|
const targetDate = new Date(records[records.length - 1].receivedAt || Date.now()).toISOString().slice(0, 10);
|
|
8293
|
-
const filePath =
|
|
9434
|
+
const filePath = path10.join(dir, `${prefix}${targetDate}.jsonl`);
|
|
8294
9435
|
fs3.writeFileSync(filePath, `${records.map((record) => JSON.stringify(record)).join("\n")}
|
|
8295
9436
|
`, "utf-8");
|
|
8296
9437
|
invalidatePersistedSavedHistoryIndex(agentType, dir);
|
|
@@ -10162,6 +11303,10 @@ function shouldIncludeSessionMetadata(profile) {
|
|
|
10162
11303
|
function shouldIncludeRuntimeMetadata(profile) {
|
|
10163
11304
|
return true;
|
|
10164
11305
|
}
|
|
11306
|
+
function getGitSummaryForWorkspace(workspace, options) {
|
|
11307
|
+
if (!workspace) return void 0;
|
|
11308
|
+
return options.getGitSummaryForWorkspace?.(workspace) || void 0;
|
|
11309
|
+
}
|
|
10165
11310
|
function findCdpManager(cdpManagers, key) {
|
|
10166
11311
|
const exact = cdpManagers.get(key);
|
|
10167
11312
|
if (exact) return exact.isConnected ? exact : null;
|
|
@@ -10217,6 +11362,8 @@ function buildIdeWorkspaceSession(state, cdpManagers, options) {
|
|
|
10217
11362
|
const controlValues = normalizeProviderStateControlValues(state.controlValues);
|
|
10218
11363
|
const includeSessionMetadata = shouldIncludeSessionMetadata(profile);
|
|
10219
11364
|
const includeSessionControls = shouldIncludeSessionControls(profile);
|
|
11365
|
+
const workspace = state.workspace || null;
|
|
11366
|
+
const git = getGitSummaryForWorkspace(workspace, options);
|
|
10220
11367
|
const title = activeChat?.title || state.name;
|
|
10221
11368
|
return {
|
|
10222
11369
|
id: state.instanceId || state.type,
|
|
@@ -10229,7 +11376,8 @@ function buildIdeWorkspaceSession(state, cdpManagers, options) {
|
|
|
10229
11376
|
activeModal: activeChat?.activeModal || null
|
|
10230
11377
|
}),
|
|
10231
11378
|
title,
|
|
10232
|
-
workspace
|
|
11379
|
+
workspace,
|
|
11380
|
+
...git && { git },
|
|
10233
11381
|
activeChat,
|
|
10234
11382
|
...summaryMetadata && { summaryMetadata },
|
|
10235
11383
|
...includeSessionMetadata && { capabilities: state.sessionCapabilities || IDE_SESSION_CAPABILITIES },
|
|
@@ -10250,6 +11398,8 @@ function buildExtensionAgentSession(parent, ext, options) {
|
|
|
10250
11398
|
const controlValues = normalizeProviderStateControlValues(ext.controlValues);
|
|
10251
11399
|
const includeSessionMetadata = shouldIncludeSessionMetadata(profile);
|
|
10252
11400
|
const includeSessionControls = shouldIncludeSessionControls(profile);
|
|
11401
|
+
const workspace = parent.workspace || null;
|
|
11402
|
+
const git = getGitSummaryForWorkspace(workspace, options);
|
|
10253
11403
|
return {
|
|
10254
11404
|
id: ext.instanceId || `${parent.instanceId}:${ext.type}`,
|
|
10255
11405
|
parentId: parent.instanceId || parent.type,
|
|
@@ -10262,7 +11412,8 @@ function buildExtensionAgentSession(parent, ext, options) {
|
|
|
10262
11412
|
activeModal: activeChat?.activeModal || null
|
|
10263
11413
|
}),
|
|
10264
11414
|
title: activeChat?.title || ext.name,
|
|
10265
|
-
workspace
|
|
11415
|
+
workspace,
|
|
11416
|
+
...git && { git },
|
|
10266
11417
|
activeChat,
|
|
10267
11418
|
...summaryMetadata && { summaryMetadata },
|
|
10268
11419
|
...includeSessionMetadata && { capabilities: ext.sessionCapabilities || EXTENSION_SESSION_CAPABILITIES },
|
|
@@ -10298,6 +11449,8 @@ function buildCliSession(state, options) {
|
|
|
10298
11449
|
const includeSessionMetadata = shouldIncludeSessionMetadata(profile);
|
|
10299
11450
|
const includeRuntimeMetadata = shouldIncludeRuntimeMetadata(profile);
|
|
10300
11451
|
const includeSessionControls = shouldIncludeSessionControls(profile);
|
|
11452
|
+
const workspace = state.workspace || null;
|
|
11453
|
+
const git = getGitSummaryForWorkspace(workspace, options);
|
|
10301
11454
|
return {
|
|
10302
11455
|
id: state.instanceId,
|
|
10303
11456
|
parentId: null,
|
|
@@ -10310,7 +11463,8 @@ function buildCliSession(state, options) {
|
|
|
10310
11463
|
activeModal: activeChat?.activeModal || null
|
|
10311
11464
|
}),
|
|
10312
11465
|
title: activeChat?.title || state.name,
|
|
10313
|
-
workspace
|
|
11466
|
+
workspace,
|
|
11467
|
+
...git && { git },
|
|
10314
11468
|
...includeRuntimeMetadata && {
|
|
10315
11469
|
runtimeKey: state.runtime?.runtimeKey,
|
|
10316
11470
|
runtimeDisplayName: state.runtime?.displayName,
|
|
@@ -10345,6 +11499,8 @@ function buildAcpSession(state, options) {
|
|
|
10345
11499
|
const controlValues = normalizeProviderStateControlValues(state.controlValues);
|
|
10346
11500
|
const includeSessionMetadata = shouldIncludeSessionMetadata(profile);
|
|
10347
11501
|
const includeSessionControls = shouldIncludeSessionControls(profile);
|
|
11502
|
+
const workspace = state.workspace || null;
|
|
11503
|
+
const git = getGitSummaryForWorkspace(workspace, options);
|
|
10348
11504
|
return {
|
|
10349
11505
|
id: state.instanceId,
|
|
10350
11506
|
parentId: null,
|
|
@@ -10356,7 +11512,8 @@ function buildAcpSession(state, options) {
|
|
|
10356
11512
|
activeModal: activeChat?.activeModal || null
|
|
10357
11513
|
}),
|
|
10358
11514
|
title: activeChat?.title || state.name,
|
|
10359
|
-
workspace
|
|
11515
|
+
workspace,
|
|
11516
|
+
...git && { git },
|
|
10360
11517
|
activeChat,
|
|
10361
11518
|
...summaryMetadata && { summaryMetadata },
|
|
10362
11519
|
...includeSessionMetadata && { capabilities: ACP_SESSION_CAPABILITIES },
|
|
@@ -10475,7 +11632,7 @@ function resolveLegacyProviderScript(fn, scriptName, params) {
|
|
|
10475
11632
|
// src/commands/chat-commands.ts
|
|
10476
11633
|
var fs4 = __toESM(require("fs"));
|
|
10477
11634
|
var os6 = __toESM(require("os"));
|
|
10478
|
-
var
|
|
11635
|
+
var path11 = __toESM(require("path"));
|
|
10479
11636
|
var import_node_crypto = require("crypto");
|
|
10480
11637
|
init_contracts();
|
|
10481
11638
|
|
|
@@ -11168,7 +12325,7 @@ function buildDebugBundleText(bundle) {
|
|
|
11168
12325
|
}
|
|
11169
12326
|
function getChatDebugBundleDir() {
|
|
11170
12327
|
const override = typeof process.env.ADHDEV_DEBUG_BUNDLE_DIR === "string" ? process.env.ADHDEV_DEBUG_BUNDLE_DIR.trim() : "";
|
|
11171
|
-
return override ||
|
|
12328
|
+
return override || path11.join(os6.homedir(), ".adhdev", "debug-bundles", "chat");
|
|
11172
12329
|
}
|
|
11173
12330
|
function safeBundleIdSegment(value, fallback) {
|
|
11174
12331
|
const normalized = String(value || fallback).trim().replace(/[^A-Za-z0-9_.-]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 80);
|
|
@@ -11201,7 +12358,7 @@ function storeChatDebugBundleOnDaemon(bundle, targetSessionId) {
|
|
|
11201
12358
|
const bundleId = createChatDebugBundleId(targetSessionId);
|
|
11202
12359
|
const dir = getChatDebugBundleDir();
|
|
11203
12360
|
fs4.mkdirSync(dir, { recursive: true });
|
|
11204
|
-
const savedPath =
|
|
12361
|
+
const savedPath = path11.join(dir, `${bundleId}.json`);
|
|
11205
12362
|
const json = `${JSON.stringify(bundle, null, 2)}
|
|
11206
12363
|
`;
|
|
11207
12364
|
fs4.writeFileSync(savedPath, json, { encoding: "utf8", mode: 384 });
|
|
@@ -11395,7 +12552,7 @@ function getCliVisibleTranscriptCount(adapter) {
|
|
|
11395
12552
|
async function getStableExtensionBaseline(h) {
|
|
11396
12553
|
const first = await readExtensionChatState(h);
|
|
11397
12554
|
if (getStateMessageCount(first) > 0 || getStateLastSignature(first)) return first;
|
|
11398
|
-
await new Promise((
|
|
12555
|
+
await new Promise((resolve15) => setTimeout(resolve15, 150));
|
|
11399
12556
|
const second = await readExtensionChatState(h);
|
|
11400
12557
|
return getStateMessageCount(second) >= getStateMessageCount(first) ? second : first;
|
|
11401
12558
|
}
|
|
@@ -11403,7 +12560,7 @@ async function verifyExtensionSendObserved(h, before) {
|
|
|
11403
12560
|
const beforeCount = getStateMessageCount(before);
|
|
11404
12561
|
const beforeSignature = getStateLastSignature(before);
|
|
11405
12562
|
for (let attempt = 0; attempt < 12; attempt += 1) {
|
|
11406
|
-
await new Promise((
|
|
12563
|
+
await new Promise((resolve15) => setTimeout(resolve15, 250));
|
|
11407
12564
|
const state = await readExtensionChatState(h);
|
|
11408
12565
|
if (state?.status === "waiting_approval") return true;
|
|
11409
12566
|
const afterCount = getStateMessageCount(state);
|
|
@@ -12339,7 +13496,7 @@ async function handleResolveAction(h, args) {
|
|
|
12339
13496
|
|
|
12340
13497
|
// src/commands/cdp-commands.ts
|
|
12341
13498
|
var fs5 = __toESM(require("fs"));
|
|
12342
|
-
var
|
|
13499
|
+
var path12 = __toESM(require("path"));
|
|
12343
13500
|
var os7 = __toESM(require("os"));
|
|
12344
13501
|
var KEY_TO_VK = {
|
|
12345
13502
|
Backspace: 8,
|
|
@@ -12596,25 +13753,25 @@ function resolveSafePath(requestedPath) {
|
|
|
12596
13753
|
const inputPath = rawPath || ".";
|
|
12597
13754
|
const home = os7.homedir();
|
|
12598
13755
|
if (inputPath.startsWith("~")) {
|
|
12599
|
-
return
|
|
13756
|
+
return path12.resolve(path12.join(home, inputPath.slice(1)));
|
|
12600
13757
|
}
|
|
12601
13758
|
if (process.platform === "win32") {
|
|
12602
13759
|
const normalized = normalizeWindowsRequestedPath(inputPath);
|
|
12603
|
-
if (
|
|
12604
|
-
return
|
|
13760
|
+
if (path12.win32.isAbsolute(normalized)) {
|
|
13761
|
+
return path12.win32.normalize(normalized);
|
|
12605
13762
|
}
|
|
12606
|
-
return
|
|
13763
|
+
return path12.win32.resolve(normalized);
|
|
12607
13764
|
}
|
|
12608
|
-
if (
|
|
12609
|
-
return
|
|
13765
|
+
if (path12.isAbsolute(inputPath)) {
|
|
13766
|
+
return path12.normalize(inputPath);
|
|
12610
13767
|
}
|
|
12611
|
-
return
|
|
13768
|
+
return path12.resolve(inputPath);
|
|
12612
13769
|
}
|
|
12613
13770
|
function listDirectoryEntriesSafe(dirPath) {
|
|
12614
13771
|
const entries = fs5.readdirSync(dirPath, { withFileTypes: true });
|
|
12615
13772
|
const files = [];
|
|
12616
13773
|
for (const entry of entries) {
|
|
12617
|
-
const entryPath =
|
|
13774
|
+
const entryPath = path12.join(dirPath, entry.name);
|
|
12618
13775
|
try {
|
|
12619
13776
|
if (entry.isDirectory()) {
|
|
12620
13777
|
files.push({ name: entry.name, type: "directory" });
|
|
@@ -12630,11 +13787,11 @@ function listDirectoryEntriesSafe(dirPath) {
|
|
|
12630
13787
|
files.push({ name: entry.name, type: "file", size });
|
|
12631
13788
|
continue;
|
|
12632
13789
|
}
|
|
12633
|
-
const
|
|
13790
|
+
const stat2 = fs5.statSync(entryPath);
|
|
12634
13791
|
files.push({
|
|
12635
13792
|
name: entry.name,
|
|
12636
|
-
type:
|
|
12637
|
-
size:
|
|
13793
|
+
type: stat2.isDirectory() ? "directory" : "file",
|
|
13794
|
+
size: stat2.isFile() ? stat2.size : void 0
|
|
12638
13795
|
});
|
|
12639
13796
|
} catch {
|
|
12640
13797
|
}
|
|
@@ -12668,7 +13825,7 @@ async function handleFileRead(h, args) {
|
|
|
12668
13825
|
async function handleFileWrite(h, args) {
|
|
12669
13826
|
try {
|
|
12670
13827
|
const filePath = resolveSafePath(args?.path);
|
|
12671
|
-
fs5.mkdirSync(
|
|
13828
|
+
fs5.mkdirSync(path12.dirname(filePath), { recursive: true });
|
|
12672
13829
|
fs5.writeFileSync(filePath, args?.content || "", "utf-8");
|
|
12673
13830
|
return { success: true, path: filePath };
|
|
12674
13831
|
} catch (e) {
|
|
@@ -13017,7 +14174,7 @@ async function executeProviderScript(h, args, scriptName) {
|
|
|
13017
14174
|
const enterCount = cliCommand.enterCount || 1;
|
|
13018
14175
|
await adapter.writeRaw(cliCommand.text + "\r");
|
|
13019
14176
|
for (let i = 1; i < enterCount; i += 1) {
|
|
13020
|
-
await new Promise((
|
|
14177
|
+
await new Promise((resolve15) => setTimeout(resolve15, 50));
|
|
13021
14178
|
await adapter.writeRaw("\r");
|
|
13022
14179
|
}
|
|
13023
14180
|
}
|
|
@@ -13511,6 +14668,12 @@ var DaemonCommandHandler = class {
|
|
|
13511
14668
|
this._currentRoute = this.resolveRoute(args);
|
|
13512
14669
|
const startedAt = Date.now();
|
|
13513
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
|
+
}
|
|
13514
14677
|
const sessionScopedCommands = /* @__PURE__ */ new Set([
|
|
13515
14678
|
"read_chat",
|
|
13516
14679
|
"get_chat_debug_bundle",
|
|
@@ -13536,7 +14699,6 @@ var DaemonCommandHandler = class {
|
|
|
13536
14699
|
this.logCommandEnd(cmd, result2, startedAt);
|
|
13537
14700
|
return result2;
|
|
13538
14701
|
}
|
|
13539
|
-
let result;
|
|
13540
14702
|
if (!this._currentRoute.session && !this._currentRoute.managerKey && !this._currentRoute.providerType) {
|
|
13541
14703
|
const cdpCommands = ["send_chat", "read_chat", "list_chats", "new_chat", "switch_chat", "set_mode", "change_model", "set_thought_level", "resolve_action"];
|
|
13542
14704
|
if (cdpCommands.includes(cmd)) {
|
|
@@ -13687,7 +14849,7 @@ var DaemonCommandHandler = class {
|
|
|
13687
14849
|
try {
|
|
13688
14850
|
const http3 = await import("http");
|
|
13689
14851
|
const postData = JSON.stringify(body);
|
|
13690
|
-
const result = await new Promise((
|
|
14852
|
+
const result = await new Promise((resolve15, reject) => {
|
|
13691
14853
|
const req = http3.request({
|
|
13692
14854
|
hostname: "127.0.0.1",
|
|
13693
14855
|
port: 19280,
|
|
@@ -13699,9 +14861,9 @@ var DaemonCommandHandler = class {
|
|
|
13699
14861
|
res.on("data", (chunk) => data += chunk);
|
|
13700
14862
|
res.on("end", () => {
|
|
13701
14863
|
try {
|
|
13702
|
-
|
|
14864
|
+
resolve15(JSON.parse(data));
|
|
13703
14865
|
} catch {
|
|
13704
|
-
|
|
14866
|
+
resolve15({ raw: data });
|
|
13705
14867
|
}
|
|
13706
14868
|
});
|
|
13707
14869
|
});
|
|
@@ -13719,15 +14881,15 @@ var DaemonCommandHandler = class {
|
|
|
13719
14881
|
if (!providerType) return { success: false, error: "providerType required" };
|
|
13720
14882
|
try {
|
|
13721
14883
|
const http3 = await import("http");
|
|
13722
|
-
const result = await new Promise((
|
|
14884
|
+
const result = await new Promise((resolve15, reject) => {
|
|
13723
14885
|
http3.get(`http://127.0.0.1:19280/api/providers/${providerType}/${endpoint}`, (res) => {
|
|
13724
14886
|
let data = "";
|
|
13725
14887
|
res.on("data", (chunk) => data += chunk);
|
|
13726
14888
|
res.on("end", () => {
|
|
13727
14889
|
try {
|
|
13728
|
-
|
|
14890
|
+
resolve15(JSON.parse(data));
|
|
13729
14891
|
} catch {
|
|
13730
|
-
|
|
14892
|
+
resolve15({ raw: data });
|
|
13731
14893
|
}
|
|
13732
14894
|
});
|
|
13733
14895
|
}).on("error", reject);
|
|
@@ -13741,7 +14903,7 @@ var DaemonCommandHandler = class {
|
|
|
13741
14903
|
try {
|
|
13742
14904
|
const http3 = await import("http");
|
|
13743
14905
|
const postData = JSON.stringify(args || {});
|
|
13744
|
-
const result = await new Promise((
|
|
14906
|
+
const result = await new Promise((resolve15, reject) => {
|
|
13745
14907
|
const req = http3.request({
|
|
13746
14908
|
hostname: "127.0.0.1",
|
|
13747
14909
|
port: 19280,
|
|
@@ -13753,9 +14915,9 @@ var DaemonCommandHandler = class {
|
|
|
13753
14915
|
res.on("data", (chunk) => data += chunk);
|
|
13754
14916
|
res.on("end", () => {
|
|
13755
14917
|
try {
|
|
13756
|
-
|
|
14918
|
+
resolve15(JSON.parse(data));
|
|
13757
14919
|
} catch {
|
|
13758
|
-
|
|
14920
|
+
resolve15({ raw: data });
|
|
13759
14921
|
}
|
|
13760
14922
|
});
|
|
13761
14923
|
});
|
|
@@ -13772,7 +14934,7 @@ var DaemonCommandHandler = class {
|
|
|
13772
14934
|
|
|
13773
14935
|
// src/commands/cli-manager.ts
|
|
13774
14936
|
var os13 = __toESM(require("os"));
|
|
13775
|
-
var
|
|
14937
|
+
var path16 = __toESM(require("path"));
|
|
13776
14938
|
var crypto4 = __toESM(require("crypto"));
|
|
13777
14939
|
var import_fs5 = require("fs");
|
|
13778
14940
|
var import_child_process6 = require("child_process");
|
|
@@ -13782,7 +14944,7 @@ init_config();
|
|
|
13782
14944
|
|
|
13783
14945
|
// src/providers/cli-provider-instance.ts
|
|
13784
14946
|
var os12 = __toESM(require("os"));
|
|
13785
|
-
var
|
|
14947
|
+
var path15 = __toESM(require("path"));
|
|
13786
14948
|
var crypto3 = __toESM(require("crypto"));
|
|
13787
14949
|
var fs6 = __toESM(require("fs"));
|
|
13788
14950
|
var import_node_module = require("module");
|
|
@@ -13843,7 +15005,7 @@ function buildIncrementalHistoryAppendMessages(previousMessages, currentMessages
|
|
|
13843
15005
|
var CachedDatabaseSync = null;
|
|
13844
15006
|
function getDatabaseSync() {
|
|
13845
15007
|
if (CachedDatabaseSync) return CachedDatabaseSync;
|
|
13846
|
-
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"));
|
|
13847
15009
|
const sqliteModule = requireFn(`node:${"sqlite"}`);
|
|
13848
15010
|
CachedDatabaseSync = sqliteModule.DatabaseSync;
|
|
13849
15011
|
if (!CachedDatabaseSync) {
|
|
@@ -13881,7 +15043,7 @@ async function waitForCliAdapterReady(adapter, options) {
|
|
|
13881
15043
|
if (status === "stopped") {
|
|
13882
15044
|
throw new Error("CLI runtime stopped before it became ready");
|
|
13883
15045
|
}
|
|
13884
|
-
await new Promise((
|
|
15046
|
+
await new Promise((resolve15) => setTimeout(resolve15, pollMs));
|
|
13885
15047
|
}
|
|
13886
15048
|
throw new Error(`CLI runtime did not become ready within ${timeoutMs}ms`);
|
|
13887
15049
|
}
|
|
@@ -14232,7 +15394,7 @@ var CliProviderInstance = class {
|
|
|
14232
15394
|
const enterCount = cliCommand.enterCount || 1;
|
|
14233
15395
|
await this.adapter.writeRaw(cliCommand.text + "\r");
|
|
14234
15396
|
for (let i = 1; i < enterCount; i += 1) {
|
|
14235
|
-
await new Promise((
|
|
15397
|
+
await new Promise((resolve15) => setTimeout(resolve15, 50));
|
|
14236
15398
|
await this.adapter.writeRaw("\r");
|
|
14237
15399
|
}
|
|
14238
15400
|
}
|
|
@@ -15346,13 +16508,13 @@ var AcpProviderInstance = class {
|
|
|
15346
16508
|
}
|
|
15347
16509
|
this.currentStatus = "waiting_approval";
|
|
15348
16510
|
this.detectStatusTransition();
|
|
15349
|
-
const approved = await new Promise((
|
|
15350
|
-
this.permissionResolvers.push(
|
|
16511
|
+
const approved = await new Promise((resolve15) => {
|
|
16512
|
+
this.permissionResolvers.push(resolve15);
|
|
15351
16513
|
setTimeout(() => {
|
|
15352
|
-
const idx = this.permissionResolvers.indexOf(
|
|
16514
|
+
const idx = this.permissionResolvers.indexOf(resolve15);
|
|
15353
16515
|
if (idx >= 0) {
|
|
15354
16516
|
this.permissionResolvers.splice(idx, 1);
|
|
15355
|
-
|
|
16517
|
+
resolve15(false);
|
|
15356
16518
|
}
|
|
15357
16519
|
}, 3e5);
|
|
15358
16520
|
});
|
|
@@ -15927,11 +17089,11 @@ function shouldRestoreHostedRuntime(record, managerTag) {
|
|
|
15927
17089
|
// src/commands/cli-manager.ts
|
|
15928
17090
|
function isExplicitCommand(command) {
|
|
15929
17091
|
const trimmed = command.trim();
|
|
15930
|
-
return
|
|
17092
|
+
return path16.isAbsolute(trimmed) || trimmed.includes("/") || trimmed.includes("\\") || trimmed.startsWith("~");
|
|
15931
17093
|
}
|
|
15932
17094
|
function expandExecutable(command) {
|
|
15933
17095
|
const trimmed = command.trim();
|
|
15934
|
-
return trimmed.startsWith("~") ?
|
|
17096
|
+
return trimmed.startsWith("~") ? path16.join(os13.homedir(), trimmed.slice(1)) : trimmed;
|
|
15935
17097
|
}
|
|
15936
17098
|
function commandExists(command) {
|
|
15937
17099
|
const trimmed = command.trim();
|
|
@@ -16212,7 +17374,7 @@ var DaemonCliManager = class {
|
|
|
16212
17374
|
async startSession(cliType, workingDir, cliArgs, initialModel, options) {
|
|
16213
17375
|
const trimmed = (workingDir || "").trim();
|
|
16214
17376
|
if (!trimmed) throw new Error("working directory required");
|
|
16215
|
-
const resolvedDir = trimmed.startsWith("~") ? trimmed.replace(/^~/, os13.homedir()) :
|
|
17377
|
+
const resolvedDir = trimmed.startsWith("~") ? trimmed.replace(/^~/, os13.homedir()) : path16.resolve(trimmed);
|
|
16216
17378
|
const normalizedType = this.providerLoader.resolveAlias(cliType);
|
|
16217
17379
|
const rawProvider = this.providerLoader.getByAlias(cliType);
|
|
16218
17380
|
const provider = rawProvider ? this.providerLoader.resolve(normalizedType) || rawProvider : void 0;
|
|
@@ -16713,11 +17875,11 @@ Run 'adhdev doctor' for detailed diagnostics.`
|
|
|
16713
17875
|
var import_child_process7 = require("child_process");
|
|
16714
17876
|
var net = __toESM(require("net"));
|
|
16715
17877
|
var os15 = __toESM(require("os"));
|
|
16716
|
-
var
|
|
17878
|
+
var path18 = __toESM(require("path"));
|
|
16717
17879
|
|
|
16718
17880
|
// src/providers/provider-loader.ts
|
|
16719
17881
|
var fs7 = __toESM(require("fs"));
|
|
16720
|
-
var
|
|
17882
|
+
var path17 = __toESM(require("path"));
|
|
16721
17883
|
var os14 = __toESM(require("os"));
|
|
16722
17884
|
var chokidar = __toESM(require("chokidar"));
|
|
16723
17885
|
init_logger();
|
|
@@ -16982,7 +18144,7 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
16982
18144
|
try {
|
|
16983
18145
|
if (!fs7.existsSync(candidate) || !fs7.statSync(candidate).isDirectory()) return false;
|
|
16984
18146
|
return ["ide", "extension", "cli", "acp"].some(
|
|
16985
|
-
(category) => fs7.existsSync(
|
|
18147
|
+
(category) => fs7.existsSync(path17.join(candidate, category))
|
|
16986
18148
|
);
|
|
16987
18149
|
} catch {
|
|
16988
18150
|
return false;
|
|
@@ -16990,20 +18152,20 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
16990
18152
|
}
|
|
16991
18153
|
static hasProviderRootMarker(candidate) {
|
|
16992
18154
|
try {
|
|
16993
|
-
return fs7.existsSync(
|
|
18155
|
+
return fs7.existsSync(path17.join(candidate, _ProviderLoader.SIBLING_MARKER_FILE));
|
|
16994
18156
|
} catch {
|
|
16995
18157
|
return false;
|
|
16996
18158
|
}
|
|
16997
18159
|
}
|
|
16998
18160
|
detectDefaultUserDir() {
|
|
16999
|
-
const fallback =
|
|
18161
|
+
const fallback = path17.join(os14.homedir(), ".adhdev", "providers");
|
|
17000
18162
|
const envOptIn = process.env[_ProviderLoader.SIBLING_ENV_VAR] === "1";
|
|
17001
18163
|
const visited = /* @__PURE__ */ new Set();
|
|
17002
18164
|
for (const start of this.probeStarts) {
|
|
17003
|
-
let current =
|
|
18165
|
+
let current = path17.resolve(start);
|
|
17004
18166
|
while (!visited.has(current)) {
|
|
17005
18167
|
visited.add(current);
|
|
17006
|
-
const siblingCandidate =
|
|
18168
|
+
const siblingCandidate = path17.join(path17.dirname(current), _ProviderLoader.REPO_PROVIDER_DIRNAME);
|
|
17007
18169
|
if (_ProviderLoader.looksLikeProviderRoot(siblingCandidate)) {
|
|
17008
18170
|
const hasMarker = _ProviderLoader.hasProviderRootMarker(siblingCandidate);
|
|
17009
18171
|
if (envOptIn || hasMarker) {
|
|
@@ -17025,7 +18187,7 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
17025
18187
|
return { path: siblingCandidate, source };
|
|
17026
18188
|
}
|
|
17027
18189
|
}
|
|
17028
|
-
const parent =
|
|
18190
|
+
const parent = path17.dirname(current);
|
|
17029
18191
|
if (parent === current) break;
|
|
17030
18192
|
current = parent;
|
|
17031
18193
|
}
|
|
@@ -17035,11 +18197,11 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
17035
18197
|
constructor(options) {
|
|
17036
18198
|
this.logFn = options?.logFn || LOG.forComponent("Provider").asLogFn();
|
|
17037
18199
|
this.probeStarts = options?.probeStarts ?? [process.cwd(), __dirname];
|
|
17038
|
-
this.defaultProvidersDir =
|
|
18200
|
+
this.defaultProvidersDir = path17.join(os14.homedir(), ".adhdev", "providers");
|
|
17039
18201
|
const detected = this.detectDefaultUserDir();
|
|
17040
18202
|
this.userDir = detected.path;
|
|
17041
18203
|
this.userDirSource = detected.source;
|
|
17042
|
-
this.upstreamDir =
|
|
18204
|
+
this.upstreamDir = path17.join(this.defaultProvidersDir, ".upstream");
|
|
17043
18205
|
this.disableUpstream = false;
|
|
17044
18206
|
this.applySourceConfig({
|
|
17045
18207
|
userDir: options?.userDir,
|
|
@@ -17098,7 +18260,7 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
17098
18260
|
this.userDir = detected.path;
|
|
17099
18261
|
this.userDirSource = detected.source;
|
|
17100
18262
|
}
|
|
17101
|
-
this.upstreamDir =
|
|
18263
|
+
this.upstreamDir = path17.join(this.defaultProvidersDir, ".upstream");
|
|
17102
18264
|
this.disableUpstream = this.sourceMode === "no-upstream";
|
|
17103
18265
|
if (this.explicitProviderDir) {
|
|
17104
18266
|
this.log(`Config 'providerDir' applied: ${this.userDir}`);
|
|
@@ -17112,7 +18274,7 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
17112
18274
|
* Canonical provider directory shape for a given root.
|
|
17113
18275
|
*/
|
|
17114
18276
|
getProviderDir(root, category, type) {
|
|
17115
|
-
return
|
|
18277
|
+
return path17.join(root, category, type);
|
|
17116
18278
|
}
|
|
17117
18279
|
/**
|
|
17118
18280
|
* Canonical user override directory for a provider.
|
|
@@ -17139,7 +18301,7 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
17139
18301
|
resolveProviderFile(type, ...segments) {
|
|
17140
18302
|
const dir = this.findProviderDirInternal(type);
|
|
17141
18303
|
if (!dir) return null;
|
|
17142
|
-
return
|
|
18304
|
+
return path17.join(dir, ...segments);
|
|
17143
18305
|
}
|
|
17144
18306
|
/**
|
|
17145
18307
|
* Load all providers (3-tier priority)
|
|
@@ -17178,7 +18340,7 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
17178
18340
|
if (!fs7.existsSync(this.upstreamDir)) return false;
|
|
17179
18341
|
try {
|
|
17180
18342
|
return fs7.readdirSync(this.upstreamDir).some(
|
|
17181
|
-
(d) => fs7.statSync(
|
|
18343
|
+
(d) => fs7.statSync(path17.join(this.upstreamDir, d)).isDirectory()
|
|
17182
18344
|
);
|
|
17183
18345
|
} catch {
|
|
17184
18346
|
return false;
|
|
@@ -17675,8 +18837,8 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
17675
18837
|
resolved._resolvedScriptDir = entry.scriptDir;
|
|
17676
18838
|
resolved._resolvedScriptsSource = `compatibility:${entry.ideVersion}`;
|
|
17677
18839
|
if (providerDir) {
|
|
17678
|
-
const fullDir =
|
|
17679
|
-
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;
|
|
17680
18842
|
}
|
|
17681
18843
|
matched = true;
|
|
17682
18844
|
}
|
|
@@ -17691,8 +18853,8 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
17691
18853
|
resolved._resolvedScriptDir = base.defaultScriptDir;
|
|
17692
18854
|
resolved._resolvedScriptsSource = "defaultScriptDir:version_miss";
|
|
17693
18855
|
if (providerDir) {
|
|
17694
|
-
const fullDir =
|
|
17695
|
-
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;
|
|
17696
18858
|
}
|
|
17697
18859
|
}
|
|
17698
18860
|
resolved._versionWarning = `Version ${currentVersion} not in compatibility matrix. Using default scripts.`;
|
|
@@ -17709,8 +18871,8 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
17709
18871
|
resolved._resolvedScriptDir = dirOverride;
|
|
17710
18872
|
resolved._resolvedScriptsSource = `versions:${range}`;
|
|
17711
18873
|
if (providerDir) {
|
|
17712
|
-
const fullDir =
|
|
17713
|
-
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;
|
|
17714
18876
|
}
|
|
17715
18877
|
}
|
|
17716
18878
|
} else if (override.scripts) {
|
|
@@ -17726,8 +18888,8 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
17726
18888
|
resolved._resolvedScriptDir = base.defaultScriptDir;
|
|
17727
18889
|
resolved._resolvedScriptsSource = "defaultScriptDir:no_version";
|
|
17728
18890
|
if (providerDir) {
|
|
17729
|
-
const fullDir =
|
|
17730
|
-
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;
|
|
17731
18893
|
}
|
|
17732
18894
|
}
|
|
17733
18895
|
}
|
|
@@ -17759,14 +18921,14 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
17759
18921
|
this.log(` [loadScriptsFromDir] ${type}: providerDir not found`);
|
|
17760
18922
|
return null;
|
|
17761
18923
|
}
|
|
17762
|
-
const dir =
|
|
18924
|
+
const dir = path17.join(providerDir, scriptDir);
|
|
17763
18925
|
if (!fs7.existsSync(dir)) {
|
|
17764
18926
|
this.log(` [loadScriptsFromDir] ${type}: dir not found: ${dir}`);
|
|
17765
18927
|
return null;
|
|
17766
18928
|
}
|
|
17767
18929
|
const cached = this.scriptsCache.get(dir);
|
|
17768
18930
|
if (cached) return cached;
|
|
17769
|
-
const scriptsJs =
|
|
18931
|
+
const scriptsJs = path17.join(dir, "scripts.js");
|
|
17770
18932
|
if (fs7.existsSync(scriptsJs)) {
|
|
17771
18933
|
try {
|
|
17772
18934
|
delete require.cache[require.resolve(scriptsJs)];
|
|
@@ -17808,7 +18970,7 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
17808
18970
|
return;
|
|
17809
18971
|
}
|
|
17810
18972
|
if (filePath.endsWith(".js") || filePath.endsWith(".json")) {
|
|
17811
|
-
this.log(`File changed: ${
|
|
18973
|
+
this.log(`File changed: ${path17.basename(filePath)}, reloading...`);
|
|
17812
18974
|
this.reload();
|
|
17813
18975
|
}
|
|
17814
18976
|
};
|
|
@@ -17863,7 +19025,7 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
17863
19025
|
}
|
|
17864
19026
|
const https = require("https");
|
|
17865
19027
|
const { execSync: execSync7 } = require("child_process");
|
|
17866
|
-
const metaPath =
|
|
19028
|
+
const metaPath = path17.join(this.upstreamDir, _ProviderLoader.META_FILE);
|
|
17867
19029
|
let prevEtag = "";
|
|
17868
19030
|
let prevTimestamp = 0;
|
|
17869
19031
|
try {
|
|
@@ -17880,7 +19042,7 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
17880
19042
|
return { updated: false };
|
|
17881
19043
|
}
|
|
17882
19044
|
try {
|
|
17883
|
-
const etag = await new Promise((
|
|
19045
|
+
const etag = await new Promise((resolve15, reject) => {
|
|
17884
19046
|
const options = {
|
|
17885
19047
|
method: "HEAD",
|
|
17886
19048
|
hostname: "github.com",
|
|
@@ -17898,7 +19060,7 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
17898
19060
|
headers: { "User-Agent": "adhdev-launcher" },
|
|
17899
19061
|
timeout: 1e4
|
|
17900
19062
|
}, (res2) => {
|
|
17901
|
-
|
|
19063
|
+
resolve15(res2.headers.etag || res2.headers["last-modified"] || "");
|
|
17902
19064
|
});
|
|
17903
19065
|
req2.on("error", reject);
|
|
17904
19066
|
req2.on("timeout", () => {
|
|
@@ -17907,7 +19069,7 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
17907
19069
|
});
|
|
17908
19070
|
req2.end();
|
|
17909
19071
|
} else {
|
|
17910
|
-
|
|
19072
|
+
resolve15(res.headers.etag || res.headers["last-modified"] || "");
|
|
17911
19073
|
}
|
|
17912
19074
|
});
|
|
17913
19075
|
req.on("error", reject);
|
|
@@ -17923,17 +19085,17 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
17923
19085
|
return { updated: false };
|
|
17924
19086
|
}
|
|
17925
19087
|
this.log("Downloading latest providers from GitHub...");
|
|
17926
|
-
const tmpTar =
|
|
17927
|
-
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()}`);
|
|
17928
19090
|
await this.downloadFile(_ProviderLoader.GITHUB_TARBALL_URL, tmpTar);
|
|
17929
19091
|
fs7.mkdirSync(tmpExtract, { recursive: true });
|
|
17930
19092
|
execSync7(`tar -xzf "${tmpTar}" -C "${tmpExtract}"`, { timeout: 3e4 });
|
|
17931
19093
|
const extracted = fs7.readdirSync(tmpExtract);
|
|
17932
19094
|
const rootDir = extracted.find(
|
|
17933
|
-
(d) => fs7.statSync(
|
|
19095
|
+
(d) => fs7.statSync(path17.join(tmpExtract, d)).isDirectory() && d.startsWith("adhdev-providers")
|
|
17934
19096
|
);
|
|
17935
19097
|
if (!rootDir) throw new Error("Unexpected tarball structure");
|
|
17936
|
-
const sourceDir =
|
|
19098
|
+
const sourceDir = path17.join(tmpExtract, rootDir);
|
|
17937
19099
|
const backupDir = this.upstreamDir + ".bak";
|
|
17938
19100
|
if (fs7.existsSync(this.upstreamDir)) {
|
|
17939
19101
|
if (fs7.existsSync(backupDir)) fs7.rmSync(backupDir, { recursive: true, force: true });
|
|
@@ -17971,7 +19133,7 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
17971
19133
|
downloadFile(url, destPath) {
|
|
17972
19134
|
const https = require("https");
|
|
17973
19135
|
const http3 = require("http");
|
|
17974
|
-
return new Promise((
|
|
19136
|
+
return new Promise((resolve15, reject) => {
|
|
17975
19137
|
const doRequest = (reqUrl, redirectCount = 0) => {
|
|
17976
19138
|
if (redirectCount > 5) {
|
|
17977
19139
|
reject(new Error("Too many redirects"));
|
|
@@ -17991,7 +19153,7 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
17991
19153
|
res.pipe(ws);
|
|
17992
19154
|
ws.on("finish", () => {
|
|
17993
19155
|
ws.close();
|
|
17994
|
-
|
|
19156
|
+
resolve15();
|
|
17995
19157
|
});
|
|
17996
19158
|
ws.on("error", reject);
|
|
17997
19159
|
});
|
|
@@ -18008,8 +19170,8 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
18008
19170
|
copyDirRecursive(src, dest) {
|
|
18009
19171
|
fs7.mkdirSync(dest, { recursive: true });
|
|
18010
19172
|
for (const entry of fs7.readdirSync(src, { withFileTypes: true })) {
|
|
18011
|
-
const srcPath =
|
|
18012
|
-
const destPath =
|
|
19173
|
+
const srcPath = path17.join(src, entry.name);
|
|
19174
|
+
const destPath = path17.join(dest, entry.name);
|
|
18013
19175
|
if (entry.isDirectory()) {
|
|
18014
19176
|
this.copyDirRecursive(srcPath, destPath);
|
|
18015
19177
|
} else {
|
|
@@ -18020,7 +19182,7 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
18020
19182
|
/** .meta.json save */
|
|
18021
19183
|
writeMeta(metaPath, etag, timestamp) {
|
|
18022
19184
|
try {
|
|
18023
|
-
fs7.mkdirSync(
|
|
19185
|
+
fs7.mkdirSync(path17.dirname(metaPath), { recursive: true });
|
|
18024
19186
|
fs7.writeFileSync(metaPath, JSON.stringify({
|
|
18025
19187
|
etag,
|
|
18026
19188
|
timestamp,
|
|
@@ -18037,7 +19199,7 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
18037
19199
|
const scan = (d) => {
|
|
18038
19200
|
try {
|
|
18039
19201
|
for (const entry of fs7.readdirSync(d, { withFileTypes: true })) {
|
|
18040
|
-
if (entry.isDirectory()) scan(
|
|
19202
|
+
if (entry.isDirectory()) scan(path17.join(d, entry.name));
|
|
18041
19203
|
else if (entry.name === "provider.json") count++;
|
|
18042
19204
|
}
|
|
18043
19205
|
} catch {
|
|
@@ -18265,17 +19427,17 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
18265
19427
|
for (const root of searchRoots) {
|
|
18266
19428
|
if (!fs7.existsSync(root)) continue;
|
|
18267
19429
|
const candidate = this.getProviderDir(root, cat, type);
|
|
18268
|
-
if (fs7.existsSync(
|
|
18269
|
-
const catDir =
|
|
19430
|
+
if (fs7.existsSync(path17.join(candidate, "provider.json"))) return candidate;
|
|
19431
|
+
const catDir = path17.join(root, cat);
|
|
18270
19432
|
if (fs7.existsSync(catDir)) {
|
|
18271
19433
|
try {
|
|
18272
19434
|
for (const entry of fs7.readdirSync(catDir, { withFileTypes: true })) {
|
|
18273
19435
|
if (!entry.isDirectory()) continue;
|
|
18274
|
-
const jsonPath =
|
|
19436
|
+
const jsonPath = path17.join(catDir, entry.name, "provider.json");
|
|
18275
19437
|
if (fs7.existsSync(jsonPath)) {
|
|
18276
19438
|
try {
|
|
18277
19439
|
const data = JSON.parse(fs7.readFileSync(jsonPath, "utf-8"));
|
|
18278
|
-
if (data.type === type) return
|
|
19440
|
+
if (data.type === type) return path17.join(catDir, entry.name);
|
|
18279
19441
|
} catch {
|
|
18280
19442
|
}
|
|
18281
19443
|
}
|
|
@@ -18292,7 +19454,7 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
18292
19454
|
* (template substitution is NOT applied here — scripts.js handles that)
|
|
18293
19455
|
*/
|
|
18294
19456
|
buildScriptWrappersFromDir(dir) {
|
|
18295
|
-
const scriptsJs =
|
|
19457
|
+
const scriptsJs = path17.join(dir, "scripts.js");
|
|
18296
19458
|
if (fs7.existsSync(scriptsJs)) {
|
|
18297
19459
|
try {
|
|
18298
19460
|
delete require.cache[require.resolve(scriptsJs)];
|
|
@@ -18306,7 +19468,7 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
18306
19468
|
for (const file of fs7.readdirSync(dir)) {
|
|
18307
19469
|
if (!file.endsWith(".js")) continue;
|
|
18308
19470
|
const scriptName = toCamel(file.replace(".js", ""));
|
|
18309
|
-
const filePath =
|
|
19471
|
+
const filePath = path17.join(dir, file);
|
|
18310
19472
|
result[scriptName] = (...args) => {
|
|
18311
19473
|
try {
|
|
18312
19474
|
let content = fs7.readFileSync(filePath, "utf-8");
|
|
@@ -18366,7 +19528,7 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
18366
19528
|
}
|
|
18367
19529
|
const hasJson = entries.some((e) => e.name === "provider.json");
|
|
18368
19530
|
if (hasJson) {
|
|
18369
|
-
const jsonPath =
|
|
19531
|
+
const jsonPath = path17.join(d, "provider.json");
|
|
18370
19532
|
try {
|
|
18371
19533
|
const raw = fs7.readFileSync(jsonPath, "utf-8");
|
|
18372
19534
|
const mod = JSON.parse(raw);
|
|
@@ -18387,7 +19549,7 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
18387
19549
|
this.log(`\u26A0 Invalid provider at ${jsonPath}: ${validation.errors.join("; ")}`);
|
|
18388
19550
|
} else {
|
|
18389
19551
|
const hasCompatibility = Array.isArray(normalizedProvider.compatibility);
|
|
18390
|
-
const scriptsPath =
|
|
19552
|
+
const scriptsPath = path17.join(d, "scripts.js");
|
|
18391
19553
|
if (!hasCompatibility && fs7.existsSync(scriptsPath)) {
|
|
18392
19554
|
try {
|
|
18393
19555
|
delete require.cache[require.resolve(scriptsPath)];
|
|
@@ -18413,7 +19575,7 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
18413
19575
|
if (!entry.isDirectory()) continue;
|
|
18414
19576
|
if (entry.name.startsWith("_") || entry.name.startsWith(".")) continue;
|
|
18415
19577
|
if (excludeDirs && d === dir && excludeDirs.includes(entry.name)) continue;
|
|
18416
|
-
scan(
|
|
19578
|
+
scan(path17.join(d, entry.name));
|
|
18417
19579
|
}
|
|
18418
19580
|
}
|
|
18419
19581
|
};
|
|
@@ -18448,9 +19610,9 @@ var ProviderLoader = class _ProviderLoader {
|
|
|
18448
19610
|
}
|
|
18449
19611
|
}
|
|
18450
19612
|
compareVersions(a, b) {
|
|
18451
|
-
const
|
|
18452
|
-
const pa =
|
|
18453
|
-
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);
|
|
18454
19616
|
for (let i = 0; i < Math.max(pa.length, pb.length); i++) {
|
|
18455
19617
|
const va = pa[i] || 0;
|
|
18456
19618
|
const vb = pb[i] || 0;
|
|
@@ -18570,17 +19732,17 @@ async function findFreePort(ports) {
|
|
|
18570
19732
|
throw new Error("No free port found");
|
|
18571
19733
|
}
|
|
18572
19734
|
function checkPortFree(port) {
|
|
18573
|
-
return new Promise((
|
|
19735
|
+
return new Promise((resolve15) => {
|
|
18574
19736
|
const server = net.createServer();
|
|
18575
19737
|
server.unref();
|
|
18576
|
-
server.on("error", () =>
|
|
19738
|
+
server.on("error", () => resolve15(false));
|
|
18577
19739
|
server.listen(port, "127.0.0.1", () => {
|
|
18578
|
-
server.close(() =>
|
|
19740
|
+
server.close(() => resolve15(true));
|
|
18579
19741
|
});
|
|
18580
19742
|
});
|
|
18581
19743
|
}
|
|
18582
19744
|
async function isCdpActive(port) {
|
|
18583
|
-
return new Promise((
|
|
19745
|
+
return new Promise((resolve15) => {
|
|
18584
19746
|
const req = require("http").get(`http://127.0.0.1:${port}/json/version`, {
|
|
18585
19747
|
timeout: 2e3
|
|
18586
19748
|
}, (res) => {
|
|
@@ -18589,16 +19751,16 @@ async function isCdpActive(port) {
|
|
|
18589
19751
|
res.on("end", () => {
|
|
18590
19752
|
try {
|
|
18591
19753
|
const info = JSON.parse(data);
|
|
18592
|
-
|
|
19754
|
+
resolve15(!!info["WebKit-Version"] || !!info["Browser"]);
|
|
18593
19755
|
} catch {
|
|
18594
|
-
|
|
19756
|
+
resolve15(false);
|
|
18595
19757
|
}
|
|
18596
19758
|
});
|
|
18597
19759
|
});
|
|
18598
|
-
req.on("error", () =>
|
|
19760
|
+
req.on("error", () => resolve15(false));
|
|
18599
19761
|
req.on("timeout", () => {
|
|
18600
19762
|
req.destroy();
|
|
18601
|
-
|
|
19763
|
+
resolve15(false);
|
|
18602
19764
|
});
|
|
18603
19765
|
});
|
|
18604
19766
|
}
|
|
@@ -18738,8 +19900,8 @@ function detectCurrentWorkspace(ideId) {
|
|
|
18738
19900
|
const appNameMap = getMacAppIdentifiers();
|
|
18739
19901
|
const appName = appNameMap[ideId];
|
|
18740
19902
|
if (appName) {
|
|
18741
|
-
const storagePath =
|
|
18742
|
-
process.env.APPDATA ||
|
|
19903
|
+
const storagePath = path18.join(
|
|
19904
|
+
process.env.APPDATA || path18.join(os15.homedir(), "AppData", "Roaming"),
|
|
18743
19905
|
appName,
|
|
18744
19906
|
"storage.json"
|
|
18745
19907
|
);
|
|
@@ -18917,9 +20079,9 @@ init_logger();
|
|
|
18917
20079
|
|
|
18918
20080
|
// src/logging/command-log.ts
|
|
18919
20081
|
var fs8 = __toESM(require("fs"));
|
|
18920
|
-
var
|
|
20082
|
+
var path19 = __toESM(require("path"));
|
|
18921
20083
|
var os16 = __toESM(require("os"));
|
|
18922
|
-
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");
|
|
18923
20085
|
var MAX_FILE_SIZE = 5 * 1024 * 1024;
|
|
18924
20086
|
var MAX_DAYS = 7;
|
|
18925
20087
|
try {
|
|
@@ -18957,13 +20119,13 @@ function getDateStr2() {
|
|
|
18957
20119
|
return (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
|
|
18958
20120
|
}
|
|
18959
20121
|
var currentDate2 = getDateStr2();
|
|
18960
|
-
var currentFile =
|
|
20122
|
+
var currentFile = path19.join(LOG_DIR2, `commands-${currentDate2}.jsonl`);
|
|
18961
20123
|
var writeCount2 = 0;
|
|
18962
20124
|
function checkRotation() {
|
|
18963
20125
|
const today = getDateStr2();
|
|
18964
20126
|
if (today !== currentDate2) {
|
|
18965
20127
|
currentDate2 = today;
|
|
18966
|
-
currentFile =
|
|
20128
|
+
currentFile = path19.join(LOG_DIR2, `commands-${currentDate2}.jsonl`);
|
|
18967
20129
|
cleanOldFiles();
|
|
18968
20130
|
}
|
|
18969
20131
|
}
|
|
@@ -18977,7 +20139,7 @@ function cleanOldFiles() {
|
|
|
18977
20139
|
const dateMatch = file.match(/commands-(\d{4}-\d{2}-\d{2})/);
|
|
18978
20140
|
if (dateMatch && dateMatch[1] < cutoffStr) {
|
|
18979
20141
|
try {
|
|
18980
|
-
fs8.unlinkSync(
|
|
20142
|
+
fs8.unlinkSync(path19.join(LOG_DIR2, file));
|
|
18981
20143
|
} catch {
|
|
18982
20144
|
}
|
|
18983
20145
|
}
|
|
@@ -18987,8 +20149,8 @@ function cleanOldFiles() {
|
|
|
18987
20149
|
}
|
|
18988
20150
|
function checkSize() {
|
|
18989
20151
|
try {
|
|
18990
|
-
const
|
|
18991
|
-
if (
|
|
20152
|
+
const stat2 = fs8.statSync(currentFile);
|
|
20153
|
+
if (stat2.size > MAX_FILE_SIZE) {
|
|
18992
20154
|
const backup = currentFile.replace(".jsonl", ".1.jsonl");
|
|
18993
20155
|
try {
|
|
18994
20156
|
fs8.unlinkSync(backup);
|
|
@@ -19274,12 +20436,18 @@ function buildStatusSnapshot(options) {
|
|
|
19274
20436
|
const unreadSourceSessions = buildSessionEntries(
|
|
19275
20437
|
options.allStates,
|
|
19276
20438
|
options.cdpManagers,
|
|
19277
|
-
{
|
|
20439
|
+
{
|
|
20440
|
+
profile: "full",
|
|
20441
|
+
getGitSummaryForWorkspace: options.getGitSummaryForWorkspace
|
|
20442
|
+
}
|
|
19278
20443
|
);
|
|
19279
20444
|
const sessions = profile === "full" ? unreadSourceSessions : profile === "live" ? unreadSourceSessions.map(projectLiveSessionFromFull) : buildSessionEntries(
|
|
19280
20445
|
options.allStates,
|
|
19281
20446
|
options.cdpManagers,
|
|
19282
|
-
{
|
|
20447
|
+
{
|
|
20448
|
+
profile,
|
|
20449
|
+
getGitSummaryForWorkspace: options.getGitSummaryForWorkspace
|
|
20450
|
+
}
|
|
19283
20451
|
);
|
|
19284
20452
|
const sessionsById = new Map(sessions.map((session) => [session.id, session]));
|
|
19285
20453
|
for (const sourceSession of unreadSourceSessions) {
|
|
@@ -19373,13 +20541,13 @@ var import_child_process8 = require("child_process");
|
|
|
19373
20541
|
var import_child_process9 = require("child_process");
|
|
19374
20542
|
var fs9 = __toESM(require("fs"));
|
|
19375
20543
|
var os18 = __toESM(require("os"));
|
|
19376
|
-
var
|
|
20544
|
+
var path20 = __toESM(require("path"));
|
|
19377
20545
|
var UPGRADE_HELPER_ENV = "ADHDEV_DAEMON_UPGRADE_HELPER";
|
|
19378
20546
|
function getUpgradeLogPath() {
|
|
19379
20547
|
const home = os18.homedir();
|
|
19380
|
-
const dir =
|
|
20548
|
+
const dir = path20.join(home, ".adhdev");
|
|
19381
20549
|
fs9.mkdirSync(dir, { recursive: true });
|
|
19382
|
-
return
|
|
20550
|
+
return path20.join(dir, "daemon-upgrade.log");
|
|
19383
20551
|
}
|
|
19384
20552
|
function appendUpgradeLog(message) {
|
|
19385
20553
|
const line = `[${(/* @__PURE__ */ new Date()).toISOString()}] ${message}
|
|
@@ -19390,14 +20558,14 @@ function appendUpgradeLog(message) {
|
|
|
19390
20558
|
}
|
|
19391
20559
|
}
|
|
19392
20560
|
function resolveSiblingNpmInvocation(nodeExecutable, platform10 = process.platform) {
|
|
19393
|
-
const binDir =
|
|
20561
|
+
const binDir = path20.dirname(nodeExecutable);
|
|
19394
20562
|
if (platform10 === "win32") {
|
|
19395
|
-
const npmCliPath =
|
|
20563
|
+
const npmCliPath = path20.join(binDir, "node_modules", "npm", "bin", "npm-cli.js");
|
|
19396
20564
|
if (fs9.existsSync(npmCliPath)) {
|
|
19397
20565
|
return { executable: nodeExecutable, argsPrefix: [npmCliPath], execOptions: getNpmExecOptions(platform10) };
|
|
19398
20566
|
}
|
|
19399
20567
|
for (const candidate of ["npm.exe", "npm"]) {
|
|
19400
|
-
const candidatePath =
|
|
20568
|
+
const candidatePath = path20.join(binDir, candidate);
|
|
19401
20569
|
if (fs9.existsSync(candidatePath)) {
|
|
19402
20570
|
return { executable: candidatePath, argsPrefix: [], execOptions: getNpmExecOptions(platform10) };
|
|
19403
20571
|
}
|
|
@@ -19405,7 +20573,7 @@ function resolveSiblingNpmInvocation(nodeExecutable, platform10 = process.platfo
|
|
|
19405
20573
|
return { executable: nodeExecutable, argsPrefix: [npmCliPath], execOptions: getNpmExecOptions(platform10) };
|
|
19406
20574
|
}
|
|
19407
20575
|
for (const candidate of ["npm"]) {
|
|
19408
|
-
const candidatePath =
|
|
20576
|
+
const candidatePath = path20.join(binDir, candidate);
|
|
19409
20577
|
if (fs9.existsSync(candidatePath)) {
|
|
19410
20578
|
return { executable: candidatePath, argsPrefix: [], execOptions: getNpmExecOptions(platform10) };
|
|
19411
20579
|
}
|
|
@@ -19422,13 +20590,13 @@ function findCurrentPackageRoot(currentCliPath, packageName) {
|
|
|
19422
20590
|
let currentDir = resolvedPath;
|
|
19423
20591
|
try {
|
|
19424
20592
|
if (fs9.statSync(resolvedPath).isFile()) {
|
|
19425
|
-
currentDir =
|
|
20593
|
+
currentDir = path20.dirname(resolvedPath);
|
|
19426
20594
|
}
|
|
19427
20595
|
} catch {
|
|
19428
|
-
currentDir =
|
|
20596
|
+
currentDir = path20.dirname(resolvedPath);
|
|
19429
20597
|
}
|
|
19430
20598
|
while (true) {
|
|
19431
|
-
const packageJsonPath =
|
|
20599
|
+
const packageJsonPath = path20.join(currentDir, "package.json");
|
|
19432
20600
|
try {
|
|
19433
20601
|
if (fs9.existsSync(packageJsonPath)) {
|
|
19434
20602
|
const parsed = JSON.parse(fs9.readFileSync(packageJsonPath, "utf8"));
|
|
@@ -19439,7 +20607,7 @@ function findCurrentPackageRoot(currentCliPath, packageName) {
|
|
|
19439
20607
|
}
|
|
19440
20608
|
} catch {
|
|
19441
20609
|
}
|
|
19442
|
-
const parentDir =
|
|
20610
|
+
const parentDir = path20.dirname(currentDir);
|
|
19443
20611
|
if (parentDir === currentDir) {
|
|
19444
20612
|
return null;
|
|
19445
20613
|
}
|
|
@@ -19447,13 +20615,13 @@ function findCurrentPackageRoot(currentCliPath, packageName) {
|
|
|
19447
20615
|
}
|
|
19448
20616
|
}
|
|
19449
20617
|
function resolveInstallPrefixFromPackageRoot(packageRoot, packageName) {
|
|
19450
|
-
const nodeModulesDir = packageName.startsWith("@") ?
|
|
19451
|
-
if (
|
|
20618
|
+
const nodeModulesDir = packageName.startsWith("@") ? path20.dirname(path20.dirname(packageRoot)) : path20.dirname(packageRoot);
|
|
20619
|
+
if (path20.basename(nodeModulesDir) !== "node_modules") {
|
|
19452
20620
|
return null;
|
|
19453
20621
|
}
|
|
19454
|
-
const maybeLibDir =
|
|
19455
|
-
if (
|
|
19456
|
-
return
|
|
20622
|
+
const maybeLibDir = path20.dirname(nodeModulesDir);
|
|
20623
|
+
if (path20.basename(maybeLibDir) === "lib") {
|
|
20624
|
+
return path20.dirname(maybeLibDir);
|
|
19457
20625
|
}
|
|
19458
20626
|
return maybeLibDir;
|
|
19459
20627
|
}
|
|
@@ -19561,14 +20729,14 @@ async function waitForPidExit(pid, timeoutMs) {
|
|
|
19561
20729
|
while (Date.now() - start < timeoutMs) {
|
|
19562
20730
|
try {
|
|
19563
20731
|
process.kill(pid, 0);
|
|
19564
|
-
await new Promise((
|
|
20732
|
+
await new Promise((resolve15) => setTimeout(resolve15, 250));
|
|
19565
20733
|
} catch {
|
|
19566
20734
|
return;
|
|
19567
20735
|
}
|
|
19568
20736
|
}
|
|
19569
20737
|
}
|
|
19570
20738
|
function stopSessionHostProcesses(appName) {
|
|
19571
|
-
const pidFile =
|
|
20739
|
+
const pidFile = path20.join(os18.homedir(), ".adhdev", `${appName}-session-host.pid`);
|
|
19572
20740
|
try {
|
|
19573
20741
|
if (fs9.existsSync(pidFile)) {
|
|
19574
20742
|
const pid = Number.parseInt(fs9.readFileSync(pidFile, "utf8").trim(), 10);
|
|
@@ -19585,7 +20753,7 @@ function stopSessionHostProcesses(appName) {
|
|
|
19585
20753
|
}
|
|
19586
20754
|
}
|
|
19587
20755
|
function removeDaemonPidFile() {
|
|
19588
|
-
const pidFile =
|
|
20756
|
+
const pidFile = path20.join(os18.homedir(), ".adhdev", "daemon.pid");
|
|
19589
20757
|
try {
|
|
19590
20758
|
fs9.unlinkSync(pidFile);
|
|
19591
20759
|
} catch {
|
|
@@ -19596,7 +20764,7 @@ function cleanupStaleGlobalInstallDirs(pkgName, surface) {
|
|
|
19596
20764
|
const npmRoot = String(execNpmCommandSync(["root", "-g", ...prefixArgs], { encoding: "utf8" }, surface)).trim();
|
|
19597
20765
|
if (!npmRoot) return;
|
|
19598
20766
|
const npmPrefix = surface.installPrefix || String(execNpmCommandSync(["prefix", "-g", ...prefixArgs], { encoding: "utf8" }, surface)).trim();
|
|
19599
|
-
const binDir = process.platform === "win32" ? npmPrefix :
|
|
20767
|
+
const binDir = process.platform === "win32" ? npmPrefix : path20.join(npmPrefix, "bin");
|
|
19600
20768
|
const packageBaseName = pkgName.startsWith("@") ? pkgName.split("/")[1] : pkgName;
|
|
19601
20769
|
const binNames = /* @__PURE__ */ new Set([packageBaseName]);
|
|
19602
20770
|
if (pkgName === "@adhdev/daemon-standalone") {
|
|
@@ -19604,25 +20772,25 @@ function cleanupStaleGlobalInstallDirs(pkgName, surface) {
|
|
|
19604
20772
|
}
|
|
19605
20773
|
if (pkgName.startsWith("@")) {
|
|
19606
20774
|
const [scope, name] = pkgName.split("/");
|
|
19607
|
-
const scopeDir =
|
|
20775
|
+
const scopeDir = path20.join(npmRoot, scope);
|
|
19608
20776
|
if (!fs9.existsSync(scopeDir)) return;
|
|
19609
20777
|
for (const entry of fs9.readdirSync(scopeDir)) {
|
|
19610
20778
|
if (!entry.startsWith(`.${name}-`)) continue;
|
|
19611
|
-
fs9.rmSync(
|
|
19612
|
-
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)}`);
|
|
19613
20781
|
}
|
|
19614
20782
|
} else {
|
|
19615
20783
|
for (const entry of fs9.readdirSync(npmRoot)) {
|
|
19616
20784
|
if (!entry.startsWith(`.${pkgName}-`)) continue;
|
|
19617
|
-
fs9.rmSync(
|
|
19618
|
-
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)}`);
|
|
19619
20787
|
}
|
|
19620
20788
|
}
|
|
19621
20789
|
if (fs9.existsSync(binDir)) {
|
|
19622
20790
|
for (const entry of fs9.readdirSync(binDir)) {
|
|
19623
20791
|
if (!Array.from(binNames).some((name) => entry.startsWith(`.${name}-`))) continue;
|
|
19624
|
-
fs9.rmSync(
|
|
19625
|
-
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)}`);
|
|
19626
20794
|
}
|
|
19627
20795
|
}
|
|
19628
20796
|
}
|
|
@@ -19672,7 +20840,7 @@ async function runDaemonUpgradeHelper(payload) {
|
|
|
19672
20840
|
appendUpgradeLog(installOutput.trim());
|
|
19673
20841
|
}
|
|
19674
20842
|
if (process.platform === "win32") {
|
|
19675
|
-
await new Promise((
|
|
20843
|
+
await new Promise((resolve15) => setTimeout(resolve15, 500));
|
|
19676
20844
|
cleanupStaleGlobalInstallDirs(payload.packageName, installCommand.surface);
|
|
19677
20845
|
appendUpgradeLog("Post-install staging cleanup complete");
|
|
19678
20846
|
}
|
|
@@ -21066,7 +22234,7 @@ var ProviderStreamAdapter = class {
|
|
|
21066
22234
|
const beforeCount = this.messageCount(before);
|
|
21067
22235
|
const beforeSignature = this.lastMessageSignature(before);
|
|
21068
22236
|
for (let attempt = 0; attempt < 12; attempt += 1) {
|
|
21069
|
-
await new Promise((
|
|
22237
|
+
await new Promise((resolve15) => setTimeout(resolve15, 250));
|
|
21070
22238
|
let state;
|
|
21071
22239
|
try {
|
|
21072
22240
|
state = await this.readChat(evaluate);
|
|
@@ -21088,7 +22256,7 @@ var ProviderStreamAdapter = class {
|
|
|
21088
22256
|
if (this.messageCount(first) > 0 || this.lastMessageSignature(first)) {
|
|
21089
22257
|
return first;
|
|
21090
22258
|
}
|
|
21091
|
-
await new Promise((
|
|
22259
|
+
await new Promise((resolve15) => setTimeout(resolve15, 150));
|
|
21092
22260
|
const second = await this.readChat(evaluate);
|
|
21093
22261
|
return this.messageCount(second) >= this.messageCount(first) ? second : first;
|
|
21094
22262
|
}
|
|
@@ -21239,7 +22407,7 @@ var ProviderStreamAdapter = class {
|
|
|
21239
22407
|
if (typeof data.error === "string" && data.error.trim()) return false;
|
|
21240
22408
|
}
|
|
21241
22409
|
for (let attempt = 0; attempt < 6; attempt += 1) {
|
|
21242
|
-
await new Promise((
|
|
22410
|
+
await new Promise((resolve15) => setTimeout(resolve15, 250));
|
|
21243
22411
|
const state = await this.readChat(evaluate);
|
|
21244
22412
|
const title = this.getStateTitle(state);
|
|
21245
22413
|
if (this.titlesMatch(title, sessionId)) return true;
|
|
@@ -22100,11 +23268,11 @@ init_chat_message_normalization();
|
|
|
22100
23268
|
|
|
22101
23269
|
// src/providers/version-archive.ts
|
|
22102
23270
|
var fs11 = __toESM(require("fs"));
|
|
22103
|
-
var
|
|
23271
|
+
var path21 = __toESM(require("path"));
|
|
22104
23272
|
var os19 = __toESM(require("os"));
|
|
22105
23273
|
var import_child_process10 = require("child_process");
|
|
22106
23274
|
var import_os3 = require("os");
|
|
22107
|
-
var ARCHIVE_PATH =
|
|
23275
|
+
var ARCHIVE_PATH = path21.join(os19.homedir(), ".adhdev", "version-history.json");
|
|
22108
23276
|
var MAX_ENTRIES_PER_PROVIDER = 20;
|
|
22109
23277
|
var VersionArchive = class {
|
|
22110
23278
|
history = {};
|
|
@@ -22151,7 +23319,7 @@ var VersionArchive = class {
|
|
|
22151
23319
|
}
|
|
22152
23320
|
save() {
|
|
22153
23321
|
try {
|
|
22154
|
-
fs11.mkdirSync(
|
|
23322
|
+
fs11.mkdirSync(path21.dirname(ARCHIVE_PATH), { recursive: true });
|
|
22155
23323
|
fs11.writeFileSync(ARCHIVE_PATH, JSON.stringify(this.history, null, 2));
|
|
22156
23324
|
} catch {
|
|
22157
23325
|
}
|
|
@@ -22208,7 +23376,7 @@ function checkPathExists2(paths) {
|
|
|
22208
23376
|
for (const p of paths) {
|
|
22209
23377
|
if (p.includes("*")) {
|
|
22210
23378
|
const home = os19.homedir();
|
|
22211
|
-
const resolved = p.replace(/\*/g, home.split(
|
|
23379
|
+
const resolved = p.replace(/\*/g, home.split(path21.sep).pop() || "");
|
|
22212
23380
|
if (fs11.existsSync(resolved)) return resolved;
|
|
22213
23381
|
} else {
|
|
22214
23382
|
if (fs11.existsSync(p)) return p;
|
|
@@ -22218,7 +23386,7 @@ function checkPathExists2(paths) {
|
|
|
22218
23386
|
}
|
|
22219
23387
|
function getMacAppVersion(appPath) {
|
|
22220
23388
|
if ((0, import_os3.platform)() !== "darwin" || !appPath.endsWith(".app")) return null;
|
|
22221
|
-
const plistPath =
|
|
23389
|
+
const plistPath = path21.join(appPath, "Contents", "Info.plist");
|
|
22222
23390
|
if (!fs11.existsSync(plistPath)) return null;
|
|
22223
23391
|
const raw = runCommand(`/usr/libexec/PlistBuddy -c "Print CFBundleShortVersionString" "${plistPath}"`);
|
|
22224
23392
|
return raw || null;
|
|
@@ -22244,7 +23412,7 @@ async function detectAllVersions(loader, archive) {
|
|
|
22244
23412
|
const cliBin = provider.cli ? findBinary2(provider.cli) : null;
|
|
22245
23413
|
let resolvedBin = cliBin;
|
|
22246
23414
|
if (!resolvedBin && appPath && currentOs === "darwin") {
|
|
22247
|
-
const bundled =
|
|
23415
|
+
const bundled = path21.join(appPath, "Contents", "Resources", "app", "bin", provider.cli || "");
|
|
22248
23416
|
if (provider.cli && fs11.existsSync(bundled)) resolvedBin = bundled;
|
|
22249
23417
|
}
|
|
22250
23418
|
info.installed = !!(appPath || resolvedBin);
|
|
@@ -22285,7 +23453,7 @@ async function detectAllVersions(loader, archive) {
|
|
|
22285
23453
|
// src/daemon/dev-server.ts
|
|
22286
23454
|
var http2 = __toESM(require("http"));
|
|
22287
23455
|
var fs15 = __toESM(require("fs"));
|
|
22288
|
-
var
|
|
23456
|
+
var path25 = __toESM(require("path"));
|
|
22289
23457
|
init_config();
|
|
22290
23458
|
|
|
22291
23459
|
// src/daemon/scaffold-template.ts
|
|
@@ -22636,7 +23804,7 @@ init_logger();
|
|
|
22636
23804
|
|
|
22637
23805
|
// src/daemon/dev-cdp-handlers.ts
|
|
22638
23806
|
var fs12 = __toESM(require("fs"));
|
|
22639
|
-
var
|
|
23807
|
+
var path22 = __toESM(require("path"));
|
|
22640
23808
|
init_logger();
|
|
22641
23809
|
async function handleCdpEvaluate(ctx, req, res) {
|
|
22642
23810
|
const body = await ctx.readBody(req);
|
|
@@ -22815,17 +23983,17 @@ async function handleScriptHints(ctx, type, _req, res) {
|
|
|
22815
23983
|
return;
|
|
22816
23984
|
}
|
|
22817
23985
|
let scriptsPath = "";
|
|
22818
|
-
const directScripts =
|
|
23986
|
+
const directScripts = path22.join(dir, "scripts.js");
|
|
22819
23987
|
if (fs12.existsSync(directScripts)) {
|
|
22820
23988
|
scriptsPath = directScripts;
|
|
22821
23989
|
} else {
|
|
22822
|
-
const scriptsDir =
|
|
23990
|
+
const scriptsDir = path22.join(dir, "scripts");
|
|
22823
23991
|
if (fs12.existsSync(scriptsDir)) {
|
|
22824
23992
|
const versions = fs12.readdirSync(scriptsDir).filter((d) => {
|
|
22825
|
-
return fs12.statSync(
|
|
23993
|
+
return fs12.statSync(path22.join(scriptsDir, d)).isDirectory();
|
|
22826
23994
|
}).sort().reverse();
|
|
22827
23995
|
for (const ver of versions) {
|
|
22828
|
-
const p =
|
|
23996
|
+
const p = path22.join(scriptsDir, ver, "scripts.js");
|
|
22829
23997
|
if (fs12.existsSync(p)) {
|
|
22830
23998
|
scriptsPath = p;
|
|
22831
23999
|
break;
|
|
@@ -23654,7 +24822,7 @@ async function handleDomContext(ctx, type, req, res) {
|
|
|
23654
24822
|
|
|
23655
24823
|
// src/daemon/dev-cli-debug.ts
|
|
23656
24824
|
var fs13 = __toESM(require("fs"));
|
|
23657
|
-
var
|
|
24825
|
+
var path23 = __toESM(require("path"));
|
|
23658
24826
|
function slugifyFixtureName(value) {
|
|
23659
24827
|
const normalized = String(value || "").trim().toLowerCase().replace(/[^a-z0-9._-]+/g, "-").replace(/^-+|-+$/g, "");
|
|
23660
24828
|
return normalized || `fixture-${Date.now()}`;
|
|
@@ -23664,11 +24832,11 @@ function getCliFixtureDir(ctx, type) {
|
|
|
23664
24832
|
if (!providerDir) {
|
|
23665
24833
|
throw new Error(`Provider directory not found for '${type}'`);
|
|
23666
24834
|
}
|
|
23667
|
-
return
|
|
24835
|
+
return path23.join(providerDir, "fixtures");
|
|
23668
24836
|
}
|
|
23669
24837
|
function readCliFixture(ctx, type, name) {
|
|
23670
24838
|
const fixtureDir = getCliFixtureDir(ctx, type);
|
|
23671
|
-
const filePath =
|
|
24839
|
+
const filePath = path23.join(fixtureDir, `${name}.json`);
|
|
23672
24840
|
if (!fs13.existsSync(filePath)) {
|
|
23673
24841
|
throw new Error(`Fixture not found: ${filePath}`);
|
|
23674
24842
|
}
|
|
@@ -23837,7 +25005,7 @@ function getCliTargetBundle(ctx, type, instanceId) {
|
|
|
23837
25005
|
return { target, instance, adapter };
|
|
23838
25006
|
}
|
|
23839
25007
|
function sleep(ms) {
|
|
23840
|
-
return new Promise((
|
|
25008
|
+
return new Promise((resolve15) => setTimeout(resolve15, ms));
|
|
23841
25009
|
}
|
|
23842
25010
|
async function waitForCliReady(ctx, type, instanceId, timeoutMs) {
|
|
23843
25011
|
const startedAt = Date.now();
|
|
@@ -24135,7 +25303,7 @@ async function runCliAutoImplVerification(ctx, type, verification) {
|
|
|
24135
25303
|
return {
|
|
24136
25304
|
mode: "fixture_replay_suite",
|
|
24137
25305
|
pass: results.every((item) => item.pass),
|
|
24138
|
-
failures: results.flatMap((item) => item.failures.map((
|
|
25306
|
+
failures: results.flatMap((item) => item.failures.map((failure2) => `${item.fixtureName}: ${failure2}`)),
|
|
24139
25307
|
result: firstFailure.result,
|
|
24140
25308
|
assertions: firstFailure.assertions,
|
|
24141
25309
|
fixture: firstFailure.fixture,
|
|
@@ -24435,7 +25603,7 @@ async function handleCliFixtureCapture(ctx, req, res) {
|
|
|
24435
25603
|
},
|
|
24436
25604
|
notes: typeof body?.notes === "string" ? body.notes : void 0
|
|
24437
25605
|
};
|
|
24438
|
-
const filePath =
|
|
25606
|
+
const filePath = path23.join(fixtureDir, `${name}.json`);
|
|
24439
25607
|
fs13.writeFileSync(filePath, JSON.stringify(fixture, null, 2));
|
|
24440
25608
|
ctx.json(res, 200, {
|
|
24441
25609
|
saved: true,
|
|
@@ -24459,7 +25627,7 @@ async function handleCliFixtureList(ctx, type, _req, res) {
|
|
|
24459
25627
|
return;
|
|
24460
25628
|
}
|
|
24461
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) => {
|
|
24462
|
-
const fullPath =
|
|
25630
|
+
const fullPath = path23.join(fixtureDir, file);
|
|
24463
25631
|
try {
|
|
24464
25632
|
const raw = JSON.parse(fs13.readFileSync(fullPath, "utf-8"));
|
|
24465
25633
|
return {
|
|
@@ -24595,7 +25763,7 @@ async function handleCliRaw(ctx, req, res) {
|
|
|
24595
25763
|
|
|
24596
25764
|
// src/daemon/dev-auto-implement.ts
|
|
24597
25765
|
var fs14 = __toESM(require("fs"));
|
|
24598
|
-
var
|
|
25766
|
+
var path24 = __toESM(require("path"));
|
|
24599
25767
|
var os20 = __toESM(require("os"));
|
|
24600
25768
|
function getAutoImplPid(ctx) {
|
|
24601
25769
|
const pid = ctx.autoImplProcess?.pid;
|
|
@@ -24645,22 +25813,22 @@ function getLatestScriptVersionDir(scriptsDir) {
|
|
|
24645
25813
|
if (!fs14.existsSync(scriptsDir)) return null;
|
|
24646
25814
|
const versions = fs14.readdirSync(scriptsDir).filter((d) => {
|
|
24647
25815
|
try {
|
|
24648
|
-
return fs14.statSync(
|
|
25816
|
+
return fs14.statSync(path24.join(scriptsDir, d)).isDirectory();
|
|
24649
25817
|
} catch {
|
|
24650
25818
|
return false;
|
|
24651
25819
|
}
|
|
24652
25820
|
}).sort((a, b) => b.localeCompare(a, void 0, { numeric: true, sensitivity: "base" }));
|
|
24653
25821
|
if (versions.length === 0) return null;
|
|
24654
|
-
return
|
|
25822
|
+
return path24.join(scriptsDir, versions[0]);
|
|
24655
25823
|
}
|
|
24656
25824
|
function resolveAutoImplWritableProviderDir(ctx, category, type, requestedDir) {
|
|
24657
|
-
const canonicalUserDir =
|
|
24658
|
-
const desiredDir = requestedDir ?
|
|
24659
|
-
const upstreamRoot =
|
|
24660
|
-
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}`)) {
|
|
24661
25829
|
return { dir: null, reason: `Refusing to write into upstream provider directory: ${desiredDir}` };
|
|
24662
25830
|
}
|
|
24663
|
-
if (
|
|
25831
|
+
if (path24.basename(desiredDir) !== type) {
|
|
24664
25832
|
return { dir: null, reason: `Requested writable provider directory must end with '${type}': ${desiredDir}` };
|
|
24665
25833
|
}
|
|
24666
25834
|
const sourceDir = ctx.findProviderDir(type);
|
|
@@ -24668,11 +25836,11 @@ function resolveAutoImplWritableProviderDir(ctx, category, type, requestedDir) {
|
|
|
24668
25836
|
return { dir: null, reason: `Provider source directory not found for '${type}'` };
|
|
24669
25837
|
}
|
|
24670
25838
|
if (!fs14.existsSync(desiredDir)) {
|
|
24671
|
-
fs14.mkdirSync(
|
|
25839
|
+
fs14.mkdirSync(path24.dirname(desiredDir), { recursive: true });
|
|
24672
25840
|
fs14.cpSync(sourceDir, desiredDir, { recursive: true });
|
|
24673
25841
|
ctx.log(`Auto-implement writable copy created: ${desiredDir}`);
|
|
24674
25842
|
}
|
|
24675
|
-
const providerJson =
|
|
25843
|
+
const providerJson = path24.join(desiredDir, "provider.json");
|
|
24676
25844
|
if (!fs14.existsSync(providerJson)) {
|
|
24677
25845
|
return { dir: null, reason: `provider.json not found in writable provider directory: ${desiredDir}` };
|
|
24678
25846
|
}
|
|
@@ -24683,13 +25851,13 @@ function loadAutoImplReferenceScripts(ctx, referenceType) {
|
|
|
24683
25851
|
const refDir = ctx.findProviderDir(referenceType);
|
|
24684
25852
|
if (!refDir || !fs14.existsSync(refDir)) return {};
|
|
24685
25853
|
const referenceScripts = {};
|
|
24686
|
-
const scriptsDir =
|
|
25854
|
+
const scriptsDir = path24.join(refDir, "scripts");
|
|
24687
25855
|
const latestDir = getLatestScriptVersionDir(scriptsDir);
|
|
24688
25856
|
if (!latestDir) return referenceScripts;
|
|
24689
25857
|
for (const file of fs14.readdirSync(latestDir)) {
|
|
24690
25858
|
if (!file.endsWith(".js")) continue;
|
|
24691
25859
|
try {
|
|
24692
|
-
referenceScripts[file] = fs14.readFileSync(
|
|
25860
|
+
referenceScripts[file] = fs14.readFileSync(path24.join(latestDir, file), "utf-8");
|
|
24693
25861
|
} catch {
|
|
24694
25862
|
}
|
|
24695
25863
|
}
|
|
@@ -24797,9 +25965,9 @@ async function handleAutoImplement(ctx, type, req, res) {
|
|
|
24797
25965
|
});
|
|
24798
25966
|
const referenceScripts = loadAutoImplReferenceScripts(ctx, resolvedReference);
|
|
24799
25967
|
const prompt = buildAutoImplPrompt(ctx, type, provider, providerDir, functions, domContext, referenceScripts, comment, resolvedReference, verification);
|
|
24800
|
-
const tmpDir =
|
|
25968
|
+
const tmpDir = path24.join(os20.tmpdir(), "adhdev-autoimpl");
|
|
24801
25969
|
if (!fs14.existsSync(tmpDir)) fs14.mkdirSync(tmpDir, { recursive: true });
|
|
24802
|
-
const promptFile =
|
|
25970
|
+
const promptFile = path24.join(tmpDir, `prompt-${type}-${Date.now()}.md`);
|
|
24803
25971
|
fs14.writeFileSync(promptFile, prompt, "utf-8");
|
|
24804
25972
|
ctx.log(`Auto-implement prompt written to ${promptFile} (${prompt.length} chars)`);
|
|
24805
25973
|
const agentProvider = ctx.providerLoader.resolve(agent) || ctx.providerLoader.getMeta(agent);
|
|
@@ -25231,7 +26399,7 @@ function buildAutoImplPrompt(ctx, type, provider, providerDir, functions, domCon
|
|
|
25231
26399
|
setMode: "set_mode.js"
|
|
25232
26400
|
};
|
|
25233
26401
|
const targetFileNames = new Set(functions.map((fn) => funcToFile[fn]).filter(Boolean));
|
|
25234
|
-
const scriptsDir =
|
|
26402
|
+
const scriptsDir = path24.join(providerDir, "scripts");
|
|
25235
26403
|
const latestScriptsDir = getLatestScriptVersionDir(scriptsDir);
|
|
25236
26404
|
if (latestScriptsDir) {
|
|
25237
26405
|
lines.push(`Scripts version directory: \`${latestScriptsDir}\``);
|
|
@@ -25242,7 +26410,7 @@ function buildAutoImplPrompt(ctx, type, provider, providerDir, functions, domCon
|
|
|
25242
26410
|
for (const file of fs14.readdirSync(latestScriptsDir)) {
|
|
25243
26411
|
if (file.endsWith(".js") && targetFileNames.has(file)) {
|
|
25244
26412
|
try {
|
|
25245
|
-
const content = fs14.readFileSync(
|
|
26413
|
+
const content = fs14.readFileSync(path24.join(latestScriptsDir, file), "utf-8");
|
|
25246
26414
|
lines.push(`### \`${file}\` \u270F\uFE0F EDIT`);
|
|
25247
26415
|
lines.push("```javascript");
|
|
25248
26416
|
lines.push(content);
|
|
@@ -25259,7 +26427,7 @@ function buildAutoImplPrompt(ctx, type, provider, providerDir, functions, domCon
|
|
|
25259
26427
|
lines.push("");
|
|
25260
26428
|
for (const file of refFiles) {
|
|
25261
26429
|
try {
|
|
25262
|
-
const content = fs14.readFileSync(
|
|
26430
|
+
const content = fs14.readFileSync(path24.join(latestScriptsDir, file), "utf-8");
|
|
25263
26431
|
lines.push(`### \`${file}\` \u{1F512}`);
|
|
25264
26432
|
lines.push("```javascript");
|
|
25265
26433
|
lines.push(content);
|
|
@@ -25300,10 +26468,10 @@ function buildAutoImplPrompt(ctx, type, provider, providerDir, functions, domCon
|
|
|
25300
26468
|
lines.push("");
|
|
25301
26469
|
}
|
|
25302
26470
|
}
|
|
25303
|
-
const docsDir =
|
|
26471
|
+
const docsDir = path24.join(providerDir, "../../docs");
|
|
25304
26472
|
const loadGuide = (name) => {
|
|
25305
26473
|
try {
|
|
25306
|
-
const p =
|
|
26474
|
+
const p = path24.join(docsDir, name);
|
|
25307
26475
|
if (fs14.existsSync(p)) return fs14.readFileSync(p, "utf-8");
|
|
25308
26476
|
} catch {
|
|
25309
26477
|
}
|
|
@@ -25540,7 +26708,7 @@ function buildCliAutoImplPrompt(ctx, type, provider, providerDir, functions, ref
|
|
|
25540
26708
|
parseApproval: "parse_approval.js"
|
|
25541
26709
|
};
|
|
25542
26710
|
const targetFileNames = new Set(functions.map((fn) => funcToFile[fn]).filter(Boolean));
|
|
25543
|
-
const scriptsDir =
|
|
26711
|
+
const scriptsDir = path24.join(providerDir, "scripts");
|
|
25544
26712
|
const latestScriptsDir = getLatestScriptVersionDir(scriptsDir);
|
|
25545
26713
|
if (latestScriptsDir) {
|
|
25546
26714
|
lines.push(`Scripts version directory: \`${latestScriptsDir}\``);
|
|
@@ -25552,7 +26720,7 @@ function buildCliAutoImplPrompt(ctx, type, provider, providerDir, functions, ref
|
|
|
25552
26720
|
if (!file.endsWith(".js")) continue;
|
|
25553
26721
|
if (!targetFileNames.has(file)) continue;
|
|
25554
26722
|
try {
|
|
25555
|
-
const content = fs14.readFileSync(
|
|
26723
|
+
const content = fs14.readFileSync(path24.join(latestScriptsDir, file), "utf-8");
|
|
25556
26724
|
lines.push(`### \`${file}\` \u270F\uFE0F EDIT`);
|
|
25557
26725
|
lines.push("```javascript");
|
|
25558
26726
|
lines.push(content);
|
|
@@ -25568,7 +26736,7 @@ function buildCliAutoImplPrompt(ctx, type, provider, providerDir, functions, ref
|
|
|
25568
26736
|
lines.push("");
|
|
25569
26737
|
for (const file of refFiles) {
|
|
25570
26738
|
try {
|
|
25571
|
-
const content = fs14.readFileSync(
|
|
26739
|
+
const content = fs14.readFileSync(path24.join(latestScriptsDir, file), "utf-8");
|
|
25572
26740
|
lines.push(`### \`${file}\` \u{1F512}`);
|
|
25573
26741
|
lines.push("```javascript");
|
|
25574
26742
|
lines.push(content);
|
|
@@ -25601,10 +26769,10 @@ function buildCliAutoImplPrompt(ctx, type, provider, providerDir, functions, ref
|
|
|
25601
26769
|
lines.push("");
|
|
25602
26770
|
}
|
|
25603
26771
|
}
|
|
25604
|
-
const docsDir =
|
|
26772
|
+
const docsDir = path24.join(providerDir, "../../docs");
|
|
25605
26773
|
const loadGuide = (name) => {
|
|
25606
26774
|
try {
|
|
25607
|
-
const p =
|
|
26775
|
+
const p = path24.join(docsDir, name);
|
|
25608
26776
|
if (fs14.existsSync(p)) return fs14.readFileSync(p, "utf-8");
|
|
25609
26777
|
} catch {
|
|
25610
26778
|
}
|
|
@@ -26051,8 +27219,8 @@ var DevServer = class _DevServer {
|
|
|
26051
27219
|
}
|
|
26052
27220
|
getEndpointList() {
|
|
26053
27221
|
return this.routes.map((r) => {
|
|
26054
|
-
const
|
|
26055
|
-
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}`;
|
|
26056
27224
|
});
|
|
26057
27225
|
}
|
|
26058
27226
|
async start(port = DEV_SERVER_PORT) {
|
|
@@ -26083,15 +27251,15 @@ var DevServer = class _DevServer {
|
|
|
26083
27251
|
this.json(res, 500, { error: e.message });
|
|
26084
27252
|
}
|
|
26085
27253
|
});
|
|
26086
|
-
return new Promise((
|
|
27254
|
+
return new Promise((resolve15, reject) => {
|
|
26087
27255
|
this.server.listen(port, "127.0.0.1", () => {
|
|
26088
27256
|
this.log(`Dev server listening on http://127.0.0.1:${port}`);
|
|
26089
|
-
|
|
27257
|
+
resolve15();
|
|
26090
27258
|
});
|
|
26091
27259
|
this.server.on("error", (e) => {
|
|
26092
27260
|
if (e.code === "EADDRINUSE") {
|
|
26093
27261
|
this.log(`Port ${port} in use, skipping dev server`);
|
|
26094
|
-
|
|
27262
|
+
resolve15();
|
|
26095
27263
|
} else {
|
|
26096
27264
|
reject(e);
|
|
26097
27265
|
}
|
|
@@ -26173,20 +27341,20 @@ var DevServer = class _DevServer {
|
|
|
26173
27341
|
child.stderr?.on("data", (d) => {
|
|
26174
27342
|
stderr += d.toString().slice(0, 2e3);
|
|
26175
27343
|
});
|
|
26176
|
-
await new Promise((
|
|
27344
|
+
await new Promise((resolve15) => {
|
|
26177
27345
|
const timer = setTimeout(() => {
|
|
26178
27346
|
child.kill();
|
|
26179
|
-
|
|
27347
|
+
resolve15();
|
|
26180
27348
|
}, 3e3);
|
|
26181
27349
|
child.on("exit", () => {
|
|
26182
27350
|
clearTimeout(timer);
|
|
26183
|
-
|
|
27351
|
+
resolve15();
|
|
26184
27352
|
});
|
|
26185
27353
|
child.stdout?.once("data", () => {
|
|
26186
27354
|
setTimeout(() => {
|
|
26187
27355
|
child.kill();
|
|
26188
27356
|
clearTimeout(timer);
|
|
26189
|
-
|
|
27357
|
+
resolve15();
|
|
26190
27358
|
}, 500);
|
|
26191
27359
|
});
|
|
26192
27360
|
});
|
|
@@ -26340,12 +27508,12 @@ var DevServer = class _DevServer {
|
|
|
26340
27508
|
// ─── DevConsole SPA ───
|
|
26341
27509
|
getConsoleDistDir() {
|
|
26342
27510
|
const candidates = [
|
|
26343
|
-
|
|
26344
|
-
|
|
26345
|
-
|
|
27511
|
+
path25.resolve(__dirname, "../../web-devconsole/dist"),
|
|
27512
|
+
path25.resolve(__dirname, "../../../web-devconsole/dist"),
|
|
27513
|
+
path25.join(process.cwd(), "packages/web-devconsole/dist")
|
|
26346
27514
|
];
|
|
26347
27515
|
for (const dir of candidates) {
|
|
26348
|
-
if (fs15.existsSync(
|
|
27516
|
+
if (fs15.existsSync(path25.join(dir, "index.html"))) return dir;
|
|
26349
27517
|
}
|
|
26350
27518
|
return null;
|
|
26351
27519
|
}
|
|
@@ -26355,7 +27523,7 @@ var DevServer = class _DevServer {
|
|
|
26355
27523
|
this.json(res, 500, { error: "DevConsole not found. Run: npm run build -w packages/web-devconsole" });
|
|
26356
27524
|
return;
|
|
26357
27525
|
}
|
|
26358
|
-
const htmlPath =
|
|
27526
|
+
const htmlPath = path25.join(distDir, "index.html");
|
|
26359
27527
|
try {
|
|
26360
27528
|
const html = fs15.readFileSync(htmlPath, "utf-8");
|
|
26361
27529
|
res.writeHead(200, { "Content-Type": "text/html; charset=utf-8" });
|
|
@@ -26380,15 +27548,15 @@ var DevServer = class _DevServer {
|
|
|
26380
27548
|
this.json(res, 404, { error: "Not found" });
|
|
26381
27549
|
return;
|
|
26382
27550
|
}
|
|
26383
|
-
const safePath =
|
|
26384
|
-
const filePath =
|
|
27551
|
+
const safePath = path25.normalize(pathname).replace(/^\.\.\//, "");
|
|
27552
|
+
const filePath = path25.join(distDir, safePath);
|
|
26385
27553
|
if (!filePath.startsWith(distDir)) {
|
|
26386
27554
|
this.json(res, 403, { error: "Forbidden" });
|
|
26387
27555
|
return;
|
|
26388
27556
|
}
|
|
26389
27557
|
try {
|
|
26390
27558
|
const content = fs15.readFileSync(filePath);
|
|
26391
|
-
const ext =
|
|
27559
|
+
const ext = path25.extname(filePath);
|
|
26392
27560
|
const contentType = _DevServer.MIME_MAP[ext] || "application/octet-stream";
|
|
26393
27561
|
res.writeHead(200, { "Content-Type": contentType, "Cache-Control": "public, max-age=31536000, immutable" });
|
|
26394
27562
|
res.end(content);
|
|
@@ -26501,10 +27669,10 @@ var DevServer = class _DevServer {
|
|
|
26501
27669
|
const rel = prefix ? `${prefix}/${entry.name}` : entry.name;
|
|
26502
27670
|
if (entry.isDirectory()) {
|
|
26503
27671
|
files.push({ path: rel, size: 0, type: "dir" });
|
|
26504
|
-
scan(
|
|
27672
|
+
scan(path25.join(d, entry.name), rel);
|
|
26505
27673
|
} else {
|
|
26506
|
-
const
|
|
26507
|
-
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" });
|
|
26508
27676
|
}
|
|
26509
27677
|
}
|
|
26510
27678
|
} catch {
|
|
@@ -26526,7 +27694,7 @@ var DevServer = class _DevServer {
|
|
|
26526
27694
|
this.json(res, 404, { error: `Provider directory not found: ${type}` });
|
|
26527
27695
|
return;
|
|
26528
27696
|
}
|
|
26529
|
-
const fullPath =
|
|
27697
|
+
const fullPath = path25.resolve(dir, path25.normalize(filePath));
|
|
26530
27698
|
if (!fullPath.startsWith(dir)) {
|
|
26531
27699
|
this.json(res, 403, { error: "Forbidden" });
|
|
26532
27700
|
return;
|
|
@@ -26551,14 +27719,14 @@ var DevServer = class _DevServer {
|
|
|
26551
27719
|
this.json(res, 404, { error: `Provider directory not found: ${type}` });
|
|
26552
27720
|
return;
|
|
26553
27721
|
}
|
|
26554
|
-
const fullPath =
|
|
27722
|
+
const fullPath = path25.resolve(dir, path25.normalize(filePath));
|
|
26555
27723
|
if (!fullPath.startsWith(dir)) {
|
|
26556
27724
|
this.json(res, 403, { error: "Forbidden" });
|
|
26557
27725
|
return;
|
|
26558
27726
|
}
|
|
26559
27727
|
try {
|
|
26560
27728
|
if (fs15.existsSync(fullPath)) fs15.copyFileSync(fullPath, fullPath + ".bak");
|
|
26561
|
-
fs15.mkdirSync(
|
|
27729
|
+
fs15.mkdirSync(path25.dirname(fullPath), { recursive: true });
|
|
26562
27730
|
fs15.writeFileSync(fullPath, content, "utf-8");
|
|
26563
27731
|
this.log(`File saved: ${fullPath} (${content.length} chars)`);
|
|
26564
27732
|
this.providerLoader.reload();
|
|
@@ -26575,7 +27743,7 @@ var DevServer = class _DevServer {
|
|
|
26575
27743
|
return;
|
|
26576
27744
|
}
|
|
26577
27745
|
for (const name of ["scripts.js", "provider.json"]) {
|
|
26578
|
-
const p =
|
|
27746
|
+
const p = path25.join(dir, name);
|
|
26579
27747
|
if (fs15.existsSync(p)) {
|
|
26580
27748
|
const source = fs15.readFileSync(p, "utf-8");
|
|
26581
27749
|
this.json(res, 200, { type, path: p, source, lines: source.split("\n").length });
|
|
@@ -26596,8 +27764,8 @@ var DevServer = class _DevServer {
|
|
|
26596
27764
|
this.json(res, 404, { error: `Provider not found: ${type}` });
|
|
26597
27765
|
return;
|
|
26598
27766
|
}
|
|
26599
|
-
const target = fs15.existsSync(
|
|
26600
|
-
const targetPath =
|
|
27767
|
+
const target = fs15.existsSync(path25.join(dir, "scripts.js")) ? "scripts.js" : "provider.json";
|
|
27768
|
+
const targetPath = path25.join(dir, target);
|
|
26601
27769
|
try {
|
|
26602
27770
|
if (fs15.existsSync(targetPath)) fs15.copyFileSync(targetPath, targetPath + ".bak");
|
|
26603
27771
|
fs15.writeFileSync(targetPath, source, "utf-8");
|
|
@@ -26689,14 +27857,14 @@ var DevServer = class _DevServer {
|
|
|
26689
27857
|
child.stderr?.on("data", (d) => {
|
|
26690
27858
|
stderr += d.toString();
|
|
26691
27859
|
});
|
|
26692
|
-
await new Promise((
|
|
27860
|
+
await new Promise((resolve15) => {
|
|
26693
27861
|
const timer = setTimeout(() => {
|
|
26694
27862
|
child.kill();
|
|
26695
|
-
|
|
27863
|
+
resolve15();
|
|
26696
27864
|
}, timeout);
|
|
26697
27865
|
child.on("exit", () => {
|
|
26698
27866
|
clearTimeout(timer);
|
|
26699
|
-
|
|
27867
|
+
resolve15();
|
|
26700
27868
|
});
|
|
26701
27869
|
});
|
|
26702
27870
|
const elapsed = Date.now() - start;
|
|
@@ -26744,7 +27912,7 @@ var DevServer = class _DevServer {
|
|
|
26744
27912
|
}
|
|
26745
27913
|
let targetDir;
|
|
26746
27914
|
targetDir = this.providerLoader.getUserProviderDir(category, type);
|
|
26747
|
-
const jsonPath =
|
|
27915
|
+
const jsonPath = path25.join(targetDir, "provider.json");
|
|
26748
27916
|
if (fs15.existsSync(jsonPath)) {
|
|
26749
27917
|
this.json(res, 409, { error: `Provider already exists at ${targetDir}`, path: targetDir });
|
|
26750
27918
|
return;
|
|
@@ -26756,8 +27924,8 @@ var DevServer = class _DevServer {
|
|
|
26756
27924
|
const createdFiles = ["provider.json"];
|
|
26757
27925
|
if (result.files) {
|
|
26758
27926
|
for (const [relPath, content] of Object.entries(result.files)) {
|
|
26759
|
-
const fullPath =
|
|
26760
|
-
fs15.mkdirSync(
|
|
27927
|
+
const fullPath = path25.join(targetDir, relPath);
|
|
27928
|
+
fs15.mkdirSync(path25.dirname(fullPath), { recursive: true });
|
|
26761
27929
|
fs15.writeFileSync(fullPath, content, "utf-8");
|
|
26762
27930
|
createdFiles.push(relPath);
|
|
26763
27931
|
}
|
|
@@ -26810,22 +27978,22 @@ var DevServer = class _DevServer {
|
|
|
26810
27978
|
if (!fs15.existsSync(scriptsDir)) return null;
|
|
26811
27979
|
const versions = fs15.readdirSync(scriptsDir).filter((d) => {
|
|
26812
27980
|
try {
|
|
26813
|
-
return fs15.statSync(
|
|
27981
|
+
return fs15.statSync(path25.join(scriptsDir, d)).isDirectory();
|
|
26814
27982
|
} catch {
|
|
26815
27983
|
return false;
|
|
26816
27984
|
}
|
|
26817
27985
|
}).sort((a, b) => b.localeCompare(a, void 0, { numeric: true, sensitivity: "base" }));
|
|
26818
27986
|
if (versions.length === 0) return null;
|
|
26819
|
-
return
|
|
27987
|
+
return path25.join(scriptsDir, versions[0]);
|
|
26820
27988
|
}
|
|
26821
27989
|
resolveAutoImplWritableProviderDir(category, type, requestedDir) {
|
|
26822
|
-
const canonicalUserDir =
|
|
26823
|
-
const desiredDir = requestedDir ?
|
|
26824
|
-
const upstreamRoot =
|
|
26825
|
-
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}`)) {
|
|
26826
27994
|
return { dir: null, reason: `Refusing to write into upstream provider directory: ${desiredDir}` };
|
|
26827
27995
|
}
|
|
26828
|
-
if (
|
|
27996
|
+
if (path25.basename(desiredDir) !== type) {
|
|
26829
27997
|
return { dir: null, reason: `Requested writable provider directory must end with '${type}': ${desiredDir}` };
|
|
26830
27998
|
}
|
|
26831
27999
|
const sourceDir = this.findProviderDir(type);
|
|
@@ -26833,11 +28001,11 @@ var DevServer = class _DevServer {
|
|
|
26833
28001
|
return { dir: null, reason: `Provider source directory not found for '${type}'` };
|
|
26834
28002
|
}
|
|
26835
28003
|
if (!fs15.existsSync(desiredDir)) {
|
|
26836
|
-
fs15.mkdirSync(
|
|
28004
|
+
fs15.mkdirSync(path25.dirname(desiredDir), { recursive: true });
|
|
26837
28005
|
fs15.cpSync(sourceDir, desiredDir, { recursive: true });
|
|
26838
28006
|
this.log(`Auto-implement writable copy created: ${desiredDir}`);
|
|
26839
28007
|
}
|
|
26840
|
-
const providerJson =
|
|
28008
|
+
const providerJson = path25.join(desiredDir, "provider.json");
|
|
26841
28009
|
if (!fs15.existsSync(providerJson)) {
|
|
26842
28010
|
return { dir: null, reason: `provider.json not found in writable provider directory: ${desiredDir}` };
|
|
26843
28011
|
}
|
|
@@ -26873,7 +28041,7 @@ var DevServer = class _DevServer {
|
|
|
26873
28041
|
setMode: "set_mode.js"
|
|
26874
28042
|
};
|
|
26875
28043
|
const targetFileNames = new Set(functions.map((fn) => funcToFile[fn]).filter(Boolean));
|
|
26876
|
-
const scriptsDir =
|
|
28044
|
+
const scriptsDir = path25.join(providerDir, "scripts");
|
|
26877
28045
|
const latestScriptsDir = this.getLatestScriptVersionDir(scriptsDir);
|
|
26878
28046
|
if (latestScriptsDir) {
|
|
26879
28047
|
lines.push(`Scripts version directory: \`${latestScriptsDir}\``);
|
|
@@ -26884,7 +28052,7 @@ var DevServer = class _DevServer {
|
|
|
26884
28052
|
for (const file of fs15.readdirSync(latestScriptsDir)) {
|
|
26885
28053
|
if (file.endsWith(".js") && targetFileNames.has(file)) {
|
|
26886
28054
|
try {
|
|
26887
|
-
const content = fs15.readFileSync(
|
|
28055
|
+
const content = fs15.readFileSync(path25.join(latestScriptsDir, file), "utf-8");
|
|
26888
28056
|
lines.push(`### \`${file}\` \u270F\uFE0F EDIT`);
|
|
26889
28057
|
lines.push("```javascript");
|
|
26890
28058
|
lines.push(content);
|
|
@@ -26901,7 +28069,7 @@ var DevServer = class _DevServer {
|
|
|
26901
28069
|
lines.push("");
|
|
26902
28070
|
for (const file of refFiles) {
|
|
26903
28071
|
try {
|
|
26904
|
-
const content = fs15.readFileSync(
|
|
28072
|
+
const content = fs15.readFileSync(path25.join(latestScriptsDir, file), "utf-8");
|
|
26905
28073
|
lines.push(`### \`${file}\` \u{1F512}`);
|
|
26906
28074
|
lines.push("```javascript");
|
|
26907
28075
|
lines.push(content);
|
|
@@ -26942,10 +28110,10 @@ var DevServer = class _DevServer {
|
|
|
26942
28110
|
lines.push("");
|
|
26943
28111
|
}
|
|
26944
28112
|
}
|
|
26945
|
-
const docsDir =
|
|
28113
|
+
const docsDir = path25.join(providerDir, "../../docs");
|
|
26946
28114
|
const loadGuide = (name) => {
|
|
26947
28115
|
try {
|
|
26948
|
-
const p =
|
|
28116
|
+
const p = path25.join(docsDir, name);
|
|
26949
28117
|
if (fs15.existsSync(p)) return fs15.readFileSync(p, "utf-8");
|
|
26950
28118
|
} catch {
|
|
26951
28119
|
}
|
|
@@ -27119,7 +28287,7 @@ var DevServer = class _DevServer {
|
|
|
27119
28287
|
parseApproval: "parse_approval.js"
|
|
27120
28288
|
};
|
|
27121
28289
|
const targetFileNames = new Set(functions.map((fn) => funcToFile[fn]).filter(Boolean));
|
|
27122
|
-
const scriptsDir =
|
|
28290
|
+
const scriptsDir = path25.join(providerDir, "scripts");
|
|
27123
28291
|
const latestScriptsDir = this.getLatestScriptVersionDir(scriptsDir);
|
|
27124
28292
|
if (latestScriptsDir) {
|
|
27125
28293
|
lines.push(`Scripts version directory: \`${latestScriptsDir}\``);
|
|
@@ -27131,7 +28299,7 @@ var DevServer = class _DevServer {
|
|
|
27131
28299
|
if (!file.endsWith(".js")) continue;
|
|
27132
28300
|
if (!targetFileNames.has(file)) continue;
|
|
27133
28301
|
try {
|
|
27134
|
-
const content = fs15.readFileSync(
|
|
28302
|
+
const content = fs15.readFileSync(path25.join(latestScriptsDir, file), "utf-8");
|
|
27135
28303
|
lines.push(`### \`${file}\` \u270F\uFE0F EDIT`);
|
|
27136
28304
|
lines.push("```javascript");
|
|
27137
28305
|
lines.push(content);
|
|
@@ -27147,7 +28315,7 @@ var DevServer = class _DevServer {
|
|
|
27147
28315
|
lines.push("");
|
|
27148
28316
|
for (const file of refFiles) {
|
|
27149
28317
|
try {
|
|
27150
|
-
const content = fs15.readFileSync(
|
|
28318
|
+
const content = fs15.readFileSync(path25.join(latestScriptsDir, file), "utf-8");
|
|
27151
28319
|
lines.push(`### \`${file}\` \u{1F512}`);
|
|
27152
28320
|
lines.push("```javascript");
|
|
27153
28321
|
lines.push(content);
|
|
@@ -27180,10 +28348,10 @@ var DevServer = class _DevServer {
|
|
|
27180
28348
|
lines.push("");
|
|
27181
28349
|
}
|
|
27182
28350
|
}
|
|
27183
|
-
const docsDir =
|
|
28351
|
+
const docsDir = path25.join(providerDir, "../../docs");
|
|
27184
28352
|
const loadGuide = (name) => {
|
|
27185
28353
|
try {
|
|
27186
|
-
const p =
|
|
28354
|
+
const p = path25.join(docsDir, name);
|
|
27187
28355
|
if (fs15.existsSync(p)) return fs15.readFileSync(p, "utf-8");
|
|
27188
28356
|
} catch {
|
|
27189
28357
|
}
|
|
@@ -27366,14 +28534,14 @@ data: ${JSON.stringify(msg.data)}
|
|
|
27366
28534
|
res.end(JSON.stringify(data, null, 2));
|
|
27367
28535
|
}
|
|
27368
28536
|
async readBody(req) {
|
|
27369
|
-
return new Promise((
|
|
28537
|
+
return new Promise((resolve15) => {
|
|
27370
28538
|
let body = "";
|
|
27371
28539
|
req.on("data", (chunk) => body += chunk);
|
|
27372
28540
|
req.on("end", () => {
|
|
27373
28541
|
try {
|
|
27374
|
-
|
|
28542
|
+
resolve15(JSON.parse(body));
|
|
27375
28543
|
} catch {
|
|
27376
|
-
|
|
28544
|
+
resolve15({});
|
|
27377
28545
|
}
|
|
27378
28546
|
});
|
|
27379
28547
|
});
|
|
@@ -27883,7 +29051,7 @@ async function waitForReady(endpoint, timeoutMs = STARTUP_TIMEOUT_MS) {
|
|
|
27883
29051
|
const deadline = Date.now() + timeoutMs;
|
|
27884
29052
|
while (Date.now() < deadline) {
|
|
27885
29053
|
if (await canConnect(endpoint)) return;
|
|
27886
|
-
await new Promise((
|
|
29054
|
+
await new Promise((resolve15) => setTimeout(resolve15, STARTUP_POLL_MS));
|
|
27887
29055
|
}
|
|
27888
29056
|
throw new Error(`Session host did not become ready within ${timeoutMs}ms`);
|
|
27889
29057
|
}
|
|
@@ -28061,10 +29229,10 @@ async function installExtension(ide, extension) {
|
|
|
28061
29229
|
const buffer = Buffer.from(await res.arrayBuffer());
|
|
28062
29230
|
const fs16 = await import("fs");
|
|
28063
29231
|
fs16.writeFileSync(vsixPath, buffer);
|
|
28064
|
-
return new Promise((
|
|
29232
|
+
return new Promise((resolve15) => {
|
|
28065
29233
|
const cmd = `"${ide.cliCommand}" --install-extension "${vsixPath}" --force`;
|
|
28066
29234
|
(0, import_child_process11.exec)(cmd, { timeout: 6e4 }, (error, _stdout, stderr) => {
|
|
28067
|
-
|
|
29235
|
+
resolve15({
|
|
28068
29236
|
extensionId: extension.id,
|
|
28069
29237
|
marketplaceId: extension.marketplaceId,
|
|
28070
29238
|
success: !error,
|
|
@@ -28077,11 +29245,11 @@ async function installExtension(ide, extension) {
|
|
|
28077
29245
|
} catch (e) {
|
|
28078
29246
|
}
|
|
28079
29247
|
}
|
|
28080
|
-
return new Promise((
|
|
29248
|
+
return new Promise((resolve15) => {
|
|
28081
29249
|
const cmd = `"${ide.cliCommand}" --install-extension ${extension.marketplaceId} --force`;
|
|
28082
29250
|
(0, import_child_process11.exec)(cmd, { timeout: 6e4 }, (error, stdout, stderr) => {
|
|
28083
29251
|
if (error) {
|
|
28084
|
-
|
|
29252
|
+
resolve15({
|
|
28085
29253
|
extensionId: extension.id,
|
|
28086
29254
|
marketplaceId: extension.marketplaceId,
|
|
28087
29255
|
success: false,
|
|
@@ -28089,7 +29257,7 @@ async function installExtension(ide, extension) {
|
|
|
28089
29257
|
error: stderr || error.message
|
|
28090
29258
|
});
|
|
28091
29259
|
} else {
|
|
28092
|
-
|
|
29260
|
+
resolve15({
|
|
28093
29261
|
extensionId: extension.id,
|
|
28094
29262
|
marketplaceId: extension.marketplaceId,
|
|
28095
29263
|
success: true,
|
|
@@ -28419,6 +29587,7 @@ async function shutdownDaemonComponents(components) {
|
|
|
28419
29587
|
DEFAULT_CDP_SCAN_INTERVAL_MS,
|
|
28420
29588
|
DEFAULT_CHAT_TAIL_RECENT_MESSAGE_GRACE_MS,
|
|
28421
29589
|
DEFAULT_DAEMON_PORT,
|
|
29590
|
+
DEFAULT_GIT_WORKSPACE_POLL_INTERVAL_MS,
|
|
28422
29591
|
DEFAULT_MACHINE_RUNTIME_SUBSCRIPTION_INTERVAL_MS,
|
|
28423
29592
|
DEFAULT_SESSION_HOST_APP_NAME,
|
|
28424
29593
|
DEFAULT_SESSION_HOST_DIAGNOSTICS_SUBSCRIPTION_INTERVAL_MS,
|
|
@@ -28437,8 +29606,12 @@ async function shutdownDaemonComponents(components) {
|
|
|
28437
29606
|
DaemonCommandRouter,
|
|
28438
29607
|
DaemonStatusReporter,
|
|
28439
29608
|
DevServer,
|
|
29609
|
+
GitCommandError,
|
|
29610
|
+
GitWorkspaceMonitor,
|
|
28440
29611
|
IdeProviderInstance,
|
|
29612
|
+
InMemoryGitSnapshotStore,
|
|
28441
29613
|
LOG,
|
|
29614
|
+
MIN_GIT_WORKSPACE_POLL_INTERVAL_MS,
|
|
28442
29615
|
MIN_MACHINE_RUNTIME_SUBSCRIPTION_INTERVAL_MS,
|
|
28443
29616
|
MIN_SESSION_HOST_DIAGNOSTICS_SUBSCRIPTION_INTERVAL_MS,
|
|
28444
29617
|
NodePtyTransportFactory,
|
|
@@ -28466,9 +29639,14 @@ async function shutdownDaemonComponents(components) {
|
|
|
28466
29639
|
buildUserChatMessage,
|
|
28467
29640
|
classifyHotChatSessionsForSubscriptionFlush,
|
|
28468
29641
|
clearDebugTrace,
|
|
29642
|
+
compareGitSnapshots,
|
|
28469
29643
|
configureDebugTraceStore,
|
|
28470
29644
|
connectCdpManager,
|
|
28471
29645
|
createDebugTraceStore,
|
|
29646
|
+
createDefaultGitCommandServices,
|
|
29647
|
+
createGitCompactSummary,
|
|
29648
|
+
createGitSnapshotStore,
|
|
29649
|
+
createGitWorkspaceMonitor,
|
|
28472
29650
|
createInteractionId,
|
|
28473
29651
|
detectAllVersions,
|
|
28474
29652
|
detectCLIs,
|
|
@@ -28483,6 +29661,9 @@ async function shutdownDaemonComponents(components) {
|
|
|
28483
29661
|
getCurrentDaemonLogPath,
|
|
28484
29662
|
getDaemonLogDir,
|
|
28485
29663
|
getDebugRuntimeConfig,
|
|
29664
|
+
getGitDiffSummary,
|
|
29665
|
+
getGitFileDiff,
|
|
29666
|
+
getGitRepoStatus,
|
|
28486
29667
|
getHostMemorySnapshot,
|
|
28487
29668
|
getLogLevel,
|
|
28488
29669
|
getNpmExecOptions,
|
|
@@ -28494,6 +29675,7 @@ async function shutdownDaemonComponents(components) {
|
|
|
28494
29675
|
getSessionHostRecoveryLabel,
|
|
28495
29676
|
getSessionHostSurfaceKind,
|
|
28496
29677
|
getWorkspaceState,
|
|
29678
|
+
handleGitCommand,
|
|
28497
29679
|
hasCdpManager,
|
|
28498
29680
|
hashSignatureParts,
|
|
28499
29681
|
initDaemonComponents,
|
|
@@ -28502,9 +29684,11 @@ async function shutdownDaemonComponents(components) {
|
|
|
28502
29684
|
isBuiltinChatMessageKind,
|
|
28503
29685
|
isCdpConnected,
|
|
28504
29686
|
isExtensionInstalled,
|
|
29687
|
+
isGitCommandName,
|
|
28505
29688
|
isIdeRunning,
|
|
28506
29689
|
isManagedStatusWaiting,
|
|
28507
29690
|
isManagedStatusWorking,
|
|
29691
|
+
isPathInside,
|
|
28508
29692
|
isSessionHostLiveRuntime,
|
|
28509
29693
|
isSessionHostRecoverySnapshot,
|
|
28510
29694
|
isSetupComplete,
|
|
@@ -28522,10 +29706,13 @@ async function shutdownDaemonComponents(components) {
|
|
|
28522
29706
|
normalizeChatMessageKind,
|
|
28523
29707
|
normalizeChatMessages,
|
|
28524
29708
|
normalizeChatTailActiveModal,
|
|
29709
|
+
normalizeGitOutput,
|
|
29710
|
+
normalizeGitWorkspaceSubscriptionParams,
|
|
28525
29711
|
normalizeInputEnvelope,
|
|
28526
29712
|
normalizeManagedStatus,
|
|
28527
29713
|
normalizeMessageParts,
|
|
28528
29714
|
normalizeSessionModalFields,
|
|
29715
|
+
parsePorcelainV2Status,
|
|
28529
29716
|
parseProviderSourceConfigUpdate,
|
|
28530
29717
|
partitionSessionHostDiagnosticsSessions,
|
|
28531
29718
|
partitionSessionHostRecords,
|
|
@@ -28541,9 +29728,11 @@ async function shutdownDaemonComponents(components) {
|
|
|
28541
29728
|
resolveChatMessageKind,
|
|
28542
29729
|
resolveCurrentGlobalInstallSurface,
|
|
28543
29730
|
resolveDebugRuntimeConfig,
|
|
29731
|
+
resolveGitRepository,
|
|
28544
29732
|
resolveSessionHostAppName,
|
|
28545
29733
|
resolveSessionHostAppNameResolution,
|
|
28546
29734
|
runAsyncBatch,
|
|
29735
|
+
runGit,
|
|
28547
29736
|
saveConfig,
|
|
28548
29737
|
saveState,
|
|
28549
29738
|
setDebugRuntimeConfig,
|
|
@@ -28554,6 +29743,7 @@ async function shutdownDaemonComponents(components) {
|
|
|
28554
29743
|
shutdownDaemonComponents,
|
|
28555
29744
|
spawnDetachedDaemonUpgradeHelper,
|
|
28556
29745
|
startDaemonDevSupport,
|
|
29746
|
+
summarizeGitStatus,
|
|
28557
29747
|
updateConfig,
|
|
28558
29748
|
upsertSavedProviderSession
|
|
28559
29749
|
});
|