@joshuafolkken/kit 1.1094.0 → 1.1136.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 (177) hide show
  1. package/.claude/agents/investigator.md +17 -0
  2. package/.claude/settings.json +1 -0
  3. package/.claude/skills/workflow-commands/SKILL.md +1 -1
  4. package/.claude/skills/workflow-commands/background-commands.md +36 -85
  5. package/.claude/skills/workflow-commands/backlogrun-progress.md +31 -34
  6. package/.claude/skills/workflow-commands/backlogrun-steps.md +2 -2
  7. package/.claude/skills/workflow-commands/delegation.md +5 -1
  8. package/.claude/skills/workflow-commands/fullrun.md +5 -4
  9. package/.claude/skills/workflow-commands/halfrun.md +5 -4
  10. package/.claude/skills/workflow-commands/latest-gate.md +7 -15
  11. package/.claude/skills/workflow-commands/pre-gate-cut.md +4 -8
  12. package/.claude/skills/workflow-commands/split-assessment.md +4 -18
  13. package/.github/actions/setup-node/action.yml +33 -0
  14. package/.github/actions/setup-pnpm/action.yml +4 -4
  15. package/.github/workflows/auto-tag.yml +2 -3
  16. package/.github/workflows/ci.yml +7 -8
  17. package/.github/workflows/dependabot-auto-merge.yml +1 -0
  18. package/.github/workflows/pr-classification.yml +1 -3
  19. package/.github/workflows/production.yml +1 -0
  20. package/.github/workflows/publish.yml +10 -9
  21. package/.github/workflows/sonar-qube.yml +17 -13
  22. package/.pnpmfile.mjs +29 -0
  23. package/AGENTS.md +4 -11
  24. package/CLAUDE.md +24 -17
  25. package/GEMINI.md +4 -13
  26. package/README.md +8 -3
  27. package/SECURITY.md +2 -0
  28. package/cspell/index.yaml +4 -0
  29. package/dist/CLAUDE.basic.md +6 -6
  30. package/dist/CLAUDE.md +24 -17
  31. package/dist/CLAUDE.static.md +6 -6
  32. package/dist/config-merge/index.js +33 -9
  33. package/dist/hooks/batch-guard.js +4 -4
  34. package/dist/hooks/{chunk-OIZUHPJI.js → chunk-FO2I7UT7.js} +1 -1
  35. package/dist/hooks/{chunk-NKOG3XAV.js → chunk-GDU26K3J.js} +11 -3
  36. package/dist/hooks/{chunk-O4LL4HTI.js → chunk-HANSKHES.js} +2 -2
  37. package/dist/hooks/{chunk-3C4YCCEF.js → chunk-HBKZLITF.js} +4 -4
  38. package/dist/hooks/{chunk-UD24EAIL.js → chunk-JKKTVDAG.js} +1984 -146
  39. package/dist/hooks/{chunk-M2XDCUKD.js → chunk-KBXZLMRH.js} +89 -1803
  40. package/dist/hooks/{chunk-IL27YTPH.js → chunk-KOKOAV6D.js} +2 -2
  41. package/dist/hooks/{chunk-7ZPFAVR7.js → chunk-LJBLGHEH.js} +59 -19
  42. package/dist/hooks/{chunk-E54KGFEQ.js → chunk-NFZGFGOR.js} +1 -1
  43. package/dist/hooks/{chunk-KHWHKJOM.js → chunk-RFWWUI5F.js} +4 -4
  44. package/dist/hooks/codex-hook-adapter.js +12 -47
  45. package/dist/hooks/duplicate-read-guard.js +5 -5
  46. package/dist/hooks/format-edited.js +2 -2
  47. package/dist/hooks/inputs.json +175 -173
  48. package/dist/hooks/investigation-guard.js +5 -5
  49. package/dist/hooks/pretool-guard.js +9 -9
  50. package/dist/hooks/stop-guard.js +17 -12
  51. package/dist/josh.js +87 -31
  52. package/dist/version/index.js +36 -20
  53. package/eslint/rules/unicorn.js +3 -2
  54. package/package.json +23 -5
  55. package/pnpm-workspace.yaml +5 -7
  56. package/prompts/collaboration-workflow/glossary.md +17 -0
  57. package/prompts/collaboration-workflow/issue-template.md +1 -1
  58. package/prompts/collaboration-workflow/operating-rules.md +1 -1
  59. package/prompts/collaboration-workflow/principles.md +9 -0
  60. package/prompts/collaboration-workflow.md +1 -0
  61. package/scripts/backlog/backlog-arrival.ts +30 -10
  62. package/scripts/backlog/backlog-budget-cli.ts +15 -16
  63. package/scripts/backlog/backlog-offer-cli.ts +6 -14
  64. package/scripts/backlog/backlog-plan.ts +29 -18
  65. package/scripts/backlog/backlog-ready.ts +20 -7
  66. package/scripts/config-merge/parse-jsonc.ts +33 -3
  67. package/scripts/config-merge/patch-json-key.ts +13 -6
  68. package/scripts/cost-runtime/cost-cli.ts +3 -7
  69. package/scripts/delegation/delegation-policy.ts +9 -1
  70. package/scripts/delegation/investigation-guard.ts +1 -1
  71. package/scripts/delegation/investigation-reads.ts +105 -19
  72. package/scripts/doctor/doctor-consumer.ts +3 -5
  73. package/scripts/doctor/doctor-io.ts +9 -13
  74. package/scripts/document/backlogrun-parent-read-set.ts +12 -1
  75. package/scripts/document/capped-print.ts +74 -0
  76. package/scripts/document/document-byte-budget.ts +1 -0
  77. package/scripts/document/document-section-cli.ts +4 -3
  78. package/scripts/document/entry-read-budget.ts +13 -7
  79. package/scripts/document/entry-read-set.ts +32 -8
  80. package/scripts/document/lane-child-read-set.ts +7 -0
  81. package/scripts/document/read-set-point-of-use.ts +8 -3
  82. package/scripts/document/read-set-trim.ts +3 -1
  83. package/scripts/epic/epic-audit.ts +3 -18
  84. package/scripts/gate/scoped-green.ts +25 -14
  85. package/scripts/gh/git-gh-issue-list.ts +12 -11
  86. package/scripts/gh/git-gh-issue-write.ts +4 -1
  87. package/scripts/gh/git-gh-pr-auto-merge.ts +4 -1
  88. package/scripts/git/git-command.ts +6 -1
  89. package/scripts/git/git-spawn-sync.ts +65 -0
  90. package/scripts/git/git-spawn.ts +5 -4
  91. package/scripts/git/stash/stash-pop-args.ts +1 -6
  92. package/scripts/init/claude-kit-only-settings.ts +29 -0
  93. package/scripts/init/init-copy-content.ts +8 -2
  94. package/scripts/init/init-file-action.ts +54 -0
  95. package/scripts/init/init-logic-migrate.ts +35 -17
  96. package/scripts/init/init-logic-secretlint.ts +1 -1
  97. package/scripts/init/init-logic.ts +6 -22
  98. package/scripts/init/init.ts +11 -68
  99. package/scripts/init/initial-commit.ts +24 -0
  100. package/scripts/init/kit-written-paths.ts +2 -0
  101. package/scripts/init/project-profile.ts +3 -6
  102. package/scripts/init/start-exec.ts +16 -3
  103. package/scripts/init/start-steps.ts +10 -13
  104. package/scripts/issue/defect-rate-cli.ts +61 -20
  105. package/scripts/issue/issue-backlinks.ts +7 -14
  106. package/scripts/issue/issue-cite.ts +12 -6
  107. package/scripts/issue/issue-file.ts +5 -12
  108. package/scripts/issue/issue-read-cli.ts +1 -0
  109. package/scripts/issue/issue-report-failures.ts +6 -2
  110. package/scripts/issue/issue-state-cli.ts +1 -1
  111. package/scripts/issue/markdown-section.ts +21 -6
  112. package/scripts/issue/measure-rerun-cli.ts +73 -14
  113. package/scripts/josh/josh-commands-lane.ts +1 -1
  114. package/scripts/josh/josh-commands-project.ts +8 -1
  115. package/scripts/josh/josh-commands-workflow.ts +1 -1
  116. package/scripts/josh/run-github-prerequisite.ts +3 -6
  117. package/scripts/lane/lane-await.ts +89 -15
  118. package/scripts/lane/lane-cli.ts +11 -13
  119. package/scripts/lane/lane-close.ts +4 -1
  120. package/scripts/lane/lane-launch-cli.ts +10 -16
  121. package/scripts/lane/openai-review-broker.ts +4 -1
  122. package/scripts/lib/cli-flags.ts +31 -2
  123. package/scripts/lib/error-message.ts +12 -1
  124. package/scripts/lines/line-targets.ts +0 -11
  125. package/scripts/lines/lines-command.ts +5 -3
  126. package/scripts/propagate/propagate-git.ts +3 -8
  127. package/scripts/refactor/refactor-scan.ts +2 -1
  128. package/scripts/registry-migration/migrate-logic.ts +28 -19
  129. package/scripts/registry-migration/migrate.ts +6 -5
  130. package/scripts/release/github-release-cli.ts +14 -3
  131. package/scripts/release/github-release-environment.ts +1 -0
  132. package/scripts/release/github-release.ts +103 -17
  133. package/scripts/release/release-publish.ts +36 -2
  134. package/scripts/release/release-worktree.ts +97 -2
  135. package/scripts/review/review-checkout.ts +3 -2
  136. package/scripts/review/review-record-cli.ts +9 -16
  137. package/scripts/rules/early-heartbeat.ts +4 -3
  138. package/scripts/rules/lane-park.ts +9 -0
  139. package/scripts/rules/stop-rules.ts +7 -4
  140. package/scripts/run/run-carry-args.ts +8 -12
  141. package/scripts/run/run-carry-cli.ts +3 -1
  142. package/scripts/run/run-carry-conversation.ts +94 -0
  143. package/scripts/run/run-carry-reclaim.ts +37 -0
  144. package/scripts/run/run-carry.ts +21 -5
  145. package/scripts/run/run-cut-args.ts +1 -6
  146. package/scripts/run/run-ending-cli.ts +1 -5
  147. package/scripts/run/run-entry-cli.ts +40 -9
  148. package/scripts/run/run-entry-stop.ts +104 -0
  149. package/scripts/run/run-event-stream-emit.ts +7 -2
  150. package/scripts/run/run-hold.ts +4 -1
  151. package/scripts/run/run-liveness-cli.ts +1 -5
  152. package/scripts/run/run-merge-cli.ts +2 -10
  153. package/scripts/run/run-merge-steps.ts +4 -1
  154. package/scripts/run/run-parent-cut-hook.ts +4 -1
  155. package/scripts/run/run-prep-cli.ts +4 -1
  156. package/scripts/run/run-progress-args.ts +20 -4
  157. package/scripts/run/run-progress-cli.ts +31 -29
  158. package/scripts/run/run-progress-clock.ts +4 -1
  159. package/scripts/run/run-ship-cli.ts +8 -16
  160. package/scripts/run/run-ship-probe.ts +4 -1
  161. package/scripts/run/run-status-cli.ts +2 -15
  162. package/scripts/run/run-tidy-lanes.ts +4 -1
  163. package/scripts/run/run-wake-cli.ts +2 -10
  164. package/scripts/run/run-watcher-guard.ts +9 -5
  165. package/scripts/safe-chain/pack-hook.ts +92 -0
  166. package/scripts/sync/sync-ai-files.ts +4 -0
  167. package/scripts/test/test-declared-changed.ts +13 -16
  168. package/scripts/test/test-declared.ts +3 -7
  169. package/scripts/test/test-related.ts +1 -6
  170. package/scripts/test/test-unit-guard.ts +21 -7
  171. package/scripts/time-runtime/time-spans.ts +4 -0
  172. package/scripts/version/version-commands.ts +11 -1
  173. package/templates/CLAUDE.basic.md +6 -6
  174. package/templates/workflows/ci.yml +16 -82
  175. package/templates/workflows/dependabot-auto-merge.yml +1 -0
  176. package/templates/workflows/github-release.yml +14 -28
  177. package/tsconfig.sonar.json +4 -22
