adaria-ai 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +21 -0
- package/apps.example.yaml +65 -0
- package/dist/agent/audit.d.ts +16 -0
- package/dist/agent/audit.d.ts.map +1 -0
- package/dist/agent/audit.js +42 -0
- package/dist/agent/audit.js.map +1 -0
- package/dist/agent/claude.d.ts +62 -0
- package/dist/agent/claude.d.ts.map +1 -0
- package/dist/agent/claude.js +297 -0
- package/dist/agent/claude.js.map +1 -0
- package/dist/agent/conversation-summary.d.ts +29 -0
- package/dist/agent/conversation-summary.d.ts.map +1 -0
- package/dist/agent/conversation-summary.js +221 -0
- package/dist/agent/conversation-summary.js.map +1 -0
- package/dist/agent/core.d.ts +81 -0
- package/dist/agent/core.d.ts.map +1 -0
- package/dist/agent/core.js +527 -0
- package/dist/agent/core.js.map +1 -0
- package/dist/agent/mcp-launcher.d.ts +42 -0
- package/dist/agent/mcp-launcher.d.ts.map +1 -0
- package/dist/agent/mcp-launcher.js +38 -0
- package/dist/agent/mcp-launcher.js.map +1 -0
- package/dist/agent/mcp-manager.d.ts +81 -0
- package/dist/agent/mcp-manager.d.ts.map +1 -0
- package/dist/agent/mcp-manager.js +136 -0
- package/dist/agent/mcp-manager.js.map +1 -0
- package/dist/agent/memory.d.ts +10 -0
- package/dist/agent/memory.d.ts.map +1 -0
- package/dist/agent/memory.js +95 -0
- package/dist/agent/memory.js.map +1 -0
- package/dist/agent/safety.d.ts +45 -0
- package/dist/agent/safety.d.ts.map +1 -0
- package/dist/agent/safety.js +71 -0
- package/dist/agent/safety.js.map +1 -0
- package/dist/agent/session.d.ts +27 -0
- package/dist/agent/session.d.ts.map +1 -0
- package/dist/agent/session.js +124 -0
- package/dist/agent/session.js.map +1 -0
- package/dist/agent/tool-descriptions.d.ts +8 -0
- package/dist/agent/tool-descriptions.d.ts.map +1 -0
- package/dist/agent/tool-descriptions.js +26 -0
- package/dist/agent/tool-descriptions.js.map +1 -0
- package/dist/cli/analyze.d.ts +8 -0
- package/dist/cli/analyze.d.ts.map +1 -0
- package/dist/cli/analyze.js +114 -0
- package/dist/cli/analyze.js.map +1 -0
- package/dist/cli/daemon.d.ts +2 -0
- package/dist/cli/daemon.d.ts.map +1 -0
- package/dist/cli/daemon.js +91 -0
- package/dist/cli/daemon.js.map +1 -0
- package/dist/cli/doctor.d.ts +2 -0
- package/dist/cli/doctor.d.ts.map +1 -0
- package/dist/cli/doctor.js +198 -0
- package/dist/cli/doctor.js.map +1 -0
- package/dist/cli/init.d.ts +3 -0
- package/dist/cli/init.d.ts.map +1 -0
- package/dist/cli/init.js +459 -0
- package/dist/cli/init.js.map +1 -0
- package/dist/cli/logs.d.ts +4 -0
- package/dist/cli/logs.d.ts.map +1 -0
- package/dist/cli/logs.js +50 -0
- package/dist/cli/logs.js.map +1 -0
- package/dist/cli/monitor-cmd.d.ts +11 -0
- package/dist/cli/monitor-cmd.d.ts.map +1 -0
- package/dist/cli/monitor-cmd.js +59 -0
- package/dist/cli/monitor-cmd.js.map +1 -0
- package/dist/cli/start.d.ts +11 -0
- package/dist/cli/start.d.ts.map +1 -0
- package/dist/cli/start.js +103 -0
- package/dist/cli/start.js.map +1 -0
- package/dist/cli/status.d.ts +9 -0
- package/dist/cli/status.d.ts.map +1 -0
- package/dist/cli/status.js +49 -0
- package/dist/cli/status.js.map +1 -0
- package/dist/cli/stop.d.ts +2 -0
- package/dist/cli/stop.d.ts.map +1 -0
- package/dist/cli/stop.js +34 -0
- package/dist/cli/stop.js.map +1 -0
- package/dist/collectors/appstore.d.ts +51 -0
- package/dist/collectors/appstore.d.ts.map +1 -0
- package/dist/collectors/appstore.js +166 -0
- package/dist/collectors/appstore.js.map +1 -0
- package/dist/collectors/arden-tts.d.ts +60 -0
- package/dist/collectors/arden-tts.d.ts.map +1 -0
- package/dist/collectors/arden-tts.js +83 -0
- package/dist/collectors/arden-tts.js.map +1 -0
- package/dist/collectors/asomobile.d.ts +37 -0
- package/dist/collectors/asomobile.d.ts.map +1 -0
- package/dist/collectors/asomobile.js +88 -0
- package/dist/collectors/asomobile.js.map +1 -0
- package/dist/collectors/eodin-blog.d.ts +90 -0
- package/dist/collectors/eodin-blog.d.ts.map +1 -0
- package/dist/collectors/eodin-blog.js +238 -0
- package/dist/collectors/eodin-blog.js.map +1 -0
- package/dist/collectors/eodin-sdk.d.ts +60 -0
- package/dist/collectors/eodin-sdk.d.ts.map +1 -0
- package/dist/collectors/eodin-sdk.js +112 -0
- package/dist/collectors/eodin-sdk.js.map +1 -0
- package/dist/collectors/fridgify-recipes.d.ts +65 -0
- package/dist/collectors/fridgify-recipes.d.ts.map +1 -0
- package/dist/collectors/fridgify-recipes.js +111 -0
- package/dist/collectors/fridgify-recipes.js.map +1 -0
- package/dist/collectors/playstore.d.ts +46 -0
- package/dist/collectors/playstore.d.ts.map +1 -0
- package/dist/collectors/playstore.js +140 -0
- package/dist/collectors/playstore.js.map +1 -0
- package/dist/collectors/youtube.d.ts +44 -0
- package/dist/collectors/youtube.d.ts.map +1 -0
- package/dist/collectors/youtube.js +107 -0
- package/dist/collectors/youtube.js.map +1 -0
- package/dist/config/apps-schema.d.ts +94 -0
- package/dist/config/apps-schema.d.ts.map +1 -0
- package/dist/config/apps-schema.js +66 -0
- package/dist/config/apps-schema.js.map +1 -0
- package/dist/config/keychain.d.ts +14 -0
- package/dist/config/keychain.d.ts.map +1 -0
- package/dist/config/keychain.js +89 -0
- package/dist/config/keychain.js.map +1 -0
- package/dist/config/load-apps.d.ts +16 -0
- package/dist/config/load-apps.d.ts.map +1 -0
- package/dist/config/load-apps.js +38 -0
- package/dist/config/load-apps.js.map +1 -0
- package/dist/config/schema.d.ts +306 -0
- package/dist/config/schema.d.ts.map +1 -0
- package/dist/config/schema.js +220 -0
- package/dist/config/schema.js.map +1 -0
- package/dist/config/store.d.ts +38 -0
- package/dist/config/store.d.ts.map +1 -0
- package/dist/config/store.js +180 -0
- package/dist/config/store.js.map +1 -0
- package/dist/db/queries.d.ts +304 -0
- package/dist/db/queries.d.ts.map +1 -0
- package/dist/db/queries.js +327 -0
- package/dist/db/queries.js.map +1 -0
- package/dist/db/schema.d.ts +15 -0
- package/dist/db/schema.d.ts.map +1 -0
- package/dist/db/schema.js +252 -0
- package/dist/db/schema.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +86 -0
- package/dist/index.js.map +1 -0
- package/dist/messenger/adapter.d.ts +63 -0
- package/dist/messenger/adapter.d.ts.map +1 -0
- package/dist/messenger/adapter.js +7 -0
- package/dist/messenger/adapter.js.map +1 -0
- package/dist/messenger/factory.d.ts +12 -0
- package/dist/messenger/factory.d.ts.map +1 -0
- package/dist/messenger/factory.js +9 -0
- package/dist/messenger/factory.js.map +1 -0
- package/dist/messenger/slack.d.ts +30 -0
- package/dist/messenger/slack.d.ts.map +1 -0
- package/dist/messenger/slack.js +309 -0
- package/dist/messenger/slack.js.map +1 -0
- package/dist/messenger/split.d.ts +17 -0
- package/dist/messenger/split.d.ts.map +1 -0
- package/dist/messenger/split.js +56 -0
- package/dist/messenger/split.js.map +1 -0
- package/dist/orchestrator/dashboard.d.ts +67 -0
- package/dist/orchestrator/dashboard.d.ts.map +1 -0
- package/dist/orchestrator/dashboard.js +113 -0
- package/dist/orchestrator/dashboard.js.map +1 -0
- package/dist/orchestrator/monitor.d.ts +37 -0
- package/dist/orchestrator/monitor.d.ts.map +1 -0
- package/dist/orchestrator/monitor.js +236 -0
- package/dist/orchestrator/monitor.js.map +1 -0
- package/dist/orchestrator/types.d.ts +82 -0
- package/dist/orchestrator/types.d.ts.map +1 -0
- package/dist/orchestrator/types.js +12 -0
- package/dist/orchestrator/types.js.map +1 -0
- package/dist/orchestrator/weekly.d.ts +66 -0
- package/dist/orchestrator/weekly.d.ts.map +1 -0
- package/dist/orchestrator/weekly.js +376 -0
- package/dist/orchestrator/weekly.js.map +1 -0
- package/dist/prompts/loader.d.ts +18 -0
- package/dist/prompts/loader.d.ts.map +1 -0
- package/dist/prompts/loader.js +28 -0
- package/dist/prompts/loader.js.map +1 -0
- package/dist/security/auth.d.ts +14 -0
- package/dist/security/auth.d.ts.map +1 -0
- package/dist/security/auth.js +14 -0
- package/dist/security/auth.js.map +1 -0
- package/dist/security/prompt-guard.d.ts +21 -0
- package/dist/security/prompt-guard.d.ts.map +1 -0
- package/dist/security/prompt-guard.js +54 -0
- package/dist/security/prompt-guard.js.map +1 -0
- package/dist/skills/aso.d.ts +60 -0
- package/dist/skills/aso.d.ts.map +1 -0
- package/dist/skills/aso.js +322 -0
- package/dist/skills/aso.js.map +1 -0
- package/dist/skills/content.d.ts +25 -0
- package/dist/skills/content.d.ts.map +1 -0
- package/dist/skills/content.js +90 -0
- package/dist/skills/content.js.map +1 -0
- package/dist/skills/index.d.ts +65 -0
- package/dist/skills/index.d.ts.map +1 -0
- package/dist/skills/index.js +90 -0
- package/dist/skills/index.js.map +1 -0
- package/dist/skills/onboarding.d.ts +58 -0
- package/dist/skills/onboarding.d.ts.map +1 -0
- package/dist/skills/onboarding.js +274 -0
- package/dist/skills/onboarding.js.map +1 -0
- package/dist/skills/registry.d.ts +24 -0
- package/dist/skills/registry.d.ts.map +1 -0
- package/dist/skills/registry.js +66 -0
- package/dist/skills/registry.js.map +1 -0
- package/dist/skills/review.d.ts +33 -0
- package/dist/skills/review.d.ts.map +1 -0
- package/dist/skills/review.js +236 -0
- package/dist/skills/review.js.map +1 -0
- package/dist/skills/sdk-request.d.ts +30 -0
- package/dist/skills/sdk-request.d.ts.map +1 -0
- package/dist/skills/sdk-request.js +72 -0
- package/dist/skills/sdk-request.js.map +1 -0
- package/dist/skills/seo-blog.d.ts +64 -0
- package/dist/skills/seo-blog.d.ts.map +1 -0
- package/dist/skills/seo-blog.js +268 -0
- package/dist/skills/seo-blog.js.map +1 -0
- package/dist/skills/short-form.d.ts +28 -0
- package/dist/skills/short-form.d.ts.map +1 -0
- package/dist/skills/short-form.js +121 -0
- package/dist/skills/short-form.js.map +1 -0
- package/dist/skills/social-publish.d.ts +32 -0
- package/dist/skills/social-publish.d.ts.map +1 -0
- package/dist/skills/social-publish.js +133 -0
- package/dist/skills/social-publish.js.map +1 -0
- package/dist/social/base.d.ts +47 -0
- package/dist/social/base.d.ts.map +1 -0
- package/dist/social/base.js +26 -0
- package/dist/social/base.js.map +1 -0
- package/dist/social/facebook.d.ts +27 -0
- package/dist/social/facebook.d.ts.map +1 -0
- package/dist/social/facebook.js +166 -0
- package/dist/social/facebook.js.map +1 -0
- package/dist/social/factory.d.ts +26 -0
- package/dist/social/factory.d.ts.map +1 -0
- package/dist/social/factory.js +32 -0
- package/dist/social/factory.js.map +1 -0
- package/dist/social/linkedin.d.ts +26 -0
- package/dist/social/linkedin.d.ts.map +1 -0
- package/dist/social/linkedin.js +190 -0
- package/dist/social/linkedin.js.map +1 -0
- package/dist/social/threads.d.ts +21 -0
- package/dist/social/threads.d.ts.map +1 -0
- package/dist/social/threads.js +122 -0
- package/dist/social/threads.js.map +1 -0
- package/dist/social/tiktok.d.ts +23 -0
- package/dist/social/tiktok.d.ts.map +1 -0
- package/dist/social/tiktok.js +110 -0
- package/dist/social/tiktok.js.map +1 -0
- package/dist/social/twitter.d.ts +30 -0
- package/dist/social/twitter.d.ts.map +1 -0
- package/dist/social/twitter.js +189 -0
- package/dist/social/twitter.js.map +1 -0
- package/dist/social/youtube.d.ts +21 -0
- package/dist/social/youtube.d.ts.map +1 -0
- package/dist/social/youtube.js +108 -0
- package/dist/social/youtube.js.map +1 -0
- package/dist/tools/app-info.d.ts +7 -0
- package/dist/tools/app-info.d.ts.map +1 -0
- package/dist/tools/app-info.js +53 -0
- package/dist/tools/app-info.js.map +1 -0
- package/dist/tools/collector-fetch.d.ts +11 -0
- package/dist/tools/collector-fetch.d.ts.map +1 -0
- package/dist/tools/collector-fetch.js +101 -0
- package/dist/tools/collector-fetch.js.map +1 -0
- package/dist/tools/db-query.d.ts +29 -0
- package/dist/tools/db-query.d.ts.map +1 -0
- package/dist/tools/db-query.js +159 -0
- package/dist/tools/db-query.js.map +1 -0
- package/dist/tools/skill-result.d.ts +8 -0
- package/dist/tools/skill-result.d.ts.map +1 -0
- package/dist/tools/skill-result.js +63 -0
- package/dist/tools/skill-result.js.map +1 -0
- package/dist/tools/tool-host.d.ts +12 -0
- package/dist/tools/tool-host.d.ts.map +1 -0
- package/dist/tools/tool-host.js +124 -0
- package/dist/tools/tool-host.js.map +1 -0
- package/dist/types/collectors.d.ts +198 -0
- package/dist/types/collectors.d.ts.map +1 -0
- package/dist/types/collectors.js +28 -0
- package/dist/types/collectors.js.map +1 -0
- package/dist/types/skill.d.ts +60 -0
- package/dist/types/skill.d.ts.map +1 -0
- package/dist/types/skill.js +9 -0
- package/dist/types/skill.js.map +1 -0
- package/dist/utils/circuit-breaker.d.ts +26 -0
- package/dist/utils/circuit-breaker.d.ts.map +1 -0
- package/dist/utils/circuit-breaker.js +67 -0
- package/dist/utils/circuit-breaker.js.map +1 -0
- package/dist/utils/errors.d.ts +44 -0
- package/dist/utils/errors.d.ts.map +1 -0
- package/dist/utils/errors.js +75 -0
- package/dist/utils/errors.js.map +1 -0
- package/dist/utils/escape.d.ts +11 -0
- package/dist/utils/escape.d.ts.map +1 -0
- package/dist/utils/escape.js +19 -0
- package/dist/utils/escape.js.map +1 -0
- package/dist/utils/logger.d.ts +19 -0
- package/dist/utils/logger.d.ts.map +1 -0
- package/dist/utils/logger.js +93 -0
- package/dist/utils/logger.js.map +1 -0
- package/dist/utils/parse-json.d.ts +13 -0
- package/dist/utils/parse-json.d.ts.map +1 -0
- package/dist/utils/parse-json.js +61 -0
- package/dist/utils/parse-json.js.map +1 -0
- package/dist/utils/paths.d.ts +14 -0
- package/dist/utils/paths.d.ts.map +1 -0
- package/dist/utils/paths.js +19 -0
- package/dist/utils/paths.js.map +1 -0
- package/dist/utils/rate-limiter.d.ts +20 -0
- package/dist/utils/rate-limiter.d.ts.map +1 -0
- package/dist/utils/rate-limiter.js +47 -0
- package/dist/utils/rate-limiter.js.map +1 -0
- package/dist/utils/retry.d.ts +26 -0
- package/dist/utils/retry.d.ts.map +1 -0
- package/dist/utils/retry.js +61 -0
- package/dist/utils/retry.js.map +1 -0
- package/launchd/.gitkeep +0 -0
- package/launchd/com.adaria-ai.daemon.plist.template +62 -0
- package/launchd/com.adaria-ai.monitor.plist.template +41 -0
- package/launchd/com.adaria-ai.weekly.plist.template +43 -0
- package/package.json +72 -0
- package/prompts/aso-description.md +44 -0
- package/prompts/aso-inapp-events.md +20 -0
- package/prompts/aso-metadata.md +34 -0
- package/prompts/aso-screenshots.md +20 -0
- package/prompts/onboarding-hypotheses.md +38 -0
- package/prompts/onboarding-review-timing.md +24 -0
- package/prompts/review-clustering.md +19 -0
- package/prompts/review-replies.md +18 -0
- package/prompts/review-sentiment.md +16 -0
- package/prompts/seo-blog-fridgify-recipe.md +116 -0
- package/prompts/seo-blog.md +69 -0
- package/prompts/short-form-ideas.md +50 -0
- package/prompts/social-publish.md +46 -0
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* app-info MCP tool — read parsed apps.yaml metadata.
|
|
3
|
+
*/
|
|
4
|
+
import type { AppConfig } from "../config/apps-schema.js";
|
|
5
|
+
import type { McpToolImplementation } from "../agent/mcp-manager.js";
|
|
6
|
+
export declare function createAppInfoTool(apps: AppConfig[]): McpToolImplementation;
|
|
7
|
+
//# sourceMappingURL=app-info.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"app-info.d.ts","sourceRoot":"","sources":["../../src/tools/app-info.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,0BAA0B,CAAC;AAC1D,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,yBAAyB,CAAC;AAErE,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,SAAS,EAAE,GAAG,qBAAqB,CAoD1E"}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* app-info MCP tool — read parsed apps.yaml metadata.
|
|
3
|
+
*/
|
|
4
|
+
export function createAppInfoTool(apps) {
|
|
5
|
+
return {
|
|
6
|
+
id: "app-info",
|
|
7
|
+
name: "App Info",
|
|
8
|
+
description: "Read app metadata from apps.yaml. Call with no arguments to list all apps, " +
|
|
9
|
+
"or pass an app ID to get detailed config for a specific app. " +
|
|
10
|
+
"Returns: id, name, platforms, store IDs, keywords, competitors, locale, features.",
|
|
11
|
+
inputSchema: {
|
|
12
|
+
type: "object",
|
|
13
|
+
properties: {
|
|
14
|
+
app: {
|
|
15
|
+
type: "string",
|
|
16
|
+
description: "App ID to look up. Omit to list all apps.",
|
|
17
|
+
},
|
|
18
|
+
},
|
|
19
|
+
},
|
|
20
|
+
handler: (input) => {
|
|
21
|
+
const obj = (input ?? {});
|
|
22
|
+
const appId = typeof obj["app"] === "string" ? obj["app"].toLowerCase() : undefined;
|
|
23
|
+
if (!appId) {
|
|
24
|
+
return Promise.resolve({
|
|
25
|
+
appCount: apps.length,
|
|
26
|
+
apps: apps.map((a) => ({
|
|
27
|
+
id: a.id,
|
|
28
|
+
name: a.name,
|
|
29
|
+
platform: a.platform,
|
|
30
|
+
active: a.active,
|
|
31
|
+
})),
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
const app = apps.find((a) => a.id.toLowerCase() === appId);
|
|
35
|
+
if (!app) {
|
|
36
|
+
return Promise.resolve({ error: `App "${appId}" not found. Available: ${apps.map((a) => a.id).join(", ")}` });
|
|
37
|
+
}
|
|
38
|
+
return Promise.resolve({
|
|
39
|
+
id: app.id,
|
|
40
|
+
name: app.name,
|
|
41
|
+
platform: app.platform,
|
|
42
|
+
appStoreId: app.appStoreId,
|
|
43
|
+
playStorePackage: app.playStorePackage,
|
|
44
|
+
primaryKeywords: app.primaryKeywords,
|
|
45
|
+
competitors: app.competitors,
|
|
46
|
+
locale: app.locale,
|
|
47
|
+
features: app.features,
|
|
48
|
+
active: app.active,
|
|
49
|
+
});
|
|
50
|
+
},
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
//# sourceMappingURL=app-info.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"app-info.js","sourceRoot":"","sources":["../../src/tools/app-info.ts"],"names":[],"mappings":"AAAA;;GAEG;AAKH,MAAM,UAAU,iBAAiB,CAAC,IAAiB;IACjD,OAAO;QACL,EAAE,EAAE,UAAU;QACd,IAAI,EAAE,UAAU;QAChB,WAAW,EACT,6EAA6E;YAC7E,+DAA+D;YAC/D,mFAAmF;QACrF,WAAW,EAAE;YACX,IAAI,EAAE,QAAQ;YACd,UAAU,EAAE;gBACV,GAAG,EAAE;oBACH,IAAI,EAAE,QAAQ;oBACd,WAAW,EAAE,2CAA2C;iBACzD;aACF;SACF;QACD,OAAO,EAAE,CAAC,KAAc,EAAoB,EAAE;YAC5C,MAAM,GAAG,GAAG,CAAC,KAAK,IAAI,EAAE,CAA4B,CAAC;YACrD,MAAM,KAAK,GAAG,OAAO,GAAG,CAAC,KAAK,CAAC,KAAK,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC;YAEpF,IAAI,CAAC,KAAK,EAAE,CAAC;gBACX,OAAO,OAAO,CAAC,OAAO,CAAC;oBACrB,QAAQ,EAAE,IAAI,CAAC,MAAM;oBACrB,IAAI,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;wBACrB,EAAE,EAAE,CAAC,CAAC,EAAE;wBACR,IAAI,EAAE,CAAC,CAAC,IAAI;wBACZ,QAAQ,EAAE,CAAC,CAAC,QAAQ;wBACpB,MAAM,EAAE,CAAC,CAAC,MAAM;qBACjB,CAAC,CAAC;iBACJ,CAAC,CAAC;YACL,CAAC;YAED,MAAM,GAAG,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,WAAW,EAAE,KAAK,KAAK,CAAC,CAAC;YAC3D,IAAI,CAAC,GAAG,EAAE,CAAC;gBACT,OAAO,OAAO,CAAC,OAAO,CAAC,EAAE,KAAK,EAAE,QAAQ,KAAK,2BAA2B,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,EAAE,CAAC,CAAC;YAChH,CAAC;YAED,OAAO,OAAO,CAAC,OAAO,CAAC;gBACrB,EAAE,EAAE,GAAG,CAAC,EAAE;gBACV,IAAI,EAAE,GAAG,CAAC,IAAI;gBACd,QAAQ,EAAE,GAAG,CAAC,QAAQ;gBACtB,UAAU,EAAE,GAAG,CAAC,UAAU;gBAC1B,gBAAgB,EAAE,GAAG,CAAC,gBAAgB;gBACtC,eAAe,EAAE,GAAG,CAAC,eAAe;gBACpC,WAAW,EAAE,GAAG,CAAC,WAAW;gBAC5B,MAAM,EAAE,GAAG,CAAC,MAAM;gBAClB,QAAQ,EAAE,GAAG,CAAC,QAAQ;gBACtB,MAAM,EAAE,GAAG,CAAC,MAAM;aACnB,CAAC,CAAC;QACL,CAAC;KACF,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* collector-fetch MCP tool — cache-aware collector data retrieval.
|
|
3
|
+
*
|
|
4
|
+
* Returns the latest data from a named collector for a given app.
|
|
5
|
+
* In M5.5, this queries the DB for cached data. Fresh API calls
|
|
6
|
+
* are deferred to the orchestrator (M6).
|
|
7
|
+
*/
|
|
8
|
+
import type Database from "better-sqlite3";
|
|
9
|
+
import type { McpToolImplementation } from "../agent/mcp-manager.js";
|
|
10
|
+
export declare function createCollectorFetchTool(db: Database.Database): McpToolImplementation;
|
|
11
|
+
//# sourceMappingURL=collector-fetch.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"collector-fetch.d.ts","sourceRoot":"","sources":["../../src/tools/collector-fetch.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,QAAQ,MAAM,gBAAgB,CAAC;AAC3C,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,yBAAyB,CAAC;AAoErE,wBAAgB,wBAAwB,CAAC,EAAE,EAAE,QAAQ,CAAC,QAAQ,GAAG,qBAAqB,CAkDrF"}
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* collector-fetch MCP tool — cache-aware collector data retrieval.
|
|
3
|
+
*
|
|
4
|
+
* Returns the latest data from a named collector for a given app.
|
|
5
|
+
* In M5.5, this queries the DB for cached data. Fresh API calls
|
|
6
|
+
* are deferred to the orchestrator (M6).
|
|
7
|
+
*/
|
|
8
|
+
import { getRecentKeywordRankings, getRecentReviews, getSentimentSummary, getRecentShortFormPerformance, getSeoMetricsByRange, getWebTrafficByRange, getRecentBlogPosts, } from "../db/queries.js";
|
|
9
|
+
const ALLOWED_COLLECTORS = [
|
|
10
|
+
"keyword-rankings",
|
|
11
|
+
"reviews",
|
|
12
|
+
"sentiment",
|
|
13
|
+
"short-form",
|
|
14
|
+
"seo-metrics",
|
|
15
|
+
"web-traffic",
|
|
16
|
+
"blog-posts",
|
|
17
|
+
];
|
|
18
|
+
const MAX_OUTPUT_BYTES = 10_240;
|
|
19
|
+
function truncateArray(data) {
|
|
20
|
+
let result = data;
|
|
21
|
+
while (result.length > 0) {
|
|
22
|
+
if (JSON.stringify(result).length <= MAX_OUTPUT_BYTES)
|
|
23
|
+
return result;
|
|
24
|
+
result = result.slice(0, Math.max(1, result.length - 1));
|
|
25
|
+
}
|
|
26
|
+
return result;
|
|
27
|
+
}
|
|
28
|
+
/** Strip review body text to prevent PII leaks to Slack. */
|
|
29
|
+
function redactReviews(rows) {
|
|
30
|
+
return rows.map((r) => ({ ...r, body: "[redacted]", reply_draft: "[redacted]" }));
|
|
31
|
+
}
|
|
32
|
+
function fetchCollectorData(db, collector, appId, days) {
|
|
33
|
+
const now = new Date();
|
|
34
|
+
const startDate = new Date(now.getTime() - days * 86_400_000).toISOString().slice(0, 10);
|
|
35
|
+
const endDate = now.toISOString().slice(0, 10);
|
|
36
|
+
switch (collector) {
|
|
37
|
+
case "keyword-rankings":
|
|
38
|
+
return getRecentKeywordRankings(db, appId, days);
|
|
39
|
+
case "reviews":
|
|
40
|
+
return redactReviews(getRecentReviews(db, appId, days));
|
|
41
|
+
case "sentiment":
|
|
42
|
+
return getSentimentSummary(db, appId, days);
|
|
43
|
+
case "short-form":
|
|
44
|
+
return getRecentShortFormPerformance(db, appId, days);
|
|
45
|
+
case "seo-metrics":
|
|
46
|
+
return getSeoMetricsByRange(db, startDate, endDate);
|
|
47
|
+
case "web-traffic":
|
|
48
|
+
return getWebTrafficByRange(db, startDate, endDate);
|
|
49
|
+
case "blog-posts":
|
|
50
|
+
return getRecentBlogPosts(db, appId, days);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
export function createCollectorFetchTool(db) {
|
|
54
|
+
return {
|
|
55
|
+
id: "collector-fetch",
|
|
56
|
+
name: "Collector Fetch",
|
|
57
|
+
description: "Fetch cached marketing data from the database for a specific app. " +
|
|
58
|
+
"Available collectors: " + ALLOWED_COLLECTORS.join(", ") + ". " +
|
|
59
|
+
"Review body text is redacted for privacy. " +
|
|
60
|
+
"seo-metrics and web-traffic are site-wide (no app_id filter). " +
|
|
61
|
+
"Use `days` to control the time window (default 7).",
|
|
62
|
+
inputSchema: {
|
|
63
|
+
type: "object",
|
|
64
|
+
required: ["collector", "app"],
|
|
65
|
+
properties: {
|
|
66
|
+
collector: {
|
|
67
|
+
type: "string",
|
|
68
|
+
enum: [...ALLOWED_COLLECTORS],
|
|
69
|
+
description: "Which collector data to fetch.",
|
|
70
|
+
},
|
|
71
|
+
app: {
|
|
72
|
+
type: "string",
|
|
73
|
+
description: "App ID from apps.yaml (e.g. 'fridgify').",
|
|
74
|
+
},
|
|
75
|
+
days: {
|
|
76
|
+
type: "number",
|
|
77
|
+
description: "Number of days to look back (default 7, max 90).",
|
|
78
|
+
},
|
|
79
|
+
},
|
|
80
|
+
},
|
|
81
|
+
handler: (input) => {
|
|
82
|
+
if (!input || typeof input !== "object") {
|
|
83
|
+
return Promise.resolve({ error: "Input must be an object with `collector` and `app` fields." });
|
|
84
|
+
}
|
|
85
|
+
const obj = input;
|
|
86
|
+
if (typeof obj["collector"] !== "string" || typeof obj["app"] !== "string") {
|
|
87
|
+
return Promise.resolve({ error: "Missing required fields: `collector` (string) and `app` (string)." });
|
|
88
|
+
}
|
|
89
|
+
const collector = obj["collector"];
|
|
90
|
+
const appId = obj["app"];
|
|
91
|
+
const days = Math.min(typeof obj["days"] === "number" ? obj["days"] : 7, 90);
|
|
92
|
+
if (!ALLOWED_COLLECTORS.includes(collector)) {
|
|
93
|
+
return Promise.resolve({ error: `Unknown collector: "${collector}". Allowed: ${ALLOWED_COLLECTORS.join(", ")}` });
|
|
94
|
+
}
|
|
95
|
+
const data = fetchCollectorData(db, collector, appId, days);
|
|
96
|
+
const result = Array.isArray(data) ? truncateArray(data) : data;
|
|
97
|
+
return Promise.resolve(result);
|
|
98
|
+
},
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
//# sourceMappingURL=collector-fetch.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"collector-fetch.js","sourceRoot":"","sources":["../../src/tools/collector-fetch.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* db-query MCP tool — read-only access to whitelisted SQLite tables.
|
|
3
|
+
*
|
|
4
|
+
* Strictly read-only: SELECT only, no write paths. Table whitelist is
|
|
5
|
+
* enforced at the tool level, not trust-based.
|
|
6
|
+
*/
|
|
7
|
+
import type Database from "better-sqlite3";
|
|
8
|
+
import type { McpToolImplementation } from "../agent/mcp-manager.js";
|
|
9
|
+
interface DbQueryInput {
|
|
10
|
+
table: string;
|
|
11
|
+
where?: Record<string, unknown> | undefined;
|
|
12
|
+
orderBy?: string | undefined;
|
|
13
|
+
limit?: number | undefined;
|
|
14
|
+
}
|
|
15
|
+
declare function validateInput(input: unknown): DbQueryInput;
|
|
16
|
+
declare function buildQuery(params: DbQueryInput): {
|
|
17
|
+
sql: string;
|
|
18
|
+
bindings: unknown[];
|
|
19
|
+
};
|
|
20
|
+
export declare function createDbQueryTool(db: Database.Database): McpToolImplementation;
|
|
21
|
+
/** Exported for testing. */
|
|
22
|
+
export declare const _test: {
|
|
23
|
+
ALLOWED_TABLES: Set<string>;
|
|
24
|
+
REDACTED_COLUMNS: Record<string, Set<string>>;
|
|
25
|
+
validateInput: typeof validateInput;
|
|
26
|
+
buildQuery: typeof buildQuery;
|
|
27
|
+
};
|
|
28
|
+
export {};
|
|
29
|
+
//# sourceMappingURL=db-query.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"db-query.d.ts","sourceRoot":"","sources":["../../src/tools/db-query.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,QAAQ,MAAM,gBAAgB,CAAC;AAC3C,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,yBAAyB,CAAC;AA4BrE,UAAU,YAAY;IACpB,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,CAAC;IAC5C,OAAO,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC7B,KAAK,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CAC5B;AAED,iBAAS,aAAa,CAAC,KAAK,EAAE,OAAO,GAAG,YAAY,CAgBnD;AAED,iBAAS,UAAU,CAAC,MAAM,EAAE,YAAY,GAAG;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,OAAO,EAAE,CAAA;CAAE,CA6C9E;AA6BD,wBAAgB,iBAAiB,CAAC,EAAE,EAAE,QAAQ,CAAC,QAAQ,GAAG,qBAAqB,CA6C9E;AAED,4BAA4B;AAC5B,eAAO,MAAM,KAAK;;;;;CAAkE,CAAC"}
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* db-query MCP tool — read-only access to whitelisted SQLite tables.
|
|
3
|
+
*
|
|
4
|
+
* Strictly read-only: SELECT only, no write paths. Table whitelist is
|
|
5
|
+
* enforced at the tool level, not trust-based.
|
|
6
|
+
*/
|
|
7
|
+
const MAX_ROWS = 50;
|
|
8
|
+
const MAX_OUTPUT_BYTES = 10_240; // 10 KB
|
|
9
|
+
/** Tables Claude is allowed to query. Anything not in this set is rejected. */
|
|
10
|
+
const ALLOWED_TABLES = new Set([
|
|
11
|
+
"keyword_rankings",
|
|
12
|
+
"sdk_events",
|
|
13
|
+
"reviews",
|
|
14
|
+
"approvals",
|
|
15
|
+
"competitor_metadata",
|
|
16
|
+
"agent_metrics",
|
|
17
|
+
"blog_posts",
|
|
18
|
+
"short_form_performance",
|
|
19
|
+
"seo_metrics",
|
|
20
|
+
"web_traffic",
|
|
21
|
+
"blog_performance",
|
|
22
|
+
"social_posts",
|
|
23
|
+
]);
|
|
24
|
+
/** Columns that must never be returned — contains raw user-authored text
|
|
25
|
+
* that could carry prompt injection or PII. */
|
|
26
|
+
const REDACTED_COLUMNS = {
|
|
27
|
+
reviews: new Set(["body", "reply_draft"]),
|
|
28
|
+
competitor_metadata: new Set(["description"]),
|
|
29
|
+
};
|
|
30
|
+
function validateInput(input) {
|
|
31
|
+
if (!input || typeof input !== "object") {
|
|
32
|
+
throw new Error("Input must be an object with a `table` field.");
|
|
33
|
+
}
|
|
34
|
+
const obj = input;
|
|
35
|
+
if (typeof obj["table"] !== "string") {
|
|
36
|
+
throw new Error("Missing required field: `table`.");
|
|
37
|
+
}
|
|
38
|
+
return {
|
|
39
|
+
table: obj["table"],
|
|
40
|
+
where: typeof obj["where"] === "object" && obj["where"] !== null
|
|
41
|
+
? obj["where"]
|
|
42
|
+
: undefined,
|
|
43
|
+
orderBy: typeof obj["orderBy"] === "string" ? obj["orderBy"] : undefined,
|
|
44
|
+
limit: typeof obj["limit"] === "number" ? obj["limit"] : undefined,
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
function buildQuery(params) {
|
|
48
|
+
if (!ALLOWED_TABLES.has(params.table)) {
|
|
49
|
+
throw new Error(`Table "${params.table}" is not in the whitelist. Allowed: ${[...ALLOWED_TABLES].join(", ")}`);
|
|
50
|
+
}
|
|
51
|
+
// Determine which columns to select (exclude redacted ones)
|
|
52
|
+
const redacted = REDACTED_COLUMNS[params.table];
|
|
53
|
+
let selectClause = "*";
|
|
54
|
+
if (redacted) {
|
|
55
|
+
// We need to know actual columns — use a safe approach: SELECT all
|
|
56
|
+
// then strip in post-processing. But for safety, we document that
|
|
57
|
+
// the redaction happens at the result level.
|
|
58
|
+
selectClause = "*";
|
|
59
|
+
}
|
|
60
|
+
const parts = [`SELECT ${selectClause} FROM ${params.table}`];
|
|
61
|
+
const bindings = [];
|
|
62
|
+
if (params.where && Object.keys(params.where).length > 0) {
|
|
63
|
+
const conditions = [];
|
|
64
|
+
for (const [key, value] of Object.entries(params.where)) {
|
|
65
|
+
// Validate column name: letters, digits, underscores only
|
|
66
|
+
if (!/^[a-zA-Z_]\w*$/.test(key)) {
|
|
67
|
+
throw new Error(`Invalid column name in where clause: "${key}"`);
|
|
68
|
+
}
|
|
69
|
+
conditions.push(`${key} = ?`);
|
|
70
|
+
bindings.push(value);
|
|
71
|
+
}
|
|
72
|
+
parts.push("WHERE " + conditions.join(" AND "));
|
|
73
|
+
}
|
|
74
|
+
if (params.orderBy) {
|
|
75
|
+
// Validate: column name optionally followed by ASC/DESC
|
|
76
|
+
if (!/^[a-zA-Z_]\w*(?:\s+(?:ASC|DESC))?$/i.test(params.orderBy)) {
|
|
77
|
+
throw new Error(`Invalid orderBy: "${params.orderBy}". Use "column_name" or "column_name DESC".`);
|
|
78
|
+
}
|
|
79
|
+
parts.push(`ORDER BY ${params.orderBy}`);
|
|
80
|
+
}
|
|
81
|
+
const limit = Math.min(params.limit ?? MAX_ROWS, MAX_ROWS);
|
|
82
|
+
parts.push(`LIMIT ${String(limit)}`);
|
|
83
|
+
return { sql: parts.join(" "), bindings };
|
|
84
|
+
}
|
|
85
|
+
function redactRows(table, rows) {
|
|
86
|
+
const redacted = REDACTED_COLUMNS[table];
|
|
87
|
+
if (!redacted)
|
|
88
|
+
return rows;
|
|
89
|
+
return rows.map((row) => {
|
|
90
|
+
const clean = { ...row };
|
|
91
|
+
for (const col of redacted) {
|
|
92
|
+
if (col in clean) {
|
|
93
|
+
clean[col] = "[redacted]";
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
return clean;
|
|
97
|
+
});
|
|
98
|
+
}
|
|
99
|
+
/** Truncate rows to stay under output byte limit. Removes rows from
|
|
100
|
+
* the end until the JSON representation fits. */
|
|
101
|
+
function truncateRows(rows) {
|
|
102
|
+
let result = rows;
|
|
103
|
+
while (result.length > 0) {
|
|
104
|
+
const json = JSON.stringify(result);
|
|
105
|
+
if (json.length <= MAX_OUTPUT_BYTES)
|
|
106
|
+
return result;
|
|
107
|
+
result = result.slice(0, Math.max(1, result.length - 1));
|
|
108
|
+
}
|
|
109
|
+
return result;
|
|
110
|
+
}
|
|
111
|
+
export function createDbQueryTool(db) {
|
|
112
|
+
return {
|
|
113
|
+
id: "db-query",
|
|
114
|
+
name: "Database Query",
|
|
115
|
+
description: "Query the adaria-ai marketing database. Read-only SELECT on whitelisted tables: " +
|
|
116
|
+
[...ALLOWED_TABLES].join(", ") +
|
|
117
|
+
". Review body text and competitor descriptions are redacted. " +
|
|
118
|
+
"Use this to answer questions about keyword rankings, reviews (counts/ratings only), " +
|
|
119
|
+
"SDK events, blog posts, and performance metrics. Max 50 rows / 10KB output.",
|
|
120
|
+
inputSchema: {
|
|
121
|
+
type: "object",
|
|
122
|
+
required: ["table"],
|
|
123
|
+
properties: {
|
|
124
|
+
table: {
|
|
125
|
+
type: "string",
|
|
126
|
+
enum: [...ALLOWED_TABLES],
|
|
127
|
+
description: "The table to query.",
|
|
128
|
+
},
|
|
129
|
+
where: {
|
|
130
|
+
type: "object",
|
|
131
|
+
description: "Column equality filters, e.g. { app_id: 'fridgify', platform: 'ios' }",
|
|
132
|
+
},
|
|
133
|
+
orderBy: {
|
|
134
|
+
type: "string",
|
|
135
|
+
description: 'Column to sort by, optionally with ASC/DESC, e.g. "recorded_at DESC"',
|
|
136
|
+
},
|
|
137
|
+
limit: {
|
|
138
|
+
type: "number",
|
|
139
|
+
description: "Maximum rows to return (capped at 50).",
|
|
140
|
+
},
|
|
141
|
+
},
|
|
142
|
+
},
|
|
143
|
+
handler: (input) => {
|
|
144
|
+
try {
|
|
145
|
+
const params = validateInput(input);
|
|
146
|
+
const { sql, bindings } = buildQuery(params);
|
|
147
|
+
const rows = db.prepare(sql).all(...bindings);
|
|
148
|
+
const redactedRows = redactRows(params.table, rows);
|
|
149
|
+
return Promise.resolve({ rowCount: redactedRows.length, rows: truncateRows(redactedRows) });
|
|
150
|
+
}
|
|
151
|
+
catch (err) {
|
|
152
|
+
return Promise.resolve({ error: err instanceof Error ? err.message : String(err) });
|
|
153
|
+
}
|
|
154
|
+
},
|
|
155
|
+
};
|
|
156
|
+
}
|
|
157
|
+
/** Exported for testing. */
|
|
158
|
+
export const _test = { ALLOWED_TABLES, REDACTED_COLUMNS, validateInput, buildQuery };
|
|
159
|
+
//# sourceMappingURL=db-query.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"db-query.js","sourceRoot":"","sources":["../../src/tools/db-query.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* skill-result MCP tool — read last-N weekly briefing blobs from
|
|
3
|
+
* agent_metrics per app.
|
|
4
|
+
*/
|
|
5
|
+
import type Database from "better-sqlite3";
|
|
6
|
+
import type { McpToolImplementation } from "../agent/mcp-manager.js";
|
|
7
|
+
export declare function createSkillResultTool(db: Database.Database): McpToolImplementation;
|
|
8
|
+
//# sourceMappingURL=skill-result.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"skill-result.d.ts","sourceRoot":"","sources":["../../src/tools/skill-result.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,QAAQ,MAAM,gBAAgB,CAAC;AAC3C,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,yBAAyB,CAAC;AAgBrE,wBAAgB,qBAAqB,CAAC,EAAE,EAAE,QAAQ,CAAC,QAAQ,GAAG,qBAAqB,CAgDlF"}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* skill-result MCP tool — read last-N weekly briefing blobs from
|
|
3
|
+
* agent_metrics per app.
|
|
4
|
+
*/
|
|
5
|
+
import { getAgentMetrics } from "../db/queries.js";
|
|
6
|
+
const ALLOWED_SKILLS = ["aso", "review", "onboarding", "seo-blog", "short-form", "sdk-request", "content"];
|
|
7
|
+
const MAX_OUTPUT_BYTES = 10_240;
|
|
8
|
+
function truncateArray(data) {
|
|
9
|
+
let result = data;
|
|
10
|
+
while (result.length > 0) {
|
|
11
|
+
if (JSON.stringify(result).length <= MAX_OUTPUT_BYTES)
|
|
12
|
+
return result;
|
|
13
|
+
result = result.slice(0, Math.max(1, result.length - 1));
|
|
14
|
+
}
|
|
15
|
+
return result;
|
|
16
|
+
}
|
|
17
|
+
export function createSkillResultTool(db) {
|
|
18
|
+
return {
|
|
19
|
+
id: "skill-result",
|
|
20
|
+
name: "Skill Result",
|
|
21
|
+
description: "Read the last N weekly skill run results (agent_metrics) for an app. " +
|
|
22
|
+
"Available skills: " + ALLOWED_SKILLS.join(", ") + ". " +
|
|
23
|
+
"Use this to check how skills performed in recent weeks.",
|
|
24
|
+
inputSchema: {
|
|
25
|
+
type: "object",
|
|
26
|
+
required: ["skill", "app"],
|
|
27
|
+
properties: {
|
|
28
|
+
skill: {
|
|
29
|
+
type: "string",
|
|
30
|
+
enum: [...ALLOWED_SKILLS],
|
|
31
|
+
description: "Which skill's results to fetch.",
|
|
32
|
+
},
|
|
33
|
+
app: {
|
|
34
|
+
type: "string",
|
|
35
|
+
description: "App ID from apps.yaml.",
|
|
36
|
+
},
|
|
37
|
+
limit: {
|
|
38
|
+
type: "number",
|
|
39
|
+
description: "Number of recent results to return (default 5, max 20).",
|
|
40
|
+
},
|
|
41
|
+
},
|
|
42
|
+
},
|
|
43
|
+
handler: (input) => {
|
|
44
|
+
if (!input || typeof input !== "object") {
|
|
45
|
+
return Promise.resolve({ error: "Input must be an object with `skill` and `app` fields." });
|
|
46
|
+
}
|
|
47
|
+
const obj = input;
|
|
48
|
+
if (typeof obj["skill"] !== "string" || typeof obj["app"] !== "string") {
|
|
49
|
+
return Promise.resolve({ error: "Missing required fields: `skill` (string) and `app` (string)." });
|
|
50
|
+
}
|
|
51
|
+
const skill = obj["skill"];
|
|
52
|
+
const appId = obj["app"];
|
|
53
|
+
const limit = Math.min(typeof obj["limit"] === "number" ? obj["limit"] : 5, 20);
|
|
54
|
+
if (!ALLOWED_SKILLS.includes(skill)) {
|
|
55
|
+
return Promise.resolve({ error: `Unknown skill: "${skill}". Allowed: ${ALLOWED_SKILLS.join(", ")}` });
|
|
56
|
+
}
|
|
57
|
+
const rows = getAgentMetrics(db, appId, skill, limit * 7);
|
|
58
|
+
const limited = rows.slice(0, limit);
|
|
59
|
+
return Promise.resolve(truncateArray(limited));
|
|
60
|
+
},
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
//# sourceMappingURL=skill-result.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"skill-result.js","sourceRoot":"","sources":["../../src/tools/skill-result.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MCP tool host — stdio JSON-RPC server for Mode B tools.
|
|
3
|
+
*
|
|
4
|
+
* Claude CLI spawns this as a subprocess via `mcp-config.json`.
|
|
5
|
+
* It speaks the MCP protocol: reads JSON-RPC requests from stdin,
|
|
6
|
+
* dispatches to registered tool handlers, writes responses to stdout.
|
|
7
|
+
*
|
|
8
|
+
* This process opens its own SQLite connection and loads apps.yaml
|
|
9
|
+
* because it runs in a separate process from the daemon.
|
|
10
|
+
*/
|
|
11
|
+
export {};
|
|
12
|
+
//# sourceMappingURL=tool-host.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tool-host.d.ts","sourceRoot":"","sources":["../../src/tools/tool-host.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG"}
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MCP tool host — stdio JSON-RPC server for Mode B tools.
|
|
3
|
+
*
|
|
4
|
+
* Claude CLI spawns this as a subprocess via `mcp-config.json`.
|
|
5
|
+
* It speaks the MCP protocol: reads JSON-RPC requests from stdin,
|
|
6
|
+
* dispatches to registered tool handlers, writes responses to stdout.
|
|
7
|
+
*
|
|
8
|
+
* This process opens its own SQLite connection and loads apps.yaml
|
|
9
|
+
* because it runs in a separate process from the daemon.
|
|
10
|
+
*/
|
|
11
|
+
import { createInterface } from "node:readline";
|
|
12
|
+
import { initDatabase } from "../db/schema.js";
|
|
13
|
+
import { loadApps } from "../config/load-apps.js";
|
|
14
|
+
import { createDbQueryTool } from "./db-query.js";
|
|
15
|
+
import { createCollectorFetchTool } from "./collector-fetch.js";
|
|
16
|
+
import { createSkillResultTool } from "./skill-result.js";
|
|
17
|
+
import { createAppInfoTool } from "./app-info.js";
|
|
18
|
+
function respond(res) {
|
|
19
|
+
process.stdout.write(JSON.stringify(res) + "\n");
|
|
20
|
+
}
|
|
21
|
+
async function main() {
|
|
22
|
+
// Initialize DB + apps
|
|
23
|
+
const db = initDatabase();
|
|
24
|
+
const { apps } = await loadApps();
|
|
25
|
+
// Register tools
|
|
26
|
+
const tools = new Map();
|
|
27
|
+
const toolList = [
|
|
28
|
+
createDbQueryTool(db),
|
|
29
|
+
createCollectorFetchTool(db),
|
|
30
|
+
createSkillResultTool(db),
|
|
31
|
+
createAppInfoTool(apps),
|
|
32
|
+
];
|
|
33
|
+
for (const tool of toolList) {
|
|
34
|
+
tools.set(tool.id, tool);
|
|
35
|
+
}
|
|
36
|
+
const rl = createInterface({ input: process.stdin, terminal: false });
|
|
37
|
+
rl.on("line", (line) => {
|
|
38
|
+
void (async () => {
|
|
39
|
+
let request;
|
|
40
|
+
try {
|
|
41
|
+
request = JSON.parse(line);
|
|
42
|
+
}
|
|
43
|
+
catch {
|
|
44
|
+
respond({ jsonrpc: "2.0", id: null, error: { code: -32700, message: "Parse error" } });
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
const id = request.id ?? null;
|
|
48
|
+
if (request.method === "initialize") {
|
|
49
|
+
respond({
|
|
50
|
+
jsonrpc: "2.0",
|
|
51
|
+
id,
|
|
52
|
+
result: {
|
|
53
|
+
protocolVersion: "2024-11-05",
|
|
54
|
+
capabilities: { tools: {} },
|
|
55
|
+
serverInfo: { name: "adaria-tools", version: "0.1.0" },
|
|
56
|
+
},
|
|
57
|
+
});
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
if (request.method === "notifications/initialized") {
|
|
61
|
+
// Client ack — no response needed for notifications
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
if (request.method === "tools/list") {
|
|
65
|
+
respond({
|
|
66
|
+
jsonrpc: "2.0",
|
|
67
|
+
id,
|
|
68
|
+
result: {
|
|
69
|
+
tools: toolList.map((t) => ({
|
|
70
|
+
name: t.id,
|
|
71
|
+
description: t.description,
|
|
72
|
+
inputSchema: t.inputSchema,
|
|
73
|
+
})),
|
|
74
|
+
},
|
|
75
|
+
});
|
|
76
|
+
return;
|
|
77
|
+
}
|
|
78
|
+
if (request.method === "tools/call") {
|
|
79
|
+
const toolName = request.params?.["name"];
|
|
80
|
+
const toolInput = request.params?.["arguments"] ?? {};
|
|
81
|
+
if (!toolName) {
|
|
82
|
+
respond({ jsonrpc: "2.0", id, error: { code: -32602, message: "Missing tool name" } });
|
|
83
|
+
return;
|
|
84
|
+
}
|
|
85
|
+
const tool = tools.get(toolName);
|
|
86
|
+
if (!tool) {
|
|
87
|
+
respond({ jsonrpc: "2.0", id, error: { code: -32601, message: `Unknown tool: ${toolName}` } });
|
|
88
|
+
return;
|
|
89
|
+
}
|
|
90
|
+
try {
|
|
91
|
+
const result = await tool.handler(toolInput);
|
|
92
|
+
respond({
|
|
93
|
+
jsonrpc: "2.0",
|
|
94
|
+
id,
|
|
95
|
+
result: {
|
|
96
|
+
content: [{ type: "text", text: typeof result === "string" ? result : JSON.stringify(result) }],
|
|
97
|
+
},
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
catch (err) {
|
|
101
|
+
respond({
|
|
102
|
+
jsonrpc: "2.0",
|
|
103
|
+
id,
|
|
104
|
+
result: {
|
|
105
|
+
content: [{ type: "text", text: `Error: ${err instanceof Error ? err.message : String(err)}` }],
|
|
106
|
+
isError: true,
|
|
107
|
+
},
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
return;
|
|
111
|
+
}
|
|
112
|
+
respond({ jsonrpc: "2.0", id, error: { code: -32601, message: `Unknown method: ${request.method}` } });
|
|
113
|
+
})();
|
|
114
|
+
});
|
|
115
|
+
rl.on("close", () => {
|
|
116
|
+
db.close();
|
|
117
|
+
process.exit(0);
|
|
118
|
+
});
|
|
119
|
+
}
|
|
120
|
+
main().catch((err) => {
|
|
121
|
+
process.stderr.write(`[tool-host] Fatal: ${err instanceof Error ? err.message : String(err)}\n`);
|
|
122
|
+
process.exit(1);
|
|
123
|
+
});
|
|
124
|
+
//# sourceMappingURL=tool-host.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tool-host.js","sourceRoot":"","sources":["../../src/tools/tool-host.ts"],"names":[],"mappings":"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"}
|