snow-flow 4.0.0 → 4.0.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.
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 v3.6.25 ❄️
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/v/snow-flow.svg?style=for-the-badge&logo=npm&color=CB3837" alt="npm version"></a>
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
- ## 🎉 What's New in v3.6.25
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>🚀 Major Features</h3>
54
+ <h3>🏁 Final Release Features</h3>
31
55
  <ul align="left">
32
- <li><strong>Catalog UI Policy Deployment</strong><br/>Deploy via unified <code>snow_deploy</code> tool</li>
33
- <li><strong>Knowledge Base Verification</strong><br/>Prevents orphaned articles with strict validation</li>
34
- <li><strong>Catalog Variable Table Fix</strong><br/>Variables now use correct <code>item_option_new</code></li>
35
- <li><strong>Enhanced UI Policy Debugging</strong><br/>Comprehensive reference field debugging</li>
36
- <li><strong>18th MCP Server</strong><br/>Local Development Server for artifact syncing</li>
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>🔧 Critical Fixes</h3>
64
+ <h3>🚀 Latest Improvements</h3>
41
65
  <ul align="left">
42
- <li>✅ Catalog variables now visible in ServiceNow</li>
43
- <li>✅ UI policy actions reference fields fixed</li>
44
- <li>✅ Non-existent KB error handling added</li>
45
- <li>✅ MCP transport 3x faster operations</li>
46
- <li>✅ Widget coherence validation improved</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
@@ -0,0 +1,3 @@
1
+ import { Command } from 'commander';
2
+ export declare function registerAuthCommands(program: Command): void;
3
+ //# sourceMappingURL=auth.d.ts.map
@@ -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,3 @@
1
+ import { Command } from 'commander';
2
+ export declare function registerSessionCommands(program: Command): void;
3
+ //# sourceMappingURL=session.d.ts.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
@@ -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 '3.6.25';
39
+ return '4.0.0';
40
40
  }
41
41
  // Export a constant that uses the dynamic version
42
42
  exports.VERSION = getDynamicVersion();