@annix/claude-swarm 0.1.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.
Files changed (52) hide show
  1. package/README.md +197 -0
  2. package/bin/claude-swarm +50 -0
  3. package/dist/.build-hash +1 -0
  4. package/dist/adapters/AppAdapter.d.ts +9 -0
  5. package/dist/adapters/AppAdapter.d.ts.map +1 -0
  6. package/dist/adapters/AppAdapter.js +3 -0
  7. package/dist/adapters/AppAdapter.js.map +1 -0
  8. package/dist/adapters/ConfigAdapter.d.ts +21 -0
  9. package/dist/adapters/ConfigAdapter.d.ts.map +1 -0
  10. package/dist/adapters/ConfigAdapter.js +114 -0
  11. package/dist/adapters/ConfigAdapter.js.map +1 -0
  12. package/dist/adapters/DevServerAdapter.d.ts +15 -0
  13. package/dist/adapters/DevServerAdapter.d.ts.map +1 -0
  14. package/dist/adapters/DevServerAdapter.js +84 -0
  15. package/dist/adapters/DevServerAdapter.js.map +1 -0
  16. package/dist/adapters/NestAdapter.d.ts +8 -0
  17. package/dist/adapters/NestAdapter.d.ts.map +1 -0
  18. package/dist/adapters/NestAdapter.js +14 -0
  19. package/dist/adapters/NestAdapter.js.map +1 -0
  20. package/dist/adapters/NextAdapter.d.ts +8 -0
  21. package/dist/adapters/NextAdapter.d.ts.map +1 -0
  22. package/dist/adapters/NextAdapter.js +14 -0
  23. package/dist/adapters/NextAdapter.js.map +1 -0
  24. package/dist/adapters/NullAdapter.d.ts +10 -0
  25. package/dist/adapters/NullAdapter.d.ts.map +1 -0
  26. package/dist/adapters/NullAdapter.js +17 -0
  27. package/dist/adapters/NullAdapter.js.map +1 -0
  28. package/dist/adapters/ProcessAdapter.d.ts +21 -0
  29. package/dist/adapters/ProcessAdapter.d.ts.map +1 -0
  30. package/dist/adapters/ProcessAdapter.js +66 -0
  31. package/dist/adapters/ProcessAdapter.js.map +1 -0
  32. package/dist/adapters/ViteAdapter.d.ts +8 -0
  33. package/dist/adapters/ViteAdapter.d.ts.map +1 -0
  34. package/dist/adapters/ViteAdapter.js +14 -0
  35. package/dist/adapters/ViteAdapter.js.map +1 -0
  36. package/dist/adapters/index.d.ts +11 -0
  37. package/dist/adapters/index.d.ts.map +1 -0
  38. package/dist/adapters/index.js +18 -0
  39. package/dist/adapters/index.js.map +1 -0
  40. package/dist/config.d.ts +19 -0
  41. package/dist/config.d.ts.map +1 -0
  42. package/dist/config.js +48 -0
  43. package/dist/config.js.map +1 -0
  44. package/dist/index.d.ts +3 -0
  45. package/dist/index.d.ts.map +1 -0
  46. package/dist/index.js +1695 -0
  47. package/dist/index.js.map +1 -0
  48. package/dist/log.d.ts +8 -0
  49. package/dist/log.d.ts.map +1 -0
  50. package/dist/log.js +33 -0
  51. package/dist/log.js.map +1 -0
  52. package/package.json +44 -0
