flightdesk 0.1.13 → 0.2.0
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 +335 -38
- package/main.js.map +4 -4
- package/package.json +1 -1
package/main.js
CHANGED
|
@@ -958,8 +958,8 @@ var require_command = __commonJS({
|
|
|
958
958
|
"node_modules/.pnpm/commander@12.1.0/node_modules/commander/lib/command.js"(exports2) {
|
|
959
959
|
var EventEmitter = require("node:events").EventEmitter;
|
|
960
960
|
var childProcess = require("node:child_process");
|
|
961
|
-
var
|
|
962
|
-
var
|
|
961
|
+
var path4 = require("node:path");
|
|
962
|
+
var fs5 = require("node:fs");
|
|
963
963
|
var process2 = require("node:process");
|
|
964
964
|
var { Argument: Argument2, humanReadableArgName } = require_argument();
|
|
965
965
|
var { CommanderError: CommanderError2 } = require_error();
|
|
@@ -1891,11 +1891,11 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
1891
1891
|
let launchWithNode = false;
|
|
1892
1892
|
const sourceExt = [".js", ".ts", ".tsx", ".mjs", ".cjs"];
|
|
1893
1893
|
function findFile(baseDir, baseName) {
|
|
1894
|
-
const localBin =
|
|
1895
|
-
if (
|
|
1896
|
-
if (sourceExt.includes(
|
|
1894
|
+
const localBin = path4.resolve(baseDir, baseName);
|
|
1895
|
+
if (fs5.existsSync(localBin)) return localBin;
|
|
1896
|
+
if (sourceExt.includes(path4.extname(baseName))) return void 0;
|
|
1897
1897
|
const foundExt = sourceExt.find(
|
|
1898
|
-
(ext) =>
|
|
1898
|
+
(ext) => fs5.existsSync(`${localBin}${ext}`)
|
|
1899
1899
|
);
|
|
1900
1900
|
if (foundExt) return `${localBin}${foundExt}`;
|
|
1901
1901
|
return void 0;
|
|
@@ -1907,21 +1907,21 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
1907
1907
|
if (this._scriptPath) {
|
|
1908
1908
|
let resolvedScriptPath;
|
|
1909
1909
|
try {
|
|
1910
|
-
resolvedScriptPath =
|
|
1910
|
+
resolvedScriptPath = fs5.realpathSync(this._scriptPath);
|
|
1911
1911
|
} catch (err) {
|
|
1912
1912
|
resolvedScriptPath = this._scriptPath;
|
|
1913
1913
|
}
|
|
1914
|
-
executableDir =
|
|
1915
|
-
|
|
1914
|
+
executableDir = path4.resolve(
|
|
1915
|
+
path4.dirname(resolvedScriptPath),
|
|
1916
1916
|
executableDir
|
|
1917
1917
|
);
|
|
1918
1918
|
}
|
|
1919
1919
|
if (executableDir) {
|
|
1920
1920
|
let localFile = findFile(executableDir, executableFile);
|
|
1921
1921
|
if (!localFile && !subcommand._executableFile && this._scriptPath) {
|
|
1922
|
-
const legacyName =
|
|
1922
|
+
const legacyName = path4.basename(
|
|
1923
1923
|
this._scriptPath,
|
|
1924
|
-
|
|
1924
|
+
path4.extname(this._scriptPath)
|
|
1925
1925
|
);
|
|
1926
1926
|
if (legacyName !== this._name) {
|
|
1927
1927
|
localFile = findFile(
|
|
@@ -1932,7 +1932,7 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
1932
1932
|
}
|
|
1933
1933
|
executableFile = localFile || executableFile;
|
|
1934
1934
|
}
|
|
1935
|
-
launchWithNode = sourceExt.includes(
|
|
1935
|
+
launchWithNode = sourceExt.includes(path4.extname(executableFile));
|
|
1936
1936
|
let proc;
|
|
1937
1937
|
if (process2.platform !== "win32") {
|
|
1938
1938
|
if (launchWithNode) {
|
|
@@ -2772,7 +2772,7 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
2772
2772
|
* @return {Command}
|
|
2773
2773
|
*/
|
|
2774
2774
|
nameFromFilename(filename) {
|
|
2775
|
-
this._name =
|
|
2775
|
+
this._name = path4.basename(filename, path4.extname(filename));
|
|
2776
2776
|
return this;
|
|
2777
2777
|
}
|
|
2778
2778
|
/**
|
|
@@ -2786,9 +2786,9 @@ Expecting one of '${allowedValues.join("', '")}'`);
|
|
|
2786
2786
|
* @param {string} [path]
|
|
2787
2787
|
* @return {(string|null|Command)}
|
|
2788
2788
|
*/
|
|
2789
|
-
executableDir(
|
|
2790
|
-
if (
|
|
2791
|
-
this._executableDir =
|
|
2789
|
+
executableDir(path5) {
|
|
2790
|
+
if (path5 === void 0) return this._executableDir;
|
|
2791
|
+
this._executableDir = path5;
|
|
2792
2792
|
return this;
|
|
2793
2793
|
}
|
|
2794
2794
|
/**
|
|
@@ -3052,8 +3052,7 @@ function setApiUrl(url) {
|
|
|
3052
3052
|
apiUrlOverride = url;
|
|
3053
3053
|
}
|
|
3054
3054
|
function getApiUrl() {
|
|
3055
|
-
|
|
3056
|
-
return apiUrlOverride ?? config.apiUrl ?? DEFAULT_API_URL;
|
|
3055
|
+
return apiUrlOverride ?? DEFAULT_API_URL;
|
|
3057
3056
|
}
|
|
3058
3057
|
function loadConfig() {
|
|
3059
3058
|
try {
|
|
@@ -3064,7 +3063,6 @@ function loadConfig() {
|
|
|
3064
3063
|
return migrateOldConfig(parsed);
|
|
3065
3064
|
}
|
|
3066
3065
|
return {
|
|
3067
|
-
apiUrl: DEFAULT_API_URL,
|
|
3068
3066
|
organizations: [],
|
|
3069
3067
|
repoMapping: {},
|
|
3070
3068
|
...parsed
|
|
@@ -3074,7 +3072,6 @@ function loadConfig() {
|
|
|
3074
3072
|
console.error("Warning: Failed to load config file:", error);
|
|
3075
3073
|
}
|
|
3076
3074
|
return {
|
|
3077
|
-
apiUrl: DEFAULT_API_URL,
|
|
3078
3075
|
organizations: [],
|
|
3079
3076
|
repoMapping: {}
|
|
3080
3077
|
};
|
|
@@ -3084,7 +3081,6 @@ function migrateOldConfig(oldConfig) {
|
|
|
3084
3081
|
const defaultOrg = oldConfig.defaultOrganization ? oldConfig.organizations.find((o) => o.id === oldConfig.defaultOrganization) : oldConfig.organizations[0];
|
|
3085
3082
|
const newConfig = {
|
|
3086
3083
|
apiKey: defaultOrg?.apiKey,
|
|
3087
|
-
apiUrl: defaultOrg?.apiUrl || DEFAULT_API_URL,
|
|
3088
3084
|
activeOrganization: defaultOrg?.id,
|
|
3089
3085
|
organizations: oldConfig.organizations.map((o) => ({
|
|
3090
3086
|
id: o.id,
|
|
@@ -3276,6 +3272,7 @@ var FlightDeskAPI = class _FlightDeskAPI {
|
|
|
3276
3272
|
status
|
|
3277
3273
|
branchName
|
|
3278
3274
|
prUrl
|
|
3275
|
+
sessionViewUrl
|
|
3279
3276
|
createdAt
|
|
3280
3277
|
project {
|
|
3281
3278
|
id
|
|
@@ -3371,6 +3368,71 @@ var FlightDeskAPI = class _FlightDeskAPI {
|
|
|
3371
3368
|
const result = await this.graphql(query, { taskId });
|
|
3372
3369
|
return result.userTaskPrompts;
|
|
3373
3370
|
}
|
|
3371
|
+
// ============================================================================
|
|
3372
|
+
// Preview Environment Operations
|
|
3373
|
+
// ============================================================================
|
|
3374
|
+
async getTaskInstance(taskId) {
|
|
3375
|
+
const query = `
|
|
3376
|
+
query GetTaskInstance($taskId: String!) {
|
|
3377
|
+
userTaskInstance(taskId: $taskId) {
|
|
3378
|
+
id
|
|
3379
|
+
taskId
|
|
3380
|
+
workerId
|
|
3381
|
+
containerId
|
|
3382
|
+
previewUrl
|
|
3383
|
+
sshHost
|
|
3384
|
+
sshPort
|
|
3385
|
+
sshUser
|
|
3386
|
+
status
|
|
3387
|
+
lastActivityAt
|
|
3388
|
+
suspendedAt
|
|
3389
|
+
createdAt
|
|
3390
|
+
updatedAt
|
|
3391
|
+
sshConnectionString
|
|
3392
|
+
}
|
|
3393
|
+
}
|
|
3394
|
+
`;
|
|
3395
|
+
const result = await this.graphql(query, { taskId });
|
|
3396
|
+
return result.userTaskInstance;
|
|
3397
|
+
}
|
|
3398
|
+
async getInstanceLogs(taskId, lines = 100) {
|
|
3399
|
+
const query = `
|
|
3400
|
+
query GetInstanceLogs($taskId: String!, $lines: Float) {
|
|
3401
|
+
userInstanceLogs(taskId: $taskId, lines: $lines) {
|
|
3402
|
+
logs
|
|
3403
|
+
}
|
|
3404
|
+
}
|
|
3405
|
+
`;
|
|
3406
|
+
const result = await this.graphql(query, { taskId, lines });
|
|
3407
|
+
return result.userInstanceLogs;
|
|
3408
|
+
}
|
|
3409
|
+
async restartInstance(taskId) {
|
|
3410
|
+
const query = `
|
|
3411
|
+
mutation RestartInstance($taskId: String!) {
|
|
3412
|
+
userRestartInstance(taskId: $taskId)
|
|
3413
|
+
}
|
|
3414
|
+
`;
|
|
3415
|
+
const result = await this.graphql(query, { taskId });
|
|
3416
|
+
return result.userRestartInstance;
|
|
3417
|
+
}
|
|
3418
|
+
async resumeInstance(taskId) {
|
|
3419
|
+
const query = `
|
|
3420
|
+
mutation ResumeInstance($taskId: String!) {
|
|
3421
|
+
userResumeInstance(taskId: $taskId)
|
|
3422
|
+
}
|
|
3423
|
+
`;
|
|
3424
|
+
const result = await this.graphql(query, { taskId });
|
|
3425
|
+
return result.userResumeInstance;
|
|
3426
|
+
}
|
|
3427
|
+
async tearDownInstance(taskId) {
|
|
3428
|
+
const query = `
|
|
3429
|
+
mutation TearDownInstance($taskId: String!) {
|
|
3430
|
+
userTearDownInstance(taskId: $taskId)
|
|
3431
|
+
}
|
|
3432
|
+
`;
|
|
3433
|
+
const result = await this.graphql(query, { taskId });
|
|
3434
|
+
return result.userTearDownInstance;
|
|
3435
|
+
}
|
|
3374
3436
|
};
|
|
3375
3437
|
async function fetchUserInfo(apiKey, apiUrl = "https://api.flightdesk.dev") {
|
|
3376
3438
|
const response = await fetch(`${apiUrl}/graphql`, {
|
|
@@ -3996,7 +4058,7 @@ async function reconcileTaskStatus(api, task2) {
|
|
|
3996
4058
|
let expectedStatus = null;
|
|
3997
4059
|
let reason = "";
|
|
3998
4060
|
if (task2.prUrl) {
|
|
3999
|
-
if (!["PR_OPEN", "MERGED", "ARCHIVED", "REVIEW_RUNNING", "REVIEW_DONE", "QA_READY", "QA_APPROVED"].includes(task2.status)) {
|
|
4061
|
+
if (!["PR_OPEN", "PREVIEW_STARTING", "PREVIEW_READY", "MERGED", "ARCHIVED", "REVIEW_RUNNING", "REVIEW_DONE", "QA_READY", "QA_APPROVED"].includes(task2.status)) {
|
|
4000
4062
|
expectedStatus = "PR_OPEN";
|
|
4001
4063
|
reason = `has PR URL but status is ${task2.status}`;
|
|
4002
4064
|
}
|
|
@@ -4878,9 +4940,248 @@ async function listProjects(api) {
|
|
|
4878
4940
|
${projects.length} project(s)`);
|
|
4879
4941
|
}
|
|
4880
4942
|
|
|
4943
|
+
// apps/cli/src/commands/preview.ts
|
|
4944
|
+
var import_child_process2 = require("child_process");
|
|
4945
|
+
var path3 = __toESM(require("path"));
|
|
4946
|
+
var os3 = __toESM(require("os"));
|
|
4947
|
+
var fs4 = __toESM(require("fs"));
|
|
4948
|
+
async function previewCommand(action, options) {
|
|
4949
|
+
const { config, org: org2 } = requireActiveOrg();
|
|
4950
|
+
const api = FlightDeskAPI.fromConfig(config, org2);
|
|
4951
|
+
try {
|
|
4952
|
+
switch (action) {
|
|
4953
|
+
case "status":
|
|
4954
|
+
await handleStatus2(api, options);
|
|
4955
|
+
break;
|
|
4956
|
+
case "logs":
|
|
4957
|
+
await handleLogs(api, options);
|
|
4958
|
+
break;
|
|
4959
|
+
case "mount":
|
|
4960
|
+
await handleMount(api, options);
|
|
4961
|
+
break;
|
|
4962
|
+
case "unmount":
|
|
4963
|
+
await handleUnmount(api, options);
|
|
4964
|
+
break;
|
|
4965
|
+
case "restart":
|
|
4966
|
+
await handleRestart(api, options);
|
|
4967
|
+
break;
|
|
4968
|
+
case "resume":
|
|
4969
|
+
await handleResume(api, options);
|
|
4970
|
+
break;
|
|
4971
|
+
case "teardown":
|
|
4972
|
+
await handleTeardown(api, options);
|
|
4973
|
+
break;
|
|
4974
|
+
}
|
|
4975
|
+
} catch (error) {
|
|
4976
|
+
console.error(`Error: ${error}`);
|
|
4977
|
+
process.exit(1);
|
|
4978
|
+
}
|
|
4979
|
+
}
|
|
4980
|
+
function getStatusEmoji3(status) {
|
|
4981
|
+
const statusEmojis = {
|
|
4982
|
+
STARTING: "\u{1F504}",
|
|
4983
|
+
READY: "\u2705",
|
|
4984
|
+
SUSPENDED: "\u{1F4A4}",
|
|
4985
|
+
RESTARTING: "\u{1F504}",
|
|
4986
|
+
TEARDOWN: "\u{1F5D1}\uFE0F",
|
|
4987
|
+
ERROR: "\u274C"
|
|
4988
|
+
};
|
|
4989
|
+
return statusEmojis[status] || "\u2753";
|
|
4990
|
+
}
|
|
4991
|
+
async function handleStatus2(api, options) {
|
|
4992
|
+
const instance = await api.getTaskInstance(options.taskId);
|
|
4993
|
+
if (!instance) {
|
|
4994
|
+
console.log("\n\u26A0\uFE0F No preview environment found for this task");
|
|
4995
|
+
console.log(" The preview environment may not have been created yet,");
|
|
4996
|
+
console.log(" or the PR may be closed.");
|
|
4997
|
+
return;
|
|
4998
|
+
}
|
|
4999
|
+
const emoji = getStatusEmoji3(instance.status);
|
|
5000
|
+
console.log("\n\u{1F4E6} Preview Environment");
|
|
5001
|
+
console.log("\u2500".repeat(50));
|
|
5002
|
+
console.log(`${emoji} Status: ${instance.status}`);
|
|
5003
|
+
console.log(` ID: ${instance.id.substring(0, 8)}`);
|
|
5004
|
+
console.log(` Preview URL: ${instance.previewUrl}`);
|
|
5005
|
+
console.log(` SSH: ${instance.sshConnectionString}`);
|
|
5006
|
+
console.log(` Container: ${instance.containerId.substring(0, 12)}`);
|
|
5007
|
+
if (instance.lastActivityAt) {
|
|
5008
|
+
const lastActivity = new Date(instance.lastActivityAt);
|
|
5009
|
+
const minutesAgo = Math.round((Date.now() - lastActivity.getTime()) / 6e4);
|
|
5010
|
+
console.log(` Last Activity: ${minutesAgo} minutes ago`);
|
|
5011
|
+
}
|
|
5012
|
+
if (instance.suspendedAt) {
|
|
5013
|
+
const suspended = new Date(instance.suspendedAt);
|
|
5014
|
+
console.log(` Suspended At: ${suspended.toLocaleString()}`);
|
|
5015
|
+
}
|
|
5016
|
+
console.log(` Created: ${new Date(instance.createdAt).toLocaleString()}`);
|
|
5017
|
+
console.log("");
|
|
5018
|
+
}
|
|
5019
|
+
async function handleLogs(api, options) {
|
|
5020
|
+
const lines = options.lines || 100;
|
|
5021
|
+
if (options.follow) {
|
|
5022
|
+
const instance = await api.getTaskInstance(options.taskId);
|
|
5023
|
+
if (!instance) {
|
|
5024
|
+
console.error("No preview environment found for this task");
|
|
5025
|
+
process.exit(1);
|
|
5026
|
+
}
|
|
5027
|
+
console.log(`\u{1F4CB} Streaming logs from ${instance.previewUrl}...
|
|
5028
|
+
`);
|
|
5029
|
+
console.log(`(Press Ctrl+C to stop)
|
|
5030
|
+
`);
|
|
5031
|
+
const sshCommand = `docker logs -f ${instance.containerId}`;
|
|
5032
|
+
const ssh = (0, import_child_process2.spawn)("ssh", [
|
|
5033
|
+
"-o",
|
|
5034
|
+
"StrictHostKeyChecking=no",
|
|
5035
|
+
"-o",
|
|
5036
|
+
"UserKnownHostsFile=/dev/null",
|
|
5037
|
+
"-p",
|
|
5038
|
+
String(instance.sshPort),
|
|
5039
|
+
`${instance.sshUser}@${instance.sshHost}`,
|
|
5040
|
+
sshCommand
|
|
5041
|
+
]);
|
|
5042
|
+
ssh.stdout.pipe(process.stdout);
|
|
5043
|
+
ssh.stderr.pipe(process.stderr);
|
|
5044
|
+
ssh.on("close", (code) => {
|
|
5045
|
+
process.exit(code || 0);
|
|
5046
|
+
});
|
|
5047
|
+
process.on("SIGINT", () => {
|
|
5048
|
+
ssh.kill();
|
|
5049
|
+
process.exit(0);
|
|
5050
|
+
});
|
|
5051
|
+
return;
|
|
5052
|
+
}
|
|
5053
|
+
const result = await api.getInstanceLogs(options.taskId, lines);
|
|
5054
|
+
if (!result.logs) {
|
|
5055
|
+
console.log("No logs available");
|
|
5056
|
+
return;
|
|
5057
|
+
}
|
|
5058
|
+
console.log(result.logs);
|
|
5059
|
+
}
|
|
5060
|
+
async function handleMount(api, options) {
|
|
5061
|
+
const instance = await api.getTaskInstance(options.taskId);
|
|
5062
|
+
if (!instance) {
|
|
5063
|
+
console.error("No preview environment found for this task");
|
|
5064
|
+
process.exit(1);
|
|
5065
|
+
}
|
|
5066
|
+
if (instance.status === "SUSPENDED") {
|
|
5067
|
+
console.log("\u23F8\uFE0F Instance is suspended. Resuming...");
|
|
5068
|
+
await api.resumeInstance(options.taskId);
|
|
5069
|
+
await new Promise((resolve) => setTimeout(resolve, 3e3));
|
|
5070
|
+
}
|
|
5071
|
+
try {
|
|
5072
|
+
(0, import_child_process2.execSync)("which sshfs", { stdio: "ignore" });
|
|
5073
|
+
} catch {
|
|
5074
|
+
console.error("\u274C sshfs is not installed.");
|
|
5075
|
+
console.error("");
|
|
5076
|
+
console.error("Install it with:");
|
|
5077
|
+
if (process.platform === "darwin") {
|
|
5078
|
+
console.error(" brew install macfuse sshfs");
|
|
5079
|
+
} else if (process.platform === "linux") {
|
|
5080
|
+
console.error(" sudo apt install sshfs");
|
|
5081
|
+
} else {
|
|
5082
|
+
console.error(" SSHFS is not supported on this platform");
|
|
5083
|
+
}
|
|
5084
|
+
process.exit(1);
|
|
5085
|
+
}
|
|
5086
|
+
const mountDir = options.directory || path3.join(os3.homedir(), "flightdesk-mounts", options.taskId.substring(0, 8));
|
|
5087
|
+
if (!fs4.existsSync(mountDir)) {
|
|
5088
|
+
fs4.mkdirSync(mountDir, { recursive: true });
|
|
5089
|
+
}
|
|
5090
|
+
try {
|
|
5091
|
+
const mounted = (0, import_child_process2.execSync)("mount", { encoding: "utf8" });
|
|
5092
|
+
if (mounted.includes(mountDir)) {
|
|
5093
|
+
console.log(`\u{1F4C1} Already mounted at ${mountDir}`);
|
|
5094
|
+
return;
|
|
5095
|
+
}
|
|
5096
|
+
} catch {
|
|
5097
|
+
}
|
|
5098
|
+
console.log(`\u{1F4C1} Mounting preview environment to ${mountDir}...`);
|
|
5099
|
+
const sshfsCmd = [
|
|
5100
|
+
"sshfs",
|
|
5101
|
+
"-o",
|
|
5102
|
+
"StrictHostKeyChecking=no",
|
|
5103
|
+
"-o",
|
|
5104
|
+
"UserKnownHostsFile=/dev/null",
|
|
5105
|
+
"-o",
|
|
5106
|
+
"reconnect",
|
|
5107
|
+
"-o",
|
|
5108
|
+
"ServerAliveInterval=15",
|
|
5109
|
+
"-o",
|
|
5110
|
+
"ServerAliveCountMax=3",
|
|
5111
|
+
"-p",
|
|
5112
|
+
String(instance.sshPort),
|
|
5113
|
+
`${instance.sshUser}@${instance.sshHost}:/app`,
|
|
5114
|
+
mountDir
|
|
5115
|
+
];
|
|
5116
|
+
try {
|
|
5117
|
+
(0, import_child_process2.execSync)(sshfsCmd.join(" "), { stdio: "inherit" });
|
|
5118
|
+
console.log("");
|
|
5119
|
+
console.log("\u2705 Mounted successfully!");
|
|
5120
|
+
console.log(` Location: ${mountDir}`);
|
|
5121
|
+
console.log("");
|
|
5122
|
+
console.log(" To unmount:");
|
|
5123
|
+
console.log(` fd preview unmount ${options.taskId}`);
|
|
5124
|
+
console.log("");
|
|
5125
|
+
console.log(" Or manually:");
|
|
5126
|
+
if (process.platform === "darwin") {
|
|
5127
|
+
console.log(` umount ${mountDir}`);
|
|
5128
|
+
} else {
|
|
5129
|
+
console.log(` fusermount -u ${mountDir}`);
|
|
5130
|
+
}
|
|
5131
|
+
} catch (error) {
|
|
5132
|
+
console.error(`\u274C Mount failed: ${error}`);
|
|
5133
|
+
process.exit(1);
|
|
5134
|
+
}
|
|
5135
|
+
}
|
|
5136
|
+
async function handleUnmount(_api, options) {
|
|
5137
|
+
const mountDir = path3.join(os3.homedir(), "flightdesk-mounts", options.taskId.substring(0, 8));
|
|
5138
|
+
if (!fs4.existsSync(mountDir)) {
|
|
5139
|
+
console.log("Mount directory does not exist");
|
|
5140
|
+
return;
|
|
5141
|
+
}
|
|
5142
|
+
console.log(`\u{1F4C1} Unmounting ${mountDir}...`);
|
|
5143
|
+
try {
|
|
5144
|
+
if (process.platform === "darwin") {
|
|
5145
|
+
(0, import_child_process2.execSync)(`umount ${mountDir}`, { stdio: "inherit" });
|
|
5146
|
+
} else {
|
|
5147
|
+
(0, import_child_process2.execSync)(`fusermount -u ${mountDir}`, { stdio: "inherit" });
|
|
5148
|
+
}
|
|
5149
|
+
console.log("\u2705 Unmounted successfully");
|
|
5150
|
+
try {
|
|
5151
|
+
fs4.rmdirSync(mountDir);
|
|
5152
|
+
} catch {
|
|
5153
|
+
}
|
|
5154
|
+
} catch (error) {
|
|
5155
|
+
console.error(`\u274C Unmount failed: ${error}`);
|
|
5156
|
+
console.error("");
|
|
5157
|
+
console.error("Try force unmounting:");
|
|
5158
|
+
if (process.platform === "darwin") {
|
|
5159
|
+
console.error(` diskutil unmount force ${mountDir}`);
|
|
5160
|
+
} else {
|
|
5161
|
+
console.error(` fusermount -uz ${mountDir}`);
|
|
5162
|
+
}
|
|
5163
|
+
process.exit(1);
|
|
5164
|
+
}
|
|
5165
|
+
}
|
|
5166
|
+
async function handleRestart(api, options) {
|
|
5167
|
+
console.log("\u{1F504} Restarting preview environment...");
|
|
5168
|
+
await api.restartInstance(options.taskId);
|
|
5169
|
+
console.log("\u2705 Restart initiated. The preview will be available shortly.");
|
|
5170
|
+
}
|
|
5171
|
+
async function handleResume(api, options) {
|
|
5172
|
+
console.log("\u25B6\uFE0F Resuming preview environment...");
|
|
5173
|
+
await api.resumeInstance(options.taskId);
|
|
5174
|
+
console.log("\u2705 Resume initiated. The preview should be ready in about 30 seconds.");
|
|
5175
|
+
}
|
|
5176
|
+
async function handleTeardown(api, options) {
|
|
5177
|
+
console.log("\u{1F5D1}\uFE0F Tearing down preview environment...");
|
|
5178
|
+
await api.tearDownInstance(options.taskId);
|
|
5179
|
+
console.log("\u2705 Preview environment has been torn down.");
|
|
5180
|
+
}
|
|
5181
|
+
|
|
4881
5182
|
// apps/cli/src/main.ts
|
|
4882
5183
|
var program2 = new Command();
|
|
4883
|
-
program2.name("flightdesk").description("FlightDesk CLI - AI task management for Claude Code sessions").version("0.
|
|
5184
|
+
program2.name("flightdesk").description("FlightDesk CLI - AI task management for Claude Code sessions").version("0.2.0").option("--dev", "Use local development API (localhost:3000)").option("--api <url>", "Use custom API URL");
|
|
4884
5185
|
program2.hook("preAction", () => {
|
|
4885
5186
|
const opts = program2.opts();
|
|
4886
5187
|
if (opts.api) {
|
|
@@ -4912,20 +5213,16 @@ org.command("switch <name>").description("Switch active organization").action(or
|
|
|
4912
5213
|
org.command("refresh").description("Refresh organizations from API").action(orgRefreshCommand);
|
|
4913
5214
|
program2.command("context").description("Show current repository context and mapped organization").action(contextCommand);
|
|
4914
5215
|
program2.command("sync").description("Refresh project-to-repository mappings from all organizations").action(syncCommand);
|
|
4915
|
-
program2.command("
|
|
4916
|
-
|
|
4917
|
-
|
|
4918
|
-
|
|
4919
|
-
|
|
4920
|
-
|
|
4921
|
-
});
|
|
4922
|
-
|
|
4923
|
-
|
|
4924
|
-
|
|
4925
|
-
});
|
|
4926
|
-
program2.command("logs <task-id>").description("Stream logs from a preview environment").option("-f, --follow", "Follow log output").option("--process <name>", "Filter by process name").action((taskId) => {
|
|
4927
|
-
console.log("\u26A0\uFE0F Logs command requires preview environments (Phase 9)");
|
|
4928
|
-
console.log(` Task ID: ${taskId}`);
|
|
4929
|
-
});
|
|
5216
|
+
var preview = program2.command("preview").description("Preview environment management");
|
|
5217
|
+
preview.command("status <task-id>").description("Show preview environment status").action((taskId) => previewCommand("status", { taskId }));
|
|
5218
|
+
preview.command("logs <task-id>").description("Get logs from preview environment").option("-n, --lines <lines>", "Number of log lines", "100").option("-f, --follow", "Follow log output").action((taskId, options) => previewCommand("logs", { taskId, lines: parseInt(options.lines || "100"), follow: options.follow }));
|
|
5219
|
+
preview.command("mount <task-id>").description("Mount preview environment filesystem via SSHFS").option("-d, --directory <path>", "Custom mount directory").action((taskId, options) => previewCommand("mount", { taskId, directory: options.directory }));
|
|
5220
|
+
preview.command("unmount <task-id>").description("Unmount preview environment filesystem").action((taskId) => previewCommand("unmount", { taskId }));
|
|
5221
|
+
preview.command("restart <task-id>").description("Restart preview environment processes").action((taskId) => previewCommand("restart", { taskId }));
|
|
5222
|
+
preview.command("resume <task-id>").description("Resume a suspended preview environment").action((taskId) => previewCommand("resume", { taskId }));
|
|
5223
|
+
preview.command("teardown <task-id>").description("Tear down preview environment").action((taskId) => previewCommand("teardown", { taskId }));
|
|
5224
|
+
program2.command("mount <task-id>").description('Mount preview environment filesystem (shorthand for "preview mount")').option("-d, --directory <path>", "Custom mount directory").action((taskId, options) => previewCommand("mount", { taskId, directory: options.directory }));
|
|
5225
|
+
program2.command("unmount <task-id>").description('Unmount preview environment filesystem (shorthand for "preview unmount")').action((taskId) => previewCommand("unmount", { taskId }));
|
|
5226
|
+
program2.command("logs <task-id>").description('Get logs from preview environment (shorthand for "preview logs")').option("-n, --lines <lines>", "Number of log lines", "100").option("-f, --follow", "Follow log output").action((taskId, options) => previewCommand("logs", { taskId, lines: parseInt(options.lines || "100"), follow: options.follow }));
|
|
4930
5227
|
program2.parse();
|
|
4931
5228
|
//# sourceMappingURL=main.js.map
|