cli-community-intelligence 0.1.13 → 0.1.15

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.
@@ -1,72 +1,13 @@
1
1
  // ABOUTME: OpenClaw plugin extension entry point
2
2
  // ABOUTME: Registers community-intelligence CLI commands as OpenClaw tools
3
3
 
4
- import { definePluginEntry } from 'openclaw/plugin-sdk/plugin-entry'
5
4
  import { exec } from 'child_process'
6
5
  import { promisify } from 'util'
6
+ import { dirname, resolve } from 'path'
7
+ import { fileURLToPath } from 'url'
7
8
 
8
9
  const execAsync = promisify(exec)
9
-
10
- // ---------------------------------------------------------------------------------------------------------------------
11
- //
12
- // Constants
13
- //
14
- // ---------------------------------------------------------------------------------------------------------------------
15
-
16
- const scrapeToolDef = {
17
- id: 'community-intelligence-scrape',
18
- name: 'community-intelligence-scrape',
19
- description:
20
- 'Scrape posts and comments from online communities (Reddit, YouTube). ' +
21
- 'Use --subreddits for Reddit, --query or --channels for YouTube. ' +
22
- 'Supports --incremental to only fetch new posts since last scrape.',
23
- parameters: {
24
- type: 'object',
25
- properties: {
26
- source: { type: 'string', enum: ['reddit', 'youtube'], description: 'Source platform to scrape' },
27
- subreddits: { type: 'string', description: 'Comma-separated subreddit names (reddit only)' },
28
- query: { type: 'string', description: 'Search query (youtube only)' },
29
- channels: { type: 'string', description: 'Comma-separated YouTube channel IDs (youtube only)' },
30
- incremental: { type: 'boolean', description: 'Only fetch posts newer than last scrape' },
31
- backfill: { type: 'number', description: 'Number of days to backfill' },
32
- },
33
- required: ['source'],
34
- },
35
- }
36
-
37
- const queryToolDef = {
38
- id: 'community-intelligence-query',
39
- name: 'community-intelligence-query',
40
- description:
41
- 'Search the scraped community posts corpus. Filter by source, channel, text, author, date range, or score.',
42
- parameters: {
43
- type: 'object',
44
- properties: {
45
- source: { type: 'string', description: 'Filter by source (reddit, youtube)' },
46
- channel: { type: 'string', description: 'Filter by channel/subreddit' },
47
- text: { type: 'string', description: 'Search text in body and title' },
48
- author: { type: 'string', description: 'Filter by author' },
49
- since: { type: 'string', description: 'Posts after this date (ISO 8601)' },
50
- until: { type: 'string', description: 'Posts before this date (ISO 8601)' },
51
- minScore: { type: 'number', description: 'Minimum score' },
52
- limit: { type: 'number', description: 'Maximum number of results' },
53
- },
54
- },
55
- }
56
-
57
- const statusToolDef = {
58
- id: 'community-intelligence-status',
59
- name: 'community-intelligence-status',
60
- description: 'Show summary statistics for the scraped community intelligence corpus.',
61
- parameters: { type: 'object', properties: {} },
62
- }
63
-
64
- const exportToolDef = {
65
- id: 'community-intelligence-export',
66
- name: 'community-intelligence-export',
67
- description: 'Export matching posts as JSON. Same filters as query.',
68
- parameters: queryToolDef.parameters,
69
- }
10
+ const __dirname = dirname(fileURLToPath(import.meta.url))
70
11
 
71
12
  // ---------------------------------------------------------------------------------------------------------------------
72
13
  //
