@shepai/cli 1.35.3 → 1.37.0
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/dist/packages/core/src/application/ports/output/agents/phase-timing-repository.interface.d.ts +7 -0
- package/dist/packages/core/src/application/ports/output/agents/phase-timing-repository.interface.d.ts.map +1 -1
- package/dist/packages/core/src/application/ports/output/services/ide-launcher-service.interface.d.ts +64 -0
- package/dist/packages/core/src/application/ports/output/services/ide-launcher-service.interface.d.ts.map +1 -0
- package/dist/packages/core/src/application/ports/output/services/ide-launcher-service.interface.js +7 -0
- package/dist/packages/core/src/application/ports/output/services/index.d.ts +1 -0
- package/dist/packages/core/src/application/ports/output/services/index.d.ts.map +1 -1
- package/dist/packages/core/src/application/use-cases/agents/approve-agent-run.use-case.d.ts +3 -1
- package/dist/packages/core/src/application/use-cases/agents/approve-agent-run.use-case.d.ts.map +1 -1
- package/dist/packages/core/src/application/use-cases/agents/approve-agent-run.use-case.js +22 -2
- package/dist/packages/core/src/application/use-cases/ide/launch-ide.use-case.d.ts +20 -0
- package/dist/packages/core/src/application/use-cases/ide/launch-ide.use-case.d.ts.map +1 -0
- package/dist/packages/core/src/application/use-cases/ide/launch-ide.use-case.js +54 -0
- package/dist/packages/core/src/domain/generated/output.d.ts +8 -0
- package/dist/packages/core/src/domain/generated/output.d.ts.map +1 -1
- package/dist/packages/core/src/infrastructure/di/container.d.ts.map +1 -1
- package/dist/packages/core/src/infrastructure/di/container.js +7 -0
- package/dist/packages/core/src/infrastructure/persistence/sqlite/migrations.d.ts.map +1 -1
- package/dist/packages/core/src/infrastructure/persistence/sqlite/migrations.js +8 -0
- package/dist/packages/core/src/infrastructure/repositories/sqlite-phase-timing.repository.d.ts +1 -0
- package/dist/packages/core/src/infrastructure/repositories/sqlite-phase-timing.repository.d.ts.map +1 -1
- package/dist/packages/core/src/infrastructure/repositories/sqlite-phase-timing.repository.js +28 -0
- package/dist/packages/core/src/infrastructure/services/agents/feature-agent/feature-agent-worker.d.ts.map +1 -1
- package/dist/packages/core/src/infrastructure/services/agents/feature-agent/feature-agent-worker.js +3 -1
- package/dist/packages/core/src/infrastructure/services/agents/feature-agent/phase-timing-context.d.ts +9 -0
- package/dist/packages/core/src/infrastructure/services/agents/feature-agent/phase-timing-context.d.ts.map +1 -1
- package/dist/packages/core/src/infrastructure/services/agents/feature-agent/phase-timing-context.js +26 -0
- package/dist/packages/core/src/infrastructure/services/ide-launchers/json-driven-ide-launcher.service.d.ts +23 -0
- package/dist/packages/core/src/infrastructure/services/ide-launchers/json-driven-ide-launcher.service.d.ts.map +1 -0
- package/dist/packages/core/src/infrastructure/services/ide-launchers/json-driven-ide-launcher.service.js +114 -0
- package/dist/packages/core/src/infrastructure/services/tool-installer/tool-metadata.d.ts +20 -4
- package/dist/packages/core/src/infrastructure/services/tool-installer/tool-metadata.d.ts.map +1 -1
- package/dist/packages/core/src/infrastructure/services/tool-installer/tool-metadata.js +9 -1
- package/dist/packages/core/src/infrastructure/services/tool-installer/tools/antigravity.json +5 -2
- package/dist/packages/core/src/infrastructure/services/tool-installer/tools/claude-code.json +8 -2
- package/dist/packages/core/src/infrastructure/services/tool-installer/tools/cursor-cli.json +8 -2
- package/dist/packages/core/src/infrastructure/services/tool-installer/tools/cursor.json +2 -2
- package/dist/packages/core/src/infrastructure/services/tool-installer/tools/vscode.json +2 -2
- package/dist/packages/core/src/infrastructure/services/tool-installer/tools/windsurf.json +2 -2
- package/dist/packages/core/src/infrastructure/services/tool-installer/tools/zed.json +2 -2
- package/dist/src/presentation/cli/commands/feat/show.command.d.ts.map +1 -1
- package/dist/src/presentation/cli/commands/feat/show.command.js +46 -12
- package/dist/src/presentation/cli/commands/ide-open.command.d.ts +3 -1
- package/dist/src/presentation/cli/commands/ide-open.command.d.ts.map +1 -1
- package/dist/src/presentation/cli/commands/ide-open.command.js +27 -28
- package/dist/src/presentation/cli/commands/install.command.js +3 -3
- package/dist/src/presentation/cli/commands/settings/ide.command.d.ts +1 -0
- package/dist/src/presentation/cli/commands/settings/ide.command.d.ts.map +1 -1
- package/dist/src/presentation/cli/commands/settings/ide.command.js +10 -13
- package/dist/src/presentation/tui/prompts/ide-select.prompt.d.ts +9 -25
- package/dist/src/presentation/tui/prompts/ide-select.prompt.d.ts.map +1 -1
- package/dist/src/presentation/tui/prompts/ide-select.prompt.js +9 -29
- package/dist/src/presentation/web/app/api/ide/open/route.d.ts.map +1 -1
- package/dist/src/presentation/web/app/api/ide/open/route.js +3 -2
- package/dist/tsconfig.build.tsbuildinfo +1 -1
- package/package.json +1 -1
- package/web/.next/BUILD_ID +1 -1
- package/web/.next/build-manifest.json +2 -2
- package/web/.next/cache/.previewinfo +1 -1
- package/web/.next/cache/.rscinfo +1 -1
- package/web/.next/cache/.tsbuildinfo +1 -1
- package/web/.next/cache/config.json +3 -3
- package/web/.next/fallback-build-manifest.json +2 -2
- package/web/.next/prerender-manifest.json +3 -3
- package/web/.next/required-server-files.js +1 -1
- package/web/.next/required-server-files.json +1 -1
- package/web/.next/server/app/_global-error.html +2 -2
- package/web/.next/server/app/_global-error.rsc +1 -1
- package/web/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +1 -1
- package/web/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
- package/web/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
- package/web/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
- package/web/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
- package/web/.next/server/app/api/ide/open/route.js +1 -2
- package/web/.next/server/app/api/ide/open/route.js.nft.json +1 -1
- package/web/.next/server/app/api/shell/open/route.js +1 -1
- package/web/.next/server/app/api/shell/open/route.js.nft.json +1 -1
- package/web/.next/server/chunks/[root-of-the-server]__04ae3a77._.js +3 -0
- package/web/.next/server/chunks/[root-of-the-server]__04ae3a77._.js.map +1 -0
- package/web/.next/server/chunks/[root-of-the-server]__f32c280c._.js +3 -0
- package/web/.next/server/chunks/[root-of-the-server]__f32c280c._.js.map +1 -0
- package/web/.next/server/chunks/ssr/[root-of-the-server]__f12b60be._.js +1 -1
- package/web/.next/server/chunks/ssr/src_presentation_web_components_e599bb8c._.js.map +1 -1
- package/web/.next/server/chunks/ssr/src_presentation_web_ed0934e5._.js.map +1 -1
- package/web/.next/server/pages/500.html +2 -2
- package/web/.next/server/server-reference-manifest.js +1 -1
- package/web/.next/server/server-reference-manifest.json +1 -1
- package/web/.next/standalone/src/presentation/web/.next/BUILD_ID +1 -1
- package/web/.next/standalone/src/presentation/web/.next/build-manifest.json +2 -2
- package/web/.next/standalone/src/presentation/web/.next/prerender-manifest.json +3 -3
- package/web/.next/standalone/src/presentation/web/.next/required-server-files.json +1 -1
- package/web/.next/standalone/src/presentation/web/.next/server/app/_global-error.html +2 -2
- package/web/.next/standalone/src/presentation/web/.next/server/app/_global-error.rsc +1 -1
- package/web/.next/standalone/src/presentation/web/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +1 -1
- package/web/.next/standalone/src/presentation/web/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
- package/web/.next/standalone/src/presentation/web/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
- package/web/.next/standalone/src/presentation/web/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
- package/web/.next/standalone/src/presentation/web/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
- package/web/.next/standalone/src/presentation/web/.next/server/app/api/ide/open/route.js +1 -2
- package/web/.next/standalone/src/presentation/web/.next/server/app/api/ide/open/route.js.nft.json +1 -1
- package/web/.next/standalone/src/presentation/web/.next/server/app/api/shell/open/route.js +1 -1
- package/web/.next/standalone/src/presentation/web/.next/server/app/api/shell/open/route.js.nft.json +1 -1
- package/web/.next/standalone/src/presentation/web/.next/server/chunks/[root-of-the-server]__04ae3a77._.js +3 -0
- package/web/.next/standalone/src/presentation/web/.next/server/chunks/[root-of-the-server]__f32c280c._.js +3 -0
- package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/[root-of-the-server]__f12b60be._.js +1 -1
- package/web/.next/standalone/src/presentation/web/.next/server/pages/500.html +2 -2
- package/web/.next/standalone/src/presentation/web/.next/server/server-reference-manifest.js +1 -1
- package/web/.next/standalone/src/presentation/web/.next/server/server-reference-manifest.json +1 -1
- package/web/.next/standalone/src/presentation/web/app/api/ide/open/route.ts +4 -2
- package/web/.next/standalone/src/presentation/web/server.js +1 -1
- package/web/.next/trace +1 -1
- package/web/.next/trace-build +1 -1
- package/dist/packages/core/src/infrastructure/services/ide-launchers/antigravity.launcher.d.ts +0 -10
- package/dist/packages/core/src/infrastructure/services/ide-launchers/antigravity.launcher.d.ts.map +0 -1
- package/dist/packages/core/src/infrastructure/services/ide-launchers/antigravity.launcher.js +0 -21
- package/dist/packages/core/src/infrastructure/services/ide-launchers/cursor.launcher.d.ts +0 -10
- package/dist/packages/core/src/infrastructure/services/ide-launchers/cursor.launcher.d.ts.map +0 -1
- package/dist/packages/core/src/infrastructure/services/ide-launchers/cursor.launcher.js +0 -21
- package/dist/packages/core/src/infrastructure/services/ide-launchers/ide-launcher.interface.d.ts +0 -31
- package/dist/packages/core/src/infrastructure/services/ide-launchers/ide-launcher.interface.d.ts.map +0 -1
- package/dist/packages/core/src/infrastructure/services/ide-launchers/ide-launcher.interface.js +0 -8
- package/dist/packages/core/src/infrastructure/services/ide-launchers/ide-launcher.registry.d.ts +0 -9
- package/dist/packages/core/src/infrastructure/services/ide-launchers/ide-launcher.registry.d.ts.map +0 -1
- package/dist/packages/core/src/infrastructure/services/ide-launchers/ide-launcher.registry.js +0 -24
- package/dist/packages/core/src/infrastructure/services/ide-launchers/launch-ide.d.ts +0 -30
- package/dist/packages/core/src/infrastructure/services/ide-launchers/launch-ide.d.ts.map +0 -1
- package/dist/packages/core/src/infrastructure/services/ide-launchers/launch-ide.js +0 -43
- package/dist/packages/core/src/infrastructure/services/ide-launchers/vscode.launcher.d.ts +0 -10
- package/dist/packages/core/src/infrastructure/services/ide-launchers/vscode.launcher.d.ts.map +0 -1
- package/dist/packages/core/src/infrastructure/services/ide-launchers/vscode.launcher.js +0 -21
- package/dist/packages/core/src/infrastructure/services/ide-launchers/windsurf.launcher.d.ts +0 -10
- package/dist/packages/core/src/infrastructure/services/ide-launchers/windsurf.launcher.d.ts.map +0 -1
- package/dist/packages/core/src/infrastructure/services/ide-launchers/windsurf.launcher.js +0 -21
- package/dist/packages/core/src/infrastructure/services/ide-launchers/zed.launcher.d.ts +0 -10
- package/dist/packages/core/src/infrastructure/services/ide-launchers/zed.launcher.d.ts.map +0 -1
- package/dist/packages/core/src/infrastructure/services/ide-launchers/zed.launcher.js +0 -21
- package/web/.next/server/chunks/403f9_next_dist_esm_build_templates_app-route_12059e3e.js +0 -3
- package/web/.next/server/chunks/403f9_next_dist_esm_build_templates_app-route_12059e3e.js.map +0 -1
- package/web/.next/server/chunks/[root-of-the-server]__0af905fe._.js +0 -3
- package/web/.next/server/chunks/[root-of-the-server]__0af905fe._.js.map +0 -1
- package/web/.next/server/chunks/[root-of-the-server]__72567d8d._.js +0 -3
- package/web/.next/server/chunks/[root-of-the-server]__72567d8d._.js.map +0 -1
- package/web/.next/standalone/src/presentation/web/.next/server/chunks/403f9_next_dist_esm_build_templates_app-route_12059e3e.js +0 -3
- package/web/.next/standalone/src/presentation/web/.next/server/chunks/[root-of-the-server]__0af905fe._.js +0 -3
- package/web/.next/standalone/src/presentation/web/.next/server/chunks/[root-of-the-server]__72567d8d._.js +0 -3
- /package/web/.next/static/{aMt5PeCCyLYG-zTyUFrpm → zoaB52IxAh-lSl8Qreb0t}/_buildManifest.js +0 -0
- /package/web/.next/static/{aMt5PeCCyLYG-zTyUFrpm → zoaB52IxAh-lSl8Qreb0t}/_clientMiddlewareManifest.json +0 -0
- /package/web/.next/static/{aMt5PeCCyLYG-zTyUFrpm → zoaB52IxAh-lSl8Qreb0t}/_ssgManifest.js +0 -0
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* JSON-Driven IDE Launcher Service
|
|
3
|
+
*
|
|
4
|
+
* Replaces the 5 hard-coded IDE launcher classes with a single service that
|
|
5
|
+
* derives editor commands from the JSON tool metadata files. Reads from the
|
|
6
|
+
* already-loaded TOOL_METADATA record, filters by category "ide" and presence
|
|
7
|
+
* of openDirectory, and performs {dir} placeholder substitution at launch time.
|
|
8
|
+
*/
|
|
9
|
+
import type { IIdeLauncherService, LaunchIdeResult } from '../../../application/ports/output/services/ide-launcher-service.interface.js';
|
|
10
|
+
/**
|
|
11
|
+
* Resolve a platform-specific value from a string or per-platform record.
|
|
12
|
+
* When the value is a plain string, returns it directly.
|
|
13
|
+
* When the value is a record, returns the entry for the current os.platform(),
|
|
14
|
+
* falling back to the first value if the current platform is not present.
|
|
15
|
+
*/
|
|
16
|
+
export declare function resolvePlatformValue(value: string | Record<string, string>): string;
|
|
17
|
+
export declare class JsonDrivenIdeLauncherService implements IIdeLauncherService {
|
|
18
|
+
private readonly editors;
|
|
19
|
+
constructor();
|
|
20
|
+
launch(editorId: string, directoryPath: string): Promise<LaunchIdeResult>;
|
|
21
|
+
checkAvailability(editorId: string): Promise<boolean>;
|
|
22
|
+
}
|
|
23
|
+
//# sourceMappingURL=json-driven-ide-launcher.service.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"json-driven-ide-launcher.service.d.ts","sourceRoot":"","sources":["../../../../../../../packages/core/src/infrastructure/services/ide-launchers/json-driven-ide-launcher.service.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAKH,OAAO,KAAK,EACV,mBAAmB,EACnB,eAAe,EAChB,MAAM,8EAA8E,CAAC;AActF;;;;;GAKG;AACH,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,MAAM,CAGnF;AAED,qBACa,4BAA6B,YAAW,mBAAmB;IACtE,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAwB;;IAgB1C,MAAM,CAAC,QAAQ,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,GAAG,OAAO,CAAC,eAAe,CAAC;IAoD/E,iBAAiB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;CAWtD"}
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* JSON-Driven IDE Launcher Service
|
|
3
|
+
*
|
|
4
|
+
* Replaces the 5 hard-coded IDE launcher classes with a single service that
|
|
5
|
+
* derives editor commands from the JSON tool metadata files. Reads from the
|
|
6
|
+
* already-loaded TOOL_METADATA record, filters by category "ide" and presence
|
|
7
|
+
* of openDirectory, and performs {dir} placeholder substitution at launch time.
|
|
8
|
+
*/
|
|
9
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
10
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
11
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
12
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
13
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
14
|
+
};
|
|
15
|
+
var __metadata = (this && this.__metadata) || function (k, v) {
|
|
16
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
17
|
+
};
|
|
18
|
+
import { injectable } from 'tsyringe';
|
|
19
|
+
import { spawn, execFile } from 'node:child_process';
|
|
20
|
+
import { platform } from 'node:os';
|
|
21
|
+
import { TOOL_METADATA } from '../tool-installer/tool-metadata.js';
|
|
22
|
+
/**
|
|
23
|
+
* Resolve a platform-specific value from a string or per-platform record.
|
|
24
|
+
* When the value is a plain string, returns it directly.
|
|
25
|
+
* When the value is a record, returns the entry for the current os.platform(),
|
|
26
|
+
* falling back to the first value if the current platform is not present.
|
|
27
|
+
*/
|
|
28
|
+
export function resolvePlatformValue(value) {
|
|
29
|
+
if (typeof value === 'string')
|
|
30
|
+
return value;
|
|
31
|
+
return value[platform()] ?? Object.values(value)[0];
|
|
32
|
+
}
|
|
33
|
+
let JsonDrivenIdeLauncherService = class JsonDrivenIdeLauncherService {
|
|
34
|
+
editors;
|
|
35
|
+
constructor() {
|
|
36
|
+
this.editors = new Map();
|
|
37
|
+
for (const [id, meta] of Object.entries(TOOL_METADATA)) {
|
|
38
|
+
if (meta.openDirectory != null) {
|
|
39
|
+
this.editors.set(id, {
|
|
40
|
+
name: meta.name,
|
|
41
|
+
binary: meta.binary,
|
|
42
|
+
openDirectory: meta.openDirectory,
|
|
43
|
+
spawnOptions: meta.spawnOptions,
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
async launch(editorId, directoryPath) {
|
|
49
|
+
const entry = this.editors.get(editorId);
|
|
50
|
+
if (!entry) {
|
|
51
|
+
const available = [...this.editors.keys()].join(', ');
|
|
52
|
+
return {
|
|
53
|
+
ok: false,
|
|
54
|
+
code: 'unknown_editor',
|
|
55
|
+
message: `No launcher found for editor: ${editorId}. Available: ${available}`,
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
const openCmd = resolvePlatformValue(entry.openDirectory);
|
|
59
|
+
if (!openCmd.includes('{dir}')) {
|
|
60
|
+
return {
|
|
61
|
+
ok: false,
|
|
62
|
+
code: 'launch_failed',
|
|
63
|
+
message: `openDirectory for "${editorId}" is missing {dir} placeholder: "${openCmd}"`,
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
const resolved = openCmd.replace('{dir}', directoryPath);
|
|
67
|
+
const useShell = entry.spawnOptions?.shell === true;
|
|
68
|
+
const opts = {
|
|
69
|
+
detached: entry.spawnOptions?.detached ?? !useShell,
|
|
70
|
+
stdio: (entry.spawnOptions?.stdio ?? 'ignore'),
|
|
71
|
+
shell: useShell,
|
|
72
|
+
};
|
|
73
|
+
try {
|
|
74
|
+
let child;
|
|
75
|
+
if (useShell) {
|
|
76
|
+
child = spawn(resolved, [], opts);
|
|
77
|
+
}
|
|
78
|
+
else {
|
|
79
|
+
const [command, ...args] = resolved.split(/\s+/);
|
|
80
|
+
child = spawn(command, args, opts);
|
|
81
|
+
}
|
|
82
|
+
if (opts.detached)
|
|
83
|
+
child.unref();
|
|
84
|
+
return {
|
|
85
|
+
ok: true,
|
|
86
|
+
editorName: entry.name,
|
|
87
|
+
worktreePath: directoryPath,
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
catch (error) {
|
|
91
|
+
return {
|
|
92
|
+
ok: false,
|
|
93
|
+
code: 'launch_failed',
|
|
94
|
+
message: error instanceof Error ? error.message : 'Failed to launch IDE',
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
checkAvailability(editorId) {
|
|
99
|
+
const entry = this.editors.get(editorId);
|
|
100
|
+
if (!entry)
|
|
101
|
+
return Promise.resolve(false);
|
|
102
|
+
const binary = resolvePlatformValue(entry.binary);
|
|
103
|
+
return new Promise((resolve) => {
|
|
104
|
+
execFile('which', [binary], (err) => {
|
|
105
|
+
resolve(!err);
|
|
106
|
+
});
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
};
|
|
110
|
+
JsonDrivenIdeLauncherService = __decorate([
|
|
111
|
+
injectable(),
|
|
112
|
+
__metadata("design:paramtypes", [])
|
|
113
|
+
], JsonDrivenIdeLauncherService);
|
|
114
|
+
export { JsonDrivenIdeLauncherService };
|
|
@@ -14,8 +14,8 @@ export interface ToolMetadata {
|
|
|
14
14
|
summary: string;
|
|
15
15
|
/** Detailed description */
|
|
16
16
|
description: string;
|
|
17
|
-
/** Tool
|
|
18
|
-
|
|
17
|
+
/** Tool tags for grouping in listings. A tool can belong to multiple categories. */
|
|
18
|
+
tags: ('ide' | 'cli-agent')[];
|
|
19
19
|
/** Binary name to check with 'which' command (string or per-platform map) */
|
|
20
20
|
binary: string | Record<string, string>;
|
|
21
21
|
/** Package manager or installation method */
|
|
@@ -30,8 +30,24 @@ export interface ToolMetadata {
|
|
|
30
30
|
verifyCommand: string;
|
|
31
31
|
/** Whether the tool supports automated installation (default: true) */
|
|
32
32
|
autoInstall?: boolean;
|
|
33
|
-
/** Command to open a directory in this tool
|
|
34
|
-
|
|
33
|
+
/** Command to open a directory in this tool.
|
|
34
|
+
* String format: "code {dir}" — single command for all platforms.
|
|
35
|
+
* Object format: { "linux": "antigravity {dir}", "darwin": "agy {dir}" } — per-platform commands. */
|
|
36
|
+
openDirectory?: string | Record<string, string>;
|
|
37
|
+
/** Override default spawn options for the launch process.
|
|
38
|
+
* Defaults: { detached: true, stdio: "ignore" } (GUI IDEs).
|
|
39
|
+
* CLI agents should use { shell: true, stdio: "inherit" } to run in the current terminal. */
|
|
40
|
+
spawnOptions?: {
|
|
41
|
+
shell?: boolean;
|
|
42
|
+
stdio?: 'ignore' | 'inherit' | 'pipe';
|
|
43
|
+
detached?: boolean;
|
|
44
|
+
};
|
|
35
45
|
}
|
|
36
46
|
export declare const TOOL_METADATA: Record<string, ToolMetadata>;
|
|
47
|
+
/**
|
|
48
|
+
* Returns entries from TOOL_METADATA that can open a directory as an IDE.
|
|
49
|
+
* A tool qualifies if it has an `openDirectory` field, regardless of category.
|
|
50
|
+
* Each entry is [toolId, metadata].
|
|
51
|
+
*/
|
|
52
|
+
export declare function getIdeEntries(): [string, ToolMetadata][];
|
|
37
53
|
//# sourceMappingURL=tool-metadata.d.ts.map
|
package/dist/packages/core/src/infrastructure/services/tool-installer/tool-metadata.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tool-metadata.d.ts","sourceRoot":"","sources":["../../../../../../../packages/core/src/infrastructure/services/tool-installer/tool-metadata.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAMH,MAAM,WAAW,YAAY;IAC3B,kCAAkC;IAClC,IAAI,EAAE,MAAM,CAAC;IAEb,6BAA6B;IAC7B,OAAO,EAAE,MAAM,CAAC;IAEhB,2BAA2B;IAC3B,WAAW,EAAE,MAAM,CAAC;IAEpB,
|
|
1
|
+
{"version":3,"file":"tool-metadata.d.ts","sourceRoot":"","sources":["../../../../../../../packages/core/src/infrastructure/services/tool-installer/tool-metadata.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAMH,MAAM,WAAW,YAAY;IAC3B,kCAAkC;IAClC,IAAI,EAAE,MAAM,CAAC;IAEb,6BAA6B;IAC7B,OAAO,EAAE,MAAM,CAAC;IAEhB,2BAA2B;IAC3B,WAAW,EAAE,MAAM,CAAC;IAEpB,oFAAoF;IACpF,IAAI,EAAE,CAAC,KAAK,GAAG,WAAW,CAAC,EAAE,CAAC;IAE9B,6EAA6E;IAC7E,MAAM,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAExC,6CAA6C;IAC7C,cAAc,EAAE,MAAM,CAAC;IAEvB,wFAAwF;IACxF,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAEjC,2CAA2C;IAC3C,OAAO,EAAE,MAAM,CAAC;IAEhB,iCAAiC;IACjC,gBAAgB,EAAE,MAAM,CAAC;IAEzB,8DAA8D;IAC9D,aAAa,EAAE,MAAM,CAAC;IAEtB,uEAAuE;IACvE,WAAW,CAAC,EAAE,OAAO,CAAC;IAEtB;;yGAEqG;IACrG,aAAa,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAEhD;;iGAE6F;IAC7F,YAAY,CAAC,EAAE;QACb,KAAK,CAAC,EAAE,OAAO,CAAC;QAChB,KAAK,CAAC,EAAE,QAAQ,GAAG,SAAS,GAAG,MAAM,CAAC;QACtC,QAAQ,CAAC,EAAE,OAAO,CAAC;KACpB,CAAC;CACH;AA8CD,eAAO,MAAM,aAAa,EAAE,MAAM,CAAC,MAAM,EAAE,YAAY,CAAsB,CAAC;AAE9E;;;;GAIG;AACH,wBAAgB,aAAa,IAAI,CAAC,MAAM,EAAE,YAAY,CAAC,EAAE,CAExD"}
|
|
@@ -14,7 +14,7 @@ const REQUIRED_FIELDS = [
|
|
|
14
14
|
'name',
|
|
15
15
|
'summary',
|
|
16
16
|
'description',
|
|
17
|
-
'
|
|
17
|
+
'tags',
|
|
18
18
|
'binary',
|
|
19
19
|
'packageManager',
|
|
20
20
|
'commands',
|
|
@@ -50,3 +50,11 @@ function loadToolMetadata() {
|
|
|
50
50
|
return metadata;
|
|
51
51
|
}
|
|
52
52
|
export const TOOL_METADATA = loadToolMetadata();
|
|
53
|
+
/**
|
|
54
|
+
* Returns entries from TOOL_METADATA that can open a directory as an IDE.
|
|
55
|
+
* A tool qualifies if it has an `openDirectory` field, regardless of category.
|
|
56
|
+
* Each entry is [toolId, metadata].
|
|
57
|
+
*/
|
|
58
|
+
export function getIdeEntries() {
|
|
59
|
+
return Object.entries(TOOL_METADATA).filter(([, meta]) => meta.openDirectory != null);
|
|
60
|
+
}
|
package/dist/packages/core/src/infrastructure/services/tool-installer/tools/antigravity.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"name": "Google Antigravity",
|
|
3
3
|
"summary": "AI-powered agentic development platform",
|
|
4
4
|
"description": "Google Antigravity is an AI-powered platform that enables agentic development workflows, helping developers build intelligent applications with autonomous agents.",
|
|
5
|
-
"
|
|
5
|
+
"tags": ["ide"],
|
|
6
6
|
"binary": {
|
|
7
7
|
"linux": "antigravity",
|
|
8
8
|
"darwin": "agy"
|
|
@@ -16,5 +16,8 @@
|
|
|
16
16
|
"documentationUrl": "https://codelabs.developers.google.com/getting-started-google-antigravity",
|
|
17
17
|
"verifyCommand": "agy --version",
|
|
18
18
|
"autoInstall": false,
|
|
19
|
-
"openDirectory":
|
|
19
|
+
"openDirectory": {
|
|
20
|
+
"linux": "antigravity {dir}",
|
|
21
|
+
"darwin": "agy {dir}"
|
|
22
|
+
}
|
|
20
23
|
}
|
package/dist/packages/core/src/infrastructure/services/tool-installer/tools/claude-code.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"name": "Claude Code",
|
|
3
3
|
"summary": "AI-powered code assistant from Anthropic",
|
|
4
4
|
"description": "Claude Code is an AI-powered code assistant from Anthropic that helps you write, understand, and debug code with advanced AI capabilities.",
|
|
5
|
-
"
|
|
5
|
+
"tags": ["ide", "cli-agent"],
|
|
6
6
|
"binary": "claude",
|
|
7
7
|
"packageManager": "curl",
|
|
8
8
|
"commands": {
|
|
@@ -12,5 +12,11 @@
|
|
|
12
12
|
"timeout": 300000,
|
|
13
13
|
"documentationUrl": "https://code.claude.com/docs/en/overview",
|
|
14
14
|
"verifyCommand": "claude --version",
|
|
15
|
-
"autoInstall": true
|
|
15
|
+
"autoInstall": true,
|
|
16
|
+
"openDirectory": "cd {dir} && exec claude",
|
|
17
|
+
"spawnOptions": {
|
|
18
|
+
"shell": true,
|
|
19
|
+
"stdio": "inherit",
|
|
20
|
+
"detached": false
|
|
21
|
+
}
|
|
16
22
|
}
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"name": "Cursor CLI",
|
|
3
3
|
"summary": "AI-powered terminal coding agent",
|
|
4
4
|
"description": "Cursor CLI is a terminal-based AI coding agent that brings conversational AI assistance directly to your command line for any IDE or terminal.",
|
|
5
|
-
"
|
|
5
|
+
"tags": ["ide", "cli-agent"],
|
|
6
6
|
"binary": "cursor-agent",
|
|
7
7
|
"packageManager": "curl",
|
|
8
8
|
"commands": {
|
|
@@ -12,5 +12,11 @@
|
|
|
12
12
|
"timeout": 300000,
|
|
13
13
|
"documentationUrl": "https://www.codecademy.com/article/getting-started-with-cursor-cli",
|
|
14
14
|
"verifyCommand": "cursor-agent --version",
|
|
15
|
-
"autoInstall": true
|
|
15
|
+
"autoInstall": true,
|
|
16
|
+
"openDirectory": "cd {dir} && exec cursor-agent",
|
|
17
|
+
"spawnOptions": {
|
|
18
|
+
"shell": true,
|
|
19
|
+
"stdio": "inherit",
|
|
20
|
+
"detached": false
|
|
21
|
+
}
|
|
16
22
|
}
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"name": "Cursor",
|
|
3
3
|
"summary": "AI-powered code editor for efficient development",
|
|
4
4
|
"description": "Cursor is an AI-powered code editor built on VS Code, designed to streamline development workflows with advanced AI-assisted coding capabilities.",
|
|
5
|
-
"
|
|
5
|
+
"tags": ["ide"],
|
|
6
6
|
"binary": "cursor",
|
|
7
7
|
"packageManager": "manual",
|
|
8
8
|
"commands": {
|
|
@@ -13,5 +13,5 @@
|
|
|
13
13
|
"documentationUrl": "https://cursor.com/download",
|
|
14
14
|
"verifyCommand": "cursor --version",
|
|
15
15
|
"autoInstall": false,
|
|
16
|
-
"openDirectory": "cursor
|
|
16
|
+
"openDirectory": "cursor {dir}"
|
|
17
17
|
}
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"name": "Visual Studio Code",
|
|
3
3
|
"summary": "Lightweight but powerful source code editor",
|
|
4
4
|
"description": "Microsoft Visual Studio Code is a free, open-source code editor with built-in support for debugging, version control, and extensions for enhanced development workflows.",
|
|
5
|
-
"
|
|
5
|
+
"tags": ["ide"],
|
|
6
6
|
"binary": "code",
|
|
7
7
|
"packageManager": "apt",
|
|
8
8
|
"commands": {
|
|
@@ -13,5 +13,5 @@
|
|
|
13
13
|
"documentationUrl": "https://code.visualstudio.com/docs/setup/linux",
|
|
14
14
|
"verifyCommand": "code --version --no-sandbox --user-data-dir=/tmp/vscode-test",
|
|
15
15
|
"autoInstall": true,
|
|
16
|
-
"openDirectory": "code
|
|
16
|
+
"openDirectory": "code {dir}"
|
|
17
17
|
}
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"name": "Windsurf",
|
|
3
3
|
"summary": "AI-powered code editor by Codeium",
|
|
4
4
|
"description": "Windsurf is an AI-powered code editor by Codeium that provides intelligent code assistance and automation features for modern development.",
|
|
5
|
-
"
|
|
5
|
+
"tags": ["ide"],
|
|
6
6
|
"binary": "windsurf",
|
|
7
7
|
"packageManager": "apt",
|
|
8
8
|
"commands": {
|
|
@@ -13,5 +13,5 @@
|
|
|
13
13
|
"documentationUrl": "https://docs.windsurf.com/windsurf/getting-started",
|
|
14
14
|
"verifyCommand": "windsurf --version --no-sandbox --user-data-dir=/tmp/windsurf-test",
|
|
15
15
|
"autoInstall": true,
|
|
16
|
-
"openDirectory": "windsurf
|
|
16
|
+
"openDirectory": "windsurf {dir}"
|
|
17
17
|
}
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"name": "Zed",
|
|
3
3
|
"summary": "High-performance code editor written in Rust",
|
|
4
4
|
"description": "Zed is a high-performance code editor written in Rust, designed for speed and collaboration with modern developer workflows.",
|
|
5
|
-
"
|
|
5
|
+
"tags": ["ide"],
|
|
6
6
|
"binary": "zed",
|
|
7
7
|
"packageManager": "curl",
|
|
8
8
|
"commands": {
|
|
@@ -13,5 +13,5 @@
|
|
|
13
13
|
"documentationUrl": "https://zed.dev/docs/installation",
|
|
14
14
|
"verifyCommand": "zed --version",
|
|
15
15
|
"autoInstall": true,
|
|
16
|
-
"openDirectory": "zed
|
|
16
|
+
"openDirectory": "zed {dir}"
|
|
17
17
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"show.command.d.ts","sourceRoot":"","sources":["../../../../../../src/presentation/cli/commands/feat/show.command.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"show.command.d.ts","sourceRoot":"","sources":["../../../../../../src/presentation/cli/commands/feat/show.command.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAmFpC,wBAAgB,iBAAiB,IAAI,OAAO,CAiO3C"}
|
|
@@ -61,6 +61,17 @@ function formatLifecycle(lifecycle) {
|
|
|
61
61
|
return colors.warning(lifecycle);
|
|
62
62
|
return colors.info(lifecycle);
|
|
63
63
|
}
|
|
64
|
+
function formatDuration(ms) {
|
|
65
|
+
const secs = ms / 1000;
|
|
66
|
+
const totalSecs = Math.round(secs);
|
|
67
|
+
const mins = Math.floor(totalSecs / 60);
|
|
68
|
+
const remSecs = totalSecs % 60;
|
|
69
|
+
const secsStr = secs.toFixed(1);
|
|
70
|
+
if (mins > 0) {
|
|
71
|
+
return `${secsStr}s (${mins}m ${remSecs}s)`;
|
|
72
|
+
}
|
|
73
|
+
return `${secsStr}s`;
|
|
74
|
+
}
|
|
64
75
|
function isProcessAlive(pid) {
|
|
65
76
|
try {
|
|
66
77
|
process.kill(pid, 0);
|
|
@@ -109,7 +120,8 @@ export function createShowCommand() {
|
|
|
109
120
|
const isWaiting = run?.status === 'waiting_approval';
|
|
110
121
|
const maxDurationMs = Math.max(...timings.map((t) => (t.durationMs != null ? Number(t.durationMs) : 0)));
|
|
111
122
|
const MAX_BAR = 20;
|
|
112
|
-
const lines =
|
|
123
|
+
const lines = [];
|
|
124
|
+
for (const [idx, t] of timings.entries()) {
|
|
113
125
|
const isLast = idx === timings.length - 1;
|
|
114
126
|
const isSubPhase = t.phase.includes(':');
|
|
115
127
|
const label = isSubPhase
|
|
@@ -121,21 +133,43 @@ export function createShowCommand() {
|
|
|
121
133
|
const secs = (ms / 1000).toFixed(1);
|
|
122
134
|
const barLen = maxDurationMs > 0 ? Math.max(1, Math.round((ms / maxDurationMs) * MAX_BAR)) : 1;
|
|
123
135
|
const bar = `${colors.success('\u2588'.repeat(barLen))}${colors.muted('\u2591'.repeat(MAX_BAR - barLen))}`;
|
|
124
|
-
|
|
136
|
+
lines.push(`${label} ${bar} ${secs}s`);
|
|
125
137
|
}
|
|
126
138
|
// Waiting for approval - only the LAST timing
|
|
127
|
-
if (isLast && isWaiting) {
|
|
128
|
-
|
|
139
|
+
else if (isLast && isWaiting) {
|
|
140
|
+
lines.push(`${label} ${colors.warning('awaiting review')}`);
|
|
129
141
|
}
|
|
130
142
|
// Running phase - blue bar with elapsed time
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
143
|
+
else {
|
|
144
|
+
const elapsedMs = Math.max(0, Date.now() - new Date(t.startedAt).getTime());
|
|
145
|
+
const secs = (elapsedMs / 1000).toFixed(1);
|
|
146
|
+
const barLen = maxDurationMs > 0
|
|
147
|
+
? Math.min(MAX_BAR, Math.max(1, Math.round((elapsedMs / maxDurationMs) * MAX_BAR)))
|
|
148
|
+
: 1;
|
|
149
|
+
const bar = `${colors.info('\u2588'.repeat(barLen))}${colors.muted('\u2591'.repeat(MAX_BAR - barLen))}`;
|
|
150
|
+
lines.push(`${label} ${bar} ${secs}s (running)`);
|
|
151
|
+
}
|
|
152
|
+
// Show approval wait time under gated phases
|
|
153
|
+
if (t.approvalWaitMs != null && Number(t.approvalWaitMs) > 0) {
|
|
154
|
+
const waitMs = Number(t.approvalWaitMs);
|
|
155
|
+
const waitSecs = (waitMs / 1000).toFixed(1);
|
|
156
|
+
const waitLabel = ' \u21b3 approval'.padEnd(16);
|
|
157
|
+
const waitBarLen = maxDurationMs > 0 ? Math.max(1, Math.round((waitMs / maxDurationMs) * MAX_BAR)) : 1;
|
|
158
|
+
const waitBar = `${colors.warning('\u2588'.repeat(waitBarLen))}${colors.muted('\u2591'.repeat(MAX_BAR - waitBarLen))}`;
|
|
159
|
+
lines.push(`${waitLabel} ${waitBar} ${waitSecs}s`);
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
// Summary totals
|
|
163
|
+
const totalExecMs = timings.reduce((sum, t) => sum + (t.durationMs != null ? Number(t.durationMs) : 0), 0);
|
|
164
|
+
const totalWaitMs = timings.reduce((sum, t) => sum + (t.approvalWaitMs != null ? Number(t.approvalWaitMs) : 0), 0);
|
|
165
|
+
if (totalExecMs > 0) {
|
|
166
|
+
lines.push('');
|
|
167
|
+
lines.push(`${'Total execution'.padEnd(16)} ${formatDuration(totalExecMs)}`);
|
|
168
|
+
if (totalWaitMs > 0) {
|
|
169
|
+
lines.push(`${'Total wait'.padEnd(16)} ${formatDuration(totalWaitMs)}`);
|
|
170
|
+
lines.push(`${'Total wall-clock'.padEnd(16)} ${formatDuration(totalExecMs + totalWaitMs)}`);
|
|
171
|
+
}
|
|
172
|
+
}
|
|
139
173
|
textBlocks.push({ title: 'Phase Timing', content: lines.join('\n') });
|
|
140
174
|
}
|
|
141
175
|
if (run?.status === 'waiting_approval') {
|
|
@@ -2,8 +2,10 @@
|
|
|
2
2
|
* IDE Open Command
|
|
3
3
|
*
|
|
4
4
|
* Opens a feature worktree in the configured IDE.
|
|
5
|
+
* IDE flags (e.g. --vscode, --cursor) are derived dynamically from
|
|
6
|
+
* the JSON tool metadata files in packages/core.
|
|
5
7
|
*
|
|
6
|
-
* Usage: shep ide <feat-id> [
|
|
8
|
+
* Usage: shep ide <feat-id> [--<ide-name>]
|
|
7
9
|
*/
|
|
8
10
|
import { Command } from 'commander';
|
|
9
11
|
export declare function createIdeOpenCommand(): Command;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ide-open.command.d.ts","sourceRoot":"","sources":["../../../../../src/presentation/cli/commands/ide-open.command.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"ide-open.command.d.ts","sourceRoot":"","sources":["../../../../../src/presentation/cli/commands/ide-open.command.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAwBpC,wBAAgB,oBAAoB,IAAI,OAAO,CAwC9C"}
|
|
@@ -2,51 +2,49 @@
|
|
|
2
2
|
* IDE Open Command
|
|
3
3
|
*
|
|
4
4
|
* Opens a feature worktree in the configured IDE.
|
|
5
|
+
* IDE flags (e.g. --vscode, --cursor) are derived dynamically from
|
|
6
|
+
* the JSON tool metadata files in packages/core.
|
|
5
7
|
*
|
|
6
|
-
* Usage: shep ide <feat-id> [
|
|
8
|
+
* Usage: shep ide <feat-id> [--<ide-name>]
|
|
7
9
|
*/
|
|
8
10
|
import { Command } from 'commander';
|
|
9
|
-
import { EditorType } from '../../../../packages/core/src/domain/generated/output.js';
|
|
10
11
|
import { container } from '../../../../packages/core/src/infrastructure/di/container.js';
|
|
11
12
|
import { ShowFeatureUseCase } from '../../../../packages/core/src/application/use-cases/features/show-feature.use-case.js';
|
|
13
|
+
import { LaunchIdeUseCase } from '../../../../packages/core/src/application/use-cases/ide/launch-ide.use-case.js';
|
|
12
14
|
import { getSettings } from '../../../../packages/core/src/infrastructure/services/settings.service.js';
|
|
13
|
-
import {
|
|
15
|
+
import { getIdeEntries } from '../../../../packages/core/src/infrastructure/services/tool-installer/tool-metadata.js';
|
|
14
16
|
import { messages } from '../ui/index.js';
|
|
15
|
-
/**
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
windsurf: EditorType.Windsurf,
|
|
20
|
-
zed: EditorType.Zed,
|
|
21
|
-
antigravity: EditorType.Antigravity,
|
|
22
|
-
};
|
|
17
|
+
/** Commander converts --kebab-case flags to camelCase option keys. */
|
|
18
|
+
function toCamelCase(s) {
|
|
19
|
+
return s.replace(/-([a-z])/g, (_, c) => c.toUpperCase());
|
|
20
|
+
}
|
|
23
21
|
/**
|
|
24
22
|
* Determine which editor to use based on CLI flags and settings.
|
|
25
23
|
* Flag takes precedence over settings.
|
|
26
24
|
*/
|
|
27
|
-
function resolveEditorId(options) {
|
|
28
|
-
for (const
|
|
29
|
-
if (options[
|
|
30
|
-
return
|
|
31
|
-
}
|
|
25
|
+
function resolveEditorId(options, ideIds) {
|
|
26
|
+
for (const id of ideIds) {
|
|
27
|
+
if (options[toCamelCase(id)])
|
|
28
|
+
return id;
|
|
32
29
|
}
|
|
33
30
|
return getSettings().environment.defaultEditor;
|
|
34
31
|
}
|
|
35
32
|
export function createIdeOpenCommand() {
|
|
36
|
-
|
|
33
|
+
const cmd = new Command('ide')
|
|
37
34
|
.description('Open a feature worktree in your IDE')
|
|
38
|
-
.argument('<feat-id>', 'Feature ID or prefix')
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
.option(
|
|
43
|
-
|
|
44
|
-
|
|
35
|
+
.argument('<feat-id>', 'Feature ID or prefix');
|
|
36
|
+
const ideEntries = getIdeEntries();
|
|
37
|
+
const ideIds = ideEntries.map(([id]) => id);
|
|
38
|
+
for (const [id, meta] of ideEntries) {
|
|
39
|
+
cmd.option(`--${id}`, `Open in ${meta.name}`);
|
|
40
|
+
}
|
|
41
|
+
cmd.action(async (featId, options) => {
|
|
45
42
|
try {
|
|
46
|
-
const editorId = resolveEditorId(options);
|
|
47
|
-
const
|
|
48
|
-
const feature = await
|
|
49
|
-
const
|
|
43
|
+
const editorId = resolveEditorId(options, ideIds);
|
|
44
|
+
const showFeature = container.resolve(ShowFeatureUseCase);
|
|
45
|
+
const feature = await showFeature.execute(featId);
|
|
46
|
+
const launchIde = container.resolve(LaunchIdeUseCase);
|
|
47
|
+
const result = await launchIde.execute({
|
|
50
48
|
editorId,
|
|
51
49
|
repositoryPath: feature.repositoryPath,
|
|
52
50
|
branch: feature.branch,
|
|
@@ -64,4 +62,5 @@ export function createIdeOpenCommand() {
|
|
|
64
62
|
process.exitCode = 1;
|
|
65
63
|
}
|
|
66
64
|
});
|
|
65
|
+
return cmd;
|
|
67
66
|
}
|
|
@@ -17,8 +17,8 @@ import { TOOL_METADATA } from '../../../../packages/core/src/infrastructure/serv
|
|
|
17
17
|
import { messages, fmt, colors } from '../ui/index.js';
|
|
18
18
|
function printToolsList() {
|
|
19
19
|
const tools = Object.entries(TOOL_METADATA);
|
|
20
|
-
const ides = tools.filter(([, meta]) => meta.
|
|
21
|
-
const cliAgents = tools.filter(([, meta]) => meta.
|
|
20
|
+
const ides = tools.filter(([, meta]) => meta.tags.includes('ide'));
|
|
21
|
+
const cliAgents = tools.filter(([, meta]) => meta.tags.includes('cli-agent'));
|
|
22
22
|
console.log(fmt.heading('IDEs:'));
|
|
23
23
|
for (const [key, meta] of ides) {
|
|
24
24
|
console.log(` ${colors.accent(key.padEnd(16))}${meta.name} - ${colors.muted(meta.summary)}`);
|
|
@@ -101,7 +101,7 @@ function printInstallInstructions(metadata) {
|
|
|
101
101
|
console.log(`${fmt.label('Name:')} ${metadata.name}`);
|
|
102
102
|
console.log(`${fmt.label('Summary:')} ${metadata.summary}`);
|
|
103
103
|
console.log(`${fmt.label('Description:')} ${metadata.description}`);
|
|
104
|
-
console.log(`${fmt.label('
|
|
104
|
+
console.log(`${fmt.label('Tags:')} ${metadata.tags.join(', ')}`);
|
|
105
105
|
console.log();
|
|
106
106
|
const binaryDisplay = typeof metadata.binary === 'string'
|
|
107
107
|
? metadata.binary
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ide.command.d.ts","sourceRoot":"","sources":["../../../../../../src/presentation/cli/commands/settings/ide.command.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"ide.command.d.ts","sourceRoot":"","sources":["../../../../../../src/presentation/cli/commands/settings/ide.command.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAkBpC;;GAEG;AACH,wBAAgB,gBAAgB,IAAI,OAAO,CA+D1C"}
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
* IDE Configuration Command
|
|
3
3
|
*
|
|
4
4
|
* Configures the preferred IDE/editor used by Shep.
|
|
5
|
+
* Valid editors are derived dynamically from JSON tool metadata.
|
|
5
6
|
*
|
|
6
7
|
* Usage:
|
|
7
8
|
* shep settings ide # Interactive selection
|
|
@@ -9,22 +10,21 @@
|
|
|
9
10
|
*/
|
|
10
11
|
import { Command } from 'commander';
|
|
11
12
|
import { select } from '@inquirer/prompts';
|
|
12
|
-
import { EditorType } from '../../../../../packages/core/src/domain/generated/output.js';
|
|
13
13
|
import { container } from '../../../../../packages/core/src/infrastructure/di/container.js';
|
|
14
14
|
import { UpdateSettingsUseCase } from '../../../../../packages/core/src/application/use-cases/settings/update-settings.use-case.js';
|
|
15
15
|
import { createIdeSelectConfig } from '../../../tui/prompts/ide-select.prompt.js';
|
|
16
16
|
import { getSettings, resetSettings, initializeSettings, } from '../../../../../packages/core/src/infrastructure/services/settings.service.js';
|
|
17
|
-
import {
|
|
17
|
+
import { getIdeEntries } from '../../../../../packages/core/src/infrastructure/services/tool-installer/tool-metadata.js';
|
|
18
18
|
import { messages } from '../../ui/index.js';
|
|
19
|
-
/** Valid
|
|
20
|
-
const VALID_EDITORS = new Set(
|
|
19
|
+
/** Valid IDE tool IDs derived from JSON metadata. */
|
|
20
|
+
const VALID_EDITORS = new Set(getIdeEntries().map(([id]) => id));
|
|
21
21
|
/**
|
|
22
22
|
* Create the IDE configuration command.
|
|
23
23
|
*/
|
|
24
24
|
export function createIdeCommand() {
|
|
25
25
|
return new Command('ide')
|
|
26
26
|
.description('Configure preferred IDE/editor')
|
|
27
|
-
.option('--editor <name>',
|
|
27
|
+
.option('--editor <name>', `IDE/editor name (${[...VALID_EDITORS].join(', ')})`)
|
|
28
28
|
.addHelpText('after', `
|
|
29
29
|
Examples:
|
|
30
30
|
$ shep settings ide Interactive selection
|
|
@@ -44,14 +44,11 @@ Examples:
|
|
|
44
44
|
else {
|
|
45
45
|
editorValue = await select(createIdeSelectConfig());
|
|
46
46
|
}
|
|
47
|
-
// PATH check via launcher
|
|
48
|
-
const
|
|
49
|
-
const
|
|
50
|
-
if (
|
|
51
|
-
|
|
52
|
-
if (!available) {
|
|
53
|
-
messages.warning(`'${launcher.binary}' not found in PATH. The editor will still be saved.`);
|
|
54
|
-
}
|
|
47
|
+
// PATH check via IDE launcher service (non-blocking warning)
|
|
48
|
+
const ideLauncher = container.resolve('IIdeLauncherService');
|
|
49
|
+
const available = await ideLauncher.checkAvailability(editorValue);
|
|
50
|
+
if (!available) {
|
|
51
|
+
messages.warning(`Editor '${editorValue}' not found in PATH. The editor will still be saved.`);
|
|
55
52
|
}
|
|
56
53
|
// Persist settings
|
|
57
54
|
const settings = getSettings();
|