@joshuafolkken/kit 1.883.0 → 1.921.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.
Files changed (112) hide show
  1. package/.claude/skills/workflow-commands/fullrun-steps.md +4 -2
  2. package/.claude/skills/workflow-commands/halfrun.md +3 -1
  3. package/.claude/skills/workflow-commands/kickoff.md +5 -3
  4. package/.claude/skills/workflow-commands/observation-filing.md +3 -1
  5. package/.claude/skills/workflow-commands/prerequisite.md +3 -1
  6. package/.claude/skills/workflow-commands/target-repository.md +1 -1
  7. package/.github/pull_request_template.md +12 -0
  8. package/.github/release.yml +3 -0
  9. package/.github/workflows/ci.yml +8 -0
  10. package/.github/workflows/production.yml +10 -1
  11. package/.github/workflows/publish.yml +72 -2
  12. package/CLAUDE.md +2 -0
  13. package/dist/CLAUDE.md +2 -0
  14. package/dist/CLAUDE.static.md +8 -0
  15. package/dist/hooks/batch-guard.js +4 -4
  16. package/dist/hooks/{chunk-36UE53LS.js → chunk-3HZ5MJIW.js} +2 -2
  17. package/dist/hooks/chunk-3V37IID6.js +82 -0
  18. package/dist/hooks/{chunk-FRJKVSK3.js → chunk-77RLKZ5V.js} +2 -2
  19. package/dist/hooks/{chunk-VGYSA2NT.js → chunk-LC765SUA.js} +16 -2
  20. package/dist/hooks/{chunk-ZBK4XRAS.js → chunk-NWD47MW3.js} +3 -3
  21. package/dist/hooks/{chunk-4OXFU3MK.js → chunk-O2FBZPSW.js} +619 -156
  22. package/dist/hooks/{chunk-6MQCXEEA.js → chunk-OLTAGGHH.js} +25 -88
  23. package/dist/hooks/{chunk-FNFOLFFV.js → chunk-OYU6KPRA.js} +1 -1
  24. package/dist/hooks/{chunk-PRDCNGA6.js → chunk-UANRLZV7.js} +4 -4
  25. package/dist/hooks/{chunk-264QY6KS.js → chunk-UULARQ5Q.js} +23 -1
  26. package/dist/hooks/{chunk-Y5OYCU2F.js → chunk-XMR3BS35.js} +3 -3
  27. package/dist/hooks/codex-hook-adapter.js +11 -10
  28. package/dist/hooks/duplicate-read-guard.js +5 -5
  29. package/dist/hooks/format-edited.js +3 -2
  30. package/dist/hooks/investigation-guard.js +5 -5
  31. package/dist/hooks/pretool-guard.js +10 -9
  32. package/dist/hooks/stop-guard.js +3 -3
  33. package/dist/josh.js +155 -12
  34. package/package.json +70 -19
  35. package/prettier/index.js +3 -8
  36. package/prettier/static.d.ts +3 -0
  37. package/prettier/static.js +10 -0
  38. package/prompts/collaboration-workflow/issue-template.md +11 -4
  39. package/prompts/collaboration-workflow/upstream-interrupt.md +1 -1
  40. package/prompts/collaboration-workflow/wip-cap.md +2 -2
  41. package/prompts/review.md +2 -2
  42. package/prompts/testing-guide.md +1 -0
  43. package/scripts/build/build-claude-md.ts +6 -1
  44. package/scripts/ci/pr-classification.ts +114 -0
  45. package/scripts/document/document-byte-budget.ts +3 -2
  46. package/scripts/gate/gate-report.ts +2 -0
  47. package/scripts/gate/gate-steps.ts +50 -0
  48. package/scripts/gate/project-checks.ts +121 -0
  49. package/scripts/gate/verification-gate.ts +14 -43
  50. package/scripts/git/git-common-directory.ts +9 -1
  51. package/scripts/git/git-gh-pr-rollup.ts +29 -1
  52. package/scripts/git/git-gh-pr.ts +61 -1
  53. package/scripts/git/git-pr.ts +62 -13
  54. package/scripts/git/issue-labels.ts +9 -0
  55. package/scripts/init/distributed-paths.ts +9 -5
  56. package/scripts/init/hook-command-bootstrap.ts +40 -8
  57. package/scripts/init/hook-command-rewrite.ts +7 -3
  58. package/scripts/init/init-actions.ts +94 -7
  59. package/scripts/init/init-ai-copy.ts +104 -19
  60. package/scripts/init/init-static.ts +52 -0
  61. package/scripts/init/init.ts +97 -30
  62. package/scripts/init/project-profile-cli.ts +14 -0
  63. package/scripts/init/project-profile.ts +149 -0
  64. package/scripts/init/start.ts +30 -0
  65. package/scripts/issue/issue-bug-label.ts +13 -0
  66. package/scripts/issue/issue-classification.ts +74 -0
  67. package/scripts/issue/issue-lint-cli.ts +10 -3
  68. package/scripts/issue/markdown-section.ts +38 -4
  69. package/scripts/josh/__snapshots__/josh-command-map.test.ts.snap +27 -1
  70. package/scripts/josh/josh-command-map.ts +3 -0
  71. package/scripts/josh/josh-commands-development.ts +6 -0
  72. package/scripts/josh/josh-commands-project.ts +14 -1
  73. package/scripts/josh/josh-logic.ts +13 -0
  74. package/scripts/josh/run-github-prerequisite.ts +32 -0
  75. package/scripts/lane/lane-await.ts +8 -1
  76. package/scripts/lane/openai-lane-ship.ts +30 -0
  77. package/scripts/lane/openai-lane-supervisor.ts +35 -8
  78. package/scripts/lane/openai-review-broker.ts +260 -0
  79. package/scripts/lint/cspell-cached.ts +21 -0
  80. package/scripts/lint/lint-parallel.ts +44 -1
  81. package/scripts/observations/observations-flush.ts +1 -1
  82. package/scripts/package/production-dependency-graph.ts +68 -0
  83. package/scripts/package/verify-optional-eslint-install.ts +62 -0
  84. package/scripts/propagate/propagate-run.ts +6 -0
  85. package/scripts/propagate/propagate-steps.ts +2 -0
  86. package/scripts/release/github-release-cli.ts +11 -0
  87. package/scripts/release/github-release.ts +220 -0
  88. package/scripts/release/publish-tag-cli.ts +8 -0
  89. package/scripts/release/publish-tag.ts +11 -0
  90. package/scripts/release/release-publish.ts +7 -2
  91. package/scripts/rules/delivered-rules.ts +2 -0
  92. package/scripts/rules/issue-bug-label.ts +85 -0
  93. package/scripts/rules/issue-filing-args.ts +50 -0
  94. package/scripts/run/run-merge-cli.ts +19 -0
  95. package/scripts/run/run-merge.ts +9 -1
  96. package/scripts/run/run-ship-cli.ts +20 -0
  97. package/scripts/run/run-ship-detach.ts +180 -14
  98. package/scripts/run/run-ship-review-steps.ts +45 -25
  99. package/scripts/run/run-wake-session.ts +3 -1
  100. package/scripts/test/pilot-files.ts +0 -2
  101. package/scripts/test/skip-marker.ts +3 -0
  102. package/scripts/test/test-declared-changed.ts +2 -1
  103. package/scripts/test/test-declared-logic.ts +15 -10
  104. package/scripts/test/test-declared.ts +20 -8
  105. package/scripts/test/test-red-logic.ts +3 -3
  106. package/scripts/test/test-unit-guard.ts +24 -12
  107. package/scripts/version/version-check-arguments.ts +14 -0
  108. package/scripts/version/version-check.ts +10 -3
  109. package/templates/CLAUDE.static.md +8 -0
  110. package/templates/cursorrules.static +1 -0
  111. package/templates/prettierignore.static +12 -0
  112. package/templates/workflows/ci.yml +5 -0
