@vee-stack/delta-cli 2.0.4 → 2.0.5

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.
Files changed (135) hide show
  1. package/dist/analyzer/commands/analyze.js +260 -0
  2. package/dist/analyzer/commands/config.js +83 -0
  3. package/dist/analyzer/commands/report.js +38 -0
  4. package/dist/analyzer/generators/report.generator.js +123 -0
  5. package/dist/analyzer/index.js +44 -0
  6. package/dist/analyzer/scanners/project.scanner.js +92 -0
  7. package/dist/analyzer/validators/contracts.validator.js +42 -0
  8. package/dist/analyzer/validators/maintainability.validator.js +40 -0
  9. package/dist/analyzer/validators/observability.validator.js +39 -0
  10. package/dist/analyzer/validators/performance.validator.js +42 -0
  11. package/dist/analyzer/validators/security.validator.js +66 -0
  12. package/dist/analyzer/validators/soc.validator.js +75 -0
  13. package/dist/apps/cli/src/analyzer/commands/analyze.js +256 -0
  14. package/dist/apps/cli/src/analyzer/commands/config.js +83 -0
  15. package/dist/apps/cli/src/analyzer/commands/report.js +38 -0
  16. package/dist/apps/cli/src/analyzer/generators/report.generator.js +123 -0
  17. package/dist/apps/cli/src/analyzer/index.js +44 -0
  18. package/dist/apps/cli/src/analyzer/scanners/project.scanner.js +92 -0
  19. package/dist/apps/cli/src/analyzer/validators/contracts.validator.js +42 -0
  20. package/dist/apps/cli/src/analyzer/validators/maintainability.validator.js +40 -0
  21. package/dist/apps/cli/src/analyzer/validators/observability.validator.js +39 -0
  22. package/dist/apps/cli/src/analyzer/validators/performance.validator.js +42 -0
  23. package/dist/apps/cli/src/analyzer/validators/security.validator.js +66 -0
  24. package/dist/apps/cli/src/analyzer/validators/soc.validator.js +75 -0
  25. package/dist/apps/cli/src/auth/secure-auth.js +312 -0
  26. package/dist/apps/cli/src/commands/analyze.js +286 -0
  27. package/dist/apps/cli/src/commands/auth-new.js +37 -0
  28. package/dist/apps/cli/src/commands/auth.js +122 -0
  29. package/dist/apps/cli/src/commands/config.js +49 -0
  30. package/dist/apps/cli/src/commands/deploy.js +6 -0
  31. package/dist/apps/cli/src/commands/init.js +47 -0
  32. package/dist/apps/cli/src/commands/logout.js +23 -0
  33. package/dist/apps/cli/src/commands/plugins.js +21 -0
  34. package/dist/apps/cli/src/commands/status.js +80 -0
  35. package/dist/apps/cli/src/commands/sync.js +6 -0
  36. package/dist/apps/cli/src/commands/whoami.js +115 -0
  37. package/dist/apps/cli/src/components/Dashboard.js +168 -0
  38. package/dist/apps/cli/src/components/DeltaApp.js +56 -0
  39. package/dist/apps/cli/src/components/UnifiedManager.js +324 -0
  40. package/dist/apps/cli/src/core/audit.js +184 -0
  41. package/dist/apps/cli/src/core/completion.js +294 -0
  42. package/dist/apps/cli/src/core/contracts.js +6 -0
  43. package/dist/apps/cli/src/core/engine.js +124 -0
  44. package/dist/apps/cli/src/core/exit-codes.js +71 -0
  45. package/dist/apps/cli/src/core/hooks.js +181 -0
  46. package/dist/apps/cli/src/core/index.js +7 -0
  47. package/dist/apps/cli/src/core/policy.js +115 -0
  48. package/dist/apps/cli/src/core/profiles.js +161 -0
  49. package/dist/apps/cli/src/core/wizard.js +203 -0
  50. package/dist/apps/cli/src/index.js +636 -0
  51. package/dist/apps/cli/src/interactive/index.js +11 -0
  52. package/dist/apps/cli/src/plugins/GitStatusPlugin.js +99 -0
  53. package/dist/apps/cli/src/providers/ai-provider.js +74 -0
  54. package/dist/apps/cli/src/providers/local-provider.js +302 -0
  55. package/dist/apps/cli/src/providers/remote-provider.js +100 -0
  56. package/dist/apps/cli/src/types/api.js +3 -0
  57. package/dist/apps/cli/src/ui.js +219 -0
  58. package/dist/apps/cli/src/welcome.js +81 -0
  59. package/dist/auth/secure-auth.js +418 -0
  60. package/dist/bundle.js +45 -45
  61. package/dist/commands/analyze.js +363 -0
  62. package/dist/commands/auth-new.js +37 -0
  63. package/dist/commands/auth.js +133 -0
  64. package/dist/commands/config.js +50 -0
  65. package/dist/commands/deploy.js +6 -0
  66. package/dist/commands/init.js +47 -0
  67. package/dist/commands/logout.js +30 -0
  68. package/dist/commands/plugins.js +21 -0
  69. package/dist/commands/status.js +82 -0
  70. package/dist/commands/sync.js +6 -0
  71. package/dist/commands/whoami.js +71 -0
  72. package/dist/components/Dashboard.js +169 -0
  73. package/dist/components/DeltaApp.js +57 -0
  74. package/dist/components/UnifiedManager.js +344 -0
  75. package/dist/core/audit.js +184 -0
  76. package/dist/core/completion.js +294 -0
  77. package/dist/core/contracts.js +6 -0
  78. package/dist/core/engine.js +124 -0
  79. package/dist/core/exit-codes.js +71 -0
  80. package/dist/core/hooks.js +181 -0
  81. package/dist/core/index.js +7 -0
  82. package/dist/core/policy.js +115 -0
  83. package/dist/core/profiles.js +161 -0
  84. package/dist/core/wizard.js +203 -0
  85. package/dist/index.js +387 -0
  86. package/dist/interactive/index.js +11 -0
  87. package/dist/packages/domain/src/constitution/contracts/index.js +43 -0
  88. package/dist/packages/domain/src/constitution/contracts/ts.rules.js +268 -0
  89. package/dist/packages/domain/src/constitution/index.js +139 -0
  90. package/dist/packages/domain/src/constitution/maintainability/index.js +43 -0
  91. package/dist/packages/domain/src/constitution/maintainability/ts.rules.js +344 -0
  92. package/dist/packages/domain/src/constitution/observability/index.js +43 -0
  93. package/dist/packages/domain/src/constitution/observability/ts.rules.js +307 -0
  94. package/dist/packages/domain/src/constitution/performance/index.js +43 -0
  95. package/dist/packages/domain/src/constitution/performance/ts.rules.js +325 -0
  96. package/dist/packages/domain/src/constitution/security/index.js +50 -0
  97. package/dist/packages/domain/src/constitution/security/ts.rules.js +267 -0
  98. package/dist/packages/domain/src/constitution/soc/index.js +43 -0
  99. package/dist/packages/domain/src/constitution/soc/ts.rules.js +360 -0
  100. package/dist/packages/domain/src/contracts/analysis.contract.js +18 -0
  101. package/dist/packages/domain/src/contracts/index.js +7 -0
  102. package/dist/packages/domain/src/contracts/projects.contract.js +18 -0
  103. package/dist/packages/domain/src/control/registry/rules.registry.js +29 -0
  104. package/dist/packages/domain/src/control/schemas/policies.js +6 -0
  105. package/dist/packages/domain/src/core/analysis/discovery.js +163 -0
  106. package/dist/packages/domain/src/core/analysis/engine.contract.js +298 -0
  107. package/dist/packages/domain/src/core/analysis/engine.js +77 -0
  108. package/dist/packages/domain/src/core/analysis/index.js +14 -0
  109. package/dist/packages/domain/src/core/analysis/orchestrator.js +242 -0
  110. package/dist/packages/domain/src/core/comparison/engine.js +29 -0
  111. package/dist/packages/domain/src/core/comparison/index.js +5 -0
  112. package/dist/packages/domain/src/core/documentation/index.js +5 -0
  113. package/dist/packages/domain/src/core/documentation/pipeline.js +41 -0
  114. package/dist/packages/domain/src/core/fs/adapter.js +111 -0
  115. package/dist/packages/domain/src/core/fs/index.js +5 -0
  116. package/dist/packages/domain/src/core/parser/unified-parser.js +166 -0
  117. package/dist/packages/domain/src/index.js +33 -0
  118. package/dist/packages/domain/src/plugin/registry.js +195 -0
  119. package/dist/packages/domain/src/plugin/types.js +6 -0
  120. package/dist/packages/domain/src/ports/analysis.engine.js +7 -0
  121. package/dist/packages/domain/src/ports/audit.logger.js +7 -0
  122. package/dist/packages/domain/src/ports/project.repository.js +7 -0
  123. package/dist/packages/domain/src/rules/index.js +134 -0
  124. package/dist/packages/domain/src/types/analysis.js +6 -0
  125. package/dist/packages/domain/src/types/errors.js +53 -0
  126. package/dist/packages/domain/src/types/fs.js +6 -0
  127. package/dist/packages/domain/src/types/index.js +7 -0
  128. package/dist/plugins/GitStatusPlugin.js +93 -0
  129. package/dist/providers/ai-provider.js +74 -0
  130. package/dist/providers/local-provider.js +304 -0
  131. package/dist/providers/remote-provider.js +100 -0
  132. package/dist/types/api.js +3 -0
  133. package/dist/ui.js +219 -0
  134. package/dist/welcome.js +81 -0
  135. package/package.json +18 -18