@@ -1,8 +1,8 @@
1
1
  #!/usr/bin/env tsx
2
2
  import { text } from 'node:stream/consumers'
3
3
  import { fileURLToPath } from 'node:url'
4
- import { parseArgs } from 'node:util'
5
4
  import { project_checks } from '#scripts/gate/project-checks'
5
+ import { cli_flags } from '#scripts/lib/cli-flags'
6
6
  import { test_declared_changed } from './test-declared-changed'
7
7
  import { test_declared_logic, type Verdict } from './test-declared-logic'
8
8
  import { test_declared_match, type MatchResult } from './test-declared-match'
@@ -55,13 +55,9 @@ interface Options {
55
55
  // The parsed flags, or `undefined` when an unknown one was passed — the strict parse is what turns a
56
56
  // typo into a refusal rather than a silent re-print of the verdict.
57
57
  function parse(argv: ReadonlyArray<string>): Options | undefined {
58
- try {
59
- const { values } = parseArgs({ args: [...argv], options: PARSE_ARGS_OPTIONS, strict: true })
58
+ const values = cli_flags.values_of(argv, PARSE_ARGS_OPTIONS)
60
59
 
61
- return { is_help: values.help, is_match: values.match }
62
- } catch {
63
- return undefined
64
- }
60
+ return values === undefined ? undefined : { is_help: values.help, is_match: values.match }
65
61
  }
66
62
 
67
63
  // The next command a verdict leaves to run, or `undefined` when there is nothing to do next. Only
@@ -26,12 +26,7 @@ import { test_unit_guard } from './test-unit-guard'
26
26
  function conclusive_tree(before: GateTree | undefined): GateTree | undefined {
27
27
  if (before === undefined) return undefined
28
28
 
29
- const action = test_unit_guard.resolve_guard_action(
30
- test_unit_guard.is_vitest_installed(process.cwd()),
31
- test_unit_guard.has_unit_tests(process.cwd()),
32
- )
33
-
34
- return action === 'run' ? before : undefined
29
+ return test_unit_guard.guard_action(process.cwd()) === 'run' ? before : undefined
35
30
  }
36
31
 
37
32
  async function run_related_tests(command_arguments: ReadonlyArray<string>): Promise<number> {
@@ -79,6 +79,24 @@ function has_unit_tests(project_directory: string): boolean {
79
79
  return matches.length > 0
80
80
  }
81
81
 
82
+ // The guard's decision for one project, asked here once so the run, the scoped record and the gate's
83
+ // precondition can never disagree about whether this project's vitest runs (joshuafolkken/kit#3136).
84
+ function guard_action(project_directory: string): GuardAction {
85
+ return resolve_guard_action(
86
+ is_vitest_installed(project_directory),
87
+ has_unit_tests(project_directory),
88
+ project_checks.is_basic(project_directory),
89
+ )
90
+ }
91
+
92
+ // **A skip is the project having no unit suite, so no unit check can ever vouch for its tree.** The
93
+ // failing branch is not one: it is a broken suite, and it is left to fail where it is reported.
94
+ function is_skipping(project_directory: string): boolean {
95
+ const action = guard_action(project_directory)
96
+
97
+ return action === SKIP_ACTION || action === SKIP_NO_TESTS_ACTION
98
+ }
99
+
82
100
  // A lane's port allocation belongs to its development and preview servers, not to unit fixtures.
83
101
  // Passing it into Vitest makes every case that deliberately omits or replaces the seed inherit the
84
102
  // checkout's seat instead. Keep the rest of the caller's environment, including CI and PATH guards.
@@ -155,13 +173,7 @@ async function run_guarded_vitest(
155
173
  command_label: string = UNIT_COMMAND_LABEL,
156
174
  announcement?: string,
157
175
  ): Promise<number> {
158
- const is_installed = is_vitest_installed(project_directory)
159
- const has_tests = has_unit_tests(project_directory)
160
- const action = resolve_guard_action(
161
- is_installed,
162
- has_tests,
163
- project_checks.is_basic(project_directory),
164
- )
176
+ const action = guard_action(project_directory)
165
177
 
166
178
  if (action !== 'run') return report_no_run(action, command_label)
167
179
  if (announcement !== undefined) process.stdout.write(`${announcement}\n`)
@@ -185,6 +197,8 @@ if (process.argv[1] === fileURLToPath(import.meta.url)) {
185
197
 
186
198
  const test_unit_guard = {
187
199
  SKIP_MARKER,
200
+ guard_action,
201
+ is_skipping,
188
202
  resolve_guard_action,
189
203
  is_vitest_installed,
190
204
  has_unit_tests,
@@ -138,6 +138,9 @@ interface ToolCall {
138
138
  // second write to one file is independent work, a read of a file just written is not
139
139
  // (joshuafolkken/kit#1509).
140
140
  is_writing: boolean
141
+ // The conservative write answer `is_read_only_call` asks of a live call, carried so a reader of the
142
+ // transcript asks the same read-only question as the guard (joshuafolkken/kit#3139).
143
+ may_write: boolean
141
144
  // Whether this is a subagent launch whose prompt builds on an earlier launch's finding
142
145
  // (joshuafolkken/kit#1854). Carried for the reason every field here is — the prompt it is read from
143
146
  // is the input, and a span keeps none. `time-agent-bundles.ts` reads it.
@@ -474,6 +477,7 @@ function to_spans(events: ReadonlyArray<TimelineEvent>, finished: FinishedAt): A
474
477
  is_bundleable: event.is_bundleable,
475
478
  targets: event.targets,
476
479
  is_writing: event.is_writing,
480
+ may_write: event.may_write,
477
481
  has_prior_reference: event.has_prior_reference,
478
482
  writes: event.writes,
479
483
  message_id: event.message_id,
@@ -24,6 +24,8 @@ import { version_targets } from './version-targets'
24
24
  const FAILURE_EXIT_CODE = 1
25
25
  const ALREADY_UP_TO_DATE = 'Already up to date'
26
26
  const NO_QUARANTINE_MINUTES = 0
27
+ // A global install that goes to the network — the same ten minutes `lane-install.ts` gives one.
28
+ const UPGRADE_TIMEOUT_MS = 600_000
27
29
 
28
30
  // What the local minimum-release-age policy permits for one package. Resolved per package because
29
31
  // the newest installable release is a property of that package's own publish history. Returns a hold
@@ -195,8 +197,16 @@ function run_check(config: VersionCommandConfig): void {
195
197
  )
196
198
  }
197
199
 
200
+ // Through `sh -c` because an upgrade command is the user's own configured string — `pnpm add -g …`,
201
+ // or a chain with `&&` — so it is inside the trust boundary and needs a shell to mean what it says.
202
+ // The bound keeps a registry that never answers from holding `josh version` open forever; a timed-out
203
+ // run has no exit code, so it falls through to the failure code like any other failed step.
198
204
  function run_upgrade_command(command: string): number {
199
- const result = execaSync('sh', ['-c', command], { stdio: 'inherit', reject: false })
205
+ const result = execaSync('sh', ['-c', command], {
206
+ stdio: 'inherit',
207
+ reject: false,
208
+ timeout: UPGRADE_TIMEOUT_MS,
209
+ })
200
210
 
201
211
  return result.exitCode ?? FAILURE_EXIT_CODE
202
212
  }
@@ -1,8 +1,8 @@
1
1
  # Project instructions
2
2
 
3
- - 既存のファイルと利用者の設定を尊重し、変更する前に内容を確認する。
4
- - 変更には検証を付け、実行した結果を報告する。
5
- - HTML、CSS、JavaScript のファイルがある場合は Prettier で整形する。
6
- - 画面に見える変更をした場合はブラウザーで表示と操作を確認する。
7
- - JavaScript または TypeScript の動作を変更した場合は、その動作を確認する自動テストを追加する。
8
- - Git や GitHub を使う場合だけ、それぞれのワークフローを利用する。
3
+ - Respect existing files and the user's settings, and read a file's contents before changing it.
4
+ - Verify every change, and report the results you actually observed.
5
+ - Format HTML, CSS and JavaScript files with Prettier when the project has any.
6
+ - After a change that is visible on screen, check its display and interaction in a browser.
7
+ - After changing JavaScript or TypeScript behavior, add an automated test that checks that behavior.
8
+ - Use the Git or GitHub workflow only when you use Git or GitHub.
@@ -29,12 +29,11 @@ concurrency:
29
29
  # list (e.g. `chromium firefox webkit`) instead of editing this file, which josh sync overwrites.
30
30
  env:
31
31
  JOSH_PLAYWRIGHT_BROWSERS: ${{ vars.JOSH_PLAYWRIGHT_BROWSERS || 'chromium' }}
32
- # The safe-chain release every "Setup safe-chain" step installs, and the SHA-256 of that release's
33
- # install-safe-chain.sh. The installer puts the safe-chain binary under ~/.safe-chain/bin and
34
- # adds it to PATH beside the shims; `pnpm dlx … setup-ci` left only the shims, which then let
35
- # every install through without a scan (joshuafolkken/kit#2711). `josh latest` moves both together.
36
- SAFE_CHAIN_INSTALLER_VERSION: 1.5.20
37
- SAFE_CHAIN_INSTALLER_SHA256: 0ad25efe15d1fa56105157a454d647223e78eb0c53d1f85e3d10afcd722e7bfd
32
+
33
+ # Every job that needs pnpm prepares it through `.github/actions/setup-pnpm`, which `josh sync`
34
+ # writes beside this file: the pnpm version resolution, the store cache, the hash-verified safe-chain
35
+ # installer and the install. kit's own `ci.yml` calls the same action, so the path a consumer runs is
36
+ # the path kit runs (joshuafolkken/kit#3095).
38
37
 
39
38
  jobs:
40
39
  playwright-image:
@@ -126,37 +125,11 @@ jobs:
126
125
  persist-credentials: false
127
126
 
128
127
  - name: Setup Node.js
129
- uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
130
- with:
131
- node-version: '24'
128
+ uses: ./.github/actions/setup-node
132
129
 
133
130
  - name: Configure GitHub Packages authentication for existing projects
134
131
  run: printf '//npm.pkg.github.com/:_authToken=${NODE_AUTH_TOKEN}\n' >> "$HOME/.npmrc"
135
132
 
136
- - name: Resolve pnpm version
137
- id: pnpm-version
138
- run: |
139
- 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'")
140
- test -n "$version"
141
- echo "version=$version" >> "$GITHUB_OUTPUT"
142
-
143
- - name: Setup pnpm
144
- uses: pnpm/setup@fbda4c85fc2e1e08721cd8763afea8f48d60f024 # v3.0.0
145
- with:
146
- version: ${{ steps.pnpm-version.outputs.version }}
147
- install: false
148
-
149
- - name: Resolve pnpm store path
150
- run: echo "PNPM_STORE_PATH=$(pnpm store path)" >> "$GITHUB_ENV"
151
-
152
- - name: Setup pnpm store cache
153
- uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
154
- with:
155
- path: ${{ env.PNPM_STORE_PATH }}
156
- key: ${{ runner.os }}-pnpm-store-${{ hashFiles('pnpm-lock.yaml') }}
157
- restore-keys: |
158
- ${{ runner.os }}-pnpm-store-
159
-
160
133
  - name: Setup ESLint cache
161
134
  uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
162
135
  id: eslint-cache
@@ -188,17 +161,10 @@ jobs:
188
161
  ${{ runner.os }}-cspell-cache-${{ hashFiles('pnpm-lock.yaml') }}-
189
162
  ${{ runner.os }}-cspell-cache-
190
163
 
191
- - name: Setup safe-chain
192
- run: |
193
- installer="$RUNNER_TEMP/install-safe-chain.sh"
194
- curl --proto '=https' -fsSL "https://github.com/AikidoSec/safe-chain/releases/download/$SAFE_CHAIN_INSTALLER_VERSION/install-safe-chain.sh" -o "$installer"
195
- echo "$SAFE_CHAIN_INSTALLER_SHA256 $installer" | sha256sum -c -
196
- sh "$installer" --ci
197
-
198
- - name: Install dependencies
199
- env:
200
- NODE_AUTH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
201
- run: pnpm install --frozen-lockfile --ignore-scripts
164
+ - name: Setup pnpm and install dependencies
165
+ uses: ./.github/actions/setup-pnpm
166
+ with:
167
+ node-auth-token: ${{ secrets.GITHUB_TOKEN }}
202
168
 
203
169
  # A `basic` project has no `prepare`, no build and no SvelteKit, so the ordered steps below
204
170
  # would fail on its first pull request (joshuafolkken/kit#2814). The profile is read from
@@ -399,37 +365,11 @@ jobs:
399
365
  persist-credentials: false
400
366
 
401
367
  - name: Setup Node.js
402
- uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
403
- with:
404
- node-version: '24'
368
+ uses: ./.github/actions/setup-node
405
369
 
406
370
  - name: Configure GitHub Packages authentication for existing projects
407
371
  run: printf '//npm.pkg.github.com/:_authToken=${NODE_AUTH_TOKEN}\n' >> "$HOME/.npmrc"
408
372
 
409
- - name: Resolve pnpm version
410
- id: pnpm-version
411
- run: |
412
- 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'")
413
- test -n "$version"
414
- echo "version=$version" >> "$GITHUB_OUTPUT"
415
-
416
- - name: Setup pnpm
417
- uses: pnpm/setup@fbda4c85fc2e1e08721cd8763afea8f48d60f024 # v3.0.0
418
- with:
419
- version: ${{ steps.pnpm-version.outputs.version }}
420
- install: false
421
-
422
- - name: Resolve pnpm store path
423
- run: echo "PNPM_STORE_PATH=$(pnpm store path)" >> "$GITHUB_ENV"
424
-
425
- - name: Setup pnpm store cache
426
- uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
427
- with:
428
- path: ${{ env.PNPM_STORE_PATH }}
429
- key: ${{ runner.os }}-pnpm-store-${{ hashFiles('pnpm-lock.yaml') }}
430
- restore-keys: |
431
- ${{ runner.os }}-pnpm-store-
432
-
433
373
  - name: Setup build cache
434
374
  uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
435
375
  id: build-cache
@@ -441,17 +381,10 @@ jobs:
441
381
  ${{ runner.os }}-build-cache-e2e-${{ hashFiles('pnpm-lock.yaml') }}-
442
382
  ${{ runner.os }}-build-cache-e2e-
443
383
 
444
- - name: Setup safe-chain
445
- run: |
446
- installer="$RUNNER_TEMP/install-safe-chain.sh"
447
- curl --proto '=https' -fsSL "https://github.com/AikidoSec/safe-chain/releases/download/$SAFE_CHAIN_INSTALLER_VERSION/install-safe-chain.sh" -o "$installer"
448
- echo "$SAFE_CHAIN_INSTALLER_SHA256 $installer" | sha256sum -c -
449
- sh "$installer" --ci
450
-
451
- - name: Install dependencies
452
- env:
453
- NODE_AUTH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
454
- run: pnpm install --frozen-lockfile --ignore-scripts
384
+ - name: Setup pnpm and install dependencies
385
+ uses: ./.github/actions/setup-pnpm
386
+ with:
387
+ node-auth-token: ${{ secrets.GITHUB_TOKEN }}
455
388
 
456
389
  # --ignore-scripts suppresses the install-time `prepare`, so generated framework
457
390
  # files never appear. Playwright >= 1.62 hard-throws when a tsconfig `extends`
@@ -679,6 +612,7 @@ jobs:
679
612
  needs.e2e-detect.result == 'success' &&
680
613
  (needs.e2e.result == 'success' || needs.e2e.result == 'skipped')
681
614
  runs-on: ubuntu-latest
615
+ timeout-minutes: 5
682
616
  permissions:
683
617
  contents: write
684
618
  steps:
@@ -27,6 +27,7 @@ jobs:
27
27
  # what stays restricted to Dependabot's own events, on the step below.
28
28
  auto-merge:
29
29
  runs-on: ubuntu-latest
30
+ timeout-minutes: 10
30
31
  if: github.event.pull_request.user.login == 'dependabot[bot]'
31
32
  steps:
32
33
  # Whether the pull request touches a workflow some upstream package overwrites. Decided from
@@ -1,14 +1,13 @@
1
1
  name: GitHub Release
2
2
 
3
3
  # Creates the GitHub Release, with notes generated from `.github/release.yml`, for each tag
4
- # `josh release` cuts (joshuafolkken/kit#3007). A repository with a Publish workflow gets its release
5
- # once that workflow has succeeded for the tag; one without it gets the release when auto-tag.yml
6
- # announces the tag. kit's own release is the `create-release` job of its publish.yml, which runs the
7
- # same `josh release:github`, so this file is distributed but never runs in kit.
4
+ # `josh release` cuts (joshuafolkken/kit#3007). It starts when auto-tag.yml announces the tag; a
5
+ # repository with a Publish workflow gets its release once that workflow has succeeded for the tag,
6
+ # waited for inside `josh release:github`. A `workflow_run` on Publish is not used: a Publish run
7
+ # started by the GITHUB_TOKEN never fires one (joshuafolkken/kit#3138). kit's own release is the
8
+ # `create-release` job of its publish.yml, which runs the same `josh release:github`, so this file is
9
+ # distributed but never runs in kit.
8
10
  on:
9
- workflow_run:
10
- workflows: [Publish]
11
- types: [completed]
12
11
  repository_dispatch:
13
12
  types: [new-tag-created]
14
13
 
@@ -17,12 +16,6 @@ on:
17
16
 
18
17
  jobs:
19
18
  release:
20
- # The Publish run is titled `Publish <tag>`; its head branch is not the tag when it was started by
21
- # repository_dispatch, so the title is where the tag is read from.
22
- if: >-
23
- (github.event_name == 'workflow_run' && github.event.workflow_run.conclusion == 'success' &&
24
- startsWith(github.event.workflow_run.display_title, 'Publish v')) ||
25
- github.event_name == 'repository_dispatch'
26
19
  runs-on: ubuntu-latest
27
20
  timeout-minutes: 65
28
21
  permissions:
@@ -36,30 +29,22 @@ jobs:
36
29
  fetch-depth: 0
37
30
  persist-credentials: false
38
31
 
39
- # A repository with a Publish workflow is released from the workflow_run above, after its
40
- # publication, so the tag announcement is left alone there and one tag never starts two releases.
32
+ # A repository with a Publish workflow waits for that workflow's `Publish <tag>` run to succeed
33
+ # before releasing; the announcement is the only trigger, so one tag never starts two releases.
41
34
  - name: Select release tag
42
35
  id: release
43
36
  env:
44
- EVENT_NAME: ${{ github.event_name }}
45
- RUN_TITLE: ${{ github.event.workflow_run.display_title }}
46
- RUN_WORKFLOW: ${{ github.event.workflow_run.workflow_id }}
47
37
  DISPATCH_TAG: ${{ github.event.client_payload.tag }}
48
38
  run: |
49
- if [ "$EVENT_NAME" = workflow_run ]; then
50
- echo "tag=${RUN_TITLE#Publish }" >> "$GITHUB_OUTPUT"
51
- echo "workflow=$RUN_WORKFLOW" >> "$GITHUB_OUTPUT"
52
- elif [ -f .github/workflows/publish.yml ]; then
53
- echo "ℹ️ publish.yml releases this tag once it has published, skipping"
54
- else
55
- echo "tag=$DISPATCH_TAG" >> "$GITHUB_OUTPUT"
39
+ echo "tag=$DISPATCH_TAG" >> "$GITHUB_OUTPUT"
40
+ if [ -f .github/workflows/publish.yml ]; then
41
+ echo "workflow=publish.yml" >> "$GITHUB_OUTPUT"
42
+ echo "await=true" >> "$GITHUB_OUTPUT"
56
43
  fi
57
44
 
58
45
  - name: Setup Node.js
59
46
  if: steps.release.outputs.tag != ''
60
- uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
61
- with:
62
- node-version: '24'
47
+ uses: ./.github/actions/setup-node
63
48
 
64
49
  - name: Configure GitHub Packages authentication for existing projects
65
50
  if: steps.release.outputs.tag != ''
@@ -79,3 +64,4 @@ jobs:
79
64
  GH_TOKEN: ${{ github.token }}
80
65
  RELEASE_TAG: ${{ steps.release.outputs.tag }}
81
66
  RELEASE_WORKFLOW: ${{ steps.release.outputs.workflow }}
67
+ RELEASE_AWAIT_PUBLISH: ${{ steps.release.outputs.await }}
@@ -1,29 +1,11 @@
1
1
  {
2
+ "extends": "@joshuafolkken/kit/tsconfig/base",
2
3
  "compilerOptions": {
3
- "target": "ES2020",
4
- "module": "ES2020",
5
- "lib": ["ES2020", "DOM", "DOM.Iterable"],
6
- "moduleResolution": "node",
7
- "allowImportingTsExtensions": false,
4
+ "target": "ES2022",
5
+ "lib": ["ES2023", "DOM", "DOM.Iterable"],
6
+ "types": ["node"],
8
7
  "allowJs": true,
9
8
  "checkJs": true,
10
- "esModuleInterop": true,
11
- "forceConsistentCasingInFileNames": true,
12
- "resolveJsonModule": true,
13
- "skipLibCheck": true,
14
- "sourceMap": true,
15
- "strict": true,
16
- "noUncheckedIndexedAccess": true,
17
- "noImplicitOverride": true,
18
- "noUnusedLocals": true,
19
- "noUnusedParameters": true,
20
- "exactOptionalPropertyTypes": true,
21
- "noFallthroughCasesInSwitch": true,
22
- "noImplicitReturns": true,
23
- "noPropertyAccessFromIndexSignature": true,
24
- "allowUnusedLabels": false,
25
- "allowUnreachableCode": false,
26
- "isolatedModules": true,
27
9
  "paths": {
28
10
  "$lib": ["./src/lib"],
29
11
  "$lib/*": ["./src/lib/*"]