alif-digest 1.0.13 → 1.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.
Files changed (99) hide show
  1. package/CONTRIBUTING.md +54 -0
  2. package/README.md +88 -62
  3. package/ROADMAP.md +36 -0
  4. package/dist/cli/commands/config.d.ts +2 -0
  5. package/dist/cli/commands/config.js +68 -0
  6. package/dist/cli/commands/config.js.map +1 -0
  7. package/dist/cli/commands/debug.js +121 -28
  8. package/dist/cli/commands/debug.js.map +1 -1
  9. package/dist/cli/commands/init.js +19 -6
  10. package/dist/cli/commands/init.js.map +1 -1
  11. package/dist/cli/commands/run.d.ts +2 -0
  12. package/dist/cli/commands/run.js +12 -5
  13. package/dist/cli/commands/run.js.map +1 -1
  14. package/dist/cli/commands/schedule.js +11 -8
  15. package/dist/cli/commands/schedule.js.map +1 -1
  16. package/dist/cli/index.js +4 -0
  17. package/dist/cli/index.js.map +1 -1
  18. package/dist/core/config-schema.d.ts +10 -1
  19. package/dist/core/config-schema.js +7 -1
  20. package/dist/core/config-schema.js.map +1 -1
  21. package/dist/core/debug/llm-tester.js +3 -1
  22. package/dist/core/debug/llm-tester.js.map +1 -1
  23. package/dist/core/default-keywords.d.ts +5 -0
  24. package/dist/core/default-keywords.js +80 -6
  25. package/dist/core/default-keywords.js.map +1 -1
  26. package/dist/core/filters/deduplicator.d.ts +5 -2
  27. package/dist/core/filters/deduplicator.js +67 -11
  28. package/dist/core/filters/deduplicator.js.map +1 -1
  29. package/dist/core/filters/keywords.d.ts +1 -0
  30. package/dist/core/filters/keywords.js +3 -0
  31. package/dist/core/filters/keywords.js.map +1 -1
  32. package/dist/core/logger.d.ts +16 -0
  33. package/dist/core/logger.js +40 -0
  34. package/dist/core/logger.js.map +1 -0
  35. package/dist/core/pipeline.d.ts +1 -0
  36. package/dist/core/pipeline.js +130 -28
  37. package/dist/core/pipeline.js.map +1 -1
  38. package/dist/core/scheduler.js +2 -1
  39. package/dist/core/scheduler.js.map +1 -1
  40. package/dist/core/scraper-types.d.ts +1 -0
  41. package/dist/core/scraper-types.js.map +1 -1
  42. package/dist/core/scrapers/scrape-scraper.js +25 -2
  43. package/dist/core/scrapers/scrape-scraper.js.map +1 -1
  44. package/dist/db/article-store.d.ts +6 -1
  45. package/dist/db/article-store.js +4 -1
  46. package/dist/db/article-store.js.map +1 -1
  47. package/dist/db/migrate.js +2 -1
  48. package/dist/db/migrate.js.map +1 -1
  49. package/dist/providers/delivery/slack.js +3 -1
  50. package/dist/providers/delivery/slack.js.map +1 -1
  51. package/dist/providers/delivery/webhook.js +3 -1
  52. package/dist/providers/delivery/webhook.js.map +1 -1
  53. package/dist/providers/llm/anthropic.d.ts +1 -0
  54. package/dist/providers/llm/anthropic.js +20 -2
  55. package/dist/providers/llm/anthropic.js.map +1 -1
  56. package/dist/providers/llm/common.d.ts +10 -0
  57. package/dist/providers/llm/common.js +26 -0
  58. package/dist/providers/llm/common.js.map +1 -1
  59. package/dist/providers/llm/index.d.ts +1 -0
  60. package/dist/providers/llm/ollama.d.ts +1 -0
  61. package/dist/providers/llm/ollama.js +21 -3
  62. package/dist/providers/llm/ollama.js.map +1 -1
  63. package/dist/providers/llm/openrouter.d.ts +1 -0
  64. package/dist/providers/llm/openrouter.js +20 -3
  65. package/dist/providers/llm/openrouter.js.map +1 -1
  66. package/package.json +3 -1
  67. package/src/cli/commands/config.ts +74 -0
  68. package/src/cli/commands/debug.ts +137 -29
  69. package/src/cli/commands/init.ts +19 -6
  70. package/src/cli/commands/run.ts +18 -9
  71. package/src/cli/commands/schedule.ts +11 -8
  72. package/src/cli/index.ts +4 -0
  73. package/src/core/config-schema.ts +7 -1
  74. package/src/core/debug/llm-tester.ts +4 -2
  75. package/src/core/default-keywords.ts +87 -6
  76. package/src/core/filters/deduplicator.ts +81 -12
  77. package/src/core/filters/keywords.ts +4 -0
  78. package/src/core/logger.ts +51 -0
  79. package/src/core/pipeline.ts +163 -33
  80. package/src/core/scheduler.ts +2 -1
  81. package/src/core/scraper-types.ts +1 -0
  82. package/src/core/scrapers/scrape-scraper.ts +25 -2
  83. package/src/db/article-store.ts +8 -4
  84. package/src/db/migrate.ts +2 -1
  85. package/src/providers/delivery/slack.ts +5 -2
  86. package/src/providers/delivery/webhook.ts +5 -2
  87. package/src/providers/llm/anthropic.ts +25 -2
  88. package/src/providers/llm/common.ts +28 -0
  89. package/src/providers/llm/index.ts +1 -0
  90. package/src/providers/llm/ollama.ts +21 -2
  91. package/src/providers/llm/openrouter.ts +25 -3
  92. package/tests/api-scraper.test.ts +60 -0
  93. package/tests/config-manager.test.ts +46 -1
  94. package/tests/deduplicator.test.ts +158 -0
  95. package/tests/delivery-providers.test.ts +86 -0
  96. package/tests/html-arxiv-scrapers.test.ts +90 -0
  97. package/tests/json-scraper.test.ts +84 -0
  98. package/tests/rss-scraper.test.ts +66 -0
  99. package/tests/schedule.test.ts +164 -0
