nomoreide 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.
package/README.md ADDED
@@ -0,0 +1,217 @@
1
+ # NoMoreIDE
2
+
3
+ NoMoreIDE is an AI-native terminal workbench for the post-IDE development loop. It gives coding agents and humans a shared local control surface for services, ports, logs, Git review, and MCP workflows.
4
+
5
+ ## Status
6
+
7
+ This is an MVP with a working MCP server, core process manager, terminal UI, React web UI, and safe Git review tools.
8
+
9
+ ## Install
10
+
11
+ ```bash
12
+ npm install -g nomoreide
13
+ ```
14
+
15
+ Or from a local checkout:
16
+
17
+ ```bash
18
+ npm install
19
+ npm run build
20
+ ```
21
+
22
+ ## Run
23
+
24
+ Start the MCP server:
25
+
26
+ ```bash
27
+ nomoreide
28
+ ```
29
+
30
+ From a local checkout:
31
+
32
+ ```bash
33
+ npm run dev
34
+ ```
35
+
36
+ Start the terminal UI:
37
+
38
+ ```bash
39
+ npm run dev -- tui
40
+ ```
41
+
42
+ Start the local web UI:
43
+
44
+ ```bash
45
+ npm run dev -- web
46
+ ```
47
+
48
+ The web UI listens on `http://127.0.0.1:4317` by default. Use another port with:
49
+
50
+ ```bash
51
+ npm run dev -- web --port=4320
52
+ ```
53
+
54
+ ## CLI
55
+
56
+ Register a service:
57
+
58
+ ```bash
59
+ npm run dev -- add service backend --command "npm run dev" --cwd /absolute/path/to/backend --port 3001
60
+ ```
61
+
62
+ Register a bundle:
63
+
64
+ ```bash
65
+ npm run dev -- add bundle full-stack db backend frontend
66
+ ```
67
+
68
+ List registered services and bundles:
69
+
70
+ ```bash
71
+ npm run dev -- list
72
+ ```
73
+
74
+ Start, stop, or restart a registered service:
75
+
76
+ ```bash
77
+ npm run dev -- start backend
78
+ npm run dev -- stop backend
79
+ npm run dev -- restart backend
80
+ ```
81
+
82
+ Start or stop a bundle:
83
+
84
+ ```bash
85
+ npm run dev -- start full-stack
86
+ npm run dev -- stop full-stack
87
+ ```
88
+
89
+ Read recent in-memory logs for the current NoMoreIDE process:
90
+
91
+ ```bash
92
+ npm run dev -- logs backend
93
+ ```
94
+
95
+ ## Git
96
+
97
+ NoMoreIDE includes safe Git review commands. It does not expose destructive actions such as hard reset, clean, force push, or branch deletion.
98
+
99
+ Show status:
100
+
101
+ ```bash
102
+ npm run dev -- git status --cwd /absolute/path/to/repo
103
+ ```
104
+
105
+ Register and select Git folders for the web UI:
106
+
107
+ ```bash
108
+ npm run dev -- git add-repo app --path /absolute/path/to/repo
109
+ npm run dev -- git select-repo app
110
+ ```
111
+
112
+ Show unstaged diff:
113
+
114
+ ```bash
115
+ npm run dev -- git diff --cwd /absolute/path/to/repo
116
+ ```
117
+
118
+ Stage or unstage explicit files:
119
+
120
+ ```bash
121
+ npm run dev -- git stage --cwd /absolute/path/to/repo src/index.ts README.md
122
+ npm run dev -- git unstage --cwd /absolute/path/to/repo src/index.ts
123
+ ```
124
+
125
+ Commit staged changes:
126
+
127
+ ```bash
128
+ npm run dev -- git commit --cwd /absolute/path/to/repo --message "feat: add service dashboard"
129
+ ```
130
+
131
+ Show recent commits:
132
+
133
+ ```bash
134
+ npm run dev -- git log --cwd /absolute/path/to/repo
135
+ ```
136
+
137
+ For an MCP client, point a stdio server entry at the built CLI:
138
+
139
+ ```json
140
+ {
141
+ "mcpServers": {
142
+ "nomoreide": {
143
+ "command": "node",
144
+ "args": ["/absolute/path/to/nomoreide/dist/index.js"]
145
+ }
146
+ }
147
+ }
148
+ ```
149
+
150
+ NoMoreIDE stores service definitions in `nomoreide.config.json` in the directory where the server is launched. Logs are written to `.nomoreide/logs/`.
151
+
152
+ ## MCP Tools
153
+
154
+ - `nomoreide_list_services`
155
+ - `nomoreide_register_service`
156
+ - `nomoreide_start_service`
157
+ - `nomoreide_stop_service`
158
+ - `nomoreide_restart_service`
159
+ - `nomoreide_read_logs`
160
+ - `nomoreide_register_bundle`
161
+ - `nomoreide_start_bundle`
162
+ - `nomoreide_stop_bundle`
163
+ - `nomoreide_status`
164
+ - `nomoreide_git_status`
165
+ - `nomoreide_git_diff`
166
+ - `nomoreide_git_staged_diff`
167
+ - `nomoreide_git_log`
168
+ - `nomoreide_git_stage`
169
+ - `nomoreide_git_unstage`
170
+ - `nomoreide_git_commit`
171
+ - `nomoreide_git_register_repository`
172
+ - `nomoreide_git_select_repository`
173
+
174
+ ## Example Service
175
+
176
+ Register a service through MCP with:
177
+
178
+ ```json
179
+ {
180
+ "name": "backend",
181
+ "command": "npm run dev",
182
+ "cwd": "/absolute/path/to/project/backend",
183
+ "port": 3001,
184
+ "env": {
185
+ "NODE_ENV": "development"
186
+ },
187
+ "description": "API server"
188
+ }
189
+ ```
190
+
191
+ ## Example Bundle
192
+
193
+ ```json
194
+ {
195
+ "name": "full-stack",
196
+ "services": ["db", "backend", "frontend"]
197
+ }
198
+ ```
199
+
200
+ Then call `nomoreide_start_bundle` with:
201
+
202
+ ```json
203
+ {
204
+ "name": "full-stack"
205
+ }
206
+ ```
207
+
208
+ ## Safety Model
209
+
210
+ NoMoreIDE does not scan the whole machine and does not kill unrelated processes. If a registered service port is already occupied, NoMoreIDE reports the conflict instead of terminating the process.
211
+
212
+ ## Development
213
+
214
+ ```bash
215
+ npm test
216
+ npm run build
217
+ ```
@@ -0,0 +1,7 @@
1
+ export interface CliOptions {
2
+ configPath?: string;
3
+ logDir?: string;
4
+ stdout?: (line: string) => void;
5
+ stderr?: (line: string) => void;
6
+ }
7
+ export declare function runCli(args: string[], options?: CliOptions): Promise<number>;
@@ -0,0 +1,192 @@
1
+ import { resolve } from "node:path";
2
+ import { ConfigStore } from "../core/config-store.js";
3
+ import { GitManager } from "../core/git-manager.js";
4
+ import { LogStore } from "../core/log-store.js";
5
+ import { ProcessManager } from "../core/process-manager.js";
6
+ export async function runCli(args, options = {}) {
7
+ const stdout = options.stdout ?? ((line) => console.log(line));
8
+ const stderr = options.stderr ?? ((line) => console.error(line));
9
+ const configStore = new ConfigStore(options.configPath ?? resolve(process.cwd(), "nomoreide.config.json"));
10
+ const logStore = new LogStore({
11
+ baseDir: options.logDir ?? resolve(process.cwd(), ".nomoreide/logs"),
12
+ });
13
+ const manager = new ProcessManager({ configStore, logStore });
14
+ try {
15
+ const [command, subcommand, ...rest] = args;
16
+ if (command === "git") {
17
+ return await runGitCli(subcommand, rest, stdout, configStore);
18
+ }
19
+ if (command === "add" && subcommand === "service") {
20
+ const name = rest[0];
21
+ const flags = parseFlags(rest.slice(1));
22
+ if (!name) {
23
+ throw new UsageError("service name is required");
24
+ }
25
+ if (!flags.command) {
26
+ throw new UsageError("--command is required");
27
+ }
28
+ await configStore.registerService({
29
+ name,
30
+ command: flags.command,
31
+ cwd: flags.cwd ?? process.cwd(),
32
+ port: flags.port ? Number(flags.port) : undefined,
33
+ description: flags.description,
34
+ });
35
+ stdout(`Registered service ${name}`);
36
+ return 0;
37
+ }
38
+ if (command === "add" && subcommand === "bundle") {
39
+ const [name, ...services] = rest;
40
+ if (!name) {
41
+ throw new UsageError("bundle name is required");
42
+ }
43
+ if (services.length === 0) {
44
+ throw new UsageError("at least one service is required");
45
+ }
46
+ await configStore.registerBundle({ name, services });
47
+ stdout(`Registered bundle ${name}`);
48
+ return 0;
49
+ }
50
+ if (command === "list") {
51
+ const config = await configStore.load();
52
+ stdout("Services");
53
+ for (const service of config.services) {
54
+ stdout(`${service.name}\t${service.port ?? "-"}\t${service.command}\t${service.cwd}`);
55
+ }
56
+ stdout("Bundles");
57
+ for (const bundle of config.bundles) {
58
+ stdout(`${bundle.name}\t${bundle.services.join(",")}`);
59
+ }
60
+ return 0;
61
+ }
62
+ if (command === "logs") {
63
+ const name = subcommand;
64
+ if (!name) {
65
+ throw new UsageError("service name is required");
66
+ }
67
+ for (const entry of logStore.read(name, 200)) {
68
+ stdout(`${entry.timestamp}\t${entry.stream}\t${entry.text}`);
69
+ }
70
+ return 0;
71
+ }
72
+ if (["start", "stop", "restart"].includes(command ?? "")) {
73
+ const name = subcommand;
74
+ if (!name) {
75
+ throw new UsageError("service or bundle name is required");
76
+ }
77
+ const config = await configStore.load();
78
+ const isBundle = config.bundles.some((bundle) => bundle.name === name);
79
+ const result = command === "start"
80
+ ? isBundle
81
+ ? await manager.startBundle(name)
82
+ : await manager.startService(name)
83
+ : command === "stop"
84
+ ? isBundle
85
+ ? await manager.stopBundle(name)
86
+ : await manager.stopService(name)
87
+ : await manager.restartService(name);
88
+ stdout(JSON.stringify(result, null, 2));
89
+ return 0;
90
+ }
91
+ throw new UsageError("Usage: nomoreide [mcp|tui|web|list|logs|start|stop|restart|add]");
92
+ }
93
+ catch (error) {
94
+ stderr(error instanceof Error ? error.message : String(error));
95
+ return error instanceof UsageError ? 1 : 2;
96
+ }
97
+ }
98
+ class UsageError extends Error {
99
+ }
100
+ async function runGitCli(subcommand, args, stdout, configStore) {
101
+ const flags = parseFlags(args);
102
+ const cwd = flags.cwd ?? process.cwd();
103
+ const positional = args.filter((arg, index) => {
104
+ if (!arg.startsWith("--")) {
105
+ const previous = args[index - 1];
106
+ return !(previous?.startsWith("--") && !previous.includes("="));
107
+ }
108
+ return false;
109
+ });
110
+ const git = new GitManager(cwd);
111
+ if (subcommand === "status") {
112
+ const status = await git.status();
113
+ stdout(`Branch\t${status.branch || "(detached)"}`);
114
+ for (const file of status.files) {
115
+ stdout(`${file.index}${file.workingTree}\t${file.path}`);
116
+ }
117
+ return 0;
118
+ }
119
+ if (subcommand === "add-repo") {
120
+ const name = positional[0];
121
+ if (!name) {
122
+ throw new UsageError("repository name is required");
123
+ }
124
+ if (!flags.path) {
125
+ throw new UsageError("--path is required");
126
+ }
127
+ await configStore.registerGitRepository({ name, path: flags.path });
128
+ stdout(`Registered Git repository ${name}`);
129
+ return 0;
130
+ }
131
+ if (subcommand === "select-repo") {
132
+ const name = positional[0];
133
+ if (!name) {
134
+ throw new UsageError("repository name is required");
135
+ }
136
+ await configStore.selectGitRepository(name);
137
+ stdout(`Selected Git repository ${name}`);
138
+ return 0;
139
+ }
140
+ if (subcommand === "diff") {
141
+ stdout(await git.diff(positional[0]));
142
+ return 0;
143
+ }
144
+ if (subcommand === "staged-diff") {
145
+ stdout(await git.stagedDiff(positional[0]));
146
+ return 0;
147
+ }
148
+ if (subcommand === "log") {
149
+ for (const entry of await git.log(flags.limit ? Number(flags.limit) : 10)) {
150
+ stdout(`${entry.hash.slice(0, 8)}\t${entry.subject}`);
151
+ }
152
+ return 0;
153
+ }
154
+ if (subcommand === "stage") {
155
+ await git.stage(positional);
156
+ stdout(`Staged ${positional.join(", ")}`);
157
+ return 0;
158
+ }
159
+ if (subcommand === "unstage") {
160
+ await git.unstage(positional);
161
+ stdout(`Unstaged ${positional.join(", ")}`);
162
+ return 0;
163
+ }
164
+ if (subcommand === "commit") {
165
+ const message = flags.message;
166
+ if (!message) {
167
+ throw new UsageError("--message is required");
168
+ }
169
+ stdout(await git.commit(message));
170
+ return 0;
171
+ }
172
+ throw new UsageError("Usage: nomoreide git [status|diff|staged-diff|log|stage|unstage|commit]");
173
+ }
174
+ function parseFlags(args) {
175
+ const flags = {};
176
+ for (let index = 0; index < args.length; index += 1) {
177
+ const arg = args[index];
178
+ if (!arg?.startsWith("--")) {
179
+ continue;
180
+ }
181
+ const [key, inlineValue] = arg.slice(2).split("=", 2);
182
+ flags[toCamelCase(key)] = inlineValue ?? args[index + 1];
183
+ if (!inlineValue) {
184
+ index += 1;
185
+ }
186
+ }
187
+ return flags;
188
+ }
189
+ function toCamelCase(input) {
190
+ return input.replace(/-([a-z])/g, (_match, letter) => letter.toUpperCase());
191
+ }
192
+ //# sourceMappingURL=commands.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"commands.js","sourceRoot":"","sources":["../../src/cli/commands.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,11 @@
1
+ import type { BundleDefinition, NoMoreIdeConfig, GitRepositoryDefinition, ServiceDefinition } from "./types.js";
2
+ export declare class ConfigStore {
3
+ private readonly configPath;
4
+ constructor(configPath?: string);
5
+ load(): Promise<NoMoreIdeConfig>;
6
+ save(config: NoMoreIdeConfig): Promise<void>;
7
+ registerService(service: ServiceDefinition): Promise<NoMoreIdeConfig>;
8
+ registerBundle(bundle: BundleDefinition): Promise<NoMoreIdeConfig>;
9
+ registerGitRepository(repository: GitRepositoryDefinition): Promise<NoMoreIdeConfig>;
10
+ selectGitRepository(name: string): Promise<NoMoreIdeConfig>;
11
+ }
@@ -0,0 +1,101 @@
1
+ import { mkdir, readFile, writeFile } from "node:fs/promises";
2
+ import { dirname } from "node:path";
3
+ import { z } from "zod";
4
+ const serviceSchema = z.object({
5
+ name: z.string().min(1),
6
+ command: z.string().min(1),
7
+ cwd: z.string().min(1),
8
+ port: z.number().int().positive().max(65535).optional(),
9
+ env: z.record(z.string()).optional(),
10
+ description: z.string().optional(),
11
+ });
12
+ const bundleSchema = z.object({
13
+ name: z.string().min(1),
14
+ services: z.array(z.string().min(1)),
15
+ });
16
+ const gitRepositorySchema = z.object({
17
+ name: z.string().min(1),
18
+ path: z.string().min(1),
19
+ });
20
+ const configSchema = z.object({
21
+ version: z.literal(1),
22
+ services: z.array(serviceSchema),
23
+ bundles: z.array(bundleSchema),
24
+ gitRepositories: z.array(gitRepositorySchema).default([]),
25
+ selectedGitRepository: z.string().min(1).optional(),
26
+ });
27
+ const defaultConfig = {
28
+ version: 1,
29
+ services: [],
30
+ bundles: [],
31
+ gitRepositories: [],
32
+ };
33
+ export class ConfigStore {
34
+ configPath;
35
+ constructor(configPath = "nomoreide.config.json") {
36
+ this.configPath = configPath;
37
+ }
38
+ async load() {
39
+ try {
40
+ const raw = await readFile(this.configPath, "utf8");
41
+ return configSchema.parse(JSON.parse(raw));
42
+ }
43
+ catch (error) {
44
+ if (isMissingFileError(error)) {
45
+ return structuredClone(defaultConfig);
46
+ }
47
+ throw error;
48
+ }
49
+ }
50
+ async save(config) {
51
+ const parsed = configSchema.parse(config);
52
+ await mkdir(dirname(this.configPath), { recursive: true });
53
+ await writeFile(this.configPath, `${JSON.stringify(parsed, null, 2)}\n`);
54
+ }
55
+ async registerService(service) {
56
+ const parsedService = serviceSchema.parse(service);
57
+ const config = await this.load();
58
+ config.services = [
59
+ ...config.services.filter((item) => item.name !== parsedService.name),
60
+ parsedService,
61
+ ];
62
+ await this.save(config);
63
+ return config;
64
+ }
65
+ async registerBundle(bundle) {
66
+ const parsedBundle = bundleSchema.parse(bundle);
67
+ const config = await this.load();
68
+ config.bundles = [
69
+ ...config.bundles.filter((item) => item.name !== parsedBundle.name),
70
+ parsedBundle,
71
+ ];
72
+ await this.save(config);
73
+ return config;
74
+ }
75
+ async registerGitRepository(repository) {
76
+ const parsedRepository = gitRepositorySchema.parse(repository);
77
+ const config = await this.load();
78
+ config.gitRepositories = [
79
+ ...config.gitRepositories.filter((item) => item.name !== parsedRepository.name),
80
+ parsedRepository,
81
+ ];
82
+ config.selectedGitRepository ??= parsedRepository.name;
83
+ await this.save(config);
84
+ return config;
85
+ }
86
+ async selectGitRepository(name) {
87
+ const config = await this.load();
88
+ if (!config.gitRepositories.some((repository) => repository.name === name)) {
89
+ throw new Error(`Git repository "${name}" is not registered.`);
90
+ }
91
+ config.selectedGitRepository = name;
92
+ await this.save(config);
93
+ return config;
94
+ }
95
+ }
96
+ function isMissingFileError(error) {
97
+ return (error instanceof Error &&
98
+ "code" in error &&
99
+ error.code === "ENOENT");
100
+ }
101
+ //# sourceMappingURL=config-store.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config-store.js","sourceRoot":"","sources":["../../src/core/config-store.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,25 @@
1
+ export interface GitFileStatus {
2
+ path: string;
3
+ index: string;
4
+ workingTree: string;
5
+ }
6
+ export interface GitStatus {
7
+ branch: string;
8
+ files: GitFileStatus[];
9
+ }
10
+ export interface GitLogEntry {
11
+ hash: string;
12
+ subject: string;
13
+ }
14
+ export declare class GitManager {
15
+ private readonly cwd;
16
+ constructor(cwd?: string);
17
+ status(): Promise<GitStatus>;
18
+ diff(path?: string): Promise<string>;
19
+ stagedDiff(path?: string): Promise<string>;
20
+ log(limit?: number): Promise<GitLogEntry[]>;
21
+ stage(paths: string[]): Promise<string>;
22
+ unstage(paths: string[]): Promise<string>;
23
+ commit(message: string): Promise<string>;
24
+ private git;
25
+ }
@@ -0,0 +1,83 @@
1
+ import { execFile } from "node:child_process";
2
+ import { promisify } from "node:util";
3
+ const execFileAsync = promisify(execFile);
4
+ export class GitManager {
5
+ cwd;
6
+ constructor(cwd = process.cwd()) {
7
+ this.cwd = cwd;
8
+ }
9
+ async status() {
10
+ const [branch, porcelain] = await Promise.all([
11
+ this.git(["branch", "--show-current"]),
12
+ this.git(["status", "--porcelain=v1"]),
13
+ ]);
14
+ return {
15
+ branch: branch.trim(),
16
+ files: porcelain
17
+ .split("\n")
18
+ .filter(Boolean)
19
+ .map((line) => ({
20
+ index: line[0] ?? " ",
21
+ workingTree: line[1] ?? " ",
22
+ path: line.slice(3),
23
+ })),
24
+ };
25
+ }
26
+ async diff(path) {
27
+ return this.git(path ? ["diff", "--", path] : ["diff"]);
28
+ }
29
+ async stagedDiff(path) {
30
+ return this.git(path ? ["diff", "--cached", "--", path] : ["diff", "--cached"]);
31
+ }
32
+ async log(limit = 10) {
33
+ const output = await this.git([
34
+ "log",
35
+ `-${limit}`,
36
+ "--pretty=format:%H%x09%s",
37
+ ]);
38
+ return output
39
+ .split("\n")
40
+ .filter(Boolean)
41
+ .map((line) => {
42
+ const [hash = "", subject = ""] = line.split("\t");
43
+ return { hash, subject };
44
+ });
45
+ }
46
+ async stage(paths) {
47
+ requirePaths(paths);
48
+ return this.git(["add", "--", ...paths]);
49
+ }
50
+ async unstage(paths) {
51
+ requirePaths(paths);
52
+ return this.git(["restore", "--staged", "--", ...paths]);
53
+ }
54
+ async commit(message) {
55
+ if (!message.trim()) {
56
+ throw new Error("commit message is required");
57
+ }
58
+ return this.git(["commit", "-m", message]);
59
+ }
60
+ async git(args) {
61
+ try {
62
+ const { stdout, stderr } = await execFileAsync("git", args, {
63
+ cwd: this.cwd,
64
+ });
65
+ return stdout || stderr;
66
+ }
67
+ catch (error) {
68
+ if (isExecError(error)) {
69
+ throw new Error((error.stderr || error.stdout || error.message).trim());
70
+ }
71
+ throw error;
72
+ }
73
+ }
74
+ }
75
+ function requirePaths(paths) {
76
+ if (paths.length === 0 || paths.some((path) => !path.trim())) {
77
+ throw new Error("at least one file path is required");
78
+ }
79
+ }
80
+ function isExecError(error) {
81
+ return error instanceof Error;
82
+ }
83
+ //# sourceMappingURL=git-manager.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"git-manager.js","sourceRoot":"","sources":["../../src/core/git-manager.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,14 @@
1
+ import type { LogEntry, LogStream } from "./types.js";
2
+ interface LogStoreOptions {
3
+ baseDir?: string;
4
+ maxLinesPerService?: number;
5
+ }
6
+ export declare class LogStore {
7
+ private readonly entriesByService;
8
+ private readonly baseDir;
9
+ private readonly maxLinesPerService;
10
+ constructor(options?: LogStoreOptions);
11
+ append(service: string, stream: LogStream, text: string): Promise<LogEntry>;
12
+ read(service: string, limit?: number): LogEntry[];
13
+ }
14
+ export {};