@hyperdrive.bot/gut 0.1.4 → 0.1.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -779
- package/bin/run.js +5 -0
- package/package.json +10 -10
- package/bin/run +0 -5
- package/dist/base-command.d.ts +0 -21
- package/dist/base-command.js +0 -110
- package/dist/commands/add.d.ts +0 -13
- package/dist/commands/add.js +0 -73
- package/dist/commands/affected.d.ts +0 -23
- package/dist/commands/affected.js +0 -326
- package/dist/commands/audit.d.ts +0 -33
- package/dist/commands/audit.js +0 -593
- package/dist/commands/back.d.ts +0 -6
- package/dist/commands/back.js +0 -29
- package/dist/commands/commit.d.ts +0 -11
- package/dist/commands/commit.js +0 -113
- package/dist/commands/context.d.ts +0 -6
- package/dist/commands/context.js +0 -36
- package/dist/commands/contexts.d.ts +0 -7
- package/dist/commands/contexts.js +0 -92
- package/dist/commands/deps.d.ts +0 -10
- package/dist/commands/deps.js +0 -104
- package/dist/commands/entity/add.d.ts +0 -16
- package/dist/commands/entity/add.js +0 -105
- package/dist/commands/entity/clone-all.d.ts +0 -17
- package/dist/commands/entity/clone-all.js +0 -135
- package/dist/commands/entity/clone.d.ts +0 -15
- package/dist/commands/entity/clone.js +0 -109
- package/dist/commands/entity/list.d.ts +0 -11
- package/dist/commands/entity/list.js +0 -82
- package/dist/commands/entity/remove.d.ts +0 -12
- package/dist/commands/entity/remove.js +0 -58
- package/dist/commands/focus.d.ts +0 -19
- package/dist/commands/focus.js +0 -139
- package/dist/commands/graph.d.ts +0 -18
- package/dist/commands/graph.js +0 -238
- package/dist/commands/init.d.ts +0 -11
- package/dist/commands/init.js +0 -84
- package/dist/commands/insights.d.ts +0 -21
- package/dist/commands/insights.js +0 -434
- package/dist/commands/patterns.d.ts +0 -40
- package/dist/commands/patterns.js +0 -412
- package/dist/commands/pull.d.ts +0 -11
- package/dist/commands/pull.js +0 -121
- package/dist/commands/push.d.ts +0 -11
- package/dist/commands/push.js +0 -101
- package/dist/commands/quick-setup.d.ts +0 -20
- package/dist/commands/quick-setup.js +0 -422
- package/dist/commands/recent.d.ts +0 -9
- package/dist/commands/recent.js +0 -55
- package/dist/commands/related.d.ts +0 -23
- package/dist/commands/related.js +0 -257
- package/dist/commands/repos.d.ts +0 -14
- package/dist/commands/repos.js +0 -185
- package/dist/commands/stack.d.ts +0 -10
- package/dist/commands/stack.js +0 -83
- package/dist/commands/status.d.ts +0 -14
- package/dist/commands/status.js +0 -246
- package/dist/commands/sync.d.ts +0 -11
- package/dist/commands/sync.js +0 -142
- package/dist/commands/unfocus.d.ts +0 -6
- package/dist/commands/unfocus.js +0 -23
- package/dist/commands/used-by.d.ts +0 -10
- package/dist/commands/used-by.js +0 -111
- package/dist/commands/workspace.d.ts +0 -20
- package/dist/commands/workspace.js +0 -365
- package/dist/index.d.ts +0 -1
- package/dist/index.js +0 -5
- package/dist/models/entity.model.d.ts +0 -81
- package/dist/models/entity.model.js +0 -2
- package/dist/services/config.service.d.ts +0 -34
- package/dist/services/config.service.js +0 -230
- package/dist/services/entity.service.d.ts +0 -19
- package/dist/services/entity.service.js +0 -130
- package/dist/services/focus.service.d.ts +0 -70
- package/dist/services/focus.service.js +0 -587
- package/dist/services/git.service.d.ts +0 -37
- package/dist/services/git.service.js +0 -180
- package/dist/utils/display.d.ts +0 -25
- package/dist/utils/display.js +0 -150
- package/dist/utils/filesystem.d.ts +0 -32
- package/dist/utils/filesystem.js +0 -220
- package/dist/utils/index.d.ts +0 -13
- package/dist/utils/index.js +0 -18
- package/dist/utils/validation.d.ts +0 -22
- package/dist/utils/validation.js +0 -196
- package/oclif.manifest.json +0 -1463
package/dist/commands/audit.js
DELETED
|
@@ -1,593 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
const tslib_1 = require("tslib");
|
|
4
|
-
const core_1 = require("@oclif/core");
|
|
5
|
-
const base_command_1 = require("../base-command");
|
|
6
|
-
const chalk_1 = tslib_1.__importDefault(require("chalk"));
|
|
7
|
-
const fs = tslib_1.__importStar(require("fs"));
|
|
8
|
-
const path = tslib_1.__importStar(require("path"));
|
|
9
|
-
class Audit extends base_command_1.BaseCommand {
|
|
10
|
-
static description = 'Access and change audit across workspace';
|
|
11
|
-
static examples = [
|
|
12
|
-
'<%= config.bin %> <%= command.id %>',
|
|
13
|
-
'<%= config.bin %> <%= command.id %> --entity mindtools',
|
|
14
|
-
'<%= config.bin %> <%= command.id %> --security',
|
|
15
|
-
'<%= config.bin %> <%= command.id %> --compliance',
|
|
16
|
-
];
|
|
17
|
-
static flags = {
|
|
18
|
-
entity: core_1.Flags.string({
|
|
19
|
-
char: 'e',
|
|
20
|
-
description: 'audit specific entity',
|
|
21
|
-
}),
|
|
22
|
-
security: core_1.Flags.boolean({
|
|
23
|
-
char: 's',
|
|
24
|
-
description: 'focus on security audit',
|
|
25
|
-
default: false,
|
|
26
|
-
}),
|
|
27
|
-
compliance: core_1.Flags.boolean({
|
|
28
|
-
char: 'c',
|
|
29
|
-
description: 'focus on compliance audit',
|
|
30
|
-
default: false,
|
|
31
|
-
}),
|
|
32
|
-
access: core_1.Flags.boolean({
|
|
33
|
-
char: 'a',
|
|
34
|
-
description: 'audit access patterns and permissions',
|
|
35
|
-
default: false,
|
|
36
|
-
}),
|
|
37
|
-
changes: core_1.Flags.boolean({
|
|
38
|
-
description: 'audit recent changes and activity',
|
|
39
|
-
default: false,
|
|
40
|
-
}),
|
|
41
|
-
json: core_1.Flags.boolean({
|
|
42
|
-
description: 'output as JSON',
|
|
43
|
-
default: false,
|
|
44
|
-
}),
|
|
45
|
-
};
|
|
46
|
-
async run() {
|
|
47
|
-
const { flags } = await this.parse(Audit);
|
|
48
|
-
let entities = [];
|
|
49
|
-
if (flags.entity) {
|
|
50
|
-
const entity = this.entityService.findEntity(flags.entity);
|
|
51
|
-
if (!entity) {
|
|
52
|
-
this.error(`Entity '${flags.entity}' not found`);
|
|
53
|
-
}
|
|
54
|
-
entities = [entity];
|
|
55
|
-
}
|
|
56
|
-
else {
|
|
57
|
-
entities = this.entityService.getAllEntities();
|
|
58
|
-
}
|
|
59
|
-
if (entities.length === 0) {
|
|
60
|
-
this.error('No entities found to audit');
|
|
61
|
-
}
|
|
62
|
-
const auditResults = await this.performAudit(entities, flags);
|
|
63
|
-
if (flags.json) {
|
|
64
|
-
this.log(JSON.stringify(auditResults, null, 2));
|
|
65
|
-
return;
|
|
66
|
-
}
|
|
67
|
-
this.displayAuditResults(auditResults, flags);
|
|
68
|
-
}
|
|
69
|
-
async performAudit(entities, flags) {
|
|
70
|
-
const results = {
|
|
71
|
-
timestamp: new Date().toISOString(),
|
|
72
|
-
scope: {
|
|
73
|
-
entities: entities.map(e => e.name),
|
|
74
|
-
audit_types: this.getAuditTypes(flags)
|
|
75
|
-
},
|
|
76
|
-
findings: [],
|
|
77
|
-
summary: {
|
|
78
|
-
total_entities: entities.length,
|
|
79
|
-
issues_found: 0,
|
|
80
|
-
security_issues: 0,
|
|
81
|
-
compliance_issues: 0,
|
|
82
|
-
access_issues: 0
|
|
83
|
-
}
|
|
84
|
-
};
|
|
85
|
-
for (const entity of entities) {
|
|
86
|
-
const entityAudit = await this.auditEntity(entity, flags);
|
|
87
|
-
results.findings.push(entityAudit);
|
|
88
|
-
// Update summary
|
|
89
|
-
results.summary.issues_found += entityAudit.issues.length;
|
|
90
|
-
results.summary.security_issues += entityAudit.security_issues.length;
|
|
91
|
-
results.summary.compliance_issues += entityAudit.compliance_issues.length;
|
|
92
|
-
results.summary.access_issues += entityAudit.access_issues.length;
|
|
93
|
-
}
|
|
94
|
-
return results;
|
|
95
|
-
}
|
|
96
|
-
async auditEntity(entity, flags) {
|
|
97
|
-
const entityPath = this.entityService.resolveEntityPath(entity);
|
|
98
|
-
const audit = {
|
|
99
|
-
entity: entity.name,
|
|
100
|
-
type: entity.type,
|
|
101
|
-
path: entity.path,
|
|
102
|
-
timestamp: new Date().toISOString(),
|
|
103
|
-
exists: fs.existsSync(entityPath),
|
|
104
|
-
issues: [],
|
|
105
|
-
security_issues: [],
|
|
106
|
-
compliance_issues: [],
|
|
107
|
-
access_issues: [],
|
|
108
|
-
metadata_audit: {},
|
|
109
|
-
git_audit: {},
|
|
110
|
-
file_audit: {}
|
|
111
|
-
};
|
|
112
|
-
if (!audit.exists) {
|
|
113
|
-
audit.issues.push({
|
|
114
|
-
type: 'missing_entity',
|
|
115
|
-
severity: 'high',
|
|
116
|
-
message: 'Entity path does not exist',
|
|
117
|
-
path: entityPath
|
|
118
|
-
});
|
|
119
|
-
return audit;
|
|
120
|
-
}
|
|
121
|
-
// Metadata audit
|
|
122
|
-
audit.metadata_audit = await this.auditMetadata(entity);
|
|
123
|
-
// Git audit
|
|
124
|
-
if (await this.gitService.isRepository(entityPath)) {
|
|
125
|
-
audit.git_audit = await this.auditGitRepository(entityPath);
|
|
126
|
-
}
|
|
127
|
-
// File structure audit
|
|
128
|
-
audit.file_audit = await this.auditFileStructure(entityPath, entity.type);
|
|
129
|
-
// Security audit
|
|
130
|
-
if (flags.security || !this.hasSpecificAuditType(flags)) {
|
|
131
|
-
audit.security_issues = await this.performSecurityAudit(entityPath, entity);
|
|
132
|
-
}
|
|
133
|
-
// Compliance audit
|
|
134
|
-
if (flags.compliance || !this.hasSpecificAuditType(flags)) {
|
|
135
|
-
audit.compliance_issues = await this.performComplianceAudit(entity);
|
|
136
|
-
}
|
|
137
|
-
// Access audit
|
|
138
|
-
if (flags.access || !this.hasSpecificAuditType(flags)) {
|
|
139
|
-
audit.access_issues = await this.performAccessAudit(entity);
|
|
140
|
-
}
|
|
141
|
-
return audit;
|
|
142
|
-
}
|
|
143
|
-
async auditMetadata(entity) {
|
|
144
|
-
const issues = [];
|
|
145
|
-
const metadata = entity.metadata || {};
|
|
146
|
-
// Check required metadata fields
|
|
147
|
-
if (entity.type === 'client') {
|
|
148
|
-
if (!metadata.business?.primary_contact) {
|
|
149
|
-
issues.push({
|
|
150
|
-
type: 'missing_metadata',
|
|
151
|
-
field: 'business.primary_contact',
|
|
152
|
-
severity: 'medium',
|
|
153
|
-
message: 'Client entity missing primary contact information'
|
|
154
|
-
});
|
|
155
|
-
}
|
|
156
|
-
if (!metadata.business?.contract_value) {
|
|
157
|
-
issues.push({
|
|
158
|
-
type: 'missing_metadata',
|
|
159
|
-
field: 'business.contract_value',
|
|
160
|
-
severity: 'low',
|
|
161
|
-
message: 'Client entity missing contract value'
|
|
162
|
-
});
|
|
163
|
-
}
|
|
164
|
-
}
|
|
165
|
-
// Check metadata file existence
|
|
166
|
-
const entityPath = this.entityService.resolveEntityPath(entity);
|
|
167
|
-
const metadataPath = path.join(entityPath, '.entity.yaml');
|
|
168
|
-
return {
|
|
169
|
-
has_metadata_file: fs.existsSync(metadataPath),
|
|
170
|
-
metadata_completeness: this.calculateMetadataCompleteness(metadata, entity.type),
|
|
171
|
-
issues: issues
|
|
172
|
-
};
|
|
173
|
-
}
|
|
174
|
-
async auditGitRepository(repoPath) {
|
|
175
|
-
const audit = {
|
|
176
|
-
is_git_repo: true,
|
|
177
|
-
issues: []
|
|
178
|
-
};
|
|
179
|
-
try {
|
|
180
|
-
// Check git status
|
|
181
|
-
const status = await this.gitService.getStatus(repoPath);
|
|
182
|
-
audit.status = status;
|
|
183
|
-
// Check for uncommitted changes
|
|
184
|
-
if (status.hasChanges) {
|
|
185
|
-
audit.issues.push({
|
|
186
|
-
type: 'uncommitted_changes',
|
|
187
|
-
severity: 'low',
|
|
188
|
-
message: `Repository has ${status.changes.length} uncommitted changes`
|
|
189
|
-
});
|
|
190
|
-
}
|
|
191
|
-
// Check remote configuration
|
|
192
|
-
try {
|
|
193
|
-
const remotes = await this.gitService.exec(['remote', '-v'], { cwd: repoPath });
|
|
194
|
-
audit.has_remote = remotes.length > 0;
|
|
195
|
-
if (!audit.has_remote) {
|
|
196
|
-
audit.issues.push({
|
|
197
|
-
type: 'no_remote',
|
|
198
|
-
severity: 'medium',
|
|
199
|
-
message: 'Repository has no remote configured'
|
|
200
|
-
});
|
|
201
|
-
}
|
|
202
|
-
}
|
|
203
|
-
catch {
|
|
204
|
-
audit.has_remote = false;
|
|
205
|
-
}
|
|
206
|
-
// Check branch information
|
|
207
|
-
try {
|
|
208
|
-
const branch = await this.gitService.exec(['branch', '--show-current'], { cwd: repoPath });
|
|
209
|
-
audit.current_branch = branch.trim();
|
|
210
|
-
if (audit.current_branch === 'master' || audit.current_branch === 'main') {
|
|
211
|
-
// Check if working directly on main branch
|
|
212
|
-
if (status.hasChanges) {
|
|
213
|
-
audit.issues.push({
|
|
214
|
-
type: 'working_on_main',
|
|
215
|
-
severity: 'medium',
|
|
216
|
-
message: 'Working directly on main/master branch with uncommitted changes'
|
|
217
|
-
});
|
|
218
|
-
}
|
|
219
|
-
}
|
|
220
|
-
}
|
|
221
|
-
catch {
|
|
222
|
-
// Ignore branch check errors
|
|
223
|
-
}
|
|
224
|
-
}
|
|
225
|
-
catch (error) {
|
|
226
|
-
audit.issues.push({
|
|
227
|
-
type: 'git_error',
|
|
228
|
-
severity: 'high',
|
|
229
|
-
message: `Git audit failed: ${error.message}`
|
|
230
|
-
});
|
|
231
|
-
}
|
|
232
|
-
return audit;
|
|
233
|
-
}
|
|
234
|
-
async auditFileStructure(entityPath, entityType) {
|
|
235
|
-
const audit = {
|
|
236
|
-
structure_score: 0,
|
|
237
|
-
issues: [],
|
|
238
|
-
recommendations: []
|
|
239
|
-
};
|
|
240
|
-
try {
|
|
241
|
-
const files = fs.readdirSync(entityPath);
|
|
242
|
-
// Check for common files based on entity type
|
|
243
|
-
const expectedFiles = this.getExpectedFiles(entityType);
|
|
244
|
-
for (const expectedFile of expectedFiles) {
|
|
245
|
-
if (!files.includes(expectedFile.name)) {
|
|
246
|
-
audit.issues.push({
|
|
247
|
-
type: 'missing_file',
|
|
248
|
-
severity: expectedFile.required ? 'medium' : 'low',
|
|
249
|
-
message: `Missing ${expectedFile.description}: ${expectedFile.name}`
|
|
250
|
-
});
|
|
251
|
-
}
|
|
252
|
-
}
|
|
253
|
-
// Check for documentation
|
|
254
|
-
const hasReadme = files.some(f => f.toLowerCase().startsWith('readme'));
|
|
255
|
-
if (!hasReadme) {
|
|
256
|
-
audit.recommendations.push('Add README.md file for documentation');
|
|
257
|
-
}
|
|
258
|
-
// Check for configuration files
|
|
259
|
-
const hasConfig = files.some(f => f.includes('config') || f.includes('.env'));
|
|
260
|
-
audit.has_configuration = hasConfig;
|
|
261
|
-
audit.structure_score = this.calculateStructureScore(files, expectedFiles);
|
|
262
|
-
}
|
|
263
|
-
catch (error) {
|
|
264
|
-
audit.issues.push({
|
|
265
|
-
type: 'file_audit_error',
|
|
266
|
-
severity: 'high',
|
|
267
|
-
message: `File structure audit failed: ${error.message}`
|
|
268
|
-
});
|
|
269
|
-
}
|
|
270
|
-
return audit;
|
|
271
|
-
}
|
|
272
|
-
async performSecurityAudit(entityPath, entity) {
|
|
273
|
-
const issues = [];
|
|
274
|
-
// Check for sensitive files
|
|
275
|
-
const sensitivePatterns = [
|
|
276
|
-
'.env',
|
|
277
|
-
'secrets',
|
|
278
|
-
'private',
|
|
279
|
-
'credentials',
|
|
280
|
-
'password',
|
|
281
|
-
'key',
|
|
282
|
-
'token'
|
|
283
|
-
];
|
|
284
|
-
try {
|
|
285
|
-
const files = this.getAllFiles(entityPath);
|
|
286
|
-
for (const file of files) {
|
|
287
|
-
const fileName = path.basename(file).toLowerCase();
|
|
288
|
-
for (const pattern of sensitivePatterns) {
|
|
289
|
-
if (fileName.includes(pattern)) {
|
|
290
|
-
issues.push({
|
|
291
|
-
type: 'sensitive_file',
|
|
292
|
-
severity: 'high',
|
|
293
|
-
message: `Potentially sensitive file found: ${file}`,
|
|
294
|
-
file: file
|
|
295
|
-
});
|
|
296
|
-
}
|
|
297
|
-
}
|
|
298
|
-
}
|
|
299
|
-
// Check for .gitignore
|
|
300
|
-
const gitignorePath = path.join(entityPath, '.gitignore');
|
|
301
|
-
if (!fs.existsSync(gitignorePath)) {
|
|
302
|
-
issues.push({
|
|
303
|
-
type: 'missing_gitignore',
|
|
304
|
-
severity: 'medium',
|
|
305
|
-
message: 'No .gitignore file found'
|
|
306
|
-
});
|
|
307
|
-
}
|
|
308
|
-
}
|
|
309
|
-
catch (error) {
|
|
310
|
-
issues.push({
|
|
311
|
-
type: 'security_audit_error',
|
|
312
|
-
severity: 'high',
|
|
313
|
-
message: `Security audit failed: ${error.message}`
|
|
314
|
-
});
|
|
315
|
-
}
|
|
316
|
-
return issues;
|
|
317
|
-
}
|
|
318
|
-
async performComplianceAudit(entity) {
|
|
319
|
-
const issues = [];
|
|
320
|
-
const metadata = entity.metadata || {};
|
|
321
|
-
// Check business compliance for client entities
|
|
322
|
-
if (entity.type === 'client') {
|
|
323
|
-
if (!metadata.business?.status) {
|
|
324
|
-
issues.push({
|
|
325
|
-
type: 'missing_business_status',
|
|
326
|
-
severity: 'medium',
|
|
327
|
-
message: 'Client entity missing business status'
|
|
328
|
-
});
|
|
329
|
-
}
|
|
330
|
-
// Check for required documentation
|
|
331
|
-
const entityPath = this.entityService.resolveEntityPath(entity);
|
|
332
|
-
const requiredDocs = ['README.md', '.entity.yaml'];
|
|
333
|
-
for (const doc of requiredDocs) {
|
|
334
|
-
const docPath = path.join(entityPath, doc);
|
|
335
|
-
if (!fs.existsSync(docPath)) {
|
|
336
|
-
issues.push({
|
|
337
|
-
type: 'missing_documentation',
|
|
338
|
-
severity: 'medium',
|
|
339
|
-
message: `Required documentation missing: ${doc}`
|
|
340
|
-
});
|
|
341
|
-
}
|
|
342
|
-
}
|
|
343
|
-
}
|
|
344
|
-
// Check metadata completeness
|
|
345
|
-
const completeness = this.calculateMetadataCompleteness(metadata, entity.type);
|
|
346
|
-
if (completeness < 0.7) {
|
|
347
|
-
issues.push({
|
|
348
|
-
type: 'incomplete_metadata',
|
|
349
|
-
severity: 'low',
|
|
350
|
-
message: `Entity metadata only ${Math.round(completeness * 100)}% complete`
|
|
351
|
-
});
|
|
352
|
-
}
|
|
353
|
-
return issues;
|
|
354
|
-
}
|
|
355
|
-
async performAccessAudit(entity) {
|
|
356
|
-
const issues = [];
|
|
357
|
-
// Check path accessibility
|
|
358
|
-
const entityPath = this.entityService.resolveEntityPath(entity);
|
|
359
|
-
try {
|
|
360
|
-
const stats = fs.statSync(entityPath);
|
|
361
|
-
// Check if path is accessible
|
|
362
|
-
if (!stats.isDirectory()) {
|
|
363
|
-
issues.push({
|
|
364
|
-
type: 'invalid_path',
|
|
365
|
-
severity: 'high',
|
|
366
|
-
message: 'Entity path is not a directory'
|
|
367
|
-
});
|
|
368
|
-
}
|
|
369
|
-
// Check permissions (basic check)
|
|
370
|
-
try {
|
|
371
|
-
fs.accessSync(entityPath, fs.constants.R_OK | fs.constants.W_OK);
|
|
372
|
-
}
|
|
373
|
-
catch {
|
|
374
|
-
issues.push({
|
|
375
|
-
type: 'permission_issue',
|
|
376
|
-
severity: 'high',
|
|
377
|
-
message: 'Insufficient permissions for entity path'
|
|
378
|
-
});
|
|
379
|
-
}
|
|
380
|
-
}
|
|
381
|
-
catch (error) {
|
|
382
|
-
issues.push({
|
|
383
|
-
type: 'access_error',
|
|
384
|
-
severity: 'high',
|
|
385
|
-
message: `Cannot access entity path: ${error.message}`
|
|
386
|
-
});
|
|
387
|
-
}
|
|
388
|
-
// Check for private/business separation
|
|
389
|
-
if (entity.type === 'client') {
|
|
390
|
-
const hasPrivate = entity.path.includes('private') || entity.path.includes('business');
|
|
391
|
-
const metadata = entity.metadata || {};
|
|
392
|
-
if (metadata.business && !hasPrivate) {
|
|
393
|
-
issues.push({
|
|
394
|
-
type: 'missing_private_separation',
|
|
395
|
-
severity: 'medium',
|
|
396
|
-
message: 'Client entity with business data should have private/business separation'
|
|
397
|
-
});
|
|
398
|
-
}
|
|
399
|
-
}
|
|
400
|
-
return issues;
|
|
401
|
-
}
|
|
402
|
-
displayAuditResults(results, flags) {
|
|
403
|
-
this.log(chalk_1.default.bold('\n🔍 Workspace Audit Report'));
|
|
404
|
-
this.log(chalk_1.default.dim('─'.repeat(50)));
|
|
405
|
-
this.log(`📅 Generated: ${new Date(results.timestamp).toLocaleString()}`);
|
|
406
|
-
this.log(`📊 Scope: ${results.scope.entities.length} entities`);
|
|
407
|
-
this.log(`🎯 Audit Types: ${results.scope.audit_types.join(', ')}`);
|
|
408
|
-
this.log('');
|
|
409
|
-
// Summary
|
|
410
|
-
this.log(chalk_1.default.bold('📋 Summary:'));
|
|
411
|
-
const summary = results.summary;
|
|
412
|
-
if (summary.issues_found === 0) {
|
|
413
|
-
this.log(chalk_1.default.green('✅ No issues found'));
|
|
414
|
-
}
|
|
415
|
-
else {
|
|
416
|
-
this.log(`⚠️ Total Issues: ${chalk_1.default.yellow(summary.issues_found)}`);
|
|
417
|
-
if (summary.security_issues > 0) {
|
|
418
|
-
this.log(`🔒 Security Issues: ${chalk_1.default.red(summary.security_issues)}`);
|
|
419
|
-
}
|
|
420
|
-
if (summary.compliance_issues > 0) {
|
|
421
|
-
this.log(`📋 Compliance Issues: ${chalk_1.default.yellow(summary.compliance_issues)}`);
|
|
422
|
-
}
|
|
423
|
-
if (summary.access_issues > 0) {
|
|
424
|
-
this.log(`🔐 Access Issues: ${chalk_1.default.red(summary.access_issues)}`);
|
|
425
|
-
}
|
|
426
|
-
}
|
|
427
|
-
this.log('');
|
|
428
|
-
// Detailed findings
|
|
429
|
-
for (const finding of results.findings) {
|
|
430
|
-
this.displayEntityAudit(finding);
|
|
431
|
-
}
|
|
432
|
-
// Recommendations
|
|
433
|
-
this.displayRecommendations(results);
|
|
434
|
-
}
|
|
435
|
-
displayEntityAudit(audit) {
|
|
436
|
-
const emoji = this.getTypeEmoji(audit.type);
|
|
437
|
-
const issueCount = audit.issues.length + audit.security_issues.length +
|
|
438
|
-
audit.compliance_issues.length + audit.access_issues.length;
|
|
439
|
-
const statusIcon = issueCount === 0 ? chalk_1.default.green('✅') :
|
|
440
|
-
issueCount < 3 ? chalk_1.default.yellow('⚠️') : chalk_1.default.red('❌');
|
|
441
|
-
this.log(`${emoji} ${chalk_1.default.bold(audit.entity)} ${statusIcon}`);
|
|
442
|
-
if (!audit.exists) {
|
|
443
|
-
this.log(` ${chalk_1.default.red('❌ Entity path does not exist')}`);
|
|
444
|
-
return;
|
|
445
|
-
}
|
|
446
|
-
// Show critical issues
|
|
447
|
-
const criticalIssues = [
|
|
448
|
-
...audit.issues,
|
|
449
|
-
...audit.security_issues,
|
|
450
|
-
...audit.compliance_issues,
|
|
451
|
-
...audit.access_issues
|
|
452
|
-
].filter(issue => issue.severity === 'high');
|
|
453
|
-
if (criticalIssues.length > 0) {
|
|
454
|
-
this.log(` ${chalk_1.default.red('🚨 Critical Issues:')}`);
|
|
455
|
-
criticalIssues.forEach(issue => {
|
|
456
|
-
this.log(` • ${issue.message}`);
|
|
457
|
-
});
|
|
458
|
-
}
|
|
459
|
-
// Show metadata completeness
|
|
460
|
-
if (audit.metadata_audit?.metadata_completeness !== undefined) {
|
|
461
|
-
const completeness = Math.round(audit.metadata_audit.metadata_completeness * 100);
|
|
462
|
-
const color = completeness >= 80 ? chalk_1.default.green : completeness >= 60 ? chalk_1.default.yellow : chalk_1.default.red;
|
|
463
|
-
this.log(` 📊 Metadata: ${color(`${completeness}% complete`)}`);
|
|
464
|
-
}
|
|
465
|
-
// Show git status
|
|
466
|
-
if (audit.git_audit?.is_git_repo) {
|
|
467
|
-
const gitStatus = audit.git_audit.status?.hasChanges ?
|
|
468
|
-
chalk_1.default.yellow('uncommitted changes') : chalk_1.default.green('clean');
|
|
469
|
-
this.log(` 📁 Git: ${gitStatus}`);
|
|
470
|
-
}
|
|
471
|
-
this.log('');
|
|
472
|
-
}
|
|
473
|
-
displayRecommendations(results) {
|
|
474
|
-
const allRecommendations = [];
|
|
475
|
-
// Collect recommendations from all findings
|
|
476
|
-
for (const finding of results.findings) {
|
|
477
|
-
if (finding.file_audit?.recommendations) {
|
|
478
|
-
allRecommendations.push(...finding.file_audit.recommendations);
|
|
479
|
-
}
|
|
480
|
-
}
|
|
481
|
-
if (allRecommendations.length > 0) {
|
|
482
|
-
this.log(chalk_1.default.bold('💡 Recommendations:'));
|
|
483
|
-
const uniqueRecommendations = [...new Set(allRecommendations)];
|
|
484
|
-
uniqueRecommendations.forEach(rec => {
|
|
485
|
-
this.log(` • ${rec}`);
|
|
486
|
-
});
|
|
487
|
-
}
|
|
488
|
-
}
|
|
489
|
-
// Helper methods
|
|
490
|
-
getAuditTypes(flags) {
|
|
491
|
-
const types = [];
|
|
492
|
-
if (flags.security)
|
|
493
|
-
types.push('security');
|
|
494
|
-
if (flags.compliance)
|
|
495
|
-
types.push('compliance');
|
|
496
|
-
if (flags.access)
|
|
497
|
-
types.push('access');
|
|
498
|
-
if (flags.changes)
|
|
499
|
-
types.push('changes');
|
|
500
|
-
if (types.length === 0)
|
|
501
|
-
types.push('general');
|
|
502
|
-
return types;
|
|
503
|
-
}
|
|
504
|
-
hasSpecificAuditType(flags) {
|
|
505
|
-
return flags.security || flags.compliance || flags.access || flags.changes;
|
|
506
|
-
}
|
|
507
|
-
calculateMetadataCompleteness(metadata, entityType) {
|
|
508
|
-
const requiredFields = this.getRequiredMetadataFields(entityType);
|
|
509
|
-
let completedFields = 0;
|
|
510
|
-
for (const field of requiredFields) {
|
|
511
|
-
if (this.hasNestedField(metadata, field)) {
|
|
512
|
-
completedFields++;
|
|
513
|
-
}
|
|
514
|
-
}
|
|
515
|
-
return requiredFields.length > 0 ? completedFields / requiredFields.length : 1;
|
|
516
|
-
}
|
|
517
|
-
getRequiredMetadataFields(entityType) {
|
|
518
|
-
const fields = {
|
|
519
|
-
client: ['business.primary_contact', 'business.status', 'relationships.dependent_systems'],
|
|
520
|
-
prospect: ['business.status', 'relationships.similar_entities'],
|
|
521
|
-
company: ['business.status'],
|
|
522
|
-
initiative: ['relationships.related_initiatives'],
|
|
523
|
-
system: ['relationships.dependent_systems']
|
|
524
|
-
};
|
|
525
|
-
return fields[entityType] || [];
|
|
526
|
-
}
|
|
527
|
-
hasNestedField(obj, fieldPath) {
|
|
528
|
-
const parts = fieldPath.split('.');
|
|
529
|
-
let current = obj;
|
|
530
|
-
for (const part of parts) {
|
|
531
|
-
if (!current || typeof current !== 'object' || !(part in current)) {
|
|
532
|
-
return false;
|
|
533
|
-
}
|
|
534
|
-
current = current[part];
|
|
535
|
-
}
|
|
536
|
-
return current !== undefined && current !== null && current !== '';
|
|
537
|
-
}
|
|
538
|
-
getExpectedFiles(entityType) {
|
|
539
|
-
const common = [
|
|
540
|
-
{ name: '.entity.yaml', required: true, description: 'Entity metadata' },
|
|
541
|
-
{ name: 'README.md', required: false, description: 'Documentation' }
|
|
542
|
-
];
|
|
543
|
-
const typeSpecific = {
|
|
544
|
-
client: [
|
|
545
|
-
{ name: 'package.json', required: false, description: 'Project configuration' },
|
|
546
|
-
{ name: '.gitignore', required: true, description: 'Git ignore rules' }
|
|
547
|
-
],
|
|
548
|
-
system: [
|
|
549
|
-
{ name: 'package.json', required: true, description: 'Project configuration' },
|
|
550
|
-
{ name: '.gitignore', required: true, description: 'Git ignore rules' }
|
|
551
|
-
]
|
|
552
|
-
};
|
|
553
|
-
return [...common, ...(typeSpecific[entityType] || [])];
|
|
554
|
-
}
|
|
555
|
-
calculateStructureScore(files, expectedFiles) {
|
|
556
|
-
let score = 0;
|
|
557
|
-
const totalExpected = expectedFiles.length;
|
|
558
|
-
for (const expected of expectedFiles) {
|
|
559
|
-
if (files.includes(expected.name)) {
|
|
560
|
-
score += expected.required ? 2 : 1;
|
|
561
|
-
}
|
|
562
|
-
}
|
|
563
|
-
return totalExpected > 0 ? score / (totalExpected * 2) : 1;
|
|
564
|
-
}
|
|
565
|
-
getAllFiles(dirPath, maxDepth = 2) {
|
|
566
|
-
const files = [];
|
|
567
|
-
const traverse = (currentPath, depth) => {
|
|
568
|
-
if (depth > maxDepth)
|
|
569
|
-
return;
|
|
570
|
-
try {
|
|
571
|
-
const items = fs.readdirSync(currentPath);
|
|
572
|
-
for (const item of items) {
|
|
573
|
-
if (item.startsWith('.') && item !== '.entity.yaml')
|
|
574
|
-
continue;
|
|
575
|
-
const itemPath = path.join(currentPath, item);
|
|
576
|
-
const stats = fs.statSync(itemPath);
|
|
577
|
-
if (stats.isFile()) {
|
|
578
|
-
files.push(path.relative(dirPath, itemPath));
|
|
579
|
-
}
|
|
580
|
-
else if (stats.isDirectory()) {
|
|
581
|
-
traverse(itemPath, depth + 1);
|
|
582
|
-
}
|
|
583
|
-
}
|
|
584
|
-
}
|
|
585
|
-
catch {
|
|
586
|
-
// Ignore permission errors
|
|
587
|
-
}
|
|
588
|
-
};
|
|
589
|
-
traverse(dirPath, 0);
|
|
590
|
-
return files;
|
|
591
|
-
}
|
|
592
|
-
}
|
|
593
|
-
exports.default = Audit;
|
package/dist/commands/back.d.ts
DELETED
package/dist/commands/back.js
DELETED
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
const tslib_1 = require("tslib");
|
|
4
|
-
const base_command_1 = require("../base-command");
|
|
5
|
-
const chalk_1 = tslib_1.__importDefault(require("chalk"));
|
|
6
|
-
class Back extends base_command_1.BaseCommand {
|
|
7
|
-
static description = 'Navigate back to the previous focus';
|
|
8
|
-
static examples = [
|
|
9
|
-
'<%= config.bin %> <%= command.id %>',
|
|
10
|
-
];
|
|
11
|
-
async run() {
|
|
12
|
-
await this.parse(Back);
|
|
13
|
-
const focusedEntities = await this.focusService.getFocusedEntities();
|
|
14
|
-
const history = await this.configService.getHistory();
|
|
15
|
-
if (history.length < 2) {
|
|
16
|
-
this.log(chalk_1.default.yellow('No previous focus available'));
|
|
17
|
-
this.log(chalk_1.default.dim('Focus history is empty or has only the current focus'));
|
|
18
|
-
return;
|
|
19
|
-
}
|
|
20
|
-
const previousEntry = history[1];
|
|
21
|
-
const currentEntities = focusedEntities.map(e => e.name).join(', ') || 'none';
|
|
22
|
-
const previousEntities = previousEntry.entities.join(', ');
|
|
23
|
-
await this.focusService.switchToPrevious();
|
|
24
|
-
this.log(chalk_1.default.green('✓ Switched to previous focus'));
|
|
25
|
-
this.log(chalk_1.default.dim(` From: ${currentEntities}`));
|
|
26
|
-
this.log(chalk_1.default.dim(` To: ${previousEntities}`));
|
|
27
|
-
}
|
|
28
|
-
}
|
|
29
|
-
exports.default = Back;
|
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
import { BaseCommand } from '../base-command';
|
|
2
|
-
export default class Commit extends BaseCommand {
|
|
3
|
-
static description: string;
|
|
4
|
-
static examples: string[];
|
|
5
|
-
static flags: {
|
|
6
|
-
message: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
|
|
7
|
-
all: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
|
|
8
|
-
amend: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
|
|
9
|
-
};
|
|
10
|
-
run(): Promise<void>;
|
|
11
|
-
}
|