@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.
Files changed (87) hide show
  1. package/README.md +809 -0
  2. package/bin/dev +16 -0
  3. package/bin/run +5 -0
  4. package/dist/base-command.d.ts +21 -0
  5. package/dist/base-command.js +110 -0
  6. package/dist/commands/add.d.ts +13 -0
  7. package/dist/commands/add.js +73 -0
  8. package/dist/commands/affected.d.ts +23 -0
  9. package/dist/commands/affected.js +326 -0
  10. package/dist/commands/audit.d.ts +33 -0
  11. package/dist/commands/audit.js +593 -0
  12. package/dist/commands/back.d.ts +6 -0
  13. package/dist/commands/back.js +29 -0
  14. package/dist/commands/commit.d.ts +11 -0
  15. package/dist/commands/commit.js +113 -0
  16. package/dist/commands/context.d.ts +6 -0
  17. package/dist/commands/context.js +36 -0
  18. package/dist/commands/contexts.d.ts +7 -0
  19. package/dist/commands/contexts.js +92 -0
  20. package/dist/commands/deps.d.ts +10 -0
  21. package/dist/commands/deps.js +104 -0
  22. package/dist/commands/entity/add.d.ts +16 -0
  23. package/dist/commands/entity/add.js +105 -0
  24. package/dist/commands/entity/clone-all.d.ts +17 -0
  25. package/dist/commands/entity/clone-all.js +135 -0
  26. package/dist/commands/entity/clone.d.ts +15 -0
  27. package/dist/commands/entity/clone.js +109 -0
  28. package/dist/commands/entity/list.d.ts +11 -0
  29. package/dist/commands/entity/list.js +82 -0
  30. package/dist/commands/entity/remove.d.ts +12 -0
  31. package/dist/commands/entity/remove.js +58 -0
  32. package/dist/commands/focus.d.ts +19 -0
  33. package/dist/commands/focus.js +139 -0
  34. package/dist/commands/graph.d.ts +18 -0
  35. package/dist/commands/graph.js +238 -0
  36. package/dist/commands/init.d.ts +11 -0
  37. package/dist/commands/init.js +84 -0
  38. package/dist/commands/insights.d.ts +21 -0
  39. package/dist/commands/insights.js +434 -0
  40. package/dist/commands/patterns.d.ts +40 -0
  41. package/dist/commands/patterns.js +412 -0
  42. package/dist/commands/pull.d.ts +11 -0
  43. package/dist/commands/pull.js +121 -0
  44. package/dist/commands/push.d.ts +11 -0
  45. package/dist/commands/push.js +101 -0
  46. package/dist/commands/quick-setup.d.ts +20 -0
  47. package/dist/commands/quick-setup.js +422 -0
  48. package/dist/commands/recent.d.ts +9 -0
  49. package/dist/commands/recent.js +55 -0
  50. package/dist/commands/related.d.ts +23 -0
  51. package/dist/commands/related.js +257 -0
  52. package/dist/commands/repos.d.ts +14 -0
  53. package/dist/commands/repos.js +185 -0
  54. package/dist/commands/stack.d.ts +10 -0
  55. package/dist/commands/stack.js +83 -0
  56. package/dist/commands/status.d.ts +14 -0
  57. package/dist/commands/status.js +246 -0
  58. package/dist/commands/sync.d.ts +11 -0
  59. package/dist/commands/sync.js +142 -0
  60. package/dist/commands/unfocus.d.ts +6 -0
  61. package/dist/commands/unfocus.js +23 -0
  62. package/dist/commands/used-by.d.ts +10 -0
  63. package/dist/commands/used-by.js +111 -0
  64. package/dist/commands/workspace.d.ts +20 -0
  65. package/dist/commands/workspace.js +365 -0
  66. package/dist/index.d.ts +1 -0
  67. package/dist/index.js +5 -0
  68. package/dist/models/entity.model.d.ts +81 -0
  69. package/dist/models/entity.model.js +2 -0
  70. package/dist/services/config.service.d.ts +34 -0
  71. package/dist/services/config.service.js +230 -0
  72. package/dist/services/entity.service.d.ts +19 -0
  73. package/dist/services/entity.service.js +130 -0
  74. package/dist/services/focus.service.d.ts +70 -0
  75. package/dist/services/focus.service.js +587 -0
  76. package/dist/services/git.service.d.ts +37 -0
  77. package/dist/services/git.service.js +180 -0
  78. package/dist/utils/display.d.ts +25 -0
  79. package/dist/utils/display.js +150 -0
  80. package/dist/utils/filesystem.d.ts +32 -0
  81. package/dist/utils/filesystem.js +220 -0
  82. package/dist/utils/index.d.ts +13 -0
  83. package/dist/utils/index.js +18 -0
  84. package/dist/utils/validation.d.ts +22 -0
  85. package/dist/utils/validation.js +196 -0
  86. package/oclif.manifest.json +1463 -0
  87. 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
+ }