@protobase/cli 0.67.11 → 0.67.12
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/cli/package.js +1 -1
- package/package.json +7 -7
- package/skills/protobase/references/features/record-pages.md +1 -0
- package/skills/protobase/references/features/workflows.md +3 -1
- package/skills/protobase/references/reference/mcp.md +2 -2
- package/skills/protobase/references/reference/plugins.md +6 -0
- package/skills/protobase/references/reference/workflows.md +32 -4
package/dist/cli/package.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@protobase/cli",
|
|
3
|
-
"version": "0.67.
|
|
3
|
+
"version": "0.67.12",
|
|
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.
|
|
47
|
-
"@protobase/layout": "0.67.
|
|
48
|
-
"@protobase/query": "0.67.
|
|
49
|
-
"@protobase/schema": "0.67.
|
|
50
|
-
"@protobase/server": "0.67.
|
|
51
|
-
"@protobase/ui": "0.67.
|
|
46
|
+
"@protobase/config": "0.67.12",
|
|
47
|
+
"@protobase/layout": "0.67.12",
|
|
48
|
+
"@protobase/query": "0.67.12",
|
|
49
|
+
"@protobase/schema": "0.67.12",
|
|
50
|
+
"@protobase/server": "0.67.12",
|
|
51
|
+
"@protobase/ui": "0.67.12",
|
|
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",
|
|
@@ -11,6 +11,7 @@ The page of one record, with its sections, related records, galleries, charts an
|
|
|
11
11
|
- [Unsaved edits](../reference/ui-config.md#editing-a-record): Unsaved changes to a record stay in the browser and can be resumed, and leaving a form, a dialog or a comment with changes asks first.
|
|
12
12
|
- [Record forms](../reference/ui-config.md#editing-a-record): Relations are picked from a list that narrows as you type, numbers are read as the browser's language writes them, and a refused save says under each field what is wrong.
|
|
13
13
|
- [Titles per reader](../reference/ui-config.md#titles-per-reader): A record without a name of its own, such as a direct message, is titled for each reader from its fields, such as after the other members, in the sidebar, breadcrumbs, heading, browser tab, relation links, list columns, relation pickers, filters and search.
|
|
14
|
+
- [JSON fields on forms](../reference/plugins.md#json) (beta): A JSON field, such as a workflow run's input, is edited on forms as JSON text and shown written out on several lines.
|
|
14
15
|
- [Member fields](../reference/plugins.md#members): A field that holds a list of people, such as a private channel's members, picks the organization's members by name on forms and shows them by avatar and name.
|
|
15
16
|
- [Save feedback](../reference/ui-config.md#the-record-page): A view shows saving on the Save button instead of in a toast.
|
|
16
17
|
- [Save conflicts](../reference/ui-config.md#editing-a-record): When someone else changed a record while you edited it, Save shows their value beside yours for each field you both changed, and you keep yours or take theirs.
|
|
@@ -13,6 +13,8 @@ Graphs of steps the server runs along their edges, written in a language a model
|
|
|
13
13
|
- [Records steps](../reference/workflows.md#apprecords) (beta): Create, update, get and list records as the workflow's last editor, with the roles they hold now.
|
|
14
14
|
- [Mail step](../reference/workflows.md#appmailsend) (beta): Sends mail, with files the run downloaded attached, from the app's own sender.
|
|
15
15
|
- [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.
|
|
16
|
+
- [Run debugger](../reference/workflows.md#following-and-debugging-a-run) (beta): Each workflow lists its runs with their status, who started them, when and for how long; a run's page marks every step's status on the workflow's graph, live while it runs, with each step's input, output, logs, timing, tries and error, secrets blanked out.
|
|
17
|
+
- [Re-run from the failed step](../reference/workflows.md#re-running-a-failed-run) (beta): Once the workflow is fixed, a failed run runs again from the step that failed, keeping what the steps before it gave; a test run starts the workflow with a sample input from its page.
|
|
16
18
|
- [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.
|
|
17
19
|
- [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.
|
|
18
|
-
- [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.
|
|
20
|
+
- [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 and re-run it from there.
|
|
@@ -99,7 +99,7 @@ In an app with [workflows](workflows.md), the endpoint also offers tools to find
|
|
|
99
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
100
|
| `create_workflow` | Creates a workflow from its `name`, `description` and `definition`, and returns its `id`, `version` and ETag. |
|
|
101
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`. |
|
|
102
|
+
| `run_workflow` | Starts a run of a workflow's current version with an `input`, and returns its `run_id` and `status`. With `rerun_of`, a failed run's id, it [re-runs](workflows.md#re-running-a-failed-run) that run from its failed step instead, on its input. |
|
|
103
103
|
|
|
104
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
105
|
|
|
@@ -107,7 +107,7 @@ An `edit` is a [JSON Merge Patch](https://www.rfc-editor.org/rfc/rfc7396) of the
|
|
|
107
107
|
{ "id": "...", "edit": { "stateMachine": { "States": { "Notify": { "Arguments": { "url": "https://hooks.example.com/v2" } } } } } }
|
|
108
108
|
```
|
|
109
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
|
|
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 re-runs the run from that step.
|
|
111
111
|
|
|
112
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
113
|
|
|
@@ -149,6 +149,10 @@ Each part gets:
|
|
|
149
149
|
|
|
150
150
|
[Adding a field type](../guides/field-type.md) builds one step by step.
|
|
151
151
|
|
|
152
|
+
### JSON
|
|
153
|
+
|
|
154
|
+
`json` is a field type Protobase brings for any JSON field a form should edit, such as a workflow run's `input`: `r.input.widget('json')`. The form edits the value as JSON text, the record page shows it written out on several lines, and a list's table on one. Text that does not parse yet says so under the box and leaves the value as it last parsed; an emptied box is null. It takes the form's whole width. A plugin that registers a field type named `json` replaces it.
|
|
155
|
+
|
|
152
156
|
### Members
|
|
153
157
|
|
|
154
158
|
`members` is a field type Protobase brings, for a JSON field that holds an array of user ids, such as who may read a private channel. No plugin registers it; a view picks it as it picks any other:
|
|
@@ -167,6 +171,8 @@ The create form and the record's form pick the members of the organization the s
|
|
|
167
171
|
|
|
168
172
|
`workflow` is the field type the `workflows` resource draws its `definition` with: the [workflow editor](workflows.md#the-editor). Another JSON field holding a workflow's definition picks it as `r.definition.widget('workflow')`. It takes the form's whole width, and a list's table shows how many steps the workflow has. A plugin that registers a field type named `workflow` replaces it.
|
|
169
173
|
|
|
174
|
+
`workflow_run` is the field type the `workflow_runs` resource draws its own `id` with: the run's [trace](workflows.md#following-and-debugging-a-run) on its workflow's graph, with the chosen step's records under it. Another uuid field holding a run's id picks it as `r.run_id.widget('workflow_run')`. It takes the whole width, and a list's table shows the id. A plugin that registers a field type named `workflow_run` replaces it.
|
|
175
|
+
|
|
170
176
|
## Building
|
|
171
177
|
|
|
172
178
|
```sh
|
|
@@ -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, over MCP
|
|
8
|
+
Workflows run when they are started through the API, over MCP, from the app's code or by a test run in the admin app. Triggers and sign-in connections to other services 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.
|
|
@@ -24,7 +24,7 @@ It adds four resources, over a `workflows` schema that [`protobase migration`](c
|
|
|
24
24
|
| --- | --- |
|
|
25
25
|
| `workflows` | A name, a description and the definition. Each save that changes the definition is checked, and kept as the workflow's next version, saved by the caller. |
|
|
26
26
|
| `workflow_versions` | Every version of every definition as it was saved, with who saved it and when. Read-only. |
|
|
27
|
-
| `workflow_runs` | A run, started by creating it with `workflow_id` and an `input
|
|
27
|
+
| `workflow_runs` | A run, started by creating it with `workflow_id` and an `input`, or with `rerun_of` to [re-run a failed run](#re-running-a-failed-run); it runs the version its workflow had then. Its status, output, error and timing are written by the runner. |
|
|
28
28
|
| `workflow_steps` | Every step of every run. Read-only. |
|
|
29
29
|
|
|
30
30
|
| `workflows` | |
|
|
@@ -93,7 +93,7 @@ The document holds no layout: the [editor](#the-editor) lays the graph out from
|
|
|
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, over MCP
|
|
96
|
+
A save checks a trigger's shape; runs start through the API, over MCP, from the app's code or by a [test run](#test-runs). <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
|
|
|
@@ -210,9 +210,37 @@ Each step is recorded as a `workflow_steps` record: the state, its type, the sco
|
|
|
210
210
|
|
|
211
211
|
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.
|
|
212
212
|
|
|
213
|
+
### Following and debugging a run
|
|
214
|
+
|
|
215
|
+
A workflow's page in the admin app lists its runs, newest first, with their status, who or what started them, when, how long they took, their version and error. A run's page, `/workflow_runs/<id>`, draws the workflow's graph as the run's version has it, the `workflow_run` [field type](plugins.md#workflow) on the run's `id`, with a mark on each state:
|
|
216
|
+
|
|
217
|
+
| Mark | |
|
|
218
|
+
| --- | --- |
|
|
219
|
+
| Succeeded, Caught, Failed | How the state's last step ended; for a state inside a Map, the worst of its items. A failed state's box is red. |
|
|
220
|
+
| Retrying | Its last try failed and a retrier tries it again. |
|
|
221
|
+
| Running | The run is on it, or goes on to it next. |
|
|
222
|
+
|
|
223
|
+
A state that took more than one step, by its tries, its visits or a Map's items, says how many. Choosing a state lists its steps under the graph in the order they ran, 20 at a time with *Show more*: each with its try, the Map item it ran in, its status, when it started and how long it took, its error and cause, input, output, the variables it assigned and its logs, and a link to the step's own page. Choosing the trigger shows the run's input. The page opens on the state that failed, the innermost one when a Map's item failed, so a failed run shows its error and logs at once.
|
|
224
|
+
|
|
225
|
+
While a run is queued, running or waiting, the page reads the run and its steps again every second, through the API as the person, so the marks, the step lists and the run's fields change as it goes, without a reload; it stops once the run has ended. The graph marks the states of a run's first 500 steps; the run's *Steps* list has them all. <gap>The graph cannot mark the steps after a run's first 500 because reading a run's steps in more than one page for the trace is not implemented.</gap> Everything the page shows is what the run recorded, so a [secret](#secrets) shows as `[redacted]` wherever it would have been.
|
|
226
|
+
|
|
227
|
+
### Re-running a failed run
|
|
228
|
+
|
|
229
|
+
A failed run's page offers *Re-run from the failed step*. It opens the form for a new run with `workflow_id` and `rerun_of` filled in; creating it, through the form or `POST /api/v1/workflow_runs` with `{ "workflow_id": "...", "rerun_of": "..." }`, starts a run that:
|
|
230
|
+
|
|
231
|
+
- runs on the workflow's version now, so fix the step first, and on the earlier run's input: a re-run given an `input` of its own is refused with `rerun-input`;
|
|
232
|
+
- keeps the earlier run's steps, copied as they were, but the try that failed and that state's retried tries before it, so the failed state runs again from its first try and none of the steps before it runs again. A Map that runs again keeps its finished items and runs again only those that had not finished, each from where it stood;
|
|
233
|
+
- is refused, and nothing starts, when the earlier run is not one of the workflow's runs the person may read (404), did not fail (`run-not-failed`), or would go on at a state the version no longer has (`rerun-refused`, naming the state).
|
|
234
|
+
|
|
235
|
+
A kept step's card on the run's page says it is from the earlier run, as it finished before the re-run started; the earlier run's page lists its re-runs.
|
|
236
|
+
|
|
237
|
+
### Test runs
|
|
238
|
+
|
|
239
|
+
A workflow's page offers *Test run*: the form for a new run of the workflow, whose `input` takes a sample input as JSON, which every state reads as `$states.context.Execution.Input`. Creating it opens the run's page, which follows it as it runs. A test run is a run like any other: its steps do what they do, as the workflow's last editor, with the version saved last.
|
|
240
|
+
|
|
213
241
|
## Over MCP
|
|
214
242
|
|
|
215
|
-
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,
|
|
243
|
+
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, reads each of the run's steps with its input, output, logs and error, and re-runs a failed run from its failed step once the workflow is fixed. The endpoint's instructions describe this language, and a refused definition comes back with its problems, each naming the state and field.
|
|
216
244
|
|
|
217
245
|
## Who may do what
|
|
218
246
|
|