@joshuafolkken/kit 1.1471.0 → 1.1514.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/.claude/settings.json +6 -6
- package/.claude/skills/epic-commands/SKILL.md +2 -14
- package/.claude/skills/epic-commands/epic-bundle.md +9 -5
- package/.claude/skills/epic-commands/execution-waves.md +1 -2
- package/.claude/skills/verify-ui/SKILL.md +1 -2
- package/.claude/skills/workflow-commands/SKILL.md +7 -9
- package/.claude/skills/workflow-commands/background-commands.md +3 -7
- package/.claude/skills/workflow-commands/backlogrun-child.md +3 -10
- package/.claude/skills/workflow-commands/backlogrun-lanes.md +6 -15
- package/.claude/skills/workflow-commands/backlogrun-park.md +2 -8
- package/.claude/skills/workflow-commands/backlogrun-progress.md +10 -19
- package/.claude/skills/workflow-commands/backlogrun-recovery.md +8 -8
- package/.claude/skills/workflow-commands/backlogrun-steps.md +2 -10
- package/.claude/skills/workflow-commands/backlogrun.md +31 -50
- package/.claude/skills/workflow-commands/chain-rule.md +7 -6
- package/.claude/skills/workflow-commands/delegation.md +12 -8
- package/.claude/skills/workflow-commands/entry-sequence.md +1 -3
- package/.claude/skills/workflow-commands/followup.md +3 -6
- package/.claude/skills/workflow-commands/fullrun-steps.md +3 -5
- package/.claude/skills/workflow-commands/fullrun.md +4 -6
- package/.claude/skills/workflow-commands/halfrun.md +3 -7
- package/.claude/skills/workflow-commands/into-target.md +1 -2
- package/.claude/skills/workflow-commands/issue-comments.md +3 -3
- package/.claude/skills/workflow-commands/issue-scout.md +3 -2
- package/.claude/skills/workflow-commands/latest-gate.md +2 -6
- package/.claude/skills/workflow-commands/needs-human-review.md +2 -5
- package/.claude/skills/workflow-commands/observation-filing.md +0 -14
- package/.claude/skills/workflow-commands/observation-ledger.md +4 -9
- package/.claude/skills/workflow-commands/pre-gate-cut.md +11 -16
- package/.claude/skills/workflow-commands/prerequisite.md +1 -2
- package/.claude/skills/workflow-commands/progress-watcher.md +2 -7
- package/.claude/skills/workflow-commands/prrun.md +3 -5
- package/.claude/skills/workflow-commands/retrospective.md +4 -4
- package/.claude/skills/workflow-commands/split-assessment.md +1 -3
- package/.claude/skills/workflow-commands/target-repository.md +1 -2
- package/.claude/skills/workflow-commands/working-tree-hold.md +2 -4
- package/.codex/hooks.json +6 -6
- package/.github/actions/setup-node/action.yml +1 -1
- package/.github/workflows/ci.yml +1 -1
- package/.github/workflows/publish.yml +2 -2
- package/CLAUDE.md +1 -1
- package/cspell/index.yaml +7 -0
- package/dist/CLAUDE.md +1 -1
- package/dist/commands/document-section-cli.js +67 -34
- package/dist/hooks/batch-guard.js +6 -6
- package/dist/hooks/chunk-4KKD2UTK.js +66 -0
- package/dist/hooks/{chunk-J47HU5H5.js → chunk-6TS2JD6D.js} +3 -3
- package/dist/hooks/chunk-7DSBJVFH.js +50 -0
- package/dist/hooks/{chunk-YHBZAJSV.js → chunk-A65Y4YOR.js} +3 -3
- package/dist/hooks/{chunk-E7OIKX5Z.js → chunk-APUO6U4J.js} +85 -7
- package/dist/hooks/{chunk-IX6TTTI6.js → chunk-EFXE6C37.js} +8 -22
- package/dist/hooks/chunk-GP4IEC4O.js +20 -0
- package/dist/hooks/{chunk-SHGPANFB.js → chunk-JP45SOCJ.js} +3 -3
- package/dist/hooks/{chunk-K4EOONYM.js → chunk-LAOV7NLM.js} +1 -1
- package/dist/hooks/chunk-M4HGZV7U.js +83 -0
- package/dist/hooks/{chunk-KC5AK2GF.js → chunk-O6GDRNJB.js} +3 -3
- package/dist/hooks/{chunk-YYPI7SJZ.js → chunk-PF2NZL2A.js} +5 -5
- package/dist/hooks/{chunk-H5HVWYXK.js → chunk-PTICX4OL.js} +3 -4
- package/dist/hooks/{chunk-IIGFYXKC.js → chunk-RT27QRJW.js} +581 -1438
- package/dist/hooks/{chunk-43ZHT22P.js → chunk-SYOTDYCI.js} +1127 -1089
- package/dist/hooks/{chunk-AS74OU3D.js → chunk-TNUMY6NL.js} +1507 -1336
- package/dist/hooks/chunk-UPUZF3AN.js +279 -0
- package/dist/hooks/{chunk-EUMACUK2.js → chunk-WK6SMBIC.js} +1948 -806
- package/dist/hooks/codex-hook-adapter.js +17 -14
- package/dist/hooks/duplicate-read-guard.js +7 -7
- package/dist/hooks/format-edited.js +5 -4
- package/dist/hooks/inputs.json +317 -264
- package/dist/hooks/investigation-guard.js +8 -11
- package/dist/hooks/pretool-guard.js +16 -13
- package/dist/hooks/session-lang.js +370 -25
- package/dist/hooks/stop-guard.js +2576 -176
- package/dist/josh.js +2124 -277
- package/lefthook/base.yml +5 -3
- package/package.json +12 -10
- package/prompts/collaboration-workflow/file-edits.md +1 -3
- package/prompts/collaboration-workflow/gh-rest.md +1 -2
- package/prompts/collaboration-workflow/issue-citation.md +2 -4
- package/prompts/collaboration-workflow/issue-template.md +10 -2
- package/prompts/collaboration-workflow/lane-instructions.md +35 -0
- package/prompts/collaboration-workflow/operating-rules.md +2 -6
- package/prompts/collaboration-workflow/output-bounds.md +3 -3
- package/prompts/collaboration-workflow/overview.md +1 -1
- package/prompts/collaboration-workflow/principles.md +14 -8
- package/prompts/collaboration-workflow/report-format.md +9 -0
- package/prompts/collaboration-workflow/residency.md +12 -8
- package/prompts/collaboration-workflow/rule-delivery.md +3 -11
- package/prompts/collaboration-workflow/shell-body.md +6 -6
- package/prompts/collaboration-workflow/turn-batching.md +5 -5
- package/prompts/collaboration-workflow/upstream-interrupt.md +2 -2
- package/prompts/collaboration-workflow/wip-cap.md +6 -6
- package/prompts/collaboration-workflow.md +1 -0
- package/prompts/review.md +4 -5
- package/prompts/testing-guide.md +2 -2
- package/scripts/agent/agent-argv.ts +20 -4
- package/scripts/agent/agent-role-profile.ts +101 -45
- package/scripts/agent/agent-safe-text.ts +60 -0
- package/scripts/agent/claude-agent-argv.ts +14 -0
- package/scripts/agent/codex-agent-argv.ts +2 -0
- package/scripts/agent/lane-instructions.ts +144 -0
- package/scripts/backlog/backlog-budget.ts +4 -4
- package/scripts/backlog/backlog-drive-named.ts +1 -1
- package/scripts/backlog/backlog-drive-restore.ts +9 -1
- package/scripts/backlog/backlog-occupied.ts +56 -0
- package/scripts/backlog/backlog-ready.ts +47 -10
- package/scripts/delegation/duplicate-read-guard.ts +2 -2
- package/scripts/delegation/investigation-guard.ts +15 -65
- package/scripts/delegation/investigation-reads.ts +0 -1
- package/scripts/document/document-byte-budget.ts +6 -5
- package/scripts/document/document-section-cli.ts +17 -5
- package/scripts/document/entry-read-budget.ts +2 -2
- package/scripts/document/read-set-cli.ts +4 -1
- package/scripts/epic/epic-audit-orphans.ts +5 -8
- package/scripts/epic/epic-audit.ts +52 -1
- package/scripts/epic/epic-bundle-evidence.ts +49 -26
- package/scripts/epic/epic-bundle-referenced.ts +14 -3
- package/scripts/epic/epic-bundle.ts +17 -9
- package/scripts/followup/git-followup-workflow.ts +19 -1
- package/scripts/gate/check-inputs.ts +129 -0
- package/scripts/gate/check-reuse.ts +162 -0
- package/scripts/gate/core-budget.ts +93 -44
- package/scripts/gate/core-wait.ts +130 -0
- package/scripts/gate/free-cores.ts +49 -0
- package/scripts/gate/gate-ledger.ts +17 -3
- package/scripts/gate/gate-plan.ts +23 -1
- package/scripts/gate/gate-report.ts +15 -2
- package/scripts/gate/gate-run-steps.ts +150 -0
- package/scripts/gate/held-mark.ts +55 -0
- package/scripts/gate/machine-capacity.ts +70 -11
- package/scripts/gate/pre-commit-type-check.ts +14 -1
- package/scripts/gate/verification-gate.ts +58 -125
- package/scripts/gh/git-gh-issue-rest.ts +1 -0
- package/scripts/gh/git-gh-issue-write.ts +24 -2
- package/scripts/gh/git-pr.ts +13 -1
- package/scripts/git/main-merge-regenerate.ts +78 -0
- package/scripts/git/main-merge.ts +14 -5
- package/scripts/hooks/batch-guard.ts +5 -8
- package/scripts/hooks/pre-commit-lint.ts +91 -0
- package/scripts/hooks/pre-push-unit.ts +1 -1
- package/scripts/hooks/pretool-guard.ts +27 -52
- package/scripts/hooks/reserved-run.ts +1 -0
- package/scripts/hooks/run-hook.sh +10 -12
- package/scripts/hooks/stop-actions.ts +204 -0
- package/scripts/hooks/stop-guard.ts +62 -21
- package/scripts/init/hook-launch.ts +12 -7
- package/scripts/issue/expected-effect-lint.ts +59 -0
- package/scripts/issue/issue-cite-cli.ts +35 -15
- package/scripts/issue/issue-classification.ts +1 -1
- package/scripts/issue/issue-lint-cli.ts +5 -3
- package/scripts/issue/issue-scout-cli.ts +19 -14
- package/scripts/issue/markdown-section.ts +19 -5
- package/scripts/josh/command-usage.ts +110 -0
- package/scripts/josh/josh-command-map.ts +2 -0
- package/scripts/josh/josh-command-types.ts +55 -9
- package/scripts/josh/josh-commands-ai.ts +13 -0
- package/scripts/josh/josh-commands-development.ts +1 -1
- package/scripts/josh/josh-commands-hooks.ts +6 -0
- package/scripts/josh/josh-commands-lane.ts +10 -1
- package/scripts/josh/josh-commands-workflow.ts +5 -0
- package/scripts/josh/josh-logic.ts +6 -15
- package/scripts/josh/josh-usage-automation.ts +121 -0
- package/scripts/josh/josh-usage-backlog.ts +180 -0
- package/scripts/josh/josh-usage-developer.ts +230 -0
- package/scripts/josh/josh-usage-hooks.ts +38 -0
- package/scripts/josh/josh-usage-issue.ts +205 -0
- package/scripts/josh/josh-usage-review.ts +101 -0
- package/scripts/josh/josh-usage-run.ts +252 -0
- package/scripts/josh/josh-usage-session.ts +238 -0
- package/scripts/josh/josh-usage-workflow.ts +212 -0
- package/scripts/josh/josh.ts +14 -5
- package/scripts/josh/package-directory.ts +20 -0
- package/scripts/lane/lane-capacity.ts +8 -2
- package/scripts/lane/lane-check-stats.ts +56 -0
- package/scripts/lane/lane-child-invocation.ts +35 -4
- package/scripts/lane/lane-dispatch.ts +3 -3
- package/scripts/lane/lane-guard-policy.ts +2 -2
- package/scripts/lane/lane-handoff.ts +8 -1
- package/scripts/lane/lane-install.ts +12 -4
- package/scripts/lane/lane-ledger.ts +43 -1
- package/scripts/lane/lane-limit-cli.ts +8 -9
- package/scripts/lane/lane-measure-cli.ts +2 -0
- package/scripts/lane/lane-preserve.ts +29 -1
- package/scripts/lane/lane-registry.ts +9 -7
- package/scripts/lane/lane-restart.ts +5 -26
- package/scripts/lane/lane-session-action.ts +146 -0
- package/scripts/lane/lane-session-broker.ts +57 -138
- package/scripts/lane/lane-withdraw-cli.ts +71 -0
- package/scripts/lane/lane-withdraw.ts +182 -0
- package/scripts/lint/format.ts +4 -4
- package/scripts/lint/lint-parallel.ts +10 -3
- package/scripts/lint/lint-related-scope.ts +4 -1
- package/scripts/notify/telegram-test.ts +10 -5
- package/scripts/report/report-format-reference.ts +2 -0
- package/scripts/review/acceptance-map-check.ts +61 -0
- package/scripts/review/acceptance-map.ts +205 -0
- package/scripts/review/review-brief-cli.ts +1 -1
- package/scripts/rules/agent-model.ts +59 -0
- package/scripts/rules/delivered-rules.ts +11 -2
- package/scripts/rules/filing-cap.ts +1 -0
- package/scripts/rules/firing-point.ts +6 -5
- package/scripts/rules/guard-remedy.ts +117 -0
- package/scripts/rules/issue-comments.ts +67 -6
- package/scripts/rules/last-prompt.ts +50 -5
- package/scripts/rules/oracle-list-cli.ts +7 -0
- package/scripts/rules/piped-verification.ts +3 -1
- package/scripts/rules/rule-list.ts +4 -1
- package/scripts/rules/rule-registry-rows.ts +10 -0
- package/scripts/rules/rule-registry.ts +7 -4
- package/scripts/rules/rule-rewrite.ts +114 -0
- package/scripts/rules/rule-value.ts +7 -1
- package/scripts/rules/shell-segments.ts +15 -0
- package/scripts/rules/stop-decision.ts +77 -0
- package/scripts/rules/stop-rules.ts +147 -47
- package/scripts/rules/tail-commands.ts +15 -1
- package/scripts/run/board/run-board-cli.ts +2 -0
- package/scripts/run/board/run-board-closed.ts +8 -2
- package/scripts/run/board/run-board-github.ts +9 -1
- package/scripts/run/board/run-board-header.ts +4 -1
- package/scripts/run/board/run-board-labels.ts +2 -0
- package/scripts/run/board/run-board-layout.ts +1 -1
- package/scripts/run/board/run-board-read.ts +16 -0
- package/scripts/run/board/run-board-reason.ts +10 -1
- package/scripts/run/board/run-board-render-legend.ts +1 -0
- package/scripts/run/board/run-board-render-slot.ts +1 -1
- package/scripts/run/board/run-board-render-waits.ts +41 -0
- package/scripts/run/board/run-board-render.ts +6 -1
- package/scripts/run/board/run-board-row-yield.ts +1 -0
- package/scripts/run/board/run-board-state.ts +5 -0
- package/scripts/run/board/run-board-status.ts +72 -21
- package/scripts/run/board/run-board-tick.ts +5 -1
- package/scripts/run/cut/run-cut-cli.ts +3 -2
- package/scripts/run/cut/run-cut-report.ts +16 -0
- package/scripts/run/detached-launch.ts +23 -4
- package/scripts/run/entry/run-entry-cli.ts +8 -1
- package/scripts/run/event/run-event-render.ts +1 -0
- package/scripts/run/event/run-event-scope.ts +19 -1
- package/scripts/run/event/run-event-stream-emit.ts +13 -6
- package/scripts/run/event/run-event-stream.ts +4 -0
- package/scripts/run/hold/run-hold-session.ts +46 -0
- package/scripts/run/hold/run-hold.ts +7 -1
- package/scripts/run/launch-priority.ts +32 -0
- package/scripts/run/merge/run-merge-cli.ts +16 -65
- package/scripts/run/merge/run-merge-signals.ts +99 -0
- package/scripts/run/merge/run-merge-steps.ts +11 -1
- package/scripts/run/merge/run-merge.ts +21 -9
- package/scripts/run/run-liveness.ts +1 -1
- package/scripts/run/run-poll-hook.ts +157 -0
- package/scripts/run/run-step-cli.ts +22 -15
- package/scripts/run/run-step-section.ts +85 -0
- package/scripts/run/ship/run-ship-cli.ts +5 -12
- package/scripts/run/ship/run-ship-detach.ts +9 -0
- package/scripts/run/ship/run-ship-next.ts +10 -2
- package/scripts/run/ship/run-ship-overlap.ts +195 -0
- package/scripts/run/ship/run-ship-pre-detach.ts +33 -15
- package/scripts/run/ship/run-ship-preflight.ts +28 -2
- package/scripts/run/ship/run-ship-return.ts +31 -7
- package/scripts/run/ship/run-ship-review-steps.ts +12 -10
- package/scripts/run/ship/run-ship-steps.ts +1 -1
- package/scripts/run/ship/run-ship-stop-context.ts +206 -0
- package/scripts/run/ship/run-ship-sync.ts +14 -6
- package/scripts/test/test-e2e-guard.ts +30 -5
- package/scripts/test/test-unit-guard.ts +16 -1
- package/scripts/test/unit-worker-share.ts +26 -4
- package/scripts/time-runtime/time-shell.ts +29 -4
- package/scripts/time-runtime/time-spans.ts +1 -0
- package/scripts/time-runtime/time-tool-call.ts +7 -0
- package/templates/gitignore +6 -2
- package/dist/hooks/chunk-K4LMBQC2.js +0 -68
|
@@ -101,16 +101,26 @@ async function local_slug_for(targets: ReadonlyArray<CiteTarget>): Promise<strin
|
|
|
101
101
|
return has_bare_target ? await git_gh_command.repo_get_name_with_owner() : undefined
|
|
102
102
|
}
|
|
103
103
|
|
|
104
|
+
// The citation lines and the failure lines of one invocation, apart.
|
|
105
|
+
interface CiteReport {
|
|
106
|
+
lines: ReadonlyArray<string>
|
|
107
|
+
failures: ReadonlyArray<string>
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
function split_results(results: ReadonlyArray<LineResult>): CiteReport {
|
|
111
|
+
return {
|
|
112
|
+
lines: results.filter((result) => result.kind === 'ok').map((result) => result.line),
|
|
113
|
+
failures: results.filter((result) => result.kind === 'fail').map((result) => result.line),
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
|
|
104
117
|
// Citations to stdout so the block stays paste-ready; failures to stderr so each unanswered number is
|
|
105
118
|
// named without landing in what gets pasted. A failure sets a non-zero exit.
|
|
106
|
-
function report(
|
|
107
|
-
|
|
108
|
-
const
|
|
109
|
-
|
|
110
|
-
if (lines.length > 0) console.info(lines.join(LINE_SEPARATOR))
|
|
111
|
-
for (const failure of failures) console.error(failure)
|
|
119
|
+
function report(cited: CiteReport): number {
|
|
120
|
+
if (cited.lines.length > 0) console.info(cited.lines.join(LINE_SEPARATOR))
|
|
121
|
+
for (const failure of cited.failures) console.error(failure)
|
|
112
122
|
|
|
113
|
-
return failures.length === 0 ? SUCCESS_EXIT_CODE : FAILURE_EXIT_CODE
|
|
123
|
+
return cited.failures.length === 0 ? SUCCESS_EXIT_CODE : FAILURE_EXIT_CODE
|
|
114
124
|
}
|
|
115
125
|
|
|
116
126
|
// The targets the command line names, or `undefined` for a line nobody can read — an unknown flag and
|
|
@@ -122,14 +132,11 @@ function read_targets(args: ReadonlyArray<string>): ReadonlyArray<CiteTarget> |
|
|
|
122
132
|
return parse_targets(parsed.positionals, parsed.values.repo)
|
|
123
133
|
}
|
|
124
134
|
|
|
125
|
-
|
|
135
|
+
// The lines `issue:cite` prints for `args`, without printing them — the `Stop` hook shows them itself
|
|
136
|
+
// (`stop-actions.ts`). `undefined` for a line nobody can read.
|
|
137
|
+
async function cite(args: ReadonlyArray<string>): Promise<CiteReport | undefined> {
|
|
126
138
|
const targets = read_targets(args)
|
|
127
|
-
|
|
128
|
-
if (targets === undefined) {
|
|
129
|
-
console.error(USAGE)
|
|
130
|
-
|
|
131
|
-
return FAILURE_EXIT_CODE
|
|
132
|
-
}
|
|
139
|
+
if (targets === undefined) return undefined
|
|
133
140
|
|
|
134
141
|
const local_slug = await local_slug_for(targets)
|
|
135
142
|
const results = await bounded_pool.bounded_map(
|
|
@@ -138,7 +145,19 @@ async function run(args: ReadonlyArray<string>): Promise<number> {
|
|
|
138
145
|
async (target) => await cite_target(target, local_slug),
|
|
139
146
|
)
|
|
140
147
|
|
|
141
|
-
return
|
|
148
|
+
return split_results(results)
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
async function run(args: ReadonlyArray<string>): Promise<number> {
|
|
152
|
+
const cited = await cite(args)
|
|
153
|
+
|
|
154
|
+
if (cited === undefined) {
|
|
155
|
+
console.error(USAGE)
|
|
156
|
+
|
|
157
|
+
return FAILURE_EXIT_CODE
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
return report(cited)
|
|
142
161
|
}
|
|
143
162
|
|
|
144
163
|
async function main(args: ReadonlyArray<string>): Promise<void> {
|
|
@@ -147,6 +166,7 @@ async function main(args: ReadonlyArray<string>): Promise<void> {
|
|
|
147
166
|
|
|
148
167
|
const issue_cite_cli = {
|
|
149
168
|
USAGE,
|
|
169
|
+
cite,
|
|
150
170
|
parse_targets,
|
|
151
171
|
run,
|
|
152
172
|
}
|
|
@@ -2,7 +2,7 @@ import { issue_bug_label } from './issue-bug-label'
|
|
|
2
2
|
import { BREAKING_CHANGE_LABEL, BUG_LABEL, ENHANCEMENT_LABEL, has_label_name } from './issue-labels'
|
|
3
3
|
import { markdown_section } from './markdown-section'
|
|
4
4
|
|
|
5
|
-
const FEATURE_DECLARATIONS = ['- 目的: 機能追加', '- 目的: 機能改善']
|
|
5
|
+
const FEATURE_DECLARATIONS = ['- 目的: 機能追加', '- 目的: 機能改善', '- 目的: 時間短縮']
|
|
6
6
|
const BREAKING_DECLARATION = '- 互換性: 破壊的変更'
|
|
7
7
|
const NON_BUG_DECLARATION = '- 種別: 非不具合'
|
|
8
8
|
const CLASSIFICATION_LABELS = [BUG_LABEL, ENHANCEMENT_LABEL, BREAKING_CHANGE_LABEL]
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
import { readFile } from 'node:fs/promises'
|
|
3
3
|
import { fileURLToPath } from 'node:url'
|
|
4
4
|
import { behavior_change_lint } from './behavior-change-lint'
|
|
5
|
+
import { expected_effect_lint } from './expected-effect-lint'
|
|
5
6
|
import { issue_classification } from './issue-classification'
|
|
6
7
|
import { issue_lint } from './issue-lint'
|
|
7
8
|
|
|
@@ -9,7 +10,7 @@ import { issue_lint } from './issue-lint'
|
|
|
9
10
|
// one per line, exiting non-zero. It reads a path rather than stdin so it can
|
|
10
11
|
// lint a body written to a file before the `gh api … issues` call that files it. A body that declares
|
|
11
12
|
// itself a behavior-change Issue is additionally held to the firing-point, baseline and reproduction
|
|
12
|
-
// rules.
|
|
13
|
+
// rules, and one that declares a run-time-shortening aim to the expected-effect estimate.
|
|
13
14
|
|
|
14
15
|
const SUCCESS_EXIT_CODE = 0
|
|
15
16
|
const FAILURE_EXIT_CODE = 1
|
|
@@ -17,14 +18,15 @@ const OK_MESSAGE = 'ok'
|
|
|
17
18
|
const NO_LABELS = 'none'
|
|
18
19
|
const USAGE = 'Usage: josh issue:lint <path-to-issue-body>'
|
|
19
20
|
|
|
20
|
-
// Every problem a body has: the four base template headings it lacks, then the behavior-change
|
|
21
|
-
// problems (empty for an Issue that does not declare itself one).
|
|
21
|
+
// Every problem a body has: the four base template headings it lacks, then the behavior-change and
|
|
22
|
+
// expected-effect problems (each empty for an Issue that does not declare itself one).
|
|
22
23
|
function problems(body: string): ReadonlyArray<string> {
|
|
23
24
|
const missing = issue_lint.missing_headings(body).map((heading) => `missing heading: ${heading}`)
|
|
24
25
|
|
|
25
26
|
return [
|
|
26
27
|
...missing,
|
|
27
28
|
...behavior_change_lint.problems(body),
|
|
29
|
+
...expected_effect_lint.problems(body),
|
|
28
30
|
...issue_classification.problems(body),
|
|
29
31
|
]
|
|
30
32
|
}
|
|
@@ -103,7 +103,7 @@ function draft_of(args: ScoutArguments, repo: string): BacklogIssue {
|
|
|
103
103
|
}
|
|
104
104
|
|
|
105
105
|
// The epic beside a candidate is the placement answer for a draft that cites nothing: the epic half
|
|
106
|
-
// below decides from
|
|
106
|
+
// below decides from signal references, and a title-only draft has none to give it.
|
|
107
107
|
function format_duplicate(candidate: DuplicateCandidate): string {
|
|
108
108
|
const score = candidate.is_referenced === true ? 'ref' : candidate.score.toFixed(SCORE_DIGITS)
|
|
109
109
|
const epic = candidate.epic === undefined ? '' : ` (epic ${session_cite.issue(candidate.epic)})`
|
|
@@ -162,12 +162,13 @@ function format_epic(decision: BundleDecision): Array<string> {
|
|
|
162
162
|
return lines
|
|
163
163
|
}
|
|
164
164
|
|
|
165
|
-
// A draft cites nothing, so the epic half has nothing to decide from: its two
|
|
166
|
-
//
|
|
167
|
-
//
|
|
165
|
+
// A draft cites nothing where a citation counts, so the epic half has nothing to decide from: its two
|
|
166
|
+
// signals are references in the acceptance criteria or the `parent: #N` line and recorded
|
|
167
|
+
// dependencies, and a title or a background mention carries neither. Saying "file it standalone"
|
|
168
|
+
// there reports a scan that found nothing when none was possible — the confident wrong answer the gap
|
|
168
169
|
// warnings exist to prevent everywhere else in this command.
|
|
169
170
|
const NO_REFERENCE_LINE =
|
|
170
|
-
'Epic: not asked — no issue number in the summary. Pass --body "
|
|
171
|
+
'Epic: not asked — no issue number in the summary\'s acceptance criteria or parent line. Pass --body "parent: #<N>", or take the epic printed beside a duplicate above.'
|
|
171
172
|
|
|
172
173
|
// Every placing verdict above asserts that no epic already tracks the draft's relatives, and a cut
|
|
173
174
|
// epic listing cannot support that: `epic:bundle` withholds them for it,
|
|
@@ -195,18 +196,22 @@ function format_epic_decision(
|
|
|
195
196
|
return format_epic(decision).join('\n')
|
|
196
197
|
}
|
|
197
198
|
|
|
198
|
-
//
|
|
199
|
-
//
|
|
200
|
-
|
|
201
|
-
|
|
199
|
+
// The issue numbers the summary names where `decide_bundle` counts a reference — its acceptance
|
|
200
|
+
// criteria and its `parent: #N` line — read through the same parser the decision itself uses: a
|
|
201
|
+
// second reading of "does this body cite anything" could disagree with the one that matters, and an
|
|
202
|
+
// issue cited only as the background of the filing is not one the draft belongs with.
|
|
203
|
+
function signal_numbers(draft: BacklogIssue): Array<number> {
|
|
204
|
+
return epic_audit_logic
|
|
205
|
+
.signal_references(draft.body, draft.repo)
|
|
206
|
+
.map((reference) => reference.number)
|
|
202
207
|
}
|
|
203
208
|
|
|
204
209
|
// The open epics the summary names outright. `decide_bundle` excludes an epic from the candidate pool
|
|
205
|
-
// — a container is not a sibling — so a draft
|
|
206
|
-
// workflow documents themselves suggest, otherwise reaches `none` and is told to file
|
|
207
|
-
// the epic it named never mentioned.
|
|
210
|
+
// — a container is not a sibling — so a draft whose `parent: #1153` line names the epic, which is the
|
|
211
|
+
// phrasing the workflow documents themselves suggest, otherwise reaches `none` and is told to file
|
|
212
|
+
// standalone with the epic it named never mentioned.
|
|
208
213
|
function named_epics(draft: BacklogIssue, issues: ReadonlyArray<BacklogIssue>): Array<number> {
|
|
209
|
-
const named = new Set(
|
|
214
|
+
const named = new Set(signal_numbers(draft))
|
|
210
215
|
|
|
211
216
|
return issues
|
|
212
217
|
.filter((issue) => issue.is_epic === true && named.has(issue.number))
|
|
@@ -241,7 +246,7 @@ function format_epic_answer(
|
|
|
241
246
|
|
|
242
247
|
if (named.length > 0) return format_named_epics(named, decision).join('\n')
|
|
243
248
|
|
|
244
|
-
return format_epic_decision(decision,
|
|
249
|
+
return format_epic_decision(decision, signal_numbers(draft).length > 0, is_membership_established)
|
|
245
250
|
}
|
|
246
251
|
|
|
247
252
|
// The closed rows reach the duplicate half only. `decide_bundle` places a draft among issues that
|
|
@@ -3,6 +3,9 @@
|
|
|
3
3
|
// way, so the slicing lives in one place rather than being written twice.
|
|
4
4
|
|
|
5
5
|
const HEADING_PREFIX = '## '
|
|
6
|
+
// A body saved from GitHub's web editor ends its lines with CRLF; a kept `\r` would end every line's
|
|
7
|
+
// text with it and defeat each `$`-anchored match downstream.
|
|
8
|
+
const LINE_BREAK_PATTERN = /\r?\n/u
|
|
6
9
|
|
|
7
10
|
function is_heading(line: string): boolean {
|
|
8
11
|
return line.trimStart().startsWith(HEADING_PREFIX)
|
|
@@ -29,21 +32,31 @@ function next_fence(line: string, fence: string): string | undefined {
|
|
|
29
32
|
return undefined
|
|
30
33
|
}
|
|
31
34
|
|
|
32
|
-
function
|
|
35
|
+
function lines_of(body: string): ReadonlyArray<string> {
|
|
36
|
+
return body.split(LINE_BREAK_PATTERN)
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
// The body's lines with every fenced line, fences included, blanked. Indentation is kept, so a list
|
|
40
|
+
// item's indented continuation survives.
|
|
41
|
+
function fence_free_lines(body: string): ReadonlyArray<string> {
|
|
33
42
|
let fence = ''
|
|
34
43
|
const visible: Array<string> = []
|
|
35
44
|
|
|
36
|
-
for (const line of body
|
|
45
|
+
for (const line of lines_of(body)) {
|
|
37
46
|
const next = next_fence(line, fence)
|
|
38
|
-
const visible_line = line.replace(/^(?: {4}|\t).*/u, '')
|
|
39
47
|
|
|
40
|
-
visible.push(next === undefined && fence === '' ?
|
|
48
|
+
visible.push(next === undefined && fence === '' ? line : '')
|
|
41
49
|
fence = next ?? fence
|
|
42
50
|
}
|
|
43
51
|
|
|
44
52
|
return visible
|
|
45
53
|
}
|
|
46
54
|
|
|
55
|
+
// As `fence_free_lines`, with an indented code line (4 spaces or a tab) blanked too.
|
|
56
|
+
function unfenced_lines(body: string): ReadonlyArray<string> {
|
|
57
|
+
return fence_free_lines(body).map((line) => line.replace(/^(?: {4}|\t).*/u, ''))
|
|
58
|
+
}
|
|
59
|
+
|
|
47
60
|
function has_unfenced_line(body: string, text: string): boolean {
|
|
48
61
|
return unfenced_lines(body).some((line) => line.trim() === text)
|
|
49
62
|
}
|
|
@@ -59,7 +72,7 @@ function section_lines_matching(
|
|
|
59
72
|
body: string,
|
|
60
73
|
is_target: (line: string) => boolean,
|
|
61
74
|
): ReadonlyArray<string> {
|
|
62
|
-
const lines = body
|
|
75
|
+
const lines = lines_of(body)
|
|
63
76
|
const visible = unfenced_lines(body)
|
|
64
77
|
const start = visible.findIndex((line) => is_target(line))
|
|
65
78
|
|
|
@@ -80,6 +93,7 @@ function section_lines(body: string, heading: string): ReadonlyArray<string> {
|
|
|
80
93
|
const markdown_section = {
|
|
81
94
|
section_lines,
|
|
82
95
|
section_lines_matching,
|
|
96
|
+
fence_free_lines,
|
|
83
97
|
unfenced_lines,
|
|
84
98
|
has_line,
|
|
85
99
|
has_unfenced_line,
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
import { canonical_command, COMMAND_MAP } from './josh-command-map'
|
|
2
|
+
import type { CommandUsage } from './josh-command-types'
|
|
3
|
+
import { AUTOMATION_USAGE } from './josh-usage-automation'
|
|
4
|
+
import { BACKLOG_USAGE } from './josh-usage-backlog'
|
|
5
|
+
import { DEVELOPER_USAGE } from './josh-usage-developer'
|
|
6
|
+
import { HOOK_USAGE } from './josh-usage-hooks'
|
|
7
|
+
import { ISSUE_USAGE } from './josh-usage-issue'
|
|
8
|
+
import { REVIEW_USAGE } from './josh-usage-review'
|
|
9
|
+
import { RUN_USAGE } from './josh-usage-run'
|
|
10
|
+
import { SESSION_USAGE } from './josh-usage-session'
|
|
11
|
+
import { WORKFLOW_USAGE } from './josh-usage-workflow'
|
|
12
|
+
|
|
13
|
+
// The single renderer of a command's usage. `josh help <command>` prints it and
|
|
14
|
+
// `scripts/document/generate-command-usage.ts` writes it between a reference page's usage markers,
|
|
15
|
+
// so the terminal and the page are one text (#3932).
|
|
16
|
+
|
|
17
|
+
type UsageTable = Readonly<Record<string, CommandUsage>>
|
|
18
|
+
|
|
19
|
+
// Which reference page renders each usage table — the one place a table is tied to its page, so the
|
|
20
|
+
// generator's coverage check and `josh help` read the same set (#3981).
|
|
21
|
+
/* eslint-disable @typescript-eslint/naming-convention */
|
|
22
|
+
const USAGE_PAGE_TABLES: Readonly<Record<string, ReadonlyArray<UsageTable>>> = {
|
|
23
|
+
'docs/josh-commands.md': [DEVELOPER_USAGE],
|
|
24
|
+
'docs/josh-commands-run.md': [RUN_USAGE, SESSION_USAGE],
|
|
25
|
+
'docs/josh-commands-backlog.md': [ISSUE_USAGE, BACKLOG_USAGE, REVIEW_USAGE],
|
|
26
|
+
'docs/josh-commands-automation.md': [AUTOMATION_USAGE, WORKFLOW_USAGE, HOOK_USAGE],
|
|
27
|
+
}
|
|
28
|
+
/* eslint-enable @typescript-eslint/naming-convention */
|
|
29
|
+
const COMMAND_USAGE: UsageTable = Object.fromEntries(
|
|
30
|
+
Object.values(USAGE_PAGE_TABLES)
|
|
31
|
+
.flat()
|
|
32
|
+
.flatMap((table) => Object.entries(table)),
|
|
33
|
+
)
|
|
34
|
+
const NOTE_GAP = 3
|
|
35
|
+
|
|
36
|
+
interface ExampleLine {
|
|
37
|
+
command: string
|
|
38
|
+
note: string | undefined
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
function usage_for(name: string): CommandUsage | undefined {
|
|
42
|
+
return Object.hasOwn(COMMAND_USAGE, name) ? COMMAND_USAGE[name] : undefined
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
function example_line(name: string, example: CommandUsage['examples'][number]): ExampleLine {
|
|
46
|
+
const command = example.arguments ? `pnpm josh ${name} ${example.arguments}` : `pnpm josh ${name}`
|
|
47
|
+
|
|
48
|
+
return { command, note: example.note }
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// Every comment starts in one column, so a block reads as a table of what each spelling does.
|
|
52
|
+
function format_examples(name: string, usage: CommandUsage): string {
|
|
53
|
+
const lines = usage.examples.map((example) => example_line(name, example))
|
|
54
|
+
const width = Math.max(...lines.map((line) => line.command.length)) + NOTE_GAP
|
|
55
|
+
const rendered = lines.map((line) =>
|
|
56
|
+
line.note === undefined ? line.command : `${line.command.padEnd(width)}# ${line.note}`,
|
|
57
|
+
)
|
|
58
|
+
|
|
59
|
+
return ['```bash', ...rendered, '```'].join('\n')
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
function code_span(text: string): string {
|
|
63
|
+
return `\`${text}\``
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
function format_flags(flags: NonNullable<CommandUsage['flags']>): string {
|
|
67
|
+
const items = flags.map(
|
|
68
|
+
(flag) =>
|
|
69
|
+
`- ${flag.names.map((spelling) => code_span(spelling)).join(' / ')} — ${flag.description}`,
|
|
70
|
+
)
|
|
71
|
+
|
|
72
|
+
return ['**Options:**', '', ...items].join('\n')
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
function format_usage(name: string): string | undefined {
|
|
76
|
+
const usage = usage_for(name)
|
|
77
|
+
if (usage === undefined) return undefined
|
|
78
|
+
const flags = usage.flags === undefined ? [] : [format_flags(usage.flags)]
|
|
79
|
+
|
|
80
|
+
return [format_examples(name, usage), ...flags].join('\n\n')
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// `josh help <command>`: the synopsis line, the description, then the usage block when the command
|
|
84
|
+
// has one. An alias resolves to its command; a name that is neither answers `undefined`.
|
|
85
|
+
function format_command_help(input: string): string | undefined {
|
|
86
|
+
const name = canonical_command(input)
|
|
87
|
+
const entry = Object.hasOwn(COMMAND_MAP, name) ? COMMAND_MAP[name] : undefined
|
|
88
|
+
if (entry === undefined) return undefined
|
|
89
|
+
const [synopsis] = entry.reference
|
|
90
|
+
const head = synopsis ? `josh ${name} ${synopsis}` : `josh ${name}`
|
|
91
|
+
const usage = format_usage(name)
|
|
92
|
+
|
|
93
|
+
return [head, '', entry.description, ...(usage === undefined ? [] : ['', usage])].join('\n')
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
// The commands whose usage blocks a reference page renders — the keys of the tables tied to it.
|
|
97
|
+
function page_commands(page: string): Array<string> {
|
|
98
|
+
const tables = Object.hasOwn(USAGE_PAGE_TABLES, page) ? USAGE_PAGE_TABLES[page] : undefined
|
|
99
|
+
|
|
100
|
+
return (tables ?? []).flatMap((table) => Object.keys(table))
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
const command_usage = {
|
|
104
|
+
USAGE_PAGES: Object.keys(USAGE_PAGE_TABLES),
|
|
105
|
+
format_command_help,
|
|
106
|
+
format_usage,
|
|
107
|
+
page_commands,
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
export { command_usage }
|
|
@@ -77,6 +77,7 @@ const ALIASES: Record<string, string> = {
|
|
|
77
77
|
tm: 'time',
|
|
78
78
|
tmd: 'time:density',
|
|
79
79
|
rtr: 'retrospective',
|
|
80
|
+
ca: 'cost:audit',
|
|
80
81
|
rvf: 'review:findings',
|
|
81
82
|
ruv: 'rule:value',
|
|
82
83
|
ev: 'eval',
|
|
@@ -86,6 +87,7 @@ const ALIASES: Record<string, string> = {
|
|
|
86
87
|
lst: 'lane:stats',
|
|
87
88
|
lli: 'lane:limit',
|
|
88
89
|
lrs: 'lane:restart',
|
|
90
|
+
lwd: 'lane:withdraw',
|
|
89
91
|
blr: 'backlogrun',
|
|
90
92
|
}
|
|
91
93
|
|
|
@@ -43,6 +43,25 @@ type CommandReference = readonly [
|
|
|
43
43
|
side_effects: ReadonlyArray<CommandSideEffect>,
|
|
44
44
|
]
|
|
45
45
|
|
|
46
|
+
// One `pnpm josh <command> <arguments>` line of a usage block, with the comment printed after it.
|
|
47
|
+
interface CommandExample {
|
|
48
|
+
arguments: string
|
|
49
|
+
note?: string
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// Spellings of one option — `-y` and `--yes` — rendered side by side.
|
|
53
|
+
interface CommandFlag {
|
|
54
|
+
names: ReadonlyArray<string>
|
|
55
|
+
description: string
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
// What `josh help <command>` prints and what the reference pages render between their usage
|
|
59
|
+
// markers — one source for both, so the page and the terminal cannot disagree (#3932).
|
|
60
|
+
interface CommandUsage {
|
|
61
|
+
examples: ReadonlyArray<CommandExample>
|
|
62
|
+
flags?: ReadonlyArray<CommandFlag>
|
|
63
|
+
}
|
|
64
|
+
|
|
46
65
|
interface CommandEntry {
|
|
47
66
|
script?: string
|
|
48
67
|
shell?: ReadonlyArray<string>
|
|
@@ -109,6 +128,13 @@ const TS_BUILD_INFO_FILE = '.tsbuildinfo'
|
|
|
109
128
|
const CSPELL_CACHE_FILE = '.cspellcache'
|
|
110
129
|
const ESLINT_EDIT_CACHE_FILE = '.eslintcache.edit'
|
|
111
130
|
const ESLINT_RELATED_CACHE_FILE = '.eslintcache.related'
|
|
131
|
+
const PRETTIER_CACHE_FILE = '.prettiercache'
|
|
132
|
+
const PRETTIER_RELATED_CACHE_FILE = '.prettiercache.related'
|
|
133
|
+
// The pre-commit hook's own, because a staged-files run on the gate's file degrades it: cspell prunes
|
|
134
|
+
// every entry the run did not visit (measured 892 KB down to 18 KB), and `eslint --quiet` stores a
|
|
135
|
+
// report without its warnings under the same config hash the gate reads.
|
|
136
|
+
const CSPELL_COMMIT_CACHE_FILE = '.cspellcache.commit'
|
|
137
|
+
const ESLINT_COMMIT_CACHE_FILE = '.eslintcache.commit'
|
|
112
138
|
|
|
113
139
|
type GateCachePortability = 'raw' | 'rooted-json'
|
|
114
140
|
|
|
@@ -139,6 +165,10 @@ const ESLINT_RELATED_CACHE_SPEC: GateCacheSpec = {
|
|
|
139
165
|
cache_file: ESLINT_RELATED_CACHE_FILE,
|
|
140
166
|
portability: ROOTED_JSON_PORTABILITY,
|
|
141
167
|
}
|
|
168
|
+
// **Prettier's caches are in neither list: they do not survive a move to another checkout.**
|
|
169
|
+
// Prettier 3 hashes each file's resolved options, *its absolute `filepath` included*, into the entry,
|
|
170
|
+
// so rebasing the keys as ESLint's are still leaves every entry a miss — two checkouts of one tree
|
|
171
|
+
// were measured sharing none of their 3,526 option hashes. Each checkout keeps a warm cache of its own.
|
|
142
172
|
const GATE_CACHE_SPECS: ReadonlyArray<GateCacheSpec> = [
|
|
143
173
|
ESLINT_CACHE_SPEC,
|
|
144
174
|
TS_CACHE_SPEC,
|
|
@@ -175,14 +205,20 @@ const GATE_CACHE_FILES: ReadonlyArray<string> = GATE_CACHE_SPECS.map((spec) => s
|
|
|
175
205
|
//
|
|
176
206
|
// **The lint's target scope is untouched.** This is where a cache is written, not what is read:
|
|
177
207
|
// `josh lint:related` narrows in front of the gate and `josh gate` still runs `josh lint` over the
|
|
178
|
-
// whole tree before any commit.
|
|
208
|
+
// whole tree before any commit. The scoped lint's prettier cache is its own for the same reason:
|
|
209
|
+
// prettier rewrites its cache file whole as well.
|
|
179
210
|
// What the ignore rules are asserted against: every cache file this package writes, wherever it is
|
|
180
|
-
// written from. The gate's
|
|
181
|
-
// ignored is committed, or spell-checked, which is a red gate with nothing
|
|
211
|
+
// written from. The gate's, the edit hook's, the scoped lint's and the pre-commit hook's — a cache
|
|
212
|
+
// file that is not ignored is committed, or spell-checked, which is a red gate with nothing
|
|
213
|
+
// misspelled in the tree.
|
|
182
214
|
const IGNORED_CACHE_FILES: ReadonlyArray<string> = [
|
|
183
215
|
...GATE_CACHE_FILES,
|
|
184
216
|
ESLINT_EDIT_CACHE_FILE,
|
|
185
217
|
ESLINT_RELATED_CACHE_FILE,
|
|
218
|
+
PRETTIER_CACHE_FILE,
|
|
219
|
+
PRETTIER_RELATED_CACHE_FILE,
|
|
220
|
+
CSPELL_COMMIT_CACHE_FILE,
|
|
221
|
+
ESLINT_COMMIT_CACHE_FILE,
|
|
186
222
|
]
|
|
187
223
|
|
|
188
224
|
// `--cache --cache-strategy content` is one convention rather than two coincidences: cspell adopted
|
|
@@ -190,11 +226,11 @@ const IGNORED_CACHE_FILES: ReadonlyArray<string> = [
|
|
|
190
226
|
const CONTENT_CACHE_FLAGS = ['--cache', '--cache-strategy', 'content'] as const
|
|
191
227
|
const CACHE_LOCATION_FLAG = '--cache-location'
|
|
192
228
|
|
|
193
|
-
//
|
|
194
|
-
// the edit hook
|
|
195
|
-
// location, a fix to the order would have to be made
|
|
196
|
-
// and its value are one unit, and a wrong order makes the tool read
|
|
197
|
-
// name rather than erroring.
|
|
229
|
+
// Every location is written with these same four flags — the eslint, prettier and spell-check caches
|
|
230
|
+
// of the gate, the scoped lint, the edit hook and the pre-commit hook — so the sequence is built here
|
|
231
|
+
// once. Spelled out per location, a fix to the order would have to be made once per location and
|
|
232
|
+
// each copy fails silently: a flag and its value are one unit, and a wrong order makes the tool read
|
|
233
|
+
// `--cache-strategy` as the file name rather than erroring.
|
|
198
234
|
function content_cache_flags(cache_file: string): ReadonlyArray<string> {
|
|
199
235
|
return [...CONTENT_CACHE_FLAGS, CACHE_LOCATION_FLAG, cache_file]
|
|
200
236
|
}
|
|
@@ -204,8 +240,12 @@ const ESLINT_EDIT_CACHE_FLAGS = content_cache_flags(ESLINT_EDIT_CACHE_FILE)
|
|
|
204
240
|
const ESLINT_RELATED_CACHE_FLAGS = content_cache_flags(ESLINT_RELATED_CACHE_FILE)
|
|
205
241
|
const TS_CACHE_FLAGS = ['--incremental', '--tsBuildInfoFile', TS_BUILD_INFO_FILE] as const
|
|
206
242
|
const CSPELL_CACHE_FLAGS = content_cache_flags(CSPELL_CACHE_FILE)
|
|
243
|
+
const PRETTIER_CACHE_FLAGS = content_cache_flags(PRETTIER_CACHE_FILE)
|
|
244
|
+
const PRETTIER_RELATED_CACHE_FLAGS = content_cache_flags(PRETTIER_RELATED_CACHE_FILE)
|
|
245
|
+
const CSPELL_COMMIT_CACHE_FLAGS = content_cache_flags(CSPELL_COMMIT_CACHE_FILE)
|
|
246
|
+
const ESLINT_COMMIT_CACHE_FLAGS = content_cache_flags(ESLINT_COMMIT_CACHE_FILE)
|
|
207
247
|
|
|
208
|
-
export type { CommandCategory, CommandEntry, GateCacheSpec }
|
|
248
|
+
export type { CommandCategory, CommandEntry, CommandUsage, GateCacheSpec }
|
|
209
249
|
// The three cache files are exported one by one as well as as a list, because `josh bench` clears
|
|
210
250
|
// them per target: the lint step writes only the eslint one, so a target
|
|
211
251
|
// that cleared the list would report a cold type check as the lint's own cost. The edit hook's cache
|
|
@@ -216,8 +256,10 @@ export {
|
|
|
216
256
|
COMMAND_SIDE_EFFECTS,
|
|
217
257
|
CSPELL_CACHE_FILE,
|
|
218
258
|
CSPELL_CACHE_FLAGS,
|
|
259
|
+
CSPELL_COMMIT_CACHE_FLAGS,
|
|
219
260
|
ESLINT_CACHE_FILE,
|
|
220
261
|
ESLINT_CACHE_FLAGS,
|
|
262
|
+
ESLINT_COMMIT_CACHE_FLAGS,
|
|
221
263
|
ESLINT_EDIT_CACHE_FLAGS,
|
|
222
264
|
ESLINT_RELATED_CACHE_FLAGS,
|
|
223
265
|
ESLINT_RELATED_CACHE_FILE,
|
|
@@ -226,6 +268,10 @@ export {
|
|
|
226
268
|
GATE_COMMAND,
|
|
227
269
|
IGNORED_CACHE_FILES,
|
|
228
270
|
OPTIONAL_ENV_FILE_FLAGS,
|
|
271
|
+
PRETTIER_CACHE_FILE,
|
|
272
|
+
PRETTIER_CACHE_FLAGS,
|
|
273
|
+
PRETTIER_RELATED_CACHE_FILE,
|
|
274
|
+
PRETTIER_RELATED_CACHE_FLAGS,
|
|
229
275
|
SHARED_CACHE_SPECS,
|
|
230
276
|
TS_BUILD_INFO_FILE,
|
|
231
277
|
TS_CACHE_FLAGS,
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { core_budget } from '#scripts/gate/core-budget'
|
|
1
2
|
import { OPTIONAL_ENV_FILE_FLAGS, type CommandEntry } from './josh-command-types'
|
|
2
3
|
import { BACKLOG_COMMANDS } from './josh-commands-backlog'
|
|
3
4
|
import { DOCUMENT_COMMANDS } from './josh-commands-document'
|
|
@@ -80,6 +81,16 @@ const AI_COMMANDS: Record<string, CommandEntry> = {
|
|
|
80
81
|
category: 'AI tools',
|
|
81
82
|
reference: ['(--cut | --over <tokens-per-request>) [--path <dir>]', 'automation', ['none']],
|
|
82
83
|
},
|
|
84
|
+
'cost:audit': {
|
|
85
|
+
script: 'scripts/cost-audit/cost-audit-cli.ts',
|
|
86
|
+
description:
|
|
87
|
+
'Report AI cost over a period by session kind, tool category and guard, with cost per merge and regressions against the period before',
|
|
88
|
+
category: 'AI tools',
|
|
89
|
+
reference: ['[--period <days>]', 'maintainer', ['none']],
|
|
90
|
+
// Kit-only: it reads kit's own transcript store, like `josh retrospective`, which carries its
|
|
91
|
+
// summary line.
|
|
92
|
+
is_kit_only: true,
|
|
93
|
+
},
|
|
83
94
|
...DOCUMENT_COMMANDS,
|
|
84
95
|
time: {
|
|
85
96
|
script: 'scripts/time/time-cli.ts',
|
|
@@ -108,6 +119,8 @@ const AI_COMMANDS: Record<string, CommandEntry> = {
|
|
|
108
119
|
"Aggregate a finished run's cost, review findings, observation ledger and events into one digest",
|
|
109
120
|
category: 'AI tools',
|
|
110
121
|
reference: ['', 'maintainer', ['none']],
|
|
122
|
+
core_weight: core_budget.CORE_WEIGHTS.retrospective,
|
|
123
|
+
memory_mb: core_budget.MEMORY_MB.retrospective,
|
|
111
124
|
// Kit-only: it reads kit's own development run — the transcript store, the review ledger and the
|
|
112
125
|
// run event stream — so it means nothing in a consumer project and is dropped from a consumer's
|
|
113
126
|
// help, through the same declaration `josh time` uses for the same reason.
|
|
@@ -129,7 +129,7 @@ const DEV_COMMANDS: Record<string, CommandEntry> = {
|
|
|
129
129
|
'stop:guard': {
|
|
130
130
|
script: 'scripts/hooks/stop-guard.ts',
|
|
131
131
|
description:
|
|
132
|
-
'Claude Code Stop hook:
|
|
132
|
+
'Claude Code Stop hook: send the hold notify, release the hold and print the issue citations itself; block on the rules that need the model (reads the Stop payload on stdin)',
|
|
133
133
|
category: 'Development',
|
|
134
134
|
reference: ['', 'automation', ['none']],
|
|
135
135
|
// **No `tsx_arguments`, deliberately**, the same as `pretool:guard` above: this runs at every
|
|
@@ -19,6 +19,12 @@ const HOOKS_COMMANDS: Record<string, CommandEntry> = {
|
|
|
19
19
|
category: 'Git hooks',
|
|
20
20
|
reference: ['[paths...]', 'automation', ['none']],
|
|
21
21
|
},
|
|
22
|
+
'pre-commit-lint': {
|
|
23
|
+
script: 'scripts/hooks/pre-commit-lint.ts',
|
|
24
|
+
description: 'Git hook: run cspell, prettier or eslint over staged files from a content cache',
|
|
25
|
+
category: 'Git hooks',
|
|
26
|
+
reference: ['<cspell|prettier|eslint> [paths...]', 'automation', ['files']],
|
|
27
|
+
},
|
|
22
28
|
'pre-push-unit': {
|
|
23
29
|
script: 'scripts/hooks/pre-push-unit.ts',
|
|
24
30
|
description: 'Git hook: run unit tests, reusing a green gate recorded on the pushed tree',
|
|
@@ -83,6 +83,15 @@ const LANE_COMMANDS: Record<string, CommandEntry> = {
|
|
|
83
83
|
category: 'AI tools',
|
|
84
84
|
reference: ['<issue>', 'developer', ['files', 'git', 'processes', 'network']],
|
|
85
85
|
},
|
|
86
|
+
// `.env` is read for `JOSH_LANE_ROOT`, as every lane command reads it, so the lane is found.
|
|
87
|
+
'lane:withdraw': {
|
|
88
|
+
script: 'scripts/lane/lane-withdraw-cli.ts',
|
|
89
|
+
tsx_arguments: OPTIONAL_ENV_FILE_FLAGS,
|
|
90
|
+
description:
|
|
91
|
+
'Stop a running lane child, stash its uncommitted work, close its issue as not planned and close the lane — booked withdrawn, not as an outage or a failure',
|
|
92
|
+
category: 'AI tools',
|
|
93
|
+
reference: ['<issue> --reason <text>', 'developer', ['files', 'git', 'processes', 'network']],
|
|
94
|
+
},
|
|
86
95
|
// A live run's lane limit: `.env` is read so the bare form reports the
|
|
87
96
|
// `JOSH_LANE_LIMIT` a person set there when no override stands.
|
|
88
97
|
'lane:limit': {
|
|
@@ -106,7 +115,7 @@ const LANE_COMMANDS: Record<string, CommandEntry> = {
|
|
|
106
115
|
'lane:stats': {
|
|
107
116
|
...MEASURE_ARGUMENTS,
|
|
108
117
|
description:
|
|
109
|
-
'Print one table row of lane throughput, gate duration and machine load over a period, the per-stage durations of a lane under it,
|
|
118
|
+
'Print one table row of lane throughput, gate duration and machine load over a period, the per-stage durations of a lane under it, the wait after each ship stop reason under those, and the duration and reuse count of each gate check last',
|
|
110
119
|
category: 'AI tools',
|
|
111
120
|
reference: ['--period <days> [--limit <lane-limit>]', 'maintainer', ['none']],
|
|
112
121
|
default_script_arguments: ['stats'],
|
|
@@ -112,6 +112,11 @@ const WORKFLOW_COMMANDS: Record<string, CommandEntry> = {
|
|
|
112
112
|
// A script rather than an `sh -c` chain, because the strategy has to be named rather than left to
|
|
113
113
|
// the caller's git configuration: a bare `git pull` aborts with `Need to specify how to reconcile
|
|
114
114
|
// divergent branches` on exactly the diverged branch the command exists for.
|
|
115
|
+
//
|
|
116
|
+
// **It declares no core weight, by measurement** (joshuafolkken/kit#3944): its own work is git, and
|
|
117
|
+
// the catalog it may regenerate took 0.6s of CPU. The heavy processes seen beside it are commit
|
|
118
|
+
// hooks — its regenerated catalog's commit runs them — which reserve themselves, and a weight here
|
|
119
|
+
// would set the held mark they inherit, folding the parallel hook tools into this one place.
|
|
115
120
|
'main:merge': {
|
|
116
121
|
script: 'scripts/git/main-merge.ts',
|
|
117
122
|
description: 'Merge origin default branch into the current branch',
|