smithers-orchestrator 0.24.2 → 0.25.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/README.md +231 -0
- package/package.json +51 -24
- package/src/CreateSmithersOptions.ts +7 -0
- package/src/MigrateSmithersStoreOptions.ts +22 -0
- package/src/OpenSmithersBackendOptions.ts +13 -0
- package/src/ResolveSmithersBackendChoiceOptions.ts +7 -0
- package/src/SmithersBackendChoice.ts +9 -0
- package/src/SmithersMigrationResult.ts +15 -0
- package/src/create.js +23 -35
- package/src/external/create-external-smithers.js +1 -27
- package/src/index.d.ts +77 -3
- package/src/index.js +8 -2
- package/src/migrateSmithersStore.js +622 -0
- package/src/openSmithersBackend.js +89 -0
- package/src/prepareOutputSchemas.js +35 -0
- package/src/resolveSmithersBackendChoice.js +193 -0
- package/src/ide/SmithersIdeAskUserResult.ts +0 -7
- package/src/ide/SmithersIdeAvailability.ts +0 -17
- package/src/ide/SmithersIdeCommandBaseResult.ts +0 -7
- package/src/ide/SmithersIdeOpenDiffResult.ts +0 -5
- package/src/ide/SmithersIdeOpenFileResult.ts +0 -8
- package/src/ide/SmithersIdeOpenWebviewResult.ts +0 -7
- package/src/ide/SmithersIdeOverlayOptions.ts +0 -7
- package/src/ide/SmithersIdeOverlayResult.ts +0 -8
- package/src/ide/SmithersIdeOverlayType.ts +0 -1
- package/src/ide/SmithersIdeResolvedConfig.ts +0 -8
- package/src/ide/SmithersIdeRunTerminalResult.ts +0 -8
- package/src/ide/SmithersIdeService.js +0 -432
- package/src/ide/SmithersIdeServiceApi.ts +0 -35
- package/src/ide/SmithersIdeServiceConfig.ts +0 -8
- package/src/ide/index.js +0 -44
- package/src/ide/tools.js +0 -94
package/README.md
ADDED
|
@@ -0,0 +1,231 @@
|
|
|
1
|
+
# smithers-orchestrator
|
|
2
|
+
|
|
3
|
+
**Run long-horizon coding-agent work as durable workflows.**
|
|
4
|
+
|
|
5
|
+
[](https://www.npmjs.com/package/smithers-orchestrator)
|
|
6
|
+
[](https://github.com/smithersai/smithers/blob/main/LICENSE)
|
|
7
|
+
[](https://smithers.sh)
|
|
8
|
+
|
|
9
|
+
Tell your coding agent to do real, multi-step work, then Smithers runs it for minutes or
|
|
10
|
+
days with crash recovery, retries, human approvals, and full observability. The same
|
|
11
|
+
workflow runs across Claude Code, Codex, Pi, AI SDK models, and remote sandboxes.
|
|
12
|
+
|
|
13
|
+
This package is the published Smithers runtime: the engine, the `smithers` CLI, the JSX
|
|
14
|
+
workflow primitives, the agent adapters, and the Gateway. Install it once and your coding
|
|
15
|
+
agent drives the rest.
|
|
16
|
+
|
|
17
|
+

|
|
18
|
+
|
|
19
|
+
*A workflow run is a list of steps you can watch, pause, approve, and rewind. The run above shows several in flight at once.*
|
|
20
|
+
|
|
21
|
+
## What you get
|
|
22
|
+
|
|
23
|
+
- 🛡️ **Durable runs that survive crashes**: every completed step is persisted the moment it
|
|
24
|
+
finishes, so a run resumes from where it stopped instead of starting over.
|
|
25
|
+
- 🔌 **Any agent, any model**: Claude Code, Codex, Pi, Antigravity, and more, plus any model
|
|
26
|
+
through the AI SDK. Swap the harness without rewriting the workflow.
|
|
27
|
+
- 🛠️ **Higher-quality output**: review loops, human approvals, and evals give agents the
|
|
28
|
+
structure that real work demands.
|
|
29
|
+
- 🧩 **Dozens of ready-to-run workflows**: planning, implementation, review, debugging,
|
|
30
|
+
tickets, audits, and long-horizon missions. Your agent can author new ones.
|
|
31
|
+
|
|
32
|
+
## When to use Smithers
|
|
33
|
+
|
|
34
|
+
Smithers is the durable runtime for *coding-agent* work: when the unit of work is an agent
|
|
35
|
+
editing a real repository over many steps, and you need that work to be inspectable,
|
|
36
|
+
approvable, and recoverable. Use it when order matters across multiple AI steps, you need
|
|
37
|
+
crash recovery, a human must approve or answer mid-run, or different tasks need different
|
|
38
|
+
models. For a single prompt → single response, call your model provider's SDK directly;
|
|
39
|
+
Smithers adds nothing there.
|
|
40
|
+
|
|
41
|
+
## Get started
|
|
42
|
+
|
|
43
|
+
Smithers is driven by your coding agent, **not** a GUI you click. Your agent runs Smithers
|
|
44
|
+
on your behalf: it scaffolds workflows, kicks off runs, watches them, and handles
|
|
45
|
+
approvals.
|
|
46
|
+
|
|
47
|
+
One command sets everything up. From inside your project:
|
|
48
|
+
|
|
49
|
+
```bash
|
|
50
|
+
bunx smithers-orchestrator init
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
`init` does everything:
|
|
54
|
+
|
|
55
|
+
- **Installs the `smithers` skill** into the coding agents on your machine (Claude Code,
|
|
56
|
+
Pi, and more), so your agent knows how and when to use Smithers. No `mkdir`, no `curl`.
|
|
57
|
+
- **Scaffolds `.smithers/`** with ready-made workflows (`hello`, `implement`, `plan`,
|
|
58
|
+
`review`, `debug`, and more) your agent can pick from.
|
|
59
|
+
|
|
60
|
+
Then just ask:
|
|
61
|
+
|
|
62
|
+
> *"orchestrate an agent to add rate limiting and keep iterating until the tests pass."*
|
|
63
|
+
|
|
64
|
+
Your agent picks the right workflow, starts the run, and keeps going through retries and
|
|
65
|
+
review loops until the work is actually done.
|
|
66
|
+
|
|
67
|
+
> **Always run `bunx smithers-orchestrator`, never `bunx smithers`.** On npm, `smithers`
|
|
68
|
+
> is an unrelated package. The installed binary alias `smithers` is only safe inside a
|
|
69
|
+
> project that resolves `node_modules/.bin/smithers`.
|
|
70
|
+
|
|
71
|
+
To wire the MCP server into every detected agent too, run
|
|
72
|
+
`bunx smithers-orchestrator mcp add`. See [Agent Support](https://smithers.sh/agents/overview)
|
|
73
|
+
for the full per-agent matrix.
|
|
74
|
+
|
|
75
|
+
## Drive it yourself
|
|
76
|
+
|
|
77
|
+
Prefer the CLI? The seeded `hello` workflow is the smallest possible run; its entire prompt
|
|
78
|
+
is an editable Markdown file at `.smithers/prompts/hello.mdx`:
|
|
79
|
+
|
|
80
|
+
```bash
|
|
81
|
+
# run your first workflow (edit .smithers/prompts/hello.mdx to change it)
|
|
82
|
+
bunx smithers-orchestrator workflow run hello
|
|
83
|
+
|
|
84
|
+
# turn a request into a practical implementation plan
|
|
85
|
+
bunx smithers-orchestrator workflow run plan --prompt "add rate limiting, audit logging, and API key rotation"
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
Watch what's happening, whether your agent started the run or you did:
|
|
89
|
+
|
|
90
|
+
```bash
|
|
91
|
+
bunx smithers-orchestrator ps # list active, paused, and recently completed runs
|
|
92
|
+
bunx smithers-orchestrator inspect RUN_ID # steps, agents, approvals, and outputs for one run
|
|
93
|
+
bunx smithers-orchestrator logs RUN_ID # tail the event log
|
|
94
|
+
bunx smithers-orchestrator chat RUN_ID # read the agent's chat output
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
Run `bunx smithers-orchestrator starters` to browse plain-English starters, and
|
|
98
|
+
`bunx smithers-orchestrator workflow list` to see what's installed.
|
|
99
|
+
|
|
100
|
+
## Durable by default
|
|
101
|
+
|
|
102
|
+
Durability is the differentiator. Runs survive crashes, restarts, and flaky tools because
|
|
103
|
+
**every completed step is persisted to SQLite the moment it finishes**. The runtime always
|
|
104
|
+
knows what's done and what to run next. Approvals, human questions, retries, and replay are
|
|
105
|
+
first-class.
|
|
106
|
+
|
|
107
|
+
```text
|
|
108
|
+
prompt → render workflow → run task → validate output → persist to SQLite → re-render → resume · inspect · replay
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
That loop is the whole model: a task runs, its output is validated against a schema and
|
|
112
|
+
written down, then the workflow re-renders from persisted state to decide the next task. A
|
|
113
|
+
crash at any point resumes from the last write, not from the top.
|
|
114
|
+
|
|
115
|
+
```bash
|
|
116
|
+
bunx smithers-orchestrator up workflow.tsx --input '{"description":"Fix bug"}'
|
|
117
|
+
bunx smithers-orchestrator up workflow.tsx --run-id abc123 --resume true # resume after a crash
|
|
118
|
+
bunx smithers-orchestrator rewind abc123 --frame 4 # time-travel to an earlier frame
|
|
119
|
+
bunx smithers-orchestrator fork abc123 # branch an alternate timeline
|
|
120
|
+
bunx smithers-orchestrator replay abc123 # replay from a checkpoint
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
## Author your own
|
|
124
|
+
|
|
125
|
+
The built-in workflows are normal Smithers TSX files: run them as-is, have your agent adapt
|
|
126
|
+
them to your repo, or have it write new ones from the same primitives. A workflow is a JSX
|
|
127
|
+
tree of tasks, each with a Zod-validated output:
|
|
128
|
+
|
|
129
|
+
```tsx
|
|
130
|
+
import { createSmithers, Sequence } from "smithers-orchestrator";
|
|
131
|
+
import { z } from "zod";
|
|
132
|
+
|
|
133
|
+
const { Workflow, Task, smithers, outputs } = createSmithers({
|
|
134
|
+
analyze: z.object({
|
|
135
|
+
summary: z.string(),
|
|
136
|
+
severity: z.enum(["low", "medium", "high"]),
|
|
137
|
+
}),
|
|
138
|
+
fix: z.object({
|
|
139
|
+
patch: z.string(),
|
|
140
|
+
explanation: z.string(),
|
|
141
|
+
}),
|
|
142
|
+
});
|
|
143
|
+
|
|
144
|
+
export default smithers((ctx) => (
|
|
145
|
+
<Workflow name="bugfix">
|
|
146
|
+
<Sequence>
|
|
147
|
+
<Task id="analyze" output={outputs.analyze} agent={analyzer}>
|
|
148
|
+
{`Analyze the bug: ${ctx.input.description}`}
|
|
149
|
+
</Task>
|
|
150
|
+
|
|
151
|
+
<Task id="fix" output={outputs.fix} agent={fixer}>
|
|
152
|
+
{`Fix this issue: ${ctx.latest("analyze").summary}`}
|
|
153
|
+
</Task>
|
|
154
|
+
</Sequence>
|
|
155
|
+
</Workflow>
|
|
156
|
+
));
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
Each task output is validated against its Zod schema and persisted to SQLite. If the
|
|
160
|
+
process crashes, Smithers resumes from the last completed node without re-running finished
|
|
161
|
+
work.
|
|
162
|
+
|
|
163
|
+
| Component | Purpose |
|
|
164
|
+
| ------------ | ------------------------------------- |
|
|
165
|
+
| `<Workflow>` | Root container |
|
|
166
|
+
| `<Task>` | AI or static task node |
|
|
167
|
+
| `<Sequence>` | Ordered execution |
|
|
168
|
+
| `<Parallel>` | Concurrent execution |
|
|
169
|
+
| `<Branch>` | Conditional execution |
|
|
170
|
+
| `<Loop>` | Repeat tasks until a condition is met |
|
|
171
|
+
|
|
172
|
+
There are many more: approvals, merge queues, sub-workflows, signals, timers, sagas,
|
|
173
|
+
sandboxes, and composite patterns. See
|
|
174
|
+
[Components](https://smithers.sh/components/workflow).
|
|
175
|
+
|
|
176
|
+
## Package entry points
|
|
177
|
+
|
|
178
|
+
The main entry re-exports the full toolkit, so most code only needs
|
|
179
|
+
`import { ... } from "smithers-orchestrator"`. Dedicated subpaths exist for focused imports:
|
|
180
|
+
|
|
181
|
+
| Import | What it gives you |
|
|
182
|
+
| --- | --- |
|
|
183
|
+
| `smithers-orchestrator` | `createSmithers`, the workflow components, agent adapters, errors, and the rest of the core API. |
|
|
184
|
+
| `smithers-orchestrator/tools` | The built-in agent tool sandbox. |
|
|
185
|
+
| `smithers-orchestrator/gateway-client` | Typed client for the Gateway RPC/WS control plane. |
|
|
186
|
+
| `smithers-orchestrator/gateway-react` | React hooks for live, multi-run state. |
|
|
187
|
+
| `smithers-orchestrator/sandbox` | The `<Sandbox>` primitive and `SandboxProvider` interface. |
|
|
188
|
+
| `smithers-orchestrator/control-plane` | Programmatic control-plane API for launching and steering runs. |
|
|
189
|
+
| `smithers-orchestrator/server` | The Gateway server (`startServer`, `createServeApp`). |
|
|
190
|
+
| `smithers-orchestrator/observability` | Prometheus metrics and OpenTelemetry tracing layers. |
|
|
191
|
+
| `smithers-orchestrator/memory` | Cross-run memory store and recall. |
|
|
192
|
+
| `smithers-orchestrator/scorers` | Eval scorers (LLM-judge, relevancy, faithfulness, …). |
|
|
193
|
+
| `smithers-orchestrator/openapi` | Generate AI SDK tools from OpenAPI specs. |
|
|
194
|
+
|
|
195
|
+
## Any agent, any model
|
|
196
|
+
|
|
197
|
+
Point each task at whichever agent is best for the job, mix several in one workflow, and
|
|
198
|
+
switch freely. The workflow doesn't change when the model does, so a frontier model can
|
|
199
|
+
plan, a fast model can fan out, and a specialized harness can do the edits.
|
|
200
|
+
|
|
201
|
+
Agent adapters ship in the box, including `ClaudeCodeAgent`, `CodexAgent`, `PiAgent`,
|
|
202
|
+
`AntigravityAgent`, `GeminiAgent`, and `AnthropicAgent` / `OpenAIAgent` for any AI SDK
|
|
203
|
+
model (with tools, structured output, and MCP). The same `<Sandbox>` primitive runs an
|
|
204
|
+
agent locally (Bubblewrap or Docker), in a container, on a managed remote like
|
|
205
|
+
[Freestyle](https://freestyle.sh), or on any backend you implement against
|
|
206
|
+
`SandboxProvider`.
|
|
207
|
+
|
|
208
|
+
## Requirements
|
|
209
|
+
|
|
210
|
+
- [Bun](https://bun.sh) ≥ 1.3
|
|
211
|
+
- TypeScript ≥ 5 (only for authoring TSX workflows)
|
|
212
|
+
- Model or provider credentials (e.g. `ANTHROPIC_API_KEY`)
|
|
213
|
+
- A version control system for snapshotting and isolating agent work:
|
|
214
|
+
[jj (Jujutsu)](https://github.com/jj-vcs/jj) or [git](https://git-scm.com). jj is
|
|
215
|
+
preferred and powers durability, time-travel, and per-task worktrees; the optional
|
|
216
|
+
`@smithers-orchestrator/jj-<platform>` package bundles a jj binary so a fresh install
|
|
217
|
+
works with no system jj.
|
|
218
|
+
|
|
219
|
+
## Docs
|
|
220
|
+
|
|
221
|
+
Full documentation lives at **[smithers.sh](https://smithers.sh)**.
|
|
222
|
+
|
|
223
|
+
- [Introduction](https://smithers.sh/introduction) — what Smithers is and when to use it.
|
|
224
|
+
- [Quickstart](https://smithers.sh/quickstart) — scaffold and run a workflow in two commands.
|
|
225
|
+
- [Tour](https://smithers.sh/tour) — a guided walk through a real run.
|
|
226
|
+
- [How It Works](https://smithers.sh/how-it-works) — the durable execution model.
|
|
227
|
+
- [Components](https://smithers.sh/components/workflow) — the full primitive set.
|
|
228
|
+
|
|
229
|
+
## License
|
|
230
|
+
|
|
231
|
+
MIT
|
package/package.json
CHANGED
|
@@ -1,7 +1,32 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "smithers-orchestrator",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.25.0",
|
|
4
4
|
"description": "Public Smithers facade for durable coding-agent workflows and Gateway operation",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"homepage": "https://smithers.sh",
|
|
7
|
+
"repository": {
|
|
8
|
+
"type": "git",
|
|
9
|
+
"url": "git+https://github.com/smithersai/smithers.git",
|
|
10
|
+
"directory": "packages/smithers"
|
|
11
|
+
},
|
|
12
|
+
"bugs": {
|
|
13
|
+
"url": "https://github.com/smithersai/smithers/issues"
|
|
14
|
+
},
|
|
15
|
+
"keywords": [
|
|
16
|
+
"ai",
|
|
17
|
+
"agent",
|
|
18
|
+
"agents",
|
|
19
|
+
"coding-agent",
|
|
20
|
+
"orchestration",
|
|
21
|
+
"workflow",
|
|
22
|
+
"durable-execution",
|
|
23
|
+
"react",
|
|
24
|
+
"jsx",
|
|
25
|
+
"llm",
|
|
26
|
+
"claude",
|
|
27
|
+
"codex",
|
|
28
|
+
"bun"
|
|
29
|
+
],
|
|
5
30
|
"type": "module",
|
|
6
31
|
"sideEffects": false,
|
|
7
32
|
"exports": {
|
|
@@ -52,7 +77,8 @@
|
|
|
52
77
|
}
|
|
53
78
|
},
|
|
54
79
|
"files": [
|
|
55
|
-
"src/"
|
|
80
|
+
"src/",
|
|
81
|
+
"README.md"
|
|
56
82
|
],
|
|
57
83
|
"bin": {
|
|
58
84
|
"smithers": "./src/bin/smithers.js"
|
|
@@ -66,28 +92,28 @@
|
|
|
66
92
|
"incur": "^0.4.1",
|
|
67
93
|
"react": "^19.2.5",
|
|
68
94
|
"zod": "^4.3.6",
|
|
69
|
-
"@smithers-orchestrator/agents": "0.
|
|
70
|
-
"@smithers-orchestrator/
|
|
71
|
-
"@smithers-orchestrator/
|
|
72
|
-
"@smithers-orchestrator/db": "0.
|
|
73
|
-
"@smithers-orchestrator/engine": "0.
|
|
74
|
-
"@smithers-orchestrator/driver": "0.
|
|
75
|
-
"@smithers-orchestrator/errors": "0.
|
|
76
|
-
"@smithers-orchestrator/gateway-client": "0.
|
|
77
|
-
"@smithers-orchestrator/gateway-react": "0.
|
|
78
|
-
"@smithers-orchestrator/graph": "0.
|
|
79
|
-
"@smithers-orchestrator/memory": "0.
|
|
80
|
-
"@smithers-orchestrator/
|
|
81
|
-
"@smithers-orchestrator/
|
|
82
|
-
"@smithers-orchestrator/
|
|
83
|
-
"@smithers-orchestrator/
|
|
84
|
-
"@smithers-orchestrator/
|
|
85
|
-
"@smithers-orchestrator/
|
|
86
|
-
"@smithers-orchestrator/server": "0.
|
|
87
|
-
"@smithers-orchestrator/time-travel": "0.
|
|
88
|
-
"@smithers-orchestrator/vcs": "0.
|
|
89
|
-
"@smithers-orchestrator/
|
|
90
|
-
"@smithers-orchestrator/
|
|
95
|
+
"@smithers-orchestrator/agents": "0.25.0",
|
|
96
|
+
"@smithers-orchestrator/components": "0.25.0",
|
|
97
|
+
"@smithers-orchestrator/control-plane": "0.25.0",
|
|
98
|
+
"@smithers-orchestrator/db": "0.25.0",
|
|
99
|
+
"@smithers-orchestrator/engine": "0.25.0",
|
|
100
|
+
"@smithers-orchestrator/driver": "0.25.0",
|
|
101
|
+
"@smithers-orchestrator/errors": "0.25.0",
|
|
102
|
+
"@smithers-orchestrator/gateway-client": "0.25.0",
|
|
103
|
+
"@smithers-orchestrator/gateway-react": "0.25.0",
|
|
104
|
+
"@smithers-orchestrator/graph": "0.25.0",
|
|
105
|
+
"@smithers-orchestrator/memory": "0.25.0",
|
|
106
|
+
"@smithers-orchestrator/observability": "0.25.0",
|
|
107
|
+
"@smithers-orchestrator/openapi": "0.25.0",
|
|
108
|
+
"@smithers-orchestrator/react-reconciler": "0.25.0",
|
|
109
|
+
"@smithers-orchestrator/sandbox": "0.25.0",
|
|
110
|
+
"@smithers-orchestrator/scorers": "0.25.0",
|
|
111
|
+
"@smithers-orchestrator/scheduler": "0.25.0",
|
|
112
|
+
"@smithers-orchestrator/server": "0.25.0",
|
|
113
|
+
"@smithers-orchestrator/time-travel": "0.25.0",
|
|
114
|
+
"@smithers-orchestrator/vcs": "0.25.0",
|
|
115
|
+
"@smithers-orchestrator/cli": "0.25.0",
|
|
116
|
+
"@smithers-orchestrator/tool-context": "0.25.0"
|
|
91
117
|
},
|
|
92
118
|
"optionalDependencies": {
|
|
93
119
|
"@electric-sql/pglite": "0.5.1",
|
|
@@ -99,6 +125,7 @@
|
|
|
99
125
|
"typescript": "~5.9.3"
|
|
100
126
|
},
|
|
101
127
|
"scripts": {
|
|
128
|
+
"test": "bun test tests",
|
|
102
129
|
"typecheck": "tsc -p tsconfig.json --noEmit",
|
|
103
130
|
"build": "tsup --dts-only"
|
|
104
131
|
}
|
|
@@ -6,4 +6,11 @@ export type CreateSmithersOptions = {
|
|
|
6
6
|
alertPolicy?: SmithersAlertPolicy;
|
|
7
7
|
dbPath?: string;
|
|
8
8
|
journalMode?: string;
|
|
9
|
+
/**
|
|
10
|
+
* Backend the caller resolved this API to. The synchronous `createSmithers`
|
|
11
|
+
* only serves `"sqlite"`; `"pglite"`/`"postgres"` require the async
|
|
12
|
+
* `openSmithersBackend` factory and fail loud here rather than silently
|
|
13
|
+
* opening bun:sqlite.
|
|
14
|
+
*/
|
|
15
|
+
backend?: "sqlite" | "pglite" | "postgres";
|
|
9
16
|
};
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
export type MigrateSmithersStoreOptions = {
|
|
2
|
+
cwd?: string;
|
|
3
|
+
dbPath?: string;
|
|
4
|
+
to?: "pglite" | "postgres";
|
|
5
|
+
url?: string;
|
|
6
|
+
env?: Record<string, string | undefined>;
|
|
7
|
+
pgliteDataDir?: string;
|
|
8
|
+
keepSqlite?: boolean;
|
|
9
|
+
batchSize?: number;
|
|
10
|
+
onProgress?: (event:
|
|
11
|
+
| { type: "table-start"; table?: string; sourceRows?: number }
|
|
12
|
+
| {
|
|
13
|
+
type: "table-copied";
|
|
14
|
+
table?: string;
|
|
15
|
+
copiedRows?: number;
|
|
16
|
+
sourceRows?: number;
|
|
17
|
+
targetRows?: number;
|
|
18
|
+
durationMs?: number;
|
|
19
|
+
}
|
|
20
|
+
| { type: "done"; copiedRows?: number; tableCount?: number; durationMs?: number }
|
|
21
|
+
) => void | Promise<void>;
|
|
22
|
+
};
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { CreateSmithersOptions } from "./CreateSmithersOptions";
|
|
2
|
+
|
|
3
|
+
type SmithersBackend = "sqlite" | "pglite" | "postgres";
|
|
4
|
+
|
|
5
|
+
export type OpenSmithersBackendOptions = CreateSmithersOptions & {
|
|
6
|
+
backend?: SmithersBackend;
|
|
7
|
+
cwd?: string;
|
|
8
|
+
configPath?: string;
|
|
9
|
+
env?: Record<string, string | undefined>;
|
|
10
|
+
connectionString?: string;
|
|
11
|
+
connection?: object;
|
|
12
|
+
pgliteDataDir?: string;
|
|
13
|
+
};
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export type SmithersMigrationResult = {
|
|
2
|
+
backend: "pglite" | "postgres";
|
|
3
|
+
dbPath: string;
|
|
4
|
+
markerPath: string;
|
|
5
|
+
target: {
|
|
6
|
+
backend: "pglite" | "postgres";
|
|
7
|
+
dataDir?: string;
|
|
8
|
+
url?: string;
|
|
9
|
+
};
|
|
10
|
+
runCount: number;
|
|
11
|
+
schemaVersion: string;
|
|
12
|
+
durationMs: number;
|
|
13
|
+
tables: Array<{ table: string; sourceRows: number; targetRows: number; durationMs: number }>;
|
|
14
|
+
sqliteRemoved: boolean;
|
|
15
|
+
};
|
package/src/create.js
CHANGED
|
@@ -18,7 +18,9 @@ import { SmithersDb } from "@smithers-orchestrator/db/adapter";
|
|
|
18
18
|
import { POSTGRES } from "@smithers-orchestrator/db/dialect";
|
|
19
19
|
import { resolve, join } from "node:path";
|
|
20
20
|
import { SmithersError } from "@smithers-orchestrator/errors/SmithersError";
|
|
21
|
+
import { assertZodV4 } from "@smithers-orchestrator/errors/assertZodV4";
|
|
21
22
|
import { findSmithersAnchorDir } from "./findSmithersAnchorDir.js";
|
|
23
|
+
import { prepareOutputSchemas } from "./prepareOutputSchemas.js";
|
|
22
24
|
/** @typedef {import("@smithers-orchestrator/components").ApprovalProps<any, any>} ApprovalProps */
|
|
23
25
|
/** @typedef {import("@smithers-orchestrator/components").SandboxProps} SandboxProps */
|
|
24
26
|
/** @typedef {import("@smithers-orchestrator/components").SignalProps<any>} SignalProps */
|
|
@@ -52,41 +54,6 @@ function computeSchemaSig(schemas, dbPath) {
|
|
|
52
54
|
}
|
|
53
55
|
return parts.join("\n");
|
|
54
56
|
}
|
|
55
|
-
/**
|
|
56
|
-
* Duplicate schema objects need distinct output refs so Task `output={outputs.foo}`
|
|
57
|
-
* can still resolve the intended table by identity.
|
|
58
|
-
* @param {Record<string, any>} schemas
|
|
59
|
-
*/
|
|
60
|
-
function prepareOutputSchemas(schemas) {
|
|
61
|
-
const counts = new Map();
|
|
62
|
-
for (const [name, zodSchema] of Object.entries(schemas)) {
|
|
63
|
-
if (name === "input")
|
|
64
|
-
continue;
|
|
65
|
-
counts.set(zodSchema, (counts.get(zodSchema) ?? 0) + 1);
|
|
66
|
-
}
|
|
67
|
-
const outputs = {
|
|
68
|
-
...schemas,
|
|
69
|
-
};
|
|
70
|
-
const zodToKeyName = new Map();
|
|
71
|
-
const ambiguousZodSchemas = new Set();
|
|
72
|
-
for (const [name, zodSchema] of Object.entries(schemas)) {
|
|
73
|
-
if (name === "input")
|
|
74
|
-
continue;
|
|
75
|
-
if ((counts.get(zodSchema) ?? 0) > 1) {
|
|
76
|
-
ambiguousZodSchemas.add(zodSchema);
|
|
77
|
-
const aliasSchema = zodSchema.clone();
|
|
78
|
-
outputs[name] = aliasSchema;
|
|
79
|
-
zodToKeyName.set(aliasSchema, name);
|
|
80
|
-
continue;
|
|
81
|
-
}
|
|
82
|
-
zodToKeyName.set(zodSchema, name);
|
|
83
|
-
}
|
|
84
|
-
return {
|
|
85
|
-
outputs,
|
|
86
|
-
zodToKeyName,
|
|
87
|
-
ambiguousZodSchemas,
|
|
88
|
-
};
|
|
89
|
-
}
|
|
90
57
|
/**
|
|
91
58
|
* @param {Record<string, string>} [base]
|
|
92
59
|
* @param {Record<string, string>} [override]
|
|
@@ -184,6 +151,13 @@ function mergeAlertPolicies(base, override) {
|
|
|
184
151
|
* @param {Record<string, any>} schemas
|
|
185
152
|
*/
|
|
186
153
|
function prepareSmithersTables(schemas) {
|
|
154
|
+
// Fail fast and clearly at workflow construction if any schema is not Zod v4.
|
|
155
|
+
// smithers reads Zod v4 internals (schema._zod) and uses z.toJSONSchema();
|
|
156
|
+
// a Zod v3 schema would otherwise silently build wrong columns here and crash
|
|
157
|
+
// later with a cryptic `schema._zod.def` TypeError deep in the agent path.
|
|
158
|
+
for (const [name, zodSchema] of Object.entries(schemas)) {
|
|
159
|
+
assertZodV4(zodSchema, name);
|
|
160
|
+
}
|
|
187
161
|
const tables = {};
|
|
188
162
|
const inputTable = schemas.input
|
|
189
163
|
? zodToTable("input", schemas.input, { isInput: true })
|
|
@@ -366,6 +340,20 @@ function buildSmithersApi(config) {
|
|
|
366
340
|
* ```
|
|
367
341
|
*/
|
|
368
342
|
export function createSmithers(schemas, opts) {
|
|
343
|
+
// Honor an explicitly requested backend instead of silently opening
|
|
344
|
+
// bun:sqlite. `createSmithers` is the synchronous SQLite path; PGlite and
|
|
345
|
+
// Postgres provision over the wire asynchronously, so a workflow that wants
|
|
346
|
+
// them must use the async `openSmithersBackend` factory (which returns this
|
|
347
|
+
// exact API). When `--backend pglite|postgres` / `SMITHERS_BACKEND` selects a
|
|
348
|
+
// non-SQLite backend but the workflow still calls `createSmithers`, fail loud
|
|
349
|
+
// (design decision 4: never silently degrade) instead of running on SQLite.
|
|
350
|
+
const requestedBackend = (opts?.backend ?? process.env.SMITHERS_BACKEND ?? "").toLowerCase();
|
|
351
|
+
if (requestedBackend === "pglite" || requestedBackend === "postgres") {
|
|
352
|
+
throw new SmithersError("INVALID_INPUT", `createSmithers() is the synchronous bun:sqlite backend and cannot serve the "${requestedBackend}" backend. ` +
|
|
353
|
+
`Author the workflow with the async factory instead:\n\n` +
|
|
354
|
+
` const { smithers, Workflow, outputs } = await openSmithersBackend(schemas);\n\n` +
|
|
355
|
+
`or run on SQLite with \`--backend sqlite\` (or SMITHERS_BACKEND=sqlite, or backend:"sqlite" in smithers.config.ts).`, { requestedBackend });
|
|
356
|
+
}
|
|
369
357
|
// Resolve the DB path from the nearest .smithers/ anchor so that running a
|
|
370
358
|
// workflow from a subdirectory always creates/uses the project-root DB, not
|
|
371
359
|
// a new one at CWD. An explicit opts.dbPath overrides this entirely.
|
|
@@ -18,6 +18,7 @@ import { SmithersError } from "@smithers-orchestrator/errors/SmithersError";
|
|
|
18
18
|
import { mkdtempSync } from "node:fs";
|
|
19
19
|
import { tmpdir } from "node:os";
|
|
20
20
|
import { join, resolve } from "node:path";
|
|
21
|
+
import { prepareOutputSchemas } from "../prepareOutputSchemas.js";
|
|
21
22
|
/** @typedef {import("@smithers-orchestrator/agents/AgentLike").AgentLike} AgentLike */
|
|
22
23
|
/** @typedef {import("@smithers-orchestrator/components/SmithersWorkflow").SmithersWorkflow<any>} SmithersWorkflow */
|
|
23
24
|
/**
|
|
@@ -64,33 +65,6 @@ export function hostNodeToReact(node, agents) {
|
|
|
64
65
|
const children = node.children.map((child) => hostNodeToReact(child, agents));
|
|
65
66
|
return React.createElement(node.tag, rawProps, ...children);
|
|
66
67
|
}
|
|
67
|
-
/**
|
|
68
|
-
* @param {Record<string, any>} schemas
|
|
69
|
-
*/
|
|
70
|
-
function prepareOutputSchemas(schemas) {
|
|
71
|
-
const counts = new Map();
|
|
72
|
-
for (const [name, zodSchema] of Object.entries(schemas)) {
|
|
73
|
-
if (name === "input")
|
|
74
|
-
continue;
|
|
75
|
-
counts.set(zodSchema, (counts.get(zodSchema) ?? 0) + 1);
|
|
76
|
-
}
|
|
77
|
-
const zodToKeyName = new Map();
|
|
78
|
-
const ambiguousZodSchemas = new Set();
|
|
79
|
-
for (const [name, zodSchema] of Object.entries(schemas)) {
|
|
80
|
-
if (name === "input")
|
|
81
|
-
continue;
|
|
82
|
-
if ((counts.get(zodSchema) ?? 0) > 1) {
|
|
83
|
-
ambiguousZodSchemas.add(zodSchema);
|
|
84
|
-
zodToKeyName.set(zodSchema.clone(), name);
|
|
85
|
-
continue;
|
|
86
|
-
}
|
|
87
|
-
zodToKeyName.set(zodSchema, name);
|
|
88
|
-
}
|
|
89
|
-
return {
|
|
90
|
-
zodToKeyName,
|
|
91
|
-
ambiguousZodSchemas,
|
|
92
|
-
};
|
|
93
|
-
}
|
|
94
68
|
/**
|
|
95
69
|
* Create a SmithersWorkflow from an external build function.
|
|
96
70
|
*
|