nomoreide 0.1.20 → 0.1.22
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/core/git-manager.js +4 -0
- package/dist/core/git-manager.js.map +1 -1
- package/dist/web/client/assets/index-BmUyXrPp.css +1 -0
- package/dist/web/client/assets/{index-CylezI98.js → index-DxODKxSd.js} +13 -13
- package/dist/web/client/index.html +2 -2
- package/dist/web/routes/agent-routes.d.ts +3 -0
- package/dist/web/routes/agent-routes.js +40 -0
- package/dist/web/routes/agent-routes.js.map +1 -0
- package/dist/web/routes/context.d.ts +39 -0
- package/dist/web/routes/context.js +48 -0
- package/dist/web/routes/context.js.map +1 -0
- package/dist/web/routes/dashboard-routes.d.ts +3 -0
- package/dist/web/routes/dashboard-routes.js +20 -0
- package/dist/web/routes/dashboard-routes.js.map +1 -0
- package/dist/web/routes/git-routes.d.ts +3 -0
- package/dist/web/routes/git-routes.js +125 -0
- package/dist/web/routes/git-routes.js.map +1 -0
- package/dist/web/routes/index.d.ts +10 -0
- package/dist/web/routes/index.js +20 -0
- package/dist/web/routes/index.js.map +1 -0
- package/dist/web/routes/service-routes.d.ts +3 -0
- package/dist/web/routes/service-routes.js +298 -0
- package/dist/web/routes/service-routes.js.map +1 -0
- package/dist/web/routes/shell-routes.d.ts +3 -0
- package/dist/web/routes/shell-routes.js +34 -0
- package/dist/web/routes/shell-routes.js.map +1 -0
- package/dist/web/server.js +21 -538
- package/dist/web/server.js.map +1 -1
- package/package.json +1 -1
- package/dist/web/client/assets/index-y4GyM_JC.css +0 -1
|
@@ -5,8 +5,8 @@
|
|
|
5
5
|
<link rel="icon" type="image/svg+xml" href="/assets/nomoreide-favicon-Ds7Tgj9p.svg" />
|
|
6
6
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
7
7
|
<title>NoMoreIDE</title>
|
|
8
|
-
<script type="module" crossorigin src="/assets/index-
|
|
9
|
-
<link rel="stylesheet" crossorigin href="/assets/index-
|
|
8
|
+
<script type="module" crossorigin src="/assets/index-DxODKxSd.js"></script>
|
|
9
|
+
<link rel="stylesheet" crossorigin href="/assets/index-BmUyXrPp.css">
|
|
10
10
|
</head>
|
|
11
11
|
<body>
|
|
12
12
|
<div id="root"></div>
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { buildAgentInfo } from "../agent-info.js";
|
|
2
|
+
import { buildUsageInfo } from "../usage-info.js";
|
|
3
|
+
import { sendJson } from "../http-utils.js";
|
|
4
|
+
import { route } from "./context.js";
|
|
5
|
+
/** Agent introspection: identity, token usage, and the live tool-call feed. */
|
|
6
|
+
export const agentRoutes = [
|
|
7
|
+
route("GET", "/api/agent", async ({ response, cwd }) => {
|
|
8
|
+
sendJson(response, { ok: true, agent: await buildAgentInfo(cwd) });
|
|
9
|
+
}),
|
|
10
|
+
route("GET", "/api/agent/usage", async ({ response, cwd }) => {
|
|
11
|
+
sendJson(response, { ok: true, usage: await buildUsageInfo(cwd) });
|
|
12
|
+
}),
|
|
13
|
+
route("GET", "/api/agent/tool-calls", ({ response, url, toolCallStore }) => {
|
|
14
|
+
const limitParam = Number(url.searchParams.get("limit"));
|
|
15
|
+
const limit = Number.isFinite(limitParam) && limitParam > 0 ? Math.min(limitParam, 500) : 100;
|
|
16
|
+
sendJson(response, { ok: true, records: toolCallStore.recent(limit) });
|
|
17
|
+
}),
|
|
18
|
+
route("GET", "/api/agent/tool-calls/stream", ({ request, response, toolCallStore }) => {
|
|
19
|
+
response.writeHead(200, {
|
|
20
|
+
"content-type": "text/event-stream",
|
|
21
|
+
"cache-control": "no-cache, no-transform",
|
|
22
|
+
connection: "keep-alive",
|
|
23
|
+
});
|
|
24
|
+
response.write(`retry: 2000\n\n`);
|
|
25
|
+
for (const record of toolCallStore.recent(50)) {
|
|
26
|
+
response.write(`event: tool-call\ndata: ${JSON.stringify(record)}\n\n`);
|
|
27
|
+
}
|
|
28
|
+
const heartbeat = setInterval(() => {
|
|
29
|
+
response.write(`: ping\n\n`);
|
|
30
|
+
}, 15000);
|
|
31
|
+
const unsubscribe = toolCallStore.subscribe((record) => {
|
|
32
|
+
response.write(`event: tool-call\ndata: ${JSON.stringify(record)}\n\n`);
|
|
33
|
+
});
|
|
34
|
+
request.on("close", () => {
|
|
35
|
+
clearInterval(heartbeat);
|
|
36
|
+
unsubscribe();
|
|
37
|
+
});
|
|
38
|
+
}),
|
|
39
|
+
];
|
|
40
|
+
//# sourceMappingURL=agent-routes.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"agent-routes.js","sourceRoot":"","sources":["../../../src/web/routes/agent-routes.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAClD,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAClD,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAC5C,OAAO,EAAE,KAAK,EAAc,MAAM,cAAc,CAAC;AAEjD,+EAA+E;AAC/E,MAAM,CAAC,MAAM,WAAW,GAAY;IAClC,KAAK,CAAC,KAAK,EAAE,YAAY,EAAE,KAAK,EAAE,EAAE,QAAQ,EAAE,GAAG,EAAE,EAAE,EAAE;QACrD,QAAQ,CAAC,QAAQ,EAAE,EAAE,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,MAAM,cAAc,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IACrE,CAAC,CAAC;IAEF,KAAK,CAAC,KAAK,EAAE,kBAAkB,EAAE,KAAK,EAAE,EAAE,QAAQ,EAAE,GAAG,EAAE,EAAE,EAAE;QAC3D,QAAQ,CAAC,QAAQ,EAAE,EAAE,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,MAAM,cAAc,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IACrE,CAAC,CAAC;IAEF,KAAK,CAAC,KAAK,EAAE,uBAAuB,EAAE,CAAC,EAAE,QAAQ,EAAE,GAAG,EAAE,aAAa,EAAE,EAAE,EAAE;QACzE,MAAM,UAAU,GAAG,MAAM,CAAC,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC;QACzD,MAAM,KAAK,GAAG,MAAM,CAAC,QAAQ,CAAC,UAAU,CAAC,IAAI,UAAU,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,UAAU,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC;QAC9F,QAAQ,CAAC,QAAQ,EAAE,EAAE,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,aAAa,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;IACzE,CAAC,CAAC;IAEF,KAAK,CAAC,KAAK,EAAE,8BAA8B,EAAE,CAAC,EAAE,OAAO,EAAE,QAAQ,EAAE,aAAa,EAAE,EAAE,EAAE;QACpF,QAAQ,CAAC,SAAS,CAAC,GAAG,EAAE;YACtB,cAAc,EAAE,mBAAmB;YACnC,eAAe,EAAE,wBAAwB;YACzC,UAAU,EAAE,YAAY;SACzB,CAAC,CAAC;QACH,QAAQ,CAAC,KAAK,CAAC,iBAAiB,CAAC,CAAC;QAClC,KAAK,MAAM,MAAM,IAAI,aAAa,CAAC,MAAM,CAAC,EAAE,CAAC,EAAE,CAAC;YAC9C,QAAQ,CAAC,KAAK,CAAC,2BAA2B,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;QAC1E,CAAC;QACD,MAAM,SAAS,GAAG,WAAW,CAAC,GAAG,EAAE;YACjC,QAAQ,CAAC,KAAK,CAAC,YAAY,CAAC,CAAC;QAC/B,CAAC,EAAE,KAAK,CAAC,CAAC;QACV,MAAM,WAAW,GAAG,aAAa,CAAC,SAAS,CAAC,CAAC,MAAM,EAAE,EAAE;YACrD,QAAQ,CAAC,KAAK,CAAC,2BAA2B,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;QAC1E,CAAC,CAAC,CAAC;QACH,OAAO,CAAC,EAAE,CAAC,OAAO,EAAE,GAAG,EAAE;YACvB,aAAa,CAAC,SAAS,CAAC,CAAC;YACzB,WAAW,EAAE,CAAC;QAChB,CAAC,CAAC,CAAC;IACL,CAAC,CAAC;CACH,CAAC"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import type { IncomingMessage, ServerResponse } from "node:http";
|
|
2
|
+
import type { ConfigStore } from "../../core/config-store.js";
|
|
3
|
+
import type { LogStore } from "../../core/log-store.js";
|
|
4
|
+
import type { ProcessManager } from "../../core/process-manager.js";
|
|
5
|
+
import type { TimelineStore } from "../../core/timeline-store.js";
|
|
6
|
+
import type { ToolCallStore } from "../../core/tool-call-store.js";
|
|
7
|
+
/** Shared stateful services every route handler receives. */
|
|
8
|
+
export interface RouteServices {
|
|
9
|
+
configStore: ConfigStore;
|
|
10
|
+
cwd: string;
|
|
11
|
+
logStore: LogStore;
|
|
12
|
+
manager: ProcessManager;
|
|
13
|
+
timelineStore: TimelineStore;
|
|
14
|
+
toolCallStore: ToolCallStore;
|
|
15
|
+
}
|
|
16
|
+
/** Per-request context handed to a route handler. */
|
|
17
|
+
export interface RequestContext extends RouteServices {
|
|
18
|
+
request: IncomingMessage;
|
|
19
|
+
response: ServerResponse;
|
|
20
|
+
url: URL;
|
|
21
|
+
params: Record<string, string>;
|
|
22
|
+
}
|
|
23
|
+
export type RouteHandler = (ctx: RequestContext) => Promise<void> | void;
|
|
24
|
+
export interface Route {
|
|
25
|
+
/** Returns matched path params when this route handles the request, else null. */
|
|
26
|
+
match(method: string, url: URL): Record<string, string> | null;
|
|
27
|
+
handle: RouteHandler;
|
|
28
|
+
}
|
|
29
|
+
/** Exact-path route; matches only the listed method(s). */
|
|
30
|
+
export declare function route(method: string | string[], pathname: string, handle: RouteHandler): Route;
|
|
31
|
+
/**
|
|
32
|
+
* Pattern route matched on pathname only — method handling lives in the
|
|
33
|
+
* handler (mirrors the original regex blocks that return their own 405).
|
|
34
|
+
* Capture groups are exposed as params under the supplied names.
|
|
35
|
+
*/
|
|
36
|
+
export declare function patternRoute(pattern: RegExp, paramNames: string[], handle: RouteHandler): Route;
|
|
37
|
+
/** Prefix route (e.g. `/assets/*`), method-filtered. */
|
|
38
|
+
export declare function prefixRoute(method: string | string[], prefix: string, handle: RouteHandler): Route;
|
|
39
|
+
export declare function errorMessage(error: unknown): string;
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/** Exact-path route; matches only the listed method(s). */
|
|
2
|
+
export function route(method, pathname, handle) {
|
|
3
|
+
const methods = Array.isArray(method) ? method : [method];
|
|
4
|
+
return {
|
|
5
|
+
match(requestMethod, url) {
|
|
6
|
+
if (!methods.includes(requestMethod))
|
|
7
|
+
return null;
|
|
8
|
+
return url.pathname === pathname ? {} : null;
|
|
9
|
+
},
|
|
10
|
+
handle,
|
|
11
|
+
};
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Pattern route matched on pathname only — method handling lives in the
|
|
15
|
+
* handler (mirrors the original regex blocks that return their own 405).
|
|
16
|
+
* Capture groups are exposed as params under the supplied names.
|
|
17
|
+
*/
|
|
18
|
+
export function patternRoute(pattern, paramNames, handle) {
|
|
19
|
+
return {
|
|
20
|
+
match(_method, url) {
|
|
21
|
+
const matched = pattern.exec(url.pathname);
|
|
22
|
+
if (!matched)
|
|
23
|
+
return null;
|
|
24
|
+
const params = {};
|
|
25
|
+
matched.slice(1).forEach((value, index) => {
|
|
26
|
+
params[paramNames[index] ?? String(index)] = value;
|
|
27
|
+
});
|
|
28
|
+
return params;
|
|
29
|
+
},
|
|
30
|
+
handle,
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
/** Prefix route (e.g. `/assets/*`), method-filtered. */
|
|
34
|
+
export function prefixRoute(method, prefix, handle) {
|
|
35
|
+
const methods = Array.isArray(method) ? method : [method];
|
|
36
|
+
return {
|
|
37
|
+
match(requestMethod, url) {
|
|
38
|
+
if (!methods.includes(requestMethod))
|
|
39
|
+
return null;
|
|
40
|
+
return url.pathname.startsWith(prefix) ? {} : null;
|
|
41
|
+
},
|
|
42
|
+
handle,
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
export function errorMessage(error) {
|
|
46
|
+
return error instanceof Error ? error.message : String(error);
|
|
47
|
+
}
|
|
48
|
+
//# sourceMappingURL=context.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"context.js","sourceRoot":"","sources":["../../../src/web/routes/context.ts"],"names":[],"mappings":"AAiCA,2DAA2D;AAC3D,MAAM,UAAU,KAAK,CACnB,MAAyB,EACzB,QAAgB,EAChB,MAAoB;IAEpB,MAAM,OAAO,GAAG,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC;IAC1D,OAAO;QACL,KAAK,CAAC,aAAa,EAAE,GAAG;YACtB,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAC;gBAAE,OAAO,IAAI,CAAC;YAClD,OAAO,GAAG,CAAC,QAAQ,KAAK,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC;QAC/C,CAAC;QACD,MAAM;KACP,CAAC;AACJ,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,YAAY,CAC1B,OAAe,EACf,UAAoB,EACpB,MAAoB;IAEpB,OAAO;QACL,KAAK,CAAC,OAAO,EAAE,GAAG;YAChB,MAAM,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;YAC3C,IAAI,CAAC,OAAO;gBAAE,OAAO,IAAI,CAAC;YAC1B,MAAM,MAAM,GAA2B,EAAE,CAAC;YAC1C,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,KAAK,EAAE,KAAK,EAAE,EAAE;gBACxC,MAAM,CAAC,UAAU,CAAC,KAAK,CAAC,IAAI,MAAM,CAAC,KAAK,CAAC,CAAC,GAAG,KAAK,CAAC;YACrD,CAAC,CAAC,CAAC;YACH,OAAO,MAAM,CAAC;QAChB,CAAC;QACD,MAAM;KACP,CAAC;AACJ,CAAC;AAED,wDAAwD;AACxD,MAAM,UAAU,WAAW,CACzB,MAAyB,EACzB,MAAc,EACd,MAAoB;IAEpB,MAAM,OAAO,GAAG,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC;IAC1D,OAAO;QACL,KAAK,CAAC,aAAa,EAAE,GAAG;YACtB,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAC;gBAAE,OAAO,IAAI,CAAC;YAClD,OAAO,GAAG,CAAC,QAAQ,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC;QACrD,CAAC;QACD,MAAM;KACP,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,YAAY,CAAC,KAAc;IACzC,OAAO,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;AAChE,CAAC"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { buildDashboardPayload } from "../dashboard.js";
|
|
2
|
+
import { listDirectories } from "../directories.js";
|
|
3
|
+
import { sendJson } from "../http-utils.js";
|
|
4
|
+
import { route } from "./context.js";
|
|
5
|
+
/** Overview / system endpoints: dashboard, health, status, directory browse. */
|
|
6
|
+
export const dashboardRoutes = [
|
|
7
|
+
route("GET", "/api/dashboard", async ({ response, configStore, cwd, logStore, manager, timelineStore }) => {
|
|
8
|
+
sendJson(response, await buildDashboardPayload({ configStore, cwd, logStore, manager, timelineStore }));
|
|
9
|
+
}),
|
|
10
|
+
route("GET", "/api/health", ({ response }) => {
|
|
11
|
+
sendJson(response, { ok: true, app: "nomoreide" });
|
|
12
|
+
}),
|
|
13
|
+
route("GET", "/api/status", ({ response, manager }) => {
|
|
14
|
+
sendJson(response, { ok: true, status: manager.status() });
|
|
15
|
+
}),
|
|
16
|
+
route("GET", "/api/fs/directories", async ({ response, url, cwd }) => {
|
|
17
|
+
sendJson(response, await listDirectories(url.searchParams.get("path")?.trim() || cwd));
|
|
18
|
+
}),
|
|
19
|
+
];
|
|
20
|
+
//# sourceMappingURL=dashboard-routes.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dashboard-routes.js","sourceRoot":"","sources":["../../../src/web/routes/dashboard-routes.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,qBAAqB,EAAE,MAAM,iBAAiB,CAAC;AACxD,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AACpD,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAC5C,OAAO,EAAE,KAAK,EAAc,MAAM,cAAc,CAAC;AAEjD,gFAAgF;AAChF,MAAM,CAAC,MAAM,eAAe,GAAY;IACtC,KAAK,CAAC,KAAK,EAAE,gBAAgB,EAAE,KAAK,EAAE,EAAE,QAAQ,EAAE,WAAW,EAAE,GAAG,EAAE,QAAQ,EAAE,OAAO,EAAE,aAAa,EAAE,EAAE,EAAE;QACxG,QAAQ,CACN,QAAQ,EACR,MAAM,qBAAqB,CAAC,EAAE,WAAW,EAAE,GAAG,EAAE,QAAQ,EAAE,OAAO,EAAE,aAAa,EAAE,CAAC,CACpF,CAAC;IACJ,CAAC,CAAC;IAEF,KAAK,CAAC,KAAK,EAAE,aAAa,EAAE,CAAC,EAAE,QAAQ,EAAE,EAAE,EAAE;QAC3C,QAAQ,CAAC,QAAQ,EAAE,EAAE,EAAE,EAAE,IAAI,EAAE,GAAG,EAAE,WAAW,EAAE,CAAC,CAAC;IACrD,CAAC,CAAC;IAEF,KAAK,CAAC,KAAK,EAAE,aAAa,EAAE,CAAC,EAAE,QAAQ,EAAE,OAAO,EAAE,EAAE,EAAE;QACpD,QAAQ,CAAC,QAAQ,EAAE,EAAE,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;IAC7D,CAAC,CAAC;IAEF,KAAK,CAAC,KAAK,EAAE,qBAAqB,EAAE,KAAK,EAAE,EAAE,QAAQ,EAAE,GAAG,EAAE,GAAG,EAAE,EAAE,EAAE;QACnE,QAAQ,CAAC,QAAQ,EAAE,MAAM,eAAe,CAAC,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,IAAI,EAAE,IAAI,GAAG,CAAC,CAAC,CAAC;IACzF,CAAC,CAAC;CACH,CAAC"}
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
import { GitManager } from "../../core/git-manager.js";
|
|
2
|
+
import { getSelectedGitRepository, readGitDiff, selectedGitCwd } from "../dashboard.js";
|
|
3
|
+
import { readForm, requiredFormValue, sendJson, sendText } from "../http-utils.js";
|
|
4
|
+
import { errorMessage, route } from "./context.js";
|
|
5
|
+
/** Read-safe Git operations plus repository registration/selection. */
|
|
6
|
+
export const gitRoutes = [
|
|
7
|
+
route("GET", "/api/git/diff", async ({ response, url, configStore, cwd }) => {
|
|
8
|
+
const config = await configStore.load();
|
|
9
|
+
const selectedGitRepository = getSelectedGitRepository(config);
|
|
10
|
+
const gitCwd = selectedGitRepository?.path ?? cwd;
|
|
11
|
+
const selectedFile = url.searchParams.get("file")?.trim();
|
|
12
|
+
if (!selectedFile) {
|
|
13
|
+
sendJson(response, { ok: false, error: "file is required" }, 400);
|
|
14
|
+
return;
|
|
15
|
+
}
|
|
16
|
+
const git = new GitManager(gitCwd);
|
|
17
|
+
const status = await git.status();
|
|
18
|
+
const selectedStatus = status.files.find((file) => file.path === selectedFile);
|
|
19
|
+
const diff = selectedStatus
|
|
20
|
+
? await git.fileDiff(selectedStatus)
|
|
21
|
+
: await readGitDiff(gitCwd, selectedFile);
|
|
22
|
+
if (diff === undefined) {
|
|
23
|
+
sendJson(response, { ok: false, error: "No changes or file not found." }, 404);
|
|
24
|
+
return;
|
|
25
|
+
}
|
|
26
|
+
sendText(response, diff);
|
|
27
|
+
}),
|
|
28
|
+
route("GET", "/api/git/files", async ({ response, configStore, cwd }) => {
|
|
29
|
+
const gitCwd = await selectedGitCwd(configStore, cwd);
|
|
30
|
+
try {
|
|
31
|
+
const files = await new GitManager(gitCwd).listTrackedFiles();
|
|
32
|
+
sendJson(response, { ok: true, files });
|
|
33
|
+
}
|
|
34
|
+
catch (error) {
|
|
35
|
+
sendJson(response, { ok: false, error: errorMessage(error) }, 400);
|
|
36
|
+
}
|
|
37
|
+
}),
|
|
38
|
+
route("GET", "/api/git/file", async ({ response, url, configStore, cwd }) => {
|
|
39
|
+
const gitCwd = await selectedGitCwd(configStore, cwd);
|
|
40
|
+
const path = url.searchParams.get("path")?.trim();
|
|
41
|
+
if (!path) {
|
|
42
|
+
sendJson(response, { ok: false, error: "path is required" }, 400);
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
try {
|
|
46
|
+
const file = await new GitManager(gitCwd).readTrackedFile(path);
|
|
47
|
+
sendJson(response, { ok: true, ...file });
|
|
48
|
+
}
|
|
49
|
+
catch (error) {
|
|
50
|
+
sendJson(response, { ok: false, error: errorMessage(error) }, 404);
|
|
51
|
+
}
|
|
52
|
+
}),
|
|
53
|
+
route("GET", "/api/git/commit", async ({ response, url, configStore, cwd }) => {
|
|
54
|
+
const gitCwd = await selectedGitCwd(configStore, cwd);
|
|
55
|
+
const hash = url.searchParams.get("hash")?.trim();
|
|
56
|
+
const file = url.searchParams.get("file")?.trim() || undefined;
|
|
57
|
+
if (!hash) {
|
|
58
|
+
sendJson(response, { ok: false, error: "hash is required" }, 400);
|
|
59
|
+
return;
|
|
60
|
+
}
|
|
61
|
+
try {
|
|
62
|
+
const diff = await new GitManager(gitCwd).commitDiff(hash, file);
|
|
63
|
+
sendText(response, diff);
|
|
64
|
+
}
|
|
65
|
+
catch (error) {
|
|
66
|
+
sendJson(response, { ok: false, error: errorMessage(error) }, 400);
|
|
67
|
+
}
|
|
68
|
+
}),
|
|
69
|
+
route("GET", "/api/git/commit/files", async ({ response, url, configStore, cwd }) => {
|
|
70
|
+
const gitCwd = await selectedGitCwd(configStore, cwd);
|
|
71
|
+
const hash = url.searchParams.get("hash")?.trim();
|
|
72
|
+
if (!hash) {
|
|
73
|
+
sendJson(response, { ok: false, error: "hash is required" }, 400);
|
|
74
|
+
return;
|
|
75
|
+
}
|
|
76
|
+
try {
|
|
77
|
+
const files = await new GitManager(gitCwd).commitFiles(hash);
|
|
78
|
+
sendJson(response, { ok: true, files });
|
|
79
|
+
}
|
|
80
|
+
catch (error) {
|
|
81
|
+
sendJson(response, { ok: false, error: errorMessage(error) }, 400);
|
|
82
|
+
}
|
|
83
|
+
}),
|
|
84
|
+
route("GET", "/api/git/graph", async ({ response, url, configStore, cwd }) => {
|
|
85
|
+
const gitCwd = await selectedGitCwd(configStore, cwd);
|
|
86
|
+
const limitParam = url.searchParams.get("limit")?.trim();
|
|
87
|
+
const parsedLimit = limitParam ? Number(limitParam) : 200;
|
|
88
|
+
const limit = Number.isFinite(parsedLimit) && parsedLimit > 0
|
|
89
|
+
? Math.min(Math.floor(parsedLimit), 2000)
|
|
90
|
+
: 200;
|
|
91
|
+
const commits = await new GitManager(gitCwd).graph(limit);
|
|
92
|
+
sendJson(response, { ok: true, commits });
|
|
93
|
+
}),
|
|
94
|
+
route("POST", "/api/git/fetch", async ({ response, configStore, cwd }) => {
|
|
95
|
+
const gitCwd = await selectedGitCwd(configStore, cwd);
|
|
96
|
+
const output = await new GitManager(gitCwd).fetch();
|
|
97
|
+
sendJson(response, { ok: true, output });
|
|
98
|
+
}),
|
|
99
|
+
route("POST", "/api/git/branches", async ({ request, response, configStore, cwd }) => {
|
|
100
|
+
const form = await readForm(request);
|
|
101
|
+
const gitCwd = await selectedGitCwd(configStore, cwd);
|
|
102
|
+
const output = await new GitManager(gitCwd).createBranch(requiredFormValue(form, "name"));
|
|
103
|
+
sendJson(response, { ok: true, output });
|
|
104
|
+
}),
|
|
105
|
+
route("POST", "/api/git/branches/switch", async ({ request, response, configStore, cwd }) => {
|
|
106
|
+
const form = await readForm(request);
|
|
107
|
+
const gitCwd = await selectedGitCwd(configStore, cwd);
|
|
108
|
+
const output = await new GitManager(gitCwd).switchBranch(requiredFormValue(form, "name"));
|
|
109
|
+
sendJson(response, { ok: true, output });
|
|
110
|
+
}),
|
|
111
|
+
route("POST", "/api/git/repositories", async ({ request, response, configStore }) => {
|
|
112
|
+
const form = await readForm(request);
|
|
113
|
+
const config = await configStore.registerGitRepository({
|
|
114
|
+
name: requiredFormValue(form, "name"),
|
|
115
|
+
path: requiredFormValue(form, "path"),
|
|
116
|
+
});
|
|
117
|
+
sendJson(response, { ok: true, config });
|
|
118
|
+
}),
|
|
119
|
+
route("POST", "/api/git/select", async ({ request, response, configStore }) => {
|
|
120
|
+
const form = await readForm(request);
|
|
121
|
+
const config = await configStore.selectGitRepository(requiredFormValue(form, "name"));
|
|
122
|
+
sendJson(response, { ok: true, config });
|
|
123
|
+
}),
|
|
124
|
+
];
|
|
125
|
+
//# sourceMappingURL=git-routes.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"git-routes.js","sourceRoot":"","sources":["../../../src/web/routes/git-routes.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { Route } from "./context.js";
|
|
2
|
+
/**
|
|
3
|
+
* All routes in dispatch order. `/api/*` route groups come first; the shell /
|
|
4
|
+
* static catch-alls are last so they only run when no API route matched.
|
|
5
|
+
*
|
|
6
|
+
* To add a feature: create `<feature>-routes.ts` exporting a `Route[]`, then
|
|
7
|
+
* register it here. The dispatcher in `server.ts` never needs to change.
|
|
8
|
+
*/
|
|
9
|
+
export declare const routes: Route[];
|
|
10
|
+
export type { Route, RouteServices, RequestContext, RouteHandler } from "./context.js";
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { dashboardRoutes } from "./dashboard-routes.js";
|
|
2
|
+
import { agentRoutes } from "./agent-routes.js";
|
|
3
|
+
import { gitRoutes } from "./git-routes.js";
|
|
4
|
+
import { serviceRoutes } from "./service-routes.js";
|
|
5
|
+
import { shellRoutes } from "./shell-routes.js";
|
|
6
|
+
/**
|
|
7
|
+
* All routes in dispatch order. `/api/*` route groups come first; the shell /
|
|
8
|
+
* static catch-alls are last so they only run when no API route matched.
|
|
9
|
+
*
|
|
10
|
+
* To add a feature: create `<feature>-routes.ts` exporting a `Route[]`, then
|
|
11
|
+
* register it here. The dispatcher in `server.ts` never needs to change.
|
|
12
|
+
*/
|
|
13
|
+
export const routes = [
|
|
14
|
+
...dashboardRoutes,
|
|
15
|
+
...agentRoutes,
|
|
16
|
+
...gitRoutes,
|
|
17
|
+
...serviceRoutes,
|
|
18
|
+
...shellRoutes,
|
|
19
|
+
];
|
|
20
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/web/routes/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AACxD,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAC5C,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACpD,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAEhD;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,MAAM,GAAY;IAC7B,GAAG,eAAe;IAClB,GAAG,WAAW;IACd,GAAG,SAAS;IACZ,GAAG,aAAa;IAChB,GAAG,WAAW;CACf,CAAC"}
|