firebase-tools 14.14.0 → 14.15.1

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 (79) hide show
  1. package/lib/apphosting/backend.js +40 -15
  2. package/lib/auth.js +37 -2
  3. package/lib/command.js +19 -5
  4. package/lib/commands/apphosting-backends-create.js +8 -5
  5. package/lib/commands/dataconnect-sdk-generate.js +3 -5
  6. package/lib/commands/dataconnect-sql-diff.js +2 -2
  7. package/lib/commands/dataconnect-sql-grant.js +2 -2
  8. package/lib/commands/dataconnect-sql-migrate.js +2 -2
  9. package/lib/commands/dataconnect-sql-setup.js +2 -2
  10. package/lib/commands/dataconnect-sql-shell.js +2 -2
  11. package/lib/commands/init.js +11 -0
  12. package/lib/commands/login.js +12 -7
  13. package/lib/crashlytics/addNote.js +27 -0
  14. package/lib/crashlytics/deleteNote.js +23 -0
  15. package/lib/crashlytics/getIssueDetails.js +5 -20
  16. package/lib/crashlytics/getSampleCrash.js +6 -20
  17. package/lib/crashlytics/listNotes.js +29 -0
  18. package/lib/crashlytics/listTopDevices.js +33 -0
  19. package/lib/crashlytics/listTopIssues.js +8 -23
  20. package/lib/crashlytics/listTopOperatingSystems.js +32 -0
  21. package/lib/crashlytics/listTopVersions.js +32 -0
  22. package/lib/crashlytics/updateIssue.js +35 -0
  23. package/lib/crashlytics/utils.js +38 -0
  24. package/lib/dataconnect/appFinder.js +103 -0
  25. package/lib/dataconnect/load.js +105 -6
  26. package/lib/deploy/dataconnect/prepare.js +1 -3
  27. package/lib/emulator/controller.js +2 -2
  28. package/lib/emulator/downloadableEmulatorInfo.json +17 -17
  29. package/lib/experiments.js +5 -0
  30. package/lib/init/features/dataconnect/create_app.js +48 -0
  31. package/lib/init/features/dataconnect/index.js +19 -45
  32. package/lib/init/features/dataconnect/sdk.js +218 -161
  33. package/lib/init/features/index.js +3 -3
  34. package/lib/init/index.js +5 -2
  35. package/lib/management/apps.js +3 -3
  36. package/lib/mcp/prompts/core/deploy.js +51 -8
  37. package/lib/mcp/prompts/crashlytics/common.js +10 -0
  38. package/lib/mcp/prompts/crashlytics/fix_issue.js +89 -0
  39. package/lib/mcp/prompts/crashlytics/index.js +6 -0
  40. package/lib/mcp/prompts/crashlytics/prioritize_issues.js +79 -0
  41. package/lib/mcp/prompts/dataconnect/index.js +9 -0
  42. package/lib/mcp/prompts/dataconnect/schema.js +68 -0
  43. package/lib/mcp/prompts/index.js +5 -3
  44. package/lib/mcp/tools/core/init.js +16 -3
  45. package/lib/mcp/tools/crashlytics/add_note.js +32 -0
  46. package/lib/mcp/tools/crashlytics/constants.js +11 -0
  47. package/lib/mcp/tools/crashlytics/delete_note.js +35 -0
  48. package/lib/mcp/tools/crashlytics/get_issue_details.js +2 -4
  49. package/lib/mcp/tools/crashlytics/get_sample_crash.js +4 -4
  50. package/lib/mcp/tools/crashlytics/index.js +16 -2
  51. package/lib/mcp/tools/crashlytics/list_notes.js +37 -0
  52. package/lib/mcp/tools/crashlytics/list_top_devices.js +33 -0
  53. package/lib/mcp/tools/crashlytics/list_top_issues.js +5 -7
  54. package/lib/mcp/tools/crashlytics/list_top_operating_systems.js +33 -0
  55. package/lib/mcp/tools/crashlytics/list_top_versions.js +33 -0
  56. package/lib/mcp/tools/crashlytics/update_issue.js +37 -0
  57. package/lib/mcp/tools/dataconnect/compile.js +43 -0
  58. package/lib/mcp/tools/dataconnect/execute_graphql.js +4 -4
  59. package/lib/mcp/tools/dataconnect/execute_graphql_read.js +4 -4
  60. package/lib/mcp/tools/dataconnect/execute_mutation.js +4 -4
  61. package/lib/mcp/tools/dataconnect/execute_query.js +4 -4
  62. package/lib/mcp/tools/dataconnect/generate_operation.js +2 -2
  63. package/lib/mcp/tools/dataconnect/get_connector.js +3 -3
  64. package/lib/mcp/tools/dataconnect/get_schema.js +3 -3
  65. package/lib/mcp/tools/dataconnect/index.js +2 -0
  66. package/lib/mcp/tools/firestore/list_collections.js +0 -3
  67. package/lib/mcp/tools/index.js +3 -0
  68. package/lib/mcp/util/dataconnect/compile.js +18 -0
  69. package/lib/mcp/util/dataconnect/content.js +655 -0
  70. package/lib/utils.js +11 -1
  71. package/package.json +1 -1
  72. package/templates/init/dataconnect/connector.yaml +0 -16
  73. package/templates/init/dataconnect/dataconnect.yaml +2 -1
  74. package/templates/init/dataconnect/mutations.gql +29 -29
  75. package/templates/init/dataconnect/queries.gql +73 -73
  76. package/templates/init/dataconnect/schema.gql +48 -48
  77. package/lib/dataconnect/fileUtils.js +0 -168
  78. /package/lib/mcp/{tools → util}/dataconnect/converter.js +0 -0
  79. /package/lib/mcp/{tools → util}/dataconnect/emulator.js +0 -0