package/README.md ADDED
@@ -0,0 +1,197 @@
1
+ # claude-swarm
2
+
3
+ Manage multiple parallel Claude CLI sessions with worktree isolation and pluggable dev server lifecycle management.
4
+
5
+ ## Features
6
+
7
+ - **Session Management**: Detect, spawn, and terminate Claude CLI sessions
8
+ - **Worktree Isolation**: Run parallel sessions in separate git worktrees
9
+ - **Cross-Platform**: Works on Windows, macOS, and Linux
10
+ - **GitHub Integration**: Start sessions from GitHub issues
11
+ - **Process Detection**: Distinguish between active (terminal-attached) and orphaned (detached) sessions
12
+ - **Cleanup Tools**: Kill orphaned sessions individually or in bulk
13
+ - **Pluggable App Adapters**: Manage dev servers for any project via config or built-in adapters
14
+ - **Live Log Viewing**: Tail dev server logs inside the TUI
15
+
16
+ ## Installation
17
+
18
+ ```sh
19
+ npm install -g @annix/claude-swarm
20
+ # or run directly via the launcher
21
+ ../claude-swarm/bin/claude-swarm
22
+ ```
23
+
24
+ ## Usage
25
+
26
+ Run from any git repository:
27
+
28
+ ```sh
29
+ claude-swarm
30
+ ```
31
+
32
+ The tool will detect the current project and load configuration from `.claude-swarm.json` in the current directory if present.
33
+
34
+ ## Project configuration
35
+
36
+ ### `.claude-swarm.json`
37
+
38
+ Create a `.claude-swarm.json` in your project root to configure the branch prefix and dev servers:
39
+
40
+ ```json
41
+ {
42
+ "branchPrefix": "claude/",
43
+ "apps": [
44
+ {
45
+ "name": "backend",
46
+ "start": "pnpm dev:backend",
47
+ "stop": "lsof -ti:4001 | xargs kill -15 2>/dev/null; true",
48
+ "kill": "lsof -ti:4001 | xargs kill -9 2>/dev/null; true",
49
+ "readyPattern": "Nest application successfully started"
50
+ },
51
+ {
52
+ "name": "frontend",
53
+ "start": "pnpm dev:frontend",
54
+ "stop": "lsof -ti:3000 | xargs kill -15 2>/dev/null; true",
55
+ "kill": "lsof -ti:3000 | xargs kill -9 2>/dev/null; true",
56
+ "readyPattern": "Ready in"
57
+ }
58
+ ]
59
+ }
60
+ ```
61
+
62
+ ### Configuration fields
63
+
64
+ | Field | Type | Default | Description |
65
+ |-------|------|---------|-------------|
66
+ | `branchPrefix` | `string` | `"claude/"` | Prefix for Claude-managed branches |
67
+ | `apps` | `AppAdapterConfig[]` | `[]` | Dev server definitions |
68
+
69
+ ### App adapter config
70
+
71
+ | Field | Type | Required | Description |
72
+ |-------|------|----------|-------------|
73
+ | `name` | `string` | Yes | Display name shown in the TUI |
74
+ | `start` | `string` | Yes | Shell command to start the server |
75
+ | `stop` | `string` | Yes | Shell command or signal to stop gracefully (e.g. `signal:SIGTERM`) |
76
+ | `kill` | `string` | Yes | Shell command or signal to force-stop (e.g. `signal:SIGKILL`, or `lsof -ti:PORT | xargs kill -9`) |
77
+ | `readyPattern` | `string` | No | Regex to match against stdout/stderr to detect when the server is ready |
78
+
79
+ When `readyPattern` is set, `start` blocks until the pattern matches or the 120 second timeout elapses.
80
+
81
+ Dev server output is always streamed to `.claude-swarm-<name>.log` in the project directory, regardless of whether `readyPattern` is set. Add `.claude-swarm-*.log` to your `.gitignore`.
82
+
83
+ ### Stop vs Kill commands
84
+
85
+ - **stop**: Sent first; should request graceful shutdown (e.g. SIGTERM or port-based kill -15)
86
+ - **kill**: Fallback if stop throws; should force-terminate (e.g. SIGKILL or port-based kill -9)
87
+
88
+ Use port-based kill commands (via `lsof`) for processes spawned through npm/pnpm scripts, as the script process PID differs from the actual server PID:
89
+
90
+ ```
91
+ "stop": "lsof -ti:4001 | xargs kill -15 2>/dev/null; true"
92
+ "kill": "lsof -ti:4001 | xargs kill -9 2>/dev/null; true"
93
+ ```
94
+
95
+ Use signal format for processes you start directly:
96
+
97
+ ```
98
+ "stop": "signal:SIGTERM"
99
+ "kill": "signal:SIGKILL"
100
+ ```
101
+
102
+ ## Multi-project support
103
+
104
+ claude-swarm manages sessions across multiple projects. On first run it detects the current git repo and adds it automatically. Additional projects can be added interactively via the session menu.
105
+
106
+ Project configurations are saved to `~/.config/claude-swarm/projects.json`. This is a user-level config file shared across all invocations.
107
+
108
+ ### `~/.config/claude-swarm/projects.json`
109
+
110
+ ```json
111
+ {
112
+ "projects": [
113
+ {
114
+ "name": "myapp",
115
+ "path": "/Users/you/dev/myapp",
116
+ "worktreeDir": "/Users/you/dev/myapp-worktrees"
117
+ }
118
+ ],
119
+ "defaultProject": "myapp"
120
+ }
121
+ ```
122
+
123
+ | Field | Type | Description |
124
+ |-------|------|-------------|
125
+ | `projects[].name` | `string` | Display name |
126
+ | `projects[].path` | `string` | Absolute path to the git repo root |
127
+ | `projects[].worktreeDir` | `string` | Where worktrees are created (default: `../name-worktrees` sibling) |
128
+ | `defaultProject` | `string` | Name of the project to select on startup |
129
+
130
+ ## Bin launcher
131
+
132
+ The `bin/claude-swarm` script provides hash-based auto-install/build: it only runs `npm install` or `npm run build` when `package-lock.json` or `src/` files have changed since the last run. This means subsequent invocations start instantly.
133
+
134
+ ```sh
135
+ # From annix:
136
+ pnpm claude-swarm
137
+
138
+ # Directly:
139
+ ../claude-swarm/bin/claude-swarm
140
+ ```
141
+
142
+ ## Branch workflow
143
+
144
+ Claude sessions work on branches with the configured prefix (default `claude/`). The TUI provides:
145
+
146
+ - **Branch listing** — all claude branches with ahead/behind status
147
+ - **Rebase** — rebase a claude branch onto main
148
+ - **Approve** — rebase + fast-forward merge + delete in one step
149
+ - **Cherry-pick** — pull specific commits from a claude branch for testing on main
150
+
151
+ ## App Adapter interface
152
+
153
+ You can use the built-in adapters programmatically:
154
+
155
+ ```typescript
156
+ import {
157
+ AppAdapter,
158
+ NestAdapter,
159
+ NextAdapter,
160
+ ViteAdapter,
161
+ NullAdapter,
162
+ ConfigAdapter,
163
+ DevServerAdapter,
164
+ } from "@annix/claude-swarm";
165
+ ```
166
+
167
+ ### Built-in adapters
168
+
169
+ | Adapter | Description |
170
+ |---------|-------------|
171
+ | `NestAdapter` | NestJS backend (`nest start --watch`) |
172
+ | `NextAdapter` | Next.js frontend (`next dev`) |
173
+ | `ViteAdapter` | Vite dev server (`vite`) |
174
+ | `NullAdapter` | No-op for projects with no managed dev server |
175
+ | `ConfigAdapter` | Generic adapter driven by `.claude-swarm.json` |
176
+ | `DevServerAdapter` | Abstract base class; extend to build custom adapters |
177
+
178
+ ### Custom adapters
179
+
180
+ Implement the `AppAdapter` interface:
181
+
182
+ ```typescript
183
+ interface AppAdapter {
184
+ readonly name: string;
185
+ start(): Promise<void>;
186
+ stop(): Promise<void>;
187
+ kill(): Promise<void>;
188
+ isRunning(): Promise<boolean>;
189
+ logFile(): string | null;
190
+ }
191
+ ```
192
+
193
+ `logFile()` should return the absolute path to the log file for this adapter, or `null` if no log is available. The path is used by the "View logs" TUI feature.
194
+
195
+ ## License
196
+
197
+ MIT
@@ -0,0 +1,50 @@
1
+ #!/bin/bash
2
+ SOURCE="${BASH_SOURCE[0]}"
3
+ while [ -L "$SOURCE" ]; do
4
+ DIR="$(cd -P "$(dirname "$SOURCE")" && pwd)"
5
+ SOURCE="$(readlink "$SOURCE")"
6
+ [[ $SOURCE != /* ]] && SOURCE="$DIR/$SOURCE"
7
+ done
8
+ SCRIPT_DIR="$(cd -P "$(dirname "$SOURCE")" && pwd)"
9
+ PROJECT_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
10
+ cd "$PROJECT_ROOT"
11
+
12
+ DEPS_HASH_FILE="node_modules/.install-hash"
13
+ BUILD_HASH_FILE="dist/.build-hash"
14
+
15
+ compute_deps_hash() {
16
+ cat package-lock.json 2>/dev/null | shasum -a 256 | cut -d' ' -f1
17
+ }
18
+
19
+ compute_src_hash() {
20
+ find src -name "*.ts" | sort | xargs shasum -a 256 2>/dev/null | shasum -a 256 | cut -d' ' -f1
21
+ }
22
+
23
+ needs_install() {
24
+ [ ! -d "node_modules" ] && return 0
25
+ [ ! -f "$DEPS_HASH_FILE" ] && return 0
26
+ [ "$(compute_deps_hash)" != "$(cat "$DEPS_HASH_FILE" 2>/dev/null)" ] && return 0
27
+ return 1
28
+ }
29
+
30
+ needs_build() {
31
+ [ ! -d "dist" ] && return 0
32
+ [ ! -f "dist/index.js" ] && return 0
33
+ [ ! -f "$BUILD_HASH_FILE" ] && return 0
34
+ [ "$(compute_src_hash)" != "$(cat "$BUILD_HASH_FILE" 2>/dev/null)" ] && return 0
35
+ return 1
36
+ }
37
+
38
+ if needs_install; then
39
+ echo "Installing dependencies..."
40
+ npm install --silent
41
+ compute_deps_hash > "$DEPS_HASH_FILE"
42
+ fi
43
+
44
+ if needs_build; then
45
+ echo "Building..."
46
+ npm run build --silent
47
+ compute_src_hash > "$BUILD_HASH_FILE"
48
+ fi
49
+
50
+ exec node dist/index.js "$@"
@@ -0,0 +1 @@
1
+ b314e1ee99e0d74721451e9016635836eaf0687106d416b2fadc05f5f93e6be3
@@ -0,0 +1,9 @@
1
+ export interface AppAdapter {
2
+ readonly name: string;
3
+ start(): Promise<void>;
4
+ stop(): Promise<void>;
5
+ kill(): Promise<void>;
6
+ isRunning(): Promise<boolean>;
7
+ logFile(): string | null;
8
+ }
9
+ //# sourceMappingURL=AppAdapter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"AppAdapter.d.ts","sourceRoot":"","sources":["../../src/adapters/AppAdapter.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,UAAU;IACzB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IACvB,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IACtB,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IACtB,SAAS,IAAI,OAAO,CAAC,OAAO,CAAC,CAAC;IAC9B,OAAO,IAAI,MAAM,GAAG,IAAI,CAAC;CAC1B"}
@@ -0,0 +1,3 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ //# sourceMappingURL=AppAdapter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"AppAdapter.js","sourceRoot":"","sources":["../../src/adapters/AppAdapter.ts"],"names":[],"mappings":""}
@@ -0,0 +1,21 @@
1
+ import type { AppAdapter } from "./AppAdapter.js";
2
+ export interface AppAdapterConfig {
3
+ name: string;
4
+ start: string;
5
+ stop: string;
6
+ kill: string;
7
+ readyPattern?: string;
8
+ }
9
+ export declare class ConfigAdapter implements AppAdapter {
10
+ readonly name: string;
11
+ private readonly config;
12
+ private readonly cwd;
13
+ constructor(config: AppAdapterConfig, cwd: string);
14
+ logFile(): string;
15
+ start(): Promise<void>;
16
+ stop(): Promise<void>;
17
+ kill(): Promise<void>;
18
+ isRunning(): Promise<boolean>;
19
+ private sendSignalToChildren;
20
+ }
21
+ //# sourceMappingURL=ConfigAdapter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ConfigAdapter.d.ts","sourceRoot":"","sources":["../../src/adapters/ConfigAdapter.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAElD,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,qBAAa,aAAc,YAAW,UAAU;IAC9C,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAmB;IAC1C,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAS;gBAEjB,MAAM,EAAE,gBAAgB,EAAE,GAAG,EAAE,MAAM;IAMjD,OAAO,IAAI,MAAM;IAIX,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IA6DtB,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAWrB,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAWrB,SAAS,IAAI,OAAO,CAAC,OAAO,CAAC;IAYnC,OAAO,CAAC,oBAAoB;CAK7B"}
@@ -0,0 +1,114 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ConfigAdapter = void 0;
4
+ const node_child_process_1 = require("node:child_process");
5
+ const node_fs_1 = require("node:fs");
6
+ const node_path_1 = require("node:path");
7
+ class ConfigAdapter {
8
+ name;
9
+ config;
10
+ cwd;
11
+ constructor(config, cwd) {
12
+ this.name = config.name;
13
+ this.config = config;
14
+ this.cwd = cwd;
15
+ }
16
+ logFile() {
17
+ return (0, node_path_1.join)(this.cwd, `.claude-swarm-${this.name}.log`);
18
+ }
19
+ async start() {
20
+ const logPath = this.logFile();
21
+ const logStream = (0, node_fs_1.createWriteStream)(logPath, { flags: "a" });
22
+ if (!this.config.readyPattern) {
23
+ const proc = (0, node_child_process_1.spawn)(this.config.start, [], {
24
+ cwd: this.cwd,
25
+ stdio: ["ignore", "pipe", "pipe"],
26
+ detached: true,
27
+ shell: true,
28
+ });
29
+ proc.stdout?.pipe(logStream);
30
+ proc.stderr?.pipe(logStream);
31
+ proc.unref();
32
+ return;
33
+ }
34
+ const pattern = new RegExp(this.config.readyPattern);
35
+ const timeoutMs = 120000;
36
+ await new Promise((resolve, reject) => {
37
+ const proc = (0, node_child_process_1.spawn)(this.config.start, [], {
38
+ cwd: this.cwd,
39
+ stdio: ["ignore", "pipe", "pipe"],
40
+ detached: true,
41
+ shell: true,
42
+ });
43
+ proc.stdout?.pipe(logStream, { end: false });
44
+ proc.stderr?.pipe(logStream, { end: false });
45
+ let settled = false;
46
+ const finish = (err) => {
47
+ if (settled)
48
+ return;
49
+ settled = true;
50
+ clearTimeout(timer);
51
+ proc.unref();
52
+ if (err) {
53
+ reject(err);
54
+ }
55
+ else {
56
+ resolve();
57
+ }
58
+ };
59
+ const checkOutput = (data) => {
60
+ if (pattern.test(data.toString())) {
61
+ finish();
62
+ }
63
+ };
64
+ proc.stdout?.on("data", checkOutput);
65
+ proc.stderr?.on("data", checkOutput);
66
+ proc.on("error", (err) => finish(err));
67
+ const timer = setTimeout(() => finish(new Error(`${this.name} did not start within ${timeoutMs}ms`)), timeoutMs);
68
+ });
69
+ }
70
+ async stop() {
71
+ if (this.config.stop.startsWith("signal:")) {
72
+ const signal = this.config.stop.replace("signal:", "");
73
+ this.sendSignalToChildren(signal);
74
+ }
75
+ else {
76
+ try {
77
+ (0, node_child_process_1.execSync)(this.config.stop, { cwd: this.cwd, stdio: "pipe" });
78
+ }
79
+ catch { }
80
+ }
81
+ }
82
+ async kill() {
83
+ if (this.config.kill.startsWith("signal:")) {
84
+ const signal = this.config.kill.replace("signal:", "");
85
+ this.sendSignalToChildren(signal);
86
+ }
87
+ else {
88
+ try {
89
+ (0, node_child_process_1.execSync)(this.config.kill, { cwd: this.cwd, stdio: "pipe" });
90
+ }
91
+ catch { }
92
+ }
93
+ }
94
+ async isRunning() {
95
+ try {
96
+ const result = (0, node_child_process_1.execSync)(`pgrep -f "${this.config.start}" 2>/dev/null`, {
97
+ encoding: "utf-8",
98
+ stdio: "pipe",
99
+ }).trim();
100
+ return result !== "";
101
+ }
102
+ catch {
103
+ return false;
104
+ }
105
+ }
106
+ sendSignalToChildren(signal) {
107
+ try {
108
+ (0, node_child_process_1.execSync)(`pkill -${signal} -f "${this.config.start}" 2>/dev/null`, { stdio: "pipe" });
109
+ }
110
+ catch { }
111
+ }
112
+ }
113
+ exports.ConfigAdapter = ConfigAdapter;
114
+ //# sourceMappingURL=ConfigAdapter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ConfigAdapter.js","sourceRoot":"","sources":["../../src/adapters/ConfigAdapter.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,15 @@
1
+ import type { AppAdapter } from "./AppAdapter.js";
2
+ export declare abstract class DevServerAdapter implements AppAdapter {
3
+ abstract readonly name: string;
4
+ protected readonly cwd: string;
5
+ protected readonly port: number;
6
+ protected abstract readonly startArgs: string[];
7
+ protected abstract readonly processPattern: string;
8
+ constructor(cwd: string, port: number);
9
+ start(): Promise<void>;
10
+ stop(): Promise<void>;
11
+ kill(): Promise<void>;
12
+ isRunning(): Promise<boolean>;
13
+ logFile(): string | null;
14
+ }
15
+ //# sourceMappingURL=DevServerAdapter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"DevServerAdapter.d.ts","sourceRoot":"","sources":["../../src/adapters/DevServerAdapter.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAElD,8BAAsB,gBAAiB,YAAW,UAAU;IAC1D,QAAQ,CAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IAC/B,SAAS,CAAC,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IAC/B,SAAS,CAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IAChC,SAAS,CAAC,QAAQ,CAAC,QAAQ,CAAC,SAAS,EAAE,MAAM,EAAE,CAAC;IAChD,SAAS,CAAC,QAAQ,CAAC,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;gBAEvC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM;IAK/B,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAWtB,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAMrB,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAMrB,SAAS,IAAI,OAAO,CAAC,OAAO,CAAC;IAYnC,OAAO,IAAI,MAAM,GAAG,IAAI;CAGzB"}
@@ -0,0 +1,84 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.DevServerAdapter = void 0;
37
+ const node_child_process_1 = require("node:child_process");
38
+ class DevServerAdapter {
39
+ cwd;
40
+ port;
41
+ constructor(cwd, port) {
42
+ this.cwd = cwd;
43
+ this.port = port;
44
+ }
45
+ async start() {
46
+ const { spawn } = await Promise.resolve().then(() => __importStar(require("node:child_process")));
47
+ const [cmd, ...args] = this.startArgs;
48
+ const proc = spawn(cmd, args, {
49
+ cwd: this.cwd,
50
+ stdio: "ignore",
51
+ detached: true,
52
+ });
53
+ proc.unref();
54
+ }
55
+ async stop() {
56
+ try {
57
+ (0, node_child_process_1.execSync)(`pkill -f "${this.processPattern}" 2>/dev/null`, { stdio: "pipe" });
58
+ }
59
+ catch { }
60
+ }
61
+ async kill() {
62
+ try {
63
+ (0, node_child_process_1.execSync)(`pkill -9 -f "${this.processPattern}" 2>/dev/null`, { stdio: "pipe" });
64
+ }
65
+ catch { }
66
+ }
67
+ async isRunning() {
68
+ try {
69
+ const result = (0, node_child_process_1.execSync)(`lsof -i :${this.port} -sTCP:LISTEN 2>/dev/null | grep -c LISTEN`, {
70
+ encoding: "utf-8",
71
+ stdio: "pipe",
72
+ }).trim();
73
+ return Number.parseInt(result, 10) > 0;
74
+ }
75
+ catch {
76
+ return false;
77
+ }
78
+ }
79
+ logFile() {
80
+ return null;
81
+ }
82
+ }
83
+ exports.DevServerAdapter = DevServerAdapter;
84
+ //# sourceMappingURL=DevServerAdapter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"DevServerAdapter.js","sourceRoot":"","sources":["../../src/adapters/DevServerAdapter.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,2DAA8C;AAG9C,MAAsB,gBAAgB;IAEjB,GAAG,CAAS;IACZ,IAAI,CAAS;IAIhC,YAAY,GAAW,EAAE,IAAY;QACnC,IAAI,CAAC,GAAG,GAAG,GAAG,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;IACnB,CAAC;IAED,KAAK,CAAC,KAAK;QACT,MAAM,EAAE,KAAK,EAAE,GAAG,wDAAa,oBAAoB,GAAC,CAAC;QACrD,MAAM,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,GAAG,IAAI,CAAC,SAAS,CAAC;QACtC,MAAM,IAAI,GAAG,KAAK,CAAC,GAAG,EAAE,IAAI,EAAE;YAC5B,GAAG,EAAE,IAAI,CAAC,GAAG;YACb,KAAK,EAAE,QAAQ;YACf,QAAQ,EAAE,IAAI;SACf,CAAC,CAAC;QACH,IAAI,CAAC,KAAK,EAAE,CAAC;IACf,CAAC;IAED,KAAK,CAAC,IAAI;QACR,IAAI,CAAC;YACH,IAAA,6BAAQ,EAAC,aAAa,IAAI,CAAC,cAAc,eAAe,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC,CAAC;QAC/E,CAAC;QAAC,MAAM,CAAC,CAAA,CAAC;IACZ,CAAC;IAED,KAAK,CAAC,IAAI;QACR,IAAI,CAAC;YACH,IAAA,6BAAQ,EAAC,gBAAgB,IAAI,CAAC,cAAc,eAAe,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC,CAAC;QAClF,CAAC;QAAC,MAAM,CAAC,CAAA,CAAC;IACZ,CAAC;IAED,KAAK,CAAC,SAAS;QACb,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,IAAA,6BAAQ,EAAC,YAAY,IAAI,CAAC,IAAI,4CAA4C,EAAE;gBACzF,QAAQ,EAAE,OAAO;gBACjB,KAAK,EAAE,MAAM;aACd,CAAC,CAAC,IAAI,EAAE,CAAC;YACV,OAAO,MAAM,CAAC,QAAQ,CAAC,MAAM,EAAE,EAAE,CAAC,GAAG,CAAC,CAAC;QACzC,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,KAAK,CAAC;QACf,CAAC;IACH,CAAC;IAED,OAAO;QACL,OAAO,IAAI,CAAC;IACd,CAAC;CACF;AAlDD,4CAkDC"}
@@ -0,0 +1,8 @@
1
+ import { DevServerAdapter } from "./DevServerAdapter.js";
2
+ export declare class NestAdapter extends DevServerAdapter {
3
+ readonly name = "nest";
4
+ protected readonly startArgs: string[];
5
+ protected readonly processPattern = "nest.* start";
6
+ constructor(cwd: string, port?: number);
7
+ }
8
+ //# sourceMappingURL=NestAdapter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"NestAdapter.d.ts","sourceRoot":"","sources":["../../src/adapters/NestAdapter.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AAEzD,qBAAa,WAAY,SAAQ,gBAAgB;IAC/C,QAAQ,CAAC,IAAI,UAAU;IACvB,SAAS,CAAC,QAAQ,CAAC,SAAS,WAAuC;IACnE,SAAS,CAAC,QAAQ,CAAC,cAAc,kBAAkB;gBAEvC,GAAG,EAAE,MAAM,EAAE,IAAI,SAAO;CAGrC"}
@@ -0,0 +1,14 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.NestAdapter = void 0;
4
+ const DevServerAdapter_js_1 = require("./DevServerAdapter.js");
5
+ class NestAdapter extends DevServerAdapter_js_1.DevServerAdapter {
6
+ name = "nest";
7
+ startArgs = ["npx", "nest", "start", "--watch"];
8
+ processPattern = "nest.* start";
9
+ constructor(cwd, port = 3000) {
10
+ super(cwd, port);
11
+ }
12
+ }
13
+ exports.NestAdapter = NestAdapter;
14
+ //# sourceMappingURL=NestAdapter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"NestAdapter.js","sourceRoot":"","sources":["../../src/adapters/NestAdapter.ts"],"names":[],"mappings":";;;AAAA,+DAAyD;AAEzD,MAAa,WAAY,SAAQ,sCAAgB;IACtC,IAAI,GAAG,MAAM,CAAC;IACJ,SAAS,GAAG,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,SAAS,CAAC,CAAC;IAChD,cAAc,GAAG,cAAc,CAAC;IAEnD,YAAY,GAAW,EAAE,IAAI,GAAG,IAAI;QAClC,KAAK,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;IACnB,CAAC;CACF;AARD,kCAQC"}
@@ -0,0 +1,8 @@
1
+ import { DevServerAdapter } from "./DevServerAdapter.js";
2
+ export declare class NextAdapter extends DevServerAdapter {
3
+ readonly name = "next";
4
+ protected readonly startArgs: string[];
5
+ protected readonly processPattern = "next dev";
6
+ constructor(cwd: string, port?: number);
7
+ }
8
+ //# sourceMappingURL=NextAdapter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"NextAdapter.d.ts","sourceRoot":"","sources":["../../src/adapters/NextAdapter.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AAEzD,qBAAa,WAAY,SAAQ,gBAAgB;IAC/C,QAAQ,CAAC,IAAI,UAAU;IACvB,SAAS,CAAC,QAAQ,CAAC,SAAS,WAA0B;IACtD,SAAS,CAAC,QAAQ,CAAC,cAAc,cAAc;gBAEnC,GAAG,EAAE,MAAM,EAAE,IAAI,SAAO;CAGrC"}
@@ -0,0 +1,14 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.NextAdapter = void 0;
4
+ const DevServerAdapter_js_1 = require("./DevServerAdapter.js");
5
+ class NextAdapter extends DevServerAdapter_js_1.DevServerAdapter {
6
+ name = "next";
7
+ startArgs = ["npx", "next", "dev"];
8
+ processPattern = "next dev";
9
+ constructor(cwd, port = 3000) {
10
+ super(cwd, port);
11
+ }
12
+ }
13
+ exports.NextAdapter = NextAdapter;
14
+ //# sourceMappingURL=NextAdapter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"NextAdapter.js","sourceRoot":"","sources":["../../src/adapters/NextAdapter.ts"],"names":[],"mappings":";;;AAAA,+DAAyD;AAEzD,MAAa,WAAY,SAAQ,sCAAgB;IACtC,IAAI,GAAG,MAAM,CAAC;IACJ,SAAS,GAAG,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,CAAC,CAAC;IACnC,cAAc,GAAG,UAAU,CAAC;IAE/C,YAAY,GAAW,EAAE,IAAI,GAAG,IAAI;QAClC,KAAK,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;IACnB,CAAC;CACF;AARD,kCAQC"}
@@ -0,0 +1,10 @@
1
+ import type { AppAdapter } from "./AppAdapter.js";
2
+ export declare class NullAdapter implements AppAdapter {
3
+ readonly name = "null";
4
+ start(): Promise<void>;
5
+ stop(): Promise<void>;
6
+ kill(): Promise<void>;
7
+ isRunning(): Promise<boolean>;
8
+ logFile(): string | null;
9
+ }
10
+ //# sourceMappingURL=NullAdapter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"NullAdapter.d.ts","sourceRoot":"","sources":["../../src/adapters/NullAdapter.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAElD,qBAAa,WAAY,YAAW,UAAU;IAC5C,QAAQ,CAAC,IAAI,UAAU;IAEjB,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAEtB,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAErB,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAErB,SAAS,IAAI,OAAO,CAAC,OAAO,CAAC;IAInC,OAAO,IAAI,MAAM,GAAG,IAAI;CAGzB"}
@@ -0,0 +1,17 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.NullAdapter = void 0;
4
+ class NullAdapter {
5
+ name = "null";
6
+ async start() { }
7
+ async stop() { }
8
+ async kill() { }
9
+ async isRunning() {
10
+ return false;
11
+ }
12
+ logFile() {
13
+ return null;
14
+ }
15
+ }
16
+ exports.NullAdapter = NullAdapter;
17
+ //# sourceMappingURL=NullAdapter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"NullAdapter.js","sourceRoot":"","sources":["../../src/adapters/NullAdapter.ts"],"names":[],"mappings":";;;AAEA,MAAa,WAAW;IACb,IAAI,GAAG,MAAM,CAAC;IAEvB,KAAK,CAAC,KAAK,KAAmB,CAAC;IAE/B,KAAK,CAAC,IAAI,KAAmB,CAAC;IAE9B,KAAK,CAAC,IAAI,KAAmB,CAAC;IAE9B,KAAK,CAAC,SAAS;QACb,OAAO,KAAK,CAAC;IACf,CAAC;IAED,OAAO;QACL,OAAO,IAAI,CAAC;IACd,CAAC;CACF;AAhBD,kCAgBC"}
@@ -0,0 +1,21 @@
1
+ import type { AppAdapter } from "./AppAdapter.js";
2
+ export interface ProcessAdapterConfig {
3
+ name: string;
4
+ command: string;
5
+ args: string[];
6
+ cwd: string;
7
+ readyPattern: RegExp;
8
+ readyTimeoutMs?: number;
9
+ }
10
+ export declare class ProcessAdapter implements AppAdapter {
11
+ readonly name: string;
12
+ private process;
13
+ private readonly config;
14
+ constructor(config: ProcessAdapterConfig);
15
+ start(): Promise<void>;
16
+ stop(): Promise<void>;
17
+ kill(): Promise<void>;
18
+ isRunning(): Promise<boolean>;
19
+ logFile(): string | null;
20
+ }
21
+ //# sourceMappingURL=ProcessAdapter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ProcessAdapter.d.ts","sourceRoot":"","sources":["../../src/adapters/ProcessAdapter.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAElD,MAAM,WAAW,oBAAoB;IACnC,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,GAAG,EAAE,MAAM,CAAC;IACZ,YAAY,EAAE,MAAM,CAAC;IACrB,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAED,qBAAa,cAAe,YAAW,UAAU;IAC/C,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,OAAO,CAAC,OAAO,CAA6B;IAC5C,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAuB;gBAElC,MAAM,EAAE,oBAAoB;IAKlC,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IA+BtB,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAOrB,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAOrB,SAAS,IAAI,OAAO,CAAC,OAAO,CAAC;IAgBnC,OAAO,IAAI,MAAM,GAAG,IAAI;CAGzB"}