@kody-ade/kody-engine 0.4.212-live.0 → 0.4.212
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/dist/bin/kody.js
CHANGED
|
@@ -1542,7 +1542,7 @@ var init_loadCoverageRules = __esm({
|
|
|
1542
1542
|
// package.json
|
|
1543
1543
|
var package_default = {
|
|
1544
1544
|
name: "@kody-ade/kody-engine",
|
|
1545
|
-
version: "0.4.212
|
|
1545
|
+
version: "0.4.212",
|
|
1546
1546
|
description: "kody \u2014 autonomous development engine. Single-session Claude Code agent behind a generic executor + declarative executable profiles.",
|
|
1547
1547
|
license: "MIT",
|
|
1548
1548
|
type: "module",
|
|
@@ -2517,9 +2517,26 @@ function listBuiltinJobs(root = getBuiltinJobsRoot()) {
|
|
|
2517
2517
|
if (!fs6.existsSync(root) || !fs6.statSync(root).isDirectory()) return [];
|
|
2518
2518
|
const out = [];
|
|
2519
2519
|
for (const ent of fs6.readdirSync(root, { withFileTypes: true })) {
|
|
2520
|
-
if (
|
|
2521
|
-
const
|
|
2522
|
-
|
|
2520
|
+
if (ent.name.startsWith("_") || ent.name.startsWith(".")) continue;
|
|
2521
|
+
const full = path6.join(root, ent.name);
|
|
2522
|
+
if (ent.isDirectory()) {
|
|
2523
|
+
const profilePath = path6.join(full, "profile.json");
|
|
2524
|
+
const promptPath = path6.join(full, "prompt.md");
|
|
2525
|
+
if (!fs6.existsSync(profilePath) || !fs6.statSync(profilePath).isFile()) continue;
|
|
2526
|
+
if (!fs6.existsSync(promptPath) || !fs6.statSync(promptPath).isFile()) continue;
|
|
2527
|
+
out.push({ slug: ent.name, dir: full, profilePath, promptPath });
|
|
2528
|
+
continue;
|
|
2529
|
+
}
|
|
2530
|
+
if (ent.isFile() && ent.name.endsWith(".md")) {
|
|
2531
|
+
const slug = ent.name.slice(0, -3);
|
|
2532
|
+
out.push({
|
|
2533
|
+
slug,
|
|
2534
|
+
dir: full,
|
|
2535
|
+
profilePath: "",
|
|
2536
|
+
promptPath: "",
|
|
2537
|
+
filePath: full
|
|
2538
|
+
});
|
|
2539
|
+
}
|
|
2523
2540
|
}
|
|
2524
2541
|
out.sort((a, b) => a.slug.localeCompare(b.slug));
|
|
2525
2542
|
return out;
|
|
@@ -9792,14 +9809,30 @@ function performInit(cwd, force) {
|
|
|
9792
9809
|
const jobsDir = path27.join(cwd, ".kody", "duties");
|
|
9793
9810
|
fs30.mkdirSync(jobsDir, { recursive: true });
|
|
9794
9811
|
for (const job of builtinJobs) {
|
|
9795
|
-
|
|
9796
|
-
|
|
9797
|
-
|
|
9798
|
-
|
|
9812
|
+
if (job.filePath && !job.profilePath) {
|
|
9813
|
+
const rel = path27.join(".kody", "duties", `${job.slug}.md`);
|
|
9814
|
+
const target = path27.join(cwd, rel);
|
|
9815
|
+
if (fs30.existsSync(target) && !force) {
|
|
9816
|
+
skipped.push(rel);
|
|
9817
|
+
continue;
|
|
9818
|
+
}
|
|
9819
|
+
fs30.writeFileSync(target, fs30.readFileSync(job.filePath, "utf-8"));
|
|
9820
|
+
wrote.push(rel);
|
|
9821
|
+
continue;
|
|
9822
|
+
}
|
|
9823
|
+
const targetDir = path27.join(jobsDir, job.slug);
|
|
9824
|
+
const relProfile = path27.join(".kody", "duties", job.slug, "profile.json");
|
|
9825
|
+
const relPrompt = path27.join(".kody", "duties", job.slug, "prompt.md");
|
|
9826
|
+
if (fs30.existsSync(targetDir) && fs30.existsSync(path27.join(targetDir, "profile.json")) && !force) {
|
|
9827
|
+
skipped.push(relProfile);
|
|
9828
|
+
skipped.push(relPrompt);
|
|
9799
9829
|
continue;
|
|
9800
9830
|
}
|
|
9801
|
-
fs30.
|
|
9802
|
-
|
|
9831
|
+
fs30.mkdirSync(targetDir, { recursive: true });
|
|
9832
|
+
fs30.writeFileSync(path27.join(targetDir, "profile.json"), fs30.readFileSync(job.profilePath, "utf-8"));
|
|
9833
|
+
fs30.writeFileSync(path27.join(targetDir, "prompt.md"), fs30.readFileSync(job.promptPath, "utf-8"));
|
|
9834
|
+
wrote.push(relProfile);
|
|
9835
|
+
wrote.push(relPrompt);
|
|
9803
9836
|
}
|
|
9804
9837
|
}
|
|
9805
9838
|
const staffDir = path27.join(cwd, ".kody", "staff");
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "watch-stale-prs",
|
|
3
|
+
"role": "primitive",
|
|
4
|
+
"describe": "Weekly digest of open PRs that haven't been touched in a while. Writes a markdown report at .kody/reports/watch-stale-prs.md (surfaced by the dashboard's /reports page).",
|
|
5
|
+
"kind": "oneshot",
|
|
6
|
+
"staff": "kody",
|
|
7
|
+
"every": "7d",
|
|
8
|
+
"inputs": [],
|
|
9
|
+
"claudeCode": {
|
|
10
|
+
"model": "inherit",
|
|
11
|
+
"permissionMode": "default",
|
|
12
|
+
"maxTurns": 100,
|
|
13
|
+
"maxThinkingTokens": null,
|
|
14
|
+
"systemPromptAppend": null,
|
|
15
|
+
"enableSubmitTool": true,
|
|
16
|
+
"tools": ["Bash", "Read", "mcp__kody-submit"],
|
|
17
|
+
"hooks": [],
|
|
18
|
+
"skills": [],
|
|
19
|
+
"commands": [],
|
|
20
|
+
"subagents": [],
|
|
21
|
+
"plugins": [],
|
|
22
|
+
"mcpServers": []
|
|
23
|
+
},
|
|
24
|
+
"cliTools": [
|
|
25
|
+
{
|
|
26
|
+
"name": "gh",
|
|
27
|
+
"install": {
|
|
28
|
+
"required": true,
|
|
29
|
+
"checkCommand": "command -v gh"
|
|
30
|
+
},
|
|
31
|
+
"verify": "gh auth status",
|
|
32
|
+
"usage": "Use `gh` for all GitHub actions: `gh pr list --state open --limit 100 --json number,title,url,updatedAt,author` to enumerate candidate PRs, `gh api -X GET /repos/{owner}/{repo}/contents/.kody/reports/watch-stale-prs.md` to fetch the existing file's `sha` for an update, `gh api -X PUT /repos/{owner}/{repo}/contents/.kody/reports/watch-stale-prs.md` to write the report (base64-encoded `content`, `message`, and `sha` when updating). NEVER edit files in the working tree.",
|
|
33
|
+
"allowedUses": ["pr", "api"]
|
|
34
|
+
}
|
|
35
|
+
],
|
|
36
|
+
"scripts": {
|
|
37
|
+
"preflight": [
|
|
38
|
+
{ "script": "loadDutyState" },
|
|
39
|
+
{ "script": "composePrompt" }
|
|
40
|
+
],
|
|
41
|
+
"postflight": [
|
|
42
|
+
{ "script": "parseJobStateFromAgentResult", "with": { "fenceLabel": "kody-job-next-state" } },
|
|
43
|
+
{ "script": "writeJobStateFile" }
|
|
44
|
+
]
|
|
45
|
+
}
|
|
46
|
+
}
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
{{dutyReference}}
|
|
2
|
+
|
|
3
|
+
You are **{{staffTitle}}** (staff `{{staffSlug}}`), running the **watch-stale-prs** duty — a weekly digest of open PRs that haven't been touched in a while. You do **not** touch code, do **not** commit, and do **not** edit files. You coordinate by inspecting GitHub state via `gh` and writing a single report file at `.kody/reports/{{dutySlug}}.md`.
|
|
4
|
+
|
|
5
|
+
## Who you are — staff persona (authoritative identity)
|
|
6
|
+
|
|
7
|
+
The duty assigns you, staff **`{{staffSlug}}`**, as its executor. This persona defines *who* runs the duty: your authority, doctrine, voice, and hard limits. Where the persona's restrictions are stricter than the duty body, **the persona wins** — a duty can never grant you authority your staff persona withholds.
|
|
8
|
+
|
|
9
|
+
{{workerPersona}}
|
|
10
|
+
|
|
11
|
+
## The duty
|
|
12
|
+
|
|
13
|
+
Slug **`{{dutySlug}}`** — *{{dutyTitle}}*, assigned to staff **`{{staffSlug}}`**, running on executable **`{{executableSlug}}`**. Cadence is enforced by the engine via the `every: 7d` profile field — this duty only fires once per 7 days regardless of how often `duty-scheduler` wakes. No prose cadence guard needed.
|
|
14
|
+
|
|
15
|
+
**Addressing the operator.** When the duty tells you to @-mention the operator, the exact handle(s) to use are: {{mentions}}. Copy that string **verbatim** — never invent, abbreviate, guess, or retype a GitHub username. If the line above is blank, the duty declared no operator; post without a mention.
|
|
16
|
+
|
|
17
|
+
### What "stale" means
|
|
18
|
+
|
|
19
|
+
Find every open PR untouched for **≥ 7 days** and write a report listing them, sorted by staleness (oldest first). When there are no stale PRs, write a short "all clear" report so operators know the check ran.
|
|
20
|
+
|
|
21
|
+
A PR is stale if:
|
|
22
|
+
|
|
23
|
+
- `state` is `OPEN`, AND
|
|
24
|
+
- `updatedAt` is more than 7 days before now.
|
|
25
|
+
|
|
26
|
+
Use `gh pr list --state open --limit 100 --json number,title,url,updatedAt,author` to enumerate. Filter and sort client-side; do not call `gh` once per PR.
|
|
27
|
+
|
|
28
|
+
### Report shape
|
|
29
|
+
|
|
30
|
+
Write to `.kody/reports/watch-stale-prs.md`. Overwrite each run.
|
|
31
|
+
|
|
32
|
+
When stale PRs exist:
|
|
33
|
+
|
|
34
|
+
```markdown
|
|
35
|
+
# Stale PRs — <ISO date>
|
|
36
|
+
|
|
37
|
+
🟡 <N> PR(s) untouched for > 7 days.
|
|
38
|
+
|
|
39
|
+
| # | Title | Author | Days stale | Updated |
|
|
40
|
+
|---|-------|--------|------------|---------|
|
|
41
|
+
| [#123](url) | <title> | @user | 14 | 2026-04-25 |
|
|
42
|
+
| ... | | | | |
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
When none:
|
|
46
|
+
|
|
47
|
+
```markdown
|
|
48
|
+
# Stale PRs — <ISO date>
|
|
49
|
+
|
|
50
|
+
🟢 No open PRs untouched for more than 7 days.
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
Truncate to the 50 oldest if the list is longer; append a final line
|
|
54
|
+
`> … and N more not shown`.
|
|
55
|
+
|
|
56
|
+
## Allowed Commands
|
|
57
|
+
|
|
58
|
+
- `gh pr list --state open --limit 100 --json number,title,url,updatedAt,author`
|
|
59
|
+
- `gh api -X GET /repos/{owner}/{repo}/contents/.kody/reports/watch-stale-prs.md`
|
|
60
|
+
— only to fetch the existing file's `sha` for an update.
|
|
61
|
+
- `gh api -X PUT /repos/{owner}/{repo}/contents/.kody/reports/watch-stale-prs.md`
|
|
62
|
+
— to write the report (base64-encoded `content`, `message`, and `sha`
|
|
63
|
+
when updating). This is the **only** permitted write path for this job.
|
|
64
|
+
|
|
65
|
+
## Restrictions
|
|
66
|
+
|
|
67
|
+
- Never edit, create, or delete any other file in the working tree.
|
|
68
|
+
- Never `git commit`, `git push`, or open a PR.
|
|
69
|
+
- Never post comments on PRs or issues; the report file is the only
|
|
70
|
+
output channel.
|
|
71
|
+
- Never call `gh` per-PR — one `pr list` is enough.
|
|
72
|
+
|
|
73
|
+
## State
|
|
74
|
+
|
|
75
|
+
`cursor`: always `"idle"` — this job has no phases; each fire is a
|
|
76
|
+
one-shot report write.
|
|
77
|
+
|
|
78
|
+
`data`:
|
|
79
|
+
|
|
80
|
+
- `lastStaleCount` (number) — how many stale PRs were in the most recent
|
|
81
|
+
report. Diagnostic only; the engine ignores it.
|
|
82
|
+
|
|
83
|
+
(Engine-managed fields like `lastFiredAt` live under `data` automatically;
|
|
84
|
+
do not write or rely on them from the prompt.)
|
|
85
|
+
|
|
86
|
+
`done`: always `false` — this job is evergreen.
|
|
87
|
+
|
|
88
|
+
## What to do on this tick
|
|
89
|
+
|
|
90
|
+
1. **Check `done`.** If the prior state has `done: true`, emit the same state back unchanged and exit without any action.
|
|
91
|
+
2. **Enumerate stale PRs** with `gh pr list`.
|
|
92
|
+
3. **Write the report** to `.kody/reports/{{dutySlug}}.md` via `gh api -X PUT`.
|
|
93
|
+
4. **Submit the new state** by calling the `submit_state` tool with `cursor: "idle"`, the `lastStaleCount` in `data`, and `done: false`.
|
|
94
|
+
|
|
95
|
+
The duty cadence (`every: 7d`) is enforced by the engine — do not re-arm it from the prompt.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kody-ade/kody-engine",
|
|
3
|
-
"version": "0.4.212
|
|
3
|
+
"version": "0.4.212",
|
|
4
4
|
"description": "kody — autonomous development engine. Single-session Claude Code agent behind a generic executor + declarative executable profiles.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -1,90 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
every: 7d
|
|
3
|
-
staff: kody
|
|
4
|
-
---
|
|
5
|
-
|
|
6
|
-
# watch-stale-prs
|
|
7
|
-
|
|
8
|
-
> Weekly digest of open PRs that haven't been touched in a while. Writes a
|
|
9
|
-
> markdown report at `.kody/reports/watch-stale-prs.md` (surfaced by the
|
|
10
|
-
> dashboard's `/reports` page).
|
|
11
|
-
>
|
|
12
|
-
> Cadence is enforced by the engine via the `every: 7d` frontmatter — this
|
|
13
|
-
> file only fires once per 7 days regardless of how often `duty-scheduler`
|
|
14
|
-
> wakes. No prose cadence guard needed.
|
|
15
|
-
|
|
16
|
-
## Job
|
|
17
|
-
|
|
18
|
-
Find every open PR untouched for **≥ 7 days** and write a report listing
|
|
19
|
-
them, sorted by staleness (oldest first). When there are no stale PRs,
|
|
20
|
-
write a short "all clear" report so operators know the check ran.
|
|
21
|
-
|
|
22
|
-
### What "stale" means
|
|
23
|
-
|
|
24
|
-
A PR is stale if:
|
|
25
|
-
|
|
26
|
-
- `state` is `OPEN`, AND
|
|
27
|
-
- `updatedAt` is more than 7 days before now.
|
|
28
|
-
|
|
29
|
-
Use `gh pr list --state open --limit 100 --json number,title,url,updatedAt,author`
|
|
30
|
-
to enumerate. Filter and sort client-side; do not call `gh` once per PR.
|
|
31
|
-
|
|
32
|
-
### Report shape
|
|
33
|
-
|
|
34
|
-
Write to `.kody/reports/watch-stale-prs.md`. Overwrite each run.
|
|
35
|
-
|
|
36
|
-
When stale PRs exist:
|
|
37
|
-
|
|
38
|
-
```markdown
|
|
39
|
-
# Stale PRs — <ISO date>
|
|
40
|
-
|
|
41
|
-
🟡 <N> PR(s) untouched for > 7 days.
|
|
42
|
-
|
|
43
|
-
| # | Title | Author | Days stale | Updated |
|
|
44
|
-
|---|-------|--------|------------|---------|
|
|
45
|
-
| [#123](url) | <title> | @user | 14 | 2026-04-25 |
|
|
46
|
-
| ... | | | | |
|
|
47
|
-
```
|
|
48
|
-
|
|
49
|
-
When none:
|
|
50
|
-
|
|
51
|
-
```markdown
|
|
52
|
-
# Stale PRs — <ISO date>
|
|
53
|
-
|
|
54
|
-
🟢 No open PRs untouched for more than 7 days.
|
|
55
|
-
```
|
|
56
|
-
|
|
57
|
-
Truncate to the 50 oldest if the list is longer; append a final line
|
|
58
|
-
`> … and N more not shown`.
|
|
59
|
-
|
|
60
|
-
## Allowed Commands
|
|
61
|
-
|
|
62
|
-
- `gh pr list --state open --limit 100 --json number,title,url,updatedAt,author`
|
|
63
|
-
- `gh api -X GET /repos/{owner}/{repo}/contents/.kody/reports/watch-stale-prs.md`
|
|
64
|
-
— only to fetch the existing file's `sha` for an update.
|
|
65
|
-
- `gh api -X PUT /repos/{owner}/{repo}/contents/.kody/reports/watch-stale-prs.md`
|
|
66
|
-
— to write the report (base64-encoded `content`, `message`, and `sha`
|
|
67
|
-
when updating). This is the **only** permitted write path for this job.
|
|
68
|
-
|
|
69
|
-
## Restrictions
|
|
70
|
-
|
|
71
|
-
- Never edit, create, or delete any other file in the working tree.
|
|
72
|
-
- Never `git commit`, `git push`, or open a PR.
|
|
73
|
-
- Never post comments on PRs or issues; the report file is the only
|
|
74
|
-
output channel.
|
|
75
|
-
- Never call `gh` per-PR — one `pr list` is enough.
|
|
76
|
-
|
|
77
|
-
## State
|
|
78
|
-
|
|
79
|
-
`cursor`: always `"idle"` — this job has no phases; each fire is a
|
|
80
|
-
one-shot report write.
|
|
81
|
-
|
|
82
|
-
`data`:
|
|
83
|
-
|
|
84
|
-
- `lastStaleCount` (number) — how many stale PRs were in the most recent
|
|
85
|
-
report. Diagnostic only; the engine ignores it.
|
|
86
|
-
|
|
87
|
-
(Engine-managed fields like `lastFiredAt` live under `data` automatically;
|
|
88
|
-
do not write or rely on them from the prompt.)
|
|
89
|
-
|
|
90
|
-
`done`: always `false` — this job is evergreen.
|