agor-live 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.
Files changed (81) hide show
  1. package/dist/cli/base-command.js +103 -9
  2. package/dist/cli/commands/auth/login.d.ts +18 -0
  3. package/dist/cli/commands/auth/login.js +133 -0
  4. package/dist/cli/commands/auth/logout.d.ts +15 -0
  5. package/dist/cli/commands/auth/logout.js +51 -0
  6. package/dist/cli/commands/auth/whoami.d.ts +15 -0
  7. package/dist/cli/commands/auth/whoami.js +67 -0
  8. package/dist/cli/commands/board/add-session.d.ts +4 -3
  9. package/dist/cli/commands/board/add-session.js +154 -33
  10. package/dist/cli/commands/board/list.d.ts +4 -3
  11. package/dist/cli/commands/board/list.js +148 -32
  12. package/dist/cli/commands/login.d.ts +16 -0
  13. package/dist/cli/commands/login.js +139 -0
  14. package/dist/cli/commands/logout.d.ts +15 -0
  15. package/dist/cli/commands/logout.js +57 -0
  16. package/dist/cli/commands/mcp/add.d.ts +4 -2
  17. package/dist/cli/commands/mcp/add.js +154 -36
  18. package/dist/cli/commands/mcp/list.d.ts +4 -3
  19. package/dist/cli/commands/mcp/list.js +154 -29
  20. package/dist/cli/commands/mcp/remove.d.ts +4 -3
  21. package/dist/cli/commands/mcp/remove.js +149 -36
  22. package/dist/cli/commands/mcp/show.d.ts +4 -3
  23. package/dist/cli/commands/mcp/show.js +169 -45
  24. package/dist/cli/commands/repo/add.d.ts +4 -2
  25. package/dist/cli/commands/repo/add.js +167 -41
  26. package/dist/cli/commands/repo/list.d.ts +4 -2
  27. package/dist/cli/commands/repo/list.js +154 -29
  28. package/dist/cli/commands/repo/rm.d.ts +4 -2
  29. package/dist/cli/commands/repo/rm.js +155 -29
  30. package/dist/cli/commands/session/list.js +103 -9
  31. package/dist/cli/commands/session/load-claude.d.ts +4 -2
  32. package/dist/cli/commands/session/load-claude.js +160 -40
  33. package/dist/cli/commands/user/create.d.ts +4 -2
  34. package/dist/cli/commands/user/create.js +153 -30
  35. package/dist/cli/commands/user/delete.d.ts +4 -2
  36. package/dist/cli/commands/user/delete.js +157 -25
  37. package/dist/cli/commands/user/update.d.ts +4 -2
  38. package/dist/cli/commands/user/update.js +162 -30
  39. package/dist/cli/commands/whoami.d.ts +15 -0
  40. package/dist/cli/commands/whoami.js +73 -0
  41. package/dist/cli/commands/worktree/add.d.ts +4 -2
  42. package/dist/cli/commands/worktree/add.js +150 -24
  43. package/dist/cli/commands/worktree/env/restart.js +103 -9
  44. package/dist/cli/commands/worktree/env/start.js +103 -9
  45. package/dist/cli/commands/worktree/env/status.js +103 -9
  46. package/dist/cli/commands/worktree/env/stop.js +103 -9
  47. package/dist/cli/commands/worktree/list.d.ts +4 -2
  48. package/dist/cli/commands/worktree/list.js +154 -27
  49. package/dist/cli/commands/worktree/rm.js +103 -9
  50. package/dist/cli/commands/worktree/show.js +103 -9
  51. package/dist/cli/commands/worktree/update.js +103 -9
  52. package/dist/cli/lib/auth.d.ts +29 -0
  53. package/dist/cli/lib/auth.js +37 -0
  54. package/dist/core/api/index.cjs +17 -0
  55. package/dist/core/api/index.d.cts +8 -1
  56. package/dist/core/api/index.d.ts +8 -1
  57. package/dist/core/api/index.js +16 -0
  58. package/dist/core/config/browser.d.cts +2 -0
  59. package/dist/core/config/browser.d.ts +2 -0
  60. package/dist/core/db/index.cjs +1 -1
  61. package/dist/core/db/index.js +1 -1
  62. package/dist/core/git/index.cjs +1 -14
  63. package/dist/core/git/index.d.cts +1 -14
  64. package/dist/core/git/index.d.ts +1 -14
  65. package/dist/core/git/index.js +1 -13
  66. package/dist/core/index.cjs +19 -15
  67. package/dist/core/index.d.cts +2 -2
  68. package/dist/core/index.d.ts +2 -2
  69. package/dist/core/index.js +18 -14
  70. package/dist/core/tools/index.cjs +31 -6
  71. package/dist/core/tools/index.js +31 -6
  72. package/dist/core/utils/cron.cjs +1 -1
  73. package/dist/core/utils/cron.js +1 -1
  74. package/dist/daemon/index.js +62 -106
  75. package/dist/daemon/services/context.js +3 -4
  76. package/dist/daemon/services/mcp-servers.d.ts +2 -7
  77. package/dist/daemon/services/scheduler.js +4 -84
  78. package/dist/daemon/services/worktrees.d.ts +2 -13
  79. package/dist/ui/assets/{index-B_3eFhE9.js → index-CDYLQXZ8.js} +127 -127
  80. package/dist/ui/index.html +1 -1
  81. package/package.json +1 -1
