@clemrig/factory 0.3.0 → 0.4.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.
Files changed (90) hide show
  1. package/README.md +111 -21
  2. package/dist/app/board.d.ts +7 -0
  3. package/dist/app/board.js +47 -0
  4. package/dist/app/board.js.map +1 -0
  5. package/dist/app/define.d.ts +27 -0
  6. package/dist/app/define.js +68 -0
  7. package/dist/app/define.js.map +1 -0
  8. package/dist/app/doctor.js +5 -4
  9. package/dist/app/doctor.js.map +1 -1
  10. package/dist/app/factory.js +10 -2
  11. package/dist/app/factory.js.map +1 -1
  12. package/dist/app/run.js +1 -1
  13. package/dist/app/run.js.map +1 -1
  14. package/dist/app/workflows/implement.d.ts +8 -0
  15. package/dist/app/workflows/implement.js +268 -0
  16. package/dist/app/workflows/implement.js.map +1 -0
  17. package/dist/app/workflows/issue-save.d.ts +2 -0
  18. package/dist/app/workflows/issue-save.js +35 -0
  19. package/dist/app/workflows/issue-save.js.map +1 -0
  20. package/dist/cli/application.js +1 -1
  21. package/dist/cli/application.js.map +1 -1
  22. package/dist/cli/help.d.ts +1 -1
  23. package/dist/cli/help.js +5 -3
  24. package/dist/cli/help.js.map +1 -1
  25. package/dist/cli/init.d.ts +2 -2
  26. package/dist/cli/init.js +4 -4
  27. package/dist/cli/init.js.map +1 -1
  28. package/dist/cli/ui.d.ts +5 -2
  29. package/dist/cli/ui.js +20 -7
  30. package/dist/cli/ui.js.map +1 -1
  31. package/dist/domain/board.d.ts +65 -0
  32. package/dist/domain/board.js +95 -0
  33. package/dist/domain/board.js.map +1 -0
  34. package/dist/domain/definition.d.ts +15 -0
  35. package/dist/domain/definition.js +28 -0
  36. package/dist/domain/definition.js.map +1 -0
  37. package/dist/domain/delivery.d.ts +9 -0
  38. package/dist/domain/delivery.js +10 -0
  39. package/dist/domain/delivery.js.map +1 -0
  40. package/dist/domain/issue.d.ts +11 -0
  41. package/dist/domain/issue.js +22 -0
  42. package/dist/domain/issue.js.map +1 -0
  43. package/dist/domain/parsed.d.ts +8 -0
  44. package/dist/domain/parsed.js +2 -0
  45. package/dist/domain/parsed.js.map +1 -0
  46. package/dist/domain/plan.d.ts +24 -0
  47. package/dist/domain/plan.js +49 -0
  48. package/dist/domain/plan.js.map +1 -0
  49. package/dist/domain/pull-request.d.ts +17 -0
  50. package/dist/domain/pull-request.js +32 -0
  51. package/dist/domain/pull-request.js.map +1 -0
  52. package/dist/domain/review.d.ts +36 -0
  53. package/dist/domain/review.js +45 -0
  54. package/dist/domain/review.js.map +1 -0
  55. package/dist/domain/spec.d.ts +18 -0
  56. package/dist/domain/spec.js +118 -0
  57. package/dist/domain/spec.js.map +1 -0
  58. package/dist/domain/verification.d.ts +16 -0
  59. package/dist/domain/verification.js +11 -0
  60. package/dist/domain/verification.js.map +1 -0
  61. package/dist/index.d.ts +8 -4
  62. package/dist/index.js +5 -3
  63. package/dist/index.js.map +1 -1
  64. package/dist/system/checks.d.ts +32 -0
  65. package/dist/system/checks.js +49 -0
  66. package/dist/system/checks.js.map +1 -0
  67. package/dist/system/factory.d.ts +7 -5
  68. package/dist/system/factory.js +19 -19
  69. package/dist/system/factory.js.map +1 -1
  70. package/dist/system/git.d.ts +25 -0
  71. package/dist/system/git.js +73 -0
  72. package/dist/system/git.js.map +1 -0
  73. package/dist/system/github.d.ts +8 -0
  74. package/dist/system/github.js +52 -0
  75. package/dist/system/github.js.map +1 -0
  76. package/dist/system/issues.d.ts +24 -0
  77. package/dist/system/issues.js +66 -0
  78. package/dist/system/issues.js.map +1 -0
  79. package/dist/system/lock.d.ts +8 -0
  80. package/dist/system/lock.js +35 -0
  81. package/dist/system/lock.js.map +1 -0
  82. package/dist/system/templates.d.ts +2 -1
  83. package/dist/system/templates.js +69 -3
  84. package/dist/system/templates.js.map +1 -1
  85. package/package.json +6 -4
  86. package/prompts/implement/implement.md +21 -0
  87. package/prompts/implement/plan.md +20 -0
  88. package/prompts/implement/review.md +17 -0
  89. package/templates/init/factory.ts +37 -2
  90. package/templates/skills/issue/SKILL.md +82 -0
package/README.md CHANGED
@@ -1,12 +1,13 @@
1
1
  # @clemrig/factory
2
2
 
3
- Write agent workflows in TypeScript inside any repository, run them in the terminal and watch them in a local dashboard.
3
+ Take a repository's issues from spec to pull request with agents, watch them on a local Kanban, and run the repository's own workflows.
4
4
 
