@zauso-ai/capstan-dev 0.1.2
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/index.d.ts +6 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +5 -0
- package/dist/index.js.map +1 -0
- package/dist/loader.d.ts +41 -0
- package/dist/loader.d.ts.map +1 -0
- package/dist/loader.js +69 -0
- package/dist/loader.js.map +1 -0
- package/dist/printer.d.ts +13 -0
- package/dist/printer.d.ts.map +1 -0
- package/dist/printer.js +38 -0
- package/dist/printer.js.map +1 -0
- package/dist/server.d.ts +13 -0
- package/dist/server.d.ts.map +1 -0
- package/dist/server.js +788 -0
- package/dist/server.js.map +1 -0
- package/dist/types.d.ts +34 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/dist/watcher.d.ts +14 -0
- package/dist/watcher.d.ts.map +1 -0
- package/dist/watcher.js +70 -0
- package/dist/watcher.js.map +1 -0
- package/package.json +48 -0
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export { createDevServer } from "./server.js";
|
|
2
|
+
export { watchRoutes } from "./watcher.js";
|
|
3
|
+
export { loadRouteModule, loadApiHandlers, loadPageModule } from "./loader.js";
|
|
4
|
+
export { printStartupBanner } from "./printer.js";
|
|
5
|
+
export type { DevServerConfig, DevServerInstance } from "./types.js";
|
|
6
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAC9C,OAAO,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAC3C,OAAO,EAAE,eAAe,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAC/E,OAAO,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAC;AAClD,YAAY,EAAE,eAAe,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAC9C,OAAO,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAC3C,OAAO,EAAE,eAAe,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAC/E,OAAO,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAC"}
|
package/dist/loader.d.ts
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Dynamically import a module from disk, bypassing Node's module cache
|
|
3
|
+
* by appending a unique query parameter to the file URL.
|
|
4
|
+
*
|
|
5
|
+
* Returns the full module namespace object.
|
|
6
|
+
*/
|
|
7
|
+
export declare function loadRouteModule(filePath: string): Promise<Record<string, unknown>>;
|
|
8
|
+
/**
|
|
9
|
+
* Import an API route file and extract the exported HTTP method handlers
|
|
10
|
+
* and optional `meta` export.
|
|
11
|
+
*
|
|
12
|
+
* API route files are expected to export one or more of:
|
|
13
|
+
* GET, POST, PUT, DELETE, PATCH
|
|
14
|
+
*
|
|
15
|
+
* Each export should be the result of `defineAPI()` from @zauso-ai/capstan-core,
|
|
16
|
+
* which produces an `APIDefinition` object with a `.handler` method.
|
|
17
|
+
*
|
|
18
|
+
* An optional `meta` export provides additional route metadata (e.g.
|
|
19
|
+
* description, tags) that is merged into the agent manifest.
|
|
20
|
+
*/
|
|
21
|
+
export declare function loadApiHandlers(filePath: string): Promise<{
|
|
22
|
+
GET?: unknown;
|
|
23
|
+
POST?: unknown;
|
|
24
|
+
PUT?: unknown;
|
|
25
|
+
DELETE?: unknown;
|
|
26
|
+
PATCH?: unknown;
|
|
27
|
+
meta?: Record<string, unknown>;
|
|
28
|
+
}>;
|
|
29
|
+
/**
|
|
30
|
+
* Import a page route file and extract the default component and
|
|
31
|
+
* optional loader function.
|
|
32
|
+
*
|
|
33
|
+
* Page files are expected to export:
|
|
34
|
+
* - `default` -- a React component (the page itself)
|
|
35
|
+
* - `loader` -- (optional) a server-side data-loading function
|
|
36
|
+
*/
|
|
37
|
+
export declare function loadPageModule(filePath: string): Promise<{
|
|
38
|
+
default?: unknown;
|
|
39
|
+
loader?: unknown;
|
|
40
|
+
}>;
|
|
41
|
+
//# sourceMappingURL=loader.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"loader.d.ts","sourceRoot":"","sources":["../src/loader.ts"],"names":[],"mappings":"AAUA;;;;;GAKG;AACH,wBAAsB,eAAe,CACnC,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAMlC;AAED;;;;;;;;;;;;GAYG;AACH,wBAAsB,eAAe,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC;IAC/D,GAAG,CAAC,EAAE,OAAO,CAAC;IACd,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,GAAG,CAAC,EAAE,OAAO,CAAC;IACd,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAChC,CAAC,CAuBD;AAED;;;;;;;GAOG;AACH,wBAAsB,cAAc,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC;IAC9D,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB,CAAC,CAYD"}
|
package/dist/loader.js
ADDED
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { pathToFileURL } from "node:url";
|
|
2
|
+
/**
|
|
3
|
+
* Monotonically increasing counter used to bust Node's ESM module cache.
|
|
4
|
+
* Each call to `loadRouteModule` gets a unique query string so that the
|
|
5
|
+
* runtime always re-evaluates the file -- critical for HMR-like behavior
|
|
6
|
+
* during development.
|
|
7
|
+
*/
|
|
8
|
+
let cacheBustCounter = 0;
|
|
9
|
+
/**
|
|
10
|
+
* Dynamically import a module from disk, bypassing Node's module cache
|
|
11
|
+
* by appending a unique query parameter to the file URL.
|
|
12
|
+
*
|
|
13
|
+
* Returns the full module namespace object.
|
|
14
|
+
*/
|
|
15
|
+
export async function loadRouteModule(filePath) {
|
|
16
|
+
const fileUrl = pathToFileURL(filePath).href;
|
|
17
|
+
const bustUrl = `${fileUrl}?t=${Date.now()}_${cacheBustCounter++}`;
|
|
18
|
+
const mod = (await import(bustUrl));
|
|
19
|
+
return mod;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Import an API route file and extract the exported HTTP method handlers
|
|
23
|
+
* and optional `meta` export.
|
|
24
|
+
*
|
|
25
|
+
* API route files are expected to export one or more of:
|
|
26
|
+
* GET, POST, PUT, DELETE, PATCH
|
|
27
|
+
*
|
|
28
|
+
* Each export should be the result of `defineAPI()` from @zauso-ai/capstan-core,
|
|
29
|
+
* which produces an `APIDefinition` object with a `.handler` method.
|
|
30
|
+
*
|
|
31
|
+
* An optional `meta` export provides additional route metadata (e.g.
|
|
32
|
+
* description, tags) that is merged into the agent manifest.
|
|
33
|
+
*/
|
|
34
|
+
export async function loadApiHandlers(filePath) {
|
|
35
|
+
const mod = await loadRouteModule(filePath);
|
|
36
|
+
const result = {};
|
|
37
|
+
if (mod["GET"] !== undefined)
|
|
38
|
+
result.GET = mod["GET"];
|
|
39
|
+
if (mod["POST"] !== undefined)
|
|
40
|
+
result.POST = mod["POST"];
|
|
41
|
+
if (mod["PUT"] !== undefined)
|
|
42
|
+
result.PUT = mod["PUT"];
|
|
43
|
+
if (mod["DELETE"] !== undefined)
|
|
44
|
+
result.DELETE = mod["DELETE"];
|
|
45
|
+
if (mod["PATCH"] !== undefined)
|
|
46
|
+
result.PATCH = mod["PATCH"];
|
|
47
|
+
if (mod["meta"] !== undefined && typeof mod["meta"] === "object") {
|
|
48
|
+
result.meta = mod["meta"];
|
|
49
|
+
}
|
|
50
|
+
return result;
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Import a page route file and extract the default component and
|
|
54
|
+
* optional loader function.
|
|
55
|
+
*
|
|
56
|
+
* Page files are expected to export:
|
|
57
|
+
* - `default` -- a React component (the page itself)
|
|
58
|
+
* - `loader` -- (optional) a server-side data-loading function
|
|
59
|
+
*/
|
|
60
|
+
export async function loadPageModule(filePath) {
|
|
61
|
+
const mod = await loadRouteModule(filePath);
|
|
62
|
+
const result = {};
|
|
63
|
+
if (mod["default"] !== undefined)
|
|
64
|
+
result.default = mod["default"];
|
|
65
|
+
if (mod["loader"] !== undefined)
|
|
66
|
+
result.loader = mod["loader"];
|
|
67
|
+
return result;
|
|
68
|
+
}
|
|
69
|
+
//# sourceMappingURL=loader.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"loader.js","sourceRoot":"","sources":["../src/loader.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAEzC;;;;;GAKG;AACH,IAAI,gBAAgB,GAAG,CAAC,CAAC;AAEzB;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,eAAe,CACnC,QAAgB;IAEhB,MAAM,OAAO,GAAG,aAAa,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC;IAC7C,MAAM,OAAO,GAAG,GAAG,OAAO,MAAM,IAAI,CAAC,GAAG,EAAE,IAAI,gBAAgB,EAAE,EAAE,CAAC;IAEnE,MAAM,GAAG,GAAG,CAAC,MAAM,MAAM,CAAC,OAAO,CAAC,CAA4B,CAAC;IAC/D,OAAO,GAAG,CAAC;AACb,CAAC;AAED;;;;;;;;;;;;GAYG;AACH,MAAM,CAAC,KAAK,UAAU,eAAe,CAAC,QAAgB;IAQpD,MAAM,GAAG,GAAG,MAAM,eAAe,CAAC,QAAQ,CAAC,CAAC;IAE5C,MAAM,MAAM,GAOR,EAAE,CAAC;IAEP,IAAI,GAAG,CAAC,KAAK,CAAC,KAAK,SAAS;QAAE,MAAM,CAAC,GAAG,GAAG,GAAG,CAAC,KAAK,CAAC,CAAC;IACtD,IAAI,GAAG,CAAC,MAAM,CAAC,KAAK,SAAS;QAAE,MAAM,CAAC,IAAI,GAAG,GAAG,CAAC,MAAM,CAAC,CAAC;IACzD,IAAI,GAAG,CAAC,KAAK,CAAC,KAAK,SAAS;QAAE,MAAM,CAAC,GAAG,GAAG,GAAG,CAAC,KAAK,CAAC,CAAC;IACtD,IAAI,GAAG,CAAC,QAAQ,CAAC,KAAK,SAAS;QAAE,MAAM,CAAC,MAAM,GAAG,GAAG,CAAC,QAAQ,CAAC,CAAC;IAC/D,IAAI,GAAG,CAAC,OAAO,CAAC,KAAK,SAAS;QAAE,MAAM,CAAC,KAAK,GAAG,GAAG,CAAC,OAAO,CAAC,CAAC;IAE5D,IAAI,GAAG,CAAC,MAAM,CAAC,KAAK,SAAS,IAAI,OAAO,GAAG,CAAC,MAAM,CAAC,KAAK,QAAQ,EAAE,CAAC;QACjE,MAAM,CAAC,IAAI,GAAG,GAAG,CAAC,MAAM,CAA4B,CAAC;IACvD,CAAC;IAED,OAAO,MAAM,CAAC;AAChB,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,CAAC,KAAK,UAAU,cAAc,CAAC,QAAgB;IAInD,MAAM,GAAG,GAAG,MAAM,eAAe,CAAC,QAAQ,CAAC,CAAC;IAE5C,MAAM,MAAM,GAGR,EAAE,CAAC;IAEP,IAAI,GAAG,CAAC,SAAS,CAAC,KAAK,SAAS;QAAE,MAAM,CAAC,OAAO,GAAG,GAAG,CAAC,SAAS,CAAC,CAAC;IAClE,IAAI,GAAG,CAAC,QAAQ,CAAC,KAAK,SAAS;QAAE,MAAM,CAAC,MAAM,GAAG,GAAG,CAAC,QAAQ,CAAC,CAAC;IAE/D,OAAO,MAAM,CAAC;AAChB,CAAC"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Print a nicely formatted startup banner to stdout showing key server
|
|
3
|
+
* information: URLs, route counts, and the application name.
|
|
4
|
+
*/
|
|
5
|
+
export declare function printStartupBanner(config: {
|
|
6
|
+
appName: string;
|
|
7
|
+
port: number;
|
|
8
|
+
host: string;
|
|
9
|
+
routeCount: number;
|
|
10
|
+
apiRouteCount: number;
|
|
11
|
+
pageRouteCount: number;
|
|
12
|
+
}): void;
|
|
13
|
+
//# sourceMappingURL=printer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"printer.d.ts","sourceRoot":"","sources":["../src/printer.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,MAAM,EAAE;IACzC,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,EAAE,MAAM,CAAC;IACnB,aAAa,EAAE,MAAM,CAAC;IACtB,cAAc,EAAE,MAAM,CAAC;CACxB,GAAG,IAAI,CAyCP"}
|
package/dist/printer.js
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Print a nicely formatted startup banner to stdout showing key server
|
|
3
|
+
* information: URLs, route counts, and the application name.
|
|
4
|
+
*/
|
|
5
|
+
export function printStartupBanner(config) {
|
|
6
|
+
const { appName, port, host, routeCount, apiRouteCount, pageRouteCount } = config;
|
|
7
|
+
const displayHost = host === "0.0.0.0" ? "localhost" : host;
|
|
8
|
+
const base = `http://${displayHost}:${port}`;
|
|
9
|
+
const webUrl = base;
|
|
10
|
+
const agentUrl = `${base}/api`;
|
|
11
|
+
const manifestUrl = `${base}/.well-known/capstan.json`;
|
|
12
|
+
const openApiUrl = `${base}/openapi.json`;
|
|
13
|
+
// Build content lines, then measure the longest to size the box.
|
|
14
|
+
const lines = [
|
|
15
|
+
"Capstan Dev Server",
|
|
16
|
+
"",
|
|
17
|
+
`App: ${appName}`,
|
|
18
|
+
`Web UI: ${webUrl}`,
|
|
19
|
+
`Agent API: ${agentUrl}`,
|
|
20
|
+
`Manifest: ${manifestUrl}`,
|
|
21
|
+
`OpenAPI: ${openApiUrl}`,
|
|
22
|
+
"",
|
|
23
|
+
`Routes: ${routeCount} (${apiRouteCount} API, ${pageRouteCount} pages)`,
|
|
24
|
+
];
|
|
25
|
+
const maxLen = Math.max(...lines.map((l) => l.length));
|
|
26
|
+
// Pad each line to the maximum width so the right border aligns.
|
|
27
|
+
const padded = lines.map((l) => l.padEnd(maxLen));
|
|
28
|
+
const horizontal = "\u2500".repeat(maxLen + 2); // ─
|
|
29
|
+
const top = ` \u250C${horizontal}\u2510`; // ┌─...─┐
|
|
30
|
+
const bottom = ` \u2514${horizontal}\u2518`; // └─...─┘
|
|
31
|
+
const body = padded
|
|
32
|
+
.map((l) => ` \u2502 ${l} \u2502`) // │ content │
|
|
33
|
+
.join("\n");
|
|
34
|
+
const banner = `\n${top}\n${body}\n${bottom}\n`;
|
|
35
|
+
// eslint-disable-next-line no-console
|
|
36
|
+
console.log(banner);
|
|
37
|
+
}
|
|
38
|
+
//# sourceMappingURL=printer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"printer.js","sourceRoot":"","sources":["../src/printer.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,MAAM,UAAU,kBAAkB,CAAC,MAOlC;IACC,MAAM,EAAE,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,UAAU,EAAE,aAAa,EAAE,cAAc,EAAE,GACtE,MAAM,CAAC;IAET,MAAM,WAAW,GAAG,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,IAAI,CAAC;IAC5D,MAAM,IAAI,GAAG,UAAU,WAAW,IAAI,IAAI,EAAE,CAAC;IAE7C,MAAM,MAAM,GAAG,IAAI,CAAC;IACpB,MAAM,QAAQ,GAAG,GAAG,IAAI,MAAM,CAAC;IAC/B,MAAM,WAAW,GAAG,GAAG,IAAI,2BAA2B,CAAC;IACvD,MAAM,UAAU,GAAG,GAAG,IAAI,eAAe,CAAC;IAE1C,iEAAiE;IACjE,MAAM,KAAK,GAAG;QACZ,oBAAoB;QACpB,EAAE;QACF,cAAc,OAAO,EAAE;QACvB,cAAc,MAAM,EAAE;QACtB,cAAc,QAAQ,EAAE;QACxB,cAAc,WAAW,EAAE;QAC3B,cAAc,UAAU,EAAE;QAC1B,EAAE;QACF,cAAc,UAAU,KAAK,aAAa,SAAS,cAAc,SAAS;KAC3E,CAAC;IAEF,MAAM,MAAM,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC;IACvD,iEAAiE;IACjE,MAAM,MAAM,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC;IAElD,MAAM,UAAU,GAAG,QAAQ,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI;IACpD,MAAM,GAAG,GAAG,WAAW,UAAU,QAAQ,CAAC,CAAC,UAAU;IACrD,MAAM,MAAM,GAAG,WAAW,UAAU,QAAQ,CAAC,CAAC,UAAU;IAExD,MAAM,IAAI,GAAG,MAAM;SAChB,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,YAAY,CAAC,SAAS,CAAC,CAAC,cAAc;SACjD,IAAI,CAAC,IAAI,CAAC,CAAC;IAEd,MAAM,MAAM,GAAG,KAAK,GAAG,KAAK,IAAI,KAAK,MAAM,IAAI,CAAC;IAEhD,sCAAsC;IACtC,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;AACtB,CAAC"}
|
package/dist/server.d.ts
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { DevServerConfig, DevServerInstance } from "./types.js";
|
|
2
|
+
/**
|
|
3
|
+
* Create and return a dev server instance that:
|
|
4
|
+
*
|
|
5
|
+
* 1. Scans `app/routes/` for route files
|
|
6
|
+
* 2. Creates a Hono server with all routes registered
|
|
7
|
+
* 3. Starts an HTTP server on the configured port
|
|
8
|
+
* 4. Watches for file changes and re-builds routes
|
|
9
|
+
* 5. Serves the agent manifest, OpenAPI spec, and health endpoint
|
|
10
|
+
* 6. Prints a startup banner with URLs and route counts
|
|
11
|
+
*/
|
|
12
|
+
export declare function createDevServer(config: DevServerConfig): Promise<DevServerInstance>;
|
|
13
|
+
//# sourceMappingURL=server.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAoBA,OAAO,KAAK,EAAE,eAAe,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AA+yBrE;;;;;;;;;GASG;AACH,wBAAsB,eAAe,CACnC,MAAM,EAAE,eAAe,GACtB,OAAO,CAAC,iBAAiB,CAAC,CA6M5B"}
|
package/dist/server.js
ADDED
|
@@ -0,0 +1,788 @@
|
|
|
1
|
+
import { createServer } from "node:http";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { Hono } from "hono";
|
|
4
|
+
import { cors } from "hono/cors";
|
|
5
|
+
import { scanRoutes } from "@zauso-ai/capstan-router";
|
|
6
|
+
import { createContext, createApproval, getApproval, listApprovals, resolveApproval, } from "@zauso-ai/capstan-core";
|
|
7
|
+
import { loadApiHandlers, loadPageModule } from "./loader.js";
|
|
8
|
+
import { watchRoutes } from "./watcher.js";
|
|
9
|
+
import { printStartupBanner } from "./printer.js";
|
|
10
|
+
// ---------------------------------------------------------------------------
|
|
11
|
+
// Helpers
|
|
12
|
+
// ---------------------------------------------------------------------------
|
|
13
|
+
/**
|
|
14
|
+
* Read the full request body from an IncomingMessage and return it
|
|
15
|
+
* as a parsed JSON value (or raw string if JSON parsing fails).
|
|
16
|
+
*/
|
|
17
|
+
function readBody(req) {
|
|
18
|
+
return new Promise((resolve, reject) => {
|
|
19
|
+
const chunks = [];
|
|
20
|
+
req.on("data", (chunk) => chunks.push(chunk));
|
|
21
|
+
req.on("error", reject);
|
|
22
|
+
req.on("end", () => {
|
|
23
|
+
const raw = Buffer.concat(chunks).toString("utf-8");
|
|
24
|
+
if (raw.length === 0) {
|
|
25
|
+
resolve(undefined);
|
|
26
|
+
return;
|
|
27
|
+
}
|
|
28
|
+
try {
|
|
29
|
+
resolve(JSON.parse(raw));
|
|
30
|
+
}
|
|
31
|
+
catch {
|
|
32
|
+
resolve(raw);
|
|
33
|
+
}
|
|
34
|
+
});
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Determine if an exported handler value looks like an APIDefinition
|
|
39
|
+
* produced by `defineAPI()` from @zauso-ai/capstan-core.
|
|
40
|
+
*/
|
|
41
|
+
function isAPIDefinition(value) {
|
|
42
|
+
return (value !== null &&
|
|
43
|
+
typeof value === "object" &&
|
|
44
|
+
"handler" in value &&
|
|
45
|
+
typeof value.handler === "function");
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Build a minimal `CapstanContext` from a raw `Request` for use outside
|
|
49
|
+
* of the Hono middleware pipeline (e.g. for page loaders).
|
|
50
|
+
*/
|
|
51
|
+
function buildStandaloneContext(request, auth) {
|
|
52
|
+
return {
|
|
53
|
+
auth: auth ?? {
|
|
54
|
+
isAuthenticated: false,
|
|
55
|
+
type: "anonymous",
|
|
56
|
+
permissions: [],
|
|
57
|
+
},
|
|
58
|
+
request,
|
|
59
|
+
env: process.env,
|
|
60
|
+
// In dev mode we don't have a real Hono context for standalone calls.
|
|
61
|
+
// The context is cast to satisfy the type; page loaders should not
|
|
62
|
+
// depend on `honoCtx` directly.
|
|
63
|
+
honoCtx: {},
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Given a scanned route manifest, build a fresh Hono application with all
|
|
68
|
+
* routes registered. Returns the Hono app plus metadata used by the
|
|
69
|
+
* framework endpoints (manifest, openapi, health).
|
|
70
|
+
*/
|
|
71
|
+
async function buildApp(manifest, config) {
|
|
72
|
+
const app = new Hono();
|
|
73
|
+
// Global middleware ---------------------------------------------------------
|
|
74
|
+
app.use("*", cors());
|
|
75
|
+
// --- Auth middleware -------------------------------------------------------
|
|
76
|
+
// If the config includes auth settings, create the auth resolver from
|
|
77
|
+
// @zauso-ai/capstan-auth. Otherwise, fall back to anonymous and warn once.
|
|
78
|
+
let resolveAuth = null;
|
|
79
|
+
if (config.auth) {
|
|
80
|
+
try {
|
|
81
|
+
const authModuleName = "@zauso-ai/capstan-auth";
|
|
82
|
+
const authPkg = (await import(authModuleName));
|
|
83
|
+
resolveAuth = authPkg.createAuthMiddleware(config.auth, {});
|
|
84
|
+
}
|
|
85
|
+
catch {
|
|
86
|
+
// @zauso-ai/capstan-auth is not installed or failed to load — continue without it.
|
|
87
|
+
// eslint-disable-next-line no-console
|
|
88
|
+
console.warn("[capstan] @zauso-ai/capstan-auth not available. Auth middleware disabled.");
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
else {
|
|
92
|
+
// eslint-disable-next-line no-console
|
|
93
|
+
console.warn("[capstan] No auth config provided. All requests treated as anonymous.");
|
|
94
|
+
}
|
|
95
|
+
// Hono middleware that resolves auth and attaches it to the context so that
|
|
96
|
+
// `createContext(c)` picks it up via `c.get("capstanAuth")`.
|
|
97
|
+
app.use("*", async (c, next) => {
|
|
98
|
+
if (resolveAuth) {
|
|
99
|
+
const authCtx = await resolveAuth(c.req.raw);
|
|
100
|
+
c.set("capstanAuth", authCtx);
|
|
101
|
+
}
|
|
102
|
+
await next();
|
|
103
|
+
});
|
|
104
|
+
// Route metadata accumulated for the agent manifest / OpenAPI spec.
|
|
105
|
+
const routeRegistry = [];
|
|
106
|
+
/**
|
|
107
|
+
* Handler registry keyed by "METHOD /path" so approved requests can
|
|
108
|
+
* re-execute the original handler without going through the HTTP stack.
|
|
109
|
+
*/
|
|
110
|
+
const handlerRegistry = new Map();
|
|
111
|
+
let apiRouteCount = 0;
|
|
112
|
+
let pageRouteCount = 0;
|
|
113
|
+
// Separate API and page routes from the manifest.
|
|
114
|
+
const apiRoutes = [];
|
|
115
|
+
const pageRoutes = [];
|
|
116
|
+
for (const route of manifest.routes) {
|
|
117
|
+
if (route.type === "api")
|
|
118
|
+
apiRoutes.push(route);
|
|
119
|
+
if (route.type === "page")
|
|
120
|
+
pageRoutes.push(route);
|
|
121
|
+
}
|
|
122
|
+
// --- Register API routes --------------------------------------------------
|
|
123
|
+
for (const route of apiRoutes) {
|
|
124
|
+
let handlers;
|
|
125
|
+
try {
|
|
126
|
+
handlers = await loadApiHandlers(route.filePath);
|
|
127
|
+
}
|
|
128
|
+
catch (err) {
|
|
129
|
+
// eslint-disable-next-line no-console
|
|
130
|
+
console.error(`[capstan] Failed to load API route ${route.filePath}:`, err instanceof Error ? err.message : err);
|
|
131
|
+
continue;
|
|
132
|
+
}
|
|
133
|
+
const methodEntries = [
|
|
134
|
+
["GET", handlers.GET],
|
|
135
|
+
["POST", handlers.POST],
|
|
136
|
+
["PUT", handlers.PUT],
|
|
137
|
+
["DELETE", handlers.DELETE],
|
|
138
|
+
["PATCH", handlers.PATCH],
|
|
139
|
+
];
|
|
140
|
+
for (const [method, handler] of methodEntries) {
|
|
141
|
+
if (handler === undefined)
|
|
142
|
+
continue;
|
|
143
|
+
apiRouteCount++;
|
|
144
|
+
// Record metadata for agent manifest / OpenAPI.
|
|
145
|
+
const meta = {
|
|
146
|
+
method,
|
|
147
|
+
path: route.urlPattern,
|
|
148
|
+
};
|
|
149
|
+
if (isAPIDefinition(handler)) {
|
|
150
|
+
if (handler.description !== undefined) {
|
|
151
|
+
meta.description = handler.description;
|
|
152
|
+
}
|
|
153
|
+
if (handler.capability !== undefined) {
|
|
154
|
+
meta.capability = handler.capability;
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
routeRegistry.push(meta);
|
|
158
|
+
// Store the handler for approval re-execution.
|
|
159
|
+
if (isAPIDefinition(handler)) {
|
|
160
|
+
const routeKey = `${method} ${route.urlPattern}`;
|
|
161
|
+
const apiHandler = handler;
|
|
162
|
+
handlerRegistry.set(routeKey, async (input, ctx) => {
|
|
163
|
+
return apiHandler.handler({ input, ctx });
|
|
164
|
+
});
|
|
165
|
+
}
|
|
166
|
+
// Mount the handler on the Hono app.
|
|
167
|
+
const honoMethod = method.toLowerCase();
|
|
168
|
+
app[honoMethod](route.urlPattern, async (c) => {
|
|
169
|
+
const ctx = createContext(c);
|
|
170
|
+
// Parse input from query string (GET) or request body (others).
|
|
171
|
+
let input;
|
|
172
|
+
try {
|
|
173
|
+
if (method === "GET") {
|
|
174
|
+
input = Object.fromEntries(new URL(c.req.url).searchParams);
|
|
175
|
+
}
|
|
176
|
+
else {
|
|
177
|
+
const contentType = c.req.header("content-type") ?? "";
|
|
178
|
+
if (contentType.includes("application/json")) {
|
|
179
|
+
input = await c.req.json();
|
|
180
|
+
}
|
|
181
|
+
else {
|
|
182
|
+
input = {};
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
catch {
|
|
187
|
+
input = {};
|
|
188
|
+
}
|
|
189
|
+
try {
|
|
190
|
+
// --- Policy enforcement -------------------------------------------
|
|
191
|
+
// If the handler declares a policy, enforce it before executing.
|
|
192
|
+
if (isAPIDefinition(handler) && handler.policy) {
|
|
193
|
+
const policyName = handler.policy;
|
|
194
|
+
// requireAuth is a built-in policy: deny anonymous requests.
|
|
195
|
+
if (policyName === "requireAuth") {
|
|
196
|
+
if (!ctx.auth.isAuthenticated) {
|
|
197
|
+
return c.json({ error: "Unauthorized", policy: policyName }, 401);
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
// For custom policies that are not "requireAuth", create a
|
|
201
|
+
// pending approval so a human/supervisor can review the action.
|
|
202
|
+
// The dev server does not maintain a full policy registry, so
|
|
203
|
+
// custom policies are treated as requiring approval in dev mode.
|
|
204
|
+
if (policyName !== "requireAuth") {
|
|
205
|
+
const reason = `Policy "${policyName}" requires approval`;
|
|
206
|
+
const approval = createApproval({
|
|
207
|
+
method,
|
|
208
|
+
path: route.urlPattern,
|
|
209
|
+
input,
|
|
210
|
+
policy: policyName,
|
|
211
|
+
reason,
|
|
212
|
+
});
|
|
213
|
+
return c.json({
|
|
214
|
+
status: "approval_required",
|
|
215
|
+
approvalId: approval.id,
|
|
216
|
+
reason,
|
|
217
|
+
pollUrl: `/capstan/approvals/${approval.id}`,
|
|
218
|
+
}, 202);
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
if (isAPIDefinition(handler)) {
|
|
222
|
+
const result = await handler.handler({ input, ctx });
|
|
223
|
+
return c.json(result);
|
|
224
|
+
}
|
|
225
|
+
// If the export is a plain function rather than an APIDefinition,
|
|
226
|
+
// invoke it directly with a similar signature.
|
|
227
|
+
if (typeof handler === "function") {
|
|
228
|
+
const result = await handler({ input, ctx });
|
|
229
|
+
return c.json(result);
|
|
230
|
+
}
|
|
231
|
+
return c.json({ error: "Invalid handler export" }, 500);
|
|
232
|
+
}
|
|
233
|
+
catch (err) {
|
|
234
|
+
// Zod validation errors
|
|
235
|
+
if (err !== null &&
|
|
236
|
+
typeof err === "object" &&
|
|
237
|
+
"issues" in err &&
|
|
238
|
+
Array.isArray(err.issues)) {
|
|
239
|
+
return c.json({
|
|
240
|
+
error: "Validation Error",
|
|
241
|
+
issues: err.issues,
|
|
242
|
+
}, 400);
|
|
243
|
+
}
|
|
244
|
+
const message = err instanceof Error ? err.message : "Internal Server Error";
|
|
245
|
+
// eslint-disable-next-line no-console
|
|
246
|
+
console.error(`[capstan] Error in ${method} ${route.urlPattern}:`, message);
|
|
247
|
+
return c.json({ error: message }, 500);
|
|
248
|
+
}
|
|
249
|
+
});
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
// --- Register page routes -------------------------------------------------
|
|
253
|
+
for (const route of pageRoutes) {
|
|
254
|
+
let pageModule;
|
|
255
|
+
try {
|
|
256
|
+
pageModule = await loadPageModule(route.filePath);
|
|
257
|
+
}
|
|
258
|
+
catch (err) {
|
|
259
|
+
// eslint-disable-next-line no-console
|
|
260
|
+
console.error(`[capstan] Failed to load page ${route.filePath}:`, err instanceof Error ? err.message : err);
|
|
261
|
+
continue;
|
|
262
|
+
}
|
|
263
|
+
if (!pageModule.default) {
|
|
264
|
+
// eslint-disable-next-line no-console
|
|
265
|
+
console.warn(`[capstan] Page ${route.filePath} has no default export, skipping.`);
|
|
266
|
+
continue;
|
|
267
|
+
}
|
|
268
|
+
pageRouteCount++;
|
|
269
|
+
app.get(route.urlPattern, async (c) => {
|
|
270
|
+
// In dev mode we do a simplified server render:
|
|
271
|
+
// - Run the loader (if any) to get data
|
|
272
|
+
// - Attempt to render using @zauso-ai/capstan-react's renderPage
|
|
273
|
+
// - Fall back to a minimal HTML shell with loader data if React
|
|
274
|
+
// rendering is unavailable or fails.
|
|
275
|
+
const request = c.req.raw;
|
|
276
|
+
const params = {};
|
|
277
|
+
for (const name of route.params) {
|
|
278
|
+
const value = c.req.param(name);
|
|
279
|
+
if (value !== undefined) {
|
|
280
|
+
params[name] = value;
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
// Resolve auth for page loaders when auth middleware is configured.
|
|
284
|
+
let pageAuth;
|
|
285
|
+
if (resolveAuth) {
|
|
286
|
+
try {
|
|
287
|
+
pageAuth = await resolveAuth(request);
|
|
288
|
+
}
|
|
289
|
+
catch {
|
|
290
|
+
// Auth resolution failed — fall through to anonymous.
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
const ctx = buildStandaloneContext(request, pageAuth);
|
|
294
|
+
// Run loader if present
|
|
295
|
+
let loaderData = null;
|
|
296
|
+
if (typeof pageModule.loader === "function") {
|
|
297
|
+
try {
|
|
298
|
+
loaderData = await pageModule.loader({
|
|
299
|
+
params,
|
|
300
|
+
request,
|
|
301
|
+
ctx: { auth: ctx.auth },
|
|
302
|
+
fetch: {
|
|
303
|
+
get: async () => null,
|
|
304
|
+
post: async () => null,
|
|
305
|
+
put: async () => null,
|
|
306
|
+
delete: async () => null,
|
|
307
|
+
},
|
|
308
|
+
});
|
|
309
|
+
}
|
|
310
|
+
catch (err) {
|
|
311
|
+
// eslint-disable-next-line no-console
|
|
312
|
+
console.error(`[capstan] Loader error in ${route.filePath}:`, err instanceof Error ? err.message : err);
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
// Attempt full SSR via @zauso-ai/capstan-react. If the package is available
|
|
316
|
+
// and the page module has a valid React component, render it.
|
|
317
|
+
// We use a dynamic import so the dev server works even when
|
|
318
|
+
// @zauso-ai/capstan-react is not installed.
|
|
319
|
+
try {
|
|
320
|
+
const reactModuleName = "@zauso-ai/capstan-react";
|
|
321
|
+
const reactPkg = (await import(reactModuleName));
|
|
322
|
+
const result = await reactPkg.renderPage({
|
|
323
|
+
pageModule: {
|
|
324
|
+
default: pageModule.default,
|
|
325
|
+
loader: pageModule.loader,
|
|
326
|
+
},
|
|
327
|
+
layouts: [],
|
|
328
|
+
params,
|
|
329
|
+
request,
|
|
330
|
+
loaderArgs: {
|
|
331
|
+
params,
|
|
332
|
+
request,
|
|
333
|
+
ctx: { auth: ctx.auth },
|
|
334
|
+
fetch: {
|
|
335
|
+
get: async () => null,
|
|
336
|
+
post: async () => null,
|
|
337
|
+
put: async () => null,
|
|
338
|
+
delete: async () => null,
|
|
339
|
+
},
|
|
340
|
+
},
|
|
341
|
+
});
|
|
342
|
+
return c.html(result.html, result.statusCode);
|
|
343
|
+
}
|
|
344
|
+
catch {
|
|
345
|
+
// @zauso-ai/capstan-react not available or render failed -- serve a
|
|
346
|
+
// minimal HTML shell that exposes loader data.
|
|
347
|
+
const html = `<!DOCTYPE html>
|
|
348
|
+
<html lang="en">
|
|
349
|
+
<head>
|
|
350
|
+
<meta charset="utf-8" />
|
|
351
|
+
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
352
|
+
<title>${config.appName ?? "Capstan App"}</title>
|
|
353
|
+
</head>
|
|
354
|
+
<body>
|
|
355
|
+
<div id="capstan-root">
|
|
356
|
+
<p>Page: ${route.urlPattern}</p>
|
|
357
|
+
</div>
|
|
358
|
+
<script>window.__CAPSTAN_DATA__ = ${JSON.stringify({ loaderData, params })}</script>
|
|
359
|
+
</body>
|
|
360
|
+
</html>`;
|
|
361
|
+
return c.html(html);
|
|
362
|
+
}
|
|
363
|
+
});
|
|
364
|
+
}
|
|
365
|
+
// --- Approval management endpoints ----------------------------------------
|
|
366
|
+
/** List all approvals, optionally filtered by ?status=pending|approved|denied */
|
|
367
|
+
app.get("/capstan/approvals", (c) => {
|
|
368
|
+
const statusParam = new URL(c.req.url).searchParams.get("status");
|
|
369
|
+
const items = listApprovals(statusParam ?? undefined);
|
|
370
|
+
return c.json({ approvals: items });
|
|
371
|
+
});
|
|
372
|
+
/** Get a single approval by ID */
|
|
373
|
+
app.get("/capstan/approvals/:id", (c) => {
|
|
374
|
+
const id = c.req.param("id");
|
|
375
|
+
const approval = getApproval(id);
|
|
376
|
+
if (!approval) {
|
|
377
|
+
return c.json({ error: "Approval not found" }, 404);
|
|
378
|
+
}
|
|
379
|
+
return c.json(approval);
|
|
380
|
+
});
|
|
381
|
+
/** Approve a pending approval — re-executes the original handler */
|
|
382
|
+
app.post("/capstan/approvals/:id/approve", async (c) => {
|
|
383
|
+
const id = c.req.param("id");
|
|
384
|
+
const existing = getApproval(id);
|
|
385
|
+
if (!existing) {
|
|
386
|
+
return c.json({ error: "Approval not found" }, 404);
|
|
387
|
+
}
|
|
388
|
+
if (existing.status !== "pending") {
|
|
389
|
+
return c.json({ error: "Approval already resolved", status: existing.status }, 409);
|
|
390
|
+
}
|
|
391
|
+
let resolvedBy;
|
|
392
|
+
try {
|
|
393
|
+
const body = await c.req.json();
|
|
394
|
+
if (typeof body.resolvedBy === "string") {
|
|
395
|
+
resolvedBy = body.resolvedBy;
|
|
396
|
+
}
|
|
397
|
+
}
|
|
398
|
+
catch {
|
|
399
|
+
// No body or invalid JSON — that's fine.
|
|
400
|
+
}
|
|
401
|
+
const approval = resolveApproval(id, "approved", resolvedBy);
|
|
402
|
+
if (!approval) {
|
|
403
|
+
return c.json({ error: "Approval not found" }, 404);
|
|
404
|
+
}
|
|
405
|
+
// Re-execute the original handler with the stored input.
|
|
406
|
+
const routeKey = `${approval.method} ${approval.path}`;
|
|
407
|
+
const handler = handlerRegistry.get(routeKey);
|
|
408
|
+
if (!handler) {
|
|
409
|
+
return c.json({ error: "Handler not found for route", route: routeKey }, 500);
|
|
410
|
+
}
|
|
411
|
+
try {
|
|
412
|
+
const ctx = createContext(c);
|
|
413
|
+
const result = await handler(approval.input, ctx);
|
|
414
|
+
approval.result = result;
|
|
415
|
+
return c.json({
|
|
416
|
+
status: "approved",
|
|
417
|
+
approvalId: approval.id,
|
|
418
|
+
result,
|
|
419
|
+
});
|
|
420
|
+
}
|
|
421
|
+
catch (err) {
|
|
422
|
+
const message = err instanceof Error ? err.message : "Handler execution failed";
|
|
423
|
+
return c.json({ error: message, approvalId: approval.id }, 500);
|
|
424
|
+
}
|
|
425
|
+
});
|
|
426
|
+
/** Deny a pending approval */
|
|
427
|
+
app.post("/capstan/approvals/:id/deny", async (c) => {
|
|
428
|
+
const id = c.req.param("id");
|
|
429
|
+
const existing = getApproval(id);
|
|
430
|
+
if (!existing) {
|
|
431
|
+
return c.json({ error: "Approval not found" }, 404);
|
|
432
|
+
}
|
|
433
|
+
if (existing.status !== "pending") {
|
|
434
|
+
return c.json({ error: "Approval already resolved", status: existing.status }, 409);
|
|
435
|
+
}
|
|
436
|
+
let resolvedBy;
|
|
437
|
+
let reason;
|
|
438
|
+
try {
|
|
439
|
+
const body = await c.req.json();
|
|
440
|
+
if (typeof body.resolvedBy === "string") {
|
|
441
|
+
resolvedBy = body.resolvedBy;
|
|
442
|
+
}
|
|
443
|
+
if (typeof body.reason === "string") {
|
|
444
|
+
reason = body.reason;
|
|
445
|
+
}
|
|
446
|
+
}
|
|
447
|
+
catch {
|
|
448
|
+
// No body or invalid JSON — that's fine.
|
|
449
|
+
}
|
|
450
|
+
const approval = resolveApproval(id, "denied", resolvedBy);
|
|
451
|
+
if (!approval) {
|
|
452
|
+
return c.json({ error: "Approval not found" }, 404);
|
|
453
|
+
}
|
|
454
|
+
return c.json({
|
|
455
|
+
status: "denied",
|
|
456
|
+
approvalId: approval.id,
|
|
457
|
+
...(reason !== undefined ? { reason } : {}),
|
|
458
|
+
});
|
|
459
|
+
});
|
|
460
|
+
// --- Framework endpoints --------------------------------------------------
|
|
461
|
+
// Agent manifest
|
|
462
|
+
app.get("/.well-known/capstan.json", (c) => {
|
|
463
|
+
const manifest = {
|
|
464
|
+
capstan: "1.0",
|
|
465
|
+
name: config.appName ?? "capstan-app",
|
|
466
|
+
description: config.appDescription ?? "",
|
|
467
|
+
authentication: {
|
|
468
|
+
schemes: [
|
|
469
|
+
{
|
|
470
|
+
type: "bearer",
|
|
471
|
+
name: "API Key",
|
|
472
|
+
header: "Authorization",
|
|
473
|
+
description: "Bearer token for agent authentication",
|
|
474
|
+
},
|
|
475
|
+
],
|
|
476
|
+
},
|
|
477
|
+
capabilities: routeRegistry.map((r) => ({
|
|
478
|
+
key: `${r.method} ${r.path}`,
|
|
479
|
+
title: r.description ?? `${r.method} ${r.path}`,
|
|
480
|
+
mode: (r.capability ?? "read"),
|
|
481
|
+
endpoint: {
|
|
482
|
+
method: r.method,
|
|
483
|
+
path: r.path,
|
|
484
|
+
},
|
|
485
|
+
})),
|
|
486
|
+
};
|
|
487
|
+
return c.json(manifest);
|
|
488
|
+
});
|
|
489
|
+
// OpenAPI spec
|
|
490
|
+
app.get("/openapi.json", (c) => {
|
|
491
|
+
const paths = {};
|
|
492
|
+
for (const r of routeRegistry) {
|
|
493
|
+
const pathKey = r.path.replace(/:(\w+)/g, "{$1}").replace(/\*/g, "{path}");
|
|
494
|
+
if (!paths[pathKey]) {
|
|
495
|
+
paths[pathKey] = {};
|
|
496
|
+
}
|
|
497
|
+
paths[pathKey][r.method.toLowerCase()] = {
|
|
498
|
+
summary: r.description ?? `${r.method} ${r.path}`,
|
|
499
|
+
operationId: `${r.method.toLowerCase()}_${r.path.replace(/[/:*]/g, "_").replace(/^_/, "")}`,
|
|
500
|
+
responses: {
|
|
501
|
+
"200": { description: "Successful response" },
|
|
502
|
+
},
|
|
503
|
+
...(r.inputSchema ? { requestBody: { content: { "application/json": { schema: r.inputSchema } } } } : {}),
|
|
504
|
+
};
|
|
505
|
+
}
|
|
506
|
+
const spec = {
|
|
507
|
+
openapi: "3.1.0",
|
|
508
|
+
info: {
|
|
509
|
+
title: config.appName ?? "capstan-app",
|
|
510
|
+
description: config.appDescription ?? "",
|
|
511
|
+
version: "0.1.0",
|
|
512
|
+
},
|
|
513
|
+
paths,
|
|
514
|
+
};
|
|
515
|
+
return c.json(spec);
|
|
516
|
+
});
|
|
517
|
+
// Health check
|
|
518
|
+
app.get("/health", (c) => {
|
|
519
|
+
return c.json({
|
|
520
|
+
status: "ok",
|
|
521
|
+
uptime: process.uptime(),
|
|
522
|
+
timestamp: new Date().toISOString(),
|
|
523
|
+
});
|
|
524
|
+
});
|
|
525
|
+
// --- A2A endpoints ---------------------------------------------------------
|
|
526
|
+
// GET /.well-known/agent.json — A2A Agent Card discovery
|
|
527
|
+
// POST /.well-known/a2a — A2A JSON-RPC task handler
|
|
528
|
+
app.get("/.well-known/agent.json", async (c) => {
|
|
529
|
+
try {
|
|
530
|
+
const agentModuleName = "@zauso-ai/capstan-agent";
|
|
531
|
+
const agentPkg = (await import(agentModuleName));
|
|
532
|
+
const card = agentPkg.generateA2AAgentCard({
|
|
533
|
+
name: config.appName ?? "capstan-app",
|
|
534
|
+
...(config.appDescription ? { description: config.appDescription } : {}),
|
|
535
|
+
baseUrl: `http://${config.host ?? "localhost"}:${config.port ?? 3000}`,
|
|
536
|
+
}, routeRegistry);
|
|
537
|
+
return c.json(card);
|
|
538
|
+
}
|
|
539
|
+
catch {
|
|
540
|
+
return c.json({ error: "@zauso-ai/capstan-agent not available — A2A disabled" }, 501);
|
|
541
|
+
}
|
|
542
|
+
});
|
|
543
|
+
app.post("/.well-known/a2a", async (c) => {
|
|
544
|
+
try {
|
|
545
|
+
const agentModuleName = "@zauso-ai/capstan-agent";
|
|
546
|
+
const agentPkg = (await import(agentModuleName));
|
|
547
|
+
const executeRoute = async (method, urlPath, input) => {
|
|
548
|
+
const url = `http://localhost:${config.port ?? 3000}${urlPath}`;
|
|
549
|
+
const init = {
|
|
550
|
+
method,
|
|
551
|
+
headers: { "Content-Type": "application/json" },
|
|
552
|
+
};
|
|
553
|
+
if (method !== "GET" && method !== "HEAD" && input !== undefined) {
|
|
554
|
+
init.body = JSON.stringify(input);
|
|
555
|
+
}
|
|
556
|
+
const request = new Request(url, init);
|
|
557
|
+
// Use the outer Hono app reference for internal dispatch.
|
|
558
|
+
const response = await app.fetch(request);
|
|
559
|
+
try {
|
|
560
|
+
return await response.json();
|
|
561
|
+
}
|
|
562
|
+
catch {
|
|
563
|
+
return { status: response.status, body: await response.text() };
|
|
564
|
+
}
|
|
565
|
+
};
|
|
566
|
+
const handler = agentPkg.createA2AHandler({
|
|
567
|
+
name: config.appName ?? "capstan-app",
|
|
568
|
+
...(config.appDescription ? { description: config.appDescription } : {}),
|
|
569
|
+
baseUrl: `http://${config.host ?? "localhost"}:${config.port ?? 3000}`,
|
|
570
|
+
}, routeRegistry, executeRoute);
|
|
571
|
+
const body = await c.req.json();
|
|
572
|
+
const result = await handler.handleRequest(body);
|
|
573
|
+
return c.json(result);
|
|
574
|
+
}
|
|
575
|
+
catch {
|
|
576
|
+
return c.json({
|
|
577
|
+
jsonrpc: "2.0",
|
|
578
|
+
id: null,
|
|
579
|
+
error: {
|
|
580
|
+
code: -32603,
|
|
581
|
+
message: "@zauso-ai/capstan-agent not available — A2A disabled",
|
|
582
|
+
},
|
|
583
|
+
}, 501);
|
|
584
|
+
}
|
|
585
|
+
});
|
|
586
|
+
// --- MCP discovery endpoint -----------------------------------------------
|
|
587
|
+
// POST /.well-known/mcp returns a JSON description of available MCP tools
|
|
588
|
+
// so that agents can discover capabilities without connecting via stdio.
|
|
589
|
+
app.post("/.well-known/mcp", async (c) => {
|
|
590
|
+
try {
|
|
591
|
+
const agentModuleName = "@zauso-ai/capstan-agent";
|
|
592
|
+
const agentPkg = (await import(agentModuleName));
|
|
593
|
+
const tools = routeRegistry.map((r) => ({
|
|
594
|
+
name: agentPkg.routeToToolName(r.method, r.path),
|
|
595
|
+
description: r.description ?? `${r.method} ${r.path}`,
|
|
596
|
+
method: r.method,
|
|
597
|
+
path: r.path,
|
|
598
|
+
inputSchema: r.inputSchema ?? { type: "object", properties: {} },
|
|
599
|
+
}));
|
|
600
|
+
return c.json({
|
|
601
|
+
protocol: "mcp",
|
|
602
|
+
version: "1.0",
|
|
603
|
+
name: config.appName ?? "capstan-app",
|
|
604
|
+
tools,
|
|
605
|
+
});
|
|
606
|
+
}
|
|
607
|
+
catch {
|
|
608
|
+
// @zauso-ai/capstan-agent not available
|
|
609
|
+
return c.json({
|
|
610
|
+
protocol: "mcp",
|
|
611
|
+
version: "1.0",
|
|
612
|
+
name: config.appName ?? "capstan-app",
|
|
613
|
+
tools: [],
|
|
614
|
+
error: "@zauso-ai/capstan-agent not available",
|
|
615
|
+
});
|
|
616
|
+
}
|
|
617
|
+
});
|
|
618
|
+
return { app, apiRouteCount, pageRouteCount, routeRegistry };
|
|
619
|
+
}
|
|
620
|
+
// ---------------------------------------------------------------------------
|
|
621
|
+
// Public API
|
|
622
|
+
// ---------------------------------------------------------------------------
|
|
623
|
+
/**
|
|
624
|
+
* Create and return a dev server instance that:
|
|
625
|
+
*
|
|
626
|
+
* 1. Scans `app/routes/` for route files
|
|
627
|
+
* 2. Creates a Hono server with all routes registered
|
|
628
|
+
* 3. Starts an HTTP server on the configured port
|
|
629
|
+
* 4. Watches for file changes and re-builds routes
|
|
630
|
+
* 5. Serves the agent manifest, OpenAPI spec, and health endpoint
|
|
631
|
+
* 6. Prints a startup banner with URLs and route counts
|
|
632
|
+
*/
|
|
633
|
+
export async function createDevServer(config) {
|
|
634
|
+
const port = config.port ?? 3000;
|
|
635
|
+
const host = config.host ?? "0.0.0.0";
|
|
636
|
+
const routesDir = path.join(config.rootDir, "app", "routes");
|
|
637
|
+
// --- Initial route scan ---------------------------------------------------
|
|
638
|
+
let manifest = await scanRoutes(routesDir);
|
|
639
|
+
let { app, apiRouteCount, pageRouteCount, routeRegistry } = await buildApp(manifest, config);
|
|
640
|
+
// The Node.js HTTP server holds a reference to the current Hono app.
|
|
641
|
+
// When routes change we rebuild the app and swap the reference -- in-flight
|
|
642
|
+
// requests finish against the old app while new requests hit the new one.
|
|
643
|
+
let currentApp = app;
|
|
644
|
+
let mcpInstance = null;
|
|
645
|
+
async function buildMcpServer() {
|
|
646
|
+
try {
|
|
647
|
+
const agentModuleName = "@zauso-ai/capstan-agent";
|
|
648
|
+
const agentPkg = (await import(agentModuleName));
|
|
649
|
+
const executeRoute = async (method, urlPath, input) => {
|
|
650
|
+
const url = `http://localhost:${port}${urlPath}`;
|
|
651
|
+
const init = {
|
|
652
|
+
method,
|
|
653
|
+
headers: { "Content-Type": "application/json" },
|
|
654
|
+
};
|
|
655
|
+
if (method !== "GET" && method !== "HEAD" && input !== undefined) {
|
|
656
|
+
init.body = JSON.stringify(input);
|
|
657
|
+
}
|
|
658
|
+
const request = new Request(url, init);
|
|
659
|
+
const response = await currentApp.fetch(request);
|
|
660
|
+
try {
|
|
661
|
+
return await response.json();
|
|
662
|
+
}
|
|
663
|
+
catch {
|
|
664
|
+
return { status: response.status, body: await response.text() };
|
|
665
|
+
}
|
|
666
|
+
};
|
|
667
|
+
mcpInstance = agentPkg.createMcpServer({
|
|
668
|
+
name: config.appName ?? "capstan-app",
|
|
669
|
+
...(config.appDescription ? { description: config.appDescription } : {}),
|
|
670
|
+
}, routeRegistry, executeRoute);
|
|
671
|
+
}
|
|
672
|
+
catch {
|
|
673
|
+
// @zauso-ai/capstan-agent not available — MCP disabled.
|
|
674
|
+
mcpInstance = null;
|
|
675
|
+
}
|
|
676
|
+
}
|
|
677
|
+
await buildMcpServer();
|
|
678
|
+
// --- HTTP server ----------------------------------------------------------
|
|
679
|
+
const server = createServer(async (req, res) => {
|
|
680
|
+
try {
|
|
681
|
+
const url = new URL(req.url ?? "/", `http://${req.headers.host ?? `${host}:${port}`}`);
|
|
682
|
+
// Build a Web API Request from the Node.js IncomingMessage.
|
|
683
|
+
const headers = new Headers();
|
|
684
|
+
for (const [key, value] of Object.entries(req.headers)) {
|
|
685
|
+
if (value === undefined)
|
|
686
|
+
continue;
|
|
687
|
+
if (Array.isArray(value)) {
|
|
688
|
+
for (const v of value) {
|
|
689
|
+
headers.append(key, v);
|
|
690
|
+
}
|
|
691
|
+
}
|
|
692
|
+
else {
|
|
693
|
+
headers.set(key, value);
|
|
694
|
+
}
|
|
695
|
+
}
|
|
696
|
+
const hasBody = req.method !== "GET" && req.method !== "HEAD";
|
|
697
|
+
let body;
|
|
698
|
+
if (hasBody) {
|
|
699
|
+
const raw = await readBody(req);
|
|
700
|
+
body = raw !== undefined ? (typeof raw === "string" ? raw : JSON.stringify(raw)) : undefined;
|
|
701
|
+
}
|
|
702
|
+
const init = {
|
|
703
|
+
method: req.method ?? "GET",
|
|
704
|
+
headers,
|
|
705
|
+
};
|
|
706
|
+
if (body !== undefined) {
|
|
707
|
+
init.body = body;
|
|
708
|
+
}
|
|
709
|
+
const request = new Request(url.toString(), init);
|
|
710
|
+
const response = await currentApp.fetch(request);
|
|
711
|
+
// Write the Hono response back through the Node.js response.
|
|
712
|
+
res.writeHead(response.status, Object.fromEntries(response.headers.entries()));
|
|
713
|
+
const responseBody = await response.text();
|
|
714
|
+
res.end(responseBody);
|
|
715
|
+
}
|
|
716
|
+
catch (err) {
|
|
717
|
+
// eslint-disable-next-line no-console
|
|
718
|
+
console.error("[capstan] Unhandled request error:", err);
|
|
719
|
+
if (!res.headersSent) {
|
|
720
|
+
res.writeHead(500, { "Content-Type": "application/json" });
|
|
721
|
+
}
|
|
722
|
+
res.end(JSON.stringify({ error: "Internal Server Error" }));
|
|
723
|
+
}
|
|
724
|
+
});
|
|
725
|
+
// --- File watcher ---------------------------------------------------------
|
|
726
|
+
async function rebuildRoutes() {
|
|
727
|
+
try {
|
|
728
|
+
// eslint-disable-next-line no-console
|
|
729
|
+
console.log("[capstan] Routes changed, rebuilding...");
|
|
730
|
+
manifest = await scanRoutes(routesDir);
|
|
731
|
+
const rebuilt = await buildApp(manifest, config);
|
|
732
|
+
currentApp = rebuilt.app;
|
|
733
|
+
apiRouteCount = rebuilt.apiRouteCount;
|
|
734
|
+
pageRouteCount = rebuilt.pageRouteCount;
|
|
735
|
+
routeRegistry = rebuilt.routeRegistry;
|
|
736
|
+
// Rebuild MCP server with updated routes.
|
|
737
|
+
await buildMcpServer();
|
|
738
|
+
const totalRoutes = apiRouteCount + pageRouteCount;
|
|
739
|
+
// eslint-disable-next-line no-console
|
|
740
|
+
console.log(`[capstan] Rebuilt: ${totalRoutes} routes (${apiRouteCount} API, ${pageRouteCount} pages)`);
|
|
741
|
+
}
|
|
742
|
+
catch (err) {
|
|
743
|
+
// eslint-disable-next-line no-console
|
|
744
|
+
console.error("[capstan] Failed to rebuild routes:", err instanceof Error ? err.message : err);
|
|
745
|
+
}
|
|
746
|
+
}
|
|
747
|
+
const watcher = watchRoutes(routesDir, () => {
|
|
748
|
+
void rebuildRoutes();
|
|
749
|
+
});
|
|
750
|
+
// --- DevServerInstance ----------------------------------------------------
|
|
751
|
+
const instance = {
|
|
752
|
+
port,
|
|
753
|
+
host,
|
|
754
|
+
start() {
|
|
755
|
+
return new Promise((resolve, reject) => {
|
|
756
|
+
server.on("error", (err) => {
|
|
757
|
+
reject(err);
|
|
758
|
+
});
|
|
759
|
+
server.listen(port, host, () => {
|
|
760
|
+
printStartupBanner({
|
|
761
|
+
appName: config.appName ?? "capstan-app",
|
|
762
|
+
port,
|
|
763
|
+
host,
|
|
764
|
+
routeCount: apiRouteCount + pageRouteCount,
|
|
765
|
+
apiRouteCount,
|
|
766
|
+
pageRouteCount,
|
|
767
|
+
});
|
|
768
|
+
resolve();
|
|
769
|
+
});
|
|
770
|
+
});
|
|
771
|
+
},
|
|
772
|
+
stop() {
|
|
773
|
+
return new Promise((resolve, reject) => {
|
|
774
|
+
watcher.close();
|
|
775
|
+
server.close((err) => {
|
|
776
|
+
if (err) {
|
|
777
|
+
reject(err);
|
|
778
|
+
}
|
|
779
|
+
else {
|
|
780
|
+
resolve();
|
|
781
|
+
}
|
|
782
|
+
});
|
|
783
|
+
});
|
|
784
|
+
},
|
|
785
|
+
};
|
|
786
|
+
return instance;
|
|
787
|
+
}
|
|
788
|
+
//# sourceMappingURL=server.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"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"}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
export interface DevServerConfig {
|
|
2
|
+
/** Root directory of the Capstan app (contains app/ directory) */
|
|
3
|
+
rootDir: string;
|
|
4
|
+
/** Port to listen on */
|
|
5
|
+
port?: number;
|
|
6
|
+
/** Host to bind to */
|
|
7
|
+
host?: string;
|
|
8
|
+
/** App name for manifests */
|
|
9
|
+
appName?: string;
|
|
10
|
+
/** App description */
|
|
11
|
+
appDescription?: string;
|
|
12
|
+
/** Auth configuration — when set, session cookie / API key auth is enabled */
|
|
13
|
+
auth?: {
|
|
14
|
+
session: {
|
|
15
|
+
secret: string;
|
|
16
|
+
maxAge?: string;
|
|
17
|
+
};
|
|
18
|
+
apiKeys?: {
|
|
19
|
+
prefix?: string;
|
|
20
|
+
headerName?: string;
|
|
21
|
+
};
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
export interface DevServerInstance {
|
|
25
|
+
/** Start the dev server */
|
|
26
|
+
start(): Promise<void>;
|
|
27
|
+
/** Stop the dev server */
|
|
28
|
+
stop(): Promise<void>;
|
|
29
|
+
/** Current port */
|
|
30
|
+
port: number;
|
|
31
|
+
/** Current host */
|
|
32
|
+
host: string;
|
|
33
|
+
}
|
|
34
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,eAAe;IAC9B,kEAAkE;IAClE,OAAO,EAAE,MAAM,CAAC;IAChB,wBAAwB;IACxB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,sBAAsB;IACtB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,6BAA6B;IAC7B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,sBAAsB;IACtB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,8EAA8E;IAC9E,IAAI,CAAC,EAAE;QACL,OAAO,EAAE;YACP,MAAM,EAAE,MAAM,CAAC;YACf,MAAM,CAAC,EAAE,MAAM,CAAC;SACjB,CAAC;QACF,OAAO,CAAC,EAAE;YACR,MAAM,CAAC,EAAE,MAAM,CAAC;YAChB,UAAU,CAAC,EAAE,MAAM,CAAC;SACrB,CAAC;KACH,CAAC;CACH;AAED,MAAM,WAAW,iBAAiB;IAChC,2BAA2B;IAC3B,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IACvB,0BAA0B;IAC1B,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IACtB,mBAAmB;IACnB,IAAI,EAAE,MAAM,CAAC;IACb,mBAAmB;IACnB,IAAI,EAAE,MAAM,CAAC;CACd"}
|
package/dist/types.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Watch a routes directory for file changes and invoke a callback when
|
|
3
|
+
* route files (.ts, .tsx) are added, modified, or removed.
|
|
4
|
+
*
|
|
5
|
+
* Uses `node:fs.watch` in recursive mode with a 300ms debounce to
|
|
6
|
+
* coalesce rapid filesystem events (e.g. editor save + lint writes).
|
|
7
|
+
*
|
|
8
|
+
* Gracefully handles the case where the routes directory does not yet
|
|
9
|
+
* exist -- the caller should create it and restart the watcher.
|
|
10
|
+
*/
|
|
11
|
+
export declare function watchRoutes(routesDir: string, onChange: () => void): {
|
|
12
|
+
close: () => void;
|
|
13
|
+
};
|
|
14
|
+
//# sourceMappingURL=watcher.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"watcher.d.ts","sourceRoot":"","sources":["../src/watcher.ts"],"names":[],"mappings":"AAGA;;;;;;;;;GASG;AACH,wBAAgB,WAAW,CACzB,SAAS,EAAE,MAAM,EACjB,QAAQ,EAAE,MAAM,IAAI,GACnB;IAAE,KAAK,EAAE,MAAM,IAAI,CAAA;CAAE,CAiEvB"}
|
package/dist/watcher.js
ADDED
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { watch, existsSync } from "node:fs";
|
|
2
|
+
/**
|
|
3
|
+
* Watch a routes directory for file changes and invoke a callback when
|
|
4
|
+
* route files (.ts, .tsx) are added, modified, or removed.
|
|
5
|
+
*
|
|
6
|
+
* Uses `node:fs.watch` in recursive mode with a 300ms debounce to
|
|
7
|
+
* coalesce rapid filesystem events (e.g. editor save + lint writes).
|
|
8
|
+
*
|
|
9
|
+
* Gracefully handles the case where the routes directory does not yet
|
|
10
|
+
* exist -- the caller should create it and restart the watcher.
|
|
11
|
+
*/
|
|
12
|
+
export function watchRoutes(routesDir, onChange) {
|
|
13
|
+
// If the directory doesn't exist, return a no-op watcher.
|
|
14
|
+
// The dev server will retry on next explicit scan.
|
|
15
|
+
if (!existsSync(routesDir)) {
|
|
16
|
+
return { close: () => { } };
|
|
17
|
+
}
|
|
18
|
+
let debounceTimer = null;
|
|
19
|
+
let closed = false;
|
|
20
|
+
const DEBOUNCE_MS = 300;
|
|
21
|
+
/** Route-file extensions we care about. */
|
|
22
|
+
const ROUTE_EXTENSIONS = [".ts", ".tsx"];
|
|
23
|
+
function isRouteFile(filename) {
|
|
24
|
+
if (!filename)
|
|
25
|
+
return false;
|
|
26
|
+
return ROUTE_EXTENSIONS.some((ext) => filename.endsWith(ext));
|
|
27
|
+
}
|
|
28
|
+
function scheduleCallback() {
|
|
29
|
+
if (closed)
|
|
30
|
+
return;
|
|
31
|
+
if (debounceTimer !== null) {
|
|
32
|
+
clearTimeout(debounceTimer);
|
|
33
|
+
}
|
|
34
|
+
debounceTimer = setTimeout(() => {
|
|
35
|
+
debounceTimer = null;
|
|
36
|
+
if (!closed) {
|
|
37
|
+
onChange();
|
|
38
|
+
}
|
|
39
|
+
}, DEBOUNCE_MS);
|
|
40
|
+
}
|
|
41
|
+
let watcher;
|
|
42
|
+
try {
|
|
43
|
+
watcher = watch(routesDir, { recursive: true }, (_eventType, filename) => {
|
|
44
|
+
if (isRouteFile(filename ?? null)) {
|
|
45
|
+
scheduleCallback();
|
|
46
|
+
}
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
catch {
|
|
50
|
+
// If watching fails (e.g. permission error), return a no-op handle.
|
|
51
|
+
return { close: () => { } };
|
|
52
|
+
}
|
|
53
|
+
// Handle watcher errors silently -- the dev server keeps running
|
|
54
|
+
// and the user can still trigger manual reloads.
|
|
55
|
+
watcher.on("error", () => {
|
|
56
|
+
// Intentionally swallowed. The server remains usable even if the
|
|
57
|
+
// watcher encounters a transient filesystem error.
|
|
58
|
+
});
|
|
59
|
+
return {
|
|
60
|
+
close: () => {
|
|
61
|
+
closed = true;
|
|
62
|
+
if (debounceTimer !== null) {
|
|
63
|
+
clearTimeout(debounceTimer);
|
|
64
|
+
debounceTimer = null;
|
|
65
|
+
}
|
|
66
|
+
watcher.close();
|
|
67
|
+
},
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
//# sourceMappingURL=watcher.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"watcher.js","sourceRoot":"","sources":["../src/watcher.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AAG5C;;;;;;;;;GASG;AACH,MAAM,UAAU,WAAW,CACzB,SAAiB,EACjB,QAAoB;IAEpB,0DAA0D;IAC1D,mDAAmD;IACnD,IAAI,CAAC,UAAU,CAAC,SAAS,CAAC,EAAE,CAAC;QAC3B,OAAO,EAAE,KAAK,EAAE,GAAG,EAAE,GAAE,CAAC,EAAE,CAAC;IAC7B,CAAC;IAED,IAAI,aAAa,GAAyC,IAAI,CAAC;IAC/D,IAAI,MAAM,GAAG,KAAK,CAAC;IAEnB,MAAM,WAAW,GAAG,GAAG,CAAC;IAExB,2CAA2C;IAC3C,MAAM,gBAAgB,GAAG,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC;IAEzC,SAAS,WAAW,CAAC,QAAuB;QAC1C,IAAI,CAAC,QAAQ;YAAE,OAAO,KAAK,CAAC;QAC5B,OAAO,gBAAgB,CAAC,IAAI,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,QAAQ,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC;IAChE,CAAC;IAED,SAAS,gBAAgB;QACvB,IAAI,MAAM;YAAE,OAAO;QAEnB,IAAI,aAAa,KAAK,IAAI,EAAE,CAAC;YAC3B,YAAY,CAAC,aAAa,CAAC,CAAC;QAC9B,CAAC;QAED,aAAa,GAAG,UAAU,CAAC,GAAG,EAAE;YAC9B,aAAa,GAAG,IAAI,CAAC;YACrB,IAAI,CAAC,MAAM,EAAE,CAAC;gBACZ,QAAQ,EAAE,CAAC;YACb,CAAC;QACH,CAAC,EAAE,WAAW,CAAC,CAAC;IAClB,CAAC;IAED,IAAI,OAAkB,CAAC;IAEvB,IAAI,CAAC;QACH,OAAO,GAAG,KAAK,CAAC,SAAS,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,EAAE,CAAC,UAAU,EAAE,QAAQ,EAAE,EAAE;YACvE,IAAI,WAAW,CAAC,QAAQ,IAAI,IAAI,CAAC,EAAE,CAAC;gBAClC,gBAAgB,EAAE,CAAC;YACrB,CAAC;QACH,CAAC,CAAC,CAAC;IACL,CAAC;IAAC,MAAM,CAAC;QACP,oEAAoE;QACpE,OAAO,EAAE,KAAK,EAAE,GAAG,EAAE,GAAE,CAAC,EAAE,CAAC;IAC7B,CAAC;IAED,iEAAiE;IACjE,iDAAiD;IACjD,OAAO,CAAC,EAAE,CAAC,OAAO,EAAE,GAAG,EAAE;QACvB,iEAAiE;QACjE,mDAAmD;IACrD,CAAC,CAAC,CAAC;IAEH,OAAO;QACL,KAAK,EAAE,GAAG,EAAE;YACV,MAAM,GAAG,IAAI,CAAC;YACd,IAAI,aAAa,KAAK,IAAI,EAAE,CAAC;gBAC3B,YAAY,CAAC,aAAa,CAAC,CAAC;gBAC5B,aAAa,GAAG,IAAI,CAAC;YACvB,CAAC;YACD,OAAO,CAAC,KAAK,EAAE,CAAC;QAClB,CAAC;KACF,CAAC;AACJ,CAAC"}
|
package/package.json
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@zauso-ai/capstan-dev",
|
|
3
|
+
"version": "0.1.2",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"main": "./dist/index.js",
|
|
6
|
+
"types": "./dist/index.d.ts",
|
|
7
|
+
"exports": {
|
|
8
|
+
".": {
|
|
9
|
+
"types": "./dist/index.d.ts",
|
|
10
|
+
"import": "./dist/index.js"
|
|
11
|
+
}
|
|
12
|
+
},
|
|
13
|
+
"files": [
|
|
14
|
+
"dist"
|
|
15
|
+
],
|
|
16
|
+
"scripts": {
|
|
17
|
+
"build": "tsc -p tsconfig.json",
|
|
18
|
+
"typecheck": "tsc -p tsconfig.json --noEmit"
|
|
19
|
+
},
|
|
20
|
+
"dependencies": {
|
|
21
|
+
"@zauso-ai/capstan-agent": "*",
|
|
22
|
+
"@zauso-ai/capstan-auth": "*",
|
|
23
|
+
"@zauso-ai/capstan-core": "*",
|
|
24
|
+
"@zauso-ai/capstan-router": "*",
|
|
25
|
+
"hono": "^4.0.0"
|
|
26
|
+
},
|
|
27
|
+
"description": "Dev server for Capstan — file watching, hot route reload, MCP/A2A endpoints",
|
|
28
|
+
"repository": {
|
|
29
|
+
"type": "git",
|
|
30
|
+
"url": "https://github.com/barry3406/capstan.git",
|
|
31
|
+
"directory": "packages/dev"
|
|
32
|
+
},
|
|
33
|
+
"license": "MIT",
|
|
34
|
+
"author": "barry3406",
|
|
35
|
+
"homepage": "https://github.com/barry3406/capstan",
|
|
36
|
+
"keywords": [
|
|
37
|
+
"capstan",
|
|
38
|
+
"ai-agent",
|
|
39
|
+
"full-stack",
|
|
40
|
+
"framework",
|
|
41
|
+
"mcp",
|
|
42
|
+
"a2a",
|
|
43
|
+
"typescript"
|
|
44
|
+
],
|
|
45
|
+
"publishConfig": {
|
|
46
|
+
"access": "public"
|
|
47
|
+
}
|
|
48
|
+
}
|