@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
@@ -0,0 +1,268 @@
1
+ import { agent, code, defineWorkflow, END, gate, node, retry, schemaGate, step, z, } from "@clemrig/flow";
2
+ import { isSlug } from "../../domain/issue.js";
3
+ import { planCommitMessage, planOutput, planProblem, renderPlan, } from "../../domain/plan.js";
4
+ import { DELIVERY } from "../../domain/delivery.js";
5
+ import { pullRequestBody } from "../../domain/pull-request.js";
6
+ import { implementationOutput, implementationProblem, reviewChanges, reviewOutput, reviewProblem, } from "../../domain/review.js";
7
+ import { parseSpec } from "../../domain/spec.js";
8
+ import { failureFeedback, seconds, } from "../../domain/verification.js";
9
+ import { runChecks } from "../../system/checks.js";
10
+ import * as git from "../../system/git.js";
11
+ import * as github from "../../system/github.js";
12
+ import { withTreeLock } from "../../system/lock.js";
13
+ import { artifactPath, hasArtifact, readArtifact, writeArtifact, } from "../../system/issues.js";
14
+ function facts(state) {
15
+ return state.data;
16
+ }
17
+ /** Corrections the review asked for so far. */
18
+ function reviewRounds(state) {
19
+ return state.retries?.["reviewed.changes"] ?? 0;
20
+ }
21
+ function short(commit) {
22
+ return commit.slice(0, 7);
23
+ }
24
+ /** Journals each check as it starts and passes: they can take minutes. */
25
+ function journalChecks(log, where = "") {
26
+ return ({ check, ...event }) => log(event.status === "started"
27
+ ? `Running ${check.name}${where}: ${check.command.join(" ")}`
28
+ : `${check.name} passed in ${seconds(event.durationMs)}`);
29
+ }
30
+ /** Every reason not to start, found without changing anything; then the base must pass its checks. */
31
+ async function prepare(definition, { dir, state, log }) {
32
+ const slug = String(state.input.issue);
33
+ const base = await git.defaultBranch(dir);
34
+ const problems = [];
35
+ // The run commits and force-pushes on the branch the slug names.
36
+ if (slug === base)
37
+ problems.push(`Issue ${slug} names the main branch: its branch would replace ${base}; rename the issue`);
38
+ if ((await git.currentBranch(dir)) !== base)
39
+ problems.push(`Switch to ${base} first`);
40
+ if (await git.hasChanges(dir))
41
+ problems.push("Commit or discard the changes in progress first");
42
+ await git.fetchBranch(dir, base);
43
+ if ((await git.commitOf(dir, "HEAD")) !==
44
+ (await git.commitOf(dir, git.remoteRef(base))))
45
+ problems.push(`${base} must match origin/${base}: push or pull first`);
46
+ const text = await readArtifact(dir, slug, "spec");
47
+ const spec = text === undefined ? undefined : parseSpec(text);
48
+ if (!spec)
49
+ problems.push(`Issue ${slug} has no spec.md`);
50
+ else if (!spec.ok)
51
+ problems.push(...spec.problems.map((problem) => `spec.md: ${problem}`));
52
+ if (await hasArtifact(dir, slug, "plan"))
53
+ problems.push(`Issue ${slug} is already delivered (its plan.md is on ${base}): start a new issue`);
54
+ if (!(await github.isAuthenticated(dir)))
55
+ problems.push("gh is not logged in: run gh auth login");
56
+ if (problems.length > 0 || !spec?.ok || text === undefined)
57
+ throw new Error(["Cannot start:", ...problems.map((problem) => `- ${problem}`)].join("\n"));
58
+ log(`Starting point valid: ${base} matches origin, spec with ${spec.value.criteria.length} criteria, gh logged in`);
59
+ const baseCommit = await git.commitOf(dir, "HEAD");
60
+ const checks = await runChecks(dir, definition.verify, journalChecks(log, ` on ${base}`));
61
+ if (!checks.ok)
62
+ throw new Error(`${base} does not pass its own checks:\n${failureFeedback(checks.check, checks.cause, checks.output)}`);
63
+ // One run at a time per working tree: another one started during the checks
64
+ // may have moved it. Checking and taking the tree happen under one lock, so
65
+ // that two runs never both find it free; the branch starts from the approved
66
+ // commit, never from theirs.
67
+ await withTreeLock(dir, async () => {
68
+ const branch = await git.currentBranch(dir);
69
+ const head = await git.commitOf(dir, "HEAD");
70
+ if (branch !== base || head !== baseCommit)
71
+ throw new Error(`The repository moved while ${base}'s checks ran (now ${branch || "detached"} at ${short(head)}): another run is using it; start again once it is done`);
72
+ await git.switchTo(dir, slug, baseCommit);
73
+ });
74
+ log(`Created branch ${slug} from ${base} at ${short(baseCommit)}`);
75
+ return {
76
+ slug,
77
+ title: spec.value.title,
78
+ spec: text,
79
+ criteria: spec.value.criteria,
80
+ base,
81
+ baseCommit,
82
+ specPath: artifactPath(slug, "spec"),
83
+ planPath: artifactPath(slug, "plan"),
84
+ };
85
+ }
86
+ /** The implementing agent may not commit, switch branches or touch .factory/: the run stops if it did. */
87
+ async function guard({ dir, state }) {
88
+ const { slug, planCommit } = facts(state);
89
+ if ((await git.commitOf(dir, "HEAD")) !== planCommit ||
90
+ (await git.currentBranch(dir)) !== slug)
91
+ throw new Error("The implementing agent committed or switched branches: the run stops");
92
+ if (await git.hasChanges(dir, ".factory"))
93
+ throw new Error("The implementing agent changed .factory/: the run stops");
94
+ }
95
+ /** Plans, implements, checks and reviews an approved spec, then opens its pull request. */
96
+ export function implement(definition) {
97
+ return defineWorkflow({
98
+ name: DELIVERY,
99
+ input: z.object({
100
+ issue: z
101
+ .string()
102
+ .refine(isSlug, "Expected lowercase words separated by hyphens"),
103
+ }),
104
+ maxCostUsd: definition.maxCostUsd,
105
+ initial: "prepare",
106
+ // The issue's card shows these steps; each check counts in the step it checks.
107
+ steps: [
108
+ { name: "prepare", stages: ["prepare"] },
109
+ { name: "plan", stages: ["plan", "planned", "commit-plan"] },
110
+ { name: "implement", stages: ["implement", "implemented"] },
111
+ { name: "verify", stages: ["verify"] },
112
+ { name: "review", stages: ["diff", "review", "reviewed"] },
113
+ { name: "deliver", stages: ["deliver"] },
114
+ ],
115
+ nodes: {
116
+ prepare: node(step((context) => prepare(definition, context)), { ok: "plan" }),
117
+ plan: node(agent({
118
+ profile: definition.profiles.plan,
119
+ schema: planOutput,
120
+ context: ({ state }) => ({
121
+ issue: facts(state).slug,
122
+ spec: facts(state).spec,
123
+ }),
124
+ }), { ok: "planned" }),
125
+ planned: node(schemaGate({
126
+ schema: planOutput,
127
+ into: "plan",
128
+ check: (plan, { state }) => planProblem(plan, facts(state).criteria),
129
+ }), { ok: "commit-plan", invalid: retry("plan", 2) }),
130
+ "commit-plan": node(step(async ({ dir, state, log }) => {
131
+ const { slug, title, specPath, baseCommit, plan } = facts(state);
132
+ await writeArtifact(dir, slug, "plan", renderPlan(plan, { title, specPath, baseCommit }));
133
+ const planCommit = await git.commit(dir, planCommitMessage(slug), [
134
+ artifactPath(slug, "plan"),
135
+ ]);
136
+ log(`Committed plan.md (${plan.steps.length} steps) as ${short(planCommit)}`);
137
+ return { planCommit };
138
+ }), { ok: "implement" }),
139
+ implement: node(agent({
140
+ profile: definition.profiles.implement,
141
+ schema: implementationOutput,
142
+ context: ({ state }) => {
143
+ const { slug, spec, plan } = facts(state);
144
+ return { issue: slug, spec, plan };
145
+ },
146
+ }), { ok: "implemented" }),
147
+ implemented: node(gate(["ok", "invalid"], async (context) => {
148
+ // First what the agent did, whatever it answered: a malformed
149
+ // response must not hide a change it may not make.
150
+ await guard(context);
151
+ const parsed = implementationOutput.safeParse(context.state.output);
152
+ if (!parsed.success)
153
+ return {
154
+ outcome: "invalid",
155
+ reason: `Invalid structured output:\n${z.prettifyError(parsed.error)}`,
156
+ };
157
+ const problem = implementationProblem(parsed.data, facts(context.state).criteria);
158
+ if (problem)
159
+ return { outcome: "invalid", reason: problem };
160
+ return {
161
+ outcome: "ok",
162
+ reason: "Structured output and invariants valid: implementation",
163
+ data: { implementation: parsed.data },
164
+ };
165
+ }), { ok: "verify", invalid: retry("implement", 2) }),
166
+ verify: node(code(["passed", "failed"], async ({ dir, log }) => {
167
+ const checks = await runChecks(dir, definition.verify, journalChecks(log));
168
+ if (checks.ok)
169
+ return {
170
+ outcome: "passed",
171
+ reason: "Every check passed",
172
+ data: { checks: checks.passed },
173
+ };
174
+ return {
175
+ outcome: "failed",
176
+ reason: `${checks.check.name} failed: ${checks.cause}`,
177
+ feedback: failureFeedback(checks.check, checks.cause, checks.output),
178
+ };
179
+ }), { passed: "diff", failed: retry("implement", 3) }),
180
+ diff: node(step(async ({ dir, state, log }) => {
181
+ const diff = await git.stagedDiff(dir, facts(state).planCommit);
182
+ if (diff.truncated)
183
+ throw new Error("The changes are too large to review (over 2 MiB of diff): the run stops");
184
+ const files = diff.text.match(/^diff --git /gm)?.length ?? 0;
185
+ log(`Changes since the plan: ${files} files, ${diff.text.split("\n").length} diff lines`);
186
+ return { diff: diff.text };
187
+ }), { ok: "review" }),
188
+ review: node(agent({
189
+ profile: definition.profiles.review,
190
+ schema: reviewOutput,
191
+ // A new conversation for each review; a correction of its format resumes it.
192
+ session: (state) => `review-${reviewRounds(state)}`,
193
+ context: ({ state }) => {
194
+ const { slug, spec, diff, checks } = facts(state);
195
+ return { issue: slug, spec, diff, checks };
196
+ },
197
+ }), { ok: "reviewed" }),
198
+ reviewed: node(gate(["approved", "changes", "invalid"], async ({ state }) => {
199
+ const parsed = reviewOutput.safeParse(state.output);
200
+ if (!parsed.success)
201
+ return {
202
+ outcome: "invalid",
203
+ reason: `Invalid structured output:\n${z.prettifyError(parsed.error)}`,
204
+ };
205
+ const problem = reviewProblem(parsed.data, facts(state).criteria);
206
+ if (problem)
207
+ return { outcome: "invalid", reason: problem };
208
+ const changes = reviewChanges(parsed.data);
209
+ if (changes)
210
+ return {
211
+ outcome: "changes",
212
+ reason: "The review requires changes",
213
+ feedback: changes,
214
+ data: { review: parsed.data },
215
+ };
216
+ return {
217
+ outcome: "approved",
218
+ reason: "Every criterion is met and nothing blocks",
219
+ data: { review: parsed.data },
220
+ };
221
+ }), {
222
+ approved: "deliver",
223
+ changes: retry("implement", 2),
224
+ invalid: retry("review", 2),
225
+ }),
226
+ deliver: node(step(async ({ dir, state, log }) => {
227
+ const { slug, base, plan, specPath, planPath, baseCommit, criteria, implementation, review, checks, } = facts(state);
228
+ const commit = await git.commit(dir, `${plan.commit}\n\nSpec: ${specPath}`);
229
+ log(`Committed "${plan.commit}" as ${short(commit)}`);
230
+ await git.forcePush(dir, slug);
231
+ log(`Pushed ${slug}, replacing any earlier version of the branch`);
232
+ const pullRequest = await github.openPullRequest(dir, {
233
+ base,
234
+ head: slug,
235
+ title: plan.commit,
236
+ body: pullRequestBody({
237
+ criteria,
238
+ implementation,
239
+ review,
240
+ checks,
241
+ reviewRounds: reviewRounds(state),
242
+ specPath,
243
+ planPath,
244
+ baseCommit,
245
+ runId: state.id,
246
+ }),
247
+ });
248
+ log(`Pull request: ${pullRequest}`);
249
+ await git.switchTo(dir, base);
250
+ log(`Back on ${base}`);
251
+ return { pullRequest };
252
+ }), { ok: END }),
253
+ },
254
+ // Also called for a failed run, which opened no pull request.
255
+ presentResult: (state) => {
256
+ const { pullRequest, checks } = facts(state);
257
+ if (typeof pullRequest !== "string")
258
+ return [];
259
+ const rounds = reviewRounds(state);
260
+ return [
261
+ `Pull request: ${pullRequest}`,
262
+ `Review: approved ${rounds === 0 ? "at the first review" : `after ${rounds} round${rounds === 1 ? "" : "s"} of changes`}`,
263
+ `Checks passed: ${checks.map(({ name }) => name).join(", ")}`,
264
+ ];
265
+ },
266
+ });
267
+ }
268
+ //# sourceMappingURL=implement.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"implement.js","sourceRoot":"","sources":["../../../src/app/workflows/implement.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ /** Checks a draft written by an agent, then writes it as the issue's issue.md or spec.md. */
2
+ export declare const issueSave: import("@clemrig/flow").Workflow;
@@ -0,0 +1,35 @@
1
+ import { defineWorkflow, END, node, step, z } from "@clemrig/flow";
2
+ import { isSlug, parseIssue } from "../../domain/issue.js";
3
+ import { parseSpec } from "../../domain/spec.js";
4
+ import { hasArtifact, readDraft, writeArtifact } from "../../system/issues.js";
5
+ const input = z.object({
6
+ issue: z
7
+ .string()
8
+ .refine(isSlug, "Expected lowercase words separated by hyphens"),
9
+ kind: z.enum(["issue", "spec"]),
10
+ file: z.string().min(1),
11
+ });
12
+ /** Checks a draft written by an agent, then writes it as the issue's issue.md or spec.md. */
13
+ export const issueSave = defineWorkflow({
14
+ name: "issue-save",
15
+ input,
16
+ initial: "save",
17
+ nodes: {
18
+ save: node(step(async ({ dir, state }) => {
19
+ const { issue, kind, file } = state.input;
20
+ if (kind === "spec" && !(await hasArtifact(dir, issue, "issue")))
21
+ throw new Error(`Issue ${issue} does not exist: save its issue.md first`);
22
+ const text = await readDraft(file);
23
+ const parsed = kind === "issue" ? parseIssue(text) : parseSpec(text);
24
+ if (!parsed.ok)
25
+ throw new Error([
26
+ `Invalid ${kind}.md draft ${file}:`,
27
+ ...parsed.problems.map((problem) => `- ${problem}`),
28
+ ].join("\n"));
29
+ return { path: await writeArtifact(dir, issue, kind, text) };
30
+ }), { ok: END }),
31
+ },
32
+ // Also called for a failed run, which saved nothing.
33
+ presentResult: ({ data }) => typeof data.path === "string" ? [`Saved ${data.path}`] : [],
34
+ });
35
+ //# sourceMappingURL=issue-save.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"issue-save.js","sourceRoot":"","sources":["../../../src/app/workflows/issue-save.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,GAAG,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,EAAE,MAAM,eAAe,CAAC;AACnE,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAC;AAC3D,OAAO,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAC;AACjD,OAAO,EAAE,WAAW,EAAE,SAAS,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AAE/E,MAAM,KAAK,GAAG,CAAC,CAAC,MAAM,CAAC;IACrB,KAAK,EAAE,CAAC;SACL,MAAM,EAAE;SACR,MAAM,CAAC,MAAM,EAAE,+CAA+C,CAAC;IAClE,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;IAC/B,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;CACxB,CAAC,CAAC;AAGH,6FAA6F;AAC7F,MAAM,CAAC,MAAM,SAAS,GAAG,cAAc,CAAC;IACtC,IAAI,EAAE,YAAY;IAClB,KAAK;IACL,OAAO,EAAE,MAAM;IACf,KAAK,EAAE;QACL,IAAI,EAAE,IAAI,CACR,IAAI,CAAC,KAAK,EAAE,EAAE,GAAG,EAAE,KAAK,EAAE,EAAE,EAAE;YAC5B,MAAM,EAAE,KAAK,EAAE,IAAI,EAAE,IAAI,EAAE,GAAG,KAAK,CAAC,KAAc,CAAC;YACnD,IAAI,IAAI,KAAK,MAAM,IAAI,CAAC,CAAC,MAAM,WAAW,CAAC,GAAG,EAAE,KAAK,EAAE,OAAO,CAAC,CAAC;gBAC9D,MAAM,IAAI,KAAK,CACb,SAAS,KAAK,0CAA0C,CACzD,CAAC;YACJ,MAAM,IAAI,GAAG,MAAM,SAAS,CAAC,IAAI,CAAC,CAAC;YACnC,MAAM,MAAM,GAAG,IAAI,KAAK,OAAO,CAAC,CAAC,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;YACrE,IAAI,CAAC,MAAM,CAAC,EAAE;gBACZ,MAAM,IAAI,KAAK,CACb;oBACE,WAAW,IAAI,aAAa,IAAI,GAAG;oBACnC,GAAG,MAAM,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,KAAK,OAAO,EAAE,CAAC;iBACpD,CAAC,IAAI,CAAC,IAAI,CAAC,CACb,CAAC;YACJ,OAAO,EAAE,IAAI,EAAE,MAAM,aAAa,CAAC,GAAG,EAAE,KAAK,EAAE,IAAI,EAAE,IAAI,CAAC,EAAE,CAAC;QAC/D,CAAC,CAAC,EACF,EAAE,EAAE,EAAE,GAAG,EAAE,CACZ;KACF;IACD,qDAAqD;IACrD,aAAa,EAAE,CAAC,EAAE,IAAI,EAAE,EAAE,EAAE,CAC1B,OAAO,IAAI,CAAC,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,CAAC,SAAS,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE;CAC9D,CAAC,CAAC"}
@@ -51,7 +51,7 @@ export async function main(argv, directory) {
51
51
  if (error)
52
52
  process.stderr.write(`factory: factory.ts cannot be loaded, results use the default rendering: ${error}\n`);
53
53
  if (args.command === "ui")
54
- return await ui(factory, dashboardPort);
54
+ return await ui(factory, dashboardPort, error);
55
55
  const reporter = new TerminalReporter((state) => presentResult(factory, state), args.json);
56
56
  return await status(factory, reporter, args.positional[0]);
57
57
  }
