@fml-inc/fml 0.3.0 → 0.5.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.
- package/.claude-plugin/plugin.json +1 -1
- package/bin/fml +17 -0
- package/bin/mcp-server +17 -0
- package/dist/{chunk-CUBBYHH7.js → chunk-5BHBYQ2F.js} +84 -30
- package/dist/chunk-5BHBYQ2F.js.map +1 -0
- package/dist/chunk-OI562MUP.js +217 -0
- package/dist/chunk-OI562MUP.js.map +1 -0
- package/dist/{chunk-MUKYS4IB.js → chunk-YH5ROR7G.js} +1 -25
- package/dist/chunk-YH5ROR7G.js.map +1 -0
- package/dist/{chunk-CFPXJT5Q.js → chunk-ZFUJ5ZQP.js} +17 -9
- package/dist/chunk-ZFUJ5ZQP.js.map +1 -0
- package/dist/cli.js +60 -42
- package/dist/cli.js.map +1 -1
- package/dist/daemon-J27JBWLV.js +17 -0
- package/dist/daemon-utils-OODBIYB7.js +10 -0
- package/dist/mcp/server.js +112 -13
- package/dist/mcp/server.js.map +1 -1
- package/dist/{token-store-HOFFHNNN.js → token-store-T2RNLXRM.js} +2 -3
- package/package.json +2 -9
- package/bin/sync-daemon +0 -3
- package/dist/chunk-4YEAQJPF.js +0 -47
- package/dist/chunk-4YEAQJPF.js.map +0 -1
- package/dist/chunk-BOREGHA6.js +0 -221
- package/dist/chunk-BOREGHA6.js.map +0 -1
- package/dist/chunk-CFPXJT5Q.js.map +0 -1
- package/dist/chunk-CUBBYHH7.js.map +0 -1
- package/dist/chunk-MUKYS4IB.js.map +0 -1
- package/dist/daemon-GM3WNS4Z.js +0 -16
- package/dist/daemon-utils-CJO4XVJQ.js +0 -17
- /package/dist/{daemon-GM3WNS4Z.js.map → daemon-J27JBWLV.js.map} +0 -0
- /package/dist/{daemon-utils-CJO4XVJQ.js.map → daemon-utils-OODBIYB7.js.map} +0 -0
- /package/dist/{token-store-HOFFHNNN.js.map → token-store-T2RNLXRM.js.map} +0 -0
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import {
|
|
2
|
+
handleStart,
|
|
3
|
+
handleStop,
|
|
4
|
+
handleSyncStart,
|
|
5
|
+
handleSyncStop,
|
|
6
|
+
parsePanopticonRunning
|
|
7
|
+
} from "./chunk-ZFUJ5ZQP.js";
|
|
8
|
+
import "./chunk-YH5ROR7G.js";
|
|
9
|
+
import "./chunk-PZ5AY32C.js";
|
|
10
|
+
export {
|
|
11
|
+
handleStart,
|
|
12
|
+
handleStop,
|
|
13
|
+
handleSyncStart,
|
|
14
|
+
handleSyncStop,
|
|
15
|
+
parsePanopticonRunning
|
|
16
|
+
};
|
|
17
|
+
//# sourceMappingURL=daemon-J27JBWLV.js.map
|
package/dist/mcp/server.js
CHANGED
|
@@ -1,25 +1,22 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
|
-
|
|
4
|
-
ensureNativeModules,
|
|
3
|
+
createFmlClient,
|
|
5
4
|
getAuthenticatedClient
|
|
6
|
-
} from "../chunk-
|
|
5
|
+
} from "../chunk-OI562MUP.js";
|
|
7
6
|
import {
|
|
7
|
+
FML_DATA_DIR,
|
|
8
|
+
FML_LOG_DIR,
|
|
8
9
|
Sentry,
|
|
9
10
|
authStorePath,
|
|
10
11
|
getSelectedOrg,
|
|
11
12
|
getValidToken,
|
|
12
13
|
initSentry,
|
|
13
14
|
readTokens
|
|
14
|
-
} from "../chunk-
|
|
15
|
+
} from "../chunk-5BHBYQ2F.js";
|
|
15
16
|
import {
|
|
16
17
|
parsePanopticonRunning
|
|
17
|
-
} from "../chunk-
|
|
18
|
-
import "../chunk-
|
|
19
|
-
import {
|
|
20
|
-
FML_DATA_DIR,
|
|
21
|
-
FML_LOG_DIR
|
|
22
|
-
} from "../chunk-4YEAQJPF.js";
|
|
18
|
+
} from "../chunk-ZFUJ5ZQP.js";
|
|
19
|
+
import "../chunk-YH5ROR7G.js";
|
|
23
20
|
import "../chunk-PZ5AY32C.js";
|
|
24
21
|
|
|
25
22
|
// src/mcp/server.ts
|
|
@@ -30,6 +27,7 @@ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"
|
|
|
30
27
|
|
|
31
28
|
// src/mcp/tools.ts
|
|
32
29
|
import { z } from "zod";
|
|
30
|
+
import { resolveRepoFromCwd } from "@fml-inc/panopticon/repo";
|
|
33
31
|
function textResult(data) {
|
|
34
32
|
return {
|
|
35
33
|
content: [{ type: "text", text: JSON.stringify(data, null, 2) }]
|
|
@@ -72,7 +70,7 @@ function registerTools(server2) {
|
|
|
72
70
|
let orgs = null;
|
|
73
71
|
if (token) {
|
|
74
72
|
try {
|
|
75
|
-
orgs = await
|
|
73
|
+
orgs = await createFmlClient(token).queryOrgs();
|
|
76
74
|
} catch {
|
|
77
75
|
}
|
|
78
76
|
}
|
|
@@ -451,10 +449,111 @@ function registerTools(server2) {
|
|
|
451
449
|
}
|
|
452
450
|
}
|
|
453
451
|
);
|
|
452
|
+
const resolveRepoArg = (repo) => {
|
|
453
|
+
if (repo) return repo;
|
|
454
|
+
try {
|
|
455
|
+
return resolveRepoFromCwd(process.cwd())?.repo ?? null;
|
|
456
|
+
} catch {
|
|
457
|
+
return null;
|
|
458
|
+
}
|
|
459
|
+
};
|
|
460
|
+
const anamnesisResult = (result) => result.ok ? textResult(result.result) : errorResult(result.error ?? "Unknown error");
|
|
461
|
+
server2.tool(
|
|
462
|
+
"fml_path_history",
|
|
463
|
+
"Ground-truth history for a file path: PRs that touched it and review comments on it (newest first). USE FOR: understanding why a file looks the way it does, who changed it, related PRs.",
|
|
464
|
+
{
|
|
465
|
+
path: z.string().describe("Repo-relative file path, e.g. 'src/app.ts'."),
|
|
466
|
+
repo: z.string().optional().describe("owner/repo. Defaults to the current working repo."),
|
|
467
|
+
limit: z.number().optional().describe("Max items per list (default 25).")
|
|
468
|
+
},
|
|
469
|
+
async (args) => {
|
|
470
|
+
const repo = resolveRepoArg(args.repo);
|
|
471
|
+
if (!repo)
|
|
472
|
+
return errorResult(
|
|
473
|
+
"Could not determine repo \u2014 pass `repo` (owner/repo)."
|
|
474
|
+
);
|
|
475
|
+
const api = await getAuthenticatedClient();
|
|
476
|
+
if (!api) return errorResult("Not authenticated. Run `fml login`.");
|
|
477
|
+
return anamnesisResult(
|
|
478
|
+
await api.anamnesisContext("path", {
|
|
479
|
+
repo,
|
|
480
|
+
path: args.path,
|
|
481
|
+
limit: args.limit
|
|
482
|
+
})
|
|
483
|
+
);
|
|
484
|
+
}
|
|
485
|
+
);
|
|
486
|
+
server2.tool(
|
|
487
|
+
"fml_commit_context",
|
|
488
|
+
"Ground-truth context for a commit sha: the PR(s) that contain or merged it, and any revert relationships. Accepts abbreviated shas.",
|
|
489
|
+
{
|
|
490
|
+
sha: z.string().describe("Commit sha (full or abbreviated)."),
|
|
491
|
+
repo: z.string().optional().describe("owner/repo. Defaults to the current working repo.")
|
|
492
|
+
},
|
|
493
|
+
async (args) => {
|
|
494
|
+
const repo = resolveRepoArg(args.repo);
|
|
495
|
+
if (!repo)
|
|
496
|
+
return errorResult(
|
|
497
|
+
"Could not determine repo \u2014 pass `repo` (owner/repo)."
|
|
498
|
+
);
|
|
499
|
+
const api = await getAuthenticatedClient();
|
|
500
|
+
if (!api) return errorResult("Not authenticated. Run `fml login`.");
|
|
501
|
+
return anamnesisResult(
|
|
502
|
+
await api.anamnesisContext("commit", { repo, sha: args.sha })
|
|
503
|
+
);
|
|
504
|
+
}
|
|
505
|
+
);
|
|
506
|
+
server2.tool(
|
|
507
|
+
"fml_pr_context",
|
|
508
|
+
"Full ground-truth view of a pull request: metadata, commits, changed files, review comments, and derived facts.",
|
|
509
|
+
{
|
|
510
|
+
number: z.number().describe("PR number."),
|
|
511
|
+
repo: z.string().optional().describe("owner/repo. Defaults to the current working repo."),
|
|
512
|
+
limit: z.number().optional().describe("Max items per list (default 25).")
|
|
513
|
+
},
|
|
514
|
+
async (args) => {
|
|
515
|
+
const repo = resolveRepoArg(args.repo);
|
|
516
|
+
if (!repo)
|
|
517
|
+
return errorResult(
|
|
518
|
+
"Could not determine repo \u2014 pass `repo` (owner/repo)."
|
|
519
|
+
);
|
|
520
|
+
const api = await getAuthenticatedClient();
|
|
521
|
+
if (!api) return errorResult("Not authenticated. Run `fml login`.");
|
|
522
|
+
return anamnesisResult(
|
|
523
|
+
await api.anamnesisContext("pr", {
|
|
524
|
+
repo,
|
|
525
|
+
number: args.number,
|
|
526
|
+
limit: args.limit
|
|
527
|
+
})
|
|
528
|
+
);
|
|
529
|
+
}
|
|
530
|
+
);
|
|
531
|
+
server2.tool(
|
|
532
|
+
"fml_anamnesis_query",
|
|
533
|
+
"Generic query over the anamnesis fact corpus. Filter by predicate (pr_touches_path, pr_contains_commit, pr_merged_as_commit, review_comment_on_path, commit_reverts_commit, pr_reverts_pr) and/or subject/object.",
|
|
534
|
+
{
|
|
535
|
+
predicate: z.string().optional().describe("Fact predicate to filter by."),
|
|
536
|
+
subjectKind: z.string().optional(),
|
|
537
|
+
subjectValue: z.string().optional(),
|
|
538
|
+
objectKind: z.string().optional(),
|
|
539
|
+
objectValue: z.string().optional(),
|
|
540
|
+
repo: z.string().optional().describe("owner/repo. Defaults to the current working repo."),
|
|
541
|
+
limit: z.number().optional().describe("Max facts (default 25).")
|
|
542
|
+
},
|
|
543
|
+
async (args) => {
|
|
544
|
+
const repo = resolveRepoArg(args.repo);
|
|
545
|
+
if (!repo)
|
|
546
|
+
return errorResult(
|
|
547
|
+
"Could not determine repo \u2014 pass `repo` (owner/repo)."
|
|
548
|
+
);
|
|
549
|
+
const api = await getAuthenticatedClient();
|
|
550
|
+
if (!api) return errorResult("Not authenticated. Run `fml login`.");
|
|
551
|
+
return anamnesisResult(await api.anamnesisQuery({ ...args, repo }));
|
|
552
|
+
}
|
|
553
|
+
);
|
|
454
554
|
}
|
|
455
555
|
|
|
456
556
|
// src/mcp/server.ts
|
|
457
|
-
ensureNativeModules();
|
|
458
557
|
var LOG_PATH = path.join(FML_LOG_DIR, "mcp.log");
|
|
459
558
|
var server = new McpServer({
|
|
460
559
|
name: "fml",
|
|
@@ -499,7 +598,7 @@ async function main() {
|
|
|
499
598
|
await server.connect(transport);
|
|
500
599
|
if (!parsePanopticonRunning()) {
|
|
501
600
|
try {
|
|
502
|
-
const { handleStart } = await import("../daemon-
|
|
601
|
+
const { handleStart } = await import("../daemon-J27JBWLV.js");
|
|
503
602
|
await handleStart();
|
|
504
603
|
} catch {
|
|
505
604
|
console.error(
|
package/dist/mcp/server.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/mcp/server.ts","../../src/mcp/tools.ts"],"sourcesContent":["#!/usr/bin/env node\n\nimport { ensureNativeModules } from \"../native-check.js\";\nensureNativeModules();\n\nimport fs from \"node:fs\";\nimport path from \"node:path\";\nimport { McpServer } from \"@modelcontextprotocol/sdk/server/mcp.js\";\nimport { StdioServerTransport } from \"@modelcontextprotocol/sdk/server/stdio.js\";\nimport { registerTools } from \"./tools.js\";\nimport { getValidToken, readTokens } from \"../auth/token-store.js\";\nimport { authStorePath } from \"../config.js\";\nimport { initSentry, Sentry } from \"../sentry.js\";\nimport { parsePanopticonRunning } from \"../commands/daemon.js\";\nimport { FML_DATA_DIR, FML_LOG_DIR } from \"../dirs.js\";\n\nconst LOG_PATH = path.join(FML_LOG_DIR, \"mcp.log\");\n\nconst server = new McpServer({\n name: \"fml\",\n version: \"0.1.0\",\n});\n\nregisterTools(server);\n\nasync function main() {\n await initSentry();\n\n // Redirect stderr to log file (stdout is reserved for MCP JSON-RPC protocol)\n if (!fs.existsSync(FML_LOG_DIR)) {\n fs.mkdirSync(FML_LOG_DIR, { recursive: true });\n }\n const logFd = fs.openSync(LOG_PATH, \"a\");\n const logStream = fs.createWriteStream(\"\", { fd: logFd });\n process.stderr.write = logStream.write.bind(\n logStream,\n ) as typeof process.stderr.write;\n\n // Check auth state and surface setup prompts\n const tokens = readTokens();\n const tokenValid = tokens ? await getValidToken() : null;\n\n if (!tokens) {\n const storePath = authStorePath();\n try {\n const files = fs.readdirSync(FML_DATA_DIR).join(\", \") || \"(empty)\";\n console.error(\n `[fml] No auth file at ${storePath}. Dir contents: ${files}`,\n );\n } catch {\n console.error(`[fml] No auth file at ${storePath}. Dir not readable.`);\n }\n server.resource(\"setup\", \"fml://setup\", async () => ({\n contents: [\n {\n uri: \"fml://setup\",\n text: \"FML plugin is not authenticated. Run `fml login` in your terminal to sign in, then restart Claude Code.\",\n },\n ],\n }));\n console.error(\"[fml] Not authenticated — run `fml login`\");\n } else if (!tokenValid) {\n console.error(\"[fml] Token expired — run `fml login` to re-authenticate\");\n }\n\n const transport = new StdioServerTransport();\n await server.connect(transport);\n\n // Ensure panopticon is running (includes sync, which handles config snapshots)\n if (!parsePanopticonRunning()) {\n try {\n const { handleStart } = await import(\"../commands/daemon.js\");\n await handleStart();\n } catch {\n console.error(\n \"[fml] Warning: could not start panopticon. Run `fml start` manually\",\n );\n }\n }\n}\n\nmain().catch((err) => {\n Sentry.captureException(err);\n console.error(\"FML MCP server error:\", err);\n process.exit(1);\n});\n","import type { McpServer } from \"@modelcontextprotocol/sdk/server/mcp.js\";\nimport { z } from \"zod\";\nimport {\n getSelectedOrg,\n getValidToken,\n readTokens,\n} from \"../auth/token-store.js\";\nimport { createApiClient, getAuthenticatedClient } from \"../convex-client.js\";\nimport { Sentry } from \"../sentry.js\";\n\n// ─── Helpers ──────────────────────────────────────────────────────────────────\n\nfunction textResult(data: unknown) {\n return {\n content: [{ type: \"text\" as const, text: JSON.stringify(data, null, 2) }],\n };\n}\n\nfunction errorResult(message: string) {\n return {\n content: [{ type: \"text\" as const, text: message }],\n isError: true,\n };\n}\n\nconst PANOPTICON_HINT =\n \"\\n\\nFor local data, use the panopticon MCP tools instead (e.g. panopticon__sessions, panopticon__costs, panopticon__search, panopticon__timeline).\";\n\nasync function toolHandler(toolName: string, args: Record<string, unknown>) {\n try {\n const api = await getAuthenticatedClient();\n if (!api) {\n return errorResult(\n \"Not authenticated. Run `fml login` to sign in, then restart Claude Code.\" +\n PANOPTICON_HINT,\n );\n }\n const result = await api.callBackend(toolName, args);\n if (!result.ok) {\n return errorResult((result.error ?? \"Unknown error\") + PANOPTICON_HINT);\n }\n return textResult(result.result);\n } catch (err) {\n Sentry.captureException(err);\n const msg = err instanceof Error ? err.message : String(err);\n return errorResult(`Unexpected error: ${msg}` + PANOPTICON_HINT);\n }\n}\n\n// ─── Registration ─────────────────────────────────────────────────────────────\n\nexport function registerTools(server: McpServer): void {\n server.tool(\n \"whoami\",\n \"Show current authenticated user and available organizations\",\n {},\n async () => {\n const tokens = readTokens();\n const token = tokens ? await getValidToken() : null;\n let orgs = null;\n if (token) {\n try {\n orgs = await createApiClient(token).queryOrgs();\n } catch {}\n }\n return textResult({\n authenticated: !!tokens,\n user: tokens?.user ?? null,\n orgs,\n });\n },\n );\n\n // ── Messages ───────────────────────────────────────────────────────────────\n\n server.tool(\n \"fml_list_messages\",\n \"List messages from a conversation within a time range. Requires a conversationId from the FML web app.\",\n {\n startTime: z\n .number()\n .optional()\n .describe(\n \"Start time in milliseconds (inclusive). Omit to start from beginning.\",\n ),\n endTime: z\n .number()\n .optional()\n .describe(\n \"End time in milliseconds (inclusive). Omit to include up to most recent.\",\n ),\n limit: z\n .number()\n .optional()\n .describe(\n \"Maximum number of messages to return per page (default: 20)\",\n ),\n cursor: z\n .string()\n .optional()\n .describe(\"Pagination cursor from previous result to get next page\"),\n },\n async (args) => toolHandler(\"list-messages\", args),\n );\n\n server.tool(\n \"fml_list_messages_with_context\",\n \"Get messages around a specific message to see the context. Takes a message ID and returns messages before and after it.\",\n {\n messageId: z\n .string()\n .describe(\"The ID of the target message to get context around\"),\n before: z\n .number()\n .optional()\n .describe(\n \"Number of messages to retrieve before the target (default: 5)\",\n ),\n after: z\n .number()\n .optional()\n .describe(\n \"Number of messages to retrieve after the target (default: 5)\",\n ),\n },\n async (args) => toolHandler(\"list-messages-with-context\", args),\n );\n\n // ── Slack ──────────────────────────────────────────────────────────────────\n\n server.tool(\n \"fml_get_slack_channel_history\",\n \"Fetch recent message history from a Slack channel. Requires Slack integration to be connected.\",\n {\n channelId: z\n .string()\n .optional()\n .describe(\n \"Slack channel ID (e.g. C0123ABC). If omitted, uses the channel from the current Slack-sourced conversation.\",\n ),\n limit: z\n .number()\n .optional()\n .describe(\"Number of messages to fetch (default 20, max 50)\"),\n },\n async (args) => toolHandler(\"get-slack-channel-history\", args),\n );\n\n server.tool(\n \"fml_get_slack_message\",\n \"Fetch a specific Slack message by timestamp or permalink. Requires Slack integration to be connected.\",\n {\n permalink: z\n .string()\n .optional()\n .describe(\n \"Slack message permalink. If provided, channelId and messageTs are ignored.\",\n ),\n channelId: z\n .string()\n .optional()\n .describe(\n \"Slack channel ID (e.g. C0123ABC). Required if permalink not provided.\",\n ),\n messageTs: z\n .string()\n .optional()\n .describe(\n \"Message timestamp (e.g. 1234567890.123456). Required if permalink not provided.\",\n ),\n includeThreadContext: z\n .boolean()\n .optional()\n .describe(\n \"If true, fetches thread replies along with the message (default false)\",\n ),\n },\n async (args) => toolHandler(\"get-slack-message\", args),\n );\n\n // ── Skills ─────────────────────────────────────────────────────────────────\n\n server.tool(\n \"fml_list_skills\",\n \"List all available FML skills. Skills provide detailed knowledge about FML features.\",\n {},\n async () => toolHandler(\"list-skills\", {}),\n );\n\n server.tool(\n \"fml_load_skill\",\n \"Load a skill prompt by ID. Skills provide detailed knowledge about FML features.\",\n {\n skillId: z\n .string()\n .describe(\"The skill ID to load (e.g., 'fml-help', 'fml-navigation')\"),\n },\n async (args) => toolHandler(\"load-skill\", args),\n );\n\n // ── Analysis ───────────────────────────────────────────────────────────────\n\n server.tool(\n \"fml_search_analysis\",\n \"Search analysis results produced by `fml_run_analysis_workflow`. USE FOR: finding analyses by topic, type, or status across a repo (or all repos in the org). FILTERS: query (text search), promptKey (exact type like 'deep_security_auditor'), status (complete, running, failed). Pass `repositoryId` to limit the search, or omit to fan out across every repo in the org.\",\n {\n query: z\n .string()\n .optional()\n .describe(\"Text search across analysis type and content\"),\n promptKey: z\n .string()\n .optional()\n .describe(\n \"Exact filter by analysis type (e.g., 'deep_security_auditor')\",\n ),\n status: z\n .enum([\"complete\", \"running\", \"created\", \"failed\"])\n .optional()\n .describe(\"Filter by status\"),\n limit: z\n .number()\n .optional()\n .describe(\n \"Maximum number of results to return total across all matched repos (default 20)\",\n ),\n repositoryId: z\n .string()\n .optional()\n .describe(\n \"Limit to one repository. Omit to search every repo in the caller's organization.\",\n ),\n },\n async (args) => toolHandler(\"search-analysis\", args),\n );\n\n server.tool(\n \"fml_run_analysis_workflow\",\n \"Run comprehensive codebase analysis workflows on a repository. Available prompts: deep_security_auditor, deep_architecture_auditor, deep_code_quality_auditor, deep_performance_auditor, deep_ux_auditor, deep_dependencies_auditor, deep_cost_auditor, deep_ai_architecture_integration, deep_ai_security. The backend auto-picks the repo for single-repo orgs; pass `repositoryId` explicitly when the org has multiple repos (the tool will otherwise return a clarifying error listing them).\",\n {\n selectedPromptKeys: z\n .array(\n z.enum([\n \"deep_security_auditor\",\n \"deep_architecture_auditor\",\n \"deep_code_quality_auditor\",\n \"deep_performance_auditor\",\n \"deep_ux_auditor\",\n \"deep_dependencies_auditor\",\n \"deep_cost_auditor\",\n \"deep_ai_architecture_integration\",\n \"deep_ai_security\",\n ]),\n )\n .optional()\n .describe(\n \"Array of specific analysis prompts to run. If not provided, runs default set.\",\n ),\n repositoryId: z\n .string()\n .optional()\n .describe(\n \"Target repository ID. Omit for single-repo orgs (auto-pick). Required when the org has multiple repos — the tool will list them in its error if not provided.\",\n ),\n },\n async (args) => toolHandler(\"run-analysis-workflow\", args),\n );\n\n server.tool(\n \"fml_run_team_analysis\",\n \"Run a team-wide AI coding practice analysis for the caller's organization. Produces a structured report with per-person narratives covering tool usage, collaboration patterns, configuration, and notable changes. Use for prompts like 'run team analysis for the last 14 days' or 'how is the team doing?'. Kicks a durable Convex workflow and returns immediately with a reportId; when called inside a conversation, a completion message is posted back to that conversation when the workflow finishes — wait for that follow-up turn, do not poll. Idempotent: if a run is already in flight, returns the existing reportId with started=false. Requires org-owner access and at least one running dev environment.\",\n {\n windowDays: z\n .number()\n .int()\n .min(1)\n .max(90)\n .optional()\n .describe(\n \"Size of the analysis window in days. Defaults to 30. Clamped to [1, 90]. Match the user's phrasing: 'last 14 days' → 14, 'last month' → 30, 'this week' → 7.\",\n ),\n },\n async (args) => toolHandler(\"run-team-analysis\", args),\n );\n\n // ── Integrations ───────────────────────────────────────────────────────────\n\n server.tool(\n \"fml_list_integrations\",\n \"List integrations for this project — both connected and available. Use to check what integrations are active.\",\n {},\n async () => toolHandler(\"list-integrations\", {}),\n );\n\n // Integration query tools\n const integrationTools: Array<{\n name: string;\n mastraId: string;\n description: string;\n endpointHelp: string;\n }> = [\n {\n name: \"fml_query_sentry\",\n mastraId: \"integration-sentry\",\n description:\n \"Look up production errors, exceptions, and crash data from Sentry. Common endpoints: 'organizations/{orgSlug}/issues/' (GET), 'issues/{issue_id}/' (GET). {orgSlug} is auto-substituted.\",\n endpointHelp:\n \"Sentry REST API endpoint. {orgSlug} is auto-substituted. e.g. 'organizations/{orgSlug}/issues/'\",\n },\n {\n name: \"fml_query_slack\",\n mastraId: \"integration-slack\",\n description:\n \"Send messages and read channel/user info from Slack. Use channel IDs not names. Common endpoints: 'conversations.list' (GET), 'chat.postMessage' (POST).\",\n endpointHelp:\n \"Slack API method, e.g. 'conversations.list', 'chat.postMessage'\",\n },\n {\n name: \"fml_query_github\",\n mastraId: \"integration-github\",\n description:\n \"Query repository activity from GitHub — PRs, commits, issues, code. {owner} and {repo} are auto-substituted. Common endpoints: 'repos/{owner}/{repo}/pulls' (GET).\",\n endpointHelp: \"GitHub REST API path. e.g. 'repos/{owner}/{repo}/pulls'\",\n },\n {\n name: \"fml_query_linear\",\n mastraId: \"integration-linear\",\n description:\n \"Query and manage Linear issues and projects via GraphQL. Endpoint is always 'graphql', method POST.\",\n endpointHelp:\n \"Linear GraphQL endpoint — always use 'graphql' with method POST and {query, variables} in body\",\n },\n {\n name: \"fml_query_notion\",\n mastraId: \"integration-notion\",\n description:\n \"Search pages, query databases, read and write content in Notion. Common endpoints: 'search' (POST), 'databases/{id}/query' (POST).\",\n endpointHelp:\n \"Notion REST API endpoint, e.g. 'search', 'databases/{database_id}/query'\",\n },\n {\n name: \"fml_query_freshdesk\",\n mastraId: \"integration-freshdesk\",\n description:\n \"Query and manage customer support tickets in Freshdesk. Common endpoints: 'tickets' (GET), 'tickets/{id}' (GET).\",\n endpointHelp:\n \"Freshdesk REST API v2 endpoint, e.g. 'tickets', 'tickets/{id}'\",\n },\n {\n name: \"fml_query_stripe\",\n mastraId: \"integration-stripe\",\n description:\n \"Query Stripe API for customers, subscriptions, charges, invoices, and revenue. Common endpoints: 'customers' (GET), 'subscriptions?status=active' (GET), 'charges' (GET), 'invoices' (GET), 'balance' (GET).\",\n endpointHelp:\n \"Stripe REST API v1 endpoint, e.g. 'customers', 'subscriptions?status=active', 'charges', 'balance'\",\n },\n ];\n\n for (const tool of integrationTools) {\n server.tool(\n tool.name,\n tool.description,\n {\n endpoint: z.string().describe(tool.endpointHelp),\n method: z\n .enum([\"GET\", \"POST\", \"PUT\", \"PATCH\", \"DELETE\"])\n .optional()\n .describe(\"HTTP method. Defaults to GET.\"),\n body: z\n .record(z.string(), z.unknown())\n .optional()\n .describe(\"Request body as a JSON object (for POST/PUT/PATCH)\"),\n projectId: z\n .string()\n .optional()\n .describe(\n \"Optional project ID to scope this query. Required for GitHub (needs repo context).\",\n ),\n },\n async (args) => toolHandler(tool.mastraId, args),\n );\n }\n\n // ── Engineering Activity ───────────────────────────────────────────────────\n\n server.tool(\n \"get_engineering_activity\",\n \"Get agent activity summary (Claude Code, Codex, Gemini CLI, Mastra). SCOPES: 'org' (default), 'project', or 'user' (by githubUsername).\",\n {\n timeRange: z\n .enum([\"1h\", \"6h\", \"24h\", \"7d\", \"30d\"])\n .optional()\n .describe(\"Preset time range. Default '7d'.\"),\n since: z\n .string()\n .optional()\n .describe(\"ISO 8601 start timestamp. Overrides timeRange.\"),\n until: z.string().optional().describe(\"ISO 8601 end timestamp.\"),\n target: z\n .enum([\"claude\", \"codex\", \"gemini\", \"mastra\"])\n .optional()\n .describe(\"Filter by agent type. Omit for all.\"),\n scope: z\n .enum([\"org\", \"project\", \"user\"])\n .optional()\n .describe(\"Query scope. 'org' (default), 'project', or 'user'.\"),\n githubUsername: z\n .string()\n .optional()\n .describe(\"Required when scope is 'user'. GitHub username.\"),\n },\n async (args) => toolHandler(\"get-engineering-activity\", args),\n );\n\n server.tool(\n \"list_engineering_sessions\",\n \"List agent sessions (Claude Code, Codex, Gemini CLI, Mastra). Each session includes first prompt preview and event counts.\",\n {\n scope: z\n .enum([\"org\", \"project\"])\n .optional()\n .describe(\"Query scope. Default 'org'.\"),\n target: z\n .enum([\"claude\", \"codex\", \"gemini\", \"mastra\"])\n .optional()\n .describe(\"Filter by agent type. Omit for all.\"),\n githubUsername: z\n .string()\n .optional()\n .describe(\"Filter to sessions by this GitHub username.\"),\n timeRange: z.enum([\"1h\", \"6h\", \"24h\", \"7d\", \"30d\"]).optional(),\n since: z.string().optional().describe(\"ISO 8601 start timestamp.\"),\n until: z.string().optional().describe(\"ISO 8601 end timestamp.\"),\n limit: z\n .number()\n .optional()\n .describe(\"Max sessions to return (default 20, max 50).\"),\n },\n async (args) => toolHandler(\"list-engineering-sessions\", args),\n );\n\n server.tool(\n \"get_session_timeline\",\n 'Get chronological timeline for a coding agent session. Returns messages and/or hook events interleaved by timestamp. Use source=\"hooks\" to see permission requests, tool approvals, etc. REQUIRES: sessionId from list_engineering_sessions.',\n {\n sessionId: z.string().describe(\"The session ID to get details for.\"),\n includeSystemMessages: z\n .boolean()\n .optional()\n .describe(\"Include system messages (default false).\"),\n source: z\n .enum([\"messages\", \"hooks\", \"all\"])\n .optional()\n .describe(\n 'Filter by source: \"messages\" (scanner messages only), \"hooks\" (hook events only), \"all\" (both interleaved). Default \"all\".',\n ),\n eventType: z\n .string()\n .optional()\n .describe(\n 'Filter hook events by type (e.g. \"PermissionRequest\", \"PreToolUse\", \"Stop\"). Only applies when source includes hooks.',\n ),\n limit: z\n .number()\n .optional()\n .describe(\"Max entries to return (default 50, max 200).\"),\n offset: z\n .number()\n .optional()\n .describe(\"Skip first N entries for pagination.\"),\n },\n async (args) => toolHandler(\"get-session-timeline\", args),\n );\n\n server.tool(\n \"get_session_turns\",\n \"Get per-turn token accounting for a coding agent session. USE FOR: understanding cost per turn, model used at each step, cache hit analysis. REQUIRES: sessionId from list_engineering_sessions.\",\n {\n sessionId: z.string().describe(\"The session ID to get turns for.\"),\n limit: z\n .number()\n .optional()\n .describe(\"Max turns to return (default 50, max 200).\"),\n offset: z\n .number()\n .optional()\n .describe(\"Skip first N turns for pagination.\"),\n },\n async (args) => toolHandler(\"get-session-turns\", args),\n );\n\n server.tool(\n \"get_ai_spending\",\n \"Get AI spending and token usage data. Groups by 'session' (default), 'model', or 'day'.\",\n {\n timeRange: z\n .enum([\"1h\", \"6h\", \"24h\", \"7d\", \"30d\"])\n .optional()\n .describe(\"Default '7d'.\"),\n since: z.string().optional().describe(\"ISO 8601 start timestamp.\"),\n until: z.string().optional().describe(\"ISO 8601 end timestamp.\"),\n groupBy: z\n .enum([\"session\", \"model\", \"day\"])\n .optional()\n .describe(\"How to group results.\"),\n target: z\n .enum([\"claude\", \"codex\", \"gemini\", \"mastra\"])\n .optional()\n .describe(\"Filter by agent type. Omit for all.\"),\n },\n async (args) => toolHandler(\"get-ai-spending\", args),\n );\n\n server.tool(\n \"search_engineering_sessions\",\n \"Search across agent sessions by text. Searches prompts, tool names, and event payloads.\",\n {\n query: z.string().describe(\"Text to search for. Case-insensitive.\"),\n timeRange: z.enum([\"1h\", \"6h\", \"24h\", \"7d\", \"30d\"]).optional(),\n since: z.string().optional(),\n until: z.string().optional(),\n target: z\n .enum([\"claude\", \"codex\", \"gemini\", \"mastra\"])\n .optional()\n .describe(\"Filter by agent type. Omit for all.\"),\n limit: z.number().optional().describe(\"Max results (default 20).\"),\n },\n async (args) => toolHandler(\"search-engineering-sessions\", args),\n );\n\n // ── Config Snapshots ────────────────────────────────────────────────────\n\n server.tool(\n \"list_user_configs\",\n \"List user-level configuration snapshots (CLAUDE.md, settings, etc.) across the org. Shows who has configs and when they were last updated.\",\n {},\n async () => {\n try {\n const orgSlug = getSelectedOrg();\n if (!orgSlug) return errorResult(\"No org selected. Run `fml login`.\");\n const api = await getAuthenticatedClient();\n if (!api) return errorResult(\"Not authenticated. Run `fml login`.\");\n const result = await api.listUserConfigSnapshots(orgSlug);\n return textResult(result);\n } catch (err) {\n Sentry.captureException(err);\n return errorResult(\n `Error: ${err instanceof Error ? err.message : String(err)}`,\n );\n }\n },\n );\n\n server.tool(\n \"get_user_config\",\n \"Get detailed user configuration for a specific GitHub user — their CLAUDE.md, settings.json, MCP servers, etc.\",\n {\n githubUsername: z.string().describe(\"GitHub username to look up.\"),\n },\n async (args) => {\n try {\n const orgSlug = getSelectedOrg();\n if (!orgSlug) return errorResult(\"No org selected. Run `fml login`.\");\n const api = await getAuthenticatedClient();\n if (!api) return errorResult(\"Not authenticated. Run `fml login`.\");\n const result = await api.getUserConfigDetail(\n orgSlug,\n args.githubUsername,\n );\n if (!result)\n return errorResult(`No config found for ${args.githubUsername}.`);\n return textResult(result);\n } catch (err) {\n Sentry.captureException(err);\n return errorResult(\n `Error: ${err instanceof Error ? err.message : String(err)}`,\n );\n }\n },\n );\n\n server.tool(\n \"list_repo_configs\",\n \"List repository-level configuration snapshots (CLAUDE.md, .mcp.json, etc.) across the org. Optionally filter by repository.\",\n {\n repository: z\n .string()\n .optional()\n .describe(\"Filter by repository full name (e.g. 'org/repo').\"),\n },\n async (args) => {\n try {\n const orgSlug = getSelectedOrg();\n if (!orgSlug) return errorResult(\"No org selected. Run `fml login`.\");\n const api = await getAuthenticatedClient();\n if (!api) return errorResult(\"Not authenticated. Run `fml login`.\");\n const result = await api.listRepoConfigSnapshots(\n orgSlug,\n args.repository,\n );\n return textResult(result);\n } catch (err) {\n Sentry.captureException(err);\n return errorResult(\n `Error: ${err instanceof Error ? err.message : String(err)}`,\n );\n }\n },\n );\n\n server.tool(\n \"get_repo_config\",\n \"Get detailed repository configuration — CLAUDE.md files, .mcp.json, and other agent config found in a specific repo.\",\n {\n repository: z\n .string()\n .describe(\"Repository full name (e.g. 'org/repo').\"),\n },\n async (args) => {\n try {\n const orgSlug = getSelectedOrg();\n if (!orgSlug) return errorResult(\"No org selected. Run `fml login`.\");\n const api = await getAuthenticatedClient();\n if (!api) return errorResult(\"Not authenticated. Run `fml login`.\");\n const result = await api.getRepoConfigDetail(orgSlug, args.repository);\n if (!result)\n return errorResult(`No config found for ${args.repository}.`);\n return textResult(result);\n } catch (err) {\n Sentry.captureException(err);\n return errorResult(\n `Error: ${err instanceof Error ? err.message : String(err)}`,\n );\n }\n },\n );\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;AAKA,OAAO,QAAQ;AACf,OAAO,UAAU;AACjB,SAAS,iBAAiB;AAC1B,SAAS,4BAA4B;;;ACPrC,SAAS,SAAS;AAWlB,SAAS,WAAW,MAAe;AACjC,SAAO;AAAA,IACL,SAAS,CAAC,EAAE,MAAM,QAAiB,MAAM,KAAK,UAAU,MAAM,MAAM,CAAC,EAAE,CAAC;AAAA,EAC1E;AACF;AAEA,SAAS,YAAY,SAAiB;AACpC,SAAO;AAAA,IACL,SAAS,CAAC,EAAE,MAAM,QAAiB,MAAM,QAAQ,CAAC;AAAA,IAClD,SAAS;AAAA,EACX;AACF;AAEA,IAAM,kBACJ;AAEF,eAAe,YAAY,UAAkB,MAA+B;AAC1E,MAAI;AACF,UAAM,MAAM,MAAM,uBAAuB;AACzC,QAAI,CAAC,KAAK;AACR,aAAO;AAAA,QACL,6EACE;AAAA,MACJ;AAAA,IACF;AACA,UAAM,SAAS,MAAM,IAAI,YAAY,UAAU,IAAI;AACnD,QAAI,CAAC,OAAO,IAAI;AACd,aAAO,aAAa,OAAO,SAAS,mBAAmB,eAAe;AAAA,IACxE;AACA,WAAO,WAAW,OAAO,MAAM;AAAA,EACjC,SAAS,KAAK;AACZ,WAAO,iBAAiB,GAAG;AAC3B,UAAM,MAAM,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG;AAC3D,WAAO,YAAY,qBAAqB,GAAG,KAAK,eAAe;AAAA,EACjE;AACF;AAIO,SAAS,cAAcA,SAAyB;AACrD,EAAAA,QAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA,CAAC;AAAA,IACD,YAAY;AACV,YAAM,SAAS,WAAW;AAC1B,YAAM,QAAQ,SAAS,MAAM,cAAc,IAAI;AAC/C,UAAI,OAAO;AACX,UAAI,OAAO;AACT,YAAI;AACF,iBAAO,MAAM,gBAAgB,KAAK,EAAE,UAAU;AAAA,QAChD,QAAQ;AAAA,QAAC;AAAA,MACX;AACA,aAAO,WAAW;AAAA,QAChB,eAAe,CAAC,CAAC;AAAA,QACjB,MAAM,QAAQ,QAAQ;AAAA,QACtB;AAAA,MACF,CAAC;AAAA,IACH;AAAA,EACF;AAIA,EAAAA,QAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,MACE,WAAW,EACR,OAAO,EACP,SAAS,EACT;AAAA,QACC;AAAA,MACF;AAAA,MACF,SAAS,EACN,OAAO,EACP,SAAS,EACT;AAAA,QACC;AAAA,MACF;AAAA,MACF,OAAO,EACJ,OAAO,EACP,SAAS,EACT;AAAA,QACC;AAAA,MACF;AAAA,MACF,QAAQ,EACL,OAAO,EACP,SAAS,EACT,SAAS,yDAAyD;AAAA,IACvE;AAAA,IACA,OAAO,SAAS,YAAY,iBAAiB,IAAI;AAAA,EACnD;AAEA,EAAAA,QAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,MACE,WAAW,EACR,OAAO,EACP,SAAS,oDAAoD;AAAA,MAChE,QAAQ,EACL,OAAO,EACP,SAAS,EACT;AAAA,QACC;AAAA,MACF;AAAA,MACF,OAAO,EACJ,OAAO,EACP,SAAS,EACT;AAAA,QACC;AAAA,MACF;AAAA,IACJ;AAAA,IACA,OAAO,SAAS,YAAY,8BAA8B,IAAI;AAAA,EAChE;AAIA,EAAAA,QAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,MACE,WAAW,EACR,OAAO,EACP,SAAS,EACT;AAAA,QACC;AAAA,MACF;AAAA,MACF,OAAO,EACJ,OAAO,EACP,SAAS,EACT,SAAS,kDAAkD;AAAA,IAChE;AAAA,IACA,OAAO,SAAS,YAAY,6BAA6B,IAAI;AAAA,EAC/D;AAEA,EAAAA,QAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,MACE,WAAW,EACR,OAAO,EACP,SAAS,EACT;AAAA,QACC;AAAA,MACF;AAAA,MACF,WAAW,EACR,OAAO,EACP,SAAS,EACT;AAAA,QACC;AAAA,MACF;AAAA,MACF,WAAW,EACR,OAAO,EACP,SAAS,EACT;AAAA,QACC;AAAA,MACF;AAAA,MACF,sBAAsB,EACnB,QAAQ,EACR,SAAS,EACT;AAAA,QACC;AAAA,MACF;AAAA,IACJ;AAAA,IACA,OAAO,SAAS,YAAY,qBAAqB,IAAI;AAAA,EACvD;AAIA,EAAAA,QAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA,CAAC;AAAA,IACD,YAAY,YAAY,eAAe,CAAC,CAAC;AAAA,EAC3C;AAEA,EAAAA,QAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,MACE,SAAS,EACN,OAAO,EACP,SAAS,2DAA2D;AAAA,IACzE;AAAA,IACA,OAAO,SAAS,YAAY,cAAc,IAAI;AAAA,EAChD;AAIA,EAAAA,QAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,MACE,OAAO,EACJ,OAAO,EACP,SAAS,EACT,SAAS,8CAA8C;AAAA,MAC1D,WAAW,EACR,OAAO,EACP,SAAS,EACT;AAAA,QACC;AAAA,MACF;AAAA,MACF,QAAQ,EACL,KAAK,CAAC,YAAY,WAAW,WAAW,QAAQ,CAAC,EACjD,SAAS,EACT,SAAS,kBAAkB;AAAA,MAC9B,OAAO,EACJ,OAAO,EACP,SAAS,EACT;AAAA,QACC;AAAA,MACF;AAAA,MACF,cAAc,EACX,OAAO,EACP,SAAS,EACT;AAAA,QACC;AAAA,MACF;AAAA,IACJ;AAAA,IACA,OAAO,SAAS,YAAY,mBAAmB,IAAI;AAAA,EACrD;AAEA,EAAAA,QAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,MACE,oBAAoB,EACjB;AAAA,QACC,EAAE,KAAK;AAAA,UACL;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,QACF,CAAC;AAAA,MACH,EACC,SAAS,EACT;AAAA,QACC;AAAA,MACF;AAAA,MACF,cAAc,EACX,OAAO,EACP,SAAS,EACT;AAAA,QACC;AAAA,MACF;AAAA,IACJ;AAAA,IACA,OAAO,SAAS,YAAY,yBAAyB,IAAI;AAAA,EAC3D;AAEA,EAAAA,QAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,MACE,YAAY,EACT,OAAO,EACP,IAAI,EACJ,IAAI,CAAC,EACL,IAAI,EAAE,EACN,SAAS,EACT;AAAA,QACC;AAAA,MACF;AAAA,IACJ;AAAA,IACA,OAAO,SAAS,YAAY,qBAAqB,IAAI;AAAA,EACvD;AAIA,EAAAA,QAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA,CAAC;AAAA,IACD,YAAY,YAAY,qBAAqB,CAAC,CAAC;AAAA,EACjD;AAGA,QAAM,mBAKD;AAAA,IACH;AAAA,MACE,MAAM;AAAA,MACN,UAAU;AAAA,MACV,aACE;AAAA,MACF,cACE;AAAA,IACJ;AAAA,IACA;AAAA,MACE,MAAM;AAAA,MACN,UAAU;AAAA,MACV,aACE;AAAA,MACF,cACE;AAAA,IACJ;AAAA,IACA;AAAA,MACE,MAAM;AAAA,MACN,UAAU;AAAA,MACV,aACE;AAAA,MACF,cAAc;AAAA,IAChB;AAAA,IACA;AAAA,MACE,MAAM;AAAA,MACN,UAAU;AAAA,MACV,aACE;AAAA,MACF,cACE;AAAA,IACJ;AAAA,IACA;AAAA,MACE,MAAM;AAAA,MACN,UAAU;AAAA,MACV,aACE;AAAA,MACF,cACE;AAAA,IACJ;AAAA,IACA;AAAA,MACE,MAAM;AAAA,MACN,UAAU;AAAA,MACV,aACE;AAAA,MACF,cACE;AAAA,IACJ;AAAA,IACA;AAAA,MACE,MAAM;AAAA,MACN,UAAU;AAAA,MACV,aACE;AAAA,MACF,cACE;AAAA,IACJ;AAAA,EACF;AAEA,aAAW,QAAQ,kBAAkB;AACnC,IAAAA,QAAO;AAAA,MACL,KAAK;AAAA,MACL,KAAK;AAAA,MACL;AAAA,QACE,UAAU,EAAE,OAAO,EAAE,SAAS,KAAK,YAAY;AAAA,QAC/C,QAAQ,EACL,KAAK,CAAC,OAAO,QAAQ,OAAO,SAAS,QAAQ,CAAC,EAC9C,SAAS,EACT,SAAS,+BAA+B;AAAA,QAC3C,MAAM,EACH,OAAO,EAAE,OAAO,GAAG,EAAE,QAAQ,CAAC,EAC9B,SAAS,EACT,SAAS,oDAAoD;AAAA,QAChE,WAAW,EACR,OAAO,EACP,SAAS,EACT;AAAA,UACC;AAAA,QACF;AAAA,MACJ;AAAA,MACA,OAAO,SAAS,YAAY,KAAK,UAAU,IAAI;AAAA,IACjD;AAAA,EACF;AAIA,EAAAA,QAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,MACE,WAAW,EACR,KAAK,CAAC,MAAM,MAAM,OAAO,MAAM,KAAK,CAAC,EACrC,SAAS,EACT,SAAS,kCAAkC;AAAA,MAC9C,OAAO,EACJ,OAAO,EACP,SAAS,EACT,SAAS,gDAAgD;AAAA,MAC5D,OAAO,EAAE,OAAO,EAAE,SAAS,EAAE,SAAS,yBAAyB;AAAA,MAC/D,QAAQ,EACL,KAAK,CAAC,UAAU,SAAS,UAAU,QAAQ,CAAC,EAC5C,SAAS,EACT,SAAS,qCAAqC;AAAA,MACjD,OAAO,EACJ,KAAK,CAAC,OAAO,WAAW,MAAM,CAAC,EAC/B,SAAS,EACT,SAAS,qDAAqD;AAAA,MACjE,gBAAgB,EACb,OAAO,EACP,SAAS,EACT,SAAS,iDAAiD;AAAA,IAC/D;AAAA,IACA,OAAO,SAAS,YAAY,4BAA4B,IAAI;AAAA,EAC9D;AAEA,EAAAA,QAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,MACE,OAAO,EACJ,KAAK,CAAC,OAAO,SAAS,CAAC,EACvB,SAAS,EACT,SAAS,6BAA6B;AAAA,MACzC,QAAQ,EACL,KAAK,CAAC,UAAU,SAAS,UAAU,QAAQ,CAAC,EAC5C,SAAS,EACT,SAAS,qCAAqC;AAAA,MACjD,gBAAgB,EACb,OAAO,EACP,SAAS,EACT,SAAS,6CAA6C;AAAA,MACzD,WAAW,EAAE,KAAK,CAAC,MAAM,MAAM,OAAO,MAAM,KAAK,CAAC,EAAE,SAAS;AAAA,MAC7D,OAAO,EAAE,OAAO,EAAE,SAAS,EAAE,SAAS,2BAA2B;AAAA,MACjE,OAAO,EAAE,OAAO,EAAE,SAAS,EAAE,SAAS,yBAAyB;AAAA,MAC/D,OAAO,EACJ,OAAO,EACP,SAAS,EACT,SAAS,8CAA8C;AAAA,IAC5D;AAAA,IACA,OAAO,SAAS,YAAY,6BAA6B,IAAI;AAAA,EAC/D;AAEA,EAAAA,QAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,MACE,WAAW,EAAE,OAAO,EAAE,SAAS,oCAAoC;AAAA,MACnE,uBAAuB,EACpB,QAAQ,EACR,SAAS,EACT,SAAS,0CAA0C;AAAA,MACtD,QAAQ,EACL,KAAK,CAAC,YAAY,SAAS,KAAK,CAAC,EACjC,SAAS,EACT;AAAA,QACC;AAAA,MACF;AAAA,MACF,WAAW,EACR,OAAO,EACP,SAAS,EACT;AAAA,QACC;AAAA,MACF;AAAA,MACF,OAAO,EACJ,OAAO,EACP,SAAS,EACT,SAAS,8CAA8C;AAAA,MAC1D,QAAQ,EACL,OAAO,EACP,SAAS,EACT,SAAS,sCAAsC;AAAA,IACpD;AAAA,IACA,OAAO,SAAS,YAAY,wBAAwB,IAAI;AAAA,EAC1D;AAEA,EAAAA,QAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,MACE,WAAW,EAAE,OAAO,EAAE,SAAS,kCAAkC;AAAA,MACjE,OAAO,EACJ,OAAO,EACP,SAAS,EACT,SAAS,4CAA4C;AAAA,MACxD,QAAQ,EACL,OAAO,EACP,SAAS,EACT,SAAS,oCAAoC;AAAA,IAClD;AAAA,IACA,OAAO,SAAS,YAAY,qBAAqB,IAAI;AAAA,EACvD;AAEA,EAAAA,QAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,MACE,WAAW,EACR,KAAK,CAAC,MAAM,MAAM,OAAO,MAAM,KAAK,CAAC,EACrC,SAAS,EACT,SAAS,eAAe;AAAA,MAC3B,OAAO,EAAE,OAAO,EAAE,SAAS,EAAE,SAAS,2BAA2B;AAAA,MACjE,OAAO,EAAE,OAAO,EAAE,SAAS,EAAE,SAAS,yBAAyB;AAAA,MAC/D,SAAS,EACN,KAAK,CAAC,WAAW,SAAS,KAAK,CAAC,EAChC,SAAS,EACT,SAAS,uBAAuB;AAAA,MACnC,QAAQ,EACL,KAAK,CAAC,UAAU,SAAS,UAAU,QAAQ,CAAC,EAC5C,SAAS,EACT,SAAS,qCAAqC;AAAA,IACnD;AAAA,IACA,OAAO,SAAS,YAAY,mBAAmB,IAAI;AAAA,EACrD;AAEA,EAAAA,QAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,MACE,OAAO,EAAE,OAAO,EAAE,SAAS,uCAAuC;AAAA,MAClE,WAAW,EAAE,KAAK,CAAC,MAAM,MAAM,OAAO,MAAM,KAAK,CAAC,EAAE,SAAS;AAAA,MAC7D,OAAO,EAAE,OAAO,EAAE,SAAS;AAAA,MAC3B,OAAO,EAAE,OAAO,EAAE,SAAS;AAAA,MAC3B,QAAQ,EACL,KAAK,CAAC,UAAU,SAAS,UAAU,QAAQ,CAAC,EAC5C,SAAS,EACT,SAAS,qCAAqC;AAAA,MACjD,OAAO,EAAE,OAAO,EAAE,SAAS,EAAE,SAAS,2BAA2B;AAAA,IACnE;AAAA,IACA,OAAO,SAAS,YAAY,+BAA+B,IAAI;AAAA,EACjE;AAIA,EAAAA,QAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA,CAAC;AAAA,IACD,YAAY;AACV,UAAI;AACF,cAAM,UAAU,eAAe;AAC/B,YAAI,CAAC,QAAS,QAAO,YAAY,mCAAmC;AACpE,cAAM,MAAM,MAAM,uBAAuB;AACzC,YAAI,CAAC,IAAK,QAAO,YAAY,qCAAqC;AAClE,cAAM,SAAS,MAAM,IAAI,wBAAwB,OAAO;AACxD,eAAO,WAAW,MAAM;AAAA,MAC1B,SAAS,KAAK;AACZ,eAAO,iBAAiB,GAAG;AAC3B,eAAO;AAAA,UACL,UAAU,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG,CAAC;AAAA,QAC5D;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAEA,EAAAA,QAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,MACE,gBAAgB,EAAE,OAAO,EAAE,SAAS,6BAA6B;AAAA,IACnE;AAAA,IACA,OAAO,SAAS;AACd,UAAI;AACF,cAAM,UAAU,eAAe;AAC/B,YAAI,CAAC,QAAS,QAAO,YAAY,mCAAmC;AACpE,cAAM,MAAM,MAAM,uBAAuB;AACzC,YAAI,CAAC,IAAK,QAAO,YAAY,qCAAqC;AAClE,cAAM,SAAS,MAAM,IAAI;AAAA,UACvB;AAAA,UACA,KAAK;AAAA,QACP;AACA,YAAI,CAAC;AACH,iBAAO,YAAY,uBAAuB,KAAK,cAAc,GAAG;AAClE,eAAO,WAAW,MAAM;AAAA,MAC1B,SAAS,KAAK;AACZ,eAAO,iBAAiB,GAAG;AAC3B,eAAO;AAAA,UACL,UAAU,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG,CAAC;AAAA,QAC5D;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAEA,EAAAA,QAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,MACE,YAAY,EACT,OAAO,EACP,SAAS,EACT,SAAS,mDAAmD;AAAA,IACjE;AAAA,IACA,OAAO,SAAS;AACd,UAAI;AACF,cAAM,UAAU,eAAe;AAC/B,YAAI,CAAC,QAAS,QAAO,YAAY,mCAAmC;AACpE,cAAM,MAAM,MAAM,uBAAuB;AACzC,YAAI,CAAC,IAAK,QAAO,YAAY,qCAAqC;AAClE,cAAM,SAAS,MAAM,IAAI;AAAA,UACvB;AAAA,UACA,KAAK;AAAA,QACP;AACA,eAAO,WAAW,MAAM;AAAA,MAC1B,SAAS,KAAK;AACZ,eAAO,iBAAiB,GAAG;AAC3B,eAAO;AAAA,UACL,UAAU,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG,CAAC;AAAA,QAC5D;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAEA,EAAAA,QAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,MACE,YAAY,EACT,OAAO,EACP,SAAS,yCAAyC;AAAA,IACvD;AAAA,IACA,OAAO,SAAS;AACd,UAAI;AACF,cAAM,UAAU,eAAe;AAC/B,YAAI,CAAC,QAAS,QAAO,YAAY,mCAAmC;AACpE,cAAM,MAAM,MAAM,uBAAuB;AACzC,YAAI,CAAC,IAAK,QAAO,YAAY,qCAAqC;AAClE,cAAM,SAAS,MAAM,IAAI,oBAAoB,SAAS,KAAK,UAAU;AACrE,YAAI,CAAC;AACH,iBAAO,YAAY,uBAAuB,KAAK,UAAU,GAAG;AAC9D,eAAO,WAAW,MAAM;AAAA,MAC1B,SAAS,KAAK;AACZ,eAAO,iBAAiB,GAAG;AAC3B,eAAO;AAAA,UACL,UAAU,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG,CAAC;AAAA,QAC5D;AAAA,MACF;AAAA,IACF;AAAA,EACF;AACF;;;ADznBA,oBAAoB;AAapB,IAAM,WAAW,KAAK,KAAK,aAAa,SAAS;AAEjD,IAAM,SAAS,IAAI,UAAU;AAAA,EAC3B,MAAM;AAAA,EACN,SAAS;AACX,CAAC;AAED,cAAc,MAAM;AAEpB,eAAe,OAAO;AACpB,QAAM,WAAW;AAGjB,MAAI,CAAC,GAAG,WAAW,WAAW,GAAG;AAC/B,OAAG,UAAU,aAAa,EAAE,WAAW,KAAK,CAAC;AAAA,EAC/C;AACA,QAAM,QAAQ,GAAG,SAAS,UAAU,GAAG;AACvC,QAAM,YAAY,GAAG,kBAAkB,IAAI,EAAE,IAAI,MAAM,CAAC;AACxD,UAAQ,OAAO,QAAQ,UAAU,MAAM;AAAA,IACrC;AAAA,EACF;AAGA,QAAM,SAAS,WAAW;AAC1B,QAAM,aAAa,SAAS,MAAM,cAAc,IAAI;AAEpD,MAAI,CAAC,QAAQ;AACX,UAAM,YAAY,cAAc;AAChC,QAAI;AACF,YAAM,QAAQ,GAAG,YAAY,YAAY,EAAE,KAAK,IAAI,KAAK;AACzD,cAAQ;AAAA,QACN,yBAAyB,SAAS,mBAAmB,KAAK;AAAA,MAC5D;AAAA,IACF,QAAQ;AACN,cAAQ,MAAM,yBAAyB,SAAS,qBAAqB;AAAA,IACvE;AACA,WAAO,SAAS,SAAS,eAAe,aAAa;AAAA,MACnD,UAAU;AAAA,QACR;AAAA,UACE,KAAK;AAAA,UACL,MAAM;AAAA,QACR;AAAA,MACF;AAAA,IACF,EAAE;AACF,YAAQ,MAAM,gDAA2C;AAAA,EAC3D,WAAW,CAAC,YAAY;AACtB,YAAQ,MAAM,+DAA0D;AAAA,EAC1E;AAEA,QAAM,YAAY,IAAI,qBAAqB;AAC3C,QAAM,OAAO,QAAQ,SAAS;AAG9B,MAAI,CAAC,uBAAuB,GAAG;AAC7B,QAAI;AACF,YAAM,EAAE,YAAY,IAAI,MAAM,OAAO,uBAAuB;AAC5D,YAAM,YAAY;AAAA,IACpB,QAAQ;AACN,cAAQ;AAAA,QACN;AAAA,MACF;AAAA,IACF;AAAA,EACF;AACF;AAEA,KAAK,EAAE,MAAM,CAAC,QAAQ;AACpB,SAAO,iBAAiB,GAAG;AAC3B,UAAQ,MAAM,yBAAyB,GAAG;AAC1C,UAAQ,KAAK,CAAC;AAChB,CAAC;","names":["server"]}
|
|
1
|
+
{"version":3,"sources":["../../src/mcp/server.ts","../../src/mcp/tools.ts"],"sourcesContent":["#!/usr/bin/env node\n\nimport fs from \"node:fs\";\nimport path from \"node:path\";\nimport { McpServer } from \"@modelcontextprotocol/sdk/server/mcp.js\";\nimport { StdioServerTransport } from \"@modelcontextprotocol/sdk/server/stdio.js\";\nimport { registerTools } from \"./tools.js\";\nimport { getValidToken, readTokens } from \"../auth/token-store.js\";\nimport { authStorePath } from \"../config.js\";\nimport { initSentry, Sentry } from \"../sentry.js\";\nimport { parsePanopticonRunning } from \"../commands/daemon.js\";\nimport { FML_DATA_DIR, FML_LOG_DIR } from \"../dirs.js\";\n\nconst LOG_PATH = path.join(FML_LOG_DIR, \"mcp.log\");\n\nconst server = new McpServer({\n name: \"fml\",\n version: \"0.1.0\",\n});\n\nregisterTools(server);\n\nasync function main() {\n await initSentry();\n\n // Redirect stderr to log file (stdout is reserved for MCP JSON-RPC protocol)\n if (!fs.existsSync(FML_LOG_DIR)) {\n fs.mkdirSync(FML_LOG_DIR, { recursive: true });\n }\n const logFd = fs.openSync(LOG_PATH, \"a\");\n const logStream = fs.createWriteStream(\"\", { fd: logFd });\n process.stderr.write = logStream.write.bind(\n logStream,\n ) as typeof process.stderr.write;\n\n // Check auth state and surface setup prompts\n const tokens = readTokens();\n const tokenValid = tokens ? await getValidToken() : null;\n\n if (!tokens) {\n const storePath = authStorePath();\n try {\n const files = fs.readdirSync(FML_DATA_DIR).join(\", \") || \"(empty)\";\n console.error(\n `[fml] No auth file at ${storePath}. Dir contents: ${files}`,\n );\n } catch {\n console.error(`[fml] No auth file at ${storePath}. Dir not readable.`);\n }\n server.resource(\"setup\", \"fml://setup\", async () => ({\n contents: [\n {\n uri: \"fml://setup\",\n text: \"FML plugin is not authenticated. Run `fml login` in your terminal to sign in, then restart Claude Code.\",\n },\n ],\n }));\n console.error(\"[fml] Not authenticated — run `fml login`\");\n } else if (!tokenValid) {\n console.error(\"[fml] Token expired — run `fml login` to re-authenticate\");\n }\n\n const transport = new StdioServerTransport();\n await server.connect(transport);\n\n // Ensure panopticon is running (includes sync, which handles config snapshots)\n if (!parsePanopticonRunning()) {\n try {\n const { handleStart } = await import(\"../commands/daemon.js\");\n await handleStart();\n } catch {\n console.error(\n \"[fml] Warning: could not start panopticon. Run `fml start` manually\",\n );\n }\n }\n}\n\nmain().catch((err) => {\n Sentry.captureException(err);\n console.error(\"FML MCP server error:\", err);\n process.exit(1);\n});\n","import type { McpServer } from \"@modelcontextprotocol/sdk/server/mcp.js\";\nimport { z } from \"zod\";\nimport {\n getSelectedOrg,\n getValidToken,\n readTokens,\n} from \"../auth/token-store.js\";\nimport {\n createFmlClient,\n getAuthenticatedClient,\n type ToolResult,\n} from \"../fml-client.js\";\nimport { resolveRepoFromCwd } from \"@fml-inc/panopticon/repo\";\nimport { Sentry } from \"../sentry.js\";\n\n// ─── Helpers ──────────────────────────────────────────────────────────────────\n\nfunction textResult(data: unknown) {\n return {\n content: [{ type: \"text\" as const, text: JSON.stringify(data, null, 2) }],\n };\n}\n\nfunction errorResult(message: string) {\n return {\n content: [{ type: \"text\" as const, text: message }],\n isError: true,\n };\n}\n\nconst PANOPTICON_HINT =\n \"\\n\\nFor local data, use the panopticon MCP tools instead (e.g. panopticon__sessions, panopticon__costs, panopticon__search, panopticon__timeline).\";\n\nasync function toolHandler(toolName: string, args: Record<string, unknown>) {\n try {\n const api = await getAuthenticatedClient();\n if (!api) {\n return errorResult(\n \"Not authenticated. Run `fml login` to sign in, then restart Claude Code.\" +\n PANOPTICON_HINT,\n );\n }\n const result = await api.callBackend(toolName, args);\n if (!result.ok) {\n return errorResult((result.error ?? \"Unknown error\") + PANOPTICON_HINT);\n }\n return textResult(result.result);\n } catch (err) {\n Sentry.captureException(err);\n const msg = err instanceof Error ? err.message : String(err);\n return errorResult(`Unexpected error: ${msg}` + PANOPTICON_HINT);\n }\n}\n\n// ─── Registration ─────────────────────────────────────────────────────────────\n\nexport function registerTools(server: McpServer): void {\n server.tool(\n \"whoami\",\n \"Show current authenticated user and available organizations\",\n {},\n async () => {\n const tokens = readTokens();\n const token = tokens ? await getValidToken() : null;\n let orgs = null;\n if (token) {\n try {\n orgs = await createFmlClient(token).queryOrgs();\n } catch {}\n }\n return textResult({\n authenticated: !!tokens,\n user: tokens?.user ?? null,\n orgs,\n });\n },\n );\n\n // ── Messages ───────────────────────────────────────────────────────────────\n\n server.tool(\n \"fml_list_messages\",\n \"List messages from a conversation within a time range. Requires a conversationId from the FML web app.\",\n {\n startTime: z\n .number()\n .optional()\n .describe(\n \"Start time in milliseconds (inclusive). Omit to start from beginning.\",\n ),\n endTime: z\n .number()\n .optional()\n .describe(\n \"End time in milliseconds (inclusive). Omit to include up to most recent.\",\n ),\n limit: z\n .number()\n .optional()\n .describe(\n \"Maximum number of messages to return per page (default: 20)\",\n ),\n cursor: z\n .string()\n .optional()\n .describe(\"Pagination cursor from previous result to get next page\"),\n },\n async (args) => toolHandler(\"list-messages\", args),\n );\n\n server.tool(\n \"fml_list_messages_with_context\",\n \"Get messages around a specific message to see the context. Takes a message ID and returns messages before and after it.\",\n {\n messageId: z\n .string()\n .describe(\"The ID of the target message to get context around\"),\n before: z\n .number()\n .optional()\n .describe(\n \"Number of messages to retrieve before the target (default: 5)\",\n ),\n after: z\n .number()\n .optional()\n .describe(\n \"Number of messages to retrieve after the target (default: 5)\",\n ),\n },\n async (args) => toolHandler(\"list-messages-with-context\", args),\n );\n\n // ── Slack ──────────────────────────────────────────────────────────────────\n\n server.tool(\n \"fml_get_slack_channel_history\",\n \"Fetch recent message history from a Slack channel. Requires Slack integration to be connected.\",\n {\n channelId: z\n .string()\n .optional()\n .describe(\n \"Slack channel ID (e.g. C0123ABC). If omitted, uses the channel from the current Slack-sourced conversation.\",\n ),\n limit: z\n .number()\n .optional()\n .describe(\"Number of messages to fetch (default 20, max 50)\"),\n },\n async (args) => toolHandler(\"get-slack-channel-history\", args),\n );\n\n server.tool(\n \"fml_get_slack_message\",\n \"Fetch a specific Slack message by timestamp or permalink. Requires Slack integration to be connected.\",\n {\n permalink: z\n .string()\n .optional()\n .describe(\n \"Slack message permalink. If provided, channelId and messageTs are ignored.\",\n ),\n channelId: z\n .string()\n .optional()\n .describe(\n \"Slack channel ID (e.g. C0123ABC). Required if permalink not provided.\",\n ),\n messageTs: z\n .string()\n .optional()\n .describe(\n \"Message timestamp (e.g. 1234567890.123456). Required if permalink not provided.\",\n ),\n includeThreadContext: z\n .boolean()\n .optional()\n .describe(\n \"If true, fetches thread replies along with the message (default false)\",\n ),\n },\n async (args) => toolHandler(\"get-slack-message\", args),\n );\n\n // ── Skills ─────────────────────────────────────────────────────────────────\n\n server.tool(\n \"fml_list_skills\",\n \"List all available FML skills. Skills provide detailed knowledge about FML features.\",\n {},\n async () => toolHandler(\"list-skills\", {}),\n );\n\n server.tool(\n \"fml_load_skill\",\n \"Load a skill prompt by ID. Skills provide detailed knowledge about FML features.\",\n {\n skillId: z\n .string()\n .describe(\"The skill ID to load (e.g., 'fml-help', 'fml-navigation')\"),\n },\n async (args) => toolHandler(\"load-skill\", args),\n );\n\n // ── Analysis ───────────────────────────────────────────────────────────────\n\n server.tool(\n \"fml_search_analysis\",\n \"Search analysis results produced by `fml_run_analysis_workflow`. USE FOR: finding analyses by topic, type, or status across a repo (or all repos in the org). FILTERS: query (text search), promptKey (exact type like 'deep_security_auditor'), status (complete, running, failed). Pass `repositoryId` to limit the search, or omit to fan out across every repo in the org.\",\n {\n query: z\n .string()\n .optional()\n .describe(\"Text search across analysis type and content\"),\n promptKey: z\n .string()\n .optional()\n .describe(\n \"Exact filter by analysis type (e.g., 'deep_security_auditor')\",\n ),\n status: z\n .enum([\"complete\", \"running\", \"created\", \"failed\"])\n .optional()\n .describe(\"Filter by status\"),\n limit: z\n .number()\n .optional()\n .describe(\n \"Maximum number of results to return total across all matched repos (default 20)\",\n ),\n repositoryId: z\n .string()\n .optional()\n .describe(\n \"Limit to one repository. Omit to search every repo in the caller's organization.\",\n ),\n },\n async (args) => toolHandler(\"search-analysis\", args),\n );\n\n server.tool(\n \"fml_run_analysis_workflow\",\n \"Run comprehensive codebase analysis workflows on a repository. Available prompts: deep_security_auditor, deep_architecture_auditor, deep_code_quality_auditor, deep_performance_auditor, deep_ux_auditor, deep_dependencies_auditor, deep_cost_auditor, deep_ai_architecture_integration, deep_ai_security. The backend auto-picks the repo for single-repo orgs; pass `repositoryId` explicitly when the org has multiple repos (the tool will otherwise return a clarifying error listing them).\",\n {\n selectedPromptKeys: z\n .array(\n z.enum([\n \"deep_security_auditor\",\n \"deep_architecture_auditor\",\n \"deep_code_quality_auditor\",\n \"deep_performance_auditor\",\n \"deep_ux_auditor\",\n \"deep_dependencies_auditor\",\n \"deep_cost_auditor\",\n \"deep_ai_architecture_integration\",\n \"deep_ai_security\",\n ]),\n )\n .optional()\n .describe(\n \"Array of specific analysis prompts to run. If not provided, runs default set.\",\n ),\n repositoryId: z\n .string()\n .optional()\n .describe(\n \"Target repository ID. Omit for single-repo orgs (auto-pick). Required when the org has multiple repos — the tool will list them in its error if not provided.\",\n ),\n },\n async (args) => toolHandler(\"run-analysis-workflow\", args),\n );\n\n server.tool(\n \"fml_run_team_analysis\",\n \"Run a team-wide AI coding practice analysis for the caller's organization. Produces a structured report with per-person narratives covering tool usage, collaboration patterns, configuration, and notable changes. Use for prompts like 'run team analysis for the last 14 days' or 'how is the team doing?'. Kicks a durable Convex workflow and returns immediately with a reportId; when called inside a conversation, a completion message is posted back to that conversation when the workflow finishes — wait for that follow-up turn, do not poll. Idempotent: if a run is already in flight, returns the existing reportId with started=false. Requires org-owner access and at least one running dev environment.\",\n {\n windowDays: z\n .number()\n .int()\n .min(1)\n .max(90)\n .optional()\n .describe(\n \"Size of the analysis window in days. Defaults to 30. Clamped to [1, 90]. Match the user's phrasing: 'last 14 days' → 14, 'last month' → 30, 'this week' → 7.\",\n ),\n },\n async (args) => toolHandler(\"run-team-analysis\", args),\n );\n\n // ── Integrations ───────────────────────────────────────────────────────────\n\n server.tool(\n \"fml_list_integrations\",\n \"List integrations for this project — both connected and available. Use to check what integrations are active.\",\n {},\n async () => toolHandler(\"list-integrations\", {}),\n );\n\n // Integration query tools\n const integrationTools: Array<{\n name: string;\n mastraId: string;\n description: string;\n endpointHelp: string;\n }> = [\n {\n name: \"fml_query_sentry\",\n mastraId: \"integration-sentry\",\n description:\n \"Look up production errors, exceptions, and crash data from Sentry. Common endpoints: 'organizations/{orgSlug}/issues/' (GET), 'issues/{issue_id}/' (GET). {orgSlug} is auto-substituted.\",\n endpointHelp:\n \"Sentry REST API endpoint. {orgSlug} is auto-substituted. e.g. 'organizations/{orgSlug}/issues/'\",\n },\n {\n name: \"fml_query_slack\",\n mastraId: \"integration-slack\",\n description:\n \"Send messages and read channel/user info from Slack. Use channel IDs not names. Common endpoints: 'conversations.list' (GET), 'chat.postMessage' (POST).\",\n endpointHelp:\n \"Slack API method, e.g. 'conversations.list', 'chat.postMessage'\",\n },\n {\n name: \"fml_query_github\",\n mastraId: \"integration-github\",\n description:\n \"Query repository activity from GitHub — PRs, commits, issues, code. {owner} and {repo} are auto-substituted. Common endpoints: 'repos/{owner}/{repo}/pulls' (GET).\",\n endpointHelp: \"GitHub REST API path. e.g. 'repos/{owner}/{repo}/pulls'\",\n },\n {\n name: \"fml_query_linear\",\n mastraId: \"integration-linear\",\n description:\n \"Query and manage Linear issues and projects via GraphQL. Endpoint is always 'graphql', method POST.\",\n endpointHelp:\n \"Linear GraphQL endpoint — always use 'graphql' with method POST and {query, variables} in body\",\n },\n {\n name: \"fml_query_notion\",\n mastraId: \"integration-notion\",\n description:\n \"Search pages, query databases, read and write content in Notion. Common endpoints: 'search' (POST), 'databases/{id}/query' (POST).\",\n endpointHelp:\n \"Notion REST API endpoint, e.g. 'search', 'databases/{database_id}/query'\",\n },\n {\n name: \"fml_query_freshdesk\",\n mastraId: \"integration-freshdesk\",\n description:\n \"Query and manage customer support tickets in Freshdesk. Common endpoints: 'tickets' (GET), 'tickets/{id}' (GET).\",\n endpointHelp:\n \"Freshdesk REST API v2 endpoint, e.g. 'tickets', 'tickets/{id}'\",\n },\n {\n name: \"fml_query_stripe\",\n mastraId: \"integration-stripe\",\n description:\n \"Query Stripe API for customers, subscriptions, charges, invoices, and revenue. Common endpoints: 'customers' (GET), 'subscriptions?status=active' (GET), 'charges' (GET), 'invoices' (GET), 'balance' (GET).\",\n endpointHelp:\n \"Stripe REST API v1 endpoint, e.g. 'customers', 'subscriptions?status=active', 'charges', 'balance'\",\n },\n ];\n\n for (const tool of integrationTools) {\n server.tool(\n tool.name,\n tool.description,\n {\n endpoint: z.string().describe(tool.endpointHelp),\n method: z\n .enum([\"GET\", \"POST\", \"PUT\", \"PATCH\", \"DELETE\"])\n .optional()\n .describe(\"HTTP method. Defaults to GET.\"),\n body: z\n .record(z.string(), z.unknown())\n .optional()\n .describe(\"Request body as a JSON object (for POST/PUT/PATCH)\"),\n projectId: z\n .string()\n .optional()\n .describe(\n \"Optional project ID to scope this query. Required for GitHub (needs repo context).\",\n ),\n },\n async (args) => toolHandler(tool.mastraId, args),\n );\n }\n\n // ── Engineering Activity ───────────────────────────────────────────────────\n\n server.tool(\n \"get_engineering_activity\",\n \"Get agent activity summary (Claude Code, Codex, Gemini CLI, Mastra). SCOPES: 'org' (default), 'project', or 'user' (by githubUsername).\",\n {\n timeRange: z\n .enum([\"1h\", \"6h\", \"24h\", \"7d\", \"30d\"])\n .optional()\n .describe(\"Preset time range. Default '7d'.\"),\n since: z\n .string()\n .optional()\n .describe(\"ISO 8601 start timestamp. Overrides timeRange.\"),\n until: z.string().optional().describe(\"ISO 8601 end timestamp.\"),\n target: z\n .enum([\"claude\", \"codex\", \"gemini\", \"mastra\"])\n .optional()\n .describe(\"Filter by agent type. Omit for all.\"),\n scope: z\n .enum([\"org\", \"project\", \"user\"])\n .optional()\n .describe(\"Query scope. 'org' (default), 'project', or 'user'.\"),\n githubUsername: z\n .string()\n .optional()\n .describe(\"Required when scope is 'user'. GitHub username.\"),\n },\n async (args) => toolHandler(\"get-engineering-activity\", args),\n );\n\n server.tool(\n \"list_engineering_sessions\",\n \"List agent sessions (Claude Code, Codex, Gemini CLI, Mastra). Each session includes first prompt preview and event counts.\",\n {\n scope: z\n .enum([\"org\", \"project\"])\n .optional()\n .describe(\"Query scope. Default 'org'.\"),\n target: z\n .enum([\"claude\", \"codex\", \"gemini\", \"mastra\"])\n .optional()\n .describe(\"Filter by agent type. Omit for all.\"),\n githubUsername: z\n .string()\n .optional()\n .describe(\"Filter to sessions by this GitHub username.\"),\n timeRange: z.enum([\"1h\", \"6h\", \"24h\", \"7d\", \"30d\"]).optional(),\n since: z.string().optional().describe(\"ISO 8601 start timestamp.\"),\n until: z.string().optional().describe(\"ISO 8601 end timestamp.\"),\n limit: z\n .number()\n .optional()\n .describe(\"Max sessions to return (default 20, max 50).\"),\n },\n async (args) => toolHandler(\"list-engineering-sessions\", args),\n );\n\n server.tool(\n \"get_session_timeline\",\n 'Get chronological timeline for a coding agent session. Returns messages and/or hook events interleaved by timestamp. Use source=\"hooks\" to see permission requests, tool approvals, etc. REQUIRES: sessionId from list_engineering_sessions.',\n {\n sessionId: z.string().describe(\"The session ID to get details for.\"),\n includeSystemMessages: z\n .boolean()\n .optional()\n .describe(\"Include system messages (default false).\"),\n source: z\n .enum([\"messages\", \"hooks\", \"all\"])\n .optional()\n .describe(\n 'Filter by source: \"messages\" (scanner messages only), \"hooks\" (hook events only), \"all\" (both interleaved). Default \"all\".',\n ),\n eventType: z\n .string()\n .optional()\n .describe(\n 'Filter hook events by type (e.g. \"PermissionRequest\", \"PreToolUse\", \"Stop\"). Only applies when source includes hooks.',\n ),\n limit: z\n .number()\n .optional()\n .describe(\"Max entries to return (default 50, max 200).\"),\n offset: z\n .number()\n .optional()\n .describe(\"Skip first N entries for pagination.\"),\n },\n async (args) => toolHandler(\"get-session-timeline\", args),\n );\n\n server.tool(\n \"get_session_turns\",\n \"Get per-turn token accounting for a coding agent session. USE FOR: understanding cost per turn, model used at each step, cache hit analysis. REQUIRES: sessionId from list_engineering_sessions.\",\n {\n sessionId: z.string().describe(\"The session ID to get turns for.\"),\n limit: z\n .number()\n .optional()\n .describe(\"Max turns to return (default 50, max 200).\"),\n offset: z\n .number()\n .optional()\n .describe(\"Skip first N turns for pagination.\"),\n },\n async (args) => toolHandler(\"get-session-turns\", args),\n );\n\n server.tool(\n \"get_ai_spending\",\n \"Get AI spending and token usage data. Groups by 'session' (default), 'model', or 'day'.\",\n {\n timeRange: z\n .enum([\"1h\", \"6h\", \"24h\", \"7d\", \"30d\"])\n .optional()\n .describe(\"Default '7d'.\"),\n since: z.string().optional().describe(\"ISO 8601 start timestamp.\"),\n until: z.string().optional().describe(\"ISO 8601 end timestamp.\"),\n groupBy: z\n .enum([\"session\", \"model\", \"day\"])\n .optional()\n .describe(\"How to group results.\"),\n target: z\n .enum([\"claude\", \"codex\", \"gemini\", \"mastra\"])\n .optional()\n .describe(\"Filter by agent type. Omit for all.\"),\n },\n async (args) => toolHandler(\"get-ai-spending\", args),\n );\n\n server.tool(\n \"search_engineering_sessions\",\n \"Search across agent sessions by text. Searches prompts, tool names, and event payloads.\",\n {\n query: z.string().describe(\"Text to search for. Case-insensitive.\"),\n timeRange: z.enum([\"1h\", \"6h\", \"24h\", \"7d\", \"30d\"]).optional(),\n since: z.string().optional(),\n until: z.string().optional(),\n target: z\n .enum([\"claude\", \"codex\", \"gemini\", \"mastra\"])\n .optional()\n .describe(\"Filter by agent type. Omit for all.\"),\n limit: z.number().optional().describe(\"Max results (default 20).\"),\n },\n async (args) => toolHandler(\"search-engineering-sessions\", args),\n );\n\n // ── Config Snapshots ────────────────────────────────────────────────────\n\n server.tool(\n \"list_user_configs\",\n \"List user-level configuration snapshots (CLAUDE.md, settings, etc.) across the org. Shows who has configs and when they were last updated.\",\n {},\n async () => {\n try {\n const orgSlug = getSelectedOrg();\n if (!orgSlug) return errorResult(\"No org selected. Run `fml login`.\");\n const api = await getAuthenticatedClient();\n if (!api) return errorResult(\"Not authenticated. Run `fml login`.\");\n const result = await api.listUserConfigSnapshots(orgSlug);\n return textResult(result);\n } catch (err) {\n Sentry.captureException(err);\n return errorResult(\n `Error: ${err instanceof Error ? err.message : String(err)}`,\n );\n }\n },\n );\n\n server.tool(\n \"get_user_config\",\n \"Get detailed user configuration for a specific GitHub user — their CLAUDE.md, settings.json, MCP servers, etc.\",\n {\n githubUsername: z.string().describe(\"GitHub username to look up.\"),\n },\n async (args) => {\n try {\n const orgSlug = getSelectedOrg();\n if (!orgSlug) return errorResult(\"No org selected. Run `fml login`.\");\n const api = await getAuthenticatedClient();\n if (!api) return errorResult(\"Not authenticated. Run `fml login`.\");\n const result = await api.getUserConfigDetail(\n orgSlug,\n args.githubUsername,\n );\n if (!result)\n return errorResult(`No config found for ${args.githubUsername}.`);\n return textResult(result);\n } catch (err) {\n Sentry.captureException(err);\n return errorResult(\n `Error: ${err instanceof Error ? err.message : String(err)}`,\n );\n }\n },\n );\n\n server.tool(\n \"list_repo_configs\",\n \"List repository-level configuration snapshots (CLAUDE.md, .mcp.json, etc.) across the org. Optionally filter by repository.\",\n {\n repository: z\n .string()\n .optional()\n .describe(\"Filter by repository full name (e.g. 'org/repo').\"),\n },\n async (args) => {\n try {\n const orgSlug = getSelectedOrg();\n if (!orgSlug) return errorResult(\"No org selected. Run `fml login`.\");\n const api = await getAuthenticatedClient();\n if (!api) return errorResult(\"Not authenticated. Run `fml login`.\");\n const result = await api.listRepoConfigSnapshots(\n orgSlug,\n args.repository,\n );\n return textResult(result);\n } catch (err) {\n Sentry.captureException(err);\n return errorResult(\n `Error: ${err instanceof Error ? err.message : String(err)}`,\n );\n }\n },\n );\n\n server.tool(\n \"get_repo_config\",\n \"Get detailed repository configuration — CLAUDE.md files, .mcp.json, and other agent config found in a specific repo.\",\n {\n repository: z\n .string()\n .describe(\"Repository full name (e.g. 'org/repo').\"),\n },\n async (args) => {\n try {\n const orgSlug = getSelectedOrg();\n if (!orgSlug) return errorResult(\"No org selected. Run `fml login`.\");\n const api = await getAuthenticatedClient();\n if (!api) return errorResult(\"Not authenticated. Run `fml login`.\");\n const result = await api.getRepoConfigDetail(orgSlug, args.repository);\n if (!result)\n return errorResult(`No config found for ${args.repository}.`);\n return textResult(result);\n } catch (err) {\n Sentry.captureException(err);\n return errorResult(\n `Error: ${err instanceof Error ? err.message : String(err)}`,\n );\n }\n },\n );\n\n // ── Anamnesis ground-truth context ──────────────────────────────────────\n // Factual git/GitHub history for the current repo (which PRs touched a file,\n // what a commit/PR did, etc.), served from the anamnesis corpus.\n\n const resolveRepoArg = (repo?: string): string | null => {\n if (repo) return repo;\n try {\n return resolveRepoFromCwd(process.cwd())?.repo ?? null;\n } catch {\n return null;\n }\n };\n\n const anamnesisResult = (result: ToolResult) =>\n result.ok\n ? textResult(result.result)\n : errorResult(result.error ?? \"Unknown error\");\n\n server.tool(\n \"fml_path_history\",\n \"Ground-truth history for a file path: PRs that touched it and review comments on it (newest first). USE FOR: understanding why a file looks the way it does, who changed it, related PRs.\",\n {\n path: z.string().describe(\"Repo-relative file path, e.g. 'src/app.ts'.\"),\n repo: z\n .string()\n .optional()\n .describe(\"owner/repo. Defaults to the current working repo.\"),\n limit: z.number().optional().describe(\"Max items per list (default 25).\"),\n },\n async (args) => {\n const repo = resolveRepoArg(args.repo);\n if (!repo)\n return errorResult(\n \"Could not determine repo — pass `repo` (owner/repo).\",\n );\n const api = await getAuthenticatedClient();\n if (!api) return errorResult(\"Not authenticated. Run `fml login`.\");\n return anamnesisResult(\n await api.anamnesisContext(\"path\", {\n repo,\n path: args.path,\n limit: args.limit,\n }),\n );\n },\n );\n\n server.tool(\n \"fml_commit_context\",\n \"Ground-truth context for a commit sha: the PR(s) that contain or merged it, and any revert relationships. Accepts abbreviated shas.\",\n {\n sha: z.string().describe(\"Commit sha (full or abbreviated).\"),\n repo: z\n .string()\n .optional()\n .describe(\"owner/repo. Defaults to the current working repo.\"),\n },\n async (args) => {\n const repo = resolveRepoArg(args.repo);\n if (!repo)\n return errorResult(\n \"Could not determine repo — pass `repo` (owner/repo).\",\n );\n const api = await getAuthenticatedClient();\n if (!api) return errorResult(\"Not authenticated. Run `fml login`.\");\n return anamnesisResult(\n await api.anamnesisContext(\"commit\", { repo, sha: args.sha }),\n );\n },\n );\n\n server.tool(\n \"fml_pr_context\",\n \"Full ground-truth view of a pull request: metadata, commits, changed files, review comments, and derived facts.\",\n {\n number: z.number().describe(\"PR number.\"),\n repo: z\n .string()\n .optional()\n .describe(\"owner/repo. Defaults to the current working repo.\"),\n limit: z.number().optional().describe(\"Max items per list (default 25).\"),\n },\n async (args) => {\n const repo = resolveRepoArg(args.repo);\n if (!repo)\n return errorResult(\n \"Could not determine repo — pass `repo` (owner/repo).\",\n );\n const api = await getAuthenticatedClient();\n if (!api) return errorResult(\"Not authenticated. Run `fml login`.\");\n return anamnesisResult(\n await api.anamnesisContext(\"pr\", {\n repo,\n number: args.number,\n limit: args.limit,\n }),\n );\n },\n );\n\n server.tool(\n \"fml_anamnesis_query\",\n \"Generic query over the anamnesis fact corpus. Filter by predicate (pr_touches_path, pr_contains_commit, pr_merged_as_commit, review_comment_on_path, commit_reverts_commit, pr_reverts_pr) and/or subject/object.\",\n {\n predicate: z.string().optional().describe(\"Fact predicate to filter by.\"),\n subjectKind: z.string().optional(),\n subjectValue: z.string().optional(),\n objectKind: z.string().optional(),\n objectValue: z.string().optional(),\n repo: z\n .string()\n .optional()\n .describe(\"owner/repo. Defaults to the current working repo.\"),\n limit: z.number().optional().describe(\"Max facts (default 25).\"),\n },\n async (args) => {\n const repo = resolveRepoArg(args.repo);\n if (!repo)\n return errorResult(\n \"Could not determine repo — pass `repo` (owner/repo).\",\n );\n const api = await getAuthenticatedClient();\n if (!api) return errorResult(\"Not authenticated. Run `fml login`.\");\n return anamnesisResult(await api.anamnesisQuery({ ...args, repo }));\n },\n );\n}\n"],"mappings":"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","names":["server"]}
|
|
@@ -4,8 +4,7 @@ import {
|
|
|
4
4
|
readTokens,
|
|
5
5
|
setSelectedOrg,
|
|
6
6
|
writeTokens
|
|
7
|
-
} from "./chunk-
|
|
8
|
-
import "./chunk-4YEAQJPF.js";
|
|
7
|
+
} from "./chunk-5BHBYQ2F.js";
|
|
9
8
|
import "./chunk-PZ5AY32C.js";
|
|
10
9
|
export {
|
|
11
10
|
getSelectedOrg,
|
|
@@ -14,4 +13,4 @@ export {
|
|
|
14
13
|
setSelectedOrg,
|
|
15
14
|
writeTokens
|
|
16
15
|
};
|
|
17
|
-
//# sourceMappingURL=token-store-
|
|
16
|
+
//# sourceMappingURL=token-store-T2RNLXRM.js.map
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fml-inc/fml",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.5.0",
|
|
4
4
|
"description": "FML agent tools for Claude Code",
|
|
5
5
|
"license": "SEE LICENSE IN LICENSE",
|
|
6
6
|
"type": "module",
|
|
@@ -36,28 +36,21 @@
|
|
|
36
36
|
"test:watch": "vitest"
|
|
37
37
|
},
|
|
38
38
|
"dependencies": {
|
|
39
|
-
"@fml-inc/panopticon": "^0.2.
|
|
39
|
+
"@fml-inc/panopticon": "^0.2.16",
|
|
40
40
|
"@modelcontextprotocol/sdk": "^1.0.0",
|
|
41
|
-
"better-sqlite3": "^11.0.0",
|
|
42
41
|
"commander": "^13.1.0",
|
|
43
|
-
"convex": "^1.21.0",
|
|
44
|
-
"debug": "^4.4.0",
|
|
45
42
|
"open": "^10.1.0",
|
|
46
43
|
"ora": "^8.2.0",
|
|
47
44
|
"picocolors": "^1.1.1",
|
|
48
|
-
"protobufjs": "^7.0.0",
|
|
49
|
-
"smol-toml": "^1.3.0",
|
|
50
45
|
"zod": "^3.23.0"
|
|
51
46
|
},
|
|
52
47
|
"pnpm": {
|
|
53
48
|
"onlyBuiltDependencies": [
|
|
54
|
-
"better-sqlite3",
|
|
55
49
|
"esbuild"
|
|
56
50
|
]
|
|
57
51
|
},
|
|
58
52
|
"devDependencies": {
|
|
59
53
|
"@sentry/core": "^10.43.0",
|
|
60
|
-
"@types/better-sqlite3": "^7.6.0",
|
|
61
54
|
"@types/node": "^24.0.0",
|
|
62
55
|
"tsup": "^8.0.0",
|
|
63
56
|
"typescript": "^5",
|
package/bin/sync-daemon
DELETED
package/dist/chunk-4YEAQJPF.js
DELETED
|
@@ -1,47 +0,0 @@
|
|
|
1
|
-
// src/dirs.ts
|
|
2
|
-
import fs from "fs";
|
|
3
|
-
import os from "os";
|
|
4
|
-
import path from "path";
|
|
5
|
-
var home = os.homedir();
|
|
6
|
-
function dataDir() {
|
|
7
|
-
switch (process.platform) {
|
|
8
|
-
case "darwin":
|
|
9
|
-
return path.join(home, "Library", "Application Support", "fml");
|
|
10
|
-
case "win32":
|
|
11
|
-
return path.join(
|
|
12
|
-
process.env.APPDATA ?? path.join(home, "AppData", "Roaming"),
|
|
13
|
-
"fml"
|
|
14
|
-
);
|
|
15
|
-
default:
|
|
16
|
-
return path.join(
|
|
17
|
-
process.env.XDG_DATA_HOME ?? path.join(home, ".local", "share"),
|
|
18
|
-
"fml"
|
|
19
|
-
);
|
|
20
|
-
}
|
|
21
|
-
}
|
|
22
|
-
function logDir() {
|
|
23
|
-
switch (process.platform) {
|
|
24
|
-
case "darwin":
|
|
25
|
-
return path.join(home, "Library", "Logs", "fml");
|
|
26
|
-
case "win32":
|
|
27
|
-
return path.join(
|
|
28
|
-
process.env.APPDATA ?? path.join(home, "AppData", "Roaming"),
|
|
29
|
-
"fml",
|
|
30
|
-
"logs"
|
|
31
|
-
);
|
|
32
|
-
default:
|
|
33
|
-
return path.join(
|
|
34
|
-
process.env.XDG_STATE_HOME ?? path.join(home, ".local", "state"),
|
|
35
|
-
"fml",
|
|
36
|
-
"log"
|
|
37
|
-
);
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
var FML_DATA_DIR = dataDir();
|
|
41
|
-
var FML_LOG_DIR = logDir();
|
|
42
|
-
|
|
43
|
-
export {
|
|
44
|
-
FML_DATA_DIR,
|
|
45
|
-
FML_LOG_DIR
|
|
46
|
-
};
|
|
47
|
-
//# sourceMappingURL=chunk-4YEAQJPF.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/dirs.ts"],"sourcesContent":["/**\n * Platform-native directories for FML runtime data.\n *\n * macOS: ~/Library/Application Support/fml + ~/Library/Logs/fml\n * Linux: ~/.local/share/fml + ~/.local/state/fml/log\n * Windows: %APPDATA%/fml + %APPDATA%/fml/logs\n */\nimport fs from \"node:fs\";\nimport os from \"node:os\";\nimport path from \"node:path\";\n\nconst home = os.homedir();\n\nfunction dataDir(): string {\n switch (process.platform) {\n case \"darwin\":\n return path.join(home, \"Library\", \"Application Support\", \"fml\");\n case \"win32\":\n return path.join(\n process.env.APPDATA ?? path.join(home, \"AppData\", \"Roaming\"),\n \"fml\",\n );\n default:\n return path.join(\n process.env.XDG_DATA_HOME ?? path.join(home, \".local\", \"share\"),\n \"fml\",\n );\n }\n}\n\nfunction logDir(): string {\n switch (process.platform) {\n case \"darwin\":\n return path.join(home, \"Library\", \"Logs\", \"fml\");\n case \"win32\":\n return path.join(\n process.env.APPDATA ?? path.join(home, \"AppData\", \"Roaming\"),\n \"fml\",\n \"logs\",\n );\n default:\n return path.join(\n process.env.XDG_STATE_HOME ?? path.join(home, \".local\", \"state\"),\n \"fml\",\n \"log\",\n );\n }\n}\n\n/** Runtime data — SQLite DBs, PID files, config, auth tokens */\nexport const FML_DATA_DIR = dataDir();\n\n/** Log files — daemon logs, MCP logs */\nexport const FML_LOG_DIR = logDir();\n\n/** Ensure both directories exist (called once at startup). */\nexport function ensureDirs(): void {\n fs.mkdirSync(FML_DATA_DIR, { recursive: true, mode: 0o700 });\n fs.mkdirSync(FML_LOG_DIR, { recursive: true, mode: 0o700 });\n}\n"],"mappings":";AAOA,OAAO,QAAQ;AACf,OAAO,QAAQ;AACf,OAAO,UAAU;AAEjB,IAAM,OAAO,GAAG,QAAQ;AAExB,SAAS,UAAkB;AACzB,UAAQ,QAAQ,UAAU;AAAA,IACxB,KAAK;AACH,aAAO,KAAK,KAAK,MAAM,WAAW,uBAAuB,KAAK;AAAA,IAChE,KAAK;AACH,aAAO,KAAK;AAAA,QACV,QAAQ,IAAI,WAAW,KAAK,KAAK,MAAM,WAAW,SAAS;AAAA,QAC3D;AAAA,MACF;AAAA,IACF;AACE,aAAO,KAAK;AAAA,QACV,QAAQ,IAAI,iBAAiB,KAAK,KAAK,MAAM,UAAU,OAAO;AAAA,QAC9D;AAAA,MACF;AAAA,EACJ;AACF;AAEA,SAAS,SAAiB;AACxB,UAAQ,QAAQ,UAAU;AAAA,IACxB,KAAK;AACH,aAAO,KAAK,KAAK,MAAM,WAAW,QAAQ,KAAK;AAAA,IACjD,KAAK;AACH,aAAO,KAAK;AAAA,QACV,QAAQ,IAAI,WAAW,KAAK,KAAK,MAAM,WAAW,SAAS;AAAA,QAC3D;AAAA,QACA;AAAA,MACF;AAAA,IACF;AACE,aAAO,KAAK;AAAA,QACV,QAAQ,IAAI,kBAAkB,KAAK,KAAK,MAAM,UAAU,OAAO;AAAA,QAC/D;AAAA,QACA;AAAA,MACF;AAAA,EACJ;AACF;AAGO,IAAM,eAAe,QAAQ;AAG7B,IAAM,cAAc,OAAO;","names":[]}
|