@agenticmail/core 0.5.3 → 0.5.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +31 -12
- package/dist/index.js +200 -48
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -1412,22 +1412,41 @@ declare class DependencyChecker {
|
|
|
1412
1412
|
type InstallProgress = (message: string) => void;
|
|
1413
1413
|
/**
|
|
1414
1414
|
* DependencyInstaller handles installing all external dependencies.
|
|
1415
|
-
* Everything is auto-installed — no optional deps.
|
|
1415
|
+
* Everything is auto-installed — no optional deps, no manual steps.
|
|
1416
1416
|
*/
|
|
1417
1417
|
declare class DependencyInstaller {
|
|
1418
1418
|
private onProgress;
|
|
1419
1419
|
constructor(onProgress?: InstallProgress);
|
|
1420
1420
|
/**
|
|
1421
1421
|
* Ensure Docker is installed AND the daemon is running.
|
|
1422
|
-
*
|
|
1423
|
-
*
|
|
1424
|
-
*
|
|
1422
|
+
* Fully automatic — installs, accepts license, starts daemon, waits for ready.
|
|
1423
|
+
* Never asks the user to do anything manually.
|
|
1424
|
+
*
|
|
1425
|
+
* Flow:
|
|
1426
|
+
* 1. docker CLI + daemon running? → done
|
|
1427
|
+
* 2. docker CLI exists but daemon stopped? → start daemon, wait
|
|
1428
|
+
* 3. Docker.app exists (in /Applications or Caskroom)? → run installer --accept-license, start, wait
|
|
1429
|
+
* 4. Nothing installed? → install via Homebrew or DMG download, then start, wait
|
|
1425
1430
|
*/
|
|
1426
1431
|
installDocker(): Promise<void>;
|
|
1432
|
+
/** Check if `docker info` succeeds (CLI + daemon both working). */
|
|
1433
|
+
private isDockerReady;
|
|
1434
|
+
/** Check if `docker` CLI is in PATH (daemon may be stopped). */
|
|
1435
|
+
private isDockerCliInstalled;
|
|
1436
|
+
/**
|
|
1437
|
+
* Find Docker.app on macOS.
|
|
1438
|
+
* Checks /Applications first, then Homebrew Caskroom.
|
|
1439
|
+
* Validates symlinks aren't broken.
|
|
1440
|
+
*/
|
|
1441
|
+
private findDockerApp;
|
|
1442
|
+
/**
|
|
1443
|
+
* Docker.app exists but CLI isn't available.
|
|
1444
|
+
* Run the built-in installer (--accept-license), start Docker Desktop, wait.
|
|
1445
|
+
*/
|
|
1446
|
+
private setupExistingDockerApp;
|
|
1427
1447
|
/**
|
|
1428
|
-
*
|
|
1429
|
-
*
|
|
1430
|
-
* This is Docker's recommended command-line installation method.
|
|
1448
|
+
* Full Docker Desktop install on macOS.
|
|
1449
|
+
* Tries Homebrew first (cleaner, handles updates), falls back to DMG download.
|
|
1431
1450
|
*/
|
|
1432
1451
|
private installDockerMac;
|
|
1433
1452
|
/**
|
|
@@ -1436,14 +1455,14 @@ declare class DependencyInstaller {
|
|
|
1436
1455
|
*/
|
|
1437
1456
|
private installDockerLinux;
|
|
1438
1457
|
/**
|
|
1439
|
-
*
|
|
1440
|
-
* On macOS: tries Docker Desktop app
|
|
1441
|
-
* On Linux: tries systemctl,
|
|
1458
|
+
* Start the Docker daemon using multiple strategies.
|
|
1459
|
+
* On macOS: tries Docker Desktop app via `open`, direct binary launch, etc.
|
|
1460
|
+
* On Linux: tries systemctl, service, snap.
|
|
1442
1461
|
*/
|
|
1443
1462
|
private startDockerDaemon;
|
|
1444
1463
|
/**
|
|
1445
|
-
* Wait for Docker daemon to be ready
|
|
1446
|
-
*
|
|
1464
|
+
* Wait for Docker daemon to be ready.
|
|
1465
|
+
* Cycles through multiple start strategies automatically.
|
|
1447
1466
|
* Reports progress as a percentage (0-100).
|
|
1448
1467
|
*/
|
|
1449
1468
|
private waitForDocker;
|
package/dist/index.js
CHANGED
|
@@ -5894,7 +5894,7 @@ var DependencyChecker = class {
|
|
|
5894
5894
|
|
|
5895
5895
|
// src/setup/installer.ts
|
|
5896
5896
|
import { execFileSync as execFileSync2, execSync, spawn as spawnChild } from "child_process";
|
|
5897
|
-
import { existsSync as existsSync4 } from "fs";
|
|
5897
|
+
import { existsSync as existsSync4, readdirSync, lstatSync, readlinkSync } from "fs";
|
|
5898
5898
|
import { writeFile, rename, chmod as chmod2, mkdir as mkdir2, unlink } from "fs/promises";
|
|
5899
5899
|
import { join as join6 } from "path";
|
|
5900
5900
|
import { homedir as homedir5, platform as platform2, arch as arch2 } from "os";
|
|
@@ -6016,6 +6016,31 @@ function runShellWithRollingOutput(cmd, opts = {}) {
|
|
|
6016
6016
|
});
|
|
6017
6017
|
});
|
|
6018
6018
|
}
|
|
6019
|
+
function existsReal(p) {
|
|
6020
|
+
try {
|
|
6021
|
+
const stat = lstatSync(p);
|
|
6022
|
+
if (stat.isSymbolicLink()) {
|
|
6023
|
+
try {
|
|
6024
|
+
const target = readlinkSync(p);
|
|
6025
|
+
const resolved = target.startsWith("/") ? target : join6(p, "..", target);
|
|
6026
|
+
return existsSync4(resolved);
|
|
6027
|
+
} catch {
|
|
6028
|
+
return false;
|
|
6029
|
+
}
|
|
6030
|
+
}
|
|
6031
|
+
return true;
|
|
6032
|
+
} catch {
|
|
6033
|
+
return false;
|
|
6034
|
+
}
|
|
6035
|
+
}
|
|
6036
|
+
function hasHomebrew() {
|
|
6037
|
+
try {
|
|
6038
|
+
execFileSync2("brew", ["--version"], { timeout: 5e3, stdio: "ignore" });
|
|
6039
|
+
return true;
|
|
6040
|
+
} catch {
|
|
6041
|
+
return false;
|
|
6042
|
+
}
|
|
6043
|
+
}
|
|
6019
6044
|
var DependencyInstaller = class {
|
|
6020
6045
|
onProgress;
|
|
6021
6046
|
constructor(onProgress) {
|
|
@@ -6024,27 +6049,28 @@ var DependencyInstaller = class {
|
|
|
6024
6049
|
}
|
|
6025
6050
|
/**
|
|
6026
6051
|
* Ensure Docker is installed AND the daemon is running.
|
|
6027
|
-
*
|
|
6028
|
-
*
|
|
6029
|
-
*
|
|
6052
|
+
* Fully automatic — installs, accepts license, starts daemon, waits for ready.
|
|
6053
|
+
* Never asks the user to do anything manually.
|
|
6054
|
+
*
|
|
6055
|
+
* Flow:
|
|
6056
|
+
* 1. docker CLI + daemon running? → done
|
|
6057
|
+
* 2. docker CLI exists but daemon stopped? → start daemon, wait
|
|
6058
|
+
* 3. Docker.app exists (in /Applications or Caskroom)? → run installer --accept-license, start, wait
|
|
6059
|
+
* 4. Nothing installed? → install via Homebrew or DMG download, then start, wait
|
|
6030
6060
|
*/
|
|
6031
6061
|
async installDocker() {
|
|
6032
|
-
|
|
6033
|
-
|
|
6034
|
-
|
|
6035
|
-
|
|
6036
|
-
|
|
6062
|
+
if (this.isDockerReady()) return;
|
|
6063
|
+
if (this.isDockerCliInstalled()) {
|
|
6064
|
+
this.onProgress("__progress__:10:Docker installed \u2014 starting the engine...");
|
|
6065
|
+
this.startDockerDaemon();
|
|
6066
|
+
await this.waitForDocker();
|
|
6067
|
+
return;
|
|
6037
6068
|
}
|
|
6038
|
-
|
|
6039
|
-
|
|
6040
|
-
|
|
6041
|
-
|
|
6042
|
-
|
|
6043
|
-
this.onProgress("Docker found but not running \u2014 starting it now...");
|
|
6044
|
-
this.startDockerDaemon();
|
|
6045
|
-
await this.waitForDocker();
|
|
6046
|
-
return;
|
|
6047
|
-
}
|
|
6069
|
+
const dockerApp = this.findDockerApp();
|
|
6070
|
+
if (dockerApp) {
|
|
6071
|
+
this.onProgress("__progress__:10:Docker Desktop found \u2014 setting it up...");
|
|
6072
|
+
await this.setupExistingDockerApp(dockerApp);
|
|
6073
|
+
return;
|
|
6048
6074
|
}
|
|
6049
6075
|
const os = platform2();
|
|
6050
6076
|
if (os === "darwin") {
|
|
@@ -6052,15 +6078,102 @@ var DependencyInstaller = class {
|
|
|
6052
6078
|
} else if (os === "linux") {
|
|
6053
6079
|
await this.installDockerLinux();
|
|
6054
6080
|
} else {
|
|
6055
|
-
throw new Error(
|
|
6081
|
+
throw new Error(
|
|
6082
|
+
`Docker auto-install isn't supported on ${os} yet. Install it from https://docs.docker.com/get-docker/ and try again.`
|
|
6083
|
+
);
|
|
6084
|
+
}
|
|
6085
|
+
}
|
|
6086
|
+
/** Check if `docker info` succeeds (CLI + daemon both working). */
|
|
6087
|
+
isDockerReady() {
|
|
6088
|
+
try {
|
|
6089
|
+
execFileSync2("docker", ["info"], { timeout: 1e4, stdio: "ignore" });
|
|
6090
|
+
return true;
|
|
6091
|
+
} catch {
|
|
6092
|
+
return false;
|
|
6056
6093
|
}
|
|
6057
6094
|
}
|
|
6095
|
+
/** Check if `docker` CLI is in PATH (daemon may be stopped). */
|
|
6096
|
+
isDockerCliInstalled() {
|
|
6097
|
+
try {
|
|
6098
|
+
execFileSync2("docker", ["--version"], { timeout: 5e3, stdio: "ignore" });
|
|
6099
|
+
return true;
|
|
6100
|
+
} catch {
|
|
6101
|
+
return false;
|
|
6102
|
+
}
|
|
6103
|
+
}
|
|
6104
|
+
/**
|
|
6105
|
+
* Find Docker.app on macOS.
|
|
6106
|
+
* Checks /Applications first, then Homebrew Caskroom.
|
|
6107
|
+
* Validates symlinks aren't broken.
|
|
6108
|
+
*/
|
|
6109
|
+
findDockerApp() {
|
|
6110
|
+
if (existsReal("/Applications/Docker.app")) {
|
|
6111
|
+
return "/Applications/Docker.app";
|
|
6112
|
+
}
|
|
6113
|
+
const caskroomBases = [
|
|
6114
|
+
"/opt/homebrew/Caskroom",
|
|
6115
|
+
"/usr/local/Caskroom"
|
|
6116
|
+
];
|
|
6117
|
+
const caskNames = ["docker-desktop", "docker"];
|
|
6118
|
+
for (const base of caskroomBases) {
|
|
6119
|
+
for (const name of caskNames) {
|
|
6120
|
+
const caskroom = join6(base, name);
|
|
6121
|
+
if (!existsSync4(caskroom)) continue;
|
|
6122
|
+
try {
|
|
6123
|
+
const versions = readdirSync(caskroom).filter((d) => !d.startsWith("."));
|
|
6124
|
+
for (const ver of versions) {
|
|
6125
|
+
const appPath = join6(caskroom, ver, "Docker.app");
|
|
6126
|
+
if (existsReal(appPath)) return appPath;
|
|
6127
|
+
}
|
|
6128
|
+
} catch {
|
|
6129
|
+
}
|
|
6130
|
+
}
|
|
6131
|
+
}
|
|
6132
|
+
return null;
|
|
6133
|
+
}
|
|
6058
6134
|
/**
|
|
6059
|
-
*
|
|
6060
|
-
*
|
|
6061
|
-
|
|
6135
|
+
* Docker.app exists but CLI isn't available.
|
|
6136
|
+
* Run the built-in installer (--accept-license), start Docker Desktop, wait.
|
|
6137
|
+
*/
|
|
6138
|
+
async setupExistingDockerApp(appPath) {
|
|
6139
|
+
const installBin = join6(appPath, "Contents", "MacOS", "install");
|
|
6140
|
+
if (existsSync4(installBin)) {
|
|
6141
|
+
this.onProgress("__progress__:20:Installing Docker CLI tools...");
|
|
6142
|
+
const user = process.env.USER || execSync("whoami", { timeout: 5e3 }).toString().trim();
|
|
6143
|
+
try {
|
|
6144
|
+
await runWithRollingOutput(installBin, ["--accept-license", `--user=${user}`], {
|
|
6145
|
+
timeout: 12e4
|
|
6146
|
+
});
|
|
6147
|
+
} catch {
|
|
6148
|
+
}
|
|
6149
|
+
}
|
|
6150
|
+
this.onProgress("__progress__:40:Starting Docker Desktop...");
|
|
6151
|
+
this.startDockerDaemon();
|
|
6152
|
+
await this.waitForDocker();
|
|
6153
|
+
}
|
|
6154
|
+
/**
|
|
6155
|
+
* Full Docker Desktop install on macOS.
|
|
6156
|
+
* Tries Homebrew first (cleaner, handles updates), falls back to DMG download.
|
|
6062
6157
|
*/
|
|
6063
6158
|
async installDockerMac() {
|
|
6159
|
+
if (hasHomebrew()) {
|
|
6160
|
+
this.onProgress("__progress__:5:Installing Docker Desktop via Homebrew...");
|
|
6161
|
+
const brewResult = await runWithRollingOutput(
|
|
6162
|
+
"brew",
|
|
6163
|
+
["install", "--cask", "docker"],
|
|
6164
|
+
{ timeout: 6e5 }
|
|
6165
|
+
// can be slow on first install
|
|
6166
|
+
);
|
|
6167
|
+
if (brewResult.exitCode === 0) {
|
|
6168
|
+
this.onProgress("__progress__:50:Docker Desktop installed!");
|
|
6169
|
+
const appPath = this.findDockerApp();
|
|
6170
|
+
if (appPath) {
|
|
6171
|
+
await this.setupExistingDockerApp(appPath);
|
|
6172
|
+
return;
|
|
6173
|
+
}
|
|
6174
|
+
}
|
|
6175
|
+
this.onProgress("__progress__:10:Homebrew install didn't work, downloading directly...");
|
|
6176
|
+
}
|
|
6064
6177
|
const cpu = arch2();
|
|
6065
6178
|
const archName = cpu === "arm64" ? "arm64" : "amd64";
|
|
6066
6179
|
const dmgUrl = `https://desktop.docker.com/mac/main/${archName}/Docker.dmg`;
|
|
@@ -6094,18 +6207,16 @@ var DependencyInstaller = class {
|
|
|
6094
6207
|
["--accept-license", `--user=${user}`],
|
|
6095
6208
|
{ timeout: 12e4 }
|
|
6096
6209
|
);
|
|
6097
|
-
if (installResult.exitCode !== 0) {
|
|
6098
|
-
|
|
6099
|
-
throw new Error("Installer exited with errors");
|
|
6100
|
-
}
|
|
6210
|
+
if (installResult.exitCode !== 0 && !existsSync4("/Applications/Docker.app")) {
|
|
6211
|
+
throw new Error("Installer exited with errors");
|
|
6101
6212
|
}
|
|
6102
|
-
} catch
|
|
6213
|
+
} catch {
|
|
6103
6214
|
if (!existsSync4("/Applications/Docker.app")) {
|
|
6104
6215
|
this.onProgress("__progress__:60:Trying alternative install method...");
|
|
6105
6216
|
try {
|
|
6106
6217
|
execSync('cp -R "/Volumes/Docker/Docker.app" /Applications/', { timeout: 6e4, stdio: "ignore" });
|
|
6107
6218
|
} catch {
|
|
6108
|
-
throw new Error("Failed to install Docker Desktop.
|
|
6219
|
+
throw new Error("Failed to install Docker Desktop. You may need to run this with admin privileges.");
|
|
6109
6220
|
}
|
|
6110
6221
|
}
|
|
6111
6222
|
}
|
|
@@ -6117,9 +6228,14 @@ var DependencyInstaller = class {
|
|
|
6117
6228
|
await unlink(dmgPath);
|
|
6118
6229
|
} catch {
|
|
6119
6230
|
}
|
|
6120
|
-
this.
|
|
6121
|
-
|
|
6122
|
-
|
|
6231
|
+
const installed = this.findDockerApp();
|
|
6232
|
+
if (installed) {
|
|
6233
|
+
await this.setupExistingDockerApp(installed);
|
|
6234
|
+
} else {
|
|
6235
|
+
this.onProgress("__progress__:70:Starting Docker Desktop...");
|
|
6236
|
+
this.startDockerDaemon();
|
|
6237
|
+
await this.waitForDocker();
|
|
6238
|
+
}
|
|
6123
6239
|
}
|
|
6124
6240
|
/**
|
|
6125
6241
|
* Install Docker Engine on Linux using Docker's official convenience script.
|
|
@@ -6160,13 +6276,14 @@ var DependencyInstaller = class {
|
|
|
6160
6276
|
await this.waitForDocker();
|
|
6161
6277
|
}
|
|
6162
6278
|
/**
|
|
6163
|
-
*
|
|
6164
|
-
* On macOS: tries Docker Desktop app
|
|
6165
|
-
* On Linux: tries systemctl,
|
|
6279
|
+
* Start the Docker daemon using multiple strategies.
|
|
6280
|
+
* On macOS: tries Docker Desktop app via `open`, direct binary launch, etc.
|
|
6281
|
+
* On Linux: tries systemctl, service, snap.
|
|
6166
6282
|
*/
|
|
6167
6283
|
startDockerDaemon(strategy) {
|
|
6168
6284
|
const os = platform2();
|
|
6169
6285
|
if (os === "darwin") {
|
|
6286
|
+
const dockerApp = this.findDockerApp();
|
|
6170
6287
|
switch (strategy) {
|
|
6171
6288
|
case "cli":
|
|
6172
6289
|
try {
|
|
@@ -6183,24 +6300,56 @@ var DependencyInstaller = class {
|
|
|
6183
6300
|
execFileSync2("sleep", ["2"], { timeout: 5e3, stdio: "ignore" });
|
|
6184
6301
|
} catch {
|
|
6185
6302
|
}
|
|
6186
|
-
|
|
6187
|
-
|
|
6188
|
-
|
|
6303
|
+
if (dockerApp) {
|
|
6304
|
+
try {
|
|
6305
|
+
execFileSync2("open", [dockerApp], { timeout: 1e4, stdio: "ignore" });
|
|
6306
|
+
} catch {
|
|
6307
|
+
}
|
|
6308
|
+
} else {
|
|
6309
|
+
try {
|
|
6310
|
+
execFileSync2("open", ["-a", "Docker"], { timeout: 1e4, stdio: "ignore" });
|
|
6311
|
+
} catch {
|
|
6312
|
+
}
|
|
6189
6313
|
}
|
|
6190
6314
|
break;
|
|
6191
|
-
case "background":
|
|
6315
|
+
case "background": {
|
|
6316
|
+
const appBin = dockerApp ? join6(dockerApp, "Contents", "MacOS", "Docker") : "/Applications/Docker.app/Contents/MacOS/Docker";
|
|
6192
6317
|
try {
|
|
6193
|
-
const appBin = "/Applications/Docker.app/Contents/MacOS/Docker";
|
|
6194
6318
|
if (existsSync4(appBin)) {
|
|
6195
6319
|
execSync(`"${appBin}" &`, { timeout: 5e3, stdio: "ignore", shell: "sh" });
|
|
6196
6320
|
}
|
|
6197
6321
|
} catch {
|
|
6198
6322
|
}
|
|
6199
6323
|
break;
|
|
6324
|
+
}
|
|
6325
|
+
case "install": {
|
|
6326
|
+
const installBin = dockerApp ? join6(dockerApp, "Contents", "MacOS", "install") : "/Applications/Docker.app/Contents/MacOS/install";
|
|
6327
|
+
if (existsSync4(installBin)) {
|
|
6328
|
+
const user = process.env.USER || "nobody";
|
|
6329
|
+
try {
|
|
6330
|
+
execSync(`"${installBin}" --accept-license --user=${user}`, { timeout: 6e4, stdio: "ignore" });
|
|
6331
|
+
} catch {
|
|
6332
|
+
}
|
|
6333
|
+
}
|
|
6334
|
+
if (dockerApp) {
|
|
6335
|
+
try {
|
|
6336
|
+
execFileSync2("open", [dockerApp], { timeout: 1e4, stdio: "ignore" });
|
|
6337
|
+
} catch {
|
|
6338
|
+
}
|
|
6339
|
+
}
|
|
6340
|
+
break;
|
|
6341
|
+
}
|
|
6200
6342
|
default:
|
|
6201
|
-
|
|
6202
|
-
|
|
6203
|
-
|
|
6343
|
+
if (dockerApp) {
|
|
6344
|
+
try {
|
|
6345
|
+
execFileSync2("open", [dockerApp], { timeout: 1e4, stdio: "ignore" });
|
|
6346
|
+
} catch {
|
|
6347
|
+
}
|
|
6348
|
+
} else {
|
|
6349
|
+
try {
|
|
6350
|
+
execFileSync2("open", ["-a", "Docker"], { timeout: 1e4, stdio: "ignore" });
|
|
6351
|
+
} catch {
|
|
6352
|
+
}
|
|
6204
6353
|
}
|
|
6205
6354
|
}
|
|
6206
6355
|
} else if (os === "linux") {
|
|
@@ -6226,14 +6375,14 @@ var DependencyInstaller = class {
|
|
|
6226
6375
|
}
|
|
6227
6376
|
}
|
|
6228
6377
|
/**
|
|
6229
|
-
* Wait for Docker daemon to be ready
|
|
6230
|
-
*
|
|
6378
|
+
* Wait for Docker daemon to be ready.
|
|
6379
|
+
* Cycles through multiple start strategies automatically.
|
|
6231
6380
|
* Reports progress as a percentage (0-100).
|
|
6232
6381
|
*/
|
|
6233
6382
|
async waitForDocker() {
|
|
6234
6383
|
const os = platform2();
|
|
6235
|
-
const strategies = os === "darwin" ? ["default", "cli", "reopen", "background"] : ["default", "service", "snap"];
|
|
6236
|
-
const totalTime =
|
|
6384
|
+
const strategies = os === "darwin" ? ["default", "cli", "reopen", "background", "install"] : ["default", "service", "snap"];
|
|
6385
|
+
const totalTime = 3e5;
|
|
6237
6386
|
const perStrategyTime = Math.floor(totalTime / strategies.length);
|
|
6238
6387
|
const start = Date.now();
|
|
6239
6388
|
let strategyIdx = 0;
|
|
@@ -6255,6 +6404,7 @@ var DependencyInstaller = class {
|
|
|
6255
6404
|
cli: "Trying Docker CLI...",
|
|
6256
6405
|
reopen: "Restarting Docker Desktop...",
|
|
6257
6406
|
background: "Trying direct launch...",
|
|
6407
|
+
install: "Re-running Docker installer...",
|
|
6258
6408
|
service: "Trying service command...",
|
|
6259
6409
|
snap: "Trying snap..."
|
|
6260
6410
|
};
|
|
@@ -6275,7 +6425,9 @@ var DependencyInstaller = class {
|
|
|
6275
6425
|
}
|
|
6276
6426
|
await new Promise((r) => setTimeout(r, 3e3));
|
|
6277
6427
|
}
|
|
6278
|
-
throw new Error(
|
|
6428
|
+
throw new Error(
|
|
6429
|
+
"Docker could not be started after trying all available methods. This usually means Docker Desktop needs a one-time manual launch to complete its setup. Open Docker from your Applications folder, then run this command again."
|
|
6430
|
+
);
|
|
6279
6431
|
}
|
|
6280
6432
|
/**
|
|
6281
6433
|
* Start the Stalwart mail server Docker container.
|