flightdesk 0.2.4 → 0.2.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/main.js +175 -40
- package/main.js.map +3 -3
- package/package.json +1 -1
package/main.js
CHANGED
|
@@ -3577,7 +3577,51 @@ var path2 = __toESM(require("node:path"));
|
|
|
3577
3577
|
var os2 = __toESM(require("node:os"));
|
|
3578
3578
|
var fs2 = __toESM(require("node:fs"));
|
|
3579
3579
|
var readline2 = __toESM(require("node:readline"));
|
|
3580
|
+
var import_node_child_process = require("node:child_process");
|
|
3580
3581
|
var playwright = null;
|
|
3582
|
+
var PlaywrightBrowserNotInstalledError = class extends Error {
|
|
3583
|
+
constructor(autoInstallError) {
|
|
3584
|
+
const baseMessage = "Playwright browser not installed.";
|
|
3585
|
+
const autoInstallInfo = autoInstallError ? `
|
|
3586
|
+
|
|
3587
|
+
Auto-install failed: ${autoInstallError}
|
|
3588
|
+
` : "\n\n";
|
|
3589
|
+
super(
|
|
3590
|
+
baseMessage + autoInstallInfo + "Run one of the following commands:\n\n npx playwright install chromium # Just Chromium (recommended)\n npx playwright install # All browsers\n\nThen retry your command."
|
|
3591
|
+
);
|
|
3592
|
+
this.name = "PlaywrightBrowserNotInstalledError";
|
|
3593
|
+
}
|
|
3594
|
+
};
|
|
3595
|
+
function isBrowserNotInstalledError(error) {
|
|
3596
|
+
if (!(error instanceof Error)) return false;
|
|
3597
|
+
return error.message.includes("Executable doesn't exist") || error.message.includes("browserType.launch") || error.message.includes("npx playwright install");
|
|
3598
|
+
}
|
|
3599
|
+
var autoInstallAttempted = false;
|
|
3600
|
+
function tryAutoInstallBrowsers() {
|
|
3601
|
+
if (autoInstallAttempted) {
|
|
3602
|
+
return false;
|
|
3603
|
+
}
|
|
3604
|
+
autoInstallAttempted = true;
|
|
3605
|
+
console.log("");
|
|
3606
|
+
console.log("\u{1F4E6} Playwright browser not found. Installing automatically...");
|
|
3607
|
+
console.log("");
|
|
3608
|
+
try {
|
|
3609
|
+
(0, import_node_child_process.execSync)("npx playwright install chromium", {
|
|
3610
|
+
stdio: "inherit",
|
|
3611
|
+
timeout: 12e4
|
|
3612
|
+
// 2 minute timeout
|
|
3613
|
+
});
|
|
3614
|
+
console.log("");
|
|
3615
|
+
console.log("\u2705 Browser installed successfully!");
|
|
3616
|
+
console.log("");
|
|
3617
|
+
return true;
|
|
3618
|
+
} catch (error) {
|
|
3619
|
+
console.error("");
|
|
3620
|
+
console.error("\u274C Auto-install failed:", error instanceof Error ? error.message : String(error));
|
|
3621
|
+
console.error("");
|
|
3622
|
+
return false;
|
|
3623
|
+
}
|
|
3624
|
+
}
|
|
3581
3625
|
var USER_DATA_DIR = path2.join(os2.homedir(), ".flightdesk", "chromium-profile");
|
|
3582
3626
|
var STORAGE_STATE_FILE = path2.join(os2.homedir(), ".flightdesk", "auth-state.json");
|
|
3583
3627
|
var PersistentBrowser = class {
|
|
@@ -3605,9 +3649,29 @@ var PersistentBrowser = class {
|
|
|
3605
3649
|
throw new Error("Playwright not available");
|
|
3606
3650
|
}
|
|
3607
3651
|
ensureUserDataDir();
|
|
3608
|
-
|
|
3609
|
-
|
|
3610
|
-
|
|
3652
|
+
try {
|
|
3653
|
+
this.browser = await playwright.chromium.launch({
|
|
3654
|
+
headless: this.headless
|
|
3655
|
+
});
|
|
3656
|
+
} catch (error) {
|
|
3657
|
+
if (isBrowserNotInstalledError(error)) {
|
|
3658
|
+
if (tryAutoInstallBrowsers()) {
|
|
3659
|
+
try {
|
|
3660
|
+
this.browser = await playwright.chromium.launch({
|
|
3661
|
+
headless: this.headless
|
|
3662
|
+
});
|
|
3663
|
+
} catch (retryError) {
|
|
3664
|
+
throw new PlaywrightBrowserNotInstalledError(
|
|
3665
|
+
retryError instanceof Error ? retryError.message : String(retryError)
|
|
3666
|
+
);
|
|
3667
|
+
}
|
|
3668
|
+
} else {
|
|
3669
|
+
throw new PlaywrightBrowserNotInstalledError();
|
|
3670
|
+
}
|
|
3671
|
+
} else {
|
|
3672
|
+
throw error;
|
|
3673
|
+
}
|
|
3674
|
+
}
|
|
3611
3675
|
const hasAuthState = fs2.existsSync(STORAGE_STATE_FILE);
|
|
3612
3676
|
const contextOptions = {
|
|
3613
3677
|
viewport: { width: 1280, height: 720 },
|
|
@@ -3702,7 +3766,26 @@ async function launchBrowser(headless) {
|
|
|
3702
3766
|
throw new Error("Playwright not available");
|
|
3703
3767
|
}
|
|
3704
3768
|
ensureUserDataDir();
|
|
3705
|
-
|
|
3769
|
+
let browser;
|
|
3770
|
+
try {
|
|
3771
|
+
browser = await playwright.chromium.launch({ headless });
|
|
3772
|
+
} catch (error) {
|
|
3773
|
+
if (isBrowserNotInstalledError(error)) {
|
|
3774
|
+
if (tryAutoInstallBrowsers()) {
|
|
3775
|
+
try {
|
|
3776
|
+
browser = await playwright.chromium.launch({ headless });
|
|
3777
|
+
} catch (retryError) {
|
|
3778
|
+
throw new PlaywrightBrowserNotInstalledError(
|
|
3779
|
+
retryError instanceof Error ? retryError.message : String(retryError)
|
|
3780
|
+
);
|
|
3781
|
+
}
|
|
3782
|
+
} else {
|
|
3783
|
+
throw new PlaywrightBrowserNotInstalledError();
|
|
3784
|
+
}
|
|
3785
|
+
} else {
|
|
3786
|
+
throw error;
|
|
3787
|
+
}
|
|
3788
|
+
}
|
|
3706
3789
|
const hasAuthState = fs2.existsSync(STORAGE_STATE_FILE);
|
|
3707
3790
|
const contextOptions = {
|
|
3708
3791
|
viewport: { width: 1280, height: 720 },
|
|
@@ -3915,7 +3998,23 @@ async function detectActiveSpinner(page) {
|
|
|
3915
3998
|
try {
|
|
3916
3999
|
const spinner = await page.$(".code-spinner-animate");
|
|
3917
4000
|
if (spinner) {
|
|
3918
|
-
|
|
4001
|
+
const isVisibleAndAnimating = await spinner.evaluate((el) => {
|
|
4002
|
+
const style = globalThis.getComputedStyle(el);
|
|
4003
|
+
if (style.display === "none" || style.visibility === "hidden" || style.opacity === "0") {
|
|
4004
|
+
return false;
|
|
4005
|
+
}
|
|
4006
|
+
if (style.animationName && style.animationName !== "none") {
|
|
4007
|
+
return true;
|
|
4008
|
+
}
|
|
4009
|
+
if (style.animationPlayState === "paused") {
|
|
4010
|
+
return false;
|
|
4011
|
+
}
|
|
4012
|
+
const rect = el.getBoundingClientRect();
|
|
4013
|
+
return rect.width > 0 && rect.height > 0;
|
|
4014
|
+
});
|
|
4015
|
+
if (isVisibleAndAnimating) {
|
|
4016
|
+
return true;
|
|
4017
|
+
}
|
|
3919
4018
|
}
|
|
3920
4019
|
const spinnerByContent = await page.$('span:has-text("\u273D")');
|
|
3921
4020
|
if (spinnerByContent) {
|
|
@@ -3924,10 +4023,19 @@ async function detectActiveSpinner(page) {
|
|
|
3924
4023
|
while (current) {
|
|
3925
4024
|
const classList = current.classList;
|
|
3926
4025
|
if (classList?.contains("code-spinner-animate")) {
|
|
3927
|
-
|
|
4026
|
+
const style2 = globalThis.getComputedStyle(current);
|
|
4027
|
+
if (style2.display === "none" || style2.visibility === "hidden" || style2.opacity === "0") {
|
|
4028
|
+
current = current.parentElement;
|
|
4029
|
+
continue;
|
|
4030
|
+
}
|
|
4031
|
+
if (style2.animationPlayState === "paused") {
|
|
4032
|
+
current = current.parentElement;
|
|
4033
|
+
continue;
|
|
4034
|
+
}
|
|
4035
|
+
return style2.animationName !== "none";
|
|
3928
4036
|
}
|
|
3929
4037
|
const style = globalThis.getComputedStyle(current);
|
|
3930
|
-
if (style.animationName && style.animationName !== "none") {
|
|
4038
|
+
if (style.animationName && style.animationName !== "none" && style.animationPlayState !== "paused") {
|
|
3931
4039
|
return true;
|
|
3932
4040
|
}
|
|
3933
4041
|
current = current.parentElement;
|
|
@@ -3954,30 +4062,48 @@ async function authCommand() {
|
|
|
3954
4062
|
console.log(`Profile directory: ${USER_DATA_DIR}
|
|
3955
4063
|
`);
|
|
3956
4064
|
console.log("Checking current authentication status...");
|
|
3957
|
-
|
|
3958
|
-
|
|
3959
|
-
|
|
3960
|
-
|
|
3961
|
-
|
|
4065
|
+
try {
|
|
4066
|
+
const isAuthenticated = await checkAuth();
|
|
4067
|
+
if (isAuthenticated) {
|
|
4068
|
+
console.log("\u2705 Already logged in to Claude!");
|
|
4069
|
+
console.log("\nThe watch daemon will be able to monitor your sessions.");
|
|
4070
|
+
return;
|
|
4071
|
+
}
|
|
4072
|
+
} catch (error) {
|
|
4073
|
+
if (error instanceof PlaywrightBrowserNotInstalledError) {
|
|
4074
|
+
console.error("");
|
|
4075
|
+
console.error("\u274C " + error.message);
|
|
4076
|
+
process.exit(1);
|
|
4077
|
+
}
|
|
4078
|
+
throw error;
|
|
3962
4079
|
}
|
|
3963
4080
|
console.log("\u274C Not logged in to Claude.\n");
|
|
3964
4081
|
console.log("Opening browser for login...");
|
|
3965
4082
|
console.log("Please log in to your Claude account.\n");
|
|
3966
|
-
|
|
3967
|
-
|
|
3968
|
-
|
|
3969
|
-
|
|
3970
|
-
|
|
3971
|
-
|
|
3972
|
-
|
|
4083
|
+
try {
|
|
4084
|
+
const loginSuccessful = await openForLogin();
|
|
4085
|
+
if (loginSuccessful) {
|
|
4086
|
+
console.log("\n\u2705 Successfully logged in!");
|
|
4087
|
+
console.log("The watch daemon can now monitor your Claude Code sessions.");
|
|
4088
|
+
} else {
|
|
4089
|
+
console.log("\n\u274C Login was not detected.");
|
|
4090
|
+
console.log("Please try again with: flightdesk auth");
|
|
4091
|
+
}
|
|
4092
|
+
} catch (error) {
|
|
4093
|
+
if (error instanceof PlaywrightBrowserNotInstalledError) {
|
|
4094
|
+
console.error("");
|
|
4095
|
+
console.error("\u274C " + error.message);
|
|
4096
|
+
process.exit(1);
|
|
4097
|
+
}
|
|
4098
|
+
throw error;
|
|
3973
4099
|
}
|
|
3974
4100
|
}
|
|
3975
4101
|
|
|
3976
4102
|
// apps/cli/src/lib/git.ts
|
|
3977
|
-
var
|
|
4103
|
+
var import_node_child_process2 = require("node:child_process");
|
|
3978
4104
|
function detectGitRepo() {
|
|
3979
4105
|
try {
|
|
3980
|
-
const remoteUrl = (0,
|
|
4106
|
+
const remoteUrl = (0, import_node_child_process2.execSync)("git remote get-url origin", {
|
|
3981
4107
|
encoding: "utf-8",
|
|
3982
4108
|
stdio: ["pipe", "pipe", "pipe"]
|
|
3983
4109
|
}).trim();
|
|
@@ -3985,7 +4111,7 @@ function detectGitRepo() {
|
|
|
3985
4111
|
if (!repoFullName) {
|
|
3986
4112
|
return null;
|
|
3987
4113
|
}
|
|
3988
|
-
const branch = (0,
|
|
4114
|
+
const branch = (0, import_node_child_process2.execSync)("git rev-parse --abbrev-ref HEAD", {
|
|
3989
4115
|
encoding: "utf-8",
|
|
3990
4116
|
stdio: ["pipe", "pipe", "pipe"]
|
|
3991
4117
|
}).trim();
|
|
@@ -4263,16 +4389,25 @@ async function watchCommand(options) {
|
|
|
4263
4389
|
} else {
|
|
4264
4390
|
browser = new PersistentBrowser(options.headless !== false);
|
|
4265
4391
|
console.log("Checking Claude authentication...");
|
|
4266
|
-
|
|
4267
|
-
|
|
4268
|
-
|
|
4269
|
-
|
|
4270
|
-
|
|
4271
|
-
|
|
4272
|
-
|
|
4273
|
-
|
|
4274
|
-
|
|
4275
|
-
|
|
4392
|
+
try {
|
|
4393
|
+
const isAuthenticated = await browser.checkAuth();
|
|
4394
|
+
if (!isAuthenticated) {
|
|
4395
|
+
console.log("\u26A0\uFE0F Not logged into Claude. Run: flightdesk auth");
|
|
4396
|
+
console.log("");
|
|
4397
|
+
await browser.close();
|
|
4398
|
+
browser = null;
|
|
4399
|
+
} else {
|
|
4400
|
+
console.log("\u2705 Playwright ready, Claude authenticated");
|
|
4401
|
+
console.log(" (Browser session kept alive for monitoring)");
|
|
4402
|
+
console.log("");
|
|
4403
|
+
}
|
|
4404
|
+
} catch (error) {
|
|
4405
|
+
if (error instanceof PlaywrightBrowserNotInstalledError) {
|
|
4406
|
+
console.error("");
|
|
4407
|
+
console.error("\u274C " + error.message);
|
|
4408
|
+
process.exit(1);
|
|
4409
|
+
}
|
|
4410
|
+
throw error;
|
|
4276
4411
|
}
|
|
4277
4412
|
}
|
|
4278
4413
|
const api = FlightDeskAPI.fromConfig(config, org2);
|
|
@@ -5254,7 +5389,7 @@ ${projects.length} project(s)`);
|
|
|
5254
5389
|
}
|
|
5255
5390
|
|
|
5256
5391
|
// apps/cli/src/commands/preview.ts
|
|
5257
|
-
var
|
|
5392
|
+
var import_node_child_process3 = require("node:child_process");
|
|
5258
5393
|
var path3 = __toESM(require("node:path"));
|
|
5259
5394
|
var os3 = __toESM(require("node:os"));
|
|
5260
5395
|
var fs4 = __toESM(require("node:fs"));
|
|
@@ -5360,7 +5495,7 @@ async function handleLogs(api, options) {
|
|
|
5360
5495
|
`);
|
|
5361
5496
|
validateSSHParams(instance);
|
|
5362
5497
|
const sshCommand = `docker logs -f ${instance.containerId}`;
|
|
5363
|
-
const ssh = (0,
|
|
5498
|
+
const ssh = (0, import_node_child_process3.spawn)("ssh", [
|
|
5364
5499
|
"-o",
|
|
5365
5500
|
"StrictHostKeyChecking=no",
|
|
5366
5501
|
"-o",
|
|
@@ -5400,7 +5535,7 @@ async function handleMount(api, options) {
|
|
|
5400
5535
|
await new Promise((resolve) => setTimeout(resolve, 3e3));
|
|
5401
5536
|
}
|
|
5402
5537
|
try {
|
|
5403
|
-
(0,
|
|
5538
|
+
(0, import_node_child_process3.execSync)("which sshfs", { stdio: "ignore" });
|
|
5404
5539
|
} catch {
|
|
5405
5540
|
console.error("\u274C sshfs is not installed.");
|
|
5406
5541
|
console.error("");
|
|
@@ -5421,7 +5556,7 @@ async function handleMount(api, options) {
|
|
|
5421
5556
|
fs4.mkdirSync(mountDir, { recursive: true });
|
|
5422
5557
|
}
|
|
5423
5558
|
try {
|
|
5424
|
-
const mounted = (0,
|
|
5559
|
+
const mounted = (0, import_node_child_process3.execSync)("mount", { encoding: "utf8" });
|
|
5425
5560
|
if (mounted.includes(mountDir)) {
|
|
5426
5561
|
console.log(`\u{1F4C1} Already mounted at ${mountDir}`);
|
|
5427
5562
|
return;
|
|
@@ -5447,7 +5582,7 @@ async function handleMount(api, options) {
|
|
|
5447
5582
|
mountDir
|
|
5448
5583
|
];
|
|
5449
5584
|
try {
|
|
5450
|
-
const result = (0,
|
|
5585
|
+
const result = (0, import_node_child_process3.spawnSync)("sshfs", sshfsArgs, { stdio: "inherit" });
|
|
5451
5586
|
if (result.status !== 0) {
|
|
5452
5587
|
throw new Error(`sshfs exited with code ${result.status}`);
|
|
5453
5588
|
}
|
|
@@ -5481,9 +5616,9 @@ async function handleUnmount(_api, options) {
|
|
|
5481
5616
|
try {
|
|
5482
5617
|
let result;
|
|
5483
5618
|
if (process.platform === "darwin") {
|
|
5484
|
-
result = (0,
|
|
5619
|
+
result = (0, import_node_child_process3.spawnSync)("umount", [mountDir], { stdio: "inherit" });
|
|
5485
5620
|
} else {
|
|
5486
|
-
result = (0,
|
|
5621
|
+
result = (0, import_node_child_process3.spawnSync)("fusermount", ["-u", mountDir], { stdio: "inherit" });
|
|
5487
5622
|
}
|
|
5488
5623
|
if (result.status !== 0) {
|
|
5489
5624
|
throw new Error(`Unmount exited with code ${result.status}`);
|
|
@@ -5523,7 +5658,7 @@ async function handleTeardown(api, options) {
|
|
|
5523
5658
|
|
|
5524
5659
|
// apps/cli/src/main.ts
|
|
5525
5660
|
var program2 = new Command();
|
|
5526
|
-
program2.name("flightdesk").description("FlightDesk CLI - AI task management for Claude Code sessions").version("0.2.
|
|
5661
|
+
program2.name("flightdesk").description("FlightDesk CLI - AI task management for Claude Code sessions").version("0.2.5").option("--dev", "Use local development API (localhost:3000)").option("--api <url>", "Use custom API URL");
|
|
5527
5662
|
program2.hook("preAction", () => {
|
|
5528
5663
|
const opts = program2.opts();
|
|
5529
5664
|
if (opts.api) {
|