@protobase/cli 0.67.9 → 0.67.10

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.
@@ -1,4 +1,4 @@
1
1
  //#region package.json
2
- var version = "0.67.9";
2
+ var version = "0.67.10";
3
3
  //#endregion
4
4
  export { version };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@protobase/cli",
3
- "version": "0.67.9",
3
+ "version": "0.67.10",
4
4
  "description": "The protobase command: scaffold, doctor, dev, build and serve a Protobase project.",
5
5
  "license": "Apache-2.0",
6
6
  "repository": {
@@ -43,12 +43,12 @@
43
43
  "dependencies": {
44
44
  "@better-auth/core": "^1.7.12",
45
45
  "@hono/node-server": "^2.1.3",
46
- "@protobase/config": "0.67.9",
47
- "@protobase/layout": "0.67.9",
48
- "@protobase/query": "0.67.9",
49
- "@protobase/schema": "0.67.9",
50
- "@protobase/server": "0.67.9",
51
- "@protobase/ui": "0.67.9",
46
+ "@protobase/config": "0.67.10",
47
+ "@protobase/layout": "0.67.10",
48
+ "@protobase/query": "0.67.10",
49
+ "@protobase/schema": "0.67.10",
50
+ "@protobase/server": "0.67.10",
51
+ "@protobase/ui": "0.67.10",
52
52
  "@react-email/render": "^2.1.0",
53
53
  "@scalar/hono-api-reference": "^0.12.10",
54
54
  "@sentry/vite-plugin": "^11.10.0",
@@ -14,3 +14,4 @@ Graphs of steps the server runs along their edges, written in a language a model
14
14
  - [Runs and step records](../reference/workflows.md#runs-and-their-steps) (beta): Each run started by hand through the API or from the app's code, with every step's input, output, logs, timing, tries and error recorded, secrets blanked out.
15
15
  - [Runs that survive restarts](../reference/workflows.md#how-a-run-is-run) (beta): A run takes up where it stood after a restart or a crashed worker, never running a saved step again, and every limit fails closed.
16
16
  - [Who may run workflows](../reference/workflows.md#who-may-do-what) (beta): Making, changing and running workflows and reading their runs are each granted by name, within the tenant.
17
+ - [Workflows over MCP](../reference/mcp.md#workflows) (beta): AI clients find, write, validate, change by a small edit and test-run workflows as the signed-in person, and read each step of a run to fix the one that failed.
@@ -86,6 +86,31 @@ When a resource takes [comments](comments.md), the endpoint also offers `list_co
86
86
 
87
87
  `add_comment` is a write: the person approves each comment first, seeing the record's name and the whole comment, unless they hold one of the [roles without approval](#writes-without-approval). With writes limited to some resources, it comments only on those. A comment it adds mentions nobody, so it sends no emails. An empty comment, one over 10,000 characters, a resource without comments, and a record the person may not read, or one that is soft-deleted, are refused before asking.
88
88
 
89
+ ### Workflows
90
+
91
+ In an app with [workflows](workflows.md), the endpoint also offers tools to find, make, change and test-run them, and its instructions describe the workflow language: the document, the states, reading values by name, errors and retries, with an example. A client can write a working workflow from them and the tools alone, without the docs. Each tool goes through the workflow resources as the person, so their [grants](workflows.md#who-may-do-what) and tenant apply: someone without them is answered as for a resource that is not there, and nothing changes.
92
+
93
+ | Tool | What it does |
94
+ | --- | --- |
95
+ | `list_workflow_types` | The step types a Task names as its `Resource`, each with its arguments (required or not, and what each takes), its result and the errors it fails with; and the triggers, how the definition holds each and the input a run gets from it. |
96
+ | `list_workflows` | A page of the workflows the person may read, newest change first, without their definitions: `filter` on `name`, `page_size` (20 by default, at most 100) and `page_token`. |
97
+ | `get_workflow` | One workflow with its whole definition and its ETag. |
98
+ | `validate_workflow` | Checks a `definition`, or a workflow's `id` with an `edit` of its saved definition, as a save checks it, and saves nothing: `{ valid: true }`, or `{ valid: false, problems }`. |
99
+ | `get_workflow_run` | A run's status, input, output, error and cause, with its steps in the order they ran, each with its state, scope, try, status, input, output, assigned variables, logs, error and cause; `state` reads one state's steps, a page of 20 by default. |
100
+ | `create_workflow` | Creates a workflow from its `name`, `description` and `definition`, and returns its `id`, `version` and ETag. |
101
+ | `update_workflow` | Changes a workflow's definition by an `edit` or whole, as `definition`, and its `name` or `description`, and returns its `id`, new `version` and ETag. With the `etag` that `get_workflow` gave, it fails when someone changed the workflow since; an edit without one is saved against the version it was applied to. |
102
+ | `run_workflow` | Starts a run of a workflow's current version with an `input`, and returns its `run_id` and `status`. |
103
+
104
+ An `edit` is a [JSON Merge Patch](https://www.rfc-editor.org/rfc/rfc7396) of the saved definition: only what changes, at its place in the document. An object merges into the object there, `null` removes a member, and any other value, a list included, replaces it. Changing one argument of one state:
105
+
106
+ ```json
107
+ { "id": "...", "edit": { "stateMachine": { "States": { "Notify": { "Arguments": { "url": "https://hooks.example.com/v2" } } } } } }
108
+ ```
109
+
110
+ A definition the save check refuses comes back as `{ "error": "invalid-workflow", "message": ..., "problems": [...] }`, each problem `{ state, field, message }` naming the state, the field and what was expected, as `validate_workflow` gives them; nothing is saved. A run goes on in the background on the app's jobs, so `run_workflow` returns while it is queued: the client reads it with `get_workflow_run` until it has `succeeded` or `failed`, fixes the step that failed and runs it again.
111
+
112
+ `create_workflow`, `update_workflow` and `run_workflow` come with [writes](#writes), and the person approves each first, as any write, unless they hold one of the [roles without approval](#writes-without-approval); with writes limited to some resources, they save on `workflows` and run on `workflow_runs` only when the list names them. A run does what its steps do, such as requests, mail and record writes, as the workflow's last editor.
113
+
89
114
  ### SQL for admins
90
115
 
91
116
  `mcpEndpoint.sql` also offers `run_read_only_query`, as in the [assistant](assistant.md#the-built-in-backend), to people with the `admin` or `ai` role:
@@ -255,7 +280,8 @@ The endpoint serves each request on its own, without an MCP session: a `GET` or
255
280
 
256
281
  - `mcpHandler({ authenticate, resource, scope, server })`: the endpoint as a fetch handler. It checks the host, admits a valid token (`mcpGate`) and serves the request with the server that `server(session, request)` builds for its caller; `request` is the HTTP request, such as for the language the person reads.
257
282
  - `mcpServer({ info, instructions, tools, context, report, rolesWithoutApproval, approvals })`: an MCP server named by `info`, its `name`, `version` and `icons`, such as `mcpIcons(origin, icons)`, the app's icons on `origin`, and offering [assistant tools](assistant.md#the-apps-own-tools), each with its JSON Schema, its `annotations`, MCP's tool hints, and its `title` and `_meta`, and each refusing as [the app's own tools](#the-apps-own-tools) do. `context` is the tools' context without `approve`, with the `locale` its approvals are asked in (English when absent): each call gets its own, which asks the client's user, or approves at once when the session's user holds one of `rolesWithoutApproval`. It is a `ToolContext`, with the app's `records`, `resources()` and `show`, unless every tool is declared with a smaller one, such as `defineTool<BaseToolContext>(...)`, whose context is only `session`, `locale` and `approve`: a host without app records then passes `{ session }`. `report` gets what a tool throws other than a refusal. `approvals` is `mcpApprovals()`, built once and passed to every server the endpoint builds: it keeps the approvals asked for until they are answered or expire. `instructions` is what it tells clients when they connect, by default `mcpInstructions`, the advice on reading records above.
258
- - `mcpTools({ db, sql, writes, commented, own })`: the endpoint's tools for a session; `writes` is `true`, `false` or `{ resources, rolesWithoutApproval }`, `commented` names the resources with comments, and `own` are [the app's own tools](#the-apps-own-tools), offered after the rest.
283
+ - `mcpTools({ db, sql, writes, commented, workflows, own })`: the endpoint's tools for a session; `writes` is `true`, `false` or `{ resources, rolesWithoutApproval }`, `commented` names the resources with comments, `workflows: true` offers the [workflow tools](#workflows), and `own` are [the app's own tools](#the-apps-own-tools), offered after the rest.
284
+ - `workflowReadTools()` and `workflowWriteTools({ resources })`: the workflow tools alone, and `workflowInstructions`, what the endpoint tells clients about the language, to append to `mcpInstructions`.
259
285
  - `readRecordTools()`, or `listResourcesTool()`, `describeResourceTool()`, `listRecordsTool()` and `getRecordTool()`: the read tools alone; `readOnlyQueryTool(db)` is `run_read_only_query`, and `readWriteQueryTool(db)` proposes one write statement that the user approves before it runs.
260
286
  - `commentTools({ commented }, writes)`, or `listCommentsTool({ commented })` and `addCommentTool({ commented, resources })`: the comment tools on the resources named in `commented`, which call the context's `comments`, and `add_comment` only when `writes` is not `false`.
261
287
  - `writeRecordTools({ resources })`, or `createRecordTool(...)`, `updateRecordTool(...)` and `deleteRecordTool(...)`: the single write tools alone, on the listed resources or, without `resources`, on any; `batchWriteTool({ resources })` is `batch_write` alone.
@@ -5,7 +5,7 @@
5
5
  Workflows written as state machines in the States Language with JSONata, checked on every save, run step by step on the app's jobs, with every step recorded.
6
6
 
7
7
  :::caution[Beta]
8
- Workflows run when they are started through the API or from the app's code. Triggers, sign-in connections to other services, MCP tools for them and a graph editor are not built yet.
8
+ Workflows run when they are started through the API, over MCP or from the app's code. Triggers, sign-in connections to other services and a graph editor are not built yet.
9
9
  :::
10
10
 
11
11
  A **workflow** is a graph of steps that the server runs one after another along its edges: fetch something, decide, run a step per item, merge the results, write records, send mail. It is written in the **States Language**, the JSON language of state machines, with **JSONata** as its expression language, in a profile of it that reads every value by name. A language model writes and changes it as easily as a person, and the same document is what the server checks and runs. Each run records every step it takes, with what the step read, gave and logged.
@@ -93,7 +93,7 @@ The document holds no layout: an editor lays the graph out from its edges.
93
93
  | `"record": { "events": ["<resource>.<event>"] }` | on each of those record events, such as `deals.created` | `{ event, resource, key, after, before, changed }` |
94
94
  | `"manual": {}` | when someone runs the workflow by hand | the input they give |
95
95
 
96
- A save checks a trigger's shape; runs start through the API or the app's code. <gap>A webhook, schedule, mail or record trigger cannot start runs because the triggers are not implemented.</gap>
96
+ A save checks a trigger's shape; runs start through the API, over MCP or from the app's code. <gap>A webhook, schedule, mail or record trigger cannot start runs because the triggers are not implemented.</gap>
97
97
 
98
98
  ### Reading values by name
99
99
 
@@ -121,6 +121,8 @@ The save is refused, naming each state and field, when the document does not fit
121
121
 
122
122
  The problem's `problems` lists them as `{ state, field, message }`, where a state inside a Map is named by its path, such as `Each/Total`. The document's JSON Schema is `definitionSchema` of `@protobase/workflows`, and `checkDefinition` runs the whole check.
123
123
 
124
+ <gap>A save cannot refuse a Task's missing or unknown argument because checking `Arguments` per step type is not implemented.</gap> The step fails its run instead, with an error such as `Http.InvalidArguments` whose cause names the argument.
125
+
124
126
  ### States
125
127
 
126
128
  | Type | |
@@ -195,6 +197,10 @@ Each step is saved as it ends, as a `workflow_steps` record: the state, its type
195
197
 
196
198
  A workflow reads a secret only by name, `$states.context.Secrets.TICKETS_TOKEN`, and only one the config's `workflows.secrets` lists; the values are never part of the definition. Every value of the listed secrets is blanked out as `[redacted]` wherever it appears in what a run records: a step's input, output, variables, logs, error and cause, and the run's output, error and cause. In a Task's recorded input, every field whose name says it holds a secret, such as `Authorization`, `token` or `apiKey`, is blanked out too. A value an expression computes from a secret, however it changes it, such as `'Basic ' & $base64encode(...)`, is kept whole as `[redacted]`: in a Task's `Arguments` the step type gets the value and the record keeps `[redacted]`; in an `Output`, an `Assign`, a Map's `Items` or a Fail's `Error` and `Cause` the value itself is `[redacted]`, so later states read that. Read a secret in the `Arguments` of the Task that sends it. A secret that comes back changed in a step's result, such as one a server encodes in its answer, is not the value the runner looks for, and is kept as it came. A run's input is kept as its caller gave it, so a secret's value never belongs in it.
197
199
 
200
+ ## Over MCP
201
+
202
+ An AI client signed in to the app's [MCP endpoint](mcp.md#workflows) finds, makes, changes and test-runs workflows as the person: it lists the step types and triggers with their arguments, reads and validates definitions, saves one whole or by a small edit, starts a run with an input, and reads each of the run's steps with its input, output, logs and error. The endpoint's instructions describe this language, and a refused definition comes back with its problems, each naming the state and field.
203
+
198
204
  ## Who may do what
199
205
 
200
206
  The workflow resources take only [named grants](access.md#resources-that-need-named-grants): a role's wildcard such as `*.read` reaches none of them, since a run reads and sends data as its definition says.