@sylphx/flow 1.0.1 → 1.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/CHANGELOG.md +12 -0
- package/package.json +10 -9
- package/src/commands/codebase-command.ts +168 -0
- package/src/commands/flow-command.ts +1137 -0
- package/src/commands/flow-orchestrator.ts +296 -0
- package/src/commands/hook-command.ts +444 -0
- package/src/commands/init-command.ts +92 -0
- package/src/commands/init-core.ts +322 -0
- package/src/commands/knowledge-command.ts +161 -0
- package/src/commands/run-command.ts +120 -0
- package/src/components/benchmark-monitor.tsx +331 -0
- package/src/components/reindex-progress.tsx +261 -0
- package/src/composables/functional/index.ts +14 -0
- package/src/composables/functional/useEnvironment.ts +171 -0
- package/src/composables/functional/useFileSystem.ts +139 -0
- package/src/composables/index.ts +5 -0
- package/src/composables/useEnv.ts +13 -0
- package/src/composables/useRuntimeConfig.ts +27 -0
- package/src/composables/useTargetConfig.ts +45 -0
- package/src/config/ai-config.ts +376 -0
- package/src/config/constants.ts +35 -0
- package/src/config/index.ts +27 -0
- package/src/config/rules.ts +43 -0
- package/src/config/servers.ts +371 -0
- package/src/config/targets.ts +126 -0
- package/src/core/agent-loader.ts +141 -0
- package/src/core/agent-manager.ts +174 -0
- package/src/core/ai-sdk.ts +603 -0
- package/src/core/app-factory.ts +381 -0
- package/src/core/builtin-agents.ts +9 -0
- package/src/core/command-system.ts +550 -0
- package/src/core/config-system.ts +550 -0
- package/src/core/connection-pool.ts +390 -0
- package/src/core/di-container.ts +155 -0
- package/src/core/error-handling.ts +519 -0
- package/src/core/formatting/bytes.test.ts +115 -0
- package/src/core/formatting/bytes.ts +64 -0
- package/src/core/functional/async.ts +313 -0
- package/src/core/functional/either.ts +109 -0
- package/src/core/functional/error-handler.ts +135 -0
- package/src/core/functional/error-types.ts +311 -0
- package/src/core/functional/index.ts +19 -0
- package/src/core/functional/option.ts +142 -0
- package/src/core/functional/pipe.ts +189 -0
- package/src/core/functional/result.ts +204 -0
- package/src/core/functional/validation.ts +138 -0
- package/src/core/headless-display.ts +96 -0
- package/src/core/index.ts +6 -0
- package/src/core/installers/file-installer.ts +303 -0
- package/src/core/installers/mcp-installer.ts +213 -0
- package/src/core/interfaces/index.ts +22 -0
- package/src/core/interfaces/repository.interface.ts +91 -0
- package/src/core/interfaces/service.interface.ts +133 -0
- package/src/core/interfaces.ts +129 -0
- package/src/core/loop-controller.ts +200 -0
- package/src/core/result.ts +351 -0
- package/src/core/rule-loader.ts +147 -0
- package/src/core/rule-manager.ts +240 -0
- package/src/core/service-config.ts +252 -0
- package/src/core/session-service.ts +121 -0
- package/src/core/state-detector.ts +389 -0
- package/src/core/storage-factory.ts +115 -0
- package/src/core/stream-handler.ts +288 -0
- package/src/core/target-manager.ts +161 -0
- package/src/core/type-utils.ts +427 -0
- package/src/core/unified-storage.ts +456 -0
- package/src/core/upgrade-manager.ts +300 -0
- package/src/core/validation/limit.test.ts +155 -0
- package/src/core/validation/limit.ts +46 -0
- package/src/core/validation/query.test.ts +44 -0
- package/src/core/validation/query.ts +20 -0
- package/src/db/auto-migrate.ts +322 -0
- package/src/db/base-database-client.ts +144 -0
- package/src/db/cache-db.ts +218 -0
- package/src/db/cache-schema.ts +75 -0
- package/src/db/database.ts +70 -0
- package/src/db/index.ts +252 -0
- package/src/db/memory-db.ts +153 -0
- package/src/db/memory-schema.ts +29 -0
- package/src/db/schema.ts +289 -0
- package/src/db/session-repository.ts +733 -0
- package/src/domains/codebase/index.ts +5 -0
- package/src/domains/codebase/tools.ts +139 -0
- package/src/domains/index.ts +8 -0
- package/src/domains/knowledge/index.ts +10 -0
- package/src/domains/knowledge/resources.ts +537 -0
- package/src/domains/knowledge/tools.ts +174 -0
- package/src/domains/utilities/index.ts +6 -0
- package/src/domains/utilities/time/index.ts +5 -0
- package/src/domains/utilities/time/tools.ts +291 -0
- package/src/index.ts +211 -0
- package/src/services/agent-service.ts +273 -0
- package/src/services/claude-config-service.ts +252 -0
- package/src/services/config-service.ts +258 -0
- package/src/services/evaluation-service.ts +271 -0
- package/src/services/functional/evaluation-logic.ts +296 -0
- package/src/services/functional/file-processor.ts +273 -0
- package/src/services/functional/index.ts +12 -0
- package/src/services/index.ts +13 -0
- package/src/services/mcp-service.ts +432 -0
- package/src/services/memory.service.ts +476 -0
- package/src/services/search/base-indexer.ts +156 -0
- package/src/services/search/codebase-indexer-types.ts +38 -0
- package/src/services/search/codebase-indexer.ts +647 -0
- package/src/services/search/embeddings-provider.ts +455 -0
- package/src/services/search/embeddings.ts +316 -0
- package/src/services/search/functional-indexer.ts +323 -0
- package/src/services/search/index.ts +27 -0
- package/src/services/search/indexer.ts +380 -0
- package/src/services/search/knowledge-indexer.ts +422 -0
- package/src/services/search/semantic-search.ts +244 -0
- package/src/services/search/tfidf.ts +559 -0
- package/src/services/search/unified-search-service.ts +888 -0
- package/src/services/smart-config-service.ts +385 -0
- package/src/services/storage/cache-storage.ts +487 -0
- package/src/services/storage/drizzle-storage.ts +581 -0
- package/src/services/storage/index.ts +15 -0
- package/src/services/storage/lancedb-vector-storage.ts +494 -0
- package/src/services/storage/memory-storage.ts +268 -0
- package/src/services/storage/separated-storage.ts +467 -0
- package/src/services/storage/vector-storage.ts +13 -0
- package/src/shared/agents/index.ts +63 -0
- package/src/shared/files/index.ts +99 -0
- package/src/shared/index.ts +32 -0
- package/src/shared/logging/index.ts +24 -0
- package/src/shared/processing/index.ts +153 -0
- package/src/shared/types/index.ts +25 -0
- package/src/targets/claude-code.ts +574 -0
- package/src/targets/functional/claude-code-logic.ts +185 -0
- package/src/targets/functional/index.ts +6 -0
- package/src/targets/opencode.ts +529 -0
- package/src/types/agent.types.ts +32 -0
- package/src/types/api/batch.ts +108 -0
- package/src/types/api/errors.ts +118 -0
- package/src/types/api/index.ts +55 -0
- package/src/types/api/requests.ts +76 -0
- package/src/types/api/responses.ts +180 -0
- package/src/types/api/websockets.ts +85 -0
- package/src/types/api.types.ts +9 -0
- package/src/types/benchmark.ts +49 -0
- package/src/types/cli.types.ts +87 -0
- package/src/types/common.types.ts +35 -0
- package/src/types/database.types.ts +510 -0
- package/src/types/mcp-config.types.ts +448 -0
- package/src/types/mcp.types.ts +69 -0
- package/src/types/memory-types.ts +63 -0
- package/src/types/provider.types.ts +28 -0
- package/src/types/rule.types.ts +24 -0
- package/src/types/session.types.ts +214 -0
- package/src/types/target-config.types.ts +295 -0
- package/src/types/target.types.ts +140 -0
- package/src/types/todo.types.ts +25 -0
- package/src/types.ts +40 -0
- package/src/utils/advanced-tokenizer.ts +191 -0
- package/src/utils/agent-enhancer.ts +114 -0
- package/src/utils/ai-model-fetcher.ts +19 -0
- package/src/utils/async-file-operations.ts +516 -0
- package/src/utils/audio-player.ts +345 -0
- package/src/utils/cli-output.ts +266 -0
- package/src/utils/codebase-helpers.ts +211 -0
- package/src/utils/console-ui.ts +79 -0
- package/src/utils/database-errors.ts +140 -0
- package/src/utils/debug-logger.ts +49 -0
- package/src/utils/error-handler.ts +53 -0
- package/src/utils/file-operations.ts +310 -0
- package/src/utils/file-scanner.ts +259 -0
- package/src/utils/functional/array.ts +355 -0
- package/src/utils/functional/index.ts +15 -0
- package/src/utils/functional/object.ts +279 -0
- package/src/utils/functional/string.ts +281 -0
- package/src/utils/functional.ts +543 -0
- package/src/utils/help.ts +20 -0
- package/src/utils/immutable-cache.ts +106 -0
- package/src/utils/index.ts +78 -0
- package/src/utils/jsonc.ts +158 -0
- package/src/utils/logger.ts +396 -0
- package/src/utils/mcp-config.ts +249 -0
- package/src/utils/memory-tui.ts +414 -0
- package/src/utils/models-dev.ts +91 -0
- package/src/utils/notifications.ts +169 -0
- package/src/utils/object-utils.ts +51 -0
- package/src/utils/parallel-operations.ts +487 -0
- package/src/utils/paths.ts +143 -0
- package/src/utils/process-manager.ts +155 -0
- package/src/utils/prompts.ts +120 -0
- package/src/utils/search-tool-builder.ts +214 -0
- package/src/utils/secret-utils.ts +179 -0
- package/src/utils/security.ts +537 -0
- package/src/utils/session-manager.ts +168 -0
- package/src/utils/session-title.ts +87 -0
- package/src/utils/settings.ts +182 -0
- package/src/utils/simplified-errors.ts +410 -0
- package/src/utils/sync-utils.ts +159 -0
- package/src/utils/target-config.ts +570 -0
- package/src/utils/target-utils.ts +394 -0
- package/src/utils/template-engine.ts +94 -0
- package/src/utils/test-audio.ts +71 -0
- package/src/utils/todo-context.ts +46 -0
- package/src/utils/token-counter.ts +288 -0
- package/dist/index.d.ts +0 -10
- package/dist/index.js +0 -59554
- package/dist/lancedb.linux-x64-gnu-b7f0jgsz.node +0 -0
- package/dist/lancedb.linux-x64-musl-tgcv22rx.node +0 -0
- package/dist/shared/chunk-25dwp0dp.js +0 -89
- package/dist/shared/chunk-3pjb6063.js +0 -208
- package/dist/shared/chunk-4d6ydpw7.js +0 -2854
- package/dist/shared/chunk-4wjcadjk.js +0 -225
- package/dist/shared/chunk-5j4w74t6.js +0 -30
- package/dist/shared/chunk-5j8m3dh3.js +0 -58
- package/dist/shared/chunk-5thh3qem.js +0 -91
- package/dist/shared/chunk-6g9xy73m.js +0 -252
- package/dist/shared/chunk-7eq34c42.js +0 -23
- package/dist/shared/chunk-c2gwgx3r.js +0 -115
- package/dist/shared/chunk-cjd3mk4c.js +0 -1320
- package/dist/shared/chunk-g5cv6703.js +0 -368
- package/dist/shared/chunk-hpkhykhq.js +0 -574
- package/dist/shared/chunk-m2322pdk.js +0 -122
- package/dist/shared/chunk-nd5fdvaq.js +0 -26
- package/dist/shared/chunk-pgd3m6zf.js +0 -108
- package/dist/shared/chunk-qk8n91hw.js +0 -494
- package/dist/shared/chunk-rkkn8szp.js +0 -16855
- package/dist/shared/chunk-t16rfxh0.js +0 -61
- package/dist/shared/chunk-t4fbfa5v.js +0 -19
- package/dist/shared/chunk-t77h86w6.js +0 -276
- package/dist/shared/chunk-v0ez4aef.js +0 -71
- package/dist/shared/chunk-v29j2r3s.js +0 -32051
- package/dist/shared/chunk-vfbc6ew5.js +0 -765
- package/dist/shared/chunk-vmeqwm1c.js +0 -204
- package/dist/shared/chunk-x66eh37x.js +0 -137
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Models.dev API Integration
|
|
3
|
+
* Fetch model metadata as fallback source
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
export interface ModelMetadata {
|
|
7
|
+
id: string;
|
|
8
|
+
name?: string;
|
|
9
|
+
contextLength?: number;
|
|
10
|
+
maxOutput?: number;
|
|
11
|
+
inputPrice?: number;
|
|
12
|
+
outputPrice?: number;
|
|
13
|
+
provider?: string;
|
|
14
|
+
description?: string;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
interface ModelsDevResponse {
|
|
18
|
+
models: Array<{
|
|
19
|
+
id: string;
|
|
20
|
+
name?: string;
|
|
21
|
+
context_length?: number;
|
|
22
|
+
max_output?: number;
|
|
23
|
+
pricing?: {
|
|
24
|
+
input?: number;
|
|
25
|
+
output?: number;
|
|
26
|
+
};
|
|
27
|
+
provider?: string;
|
|
28
|
+
description?: string;
|
|
29
|
+
}>;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
let cachedModels: Map<string, ModelMetadata> | null = null;
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Fetch model metadata from models.dev
|
|
36
|
+
*/
|
|
37
|
+
export async function fetchModelsMetadata(): Promise<Map<string, ModelMetadata>> {
|
|
38
|
+
if (cachedModels) {
|
|
39
|
+
return cachedModels;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
try {
|
|
43
|
+
const response = await fetch('https://models.dev/api.json', {
|
|
44
|
+
headers: {
|
|
45
|
+
'User-Agent': 'sylphx-flow/1.0',
|
|
46
|
+
},
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
if (!response.ok) {
|
|
50
|
+
throw new Error(`Failed to fetch models.dev: ${response.status}`);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
const data = (await response.json()) as ModelsDevResponse;
|
|
54
|
+
|
|
55
|
+
const models = new Map<string, ModelMetadata>();
|
|
56
|
+
|
|
57
|
+
for (const model of data.models) {
|
|
58
|
+
models.set(model.id, {
|
|
59
|
+
id: model.id,
|
|
60
|
+
name: model.name,
|
|
61
|
+
contextLength: model.context_length,
|
|
62
|
+
maxOutput: model.max_output,
|
|
63
|
+
inputPrice: model.pricing?.input,
|
|
64
|
+
outputPrice: model.pricing?.output,
|
|
65
|
+
provider: model.provider,
|
|
66
|
+
description: model.description,
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
cachedModels = models;
|
|
71
|
+
return models;
|
|
72
|
+
} catch (error) {
|
|
73
|
+
console.error('Failed to fetch models.dev:', error);
|
|
74
|
+
return new Map();
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Get metadata for a specific model
|
|
80
|
+
*/
|
|
81
|
+
export async function getModelMetadata(modelId: string): Promise<ModelMetadata | null> {
|
|
82
|
+
const models = await fetchModelsMetadata();
|
|
83
|
+
return models.get(modelId) || null;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Clear cache (for testing or forcing refresh)
|
|
88
|
+
*/
|
|
89
|
+
export function clearModelsCache(): void {
|
|
90
|
+
cachedModels = null;
|
|
91
|
+
}
|
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Notification System
|
|
3
|
+
* Provides terminal and OS-level notifications for AI responses
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { playNotificationSound } from './audio-player.js';
|
|
7
|
+
|
|
8
|
+
// Terminal notification with sound
|
|
9
|
+
export function sendTerminalNotification(title: string, message: string, options?: {
|
|
10
|
+
sound?: boolean;
|
|
11
|
+
duration?: number;
|
|
12
|
+
}) {
|
|
13
|
+
const { sound = true, duration = 3000 } = options || {};
|
|
14
|
+
|
|
15
|
+
// Play system sound using cross-platform audio player
|
|
16
|
+
if (sound) {
|
|
17
|
+
playNotificationSound().catch((error) => {
|
|
18
|
+
// Fail silently - don't crash on sound errors
|
|
19
|
+
if (process.env.DEBUG) {
|
|
20
|
+
console.error('[Notifications] Failed to play sound:', error);
|
|
21
|
+
}
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
// Terminal bell only (no visual output to avoid interfering with Ink UI)
|
|
26
|
+
console.log('\u0007'); // Bell character
|
|
27
|
+
|
|
28
|
+
// Visual notification removed - interferes with Ink UI
|
|
29
|
+
// Terminal notifications in TUI apps should use Ink components instead
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
// OS-level notification using system APIs
|
|
33
|
+
export async function sendOSNotification(title: string, message: string, options?: {
|
|
34
|
+
icon?: string;
|
|
35
|
+
urgency?: 'low' | 'normal' | 'critical';
|
|
36
|
+
sound?: boolean;
|
|
37
|
+
timeout?: number;
|
|
38
|
+
}) {
|
|
39
|
+
const {
|
|
40
|
+
icon = '🌀', // Flow-themed spiral emoji for Sylphx Flow notifications
|
|
41
|
+
urgency = 'normal',
|
|
42
|
+
sound = true,
|
|
43
|
+
timeout = 5000
|
|
44
|
+
} = options || {};
|
|
45
|
+
|
|
46
|
+
try {
|
|
47
|
+
if (process.platform === 'darwin') {
|
|
48
|
+
// macOS: use osascript with simplified approach
|
|
49
|
+
const { spawn } = require('child_process');
|
|
50
|
+
|
|
51
|
+
await new Promise<void>((resolve, reject) => {
|
|
52
|
+
// Simple notification without complex escaping
|
|
53
|
+
const args = [
|
|
54
|
+
'-e', `display notification "${message.replace(/"/g, '\\"')}" with title "${title.replace(/"/g, '\\"')}"`
|
|
55
|
+
];
|
|
56
|
+
|
|
57
|
+
const proc = spawn('osascript', args, {
|
|
58
|
+
stdio: 'pipe',
|
|
59
|
+
env: { ...process.env, PATH: '/usr/bin:/bin:/usr/sbin:/sbin' }
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
let stderr = '';
|
|
63
|
+
proc.stderr?.on('data', (data) => {
|
|
64
|
+
stderr += data.toString();
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
proc.on('exit', (code) => {
|
|
68
|
+
if (code === 0) {
|
|
69
|
+
// Play sound separately if needed using cross-platform audio player
|
|
70
|
+
if (sound) {
|
|
71
|
+
playNotificationSound().catch(() => {
|
|
72
|
+
// Ignore sound errors
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
resolve();
|
|
76
|
+
} else {
|
|
77
|
+
reject(new Error(`osascript failed with code ${code}: ${stderr}`));
|
|
78
|
+
}
|
|
79
|
+
});
|
|
80
|
+
proc.on('error', reject);
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
} else if (process.platform === 'linux') {
|
|
84
|
+
// Linux: use notify-send
|
|
85
|
+
const { spawn } = require('child_process');
|
|
86
|
+
await new Promise<void>((resolve, reject) => {
|
|
87
|
+
const proc = spawn('notify-send', [
|
|
88
|
+
'--urgency', urgency,
|
|
89
|
+
'--icon', icon,
|
|
90
|
+
'--expire-time', timeout.toString(),
|
|
91
|
+
title,
|
|
92
|
+
message
|
|
93
|
+
]);
|
|
94
|
+
proc.on('exit', (code) => {
|
|
95
|
+
if (code === 0) resolve();
|
|
96
|
+
else reject(new Error(`notify-send failed with code ${code}`));
|
|
97
|
+
});
|
|
98
|
+
proc.on('error', reject);
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
} else if (process.platform === 'win32') {
|
|
102
|
+
// Windows: use PowerShell toast notifications
|
|
103
|
+
const { spawn } = require('child_process');
|
|
104
|
+
const powershellScript = `
|
|
105
|
+
Add-Type -AssemblyName System.Windows.Forms
|
|
106
|
+
$notification = New-Object System.Windows.Forms.NotifyIcon
|
|
107
|
+
$notification.Icon = [System.Drawing.SystemIcons]::Information
|
|
108
|
+
$notification.BalloonTipTitle = "${title}"
|
|
109
|
+
$notification.BalloonTipText = "${message}"
|
|
110
|
+
$notification.BalloonTipIcon = "Info"
|
|
111
|
+
$notification.Visible = $true
|
|
112
|
+
$notification.ShowBalloonTip(${timeout})
|
|
113
|
+
Start-Sleep -Milliseconds ${timeout + 1000}
|
|
114
|
+
$notification.Dispose()
|
|
115
|
+
`;
|
|
116
|
+
|
|
117
|
+
await new Promise<void>((resolve, reject) => {
|
|
118
|
+
const proc = spawn('powershell', ['-Command', powershellScript]);
|
|
119
|
+
proc.on('exit', (code) => {
|
|
120
|
+
if (code === 0) resolve();
|
|
121
|
+
else reject(new Error(`PowerShell failed with code ${code}`));
|
|
122
|
+
});
|
|
123
|
+
proc.on('error', reject);
|
|
124
|
+
});
|
|
125
|
+
}
|
|
126
|
+
} catch (error) {
|
|
127
|
+
console.warn('Failed to send OS notification:', error);
|
|
128
|
+
// Fallback to terminal notification
|
|
129
|
+
sendTerminalNotification(title, message, { sound: false });
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
// Combined notification - sends both terminal and OS notifications
|
|
134
|
+
export function sendNotification(
|
|
135
|
+
title: string,
|
|
136
|
+
message: string,
|
|
137
|
+
options?: {
|
|
138
|
+
osNotification?: boolean;
|
|
139
|
+
terminalNotification?: boolean;
|
|
140
|
+
sound?: boolean;
|
|
141
|
+
}
|
|
142
|
+
) {
|
|
143
|
+
const {
|
|
144
|
+
osNotification = true,
|
|
145
|
+
terminalNotification = true,
|
|
146
|
+
sound = true
|
|
147
|
+
} = options || {};
|
|
148
|
+
|
|
149
|
+
if (terminalNotification) {
|
|
150
|
+
sendTerminalNotification(title, message, { sound });
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
if (osNotification) {
|
|
154
|
+
sendOSNotification(title, message, { sound });
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
// Check if notifications are available
|
|
159
|
+
export async function checkNotificationSupport(): Promise<{
|
|
160
|
+
terminalSupported: boolean;
|
|
161
|
+
osSupported: boolean;
|
|
162
|
+
platform: string;
|
|
163
|
+
}> {
|
|
164
|
+
return {
|
|
165
|
+
terminalSupported: true, // Always supported
|
|
166
|
+
osSupported: process.platform === 'darwin' || process.platform === 'linux' || process.platform === 'win32',
|
|
167
|
+
platform: process.platform
|
|
168
|
+
};
|
|
169
|
+
}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Object utility functions
|
|
3
|
+
* Helper functions for working with nested objects
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Get a nested property from an object using dot notation
|
|
8
|
+
*/
|
|
9
|
+
export function getNestedProperty(obj: Record<string, unknown>, path: string): unknown {
|
|
10
|
+
const keys = path.split('.');
|
|
11
|
+
return keys.reduce((current, key) => current?.[key], obj);
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Set a nested property on an object using dot notation
|
|
16
|
+
*/
|
|
17
|
+
export function setNestedProperty(
|
|
18
|
+
obj: Record<string, unknown>,
|
|
19
|
+
path: string,
|
|
20
|
+
value: unknown
|
|
21
|
+
): void {
|
|
22
|
+
const keys = path.split('.');
|
|
23
|
+
const lastKey = keys.pop()!;
|
|
24
|
+
|
|
25
|
+
const target = keys.reduce((current, key) => {
|
|
26
|
+
if (current[key] === undefined || typeof current[key] !== 'object') {
|
|
27
|
+
current[key] = {};
|
|
28
|
+
}
|
|
29
|
+
return current[key] as Record<string, unknown>;
|
|
30
|
+
}, obj);
|
|
31
|
+
|
|
32
|
+
target[lastKey] = value;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Delete a nested property from an object using dot notation
|
|
37
|
+
*/
|
|
38
|
+
export function deleteNestedProperty(obj: Record<string, unknown>, path: string): void {
|
|
39
|
+
const keys = path.split('.');
|
|
40
|
+
const lastKey = keys.pop()!;
|
|
41
|
+
|
|
42
|
+
const target = keys.reduce((current, key) => {
|
|
43
|
+
if (current[key] === undefined || typeof current[key] !== 'object') {
|
|
44
|
+
current[key] = {};
|
|
45
|
+
return current[key] as Record<string, unknown>;
|
|
46
|
+
}
|
|
47
|
+
return current[key] as Record<string, unknown>;
|
|
48
|
+
}, obj);
|
|
49
|
+
|
|
50
|
+
delete target[lastKey];
|
|
51
|
+
}
|