@@ -0,0 +1,344 @@
1
+ import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
2
+ /**
3
+ * Delta Unified Manager - Professional TUI Dashboard
4
+ * World-class integrated terminal interface
5
+ * Design matching GUI screenshot with sidebar, cards, and logs
6
+ * Features: Keyboard Shortcuts, Log Filtering, Persistent State, Plugin System
7
+ */
8
+ import React, { useState, useEffect, useCallback, useRef } from 'react';
9
+ import { Box, Text, useApp, useInput } from 'ink';
10
+ import Spinner from 'ink-spinner';
11
+ import { spawn } from 'child_process';
12
+ import { platform, homedir } from 'os';
13
+ import { join, dirname } from 'path';
14
+ import { readFileSync, writeFileSync, existsSync, mkdirSync } from 'fs';
15
+ import { PluginRegistry } from '@delta/domain';
16
+ import { GitStatusPlugin } from '../plugins/GitStatusPlugin.js';
17
+ const CONFIG_DIR = join(homedir(), '.delta');
18
+ const STATE_FILE = join(CONFIG_DIR, 'manager-state.json');
19
+ const MENU_ITEMS = [
20
+ { id: 'build', num: '1', label: 'Build All Apps', icon: '🔨' },
21
+ { id: 'cli', num: '2', label: 'CLI Dev Server', icon: '🖥️' },
22
+ { id: 'web', num: '3', label: 'Web Dev Server', icon: '🌐' },
23
+ { id: 'docs', num: '4', label: 'Documentation', icon: '📖' },
24
+ { id: 'test', num: '5', label: 'Run Tests', icon: '🧪' },
25
+ { id: 'clean', num: '6', label: 'Clean Build', icon: '🧹' },
26
+ { id: 'install', num: '7', label: 'Install Deps', icon: '📦' },
27
+ { id: 'quit', num: '8', label: 'Quit', icon: '❌' },
28
+ ];
29
+ const SHORTCUTS = [
30
+ { key: '?', desc: 'Show help' },
31
+ { key: '/', desc: 'Search/Filter logs' },
32
+ { key: 'f', desc: 'Toggle log filters' },
33
+ { key: 'g', desc: 'Refresh Git Status (Plugin)' },
34
+ { key: '↑↓', desc: 'Navigate menu' },
35
+ { key: 'Enter', desc: 'Select/Execute' },
36
+ { key: 'Esc / Q', desc: 'Quit/Back' },
37
+ { key: '1-8', desc: 'Quick menu access' },
38
+ ];
39
+ const getSeverityFromType = (type) => {
40
+ switch (type) {
41
+ case 'error': return 'high';
42
+ case 'warning': return 'medium';
43
+ case 'success': return 'low';
44
+ default: return 'low';
45
+ }
46
+ };
47
+ const StatusBadge = ({ status, progress }) => {
48
+ const config = {
49
+ stopped: { color: 'gray', text: 'STOPPED', icon: '○' },
50
+ running: { color: 'green', text: 'RUNNING', icon: '●' },
51
+ error: { color: 'red', text: 'ERROR', icon: '✕' },
52
+ building: { color: 'yellow', text: 'BUILDING', icon: '◐' },
53
+ };
54
+ const { color, text, icon } = config[status];
55
+ return (_jsx(Text, { color: color, children: status === 'building' && progress !== undefined ? (_jsxs(_Fragment, { children: [_jsx(Spinner, { type: "dots" }), " ", text, " ", progress, "%"] })) : (_jsxs(_Fragment, { children: [icon, " ", text] })) }));
56
+ };
57
+ const ProgressBar = ({ progress, width = 15 }) => {
58
+ const filled = Math.floor((progress / 100) * width);
59
+ const empty = width - filled;
60
+ return (_jsxs(Text, { children: [_jsx(Text, { color: "green", children: '█'.repeat(filled) }), _jsx(Text, { color: "gray", children: '░'.repeat(empty) }), _jsxs(Text, { color: "cyan", children: [" ", progress, "%"] })] }));
61
+ };
62
+ const ServiceCard = ({ service }) => {
63
+ return (_jsxs(Box, { flexDirection: "column", borderStyle: "round", borderColor: service.status === 'running' ? 'green' : service.status === 'error' ? 'red' : 'gray', paddingX: 2, paddingY: 1, width: 40, children: [_jsx(Text, { bold: true, color: "white", children: service.name }), _jsx(Box, { marginY: 1, children: _jsx(StatusBadge, { status: service.status, progress: service.progress }) }), service.port && service.status === 'running' && (_jsxs(Box, { children: [_jsx(Text, { color: "cyan", children: "Port: " }), _jsx(Text, { bold: true, color: "green", children: service.port })] })), service.status === 'building' && service.progress > 0 && (_jsx(Box, { marginY: 1, children: _jsx(ProgressBar, { progress: service.progress }) })), _jsx(Text, { dimColor: true, children: service.message })] }));
64
+ };
65
+ const LogEntry = ({ entry }) => {
66
+ const colors = { info: 'white', success: 'green', error: 'red', warning: 'yellow' };
67
+ const icons = { info: 'ℹ', success: '✓', error: '✗', warning: '⚠' };
68
+ return (_jsxs(Box, { children: [_jsxs(Text, { dimColor: true, children: ["[", entry.timestamp, "] "] }), _jsxs(Text, { color: colors[entry.type], children: [icons[entry.type], " "] }), _jsxs(Text, { children: [entry.service, ": ", entry.message] })] }));
69
+ };
70
+ const MenuItem = ({ item, isSelected }) => {
71
+ return (_jsxs(Box, { paddingX: 1, width: 28, children: [_jsxs(Text, { color: isSelected ? 'cyan' : 'gray', bold: isSelected, children: [isSelected ? '❯ ' : ' ', isSelected ? '' : ' '] }), _jsx(Text, { color: isSelected ? 'cyan' : 'cyan', bold: isSelected, children: item.num }), _jsx(Text, { children: " " }), _jsx(Text, { color: isSelected ? 'white' : 'gray', children: item.icon }), _jsx(Text, { children: " " }), _jsx(Text, { color: isSelected ? 'white' : 'gray', bold: isSelected, children: item.label }), _jsx(Text, { children: ' '.repeat(28 - item.label.length - 4) })] }));
72
+ };
73
+ const HelpModal = ({ onClose }) => {
74
+ useInput((_, key) => {
75
+ if (key.escape || key.return)
76
+ onClose();
77
+ });
78
+ return (_jsxs(Box, { flexDirection: "column", borderStyle: "round", borderColor: "cyan", paddingX: 2, paddingY: 1, width: 50, children: [_jsx(Text, { bold: true, color: "cyan", children: "\u2328\uFE0F Keyboard Shortcuts" }), _jsx(Box, { marginY: 1 }), SHORTCUTS.map((s, i) => (_jsxs(Box, { children: [_jsx(Text, { color: "yellow", bold: true, children: s.key.padEnd(10) }), _jsx(Text, { color: "white", children: s.desc })] }, i))), _jsx(Box, { marginY: 1 }), _jsx(Text, { dimColor: true, children: "Press Enter or Esc to close" })] }));
79
+ };
80
+ const FilterBar = ({ severity, source, isActive }) => {
81
+ const severities = ['all', 'high', 'medium', 'low'];
82
+ const sources = ['all', 'CLI', 'Web', 'Tests', 'Build', 'System'];
83
+ return (_jsx(Box, { flexDirection: "column", marginBottom: 1, children: _jsxs(Box, { children: [_jsx(Text, { color: isActive ? 'cyan' : 'gray', bold: isActive, children: "Filter: " }), _jsx(Text, { color: "gray", children: "Severity[" }), severities.map((s, i) => (_jsxs(Text, { color: severity === s ? 'green' : 'gray', bold: severity === s, children: [s, i < severities.length - 1 ? '|' : ''] }, s))), _jsx(Text, { color: "gray", children: "] Source[" }), sources.map((s, i) => (_jsxs(Text, { color: source === s ? 'green' : 'gray', bold: source === s, children: [s, i < sources.length - 1 ? '|' : ''] }, s))), _jsx(Text, { color: "gray", children: "]" })] }) }));
84
+ };
85
+ const loadUserState = () => {
86
+ try {
87
+ if (existsSync(STATE_FILE)) {
88
+ return JSON.parse(readFileSync(STATE_FILE, 'utf-8'));
89
+ }
90
+ }
91
+ catch (err) {
92
+ void err;
93
+ }
94
+ return null;
95
+ };
96
+ const saveUserState = (state) => {
97
+ try {
98
+ if (!existsSync(CONFIG_DIR))
99
+ mkdirSync(CONFIG_DIR, { recursive: true });
100
+ writeFileSync(STATE_FILE, JSON.stringify(state, null, 2));
101
+ }
102
+ catch (err) {
103
+ void err;
104
+ }
105
+ };
106
+ export const UnifiedManager = () => {
107
+ const { exit } = useApp();
108
+ const [selectedIndex, setSelectedIndex] = useState(0);
109
+ const [logs, setLogs] = useState([]);
110
+ const [showHelp, setShowHelp] = useState(false);
111
+ const [searchMode, setSearchMode] = useState(false);
112
+ const [filterMode, setFilterMode] = useState(false);
113
+ const [searchQuery, setSearchQuery] = useState('');
114
+ const [severityFilter, setSeverityFilter] = useState('all');
115
+ const [sourceFilter, setSourceFilter] = useState('all');
116
+ const [services, setServices] = useState([
117
+ { id: 'cli', name: 'CLI Dev Server', port: undefined, status: 'stopped', message: 'Ready to start', progress: 0 },
118
+ { id: 'web', name: 'Web Dev Server', port: undefined, status: 'stopped', message: 'Ready to start', progress: 0 },
119
+ ]);
120
+ const serviceProcesses = React.useRef(new Map());
121
+ const pluginRegistryRef = useRef(null);
122
+ // Create plugin context
123
+ const createPluginContext = useCallback(() => ({
124
+ addLog: (service, message, type) => {
125
+ const timestamp = new Date().toLocaleTimeString('en-US', { hour12: false });
126
+ const severity = getSeverityFromType(type);
127
+ setLogs(prev => [...prev.slice(-50), { timestamp, service, message, type, severity }]);
128
+ },
129
+ getServices: () => services.map(s => ({ id: s.id, status: s.status, port: s.port })),
130
+ getLogFilters: () => ({ severity: severityFilter, source: sourceFilter }),
131
+ registerShortcut: () => { },
132
+ getSettings: () => ({}),
133
+ saveSettings: () => { },
134
+ }), [services, severityFilter, sourceFilter]);
135
+ // Initialize plugin system
136
+ useEffect(() => {
137
+ const context = createPluginContext();
138
+ const registry = new PluginRegistry(context);
139
+ pluginRegistryRef.current = registry;
140
+ registry.register(new GitStatusPlugin(context)).catch(() => { });
141
+ }, [createPluginContext]);
142
+ useEffect(() => {
143
+ const saved = loadUserState();
144
+ if (saved) {
145
+ setSeverityFilter(saved.logFilters.severity);
146
+ setSourceFilter(saved.logFilters.source);
147
+ setSearchQuery(saved.lastSearchQuery);
148
+ }
149
+ }, []);
150
+ useEffect(() => {
151
+ saveUserState({
152
+ selectedView: 'dashboard',
153
+ logFilters: { severity: severityFilter, source: sourceFilter },
154
+ lastSearchQuery: searchQuery,
155
+ });
156
+ }, [severityFilter, sourceFilter, searchQuery]);
157
+ const addLog = useCallback((service, message, type = 'info') => {
158
+ const timestamp = new Date().toLocaleTimeString('en-US', { hour12: false });
159
+ const severity = getSeverityFromType(type);
160
+ setLogs(prev => [...prev.slice(-50), { timestamp, service, message, type, severity }]);
161
+ }, []);
162
+ const filteredLogs = logs.filter(entry => {
163
+ if (severityFilter !== 'all' && entry.severity !== severityFilter)
164
+ return false;
165
+ if (sourceFilter !== 'all' && entry.service !== sourceFilter)
166
+ return false;
167
+ if (searchQuery && !entry.message.toLowerCase().includes(searchQuery.toLowerCase()))
168
+ return false;
169
+ return true;
170
+ });
171
+ const startService = useCallback((serviceId) => {
172
+ const service = services.find(s => s.id === serviceId);
173
+ if (!service)
174
+ return;
175
+ setServices(prev => prev.map(s => s.id === serviceId ? { ...s, status: 'building', message: 'Starting...', progress: 0 } : s));
176
+ addLog(serviceId, 'Starting service...', 'info');
177
+ let progress = 0;
178
+ const progressInterval = setInterval(() => {
179
+ progress += 10;
180
+ setServices(prev => prev.map(s => s.id === serviceId ? { ...s, progress } : s));
181
+ if (progress >= 100)
182
+ clearInterval(progressInterval);
183
+ }, 150);
184
+ // Find monorepo root by looking for pnpm-workspace.yaml
185
+ const findRoot = (startPath) => {
186
+ let current = startPath;
187
+ while (current !== dirname(current)) {
188
+ if (existsSync(join(current, 'pnpm-workspace.yaml'))) {
189
+ return current;
190
+ }
191
+ current = dirname(current);
192
+ }
193
+ return process.cwd();
194
+ };
195
+ const rootDir = findRoot(process.cwd());
196
+ const isWindows = platform() === 'win32';
197
+ const proc = spawn(isWindows ? 'pnpm.cmd' : 'pnpm', ['dev'], {
198
+ cwd: join(rootDir, serviceId === 'cli' ? 'apps/cli' : 'apps/web'),
199
+ stdio: ['ignore', 'pipe', 'pipe'],
200
+ });
201
+ serviceProcesses.current.set(serviceId, proc);
202
+ proc.stdout?.on('data', (data) => {
203
+ const output = data.toString().trim();
204
+ const portMatch = output.match(/localhost:(\d+)/) || output.match(/:(\d+)/);
205
+ if (portMatch) {
206
+ const port = parseInt(portMatch[1]);
207
+ setServices(prev => prev.map(s => s.id === serviceId ? { ...s, status: 'running', port, message: 'Watching files...', progress: 100 } : s));
208
+ addLog(serviceId, `Server running on port ${port}`, 'success');
209
+ }
210
+ });
211
+ proc.stderr?.on('data', (data) => addLog(serviceId, data.toString().trim(), 'error'));
212
+ proc.on('exit', (code) => {
213
+ clearInterval(progressInterval);
214
+ setServices(prev => prev.map(s => s.id === serviceId ? { ...s, status: code === 0 ? 'stopped' : 'error', progress: 0, message: 'Stopped' } : s));
215
+ serviceProcesses.current.delete(serviceId);
216
+ addLog(serviceId, code === 0 ? 'Service stopped' : 'Service crashed', code === 0 ? 'info' : 'error');
217
+ });
218
+ }, [services, addLog]);
219
+ const stopService = useCallback((serviceId) => {
220
+ const proc = serviceProcesses.current.get(serviceId);
221
+ if (proc) {
222
+ proc.kill('SIGTERM');
223
+ serviceProcesses.current.delete(serviceId);
224
+ }
225
+ setServices(prev => prev.map(s => s.id === serviceId ? { ...s, status: 'stopped', port: undefined, message: 'Stopped', progress: 0 } : s));
226
+ addLog(serviceId, 'Service stopped', 'info');
227
+ }, [addLog]);
228
+ const buildAll = useCallback(() => {
229
+ addLog('BUILD', 'Starting build process...', 'info');
230
+ ['CLI', 'Web'].forEach((step, i) => {
231
+ setTimeout(() => {
232
+ addLog('BUILD', `${step} Build: SUCCESS`, 'success');
233
+ if (i === 1)
234
+ addLog('BUILD', 'All builds completed successfully!', 'success');
235
+ }, (i + 1) * 1500);
236
+ });
237
+ }, [addLog]);
238
+ useInput((input, key) => {
239
+ if (showHelp)
240
+ return;
241
+ if (searchMode) {
242
+ if (key.escape) {
243
+ setSearchMode(false);
244
+ setSearchQuery('');
245
+ return;
246
+ }
247
+ if (key.return) {
248
+ setSearchMode(false);
249
+ return;
250
+ }
251
+ if (key.backspace || key.delete) {
252
+ setSearchQuery(q => q.slice(0, -1));
253
+ return;
254
+ }
255
+ if (input && !key.ctrl && !key.meta) {
256
+ setSearchQuery(q => q + input);
257
+ return;
258
+ }
259
+ return;
260
+ }
261
+ if (filterMode) {
262
+ if (key.escape) {
263
+ setFilterMode(false);
264
+ return;
265
+ }
266
+ if (input === 's') {
267
+ const severities = ['all', 'high', 'medium', 'low'];
268
+ setSeverityFilter(prev => severities[(severities.indexOf(prev) + 1) % severities.length]);
269
+ return;
270
+ }
271
+ if (input === 'r') {
272
+ const sources = ['all', 'CLI', 'Web', 'Tests', 'Build', 'System'];
273
+ setSourceFilter(prev => sources[(sources.indexOf(prev) + 1) % sources.length]);
274
+ return;
275
+ }
276
+ if (key.return) {
277
+ setFilterMode(false);
278
+ return;
279
+ }
280
+ return;
281
+ }
282
+ if (input === '?') {
283
+ setShowHelp(true);
284
+ return;
285
+ }
286
+ if (input === '/') {
287
+ setSearchMode(true);
288
+ return;
289
+ }
290
+ if (input === 'g') {
291
+ // GitStatusPlugin shortcut
292
+ const registry = pluginRegistryRef.current;
293
+ if (registry) {
294
+ registry.executeCommand('git-status', 'refresh').catch(() => { });
295
+ }
296
+ return;
297
+ }
298
+ if (input === 'q' || key.escape) {
299
+ serviceProcesses.current.forEach(proc => proc.kill('SIGTERM'));
300
+ exit();
301
+ }
302
+ if (input >= '1' && input <= '8') {
303
+ const index = parseInt(input) - 1;
304
+ if (index < MENU_ITEMS.length)
305
+ setSelectedIndex(index);
306
+ return;
307
+ }
308
+ if (key.upArrow)
309
+ setSelectedIndex(i => Math.max(0, i - 1));
310
+ if (key.downArrow)
311
+ setSelectedIndex(i => Math.min(MENU_ITEMS.length - 1, i + 1));
312
+ if (key.return) {
313
+ const item = MENU_ITEMS[selectedIndex];
314
+ switch (item.id) {
315
+ case 'build':
316
+ buildAll();
317
+ break;
318
+ case 'cli':
319
+ {
320
+ const cliService = services.find(s => s.id === 'cli');
321
+ cliService?.status === 'running' ? stopService('cli') : startService('cli');
322
+ }
323
+ break;
324
+ case 'web':
325
+ {
326
+ const webService = services.find(s => s.id === 'web');
327
+ webService?.status === 'running' ? stopService('web') : startService('web');
328
+ }
329
+ break;
330
+ case 'quit':
331
+ serviceProcesses.current.forEach(proc => proc.kill('SIGTERM'));
332
+ exit();
333
+ break;
334
+ }
335
+ }
336
+ });
337
+ useEffect(() => { addLog('SYSTEM', 'Delta Unified Manager started', 'info'); }, []);
338
+ if (showHelp) {
339
+ return (_jsx(Box, { flexDirection: "column", height: 28, justifyContent: "center", alignItems: "center", children: _jsx(HelpModal, { onClose: () => setShowHelp(false) }) }));
340
+ }
341
+ return (_jsxs(Box, { flexDirection: "column", height: 28, children: [_jsxs(Box, { justifyContent: "space-between", paddingX: 1, paddingY: 0, children: [_jsx(Text, { backgroundColor: "blue", bold: true, color: "white", children: " \uD83D\uDE80 Delta Project Manager " }), _jsx(Text, { backgroundColor: "blue", color: "white", children: " v2.0 " })] }), _jsxs(Box, { flexGrow: 1, children: [_jsx(Box, { flexDirection: "column", width: 30, borderStyle: "single", borderColor: "gray", paddingY: 1, children: MENU_ITEMS.map((item, index) => (_jsx(MenuItem, { item: item, isSelected: index === selectedIndex }, item.id))) }), _jsxs(Box, { flexDirection: "column", flexGrow: 1, paddingX: 1, paddingY: 1, children: [_jsxs(Box, { flexDirection: "row", gap: 2, marginBottom: 1, children: [_jsx(ServiceCard, { service: services[0] }), _jsx(ServiceCard, { service: services[1] })] }), _jsxs(Box, { flexGrow: 1, flexDirection: "column", borderStyle: "round", borderColor: filterMode || searchMode ? 'cyan' : 'gray', paddingX: 1, children: [_jsxs(Box, { marginBottom: 1, children: [_jsx(Text, { bold: true, color: "cyan", children: "\uD83D\uDCCB Build & Test Logs" }), searchMode && _jsxs(Text, { color: "yellow", children: [" [Search: ", searchQuery, "_]"] }), filterMode && _jsx(Text, { color: "yellow", children: " [Filter Mode - s:severity r:source Enter:done]" })] }), _jsx(FilterBar, { severity: severityFilter, source: sourceFilter, isActive: filterMode }), _jsx(Box, { flexDirection: "column", overflow: "hidden", children: filteredLogs.length === 0 ? (_jsx(Text, { dimColor: true, children: logs.length === 0 ? 'No activity yet...' : 'No logs match current filters' })) : (filteredLogs.slice(-15).map((entry, i) => _jsx(LogEntry, { entry: entry }, i))) })] })] })] }), _jsxs(Box, { justifyContent: "space-between", paddingX: 1, paddingY: 0, children: [_jsxs(Box, { children: [_jsx(Text, { backgroundColor: "gray", color: "white", children: "[" }), _jsx(Text, { backgroundColor: "gray", color: "cyan", children: "\u2191\u2193" }), _jsx(Text, { backgroundColor: "gray", color: "white", children: "] Navigate " }), _jsx(Text, { backgroundColor: "gray", color: "white", children: "[" }), _jsx(Text, { backgroundColor: "gray", color: "cyan", children: "Enter" }), _jsx(Text, { backgroundColor: "gray", color: "white", children: "] Select " }), _jsx(Text, { backgroundColor: "gray", color: "white", children: "[" }), _jsx(Text, { backgroundColor: "gray", color: "cyan", children: "?" }), _jsx(Text, { backgroundColor: "gray", color: "white", children: "] Help " }), _jsx(Text, { backgroundColor: "gray", color: "white", children: "[" }), _jsx(Text, { backgroundColor: "gray", color: "cyan", children: "Q" }), _jsx(Text, { backgroundColor: "gray", color: "white", children: "] Quit" })] }), _jsxs(Box, { children: [_jsx(Text, { backgroundColor: "gray", color: "white", children: " CLI: " }), _jsx(Text, { backgroundColor: "gray", color: services[0].status === 'running' ? 'green' : 'gray', children: services[0].port ? `localhost:${services[0].port} ✓` : '○' }), _jsx(Text, { backgroundColor: "gray", color: "white", children: " | Web: " }), _jsx(Text, { backgroundColor: "gray", color: services[1].status === 'running' ? 'green' : 'gray', children: services[1].port ? `localhost:${services[1].port} ✓` : '○' }), _jsxs(Text, { backgroundColor: "gray", color: "white", children: [" | ", platform()] })] })] })] }));
342
+ };
343
+ export default UnifiedManager;
344
+ //# sourceMappingURL=UnifiedManager.js.map
@@ -0,0 +1,184 @@
1
+ /**
2
+ * Audit Logger for Delta CLI
3
+ * Tracks all commands, results, and performance metrics
4
+ * Enterprise-grade logging for compliance and debugging
5
+ */
6
+ import { promises as fs } from 'fs';
7
+ import { homedir } from 'os';
8
+ import { join } from 'path';
9
+ const DEFAULT_CONFIG = {
10
+ enabled: true,
11
+ logLevel: 'standard',
12
+ retentionDays: 30,
13
+ maxEntries: 10000,
14
+ includeMetadata: true,
15
+ };
16
+ const AUDIT_DIR = join(homedir(), '.delta', 'audit');
17
+ const AUDIT_FILE = join(AUDIT_DIR, 'commands.jsonl');
18
+ const CONFIG_FILE = join(AUDIT_DIR, 'config.json');
19
+ export class AuditLogger {
20
+ config;
21
+ initialized = false;
22
+ constructor() {
23
+ this.config = DEFAULT_CONFIG;
24
+ }
25
+ async initialize() {
26
+ if (this.initialized)
27
+ return;
28
+ try {
29
+ await fs.mkdir(AUDIT_DIR, { recursive: true });
30
+ // Load config if exists
31
+ try {
32
+ const configData = await fs.readFile(CONFIG_FILE, 'utf-8');
33
+ this.config = { ...DEFAULT_CONFIG, ...JSON.parse(configData) };
34
+ }
35
+ catch {
36
+ // Use defaults
37
+ }
38
+ this.initialized = true;
39
+ }
40
+ catch (error) {
41
+ console.error('Failed to initialize audit logger:', error);
42
+ }
43
+ }
44
+ async logCommand(command, args, options, response, startTime) {
45
+ if (!this.config.enabled)
46
+ return;
47
+ await this.initialize();
48
+ const entry = {
49
+ id: this.generateId(),
50
+ timestamp: new Date().toISOString(),
51
+ command,
52
+ args,
53
+ options: this.sanitizeOptions(options),
54
+ exitCode: response.exitCode || (response.success ? 0 : 1),
55
+ success: response.success,
56
+ duration: Date.now() - startTime,
57
+ provider: response.meta?.provider || 'unknown',
58
+ error: response.error,
59
+ };
60
+ if (this.config.includeMetadata) {
61
+ entry.metadata = {
62
+ nodeVersion: process.version,
63
+ platform: process.platform,
64
+ cwd: process.cwd(),
65
+ ci: process.env.CI === 'true',
66
+ };
67
+ }
68
+ // Write to log file
69
+ await this.appendEntry(entry);
70
+ // Send to remote if configured
71
+ if (this.config.remoteEndpoint) {
72
+ await this.sendRemote(entry).catch(() => { });
73
+ }
74
+ }
75
+ async getRecentEntries(limit = 50) {
76
+ await this.initialize();
77
+ try {
78
+ const data = await fs.readFile(AUDIT_FILE, 'utf-8');
79
+ const lines = data.trim().split('\n').filter(Boolean);
80
+ return lines
81
+ .slice(-limit)
82
+ .map(line => JSON.parse(line))
83
+ .reverse();
84
+ }
85
+ catch {
86
+ return [];
87
+ }
88
+ }
89
+ async getStats() {
90
+ const entries = await this.getRecentEntries(1000);
91
+ if (entries.length === 0) {
92
+ return {
93
+ totalCommands: 0,
94
+ successRate: 0,
95
+ avgDuration: 0,
96
+ mostUsed: [],
97
+ lastUsed: 'Never',
98
+ };
99
+ }
100
+ const commands = entries.map(e => e.command);
101
+ const successCount = entries.filter(e => e.success).length;
102
+ const totalDuration = entries.reduce((sum, e) => sum + e.duration, 0);
103
+ // Count command frequency
104
+ const frequency = {};
105
+ commands.forEach(cmd => {
106
+ frequency[cmd] = (frequency[cmd] || 0) + 1;
107
+ });
108
+ const mostUsed = Object.entries(frequency)
109
+ .sort((a, b) => b[1] - a[1])
110
+ .slice(0, 5)
111
+ .map(([cmd]) => cmd);
112
+ return {
113
+ totalCommands: entries.length,
114
+ successRate: Math.round((successCount / entries.length) * 100),
115
+ avgDuration: Math.round(totalDuration / entries.length),
116
+ mostUsed,
117
+ lastUsed: entries[0]?.timestamp || 'Never',
118
+ };
119
+ }
120
+ async appendEntry(entry) {
121
+ const line = JSON.stringify(entry) + '\n';
122
+ await fs.appendFile(AUDIT_FILE, line, 'utf-8');
123
+ }
124
+ async sendRemote(entry) {
125
+ if (!this.config.remoteEndpoint)
126
+ return;
127
+ try {
128
+ await fetch(this.config.remoteEndpoint, {
129
+ method: 'POST',
130
+ headers: { 'Content-Type': 'application/json' },
131
+ body: JSON.stringify(entry),
132
+ });
133
+ }
134
+ catch {
135
+ // Silently fail - don't block CLI execution
136
+ }
137
+ }
138
+ sanitizeOptions(options) {
139
+ const sensitiveKeys = ['token', 'password', 'secret', 'key', 'auth'];
140
+ const sanitized = {};
141
+ for (const [key, value] of Object.entries(options)) {
142
+ if (sensitiveKeys.some(sk => key.toLowerCase().includes(sk))) {
143
+ sanitized[key] = '[REDACTED]';
144
+ }
145
+ else {
146
+ sanitized[key] = value;
147
+ }
148
+ }
149
+ return sanitized;
150
+ }
151
+ generateId() {
152
+ return `${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
153
+ }
154
+ // Cleanup old entries
155
+ async cleanup() {
156
+ if (!this.config.enabled)
157
+ return;
158
+ try {
159
+ const entries = await this.getRecentEntries(this.config.maxEntries);
160
+ const cutoff = new Date();
161
+ cutoff.setDate(cutoff.getDate() - this.config.retentionDays);
162
+ const validEntries = entries.filter(e => new Date(e.timestamp) > cutoff);
163
+ // Rewrite file with only valid entries
164
+ const data = validEntries.map(e => JSON.stringify(e)).join('\n') + '\n';
165
+ await fs.writeFile(AUDIT_FILE, data, 'utf-8');
166
+ }
167
+ catch {
168
+ // Ignore cleanup errors
169
+ }
170
+ }
171
+ }
172
+ // Singleton instance
173
+ let auditLogger = null;
174
+ export function getAuditLogger() {
175
+ if (!auditLogger) {
176
+ auditLogger = new AuditLogger();
177
+ }
178
+ return auditLogger;
179
+ }
180
+ // Export for testing
181
+ export function resetAuditLogger() {
182
+ auditLogger = null;
183
+ }
184
+ //# sourceMappingURL=audit.js.map