neofeed-cli 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/dist/index.js ADDED
@@ -0,0 +1,501 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
4
+ if (k2 === undefined) k2 = k;
5
+ var desc = Object.getOwnPropertyDescriptor(m, k);
6
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
7
+ desc = { enumerable: true, get: function() { return m[k]; } };
8
+ }
9
+ Object.defineProperty(o, k2, desc);
10
+ }) : (function(o, m, k, k2) {
11
+ if (k2 === undefined) k2 = k;
12
+ o[k2] = m[k];
13
+ }));
14
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
15
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
16
+ }) : function(o, v) {
17
+ o["default"] = v;
18
+ });
19
+ var __importStar = (this && this.__importStar) || (function () {
20
+ var ownKeys = function(o) {
21
+ ownKeys = Object.getOwnPropertyNames || function (o) {
22
+ var ar = [];
23
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
24
+ return ar;
25
+ };
26
+ return ownKeys(o);
27
+ };
28
+ return function (mod) {
29
+ if (mod && mod.__esModule) return mod;
30
+ var result = {};
31
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
32
+ __setModuleDefault(result, mod);
33
+ return result;
34
+ };
35
+ })();
36
+ var __importDefault = (this && this.__importDefault) || function (mod) {
37
+ return (mod && mod.__esModule) ? mod : { "default": mod };
38
+ };
39
+ Object.defineProperty(exports, "__esModule", { value: true });
40
+ const commander_1 = require("commander");
41
+ const chalk_1 = __importDefault(require("chalk"));
42
+ const axios_1 = __importDefault(require("axios"));
43
+ const fs_1 = __importDefault(require("fs"));
44
+ const path_1 = __importDefault(require("path"));
45
+ const os_1 = __importDefault(require("os"));
46
+ const program = new commander_1.Command();
47
+ const CONFIG_DIR = path_1.default.join(os_1.default.homedir(), '.neofeed');
48
+ const CONFIG_FILE = path_1.default.join(CONFIG_DIR, 'config.json');
49
+ // Helper to get API URL
50
+ const getApiUrl = () => {
51
+ return process.env.NEOFEED_API_URL || 'https://neofeed.app/api';
52
+ };
53
+ // Helper to get stored config
54
+ const getConfig = () => {
55
+ if (!fs_1.default.existsSync(CONFIG_FILE)) {
56
+ return null;
57
+ }
58
+ return JSON.parse(fs_1.default.readFileSync(CONFIG_FILE, 'utf-8'));
59
+ };
60
+ program
61
+ .name('neofeed')
62
+ .description('NeoFeed CLI - The Context Intersection Hub')
63
+ .version('0.1.0');
64
+ program
65
+ .command('login')
66
+ .description('Login with your NeoFeed API Key or via browser')
67
+ .argument('[api-key]', 'Your NeoFeed API Key (optional, will open browser if omitted)')
68
+ .action(async (apiKey) => {
69
+ if (!fs_1.default.existsSync(CONFIG_DIR)) {
70
+ fs_1.default.mkdirSync(CONFIG_DIR, { recursive: true });
71
+ }
72
+ if (apiKey) {
73
+ fs_1.default.writeFileSync(CONFIG_FILE, JSON.stringify({ apiKey }));
74
+ console.log(chalk_1.default.green(`βœ… Successfully logged in via API key. (Key saved to ${CONFIG_FILE})`));
75
+ return;
76
+ }
77
+ console.log(chalk_1.default.blue('🌐 Starting browser authentication...'));
78
+ const express = require('express');
79
+ const cors = require('cors');
80
+ const { default: open } = await Promise.resolve().then(() => __importStar(require('open')));
81
+ const app = express();
82
+ app.use(cors());
83
+ const port = 3456;
84
+ const tokenPromise = new Promise((resolve) => {
85
+ app.get('/callback', (req, res) => {
86
+ const token = req.query.token;
87
+ if (!token) {
88
+ res.status(400).send('<body style="background:#050505;color:white;font-family:sans-serif;display:flex;align-items:center;justify-content:center;height:100vh;margin:0;"><div style="text-align:center"><h1 style="color:#ef4444">ζŽˆζƒε€±θ΄₯</h1><p style="color:rgba(255,255,255,0.6)">ζœͺζ”Άεˆ°ζœ‰ζ•ˆηš„θΊ«δ»½δ»€η‰Œ</p></div></body>');
89
+ return;
90
+ }
91
+ res.send(`
92
+ <body style="background:#050505;color:white;font-family:system-ui, -apple-system, sans-serif;display:flex;align-items:center;justify-content:center;height:100vh;margin:0;">
93
+ <div style="text-align:center;max-width:400px;padding:40px;background:#080808;border:1px solid rgba(255,255,255,0.1);border-radius:24px;box-shadow:0 25px 50px -12px rgba(0,0,0,0.5);">
94
+ <div style="width:64px;height:64px;background:white;color:black;display:flex;align-items:center;justify-content:center;font-weight:bold;font-size:28px;border-radius:16px;margin:0 auto 24px;">N</div>
95
+ <h1 style="margin:0 0 12px;font-size:24px;">ζŽˆζƒζˆεŠŸ</h1>
96
+ <p style="margin:0 0 24px;color:rgba(255,255,255,0.6);line-height:1.5;">NeoFeed CLI 现已连ζŽ₯θ‡³ζ‚¨ηš„θ΄¦ζˆ·γ€‚<br>您可δ»₯ε…³ι—­ζ­€ηͺ—ε£εΉΆθΏ”ε›žη»ˆη«―。</p>
97
+ <div style="border-top:1px solid rgba(255,255,255,0.1);padding-top:24px;">
98
+ <button onclick="window.close()" style="background:white;color:black;border:none;padding:12px 24px;border-radius:12px;font-weight:bold;cursor:pointer;width:100%;transition:background 0.2s;">ε…³ι—­ηͺ—口</button>
99
+ </div>
100
+ </div>
101
+ <script>setTimeout(() => window.close(), 3000)</script>
102
+ </body>
103
+ `);
104
+ resolve(token);
105
+ });
106
+ });
107
+ const server = app.listen(port, async () => {
108
+ const webAuthUrl = process.env.NEOFEED_WEB_URL || 'https://neofeed.app';
109
+ const authUrl = `${webAuthUrl}/cli/auth?port=${port}`;
110
+ console.log(chalk_1.default.yellow(`Opening browser to: ${authUrl}`));
111
+ console.log(chalk_1.default.gray('Waiting for authentication...'));
112
+ try {
113
+ await open(authUrl);
114
+ }
115
+ catch (err) {
116
+ console.log(chalk_1.default.yellow(`Could not open browser automatically. Please visit manually: ${authUrl}`));
117
+ }
118
+ });
119
+ try {
120
+ const token = await tokenPromise;
121
+ fs_1.default.writeFileSync(CONFIG_FILE, JSON.stringify({ apiKey: token }));
122
+ console.log(chalk_1.default.green(`βœ… Successfully logged in via browser! (Key saved to ${CONFIG_FILE})`));
123
+ }
124
+ finally {
125
+ server.close();
126
+ process.exit(0);
127
+ }
128
+ });
129
+ program
130
+ .command('list')
131
+ .description('List recent items in your knowledge base')
132
+ .option('--limit <number>', 'Number of items to return', '10')
133
+ .option('--json', 'Output in JSON format')
134
+ .action(async (options) => {
135
+ const config = getConfig();
136
+ if (!config?.apiKey) {
137
+ console.error(chalk_1.default.red('❌ Not logged in. Please run `neofeed login <api-key>` first.'));
138
+ process.exit(1);
139
+ }
140
+ try {
141
+ if (!options.json) {
142
+ console.log(chalk_1.default.blue(`πŸ“š Fetching your recent knowledge base items...`));
143
+ }
144
+ const response = await axios_1.default.get(`${getApiUrl()}/cli/list?limit=${options.limit}`, {
145
+ headers: { Authorization: `Bearer ${config.apiKey}` }
146
+ });
147
+ const data = response.data;
148
+ if (options.json) {
149
+ console.log(JSON.stringify(data, null, 2));
150
+ }
151
+ else {
152
+ console.log('\n' + chalk_1.default.bold('πŸ“– Your NeoFeed Directory:'));
153
+ console.log(chalk_1.default.gray('----------------------------------------'));
154
+ if (data.length === 0) {
155
+ console.log(chalk_1.default.gray(' No items found.'));
156
+ }
157
+ else {
158
+ data.forEach((item, index) => {
159
+ const icon = item.type === 'agent' ? 'πŸ€–' : '🌐';
160
+ console.log(`${chalk_1.default.gray(`[${index + 1}]`)} ${icon} ${chalk_1.default.white(item.title)}`);
161
+ console.log(` ${chalk_1.default.gray(`ID: ${item.id} | Date: ${new Date(item.created_at).toLocaleDateString()}`)}`);
162
+ });
163
+ }
164
+ console.log(chalk_1.default.gray('----------------------------------------'));
165
+ console.log(chalk_1.default.green(`\n✨ Showing ${data.length} items. Use --limit to see more.`));
166
+ }
167
+ }
168
+ catch (error) {
169
+ const msg = error.response?.data?.error || error.message;
170
+ console.error(chalk_1.default.red(`❌ Failed to fetch data: ${msg}`));
171
+ process.exit(1);
172
+ }
173
+ });
174
+ program
175
+ .command('search')
176
+ .description('Search your NeoFeed knowledge base')
177
+ .argument('<query>', 'Search query')
178
+ .option('--json', 'Output in JSON format')
179
+ .action(async (query, options) => {
180
+ const config = getConfig();
181
+ if (!config?.apiKey) {
182
+ console.error(chalk_1.default.red('❌ Not logged in. Please run `neofeed login <api-key>` first.'));
183
+ process.exit(1);
184
+ }
185
+ if (!options.json) {
186
+ console.log(chalk_1.default.blue(`πŸ” Searching for: "${query}"...`));
187
+ }
188
+ try {
189
+ const response = await axios_1.default.get(`${getApiUrl()}/cli/search?q=${encodeURIComponent(query)}`, {
190
+ headers: { Authorization: `Bearer ${config.apiKey}` }
191
+ });
192
+ const data = response.data;
193
+ if (options.json) {
194
+ console.log(JSON.stringify(data, null, 2));
195
+ }
196
+ else {
197
+ if (data.length === 0) {
198
+ console.log(chalk_1.default.yellow('\nNo results found.'));
199
+ return;
200
+ }
201
+ data.forEach((item, index) => {
202
+ console.log(chalk_1.default.yellow(`\n[${index + 1}] ${item.title}`));
203
+ // Truncate content for display
204
+ const preview = item.content_raw ? item.content_raw.substring(0, 150).replace(/\n/g, ' ') + '...' : 'No content preview';
205
+ console.log(chalk_1.default.gray(preview));
206
+ });
207
+ }
208
+ }
209
+ catch (error) {
210
+ const msg = error.response?.data?.error || error.message;
211
+ console.error(chalk_1.default.red(`❌ Search failed: ${msg}`));
212
+ process.exit(1);
213
+ }
214
+ });
215
+ program
216
+ .command('read')
217
+ .alias('get')
218
+ .description('Read the full content and summary of a specific article by ID')
219
+ .argument('<id>', 'The ID of the item to read')
220
+ .option('--json', 'Output in JSON format')
221
+ .action(async (id, options) => {
222
+ const config = getConfig();
223
+ if (!config?.apiKey) {
224
+ console.error(chalk_1.default.red('❌ Not logged in. Please run `neofeed login` first.'));
225
+ process.exit(1);
226
+ }
227
+ try {
228
+ if (!options.json) {
229
+ console.log(chalk_1.default.blue(`πŸ“– Reading article: ${id}...`));
230
+ }
231
+ const response = await axios_1.default.get(`${getApiUrl()}/cli/read?id=${id}`, {
232
+ headers: { Authorization: `Bearer ${config.apiKey}` }
233
+ });
234
+ const { type, data } = response.data;
235
+ if (options.json) {
236
+ console.log(JSON.stringify(data, null, 2));
237
+ }
238
+ else {
239
+ console.log('\n' + chalk_1.default.bold.white('=================================================='));
240
+ console.log(chalk_1.default.bold.green(data.title || 'Untitled'));
241
+ console.log(chalk_1.default.gray(`ID: ${data.id} | Type: ${type} | Date: ${new Date(data.created_at).toLocaleString()}`));
242
+ if (data.url)
243
+ console.log(chalk_1.default.blue(`URL: ${data.url}`));
244
+ if (data.tags && data.tags.length > 0)
245
+ console.log(chalk_1.default.cyan(`Tags: ${data.tags.join(', ')}`));
246
+ console.log(chalk_1.default.bold.white('==================================================\n'));
247
+ if (data.summary) {
248
+ console.log(chalk_1.default.bold.yellow('πŸ’‘ AI Summary:'));
249
+ console.log(data.summary + '\n');
250
+ }
251
+ if (data.takeaways && data.takeaways.length > 0) {
252
+ console.log(chalk_1.default.bold.yellow('πŸ”‘ Key Takeaways:'));
253
+ data.takeaways.forEach((t) => console.log(`- ${t}`));
254
+ console.log('\n');
255
+ }
256
+ console.log(chalk_1.default.bold.white('πŸ“„ Full Content:'));
257
+ console.log(data.content_raw || chalk_1.default.gray('(No content available)'));
258
+ console.log('\n' + chalk_1.default.bold.white('==================================================\n'));
259
+ }
260
+ }
261
+ catch (error) {
262
+ const msg = error.response?.data?.error || error.message;
263
+ console.error(chalk_1.default.red(`❌ Failed to read article: ${msg}`));
264
+ process.exit(1);
265
+ }
266
+ });
267
+ program
268
+ .command('memo')
269
+ .description('Save a quick memo or agent interaction')
270
+ .argument('<content>', 'The content to save')
271
+ .option('-t, --title <title>', 'Title of the memo')
272
+ .option('--tags <tags>', 'Comma separated tags')
273
+ .action(async (content, options) => {
274
+ const config = getConfig();
275
+ if (!config?.apiKey) {
276
+ console.error(chalk_1.default.red('❌ Not logged in. Please run `neofeed login <api-key>` first.'));
277
+ process.exit(1);
278
+ }
279
+ try {
280
+ const response = await axios_1.default.post(`${getApiUrl()}/cli/memo`, {
281
+ content,
282
+ title: options.title,
283
+ tags: options.tags
284
+ }, {
285
+ headers: { Authorization: `Bearer ${config.apiKey}` }
286
+ });
287
+ console.log(chalk_1.default.green('βœ… Memo saved successfully!'));
288
+ console.log(chalk_1.default.gray(`ID: ${response.data.id}`));
289
+ console.log(chalk_1.default.gray(`Title: ${options.title || 'CLI Memo'}`));
290
+ console.log(chalk_1.default.gray(`Content length: ${content.length} chars`));
291
+ }
292
+ catch (error) {
293
+ const msg = error.response?.data?.error || error.message;
294
+ console.error(chalk_1.default.red(`❌ Failed to save memo: ${msg}`));
295
+ process.exit(1);
296
+ }
297
+ });
298
+ program
299
+ .command('delete')
300
+ .alias('rm')
301
+ .description('Delete an item from your knowledge base by ID')
302
+ .argument('<id>', 'The ID of the item to delete')
303
+ .action(async (id) => {
304
+ const config = getConfig();
305
+ if (!config?.apiKey) {
306
+ console.error(chalk_1.default.red('❌ Not logged in. Please run `neofeed login` first.'));
307
+ process.exit(1);
308
+ }
309
+ try {
310
+ console.log(chalk_1.default.blue(`πŸ—‘οΈ Deleting item: ${id}...`));
311
+ await axios_1.default.delete(`${getApiUrl()}/cli/delete?id=${id}`, {
312
+ headers: { Authorization: `Bearer ${config.apiKey}` }
313
+ });
314
+ console.log(chalk_1.default.green('βœ… Item successfully deleted!'));
315
+ }
316
+ catch (error) {
317
+ const msg = error.response?.data?.error || error.message;
318
+ console.error(chalk_1.default.red(`❌ Failed to delete item: ${msg}`));
319
+ process.exit(1);
320
+ }
321
+ });
322
+ program
323
+ .command('logout')
324
+ .description('Logout and remove your NeoFeed API Key')
325
+ .action(() => {
326
+ if (fs_1.default.existsSync(CONFIG_FILE)) {
327
+ fs_1.default.unlinkSync(CONFIG_FILE);
328
+ console.log(chalk_1.default.green('βœ… Successfully logged out.'));
329
+ }
330
+ else {
331
+ console.log(chalk_1.default.yellow('ℹ️ You are not logged in.'));
332
+ }
333
+ });
334
+ program
335
+ .command('whoami')
336
+ .alias('status')
337
+ .description('Show current user and knowledge base statistics')
338
+ .action(async () => {
339
+ const config = getConfig();
340
+ if (!config?.apiKey) {
341
+ console.error(chalk_1.default.red('❌ Not logged in. Please run `neofeed login` first.'));
342
+ process.exit(1);
343
+ }
344
+ try {
345
+ console.log(chalk_1.default.blue('πŸ‘€ Fetching your profile...'));
346
+ const response = await axios_1.default.get(`${getApiUrl()}/cli/me`, {
347
+ headers: { Authorization: `Bearer ${config.apiKey}` }
348
+ });
349
+ const data = response.data;
350
+ console.log('\n' + chalk_1.default.bold('=== NeoFeed Status ==='));
351
+ console.log(chalk_1.default.gray('Email: ') + chalk_1.default.white(data.email));
352
+ console.log(chalk_1.default.gray('User ID: ') + chalk_1.default.white(data.id));
353
+ console.log(chalk_1.default.gray('----------------------'));
354
+ console.log(chalk_1.default.gray('Total Feeds: ') + chalk_1.default.cyan(data.stats.feeds));
355
+ console.log(chalk_1.default.gray('Agent Interactions: ') + chalk_1.default.cyan(data.stats.agent_interactions));
356
+ console.log(chalk_1.default.gray('----------------------'));
357
+ console.log(chalk_1.default.green(`Total Items: ${data.stats.total_items}`));
358
+ console.log(chalk_1.default.bold('======================\n'));
359
+ }
360
+ catch (error) {
361
+ const msg = error.response?.data?.error || error.message;
362
+ console.error(chalk_1.default.red(`❌ Failed to fetch profile: ${msg}`));
363
+ process.exit(1);
364
+ }
365
+ });
366
+ program
367
+ .command('capture')
368
+ .alias('add')
369
+ .description('Capture a webpage URL and add it to your knowledge base')
370
+ .argument('<url>', 'The URL to capture')
371
+ .action(async (url) => {
372
+ const config = getConfig();
373
+ if (!config?.apiKey) {
374
+ console.error(chalk_1.default.red('❌ Not logged in. Please run `neofeed login` first.'));
375
+ process.exit(1);
376
+ }
377
+ try {
378
+ console.log(chalk_1.default.blue(`πŸ”— Capturing URL: ${url}...`));
379
+ await axios_1.default.post(`${getApiUrl().replace('/cli', '')}/ingest-url`, { url }, {
380
+ headers: { Authorization: `Bearer ${config.apiKey}` }
381
+ });
382
+ console.log(chalk_1.default.green('βœ… URL successfully sent to NeoFeed for processing!'));
383
+ }
384
+ catch (error) {
385
+ const msg = error.response?.data?.error || error.message;
386
+ console.error(chalk_1.default.red(`❌ Failed to capture URL: ${msg}`));
387
+ process.exit(1);
388
+ }
389
+ });
390
+ program
391
+ .command('push')
392
+ .description('Push a local file to your knowledge base as a memo')
393
+ .argument('<filepath>', 'Path to the local file')
394
+ .action(async (filepath) => {
395
+ const config = getConfig();
396
+ if (!config?.apiKey) {
397
+ console.error(chalk_1.default.red('❌ Not logged in. Please run `neofeed login` first.'));
398
+ process.exit(1);
399
+ }
400
+ if (!fs_1.default.existsSync(filepath)) {
401
+ console.error(chalk_1.default.red(`❌ File not found: ${filepath}`));
402
+ process.exit(1);
403
+ }
404
+ try {
405
+ const content = fs_1.default.readFileSync(filepath, 'utf-8');
406
+ const filename = path_1.default.basename(filepath);
407
+ console.log(chalk_1.default.blue(`πŸ“„ Pushing file: ${filename} (${content.length} chars)...`));
408
+ const response = await axios_1.default.post(`${getApiUrl()}/cli/memo`, {
409
+ title: filename,
410
+ content: content,
411
+ tags: 'cli-push'
412
+ }, {
413
+ headers: { Authorization: `Bearer ${config.apiKey}` }
414
+ });
415
+ console.log(chalk_1.default.green('βœ… File successfully pushed to NeoFeed!'));
416
+ console.log(chalk_1.default.gray(`ID: ${response.data.id}`));
417
+ }
418
+ catch (error) {
419
+ const msg = error.response?.data?.error || error.message;
420
+ console.error(chalk_1.default.red(`❌ Failed to push file: ${msg}`));
421
+ process.exit(1);
422
+ }
423
+ });
424
+ program
425
+ .command('export')
426
+ .description('Export all knowledge base items to local markdown files')
427
+ .argument('<dir>', 'Directory to export files to')
428
+ .action(async (dir) => {
429
+ const config = getConfig();
430
+ if (!config?.apiKey) {
431
+ console.error(chalk_1.default.red('❌ Not logged in. Please run `neofeed login` first.'));
432
+ process.exit(1);
433
+ }
434
+ try {
435
+ console.log(chalk_1.default.blue(`πŸ“¦ Fetching all knowledge base data...`));
436
+ const response = await axios_1.default.get(`${getApiUrl()}/cli/export`, {
437
+ headers: { Authorization: `Bearer ${config.apiKey}` }
438
+ });
439
+ const data = response.data;
440
+ if (!fs_1.default.existsSync(dir)) {
441
+ fs_1.default.mkdirSync(dir, { recursive: true });
442
+ }
443
+ let count = 0;
444
+ const processItems = (items, folder, typeName) => {
445
+ const outDir = path_1.default.join(dir, folder);
446
+ if (items.length > 0 && !fs_1.default.existsSync(outDir))
447
+ fs_1.default.mkdirSync(outDir);
448
+ items.forEach((item) => {
449
+ const safeTitle = (item.title || 'Untitled').replace(/[/\\?%*:|"<>]/g, '-');
450
+ const dateStr = new Date(item.created_at).toISOString().split('T')[0];
451
+ const filename = `${dateStr}-${safeTitle.substring(0, 50)}.md`;
452
+ let frontmatter = `---\n`;
453
+ frontmatter += `id: ${item.id}\n`;
454
+ frontmatter += `title: "${item.title?.replace(/"/g, '\\"')}"\n`;
455
+ frontmatter += `date: ${item.created_at}\n`;
456
+ frontmatter += `type: ${typeName}\n`;
457
+ if (item.url)
458
+ frontmatter += `url: ${item.url}\n`;
459
+ if (item.source_type)
460
+ frontmatter += `source: ${item.source_type}\n`;
461
+ if (item.tags && item.tags.length > 0)
462
+ frontmatter += `tags: [${item.tags.join(', ')}]\n`;
463
+ frontmatter += `---\n\n`;
464
+ fs_1.default.writeFileSync(path_1.default.join(outDir, filename), frontmatter + (item.content_raw || ''));
465
+ count++;
466
+ });
467
+ };
468
+ processItems(data.feeds, 'feeds', 'web_feed');
469
+ processItems(data.agents, 'memos', 'agent_memo');
470
+ console.log(chalk_1.default.green(`βœ… Successfully exported ${count} files to ${dir}`));
471
+ }
472
+ catch (error) {
473
+ const msg = error.response?.data?.error || error.message;
474
+ console.error(chalk_1.default.red(`❌ Failed to export: ${msg}`));
475
+ process.exit(1);
476
+ }
477
+ });
478
+ program
479
+ .command('trigger')
480
+ .description('Trigger a background agent task')
481
+ .argument('<task>', 'The name of the task (e.g. weekly-report)')
482
+ .action(async (task) => {
483
+ const config = getConfig();
484
+ if (!config?.apiKey) {
485
+ console.error(chalk_1.default.red('❌ Not logged in. Please run `neofeed login` first.'));
486
+ process.exit(1);
487
+ }
488
+ try {
489
+ console.log(chalk_1.default.blue(`πŸš€ Triggering task: ${task}...`));
490
+ await axios_1.default.post(`${getApiUrl().replace('/cli', '')}/trigger-${task}`, {}, {
491
+ headers: { Authorization: `Bearer ${config.apiKey}` }
492
+ });
493
+ console.log(chalk_1.default.green(`βœ… Task '${task}' successfully triggered!`));
494
+ }
495
+ catch (error) {
496
+ const msg = error.response?.data?.error || error.message;
497
+ console.error(chalk_1.default.red(`❌ Failed to trigger task: ${msg}`));
498
+ process.exit(1);
499
+ }
500
+ });
501
+ program.parse();
Binary file
package/package.json ADDED
@@ -0,0 +1,39 @@
1
+ {
2
+ "name": "neofeed-cli",
3
+ "version": "0.1.0",
4
+ "description": "Command line interface for NeoFeed - The Context Intersection Hub",
5
+ "main": "dist/index.js",
6
+ "bin": {
7
+ "neofeed": "./dist/index.js",
8
+ "nf": "./dist/index.js"
9
+ },
10
+ "scripts": {
11
+ "build": "tsc",
12
+ "dev": "tsx src/index.ts",
13
+ "start": "node dist/index.js"
14
+ },
15
+ "keywords": [
16
+ "neofeed",
17
+ "cli",
18
+ "agent",
19
+ "context"
20
+ ],
21
+ "author": "NeoFeed Team",
22
+ "license": "MIT",
23
+ "dependencies": {
24
+ "axios": "^1.16.0",
25
+ "chalk": "^4.1.2",
26
+ "commander": "^14.0.3",
27
+ "cors": "^2.8.6",
28
+ "dotenv": "^17.4.2",
29
+ "express": "^5.2.1",
30
+ "open": "^11.0.0"
31
+ },
32
+ "devDependencies": {
33
+ "@types/cors": "^2.8.19",
34
+ "@types/express": "^5.0.6",
35
+ "@types/node": "^25.7.0",
36
+ "tsx": "^4.21.0",
37
+ "typescript": "^6.0.3"
38
+ }
39
+ }
@@ -0,0 +1,6 @@
1
+ #!/usr/bin/expect -f
2
+ set timeout 15
3
+ spawn npm publish --access public
4
+ expect "Enter OTP:"
5
+ send "156492\r"
6
+ expect eof