@@ -43,14 +43,57 @@ ${prompt || "<the user didn't supply specific instructions>"}
43
43
  Follow the steps below taking note of any user instructions provided above.
44
44
 
45
45
  1. If there is no active user, prompt the user to run \`firebase login\` in an interactive terminal before continuing.
46
- 2. If there is no \`firebase.json\` file and the current workspace is a static web application, manually create a \`firebase.json\` with \`"hosting"\` configuration based on the current directory's web app configuration. Add a \`{"hosting": {"predeploy": "<build_script>"}}\` config to build before deploying.
47
- 3. If there is no active project, ask the user if they want to use an existing project or create a new one.
48
- 3a. If create a new one, use the \`firebase_create_project\` tool.
49
- 3b. If they want to use an existing one, ask them for a project id (the \`firebase_list_projects\` tool may be helpful).
50
- 4. Only after making sure Firebase has been initialized, run the \`firebase deploy\` shell command to perform the deploy. This may take a few minutes.
51
- 5. If the deploy has errors, attempt to fix them and ask the user clarifying questions as needed.
52
- 6. If the deploy needs \`--force\` to run successfully, ALWAYS prompt the user before running \`firebase deploy --force\`.
53
- 7. If only one specific feature is failing, use command \`firebase deploy --only <feature>\` as you debug.
46
+ 2. Analyze the source code in the current working directory to determine if this is a web app. If it isn't, end this process and tell the user "The /deploy command only works with web apps."
47
+ 3. Analyze the source code in the current working directory to determine if the app requires a server for Server-Side Rendering (SSR). This will determine whether or not to use Firebase App Hosting. Here are instructions to determine if the app needs a server:
48
+ Objective: Analyze the provided codebase files to determine if the web application requires a backend for Server-Side Rendering (SSR). Your final output must be a clear "Yes" or "No" followed by a brief justification.
49
+ Primary Analysis: package.json
50
+ This is the most critical step. If the package.json file is present, perform the following checks in order.
51
+ Parse package.json: Locate and read the contents of the package.json file.
52
+ Check Dependencies:
53
+ Examine the dependencies and devDependencies objects.
54
+ If any of the following packages are listed as keys, you can conclude the app uses SSR.
55
+ next
56
+ nuxt
57
+ @sveltejs/kit
58
+ @angular/ssr
59
+ remix
60
+ If a match is found, proceed directly to the Final Determination step.
61
+ Check Scripts: If no framework dependency was found, examine the scripts object.
62
+ Look for scripts (commonly start or serve) that execute a server process.
63
+ Examples include: "start": "next start", "start": "nuxt start", or "dev": "ng serve --ssr".
64
+ If such a script is found, conclude the app uses SSR and proceed to the Final Determination step.
65
+ Secondary Analysis: Project File Structure
66
+ Perform this analysis only if package.json is missing or inconclusive.
67
+ Scan for Framework-Specific Files and Directories: Search the codebase for the following patterns:
68
+ Next.js: A directory named app/ or pages/. Inside these, check for files containing the function name getServerSideProps.
69
+ Nuxt.js: A directory named server/.
70
+ SvelteKit: Any file ending with the .server.js suffix (e.g., +page.server.js, +layout.server.js).
71
+ Angular: A file named server.ts.
72
+ If any of these patterns are found, conclude the app uses SSR.
73
+ Final Determination
74
+ State Your Conclusion: Begin your response with a definitive "Yes" or "No".
75
+ Yes: The application requires a backend for SSR.
76
+ No: The application does not appear to require a backend for SSR and is likely a static or client-side rendered app.
77
+ Provide Justification: Follow your conclusion with a single sentence explaining the evidence.
78
+ Example (Yes): "Yes, the project requires SSR, as evidenced by the next dependency in package.json."
79
+ Example (Yes): "Yes, the project requires SSR, as evidenced by the presence of a +page.server.js file."
80
+ Example (No): "No, there are no dependencies or file structures that indicate the use of a server-side rendering framework."
81
+ 4. If there is no \`firebase.json\` file, manually create one based on whether the app requires SSR:
82
+ 4a. If the app requires SSR, configure Firebase App Hosting:
83
+ Create \`firebase.json\ with an "apphosting" configuration, setting backendId to the app's name in package.json: \`{"apphosting": {"backendId": "<backendId>"}}\
84
+ 4b. If the app does NOT require SSR, configure Firebase Hosting:
85
+ Create \`firebase.json\ with a "hosting" configuration. Add a \`{"hosting": {"predeploy": "<build_script>"}}\` config to build before deploying.
86
+ 5. Check if there is an active Firebase project for this environment (the \`firebase_get_environment\` tool may be helpful). If there is, proceed using that project. If there is not an active project, give the user two options: Use an existing Firebase project or Create a new one. Wait for their response before proceeding.
87
+ 5a. If the user chooses to use an existing Firebase project, the \`firebase_list_projects\` tool may be helpful. Set the selected project as the active project (the \`firebase_update_environment\` tool may be helpful).
88
+ 5b. If the user chooses to create a new project, use the \`firebase_create_project \` tool. Then set the new project as the active project (the \`firebase_update_environment\` tool may be helpful).
89
+ 6. If firebase.json contains an "apphosting" configuration, check if a backend exists matching the provided backendId (the \`apphosting_list_backends\` tool may be helpful).
90
+ If it doesn't exist, create one by running the \`firebase apphosting:backends:create --backend <backendId> --primary-region us-central1 --root-dir .\` shell.
91
+ 7. Only after making sure Firebase has been initialized, run the \`firebase deploy\` shell command to perform the deploy. This may take a few minutes.
92
+ 7a. If deploying to apphosting, tell the user the deployment will take a few minutes, and they can monitor deployment progress in the Firebase console: \`https://console.firebase.google.com/project/<projectId>/apphosting\`
93
+ 8. If the deploy has errors, attempt to fix them and ask the user clarifying questions as needed.
94
+ 9. If the deploy needs \`--force\` to run successfully, ALWAYS prompt the user before running \`firebase deploy --force\`.
95
+ 10. If only one specific feature is failing, use command \`firebase deploy --only <feature>\` as you debug.
96
+ 11. If the deploy succeeds, your job is finished.
54
97
  `.trim(),