@@ -0,0 +1,54 @@
1
+ # Contributing to Alif
2
+
3
+ ## 🏗 Architecture
4
+
5
+ ```text
6
+ Feeds (81 default sources)
7
+ → Scrapers (RSS, API, JSON, HTML, ArXiv)
8
+ → Exact URI Pruning
9
+ → Layer 1: Positive Keywords - Negative Penalties
10
+ → Top 150 Candidates
11
+ → NLP Deduplicator (Talisman Fuzzy Clustering)
12
+ → Top 25 Candidates
13
+ → Layer 2: LLM Batch Scorer
14
+ → Final Score = (L1 * 0.70) + (L2 * 0.30)
15
+ → LLM Analyzer (summary + category)
16
+ → Delivery (Slack / Webhook)
17
+ ```
18
+
19
+ - **Sources**: Configured in `~/.config/alif/feeds.json`
20
+ - **History**: Local SQLite database at `~/.config/alif/alif.db`
21
+ - **Providers**: `src/providers/llm/` and `src/providers/delivery/`
22
+
23
+ ---
24
+
25
+ ## 🧑‍💻 Local Development
26
+
27
+ ```bash
28
+ npm install
29
+ npm run dev -- init # set up your local config
30
+ npm run dev -- run # run from source
31
+ npm run test # run test suite
32
+ npm run lint # lint check
33
+ ```
34
+
35
+ > [!TIP]
36
+ > Configuration lives at `~/.config/alif/config.json`. You still need to run `npm run dev -- init` once before running from source.
37
+
38
+ ### Troubleshooting Husky (GUI clients)
39
+
40
+ If pre-commit hooks fail in GitHub Desktop because `npm` is not found:
41
+
42
+ ```bash
43
+ mkdir -p ~/.config/husky
44
+ echo 'export PATH="/opt/homebrew/bin:/usr/local/bin:$PATH"' > ~/.config/husky/init.sh
45
+ ```
46
+
47
+ ---
48
+
49
+ ## 🤝 How to Contribute
50
+
51
+ 1. Fork the repo.
52
+ 2. Create your feature branch (`git checkout -b feature/amazing-scraper`).
53
+ 3. Commit your changes (`git commit -m 'feat: add NewsAPI scraper'`).
54
+ 4. Push and open a Pull Request.
package/README.md CHANGED
@@ -2,8 +2,9 @@
2
2
 
3
3
  **The Autonomous AI Signal Digest CLI.**
4
4
 