5
- A workflow is an explicit graph of **CODE** stages (your code), **AGENT** stages (an agent run by [Claude Code](https://code.claude.com), [Codex](https://developers.openai.com/codex) or [Pi](https://www.npmjs.com/package/@earendil-works/pi-coding-agent)) and **GATE** stages that accept a result or send it back for correction, a bounded number of times. Workflows live in the repository's `.factory/` folder, are committed with it and run without a build step.
5
+ An idea becomes an issue; the operator specifies it with an agent; one run then plans, implements, checks and reviews it and opens its pull request; the operator approves by merging. Each of these steps is a workflow: an explicit graph of **CODE** stages (code), **AGENT** stages (an agent run by [Claude Code](https://code.claude.com), [Codex](https://developers.openai.com/codex) or [Pi](https://www.npmjs.com/package/@earendil-works/pi-coding-agent)) and **GATE** stages that accept a result or send it back for correction, a bounded number of times. The factory's workflows come with this package and are the same in every repository; the repository's `.factory/` folder adapts them (checks, budget, agents) and holds its own workflows, committed with it and run without a build step.
6
6
 
7
7
  ## Requirements
8
8
 
9
9
  - macOS or Linux, Node.js 24 or later, npm.
10
+ - For the `implement` run: Git, a GitHub repository whose remote is `origin`, with `origin/HEAD` naming the main branch (`git clone` sets it; otherwise `git remote set-head origin --auto`), and the [GitHub CLI](https://cli.github.com) `gh` logged in (`gh auth login`).
10
11
  - For agents run by Claude Code: the `claude` CLI 2.1.296 or later in the `PATH`, logged in with a claude.ai subscription (`claude`, then `/login`) or given an API key (`ANTHROPIC_API_KEY`).
11
12
  - For agents run by Codex: the `codex` CLI 0.160.1 or later in the `PATH`, logged in with a ChatGPT account or an API key (`codex login`) or given an API key (`CODEX_API_KEY`); Codex works only in a Git repository.
12
13
  - For agents run by Pi: the `pi` CLI (`@earendil-works/pi-coding-agent` 1.1.0 or later) in the `PATH`, connected to the provider each Pi profile names (`pi`, then `/login`, or the provider's API key).
@@ -20,27 +21,115 @@ npm install -g @clemrig/factory
20
21
  cd my-repository
21
22
  factory init
22
23
  factory doctor
23
- factory run ask --question "What changed recently?"
24
24
  ```
25
25
 
26
- `factory init` creates `.factory/` in the current directory and installs it; it refuses to overwrite an existing `.factory/`. Commit `.factory/`: another machine only needs `npm ci --prefix .factory`.
26
+ `factory init` creates `.factory/` and the `issue` skill in the current directory, then installs `.factory/`. It refuses, writing nothing, an existing `.factory/` or an existing `.agents/skills/issue` or `.claude/skills/issue`. When `.claude`, `.claude/skills` or `.agents` are links, the skill's link is made to resolve from the folder it really lands in, and none is made when `.claude/skills` leads to `.agents/skills`. Set the repository's checks in `.factory/factory.ts`, run `factory doctor`, then commit `.factory/`, `.agents/` and `.claude/skills/`: another machine only needs `npm ci --prefix .factory`.
27
27
 
28
28
  ```
29
29
  .factory/
30
30
  package.json pins the exact factory version
31
- factory.ts the repository's workflows
31
+ factory.ts the repository's factory: checks, budget, agents, own workflows
32
32
  workflows/ask/
33
- index.ts the example workflow
33
+ index.ts an example workflow of the repository
34
34
  prompts/answer.md the prompt of its answer stage
35
35
  tsconfig.json editor settings only
36
36
  .gitignore node_modules/, runs/, .env
37
+ issues/<slug>/ issue.md, spec.md, plan.md (committed)
37
38
  runs/ one folder per run (ignored)
38
39
  .env optional secrets (ignored)
40
+ .agents/skills/issue/ the issue skill, read by Codex and Pi
41
+ .claude/skills/issue a link to that folder, for Claude Code
39
42
  ```
40
43
 
41
44
  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.
42
45
 
43
- The example workflow `ask` reads the last 10 commits with `git log` (a CODE stage), asks a Claude Code agent whose built-in tools are limited to `Read`, `Grep` and `Glob` (`claude-sonnet-5-5`, effort `low`; this machine's MCP servers, plugins and hooks still load) 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.
46
+ ## From an idea to a pull request
47
+
48
+ 1. **Backlog.** In Claude Code, Codex or Pi, `/issue` asks for a title and a description, writes a draft outside the repository and saves it with `factory run issue-save --issue <slug> --kind issue --file <draft>`. The command checks the draft and writes `.factory/issues/<slug>/issue.md` itself: the agent chooses neither the path nor the format.
49
+ 2. **Specifying.** `/issue` again: the agent reads the code, asks questions until it can fill every section without inventing anything, and proposes the spec; once the operator agrees, `--kind spec` writes `spec.md`.
50
+ 3. Review the spec, commit it and push it on the main branch.
51
+ 4. **Executing.** `factory run implement --issue <slug>`: starting the run approves the spec. It runs without the operator; follow it in `factory ui`.
52
+ 5. **To Approve → Done.** Review and merge the pull request. After `git pull`, `plan.md` is on the main branch: the issue is done. Its folder stays.
53
+
54
+ A failed run stops; past `prepare`, it leaves the repository on the branch `<slug>`, with the agent's changes, for inspection. Clean up, fix what is needed (often the spec, committed and pushed again) and start a new run: it starts again from the main branch, recreates the branch and replaces the pull request's content. Requested changes on a pull request are fixed the same way, or by hand on the branch. An issue is abandoned by deleting its folder (and closing its pull request, if any).
55
+
56
+ `issue-save` lists every problem of a draft at once, refuses a spec for an issue that has no `issue.md`, replaces the file if it exists and commits nothing; each save is a run. The skill tells the agent never to write in `.factory/issues/` directly, commit or run `implement`. Pi reads a project's skills once the project is trusted; Codex ignores a `SKILL.md` that is itself a link, hence the folder link.
57
+
58
+ ### Issues
59
+
60
+ An issue is a folder `.factory/issues/<slug>/` holding at least one of the files below (any other folder there is ignored), identified by its slug alone: lowercase letters and digits in words separated by hyphens, which also names its branch and its `--issue` input.
61
+
62
+ - `issue.md`: a `# ` title, then a description.
63
+ - `spec.md`: a `# ` title, then exactly `## Objective`, `## Scope`, `## Out of scope`, `## Acceptance criteria` and `## Constraints`, in this order, with nothing before the first and none empty (`None.`). Acceptance criteria holds only `- AC<n>: <criterion>` items numbered from AC1 without gaps; an indented line continues an item. The spec says what and why, not how; headings stay in English, the content may be in any language. `issue-save` and `implement` read it the same way.
64
+ - `plan.md`: written by the run, in English: the approach, steps that each name the criteria they serve, their files and tests, and the risks.
65
+
66
+ ### The `implement` run
67
+
68
+ | Stage | What it does |
69
+ |---|---|
70
+ | `prepare` | Refuses to start, listing every reason, unless the repository is on the main branch without any change in progress, the main branch matches `origin` after `git fetch`, `spec.md` is valid, the issue has no `plan.md` (an issue already delivered is never restarted), its slug does not name the main branch (its branch would replace it) and `gh` is logged in; then the repository's checks must pass on the main branch, before any agent; then, under a lock of the working tree (`factory-implement.lock` in its Git directory, held for that step only) and unless the repository moved meanwhile (another run is using it: the run stops), creates (or recreates) the branch `<slug>` from the approved start commit. Branches are read and pushed by their full reference: a tag of the same name never stands in for them |
71
+ | `plan`, `planned` | The `plan` agent receives the slug and the spec and answers with a plan; every criterion must be served by a step, otherwise the plan goes back to it (2 times at most) |
72
+ | `commit-plan` | Writes `plan.md` and commits it alone (`docs: plan <slug>`): the run's reference commit |
73
+ | `implement`, `implemented` | The `implement` agent receives the spec and the plan, in one conversation for the run, and answers with evidence for each criterion and its deviations from the plan; the run stops if it committed, switched branches or changed `.factory/`, whatever it answered |
74
+ | `verify` | The repository's checks, in order; a failure, a timeout or a command that cannot start goes back to `implement` with the command, the cause and the end of its output (3 times at most) |
75
+ | `diff` | Every change since the reference commit, new files included; the run stops if it is over 2 MiB |
76
+ | `review`, `reviewed` | The `review` agent, in a new conversation for each review, receives the spec, the changes and the checks, never the implementing agent's answer, and judges each criterion `met` or `not_met`, with `blocking` or `minor` findings; an unmet criterion or a blocking finding goes back to `implement` (2 times at most) |
77
+ | `deliver` | Commits the changes with the plan's conventional commit subject, force-pushes `<slug>` to `origin`, updates the branch's open pull request or opens one with `gh`, then returns to the main branch |
78
+
79
+ A malformed agent response goes back to that agent, 2 times at most. The pull request's title is the commit subject; its body gives the summary, each criterion with its review status and evidence, the checks, the review's rounds and minor findings, the deviations from the plan, then the spec at its starting commit, `plan.md` and the run's ID. The run's result shows the pull request, the review rounds and the checks passed.
80
+
81
+ ### Kanban
82
+
83
+ `factory ui` shows the repository's issues in six columns. No status is stored: each column follows from facts.
84
+
85
+ | Column | Fact |
86
+ |---|---|
87
+ | Backlog | `issue.md` only |
88
+ | Specifying | `spec.md`, and no `implement` run yet |
89
+ | Executing | the last `implement` run is running |
90
+ | Blocked | the last `implement` run failed |
91
+ | To Approve | the last `implement` run completed, and `plan.md` is not on the main branch |
92
+ | Done | `plan.md` is on the main branch |
93
+
94
+ The files are read in the working tree, the main branch is the local branch `origin/HEAD` names, and runs are those of `.factory/runs/`. A card shows the issue's title (the `# ` line of `issue.md`; its slug without one), its slug, the newest pull request its `implement` runs recorded (a new run updates the same one) and, for each workflow shown on cards, its last run on the issue: its steps (done, current, failed or to come), its duration and its estimated cost. `implement` shows six steps: prepare, plan, implement, verify, review and deliver. The title opens the newest of these runs in the runs dashboard. The most recently active issue comes first in its column; the page refreshes every 2 seconds. What may leave the board incomplete is listed above it: a `factory.ts` that does not load (`factory ui` loads it when it starts: restart it once fixed), an unreadable `issue.md` or run, or a main branch Git cannot read (`origin/HEAD` missing: `git remote set-head origin --auto` sets it).
95
+
96
+ ## Adapt the factory
97
+
98
+ `.factory/factory.ts` exports the repository's factory; `factory init` writes one like this (comments aside), whose check is an example to replace:
99
+
100
+ ```ts
101
+ import { type AgentProfile, defineFactory } from "@clemrig/factory";
102
+ import ask from "./workflows/ask/index.ts";
103
+
104
+ const minutes = 60_000;
105
+ const opus = { runtime: "claude-code", model: "claude-opus-5-5", thinking: "high" } as const;
106
+ const reader = { ...opus, tools: ["Read", "Grep", "Glob"], timeoutMs: 20 * minutes } satisfies AgentProfile;
107
+
108
+ export default defineFactory({
109
+ verify: [{ name: "test", command: ["npm", "test"], timeoutMs: 10 * minutes }],
110
+ maxCostUsd: 25,
111
+ profiles: {
112
+ plan: reader,
113
+ implement: {
114
+ ...opus,
115
+ tools: ["Read", "Grep", "Glob", "Edit", "Write", "Bash"],
116
+ permissionMode: "dontAsk",
117
+ timeoutMs: 60 * minutes,
118
+ },
119
+ review: reader,
120
+ },
121
+ workflows: [ask],
122
+ });
123
+ ```
124
+
125
+ - `verify`: the repository's checks, at least one: `{ name, command, timeoutMs }`, the command an executable and its arguments, run without a shell in the repository. They run in order and stop at the first failure: on the main branch before the run's agents, then after each implementation.
126
+ - `maxCostUsd`: the budget of an `implement` run, in USD; `factory run implement --issue <slug> --max-cost-usd 40` changes it for one run. Codex announces no cost, so these three agents cannot run with Codex.
127
+ - `profiles`: the agents of `plan`, `implement` and `review` (see Profiles below). Each profile decides what its agent may do: here, `plan` and `review` only read the repository; `implement` also edits it and runs commands, and `permissionMode: "dontAsk"` refuses any other tool instead of waiting for a permission prompt.
128
+ - `workflows` (optional): the repository's own workflows.
129
+
130
+ `defineFactory` lists every problem at once, each agent's profile checked on its own even when other fields are wrong; it also refuses a workflow not made by `defineWorkflow`, or named like another, `issue-save` and `implement` included. Any other default export of `factory.ts` is refused.
131
+
132
+ The rest is the factory's, the same in every repository: the issue folders and their formats, `issue-save`, the `implement` run (its starting conditions, stages, correction maximums, diff limit, branch and pull request), its prompts, shipped with the package, the Kanban and its columns. None of these can be changed by a repository yet. The `issue` skill is copied once by `factory init`: a later factory version does not update it.
44
133
 
45
134
  ## Write a workflow
46
135
 
@@ -112,13 +201,7 @@ export default defineWorkflow({
112
201
  });
113
202
  ```
114
203
 
115
- ```ts
116
- // .factory/factory.ts
117
- import ask from "./workflows/ask/index.ts";
118
- import changelog from "./workflows/changelog/index.ts";
119
-
120
- export default [ask, changelog];
121
- ```
204
+ Add it to `workflows` in `.factory/factory.ts` (`workflows: [ask, changelog]`), then run it with `factory run changelog --since 2026-10-01`. The example workflow `ask` reads the last 10 commits with `git log` (a CODE stage), asks a Claude Code agent whose built-in tools are limited to `Read`, `Grep` and `Glob` (`claude-sonnet-5-5`, effort `low`; this machine's MCP servers, plugins and hooks still load) to answer the question, and checks the answer with a gate that sends it back at most 3 times: `factory run ask --question "What changed recently?"`. Copy its folder to start a new workflow.
122
205
 
123
206
  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.
124
207
 
@@ -133,10 +216,12 @@ Workflows are TypeScript run directly by Node: use erasable syntax only (no `enu
133
216
  | `pick(...keys)` | agent context from `input` and data keys |
134
217
  | `runProcess(argv, cwd, timeoutMs)` | runs a command without a shell; Ctrl-C stops it |
135
218
 
136
- `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 prompt or session name that cannot name a file, a `maxCostUsd` that is not a positive number or that a Codex stage could not check, 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.
219
+ `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 prompt or session name that cannot name a file, a `maxCostUsd` that is not a positive number or that a Codex stage could not check, `steps` that do not name each step once and hold each stage exactly once, 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.
137
220
 
138
221
  **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.
139
222
 
223
+ **On the issue cards.** A workflow whose `input` has an `issue` field and that declares `steps` is shown on the cards: each issue's card shows its last run whose `issue` input is the issue's slug. `steps` are ordered, named groups of the workflow's stages, for `changelog` above `steps: [{ name: "read", stages: ["log"] }, { name: "write", stages: ["write", "check"] }]`; a correction that goes back to an earlier stage brings the current step back. Such a workflow never changes an issue's column. `issue-save` declares no steps and is not shown.
224
+
140
225
  **Budget.** `maxCostUsd` (optional) fails a run once the cost its agents' runtimes announced exceeds it; `factory run … --max-cost-usd 2` sets it for one run, instead of the workflow's. It is checked before and after each agent call, failed or not, on the runtime's figures: a running call is not stopped and can go past it; once it is exceeded, no further call starts and the run fails at its next stage boundary, even if workflow code catches the error. A call that announced no cost fails a run that has a budget, since the budget can no longer be checked; Codex announces tokens only, so a budget is refused, before any run, for a workflow with a Codex stage. With a subscription, the cost is an estimate.
141
226
 
142
227
  **Profiles.** Each agent stage declares its profile; no machine setting of the factory changes it. A profile is a plain object: share one between stages with a constant, typed with `satisfies AgentProfile` (`AgentProfile` is exported by `@clemrig/factory`).
@@ -152,14 +237,14 @@ Workflows are TypeScript run directly by Node: use erasable syntax only (no `enu
152
237
 
153
238
  Each agent runs with this machine's and this repository's configuration, as you would run it yourself: Claude Code with its settings, `CLAUDE.md`, plugins, hooks, skills, MCP servers and memory; Codex with its `config.toml`, `AGENTS.md` files, skills and MCP servers; Pi with its extensions, skills, context files and MCP servers. The profile only adds its settings; without `tools`, `permissionMode` or `sandbox`, the agent's own configuration decides. The same workflow can therefore behave differently on another machine, and a repository's own hooks and MCP servers run with its agents. Relative skill, extension and MCP command paths are relative to `.factory/`; a bare command is looked up in the `PATH`. Runtimes are not sandboxes unless one is enabled: their tools act with your rights.
154
239
 
155
- **Prompts.** An agent's prompt is `.factory/workflows/<workflow>/prompts/<name>.md`, where the name is the stage's unless `agent({ prompt })` names another. It is appended to the runtime's system prompt (Codex receives it as the session's `developer_instructions`); the request (context and output JSON Schema) follows on standard input. Prompts are read when a run starts: an edit applies to the next run, without building anything.
240
+ **Prompts.** An agent's prompt is `.factory/workflows/<workflow>/prompts/<name>.md`, where the name is the stage's unless `agent({ prompt })` names another; the factory's own workflows read theirs from the package. It is appended to the runtime's system prompt (Codex receives it as the session's `developer_instructions`); the request (context and output JSON Schema) follows on standard input. Prompts are read when a run starts: an edit applies to the next run, without building anything.
156
241
 
157
242
  **Sessions.** An agent stage keeps one conversation per run: a correction sent back to it resumes the conversation, with the gate's feedback. `session: "name"` shares a conversation between stages of the same runtime (sharing one across runtimes is refused); `session: (state) => name` opens one per value. A run's stage and session names form one namespace per runtime: a name returned by a function joins the conversation of that name on the same runtime. Session names start and end with a letter or digit.
158
243
 
159
244
  ## Run and observe
160
245
 
161
246
  ```sh
162
- factory run changelog --since 2026-10-01 [--json]
247
+ factory run WORKFLOW [--INPUT VALUE…] [--max-cost-usd USD] [--json]
163
248
  factory status [RUN_ID] [--json]
164
249
  factory ui [--port 4321]
165
250
  factory doctor [--json]
@@ -167,21 +252,26 @@ factory doctor [--json]
167
252
 
168
253
  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
254
 
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 of its call with its model, thinking, runtime choices and tools, its end, each finished tool with its duration and the runtime's 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.
255
+ The run executes in the foreground. The terminal shows each stage's start and end, decisions and corrections with their counter (`[verify.failed 1/3]`), journal messages and, for an agent, the start of its call with its model, thinking, runtime choices and tools, its end, each finished tool with its duration and the runtime's 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
256
 
172
257
  **Ctrl-C** stops the run's child processes and ends the run as `failed` with its cause before its next stage, or instead of completing; a second Ctrl-C kills the remaining child processes and quits at once (exit code 130, the run may then stay `running`); commands that Codex runs in their own process groups are stopped by Codex on the first Ctrl-C, not by the second. A failed or interrupted run is not resumed: start a new one.
173
258
 
174
- `factory status` lists the repository's runs or shows one; while `factory.ts` cannot load, `status` and `ui` say so and still show the runs with the default rendering. `factory ui` serves a read-only dashboard of the repository's runs on `127.0.0.1` (port chosen by the system unless `--port` sets it, URL printed; Ctrl-C stops it): the runs with workflow, status, current stage, duration, estimated cost and last update, and for a run its runtimes, a timeline with one block per stage (status, duration, the agent call's model and settings, its tools and tokens as they come, journal, decision), the correction counters and the result. It follows a running run as it goes. To watch a run on another machine, forward the same port through SSH: `ssh -L 4321:127.0.0.1:4321 machine`, run `factory ui --port 4321` there, and open `http://localhost:4321/`. `factory doctor` checks Node, loads the workflows, reads their prompts, lists each workflow's options and checks each runtime's executable, version and connection, without any provider request.
259
+ `factory status` lists the repository's runs or shows one; while `factory.ts` cannot load, `status` and `ui` say so and still show the runs with the default rendering. `factory ui` serves on `127.0.0.1` (port chosen by the system unless `--port` sets it, URL printed; Ctrl-C stops it) the Kanban on `/` and, under `/runs/`, a read-only dashboard of the repository's runs: the runs with workflow, status, current stage, duration, estimated cost and last update, and for a run its runtimes, a timeline with one block per stage (status, duration, the agent call's model and settings, its tools and tokens as they come, journal, decision), the correction counters and the result. It follows a running run as it goes. To watch on another machine, forward the same port through SSH: `ssh -L 4321:127.0.0.1:4321 machine`, run `factory ui --port 4321` there, and open `http://localhost:4321/`. `factory doctor` checks Node, loads the workflows, reads their prompts, lists each workflow's options and checks each runtime's executable, version and connection, without any provider request.
175
260
 
176
261
  ## Data
177
262
 
178
- Each run keeps `state.json` and `events.jsonl` in `.factory/runs/<RUN_ID>/`, plus its Pi sessions and Claude Code and Codex session markers; Claude Code and Codex keep their transcripts in their own storage (`~/.claude/projects/…`, `~/.codex/sessions/…`). Runs hold inputs, agent outputs and the journal: they stay private and are ignored by Git. `.factory/.env` is loaded automatically, without overriding variables already set in the shell; runtimes, MCP servers and commands inherit the environment. `factory run` executes the code of `.factory/`: trust it as you trust `npm run`. The dashboard shows the same data to any local process that can reach `127.0.0.1`.
263
+ Issues live in `.factory/issues/` and are committed: their specs and plans are part of the repository's history. Each run keeps `state.json` and `events.jsonl` in `.factory/runs/<RUN_ID>/`, plus its Pi sessions and Claude Code and Codex session markers; Claude Code and Codex keep their transcripts in their own storage (`~/.claude/projects/…`, `~/.codex/sessions/…`). Runs hold inputs, agent outputs and the journal: they stay private and are ignored by Git. `.factory/.env` is loaded automatically, without overriding variables already set in the shell; runtimes, MCP servers and commands inherit the environment. `factory run` executes the code of `.factory/`: trust it as you trust `npm run`. The Kanban and the runs dashboard show the same data to any local process that can reach `127.0.0.1`.
179
264
 
180
265
  Tokens and costs are the figures each runtime announces: Claude Code announces at the end of a call its session's total, earlier calls included, and its tokens during a call are provisional; Codex announces at the end of each turn its thread's total tokens, earlier turns included, without a cost (its input includes the cached tokens, which flow takes out so that input counts the same tokens for every runtime); Pi announces each response with its cost. A run's total is the sum of its sessions, with the cost they announced: a call without a cost makes the cost partial, unknown while no call announced one. The estimated cost is the runtime's public-price estimate, not a bill.
181
266
 
182
267
  ## Limits
183
268
 
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.
269
+ - No release or observation stage: an issue is done once merged. Requested changes on a pull request are not handled by a run.
270
+ - Runs are local: Executing and Blocked show only on the machine of the run; Done shows after `git pull`. A refusal at `prepare` is a failed run, so the issue looks Blocked until its next run; after a second Ctrl-C a run may stay `running`, and its issue looks Executing until its next run.
271
+ - The repository is used in place: one `implement` run at a time, since it needs a clean tree and stops if another run moved the repository during its starting checks; after a failure, the operator cleans up. The repository's Git hooks run on the run's commits, and a failing hook fails the run.
272
+ - The factory's own agents (`plan`, `implement`, `review`) cannot run on Codex, since `maxCostUsd` is required and Codex announces no cost; the repository's own workflows and the `issue` skill can use Codex.
273
+ - Runtimes are not sandboxes: the implementing agent's tools can run any command its profile allows, bounded only by its prompt, the repository's agent instructions and the run's checks.
274
+ - Not in this version: changing the factory's prompts, correction maximums, pull request format or columns from a repository; columns added by a workflow; backlog priority; actions or drag-and-drop on the board; resuming a run, detached runs, logs `--follow` and stop; local settings or profile overrides; graph drawing in the dashboard; runs or issues of several repositories; `factory new`; a shared stage library; a test harness for workflows; CI, cron or Git hook triggers; notifications; Windows.
185
275
 
186
276
  ## License
187
277
 
@@ -0,0 +1,7 @@
1
+ import { type IssueBoard } from "../domain/board.js";
2
+ import type { Factory } from "../system/factory.js";
3
+ /**
4
+ * The Kanban as the repository is now: its issues, the main branch and its
5
+ * runs. What cannot be read is listed with the board, never hidden.
6
+ */
7
+ export declare function readBoard(factory: Factory, loadError?: string): Promise<IssueBoard>;
@@ -0,0 +1,47 @@
1
+ import { boardOf, } from "../domain/board.js";
2
+ import { issueTitle } from "../domain/issue.js";
3
+ import { branchRef, defaultBranch, filesIn } from "../system/git.js";
4
+ import { artifactPath, issuesPath, listIssueFolders, } from "../system/issues.js";
5
+ import { listRuns } from "./runs.js";
6
+ const message = (error) => error instanceof Error ? error.message : String(error);
7
+ /** The workflows that take an issue (`--issue`) and declare their steps. */
8
+ function shownWorkflows(factory) {
9
+ return [...factory.workflows.values()].flatMap(({ name, input, steps }) => steps && input?.shape.issue ? [{ name, steps }] : []);
10
+ }
11
+ /**
12
+ * The Kanban as the repository is now: its issues, the main branch and its
13
+ * runs. What cannot be read is listed with the board, never hidden.
14
+ */
15
+ export async function readBoard(factory, loadError) {
16
+ const problems = loadError
17
+ ? [`factory.ts cannot load (restart factory ui once fixed): ${loadError}`]
18
+ : [];
19
+ let delivered = new Set();
20
+ try {
21
+ const base = await defaultBranch(factory.dir);
22
+ delivered = new Set(await filesIn(factory.dir, branchRef(base), issuesPath));
23
+ }
24
+ catch (error) {
25
+ // A remote added by hand has no origin/HEAD until git sets it.
26
+ problems.push(`Done issues cannot be told apart (the main branch is origin/HEAD; git remote set-head origin --auto sets it): ${message(error)}`);
27
+ }
28
+ const runs = [];
29
+ for (const entry of await listRuns(factory))
30
+ if ("state" in entry)
31
+ runs.push(entry.state);
32
+ else
33
+ problems.push(`Run ${entry.id} cannot be read: ${entry.error}`);
34
+ const issues = (await listIssueFolders(factory.dir)).map((folder) => {
35
+ if (folder.unreadable !== undefined)
36
+ problems.push(`Issue ${folder.slug}: issue.md cannot be read: ${folder.unreadable}`);
37
+ return {
38
+ slug: folder.slug,
39
+ title: (folder.issue && issueTitle(folder.issue)) || folder.slug,
40
+ hasSpec: folder.hasSpec,
41
+ delivered: delivered.has(artifactPath(folder.slug, "plan")),
42
+ changedAt: folder.changedAt,
43
+ };
44
+ });
45
+ return boardOf(issues, runs, shownWorkflows(factory), problems);
46
+ }
47
+ //# sourceMappingURL=board.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"board.js","sourceRoot":"","sources":["../../src/app/board.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,27 @@
1
+ import { type Workflow } from "@clemrig/flow";
2
+ import { type FactoryDefinition } from "../domain/definition.js";
3
+ declare const opaque: unique symbol;
4
+ /**
5
+ * A repository's factory, as `defineFactory` validated it. Opaque: only the
6
+ * factory reads it, so that its content can change without breaking a
7
+ * repository.
8
+ */
9
+ export interface DefinedFactory {
10
+ readonly [opaque]: true;
11
+ }
12
+ /** What a defined factory holds. */
13
+ export interface FactoryWorkflows {
14
+ /** The factory's workflows, adapted to the repository; their prompts come with the package. */
15
+ base: Workflow[];
16
+ /** The repository's own workflows. */
17
+ own: Workflow[];
18
+ }
19
+ /** The workflows of a factory returned by `defineFactory`; nothing for any other value. */
20
+ export declare function workflowsOf(value: unknown): FactoryWorkflows | undefined;
21
+ /**
22
+ * A repository's factory: its workflows (`issue-save`, `implement`) adapted to
23
+ * the repository's checks, budget and agents, then its own workflows. Every
24
+ * problem is listed at once.
25
+ */
26
+ export declare function defineFactory(definition: FactoryDefinition): DefinedFactory;
27
+ export {};
@@ -0,0 +1,68 @@
1
+ import { isWorkflow, profileProblems } from "@clemrig/flow";
2
+ import { definitionProblems, } from "../domain/definition.js";
3
+ import { DELIVERY } from "../domain/delivery.js";
4
+ import { implement } from "./workflows/implement.js";
5
+ import { issueSave } from "./workflows/issue-save.js";
6
+ const defined = new WeakMap();
7
+ /** The workflows of a factory returned by `defineFactory`; nothing for any other value. */
8
+ export function workflowsOf(value) {
9
+ return typeof value === "object" && value !== null
10
+ ? defined.get(value)
11
+ : undefined;
12
+ }
13
+ /**
14
+ * A repository's factory: its workflows (`issue-save`, `implement`) adapted to
15
+ * the repository's checks, budget and agents, then its own workflows. Every
16
+ * problem is listed at once.
17
+ */
18
+ export function defineFactory(definition) {
19
+ const problems = definitionProblems(definition);
20
+ const flagged = (field) => problems.some((problem) => problem.startsWith(`${field}:`) || problem.startsWith(`${field}.`));
21
+ // factory.ts is not type-checked: the definition may be anything.
22
+ const given = typeof definition === "object" && definition !== null ? definition : {};
23
+ const own = Array.isArray(given.workflows) ? given.workflows : [];
24
+ const names = new Set([issueSave.name, DELIVERY]);
25
+ for (const [index, workflow] of own.entries())
26
+ if (!isWorkflow(workflow))
27
+ problems.push(`workflows.${index}: expected a defineWorkflow(…) result`);
28
+ else if (names.has(workflow.name))
29
+ problems.push(`workflows.${index}: a workflow is already named ${workflow.name}`);
30
+ else
31
+ names.add(workflow.name);
32
+ // Each agent's profile is checked on its own, whatever else is wrong, so
33
+ // that every problem shows at once.
34
+ const profiles = typeof given.profiles === "object" && given.profiles !== null
35
+ ? given.profiles
36
+ : {};
37
+ for (const role of ["plan", "implement", "review"]) {
38
+ const profile = profiles[role];
39
+ // A profile that is not an object is already reported by the definition.
40
+ if (typeof profile === "object" && profile !== null)
41
+ for (const { path, message } of profileProblems(profile))
42
+ problems.push(`profiles.${role}.${path}: ${message}`);
43
+ }
44
+ let base = [];
45
+ // Valid profiles make the workflow, which may still refuse their combination
46
+ // (a budget with an agent that announces no cost).
47
+ if (given.profiles && !flagged("profiles"))
48
+ try {
49
+ base = [
50
+ issueSave,
51
+ implement({
52
+ verify: given.verify ?? [],
53
+ profiles: given.profiles,
54
+ // A refused budget is already listed; the workflow does not repeat it.
55
+ maxCostUsd: flagged("maxCostUsd") ? undefined : given.maxCostUsd,
56
+ }),
57
+ ];
58
+ }
59
+ catch (error) {
60
+ problems.push(error instanceof Error ? error.message : String(error));
61
+ }
62
+ if (problems.length)
63
+ throw new Error(["Invalid factory:", ...problems.map((problem) => `- ${problem}`)].join("\n"));
64
+ const factory = Object.freeze({});
65
+ defined.set(factory, { base, own });
66
+ return factory;
67
+ }
68
+ //# sourceMappingURL=define.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"define.js","sourceRoot":"","sources":["../../src/app/define.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,eAAe,EAAiB,MAAM,eAAe,CAAC;AAC3E,OAAO,EACL,kBAAkB,GAEnB,MAAM,yBAAyB,CAAC;AACjC,OAAO,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AACjD,OAAO,EAAE,SAAS,EAAE,MAAM,0BAA0B,CAAC;AACrD,OAAO,EAAE,SAAS,EAAE,MAAM,2BAA2B,CAAC;AAqBtD,MAAM,OAAO,GAAG,IAAI,OAAO,EAA4B,CAAC;AAExD,2FAA2F;AAC3F,MAAM,UAAU,WAAW,CAAC,KAAc;IACxC,OAAO,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI;QAChD,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC;QACpB,CAAC,CAAC,SAAS,CAAC;AAChB,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,aAAa,CAAC,UAA6B;IACzD,MAAM,QAAQ,GAAG,kBAAkB,CAAC,UAAU,CAAC,CAAC;IAChD,MAAM,OAAO,GAAG,CAAC,KAAa,EAAE,EAAE,CAChC,QAAQ,CAAC,IAAI,CACX,CAAC,OAAO,EAAE,EAAE,CACV,OAAO,CAAC,UAAU,CAAC,GAAG,KAAK,GAAG,CAAC,IAAI,OAAO,CAAC,UAAU,CAAC,GAAG,KAAK,GAAG,CAAC,CACrE,CAAC;IACJ,kEAAkE;IAClE,MAAM,KAAK,GACT,OAAO,UAAU,KAAK,QAAQ,IAAI,UAAU,KAAK,IAAI,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE,CAAC;IAC1E,MAAM,GAAG,GAAG,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC;IAClE,MAAM,KAAK,GAAG,IAAI,GAAG,CAAC,CAAC,SAAS,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC,CAAC;IAClD,KAAK,MAAM,CAAC,KAAK,EAAE,QAAQ,CAAC,IAAI,GAAG,CAAC,OAAO,EAAE;QAC3C,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC;YACvB,QAAQ,CAAC,IAAI,CAAC,aAAa,KAAK,uCAAuC,CAAC,CAAC;aACtE,IAAI,KAAK,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI,CAAC;YAC/B,QAAQ,CAAC,IAAI,CACX,aAAa,KAAK,iCAAiC,QAAQ,CAAC,IAAI,EAAE,CACnE,CAAC;;YACC,KAAK,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;IAChC,yEAAyE;IACzE,oCAAoC;IACpC,MAAM,QAAQ,GACZ,OAAO,KAAK,CAAC,QAAQ,KAAK,QAAQ,IAAI,KAAK,CAAC,QAAQ,KAAK,IAAI;QAC3D,CAAC,CAAC,KAAK,CAAC,QAAQ;QAChB,CAAC,CAAC,EAAE,CAAC;IACT,KAAK,MAAM,IAAI,IAAI,CAAC,MAAM,EAAE,WAAW,EAAE,QAAQ,CAAC,EAAE,CAAC;QACnD,MAAM,OAAO,GAAG,QAAQ,CAAC,IAAI,CAAC,CAAC;QAC/B,yEAAyE;QACzE,IAAI,OAAO,OAAO,KAAK,QAAQ,IAAI,OAAO,KAAK,IAAI;YACjD,KAAK,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,eAAe,CAAC,OAAO,CAAC;gBACtD,QAAQ,CAAC,IAAI,CAAC,YAAY,IAAI,IAAI,IAAI,KAAK,OAAO,EAAE,CAAC,CAAC;IAC5D,CAAC;IACD,IAAI,IAAI,GAAe,EAAE,CAAC;IAC1B,6EAA6E;IAC7E,mDAAmD;IACnD,IAAI,KAAK,CAAC,QAAQ,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC;QACxC,IAAI,CAAC;YACH,IAAI,GAAG;gBACL,SAAS;gBACT,SAAS,CAAC;oBACR,MAAM,EAAE,KAAK,CAAC,MAAM,IAAI,EAAE;oBAC1B,QAAQ,EAAE,KAAK,CAAC,QAAQ;oBACxB,uEAAuE;oBACvE,UAAU,EAAE,OAAO,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,UAAU;iBACjE,CAAC;aACH,CAAC;QACJ,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,QAAQ,CAAC,IAAI,CAAC,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC;QACxE,CAAC;IACH,IAAI,QAAQ,CAAC,MAAM;QACjB,MAAM,IAAI,KAAK,CACb,CAAC,kBAAkB,EAAE,GAAG,QAAQ,CAAC,GAAG,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,KAAK,OAAO,EAAE,CAAC,CAAC,CAAC,IAAI,CACrE,IAAI,CACL,CACF,CAAC;IACJ,MAAM,OAAO,GAAG,MAAM,CAAC,MAAM,CAAC,EAAE,CAAmB,CAAC;IACpD,OAAO,CAAC,GAAG,CAAC,OAAO,EAAE,EAAE,IAAI,EAAE,GAAG,EAAE,CAAC,CAAC;IACpC,OAAO,OAAO,CAAC;AACjB,CAAC"}
@@ -7,7 +7,8 @@ const message = (error) => error instanceof Error ? error.message : String(error
7
7
  export async function diagnose(factoryDir) {
8
8
  loadLocalEnvironment(factoryDir);
9
9
  const node = inspectNode();
10
- let factory;
10
+ // Without a loadable factory.ts, no workflow to check.
11
+ let factory = emptyFactory(factoryDir);
11
12
  let loaded;
12
13
  try {
13
14
  factory = await loadWorkflows(factoryDir);
@@ -18,9 +19,9 @@ export async function diagnose(factoryDir) {
18
19
  }
19
20
  const workflows = [];
20
21
  const agents = {};
21
- for (const workflow of factory?.workflows.values() ?? []) {
22
+ for (const workflow of factory.workflows.values()) {
22
23
  try {
23
- await loadPrompts(factoryDir, workflow);
24
+ await loadPrompts(factory, workflow);
24
25
  workflows.push({ workflow });
25
26
  }
26
27
  catch (error) {
@@ -30,7 +31,7 @@ export async function diagnose(factoryDir) {
30
31
  agents[`${workflow.name}.${stage}`] = declared;
31
32
  }
32
33
  // Where the agents will work: the repository.
33
- const { runtimes, problems } = await inspectRuntimes(agents, factory?.dir ?? emptyFactory(factoryDir).dir);
34
+ const { runtimes, problems } = await inspectRuntimes(agents, factory.dir);
34
35
  const ok = node.ok &&
35
36
  loaded.ok &&
36
37
  workflows.every(({ error }) => error === undefined) &&
@@ -1 +1 @@
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"}
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,uDAAuD;IACvD,IAAI,OAAO,GAAY,YAAY,CAAC,UAAU,CAAC,CAAC;IAChD,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,CAAC,SAAS,CAAC,MAAM,EAAE,EAAE,CAAC;QAClD,IAAI,CAAC;YACH,MAAM,WAAW,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC;YACrC,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,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,CAAC,CAAC;IAC1E,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"}
@@ -1,10 +1,18 @@
1
1
  import { loadLocalEnvironment } from "../system/environment.js";
2
- import { emptyFactory, loadFactory } from "../system/factory.js";
2
+ import { emptyFactory, importFactory, } from "../system/factory.js";
3
+ import { workflowsOf } from "./define.js";
3
4
  import { optionProblems } from "./options.js";
4
5
  const message = (error) => error instanceof Error ? error.message : String(error);
5
6
  /** The repository's workflows, each of whose inputs can be given as options of `factory run`. */
6
7
  export async function loadWorkflows(factoryDir) {
7
- const factory = await loadFactory(factoryDir);
8
+ const exported = workflowsOf(await importFactory(factoryDir));
9
+ if (!exported)
10
+ throw new Error("factory.ts must export default defineFactory(…)");
11
+ const factory = emptyFactory(factoryDir);
12
+ for (const workflow of [...exported.base, ...exported.own])
13
+ factory.workflows.set(workflow.name, workflow);
14
+ for (const workflow of exported.base)
15
+ factory.packaged.add(workflow.name);
8
16
  for (const workflow of factory.workflows.values()) {
9
17
  const problems = optionProblems(workflow);
10
18
  if (problems.length)
@@ -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;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"}
1
+ {"version":3,"file":"factory.js","sourceRoot":"","sources":["../../src/app/factory.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,oBAAoB,EAAE,MAAM,0BAA0B,CAAC;AAChE,OAAO,EACL,YAAY,EAEZ,aAAa,GACd,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAC1C,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,QAAQ,GAAG,WAAW,CAAC,MAAM,aAAa,CAAC,UAAU,CAAC,CAAC,CAAC;IAC9D,IAAI,CAAC,QAAQ;QACX,MAAM,IAAI,KAAK,CAAC,iDAAiD,CAAC,CAAC;IACrE,MAAM,OAAO,GAAG,YAAY,CAAC,UAAU,CAAC,CAAC;IACzC,KAAK,MAAM,QAAQ,IAAI,CAAC,GAAG,QAAQ,CAAC,IAAI,EAAE,GAAG,QAAQ,CAAC,GAAG,CAAC;QACxD,OAAO,CAAC,SAAS,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC;IACjD,KAAK,MAAM,QAAQ,IAAI,QAAQ,CAAC,IAAI;QAAE,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;IAC1E,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/run.js CHANGED
@@ -16,7 +16,7 @@ export async function startRun(factory, name, options, hooks) {
16
16
  workflow,
17
17
  input,
18
18
  maxCostUsd,
19
- prompts: () => loadPrompts(factory.factoryDir, workflow),
19
+ prompts: () => loadPrompts(factory, workflow),
20
20
  dir: factory.dir,
21
21
  configDir: factory.factoryDir,
22
22
  runsDir: factory.runsDir,
@@ -1 +1 @@
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"}
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,EAAE,QAAQ,CAAC;YAC7C,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"}
@@ -0,0 +1,8 @@
1
+ import type { FactoryDefinition } from "../../domain/definition.js";
2
+ /** What the workflow uses: the factory requires the budget, the workflow also runs without one. */
3
+ type Settings = Pick<FactoryDefinition, "verify" | "profiles"> & {
4
+ maxCostUsd?: number;
5
+ };
6
+ /** Plans, implements, checks and reviews an approved spec, then opens its pull request. */
7
+ export declare function implement(definition: Settings): import("@clemrig/flow").Workflow;
8
+ export {};