55
98
  },
56
99
  },
@@ -0,0 +1,10 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.getAppIdInstruction = exports.ACTIVE_USER_INSTRUCTION = void 0;
4
+ exports.ACTIVE_USER_INSTRUCTION = "If the Firbase 'Active user' is set to <NONE>, instruct the user to run `firebase login` before continuing. You will know that the user is not logged in if we have nothing in the 'Active user' field.";
5
+ const getAppIdInstruction = (index) => `If there is no active app id, then do the following:
6
+ ${index}a. If this is an Android app, read the mobilesdk_app_id value specified in the google-services.json file. If there are multiple files or multiple app ids in single file. Ask the user to disambiguate.
7
+ ${index}b. If this is an iOS app, read the GOOGLE_APP_ID from GoogleService-Info.plist file. If there are multiple files or multiple app ids in single file. Ask the user to disambiguate.
8
+ ${index}c. If you can't find either of the above, ask the user for the app id.
9
+ `;
10
+ exports.getAppIdInstruction = getAppIdInstruction;
@@ -0,0 +1,89 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.fix_issue = void 0;
4
+ const prompt_1 = require("../../prompt");
5
+ const common_1 = require("./common");
6
+ const APP_ID_INSTRUCTION = (0, common_1.getAppIdInstruction)(2);
7
+ exports.fix_issue = (0, prompt_1.prompt)({
8
+ name: "fix_issue",
9
+ omitPrefix: false,
10
+ description: "Fix a Crashlytics issue",
11
+ arguments: [
12
+ {
13
+ name: "app_id",
14
+ description: "A Firebase app id.",
15
+ required: false,
16
+ },
17
+ {
18
+ name: "issue_id",
19
+ description: "A Crashlytics issue id.",
20
+ required: true,
21
+ },
22
+ ],
23
+ annotations: {
24
+ title: "Prioritize Crashlytics Issues",
25
+ },
26
+ }, async ({ app_id, issue_id }, { accountEmail }) => {
27
+ return [
28
+ {
29
+ role: "user",
30
+ content: {
31
+ type: "text",
32
+ text: `
33
+ Your goal is to fix a specific issue from Crashlytics.
34
+
35
+ Active user: ${accountEmail || "<NONE>"}
36
+ Active app: ${app_id || "<NONE>"}
37
+ Issue id: ${issue_id}
38
+
39
+ ## Required information
40
+
41
+ ## Required information
42
+
43
+ Before fetching and prioritizing issues, secure the following information:
44
+
45
+ First, and this is INCREDIBLY IMPORTANT, verify the active user. IT IS SO IMPORTANT THAT YOU DO THIS FIRST. NO TOOL CALL WILL WORK WITHOUT IT. ${common_1.ACTIVE_USER_INSTRUCTION}
46
+ Then, verify the app id. ${APP_ID_INSTRUCTION}
47
+ Finally, verify the issue id is not null or empty.
48
+
49
+ All are required to successfully investigate and fix an issue.
50
+
51
+ ## Steps
52
+
53
+ 1. Make sure you have a good understanding of the code structure and where different functionality exists
54
+ 2. Use the 'crashlytics_get_issue_details' tool to get more context on the issue.
55
+ 3. Use the 'crashlytics_get_sample_crash_for_issue' tool to get 3 example crashes for this issue.
56
+ 4. Read the files that exist in the stack trace of the issue to understand the crash deeply.
57
+ 5. Determine the root cause of the crash.
58
+ 6. Write out a plan using the following criteria:
59
+ 6a. Write out a description of the issue and including
60
+ * A brief description of the cause of the issue
61
+ * A determination of your level of confidence in the cause of the issue
62
+ * A determination of which library is at fault, this codebase or a dependent library
63
+ * A determination for how complex the fix will be
64
+ 6b. The plan should include relevant files to change
65
+ 6c. The plan should include a test plan to verify the fix
66
+ 6d. Use the following format for the plan:
67
+
68
+ **Cause**
69
+ <A description of the cause of the issue>
70
+
71
+ **Confidence**: <one of "not at all confident", "somewhat confident", "confident", "very confident">
72
+ **Fault**: <a determination of whether this code base is at fault or a dependent library is at fault>
73
+ **Complexity**: <one of "simple", "moderately simple", "moderately hard", "hard", "oof, I don't know where to start">
74
+
75
+ **Fix**
76
+ <A plan for how to fix the issue>
77
+
78
+ **Test**
79
+ <a plan for how to test that the issue has been fixed an protect against regressions>
80
+ 7. Present the plan to the user and get approval before making the change.
81
+ 8. Fix the issue.
82
+ 8a. Be mindful of API contracts and do not add fields to resources without a clear way to populate those fields
83
+ 8b. If there is not enough information in the crash report to find a root cause, describe why you cannot fix the issue instead of making a guess.
84
+ 9. Ask the developer if they would like you to test the fix for them.
85
+ `.trim(),
86
+ },
87
+ },
88
+ ];
89
+ });
@@ -0,0 +1,6 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.crashlyticsPrompts = void 0;
4
+ const fix_issue_1 = require("./fix_issue");
5
+ const prioritize_issues_1 = require("./prioritize_issues");
6
+ exports.crashlyticsPrompts = [fix_issue_1.fix_issue, prioritize_issues_1.prioritize_issues];
@@ -0,0 +1,79 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.prioritize_issues = void 0;
4
+ const prompt_1 = require("../../prompt");
5
+ const common_1 = require("./common");
6
+ const APP_ID_INSTRUCTION = (0, common_1.getAppIdInstruction)(2);
7
+ exports.prioritize_issues = (0, prompt_1.prompt)({
8
+ name: "prioritize_issues",
9
+ omitPrefix: false,
10
+ description: "Fetch and prioritize issues from Crashlytics.",
11
+ arguments: [
12
+ {
13
+ name: "app_id",
14
+ description: "AppId for which the issues list should be fetched.",
15
+ required: false,
16
+ },
17
+ {
18
+ name: "issue_count",
19
+ description: "The number of issues that should be returned in the final list. Defaults to 5.",
20
+ required: false,
21
+ },
22
+ {
23
+ name: "prompt",
24
+ description: "Any additional instructions you wish to provide about issue prioritization.",
25
+ required: false,
26
+ },
27
+ ],
28
+ annotations: {
29
+ title: "Prioritize Crashlytics Issues",
30
+ },
31
+ }, async ({ app_id, prompt, issue_count }, { accountEmail }) => {
32
+ return [
33
+ {
34
+ role: "user",
35
+ content: {
36
+ type: "text",
37
+ text: `
38
+ Your goal is to prioritize issues from Crashlytics and return the top ${issue_count || 5} issues based on the criteria below.
39
+
40
+ Active user: ${accountEmail || "<NONE>"}
41
+ Active app: ${app_id || "<NONE>"}
42
+
43
+ ## User Instructions
44
+
45
+ ${prompt || "<the user didn't supply specific instructions>"}
46
+
47
+ ## Required information
48
+
49
+ Before fetching and prioritizing issues, secure the following information:
50
+
51
+ First, and this is INCREDIBLY IMPORTANT, verify the active user. IT IS SO IMPORTANT THAT YOU DO THIS FIRST. NO TOOL CALL WILL WORK WITHOUT IT. ${common_1.ACTIVE_USER_INSTRUCTION}
52
+ Then, verify the app id. ${APP_ID_INSTRUCTION}
53
+
54
+ Both pieces of information are required to successfully prioritize issues.
55
+
56
+ ## Steps
57
+
58
+ Follow the steps below taking note of any user instructions provided above.
59
+
60
+ 1. Use the 'crashlytics_list_top_issues' tool to fetch up to 20 issues.
61
+ 2. Use the 'crashlytics_list_top_versions' tool to fetch the top versions for this app.
62
+ 3. If the user instructions include statements about prioritization, use those instructions.
63
+ 4. If the user instructions do not include statements about prioritization, then prioritize the returned issues using the following criteria:
64
+ 4a. The app versions for the issue include the most recent version of the app.
65
+ 4b. The number of users experiencing the issue across variants
66
+ 4c. The volume of crashes
67
+ 5. Return the top ${issue_count || 5} issue ids, with a brief description of the issue in the following format:
68
+ * Issue <issue id>
69
+ * <the issue title>
70
+ * <the issue subtitle>
71
+ * Description: <a discription of the issue based on information from the tool response>
72
+ * Rationale: <the reason this issue was prioritized in the way it was>
73
+
74
+ The point of this command is to surface information only.
75
+ `.trim(),
76
+ },
77
+ },
78
+ ];
79
+ });
@@ -0,0 +1,9 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.dataconnectPrompts = void 0;
4
+ const experiments_1 = require("../../../experiments");
5
+ const schema_1 = require("./schema");
6
+ exports.dataconnectPrompts = [];
7
+ if ((0, experiments_1.isEnabled)("mcpalpha")) {
8
+ exports.dataconnectPrompts.push(schema_1.schema);
9
+ }
@@ -0,0 +1,68 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.schema = void 0;
4
+ const prompt_1 = require("../../prompt");
5
+ const load_1 = require("../../../dataconnect/load");
6
+ const content_1 = require("../../util/dataconnect/content");
7
+ const compile_1 = require("../../util/dataconnect/compile");
8
+ function renderServices(fdcServices) {
9
+ var _a;
10
+ if (!fdcServices.length)
11
+ return "Data Connect Status: <UNCONFIGURED>";
12
+ return `\n\n## Data Connect Schema
13
+
14
+ The following is the up-to-date content of existing schema files (their paths are relative to the Data Connect source directory).
15
+
16
+ ${(_a = fdcServices[0].schema.source.files) === null || _a === void 0 ? void 0 : _a.map((f) => `\`\`\`graphql ${f.path}\n${f.content}\n\`\`\``).join("\n\n")}`;
17
+ }
18
+ function renderErrors(errors) {
19
+ return `\n\n## Current Schema Build Errors\n\n${errors || "<NO ERRORS>"}`;
20
+ }
21
+ exports.schema = (0, prompt_1.prompt)({
22
+ name: "schema",
23
+ description: "Generate or update your Firebase Data Connect schema.",
24
+ arguments: [
25
+ {
26
+ name: "prompt",
27
+ description: "describe the schema you want generated or the edits you want to make to your existing schema",
28
+ required: true,
29
+ },
30
+ ],
31
+ annotations: {
32
+ title: "Generate Data Connect Schema",
33
+ },
34
+ }, async ({ prompt }, { config, projectId, accountEmail }) => {
35
+ const fdcServices = await (0, load_1.loadAll)(projectId, config);
36
+ const buildErrors = fdcServices.length
37
+ ? await (0, compile_1.compileErrors)(fdcServices[0].sourceDirectory)
38
+ : "";
39
+ return [
40
+ {
41
+ role: "user",
42
+ content: {
43
+ type: "text",
44
+ text: `
45
+ ${content_1.MAIN_INSTRUCTIONS}\n\n${content_1.BUILTIN_SDL}
46
+
47
+ ==== CURRENT ENVIRONMENT INFO ====
48
+
49
+ User Email: ${accountEmail || "<NONE>"}
50
+ Project ID: ${projectId || "<NONE>"}
51
+ ${renderServices(fdcServices)}${renderErrors(buildErrors)}
52
+
53
+ ==== USER PROMPT ====
54
+
55
+ ${prompt}
56
+
57
+ ==== TASK INSTRUCTIONS ====
58
+
59
+ 1. If Data Connect is marked as \`<UNCONFIGURED>\`, first run the \`firebase_init\` tool with \`{dataconnect: {}}\` arguments to initialize it.
60
+ 2. If there is not an existing schema to work with (or the existing schema is the commented-out default schema about a movie app), follow the user's prompt to generate a robust schema meeting the specified requirements.
61
+ 3. If there is already a schema, perform edits to the existing schema file(s) based on the user's instructions. If schema build errors are present and seem relevant to your changes, attempt to fix them.
62
+ 4. After you have performed edits on the schema, run the \`dataconnect_compile\` tool to build the schema and see if there are any errors. Fix errors that are related to the user's prompt or your changes.
63
+ 5. If there are errors, attempt to fix them. If you have attempted to fix them 3 times without success, ask the user for help.
64
+ 6. If there are no errors, write a brief paragraph summarizing your changes.`,
65
+ },
66
+ },
67
+ ];
68
+ });
@@ -2,15 +2,17 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.availablePrompts = void 0;
4
4
  const core_1 = require("./core");
