jackherd 1.6.0 → 1.7.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 +31 -0
- package/INSTALL.md +176 -0
- package/README.md +260 -315
- package/assets/branding/README.md +7 -3
- package/assets/branding/jackherd-logo-dark-1024.png +0 -0
- package/assets/branding/jackherd-logo-dark-512.png +0 -0
- package/assets/branding/jackherd-logo-dark.svg +1 -1
- package/assets/icons/bark-dark.svg +1 -0
- package/assets/icons/bark.svg +1 -0
- package/assets/icons/bowl-dark.svg +1 -0
- package/assets/icons/bowl.svg +1 -0
- package/assets/icons/decide-dark.svg +1 -0
- package/assets/icons/decide.svg +1 -0
- package/assets/icons/ear-dark.svg +1 -0
- package/assets/icons/ear.svg +1 -0
- package/assets/icons/lanes-dark.svg +1 -0
- package/assets/icons/lanes.svg +1 -0
- package/assets/icons/plan-dark.svg +1 -0
- package/assets/icons/plan.svg +1 -0
- package/assets/icons/space.svg +1 -0
- package/dist/{chunk-QJSXHHQ3.js → chunk-OBUWTQ6Z.js} +25 -0
- package/dist/config.d.ts +14 -3
- package/dist/config.js +111 -10
- package/dist/plan-format.d.ts +180 -77
- package/dist/plan-format.js +292 -93
- package/docs/lanes-dark.svg +50 -0
- package/docs/lanes.svg +50 -1
- package/docs/skills-dark.svg +65 -0
- package/docs/skills.svg +65 -1
- package/docs/workflow-dark.svg +138 -0
- package/docs/workflow.svg +135 -169
- package/herdr-plugin/herdr-plugin.toml +6 -6
- package/herdr-plugin/open-plans.ts +1 -1
- package/herdr-plugin/restore-plans.ts +7 -7
- package/install.sh +1 -1
- package/kit/hooks/hooks/approval-gate/decision.ts +61 -0
- package/kit/hooks/hooks/approval-gate/herdr-panes.ts +24 -0
- package/kit/hooks/hooks/approval-gate/index.ts +69 -0
- package/kit/hooks/hooks/approval-gate/lane.ts +14 -0
- package/kit/hooks/hooks/approval-gate/request.ts +111 -0
- package/kit/hooks/hooks/approval-gate/run.ts +94 -0
- package/kit/hooks/hooks/approval-gate/settings.ts +26 -0
- package/kit/hooks/hooks/approval-gate/store.ts +70 -0
- package/kit/hooks/hooks/approval-gate/transcripts.ts +40 -0
- package/kit/hooks/hooks/merge-guard/approval.ts +11 -74
- package/kit/hooks/hooks/merge-guard/run.ts +2 -1
- package/kit/hooks/hooks/model-gate/agent-definition.ts +13 -0
- package/kit/hooks/hooks/model-gate/index.ts +58 -0
- package/kit/hooks/hooks/model-gate/run.ts +63 -0
- package/kit/hooks/hooks/model-log/index.ts +60 -0
- package/kit/hooks/hooks/model-log/run.ts +57 -0
- package/kit/hooks/hooks/model-log/store.ts +40 -0
- package/kit/hooks/hooks/model-log/transcript.ts +37 -0
- package/kit/hooks/hooks/shared/checkout.ts +22 -0
- package/kit/hooks/hooks/shared/command.ts +6 -0
- package/kit/hooks/hooks/shared/config.ts +21 -0
- package/kit/hooks/hooks/shared/dialog-answer.ts +5 -0
- package/kit/hooks/hooks/shared/dialog-answers.ts +74 -0
- package/kit/hooks/hooks/shared/files.ts +19 -0
- package/kit/hooks/hooks/shared/fresh.ts +4 -0
- package/kit/hooks/hooks/shared/json.ts +4 -0
- package/kit/hooks/hooks/shared/model-family.ts +48 -0
- package/kit/hooks/hooks/shared/plan-model-table.ts +41 -0
- package/kit/hooks/hooks/shared/private-directory.ts +29 -0
- package/kit/hooks/hooks/shared/repository-directory.ts +14 -0
- package/kit/hooks/hooks/shared/subagent-phase.ts +99 -0
- package/kit/hooks/hooks.json +25 -0
- package/kit/workflow/skills/follow/SKILL.md +4 -3
- package/kit/workflow/skills/implement/SKILL.md +6 -6
- package/kit/workflow/skills/orchestrate/SKILL.md +113 -30
- package/kit/workflow/skills/plan/SKILL.md +5 -5
- package/kit/workflow/skills/start/SKILL.md +2 -2
- package/package.json +4 -1
- package/schemas/jackherd.schema.json +43 -5
- package/src/check/command.ts +31 -4
- package/src/check/deferral-arrows.ts +1 -1
- package/src/check/parallel-report.ts +23 -0
- package/src/check/plan-structure-check.ts +120 -53
- package/src/cli.ts +8 -2
- package/src/config/nested-quantifier.ts +73 -0
- package/src/config/repository-directory.ts +11 -0
- package/src/config/schema.ts +63 -8
- package/src/plan-format/board-prose.ts +36 -0
- package/src/plan-format/dependencies.ts +227 -0
- package/src/plan-format/documentation-gate.ts +16 -0
- package/src/plan-format/index.ts +23 -1
- package/src/plan-format/lanes.ts +35 -1
- package/src/plan-format/model-column.ts +52 -0
- package/src/plan-format/phases.ts +16 -1
- package/src/plan-format/plan-structure.ts +10 -28
- package/src/plan-format/progress.ts +7 -29
- package/src/plans/command.ts +3 -3
- package/src/plans/current-phase.ts +71 -0
- package/src/plans/ensure-panes.ts +2 -2
- package/src/plans/herd-command.ts +4 -0
- package/src/plans/lane-discovery.ts +14 -2
- package/src/plans/lane-tickets.ts +69 -0
- package/src/plans/layout.ts +182 -88
- package/src/plans/live.ts +5 -1
- package/src/plans/phase-models-read.ts +37 -0
- package/src/plans/phase-models.ts +70 -0
- package/src/plans/plan-panes.ts +8 -7
- package/src/plans/pull-requests.ts +78 -4
- package/src/plans/selection.ts +1 -40
- package/src/plans/settings.ts +9 -3
- package/src/plans/shown-with-more.ts +5 -0
- package/src/plans/snapshot.ts +82 -8
- package/src/plans/sprint-html.ts +2 -2
- package/src/plans/supervisor.ts +5 -4
- package/src/plans/symbols.ts +9 -6
- package/src/plans/texts.ts +30 -13
- package/src/plans/view.ts +1 -0
- package/src/sync/herdr-plugin.ts +1 -1
- package/src/sync/next-steps.ts +1 -1
- package/src/sync/render.ts +2 -1
- package/src/sync/setup-questions.ts +2 -2
- package/src/terminal/text.ts +4 -0
- package/src/terminal/types.ts +1 -1
- package/src/vocabulary/index.ts +39 -0
- package/src/watch/approvals.ts +96 -0
- package/src/watch/command.ts +154 -50
- package/src/watch/failed-tests.ts +52 -0
- package/src/watch/failure-read.ts +56 -0
- package/src/watch/failures.ts +107 -0
- package/src/watch/feedback-item.ts +21 -0
- package/src/watch/feedback-read.ts +2 -1
- package/src/watch/feedback.ts +37 -28
- package/src/watch/gh-process.ts +53 -0
- package/src/watch/gh.ts +10 -20
- package/src/watch/heartbeat-progress.ts +1 -1
- package/src/watch/lane-model.ts +54 -0
- package/src/watch/lane-parallel.ts +46 -0
- package/src/watch/lane-progress.ts +28 -4
- package/src/watch/lane-report.ts +62 -9
- package/src/watch/lane-sources.ts +1 -1
- package/src/watch/no-finding.ts +47 -0
- package/src/watch/plan-badges-read.ts +19 -7
- package/src/watch/plan-badges.ts +59 -7
- package/src/watch/plan-views.ts +5 -5
- package/src/watch/previews.ts +3 -9
- package/src/watch/pull-requests.ts +12 -2
- package/src/watch/recorded-reads.ts +25 -0
- package/src/watch/source-fields.ts +4 -0
- package/src/watch/source-tickets.ts +99 -0
- package/src/watch/sources.ts +62 -15
- package/src/watch/texts.ts +21 -1
- package/src/watch/watch-defaults.ts +8 -0
- package/src/watch/watch-events.ts +64 -4
- package/src/watch/watcher-lock.ts +1 -1
- package/src/watch/workflow-runs.ts +5 -7
- package/docs/lanes.mmd +0 -9
- package/docs/skills.mmd +0 -10
|
@@ -1,8 +1,12 @@
|
|
|
1
1
|
import { CHECKS, type ChecksState } from '../plans/pull-requests'
|
|
2
|
+
import { APPROVAL_EVENT, type ApprovalEvent } from './approvals'
|
|
2
3
|
import { type CoordinatorLevel, type CoordinatorReading, isContextLevel, levelStep } from './coordinator-fill'
|
|
4
|
+
import { emptyFailureState, type FailureState, failedTestsOf, isFailureState } from './failures'
|
|
3
5
|
import { emptyFeedbackState, FEEDBACK_EVENT, type FeedbackEvent, type FeedbackState, isFeedbackState } from './feedback'
|
|
4
6
|
import { isRecord } from './json-guards'
|
|
5
7
|
import { isLaneLevels, LANE_FILL_EVENT, type LaneFillEvent, type LaneLevels } from './lane-fill'
|
|
8
|
+
import { isLaneModels, LANE_MODEL_EVENT, type LaneModelEvent, type LaneModels } from './lane-model'
|
|
9
|
+
import { isLaneParallels, LANE_PARALLEL_EVENT, type LaneParallelEvent, type LaneParallels } from './lane-parallel'
|
|
6
10
|
import { type LaneSnapshot, type SeenSeqs, seenSeqsOf } from './lane-watch'
|
|
7
11
|
import { emptyPreviewState, isPreviewState, PREVIEW_EVENT, type PreviewEvent, type PreviewState } from './previews'
|
|
8
12
|
import { PULL_REQUEST_STATE, type WatchedPullRequest } from './pull-requests'
|
|
@@ -21,10 +25,13 @@ export const WATCH_EVENT = {
|
|
|
21
25
|
feedback: FEEDBACK_EVENT,
|
|
22
26
|
preview: PREVIEW_EVENT,
|
|
23
27
|
laneFill: LANE_FILL_EVENT,
|
|
28
|
+
laneModel: LANE_MODEL_EVENT,
|
|
29
|
+
laneParallel: LANE_PARALLEL_EVENT,
|
|
30
|
+
approval: APPROVAL_EVENT,
|
|
24
31
|
source: SOURCE_EVENT,
|
|
25
32
|
} as const
|
|
26
33
|
|
|
27
|
-
export type PullRequestObservation = Omit<WatchedPullRequest, 'number' | 'branch'>
|
|
34
|
+
export type PullRequestObservation = Omit<WatchedPullRequest, 'number' | 'branch' | 'failedRuns'>
|
|
28
35
|
|
|
29
36
|
/** The settled verdict of a pull request's checks on one head commit, the unit that fires once. */
|
|
30
37
|
export type CheckVerdict = { headCommit: string; checks: ChecksState }
|
|
@@ -60,10 +67,18 @@ export type WatchState = {
|
|
|
60
67
|
coordinatorLevel: CoordinatorLevel | null
|
|
61
68
|
/** The feedback seen on the lanes' open pull requests; kept apart from `pullRequests`, it is read over REST. */
|
|
62
69
|
feedback: FeedbackState
|
|
70
|
+
/** The failed tests read from the logs of the lanes' red pull requests, once per head commit; see `failures.ts`. */
|
|
71
|
+
failures: FailureState
|
|
63
72
|
/** The previews seen on the lanes' open pull requests: per pull request the head last reported and the source versions. */
|
|
64
73
|
previews: PreviewState
|
|
65
74
|
/** The context level last read for each watched lane's agent; a rise above it fires `lane <name> <level>`. */
|
|
66
75
|
laneLevels: LaneLevels
|
|
76
|
+
/** The differing model last reported for each watched lane's agent; a lane fitting its model column has none. */
|
|
77
|
+
laneModels: LaneModels
|
|
78
|
+
/** The phases last reported as able to run together for each watched lane; a lane without two has none. */
|
|
79
|
+
laneParallels: LaneParallels
|
|
80
|
+
/** The ids of the approval requests on disk when they were last read, each reported once while it is open. */
|
|
81
|
+
approvals: string[]
|
|
67
82
|
/** Per configured source of `watch.sources`: the entries seen (`[id, fingerprint]`) and the start of a failure streak. */
|
|
68
83
|
sources: SourceState
|
|
69
84
|
/** Lane → change time of the report file last shown for it, null when it had none; a lane without an entry is unseen. */
|
|
@@ -75,12 +90,18 @@ export type WatchState = {
|
|
|
75
90
|
/** The kinds of the events a pull request fires. */
|
|
76
91
|
export const PULL_REQUEST_KINDS = [WATCH_EVENT.merged, WATCH_EVENT.checksFailed, WATCH_EVENT.checksPassed] as const
|
|
77
92
|
|
|
78
|
-
/**
|
|
93
|
+
/**
|
|
94
|
+
* A lane's pull request, or an own one without a lane, which names its branch instead. `checks failed` carries the names
|
|
95
|
+
* of the failed checks and, for a lane's pull request, the tests read from the logs of the head commit, each only when
|
|
96
|
+
* there is one; no other kind carries either.
|
|
97
|
+
*/
|
|
79
98
|
export type PullRequestEvent = {
|
|
80
99
|
kind: (typeof PULL_REQUEST_KINDS)[number]
|
|
81
100
|
number: number
|
|
82
101
|
headCommit: string
|
|
83
102
|
mergeCommit: string | null
|
|
103
|
+
failedChecks?: string[]
|
|
104
|
+
failedTests?: string[]
|
|
84
105
|
} & ({ lane: string } | { lane: null; branch: string })
|
|
85
106
|
|
|
86
107
|
/** A run of a lane's merge, or without a lane: of an own pull request's merge (`pullRequest`), else started by hand. */
|
|
@@ -105,6 +126,9 @@ export type WatchEvent =
|
|
|
105
126
|
| FeedbackEvent
|
|
106
127
|
| PreviewEvent
|
|
107
128
|
| LaneFillEvent
|
|
129
|
+
| LaneModelEvent
|
|
130
|
+
| LaneParallelEvent
|
|
131
|
+
| ApprovalEvent
|
|
108
132
|
| SourceEvent
|
|
109
133
|
|
|
110
134
|
export const isPullRequestEvent = (event: WatchEvent): event is PullRequestEvent =>
|
|
@@ -132,8 +156,12 @@ export const emptyWatchState = (): WatchState => ({
|
|
|
132
156
|
laneBranches: {},
|
|
133
157
|
coordinatorLevel: null,
|
|
134
158
|
feedback: emptyFeedbackState(),
|
|
159
|
+
failures: emptyFailureState(),
|
|
135
160
|
previews: emptyPreviewState(),
|
|
136
161
|
laneLevels: {},
|
|
162
|
+
laneModels: {},
|
|
163
|
+
laneParallels: {},
|
|
164
|
+
approvals: [],
|
|
137
165
|
sources: emptySourceState(),
|
|
138
166
|
reportMtimes: {},
|
|
139
167
|
statusLines: null,
|
|
@@ -169,8 +197,13 @@ const isWatchState = (value: Record<string, unknown>): value is WatchState =>
|
|
|
169
197
|
everyValue(value.laneBranches, (entry) => typeof entry === 'string') &&
|
|
170
198
|
(value.coordinatorLevel === null || isContextLevel(value.coordinatorLevel)) &&
|
|
171
199
|
isFeedbackState(value.feedback) &&
|
|
200
|
+
isFailureState(value.failures) &&
|
|
172
201
|
isPreviewState(value.previews) &&
|
|
173
202
|
isLaneLevels(value.laneLevels) &&
|
|
203
|
+
isLaneModels(value.laneModels) &&
|
|
204
|
+
isLaneParallels(value.laneParallels) &&
|
|
205
|
+
Array.isArray(value.approvals) &&
|
|
206
|
+
value.approvals.every((id) => typeof id === 'string') &&
|
|
174
207
|
isSourceState(value.sources) &&
|
|
175
208
|
everyValue(value.reportMtimes, isSeq) &&
|
|
176
209
|
(value.statusLines === null ||
|
|
@@ -189,8 +222,12 @@ export const parseWatchState = (json: string): WatchState => {
|
|
|
189
222
|
laneBranches: {},
|
|
190
223
|
coordinatorLevel: null,
|
|
191
224
|
feedback: emptyFeedbackState(),
|
|
225
|
+
failures: emptyFailureState(),
|
|
192
226
|
previews: emptyPreviewState(),
|
|
193
227
|
laneLevels: {},
|
|
228
|
+
laneModels: {},
|
|
229
|
+
laneParallels: {},
|
|
230
|
+
approvals: [],
|
|
194
231
|
sources: emptySourceState(),
|
|
195
232
|
reportMtimes: {},
|
|
196
233
|
statusLines: null,
|
|
@@ -260,8 +297,12 @@ export const recordWatchState = (previous: WatchState, observation: Observation,
|
|
|
260
297
|
laneBranches: keptLaneBranches(previous, observation, github.pullRequests),
|
|
261
298
|
coordinatorLevel: previous.coordinatorLevel,
|
|
262
299
|
feedback: previous.feedback,
|
|
300
|
+
failures: previous.failures,
|
|
263
301
|
previews: previous.previews,
|
|
264
302
|
laneLevels: previous.laneLevels,
|
|
303
|
+
laneModels: previous.laneModels,
|
|
304
|
+
laneParallels: previous.laneParallels,
|
|
305
|
+
approvals: previous.approvals,
|
|
265
306
|
sources: previous.sources,
|
|
266
307
|
reportMtimes: previous.reportMtimes,
|
|
267
308
|
statusLines: previous.statusLines,
|
|
@@ -317,16 +358,34 @@ const eventKindOf = (known: PullRequestRecord, observed: PullRequestSnapshot): P
|
|
|
317
358
|
const laneOfBranch = (laneBranches: Readonly<Record<string, string>>, branch: string): string | undefined =>
|
|
318
359
|
Object.keys(laneBranches).find((lane) => laneBranches[lane] === branch)
|
|
319
360
|
|
|
361
|
+
/** What a `checks failed` event adds: the failed checks' names, and a lane's failed tests; nothing for another kind. */
|
|
362
|
+
const failureDetails = (
|
|
363
|
+
kind: PullRequestEvent['kind'],
|
|
364
|
+
pullRequest: PullRequestSnapshot,
|
|
365
|
+
isLane: boolean,
|
|
366
|
+
failures: FailureState,
|
|
367
|
+
): Pick<PullRequestEvent, 'failedChecks' | 'failedTests'> => {
|
|
368
|
+
if (kind !== WATCH_EVENT.checksFailed) return {}
|
|
369
|
+
const failedChecks = pullRequest.failedRuns.map(({ name }) => name)
|
|
370
|
+
const failedTests = isLane ? failedTestsOf(failures, pullRequest.number, pullRequest.headCommit) : []
|
|
371
|
+
return {
|
|
372
|
+
...(failedChecks.length > 0 && { failedChecks }),
|
|
373
|
+
...(failedTests.length > 0 && { failedTests }),
|
|
374
|
+
}
|
|
375
|
+
}
|
|
376
|
+
|
|
320
377
|
/**
|
|
321
378
|
* The merges and settled checks of the lanes' pull requests since `previous`, and of the user's own pull requests on
|
|
322
379
|
* a branch without a lane, which name their branch. A pull request number never seen is a baseline, and so is an own
|
|
323
380
|
* one the state does not mark as own yet. Checks fire once per head commit and settled verdict: a new head commit
|
|
324
|
-
* fires when its checks settle, not while they are pending, and pending never clears what was reported.
|
|
381
|
+
* fires when its checks settle, not while they are pending, and pending never clears what was reported. A red verdict
|
|
382
|
+
* names the failed checks and, for a lane's pull request, the tests `failures` holds for its head commit.
|
|
325
383
|
*/
|
|
326
384
|
export const pullRequestEvents = (
|
|
327
385
|
previous: WatchState,
|
|
328
386
|
current: readonly PullRequestSnapshot[],
|
|
329
387
|
laneBranches: Readonly<Record<string, string>>,
|
|
388
|
+
failures: FailureState = emptyFailureState(),
|
|
330
389
|
): PullRequestEvent[] =>
|
|
331
390
|
current.flatMap((pullRequest) => {
|
|
332
391
|
const lane = laneOfBranch(laneBranches, pullRequest.branch)
|
|
@@ -336,7 +395,8 @@ export const pullRequestEvents = (
|
|
|
336
395
|
if (!kind) return []
|
|
337
396
|
const { number, headCommit, mergeCommit, branch } = pullRequest
|
|
338
397
|
const owner = lane === undefined ? { lane: null, branch } : { lane }
|
|
339
|
-
|
|
398
|
+
const details = failureDetails(kind, pullRequest, lane !== undefined, failures)
|
|
399
|
+
return [{ kind, ...owner, number, headCommit, mergeCommit, ...details }]
|
|
340
400
|
})
|
|
341
401
|
|
|
342
402
|
/** The lane each merge commit belongs to, for matching deploy runs to a lane's merge. */
|
|
@@ -95,7 +95,7 @@ const isAlive = (pid: number): boolean => {
|
|
|
95
95
|
}
|
|
96
96
|
}
|
|
97
97
|
|
|
98
|
-
/** Where `ensureWatcherDirectory` puts the watcher's files, without creating anything: for readers such as the
|
|
98
|
+
/** Where `ensureWatcherDirectory` puts the watcher's files, without creating anything: for readers such as the herd. */
|
|
99
99
|
export const watcherDirectoryOf = (root: string): string =>
|
|
100
100
|
join(tmpdir(), `${DIRECTORY_PREFIX}-${process.getuid?.() ?? 'user'}`, repositoryKey(root))
|
|
101
101
|
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import type { JackherdConfig } from '../config'
|
|
2
|
+
import { GITHUB_HOST } from '../plans/github'
|
|
3
|
+
import { runIdOfLink } from '../plans/pull-requests'
|
|
2
4
|
import { isRecord, parseArray } from './json-guards'
|
|
3
5
|
|
|
4
6
|
/** Which workflow's runs are deploys, and which environments count as their target (`watch.deploy`). */
|
|
@@ -37,8 +39,6 @@ export const WORKFLOW_RUN_FIELDS = 'databaseId,event,headSha,status,conclusion,c
|
|
|
37
39
|
|
|
38
40
|
const RUN_LIMIT = '20'
|
|
39
41
|
|
|
40
|
-
const RUN_LOG_PATH = /\/actions\/runs\/(\d+)\//
|
|
41
|
-
|
|
42
42
|
const isGhWorkflowRun = (value: unknown): value is GhWorkflowRun =>
|
|
43
43
|
isRecord(value) &&
|
|
44
44
|
typeof value.databaseId === 'number' &&
|
|
@@ -89,8 +89,6 @@ export const runListArgs = (deploy: DeployConfig | undefined, baseBranch: string
|
|
|
89
89
|
]
|
|
90
90
|
: null
|
|
91
91
|
|
|
92
|
-
/** The run ID a deployment status's `log_url` (`…/actions/runs/<id>/job/<job>`) points at, or null
|
|
93
|
-
export const runIdOfLogUrl = (logUrl: string): number | null =>
|
|
94
|
-
|
|
95
|
-
return match ? Number(match[1]) : null
|
|
96
|
-
}
|
|
92
|
+
/** The run ID a deployment status's `log_url` (`…/actions/runs/<id>/job/<job>`) points at, or null; see `runIdOfLink`. */
|
|
93
|
+
export const runIdOfLogUrl = (logUrl: string): number | null =>
|
|
94
|
+
runIdOfLink(logUrl, { host: GITHUB_HOST, repository: null })
|
package/docs/lanes.mmd
DELETED
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
flowchart LR
|
|
2
|
-
coordinator[Coordinator<br/>/orchestrate] -- prompts --> laneA[Lane a<br/>worktree a]
|
|
3
|
-
coordinator -- open decisions,<br/>one approval per PR --> user([You])
|
|
4
|
-
coordinator -- prompts --> laneB[Lane b<br/>worktree b]
|
|
5
|
-
laneA -- questions as text --> coordinator
|
|
6
|
-
laneB -- questions as text --> coordinator
|
|
7
|
-
watcher[jh watch] -- wakes --> coordinator
|
|
8
|
-
laneA -. state, PR, checks .-> watcher
|
|
9
|
-
laneB -. state, PR, checks .-> watcher
|
package/docs/skills.mmd
DELETED
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
flowchart LR
|
|
2
|
-
grill["/grill<br/>settles decisions"] -- decision rows --> plan["/plan<br/>writes the plan"]
|
|
3
|
-
plan -- phases, Writes,<br/>model per phase --> orchestrate["/orchestrate<br/>lanes in herdr"]
|
|
4
|
-
plan -- one phase --> implement["/implement<br/>builds, ticks"]
|
|
5
|
-
orchestrate -- each lane runs --> implement
|
|
6
|
-
implement --> precommit["/pre-commit<br/>jh check"]
|
|
7
|
-
precommit --> review["/review"]
|
|
8
|
-
precommit --> spec["spec-review"]
|
|
9
|
-
precommit -. routed by path .-> routed["uncle-bob · security-audit · devops"]
|
|
10
|
-
diagnose["/diagnose<br/>bug, flaky failure"] -- red command --> implement
|