@@ -1 +1 @@
1
- {"version":3,"file":"application.js","sourceRoot":"","sources":["../../src/cli/application.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"application.js","sourceRoot":"","sources":["../../src/cli/application.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- export declare const help = "factory \u2014 workflows written in this repository's .factory/\n\n factory init create .factory/ here and install it\n factory doctor [--json] check Node, workflows, prompts and runtimes\n factory run WORKFLOW [--INPUT VALUE\u2026] [--max-cost-usd USD] [--json]\n factory status [RUN_ID] [--json] list this repository's runs, or show one\n factory ui [--port N] serve a live read-only dashboard on 127.0.0.1\n\nCommands other than init and help use the nearest .factory/ in the current directory\nor a parent, with the factory version installed there. factory doctor lists each\nworkflow's input options. .factory/.env is loaded; shell variables take precedence.\n--max-cost-usd fails the run once its agents' announced cost exceeds it, instead\nof the workflow's maxCostUsd. --json writes events, then the result, as JSON lines.\nCtrl-C stops a run, which ends failed; press it again to quit at once.\nExit codes: 0 completed, 1 error or failed run, 130 second Ctrl-C.\n";
1
+ export declare const help = "factory \u2014 this repository's issues, from spec to pull request, with .factory/\n\n factory init create .factory/ here and install it\n factory doctor [--json] check Node, workflows, prompts and runtimes\n factory run WORKFLOW [--INPUT VALUE\u2026] [--max-cost-usd USD] [--json]\n factory status [RUN_ID] [--json] list this repository's runs, or show one\n factory ui [--port N] serve the live read-only Kanban, runs under /runs/\n\nCommands other than init and help use the nearest .factory/ in the current directory\nor a parent, with the factory version installed there. factory doctor lists each\nworkflow's input options. factory run issue-save saves an issue or its spec;\nfactory run implement --issue SLUG takes a pushed spec to a pull request.\n.factory/.env is loaded; shell variables take precedence.\n--max-cost-usd fails the run once its agents' announced cost exceeds it, instead\nof the workflow's maxCostUsd. --json writes events, then the result, as JSON lines.\nCtrl-C stops a run, which ends failed; press it again to quit at once.\nExit codes: 0 completed, 1 error or failed run, 130 second Ctrl-C.\n";
package/dist/cli/help.js CHANGED
@@ -1,14 +1,16 @@
1
- export const help = `factory — workflows written in this repository's .factory/
1
+ export const help = `factory — this repository's issues, from spec to pull request, with .factory/
2
2
 
3
3
  factory init create .factory/ here and install it
4
4
  factory doctor [--json] check Node, workflows, prompts and runtimes
5
5
  factory run WORKFLOW [--INPUT VALUE…] [--max-cost-usd USD] [--json]
6
6
  factory status [RUN_ID] [--json] list this repository's runs, or show one
7
- factory ui [--port N] serve a live read-only dashboard on 127.0.0.1
7
+ factory ui [--port N] serve the live read-only Kanban, runs under /runs/
8
8
 
9
9
  Commands other than init and help use the nearest .factory/ in the current directory
10
10
  or a parent, with the factory version installed there. factory doctor lists each
11
- workflow's input options. .factory/.env is loaded; shell variables take precedence.
11
+ workflow's input options. factory run issue-save saves an issue or its spec;
12
+ factory run implement --issue SLUG takes a pushed spec to a pull request.
13
+ .factory/.env is loaded; shell variables take precedence.
12
14
  --max-cost-usd fails the run once its agents' announced cost exceeds it, instead
13
15
  of the workflow's maxCostUsd. --json writes events, then the result, as JSON lines.
14
16
  Ctrl-C stops a run, which ends failed; press it again to quit at once.
@@ -1 +1 @@
1
- {"version":3,"file":"help.js","sourceRoot":"","sources":["../../src/cli/help.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,IAAI,GAAG;;;;;;;;;;;;;;;CAenB,CAAC"}
1
+ {"version":3,"file":"help.js","sourceRoot":"","sources":["../../src/cli/help.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,IAAI,GAAG;;;;;;;;;;;;;;;;;CAiBnB,CAAC"}
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * `factory init`: creates `.factory/` in `cwd` from the templates, pinned to this
3
- * factory version, then installs it. An existing `.factory/` is refused untouched;
4
- * a failed installation keeps the files.
3
+ * factory version, and the `issue` skill, then installs it. An existing
4
+ * `.factory/` or skill is refused untouched; a failed installation keeps the files.
5
5
  */
6
6
  export declare function init(cwd: string): Promise<number>;
package/dist/cli/init.js CHANGED
@@ -1,18 +1,18 @@
1
1
  import { createFactory, installFactory } from "../app/init.js";
2
2
  /**
3
3
  * `factory init`: creates `.factory/` in `cwd` from the templates, pinned to this
4
- * factory version, then installs it. An existing `.factory/` is refused untouched;
5
- * a failed installation keeps the files.
4
+ * factory version, and the `issue` skill, then installs it. An existing
5
+ * `.factory/` or skill is refused untouched; a failed installation keeps the files.
6
6
  */
7
7
  export async function init(cwd) {
8
8
  const { factoryDir, version } = await createFactory(cwd);
9
- process.stdout.write(`Created ${factoryDir}; installing @clemrig/factory ${version}…\n`);
9
+ process.stdout.write(`Created ${factoryDir} and the issue skill (.agents/skills/issue, linked from .claude/skills/issue); installing @clemrig/factory ${version}…\n`);
10
10
  const install = await installFactory(factoryDir);
11
11
  if (!install.ok) {
12
12
  process.stderr.write(`${install.output}\n`);
13
13
  throw new Error("Installation failed; .factory/ is kept: run npm install --prefix .factory");
14
14
  }
15
- process.stdout.write('Next: commit .factory/, run factory doctor, then factory run ask --question "What changed recently?"\n');
15
+ process.stdout.write("Next: set your checks in .factory/factory.ts, run factory doctor, commit .factory/, .agents/ and .claude/skills/, then use /issue in Claude Code, Codex or Pi\n");
16
16
  return 0;
17
17
  }
18
18
  //# sourceMappingURL=init.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"init.js","sourceRoot":"","sources":["../../src/cli/init.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAE/D;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,IAAI,CAAC,GAAW;IACpC,MAAM,EAAE,UAAU,EAAE,OAAO,EAAE,GAAG,MAAM,aAAa,CAAC,GAAG,CAAC,CAAC;IACzD,OAAO,CAAC,MAAM,CAAC,KAAK,CAClB,WAAW,UAAU,iCAAiC,OAAO,KAAK,CACnE,CAAC;IACF,MAAM,OAAO,GAAG,MAAM,cAAc,CAAC,UAAU,CAAC,CAAC;IACjD,IAAI,CAAC,OAAO,CAAC,EAAE,EAAE,CAAC;QAChB,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,OAAO,CAAC,MAAM,IAAI,CAAC,CAAC;QAC5C,MAAM,IAAI,KAAK,CACb,2EAA2E,CAC5E,CAAC;IACJ,CAAC;IACD,OAAO,CAAC,MAAM,CAAC,KAAK,CAClB,wGAAwG,CACzG,CAAC;IACF,OAAO,CAAC,CAAC;AACX,CAAC"}
1
+ {"version":3,"file":"init.js","sourceRoot":"","sources":["../../src/cli/init.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAE/D;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,IAAI,CAAC,GAAW;IACpC,MAAM,EAAE,UAAU,EAAE,OAAO,EAAE,GAAG,MAAM,aAAa,CAAC,GAAG,CAAC,CAAC;IACzD,OAAO,CAAC,MAAM,CAAC,KAAK,CAClB,WAAW,UAAU,8GAA8G,OAAO,KAAK,CAChJ,CAAC;IACF,MAAM,OAAO,GAAG,MAAM,cAAc,CAAC,UAAU,CAAC,CAAC;IACjD,IAAI,CAAC,OAAO,CAAC,EAAE,EAAE,CAAC;QAChB,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,OAAO,CAAC,MAAM,IAAI,CAAC,CAAC;QAC5C,MAAM,IAAI,KAAK,CACb,2EAA2E,CAC5E,CAAC;IACJ,CAAC;IACD,OAAO,CAAC,MAAM,CAAC,KAAK,CAClB,iKAAiK,CAClK,CAAC;IACF,OAAO,CAAC,CAAC;AACX,CAAC"}
package/dist/cli/ui.d.ts CHANGED
@@ -1,3 +1,6 @@
1
1
  import type { Factory } from "../app/factory.js";
2
- /** `factory ui`: serves the dashboard of the repository's runs until Ctrl-C, on `port` or one the system chooses. */
3
- export declare function ui(factory: Factory, port?: number): Promise<number>;
2
+ /**
3
+ * `factory ui`: serves the Kanban of the repository's issues, and the dashboard
4
+ * of its runs under `/runs/`, until Ctrl-C, on `port` or one the system chooses.
5
+ */
6
+ export declare function ui(factory: Factory, port?: number, loadError?: string): Promise<number>;
package/dist/cli/ui.js CHANGED
@@ -1,15 +1,28 @@
1
1
  import { basename } from "node:path";
2
- import { startDashboard } from "@clemrig/flow-ui";
2
+ import { startFactoryUi } from "@clemrig/factory-ui";
3
+ import { dashboardHandler } from "@clemrig/flow-ui";
4
+ import { readBoard } from "../app/board.js";
3
5
  import { presentResult } from "../app/runs.js";
4
- /** `factory ui`: serves the dashboard of the repository's runs until Ctrl-C, on `port` or one the system chooses. */
5
- export async function ui(factory, port) {
6
- const dashboard = await startDashboard({
6
+ /**
7
+ * `factory ui`: serves the Kanban of the repository's issues, and the dashboard
8
+ * of its runs under `/runs/`, until Ctrl-C, on `port` or one the system chooses.
9
+ */
10
+ export async function ui(factory, port, loadError) {
11
+ const label = basename(factory.dir);
12
+ const runs = await dashboardHandler({
7
13
  runsDir: factory.runsDir,
8
14
  title: "factory",
9
- label: basename(factory.dir),
15
+ label,
10
16
  presentResult: (state) => presentResult(factory, state),
17
+ });
18
+ const page = await startFactoryUi({
19
+ title: "factory",
20
+ label,
21
+ // The board the factory computes is what the page shows: checked here, where both meet.
22
+ board: () => readBoard(factory, loadError),
23
+ runs,
11
24
  }, port);
12
- process.stdout.write(`factory ui: ${dashboard.url} (read-only; Ctrl-C to stop)\n`);
25
+ process.stdout.write(`factory ui: ${page.url} (runs: ${page.url}runs/; read-only; Ctrl-C to stop)\n`);
13
26
  await new Promise((resolve) => {
14
27
  const stop = () => {
15
28
  process.off("SIGINT", stop);
@@ -19,7 +32,7 @@ export async function ui(factory, port) {
19
32
  process.on("SIGINT", stop);
20
33
  process.on("SIGTERM", stop);
21
34
  });
22
- await dashboard.close();
35
+ await page.close();
23
36
  return 0;
24
37
  }
25
38
  //# sourceMappingURL=ui.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"ui.js","sourceRoot":"","sources":["../../src/cli/ui.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAC;AACrC,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAElD,OAAO,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAE/C,qHAAqH;AACrH,MAAM,CAAC,KAAK,UAAU,EAAE,CAAC,OAAgB,EAAE,IAAa;IACtD,MAAM,SAAS,GAAG,MAAM,cAAc,CACpC;QACE,OAAO,EAAE,OAAO,CAAC,OAAO;QACxB,KAAK,EAAE,SAAS;QAChB,KAAK,EAAE,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC;QAC5B,aAAa,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,aAAa,CAAC,OAAO,EAAE,KAAK,CAAC;KACxD,EACD,IAAI,CACL,CAAC;IACF,OAAO,CAAC,MAAM,CAAC,KAAK,CAClB,eAAe,SAAS,CAAC,GAAG,gCAAgC,CAC7D,CAAC;IACF,MAAM,IAAI,OAAO,CAAO,CAAC,OAAO,EAAE,EAAE;QAClC,MAAM,IAAI,GAAG,GAAG,EAAE;YAChB,OAAO,CAAC,GAAG,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC;YAC5B,OAAO,CAAC,GAAG,CAAC,SAAS,EAAE,IAAI,CAAC,CAAC;YAC7B,OAAO,EAAE,CAAC;QACZ,CAAC,CAAC;QACF,OAAO,CAAC,EAAE,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC;QAC3B,OAAO,CAAC,EAAE,CAAC,SAAS,EAAE,IAAI,CAAC,CAAC;IAC9B,CAAC,CAAC,CAAC;IACH,MAAM,SAAS,CAAC,KAAK,EAAE,CAAC;IACxB,OAAO,CAAC,CAAC;AACX,CAAC"}
1
+ {"version":3,"file":"ui.js","sourceRoot":"","sources":["../../src/cli/ui.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAC;AACrC,OAAO,EAAc,cAAc,EAAE,MAAM,qBAAqB,CAAC;AACjE,OAAO,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AACpD,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAE5C,OAAO,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAE/C;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,EAAE,CACtB,OAAgB,EAChB,IAAa,EACb,SAAkB;IAElB,MAAM,KAAK,GAAG,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;IACpC,MAAM,IAAI,GAAG,MAAM,gBAAgB,CAAC;QAClC,OAAO,EAAE,OAAO,CAAC,OAAO;QACxB,KAAK,EAAE,SAAS;QAChB,KAAK;QACL,aAAa,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,aAAa,CAAC,OAAO,EAAE,KAAK,CAAC;KACxD,CAAC,CAAC;IACH,MAAM,IAAI,GAAG,MAAM,cAAc,CAC/B;QACE,KAAK,EAAE,SAAS;QAChB,KAAK;QACL,wFAAwF;QACxF,KAAK,EAAE,GAAmB,EAAE,CAAC,SAAS,CAAC,OAAO,EAAE,SAAS,CAAC;QAC1D,IAAI;KACL,EACD,IAAI,CACL,CAAC;IACF,OAAO,CAAC,MAAM,CAAC,KAAK,CAClB,eAAe,IAAI,CAAC,GAAG,WAAW,IAAI,CAAC,GAAG,qCAAqC,CAChF,CAAC;IACF,MAAM,IAAI,OAAO,CAAO,CAAC,OAAO,EAAE,EAAE;QAClC,MAAM,IAAI,GAAG,GAAG,EAAE;YAChB,OAAO,CAAC,GAAG,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC;YAC5B,OAAO,CAAC,GAAG,CAAC,SAAS,EAAE,IAAI,CAAC,CAAC;YAC7B,OAAO,EAAE,CAAC;QACZ,CAAC,CAAC;QACF,OAAO,CAAC,EAAE,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC;QAC3B,OAAO,CAAC,EAAE,CAAC,SAAS,EAAE,IAAI,CAAC,CAAC;IAC9B,CAAC,CAAC,CAAC;IACH,MAAM,IAAI,CAAC,KAAK,EAAE,CAAC;IACnB,OAAO,CAAC,CAAC;AACX,CAAC"}
@@ -0,0 +1,65 @@
1
+ import { type RunState, type WorkflowStep } from "@clemrig/flow";
2
+ /** The columns, in the order an issue goes through them. */
3
+ export declare const columns: readonly ["Backlog", "Specifying", "Executing", "Blocked", "To Approve", "Done"];
4
+ export type ColumnName = (typeof columns)[number];
5
+ /** What the repository says of an issue. */
6
+ export interface IssueFacts {
7
+ slug: string;
8
+ /** From `issue.md`; the slug when it has no readable title. */
9
+ title: string;
10
+ hasSpec: boolean;
11
+ /** Its `plan.md` is on the main branch. */
12
+ delivered: boolean;
13
+ /** When one of its files last changed, as an ISO date. */
14
+ changedAt: string;
15
+ }
16
+ /** How far a run went through one step of its workflow. */
17
+ export interface StepProgress {
18
+ name: string;
19
+ state: "done" | "current" | "failed" | "pending";
20
+ }
21
+ /** The last run of a workflow shown for an issue. */
22
+ export interface RunProgress {
23
+ id: string;
24
+ workflow: string;
25
+ status: RunState["status"];
26
+ /** The stage it is running, or the one it ended on. */
27
+ stage: string;
28
+ steps: StepProgress[];
29
+ durationMs: number | null;
30
+ /** Unknown (`null`) until an agent call announces a cost. */
31
+ costUsd: number | null;
32
+ /** Some agent call announced no cost. */
33
+ partial: boolean;
34
+ }
35
+ /** An issue on the board. */
36
+ export interface IssueCard {
37
+ slug: string;
38
+ title: string;
39
+ /** The newest pull request its deliveries recorded. */
40
+ pullRequest?: string;
41
+ /** The last run of each shown workflow, newest first. */
42
+ runs: RunProgress[];
43
+ }
44
+ /** The issues in their columns, and what may leave the board incomplete. */
45
+ export interface IssueBoard {
46
+ columns: {
47
+ name: ColumnName;
48
+ cards: IssueCard[];
49
+ }[];
50
+ problems: string[];
51
+ }
52
+ /** A workflow shown on the cards: one that takes an issue and declares its steps. */
53
+ export interface ShownWorkflow {
54
+ name: string;
55
+ steps: WorkflowStep[];
56
+ }
57
+ /** No status is stored: the column follows from the issue's files, the main branch and its last delivery. */
58
+ export declare function columnOf(issue: IssueFacts, lastDelivery: Pick<RunState, "status"> | undefined): ColumnName;
59
+ /** How far a run went through its workflow's steps; a correction brings its step back. */
60
+ export declare function stepsOf(steps: WorkflowStep[], run: Pick<RunState, "stage" | "status">): StepProgress[];
61
+ /**
62
+ * The Kanban: each issue in its column, the most recently active first, with
63
+ * the last run of each shown workflow. `runs` come in creation order.
64
+ */
65
+ export declare function boardOf(issues: IssueFacts[], runs: RunState[], shown: ShownWorkflow[], problems: string[]): IssueBoard;