climemo 0.1.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.
Files changed (76) hide show
  1. package/dist/commands/ask.d.ts +2 -0
  2. package/dist/commands/ask.js +37 -0
  3. package/dist/commands/ask.js.map +1 -0
  4. package/dist/commands/compare.d.ts +2 -0
  5. package/dist/commands/compare.js +57 -0
  6. package/dist/commands/compare.js.map +1 -0
  7. package/dist/commands/config.d.ts +2 -0
  8. package/dist/commands/config.js +37 -0
  9. package/dist/commands/config.js.map +1 -0
  10. package/dist/commands/daemon.d.ts +2 -0
  11. package/dist/commands/daemon.js +69 -0
  12. package/dist/commands/daemon.js.map +1 -0
  13. package/dist/commands/invite.d.ts +2 -0
  14. package/dist/commands/invite.js +49 -0
  15. package/dist/commands/invite.js.map +1 -0
  16. package/dist/commands/login.d.ts +2 -0
  17. package/dist/commands/login.js +94 -0
  18. package/dist/commands/login.js.map +1 -0
  19. package/dist/commands/logout.d.ts +2 -0
  20. package/dist/commands/logout.js +9 -0
  21. package/dist/commands/logout.js.map +1 -0
  22. package/dist/commands/members.d.ts +2 -0
  23. package/dist/commands/members.js +98 -0
  24. package/dist/commands/members.js.map +1 -0
  25. package/dist/commands/merge.d.ts +2 -0
  26. package/dist/commands/merge.js +120 -0
  27. package/dist/commands/merge.js.map +1 -0
  28. package/dist/commands/search.d.ts +2 -0
  29. package/dist/commands/search.js +32 -0
  30. package/dist/commands/search.js.map +1 -0
  31. package/dist/commands/sync.d.ts +2 -0
  32. package/dist/commands/sync.js +200 -0
  33. package/dist/commands/sync.js.map +1 -0
  34. package/dist/commands/token.d.ts +2 -0
  35. package/dist/commands/token.js +60 -0
  36. package/dist/commands/token.js.map +1 -0
  37. package/dist/commands/whoami.d.ts +2 -0
  38. package/dist/commands/whoami.js +20 -0
  39. package/dist/commands/whoami.js.map +1 -0
  40. package/dist/daemon/index.d.ts +2 -0
  41. package/dist/daemon/index.js +27 -0
  42. package/dist/daemon/index.js.map +1 -0
  43. package/dist/daemon/install.d.ts +13 -0
  44. package/dist/daemon/install.js +143 -0
  45. package/dist/daemon/install.js.map +1 -0
  46. package/dist/daemon/logger.d.ts +8 -0
  47. package/dist/daemon/logger.js +41 -0
  48. package/dist/daemon/logger.js.map +1 -0
  49. package/dist/daemon/token-refresher.d.ts +14 -0
  50. package/dist/daemon/token-refresher.js +88 -0
  51. package/dist/daemon/token-refresher.js.map +1 -0
  52. package/dist/index.d.ts +2 -0
  53. package/dist/index.js +40 -0
  54. package/dist/index.js.map +1 -0
  55. package/dist/lib/api.d.ts +13 -0
  56. package/dist/lib/api.js +18 -0
  57. package/dist/lib/api.js.map +1 -0
  58. package/dist/lib/auth.d.ts +24 -0
  59. package/dist/lib/auth.js +72 -0
  60. package/dist/lib/auth.js.map +1 -0
  61. package/dist/lib/config.d.ts +9 -0
  62. package/dist/lib/config.js +36 -0
  63. package/dist/lib/config.js.map +1 -0
  64. package/dist/lib/git.d.ts +24 -0
  65. package/dist/lib/git.js +63 -0
  66. package/dist/lib/git.js.map +1 -0
  67. package/dist/lib/keychain.d.ts +4 -0
  68. package/dist/lib/keychain.js +39 -0
  69. package/dist/lib/keychain.js.map +1 -0
  70. package/dist/lib/project.d.ts +13 -0
  71. package/dist/lib/project.js +133 -0
  72. package/dist/lib/project.js.map +1 -0
  73. package/dist/lib/server.d.ts +9 -0
  74. package/dist/lib/server.js +80 -0
  75. package/dist/lib/server.js.map +1 -0
  76. package/package.json +48 -0
