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,60 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ASO Skill โ App Store Optimization analysis.
|
|
3
|
+
*
|
|
4
|
+
* Ported from growth-agent `src/agents/aso-agent.js`. Analyzes keyword
|
|
5
|
+
* visibility, detects rank drops, discovers opportunities, tracks
|
|
6
|
+
* competitor metadata changes, and generates metadata improvement
|
|
7
|
+
* proposals via Claude.
|
|
8
|
+
*
|
|
9
|
+
* 65-80% of installs come from organic search, making this the
|
|
10
|
+
* highest-impact skill in the weekly briefing.
|
|
11
|
+
*/
|
|
12
|
+
import type { Skill } from "./index.js";
|
|
13
|
+
import type { SkillContext, SkillResult } from "../types/skill.js";
|
|
14
|
+
import type { AppConfig } from "../config/apps-schema.js";
|
|
15
|
+
import type { AsoKeywordRanking, AsoCompetitorInfo } from "../types/collectors.js";
|
|
16
|
+
interface AsoCollectors {
|
|
17
|
+
getKeywordRankings: (appId: string, platform: string, keywords: string[]) => Promise<AsoKeywordRanking[]>;
|
|
18
|
+
getKeywordSuggestions: (appId: string, platform: string, locale: string) => Promise<Array<{
|
|
19
|
+
keyword: string;
|
|
20
|
+
searchVolume: number | null;
|
|
21
|
+
competition: number | null;
|
|
22
|
+
}>>;
|
|
23
|
+
getCompetitorInfo: (competitorId: string, platform: string) => Promise<AsoCompetitorInfo>;
|
|
24
|
+
}
|
|
25
|
+
interface AppStoreCollectors {
|
|
26
|
+
getAppLocalizations?: (appId: string, locale: string) => Promise<{
|
|
27
|
+
name?: string;
|
|
28
|
+
subtitle?: string;
|
|
29
|
+
description?: string;
|
|
30
|
+
} | null>;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Injected collector dependencies. Skills receive these via SkillContext
|
|
34
|
+
* or directly โ M4 passes them as constructor args until M5 wires a
|
|
35
|
+
* unified CollectorRegistry.
|
|
36
|
+
*/
|
|
37
|
+
export interface AsoSkillDeps {
|
|
38
|
+
asoMobile: AsoCollectors;
|
|
39
|
+
appStore?: AppStoreCollectors;
|
|
40
|
+
}
|
|
41
|
+
export declare class AsoSkill implements Skill {
|
|
42
|
+
readonly name = "aso";
|
|
43
|
+
readonly commands: readonly ["aso"];
|
|
44
|
+
private readonly deps;
|
|
45
|
+
constructor(deps: AsoSkillDeps);
|
|
46
|
+
dispatch(ctx: SkillContext, text: string): Promise<SkillResult>;
|
|
47
|
+
analyzeAso(ctx: SkillContext, app: AppConfig): Promise<SkillResult>;
|
|
48
|
+
private collectKeywordRankings;
|
|
49
|
+
private calculateRankChanges;
|
|
50
|
+
private findOpportunities;
|
|
51
|
+
private detectCompetitorChanges;
|
|
52
|
+
private fetchAndCompareCompetitor;
|
|
53
|
+
private generateMetadataProposal;
|
|
54
|
+
private generateScreenshotSuggestions;
|
|
55
|
+
private generateInAppEventSuggestions;
|
|
56
|
+
private getCurrentMetadata;
|
|
57
|
+
private buildSummary;
|
|
58
|
+
}
|
|
59
|
+
export {};
|
|
60
|
+
//# sourceMappingURL=aso.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"aso.d.ts","sourceRoot":"","sources":["../../src/skills/aso.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AAExC,OAAO,KAAK,EACV,YAAY,EACZ,WAAW,EAGZ,MAAM,mBAAmB,CAAC;AAC3B,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,0BAA0B,CAAC;AAC1D,OAAO,KAAK,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAsCnF,UAAU,aAAa;IACrB,kBAAkB,EAAE,CAClB,KAAK,EAAE,MAAM,EACb,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,MAAM,EAAE,KACf,OAAO,CAAC,iBAAiB,EAAE,CAAC,CAAC;IAClC,qBAAqB,EAAE,CACrB,KAAK,EAAE,MAAM,EACb,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,MAAM,KACX,OAAO,CAAC,KAAK,CAAC;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;QAAC,WAAW,EAAE,MAAM,GAAG,IAAI,CAAA;KAAE,CAAC,CAAC,CAAC;IAClG,iBAAiB,EAAE,CACjB,YAAY,EAAE,MAAM,EACpB,QAAQ,EAAE,MAAM,KACb,OAAO,CAAC,iBAAiB,CAAC,CAAC;CACjC;AAED,UAAU,kBAAkB;IAC1B,mBAAmB,CAAC,EAAE,CACpB,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,MAAM,KACX,OAAO,CAAC;QAAE,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;QAAC,WAAW,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAC,CAAC;CACjF;AAED;;;;GAIG;AACH,MAAM,WAAW,YAAY;IAC3B,SAAS,EAAE,aAAa,CAAC;IACzB,QAAQ,CAAC,EAAE,kBAAkB,CAAC;CAC/B;AAED,qBAAa,QAAS,YAAW,KAAK;IACpC,QAAQ,CAAC,IAAI,SAAS;IACtB,QAAQ,CAAC,QAAQ,mBAAoB;IAErC,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAe;gBAExB,IAAI,EAAE,YAAY;IAIxB,QAAQ,CAAC,GAAG,EAAE,YAAY,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC;IAmB/D,UAAU,CAAC,GAAG,EAAE,YAAY,EAAE,GAAG,EAAE,SAAS,GAAG,OAAO,CAAC,WAAW,CAAC;YA8D3D,sBAAsB;IAmCpC,OAAO,CAAC,oBAAoB;YA4Bd,iBAAiB;YAqCjB,uBAAuB;YAyBvB,yBAAyB;YA2DzB,wBAAwB;YAgDxB,6BAA6B;YA2B7B,6BAA6B;YAqB7B,kBAAkB;IAgBhC,OAAO,CAAC,YAAY;CAwDrB"}
|
|
@@ -0,0 +1,322 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ASO Skill โ App Store Optimization analysis.
|
|
3
|
+
*
|
|
4
|
+
* Ported from growth-agent `src/agents/aso-agent.js`. Analyzes keyword
|
|
5
|
+
* visibility, detects rank drops, discovers opportunities, tracks
|
|
6
|
+
* competitor metadata changes, and generates metadata improvement
|
|
7
|
+
* proposals via Claude.
|
|
8
|
+
*
|
|
9
|
+
* 65-80% of installs come from organic search, making this the
|
|
10
|
+
* highest-impact skill in the weekly briefing.
|
|
11
|
+
*/
|
|
12
|
+
import { parseAppNameFromCommand } from "./index.js";
|
|
13
|
+
import { insertKeywordRanking, getKeywordRankChange, insertCompetitorMetadata, getPreviousCompetitorMetadata, } from "../db/queries.js";
|
|
14
|
+
import { preparePrompt } from "../prompts/loader.js";
|
|
15
|
+
import { warn as logWarn } from "../utils/logger.js";
|
|
16
|
+
import { sanitizeExternalText } from "../security/prompt-guard.js";
|
|
17
|
+
const MAX_DESCRIPTION_LEN = 200;
|
|
18
|
+
/** Threshold for keyword rank drops that trigger alerts. */
|
|
19
|
+
const DEFAULT_RANK_ALERT_THRESHOLD = 5;
|
|
20
|
+
export class AsoSkill {
|
|
21
|
+
name = "aso";
|
|
22
|
+
commands = ["aso"];
|
|
23
|
+
deps;
|
|
24
|
+
constructor(deps) {
|
|
25
|
+
this.deps = deps;
|
|
26
|
+
}
|
|
27
|
+
async dispatch(ctx, text) {
|
|
28
|
+
const appName = parseAppNameFromCommand(text);
|
|
29
|
+
const app = appName
|
|
30
|
+
? ctx.apps.find((a) => a.id.toLowerCase() === appName)
|
|
31
|
+
: ctx.apps[0];
|
|
32
|
+
if (!app) {
|
|
33
|
+
return {
|
|
34
|
+
summary: appName
|
|
35
|
+
? `โ App "${appName}" not found in apps.yaml. Available: ${ctx.apps.map((a) => a.id).join(", ")}`
|
|
36
|
+
: "โ No apps configured. Add apps to apps.yaml.",
|
|
37
|
+
alerts: [],
|
|
38
|
+
approvals: [],
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
return this.analyzeAso(ctx, app);
|
|
42
|
+
}
|
|
43
|
+
async analyzeAso(ctx, app) {
|
|
44
|
+
const alerts = [];
|
|
45
|
+
const approvals = [];
|
|
46
|
+
// 1. Collect current keyword rankings
|
|
47
|
+
const rankings = await this.collectKeywordRankings(ctx, app);
|
|
48
|
+
// 2. Calculate rank changes vs last week
|
|
49
|
+
const rankChanges = this.calculateRankChanges(ctx, app, rankings);
|
|
50
|
+
// 3. Detect critical drops
|
|
51
|
+
const criticalDrops = rankChanges.filter((c) => c.drop >= DEFAULT_RANK_ALERT_THRESHOLD);
|
|
52
|
+
for (const drop of criticalDrops) {
|
|
53
|
+
alerts.push({
|
|
54
|
+
severity: "high",
|
|
55
|
+
message: `"${drop.keyword}" (${drop.platform}) rank ${String(drop.previousRank)} โ ${String(drop.currentRank)} (drop -${String(drop.drop)})`,
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
// 4. Find new keyword opportunities
|
|
59
|
+
const opportunities = await this.findOpportunities(app);
|
|
60
|
+
// 5. Detect competitor metadata changes
|
|
61
|
+
const competitorChanges = await this.detectCompetitorChanges(ctx, app);
|
|
62
|
+
// 6. Generate metadata improvement proposal via Claude
|
|
63
|
+
let metadataProposal = null;
|
|
64
|
+
if (alerts.length > 0 || opportunities.length > 0 || competitorChanges.length > 0) {
|
|
65
|
+
metadataProposal = await this.generateMetadataProposal(ctx, app, rankChanges, opportunities);
|
|
66
|
+
if (metadataProposal) {
|
|
67
|
+
approvals.push({
|
|
68
|
+
id: `aso-meta-${app.id}`,
|
|
69
|
+
description: `ASO metadata change proposal for ${app.name}`,
|
|
70
|
+
agent: "aso",
|
|
71
|
+
payload: { proposal: metadataProposal },
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
// 7. Screenshot caption suggestions
|
|
76
|
+
const screenshotSuggestions = await this.generateScreenshotSuggestions(ctx, app, opportunities);
|
|
77
|
+
// 8. In-App Events suggestions (iOS only)
|
|
78
|
+
const inAppEventSuggestions = await this.generateInAppEventSuggestions(ctx, app);
|
|
79
|
+
// 9. Build summary
|
|
80
|
+
const summary = this.buildSummary(app, alerts, rankChanges, opportunities, competitorChanges, screenshotSuggestions, inAppEventSuggestions);
|
|
81
|
+
return { summary, alerts, approvals };
|
|
82
|
+
}
|
|
83
|
+
async collectKeywordRankings(ctx, app) {
|
|
84
|
+
const collected = [];
|
|
85
|
+
for (const platform of app.platform) {
|
|
86
|
+
const storeId = platform === "ios" ? app.appStoreId : app.playStorePackage;
|
|
87
|
+
if (!storeId)
|
|
88
|
+
continue;
|
|
89
|
+
try {
|
|
90
|
+
const rankings = await this.deps.asoMobile.getKeywordRankings(storeId, platform, app.primaryKeywords);
|
|
91
|
+
for (const r of rankings) {
|
|
92
|
+
insertKeywordRanking(ctx.db, {
|
|
93
|
+
app_id: app.id,
|
|
94
|
+
keyword: r.keyword,
|
|
95
|
+
platform,
|
|
96
|
+
rank: r.rank,
|
|
97
|
+
search_volume: r.searchVolume,
|
|
98
|
+
});
|
|
99
|
+
collected.push({ ...r, platform });
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
catch (err) {
|
|
103
|
+
logWarn(`[aso] Keyword ranking collection failed for ${app.id}/${platform}: ${err instanceof Error ? err.message : String(err)}`);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
return collected;
|
|
107
|
+
}
|
|
108
|
+
calculateRankChanges(ctx, app, currentRankings) {
|
|
109
|
+
const changes = [];
|
|
110
|
+
for (const ranking of currentRankings) {
|
|
111
|
+
const change = getKeywordRankChange(ctx.db, app.id, ranking.keyword, ranking.platform);
|
|
112
|
+
if (change.current_rank != null && change.previous_rank != null) {
|
|
113
|
+
const drop = change.current_rank - change.previous_rank;
|
|
114
|
+
changes.push({
|
|
115
|
+
keyword: ranking.keyword,
|
|
116
|
+
platform: ranking.platform,
|
|
117
|
+
currentRank: change.current_rank,
|
|
118
|
+
previousRank: change.previous_rank,
|
|
119
|
+
drop,
|
|
120
|
+
searchVolume: ranking.searchVolume,
|
|
121
|
+
});
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
return changes.sort((a, b) => b.drop - a.drop);
|
|
125
|
+
}
|
|
126
|
+
async findOpportunities(app) {
|
|
127
|
+
const opportunities = [];
|
|
128
|
+
for (const platform of app.platform) {
|
|
129
|
+
const storeId = platform === "ios" ? app.appStoreId : app.playStorePackage;
|
|
130
|
+
if (!storeId)
|
|
131
|
+
continue;
|
|
132
|
+
try {
|
|
133
|
+
const suggestions = await this.deps.asoMobile.getKeywordSuggestions(storeId, platform, app.locale[0] ?? "ko");
|
|
134
|
+
const existing = new Set(app.primaryKeywords.map((k) => k.toLowerCase()));
|
|
135
|
+
const filtered = suggestions.filter((s) => s.searchVolume != null &&
|
|
136
|
+
s.searchVolume > 100 &&
|
|
137
|
+
s.competition != null &&
|
|
138
|
+
s.competition < 40 &&
|
|
139
|
+
!existing.has(s.keyword.toLowerCase()));
|
|
140
|
+
for (const s of filtered.slice(0, 5)) {
|
|
141
|
+
opportunities.push({ ...s, platform });
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
catch (err) {
|
|
145
|
+
logWarn(`[aso] Keyword suggestions failed for ${app.id}/${platform}: ${err instanceof Error ? err.message : String(err)}`);
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
return opportunities;
|
|
149
|
+
}
|
|
150
|
+
async detectCompetitorChanges(ctx, app) {
|
|
151
|
+
const competitors = app.competitors;
|
|
152
|
+
if (competitors.length === 0)
|
|
153
|
+
return [];
|
|
154
|
+
const tasks = [];
|
|
155
|
+
for (const competitorId of competitors) {
|
|
156
|
+
for (const platform of app.platform) {
|
|
157
|
+
tasks.push(this.fetchAndCompareCompetitor(ctx, app, competitorId, platform));
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
const results = await Promise.allSettled(tasks);
|
|
161
|
+
return results
|
|
162
|
+
.filter((r) => r.status === "fulfilled" && r.value !== null)
|
|
163
|
+
.map((r) => r.value);
|
|
164
|
+
}
|
|
165
|
+
async fetchAndCompareCompetitor(ctx, app, competitorId, platform) {
|
|
166
|
+
try {
|
|
167
|
+
const current = await this.deps.asoMobile.getCompetitorInfo(competitorId, platform);
|
|
168
|
+
insertCompetitorMetadata(ctx.db, {
|
|
169
|
+
app_id: app.id,
|
|
170
|
+
competitor_id: competitorId,
|
|
171
|
+
platform,
|
|
172
|
+
title: current.title,
|
|
173
|
+
subtitle: current.subtitle,
|
|
174
|
+
description: current.description,
|
|
175
|
+
keywords: current.keywords,
|
|
176
|
+
});
|
|
177
|
+
const previous = getPreviousCompetitorMetadata(ctx.db, app.id, competitorId, platform);
|
|
178
|
+
if (previous) {
|
|
179
|
+
const diffs = [];
|
|
180
|
+
if (previous.title !== current.title) {
|
|
181
|
+
diffs.push({ field: "title", old: previous.title, new: current.title });
|
|
182
|
+
}
|
|
183
|
+
if (previous.subtitle !== current.subtitle) {
|
|
184
|
+
diffs.push({ field: "subtitle", old: previous.subtitle, new: current.subtitle });
|
|
185
|
+
}
|
|
186
|
+
if (previous.description !== current.description) {
|
|
187
|
+
diffs.push({
|
|
188
|
+
field: "description",
|
|
189
|
+
old: previous.description ? sanitizeExternalText(previous.description, MAX_DESCRIPTION_LEN) : previous.description,
|
|
190
|
+
new: current.description ? sanitizeExternalText(current.description, MAX_DESCRIPTION_LEN) : current.description,
|
|
191
|
+
});
|
|
192
|
+
}
|
|
193
|
+
const prevKw = previous.keywords ?? "";
|
|
194
|
+
const currKw = Array.isArray(current.keywords)
|
|
195
|
+
? current.keywords.join(",")
|
|
196
|
+
: (current.keywords ?? "");
|
|
197
|
+
if (prevKw !== currKw) {
|
|
198
|
+
diffs.push({ field: "keywords", old: previous.keywords, new: currKw });
|
|
199
|
+
}
|
|
200
|
+
if (diffs.length > 0) {
|
|
201
|
+
return { competitorId, platform, diffs };
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
catch (err) {
|
|
206
|
+
logWarn(`[aso] Competitor fetch failed for ${competitorId}: ${err instanceof Error ? err.message : String(err)}`);
|
|
207
|
+
}
|
|
208
|
+
return null;
|
|
209
|
+
}
|
|
210
|
+
async generateMetadataProposal(ctx, app, rankChanges, opportunities) {
|
|
211
|
+
const currentMetadata = await this.getCurrentMetadata(app);
|
|
212
|
+
const rankChangesText = rankChanges.length > 0
|
|
213
|
+
? rankChanges
|
|
214
|
+
.map((c) => `- "${c.keyword}" (${c.platform}): rank ${String(c.previousRank)} โ ${String(c.currentRank)} (${c.drop > 0 ? "+" + String(c.drop) : String(c.drop)}) | volume ${c.searchVolume != null ? String(c.searchVolume) : "N/A"}`)
|
|
215
|
+
.join("\n")
|
|
216
|
+
: "No changes";
|
|
217
|
+
const opportunitiesText = opportunities.length > 0
|
|
218
|
+
? opportunities
|
|
219
|
+
.map((o) => `- "${o.keyword}" (${o.platform}): volume ${o.searchVolume != null ? String(o.searchVolume) : "N/A"}, competition ${o.competition != null ? String(o.competition) : "N/A"}`)
|
|
220
|
+
.join("\n")
|
|
221
|
+
: "None";
|
|
222
|
+
const metadataText = currentMetadata
|
|
223
|
+
? `## Current metadata\n- Title: ${currentMetadata.name ?? ""}\n- Subtitle: ${currentMetadata.subtitle ?? ""}\n- Description (first 200 chars): ${currentMetadata.description ? sanitizeExternalText(currentMetadata.description, 200) : ""}...`
|
|
224
|
+
: "";
|
|
225
|
+
const prompt = preparePrompt("aso-metadata", {
|
|
226
|
+
appName: app.name,
|
|
227
|
+
primaryKeywords: app.primaryKeywords.join(", "),
|
|
228
|
+
rankChanges: rankChangesText,
|
|
229
|
+
opportunities: opportunitiesText,
|
|
230
|
+
currentMetadata: metadataText,
|
|
231
|
+
});
|
|
232
|
+
try {
|
|
233
|
+
return await ctx.runClaude(prompt);
|
|
234
|
+
}
|
|
235
|
+
catch (err) {
|
|
236
|
+
logWarn(`[aso] Metadata proposal generation failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
237
|
+
return null;
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
async generateScreenshotSuggestions(ctx, app, opportunities) {
|
|
241
|
+
const keywords = [
|
|
242
|
+
...app.primaryKeywords,
|
|
243
|
+
...opportunities.map((o) => o.keyword),
|
|
244
|
+
].slice(0, 10);
|
|
245
|
+
if (keywords.length === 0)
|
|
246
|
+
return null;
|
|
247
|
+
const prompt = preparePrompt("aso-screenshots", {
|
|
248
|
+
appName: app.name,
|
|
249
|
+
keywords: keywords.join(", "),
|
|
250
|
+
});
|
|
251
|
+
try {
|
|
252
|
+
return await ctx.runClaude(prompt);
|
|
253
|
+
}
|
|
254
|
+
catch (err) {
|
|
255
|
+
logWarn(`[aso] Screenshot suggestions failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
256
|
+
return null;
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
async generateInAppEventSuggestions(ctx, app) {
|
|
260
|
+
if (!app.platform.includes("ios"))
|
|
261
|
+
return null;
|
|
262
|
+
const prompt = preparePrompt("aso-inapp-events", {
|
|
263
|
+
appName: app.name,
|
|
264
|
+
keywords: app.primaryKeywords.join(", "),
|
|
265
|
+
});
|
|
266
|
+
try {
|
|
267
|
+
return await ctx.runClaude(prompt);
|
|
268
|
+
}
|
|
269
|
+
catch (err) {
|
|
270
|
+
logWarn(`[aso] In-App Events suggestions failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
271
|
+
return null;
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
async getCurrentMetadata(app) {
|
|
275
|
+
if (!this.deps.appStore?.getAppLocalizations)
|
|
276
|
+
return null;
|
|
277
|
+
try {
|
|
278
|
+
if (app.platform.includes("ios") && app.appStoreId) {
|
|
279
|
+
return await this.deps.appStore.getAppLocalizations(app.appStoreId, app.locale[0] ?? "ko");
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
catch {
|
|
283
|
+
// metadata fetch failure is non-fatal
|
|
284
|
+
}
|
|
285
|
+
return null;
|
|
286
|
+
}
|
|
287
|
+
buildSummary(app, alerts, rankChanges, opportunities, competitorChanges, screenshotSuggestions, inAppEventSuggestions) {
|
|
288
|
+
const hasAlert = alerts.length > 0;
|
|
289
|
+
const header = hasAlert
|
|
290
|
+
? `*๐ด [Urgent] ASO โ ${app.name}*`
|
|
291
|
+
: `*๐ข ASO โ ${app.name}*`;
|
|
292
|
+
const lines = [header];
|
|
293
|
+
if (hasAlert) {
|
|
294
|
+
const top = rankChanges.find((c) => c.drop >= DEFAULT_RANK_ALERT_THRESHOLD);
|
|
295
|
+
if (top) {
|
|
296
|
+
lines.push(`โข "${top.keyword}" rank ${String(top.previousRank)} โ ${String(top.currentRank)} (drop -${String(top.drop)})`);
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
const rising = rankChanges.filter((c) => c.drop < 0);
|
|
300
|
+
if (rising.length > 0) {
|
|
301
|
+
lines.push(`โข ๐ข ${String(rising.length)} rising keywords: ${rising.slice(0, 3).map((c) => `"${c.keyword}" +${String(Math.abs(c.drop))}`).join(", ")}`);
|
|
302
|
+
}
|
|
303
|
+
if (opportunities.length > 0) {
|
|
304
|
+
lines.push(`โข ๐ก ${String(opportunities.length)} new opportunities: ${opportunities.slice(0, 3).map((o) => `"${o.keyword}"`).join(", ")}`);
|
|
305
|
+
}
|
|
306
|
+
if (competitorChanges.length > 0) {
|
|
307
|
+
const comps = competitorChanges.map((c) => c.competitorId);
|
|
308
|
+
lines.push(`โข ๐ต Competitor metadata change detected: ${comps.join(", ")}`);
|
|
309
|
+
}
|
|
310
|
+
if (screenshotSuggestions) {
|
|
311
|
+
lines.push("โข ๐ธ Screenshot caption suggestions ready");
|
|
312
|
+
}
|
|
313
|
+
if (inAppEventSuggestions) {
|
|
314
|
+
lines.push("โข ๐
In-App Events suggestions ready");
|
|
315
|
+
}
|
|
316
|
+
if (lines.length === 1) {
|
|
317
|
+
lines.push("โข Keyword rankings stable");
|
|
318
|
+
}
|
|
319
|
+
return lines.join("\n");
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
//# sourceMappingURL=aso.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"aso.js","sourceRoot":"","sources":["../../src/skills/aso.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAGH,OAAO,EAAE,uBAAuB,EAAE,MAAM,YAAY,CAAC;AASrD,OAAO,EACL,oBAAoB,EACpB,oBAAoB,EACpB,wBAAwB,EACxB,6BAA6B,GAC9B,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AACrD,OAAO,EAAE,IAAI,IAAI,OAAO,EAAE,MAAM,oBAAoB,CAAC;AACrD,OAAO,EAAE,oBAAoB,EAAE,MAAM,6BAA6B,CAAC;AAEnE,MAAM,mBAAmB,GAAG,GAAG,CAAC;AAEhC,4DAA4D;AAC5D,MAAM,4BAA4B,GAAG,CAAC,CAAC;AA0DvC,MAAM,OAAO,QAAQ;IACV,IAAI,GAAG,KAAK,CAAC;IACb,QAAQ,GAAG,CAAC,KAAK,CAAU,CAAC;IAEpB,IAAI,CAAe;IAEpC,YAAY,IAAkB;QAC5B,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;IACnB,CAAC;IAED,KAAK,CAAC,QAAQ,CAAC,GAAiB,EAAE,IAAY;QAC5C,MAAM,OAAO,GAAG,uBAAuB,CAAC,IAAI,CAAC,CAAC;QAC9C,MAAM,GAAG,GAAG,OAAO;YACjB,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,WAAW,EAAE,KAAK,OAAO,CAAC;YACtD,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAEhB,IAAI,CAAC,GAAG,EAAE,CAAC;YACT,OAAO;gBACL,OAAO,EAAE,OAAO;oBACd,CAAC,CAAC,UAAU,OAAO,wCAAwC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE;oBACjG,CAAC,CAAC,8CAA8C;gBAClD,MAAM,EAAE,EAAE;gBACV,SAAS,EAAE,EAAE;aACd,CAAC;QACJ,CAAC;QAED,OAAO,IAAI,CAAC,UAAU,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;IACnC,CAAC;IAED,KAAK,CAAC,UAAU,CAAC,GAAiB,EAAE,GAAc;QAChD,MAAM,MAAM,GAAiB,EAAE,CAAC;QAChC,MAAM,SAAS,GAAmB,EAAE,CAAC;QAErC,sCAAsC;QACtC,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,sBAAsB,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;QAE7D,yCAAyC;QACzC,MAAM,WAAW,GAAG,IAAI,CAAC,oBAAoB,CAAC,GAAG,EAAE,GAAG,EAAE,QAAQ,CAAC,CAAC;QAElE,2BAA2B;QAC3B,MAAM,aAAa,GAAG,WAAW,CAAC,MAAM,CACtC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,IAAI,4BAA4B,CAC9C,CAAC;QACF,KAAK,MAAM,IAAI,IAAI,aAAa,EAAE,CAAC;YACjC,MAAM,CAAC,IAAI,CAAC;gBACV,QAAQ,EAAE,MAAM;gBAChB,OAAO,EAAE,IAAI,IAAI,CAAC,OAAO,MAAM,IAAI,CAAC,QAAQ,UAAU,MAAM,CAAC,IAAI,CAAC,YAAY,CAAC,MAAM,MAAM,CAAC,IAAI,CAAC,WAAW,CAAC,WAAW,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG;aAC7I,CAAC,CAAC;QACL,CAAC;QAED,oCAAoC;QACpC,MAAM,aAAa,GAAG,MAAM,IAAI,CAAC,iBAAiB,CAAC,GAAG,CAAC,CAAC;QAExD,wCAAwC;QACxC,MAAM,iBAAiB,GAAG,MAAM,IAAI,CAAC,uBAAuB,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;QAEvE,uDAAuD;QACvD,IAAI,gBAAgB,GAAkB,IAAI,CAAC;QAC3C,IAAI,MAAM,CAAC,MAAM,GAAG,CAAC,IAAI,aAAa,CAAC,MAAM,GAAG,CAAC,IAAI,iBAAiB,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAClF,gBAAgB,GAAG,MAAM,IAAI,CAAC,wBAAwB,CACpD,GAAG,EAAE,GAAG,EAAE,WAAW,EAAE,aAAa,CACrC,CAAC;YACF,IAAI,gBAAgB,EAAE,CAAC;gBACrB,SAAS,CAAC,IAAI,CAAC;oBACb,EAAE,EAAE,YAAY,GAAG,CAAC,EAAE,EAAE;oBACxB,WAAW,EAAE,oCAAoC,GAAG,CAAC,IAAI,EAAE;oBAC3D,KAAK,EAAE,KAAK;oBACZ,OAAO,EAAE,EAAE,QAAQ,EAAE,gBAAgB,EAAE;iBACxC,CAAC,CAAC;YACL,CAAC;QACH,CAAC;QAED,oCAAoC;QACpC,MAAM,qBAAqB,GAAG,MAAM,IAAI,CAAC,6BAA6B,CACpE,GAAG,EAAE,GAAG,EAAE,aAAa,CACxB,CAAC;QAEF,0CAA0C;QAC1C,MAAM,qBAAqB,GAAG,MAAM,IAAI,CAAC,6BAA6B,CACpE,GAAG,EAAE,GAAG,CACT,CAAC;QAEF,mBAAmB;QACnB,MAAM,OAAO,GAAG,IAAI,CAAC,YAAY,CAC/B,GAAG,EAAE,MAAM,EAAE,WAAW,EAAE,aAAa,EAAE,iBAAiB,EAC1D,qBAAqB,EAAE,qBAAqB,CAC7C,CAAC;QAEF,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,CAAC;IACxC,CAAC;IAEO,KAAK,CAAC,sBAAsB,CAClC,GAAiB,EACjB,GAAc;QAEd,MAAM,SAAS,GAAoD,EAAE,CAAC;QAEtE,KAAK,MAAM,QAAQ,IAAI,GAAG,CAAC,QAAQ,EAAE,CAAC;YACpC,MAAM,OAAO,GAAG,QAAQ,KAAK,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC,CAAC,GAAG,CAAC,gBAAgB,CAAC;YAC3E,IAAI,CAAC,OAAO;gBAAE,SAAS;YAEvB,IAAI,CAAC;gBACH,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,kBAAkB,CAC3D,OAAO,EAAE,QAAQ,EAAE,GAAG,CAAC,eAAe,CACvC,CAAC;gBAEF,KAAK,MAAM,CAAC,IAAI,QAAQ,EAAE,CAAC;oBACzB,oBAAoB,CAAC,GAAG,CAAC,EAAE,EAAE;wBAC3B,MAAM,EAAE,GAAG,CAAC,EAAE;wBACd,OAAO,EAAE,CAAC,CAAC,OAAO;wBAClB,QAAQ;wBACR,IAAI,EAAE,CAAC,CAAC,IAAI;wBACZ,aAAa,EAAE,CAAC,CAAC,YAAY;qBAC9B,CAAC,CAAC;oBACH,SAAS,CAAC,IAAI,CAAC,EAAE,GAAG,CAAC,EAAE,QAAQ,EAAE,CAAC,CAAC;gBACrC,CAAC;YACH,CAAC;YAAC,OAAO,GAAG,EAAE,CAAC;gBACb,OAAO,CACL,+CAA+C,GAAG,CAAC,EAAE,IAAI,QAAQ,KAAK,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CACzH,CAAC;YACJ,CAAC;QACH,CAAC;QAED,OAAO,SAAS,CAAC;IACnB,CAAC;IAEO,oBAAoB,CAC1B,GAAiB,EACjB,GAAc,EACd,eAAgE;QAEhE,MAAM,OAAO,GAAiB,EAAE,CAAC;QAEjC,KAAK,MAAM,OAAO,IAAI,eAAe,EAAE,CAAC;YACtC,MAAM,MAAM,GAAG,oBAAoB,CACjC,GAAG,CAAC,EAAE,EAAE,GAAG,CAAC,EAAE,EAAE,OAAO,CAAC,OAAO,EAAE,OAAO,CAAC,QAAQ,CAClD,CAAC;YAEF,IAAI,MAAM,CAAC,YAAY,IAAI,IAAI,IAAI,MAAM,CAAC,aAAa,IAAI,IAAI,EAAE,CAAC;gBAChE,MAAM,IAAI,GAAG,MAAM,CAAC,YAAY,GAAG,MAAM,CAAC,aAAa,CAAC;gBACxD,OAAO,CAAC,IAAI,CAAC;oBACX,OAAO,EAAE,OAAO,CAAC,OAAO;oBACxB,QAAQ,EAAE,OAAO,CAAC,QAAQ;oBAC1B,WAAW,EAAE,MAAM,CAAC,YAAY;oBAChC,YAAY,EAAE,MAAM,CAAC,aAAa;oBAClC,IAAI;oBACJ,YAAY,EAAE,OAAO,CAAC,YAAY;iBACnC,CAAC,CAAC;YACL,CAAC;QACH,CAAC;QAED,OAAO,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC;IACjD,CAAC;IAEO,KAAK,CAAC,iBAAiB,CAAC,GAAc;QAC5C,MAAM,aAAa,GAAkB,EAAE,CAAC;QAExC,KAAK,MAAM,QAAQ,IAAI,GAAG,CAAC,QAAQ,EAAE,CAAC;YACpC,MAAM,OAAO,GAAG,QAAQ,KAAK,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC,CAAC,GAAG,CAAC,gBAAgB,CAAC;YAC3E,IAAI,CAAC,OAAO;gBAAE,SAAS;YAEvB,IAAI,CAAC;gBACH,MAAM,WAAW,GAAG,MAAM,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,qBAAqB,CACjE,OAAO,EAAE,QAAQ,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,IAAI,CACzC,CAAC;gBAEF,MAAM,QAAQ,GAAG,IAAI,GAAG,CACtB,GAAG,CAAC,eAAe,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC,CAChD,CAAC;gBACF,MAAM,QAAQ,GAAG,WAAW,CAAC,MAAM,CACjC,CAAC,CAAC,EAAE,EAAE,CACJ,CAAC,CAAC,YAAY,IAAI,IAAI;oBACtB,CAAC,CAAC,YAAY,GAAG,GAAG;oBACpB,CAAC,CAAC,WAAW,IAAI,IAAI;oBACrB,CAAC,CAAC,WAAW,GAAG,EAAE;oBAClB,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,OAAO,CAAC,WAAW,EAAE,CAAC,CACzC,CAAC;gBAEF,KAAK,MAAM,CAAC,IAAI,QAAQ,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC;oBACrC,aAAa,CAAC,IAAI,CAAC,EAAE,GAAG,CAAC,EAAE,QAAQ,EAAE,CAAC,CAAC;gBACzC,CAAC;YACH,CAAC;YAAC,OAAO,GAAG,EAAE,CAAC;gBACb,OAAO,CACL,wCAAwC,GAAG,CAAC,EAAE,IAAI,QAAQ,KAAK,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAClH,CAAC;YACJ,CAAC;QACH,CAAC;QAED,OAAO,aAAa,CAAC;IACvB,CAAC;IAEO,KAAK,CAAC,uBAAuB,CACnC,GAAiB,EACjB,GAAc;QAEd,MAAM,WAAW,GAAG,GAAG,CAAC,WAAW,CAAC;QACpC,IAAI,WAAW,CAAC,MAAM,KAAK,CAAC;YAAE,OAAO,EAAE,CAAC;QAExC,MAAM,KAAK,GAA4C,EAAE,CAAC;QAC1D,KAAK,MAAM,YAAY,IAAI,WAAW,EAAE,CAAC;YACvC,KAAK,MAAM,QAAQ,IAAI,GAAG,CAAC,QAAQ,EAAE,CAAC;gBACpC,KAAK,CAAC,IAAI,CACR,IAAI,CAAC,yBAAyB,CAAC,GAAG,EAAE,GAAG,EAAE,YAAY,EAAE,QAAQ,CAAC,CACjE,CAAC;YACJ,CAAC;QACH,CAAC;QAED,MAAM,OAAO,GAAG,MAAM,OAAO,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC;QAChD,OAAO,OAAO;aACX,MAAM,CACL,CAAC,CAAC,EAAiD,EAAE,CACnD,CAAC,CAAC,MAAM,KAAK,WAAW,IAAI,CAAC,CAAC,KAAK,KAAK,IAAI,CAC/C;aACA,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC;IACzB,CAAC;IAEO,KAAK,CAAC,yBAAyB,CACrC,GAAiB,EACjB,GAAc,EACd,YAAoB,EACpB,QAAgB;QAEhB,IAAI,CAAC;YACH,MAAM,OAAO,GAAG,MAAM,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,iBAAiB,CACzD,YAAY,EAAE,QAAQ,CACvB,CAAC;YAEF,wBAAwB,CAAC,GAAG,CAAC,EAAE,EAAE;gBAC/B,MAAM,EAAE,GAAG,CAAC,EAAE;gBACd,aAAa,EAAE,YAAY;gBAC3B,QAAQ;gBACR,KAAK,EAAE,OAAO,CAAC,KAAK;gBACpB,QAAQ,EAAE,OAAO,CAAC,QAAQ;gBAC1B,WAAW,EAAE,OAAO,CAAC,WAAW;gBAChC,QAAQ,EAAE,OAAO,CAAC,QAAQ;aAC3B,CAAC,CAAC;YAEH,MAAM,QAAQ,GAAG,6BAA6B,CAC5C,GAAG,CAAC,EAAE,EAAE,GAAG,CAAC,EAAE,EAAE,YAAY,EAAE,QAAQ,CACvC,CAAC;YACF,IAAI,QAAQ,EAAE,CAAC;gBACb,MAAM,KAAK,GAA8B,EAAE,CAAC;gBAC5C,IAAI,QAAQ,CAAC,KAAK,KAAK,OAAO,CAAC,KAAK,EAAE,CAAC;oBACrC,KAAK,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,OAAO,EAAE,GAAG,EAAE,QAAQ,CAAC,KAAK,EAAE,GAAG,EAAE,OAAO,CAAC,KAAK,EAAE,CAAC,CAAC;gBAC1E,CAAC;gBACD,IAAI,QAAQ,CAAC,QAAQ,KAAK,OAAO,CAAC,QAAQ,EAAE,CAAC;oBAC3C,KAAK,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,UAAU,EAAE,GAAG,EAAE,QAAQ,CAAC,QAAQ,EAAE,GAAG,EAAE,OAAO,CAAC,QAAQ,EAAE,CAAC,CAAC;gBACnF,CAAC;gBACD,IAAI,QAAQ,CAAC,WAAW,KAAK,OAAO,CAAC,WAAW,EAAE,CAAC;oBACjD,KAAK,CAAC,IAAI,CAAC;wBACT,KAAK,EAAE,aAAa;wBACpB,GAAG,EAAE,QAAQ,CAAC,WAAW,CAAC,CAAC,CAAC,oBAAoB,CAAC,QAAQ,CAAC,WAAW,EAAE,mBAAmB,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,WAAW;wBAClH,GAAG,EAAE,OAAO,CAAC,WAAW,CAAC,CAAC,CAAC,oBAAoB,CAAC,OAAO,CAAC,WAAW,EAAE,mBAAmB,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,WAAW;qBAChH,CAAC,CAAC;gBACL,CAAC;gBACD,MAAM,MAAM,GAAG,QAAQ,CAAC,QAAQ,IAAI,EAAE,CAAC;gBACvC,MAAM,MAAM,GAAG,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,QAAQ,CAAC;oBAC5C,CAAC,CAAC,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC;oBAC5B,CAAC,CAAC,CAAC,OAAO,CAAC,QAAQ,IAAI,EAAE,CAAC,CAAC;gBAC7B,IAAI,MAAM,KAAK,MAAM,EAAE,CAAC;oBACtB,KAAK,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,UAAU,EAAE,GAAG,EAAE,QAAQ,CAAC,QAAQ,EAAE,GAAG,EAAE,MAAM,EAAE,CAAC,CAAC;gBACzE,CAAC;gBAED,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;oBACrB,OAAO,EAAE,YAAY,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAC;gBAC3C,CAAC;YACH,CAAC;QACH,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,OAAO,CACL,qCAAqC,YAAY,KAAK,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CACzG,CAAC;QACJ,CAAC;QACD,OAAO,IAAI,CAAC;IACd,CAAC;IAEO,KAAK,CAAC,wBAAwB,CACpC,GAAiB,EACjB,GAAc,EACd,WAAyB,EACzB,aAA4B;QAE5B,MAAM,eAAe,GAAG,MAAM,IAAI,CAAC,kBAAkB,CAAC,GAAG,CAAC,CAAC;QAE3D,MAAM,eAAe,GAAG,WAAW,CAAC,MAAM,GAAG,CAAC;YAC5C,CAAC,CAAC,WAAW;iBACR,GAAG,CACF,CAAC,CAAC,EAAE,EAAE,CACJ,MAAM,CAAC,CAAC,OAAO,MAAM,CAAC,CAAC,QAAQ,WAAW,MAAM,CAAC,CAAC,CAAC,YAAY,CAAC,MAAM,MAAM,CAAC,CAAC,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC,IAAI,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,GAAG,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC,YAAY,IAAI,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,KAAK,EAAE,CAC5N;iBACA,IAAI,CAAC,IAAI,CAAC;YACf,CAAC,CAAC,YAAY,CAAC;QAEjB,MAAM,iBAAiB,GAAG,aAAa,CAAC,MAAM,GAAG,CAAC;YAChD,CAAC,CAAC,aAAa;iBACV,GAAG,CACF,CAAC,CAAC,EAAE,EAAE,CACJ,MAAM,CAAC,CAAC,OAAO,MAAM,CAAC,CAAC,QAAQ,aAAa,CAAC,CAAC,YAAY,IAAI,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,KAAK,iBAAiB,CAAC,CAAC,WAAW,IAAI,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,KAAK,EAAE,CAC9K;iBACA,IAAI,CAAC,IAAI,CAAC;YACf,CAAC,CAAC,MAAM,CAAC;QAEX,MAAM,YAAY,GAAG,eAAe;YAClC,CAAC,CAAC,iCAAiC,eAAe,CAAC,IAAI,IAAI,EAAE,iBAAiB,eAAe,CAAC,QAAQ,IAAI,EAAE,sCAAsC,eAAe,CAAC,WAAW,CAAC,CAAC,CAAC,oBAAoB,CAAC,eAAe,CAAC,WAAW,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,KAAK;YAChP,CAAC,CAAC,EAAE,CAAC;QAEP,MAAM,MAAM,GAAG,aAAa,CAAC,cAAc,EAAE;YAC3C,OAAO,EAAE,GAAG,CAAC,IAAI;YACjB,eAAe,EAAE,GAAG,CAAC,eAAe,CAAC,IAAI,CAAC,IAAI,CAAC;YAC/C,WAAW,EAAE,eAAe;YAC5B,aAAa,EAAE,iBAAiB;YAChC,eAAe,EAAE,YAAY;SAC9B,CAAC,CAAC;QAEH,IAAI,CAAC;YACH,OAAO,MAAM,GAAG,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC;QACrC,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,OAAO,CACL,8CAA8C,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CACjG,CAAC;YACF,OAAO,IAAI,CAAC;QACd,CAAC;IACH,CAAC;IAEO,KAAK,CAAC,6BAA6B,CACzC,GAAiB,EACjB,GAAc,EACd,aAA4B;QAE5B,MAAM,QAAQ,GAAG;YACf,GAAG,GAAG,CAAC,eAAe;YACtB,GAAG,aAAa,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC;SACvC,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;QAEf,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC;YAAE,OAAO,IAAI,CAAC;QAEvC,MAAM,MAAM,GAAG,aAAa,CAAC,iBAAiB,EAAE;YAC9C,OAAO,EAAE,GAAG,CAAC,IAAI;YACjB,QAAQ,EAAE,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC;SAC9B,CAAC,CAAC;QAEH,IAAI,CAAC;YACH,OAAO,MAAM,GAAG,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC;QACrC,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,OAAO,CACL,wCAAwC,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAC3F,CAAC;YACF,OAAO,IAAI,CAAC;QACd,CAAC;IACH,CAAC;IAEO,KAAK,CAAC,6BAA6B,CACzC,GAAiB,EACjB,GAAc;QAEd,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,QAAQ,CAAC,KAAK,CAAC;YAAE,OAAO,IAAI,CAAC;QAE/C,MAAM,MAAM,GAAG,aAAa,CAAC,kBAAkB,EAAE;YAC/C,OAAO,EAAE,GAAG,CAAC,IAAI;YACjB,QAAQ,EAAE,GAAG,CAAC,eAAe,CAAC,IAAI,CAAC,IAAI,CAAC;SACzC,CAAC,CAAC;QAEH,IAAI,CAAC;YACH,OAAO,MAAM,GAAG,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC;QACrC,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,OAAO,CACL,2CAA2C,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAC9F,CAAC;YACF,OAAO,IAAI,CAAC;QACd,CAAC;IACH,CAAC;IAEO,KAAK,CAAC,kBAAkB,CAC9B,GAAc;QAEd,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,mBAAmB;YAAE,OAAO,IAAI,CAAC;QAC1D,IAAI,CAAC;YACH,IAAI,GAAG,CAAC,QAAQ,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,GAAG,CAAC,UAAU,EAAE,CAAC;gBACnD,OAAO,MAAM,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,mBAAmB,CACjD,GAAG,CAAC,UAAU,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,IAAI,CACtC,CAAC;YACJ,CAAC;QACH,CAAC;QAAC,MAAM,CAAC;YACP,sCAAsC;QACxC,CAAC;QACD,OAAO,IAAI,CAAC;IACd,CAAC;IAEO,YAAY,CAClB,GAAc,EACd,MAAoB,EACpB,WAAyB,EACzB,aAA4B,EAC5B,iBAAqC,EACrC,qBAAoC,EACpC,qBAAoC;QAEpC,MAAM,QAAQ,GAAG,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC;QACnC,MAAM,MAAM,GAAG,QAAQ;YACrB,CAAC,CAAC,sBAAsB,GAAG,CAAC,IAAI,GAAG;YACnC,CAAC,CAAC,aAAa,GAAG,CAAC,IAAI,GAAG,CAAC;QAC7B,MAAM,KAAK,GAAG,CAAC,MAAM,CAAC,CAAC;QAEvB,IAAI,QAAQ,EAAE,CAAC;YACb,MAAM,GAAG,GAAG,WAAW,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,IAAI,4BAA4B,CAAC,CAAC;YAC5E,IAAI,GAAG,EAAE,CAAC;gBACR,KAAK,CAAC,IAAI,CACR,MAAM,GAAG,CAAC,OAAO,UAAU,MAAM,CAAC,GAAG,CAAC,YAAY,CAAC,MAAM,MAAM,CAAC,GAAG,CAAC,WAAW,CAAC,WAAW,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAC/G,CAAC;YACJ,CAAC;QACH,CAAC;QAED,MAAM,MAAM,GAAG,WAAW,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,GAAG,CAAC,CAAC,CAAC;QACrD,IAAI,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACtB,KAAK,CAAC,IAAI,CACR,QAAQ,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,qBAAqB,MAAM,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,CAAC,OAAO,MAAM,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAC5I,CAAC;QACJ,CAAC;QAED,IAAI,aAAa,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAC7B,KAAK,CAAC,IAAI,CACR,QAAQ,MAAM,CAAC,aAAa,CAAC,MAAM,CAAC,uBAAuB,aAAa,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,CAAC,OAAO,GAAG,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAC/H,CAAC;QACJ,CAAC;QAED,IAAI,iBAAiB,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACjC,MAAM,KAAK,GAAG,iBAAiB,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC;YAC3D,KAAK,CAAC,IAAI,CAAC,6CAA6C,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QAC9E,CAAC;QAED,IAAI,qBAAqB,EAAE,CAAC;YAC1B,KAAK,CAAC,IAAI,CAAC,2CAA2C,CAAC,CAAC;QAC1D,CAAC;QAED,IAAI,qBAAqB,EAAE,CAAC;YAC1B,KAAK,CAAC,IAAI,CAAC,sCAAsC,CAAC,CAAC;QACrD,CAAC;QAED,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACvB,KAAK,CAAC,IAAI,CAAC,2BAA2B,CAAC,CAAC;QAC1C,CAAC;QAED,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC1B,CAAC;CACF"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Content Skill โ generates weekly content drafts (short-form scripts,
|
|
3
|
+
* Pinterest pins, blog posts). Uses Claude CLI instead of the
|
|
4
|
+
* Anthropic SDK directly (growth-agent used SDK; adaria-ai standardizes
|
|
5
|
+
* on CLI runner for all Claude calls).
|
|
6
|
+
*
|
|
7
|
+
* Ported from growth-agent `src/agents/content-agent.js`.
|
|
8
|
+
*
|
|
9
|
+
* NOTE: This skill overlaps with ShortFormSkill. The checklist notes
|
|
10
|
+
* "Port or fold into short-form.ts โ decide during port." Decision:
|
|
11
|
+
* keep separate because ContentAgent generates Pinterest pins and
|
|
12
|
+
* trend-research content that ShortFormSkill doesn't cover.
|
|
13
|
+
*/
|
|
14
|
+
import type { Skill } from "./index.js";
|
|
15
|
+
import type { SkillContext, SkillResult } from "../types/skill.js";
|
|
16
|
+
import type { AppConfig } from "../config/apps-schema.js";
|
|
17
|
+
export declare class ContentSkill implements Skill {
|
|
18
|
+
readonly name = "content";
|
|
19
|
+
readonly commands: readonly ["content"];
|
|
20
|
+
dispatch(ctx: SkillContext, text: string): Promise<SkillResult>;
|
|
21
|
+
generate(ctx: SkillContext, app: AppConfig): Promise<SkillResult>;
|
|
22
|
+
private generateShortFormScripts;
|
|
23
|
+
private generatePinterestPins;
|
|
24
|
+
}
|
|
25
|
+
//# sourceMappingURL=content.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"content.d.ts","sourceRoot":"","sources":["../../src/skills/content.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AAExC,OAAO,KAAK,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AACnE,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,0BAA0B,CAAC;AAG1D,qBAAa,YAAa,YAAW,KAAK;IACxC,QAAQ,CAAC,IAAI,aAAa;IAC1B,QAAQ,CAAC,QAAQ,uBAAwB;IAEnC,QAAQ,CAAC,GAAG,EAAE,YAAY,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC;IAiB/D,QAAQ,CAAC,GAAG,EAAE,YAAY,EAAE,GAAG,EAAE,SAAS,GAAG,OAAO,CAAC,WAAW,CAAC;YAiBzD,wBAAwB;YA+BxB,qBAAqB;CAyBpC"}
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Content Skill โ generates weekly content drafts (short-form scripts,
|
|
3
|
+
* Pinterest pins, blog posts). Uses Claude CLI instead of the
|
|
4
|
+
* Anthropic SDK directly (growth-agent used SDK; adaria-ai standardizes
|
|
5
|
+
* on CLI runner for all Claude calls).
|
|
6
|
+
*
|
|
7
|
+
* Ported from growth-agent `src/agents/content-agent.js`.
|
|
8
|
+
*
|
|
9
|
+
* NOTE: This skill overlaps with ShortFormSkill. The checklist notes
|
|
10
|
+
* "Port or fold into short-form.ts โ decide during port." Decision:
|
|
11
|
+
* keep separate because ContentAgent generates Pinterest pins and
|
|
12
|
+
* trend-research content that ShortFormSkill doesn't cover.
|
|
13
|
+
*/
|
|
14
|
+
import { parseAppNameFromCommand } from "./index.js";
|
|
15
|
+
import { warn as logWarn } from "../utils/logger.js";
|
|
16
|
+
export class ContentSkill {
|
|
17
|
+
name = "content";
|
|
18
|
+
commands = ["content"];
|
|
19
|
+
async dispatch(ctx, text) {
|
|
20
|
+
const appName = parseAppNameFromCommand(text);
|
|
21
|
+
const app = appName
|
|
22
|
+
? ctx.apps.find((a) => a.id.toLowerCase() === appName)
|
|
23
|
+
: ctx.apps[0];
|
|
24
|
+
if (!app) {
|
|
25
|
+
return {
|
|
26
|
+
summary: appName ? `โ App "${appName}" not found.` : "โ No apps configured.",
|
|
27
|
+
alerts: [],
|
|
28
|
+
approvals: [],
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
return this.generate(ctx, app);
|
|
32
|
+
}
|
|
33
|
+
async generate(ctx, app) {
|
|
34
|
+
const trendKeywords = app.primaryKeywords.slice(0, 10);
|
|
35
|
+
// Generate content types in parallel
|
|
36
|
+
const [scripts, pins] = await Promise.all([
|
|
37
|
+
this.generateShortFormScripts(ctx, app, trendKeywords, 3),
|
|
38
|
+
this.generatePinterestPins(ctx, app, trendKeywords, 5),
|
|
39
|
+
]);
|
|
40
|
+
const lines = [`*๐ข Content โ ${app.name}*`];
|
|
41
|
+
lines.push(`โข ${String(scripts.length)} short-form scripts ยท ${String(pins.length)} Pinterest pins`);
|
|
42
|
+
return { summary: lines.join("\n"), alerts: [], approvals: [] };
|
|
43
|
+
}
|
|
44
|
+
async generateShortFormScripts(ctx, app, keywords, count) {
|
|
45
|
+
const prompt = `Generate ${String(count)} short-form video scripts (TikTok/Reels) to promote the ${app.name} app.
|
|
46
|
+
|
|
47
|
+
## App: ${app.name}
|
|
48
|
+
## Target keywords: ${keywords.join(", ")}
|
|
49
|
+
|
|
50
|
+
## Production guide
|
|
51
|
+
- Format: faceless โ screen recording, text overlays, AI voiceover
|
|
52
|
+
- Hook (first 3s): start with a problem statement, shocking stat, or question
|
|
53
|
+
- Body (15-25s): walk through app usage step by step
|
|
54
|
+
- CTA: "Link in bio" or "Search in the App Store"
|
|
55
|
+
- Each script should use a different angle
|
|
56
|
+
|
|
57
|
+
Respond with JSON only:
|
|
58
|
+
[{"title":"...","hook":"...","body":"...","cta":"...","hashtags":["#tag1"]}]`;
|
|
59
|
+
try {
|
|
60
|
+
const raw = await ctx.runClaude(prompt);
|
|
61
|
+
const parsed = JSON.parse(raw);
|
|
62
|
+
return Array.isArray(parsed) ? parsed : [];
|
|
63
|
+
}
|
|
64
|
+
catch (err) {
|
|
65
|
+
logWarn(`[content] Short-form script generation failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
66
|
+
return [];
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
async generatePinterestPins(ctx, app, keywords, count) {
|
|
70
|
+
const prompt = `Generate ${String(count)} Pinterest pin copies for the ${app.name} app.
|
|
71
|
+
|
|
72
|
+
App: ${app.name}
|
|
73
|
+
Related keywords: ${keywords.join(", ")}
|
|
74
|
+
|
|
75
|
+
Each pin must include a title, description, and hashtags. Write in English.
|
|
76
|
+
|
|
77
|
+
Respond with JSON only:
|
|
78
|
+
[{"title":"Pin title","description":"Pin description","hashtags":["#tag1"]}]`;
|
|
79
|
+
try {
|
|
80
|
+
const raw = await ctx.runClaude(prompt);
|
|
81
|
+
const parsed = JSON.parse(raw);
|
|
82
|
+
return Array.isArray(parsed) ? parsed : [];
|
|
83
|
+
}
|
|
84
|
+
catch (err) {
|
|
85
|
+
logWarn(`[content] Pinterest pin generation failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
86
|
+
return [];
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
//# sourceMappingURL=content.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"content.js","sourceRoot":"","sources":["../../src/skills/content.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Skill registry.
|
|
3
|
+
*
|
|
4
|
+
* A "skill" is a code-defined, domain-specific handler that reacts to
|
|
5
|
+
* explicit Slack commands (Mode A). Skills are heavy, may gate write paths
|
|
6
|
+
* through `ApprovalManager`, and are NOT exposed as MCP tools.
|
|
7
|
+
*
|
|
8
|
+
* M4 upgraded the Skill interface from `dispatch(text)` โ `dispatch(ctx, text)`
|
|
9
|
+
* with a `SkillResult` return type. PlaceholderSkill still exists for
|
|
10
|
+
* skills not yet ported (M5 will remove it).
|
|
11
|
+
*/
|
|
12
|
+
import type { SkillContext, SkillResult } from "../types/skill.js";
|
|
13
|
+
export interface Skill {
|
|
14
|
+
/** Human-readable name (used in logs and Slack messages). */
|
|
15
|
+
readonly name: string;
|
|
16
|
+
/**
|
|
17
|
+
* Command words that trigger this skill when they appear as the first
|
|
18
|
+
* whitespace-separated token of a Slack message (case-insensitive).
|
|
19
|
+
*/
|
|
20
|
+
readonly commands: readonly string[];
|
|
21
|
+
/**
|
|
22
|
+
* Executes the skill with the shared context and the raw message text.
|
|
23
|
+
* The skill is responsible for parsing the app name from `text` and
|
|
24
|
+
* looking it up in `ctx.apps`.
|
|
25
|
+
*/
|
|
26
|
+
dispatch(ctx: SkillContext, text: string): Promise<SkillResult>;
|
|
27
|
+
}
|
|
28
|
+
export declare class SkillRegistry {
|
|
29
|
+
private skills;
|
|
30
|
+
register(skill: Skill): void;
|
|
31
|
+
/**
|
|
32
|
+
* Returns the skill whose `commands` match the first token of `text`,
|
|
33
|
+
* or `null` if no skill matches. Matching is case-insensitive.
|
|
34
|
+
*/
|
|
35
|
+
findSkill(text: string): Skill | null;
|
|
36
|
+
private findSkillByCommand;
|
|
37
|
+
getSkills(): readonly Skill[];
|
|
38
|
+
getSkillCount(): number;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Placeholder skill for commands not yet ported. Returns a clear
|
|
42
|
+
* "not implemented" message so the operator can verify Mode A plumbing.
|
|
43
|
+
* M5 removes this once all skills are real.
|
|
44
|
+
*/
|
|
45
|
+
export declare class PlaceholderSkill implements Skill {
|
|
46
|
+
readonly name: string;
|
|
47
|
+
readonly commands: readonly string[];
|
|
48
|
+
constructor(name: string, commands: readonly string[]);
|
|
49
|
+
dispatch(_ctx: SkillContext, _text: string): Promise<SkillResult>;
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Builds an M1 placeholder registry. Every command word that M4โM6 will
|
|
53
|
+
* eventually recognize is mapped to a no-op skill that returns a clear
|
|
54
|
+
* "not implemented" message, so the operator can verify Mode A plumbing
|
|
55
|
+
* (reactions, status evolution, audit log) before any real skill lands.
|
|
56
|
+
*/
|
|
57
|
+
export declare function createM1PlaceholderRegistry(): SkillRegistry;
|
|
58
|
+
/**
|
|
59
|
+
* Parse the app name from the second token of a command string.
|
|
60
|
+
* Returns `undefined` if no second token is present.
|
|
61
|
+
*
|
|
62
|
+
* Example: `"aso fridgify"` โ `"fridgify"`
|
|
63
|
+
*/
|
|
64
|
+
export declare function parseAppNameFromCommand(text: string): string | undefined;
|
|
65
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/skills/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAEnE,MAAM,WAAW,KAAK;IACpB,6DAA6D;IAC7D,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB;;;OAGG;IACH,QAAQ,CAAC,QAAQ,EAAE,SAAS,MAAM,EAAE,CAAC;IACrC;;;;OAIG;IACH,QAAQ,CAAC,GAAG,EAAE,YAAY,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC,CAAC;CACjE;AAED,qBAAa,aAAa;IACxB,OAAO,CAAC,MAAM,CAAe;IAE7B,QAAQ,CAAC,KAAK,EAAE,KAAK,GAAG,IAAI;IAW5B;;;OAGG;IACH,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,KAAK,GAAG,IAAI;IAMrC,OAAO,CAAC,kBAAkB;IAS1B,SAAS,IAAI,SAAS,KAAK,EAAE;IAI7B,aAAa,IAAI,MAAM;CAGxB;AAED;;;;GAIG;AACH,qBAAa,gBAAiB,YAAW,KAAK;IAE1C,QAAQ,CAAC,IAAI,EAAE,MAAM;IACrB,QAAQ,CAAC,QAAQ,EAAE,SAAS,MAAM,EAAE;gBAD3B,IAAI,EAAE,MAAM,EACZ,QAAQ,EAAE,SAAS,MAAM,EAAE;IAGtC,QAAQ,CAAC,IAAI,EAAE,YAAY,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC;CAOlE;AAED;;;;;GAKG;AACH,wBAAgB,2BAA2B,IAAI,aAAa,CAc3D;AAED;;;;;GAKG;AACH,wBAAgB,uBAAuB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAGxE"}
|