@shepai/cli 1.69.0 → 1.70.1
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/use-cases/tools/list-tools.use-case.d.ts +1 -1
- package/dist/packages/core/src/application/use-cases/tools/list-tools.use-case.d.ts.map +1 -1
- package/dist/packages/core/src/infrastructure/services/deployment/deployment-logger.d.ts +7 -0
- package/dist/packages/core/src/infrastructure/services/deployment/deployment-logger.d.ts.map +1 -0
- package/dist/packages/core/src/infrastructure/services/deployment/deployment-logger.js +17 -0
- package/dist/packages/core/src/infrastructure/services/deployment/deployment.service.d.ts.map +1 -1
- package/dist/packages/core/src/infrastructure/services/deployment/deployment.service.js +60 -7
- package/dist/packages/core/src/infrastructure/services/deployment/detect-dev-script.d.ts.map +1 -1
- package/dist/packages/core/src/infrastructure/services/deployment/detect-dev-script.js +13 -6
- package/dist/packages/core/src/infrastructure/services/tool-installer/tool-installer.service.d.ts +2 -1
- package/dist/packages/core/src/infrastructure/services/tool-installer/tool-installer.service.d.ts.map +1 -1
- package/dist/packages/core/src/infrastructure/services/tool-installer/tool-installer.service.js +17 -2
- package/dist/packages/core/src/infrastructure/services/tool-installer/tool-metadata.d.ts +1 -1
- 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/tools/CLAUDE.md +45 -18
- package/dist/packages/core/src/infrastructure/services/tool-installer/tools/alacritty.json +18 -0
- package/dist/packages/core/src/infrastructure/services/tool-installer/tools/iterm2.json +17 -0
- package/dist/packages/core/src/infrastructure/services/tool-installer/tools/kitty.json +18 -0
- package/dist/packages/core/src/infrastructure/services/tool-installer/tools/tmux.json +27 -0
- package/dist/packages/core/src/infrastructure/services/tool-installer/tools/warp.json +17 -0
- package/dist/src/presentation/web/app/actions/deploy-feature.d.ts.map +1 -1
- package/dist/src/presentation/web/app/actions/deploy-feature.js +11 -0
- package/dist/src/presentation/web/app/actions/deploy-repository.d.ts.map +1 -1
- package/dist/src/presentation/web/app/actions/deploy-repository.js +8 -0
- package/dist/src/presentation/web/components/features/tools/tool-card.d.ts.map +1 -1
- package/dist/src/presentation/web/components/features/tools/tool-card.js +1 -0
- package/dist/src/presentation/web/components/features/tools/tools-page-client.d.ts.map +1 -1
- package/dist/src/presentation/web/components/features/tools/tools-page-client.js +2 -1
- package/dist/src/presentation/web/hooks/use-deploy-action.d.ts.map +1 -1
- package/dist/src/presentation/web/hooks/use-deploy-action.js +36 -5
- 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/_not-found/page/server-reference-manifest.json +1 -1
- package/web/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/page/server-reference-manifest.json +18 -18
- package/web/.next/server/app/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/skills/page/server-reference-manifest.json +5 -5
- package/web/.next/server/app/skills/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/tools/page/server-reference-manifest.json +1 -1
- package/web/.next/server/app/tools/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/version/page/server-reference-manifest.json +1 -1
- package/web/.next/server/app/version/page_client-reference-manifest.js +1 -1
- package/web/.next/server/chunks/[root-of-the-server]__09413611._.js.map +1 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__08ba9bd3._.js +1 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__08ba9bd3._.js.map +1 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__249c74f6._.js +1 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__551fb7e1._.js +1 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__551fb7e1._.js.map +1 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__6b17a22d._.js +1 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__6b17a22d._.js.map +1 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__804c006d._.js +1 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__804c006d._.js.map +1 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__9add7c3a._.js +2 -2
- package/web/.next/server/chunks/ssr/[root-of-the-server]__9add7c3a._.js.map +1 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__e41b5eec._.js +2 -2
- package/web/.next/server/chunks/ssr/[root-of-the-server]__e41b5eec._.js.map +1 -1
- package/web/.next/server/chunks/ssr/_49bf495c._.js +1 -1
- package/web/.next/server/chunks/ssr/_49bf495c._.js.map +1 -1
- package/web/.next/server/chunks/ssr/_68b5e0de._.js +1 -1
- package/web/.next/server/chunks/ssr/_68b5e0de._.js.map +1 -1
- package/web/.next/server/chunks/ssr/_690ea95f._.js +1 -1
- package/web/.next/server/chunks/ssr/_690ea95f._.js.map +1 -1
- package/web/.next/server/chunks/ssr/_725584e5._.js +1 -1
- package/web/.next/server/chunks/ssr/_725584e5._.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 +19 -19
- 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/_not-found/page/server-reference-manifest.json +1 -1
- package/web/.next/standalone/src/presentation/web/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
- package/web/.next/standalone/src/presentation/web/.next/server/app/page/server-reference-manifest.json +18 -18
- package/web/.next/standalone/src/presentation/web/.next/server/app/page_client-reference-manifest.js +1 -1
- package/web/.next/standalone/src/presentation/web/.next/server/app/skills/page/server-reference-manifest.json +5 -5
- package/web/.next/standalone/src/presentation/web/.next/server/app/skills/page_client-reference-manifest.js +1 -1
- package/web/.next/standalone/src/presentation/web/.next/server/app/tools/page/server-reference-manifest.json +1 -1
- package/web/.next/standalone/src/presentation/web/.next/server/app/tools/page_client-reference-manifest.js +1 -1
- package/web/.next/standalone/src/presentation/web/.next/server/app/version/page/server-reference-manifest.json +1 -1
- package/web/.next/standalone/src/presentation/web/.next/server/app/version/page_client-reference-manifest.js +1 -1
- package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/[root-of-the-server]__08ba9bd3._.js +1 -1
- package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/[root-of-the-server]__249c74f6._.js +1 -1
- package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/[root-of-the-server]__551fb7e1._.js +1 -1
- package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/[root-of-the-server]__6b17a22d._.js +1 -1
- package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/[root-of-the-server]__804c006d._.js +1 -1
- package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/[root-of-the-server]__9add7c3a._.js +2 -2
- package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/[root-of-the-server]__e41b5eec._.js +2 -2
- package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/_49bf495c._.js +1 -1
- package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/_68b5e0de._.js +1 -1
- package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/_690ea95f._.js +1 -1
- package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/_725584e5._.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 +19 -19
- package/web/.next/standalone/src/presentation/web/app/actions/deploy-feature.ts +16 -0
- package/web/.next/standalone/src/presentation/web/app/actions/deploy-repository.ts +10 -0
- package/web/.next/standalone/src/presentation/web/components/features/tools/tool-card.tsx +1 -0
- package/web/.next/standalone/src/presentation/web/components/features/tools/tools-page-client.tsx +5 -1
- package/web/.next/standalone/src/presentation/web/hooks/use-deploy-action.ts +45 -5
- package/web/.next/standalone/src/presentation/web/server.js +1 -1
- package/web/.next/static/chunks/16e380b8dd9d11bc.js +1 -0
- package/web/.next/static/chunks/{5bc5d426870feb7e.js → 1ed0df845a1625f6.js} +1 -1
- package/web/.next/static/chunks/{2da52289a4a8f9e2.js → 24e1d97cab8bad6d.js} +1 -1
- package/web/.next/static/chunks/{491ae2bbae40857c.js → 505c6a9e4c5d0808.js} +1 -1
- package/web/.next/static/chunks/{5ef9d8b7401f2f1f.js → 9db5c06001f3e664.js} +2 -2
- package/web/.next/trace +1 -1
- package/web/.next/trace-build +1 -1
- package/web/.next/static/chunks/faf8ad4c823884d7.js +0 -1
- /package/web/.next/static/{7ktIn83yR3rYLLF00uLSx → 8xZoRkWykApYNlvamCGUe}/_buildManifest.js +0 -0
- /package/web/.next/static/{7ktIn83yR3rYLLF00uLSx → 8xZoRkWykApYNlvamCGUe}/_clientMiddlewareManifest.json +0 -0
- /package/web/.next/static/{7ktIn83yR3rYLLF00uLSx → 8xZoRkWykApYNlvamCGUe}/_ssgManifest.js +0 -0
|
@@ -13,7 +13,7 @@ export interface ToolItem {
|
|
|
13
13
|
name: string;
|
|
14
14
|
summary: string;
|
|
15
15
|
description: string;
|
|
16
|
-
tags: ('ide' | 'cli-agent' | 'vcs')[];
|
|
16
|
+
tags: ('ide' | 'cli-agent' | 'vcs' | 'terminal')[];
|
|
17
17
|
iconUrl: string | undefined;
|
|
18
18
|
autoInstall: boolean;
|
|
19
19
|
required: boolean;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"list-tools.use-case.d.ts","sourceRoot":"","sources":["../../../../../../../packages/core/src/application/use-cases/tools/list-tools.use-case.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAIH,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,qCAAqC,CAAC;AAClF,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,sCAAsC,CAAC;AAGlF,MAAM,WAAW,QAAQ;IACvB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,EAAE,MAAM,CAAC;IACpB,IAAI,EAAE,CAAC,KAAK,GAAG,WAAW,GAAG,KAAK,CAAC,EAAE,CAAC;
|
|
1
|
+
{"version":3,"file":"list-tools.use-case.d.ts","sourceRoot":"","sources":["../../../../../../../packages/core/src/application/use-cases/tools/list-tools.use-case.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAIH,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,qCAAqC,CAAC;AAClF,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,sCAAsC,CAAC;AAGlF,MAAM,WAAW,QAAQ;IACvB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,EAAE,MAAM,CAAC;IACpB,IAAI,EAAE,CAAC,KAAK,GAAG,WAAW,GAAG,KAAK,GAAG,UAAU,CAAC,EAAE,CAAC;IACnD,OAAO,EAAE,MAAM,GAAG,SAAS,CAAC;IAC5B,WAAW,EAAE,OAAO,CAAC;IACrB,QAAQ,EAAE,OAAO,CAAC;IAClB,aAAa,EAAE,MAAM,GAAG,SAAS,CAAC;IAClC,gBAAgB,EAAE,MAAM,CAAC;IACzB,cAAc,EAAE,MAAM,GAAG,SAAS,CAAC;IACnC,MAAM,EAAE,sBAAsB,CAAC;CAChC;AAED,MAAM,MAAM,eAAe,GAAG,QAAQ,EAAE,CAAC;AAWzC,qBACa,gBAAgB;IAGzB,OAAO,CAAC,QAAQ,CAAC,oBAAoB;gBAApB,oBAAoB,EAAE,qBAAqB;IAGxD,OAAO,IAAI,OAAO,CAAC,eAAe,CAAC;CAgC1C"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export declare function createDeploymentLogger(prefix: string): {
|
|
2
|
+
info: (...args: unknown[]) => void;
|
|
3
|
+
debug: (...args: unknown[]) => void;
|
|
4
|
+
warn: (...args: unknown[]) => void;
|
|
5
|
+
error: (...args: unknown[]) => void;
|
|
6
|
+
};
|
|
7
|
+
//# sourceMappingURL=deployment-logger.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"deployment-logger.d.ts","sourceRoot":"","sources":["../../../../../../../packages/core/src/infrastructure/services/deployment/deployment-logger.ts"],"names":[],"mappings":"AAWA,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,MAAM;oBAIvB,OAAO,EAAE;qBACR,OAAO,EAAE;oBACpB,OAAO,EAAE;qBACR,OAAO,EAAE;EAE7B"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/* eslint-disable no-console */
|
|
2
|
+
/**
|
|
3
|
+
* Debug-gated logger for deployment services.
|
|
4
|
+
*
|
|
5
|
+
* - `info` and `debug` only emit when `process.env.DEBUG` is set.
|
|
6
|
+
* - `warn` and `error` always emit (they indicate real problems).
|
|
7
|
+
*/
|
|
8
|
+
const noop = () => undefined;
|
|
9
|
+
export function createDeploymentLogger(prefix) {
|
|
10
|
+
const isDebug = !!process.env.DEBUG;
|
|
11
|
+
return {
|
|
12
|
+
info: isDebug ? (...args) => console.info(prefix, ...args) : noop,
|
|
13
|
+
debug: isDebug ? (...args) => console.debug(prefix, ...args) : noop,
|
|
14
|
+
warn: (...args) => console.warn(prefix, ...args),
|
|
15
|
+
error: (...args) => console.error(prefix, ...args),
|
|
16
|
+
};
|
|
17
|
+
}
|
package/dist/packages/core/src/infrastructure/services/deployment/deployment.service.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"deployment.service.d.ts","sourceRoot":"","sources":["../../../../../../../packages/core/src/infrastructure/services/deployment/deployment.service.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAE,KAAK,EAAqB,MAAM,oBAAoB,CAAC;AAE9D,OAAO,KAAK,EACV,kBAAkB,EAClB,gBAAgB,EACjB,MAAM,qEAAqE,CAAC;AAC7E,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;
|
|
1
|
+
{"version":3,"file":"deployment.service.d.ts","sourceRoot":"","sources":["../../../../../../../packages/core/src/infrastructure/services/deployment/deployment.service.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAE,KAAK,EAAqB,MAAM,oBAAoB,CAAC;AAE9D,OAAO,KAAK,EACV,kBAAkB,EAClB,gBAAgB,EACjB,MAAM,qEAAqE,CAAC;AAC7E,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAkBzD,MAAM,WAAW,qBAAqB;IACpC,KAAK,EAAE,OAAO,KAAK,CAAC;IACpB,eAAe,EAAE,OAAO,eAAe,CAAC;IACxC,IAAI,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,OAAO,GAAG,MAAM,KAAK,IAAI,CAAC;IAC7D,OAAO,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC;CACnC;AAgBD,qBAAa,iBAAkB,YAAW,kBAAkB;IAC1D,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAsC;IAClE,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAwB;gBAEjC,IAAI,GAAE,OAAO,CAAC,qBAAqB,CAAM;IAIrD;;;OAGG;IACH,KAAK,CAAC,QAAQ,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,IAAI;IA8EjD;;;OAGG;IACH,SAAS,CAAC,QAAQ,EAAE,MAAM,GAAG,gBAAgB,GAAG,IAAI;IAYpD;;OAEG;IACG,IAAI,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAuC3C;;OAEG;IACH,OAAO,IAAI,IAAI;IAMf;;OAEG;IACH,OAAO,CAAC,WAAW;IAQnB;;OAEG;IACH,OAAO,CAAC,oBAAoB;IAoD5B;;OAEG;YACW,aAAa;IAW3B;;OAEG;IACH,OAAO,CAAC,WAAW;CASpB"}
|
|
@@ -9,7 +9,9 @@
|
|
|
9
9
|
import { spawn } from 'node:child_process';
|
|
10
10
|
import { DeploymentState } from '../../../domain/generated/output.js';
|
|
11
11
|
import { detectDevScript } from './detect-dev-script.js';
|
|
12
|
+
import { createDeploymentLogger } from './deployment-logger.js';
|
|
12
13
|
import { parsePort } from './parse-port.js';
|
|
14
|
+
const log = createDeploymentLogger('[DeploymentService]');
|
|
13
15
|
const POLL_INTERVAL_MS = 200;
|
|
14
16
|
const MAX_WAIT_MS = 5000;
|
|
15
17
|
const defaultDeps = {
|
|
@@ -37,20 +39,24 @@ export class DeploymentService {
|
|
|
37
39
|
* If a deployment already exists for this target, it is stopped first.
|
|
38
40
|
*/
|
|
39
41
|
start(targetId, targetPath) {
|
|
42
|
+
log.info(`start() called — targetId="${targetId}", targetPath="${targetPath}"`);
|
|
40
43
|
// Stop any existing deployment for this target
|
|
41
44
|
const existing = this.deployments.get(targetId);
|
|
42
45
|
if (existing) {
|
|
46
|
+
log.info(`Stopping existing deployment for "${targetId}" (pid=${existing.pid})`);
|
|
43
47
|
this.killProcess(existing);
|
|
44
48
|
this.deployments.delete(targetId);
|
|
45
49
|
}
|
|
46
50
|
// Detect the dev script
|
|
47
51
|
const detection = this.deps.detectDevScript(targetPath);
|
|
48
52
|
if (!detection.success) {
|
|
53
|
+
log.error(`Dev script detection failed: ${detection.error}`);
|
|
49
54
|
throw new Error(detection.error);
|
|
50
55
|
}
|
|
51
56
|
// Build spawn args based on package manager
|
|
52
|
-
const { packageManager, scriptName } = detection;
|
|
57
|
+
const { packageManager, scriptName, command } = detection;
|
|
53
58
|
const args = packageManager === 'npm' ? ['run', scriptName] : [scriptName];
|
|
59
|
+
log.info(`Spawning dev server: command="${command}", packageManager="${packageManager}", scriptName="${scriptName}", cwd="${targetPath}"`);
|
|
54
60
|
const child = this.deps.spawn(packageManager, args, {
|
|
55
61
|
shell: true,
|
|
56
62
|
cwd: targetPath,
|
|
@@ -58,8 +64,10 @@ export class DeploymentService {
|
|
|
58
64
|
stdio: ['ignore', 'pipe', 'pipe'],
|
|
59
65
|
});
|
|
60
66
|
if (!child.pid) {
|
|
67
|
+
log.error('spawn() returned no PID — process failed to start');
|
|
61
68
|
throw new Error('Failed to spawn dev server: no PID returned');
|
|
62
69
|
}
|
|
70
|
+
log.info(`Process spawned — pid=${child.pid}`);
|
|
63
71
|
const entry = {
|
|
64
72
|
pid: child.pid,
|
|
65
73
|
child: child,
|
|
@@ -73,8 +81,19 @@ export class DeploymentService {
|
|
|
73
81
|
// Attach stdout/stderr listeners for port detection
|
|
74
82
|
this.attachOutputListener(entry, 'stdout');
|
|
75
83
|
this.attachOutputListener(entry, 'stderr');
|
|
84
|
+
// Handle spawn errors (command not found, permission denied, etc.)
|
|
85
|
+
child.on('error', (err) => {
|
|
86
|
+
log.error(`Child process error for "${targetId}" (pid=${entry.pid}): ${err.message}`);
|
|
87
|
+
entry.state = DeploymentState.Stopped;
|
|
88
|
+
this.deployments.delete(targetId);
|
|
89
|
+
});
|
|
76
90
|
// Clean up on process exit
|
|
77
|
-
child.on('exit', () => {
|
|
91
|
+
child.on('exit', (code, signal) => {
|
|
92
|
+
const wasBooting = entry.state === DeploymentState.Booting;
|
|
93
|
+
log.info(`Process exited for "${targetId}" (pid=${entry.pid}) — code=${code}, signal=${signal}, wasBooting=${wasBooting}`);
|
|
94
|
+
if (wasBooting) {
|
|
95
|
+
log.warn('Process exited while still in Booting state — dev server likely crashed on startup. Check stderr output above.');
|
|
96
|
+
}
|
|
78
97
|
this.deployments.delete(targetId);
|
|
79
98
|
});
|
|
80
99
|
}
|
|
@@ -84,8 +103,11 @@ export class DeploymentService {
|
|
|
84
103
|
*/
|
|
85
104
|
getStatus(targetId) {
|
|
86
105
|
const entry = this.deployments.get(targetId);
|
|
87
|
-
if (!entry)
|
|
106
|
+
if (!entry) {
|
|
107
|
+
log.debug(`getStatus("${targetId}") — no deployment found`);
|
|
88
108
|
return null;
|
|
109
|
+
}
|
|
110
|
+
log.debug(`getStatus("${targetId}") — state=${entry.state}, url=${entry.url}, pid=${entry.pid}`);
|
|
89
111
|
return { state: entry.state, url: entry.url };
|
|
90
112
|
}
|
|
91
113
|
/**
|
|
@@ -93,20 +115,24 @@ export class DeploymentService {
|
|
|
93
115
|
*/
|
|
94
116
|
async stop(targetId) {
|
|
95
117
|
const entry = this.deployments.get(targetId);
|
|
96
|
-
if (!entry)
|
|
118
|
+
if (!entry) {
|
|
119
|
+
log.info(`stop("${targetId}") — no deployment found, nothing to stop`);
|
|
97
120
|
return;
|
|
121
|
+
}
|
|
122
|
+
log.info(`stop("${targetId}") — sending SIGTERM to process group (pid=${entry.pid})`);
|
|
98
123
|
// Send SIGTERM to process group
|
|
99
124
|
try {
|
|
100
125
|
this.deps.kill(-entry.pid, 'SIGTERM');
|
|
101
126
|
}
|
|
102
127
|
catch {
|
|
103
|
-
|
|
128
|
+
log.info(`stop("${targetId}") — process already dead on SIGTERM`);
|
|
104
129
|
this.deployments.delete(targetId);
|
|
105
130
|
return;
|
|
106
131
|
}
|
|
107
132
|
// Wait for the process to exit
|
|
108
133
|
const died = await this.pollUntilDead(entry.pid, MAX_WAIT_MS, POLL_INTERVAL_MS);
|
|
109
134
|
if (!died) {
|
|
135
|
+
log.warn(`stop("${targetId}") — process did not exit after ${MAX_WAIT_MS}ms, escalating to SIGKILL`);
|
|
110
136
|
// Escalate to SIGKILL
|
|
111
137
|
try {
|
|
112
138
|
this.deps.kill(-entry.pid, 'SIGKILL');
|
|
@@ -115,6 +141,9 @@ export class DeploymentService {
|
|
|
115
141
|
// Process may have exited between check and kill
|
|
116
142
|
}
|
|
117
143
|
}
|
|
144
|
+
else {
|
|
145
|
+
log.info(`stop("${targetId}") — process exited gracefully`);
|
|
146
|
+
}
|
|
118
147
|
// Wait for the exit event to clean up the map
|
|
119
148
|
await this.waitForExit(entry.child);
|
|
120
149
|
}
|
|
@@ -143,26 +172,50 @@ export class DeploymentService {
|
|
|
143
172
|
attachOutputListener(entry, stream) {
|
|
144
173
|
const bufferKey = stream === 'stdout' ? 'stdoutBuffer' : 'stderrBuffer';
|
|
145
174
|
const childStream = entry.child[stream];
|
|
146
|
-
if (!childStream)
|
|
175
|
+
if (!childStream) {
|
|
176
|
+
log.warn(`[${entry.targetId}] No ${stream} stream available — cannot attach listener`);
|
|
147
177
|
return;
|
|
178
|
+
}
|
|
148
179
|
childStream.on('data', (chunk) => {
|
|
180
|
+
const text = chunk.toString();
|
|
149
181
|
// Append chunk to buffer
|
|
150
|
-
entry[bufferKey] +=
|
|
182
|
+
entry[bufferKey] += text;
|
|
151
183
|
// Process complete lines
|
|
152
184
|
const lines = entry[bufferKey].split('\n');
|
|
153
185
|
// Keep the last element (incomplete line) in the buffer
|
|
154
186
|
entry[bufferKey] = lines.pop() ?? '';
|
|
155
187
|
for (const line of lines) {
|
|
188
|
+
if (!line.trim())
|
|
189
|
+
continue;
|
|
190
|
+
log.debug(`[${entry.targetId}] ${stream}: ${line}`);
|
|
156
191
|
if (entry.state !== DeploymentState.Booting)
|
|
157
192
|
break;
|
|
158
193
|
const url = parsePort(line);
|
|
159
194
|
if (url) {
|
|
195
|
+
log.info(`[${entry.targetId}] Port detected — url="${url}" (from ${stream})`);
|
|
160
196
|
entry.state = DeploymentState.Ready;
|
|
161
197
|
entry.url = url;
|
|
162
198
|
break;
|
|
163
199
|
}
|
|
164
200
|
}
|
|
165
201
|
});
|
|
202
|
+
childStream.on('end', () => {
|
|
203
|
+
// Flush remaining buffer content
|
|
204
|
+
const remaining = entry[bufferKey].trim();
|
|
205
|
+
if (remaining) {
|
|
206
|
+
log.debug(`[${entry.targetId}] ${stream} (flush): ${remaining}`);
|
|
207
|
+
if (entry.state === DeploymentState.Booting) {
|
|
208
|
+
const url = parsePort(remaining);
|
|
209
|
+
if (url) {
|
|
210
|
+
log.info(`[${entry.targetId}] Port detected in flushed buffer — url="${url}"`);
|
|
211
|
+
entry.state = DeploymentState.Ready;
|
|
212
|
+
entry.url = url;
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
entry[bufferKey] = '';
|
|
216
|
+
}
|
|
217
|
+
log.debug(`[${entry.targetId}] ${stream} stream ended`);
|
|
218
|
+
});
|
|
166
219
|
}
|
|
167
220
|
/**
|
|
168
221
|
* Poll until a process is dead or timeout expires.
|
package/dist/packages/core/src/infrastructure/services/deployment/detect-dev-script.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"detect-dev-script.d.ts","sourceRoot":"","sources":["../../../../../../../packages/core/src/infrastructure/services/deployment/detect-dev-script.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;
|
|
1
|
+
{"version":3,"file":"detect-dev-script.d.ts","sourceRoot":"","sources":["../../../../../../../packages/core/src/infrastructure/services/deployment/detect-dev-script.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAgBH,MAAM,WAAW,sBAAsB;IACrC,OAAO,EAAE,IAAI,CAAC;IACd,cAAc,EAAE,MAAM,CAAC;IACvB,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,oBAAoB;IACnC,OAAO,EAAE,KAAK,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;CACf;AAED,MAAM,MAAM,qBAAqB,GAAG,sBAAsB,GAAG,oBAAoB,CAAC;AAIlF;;;;;GAKG;AACH,wBAAgB,eAAe,CAAC,OAAO,EAAE,MAAM,GAAG,qBAAqB,CAuCtE"}
|
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
*/
|
|
8
8
|
import { readFileSync, existsSync } from 'node:fs';
|
|
9
9
|
import { join } from 'node:path';
|
|
10
|
+
import { createDeploymentLogger } from './deployment-logger.js';
|
|
10
11
|
/** Script names to search for, in priority order */
|
|
11
12
|
const SCRIPT_PRIORITY = ['dev', 'start', 'serve'];
|
|
12
13
|
/** Lockfile-to-package-manager mapping, checked in order */
|
|
@@ -15,6 +16,7 @@ const LOCKFILE_MANAGERS = [
|
|
|
15
16
|
{ lockfile: 'yarn.lock', manager: 'yarn' },
|
|
16
17
|
{ lockfile: 'package-lock.json', manager: 'npm' },
|
|
17
18
|
];
|
|
19
|
+
const log = createDeploymentLogger('[detectDevScript]');
|
|
18
20
|
/**
|
|
19
21
|
* Detect the dev script and package manager for a project directory.
|
|
20
22
|
*
|
|
@@ -22,28 +24,33 @@ const LOCKFILE_MANAGERS = [
|
|
|
22
24
|
* @returns Detection result with command info, or an error
|
|
23
25
|
*/
|
|
24
26
|
export function detectDevScript(dirPath) {
|
|
27
|
+
log.info(`scanning dirPath="${dirPath}"`);
|
|
25
28
|
// Read and parse package.json
|
|
26
29
|
let packageJson;
|
|
27
30
|
try {
|
|
28
31
|
const raw = readFileSync(join(dirPath, 'package.json'), 'utf-8');
|
|
29
32
|
packageJson = JSON.parse(raw);
|
|
30
33
|
}
|
|
31
|
-
catch {
|
|
32
|
-
|
|
34
|
+
catch (err) {
|
|
35
|
+
const msg = `No package.json found in ${dirPath}`;
|
|
36
|
+
log.error(msg, err);
|
|
37
|
+
return { success: false, error: msg };
|
|
33
38
|
}
|
|
34
39
|
// Find the first matching script in priority order
|
|
35
40
|
const scripts = packageJson.scripts ?? {};
|
|
41
|
+
const availableScripts = Object.keys(scripts);
|
|
42
|
+
log.info(`available scripts: [${availableScripts.join(', ')}], looking for: [${SCRIPT_PRIORITY.join(', ')}]`);
|
|
36
43
|
const scriptName = SCRIPT_PRIORITY.find((name) => name in scripts);
|
|
37
44
|
if (!scriptName) {
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
};
|
|
45
|
+
const msg = `No dev script found in package.json. Expected one of: ${SCRIPT_PRIORITY.join(', ')}`;
|
|
46
|
+
log.warn(msg);
|
|
47
|
+
return { success: false, error: msg };
|
|
42
48
|
}
|
|
43
49
|
// Detect package manager from lockfile
|
|
44
50
|
const packageManager = detectPackageManager(dirPath);
|
|
45
51
|
// Build the command — pnpm/yarn use `<pm> <script>`, npm uses `npm run <script>`
|
|
46
52
|
const command = packageManager === 'npm' ? `npm run ${scriptName}` : `${packageManager} ${scriptName}`;
|
|
53
|
+
log.info(`detected — packageManager="${packageManager}", scriptName="${scriptName}", command="${command}"`);
|
|
47
54
|
return { success: true, packageManager, scriptName, command };
|
|
48
55
|
}
|
|
49
56
|
/**
|
package/dist/packages/core/src/infrastructure/services/tool-installer/tool-installer.service.d.ts
CHANGED
|
@@ -15,7 +15,8 @@ import type { IToolInstallerService } from '../../../application/ports/output/se
|
|
|
15
15
|
import type { ToolInstallationStatus, ToolInstallCommand } from '../../../domain/generated/output.js';
|
|
16
16
|
export declare class ToolInstallerServiceImpl implements IToolInstallerService {
|
|
17
17
|
/**
|
|
18
|
-
* Check if a tool binary is available on the system (PATH check
|
|
18
|
+
* Check if a tool binary is available on the system (PATH check,
|
|
19
|
+
* with verifyCommand fallback for GUI apps).
|
|
19
20
|
*/
|
|
20
21
|
checkAvailability(toolName: string): Promise<ToolInstallationStatus>;
|
|
21
22
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tool-installer.service.d.ts","sourceRoot":"","sources":["../../../../../../../packages/core/src/infrastructure/services/tool-installer/tool-installer.service.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAKH,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,sEAAsE,CAAC;AAClH,OAAO,KAAK,EACV,sBAAsB,EACtB,kBAAkB,EAEnB,MAAM,qCAAqC,CAAC;
|
|
1
|
+
{"version":3,"file":"tool-installer.service.d.ts","sourceRoot":"","sources":["../../../../../../../packages/core/src/infrastructure/services/tool-installer/tool-installer.service.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAKH,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,sEAAsE,CAAC;AAClH,OAAO,KAAK,EACV,sBAAsB,EACtB,kBAAkB,EAEnB,MAAM,qCAAqC,CAAC;AAsD7C,qBACa,wBAAyB,YAAW,qBAAqB;IACpE;;;OAGG;IACG,iBAAiB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,sBAAsB,CAAC;IAoC1E;;;OAGG;IACH,iBAAiB,CAAC,QAAQ,EAAE,MAAM,GAAG,kBAAkB,GAAG,IAAI;IAqB9D;;;OAGG;IACG,cAAc,CAClB,QAAQ,EAAE,MAAM,EAChB,QAAQ,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,GAChC,OAAO,CAAC,sBAAsB,CAAC;IAuElC;;OAEG;IACH,OAAO,CAAC,6BAA6B;CA4BtC"}
|
package/dist/packages/core/src/infrastructure/services/tool-installer/tool-installer.service.js
CHANGED
|
@@ -18,7 +18,7 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
|
|
|
18
18
|
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
19
19
|
};
|
|
20
20
|
import { injectable } from 'tsyringe';
|
|
21
|
-
import { execFile, spawn } from 'node:child_process';
|
|
21
|
+
import { exec, execFile, spawn } from 'node:child_process';
|
|
22
22
|
import { platform } from 'node:os';
|
|
23
23
|
import { createAvailableStatus, createMissingStatus, createErrorStatus, } from '../../../domain/value-objects/tool-installation-status.js';
|
|
24
24
|
import { TOOL_METADATA } from './tool-metadata.js';
|
|
@@ -55,9 +55,17 @@ const checkBinaryExists = (binary) => {
|
|
|
55
55
|
});
|
|
56
56
|
});
|
|
57
57
|
};
|
|
58
|
+
/**
|
|
59
|
+
* Run a shell command and resolve true when it exits 0, false otherwise.
|
|
60
|
+
* Used as a fallback for GUI apps whose binary isn't in PATH (e.g. Warp, iTerm2).
|
|
61
|
+
*/
|
|
62
|
+
const runVerifyCommand = (command) => new Promise((resolve) => {
|
|
63
|
+
exec(command, (err) => resolve(!err));
|
|
64
|
+
});
|
|
58
65
|
let ToolInstallerServiceImpl = class ToolInstallerServiceImpl {
|
|
59
66
|
/**
|
|
60
|
-
* Check if a tool binary is available on the system (PATH check
|
|
67
|
+
* Check if a tool binary is available on the system (PATH check,
|
|
68
|
+
* with verifyCommand fallback for GUI apps).
|
|
61
69
|
*/
|
|
62
70
|
async checkAvailability(toolName) {
|
|
63
71
|
const metadata = TOOL_METADATA[toolName];
|
|
@@ -69,6 +77,13 @@ let ToolInstallerServiceImpl = class ToolInstallerServiceImpl {
|
|
|
69
77
|
if (result.found) {
|
|
70
78
|
return createAvailableStatus(toolName);
|
|
71
79
|
}
|
|
80
|
+
// Binary not in PATH — try verifyCommand as fallback (handles GUI .app bundles)
|
|
81
|
+
if (result.notInPath && metadata.verifyCommand) {
|
|
82
|
+
const verified = await runVerifyCommand(metadata.verifyCommand);
|
|
83
|
+
if (verified) {
|
|
84
|
+
return createAvailableStatus(toolName);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
72
87
|
if (result.notInPath) {
|
|
73
88
|
const suggestions = this.createInstallationSuggestions(metadata);
|
|
74
89
|
return createMissingStatus(toolName, suggestions);
|
|
@@ -15,7 +15,7 @@ export interface ToolMetadata {
|
|
|
15
15
|
/** Detailed description */
|
|
16
16
|
description: string;
|
|
17
17
|
/** Tool tags for grouping in listings. A tool can belong to multiple categories. */
|
|
18
|
-
tags: ('ide' | 'cli-agent' | 'vcs')[];
|
|
18
|
+
tags: ('ide' | 'cli-agent' | 'vcs' | 'terminal')[];
|
|
19
19
|
/** URL to the tool's icon/logo image */
|
|
20
20
|
iconUrl?: string;
|
|
21
21
|
/** Binary name to check with 'which' command (string or per-platform 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,oFAAoF;IACpF,IAAI,EAAE,CAAC,KAAK,GAAG,WAAW,GAAG,KAAK,CAAC,EAAE,CAAC;
|
|
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,GAAG,KAAK,GAAG,UAAU,CAAC,EAAE,CAAC;IAEnD,wCAAwC;IACxC,OAAO,CAAC,EAAE,MAAM,CAAC;IAEjB,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,kFAAkF;IAClF,QAAQ,CAAC,EAAE,OAAO,CAAC;IAEnB;;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;IAEF;;;;wEAIoE;IACpE,eAAe,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACnD;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"}
|
|
@@ -5,24 +5,24 @@ Files are loaded dynamically by `tool-metadata.ts` — the filename (minus `.jso
|
|
|
5
5
|
|
|
6
6
|
## Schema
|
|
7
7
|
|
|
8
|
-
| Field | Type
|
|
9
|
-
| ------------------ |
|
|
10
|
-
| `name` | `string`
|
|
11
|
-
| `summary` | `string`
|
|
12
|
-
| `description` | `string`
|
|
13
|
-
| `tags` | `("ide"\|"cli-agent"\|"vcs")[]`
|
|
14
|
-
| `iconUrl` | `string`
|
|
15
|
-
| `binary` | `string \| Record<string,string>`
|
|
16
|
-
| `packageManager` | `string`
|
|
17
|
-
| `commands` | `Record<string,string>`
|
|
18
|
-
| `timeout` | `number`
|
|
19
|
-
| `documentationUrl` | `string`
|
|
20
|
-
| `verifyCommand` | `string`
|
|
21
|
-
| `autoInstall` | `boolean`
|
|
22
|
-
| `required` | `boolean`
|
|
23
|
-
| `openDirectory` | `string \| Record<string,string>`
|
|
24
|
-
| `spawnOptions` | `object`
|
|
25
|
-
| `terminalCommand` | `string \| Record<string,string>`
|
|
8
|
+
| Field | Type | Required | Description |
|
|
9
|
+
| ------------------ | ------------------------------------------- | -------- | ------------------------------------------------------------------------ |
|
|
10
|
+
| `name` | `string` | Yes | Human-readable display name |
|
|
11
|
+
| `summary` | `string` | Yes | One-line description |
|
|
12
|
+
| `description` | `string` | Yes | Detailed description |
|
|
13
|
+
| `tags` | `("ide"\|"cli-agent"\|"vcs"\|"terminal")[]` | Yes | Categories for filtering in UI and CLI |
|
|
14
|
+
| `iconUrl` | `string` | No | URL to SVG/PNG icon (use cdn.simpleicons.org when possible) |
|
|
15
|
+
| `binary` | `string \| Record<string,string>` | Yes | Binary name for `which` check. Per-platform map if differs |
|
|
16
|
+
| `packageManager` | `string` | Yes | Install method label (apt, brew, curl, manual, download) |
|
|
17
|
+
| `commands` | `Record<string,string>` | Yes | Platform-keyed install commands (`linux`, `darwin`) |
|
|
18
|
+
| `timeout` | `number` | Yes | Install timeout in ms (typically 300000) |
|
|
19
|
+
| `documentationUrl` | `string` | Yes | Official docs URL |
|
|
20
|
+
| `verifyCommand` | `string` | Yes | Command to verify installation (e.g. `git --version`) |
|
|
21
|
+
| `autoInstall` | `boolean` | No | `true` (default) = run commands automatically. `false` = manual download |
|
|
22
|
+
| `required` | `boolean` | No | `true` = tool is required for platform to function |
|
|
23
|
+
| `openDirectory` | `string \| Record<string,string>` | No | Command to open a directory. Use `{dir}` placeholder |
|
|
24
|
+
| `spawnOptions` | `object` | No | Override spawn behavior (see below) |
|
|
25
|
+
| `terminalCommand` | `string \| Record<string,string>` | No | Command to open tool in a **new terminal window** from web UI |
|
|
26
26
|
|
|
27
27
|
## Spawn Options
|
|
28
28
|
|
|
@@ -59,5 +59,32 @@ The launcher auto-detects TTY: CLI launch uses `openDirectory`, web launch uses
|
|
|
59
59
|
| `ide` | GUI code editor | VS Code, Cursor, Zed |
|
|
60
60
|
| `cli-agent` | Terminal-based AI coding agent | Claude Code, Cursor CLI |
|
|
61
61
|
| `vcs` | Version control tool | Git, GitHub CLI |
|
|
62
|
+
| `terminal` | Terminal emulator/multiplexer | tmux, Kitty, Alacritty |
|
|
62
63
|
|
|
63
64
|
Tools can have multiple tags. A tool appears in all matching filter tabs in the UI.
|
|
65
|
+
|
|
66
|
+
### Terminal Tools
|
|
67
|
+
|
|
68
|
+
Terminal tools use the `terminal` tag. GUI terminals (Kitty, Alacritty) use `brew install --cask` on macOS.
|
|
69
|
+
CLI tools like tmux use `brew install` (formula). Terminals with `--working-directory` flags can include
|
|
70
|
+
`openDirectory` for launch support. tmux requires `spawnOptions` with `shell: true` and `stdio: "inherit"`
|
|
71
|
+
since it runs inside the current terminal session.
|
|
72
|
+
|
|
73
|
+
Example (tmux):
|
|
74
|
+
|
|
75
|
+
```json
|
|
76
|
+
{
|
|
77
|
+
"name": "tmux",
|
|
78
|
+
"summary": "Terminal multiplexer for session management",
|
|
79
|
+
"tags": ["terminal"],
|
|
80
|
+
"binary": "tmux",
|
|
81
|
+
"packageManager": "brew",
|
|
82
|
+
"commands": { "darwin": "brew install tmux", "linux": "apt install -y tmux" },
|
|
83
|
+
"timeout": 300000,
|
|
84
|
+
"documentationUrl": "https://github.com/tmux/tmux/wiki",
|
|
85
|
+
"verifyCommand": "tmux -V",
|
|
86
|
+
"autoInstall": true,
|
|
87
|
+
"openDirectory": "tmux new-session -c {dir}",
|
|
88
|
+
"spawnOptions": { "shell": true, "stdio": "inherit", "detached": false }
|
|
89
|
+
}
|
|
90
|
+
```
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "Alacritty",
|
|
3
|
+
"summary": "GPU-accelerated terminal emulator",
|
|
4
|
+
"description": "Alacritty is a modern, GPU-accelerated terminal emulator focused on simplicity and performance. Cross-platform (macOS and Linux). On older Linux distributions, you may need to add a PPA before installing via apt.",
|
|
5
|
+
"tags": ["terminal"],
|
|
6
|
+
"iconUrl": "https://cdn.simpleicons.org/alacritty",
|
|
7
|
+
"binary": "alacritty",
|
|
8
|
+
"packageManager": "brew",
|
|
9
|
+
"commands": {
|
|
10
|
+
"darwin": "brew install --cask alacritty",
|
|
11
|
+
"linux": "apt install -y alacritty"
|
|
12
|
+
},
|
|
13
|
+
"timeout": 300000,
|
|
14
|
+
"documentationUrl": "https://alacritty.org/",
|
|
15
|
+
"verifyCommand": "alacritty --version",
|
|
16
|
+
"autoInstall": false,
|
|
17
|
+
"openDirectory": "alacritty --working-directory {dir}"
|
|
18
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "iTerm2",
|
|
3
|
+
"summary": "macOS terminal replacement",
|
|
4
|
+
"description": "iTerm2 is a feature-rich replacement for the default macOS Terminal.app with split panes, search, autocomplete, and extensive customization. macOS only. Verified by checking for the iTerm.app bundle in /Applications.",
|
|
5
|
+
"tags": ["terminal"],
|
|
6
|
+
"iconUrl": "https://cdn.simpleicons.org/iterm2",
|
|
7
|
+
"binary": "iterm2",
|
|
8
|
+
"packageManager": "brew",
|
|
9
|
+
"commands": {
|
|
10
|
+
"darwin": "brew install --cask iterm2"
|
|
11
|
+
},
|
|
12
|
+
"timeout": 300000,
|
|
13
|
+
"documentationUrl": "https://iterm2.com/documentation.html",
|
|
14
|
+
"verifyCommand": "test -d /Applications/iTerm.app",
|
|
15
|
+
"autoInstall": false,
|
|
16
|
+
"openDirectory": "open -a iTerm {dir}"
|
|
17
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "Kitty",
|
|
3
|
+
"summary": "Fast, GPU-based terminal emulator",
|
|
4
|
+
"description": "Kitty is a fast, feature-rich, GPU-based terminal emulator with advanced graphics support, extensibility via kittens, and modern rendering. Cross-platform (macOS and Linux).",
|
|
5
|
+
"tags": ["terminal"],
|
|
6
|
+
"iconUrl": "https://raw.githubusercontent.com/kovidgoyal/kitty/master/logo/kitty.svg",
|
|
7
|
+
"binary": "kitty",
|
|
8
|
+
"packageManager": "brew",
|
|
9
|
+
"commands": {
|
|
10
|
+
"darwin": "brew install --cask kitty",
|
|
11
|
+
"linux": "apt install -y kitty"
|
|
12
|
+
},
|
|
13
|
+
"timeout": 300000,
|
|
14
|
+
"documentationUrl": "https://sw.kovidgoyal.net/kitty/",
|
|
15
|
+
"verifyCommand": "kitty --version",
|
|
16
|
+
"autoInstall": false,
|
|
17
|
+
"openDirectory": "kitty --working-directory {dir}"
|
|
18
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "tmux",
|
|
3
|
+
"summary": "Terminal multiplexer for session management",
|
|
4
|
+
"description": "tmux is a terminal multiplexer that lets you create, manage, and switch between multiple terminal sessions. Ideal for remote development, persistent sessions, and multi-pane workflows. Cross-platform (macOS and Linux).",
|
|
5
|
+
"tags": ["terminal"],
|
|
6
|
+
"iconUrl": "https://cdn.simpleicons.org/tmux",
|
|
7
|
+
"binary": "tmux",
|
|
8
|
+
"packageManager": "brew",
|
|
9
|
+
"commands": {
|
|
10
|
+
"darwin": "brew install tmux",
|
|
11
|
+
"linux": "apt install -y tmux"
|
|
12
|
+
},
|
|
13
|
+
"timeout": 300000,
|
|
14
|
+
"documentationUrl": "https://github.com/tmux/tmux/wiki",
|
|
15
|
+
"verifyCommand": "tmux -V",
|
|
16
|
+
"autoInstall": true,
|
|
17
|
+
"openDirectory": "tmux new-session -c {dir}",
|
|
18
|
+
"terminalCommand": {
|
|
19
|
+
"darwin": "osascript -e 'tell application \"Terminal\" to do script \"tmux new-session -c {dir}\"' -e 'tell application \"Terminal\" to activate'",
|
|
20
|
+
"linux": "x-terminal-emulator -e tmux new-session -c {dir}"
|
|
21
|
+
},
|
|
22
|
+
"spawnOptions": {
|
|
23
|
+
"shell": true,
|
|
24
|
+
"stdio": "inherit",
|
|
25
|
+
"detached": false
|
|
26
|
+
}
|
|
27
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "Warp",
|
|
3
|
+
"summary": "Modern terminal with AI features",
|
|
4
|
+
"description": "Warp is a modern terminal with AI-powered features, intelligent command suggestions, and a collaborative workflow. macOS only — Linux users can install manually via AppImage from https://www.warp.dev/.",
|
|
5
|
+
"tags": ["terminal"],
|
|
6
|
+
"iconUrl": "https://cdn.simpleicons.org/warp",
|
|
7
|
+
"binary": "warp",
|
|
8
|
+
"packageManager": "brew",
|
|
9
|
+
"commands": {
|
|
10
|
+
"darwin": "brew install --cask warp"
|
|
11
|
+
},
|
|
12
|
+
"timeout": 300000,
|
|
13
|
+
"documentationUrl": "https://docs.warp.dev/",
|
|
14
|
+
"verifyCommand": "test -d /Applications/Warp.app",
|
|
15
|
+
"autoInstall": false,
|
|
16
|
+
"openDirectory": "open -a Warp {dir}"
|
|
17
|
+
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"deploy-feature.d.ts","sourceRoot":"","sources":["../../../../../../src/presentation/web/app/actions/deploy-feature.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"deploy-feature.d.ts","sourceRoot":"","sources":["../../../../../../src/presentation/web/app/actions/deploy-feature.ts"],"names":[],"mappings":"AAQA,OAAO,EAAE,eAAe,EAAE,MAAM,sCAAsC,CAAC;AAIvE,wBAAsB,aAAa,CACjC,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC;IAAE,OAAO,EAAE,OAAO,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,eAAe,CAAA;CAAE,CAAC,CAwCxE"}
|
|
@@ -1,28 +1,39 @@
|
|
|
1
1
|
'use server';
|
|
2
2
|
import { existsSync } from 'node:fs';
|
|
3
3
|
import { resolve } from '../../lib/server-container.js';
|
|
4
|
+
import { createDeploymentLogger } from '../../../../../packages/core/src/infrastructure/services/deployment/deployment-logger.js';
|
|
4
5
|
import { computeWorktreePath } from '../../../../../packages/core/src/infrastructure/services/ide-launchers/compute-worktree-path.js';
|
|
5
6
|
import { DeploymentState } from '../../../../../packages/core/src/domain/generated/output.js';
|
|
7
|
+
const log = createDeploymentLogger('[deployFeature]');
|
|
6
8
|
export async function deployFeature(featureId) {
|
|
9
|
+
log.info(`called — featureId="${featureId}"`);
|
|
7
10
|
if (!featureId?.trim()) {
|
|
11
|
+
log.warn('rejected — featureId is empty');
|
|
8
12
|
return { success: false, error: 'featureId is required' };
|
|
9
13
|
}
|
|
10
14
|
try {
|
|
11
15
|
const featureRepo = resolve('IFeatureRepository');
|
|
12
16
|
const feature = await featureRepo.findById(featureId);
|
|
13
17
|
if (!feature) {
|
|
18
|
+
log.warn(`feature not found in repository: "${featureId}"`);
|
|
14
19
|
return { success: false, error: `Feature not found: ${featureId}` };
|
|
15
20
|
}
|
|
21
|
+
log.info(`feature found — repositoryPath="${feature.repositoryPath}", branch="${feature.branch}"`);
|
|
16
22
|
const worktreePath = computeWorktreePath(feature.repositoryPath, feature.branch);
|
|
23
|
+
log.info(`computed worktreePath="${worktreePath}"`);
|
|
17
24
|
if (!existsSync(worktreePath)) {
|
|
25
|
+
log.warn(`worktree path does not exist on disk: "${worktreePath}"`);
|
|
18
26
|
return { success: false, error: `Worktree path does not exist: ${worktreePath}` };
|
|
19
27
|
}
|
|
28
|
+
log.info('worktree path exists, calling deploymentService.start()');
|
|
20
29
|
const deploymentService = resolve('IDeploymentService');
|
|
21
30
|
deploymentService.start(featureId, worktreePath);
|
|
31
|
+
log.info('start() returned successfully — state=Booting');
|
|
22
32
|
return { success: true, state: DeploymentState.Booting };
|
|
23
33
|
}
|
|
24
34
|
catch (error) {
|
|
25
35
|
const message = error instanceof Error ? error.message : 'Failed to deploy feature';
|
|
36
|
+
log.error(`error: ${message}`, error);
|
|
26
37
|
return { success: false, error: message };
|
|
27
38
|
}
|
|
28
39
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"deploy-repository.d.ts","sourceRoot":"","sources":["../../../../../../src/presentation/web/app/actions/deploy-repository.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"deploy-repository.d.ts","sourceRoot":"","sources":["../../../../../../src/presentation/web/app/actions/deploy-repository.ts"],"names":[],"mappings":"AAMA,OAAO,EAAE,eAAe,EAAE,MAAM,sCAAsC,CAAC;AAIvE,wBAAsB,gBAAgB,CACpC,cAAc,EAAE,MAAM,GACrB,OAAO,CAAC;IAAE,OAAO,EAAE,OAAO,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,eAAe,CAAA;CAAE,CAAC,CAyBxE"}
|