@liquidmetal-ai/raindrop 0.7.0 → 0.8.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 (178) hide show
  1. package/README.md +408 -73
  2. package/bin/cjs-shims.js +7 -0
  3. package/bin/run.js +20 -2
  4. package/bundle/chunk-5GH4FS6C.js +12148 -0
  5. package/bundle/chunk-6B4I2CKP.js +231 -0
  6. package/bundle/chunk-6UE75KX2.js +4481 -0
  7. package/bundle/chunk-AU3EGGJP.js +44 -0
  8. package/bundle/chunk-CDQRD3JA.js +75 -0
  9. package/bundle/chunk-CMCEP64V.js +380 -0
  10. package/bundle/chunk-CW5ZHVPX.js +292 -0
  11. package/bundle/chunk-G6NE675D.js +238720 -0
  12. package/bundle/chunk-GLIYVKQA.js +48 -0
  13. package/bundle/chunk-KXEV6E63.js +133 -0
  14. package/bundle/chunk-MCRKUPJY.js +4515 -0
  15. package/bundle/chunk-MGM2L2T3.js +805 -0
  16. package/bundle/chunk-MVQYQJHI.js +502 -0
  17. package/bundle/chunk-NG7CZTTE.js +147 -0
  18. package/bundle/chunk-PU4RCSXF.js +22452 -0
  19. package/bundle/chunk-VXAZKB3J.js +292 -0
  20. package/bundle/chunk-W2L3MYN6.js +4480 -0
  21. package/bundle/chunk-XYJACVNA.js +231 -0
  22. package/bundle/commands/annotation/get.js +153 -0
  23. package/bundle/commands/annotation/list.js +226 -0
  24. package/bundle/commands/annotation/put.js +177 -0
  25. package/bundle/commands/auth/list.js +75 -0
  26. package/bundle/commands/auth/login.js +1654 -0
  27. package/bundle/commands/auth/logout.js +27 -0
  28. package/bundle/commands/auth/select.js +53 -0
  29. package/bundle/commands/bucket/create-credential.js +173 -0
  30. package/bundle/commands/bucket/delete-credential.js +140 -0
  31. package/bundle/commands/bucket/get-credential.js +151 -0
  32. package/bundle/commands/bucket/list-credentials.js +148 -0
  33. package/bundle/commands/build/branch.js +126 -0
  34. package/bundle/commands/build/checkout.js +198 -0
  35. package/bundle/commands/build/clone.js +153 -0
  36. package/bundle/commands/build/delete.js +227 -0
  37. package/bundle/commands/build/deploy.js +160 -0
  38. package/bundle/commands/build/env/get.js +105 -0
  39. package/bundle/commands/build/env/set.js +115 -0
  40. package/bundle/commands/build/find.js +333 -0
  41. package/bundle/commands/build/generate.js +75 -0
  42. package/bundle/commands/build/init.js +76 -0
  43. package/bundle/commands/build/list.js +11 -0
  44. package/bundle/commands/build/sandbox.js +65 -0
  45. package/bundle/commands/build/start.js +84 -0
  46. package/bundle/commands/build/status.js +1839 -0
  47. package/bundle/commands/build/stop.js +84 -0
  48. package/bundle/commands/build/tools/check.js +32 -0
  49. package/bundle/commands/build/tools/fmt.js +49 -0
  50. package/bundle/commands/build/unsandbox.js +65 -0
  51. package/bundle/commands/build/upload.js +83 -0
  52. package/bundle/commands/build/validate.js +71 -0
  53. package/bundle/commands/build/workos/delete.js +86 -0
  54. package/bundle/commands/build/workos/env/attach.js +134 -0
  55. package/bundle/commands/build/workos/env/create.js +176 -0
  56. package/bundle/commands/build/workos/env/delete.js +84 -0
  57. package/bundle/commands/build/workos/env/detach.js +115 -0
  58. package/bundle/commands/build/workos/env/get.js +117 -0
  59. package/bundle/commands/build/workos/env/list.js +139 -0
  60. package/bundle/commands/build/workos/env/set.js +138 -0
  61. package/bundle/commands/build/workos/invite.js +91 -0
  62. package/bundle/commands/build/workos/setup.js +124 -0
  63. package/bundle/commands/build/workos/status.js +93 -0
  64. package/bundle/commands/dns/create.js +128 -0
  65. package/bundle/commands/dns/delete.js +80 -0
  66. package/bundle/commands/dns/get.js +167 -0
  67. package/bundle/commands/dns/list.js +193 -0
  68. package/bundle/commands/dns/records/create.js +150 -0
  69. package/bundle/commands/dns/records/delete.js +76 -0
  70. package/bundle/commands/dns/records/get.js +118 -0
  71. package/bundle/commands/dns/records/list.js +153 -0
  72. package/bundle/commands/dns/records/update.js +146 -0
  73. package/bundle/commands/logs/query.js +237 -0
  74. package/bundle/commands/logs/tail.js +155 -0
  75. package/bundle/commands/mcp/install-claude.js +220 -0
  76. package/bundle/commands/mcp/install-gemini.js +220 -0
  77. package/bundle/commands/mcp/install-goose.js +232 -0
  78. package/bundle/commands/mcp/status.js +153 -0
  79. package/bundle/commands/object/delete.js +180 -0
  80. package/bundle/commands/object/get.js +209 -0
  81. package/bundle/commands/object/list.js +206 -0
  82. package/bundle/commands/object/put.js +211 -0
  83. package/bundle/commands/query/chunk-search.js +123 -0
  84. package/bundle/commands/query/document.js +126 -0
  85. package/bundle/commands/query/events.js +98 -0
  86. package/bundle/commands/query/reindex.js +147 -0
  87. package/bundle/commands/query/search.js +169 -0
  88. package/bundle/commands/tail.js +31 -0
  89. package/bundle/index.js +51 -0
  90. package/dist/base-command.d.ts +6 -0
  91. package/dist/base-command.d.ts.map +1 -1
  92. package/dist/base-command.js +14 -1
  93. package/dist/build.d.ts +2 -1
  94. package/dist/build.d.ts.map +1 -1
  95. package/dist/build.js +169 -51
  96. package/dist/codegen.d.ts +1 -1
  97. package/dist/codegen.d.ts.map +1 -1
  98. package/dist/codegen.js +17 -3
  99. package/dist/codegen.test.js +44 -0
  100. package/dist/commands/build/checkout.d.ts.map +1 -1
  101. package/dist/commands/build/checkout.js +4 -0
  102. package/dist/commands/build/delete.d.ts.map +1 -1
  103. package/dist/commands/build/delete.js +6 -3
  104. package/dist/commands/build/deploy.d.ts.map +1 -1
  105. package/dist/commands/build/deploy.js +10 -2
  106. package/dist/commands/build/find.d.ts +1 -0
  107. package/dist/commands/build/find.d.ts.map +1 -1
  108. package/dist/commands/build/find.js +33 -2
  109. package/dist/commands/build/validate.d.ts.map +1 -1
  110. package/dist/commands/build/validate.js +0 -1
  111. package/dist/commands/build/workos/delete.d.ts +18 -0
  112. package/dist/commands/build/workos/delete.d.ts.map +1 -0
  113. package/dist/commands/build/workos/delete.js +72 -0
  114. package/dist/commands/build/workos/env/attach.d.ts +24 -0
  115. package/dist/commands/build/workos/env/attach.d.ts.map +1 -0
  116. package/dist/commands/build/workos/env/attach.js +111 -0
  117. package/dist/commands/build/workos/env/create.d.ts +26 -0
  118. package/dist/commands/build/workos/env/create.d.ts.map +1 -0
  119. package/dist/commands/build/workos/env/create.js +156 -0
  120. package/dist/commands/build/workos/env/delete.d.ts +20 -0
  121. package/dist/commands/build/workos/env/delete.d.ts.map +1 -0
  122. package/dist/commands/build/workos/env/delete.js +61 -0
  123. package/dist/commands/build/workos/env/detach.d.ts +21 -0
  124. package/dist/commands/build/workos/env/detach.d.ts.map +1 -0
  125. package/dist/commands/build/workos/env/detach.js +94 -0
  126. package/dist/commands/build/workos/env/get.d.ts +20 -0
  127. package/dist/commands/build/workos/env/get.d.ts.map +1 -0
  128. package/dist/commands/build/workos/env/get.js +94 -0
  129. package/dist/commands/build/workos/env/list.d.ts +18 -0
  130. package/dist/commands/build/workos/env/list.d.ts.map +1 -0
  131. package/dist/commands/build/workos/env/list.js +114 -0
  132. package/dist/commands/build/workos/env/set.d.ts +27 -0
  133. package/dist/commands/build/workos/env/set.d.ts.map +1 -0
  134. package/dist/commands/build/workos/env/set.js +115 -0
  135. package/dist/commands/build/workos/invite.d.ts +21 -0
  136. package/dist/commands/build/workos/invite.d.ts.map +1 -0
  137. package/dist/commands/build/workos/invite.js +68 -0
  138. package/dist/commands/build/workos/setup.d.ts +20 -0
  139. package/dist/commands/build/workos/setup.d.ts.map +1 -0
  140. package/dist/commands/build/workos/setup.js +106 -0
  141. package/dist/commands/build/workos/status.d.ts +18 -0
  142. package/dist/commands/build/workos/status.d.ts.map +1 -0
  143. package/dist/commands/build/workos/status.js +70 -0
  144. package/dist/commands/mcp/install-claude.d.ts.map +1 -1
  145. package/dist/commands/mcp/install-claude.js +0 -2
  146. package/dist/commands/mcp/install-gemini.d.ts.map +1 -1
  147. package/dist/commands/mcp/install-gemini.js +0 -2
  148. package/dist/commands/mcp/install-goose.d.ts.map +1 -1
  149. package/dist/commands/mcp/install-goose.js +0 -2
  150. package/dist/deploy.d.ts.map +1 -1
  151. package/dist/deploy.js +2 -2
  152. package/dist/index.d.ts +2 -0
  153. package/dist/index.d.ts.map +1 -1
  154. package/dist/index.js +4 -0
  155. package/oclif.manifest.json +4286 -2208
  156. package/package.json +8 -5
  157. package/templates/claude-code/debug-raindrop-app.md +89 -0
  158. package/templates/claude-code/new-raindrop-app.md +10 -6
  159. package/templates/claude-code/reattach-raindrop-session.md +50 -12
  160. package/templates/claude-code/update-raindrop-app.md +61 -9
  161. package/templates/db/node_modules/.bin/prisma +2 -2
  162. package/templates/db/node_modules/.bin/prisma-kysely +2 -2
  163. package/templates/db/node_modules/.bin/tsc +2 -2
  164. package/templates/db/node_modules/.bin/tsserver +2 -2
  165. package/templates/db/node_modules/.bin/zx +2 -2
  166. package/templates/gemini-code/debug-raindrop-app.toml +86 -0
  167. package/templates/gemini-code/new-raindrop-app.toml +9 -5
  168. package/templates/gemini-code/reattach-raindrop-session.toml +9 -11
  169. package/templates/gemini-code/update-raindrop-app.toml +55 -10
  170. package/templates/goose/debug-raindrop-app.yaml +91 -0
  171. package/templates/goose/new-raindrop-app.yaml +12 -7
  172. package/templates/goose/reattach-raindrop-session.yaml +11 -4
  173. package/templates/goose/update-raindrop-app.yaml +57 -5
  174. package/templates/init/src/_app/auth.ts +18 -0
  175. package/templates/init/src/_app/cors.ts +64 -0
  176. package/dist/tsconfig.tsbuildinfo +0 -1
  177. package/templates/claude-code/raindrop-guidelines.md +0 -322
  178. package/templates/gemini-code/raindrop-guidelines.md +0 -322