@@ -1,5 +1,61 @@
1
+ var __defProp = Object.defineProperty;
2
+ var __getOwnPropNames = Object.getOwnPropertyNames;
3
+ var __esm = (fn, res) => function __init() {
4
+ return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
5
+ };
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+
11
+ // src/lib/auth.ts
12
+ var auth_exports = {};
13
+ __export(auth_exports, {
14
+ clearToken: () => clearToken,
15
+ loadToken: () => loadToken,
16
+ saveToken: () => saveToken
17
+ });
18
+ import { mkdir, readFile, unlink, writeFile } from "fs/promises";
19
+ import { homedir } from "os";
20
+ import { join } from "path";
21
+ async function saveToken(auth) {
22
+ await mkdir(AGOR_DIR, { recursive: true });
23
+ await writeFile(TOKEN_FILE, JSON.stringify(auth, null, 2), {
24
+ mode: 384
25
+ // Owner read/write only
26
+ });
27
+ }
28
+ async function loadToken() {
29
+ try {
30
+ const data = await readFile(TOKEN_FILE, "utf-8");
31
+ const auth = JSON.parse(data);
32
+ if (auth.expiresAt && Date.now() > auth.expiresAt) {
33
+ await clearToken();
34
+ return null;
35
+ }
36
+ return auth;
37
+ } catch {
38
+ return null;
39
+ }
40
+ }
41
+ async function clearToken() {
42
+ try {
43
+ await unlink(TOKEN_FILE);
44
+ } catch {
45
+ }
46
+ }
47
+ var AGOR_DIR, TOKEN_FILE;
48
+ var init_auth = __esm({
49
+ "src/lib/auth.ts"() {
50
+ "use strict";
51
+ AGOR_DIR = join(homedir(), ".agor");
52
+ TOKEN_FILE = join(AGOR_DIR, "cli-token");
53
+ }
54
+ });
55
+
1
56
  // src/base-command.ts
2
- import { createClient, isDaemonRunning } from "@agor/core/api";
57
+ init_auth();
58
+ import { createRestClient, isDaemonRunning } from "@agor/core/api";
3
59
  import { getDaemonUrl } from "@agor/core/config";
4
60
  import { Command } from "@oclif/core";
5
61
  import chalk from "chalk";
@@ -19,7 +75,48 @@ var BaseCommand = class extends Command {
19
75
  );
20
76
  this.exit(1);
21
77
  }