@@ -92,15 +33,19 @@ const T = {
92
33
 
93
34
  const F = {
94
35
  // Create an execute handler for a given subcommand
95
- // @sig buildExecutor :: String -> (Object -> Promise Object)
96
- buildExecutor: subcommand => async params => {
36
+ // WHY: resolve the bundled CLI path relative to this file — the `community-intelligence` bin
37
+ // won't be on PATH in OpenClaw's plugin sandbox
38
+ // @sig buildExecutor :: String -> (String, Object) -> Promise Object
39
+ buildExecutor: subcommand => async (_toolCallId, params) => {
97
40
  const args = T.toArgs(params)
98
- const cmd = `community-intelligence ${subcommand} ${args}`.trim()
41
+ const cliBin = resolve(__dirname, 'dist/cli.js')
42
+ const cmd = `node "${cliBin}" ${subcommand} ${args}`.trim()
99
43
  try {
100
44
  const { stdout, stderr } = await execAsync(cmd)
101
- return { success: true, stdout, stderr }
45
+ const text = [stdout, stderr].filter(Boolean).join('\n')
46
+ return { content: [{ type: 'text', text }], details: null }
102
47
  } catch (error) {
103
- return { success: false, error: String(error) }
48
+ return { content: [{ type: 'text', text: `Error: ${String(error)}` }], details: null }
104
49
  }
105
50
  },
106
51
  }
@@ -111,13 +56,76 @@ const F = {
111
56
  //
112
57
  // ---------------------------------------------------------------------------------------------------------------------
113
58
 
114
- export default definePluginEntry({
59
+ export default {
115
60
  id: 'cli-community-intelligence',
116
61
  name: 'Community Intelligence',
62
+ description: 'Scrape and query posts from online communities (Reddit, YouTube)',
117
63
  register(api) {
118
- api.registerTool(scrapeToolDef, { execute: F.buildExecutor('scrape') })
119
- api.registerTool(queryToolDef, { execute: F.buildExecutor('query') })
120
- api.registerTool(statusToolDef, { execute: F.buildExecutor('status') })
121
- api.registerTool(exportToolDef, { execute: F.buildExecutor('export') })
64
+ api.registerTool({
65
+ name: 'community-intelligence-scrape',
66
+ description:
67
+ 'Scrape posts and comments from online communities (Reddit, YouTube). ' +
68
+ 'Use --subreddits for Reddit, --query or --channels for YouTube. ' +
69
+ 'Supports --incremental to only fetch new posts since last scrape.',
70
+ parameters: {
71
+ type: 'object',
72
+ properties: {
73
+ source: { type: 'string', enum: ['reddit', 'youtube'], description: 'Source platform to scrape' },
74
+ subreddits: { type: 'string', description: 'Comma-separated subreddit names (reddit only)' },
75
+ query: { type: 'string', description: 'Search query (youtube only)' },
76
+ channels: { type: 'string', description: 'Comma-separated YouTube channel IDs (youtube only)' },
77
+ incremental: { type: 'boolean', description: 'Only fetch posts newer than last scrape' },
78
+ backfill: { type: 'number', description: 'Number of days to backfill' },
79
+ },
80
+ required: ['source'],
81
+ },
82
+ execute: F.buildExecutor('scrape'),
83
+ })
84
+
85
+ api.registerTool({
86
+ name: 'community-intelligence-query',
87
+ description:
88
+ 'Search the scraped community posts corpus. Filter by source, channel, text, author, date range, or score.',
89
+ parameters: {
90
+ type: 'object',
91
+ properties: {
92
+ source: { type: 'string', description: 'Filter by source (reddit, youtube)' },
93
+ channel: { type: 'string', description: 'Filter by channel/subreddit' },
94
+ text: { type: 'string', description: 'Search text in body and title' },
95
+ author: { type: 'string', description: 'Filter by author' },
96
+ since: { type: 'string', description: 'Posts after this date (ISO 8601)' },
97
+ until: { type: 'string', description: 'Posts before this date (ISO 8601)' },
98
+ minScore: { type: 'number', description: 'Minimum score' },
99
+ limit: { type: 'number', description: 'Maximum number of results' },
100
+ },
101
+ },
102
+ execute: F.buildExecutor('query'),
103
+ })
104
+
105
+ api.registerTool({
106
+ name: 'community-intelligence-status',
107
+ description: 'Show summary statistics for the scraped community intelligence corpus.',
108
+ parameters: { type: 'object', properties: {} },
109
+ execute: F.buildExecutor('status'),
110
+ })
111
+
112
+ api.registerTool({
113
+ name: 'community-intelligence-export',
114
+ description: 'Export matching posts as JSON. Same filters as query.',
115
+ parameters: {
116
+ type: 'object',
117
+ properties: {
118
+ source: { type: 'string', description: 'Filter by source (reddit, youtube)' },
119
+ channel: { type: 'string', description: 'Filter by channel/subreddit' },
120
+ text: { type: 'string', description: 'Search text in body and title' },
121
+ author: { type: 'string', description: 'Filter by author' },
122
+ since: { type: 'string', description: 'Posts after this date (ISO 8601)' },
123
+ until: { type: 'string', description: 'Posts before this date (ISO 8601)' },
124
+ minScore: { type: 'number', description: 'Minimum score' },
125
+ limit: { type: 'number', description: 'Maximum number of results' },
126
+ },
127
+ },
128
+ execute: F.buildExecutor('export'),
129
+ })
122
130
  },
123
- })
131
+ }
@@ -2,7 +2,7 @@
2
2
  "id": "cli-community-intelligence",
3
3
  "name": "Community Intelligence",
4
4
  "description": "Scrape and query posts from online communities (Reddit, YouTube)",
5
- "version": "0.1.13",
5
+ "version": "0.1.15",
6
6
  "contracts": {
7
7
  "tools": [
8
8
  "community-intelligence-scrape",
@@ -11,6 +11,9 @@
11
11
  "community-intelligence-export"
12
12
  ]
13
13
  },
14
+ "capabilities": {
15
+ "childProcess": true
16
+ },
14
17
  "configSchema": {
15
18
  "type": "object",
16
19
  "additionalProperties": false,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cli-community-intelligence",
3
- "version": "0.1.13",
3
+ "version": "0.1.15",
4
4
  "description": "Community intelligence scraper for construction industry market research",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",