alif-digest 1.1.1 → 1.1.3

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
@@ -156,13 +156,37 @@ Config is stored at `~/.config/alif/config.json`. Most values can be changed wit
156
156
  }
157
157
  ```
158
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 access credentials as **Repository Secrets**.
166
+ 4. Configure your preferences as **Repository Variables** (optional).
167
+
168
+ ### Environment Variables Reference
169
+
170
+ | Variable | Type | Possible Values | Default | Description |
171
+ | ------------------------------ | -------- | ----------------------------------------- | ------------------- | ----------------------------------------------------------------------------- |
172
+ | `ALIF_LLM_PROVIDER` | Variable | `'anthropic'`, `'openrouter'`, `'ollama'` | `'anthropic'` | The AI provider to use for analysis. |
173
+ | `ALIF_LLM_API_KEY` | Secret | _Your API Key_ | - | Universal key. Alternatively use `ANTHROPIC_API_KEY` or `OPENROUTER_API_KEY`. |
174
+ | `ALIF_LLM_MODEL` | Variable | e.g. `'claude-3-5-sonnet-20240620'` | _Provider Specific_ | The specific model to use. |
175
+ | `SLACK_WEBHOOK_URL` | Secret | *https://hooks.slack.com/...* | - | Webhook URL for Slack delivery. |
176
+ | `GENERIC_WEBHOOK_URL` | Secret | _https://..._ | - | Webhook URL for generic server delivery. |
177
+ | `ALIF_SIGNAL_THRESHOLD` | Variable | `0` - `100` | `60` | Minimum score for an article to qualify. |
178
+ | `ALIF_MAX_ITEMS_PER_RUN` | Variable | `1`+ | `10` | Max articles delivered per run. |
179
+ | `ALIF_SOURCE_COOLDOWN_MINUTES` | Variable | `0`+ | `5` | Minimum gap between re-fetching a source. |
180
+
181
+ 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!
182
+
159
183
  ---
160
184
 
161
185
  ## 🤝 Architecture & Contributing
162
186
 
163
187
  Interested in how Alif works under the hood or want to run it locally?
164
188
 
165
- Check out our [**Contributing Guidelines**](CONTRIBUTING.md) for information on the architecture, local development setup, and how to submit pull requests!
189
+ 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!
166
190
 
167
191
  ---
168
192
 
@@ -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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"}
package/dist/cli/index.js CHANGED
@@ -14,8 +14,9 @@ program.name('alif').description('Alif - Daily AI Signal Digest CLI').version(ve
14
14
  program
15
15
  .command('init')
16
16
  .description('Initialize Alif configuration')
17
- .action(async () => {
18
- await initCommand();
17
+ .option('--non-interactive', 'Run without interactive prompts using environment variables')
18
+ .action(async (options) => {
19
+ await initCommand(options);
19
20
  });
20
21
  program
21
22
  .command('run')
@@ -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;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,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;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"}
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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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "alif-digest",
3
- "version": "1.1.1",
3
+ "version": "1.1.3",
4
4
  "description": "Autonomous AI Signal Digest CLI for tracking high-signal AI breakthroughs.",
5
5
  "type": "module",
6
6
  "publishConfig": {
@@ -4,110 +4,180 @@ import { ConfigManager } from '../../core/config-manager.js';
4
4
  import { Config } from '../../core/config-schema.js';
5
5
  import { logger } from '../../core/logger.js';
6
6
 
7
- export async function initCommand() {
7
+ export async function initCommand(options?: { nonInteractive?: boolean }) {
8
8
  const configManager = ConfigManager.getInstance();
9
9
  const configDir = configManager.getConfigDir();
10
10
 
11
11
  logger.log('\n--- Alif Initialization ---');
12
12
 
13
- const response = await prompts([
14
- {
15
- type: 'select',
16
- name: 'llmProvider',
17
- message: 'Which LLM provider would you like to use?',
18
- choices: [
19
- { title: 'Ollama (Local)', value: 'ollama' },
20
- { title: 'Anthropic', value: 'anthropic' },
21
- { title: 'OpenRouter', value: 'openrouter' },
22
- ],
23
- },
24
- {
25
- type: (prev) => (prev !== 'ollama' ? 'text' : null),
26
- name: 'apiKey',
27
- message: 'Enter your API Key:',
28
- },
29
- {
30
- type: 'text',
31
- name: 'model',
32
- message: 'Enter the model name (e.g., llama3, claude-3-opus-20240229):',
33
- initial: (prev, values) => {
34
- if (values.llmProvider === 'ollama') return 'llama3';
35
- if (values.llmProvider === 'anthropic') return 'claude-3-5-sonnet-20240620';
36
- return 'meta-llama/llama-3-70b-instruct';
13
+ let config: Config;
14
+
15
+ if (options?.nonInteractive) {
16
+ logger.info('Running in non-interactive mode. Reading from environment variables...');
17
+
18
+ const provider = (process.env.ALIF_LLM_PROVIDER || 'anthropic') as any;
19
+ let apiKey = process.env.ALIF_LLM_API_KEY;
20
+ if (!apiKey) {
21
+ if (provider === 'anthropic') apiKey = process.env.ANTHROPIC_API_KEY;
22
+ else if (provider === 'openrouter')
23
+ apiKey = process.env.OPENROUTER_API_KEY || process.env.OPENAI_API_KEY;
24
+ }
25
+
26
+ const model =
27
+ process.env.ALIF_LLM_MODEL ||
28
+ (provider === 'ollama'
29
+ ? 'llama3'
30
+ : provider === 'anthropic'
31
+ ? 'claude-3-5-sonnet-20240620'
32
+ : 'meta-llama/llama-3-70b-instruct');
33
+ const baseUrl =
34
+ process.env.ALIF_LLM_BASE_URL ||
35
+ (provider === 'ollama' ? 'http://localhost:11434' : undefined);
36
+
37
+ const deliveryConfigs = [];
38
+ if (process.env.SLACK_WEBHOOK_URL) {
39
+ deliveryConfigs.push({ type: 'slack' as const, webhookUrl: process.env.SLACK_WEBHOOK_URL });
40
+ }
41
+ if (process.env.GENERIC_WEBHOOK_URL) {
42
+ deliveryConfigs.push({
43
+ type: 'webhook' as const,
44
+ webhookUrl: process.env.GENERIC_WEBHOOK_URL,
45
+ });
46
+ }
47
+
48
+ config = {
49
+ llm: {
50
+ provider,
51
+ apiKey,
52
+ model,
53
+ baseUrl,
54
+ },
55
+ delivery: deliveryConfigs,
56
+ preferences: {
57
+ signalThreshold: process.env.ALIF_SIGNAL_THRESHOLD
58
+ ? parseInt(process.env.ALIF_SIGNAL_THRESHOLD, 10)
59
+ : 60,
60
+ maxItemsPerRun: process.env.ALIF_MAX_ITEMS_PER_RUN
61
+ ? parseInt(process.env.ALIF_MAX_ITEMS_PER_RUN, 10)
62
+ : 10,
63
+ sourceCooldownMinutes: process.env.ALIF_SOURCE_COOLDOWN_MINUTES
64
+ ? parseInt(process.env.ALIF_SOURCE_COOLDOWN_MINUTES, 10)
65
+ : 5,
66
+ sequentialAnalysis:
67
+ process.env.ALIF_SEQUENTIAL_ANALYSIS === 'true' || provider === 'ollama',
68
+ enableAIArticlesScoring: process.env.ALIF_ENABLE_AI_SCORING !== 'false',
69
+ customKeywords: process.env.ALIF_CUSTOM_KEYWORDS
70
+ ? JSON.parse(process.env.ALIF_CUSTOM_KEYWORDS)
71
+ : {},
72
+ negativeKeywords: process.env.ALIF_NEGATIVE_KEYWORDS
73
+ ? JSON.parse(process.env.ALIF_NEGATIVE_KEYWORDS)
74
+ : {},
75
+ logLevel: (process.env.ALIF_LOG_LEVEL as any) || 'normal',
76
+ noColor: process.env.ALIF_NO_COLOR === 'true',
77
+ },
78
+ dbPath: path.join(configDir, 'alif.db'),
79
+ feedsPath: path.join(configDir, 'feeds.json'),
80
+ };
81
+ } else {
82
+ const response = await prompts([
83
+ {
84
+ type: 'select',
85
+ name: 'llmProvider',
86
+ message: 'Which LLM provider would you like to use?',
87
+ choices: [
88
+ { title: 'Ollama (Local)', value: 'ollama' },
89
+ { title: 'Anthropic', value: 'anthropic' },
90
+ { title: 'OpenRouter', value: 'openrouter' },
91
+ ],
92
+ },
93
+ {
94
+ type: (prev) => (prev !== 'ollama' ? 'text' : null),
95
+ name: 'apiKey',
96
+ message: 'Enter your API Key:',
97
+ },
98
+ {
99
+ type: 'text',
100
+ name: 'model',
101
+ message: 'Enter the model name (e.g., llama3, claude-3-opus-20240229):',
102
+ initial: (prev, values) => {
103
+ if (values.llmProvider === 'ollama') return 'llama3';
104
+ if (values.llmProvider === 'anthropic') return 'claude-3-5-sonnet-20240620';
105
+ return 'meta-llama/llama-3-70b-instruct';
106
+ },
37
107
  },
38
- },
39
- {
40
- type: (prev, values) => (values.llmProvider === 'ollama' ? 'text' : null),
41
- name: 'baseUrl',
42
- message: 'Enter Ollama base URL:',
43
- initial: 'http://localhost:11434',
44
- },
45
- {
46
- type: 'toggle',
47
- name: 'sequentialAnalysis',
48
- message:
49
- 'Enable sequential (one-by-one) LLM processing? (Recommended for small local models)',
50
- initial: (prev, values) => values.llmProvider === 'ollama',
51
- active: 'yes',
52
- inactive: 'no',
53
- },
54
- {
55
- type: 'toggle',
56
- name: 'enableAIArticlesScoring',
57
- message: 'Enable AI Article Scoring? (Uses your LLM to intelligently score articles)',
58
- initial: true,
59
- active: 'yes',
60
- inactive: 'no',
61
- },
62
- {
63
- type: 'multiselect',
64
- name: 'deliveryProviders',
65
- message: 'Where should we deliver the digest?',
66
- choices: [
67
- { title: 'Slack', value: 'slack' },
68
- { title: 'Generic Webhook', value: 'webhook' },
69
- ],
70
- min: 1,
71
- },
72
- ]);
108
+ {
109
+ type: (prev, values) => (values.llmProvider === 'ollama' ? 'text' : null),
110
+ name: 'baseUrl',
111
+ message: 'Enter Ollama base URL:',
112
+ initial: 'http://localhost:11434',
113
+ },
114
+ {
115
+ type: 'toggle',
116
+ name: 'sequentialAnalysis',
117
+ message:
118
+ 'Enable sequential (one-by-one) LLM processing? (Recommended for small local models)',
119
+ initial: (prev, values) => values.llmProvider === 'ollama',
120
+ active: 'yes',
121
+ inactive: 'no',
122
+ },
123
+ {
124
+ type: 'toggle',
125
+ name: 'enableAIArticlesScoring',
126
+ message: 'Enable AI Article Scoring? (Uses your LLM to intelligently score articles)',
127
+ initial: true,
128
+ active: 'yes',
129
+ inactive: 'no',
130
+ },
131
+ {
132
+ type: 'multiselect',
133
+ name: 'deliveryProviders',
134
+ message: 'Where should we deliver the digest?',
135
+ choices: [
136
+ { title: 'Slack', value: 'slack' },
137
+ { title: 'Generic Webhook', value: 'webhook' },
138
+ ],
139
+ min: 1,
140
+ },
141
+ ]);
73
142
 
74
- if (!response.llmProvider || !response.deliveryProviders) {
75
- logger.warn('Initialization cancelled.');
76
- return;
77
- }
143
+ if (!response.llmProvider || !response.deliveryProviders) {
144
+ logger.warn('Initialization cancelled.');
145
+ return;
146
+ }
78
147
 
79
- const deliveryConfigs = [];
80
- for (const provider of response.deliveryProviders) {
81
- const { webhookUrl } = await prompts({
82
- type: 'text',
83
- name: 'webhookUrl',
84
- message: `Enter ${provider} Webhook URL:`,
85
- });
86
- deliveryConfigs.push({ type: provider, webhookUrl });
87
- }
148
+ const deliveryConfigs = [];
149
+ for (const provider of response.deliveryProviders) {
150
+ const { webhookUrl } = await prompts({
151
+ type: 'text',
152
+ name: 'webhookUrl',
153
+ message: `Enter ${provider} Webhook URL:`,
154
+ });
155
+ deliveryConfigs.push({ type: provider, webhookUrl });
156
+ }
88
157
 
89
- const config: Config = {
90
- llm: {
91
- provider: response.llmProvider,
92
- apiKey: response.apiKey,
93
- model: response.model,
94
- baseUrl: response.baseUrl,
95
- },
96
- delivery: deliveryConfigs,
97
- preferences: {
98
- signalThreshold: 60,
99
- maxItemsPerRun: 10,
100
- sourceCooldownMinutes: 5,
101
- sequentialAnalysis: response.sequentialAnalysis,
102
- enableAIArticlesScoring: response.enableAIArticlesScoring,
103
- customKeywords: {},
104
- negativeKeywords: {},
105
- logLevel: 'normal' as const,
106
- noColor: false,
107
- },
108
- dbPath: path.join(configDir, 'alif.db'),
109
- feedsPath: path.join(configDir, 'feeds.json'),
110
- };
158
+ config = {
159
+ llm: {
160
+ provider: response.llmProvider,
161
+ apiKey: response.apiKey,
162
+ model: response.model,
163
+ baseUrl: response.baseUrl,
164
+ },
165
+ delivery: deliveryConfigs,
166
+ preferences: {
167
+ signalThreshold: 60,
168
+ maxItemsPerRun: 10,
169
+ sourceCooldownMinutes: 5,
170
+ sequentialAnalysis: response.sequentialAnalysis,
171
+ enableAIArticlesScoring: response.enableAIArticlesScoring,
172
+ customKeywords: {},
173
+ negativeKeywords: {},
174
+ logLevel: 'normal' as const,
175
+ noColor: false,
176
+ },
177
+ dbPath: path.join(configDir, 'alif.db'),
178
+ feedsPath: path.join(configDir, 'feeds.json'),
179
+ };
180
+ }
111
181
 
112
182
  configManager.save(config);
113
183
 
package/src/cli/index.ts CHANGED
@@ -18,8 +18,9 @@ program.name('alif').description('Alif - Daily AI Signal Digest CLI').version(ve
18
18
  program
19
19
  .command('init')
20
20
  .description('Initialize Alif configuration')
21
- .action(async () => {
22
- await initCommand();
21
+ .option('--non-interactive', 'Run without interactive prompts using environment variables')
22
+ .action(async (options) => {
23
+ await initCommand(options);
23
24
  });
24
25
 
25
26
  program
@@ -10,7 +10,9 @@ export class ConfigManager {
10
10
  private configFile: string;
11
11
 
12
12
  private constructor() {
13
- this.configDir = path.join(os.homedir(), '.config', 'alif');
13
+ this.configDir = process.env.ALIF_CONFIG_DIR
14
+ ? path.resolve(process.env.ALIF_CONFIG_DIR)
15
+ : path.join(os.homedir(), '.config', 'alif');
14
16
  this.configFile = path.join(this.configDir, 'config.json');
15
17
  }
16
18
 
@@ -46,6 +46,20 @@ describe('ConfigManager', () => {
46
46
  expect(manager.getConfigFile()).toBe(mockConfigFile);
47
47
  });
48
48
 
49
+ it('should override config path using ALIF_CONFIG_DIR', () => {
50
+ // @ts-expect-error - reset singleton for tests
51
+ ConfigManager['instance'] = undefined;
52
+ process.env.ALIF_CONFIG_DIR = '/custom/config/path';
53
+
54
+ const manager = ConfigManager.getInstance();
55
+ expect(manager.getConfigDir()).toBe(path.resolve('/custom/config/path'));
56
+ expect(manager.getConfigFile()).toBe(
57
+ path.join(path.resolve('/custom/config/path'), 'config.json'),
58
+ );
59
+
60
+ delete process.env.ALIF_CONFIG_DIR;
61
+ });
62
+
49
63
  it('should throw if loading non-existent config', () => {
50
64
  vi.mocked(fs.existsSync).mockReturnValue(false);
51
65
  const manager = ConfigManager.getInstance();