snow-flow 3.6.25 → 4.0.0-final-claude
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/.env.example +89 -0
- package/README.md +40 -15
- package/dist/agent/interactive.d.ts +11 -0
- package/dist/agent/interactive.js +190 -0
- package/dist/agent/session.d.ts +12 -0
- package/dist/agent/session.js +106 -0
- package/dist/cli/auth.d.ts +3 -0
- package/dist/cli/auth.js +59 -0
- package/dist/cli/session.d.ts +3 -0
- package/dist/cli/session.js +46 -0
- package/dist/cli.js +81 -0
- package/dist/config/llm-config-loader.d.ts +31 -0
- package/dist/config/llm-config-loader.js +80 -0
- package/dist/dynamic-version.js +1 -1
- package/dist/llm/keys.d.ts +5 -0
- package/dist/llm/keys.js +29 -0
- package/dist/llm/providers.d.ts +11 -0
- package/dist/llm/providers.js +77 -0
- package/dist/mcp/bridge.d.ts +10 -0
- package/dist/mcp/bridge.js +31 -0
- package/dist/session/store.d.ts +47 -0
- package/dist/session/store.js +74 -0
- package/package.json +8 -3
- package/snowflow.config.json +15 -0
package/.env.example
ADDED
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
# Closed-source
|
|
2
|
+
OPENAI_API_KEY=
|
|
3
|
+
GOOGLE_API_KEY=
|
|
4
|
+
|
|
5
|
+
# Gateways / OSS
|
|
6
|
+
OPENROUTER_API_KEY=
|
|
7
|
+
OPENAI_COMPAT_API_KEY= # voor xAI Grok en DeepSeek (OpenAI-compatible)
|
|
8
|
+
|
|
9
|
+
# ServiceNow Configuration
|
|
10
|
+
# ===========================================
|
|
11
|
+
|
|
12
|
+
# ServiceNow Instance URL (without https://)
|
|
13
|
+
# Example: dev12345.service-now.com
|
|
14
|
+
SNOW_INSTANCE=your-instance.service-now.com
|
|
15
|
+
|
|
16
|
+
# OAuth Client ID from ServiceNow Application Registry
|
|
17
|
+
SNOW_CLIENT_ID=your-oauth-client-id
|
|
18
|
+
|
|
19
|
+
# OAuth Client Secret from ServiceNow Application Registry
|
|
20
|
+
SNOW_CLIENT_SECRET=your-oauth-client-secret
|
|
21
|
+
|
|
22
|
+
# ===========================================
|
|
23
|
+
# Snow-Flow Configuration
|
|
24
|
+
# ===========================================
|
|
25
|
+
|
|
26
|
+
# Enable debug logging (true/false)
|
|
27
|
+
SNOW_FLOW_DEBUG=true
|
|
28
|
+
|
|
29
|
+
# MAXIMUM DEBUG LEVELS
|
|
30
|
+
DEBUG=* # Debug ALLES
|
|
31
|
+
NODE_ENV=development # Development mode voor extra debug info
|
|
32
|
+
LOG_LEVEL=trace # Trace is nog hoger dan debug
|
|
33
|
+
VERBOSE=true # Extra verbose output
|
|
34
|
+
MCP_DEBUG=true # MCP specific debugging
|
|
35
|
+
MCP_LOG_LEVEL=trace # MCP trace level logging
|
|
36
|
+
SNOW_FLOW_TRACE=true # Snow-Flow trace logging
|
|
37
|
+
CLAUDE_CODE_DEBUG=true # Claude Code debug mode
|
|
38
|
+
HTTP_TRACE=true # HTTP request/response tracing
|
|
39
|
+
|
|
40
|
+
# Default coordination strategy
|
|
41
|
+
SNOW_FLOW_STRATEGY=development
|
|
42
|
+
|
|
43
|
+
# Maximum number of agents
|
|
44
|
+
SNOW_FLOW_MAX_AGENTS=5
|
|
45
|
+
|
|
46
|
+
# ===========================================
|
|
47
|
+
# Claude Code API Integration (30 minutes)
|
|
48
|
+
# ===========================================
|
|
49
|
+
# API timeout for Claude Code integration - 30 minutes
|
|
50
|
+
# This ensures Snow-Flow works smoothly with Claude Code's extended operation timeouts
|
|
51
|
+
API_TIMEOUT_MS=1800000
|
|
52
|
+
|
|
53
|
+
# ===========================================
|
|
54
|
+
# Timeout Configuration (v3.0.1+)
|
|
55
|
+
# ===========================================
|
|
56
|
+
# IMPORTANT: Snow-Flow has NO TIMEOUTS by default for maximum reliability.
|
|
57
|
+
# Operations run until completion. Only set timeouts if you specifically need them.
|
|
58
|
+
# All timeout values below are COMMENTED OUT - uncomment only what you need.
|
|
59
|
+
|
|
60
|
+
# Memory Operations (TodoWrite, etc.)
|
|
61
|
+
# MCP_MEMORY_TIMEOUT=30000 # 30 seconds
|
|
62
|
+
# MCP_MEMORY_TIMEOUT=60000 # 1 minute
|
|
63
|
+
# MCP_MEMORY_TIMEOUT=120000 # 2 minutes
|
|
64
|
+
|
|
65
|
+
# ServiceNow API Operations
|
|
66
|
+
# SNOW_API_TIMEOUT=60000 # 1 minute - quick operations
|
|
67
|
+
# SNOW_API_TIMEOUT=180000 # 3 minutes - standard operations
|
|
68
|
+
# SNOW_API_TIMEOUT=300000 # 5 minutes - complex queries
|
|
69
|
+
|
|
70
|
+
# Deployment Operations
|
|
71
|
+
# SNOW_DEPLOYMENT_TIMEOUT=300000 # 5 minutes - simple deployments
|
|
72
|
+
# SNOW_DEPLOYMENT_TIMEOUT=600000 # 10 minutes - complex widgets
|
|
73
|
+
|
|
74
|
+
# MCP transport timeout (should be higher than SNOW_DEPLOYMENT_TIMEOUT if both set)
|
|
75
|
+
# MCP_DEPLOYMENT_TIMEOUT=360000 # 6 minutes
|
|
76
|
+
# MCP_DEPLOYMENT_TIMEOUT=720000 # 12 minutes
|
|
77
|
+
|
|
78
|
+
# ===========================================
|
|
79
|
+
# Response Size Limits (v3.4.34+)
|
|
80
|
+
# ===========================================
|
|
81
|
+
# Maximum MCP response size to prevent timeouts
|
|
82
|
+
# Default: 500KB (sufficient for most widgets/flows)
|
|
83
|
+
# MCP_MAX_RESPONSE_SIZE=500000 # 500KB default (recommended)
|
|
84
|
+
# MCP_MAX_RESPONSE_SIZE=1000000 # 1MB for larger artifacts
|
|
85
|
+
# MCP_MAX_RESPONSE_SIZE=2000000 # 2MB for very large responses
|
|
86
|
+
|
|
87
|
+
# Maximum array items in responses
|
|
88
|
+
# MCP_MAX_ARRAY_ITEMS=500 # 500 items default
|
|
89
|
+
# MCP_MAX_ARRAY_ITEMS=1000 # 1000 for large datasets
|
package/README.md
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
<div align="center">
|
|
2
2
|
<img src="assets/snow-flow-logo.svg" alt="Snow-Flow Logo" width="200" height="200">
|
|
3
3
|
|
|
4
|
-
# ❄️ Snow-Flow
|
|
4
|
+
# ❄️ Snow-Flow v4.0.0 - Final Claude Code CLI Edition ❄️
|
|
5
5
|
|
|
6
6
|
<p align="center">
|
|
7
7
|
<strong>🚀 Revolutionary ServiceNow Development Framework with AI-Powered Automation</strong>
|
|
8
8
|
</p>
|
|
9
9
|
|
|
10
10
|
<p align="center">
|
|
11
|
-
<a href="https://www.npmjs.com/package/snow-flow"><img src="https://img.shields.io/npm
|
|
11
|
+
<a href="https://www.npmjs.com/package/snow-flow"><img src="https://img.shields.io/badge/npm-v4.0.0--final--claude-CB3837?style=for-the-badge&logo=npm" alt="npm version"></a>
|
|
12
12
|
<a href="https://opensource.org/licenses/MIT"><img src="https://img.shields.io/badge/License-MIT-green.svg?style=for-the-badge" alt="License: MIT"></a>
|
|
13
13
|
<a href="https://nodejs.org"><img src="https://img.shields.io/node/v/snow-flow.svg?style=for-the-badge&logo=node.js&color=339933" alt="Node.js Version"></a>
|
|
14
14
|
<a href="https://github.com/groeimetai/snow-flow"><img src="https://img.shields.io/github/stars/groeimetai/snow-flow?style=for-the-badge&logo=github" alt="GitHub Stars"></a>
|
|
@@ -21,29 +21,54 @@
|
|
|
21
21
|
|
|
22
22
|
---
|
|
23
23
|
|
|
24
|
-
##
|
|
24
|
+
## 🚨 Important Announcement: Final Claude Code CLI Edition
|
|
25
|
+
|
|
26
|
+
<div align="center">
|
|
27
|
+
<table>
|
|
28
|
+
<tr>
|
|
29
|
+
<td align="center">
|
|
30
|
+
<h3>⚡ This is the Final Claude Code CLI Version ⚡</h3>
|
|
31
|
+
<p>Snow-Flow v4.0.0 marks the end of an era. This is the last version designed specifically for Claude Code CLI.</p>
|
|
32
|
+
<p><strong>🔮 What's Coming Next:</strong></p>
|
|
33
|
+
<ul align="left">
|
|
34
|
+
<li>🤖 Support for <strong>ANY LLM</strong>: OpenAI, Google Gemini, Anthropic Claude, Ollama, and more</li>
|
|
35
|
+
<li>🔌 Modular provider system with unified interface</li>
|
|
36
|
+
<li>💻 Native CLI with interactive chat interface</li>
|
|
37
|
+
<li>🔄 Seamless switching between LLM providers</li>
|
|
38
|
+
<li>📊 Same great ServiceNow tools, now LLM-agnostic</li>
|
|
39
|
+
</ul>
|
|
40
|
+
<p><strong>Thank you to all Claude Code users who made this journey possible! 🙏</strong></p>
|
|
41
|
+
</td>
|
|
42
|
+
</tr>
|
|
43
|
+
</table>
|
|
44
|
+
</div>
|
|
45
|
+
|
|
46
|
+
---
|
|
47
|
+
|
|
48
|
+
## 🎉 What's New in v4.0.0-final-claude
|
|
25
49
|
|
|
26
50
|
<div align="center">
|
|
27
51
|
<table>
|
|
28
52
|
<tr>
|
|
29
53
|
<td align="center" width="50%">
|
|
30
|
-
<h3
|
|
54
|
+
<h3>🏁 Final Release Features</h3>
|
|
31
55
|
<ul align="left">
|
|
32
|
-
<li><strong
|
|
33
|
-
<li><strong
|
|
34
|
-
<li><strong
|
|
35
|
-
<li><strong
|
|
36
|
-
<li><strong
|
|
56
|
+
<li><strong>🔚 Final Claude Code CLI Version</strong><br/>Last release for Claude Code users</li>
|
|
57
|
+
<li><strong>📚 Complete Feature Set</strong><br/>All 18 MCP servers, 200+ tools</li>
|
|
58
|
+
<li><strong>🎯 Catalog UI Policy Support</strong><br/>Deploy via unified <code>snow_deploy</code> tool</li>
|
|
59
|
+
<li><strong>🔒 Knowledge Base Verification</strong><br/>Prevents orphaned articles</li>
|
|
60
|
+
<li><strong>✨ Beautiful Documentation</strong><br/>Enhanced README and website</li>
|
|
37
61
|
</ul>
|
|
38
62
|
</td>
|
|
39
63
|
<td align="center" width="50%">
|
|
40
|
-
<h3
|
|
64
|
+
<h3>🚀 Latest Improvements</h3>
|
|
41
65
|
<ul align="left">
|
|
42
|
-
<li>✅ Catalog variables
|
|
43
|
-
<li>✅ UI policy
|
|
44
|
-
<li>✅
|
|
45
|
-
<li>✅ MCP transport 3x faster
|
|
46
|
-
<li>✅
|
|
66
|
+
<li>✅ Catalog variables table fix (v3.6.23)</li>
|
|
67
|
+
<li>✅ UI policy debugging enhanced (v3.6.22)</li>
|
|
68
|
+
<li>✅ Knowledge validation added (v3.6.25)</li>
|
|
69
|
+
<li>✅ MCP transport 3x faster</li>
|
|
70
|
+
<li>✅ ES5 validation throughout</li>
|
|
71
|
+
<li>🎁 All previous fixes included</li>
|
|
47
72
|
</ul>
|
|
48
73
|
</td>
|
|
49
74
|
</tr>
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { SnowFlowConfig } from '../config/llm-config-loader';
|
|
2
|
+
import type { ProviderOptions } from '../llm/providers';
|
|
3
|
+
export interface InteractiveOptions extends ProviderOptions {
|
|
4
|
+
system?: string;
|
|
5
|
+
mcp: SnowFlowConfig['mcp'];
|
|
6
|
+
maxSteps?: number;
|
|
7
|
+
showReasoning?: boolean;
|
|
8
|
+
resumeId?: string;
|
|
9
|
+
}
|
|
10
|
+
export declare function runInteractive(opts: InteractiveOptions): Promise<void>;
|
|
11
|
+
//# sourceMappingURL=interactive.d.ts.map
|
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.runInteractive = runInteractive;
|
|
7
|
+
const bridge_1 = require("../mcp/bridge");
|
|
8
|
+
const chalk_1 = __importDefault(require("chalk"));
|
|
9
|
+
const boxen_1 = __importDefault(require("boxen"));
|
|
10
|
+
const node_readline_1 = __importDefault(require("node:readline"));
|
|
11
|
+
const store_js_1 = require("../session/store.js");
|
|
12
|
+
const ora_1 = __importDefault(require("ora"));
|
|
13
|
+
async function runInteractive(opts) {
|
|
14
|
+
const { provider, model, baseURL, apiKeyEnv, system, mcp, maxSteps = 40, showReasoning = true, resumeId } = opts;
|
|
15
|
+
// Resolve model
|
|
16
|
+
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
|
17
|
+
const prov = require('../llm/providers.js');
|
|
18
|
+
const llm = prov.getModel({ provider, model, baseURL, apiKeyEnv });
|
|
19
|
+
const sessionId = resumeId || (0, store_js_1.createSessionId)();
|
|
20
|
+
(0, store_js_1.startSession)({
|
|
21
|
+
id: sessionId,
|
|
22
|
+
startedAt: new Date().toISOString(),
|
|
23
|
+
objective: '(interactive)',
|
|
24
|
+
provider: { id: String(provider), model: String(model), baseURL },
|
|
25
|
+
mcp: { cmd: mcp.cmd, args: mcp.args },
|
|
26
|
+
});
|
|
27
|
+
process.stdout.write(chalk_1.default.bold(`\nSnow-Flow Interactive (${provider}:${model})`) + "\n");
|
|
28
|
+
process.stdout.write(chalk_1.default.gray('Tips: ESC ESC = vorige assistant-antwoord | /quit om te stoppen') + "\n\n");
|
|
29
|
+
// Load tools once with spinner
|
|
30
|
+
const spinner = (0, ora_1.default)('MCP-tools laden...').start();
|
|
31
|
+
const { tools, close } = await (0, bridge_1.loadMCPTools)(mcp).finally(() => spinner.stop());
|
|
32
|
+
const messages = [];
|
|
33
|
+
if (system)
|
|
34
|
+
messages.push({ role: 'system', content: system });
|
|
35
|
+
// Preload previous messages if resuming
|
|
36
|
+
if (resumeId) {
|
|
37
|
+
try {
|
|
38
|
+
const { readSession } = require('../session/store.js');
|
|
39
|
+
const rec = readSession(resumeId);
|
|
40
|
+
if (rec?.messages?.length) {
|
|
41
|
+
const recent = rec.messages.filter((m) => m.role === 'user' || m.role === 'assistant').slice(-20);
|
|
42
|
+
for (const m of recent)
|
|
43
|
+
messages.push({ role: m.role, content: m.content });
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
catch { }
|
|
47
|
+
}
|
|
48
|
+
// Key handling for ESC ESC
|
|
49
|
+
node_readline_1.default.emitKeypressEvents(process.stdin);
|
|
50
|
+
if (process.stdin.isTTY)
|
|
51
|
+
process.stdin.setRawMode(true);
|
|
52
|
+
let lastEsc = 0;
|
|
53
|
+
let lastAssistant = null;
|
|
54
|
+
let showTools = true;
|
|
55
|
+
const onKeypress = (_str, key) => {
|
|
56
|
+
if (!key)
|
|
57
|
+
return;
|
|
58
|
+
if (key.name === 'escape') {
|
|
59
|
+
const now = Date.now();
|
|
60
|
+
if (now - lastEsc < 500) {
|
|
61
|
+
// double ESC
|
|
62
|
+
if (lastAssistant) {
|
|
63
|
+
const box = (0, boxen_1.default)(lastAssistant.slice(0, 1200) + (lastAssistant.length > 1200 ? '…' : ''), { padding: 1, borderColor: 'yellow', title: 'Vorige assistant', titleAlignment: 'center' });
|
|
64
|
+
process.stdout.write('\n' + box + '\n');
|
|
65
|
+
}
|
|
66
|
+
else {
|
|
67
|
+
process.stdout.write(chalk_1.default.gray('\nGeen vorige assistant-respons beschikbaar.') + '\n');
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
lastEsc = now;
|
|
71
|
+
}
|
|
72
|
+
if (key.name === 't') {
|
|
73
|
+
showTools = !showTools;
|
|
74
|
+
process.stdout.write('\n' + (showTools ? chalk_1.default.gray('Tool events: ON') : chalk_1.default.gray('Tool events: OFF')) + '\n');
|
|
75
|
+
}
|
|
76
|
+
if (key.name === 'h') {
|
|
77
|
+
const last = messages.slice(-6);
|
|
78
|
+
const text = last.map(m => `${m.role}> ${m.content}`).join('\n');
|
|
79
|
+
const panel = (0, boxen_1.default)(text, { padding: 1, borderColor: 'blue', title: 'History (tail)', titleAlignment: 'center' });
|
|
80
|
+
process.stdout.write('\n' + panel + '\n');
|
|
81
|
+
}
|
|
82
|
+
if (key.name === 's') {
|
|
83
|
+
const fs = require('fs');
|
|
84
|
+
const out = (lastAssistant || '').toString();
|
|
85
|
+
const outPath = `${process.env.HOME || ''}/.snow-flow/sessions/${sessionId}.txt`;
|
|
86
|
+
try {
|
|
87
|
+
fs.writeFileSync(outPath, out, 'utf8');
|
|
88
|
+
}
|
|
89
|
+
catch { }
|
|
90
|
+
process.stdout.write(chalk_1.default.gray(`Saved assistant output to ${outPath}`) + '\n');
|
|
91
|
+
}
|
|
92
|
+
};
|
|
93
|
+
process.stdin.on('keypress', onKeypress);
|
|
94
|
+
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
|
95
|
+
const { streamText } = require('ai');
|
|
96
|
+
const rl = node_readline_1.default.createInterface({ input: process.stdin, output: process.stdout, terminal: true });
|
|
97
|
+
const ask = (q) => new Promise(resolve => rl.question(q, resolve));
|
|
98
|
+
try {
|
|
99
|
+
const onSignal = async () => {
|
|
100
|
+
try {
|
|
101
|
+
await close();
|
|
102
|
+
}
|
|
103
|
+
catch { }
|
|
104
|
+
(0, store_js_1.endSession)(sessionId);
|
|
105
|
+
process.stdout.write('\n' + chalk_1.default.gray('Session ended.') + '\n');
|
|
106
|
+
process.exit(0);
|
|
107
|
+
};
|
|
108
|
+
process.on('SIGINT', onSignal);
|
|
109
|
+
process.on('SIGTERM', onSignal);
|
|
110
|
+
// loop
|
|
111
|
+
while (true) {
|
|
112
|
+
const input = await ask(chalk_1.default.cyan('You: '));
|
|
113
|
+
if (!input)
|
|
114
|
+
continue;
|
|
115
|
+
if (input.trim() === '/quit')
|
|
116
|
+
break;
|
|
117
|
+
const long = input.length > 1200;
|
|
118
|
+
if (long) {
|
|
119
|
+
const preview = input.slice(0, 1200) + '…';
|
|
120
|
+
const box = (0, boxen_1.default)(preview, { padding: 1, borderColor: 'green', title: 'Preview (truncated)', titleAlignment: 'center' });
|
|
121
|
+
process.stdout.write('\n' + box + '\n');
|
|
122
|
+
const confirm = await ask(chalk_1.default.gray('Doorgaan met verzenden? [y/N] '));
|
|
123
|
+
if (!/^y(es)?$/i.test(confirm.trim()))
|
|
124
|
+
continue;
|
|
125
|
+
}
|
|
126
|
+
messages.push({ role: 'user', content: input });
|
|
127
|
+
(0, store_js_1.appendMessage)(sessionId, { role: 'user', content: input, timestamp: new Date().toISOString() });
|
|
128
|
+
const result = await streamText({
|
|
129
|
+
model: llm,
|
|
130
|
+
system,
|
|
131
|
+
messages,
|
|
132
|
+
tools,
|
|
133
|
+
maxSteps,
|
|
134
|
+
});
|
|
135
|
+
let buffer = '';
|
|
136
|
+
let inReasoning = false;
|
|
137
|
+
const write = (s) => {
|
|
138
|
+
buffer += s;
|
|
139
|
+
const out = inReasoning && showReasoning ? chalk_1.default.yellow.dim(s) : s;
|
|
140
|
+
process.stdout.write(out);
|
|
141
|
+
};
|
|
142
|
+
if (result.toolCallStream && typeof result.toolCallStream[Symbol.asyncIterator] === 'function') {
|
|
143
|
+
(async () => {
|
|
144
|
+
for await (const ev of result.toolCallStream) {
|
|
145
|
+
const name = ev?.toolName || ev?.name || 'tool';
|
|
146
|
+
const args = ev?.args ? JSON.stringify(ev.args).slice(0, 180) : '';
|
|
147
|
+
if (showTools)
|
|
148
|
+
process.stdout.write('\n' + chalk_1.default.cyan(`🔧 Tool → ${name} ${args}`) + '\n');
|
|
149
|
+
(0, store_js_1.appendToolEvent)(sessionId, { name, argsPreview: args });
|
|
150
|
+
}
|
|
151
|
+
})().catch(() => { });
|
|
152
|
+
}
|
|
153
|
+
if (result.toolResultStream && typeof result.toolResultStream[Symbol.asyncIterator] === 'function') {
|
|
154
|
+
(async () => {
|
|
155
|
+
for await (const ev of result.toolResultStream) {
|
|
156
|
+
const name = ev?.toolName || ev?.name || 'tool';
|
|
157
|
+
const out = ev?.result ? JSON.stringify(ev.result).slice(0, 180) : '';
|
|
158
|
+
if (showTools)
|
|
159
|
+
process.stdout.write(chalk_1.default.magenta(`📦 Result ← ${name} ${out}`) + '\n');
|
|
160
|
+
(0, store_js_1.appendToolEvent)(sessionId, { name, resultPreview: out });
|
|
161
|
+
}
|
|
162
|
+
})().catch(() => { });
|
|
163
|
+
}
|
|
164
|
+
process.stdout.write(chalk_1.default.green('\nAssistant: '));
|
|
165
|
+
for await (const chunk of result.textStream) {
|
|
166
|
+
const s = String(chunk);
|
|
167
|
+
if (showReasoning) {
|
|
168
|
+
if (s.includes('```reasoning') || s.toLowerCase().includes('<thinking>') || /\[\s*reasoning\s*\]/i.test(s))
|
|
169
|
+
inReasoning = true;
|
|
170
|
+
if (s.includes('```') || s.toLowerCase().includes('</thinking>'))
|
|
171
|
+
inReasoning = false;
|
|
172
|
+
}
|
|
173
|
+
write(s);
|
|
174
|
+
}
|
|
175
|
+
process.stdout.write('\n');
|
|
176
|
+
lastAssistant = buffer;
|
|
177
|
+
messages.push({ role: 'assistant', content: buffer });
|
|
178
|
+
(0, store_js_1.appendMessage)(sessionId, { role: 'assistant', content: buffer, timestamp: new Date().toISOString() });
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
finally {
|
|
182
|
+
rl.close();
|
|
183
|
+
process.stdin.off('keypress', onKeypress);
|
|
184
|
+
if (process.stdin.isTTY)
|
|
185
|
+
process.stdin.setRawMode(false);
|
|
186
|
+
await close();
|
|
187
|
+
(0, store_js_1.endSession)(sessionId);
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
//# sourceMappingURL=interactive.js.map
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { SnowFlowConfig } from '../config/llm-config-loader';
|
|
2
|
+
import type { ProviderOptions } from '../llm/providers';
|
|
3
|
+
export interface AgentRunOptions extends ProviderOptions {
|
|
4
|
+
system?: string;
|
|
5
|
+
user: string;
|
|
6
|
+
mcp: SnowFlowConfig['mcp'];
|
|
7
|
+
maxSteps?: number;
|
|
8
|
+
showReasoning?: boolean;
|
|
9
|
+
saveOutputPath?: string;
|
|
10
|
+
}
|
|
11
|
+
export declare function runAgent(opts: AgentRunOptions): Promise<void>;
|
|
12
|
+
//# sourceMappingURL=session.d.ts.map
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// Agent session placeholder to keep build green.
|
|
3
|
+
// Will be replaced with streaming + tool-calling using the AI SDK.
|
|
4
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
5
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
6
|
+
};
|
|
7
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
8
|
+
exports.runAgent = runAgent;
|
|
9
|
+
const bridge_1 = require("../mcp/bridge");
|
|
10
|
+
const boxen_1 = __importDefault(require("boxen"));
|
|
11
|
+
const chalk_1 = __importDefault(require("chalk"));
|
|
12
|
+
const store_js_1 = require("../session/store.js");
|
|
13
|
+
async function runAgent(opts) {
|
|
14
|
+
const { mcp, system, user, maxSteps = 40, provider, model, baseURL, apiKeyEnv, showReasoning = true, saveOutputPath } = opts;
|
|
15
|
+
// Resolve model via provider registry
|
|
16
|
+
let llm;
|
|
17
|
+
try {
|
|
18
|
+
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
|
19
|
+
const prov = require('../llm/providers.js');
|
|
20
|
+
llm = prov.getModel({ provider, model, baseURL, apiKeyEnv });
|
|
21
|
+
}
|
|
22
|
+
catch (e) {
|
|
23
|
+
console.error('❌ LLM provider init error:', e instanceof Error ? e.message : String(e));
|
|
24
|
+
throw e;
|
|
25
|
+
}
|
|
26
|
+
// Load MCP tools (if AI SDK MCP client is available)
|
|
27
|
+
const { tools, close } = await (0, bridge_1.loadMCPTools)(mcp);
|
|
28
|
+
// Stream using AI SDK
|
|
29
|
+
try {
|
|
30
|
+
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
|
31
|
+
const { streamText } = require('ai');
|
|
32
|
+
const sessionId = (0, store_js_1.createSessionId)();
|
|
33
|
+
(0, store_js_1.startSession)({
|
|
34
|
+
id: sessionId,
|
|
35
|
+
startedAt: new Date().toISOString(),
|
|
36
|
+
objective: user,
|
|
37
|
+
provider: { id: String(provider), model: String(model), baseURL },
|
|
38
|
+
mcp: { cmd: mcp.cmd, args: mcp.args },
|
|
39
|
+
});
|
|
40
|
+
(0, store_js_1.appendMessage)(sessionId, { role: 'user', content: user, timestamp: new Date().toISOString() });
|
|
41
|
+
const result = await streamText({
|
|
42
|
+
model: llm,
|
|
43
|
+
system: system ?? 'You are Snow-Flow, a ServiceNow engineering agent. Be precise. Use tools when helpful.',
|
|
44
|
+
messages: [{ role: 'user', content: user }],
|
|
45
|
+
tools,
|
|
46
|
+
maxSteps,
|
|
47
|
+
});
|
|
48
|
+
let buffer = '';
|
|
49
|
+
let inReasoning = false;
|
|
50
|
+
const writeChunk = (s) => {
|
|
51
|
+
buffer += s;
|
|
52
|
+
const colored = inReasoning && showReasoning ? chalk_1.default.yellow.dim(s) : s;
|
|
53
|
+
process.stdout.write(colored);
|
|
54
|
+
};
|
|
55
|
+
// Optional: stream tool call events if provided by SDK
|
|
56
|
+
if (result.toolCallStream && typeof result.toolCallStream[Symbol.asyncIterator] === 'function') {
|
|
57
|
+
(async () => {
|
|
58
|
+
for await (const ev of result.toolCallStream) {
|
|
59
|
+
const name = ev?.toolName || ev?.name || 'tool';
|
|
60
|
+
const args = ev?.args ? JSON.stringify(ev.args).slice(0, 200) : '';
|
|
61
|
+
process.stdout.write('\n' + chalk_1.default.cyan(`🔧 Tool → ${name} ${args}`) + '\n');
|
|
62
|
+
(0, store_js_1.appendToolEvent)(sessionId, { name, argsPreview: args });
|
|
63
|
+
}
|
|
64
|
+
})().catch(() => { });
|
|
65
|
+
}
|
|
66
|
+
if (result.toolResultStream && typeof result.toolResultStream[Symbol.asyncIterator] === 'function') {
|
|
67
|
+
(async () => {
|
|
68
|
+
for await (const ev of result.toolResultStream) {
|
|
69
|
+
const name = ev?.toolName || ev?.name || 'tool';
|
|
70
|
+
const out = ev?.result ? JSON.stringify(ev.result).slice(0, 200) : '';
|
|
71
|
+
process.stdout.write(chalk_1.default.magenta(`📦 Result ← ${name} ${out}`) + '\n');
|
|
72
|
+
(0, store_js_1.appendToolEvent)(sessionId, { name, resultPreview: out });
|
|
73
|
+
}
|
|
74
|
+
})().catch(() => { });
|
|
75
|
+
}
|
|
76
|
+
for await (const chunk of result.textStream) {
|
|
77
|
+
const str = String(chunk);
|
|
78
|
+
// Heuristic: detect reasoning blocks (```reasoning, <thinking>, [reasoning])
|
|
79
|
+
if (showReasoning) {
|
|
80
|
+
if (str.includes('```reasoning') || str.toLowerCase().includes('<thinking>') || /\[\s*reasoning\s*\]/i.test(str))
|
|
81
|
+
inReasoning = true;
|
|
82
|
+
if (str.includes('```') || str.toLowerCase().includes('</thinking>'))
|
|
83
|
+
inReasoning = false;
|
|
84
|
+
}
|
|
85
|
+
writeChunk(str);
|
|
86
|
+
}
|
|
87
|
+
// Render a boxed summary if output is long
|
|
88
|
+
if (buffer.length > 4000) {
|
|
89
|
+
const preview = buffer.slice(0, 1200) + '…';
|
|
90
|
+
const box = (0, boxen_1.default)(preview, { padding: 1, borderColor: 'green', title: 'Preview (truncated)', titleAlignment: 'center' });
|
|
91
|
+
process.stdout.write('\n' + box + '\n');
|
|
92
|
+
process.stdout.write(chalk_1.default.gray(`Full length: ${buffer.length} chars`) + '\n');
|
|
93
|
+
}
|
|
94
|
+
if (saveOutputPath) {
|
|
95
|
+
const fs = require('fs');
|
|
96
|
+
fs.writeFileSync(saveOutputPath, buffer, 'utf8');
|
|
97
|
+
process.stdout.write(chalk_1.default.gray(`Saved full output to ${saveOutputPath}`) + '\n');
|
|
98
|
+
}
|
|
99
|
+
(0, store_js_1.appendMessage)(sessionId, { role: 'assistant', content: buffer, timestamp: new Date().toISOString() });
|
|
100
|
+
(0, store_js_1.endSession)(sessionId);
|
|
101
|
+
}
|
|
102
|
+
finally {
|
|
103
|
+
await close();
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
//# sourceMappingURL=session.js.map
|
package/dist/cli/auth.js
ADDED
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.registerAuthCommands = registerAuthCommands;
|
|
7
|
+
const inquirer_1 = __importDefault(require("inquirer"));
|
|
8
|
+
const chalk_1 = __importDefault(require("chalk"));
|
|
9
|
+
const keys_js_1 = require("../llm/keys.js");
|
|
10
|
+
function registerAuthCommands(program) {
|
|
11
|
+
const auth = program.command('auth').description('Manage provider API credentials for Snow-Flow');
|
|
12
|
+
auth
|
|
13
|
+
.command('login')
|
|
14
|
+
.description('Interactive login to store API keys for a provider')
|
|
15
|
+
.option('--provider <provider>', 'Provider id (openai|google|openrouter|openai-compatible|ollama)')
|
|
16
|
+
.action(async (opts) => {
|
|
17
|
+
const p = opts.provider || (await inquirer_1.default.prompt([{ name: 'provider', message: 'Provider', type: 'list', choices: ['openai', 'google', 'openrouter', 'openai-compatible', 'ollama'] }])).provider;
|
|
18
|
+
const existing = (0, keys_js_1.getApiKey)(p);
|
|
19
|
+
const { apiKey } = await inquirer_1.default.prompt([{ name: 'apiKey', message: `API key for ${p}${existing ? ' (leave blank to keep existing)' : ''}`, type: 'password', mask: '*' }]);
|
|
20
|
+
if (!apiKey && existing) {
|
|
21
|
+
console.log(chalk_1.default.yellow('Keeping existing key.'));
|
|
22
|
+
return;
|
|
23
|
+
}
|
|
24
|
+
if (!apiKey) {
|
|
25
|
+
console.error(chalk_1.default.red('No key entered. Aborting.'));
|
|
26
|
+
process.exit(1);
|
|
27
|
+
}
|
|
28
|
+
(0, keys_js_1.setApiKey)(p, apiKey);
|
|
29
|
+
console.log(chalk_1.default.green(`Saved API key for ${p}.`));
|
|
30
|
+
});
|
|
31
|
+
auth
|
|
32
|
+
.command('set-key')
|
|
33
|
+
.description('Set API key non-interactively')
|
|
34
|
+
.requiredOption('--provider <provider>', 'Provider id')
|
|
35
|
+
.requiredOption('--api-key <key>', 'API key value')
|
|
36
|
+
.action((opts) => {
|
|
37
|
+
(0, keys_js_1.setApiKey)(opts.provider, opts.apiKey);
|
|
38
|
+
console.log(chalk_1.default.green(`Saved API key for ${opts.provider}.`));
|
|
39
|
+
});
|
|
40
|
+
auth
|
|
41
|
+
.command('show')
|
|
42
|
+
.description('Show configured providers (keys partially masked)')
|
|
43
|
+
.action(() => {
|
|
44
|
+
const entries = (0, keys_js_1.listKeys)();
|
|
45
|
+
for (const [p, v] of Object.entries(entries)) {
|
|
46
|
+
const mask = v ? `${v.substring(0, 4)}…${v.substring(v.length - 4)}` : '—';
|
|
47
|
+
console.log(`${p.padEnd(18)} ${mask}`);
|
|
48
|
+
}
|
|
49
|
+
});
|
|
50
|
+
auth
|
|
51
|
+
.command('clear')
|
|
52
|
+
.description('Clear a stored API key')
|
|
53
|
+
.requiredOption('--provider <provider>', 'Provider id')
|
|
54
|
+
.action((opts) => {
|
|
55
|
+
(0, keys_js_1.clearApiKey)(opts.provider);
|
|
56
|
+
console.log(chalk_1.default.yellow(`Cleared API key for ${opts.provider}.`));
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
//# sourceMappingURL=auth.js.map
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.registerSessionCommands = registerSessionCommands;
|
|
7
|
+
const chalk_1 = __importDefault(require("chalk"));
|
|
8
|
+
const store_js_1 = require("../session/store.js");
|
|
9
|
+
function registerSessionCommands(program) {
|
|
10
|
+
const sess = program.command('session').description('Manage and inspect Snow-Flow sessions');
|
|
11
|
+
sess
|
|
12
|
+
.command('list')
|
|
13
|
+
.description('List recent sessions')
|
|
14
|
+
.action(() => {
|
|
15
|
+
const rows = (0, store_js_1.listSessions)().slice(0, 30);
|
|
16
|
+
if (!rows.length)
|
|
17
|
+
return console.log('No sessions yet.');
|
|
18
|
+
for (const r of rows) {
|
|
19
|
+
console.log(`${chalk_1.default.gray(r.startedAt)} ${chalk_1.default.cyan(r.id)} ${r.objective}`);
|
|
20
|
+
}
|
|
21
|
+
});
|
|
22
|
+
sess
|
|
23
|
+
.command('show <id>')
|
|
24
|
+
.description('Show session details')
|
|
25
|
+
.action((id) => {
|
|
26
|
+
const rec = (0, store_js_1.readSession)(id);
|
|
27
|
+
if (!rec)
|
|
28
|
+
return console.error(chalk_1.default.red('Session not found.'));
|
|
29
|
+
console.log(chalk_1.default.cyan(`Session ${rec.id}`));
|
|
30
|
+
console.log(`${chalk_1.default.gray(rec.startedAt)} → ${chalk_1.default.gray(rec.endedAt ?? '…')}`);
|
|
31
|
+
console.log('Objective:', rec.objective);
|
|
32
|
+
console.log('Provider:', `${rec.provider.id} ${rec.provider.model}`);
|
|
33
|
+
console.log('MCP:', `${rec.mcp.cmd} ${(rec.mcp.args || []).join(' ')}`);
|
|
34
|
+
console.log('\nMessages:');
|
|
35
|
+
for (const m of rec.messages) {
|
|
36
|
+
console.log(`- ${chalk_1.default.yellow(m.role)} ${chalk_1.default.gray(m.timestamp)}\n ${m.content.slice(0, 400)}${m.content.length > 400 ? '…' : ''}`);
|
|
37
|
+
}
|
|
38
|
+
if (rec.toolEvents?.length) {
|
|
39
|
+
console.log('\nTool events:');
|
|
40
|
+
for (const ev of rec.toolEvents) {
|
|
41
|
+
console.log(` 🔧 ${ev.name} ${chalk_1.default.gray(ev.when)} ${ev.argsPreview ? ('args:' + ev.argsPreview) : ''} ${ev.resultPreview ? ('res:' + ev.resultPreview) : ''}`);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
//# sourceMappingURL=session.js.map
|
package/dist/cli.js
CHANGED
|
@@ -53,6 +53,11 @@ const agent_detector_js_1 = require("./utils/agent-detector.js");
|
|
|
53
53
|
const version_js_1 = require("./version.js");
|
|
54
54
|
const logger_js_1 = require("./utils/logger.js");
|
|
55
55
|
const chalk_1 = __importDefault(require("chalk"));
|
|
56
|
+
// New provider-agnostic engine imports (compile-safe placeholders)
|
|
57
|
+
const llm_config_loader_js_1 = require("./config/llm-config-loader.js");
|
|
58
|
+
const interactive_js_1 = require("./agent/interactive.js");
|
|
59
|
+
const auth_js_1 = require("./cli/auth.js");
|
|
60
|
+
const session_js_1 = require("./cli/session.js");
|
|
56
61
|
// Load environment variables
|
|
57
62
|
dotenv_1.default.config();
|
|
58
63
|
// Create CLI logger instance
|
|
@@ -62,6 +67,10 @@ program
|
|
|
62
67
|
.name('snow-flow')
|
|
63
68
|
.description('ServiceNow Multi-Agent Development Framework')
|
|
64
69
|
.version(version_js_1.VERSION);
|
|
70
|
+
// Register auth commands (API key management)
|
|
71
|
+
(0, auth_js_1.registerAuthCommands)(program);
|
|
72
|
+
// Register session inspection commands
|
|
73
|
+
(0, session_js_1.registerSessionCommands)(program);
|
|
65
74
|
// Flow deprecation handler - check for flow-related commands
|
|
66
75
|
function checkFlowDeprecation(command, objective) {
|
|
67
76
|
const flowKeywords = ['flow', 'create-flow', 'xml-flow', 'flow-designer'];
|
|
@@ -90,6 +99,18 @@ function checkFlowDeprecation(command, objective) {
|
|
|
90
99
|
program
|
|
91
100
|
.command('swarm <objective>')
|
|
92
101
|
.description('Execute multi-agent orchestration for a ServiceNow task - één command voor alles!')
|
|
102
|
+
// New engine selector: defaults to auto (uses config-driven agent when available)
|
|
103
|
+
.option('--engine <engine>', 'Execution engine (auto|agent|claude)', 'auto')
|
|
104
|
+
.option('--config <path>', 'Path to snowflow.config file')
|
|
105
|
+
.option('--show-reasoning', 'Show LLM reasoning in a different color (default)', true)
|
|
106
|
+
.option('--no-show-reasoning', 'Hide LLM reasoning blocks')
|
|
107
|
+
.option('--save-output <path>', 'Save full assistant output to a file')
|
|
108
|
+
.option('--resume <sessionId>', 'Resume an existing interactive session')
|
|
109
|
+
// Provider overrides (optional, config-driven by default)
|
|
110
|
+
.option('--provider <provider>', 'LLM provider override')
|
|
111
|
+
.option('--model <model>', 'Model override')
|
|
112
|
+
.option('--base-url <url>', 'Base URL override for openai-compatible or gateways')
|
|
113
|
+
.option('--api-key-env <name>', 'Use specific API key env var')
|
|
93
114
|
.option('--strategy <strategy>', 'Execution strategy (development, _analysis, research)', 'development')
|
|
94
115
|
.option('--mode <mode>', 'Coordination mode (hierarchical, mesh, distributed)', 'hierarchical')
|
|
95
116
|
.option('--max-agents <number>', 'Maximum number of agents', '5')
|
|
@@ -266,6 +287,66 @@ program
|
|
|
266
287
|
cliLogger.info(`🤖 Autonomous Systems: ❌ All Disabled`);
|
|
267
288
|
}
|
|
268
289
|
}
|
|
290
|
+
// Detect agent engine via config (provider-agnostic) when requested or available
|
|
291
|
+
const shouldUseAgent = (() => {
|
|
292
|
+
if (options.engine === 'agent')
|
|
293
|
+
return true;
|
|
294
|
+
if (options.engine === 'claude')
|
|
295
|
+
return false;
|
|
296
|
+
// auto: use agent when config file is present and valid
|
|
297
|
+
const cfg = (0, llm_config_loader_js_1.loadSnowFlowConfig)({
|
|
298
|
+
configPath: options.config,
|
|
299
|
+
overrides: {
|
|
300
|
+
llm: {
|
|
301
|
+
provider: options.provider || undefined,
|
|
302
|
+
model: options.model || undefined,
|
|
303
|
+
baseURL: options.baseUrl || options.baseURL || undefined,
|
|
304
|
+
apiKeyEnv: options.apiKeyEnv || undefined,
|
|
305
|
+
},
|
|
306
|
+
},
|
|
307
|
+
});
|
|
308
|
+
return Boolean(cfg && cfg.llm && cfg.llm.provider && cfg.llm.model);
|
|
309
|
+
})();
|
|
310
|
+
if (shouldUseAgent) {
|
|
311
|
+
const cfg = (0, llm_config_loader_js_1.loadSnowFlowConfig)({
|
|
312
|
+
configPath: options.config,
|
|
313
|
+
overrides: {
|
|
314
|
+
llm: {
|
|
315
|
+
provider: options.provider || undefined,
|
|
316
|
+
model: options.model || undefined,
|
|
317
|
+
baseURL: options.baseUrl || options.baseURL || undefined,
|
|
318
|
+
apiKeyEnv: options.apiKeyEnv || undefined,
|
|
319
|
+
},
|
|
320
|
+
},
|
|
321
|
+
});
|
|
322
|
+
if (!cfg) {
|
|
323
|
+
cliLogger.error('❌ Geen snowflow.config.(json|js|cjs) gevonden. Voeg config toe of gebruik --engine claude.');
|
|
324
|
+
process.exit(1);
|
|
325
|
+
}
|
|
326
|
+
// Basic validation for MVP
|
|
327
|
+
if (!cfg.llm?.provider || !cfg.llm?.model) {
|
|
328
|
+
cliLogger.error('❌ Config mist llm.provider of llm.model');
|
|
329
|
+
process.exit(1);
|
|
330
|
+
}
|
|
331
|
+
cliLogger.info('\n🤖 Using provider-agnostic Snow-Flow agent (interactive)');
|
|
332
|
+
try {
|
|
333
|
+
await (0, interactive_js_1.runInteractive)({
|
|
334
|
+
provider: cfg.llm.provider,
|
|
335
|
+
model: String(cfg.llm.model),
|
|
336
|
+
baseURL: cfg.llm.baseURL,
|
|
337
|
+
apiKeyEnv: cfg.llm.apiKeyEnv,
|
|
338
|
+
mcp: cfg.mcp,
|
|
339
|
+
system: cfg.agent?.system,
|
|
340
|
+
maxSteps: cfg.agent?.maxSteps ?? 40,
|
|
341
|
+
showReasoning: options.showReasoning !== false,
|
|
342
|
+
resumeId: options.resume || undefined,
|
|
343
|
+
});
|
|
344
|
+
}
|
|
345
|
+
catch (e) {
|
|
346
|
+
cliLogger.error('❌ Interactive agent error:', e instanceof Error ? e.message : String(e));
|
|
347
|
+
}
|
|
348
|
+
return; // end here; skip legacy Claude path
|
|
349
|
+
}
|
|
269
350
|
// Analyze the objective using intelligent agent detection
|
|
270
351
|
const taskAnalysis = analyzeObjective(objective, parseInt(options.maxAgents));
|
|
271
352
|
// Debug logging to understand task type detection
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
export type ProviderId = 'openai' | 'google' | 'openrouter' | 'openai-compatible' | 'ollama' | 'anthropic';
|
|
2
|
+
export interface SnowFlowConfig {
|
|
3
|
+
profile?: string;
|
|
4
|
+
mcp: {
|
|
5
|
+
cmd: string;
|
|
6
|
+
args?: string[];
|
|
7
|
+
env?: Record<string, string>;
|
|
8
|
+
};
|
|
9
|
+
llm: {
|
|
10
|
+
provider: ProviderId;
|
|
11
|
+
model: string;
|
|
12
|
+
baseURL?: string;
|
|
13
|
+
apiKeyEnv?: string;
|
|
14
|
+
extraBody?: Record<string, unknown>;
|
|
15
|
+
};
|
|
16
|
+
agent?: {
|
|
17
|
+
system?: string;
|
|
18
|
+
maxSteps?: number;
|
|
19
|
+
};
|
|
20
|
+
logging?: {
|
|
21
|
+
level?: 'info' | 'debug' | 'trace';
|
|
22
|
+
};
|
|
23
|
+
profiles?: Record<string, Partial<SnowFlowConfig>>;
|
|
24
|
+
}
|
|
25
|
+
export declare function findConfigPath(customPath?: string): string | undefined;
|
|
26
|
+
export declare function loadSnowFlowConfig(opts?: {
|
|
27
|
+
configPath?: string;
|
|
28
|
+
profile?: string;
|
|
29
|
+
overrides?: Partial<SnowFlowConfig>;
|
|
30
|
+
}): SnowFlowConfig | undefined;
|
|
31
|
+
//# sourceMappingURL=llm-config-loader.d.ts.map
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.findConfigPath = findConfigPath;
|
|
7
|
+
exports.loadSnowFlowConfig = loadSnowFlowConfig;
|
|
8
|
+
const fs_1 = __importDefault(require("fs"));
|
|
9
|
+
const path_1 = __importDefault(require("path"));
|
|
10
|
+
function tryLoadModule(modulePath) {
|
|
11
|
+
// CommonJS require for .js/.cjs; JSON via fs; YAML/TS not supported in MVP
|
|
12
|
+
const ext = path_1.default.extname(modulePath).toLowerCase();
|
|
13
|
+
if (ext === '.json') {
|
|
14
|
+
const raw = fs_1.default.readFileSync(modulePath, 'utf8');
|
|
15
|
+
return JSON.parse(raw);
|
|
16
|
+
}
|
|
17
|
+
if (ext === '.js' || ext === '.cjs') {
|
|
18
|
+
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
|
19
|
+
const mod = require(modulePath);
|
|
20
|
+
return mod?.default ?? mod;
|
|
21
|
+
}
|
|
22
|
+
if (ext === '.yaml' || ext === '.yml') {
|
|
23
|
+
throw new Error(`YAML config detected (${ext}). Install 'yaml' and wire parsing, or use JSON/JS/CJS now.`);
|
|
24
|
+
}
|
|
25
|
+
if (ext === '.ts') {
|
|
26
|
+
throw new Error(`TypeScript config detected (.ts). Use JS/CJS/JSON or set up ts-node/tsx runtime.`);
|
|
27
|
+
}
|
|
28
|
+
if (ext === '.mjs') {
|
|
29
|
+
throw new Error(`.mjs config not supported in MVP. Convert to .js/.cjs or use JSON.`);
|
|
30
|
+
}
|
|
31
|
+
throw new Error(`Unsupported config extension: ${ext}`);
|
|
32
|
+
}
|
|
33
|
+
function findConfigPath(customPath) {
|
|
34
|
+
const fromFlag = customPath?.trim();
|
|
35
|
+
if (fromFlag && fs_1.default.existsSync(fromFlag))
|
|
36
|
+
return path_1.default.resolve(fromFlag);
|
|
37
|
+
const fromEnv = process.env.SNOWFLOW_CONFIG?.trim();
|
|
38
|
+
if (fromEnv && fs_1.default.existsSync(fromEnv))
|
|
39
|
+
return path_1.default.resolve(fromEnv);
|
|
40
|
+
const candidates = [
|
|
41
|
+
'snowflow.config.json',
|
|
42
|
+
'snowflow.config.js',
|
|
43
|
+
'snowflow.config.cjs',
|
|
44
|
+
// reserved for later: yaml/yml/mjs/ts
|
|
45
|
+
];
|
|
46
|
+
for (const name of candidates) {
|
|
47
|
+
const p = path_1.default.resolve(process.cwd(), name);
|
|
48
|
+
if (fs_1.default.existsSync(p))
|
|
49
|
+
return p;
|
|
50
|
+
}
|
|
51
|
+
return undefined;
|
|
52
|
+
}
|
|
53
|
+
function loadSnowFlowConfig(opts) {
|
|
54
|
+
const configPath = findConfigPath(opts?.configPath);
|
|
55
|
+
if (!configPath)
|
|
56
|
+
return undefined;
|
|
57
|
+
const raw = tryLoadModule(configPath);
|
|
58
|
+
const base = {
|
|
59
|
+
profile: raw.profile || 'default',
|
|
60
|
+
mcp: raw.mcp || { cmd: 'node', args: ['dist/mcp/index.js'] },
|
|
61
|
+
llm: raw.llm,
|
|
62
|
+
agent: raw.agent || {},
|
|
63
|
+
logging: raw.logging || { level: 'info' },
|
|
64
|
+
profiles: raw.profiles || {},
|
|
65
|
+
};
|
|
66
|
+
const activeProfile = (opts?.profile || process.env.SNOWFLOW_PROFILE || base.profile || 'default');
|
|
67
|
+
const profileOverrides = (base.profiles && base.profiles[activeProfile]) || {};
|
|
68
|
+
// shallow merge base + profile + overrides
|
|
69
|
+
const merged = {
|
|
70
|
+
...base,
|
|
71
|
+
...profileOverrides,
|
|
72
|
+
...(opts?.overrides || {}),
|
|
73
|
+
mcp: { ...(base.mcp || {}), ...(profileOverrides.mcp || {}), ...(opts?.overrides?.mcp || {}) },
|
|
74
|
+
llm: { ...(base.llm || {}), ...(profileOverrides.llm || {}), ...(opts?.overrides?.llm || {}) },
|
|
75
|
+
agent: { ...(base.agent || {}), ...(profileOverrides.agent || {}), ...(opts?.overrides?.agent || {}) },
|
|
76
|
+
logging: { ...(base.logging || {}), ...(profileOverrides.logging || {}), ...(opts?.overrides?.logging || {}) },
|
|
77
|
+
};
|
|
78
|
+
return merged;
|
|
79
|
+
}
|
|
80
|
+
//# sourceMappingURL=llm-config-loader.js.map
|
package/dist/dynamic-version.js
CHANGED
|
@@ -36,7 +36,7 @@ function getDynamicVersion() {
|
|
|
36
36
|
console.warn('Warning: Could not read version from package.json:', error);
|
|
37
37
|
}
|
|
38
38
|
// Fallback to hardcoded version
|
|
39
|
-
return '
|
|
39
|
+
return '4.0.0-final-claude';
|
|
40
40
|
}
|
|
41
41
|
// Export a constant that uses the dynamic version
|
|
42
42
|
exports.VERSION = getDynamicVersion();
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export declare function setApiKey(provider: string, value: string): void;
|
|
2
|
+
export declare function getApiKey(provider: string): string | undefined;
|
|
3
|
+
export declare function clearApiKey(provider: string): void;
|
|
4
|
+
export declare function listKeys(): Record<string, string | undefined>;
|
|
5
|
+
//# sourceMappingURL=keys.d.ts.map
|
package/dist/llm/keys.js
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.setApiKey = setApiKey;
|
|
7
|
+
exports.getApiKey = getApiKey;
|
|
8
|
+
exports.clearApiKey = clearApiKey;
|
|
9
|
+
exports.listKeys = listKeys;
|
|
10
|
+
const conf_1 = __importDefault(require("conf"));
|
|
11
|
+
// Avoid generic type for broader compatibility with shimmed types
|
|
12
|
+
const store = new conf_1.default({ projectName: 'snow-flow' });
|
|
13
|
+
function setApiKey(provider, value) {
|
|
14
|
+
store.set(`keys.${provider}`, value);
|
|
15
|
+
}
|
|
16
|
+
function getApiKey(provider) {
|
|
17
|
+
return store.get(`keys.${provider}`);
|
|
18
|
+
}
|
|
19
|
+
function clearApiKey(provider) {
|
|
20
|
+
store.delete(`keys.${provider}`);
|
|
21
|
+
}
|
|
22
|
+
function listKeys() {
|
|
23
|
+
const providers = ['openai', 'google', 'openrouter', 'openai-compatible', 'ollama'];
|
|
24
|
+
const out = {};
|
|
25
|
+
for (const p of providers)
|
|
26
|
+
out[p] = getApiKey(p);
|
|
27
|
+
return out;
|
|
28
|
+
}
|
|
29
|
+
//# sourceMappingURL=keys.js.map
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { SnowFlowConfig } from '../config/llm-config-loader';
|
|
2
|
+
export type ProviderId = SnowFlowConfig['llm']['provider'];
|
|
3
|
+
export interface ProviderOptions {
|
|
4
|
+
provider: ProviderId;
|
|
5
|
+
model: string;
|
|
6
|
+
baseURL?: string;
|
|
7
|
+
apiKeyEnv?: string;
|
|
8
|
+
extraBody?: Record<string, unknown>;
|
|
9
|
+
}
|
|
10
|
+
export declare function getModel(opts: ProviderOptions): unknown;
|
|
11
|
+
//# sourceMappingURL=providers.d.ts.map
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// Compile-safe placeholder registry. Real providers will be wired via AI SDK in a follow-up step.
|
|
3
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
|
+
exports.getModel = getModel;
|
|
5
|
+
const keys_js_1 = require("./keys.js");
|
|
6
|
+
function getModel(opts) {
|
|
7
|
+
const { provider, model, baseURL, apiKeyEnv, extraBody } = opts;
|
|
8
|
+
const requireOrThrow = (name) => {
|
|
9
|
+
try {
|
|
10
|
+
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
|
11
|
+
return require(name);
|
|
12
|
+
}
|
|
13
|
+
catch (err) {
|
|
14
|
+
const hint = `Missing dependency ${name}. Run: npm i ai @ai-sdk/openai @ai-sdk/google @openrouter/ai-sdk-provider`;
|
|
15
|
+
throw new Error(hint);
|
|
16
|
+
}
|
|
17
|
+
};
|
|
18
|
+
switch (provider) {
|
|
19
|
+
case 'anthropic': {
|
|
20
|
+
// Prefer AI SDK anthropic provider if installed; otherwise instruct
|
|
21
|
+
try {
|
|
22
|
+
// Dynamic require to avoid hard dep
|
|
23
|
+
const anthropic = require('@ai-sdk/anthropic');
|
|
24
|
+
const key = process.env[apiKeyEnv || 'ANTHROPIC_API_KEY'] || (0, keys_js_1.getApiKey)('anthropic');
|
|
25
|
+
if (!key)
|
|
26
|
+
throw new Error('Missing ANTHROPIC_API_KEY');
|
|
27
|
+
return anthropic.anthropic({ apiKey: key, baseURL }).languageModel(model);
|
|
28
|
+
}
|
|
29
|
+
catch (e) {
|
|
30
|
+
throw new Error('Anthropic provider not available. Install @ai-sdk/anthropic or use OpenRouter with an Anthropic model.');
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
case 'openai': {
|
|
34
|
+
const { openai } = requireOrThrow('@ai-sdk/openai');
|
|
35
|
+
const apiKey = process.env[apiKeyEnv || 'OPENAI_API_KEY'] || (0, keys_js_1.getApiKey)('openai');
|
|
36
|
+
if (!apiKey)
|
|
37
|
+
throw new Error('Missing OPENAI_API_KEY');
|
|
38
|
+
return openai({ apiKey, baseURL }).languageModel(model);
|
|
39
|
+
}
|
|
40
|
+
case 'google': {
|
|
41
|
+
const { google } = requireOrThrow('@ai-sdk/google');
|
|
42
|
+
const apiKey = process.env[apiKeyEnv || 'GOOGLE_API_KEY']
|
|
43
|
+
|| process.env['GOOGLE_GENERATIVE_AI_API_KEY']
|
|
44
|
+
|| (0, keys_js_1.getApiKey)('google');
|
|
45
|
+
if (!apiKey)
|
|
46
|
+
throw new Error('Missing GOOGLE_API_KEY or GOOGLE_GENERATIVE_AI_API_KEY');
|
|
47
|
+
return google({ apiKey, baseURL }).languageModel(model);
|
|
48
|
+
}
|
|
49
|
+
case 'openrouter': {
|
|
50
|
+
const { createOpenRouter } = requireOrThrow('@openrouter/ai-sdk-provider');
|
|
51
|
+
const apiKey = process.env[apiKeyEnv || 'OPENROUTER_API_KEY'] || (0, keys_js_1.getApiKey)('openrouter');
|
|
52
|
+
if (!apiKey)
|
|
53
|
+
throw new Error('Missing OPENROUTER_API_KEY');
|
|
54
|
+
const or = createOpenRouter({ apiKey, baseURL, extraBody });
|
|
55
|
+
return or(model);
|
|
56
|
+
}
|
|
57
|
+
case 'openai-compatible': {
|
|
58
|
+
const { openai } = requireOrThrow('@ai-sdk/openai');
|
|
59
|
+
const keyName = apiKeyEnv || 'OPENAI_COMPAT_API_KEY';
|
|
60
|
+
const apiKey = process.env[keyName] || (0, keys_js_1.getApiKey)('openai-compatible');
|
|
61
|
+
if (!baseURL)
|
|
62
|
+
throw new Error('openai-compatible requires baseURL');
|
|
63
|
+
if (!apiKey)
|
|
64
|
+
throw new Error(`Missing ${keyName}`);
|
|
65
|
+
return openai({ apiKey, baseURL }).languageModel(model);
|
|
66
|
+
}
|
|
67
|
+
case 'ollama': {
|
|
68
|
+
const { openai } = requireOrThrow('@ai-sdk/openai');
|
|
69
|
+
const keyName = apiKeyEnv || 'OLLAMA_API_KEY';
|
|
70
|
+
const apiKey = process.env[keyName] || (0, keys_js_1.getApiKey)('ollama');
|
|
71
|
+
if (!baseURL)
|
|
72
|
+
throw new Error('ollama requires baseURL (e.g., http://localhost:11434/v1)');
|
|
73
|
+
return openai({ apiKey, baseURL }).languageModel(model);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
//# sourceMappingURL=providers.js.map
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// Minimal MCP bridge placeholder. We will hook this into AI SDK tools in a next step.
|
|
3
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
|
+
exports.loadMCPTools = loadMCPTools;
|
|
5
|
+
async function loadMCPTools(start) {
|
|
6
|
+
// Prefer using AI SDK's experimental MCP client to yield ready-to-use Tool[]
|
|
7
|
+
try {
|
|
8
|
+
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
|
9
|
+
const { experimental_createMCPClient } = require('ai');
|
|
10
|
+
// Use SDK-provided stdio transport
|
|
11
|
+
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
|
12
|
+
const { StdioClientTransport } = require('@modelcontextprotocol/sdk/client/stdio');
|
|
13
|
+
const client = await experimental_createMCPClient({
|
|
14
|
+
name: 'snow-flow',
|
|
15
|
+
transport: new StdioClientTransport({
|
|
16
|
+
command: start.cmd,
|
|
17
|
+
args: start.args ?? [],
|
|
18
|
+
env: start.env ?? {},
|
|
19
|
+
}),
|
|
20
|
+
});
|
|
21
|
+
const tools = await client.tools();
|
|
22
|
+
return { tools, close: client.close };
|
|
23
|
+
}
|
|
24
|
+
catch (err) {
|
|
25
|
+
// Fallback: no AI SDK available, return empty tools and noop close but with a hint.
|
|
26
|
+
const hint = 'AI SDK MCP bridge not available. Install "ai" or verify version to enable MCP tools.';
|
|
27
|
+
console.warn(`[snow-flow] ${hint}`);
|
|
28
|
+
return { tools: [], close: async () => { } };
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
//# sourceMappingURL=bridge.js.map
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
export interface SessionMessage {
|
|
2
|
+
role: 'system' | 'user' | 'assistant' | 'tool';
|
|
3
|
+
content: string;
|
|
4
|
+
timestamp: string;
|
|
5
|
+
meta?: Record<string, unknown>;
|
|
6
|
+
}
|
|
7
|
+
export interface SessionRecord {
|
|
8
|
+
id: string;
|
|
9
|
+
startedAt: string;
|
|
10
|
+
endedAt?: string;
|
|
11
|
+
objective: string;
|
|
12
|
+
provider: {
|
|
13
|
+
id: string;
|
|
14
|
+
model: string;
|
|
15
|
+
baseURL?: string;
|
|
16
|
+
};
|
|
17
|
+
mcp: {
|
|
18
|
+
cmd: string;
|
|
19
|
+
args?: string[];
|
|
20
|
+
};
|
|
21
|
+
messages: SessionMessage[];
|
|
22
|
+
toolEvents?: {
|
|
23
|
+
name: string;
|
|
24
|
+
when: string;
|
|
25
|
+
argsPreview?: string;
|
|
26
|
+
resultPreview?: string;
|
|
27
|
+
}[];
|
|
28
|
+
summary?: string;
|
|
29
|
+
}
|
|
30
|
+
export declare function createSessionId(): string;
|
|
31
|
+
export declare function startSession(rec: Omit<SessionRecord, 'messages' | 'toolEvents'> & {
|
|
32
|
+
messages?: SessionMessage[];
|
|
33
|
+
}): SessionRecord;
|
|
34
|
+
export declare function readSession(id: string): SessionRecord | undefined;
|
|
35
|
+
export declare function listSessions(): {
|
|
36
|
+
id: string;
|
|
37
|
+
startedAt: string;
|
|
38
|
+
objective: string;
|
|
39
|
+
}[];
|
|
40
|
+
export declare function appendMessage(id: string, msg: SessionMessage): void;
|
|
41
|
+
export declare function appendToolEvent(id: string, ev: {
|
|
42
|
+
name: string;
|
|
43
|
+
argsPreview?: string;
|
|
44
|
+
resultPreview?: string;
|
|
45
|
+
}): void;
|
|
46
|
+
export declare function endSession(id: string, summary?: string): void;
|
|
47
|
+
//# sourceMappingURL=store.d.ts.map
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.createSessionId = createSessionId;
|
|
7
|
+
exports.startSession = startSession;
|
|
8
|
+
exports.readSession = readSession;
|
|
9
|
+
exports.listSessions = listSessions;
|
|
10
|
+
exports.appendMessage = appendMessage;
|
|
11
|
+
exports.appendToolEvent = appendToolEvent;
|
|
12
|
+
exports.endSession = endSession;
|
|
13
|
+
const fs_1 = __importDefault(require("fs"));
|
|
14
|
+
const os_1 = __importDefault(require("os"));
|
|
15
|
+
const path_1 = __importDefault(require("path"));
|
|
16
|
+
function ensureDir(dir) {
|
|
17
|
+
if (!fs_1.default.existsSync(dir))
|
|
18
|
+
fs_1.default.mkdirSync(dir, { recursive: true });
|
|
19
|
+
}
|
|
20
|
+
function sessionsDir() {
|
|
21
|
+
const dir = path_1.default.join(os_1.default.homedir(), '.snow-flow', 'sessions');
|
|
22
|
+
ensureDir(dir);
|
|
23
|
+
return dir;
|
|
24
|
+
}
|
|
25
|
+
function createSessionId() {
|
|
26
|
+
return `sess_${Date.now().toString(36)}_${Math.random().toString(36).slice(2, 8)}`;
|
|
27
|
+
}
|
|
28
|
+
function sessionPath(id) {
|
|
29
|
+
return path_1.default.join(sessionsDir(), `${id}.json`);
|
|
30
|
+
}
|
|
31
|
+
function startSession(rec) {
|
|
32
|
+
const full = { ...rec, messages: rec.messages ?? [], toolEvents: [] };
|
|
33
|
+
fs_1.default.writeFileSync(sessionPath(rec.id), JSON.stringify(full, null, 2), 'utf8');
|
|
34
|
+
return full;
|
|
35
|
+
}
|
|
36
|
+
function readSession(id) {
|
|
37
|
+
const p = sessionPath(id);
|
|
38
|
+
if (!fs_1.default.existsSync(p))
|
|
39
|
+
return undefined;
|
|
40
|
+
return JSON.parse(fs_1.default.readFileSync(p, 'utf8'));
|
|
41
|
+
}
|
|
42
|
+
function listSessions() {
|
|
43
|
+
const dir = sessionsDir();
|
|
44
|
+
const files = fs_1.default.readdirSync(dir).filter(f => f.endsWith('.json'));
|
|
45
|
+
return files.map(f => {
|
|
46
|
+
const rec = JSON.parse(fs_1.default.readFileSync(path_1.default.join(dir, f), 'utf8'));
|
|
47
|
+
return { id: rec.id, startedAt: rec.startedAt, objective: rec.objective };
|
|
48
|
+
}).sort((a, b) => (a.startedAt < b.startedAt ? 1 : -1));
|
|
49
|
+
}
|
|
50
|
+
function appendMessage(id, msg) {
|
|
51
|
+
const rec = readSession(id);
|
|
52
|
+
if (!rec)
|
|
53
|
+
return;
|
|
54
|
+
rec.messages.push(msg);
|
|
55
|
+
fs_1.default.writeFileSync(sessionPath(id), JSON.stringify(rec, null, 2), 'utf8');
|
|
56
|
+
}
|
|
57
|
+
function appendToolEvent(id, ev) {
|
|
58
|
+
const rec = readSession(id);
|
|
59
|
+
if (!rec)
|
|
60
|
+
return;
|
|
61
|
+
const item = { name: ev.name, when: new Date().toISOString(), argsPreview: ev.argsPreview, resultPreview: ev.resultPreview };
|
|
62
|
+
(rec.toolEvents = rec.toolEvents || []).push(item);
|
|
63
|
+
fs_1.default.writeFileSync(sessionPath(id), JSON.stringify(rec, null, 2), 'utf8');
|
|
64
|
+
}
|
|
65
|
+
function endSession(id, summary) {
|
|
66
|
+
const rec = readSession(id);
|
|
67
|
+
if (!rec)
|
|
68
|
+
return;
|
|
69
|
+
rec.endedAt = new Date().toISOString();
|
|
70
|
+
if (summary)
|
|
71
|
+
rec.summary = summary;
|
|
72
|
+
fs_1.default.writeFileSync(sessionPath(id), JSON.stringify(rec, null, 2), 'utf8');
|
|
73
|
+
}
|
|
74
|
+
//# sourceMappingURL=store.js.map
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "snow-flow",
|
|
3
|
-
"version": "
|
|
4
|
-
"description": "
|
|
3
|
+
"version": "4.0.0-final-claude",
|
|
4
|
+
"description": "FINAL CLAUDE CODE CLI EDITION - This is the last version specifically designed for Claude Code CLI. Future versions will support multiple LLMs (OpenAI, Google, Anthropic, Ollama, etc.) through a modular provider system. Thank you to all Claude Code users!",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"type": "commonjs",
|
|
7
7
|
"bin": {
|
|
@@ -396,10 +396,15 @@
|
|
|
396
396
|
"npm": ">=8.0.0"
|
|
397
397
|
},
|
|
398
398
|
"dependencies": {
|
|
399
|
-
"@
|
|
399
|
+
"@ai-sdk/anthropic": "^2.0.4",
|
|
400
|
+
"@ai-sdk/google": "^1.2.22",
|
|
401
|
+
"@ai-sdk/openai": "^1.3.24",
|
|
400
402
|
"@modelcontextprotocol/sdk": "^1.15.1",
|
|
403
|
+
"@openrouter/ai-sdk-provider": "^1.1.2",
|
|
404
|
+
"@tensorflow/tfjs-node": "^4.22.0",
|
|
401
405
|
"@types/node-fetch": "^2.6.12",
|
|
402
406
|
"@types/uuid": "^10.0.0",
|
|
407
|
+
"ai": "^5.0.14",
|
|
403
408
|
"axios": "^1.10.0",
|
|
404
409
|
"better-sqlite3": "^9.6.0",
|
|
405
410
|
"boxen": "^8.0.1",
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
{
|
|
2
|
+
"profile": "default",
|
|
3
|
+
"mcp": { "cmd": "node", "args": ["dist/mcp/index.js"] },
|
|
4
|
+
"llm": {
|
|
5
|
+
"provider": "openai",
|
|
6
|
+
"model": "gpt-5",
|
|
7
|
+
"apiKeyEnv": "OPENAI_API_KEY"
|
|
8
|
+
},
|
|
9
|
+
"agent": { "system": "You are Snow-Flow, a precise ServiceNow engineering agent.", "maxSteps": 50 },
|
|
10
|
+
"logging": { "level": "info" },
|
|
11
|
+
"profiles": {
|
|
12
|
+
"dev": { "logging": { "level": "debug" } },
|
|
13
|
+
"prod": { "agent": { "maxSteps": 60 } }
|
|
14
|
+
}
|
|
15
|
+
}
|