@polycore/runner 0.4.0 → 1.0.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@polycore/runner",
3
- "version": "0.4.0",
3
+ "version": "1.0.0",
4
4
  "private": false,
5
5
  "description": "Polycore runner: executes governed, read-only-constrained connectors against a customer's datastores. Runs in the customer's own infrastructure; holds scoped credentials and connects outbound to the control plane.",
6
6
  "type": "module",
@@ -30,7 +30,7 @@
30
30
  "tsx": "4.21.0",
31
31
  "ws": "8.18.3",
32
32
  "zod": "4.4.3",
33
- "@polycore/protocol": "^0.4.0"
33
+ "@polycore/protocol": "^1.0.0"
34
34
  },
35
35
  "devDependencies": {
36
36
  "@types/node": "25.6.2",
package/src/action.ts CHANGED
@@ -3,20 +3,20 @@ import type { z } from "zod";
3
3
  /**
4
4
  * Blessed **actions** are the second execution lane: durable, customer-authored
5
5
  * operations (e.g. "customer 360", "refund user") that live in the customer's
6
- * own repo and are loaded by the runner. Unlike connectors generic,
7
- * read-only transports that ship inside the runner an action is a named,
6
+ * own repo and are loaded by the runner. Unlike connectors (generic,
7
+ * read-only transports that ship inside the runner), an action is a named,
8
8
  * parameterized unit of work with its own input/output contract.
9
9
  *
10
- * This is the same authoring shape as the desktop SDK's `defineAction`, minus
11
- * the UI/page concern: a Slack/agent caller consumes the structured `output`,
12
- * not a React page. An action reaches into the customer's own backend (their
13
- * Firestore, Stripe, internal APIs) using `secrets` the runner resolves from
14
- * its environment — the credential never leaves the runner's host.
10
+ * An action is a headless RPC with no UI/page concern: a Slack/agent/web caller
11
+ * consumes the structured `output`, not a rendered page. It reaches into the
12
+ * customer's own backend (their Firestore, Stripe, internal APIs) using
13
+ * `secrets` the runner resolves from its environment; the credential never
14
+ * leaves the runner's host.
15
15
  */
16
16
 
17
17
  export type ActionHazard = "read" | "write";
18
18
 
19
- /** Human-facing progress sink, mirroring the desktop SDK's `ctx.log`. */
19
+ /** Human-facing progress sink for an action's `run` (info/warn/error/success). */
20
20
  export interface ActionLogger {
21
21
  info(message: string): void;
22
22
  warn(message: string): void;
@@ -39,7 +39,7 @@ export interface Action<Input = unknown, Output = unknown> {
39
39
  readonly description: string;
40
40
  readonly tags?: readonly string[];
41
41
  /**
42
- * Hazard class. Defaults to `write` the safe default, since an
42
+ * Hazard class. Defaults to `write`, the safe default, since an
43
43
  * unclassified operation must be treated as dangerous and routed through
44
44
  * the approval gate. Declare `read` for idempotent, side-effect-free work.
45
45
  */
package/src/connect.ts CHANGED
@@ -26,6 +26,9 @@ export function describeConnectors(
26
26
  hazard: capability.hazard,
27
27
  kind: capability.kind,
28
28
  params: z.toJSONSchema(capability.params),
29
+ ...(capability.output === undefined
30
+ ? {}
31
+ : { result: z.toJSONSchema(capability.output) }),
29
32
  }));
30
33
  }
31
34
 
package/src/connector.ts CHANGED
@@ -93,6 +93,8 @@ export interface RegisteredCapability {
93
93
  readonly hazard: Hazard;
94
94
  readonly kind: CapabilityKind;
95
95
  readonly params: z.ZodType;
96
+ /** The result schema, when the capability declares one (actions do). */
97
+ readonly output?: z.ZodType;
96
98
  run(args: unknown, ctx: ConnectorContext): Promise<unknown>;
97
99
  }
98
100
 
@@ -203,6 +205,7 @@ export class ConnectorRegistry {
203
205
  hazard: action.hazard ?? "write",
204
206
  kind: "action",
205
207
  params: action.input,
208
+ output: action.output,
206
209
  run: (args, ctx) =>
207
210
  Promise.resolve(
208
211
  action.run({
package/src/index.ts CHANGED
@@ -113,7 +113,7 @@ export {
113
113
  // The pinned Zod, re-exported so action authors share the runner's exact
114
114
  // instance, schemas must be introspectable by the runner's `z.toJSONSchema`.
115
115
  // Authors import `{ defineAction, z }` from "@polycore/runner", never from a
116
- // desktop package or a second `zod` copy.
116
+ // second `zod` copy.
117
117
  export { z } from "zod";
118
118
 
119
119
  /** All built-in (Lane 1) connectors; SQL/HTTP families register here as they land. */
@@ -174,9 +174,9 @@ export const ACTIONS_DIRNAME = "actions";
174
174
  * file's directory (`baseDir`): a project's actions live in `actions/<slug>/`,
175
175
  * and when the runner serves a single project they may live directly in
176
176
  * `actions/`. Returns `undefined` when neither exists (a project with no
177
- * actions, or an env-driven config with no file directory) the runner then
177
+ * actions, or an env-driven config with no file directory); the runner then
178
178
  * serves only the built-in connectors. There is no `actionsDir` config field:
179
- * the layout is a fixed convention, exactly like the desktop `src/actions/`.
179
+ * the layout is a fixed convention (`actions/<slug>/`).
180
180
  */
181
181
  export function resolveActionsDir(
182
182
  baseDir: string,
@@ -198,7 +198,7 @@ export function resolveActionsDir(
198
198
  *
199
199
  * `actionsBaseDir` is the config file's directory; actions are discovered from
200
200
  * the `actions/` convention under it (see {@link resolveActionsDir}). Omit it
201
- * for an env-driven config with no file location the runner then serves only
201
+ * for an env-driven config with no file location; the runner then serves only
202
202
  * the built-in connectors.
203
203
  */
204
204
  export async function buildProjectRegistries(
@@ -13,8 +13,7 @@ import type { Action, LoadedAction } from "./action.js";
13
13
  * is recursed into.
14
14
  *
15
15
  * Modules are loaded via tsx's programmatic importer so the runner can load
16
- * raw `.ts` regardless of how its own process was started, exactly like the
17
- * desktop runtime's loader.
16
+ * raw `.ts` regardless of how its own process was started.
18
17
  */
19
18
  export async function loadActions(dir: string): Promise<LoadedAction[]> {
20
19
  const loaded: LoadedAction[] = [];