@clemrig/factory 0.1.0 → 0.2.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/README.md +6 -17
- package/dist/app/doctor.d.ts +2 -4
- package/dist/app/doctor.js +6 -4
- package/dist/app/doctor.js.map +1 -1
- package/dist/app/factory.d.ts +2 -0
- package/dist/app/factory.js +13 -2
- package/dist/app/factory.js.map +1 -1
- package/dist/app/init.d.ts +1 -5
- package/dist/app/init.js +1 -13
- package/dist/app/init.js.map +1 -1
- package/dist/app/options.d.ts +17 -0
- package/dist/app/options.js +78 -0
- package/dist/app/options.js.map +1 -0
- package/dist/app/run.d.ts +4 -20
- package/dist/app/run.js +22 -93
- package/dist/app/run.js.map +1 -1
- package/dist/app/runs.d.ts +4 -32
- package/dist/app/runs.js +9 -61
- package/dist/app/runs.js.map +1 -1
- package/dist/cli/application.d.ts +1 -1
- package/dist/cli/application.js +1 -1
- package/dist/cli/args.js +2 -2
- package/dist/cli/args.js.map +1 -1
- package/dist/cli/doctor.d.ts +1 -1
- package/dist/cli/doctor.js +1 -1
- package/dist/cli/doctor.js.map +1 -1
- package/dist/cli/help.d.ts +1 -1
- package/dist/cli/help.js +1 -1
- package/dist/cli/init.d.ts +1 -1
- package/dist/cli/init.js +1 -1
- package/dist/cli/launcher.d.ts +1 -1
- package/dist/cli/launcher.js +4 -4
- package/dist/cli/launcher.js.map +1 -1
- package/dist/cli/reporter.d.ts +1 -1
- package/dist/cli/reporter.js +1 -2
- package/dist/cli/reporter.js.map +1 -1
- package/dist/cli/run.d.ts +1 -5
- package/dist/cli/run.js +24 -11
- package/dist/cli/run.js.map +1 -1
- package/dist/cli/ui.d.ts +1 -1
- package/dist/cli/ui.js +10 -3
- package/dist/cli/ui.js.map +1 -1
- package/dist/index.d.ts +3 -7
- package/dist/index.js +3 -5
- package/dist/index.js.map +1 -1
- package/dist/system/factory.d.ts +1 -1
- package/dist/system/factory.js +1 -1
- package/dist/system/factory.js.map +1 -1
- package/dist/system/npm.d.ts +5 -0
- package/dist/system/npm.js +14 -0
- package/dist/system/npm.js.map +1 -0
- package/dist/system/templates.d.ts +1 -1
- package/dist/system/templates.js +1 -1
- package/package.json +7 -17
- package/dist/engine/metrics.d.ts +0 -45
- package/dist/engine/metrics.js +0 -60
- package/dist/engine/metrics.js.map +0 -1
- package/dist/engine/primitives.d.ts +0 -34
- package/dist/engine/primitives.js +0 -81
- package/dist/engine/primitives.js.map +0 -1
- package/dist/engine/profiles.d.ts +0 -53
- package/dist/engine/profiles.js +0 -117
- package/dist/engine/profiles.js.map +0 -1
- package/dist/engine/runner.d.ts +0 -13
- package/dist/engine/runner.js +0 -157
- package/dist/engine/runner.js.map +0 -1
- package/dist/engine/types.d.ts +0 -194
- package/dist/engine/types.js +0 -2
- package/dist/engine/types.js.map +0 -1
- package/dist/engine/workflow.d.ts +0 -18
- package/dist/engine/workflow.js +0 -196
- package/dist/engine/workflow.js.map +0 -1
- package/dist/system/process.d.ts +0 -21
- package/dist/system/process.js +0 -238
- package/dist/system/process.js.map +0 -1
- package/dist/system/runtimes/adapter.d.ts +0 -90
- package/dist/system/runtimes/adapter.js +0 -20
- package/dist/system/runtimes/adapter.js.map +0 -1
- package/dist/system/runtimes/agent-runtime.d.ts +0 -45
- package/dist/system/runtimes/agent-runtime.js +0 -184
- package/dist/system/runtimes/agent-runtime.js.map +0 -1
- package/dist/system/runtimes/claude-code.d.ts +0 -10
- package/dist/system/runtimes/claude-code.js +0 -383
- package/dist/system/runtimes/claude-code.js.map +0 -1
- package/dist/system/runtimes/inspect.d.ts +0 -25
- package/dist/system/runtimes/inspect.js +0 -129
- package/dist/system/runtimes/inspect.js.map +0 -1
- package/dist/system/runtimes/pi.d.ts +0 -7
- package/dist/system/runtimes/pi.js +0 -235
- package/dist/system/runtimes/pi.js.map +0 -1
- package/dist/system/runtimes/protocol.d.ts +0 -9
- package/dist/system/runtimes/protocol.js +0 -38
- package/dist/system/runtimes/protocol.js.map +0 -1
- package/dist/system/runtimes/registry.d.ts +0 -5
- package/dist/system/runtimes/registry.js +0 -5
- package/dist/system/runtimes/registry.js.map +0 -1
- package/dist/system/store.d.ts +0 -20
- package/dist/system/store.js +0 -126
- package/dist/system/store.js.map +0 -1
- package/dist/ui/server.d.ts +0 -8
- package/dist/ui/server.js +0 -111
- package/dist/ui/server.js.map +0 -1
- package/dist/ui/static/dashboard.js +0 -266
- package/dist/ui/static/follow.js +0 -67
- package/dist/ui/static/index.html +0 -20
- package/dist/ui/static/style.css +0 -166
- package/dist/ui/static/timeline.js +0 -180
package/README.md
CHANGED
|
@@ -26,7 +26,7 @@ factory run ask --question "What changed recently?"
|
|
|
26
26
|
|
|
27
27
|
```
|
|
28
28
|
.factory/
|
|
29
|
-
package.json pins the exact
|
|
29
|
+
package.json pins the exact factory version
|
|
30
30
|
factory.ts the repository's workflows
|
|
31
31
|
workflows/ask/
|
|
32
32
|
index.ts the example workflow
|
|
@@ -37,7 +37,7 @@ factory run ask --question "What changed recently?"
|
|
|
37
37
|
.env optional secrets (ignored)
|
|
38
38
|
```
|
|
39
39
|
|
|
40
|
-
The global `factory` command uses the nearest `.factory/` holding a `package.json`, in the current directory or a parent, and runs the
|
|
40
|
+
The global `factory` command uses the nearest `.factory/` holding a `package.json`, in the current directory or a parent, and runs the factory version installed there: every machine runs the version pinned in the repository. Only `factory init` and `factory help` run with the global version. Without `.factory/` the command asks for `factory init`; without installed dependencies it gives the `npm ci --prefix .factory` command to run.
|
|
41
41
|
|
|
42
42
|
The example workflow `ask` reads the last 10 commits with `git log` (a CODE stage), asks a read-only Claude Code agent (`claude-sonnet-5-5`, effort `low`, tools `Read`, `Grep`, `Glob`) to answer the question, and checks the answer with a gate that sends it back at most 3 times. Copy its folder to start a new workflow.
|
|
43
43
|
|
|
@@ -119,7 +119,7 @@ import changelog from "./workflows/changelog/index.ts";
|
|
|
119
119
|
export default [ask, changelog];
|
|
120
120
|
```
|
|
121
121
|
|
|
122
|
-
Workflows are TypeScript run directly by Node: use erasable syntax only (no `enum`, no parameter properties) and relative imports with their `.ts` extension. Import
|
|
122
|
+
Workflows are TypeScript run directly by Node: use erasable syntax only (no `enum`, no parameter properties) and relative imports with their `.ts` extension. Import only from `@clemrig/factory`, which also exports `z` (Zod), so that workflows, the factory and its engine share one Zod instance.
|
|
123
123
|
|
|
124
124
|
**Graph.** Each stage declares its outcomes and the node routes every outcome to a stage, to `END` or to `retry(stage, max)`. A stage receives `{ state, agent, log, dir }`: the run (read-only), the agent runtime, the run journal and the repository directory. Stages and agents work in the repository (the folder that contains `.factory/`), which is also the process's working directory during a run, wherever the command was started.
|
|
125
125
|
|
|
@@ -132,7 +132,7 @@ Workflows are TypeScript run directly by Node: use erasable syntax only (no `enu
|
|
|
132
132
|
| `pick(...keys)` | agent context from `input` and data keys |
|
|
133
133
|
| `runProcess(argv, cwd, timeoutMs)` | runs a command without a shell; Ctrl-C stops it |
|
|
134
134
|
|
|
135
|
-
`defineWorkflow` refuses, when the workflow is loaded: a `.` in a stage or outcome name (a correction counter is named `<stage>.<outcome>`), an unrouted outcome, an unknown target, a retry maximum outside 1–100, a loop whose edges include no `retry` (with the loop's path), an invalid profile, a write tool in a read-only profile, a prompt or session name that cannot name a file, a `maxCostUsd` that is not a positive number, and an input that is not a `z.object`
|
|
135
|
+
`defineWorkflow` refuses, when the workflow is loaded: a `.` in a stage or outcome name (a correction counter is named `<stage>.<outcome>`), an unrouted outcome, an unknown target, a retry maximum outside 1–100, a loop whose edges include no `retry` (with the loop's path), an invalid profile, a write tool in a read-only profile, a prompt or session name that cannot name a file, a `maxCostUsd` that is not a positive number, and an input that is not a `z.object`. Loading `factory.ts` also refuses an input whose name cannot be an option (`json`, `help`, `max-cost-usd`, or other than letters, digits, `-` and `_` after a letter). Every run is therefore bounded.
|
|
136
136
|
|
|
137
137
|
**Inputs.** Each field of `input` becomes a `--<name>` option of `factory run`; an option given without a value is `true` and only a boolean field accepts it: `z.boolean()`, possibly with `.optional()`, `.nullable()` or `.default(…)` (a transformed boolean or one with `.catch` takes no option alone). A missing, invalid or unknown option is refused with the list of problems, before any run is created. A workflow without `input` accepts no input option.
|
|
138
138
|
|
|
@@ -165,7 +165,7 @@ factory ui [--port 4321]
|
|
|
165
165
|
factory doctor [--json]
|
|
166
166
|
```
|
|
167
167
|
|
|
168
|
-
Before creating a run, `factory run` validates the input, reads the prompts and checks, for each runtime the workflow uses, that its executable is in the `PATH`, at least the supported version, and connected; a missing piece fails the command with the stage, runtime and reason. The terminal then shows each runtime's version and connection. A model the account cannot use fails the run at its first call, with the runtime's message.
|
|
168
|
+
Before creating a run, `factory run` validates the input, reads the prompts and checks from the repository, where the agents will work, for each runtime the workflow uses, that its executable is in the `PATH`, at least the supported version, and connected; a missing piece fails the command with the stage, runtime and reason. The terminal then shows each runtime's version and connection. A model the account cannot use fails the run at its first call, with the runtime's message.
|
|
169
169
|
|
|
170
170
|
The run executes in the foreground. The terminal shows each stage's start and end, decisions and corrections with their counter (`[check.invalid 1/3]`), journal messages and, for an agent, the start and end of its call, each finished tool with its duration and isolation warnings; then the result, the duration, the agents' tokens and estimated cost, and the runtimes used. `--json` writes every event, then the result, as JSON lines on standard output. Exit codes: 0 completed, 1 error or failed run.
|
|
171
171
|
|
|
@@ -183,17 +183,6 @@ Tokens and costs are the figures each runtime announces, never recomputed: Claud
|
|
|
183
183
|
|
|
184
184
|
Not in this version: resuming a run, detached runs, logs `--follow` and stop, local settings or profile overrides, actions or graph drawing in the dashboard, runs of several repositories, `factory new`, a shared stage library, a test harness for workflows, CI, cron or Git hook triggers, notifications, Windows.
|
|
185
185
|
|
|
186
|
-
## Develop the core
|
|
187
|
-
|
|
188
|
-
```sh
|
|
189
|
-
npm ci
|
|
190
|
-
npm run check # lint, format, typecheck, tests with coverage, build
|
|
191
|
-
npm run build
|
|
192
|
-
npm pack # then, in a test repository: npm install --no-save --prefix .factory /path/to/clemrig-factory-0.1.0.tgz
|
|
193
|
-
```
|
|
194
|
-
|
|
195
|
-
`npm link` in this repository provides a global `factory` built from it; a test repository still runs the core installed in its `.factory/`. See [AGENTS.md](AGENTS.md), [docs/ARCHITECTURE.md](docs/ARCHITECTURE.md), [docs/DEVELOPMENT.md](docs/DEVELOPMENT.md) and the [decisions](docs/decisions/README.md) (in French).
|
|
196
|
-
|
|
197
186
|
## License
|
|
198
187
|
|
|
199
|
-
|
|
188
|
+
MIT
|
package/dist/app/doctor.d.ts
CHANGED
|
@@ -1,7 +1,5 @@
|
|
|
1
|
-
import type
|
|
2
|
-
|
|
3
|
-
import { type AgentProblem, type RuntimeStatus } from "../system/runtimes/inspect.js";
|
|
4
|
-
export type { AgentProblem, RuntimeStatus, } from "../system/runtimes/inspect.js";
|
|
1
|
+
import { type AgentProblem, type Runtime, type RuntimeStatus, type Workflow } from "@clemrig/flow";
|
|
2
|
+
export type { RuntimeStatus } from "@clemrig/flow";
|
|
5
3
|
/** What `factory doctor` found, without any provider request. */
|
|
6
4
|
export interface Diagnosis {
|
|
7
5
|
ok: boolean;
|
package/dist/app/doctor.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
|
+
import { inspectNode, inspectRuntimes, } from "@clemrig/flow";
|
|
1
2
|
import { loadLocalEnvironment } from "../system/environment.js";
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
3
|
+
import { emptyFactory, loadPrompts } from "../system/factory.js";
|
|
4
|
+
import { loadWorkflows } from "./factory.js";
|
|
4
5
|
const message = (error) => error instanceof Error ? error.message : String(error);
|
|
5
6
|
/** Node, the factory and its workflows' prompts, then each runtime in use. */
|
|
6
7
|
export async function diagnose(factoryDir) {
|
|
@@ -9,7 +10,7 @@ export async function diagnose(factoryDir) {
|
|
|
9
10
|
let factory;
|
|
10
11
|
let loaded;
|
|
11
12
|
try {
|
|
12
|
-
factory = await
|
|
13
|
+
factory = await loadWorkflows(factoryDir);
|
|
13
14
|
loaded = { ok: true, detail: `Factory ${factoryDir}` };
|
|
14
15
|
}
|
|
15
16
|
catch (error) {
|
|
@@ -28,7 +29,8 @@ export async function diagnose(factoryDir) {
|
|
|
28
29
|
for (const [stage, declared] of Object.entries(workflow.agents))
|
|
29
30
|
agents[`${workflow.name}.${stage}`] = declared;
|
|
30
31
|
}
|
|
31
|
-
|
|
32
|
+
// Where the agents will work: the repository.
|
|
33
|
+
const { runtimes, problems } = await inspectRuntimes(agents, factory?.dir ?? emptyFactory(factoryDir).dir);
|
|
32
34
|
const ok = node.ok &&
|
|
33
35
|
loaded.ok &&
|
|
34
36
|
workflows.every(({ error }) => error === undefined) &&
|
package/dist/app/doctor.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"doctor.js","sourceRoot":"","sources":["../../src/app/doctor.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"doctor.js","sourceRoot":"","sources":["../../src/app/doctor.ts"],"names":[],"mappings":"AAAA,OAAO,EAGL,WAAW,EACX,eAAe,GAIhB,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,oBAAoB,EAAE,MAAM,0BAA0B,CAAC;AAChE,OAAO,EAAE,YAAY,EAAgB,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAC/E,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAgB7C,MAAM,OAAO,GAAG,CAAC,KAAc,EAAE,EAAE,CACjC,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;AAEzD,8EAA8E;AAC9E,MAAM,CAAC,KAAK,UAAU,QAAQ,CAAC,UAAkB;IAC/C,oBAAoB,CAAC,UAAU,CAAC,CAAC;IACjC,MAAM,IAAI,GAAG,WAAW,EAAE,CAAC;IAC3B,IAAI,OAA4B,CAAC;IACjC,IAAI,MAAqB,CAAC;IAC1B,IAAI,CAAC;QACH,OAAO,GAAG,MAAM,aAAa,CAAC,UAAU,CAAC,CAAC;QAC1C,MAAM,GAAG,EAAE,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,WAAW,UAAU,EAAE,EAAE,CAAC;IACzD,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,MAAM,GAAG,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,YAAY,OAAO,CAAC,KAAK,CAAC,EAAE,EAAE,CAAC;IAC/D,CAAC;IACD,MAAM,SAAS,GAA2B,EAAE,CAAC;IAC7C,MAAM,MAAM,GAA+B,EAAE,CAAC;IAC9C,KAAK,MAAM,QAAQ,IAAI,OAAO,EAAE,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,EAAE,CAAC;QACzD,IAAI,CAAC;YACH,MAAM,WAAW,CAAC,UAAU,EAAE,QAAQ,CAAC,CAAC;YACxC,SAAS,CAAC,IAAI,CAAC,EAAE,QAAQ,EAAE,CAAC,CAAC;QAC/B,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,SAAS,CAAC,IAAI,CAAC,EAAE,QAAQ,EAAE,KAAK,EAAE,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;QACtD,CAAC;QACD,KAAK,MAAM,CAAC,KAAK,EAAE,QAAQ,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAC;YAC7D,MAAM,CAAC,GAAG,QAAQ,CAAC,IAAI,IAAI,KAAK,EAAE,CAAC,GAAG,QAAQ,CAAC;IACnD,CAAC;IACD,8CAA8C;IAC9C,MAAM,EAAE,QAAQ,EAAE,QAAQ,EAAE,GAAG,MAAM,eAAe,CAClD,MAAM,EACN,OAAO,EAAE,GAAG,IAAI,YAAY,CAAC,UAAU,CAAC,CAAC,GAAG,CAC7C,CAAC;IACF,MAAM,EAAE,GACN,IAAI,CAAC,EAAE;QACP,MAAM,CAAC,EAAE;QACT,SAAS,CAAC,KAAK,CAAC,CAAC,EAAE,KAAK,EAAE,EAAE,EAAE,CAAC,KAAK,KAAK,SAAS,CAAC;QACnD,QAAQ,CAAC,MAAM,KAAK,CAAC,CAAC;IACxB,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,QAAQ,EAAE,QAAQ,EAAE,CAAC;AACtE,CAAC"}
|
package/dist/app/factory.d.ts
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { type Factory } from "../system/factory.js";
|
|
2
2
|
export type { Factory } from "../system/factory.js";
|
|
3
|
+
/** The repository's workflows, each of whose inputs can be given as options of `factory run`. */
|
|
4
|
+
export declare function loadWorkflows(factoryDir: string): Promise<Factory>;
|
|
3
5
|
/** Loads `.factory/.env` without overriding the shell, then the repository's workflows. */
|
|
4
6
|
export declare function openFactory(factoryDir: string): Promise<Factory>;
|
|
5
7
|
/**
|
package/dist/app/factory.js
CHANGED
|
@@ -1,10 +1,21 @@
|
|
|
1
1
|
import { loadLocalEnvironment } from "../system/environment.js";
|
|
2
2
|
import { emptyFactory, loadFactory } from "../system/factory.js";
|
|
3
|
+
import { optionProblems } from "./options.js";
|
|
3
4
|
const message = (error) => error instanceof Error ? error.message : String(error);
|
|
5
|
+
/** The repository's workflows, each of whose inputs can be given as options of `factory run`. */
|
|
6
|
+
export async function loadWorkflows(factoryDir) {
|
|
7
|
+
const factory = await loadFactory(factoryDir);
|
|
8
|
+
for (const workflow of factory.workflows.values()) {
|
|
9
|
+
const problems = optionProblems(workflow);
|
|
10
|
+
if (problems.length)
|
|
11
|
+
throw new Error(`Invalid workflow ${workflow.name}: ${problems.join("; ")}`);
|
|
12
|
+
}
|
|
13
|
+
return factory;
|
|
14
|
+
}
|
|
4
15
|
/** Loads `.factory/.env` without overriding the shell, then the repository's workflows. */
|
|
5
16
|
export async function openFactory(factoryDir) {
|
|
6
17
|
loadLocalEnvironment(factoryDir);
|
|
7
|
-
return
|
|
18
|
+
return loadWorkflows(factoryDir);
|
|
8
19
|
}
|
|
9
20
|
/**
|
|
10
21
|
* The factory to read runs with: while `factory.ts` cannot load, its runs stay
|
|
@@ -13,7 +24,7 @@ export async function openFactory(factoryDir) {
|
|
|
13
24
|
export async function openFactoryForReading(factoryDir) {
|
|
14
25
|
loadLocalEnvironment(factoryDir);
|
|
15
26
|
try {
|
|
16
|
-
return { factory: await
|
|
27
|
+
return { factory: await loadWorkflows(factoryDir) };
|
|
17
28
|
}
|
|
18
29
|
catch (error) {
|
|
19
30
|
return { factory: emptyFactory(factoryDir), error: message(error) };
|
package/dist/app/factory.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"factory.js","sourceRoot":"","sources":["../../src/app/factory.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,oBAAoB,EAAE,MAAM,0BAA0B,CAAC;AAChE,OAAO,EAAE,YAAY,EAAgB,WAAW,EAAE,MAAM,sBAAsB,CAAC;
|
|
1
|
+
{"version":3,"file":"factory.js","sourceRoot":"","sources":["../../src/app/factory.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,oBAAoB,EAAE,MAAM,0BAA0B,CAAC;AAChE,OAAO,EAAE,YAAY,EAAgB,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAC/E,OAAO,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAI9C,MAAM,OAAO,GAAG,CAAC,KAAc,EAAE,EAAE,CACjC,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;AAEzD,iGAAiG;AACjG,MAAM,CAAC,KAAK,UAAU,aAAa,CAAC,UAAkB;IACpD,MAAM,OAAO,GAAG,MAAM,WAAW,CAAC,UAAU,CAAC,CAAC;IAC9C,KAAK,MAAM,QAAQ,IAAI,OAAO,CAAC,SAAS,CAAC,MAAM,EAAE,EAAE,CAAC;QAClD,MAAM,QAAQ,GAAG,cAAc,CAAC,QAAQ,CAAC,CAAC;QAC1C,IAAI,QAAQ,CAAC,MAAM;YACjB,MAAM,IAAI,KAAK,CACb,oBAAoB,QAAQ,CAAC,IAAI,KAAK,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAC5D,CAAC;IACN,CAAC;IACD,OAAO,OAAO,CAAC;AACjB,CAAC;AAED,2FAA2F;AAC3F,MAAM,CAAC,KAAK,UAAU,WAAW,CAAC,UAAkB;IAClD,oBAAoB,CAAC,UAAU,CAAC,CAAC;IACjC,OAAO,aAAa,CAAC,UAAU,CAAC,CAAC;AACnC,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,qBAAqB,CACzC,UAAkB;IAElB,oBAAoB,CAAC,UAAU,CAAC,CAAC;IACjC,IAAI,CAAC;QACH,OAAO,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC,UAAU,CAAC,EAAE,CAAC;IACtD,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO,EAAE,OAAO,EAAE,YAAY,CAAC,UAAU,CAAC,EAAE,KAAK,EAAE,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;IACtE,CAAC;AACH,CAAC"}
|
package/dist/app/init.d.ts
CHANGED
|
@@ -1,6 +1,2 @@
|
|
|
1
|
+
export { npmInstall as installFactory } from "../system/npm.js";
|
|
1
2
|
export { createFromTemplates as createFactory } from "../system/templates.js";
|
|
2
|
-
/** Installs `.factory/`'s dependencies; `output` explains a failure. */
|
|
3
|
-
export declare function installFactory(factoryDir: string): Promise<{
|
|
4
|
-
ok: boolean;
|
|
5
|
-
output: string;
|
|
6
|
-
}>;
|
package/dist/app/init.js
CHANGED
|
@@ -1,15 +1,3 @@
|
|
|
1
|
-
|
|
1
|
+
export { npmInstall as installFactory } from "../system/npm.js";
|
|
2
2
|
export { createFromTemplates as createFactory } from "../system/templates.js";
|
|
3
|
-
/** Installs `.factory/`'s dependencies; `output` explains a failure. */
|
|
4
|
-
export async function installFactory(factoryDir) {
|
|
5
|
-
const install = await runProcess(["npm", "install", "--no-audit", "--no-fund"], factoryDir, 600_000).catch((error) => ({
|
|
6
|
-
exitCode: 1,
|
|
7
|
-
stdout: "",
|
|
8
|
-
stderr: error instanceof Error ? error.message : String(error),
|
|
9
|
-
}));
|
|
10
|
-
return {
|
|
11
|
-
ok: install.exitCode === 0,
|
|
12
|
-
output: install.stderr || install.stdout,
|
|
13
|
-
};
|
|
14
|
-
}
|
|
15
3
|
//# sourceMappingURL=init.js.map
|
package/dist/app/init.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"init.js","sourceRoot":"","sources":["../../src/app/init.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"init.js","sourceRoot":"","sources":["../../src/app/init.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,IAAI,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAChE,OAAO,EAAE,mBAAmB,IAAI,aAAa,EAAE,MAAM,wBAAwB,CAAC"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { type Workflow, type z } from "@clemrig/flow";
|
|
2
|
+
/** What an option may be called, after its `--`. */
|
|
3
|
+
export declare const OPTION_NAME: RegExp;
|
|
4
|
+
/** Why some inputs of the workflow cannot be given as `--<name>` options of `factory run`. */
|
|
5
|
+
export declare function optionProblems(workflow: Pick<Workflow, "input">): string[];
|
|
6
|
+
/** Whether a field takes an option given alone: a boolean, possibly optional or defaulted. */
|
|
7
|
+
export declare function isFlag(schema: z.ZodType): boolean;
|
|
8
|
+
/**
|
|
9
|
+
* The input that `factory run` options give the workflow. An option given
|
|
10
|
+
* without a value is `true`, accepted only by a boolean field: otherwise it is
|
|
11
|
+
* refused with every other problem, found by validating the input once.
|
|
12
|
+
*/
|
|
13
|
+
export declare function inputFromOptions(workflow: Pick<Workflow, "name" | "input">, options: Record<string, string | boolean>): Record<string, string | boolean>;
|
|
14
|
+
/** A refused input of `factory run`, worded as options; any other error as it is. */
|
|
15
|
+
export declare function asOptionsError(workflow: Pick<Workflow, "name">, options: Record<string, string | boolean>, error: unknown): unknown;
|
|
16
|
+
/** `--max-cost-usd`: the run's budget instead of the workflow's. */
|
|
17
|
+
export declare function parseBudget(value: string | boolean): number;
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import { InvalidInputError, parseInput, } from "@clemrig/flow";
|
|
2
|
+
/** Options of every `factory run`: no input may take their names. */
|
|
3
|
+
const GLOBAL_OPTIONS = ["json", "help", "max-cost-usd"];
|
|
4
|
+
/** What an option may be called, after its `--`. */
|
|
5
|
+
export const OPTION_NAME = /^[a-zA-Z][a-zA-Z0-9_-]*$/;
|
|
6
|
+
/** Why some inputs of the workflow cannot be given as `--<name>` options of `factory run`. */
|
|
7
|
+
export function optionProblems(workflow) {
|
|
8
|
+
return Object.keys(workflow.input?.shape ?? {}).flatMap((name) => GLOBAL_OPTIONS.includes(name)
|
|
9
|
+
? [`input ${name} conflicts with the global --${name} option`]
|
|
10
|
+
: OPTION_NAME.test(name)
|
|
11
|
+
? []
|
|
12
|
+
: [`input ${name} is not a valid option name`]);
|
|
13
|
+
}
|
|
14
|
+
/** Whether a field takes an option given alone: a boolean, possibly optional or defaulted. */
|
|
15
|
+
export function isFlag(schema) {
|
|
16
|
+
let def = schema.def;
|
|
17
|
+
while (def.innerType &&
|
|
18
|
+
["optional", "nullable", "default"].includes(def.type))
|
|
19
|
+
def = def.innerType.def;
|
|
20
|
+
return def.type === "boolean";
|
|
21
|
+
}
|
|
22
|
+
/** Options given without a value to a field that is not a boolean: they have no value to give. */
|
|
23
|
+
function valueless(workflow, options) {
|
|
24
|
+
const shape = workflow.input?.shape ?? {};
|
|
25
|
+
return Object.keys(options).filter((name) => {
|
|
26
|
+
const field = Object.hasOwn(shape, name) ? shape[name] : undefined;
|
|
27
|
+
return options[name] === true && field !== undefined && !isFlag(field);
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
/** Every problem of `factory run` options, worded as options. */
|
|
31
|
+
function optionsError(workflow, options, missingValues, problems) {
|
|
32
|
+
const found = missingValues.map((name) => `--${name}: missing value`);
|
|
33
|
+
for (const { kind, field, message } of problems) {
|
|
34
|
+
const name = field.split(".")[0] ?? "";
|
|
35
|
+
if (kind === "unknown")
|
|
36
|
+
found.push(`unknown option --${field}`);
|
|
37
|
+
else if (!missingValues.includes(name))
|
|
38
|
+
found.push(Object.hasOwn(options, name)
|
|
39
|
+
? `--${name}: ${message}`
|
|
40
|
+
: `missing option --${name}`);
|
|
41
|
+
}
|
|
42
|
+
return new Error(`Invalid input for ${workflow.name}: ${found.join("; ")}`);
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* The input that `factory run` options give the workflow. An option given
|
|
46
|
+
* without a value is `true`, accepted only by a boolean field: otherwise it is
|
|
47
|
+
* refused with every other problem, found by validating the input once.
|
|
48
|
+
*/
|
|
49
|
+
export function inputFromOptions(workflow, options) {
|
|
50
|
+
const missingValues = valueless(workflow, options);
|
|
51
|
+
const input = Object.fromEntries(Object.entries(options).filter(([name]) => !missingValues.includes(name)));
|
|
52
|
+
if (!missingValues.length)
|
|
53
|
+
return input;
|
|
54
|
+
let problems = [];
|
|
55
|
+
try {
|
|
56
|
+
parseInput(workflow, input);
|
|
57
|
+
}
|
|
58
|
+
catch (error) {
|
|
59
|
+
if (!(error instanceof InvalidInputError))
|
|
60
|
+
throw error;
|
|
61
|
+
problems = error.problems;
|
|
62
|
+
}
|
|
63
|
+
throw optionsError(workflow, options, missingValues, problems);
|
|
64
|
+
}
|
|
65
|
+
/** A refused input of `factory run`, worded as options; any other error as it is. */
|
|
66
|
+
export function asOptionsError(workflow, options, error) {
|
|
67
|
+
return error instanceof InvalidInputError
|
|
68
|
+
? optionsError(workflow, options, [], error.problems)
|
|
69
|
+
: error;
|
|
70
|
+
}
|
|
71
|
+
/** `--max-cost-usd`: the run's budget instead of the workflow's. */
|
|
72
|
+
export function parseBudget(value) {
|
|
73
|
+
const budget = Number(value);
|
|
74
|
+
if (typeof value !== "string" || !Number.isFinite(budget) || budget <= 0)
|
|
75
|
+
throw new Error(`Invalid --max-cost-usd ${String(value)}: expected a positive number of USD`);
|
|
76
|
+
return budget;
|
|
77
|
+
}
|
|
78
|
+
//# sourceMappingURL=options.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"options.js","sourceRoot":"","sources":["../../src/app/options.ts"],"names":[],"mappings":"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"}
|
package/dist/app/run.d.ts
CHANGED
|
@@ -1,24 +1,8 @@
|
|
|
1
|
-
import type
|
|
1
|
+
import { type RunHooks, type StartedRun } from "@clemrig/flow";
|
|
2
2
|
import { type Factory } from "../system/factory.js";
|
|
3
|
-
import { type RuntimeStatus } from "../system/runtimes/inspect.js";
|
|
4
|
-
export interface RunHooks {
|
|
5
|
-
/** Each stage, journal and agent event, once recorded. */
|
|
6
|
-
onEvent(event: RunEvent): void;
|
|
7
|
-
}
|
|
8
|
-
/** A created run, executing in the foreground. */
|
|
9
|
-
export interface StartedRun {
|
|
10
|
-
state: Readonly<RunState>;
|
|
11
|
-
/** Each runtime the run uses: version, executable and connection. */
|
|
12
|
-
runtimes: RuntimeStatus[];
|
|
13
|
-
/** Settles with the run once it completed or failed. */
|
|
14
|
-
done: Promise<RunState>;
|
|
15
|
-
/** Fails the run with `reason` before its next stage. */
|
|
16
|
-
stop(reason: Error): void;
|
|
17
|
-
/** Kills the child process groups still running, before quitting at once. */
|
|
18
|
-
kill(): void;
|
|
19
|
-
}
|
|
20
3
|
/**
|
|
21
|
-
*
|
|
22
|
-
*
|
|
4
|
+
* Starts a workflow of the factory from `factory run` options, with its prompts
|
|
5
|
+
* from `.factory/`; the run works in the repository that contains `.factory/`
|
|
6
|
+
* and is kept in its `runs/`.
|
|
23
7
|
*/
|
|
24
8
|
export declare function startRun(factory: Factory, name: string, options: Record<string, string | boolean>, hooks: RunHooks): Promise<StartedRun>;
|
package/dist/app/run.js
CHANGED
|
@@ -1,100 +1,29 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { executeWorkflow } from "../engine/runner.js";
|
|
3
|
-
import { parseInput } from "../engine/workflow.js";
|
|
1
|
+
import { startRun as start, } from "@clemrig/flow";
|
|
4
2
|
import { loadPrompts, workflowOf } from "../system/factory.js";
|
|
5
|
-
import {
|
|
6
|
-
import { AgentRuntime } from "../system/runtimes/agent-runtime.js";
|
|
7
|
-
import { inspectRuntimes, } from "../system/runtimes/inspect.js";
|
|
8
|
-
import { FileRunStore, newRunId } from "../system/store.js";
|
|
9
|
-
/** `--max-cost-usd`: the run's budget instead of the workflow's. */
|
|
10
|
-
function parseBudget(value) {
|
|
11
|
-
const budget = Number(value);
|
|
12
|
-
if (typeof value !== "string" || !Number.isFinite(budget) || budget <= 0)
|
|
13
|
-
throw new Error(`Invalid --max-cost-usd ${String(value)}: expected a positive number of USD`);
|
|
14
|
-
return budget;
|
|
15
|
-
}
|
|
3
|
+
import { asOptionsError, inputFromOptions, parseBudget } from "./options.js";
|
|
16
4
|
/**
|
|
17
|
-
*
|
|
18
|
-
*
|
|
5
|
+
* Starts a workflow of the factory from `factory run` options, with its prompts
|
|
6
|
+
* from `.factory/`; the run works in the repository that contains `.factory/`
|
|
7
|
+
* and is kept in its `runs/`.
|
|
19
8
|
*/
|
|
20
9
|
export async function startRun(factory, name, options, hooks) {
|
|
21
10
|
const workflow = workflowOf(factory, name);
|
|
22
|
-
const { "max-cost-usd": budget, ...
|
|
23
|
-
const maxCostUsd = budget === undefined ?
|
|
24
|
-
const input =
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
updatedAt: now,
|
|
40
|
-
metrics: emptyMetrics(),
|
|
41
|
-
runtimes: Object.fromEntries(Object.entries(runtimes).map(([runtime, { detail }]) => [
|
|
42
|
-
runtime,
|
|
43
|
-
detail,
|
|
44
|
-
])),
|
|
45
|
-
};
|
|
46
|
-
const store = new FileRunStore(factory.runsDir, state.id);
|
|
47
|
-
const agent = new AgentRuntime({
|
|
48
|
-
dir: factory.dir,
|
|
49
|
-
factoryDir: factory.factoryDir,
|
|
50
|
-
prompts,
|
|
51
|
-
onUsage: async (report) => {
|
|
52
|
-
if (state.metrics)
|
|
53
|
-
recordUsage(state.metrics, report);
|
|
54
|
-
await store.save(state);
|
|
55
|
-
},
|
|
56
|
-
run: { id: state.id, directory: store.directory },
|
|
57
|
-
executables,
|
|
58
|
-
});
|
|
59
|
-
await store.save(state);
|
|
60
|
-
const controller = new AbortController();
|
|
61
|
-
/**
|
|
62
|
-
* Past its budget, the run stops: the abort fails it at its next stage
|
|
63
|
-
* boundary even if workflow code catches the error, and no call starts.
|
|
64
|
-
*/
|
|
65
|
-
const overBudget = () => {
|
|
66
|
-
const problem = maxCostUsd === undefined || !state.metrics
|
|
67
|
-
? undefined
|
|
68
|
-
: budgetProblem(state.metrics, maxCostUsd);
|
|
69
|
-
if (problem)
|
|
70
|
-
controller.abort(new Error(problem));
|
|
71
|
-
return problem;
|
|
72
|
-
};
|
|
73
|
-
// Checked before each agent call and after it, failed or not, on the figures its runtime announced.
|
|
74
|
-
const budgeted = {
|
|
75
|
-
async execute(request, record) {
|
|
76
|
-
const refused = overBudget();
|
|
77
|
-
if (refused)
|
|
78
|
-
throw new Error(refused);
|
|
79
|
-
const value = await agent
|
|
80
|
-
.execute(request, record)
|
|
81
|
-
.finally(() => overBudget());
|
|
82
|
-
const exceeded = overBudget();
|
|
83
|
-
if (exceeded)
|
|
84
|
-
throw new Error(exceeded);
|
|
85
|
-
return value;
|
|
86
|
-
},
|
|
87
|
-
};
|
|
88
|
-
const done = inDirectory(factory.dir, () => executeWorkflow(workflow, state, { agent: budgeted, dir: factory.dir }, store, {
|
|
89
|
-
onEvent: hooks.onEvent,
|
|
90
|
-
signal: controller.signal,
|
|
91
|
-
}));
|
|
92
|
-
return {
|
|
93
|
-
state,
|
|
94
|
-
runtimes: Object.values(runtimes),
|
|
95
|
-
done,
|
|
96
|
-
stop: (reason) => controller.abort(reason),
|
|
97
|
-
kill: killProcessGroups,
|
|
98
|
-
};
|
|
11
|
+
const { "max-cost-usd": budget, ...given } = options;
|
|
12
|
+
const maxCostUsd = budget === undefined ? undefined : parseBudget(budget);
|
|
13
|
+
const input = inputFromOptions(workflow, given);
|
|
14
|
+
try {
|
|
15
|
+
return await start({
|
|
16
|
+
workflow,
|
|
17
|
+
input,
|
|
18
|
+
maxCostUsd,
|
|
19
|
+
prompts: () => loadPrompts(factory.factoryDir, workflow),
|
|
20
|
+
dir: factory.dir,
|
|
21
|
+
configDir: factory.factoryDir,
|
|
22
|
+
runsDir: factory.runsDir,
|
|
23
|
+
}, hooks);
|
|
24
|
+
}
|
|
25
|
+
catch (error) {
|
|
26
|
+
throw asOptionsError(workflow, given, error);
|
|
27
|
+
}
|
|
99
28
|
}
|
|
100
29
|
//# sourceMappingURL=run.js.map
|
package/dist/app/run.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"run.js","sourceRoot":"","sources":["../../src/app/run.ts"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"run.js","sourceRoot":"","sources":["../../src/app/run.ts"],"names":[],"mappings":"AAAA,OAAO,EAGL,QAAQ,IAAI,KAAK,GAClB,MAAM,eAAe,CAAC;AACvB,OAAO,EAAgB,WAAW,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AAC7E,OAAO,EAAE,cAAc,EAAE,gBAAgB,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAE7E;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,QAAQ,CAC5B,OAAgB,EAChB,IAAY,EACZ,OAAyC,EACzC,KAAe;IAEf,MAAM,QAAQ,GAAG,UAAU,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC;IAC3C,MAAM,EAAE,cAAc,EAAE,MAAM,EAAE,GAAG,KAAK,EAAE,GAAG,OAAO,CAAC;IACrD,MAAM,UAAU,GAAG,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,WAAW,CAAC,MAAM,CAAC,CAAC;IAC1E,MAAM,KAAK,GAAG,gBAAgB,CAAC,QAAQ,EAAE,KAAK,CAAC,CAAC;IAChD,IAAI,CAAC;QACH,OAAO,MAAM,KAAK,CAChB;YACE,QAAQ;YACR,KAAK;YACL,UAAU;YACV,OAAO,EAAE,GAAG,EAAE,CAAC,WAAW,CAAC,OAAO,CAAC,UAAU,EAAE,QAAQ,CAAC;YACxD,GAAG,EAAE,OAAO,CAAC,GAAG;YAChB,SAAS,EAAE,OAAO,CAAC,UAAU;YAC7B,OAAO,EAAE,OAAO,CAAC,OAAO;SACzB,EACD,KAAK,CACN,CAAC;IACJ,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,MAAM,cAAc,CAAC,QAAQ,EAAE,KAAK,EAAE,KAAK,CAAC,CAAC;IAC/C,CAAC;AACH,CAAC"}
|
package/dist/app/runs.d.ts
CHANGED
|
@@ -1,36 +1,8 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { RunEntry, RunState } from "@clemrig/flow";
|
|
2
2
|
import type { Factory } from "../system/factory.js";
|
|
3
|
-
|
|
4
|
-
/** A run, or why it cannot be read. */
|
|
5
|
-
export type RunEntry = {
|
|
6
|
-
id: string;
|
|
7
|
-
state: RunState;
|
|
8
|
-
} | {
|
|
9
|
-
id: string;
|
|
10
|
-
error: string;
|
|
11
|
-
};
|
|
12
|
-
/** The repository's runs in creation order; an unreadable run comes with its error. */
|
|
3
|
+
/** The repository's runs, in creation order; an unreadable run comes with its error. */
|
|
13
4
|
export declare function listRuns(factory: Factory): Promise<RunEntry[]>;
|
|
14
|
-
/**
|
|
15
|
-
export declare function summarizeRun(state: RunState): {
|
|
16
|
-
id: string;
|
|
17
|
-
workflow: string;
|
|
18
|
-
status: "completed" | "failed" | "running";
|
|
19
|
-
stage: string;
|
|
20
|
-
durationMs: number | null;
|
|
21
|
-
costUsd: number | null;
|
|
22
|
-
/** Some agent call announced no usage. */
|
|
23
|
-
partial: boolean;
|
|
24
|
-
updatedAt: string;
|
|
25
|
-
};
|
|
26
|
-
/** One run's state; an unknown ID is refused. */
|
|
5
|
+
/** One run of the repository; an unknown ID is refused. */
|
|
27
6
|
export declare function loadRun(factory: Factory, id: string): Promise<RunState>;
|
|
28
|
-
/**
|
|
29
|
-
export declare function loadRunEvents(factory: Factory, id: string): Promise<RunEvent[]>;
|
|
30
|
-
/**
|
|
31
|
-
* A run's result lines: its workflow's rendering, or its validated data when the
|
|
32
|
-
* workflow left `factory.ts`. A failing rendering becomes the explanation.
|
|
33
|
-
*/
|
|
7
|
+
/** A run's result lines: its workflow's rendering, or its validated data when the workflow left `factory.ts`. */
|
|
34
8
|
export declare function presentResult(factory: Factory, state: Readonly<RunState>): string[];
|
|
35
|
-
/** Each correction route's maximum, keyed `<stage>.<outcome>` like a run's counters. */
|
|
36
|
-
export declare function retryMaximums(factory: Factory, workflow: string): Map<string, number>;
|
package/dist/app/runs.js
CHANGED
|
@@ -1,66 +1,14 @@
|
|
|
1
|
-
import
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
const message = (error) => error instanceof Error ? error.message : String(error);
|
|
6
|
-
/** The repository's runs in creation order; an unreadable run comes with its error. */
|
|
7
|
-
export async function listRuns(factory) {
|
|
8
|
-
const entries = [];
|
|
9
|
-
for (const id of await FileRunStore.list(factory.runsDir))
|
|
10
|
-
try {
|
|
11
|
-
entries.push({
|
|
12
|
-
id,
|
|
13
|
-
state: await new FileRunStore(factory.runsDir, id).load(),
|
|
14
|
-
});
|
|
15
|
-
}
|
|
16
|
-
catch (error) {
|
|
17
|
-
entries.push({ id, error: message(error) });
|
|
18
|
-
}
|
|
19
|
-
return entries;
|
|
1
|
+
import * as flow from "@clemrig/flow";
|
|
2
|
+
/** The repository's runs, in creation order; an unreadable run comes with its error. */
|
|
3
|
+
export function listRuns(factory) {
|
|
4
|
+
return flow.listRuns(factory.runsDir);
|
|
20
5
|
}
|
|
21
|
-
/**
|
|
22
|
-
export function
|
|
23
|
-
|
|
24
|
-
return {
|
|
25
|
-
id: state.id,
|
|
26
|
-
workflow: state.workflow,
|
|
27
|
-
status: state.status,
|
|
28
|
-
stage: state.stage,
|
|
29
|
-
durationMs: elapsedMs(state),
|
|
30
|
-
costUsd: usage?.responses ? usage.costUsd : null,
|
|
31
|
-
/** Some agent call announced no usage. */
|
|
32
|
-
partial: Boolean(usage?.missing),
|
|
33
|
-
updatedAt: state.updatedAt,
|
|
34
|
-
};
|
|
6
|
+
/** One run of the repository; an unknown ID is refused. */
|
|
7
|
+
export function loadRun(factory, id) {
|
|
8
|
+
return flow.loadRun(factory.runsDir, id);
|
|
35
9
|
}
|
|
36
|
-
/**
|
|
37
|
-
export async function loadRun(factory, id) {
|
|
38
|
-
return new FileRunStore(factory.runsDir, id).load();
|
|
39
|
-
}
|
|
40
|
-
/** One run's stage and journal events, in order. */
|
|
41
|
-
export async function loadRunEvents(factory, id) {
|
|
42
|
-
return new FileRunStore(factory.runsDir, id).events();
|
|
43
|
-
}
|
|
44
|
-
/**
|
|
45
|
-
* A run's result lines: its workflow's rendering, or its validated data when the
|
|
46
|
-
* workflow left `factory.ts`. A failing rendering becomes the explanation.
|
|
47
|
-
*/
|
|
10
|
+
/** A run's result lines: its workflow's rendering, or its validated data when the workflow left `factory.ts`. */
|
|
48
11
|
export function presentResult(factory, state) {
|
|
49
|
-
|
|
50
|
-
const workflow = factory.workflows.get(state.workflow);
|
|
51
|
-
return workflow ? workflow.presentResult(state) : presentData(state);
|
|
52
|
-
}
|
|
53
|
-
catch (error) {
|
|
54
|
-
return [`Result unavailable: ${message(error)}`];
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
/** Each correction route's maximum, keyed `<stage>.<outcome>` like a run's counters. */
|
|
58
|
-
export function retryMaximums(factory, workflow) {
|
|
59
|
-
const found = new Map();
|
|
60
|
-
for (const [name, node] of Object.entries(factory.workflows.get(workflow)?.nodes ?? {}))
|
|
61
|
-
for (const [outcome, edge] of Object.entries(node.on))
|
|
62
|
-
if (edge && typeof edge === "object")
|
|
63
|
-
found.set(`${name}.${outcome}`, edge.max);
|
|
64
|
-
return found;
|
|
12
|
+
return flow.presentResult(factory.workflows.get(state.workflow), state);
|
|
65
13
|
}
|
|
66
14
|
//# sourceMappingURL=runs.js.map
|
package/dist/app/runs.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"runs.js","sourceRoot":"","sources":["../../src/app/runs.ts"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"runs.js","sourceRoot":"","sources":["../../src/app/runs.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,IAAI,MAAM,eAAe,CAAC;AAItC,wFAAwF;AACxF,MAAM,UAAU,QAAQ,CAAC,OAAgB;IACvC,OAAO,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;AACxC,CAAC;AAED,2DAA2D;AAC3D,MAAM,UAAU,OAAO,CAAC,OAAgB,EAAE,EAAU;IAClD,OAAO,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC;AAC3C,CAAC;AAED,iHAAiH;AACjH,MAAM,UAAU,aAAa,CAC3B,OAAgB,EAChB,KAAyB;IAEzB,OAAO,IAAI,CAAC,aAAa,CAAC,OAAO,CAAC,SAAS,CAAC,GAAG,CAAC,KAAK,CAAC,QAAQ,CAAC,EAAE,KAAK,CAAC,CAAC;AAC1E,CAAC"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* The command run by the
|
|
2
|
+
* The command run by the factory installed in `.factory/`: the global `factory`
|
|
3
3
|
* calls it with the arguments it received and the `.factory/` it found. This
|
|
4
4
|
* contract only changes with a major version.
|
|
5
5
|
*/
|
package/dist/cli/application.js
CHANGED
|
@@ -16,7 +16,7 @@ function parsePort(value) {
|
|
|
16
16
|
return port;
|
|
17
17
|
}
|
|
18
18
|
/**
|
|
19
|
-
* The command run by the
|
|
19
|
+
* The command run by the factory installed in `.factory/`: the global `factory`
|
|
20
20
|
* calls it with the arguments it received and the `.factory/` it found. This
|
|
21
21
|
* contract only changes with a major version.
|
|
22
22
|
*/
|