22
- return createClient(this.daemonUrl, true, { verbose: false });
78
+ const client = await createRestClient(this.daemonUrl);
79
+ const storedAuth = await loadToken();
80
+ if (storedAuth) {
81
+ try {
82
+ await client.authenticate({
83
+ strategy: "jwt",
84
+ accessToken: storedAuth.accessToken
85
+ });
86
+ } catch (_error) {
87
+ const { clearToken: clearToken2 } = await Promise.resolve().then(() => (init_auth(), auth_exports));
88
+ await clearToken2();
89
+ this.error(
90
+ chalk.red("\u2717 Authentication failed") + "\n\n" + chalk.dim("Your session has expired or is invalid.") + "\n" + chalk.dim("Please login again:") + "\n " + chalk.cyan("agor login")
91
+ );
92
+ }
93
+ } else {
94
+ try {
95
+ const response = await fetch(`${this.daemonUrl}/health`);
96
+ const health = await response.json();
97
+ if (health.auth?.requireAuth) {
98
+ this.error(
99
+ chalk.red("\u2717 Not authenticated") + "\n\n" + chalk.dim("This Agor instance requires authentication.") + "\n" + chalk.dim("Please login:") + "\n " + chalk.cyan("agor login")
100
+ );
101
+ }
102
+ try {
103
+ await client.authenticate({ strategy: "anonymous" });
104
+ } catch (_authError) {
105
+ this.error(
106
+ chalk.red("\u2717 Authentication failed") + "\n\n" + chalk.dim("Please login:") + "\n " + chalk.cyan("agor login")
107
+ );
108
+ }
109
+ } catch (_error) {
110
+ try {
111
+ await client.authenticate({ strategy: "anonymous" });
112
+ } catch {
113
+ this.error(
114
+ chalk.red("\u2717 Not authenticated") + "\n\n" + chalk.dim("Please login to use the Agor CLI:") + "\n " + chalk.cyan("agor login")
115
+ );
116
+ }
117
+ }
118
+ }
119
+ return client;
23
120
  }
24
121
  /**
25
122
  * Cleanup client connection
@@ -27,13 +124,10 @@ var BaseCommand = class extends Command {
27
124
  * Ensures socket is properly closed to prevent hanging processes
28
125
  */
29
126
  async cleanupClient(client) {
30
- await new Promise((resolve) => {
31
- client.io.once("disconnect", () => resolve());
32
- client.io.removeAllListeners("connect");
33
- client.io.removeAllListeners("connect_error");
34
- client.io.close();
35
- setTimeout(resolve, 1e3);
36
- });
127
+ client.io.io.opts.reconnection = false;
128
+ client.io.removeAllListeners();
129
+ client.io.close();
130
+ await new Promise((resolve) => setTimeout(resolve, 100));
37
131
  }
38
132
  };
