snow-flow 2.0.2 → 2.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/{.claude/mcp-config.json → .mcp.json} +13 -12
- package/.releaserc.json +47 -0
- package/README.md +6 -0
- package/package.json +1 -1
- package/.claude/claude-settings.json +0 -15
- package/.claude/commands/analysis/README.md +0 -9
- package/.claude/commands/automation/README.md +0 -9
- package/.claude/commands/github/README.md +0 -11
- package/.claude/commands/helpers/standard-checkpoint-hooks.sh +0 -179
- package/.claude/commands/hooks/README.md +0 -11
- package/.claude/commands/monitoring/README.md +0 -9
- package/.claude/commands/optimization/README.md +0 -9
- package/.claude/commands/training/README.md +0 -9
- package/.claude/commands/workflows/README.md +0 -9
- package/.claude/config.json +0 -36
- package/.claude/helpers/github-setup.sh +0 -28
- package/.claude/helpers/quick-start.sh +0 -19
- package/.claude/helpers/setup-mcp.sh +0 -18
- package/.claude/settings.json +0 -114
- package/.claude/settings.local.json +0 -33
- package/.claude-flow/metrics/agent-metrics.json +0 -1
- package/.claude-flow/metrics/performance.json +0 -9
- package/.claude-flow/metrics/system-metrics.json +0 -15986
- package/.claude-flow/metrics/task-metrics.json +0 -10
- package/.roo/README.md +0 -402
- package/.roo/mcp-list.txt +0 -257
- package/.roo/mcp.json +0 -32
- package/.roo/workflows/basic-tdd.json +0 -32
- package/.roomodes +0 -201
- package/CLAUDE.md +0 -393
- package/bin/snow-flow.js +0 -3
- package/dist/cli.js.bak +0 -2052
- package/dist/config/snow-flow-config.d.ts +0 -1492
- package/dist/config/snow-flow-config.js +0 -938
- package/scripts/create-env.js +0 -91
- package/scripts/postinstall.js +0 -30
- package/scripts/register-mcp-servers.js +0 -210
- package/scripts/reset-mcp-servers.js +0 -246
- package/scripts/setup-mcp.js +0 -106
- package/scripts/update-version.js +0 -31
- package/src/agents/README.md +0 -192
- package/src/agents/base-agent.ts +0 -251
- package/src/agents/coordinator.ts +0 -971
- package/src/agents/index.ts +0 -18
- package/src/agents/queen-403-handler.ts +0 -230
- package/src/agents/queen-agent.ts +0 -1399
- package/src/agents/script-writer-agent.ts +0 -769
- package/src/agents/security-agent.ts +0 -726
- package/src/agents/widget-creator-agent.ts +0 -568
- package/src/api/error-handling.ts +0 -1758
- package/src/api/natural-language-mapper.ts +0 -630
- package/src/api/performance-optimizer.ts +0 -891
- package/src/api/transaction-manager.ts +0 -754
- package/src/cli/deploy-artifact.ts +0 -304
- package/src/cli/snow-flow-cli-integration.ts +0 -434
- package/src/cli.ts +0 -4455
- package/src/cli.ts.bak +0 -5616
- package/src/compliance/advanced-compliance-system.ts +0 -1268
- package/src/compliance/index.ts +0 -19
- package/src/config/snow-flow-config.ts +0 -1019
- package/src/documentation/index.ts +0 -16
- package/src/documentation/self-documenting-system.ts +0 -1421
- package/src/dynamic-version.ts +0 -44
- package/src/healing/index.ts +0 -20
- package/src/healing/self-healing-system.ts +0 -1435
- package/src/health/README.md +0 -161
- package/src/health/system-health.ts +0 -995
- package/src/index.ts +0 -60
- package/src/intelligence/acl-analyzer.ts +0 -377
- package/src/intelligence/auto-resolution-engine.ts +0 -643
- package/src/intelligence/gap-analysis-engine.ts +0 -488
- package/src/intelligence/manual-instructions-generator.ts +0 -744
- package/src/intelligence/mcp-coverage-analyzer.ts +0 -708
- package/src/intelligence/multi-pass-requirements-analyzer.ts +0 -603
- package/src/intelligence/performance-recommendations-engine.ts +0 -1223
- package/src/intelligence/requirements-analyzer.ts +0 -1148
- package/src/intelligence/task-analyzer.ts +0 -628
- package/src/managers/scope-manager.ts +0 -555
- package/src/mcp/advanced/servicenow-advanced-features-mcp.ts +0 -16110
- package/src/mcp/base-mcp-server.ts +0 -660
- package/src/mcp/http-transport-wrapper.ts +0 -426
- package/src/mcp/service-discovery-client.ts +0 -312
- package/src/mcp/servicenow-automation-mcp-refactored.ts +0 -678
- package/src/mcp/servicenow-automation-mcp.ts +0 -838
- package/src/mcp/servicenow-deployment-mcp-refactored.ts +0 -1292
- package/src/mcp/servicenow-deployment-mcp.ts +0 -7244
- package/src/mcp/servicenow-graph-memory-mcp-refactored.ts +0 -721
- package/src/mcp/servicenow-graph-memory-mcp.ts +0 -832
- package/src/mcp/servicenow-integration-mcp-refactored.ts +0 -655
- package/src/mcp/servicenow-integration-mcp.ts +0 -819
- package/src/mcp/servicenow-intelligent-mcp-refactored.ts +0 -977
- package/src/mcp/servicenow-intelligent-mcp.ts +0 -4638
- package/src/mcp/servicenow-mcp-server.ts +0 -728
- package/src/mcp/servicenow-memory-mcp.ts +0 -474
- package/src/mcp/servicenow-operations-mcp-refactored.ts +0 -1995
- package/src/mcp/servicenow-operations-mcp.ts +0 -3384
- package/src/mcp/servicenow-platform-development-mcp-refactored.ts +0 -611
- package/src/mcp/servicenow-platform-development-mcp.ts +0 -970
- package/src/mcp/servicenow-progressive-indexer.ts +0 -370
- package/src/mcp/servicenow-reporting-analytics-mcp-refactored.ts +0 -695
- package/src/mcp/servicenow-reporting-analytics-mcp.ts +0 -1123
- package/src/mcp/servicenow-security-compliance-mcp-refactored.ts +0 -642
- package/src/mcp/servicenow-security-compliance-mcp.ts +0 -1157
- package/src/mcp/servicenow-update-set-mcp-refactored.ts +0 -751
- package/src/mcp/servicenow-update-set-mcp.ts +0 -811
- package/src/mcp/shared/agent-context-provider.ts +0 -365
- package/src/mcp/shared/base-mcp-server.ts +0 -2463
- package/src/mcp/shared/mcp-memory-manager.ts +0 -540
- package/src/mcp/shared/mcp-resource-manager.ts +0 -367
- package/src/mcp/snow-flow-mcp.ts +0 -911
- package/src/mcp/start-all-mcp-servers.ts +0 -102
- package/src/mcp/start-servicenow-mcp.ts +0 -67
- package/src/monitoring/enhanced-monitoring-system.ts +0 -1345
- package/src/monitoring/performance-tracker.ts +0 -777
- package/src/optimization/cost-optimization-engine.ts +0 -1125
- package/src/optimization/index.ts +0 -10
- package/src/queen/README.md +0 -403
- package/src/queen/agent-factory.ts +0 -574
- package/src/queen/index.ts +0 -94
- package/src/queen/mcp-execution-bridge.ts +0 -681
- package/src/queen/neural-learning.ts +0 -319
- package/src/queen/parallel-agent-engine.ts +0 -848
- package/src/queen/queen-memory-system.ts +0 -490
- package/src/queen/queen-memory.ts +0 -456
- package/src/queen/servicenow-queen.ts +0 -1029
- package/src/queen/types.ts +0 -87
- package/src/rollback/smart-rollback-system.ts +0 -866
- package/src/schemas/deployment.schema.json +0 -58
- package/src/schemas/flow.schema.json +0 -79
- package/src/schemas/widget.schema.json +0 -72
- package/src/snow-flow-system.ts +0 -541
- package/src/sparc/sparc-help.ts +0 -49
- package/src/sparc/team-sparc.ts +0 -88
- package/src/strategies/global-scope-strategy.ts +0 -736
- package/src/templates/base/application.template.json +0 -45
- package/src/templates/base/business_rule.template.json +0 -33
- package/src/templates/base/script_include.template.json +0 -18
- package/src/templates/base/table.template.json +0 -64
- package/src/templates/base/widget.template.json +0 -25
- package/src/templates/patterns/composite.incident-management.template.json +0 -140
- package/src/templates/patterns/widget.dashboard.template.json +0 -238
- package/src/templates/patterns/widget.datatable.template.json +0 -292
- package/src/testing/integration-test-suite.ts +0 -1276
- package/src/types/index.ts +0 -183
- package/src/types/neo4j-driver.d.ts +0 -23
- package/src/types/servicenow.types.ts +0 -307
- package/src/types/snow-flow.types.ts +0 -186
- package/src/types/todo.types.ts +0 -70
- package/src/utils/action-type-cache.ts +0 -286
- package/src/utils/agent-detector.ts +0 -573
- package/src/utils/artifact-tracker.ts +0 -379
- package/src/utils/dependency-detector.ts +0 -233
- package/src/utils/deployment-metadata-handler.ts +0 -518
- package/src/utils/error-recovery.ts +0 -680
- package/src/utils/logger.ts +0 -60
- package/src/utils/mcp-auth-middleware.ts +0 -262
- package/src/utils/mcp-config-manager.ts +0 -270
- package/src/utils/mcp-server-manager.ts +0 -446
- package/src/utils/mcp-tool-registry.ts +0 -298
- package/src/utils/migrate-snow-flow.ts +0 -98
- package/src/utils/oauth-html-templates.ts +0 -188
- package/src/utils/scope-utils.ts +0 -443
- package/src/utils/servicenow-client.ts +0 -3321
- package/src/utils/servicenow-id-generator.ts +0 -181
- package/src/utils/snow-memory-manager.ts +0 -605
- package/src/utils/snow-oauth.ts +0 -797
- package/src/utils/template-engine.ts +0 -463
- package/src/utils/theme-manager.ts +0 -295
- package/src/utils/unified-auth-store.ts +0 -222
- package/src/utils/update-set-importer.ts +0 -422
- package/src/utils/update-set-xml-packager.ts +0 -371
- package/src/utils/widget-template-generator.ts +0 -1744
- package/src/version.ts +0 -1950
|
@@ -1,295 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Service Portal Theme Manager
|
|
3
|
-
* Handles automatic dependency injection into Service Portal themes
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
import { DependencyInfo, DependencyDetector } from './dependency-detector';
|
|
7
|
-
import { logger } from './logger';
|
|
8
|
-
import inquirer from 'inquirer';
|
|
9
|
-
import chalk from 'chalk';
|
|
10
|
-
|
|
11
|
-
export interface ThemeUpdateOptions {
|
|
12
|
-
autoPermissions?: boolean;
|
|
13
|
-
skipPrompt?: boolean;
|
|
14
|
-
useMinified?: boolean;
|
|
15
|
-
themeId?: string;
|
|
16
|
-
themeName?: string;
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
export interface ThemeInfo {
|
|
20
|
-
sys_id: string;
|
|
21
|
-
name: string;
|
|
22
|
-
css_variables?: string;
|
|
23
|
-
footer?: string;
|
|
24
|
-
header?: string;
|
|
25
|
-
js_includes?: string;
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
export class ServicePortalThemeManager {
|
|
29
|
-
/**
|
|
30
|
-
* Update Service Portal theme with dependencies
|
|
31
|
-
*/
|
|
32
|
-
static async updateThemeWithDependencies(
|
|
33
|
-
dependencies: DependencyInfo[],
|
|
34
|
-
mcpTools: any,
|
|
35
|
-
options: ThemeUpdateOptions = {}
|
|
36
|
-
): Promise<{success: boolean; message: string}> {
|
|
37
|
-
try {
|
|
38
|
-
// Step 1: Find the Service Portal theme
|
|
39
|
-
logger.info('🔍 Finding Service Portal theme...');
|
|
40
|
-
const theme = await this.findTheme(mcpTools, options);
|
|
41
|
-
|
|
42
|
-
if (!theme) {
|
|
43
|
-
return {
|
|
44
|
-
success: false,
|
|
45
|
-
message: '❌ No Service Portal theme found. Please specify a theme name or ID.'
|
|
46
|
-
};
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
logger.info(`📋 Found theme: ${theme.name} (${theme.sys_id})`);
|
|
50
|
-
|
|
51
|
-
// Step 2: Check which dependencies are missing
|
|
52
|
-
const currentHeader = theme.header || '';
|
|
53
|
-
const missingDeps = DependencyDetector.getMissingDependencies(
|
|
54
|
-
dependencies,
|
|
55
|
-
currentHeader
|
|
56
|
-
);
|
|
57
|
-
|
|
58
|
-
if (missingDeps.length === 0) {
|
|
59
|
-
logger.info('✅ All dependencies are already installed in the theme');
|
|
60
|
-
return {
|
|
61
|
-
success: true,
|
|
62
|
-
message: 'All required dependencies are already present in the theme'
|
|
63
|
-
};
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
// Step 3: Prompt user for confirmation (unless auto-permissions or skip prompt)
|
|
67
|
-
if (!options.autoPermissions && !options.skipPrompt) {
|
|
68
|
-
const shouldInstall = await this.promptForDependencies(missingDeps, theme.name);
|
|
69
|
-
if (!shouldInstall) {
|
|
70
|
-
return {
|
|
71
|
-
success: false,
|
|
72
|
-
message: 'User cancelled dependency installation'
|
|
73
|
-
};
|
|
74
|
-
}
|
|
75
|
-
} else if (options.autoPermissions) {
|
|
76
|
-
logger.info('🤖 Auto-permissions enabled - installing dependencies automatically');
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
// Step 4: Generate script tags
|
|
80
|
-
const scriptTags = DependencyDetector.generateScriptTags(
|
|
81
|
-
missingDeps,
|
|
82
|
-
options.useMinified !== false
|
|
83
|
-
);
|
|
84
|
-
|
|
85
|
-
// Step 5: Update theme header
|
|
86
|
-
const updatedHeader = this.injectDependencies(currentHeader, scriptTags);
|
|
87
|
-
|
|
88
|
-
// Step 6: Save updated theme
|
|
89
|
-
logger.info('💾 Updating Service Portal theme...');
|
|
90
|
-
const updateResult = await this.updateTheme(
|
|
91
|
-
mcpTools,
|
|
92
|
-
theme.sys_id,
|
|
93
|
-
{ header: updatedHeader }
|
|
94
|
-
);
|
|
95
|
-
|
|
96
|
-
if (updateResult.success) {
|
|
97
|
-
const depNames = missingDeps.map(d => d.name).join(', ');
|
|
98
|
-
logger.info(chalk.green(`✅ Successfully added dependencies: ${depNames}`));
|
|
99
|
-
return {
|
|
100
|
-
success: true,
|
|
101
|
-
message: `Successfully added ${missingDeps.length} dependencies to theme "${theme.name}"`
|
|
102
|
-
};
|
|
103
|
-
} else {
|
|
104
|
-
return {
|
|
105
|
-
success: false,
|
|
106
|
-
message: updateResult.message || 'Failed to update theme'
|
|
107
|
-
};
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
} catch (error: any) {
|
|
111
|
-
logger.error('❌ Error updating theme:', error);
|
|
112
|
-
return {
|
|
113
|
-
success: false,
|
|
114
|
-
message: `Error updating theme: ${error.message}`
|
|
115
|
-
};
|
|
116
|
-
}
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
/**
|
|
120
|
-
* Find Service Portal theme
|
|
121
|
-
*/
|
|
122
|
-
private static async findTheme(
|
|
123
|
-
mcpTools: any,
|
|
124
|
-
options: ThemeUpdateOptions
|
|
125
|
-
): Promise<ThemeInfo | null> {
|
|
126
|
-
try {
|
|
127
|
-
// If theme ID is provided, use direct lookup
|
|
128
|
-
if (options.themeId) {
|
|
129
|
-
const result = await mcpTools.snow_get_by_sysid({
|
|
130
|
-
sys_id: options.themeId,
|
|
131
|
-
table: 'sp_theme'
|
|
132
|
-
});
|
|
133
|
-
return result.record || null;
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
// Search by name or find default theme
|
|
137
|
-
const searchQuery = options.themeName
|
|
138
|
-
? `name=${options.themeName}`
|
|
139
|
-
: 'active=true^ORDERBYname';
|
|
140
|
-
|
|
141
|
-
const result = await mcpTools.snow_find_artifact({
|
|
142
|
-
query: searchQuery,
|
|
143
|
-
type: 'any',
|
|
144
|
-
table: 'sp_theme'
|
|
145
|
-
});
|
|
146
|
-
|
|
147
|
-
if (result.artifacts && result.artifacts.length > 0) {
|
|
148
|
-
// Return first active theme or first theme found
|
|
149
|
-
return result.artifacts[0];
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
// Try to find any theme
|
|
153
|
-
const anyThemeResult = await mcpTools.snow_comprehensive_search({
|
|
154
|
-
query: 'Service Portal theme'
|
|
155
|
-
});
|
|
156
|
-
|
|
157
|
-
if (anyThemeResult.results && anyThemeResult.results.length > 0) {
|
|
158
|
-
const themeResult = anyThemeResult.results.find((r: any) =>
|
|
159
|
-
r.sys_class_name === 'sp_theme'
|
|
160
|
-
);
|
|
161
|
-
return themeResult || null;
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
return null;
|
|
165
|
-
} catch (error) {
|
|
166
|
-
logger.error('Error finding theme:', error);
|
|
167
|
-
return null;
|
|
168
|
-
}
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
/**
|
|
172
|
-
* Prompt user for dependency installation
|
|
173
|
-
*/
|
|
174
|
-
private static async promptForDependencies(
|
|
175
|
-
dependencies: DependencyInfo[],
|
|
176
|
-
themeName: string
|
|
177
|
-
): Promise<boolean> {
|
|
178
|
-
console.log('\n' + chalk.yellow('📦 Missing Dependencies Detected:'));
|
|
179
|
-
|
|
180
|
-
dependencies.forEach(dep => {
|
|
181
|
-
console.log(chalk.cyan(` • ${dep.name} (${dep.version || 'latest'})`));
|
|
182
|
-
console.log(chalk.gray(` ${dep.description}`));
|
|
183
|
-
});
|
|
184
|
-
|
|
185
|
-
console.log('\n' + chalk.yellow(`These dependencies need to be added to the "${themeName}" theme.`));
|
|
186
|
-
|
|
187
|
-
const { confirm } = await inquirer.prompt([
|
|
188
|
-
{
|
|
189
|
-
type: 'confirm',
|
|
190
|
-
name: 'confirm',
|
|
191
|
-
message: 'Would you like to automatically install these dependencies?',
|
|
192
|
-
default: true
|
|
193
|
-
}
|
|
194
|
-
]);
|
|
195
|
-
|
|
196
|
-
return confirm;
|
|
197
|
-
}
|
|
198
|
-
|
|
199
|
-
/**
|
|
200
|
-
* Inject dependencies into theme header
|
|
201
|
-
*/
|
|
202
|
-
private static injectDependencies(currentHeader: string, scriptTags: string): string {
|
|
203
|
-
// Check if header already has a dependency section
|
|
204
|
-
const dependencyMarker = '<!-- Snow-Flow Dependencies -->';
|
|
205
|
-
const endMarker = '<!-- End Snow-Flow Dependencies -->';
|
|
206
|
-
|
|
207
|
-
// Create dependency section
|
|
208
|
-
const dependencySection = `
|
|
209
|
-
${dependencyMarker}
|
|
210
|
-
${scriptTags}
|
|
211
|
-
${endMarker}`;
|
|
212
|
-
|
|
213
|
-
// If markers exist, replace the section
|
|
214
|
-
if (currentHeader.includes(dependencyMarker)) {
|
|
215
|
-
const regex = new RegExp(
|
|
216
|
-
`${dependencyMarker}[\\s\\S]*?${endMarker}`,
|
|
217
|
-
'g'
|
|
218
|
-
);
|
|
219
|
-
return currentHeader.replace(regex, dependencySection);
|
|
220
|
-
}
|
|
221
|
-
|
|
222
|
-
// Otherwise, add before closing </head> or at the end
|
|
223
|
-
if (currentHeader.includes('</head>')) {
|
|
224
|
-
return currentHeader.replace('</head>', `${dependencySection}\n</head>`);
|
|
225
|
-
}
|
|
226
|
-
|
|
227
|
-
// Just append if no head tag
|
|
228
|
-
return currentHeader + '\n' + dependencySection;
|
|
229
|
-
}
|
|
230
|
-
|
|
231
|
-
/**
|
|
232
|
-
* Update theme in ServiceNow
|
|
233
|
-
*/
|
|
234
|
-
private static async updateTheme(
|
|
235
|
-
mcpTools: any,
|
|
236
|
-
themeId: string,
|
|
237
|
-
updates: Partial<ThemeInfo>
|
|
238
|
-
): Promise<{success: boolean; message?: string}> {
|
|
239
|
-
try {
|
|
240
|
-
// Use snow_edit_by_sysid to update the theme
|
|
241
|
-
const result = await mcpTools.snow_edit_by_sysid({
|
|
242
|
-
sys_id: themeId,
|
|
243
|
-
table: 'sp_theme',
|
|
244
|
-
field: 'header',
|
|
245
|
-
value: updates.header
|
|
246
|
-
});
|
|
247
|
-
|
|
248
|
-
return { success: true };
|
|
249
|
-
} catch (error: any) {
|
|
250
|
-
return {
|
|
251
|
-
success: false,
|
|
252
|
-
message: error.message || 'Failed to update theme'
|
|
253
|
-
};
|
|
254
|
-
}
|
|
255
|
-
}
|
|
256
|
-
|
|
257
|
-
/**
|
|
258
|
-
* Check if widget requires dependencies and handle installation
|
|
259
|
-
*/
|
|
260
|
-
static async handleWidgetDependencies(
|
|
261
|
-
widgetConfig: any,
|
|
262
|
-
mcpTools: any,
|
|
263
|
-
options: ThemeUpdateOptions = {}
|
|
264
|
-
): Promise<{
|
|
265
|
-
dependencies: DependencyInfo[];
|
|
266
|
-
installed: boolean;
|
|
267
|
-
message: string;
|
|
268
|
-
}> {
|
|
269
|
-
// Detect dependencies in widget
|
|
270
|
-
const dependencies = DependencyDetector.analyzeWidget(widgetConfig);
|
|
271
|
-
|
|
272
|
-
if (dependencies.length === 0) {
|
|
273
|
-
return {
|
|
274
|
-
dependencies: [],
|
|
275
|
-
installed: true,
|
|
276
|
-
message: 'No external dependencies detected'
|
|
277
|
-
};
|
|
278
|
-
}
|
|
279
|
-
|
|
280
|
-
logger.info(`🔍 Detected ${dependencies.length} dependencies in widget`);
|
|
281
|
-
|
|
282
|
-
// Update theme with dependencies
|
|
283
|
-
const result = await this.updateThemeWithDependencies(
|
|
284
|
-
dependencies,
|
|
285
|
-
mcpTools,
|
|
286
|
-
options
|
|
287
|
-
);
|
|
288
|
-
|
|
289
|
-
return {
|
|
290
|
-
dependencies,
|
|
291
|
-
installed: result.success,
|
|
292
|
-
message: result.message
|
|
293
|
-
};
|
|
294
|
-
}
|
|
295
|
-
}
|
|
@@ -1,222 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Unified Authentication Store for ServiceNow
|
|
3
|
-
*
|
|
4
|
-
* Provides shared token storage accessible from both CLI and MCP contexts.
|
|
5
|
-
* Solves the token isolation problem between different execution contexts.
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
import { promises as fs } from 'fs';
|
|
9
|
-
import { join } from 'path';
|
|
10
|
-
import os from 'os';
|
|
11
|
-
import dotenv from 'dotenv';
|
|
12
|
-
|
|
13
|
-
// Load environment variables
|
|
14
|
-
dotenv.config();
|
|
15
|
-
|
|
16
|
-
export interface AuthTokens {
|
|
17
|
-
instance: string;
|
|
18
|
-
clientId: string;
|
|
19
|
-
clientSecret: string;
|
|
20
|
-
accessToken?: string;
|
|
21
|
-
refreshToken?: string;
|
|
22
|
-
expiresAt?: string;
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
export class UnifiedAuthStore {
|
|
26
|
-
private static instance: UnifiedAuthStore;
|
|
27
|
-
private tokenPath: string;
|
|
28
|
-
private memoryStore: AuthTokens | null = null;
|
|
29
|
-
|
|
30
|
-
constructor() {
|
|
31
|
-
// Use consistent path across all contexts
|
|
32
|
-
const configDir = process.env.SNOW_FLOW_HOME || join(os.homedir(), '.snow-flow');
|
|
33
|
-
this.tokenPath = join(configDir, 'auth.json');
|
|
34
|
-
|
|
35
|
-
// Also check environment for shared tokens (from MCP bridge)
|
|
36
|
-
if (process.env.SNOW_OAUTH_TOKENS) {
|
|
37
|
-
try {
|
|
38
|
-
this.memoryStore = JSON.parse(process.env.SNOW_OAUTH_TOKENS);
|
|
39
|
-
} catch (e) {
|
|
40
|
-
console.error('Failed to parse SNOW_OAUTH_TOKENS from environment');
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
static getInstance(): UnifiedAuthStore {
|
|
46
|
-
if (!UnifiedAuthStore.instance) {
|
|
47
|
-
UnifiedAuthStore.instance = new UnifiedAuthStore();
|
|
48
|
-
}
|
|
49
|
-
return UnifiedAuthStore.instance;
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
/**
|
|
53
|
-
* Get tokens from file or memory
|
|
54
|
-
*/
|
|
55
|
-
async getTokens(): Promise<AuthTokens | null> {
|
|
56
|
-
try {
|
|
57
|
-
// First check memory store (fastest)
|
|
58
|
-
if (this.memoryStore) {
|
|
59
|
-
return this.memoryStore;
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
// Then check file system
|
|
63
|
-
const data = await fs.readFile(this.tokenPath, 'utf8');
|
|
64
|
-
const tokens = JSON.parse(data);
|
|
65
|
-
|
|
66
|
-
// Cache in memory for performance
|
|
67
|
-
this.memoryStore = tokens;
|
|
68
|
-
|
|
69
|
-
return tokens;
|
|
70
|
-
} catch (error) {
|
|
71
|
-
// Fallback to environment variables
|
|
72
|
-
return this.getTokensFromEnv();
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
/**
|
|
77
|
-
* Save tokens to file and memory
|
|
78
|
-
*/
|
|
79
|
-
async saveTokens(tokens: AuthTokens): Promise<void> {
|
|
80
|
-
try {
|
|
81
|
-
const configDir = join(os.homedir(), '.snow-flow');
|
|
82
|
-
await fs.mkdir(configDir, { recursive: true });
|
|
83
|
-
|
|
84
|
-
await fs.writeFile(this.tokenPath, JSON.stringify(tokens, null, 2));
|
|
85
|
-
|
|
86
|
-
// Update memory store
|
|
87
|
-
this.memoryStore = tokens;
|
|
88
|
-
|
|
89
|
-
// Update environment for child processes
|
|
90
|
-
process.env.SNOW_OAUTH_TOKENS = JSON.stringify(tokens);
|
|
91
|
-
} catch (error) {
|
|
92
|
-
console.error('Failed to save tokens:', error);
|
|
93
|
-
throw error;
|
|
94
|
-
}
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
/**
|
|
98
|
-
* Get tokens from environment variables (fallback)
|
|
99
|
-
*/
|
|
100
|
-
private getTokensFromEnv(): AuthTokens | null {
|
|
101
|
-
const instance = process.env.SNOW_INSTANCE;
|
|
102
|
-
const clientId = process.env.SNOW_CLIENT_ID;
|
|
103
|
-
const clientSecret = process.env.SNOW_CLIENT_SECRET;
|
|
104
|
-
|
|
105
|
-
if (!instance || !clientId || !clientSecret) {
|
|
106
|
-
return null;
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
return {
|
|
110
|
-
instance: instance.replace(/\/$/, ''),
|
|
111
|
-
clientId,
|
|
112
|
-
clientSecret,
|
|
113
|
-
accessToken: process.env.SNOW_ACCESS_TOKEN,
|
|
114
|
-
refreshToken: process.env.SNOW_REFRESH_TOKEN,
|
|
115
|
-
expiresAt: process.env.SNOW_TOKEN_EXPIRES_AT
|
|
116
|
-
};
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
/**
|
|
120
|
-
* Check if tokens are valid and not expired
|
|
121
|
-
*/
|
|
122
|
-
async isAuthenticated(): Promise<boolean> {
|
|
123
|
-
try {
|
|
124
|
-
const tokens = await this.getTokens();
|
|
125
|
-
if (!tokens || !tokens.accessToken) {
|
|
126
|
-
return false;
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
// Check expiration
|
|
130
|
-
if (tokens.expiresAt) {
|
|
131
|
-
const expiresAt = new Date(tokens.expiresAt);
|
|
132
|
-
const now = new Date();
|
|
133
|
-
return now < expiresAt;
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
// If no expiration, assume valid
|
|
137
|
-
return true;
|
|
138
|
-
} catch (error) {
|
|
139
|
-
return false;
|
|
140
|
-
}
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
/**
|
|
144
|
-
* Clear all stored tokens
|
|
145
|
-
*/
|
|
146
|
-
async clearTokens(): Promise<void> {
|
|
147
|
-
try {
|
|
148
|
-
await fs.unlink(this.tokenPath);
|
|
149
|
-
} catch (error) {
|
|
150
|
-
// Ignore if file doesn't exist
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
// Clear memory and environment
|
|
154
|
-
this.memoryStore = null;
|
|
155
|
-
delete process.env.SNOW_OAUTH_TOKENS;
|
|
156
|
-
delete process.env.SNOW_ACCESS_TOKEN;
|
|
157
|
-
delete process.env.SNOW_REFRESH_TOKEN;
|
|
158
|
-
delete process.env.SNOW_TOKEN_EXPIRES_AT;
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
/**
|
|
162
|
-
* Get ServiceNow instance URL
|
|
163
|
-
*/
|
|
164
|
-
async getInstanceUrl(): Promise<string | null> {
|
|
165
|
-
const tokens = await this.getTokens();
|
|
166
|
-
if (!tokens) {
|
|
167
|
-
return null;
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
let instance = tokens.instance;
|
|
171
|
-
if (!instance.startsWith('http')) {
|
|
172
|
-
instance = `https://${instance}`;
|
|
173
|
-
}
|
|
174
|
-
if (!instance.endsWith('.service-now.com')) {
|
|
175
|
-
instance = `${instance}.service-now.com`;
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
return instance;
|
|
179
|
-
}
|
|
180
|
-
|
|
181
|
-
/**
|
|
182
|
-
* Get headers for API requests
|
|
183
|
-
*/
|
|
184
|
-
async getAuthHeaders(): Promise<Record<string, string> | null> {
|
|
185
|
-
const tokens = await this.getTokens();
|
|
186
|
-
if (!tokens || !tokens.accessToken) {
|
|
187
|
-
return null;
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
return {
|
|
191
|
-
'Authorization': `Bearer ${tokens.accessToken}`,
|
|
192
|
-
'Content-Type': 'application/json',
|
|
193
|
-
'Accept': 'application/json'
|
|
194
|
-
};
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
/**
|
|
198
|
-
* Bridge tokens to MCP servers via environment
|
|
199
|
-
*/
|
|
200
|
-
async bridgeToMCP(): Promise<void> {
|
|
201
|
-
const tokens = await this.getTokens();
|
|
202
|
-
if (tokens) {
|
|
203
|
-
process.env.SNOW_OAUTH_TOKENS = JSON.stringify(tokens);
|
|
204
|
-
process.env.SNOW_INSTANCE = tokens.instance;
|
|
205
|
-
process.env.SNOW_CLIENT_ID = tokens.clientId;
|
|
206
|
-
process.env.SNOW_CLIENT_SECRET = tokens.clientSecret;
|
|
207
|
-
|
|
208
|
-
if (tokens.accessToken) {
|
|
209
|
-
process.env.SNOW_ACCESS_TOKEN = tokens.accessToken;
|
|
210
|
-
}
|
|
211
|
-
if (tokens.refreshToken) {
|
|
212
|
-
process.env.SNOW_REFRESH_TOKEN = tokens.refreshToken;
|
|
213
|
-
}
|
|
214
|
-
if (tokens.expiresAt) {
|
|
215
|
-
process.env.SNOW_TOKEN_EXPIRES_AT = tokens.expiresAt;
|
|
216
|
-
}
|
|
217
|
-
}
|
|
218
|
-
}
|
|
219
|
-
}
|
|
220
|
-
|
|
221
|
-
// Export singleton instance
|
|
222
|
-
export const unifiedAuthStore = UnifiedAuthStore.getInstance();
|