@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,109 @@
|
|
|
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 = tslib_1.__importDefault(require("../../base-command"));
|
|
6
|
+
const path = tslib_1.__importStar(require("path"));
|
|
7
|
+
const fs = tslib_1.__importStar(require("fs"));
|
|
8
|
+
const child_process_1 = require("child_process");
|
|
9
|
+
const chalk_1 = tslib_1.__importDefault(require("chalk"));
|
|
10
|
+
const ora_1 = tslib_1.__importDefault(require("ora"));
|
|
11
|
+
class Clone extends base_command_1.default {
|
|
12
|
+
static description = 'Clone a specific entity from its repository';
|
|
13
|
+
static examples = [
|
|
14
|
+
'<%= config.bin %> <%= command.id %> my-app',
|
|
15
|
+
'<%= config.bin %> <%= command.id %> my-app --branch develop',
|
|
16
|
+
'<%= config.bin %> <%= command.id %> my-app --depth 1',
|
|
17
|
+
];
|
|
18
|
+
static flags = {
|
|
19
|
+
branch: core_1.Flags.string({
|
|
20
|
+
char: 'b',
|
|
21
|
+
description: 'Branch to clone',
|
|
22
|
+
default: 'main',
|
|
23
|
+
}),
|
|
24
|
+
depth: core_1.Flags.integer({
|
|
25
|
+
char: 'd',
|
|
26
|
+
description: 'Create a shallow clone with specified depth',
|
|
27
|
+
}),
|
|
28
|
+
path: core_1.Flags.string({
|
|
29
|
+
char: 'p',
|
|
30
|
+
description: 'Custom path to clone to (relative to workspace)',
|
|
31
|
+
}),
|
|
32
|
+
force: core_1.Flags.boolean({
|
|
33
|
+
char: 'f',
|
|
34
|
+
description: 'Force clone even if directory exists',
|
|
35
|
+
default: false,
|
|
36
|
+
}),
|
|
37
|
+
};
|
|
38
|
+
static args = {
|
|
39
|
+
name: core_1.Args.string({
|
|
40
|
+
name: 'name',
|
|
41
|
+
required: true,
|
|
42
|
+
description: 'Name of the entity to clone',
|
|
43
|
+
}),
|
|
44
|
+
};
|
|
45
|
+
async run() {
|
|
46
|
+
const { args, flags } = await this.parse(Clone);
|
|
47
|
+
const { name } = args;
|
|
48
|
+
const { branch, depth, path: customPath, force } = flags;
|
|
49
|
+
const spinner = (0, ora_1.default)();
|
|
50
|
+
try {
|
|
51
|
+
const entity = await this.entityService.getEntity(name);
|
|
52
|
+
if (!entity) {
|
|
53
|
+
this.error(`Entity '${name}' not found`);
|
|
54
|
+
}
|
|
55
|
+
if (!entity.repository) {
|
|
56
|
+
this.error(`Entity '${name}' has no repository configured`);
|
|
57
|
+
}
|
|
58
|
+
const clonePath = customPath
|
|
59
|
+
? path.resolve(this.config.root, customPath)
|
|
60
|
+
: path.resolve(this.config.root, entity.path);
|
|
61
|
+
if (fs.existsSync(clonePath)) {
|
|
62
|
+
if (!force) {
|
|
63
|
+
this.error(`Directory already exists: ${clonePath}. Use --force to overwrite`);
|
|
64
|
+
}
|
|
65
|
+
spinner.start(`Removing existing directory: ${clonePath}`);
|
|
66
|
+
(0, child_process_1.execSync)(`rm -rf ${clonePath}`, { stdio: 'pipe' });
|
|
67
|
+
spinner.succeed(`Removed existing directory`);
|
|
68
|
+
}
|
|
69
|
+
const parentDir = path.dirname(clonePath);
|
|
70
|
+
if (!fs.existsSync(parentDir)) {
|
|
71
|
+
fs.mkdirSync(parentDir, { recursive: true });
|
|
72
|
+
}
|
|
73
|
+
let cloneCommand = `git clone`;
|
|
74
|
+
if (branch && branch !== 'main') {
|
|
75
|
+
cloneCommand += ` -b ${branch}`;
|
|
76
|
+
}
|
|
77
|
+
if (depth) {
|
|
78
|
+
cloneCommand += ` --depth ${depth}`;
|
|
79
|
+
}
|
|
80
|
+
cloneCommand += ` ${entity.repository} ${clonePath}`;
|
|
81
|
+
spinner.start(`Cloning ${name} from ${entity.repository}`);
|
|
82
|
+
try {
|
|
83
|
+
(0, child_process_1.execSync)(cloneCommand, { stdio: 'pipe' });
|
|
84
|
+
spinner.succeed(`Successfully cloned ${name}`);
|
|
85
|
+
}
|
|
86
|
+
catch (error) {
|
|
87
|
+
spinner.fail(`Failed to clone ${name}`);
|
|
88
|
+
this.error(error.message);
|
|
89
|
+
}
|
|
90
|
+
if (customPath && customPath !== entity.path) {
|
|
91
|
+
entity.path = customPath;
|
|
92
|
+
await this.entityService.updateEntity(name, entity);
|
|
93
|
+
this.log(chalk_1.default.yellow(`Updated entity path to: ${customPath}`));
|
|
94
|
+
}
|
|
95
|
+
this.log(chalk_1.default.green(`ā Entity '${name}' cloned to ${clonePath}`));
|
|
96
|
+
const gitBranch = (0, child_process_1.execSync)('git branch --show-current', {
|
|
97
|
+
cwd: clonePath,
|
|
98
|
+
encoding: 'utf-8'
|
|
99
|
+
}).trim();
|
|
100
|
+
this.log(chalk_1.default.dim(` Branch: ${gitBranch}`));
|
|
101
|
+
this.log(chalk_1.default.dim(` Repository: ${entity.repository}`));
|
|
102
|
+
}
|
|
103
|
+
catch (error) {
|
|
104
|
+
spinner.fail();
|
|
105
|
+
this.error(error.message);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
exports.default = Clone;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { BaseCommand } from '../../base-command';
|
|
2
|
+
export default class ListEntities extends BaseCommand {
|
|
3
|
+
static description: string;
|
|
4
|
+
static examples: string[];
|
|
5
|
+
static flags: {
|
|
6
|
+
type: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
|
|
7
|
+
json: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
|
|
8
|
+
verbose: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
|
|
9
|
+
};
|
|
10
|
+
run(): Promise<void>;
|
|
11
|
+
}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const core_1 = require("@oclif/core");
|
|
4
|
+
const base_command_1 = require("../../base-command");
|
|
5
|
+
class ListEntities extends base_command_1.BaseCommand {
|
|
6
|
+
static description = 'List all configured entities';
|
|
7
|
+
static examples = [
|
|
8
|
+
'<%= config.bin %> <%= command.id %>',
|
|
9
|
+
'<%= config.bin %> <%= command.id %> --type delivery',
|
|
10
|
+
'<%= config.bin %> <%= command.id %> --json',
|
|
11
|
+
];
|
|
12
|
+
static flags = {
|
|
13
|
+
type: core_1.Flags.string({
|
|
14
|
+
char: 't',
|
|
15
|
+
description: 'filter by entity type',
|
|
16
|
+
options: ['delivery', 'module', 'service', 'tool'],
|
|
17
|
+
}),
|
|
18
|
+
json: core_1.Flags.boolean({
|
|
19
|
+
description: 'output as JSON',
|
|
20
|
+
}),
|
|
21
|
+
verbose: core_1.Flags.boolean({
|
|
22
|
+
char: 'v',
|
|
23
|
+
description: 'show detailed information',
|
|
24
|
+
}),
|
|
25
|
+
};
|
|
26
|
+
async run() {
|
|
27
|
+
const { flags } = await this.parse(ListEntities);
|
|
28
|
+
let entities = this.entityService.getAllEntities();
|
|
29
|
+
// Filter by type if specified
|
|
30
|
+
if (flags.type) {
|
|
31
|
+
entities = entities.filter(e => e.type === flags.type);
|
|
32
|
+
}
|
|
33
|
+
// JSON output
|
|
34
|
+
if (flags.json) {
|
|
35
|
+
this.log(JSON.stringify(entities, null, 2));
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
38
|
+
// Regular output
|
|
39
|
+
if (entities.length === 0) {
|
|
40
|
+
if (flags.type) {
|
|
41
|
+
this.log(`No ${flags.type} entities configured`);
|
|
42
|
+
}
|
|
43
|
+
else {
|
|
44
|
+
this.log('No entities configured');
|
|
45
|
+
this.log('\nAdd entities with: gut entity add <type> <name> --path <path>');
|
|
46
|
+
}
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
|
+
this.log(`\n${entities.length} entities configured:`);
|
|
50
|
+
if (flags.verbose) {
|
|
51
|
+
// Detailed view
|
|
52
|
+
for (const entity of entities) {
|
|
53
|
+
this.log(`\n${this.getTypeEmoji(entity.type)} ${entity.name}`);
|
|
54
|
+
this.log(` Type: ${entity.type}`);
|
|
55
|
+
this.log(` Path: ${entity.path}`);
|
|
56
|
+
if (entity.remote) {
|
|
57
|
+
this.log(` Remote: ${entity.remote}`);
|
|
58
|
+
}
|
|
59
|
+
if (entity.repo) {
|
|
60
|
+
this.log(` Repo: ${entity.repo}`);
|
|
61
|
+
}
|
|
62
|
+
if (entity.description) {
|
|
63
|
+
this.log(` Description: ${entity.description}`);
|
|
64
|
+
}
|
|
65
|
+
// Check if focused
|
|
66
|
+
if (await this.focusService.isFocused(entity.name)) {
|
|
67
|
+
this.log(` Status: šÆ FOCUSED`);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
else {
|
|
72
|
+
// Simple view
|
|
73
|
+
this.printEntityList(entities);
|
|
74
|
+
// Show focused entities
|
|
75
|
+
const focusedEntities = await this.focusService.getFocusedEntities();
|
|
76
|
+
if (focusedEntities.length > 0) {
|
|
77
|
+
this.log(`\nšÆ Current focus: ${focusedEntities.map(e => e.name).join(', ')}`);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
exports.default = ListEntities;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { BaseCommand } from '../../base-command';
|
|
2
|
+
export default class RemoveEntity extends BaseCommand {
|
|
3
|
+
static description: string;
|
|
4
|
+
static examples: string[];
|
|
5
|
+
static args: {
|
|
6
|
+
name: import("@oclif/core/lib/interfaces").Arg<string, Record<string, unknown>>;
|
|
7
|
+
};
|
|
8
|
+
static flags: {
|
|
9
|
+
force: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
|
|
10
|
+
};
|
|
11
|
+
run(): Promise<void>;
|
|
12
|
+
}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const core_1 = require("@oclif/core");
|
|
4
|
+
const base_command_1 = require("../../base-command");
|
|
5
|
+
class RemoveEntity extends base_command_1.BaseCommand {
|
|
6
|
+
static description = 'Remove an entity from the workspace configuration';
|
|
7
|
+
static examples = [
|
|
8
|
+
'<%= config.bin %> <%= command.id %> my-app',
|
|
9
|
+
'<%= config.bin %> <%= command.id %> my-app --force',
|
|
10
|
+
];
|
|
11
|
+
static args = {
|
|
12
|
+
name: core_1.Args.string({
|
|
13
|
+
name: 'name',
|
|
14
|
+
required: true,
|
|
15
|
+
description: 'Entity name to remove',
|
|
16
|
+
}),
|
|
17
|
+
};
|
|
18
|
+
static flags = {
|
|
19
|
+
force: core_1.Flags.boolean({
|
|
20
|
+
char: 'f',
|
|
21
|
+
description: 'skip confirmation prompt',
|
|
22
|
+
}),
|
|
23
|
+
};
|
|
24
|
+
async run() {
|
|
25
|
+
const { args, flags } = await this.parse(RemoveEntity);
|
|
26
|
+
// Check if entity exists
|
|
27
|
+
const entity = this.entityService.findEntity(args.name);
|
|
28
|
+
if (!entity) {
|
|
29
|
+
this.error(`Entity '${args.name}' not found`);
|
|
30
|
+
}
|
|
31
|
+
// Check if entity is currently focused
|
|
32
|
+
if (await this.focusService.isFocused(args.name)) {
|
|
33
|
+
this.warn(`Entity '${args.name}' is currently focused`);
|
|
34
|
+
if (!flags.force) {
|
|
35
|
+
this.error('Cannot remove focused entity. Unfocus first with "gut unfocus" or use --force');
|
|
36
|
+
}
|
|
37
|
+
// Clear focus if forcing
|
|
38
|
+
await this.focusService.clearFocus();
|
|
39
|
+
this.log('Cleared focus');
|
|
40
|
+
}
|
|
41
|
+
// Confirmation prompt if not forcing
|
|
42
|
+
if (!flags.force) {
|
|
43
|
+
this.log(`\nAbout to remove entity:`);
|
|
44
|
+
this.log(` Name: ${entity.name}`);
|
|
45
|
+
this.log(` Type: ${entity.type}`);
|
|
46
|
+
this.log(` Path: ${entity.path}`);
|
|
47
|
+
// In a real implementation, we'd use inquirer or similar for prompts
|
|
48
|
+
// For now, we'll just proceed with a warning
|
|
49
|
+
this.warn('\nThis will only remove the entity from gut configuration.');
|
|
50
|
+
this.warn('The actual files/directory will NOT be deleted.');
|
|
51
|
+
}
|
|
52
|
+
// Remove entity
|
|
53
|
+
this.entityService.removeEntity(args.name);
|
|
54
|
+
this.log(`\nā
Removed entity '${args.name}' from configuration`);
|
|
55
|
+
this.log('Note: The actual files/directory were not deleted');
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
exports.default = RemoveEntity;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { BaseCommand } from '../base-command';
|
|
2
|
+
export default class Focus extends BaseCommand {
|
|
3
|
+
static description: string;
|
|
4
|
+
static examples: string[];
|
|
5
|
+
static args: {
|
|
6
|
+
entityTypeOrName: import("@oclif/core/lib/interfaces").Arg<string | undefined, Record<string, unknown>>;
|
|
7
|
+
entityName: import("@oclif/core/lib/interfaces").Arg<string | undefined, Record<string, unknown>>;
|
|
8
|
+
};
|
|
9
|
+
static flags: {
|
|
10
|
+
clear: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
|
|
11
|
+
add: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
|
|
12
|
+
mode: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
|
|
13
|
+
duration: import("@oclif/core/lib/interfaces").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces").CustomOptions>;
|
|
14
|
+
remember: import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
|
|
15
|
+
};
|
|
16
|
+
static strict: boolean;
|
|
17
|
+
run(): Promise<void>;
|
|
18
|
+
private isEntityType;
|
|
19
|
+
}
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const core_1 = require("@oclif/core");
|
|
4
|
+
const base_command_1 = require("../base-command");
|
|
5
|
+
class Focus extends base_command_1.BaseCommand {
|
|
6
|
+
static description = 'Set focus on one or more entities with optional type and mode';
|
|
7
|
+
static examples = [
|
|
8
|
+
'<%= config.bin %> <%= command.id %> my-app',
|
|
9
|
+
'<%= config.bin %> <%= command.id %> client mindtools',
|
|
10
|
+
'<%= config.bin %> <%= command.id %> client mindtools --mode delivery',
|
|
11
|
+
'<%= config.bin %> <%= command.id %> prospect jazida --mode research',
|
|
12
|
+
'<%= config.bin %> <%= command.id %> my-app auth-service',
|
|
13
|
+
'<%= config.bin %> <%= command.id %> --clear',
|
|
14
|
+
];
|
|
15
|
+
static args = {
|
|
16
|
+
entityTypeOrName: core_1.Args.string({
|
|
17
|
+
name: 'entityTypeOrName',
|
|
18
|
+
required: false,
|
|
19
|
+
description: 'Entity type (client/prospect/company/initiative) or entity name',
|
|
20
|
+
}),
|
|
21
|
+
entityName: core_1.Args.string({
|
|
22
|
+
name: 'entityName',
|
|
23
|
+
required: false,
|
|
24
|
+
description: 'Entity name (when first arg is entity type)',
|
|
25
|
+
}),
|
|
26
|
+
};
|
|
27
|
+
static flags = {
|
|
28
|
+
clear: core_1.Flags.boolean({
|
|
29
|
+
char: 'c',
|
|
30
|
+
description: 'clear current focus',
|
|
31
|
+
exclusive: ['add', 'mode'],
|
|
32
|
+
}),
|
|
33
|
+
add: core_1.Flags.boolean({
|
|
34
|
+
char: 'a',
|
|
35
|
+
description: 'add to current focus instead of replacing',
|
|
36
|
+
}),
|
|
37
|
+
mode: core_1.Flags.string({
|
|
38
|
+
char: 'm',
|
|
39
|
+
description: 'focus mode (delivery, strategy, audit, debug, research, proposal)',
|
|
40
|
+
options: ['delivery', 'strategy', 'audit', 'debug', 'research', 'proposal'],
|
|
41
|
+
}),
|
|
42
|
+
duration: core_1.Flags.string({
|
|
43
|
+
char: 'd',
|
|
44
|
+
description: 'focus duration (e.g., 2h, 90m)',
|
|
45
|
+
}),
|
|
46
|
+
remember: core_1.Flags.boolean({
|
|
47
|
+
char: 'r',
|
|
48
|
+
description: 'remember current focus before switching',
|
|
49
|
+
}),
|
|
50
|
+
};
|
|
51
|
+
static strict = false; // Allow multiple arguments
|
|
52
|
+
async run() {
|
|
53
|
+
const { flags, argv, args } = await this.parse(Focus);
|
|
54
|
+
// Clear focus
|
|
55
|
+
if (flags.clear) {
|
|
56
|
+
await this.focusService.clearFocus();
|
|
57
|
+
this.log('ā Focus cleared');
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
// Show current focus if no arguments
|
|
61
|
+
if (argv.length === 0) {
|
|
62
|
+
const focus = await this.focusService.getCurrentFocus();
|
|
63
|
+
if (!focus) {
|
|
64
|
+
this.log('No current focus');
|
|
65
|
+
this.log('\nSet focus with: gut focus <entity-name>');
|
|
66
|
+
this.log('Or: gut focus <entity-type> <entity-name>');
|
|
67
|
+
this.log('\nExamples:');
|
|
68
|
+
this.log(' gut focus client mindtools --mode delivery');
|
|
69
|
+
this.log(' gut focus prospect jazida --mode research');
|
|
70
|
+
return;
|
|
71
|
+
}
|
|
72
|
+
const entities = await this.focusService.getFocusedEntities();
|
|
73
|
+
this.log(`\nšÆ Current focus: ${await this.focusService.getFocusDescription()}`);
|
|
74
|
+
if (focus.mode) {
|
|
75
|
+
this.log(`š Mode: ${focus.mode}`);
|
|
76
|
+
}
|
|
77
|
+
if (entities.length > 0) {
|
|
78
|
+
this.log('\nFocused entities:');
|
|
79
|
+
for (const entity of entities) {
|
|
80
|
+
this.log(` ${this.getTypeEmoji(entity.type)} ${entity.name} (${entity.type}) - ${entity.path}`);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
return;
|
|
84
|
+
}
|
|
85
|
+
try {
|
|
86
|
+
// Parse arguments - support both "entity-name" and "entity-type entity-name" formats
|
|
87
|
+
let entityNames = [];
|
|
88
|
+
let entityType = undefined;
|
|
89
|
+
if (argv.length >= 2 && this.isEntityType(String(argv[0]))) {
|
|
90
|
+
// Format: gut focus client mindtools
|
|
91
|
+
entityType = argv[0];
|
|
92
|
+
entityNames = argv.slice(1).map(String);
|
|
93
|
+
}
|
|
94
|
+
else {
|
|
95
|
+
// Format: gut focus mindtools (backward compatibility)
|
|
96
|
+
entityNames = argv.map(String);
|
|
97
|
+
}
|
|
98
|
+
if (flags.remember) {
|
|
99
|
+
// Save current focus to stack before switching
|
|
100
|
+
await this.focusService.pushFocusToStack();
|
|
101
|
+
}
|
|
102
|
+
if (flags.add) {
|
|
103
|
+
// Add to existing focus
|
|
104
|
+
await this.focusService.addToFocus(entityNames, {
|
|
105
|
+
entityType,
|
|
106
|
+
mode: flags.mode,
|
|
107
|
+
duration: flags.duration,
|
|
108
|
+
});
|
|
109
|
+
this.log(`ā Added to focus: ${entityNames.join(', ')}`);
|
|
110
|
+
}
|
|
111
|
+
else {
|
|
112
|
+
// Set new focus
|
|
113
|
+
await this.focusService.setFocus(entityNames, {
|
|
114
|
+
entityType,
|
|
115
|
+
mode: flags.mode,
|
|
116
|
+
duration: flags.duration,
|
|
117
|
+
});
|
|
118
|
+
const modeText = flags.mode ? ` (${flags.mode} mode)` : '';
|
|
119
|
+
this.log(`ā Focus set to: ${entityNames.join(', ')}${modeText}`);
|
|
120
|
+
}
|
|
121
|
+
// Show what's now focused
|
|
122
|
+
const entities = await this.focusService.getFocusedEntities();
|
|
123
|
+
if (entities.length > 1) {
|
|
124
|
+
this.log(`\nNow focused on ${entities.length} entities:`);
|
|
125
|
+
for (const entity of entities) {
|
|
126
|
+
this.log(` ${this.getTypeEmoji(entity.type)} ${entity.name} (${entity.type})`);
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
catch (error) {
|
|
131
|
+
this.error(error.message);
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
isEntityType(value) {
|
|
135
|
+
const entityTypes = ['client', 'prospect', 'company', 'initiative', 'system', 'delivery', 'module', 'service', 'tool'];
|
|
136
|
+
return entityTypes.includes(value);
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
exports.default = Focus;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { BaseCommand } from '../base-command';
|
|
2
|
+
export default class Graph extends BaseCommand {
|
|
3
|
+
static description: string;
|
|
4
|
+
static examples: string[];
|
|
5
|
+
static flags: {
|
|
6
|
+
format: import("@oclif/core/lib/interfaces").OptionFlag<string, import("@oclif/core/lib/interfaces").CustomOptions>;
|
|
7
|
+
'focus-only': import("@oclif/core/lib/interfaces").BooleanFlag<boolean>;
|
|
8
|
+
depth: import("@oclif/core/lib/interfaces").OptionFlag<number, import("@oclif/core/lib/interfaces").CustomOptions>;
|
|
9
|
+
};
|
|
10
|
+
run(): Promise<void>;
|
|
11
|
+
private buildRelationshipGraph;
|
|
12
|
+
private inferRelationships;
|
|
13
|
+
private displayAsciiGraph;
|
|
14
|
+
private displayDotGraph;
|
|
15
|
+
private getRelationshipIcon;
|
|
16
|
+
private getNodeColor;
|
|
17
|
+
private getEdgeColor;
|
|
18
|
+
}
|