flightdesk 0.1.11 → 0.1.13

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.
Files changed (3) hide show
  1. package/main.js +94 -8
  2. package/main.js.map +4 -4
  3. package/package.json +1 -1
package/main.js CHANGED
@@ -3935,17 +3935,30 @@ async function watchCommand(options) {
3935
3935
  try {
3936
3936
  const tasks = await api.listTasks();
3937
3937
  const activeTasks = tasks.filter(
3938
- (t) => ["DISPATCHED", "IN_PROGRESS", "BRANCH_CREATED"].includes(t.status)
3938
+ (t) => ["DISPATCHED", "IN_PROGRESS", "BRANCH_CREATED"].includes(t.status) || t.status === "PENDING" && t.sessionViewUrl
3939
3939
  );
3940
3940
  if (activeTasks.length === 0) {
3941
3941
  console.log(" No active tasks to monitor");
3942
3942
  return;
3943
3943
  }
3944
+ const needsReconciliation = activeTasks.filter((t) => {
3945
+ if (t.prUrl && !["PR_OPEN", "MERGED", "ARCHIVED"].includes(t.status)) return true;
3946
+ if (t.branchName && t.status === "PENDING") return true;
3947
+ if (t.sessionViewUrl && t.status === "PENDING") return true;
3948
+ return false;
3949
+ });
3950
+ if (needsReconciliation.length > 0) {
3951
+ console.log(` \u26A0\uFE0F ${needsReconciliation.length} task(s) need status reconciliation`);
3952
+ }
3944
3953
  console.log(` Found ${activeTasks.length} active task(s)`);
3945
3954
  for (const task2 of activeTasks) {
3946
3955
  console.log(`
3947
3956
  \u{1F4CB} ${task2.title}`);
3948
3957
  console.log(` Status: ${task2.status}`);
3958
+ const reconciled = await reconcileTaskStatus(api, task2);
3959
+ if (reconciled) {
3960
+ continue;
3961
+ }
3949
3962
  if (task2.sessionViewUrl && playwrightAvailable) {
3950
3963
  console.log(` Checking session...`);
3951
3964
  const sessionInfo = await monitorSession(task2.sessionViewUrl, {
@@ -3979,6 +3992,39 @@ Watching... (Ctrl+C to stop)
3979
3992
  await new Promise((_resolve) => {
3980
3993
  });
3981
3994
  }
3995
+ async function reconcileTaskStatus(api, task2) {
3996
+ let expectedStatus = null;
3997
+ let reason = "";
3998
+ if (task2.prUrl) {
3999
+ if (!["PR_OPEN", "MERGED", "ARCHIVED", "REVIEW_RUNNING", "REVIEW_DONE", "QA_READY", "QA_APPROVED"].includes(task2.status)) {
4000
+ expectedStatus = "PR_OPEN";
4001
+ reason = `has PR URL but status is ${task2.status}`;
4002
+ }
4003
+ } else if (task2.branchName) {
4004
+ if (["PENDING", "DISPATCHED"].includes(task2.status)) {
4005
+ expectedStatus = "IN_PROGRESS";
4006
+ reason = `has branch but status is ${task2.status}`;
4007
+ }
4008
+ } else if (task2.sessionViewUrl) {
4009
+ if (task2.status === "PENDING") {
4010
+ expectedStatus = "DISPATCHED";
4011
+ reason = `has session URL but status is PENDING`;
4012
+ }
4013
+ }
4014
+ if (expectedStatus) {
4015
+ console.log(` \u{1F527} Status reconciliation: ${reason}`);
4016
+ console.log(` Updating: ${task2.status} \u2192 ${expectedStatus}`);
4017
+ try {
4018
+ await api.updateTask(task2.id, { status: expectedStatus });
4019
+ console.log(" \u2705 Status reconciled");
4020
+ return true;
4021
+ } catch (error) {
4022
+ console.log(` \u274C Failed to reconcile: ${error}`);
4023
+ return false;
4024
+ }
4025
+ }
4026
+ return false;
4027
+ }
3982
4028
  async function processSessionInfo(api, task2, info) {
3983
4029
  if (info.status === "error") {
3984
4030
  console.log(` \u274C Error: ${info.error}`);
@@ -4380,9 +4426,9 @@ async function syncCommand() {
4380
4426
  const api = FlightDeskAPI.fromConfig(config, org2);
4381
4427
  const projects = await api.listProjects();
4382
4428
  console.log(` Found ${projects.length} project(s)`);
4383
- for (const project of projects) {
4384
- if (project.githubRepo) {
4385
- newMappings[project.githubRepo] = org2.id;
4429
+ for (const project2 of projects) {
4430
+ if (project2.githubRepo) {
4431
+ newMappings[project2.githubRepo] = org2.id;
4386
4432
  totalProjects++;
4387
4433
  }
4388
4434
  }
@@ -4669,16 +4715,23 @@ Summary:`);
4669
4715
  `);
4670
4716
  let created = 0;
4671
4717
  let failed = 0;
4672
- for (const { session, project } of importableSessions) {
4718
+ for (const { session, project: project2 } of importableSessions) {
4673
4719
  try {
4674
4720
  const task2 = await api.createTask({
4675
- projectId: project.id,
4721
+ projectId: project2.id,
4676
4722
  title: session.title,
4677
4723
  description: `Imported from Claude Code session`
4678
4724
  });
4725
+ let status = "DISPATCHED";
4726
+ if (session.archived) {
4727
+ status = "ARCHIVED";
4728
+ } else if (session.branchName) {
4729
+ status = "IN_PROGRESS";
4730
+ }
4679
4731
  await api.updateTask(task2.id, {
4680
4732
  branchName: session.branchName,
4681
- sessionViewUrl: session.url
4733
+ sessionViewUrl: session.url,
4734
+ status
4682
4735
  });
4683
4736
  console.log(` \u2705 ${session.title.slice(0, 50)}`);
4684
4737
  created++;
@@ -4794,9 +4847,40 @@ async function scanClaudeSessions(options) {
4794
4847
  }
4795
4848
  }
4796
4849
 
4850
+ // apps/cli/src/commands/project.ts
4851
+ async function projectCommand(action, options) {
4852
+ const { config, org: org2 } = requireActiveOrg();
4853
+ const api = FlightDeskAPI.fromConfig(config, org2);
4854
+ switch (action) {
4855
+ case "list":
4856
+ await listProjects(api);
4857
+ break;
4858
+ default:
4859
+ console.error(`Unknown action: ${action}`);
4860
+ process.exit(1);
4861
+ }
4862
+ }
4863
+ async function listProjects(api) {
4864
+ const projects = await api.listProjects();
4865
+ if (projects.length === 0) {
4866
+ console.log("No projects found.");
4867
+ console.log("\nCreate a project at https://app.flightdesk.dev/app/projects/new");
4868
+ return;
4869
+ }
4870
+ console.log("Projects:\n");
4871
+ const maxNameLen = Math.max(...projects.map((p) => p.name.length), 4);
4872
+ for (const project2 of projects) {
4873
+ const name = project2.name.padEnd(maxNameLen);
4874
+ const repo = project2.githubRepo || "(no repo)";
4875
+ console.log(` ${project2.id} ${name} ${repo}`);
4876
+ }
4877
+ console.log(`
4878
+ ${projects.length} project(s)`);
4879
+ }
4880
+
4797
4881
  // apps/cli/src/main.ts
4798
4882
  var program2 = new Command();
4799
- program2.name("flightdesk").description("FlightDesk CLI - AI task management for Claude Code sessions").version("0.1.11").option("--dev", "Use local development API (localhost:3000)").option("--api <url>", "Use custom API URL");
4883
+ program2.name("flightdesk").description("FlightDesk CLI - AI task management for Claude Code sessions").version("0.1.13").option("--dev", "Use local development API (localhost:3000)").option("--api <url>", "Use custom API URL");
4800
4884
  program2.hook("preAction", () => {
4801
4885
  const opts = program2.opts();
4802
4886
  if (opts.api) {
@@ -4811,6 +4895,8 @@ program2.hook("preAction", () => {
4811
4895
  program2.command("init").description("Configure FlightDesk CLI with your API credentials").action(initCommand);
4812
4896
  program2.command("auth").description("Log in to Claude for session monitoring").action(authCommand);
4813
4897
  program2.command("register <project-id> [task-id]").description("Register a Claude Code session with a FlightDesk task").option("--view-url <url>", "Claude Code session view URL").option("--teleport-id <id>", "Claude Code teleport ID").option("--title <title>", "Task title (creates new task if task-id not provided)").option("--description <description>", "Task description").action(registerCommand);
4898
+ var project = program2.command("project").description("Project management commands");
4899
+ project.command("list").description("List projects in the active organization").action(() => projectCommand("list", {}));
4814
4900
  var task = program2.command("task").description("Task management commands");
4815
4901
  task.command("create").description("Create a new task").requiredOption("-p, --project <id>", "Project ID").requiredOption("-t, --title <title>", "Task title").option("-d, --description <description>", "Task description").action((options) => taskCommand("create", options));
4816
4902
  task.command("list").description("List tasks").option("-p, --project <id>", "Filter by project ID").option("--status <status>", "Filter by status").action((options) => taskCommand("list", options));