@lchase/kiln 0.11.0 → 0.13.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 +27 -0
- package/assets/serve.css +20 -0
- package/assets/serve.js +53 -0
- package/dist/attention.js +2 -0
- package/dist/board-view.js +7 -0
- package/dist/cli.js +10 -2
- package/dist/config.js +5 -0
- package/dist/driver.js +67 -13
- package/dist/events.js +85 -2
- package/dist/host.js +106 -1
- package/dist/intake/jira.js +87 -0
- package/dist/jobs.js +4 -3
- package/dist/reconcile.js +7 -3
- package/dist/report.js +8 -0
- package/dist/review-post.js +269 -0
- package/dist/schemas.js +51 -3
- package/dist/serve-page.js +33 -2
- package/dist/serve.js +13 -4
- package/dist/settings.js +40 -1
- package/dist/triggers.js +797 -0
- package/dist/workflow.js +18 -15
- package/package.json +1 -1
- package/prompts/kiln/review.md +13 -0
- package/workflows/review.yaml +64 -0
package/dist/workflow.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { createHash } from "node:crypto";
|
|
2
|
-
import { existsSync, mkdirSync, readdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
2
|
+
import { existsSync, mkdirSync, readdirSync, readFileSync, statSync, writeFileSync } from "node:fs";
|
|
3
3
|
import { basename, join, sep } from "node:path";
|
|
4
4
|
import { jobBasename, packageRoot } from "./paths.js";
|
|
5
5
|
const FACTORY_DIRECTIVE = /^<!--\s*factory:\s*(prompts\/factory\/[a-z0-9-]+\.md)\s*-->/;
|
|
@@ -12,7 +12,10 @@ const PROMPT_COUNTS = {
|
|
|
12
12
|
feature: FEATURE_PROMPTS,
|
|
13
13
|
investigation: INVESTIGATION_PROMPTS,
|
|
14
14
|
fix: FIX_PROMPTS,
|
|
15
|
+
review: 1,
|
|
15
16
|
};
|
|
17
|
+
/** Workflow name for a draft pull-request review. It ends at a gate and does not open a pull request. */
|
|
18
|
+
export const REVIEW_WORKFLOW = "review";
|
|
16
19
|
/**
|
|
17
20
|
* Values Kiln can pass into a workflow. A workflow's inputSchema lists the
|
|
18
21
|
* ones it uses. `description` and `acceptance` stay so
|
|
@@ -52,18 +55,7 @@ export function assertWorkflowName(name) {
|
|
|
52
55
|
}
|
|
53
56
|
return path;
|
|
54
57
|
}
|
|
55
|
-
|
|
56
|
-
* Yak reads `prompt.file` with `path.resolve(cwd, file)`, and Kiln launches
|
|
57
|
-
* yak with cwd set to the product checkout. Rewrite `prompts/kiln/<name>.md`
|
|
58
|
-
* to an absolute file under the kiln directory: the Kiln preamble plus the
|
|
59
|
-
* verbatim factory prompt. The content hash is part of the filename, so a
|
|
60
|
-
* prompt edit changes the path yak caches on.
|
|
61
|
-
*
|
|
62
|
-
* A preamble that starts with `<!-- factory: prompts/factory/<file>.md -->`
|
|
63
|
-
* is combined with that factory body. A prompt without that directive is
|
|
64
|
-
* stored as itself. `prompts/kiln/investigation.md` uses the second form.
|
|
65
|
-
*/
|
|
66
|
-
export function materializeWorkflow(kilnDir, jobId, workflowName) {
|
|
58
|
+
export function materializeWorkflow(kilnDir, jobId, workflowName, options = {}) {
|
|
67
59
|
const sourcePath = assertWorkflowName(workflowName);
|
|
68
60
|
const source = readFileSync(sourcePath, "utf8");
|
|
69
61
|
const destDir = join(kilnDir, "rendered", jobBasename(jobId));
|
|
@@ -72,7 +64,8 @@ export function materializeWorkflow(kilnDir, jobId, workflowName) {
|
|
|
72
64
|
const rendered = source.replace(/file: prompts\/kiln\/([a-z0-9-]+)\.md/g, (_full, name) => {
|
|
73
65
|
count += 1;
|
|
74
66
|
const rel = `prompts/kiln/${name}.md`;
|
|
75
|
-
const
|
|
67
|
+
const override = name === "review" ? options.reviewPrompt : undefined;
|
|
68
|
+
const absolute = writeCombinedPrompt(rel, destDir, override);
|
|
76
69
|
return `file: ${yamlDoubleQuote(absolute)}`;
|
|
77
70
|
});
|
|
78
71
|
const expected = PROMPT_COUNTS[workflowName];
|
|
@@ -187,8 +180,18 @@ function declaredInputProperties(yaml) {
|
|
|
187
180
|
}
|
|
188
181
|
return names;
|
|
189
182
|
}
|
|
190
|
-
function writeCombinedPrompt(preambleRel, destDir) {
|
|
183
|
+
function writeCombinedPrompt(preambleRel, destDir, overridePath) {
|
|
191
184
|
const root = packageRoot();
|
|
185
|
+
if (overridePath) {
|
|
186
|
+
if (!existsSync(overridePath) || !statSync(overridePath).isFile()) {
|
|
187
|
+
throw new Error("Review prompt file was not found.");
|
|
188
|
+
}
|
|
189
|
+
const combined = `${readFileSync(overridePath, "utf8").trimEnd()}\n`;
|
|
190
|
+
const digest = createHash("sha256").update(combined).digest("hex").slice(0, 16);
|
|
191
|
+
const outPath = join(destDir, `${basename(preambleRel, ".md")}-${digest}.md`);
|
|
192
|
+
writeFileSync(outPath, combined);
|
|
193
|
+
return outPath;
|
|
194
|
+
}
|
|
192
195
|
const preamblePath = join(root, preambleRel);
|
|
193
196
|
const preamble = readFileSync(preamblePath, "utf8");
|
|
194
197
|
const directive = preamble.match(FACTORY_DIRECTIVE);
|
package/package.json
CHANGED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
Kiln runs this review inside yak. The working directory is an isolated worktree at `{{input.baseRef}}`. That commit is the pull request head. Do not guess a branch name.
|
|
2
|
+
|
|
3
|
+
Read the change. Return a draft review and nothing else. Do not post the review, approve the pull request, merge it, push, or comment. Kiln posts the draft only after a person approves the gate, and only as a comment. Do not change product code. Do not create, modify, or delete files. Read-only git and file inspection are allowed.
|
|
4
|
+
|
|
5
|
+
Return JSON with `markdown` and `findings`. `findings` is a list. Each item has `severity` (`note`, `nit`, `warning`, or `blocking`), `file`, `line`, and `comment`. `comment` is the text a person might post later. `markdown` is the whole draft a person will read, and it must include every finding with its severity, file, line, and suggested comment. If you find nothing, return an empty `findings` list and say so in `markdown`.
|
|
6
|
+
|
|
7
|
+
Do not invent files or line numbers. If you did not see a line, do not cite it.
|
|
8
|
+
|
|
9
|
+
Spec title: {{input.title}}
|
|
10
|
+
|
|
11
|
+
{{input.spec}}
|
|
12
|
+
|
|
13
|
+
Launch id: {{input.runNonce}}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
# Draft review of one pull request, run by yak (@lchase/yak).
|
|
2
|
+
#
|
|
3
|
+
# The agent returns findings (severity, file, line, suggested comment).
|
|
4
|
+
# A person approves or rejects the draft in the Inbox. Approving posts the
|
|
5
|
+
# draft as a pull request comment. Kiln does not approve the pull request
|
|
6
|
+
# or merge it. Rejecting or revising does not post.
|
|
7
|
+
#
|
|
8
|
+
# `reviewPrompt` in the kiln config replaces prompts/kiln/review.md.
|
|
9
|
+
# The packaged file is the generic default.
|
|
10
|
+
#
|
|
11
|
+
# `adapter: "mock"` reads `test/fixtures/kiln-review/draft.json` from the checkout.
|
|
12
|
+
name: kiln-review
|
|
13
|
+
version: "1"
|
|
14
|
+
inputSchema:
|
|
15
|
+
inline:
|
|
16
|
+
type: object
|
|
17
|
+
additionalProperties: false
|
|
18
|
+
properties:
|
|
19
|
+
title: { type: string }
|
|
20
|
+
spec: { type: string }
|
|
21
|
+
runNonce: { type: string }
|
|
22
|
+
baseRef: { type: string }
|
|
23
|
+
required: [title, spec, runNonce, baseRef]
|
|
24
|
+
steps:
|
|
25
|
+
- id: draft
|
|
26
|
+
needs: [input]
|
|
27
|
+
agent:
|
|
28
|
+
model: opus
|
|
29
|
+
prompt:
|
|
30
|
+
file: prompts/kiln/review.md
|
|
31
|
+
schema:
|
|
32
|
+
inline:
|
|
33
|
+
type: object
|
|
34
|
+
additionalProperties: false
|
|
35
|
+
properties:
|
|
36
|
+
markdown: { type: string, minLength: 1 }
|
|
37
|
+
findings:
|
|
38
|
+
type: array
|
|
39
|
+
items:
|
|
40
|
+
type: object
|
|
41
|
+
additionalProperties: false
|
|
42
|
+
properties:
|
|
43
|
+
severity: { type: string, enum: [note, nit, warning, blocking] }
|
|
44
|
+
file: { type: string, minLength: 1 }
|
|
45
|
+
line: { type: integer, minimum: 1 }
|
|
46
|
+
comment: { type: string, minLength: 1 }
|
|
47
|
+
required: [severity, file, line, comment]
|
|
48
|
+
required: [markdown, findings]
|
|
49
|
+
tools: [Read, Grep, Glob, Bash]
|
|
50
|
+
produces: draft
|
|
51
|
+
|
|
52
|
+
- id: approve
|
|
53
|
+
needs: [input, draft]
|
|
54
|
+
gate:
|
|
55
|
+
schema:
|
|
56
|
+
inline:
|
|
57
|
+
type: object
|
|
58
|
+
additionalProperties: false
|
|
59
|
+
properties:
|
|
60
|
+
decision: { type: string, enum: [approve, reject] }
|
|
61
|
+
required: [decision]
|
|
62
|
+
render:
|
|
63
|
+
inline: "Draft review for \"{{input.title}}\"?\n\nApproving posts this draft as a pull request comment. Kiln does not approve the pull request or merge it.\n\n{{draft.markdown}}"
|
|
64
|
+
produces: approval
|