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 +217 -0
- package/dist/cli/commands.d.ts +7 -0
- package/dist/cli/commands.js +192 -0
- package/dist/cli/commands.js.map +1 -0
- package/dist/core/config-store.d.ts +11 -0
- package/dist/core/config-store.js +101 -0
- package/dist/core/config-store.js.map +1 -0
- package/dist/core/git-manager.d.ts +25 -0
- package/dist/core/git-manager.js +83 -0
- package/dist/core/git-manager.js.map +1 -0
- package/dist/core/log-store.d.ts +14 -0
- package/dist/core/log-store.js +32 -0
- package/dist/core/log-store.js.map +1 -0
- package/dist/core/port-utils.d.ts +6 -0
- package/dist/core/port-utils.js +23 -0
- package/dist/core/port-utils.js.map +1 -0
- package/dist/core/process-manager.d.ts +29 -0
- package/dist/core/process-manager.js +172 -0
- package/dist/core/process-manager.js.map +1 -0
- package/dist/core/types.d.ts +44 -0
- package/dist/core/types.js +2 -0
- package/dist/core/types.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +26 -0
- package/dist/index.js.map +1 -0
- package/dist/mcp/server.d.ts +19 -0
- package/dist/mcp/server.js +206 -0
- package/dist/mcp/server.js.map +1 -0
- package/dist/tui/app.d.ts +20 -0
- package/dist/tui/app.js +135 -0
- package/dist/tui/app.js.map +1 -0
- package/dist/web/client/assets/index-CvX1Rx-e.css +1 -0
- package/dist/web/client/assets/index-Dy5kcoI8.js +11 -0
- package/dist/web/client/index.html +13 -0
- package/dist/web/server.d.ts +15 -0
- package/dist/web/server.js +321 -0
- package/dist/web/server.js.map +1 -0
- package/package.json +52 -0
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,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 {};
|