@@ -0,0 +1,155 @@
1
+ import {
2
+ displayTraceGroupedEvents
3
+ } from "../../chunk-KXEV6E63.js";
4
+ import {
5
+ BaseCommand
6
+ } from "../../chunk-MCRKUPJY.js";
7
+ import {
8
+ StreamLogsRequestSchema,
9
+ __toESM,
10
+ create,
11
+ init_cjs_shims,
12
+ require_lib,
13
+ valueOf
14
+ } from "../../chunk-G6NE675D.js";
15
+
16
+ // src/commands/logs/tail.ts
17
+ init_cjs_shims();
18
+ var import_core = __toESM(require_lib(), 1);
19
+ var Tail = class extends BaseCommand {
20
+ static args = {};
21
+ static description = "tail logs of applications deployed";
22
+ static examples = [
23
+ `<%= config.bin %> <%= command.id %>`,
24
+ `<%= config.bin %> <%= command.id %> --application my-app`,
25
+ `<%= config.bin %> <%= command.id %> --application my-app --version v1.2.3`
26
+ ];
27
+ static flags = {
28
+ ...BaseCommand.HIDDEN_FLAGS,
29
+ output: import_core.Flags.string({
30
+ char: "o",
31
+ description: "output format",
32
+ default: "text",
33
+ options: ["text", "json"]
34
+ }),
35
+ impersonate: import_core.Flags.string({
36
+ char: "i",
37
+ description: "impersonate organization",
38
+ required: false,
39
+ hidden: true
40
+ }),
41
+ manifest: import_core.Flags.string({
42
+ char: "m",
43
+ description: "project manifest",
44
+ required: false,
45
+ default: "raindrop.manifest",
46
+ hidden: true
47
+ }),
48
+ application: import_core.Flags.string({
49
+ char: "a",
50
+ description: "application",
51
+ required: false
52
+ }),
53
+ version: import_core.Flags.string({
54
+ char: "v",
55
+ description: "application version",
56
+ required: false
57
+ }),
58
+ rainbowAuthService: import_core.Flags.string({
59
+ default: "https://liquidmetal.run/api/connect",
60
+ hidden: true,
61
+ env: "LIQUIDMETAL_RAINBOW_AUTH_SERVICE"
62
+ }),
63
+ raindropCatalogService: import_core.Flags.string({
64
+ env: "RAINDROP_CATALOG_SERVICE",
65
+ description: "URL of the catalog service",
66
+ hidden: true
67
+ })
68
+ };
69
+ async run() {
70
+ const apps = await this.loadManifest();
71
+ const config = await this.loadConfig();
72
+ if (!this.flags.version) {
73
+ if (!config.versionId) {
74
+ this.error("No version provided or found in config", { exit: 1 });
75
+ }
76
+ this.flags.version = config.versionId;
77
+ }
78
+ if (!this.flags.application) {
79
+ const app = apps[0];
80
+ if (app === void 0) {
81
+ this.error("No application provided or found in manifest", { exit: 1 });
82
+ }
83
+ this.flags.application = valueOf(app.name);
84
+ }
85
+ const {
86
+ userId,
87
+ client: riverjackService,
88
+ organizationId: defaultOrganizationId
89
+ } = await this.tenantRiverjackService();
90
+ const organizationId = this.flags.impersonate ?? defaultOrganizationId;
91
+ this.log(`Using organization: ${organizationId}`);
92
+ this.log(`Using user: ${userId}`);
93
+ this.log(`Tailing logs for ${this.flags.application}@${this.flags.version} using Riverjack service...`);
94
+ this.log("Press Ctrl+C to stop\n");
95
+ try {
96
+ const request = create(StreamLogsRequestSchema, {
97
+ organizationId,
98
+ userId,
99
+ applicationName: this.flags.application,
100
+ applicationVersionId: this.flags.version
101
+ });
102
+ for await (const resp of riverjackService.streamLogs(request)) {
103
+ if (this.flags.output === "json") {
104
+ this.log(JSON.stringify(resp, null, 2));
105
+ continue;
106
+ }
107
+ switch (resp.responseType) {
108
+ case "heartbeat":
109
+ break;
110
+ case "stream_started":
111
+ this.log(`\u{1F504} Started streaming logs for ${this.flags.application}@${this.flags.version}`);
112
+ this.log(` Organization: ${organizationId}`);
113
+ this.log(` User: ${userId}`);
114
+ if (resp.timestamp) {
115
+ this.log(` Time: ${new Date(resp.timestamp).toLocaleString()}`);
116
+ }
117
+ break;
118
+ case "events":
119
+ if (resp.events && resp.events.length > 0) {
120
+ displayTraceGroupedEvents(resp.events, { log: (message) => this.log(message) });
121
+ }
122
+ break;
123
+ case "stream_ended":
124
+ this.log(`\u2705 Stream ended`);
125
+ if (resp.timestamp) {
126
+ this.log(` End time: ${new Date(resp.timestamp).toLocaleString()}`);
127
+ }
128
+ break;
129
+ case "service_error":
130
+ this.log(`\u274C Service error`);
131
+ if (resp.message) {
132
+ this.log(` Error: ${resp.message}`);
133
+ }
134
+ if (resp.timestamp) {
135
+ this.log(` Time: ${new Date(resp.timestamp).toLocaleString()}`);
136
+ }
137
+ break;
138
+ default:
139
+ if (resp.message) {
140
+ this.log(resp.message);
141
+ }
142
+ }
143
+ }
144
+ } catch (error) {
145
+ if (error instanceof Error) {
146
+ this.error(`Failed to tail logs: ${error.message}`, { exit: 1 });
147
+ } else {
148
+ this.error("Failed to tail logs: Unknown error", { exit: 1 });
149
+ }
150
+ }
151
+ }
152
+ };
153
+ export {
154
+ Tail as default
155
+ };
@@ -0,0 +1,220 @@
1
+ import {
2
+ BaseCommand
3
+ } from "../../chunk-MCRKUPJY.js";
4
+ import {
5
+ init_cjs_shims,
6
+ urlifyOrganizationId
7
+ } from "../../chunk-G6NE675D.js";
8
+
9
+ // src/commands/mcp/install-claude.ts
10
+ init_cjs_shims();
11
+ import { spawn } from "node:child_process";
12
+ import { readFile, writeFile, mkdir, access } from "node:fs/promises";
13
+ import { dirname, join } from "node:path";
14
+ import { fileURLToPath } from "node:url";
15
+ import { homedir } from "node:os";
16
+ import { constants } from "node:fs";
17
+ var McpInstallClaude = class extends BaseCommand {
18
+ static description = "Install complete Raindrop integration for Claude Code IDE";
19
+ static examples = [
20
+ `<%= config.bin %> mcp install-claude
21
+ Install Raindrop MCP server and Claude Code configuration files
22
+
23
+ This command will:
24
+ - Check if Claude CLI is installed and accessible
25
+ - Verify if raindrop-mcp server already exists (prevents duplicates)
26
+ - Add the raindrop-mcp server to your Claude Code MCP configuration
27
+ - Create Claude Code slash commands in ~/.claude/commands/:
28
+ \u2022 /new-raindrop-app - Start new Raindrop application development
29
+ \u2022 /update-raindrop-app - Update existing Raindrop applications
30
+ \u2022 /reattach-raindrop-session - Resume previous development sessions
31
+
32
+ Requirements:
33
+ - Claude CLI must be installed (https://claude.ai/download)
34
+ - You must be logged into your Raindrop organization via 'raindrop auth login'
35
+ `
36
+ ];
37
+ static flags = {
38
+ ...BaseCommand.HIDDEN_FLAGS
39
+ };
40
+ async run() {
41
+ await this.installClaudeIntegration();
42
+ await this.createClaudeConfigFiles();
43
+ }
44
+ async installClaudeIntegration() {
45
+ console.log("\u{1F50D} Checking if Claude CLI is installed...");
46
+ if (!await this.checkClaudeInstalled()) {
47
+ this.error("Claude CLI is not installed. Please install it first: https://claude.ai/download", { exit: 1 });
48
+ }
49
+ console.log("Claude CLI is installed");
50
+ console.log("\u{1F50D} Checking for existing MCP server...");
51
+ if (await this.checkMcpServerExists()) {
52
+ console.log('MCP server "raindrop-mcp" already exists in Claude Code configuration');
53
+ console.log("");
54
+ console.log("To update the existing server:");
55
+ console.log(" 1. Remove the existing server: claude mcp remove raindrop-mcp");
56
+ console.log(" 2. Run this command again: raindrop mcp install-claude");
57
+ console.log("");
58
+ console.log("Or manually update the server URL in your Claude Code MCP settings.");
59
+ this.error("MCP server already exists. Please remove it first before adding a new one.", { exit: 1 });
60
+ }
61
+ console.log("\u{1F50D} Getting organization identity...");
62
+ let identity;
63
+ try {
64
+ identity = await this.catalogIdentity();
65
+ console.log(`Organization ID: ${identity.organizationId}`);
66
+ } catch (error) {
67
+ console.log(`Failed to get identity: ${error.message}`);
68
+ this.error(`Failed to get organization identity: ${error.message}`, { exit: 1 });
69
+ }
70
+ const urlSafeOrgId = urlifyOrganizationId(identity.organizationId);
71
+ const mcpUrl = `https://raindrop-mcp.${urlSafeOrgId}.lmapp.run/mcp`;
72
+ console.log(`\u{1F50D} MCP URL: ${mcpUrl}`);
73
+ if (await this.checkMcpAlreadyConfigured()) {
74
+ console.log("\u2705 MCP integration already configured.");
75
+ console.log("\u{1F4A1} Use `raindrop mcp status` to check current configuration.");
76
+ return;
77
+ }
78
+ try {
79
+ console.log("\u{1F50D} Executing Claude MCP command...");
80
+ await this.executeClaudeCommand(["mcp", "add", "--transport", "http", "raindrop-mcp", mcpUrl]);
81
+ console.log("MCP integration for Claude Code installed successfully");
82
+ console.log(`Server URL: ${mcpUrl}`);
83
+ } catch (error) {
84
+ console.log(`Claude command failed: ${error.message}`);
85
+ this.error(`Failed to configure Claude MCP integration: ${error.message}`, { exit: 1 });
86
+ }
87
+ }
88
+ async createClaudeConfigFiles() {
89
+ try {
90
+ const home = homedir();
91
+ const raindropDir = join(home, ".raindrop");
92
+ const claudeDir = join(home, ".claude");
93
+ const commandsDir = join(claudeDir, "commands");
94
+ await mkdir(raindropDir, { recursive: true });
95
+ await mkdir(claudeDir, { recursive: true });
96
+ await mkdir(commandsDir, { recursive: true });
97
+ const currentFileUrl = import.meta.url;
98
+ const currentDir = dirname(fileURLToPath(currentFileUrl));
99
+ let packageRoot = currentDir;
100
+ while (packageRoot !== dirname(packageRoot)) {
101
+ try {
102
+ await access(join(packageRoot, "package.json"), constants.F_OK);
103
+ break;
104
+ } catch {
105
+ packageRoot = dirname(packageRoot);
106
+ }
107
+ }
108
+ const templatesDir = join(packageRoot, "templates", "claude-code");
109
+ const fileMap = [
110
+ ["new-raindrop-app.md", join(commandsDir, "new-raindrop-app.md"), "New app command"],
111
+ ["update-raindrop-app.md", join(commandsDir, "update-raindrop-app.md"), "Update app command"],
112
+ ["reattach-raindrop-session.md", join(commandsDir, "reattach-raindrop-session.md"), "Reattach session command"]
113
+ ];
114
+ const createdFiles = [];
115
+ const skippedFiles = [];
116
+ const existingFiles = [];
117
+ for (const [, destPath] of fileMap) {
118
+ try {
119
+ await access(destPath, constants.F_OK);
120
+ existingFiles.push(destPath);
121
+ } catch {
122
+ }
123
+ }
124
+ for (const [templateFile, destPath, description] of fileMap) {
125
+ try {
126
+ const templatePath = join(templatesDir, templateFile);
127
+ const content = await readFile(templatePath, "utf-8");
128
+ await writeFile(destPath, content, "utf-8");
129
+ createdFiles.push(destPath);
130
+ } catch (error) {
131
+ console.log(`Failed to create ${description}: ${error.message}`);
132
+ skippedFiles.push(destPath);
133
+ }
134
+ }
135
+ if (createdFiles.length > 0) {
136
+ console.log("\u{1F4DD} Created Claude Code configuration files:");
137
+ for (const filePath of createdFiles) {
138
+ console.log(` ${filePath}`);
139
+ }
140
+ }
141
+ if (skippedFiles.length > 0) {
142
+ console.log("Skipped files due to errors:");
143
+ for (const filePath of skippedFiles) {
144
+ console.log(` ${filePath}`);
145
+ }
146
+ }
147
+ if (createdFiles.length > 0) {
148
+ console.log("Restart Claude Code for changes to take effect");
149
+ }
150
+ } catch (error) {
151
+ this.error(`Failed to create Claude configuration files: ${error.message}`, { exit: 1 });
152
+ }
153
+ }
154
+ async checkClaudeInstalled() {
155
+ return new Promise((resolve) => {
156
+ const childProcess = spawn("claude", ["--version"], { stdio: "ignore" });
157
+ childProcess.on("close", (code) => resolve(code === 0));
158
+ childProcess.on("error", () => resolve(false));
159
+ });
160
+ }
161
+ async checkMcpServerExists() {
162
+ return new Promise((resolve) => {
163
+ const childProcess = spawn("claude", ["mcp", "list"], { stdio: "pipe" });
164
+ let output = "";
165
+ childProcess.stdout?.on("data", (data) => {
166
+ output += data.toString();
167
+ });
168
+ childProcess.on("close", (code) => {
169
+ if (code !== 0) {
170
+ resolve(false);
171
+ return;
172
+ }
173
+ resolve(output.includes("raindrop-mcp"));
174
+ });
175
+ childProcess.on("error", () => resolve(false));
176
+ });
177
+ }
178
+ async executeClaudeCommand(args) {
179
+ return new Promise((resolve, reject) => {
180
+ const childProcess = spawn("claude", args, {
181
+ stdio: "inherit"
182
+ // Show output to user so we can see errors
183
+ });
184
+ childProcess.on("close", (code) => {
185
+ if (code === 0) {
186
+ resolve();
187
+ } else {
188
+ reject(new Error(`Claude MCP command failed with exit code ${code}`));
189
+ }
190
+ });
191
+ childProcess.on("error", (error) => {
192
+ reject(new Error(`Failed to execute Claude CLI: ${error.message}`));
193
+ });
194
+ });
195
+ }
196
+ async checkMcpAlreadyConfigured() {
197
+ return new Promise((resolve) => {
198
+ const childProcess = spawn("claude", ["mcp", "list"], {
199
+ stdio: "pipe"
200
+ });
201
+ let output = "";
202
+ childProcess.stdout?.on("data", (data) => {
203
+ output += data.toString();
204
+ });
205
+ childProcess.on("close", (code) => {
206
+ if (code === 0) {
207
+ resolve(output.includes("raindrop-mcp"));
208
+ } else {
209
+ resolve(false);
210
+ }
211
+ });
212
+ childProcess.on("error", () => {
213
+ resolve(false);
214
+ });
215
+ });
216
+ }
217
+ };
218
+ export {
219
+ McpInstallClaude as default
220
+ };
@@ -0,0 +1,220 @@
1
+ import {
2
+ BaseCommand
3
+ } from "../../chunk-MCRKUPJY.js";
4
+ import {
5
+ init_cjs_shims,
6
+ urlifyOrganizationId
7
+ } from "../../chunk-G6NE675D.js";
8
+
9
+ // src/commands/mcp/install-gemini.ts
10
+ init_cjs_shims();
11
+ import { spawn } from "node:child_process";
12
+ import { readFile, writeFile, mkdir, access } from "node:fs/promises";
13
+ import { dirname, join } from "node:path";
14
+ import { fileURLToPath } from "node:url";
15
+ import { homedir } from "node:os";
16
+ import { constants } from "node:fs";
17
+ var McpInstallGemini = class extends BaseCommand {
18
+ static description = "Install complete Raindrop integration for Gemini CLI";
19
+ static examples = [
20
+ `<%= config.bin %> mcp install-gemini
21
+ Install Raindrop MCP server and Gemini CLI configuration files
22
+
23
+ This command will:
24
+ - Check if Gemini CLI is installed and accessible
25
+ - Verify if raindrop-mcp server already exists (prevents duplicates)
26
+ - Add the raindrop-mcp server to your Gemini CLI MCP configuration
27
+ - Create Gemini CLI slash commands in ~/.gemini/commands/ (TOML format):
28
+ \u2022 /new-raindrop-app - Start new Raindrop application development
29
+ \u2022 /update-raindrop-app - Update existing Raindrop applications
30
+ \u2022 /reattach-raindrop-session - Resume previous development sessions
31
+
32
+ Requirements:
33
+ - Gemini CLI must be installed
34
+ - You must be logged into your Raindrop organization via 'raindrop auth login'
35
+ `
36
+ ];
37
+ static flags = {
38
+ ...BaseCommand.HIDDEN_FLAGS
39
+ };
40
+ async run() {
41
+ await this.installGeminiIntegration();
42
+ await this.createGeminiConfigFiles();
43
+ }
44
+ async installGeminiIntegration() {
45
+ console.log("\u{1F50D} Checking if Gemini CLI is installed...");
46
+ if (!await this.checkGeminiInstalled()) {
47
+ this.error("Gemini CLI is not installed. Please install it first at https://github.com/google-gemini/gemini-cli.", { exit: 1 });
48
+ }
49
+ console.log("Gemini CLI is installed");
50
+ console.log("\u{1F50D} Checking for existing MCP server...");
51
+ if (await this.checkMcpServerExists()) {
52
+ console.log('MCP server "raindrop-mcp" already exists in Gemini CLI configuration');
53
+ console.log("");
54
+ console.log("To update the existing server:");
55
+ console.log(" 1. Remove the existing server: gemini mcp remove raindrop-mcp");
56
+ console.log(" 2. Run this command again: raindrop mcp install-gemini");
57
+ console.log("");
58
+ console.log("Or manually update the server URL in your Gemini CLI MCP settings.");
59
+ this.error("MCP server already exists. Please remove it first before adding a new one.", { exit: 1 });
60
+ }
61
+ console.log("\u{1F50D} Getting organization identity...");
62
+ let identity;
63
+ try {
64
+ identity = await this.catalogIdentity();
65
+ console.log(`Organization ID: ${identity.organizationId}`);
66
+ } catch (error) {
67
+ console.log(`Failed to get identity: ${error.message}`);
68
+ this.error(`Failed to get organization identity: ${error.message}`, { exit: 1 });
69
+ }
70
+ const urlSafeOrgId = urlifyOrganizationId(identity.organizationId);
71
+ const mcpUrl = `https://raindrop-mcp.${urlSafeOrgId}.lmapp.run/mcp`;
72
+ console.log(`\u{1F50D} MCP URL: ${mcpUrl}`);
73
+ if (await this.checkMcpAlreadyConfigured()) {
74
+ console.log("\u2705 MCP integration already configured.");
75
+ console.log("\u{1F4A1} Use `raindrop mcp status` to check current configuration.");
76
+ return;
77
+ }
78
+ try {
79
+ console.log("\u{1F50D} Executing Gemini MCP command...");
80
+ await this.executeGeminiCommand(["mcp", "add", "--transport", "http", "raindrop-mcp", mcpUrl, "--trust"]);
81
+ console.log("MCP integration for Gemini installed successfully");
82
+ console.log(`Server URL: ${mcpUrl}`);
83
+ } catch (error) {
84
+ console.log(`Gemini command failed: ${error.message}`);
85
+ this.error(`Failed to configure Gemini MCP integration: ${error.message}`, { exit: 1 });
86
+ }
87
+ }
88
+ async createGeminiConfigFiles() {
89
+ try {
90
+ const home = homedir();
91
+ const raindropDir = join(home, ".raindrop");
92
+ const geminiDir = join(home, ".gemini");
93
+ const commandsDir = join(geminiDir, "commands");
94
+ await mkdir(raindropDir, { recursive: true });
95
+ await mkdir(geminiDir, { recursive: true });
96
+ await mkdir(commandsDir, { recursive: true });
97
+ const currentFileUrl = import.meta.url;
98
+ const currentDir = dirname(fileURLToPath(currentFileUrl));
99
+ let packageRoot = currentDir;
100
+ while (packageRoot !== dirname(packageRoot)) {
101
+ try {
102
+ await access(join(packageRoot, "package.json"), constants.F_OK);
103
+ break;
104
+ } catch {
105
+ packageRoot = dirname(packageRoot);
106
+ }
107
+ }
108
+ const templatesDir = join(packageRoot, "templates", "gemini-code");
109
+ const fileMap = [
110
+ ["new-raindrop-app.toml", join(commandsDir, "new-raindrop-app.toml"), "New app command"],
111
+ ["update-raindrop-app.toml", join(commandsDir, "update-raindrop-app.toml"), "Update app command"],
112
+ ["reattach-raindrop-session.toml", join(commandsDir, "reattach-raindrop-session.toml"), "Reattach session command"]
113
+ ];
114
+ const createdFiles = [];
115
+ const skippedFiles = [];
116
+ const existingFiles = [];
117
+ for (const [, destPath] of fileMap) {
118
+ try {
119
+ await access(destPath, constants.F_OK);
120
+ existingFiles.push(destPath);
121
+ } catch {
122
+ }
123
+ }
124
+ for (const [templateFile, destPath, description] of fileMap) {
125
+ try {
126
+ const templatePath = join(templatesDir, templateFile);
127
+ const content = await readFile(templatePath, "utf-8");
128
+ await writeFile(destPath, content, "utf-8");
129
+ createdFiles.push(destPath);
130
+ } catch (error) {
131
+ console.log(`Failed to create ${description}: ${error.message}`);
132
+ skippedFiles.push(destPath);
133
+ }
134
+ }
135
+ if (createdFiles.length > 0) {
136
+ console.log("\u{1F4DD} Created Gemini CLI configuration files:");
137
+ for (const filePath of createdFiles) {
138
+ console.log(` ${filePath}`);
139
+ }
140
+ }
141
+ if (skippedFiles.length > 0) {
142
+ console.log("Skipped files due to errors:");
143
+ for (const filePath of skippedFiles) {
144
+ console.log(` ${filePath}`);
145
+ }
146
+ }
147
+ if (createdFiles.length > 0) {
148
+ console.log("Start or Restart Gemini CLI for changes to take effect");
149
+ }
150
+ } catch (error) {
151
+ this.error(`Failed to create Gemini configuration files: ${error.message}`, { exit: 1 });
152
+ }
153
+ }
154
+ async checkGeminiInstalled() {
155
+ return new Promise((resolve) => {
156
+ const childProcess = spawn("gemini", ["--version"], { stdio: "ignore" });
157
+ childProcess.on("close", (code) => resolve(code === 0));
158
+ childProcess.on("error", () => resolve(false));
159
+ });
160
+ }
161
+ async checkMcpServerExists() {
162
+ return new Promise((resolve) => {
163
+ const childProcess = spawn("gemini", ["mcp", "list"], { stdio: "pipe" });
164
+ let output = "";
165
+ childProcess.stdout?.on("data", (data) => {
166
+ output += data.toString();
167
+ });
168
+ childProcess.on("close", (code) => {
169
+ if (code !== 0) {
170
+ resolve(false);
171
+ return;
172
+ }
173
+ resolve(output.includes("raindrop-mcp"));
174
+ });
175
+ childProcess.on("error", () => resolve(false));
176
+ });
177
+ }
178
+ async executeGeminiCommand(args) {
179
+ return new Promise((resolve, reject) => {
180
+ const childProcess = spawn("gemini", args, {
181
+ stdio: "inherit"
182
+ // Show output to user so we can see errors
183
+ });
184
+ childProcess.on("close", (code) => {
185
+ if (code === 0) {
186
+ resolve();
187
+ } else {
188
+ reject(new Error(`Gemini MCP command failed with exit code ${code}`));
189
+ }
190
+ });
191
+ childProcess.on("error", (error) => {
192
+ reject(new Error(`Failed to execute Gemini CLI: ${error.message}`));
193
+ });
194
+ });
195
+ }
196
+ async checkMcpAlreadyConfigured() {
197
+ return new Promise((resolve) => {
198
+ const childProcess = spawn("gemini", ["mcp", "list"], {
199
+ stdio: "pipe"
200
+ });
201
+ let output = "";
202
+ childProcess.stdout?.on("data", (data) => {
203
+ output += data.toString();
204
+ });
205
+ childProcess.on("close", (code) => {
206
+ if (code === 0) {
207
+ resolve(output.includes("raindrop-mcp"));
208
+ } else {
209
+ resolve(false);
210
+ }
211
+ });
212
+ childProcess.on("error", () => {
213
+ resolve(false);
214
+ });
215
+ });
216
+ }
217
+ };
218
+ export {
219
+ McpInstallGemini as default
220
+ };