@devframes/plugin-inspect 0.0.1

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/LICENSE.md ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025-PRESENT Anthony Fu <https://github.com/antfu>
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,60 @@
1
+ # @devframes/plugin-inspect
2
+
3
+ > [!WARNING] Experimental
4
+ > This plugin is experimental and may change without a major version bump until
5
+ > it stabilizes.
6
+
7
+ A devframe plugin that inspects *its own* connection (and, when mounted in a
8
+ host, the host's): browse every registered RPC function with its metadata,
9
+ invoke read-only `query`/`static` functions and inspect the results, watch
10
+ shared-state keys update live, and explore the agent-exposed surface.
11
+
12
+ Ported in spirit from the RPC & State panels of
13
+ [`vitejs/devtools`](https://github.com/vitejs/devtools); rebuilt on devframe's
14
+ framework-neutral client (`connectDevframe`, `rpc.sharedState`) with a Vue + Vite SPA.
15
+
16
+ ## Use it standalone
17
+
18
+ ```bash
19
+ npx @devframes/plugin-inspect
20
+ ```
21
+
22
+ Opens the inspector against a fresh standalone devframe connection — useful as a
23
+ reference and for poking at the introspection RPCs themselves.
24
+
25
+ ## Mount into a Vite host
26
+
27
+ ```ts
28
+ // vite.config.ts
29
+ import { inspectVitePlugin } from '@devframes/plugin-inspect/vite'
30
+ import { defineConfig } from 'vite'
31
+
32
+ export default defineConfig({
33
+ plugins: [
34
+ inspectVitePlugin(),
35
+ ],
36
+ })
37
+ ```
38
+
39
+ ## Programmatic
40
+
41
+ ```ts
42
+ import { createInspectDevframe } from '@devframes/plugin-inspect'
43
+
44
+ const devframe = createInspectDevframe({ port: 9100 })
45
+ ```
46
+
47
+ ## RPC surface
48
+
49
+ All functions are namespaced `devframes-plugin-inspect:*`:
50
+
51
+ | Function | Type | What it returns |
52
+ |----------|------|-----------------|
53
+ | `list-functions` | `query` (snapshot) | Every registered RPC function with metadata (type, JSON-serializable/snapshot flags, args/return JSON Schema, agent exposure). |
54
+ | `invoke` | `action` | Invokes a read-only `query`/`static` function by name and returns a result envelope. Refuses `action`/`event` functions. |
55
+ | `list-state-keys` | `query` (snapshot) | The keys of every shared-state entry on the connection. |
56
+ | `describe-agent` | `query` (snapshot) | The agent manifest — tools and readable resources. |
57
+
58
+ The three `query` functions are agent-exposed (read-only) and bake into the
59
+ static dump, so the inspector still lists functions, state keys, and the agent
60
+ surface when deployed as a static SPA.
package/bin.mjs ADDED
@@ -0,0 +1,13 @@
1
+ #!/usr/bin/env node
2
+ import process from 'node:process'
3
+ import { createInspectCli } from './dist/cli.mjs'
4
+
5
+ async function main() {
6
+ const cli = createInspectCli()
7
+ await cli.parse()
8
+ }
9
+
10
+ main().catch((error) => {
11
+ console.error(error)
12
+ process.exit(1)
13
+ })
package/dist/cli.d.mts ADDED
@@ -0,0 +1,12 @@
1
+ import { CliHandle } from "devframe/adapters/cli";
2
+
3
+ //#region src/cli.d.ts
4
+ /**
5
+ * Build the standalone CLI for the inspector — backs the package `bin`
6
+ * (`devframe-inspect`) and `npx @devframes/plugin-inspect`. Wraps the
7
+ * default {@link createInspectDevframe} definition with devframe's
8
+ * `dev` / `build` / `spa` / `mcp` command shell.
9
+ */
10
+ declare function createInspectCli(): CliHandle;
11
+ //#endregion
12
+ export { createInspectCli };
package/dist/cli.mjs ADDED
@@ -0,0 +1,14 @@
1
+ import { n as inspectDevframe } from "./src-9kAqdLdh.mjs";
2
+ import { createCli } from "devframe/adapters/cli";
3
+ //#region src/cli.ts
4
+ /**
5
+ * Build the standalone CLI for the inspector — backs the package `bin`
6
+ * (`devframe-inspect`) and `npx @devframes/plugin-inspect`. Wraps the
7
+ * default {@link createInspectDevframe} definition with devframe's
8
+ * `dev` / `build` / `spa` / `mcp` command shell.
9
+ */
10
+ function createInspectCli() {
11
+ return createCli(inspectDevframe);
12
+ }
13
+ //#endregion
14
+ export { createInspectCli };
@@ -0,0 +1,12 @@
1
+ import { i as RpcFunctionInfo, n as InvokeResult, r as RpcFunctionAgentInfo, t as AgentManifest } from "../types-Cz7H8Eh1.mjs";
2
+ import { DevframeRpcClient, DevframeRpcClientOptions } from "devframe/client";
3
+
4
+ //#region src/client/index.d.ts
5
+ /**
6
+ * Connect to the inspector's devframe backend. A thin, typed wrapper
7
+ * around devframe's {@link connectDevframe}; the SPA derives its base
8
+ * from `document.baseURI`, so no options are required in the common case.
9
+ */
10
+ declare function connectInspect(options?: DevframeRpcClientOptions): Promise<DevframeRpcClient>;
11
+ //#endregion
12
+ export { type AgentManifest, type DevframeRpcClient, type InvokeResult, type RpcFunctionAgentInfo, type RpcFunctionInfo, connectInspect };
@@ -0,0 +1,12 @@
1
+ import { connectDevframe } from "devframe/client";
2
+ //#region src/client/index.ts
3
+ /**
4
+ * Connect to the inspector's devframe backend. A thin, typed wrapper
5
+ * around devframe's {@link connectDevframe}; the SPA derives its base
6
+ * from `document.baseURI`, so no options are required in the common case.
7
+ */
8
+ function connectInspect(options) {
9
+ return connectDevframe(options);
10
+ }
11
+ //#endregion
12
+ export { connectInspect };
@@ -0,0 +1,37 @@
1
+ import { DevframeDefinition } from "devframe/types";
2
+
3
+ //#region src/index.d.ts
4
+ interface InspectDevframeOptions {
5
+ /** Override the devframe id (and default CLI command / mount path). */
6
+ id?: string;
7
+ /** Override the display name shown in a host dock. */
8
+ name?: string;
9
+ /** Override the dock icon. */
10
+ icon?: string;
11
+ /**
12
+ * Override the mount path. Left unset, the SPA mounts at `/` standalone
13
+ * and `/__<id>/` when hosted (Vite/embedded).
14
+ */
15
+ basePath?: string;
16
+ /** Preferred standalone CLI port. */
17
+ port?: number;
18
+ /**
19
+ * Require the trust handshake on the standalone server. Defaults to
20
+ * `false` (auto-trust) since the inspector is a single-user localhost
21
+ * tool. Hosted adapters manage their own auth.
22
+ */
23
+ auth?: boolean;
24
+ }
25
+ /**
26
+ * Build a {@link DevframeDefinition} for the Devframe Inspector. The
27
+ * same definition runs standalone (`/cli`, `/spa`, `/build`) and mounts
28
+ * into a host (`/vite`, hub).
29
+ *
30
+ * @experimental This plugin is experimental and may change without a major
31
+ * version bump until it stabilizes.
32
+ */
33
+ declare function createInspectDevframe(options?: InspectDevframeOptions): DevframeDefinition;
34
+ /** The default inspector devframe definition. */
35
+ declare const inspectDevframe: DevframeDefinition;
36
+ //#endregion
37
+ export { createInspectDevframe as n, inspectDevframe as r, InspectDevframeOptions as t };
@@ -0,0 +1,3 @@
1
+ import { i as RpcFunctionInfo, n as InvokeResult } from "./types-Cz7H8Eh1.mjs";
2
+ import { n as createInspectDevframe, r as inspectDevframe, t as InspectDevframeOptions } from "./index-E4zIjo1K.mjs";
3
+ export { InspectDevframeOptions, InvokeResult, RpcFunctionInfo, createInspectDevframe, inspectDevframe as default };
package/dist/index.mjs ADDED
@@ -0,0 +1,2 @@
1
+ import { n as inspectDevframe, t as createInspectDevframe } from "./src-9kAqdLdh.mjs";
2
+ export { createInspectDevframe, inspectDevframe as default };
@@ -0,0 +1,12 @@
1
+ import { serverFunctions } from "../rpc/index.mjs";
2
+ import { DevframeNodeContext } from "devframe/types";
3
+
4
+ //#region src/node/index.d.ts
5
+ /**
6
+ * Register the inspector's introspection RPC functions on a devframe
7
+ * node context. Called from the definition's `setup(ctx)` and reusable
8
+ * by host adapters that wire their own context.
9
+ */
10
+ declare function setupInspect(ctx: DevframeNodeContext): void;
11
+ //#endregion
12
+ export { serverFunctions, setupInspect };
@@ -0,0 +1,12 @@
1
+ import { t as serverFunctions } from "../rpc-Cb6r6pvt.mjs";
2
+ //#region src/node/index.ts
3
+ /**
4
+ * Register the inspector's introspection RPC functions on a devframe
5
+ * node context. Called from the definition's `setup(ctx)` and reusable
6
+ * by host adapters that wire their own context.
7
+ */
8
+ function setupInspect(ctx) {
9
+ for (const fn of serverFunctions) ctx.rpc.register(fn);
10
+ }
11
+ //#endregion
12
+ export { serverFunctions, setupInspect };
@@ -0,0 +1,100 @@
1
+ import { i as RpcFunctionInfo, n as InvokeResult } from "../types-Cz7H8Eh1.mjs";
2
+ import * as _$devframe from "devframe";
3
+ import * as _$devframe_rpc0 from "devframe/rpc";
4
+ import { RpcDefinitionsToFunctions } from "devframe/rpc";
5
+
6
+ //#region src/rpc/index.d.ts
7
+ /**
8
+ * The introspection RPC functions registered by the inspector plugin.
9
+ * Namespaced `devframes-plugin-inspect:*` per the plugin convention.
10
+ */
11
+ declare const serverFunctions: readonly [{
12
+ name: "devframes-plugin-inspect:list-functions";
13
+ type?: "query" | undefined;
14
+ cacheable?: boolean;
15
+ args?: undefined;
16
+ returns?: undefined;
17
+ jsonSerializable?: boolean;
18
+ agent?: _$devframe.RpcFunctionAgentOptions;
19
+ setup?: ((context: _$devframe.DevframeNodeContext) => _$devframe_rpc0.Thenable<_$devframe_rpc0.RpcFunctionSetupResult<[], Promise<RpcFunctionInfo[]>>>) | undefined;
20
+ handler?: (() => Promise<RpcFunctionInfo[]>) | undefined;
21
+ dump?: _$devframe_rpc0.RpcDump<[], Promise<RpcFunctionInfo[]>, _$devframe.DevframeNodeContext> | undefined;
22
+ snapshot?: boolean;
23
+ __cache?: WeakMap<object, _$devframe_rpc0.Thenable<_$devframe_rpc0.RpcFunctionSetupResult<[], Promise<RpcFunctionInfo[]>>>> | undefined;
24
+ __promise?: _$devframe_rpc0.Thenable<_$devframe_rpc0.RpcFunctionSetupResult<[], Promise<RpcFunctionInfo[]>>> | undefined;
25
+ }, {
26
+ name: "devframes-plugin-inspect:invoke";
27
+ type?: "action" | undefined;
28
+ cacheable?: boolean;
29
+ args?: undefined;
30
+ returns?: undefined;
31
+ jsonSerializable?: boolean;
32
+ agent?: _$devframe.RpcFunctionAgentOptions;
33
+ setup?: ((context: _$devframe.DevframeNodeContext) => _$devframe_rpc0.Thenable<_$devframe_rpc0.RpcFunctionSetupResult<[name: string, args?: unknown[] | undefined], Promise<InvokeResult>>>) | undefined;
34
+ handler?: ((name: string, args?: unknown[] | undefined) => Promise<InvokeResult>) | undefined;
35
+ dump?: _$devframe_rpc0.RpcDump<[name: string, args?: unknown[] | undefined], Promise<InvokeResult>, _$devframe.DevframeNodeContext> | undefined;
36
+ snapshot?: boolean;
37
+ __cache?: WeakMap<object, _$devframe_rpc0.Thenable<_$devframe_rpc0.RpcFunctionSetupResult<[name: string, args?: unknown[] | undefined], Promise<InvokeResult>>>> | undefined;
38
+ __promise?: _$devframe_rpc0.Thenable<_$devframe_rpc0.RpcFunctionSetupResult<[name: string, args?: unknown[] | undefined], Promise<InvokeResult>>> | undefined;
39
+ }, {
40
+ name: "devframes-plugin-inspect:list-state-keys";
41
+ type?: "query" | undefined;
42
+ cacheable?: boolean;
43
+ args?: undefined;
44
+ returns?: undefined;
45
+ jsonSerializable?: boolean;
46
+ agent?: _$devframe.RpcFunctionAgentOptions;
47
+ setup?: ((context: _$devframe.DevframeNodeContext) => _$devframe_rpc0.Thenable<_$devframe_rpc0.RpcFunctionSetupResult<[], Promise<string[]>>>) | undefined;
48
+ handler?: (() => Promise<string[]>) | undefined;
49
+ dump?: _$devframe_rpc0.RpcDump<[], Promise<string[]>, _$devframe.DevframeNodeContext> | undefined;
50
+ snapshot?: boolean;
51
+ __cache?: WeakMap<object, _$devframe_rpc0.Thenable<_$devframe_rpc0.RpcFunctionSetupResult<[], Promise<string[]>>>> | undefined;
52
+ __promise?: _$devframe_rpc0.Thenable<_$devframe_rpc0.RpcFunctionSetupResult<[], Promise<string[]>>> | undefined;
53
+ }, {
54
+ name: "devframes-plugin-inspect:describe-agent";
55
+ type?: "query" | undefined;
56
+ cacheable?: boolean;
57
+ args?: undefined;
58
+ returns?: undefined;
59
+ jsonSerializable?: boolean;
60
+ agent?: _$devframe.RpcFunctionAgentOptions;
61
+ setup?: ((context: _$devframe.DevframeNodeContext) => _$devframe_rpc0.Thenable<_$devframe_rpc0.RpcFunctionSetupResult<[], Promise<_$devframe.AgentManifest>>>) | undefined;
62
+ handler?: (() => Promise<_$devframe.AgentManifest>) | undefined;
63
+ dump?: _$devframe_rpc0.RpcDump<[], Promise<_$devframe.AgentManifest>, _$devframe.DevframeNodeContext> | undefined;
64
+ snapshot?: boolean;
65
+ __cache?: WeakMap<object, _$devframe_rpc0.Thenable<_$devframe_rpc0.RpcFunctionSetupResult<[], Promise<_$devframe.AgentManifest>>>> | undefined;
66
+ __promise?: _$devframe_rpc0.Thenable<_$devframe_rpc0.RpcFunctionSetupResult<[], Promise<_$devframe.AgentManifest>>> | undefined;
67
+ }, {
68
+ name: "devframes-plugin-inspect:invoke-agent-tool";
69
+ type?: "action" | undefined;
70
+ cacheable?: boolean;
71
+ args?: undefined;
72
+ returns?: undefined;
73
+ jsonSerializable?: boolean;
74
+ agent?: _$devframe.RpcFunctionAgentOptions;
75
+ setup?: ((context: _$devframe.DevframeNodeContext) => _$devframe_rpc0.Thenable<_$devframe_rpc0.RpcFunctionSetupResult<[id: string, args: unknown], Promise<InvokeResult>>>) | undefined;
76
+ handler?: ((id: string, args: unknown) => Promise<InvokeResult>) | undefined;
77
+ dump?: _$devframe_rpc0.RpcDump<[id: string, args: unknown], Promise<InvokeResult>, _$devframe.DevframeNodeContext> | undefined;
78
+ snapshot?: boolean;
79
+ __cache?: WeakMap<object, _$devframe_rpc0.Thenable<_$devframe_rpc0.RpcFunctionSetupResult<[id: string, args: unknown], Promise<InvokeResult>>>> | undefined;
80
+ __promise?: _$devframe_rpc0.Thenable<_$devframe_rpc0.RpcFunctionSetupResult<[id: string, args: unknown], Promise<InvokeResult>>> | undefined;
81
+ }, {
82
+ name: "devframes-plugin-inspect:read-agent-resource";
83
+ type?: "action" | undefined;
84
+ cacheable?: boolean;
85
+ args?: undefined;
86
+ returns?: undefined;
87
+ jsonSerializable?: boolean;
88
+ agent?: _$devframe.RpcFunctionAgentOptions;
89
+ setup?: ((context: _$devframe.DevframeNodeContext) => _$devframe_rpc0.Thenable<_$devframe_rpc0.RpcFunctionSetupResult<[id: string], Promise<InvokeResult>>>) | undefined;
90
+ handler?: ((id: string) => Promise<InvokeResult>) | undefined;
91
+ dump?: _$devframe_rpc0.RpcDump<[id: string], Promise<InvokeResult>, _$devframe.DevframeNodeContext> | undefined;
92
+ snapshot?: boolean;
93
+ __cache?: WeakMap<object, _$devframe_rpc0.Thenable<_$devframe_rpc0.RpcFunctionSetupResult<[id: string], Promise<InvokeResult>>>> | undefined;
94
+ __promise?: _$devframe_rpc0.Thenable<_$devframe_rpc0.RpcFunctionSetupResult<[id: string], Promise<InvokeResult>>> | undefined;
95
+ }];
96
+ declare module 'devframe' {
97
+ interface DevframeRpcServerFunctions extends RpcDefinitionsToFunctions<typeof serverFunctions> {}
98
+ }
99
+ //#endregion
100
+ export { serverFunctions };
@@ -0,0 +1,2 @@
1
+ import { t as serverFunctions } from "../rpc-Cb6r6pvt.mjs";
2
+ export { serverFunctions };
@@ -0,0 +1,256 @@
1
+ import { createDefineWrapperWithContext } from "devframe/rpc";
2
+ import { defineDiagnostics } from "nostics";
3
+ import { toJsonSchema } from "@valibot/to-json-schema";
4
+ //#region src/rpc/functions/_define.ts
5
+ /**
6
+ * `defineRpcFunction` pre-bound to the framework-neutral
7
+ * {@link DevframeNodeContext}, so each inspector function's `setup(ctx)`
8
+ * receives the typed node context (`ctx.rpc`, `ctx.agent`, …) instead of
9
+ * the default `undefined` context.
10
+ */
11
+ const defineInspectRpc = createDefineWrapperWithContext();
12
+ //#endregion
13
+ //#region src/rpc/functions/describe-agent.ts
14
+ /**
15
+ * Surface the agent-exposed surface of the connection: the unified
16
+ * manifest of tools (RPC functions flagged with `agent`, plus
17
+ * host-registered tools) and readable resources. `snapshot: true` bakes
18
+ * the manifest into the static dump for `build`/`spa` mode.
19
+ */
20
+ const describeAgent = defineInspectRpc({
21
+ name: "devframes-plugin-inspect:describe-agent",
22
+ type: "query",
23
+ jsonSerializable: true,
24
+ snapshot: true,
25
+ agent: {
26
+ description: "Describe the agent-exposed surface of this devframe: the list of tools (agent-flagged RPC functions and host-registered tools) and readable resources, with their titles, descriptions, safety hints, and schemas. Read-only.",
27
+ title: "Describe agent surface"
28
+ },
29
+ setup: (ctx) => ({ handler: async () => {
30
+ return ctx.agent.list();
31
+ } })
32
+ });
33
+ //#endregion
34
+ //#region src/diagnostics.ts
35
+ /**
36
+ * Structured diagnostics for `@devframes/plugin-inspect`. Node-side only.
37
+ * Codes use the plugin-private `DP_INSPECT_` band (see the built-in
38
+ * plugins planning index) so they never collide with devframe core
39
+ * (`DF00xx`) or `@devframes/hub` (`DF80xx`).
40
+ */
41
+ const diagnostics = defineDiagnostics({
42
+ docsBase: "https://devfra.me/errors",
43
+ codes: {
44
+ DP_INSPECT_0001: {
45
+ why: (p) => `Cannot invoke "${p.name}" — no RPC function with that name is registered on this connection.`,
46
+ fix: "Call `devframes-plugin-inspect:list-functions` to see the registered names, or check for a typo."
47
+ },
48
+ DP_INSPECT_0002: {
49
+ why: (p) => `Refusing to invoke "${p.name}" — only read-only "query" and "static" functions are invokable from the inspector, but this one is "${p.type}".`,
50
+ fix: "The inspector deliberately blocks `action`/`event` functions to avoid triggering side effects. Invoke those through their own UI instead."
51
+ }
52
+ }
53
+ });
54
+ //#endregion
55
+ //#region src/rpc/functions/invoke.ts
56
+ const INVOKABLE_TYPES$1 = new Set(["query", "static"]);
57
+ /**
58
+ * Invoke a read-only RPC function by name and return a result envelope.
59
+ *
60
+ * Deliberately gated to `query` / `static` functions — `action` and
61
+ * `event` functions may carry side effects, so the inspector refuses to
62
+ * fire them (`DP_INSPECT_0002`). Uses structured-clone serialization
63
+ * (default) so arbitrary return values round-trip without the strict-JSON
64
+ * constraints that `jsonSerializable: true` would impose.
65
+ */
66
+ const invoke = defineInspectRpc({
67
+ name: "devframes-plugin-inspect:invoke",
68
+ type: "action",
69
+ setup: (ctx) => ({ handler: async (name, args = []) => {
70
+ const def = ctx.rpc.definitions.get(name);
71
+ if (!def) throw diagnostics.DP_INSPECT_0001({ name });
72
+ const type = def.type ?? "query";
73
+ if (!INVOKABLE_TYPES$1.has(type)) throw diagnostics.DP_INSPECT_0002({
74
+ name,
75
+ type
76
+ });
77
+ const start = Date.now();
78
+ try {
79
+ return {
80
+ ok: true,
81
+ result: await ctx.rpc.invokeLocal(name, ...args),
82
+ durationMs: Date.now() - start
83
+ };
84
+ } catch (error) {
85
+ const e = error;
86
+ return {
87
+ ok: false,
88
+ error: {
89
+ name: e?.name ?? "Error",
90
+ message: e?.message ?? String(error),
91
+ stack: e?.stack
92
+ },
93
+ durationMs: Date.now() - start
94
+ };
95
+ }
96
+ } })
97
+ });
98
+ //#endregion
99
+ //#region src/rpc/functions/invoke-agent-tool.ts
100
+ const invokeAgentTool = defineInspectRpc({
101
+ name: "devframes-plugin-inspect:invoke-agent-tool",
102
+ type: "action",
103
+ setup: (ctx) => ({ handler: async (id, args) => {
104
+ const start = Date.now();
105
+ try {
106
+ return {
107
+ ok: true,
108
+ result: await ctx.agent.invoke(id, args),
109
+ durationMs: Date.now() - start
110
+ };
111
+ } catch (error) {
112
+ const e = error;
113
+ return {
114
+ ok: false,
115
+ error: {
116
+ name: e?.name ?? "Error",
117
+ message: e?.message ?? String(error),
118
+ stack: e?.stack
119
+ },
120
+ durationMs: Date.now() - start
121
+ };
122
+ }
123
+ } })
124
+ });
125
+ //#endregion
126
+ //#region src/rpc/functions/_schema.ts
127
+ const FALLBACK_SCHEMA = Object.freeze({
128
+ type: "object",
129
+ additionalProperties: true
130
+ });
131
+ /**
132
+ * Convert a valibot return schema to JSON Schema, swallowing
133
+ * conversion failures (unsupported valibot actions) into a permissive
134
+ * fallback so introspection never throws.
135
+ */
136
+ function returnSchemaToJson(schema) {
137
+ if (!schema) return void 0;
138
+ try {
139
+ return toJsonSchema(schema);
140
+ } catch {
141
+ return FALLBACK_SCHEMA;
142
+ }
143
+ }
144
+ /**
145
+ * Convert the positional args valibot schemas to a single JSON Schema
146
+ * tuple (`type: 'array'` + `prefixItems`). Returns `undefined` when the
147
+ * function declares no args.
148
+ */
149
+ function argsSchemaToJson(args) {
150
+ if (!args || args.length === 0) return void 0;
151
+ return {
152
+ type: "array",
153
+ prefixItems: args.map((arg) => {
154
+ try {
155
+ return toJsonSchema(arg);
156
+ } catch {
157
+ return FALLBACK_SCHEMA;
158
+ }
159
+ })
160
+ };
161
+ }
162
+ //#endregion
163
+ //#region src/rpc/functions/list-functions.ts
164
+ const INVOKABLE_TYPES = new Set(["query", "static"]);
165
+ //#endregion
166
+ //#region src/rpc/index.ts
167
+ /**
168
+ * The introspection RPC functions registered by the inspector plugin.
169
+ * Namespaced `devframes-plugin-inspect:*` per the plugin convention.
170
+ */
171
+ const serverFunctions = [
172
+ defineInspectRpc({
173
+ name: "devframes-plugin-inspect:list-functions",
174
+ type: "query",
175
+ jsonSerializable: true,
176
+ snapshot: true,
177
+ agent: {
178
+ description: "List every RPC function registered on this devframe connection, with metadata (name, type, JSON-serializable/snapshot flags, args/return schema, agent exposure). Read-only — the canonical way to discover what the running devframe can do.",
179
+ title: "List RPC functions"
180
+ },
181
+ setup: (ctx) => ({ handler: async () => {
182
+ const out = [];
183
+ for (const [name, fn] of ctx.rpc.definitions) {
184
+ const type = fn.type ?? "query";
185
+ let agent;
186
+ if (fn.agent) agent = {
187
+ description: fn.agent.description,
188
+ title: fn.agent.title,
189
+ safety: fn.agent.safety,
190
+ tags: fn.agent.tags
191
+ };
192
+ out.push({
193
+ name,
194
+ type,
195
+ jsonSerializable: fn.jsonSerializable === true,
196
+ snapshot: fn.snapshot === true,
197
+ cacheable: fn.cacheable === true,
198
+ hasArgs: !!fn.args,
199
+ hasReturns: !!fn.returns,
200
+ hasDump: !!fn.dump,
201
+ hasSetup: !!fn.setup,
202
+ hasHandler: !!fn.handler,
203
+ invokable: INVOKABLE_TYPES.has(type),
204
+ agent,
205
+ argsSchema: argsSchemaToJson(fn.args),
206
+ returnsSchema: returnSchemaToJson(fn.returns)
207
+ });
208
+ }
209
+ out.sort((a, b) => a.name.localeCompare(b.name));
210
+ return out;
211
+ } })
212
+ }),
213
+ invoke,
214
+ defineInspectRpc({
215
+ name: "devframes-plugin-inspect:list-state-keys",
216
+ type: "query",
217
+ jsonSerializable: true,
218
+ snapshot: true,
219
+ agent: {
220
+ description: "List the keys of all shared-state entries published by this devframe connection. Read-only. Pair with the built-in shared-state reads to inspect individual values.",
221
+ title: "List shared-state keys"
222
+ },
223
+ setup: (ctx) => ({ handler: async () => {
224
+ return [...ctx.rpc.sharedState.keys()].sort();
225
+ } })
226
+ }),
227
+ describeAgent,
228
+ invokeAgentTool,
229
+ defineInspectRpc({
230
+ name: "devframes-plugin-inspect:read-agent-resource",
231
+ type: "action",
232
+ setup: (ctx) => ({ handler: async (id) => {
233
+ const start = Date.now();
234
+ try {
235
+ return {
236
+ ok: true,
237
+ result: await ctx.agent.read(id),
238
+ durationMs: Date.now() - start
239
+ };
240
+ } catch (error) {
241
+ const e = error;
242
+ return {
243
+ ok: false,
244
+ error: {
245
+ name: e?.name ?? "Error",
246
+ message: e?.message ?? String(error),
247
+ stack: e?.stack
248
+ },
249
+ durationMs: Date.now() - start
250
+ };
251
+ }
252
+ } })
253
+ })
254
+ ];
255
+ //#endregion
256
+ export { serverFunctions as t };