jackherd 1.10.0 → 1.11.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 +19 -0
- package/README.md +17 -2
- package/dist/{chunk-5MQBCUQ5.js → chunk-RMMXD4G5.js} +9 -2
- package/dist/config.d.ts +60 -0
- package/dist/config.js +39 -4
- package/dist/plan-format.d.ts +7 -1
- package/dist/plan-format.js +4 -2
- package/herdr-plugin/herdr-plugin.toml +1 -1
- package/install.sh +1 -1
- package/kit/hooks/hooks/open-question/run.ts +8 -3
- package/kit/rules/rules/kit/pull-requests.md +2 -0
- package/kit/workflow/skills/follow/SKILL.md +3 -3
- package/kit/workflow/skills/orchestrate/SKILL.md +10 -2
- package/package.json +1 -1
- package/recipes/sources.md +4 -0
- package/schemas/jackherd.schema.json +80 -0
- package/src/cli.ts +1 -0
- package/src/config/schema.ts +24 -1
- package/src/config/tones.ts +27 -0
- package/src/lane-prompt/additions.ts +14 -0
- package/src/lane-prompt/command.ts +8 -2
- package/src/lane-prompt/input.ts +44 -3
- package/src/lane-prompt/options.ts +2 -0
- package/src/mermaid/command.ts +36 -0
- package/src/mermaid/problems.ts +48 -0
- package/src/plan-format/dependencies.ts +2 -2
- package/src/plan-format/waiting.ts +15 -2
- package/src/plans/appointment-rows.ts +34 -10
- package/src/plans/ask-coordinator.ts +46 -12
- package/src/plans/ask-target.ts +13 -2
- package/src/plans/board-close.ts +85 -0
- package/src/plans/frame.ts +5 -12
- package/src/plans/git.ts +35 -0
- package/src/plans/groomed.ts +27 -0
- package/src/plans/layout-phase.ts +7 -4
- package/src/plans/layout.ts +258 -48
- package/src/plans/link-chips.ts +22 -4
- package/src/plans/live.ts +73 -5
- package/src/plans/next-rows.ts +44 -0
- package/src/plans/planned.ts +22 -0
- package/src/plans/row-actions.ts +52 -0
- package/src/plans/row-focus.ts +148 -0
- package/src/plans/row-targets.ts +7 -0
- package/src/plans/selection.ts +14 -1
- package/src/plans/settings.ts +10 -0
- package/src/plans/snapshot.ts +79 -21
- package/src/plans/source-asked.ts +19 -0
- package/src/plans/source-prefix.ts +17 -0
- package/src/plans/source-rows.ts +188 -0
- package/src/plans/texts.ts +28 -3
- package/src/plans/tones.ts +30 -0
- package/src/plans/view.ts +8 -2
- package/src/plans/waiting-click.ts +129 -24
- package/src/terminal/text.ts +8 -0
- package/src/terminal/types.ts +4 -0
- package/src/vocabulary/index.ts +10 -0
- package/src/watch/plan-badges-read.ts +9 -2
- package/src/watch/plan-badges.ts +10 -2
- package/src/watch/report-questions.ts +4 -3
- package/src/watch/source-entries.ts +55 -0
- package/src/watch/source-fields.ts +1 -0
- package/src/watch/source-statuses.ts +60 -0
- package/src/watch/source-tickets.ts +21 -1
- package/src/watch/sources.ts +41 -1
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,25 @@
|
|
|
2
2
|
|
|
3
3
|
What changed for people who use jackherd, newest first.
|
|
4
4
|
|
|
5
|
+
## 1.11.0
|
|
6
|
+
|
|
7
|
+
- **The herd lists your sources.** A `watch.sources` entry that is no ticket gets a row in a `Sources` block: when it last ran, since when it fails (red mark), its newest report (amber mark while it is under a day old); a click opens the report's URL. `/jh-follow` and `recipes/sources.md` say how.
|
|
8
|
+
- **The colours of the herd are configurable.** `plans.tones` names the tone of each role (`waiting`, `new`, `running`, `resting`) from amber, teal, grey, red, green, blue and magenta; a source may carry its own `tone` for its new reports. The defaults are the colours it had.
|
|
9
|
+
- **A row from a source says which one.** `watch.sources[].label` (at most 40 characters, one line; without it the source's name) is put before a "Waiting for you" row whose `Origin` cell names the source, as `<label>: <row>`.
|
|
10
|
+
- **"Waiting for you" rows have `[done]`, the appointments have `[done]`, `[run]` and `[move]`.** `[done]` closes the row (the board's status cell, a sent file's record), `[run]` asks the coordinator to run the appointment now, `[move]` to ask you for a new time.
|
|
11
|
+
- **New blocks and cells in the herd.** `Next` shows the board's next section; a resting lane says `waits on: …` or `after: …`; `groomed 3d ago` beside the clock (amber from eight days) from the board-grooming appointment; `planned` shows the next phase per plan, with `stale?` once its plan file has not changed on the base branch for 14 days.
|
|
12
|
+
- **`jh mermaid <file>` checks the diagrams of a pull request text.** An edge label between dashes (`-- text -->`) or a pipe label without quotes makes GitHub show `Lexical error` instead of the diagram; the command exits 1 with the line. The pull request rule now says to write `-->|"label"|` and to run it before `gh pr create` or `gh pr edit`.
|
|
13
|
+
- **A report that says "Keine offenen." asks nothing.** The watcher no longer counts it as a question, and a bold or listed "None." does not either.
|
|
14
|
+
- **A note in the write set no longer widens it to the whole repository.** A backticked config key such as `watch.sources[].label` in the `Writes` cell of a plan's dependency table is no path, so `jh lane prompt` lists only the real folders.
|
|
15
|
+
- **One colour rule for the buttons.** The buttons no longer wear the colour of the row's mark: amber and bold in "Waiting for you", the normal foreground colour in the other blocks, dim only where nothing is left to do (an entry that says `↑ asked`).
|
|
16
|
+
- **A source with several entries opens on a click.** The `Sources` block shows one folded row per source (amber only for a new entry that no row of "Waiting for you" asks about); opened, it lists up to five entries with title, count (`map.count`, new) and time, then `+<n> more`. A click on an entry opens its `url`, `[ask]` asks the coordinator to look at exactly that entry, and an entry that "Waiting for you" already asks about is dim and says `↑ asked`. The watcher keeps the last 20 entries of such a source.
|
|
17
|
+
- **A question put off twice stays one open question.** The `open-question` hook writes no second record while one with the same text is still open, so asking it again with `[ask]` and answering "later" again leaves a single row.
|
|
18
|
+
- **A click folds the ticked tasks again.** The listed ticked tasks of a phase get a line `▾ <n> ticked · click or a folds them` above them; before, only `a` closed the list that a click had opened. The key hint and the legend name both.
|
|
19
|
+
- **`jh lane prompt` keeps your additions and names no contested phase.** What you write below the marker line at the end of the prompt file stays through every new writing, `--handover` included. A phase that two open rows of the board name comes into neither prompt; the command prints it and a lane left with nothing is refused.
|
|
20
|
+
- **The row under the mouse or the arrows is marked, everywhere.** Any clickable row of the herd (lane, phase, ticked line, `waiting`, `planned`, and the rows of `Waiting for you`, `Next`, `Appointments` and `Sources`) gets a light background and a `❯` in front, and its buttons turn bold; the background joins the text and its buttons across the full width. The herd now asks the terminal for mouse movement and redraws only when the row under the mouse changes. `↑↓` also walks the rows of the blocks on top; enter on one asks, opens or expands it, and never presses `[done]` or `[run]`. The legend names it.
|
|
21
|
+
- **Links are bracket buttons, and the mouse bolds only the one it is on.** The links under a lane (`[↗ #<n>] [📄 Plan] [✦ title]`) lose the grey background and read like `[ask]`: a square bracket means a click does something. `… checks` stays plain text, amber and dark red badges stay badges. An artifact link shows its title (the link text, the bold label before it, else the text of its line) instead of "Artifact". With the mouse over a row only the bracket under it turns bold; with the arrows the whole row is the unit. A line of links is marked by the mouse, not walked by the arrows.
|
|
22
|
+
- **The README follows a source from the command to your answer.** A short section with a diagram: source, watcher, coordinator, "Waiting for you", you.
|
|
23
|
+
|
|
5
24
|
## 1.10.0
|
|
6
25
|
|
|
7
26
|
- **`jh sync` writes the ask rules the merge guard left behind.** A project sync adds `permissions.ask` rules for `gh run rerun` and the `gh api` writes that merge, write a file, dispatch or rerun a workflow, or move a ref; it records them in the lock, removes one only when the kit drops it and only if a kit shipped it, and leaves your own rules alone. Claude Code applies a matching ask rule even when a hook answers `allow`.
|
package/README.md
CHANGED
|
@@ -71,6 +71,21 @@ Install with one command, run `/jh-start` in a repository, and it offers your fi
|
|
|
71
71
|
|
|
72
72
|
By hand (Bun 1.3+): `bun add -g jackherd` or `npm install -g jackherd`, then `jh init --global` for yourself, or `jh init` in a repository to give your team the same skills and guard hooks. → [INSTALL.md](https://unpkg.com/jackherd/INSTALL.md)
|
|
73
73
|
|
|
74
|
+
## Follow anything outside GitHub
|
|
75
|
+
|
|
76
|
+
`/jh-follow` turns a ticket, an error log or a status page into something Jack acts on. It writes the source to `watch.sources` after a dry run and your yes; from then on a change takes this path:
|
|
77
|
+
|
|
78
|
+
```mermaid
|
|
79
|
+
flowchart LR
|
|
80
|
+
source["Source<br/>ticket, error log, status page"] -->|"new or changed entry"| watcher["jh watch"]
|
|
81
|
+
watcher -->|"=== source … report"| coordinator["Jack"]
|
|
82
|
+
coordinator -->|"board row, origin = source"| waiting["Waiting for you<br/>Error log · Checkout: …"]
|
|
83
|
+
waiting -->|"[ask]"| coordinator
|
|
84
|
+
coordinator -->|"asks you, then a lane works it"| you["You"]
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
The herd lists each source that is no ticket in a `Sources` block (when it ran, since when it fails, its newest report, a click opens it), and a row that came from a source starts with its `label`. Details and every field: [recipes](https://unpkg.com/jackherd/recipes/sources.md).
|
|
88
|
+
|
|
74
89
|
## In detail
|
|
75
90
|
|
|
76
91
|
<details>
|
|
@@ -175,7 +190,7 @@ On top, **Waiting for you** lists what needs your answer: a file or Artifact sen
|
|
|
175
190
|
────────────────────────────────────────────────────────────────────────────────
|
|
176
191
|
· no agent (1) docs-site 1/3
|
|
177
192
|
────────────────────────────────────────────────────────────────────────────────
|
|
178
|
-
↑↓ select →← open a ticked tasks s html q quit ? help
|
|
193
|
+
↑↓ select →← open a/click ticked tasks s html q quit ? help
|
|
179
194
|
```
|
|
180
195
|
|
|
181
196
|
</details>
|
|
@@ -191,7 +206,7 @@ On top, **Waiting for you** lists what needs your answer: a file or Artifact sen
|
|
|
191
206
|
| `jh check` | types, lint and tests of what you touched, plus the plan and board checks (`--skip-slow`, `--parallel <plan>`) |
|
|
192
207
|
| `jh herd` | the live view (`--once`, `--lane <name>`) |
|
|
193
208
|
| `jh watch` | the watcher Jack runs |
|
|
194
|
-
| `jh lane prompt <lane>` | writes a lane's first prompt from its board row and its plan (`--out`, `--handover`) |
|
|
209
|
+
| `jh lane prompt <lane>` | writes a lane's first prompt from its board row and its plan (`--out`, `--handover`); your additions below the marker line at its end stay |
|
|
195
210
|
| `jh lane close <lane>` | removes a finished lane: agent, worktree, herdr workspace and branch, and marks the board; first checks that nothing is lost, and refuses with every reason; `--dry-run` only checks. Claude Code asks before each call |
|
|
196
211
|
| `jh preview <file>` | renders a Markdown file through the GitHub API into a preview in GitHub and npm style |
|
|
197
212
|
| `jh waiting` | the files and Artifacts sent to you that you have not answered yet (`close <id>…` or `close --all` once you have) |
|
|
@@ -40,15 +40,21 @@ var APPOINTMENT_VOCABULARY = {
|
|
|
40
40
|
heading: "Termine",
|
|
41
41
|
columns: { when: "Wann", action: "Aktion", origin: "Herkunft", status: "Stand" },
|
|
42
42
|
statusAlso: ["Status"],
|
|
43
|
-
open: ["offen"]
|
|
43
|
+
open: ["offen"],
|
|
44
|
+
grooming: "board-pflege"
|
|
44
45
|
},
|
|
45
46
|
[PLAN_LANGUAGE.en]: {
|
|
46
47
|
heading: "Appointments",
|
|
47
48
|
columns: { when: "When", action: "Action", origin: "Origin", status: "Status" },
|
|
48
49
|
statusAlso: [],
|
|
49
|
-
open: ["open"]
|
|
50
|
+
open: ["open"],
|
|
51
|
+
grooming: "board grooming"
|
|
50
52
|
}
|
|
51
53
|
};
|
|
54
|
+
var NEXT_VOCABULARY = {
|
|
55
|
+
[PLAN_LANGUAGE.de]: { heading: "Als N\xE4chstes" },
|
|
56
|
+
[PLAN_LANGUAGE.en]: { heading: "Next" }
|
|
57
|
+
};
|
|
52
58
|
var WAITING_VOCABULARY = {
|
|
53
59
|
[PLAN_LANGUAGE.de]: {
|
|
54
60
|
heading: "Wartet auf dich",
|
|
@@ -164,6 +170,7 @@ export {
|
|
|
164
170
|
LANE_PROMPT_OPENING,
|
|
165
171
|
APPROVAL_TEXTS,
|
|
166
172
|
APPOINTMENT_VOCABULARY,
|
|
173
|
+
NEXT_VOCABULARY,
|
|
167
174
|
WAITING_VOCABULARY,
|
|
168
175
|
isPlanLanguage,
|
|
169
176
|
PLAN_STATUS,
|
package/dist/config.d.ts
CHANGED
|
@@ -34,11 +34,22 @@ declare const sourceSchema: z.ZodObject<{
|
|
|
34
34
|
body: z.ZodOptional<z.ZodString>;
|
|
35
35
|
author: z.ZodOptional<z.ZodString>;
|
|
36
36
|
status: z.ZodOptional<z.ZodString>;
|
|
37
|
+
count: z.ZodOptional<z.ZodString>;
|
|
37
38
|
}, z.core.$catchall<z.ZodString>>;
|
|
38
39
|
ignoreAuthors: z.ZodDefault<z.ZodArray<z.ZodString>>;
|
|
39
40
|
reportLimit: z.ZodDefault<z.ZodNumber>;
|
|
41
|
+
label: z.ZodOptional<z.ZodString>;
|
|
40
42
|
lane: z.ZodOptional<z.ZodString>;
|
|
41
43
|
ticket: z.ZodOptional<z.ZodBoolean>;
|
|
44
|
+
tone: z.ZodOptional<z.ZodEnum<{
|
|
45
|
+
amber: "amber";
|
|
46
|
+
teal: "teal";
|
|
47
|
+
grey: "grey";
|
|
48
|
+
red: "red";
|
|
49
|
+
green: "green";
|
|
50
|
+
blue: "blue";
|
|
51
|
+
magenta: "magenta";
|
|
52
|
+
}>>;
|
|
42
53
|
reportOn: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
43
54
|
}, z.core.$strict>;
|
|
44
55
|
declare const jackherdConfigSchema: z.ZodObject<{
|
|
@@ -110,6 +121,44 @@ declare const jackherdConfigSchema: z.ZodObject<{
|
|
|
110
121
|
alertTokens: z.ZodDefault<z.ZodNumber>;
|
|
111
122
|
}, z.core.$strict>>;
|
|
112
123
|
}, z.core.$strict>>;
|
|
124
|
+
tones: z.ZodPrefault<z.ZodObject<{
|
|
125
|
+
waiting: z.ZodDefault<z.ZodEnum<{
|
|
126
|
+
amber: "amber";
|
|
127
|
+
teal: "teal";
|
|
128
|
+
grey: "grey";
|
|
129
|
+
red: "red";
|
|
130
|
+
green: "green";
|
|
131
|
+
blue: "blue";
|
|
132
|
+
magenta: "magenta";
|
|
133
|
+
}>>;
|
|
134
|
+
new: z.ZodDefault<z.ZodEnum<{
|
|
135
|
+
amber: "amber";
|
|
136
|
+
teal: "teal";
|
|
137
|
+
grey: "grey";
|
|
138
|
+
red: "red";
|
|
139
|
+
green: "green";
|
|
140
|
+
blue: "blue";
|
|
141
|
+
magenta: "magenta";
|
|
142
|
+
}>>;
|
|
143
|
+
running: z.ZodDefault<z.ZodEnum<{
|
|
144
|
+
amber: "amber";
|
|
145
|
+
teal: "teal";
|
|
146
|
+
grey: "grey";
|
|
147
|
+
red: "red";
|
|
148
|
+
green: "green";
|
|
149
|
+
blue: "blue";
|
|
150
|
+
magenta: "magenta";
|
|
151
|
+
}>>;
|
|
152
|
+
resting: z.ZodDefault<z.ZodEnum<{
|
|
153
|
+
amber: "amber";
|
|
154
|
+
teal: "teal";
|
|
155
|
+
grey: "grey";
|
|
156
|
+
red: "red";
|
|
157
|
+
green: "green";
|
|
158
|
+
blue: "blue";
|
|
159
|
+
magenta: "magenta";
|
|
160
|
+
}>>;
|
|
161
|
+
}, z.core.$strict>>;
|
|
113
162
|
}, z.core.$strict>>;
|
|
114
163
|
watch: z.ZodPrefault<z.ZodObject<{
|
|
115
164
|
deploy: z.ZodOptional<z.ZodObject<{
|
|
@@ -149,11 +198,22 @@ declare const jackherdConfigSchema: z.ZodObject<{
|
|
|
149
198
|
body: z.ZodOptional<z.ZodString>;
|
|
150
199
|
author: z.ZodOptional<z.ZodString>;
|
|
151
200
|
status: z.ZodOptional<z.ZodString>;
|
|
201
|
+
count: z.ZodOptional<z.ZodString>;
|
|
152
202
|
}, z.core.$catchall<z.ZodString>>;
|
|
153
203
|
ignoreAuthors: z.ZodDefault<z.ZodArray<z.ZodString>>;
|
|
154
204
|
reportLimit: z.ZodDefault<z.ZodNumber>;
|
|
205
|
+
label: z.ZodOptional<z.ZodString>;
|
|
155
206
|
lane: z.ZodOptional<z.ZodString>;
|
|
156
207
|
ticket: z.ZodOptional<z.ZodBoolean>;
|
|
208
|
+
tone: z.ZodOptional<z.ZodEnum<{
|
|
209
|
+
amber: "amber";
|
|
210
|
+
teal: "teal";
|
|
211
|
+
grey: "grey";
|
|
212
|
+
red: "red";
|
|
213
|
+
green: "green";
|
|
214
|
+
blue: "blue";
|
|
215
|
+
magenta: "magenta";
|
|
216
|
+
}>>;
|
|
157
217
|
reportOn: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
158
218
|
}, z.core.$strict>>>;
|
|
159
219
|
}, z.core.$strict>>;
|
package/dist/config.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
2
|
PLAN_LANGUAGE,
|
|
3
3
|
RESPONSE_ADDRESS
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-RMMXD4G5.js";
|
|
5
5
|
|
|
6
6
|
// src/config/json-schema.ts
|
|
7
7
|
import { z as z3 } from "zod";
|
|
@@ -164,7 +164,8 @@ var SOURCE_FIELD = {
|
|
|
164
164
|
url: "url",
|
|
165
165
|
body: "body",
|
|
166
166
|
author: "author",
|
|
167
|
-
status: "status"
|
|
167
|
+
status: "status",
|
|
168
|
+
count: "count"
|
|
168
169
|
};
|
|
169
170
|
var CONTENT_FIELDS = [SOURCE_FIELD.title, SOURCE_FIELD.author, SOURCE_FIELD.body, SOURCE_FIELD.url];
|
|
170
171
|
|
|
@@ -274,6 +275,25 @@ import { isAbsolute } from "path";
|
|
|
274
275
|
var segmentsOf = (path) => path.split(/[\\/]/).filter((segment) => segment !== "" && segment !== ".");
|
|
275
276
|
var isRepositoryDirectory = (value) => !isAbsolute(value) && segmentsOf(value).length > 0 && !segmentsOf(value).includes("..");
|
|
276
277
|
|
|
278
|
+
// src/config/tones.ts
|
|
279
|
+
var TONE = {
|
|
280
|
+
amber: "amber",
|
|
281
|
+
teal: "teal",
|
|
282
|
+
grey: "grey",
|
|
283
|
+
red: "red",
|
|
284
|
+
green: "green",
|
|
285
|
+
blue: "blue",
|
|
286
|
+
magenta: "magenta"
|
|
287
|
+
};
|
|
288
|
+
var TONE_NAMES = Object.values(TONE);
|
|
289
|
+
var TONE_ROLE = { waiting: "waiting", new: "new", running: "running", resting: "resting" };
|
|
290
|
+
var DEFAULT_TONES = {
|
|
291
|
+
[TONE_ROLE.waiting]: TONE.amber,
|
|
292
|
+
[TONE_ROLE.new]: TONE.amber,
|
|
293
|
+
[TONE_ROLE.running]: TONE.teal,
|
|
294
|
+
[TONE_ROLE.resting]: TONE.grey
|
|
295
|
+
};
|
|
296
|
+
|
|
277
297
|
// src/config/schema.ts
|
|
278
298
|
var TERMINAL_ADAPTER = { none: "none", herdr: "herdr" };
|
|
279
299
|
var MODEL_ROLE = {
|
|
@@ -387,11 +407,14 @@ var sourceMapSchema = z2.object({
|
|
|
387
407
|
[SOURCE_FIELD.body]: sourcePath.optional(),
|
|
388
408
|
[SOURCE_FIELD.author]: sourcePath.optional(),
|
|
389
409
|
/** A ticket source's status, shown on its badge in the herd; also a field `reportOn` can name. */
|
|
390
|
-
[SOURCE_FIELD.status]: sourcePath.optional()
|
|
410
|
+
[SOURCE_FIELD.status]: sourcePath.optional(),
|
|
411
|
+
/** How often the entry happened (an error count), shown as `113×` beside the entry in the herd's `Sources` block. */
|
|
412
|
+
[SOURCE_FIELD.count]: sourcePath.optional()
|
|
391
413
|
}).catchall(sourcePath).refine((map) => Object.keys(map).every((field) => SOURCE_FIELD_NAME.test(field)), {
|
|
392
414
|
message: "a map field is a letter, then letters, digits and `_`"
|
|
393
415
|
});
|
|
394
416
|
var canChange = ({ map, reportOn }) => map.updatedAt !== void 0 || CONTENT_FIELDS.some((field) => map[field] !== void 0) || reportOn !== void 0;
|
|
417
|
+
var toneName = z2.enum(TONE_NAMES);
|
|
395
418
|
var sourceSchema = z2.strictObject({
|
|
396
419
|
/** Printed in every report of the source and the key of its saved state. */
|
|
397
420
|
name: z2.string().regex(/^[A-Za-z0-9][\w.-]*$/, "letters, digits, `_`, `.` and `-`"),
|
|
@@ -406,6 +429,8 @@ var sourceSchema = z2.strictObject({
|
|
|
406
429
|
ignoreAuthors: z2.array(z2.string().min(1)).default([]),
|
|
407
430
|
/** The most new or changed entries one report shows of this source; the rest is one line `+<n> more`. */
|
|
408
431
|
reportLimit: z2.number().int().min(1).default(5),
|
|
432
|
+
/** Shown before a row of "Waiting for you" that came from this source (`Error log · Checkout: …`); without it the source's name. */
|
|
433
|
+
label: z2.string().min(1).max(40).regex(/^[^\r\n]+$/, "one line").optional(),
|
|
409
434
|
/** The lane the source's reports name. */
|
|
410
435
|
lane: z2.string().min(1).optional(),
|
|
411
436
|
/**
|
|
@@ -413,6 +438,8 @@ var sourceSchema = z2.strictObject({
|
|
|
413
438
|
* the lane above or the lane whose board row or plan names its id.
|
|
414
439
|
*/
|
|
415
440
|
ticket: z2.boolean().optional(),
|
|
441
|
+
/** The tone of the source's mark in the herd's `Sources` block while its newest report is new; without it the tone of the role `new`. */
|
|
442
|
+
tone: toneName.optional(),
|
|
416
443
|
/**
|
|
417
444
|
* The mapped fields whose change reports, with the old and the new value, in place of the content of `title`,
|
|
418
445
|
* `author`, `body` and `url`; without it a change of that content reports.
|
|
@@ -512,6 +539,12 @@ var hintsSchema = z2.strictObject({
|
|
|
512
539
|
taskSignal: z2.boolean().default(true)
|
|
513
540
|
});
|
|
514
541
|
var DEFAULT_TASK_SIGNAL_MINUTES = 10;
|
|
542
|
+
var tonesSchema = z2.strictObject({
|
|
543
|
+
waiting: toneName.default(DEFAULT_TONES.waiting),
|
|
544
|
+
new: toneName.default(DEFAULT_TONES.new),
|
|
545
|
+
running: toneName.default(DEFAULT_TONES.running),
|
|
546
|
+
resting: toneName.default(DEFAULT_TONES.resting)
|
|
547
|
+
});
|
|
515
548
|
var contextSchema = z2.strictObject({
|
|
516
549
|
/** Tokens in a lane's context from which its fill shows yellow and `/implement` offers a new chat. */
|
|
517
550
|
warnTokens: tokenCount.default(25e4),
|
|
@@ -581,7 +614,9 @@ var jackherdConfigSchema = z2.strictObject({
|
|
|
581
614
|
icon: z2.string().min(1)
|
|
582
615
|
})
|
|
583
616
|
).default(DEFAULT_LINK_KINDS.map((kind) => ({ ...kind }))),
|
|
584
|
-
context: contextSchema.prefault({})
|
|
617
|
+
context: contextSchema.prefault({}),
|
|
618
|
+
/** The colour of each role in the herd, by name: what waits for you, what is new, what runs, what rests. */
|
|
619
|
+
tones: tonesSchema.prefault({})
|
|
585
620
|
}).prefault({}),
|
|
586
621
|
/**
|
|
587
622
|
* Read by `jh watch`; without `deploy` it reports no deploy runs. `feedback` is on unless set to `false`:
|
package/dist/plan-format.d.ts
CHANGED
|
@@ -64,6 +64,12 @@ declare const APPOINTMENT_VOCABULARY: Record<PlanLanguage, {
|
|
|
64
64
|
/** Further header names that count as the status column. */
|
|
65
65
|
statusAlso: readonly string[];
|
|
66
66
|
open: readonly string[];
|
|
67
|
+
/** The lower-case word an action starts with when it is the weekly board grooming, which the herd's header counts from. */
|
|
68
|
+
grooming: string;
|
|
69
|
+
}>;
|
|
70
|
+
/** The heading of the board section of what the coordinator does next, a numbered list of at most three lines. */
|
|
71
|
+
declare const NEXT_VOCABULARY: Record<PlanLanguage, {
|
|
72
|
+
heading: string;
|
|
67
73
|
}>;
|
|
68
74
|
/**
|
|
69
75
|
* The board section of what waits on the user's answer (a sent preview, an open question, a report to accept): its
|
|
@@ -568,4 +574,4 @@ declare const readSprintDocument: (markdown: string, language: PlanLanguage) =>
|
|
|
568
574
|
*/
|
|
569
575
|
declare const readPhaseDependencies: (planMarkdown: string, language: PlanLanguage) => Record<string, string>;
|
|
570
576
|
|
|
571
|
-
export { ADDRESS_FORM, APPOINTMENT_VOCABULARY, APPROVAL_TEXTS, type ChecklistItem, type ColumnModel, type DeferredItem, type DriftFinding, LANE_PROMPT_OPENING, LANGUAGE_NAME, type LaneProgress, type LongPhaseTitle, type MergedPhaseWithOpenBoxes, type MisplacedDeferral, PHASE_CELL_LIMIT, PHASE_ID_PREFIX, PHASE_TITLE_LIMIT, PLAN_LANGUAGE, PLAN_STATUS, PLAN_VOCABULARY, PROSE_REASON, type PhaseDependency, type PhaseHeading, type PhaseProgress, type PhaseSchedule, type PhaseTally, type PhaseWithoutGate, type PhaseWithoutRow, type PlanHeader, type PlanLanguage, type PlanPhase, type PlanStatus, type PlanStep, type PlanVocabulary, type PlansByHref, type ProseReason, RESPONSE_ADDRESS, type ResponseAddress, type RowWithProse, type RowWithoutPhase, SELF_MERGE_LABEL, SHORT_NAME_LIMIT, SHORT_NAME_PROBLEM, STANDING_APPROVAL_TEXTS, type ShortNameFinding, type ShortNameProblem, type SprintDocument, type SprintLane, type SprintPlanRow, type SprintPlanTable, type StatusWord, type StepProgress, WAITING_VOCABULARY, activeItem, boardRowsWithProse, boardRowsWithoutPhase, classifyStatus, columnModels, countDecisions, criticalPath, currentPhase, currentPhaseOf, deferralTarget, differsFromColumn, endsPhase, findDrift, hasLanesTable, isCheckboxLine, isDocumentationGateItem, isOpenCheckboxLine, isPhaseFinished, isPhaseOpen, isPlanLanguage, isReviewGateLine, isTickedUnmerged, laneNameOf, laneProgress, longPhaseTitles, mergedPhasesWithOpenBoxes, misplacedDeferrals, newPhasesWithoutReviewGate, onlyDocumentationOpen, parallelGroups, parallelGroupsOfPlan, parseDependencyTable, parsePlanPhases, parseSprintLanes, phaseHeading, phaseHeadingPattern, phaseHeadings, phaseIdsOfCell, phaseIdsOfPlan, phaseLabel, phaseLabels, phaseProgress, phaseWaves, phasesText, phasesWithoutDependencyRow, readPhaseDependencies, readPlanHeader, readSprintDocument, resolvePlanPath, sectionHeading, shortNameFindings, shortTitle, sprintTitleOf, sumPhases, tallyPhases, wavesOfPlan, withoutRepeats };
|
|
577
|
+
export { ADDRESS_FORM, APPOINTMENT_VOCABULARY, APPROVAL_TEXTS, type ChecklistItem, type ColumnModel, type DeferredItem, type DriftFinding, LANE_PROMPT_OPENING, LANGUAGE_NAME, type LaneProgress, type LongPhaseTitle, type MergedPhaseWithOpenBoxes, type MisplacedDeferral, NEXT_VOCABULARY, PHASE_CELL_LIMIT, PHASE_ID_PREFIX, PHASE_TITLE_LIMIT, PLAN_LANGUAGE, PLAN_STATUS, PLAN_VOCABULARY, PROSE_REASON, type PhaseDependency, type PhaseHeading, type PhaseProgress, type PhaseSchedule, type PhaseTally, type PhaseWithoutGate, type PhaseWithoutRow, type PlanHeader, type PlanLanguage, type PlanPhase, type PlanStatus, type PlanStep, type PlanVocabulary, type PlansByHref, type ProseReason, RESPONSE_ADDRESS, type ResponseAddress, type RowWithProse, type RowWithoutPhase, SELF_MERGE_LABEL, SHORT_NAME_LIMIT, SHORT_NAME_PROBLEM, STANDING_APPROVAL_TEXTS, type ShortNameFinding, type ShortNameProblem, type SprintDocument, type SprintLane, type SprintPlanRow, type SprintPlanTable, type StatusWord, type StepProgress, WAITING_VOCABULARY, activeItem, boardRowsWithProse, boardRowsWithoutPhase, classifyStatus, columnModels, countDecisions, criticalPath, currentPhase, currentPhaseOf, deferralTarget, differsFromColumn, endsPhase, findDrift, hasLanesTable, isCheckboxLine, isDocumentationGateItem, isOpenCheckboxLine, isPhaseFinished, isPhaseOpen, isPlanLanguage, isReviewGateLine, isTickedUnmerged, laneNameOf, laneProgress, longPhaseTitles, mergedPhasesWithOpenBoxes, misplacedDeferrals, newPhasesWithoutReviewGate, onlyDocumentationOpen, parallelGroups, parallelGroupsOfPlan, parseDependencyTable, parsePlanPhases, parseSprintLanes, phaseHeading, phaseHeadingPattern, phaseHeadings, phaseIdsOfCell, phaseIdsOfPlan, phaseLabel, phaseLabels, phaseProgress, phaseWaves, phasesText, phasesWithoutDependencyRow, readPhaseDependencies, readPlanHeader, readSprintDocument, resolvePlanPath, sectionHeading, shortNameFindings, shortTitle, sprintTitleOf, sumPhases, tallyPhases, wavesOfPlan, withoutRepeats };
|
package/dist/plan-format.js
CHANGED
|
@@ -4,6 +4,7 @@ import {
|
|
|
4
4
|
APPROVAL_TEXTS,
|
|
5
5
|
LANE_PROMPT_OPENING,
|
|
6
6
|
LANGUAGE_NAME,
|
|
7
|
+
NEXT_VOCABULARY,
|
|
7
8
|
PLAN_LANGUAGE,
|
|
8
9
|
PLAN_STATUS,
|
|
9
10
|
PLAN_VOCABULARY,
|
|
@@ -15,7 +16,7 @@ import {
|
|
|
15
16
|
isPlanLanguage,
|
|
16
17
|
phaseHeading,
|
|
17
18
|
sectionHeading
|
|
18
|
-
} from "./chunk-
|
|
19
|
+
} from "./chunk-RMMXD4G5.js";
|
|
19
20
|
|
|
20
21
|
// src/plan-format/lanes.ts
|
|
21
22
|
import { posix } from "path";
|
|
@@ -499,7 +500,7 @@ var dependsOf = (cell, language) => {
|
|
|
499
500
|
return { after, external };
|
|
500
501
|
};
|
|
501
502
|
var pathOf = (entry) => {
|
|
502
|
-
if (/\s/.test(entry)) return null;
|
|
503
|
+
if (/\s/.test(entry) || entry.includes("[]")) return null;
|
|
503
504
|
const glob = entry.search(GLOB_CHARACTER);
|
|
504
505
|
const literal = glob === -1 ? entry : entry.slice(0, Math.max(entry.lastIndexOf("/", glob), 0));
|
|
505
506
|
const path = literal.replace(/^\.\//, "").replace(/\/+$/, "");
|
|
@@ -902,6 +903,7 @@ export {
|
|
|
902
903
|
APPROVAL_TEXTS,
|
|
903
904
|
LANE_PROMPT_OPENING,
|
|
904
905
|
LANGUAGE_NAME,
|
|
906
|
+
NEXT_VOCABULARY,
|
|
905
907
|
PHASE_CELL_LIMIT,
|
|
906
908
|
PHASE_ID_PREFIX,
|
|
907
909
|
PHASE_TITLE_LIMIT,
|
package/install.sh
CHANGED
|
@@ -9,7 +9,7 @@ set -eu
|
|
|
9
9
|
|
|
10
10
|
# The default is the version this file ships with. The release bump changes it together with
|
|
11
11
|
# package.json; install.test.ts fails while the two differ. Overridable, but only by a plain release.
|
|
12
|
-
JACKHERD_VERSION="${JACKHERD_VERSION:-1.
|
|
12
|
+
JACKHERD_VERSION="${JACKHERD_VERSION:-1.11.0}"
|
|
13
13
|
|
|
14
14
|
JACKHERD_PACKAGE='jackherd'
|
|
15
15
|
# Test seam: the terminal the wizard asks its questions on.
|
|
@@ -28,7 +28,8 @@ export const relevantLines = (text: string): string => {
|
|
|
28
28
|
* Records the questions of the session's dialogs that ended without an answer, and closes the open records of every
|
|
29
29
|
* session that a dialog in this transcript has answered since. The whole transcript is read, not the last turn: a
|
|
30
30
|
* rejected dialog ends its turn without a Stop hook, so it is found at the end of the next turn. Claude Code's hook
|
|
31
|
-
* input: `cwd`, `session_id`, `transcript_path`.
|
|
31
|
+
* input: `cwd`, `session_id`, `transcript_path`. A question whose text has an open record already adds none, so asking
|
|
32
|
+
* it again and putting it off again leaves one. Writes nothing on any failure.
|
|
32
33
|
*/
|
|
33
34
|
export const runOpenQuestion = (input: unknown, dependencies: OpenQuestionDependencies): void => {
|
|
34
35
|
try {
|
|
@@ -44,8 +45,12 @@ export const runOpenQuestion = (input: unknown, dependencies: OpenQuestionDepend
|
|
|
44
45
|
if (answer) dependencies.writeRecord(main, { ...record, closedAt: answer.answeredAt })
|
|
45
46
|
}
|
|
46
47
|
const known = new Set(stored.map(({ id }) => id))
|
|
47
|
-
|
|
48
|
-
|
|
48
|
+
const openTexts = new Set(stored.filter(({ closedAt }) => closedAt === null).map(({ question }) => question))
|
|
49
|
+
for (const record of openQuestionsOf(entries, { cwd, session, answered, idOf: dependencies.idOf })) {
|
|
50
|
+
if (known.has(record.id) || openTexts.has(record.question)) continue
|
|
51
|
+
openTexts.add(record.question)
|
|
52
|
+
dependencies.writeRecord(main, record)
|
|
53
|
+
}
|
|
49
54
|
} catch {
|
|
50
55
|
// A failed record is no record; the herd shows no question.
|
|
51
56
|
}
|
|
@@ -42,6 +42,8 @@ Add a fenced ` ```mermaid ` block **when it removes reader effort**:
|
|
|
42
42
|
|
|
43
43
|
Keep each diagram to one idea; two small diagrams beat one dense one. Small or single-file PRs need none.
|
|
44
44
|
|
|
45
|
+
Write edge labels as `-->|"label"|` (`-- text -->` breaks on a `--` in it); `jh mermaid <body file>` must exit 0 before `gh pr create` or `gh pr edit`.
|
|
46
|
+
|
|
45
47
|
## Review order (large PRs)
|
|
46
48
|
|
|
47
49
|
When a PR spans many files, add a short **suggested review order** — **pure/domain logic first, adapters next, UI and wiring last**. A `| # | Area | Start here | Why first |` table works well.
|
|
@@ -15,8 +15,8 @@ You add one entry to `watch.sources`, so that `jh watch` reports a new or change
|
|
|
15
15
|
- **Service:** the services the recipe index lists, and "another command that prints JSON".
|
|
16
16
|
- **What to follow:** the item the argument names (its comments, recommended) or a query over several items.
|
|
17
17
|
- **Lane:** the lane the reports name, from the board's lanes table, or none.
|
|
18
|
-
- **Ticket:** whether the entries are tickets (`ticket: true`, recommended for an issue tracker or a project board), which the herd shows as a badge beside the plan of their lane: the lane above, or the lane whose name, board row or plan names the ticket's id. A source of comments or messages is no ticket. The path of the status you find yourself in step 3.
|
|
19
|
-
- **What reports:** a change of what the user reads (title, body, the latest comment; recommended), or a change of named fields such as a status (`reportOn` with those fields, mapped in `map`).
|
|
18
|
+
- **Ticket:** whether the entries are tickets (`ticket: true`, recommended for an issue tracker or a project board), which the herd shows as a badge beside the plan of their lane: the lane above, or the lane whose name, board row or plan names the ticket's id. A source of comments or messages is no ticket; it shows in the herd's `Sources` block instead (a click opens the entry at `map.url`). The path of the status you find yourself in step 3.
|
|
19
|
+
- **Tone:** for a non-ticket source, the colour of its `Sources` mark while its report is new (`tone`: amber, teal, grey, red, green, blue, magenta); recommended: no `tone`.- **What reports:** a change of what the user reads (title, body, the latest comment; recommended), or a change of named fields such as a status (`reportOn` with those fields, mapped in `map`).
|
|
20
20
|
- **Own changes:** ignore the user's own account on that service (`ignoreAuthors`, needs an author in the map), or report everything.
|
|
21
21
|
|
|
22
22
|
## 2. Check, read only
|
|
@@ -30,7 +30,7 @@ Anything missing goes to the user as the command to run themselves (`! <command>
|
|
|
30
30
|
|
|
31
31
|
Before filling, read the help of the installed CLI version for every command the recipe calls (`acli jira workitem search --help` and `workitem view --help`, `gh issue list --help`) and confirm that the fields and options the entry needs exist there. Read the provider's web documentation only when the help leaves it open or no recipe fits. A recipe is a starting point; the installed version decides.
|
|
32
32
|
|
|
33
|
-
Fill the recipe with the item or query and the answers from step 1: a `name` of letters, digits, `.`, `_` and `-` that says what is followed, `lane`, `ignoreAuthors` and `
|
|
33
|
+
Fill the recipe with the item or query and the answers from step 1: a `name` of letters, digits, `.`, `_` and `-` that says what is followed, `lane`, `ignoreAuthors`, `ticket` and `tone` where chosen, and a short `label` (e.g. `Error log · Checkout`; it prefixes the source's `Waiting for you` rows). For a ticket source, find the path of the status in the output (from the CLI's help, or the dry run with `--raw`) and set it as `map.status`; the entry you show for approval in step 4 carries it, and without a status in the output the entry has none and the badge shows only the key. A recipe that needs a script (a token from the environment, or one call per item) gets TypeScript run by Bun: write it, from the recipe's script under `recipes/sources/`, to the scratchpad first as `<name>.ts`, never into the repository before step 4, and let the entry's `command` be `["bun", "scripts/sources/<name>.ts"]`. Script and direct command follow the index's **Rules every recipe follows**.
|
|
34
34
|
|
|
35
35
|
Write the entry as one JSON object to a draft file in the scratchpad and run, from the main checkout:
|
|
36
36
|
|
|
@@ -67,7 +67,7 @@ Each file under `references/` is read when its trigger fires: the step or the ev
|
|
|
67
67
|
`jh lane prompt <lane> [--board <board>]` writes the lane prompt from the lane's board row and its plan, in
|
|
68
68
|
the plan's language, to `.claude/handover/<lane>-prompt.md` and prints the path. It opens with a first line
|
|
69
69
|
that names the lane, which the hooks and the project's rules read: keep that line as it is. Before you send
|
|
70
|
-
it, add to the file with `Edit
|
|
70
|
+
it, add to the file with `Edit`, below the marker line at its end (it stays through every new writing), the open questions that touch the lane and what the project
|
|
71
71
|
supplement adds to the lane prompt. Never paste the rules of this skill into a lane prompt. The lane asks you in text blocks at the end of its turn; answer them with
|
|
72
72
|
`herdr agent prompt` (§ 2 step 8).
|
|
73
73
|
|
|
@@ -290,10 +290,18 @@ watcher reports an open row once when it falls due (`due`, above); an empty stat
|
|
|
290
290
|
and a reworded or moved row is a new appointment and reports again. Close a reported row through its
|
|
291
291
|
status cell.
|
|
292
292
|
|
|
293
|
+
**Board grooming** is an appointment of its own, a row in that section whose action starts with
|
|
294
|
+
`Board-Pflege` (`Board grooming`); a board without one gets it, due a week from now. When it reports:
|
|
295
|
+
check that the open lane rows still serve the board's goal (a mismatch joins the bundled question), rewrite the
|
|
296
|
+
board's `Als Nächstes` (`Next`) section (three lines at most, each with a date), clear finished lane
|
|
297
|
+
rows, ask for outdated plans in one bundled question, then set its `When` a week after now and leave its status
|
|
298
|
+
empty: this is the one appointment that is moved, not closed. The herd
|
|
299
|
+
counts `groomed <n>d ago` from it and turns it amber at eight days.
|
|
300
|
+
|
|
293
301
|
**Anything that waits on the user's answer** (a preview or a file sent to them, a question put to them, a
|
|
294
302
|
report handed over for acceptance) goes into the board in the same turn you send it, in the section
|
|
295
303
|
`## Wartet auf dich` (German plans) or `## Waiting for you` (English), one row `Since | Item | Origin | Status`
|
|
296
|
-
(`Seit | Punkt | Herkunft | Stand`) with the time as in **An agreed time
|
|
304
|
+
(`Seit | Punkt | Herkunft | Stand`) with the time as in **An agreed time**; for a source's report the origin is the source's name, and the herd prefixes the row with its label. It survives a hand-over, which a
|
|
297
305
|
message in this chat does not. Close a row in its status cell in the turn the user's answer arrives (also a
|
|
298
306
|
"no"), or when the thing is withdrawn; an empty status counts as open. A file sent with `SendUserFile` and an
|
|
299
307
|
Artifact you publish need no row (the kit hook `sent-file` records each): close them after the answer with
|
package/package.json
CHANGED
package/recipes/sources.md
CHANGED
|
@@ -60,6 +60,10 @@ A run that ends with an exit code other than 0, runs past 30 seconds (then its w
|
|
|
60
60
|
|
|
61
61
|
**Show a ticket beside its plan.** `"ticket": true` marks a source's entries as tickets. The herd then shows each one as a badge in the 📎 line of its lane's plan, right after `📄 Plan`: `📡 T-123 · In Progress`, linked to the ticket. A ticket belongs to the source's `lane`, and also to any lane whose board row, name or plan names its id as a whole word (`T-12` is not found in `T-123`); so one source listing all your open tickets works without `lane`. `map.status` is the status the badge shows; without it the badge shows only the key. A ticket whose last reported change is less than a day old is amber, and a folded lane then shows `📡 <n>` in amber before its bar, linked to the first new ticket. A lane shows at most three tickets, new ones first, then `+<n>`; a link chip of the plan with the same URL gives way to the badge. For this the saved state keeps, of a marked source only, each entry of its last successful run with its URL, its status (stored like a `reportOn` value) and the time its last change was reported. The badges come from the watcher's state like the pull request badges: without a running watcher or with a state older than three minutes there are none, and the header says `watcher off` or `state 4 min old`, also without a pull request. The [GitHub Projects recipe](#user-content-recipes) is a ticket source with a status.
|
|
62
62
|
|
|
63
|
+
**Show a source in the herd.** A source without `ticket` appears in the herd's `Sources` block, one row each: its name, when it last ran (`ran 12 min ago`), since when it fails (`failing since 3 h ago`, mark red) and its newest report (mark amber while that report is under a day old). A source with several entries is one folded row; a click opens its entries (up to five, then `+<n> more`), each with its title, `map.count` as `113×` and the time of its last change. A click on an entry opens its `url` (the watcher keeps it only as a checked `https:` URL of at most 200 characters, so map a short link), `[ask]` asks the coordinator to look at that entry. An entry that an open row of "Waiting for you" already asks about (the row's `Origin` names the source and its text the title) is dim and says `↑ asked`; the row is amber only for a new entry nobody asked about. The watcher keeps the last 20 entries of such a source. `tone` (amber, teal, grey, red, green, blue or magenta) sets the mark's colour while the report is new, instead of the tone of the role `new`; the roles `waiting`, `new`, `running` and `resting` take their tones from `plans.tones` in the config (defaults: amber, amber, teal, grey).
|
|
64
|
+
|
|
65
|
+
**Name a source in "Waiting for you".** A row of the board's waiting section whose `Origin` cell is the name of a source (case ignored) shows `<label>: <row>` in the herd; `label` (one line, at most 40 characters) is optional, without it the source's name stands before the row. `/jh-follow` proposes a short label when it writes the entry.
|
|
66
|
+
|
|
63
67
|
**How you hear about it.** The report goes to the coordinator, as a `=== source …` event of its watcher. It passes you one line with the entry, its gist and the link. A decision inside it, such as a product owner's answer, it takes over only after you confirmed it, since the text comes from outside. You hear of it only while the coordinator's session and its watcher run; what happened in between is reported at the next start. There is no desktop notification of its own: you get the one herdr shows for any lane that needs you. What a source reports is a change in the mapped content fields (`title`, `author`, `body`, `url`), or with `reportOn` a change of the fields it names, such as a status.
|
|
64
68
|
|
|
65
69
|
**Try a source before the watcher runs it.** `jh watch source <name> --dry-run` runs a configured source once; a draft not yet in the config comes as a file (`jh watch source draft.json --dry-run`, one source object) or on stdin (`-`). It lists the entries (`<id> · <author> · <title>`), says that the watcher's first run of the source is a baseline and reports nothing, and shows one entry as a later report would print it; it neither reads nor changes the watcher's state. A field of `map` that is empty in every entry is named with its path (`map.updatedAt: in 23 of 23 entries empty (.fields.updated)`), read from the raw output, so a run that failed on a missing `id` or `updatedAt` names it too; the dry run then ends with exit code 1, as for a failed run, and `/jh-follow` does not write the source. Without entries it says `0 entries: map not checked`. `--raw` adds the command's output, for finding the paths of `items` and `map`:
|
|
@@ -297,6 +297,65 @@
|
|
|
297
297
|
}
|
|
298
298
|
},
|
|
299
299
|
"additionalProperties": false
|
|
300
|
+
},
|
|
301
|
+
"tones": {
|
|
302
|
+
"default": {},
|
|
303
|
+
"type": "object",
|
|
304
|
+
"properties": {
|
|
305
|
+
"waiting": {
|
|
306
|
+
"default": "amber",
|
|
307
|
+
"type": "string",
|
|
308
|
+
"enum": [
|
|
309
|
+
"amber",
|
|
310
|
+
"teal",
|
|
311
|
+
"grey",
|
|
312
|
+
"red",
|
|
313
|
+
"green",
|
|
314
|
+
"blue",
|
|
315
|
+
"magenta"
|
|
316
|
+
]
|
|
317
|
+
},
|
|
318
|
+
"new": {
|
|
319
|
+
"default": "amber",
|
|
320
|
+
"type": "string",
|
|
321
|
+
"enum": [
|
|
322
|
+
"amber",
|
|
323
|
+
"teal",
|
|
324
|
+
"grey",
|
|
325
|
+
"red",
|
|
326
|
+
"green",
|
|
327
|
+
"blue",
|
|
328
|
+
"magenta"
|
|
329
|
+
]
|
|
330
|
+
},
|
|
331
|
+
"running": {
|
|
332
|
+
"default": "teal",
|
|
333
|
+
"type": "string",
|
|
334
|
+
"enum": [
|
|
335
|
+
"amber",
|
|
336
|
+
"teal",
|
|
337
|
+
"grey",
|
|
338
|
+
"red",
|
|
339
|
+
"green",
|
|
340
|
+
"blue",
|
|
341
|
+
"magenta"
|
|
342
|
+
]
|
|
343
|
+
},
|
|
344
|
+
"resting": {
|
|
345
|
+
"default": "grey",
|
|
346
|
+
"type": "string",
|
|
347
|
+
"enum": [
|
|
348
|
+
"amber",
|
|
349
|
+
"teal",
|
|
350
|
+
"grey",
|
|
351
|
+
"red",
|
|
352
|
+
"green",
|
|
353
|
+
"blue",
|
|
354
|
+
"magenta"
|
|
355
|
+
]
|
|
356
|
+
}
|
|
357
|
+
},
|
|
358
|
+
"additionalProperties": false
|
|
300
359
|
}
|
|
301
360
|
},
|
|
302
361
|
"additionalProperties": false
|
|
@@ -483,6 +542,9 @@
|
|
|
483
542
|
},
|
|
484
543
|
"status": {
|
|
485
544
|
"type": "string"
|
|
545
|
+
},
|
|
546
|
+
"count": {
|
|
547
|
+
"type": "string"
|
|
486
548
|
}
|
|
487
549
|
},
|
|
488
550
|
"required": [
|
|
@@ -506,6 +568,12 @@
|
|
|
506
568
|
"minimum": 1,
|
|
507
569
|
"maximum": 9007199254740991
|
|
508
570
|
},
|
|
571
|
+
"label": {
|
|
572
|
+
"type": "string",
|
|
573
|
+
"minLength": 1,
|
|
574
|
+
"maxLength": 40,
|
|
575
|
+
"pattern": "^[^\\r\\n]+$"
|
|
576
|
+
},
|
|
509
577
|
"lane": {
|
|
510
578
|
"type": "string",
|
|
511
579
|
"minLength": 1
|
|
@@ -513,6 +581,18 @@
|
|
|
513
581
|
"ticket": {
|
|
514
582
|
"type": "boolean"
|
|
515
583
|
},
|
|
584
|
+
"tone": {
|
|
585
|
+
"type": "string",
|
|
586
|
+
"enum": [
|
|
587
|
+
"amber",
|
|
588
|
+
"teal",
|
|
589
|
+
"grey",
|
|
590
|
+
"red",
|
|
591
|
+
"green",
|
|
592
|
+
"blue",
|
|
593
|
+
"magenta"
|
|
594
|
+
]
|
|
595
|
+
},
|
|
516
596
|
"reportOn": {
|
|
517
597
|
"minItems": 1,
|
|
518
598
|
"maxItems": 10,
|
package/src/cli.ts
CHANGED
|
@@ -25,6 +25,7 @@ export const COMMANDS: CommandTable = {
|
|
|
25
25
|
init: () => import('./sync/init-command'),
|
|
26
26
|
[HERD_COMMAND.alias]: () => import('./plans/command'),
|
|
27
27
|
lane: () => import('./lane/command'),
|
|
28
|
+
mermaid: () => import('./mermaid/command'),
|
|
28
29
|
preview: () => import('./preview/command'),
|
|
29
30
|
settled: () => import('./settled/command'),
|
|
30
31
|
sync: () => import('./sync/command'),
|