5
- Alif (ألف) scours the web for high-signal AI developments, selects the most relevant breakthroughs using LLMs, and delivers a curated digest directly to your workspace.
5
+ Alif (ألف) scours the web for high-signal AI developments, cuts through the noise using a multi-layer scoring system, and delivers a curated daily digest directly to your workspace — powered by your own LLM.
6
6
 
7
+ [![npm version](https://img.shields.io/npm/v/alif-digest.svg)](https://www.npmjs.com/package/alif-digest)
7
8
  [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
8
9
  [![TypeScript](https://img.shields.io/badge/TypeScript-5.0-blue.svg)](https://www.typescriptlang.org/)
9
10
 
@@ -11,17 +12,15 @@ Alif (ألف) scours the web for high-signal AI developments, selects the most r
11
12
 
12
13
  ## ⚡️ Quick Start
13
14
 
14
- Alif helps you track AI breakthroughs by aggregating and analyzing high-signal sources. Follow these steps to get started:
15
-
16
15
  ### 1. Install
17
16
 
18
17
  ```bash
19
18
  npm install -g alif-digest
20
19
  ```
21
20
 
22
- ### 2. Setup
21
+ ### 2. Initialize
23
22
 
24
- Initialize your environment. Alif will guide you through connecting an LLM (Local Ollama, Anthropic, or OpenRouter) and setting up your delivery channels.
23
+ Alif will interactively guide you through connecting an LLM (Local Ollama, Anthropic, or OpenRouter) and setting up your delivery channels.
25
24
 
26
25
  ```bash
27
26
  alif init
@@ -29,26 +28,42 @@ alif init
29
28
 
30
29
  ### 3. Run
31
30
 
32
- Generate your daily digest. Alif will scrape all sources, filter the noise, analyze the breakthroughs, and deliver the results.
31
+ Alif scrapes all sources, applies multi-layer scoring, analyzes the top items with your LLM, and delivers the results.
33
32
 
34
33
  ```bash
35
34
  alif run
35
+
36
+ # Skip source cooldown (re-fetch all sources immediately)
37
+ alif run --force
36
38
  ```
37
39
 
38
40
  ### 4. Schedule
39
41
 
40
- Keep the signals flowing by checking for scheduled runs.
42
+ Keep the signals flowing automatically.
41
43
 
42
44
  ```bash
43
- alif schedule add
44
- alif schedule check
45
+ alif schedule add # Schedule a recurring digest
46
+ alif schedule list # View scheduled jobs
47
+ alif schedule check # Trigger any pending scheduled jobs
45
48
  ```
46
49
 
47
50
  ---
48
51
 
52
+ ## ✨ Features
53
+
54
+ - **Multi-Layer AI Scoring**: Specialized two-stage evaluation engine combining keyword heuristics and deep NLP analysis to surface truly important signals.
55
+ - **Smart Deduplication**: Blazing-fast fuzzy clustering ensures you never read three variations of the same news story.
56
+ - **Aggressive Noise Reduction**: Automatically downranks PR pieces, sponsored fluff, and empty listicles.
57
+ - **Broad Content Ingestion**: Seamlessly scrapes various RSS, JSON API, raw HTML, and ArXiv feeds.
58
+ - **Customizable Delivery**: Push your personalized daily digests directly to Slack or any Webhook.
59
+ - **Bring Your Own AI**: Works out-of-the-box with local Ollama models or cloud providers like OpenRouter.
60
+ - **Built-in Automation**: Schedule recurring digests to keep your feeds curated entirely on autopilot.
61
+
62
+ ---
63
+
49
64
  ## 🤖 Models
50
65
 
51
- Use standard instruction-tuned models that support structured output. Avoid thinking/reasoning models.
66
+ Use **standard instruction-tuned models** that support structured output. Avoid thinking/reasoning models (e.g. DeepSeek R1, Qwen Thinking variants) as they interfere with JSON schema generation.
52
67
 
53
68
  ### Tested Models
54
69
 
@@ -59,86 +74,97 @@ Use standard instruction-tuned models that support structured output. Avoid thin
59
74
 
60
75
  ---
61
76
 
62
- ## 🛠 For Tinkers (Customize & Contribute)
77
+ ## 🛠 CLI Reference
63
78
 
64
- Alif is built with extreme modularity. Everything from scrapers to LLM providers follows a strict factory pattern.
79
+ ### `alif init`
65
80
 
66
- ### Architecture
81
+ Interactive wizard to configure your LLM provider, model, delivery channel, and preferences.
67
82
 
68
- - **Inspiration**: Built to solve the "noise" problem in AI news.
69
- - **Persistence**: Local SQLite database handles article deduplication and history.
70
- - **Workflow**: `Scraper` → `Deduplicator` → `Keyword Scorer` → `LLM Analyzer` → `Delivery`.
83
+ ### `alif run [--force] [--verbose] [--quiet]`
71
84
 
72
- ### Customizing Sources & Keywords
85
+ Run the full pipeline.
73
86
 
74
- Your feeds are stored in `~/.config/alif/feeds.json`. You can add any source using the supported types: `rss`, `api`, `json`, or `scrape`.
87
+ - `--force`: Bypass the source cooldown to re-fetch all sources immediately.
88
+ - `--verbose`: Stream detailed layer-by-layer scoring and prompt output (great for debugging LLMs).
89
+ - `--quiet`: Suppress all output except for errors.
75
90
 
76
- **Keyword Signal Overrides**
77
- Alif ships with a set of default base keywords. If you want to change what Alif considers "high-signal" (or silence certain topics), add a `customKeywords` object to the `preferences` section in `~/.config/alif/config.json`:
91
+ ### `alif config`
78
92
 
79
- ```json
80
- "preferences": {
81
- "signalThreshold": 60,
82
- "sequentialAnalysis": true,
83
- "customKeywords": {
84
- "my-favorite-framework": 100,
85
- "topic-i-want-to-ignore": 0,
86
- "gpt-5": 50
87
- }
88
- }
89
- ```
93
+ Manage your configuration without manually editing `config.json`.
90
94
 
91
- - **`signalThreshold`**: Minimum score (0-100) for an article to be considered "high-signal".
92
- - **`sequentialAnalysis`**: If `true`, Alif will analyze articles one-by-one. This is **highly recommended** for local models (like Ollama 2B/3B) that might struggle with batching multiple items in one prompt.
93
- - **`customKeywords`**: Your custom keywords will be merged with the base keywords. If you define a key that already exists, your weight will override the default.
95
+ ```bash
96
+ alif config show # Print current config
97
+ alif config set signalThreshold 70 # Update a preference value
98
+ alif config set maxItemsPerRun 5 # Change how many items are delivered
99
+ alif config set sequentialAnalysis true # Enable one-by-one LLM processing
100
+ alif config toggle-ai-scoring # Toggle Layer 2 AI Article Scoring on/off
101
+ alif config set logLevel verbose # Change log verbosity (silent, normal, verbose)
102
+ alif config set noColor true # Disable ANSI colored output
103
+ ```
94
104
 
95
- ### Project Structure
105
+ ### `alif schedule`
96
106
 
97
- - `src/core/scrapers/`: Logic for data ingestion.
98
- - `src/providers/llm/`: Support for Ollama, Anthropic, and OpenRouter.
99
- - `src/providers/delivery/`: Slack Block Kit and generic Webhook support.
107
+ ```bash
108
+ alif schedule add # Add a new cron schedule
109
+ alif schedule list # List all schedules
110
+ alif schedule delete # Remove a schedule
111
+ alif schedule check # Run any due schedules
112
+ ```
100
113
 
101
- ### Local Development
114
+ ### `alif debug`
102
115
 
103
116
  ```bash
104
- # Install dependencies
105
- npm install
106
-
107
- # Run the CLI from source (requires one-time initialization)
108
- npm run dev -- init
109
- npm run dev -- run
117
+ alif debug llm <provider> --model <name> [--key <api-key>]
118
+ # Test your LLM connection and see the full audit trail (prompt, response, latency)
110
119
 
111
- # Execute tests
112
- npm run test
120
+ alif debug audit-feeds [--output <path>]
121
+ # Scrape all feeds dry-run: see item counts and content sizes per source
122
+ # Saves a detailed JSON report (default: ~/.config/alif/audit_report.json)
113
123
  ```
114
124
 
115
- > [!TIP]
116
- > **Developer Hint**: The CLI looks for configuration in `~/.config/alif/config.json`. If you are running in development, you still need to run `npm run dev -- init` once to generate your local config and database path.
125
+ ---
117
126
 
118
- ### Troubleshooting Husky (GUI / GitHub Desktop)
127
+ ## ⚙️ Configuration Reference
119
128
 
120
- If you're using a GUI client like GitHub Desktop on macOS and the pre-commit hooks fail because `npm` or `node` is not found, you need to ensure Husky can find your PATH.
129
+ Config is stored at `~/.config/alif/config.json`. Most values can be changed with `alif config set`.
121
130
 
122
- Run the following in your terminal:
131
+ | Preference | Type | Default | Description |
132
+ | ------------------------- | --------- | ---------- | ---------------------------------------------------------------- |
133
+ | `signalThreshold` | `number` | `60` | Minimum score (0–100) for an article to qualify |
134
+ | `maxItemsPerRun` | `number` | `10` | Max articles delivered per run |
135
+ | `sourceCooldownMinutes` | `number` | `5` | Minimum gap between re-fetching the same source |
136
+ | `sequentialAnalysis` | `boolean` | `false` | Analyze articles one-by-one (recommended for small local models) |
137
+ | `enableAIArticlesScoring` | `boolean` | `true` | Enable Layer 2 LLM-based article scoring |
138
+ | `customKeywords` | `object` | `{}` | Add or override keyword signal weights |
139
+ | `negativeKeywords` | `object` | `{}` | Add custom noise/penalty keywords |
140
+ | `logLevel` | `string` | `'normal'` | Set logging verbosity: `'silent'`, `'normal'`, or `'verbose'` |
141
+ | `noColor` | `boolean` | `false` | Disable colored terminal output (`NO_COLOR=1` also works) |
123
142
 
124
- ```bash
125
- mkdir -p ~/.config/husky
126
- echo 'export PATH="/opt/homebrew/bin:/usr/local/bin:$PATH"' > ~/.config/husky/init.sh
143
+ **Custom keywords example:**
144
+
145
+ ```json
146
+ "customKeywords": {
147
+ "my-framework": 30,
148
+ "competitor-name": 0
149
+ },
150
+ "negativeKeywords": {
151
+ "webinar": 20
152
+ }
127
153
  ```
128
154
 
129
- ### Contributing
155
+ ---
156
+
157
+ ## 🤝 Architecture & Contributing
158
+
159
+ Interested in how Alif works under the hood or want to run it locally?
130
160
 
131
- 1. Fork the repo.
132
- 2. Create your feature branch (`git checkout -b feature/amazing-scraper`).
133
- 3. Commit your changes (`git commit -m 'Add support for NewsAPI'`).
134
- 4. Push to the branch (`git push origin feature/amazing-scraper`).
135
- 5. Open a Pull Request.
161
+ Check out our [**Contributing Guidelines**](CONTRIBUTING.md) for information on the architecture, local development setup, and how to submit pull requests!
136
162
 
137
163
  ---
138
164
 
139
165
  ## 📢 Acknowledgements
140
166
 
141
- Special thanks to [Roland](https://github.com/rolandbrecht/), whose initial technical foundation helped turn this concept into a reality and [Antigravity](https://antigravity.google/) for the help in building this project.
167
+ Thanks to [Roland](https://github.com/rolandbrecht/) for the initial technical foundation, and [Antigravity](https://antigravity.google/) for the help in building this project.
142
168
 
143
169
  ## 📄 License
144
170
 
package/ROADMAP.md ADDED
@@ -0,0 +1,36 @@
1
+ # Alif-Digest Roadmap
2
+
3
+ Items planned for future development, roughly in priority order.
4
+
5
+ ---
6
+
7
+ ## 🔴 High Priority
8
+
9
+ ### Config pre-flight validation
10
+
11
+ `alif validate` or an automatic pre-flight check at the start of `alif run` that catches misconfigured/missing API keys, malformed URLs, etc. — before scraping has already happened.
12
+
13
+ ### Expand default keywords
14
+
15
+ The default keyword list in `default-keywords.ts` is thin. A richer, categorized list (models, research, tools, policy) would meaningfully improve signal quality out of the box.
16
+
17
+ ---
18
+
19
+ ## 🟡 Medium Priority
20
+
21
+ ### `alif history` and `alif status`
22
+
23
+ - `alif history` — show last N delivered digests from the local DB
24
+ - `alif status` — show source health table (last checked, items found, errors)
25
+
26
+ ### `alif run --sequential`
27
+
28
+ Allow overriding sequential analysis mode per-run from the CLI without editing config.
29
+
30
+ ---
31
+
32
+ ## 🟢 Future Delivery Channels
33
+
34
+ - **Discord** — dedicated provider for Discord webhook format
35
+ - **Telegram** — Telegram Bot API delivery
36
+ - **Email** — via SMTP or a transactional email service (Resend, Mailgun)
@@ -0,0 +1,2 @@
1
+ import { Command } from 'commander';
2
+ export declare const configCommand: Command;
@@ -0,0 +1,68 @@
1
+ import { Command } from 'commander';
2
+ import { ConfigManager } from '../../core/config-manager.js';
3
+ import { logger } from '../../core/logger.js';
4
+ export const configCommand = new Command('config').description('Manage Alif configuration');
5
+ configCommand
6
+ .command('show')
7
+ .description('Display current configuration')
8
+ .action(() => {
9
+ const cm = ConfigManager.getInstance();
10
+ if (!cm.exists()) {
11
+ logger.error('Alif is not initialized. Run "alif init" first.');
12
+ process.exit(1);
13
+ }
14
+ const config = cm.load();
15
+ logger.log(JSON.stringify(config, null, 2));
16
+ });
17
+ configCommand
18
+ .command('set <key> <value>')
19
+ .description('Update a preference value (e.g. alif config set signalThreshold 70)')
20
+ .action((key, value) => {
21
+ const cm = ConfigManager.getInstance();
22
+ if (!cm.exists()) {
23
+ logger.error('Alif is not initialized. Run "alif init" first.');
24
+ process.exit(1);
25
+ }
26
+ const config = cm.load();
27
+ const prefs = config.preferences;
28
+ if (!(key in prefs)) {
29
+ logger.error(`Unknown preference key: "${key}"`);
30
+ process.exit(1);
31
+ }
32
+ const current = prefs[key];
33
+ if (typeof current === 'boolean') {
34
+ prefs[key] = value === 'true' || value === '1';
35
+ }
36
+ else if (typeof current === 'number') {
37
+ const num = Number(value);
38
+ if (isNaN(num)) {
39
+ logger.error(`Value "${value}" is not a valid number.`);
40
+ process.exit(1);
41
+ }
42
+ prefs[key] = num;
43
+ }
44
+ else {
45
+ prefs[key] = value;
46
+ }
47
+ cm.save({ ...config, preferences: prefs });
48
+ logger.success(`Set ${key} = ${prefs[key]}`);
49
+ });
50
+ configCommand
51
+ .command('toggle-ai-scoring')
52
+ .description('Toggle AI Article Scoring (Layer 2) on or off')
53
+ .action(() => {
54
+ const cm = ConfigManager.getInstance();
55
+ if (!cm.exists()) {
56
+ logger.error('Alif is not initialized. Run "alif init" first.');
57
+ process.exit(1);
58
+ }
59
+ const config = cm.load();
60
+ const current = config.preferences.enableAIArticlesScoring;
61
+ const updated = !current;
62
+ cm.save({
63
+ ...config,
64
+ preferences: { ...config.preferences, enableAIArticlesScoring: updated },
65
+ });
66
+ logger.success(`AI Article Scoring is now ${updated ? 'ENABLED ✅' : 'DISABLED ❌'}`);
67
+ });
68
+ //# sourceMappingURL=config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../../../src/cli/commands/config.ts"],"names":[],"mappings":"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"}
@@ -3,6 +3,11 @@ import { LLMTester } from '../../core/debug/llm-tester.js';
3
3
  import { OllamaProvider } from '../../providers/llm/ollama.js';
4
4
  import { AnthropicProvider } from '../../providers/llm/anthropic.js';
5
5
  import { OpenRouterProvider } from '../../providers/llm/openrouter.js';
6
+ import { ScraperOrchestrator } from '../../core/orchestrator.js';
7
+ import { ConfigManager } from '../../core/config-manager.js';
8
+ import fs from 'fs';
9
+ import path from 'path';
10
+ import { logger } from '../../core/logger.js';
6
11
  export const debugCommand = new Command('debug').description('Debug utilities for Alif');
7
12
  debugCommand
8
13
  .command('llm')
@@ -12,6 +17,7 @@ debugCommand
12
17
  .option('--endpoint <url>', 'Base URL/Endpoint (default from config)')
13
18
  .option('--key <token>', 'API Key (if required)')
14
19
  .option('--sequential', 'Process items one-by-one')
20
+ .option('--score', 'Test Layer 2 AI Article Scoring instead of analysis')
15
21
  .action(async (providerName, options) => {
16
22
  let provider;
17
23
  switch (providerName.toLowerCase()) {
@@ -40,36 +46,123 @@ debugCommand
40
46
  default:
41
47
  throw new Error(`Unknown provider: ${providerName}`);
42
48
  }
43
- const tester = new LLMTester(provider);
44
- const { results, debugInfo, totalLatency } = await tester.runTest({
45
- sequential: options.sequential,
46
- });
47
- console.log('\n' + '='.repeat(50));
48
- console.log('LLM DIAGNOSTIC AUDIT TRAIL');
49
- console.log('='.repeat(50));
50
- if (debugInfo) {
51
- console.log('\n[1] PROMPT SENT TO LLM:');
52
- console.log('-'.repeat(30));
53
- console.log(debugInfo.prompt);
54
- console.log('\n[2] RAW RESPONSE FROM LLM:');
55
- console.log('-'.repeat(30));
56
- if (!debugInfo.rawResponse || debugInfo.rawResponse.trim() === '') {
57
- console.log('<<< EMPTY RESPONSE >>>');
58
- }
59
- else {
60
- console.log(debugInfo.rawResponse);
49
+ logger.log('\n' + '='.repeat(50));
50
+ logger.info('LLM DIAGNOSTIC AUDIT TRAIL');
51
+ logger.log('='.repeat(50));
52
+ if (options.score) {
53
+ // --- SCORE DEBUG MODE ---
54
+ const SCORE_TEST_TITLES = [
55
+ 'OpenAI releases GPT-5 — biggest model leap in three years',
56
+ 'DeepSeek V4 open-sourced: beats GPT-4o on 12 benchmarks',
57
+ 'Anthropic raises $5B Series E at $75B valuation',
58
+ 'Cline 2.0 released: autonomous coding agent with computer use',
59
+ 'Top 10 AI tools you should be using in 2025',
60
+ 'Sponsored: How Company X saved millions with AI',
61
+ 'New EU AI Act enforcement deadlines announced',
62
+ 'NVIDIA Blackwell B200 GPUs now available for cloud providers',
63
+ 'Google Antigravity adds agentic coding to all tiers',
64
+ 'A beginner tutorial on building a RAG pipeline',
65
+ ];
66
+ const startTime = Date.now();
67
+ const scores = await provider.score(SCORE_TEST_TITLES);
68
+ const latency = Date.now() - startTime;
69
+ logger.info(`\n[1] SCORING PROMPT SENT: ${SCORE_TEST_TITLES.length} titles`);
70
+ logger.info('-'.repeat(30));
71
+ SCORE_TEST_TITLES.forEach((t, i) => logger.debug(` ${i}: ${t}`));
72
+ logger.info('\n[2] SCORES RETURNED:');
73
+ logger.info('-'.repeat(30));
74
+ SCORE_TEST_TITLES.forEach((t, i) => {
75
+ const s = scores[i] ?? '?';
76
+ const bar = '█'.repeat(Math.round(Number(s) / 5));
77
+ logger.info(` ${String(s).padStart(3)} ${bar.padEnd(20)} ${t}`);
78
+ });
79
+ logger.info('\n[3] LATENCY:');
80
+ logger.info('-'.repeat(10));
81
+ logger.info(`${latency}ms`);
82
+ }
83
+ else {
84
+ // --- ANALYSIS DEBUG MODE (existing) ---
85
+ const tester = new LLMTester(provider);
86
+ const { results, debugInfo, totalLatency } = await tester.runTest({
87
+ sequential: options.sequential,
88
+ });
89
+ if (debugInfo) {
90
+ logger.info('\n[1] PROMPT SENT TO LLM:');
91
+ logger.info('-'.repeat(30));
92
+ logger.debug(debugInfo.prompt);
93
+ logger.info('\n[2] RAW RESPONSE FROM LLM:');
94
+ logger.info('-'.repeat(30));
95
+ if (!debugInfo.rawResponse || debugInfo.rawResponse.trim() === '') {
96
+ logger.warn('<<< EMPTY RESPONSE >>>');
97
+ }
98
+ else {
99
+ logger.debug(debugInfo.rawResponse);
100
+ }
101
+ logger.info('\n[3] LATENCY:');
102
+ logger.info('-'.repeat(10));
103
+ logger.info(`${debugInfo.latencyMs}ms`);
61
104
  }
62
- console.log('\n[3] LATENCY:');
63
- console.log('-'.repeat(10));
64
- console.log(`${debugInfo.latencyMs}ms`);
105
+ logger.info('\n[4] PARSED RESULTS:');
106
+ logger.info('-'.repeat(30));
107
+ results.forEach((res, idx) => {
108
+ logger.info(`${idx + 1}. [${res.category}] ${res.summary || 'Summary failed'}`);
109
+ });
110
+ logger.log('\n' + '='.repeat(50));
111
+ logger.info(`TOTAL PROCESS TIME: ${totalLatency}ms`);
112
+ logger.log('='.repeat(50));
113
+ }
114
+ });
115
+ debugCommand
116
+ .command('audit-feeds')
117
+ .description('Audit all configured feeds for volume and data size')
118
+ .option('--output <path>', 'Custom output path for JSON report')
119
+ .action(async (options) => {
120
+ const configManager = ConfigManager.getInstance();
121
+ if (!configManager.exists()) {
122
+ throw new Error('Alif is not initialized. Run "alif init" first.');
123
+ }
124
+ const config = configManager.load();
125
+ if (!fs.existsSync(config.feedsPath)) {
126
+ throw new Error(`Feeds file not found at ${config.feedsPath}`);
65
127
  }
66
- console.log('\n[4] PARSED RESULTS:');
67
- console.log('-'.repeat(30));
68
- results.forEach((res, idx) => {
69
- console.log(`${idx + 1}. [${res.category}] ${res.summary || 'Summary failed'}`);
128
+ const feeds = JSON.parse(fs.readFileSync(config.feedsPath, 'utf-8'));
129
+ logger.info(`[Diagnostic] Auditing ${feeds.length} feeds...`);
130
+ const orchestrator = new ScraperOrchestrator();
131
+ const startTime = Date.now();
132
+ const results = await orchestrator.runAll(feeds);
133
+ const duration = Date.now() - startTime;
134
+ const auditData = results.map((res) => {
135
+ const totalChars = res.items.reduce((acc, item) => acc + (item.content?.length || 0) + (item.title?.length || 0), 0);
136
+ return {
137
+ source: res.source,
138
+ status: res.status,
139
+ itemCount: res.items.length,
140
+ totalCharacters: totalChars,
141
+ averageItemSize: res.items.length > 0 ? Math.round(totalChars / res.items.length) : 0,
142
+ error: res.error,
143
+ };
70
144
  });
71
- console.log('\n' + '='.repeat(50));
72
- console.log(`TOTAL PROCESS TIME: ${totalLatency}ms`);
73
- console.log('='.repeat(50));
145
+ const summary = {
146
+ totalFeeds: feeds.length,
147
+ successfulFeeds: auditData.filter((d) => d.status === 'ok').length,
148
+ failedFeeds: auditData.filter((d) => d.status === 'error').length,
149
+ totalItems: auditData.reduce((acc, d) => acc + d.itemCount, 0),
150
+ totalCharacters: auditData.reduce((acc, d) => acc + d.totalCharacters, 0),
151
+ durationMs: duration,
152
+ timestamp: new Date().toISOString(),
153
+ };
154
+ const reportPath = options.output || path.join(configManager.getConfigDir(), 'audit_report.json');
155
+ fs.writeFileSync(reportPath, JSON.stringify({ summary, details: auditData }, null, 2));
156
+ logger.log('\n' + '='.repeat(50));
157
+ logger.info('FEED AUDIT SUMMARY');
158
+ logger.log('='.repeat(50));
159
+ logger.info(`Total Feeds: ${summary.totalFeeds}`);
160
+ logger.info(`Successful: ${summary.successfulFeeds}`);
161
+ logger.info(`Failed: ${summary.failedFeeds}`);
162
+ logger.info(`Total Items: ${summary.totalItems}`);
163
+ logger.info(`Total Content: ${(summary.totalCharacters / 1024 / 1024).toFixed(2)} MB`);
164
+ logger.info(`Time taken: ${(duration / 1000).toFixed(2)}s`);
165
+ logger.log('='.repeat(50));
166
+ logger.success(`\nDetailed report saved to: ${reportPath}`);
74
167
  });
75
168
  //# sourceMappingURL=debug.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"debug.js","sourceRoot":"","sources":["../../../src/cli/commands/debug.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"debug.js","sourceRoot":"","sources":["../../../src/cli/commands/debug.ts"],"names":[],"mappings":"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"}