jackherd 1.9.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 +49 -0
- package/INSTALL.md +1 -1
- package/README.md +65 -32
- package/dist/{chunk-MCP4XJQH.js → chunk-RMMXD4G5.js} +18 -6
- package/dist/config.d.ts +99 -4
- package/dist/config.js +105 -29
- package/dist/plan-format.d.ts +51 -6
- package/dist/plan-format.js +49 -7
- 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/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 -187
- 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 +57 -0
- package/kit/hooks/hooks/open-question/store.ts +39 -0
- package/kit/hooks/hooks/sent-file/store.ts +3 -12
- 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 +13 -5
- package/kit/review/agents/skill-review.md +34 -0
- package/kit/review/skills/pre-commit/SKILL.md +1 -1
- package/kit/rules/rules/kit/pull-requests.md +2 -0
- package/kit/workflow/skills/follow/SKILL.md +3 -10
- package/kit/workflow/skills/implement/SKILL.md +8 -6
- package/kit/workflow/skills/orchestrate/SKILL.md +218 -433
- 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 +3 -1
- package/recipes/README.md +2 -1
- package/recipes/sources.md +5 -1
- package/schemas/jackherd.schema.json +139 -5
- 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 +2 -0
- package/src/config/auto-window.ts +8 -0
- package/src/config/link-kinds.ts +7 -1
- package/src/config/schema.ts +82 -25
- package/src/config/tones.ts +27 -0
- 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/additions.ts +14 -0
- package/src/lane-prompt/build.ts +74 -0
- package/src/lane-prompt/command.ts +93 -0
- package/src/lane-prompt/input.ts +157 -0
- package/src/lane-prompt/options.ts +70 -0
- package/src/lane-prompt/texts.ts +101 -0
- package/src/mermaid/command.ts +36 -0
- package/src/mermaid/problems.ts +48 -0
- package/src/plan-format/clock.ts +8 -0
- package/src/plan-format/dependencies.ts +9 -6
- package/src/plan-format/index.ts +1 -0
- package/src/plan-format/short-names.ts +71 -0
- package/src/plan-format/waiting.ts +22 -4
- package/src/plans/appointment-rows.ts +83 -0
- package/src/plans/ask-coordinator.ts +111 -0
- package/src/plans/ask-target.ts +36 -0
- package/src/plans/board-close.ts +85 -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/fetch.ts +26 -3
- package/src/plans/frame.ts +5 -12
- package/src/plans/git.ts +54 -5
- package/src/plans/groomed.ts +27 -0
- 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-summary.ts +253 -45
- package/src/plans/layout-phase.ts +36 -11
- package/src/plans/layout-summary.ts +89 -18
- package/src/plans/layout.ts +502 -98
- package/src/plans/link-chips.ts +23 -4
- package/src/plans/live.ts +178 -23
- package/src/plans/next-rows.ts +44 -0
- package/src/plans/phase-ids.ts +8 -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/planned.ts +22 -0
- package/src/plans/pull-requests.ts +17 -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/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 +111 -18
- package/src/plans/sent-files-read.ts +6 -15
- package/src/plans/sent-files.ts +7 -14
- package/src/plans/settings.ts +12 -1
- package/src/plans/signalled-phase.ts +42 -0
- package/src/plans/signals-read.ts +12 -4
- package/src/plans/snapshot.ts +162 -81
- 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/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 +66 -17
- package/src/plans/subagents.ts +64 -6
- 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 +48 -6
- package/src/plans/tones.ts +30 -0
- package/src/plans/view.ts +25 -11
- package/src/plans/waiting-click.ts +295 -35
- package/src/plans/waiting-records.ts +39 -0
- package/src/plans/waiting-window.ts +8 -0
- package/src/preview/command.ts +25 -3
- package/src/shared/private-location.ts +89 -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/claude-read.ts +27 -10
- package/src/terminal/text.ts +16 -3
- package/src/terminal/types.ts +4 -0
- package/src/version/skill-diff.ts +46 -0
- package/src/vocabulary/index.ts +26 -6
- package/src/waiting/command.ts +22 -7
- package/src/watch/appointments.ts +1 -2
- package/src/watch/asking-lanes.ts +40 -0
- package/src/watch/base-tip.ts +11 -0
- package/src/watch/command.ts +330 -105
- package/src/watch/heartbeat-progress.ts +6 -18
- package/src/watch/kit-update.ts +28 -9
- package/src/watch/lane-name.ts +6 -0
- package/src/watch/lane-progress.ts +40 -8
- package/src/watch/lane-report-file.ts +20 -5
- package/src/watch/lane-report.ts +32 -4
- package/src/watch/lane-sources.ts +31 -3
- package/src/watch/main-checkout.ts +34 -0
- package/src/watch/plan-badges-read.ts +22 -9
- package/src/watch/plan-badges.ts +10 -2
- package/src/watch/pull-requests.ts +6 -2
- package/src/watch/reference-paths.ts +87 -0
- package/src/watch/report-questions.ts +4 -3
- 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-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 +47 -4
- package/src/watch/stream-output.ts +4 -3
- 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 +5 -15
- package/src/watch/task-parallel-read.ts +3 -1
- package/src/watch/task-parallel.ts +36 -7
- 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/watch-events.ts +23 -0
- package/src/watch/watcher-lock.ts +25 -29
- 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
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { phaseLabel } from '../plan-format'
|
|
2
2
|
import { fit, paint, spread, visibleLength } from '../terminal/text'
|
|
3
3
|
import { deeper, type Frame, joinFrames, nest, rowFrame, textFrame } from './frame'
|
|
4
|
-
import type { ActivePhase, LaneSummary } from './lane-summary'
|
|
4
|
+
import type { ActivePhase, LaneSummary, PlacedPhase } from './lane-summary'
|
|
5
5
|
import {
|
|
6
6
|
activeArrow,
|
|
7
7
|
activeTitle,
|
|
@@ -14,12 +14,14 @@ import {
|
|
|
14
14
|
phaseChildren,
|
|
15
15
|
phaseCountCell,
|
|
16
16
|
plain,
|
|
17
|
+
subagentLine,
|
|
17
18
|
TASK_INDENT,
|
|
18
19
|
taskFrame,
|
|
20
|
+
taskTitle,
|
|
19
21
|
} from './layout-phase'
|
|
20
22
|
import { type PhaseModel, phaseModelKey } from './phase-models'
|
|
21
23
|
import { phaseRanges } from './phase-ranges'
|
|
22
|
-
import { itemKey, phaseKey } from './selection'
|
|
24
|
+
import { finishedKey, itemKey, nextKey, phaseKey } from './selection'
|
|
23
25
|
import { PHASE_COUNT } from './symbols'
|
|
24
26
|
import { type HerdTexts, TEXTS } from './texts'
|
|
25
27
|
|
|
@@ -62,6 +64,46 @@ const activeRow = (active: ActivePhase, current: boolean, context: SummaryContex
|
|
|
62
64
|
return spread(head, candidates.find((right) => titleRoom(right) >= MIN_TITLE_WIDTH) ?? count, width)
|
|
63
65
|
}
|
|
64
66
|
|
|
67
|
+
/** What an active task reads as on one row: `Review gate` for a box of the review gate, else its short name or text. */
|
|
68
|
+
const taskText = (item: ActivePhase['phase']['items'][number], labels: HerdTexts): string =>
|
|
69
|
+
item.gate ? labels.reviewGate : taskTitle(item.text)
|
|
70
|
+
|
|
71
|
+
/** The texts of the tasks agents report on the phase, then the descriptions of the subagents that name no phase as `Subagent: …`. */
|
|
72
|
+
const reportedTexts = (
|
|
73
|
+
{ phase, tasks }: ActivePhase,
|
|
74
|
+
subagentTasks: readonly string[],
|
|
75
|
+
labels: HerdTexts,
|
|
76
|
+
): string[] => [
|
|
77
|
+
...tasks
|
|
78
|
+
.filter(({ guessed }) => !guessed)
|
|
79
|
+
.flatMap(({ index }) => {
|
|
80
|
+
const item = phase.items[index]
|
|
81
|
+
return item ? [taskText(item, labels)] : []
|
|
82
|
+
}),
|
|
83
|
+
...subagentTasks.map((description) => `${TEXTS.subagent} ${taskTitle(description)}`),
|
|
84
|
+
]
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* `▶ Name +1` for a folded lane, behind `indent`: the first task the phase is on with the arrow of the open lane, `+n`
|
|
88
|
+
* for the others in parallel at the end; no ticks, the phase row shows them; the name cut to the pane's edge. A task
|
|
89
|
+
* an agent reports comes first, the descriptions of the `subagentTasks` after it. Null while neither exists: a task
|
|
90
|
+
* the herd only guesses from words is no sign that the lane works.
|
|
91
|
+
*/
|
|
92
|
+
export const foldedTaskLine = (
|
|
93
|
+
active: ActivePhase,
|
|
94
|
+
subagentTasks: readonly string[],
|
|
95
|
+
labels: HerdTexts,
|
|
96
|
+
indent: string,
|
|
97
|
+
width: number,
|
|
98
|
+
): string | null => {
|
|
99
|
+
const [first, ...others] = reportedTexts(active, subagentTasks, labels)
|
|
100
|
+
if (first === undefined) return null
|
|
101
|
+
const lead = `${activeArrow(false)} `
|
|
102
|
+
const tail = others.length > 0 ? ` +${others.length}` : ''
|
|
103
|
+
const room = Math.max(width - visibleLength(indent) - visibleLength(lead) - visibleLength(tail), 1)
|
|
104
|
+
return `${indent}${lead}${activeTitle(fit(first, room), false)}${tail}`
|
|
105
|
+
}
|
|
106
|
+
|
|
65
107
|
/**
|
|
66
108
|
* One row per active task under a closed running phase, each with its own arrow: the title bold and the agent dim
|
|
67
109
|
* after it where agents reported it, `▷` and a plain title where the herd guesses. Always on one line whatever the
|
|
@@ -72,7 +114,7 @@ const taskLinesFrame = (context: SummaryContext, phaseRowKey: string, { phase, t
|
|
|
72
114
|
tasks.flatMap((task) => {
|
|
73
115
|
const item = phase.items[task.index]
|
|
74
116
|
if (!item) return []
|
|
75
|
-
const text = item
|
|
117
|
+
const text = taskText(item, context.labels)
|
|
76
118
|
const line = spread(
|
|
77
119
|
`${TASK_INDENT}${activeArrow(task.guessed)} ${activeTitle(text, task.guessed)}`,
|
|
78
120
|
agentCell(task.agent),
|
|
@@ -117,30 +159,59 @@ const nextLineText = (summary: LaneSummary, labels: HerdTexts): string => {
|
|
|
117
159
|
return text ? `${paint.dim(labels.next)} ${text}` : ''
|
|
118
160
|
}
|
|
119
161
|
|
|
120
|
-
/** `
|
|
121
|
-
const unmergedNote = ({ finished }: LaneSummary, labels: HerdTexts): string => {
|
|
122
|
-
const unmerged = finished.filter(({ unmerged }) => unmerged).map(({ id }) => id)
|
|
123
|
-
if (unmerged.length === 0) return ''
|
|
124
|
-
const which = unmerged.length === finished.length ? '' : `${phaseRanges(unmerged)} `
|
|
125
|
-
return ` · ${paint.yellow(`${which}${labels.notMerged}`)}`
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
/** `✓ P1–P7, P10 · not merged` on one line: one ✓, the finished phases as ranges. */
|
|
162
|
+
/** `done P1–P7, P10` on one line: the word `done` in green, the finished phases as ranges. */
|
|
129
163
|
const finishedText = (summary: LaneSummary, labels: HerdTexts): string => {
|
|
130
164
|
const phases = phaseRanges(summary.finished.map(({ id }) => id))
|
|
131
|
-
return phases ? `${paint.green(
|
|
165
|
+
return phases ? `${paint.green(labels.done)} ${phases}` : ''
|
|
132
166
|
}
|
|
133
167
|
|
|
134
|
-
/**
|
|
135
|
-
const
|
|
168
|
+
/** A phase that does not run as a row, which opens to its tasks like a running one; closed, it has no task line below it. */
|
|
169
|
+
const restingFrame = (context: SummaryContext, { phase, stepIndex }: PlacedPhase): Frame =>
|
|
170
|
+
activeFrame(context, { phase, stepIndex, minutesAgo: null, tasks: [] })
|
|
171
|
+
|
|
172
|
+
/**
|
|
173
|
+
* One line of text cut at the pane's edge, a row under `key`; no line when the text is empty. Open, it continues with
|
|
174
|
+
* a row per phase it names and the `unwritten` lines, each phase opening to its tasks.
|
|
175
|
+
*/
|
|
176
|
+
const foldFrame = (
|
|
177
|
+
context: SummaryContext,
|
|
178
|
+
key: string,
|
|
179
|
+
text: string,
|
|
180
|
+
{ phases, unwritten }: { phases: readonly PlacedPhase[]; unwritten: string[] },
|
|
181
|
+
): Frame => {
|
|
182
|
+
if (!text) return textFrame([])
|
|
183
|
+
const row = rowFrame(key, [fit(text, context.width)], [], context)
|
|
184
|
+
if (!context.state.expanded.has(key)) return row
|
|
185
|
+
const inner = deeper(context)
|
|
186
|
+
const children = [
|
|
187
|
+
...phases.map((placed) => restingFrame(inner, placed)),
|
|
188
|
+
...unwritten.map((line) => textFrame([fit(line, inner.width)])),
|
|
189
|
+
]
|
|
190
|
+
return joinFrames([row, nest(children)])
|
|
191
|
+
}
|
|
136
192
|
|
|
137
193
|
/** What an open lane shows above its phases, drawn at the width of its branches: the session, its pull requests and its link chips. */
|
|
138
194
|
export type LaneHead = { session: Frame; pullRequests: Frame; chips: Frame }
|
|
139
195
|
|
|
196
|
+
/** The `next` and `done` rows of an open lane. */
|
|
197
|
+
const restingFrames = (context: SummaryContext, summary: LaneSummary): Frame[] => {
|
|
198
|
+
const laneName = context.progress.lane.name
|
|
199
|
+
return [
|
|
200
|
+
foldFrame(context, nextKey(laneName), nextLineText(summary, context.labels), {
|
|
201
|
+
phases: summary.waitingPhases,
|
|
202
|
+
unwritten: summary.unwritten.map(unwrittenText),
|
|
203
|
+
}),
|
|
204
|
+
foldFrame(context, finishedKey(laneName), finishedText(summary, context.labels), {
|
|
205
|
+
phases: summary.finishedPhases,
|
|
206
|
+
unwritten: [],
|
|
207
|
+
}),
|
|
208
|
+
]
|
|
209
|
+
}
|
|
210
|
+
|
|
140
211
|
/**
|
|
141
212
|
* The children of an open lane, one branch each, told apart by their marks rather than by a label: the session
|
|
142
213
|
* (`⎇`), the pull requests (`↗`), the link chips, then one branch per running phase (its tasks `▶`/`▷` under it), the
|
|
143
|
-
* `now:` lines, `next` with the open phases that wait, and
|
|
214
|
+
* `now:` and `Subagent:` lines, `next` with the open phases that wait, and `done` with the finished ones; a branch without lines is left out.
|
|
144
215
|
*/
|
|
145
216
|
export const summaryChildren = (context: LaneContext, summary: LaneSummary, head: LaneHead): Frame[] => {
|
|
146
217
|
const labels = TEXTS.herd
|
|
@@ -152,7 +223,7 @@ export const summaryChildren = (context: LaneContext, summary: LaneSummary, head
|
|
|
152
223
|
head.chips,
|
|
153
224
|
...summary.active.map((active) => activeFrame(inner, active)),
|
|
154
225
|
...summary.unplanned.map((task) => textFrame([nowLine(task, width)])),
|
|
155
|
-
|
|
156
|
-
|
|
226
|
+
...summary.subagentTasks.map((description) => textFrame([subagentLine(description, width)])),
|
|
227
|
+
...restingFrames(inner, summary),
|
|
157
228
|
]
|
|
158
229
|
}
|