@@ -7,6 +7,8 @@ the run is at, and the sections below carry that step in full.
7
7
 
8
8
  ## The `fullrun #N` step list
9
9
 
10
+ Use `pnpm josh issue:lint` `labels:`; see `prompts/collaboration-workflow/issue-template.md`.
11
+
10
12
  **Add `in-progress` the moment `run:hold` answered `hold`** (create if missing:
11
13
  `gh api repos/{owner}/{repo}/labels -f name=in-progress -f color=0075ca -f description="Work is
12
14
  actively in progress" --silent 2>/dev/null || true`, then `gh api
@@ -49,8 +51,8 @@ completion notification, then merges; if blockers are found it exits non-zero
49
51
  `kickoff new` + `fullrun #N` in one run. Steps: (1) Derive an English title, or use the provided one.
50
52
  **(1a) Run `pnpm josh issue:scout "<title>" [--body "<summary>"]` before creating the Issue** — a
51
53
  candidate that covers the same work stops the run rather than filing a second Issue (`SKILL.md` → §2e).
52
- (2) Create Issue: `gh api repos/{owner}/{repo}/issues -f title="<title>" -f 'labels[]=depth:<n>' -f
53
- body="<body>"` (body per `prompts/collaboration-workflow/issue-template.md`). Capture `<N>`. (3) Add
54
+ (2) Create Issue: `gh api repos/{owner}/{repo}/issues -f title="<title>" -f 'labels[]=depth:<n>' -F
55
+ body=@<body-file>` (per `prompts/collaboration-workflow/issue-template.md`). Capture `<N>`. (3) Add
54
56
  `in-progress` (as above). (4) Post the agreed plan in the session language: fill the body if blank,
55
57
  otherwise add a comment. (5) If the working tree already has staged or modified files,
56
58
  `git stash push -m "fullrun new: pre-existing changes"` first. (6) `git switch main && git pull`. (7)
@@ -1,5 +1,7 @@
1
1
  # `halfrun` — the manifest (implement + verify, stop before commit)
2
2
 
3
+ When this run files a new Issue, run `pnpm josh issue:lint <body-file>` and apply every label in its `labels:` answer at creation; `prompts/collaboration-workflow/issue-template.md` is the single source for this classification. Keep the existing `depth` and `route` labels.
4
+
3
5
  `halfrun` sits between `kickoff` (plan only) and `fullrun` (full execution with auto-merge). It
4
6
  implements the change and runs the full verification gate, then **stops before commit** — nothing is
5
7
  committed, pushed, or opened as a PR — so the user manually verifies the change (typically by exercising
@@ -52,7 +54,7 @@ back with fixes, treat each as a new round: implement, re-run `pnpm josh gate`,
52
54
  `halfrun new` or `halfrun new "<title>"`: `kickoff new` + `halfrun #<N>` (no Issue exists yet). Steps
53
55
  mirror `fullrun new` (1)–(8): derive an English title (or use the provided one) → **run `pnpm josh
54
56
  issue:scout "<title>" [--body "<summary>"]` before creating the Issue** (`SKILL.md` → §2e) → create the
55
- Issue (`gh api repos/{owner}/{repo}/issues -f title="<title>" -f 'labels[]=depth:<n>' -f body="<body>"`,
57
+ Issue (`gh api repos/{owner}/{repo}/issues -f title="<title>" -f 'labels[]=depth:<n>' -F body=@<body-file>`,
56
58
  body per `prompts/collaboration-workflow/issue-template.md`) → add `in-progress` → post the agreed plan → stash
57
59
  any pre-existing changes with `git stash push -m "halfrun new: pre-existing changes"`, popped by
58
60
  message with `pnpm josh stash:pop "halfrun new: pre-existing changes"`, never a positional `git stash pop` →
@@ -47,13 +47,13 @@ split is found.
47
47
  title. **(1a) Run `pnpm josh issue:scout "<title>" [--body "<summary>"]` before creating the Issue** —
48
48
  a candidate that covers the same work stops the run rather than filing a second Issue (`SKILL.md` →
49
49
  §2e). (2) Create Issue: `gh api repos/{owner}/{repo}/issues -f title="<title>" -f 'labels[]=depth:<n>'
50
- -f body="<body>"` (body per `prompts/collaboration-workflow/issue-template.md`). Capture `<N>`. (3)
50
+ -F body=@<body-file>` (body per `prompts/collaboration-workflow/issue-template.md`). Capture `<N>`. (3)
51
51
  Post the plan in the session language, using the same body/comment logic as `kickoff #<N>`. (4) Send
52
52
  Telegram notification. (5) **Stop** — do not implement. **Multi-issue split path**: (1) For each
53
53
  independent deliverable, derive a focused English title, **run `pnpm josh issue:scout "<sub-title>"`
54
54
  on it** (`SKILL.md` → §2e), and create a separate Issue with the `route:split` label: `gh api
55
55
  repos/{owner}/{repo}/issues -f title="<sub-title>" -f 'labels[]=route:split' -f 'labels[]=depth:<n>'
56
- -f body="<body>"`. Capture each Issue number. **When the split is filed into a repository other than
56
+ -F body=@<body-file>`. Capture each Issue number. **When the split is filed into a repository other than
57
57
  the one this session is running in**, every child body gets the `## Origin` backlink described in the
58
58
  cross-package rule the AI documents keep resident, the epic body carries the same link as prose or a
59
59
  plain bullet (never as a checkbox row, which would disable its auto-close), and the originating Issue
@@ -66,7 +66,7 @@ split is found.
66
66
  josh epic:check <E>`. Only where `josh` is unavailable, fall back to the manual procedure: ensure the
67
67
  label exists (`gh api repos/{owner}/{repo}/labels -f name=epic -f color=5319e7 -f description="Tracks
68
68
  a batch of child issues from one split" --silent 2>/dev/null || true`), then create the epic with `gh
69
- api repos/{owner}/{repo}/issues -f title="<epic-title>" -f 'labels[]=epic' -f body="<body>"`. Its body
69
+ api repos/{owner}/{repo}/issues -f title="<epic-title>" -f 'labels[]=epic' -F body=@<body-file>`. Its body
70
70
  follows the epic format in `prompts/collaboration-workflow/issue-template.md` — split rationale,
71
71
  dependencies, the `backlogrun` command, and a child task list in task-list syntax (`- [ ] #N`). The epic
72
72
  exists as the **non-closing home for the split rationale**. When the children have no required order,
@@ -80,3 +80,5 @@ split is found.
80
80
  **database id**, not its issue number; a failure here is non-fatal). Never fold the relation into the
81
81
  creation call. (3) Send Telegram notification listing all created issues. (4) Present the command
82
82
  `backlogrun #<E> --only`. (5) **Stop** — do not implement.
83
+
84
+ Before filing, run `pnpm josh issue:lint <body-file>` and apply every label in its `labels:` answer at creation, following `prompts/collaboration-workflow/issue-template.md` for classification.
@@ -29,6 +29,8 @@ backlog pool (`backlogrun-steps.md` → "What one invocation approves").
29
29
 
30
30
  The detail below is read at the filing decision, and the marker suite pins the rules here.
31
31
 
32
+ Before filing an observation, run `pnpm josh issue:lint <body-file>` and apply every label in its `labels:` answer at creation; `prompts/collaboration-workflow/issue-template.md` is the single source. Keep the depth label.
33
+
32
34
  ### The depth test — a discretionary filing cites the product work it blocked
33
35
 
34
36
  **A run that has just spent an hour inside the workflow tooling files findings about the workflow
@@ -55,7 +57,7 @@ cap's branch-2 filing all pass through a `gh api … issues` call, and the depth
55
57
  beside whatever `route:` label that call already carries.
56
58
 
57
59
  ```bash
58
- gh api repos/{owner}/{repo}/issues -f title="<title>" -f 'labels[]=depth:1' -f body="<body>"
60
+ gh api repos/{owner}/{repo}/issues -f title="<title>" -f 'labels[]=depth:1' -F body=@<body-file>
59
61
  gh api repos/{owner}/{repo}/issues/<N>/labels -f 'labels[]=depth:1' # an Issue already filed
60
62
  ```
61
63
 
@@ -25,8 +25,10 @@ stays countable by filing route afterwards. **This paragraph belongs to the prer
25
25
  the table** — the label means a filing the run is *blocked by*, so the observation row carries no
26
26
  `route:` label of its own (§2i):
27
27
 
28
+ Before that call, run `pnpm josh issue:lint <body-file>` and apply every label in its `labels:` answer at creation; `prompts/collaboration-workflow/issue-template.md` is the single source. Keep `route:tier-a` and `depth`.
29
+
28
30
  ```bash
29
- gh api repos/{owner}/{repo}/issues -f title="<title>" -f 'labels[]=route:tier-a' -f 'labels[]=depth:<n>' -f body="<body>"
31
+ gh api repos/{owner}/{repo}/issues -f title="<title>" -f 'labels[]=route:tier-a' -f 'labels[]=depth:<n>' -F body=@<body-file>
30
32
  ```
31
33
 
32
34
  Every "file the prerequisite" below means that labelled filing, and it always happens **first**: the
@@ -41,7 +41,7 @@ backlogrun joshuafolkken/kit#858 --only
41
41
  never clone. The one exception is the split path's epic, since `pnpm josh epic` only writes the
42
42
  repository it runs in — run it in that repository's checkout, or fall back to `gh api
43
43
  repos/<owner/repo>/labels …` followed by `gh api repos/<owner/repo>/issues -f title="<epic-title>" -f
44
- 'labels[]=epic' -f body="<body>"`, and report that `epic:check` could not be run. The promote arm has
44
+ 'labels[]=epic' -F body=@<body-file>`, and report that `epic:check` could not be run. The promote arm has
45
45
  no such fallback: with no checkout there, file the children and stop.
46
46
  - **The implementing entries require a checkout and never create one — when the target is another
47
47
  repository.** A prefix naming the session's own repository changes nothing (`fullrun kit#412` in the
@@ -1 +1,13 @@
1
1
  closes #
2
+
3
+ ## Release classification
4
+
5
+ Add exactly one label before merging:
6
+
7
+ - `breaking-change` — any incompatible change, even when it also adds a feature or fixes a bug
8
+ - `enhancement` — a compatible new feature or improvement
9
+ - `bugfix` — a compatible fix
10
+ - `other-change` — documentation, dependencies, or maintenance included in Other Changes
11
+ - `ignore-for-release` — omit this pull request from the changelog
12
+
13
+ Automated pull requests without a classification label are treated as Other Changes. If an automated pull request needs another classification or exclusion, add that one label.
@@ -13,6 +13,9 @@ changelog:
13
13
  labels:
14
14
  - Semver-Minor
15
15
  - enhancement
16
+ - title: Bug Fixes 🐛
17
+ labels:
18
+ - bugfix
16
19
  - title: Other Changes
17
20
  labels:
18
21
  - '*'
@@ -6,6 +6,7 @@ on:
6
6
 
7
7
  pull_request:
8
8
  branches: [main]
9
+ types: [opened, synchronize, reopened, labeled, unlabeled]
9
10
 
10
11
  # A push run is grouped by the commit it carries, so a later push to main never cancels an earlier
11
12
  # one. Without the sha every push to main shares one group — `github.ref` is `refs/heads/main` for
@@ -351,6 +352,10 @@ jobs:
351
352
  - name: Run verification gate
352
353
  run: pnpm josh gate --verbose --no-unit
353
354
 
355
+ - name: Check release classification
356
+ if: github.event_name == 'pull_request'
357
+ run: pnpm josh pr:classification
358
+
354
359
  # The other half of the gate, on a runner of its own. It carries the same setup steps as
355
360
  # `static-checks` rather than sharing them: a GitHub job is its own machine, so every job that
356
361
  # needs Node sets Node up, and this workflow already writes that preamble once per job. The
@@ -425,6 +430,9 @@ jobs:
425
430
  - name: Run unit tests
426
431
  run: pnpm josh test:unit
427
432
 
433
+ - name: Verify optional ESLint consumer install
434
+ run: pnpm exec tsx scripts/package/verify-optional-eslint-install.ts
435
+
428
436
  # **The required status check. `Checks` is a name the branch ruleset already requires, and this job
429
437
  # is what keeps that name meaning what it meant** (joshuafolkken/kit#1226) — every check the single
430
438
  # `Checks` job used to run has passed. It runs no checks itself; it reads the two halves' results.
@@ -2,9 +2,18 @@ name: Release to Production
2
2
  on:
3
3
  repository_dispatch:
4
4
  types: [new-tag-created]
5
+ workflow_call:
6
+ inputs:
7
+ tag:
8
+ required: true
9
+ type: string
5
10
 
6
11
  jobs:
7
12
  update-branch:
13
+ if: github.repository != 'joshuafolkken/kit' || inputs.tag != ''
14
+ concurrency:
15
+ group: production-update
16
+ queue: max
8
17
  runs-on: ubuntu-latest
9
18
  permissions:
10
19
  contents: write
@@ -24,7 +33,7 @@ jobs:
24
33
  # repository_dispatch always runs on the default branch, so the event ref
25
34
  # resolves to that branch, not the released tag. Use the tag carried in the
26
35
  # dispatch payload (set by auto-tag.yml) as the merge source instead.
27
- REF_NAME: ${{ github.event.client_payload.tag }}
36
+ REF_NAME: ${{ inputs.tag || github.event.client_payload.tag }}
28
37
  run: |
29
38
  if [ -z "$REF_NAME" ]; then
30
39
  echo "::error::new-tag-created dispatch carried no tag payload; aborting." >&2
@@ -1,4 +1,5 @@
1
1
  name: Publish
2
+ run-name: Publish ${{ github.event.client_payload.tag }}
2
3
 
3
4
  on:
4
5
  repository_dispatch:
@@ -6,6 +7,9 @@ on:
6
7
 
7
8
  jobs:
8
9
  publish-github:
10
+ concurrency:
11
+ group: package-publish
12
+ queue: max
9
13
  runs-on: ubuntu-latest
10
14
  timeout-minutes: 10
11
15
  permissions:
@@ -36,11 +40,24 @@ jobs:
36
40
 
37
41
  - run: pnpm install --frozen-lockfile --ignore-scripts
38
42
 
39
- - run: pnpm publish --no-git-checks --tag latest --registry https://npm.pkg.github.com
43
+ - name: Select GitHub Packages tag
44
+ id: publish-tag
45
+ run: |
46
+ version=$(node -p "require('./package.json').version")
47
+ latest=$(cd "$RUNNER_TEMP" && npm view @joshuafolkken/kit dist-tags.latest --registry https://npm.pkg.github.com)
48
+ tag=$(pnpm exec tsx scripts/release/publish-tag-cli.ts "$version" "$latest")
49
+ echo "tag=$tag" >> "$GITHUB_OUTPUT"
50
+ env:
51
+ NODE_AUTH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
52
+
53
+ - run: pnpm publish --no-git-checks --tag ${{ steps.publish-tag.outputs.tag }} --registry https://npm.pkg.github.com
40
54
  env:
41
55
  NODE_AUTH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
42
56
 
43
57
  publish-npm:
58
+ concurrency:
59
+ group: package-publish
60
+ queue: max
44
61
  runs-on: ubuntu-latest
45
62
  timeout-minutes: 10
46
63
  permissions:
@@ -72,5 +89,58 @@ jobs:
72
89
 
73
90
  - run: pnpm pack --out "$RUNNER_TEMP/kit.tgz"
74
91
 
92
+ - name: Select npm tag
93
+ id: publish-tag
94
+ run: |
95
+ version=$(node -p "require('./package.json').version")
96
+ latest=$(cd "$RUNNER_TEMP" && npm view @joshuafolkken/kit dist-tags.latest --registry https://registry.npmjs.org)
97
+ tag=$(pnpm exec tsx scripts/release/publish-tag-cli.ts "$version" "$latest")
98
+ echo "tag=$tag" >> "$GITHUB_OUTPUT"
99
+
75
100
  - name: Publish to npm
76
- run: cd "$RUNNER_TEMP" && npm publish kit.tgz --access public --tag latest --registry https://registry.npmjs.org --userconfig /dev/null
101
+ run: cd "$RUNNER_TEMP" && npm publish kit.tgz --access public --tag ${{ steps.publish-tag.outputs.tag }} --registry https://registry.npmjs.org --userconfig /dev/null
102
+
103
+ update-production:
104
+ needs: [publish-github, publish-npm]
105
+ permissions:
106
+ contents: write
107
+ uses: ./.github/workflows/production.yml
108
+ with:
109
+ tag: ${{ github.event.client_payload.tag }}
110
+
111
+ create-release:
112
+ needs: [publish-github, publish-npm, update-production]
113
+ runs-on: ubuntu-latest
114
+ timeout-minutes: 65
115
+ permissions:
116
+ actions: read
117
+ contents: write
118
+ steps:
119
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
120
+ with:
121
+ ref: ${{ github.event.client_payload.tag }}
122
+ fetch-depth: 0
123
+
124
+ - uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
125
+ with:
126
+ node-version: 24
127
+
128
+ - name: Resolve pnpm version
129
+ id: pnpm-version
130
+ run: |
131
+ version=$(node -p "const m = require('./package.json'); m.packageManager?.match(/^pnpm@([^+]+)/)?.[1] ?? (m.devEngines?.packageManager?.name === 'pnpm' ? m.devEngines.packageManager.version?.split('+')[0] : 'latest') ?? 'latest'")
132
+ test -n "$version"
133
+ echo "version=$version" >> "$GITHUB_OUTPUT"
134
+
135
+ - uses: pnpm/setup@fbda4c85fc2e1e08721cd8763afea8f48d60f024 # v3.0.0
136
+ with:
137
+ version: ${{ steps.pnpm-version.outputs.version }}
138
+ install: false
139
+
140
+ - run: pnpm install --frozen-lockfile --ignore-scripts
141
+
142
+ - name: Publish GitHub Release
143
+ run: pnpm exec tsx scripts/release/github-release-cli.ts
144
+ env:
145
+ GH_TOKEN: ${{ github.token }}
146
+ RELEASE_TAG: ${{ github.event.client_payload.tag }}
package/CLAUDE.md CHANGED
@@ -108,6 +108,7 @@ For every code modification, in order:
108
108
 
109
109
  - **Tests are required for ALL code changes** (bug fixes, timing/animation fixes and refactors included): bug fix → regression test; UI/animation/timing → E2E for the observable change; logic/utility → unit; refactor → tests pinning existing behavior BEFORE the change (`prompts/refactoring.md`).
110
110
  - **Non-runtime updates (pre-approved manual-only exception)**: a change touching no executable runtime code path may proceed with manual verification — declare it in Step 0 and state why. It covers docs, non-executable config, editor/IDE files, and cosmetic asset swaps with no selector/path change; the mechanically exempt (`*.md`, `.editorconfig`, `.idea/**`, `.vscode/**`, `prompts/**`) are recognized by the command below, and the rest stay the exemption a person declares. A test infeasible for a runtime change needs its reason stated and user approval.
111
+ - **static の HTML/CSS 例外:** `package.json` に `josh.profile: static` が記録され、変更が HTML/CSS だけなら自動テストの代わりにブラウザーで表示を確認する。対象ページを開き、想定する画面幅でレイアウト・リンク・HTML 内の操作を確認し、観察結果を報告する。HTML/CSS と同時に変更した場合も、JavaScript と TypeScript のファイルには自動テストが必要。`pnpm josh test:declared` はこの場合だけ理由を添えて `exempt` と表示する。
111
112
  - **The commit stage answers this mechanically**: `pnpm josh test:declared` prints `required` / `exempt` / `satisfied` from the changed paths, and a runtime change with no test is refused at `pnpm josh git -y` on `required` — add the declared test or declare the non-runtime exception, then reissue (`prompts/collaboration-workflow/rule-delivery.md`).
112
113
  - **Read a target's line headroom before editing: `pnpm josh lines <path>`** — near the limit, `Target` carries the splitting plan.
113
114
 
@@ -121,6 +122,7 @@ For every code modification, in order:
121
122
  Run the full verification set **in order**; do not skip, reorder, or report completion on a failed or skipped step without the user agreeing. Inside a `fullrun` / `backlogrun` the gate runs beside the review and the merge chain (`workflow-commands` skill → §2, `prompts/review.md`).
122
123
 
123
124
  0. **Test gate** — no tests added? Continue only under the non-runtime exception (Step 0) or explicit approval; otherwise stop and add tests.
125
+ static プロファイルの HTML/CSS だけの変更には、Step 0 の手動ブラウザー確認を適用できる。
124
126
  1. **Refactor** — `prompts/refactoring.md`, until no high/medium items remain.
125
127
  2. **`pnpm josh gate`** — lint, type check, spell check and unit tests concurrently. One gate per run; while implementing re-run a single check by name (`pnpm josh lint:related` / `pnpm josh cspell:dot` / `pnpm josh test:related`).
126
128
  3. **Self-review** — a subagent runs `/code-review` per `prompts/review.md` (never a main-line `Skill` load); level from the changed paths, at most two rounds, high/medium findings resolved. `prompts/review.md` → "Review round cap".
package/dist/CLAUDE.md CHANGED
@@ -108,6 +108,7 @@ For every code modification, in order:
108
108
 
109
109
  - **Tests are required for ALL code changes** (bug fixes, timing/animation fixes and refactors included): bug fix → regression test; UI/animation/timing → E2E for the observable change; logic/utility → unit; refactor → tests pinning existing behavior BEFORE the change (`node_modules/@joshuafolkken/kit/prompts/refactoring.md`).
110
110
  - **Non-runtime updates (pre-approved manual-only exception)**: a change touching no executable runtime code path may proceed with manual verification — declare it in Step 0 and state why. It covers docs, non-executable config, editor/IDE files, and cosmetic asset swaps with no selector/path change; the mechanically exempt (`*.md`, `.editorconfig`, `.idea/**`, `.vscode/**`, `prompts/**`) are recognized by the command below, and the rest stay the exemption a person declares. A test infeasible for a runtime change needs its reason stated and user approval.
111
+ - **static の HTML/CSS 例外:** `package.json` に `josh.profile: static` が記録され、変更が HTML/CSS だけなら自動テストの代わりにブラウザーで表示を確認する。対象ページを開き、想定する画面幅でレイアウト・リンク・HTML 内の操作を確認し、観察結果を報告する。HTML/CSS と同時に変更した場合も、JavaScript と TypeScript のファイルには自動テストが必要。`pnpm josh test:declared` はこの場合だけ理由を添えて `exempt` と表示する。
111
112
  - **The commit stage answers this mechanically**: `pnpm josh test:declared` prints `required` / `exempt` / `satisfied` from the changed paths, and a runtime change with no test is refused at `pnpm josh git -y` on `required` — add the declared test or declare the non-runtime exception, then reissue (`node_modules/@joshuafolkken/kit/prompts/collaboration-workflow/rule-delivery.md`).
112
113
  - **Read a target's line headroom before editing: `pnpm josh lines <path>`** — near the limit, `Target` carries the splitting plan.
113
114
 
@@ -121,6 +122,7 @@ For every code modification, in order:
121
122
  Run the full verification set **in order**; do not skip, reorder, or report completion on a failed or skipped step without the user agreeing. Inside a `fullrun` / `backlogrun` the gate runs beside the review and the merge chain (`workflow-commands` skill → §2, `node_modules/@joshuafolkken/kit/prompts/review.md`).
122
123
 
123
124
  0. **Test gate** — no tests added? Continue only under the non-runtime exception (Step 0) or explicit approval; otherwise stop and add tests.
125
+ static プロファイルの HTML/CSS だけの変更には、Step 0 の手動ブラウザー確認を適用できる。
124
126
  1. **Refactor** — `node_modules/@joshuafolkken/kit/prompts/refactoring.md`, until no high/medium items remain.
125
127
  2. **`pnpm josh gate`** — lint, type check, spell check and unit tests concurrently. One gate per run; while implementing re-run a single check by name (`pnpm josh lint:related` / `pnpm josh cspell:dot` / `pnpm josh test:related`).
126
128
  3. **Self-review** — a subagent runs `/code-review` per `node_modules/@joshuafolkken/kit/prompts/review.md` (never a main-line `Skill` load); level from the changed paths, at most two rounds, high/medium findings resolved. `node_modules/@joshuafolkken/kit/prompts/review.md` → "Review round cap".
@@ -0,0 +1,8 @@
1
+ # Project instructions
2
+
3
+ - 既存のファイルと利用者の設定を尊重し、変更する前に内容を確認する。
4
+ - 変更には検証を付け、実行した結果を報告する。
5
+ - HTML、CSS、JavaScript のファイルがある場合は Prettier で整形する。
6
+ - 画面に見える変更をした場合はブラウザーで表示と操作を確認する。
7
+ - JavaScript または TypeScript の動作を変更した場合は、その動作を確認する自動テストを追加する。
8
+ - Git や GitHub を使う場合だけ、それぞれのワークフローを利用する。
@@ -9,10 +9,10 @@ import {
9
9
  load_environment_file,
10
10
  notice_refusal_path,
11
11
  refusal_path
12
- } from "./chunk-FRJKVSK3.js";
13
- import "./chunk-36UE53LS.js";
14
- import "./chunk-FNFOLFFV.js";
15
- import "./chunk-264QY6KS.js";
12
+ } from "./chunk-77RLKZ5V.js";
13
+ import "./chunk-3HZ5MJIW.js";
14
+ import "./chunk-OYU6KPRA.js";
15
+ import "./chunk-UULARQ5Q.js";
16
16
  import "./chunk-FXAKJKTB.js";
17
17
  import "./chunk-SSX23SJ2.js";
18
18
  export {
@@ -1,13 +1,13 @@
1
1
  import {
2
2
  lane_child_marker
3
- } from "./chunk-FNFOLFFV.js";
3
+ } from "./chunk-OYU6KPRA.js";
4
4
  import {
5
5
  time_bundle_call,
6
6
  time_format,
7
7
  time_round_trips,
8
8
  time_spans,
9
9
  time_transcript_line
10
- } from "./chunk-264QY6KS.js";
10
+ } from "./chunk-UULARQ5Q.js";
11
11
 
12
12
  // scripts/lane/lane-guard-policy.ts
13
13
  var DEFAULT_MODE = "refuse";
@@ -0,0 +1,82 @@
1
+ // scripts/build/local-bin.ts
2
+ import { existsSync, readFileSync } from "node:fs";
3
+ import { createRequire } from "node:module";
4
+ import path from "node:path";
5
+
6
+ // scripts/lib/schemas.ts
7
+ import { z } from "zod";
8
+ var overrides_snapshot_schema = z.record(z.string(), z.string());
9
+ var package_version_schema = z.object({ version: z.string() });
10
+ var package_named_version_schema = z.looseObject({ name: z.string(), version: z.string() });
11
+ var package_with_version_schema = z.looseObject({ version: z.string() });
12
+ var ls_global_dependency_schema = z.looseObject({ version: z.string() });
13
+ var ls_global_dependencies_schema = z.record(z.string(), ls_global_dependency_schema).optional();
14
+ var pnpm_ls_global_schema = z.array(
15
+ z.looseObject({
16
+ dependencies: ls_global_dependencies_schema
17
+ })
18
+ );
19
+ var vscode_settings_schema = z.record(z.string(), z.unknown());
20
+ var with_scripts_schema = z.looseObject({
21
+ scripts: z.record(z.string(), z.string()).optional()
22
+ });
23
+ var with_development_deps_schema = z.looseObject({
24
+ devDependencies: z.record(z.string(), z.string()).optional()
25
+ });
26
+ var with_package_manager_schema = z.looseObject({
27
+ packageManager: z.string().optional()
28
+ });
29
+ var with_development_engine_schema = z.looseObject({
30
+ devEngines: z.record(z.string(), z.unknown()).optional()
31
+ });
32
+ var bin_entry_schema = z.union([z.string(), z.record(z.string(), z.string())]).optional();
33
+ var package_bin_schema = z.looseObject({ bin: bin_entry_schema });
34
+ var json_object_schema = z.record(z.string(), z.unknown());
35
+ var string_array_schema = z.array(z.string());
36
+ var string_record_schema = z.record(z.string(), z.string());
37
+
38
+ // scripts/build/local-bin.ts
39
+ var NODE_MODULES = "node_modules";
40
+ var BIN_DIR = ".bin";
41
+ var WINDOWS_PLATFORM = "win32";
42
+ var WINDOWS_SHIM_SUFFIX = ".cmd";
43
+ var PACKAGE_JSON = "package.json";
44
+ function resolve_local_bin(project_root, bin_name) {
45
+ const shim = process.platform === WINDOWS_PLATFORM ? `${bin_name}${WINDOWS_SHIM_SUFFIX}` : bin_name;
46
+ return path.join(project_root, NODE_MODULES, BIN_DIR, shim);
47
+ }
48
+ function ancestor_directories(start_directory) {
49
+ const directories = [];
50
+ let current = start_directory;
51
+ while (!directories.includes(current)) {
52
+ directories.push(current);
53
+ current = path.dirname(current);
54
+ }
55
+ return directories;
56
+ }
57
+ function find_local_bin_upwards(start_directory, bin_name) {
58
+ return ancestor_directories(start_directory).map((directory) => resolve_local_bin(directory, bin_name)).find((candidate) => existsSync(candidate));
59
+ }
60
+ function read_bin_entry(manifest_path, package_name, bin_name) {
61
+ const { bin } = package_bin_schema.parse(JSON.parse(readFileSync(manifest_path, "utf8")));
62
+ if (typeof bin === "string") return bin_name === path.basename(package_name) ? bin : void 0;
63
+ return bin?.[bin_name];
64
+ }
65
+ function resolve_package_bin(base_directory, package_name, bin_name) {
66
+ try {
67
+ const resolve_from = createRequire(path.join(base_directory, PACKAGE_JSON));
68
+ const manifest_path = resolve_from.resolve(`${package_name}/${PACKAGE_JSON}`);
69
+ const bin_entry = read_bin_entry(manifest_path, package_name, bin_name);
70
+ if (bin_entry === void 0) return void 0;
71
+ const cli_entry = path.join(path.dirname(manifest_path), bin_entry);
72
+ return existsSync(cli_entry) ? cli_entry : void 0;
73
+ } catch {
74
+ return void 0;
75
+ }
76
+ }
77
+
78
+ export {
79
+ resolve_local_bin,
80
+ find_local_bin_upwards,
81
+ resolve_package_bin
82
+ };
@@ -1,10 +1,10 @@
1
1
  import {
2
2
  lane_guard_policy,
3
3
  time_batch_guard
4
- } from "./chunk-36UE53LS.js";
4
+ } from "./chunk-3HZ5MJIW.js";
5
5
  import {
6
6
  hook_decision
7
- } from "./chunk-FNFOLFFV.js";
7
+ } from "./chunk-OYU6KPRA.js";
8
8
 
