@hyperdrive.bot/gut 0.1.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/README.md +809 -0
- package/bin/dev +16 -0
- package/bin/run +5 -0
- package/dist/base-command.d.ts +21 -0
- package/dist/base-command.js +110 -0
- package/dist/commands/add.d.ts +13 -0
- package/dist/commands/add.js +73 -0
- package/dist/commands/affected.d.ts +23 -0
- package/dist/commands/affected.js +326 -0
- package/dist/commands/audit.d.ts +33 -0
- package/dist/commands/audit.js +593 -0
- package/dist/commands/back.d.ts +6 -0
- package/dist/commands/back.js +29 -0
- package/dist/commands/commit.d.ts +11 -0
- package/dist/commands/commit.js +113 -0
- package/dist/commands/context.d.ts +6 -0
- package/dist/commands/context.js +36 -0
- package/dist/commands/contexts.d.ts +7 -0
- package/dist/commands/contexts.js +92 -0
- package/dist/commands/deps.d.ts +10 -0
- package/dist/commands/deps.js +104 -0
- package/dist/commands/entity/add.d.ts +16 -0
- package/dist/commands/entity/add.js +105 -0
- package/dist/commands/entity/clone-all.d.ts +17 -0
- package/dist/commands/entity/clone-all.js +135 -0
- package/dist/commands/entity/clone.d.ts +15 -0
- package/dist/commands/entity/clone.js +109 -0
- package/dist/commands/entity/list.d.ts +11 -0
- package/dist/commands/entity/list.js +82 -0
- package/dist/commands/entity/remove.d.ts +12 -0
- package/dist/commands/entity/remove.js +58 -0
- package/dist/commands/focus.d.ts +19 -0
- package/dist/commands/focus.js +139 -0
- package/dist/commands/graph.d.ts +18 -0
- package/dist/commands/graph.js +238 -0
- package/dist/commands/init.d.ts +11 -0
- package/dist/commands/init.js +84 -0
- package/dist/commands/insights.d.ts +21 -0
- package/dist/commands/insights.js +434 -0
- package/dist/commands/patterns.d.ts +40 -0
- package/dist/commands/patterns.js +412 -0
- package/dist/commands/pull.d.ts +11 -0
- package/dist/commands/pull.js +121 -0
- package/dist/commands/push.d.ts +11 -0
- package/dist/commands/push.js +101 -0
- package/dist/commands/quick-setup.d.ts +20 -0
- package/dist/commands/quick-setup.js +422 -0
- package/dist/commands/recent.d.ts +9 -0
- package/dist/commands/recent.js +55 -0
- package/dist/commands/related.d.ts +23 -0
- package/dist/commands/related.js +257 -0
- package/dist/commands/repos.d.ts +14 -0
- package/dist/commands/repos.js +185 -0
- package/dist/commands/stack.d.ts +10 -0
- package/dist/commands/stack.js +83 -0
- package/dist/commands/status.d.ts +14 -0
- package/dist/commands/status.js +246 -0
- package/dist/commands/sync.d.ts +11 -0
- package/dist/commands/sync.js +142 -0
- package/dist/commands/unfocus.d.ts +6 -0
- package/dist/commands/unfocus.js +23 -0
- package/dist/commands/used-by.d.ts +10 -0
- package/dist/commands/used-by.js +111 -0
- package/dist/commands/workspace.d.ts +20 -0
- package/dist/commands/workspace.js +365 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +5 -0
- package/dist/models/entity.model.d.ts +81 -0
- package/dist/models/entity.model.js +2 -0
- package/dist/services/config.service.d.ts +34 -0
- package/dist/services/config.service.js +230 -0
- package/dist/services/entity.service.d.ts +19 -0
- package/dist/services/entity.service.js +130 -0
- package/dist/services/focus.service.d.ts +70 -0
- package/dist/services/focus.service.js +587 -0
- package/dist/services/git.service.d.ts +37 -0
- package/dist/services/git.service.js +180 -0
- package/dist/utils/display.d.ts +25 -0
- package/dist/utils/display.js +150 -0
- package/dist/utils/filesystem.d.ts +32 -0
- package/dist/utils/filesystem.js +220 -0
- package/dist/utils/index.d.ts +13 -0
- package/dist/utils/index.js +18 -0
- package/dist/utils/validation.d.ts +22 -0
- package/dist/utils/validation.js +196 -0
- package/oclif.manifest.json +1463 -0
- package/package.json +76 -0
|
@@ -0,0 +1,238 @@
|
|
|
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
|
+
class Graph extends base_command_1.BaseCommand {
|
|
8
|
+
static description = 'Visualize repository relationships and dependencies';
|
|
9
|
+
static examples = [
|
|
10
|
+
'<%= config.bin %> <%= command.id %>',
|
|
11
|
+
'<%= config.bin %> <%= command.id %> --format ascii',
|
|
12
|
+
'<%= config.bin %> <%= command.id %> --focus-only',
|
|
13
|
+
];
|
|
14
|
+
static flags = {
|
|
15
|
+
format: core_1.Flags.string({
|
|
16
|
+
char: 'f',
|
|
17
|
+
description: 'output format',
|
|
18
|
+
options: ['ascii', 'dot', 'json'],
|
|
19
|
+
default: 'ascii',
|
|
20
|
+
}),
|
|
21
|
+
'focus-only': core_1.Flags.boolean({
|
|
22
|
+
description: 'show only focused entities and their relationships',
|
|
23
|
+
default: false,
|
|
24
|
+
}),
|
|
25
|
+
depth: core_1.Flags.integer({
|
|
26
|
+
char: 'd',
|
|
27
|
+
description: 'maximum depth of relationships to show',
|
|
28
|
+
default: 2,
|
|
29
|
+
}),
|
|
30
|
+
};
|
|
31
|
+
async run() {
|
|
32
|
+
const { flags } = await this.parse(Graph);
|
|
33
|
+
const entities = flags['focus-only']
|
|
34
|
+
? await this.focusService.getFocusedEntities()
|
|
35
|
+
: this.entityService.getAllEntities();
|
|
36
|
+
if (entities.length === 0) {
|
|
37
|
+
this.error('No entities found. Add entities first or set focus.');
|
|
38
|
+
}
|
|
39
|
+
this.log(chalk_1.default.bold('\nšøļø Repository Relationship Graph'));
|
|
40
|
+
this.log(chalk_1.default.dim('ā'.repeat(50)));
|
|
41
|
+
const graph = await this.buildRelationshipGraph(entities, flags.depth);
|
|
42
|
+
switch (flags.format) {
|
|
43
|
+
case 'ascii':
|
|
44
|
+
this.displayAsciiGraph(graph);
|
|
45
|
+
break;
|
|
46
|
+
case 'dot':
|
|
47
|
+
this.displayDotGraph(graph);
|
|
48
|
+
break;
|
|
49
|
+
case 'json':
|
|
50
|
+
this.log(JSON.stringify(graph, null, 2));
|
|
51
|
+
break;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
async buildRelationshipGraph(entities, maxDepth) {
|
|
55
|
+
const nodes = new Map();
|
|
56
|
+
const edges = [];
|
|
57
|
+
// Build nodes
|
|
58
|
+
for (const entity of entities) {
|
|
59
|
+
nodes.set(entity.name, {
|
|
60
|
+
name: entity.name,
|
|
61
|
+
type: entity.type,
|
|
62
|
+
path: entity.path,
|
|
63
|
+
metadata: entity.metadata || {}
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
// Build edges from metadata relationships
|
|
67
|
+
for (const entity of entities) {
|
|
68
|
+
const metadata = entity.metadata;
|
|
69
|
+
if (!metadata?.relationships)
|
|
70
|
+
continue;
|
|
71
|
+
// Direct dependencies
|
|
72
|
+
if (metadata.relationships.dependent_systems) {
|
|
73
|
+
for (const dep of metadata.relationships.dependent_systems) {
|
|
74
|
+
edges.push({
|
|
75
|
+
from: entity.name,
|
|
76
|
+
to: dep,
|
|
77
|
+
type: 'depends_on',
|
|
78
|
+
weight: 1
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
// Similar entities
|
|
83
|
+
if (metadata.relationships.similar_entities) {
|
|
84
|
+
for (const similar of metadata.relationships.similar_entities) {
|
|
85
|
+
edges.push({
|
|
86
|
+
from: entity.name,
|
|
87
|
+
to: similar,
|
|
88
|
+
type: 'similar_to',
|
|
89
|
+
weight: 0.5
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
// Related initiatives
|
|
94
|
+
if (metadata.relationships.related_initiatives) {
|
|
95
|
+
for (const initiative of metadata.relationships.related_initiatives) {
|
|
96
|
+
edges.push({
|
|
97
|
+
from: entity.name,
|
|
98
|
+
to: initiative,
|
|
99
|
+
type: 'part_of',
|
|
100
|
+
weight: 0.7
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
// Infer additional relationships
|
|
106
|
+
this.inferRelationships(Array.from(nodes.values()), edges);
|
|
107
|
+
return {
|
|
108
|
+
nodes: Array.from(nodes.values()),
|
|
109
|
+
edges: edges
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
inferRelationships(nodes, edges) {
|
|
113
|
+
// Infer system dependencies
|
|
114
|
+
const systems = nodes.filter(n => n.type === 'system');
|
|
115
|
+
const clients = nodes.filter(n => n.type === 'client');
|
|
116
|
+
// All clients likely depend on systems
|
|
117
|
+
for (const client of clients) {
|
|
118
|
+
for (const system of systems) {
|
|
119
|
+
// Don't add if relationship already exists
|
|
120
|
+
const exists = edges.some(e => e.from === client.name && e.to === system.name);
|
|
121
|
+
if (!exists) {
|
|
122
|
+
edges.push({
|
|
123
|
+
from: client.name,
|
|
124
|
+
to: system.name,
|
|
125
|
+
type: 'likely_depends_on',
|
|
126
|
+
weight: 0.3
|
|
127
|
+
});
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
// Infer shared dependencies
|
|
132
|
+
const sharedSystems = systems.filter(s => s.name.includes('shared') || s.name.includes('common'));
|
|
133
|
+
for (const shared of sharedSystems) {
|
|
134
|
+
for (const entity of nodes) {
|
|
135
|
+
if (entity.type === 'client' || entity.type === 'delivery') {
|
|
136
|
+
const exists = edges.some(e => e.from === entity.name && e.to === shared.name);
|
|
137
|
+
if (!exists) {
|
|
138
|
+
edges.push({
|
|
139
|
+
from: entity.name,
|
|
140
|
+
to: shared.name,
|
|
141
|
+
type: 'uses_shared',
|
|
142
|
+
weight: 0.4
|
|
143
|
+
});
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
displayAsciiGraph(graph) {
|
|
150
|
+
const { nodes, edges } = graph;
|
|
151
|
+
// Group nodes by type
|
|
152
|
+
const byType = nodes.reduce((acc, node) => {
|
|
153
|
+
if (!acc[node.type])
|
|
154
|
+
acc[node.type] = [];
|
|
155
|
+
acc[node.type].push(node);
|
|
156
|
+
return acc;
|
|
157
|
+
}, {});
|
|
158
|
+
// Display nodes by type
|
|
159
|
+
const typeOrder = ['client', 'prospect', 'company', 'initiative', 'system'];
|
|
160
|
+
for (const type of typeOrder) {
|
|
161
|
+
if (!byType[type])
|
|
162
|
+
continue;
|
|
163
|
+
this.log(`\n${chalk_1.default.bold(type.toUpperCase())}:`);
|
|
164
|
+
for (const node of byType[type]) {
|
|
165
|
+
const emoji = this.getTypeEmoji(node.type);
|
|
166
|
+
this.log(` ${emoji} ${chalk_1.default.cyan(node.name)}`);
|
|
167
|
+
// Show outgoing relationships
|
|
168
|
+
const outgoing = edges.filter((e) => e.from === node.name);
|
|
169
|
+
for (const edge of outgoing) {
|
|
170
|
+
const relationshipIcon = this.getRelationshipIcon(edge.type);
|
|
171
|
+
const targetNode = nodes.find((n) => n.name === edge.to);
|
|
172
|
+
const targetEmoji = targetNode ? this.getTypeEmoji(targetNode.type) : 'š';
|
|
173
|
+
this.log(` ${relationshipIcon} ${targetEmoji} ${edge.to} ${chalk_1.default.dim(`(${edge.type})`)}`);
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
// Show relationship summary
|
|
178
|
+
this.log(chalk_1.default.bold('\nš Relationship Summary:'));
|
|
179
|
+
const relationshipCounts = edges.reduce((acc, edge) => {
|
|
180
|
+
acc[edge.type] = (acc[edge.type] || 0) + 1;
|
|
181
|
+
return acc;
|
|
182
|
+
}, {});
|
|
183
|
+
for (const [type, count] of Object.entries(relationshipCounts)) {
|
|
184
|
+
this.log(` ${this.getRelationshipIcon(type)} ${type}: ${count}`);
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
displayDotGraph(graph) {
|
|
188
|
+
const { nodes, edges } = graph;
|
|
189
|
+
this.log('digraph EntityGraph {');
|
|
190
|
+
this.log(' rankdir=TB;');
|
|
191
|
+
this.log(' node [shape=box, style=rounded];');
|
|
192
|
+
this.log('');
|
|
193
|
+
// Nodes
|
|
194
|
+
for (const node of nodes) {
|
|
195
|
+
const color = this.getNodeColor(node.type);
|
|
196
|
+
this.log(` "${node.name}" [label="${node.name}\\n(${node.type})", fillcolor="${color}", style=filled];`);
|
|
197
|
+
}
|
|
198
|
+
this.log('');
|
|
199
|
+
// Edges
|
|
200
|
+
for (const edge of edges) {
|
|
201
|
+
const style = edge.type.includes('likely') ? 'dashed' : 'solid';
|
|
202
|
+
const color = this.getEdgeColor(edge.type);
|
|
203
|
+
this.log(` "${edge.from}" -> "${edge.to}" [label="${edge.type}", style=${style}, color="${color}"];`);
|
|
204
|
+
}
|
|
205
|
+
this.log('}');
|
|
206
|
+
}
|
|
207
|
+
getRelationshipIcon(type) {
|
|
208
|
+
switch (type) {
|
|
209
|
+
case 'depends_on': return 'š';
|
|
210
|
+
case 'similar_to': return 'š';
|
|
211
|
+
case 'part_of': return 'š';
|
|
212
|
+
case 'likely_depends_on': return 'š';
|
|
213
|
+
case 'uses_shared': return 'š';
|
|
214
|
+
default: return 'ā';
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
getNodeColor(type) {
|
|
218
|
+
switch (type) {
|
|
219
|
+
case 'client': return 'lightblue';
|
|
220
|
+
case 'prospect': return 'lightyellow';
|
|
221
|
+
case 'company': return 'lightgreen';
|
|
222
|
+
case 'initiative': return 'lightcoral';
|
|
223
|
+
case 'system': return 'lightgray';
|
|
224
|
+
default: return 'white';
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
getEdgeColor(type) {
|
|
228
|
+
switch (type) {
|
|
229
|
+
case 'depends_on': return 'red';
|
|
230
|
+
case 'similar_to': return 'blue';
|
|
231
|
+
case 'part_of': return 'green';
|
|
232
|
+
case 'likely_depends_on': return 'orange';
|
|
233
|
+
case 'uses_shared': return 'purple';
|
|
234
|
+
default: return 'black';
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
exports.default = Graph;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { BaseCommand } from '../base-command';
|
|
2
|
+
export default class Init extends BaseCommand {
|
|
3
|
+
static description: string;
|
|
4
|
+
static examples: string[];
|
|
5
|
+
static flags: {
|
|
6
|
+
force: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
|
|
7
|
+
workspace: import("@oclif/core/lib/interfaces").OptionFlag<string, import("@oclif/core/lib/interfaces").CustomOptions>;
|
|
8
|
+
};
|
|
9
|
+
protected get requiresInit(): boolean;
|
|
10
|
+
run(): Promise<void>;
|
|
11
|
+
}
|
|
@@ -0,0 +1,84 @@
|
|
|
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 fs = tslib_1.__importStar(require("fs"));
|
|
7
|
+
const path = tslib_1.__importStar(require("path"));
|
|
8
|
+
class Init extends base_command_1.BaseCommand {
|
|
9
|
+
static description = 'Initialize a gut workspace';
|
|
10
|
+
static examples = [
|
|
11
|
+
'<%= config.bin %> <%= command.id %>',
|
|
12
|
+
'<%= config.bin %> <%= command.id %> --force',
|
|
13
|
+
];
|
|
14
|
+
static flags = {
|
|
15
|
+
force: core_1.Flags.boolean({
|
|
16
|
+
char: 'f',
|
|
17
|
+
description: 'force initialization even if already initialized',
|
|
18
|
+
}),
|
|
19
|
+
workspace: core_1.Flags.string({
|
|
20
|
+
char: 'w',
|
|
21
|
+
description: 'workspace root directory',
|
|
22
|
+
default: process.cwd(),
|
|
23
|
+
}),
|
|
24
|
+
};
|
|
25
|
+
get requiresInit() {
|
|
26
|
+
return false; // This command doesn't require initialization
|
|
27
|
+
}
|
|
28
|
+
async run() {
|
|
29
|
+
const { flags } = await this.parse(Init);
|
|
30
|
+
// Check if already initialized
|
|
31
|
+
if (this.configService.isInitialized() && !flags.force) {
|
|
32
|
+
this.log('Workspace already initialized. Use --force to reinitialize.');
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
this.log('š Initializing gut workspace...\n');
|
|
36
|
+
// Create .gut directory
|
|
37
|
+
const gutDir = this.configService.getGutDir();
|
|
38
|
+
if (!fs.existsSync(gutDir)) {
|
|
39
|
+
fs.mkdirSync(gutDir, { recursive: true });
|
|
40
|
+
this.log(`ā Created .gut directory`);
|
|
41
|
+
}
|
|
42
|
+
// Discover entities
|
|
43
|
+
this.log('\nš Discovering entities...');
|
|
44
|
+
const discovered = this.entityService.discoverEntities();
|
|
45
|
+
if (discovered.length > 0) {
|
|
46
|
+
this.log(`Found ${discovered.length} potential entities:`);
|
|
47
|
+
this.printEntityList(discovered);
|
|
48
|
+
// Save discovered entities
|
|
49
|
+
const config = {
|
|
50
|
+
initialized: true,
|
|
51
|
+
entities: discovered,
|
|
52
|
+
workspace: flags.workspace,
|
|
53
|
+
};
|
|
54
|
+
this.configService.saveConfig(config);
|
|
55
|
+
this.log('\nā Configuration saved');
|
|
56
|
+
}
|
|
57
|
+
else {
|
|
58
|
+
// Initialize with empty configuration
|
|
59
|
+
const config = {
|
|
60
|
+
initialized: true,
|
|
61
|
+
entities: [],
|
|
62
|
+
workspace: flags.workspace,
|
|
63
|
+
};
|
|
64
|
+
this.configService.saveConfig(config);
|
|
65
|
+
this.log('No entities discovered. You can add them manually with "gut entity add"');
|
|
66
|
+
}
|
|
67
|
+
// Add .gut to .gitignore if it exists
|
|
68
|
+
const gitignorePath = path.join(flags.workspace, '.gitignore');
|
|
69
|
+
if (fs.existsSync(gitignorePath)) {
|
|
70
|
+
const gitignore = fs.readFileSync(gitignorePath, 'utf8');
|
|
71
|
+
if (!gitignore.includes('.gut')) {
|
|
72
|
+
fs.appendFileSync(gitignorePath, '\n# Gut workspace files\n.gut/\n');
|
|
73
|
+
this.log('ā Added .gut to .gitignore');
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
this.log('\nā
Workspace initialized successfully!');
|
|
77
|
+
this.log('\nNext steps:');
|
|
78
|
+
this.log(' ⢠Review discovered entities: gut entity list');
|
|
79
|
+
this.log(' ⢠Add more entities: gut entity add <type> <name> --path <path>');
|
|
80
|
+
this.log(' ⢠Set focus: gut focus <entity>');
|
|
81
|
+
this.log(' ⢠Get help: gut help');
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
exports.default = Init;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import BaseCommand from '../base-command';
|
|
2
|
+
export default class Insights extends BaseCommand {
|
|
3
|
+
static description: string;
|
|
4
|
+
static examples: string[];
|
|
5
|
+
static flags: {
|
|
6
|
+
detailed: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
|
|
7
|
+
format: import("@oclif/core/lib/interfaces").OptionFlag<string, import("@oclif/core/lib/interfaces").CustomOptions>;
|
|
8
|
+
'include-ignored': import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
|
|
9
|
+
};
|
|
10
|
+
run(): Promise<void>;
|
|
11
|
+
private analyzeEntity;
|
|
12
|
+
private countFiles;
|
|
13
|
+
private getLanguageFromExt;
|
|
14
|
+
private isTextFile;
|
|
15
|
+
private formatSize;
|
|
16
|
+
private calculateWorkspaceStats;
|
|
17
|
+
private parseRelativeDate;
|
|
18
|
+
private printTable;
|
|
19
|
+
private printSummary;
|
|
20
|
+
private printJSON;
|
|
21
|
+
}
|