alif-digest 1.1.0 → 1.1.2

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,68 @@
1
+ name: Scheduled Run
2
+
3
+ on:
4
+ schedule:
5
+ - cron: '0 8 * * *' # Example: 8:00 AM UTC daily
6
+ workflow_dispatch:
7
+
8
+ jobs:
9
+ run-alif:
10
+ runs-on: ubuntu-latest
11
+ steps:
12
+ - name: Checkout Code
13
+ uses: actions/checkout@v4
14
+
15
+ - name: Setup Node.js
16
+ uses: actions/setup-node@v4
17
+ with:
18
+ node-version: 22
19
+
20
+ - name: Cache Alif Data Directory
21
+ uses: actions/cache@v4
22
+ with:
23
+ path: .alif-data
24
+ key: ${{ runner.os }}-alif-data-${{ github.run_id }}
25
+ restore-keys: |
26
+ ${{ runner.os }}-alif-data-
27
+
28
+ - name: Install Alif Digest
29
+ run: npm install -g alif-digest
30
+
31
+ - name: Initialize Alif Configuration
32
+ env:
33
+ ALIF_CONFIG_DIR: ${{ github.workspace }}/.alif-data
34
+ ALIF_LLM_PROVIDER: ${{ vars.ALIF_LLM_PROVIDER || 'anthropic' }}
35
+ ALIF_LLM_MODEL: ${{ vars.ALIF_LLM_MODEL || '' }}
36
+ ALIF_LLM_BASE_URL: ${{ vars.ALIF_LLM_BASE_URL || '' }}
37
+ ALIF_SIGNAL_THRESHOLD: ${{ vars.ALIF_SIGNAL_THRESHOLD || '60' }}
38
+ ALIF_MAX_ITEMS_PER_RUN: ${{ vars.ALIF_MAX_ITEMS_PER_RUN || '10' }}
39
+ ALIF_SOURCE_COOLDOWN_MINUTES: ${{ vars.ALIF_SOURCE_COOLDOWN_MINUTES || '5' }}
40
+ ALIF_SEQUENTIAL_ANALYSIS: ${{ vars.ALIF_SEQUENTIAL_ANALYSIS || 'false' }}
41
+ ALIF_ENABLE_AI_SCORING: ${{ vars.ALIF_ENABLE_AI_SCORING || 'true' }}
42
+ ALIF_LOG_LEVEL: ${{ vars.ALIF_LOG_LEVEL || 'verbose' }}
43
+ ALIF_CUSTOM_KEYWORDS: ${{ vars.ALIF_CUSTOM_KEYWORDS || '{}' }}
44
+ ALIF_NEGATIVE_KEYWORDS: ${{ vars.ALIF_NEGATIVE_KEYWORDS || '{}' }}
45
+ ALIF_NO_COLOR: ${{ vars.ALIF_NO_COLOR || 'false' }}
46
+
47
+ ALIF_LLM_API_KEY: ${{ secrets.ALIF_LLM_API_KEY || '' }}
48
+ ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY || '' }}
49
+ OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY || '' }}
50
+ SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL || '' }}
51
+ GENERIC_WEBHOOK_URL: ${{ secrets.GENERIC_WEBHOOK_URL || '' }}
52
+ run: alif init --non-interactive
53
+
54
+ - name: Run Alif
55
+ env:
56
+ ALIF_CONFIG_DIR: ${{ github.workspace }}/.alif-data
57
+ ALIF_LLM_API_KEY: ${{ secrets.ALIF_LLM_API_KEY }}
58
+ OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
59
+ ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
60
+ SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }}
61
+ run: alif run
62
+
63
+ - name: Update Cache
64
+ if: always()
65
+ uses: actions/cache/save@v4
66
+ with:
67
+ path: .alif-data
68
+ key: ${{ runner.os }}-alif-data-${{ github.run_id }}
package/README.md CHANGED
@@ -80,6 +80,10 @@ Use **standard instruction-tuned models** that support structured output. Avoid
80
80
 