9
9
  // scripts/hooks/batch-guard.ts
10
10
  import { text } from "node:stream/consumers";
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  lane_child_marker,
3
3
  run_issue_number
4
- } from "./chunk-FNFOLFFV.js";
4
+ } from "./chunk-OYU6KPRA.js";
5
5
  import {
6
6
  PLATFORM_TEMP_ROOT,
7
7
  cost_blocks,
@@ -11,7 +11,7 @@ import {
11
11
  time_density_hook,
12
12
  time_shell,
13
13
  time_transcript_line
14
- } from "./chunk-264QY6KS.js";
14
+ } from "./chunk-UULARQ5Q.js";
15
15
  import {
16
16
  ENV_FILE_NAME,
17
17
  LANE_SEAT_KEY,
@@ -1512,6 +1512,9 @@ var run_cut = {
1512
1512
  };
1513
1513
 
1514
1514
  // scripts/git/issue-labels.ts
1515
+ var BUG_LABEL = "bug";
1516
+ var ENHANCEMENT_LABEL = "enhancement";
1517
+ var BREAKING_CHANGE_LABEL = "breaking-change";
1515
1518
  var IN_PROGRESS_LABEL = "in-progress";
1516
1519
  var NEEDS_DECISION_LABEL = "needs-decision";
1517
1520
  var NEEDS_HUMAN_REVIEW_LABEL = "needs-human-review";
@@ -1519,6 +1522,13 @@ var ALREADY_DONE_LABEL = "already-done";
1519
1522
  function has_any_label(labels, wanted) {
1520
1523
  return (labels ?? []).some((label) => wanted.has(label.name.toLowerCase()));
1521
1524
  }
1525
+ function label_name_of(labels, wanted) {
1526
+ const target = wanted.toLowerCase();
1527
+ return labels.find((label) => label.toLowerCase() === target);
1528
+ }
1529
+ function has_label_name(labels, wanted) {
1530
+ return label_name_of(labels, wanted) !== void 0;
1531
+ }
1522
1532
 
1523
1533
  // scripts/rules/shell-segments.ts
1524
1534
  var SEGMENT_SEPARATOR = /&&|\|\||;|\n/u;
@@ -3276,11 +3286,15 @@ export {
3276
3286
  lane_child_invocation,
3277
3287
  run_hold,
3278
3288
  run_cut,
3289
+ BUG_LABEL,
3290
+ ENHANCEMENT_LABEL,
3291
+ BREAKING_CHANGE_LABEL,
3279
3292
  IN_PROGRESS_LABEL,
3280
3293
  NEEDS_DECISION_LABEL,
3281
3294
  NEEDS_HUMAN_REVIEW_LABEL,
3282
3295
  ALREADY_DONE_LABEL,
3283
3296
  has_any_label,
3297
+ has_label_name,
3284
3298
  lane_park,
3285
3299
  repo_party,
3286
3300
  FULL_PAGE_QUERY,
@@ -1,12 +1,12 @@
1
1
  import {
2
2
  investigation_reads
3
- } from "./chunk-Y5OYCU2F.js";
3
+ } from "./chunk-XMR3BS35.js";
4
4
  import {
5
5
  lane_guard_policy
6
- } from "./chunk-36UE53LS.js";
6
+ } from "./chunk-3HZ5MJIW.js";
7
7
  import {
8
8
  hook_decision
9
- } from "./chunk-FNFOLFFV.js";
9
+ } from "./chunk-OYU6KPRA.js";
10
10
 
11
11
  // scripts/delegation/investigation-guard.ts
12
12
  import { text } from "node:stream/consumers";