devframe 0.6.2 → 0.7.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/adapters/build.d.mts +1 -2
- package/dist/adapters/build.mjs +1 -1
- package/dist/adapters/cac.d.mts +40 -0
- package/dist/adapters/cac.mjs +2 -0
- package/dist/adapters/cli.d.mts +8 -32
- package/dist/adapters/cli.mjs +3 -143
- package/dist/adapters/dev.d.mts +3 -4
- package/dist/adapters/dev.mjs +1 -1
- package/dist/adapters/embedded.d.mts +1 -2
- package/dist/adapters/mcp.d.mts +2 -1
- package/dist/adapters/mcp.mjs +1 -1
- package/dist/{build-server-0jWgMrz-.mjs → build-server-Bo0G5XcS.mjs} +10 -4
- package/dist/cac-BFCgKymz.mjs +152 -0
- package/dist/client/index.d.mts +90 -6
- package/dist/client/index.mjs +150 -8
- package/dist/{context-DgkYTlXx.d.mts → context-B1sekkgB.d.mts} +3 -3
- package/dist/{dev-DE51PeJc.mjs → dev-Bs4oRVnI.mjs} +2 -2
- package/dist/{devframe-CpXy1ZlO.d.mts → devframe-CnTVuGw9.d.mts} +76 -16
- package/dist/{dump-D09PZb7T.mjs → dump-CocOVBVz.mjs} +3 -1
- package/dist/{hash-PAfnyu2k.mjs → hash-KtDZYXDN.mjs} +5 -2
- package/dist/helpers/vite.d.mts +7 -5
- package/dist/helpers/vite.mjs +2 -2
- package/dist/{http-COX960WK.mjs → http-BirzlyE9.mjs} +1 -1
- package/dist/{index-DI_TMGjv.d.mts → index-DgsLFhZg.d.mts} +2 -3
- package/dist/{index-DzeFcwMM.d.mts → index-Dpsr-8dD.d.mts} +4 -4
- package/dist/{index-BAZpbgHu.d.mts → index-YDSJgsyG.d.mts} +1 -2
- package/dist/index.d.mts +5 -5
- package/dist/{launch-editor-DIzaS5EG.mjs → launch-editor-C_xuzLnF.mjs} +67 -16
- package/dist/node/auth.d.mts +1 -1
- package/dist/node/hub-internals.d.mts +2 -3
- package/dist/node/index.d.mts +5 -6
- package/dist/recipes/interactive-auth.d.mts +2 -3
- package/dist/recipes/interactive-auth.mjs +1 -0
- package/dist/recipes/open-helpers.d.mts +3 -2
- package/dist/recipes/open-helpers.mjs +1 -1
- package/dist/rpc/client.d.mts +0 -1
- package/dist/rpc/dump.d.mts +1 -1
- package/dist/rpc/dump.mjs +1 -1
- package/dist/rpc/index.d.mts +2 -2
- package/dist/rpc/index.mjs +1 -1
- package/dist/rpc/server.d.mts +0 -1
- package/dist/rpc/transports/ws-client.d.mts +1 -1
- package/dist/rpc/transports/ws-server.d.mts +1 -1
- package/dist/{server-C83NJvZp.d.mts → server-4QH37sb-.d.mts} +2 -3
- package/dist/types/index.d.mts +4 -4
- package/dist/{types-oEqKqUC9.d.mts → types-CrzNxXKq.d.mts} +42 -23
- package/dist/utils/events.d.mts +1 -2
- package/dist/utils/hash.mjs +1 -1
- package/dist/utils/launch-editor.mjs +1 -1
- package/dist/utils/serve-static.d.mts +0 -1
- package/dist/utils/shared-state.d.mts +1 -1
- package/dist/utils/streaming-channel.d.mts +1 -1
- package/dist/utils/when.d.mts +1 -330
- package/dist/{ws-client-nBjpin71.d.mts → ws-client-DSXiI2h7.d.mts} +1 -2
- package/dist/{ws-server-BUgJpdX4.d.mts → ws-server-CceOy6He.d.mts} +1 -2
- package/package.json +11 -6
- package/skills/devframe/SKILL.md +4 -4
package/dist/adapters/build.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { t as collectStaticRpcDump } from "../dump-
|
|
1
|
+
import { t as collectStaticRpcDump } from "../dump-CocOVBVz.mjs";
|
|
2
2
|
import { n as colors } from "../diagnostics-reporter-CsIG85Q5.mjs";
|
|
3
3
|
import { DEVFRAME_CONNECTION_META_FILENAME, DEVFRAME_RPC_DUMP_DIRNAME, DEVFRAME_RPC_DUMP_MANIFEST_FILENAME } from "../constants.mjs";
|
|
4
4
|
import { n as strictJsonStringify } from "../serialization-DpLXCy13.mjs";
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { Dt as defineCliFlags, Et as InferCliFlags, Ot as parseCliFlags, Tt as CliFlagsSchema, r as DevframeDefinition } from "../devframe-CnTVuGw9.mjs";
|
|
2
|
+
import { CAC } from "cac";
|
|
3
|
+
import { H3 } from "h3";
|
|
4
|
+
//#region src/adapters/cac.d.ts
|
|
5
|
+
interface CreateCacOptions {
|
|
6
|
+
/** Default port for `dev` (default: 9999). */
|
|
7
|
+
defaultPort?: number;
|
|
8
|
+
/**
|
|
9
|
+
* Final CAC hook invoked after devframe's built-in subcommands and
|
|
10
|
+
* after the definition's `cli.configure`. Use this to add app-level
|
|
11
|
+
* flags and commands at the assembly stage.
|
|
12
|
+
*/
|
|
13
|
+
configureCli?: (cli: CAC) => void;
|
|
14
|
+
/**
|
|
15
|
+
* Called once the dev server is listening. Use this to print a
|
|
16
|
+
* startup banner or trigger side-effects that depend on the live URL.
|
|
17
|
+
*/
|
|
18
|
+
onReady?: (info: {
|
|
19
|
+
origin: string;
|
|
20
|
+
port: number;
|
|
21
|
+
app: H3;
|
|
22
|
+
}) => void | Promise<void>;
|
|
23
|
+
}
|
|
24
|
+
interface CacHandle {
|
|
25
|
+
/**
|
|
26
|
+
* Raw CAC instance. Mutate before calling `parse()` for last-mile
|
|
27
|
+
* flag or command additions that don't fit `configureCli`.
|
|
28
|
+
*/
|
|
29
|
+
cli: CAC;
|
|
30
|
+
parse: (argv?: string[]) => Promise<void>;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Wrap a {@link DevframeDefinition} in a `cac`-powered command-line
|
|
34
|
+
* interface exposing `dev` / `build` / `mcp` subcommands.
|
|
35
|
+
*
|
|
36
|
+
* Requires the optional `cac` peer dependency.
|
|
37
|
+
*/
|
|
38
|
+
declare function createCac(d: DevframeDefinition, options?: CreateCacOptions): CacHandle;
|
|
39
|
+
//#endregion
|
|
40
|
+
export { CacHandle, type CliFlagsSchema, CreateCacOptions, type InferCliFlags, createCac, defineCliFlags, parseCliFlags };
|
package/dist/adapters/cli.d.mts
CHANGED
|
@@ -1,35 +1,11 @@
|
|
|
1
|
-
import { Dt as
|
|
2
|
-
import {
|
|
3
|
-
import { H3 } from "h3";
|
|
4
|
-
|
|
1
|
+
import { Dt as defineCliFlags, Et as InferCliFlags, Ot as parseCliFlags, Tt as CliFlagsSchema } from "../devframe-CnTVuGw9.mjs";
|
|
2
|
+
import { CacHandle, CreateCacOptions, createCac } from "./cac.mjs";
|
|
5
3
|
//#region src/adapters/cli.d.ts
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
* flags and commands at the assembly stage.
|
|
13
|
-
*/
|
|
14
|
-
configureCli?: (cli: CAC) => void;
|
|
15
|
-
/**
|
|
16
|
-
* Called once the dev server is listening. Use this to print a
|
|
17
|
-
* startup banner or trigger side-effects that depend on the live URL.
|
|
18
|
-
*/
|
|
19
|
-
onReady?: (info: {
|
|
20
|
-
origin: string;
|
|
21
|
-
port: number;
|
|
22
|
-
app: H3;
|
|
23
|
-
}) => void | Promise<void>;
|
|
24
|
-
}
|
|
25
|
-
interface CliHandle {
|
|
26
|
-
/**
|
|
27
|
-
* Raw CAC instance. Mutate before calling `parse()` for last-mile
|
|
28
|
-
* flag or command additions that don't fit `configureCli`.
|
|
29
|
-
*/
|
|
30
|
-
cli: CAC;
|
|
31
|
-
parse: (argv?: string[]) => Promise<void>;
|
|
32
|
-
}
|
|
33
|
-
declare function createCli(d: DevframeDefinition, options?: CreateCliOptions): CliHandle;
|
|
4
|
+
/** @deprecated Use `createCac` from `devframe/adapters/cac` instead. */
|
|
5
|
+
declare const createCli: typeof createCac;
|
|
6
|
+
/** @deprecated Use `CreateCacOptions` from `devframe/adapters/cac` instead. */
|
|
7
|
+
type CreateCliOptions = CreateCacOptions;
|
|
8
|
+
/** @deprecated Use `CacHandle` from `devframe/adapters/cac` instead. */
|
|
9
|
+
type CliHandle = CacHandle;
|
|
34
10
|
//#endregion
|
|
35
11
|
export { type CliFlagsSchema, CliHandle, CreateCliOptions, type InferCliFlags, createCli, defineCliFlags, parseCliFlags };
|
package/dist/adapters/cli.mjs
CHANGED
|
@@ -1,146 +1,6 @@
|
|
|
1
|
-
import { n as
|
|
2
|
-
import { createBuild } from "./build.mjs";
|
|
3
|
-
import { n as resolveDevServerPort, t as createDevServer } from "../dev-DE51PeJc.mjs";
|
|
4
|
-
import process from "node:process";
|
|
5
|
-
import cac from "cac";
|
|
6
|
-
import { safeParse } from "valibot";
|
|
7
|
-
//#region src/adapters/flags.ts
|
|
8
|
-
/**
|
|
9
|
-
* Identity helper that preserves the literal schema-map type — use this
|
|
10
|
-
* so `InferCliFlags<typeof myFlags>` resolves to the right object shape.
|
|
11
|
-
*
|
|
12
|
-
* ```ts
|
|
13
|
-
* const appFlags = defineCliFlags({
|
|
14
|
-
* depth: v.pipe(v.number(), v.integer()),
|
|
15
|
-
* config: v.optional(v.string()),
|
|
16
|
-
* })
|
|
17
|
-
*
|
|
18
|
-
* defineDevframe({
|
|
19
|
-
* cli: { flags: appFlags },
|
|
20
|
-
* setup(ctx, info) {
|
|
21
|
-
* const flags = info.flags as InferCliFlags<typeof appFlags>
|
|
22
|
-
* flags.depth // number
|
|
23
|
-
* flags.config // string | undefined
|
|
24
|
-
* },
|
|
25
|
-
* })
|
|
26
|
-
* ```
|
|
27
|
-
*/
|
|
28
|
-
function defineCliFlags(flags) {
|
|
29
|
-
return flags;
|
|
30
|
-
}
|
|
31
|
-
/**
|
|
32
|
-
* Best-effort probe of a valibot schema to decide whether the
|
|
33
|
-
* corresponding CAC option takes a value. Unwraps `optional` / `nullable`
|
|
34
|
-
* / `nullish` / `default` / `pipe` wrappers then matches on the inner
|
|
35
|
-
* type's kind.
|
|
36
|
-
*/
|
|
37
|
-
function getSchemaKind(schema) {
|
|
38
|
-
let current = schema;
|
|
39
|
-
while (current) {
|
|
40
|
-
const kind = current.type;
|
|
41
|
-
if (kind === "optional" || kind === "nullable" || kind === "nullish" || kind === "undefined") {
|
|
42
|
-
current = current.wrapped ?? current.inner;
|
|
43
|
-
continue;
|
|
44
|
-
}
|
|
45
|
-
if (kind === "pipe" && Array.isArray(current.pipe) && current.pipe.length > 0) {
|
|
46
|
-
current = current.pipe[0];
|
|
47
|
-
continue;
|
|
48
|
-
}
|
|
49
|
-
return kind;
|
|
50
|
-
}
|
|
51
|
-
return "unknown";
|
|
52
|
-
}
|
|
53
|
-
/** Whether the CAC option for this schema should be a boolean flag. */
|
|
54
|
-
function isBooleanFlag(schema) {
|
|
55
|
-
return getSchemaKind(schema) === "boolean";
|
|
56
|
-
}
|
|
57
|
-
/** Validate and coerce the raw cac-parsed bag against a {@link CliFlagsSchema}. */
|
|
58
|
-
function parseCliFlags(schema, raw) {
|
|
59
|
-
const flags = {};
|
|
60
|
-
const issues = [];
|
|
61
|
-
for (const [key, fieldSchema] of Object.entries(schema)) {
|
|
62
|
-
const result = safeParse(fieldSchema, raw[key]);
|
|
63
|
-
if (result.success) flags[key] = result.output;
|
|
64
|
-
else issues.push(`--${toKebab(key)}: ${result.issues.map((i) => i.message).join(", ")}`);
|
|
65
|
-
}
|
|
66
|
-
for (const [key, value] of Object.entries(raw)) if (!(key in schema) && !(key in flags)) flags[key] = value;
|
|
67
|
-
return issues.length ? {
|
|
68
|
-
flags,
|
|
69
|
-
issues
|
|
70
|
-
} : { flags };
|
|
71
|
-
}
|
|
72
|
-
function toKebab(camel) {
|
|
73
|
-
return camel.replaceAll(/([a-z])([A-Z])/g, "$1-$2").toLowerCase();
|
|
74
|
-
}
|
|
75
|
-
/** Kebab-case a schema key for CAC option registration. */
|
|
76
|
-
function flagKeyToOption(camel) {
|
|
77
|
-
return toKebab(camel);
|
|
78
|
-
}
|
|
79
|
-
//#endregion
|
|
1
|
+
import { n as defineCliFlags, r as parseCliFlags, t as createCac } from "../cac-BFCgKymz.mjs";
|
|
80
2
|
//#region src/adapters/cli.ts
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
const defaultHost = d.cli?.host ?? "localhost";
|
|
84
|
-
const cli = cac(d.cli?.command ?? d.id);
|
|
85
|
-
const devCommand = cli.command("[...args]", "Start a local dev server").option("--port <port>", "Port to listen on").option("--host <host>", "Host to bind to", { default: defaultHost }).option("--open", "Open the browser on start").option("--no-open", "Do not open the browser").option("--mcp", "Expose an MCP server over HTTP at /__mcp (use --no-mcp to disable) [experimental]");
|
|
86
|
-
if (d.cli?.flags) for (const [key, schema] of Object.entries(d.cli.flags)) {
|
|
87
|
-
const optionName = flagKeyToOption(key);
|
|
88
|
-
const description = schema.description ?? "";
|
|
89
|
-
if (isBooleanFlag(schema)) devCommand.option(`--${optionName}`, description);
|
|
90
|
-
else devCommand.option(`--${optionName} <value>`, description);
|
|
91
|
-
}
|
|
92
|
-
devCommand.action(async (_args, rawFlags) => {
|
|
93
|
-
const flags = resolveTypedFlags(d, rawFlags);
|
|
94
|
-
const host = flags.host ?? defaultHost;
|
|
95
|
-
const port = flags.port ?? await resolveDevServerPort(d, {
|
|
96
|
-
host,
|
|
97
|
-
defaultPort
|
|
98
|
-
});
|
|
99
|
-
const mcp = flags.mcp;
|
|
100
|
-
await createDevServer(d, {
|
|
101
|
-
host,
|
|
102
|
-
port,
|
|
103
|
-
flags,
|
|
104
|
-
mcp,
|
|
105
|
-
onReady: options.onReady
|
|
106
|
-
});
|
|
107
|
-
});
|
|
108
|
-
cli.command("build", "Build a self-contained static deploy of the devframe").option("--out-dir <outDir>", "Output directory", { default: "dist-static" }).option("--base <base>", "URL base", { default: "/" }).option("--pretty", "Pretty-print dump JSON (larger on disk)").action(async (flags) => {
|
|
109
|
-
await createBuild(d, {
|
|
110
|
-
outDir: flags.outDir,
|
|
111
|
-
base: flags.base,
|
|
112
|
-
pretty: flags.pretty
|
|
113
|
-
});
|
|
114
|
-
});
|
|
115
|
-
cli.command("mcp", "Start an MCP server exposing agent-facing tools (stdio) [experimental]").action(async () => {
|
|
116
|
-
const { createMcpServer } = await import("./mcp.mjs");
|
|
117
|
-
await createMcpServer(d, {
|
|
118
|
-
transport: "stdio",
|
|
119
|
-
onReady: ({ transport }) => {
|
|
120
|
-
console.error(`[devframe] "${d.id}" MCP server ready (${transport})`);
|
|
121
|
-
}
|
|
122
|
-
});
|
|
123
|
-
});
|
|
124
|
-
d.cli?.configure?.(cli);
|
|
125
|
-
options.configureCli?.(cli);
|
|
126
|
-
cli.help();
|
|
127
|
-
cli.version("0.0.0");
|
|
128
|
-
return {
|
|
129
|
-
cli,
|
|
130
|
-
async parse(argv = process.argv) {
|
|
131
|
-
cli.parse(argv, { run: false });
|
|
132
|
-
await cli.runMatchedCommand();
|
|
133
|
-
}
|
|
134
|
-
};
|
|
135
|
-
}
|
|
136
|
-
function resolveTypedFlags(d, raw) {
|
|
137
|
-
if (!d.cli?.flags) return raw;
|
|
138
|
-
const { flags, issues } = parseCliFlags(d.cli.flags, raw);
|
|
139
|
-
if (issues?.length) {
|
|
140
|
-
for (const issue of issues) console.error(colors.red`[devframe] invalid flag — ${issue}`);
|
|
141
|
-
process.exit(1);
|
|
142
|
-
}
|
|
143
|
-
return flags;
|
|
144
|
-
}
|
|
3
|
+
/** @deprecated Use `createCac` from `devframe/adapters/cac` instead. */
|
|
4
|
+
const createCli = createCac;
|
|
145
5
|
//#endregion
|
|
146
6
|
export { createCli, defineCliFlags, parseCliFlags };
|
package/dist/adapters/dev.d.mts
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { n as StartedServer } from "../server-
|
|
1
|
+
import { d as McpRouteOptions, r as DevframeDefinition, u as DevframeWsOptions } from "../devframe-CnTVuGw9.mjs";
|
|
2
|
+
import { n as StartedServer } from "../server-4QH37sb-.mjs";
|
|
3
3
|
import { H3 } from "h3";
|
|
4
|
-
|
|
5
4
|
//#region src/adapters/dev.d.ts
|
|
6
5
|
interface CreateDevServerOptions {
|
|
7
6
|
/** Bind host. Default: `def.cli?.host ?? 'localhost'`. */
|
|
@@ -98,7 +97,7 @@ declare function resolveDevServerPort(def: DevframeDefinition, options?: Resolve
|
|
|
98
97
|
*
|
|
99
98
|
* Use this directly when integrating devframe into an existing CLI
|
|
100
99
|
* framework (commander, yargs, hand-rolled CAC). For the all-in-one
|
|
101
|
-
* `dev` / `build` / `mcp` shell, reach for {@link
|
|
100
|
+
* `dev` / `build` / `mcp` shell, reach for {@link createCac} instead.
|
|
102
101
|
*/
|
|
103
102
|
declare function createDevServer(def: DevframeDefinition, options?: CreateDevServerOptions): Promise<StartedServer>;
|
|
104
103
|
//#endregion
|
package/dist/adapters/dev.mjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { n as resolveDevServerPort, t as createDevServer } from "../dev-
|
|
1
|
+
import { n as resolveDevServerPort, t as createDevServer } from "../dev-Bs4oRVnI.mjs";
|
|
2
2
|
export { createDevServer, resolveDevServerPort };
|
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
1
|
+
import { g as DevframeNodeContext, r as DevframeDefinition } from "../devframe-CnTVuGw9.mjs";
|
|
3
2
|
//#region src/adapters/embedded.d.ts
|
|
4
3
|
interface CreateEmbeddedOptions {
|
|
5
4
|
/** Target context the devframe is registered into. Required. */
|
package/dist/adapters/mcp.d.mts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import { r as DevframeDefinition } from "../devframe-
|
|
1
|
+
import { r as DevframeDefinition } from "../devframe-CnTVuGw9.mjs";
|
|
2
|
+
import "@modelcontextprotocol/sdk/server/index.js";
|
|
2
3
|
//#region src/adapters/mcp/build-server.d.ts
|
|
3
4
|
interface CreateMcpServerOptions {
|
|
4
5
|
/**
|
package/dist/adapters/mcp.mjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { n as createMcpServer } from "../build-server-
|
|
1
|
+
import { n as createMcpServer } from "../build-server-Bo0G5XcS.mjs";
|
|
2
2
|
export { createMcpServer };
|
|
@@ -229,10 +229,16 @@ function registerToolHandlers(server, ctx) {
|
|
|
229
229
|
server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
230
230
|
const { name, arguments: args } = request.params;
|
|
231
231
|
try {
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
232
|
+
const tool = ctx.agent.getTool(name);
|
|
233
|
+
const outputSchema = tool ? tool.outputSchema ?? computeOutputSchema(tool, ctx) : void 0;
|
|
234
|
+
const result = await ctx.agent.invoke(name, args ?? {});
|
|
235
|
+
return {
|
|
236
|
+
content: [{
|
|
237
|
+
type: "text",
|
|
238
|
+
text: stringifyForMcp(result)
|
|
239
|
+
}],
|
|
240
|
+
...outputSchema ? { structuredContent: result } : {}
|
|
241
|
+
};
|
|
236
242
|
} catch (error) {
|
|
237
243
|
return {
|
|
238
244
|
isError: true,
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
import { n as colors } from "./diagnostics-reporter-CsIG85Q5.mjs";
|
|
2
|
+
import { createBuild } from "./adapters/build.mjs";
|
|
3
|
+
import { n as resolveDevServerPort, t as createDevServer } from "./dev-Bs4oRVnI.mjs";
|
|
4
|
+
import process from "node:process";
|
|
5
|
+
import cac from "cac";
|
|
6
|
+
import { safeParse } from "valibot";
|
|
7
|
+
//#region src/adapters/flags.ts
|
|
8
|
+
/**
|
|
9
|
+
* Identity helper that preserves the literal schema-map type — use this
|
|
10
|
+
* so `InferCliFlags<typeof myFlags>` resolves to the right object shape.
|
|
11
|
+
*
|
|
12
|
+
* ```ts
|
|
13
|
+
* const appFlags = defineCliFlags({
|
|
14
|
+
* depth: v.pipe(v.number(), v.integer()),
|
|
15
|
+
* config: v.optional(v.string()),
|
|
16
|
+
* })
|
|
17
|
+
*
|
|
18
|
+
* defineDevframe({
|
|
19
|
+
* cli: { flags: appFlags },
|
|
20
|
+
* setup(ctx, info) {
|
|
21
|
+
* const flags = info.flags as InferCliFlags<typeof appFlags>
|
|
22
|
+
* flags.depth // number
|
|
23
|
+
* flags.config // string | undefined
|
|
24
|
+
* },
|
|
25
|
+
* })
|
|
26
|
+
* ```
|
|
27
|
+
*/
|
|
28
|
+
function defineCliFlags(flags) {
|
|
29
|
+
return flags;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Best-effort probe of a valibot schema to decide whether the
|
|
33
|
+
* corresponding CAC option takes a value. Unwraps `optional` / `nullable`
|
|
34
|
+
* / `nullish` / `default` / `pipe` wrappers then matches on the inner
|
|
35
|
+
* type's kind.
|
|
36
|
+
*/
|
|
37
|
+
function getSchemaKind(schema) {
|
|
38
|
+
let current = schema;
|
|
39
|
+
while (current) {
|
|
40
|
+
const kind = current.type;
|
|
41
|
+
if (kind === "optional" || kind === "nullable" || kind === "nullish" || kind === "undefined") {
|
|
42
|
+
current = current.wrapped ?? current.inner;
|
|
43
|
+
continue;
|
|
44
|
+
}
|
|
45
|
+
if (kind === "pipe" && Array.isArray(current.pipe) && current.pipe.length > 0) {
|
|
46
|
+
current = current.pipe[0];
|
|
47
|
+
continue;
|
|
48
|
+
}
|
|
49
|
+
return kind;
|
|
50
|
+
}
|
|
51
|
+
return "unknown";
|
|
52
|
+
}
|
|
53
|
+
/** Whether the CAC option for this schema should be a boolean flag. */
|
|
54
|
+
function isBooleanFlag(schema) {
|
|
55
|
+
return getSchemaKind(schema) === "boolean";
|
|
56
|
+
}
|
|
57
|
+
/** Validate and coerce the raw cac-parsed bag against a {@link CliFlagsSchema}. */
|
|
58
|
+
function parseCliFlags(schema, raw) {
|
|
59
|
+
const flags = {};
|
|
60
|
+
const issues = [];
|
|
61
|
+
for (const [key, fieldSchema] of Object.entries(schema)) {
|
|
62
|
+
const result = safeParse(fieldSchema, raw[key]);
|
|
63
|
+
if (result.success) flags[key] = result.output;
|
|
64
|
+
else issues.push(`--${toKebab(key)}: ${result.issues.map((i) => i.message).join(", ")}`);
|
|
65
|
+
}
|
|
66
|
+
for (const [key, value] of Object.entries(raw)) if (!(key in schema) && !(key in flags)) flags[key] = value;
|
|
67
|
+
return issues.length ? {
|
|
68
|
+
flags,
|
|
69
|
+
issues
|
|
70
|
+
} : { flags };
|
|
71
|
+
}
|
|
72
|
+
function toKebab(camel) {
|
|
73
|
+
return camel.replaceAll(/([a-z])([A-Z])/g, "$1-$2").toLowerCase();
|
|
74
|
+
}
|
|
75
|
+
/** Kebab-case a schema key for CAC option registration. */
|
|
76
|
+
function flagKeyToOption(camel) {
|
|
77
|
+
return toKebab(camel);
|
|
78
|
+
}
|
|
79
|
+
//#endregion
|
|
80
|
+
//#region src/adapters/cac.ts
|
|
81
|
+
/**
|
|
82
|
+
* Wrap a {@link DevframeDefinition} in a `cac`-powered command-line
|
|
83
|
+
* interface exposing `dev` / `build` / `mcp` subcommands.
|
|
84
|
+
*
|
|
85
|
+
* Requires the optional `cac` peer dependency.
|
|
86
|
+
*/
|
|
87
|
+
function createCac(d, options = {}) {
|
|
88
|
+
const defaultPort = options.defaultPort ?? d.cli?.port ?? 9999;
|
|
89
|
+
const defaultHost = d.cli?.host ?? "localhost";
|
|
90
|
+
const cli = cac(d.cli?.command ?? d.id);
|
|
91
|
+
const devCommand = cli.command("[...args]", "Start a local dev server").option("--port <port>", "Port to listen on").option("--host <host>", "Host to bind to", { default: defaultHost }).option("--open", "Open the browser on start").option("--no-open", "Do not open the browser").option("--mcp", "Expose an MCP server over HTTP at /__mcp (use --no-mcp to disable) [experimental]");
|
|
92
|
+
if (d.cli?.flags) for (const [key, schema] of Object.entries(d.cli.flags)) {
|
|
93
|
+
const optionName = flagKeyToOption(key);
|
|
94
|
+
const description = schema.description ?? "";
|
|
95
|
+
if (isBooleanFlag(schema)) devCommand.option(`--${optionName}`, description);
|
|
96
|
+
else devCommand.option(`--${optionName} <value>`, description);
|
|
97
|
+
}
|
|
98
|
+
devCommand.action(async (_args, rawFlags) => {
|
|
99
|
+
const flags = resolveTypedFlags(d, rawFlags);
|
|
100
|
+
const host = flags.host ?? defaultHost;
|
|
101
|
+
const port = flags.port ?? await resolveDevServerPort(d, {
|
|
102
|
+
host,
|
|
103
|
+
defaultPort
|
|
104
|
+
});
|
|
105
|
+
const mcp = flags.mcp;
|
|
106
|
+
await createDevServer(d, {
|
|
107
|
+
host,
|
|
108
|
+
port,
|
|
109
|
+
flags,
|
|
110
|
+
mcp,
|
|
111
|
+
onReady: options.onReady
|
|
112
|
+
});
|
|
113
|
+
});
|
|
114
|
+
cli.command("build", "Build a self-contained static deploy of the devframe").option("--out-dir <outDir>", "Output directory", { default: "dist-static" }).option("--base <base>", "URL base", { default: "/" }).option("--pretty", "Pretty-print dump JSON (larger on disk)").action(async (flags) => {
|
|
115
|
+
await createBuild(d, {
|
|
116
|
+
outDir: flags.outDir,
|
|
117
|
+
base: flags.base,
|
|
118
|
+
pretty: flags.pretty
|
|
119
|
+
});
|
|
120
|
+
});
|
|
121
|
+
cli.command("mcp", "Start an MCP server exposing agent-facing tools (stdio) [experimental]").action(async () => {
|
|
122
|
+
const { createMcpServer } = await import("./adapters/mcp.mjs");
|
|
123
|
+
await createMcpServer(d, {
|
|
124
|
+
transport: "stdio",
|
|
125
|
+
onReady: ({ transport }) => {
|
|
126
|
+
console.error(`[devframe] "${d.id}" MCP server ready (${transport})`);
|
|
127
|
+
}
|
|
128
|
+
});
|
|
129
|
+
});
|
|
130
|
+
d.cli?.configure?.(cli);
|
|
131
|
+
options.configureCli?.(cli);
|
|
132
|
+
cli.help();
|
|
133
|
+
cli.version("0.0.0");
|
|
134
|
+
return {
|
|
135
|
+
cli,
|
|
136
|
+
async parse(argv = process.argv) {
|
|
137
|
+
cli.parse(argv, { run: false });
|
|
138
|
+
await cli.runMatchedCommand();
|
|
139
|
+
}
|
|
140
|
+
};
|
|
141
|
+
}
|
|
142
|
+
function resolveTypedFlags(d, raw) {
|
|
143
|
+
if (!d.cli?.flags) return raw;
|
|
144
|
+
const { flags, issues } = parseCliFlags(d.cli.flags, raw);
|
|
145
|
+
if (issues?.length) {
|
|
146
|
+
for (const issue of issues) console.error(colors.red`[devframe] invalid flag — ${issue}`);
|
|
147
|
+
process.exit(1);
|
|
148
|
+
}
|
|
149
|
+
return flags;
|
|
150
|
+
}
|
|
151
|
+
//#endregion
|
|
152
|
+
export { defineCliFlags as n, parseCliFlags as r, createCac as t };
|
package/dist/client/index.d.mts
CHANGED
|
@@ -1,9 +1,57 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { _ as RpcFunctionDefinition, w as RpcFunctionsCollector } from "../types-
|
|
3
|
-
import { C as RpcCacheManager, w as RpcCacheOptions } from "../index-
|
|
4
|
-
import { t as WsRpcChannelOptions } from "../ws-client-
|
|
1
|
+
import { A as StreamSink, St as EventEmitter, X as DevframeSettings, at as DevframeRpcClientFunctions, b as RpcSharedStateGetOptions, k as StreamReader, nt as ScopedSharedStates, ot as DevframeRpcServerFunctions, p as ConnectionMeta, rt as SettingsForNamespace, tt as ScopedServerFunctions, x as RpcSharedStateHost, z as SharedState } from "../devframe-CnTVuGw9.mjs";
|
|
2
|
+
import { _ as RpcFunctionDefinition, w as RpcFunctionsCollector } from "../types-CrzNxXKq.mjs";
|
|
3
|
+
import { C as RpcCacheManager, w as RpcCacheOptions } from "../index-DgsLFhZg.mjs";
|
|
4
|
+
import { t as WsRpcChannelOptions } from "../ws-client-DSXiI2h7.mjs";
|
|
5
5
|
import { BirpcOptions, BirpcReturn } from "birpc";
|
|
6
|
-
|
|
6
|
+
//#region src/client/connection.d.ts
|
|
7
|
+
/**
|
|
8
|
+
* The connection lifecycle of a devframe client, as a single value a UI can
|
|
9
|
+
* render from. Derived from the transport (WebSocket open/close/error) and the
|
|
10
|
+
* trust handshake, so a viewer never has to reason about the two dimensions
|
|
11
|
+
* separately.
|
|
12
|
+
*
|
|
13
|
+
* - `connecting` — establishing the WebSocket / running the initial trust
|
|
14
|
+
* handshake. Calls issued here queue until the socket opens.
|
|
15
|
+
* - `connected` — socket open and trusted; RPC calls will be served.
|
|
16
|
+
* - `unauthorized` — socket open but the server rejected trust (no valid token,
|
|
17
|
+
* or an auth-enforcing host refused it). Calls fail fast with an auth error;
|
|
18
|
+
* the UI should prompt for re-authentication or a reload.
|
|
19
|
+
* - `disconnected` — the socket closed (dropped mid-session, or never opened).
|
|
20
|
+
* Pending and new calls fail fast until the page reconnects.
|
|
21
|
+
* - `error` — a fatal connection error (e.g. the WebSocket errored, or the
|
|
22
|
+
* connection meta could not be loaded).
|
|
23
|
+
*
|
|
24
|
+
* A `static` backend has no live socket, so it reports `connected` for its
|
|
25
|
+
* whole life.
|
|
26
|
+
*/
|
|
27
|
+
type DevframeConnectionStatus = 'connecting' | 'connected' | 'unauthorized' | 'disconnected' | 'error';
|
|
28
|
+
/**
|
|
29
|
+
* What kind of failure a {@link DevframeConnectionError} describes:
|
|
30
|
+
* - `connection` — the transport dropped, errored, or never opened.
|
|
31
|
+
* - `auth` — the server rejected trust for this client.
|
|
32
|
+
* - `timeout` — a call exceeded its {@link DevframeRpcClientOptions.callTimeout}.
|
|
33
|
+
*/
|
|
34
|
+
type DevframeConnectionErrorKind = 'connection' | 'auth' | 'timeout';
|
|
35
|
+
/**
|
|
36
|
+
* The error rejected from `rpc.call(...)` (and carried on
|
|
37
|
+
* `rpc.connectionError`) when a call cannot be served because the connection is
|
|
38
|
+
* down, the client is unauthorized, or a call timed out. Its `kind` lets a UI
|
|
39
|
+
* tailor its message and recovery affordance without string-matching.
|
|
40
|
+
*/
|
|
41
|
+
declare class DevframeConnectionError extends Error {
|
|
42
|
+
name: string;
|
|
43
|
+
readonly kind: DevframeConnectionErrorKind;
|
|
44
|
+
constructor(kind: DevframeConnectionErrorKind, message: string, options?: {
|
|
45
|
+
cause?: unknown;
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Whether a status means calls can be attempted. `connecting` counts because
|
|
50
|
+
* the transport queues outgoing calls until the socket opens; the terminal
|
|
51
|
+
* failure states short-circuit calls so a stuck socket never hangs the UI.
|
|
52
|
+
*/
|
|
53
|
+
declare function isCallableStatus(status: DevframeConnectionStatus): boolean;
|
|
54
|
+
//#endregion
|
|
7
55
|
//#region src/client/rpc-streaming.d.ts
|
|
8
56
|
interface StreamingSubscribeOptions {
|
|
9
57
|
/** Maximum buffered chunks before the oldest is dropped. Default 256. */
|
|
@@ -119,6 +167,21 @@ interface DevframeRpcContext {
|
|
|
119
167
|
type DevframeClientRpcHost = RpcFunctionsCollector<DevframeRpcClientFunctions, DevframeRpcContext>;
|
|
120
168
|
interface RpcClientEvents {
|
|
121
169
|
'rpc:is-trusted:updated': (isTrusted: boolean) => void;
|
|
170
|
+
/**
|
|
171
|
+
* The connection status changed. Carries the new status and the previous one
|
|
172
|
+
* so a UI can react to specific transitions (e.g. `connected` → `disconnected`).
|
|
173
|
+
*/
|
|
174
|
+
'connection:status': (status: DevframeConnectionStatus, previous: DevframeConnectionStatus) => void;
|
|
175
|
+
/**
|
|
176
|
+
* A connection-level error occurred (the WebSocket errored, or trust was
|
|
177
|
+
* refused). The status typically moves to `error`/`unauthorized` alongside it.
|
|
178
|
+
*/
|
|
179
|
+
'connection:error': (error: Error) => void;
|
|
180
|
+
/**
|
|
181
|
+
* An RPC call rejected — either from the server, or because the connection
|
|
182
|
+
* was down / timed out. Useful for a global error feed or toast surface.
|
|
183
|
+
*/
|
|
184
|
+
'rpc:error': (error: Error, method: string) => void;
|
|
122
185
|
}
|
|
123
186
|
interface DevframeRpcClientOptions {
|
|
124
187
|
connectionMeta?: ConnectionMeta;
|
|
@@ -138,6 +201,14 @@ interface DevframeRpcClientOptions {
|
|
|
138
201
|
wsOptions?: Partial<WsRpcChannelOptions>;
|
|
139
202
|
rpcOptions?: Partial<BirpcOptions<DevframeRpcServerFunctions, DevframeRpcClientFunctions, boolean>>;
|
|
140
203
|
cacheOptions?: boolean | Partial<RpcCacheOptions>;
|
|
204
|
+
/**
|
|
205
|
+
* Reject a pending `rpc.call(...)` if the server hasn't answered within this
|
|
206
|
+
* many milliseconds, with a {@link DevframeConnectionError} of kind
|
|
207
|
+
* `'timeout'`. Guards against a live-but-unresponsive server hanging the UI.
|
|
208
|
+
* Omit (or `0`) to wait indefinitely. Calls always fail fast — regardless of
|
|
209
|
+
* this option — once the socket closes or trust is refused.
|
|
210
|
+
*/
|
|
211
|
+
callTimeout?: number;
|
|
141
212
|
}
|
|
142
213
|
type DevframeRpcClientCall = BirpcReturn<DevframeRpcServerFunctions, DevframeRpcClientFunctions>['$call'];
|
|
143
214
|
type DevframeRpcClientCallEvent = BirpcReturn<DevframeRpcServerFunctions, DevframeRpcClientFunctions>['$callEvent'];
|
|
@@ -151,6 +222,17 @@ interface DevframeRpcClient {
|
|
|
151
222
|
* Whether the client is trusted
|
|
152
223
|
*/
|
|
153
224
|
readonly isTrusted: boolean | null;
|
|
225
|
+
/**
|
|
226
|
+
* The current connection status. Drives connection/auth/error UI without the
|
|
227
|
+
* consumer having to track the transport and trust handshake separately.
|
|
228
|
+
* Subscribe to `events.on('connection:status', …)` to react to changes.
|
|
229
|
+
*/
|
|
230
|
+
readonly status: DevframeConnectionStatus;
|
|
231
|
+
/**
|
|
232
|
+
* The most recent connection-level error (WebSocket error, refused trust, or
|
|
233
|
+
* failed connection-meta load), or `null` when the connection is healthy.
|
|
234
|
+
*/
|
|
235
|
+
readonly connectionError: Error | null;
|
|
154
236
|
/**
|
|
155
237
|
* The connection meta
|
|
156
238
|
*/
|
|
@@ -225,6 +307,8 @@ interface DevframeRpcClient {
|
|
|
225
307
|
}
|
|
226
308
|
interface DevframeRpcClientMode {
|
|
227
309
|
readonly isTrusted: boolean;
|
|
310
|
+
readonly status: DevframeConnectionStatus;
|
|
311
|
+
readonly connectionError: Error | null;
|
|
228
312
|
ensureTrusted: DevframeRpcClient['ensureTrusted'];
|
|
229
313
|
requestTrust: DevframeRpcClient['requestTrust'];
|
|
230
314
|
requestTrustWithToken: DevframeRpcClient['requestTrustWithToken'];
|
|
@@ -276,4 +360,4 @@ declare function createClientSettings<T extends Record<string, any> = Record<str
|
|
|
276
360
|
//#region src/client/index.d.ts
|
|
277
361
|
declare const connectDevframe: typeof getDevframeRpcClient;
|
|
278
362
|
//#endregion
|
|
279
|
-
export { DevframeClientRpcHost, DevframeRpcClient, DevframeRpcClientCall, DevframeRpcClientCallEvent, DevframeRpcClientCallOptional, DevframeRpcClientMode, DevframeRpcClientOptions, DevframeRpcContext, DevframeScopedClientContext, DevframeScopedClientRpc, DevframeScopedClientStreamingHost, RpcClientEvents, RpcStreamingClientHost, StreamingSubscribeOptions, authenticateWithUrlOtp, connectDevframe, consumeOtpFromUrl, createClientSettings, createRpcStreamingClientHost, createScopedClientContext, getDevframeRpcClient, readOtpFromUrl };
|
|
363
|
+
export { DevframeClientRpcHost, DevframeConnectionError, DevframeConnectionErrorKind, DevframeConnectionStatus, DevframeRpcClient, DevframeRpcClientCall, DevframeRpcClientCallEvent, DevframeRpcClientCallOptional, DevframeRpcClientMode, DevframeRpcClientOptions, DevframeRpcContext, DevframeScopedClientContext, DevframeScopedClientRpc, DevframeScopedClientStreamingHost, RpcClientEvents, RpcStreamingClientHost, StreamingSubscribeOptions, authenticateWithUrlOtp, connectDevframe, consumeOtpFromUrl, createClientSettings, createRpcStreamingClientHost, createScopedClientContext, getDevframeRpcClient, isCallableStatus, readOtpFromUrl };
|