5
+ const dataconnect_1 = require("./dataconnect");
6
+ const crashlytics_1 = require("./crashlytics");
5
7
  const prompts = {
6
8
  core: core_1.corePrompts,
7
9
  firestore: [],
8
10
  storage: [],
9
- dataconnect: [],
11
+ dataconnect: dataconnect_1.dataconnectPrompts,
10
12
  auth: [],
11
13
  messaging: [],
12
14
  remoteconfig: [],
13
- crashlytics: [],
15
+ crashlytics: crashlytics_1.crashlyticsPrompts,
14
16
  apphosting: [],
15
17
  database: [],
16
18
  };
@@ -24,7 +26,7 @@ function namespacePrompts(promptsToNamespace, feature) {
24
26
  newPrompt.mcp.name = `firebase:${p.mcp.name}`;
25
27
  }
26
28
  else {
27
- newPrompt.mcp.name = `firebase:${feature}:${p.mcp.name}`;
29
+ newPrompt.mcp.name = `${feature}:${p.mcp.name}`;
28
30
  }
29
31
  newPrompt.mcp._meta = Object.assign(Object.assign({}, p.mcp._meta), { feature });
30
32
  return newPrompt;
@@ -78,7 +78,8 @@ exports.init = (0, tool_1.tool)({
78
78
  .describe("The Postgres database ID to use in the Firebase Data Connect service."),
79
79
  })
