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.
@@ -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
@@ -11,7 +11,6 @@ exports.snowFlowSystem = exports.SnowFlowSystem = void 0;
11
11
  const events_1 = require("events");
12
12
  const snow_flow_config_1 = require("./config/snow-flow-config");
13
13
  const servicenow_queen_1 = require("./queen/servicenow-queen");
14
- const memory_system_1 = require("./memory/memory-system");
15
14
  const mcp_server_manager_1 = require("./utils/mcp-server-manager");
16
15
  const performance_tracker_1 = require("./monitoring/performance-tracker");
17
16
  const system_health_1 = require("./health/system-health");
@@ -10,7 +10,6 @@ Object.defineProperty(exports, "__esModule", { value: true });
10
10
  exports.IntegrationTestSuite = void 0;
11
11
  const logger_js_1 = require("../utils/logger.js");
12
12
  const servicenow_client_js_1 = require("../utils/servicenow-client.js");
13
- const memory_system_js_1 = require("../memory/memory-system.js");
14
13
  class IntegrationTestSuite {
15
14
  constructor() {
16
15
  // Flow-related systems removed in v1.4.0
@@ -47,6 +47,7 @@ const fs = __importStar(require("fs"));
47
47
  const path = __importStar(require("path"));
48
48
  const smart_field_fetcher_js_1 = require("./smart-field-fetcher.js");
49
49
  const mcp_timeout_config_js_1 = require("./mcp-timeout-config.js");
50
+ const chunking_manager_js_1 = require("./chunking-manager.js");
50
51
  const artifact_registry_1 = require("./artifact-sync/artifact-registry");
51
52
  class ArtifactLocalSync {
52
53
  constructor(client, customBaseDir) {
@@ -285,6 +286,22 @@ class ArtifactLocalSync {
285
286
  }
286
287
  // Map back to ServiceNow field
287
288
  if (file.field && file.field !== 'documentation' && file.field !== 'metadata') {
289
+ // Check if field needs chunking (large server scripts)
290
+ if (chunking_manager_js_1.ChunkingManager.needsChunking(processedContent)) {
291
+ console.log(` ⚠️ Large field detected: ${file.field} (${processedContent.length} chars)`);
292
+ // Attempt chunked update
293
+ const chunkResult = await chunking_manager_js_1.ChunkingManager.attemptChunkedUpdate(this.client, config.tableName, sys_id, file.field, processedContent);
294
+ if (!chunkResult.success) {
295
+ // Add to validation results as a manual instruction
296
+ validationResults.push({
297
+ valid: false,
298
+ errors: [],
299
+ warnings: [`Large ${file.field} requires manual update`],
300
+ hints: [chunkResult.message]
301
+ });
302
+ continue; // Skip adding to updates
303
+ }
304
+ }
288
305
  updates[file.field] = processedContent;
289
306
  console.log(` 📝 Changed: ${file.filename} (${file.field})`);
290
307
  // Validate ES5 if required
@@ -0,0 +1,39 @@
1
+ /**
2
+ * Chunking Manager for Large ServiceNow Artifacts
3
+ * Handles scripts >30k characters that exceed API token limits
4
+ */
5
+ export interface ChunkingStrategy {
6
+ maxChunkSize: number;
7
+ overlapSize: number;
8
+ chunkType: 'lines' | 'functions' | 'blocks';
9
+ }
10
+ export interface ScriptChunk {
11
+ index: number;
12
+ content: string;
13
+ startLine: number;
14
+ endLine: number;
15
+ type: 'complete' | 'partial_start' | 'partial_middle' | 'partial_end';
16
+ hasContext: boolean;
17
+ }
18
+ export declare class ChunkingManager {
19
+ /**
20
+ * Determine if script needs chunking
21
+ */
22
+ static needsChunking(script: string, maxSize?: number): boolean;
23
+ /**
24
+ * Split large script into manageable chunks
25
+ */
26
+ static chunkScript(script: string, strategy?: ChunkingStrategy): ScriptChunk[];
27
+ /**
28
+ * Generate instructions for manual large script handling
29
+ */
30
+ static generateManualInstructions(scriptName: string, scriptSize: number, chunks: ScriptChunk[]): string;
31
+ /**
32
+ * Attempt smart chunked update for large scripts
33
+ */
34
+ static attemptChunkedUpdate(client: any, table: string, sys_id: string, field: string, script: string): Promise<{
35
+ success: boolean;
36
+ message: string;
37
+ }>;
38
+ }
39
+ //# sourceMappingURL=chunking-manager.d.ts.map
@@ -0,0 +1,142 @@
1
+ "use strict";
2
+ /**
3
+ * Chunking Manager for Large ServiceNow Artifacts
4
+ * Handles scripts >30k characters that exceed API token limits
5
+ */
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ exports.ChunkingManager = void 0;
8
+ class ChunkingManager {
9
+ /**
10
+ * Determine if script needs chunking
11
+ */
12
+ static needsChunking(script, maxSize = 30000) {
13
+ return script.length > maxSize;
14
+ }
15
+ /**
16
+ * Split large script into manageable chunks
17
+ */
18
+ static chunkScript(script, strategy = {
19
+ maxChunkSize: 25000,
20
+ overlapSize: 500,
21
+ chunkType: 'functions'
22
+ }) {
23
+ const lines = script.split('\n');
24
+ const chunks = [];
25
+ if (!this.needsChunking(script)) {
26
+ return [{
27
+ index: 0,
28
+ content: script,
29
+ startLine: 1,
30
+ endLine: lines.length,
31
+ type: 'complete',
32
+ hasContext: true
33
+ }];
34
+ }
35
+ let currentChunk = '';
36
+ let currentStartLine = 1;
37
+ let chunkIndex = 0;
38
+ for (let i = 0; i < lines.length; i++) {
39
+ const line = lines[i];
40
+ const potentialChunk = currentChunk + line + '\n';
41
+ if (potentialChunk.length > strategy.maxChunkSize) {
42
+ // Current chunk is full, save it
43
+ if (currentChunk.trim()) {
44
+ chunks.push({
45
+ index: chunkIndex++,
46
+ content: currentChunk.trim(),
47
+ startLine: currentStartLine,
48
+ endLine: i,
49
+ type: chunkIndex === 0 ? 'partial_start' : 'partial_middle',
50
+ hasContext: true
51
+ });
52
+ }
53
+ // Start new chunk with overlap
54
+ const overlapLines = Math.min(Math.floor(strategy.overlapSize / 50), // Assume ~50 chars per line
55
+ 10 // Max 10 lines overlap
56
+ );
57
+ const overlapStart = Math.max(0, i - overlapLines);
58
+ currentChunk = lines.slice(overlapStart, i + 1).join('\n') + '\n';
59
+ currentStartLine = overlapStart + 1;
60
+ }
61
+ else {
62
+ currentChunk += line + '\n';
63
+ }
64
+ }
65
+ // Add final chunk
66
+ if (currentChunk.trim()) {
67
+ chunks.push({
68
+ index: chunkIndex,
69
+ content: currentChunk.trim(),
70
+ startLine: currentStartLine,
71
+ endLine: lines.length,
72
+ type: 'partial_end',
73
+ hasContext: true
74
+ });
75
+ }
76
+ return chunks;
77
+ }
78
+ /**
79
+ * Generate instructions for manual large script handling
80
+ */
81
+ static generateManualInstructions(scriptName, scriptSize, chunks) {
82
+ return `
83
+ 🚨 LARGE SCRIPT DETECTED: ${scriptName} (${scriptSize.toLocaleString()} characters)
84
+
85
+ ⚠️ This script exceeds API token limits and cannot be updated automatically.
86
+
87
+ 🔧 MANUAL UPDATE REQUIRED:
88
+
89
+ 1. **Navigate to ServiceNow**:
90
+ - Go to Service Portal → Widgets
91
+ - Find and edit your widget
92
+ - Click on "Server Script" tab
93
+
94
+ 2. **Copy the updated script**:
95
+ - Script has been split into ${chunks.length} chunks below
96
+ - Copy ALL chunks in order and paste into ServiceNow
97
+
98
+ 3. **Chunks to copy**:
99
+ ${chunks.map(chunk => `
100
+ **Chunk ${chunk.index + 1}/${chunks.length}** (Lines ${chunk.startLine}-${chunk.endLine}):
101
+ \`\`\`javascript
102
+ ${chunk.content.substring(0, 500)}${chunk.content.length > 500 ? '...\n[truncated for display]' : ''}
103
+ \`\`\`
104
+ `).join('')}
105
+
106
+ 4. **Validation**:
107
+ - Ensure no syntax errors after pasting
108
+ - Test widget functionality
109
+ - Consider breaking into smaller Script Includes
110
+
111
+ 💡 **Prevention for future**:
112
+ - Keep server scripts under 30,000 characters
113
+ - Use Script Includes for reusable functions
114
+ - Move complex logic to business rules where appropriate
115
+ `;
116
+ }
117
+ /**
118
+ * Attempt smart chunked update for large scripts
119
+ */
120
+ static async attemptChunkedUpdate(client, table, sys_id, field, script) {
121
+ if (!this.needsChunking(script)) {
122
+ // Not chunked, do normal update
123
+ try {
124
+ await client.updateRecord(table, sys_id, { [field]: script });
125
+ return { success: true, message: 'Script updated successfully' };
126
+ }
127
+ catch (error) {
128
+ return { success: false, message: `Update failed: ${error}` };
129
+ }
130
+ }
131
+ // For large scripts, we can't actually chunk the API call
132
+ // But we can provide intelligent guidance
133
+ const chunks = this.chunkScript(script);
134
+ const instructions = this.generateManualInstructions(field, script.length, chunks);
135
+ return {
136
+ success: false,
137
+ message: `Script too large for automatic update. Manual steps required:\n${instructions}`
138
+ };
139
+ }
140
+ }
141
+ exports.ChunkingManager = ChunkingManager;
142
+ //# sourceMappingURL=chunking-manager.js.map
@@ -130,8 +130,8 @@ class SmartFieldFetcher {
130
130
  description: group.description,
131
131
  fields: group.fields
132
132
  };
133
- // Add to flat structure for easy access
134
- Object.assign(results, response.result[0]);
133
+ // FIX: getRecord returns direct object, not response.result[0]
134
+ Object.assign(results, response);
135
135
  }
136
136
  }
137
137
  catch (error) {
@@ -232,8 +232,9 @@ class SmartFieldFetcher {
232
232
  // Try using getRecord instead of searchRecords with short timeout
233
233
  const directResponse = await (0, mcp_timeout_config_js_1.withMCPTimeout)(this.client.getRecord('sp_widget', sys_id), 5000, // 5 second timeout for direct fetch
234
234
  `Direct widget fetch ${sys_id}`);
235
- if (directResponse && directResponse.success && directResponse.data && directResponse.data.result) {
236
- const directData = directResponse.data.result;
235
+ if (directResponse) {
236
+ // FIX: getRecord returns direct object, not nested structure
237
+ const directData = directResponse;
237
238
  // Merge any new data we got
238
239
  Object.assign(results, directData);
239
240
  console.log(`📊 Direct API retrieved:`);
@@ -292,6 +293,7 @@ class SmartFieldFetcher {
292
293
  console.log(` 📄 Fetching field: ${field}`);
293
294
  const response = await this.client.getRecord(table, sys_id);
294
295
  if (response) {
296
+ // FIX: getRecord returns direct object
295
297
  result.data[field] = response[field];
296
298
  result._field_status[field] = 'success';
297
299
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "snow-flow",
3
- "version": "4.0.0",
3
+ "version": "4.0.2",
4
4
  "description": "KNOWLEDGE BASE VERIFICATION - v3.6.25 adds critical validation to snow_create_knowledge_article. Now throws error when non-existent knowledge base is specified, preventing orphaned articles. Includes helpful suggestions to create or discover valid knowledge bases.",
5
5
  "main": "dist/index.js",
6
6
  "type": "commonjs",