@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-live.0",
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 (!ent.isFile() || !ent.name.endsWith(".md")) continue;
2521
- const slug = ent.name.slice(0, -3);
2522
- out.push({ slug, filePath: path6.join(root, ent.name) });
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
- const rel = path27.join(".kody", "duties", `${job.slug}.md`);
9796
- const target = path27.join(cwd, rel);
9797
- if (fs30.existsSync(target) && !force) {
9798
- skipped.push(rel);
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.writeFileSync(target, fs30.readFileSync(job.filePath, "utf-8"));
9802
- wrote.push(rel);
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-live.0",
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.