80
80
  .optional()
81
- .describe("Provide this object to initialize Firebase Data Connect with Cloud SQL Postgres in this project directory."),
81
+ .describe("Provide this object to initialize Firebase Data Connect with Cloud SQL Postgres in this project directory.\n" +
82
+ "It installs Data Connect Generated SDKs in all detected apps in the folder."),
82
83
  storage: zod_1.z
83
84
  .object({
84
85
  rules_filename: zod_1.z
@@ -138,6 +139,9 @@ exports.init = (0, tool_1.tool)({
138
139
  cloudSqlInstanceId: features.dataconnect.cloudsql_instance_id || "",
139
140
  cloudSqlDatabase: features.dataconnect.cloudsql_database || "",
140
141
  };
142
+ featureInfo.dataconnectSdk = {
143
+ apps: [],
144
+ };
141
145
  }
142
146
  const setup = {
143
147
  config: config === null || config === void 0 ? void 0 : config.src,
@@ -145,10 +149,19 @@ exports.init = (0, tool_1.tool)({
145
149
  projectId: projectId,
146
150
  features: [...featuresList],
147
151
  featureInfo: featureInfo,
152
+ instructions: [],
148
153
  };
149
154
  await (0, index_1.actuate)(setup, config, { force: true });
150
155
  config.writeProjectFile("firebase.json", setup.config);
151
156
  config.writeProjectFile(".firebaserc", setup.rcfile);
152
- return (0, util_1.toContent)(`Successfully setup the project ${projectId} with those features: ${featuresList.join(", ")}` +
153
- " To deploy them, you can run `firebase deploy` in command line.");
157
+ if (featureInfo.dataconnectSdk && !featureInfo.dataconnectSdk.apps.length) {
158
+ setup.instructions.push(`No app is found in the current folder. We recommend you create an app (web, ios, android) first, then re-run the 'firebase_init' MCP tool to add Data Connect SDKs to your apps.
159
+ Consider popular commands like 'npx create-react-app my-app', 'npx create-next-app my-app', 'flutter create my-app', etc`);
160
+ }
161
+ return (0, util_1.toContent)(`Successfully setup those features: ${featuresList.join(", ")}
162
+
163
+ To get started:
164
+
165
+ - ${setup.instructions.join("\n\n- ")}
166
+ `);
154
167
  });
@@ -0,0 +1,32 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.add_note = void 0;
4
+ const zod_1 = require("zod");
5
+ const tool_1 = require("../../tool");
6
+ const util_1 = require("../../util");
7
+ const addNote_1 = require("../../../crashlytics/addNote");
8
+ const constants_1 = require("./constants");
9
+ exports.add_note = (0, tool_1.tool)({
10
+ name: "add_note",
11
+ description: "Add a note to an issue from crashlytics.",
12
+ inputSchema: zod_1.z.object({
13
+ app_id: constants_1.APP_ID_FIELD,
14
+ issue_id: zod_1.z.string().describe("The issue id to add the note to."),
15
+ note: zod_1.z.string().describe("The note to add to the issue."),
16
+ }),
17
+ annotations: {
18
+ title: "Add note to Crashlytics issue.",
19
+ readOnlyHint: true,
20
+ },
21
+ _meta: {
22
+ requiresAuth: true,
23
+ },
24
+ }, async ({ app_id, issue_id, note }) => {
25
+ if (!app_id)
26
+ return (0, util_1.mcpError)(`Must specify 'app_id' parameter.`);
27
+ if (!issue_id)
28
+ return (0, util_1.mcpError)(`Must specify 'issue_id' parameter.`);
29
+ if (!note)
30
+ return (0, util_1.mcpError)(`Must specify 'note' parameter.`);
31
+ return (0, util_1.toContent)(await (0, addNote_1.addNote)(app_id, issue_id, note));
32
+ });
@@ -0,0 +1,11 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.APP_ID_FIELD = void 0;
4
+ const zod_1 = require("zod");
5
+ exports.APP_ID_FIELD = zod_1.z
6
+ .string()
7
+ .describe("AppId for the application. For an Android application, read the " +
8
+ "mobilesdk_app_id value specified in the google-services.json file for " +
9
+ "the current package name. For an iOS Application, read the GOOGLE_APP_ID " +
10
+ "from GoogleService-Info.plist. If neither is available, ask the user to " +
11
+ "provide the app id.");
@@ -0,0 +1,35 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.delete_note = void 0;
4
+ const zod_1 = require("zod");
5
+ const tool_1 = require("../../tool");
6
+ const util_1 = require("../../util");
7
+ const deleteNote_1 = require("../../../crashlytics/deleteNote");
8
+ const constants_1 = require("./constants");
9
+ exports.delete_note = (0, tool_1.tool)({
10
+ name: "delete_note",
11
+ description: "Delete a note from an issue in Crashlytics.",
12
+ inputSchema: zod_1.z.object({
13
+ app_id: constants_1.APP_ID_FIELD,
14
+ issue_id: zod_1.z.string().describe("The issue id to delete the note from."),
15
+ note_id: zod_1.z.string().describe("The note id to delete."),
16
+ }),
17
+ annotations: {
18
+ title: "Delete Note from Crashlytics Issue.",
19
+ readOnlyHint: true,
20
+ },
21
+ _meta: {
22
+ requiresAuth: true,
23
+ },
24
+ }, async ({ app_id, issue_id, note_id }) => {
25
+ if (!app_id) {
26
+ return (0, util_1.mcpError)(`Must specify 'app_id' parameter.`);
27
+ }
28
+ if (!issue_id) {
29
+ return (0, util_1.mcpError)(`Must specify 'issue_id' parameter.`);
30
+ }
31
+ if (!note_id) {
32
+ return (0, util_1.mcpError)(`Must specify 'note_id' parameter.`);
33
+ }
34
+ return (0, util_1.toContent)(await (0, deleteNote_1.deleteNote)(app_id, issue_id, note_id));
35
+ });
@@ -5,13 +5,12 @@ const zod_1 = require("zod");
5
5
  const tool_1 = require("../../tool");
6
6
  const util_1 = require("../../util");
7
7
  const getIssueDetails_1 = require("../../../crashlytics/getIssueDetails");
8
+ const constants_1 = require("./constants");
8
9
  exports.get_issue_details = (0, tool_1.tool)({
9
10
  name: "get_issue_details",
10
11
  description: "Gets the details about a specific crashlytics issue.",
11
12
  inputSchema: zod_1.z.object({
12
- app_id: zod_1.z
13
- .string()
14
- .describe("The AppID for which the issues list should be fetched. For an Android application, read the mobilesdk_app_id value specified in the google-services.json file for the current package name. For an iOS Application, read the GOOGLE_APP_ID from GoogleService-Info.plist. If neither is available, use the `firebase_list_apps` tool to find an app_id to pass to this tool."),
13
+ app_id: constants_1.APP_ID_FIELD,
15
14
  issue_id: zod_1.z
16
15
  .string()
17
16
  .describe("The issue ID for which the details needs to be fetched. This is the value of the field `id` in the list of issues. Defaults to the first id in the list of issues."),
@@ -22,7 +21,6 @@ exports.get_issue_details = (0, tool_1.tool)({
22
21
  },
23
22
  _meta: {
24
23
  requiresAuth: true,
25
- requiresProject: false,
26
24
  },
27
25
  }, async ({ app_id, issue_id }) => {
28
26
  if (!app_id)
@@ -5,13 +5,12 @@ const zod_1 = require("zod");
5
5
  const tool_1 = require("../../tool");
6
6
  const util_1 = require("../../util");
7
7
  const getSampleCrash_1 = require("../../../crashlytics/getSampleCrash");
8
+ const constants_1 = require("./constants");
8
9
  exports.get_sample_crash = (0, tool_1.tool)({
9
10
  name: "get_sample_crash_for_issue",
10
11
  description: "Gets the sample crash for an issue.",
11
12
  inputSchema: zod_1.z.object({
12
- app_id: zod_1.z
13
- .string()
14
- .describe("AppId for which the issues list should be fetched. For an Android application, read the mobilesdk_app_id value specified in the google-services.json file for the current package name. For an iOS Application, read the GOOGLE_APP_ID from GoogleService-Info.plist. If neither is available, use the `firebase_list_apps` tool to find an app_id to pass to this tool."),
13
+ app_id: constants_1.APP_ID_FIELD,
15
14
  issue_id: zod_1.z
16
15
  .string()
17
16
  .describe("The issue Id for which the sample crash needs to be fetched. This is the value of the field `id` in the list of issues. Defaults to the first id in the list of issues."),
@@ -30,13 +29,14 @@ exports.get_sample_crash = (0, tool_1.tool)({
30
29
  },
31
30
  _meta: {
32
31
  requiresAuth: true,
33
- requiresProject: false,
34
32
  },
35
33
  }, async ({ app_id, issue_id, variant_id, sample_count }) => {
36
34
  if (!app_id)
37
35
  return (0, util_1.mcpError)(`Must specify 'app_id' parameter.`);
38
36
  if (!issue_id)
39
37
  return (0, util_1.mcpError)(`Must specify 'issue_id' parameter.`);
38
+ if (!sample_count)
39
+ sample_count = 1;
40
40
  if (sample_count > 3)
41
41
  sample_count = 3;
42
42
  return (0, util_1.toContent)(await (0, getSampleCrash_1.getSampleCrash)(app_id, issue_id, sample_count, variant_id));
@@ -1,11 +1,25 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.crashlyticsTools = void 0;
4
+ const add_note_1 = require("./add_note");
5
+ const delete_note_1 = require("./delete_note");
4
6
  const get_issue_details_1 = require("./get_issue_details");
5
- const list_top_issues_1 = require("./list_top_issues");
6
7
  const get_sample_crash_1 = require("./get_sample_crash");
8
+ const list_notes_1 = require("./list_notes");
9
+ const list_top_devices_1 = require("./list_top_devices");
10
+ const list_top_issues_1 = require("./list_top_issues");
11
+ const list_top_operating_systems_1 = require("./list_top_operating_systems");
12
+ const list_top_versions_1 = require("./list_top_versions");
13
+ const update_issue_1 = require("./update_issue");
7
14
  exports.crashlyticsTools = [
8
- list_top_issues_1.list_top_issues,
15
+ add_note_1.add_note,
16
+ delete_note_1.delete_note,
9
17
  get_issue_details_1.get_issue_details,
10
18
  get_sample_crash_1.get_sample_crash,
19
+ list_notes_1.list_notes,
20
+ list_top_devices_1.list_top_devices,
21
+ list_top_issues_1.list_top_issues,
22
+ list_top_operating_systems_1.list_top_operating_systems,
23
+ list_top_versions_1.list_top_versions,
24
+ update_issue_1.update_issue,
11
25
  ];
@@ -0,0 +1,37 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.list_notes = void 0;
4
+ const zod_1 = require("zod");
5
+ const tool_1 = require("../../tool");
6
+ const util_1 = require("../../util");
7
+ const listNotes_1 = require("../../../crashlytics/listNotes");
8
+ const constants_1 = require("./constants");
9
+ exports.list_notes = (0, tool_1.tool)({
10
+ name: "list_notes",
11
+ description: "List all notes for an issue in Crashlytics.",
12
+ inputSchema: zod_1.z.object({
13
+ app_id: constants_1.APP_ID_FIELD,
14
+ issue_id: zod_1.z.string().describe("The issue id to list notes for."),
15
+ note_count: zod_1.z
16
+ .number()
17
+ .optional()
18
+ .default(10)
19
+ .describe("Number of notes that needs to be fetched. Defaults to 10 if unspecified."),
20
+ }),
21
+ annotations: {
22
+ title: "List notes for a Crashlytics issue.",
23
+ readOnlyHint: true,
24
+ },
25
+ _meta: {
26
+ requiresAuth: true,
27
+ },
28
+ }, async ({ app_id, issue_id, note_count }) => {
29
+ if (!app_id) {
30
+ return (0, util_1.mcpError)(`Must specify 'app_id' parameter.`);
31
+ }
32
+ if (!issue_id) {
33
+ return (0, util_1.mcpError)(`Must specify 'issue_id' parameter.`);
34
+ }
35
+ note_count !== null && note_count !== void 0 ? note_count : (note_count = 10);
36
+ return (0, util_1.toContent)(await (0, listNotes_1.listNotes)(app_id, issue_id, note_count));
37
+ });
@@ -0,0 +1,33 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.list_top_devices = void 0;
4
+ const zod_1 = require("zod");
5
+ const tool_1 = require("../../tool");
6
+ const util_1 = require("../../util");
7
+ const listTopDevices_1 = require("../../../crashlytics/listTopDevices");
8
+ const constants_1 = require("./constants");
9
+ exports.list_top_devices = (0, tool_1.tool)({
10
+ name: "list_top_devices",
11
+ description: "List the top devices from Crashlytics for an application.",
12
+ inputSchema: zod_1.z.object({
13
+ app_id: constants_1.APP_ID_FIELD,
14
+ issue_id: zod_1.z.string().optional().describe("The issue id to filter on"),
15
+ device_count: zod_1.z
16
+ .number()
17
+ .optional()
18
+ .default(10)
19
+ .describe("Number of devices that needs to be fetched. Defaults to 10 if unspecified."),
20
+ }),
21
+ annotations: {
22
+ title: "List Top Crashlytics Devices.",
23
+ readOnlyHint: true,
24
+ },
25
+ _meta: {
26
+ requiresAuth: true,
27
+ },
28
+ }, async ({ app_id, issue_id, device_count }) => {
29
+ if (!app_id)
30
+ return (0, util_1.mcpError)(`Must specify 'app_id' parameter.`);
31
+ device_count !== null && device_count !== void 0 ? device_count : (device_count = 10);
32
+ return (0, util_1.toContent)(await (0, listTopDevices_1.listTopDevices)(app_id, device_count, issue_id));
33
+ });