@@ -0,0 +1,2 @@
1
+ import { Command } from "commander";
2
+ export declare const askCommand: Command;
@@ -0,0 +1,37 @@
1
+ import { Command } from "commander";
2
+ import { apiRequest } from "../lib/api.js";
3
+ import { resolveProject } from "../lib/project.js";
4
+ export const askCommand = new Command("ask")
5
+ .description("Ask AI about your project documents")
6
+ .argument("<question>", "Question to ask")
7
+ .option("--project <projectId>", "Project ID (auto-detected from git repo if omitted)")
8
+ .option("--model <model>", "AI model to use (e.g., google/gemini-2.0-flash-001)")
9
+ .action(async (question, options, cmd) => {
10
+ const globalOpts = cmd.optsWithGlobals();
11
+ try {
12
+ const projectId = options.project || await resolveProject(globalOpts.token);
13
+ const body = {
14
+ question,
15
+ project_ids: [projectId],
16
+ };
17
+ if (options.model) {
18
+ body.model = options.model;
19
+ }
20
+ const { ok, data } = await apiRequest("/api/ask", {
21
+ method: "POST",
22
+ body,
23
+ token: globalOpts.token,
24
+ });
25
+ if (!ok) {
26
+ console.error(JSON.stringify({ error: "Failed to get answer", details: data }));
27
+ process.exit(1);
28
+ }
29
+ console.log(JSON.stringify(data, null, 2));
30
+ }
31
+ catch (err) {
32
+ const message = err instanceof Error ? err.message : String(err);
33
+ console.error(JSON.stringify({ error: message }));
34
+ process.exit(1);
35
+ }
36
+ });
37
+ //# sourceMappingURL=ask.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ask.js","sourceRoot":"","sources":["../../src/commands/ask.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAC3C,OAAO,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAEnD,MAAM,CAAC,MAAM,UAAU,GAAG,IAAI,OAAO,CAAC,KAAK,CAAC;KACzC,WAAW,CAAC,qCAAqC,CAAC;KAClD,QAAQ,CAAC,YAAY,EAAE,iBAAiB,CAAC;KACzC,MAAM,CAAC,uBAAuB,EAAE,qDAAqD,CAAC;KACtF,MAAM,CAAC,iBAAiB,EAAE,qDAAqD,CAAC;KAChF,MAAM,CAAC,KAAK,EAAE,QAAgB,EAAE,OAAO,EAAE,GAAG,EAAE,EAAE;IAC/C,MAAM,UAAU,GAAG,GAAG,CAAC,eAAe,EAAE,CAAC;IAEzC,IAAI,CAAC;QACH,MAAM,SAAS,GAAG,OAAO,CAAC,OAAO,IAAI,MAAM,cAAc,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC;QAE5E,MAAM,IAAI,GAA4B;YACpC,QAAQ;YACR,WAAW,EAAE,CAAC,SAAS,CAAC;SACzB,CAAC;QACF,IAAI,OAAO,CAAC,KAAK,EAAE,CAAC;YAClB,IAAI,CAAC,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC;QAC7B,CAAC;QAED,MAAM,EAAE,EAAE,EAAE,IAAI,EAAE,GAAG,MAAM,UAAU,CAAC,UAAU,EAAE;YAChD,MAAM,EAAE,MAAM;YACd,IAAI;YACJ,KAAK,EAAE,UAAU,CAAC,KAAK;SACxB,CAAC,CAAC;QAEH,IAAI,CAAC,EAAE,EAAE,CAAC;YACR,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,KAAK,EAAE,sBAAsB,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;YAChF,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;QAED,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;IAC7C,CAAC;IAAC,OAAO,GAAY,EAAE,CAAC;QACtB,MAAM,OAAO,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;QACjE,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,KAAK,EAAE,OAAO,EAAE,CAAC,CAAC,CAAC;QAClD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;AACH,CAAC,CAAC,CAAC"}
@@ -0,0 +1,2 @@
1
+ import { Command } from "commander";
2
+ export declare const compareCommand: Command;
@@ -0,0 +1,57 @@
1
+ import { Command } from "commander";
2
+ import { apiRequest } from "../lib/api.js";
3
+ export const compareCommand = new Command("compare")
4
+ .description("Compare projects on a specific topic")
5
+ .argument("<projectA>", "First project ID")
6
+ .argument("[projectB]", "Second project ID (optional if --all)")
7
+ .option("--all", "Compare all projects")
8
+ .option("--topic <topic>", "Comparison topic", "overview")
9
+ .option("--model <model>", "AI model to use")
10
+ .action(async (projectA, projectB, options, cmd) => {
11
+ const globalOpts = cmd.optsWithGlobals();
12
+ try {
13
+ let projectIds;
14
+ if (options.all) {
15
+ // Fetch all projects first
16
+ const { ok, data } = await apiRequest("/api/projects", {
17
+ token: globalOpts.token,
18
+ });
19
+ if (!ok || !data) {
20
+ console.error(JSON.stringify({ error: "Failed to fetch projects" }));
21
+ process.exit(1);
22
+ }
23
+ projectIds = (data.data || []).map((p) => p.id);
24
+ }
25
+ else {
26
+ projectIds = [projectA];
27
+ if (projectB)
28
+ projectIds.push(projectB);
29
+ if (projectIds.length < 2) {
30
+ console.error(JSON.stringify({ error: "Need at least 2 projects to compare. Use --all or provide two project IDs." }));
31
+ process.exit(1);
32
+ }
33
+ }
34
+ const body = {
35
+ project_ids: projectIds,
36
+ topic: options.topic,
37
+ };
38
+ if (options.model)
39
+ body.model = options.model;
40
+ const { ok, data } = await apiRequest("/api/compare", {
41
+ method: "POST",
42
+ body,
43
+ token: globalOpts.token,
44
+ });
45
+ if (!ok) {
46
+ console.error(JSON.stringify({ error: "Comparison failed", details: data }));
47
+ process.exit(1);
48
+ }
49
+ console.log(JSON.stringify(data, null, 2));
50
+ }
51
+ catch (err) {
52
+ const message = err instanceof Error ? err.message : String(err);
53
+ console.error(JSON.stringify({ error: message }));
54
+ process.exit(1);
55
+ }
56
+ });
57
+ //# sourceMappingURL=compare.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"compare.js","sourceRoot":"","sources":["../../src/commands/compare.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ import { Command } from "commander";
2
+ export declare const configCommand: Command;
@@ -0,0 +1,37 @@
1
+ import { Command } from "commander";
2
+ import { getConfig, setConfig } from "../lib/config.js";
3
+ export const configCommand = new Command("config")
4
+ .description("CLI configuration");
5
+ configCommand
6
+ .command("set <key> <value>")
7
+ .description("Set a config value")
8
+ .action((key, value) => {
9
+ const validKeys = ["apiUrl", "defaultProject", "defaultModel", "slackWebhook"];
10
+ if (!validKeys.includes(key)) {
11
+ console.error(`Unknown config key: ${key}`);
12
+ console.error(`Valid keys: ${validKeys.join(", ")}`);
13
+ process.exit(1);
14
+ }
15
+ setConfig({ [key]: value });
16
+ console.log(JSON.stringify({ [key]: value }));
17
+ });
18
+ configCommand
19
+ .command("list")
20
+ .description("Show current configuration")
21
+ .action(() => {
22
+ const config = getConfig();
23
+ console.log(JSON.stringify(config, null, 2));
24
+ });
25
+ configCommand
26
+ .command("get <key>")
27
+ .description("Get a config value")
28
+ .action((key) => {
29
+ const config = getConfig();
30
+ const value = config[key];
31
+ if (value === undefined) {
32
+ console.error(`Config key not set: ${key}`);
33
+ process.exit(1);
34
+ }
35
+ console.log(JSON.stringify({ [key]: value }));
36
+ });
37
+ //# sourceMappingURL=config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/commands/config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,SAAS,EAAE,SAAS,EAAkB,MAAM,kBAAkB,CAAC;AAExE,MAAM,CAAC,MAAM,aAAa,GAAG,IAAI,OAAO,CAAC,QAAQ,CAAC;KAC/C,WAAW,CAAC,mBAAmB,CAAC,CAAC;AAEpC,aAAa;KACV,OAAO,CAAC,mBAAmB,CAAC;KAC5B,WAAW,CAAC,oBAAoB,CAAC;KACjC,MAAM,CAAC,CAAC,GAAW,EAAE,KAAa,EAAE,EAAE;IACrC,MAAM,SAAS,GAAwB,CAAC,QAAQ,EAAE,gBAAgB,EAAE,cAAc,EAAE,cAAc,CAAC,CAAC;IAEpG,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,GAAsB,CAAC,EAAE,CAAC;QAChD,OAAO,CAAC,KAAK,CAAC,uBAAuB,GAAG,EAAE,CAAC,CAAC;QAC5C,OAAO,CAAC,KAAK,CAAC,eAAe,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QACrD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,SAAS,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,KAAK,EAAwB,CAAC,CAAC;IAClD,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC;AAChD,CAAC,CAAC,CAAC;AAEL,aAAa;KACV,OAAO,CAAC,MAAM,CAAC;KACf,WAAW,CAAC,4BAA4B,CAAC;KACzC,MAAM,CAAC,GAAG,EAAE;IACX,MAAM,MAAM,GAAG,SAAS,EAAE,CAAC;IAC3B,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;AAC/C,CAAC,CAAC,CAAC;AAEL,aAAa;KACV,OAAO,CAAC,WAAW,CAAC;KACpB,WAAW,CAAC,oBAAoB,CAAC;KACjC,MAAM,CAAC,CAAC,GAAW,EAAE,EAAE;IACtB,MAAM,MAAM,GAAG,SAAS,EAAE,CAAC;IAC3B,MAAM,KAAK,GAAG,MAAM,CAAC,GAAsB,CAAC,CAAC;IAC7C,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;QACxB,OAAO,CAAC,KAAK,CAAC,uBAAuB,GAAG,EAAE,CAAC,CAAC;QAC5C,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IACD,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,CAAC,GAAG,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC;AAChD,CAAC,CAAC,CAAC"}
@@ -0,0 +1,2 @@
1
+ import { Command } from "commander";
2
+ export declare const daemonCommand: Command;
@@ -0,0 +1,69 @@
1
+ import { Command } from "commander";
2
+ import { installDaemon, uninstallDaemon, isDaemonRunning } from "../daemon/install.js";
3
+ import { DaemonLogger } from "../daemon/logger.js";
4
+ export const daemonCommand = new Command("daemon")
5
+ .description("Daemon management");
6
+ daemonCommand
7
+ .command("start")
8
+ .description("Install and start the daemon")
9
+ .action(() => {
10
+ const logger = new DaemonLogger();
11
+ try {
12
+ installDaemon(logger);
13
+ console.log(JSON.stringify({ status: "started", message: "Daemon installed and started." }));
14
+ }
15
+ catch (err) {
16
+ const message = err instanceof Error ? err.message : String(err);
17
+ console.error(JSON.stringify({ status: "error", message }));
18
+ process.exit(1);
19
+ }
20
+ });
21
+ daemonCommand
22
+ .command("stop")
23
+ .description("Stop and uninstall the daemon")
24
+ .action(() => {
25
+ const logger = new DaemonLogger();
26
+ try {
27
+ uninstallDaemon(logger);
28
+ console.log(JSON.stringify({ status: "stopped", message: "Daemon stopped and uninstalled." }));
29
+ }
30
+ catch (err) {
31
+ const message = err instanceof Error ? err.message : String(err);
32
+ console.error(JSON.stringify({ status: "error", message }));
33
+ process.exit(1);
34
+ }
35
+ });
36
+ daemonCommand
37
+ .command("status")
38
+ .description("Check daemon status")
39
+ .action(() => {
40
+ const running = isDaemonRunning();
41
+ console.log(JSON.stringify({
42
+ status: running ? "running" : "stopped",
43
+ platform: process.platform,
44
+ }));
45
+ });
46
+ daemonCommand
47
+ .command("run")
48
+ .description("Run daemon in foreground (used by launchd/systemd)")
49
+ .action(async () => {
50
+ // Dynamic import to avoid loading daemon code for other commands
51
+ const { TokenRefresher } = await import("../daemon/token-refresher.js");
52
+ const logger = new DaemonLogger();
53
+ logger.info("Climemo daemon starting in foreground...");
54
+ const tokenRefresher = new TokenRefresher(logger);
55
+ tokenRefresher.start(30 * 60 * 1000);
56
+ process.on("SIGINT", () => {
57
+ logger.info("Daemon shutting down...");
58
+ tokenRefresher.stop();
59
+ process.exit(0);
60
+ });
61
+ process.on("SIGTERM", () => {
62
+ logger.info("Daemon shutting down...");
63
+ tokenRefresher.stop();
64
+ process.exit(0);
65
+ });
66
+ // Keep process alive
67
+ setInterval(() => { }, 1 << 30);
68
+ });
69
+ //# sourceMappingURL=daemon.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"daemon.js","sourceRoot":"","sources":["../../src/commands/daemon.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ import { Command } from "commander";
2
+ export declare const inviteCommand: Command;
@@ -0,0 +1,49 @@
1
+ import { Command } from "commander";
2
+ import { apiRequest } from "../lib/api.js";
3
+ export const inviteCommand = new Command("invite")
4
+ .description("Invite a team member to your workspace")
5
+ .argument("<email>", "Email of the person to invite")
6
+ .option("--role <role>", "Role: member or admin", "member")
7
+ .option("--org <orgId>", "Organization ID (uses default workspace if omitted)")
8
+ .action(async (email, options, cmd) => {
9
+ const globalOpts = cmd.optsWithGlobals();
10
+ try {
11
+ let orgId = options.org;
12
+ // If no org specified, get user's default (first) org
13
+ if (!orgId) {
14
+ const { ok, data } = await apiRequest("/api/organizations", {
15
+ token: globalOpts.token,
16
+ });
17
+ if (!ok || !data) {
18
+ console.error(JSON.stringify({ error: "Failed to fetch organizations" }));
19
+ process.exit(1);
20
+ }
21
+ const orgs = data.data || [];
22
+ if (orgs.length === 0) {
23
+ console.error(JSON.stringify({ error: "No workspace found" }));
24
+ process.exit(1);
25
+ }
26
+ orgId = orgs[0].id;
27
+ }
28
+ const { ok, data } = await apiRequest("/api/organizations/invite", {
29
+ method: "POST",
30
+ body: {
31
+ email,
32
+ organization_id: orgId,
33
+ role: options.role,
34
+ },
35
+ token: globalOpts.token,
36
+ });
37
+ if (!ok) {
38
+ console.error(JSON.stringify({ error: "Invite failed", details: data }));
39
+ process.exit(1);
40
+ }
41
+ console.log(JSON.stringify(data, null, 2));
42
+ }
43
+ catch (err) {
44
+ const message = err instanceof Error ? err.message : String(err);
45
+ console.error(JSON.stringify({ error: message }));
46
+ process.exit(1);
47
+ }
48
+ });
49
+ //# sourceMappingURL=invite.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"invite.js","sourceRoot":"","sources":["../../src/commands/invite.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAE3C,MAAM,CAAC,MAAM,aAAa,GAAG,IAAI,OAAO,CAAC,QAAQ,CAAC;KAC/C,WAAW,CAAC,wCAAwC,CAAC;KACrD,QAAQ,CAAC,SAAS,EAAE,+BAA+B,CAAC;KACpD,MAAM,CAAC,eAAe,EAAE,uBAAuB,EAAE,QAAQ,CAAC;KAC1D,MAAM,CAAC,eAAe,EAAE,qDAAqD,CAAC;KAC9E,MAAM,CAAC,KAAK,EAAE,KAAa,EAAE,OAAO,EAAE,GAAG,EAAE,EAAE;IAC5C,MAAM,UAAU,GAAG,GAAG,CAAC,eAAe,EAAE,CAAC;IAEzC,IAAI,CAAC;QACH,IAAI,KAAK,GAAG,OAAO,CAAC,GAAG,CAAC;QAExB,sDAAsD;QACtD,IAAI,CAAC,KAAK,EAAE,CAAC;YACX,MAAM,EAAE,EAAE,EAAE,IAAI,EAAE,GAAG,MAAM,UAAU,CAAC,oBAAoB,EAAE;gBAC1D,KAAK,EAAE,UAAU,CAAC,KAAK;aACxB,CAAC,CAAC;YACH,IAAI,CAAC,EAAE,IAAI,CAAC,IAAI,EAAE,CAAC;gBACjB,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,KAAK,EAAE,+BAA+B,EAAE,CAAC,CAAC,CAAC;gBAC1E,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YAClB,CAAC;YACD,MAAM,IAAI,GAAI,IAAmC,CAAC,IAAI,IAAI,EAAE,CAAC;YAC7D,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;gBACtB,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,KAAK,EAAE,oBAAoB,EAAE,CAAC,CAAC,CAAC;gBAC/D,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YAClB,CAAC;YACD,KAAK,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;QACrB,CAAC;QAED,MAAM,EAAE,EAAE,EAAE,IAAI,EAAE,GAAG,MAAM,UAAU,CAAC,2BAA2B,EAAE;YACjE,MAAM,EAAE,MAAM;YACd,IAAI,EAAE;gBACJ,KAAK;gBACL,eAAe,EAAE,KAAK;gBACtB,IAAI,EAAE,OAAO,CAAC,IAAI;aACnB;YACD,KAAK,EAAE,UAAU,CAAC,KAAK;SACxB,CAAC,CAAC;QAEH,IAAI,CAAC,EAAE,EAAE,CAAC;YACR,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,KAAK,EAAE,eAAe,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;YACzE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;QAED,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;IAC7C,CAAC;IAAC,OAAO,GAAY,EAAE,CAAC;QACtB,MAAM,OAAO,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;QACjE,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,KAAK,EAAE,OAAO,EAAE,CAAC,CAAC,CAAC;QAClD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;AACH,CAAC,CAAC,CAAC"}
@@ -0,0 +1,2 @@
1
+ import { Command } from "commander";
2
+ export declare const loginCommand: Command;
@@ -0,0 +1,94 @@
1
+ import { Command } from "commander";
2
+ import { saveTokens, getAccessToken } from "../lib/keychain.js";
3
+ import { validateToken } from "../lib/auth.js";
4
+ import { getConfig } from "../lib/config.js";
5
+ export const loginCommand = new Command("login")
6
+ .description("Log in to Climemo via browser OAuth")
7
+ .option("--provider <provider>", "OAuth provider: github | google", "github")
8
+ .action(async (options) => {
9
+ const config = getConfig();
10
+ const apiBase = config.apiUrl;
11
+ // Check if already logged in
12
+ const existingToken = await getAccessToken();
13
+ if (existingToken) {
14
+ const { valid, email } = await validateToken(existingToken);
15
+ if (valid) {
16
+ console.log(`Already logged in as ${email}`);
17
+ console.log('Run "climemo logout" first to switch accounts.');
18
+ return;
19
+ }
20
+ }
21
+ console.log("Opening browser for login...");
22
+ try {
23
+ // Start local callback server and open browser
24
+ const { code, port, close } = await startCallbackServerAndOpenBrowser(apiBase, options.provider);
25
+ // Exchange code for tokens via API
26
+ console.log("Authenticating...");
27
+ const res = await fetch(`${apiBase}/api/cli/token/exchange`, {
28
+ method: "POST",
29
+ headers: { "Content-Type": "application/json" },
30
+ body: JSON.stringify({ code, redirect_port: port }),
31
+ });
32
+ if (!res.ok) {
33
+ const err = await res.text();
34
+ console.error("Login failed:", err);
35
+ close();
36
+ process.exit(1);
37
+ }
38
+ const { access_token, refresh_token, user } = await res.json();
39
+ // Save to OS Keychain
40
+ await saveTokens(access_token, refresh_token);
41
+ close();
42
+ console.log("");
43
+ console.log(`Logged in as ${user.email}`);
44
+ console.log(" Token stored in OS Keychain (no plaintext files)");
45
+ console.log("");
46
+ }
47
+ catch (err) {
48
+ const message = err instanceof Error ? err.message : String(err);
49
+ console.error("Login failed:", message);
50
+ process.exit(1);
51
+ }
52
+ });
53
+ async function startCallbackServerAndOpenBrowser(apiBase, provider) {
54
+ const { createServer } = await import("http");
55
+ return new Promise((resolve, reject) => {
56
+ const server = createServer(async (req, res) => {
57
+ const url = new URL(req.url || "/", `http://localhost`);
58
+ const code = url.searchParams.get("code");
59
+ const error = url.searchParams.get("error");
60
+ if (error) {
61
+ res.writeHead(200, { "Content-Type": "text/html" });
62
+ res.end("<html><body><h1>Login failed</h1><p>Please try again.</p></body></html>");
63
+ reject(new Error(`Auth failed: ${error}`));
64
+ server.close();
65
+ return;
66
+ }
67
+ if (code) {
68
+ res.writeHead(200, { "Content-Type": "text/html" });
69
+ res.end(`<html><body style="font-family:sans-serif;display:flex;justify-content:center;align-items:center;min-height:100vh;margin:0">
70
+ <div style="text-align:center"><h1 style="color:#18181b">Login successful!</h1><p style="color:#71717a">You can close this window.</p></div></body></html>`);
71
+ resolve({
72
+ code,
73
+ port: server.address().port,
74
+ close: () => server.close(),
75
+ });
76
+ }
77
+ });
78
+ server.listen(0, "127.0.0.1", async () => {
79
+ const addr = server.address();
80
+ const callbackUrl = `http://127.0.0.1:${addr.port}`;
81
+ const loginUrl = `${apiBase}/api/cli/auth?provider=${provider}&redirect_uri=${encodeURIComponent(callbackUrl)}`;
82
+ // Open browser
83
+ const open = (await import("open")).default;
84
+ await open(loginUrl);
85
+ console.log(`Waiting for browser login... (port ${addr.port})`);
86
+ });
87
+ // Timeout after 5 minutes
88
+ setTimeout(() => {
89
+ server.close();
90
+ reject(new Error("Login timed out after 5 minutes."));
91
+ }, 5 * 60 * 1000);
92
+ });
93
+ }
94
+ //# sourceMappingURL=login.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"login.js","sourceRoot":"","sources":["../../src/commands/login.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ import { Command } from "commander";
2
+ export declare const logoutCommand: Command;
@@ -0,0 +1,9 @@
1
+ import { Command } from "commander";
2
+ import { clearTokens } from "../lib/keychain.js";
3
+ export const logoutCommand = new Command("logout")
4
+ .description("Log out and remove stored tokens")
5
+ .action(async () => {
6
+ await clearTokens();
7
+ console.log("Logged out. Tokens removed from OS Keychain.");
8
+ });
9
+ //# sourceMappingURL=logout.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"logout.js","sourceRoot":"","sources":["../../src/commands/logout.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAEjD,MAAM,CAAC,MAAM,aAAa,GAAG,IAAI,OAAO,CAAC,QAAQ,CAAC;KAC/C,WAAW,CAAC,kCAAkC,CAAC;KAC/C,MAAM,CAAC,KAAK,IAAI,EAAE;IACjB,MAAM,WAAW,EAAE,CAAC;IACpB,OAAO,CAAC,GAAG,CAAC,8CAA8C,CAAC,CAAC;AAC9D,CAAC,CAAC,CAAC"}
@@ -0,0 +1,2 @@
1
+ import { Command } from "commander";
2
+ export declare const membersCommand: Command;
@@ -0,0 +1,98 @@
1
+ import { Command } from "commander";
2
+ import { apiRequest } from "../lib/api.js";
3
+ function getOrgOption(cmd) {
4
+ const globalOpts = cmd.optsWithGlobals();
5
+ return { token: globalOpts.token, org: globalOpts.org };
6
+ }
7
+ async function resolveOrgId(token, orgOption) {
8
+ if (orgOption)
9
+ return orgOption;
10
+ const { ok, data } = await apiRequest("/api/organizations", { token });
11
+ if (!ok || !data) {
12
+ console.error(JSON.stringify({ error: "Failed to fetch organizations" }));
13
+ process.exit(1);
14
+ }
15
+ const orgs = data.data || [];
16
+ if (orgs.length === 0) {
17
+ console.error(JSON.stringify({ error: "No workspace found" }));
18
+ process.exit(1);
19
+ }
20
+ return orgs[0].id;
21
+ }
22
+ const listSubcommand = new Command("list")
23
+ .description("List workspace members")
24
+ .option("--org <orgId>", "Organization ID (uses default workspace if omitted)")
25
+ .action(async (_options, cmd) => {
26
+ const { token, org } = getOrgOption(cmd);
27
+ try {
28
+ const orgId = await resolveOrgId(token, org);
29
+ const { ok, data } = await apiRequest(`/api/organizations/members?organization_id=${orgId}`, { token });
30
+ if (!ok) {
31
+ console.error(JSON.stringify({ error: "Failed to list members", details: data }));
32
+ process.exit(1);
33
+ }
34
+ console.log(JSON.stringify(data, null, 2));
35
+ }
36
+ catch (err) {
37
+ const message = err instanceof Error ? err.message : String(err);
38
+ console.error(JSON.stringify({ error: message }));
39
+ process.exit(1);
40
+ }
41
+ });
42
+ const removeSubcommand = new Command("remove")
43
+ .description("Remove a member from the workspace")
44
+ .argument("<email>", "Email of the member to remove")
45
+ .option("--org <orgId>", "Organization ID (uses default workspace if omitted)")
46
+ .action(async (email, _options, cmd) => {
47
+ const { token, org } = getOrgOption(cmd);
48
+ try {
49
+ const orgId = await resolveOrgId(token, org);
50
+ const { ok, data } = await apiRequest("/api/organizations/members", {
51
+ method: "DELETE",
52
+ body: { email, organization_id: orgId },
53
+ token,
54
+ });
55
+ if (!ok) {
56
+ console.error(JSON.stringify({ error: "Failed to remove member", details: data }));
57
+ process.exit(1);
58
+ }
59
+ console.log(JSON.stringify(data, null, 2));
60
+ }
61
+ catch (err) {
62
+ const message = err instanceof Error ? err.message : String(err);
63
+ console.error(JSON.stringify({ error: message }));
64
+ process.exit(1);
65
+ }
66
+ });
67
+ const roleSubcommand = new Command("role")
68
+ .description("Change a member's role")
69
+ .argument("<email>", "Email of the member")
70
+ .argument("<role>", "New role: member, admin, or owner")
71
+ .option("--org <orgId>", "Organization ID (uses default workspace if omitted)")
72
+ .action(async (email, role, _options, cmd) => {
73
+ const { token, org } = getOrgOption(cmd);
74
+ try {
75
+ const orgId = await resolveOrgId(token, org);
76
+ const { ok, data } = await apiRequest("/api/organizations/members", {
77
+ method: "PATCH",
78
+ body: { email, organization_id: orgId, role },
79
+ token,
80
+ });
81
+ if (!ok) {
82
+ console.error(JSON.stringify({ error: "Failed to update role", details: data }));
83
+ process.exit(1);
84
+ }
85
+ console.log(JSON.stringify(data, null, 2));
86
+ }
87
+ catch (err) {
88
+ const message = err instanceof Error ? err.message : String(err);
89
+ console.error(JSON.stringify({ error: message }));
90
+ process.exit(1);
91
+ }
92
+ });
93
+ export const membersCommand = new Command("members")
94
+ .description("Manage workspace members")
95
+ .addCommand(listSubcommand)
96
+ .addCommand(removeSubcommand)
97
+ .addCommand(roleSubcommand);
98
+ //# sourceMappingURL=members.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"members.js","sourceRoot":"","sources":["../../src/commands/members.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ import { Command } from "commander";
2
+ export declare const mergeCommand: Command;