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
package/dist/index.js
ADDED
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { readFileSync } from "node:fs";
|
|
3
|
+
import { Command } from "commander";
|
|
4
|
+
import { PACKAGE_JSON_PATH } from "./utils/paths.js";
|
|
5
|
+
const pkg = JSON.parse(readFileSync(PACKAGE_JSON_PATH, "utf-8"));
|
|
6
|
+
const program = new Command();
|
|
7
|
+
program
|
|
8
|
+
.name("adaria-ai")
|
|
9
|
+
.description(pkg.description ??
|
|
10
|
+
"Marketing operations agent for the Adaria.ai app portfolio")
|
|
11
|
+
.version(pkg.version);
|
|
12
|
+
program
|
|
13
|
+
.command("init [section]")
|
|
14
|
+
.description("Interactive setup wizard (sections: slack, collectors, social)")
|
|
15
|
+
.action(async (section) => {
|
|
16
|
+
const { runInit } = await import("./cli/init.js");
|
|
17
|
+
const validSections = ["slack", "collectors", "social"];
|
|
18
|
+
if (section && !validSections.includes(section)) {
|
|
19
|
+
console.error(`Unknown section: ${section}. Valid: ${validSections.join(", ")}`);
|
|
20
|
+
process.exit(1);
|
|
21
|
+
}
|
|
22
|
+
await runInit(section);
|
|
23
|
+
process.exit(0);
|
|
24
|
+
});
|
|
25
|
+
program
|
|
26
|
+
.command("daemon")
|
|
27
|
+
.description("Run the reactive Slack daemon in foreground (launchd entry)")
|
|
28
|
+
.action(async () => {
|
|
29
|
+
const { runDaemon } = await import("./cli/daemon.js");
|
|
30
|
+
await runDaemon();
|
|
31
|
+
});
|
|
32
|
+
program
|
|
33
|
+
.command("start")
|
|
34
|
+
.description("Load the adaria-ai daemon into launchd")
|
|
35
|
+
.action(async () => {
|
|
36
|
+
const { runStart } = await import("./cli/start.js");
|
|
37
|
+
await runStart();
|
|
38
|
+
});
|
|
39
|
+
program
|
|
40
|
+
.command("stop")
|
|
41
|
+
.description("Unload the adaria-ai daemon from launchd")
|
|
42
|
+
.action(async () => {
|
|
43
|
+
const { runStop } = await import("./cli/stop.js");
|
|
44
|
+
await runStop();
|
|
45
|
+
});
|
|
46
|
+
program
|
|
47
|
+
.command("status")
|
|
48
|
+
.description("Show launchd status for the adaria-ai daemon")
|
|
49
|
+
.action(async () => {
|
|
50
|
+
const { runStatus } = await import("./cli/status.js");
|
|
51
|
+
await runStatus();
|
|
52
|
+
});
|
|
53
|
+
program
|
|
54
|
+
.command("logs")
|
|
55
|
+
.description("Print (or follow) ~/.adaria/logs/adaria-YYYY-MM-DD.log")
|
|
56
|
+
.option("-f, --follow", "Follow log output")
|
|
57
|
+
.action(async (opts) => {
|
|
58
|
+
const { runLogs } = await import("./cli/logs.js");
|
|
59
|
+
await runLogs(opts);
|
|
60
|
+
});
|
|
61
|
+
program
|
|
62
|
+
.command("analyze")
|
|
63
|
+
.description("Run the weekly orchestrator (one-shot, launchd cron entry)")
|
|
64
|
+
.action(async () => {
|
|
65
|
+
const { runAnalyze } = await import("./cli/analyze.js");
|
|
66
|
+
await runAnalyze();
|
|
67
|
+
});
|
|
68
|
+
program
|
|
69
|
+
.command("monitor")
|
|
70
|
+
.description("Run the daily monitor (one-shot, launchd cron entry)")
|
|
71
|
+
.action(async () => {
|
|
72
|
+
const { runMonitorCmd } = await import("./cli/monitor-cmd.js");
|
|
73
|
+
await runMonitorCmd();
|
|
74
|
+
});
|
|
75
|
+
program
|
|
76
|
+
.command("doctor")
|
|
77
|
+
.description("Run health checks against config, Claude CLI, and allowlist")
|
|
78
|
+
.action(async () => {
|
|
79
|
+
const { runDoctor } = await import("./cli/doctor.js");
|
|
80
|
+
await runDoctor();
|
|
81
|
+
});
|
|
82
|
+
program.parseAsync().catch((err) => {
|
|
83
|
+
console.error(err instanceof Error ? err.message : String(err));
|
|
84
|
+
process.exit(1);
|
|
85
|
+
});
|
|
86
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Platform-agnostic messenger interface. adaria-ai v1 only implements Slack,
|
|
3
|
+
* but the adapter layer stays generic so Telegram or another messenger can
|
|
4
|
+
* slot in without refactoring consumers.
|
|
5
|
+
*/
|
|
6
|
+
export interface ImageAttachment {
|
|
7
|
+
url: string;
|
|
8
|
+
mimeType: string;
|
|
9
|
+
filename?: string;
|
|
10
|
+
/** HTTP header required to fetch the URL (e.g. "Bearer xoxb-..."). */
|
|
11
|
+
authHeader?: string;
|
|
12
|
+
}
|
|
13
|
+
export interface IncomingMessage {
|
|
14
|
+
platform: "slack";
|
|
15
|
+
/** Platform user ID (Slack `U...` or equivalent). Checked against allowlist. */
|
|
16
|
+
userId: string;
|
|
17
|
+
channelId: string;
|
|
18
|
+
/** Thread root timestamp — the message to reply under. */
|
|
19
|
+
threadId?: string;
|
|
20
|
+
/**
|
|
21
|
+
* Raw Slack event timestamp (`event.ts`) — present on messages originated
|
|
22
|
+
* by a real Slack event. Required for adding reactions, updating the
|
|
23
|
+
* message in place, and deduping. Kept distinct from `timestamp` so we
|
|
24
|
+
* don't round-trip through Date and lose precision.
|
|
25
|
+
*
|
|
26
|
+
* Optional because M1e/M6 may re-inject synthetic messages (approval
|
|
27
|
+
* button callbacks, cron-initiated analyses) that have no originating
|
|
28
|
+
* event. Consumers that need to addReaction/updateText must guard with
|
|
29
|
+
* `if (msg.eventTs)` — the growth-agent Phase 1 lesson is "don't
|
|
30
|
+
* reconstruct from Date", not "every message must have one".
|
|
31
|
+
*/
|
|
32
|
+
eventTs?: string;
|
|
33
|
+
text: string;
|
|
34
|
+
images?: ImageAttachment[];
|
|
35
|
+
/** Human-readable timestamp for logging and UX. */
|
|
36
|
+
timestamp: Date;
|
|
37
|
+
}
|
|
38
|
+
export interface MessengerAdapter {
|
|
39
|
+
/** Start the connection to the platform. */
|
|
40
|
+
start(): Promise<void>;
|
|
41
|
+
/** Stop the connection cleanly. */
|
|
42
|
+
stop(): Promise<void>;
|
|
43
|
+
/** Register the incoming message callback. */
|
|
44
|
+
onMessage(handler: (msg: IncomingMessage) => void | Promise<void>): void;
|
|
45
|
+
/** Send a text message. Returns the new message ID (ts on Slack). */
|
|
46
|
+
sendText(channelId: string, text: string, threadId?: string): Promise<string>;
|
|
47
|
+
/** Update an existing message by its ID. */
|
|
48
|
+
updateText(channelId: string, messageId: string, text: string, threadId?: string): Promise<void>;
|
|
49
|
+
/**
|
|
50
|
+
* Send a message with Slack Block Kit blocks. `fallbackText` is shown
|
|
51
|
+
* in notifications and non-Block-Kit clients.
|
|
52
|
+
*/
|
|
53
|
+
sendBlocks?(channelId: string, fallbackText: string, blocks: readonly Record<string, unknown>[], threadId?: string): Promise<string>;
|
|
54
|
+
/** Add a reaction to a message (best-effort; no-op if unsupported). */
|
|
55
|
+
addReaction?(channelId: string, messageTs: string, emoji: string): Promise<void>;
|
|
56
|
+
/** Remove a reaction from a message (best-effort; no-op if unsupported). */
|
|
57
|
+
removeReaction?(channelId: string, messageTs: string, emoji: string): Promise<void>;
|
|
58
|
+
/** Send an approval message with Approve/Reject buttons. */
|
|
59
|
+
sendApproval(channelId: string, text: string, taskId: string, threadId?: string): Promise<void>;
|
|
60
|
+
/** Register the approval/rejection callback. */
|
|
61
|
+
onApproval(handler: (taskId: string, approved: boolean) => void): void;
|
|
62
|
+
}
|
|
63
|
+
//# sourceMappingURL=adapter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"adapter.d.ts","sourceRoot":"","sources":["../../src/messenger/adapter.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,MAAM,WAAW,eAAe;IAC9B,GAAG,EAAE,MAAM,CAAC;IACZ,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,sEAAsE;IACtE,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,eAAe;IAC9B,QAAQ,EAAE,OAAO,CAAC;IAClB,gFAAgF;IAChF,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;IAClB,0DAA0D;IAC1D,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB;;;;;;;;;;;OAWG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,CAAC,EAAE,eAAe,EAAE,CAAC;IAC3B,mDAAmD;IACnD,SAAS,EAAE,IAAI,CAAC;CACjB;AAED,MAAM,WAAW,gBAAgB;IAC/B,4CAA4C;IAC5C,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IAEvB,mCAAmC;IACnC,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IAEtB,8CAA8C;IAC9C,SAAS,CAAC,OAAO,EAAE,CAAC,GAAG,EAAE,eAAe,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;IAEzE,qEAAqE;IACrE,QAAQ,CACN,SAAS,EAAE,MAAM,EACjB,IAAI,EAAE,MAAM,EACZ,QAAQ,CAAC,EAAE,MAAM,GAChB,OAAO,CAAC,MAAM,CAAC,CAAC;IAEnB,4CAA4C;IAC5C,UAAU,CACR,SAAS,EAAE,MAAM,EACjB,SAAS,EAAE,MAAM,EACjB,IAAI,EAAE,MAAM,EACZ,QAAQ,CAAC,EAAE,MAAM,GAChB,OAAO,CAAC,IAAI,CAAC,CAAC;IAEjB;;;OAGG;IACH,UAAU,CAAC,CACT,SAAS,EAAE,MAAM,EACjB,YAAY,EAAE,MAAM,EACpB,MAAM,EAAE,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,EAC1C,QAAQ,CAAC,EAAE,MAAM,GAChB,OAAO,CAAC,MAAM,CAAC,CAAC;IAEnB,uEAAuE;IACvE,WAAW,CAAC,CACV,SAAS,EAAE,MAAM,EACjB,SAAS,EAAE,MAAM,EACjB,KAAK,EAAE,MAAM,GACZ,OAAO,CAAC,IAAI,CAAC,CAAC;IAEjB,4EAA4E;IAC5E,cAAc,CAAC,CACb,SAAS,EAAE,MAAM,EACjB,SAAS,EAAE,MAAM,EACjB,KAAK,EAAE,MAAM,GACZ,OAAO,CAAC,IAAI,CAAC,CAAC;IAEjB,4DAA4D;IAC5D,YAAY,CACV,SAAS,EAAE,MAAM,EACjB,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,MAAM,EACd,QAAQ,CAAC,EAAE,MAAM,GAChB,OAAO,CAAC,IAAI,CAAC,CAAC;IAEjB,gDAAgD;IAChD,UAAU,CAAC,OAAO,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,OAAO,KAAK,IAAI,GAAG,IAAI,CAAC;CACxE"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"adapter.js","sourceRoot":"","sources":["../../src/messenger/adapter.ts"],"names":[],"mappings":"AAAA;;;;GAIG"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Messenger factory.
|
|
3
|
+
*
|
|
4
|
+
* adaria-ai v1 is Slack-only. The factory stays here (rather than
|
|
5
|
+
* inlining `new SlackAdapter(...)` in `cli/daemon.ts`) so that when a
|
|
6
|
+
* second platform ever lands, only this one file needs to grow a
|
|
7
|
+
* switch, not every daemon entry point.
|
|
8
|
+
*/
|
|
9
|
+
import type { AdariaConfig } from "../config/schema.js";
|
|
10
|
+
import type { MessengerAdapter } from "./adapter.js";
|
|
11
|
+
export declare function createMessengerAdapter(config: AdariaConfig): MessengerAdapter;
|
|
12
|
+
//# sourceMappingURL=factory.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"factory.d.ts","sourceRoot":"","sources":["../../src/messenger/factory.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AACxD,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAGrD,wBAAgB,sBAAsB,CACpC,MAAM,EAAE,YAAY,GACnB,gBAAgB,CAMlB"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { SlackAdapter } from "./slack.js";
|
|
2
|
+
export function createMessengerAdapter(config) {
|
|
3
|
+
return new SlackAdapter({
|
|
4
|
+
botToken: config.slack.botToken,
|
|
5
|
+
appToken: config.slack.appToken,
|
|
6
|
+
signingSecret: config.slack.signingSecret,
|
|
7
|
+
});
|
|
8
|
+
}
|
|
9
|
+
//# sourceMappingURL=factory.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"factory.js","sourceRoot":"","sources":["../../src/messenger/factory.ts"],"names":[],"mappings":"AAUA,OAAO,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAE1C,MAAM,UAAU,sBAAsB,CACpC,MAAoB;IAEpB,OAAO,IAAI,YAAY,CAAC;QACtB,QAAQ,EAAE,MAAM,CAAC,KAAK,CAAC,QAAQ;QAC/B,QAAQ,EAAE,MAAM,CAAC,KAAK,CAAC,QAAQ;QAC/B,aAAa,EAAE,MAAM,CAAC,KAAK,CAAC,aAAa;KAC1C,CAAC,CAAC;AACL,CAAC"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import type { IncomingMessage, MessengerAdapter } from "./adapter.js";
|
|
2
|
+
export interface SlackAdapterConfig {
|
|
3
|
+
botToken: string;
|
|
4
|
+
appToken: string;
|
|
5
|
+
signingSecret: string;
|
|
6
|
+
}
|
|
7
|
+
export declare class SlackAdapter implements MessengerAdapter {
|
|
8
|
+
private readonly app;
|
|
9
|
+
private readonly botToken;
|
|
10
|
+
private messageHandler?;
|
|
11
|
+
private approvalHandler?;
|
|
12
|
+
private readonly rateLimiter;
|
|
13
|
+
private processedMessages;
|
|
14
|
+
constructor(config: SlackAdapterConfig);
|
|
15
|
+
/** Returns true if `ts` has been seen before (i.e. is a dupe). */
|
|
16
|
+
private isDuplicate;
|
|
17
|
+
private setupListeners;
|
|
18
|
+
private extractImages;
|
|
19
|
+
start(): Promise<void>;
|
|
20
|
+
stop(): Promise<void>;
|
|
21
|
+
onMessage(handler: (msg: IncomingMessage) => void | Promise<void>): void;
|
|
22
|
+
onApproval(handler: (taskId: string, approved: boolean) => void): void;
|
|
23
|
+
sendText(channelId: string, text: string, threadId?: string): Promise<string>;
|
|
24
|
+
updateText(channelId: string, messageId: string, text: string, threadId?: string): Promise<void>;
|
|
25
|
+
sendApproval(channelId: string, text: string, taskId: string, threadId?: string): Promise<void>;
|
|
26
|
+
sendBlocks(channelId: string, fallbackText: string, blocks: readonly Record<string, unknown>[], threadId?: string): Promise<string>;
|
|
27
|
+
addReaction(channelId: string, messageTs: string, emoji: string): Promise<void>;
|
|
28
|
+
removeReaction(channelId: string, messageTs: string, emoji: string): Promise<void>;
|
|
29
|
+
}
|
|
30
|
+
//# sourceMappingURL=slack.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"slack.d.ts","sourceRoot":"","sources":["../../src/messenger/slack.ts"],"names":[],"mappings":"AAoBA,OAAO,KAAK,EAEV,eAAe,EACf,gBAAgB,EACjB,MAAM,cAAc,CAAC;AAStB,MAAM,WAAW,kBAAkB;IACjC,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,aAAa,EAAE,MAAM,CAAC;CACvB;AAMD,qBAAa,YAAa,YAAW,gBAAgB;IACnD,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAM;IAC1B,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAS;IAClC,OAAO,CAAC,cAAc,CAAC,CAAiD;IACxE,OAAO,CAAC,eAAe,CAAC,CAA8C;IAGtE,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAyB;IAGrD,OAAO,CAAC,iBAAiB,CAAqB;gBAElC,MAAM,EAAE,kBAAkB;IAoBtC,kEAAkE;IAClE,OAAO,CAAC,WAAW;IAWnB,OAAO,CAAC,cAAc;IAiGtB,OAAO,CAAC,aAAa;IAkBf,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAMtB,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAK3B,SAAS,CAAC,OAAO,EAAE,CAAC,GAAG,EAAE,eAAe,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI;IAIxE,UAAU,CAAC,OAAO,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,OAAO,KAAK,IAAI,GAAG,IAAI;IAIhE,QAAQ,CACZ,SAAS,EAAE,MAAM,EACjB,IAAI,EAAE,MAAM,EACZ,QAAQ,CAAC,EAAE,MAAM,GAChB,OAAO,CAAC,MAAM,CAAC;IAeZ,UAAU,CACd,SAAS,EAAE,MAAM,EACjB,SAAS,EAAE,MAAM,EACjB,IAAI,EAAE,MAAM,EACZ,QAAQ,CAAC,EAAE,MAAM,GAChB,OAAO,CAAC,IAAI,CAAC;IAoBV,YAAY,CAChB,SAAS,EAAE,MAAM,EACjB,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,MAAM,EACd,QAAQ,CAAC,EAAE,MAAM,GAChB,OAAO,CAAC,IAAI,CAAC;IAsDV,UAAU,CACd,SAAS,EAAE,MAAM,EACjB,YAAY,EAAE,MAAM,EACpB,MAAM,EAAE,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,EAC1C,QAAQ,CAAC,EAAE,MAAM,GAChB,OAAO,CAAC,MAAM,CAAC;IAYZ,WAAW,CACf,SAAS,EAAE,MAAM,EACjB,SAAS,EAAE,MAAM,EACjB,KAAK,EAAE,MAAM,GACZ,OAAO,CAAC,IAAI,CAAC;IAkBV,cAAc,CAClB,SAAS,EAAE,MAAM,EACjB,SAAS,EAAE,MAAM,EACjB,KAAK,EAAE,MAAM,GACZ,OAAO,CAAC,IAAI,CAAC;CAajB"}
|
|
@@ -0,0 +1,309 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Slack adapter — Socket Mode + Bolt.
|
|
3
|
+
*
|
|
4
|
+
* Ports pilot-ai's `SlackAdapter` with the adaria-ai adjustments called
|
|
5
|
+
* for in the porting matrix and the messenger interface review:
|
|
6
|
+
*
|
|
7
|
+
* 1. `eventTs` field is populated on every outbound `IncomingMessage`.
|
|
8
|
+
* pilot-ai only set `threadId`, which forced `core.ts` to fall back
|
|
9
|
+
* to the thread root for reactions — the growth-agent Phase 1 bug
|
|
10
|
+
* that motivated adding `eventTs` to the adapter interface in the
|
|
11
|
+
* first place.
|
|
12
|
+
* 2. Telegram is dropped (adaria-ai is Slack-only in v1).
|
|
13
|
+
* 3. `console.log`/`console.error` are replaced with the adaria-ai
|
|
14
|
+
* structured logger so launchd's combined `stderr` file remains
|
|
15
|
+
* readable.
|
|
16
|
+
* 4. Bot token is no longer stashed on the instance — we pull it from
|
|
17
|
+
* config at construction time only, so there's no long-lived
|
|
18
|
+
* reference to it outside the Bolt client.
|
|
19
|
+
*/
|
|
20
|
+
import { App } from "@slack/bolt";
|
|
21
|
+
import { splitMessage, MAX_MESSAGE_LENGTH } from "./split.js";
|
|
22
|
+
import { RateLimiter } from "../utils/rate-limiter.js";
|
|
23
|
+
import { debug as logDebug, info as logInfo, error as logError, } from "../utils/logger.js";
|
|
24
|
+
/** Upper bound on the dedup Set before we trim it in half. */
|
|
25
|
+
const DEDUP_HIGH_WATER_MARK = 1000;
|
|
26
|
+
const DEDUP_TRIM_TO = 500;
|
|
27
|
+
export class SlackAdapter {
|
|
28
|
+
app;
|
|
29
|
+
botToken;
|
|
30
|
+
messageHandler;
|
|
31
|
+
approvalHandler;
|
|
32
|
+
// Slack tier 2 "posting" API allows roughly 1 message per second to a
|
|
33
|
+
// given channel; 5 is a reasonable burst before back-pressure.
|
|
34
|
+
rateLimiter = new RateLimiter(5, 1);
|
|
35
|
+
// Dedup across `message` and `app_mention` — Slack delivers both for a
|
|
36
|
+
// channel mention, and we only want to process each `ts` once.
|
|
37
|
+
processedMessages = new Set();
|
|
38
|
+
constructor(config) {
|
|
39
|
+
this.botToken = config.botToken;
|
|
40
|
+
this.app = new App({
|
|
41
|
+
token: config.botToken,
|
|
42
|
+
appToken: config.appToken,
|
|
43
|
+
signingSecret: config.signingSecret,
|
|
44
|
+
socketMode: true,
|
|
45
|
+
logLevel: "INFO",
|
|
46
|
+
});
|
|
47
|
+
this.app.error((err) => {
|
|
48
|
+
logError(`Slack unhandled error: ${err instanceof Error ? err.message : String(err)}`);
|
|
49
|
+
return Promise.resolve();
|
|
50
|
+
});
|
|
51
|
+
this.setupListeners();
|
|
52
|
+
}
|
|
53
|
+
/** Returns true if `ts` has been seen before (i.e. is a dupe). */
|
|
54
|
+
isDuplicate(ts) {
|
|
55
|
+
if (!ts)
|
|
56
|
+
return false;
|
|
57
|
+
if (this.processedMessages.has(ts))
|
|
58
|
+
return true;
|
|
59
|
+
this.processedMessages.add(ts);
|
|
60
|
+
if (this.processedMessages.size > DEDUP_HIGH_WATER_MARK) {
|
|
61
|
+
const entries = [...this.processedMessages];
|
|
62
|
+
this.processedMessages = new Set(entries.slice(-DEDUP_TRIM_TO));
|
|
63
|
+
}
|
|
64
|
+
return false;
|
|
65
|
+
}
|
|
66
|
+
setupListeners() {
|
|
67
|
+
this.app.message(({ message }) => {
|
|
68
|
+
const handler = this.messageHandler;
|
|
69
|
+
if (!handler)
|
|
70
|
+
return Promise.resolve();
|
|
71
|
+
// Only plain messages and file-share wrappers. Bot messages,
|
|
72
|
+
// channel_join, edits, etc. are subtyped and get ignored.
|
|
73
|
+
const subtype = message.subtype;
|
|
74
|
+
if (subtype && subtype !== "file_share") {
|
|
75
|
+
return Promise.resolve();
|
|
76
|
+
}
|
|
77
|
+
const msg = message;
|
|
78
|
+
if (!msg.user)
|
|
79
|
+
return Promise.resolve();
|
|
80
|
+
if (!msg.text && !msg.files?.length)
|
|
81
|
+
return Promise.resolve();
|
|
82
|
+
const eventTs = msg.ts ?? "";
|
|
83
|
+
if (this.isDuplicate(eventTs))
|
|
84
|
+
return Promise.resolve();
|
|
85
|
+
const images = this.extractImages(msg.files);
|
|
86
|
+
// file_share events with no text and no image attachments (e.g. a
|
|
87
|
+
// PDF drop) would otherwise reach core.ts as a mention with an
|
|
88
|
+
// empty prompt, triggering the full Thinking → Claude pipeline on
|
|
89
|
+
// a zero-byte query (M1 messenger review MED #1).
|
|
90
|
+
if (!msg.text && images.length === 0)
|
|
91
|
+
return Promise.resolve();
|
|
92
|
+
const incoming = {
|
|
93
|
+
platform: "slack",
|
|
94
|
+
userId: msg.user,
|
|
95
|
+
channelId: msg.channel ?? "",
|
|
96
|
+
text: msg.text ?? "",
|
|
97
|
+
eventTs,
|
|
98
|
+
timestamp: new Date(parseFloat(eventTs || "0") * 1000),
|
|
99
|
+
};
|
|
100
|
+
const threadId = msg.thread_ts ?? eventTs;
|
|
101
|
+
if (threadId)
|
|
102
|
+
incoming.threadId = threadId;
|
|
103
|
+
if (images.length > 0)
|
|
104
|
+
incoming.images = images;
|
|
105
|
+
return Promise.resolve(handler(incoming));
|
|
106
|
+
});
|
|
107
|
+
this.app.event("app_mention", ({ event }) => {
|
|
108
|
+
const handler = this.messageHandler;
|
|
109
|
+
if (!handler)
|
|
110
|
+
return Promise.resolve();
|
|
111
|
+
if (this.isDuplicate(event.ts))
|
|
112
|
+
return Promise.resolve();
|
|
113
|
+
// Strip the `<@BOT_ID>` prefix from the mention text.
|
|
114
|
+
const text = (event.text ?? "").replace(/<@[A-Z0-9]+>/g, "").trim();
|
|
115
|
+
if (!text || !event.user)
|
|
116
|
+
return Promise.resolve();
|
|
117
|
+
const eventTs = event.ts;
|
|
118
|
+
const incoming = {
|
|
119
|
+
platform: "slack",
|
|
120
|
+
userId: event.user,
|
|
121
|
+
channelId: event.channel,
|
|
122
|
+
text,
|
|
123
|
+
eventTs,
|
|
124
|
+
timestamp: new Date(parseFloat(eventTs) * 1000),
|
|
125
|
+
};
|
|
126
|
+
const threadId = event.thread_ts ?? eventTs;
|
|
127
|
+
if (threadId)
|
|
128
|
+
incoming.threadId = threadId;
|
|
129
|
+
return Promise.resolve(handler(incoming));
|
|
130
|
+
});
|
|
131
|
+
this.app.action("approve_task", ({ action, ack }) => {
|
|
132
|
+
return ack().then(() => {
|
|
133
|
+
const handler = this.approvalHandler;
|
|
134
|
+
if (!handler)
|
|
135
|
+
return;
|
|
136
|
+
const value = action.value;
|
|
137
|
+
if (value)
|
|
138
|
+
handler(value, true);
|
|
139
|
+
});
|
|
140
|
+
});
|
|
141
|
+
this.app.action("reject_task", ({ action, ack }) => {
|
|
142
|
+
return ack().then(() => {
|
|
143
|
+
const handler = this.approvalHandler;
|
|
144
|
+
if (!handler)
|
|
145
|
+
return;
|
|
146
|
+
const value = action.value;
|
|
147
|
+
if (value)
|
|
148
|
+
handler(value, false);
|
|
149
|
+
});
|
|
150
|
+
});
|
|
151
|
+
}
|
|
152
|
+
extractImages(files) {
|
|
153
|
+
if (!files)
|
|
154
|
+
return [];
|
|
155
|
+
const images = [];
|
|
156
|
+
for (const file of files) {
|
|
157
|
+
if (file.mimetype.startsWith("image/")) {
|
|
158
|
+
images.push({
|
|
159
|
+
url: file.url_private,
|
|
160
|
+
mimeType: file.mimetype,
|
|
161
|
+
filename: file.name,
|
|
162
|
+
authHeader: `Bearer ${this.botToken}`,
|
|
163
|
+
});
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
return images;
|
|
167
|
+
}
|
|
168
|
+
async start() {
|
|
169
|
+
logInfo("Slack: connecting via Socket Mode...");
|
|
170
|
+
await this.app.start();
|
|
171
|
+
logInfo("Slack: connected and listening for messages");
|
|
172
|
+
}
|
|
173
|
+
async stop() {
|
|
174
|
+
logInfo("Slack: disconnecting...");
|
|
175
|
+
await this.app.stop();
|
|
176
|
+
}
|
|
177
|
+
onMessage(handler) {
|
|
178
|
+
this.messageHandler = handler;
|
|
179
|
+
}
|
|
180
|
+
onApproval(handler) {
|
|
181
|
+
this.approvalHandler = handler;
|
|
182
|
+
}
|
|
183
|
+
async sendText(channelId, text, threadId) {
|
|
184
|
+
const chunks = splitMessage(text, MAX_MESSAGE_LENGTH.slack);
|
|
185
|
+
let lastTs = "";
|
|
186
|
+
for (const chunk of chunks) {
|
|
187
|
+
await this.rateLimiter.acquire();
|
|
188
|
+
const result = await this.app.client.chat.postMessage({
|
|
189
|
+
channel: channelId,
|
|
190
|
+
text: chunk,
|
|
191
|
+
...(threadId ? { thread_ts: threadId } : {}),
|
|
192
|
+
});
|
|
193
|
+
lastTs = result.ts ?? "";
|
|
194
|
+
}
|
|
195
|
+
return lastTs;
|
|
196
|
+
}
|
|
197
|
+
async updateText(channelId, messageId, text, threadId) {
|
|
198
|
+
const chunks = splitMessage(text, MAX_MESSAGE_LENGTH.slack);
|
|
199
|
+
const head = chunks[0] ?? "";
|
|
200
|
+
await this.app.client.chat.update({
|
|
201
|
+
channel: channelId,
|
|
202
|
+
ts: messageId,
|
|
203
|
+
text: head,
|
|
204
|
+
});
|
|
205
|
+
// Extra chunks are posted as new thread replies under the original
|
|
206
|
+
// message, so the edited head + appended tail read as one response.
|
|
207
|
+
for (let i = 1; i < chunks.length; i++) {
|
|
208
|
+
await this.rateLimiter.acquire();
|
|
209
|
+
await this.app.client.chat.postMessage({
|
|
210
|
+
channel: channelId,
|
|
211
|
+
text: chunks[i] ?? "",
|
|
212
|
+
thread_ts: threadId ?? messageId,
|
|
213
|
+
});
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
async sendApproval(channelId, text, taskId, threadId) {
|
|
217
|
+
const BLOCK_TEXT_LIMIT = 3000;
|
|
218
|
+
const approvalButtons = {
|
|
219
|
+
type: "actions",
|
|
220
|
+
elements: [
|
|
221
|
+
{
|
|
222
|
+
type: "button",
|
|
223
|
+
text: { type: "plain_text", text: "Approve" },
|
|
224
|
+
style: "primary",
|
|
225
|
+
action_id: "approve_task",
|
|
226
|
+
value: taskId,
|
|
227
|
+
},
|
|
228
|
+
{
|
|
229
|
+
type: "button",
|
|
230
|
+
text: { type: "plain_text", text: "Reject" },
|
|
231
|
+
style: "danger",
|
|
232
|
+
action_id: "reject_task",
|
|
233
|
+
value: taskId,
|
|
234
|
+
},
|
|
235
|
+
],
|
|
236
|
+
};
|
|
237
|
+
if (text.length > BLOCK_TEXT_LIMIT) {
|
|
238
|
+
// Slack's `section` block has its own character limit; when the
|
|
239
|
+
// proposal text is too long, send it as plain messages first and
|
|
240
|
+
// then the buttons in a separate, minimal block message.
|
|
241
|
+
await this.sendText(channelId, text, threadId);
|
|
242
|
+
await this.rateLimiter.acquire();
|
|
243
|
+
await this.app.client.chat.postMessage({
|
|
244
|
+
channel: channelId,
|
|
245
|
+
text: "Approve or reject?",
|
|
246
|
+
...(threadId ? { thread_ts: threadId } : {}),
|
|
247
|
+
blocks: [approvalButtons],
|
|
248
|
+
});
|
|
249
|
+
}
|
|
250
|
+
else {
|
|
251
|
+
// M1 messenger review MED #2 — the short path used to skip the
|
|
252
|
+
// rate limiter while the long path acquired a token. Acquire here
|
|
253
|
+
// so the two paths behave identically under bursty M5 approvals.
|
|
254
|
+
await this.rateLimiter.acquire();
|
|
255
|
+
await this.app.client.chat.postMessage({
|
|
256
|
+
channel: channelId,
|
|
257
|
+
text,
|
|
258
|
+
...(threadId ? { thread_ts: threadId } : {}),
|
|
259
|
+
blocks: [
|
|
260
|
+
{
|
|
261
|
+
type: "section",
|
|
262
|
+
text: { type: "mrkdwn", text },
|
|
263
|
+
},
|
|
264
|
+
approvalButtons,
|
|
265
|
+
],
|
|
266
|
+
});
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
async sendBlocks(channelId, fallbackText, blocks, threadId) {
|
|
270
|
+
await this.rateLimiter.acquire();
|
|
271
|
+
const result = await this.app.client.chat.postMessage({
|
|
272
|
+
channel: channelId,
|
|
273
|
+
text: fallbackText,
|
|
274
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-explicit-any
|
|
275
|
+
blocks: blocks,
|
|
276
|
+
...(threadId ? { thread_ts: threadId } : {}),
|
|
277
|
+
});
|
|
278
|
+
return result.ts ?? "";
|
|
279
|
+
}
|
|
280
|
+
async addReaction(channelId, messageTs, emoji) {
|
|
281
|
+
try {
|
|
282
|
+
await this.app.client.reactions.add({
|
|
283
|
+
channel: channelId,
|
|
284
|
+
timestamp: messageTs,
|
|
285
|
+
name: emoji,
|
|
286
|
+
});
|
|
287
|
+
}
|
|
288
|
+
catch (err) {
|
|
289
|
+
// Reactions fail routinely in normal operation (already-reacted,
|
|
290
|
+
// missing scope, rate-limit). core.ts fires up to 5 reaction
|
|
291
|
+
// calls per message — warn-logging every failure would flood the
|
|
292
|
+
// disk log. Downgraded to debug (M1 messenger review MED #3).
|
|
293
|
+
logDebug(`addReaction(${emoji}) failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
async removeReaction(channelId, messageTs, emoji) {
|
|
297
|
+
try {
|
|
298
|
+
await this.app.client.reactions.remove({
|
|
299
|
+
channel: channelId,
|
|
300
|
+
timestamp: messageTs,
|
|
301
|
+
name: emoji,
|
|
302
|
+
});
|
|
303
|
+
}
|
|
304
|
+
catch (err) {
|
|
305
|
+
logDebug(`removeReaction(${emoji}) failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
//# sourceMappingURL=slack.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"slack.js","sourceRoot":"","sources":["../../src/messenger/slack.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Message splitting utility for messenger adapters.
|
|
3
|
+
*
|
|
4
|
+
* Platform limits and code-block continuity preservation come from
|
|
5
|
+
* pilot-ai. Telegram is dropped — adaria-ai ships Slack only in v1.
|
|
6
|
+
*/
|
|
7
|
+
export declare const MAX_MESSAGE_LENGTH: {
|
|
8
|
+
readonly slack: 4000;
|
|
9
|
+
};
|
|
10
|
+
/**
|
|
11
|
+
* Splits a long message into chunks that fit within `maxLength`.
|
|
12
|
+
* Preserves Markdown code blocks (```) across split boundaries by
|
|
13
|
+
* closing them at the end of one chunk and reopening at the start
|
|
14
|
+
* of the next.
|
|
15
|
+
*/
|
|
16
|
+
export declare function splitMessage(text: string, maxLength: number): string[];
|
|
17
|
+
//# sourceMappingURL=split.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"split.d.ts","sourceRoot":"","sources":["../../src/messenger/split.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,eAAO,MAAM,kBAAkB;;CAErB,CAAC;AAEX;;;;;GAKG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,EAAE,CA2BtE"}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Message splitting utility for messenger adapters.
|
|
3
|
+
*
|
|
4
|
+
* Platform limits and code-block continuity preservation come from
|
|
5
|
+
* pilot-ai. Telegram is dropped — adaria-ai ships Slack only in v1.
|
|
6
|
+
*/
|
|
7
|
+
export const MAX_MESSAGE_LENGTH = {
|
|
8
|
+
slack: 4000,
|
|
9
|
+
};
|
|
10
|
+
/**
|
|
11
|
+
* Splits a long message into chunks that fit within `maxLength`.
|
|
12
|
+
* Preserves Markdown code blocks (```) across split boundaries by
|
|
13
|
+
* closing them at the end of one chunk and reopening at the start
|
|
14
|
+
* of the next.
|
|
15
|
+
*/
|
|
16
|
+
export function splitMessage(text, maxLength) {
|
|
17
|
+
if (text.length <= maxLength)
|
|
18
|
+
return [text];
|
|
19
|
+
const chunks = [];
|
|
20
|
+
let remaining = text;
|
|
21
|
+
while (remaining.length > 0) {
|
|
22
|
+
if (remaining.length <= maxLength) {
|
|
23
|
+
chunks.push(remaining);
|
|
24
|
+
break;
|
|
25
|
+
}
|
|
26
|
+
const splitAt = findSplitPoint(remaining, maxLength);
|
|
27
|
+
let chunk = remaining.slice(0, splitAt);
|
|
28
|
+
remaining = remaining.slice(splitAt);
|
|
29
|
+
// If chunk ends mid-code-block, close it and reopen on the next chunk.
|
|
30
|
+
const openBlocks = countCodeBlockMarkers(chunk);
|
|
31
|
+
if (openBlocks % 2 === 1) {
|
|
32
|
+
chunk += "\n```";
|
|
33
|
+
remaining = "```\n" + remaining;
|
|
34
|
+
}
|
|
35
|
+
chunks.push(chunk);
|
|
36
|
+
}
|
|
37
|
+
return chunks;
|
|
38
|
+
}
|
|
39
|
+
/** Prefer line-boundary splits, then space, then hard cut. */
|
|
40
|
+
function findSplitPoint(text, maxLength) {
|
|
41
|
+
const lastNewline = text.lastIndexOf("\n", maxLength);
|
|
42
|
+
if (lastNewline > maxLength * 0.5) {
|
|
43
|
+
return lastNewline + 1;
|
|
44
|
+
}
|
|
45
|
+
const lastSpace = text.lastIndexOf(" ", maxLength);
|
|
46
|
+
if (lastSpace > maxLength * 0.5) {
|
|
47
|
+
return lastSpace + 1;
|
|
48
|
+
}
|
|
49
|
+
return maxLength;
|
|
50
|
+
}
|
|
51
|
+
/** Counts ``` markers. Odd count means the text ends inside a block. */
|
|
52
|
+
function countCodeBlockMarkers(text) {
|
|
53
|
+
const matches = text.match(/```/g);
|
|
54
|
+
return matches ? matches.length : 0;
|
|
55
|
+
}
|
|
56
|
+
//# sourceMappingURL=split.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"split.js","sourceRoot":"","sources":["../../src/messenger/split.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,MAAM,CAAC,MAAM,kBAAkB,GAAG;IAChC,KAAK,EAAE,IAAI;CACH,CAAC;AAEX;;;;;GAKG;AACH,MAAM,UAAU,YAAY,CAAC,IAAY,EAAE,SAAiB;IAC1D,IAAI,IAAI,CAAC,MAAM,IAAI,SAAS;QAAE,OAAO,CAAC,IAAI,CAAC,CAAC;IAE5C,MAAM,MAAM,GAAa,EAAE,CAAC;IAC5B,IAAI,SAAS,GAAG,IAAI,CAAC;IAErB,OAAO,SAAS,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC5B,IAAI,SAAS,CAAC,MAAM,IAAI,SAAS,EAAE,CAAC;YAClC,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;YACvB,MAAM;QACR,CAAC;QAED,MAAM,OAAO,GAAG,cAAc,CAAC,SAAS,EAAE,SAAS,CAAC,CAAC;QACrD,IAAI,KAAK,GAAG,SAAS,CAAC,KAAK,CAAC,CAAC,EAAE,OAAO,CAAC,CAAC;QACxC,SAAS,GAAG,SAAS,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;QAErC,uEAAuE;QACvE,MAAM,UAAU,GAAG,qBAAqB,CAAC,KAAK,CAAC,CAAC;QAChD,IAAI,UAAU,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC;YACzB,KAAK,IAAI,OAAO,CAAC;YACjB,SAAS,GAAG,OAAO,GAAG,SAAS,CAAC;QAClC,CAAC;QAED,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IACrB,CAAC;IAED,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,8DAA8D;AAC9D,SAAS,cAAc,CAAC,IAAY,EAAE,SAAiB;IACrD,MAAM,WAAW,GAAG,IAAI,CAAC,WAAW,CAAC,IAAI,EAAE,SAAS,CAAC,CAAC;IACtD,IAAI,WAAW,GAAG,SAAS,GAAG,GAAG,EAAE,CAAC;QAClC,OAAO,WAAW,GAAG,CAAC,CAAC;IACzB,CAAC;IACD,MAAM,SAAS,GAAG,IAAI,CAAC,WAAW,CAAC,GAAG,EAAE,SAAS,CAAC,CAAC;IACnD,IAAI,SAAS,GAAG,SAAS,GAAG,GAAG,EAAE,CAAC;QAChC,OAAO,SAAS,GAAG,CAAC,CAAC;IACvB,CAAC;IACD,OAAO,SAAS,CAAC;AACnB,CAAC;AAED,wEAAwE;AACxE,SAAS,qBAAqB,CAAC,IAAY;IACzC,MAAM,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;IACnC,OAAO,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC;AACtC,CAAC"}
|