39
133
  export {
@@ -0,0 +1,18 @@
1
+ import * as _oclif_core_interfaces from '@oclif/core/interfaces';
2
+ import { Command } from '@oclif/core';
3
+
4
+ declare class Login extends Command {
5
+ static description: string;
6
+ static examples: string[];
7
+ static flags: {
8
+ email: _oclif_core_interfaces.OptionFlag<string | undefined, _oclif_core_interfaces.CustomOptions>;
9
+ password: _oclif_core_interfaces.OptionFlag<string | undefined, _oclif_core_interfaces.CustomOptions>;
10
+ };
11
+ run(): Promise<void>;
12
+ /**
13
+ * Prompt helper with proper typing
14
+ */
15
+ private prompt;
16
+ }
17
+
18
+ export { Login as default };
@@ -0,0 +1,133 @@
1
+ // src/commands/auth/login.ts
2
+ import * as readline from "readline";
3
+ import { createRestClient, isDaemonRunning } from "@agor/core/api";
4
+ import { getDaemonUrl } from "@agor/core/config";
5
+ import { Command, Flags } from "@oclif/core";
6
+ import chalk from "chalk";
7
+
8
+ // src/lib/auth.ts
9
+ import { mkdir, readFile, unlink, writeFile } from "fs/promises";
10
+ import { homedir } from "os";
11
+ import { join } from "path";
12
+ var AGOR_DIR = join(homedir(), ".agor");
13
+ var TOKEN_FILE = join(AGOR_DIR, "cli-token");
14
+ async function saveToken(auth) {
15
+ await mkdir(AGOR_DIR, { recursive: true });
16
+ await writeFile(TOKEN_FILE, JSON.stringify(auth, null, 2), {
17
+ mode: 384
18
+ // Owner read/write only
19
+ });
20
+ }
21
+
22
+ // src/commands/auth/login.ts
23
+ var Login = class _Login extends Command {
24
+ static description = "Authenticate with Agor daemon";
25
+ static examples = [
26
+ "<%= config.bin %> <%= command.id %>",
27
+ "<%= config.bin %> <%= command.id %> --email user@example.com"
28
+ ];
29
+ static flags = {
30
+ email: Flags.string({
31
+ char: "e",
32
+ description: "Email address"
33
+ }),
34
+ password: Flags.string({
35
+ char: "p",
36
+ description: "Password (will prompt if not provided)"
37
+ })
38
+ };
39
+ async run() {
40
+ const { flags } = await this.parse(_Login);
41
+ const daemonUrl = await getDaemonUrl();
42
+ const running = await isDaemonRunning(daemonUrl);
43
+ if (!running) {
44
+ this.error(
45
+ chalk.red("\u2717 Daemon not running") + "\n\n" + chalk.bold("To start the daemon:") + "\n " + chalk.cyan("cd apps/agor-daemon && pnpm dev")
46
+ );
47
+ }
48
+ const email = flags.email || await this.prompt("Email", {
49
+ type: "input",
50
+ required: true
51
+ });
52
+ const password = flags.password || await this.prompt("Password", {
53
+ type: "hide",
54
+ required: true
55
+ });
56
+ const client = await createRestClient(daemonUrl);
57
+ try {
58
+ this.log(chalk.dim("Authenticating..."));
59
+ const authResult = await client.authenticate({
60
+ strategy: "local",
61
+ email,
62
+ password
63
+ });
64
+ if (!authResult.accessToken || !authResult.user) {
65
+ this.error("Authentication failed - no token returned");
66
+ }
67
+ const expiresAt = Date.now() + 7 * 24 * 60 * 60 * 1e3;
68
+ await saveToken({
69
+ accessToken: authResult.accessToken,
70
+ user: {
71
+ user_id: authResult.user.user_id,
72
+ email: authResult.user.email,
73
+ // biome-ignore lint/suspicious/noExplicitAny: AuthenticatedUser type doesn't include name, but it's returned
74
+ name: authResult.user.name,
75
+ role: authResult.user.role || "viewer"
76
+ },
77
+ expiresAt
78
+ });
79
+ this.log("");
80
+ this.log(chalk.green("\u2713 Logged in successfully"));
81
+ this.log("");
82
+ this.log(chalk.dim("User:"), chalk.cyan(authResult.user.email));
83
+ const userName = authResult.user.name;
84
+ if (userName) {
85
+ this.log(chalk.dim("Name:"), userName);
86
+ }
87
+ this.log(chalk.dim("Role:"), authResult.user.role || "viewer");
88
+ this.log("");
89
+ this.log(chalk.dim("Token saved to ~/.agor/cli-token"));
90
+ this.log(chalk.dim("Token expires in 7 days"));
91
+ this.log("");
92
+ client.io.io.opts.reconnection = false;
93
+ client.io.removeAllListeners();
94
+ client.io.close();
95
+ process.exit(0);
96
+ } catch (error) {
97
+ client.io.io.opts.reconnection = false;
98
+ client.io.removeAllListeners();
99
+ client.io.close();
100
+ const errorMessage = error instanceof Error ? error.message : String(error);
101
+ if (errorMessage.includes("Invalid login") || errorMessage.includes("NotFound")) {
102
+ this.error(chalk.red("\u2717 Invalid email or password"));
103
+ }
104
+ this.error(chalk.red(`\u2717 Authentication failed: ${errorMessage}`));
105
+ }
106
+ }
107
+ /**
108
+ * Prompt helper with proper typing
109
+ */
110
+ async prompt(message, options) {
111
+ return new Promise((resolve) => {
112
+ const rl = readline.createInterface({
113
+ input: process.stdin,
114
+ output: process.stdout
115
+ });
116
+ const hiddenOutput = options.type === "hide";
117
+ if (hiddenOutput && process.stdin.isTTY) {
118
+ process.stdin.setRawMode?.(true);
119
+ }
120
+ rl.question(`${message}: `, (answer) => {
121
+ if (hiddenOutput && process.stdin.isTTY) {
122
+ process.stdin.setRawMode?.(false);
123
+ console.log("");
124
+ }
125
+ rl.close();
126
+ resolve(answer.trim());
127
+ });
128
+ });
129
+ }
130
+ };
131
+ export {
132
+ Login as default
133
+ };
@@ -0,0 +1,15 @@
1
+ import { Command } from '@oclif/core';
2
+
3
+ /**
4
+ * `agor logout` - Clear stored authentication token
5
+ *
6
+ * Removes JWT token from disk
7
+ */
8
+
9
+ declare class Logout extends Command {
10
+ static description: string;
11
+ static examples: string[];
12
+ run(): Promise<void>;
13
+ }
14
+
15
+ export { Logout as default };
@@ -0,0 +1,51 @@
1
+ // src/commands/auth/logout.ts
2
+ import { Command } from "@oclif/core";
3
+ import chalk from "chalk";
4
+
5
+ // src/lib/auth.ts
6
+ import { mkdir, readFile, unlink, writeFile } from "fs/promises";
7
+ import { homedir } from "os";
8
+ import { join } from "path";
9
+ var AGOR_DIR = join(homedir(), ".agor");
10
+ var TOKEN_FILE = join(AGOR_DIR, "cli-token");
11
+ async function loadToken() {
12
+ try {
13
+ const data = await readFile(TOKEN_FILE, "utf-8");
14
+ const auth = JSON.parse(data);
15
+ if (auth.expiresAt && Date.now() > auth.expiresAt) {
16
+ await clearToken();
17
+ return null;
18
+ }
19
+ return auth;
20
+ } catch {
21
+ return null;
22
+ }
23
+ }
24
+ async function clearToken() {
25
+ try {
26
+ await unlink(TOKEN_FILE);
27
+ } catch {
28
+ }
29
+ }
30
+
31
+ // src/commands/auth/logout.ts
32
+ var Logout = class extends Command {
33
+ static description = "Logout and clear stored authentication token";
34
+ static examples = ["<%= config.bin %> <%= command.id %>"];
35
+ async run() {
36
+ const storedAuth = await loadToken();
37
+ if (!storedAuth) {
38
+ this.log(chalk.dim("Not currently logged in"));
39
+ return;
40
+ }
41
+ await clearToken();
42
+ this.log("");
43
+ this.log(chalk.green("\u2713 Logged out successfully"));
44
+ this.log("");
45
+ this.log(chalk.dim("Token removed from ~/.agor/cli-token"));
46
+ this.log("");
47
+ }
48
+ };
49
+ export {
50
+ Logout as default
51
+ };
@@ -0,0 +1,15 @@
1
+ import { Command } from '@oclif/core';
2
+
3
+ /**
4
+ * `agor whoami` - Show current authenticated user
5
+ *
6
+ * Displays information about the currently authenticated user
7
+ */
8
+
9
+ declare class Whoami extends Command {
10
+ static description: string;
11
+ static examples: string[];
12
+ run(): Promise<void>;
13
+ }
14
+
15
+ export { Whoami as default };
@@ -0,0 +1,67 @@
1
+ // src/commands/auth/whoami.ts
2
+ import { Command } from "@oclif/core";
3
+ import chalk from "chalk";
4
+
5
+ // src/lib/auth.ts
6
+ import { mkdir, readFile, unlink, writeFile } from "fs/promises";
7
+ import { homedir } from "os";
8
+ import { join } from "path";
9
+ var AGOR_DIR = join(homedir(), ".agor");
10
+ var TOKEN_FILE = join(AGOR_DIR, "cli-token");
11
+ async function loadToken() {
12
+ try {
13
+ const data = await readFile(TOKEN_FILE, "utf-8");
14
+ const auth = JSON.parse(data);
15
+ if (auth.expiresAt && Date.now() > auth.expiresAt) {
16
+ await clearToken();
17
+ return null;
18
+ }
19
+ return auth;
20
+ } catch {
21
+ return null;
22
+ }
23
+ }
24
+ async function clearToken() {
25
+ try {
26
+ await unlink(TOKEN_FILE);
27
+ } catch {
28
+ }
29
+ }
30
+
31
+ // src/commands/auth/whoami.ts
32
+ var Whoami = class extends Command {
33
+ static description = "Show current authenticated user";
34
+ static examples = ["<%= config.bin %> <%= command.id %>"];
35
+ async run() {
36
+ const storedAuth = await loadToken();
37
+ if (!storedAuth) {
38
+ this.log(chalk.dim("Not currently logged in"));
39
+ this.log("");
40
+ this.log(chalk.dim("To login:"), chalk.cyan("agor login"));
41
+ this.log("");
42
+ return;
43
+ }
44
+ this.log("");
45
+ this.log(chalk.green("\u2713 Authenticated"));
46
+ this.log("");
47
+ this.log(chalk.dim("User ID:"), chalk.cyan(storedAuth.user.user_id));
48
+ this.log(chalk.dim("Email:"), chalk.cyan(storedAuth.user.email));
49
+ if (storedAuth.user.name) {
50
+ this.log(chalk.dim("Name:"), storedAuth.user.name);
51
+ }
52
+ this.log(chalk.dim("Role:"), storedAuth.user.role);
53
+ this.log("");
54
+ const expiresIn = storedAuth.expiresAt - Date.now();
55
+ const daysLeft = Math.floor(expiresIn / (24 * 60 * 60 * 1e3));
56
+ const hoursLeft = Math.floor(expiresIn % (24 * 60 * 60 * 1e3) / (60 * 60 * 1e3));
57
+ if (expiresIn > 0) {
58
+ this.log(chalk.dim("Token expires in:"), `${daysLeft}d ${hoursLeft}h`);
59
+ } else {
60
+ this.log(chalk.red("Token expired"), chalk.dim("- please login again"));
61
+ }
62
+ this.log("");
63
+ }
64
+ };
65
+ export {
66
+ Whoami as default
67
+ };
@@ -1,7 +1,9 @@
1
1
  import * as _oclif_core_interfaces from '@oclif/core/interfaces';
2
- import { Command } from '@oclif/core';
2
+ import { BaseCommand } from '../../base-command.js';
3
+ import '@agor/core/api';
4
+ import '@oclif/core';
3
5
 
4
- declare class BoardAddSession extends Command {
6
+ declare class BoardAddSession extends BaseCommand {
5
7
  static description: string;
6
8
  static examples: string[];
7
9
  static args: {
@@ -9,7 +11,6 @@ declare class BoardAddSession extends Command {
9
11
  sessionId: _oclif_core_interfaces.Arg<string, Record<string, unknown>>;
10
12
  };
11
13
  run(): Promise<void>;
12
- private cleanup;
13
14
  }
14
15
 
15
16
  export { BoardAddSession as default };
@@ -1,8 +1,142 @@
1
+ var __defProp = Object.defineProperty;
2
+ var __getOwnPropNames = Object.getOwnPropertyNames;
3
+ var __esm = (fn, res) => function __init() {
4
+ return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
5
+ };
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+
11
+ // src/lib/auth.ts
12
+ var auth_exports = {};
13
+ __export(auth_exports, {
14
+ clearToken: () => clearToken,
15
+ loadToken: () => loadToken,
16
+ saveToken: () => saveToken
17
+ });
18
+ import { mkdir, readFile, unlink, writeFile } from "fs/promises";
19
+ import { homedir } from "os";
20
+ import { join } from "path";
21
+ async function saveToken(auth) {
22
+ await mkdir(AGOR_DIR, { recursive: true });
23
+ await writeFile(TOKEN_FILE, JSON.stringify(auth, null, 2), {
24
+ mode: 384
25
+ // Owner read/write only
26
+ });
27
+ }
28
+ async function loadToken() {
29
+ try {
30
+ const data = await readFile(TOKEN_FILE, "utf-8");
31
+ const auth = JSON.parse(data);
32
+ if (auth.expiresAt && Date.now() > auth.expiresAt) {
33
+ await clearToken();
34
+ return null;
35
+ }
36
+ return auth;
37
+ } catch {
38
+ return null;
39
+ }
40
+ }
41
+ async function clearToken() {
42
+ try {
43
+ await unlink(TOKEN_FILE);
44
+ } catch {
45
+ }
46
+ }
47
+ var AGOR_DIR, TOKEN_FILE;
48
+ var init_auth = __esm({
49
+ "src/lib/auth.ts"() {
50
+ "use strict";
51
+ AGOR_DIR = join(homedir(), ".agor");
52
+ TOKEN_FILE = join(AGOR_DIR, "cli-token");
53
+ }
54
+ });
55
+
1
56
  // src/commands/board/add-session.ts
2
- import { createClient } from "@agor/core/api";
3
- import { Args, Command } from "@oclif/core";
57
+ import { Args } from "@oclif/core";
58
+ import chalk2 from "chalk";
59
+
60
+ // src/base-command.ts
61
+ init_auth();
62
+ import { createRestClient, isDaemonRunning } from "@agor/core/api";
63
+ import { getDaemonUrl } from "@agor/core/config";
64
+ import { Command } from "@oclif/core";
4
65
  import chalk from "chalk";
5
- var BoardAddSession = class _BoardAddSession extends Command {
66
+ var BaseCommand = class extends Command {
67
+ daemonUrl = null;
68
+ /**
69
+ * Connect to daemon (checks if running first)
70
+ *
71
+ * @returns Feathers client instance
72
+ */
73
+ async connectToDaemon() {
74
+ this.daemonUrl = await getDaemonUrl();
75
+ const running = await isDaemonRunning(this.daemonUrl);
76
+ if (!running) {
77
+ this.log(
78
+ chalk.red("\u2717 Daemon not running") + "\n\n" + chalk.bold("To start the daemon:") + "\n " + chalk.cyan("cd apps/agor-daemon && pnpm dev") + "\n\n" + chalk.bold("To configure daemon URL:") + "\n " + chalk.cyan("agor config set daemon.url <url>") + "\n " + chalk.gray(`Current: ${this.daemonUrl}`)
79
+ );
80
+ this.exit(1);
81
+ }
82
+ const client = await createRestClient(this.daemonUrl);
83
+ const storedAuth = await loadToken();
84
+ if (storedAuth) {
85
+ try {
86
+ await client.authenticate({
87
+ strategy: "jwt",
88
+ accessToken: storedAuth.accessToken
89
+ });
90
+ } catch (_error) {
91
+ const { clearToken: clearToken2 } = await Promise.resolve().then(() => (init_auth(), auth_exports));
92
+ await clearToken2();
93
+ this.error(
94
+ chalk.red("\u2717 Authentication failed") + "\n\n" + chalk.dim("Your session has expired or is invalid.") + "\n" + chalk.dim("Please login again:") + "\n " + chalk.cyan("agor login")
95
+ );
96
+ }
97
+ } else {
98
+ try {
99
+ const response = await fetch(`${this.daemonUrl}/health`);
100
+ const health = await response.json();
101
+ if (health.auth?.requireAuth) {
102
+ this.error(
103
+ chalk.red("\u2717 Not authenticated") + "\n\n" + chalk.dim("This Agor instance requires authentication.") + "\n" + chalk.dim("Please login:") + "\n " + chalk.cyan("agor login")
104
+ );
105
+ }
106
+ try {
107
+ await client.authenticate({ strategy: "anonymous" });
108
+ } catch (_authError) {
109
+ this.error(
110
+ chalk.red("\u2717 Authentication failed") + "\n\n" + chalk.dim("Please login:") + "\n " + chalk.cyan("agor login")
111
+ );
112
+ }
113
+ } catch (_error) {
114
+ try {
115
+ await client.authenticate({ strategy: "anonymous" });
116
+ } catch {
117
+ this.error(
118
+ chalk.red("\u2717 Not authenticated") + "\n\n" + chalk.dim("Please login to use the Agor CLI:") + "\n " + chalk.cyan("agor login")
119
+ );
120
+ }
121
+ }
122
+ }
123
+ return client;
124
+ }
125
+ /**
126
+ * Cleanup client connection
127
+ *
128
+ * Ensures socket is properly closed to prevent hanging processes
129
+ */
130
+ async cleanupClient(client) {
131
+ client.io.io.opts.reconnection = false;
132
+ client.io.removeAllListeners();
133
+ client.io.close();
134
+ await new Promise((resolve) => setTimeout(resolve, 100));
135
+ }
136
+ };
137
+
138
+ // src/commands/board/add-session.ts
139
+ var BoardAddSession = class _BoardAddSession extends BaseCommand {
6
140
  static description = "Add a session's worktree to a board (sessions are organized through worktrees)";
7
141
  static examples = [
8
142
  "<%= config.bin %> <%= command.id %> default 0199b86c",
@@ -20,7 +154,7 @@ var BoardAddSession = class _BoardAddSession extends Command {
20
154
  };
21
155
  async run() {
22
156
  const { args } = await this.parse(_BoardAddSession);
23
- const client = createClient();
157
+ const client = await this.connectToDaemon();
24
158
  try {
25
159
  const boardsResult = await client.service("boards").find();
26
160
  const boards = Array.isArray(boardsResult) ? boardsResult : boardsResult.data;
@@ -28,9 +162,8 @@ var BoardAddSession = class _BoardAddSession extends Command {
28
162
  (b) => b.board_id === args.boardId || b.board_id.startsWith(args.boardId) || b.slug === args.boardId
29
163
  );
30
164
  if (!board) {
31
- this.log(chalk.red(`\u2717 Board not found: ${args.boardId}`));
32
- await this.cleanup(client);
33
- process.exit(1);
165
+ await this.cleanupClient(client);
166
+ this.error(`Board not found: ${args.boardId}`);
34
167
  }
35
168
  const sessionsResult = await client.service("sessions").find();
36
169
  const sessions = Array.isArray(sessionsResult) ? sessionsResult : sessionsResult.data;
@@ -38,22 +171,19 @@ var BoardAddSession = class _BoardAddSession extends Command {
38
171
  (s) => s.session_id === args.sessionId || s.session_id.startsWith(args.sessionId)
39
172
  );
40
173
  if (!session) {
41
- this.log(chalk.red(`\u2717 Session not found: ${args.sessionId}`));
42
- await this.cleanup(client);
43
- process.exit(1);
174
+ await this.cleanupClient(client);
175
+ this.error(`Session not found: ${args.sessionId}`);
44
176
  }
45
177
  if (!session.worktree_id) {
46
- this.log(chalk.red(`\u2717 Session has no worktree associated`));
47
- await this.cleanup(client);
48
- process.exit(1);
178
+ await this.cleanupClient(client);
179
+ this.error("Session has no worktree associated");
49
180
  }
50
181
  const worktreesResult = await client.service("worktrees").find();
51
182
  const worktrees = Array.isArray(worktreesResult) ? worktreesResult : worktreesResult.data;
52
183
  const worktree = worktrees.find((w) => w.worktree_id === session.worktree_id);
53
184
  if (!worktree) {
54
- this.log(chalk.red(`\u2717 Worktree not found for session`));
55
- await this.cleanup(client);
56
- process.exit(1);
185
+ await this.cleanupClient(client);
186
+ this.error("Worktree not found for session");
57
187
  }
58
188
  const boardObjectsResult = await client.service("board-objects").find({
59
189
  query: {
@@ -65,8 +195,8 @@ var BoardAddSession = class _BoardAddSession extends Command {
65
195
  (bo) => bo.worktree_id === worktree.worktree_id
66
196
  );
67
197
  if (existingObject) {
68
- this.log(chalk.yellow(`\u26A0 Worktree "${worktree.name}" already on board "${board.name}"`));
69
- await this.cleanup(client);
198
+ this.log(chalk2.yellow(`\u26A0 Worktree "${worktree.name}" already on board "${board.name}"`));
199
+ await this.cleanupClient(client);
70
200
  return;
71
201
  }
72
202
  await client.service("board-objects").create({
@@ -75,26 +205,17 @@ var BoardAddSession = class _BoardAddSession extends Command {
75
205
  position: { x: 100, y: 100 }
76
206
  });
77
207
  this.log(
78
- chalk.green(
208
+ chalk2.green(
79
209
  `\u2713 Added worktree "${worktree.name}" (containing session ${session.session_id.substring(0, 8)}) to board "${board.name}"`
80
210
  )
81
211
  );
82
212
  } catch (error) {
83
- this.log(chalk.red("\u2717 Failed to add session to board"));
84
- if (error instanceof Error) {
85
- this.log(chalk.red(error.message));
86
- }
87
- await this.cleanup(client);
88
- process.exit(1);
213
+ await this.cleanupClient(client);
214
+ this.error(
215
+ `Failed to add session to board: ${error instanceof Error ? error.message : String(error)}`
216
+ );
89
217
  }
90
- await this.cleanup(client);
91
- }
92
- async cleanup(client) {
93
- await new Promise((resolve) => {
94
- client.io.once("disconnect", () => resolve());
95
- client.io.close();
96
- setTimeout(() => resolve(), 1e3);
97
- });
218
+ await this.cleanupClient(client);
98
219
  }
99
220
  };
100
221
  export {