@executioncontrolprotocol/cli 0.10.0 → 0.11.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 +61 -0
- package/dist/commands/invoke.d.ts +17 -0
- package/dist/commands/invoke.d.ts.map +1 -0
- package/dist/commands/invoke.js +47 -0
- package/dist/commands/invoke.js.map +1 -0
- package/dist/commands/serve.d.ts +15 -0
- package/dist/commands/serve.d.ts.map +1 -0
- package/dist/commands/serve.js +53 -0
- package/dist/commands/serve.js.map +1 -0
- package/dist/commands/test/rerun.d.ts +16 -0
- package/dist/commands/test/rerun.d.ts.map +1 -0
- package/dist/commands/test/rerun.js +38 -0
- package/dist/commands/test/rerun.js.map +1 -0
- package/dist/commands/test/run.d.ts +14 -0
- package/dist/commands/test/run.d.ts.map +1 -0
- package/dist/commands/test/run.js +36 -0
- package/dist/commands/test/run.js.map +1 -0
- package/dist/commands/test/start.d.ts +17 -0
- package/dist/commands/test/start.d.ts.map +1 -0
- package/dist/commands/test/start.js +43 -0
- package/dist/commands/test/start.js.map +1 -0
- package/dist/commands/test/status.d.ts +12 -0
- package/dist/commands/test/status.d.ts.map +1 -0
- package/dist/commands/test/status.js +24 -0
- package/dist/commands/test/status.js.map +1 -0
- package/dist/commands/test.d.ts +9 -0
- package/dist/commands/test.d.ts.map +1 -0
- package/dist/commands/test.js +32 -0
- package/dist/commands/test.js.map +1 -0
- package/dist/commands/up.d.ts +18 -0
- package/dist/commands/up.d.ts.map +1 -0
- package/dist/commands/up.js +95 -0
- package/dist/commands/up.js.map +1 -0
- package/dist/lib/http/create-serve-handler.d.ts +15 -0
- package/dist/lib/http/create-serve-handler.d.ts.map +1 -0
- package/dist/lib/http/create-serve-handler.js +34 -0
- package/dist/lib/http/create-serve-handler.js.map +1 -0
- package/dist/lib/http/create-serve.d.ts +30 -0
- package/dist/lib/http/create-serve.d.ts.map +1 -0
- package/dist/lib/http/create-serve.js +43 -0
- package/dist/lib/http/create-serve.js.map +1 -0
- package/dist/lib/http/handle-invoke.d.ts +42 -0
- package/dist/lib/http/handle-invoke.d.ts.map +1 -0
- package/dist/lib/http/handle-invoke.js +66 -0
- package/dist/lib/http/handle-invoke.js.map +1 -0
- package/dist/lib/http/read-body.d.ts +7 -0
- package/dist/lib/http/read-body.d.ts.map +1 -0
- package/dist/lib/http/read-body.js +12 -0
- package/dist/lib/http/read-body.js.map +1 -0
- package/dist/lib/http/write-json.d.ts +7 -0
- package/dist/lib/http/write-json.d.ts.map +1 -0
- package/dist/lib/http/write-json.js +11 -0
- package/dist/lib/http/write-json.js.map +1 -0
- package/dist/lib/test-session-io.d.ts +12 -0
- package/dist/lib/test-session-io.d.ts.map +1 -0
- package/dist/lib/test-session-io.js +36 -0
- package/dist/lib/test-session-io.js.map +1 -0
- package/dist/lib/up/constants.d.ts +15 -0
- package/dist/lib/up/constants.d.ts.map +1 -0
- package/dist/lib/up/constants.js +21 -0
- package/dist/lib/up/constants.js.map +1 -0
- package/dist/lib/up/cors.d.ts +12 -0
- package/dist/lib/up/cors.d.ts.map +1 -0
- package/dist/lib/up/cors.js +28 -0
- package/dist/lib/up/cors.js.map +1 -0
- package/dist/lib/up/create-daemon.d.ts +37 -0
- package/dist/lib/up/create-daemon.d.ts.map +1 -0
- package/dist/lib/up/create-daemon.js +63 -0
- package/dist/lib/up/create-daemon.js.map +1 -0
- package/dist/lib/up/handle-request.d.ts +19 -0
- package/dist/lib/up/handle-request.d.ts.map +1 -0
- package/dist/lib/up/handle-request.js +49 -0
- package/dist/lib/up/handle-request.js.map +1 -0
- package/dist/lib/up/open-browser.d.ts +19 -0
- package/dist/lib/up/open-browser.d.ts.map +1 -0
- package/dist/lib/up/open-browser.js +43 -0
- package/dist/lib/up/open-browser.js.map +1 -0
- package/dist/lib/up/read-body.d.ts +3 -0
- package/dist/lib/up/read-body.d.ts.map +1 -0
- package/dist/lib/up/read-body.js +3 -0
- package/dist/lib/up/read-body.js.map +1 -0
- package/package.json +8 -7
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import { randomUUID } from "node:crypto";
|
|
2
|
+
import { Command, Flags } from "@oclif/core";
|
|
3
|
+
import { DEFAULT_DEMO_OPEN_URL, DEFAULT_ECP_UP_HOST, DEFAULT_ECP_UP_PORT, DEFAULT_OLLAMA_URL, } from "../lib/up/constants.js";
|
|
4
|
+
import { startEcpUpDaemon } from "../lib/up/create-daemon.js";
|
|
5
|
+
import { buildDemoOpenUrl, openBrowserUrl, originFromUrl } from "../lib/up/open-browser.js";
|
|
6
|
+
/** Start the local ECP daemon (bridges Ollama for the browser demo). */
|
|
7
|
+
export default class Up extends Command {
|
|
8
|
+
static summary = "Start the local ECP daemon";
|
|
9
|
+
static description = "Run a loopback HTTP daemon that exposes ECP invoke for local Ollama " +
|
|
10
|
+
"(CORS + Private Network Access). Opens the browser demo with ?token= for pairing.";
|
|
11
|
+
static examples = [
|
|
12
|
+
"<%= config.bin %> <%= command.id %>",
|
|
13
|
+
"<%= config.bin %> <%= command.id %> --open-url http://localhost:5173/",
|
|
14
|
+
"<%= config.bin %> <%= command.id %> --no-open",
|
|
15
|
+
];
|
|
16
|
+
static flags = {
|
|
17
|
+
port: Flags.integer({
|
|
18
|
+
description: "Listen port (ECP leet default 3090)",
|
|
19
|
+
default: DEFAULT_ECP_UP_PORT,
|
|
20
|
+
}),
|
|
21
|
+
host: Flags.string({
|
|
22
|
+
description: "Bind host (loopback only by default)",
|
|
23
|
+
default: DEFAULT_ECP_UP_HOST,
|
|
24
|
+
}),
|
|
25
|
+
"ollama-url": Flags.string({
|
|
26
|
+
description: "Ollama HTTP API base URL",
|
|
27
|
+
default: DEFAULT_OLLAMA_URL,
|
|
28
|
+
}),
|
|
29
|
+
"cors-origin": Flags.string({
|
|
30
|
+
description: "Extra allowed CORS origin (repeatable)",
|
|
31
|
+
multiple: true,
|
|
32
|
+
default: [],
|
|
33
|
+
}),
|
|
34
|
+
token: Flags.string({
|
|
35
|
+
description: "Pairing token for /v1/invoke (auto-generated if omitted)",
|
|
36
|
+
}),
|
|
37
|
+
"open-url": Flags.string({
|
|
38
|
+
description: "Browser demo URL to open with ?token= (pairing)",
|
|
39
|
+
default: DEFAULT_DEMO_OPEN_URL,
|
|
40
|
+
}),
|
|
41
|
+
open: Flags.boolean({
|
|
42
|
+
description: "Open the browser demo after the daemon starts",
|
|
43
|
+
allowNo: true,
|
|
44
|
+
default: true,
|
|
45
|
+
}),
|
|
46
|
+
};
|
|
47
|
+
async run() {
|
|
48
|
+
const { flags } = await this.parse(Up);
|
|
49
|
+
const token = flags.token ?? randomUUID();
|
|
50
|
+
const openUrl = flags["open-url"];
|
|
51
|
+
const openOrigin = originFromUrl(openUrl);
|
|
52
|
+
const corsOrigins = [
|
|
53
|
+
...flags["cors-origin"],
|
|
54
|
+
...(openOrigin ? [openOrigin] : []),
|
|
55
|
+
];
|
|
56
|
+
const daemon = await startEcpUpDaemon({
|
|
57
|
+
port: flags.port,
|
|
58
|
+
host: flags.host,
|
|
59
|
+
ollamaUrl: flags["ollama-url"],
|
|
60
|
+
corsOrigins,
|
|
61
|
+
token,
|
|
62
|
+
});
|
|
63
|
+
const bridgeBaseURL = `http://${daemon.host}:${daemon.port}`;
|
|
64
|
+
const demoUrl = buildDemoOpenUrl(openUrl, {
|
|
65
|
+
token: daemon.token,
|
|
66
|
+
bridgeBaseURL,
|
|
67
|
+
});
|
|
68
|
+
this.log(`ECP daemon on ${bridgeBaseURL}`);
|
|
69
|
+
this.log(`Pairing token: ${daemon.token}`);
|
|
70
|
+
this.log("GET /health (no auth) · POST /v1/invoke (Bearer token)");
|
|
71
|
+
if (flags.open) {
|
|
72
|
+
this.log(`Opening ${demoUrl}`);
|
|
73
|
+
try {
|
|
74
|
+
openBrowserUrl(demoUrl);
|
|
75
|
+
}
|
|
76
|
+
catch (err) {
|
|
77
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
78
|
+
this.warn(`Could not open browser: ${message}`);
|
|
79
|
+
this.log(`Open manually: ${demoUrl}`);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
else {
|
|
83
|
+
this.log(`Demo URL: ${demoUrl}`);
|
|
84
|
+
}
|
|
85
|
+
this.log("Press Ctrl+C to stop.");
|
|
86
|
+
await new Promise((resolve) => {
|
|
87
|
+
const shutdown = () => {
|
|
88
|
+
void daemon.close().finally(() => resolve());
|
|
89
|
+
};
|
|
90
|
+
process.once("SIGINT", shutdown);
|
|
91
|
+
process.once("SIGTERM", shutdown);
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
//# sourceMappingURL=up.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"up.js","sourceRoot":"","sources":["../../src/commands/up.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { IncomingMessage, ServerResponse } from "node:http";
|
|
2
|
+
import type { Ecp } from "@executioncontrolprotocol/core";
|
|
3
|
+
/** Dependencies for {@link createServeRequestHandler}. @category CLI */
|
|
4
|
+
export interface ServeRequestHandlerOptions {
|
|
5
|
+
/** Operational ECP instance. */
|
|
6
|
+
ecp: Ecp;
|
|
7
|
+
/** Allowlisted CORS origins (empty = no CORS reflection). */
|
|
8
|
+
allowOrigins: ReadonlySet<string>;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Create the HTTP request handler for `ecp serve` (no auth).
|
|
12
|
+
* @category CLI
|
|
13
|
+
*/
|
|
14
|
+
export declare function createServeRequestHandler(options: ServeRequestHandlerOptions): (req: IncomingMessage, res: ServerResponse) => Promise<void>;
|
|
15
|
+
//# sourceMappingURL=create-serve-handler.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"create-serve-handler.d.ts","sourceRoot":"","sources":["../../../src/lib/http/create-serve-handler.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,WAAW,CAAA;AAChE,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,gCAAgC,CAAA;AAMzD,wEAAwE;AACxE,MAAM,WAAW,0BAA0B;IACzC,gCAAgC;IAChC,GAAG,EAAE,GAAG,CAAA;IACR,6DAA6D;IAC7D,YAAY,EAAE,WAAW,CAAC,MAAM,CAAC,CAAA;CAClC;AAED;;;GAGG;AACH,wBAAgB,yBAAyB,CAAC,OAAO,EAAE,0BAA0B,IAIzE,KAAK,eAAe,EACpB,KAAK,cAAc,KAClB,OAAO,CAAC,IAAI,CAAC,CA2BjB"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { handleInvokePost } from "./handle-invoke.js";
|
|
2
|
+
import { writeJson } from "./write-json.js";
|
|
3
|
+
import { ECP_UP_VERSION } from "../up/constants.js";
|
|
4
|
+
import { setCorsAndPna } from "../up/cors.js";
|
|
5
|
+
/**
|
|
6
|
+
* Create the HTTP request handler for `ecp serve` (no auth).
|
|
7
|
+
* @category CLI
|
|
8
|
+
*/
|
|
9
|
+
export function createServeRequestHandler(options) {
|
|
10
|
+
const { ecp, allowOrigins } = options;
|
|
11
|
+
return async function handleServeRequest(req, res) {
|
|
12
|
+
setCorsAndPna(req, res, allowOrigins);
|
|
13
|
+
if (req.method === "OPTIONS") {
|
|
14
|
+
res.writeHead(204);
|
|
15
|
+
res.end();
|
|
16
|
+
return;
|
|
17
|
+
}
|
|
18
|
+
const url = new URL(req.url ?? "/", `http://${req.headers.host ?? "127.0.0.1"}`);
|
|
19
|
+
const pathname = url.pathname;
|
|
20
|
+
if (req.method === "GET" && pathname === "/health") {
|
|
21
|
+
writeJson(res, 200, {
|
|
22
|
+
ok: true,
|
|
23
|
+
version: ECP_UP_VERSION,
|
|
24
|
+
});
|
|
25
|
+
return;
|
|
26
|
+
}
|
|
27
|
+
if (req.method === "POST" && pathname === "/v1/invoke") {
|
|
28
|
+
await handleInvokePost(ecp, req, res);
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
31
|
+
writeJson(res, 404, { error: "Not found" });
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
//# sourceMappingURL=create-serve-handler.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"create-serve-handler.js","sourceRoot":"","sources":["../../../src/lib/http/create-serve-handler.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAA;AACrD,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAA;AAC3C,OAAO,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAA;AACnD,OAAO,EAAE,aAAa,EAAE,MAAM,eAAe,CAAA;AAU7C;;;GAGG;AACH,MAAM,UAAU,yBAAyB,CAAC,OAAmC;IAC3E,MAAM,EAAE,GAAG,EAAE,YAAY,EAAE,GAAG,OAAO,CAAA;IAErC,OAAO,KAAK,UAAU,kBAAkB,CACtC,GAAoB,EACpB,GAAmB;QAEnB,aAAa,CAAC,GAAG,EAAE,GAAG,EAAE,YAAY,CAAC,CAAA;QAErC,IAAI,GAAG,CAAC,MAAM,KAAK,SAAS,EAAE,CAAC;YAC7B,GAAG,CAAC,SAAS,CAAC,GAAG,CAAC,CAAA;YAClB,GAAG,CAAC,GAAG,EAAE,CAAA;YACT,OAAM;QACR,CAAC;QAED,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,GAAG,CAAC,GAAG,IAAI,GAAG,EAAE,UAAU,GAAG,CAAC,OAAO,CAAC,IAAI,IAAI,WAAW,EAAE,CAAC,CAAA;QAChF,MAAM,QAAQ,GAAG,GAAG,CAAC,QAAQ,CAAA;QAE7B,IAAI,GAAG,CAAC,MAAM,KAAK,KAAK,IAAI,QAAQ,KAAK,SAAS,EAAE,CAAC;YACnD,SAAS,CAAC,GAAG,EAAE,GAAG,EAAE;gBAClB,EAAE,EAAE,IAAI;gBACR,OAAO,EAAE,cAAc;aACxB,CAAC,CAAA;YACF,OAAM;QACR,CAAC;QAED,IAAI,GAAG,CAAC,MAAM,KAAK,MAAM,IAAI,QAAQ,KAAK,YAAY,EAAE,CAAC;YACvD,MAAM,gBAAgB,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC,CAAA;YACrC,OAAM;QACR,CAAC;QAED,SAAS,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE,KAAK,EAAE,WAAW,EAAE,CAAC,CAAA;IAC7C,CAAC,CAAA;AACH,CAAC"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { type Server } from "node:http";
|
|
2
|
+
import type { Ecp } from "@executioncontrolprotocol/core";
|
|
3
|
+
/** Options for {@link startEcpServe}. @category CLI */
|
|
4
|
+
export interface StartEcpServeOptions {
|
|
5
|
+
/** Initialized operational ECP instance. */
|
|
6
|
+
ecp: Ecp;
|
|
7
|
+
/** Listen port (default 3090). */
|
|
8
|
+
port?: number;
|
|
9
|
+
/** Bind host (default 127.0.0.1). */
|
|
10
|
+
host?: string;
|
|
11
|
+
/** Extra CORS origins. */
|
|
12
|
+
corsOrigins?: string[];
|
|
13
|
+
}
|
|
14
|
+
/** Result of starting `ecp serve`. @category CLI */
|
|
15
|
+
export interface EcpServeServer {
|
|
16
|
+
/** Listening HTTP server. */
|
|
17
|
+
server: Server;
|
|
18
|
+
/** Resolved listen port. */
|
|
19
|
+
port: number;
|
|
20
|
+
/** Resolved bind host. */
|
|
21
|
+
host: string;
|
|
22
|
+
/** Close the HTTP server (does not terminate ECP). */
|
|
23
|
+
close: () => Promise<void>;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Start a loopback HTTP server that exposes `POST /v1/invoke` for an environment.
|
|
27
|
+
* @category CLI
|
|
28
|
+
*/
|
|
29
|
+
export declare function startEcpServe(options: StartEcpServeOptions): Promise<EcpServeServer>;
|
|
30
|
+
//# sourceMappingURL=create-serve.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"create-serve.d.ts","sourceRoot":"","sources":["../../../src/lib/http/create-serve.ts"],"names":[],"mappings":"AAAA,OAAO,EAAgB,KAAK,MAAM,EAAE,MAAM,WAAW,CAAA;AACrD,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,gCAAgC,CAAA;AAIzD,uDAAuD;AACvD,MAAM,WAAW,oBAAoB;IACnC,4CAA4C;IAC5C,GAAG,EAAE,GAAG,CAAA;IACR,kCAAkC;IAClC,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,qCAAqC;IACrC,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,0BAA0B;IAC1B,WAAW,CAAC,EAAE,MAAM,EAAE,CAAA;CACvB;AAED,oDAAoD;AACpD,MAAM,WAAW,cAAc;IAC7B,6BAA6B;IAC7B,MAAM,EAAE,MAAM,CAAA;IACd,4BAA4B;IAC5B,IAAI,EAAE,MAAM,CAAA;IACZ,0BAA0B;IAC1B,IAAI,EAAE,MAAM,CAAA;IACZ,sDAAsD;IACtD,KAAK,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAA;CAC3B;AAED;;;GAGG;AACH,wBAAsB,aAAa,CAAC,OAAO,EAAE,oBAAoB,GAAG,OAAO,CAAC,cAAc,CAAC,CAsC1F"}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { createServer } from "node:http";
|
|
2
|
+
import { DEFAULT_ECP_UP_HOST, DEFAULT_ECP_UP_PORT } from "../up/constants.js";
|
|
3
|
+
import { createServeRequestHandler } from "./create-serve-handler.js";
|
|
4
|
+
/**
|
|
5
|
+
* Start a loopback HTTP server that exposes `POST /v1/invoke` for an environment.
|
|
6
|
+
* @category CLI
|
|
7
|
+
*/
|
|
8
|
+
export async function startEcpServe(options) {
|
|
9
|
+
const port = options.port ?? DEFAULT_ECP_UP_PORT;
|
|
10
|
+
const host = options.host ?? DEFAULT_ECP_UP_HOST;
|
|
11
|
+
const allowOrigins = new Set(options.corsOrigins ?? []);
|
|
12
|
+
const handler = createServeRequestHandler({
|
|
13
|
+
ecp: options.ecp,
|
|
14
|
+
allowOrigins,
|
|
15
|
+
});
|
|
16
|
+
const server = createServer((req, res) => {
|
|
17
|
+
void handler(req, res).catch((err) => {
|
|
18
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
19
|
+
if (!res.headersSent) {
|
|
20
|
+
res.writeHead(500, { "Content-Type": "application/json" });
|
|
21
|
+
}
|
|
22
|
+
res.end(JSON.stringify({ error: message }));
|
|
23
|
+
});
|
|
24
|
+
});
|
|
25
|
+
await new Promise((resolve, reject) => {
|
|
26
|
+
server.once("error", reject);
|
|
27
|
+
server.listen(port, host, () => {
|
|
28
|
+
server.off("error", reject);
|
|
29
|
+
resolve();
|
|
30
|
+
});
|
|
31
|
+
});
|
|
32
|
+
return {
|
|
33
|
+
server,
|
|
34
|
+
port,
|
|
35
|
+
host,
|
|
36
|
+
close: async () => {
|
|
37
|
+
await new Promise((resolve, reject) => {
|
|
38
|
+
server.close((err) => (err ? reject(err) : resolve()));
|
|
39
|
+
});
|
|
40
|
+
},
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
//# sourceMappingURL=create-serve.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"create-serve.js","sourceRoot":"","sources":["../../../src/lib/http/create-serve.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAe,MAAM,WAAW,CAAA;AAErD,OAAO,EAAE,mBAAmB,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAA;AAC7E,OAAO,EAAE,yBAAyB,EAAE,MAAM,2BAA2B,CAAA;AA0BrE;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,aAAa,CAAC,OAA6B;IAC/D,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,IAAI,mBAAmB,CAAA;IAChD,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,IAAI,mBAAmB,CAAA;IAChD,MAAM,YAAY,GAAG,IAAI,GAAG,CAAS,OAAO,CAAC,WAAW,IAAI,EAAE,CAAC,CAAA;IAE/D,MAAM,OAAO,GAAG,yBAAyB,CAAC;QACxC,GAAG,EAAE,OAAO,CAAC,GAAG;QAChB,YAAY;KACb,CAAC,CAAA;IAEF,MAAM,MAAM,GAAG,YAAY,CAAC,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE;QACvC,KAAK,OAAO,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,GAAG,EAAE,EAAE;YACnC,MAAM,OAAO,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAA;YAChE,IAAI,CAAC,GAAG,CAAC,WAAW,EAAE,CAAC;gBACrB,GAAG,CAAC,SAAS,CAAC,GAAG,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE,CAAC,CAAA;YAC5D,CAAC;YACD,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,KAAK,EAAE,OAAO,EAAE,CAAC,CAAC,CAAA;QAC7C,CAAC,CAAC,CAAA;IACJ,CAAC,CAAC,CAAA;IAEF,MAAM,IAAI,OAAO,CAAO,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;QAC1C,MAAM,CAAC,IAAI,CAAC,OAAO,EAAE,MAAM,CAAC,CAAA;QAC5B,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,IAAI,EAAE,GAAG,EAAE;YAC7B,MAAM,CAAC,GAAG,CAAC,OAAO,EAAE,MAAM,CAAC,CAAA;YAC3B,OAAO,EAAE,CAAA;QACX,CAAC,CAAC,CAAA;IACJ,CAAC,CAAC,CAAA;IAEF,OAAO;QACL,MAAM;QACN,IAAI;QACJ,IAAI;QACJ,KAAK,EAAE,KAAK,IAAI,EAAE;YAChB,MAAM,IAAI,OAAO,CAAO,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;gBAC1C,MAAM,CAAC,KAAK,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC,CAAA;YACxD,CAAC,CAAC,CAAA;QACJ,CAAC;KACF,CAAA;AACH,CAAC"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import type { IncomingMessage, ServerResponse } from "node:http";
|
|
2
|
+
import type { Ecp } from "@executioncontrolprotocol/core";
|
|
3
|
+
/** JSON body for `POST /v1/invoke`. @category CLI */
|
|
4
|
+
export interface InvokeHttpBody {
|
|
5
|
+
/** Capability id to invoke. */
|
|
6
|
+
capability?: string;
|
|
7
|
+
/** Capability input payload. */
|
|
8
|
+
input?: unknown;
|
|
9
|
+
/** Optional provider capability override (harness `.uses`). */
|
|
10
|
+
provider?: string;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Parse and validate a `/v1/invoke` request body.
|
|
14
|
+
* @category CLI
|
|
15
|
+
*/
|
|
16
|
+
export declare function parseInvokeBody(raw: string): {
|
|
17
|
+
ok: true;
|
|
18
|
+
body: {
|
|
19
|
+
capability: string;
|
|
20
|
+
input: unknown;
|
|
21
|
+
provider?: string;
|
|
22
|
+
};
|
|
23
|
+
} | {
|
|
24
|
+
ok: false;
|
|
25
|
+
error: string;
|
|
26
|
+
};
|
|
27
|
+
/**
|
|
28
|
+
* Run `ecp.invoke` for a parsed invoke body and return the result.
|
|
29
|
+
* @category CLI
|
|
30
|
+
*/
|
|
31
|
+
export declare function runHttpInvoke(ecp: Ecp, body: {
|
|
32
|
+
capability: string;
|
|
33
|
+
input: unknown;
|
|
34
|
+
provider?: string;
|
|
35
|
+
}): Promise<import("@executioncontrolprotocol/core").InvokeResult<unknown>>;
|
|
36
|
+
/**
|
|
37
|
+
* Handle `POST /v1/invoke`: read body, invoke, write JSON result.
|
|
38
|
+
* Does not perform authentication.
|
|
39
|
+
* @category CLI
|
|
40
|
+
*/
|
|
41
|
+
export declare function handleInvokePost(ecp: Ecp, req: IncomingMessage, res: ServerResponse): Promise<void>;
|
|
42
|
+
//# sourceMappingURL=handle-invoke.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"handle-invoke.d.ts","sourceRoot":"","sources":["../../../src/lib/http/handle-invoke.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,WAAW,CAAA;AAChE,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,gCAAgC,CAAA;AAIzD,qDAAqD;AACrD,MAAM,WAAW,cAAc;IAC7B,+BAA+B;IAC/B,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,gCAAgC;IAChC,KAAK,CAAC,EAAE,OAAO,CAAA;IACf,+DAA+D;IAC/D,QAAQ,CAAC,EAAE,MAAM,CAAA;CAClB;AAED;;;GAGG;AACH,wBAAgB,eAAe,CAC7B,GAAG,EAAE,MAAM,GACV;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,IAAI,EAAE;QAAE,UAAU,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,OAAO,CAAC;QAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;KAAE,CAAA;CAAE,GAAG;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAoB9G;AAED;;;GAGG;AACH,wBAAsB,aAAa,CACjC,GAAG,EAAE,GAAG,EACR,IAAI,EAAE;IAAE,UAAU,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,OAAO,CAAC;IAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;CAAE,2EAIhE;AAED;;;;GAIG;AACH,wBAAsB,gBAAgB,CACpC,GAAG,EAAE,GAAG,EACR,GAAG,EAAE,eAAe,EACpB,GAAG,EAAE,cAAc,GAClB,OAAO,CAAC,IAAI,CAAC,CAuBf"}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { readRequestBody } from "./read-body.js";
|
|
2
|
+
import { writeJson } from "./write-json.js";
|
|
3
|
+
/**
|
|
4
|
+
* Parse and validate a `/v1/invoke` request body.
|
|
5
|
+
* @category CLI
|
|
6
|
+
*/
|
|
7
|
+
export function parseInvokeBody(raw) {
|
|
8
|
+
let parsed;
|
|
9
|
+
try {
|
|
10
|
+
parsed = raw.trim() ? JSON.parse(raw) : {};
|
|
11
|
+
}
|
|
12
|
+
catch {
|
|
13
|
+
return { ok: false, error: "Invalid JSON body" };
|
|
14
|
+
}
|
|
15
|
+
if (typeof parsed.capability !== "string" || !parsed.capability.trim()) {
|
|
16
|
+
return { ok: false, error: "capability is required" };
|
|
17
|
+
}
|
|
18
|
+
return {
|
|
19
|
+
ok: true,
|
|
20
|
+
body: {
|
|
21
|
+
capability: parsed.capability,
|
|
22
|
+
input: parsed.input ?? {},
|
|
23
|
+
...(typeof parsed.provider === "string" && parsed.provider.trim()
|
|
24
|
+
? { provider: parsed.provider }
|
|
25
|
+
: {}),
|
|
26
|
+
},
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Run `ecp.invoke` for a parsed invoke body and return the result.
|
|
31
|
+
* @category CLI
|
|
32
|
+
*/
|
|
33
|
+
export async function runHttpInvoke(ecp, body) {
|
|
34
|
+
const builder = ecp.invoke(body.capability).with(body.input);
|
|
35
|
+
return (body.provider ? builder.uses(body.provider) : builder).process();
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Handle `POST /v1/invoke`: read body, invoke, write JSON result.
|
|
39
|
+
* Does not perform authentication.
|
|
40
|
+
* @category CLI
|
|
41
|
+
*/
|
|
42
|
+
export async function handleInvokePost(ecp, req, res) {
|
|
43
|
+
let raw;
|
|
44
|
+
try {
|
|
45
|
+
raw = await readRequestBody(req);
|
|
46
|
+
}
|
|
47
|
+
catch (err) {
|
|
48
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
49
|
+
writeJson(res, 400, { error: message });
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
const parsed = parseInvokeBody(raw);
|
|
53
|
+
if (!parsed.ok) {
|
|
54
|
+
writeJson(res, 400, { error: parsed.error });
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
try {
|
|
58
|
+
const result = await runHttpInvoke(ecp, parsed.body);
|
|
59
|
+
writeJson(res, 200, result);
|
|
60
|
+
}
|
|
61
|
+
catch (err) {
|
|
62
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
63
|
+
writeJson(res, 500, { error: message });
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
//# sourceMappingURL=handle-invoke.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"handle-invoke.js","sourceRoot":"","sources":["../../../src/lib/http/handle-invoke.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"read-body.d.ts","sourceRoot":"","sources":["../../../src/lib/http/read-body.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,WAAW,CAAA;AAEhD;;;GAGG;AACH,wBAAsB,eAAe,CAAC,GAAG,EAAE,eAAe,GAAG,OAAO,CAAC,MAAM,CAAC,CAM3E"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Read the full request body as UTF-8 text.
|
|
3
|
+
* @category CLI
|
|
4
|
+
*/
|
|
5
|
+
export async function readRequestBody(req) {
|
|
6
|
+
const chunks = [];
|
|
7
|
+
for await (const chunk of req) {
|
|
8
|
+
chunks.push(typeof chunk === "string" ? Buffer.from(chunk) : chunk);
|
|
9
|
+
}
|
|
10
|
+
return Buffer.concat(chunks).toString("utf8");
|
|
11
|
+
}
|
|
12
|
+
//# sourceMappingURL=read-body.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"read-body.js","sourceRoot":"","sources":["../../../src/lib/http/read-body.ts"],"names":[],"mappings":"AAEA;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,eAAe,CAAC,GAAoB;IACxD,MAAM,MAAM,GAAa,EAAE,CAAA;IAC3B,IAAI,KAAK,EAAE,MAAM,KAAK,IAAI,GAAG,EAAE,CAAC;QAC9B,MAAM,CAAC,IAAI,CAAC,OAAO,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAA;IACrE,CAAC;IACD,OAAO,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAA;AAC/C,CAAC"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { ServerResponse } from "node:http";
|
|
2
|
+
/**
|
|
3
|
+
* Write a JSON response with the given status code.
|
|
4
|
+
* @category CLI
|
|
5
|
+
*/
|
|
6
|
+
export declare function writeJson(res: ServerResponse, status: number, body: unknown): void;
|
|
7
|
+
//# sourceMappingURL=write-json.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"write-json.d.ts","sourceRoot":"","sources":["../../../src/lib/http/write-json.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,WAAW,CAAA;AAG/C;;;GAGG;AACH,wBAAgB,SAAS,CAAC,GAAG,EAAE,cAAc,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,GAAG,IAAI,CAIlF"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { JSON_MIME } from "../up/constants.js";
|
|
2
|
+
/**
|
|
3
|
+
* Write a JSON response with the given status code.
|
|
4
|
+
* @category CLI
|
|
5
|
+
*/
|
|
6
|
+
export function writeJson(res, status, body) {
|
|
7
|
+
const payload = JSON.stringify(body);
|
|
8
|
+
res.writeHead(status, { "Content-Type": JSON_MIME });
|
|
9
|
+
res.end(payload);
|
|
10
|
+
}
|
|
11
|
+
//# sourceMappingURL=write-json.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"write-json.js","sourceRoot":"","sources":["../../../src/lib/http/write-json.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAA;AAE9C;;;GAGG;AACH,MAAM,UAAU,SAAS,CAAC,GAAmB,EAAE,MAAc,EAAE,IAAa;IAC1E,MAAM,OAAO,GAAG,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAA;IACpC,GAAG,CAAC,SAAS,CAAC,MAAM,EAAE,EAAE,cAAc,EAAE,SAAS,EAAE,CAAC,CAAA;IACpD,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,CAAA;AAClB,CAAC"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { TestSessionSnapshot } from "@executioncontrolprotocol/types";
|
|
2
|
+
/**
|
|
3
|
+
* Read a test session snapshot JSON file.
|
|
4
|
+
* @category CLI
|
|
5
|
+
*/
|
|
6
|
+
export declare function readTestSessionFile(path: string): Promise<TestSessionSnapshot>;
|
|
7
|
+
/**
|
|
8
|
+
* Write a test session snapshot JSON file.
|
|
9
|
+
* @category CLI
|
|
10
|
+
*/
|
|
11
|
+
export declare function writeTestSessionFile(path: string, snapshot: TestSessionSnapshot): Promise<void>;
|
|
12
|
+
//# sourceMappingURL=test-session-io.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"test-session-io.d.ts","sourceRoot":"","sources":["../../src/lib/test-session-io.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,iCAAiC,CAAA;AAE1E;;;GAGG;AACH,wBAAsB,mBAAmB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,mBAAmB,CAAC,CAwBpF;AAED;;;GAGG;AACH,wBAAsB,oBAAoB,CACxC,IAAI,EAAE,MAAM,EACZ,QAAQ,EAAE,mBAAmB,GAC5B,OAAO,CAAC,IAAI,CAAC,CAEf"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { writeFile, readFile } from "node:fs/promises";
|
|
2
|
+
/**
|
|
3
|
+
* Read a test session snapshot JSON file.
|
|
4
|
+
* @category CLI
|
|
5
|
+
*/
|
|
6
|
+
export async function readTestSessionFile(path) {
|
|
7
|
+
let raw;
|
|
8
|
+
try {
|
|
9
|
+
raw = await readFile(path, "utf8");
|
|
10
|
+
}
|
|
11
|
+
catch {
|
|
12
|
+
throw new Error(`--session: cannot read file "${path}"`);
|
|
13
|
+
}
|
|
14
|
+
let parsed;
|
|
15
|
+
try {
|
|
16
|
+
parsed = JSON.parse(raw);
|
|
17
|
+
}
|
|
18
|
+
catch (err) {
|
|
19
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
20
|
+
throw new Error(`--session: invalid JSON in "${path}" (${message})`);
|
|
21
|
+
}
|
|
22
|
+
if (!parsed ||
|
|
23
|
+
typeof parsed !== "object" ||
|
|
24
|
+
parsed.schema !== "@executioncontrolprotocol.test.session") {
|
|
25
|
+
throw new Error(`--session: expected schema "@executioncontrolprotocol.test.session" in "${path}"`);
|
|
26
|
+
}
|
|
27
|
+
return parsed;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Write a test session snapshot JSON file.
|
|
31
|
+
* @category CLI
|
|
32
|
+
*/
|
|
33
|
+
export async function writeTestSessionFile(path, snapshot) {
|
|
34
|
+
await writeFile(path, JSON.stringify(snapshot, null, 2) + "\n", "utf8");
|
|
35
|
+
}
|
|
36
|
+
//# sourceMappingURL=test-session-io.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"test-session-io.js","sourceRoot":"","sources":["../../src/lib/test-session-io.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAA;AAGtD;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,mBAAmB,CAAC,IAAY;IACpD,IAAI,GAAW,CAAA;IACf,IAAI,CAAC;QACH,GAAG,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC,CAAA;IACpC,CAAC;IAAC,MAAM,CAAC;QACP,MAAM,IAAI,KAAK,CAAC,gCAAgC,IAAI,GAAG,CAAC,CAAA;IAC1D,CAAC;IACD,IAAI,MAAe,CAAA;IACnB,IAAI,CAAC;QACH,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAA;IAC1B,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,MAAM,OAAO,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAA;QAChE,MAAM,IAAI,KAAK,CAAC,+BAA+B,IAAI,MAAM,OAAO,GAAG,CAAC,CAAA;IACtE,CAAC;IACD,IACE,CAAC,MAAM;QACP,OAAO,MAAM,KAAK,QAAQ;QACzB,MAA8B,CAAC,MAAM,KAAK,wCAAwC,EACnF,CAAC;QACD,MAAM,IAAI,KAAK,CACb,2EAA2E,IAAI,GAAG,CACnF,CAAA;IACH,CAAC;IACD,OAAO,MAA6B,CAAA;AACtC,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,oBAAoB,CACxC,IAAY,EACZ,QAA6B;IAE7B,MAAM,SAAS,CAAC,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC,GAAG,IAAI,EAAE,MAAM,CAAC,CAAA;AACzE,CAAC"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/** Default loopback port for `ecp up` (ECP leet: E=3, C=0, P=9). @category CLI */
|
|
2
|
+
export declare const DEFAULT_ECP_UP_PORT = 3090;
|
|
3
|
+
/** Default bind host (loopback only). @category CLI */
|
|
4
|
+
export declare const DEFAULT_ECP_UP_HOST = "127.0.0.1";
|
|
5
|
+
/** Default Ollama HTTP API base URL. @category CLI */
|
|
6
|
+
export declare const DEFAULT_OLLAMA_URL = "http://127.0.0.1:11434";
|
|
7
|
+
/** Default browser demo URL opened by `ecp up`. @category CLI */
|
|
8
|
+
export declare const DEFAULT_DEMO_OPEN_URL = "https://executioncontrolprotocol.github.io/browser-demo/";
|
|
9
|
+
/** Built-in CORS origins for local Vite + hosted demo. @category CLI */
|
|
10
|
+
export declare const DEFAULT_CORS_ORIGINS: readonly string[];
|
|
11
|
+
/** JSON MIME type for daemon responses. @category CLI */
|
|
12
|
+
export declare const JSON_MIME = "application/json";
|
|
13
|
+
/** Daemon package version string for /health (from `@executioncontrolprotocol/cli` package.json). @category CLI */
|
|
14
|
+
export declare const ECP_UP_VERSION: string;
|
|
15
|
+
//# sourceMappingURL=constants.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../../../src/lib/up/constants.ts"],"names":[],"mappings":"AAEA,kFAAkF;AAClF,eAAO,MAAM,mBAAmB,OAAO,CAAA;AAEvC,uDAAuD;AACvD,eAAO,MAAM,mBAAmB,cAAc,CAAA;AAE9C,sDAAsD;AACtD,eAAO,MAAM,kBAAkB,2BAA2B,CAAA;AAE1D,iEAAiE;AACjE,eAAO,MAAM,qBAAqB,6DAA6D,CAAA;AAE/F,wEAAwE;AACxE,eAAO,MAAM,oBAAoB,EAAE,SAAS,MAAM,EAIjD,CAAA;AAED,yDAAyD;AACzD,eAAO,MAAM,SAAS,qBAAqB,CAAA;AAI3C,mHAAmH;AACnH,eAAO,MAAM,cAAc,QAAoE,CAAA"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { createRequire } from "node:module";
|
|
2
|
+
/** Default loopback port for `ecp up` (ECP leet: E=3, C=0, P=9). @category CLI */
|
|
3
|
+
export const DEFAULT_ECP_UP_PORT = 3090;
|
|
4
|
+
/** Default bind host (loopback only). @category CLI */
|
|
5
|
+
export const DEFAULT_ECP_UP_HOST = "127.0.0.1";
|
|
6
|
+
/** Default Ollama HTTP API base URL. @category CLI */
|
|
7
|
+
export const DEFAULT_OLLAMA_URL = "http://127.0.0.1:11434";
|
|
8
|
+
/** Default browser demo URL opened by `ecp up`. @category CLI */
|
|
9
|
+
export const DEFAULT_DEMO_OPEN_URL = "https://executioncontrolprotocol.github.io/browser-demo/";
|
|
10
|
+
/** Built-in CORS origins for local Vite + hosted demo. @category CLI */
|
|
11
|
+
export const DEFAULT_CORS_ORIGINS = [
|
|
12
|
+
"http://localhost:5173",
|
|
13
|
+
"http://127.0.0.1:5173",
|
|
14
|
+
"https://executioncontrolprotocol.github.io",
|
|
15
|
+
];
|
|
16
|
+
/** JSON MIME type for daemon responses. @category CLI */
|
|
17
|
+
export const JSON_MIME = "application/json";
|
|
18
|
+
const require = createRequire(import.meta.url);
|
|
19
|
+
/** Daemon package version string for /health (from `@executioncontrolprotocol/cli` package.json). @category CLI */
|
|
20
|
+
export const ECP_UP_VERSION = require("../../../package.json").version;
|
|
21
|
+
//# sourceMappingURL=constants.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"constants.js","sourceRoot":"","sources":["../../../src/lib/up/constants.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAA;AAE3C,kFAAkF;AAClF,MAAM,CAAC,MAAM,mBAAmB,GAAG,IAAI,CAAA;AAEvC,uDAAuD;AACvD,MAAM,CAAC,MAAM,mBAAmB,GAAG,WAAW,CAAA;AAE9C,sDAAsD;AACtD,MAAM,CAAC,MAAM,kBAAkB,GAAG,wBAAwB,CAAA;AAE1D,iEAAiE;AACjE,MAAM,CAAC,MAAM,qBAAqB,GAAG,0DAA0D,CAAA;AAE/F,wEAAwE;AACxE,MAAM,CAAC,MAAM,oBAAoB,GAAsB;IACrD,uBAAuB;IACvB,uBAAuB;IACvB,4CAA4C;CAC7C,CAAA;AAED,yDAAyD;AACzD,MAAM,CAAC,MAAM,SAAS,GAAG,kBAAkB,CAAA;AAE3C,MAAM,OAAO,GAAG,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAA;AAE9C,mHAAmH;AACnH,MAAM,CAAC,MAAM,cAAc,GAAI,OAAO,CAAC,uBAAuB,CAAyB,CAAC,OAAO,CAAA"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { IncomingMessage, ServerResponse } from "node:http";
|
|
2
|
+
/**
|
|
3
|
+
* Apply CORS + Private Network Access headers for Chromium loopback access.
|
|
4
|
+
* @category CLI
|
|
5
|
+
*/
|
|
6
|
+
export declare function setCorsAndPna(req: IncomingMessage, res: ServerResponse, allowOrigins: ReadonlySet<string>): void;
|
|
7
|
+
/**
|
|
8
|
+
* Extract Bearer token from Authorization header.
|
|
9
|
+
* @category CLI
|
|
10
|
+
*/
|
|
11
|
+
export declare function readBearerToken(req: IncomingMessage): string | undefined;
|
|
12
|
+
//# sourceMappingURL=cors.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cors.d.ts","sourceRoot":"","sources":["../../../src/lib/up/cors.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,WAAW,CAAA;AAEhE;;;GAGG;AACH,wBAAgB,aAAa,CAC3B,GAAG,EAAE,eAAe,EACpB,GAAG,EAAE,cAAc,EACnB,YAAY,EAAE,WAAW,CAAC,MAAM,CAAC,GAChC,IAAI,CAWN;AAED;;;GAGG;AACH,wBAAgB,eAAe,CAAC,GAAG,EAAE,eAAe,GAAG,MAAM,GAAG,SAAS,CAKxE"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Apply CORS + Private Network Access headers for Chromium loopback access.
|
|
3
|
+
* @category CLI
|
|
4
|
+
*/
|
|
5
|
+
export function setCorsAndPna(req, res, allowOrigins) {
|
|
6
|
+
const origin = req.headers.origin;
|
|
7
|
+
if (typeof origin === "string" && allowOrigins.has(origin)) {
|
|
8
|
+
res.setHeader("Access-Control-Allow-Origin", origin);
|
|
9
|
+
res.setHeader("Vary", "Origin");
|
|
10
|
+
}
|
|
11
|
+
res.setHeader("Access-Control-Allow-Methods", "GET, POST, OPTIONS");
|
|
12
|
+
res.setHeader("Access-Control-Allow-Headers", "Authorization, Content-Type");
|
|
13
|
+
if (req.headers["access-control-request-private-network"] === "true") {
|
|
14
|
+
res.setHeader("Access-Control-Allow-Private-Network", "true");
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Extract Bearer token from Authorization header.
|
|
19
|
+
* @category CLI
|
|
20
|
+
*/
|
|
21
|
+
export function readBearerToken(req) {
|
|
22
|
+
const header = req.headers.authorization;
|
|
23
|
+
if (typeof header !== "string")
|
|
24
|
+
return undefined;
|
|
25
|
+
const match = /^Bearer\s+(.+)$/i.exec(header.trim());
|
|
26
|
+
return match?.[1]?.trim() || undefined;
|
|
27
|
+
}
|
|
28
|
+
//# sourceMappingURL=cors.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cors.js","sourceRoot":"","sources":["../../../src/lib/up/cors.ts"],"names":[],"mappings":"AAEA;;;GAGG;AACH,MAAM,UAAU,aAAa,CAC3B,GAAoB,EACpB,GAAmB,EACnB,YAAiC;IAEjC,MAAM,MAAM,GAAG,GAAG,CAAC,OAAO,CAAC,MAAM,CAAA;IACjC,IAAI,OAAO,MAAM,KAAK,QAAQ,IAAI,YAAY,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC;QAC3D,GAAG,CAAC,SAAS,CAAC,6BAA6B,EAAE,MAAM,CAAC,CAAA;QACpD,GAAG,CAAC,SAAS,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAA;IACjC,CAAC;IACD,GAAG,CAAC,SAAS,CAAC,8BAA8B,EAAE,oBAAoB,CAAC,CAAA;IACnE,GAAG,CAAC,SAAS,CAAC,8BAA8B,EAAE,6BAA6B,CAAC,CAAA;IAC5E,IAAI,GAAG,CAAC,OAAO,CAAC,wCAAwC,CAAC,KAAK,MAAM,EAAE,CAAC;QACrE,GAAG,CAAC,SAAS,CAAC,sCAAsC,EAAE,MAAM,CAAC,CAAA;IAC/D,CAAC;AACH,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,eAAe,CAAC,GAAoB;IAClD,MAAM,MAAM,GAAG,GAAG,CAAC,OAAO,CAAC,aAAa,CAAA;IACxC,IAAI,OAAO,MAAM,KAAK,QAAQ;QAAE,OAAO,SAAS,CAAA;IAChD,MAAM,KAAK,GAAG,kBAAkB,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC,CAAA;IACpD,OAAO,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,IAAI,SAAS,CAAA;AACxC,CAAC"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { type Server } from "node:http";
|
|
2
|
+
import type { Ecp } from "@executioncontrolprotocol/core";
|
|
3
|
+
import "@executioncontrolprotocol/extension-ollama";
|
|
4
|
+
/** Options for {@link startEcpUpDaemon}. @category CLI */
|
|
5
|
+
export interface StartEcpUpDaemonOptions {
|
|
6
|
+
/** Listen port (default 3090). */
|
|
7
|
+
port?: number;
|
|
8
|
+
/** Bind host (default 127.0.0.1). */
|
|
9
|
+
host?: string;
|
|
10
|
+
/** Ollama API base URL. */
|
|
11
|
+
ollamaUrl?: string;
|
|
12
|
+
/** Extra CORS origins (merged with Vite defaults). */
|
|
13
|
+
corsOrigins?: string[];
|
|
14
|
+
/** Pairing token for `/v1/invoke`. */
|
|
15
|
+
token: string;
|
|
16
|
+
}
|
|
17
|
+
/** Result of starting the daemon. @category CLI */
|
|
18
|
+
export interface EcpUpDaemon {
|
|
19
|
+
/** Listening HTTP server. */
|
|
20
|
+
server: Server;
|
|
21
|
+
/** Operational ECP instance. */
|
|
22
|
+
ecp: Ecp;
|
|
23
|
+
/** Resolved listen port. */
|
|
24
|
+
port: number;
|
|
25
|
+
/** Resolved bind host. */
|
|
26
|
+
host: string;
|
|
27
|
+
/** Pairing token. */
|
|
28
|
+
token: string;
|
|
29
|
+
/** Close the server and terminate ECP. */
|
|
30
|
+
close: () => Promise<void>;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Start the local ECP daemon (`ecp up`).
|
|
34
|
+
* @category CLI
|
|
35
|
+
*/
|
|
36
|
+
export declare function startEcpUpDaemon(options: StartEcpUpDaemonOptions): Promise<EcpUpDaemon>;
|
|
37
|
+
//# sourceMappingURL=create-daemon.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"create-daemon.d.ts","sourceRoot":"","sources":["../../../src/lib/up/create-daemon.ts"],"names":[],"mappings":"AAAA,OAAO,EAAgB,KAAK,MAAM,EAAE,MAAM,WAAW,CAAA;AAErD,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,gCAAgC,CAAA;AACzD,OAAO,4CAA4C,CAAA;AAUnD,0DAA0D;AAC1D,MAAM,WAAW,uBAAuB;IACtC,kCAAkC;IAClC,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,qCAAqC;IACrC,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,2BAA2B;IAC3B,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,sDAAsD;IACtD,WAAW,CAAC,EAAE,MAAM,EAAE,CAAA;IACtB,sCAAsC;IACtC,KAAK,EAAE,MAAM,CAAA;CACd;AAED,mDAAmD;AACnD,MAAM,WAAW,WAAW;IAC1B,6BAA6B;IAC7B,MAAM,EAAE,MAAM,CAAA;IACd,gCAAgC;IAChC,GAAG,EAAE,GAAG,CAAA;IACR,4BAA4B;IAC5B,IAAI,EAAE,MAAM,CAAA;IACZ,0BAA0B;IAC1B,IAAI,EAAE,MAAM,CAAA;IACZ,qBAAqB;IACrB,KAAK,EAAE,MAAM,CAAA;IACb,0CAA0C;IAC1C,KAAK,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAA;CAC3B;AAED;;;GAGG;AACH,wBAAsB,gBAAgB,CACpC,OAAO,EAAE,uBAAuB,GAC/B,OAAO,CAAC,WAAW,CAAC,CA0DtB"}
|