@kernel.chat/kbot 3.20.1 → 3.22.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/dist/agent.d.ts.map +1 -1
- package/dist/agent.js +33 -0
- package/dist/agent.js.map +1 -1
- package/dist/cli.js +141 -1
- package/dist/cli.js.map +1 -1
- package/dist/discovery.d.ts +58 -0
- package/dist/discovery.d.ts.map +1 -0
- package/dist/discovery.js +364 -0
- package/dist/discovery.js.map +1 -0
- package/dist/privacy-router.d.ts +48 -0
- package/dist/privacy-router.d.ts.map +1 -0
- package/dist/privacy-router.js +247 -0
- package/dist/privacy-router.js.map +1 -0
- package/dist/sandbox-policy.d.ts +47 -0
- package/dist/sandbox-policy.d.ts.map +1 -0
- package/dist/sandbox-policy.js +257 -0
- package/dist/sandbox-policy.js.map +1 -0
- package/package.json +1 -1
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
export interface DiscoveryConfig {
|
|
2
|
+
/** Project name (e.g., "kbot", "my-api") */
|
|
3
|
+
projectName: string;
|
|
4
|
+
/** One-line description */
|
|
5
|
+
projectDescription: string;
|
|
6
|
+
/** Topics kbot should look for (e.g., ["AI agent", "terminal tool", "local LLM"]) */
|
|
7
|
+
topics: string[];
|
|
8
|
+
/** HN username (for posting) */
|
|
9
|
+
hnUsername?: string;
|
|
10
|
+
/** HN cookie string (for posting) */
|
|
11
|
+
hnCookie?: string;
|
|
12
|
+
/** GitHub token (for commenting on issues) — uses gh CLI if available */
|
|
13
|
+
githubToken?: string;
|
|
14
|
+
/** Max posts per cycle */
|
|
15
|
+
maxPostsPerCycle: number;
|
|
16
|
+
/** Poll interval in minutes */
|
|
17
|
+
pollIntervalMinutes: number;
|
|
18
|
+
/** Dry run — find + draft but don't post */
|
|
19
|
+
dryRun: boolean;
|
|
20
|
+
/** Ollama model for analysis */
|
|
21
|
+
ollamaModel: string;
|
|
22
|
+
/** Ollama URL */
|
|
23
|
+
ollamaUrl: string;
|
|
24
|
+
}
|
|
25
|
+
export interface Opportunity {
|
|
26
|
+
source: 'hn' | 'github' | 'reddit';
|
|
27
|
+
title: string;
|
|
28
|
+
url: string;
|
|
29
|
+
snippet: string;
|
|
30
|
+
foundAt: string;
|
|
31
|
+
}
|
|
32
|
+
export interface PostRecord {
|
|
33
|
+
timestamp: string;
|
|
34
|
+
url: string;
|
|
35
|
+
title: string;
|
|
36
|
+
comment: string;
|
|
37
|
+
platform: string;
|
|
38
|
+
success: boolean;
|
|
39
|
+
error?: string;
|
|
40
|
+
}
|
|
41
|
+
export interface DiscoveryState {
|
|
42
|
+
totalScans: number;
|
|
43
|
+
totalFound: number;
|
|
44
|
+
totalPosted: number;
|
|
45
|
+
totalSkipped: number;
|
|
46
|
+
lastScan: string;
|
|
47
|
+
posts: PostRecord[];
|
|
48
|
+
}
|
|
49
|
+
export declare function loadConfig(): DiscoveryConfig | null;
|
|
50
|
+
export declare function saveConfig(config: DiscoveryConfig): void;
|
|
51
|
+
export declare function runDiscoveryCycle(config: DiscoveryConfig): Promise<{
|
|
52
|
+
found: number;
|
|
53
|
+
posted: number;
|
|
54
|
+
skipped: number;
|
|
55
|
+
}>;
|
|
56
|
+
export declare function getDiscoveryState(): DiscoveryState;
|
|
57
|
+
export declare function getRecentLog(lines?: number): string;
|
|
58
|
+
//# sourceMappingURL=discovery.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"discovery.d.ts","sourceRoot":"","sources":["../src/discovery.ts"],"names":[],"mappings":"AAuBA,MAAM,WAAW,eAAe;IAC9B,4CAA4C;IAC5C,WAAW,EAAE,MAAM,CAAA;IACnB,2BAA2B;IAC3B,kBAAkB,EAAE,MAAM,CAAA;IAC1B,qFAAqF;IACrF,MAAM,EAAE,MAAM,EAAE,CAAA;IAChB,gCAAgC;IAChC,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,qCAAqC;IACrC,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,yEAAyE;IACzE,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,0BAA0B;IAC1B,gBAAgB,EAAE,MAAM,CAAA;IACxB,+BAA+B;IAC/B,mBAAmB,EAAE,MAAM,CAAA;IAC3B,4CAA4C;IAC5C,MAAM,EAAE,OAAO,CAAA;IACf,gCAAgC;IAChC,WAAW,EAAE,MAAM,CAAA;IACnB,iBAAiB;IACjB,SAAS,EAAE,MAAM,CAAA;CAClB;AAED,MAAM,WAAW,WAAW;IAC1B,MAAM,EAAE,IAAI,GAAG,QAAQ,GAAG,QAAQ,CAAA;IAClC,KAAK,EAAE,MAAM,CAAA;IACb,GAAG,EAAE,MAAM,CAAA;IACX,OAAO,EAAE,MAAM,CAAA;IACf,OAAO,EAAE,MAAM,CAAA;CAChB;AAED,MAAM,WAAW,UAAU;IACzB,SAAS,EAAE,MAAM,CAAA;IACjB,GAAG,EAAE,MAAM,CAAA;IACX,KAAK,EAAE,MAAM,CAAA;IACb,OAAO,EAAE,MAAM,CAAA;IACf,QAAQ,EAAE,MAAM,CAAA;IAChB,OAAO,EAAE,OAAO,CAAA;IAChB,KAAK,CAAC,EAAE,MAAM,CAAA;CACf;AAED,MAAM,WAAW,cAAc;IAC7B,UAAU,EAAE,MAAM,CAAA;IAClB,UAAU,EAAE,MAAM,CAAA;IAClB,WAAW,EAAE,MAAM,CAAA;IACnB,YAAY,EAAE,MAAM,CAAA;IACpB,QAAQ,EAAE,MAAM,CAAA;IAChB,KAAK,EAAE,UAAU,EAAE,CAAA;CACpB;AAeD,wBAAgB,UAAU,IAAI,eAAe,GAAG,IAAI,CAGnD;AAED,wBAAgB,UAAU,CAAC,MAAM,EAAE,eAAe,GAAG,IAAI,CAGxD;AAoQD,wBAAsB,iBAAiB,CAAC,MAAM,EAAE,eAAe,GAAG,OAAO,CAAC;IACxE,KAAK,EAAE,MAAM,CAAA;IACb,MAAM,EAAE,MAAM,CAAA;IACd,OAAO,EAAE,MAAM,CAAA;CAChB,CAAC,CAkGD;AAED,wBAAgB,iBAAiB,IAAI,cAAc,CAElD;AAED,wBAAgB,YAAY,CAAC,KAAK,SAAK,GAAG,MAAM,CAI/C"}
|
|
@@ -0,0 +1,364 @@
|
|
|
1
|
+
// kbot Discovery Agent — autonomous outreach for any project
|
|
2
|
+
//
|
|
3
|
+
// Scans HN, GitHub Issues, Reddit for conversations relevant to your project.
|
|
4
|
+
// Drafts authentic technical responses. Posts them autonomously.
|
|
5
|
+
// Learns what works. Adjusts over time.
|
|
6
|
+
//
|
|
7
|
+
// Usage:
|
|
8
|
+
// kbot discovery start # start autonomous discovery loop
|
|
9
|
+
// kbot discovery start --dry-run # find + draft but don't post
|
|
10
|
+
// kbot discovery status # show what's been found/posted
|
|
11
|
+
// kbot discovery auth # configure HN/Reddit/GitHub credentials
|
|
12
|
+
// kbot discovery log # show recent activity
|
|
13
|
+
//
|
|
14
|
+
// The user teaches kbot once: project name, description, topics of expertise,
|
|
15
|
+
// and platform credentials. Then kbot runs autonomously.
|
|
16
|
+
import { existsSync, readFileSync, writeFileSync, mkdirSync, appendFileSync } from 'node:fs';
|
|
17
|
+
import { join } from 'node:path';
|
|
18
|
+
import { homedir } from 'node:os';
|
|
19
|
+
import { execSync } from 'node:child_process';
|
|
20
|
+
// ── Paths ──
|
|
21
|
+
const DISCOVERY_DIR = join(homedir(), '.kbot', 'discovery');
|
|
22
|
+
const CONFIG_FILE = join(DISCOVERY_DIR, 'config.json');
|
|
23
|
+
const STATE_FILE = join(DISCOVERY_DIR, 'state.json');
|
|
24
|
+
const LOG_FILE = join(DISCOVERY_DIR, 'activity.log');
|
|
25
|
+
function ensureDir() {
|
|
26
|
+
if (!existsSync(DISCOVERY_DIR))
|
|
27
|
+
mkdirSync(DISCOVERY_DIR, { recursive: true });
|
|
28
|
+
}
|
|
29
|
+
// ── Config ──
|
|
30
|
+
export function loadConfig() {
|
|
31
|
+
if (!existsSync(CONFIG_FILE))
|
|
32
|
+
return null;
|
|
33
|
+
try {
|
|
34
|
+
return JSON.parse(readFileSync(CONFIG_FILE, 'utf8'));
|
|
35
|
+
}
|
|
36
|
+
catch {
|
|
37
|
+
return null;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
export function saveConfig(config) {
|
|
41
|
+
ensureDir();
|
|
42
|
+
writeFileSync(CONFIG_FILE, JSON.stringify(config, null, 2));
|
|
43
|
+
}
|
|
44
|
+
function loadState() {
|
|
45
|
+
if (!existsSync(STATE_FILE))
|
|
46
|
+
return { totalScans: 0, totalFound: 0, totalPosted: 0, totalSkipped: 0, lastScan: '', posts: [] };
|
|
47
|
+
try {
|
|
48
|
+
return JSON.parse(readFileSync(STATE_FILE, 'utf8'));
|
|
49
|
+
}
|
|
50
|
+
catch {
|
|
51
|
+
return { totalScans: 0, totalFound: 0, totalPosted: 0, totalSkipped: 0, lastScan: '', posts: [] };
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
function saveState(state) {
|
|
55
|
+
ensureDir();
|
|
56
|
+
writeFileSync(STATE_FILE, JSON.stringify(state, null, 2));
|
|
57
|
+
}
|
|
58
|
+
function log(msg) {
|
|
59
|
+
ensureDir();
|
|
60
|
+
const line = `[${new Date().toISOString().slice(0, 19)}] ${msg}\n`;
|
|
61
|
+
appendFileSync(LOG_FILE, line);
|
|
62
|
+
console.log(msg);
|
|
63
|
+
}
|
|
64
|
+
// ── Scanning ──
|
|
65
|
+
async function fetchJson(url) {
|
|
66
|
+
const res = await fetch(url, {
|
|
67
|
+
headers: { 'User-Agent': 'kbot-discovery/1.0' },
|
|
68
|
+
signal: AbortSignal.timeout(10000),
|
|
69
|
+
});
|
|
70
|
+
if (!res.ok)
|
|
71
|
+
throw new Error(`HTTP ${res.status}`);
|
|
72
|
+
return res.json();
|
|
73
|
+
}
|
|
74
|
+
async function scanHN(topics) {
|
|
75
|
+
const opportunities = [];
|
|
76
|
+
const queries = topics.map(t => t.replace(/\s+/g, '+'));
|
|
77
|
+
for (const q of queries.slice(0, 4)) {
|
|
78
|
+
try {
|
|
79
|
+
const data = await fetchJson(`https://hn.algolia.com/api/v1/search_by_date?query=${q}&tags=(story,show_hn,ask_hn)&hitsPerPage=5`);
|
|
80
|
+
for (const hit of (data.hits || [])) {
|
|
81
|
+
if (hit.points >= 1) {
|
|
82
|
+
opportunities.push({
|
|
83
|
+
source: 'hn',
|
|
84
|
+
title: hit.title,
|
|
85
|
+
url: `https://news.ycombinator.com/item?id=${hit.objectID}`,
|
|
86
|
+
snippet: hit.title,
|
|
87
|
+
foundAt: new Date().toISOString(),
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
catch { /* skip failed queries */ }
|
|
93
|
+
}
|
|
94
|
+
// Also search comments for questions/requests
|
|
95
|
+
for (const q of queries.slice(0, 2)) {
|
|
96
|
+
try {
|
|
97
|
+
const data = await fetchJson(`https://hn.algolia.com/api/v1/search_by_date?query=${q}&tags=comment&hitsPerPage=3`);
|
|
98
|
+
for (const hit of (data.hits || [])) {
|
|
99
|
+
if (hit.comment_text?.length > 50) {
|
|
100
|
+
opportunities.push({
|
|
101
|
+
source: 'hn',
|
|
102
|
+
title: hit.story_title || 'HN thread',
|
|
103
|
+
url: `https://news.ycombinator.com/item?id=${hit.objectID}`,
|
|
104
|
+
snippet: hit.comment_text.slice(0, 200),
|
|
105
|
+
foundAt: new Date().toISOString(),
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
catch { /* skip */ }
|
|
111
|
+
}
|
|
112
|
+
return opportunities;
|
|
113
|
+
}
|
|
114
|
+
async function scanGitHub(topics) {
|
|
115
|
+
const opportunities = [];
|
|
116
|
+
for (const topic of topics.slice(0, 3)) {
|
|
117
|
+
try {
|
|
118
|
+
const q = encodeURIComponent(`${topic} in:title,body state:open`);
|
|
119
|
+
const data = await fetchJson(`https://api.github.com/search/issues?q=${q}&sort=created&order=desc&per_page=5`);
|
|
120
|
+
for (const item of (data.items || [])) {
|
|
121
|
+
opportunities.push({
|
|
122
|
+
source: 'github',
|
|
123
|
+
title: item.title,
|
|
124
|
+
url: item.html_url,
|
|
125
|
+
snippet: (item.body || '').slice(0, 200),
|
|
126
|
+
foundAt: new Date().toISOString(),
|
|
127
|
+
});
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
catch { /* skip */ }
|
|
131
|
+
}
|
|
132
|
+
return opportunities;
|
|
133
|
+
}
|
|
134
|
+
async function scanReddit(topics) {
|
|
135
|
+
const opportunities = [];
|
|
136
|
+
const subs = ['programming', 'commandline', 'artificial', 'LocalLLaMA', 'ChatGPTCoding'];
|
|
137
|
+
for (const sub of subs.slice(0, 3)) {
|
|
138
|
+
try {
|
|
139
|
+
const data = await fetchJson(`https://www.reddit.com/r/${sub}/new.json?limit=5`);
|
|
140
|
+
for (const post of (data.data?.children || [])) {
|
|
141
|
+
const d = post.data;
|
|
142
|
+
const matchesTopic = topics.some(t => d.title.toLowerCase().includes(t.toLowerCase()) ||
|
|
143
|
+
d.selftext.toLowerCase().includes(t.toLowerCase()));
|
|
144
|
+
if (matchesTopic) {
|
|
145
|
+
opportunities.push({
|
|
146
|
+
source: 'reddit',
|
|
147
|
+
title: d.title,
|
|
148
|
+
url: `https://www.reddit.com${d.permalink}`,
|
|
149
|
+
snippet: d.selftext.slice(0, 200),
|
|
150
|
+
foundAt: new Date().toISOString(),
|
|
151
|
+
});
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
catch { /* skip */ }
|
|
156
|
+
}
|
|
157
|
+
return opportunities;
|
|
158
|
+
}
|
|
159
|
+
// ── Analysis (Local Ollama) ──
|
|
160
|
+
async function analyzeOpportunity(opp, config) {
|
|
161
|
+
const prompt = `You are evaluating whether to comment on this post. You represent the project "${config.projectName}" — ${config.projectDescription}.
|
|
162
|
+
|
|
163
|
+
Post title: "${opp.title}"
|
|
164
|
+
Post snippet: "${opp.snippet}"
|
|
165
|
+
Platform: ${opp.source}
|
|
166
|
+
|
|
167
|
+
Rules:
|
|
168
|
+
- Only respond if you have GENUINE technical insight to add
|
|
169
|
+
- Never be promotional — no "check out my tool" or "we built something similar"
|
|
170
|
+
- Share specific technical knowledge, ask good questions, or add nuance
|
|
171
|
+
- If the post is about medical, legal, financial, or political topics → NOT RELEVANT
|
|
172
|
+
- If you can't add real value → NOT RELEVANT
|
|
173
|
+
|
|
174
|
+
Reply in this EXACT JSON format (no markdown, no explanation):
|
|
175
|
+
{"relevant": true/false, "reasoning": "why", "draft": "your comment text"}`;
|
|
176
|
+
try {
|
|
177
|
+
const res = await fetch(`${config.ollamaUrl}/api/generate`, {
|
|
178
|
+
method: 'POST',
|
|
179
|
+
headers: { 'Content-Type': 'application/json' },
|
|
180
|
+
body: JSON.stringify({
|
|
181
|
+
model: config.ollamaModel,
|
|
182
|
+
prompt,
|
|
183
|
+
stream: false,
|
|
184
|
+
options: { num_predict: 500, temperature: 0.7 },
|
|
185
|
+
}),
|
|
186
|
+
});
|
|
187
|
+
if (!res.ok)
|
|
188
|
+
return { relevant: false, draft: '', reasoning: 'Ollama unavailable' };
|
|
189
|
+
const data = await res.json();
|
|
190
|
+
const raw = (data.response || '')
|
|
191
|
+
.replace(/<think>[\s\S]*?<\/think>/g, '')
|
|
192
|
+
.trim();
|
|
193
|
+
const jsonMatch = raw.match(/\{[\s\S]*\}/);
|
|
194
|
+
if (jsonMatch) {
|
|
195
|
+
const parsed = JSON.parse(jsonMatch[0]);
|
|
196
|
+
return {
|
|
197
|
+
relevant: !!parsed.relevant,
|
|
198
|
+
draft: parsed.draft || '',
|
|
199
|
+
reasoning: parsed.reasoning || '',
|
|
200
|
+
};
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
catch { /* analysis failed */ }
|
|
204
|
+
return { relevant: false, draft: '', reasoning: 'Analysis failed' };
|
|
205
|
+
}
|
|
206
|
+
// ── Posting ──
|
|
207
|
+
async function postToHN(url, comment, config) {
|
|
208
|
+
if (!config.hnCookie)
|
|
209
|
+
return false;
|
|
210
|
+
const idMatch = url.match(/id=(\d+)/);
|
|
211
|
+
if (!idMatch)
|
|
212
|
+
return false;
|
|
213
|
+
const itemId = idMatch[1];
|
|
214
|
+
try {
|
|
215
|
+
// Fetch page for HMAC token
|
|
216
|
+
const pageRes = await fetch(`https://news.ycombinator.com/item?id=${itemId}`, {
|
|
217
|
+
headers: { 'Cookie': config.hnCookie },
|
|
218
|
+
});
|
|
219
|
+
const html = await pageRes.text();
|
|
220
|
+
// Verify logged in
|
|
221
|
+
if (config.hnUsername && !html.includes(config.hnUsername)) {
|
|
222
|
+
log('HN cookie expired — run `kbot discovery auth` to refresh');
|
|
223
|
+
return false;
|
|
224
|
+
}
|
|
225
|
+
// Extract HMAC
|
|
226
|
+
const hmacMatch = html.match(/name="hmac"\s+value="([^"]+)"/)
|
|
227
|
+
|| html.match(/value="([^"]+)"\s+name="hmac"/)
|
|
228
|
+
|| html.match(/hmac.*?value="([a-f0-9]{40,})"/);
|
|
229
|
+
if (!hmacMatch) {
|
|
230
|
+
log('No HMAC found on HN page');
|
|
231
|
+
return false;
|
|
232
|
+
}
|
|
233
|
+
// Post comment
|
|
234
|
+
const postRes = await fetch('https://news.ycombinator.com/comment', {
|
|
235
|
+
method: 'POST',
|
|
236
|
+
headers: {
|
|
237
|
+
'Content-Type': 'application/x-www-form-urlencoded',
|
|
238
|
+
'Cookie': config.hnCookie,
|
|
239
|
+
'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7)',
|
|
240
|
+
'Origin': 'https://news.ycombinator.com',
|
|
241
|
+
'Referer': `https://news.ycombinator.com/item?id=${itemId}`,
|
|
242
|
+
},
|
|
243
|
+
body: `parent=${itemId}&goto=item%3Fid%3D${itemId}&hmac=${encodeURIComponent(hmacMatch[1])}&text=${encodeURIComponent(comment)}`,
|
|
244
|
+
redirect: 'manual',
|
|
245
|
+
});
|
|
246
|
+
return postRes.status === 302 || postRes.status === 200;
|
|
247
|
+
}
|
|
248
|
+
catch {
|
|
249
|
+
return false;
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
async function postToGitHub(url, comment) {
|
|
253
|
+
// Use gh CLI — already authenticated
|
|
254
|
+
const match = url.match(/github\.com\/([^/]+\/[^/]+)\/issues\/(\d+)/);
|
|
255
|
+
if (!match)
|
|
256
|
+
return false;
|
|
257
|
+
try {
|
|
258
|
+
execSync(`gh issue comment ${match[2]} --repo ${match[1]} --body "${comment.replace(/"/g, '\\"')}"`, {
|
|
259
|
+
timeout: 15000, stdio: 'pipe',
|
|
260
|
+
});
|
|
261
|
+
return true;
|
|
262
|
+
}
|
|
263
|
+
catch {
|
|
264
|
+
return false;
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
// ── Main Discovery Loop ──
|
|
268
|
+
export async function runDiscoveryCycle(config) {
|
|
269
|
+
const state = loadState();
|
|
270
|
+
state.totalScans++;
|
|
271
|
+
state.lastScan = new Date().toISOString();
|
|
272
|
+
log(`Scan #${state.totalScans} — searching ${config.topics.join(', ')}...`);
|
|
273
|
+
// Scan all platforms
|
|
274
|
+
const [hnOpps, ghOpps, redditOpps] = await Promise.allSettled([
|
|
275
|
+
scanHN(config.topics),
|
|
276
|
+
scanGitHub(config.topics),
|
|
277
|
+
scanReddit(config.topics),
|
|
278
|
+
]);
|
|
279
|
+
const allOpps = [
|
|
280
|
+
...(hnOpps.status === 'fulfilled' ? hnOpps.value : []),
|
|
281
|
+
...(ghOpps.status === 'fulfilled' ? ghOpps.value : []),
|
|
282
|
+
...(redditOpps.status === 'fulfilled' ? redditOpps.value : []),
|
|
283
|
+
];
|
|
284
|
+
// Dedup by URL
|
|
285
|
+
const seen = new Set(state.posts.map(p => p.url));
|
|
286
|
+
const fresh = allOpps.filter(o => !seen.has(o.url));
|
|
287
|
+
log(`Found ${allOpps.length} total, ${fresh.length} new`);
|
|
288
|
+
state.totalFound += fresh.length;
|
|
289
|
+
let posted = 0;
|
|
290
|
+
let skipped = 0;
|
|
291
|
+
for (const opp of fresh.slice(0, config.maxPostsPerCycle * 3)) {
|
|
292
|
+
if (posted >= config.maxPostsPerCycle)
|
|
293
|
+
break;
|
|
294
|
+
const analysis = await analyzeOpportunity(opp, config);
|
|
295
|
+
if (!analysis.relevant) {
|
|
296
|
+
log(` SKIP: ${opp.title.slice(0, 50)} — ${analysis.reasoning.slice(0, 60)}`);
|
|
297
|
+
skipped++;
|
|
298
|
+
state.totalSkipped++;
|
|
299
|
+
continue;
|
|
300
|
+
}
|
|
301
|
+
log(` RELEVANT: ${opp.title.slice(0, 50)}`);
|
|
302
|
+
log(` Draft: ${analysis.draft.slice(0, 80)}...`);
|
|
303
|
+
if (config.dryRun) {
|
|
304
|
+
log(' (dry run — not posting)');
|
|
305
|
+
state.posts.push({
|
|
306
|
+
timestamp: new Date().toISOString(),
|
|
307
|
+
url: opp.url, title: opp.title,
|
|
308
|
+
comment: analysis.draft, platform: opp.source,
|
|
309
|
+
success: false, error: 'dry_run',
|
|
310
|
+
});
|
|
311
|
+
continue;
|
|
312
|
+
}
|
|
313
|
+
// Post
|
|
314
|
+
let success = false;
|
|
315
|
+
let error;
|
|
316
|
+
if (opp.source === 'hn') {
|
|
317
|
+
success = await postToHN(opp.url, analysis.draft, config);
|
|
318
|
+
if (!success)
|
|
319
|
+
error = 'hn_post_failed';
|
|
320
|
+
}
|
|
321
|
+
else if (opp.source === 'github') {
|
|
322
|
+
success = await postToGitHub(opp.url, analysis.draft);
|
|
323
|
+
if (!success)
|
|
324
|
+
error = 'github_post_failed';
|
|
325
|
+
}
|
|
326
|
+
else {
|
|
327
|
+
error = 'platform_unsupported';
|
|
328
|
+
}
|
|
329
|
+
state.posts.push({
|
|
330
|
+
timestamp: new Date().toISOString(),
|
|
331
|
+
url: opp.url, title: opp.title,
|
|
332
|
+
comment: analysis.draft, platform: opp.source,
|
|
333
|
+
success, error,
|
|
334
|
+
});
|
|
335
|
+
if (success) {
|
|
336
|
+
posted++;
|
|
337
|
+
state.totalPosted++;
|
|
338
|
+
log(` POSTED to ${opp.source}: ${opp.title.slice(0, 50)}`);
|
|
339
|
+
}
|
|
340
|
+
else {
|
|
341
|
+
log(` FAILED: ${error}`);
|
|
342
|
+
}
|
|
343
|
+
// Cooldown between posts (10 seconds)
|
|
344
|
+
if (posted < config.maxPostsPerCycle) {
|
|
345
|
+
await new Promise(r => setTimeout(r, 10000));
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
// Keep only last 200 post records
|
|
349
|
+
if (state.posts.length > 200)
|
|
350
|
+
state.posts = state.posts.slice(-200);
|
|
351
|
+
saveState(state);
|
|
352
|
+
log(`Cycle done: ${fresh.length} found, ${posted} posted, ${skipped} skipped`);
|
|
353
|
+
return { found: fresh.length, posted, skipped };
|
|
354
|
+
}
|
|
355
|
+
export function getDiscoveryState() {
|
|
356
|
+
return loadState();
|
|
357
|
+
}
|
|
358
|
+
export function getRecentLog(lines = 20) {
|
|
359
|
+
if (!existsSync(LOG_FILE))
|
|
360
|
+
return 'No activity yet.';
|
|
361
|
+
const content = readFileSync(LOG_FILE, 'utf8');
|
|
362
|
+
return content.split('\n').filter(Boolean).slice(-lines).join('\n');
|
|
363
|
+
}
|
|
364
|
+
//# sourceMappingURL=discovery.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"discovery.js","sourceRoot":"","sources":["../src/discovery.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
export type PrivacyLevel = 'local-only' | 'local-preferred' | 'cloud-allowed';
|
|
2
|
+
export interface PrivacyPolicy {
|
|
3
|
+
/** Default routing: local-only, local-preferred, cloud-allowed */
|
|
4
|
+
defaultLevel: PrivacyLevel;
|
|
5
|
+
/** Patterns that ALWAYS force local (never sent to cloud) */
|
|
6
|
+
sensitivePatterns: string[];
|
|
7
|
+
/** Domains/hosts allowed for cloud inference */
|
|
8
|
+
allowedCloudHosts: string[];
|
|
9
|
+
/** File path patterns that are always private */
|
|
10
|
+
privateFilePaths: string[];
|
|
11
|
+
/** Whether to log routing decisions */
|
|
12
|
+
auditLog: boolean;
|
|
13
|
+
}
|
|
14
|
+
export interface RoutingDecision {
|
|
15
|
+
/** Where to send: local or cloud */
|
|
16
|
+
target: 'local' | 'cloud';
|
|
17
|
+
/** Why this decision was made */
|
|
18
|
+
reason: string;
|
|
19
|
+
/** Was sensitive content detected? */
|
|
20
|
+
sensitiveDetected: boolean;
|
|
21
|
+
/** What patterns matched (if any) */
|
|
22
|
+
matchedPatterns: string[];
|
|
23
|
+
}
|
|
24
|
+
declare const PRIVACY_POLICY_FILE: string;
|
|
25
|
+
declare const DEFAULT_POLICY: PrivacyPolicy;
|
|
26
|
+
/** Load privacy policy from YAML-like config, or return defaults */
|
|
27
|
+
export declare function loadPrivacyPolicy(): PrivacyPolicy;
|
|
28
|
+
/** Write the default policy file so users can customize it */
|
|
29
|
+
export declare function writeDefaultPolicy(): void;
|
|
30
|
+
/** Check if content contains sensitive patterns */
|
|
31
|
+
export declare function detectSensitiveContent(content: string, policy: PrivacyPolicy): {
|
|
32
|
+
sensitive: boolean;
|
|
33
|
+
matches: string[];
|
|
34
|
+
};
|
|
35
|
+
/** Check if a file path is private */
|
|
36
|
+
export declare function isPrivateFilePath(filePath: string, policy: PrivacyPolicy): boolean;
|
|
37
|
+
/**
|
|
38
|
+
* Decide whether a prompt/tool call should go to local or cloud.
|
|
39
|
+
* This is called BEFORE every inference request.
|
|
40
|
+
*/
|
|
41
|
+
export declare function routeForPrivacy(content: string, policy?: PrivacyPolicy, options?: {
|
|
42
|
+
filePaths?: string[];
|
|
43
|
+
forceLocal?: boolean;
|
|
44
|
+
forceCloud?: boolean;
|
|
45
|
+
}): RoutingDecision;
|
|
46
|
+
export declare function logRoutingDecision(decision: RoutingDecision, prompt: string): void;
|
|
47
|
+
export { DEFAULT_POLICY, PRIVACY_POLICY_FILE };
|
|
48
|
+
//# sourceMappingURL=privacy-router.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"privacy-router.d.ts","sourceRoot":"","sources":["../src/privacy-router.ts"],"names":[],"mappings":"AAoBA,MAAM,MAAM,YAAY,GAAG,YAAY,GAAG,iBAAiB,GAAG,eAAe,CAAA;AAE7E,MAAM,WAAW,aAAa;IAC5B,kEAAkE;IAClE,YAAY,EAAE,YAAY,CAAA;IAC1B,6DAA6D;IAC7D,iBAAiB,EAAE,MAAM,EAAE,CAAA;IAC3B,gDAAgD;IAChD,iBAAiB,EAAE,MAAM,EAAE,CAAA;IAC3B,iDAAiD;IACjD,gBAAgB,EAAE,MAAM,EAAE,CAAA;IAC1B,uCAAuC;IACvC,QAAQ,EAAE,OAAO,CAAA;CAClB;AAED,MAAM,WAAW,eAAe;IAC9B,oCAAoC;IACpC,MAAM,EAAE,OAAO,GAAG,OAAO,CAAA;IACzB,iCAAiC;IACjC,MAAM,EAAE,MAAM,CAAA;IACd,sCAAsC;IACtC,iBAAiB,EAAE,OAAO,CAAA;IAC1B,qCAAqC;IACrC,eAAe,EAAE,MAAM,EAAE,CAAA;CAC1B;AAKD,QAAA,MAAM,mBAAmB,QAAmC,CAAA;AAK5D,QAAA,MAAM,cAAc,EAAE,aA6BrB,CAAA;AAQD,oEAAoE;AACpE,wBAAgB,iBAAiB,IAAI,aAAa,CA6CjD;AAED,8DAA8D;AAC9D,wBAAgB,kBAAkB,IAAI,IAAI,CAkDzC;AAID,mDAAmD;AACnD,wBAAgB,sBAAsB,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,aAAa,GAAG;IAAE,SAAS,EAAE,OAAO,CAAC;IAAC,OAAO,EAAE,MAAM,EAAE,CAAA;CAAE,CAaxH;AAED,sCAAsC;AACtC,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,aAAa,GAAG,OAAO,CAalF;AAID;;;GAGG;AACH,wBAAgB,eAAe,CAC7B,OAAO,EAAE,MAAM,EACf,MAAM,CAAC,EAAE,aAAa,EACtB,OAAO,CAAC,EAAE;IAAE,SAAS,CAAC,EAAE,MAAM,EAAE,CAAC;IAAC,UAAU,CAAC,EAAE,OAAO,CAAC;IAAC,UAAU,CAAC,EAAE,OAAO,CAAA;CAAE,GAC7E,eAAe,CA6CjB;AAID,wBAAgB,kBAAkB,CAAC,QAAQ,EAAE,eAAe,EAAE,MAAM,EAAE,MAAM,GAAG,IAAI,CAWlF;AAED,OAAO,EAAE,cAAc,EAAE,mBAAmB,EAAE,CAAA"}
|