@crowdlisten/harness 1.0.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.
Files changed (109) hide show
  1. package/AGENTS.md +167 -0
  2. package/LICENSE +21 -0
  3. package/README.md +153 -0
  4. package/dist/agent-proxy.d.ts +24 -0
  5. package/dist/agent-proxy.js +140 -0
  6. package/dist/agent-tools.d.ts +736 -0
  7. package/dist/agent-tools.js +409 -0
  8. package/dist/context/api.d.ts +5 -0
  9. package/dist/context/api.js +164 -0
  10. package/dist/context/cli.d.ts +19 -0
  11. package/dist/context/cli.js +108 -0
  12. package/dist/context/extractor.d.ts +12 -0
  13. package/dist/context/extractor.js +43 -0
  14. package/dist/context/index.d.ts +12 -0
  15. package/dist/context/index.js +11 -0
  16. package/dist/context/matcher.d.ts +39 -0
  17. package/dist/context/matcher.js +246 -0
  18. package/dist/context/parser.d.ts +28 -0
  19. package/dist/context/parser.js +157 -0
  20. package/dist/context/pipeline.d.ts +26 -0
  21. package/dist/context/pipeline.js +56 -0
  22. package/dist/context/prompts.d.ts +6 -0
  23. package/dist/context/prompts.js +60 -0
  24. package/dist/context/providers.d.ts +6 -0
  25. package/dist/context/providers.js +106 -0
  26. package/dist/context/redactor.d.ts +10 -0
  27. package/dist/context/redactor.js +68 -0
  28. package/dist/context/server.d.ts +5 -0
  29. package/dist/context/server.js +134 -0
  30. package/dist/context/store.d.ts +12 -0
  31. package/dist/context/store.js +82 -0
  32. package/dist/context/types.d.ts +79 -0
  33. package/dist/context/types.js +4 -0
  34. package/dist/context/user-state.d.ts +40 -0
  35. package/dist/context/user-state.js +144 -0
  36. package/dist/index.d.ts +14 -0
  37. package/dist/index.js +385 -0
  38. package/dist/insights/browser/BrowserPool.d.ts +87 -0
  39. package/dist/insights/browser/BrowserPool.js +266 -0
  40. package/dist/insights/browser/RequestInterceptor.d.ts +46 -0
  41. package/dist/insights/browser/RequestInterceptor.js +115 -0
  42. package/dist/insights/cli.d.ts +8 -0
  43. package/dist/insights/cli.js +206 -0
  44. package/dist/insights/core/base/BaseAdapter.d.ts +37 -0
  45. package/dist/insights/core/base/BaseAdapter.js +123 -0
  46. package/dist/insights/core/health/HealthMonitor.d.ts +75 -0
  47. package/dist/insights/core/health/HealthMonitor.js +171 -0
  48. package/dist/insights/core/interfaces/SocialMediaPlatform.d.ts +125 -0
  49. package/dist/insights/core/interfaces/SocialMediaPlatform.js +42 -0
  50. package/dist/insights/core/utils/DataNormalizer.d.ts +53 -0
  51. package/dist/insights/core/utils/DataNormalizer.js +349 -0
  52. package/dist/insights/core/utils/InstagramUrlUtils.d.ts +11 -0
  53. package/dist/insights/core/utils/InstagramUrlUtils.js +60 -0
  54. package/dist/insights/core/utils/TikTokUrlUtils.d.ts +10 -0
  55. package/dist/insights/core/utils/TikTokUrlUtils.js +57 -0
  56. package/dist/insights/handlers.d.ts +157 -0
  57. package/dist/insights/handlers.js +246 -0
  58. package/dist/insights/index.d.ts +437 -0
  59. package/dist/insights/index.js +426 -0
  60. package/dist/insights/platforms/instagram/InstagramAdapter.d.ts +34 -0
  61. package/dist/insights/platforms/instagram/InstagramAdapter.js +342 -0
  62. package/dist/insights/platforms/moltbook/MoltbookAdapter.d.ts +31 -0
  63. package/dist/insights/platforms/moltbook/MoltbookAdapter.js +227 -0
  64. package/dist/insights/platforms/reddit/RedditAdapter.d.ts +21 -0
  65. package/dist/insights/platforms/reddit/RedditAdapter.js +212 -0
  66. package/dist/insights/platforms/tiktok/TikTokAdapter.d.ts +34 -0
  67. package/dist/insights/platforms/tiktok/TikTokAdapter.js +269 -0
  68. package/dist/insights/platforms/twitter/TwitterAdapter.d.ts +23 -0
  69. package/dist/insights/platforms/twitter/TwitterAdapter.js +211 -0
  70. package/dist/insights/platforms/xiaohongshu/XiaohongshuAdapter.d.ts +35 -0
  71. package/dist/insights/platforms/xiaohongshu/XiaohongshuAdapter.js +258 -0
  72. package/dist/insights/platforms/youtube/YouTubeAdapter.d.ts +22 -0
  73. package/dist/insights/platforms/youtube/YouTubeAdapter.js +254 -0
  74. package/dist/insights/service-config.d.ts +7 -0
  75. package/dist/insights/service-config.js +60 -0
  76. package/dist/insights/services/UnifiedSocialMediaService.d.ts +94 -0
  77. package/dist/insights/services/UnifiedSocialMediaService.js +259 -0
  78. package/dist/insights/vision/VisionExtractor.d.ts +46 -0
  79. package/dist/insights/vision/VisionExtractor.js +236 -0
  80. package/dist/learnings.d.ts +50 -0
  81. package/dist/learnings.js +130 -0
  82. package/dist/openapi.d.ts +29 -0
  83. package/dist/openapi.js +169 -0
  84. package/dist/server-factory.d.ts +20 -0
  85. package/dist/server-factory.js +41 -0
  86. package/dist/suggestions.d.ts +16 -0
  87. package/dist/suggestions.js +72 -0
  88. package/dist/telemetry.d.ts +44 -0
  89. package/dist/telemetry.js +93 -0
  90. package/dist/tools/registry.d.ts +65 -0
  91. package/dist/tools/registry.js +256 -0
  92. package/dist/tools.d.ts +2433 -0
  93. package/dist/tools.js +2294 -0
  94. package/dist/transport/http.d.ts +15 -0
  95. package/dist/transport/http.js +154 -0
  96. package/package.json +76 -0
  97. package/skills/catalog.json +272 -0
  98. package/skills/community-catalog.json +4202 -0
  99. package/skills/competitive-analysis/SKILL.md +174 -0
  100. package/skills/content-creator/SKILL.md +256 -0
  101. package/skills/content-strategy/SKILL.md +222 -0
  102. package/skills/data-storytelling/SKILL.md +248 -0
  103. package/skills/heuristic-evaluation/SKILL.md +201 -0
  104. package/skills/market-research-reports/SKILL.md +184 -0
  105. package/skills/user-stories/SKILL.md +178 -0
  106. package/skills/ux-researcher/SKILL.md +239 -0
  107. package/web-dist/assets/index-B1b25lNd.css +1 -0
  108. package/web-dist/assets/index-CDWHwHbl.js +64 -0
  109. package/web-dist/index.html +16 -0
