jackherd 1.8.1 → 1.10.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/CHANGELOG.md +60 -0
- package/INSTALL.md +3 -1
- package/README.md +75 -64
- package/dist/{chunk-OU2KALXP.js → chunk-5MQBCUQ5.js} +24 -4
- package/dist/config.d.ts +45 -4
- package/dist/config.js +84 -27
- package/dist/plan-format.d.ts +63 -7
- package/dist/plan-format.js +66 -12
- package/docs/workflow-dark.svg +67 -63
- package/docs/workflow.svg +67 -63
- package/herdr-plugin/herdr-plugin.toml +1 -1
- package/install.sh +1 -1
- package/kit/hooks/ask-rules.json +15 -0
- package/kit/hooks/hooks/approval-gate/index.ts +22 -4
- package/kit/hooks/hooks/approval-gate/run.ts +29 -6
- package/kit/hooks/hooks/approval-gate/subagent.ts +18 -0
- package/kit/hooks/hooks/ask-hint/decision.ts +82 -14
- package/kit/hooks/hooks/ask-hint/index.ts +15 -19
- package/kit/hooks/hooks/ask-hint/settings.ts +3 -18
- package/kit/hooks/hooks/git-guard/decision.ts +50 -102
- package/kit/hooks/hooks/merge-guard/always-ask.ts +63 -0
- package/kit/hooks/hooks/merge-guard/{plan-approval-settings.ts → board-settings.ts} +21 -67
- package/kit/hooks/hooks/merge-guard/check-free.ts +20 -0
- package/kit/hooks/hooks/merge-guard/decision.ts +127 -140
- package/kit/hooks/hooks/merge-guard/index.ts +6 -3
- package/kit/hooks/hooks/merge-guard/lane-plan.ts +79 -0
- package/kit/hooks/hooks/merge-guard/run.ts +59 -54
- package/kit/hooks/hooks/merge-guard/settings.ts +13 -1
- package/kit/hooks/hooks/merge-guard/standing-approval.ts +142 -0
- package/kit/hooks/hooks/open-question/index.ts +26 -0
- package/kit/hooks/hooks/open-question/record.ts +135 -0
- package/kit/hooks/hooks/open-question/run.ts +52 -0
- package/kit/hooks/hooks/open-question/store.ts +39 -0
- package/kit/hooks/hooks/sent-file/index.ts +19 -0
- package/kit/hooks/hooks/sent-file/record.ts +128 -0
- package/kit/hooks/hooks/sent-file/run.ts +48 -0
- package/kit/hooks/hooks/sent-file/store.ts +9 -0
- package/kit/hooks/hooks/shared/board-lanes.ts +15 -2
- package/kit/hooks/hooks/shared/config.ts +7 -0
- package/kit/hooks/hooks/shared/dialog-answers.ts +9 -9
- package/kit/hooks/hooks/shared/files.ts +7 -0
- package/kit/hooks/hooks/shared/lane.ts +1 -1
- package/kit/hooks/hooks/shared/newest-verdict.ts +10 -0
- package/kit/hooks/hooks/shared/private-directory.ts +56 -9
- package/kit/hooks/hooks/shared/program-position.ts +2 -75
- package/kit/hooks/hooks/shared/shell-aliases.ts +1 -71
- package/kit/hooks/hooks/{ask-hint → shared}/transcript.ts +37 -6
- package/kit/hooks/hooks/{merge-guard → shared}/xargs-program.ts +10 -8
- package/kit/hooks/hooks/task-hint/decision.ts +49 -0
- package/kit/hooks/hooks/task-hint/index.ts +79 -0
- package/kit/hooks/hooks/task-hint/run.ts +62 -0
- package/kit/hooks/hooks/task-hint/store.ts +51 -0
- package/kit/hooks/hooks.json +21 -4
- package/kit/hooks/statusline.sh +1 -1
- package/kit/review/agents/skill-review.md +34 -0
- package/kit/review/skills/pre-commit/SKILL.md +1 -1
- package/kit/workflow/skills/follow/SKILL.md +1 -8
- package/kit/workflow/skills/implement/SKILL.md +10 -6
- package/kit/workflow/skills/orchestrate/SKILL.md +213 -412
- package/kit/workflow/skills/orchestrate/handover/decision.ts +43 -8
- package/kit/workflow/skills/orchestrate/handover/index.ts +32 -4
- package/kit/workflow/skills/orchestrate/handover/standing-approval.ts +84 -0
- package/kit/workflow/skills/orchestrate/references/acceptance.md +15 -0
- package/kit/workflow/skills/orchestrate/references/close-lane.md +17 -0
- package/kit/workflow/skills/orchestrate/references/coordinator-handover.md +43 -17
- package/kit/workflow/skills/orchestrate/references/draft-review.md +19 -0
- package/kit/workflow/skills/orchestrate/references/events.md +86 -0
- package/kit/workflow/skills/orchestrate/references/herd.md +6 -6
- package/kit/workflow/skills/orchestrate/references/lane-handover.md +18 -0
- package/kit/workflow/skills/orchestrate/references/lane-session.md +25 -0
- package/kit/workflow/skills/orchestrate/references/lane-setup.md +37 -0
- package/kit/workflow/skills/orchestrate/references/plan-commit.md +22 -10
- package/kit/workflow/skills/orchestrate/references/sensitive-input.md +5 -7
- package/kit/workflow/skills/plan/SKILL.md +6 -5
- package/kit/workflow/skills/plan/references/template-English.md +4 -4
- package/kit/workflow/skills/plan/references/template-German.md +4 -4
- package/package.json +4 -1
- package/recipes/README.md +2 -1
- package/recipes/sources.md +1 -1
- package/schemas/jackherd.schema.json +85 -7
- package/src/check/agent-text-reviewers.ts +23 -0
- package/src/check/command.ts +2 -0
- package/src/check/plan-structure-check.ts +49 -2
- package/src/check/plan.ts +8 -1
- package/src/check/schema.ts +9 -0
- package/src/check/skill-budget-defaults.ts +55 -0
- package/src/check/skill-budgets.ts +185 -0
- package/src/cli.ts +4 -0
- package/src/config/auto-window.ts +8 -0
- package/src/config/link-kinds.ts +7 -1
- package/src/config/schema.ts +80 -26
- package/src/context/fill.ts +12 -0
- package/src/context/session-log.ts +43 -1
- package/src/lane/close-board.ts +106 -0
- package/src/lane/close-check.ts +183 -0
- package/src/lane/close-command-line.ts +11 -0
- package/src/lane/close-command.ts +217 -0
- package/src/lane/close-options.ts +43 -0
- package/src/lane/close-survey.ts +83 -0
- package/src/lane/close.ts +141 -0
- package/src/lane/command.ts +13 -0
- package/src/lane-prompt/build.ts +74 -0
- package/src/lane-prompt/command.ts +87 -0
- package/src/lane-prompt/input.ts +116 -0
- package/src/lane-prompt/options.ts +68 -0
- package/src/lane-prompt/texts.ts +101 -0
- package/src/plan-format/clock.ts +12 -0
- package/src/plan-format/dependencies.ts +9 -9
- package/src/plan-format/index.ts +1 -0
- package/src/plan-format/lanes.ts +30 -5
- package/src/plan-format/short-names.ts +71 -0
- package/src/plan-format/terminal-text.ts +4 -0
- package/src/plan-format/waiting.ts +53 -0
- package/src/plans/active-tasks.ts +60 -0
- package/src/plans/appointment-rows.ts +59 -0
- package/src/plans/ask-coordinator.ts +77 -0
- package/src/plans/ask-target.ts +25 -0
- package/src/plans/child-stop.ts +51 -0
- package/src/plans/closable-records.ts +34 -0
- package/src/plans/command.ts +3 -2
- package/src/plans/current-phase.ts +17 -7
- package/src/plans/current-task.ts +63 -5
- package/src/plans/fetch.ts +26 -3
- package/src/plans/git.ts +19 -5
- package/src/plans/herd-claim.ts +173 -0
- package/src/plans/herd-memory.ts +36 -25
- package/src/plans/lane-plans.ts +44 -13
- package/src/plans/lane-standing.ts +9 -4
- package/src/plans/lane-summary.ts +367 -92
- package/src/plans/lane-tickets.ts +15 -0
- package/src/plans/layout-phase.ts +80 -19
- package/src/plans/layout-summary.ts +163 -74
- package/src/plans/layout.ts +472 -114
- package/src/plans/link-chips.ts +1 -0
- package/src/plans/live.ts +119 -10
- package/src/plans/phase-ids.ts +8 -0
- package/src/plans/phase-models.ts +1 -1
- package/src/plans/phase-ranges.ts +45 -0
- package/src/plans/phase-source.ts +15 -0
- package/src/plans/plan-cache.ts +28 -0
- package/src/plans/plan-heads.ts +54 -0
- package/src/plans/pull-requests.ts +23 -2
- package/src/plans/question-records.ts +48 -0
- package/src/plans/questions-read.ts +13 -0
- package/src/plans/read-cache.ts +8 -0
- package/src/plans/record-id.ts +4 -0
- package/src/plans/restart-decision.ts +13 -4
- package/src/plans/selection.ts +117 -34
- package/src/plans/sent-files-read.ts +13 -0
- package/src/plans/sent-files.ts +114 -0
- package/src/plans/settings.ts +2 -1
- package/src/plans/signalled-phase.ts +42 -0
- package/src/plans/signals-read.ts +62 -0
- package/src/plans/snapshot.ts +279 -60
- package/src/plans/sprint-export.ts +11 -11
- package/src/plans/sprint-page.ts +5 -5
- package/src/plans/subagent-phases.ts +95 -0
- package/src/plans/subagent-tasks.ts +51 -0
- package/src/plans/subagents-read.ts +131 -0
- package/src/plans/subagents.ts +190 -0
- package/src/plans/supervisor.ts +14 -4
- package/src/plans/symbols.ts +3 -0
- package/src/plans/task-name.ts +34 -0
- package/src/plans/texts.ts +36 -14
- package/src/plans/unlisted-lanes.ts +10 -5
- package/src/plans/view.ts +20 -12
- package/src/plans/waiting-click.ts +231 -0
- package/src/plans/waiting-records.ts +39 -0
- package/src/plans/waiting-window.ts +8 -0
- package/src/preview/command.ts +105 -0
- package/src/preview/embed.ts +209 -0
- package/src/preview/images.ts +89 -0
- package/src/preview/open.ts +12 -0
- package/src/preview/options.ts +32 -0
- package/src/preview/page.ts +89 -0
- package/src/preview/render.ts +41 -0
- package/src/settled/board-row.ts +1 -2
- package/src/shared/is-record.ts +2 -0
- package/src/shared/private-location.ts +89 -0
- package/src/shared/private-records.ts +48 -0
- package/src/shared/stat-cache.ts +48 -0
- package/src/sync/kit-source.ts +29 -10
- package/src/sync/kit.ts +2 -0
- package/src/sync/manifest.ts +2 -0
- package/src/sync/plan-ask-rules.ts +94 -0
- package/src/sync/plan-hooks.ts +2 -0
- package/src/sync/render.ts +3 -3
- package/src/sync/settings-hooks.ts +4 -1
- package/src/sync/sync-plan.ts +1 -0
- package/src/sync/sync.ts +24 -3
- package/src/task-signals/agent.ts +15 -0
- package/src/task-signals/claude-read.ts +89 -0
- package/src/task-signals/claude-signals.ts +112 -0
- package/src/task-signals/command.ts +71 -0
- package/src/task-signals/fixtures/session.jsonl +7 -0
- package/src/task-signals/matcher.ts +96 -0
- package/src/task-signals/record-store.ts +40 -0
- package/src/task-signals/record.ts +68 -0
- package/src/task-signals/text.ts +13 -0
- package/src/task-signals/types.ts +14 -0
- package/src/terminal/open.ts +13 -6
- package/src/terminal/text.ts +16 -4
- package/src/terminal/width.ts +2 -1
- package/src/version/skill-diff.ts +46 -0
- package/src/vocabulary/index.ts +44 -6
- package/src/waiting/command.ts +50 -0
- package/src/watch/appointments.ts +2 -4
- package/src/watch/approvals.ts +2 -2
- package/src/watch/asking-lanes.ts +40 -0
- package/src/watch/base-tip.ts +11 -0
- package/src/watch/command.ts +401 -90
- package/src/watch/failed-tests.ts +56 -10
- package/src/watch/failure-read.ts +18 -6
- package/src/watch/failures.ts +29 -5
- package/src/watch/feedback.ts +1 -1
- package/src/watch/gh-process.ts +9 -3
- package/src/watch/heartbeat-progress.ts +6 -18
- package/src/watch/json-guards.ts +0 -3
- package/src/watch/kit-update.ts +28 -9
- package/src/watch/lane-fill.ts +1 -1
- package/src/watch/lane-model.ts +1 -1
- package/src/watch/lane-name.ts +6 -0
- package/src/watch/lane-parallel.ts +1 -1
- package/src/watch/lane-progress.ts +58 -14
- package/src/watch/lane-report-file.ts +20 -5
- package/src/watch/lane-report.ts +37 -5
- package/src/watch/lane-rest.ts +28 -0
- package/src/watch/lane-sources.ts +31 -3
- package/src/watch/main-checkout.ts +34 -0
- package/src/watch/plan-badges-read.ts +13 -7
- package/src/watch/plan-badges.ts +9 -2
- package/src/watch/previews.ts +1 -1
- package/src/watch/pull-requests.ts +8 -3
- package/src/watch/reference-paths.ts +87 -0
- package/src/watch/running-subagents.ts +43 -0
- package/src/watch/skill-change.ts +124 -32
- package/src/watch/source-change.ts +48 -0
- package/src/watch/source-path.ts +1 -1
- package/src/watch/sources.ts +7 -4
- package/src/watch/stream-output.ts +14 -8
- package/src/watch/task-parallel-auto.ts +208 -0
- package/src/watch/task-parallel-data-paths.ts +46 -0
- package/src/watch/task-parallel-input.ts +108 -0
- package/src/watch/task-parallel-read.ts +151 -0
- package/src/watch/task-parallel-touched.ts +39 -0
- package/src/watch/task-parallel.ts +235 -0
- package/src/watch/task-signal-missing.ts +69 -0
- package/src/watch/task-signal-read.ts +29 -0
- package/src/watch/texts.ts +10 -0
- package/src/watch/update-available.ts +6 -3
- package/src/watch/waiting-line.ts +19 -0
- package/src/watch/watch-events.ts +36 -1
- package/src/watch/watcher-lock.ts +25 -29
- package/src/watch/workflow-runs.ts +2 -1
- package/kit/hooks/hooks/merge-guard/plan-approval-record.ts +0 -23
- package/kit/hooks/hooks/merge-guard/plan-approval-sources.ts +0 -196
- package/kit/hooks/hooks/merge-guard/plan-approval.ts +0 -168
- package/kit/hooks/hooks/merge-guard/plan-growth.ts +0 -40
- package/kit/hooks/hooks/merge-guard/plan-pointers.ts +0 -194
- package/kit/hooks/hooks/shared/command-text-runners.ts +0 -71
- package/kit/hooks/hooks/shared/plan-open-phases.ts +0 -114
|
@@ -35,7 +35,9 @@ Skip this when the request already carries its decisions (a plan for a bug fix w
|
|
|
35
35
|
|
|
36
36
|
The closing documentation section reads `## N — …` with rows `N.1` to `N.5`: replace `N` with the number of that phase (`## 10 — …`, `10.1`). A literal `N` is no phase to the herd, which shows it as "not in the plan".
|
|
37
37
|
|
|
38
|
-
A checkbox moved on purpose to a later phase stays where it is, unticked, and ends in the target: `- [ ] Update the documentation → P9`. The herd counts it neither as open nor as done in its own phase and lists it as open in phase 9
|
|
38
|
+
A checkbox moved on purpose to a later phase stays where it is, unticked, and ends in the target: `- [ ] Update the documentation → P9`. The herd counts it neither as open nor as done in its own phase and lists it as open in phase 9. The arrow stands only at the end of the line. Once a phase's tasks are ticked on the base branch, every box still open in it, gate boxes included, is ticked or moved on this way; `jh check` checks both.
|
|
39
|
+
|
|
40
|
+
A task starts with its short name: `- [ ] **Name**: …` (a review-gate item keeps its own form). The name has 40 characters at most and names the subject and the result, what is different afterwards (`Heartbeat shows progress without ticks`, `` `ask-hint` finds questions anywhere ``); the how, the conditions, the origin and the evidence follow the colon. A phase's title is its name, its context goes into the origin line. A task the user adds later: `- [ ] **Name**: … (User <DD.MM.> <HH:MM>)`.
|
|
39
41
|
|
|
40
42
|
What the template's tables mean:
|
|
41
43
|
|
|
@@ -67,7 +69,7 @@ Every phase gets the review gate block from the template at its end. Add the rev
|
|
|
67
69
|
- **Shared code checked:** For every planned component it is documented why it is built new instead of reused or extended.
|
|
68
70
|
- **Tests defined:** The tests section is filled in or carries an explicit rationale why none are needed (decision tree in `.claude/rules/kit/testing.md`).
|
|
69
71
|
- **Model recommendations defined:** `## {{kit.heading.implementation}}` starts with the model table, one row per phase, justified by error cost × complexity.
|
|
70
|
-
- **Parallelism defined (3+ phases):** the dependencies table follows it
|
|
72
|
+
- **Parallelism defined (3+ phases):** the dependencies table follows it, a row for every phase, one added later too. Every migration, schema bump and new event of a phase is a serial marker, every shared file stands under {{kit.heading.writes}}; otherwise `/implement` starts two phases that collide.
|
|
71
73
|
- **arc42 check (after the plan exists):** apply the filter in `.claude/rules/kit/arc42.md` to the finished plan and **ask the user concretely** which sections should be extended. On "yes", add a concrete task to `## {{kit.heading.documentation}}`.
|
|
72
74
|
- **Architecture check (after the plan exists):** apply the filter in `.claude/rules/kit/architecture-files.md` — new ownership, a new invariant or an accepted risk each trigger a concrete question about the unit's `ARCHITECTURE.md`.
|
|
73
75
|
- **arc42 closing phase (3+ phases or a new service/package):** end the plan with the architecture documentation phase from the template. Add arc42 sections beyond it only when they deliver real value.
|
|
@@ -94,9 +96,8 @@ Derive the rows from the dependencies table and the model table, nothing else:
|
|
|
94
96
|
- **Plan:** a Markdown link to the plan, its path relative to the board's directory (`../<file>.md` for a plan
|
|
95
97
|
directly under `{{kit.planDirectory}}`).
|
|
96
98
|
Plans stay where they are; the row only links them.
|
|
97
|
-
- **Lane name:** short kebab case, unique on the board
|
|
98
|
-
|
|
99
|
-
watcher reporting the lane as `no agent`.
|
|
99
|
+
- **Lane name:** short kebab case, unique on the board; the worktree directory and the herdr agent carry the same name
|
|
100
|
+
(`/orchestrate` § 2).
|
|
100
101
|
- **Port:** `–`; the coordinator sets it when the lane starts, unless the project supplement assigns ports here.
|
|
101
102
|
|
|
102
103
|
Show the rows as the table they become: `## {{kit.heading.lanes}}` with the columns lane, port, plan, phases, starts
|
|
@@ -42,8 +42,8 @@ What changes concretely? Files, modules, flows.
|
|
|
42
42
|
|
|
43
43
|
### {{kit.heading.phase}} 1: ...
|
|
44
44
|
|
|
45
|
-
- [ ]
|
|
46
|
-
- [ ]
|
|
45
|
+
- [ ] **Name of step 1**: how, conditions, origin, evidence
|
|
46
|
+
- [ ] **Name of step 2**: how, conditions, origin, evidence
|
|
47
47
|
|
|
48
48
|
**Review gate {{kit.heading.phase}} 1:**
|
|
49
49
|
|
|
@@ -67,13 +67,13 @@ Which tests are needed? Decide with the decision tree in `.claude/rules/kit/test
|
|
|
67
67
|
|
|
68
68
|
What gets documented after completion?
|
|
69
69
|
|
|
70
|
-
- [ ] ...
|
|
70
|
+
- [ ] **Name**: ...
|
|
71
71
|
|
|
72
72
|
## Follow-ups
|
|
73
73
|
|
|
74
74
|
> Ideas that come up during the work: noted here, not built in this plan, presented together once the release PR is merged.
|
|
75
75
|
|
|
76
|
-
- [ ]
|
|
76
|
+
- [ ] **Name**: the idea in one sentence (User <DD.MM.> <HH:MM>, where it came up)
|
|
77
77
|
|
|
78
78
|
## Rejected Alternatives
|
|
79
79
|
|
|
@@ -42,8 +42,8 @@ Was ändert sich konkret? Dateien, Module, Flows.
|
|
|
42
42
|
|
|
43
43
|
### {{kit.heading.phase}} 1: ...
|
|
44
44
|
|
|
45
|
-
- [ ] Schritt 1
|
|
46
|
-
- [ ] Schritt 2
|
|
45
|
+
- [ ] **Name von Schritt 1**: Wie, Bedingungen, Herkunft, Beleg
|
|
46
|
+
- [ ] **Name von Schritt 2**: Wie, Bedingungen, Herkunft, Beleg
|
|
47
47
|
|
|
48
48
|
**Review-Gate {{kit.heading.phase}} 1:**
|
|
49
49
|
|
|
@@ -67,13 +67,13 @@ Welche Tests sind nötig? Entscheidung nach dem Entscheidungsbaum in `.claude/ru
|
|
|
67
67
|
|
|
68
68
|
Was wird nach Abschluss dokumentiert?
|
|
69
69
|
|
|
70
|
-
- [ ] ...
|
|
70
|
+
- [ ] **Name**: ...
|
|
71
71
|
|
|
72
72
|
## Follow-ups
|
|
73
73
|
|
|
74
74
|
> Ideen, die während der Umsetzung aufkommen: hier vorgemerkt, nicht in diesem Plan gebaut, gesammelt vorgelegt, sobald der Release-PR gemergt ist.
|
|
75
75
|
|
|
76
|
-
- [ ] Idee in einem Satz (User <TT.MM.> <HH:MM>, wo sie aufkam)
|
|
76
|
+
- [ ] **Name**: Idee in einem Satz (User <TT.MM.> <HH:MM>, wo sie aufkam)
|
|
77
77
|
|
|
78
78
|
## Verworfene Alternativen
|
|
79
79
|
|
package/package.json
CHANGED
|
@@ -1,13 +1,15 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "jackherd",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.10.0",
|
|
4
4
|
"keywords": [
|
|
5
5
|
"claude-code",
|
|
6
6
|
"coding-agents",
|
|
7
7
|
"ai-agents",
|
|
8
8
|
"agent-skills",
|
|
9
9
|
"subagents",
|
|
10
|
+
"multi-agent",
|
|
10
11
|
"orchestration",
|
|
12
|
+
"plan-driven",
|
|
11
13
|
"git-worktree",
|
|
12
14
|
"herdr",
|
|
13
15
|
"planning",
|
|
@@ -48,6 +50,7 @@
|
|
|
48
50
|
"!docs/gen",
|
|
49
51
|
"assets",
|
|
50
52
|
"!assets/icons/build.ts",
|
|
53
|
+
"!assets/icons/version.ts",
|
|
51
54
|
"!assets/branding/outline.ts",
|
|
52
55
|
"recipes",
|
|
53
56
|
"README.md",
|
package/recipes/README.md
CHANGED
|
@@ -15,7 +15,8 @@ Each recipe is one `watch.sources` entry for the jackherd watcher: put in your k
|
|
|
15
15
|
## Rules every recipe follows
|
|
16
16
|
|
|
17
17
|
- **A token never goes into an argument:** an argument shows in the process list. Where a tool keeps its own login, it is used; where a token sits in an environment variable, a small TypeScript script run by Bun (which runs wherever `jh` does) puts it from `process.env` straight into the request header.
|
|
18
|
-
- **A script
|
|
18
|
+
- **A script prints one JSON value on stdout and nothing else.**
|
|
19
|
+
- **A script fails with an exit code**, never with an empty answer the watcher would take for a source with nothing new, and it prints neither the token nor the body of a failed answer. A 200 that carries an `errors` list, as GraphQL answers, is a failure too. Every request and every tool call is bounded with `AbortSignal.timeout(20_000)`, well under the 30 seconds a source may run.
|
|
19
20
|
- **The scripts are files of their own** under [`sources/`](sources/). Copy one to `scripts/sources/<name>.ts` in your repository, the path the entry's `command` names. The closing `export {}` makes the file a module, so the type check accepts top-level `await` and the names do not clash between scripts.
|
|
20
21
|
- **A recipe that needs no script** (`gh …`, `curl` on a public page, `curl --netrc`) stays a direct command.
|
|
21
22
|
- **`bun` as the first word, never a path to it.** The watcher starts a source without a shell and reads `bun` to mean the Bun that runs the watcher itself, so the entry needs no absolute path, which would differ from machine to machine, even when Bun is not on the `PATH` (installed in `~/.bun/bin` only, say).
|
package/recipes/sources.md
CHANGED
|
@@ -36,7 +36,7 @@ Source reports are off unless the config lists `watch.sources`. The watcher cann
|
|
|
36
36
|
|
|
37
37
|
`items` is the path of the list in the output (without it the output is the list), `map` picks each entry's fields: `id` is required, `updatedAt` too unless a content field (`title`, `author`, `body`, `url`) or `reportOn` can tell a change, and `title`, `url`, `body`, `author` and `status` (a ticket's status, below) are optional; any further field you name (`priority`, `assignee`; a letter, then letters, digits and `_`) is read for `reportOn`. A path is `.` for the whole value or a chain of `.key`, `[n]` and `[-n]` (counted from the end), nothing more; for anything else, put a script in between.
|
|
38
38
|
|
|
39
|
-
What counts as news: an unknown `id` reports `new`; `updated` only when what you read changed, a short hash over `title`, `author`, `body` and `url`. A change of the time alone (a label, a sprint, a status) wakes nobody; where none of the four is mapped, `updatedAt` is the content, and then it is required. An entry whose `author` is in `ignoreAuthors` (case ignored) is recorded but wakes nobody, so your own comment does not. The first successful run of a source is a baseline, and the saved state holds per source only each id with its hash (with `reportOn` also the values of those fields, which may name people, such as an assignee), the 1000 seen most recently, so a restart repeats nothing and an entry that falls out of a time window and comes back is not new. Everything one GitHub read finds goes into one report, at most `reportLimit` entries per source (`5`), the rest as one line `=== source tickets +3 more`. The body shows its first line with text that is no Markdown heading (a bot's `## Code review` is skipped; a body of headings only shows the first), at most 160 characters, and the URL only as an `https:` URL without user name or password. `every` is in minutes, at least 1, `5` by default; the sources run with the GitHub read, so at most once a minute,
|
|
39
|
+
What counts as news: an unknown `id` reports `new`; `updated` only when what you read changed, a short hash over `title`, `author`, `body` and `url`. A change of the time alone (a label, a sprint, a status) wakes nobody; where none of the four is mapped, `updatedAt` is the content, and then it is required. An entry whose `author` is in `ignoreAuthors` (case ignored) is recorded but wakes nobody, so your own comment does not. The first successful run of a source is a baseline, and the saved state holds per source only each id with its hash (with `reportOn` also the values of those fields, which may name people, such as an assignee), the 1000 seen most recently, so a restart repeats nothing and an entry that falls out of a time window and comes back is not new. Everything one GitHub read finds goes into one report, at most `reportLimit` entries per source (`5`), the rest as one line `=== source tickets +3 more`. The body shows its first line with text that is no Markdown heading (a bot's `## Code review` is skipped; a body of headings only shows the first), at most 160 characters, and the URL only as an `https:` URL without user name or password. `every` is in minutes, at least 1, `5` by default; the sources run with the GitHub read, so at most once a minute. The saved state keeps when each source last ran, failed or not, so a restart runs a source only once its `every` has passed; a source the state does not know yet, a new one or one from a state written before that time was kept, runs at once.
|
|
40
40
|
|
|
41
41
|
**Report a status change.** `reportOn` names the mapped fields whose change reports, in place of the content hash: with `"reportOn": ["status"]` a ticket that moves from one column to the next wakes the coordinator, and a new comment alone does not. The report names each changed field with its old and new value, cut to 60 characters, `(empty)` for none, in one line; the body follows only when `body` is one of the changed fields. An unknown `id` still reports `new`, and `ignoreAuthors`, `reportLimit` and the one report per read stay as they are. `status` is just a field name: any mapped field but `id` may be listed, including `title` or `body`.
|
|
42
42
|
|
|
@@ -178,6 +178,17 @@
|
|
|
178
178
|
},
|
|
179
179
|
"additionalProperties": false
|
|
180
180
|
},
|
|
181
|
+
"preview": {
|
|
182
|
+
"default": {},
|
|
183
|
+
"type": "object",
|
|
184
|
+
"properties": {
|
|
185
|
+
"publish": {
|
|
186
|
+
"default": true,
|
|
187
|
+
"type": "boolean"
|
|
188
|
+
}
|
|
189
|
+
},
|
|
190
|
+
"additionalProperties": false
|
|
191
|
+
},
|
|
181
192
|
"plans": {
|
|
182
193
|
"default": {},
|
|
183
194
|
"type": "object",
|
|
@@ -270,13 +281,13 @@
|
|
|
270
281
|
"type": "object",
|
|
271
282
|
"properties": {
|
|
272
283
|
"warnTokens": {
|
|
273
|
-
"default":
|
|
284
|
+
"default": 350000,
|
|
274
285
|
"type": "integer",
|
|
275
286
|
"exclusiveMinimum": 0,
|
|
276
287
|
"maximum": 9007199254740991
|
|
277
288
|
},
|
|
278
289
|
"alertTokens": {
|
|
279
|
-
"default":
|
|
290
|
+
"default": 500000,
|
|
280
291
|
"type": "integer",
|
|
281
292
|
"exclusiveMinimum": 0,
|
|
282
293
|
"maximum": 9007199254740991
|
|
@@ -361,6 +372,45 @@
|
|
|
361
372
|
},
|
|
362
373
|
"additionalProperties": false
|
|
363
374
|
},
|
|
375
|
+
"parallelTasks": {
|
|
376
|
+
"default": {},
|
|
377
|
+
"type": "object",
|
|
378
|
+
"properties": {
|
|
379
|
+
"maxTokens": {
|
|
380
|
+
"default": 100000,
|
|
381
|
+
"type": "integer",
|
|
382
|
+
"exclusiveMinimum": 0,
|
|
383
|
+
"maximum": 9007199254740991
|
|
384
|
+
},
|
|
385
|
+
"auto": {
|
|
386
|
+
"type": "object",
|
|
387
|
+
"properties": {
|
|
388
|
+
"since": {
|
|
389
|
+
"type": "string",
|
|
390
|
+
"format": "date",
|
|
391
|
+
"pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$"
|
|
392
|
+
},
|
|
393
|
+
"until": {
|
|
394
|
+
"type": "string",
|
|
395
|
+
"format": "date",
|
|
396
|
+
"pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))$"
|
|
397
|
+
}
|
|
398
|
+
},
|
|
399
|
+
"required": [
|
|
400
|
+
"since",
|
|
401
|
+
"until"
|
|
402
|
+
],
|
|
403
|
+
"additionalProperties": false
|
|
404
|
+
}
|
|
405
|
+
},
|
|
406
|
+
"additionalProperties": false
|
|
407
|
+
},
|
|
408
|
+
"taskSignalMinutes": {
|
|
409
|
+
"default": 10,
|
|
410
|
+
"type": "integer",
|
|
411
|
+
"exclusiveMinimum": 0,
|
|
412
|
+
"maximum": 9007199254740991
|
|
413
|
+
},
|
|
364
414
|
"previews": {
|
|
365
415
|
"type": "object",
|
|
366
416
|
"properties": {
|
|
@@ -491,9 +541,7 @@
|
|
|
491
541
|
"commands": {
|
|
492
542
|
"default": [
|
|
493
543
|
"gh pr merge",
|
|
494
|
-
"gh workflow run"
|
|
495
|
-
"gh run rerun",
|
|
496
|
-
"gh api"
|
|
544
|
+
"gh workflow run"
|
|
497
545
|
],
|
|
498
546
|
"type": "array",
|
|
499
547
|
"items": {
|
|
@@ -531,12 +579,26 @@
|
|
|
531
579
|
},
|
|
532
580
|
"additionalProperties": false
|
|
533
581
|
},
|
|
582
|
+
"alwaysAsk": {
|
|
583
|
+
"default": [],
|
|
584
|
+
"type": "array",
|
|
585
|
+
"items": {
|
|
586
|
+
"type": "string",
|
|
587
|
+
"pattern": "^[A-Za-z0-9_.*/-]+$"
|
|
588
|
+
}
|
|
589
|
+
},
|
|
590
|
+
"requiredChecks": {
|
|
591
|
+
"type": "array",
|
|
592
|
+
"items": {
|
|
593
|
+
"type": "string",
|
|
594
|
+
"maxLength": 200
|
|
595
|
+
}
|
|
596
|
+
},
|
|
534
597
|
"planApproval": {
|
|
535
|
-
"
|
|
598
|
+
"deprecated": true,
|
|
536
599
|
"type": "object",
|
|
537
600
|
"properties": {
|
|
538
601
|
"exceptPaths": {
|
|
539
|
-
"default": [],
|
|
540
602
|
"type": "array",
|
|
541
603
|
"items": {
|
|
542
604
|
"type": "string",
|
|
@@ -578,6 +640,10 @@
|
|
|
578
640
|
"askUserQuestion": {
|
|
579
641
|
"default": true,
|
|
580
642
|
"type": "boolean"
|
|
643
|
+
},
|
|
644
|
+
"taskSignal": {
|
|
645
|
+
"default": true,
|
|
646
|
+
"type": "boolean"
|
|
581
647
|
}
|
|
582
648
|
},
|
|
583
649
|
"additionalProperties": false
|
|
@@ -717,6 +783,18 @@
|
|
|
717
783
|
],
|
|
718
784
|
"additionalProperties": false
|
|
719
785
|
},
|
|
786
|
+
"skillBudgets": {
|
|
787
|
+
"type": "object",
|
|
788
|
+
"propertyNames": {
|
|
789
|
+
"type": "string",
|
|
790
|
+
"minLength": 1
|
|
791
|
+
},
|
|
792
|
+
"additionalProperties": {
|
|
793
|
+
"type": "integer",
|
|
794
|
+
"exclusiveMinimum": 0,
|
|
795
|
+
"maximum": 9007199254740991
|
|
796
|
+
}
|
|
797
|
+
},
|
|
720
798
|
"looseTests": {
|
|
721
799
|
"default": false,
|
|
722
800
|
"type": "boolean"
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { matchesAnyGlob } from './glob'
|
|
2
|
+
|
|
3
|
+
/** The kit agent that judges how a changed agent text steers its reader. */
|
|
4
|
+
export const AGENT_TEXT_REVIEWER = 'skill-review'
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Texts an agent reads as instructions, wherever they sit: the project's `.claude/` and a kit source tree alike.
|
|
8
|
+
* Only Markdown counts, so a script beside a skill or a source directory named `agents` stays out.
|
|
9
|
+
*/
|
|
10
|
+
const AGENT_TEXT_GLOBS = [
|
|
11
|
+
'**/skills/**/*.md',
|
|
12
|
+
'**/agents/**/*.md',
|
|
13
|
+
'**/rules/**/*.md',
|
|
14
|
+
'.claude/project/**/*.md',
|
|
15
|
+
'**/CLAUDE.md',
|
|
16
|
+
'**/AGENTS.md',
|
|
17
|
+
] as const
|
|
18
|
+
|
|
19
|
+
export const isAgentTextPath = (path: string): boolean => matchesAnyGlob(path, AGENT_TEXT_GLOBS)
|
|
20
|
+
|
|
21
|
+
/** The agent-text reviewer when a change touches an agent text. */
|
|
22
|
+
export const agentTextReviewers = (paths: readonly string[]): string[] =>
|
|
23
|
+
paths.some(isAgentTextPath) ? [AGENT_TEXT_REVIEWER] : []
|
package/src/check/command.ts
CHANGED
|
@@ -15,6 +15,7 @@ import { publicContentCheck } from './public-content-check'
|
|
|
15
15
|
import { artifactResult, formatPlanHeader, formatResults, skippedSlowResult, summarize } from './report'
|
|
16
16
|
import { type CheckResult, SKIP_SLOW_FLAG } from './result'
|
|
17
17
|
import { type CheckSettings, CONFIG_PATH, parseCheckSettings } from './settings'
|
|
18
|
+
import { skillBudgetCheck } from './skill-budgets'
|
|
18
19
|
|
|
19
20
|
type CheckTarget = { root: string; configPath: string }
|
|
20
21
|
|
|
@@ -154,6 +155,7 @@ export const run = async (args: string[], home: string = homedir()): Promise<num
|
|
|
154
155
|
const results = await executePlan(plan, root, args.includes(SKIP_SLOW_FLAG), [
|
|
155
156
|
publicContent,
|
|
156
157
|
deferralArrows,
|
|
158
|
+
skillBudgetCheck(root, settings.check.skillBudgets),
|
|
157
159
|
...planStructure,
|
|
158
160
|
])
|
|
159
161
|
print(formatResults(results))
|
|
@@ -4,10 +4,13 @@ import {
|
|
|
4
4
|
boardRowsWithoutPhase,
|
|
5
5
|
boardRowsWithProse,
|
|
6
6
|
hasLanesTable,
|
|
7
|
+
type LongPhaseTitle,
|
|
8
|
+
longPhaseTitles,
|
|
7
9
|
type MergedPhaseWithOpenBoxes,
|
|
8
10
|
mergedPhasesWithOpenBoxes,
|
|
9
11
|
newPhasesWithoutReviewGate,
|
|
10
12
|
PHASE_CELL_LIMIT,
|
|
13
|
+
PHASE_TITLE_LIMIT,
|
|
11
14
|
type PhaseWithoutGate,
|
|
12
15
|
type PhaseWithoutRow,
|
|
13
16
|
PLAN_VOCABULARY,
|
|
@@ -17,6 +20,10 @@ import {
|
|
|
17
20
|
phasesWithoutDependencyRow,
|
|
18
21
|
type RowWithoutPhase,
|
|
19
22
|
type RowWithProse,
|
|
23
|
+
SHORT_NAME_LIMIT,
|
|
24
|
+
SHORT_NAME_PROBLEM,
|
|
25
|
+
type ShortNameFinding,
|
|
26
|
+
shortNameFindings,
|
|
20
27
|
} from '../plan-format'
|
|
21
28
|
import { changedPlansOf } from './deferral-arrows'
|
|
22
29
|
import { CHECK_STATUS, type CheckResult } from './result'
|
|
@@ -129,6 +136,30 @@ const unlistedReport: Report<PhaseWithoutRow> = {
|
|
|
129
136
|
clean: 'every phase has a row in the dependency table',
|
|
130
137
|
}
|
|
131
138
|
|
|
139
|
+
const shortNameText = (found: Found<ShortNameFinding>): string =>
|
|
140
|
+
found.problem === SHORT_NAME_PROBLEM.long
|
|
141
|
+
? `${found.path}:${found.line} Phase ${found.phase}: the short name has ${found.length} characters (limit ${SHORT_NAME_LIMIT})`
|
|
142
|
+
: `${found.path}:${found.line} Phase ${found.phase}: open task has no short name; start it with - [ ] **Name**: (${SHORT_NAME_LIMIT} characters at most)`
|
|
143
|
+
|
|
144
|
+
const shortNameReport: Report<ShortNameFinding> = {
|
|
145
|
+
name: 'Task short names',
|
|
146
|
+
noun: 'plan',
|
|
147
|
+
rule: 'open tasks the change wrote start with a short name',
|
|
148
|
+
unmet: CHECK_STATUS.warn,
|
|
149
|
+
text: shortNameText,
|
|
150
|
+
clean: 'every open task the change wrote has a short name',
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
const titleReport: Report<LongPhaseTitle> = {
|
|
154
|
+
name: 'Phase title length',
|
|
155
|
+
noun: 'plan',
|
|
156
|
+
rule: `phase titles the change wrote have ${PHASE_TITLE_LIMIT} characters at most`,
|
|
157
|
+
unmet: CHECK_STATUS.warn,
|
|
158
|
+
text: ({ path, line, id, title, length }) =>
|
|
159
|
+
`${path}:${line} Phase ${id} ${title} has ${length} characters (limit ${PHASE_TITLE_LIMIT}); the title is the phase's name, its context goes into the origin line`,
|
|
160
|
+
clean: `every phase title the change wrote has ${PHASE_TITLE_LIMIT} characters at most`,
|
|
161
|
+
}
|
|
162
|
+
|
|
132
163
|
const withPath =
|
|
133
164
|
<T>(path: string) =>
|
|
134
165
|
(found: T): Found<T> => ({ ...found, path })
|
|
@@ -150,6 +181,12 @@ const mergedOf = ({ path, current, base }: Changed, language: PlanLanguage): Fou
|
|
|
150
181
|
const unlistedOf = ({ path, current }: Changed, language: PlanLanguage): Found<PhaseWithoutRow>[] | null =>
|
|
151
182
|
phasesWithoutDependencyRow(current, language)?.map(withPath(path)) ?? null
|
|
152
183
|
|
|
184
|
+
const shortNamesOf = ({ path, current, previousLines }: Changed, language: PlanLanguage): Found<ShortNameFinding>[] =>
|
|
185
|
+
shortNameFindings(current, language, previousLines).map(withPath(path))
|
|
186
|
+
|
|
187
|
+
const titlesOf = ({ path, current, previousLines }: Changed, language: PlanLanguage): Found<LongPhaseTitle>[] =>
|
|
188
|
+
longPhaseTitles(current, language, previousLines).map(withPath(path))
|
|
189
|
+
|
|
153
190
|
const changedContents = ({ root, previousOf, baseOf, language }: PlanCheckInput, plans: readonly string[]): Changed[] =>
|
|
154
191
|
plans
|
|
155
192
|
.filter((path) => existsSync(join(root, path)))
|
|
@@ -166,10 +203,12 @@ const changedContents = ({ root, previousOf, baseOf, language }: PlanCheckInput,
|
|
|
166
203
|
* - a lane row the change added or edited that names no phase warns, and so does one whose phases cell is longer
|
|
167
204
|
* than `PHASE_CELL_LIMIT` or records a side order of the user;
|
|
168
205
|
* - a phase whose tasks are all ticked on the base branch and that still has open boxes without `→ P<n>` warns;
|
|
169
|
-
* - a phase of a plan with a dependency table that has no row in it warns
|
|
206
|
+
* - a phase of a plan with a dependency table that has no row in it warns;
|
|
207
|
+
* - an open task the change added or edited without a short name, or with one over `SHORT_NAME_LIMIT`, warns, and so
|
|
208
|
+
* does a phase title it wrote over `PHASE_TITLE_LIMIT`.
|
|
170
209
|
*
|
|
171
210
|
* Empty when no plan changed. The row and prose results are left out when no changed file has a lanes table, the
|
|
172
|
-
* merged
|
|
211
|
+
* merged, short-name and phase-title results when every one has, the dependency result when no changed plan has the table.
|
|
173
212
|
*/
|
|
174
213
|
export const planStructureChecks = (input: PlanCheckInput): CheckResult[] => {
|
|
175
214
|
const files = changedPlansOf(input.paths, input.planDirectory)
|
|
@@ -185,6 +224,8 @@ export const planStructureChecks = (input: PlanCheckInput): CheckResult[] => {
|
|
|
185
224
|
const prose = boards.flatMap((file) => proseOf(file, language))
|
|
186
225
|
const merged = plans.flatMap((file) => mergedOf(file, language))
|
|
187
226
|
const unlisted = unlistedPerPlan.flat()
|
|
227
|
+
const shortNames = plans.flatMap((file) => shortNamesOf(file, language))
|
|
228
|
+
const titles = plans.flatMap((file) => titlesOf(file, language))
|
|
188
229
|
const durationMs = Date.now() - started
|
|
189
230
|
return [
|
|
190
231
|
findingsResult(gateReport(language), gates, files.length, durationMs),
|
|
@@ -198,5 +239,11 @@ export const planStructureChecks = (input: PlanCheckInput): CheckResult[] => {
|
|
|
198
239
|
...(unlistedPerPlan.length > 0
|
|
199
240
|
? [findingsResult(unlistedReport, unlisted, unlistedPerPlan.length, durationMs)]
|
|
200
241
|
: []),
|
|
242
|
+
...(plans.length > 0
|
|
243
|
+
? [
|
|
244
|
+
findingsResult(shortNameReport, shortNames, plans.length, durationMs),
|
|
245
|
+
findingsResult(titleReport, titles, plans.length, durationMs),
|
|
246
|
+
]
|
|
247
|
+
: []),
|
|
201
248
|
]
|
|
202
249
|
}
|
package/src/check/plan.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { JackherdConfig } from '../config'
|
|
2
|
+
import { agentTextReviewers } from './agent-text-reviewers'
|
|
2
3
|
import { type ChangedFile, generatorOwnedFiles, stagedBuildArtifacts } from './changes'
|
|
3
4
|
import { tokenize } from './command-line'
|
|
4
5
|
import { looseDirectories, packageRootsFor } from './roots'
|
|
@@ -90,7 +91,13 @@ export const planChecks = (
|
|
|
90
91
|
return {
|
|
91
92
|
paths,
|
|
92
93
|
roots,
|
|
93
|
-
reviewers: [
|
|
94
|
+
reviewers: [
|
|
95
|
+
...new Set([
|
|
96
|
+
...reviewersFor(paths, config.reviewerRoutes),
|
|
97
|
+
...publicContentReviewers(paths, config.publicContent),
|
|
98
|
+
...agentTextReviewers(paths),
|
|
99
|
+
]),
|
|
100
|
+
],
|
|
94
101
|
generated: generatorOwnedFiles(paths, config.generatorOwned),
|
|
95
102
|
artifacts: stagedBuildArtifacts(files, config.buildArtifacts),
|
|
96
103
|
checks:
|
package/src/check/schema.ts
CHANGED
|
@@ -57,6 +57,9 @@ const publicContent = z.strictObject({
|
|
|
57
57
|
reviewer: nonEmpty.default('public-content'),
|
|
58
58
|
})
|
|
59
59
|
|
|
60
|
+
/** A budget in words per path or glob from the project root; a key joining two paths with ` + ` budgets them together. */
|
|
61
|
+
const skillBudgets = z.record(glob, z.number().int().positive())
|
|
62
|
+
|
|
60
63
|
/**
|
|
61
64
|
* The `check` block of `.jackherd/config.json`. Test and type commands come from the top-level
|
|
62
65
|
* `commands` block; this block holds what only the check runner reads.
|
|
@@ -73,6 +76,11 @@ export const checkConfigSchema = z.strictObject({
|
|
|
73
76
|
buildArtifacts: z.array(glob).default([...DEFAULT_BUILD_ARTIFACT_GLOBS]),
|
|
74
77
|
reviewerRoutes: z.array(reviewerRoute).default([]),
|
|
75
78
|
publicContent: publicContent.optional(),
|
|
79
|
+
/**
|
|
80
|
+
* Word budgets for the files an agent loads again and again. An entry replaces the kit's budget for the same
|
|
81
|
+
* path and sets one for the project's own skills; a file with none is measured against the kit's default.
|
|
82
|
+
*/
|
|
83
|
+
skillBudgets: skillBudgets.optional(),
|
|
76
84
|
/** Also run tests in directories that hold test files but belong to no package. */
|
|
77
85
|
looseTests: z.boolean().default(false),
|
|
78
86
|
})
|
|
@@ -81,3 +89,4 @@ export type CheckConfig = z.infer<typeof checkConfigSchema>
|
|
|
81
89
|
export type ReviewerRoute = CheckConfig['reviewerRoutes'][number]
|
|
82
90
|
export type ProjectCheck = CheckConfig['checks'][number]
|
|
83
91
|
export type PublicContentConfig = NonNullable<CheckConfig['publicContent']>
|
|
92
|
+
export type SkillBudgets = NonNullable<CheckConfig['skillBudgets']>
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
/** Words allowed to a skill the kit did not install and the project gave no budget. */
|
|
2
|
+
export const OWN_SKILL_BUDGET = 2000
|
|
3
|
+
|
|
4
|
+
/** Words allowed to a file the kit installed when neither the project nor `KIT_SKILL_BUDGETS` names it. */
|
|
5
|
+
export const KIT_FILE_FALLBACK_BUDGET = 2000
|
|
6
|
+
|
|
7
|
+
/** Words allowed to a project supplement, `.claude/project/<skill>.md`. */
|
|
8
|
+
export const SUPPLEMENT_BUDGET = 800
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* The kit's word budgets, by path from the project root. A key joining two paths with ` + ` budgets what is
|
|
12
|
+
* loaded together. A budget is the measured size plus at most 10 %, so a file has room for a sentence, not for a
|
|
13
|
+
* section; a file that needs more justifies the growth where it raises the number.
|
|
14
|
+
*/
|
|
15
|
+
export const KIT_SKILL_BUDGETS: Readonly<Record<string, number>> = {
|
|
16
|
+
'.claude/skills/devops/SKILL.md': 321,
|
|
17
|
+
'.claude/skills/diagnose/SKILL.md': 1521,
|
|
18
|
+
'.claude/skills/diagnose/references/feedback-loops.md': 636,
|
|
19
|
+
'.claude/skills/follow/SKILL.md': 1100,
|
|
20
|
+
'.claude/skills/grill/SKILL.md': 685,
|
|
21
|
+
'.claude/skills/implement/SKILL.md': 2190,
|
|
22
|
+
'.claude/skills/orchestrate/SKILL.md': 7820,
|
|
23
|
+
'.claude/skills/orchestrate/references/acceptance.md': 200,
|
|
24
|
+
'.claude/skills/orchestrate/references/close-lane.md': 250,
|
|
25
|
+
'.claude/skills/orchestrate/references/coordinator-handover.md': 551,
|
|
26
|
+
'.claude/skills/orchestrate/references/draft-review.md': 300,
|
|
27
|
+
'.claude/skills/orchestrate/references/events.md': 1070,
|
|
28
|
+
'.claude/skills/orchestrate/references/herd.md': 299,
|
|
29
|
+
'.claude/skills/orchestrate/references/lane-handover.md': 280,
|
|
30
|
+
'.claude/skills/orchestrate/references/lane-session.md': 280,
|
|
31
|
+
'.claude/skills/orchestrate/references/lane-setup.md': 380,
|
|
32
|
+
'.claude/skills/orchestrate/references/plan-commit.md': 330,
|
|
33
|
+
'.claude/skills/orchestrate/references/sensitive-input.md': 269,
|
|
34
|
+
'.claude/skills/plan/SKILL.md': 1920,
|
|
35
|
+
'.claude/skills/plan/references/template-English.md': 536,
|
|
36
|
+
'.claude/skills/plan/references/template-German.md': 501,
|
|
37
|
+
'.claude/skills/pre-commit/SKILL.md': 1003,
|
|
38
|
+
'.claude/skills/review/SKILL.md': 319,
|
|
39
|
+
'.claude/skills/security-audit/SKILL.md': 519,
|
|
40
|
+
'.claude/skills/start/SKILL.md': 607,
|
|
41
|
+
'.claude/skills/uncle-bob/SKILL.md': 466,
|
|
42
|
+
'.claude/skills/orchestrate/SKILL.md + .claude/project/orchestrate.md': 8620,
|
|
43
|
+
'.claude/agents/devops.md': 104,
|
|
44
|
+
'.claude/agents/explore.md': 132,
|
|
45
|
+
'.claude/agents/implement.md': 303,
|
|
46
|
+
'.claude/agents/plan.md': 209,
|
|
47
|
+
'.claude/agents/public-content.md': 449,
|
|
48
|
+
'.claude/agents/security-audit.md': 128,
|
|
49
|
+
'.claude/agents/skill-review.md': 468,
|
|
50
|
+
'.claude/agents/spec-review.md': 1137,
|
|
51
|
+
'.claude/agents/uncle-bob.md': 111,
|
|
52
|
+
'.claude/rules/kit/code-style.md': 1664,
|
|
53
|
+
'.claude/rules/kit/pull-requests.md': 601,
|
|
54
|
+
'.claude/rules/kit/testing.md': 741,
|
|
55
|
+
}
|