@lchase/kiln 0.0.0-stage → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +227 -2
- package/dist/cli.js +334 -0
- package/dist/config.js +237 -0
- package/dist/delivery.js +245 -0
- package/dist/driver.js +634 -0
- package/dist/errors.js +6 -0
- package/dist/host.js +223 -0
- package/dist/intake/file.js +29 -0
- package/dist/intake/jira.js +582 -0
- package/dist/intake/prompt.js +47 -0
- package/dist/intake/tickets.js +443 -0
- package/dist/jobs.js +149 -0
- package/dist/paths.js +34 -0
- package/dist/reconcile.js +123 -0
- package/dist/report.js +157 -0
- package/dist/schemas.js +90 -0
- package/dist/truncate-output.js +122 -0
- package/dist/workflow.js +113 -0
- package/package.json +40 -4
- package/prompts/factory/approver.md +49 -0
- package/prompts/factory/builder.md +76 -0
- package/prompts/factory/review-code.md +55 -0
- package/prompts/factory/review-security.md +50 -0
- package/prompts/factory/review-ui.md +50 -0
- package/prompts/factory/review-ux.md +48 -0
- package/prompts/factory/spec-writer.md +67 -0
- package/prompts/kiln/approver.md +33 -0
- package/prompts/kiln/build.md +38 -0
- package/prompts/kiln/code.md +26 -0
- package/prompts/kiln/security.md +26 -0
- package/prompts/kiln/spec.md +18 -0
- package/prompts/kiln/ui.md +26 -0
- package/prompts/kiln/ux.md +26 -0
- package/workflows/feature.yaml +239 -0
|
@@ -0,0 +1,239 @@
|
|
|
1
|
+
# One Kiln job, run by yak (@lchase/yak).
|
|
2
|
+
#
|
|
3
|
+
# Faithful to Lawrence Chase's factory plugin v0.7.0 (MIT):
|
|
4
|
+
# https://github.com/lchase/coding-agent-plugins/tree/4c84a2ce7fbde5ac298c0de9f0b90141eac4ed98/plugins/factory
|
|
5
|
+
# skills/factory/SKILL.md (the loop: spec, build, 4 reviews, approver)
|
|
6
|
+
# agents/spec-writer.md model opus
|
|
7
|
+
# agents/builder.md model opus
|
|
8
|
+
# agents/review-security.md model opus
|
|
9
|
+
# agents/review-ux.md model sonnet
|
|
10
|
+
# agents/review-ui.md model sonnet
|
|
11
|
+
# agents/review-code.md model sonnet
|
|
12
|
+
# agents/approver.md model opus
|
|
13
|
+
# The prompt bodies are copied verbatim into prompts/factory/. Each step's
|
|
14
|
+
# prompt file is a Kiln preamble (prompts/kiln/) that maps the factory's
|
|
15
|
+
# job-folder files onto yak artifacts and tells the agent to return JSON
|
|
16
|
+
# instead of writing a file. `kiln tick` appends the factory body and rewrites
|
|
17
|
+
# prompt.file to an absolute path under the kiln directory before launching,
|
|
18
|
+
# because yak resolves prompt.file from the checkout cwd
|
|
19
|
+
# (yak src/steps/agent.ts, path.resolve(cwd, file)).
|
|
20
|
+
#
|
|
21
|
+
# yak 0.6.1 limits this file still works inside:
|
|
22
|
+
# - command.run is not templated. verify runs $KILN_TEST through
|
|
23
|
+
# dist/truncate-output.js ($KILN_VERIFY_WRAPPER). `kiln tick` sets
|
|
24
|
+
# KILN_TEST from repos.<repo>.test. An empty value fails the step. The
|
|
25
|
+
# wrapper keeps the test's exit code and cuts stdout/stderr to the last
|
|
26
|
+
# 200 lines or 20KB, with a leading `[truncated:` line when it cuts.
|
|
27
|
+
# land commits with `git commit -m "kiln: $KILN_TASK_TITLE"`. verify and
|
|
28
|
+
# land need `input` (it carries a per-launch runNonce) so one job cannot
|
|
29
|
+
# cache-hit another. land runs only when approval.decision is approve,
|
|
30
|
+
# and it does not fail when the index is empty. `git add -A` stages every
|
|
31
|
+
# uncommitted path in the worktree.
|
|
32
|
+
# - input.baseRef is the commit the worktree was branched from (full SHA).
|
|
33
|
+
# deliver=local uses checkout HEAD. deliver=pr uses origin/<base>, or the
|
|
34
|
+
# upstream yak/<run-id> tip when the job is stacked. Every preamble maps
|
|
35
|
+
# `<main branch>` to that SHA. The worktree branch is yak/<run-id>.
|
|
36
|
+
# - A loop body does not evaluate skipIf, so the UI reviewer is a real step.
|
|
37
|
+
# review-ui.md itself returns PASS when no UI changed.
|
|
38
|
+
# - A loop-body artifact is not a top-level producer. The approver reads the
|
|
39
|
+
# last verify on rounds.verify; needs: [verify] on the approver is rejected.
|
|
40
|
+
# Reviewers run inside the loop, so they need verify directly. They inherit
|
|
41
|
+
# input (for baseRef) instead of listing it in needs, and the loop's
|
|
42
|
+
# concurrency is 4 so the four reviewers start together.
|
|
43
|
+
name: kiln-feature
|
|
44
|
+
version: "1"
|
|
45
|
+
inputSchema:
|
|
46
|
+
inline:
|
|
47
|
+
type: object
|
|
48
|
+
additionalProperties: false
|
|
49
|
+
properties:
|
|
50
|
+
title: { type: string }
|
|
51
|
+
description: { type: string }
|
|
52
|
+
acceptance: { type: string }
|
|
53
|
+
runNonce: { type: string }
|
|
54
|
+
baseRef: { type: string }
|
|
55
|
+
required: [title, description, acceptance, runNonce, baseRef]
|
|
56
|
+
steps:
|
|
57
|
+
- id: spec
|
|
58
|
+
needs: [input]
|
|
59
|
+
agent:
|
|
60
|
+
model: opus
|
|
61
|
+
prompt:
|
|
62
|
+
file: prompts/kiln/spec.md
|
|
63
|
+
schema:
|
|
64
|
+
inline:
|
|
65
|
+
type: object
|
|
66
|
+
additionalProperties: false
|
|
67
|
+
properties:
|
|
68
|
+
goal: { type: string }
|
|
69
|
+
design: { type: string }
|
|
70
|
+
acceptance: { type: string }
|
|
71
|
+
required: [goal, design, acceptance]
|
|
72
|
+
tools: [Read, Grep, Glob, Bash, Write, Skill]
|
|
73
|
+
produces: spec
|
|
74
|
+
|
|
75
|
+
- id: revise
|
|
76
|
+
needs: [spec]
|
|
77
|
+
loop:
|
|
78
|
+
# A BLOCKED build, a red verify (exitCode != 0), or any CHANGES verdict
|
|
79
|
+
# sends the builder around again. failOn: never on verify is what keeps
|
|
80
|
+
# a red test from failing the run before that can happen. max 2 rounds,
|
|
81
|
+
# then the approver still runs (factory step 5: round 2 done goes to
|
|
82
|
+
# the approver).
|
|
83
|
+
until: 'build.status == "READY" && security.verdict == "PASS" && ux.verdict == "PASS" && ui.verdict == "PASS" && code.verdict == "PASS" && verify.exitCode == 0'
|
|
84
|
+
budget:
|
|
85
|
+
maxIterations: 2
|
|
86
|
+
onExhausted: continue
|
|
87
|
+
concurrency: 4
|
|
88
|
+
body:
|
|
89
|
+
# security, ux, ui, code, and verify are later in this body, so on
|
|
90
|
+
# build they are the previous round. Round 1 leaves them undefined;
|
|
91
|
+
# the prompt's `.field ||` defaults cover findings and verify text.
|
|
92
|
+
# Round 1 leaves verify undefined. A verify that ran with exitCode
|
|
93
|
+
# null was signal-killed, so `verify.exitCode == null` is not labeled
|
|
94
|
+
# round 1. Exit code 0 still renders as 0.
|
|
95
|
+
# `{{ security || "x" }}` does not validate.
|
|
96
|
+
- id: build
|
|
97
|
+
needs: [input, spec, security, ux, ui, code, verify]
|
|
98
|
+
agent:
|
|
99
|
+
model: opus
|
|
100
|
+
prompt:
|
|
101
|
+
file: prompts/kiln/build.md
|
|
102
|
+
schema:
|
|
103
|
+
inline:
|
|
104
|
+
type: object
|
|
105
|
+
additionalProperties: false
|
|
106
|
+
properties:
|
|
107
|
+
summary: { type: string }
|
|
108
|
+
status: { type: string, enum: [READY, BLOCKED] }
|
|
109
|
+
required: [summary, status]
|
|
110
|
+
tools: [Read, Grep, Glob, Bash, Write, Edit, Skill]
|
|
111
|
+
produces: build
|
|
112
|
+
|
|
113
|
+
- id: verify
|
|
114
|
+
needs: [input, build]
|
|
115
|
+
command:
|
|
116
|
+
run: 'node "${KILN_VERIFY_WRAPPER:?KILN_VERIFY_WRAPPER is empty}"'
|
|
117
|
+
failOn: never
|
|
118
|
+
capture: [stdout, stderr, exitCode]
|
|
119
|
+
produces: verify
|
|
120
|
+
|
|
121
|
+
# Build and verify stay in order. These four do not need each other,
|
|
122
|
+
# so concurrency 4 starts them together. They have no Write or Edit.
|
|
123
|
+
# Bash stays, because the factory prompts diff with git. Yak warns
|
|
124
|
+
# that concurrent Bash steps share one cwd. The preambles forbid
|
|
125
|
+
# re-running tests, builds, and any other write; git and file reads
|
|
126
|
+
# stay. input is inherited for baseRef; it is not in needs.
|
|
127
|
+
- id: security
|
|
128
|
+
needs: [spec, build, verify]
|
|
129
|
+
agent:
|
|
130
|
+
model: opus
|
|
131
|
+
context:
|
|
132
|
+
inherit: [input]
|
|
133
|
+
prompt:
|
|
134
|
+
file: prompts/kiln/security.md
|
|
135
|
+
schema:
|
|
136
|
+
inline:
|
|
137
|
+
type: object
|
|
138
|
+
additionalProperties: false
|
|
139
|
+
properties:
|
|
140
|
+
verdict: { type: string, enum: [PASS, CHANGES] }
|
|
141
|
+
findings: { type: string }
|
|
142
|
+
required: [verdict, findings]
|
|
143
|
+
tools: [Read, Grep, Glob, Bash, Skill]
|
|
144
|
+
produces: security
|
|
145
|
+
|
|
146
|
+
- id: ux
|
|
147
|
+
needs: [spec, build, verify]
|
|
148
|
+
agent:
|
|
149
|
+
model: sonnet
|
|
150
|
+
context:
|
|
151
|
+
inherit: [input]
|
|
152
|
+
prompt:
|
|
153
|
+
file: prompts/kiln/ux.md
|
|
154
|
+
schema:
|
|
155
|
+
inline:
|
|
156
|
+
type: object
|
|
157
|
+
additionalProperties: false
|
|
158
|
+
properties:
|
|
159
|
+
verdict: { type: string, enum: [PASS, CHANGES] }
|
|
160
|
+
findings: { type: string }
|
|
161
|
+
required: [verdict, findings]
|
|
162
|
+
tools: [Read, Grep, Glob, Bash, Skill]
|
|
163
|
+
produces: ux
|
|
164
|
+
|
|
165
|
+
- id: ui
|
|
166
|
+
needs: [spec, build, verify]
|
|
167
|
+
agent:
|
|
168
|
+
model: sonnet
|
|
169
|
+
context:
|
|
170
|
+
inherit: [input]
|
|
171
|
+
prompt:
|
|
172
|
+
file: prompts/kiln/ui.md
|
|
173
|
+
schema:
|
|
174
|
+
inline:
|
|
175
|
+
type: object
|
|
176
|
+
additionalProperties: false
|
|
177
|
+
properties:
|
|
178
|
+
verdict: { type: string, enum: [PASS, CHANGES] }
|
|
179
|
+
findings: { type: string }
|
|
180
|
+
required: [verdict, findings]
|
|
181
|
+
tools: [Read, Grep, Glob, Bash, Skill]
|
|
182
|
+
produces: ui
|
|
183
|
+
|
|
184
|
+
- id: code
|
|
185
|
+
needs: [spec, build, verify]
|
|
186
|
+
agent:
|
|
187
|
+
model: sonnet
|
|
188
|
+
context:
|
|
189
|
+
inherit: [input]
|
|
190
|
+
prompt:
|
|
191
|
+
file: prompts/kiln/code.md
|
|
192
|
+
schema:
|
|
193
|
+
inline:
|
|
194
|
+
type: object
|
|
195
|
+
additionalProperties: false
|
|
196
|
+
properties:
|
|
197
|
+
verdict: { type: string, enum: [PASS, CHANGES] }
|
|
198
|
+
findings: { type: string }
|
|
199
|
+
required: [verdict, findings]
|
|
200
|
+
tools: [Read, Grep, Glob, Bash, Skill]
|
|
201
|
+
produces: code
|
|
202
|
+
produces: rounds
|
|
203
|
+
|
|
204
|
+
- id: approver
|
|
205
|
+
needs: [input, spec, rounds]
|
|
206
|
+
agent:
|
|
207
|
+
model: opus
|
|
208
|
+
prompt:
|
|
209
|
+
file: prompts/kiln/approver.md
|
|
210
|
+
schema:
|
|
211
|
+
inline:
|
|
212
|
+
type: object
|
|
213
|
+
additionalProperties: false
|
|
214
|
+
properties:
|
|
215
|
+
decision: { type: string, enum: [APPROVE, ESCALATE] }
|
|
216
|
+
reason: { type: string }
|
|
217
|
+
required: [decision, reason]
|
|
218
|
+
tools: [Read, Grep, Glob, Bash, Write, Skill]
|
|
219
|
+
produces: decision
|
|
220
|
+
|
|
221
|
+
- id: approve
|
|
222
|
+
needs: [input, decision]
|
|
223
|
+
gate:
|
|
224
|
+
schema:
|
|
225
|
+
inline:
|
|
226
|
+
type: object
|
|
227
|
+
additionalProperties: false
|
|
228
|
+
properties:
|
|
229
|
+
decision: { type: string, enum: [approve, reject] }
|
|
230
|
+
required: [decision]
|
|
231
|
+
render:
|
|
232
|
+
inline: 'Approve "{{input.title}}"? Agent decision: {{decision.decision}}. {{decision.reason}}'
|
|
233
|
+
produces: approval
|
|
234
|
+
|
|
235
|
+
- id: land
|
|
236
|
+
needs: [input, approval]
|
|
237
|
+
skipIf: 'approval.decision != "approve"'
|
|
238
|
+
command:
|
|
239
|
+
run: 'git add -A && git diff --cached --quiet || git commit -m "kiln: $KILN_TASK_TITLE"'
|