package/AGENTS.md ADDED
@@ -0,0 +1,167 @@
1
+ # CrowdListen — Agent Reference
2
+
3
+ Unified MCP server for AI agents. Planning, social listening, skill packs, and knowledge management with progressive disclosure.
4
+
5
+ ## Quick Start
6
+
7
+ ```bash
8
+ npx @crowdlisten/harness login
9
+ ```
10
+
11
+ Auto-configures MCP for Claude Code, Cursor, Gemini CLI, Codex, OpenClaw, Amp.
12
+
13
+ ### Manual MCP config (stdio)
14
+ ```json
15
+ { "crowdlisten": { "command": "npx", "args": ["-y", "@crowdlisten/harness"] } }
16
+ ```
17
+
18
+ ### Remote MCP config (Streamable HTTP)
19
+ ```json
20
+ {
21
+ "crowdlisten": {
22
+ "url": "https://mcp.crowdlisten.com/mcp",
23
+ "headers": {
24
+ "Authorization": "Bearer YOUR_API_KEY"
25
+ }
26
+ }
27
+ }
28
+ ```
29
+
30
+ ## Interfaces
31
+
32
+ | Interface | Access | Best for |
33
+ |-----------|--------|----------|
34
+ | MCP stdio | `npx @crowdlisten/harness` — ~41 tools | Local agents |
35
+ | MCP HTTP | `POST https://mcp.crowdlisten.com/mcp` | Remote agents, cloud |
36
+ | REST | `POST https://mcp.crowdlisten.com/tools/{name}` | Non-MCP integrations |
37
+ | OpenAPI | `GET https://mcp.crowdlisten.com/openapi.json` | Docs, code gen |
38
+ | CLI | `npx @crowdlisten/harness login/setup/serve/openapi` | Auth, config, hosting |
39
+ | Web UI | `npx @crowdlisten/harness context` → localhost:3847 | Visual context extraction |
40
+
41
+ ## Progressive Disclosure
42
+
43
+ You start with **4 tools**. Activate skill packs to unlock more:
44
+
45
+ ```
46
+ list_skill_packs() → see available packs
47
+ activate_skill_pack({ pack_id: "planning" }) → unlocks 11 task tools
48
+ activate_skill_pack({ pack_id: "social-listening" }) → unlocks 7 social tools
49
+ ```
50
+
51
+ After activation, new tools appear automatically via `tools/list_changed`.
52
+
53
+ ## Always-On Tools (4)
54
+
55
+ - **list_skill_packs**(include_virtual?) — List all packs with status (active/available), tool counts
56
+ - **activate_skill_pack**(pack_id) — Activate a pack to unlock its tools. For SKILL.md packs, returns workflow instructions.
57
+ - **remember**(type, title, content) — Save context across sessions. Types: preference, decision, pattern, insight, style
58
+ - **recall**(type?, search?, limit?) — Retrieve saved context blocks
59
+
60
+ ## Skill Packs
61
+
62
+ | Pack | Tools | Description |
63
+ |------|-------|-------------|
64
+ | **core** (always on) | 4 | Discovery + memory |
65
+ | **planning** | 11 | Tasks, plans, progress tracking |
66
+ | **knowledge** | 3 | Project knowledge base |
67
+ | **social-listening** | 7 | Search social platforms (free) |
68
+ | **audience-analysis** | 6 | AI analysis (CROWDLISTEN_API_KEY) |
69
+ | **sessions** | 3 | Multi-agent coordination |
70
+ | **setup** | 5 | Board management |
71
+ | **legacy** | 6 | Previous-gen context extraction |
72
+
73
+ Plus: 8 native SKILL.md workflow packs (competitive-analysis, content-creator, etc.)
74
+
75
+ ## Planning Pack (11 tools)
76
+
77
+ - **list_tasks**(board_id?, status?, limit?) — List board tasks
78
+ - **get_task**(task_id) — Full task details
79
+ - **create_task**(title, description?, priority?) — Create task
80
+ - **update_task**(task_id, ...) — Update task fields
81
+ - **claim_task**(task_id, executor?, branch?) — Start work, get context
82
+ - **complete_task**(task_id, summary?) — Mark done
83
+ - **delete_task**(task_id) — Remove task
84
+ - **log_progress**(task_id, message) — Track execution
85
+ - **create_plan**(task_id, approach, ...) — Draft execution plan
86
+ - **get_plan**(task_id) — View plan with history
87
+ - **update_plan**(plan_id, ...) — Iterate, submit for review
88
+
89
+ ## Knowledge Pack (3 tools)
90
+
91
+ - **query_context**(search?, type?, tags?) — Search decisions, patterns, learnings
92
+ - **add_context**(type, title, body, ...) — Write to knowledge base
93
+ - **record_learning**(task_id, title, body, promote?) — Capture learning
94
+
95
+ ## Social Listening Pack (7 tools, free)
96
+
97
+ - **search_content**(platform, query, limit?) — Search posts across platforms
98
+ - **get_content_comments**(platform, contentId, limit?) — Get comments/replies
99
+ - **get_trending_content**(platform, limit?) — Trending posts
100
+ - **get_user_content**(platform, userId, limit?) — User's recent posts
101
+ - **get_platform_status**() — Available platforms + capabilities
102
+ - **health_check**() — Platform connectivity status
103
+ - **extract_url**(url, mode?, limit?) — Vision extraction from any URL
104
+
105
+ Platforms: reddit, twitter, tiktok, instagram, youtube, moltbook
106
+
107
+ ## Audience Analysis Pack (6 tools, CROWDLISTEN_API_KEY)
108
+
109
+ - **analyze_content**(platform, contentId, analysisDepth?) — Sentiment, themes, tensions
110
+ - **cluster_opinions**(platform, contentId, clusterCount?) — Opinion clustering
111
+ - **enrich_content**(platform, contentId, question?) — Intent/stance analysis
112
+ - **deep_analyze**(platform, contentId, analysisDepth?) — Full audience intelligence
113
+ - **extract_insights**(platform, contentId, categories?) — Pain points, feature requests
114
+ - **research_synthesis**(query, platforms?, depth?) — Cross-platform research
115
+
116
+ ## Analysis (5 tools) — requires CROWDLISTEN_API_KEY
117
+
118
+ - **run_analysis**(project_id, question, platforms?, max_results?) — Run audience analysis across Reddit, YouTube, TikTok, Twitter, Instagram, Xiaohongshu. Streams results.
119
+ - **continue_analysis**(analysis_id, question) — Follow-up question on existing analysis.
120
+ - **get_analysis**(analysis_id) — Get full analysis results with themes, sentiment, quotes.
121
+ - **list_analyses**(project_id, limit?) — List analyses for a project.
122
+ - **generate_specs**(project_id, analysis_id?, spec_type?) — Generate feature requests, user stories, acceptance criteria from analysis.
123
+
124
+ ## Content & Vectors (4 tools) — requires CROWDLISTEN_API_KEY
125
+
126
+ - **ingest_content**(project_id, content, source_url?, title?, metadata?) — Ingest content into vector store.
127
+ - **search_vectors**(project_id, query, limit?, threshold?) — Semantic search across ingested content.
128
+ - **get_content_stats**(project_id) — Document count, chunks, storage usage.
129
+ - **delete_content**(content_id) — Delete content document and embeddings.
130
+
131
+ ## Document Generation (2 tools) — requires CROWDLISTEN_API_KEY
132
+
133
+ - **generate_prd**(project_id, analysis_ids?, template?, sections?) — Generate PRD from analysis. Templates: standard, lean, technical, marketing.
134
+ - **update_prd_section**(document_id, section, instructions?, content?) — Update a specific PRD section.
135
+
136
+ ## Sessions (3 tools) — Parallel Agents
137
+
138
+ - **start_session**(task_id, executor?, focus) — Start additional parallel session.
139
+ - **list_sessions**(task_id, status?) — List sessions showing status and focus.
140
+ - **update_session**(session_id, status?, focus?) — Update session: idle, running, completed, failed, stopped.
141
+
142
+ ## LLM Proxy (2 tools) — free, no API key
143
+
144
+ - **llm_complete**(prompt, model?, max_tokens?, temperature?, system?) — LLM completion through CrowdListen. Default: gpt-4o-mini.
145
+ - **list_llm_models**() — List available models and capabilities.
146
+
147
+ ## Agent Network (3 tools) — mixed auth
148
+
149
+ - **register_agent**(name, capabilities?, executor?) — Register in agent network. Free.
150
+ - **get_capabilities**() — List network capabilities. Free.
151
+ - **submit_analysis**(agent_id, analysis_id, summary) — Share analysis results. Requires API key.
152
+
153
+ ## Core Workflow
154
+
155
+ ```
156
+ list_skill_packs → activate_skill_pack("planning")
157
+ → list_tasks → claim_task → query_context → create_plan
158
+ → [human review] → execute → record_learning → complete_task
159
+ ```
160
+
161
+ ## Privacy
162
+
163
+ - PII redacted locally before LLM calls
164
+ - Context stored locally (~/.crowdlisten/)
165
+ - User's own API keys for extraction
166
+ - No data syncs without explicit user action
167
+ - Agent-proxied tools go through `agent.crowdlisten.com` with your API key
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 CrowdListen
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,153 @@
1
+ # CrowdListen
2
+
3
+ > Give your AI agent crowd context — analyzed intelligence from what real users say, what markets think, and what communities want.
4
+
5
+ ![CrowdListen — Give your agent evidence, not guesses](docs/images/hero.png)
6
+
7
+ [English](README.md) | [中文文档](README-CN.md) | [한국어](README-KO.md) | [Español](README-ES.md)
8
+
9
+ ## The Problem
10
+
11
+ AI agents don't know what your users think. Every session starts from scratch — no awareness of what people say on Reddit, no signal from TikTok comments, no synthesis of forum discussions. You end up copy-pasting feedback manually and watching your agent make decisions without the one input that matters most: what real people think.
12
+
13
+ CrowdListen fixes this with a four-step loop:
14
+
15
+ 1. **Listen** — search Reddit, YouTube, TikTok, Twitter/X, Instagram, Xiaohongshu, and forums
16
+ 2. **Analyze** — cluster opinions by theme, extract pain points, synthesize cross-platform reports
17
+ 3. **Remember** — save analyzed insights with semantic embeddings, not raw posts
18
+ 4. **Recall** — any agent retrieves crowd context via natural language, across sessions and devices
19
+
20
+ Any agent — Claude Code, Cursor, Gemini CLI, Codex — can recall this later. The intelligence compounds across sessions and across agents. That's crowd context.
21
+
22
+ ## Get Started
23
+
24
+ One command. Your browser opens, you sign in, and your agents are configured automatically:
25
+
26
+ ```bash
27
+ npx @crowdlisten/harness login
28
+ ```
29
+
30
+ Auto-configures MCP for **Claude Code, Cursor, Gemini CLI, Codex, Amp, and OpenClaw**. No env vars, no JSON editing, no API keys to manage. Restart your agent after login.
31
+
32
+ ### Manual Setup
33
+
34
+ Add to your agent's MCP config:
35
+
36
+ ```json
37
+ {
38
+ "mcpServers": {
39
+ "crowdlisten": {
40
+ "command": "npx",
41
+ "args": ["-y", "@crowdlisten/harness"]
42
+ }
43
+ }
44
+ }
45
+ ```
46
+
47
+ For remote access, use the HTTP transport:
48
+
49
+ ```json
50
+ {
51
+ "mcpServers": {
52
+ "crowdlisten": {
53
+ "url": "https://mcp.crowdlisten.com/mcp",
54
+ "headers": {
55
+ "Authorization": "Bearer YOUR_API_KEY"
56
+ }
57
+ }
58
+ }
59
+ }
60
+ ```
61
+
62
+ ## What You Can Do
63
+
64
+ | Capability | What it does | How it works |
65
+ |---|---|---|
66
+ | **Search social platforms** | Search Reddit, YouTube, TikTok, Twitter/X, Instagram, Xiaohongshu from one tool | Returns structured posts with engagement metrics, timestamps, and author info — same format regardless of platform |
67
+ | **Analyze audience signal** | Cluster opinions, extract pain points, generate cross-platform reports | AI groups comments by theme, scores sentiment, identifies competitive signals |
68
+ | **Save and recall across sessions** | Semantic memory that follows you across agents and devices | Your agent saves with `save`, retrieves with `recall` using meaning-based search — not keyword matching |
69
+ | **Plan and track work** | Tasks, execution plans, progress tracking | Your agent claims tasks, drafts plans with assumptions and risks, logs progress |
70
+ | **Get specs from crowd feedback** | Turn crowd intelligence into implementation-ready specs | Specs include evidence citations, acceptance criteria, and confidence scores |
71
+ | **Extract from any website** | Screenshot any URL and get structured data back | Vision mode sends screenshots to an LLM — works on forums, paywalled sites, anything with a URL |
72
+
73
+ ## How It Works
74
+
75
+ ![CrowdListen Pipeline — Raw Crowd Signals to Agent Delivery](docs/images/pipeline.jpg)
76
+
77
+ Your agent starts with **5 core tools** and activates skill packs on demand. No restart required — new tools appear instantly.
78
+
79
+ ### Skill Packs
80
+
81
+ | Pack | Tools | What it does | Free? |
82
+ |------|:-----:|---|:---:|
83
+ | **core** (always on) | 5 | Semantic memory, discovery, preferences | Yes |
84
+ | **social-listening** | 7 | Search Reddit, TikTok, YouTube, Twitter, Instagram, Xiaohongshu | Yes |
85
+ | **audience-analysis** | 6 | Opinion clustering, deep analysis, insight extraction, research synthesis | API key |
86
+ | **planning** | 11 | Tasks, execution plans, progress tracking | Yes |
87
+ | **spec-delivery** | 3 | Browse and claim actionable specs from crowd feedback | Yes |
88
+ | **sessions** | 3 | Multi-agent coordination | Yes |
89
+ | **analysis** | 5 | Run full analyses, generate specs from results | API key |
90
+ | **content** | 4 | Ingest content, vector search | API key |
91
+ | **generation** | 2 | PRD generation | API key |
92
+ | **llm** | 2 | Free LLM completion proxy | Yes |
93
+ | **agent-network** | 3 | Register agents, discover capabilities | Mixed |
94
+
95
+ Plus 8 **workflow packs** (competitive-analysis, content-strategy, market-research, ux-research, and more) that deliver expert methodology when activated.
96
+
97
+ Full tool reference: **[docs/TOOLS.md](docs/TOOLS.md)**
98
+
99
+ ### Platforms
100
+
101
+ | Platform | Setup | Notes |
102
+ |---|---|---|
103
+ | Reddit | None | Works immediately |
104
+ | TikTok, Instagram, Xiaohongshu | `npx playwright install chromium` | Browser-based extraction |
105
+ | Twitter/X | `TWITTER_USERNAME` + `TWITTER_PASSWORD` in `.env` | Credential-based |
106
+ | YouTube | `YOUTUBE_API_KEY` in `.env` | API key required |
107
+ | Vision mode (any URL) | Any one of: `ANTHROPIC_API_KEY`, `GEMINI_API_KEY`, or `OPENAI_API_KEY` | Screenshots + LLM extraction |
108
+
109
+ ### Supported Agents
110
+
111
+ **Auto-configured on login:** Claude Code, Cursor, Gemini CLI, Codex, Amp, OpenClaw
112
+
113
+ **Also works with (manual config):** Copilot, Droid, Qwen Code, OpenCode
114
+
115
+ ## CLI
116
+
117
+ ```bash
118
+ npx @crowdlisten/harness login # Sign in + auto-configure agents
119
+ npx @crowdlisten/harness setup # Re-run auto-configure
120
+ npx @crowdlisten/harness serve # Start HTTP server on :3848
121
+
122
+ npx crowdlisten search reddit "AI agents" --limit 20
123
+ npx crowdlisten vision https://news.ycombinator.com --limit 10
124
+ npx crowdlisten trending reddit --limit 10
125
+ ```
126
+
127
+ ## Privacy
128
+
129
+ - PII redacted locally before LLM calls
130
+ - Memories stored with row-level security — users can only access their own data
131
+ - Local fallback when cloud is unavailable
132
+ - Your own API keys for LLM extraction
133
+ - No data syncs without explicit action
134
+ - MIT open-source and inspectable
135
+
136
+ ## Development
137
+
138
+ ```bash
139
+ git clone https://github.com/Crowdlisten/crowdlisten_harness.git
140
+ cd crowdlisten_harness
141
+ npm install && npm run build
142
+ npm test # 210+ tests via Vitest
143
+ ```
144
+
145
+ For agent-readable capability descriptions and example workflows, see [AGENTS.md](AGENTS.md).
146
+
147
+ ## Contributing
148
+
149
+ Highest-value contributions: new platform adapters (Threads, Bluesky, Hacker News, Product Hunt, Mastodon) and extraction fixes.
150
+
151
+ ## License
152
+
153
+ MIT — [crowdlisten.com](https://crowdlisten.com)
@@ -0,0 +1,24 @@
1
+ /**
2
+ * Agent Proxy — Shared HTTP client for agent.crowdlisten.com
3
+ *
4
+ * All agent-proxied tools route through these helpers.
5
+ * Supports POST, GET, and SSE streaming endpoints.
6
+ */
7
+ /**
8
+ * Returns the CROWDLISTEN_API_KEY or throws.
9
+ * Tools that require auth call this; free tools skip it.
10
+ */
11
+ export declare function requireApiKey(): string;
12
+ export declare function agentPost(path: string, body: Record<string, unknown>, apiKey?: string): Promise<unknown>;
13
+ export declare function agentGet(path: string, apiKey?: string): Promise<unknown>;
14
+ export declare function agentDelete(path: string, apiKey?: string): Promise<unknown>;
15
+ /**
16
+ * Connects to an SSE endpoint, collects all events, and returns
17
+ * the aggregated result. Used for long-running operations like
18
+ * analysis/run and PRD generation.
19
+ *
20
+ * Collects `data:` lines until the stream closes or times out.
21
+ * If the last event contains a JSON object with a "status" field,
22
+ * that's treated as the final result. Otherwise returns all events.
23
+ */
24
+ export declare function agentStream(path: string, body: Record<string, unknown>, apiKey?: string, timeoutMs?: number): Promise<unknown>;
@@ -0,0 +1,140 @@
1
+ /**
2
+ * Agent Proxy — Shared HTTP client for agent.crowdlisten.com
3
+ *
4
+ * All agent-proxied tools route through these helpers.
5
+ * Supports POST, GET, and SSE streaming endpoints.
6
+ */
7
+ const AGENT_BASE = process.env.CROWDLISTEN_AGENT_URL || "https://agent.crowdlisten.com";
8
+ // ─── Auth ──────────────────────────────────────────────────────────────────
9
+ /**
10
+ * Returns the CROWDLISTEN_API_KEY or throws.
11
+ * Tools that require auth call this; free tools skip it.
12
+ */
13
+ export function requireApiKey() {
14
+ const key = process.env.CROWDLISTEN_API_KEY;
15
+ if (!key) {
16
+ throw new Error("CROWDLISTEN_API_KEY is required for this tool. " +
17
+ "Get one at https://crowdlisten.com/settings/api-keys");
18
+ }
19
+ return key;
20
+ }
21
+ function headers(apiKey) {
22
+ const h = {
23
+ "Content-Type": "application/json",
24
+ Accept: "application/json",
25
+ };
26
+ if (apiKey)
27
+ h["Authorization"] = `Bearer ${apiKey}`;
28
+ return h;
29
+ }
30
+ // ─── POST ──────────────────────────────────────────────────────────────────
31
+ export async function agentPost(path, body, apiKey) {
32
+ const url = `${AGENT_BASE}${path}`;
33
+ const res = await fetch(url, {
34
+ method: "POST",
35
+ headers: headers(apiKey),
36
+ body: JSON.stringify(body),
37
+ });
38
+ if (!res.ok) {
39
+ const text = await res.text().catch(() => "");
40
+ throw new Error(`Agent API error ${res.status} on POST ${path}: ${text || res.statusText}`);
41
+ }
42
+ return res.json();
43
+ }
44
+ // ─── GET ───────────────────────────────────────────────────────────────────
45
+ export async function agentGet(path, apiKey) {
46
+ const url = `${AGENT_BASE}${path}`;
47
+ const res = await fetch(url, {
48
+ method: "GET",
49
+ headers: headers(apiKey),
50
+ });
51
+ if (!res.ok) {
52
+ const text = await res.text().catch(() => "");
53
+ throw new Error(`Agent API error ${res.status} on GET ${path}: ${text || res.statusText}`);
54
+ }
55
+ return res.json();
56
+ }
57
+ // ─── DELETE ────────────────────────────────────────────────────────────────
58
+ export async function agentDelete(path, apiKey) {
59
+ const url = `${AGENT_BASE}${path}`;
60
+ const res = await fetch(url, {
61
+ method: "DELETE",
62
+ headers: headers(apiKey),
63
+ });
64
+ if (!res.ok) {
65
+ const text = await res.text().catch(() => "");
66
+ throw new Error(`Agent API error ${res.status} on DELETE ${path}: ${text || res.statusText}`);
67
+ }
68
+ return res.json();
69
+ }
70
+ // ─── SSE Stream → Aggregated Result ────────────────────────────────────────
71
+ /**
72
+ * Connects to an SSE endpoint, collects all events, and returns
73
+ * the aggregated result. Used for long-running operations like
74
+ * analysis/run and PRD generation.
75
+ *
76
+ * Collects `data:` lines until the stream closes or times out.
77
+ * If the last event contains a JSON object with a "status" field,
78
+ * that's treated as the final result. Otherwise returns all events.
79
+ */
80
+ export async function agentStream(path, body, apiKey, timeoutMs = 120_000) {
81
+ const url = `${AGENT_BASE}${path}`;
82
+ const controller = new AbortController();
83
+ const timer = setTimeout(() => controller.abort(), timeoutMs);
84
+ try {
85
+ const res = await fetch(url, {
86
+ method: "POST",
87
+ headers: {
88
+ ...headers(apiKey),
89
+ Accept: "text/event-stream",
90
+ },
91
+ body: JSON.stringify(body),
92
+ signal: controller.signal,
93
+ });
94
+ if (!res.ok) {
95
+ const text = await res.text().catch(() => "");
96
+ throw new Error(`Agent API error ${res.status} on SSE ${path}: ${text || res.statusText}`);
97
+ }
98
+ // Read SSE stream
99
+ const reader = res.body?.getReader();
100
+ if (!reader)
101
+ throw new Error("No response body from SSE endpoint");
102
+ const decoder = new TextDecoder();
103
+ const events = [];
104
+ let buffer = "";
105
+ while (true) {
106
+ const { done, value } = await reader.read();
107
+ if (done)
108
+ break;
109
+ buffer += decoder.decode(value, { stream: true });
110
+ const lines = buffer.split("\n");
111
+ buffer = lines.pop() || "";
112
+ for (const line of lines) {
113
+ if (line.startsWith("data: ")) {
114
+ const data = line.slice(6).trim();
115
+ if (data === "[DONE]")
116
+ continue;
117
+ try {
118
+ events.push(JSON.parse(data));
119
+ }
120
+ catch {
121
+ events.push(data);
122
+ }
123
+ }
124
+ }
125
+ }
126
+ // Return the last event if it looks like a final result, otherwise all events
127
+ if (events.length === 0)
128
+ return { status: "completed", events: [] };
129
+ const last = events[events.length - 1];
130
+ if (typeof last === "object" &&
131
+ last !== null &&
132
+ "status" in last) {
133
+ return last;
134
+ }
135
+ return { status: "completed", events };
136
+ }
137
+ finally {
138
+ clearTimeout(timer);
139
+ }
140
+ }