81
81
  Interactive wizard to configure your LLM provider, model, delivery channel, and preferences.
82
82
 
83
+ ### `alif validate`
84
+
85
+ Runs a strict pre-flight check on your `config.json` and `feeds.json` files. It verifies that your Cloud LLM API keys are present (if selected), that Delivery Webhook URLs are valid HTTP destinations, and that the `feeds.json` array exists and contains the correct format schema.
86
+
83
87
  ### `alif run [--force] [--verbose] [--quiet]`
84
88
 
85
89
  Run the full pipeline.
@@ -152,13 +156,31 @@ Config is stored at `~/.config/alif/config.json`. Most values can be changed wit
152
156
  }
153
157
  ```
154
158
 
159
+ ## ☁️ Running on GitHub Actions (Free)
160
+
161
+ You can run Alif entirely in the cloud for free using GitHub Actions, without ever installing it locally.
162
+
163
+ 1. **Fork this repository.**
164
+ 2. Navigate to your fork's **Settings > Secrets and variables > Actions**.
165
+ 3. Add your sensitive API keys as **Repository Secrets**:
166
+ - `ALIF_LLM_API_KEY` (or `OPENAI_API_KEY`, `ANTHROPIC_API_KEY`)
167
+ - `SLACK_WEBHOOK_URL` (or `GENERIC_WEBHOOK_URL`)
168
+ 4. Configure your preferences as **Repository Variables** (optional):
169
+ - `ALIF_LLM_PROVIDER` (default: anthropic)
170
+ - `ALIF_LLM_MODEL`
171
+ - `ALIF_SIGNAL_THRESHOLD` (default: 60)
172
+ - `ALIF_MAX_ITEMS_PER_RUN` (default: 10)
173
+ - `ALIF_SOURCE_COOLDOWN_MINUTES` (default: 5)
174
+
175
+ The included workflow (`.github/workflows/alif-scheduled-run.yml`) automatically runs every day at 8:00 AM UTC (feel free to change the schedule in your forked version), caches your database/state, and delivers your customized digest!
176
+
155
177
  ---
156
178
 
157
179
  ## 🤝 Architecture & Contributing
158
180
 
159
181
  Interested in how Alif works under the hood or want to run it locally?
160
182
 
161
- Check out our [**Contributing Guidelines**](CONTRIBUTING.md) for information on the architecture, local development setup, and how to submit pull requests!
183
+ Check out our [**Contributing Guidelines**](https://github.com/qaribhaider/alif/blob/main/CONTRIBUTING.md) for information on the architecture, local development setup, and how to submit pull requests!
162
184
 
163
185
  ---
164
186
 
package/ROADMAP.md CHANGED
@@ -6,13 +6,7 @@ Items planned for future development, roughly in priority order.
6
6
 
7
7
  ## 🔴 High Priority
8
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.
9
+ _Currently empty - all planned high-priority features have shipped!_
16
10
 
17
11
  ---
18
12
 
@@ -1 +1,3 @@
1
- export declare function initCommand(): Promise<void>;
1
+ export declare function initCommand(options?: {
2
+ nonInteractive?: boolean;
3
+ }): Promise<void>;
@@ -2,106 +2,170 @@ import prompts from 'prompts';
2
2
  import path from 'path';
3
3
  import { ConfigManager } from '../../core/config-manager.js';
4
4
  import { logger } from '../../core/logger.js';
5
- export async function initCommand() {
5
+ export async function initCommand(options) {
6
6
  const configManager = ConfigManager.getInstance();
7
7
  const configDir = configManager.getConfigDir();
8
8
  logger.log('\n--- Alif Initialization ---');
9
- const response = await prompts([
10
- {
11
- type: 'select',
12
- name: 'llmProvider',
13
- message: 'Which LLM provider would you like to use?',
14
- choices: [
15
- { title: 'Ollama (Local)', value: 'ollama' },
16
- { title: 'Anthropic', value: 'anthropic' },
17
- { title: 'OpenRouter', value: 'openrouter' },
18
- ],
19
- },
20
- {
21
- type: (prev) => (prev !== 'ollama' ? 'text' : null),
22
- name: 'apiKey',
23
- message: 'Enter your API Key:',
24
- },
25
- {
26
- type: 'text',
27
- name: 'model',
28
- message: 'Enter the model name (e.g., llama3, claude-3-opus-20240229):',
29
- initial: (prev, values) => {
30
- if (values.llmProvider === 'ollama')
31
- return 'llama3';
32
- if (values.llmProvider === 'anthropic')
33
- return 'claude-3-5-sonnet-20240620';
34
- return 'meta-llama/llama-3-70b-instruct';
9
+ let config;
10
+ if (options?.nonInteractive) {
11
+ logger.info('Running in non-interactive mode. Reading from environment variables...');
12
+ const provider = (process.env.ALIF_LLM_PROVIDER || 'anthropic');
13
+ let apiKey = process.env.ALIF_LLM_API_KEY;
14
+ if (!apiKey) {
15
+ if (provider === 'anthropic')
16
+ apiKey = process.env.ANTHROPIC_API_KEY;
17
+ else if (provider === 'openrouter')
18
+ apiKey = process.env.OPENROUTER_API_KEY || process.env.OPENAI_API_KEY;
19
+ }
20
+ const model = process.env.ALIF_LLM_MODEL ||
21
+ (provider === 'ollama'
22
+ ? 'llama3'
23
+ : provider === 'anthropic'
24
+ ? 'claude-3-5-sonnet-20240620'
25
+ : 'meta-llama/llama-3-70b-instruct');
26
+ const baseUrl = process.env.ALIF_LLM_BASE_URL ||
27
+ (provider === 'ollama' ? 'http://localhost:11434' : undefined);
28
+ const deliveryConfigs = [];
29
+ if (process.env.SLACK_WEBHOOK_URL) {
30
+ deliveryConfigs.push({ type: 'slack', webhookUrl: process.env.SLACK_WEBHOOK_URL });
31
+ }
32
+ if (process.env.GENERIC_WEBHOOK_URL) {
33
+ deliveryConfigs.push({
34
+ type: 'webhook',
35
+ webhookUrl: process.env.GENERIC_WEBHOOK_URL,
36
+ });
37
+ }
38
+ config = {
39
+ llm: {
40
+ provider,
41
+ apiKey,
42
+ model,
43
+ baseUrl,
35
44
  },
36
- },
37
- {
38
- type: (prev, values) => (values.llmProvider === 'ollama' ? 'text' : null),
39
- name: 'baseUrl',
40
- message: 'Enter Ollama base URL:',
41
- initial: 'http://localhost:11434',
42
- },
43
- {
44
- type: 'toggle',
45
- name: 'sequentialAnalysis',
46
- message: 'Enable sequential (one-by-one) LLM processing? (Recommended for small local models)',
47
- initial: (prev, values) => values.llmProvider === 'ollama',
48
- active: 'yes',
49
- inactive: 'no',
50
- },
51
- {
52
- type: 'toggle',
53
- name: 'enableAIArticlesScoring',
54
- message: 'Enable AI Article Scoring? (Uses your LLM to intelligently score articles)',
55
- initial: true,
56
- active: 'yes',
57
- inactive: 'no',
58
- },
59
- {
60
- type: 'multiselect',
61
- name: 'deliveryProviders',
62
- message: 'Where should we deliver the digest?',
63
- choices: [
64
- { title: 'Slack', value: 'slack' },
65
- { title: 'Generic Webhook', value: 'webhook' },
66
- ],
67
- min: 1,
68
- },
69
- ]);
70
- if (!response.llmProvider || !response.deliveryProviders) {
71
- logger.warn('Initialization cancelled.');
72
- return;
45
+ delivery: deliveryConfigs,
46
+ preferences: {
47
+ signalThreshold: process.env.ALIF_SIGNAL_THRESHOLD
48
+ ? parseInt(process.env.ALIF_SIGNAL_THRESHOLD, 10)
49
+ : 60,
50
+ maxItemsPerRun: process.env.ALIF_MAX_ITEMS_PER_RUN
51
+ ? parseInt(process.env.ALIF_MAX_ITEMS_PER_RUN, 10)
52
+ : 10,
53
+ sourceCooldownMinutes: process.env.ALIF_SOURCE_COOLDOWN_MINUTES
54
+ ? parseInt(process.env.ALIF_SOURCE_COOLDOWN_MINUTES, 10)
55
+ : 5,
56
+ sequentialAnalysis: process.env.ALIF_SEQUENTIAL_ANALYSIS === 'true' || provider === 'ollama',
57
+ enableAIArticlesScoring: process.env.ALIF_ENABLE_AI_SCORING !== 'false',
58
+ customKeywords: process.env.ALIF_CUSTOM_KEYWORDS
59
+ ? JSON.parse(process.env.ALIF_CUSTOM_KEYWORDS)
60
+ : {},
61
+ negativeKeywords: process.env.ALIF_NEGATIVE_KEYWORDS
62
+ ? JSON.parse(process.env.ALIF_NEGATIVE_KEYWORDS)
63
+ : {},
64
+ logLevel: process.env.ALIF_LOG_LEVEL || 'normal',
65
+ noColor: process.env.ALIF_NO_COLOR === 'true',
66
+ },
67
+ dbPath: path.join(configDir, 'alif.db'),
68
+ feedsPath: path.join(configDir, 'feeds.json'),
69
+ };
73
70
  }
74
- const deliveryConfigs = [];
75
- for (const provider of response.deliveryProviders) {
76
- const { webhookUrl } = await prompts({
77
- type: 'text',
78
- name: 'webhookUrl',
79
- message: `Enter ${provider} Webhook URL:`,
80
- });
81
- deliveryConfigs.push({ type: provider, webhookUrl });
71
+ else {
72
+ const response = await prompts([
73
+ {
74
+ type: 'select',
75
+ name: 'llmProvider',
76
+ message: 'Which LLM provider would you like to use?',
77
+ choices: [
78
+ { title: 'Ollama (Local)', value: 'ollama' },
79
+ { title: 'Anthropic', value: 'anthropic' },
80
+ { title: 'OpenRouter', value: 'openrouter' },
81
+ ],
82
+ },
83
+ {
84
+ type: (prev) => (prev !== 'ollama' ? 'text' : null),
85
+ name: 'apiKey',
86
+ message: 'Enter your API Key:',
87
+ },
88
+ {
89
+ type: 'text',
90
+ name: 'model',
91
+ message: 'Enter the model name (e.g., llama3, claude-3-opus-20240229):',
92
+ initial: (prev, values) => {
93
+ if (values.llmProvider === 'ollama')
94
+ return 'llama3';
95
+ if (values.llmProvider === 'anthropic')
96
+ return 'claude-3-5-sonnet-20240620';
97
+ return 'meta-llama/llama-3-70b-instruct';
98
+ },
99
+ },
100
+ {
101
+ type: (prev, values) => (values.llmProvider === 'ollama' ? 'text' : null),
102
+ name: 'baseUrl',
103
+ message: 'Enter Ollama base URL:',
104
+ initial: 'http://localhost:11434',
105
+ },
106
+ {
107
+ type: 'toggle',
108
+ name: 'sequentialAnalysis',
109
+ message: 'Enable sequential (one-by-one) LLM processing? (Recommended for small local models)',
110
+ initial: (prev, values) => values.llmProvider === 'ollama',
111
+ active: 'yes',
112
+ inactive: 'no',
113
+ },
114
+ {
115
+ type: 'toggle',
116
+ name: 'enableAIArticlesScoring',
117
+ message: 'Enable AI Article Scoring? (Uses your LLM to intelligently score articles)',
118
+ initial: true,
119
+ active: 'yes',
120
+ inactive: 'no',
121
+ },
122
+ {
123
+ type: 'multiselect',
124
+ name: 'deliveryProviders',
125
+ message: 'Where should we deliver the digest?',
126
+ choices: [
127
+ { title: 'Slack', value: 'slack' },
128
+ { title: 'Generic Webhook', value: 'webhook' },
129
+ ],
130
+ min: 1,
131
+ },
132
+ ]);
133
+ if (!response.llmProvider || !response.deliveryProviders) {
134
+ logger.warn('Initialization cancelled.');
135
+ return;
136
+ }
137
+ const deliveryConfigs = [];
138
+ for (const provider of response.deliveryProviders) {
139
+ const { webhookUrl } = await prompts({
140
+ type: 'text',
141
+ name: 'webhookUrl',
142
+ message: `Enter ${provider} Webhook URL:`,
143
+ });
144
+ deliveryConfigs.push({ type: provider, webhookUrl });
145
+ }
146
+ config = {
147
+ llm: {
148
+ provider: response.llmProvider,
149
+ apiKey: response.apiKey,
150
+ model: response.model,
151
+ baseUrl: response.baseUrl,
152
+ },
153
+ delivery: deliveryConfigs,
154
+ preferences: {
155
+ signalThreshold: 60,
156
+ maxItemsPerRun: 10,
157
+ sourceCooldownMinutes: 5,
158
+ sequentialAnalysis: response.sequentialAnalysis,
159
+ enableAIArticlesScoring: response.enableAIArticlesScoring,
160
+ customKeywords: {},
161
+ negativeKeywords: {},
162
+ logLevel: 'normal',
163
+ noColor: false,
164
+ },
165
+ dbPath: path.join(configDir, 'alif.db'),
166
+ feedsPath: path.join(configDir, 'feeds.json'),
167
+ };
82
168
  }
83
- const config = {
84
- llm: {
85
- provider: response.llmProvider,
86
- apiKey: response.apiKey,
87
- model: response.model,
88
- baseUrl: response.baseUrl,
89
- },
90
- delivery: deliveryConfigs,
91
- preferences: {
92
- signalThreshold: 60,
93
- maxItemsPerRun: 10,
94
- sourceCooldownMinutes: 5,
95
- sequentialAnalysis: response.sequentialAnalysis,
96
- enableAIArticlesScoring: response.enableAIArticlesScoring,
97
- customKeywords: {},
98
- negativeKeywords: {},
99
- logLevel: 'normal',
100
- noColor: false,
101
- },
102
- dbPath: path.join(configDir, 'alif.db'),
103
- feedsPath: path.join(configDir, 'feeds.json'),
104
- };
105
169
  configManager.save(config);
106
170
  logger.success(`Configuration saved to ${configManager.getConfigFile()}`);
107
171
  logger.info(`Database will be located at ${config.dbPath}`);
@@ -1 +1 @@
1
- {"version":3,"file":"init.js","sourceRoot":"","sources":["../../../src/cli/commands/init.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"init.js","sourceRoot":"","sources":["../../../src/cli/commands/init.ts"],"names":[],"mappings":"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"}
@@ -4,6 +4,7 @@ import { createDatabase } from '../../db/connection.js';
4
4
  import { runMigrations } from '../../db/migrate.js';
5
5
  import { Pipeline } from '../../core/pipeline.js';
6
6
  import { configureLogger, logger } from '../../core/logger.js';
7
+ import { Validator } from '../../core/validator.js';
7
8
  export async function runPipeline(config, db, force = false) {
8
9
  const pipeline = new Pipeline(config, db);
9
10
  // Load feeds
@@ -31,6 +32,9 @@ export async function runCommand(options = {}) {
31
32
  noColor: config.preferences.noColor,
32
33
  override: options.verbose ? 'verbose' : options.quiet ? 'quiet' : undefined,
33
34
  });
35
+ // Pre-flight validation
36
+ const validator = new Validator(config, config.feedsPath);
37
+ validator.printAndExitIfFailed();
34
38
  db = createDatabase(config.dbPath);
35
39
  runMigrations(db);
36
40
  await runPipeline(config, db, options.force);
@@ -1 +1 @@
1
- {"version":3,"file":"run.js","sourceRoot":"","sources":["../../../src/cli/commands/run.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"run.js","sourceRoot":"","sources":["../../../src/cli/commands/run.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1 @@
1
+ export declare function validateCommand(): Promise<void>;
@@ -0,0 +1,35 @@
1
+ import { ConfigManager } from '../../core/config-manager.js';
2
+ import { Validator } from '../../core/validator.js';
3
+ import { logger } from '../../core/logger.js';
4
+ export async function validateCommand() {
5
+ const configManager = ConfigManager.getInstance();
6
+ if (!configManager.exists()) {
7
+ logger.error('Alif is not initialized. Run "alif init" first.');
8
+ process.exit(1);
9
+ }
10
+ try {
11
+ const config = configManager.load();
12
+ const validator = new Validator(config, config.feedsPath);
13
+ logger.info('Running pre-flight validation...');
14
+ const failures = validator.validate();
15
+ if (failures.length > 0) {
16
+ logger.error(`Validation failed with ${failures.length} errors:`);
17
+ failures.forEach((f) => logger.error(` [${f.scope}] ${f.message}`));
18
+ process.exit(1);
19
+ }
20
+ else {
21
+ logger.success('All configurations and feeds are valid! 🎉');
22
+ process.exit(0);
23
+ }
24
+ }
25
+ catch (error) {
26
+ if (error instanceof Error) {
27
+ logger.error(`Validation failed exception: ${error.message}`);
28
+ }
29
+ else {
30
+ logger.error('An unknown error occurred during validation.');
31
+ }
32
+ process.exit(1);
33
+ }
34
+ }
35
+ //# sourceMappingURL=validate.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"validate.js","sourceRoot":"","sources":["../../../src/cli/commands/validate.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,8BAA8B,CAAC;AAC7D,OAAO,EAAE,SAAS,EAAE,MAAM,yBAAyB,CAAC;AACpD,OAAO,EAAE,MAAM,EAAE,MAAM,sBAAsB,CAAC;AAE9C,MAAM,CAAC,KAAK,UAAU,eAAe;IACnC,MAAM,aAAa,GAAG,aAAa,CAAC,WAAW,EAAE,CAAC;IAElD,IAAI,CAAC,aAAa,CAAC,MAAM,EAAE,EAAE,CAAC;QAC5B,MAAM,CAAC,KAAK,CAAC,iDAAiD,CAAC,CAAC;QAChE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,aAAa,CAAC,IAAI,EAAE,CAAC;QACpC,MAAM,SAAS,GAAG,IAAI,SAAS,CAAC,MAAM,EAAE,MAAM,CAAC,SAAS,CAAC,CAAC;QAE1D,MAAM,CAAC,IAAI,CAAC,kCAAkC,CAAC,CAAC;QAChD,MAAM,QAAQ,GAAG,SAAS,CAAC,QAAQ,EAAE,CAAC;QAEtC,IAAI,QAAQ,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACxB,MAAM,CAAC,KAAK,CAAC,0BAA0B,QAAQ,CAAC,MAAM,UAAU,CAAC,CAAC;YAClE,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,KAAK,KAAK,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC;YACrE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;aAAM,CAAC;YACN,MAAM,CAAC,OAAO,CAAC,4CAA4C,CAAC,CAAC;YAC7D,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;IACH,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,IAAI,KAAK,YAAY,KAAK,EAAE,CAAC;YAC3B,MAAM,CAAC,KAAK,CAAC,gCAAgC,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC;QAChE,CAAC;aAAM,CAAC;YACN,MAAM,CAAC,KAAK,CAAC,8CAA8C,CAAC,CAAC;QAC/D,CAAC;QACD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;AACH,CAAC"}
package/dist/cli/index.js CHANGED
@@ -6,6 +6,7 @@ import { runCommand } from './commands/run.js';
6
6
  import { scheduleCommand } from './commands/schedule.js';
7
7
  import { debugCommand } from './commands/debug.js';
8
8
  import { configCommand } from './commands/config.js';
9
+ import { validateCommand } from './commands/validate.js';
9
10
  const require = createRequire(import.meta.url);
10
11
  const { version } = require('../../package.json');
11
12
  const program = new Command();
@@ -13,8 +14,9 @@ program.name('alif').description('Alif - Daily AI Signal Digest CLI').version(ve
13
14
  program
14
15
  .command('init')
15
16
  .description('Initialize Alif configuration')
16
- .action(async () => {
17
- await initCommand();
17
+ .option('--non-interactive', 'Run without interactive prompts using environment variables')
18
+ .action(async (options) => {
19
+ await initCommand(options);
18
20
  });
19
21
  program
20
22
  .command('run')
@@ -32,6 +34,12 @@ program
32
34
  .action(async (action) => {
33
35
  await scheduleCommand(action);
34
36
  });
37
+ program
38
+ .command('validate')
39
+ .description('Run a pre-flight configuration check')
40
+ .action(async () => {
41
+ await validateCommand();
42
+ });
35
43
  program.addCommand(debugCommand);
36
44
  program.addCommand(configCommand);
37
45
  program.parse(process.argv);
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/cli/index.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,aAAa,EAAE,MAAM,QAAQ,CAAC;AACvC,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACjD,OAAO,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAC/C,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AACzD,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AACnD,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAErD,MAAM,OAAO,GAAG,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAC/C,MAAM,EAAE,OAAO,EAAE,GAAG,OAAO,CAAC,oBAAoB,CAAC,CAAC;AAElD,MAAM,OAAO,GAAG,IAAI,OAAO,EAAE,CAAC;AAE9B,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,WAAW,CAAC,mCAAmC,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;AAEvF,OAAO;KACJ,OAAO,CAAC,MAAM,CAAC;KACf,WAAW,CAAC,+BAA+B,CAAC;KAC5C,MAAM,CAAC,KAAK,IAAI,EAAE;IACjB,MAAM,WAAW,EAAE,CAAC;AACtB,CAAC,CAAC,CAAC;AAEL,OAAO;KACJ,OAAO,CAAC,KAAK,CAAC;KACd,WAAW,CAAC,mCAAmC,CAAC;KAChD,MAAM,CAAC,aAAa,EAAE,wBAAwB,CAAC;KAC/C,MAAM,CAAC,eAAe,EAAE,4BAA4B,CAAC;KACrD,MAAM,CAAC,aAAa,EAAE,mCAAmC,CAAC;KAC1D,MAAM,CAAC,KAAK,EAAE,OAAO,EAAE,EAAE;IACxB,MAAM,UAAU,CAAC,OAAO,CAAC,CAAC;AAC5B,CAAC,CAAC,CAAC;AAEL,OAAO;KACJ,OAAO,CAAC,mBAAmB,CAAC;KAC5B,WAAW,CAAC,yBAAyB,CAAC;KACtC,WAAW,CAAC,OAAO,EAAE,qCAAqC,CAAC;KAC3D,MAAM,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE;IACvB,MAAM,eAAe,CAAC,MAAM,CAAC,CAAC;AAChC,CAAC,CAAC,CAAC;AAEL,OAAO,CAAC,UAAU,CAAC,YAAY,CAAC,CAAC;AACjC,OAAO,CAAC,UAAU,CAAC,aAAa,CAAC,CAAC;AAElC,OAAO,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/cli/index.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,aAAa,EAAE,MAAM,QAAQ,CAAC;AACvC,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACjD,OAAO,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAC/C,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AACzD,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AACnD,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AACrD,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAEzD,MAAM,OAAO,GAAG,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAC/C,MAAM,EAAE,OAAO,EAAE,GAAG,OAAO,CAAC,oBAAoB,CAAC,CAAC;AAElD,MAAM,OAAO,GAAG,IAAI,OAAO,EAAE,CAAC;AAE9B,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,WAAW,CAAC,mCAAmC,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;AAEvF,OAAO;KACJ,OAAO,CAAC,MAAM,CAAC;KACf,WAAW,CAAC,+BAA+B,CAAC;KAC5C,MAAM,CAAC,mBAAmB,EAAE,6DAA6D,CAAC;KAC1F,MAAM,CAAC,KAAK,EAAE,OAAO,EAAE,EAAE;IACxB,MAAM,WAAW,CAAC,OAAO,CAAC,CAAC;AAC7B,CAAC,CAAC,CAAC;AAEL,OAAO;KACJ,OAAO,CAAC,KAAK,CAAC;KACd,WAAW,CAAC,mCAAmC,CAAC;KAChD,MAAM,CAAC,aAAa,EAAE,wBAAwB,CAAC;KAC/C,MAAM,CAAC,eAAe,EAAE,4BAA4B,CAAC;KACrD,MAAM,CAAC,aAAa,EAAE,mCAAmC,CAAC;KAC1D,MAAM,CAAC,KAAK,EAAE,OAAO,EAAE,EAAE;IACxB,MAAM,UAAU,CAAC,OAAO,CAAC,CAAC;AAC5B,CAAC,CAAC,CAAC;AAEL,OAAO;KACJ,OAAO,CAAC,mBAAmB,CAAC;KAC5B,WAAW,CAAC,yBAAyB,CAAC;KACtC,WAAW,CAAC,OAAO,EAAE,qCAAqC,CAAC;KAC3D,MAAM,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE;IACvB,MAAM,eAAe,CAAC,MAAM,CAAC,CAAC;AAChC,CAAC,CAAC,CAAC;AAEL,OAAO;KACJ,OAAO,CAAC,UAAU,CAAC;KACnB,WAAW,CAAC,sCAAsC,CAAC;KACnD,MAAM,CAAC,KAAK,IAAI,EAAE;IACjB,MAAM,eAAe,EAAE,CAAC;AAC1B,CAAC,CAAC,CAAC;AAEL,OAAO,CAAC,UAAU,CAAC,YAAY,CAAC,CAAC;AACjC,OAAO,CAAC,UAAU,CAAC,aAAa,CAAC,CAAC;AAElC,OAAO,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC"}
@@ -8,7 +8,9 @@ export class ConfigManager {
8
8
  configDir;
9
9
  configFile;
10
10
  constructor() {
11
- this.configDir = path.join(os.homedir(), '.config', 'alif');
11
+ this.configDir = process.env.ALIF_CONFIG_DIR
12
+ ? path.resolve(process.env.ALIF_CONFIG_DIR)
13
+ : path.join(os.homedir(), '.config', 'alif');
12
14
  this.configFile = path.join(this.configDir, 'config.json');
13
15
  }
14
16
  static getInstance() {
@@ -1 +1 @@
1
- {"version":3,"file":"config-manager.js","sourceRoot":"","sources":["../../src/core/config-manager.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"config-manager.js","sourceRoot":"","sources":["../../src/core/config-manager.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,12 @@
1
+ import { Config } from './config-schema.js';
2
+ export interface ValidationFailure {
3
+ scope: 'LLM' | 'Delivery' | 'Feeds' | 'Config';
4
+ message: string;
5
+ }
6
+ export declare class Validator {
7
+ private config;
8
+ private feedsPath;
9
+ constructor(config: Config, feedsPath: string);
10
+ validate(): ValidationFailure[];
11
+ printAndExitIfFailed(): void;
12
+ }