cli-community-intelligence 0.1.5 → 0.1.7

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.
@@ -0,0 +1,116 @@
1
+ // ABOUTME: OpenClaw plugin extension entry point
2
+ // ABOUTME: Registers community-intelligence CLI commands as OpenClaw tools
3
+
4
+ import { definePluginEntry } from 'openclaw/plugin-sdk/plugin-entry'
5
+ import { runCommand } from 'openclaw/plugin-sdk/run-command'
6
+
7
+ // ---------------------------------------------------------------------------------------------------------------------
8
+ //
9
+ // Constants
10
+ //
11
+ // ---------------------------------------------------------------------------------------------------------------------
12
+
13
+ const scrapeToolDef = {
14
+ id: 'community-intelligence-scrape',
15
+ name: 'Scrape Community Posts',
16
+ description:
17
+ 'Scrape posts and comments from online communities (Reddit, YouTube). ' +
18
+ 'Use --subreddits for Reddit, --query or --channels for YouTube. ' +
19
+ 'Supports --incremental to only fetch new posts since last scrape.',
20
+ parameters: {
21
+ type: 'object',
22
+ properties: {
23
+ source: { type: 'string', enum: ['reddit', 'youtube'], description: 'Source platform to scrape' },
24
+ subreddits: { type: 'string', description: 'Comma-separated subreddit names (reddit only)' },
25
+ query: { type: 'string', description: 'Search query (youtube only)' },
26
+ channels: { type: 'string', description: 'Comma-separated YouTube channel IDs (youtube only)' },
27
+ incremental: { type: 'boolean', description: 'Only fetch posts newer than last scrape' },
28
+ backfill: { type: 'number', description: 'Number of days to backfill' },
29
+ },
30
+ required: ['source'],
31
+ },
32
+ }
33
+
34
+ const queryToolDef = {
35
+ id: 'community-intelligence-query',
36
+ name: 'Query Community Corpus',
37
+ description:
38
+ 'Search the scraped community posts corpus. Filter by source, channel, text, author, date range, or score.',
39
+ parameters: {
40
+ type: 'object',
41
+ properties: {
42
+ source: { type: 'string', description: 'Filter by source (reddit, youtube)' },
43
+ channel: { type: 'string', description: 'Filter by channel/subreddit' },
44
+ text: { type: 'string', description: 'Search text in body and title' },
45
+ author: { type: 'string', description: 'Filter by author' },
46
+ since: { type: 'string', description: 'Posts after this date (ISO 8601)' },
47
+ until: { type: 'string', description: 'Posts before this date (ISO 8601)' },
48
+ minScore: { type: 'number', description: 'Minimum score' },
49
+ limit: { type: 'number', description: 'Maximum number of results' },
50
+ },
51
+ },
52
+ }
53
+
54
+ const statusToolDef = {
55
+ id: 'community-intelligence-status',
56
+ name: 'Community Corpus Status',
57
+ description: 'Show summary statistics for the scraped community intelligence corpus.',
58
+ parameters: { type: 'object', properties: {} },
59
+ }
60
+
61
+ const exportToolDef = {
62
+ id: 'community-intelligence-export',
63
+ name: 'Export Community Posts',
64
+ description: 'Export matching posts as JSON. Same filters as query.',
65
+ parameters: queryToolDef.parameters,
66
+ }
67
+
68
+ // ---------------------------------------------------------------------------------------------------------------------
69
+ //
70
+ // Transformers
71
+ //
72
+ // ---------------------------------------------------------------------------------------------------------------------
73
+
74
+ const T = {
75
+ // Build CLI args string from params object, skipping undefined values
76
+ // @sig toArgs :: Object -> String
77
+ toArgs: params =>
78
+ Object.entries(params)
79
+ .filter(([, v]) => v !== undefined && v !== '')
80
+ .map(([k, v]) => (v === true ? `--${k}` : `--${k} ${v}`))
81
+ .join(' '),
82
+ }
83
+
84
+ // ---------------------------------------------------------------------------------------------------------------------
85
+ //
86
+ // Factories
87
+ //
88
+ // ---------------------------------------------------------------------------------------------------------------------
89
+
90
+ const F = {
91
+ // Create an execute handler for a given subcommand
92
+ // @sig buildExecutor :: String -> (Object -> Promise Object)
93
+ buildExecutor: subcommand => async params => {
94
+ const args = T.toArgs(params)
95
+ const cmd = `community-intelligence ${subcommand} ${args}`.trim()
96
+ try {
97
+ const result = await runCommand(cmd)
98
+ return { success: true, stdout: result.stdout, stderr: result.stderr }
99
+ } catch (error) {
100
+ return { success: false, error: String(error) }
101
+ }
102
+ },
103
+ }
104
+
105
+ // ---------------------------------------------------------------------------------------------------------------------
106
+ //
107
+ // Exports
108
+ //
109
+ // ---------------------------------------------------------------------------------------------------------------------
110
+
111
+ export default definePluginEntry(async api => {
112
+ api.registerTool(scrapeToolDef, { execute: F.buildExecutor('scrape') })
113
+ api.registerTool(queryToolDef, { execute: F.buildExecutor('query') })
114
+ api.registerTool(statusToolDef, { execute: F.buildExecutor('status') })
115
+ api.registerTool(exportToolDef, { execute: F.buildExecutor('export') })
116
+ })
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cli-community-intelligence",
3
- "version": "0.1.5",
3
+ "version": "0.1.7",
4
4
  "description": "Community intelligence scraper for construction industry market research",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -11,6 +11,11 @@
11
11
  "type": "git",
12
12
  "url": "https://github.com/graffio/graffio-monorepo.git"
13
13
  },
14
+ "openclaw": {
15
+ "extensions": [
16
+ "./openclaw-extension.js"
17
+ ]
18
+ },
14
19
  "dependencies": {
15
20
  "better-sqlite3": "^8.7.0"
16
21
  }