@joshuafolkken/kit 1.1453.0 → 1.1471.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 (224) hide show
  1. package/.claude/skills/dependency-update/SKILL.md +26 -55
  2. package/.claude/skills/epic-commands/SKILL.md +87 -148
  3. package/.claude/skills/epic-commands/epic-bundle.md +45 -77
  4. package/.claude/skills/epic-commands/execution-waves.md +44 -81
  5. package/.claude/skills/verify-ui/SKILL.md +25 -50
  6. package/.claude/skills/workflow-commands/background-commands.md +36 -47
  7. package/.claude/skills/workflow-commands/backlogrun-child.md +72 -85
  8. package/.claude/skills/workflow-commands/backlogrun-handoff-report.md +1 -1
  9. package/.claude/skills/workflow-commands/backlogrun-lanes.md +91 -121
  10. package/.claude/skills/workflow-commands/backlogrun-park.md +73 -117
  11. package/.claude/skills/workflow-commands/backlogrun-progress.md +7 -9
  12. package/.claude/skills/workflow-commands/backlogrun-recovery.md +11 -20
  13. package/.claude/skills/workflow-commands/backlogrun-steps.md +43 -52
  14. package/.claude/skills/workflow-commands/chain-rule.md +24 -34
  15. package/.claude/skills/workflow-commands/followup.md +57 -76
  16. package/.claude/skills/workflow-commands/halfrun.md +2 -1
  17. package/.claude/skills/workflow-commands/issue-comments.md +43 -60
  18. package/.claude/skills/workflow-commands/kickoff.md +65 -74
  19. package/.claude/skills/workflow-commands/observation-filing.md +62 -107
  20. package/.claude/skills/workflow-commands/observation-ledger.md +56 -111
  21. package/.claude/skills/workflow-commands/pre-gate-cut.md +89 -138
  22. package/.claude/skills/workflow-commands/prerequisite.md +10 -15
  23. package/.claude/skills/workflow-commands/progress-watcher.md +21 -26
  24. package/.claude/skills/workflow-commands/prrun.md +2 -1
  25. package/.claude/skills/workflow-commands/retrospective.md +31 -50
  26. package/.claude/skills/workflow-commands/split-assessment.md +34 -58
  27. package/.claude/skills/workflow-commands/working-tree-hold.md +54 -71
  28. package/CLAUDE.md +7 -6
  29. package/README.md +2 -9
  30. package/dist/CLAUDE.md +7 -6
  31. package/dist/hooks/batch-guard.js +6 -6
  32. package/dist/hooks/{chunk-Y3GKIKGW.js → chunk-43ZHT22P.js} +31 -15
  33. package/dist/hooks/{chunk-MBJYQPEK.js → chunk-AS74OU3D.js} +24 -8
  34. package/dist/hooks/{chunk-3C4XRYG6.js → chunk-E7OIKX5Z.js} +17 -12
  35. package/dist/hooks/{chunk-Z4XI7CZS.js → chunk-EUMACUK2.js} +18 -12
  36. package/dist/hooks/{chunk-NO4AALP5.js → chunk-H5HVWYXK.js} +4 -4
  37. package/dist/hooks/{chunk-5C7L6FRC.js → chunk-IIGFYXKC.js} +346 -241
  38. package/dist/hooks/{chunk-W5ZKGTSY.js → chunk-J47HU5H5.js} +14 -3
  39. package/dist/hooks/{chunk-OLMO72ON.js → chunk-K4EOONYM.js} +1 -1
  40. package/dist/hooks/{chunk-LBFYEOXJ.js → chunk-K4LMBQC2.js} +4 -4
  41. package/dist/hooks/{chunk-D3NJXN5M.js → chunk-KC5AK2GF.js} +8 -6
  42. package/dist/hooks/chunk-SHGPANFB.js +56 -0
  43. package/dist/hooks/{chunk-EF5GQ6WS.js → chunk-YHBZAJSV.js} +3 -3
  44. package/dist/hooks/{chunk-SHYUQOIS.js → chunk-YYPI7SJZ.js} +5 -5
  45. package/dist/hooks/codex-hook-adapter.js +13 -13
  46. package/dist/hooks/duplicate-read-guard.js +7 -7
  47. package/dist/hooks/format-edited.js +3 -3
  48. package/dist/hooks/inputs.json +251 -247
  49. package/dist/hooks/investigation-guard.js +7 -7
  50. package/dist/hooks/pretool-guard.js +12 -12
  51. package/dist/hooks/session-lang.js +6 -5
  52. package/dist/hooks/stop-guard.js +75 -18
  53. package/dist/josh.js +6 -7
  54. package/dist/managed-marker/index.js +1 -2
  55. package/dist/version/index.js +15 -12
  56. package/eslint/base.js +2 -1
  57. package/eslint/rules/unicorn.js +16 -0
  58. package/package.json +3 -3
  59. package/prompts/coding-standards.md +12 -22
  60. package/prompts/collaboration-workflow/file-edits.md +26 -44
  61. package/prompts/collaboration-workflow/gh-rest.md +20 -36
  62. package/prompts/collaboration-workflow/glossary.md +5 -7
  63. package/prompts/collaboration-workflow/issue-citation.md +7 -13
  64. package/prompts/collaboration-workflow/issue-template.md +29 -29
  65. package/prompts/collaboration-workflow/operating-rules.md +35 -44
  66. package/prompts/collaboration-workflow/output-bounds.md +15 -15
  67. package/prompts/collaboration-workflow/overview.md +14 -19
  68. package/prompts/collaboration-workflow/plan-comment.md +13 -13
  69. package/prompts/collaboration-workflow/principles.md +50 -53
  70. package/prompts/collaboration-workflow/proposal-request.md +1 -9
  71. package/prompts/collaboration-workflow/report-format.md +32 -49
  72. package/prompts/collaboration-workflow/residency.md +10 -10
  73. package/prompts/collaboration-workflow/rule-delivery.md +9 -9
  74. package/prompts/collaboration-workflow/shell-body.md +11 -21
  75. package/prompts/collaboration-workflow/turn-batching.md +8 -14
  76. package/prompts/collaboration-workflow/upstream-interrupt.md +26 -34
  77. package/prompts/collaboration-workflow/wip-cap.md +24 -30
  78. package/prompts/collaboration-workflow.md +24 -25
  79. package/prompts/refactoring.md +33 -43
  80. package/prompts/review-rubric.md +84 -129
  81. package/prompts/review.md +111 -141
  82. package/prompts/sonar-hotspot-handling.md +22 -50
  83. package/prompts/testing-guide.md +48 -99
  84. package/scripts/adopt/adopt-toolkits.ts +2 -4
  85. package/scripts/agent/agent-exit-record.ts +23 -1
  86. package/scripts/agent/codex-agent-argv.ts +7 -2
  87. package/scripts/backlog/backlog-budget-cli.ts +1 -2
  88. package/scripts/backlog/backlog-drive-carried.ts +26 -0
  89. package/scripts/backlog/backlog-drive-cli.ts +10 -5
  90. package/scripts/backlog/backlog-drive-named.ts +2 -4
  91. package/scripts/backlog/backlog-drive-restore.ts +19 -1
  92. package/scripts/backlog/backlog-drive-seats.ts +27 -0
  93. package/scripts/backlog/backlog-drive.ts +11 -6
  94. package/scripts/backlog/backlog-ready.ts +13 -6
  95. package/scripts/behavior/behavior-rules.ts +3 -2
  96. package/scripts/cost-runtime/codex-usage.ts +4 -2
  97. package/scripts/cost-runtime/cost-cli.ts +1 -2
  98. package/scripts/delegation/investigation-guard.ts +1 -1
  99. package/scripts/delegation/investigation-reads.ts +1 -1
  100. package/scripts/discovery/repo-discovery.ts +4 -2
  101. package/scripts/discovery/repo-origin.ts +2 -4
  102. package/scripts/doctor/doctor-logic.ts +6 -3
  103. package/scripts/document/document-byte-budget.ts +27 -27
  104. package/scripts/document/document-byte-check.ts +1 -2
  105. package/scripts/document/entry-read-budget.ts +2 -2
  106. package/scripts/epic/epic-audit-rationale.ts +8 -2
  107. package/scripts/epic/epic-bundle-cli.ts +1 -2
  108. package/scripts/epic/epic-chains.ts +6 -2
  109. package/scripts/epic/epic-close-comment.ts +1 -2
  110. package/scripts/gate/verification-gate.ts +7 -2
  111. package/scripts/gh/git-pr-ai-review.ts +12 -1
  112. package/scripts/gh/git-pr-confirmation.ts +11 -7
  113. package/scripts/gh/git-pr.ts +6 -2
  114. package/scripts/git/git-common-directory.ts +3 -3
  115. package/scripts/git/git-diff-reads.ts +16 -9
  116. package/scripts/git/git-execa-error.ts +1 -2
  117. package/scripts/hooks/format-edited-file.ts +10 -4
  118. package/scripts/hooks/pre-push-unit.ts +15 -4
  119. package/scripts/hooks/pretool-guard.ts +23 -29
  120. package/scripts/hooks/step-zero-notice.ts +3 -2
  121. package/scripts/init/hook-command-rewrite.ts +6 -2
  122. package/scripts/init/init-logic-deploy-vps.ts +4 -2
  123. package/scripts/issue/behavior-change-lint.ts +12 -6
  124. package/scripts/issue/issue-scout-cli.ts +3 -2
  125. package/scripts/josh/file-map-stamp.ts +1 -3
  126. package/scripts/josh/hook-decision.ts +17 -2
  127. package/scripts/josh/josh-commands-workflow.ts +1 -1
  128. package/scripts/lane/lane-await.ts +3 -2
  129. package/scripts/lane/lane-child-invocation.ts +14 -1
  130. package/scripts/lane/lane-guard-policy.ts +4 -4
  131. package/scripts/lane/lane-ledger.ts +9 -0
  132. package/scripts/lane/lane-load.ts +9 -2
  133. package/scripts/lane/lane-measure-cli.ts +2 -0
  134. package/scripts/lane/lane-parked.ts +18 -0
  135. package/scripts/lane/lane-process-load.ts +125 -0
  136. package/scripts/lane/lane-process-stats.ts +93 -0
  137. package/scripts/lane/lane-registry.ts +8 -3
  138. package/scripts/lane/lane-session-broker.ts +29 -5
  139. package/scripts/lane/lane-spent.ts +14 -3
  140. package/scripts/lane/lane-stats.ts +1 -0
  141. package/scripts/managed-marker/managed-marker-logic.ts +1 -2
  142. package/scripts/notify/confirmation-options.ts +59 -0
  143. package/scripts/notify/notify-opt-in.ts +33 -0
  144. package/scripts/notify/telegram-notify.ts +25 -8
  145. package/scripts/notify/telegram-test-logic.ts +33 -1
  146. package/scripts/notify/telegram-test.ts +4 -2
  147. package/scripts/overrides/lockfile-overrides.ts +1 -3
  148. package/scripts/propagate/propagate.ts +1 -2
  149. package/scripts/release/release-progress.ts +3 -2
  150. package/scripts/report/report-lint.ts +7 -4
  151. package/scripts/review/review-record-cli.ts +6 -2
  152. package/scripts/rules/destructive-command.ts +6 -9
  153. package/scripts/rules/direct-filing.ts +3 -7
  154. package/scripts/rules/early-heartbeat.ts +7 -18
  155. package/scripts/rules/file-body.ts +6 -13
  156. package/scripts/rules/filing-cap.ts +3 -6
  157. package/scripts/rules/git-force.ts +5 -9
  158. package/scripts/rules/implementation-cut.ts +37 -35
  159. package/scripts/rules/index-guard.ts +4 -7
  160. package/scripts/rules/issue-comments.ts +5 -15
  161. package/scripts/rules/josh-git-bare.ts +3 -6
  162. package/scripts/rules/lane-background.ts +10 -21
  163. package/scripts/rules/lane-carry-conflict.ts +7 -17
  164. package/scripts/rules/lane-interactive-ask.ts +6 -11
  165. package/scripts/rules/lane-park.ts +5 -13
  166. package/scripts/rules/lane-split-park.ts +2 -7
  167. package/scripts/rules/lane-switch-main.ts +9 -12
  168. package/scripts/rules/oracle-consulted.ts +4 -5
  169. package/scripts/rules/piped-verification.ts +81 -31
  170. package/scripts/rules/poll-loop.ts +7 -17
  171. package/scripts/rules/pre-gate-cut.ts +7 -21
  172. package/scripts/rules/prior-comment-read.ts +7 -5
  173. package/scripts/rules/protected-files.ts +5 -9
  174. package/scripts/rules/raw-field-body.ts +3 -7
  175. package/scripts/rules/rule-body-guard.ts +4 -11
  176. package/scripts/rules/run-tail-rule.ts +6 -22
  177. package/scripts/rules/shell-body-trigger.ts +7 -8
  178. package/scripts/rules/shell-segments.ts +7 -0
  179. package/scripts/rules/stop-rules.ts +17 -29
  180. package/scripts/rules/test-declared-commit.ts +4 -10
  181. package/scripts/rules/third-party-write.ts +5 -10
  182. package/scripts/rules/worktree-guard.ts +5 -12
  183. package/scripts/run/board/run-board-github.ts +11 -3
  184. package/scripts/run/board/run-board-idle.ts +31 -0
  185. package/scripts/run/board/run-board-read.ts +9 -12
  186. package/scripts/run/board/run-board-reason.ts +7 -3
  187. package/scripts/run/board/run-board-state.ts +4 -0
  188. package/scripts/run/board/run-board-status.ts +18 -3
  189. package/scripts/run/board/run-board-thanks.ts +7 -2
  190. package/scripts/run/board/run-board-tick.ts +32 -7
  191. package/scripts/run/carry/run-carry-args.ts +1 -3
  192. package/scripts/run/carry/run-carry-conversation.ts +7 -2
  193. package/scripts/run/cut/run-cut-cli.ts +15 -20
  194. package/scripts/run/cut/run-cut-decline.ts +72 -0
  195. package/scripts/run/cut/run-cut-ready.ts +74 -0
  196. package/scripts/run/cut/run-cut-report.ts +13 -0
  197. package/scripts/run/cut/run-cut.ts +10 -1
  198. package/scripts/run/entry/run-entry-stop.ts +6 -3
  199. package/scripts/run/hold/run-hold-cli.ts +14 -3
  200. package/scripts/run/hold/run-hold.ts +6 -3
  201. package/scripts/run/merge/run-merge-cli.ts +30 -7
  202. package/scripts/run/merge/run-merge-ship.ts +59 -1
  203. package/scripts/run/merge/run-merge.ts +3 -2
  204. package/scripts/run/run-ending.ts +31 -3
  205. package/scripts/run/run-parent-cut-hook.ts +5 -10
  206. package/scripts/run/run-preflight.ts +1 -2
  207. package/scripts/run/run-stop-notify.ts +3 -2
  208. package/scripts/run/run-watcher-guard.ts +6 -3
  209. package/scripts/run/ship/run-ship-review-steps.ts +13 -4
  210. package/scripts/run/ship/run-ship-review.ts +15 -2
  211. package/scripts/run/tidy/run-tidy-cli.ts +3 -3
  212. package/scripts/run/tidy/run-tidy-lanes.ts +3 -2
  213. package/scripts/safe-chain/project-config.ts +7 -2
  214. package/scripts/sync/sync-hook-safety.ts +8 -2
  215. package/scripts/test/unit-worker-share.ts +3 -2
  216. package/scripts/time-runtime/time-batch-guard.ts +3 -3
  217. package/scripts/time-runtime/time-hook-transcript.ts +3 -2
  218. package/scripts/time-runtime/time-shell.ts +10 -0
  219. package/scripts/version/effective-upstream.ts +3 -4
  220. package/scripts/version/kit-version-config.ts +8 -2
  221. package/scripts/version/latest-corepack.ts +1 -2
  222. package/scripts/version/release-hold.ts +11 -4
  223. package/scripts/version/version-commands.ts +12 -4
  224. package/dist/hooks/chunk-UT7YC3N2.js +0 -56
@@ -1,22 +1,22 @@
1
1
  #!/usr/bin/env tsx
2
2
  import {
3
3
  pretool_guard
4
- } from "./chunk-5C7L6FRC.js";
5
- import "./chunk-SHYUQOIS.js";
6
- import "./chunk-Y3GKIKGW.js";
4
+ } from "./chunk-IIGFYXKC.js";
5
+ import "./chunk-YYPI7SJZ.js";
6
+ import "./chunk-43ZHT22P.js";
7
7
  import "./chunk-IX6TTTI6.js";
8
- import "./chunk-Z4XI7CZS.js";
8
+ import "./chunk-EUMACUK2.js";
9
9
  import "./chunk-CDY4NFQG.js";
10
- import "./chunk-EF5GQ6WS.js";
11
- import "./chunk-LBFYEOXJ.js";
12
- import "./chunk-NO4AALP5.js";
13
- import "./chunk-UT7YC3N2.js";
10
+ import "./chunk-YHBZAJSV.js";
11
+ import "./chunk-K4LMBQC2.js";
12
+ import "./chunk-H5HVWYXK.js";
13
+ import "./chunk-SHGPANFB.js";
14
14
  import {
15
15
  hook_decision
16
- } from "./chunk-W5ZKGTSY.js";
17
- import "./chunk-MBJYQPEK.js";
18
- import "./chunk-OLMO72ON.js";
19
- import "./chunk-3C4XRYG6.js";
16
+ } from "./chunk-J47HU5H5.js";
17
+ import "./chunk-AS74OU3D.js";
18
+ import "./chunk-K4EOONYM.js";
19
+ import "./chunk-E7OIKX5Z.js";
20
20
  import "./chunk-DGT54IH5.js";
21
21
 
22
22
  // scripts/hooks/pretool-guard-cli.ts
@@ -8,19 +8,19 @@ import {
8
8
  run_event_stream_emit,
9
9
  run_headless,
10
10
  session_language
11
- } from "./chunk-Z4XI7CZS.js";
11
+ } from "./chunk-EUMACUK2.js";
12
12
  import {
13
13
  error_text
14
14
  } from "./chunk-CDY4NFQG.js";
15
15
  import {
16
16
  josh_environment_file
17
- } from "./chunk-OLMO72ON.js";
17
+ } from "./chunk-K4EOONYM.js";
18
18
  import {
19
19
  agent_session_environment,
20
20
  json_value,
21
21
  process_identity,
22
22
  run_carry
23
- } from "./chunk-3C4XRYG6.js";
23
+ } from "./chunk-E7OIKX5Z.js";
24
24
  import {
25
25
  stamp_file
26
26
  } from "./chunk-DGT54IH5.js";
@@ -227,8 +227,9 @@ function ensure_ledger_directory(directory) {
227
227
  }
228
228
  }
229
229
  function ledger_arguments(common_directory, profile) {
230
- if (common_directory === void 0 || profile.role !== agent_role_profile.WORKER) return [];
231
- if (path2.basename(common_directory) !== GIT_DIRECTORY) return [];
230
+ if (common_directory === void 0 || profile.role !== agent_role_profile.WORKER || path2.basename(common_directory) !== GIT_DIRECTORY) {
231
+ return [];
232
+ }
232
233
  const directory = path2.join(path2.dirname(common_directory), LEDGER_DIRECTORY);
233
234
  ensure_ledger_directory(directory);
234
235
  return [ADD_DIRECTORY_FLAG, directory];
@@ -13,7 +13,7 @@ import {
13
13
  repo_party,
14
14
  run_cut,
15
15
  run_hold
16
- } from "./chunk-Y3GKIKGW.js";
16
+ } from "./chunk-43ZHT22P.js";
17
17
  import {
18
18
  agent_headless,
19
19
  agent_role_profile,
@@ -23,22 +23,22 @@ import {
23
23
  run_event_stream_emit,
24
24
  run_headless,
25
25
  session_language
26
- } from "./chunk-Z4XI7CZS.js";
26
+ } from "./chunk-EUMACUK2.js";
27
27
  import {
28
28
  timed_fetch
29
29
  } from "./chunk-723HKZO5.js";
30
30
  import "./chunk-CDY4NFQG.js";
31
31
  import {
32
32
  hook_decision
33
- } from "./chunk-W5ZKGTSY.js";
33
+ } from "./chunk-J47HU5H5.js";
34
34
  import {
35
35
  time_density_hook,
36
36
  time_hook_transcript,
37
37
  time_reported_failure
38
- } from "./chunk-MBJYQPEK.js";
38
+ } from "./chunk-AS74OU3D.js";
39
39
  import {
40
40
  lane_child_marker
41
- } from "./chunk-OLMO72ON.js";
41
+ } from "./chunk-K4EOONYM.js";
42
42
  import {
43
43
  backlog_budget,
44
44
  issue_number_shape,
@@ -47,7 +47,7 @@ import {
47
47
  process_owner_schema,
48
48
  run_carry,
49
49
  run_invocation
50
- } from "./chunk-3C4XRYG6.js";
50
+ } from "./chunk-E7OIKX5Z.js";
51
51
  import {
52
52
  stamp_file
53
53
  } from "./chunk-DGT54IH5.js";
@@ -243,13 +243,16 @@ var NONE2 = 0;
243
243
  async function live_lane_count() {
244
244
  return lane_registry.live_count(await lane_registry.list_lanes());
245
245
  }
246
+ async function free_lanes_beside(lanes) {
247
+ const limit = await lane_capacity.lane_limit();
248
+ if (limit.kind !== "limit") return void 0;
249
+ return lane_capacity.free_lanes(limit.limit, lane_registry.live_count(lanes));
250
+ }
246
251
  async function free_under(limit) {
247
252
  return lane_capacity.free_lanes(limit, await live_lane_count());
248
253
  }
249
254
  async function free_lane_count() {
250
- const limit = await lane_capacity.lane_limit();
251
- if (limit.kind !== "limit") return NO_FREE;
252
- return await free_under(limit.limit);
255
+ return await free_lanes_beside(await lane_registry.list_lanes()) ?? NO_FREE;
253
256
  }
254
257
  async function drive_free_lane_count() {
255
258
  const limit = await lane_capacity.lane_limit();
@@ -306,6 +309,7 @@ var backlog_ready = {
306
309
  read_backlog_next,
307
310
  print_offer_hint,
308
311
  free_lane_count,
312
+ free_lanes_beside,
309
313
  live_lane_count,
310
314
  drive_free_lane_count,
311
315
  drains_pool,
@@ -317,6 +321,52 @@ var backlog_ready = {
317
321
 
318
322
  // scripts/notify/telegram-notify.ts
319
323
  import { z } from "zod";
324
+
325
+ // scripts/notify/confirmation-options.ts
326
+ var JAPANESE_LANG_PREFIX = "ja";
327
+ var JAPANESE_HEADINGS = {
328
+ recommended: "\u63A8\u5968:",
329
+ alternatives: "\u4ED6\u306E\u9078\u629E\u80A2:",
330
+ none: "\u306A\u3057"
331
+ };
332
+ var ENGLISH_HEADINGS = {
333
+ recommended: "Recommended:",
334
+ alternatives: "Alternatives:",
335
+ none: "none"
336
+ };
337
+ function headings() {
338
+ const { lang } = session_language.resolve_session_lang();
339
+ return lang.toLowerCase().startsWith(JAPANESE_LANG_PREFIX) ? JAPANESE_HEADINGS : ENGLISH_HEADINGS;
340
+ }
341
+ function alternatives_block(options, labels) {
342
+ if (options.alternatives.length === 0) return `${labels.alternatives} ${labels.none}`;
343
+ const lines = options.alternatives.map((alternative) => `- ${alternative}`);
344
+ return [labels.alternatives, ...lines].join("\n");
345
+ }
346
+ function block(options) {
347
+ const labels = headings();
348
+ return `${labels.recommended} ${options.recommended}
349
+ ${alternatives_block(options, labels)}`;
350
+ }
351
+ var confirmation_options = { block };
352
+
353
+ // scripts/notify/notify-opt-in.ts
354
+ var OPT_IN_KEY = "JOSH_NOTIFY_OPT_IN";
355
+ var OPTIONAL_TASK_TYPES = /* @__PURE__ */ new Set(["planning", "completion"]);
356
+ var LIST_SEPARATOR = ",";
357
+ function opted_in_types() {
358
+ return (process.env[OPT_IN_KEY] ?? "").split(LIST_SEPARATOR).map((entry) => entry.trim().toLowerCase()).filter((entry) => entry.length > 0);
359
+ }
360
+ function is_skipped(task_type) {
361
+ if (!OPTIONAL_TASK_TYPES.has(task_type)) return false;
362
+ return !opted_in_types().includes(task_type);
363
+ }
364
+ function skip_line(task_type) {
365
+ return `\u{1F515} ${task_type} notifications are not opted in (${OPT_IN_KEY}).`;
366
+ }
367
+ var notify_opt_in = { is_skipped, skip_line };
368
+
369
+ // scripts/notify/telegram-notify.ts
320
370
  var TELEGRAM_API_BASE = "https://api.telegram.org";
321
371
  var TELEGRAM_TEXT_LIMIT = 4096;
322
372
  var BODY_TRUNCATION_MARK = "\n...";
@@ -377,6 +427,12 @@ function load_config() {
377
427
  function is_notify_disabled() {
378
428
  return parse_environment_string(process.env[NOTIFY_SWITCH_KEY]).toLowerCase() === NOTIFY_OFF_VALUE;
379
429
  }
430
+ function skip_line2(task_type) {
431
+ if (is_notify_disabled()) {
432
+ return `\u{1F515} Telegram notifications are disabled (${NOTIFY_SWITCH_KEY}=${NOTIFY_OFF_VALUE}).`;
433
+ }
434
+ return notify_opt_in.is_skipped(task_type) ? notify_opt_in.skip_line(task_type) : void 0;
435
+ }
380
436
  function build_header(task_type, repo_name) {
381
437
  const { icon, label } = TASK_DEFINITIONS[task_type];
382
438
  if (repo_name === void 0 || repo_name.length === 0) return `${icon} ${label}`;
@@ -402,6 +458,7 @@ function build_url_parts(input) {
402
458
  function build_blocks(input) {
403
459
  const blocks = [build_title_block(input)];
404
460
  push_if_present(blocks, input.body);
461
+ push_if_present(blocks, input.choices);
405
462
  blocks.push(...build_url_parts(input));
406
463
  return blocks;
407
464
  }
@@ -435,10 +492,9 @@ function build_send_failure(error, config) {
435
492
  return new Error(`${SEND_FAILED_PREFIX}: ${reason}`, { cause: new Error(reason) });
436
493
  }
437
494
  async function send(input) {
438
- if (is_notify_disabled()) {
439
- console.info(
440
- `\u{1F515} Telegram notifications are disabled (${NOTIFY_SWITCH_KEY}=${NOTIFY_OFF_VALUE}).`
441
- );
495
+ const skipped = skip_line2(input.task_type);
496
+ if (skipped !== void 0) {
497
+ console.info(skipped);
442
498
  return;
443
499
  }
444
500
  const config = load_config();
@@ -487,6 +543,7 @@ async function confirm(input) {
487
543
  repo_name: gh_spawn.get_repo_name_with_owner_within(REPO_LOOKUP_TIMEOUT_MS),
488
544
  issue_title: input.issue_title,
489
545
  body: input.body,
546
+ choices: confirmation_options.block(input),
490
547
  issue_url: void 0,
491
548
  pr_url: void 0
492
549
  },
@@ -762,23 +819,23 @@ var stop_payload_schema = z3.object({
762
819
  last_assistant_message: z3.string().nullish()
763
820
  });
764
821
  var NO_OUTCOME = { reason: void 0 };
765
- var STOP_NOTIFY_REASON = '\u26D4 mid-workflow stop notification: this working tree is still held by a run and no `confirmation` Telegram was sent this turn, so a person is being left to wait off-screen without knowing the run paused. `CLAUDE.md` \u2192 "Mid-workflow stop notification" requires `pnpm josh notify --task-type confirmation --issue-url "<url>" --body=$\'<reason>\'` before any mid-workflow pause. Send it, then end with a one-line confirmation that it was sent \u2014 do not repeat your previous reply. This fires only while the hold is held and no notify is on the transcript, and `stop_hook_active` lets a second stop through so a run is never wedged.';
766
- var HOLD_RELEASE_REASON = "\u26D4 working-tree hold not released: this working tree is clean but its `run:hold` record is still in place, so the next run here runs `pnpm josh ms` believing the tree is free while you hold it. The workflow-commands skill \u2192 `working-tree-hold.md`: a stop that leaves the tree clean releases the hold with `pnpm josh run:release <N>` (bare for a `new` entry). A `halfrun` pre-commit stop and a `needs-human-review` stop keep the hold because their tree is dirty, and a `prrun` stop keeps it by its stop mark \u2014 this row is silent there. Release it, then end with a one-line confirmation that it was released \u2014 do not repeat your previous reply.";
822
+ var STOP_NOTIFY_REASON = '\u26D4 mid-workflow stop notification: this working tree is still held by a run and no `confirmation` Telegram was sent this turn. Send `pnpm josh notify --task-type confirmation --issue-url "<url>" --body=$\'<reason>\' --recommended "<choice>" --alternative "<choice>"` (`CLAUDE.md` \u2192 "Mid-workflow stop notification"), then confirm in one line that it was sent \u2014 do not repeat your previous reply.';
823
+ var HOLD_RELEASE_REASON = "\u26D4 working-tree hold not released: this working tree is clean but its `run:hold` record is still in place. Release it with `pnpm josh run:release <N>` (bare for a `new` entry; `working-tree-hold.md`), then confirm in one line that it was released \u2014 do not repeat your previous reply.";
767
824
  var ISSUE_CITATION_REASON = "Session-facing output cites an Issue as a number-link so the reader can click through and see which repository it is (`CLAUDE.md`, `prompts/collaboration-workflow/issue-citation.md`).";
768
825
  function build_citation_reason(references) {
769
826
  const numbers = references.join(", ");
770
827
  const command = `pnpm josh issue:cite ${issue_citation.cite_arguments(references).join(" ")}`;
771
828
  return `\u26D4 issue citation: your reply names an Issue as a bare \`#N\` (${numbers}). Run \`${command}\` to print the paste-ready citation lines, then print the corrected citation lines alone \u2014 do not repeat your previous reply. ${ISSUE_CITATION_REASON}`;
772
829
  }
773
- var FILING_OFFER_REASON = '\u26D4 filing offer: your reply offers to file an Issue instead of filing it, and this run is unattended \u2014 nobody is there to answer. Filing into a first-party repository there is Tier A \u2014 the trigger is the judgement that it is worth filing, not the run\'s progress (the workflow-commands skill \u2192 `observation-filing.md`). Run `pnpm josh issue:file "<title>" --body-file <path> --depth <0|1|2>` \u2014 it scouts, lints, labels and runs `epic:bundle` itself \u2014 then end with the one-line citation of what was filed; do not repeat your previous reply. If it is not worth filing after all, say so in one line instead.';
830
+ var FILING_OFFER_REASON = '\u26D4 filing offer: your reply offers to file an Issue instead of filing it, and this run is unattended \u2014 nobody is there to answer. Run `pnpm josh issue:file "<title>" --body-file <path> --depth <0|1|2>` (Tier A, `observation-filing.md`), then end with the one-line citation of what was filed; do not repeat your previous reply. If it is not worth filing after all, say so in one line instead.';
774
831
  var HEADLESS_WAIT_MARKER = "\u26D4 headless parent:";
775
832
  var HEADLESS_REFUSAL_CAP = 3;
776
833
  var HEADLESS_WAIT_CALLS = ['"command":"pnpm josh lane:await'];
777
- var HEADLESS_WAIT_BODY = ' this is a `claude -p` `backlogrun` parent (`JOSH_RUN_HEADLESS`) with lanes still in flight, and ending this turn ends the process \u2014 its background waits are killed with it and the lanes are left without a parent. Do not watch them yourself: the `run:wake` supervisor\'s driver watches the lanes and wakes a session only for a branch that needs judging. Hand the loop back with `pnpm josh run:carry --cut --owner "$PPID"` (or `--end` when the run is over), then end the turn (`backlogrun-progress.md` \u2192 "Picking the lanes up in the fresh session").';
834
+ var HEADLESS_WAIT_BODY = ' this is a `claude -p` `backlogrun` parent with lanes in flight, and ending this turn kills the process and its background waits. Hand the loop back with `pnpm josh run:carry --cut --owner "$PPID"` (or `--end` when the run is over), then end the turn (`backlogrun-progress.md`).';
778
835
  var HEADLESS_WAIT_REASON = `${HEADLESS_WAIT_MARKER}${HEADLESS_WAIT_BODY}`;
779
836
  var INDEX_COMMAND_PATTERN = /git (?:add|stage|rm --cached|restore --staged|restore -S)\b/u;
780
837
  var PERMISSION_PATTERN = /許可|承認|permission|approve|approval|authorization/iu;
781
- var LANE_INDEX_REASON = '\u26D4 lane index permission: this is a dispatched lane child (`JOSH_LANE_CHILD`) and your reply asks a person for permission to change the git index. A lane is a per-run work tree with no person\'s staging to protect, and the sanctioned commit flow is already authorized: remove any conflict markers, then run `pnpm josh git -y`, which stages and commits them \u2014 a conflicted merge included. This is Tier A (`.claude/skills/workflow-commands/chain-rule.md` \u2192 "origin/main is merged in before the gate"). Do it and continue the run \u2014 do not repeat your previous reply.';
838
+ var LANE_INDEX_REASON = "\u26D4 lane index permission: this is a dispatched lane child (`JOSH_LANE_CHILD`) and your reply asks a person for permission to change the git index. That is Tier A here (`chain-rule.md`): remove any conflict markers, run `pnpm josh git -y` (it stages and commits, a conflicted merge included) and continue the run \u2014 do not repeat your previous reply.";
782
839
  function asks_index_permission(message2) {
783
840
  return INDEX_COMMAND_PATTERN.test(message2) && PERMISSION_PATTERN.test(message2);
784
841
  }
package/dist/josh.js CHANGED
@@ -743,8 +743,9 @@ function is_worker_flag(argument) {
743
743
  return WORKER_FLAGS.some((flag) => argument === flag || argument.startsWith(`${flag}=`));
744
744
  }
745
745
  function worker_arguments(vitest_arguments, share) {
746
- if (share === void 0) return [];
747
- if (vitest_arguments.some((argument) => is_worker_flag(argument))) return [];
746
+ if (share === void 0 || vitest_arguments.some((argument) => is_worker_flag(argument))) {
747
+ return [];
748
+ }
748
749
  return [`${WORKER_FLAG}=${String(share)}`];
749
750
  }
750
751
  function mark_run_started(target) {
@@ -2747,7 +2748,7 @@ var WORKFLOW_COMMANDS = {
2747
2748
  description: "Send Telegram notification",
2748
2749
  category: "Workflow",
2749
2750
  reference: [
2750
- "[--task-type <type>] [--body <text> | --body-file <path>] [--issue-url <url>] [--pr-url <url>] [--issue-title <text>] [--repo-name <name>]",
2751
+ "[--task-type <type>] [--body <text> | --body-file <path>] [--issue-url <url>] [--pr-url <url>] [--issue-title <text>] [--repo-name <name>] [--recommended <text>] [--alternative <text>]...",
2751
2752
  "automation",
2752
2753
  ["notifications"]
2753
2754
  ],
@@ -3024,8 +3025,7 @@ function parse_scp_like(url) {
3024
3025
  const user_end = url.indexOf(USER_SEPARATOR);
3025
3026
  const authority = user_end === NOT_FOUND ? url : url.slice(user_end + 1);
3026
3027
  const host_end = authority.indexOf(HOST_SEPARATOR);
3027
- if (host_end === NOT_FOUND) return void 0;
3028
- if (!is_github_ssh_host(authority.slice(0, host_end))) return void 0;
3028
+ if (host_end === NOT_FOUND || !is_github_ssh_host(authority.slice(0, host_end))) return void 0;
3029
3029
  return to_identity(authority.slice(host_end + 1));
3030
3030
  }
3031
3031
  function parse_url_like(url) {
@@ -3053,8 +3053,7 @@ function origin_section_lines(lines) {
3053
3053
  }
3054
3054
  function url_value(line) {
3055
3055
  const separator = line.indexOf("=");
3056
- if (separator === NOT_FOUND) return void 0;
3057
- if (line.slice(0, separator).trim() !== URL_KEY) return void 0;
3056
+ if (separator === NOT_FOUND || line.slice(0, separator).trim() !== URL_KEY) return void 0;
3058
3057
  return line.slice(separator + 1).trim();
3059
3058
  }
3060
3059
  function parse_origin_from_config(content) {
@@ -18,8 +18,7 @@ function is_marked(text) {
18
18
  return text.startsWith(MARKER_PREFIX);
19
19
  }
20
20
  function apply_marker_for_destination(destination, text, package_name) {
21
- if (!is_workflow_destination(destination)) return text;
22
- if (is_marked(text)) return text;
21
+ if (!is_workflow_destination(destination) || is_marked(text)) return text;
23
22
  return `${marker_block(package_name)}${text}`;
24
23
  }
25
24
  var managed_marker_logic = {
@@ -141,8 +141,7 @@ function read_matching_version(manifest_path, package_name) {
141
141
  const parsed = package_named_version_schema.safeParse(
142
142
  json_value.parse_or_undefined(readFileSync(manifest_path, "utf8"))
143
143
  );
144
- if (!parsed.success) return void 0;
145
- if (parsed.data.name !== package_name) return void 0;
144
+ if (!parsed.success || parsed.data.name !== package_name) return void 0;
146
145
  return parsed.data.version;
147
146
  }
148
147
  function walk_up_for_version(start_directory, package_name) {
@@ -152,9 +151,9 @@ function walk_up_for_version(start_directory, package_name) {
152
151
  }
153
152
  return void 0;
154
153
  }
155
- function resolve_from_base(base_url, package_name, resolve_marker) {
154
+ function resolve_from_base(base_url, package_name, resolve_marker = package_name) {
156
155
  try {
157
- return createRequire(base_url).resolve(resolve_marker ?? package_name);
156
+ return createRequire(base_url).resolve(resolve_marker);
158
157
  } catch {
159
158
  return void 0;
160
159
  }
@@ -281,8 +280,9 @@ function is_latest_withheld(times, latest, minimum_age_minutes, now_ms) {
281
280
  return published_ms > now_ms - minimum_age_minutes * MS_PER_MINUTE2;
282
281
  }
283
282
  function resolve_installable(times, latest, minimum_age_minutes, now_ms) {
284
- if (times === void 0) return void 0;
285
- if (!is_latest_withheld(times, latest, minimum_age_minutes, now_ms)) return void 0;
283
+ if (times === void 0 || !is_latest_withheld(times, latest, minimum_age_minutes, now_ms)) {
284
+ return void 0;
285
+ }
286
286
  const installable = release_age.select_aged_version(times, void 0, minimum_age_minutes, now_ms);
287
287
  return installable === latest ? void 0 : installable;
288
288
  }
@@ -307,8 +307,9 @@ function format_release_hold_note(version, latest, installable, minimum_age_minu
307
307
  return `${head}; an unpinned resolve lands on ${installable}`;
308
308
  }
309
309
  function build_release_hold_notes(version, latest, installable, minimum_age_minutes) {
310
- if (version === void 0 || installable === void 0) return [];
311
- if (!is_release_age_hold(version, latest, installable)) return [];
310
+ if (version === void 0 || installable === void 0 || !is_release_age_hold(version, latest, installable)) {
311
+ return [];
312
+ }
312
313
  return [format_release_hold_note(version, latest, installable, minimum_age_minutes)];
313
314
  }
314
315
  var release_hold = {
@@ -1399,8 +1400,9 @@ function build_extras(config) {
1399
1400
  }
1400
1401
  function build_upstream_effective(upstream, context) {
1401
1402
  const { resolve_effective_version, resolve_global_upgrade_command } = upstream;
1402
- if (resolve_effective_version === void 0) return void 0;
1403
- if (resolve_global_upgrade_command === void 0) return void 0;
1403
+ if (resolve_effective_version === void 0 || resolve_global_upgrade_command === void 0) {
1404
+ return void 0;
1405
+ }
1404
1406
  return {
1405
1407
  version: resolve_effective_version(context),
1406
1408
  upgrade_command: resolve_global_upgrade_command(context)
@@ -1485,8 +1487,9 @@ function build_idle_message(reports) {
1485
1487
  }
1486
1488
  function describe_effective_outcome(upstream, report, snapshot) {
1487
1489
  const { resolve_effective_version } = upstream;
1488
- if (resolve_effective_version === void 0 || report === void 0) return [];
1489
- if (version_check_logic.build_effective_upgrade_commands(report).length === 0) return [];
1490
+ if (resolve_effective_version === void 0 || report === void 0 || version_check_logic.build_effective_upgrade_commands(report).length === 0) {
1491
+ return [];
1492
+ }
1490
1493
  const after = resolve_effective_version({
1491
1494
  latest: snapshot.latest,
1492
1495
  upstream_latest: report.latest
package/eslint/base.js CHANGED
@@ -29,7 +29,7 @@ import {
29
29
  SPEC_FILENAME_PATTERNS,
30
30
  } from './rules/test-filename.js'
31
31
  import { typescript_rules } from './rules/typescript.js'
32
- import { unicorn_rules } from './rules/unicorn.js'
32
+ import { unicorn_rules, unicorn_test_rules } from './rules/unicorn.js'
33
33
 
34
34
  const FILE_PATTERNS = {
35
35
  d_ts: ['**/*.d.ts'],
@@ -234,6 +234,7 @@ export function create_base_config({ gitignore_path, tsconfig_root_dir }) {
234
234
  // `expect(x).toBe(0.05)` compares deterministic config constants, not computed
235
235
  // floats; working around the rule only weakens the assertion.
236
236
  'sonarjs/no-floating-point-equality': 'off',
237
+ ...unicorn_test_rules,
237
238
  },
238
239
  },
239
240
  {
@@ -205,3 +205,19 @@ export const unicorn_rules = {
205
205
  // たびにエディタと衝突し、可読性の利得なく差分ノイズだけを生むため無効化する(joshuafolkken/kit#3273)。
206
206
  'unicorn/no-asterisk-prefix-in-documentation-comments': 'off',
207
207
  }
208
+
209
+ // unicorn 78 のベースライン方針(joshuafolkken/kit#3882): 78 は新ルール 2 つ
210
+ // (no-unnecessary-default-arguments / no-repeated-call-wrappers)に加え、型解決とコメントを含む
211
+ // コードの検査を広げたため、既存ルールが新たに報告する。prefer-combined-guards /
212
+ // prefer-minimal-ternary / no-negated-condition / prefer-default-parameters は正当な
213
+ // クリーンアップなので採用し、コードを直す。consistent-boolean-name だけは下記のとおり
214
+ // テストファイルで外す。
215
+ export const unicorn_test_rules = {
216
+ // 78 は vi.fn() / vi.spyOn() / vi.mocked() の戻り型を解決できるようになり、真偽値を返す関数の
217
+ // モックやスパイ(`const write = vi.spyOn(process.stdout, 'write')`)を真偽値の束縛として報告する。
218
+ // 関数値の const を checkVariables で検査するのはプラグインの文書どおりの仕様(77 でも
219
+ // `const f = () => true` は報告される)で、誤検知ではない。ただしテストの束縛はほぼすべて
220
+ // 差し替える関数を名前で示すテストダブルで、`is_write` のような名前は述語の結果のように読めて
221
+ // 誤解を招く。kit が関数名を検査しない(checkFunctions: 'never')のと同じ理由でテストでは外す。
222
+ 'unicorn/consistent-boolean-name': 'off',
223
+ }
package/package.json CHANGED
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "1.1453.0",
2
+ "version": "1.1471.0",
3
3
  "name": "@joshuafolkken/kit",
4
4
  "description": "Development toolkit for AI-assisted projects: formatting, AI assistant rules and a Git/GitHub Issue workflow for any repository, plus lint, type check, tests and hooks for Node projects",
5
5
  "keywords": [
@@ -178,7 +178,7 @@
178
178
  "eslint-plugin-import-x": "^4.17.1",
179
179
  "eslint-plugin-promise": "^7.3.0",
180
180
  "eslint-plugin-sonarjs": "^4.2.1",
181
- "eslint-plugin-unicorn": "^77.0.0",
181
+ "eslint-plugin-unicorn": "^78.0.0",
182
182
  "globals": "^17.12.0",
183
183
  "prettier": "^3.9.9",
184
184
  "prettier-plugin-svelte": "^4.1.1",
@@ -260,7 +260,7 @@
260
260
  "eslint-plugin-import-x": "^4.17.1",
261
261
  "eslint-plugin-promise": "^7.3.0",
262
262
  "eslint-plugin-sonarjs": "^4.2.2",
263
- "eslint-plugin-unicorn": "^77.0.0",
263
+ "eslint-plugin-unicorn": "^78.0.0",
264
264
  "eslint_d": "^15.0.3",
265
265
  "globals": "^17.13.0",
266
266
  "lefthook": "^2.2.1",
@@ -1,27 +1,21 @@
1
1
  # コーディング指針 — lint では表せない書き方
2
2
 
3
- 命名・エクスポート・ファイル名・内容の規約の単一ソースは下記「Conventions」、関数の構文・品質上限・型安全・早期 return・マジックナンバーの単一ソースは `CLAUDE.md` → "Critical Conventions (non-standard — always apply)" である。その大半は ESLint が強制する(クラスのプロパティ・メソッドの `snake_case` などここに書いていない細目は `eslint/rules/naming-convention.js` が持つ)。ただし **`function` 構文(アロー関数を使わない)と早期 return の 1 行形式は lint が検査しない**ので、書き手とレビューが確かめる。このファイルは本文を写さず、lint では表せない書き方の指針だけを持つ。
4
-
5
- lint・型検査の実行手順は `CLAUDE.md` → "Code Change Rules" の検証ゲート(`pnpm josh gate`、実装中は `pnpm josh lint:related` / `pnpm josh test:related`)が単一ソースである。
3
+ 関数の構文・品質上限・型安全・早期 return・マジックナンバーは `CLAUDE.md` → "Critical Conventions (non-standard — always apply)"、lint・型検査の実行は `CLAUDE.md` → "Code Change Rules"(`pnpm josh gate`、実装中は `pnpm josh lint:related` / `pnpm josh test:related`)に従う。ここにない命名の細目(クラスのプロパティ・メソッドの `snake_case` など)は `eslint/rules/naming-convention.js` が持つ。**`function` 構文(アロー関数を使わない)と早期 return の 1 行形式は lint が検査しない**ので、書き手とレビューが確かめる。
6
4
 
7
5
  ## Conventions
8
6
 
9
- `CLAUDE.md` から移した、lint が強制する規約の単一ソース。
10
-
11
- - **Naming**: `snake_case` variables / functions / params · `PascalCase` types / classes / interfaces / enums · `UPPER_CASE` enum members · booleans prefixed `is_` / `has_` / `should_` / `can_` / `will_` / `did_` · constants `UPPER_CASE` or `snake_case`
12
- - **Functions & exports**: multiple functions → a namespace object `export { my_module }` (constants exempt) · no `export default`
13
- - **Files**: Svelte `PascalCase.svelte(.ts)` · TypeScript `kebab-case.ts` · tests `*.test.ts` / `*.svelte.test.ts`, colocated, never `*.spec.ts` (`prompts/testing-guide.md`) · in `scripts/`, no `../` imports — use `#scripts/*`
14
- - **Content rules**: user-visible strings use i18n message keys in every locale · comments / test titles English only (`eslint/rules/` may explain rationale in Japanese) · no duplication; `/* @refactor-ignore */` at file top excludes a file from refactoring
7
+ - Naming: `snake_case` variables / functions / params · `PascalCase` types / classes / interfaces / enums · `UPPER_CASE` enum members · booleans prefixed `is_` / `has_` / `should_` / `can_` / `will_` / `did_` · constants `UPPER_CASE` or `snake_case`
8
+ - Functions & exports: multiple functions → a namespace object `export { my_module }` (constants exempt) · no `export default`
9
+ - Files: Svelte `PascalCase.svelte(.ts)` · TypeScript `kebab-case.ts` · tests `*.test.ts` / `*.svelte.test.ts`, colocated, never `*.spec.ts` (`prompts/testing-guide.md`) · in `scripts/`, no `../` imports — use `#scripts/*`
10
+ - Content rules: user-visible strings use i18n message keys in every locale · comments / test titles English only (`eslint/rules/` may explain rationale in Japanese) · no duplication; `/* @refactor-ignore */` at file top excludes a file from refactoring
15
11
 
16
12
  ## 📝 基本方針
17
13
 
18
- 一般的な書き方の助言(シンプルさ・命名・過度な抽象化の回避など)は繰り返さない。lint が強制せず、一般論でもない指針だけを置く。
19
-
20
- - **意図が不明瞭な処理は関数に抽出する**: 条件式や処理の意図がわかりにくければ、たとえ 1 行でも抽出し、関数名で意図を表す(`if (is_eligible_for_service(user))`)
21
- - **コメントは「なぜ」だけ、経緯は書かない**: 残すのは一行の理由(そのルールの意図)だけ。「以前は…」という経緯、Issue 番号への参照、計測値は git 履歴と Issue が保持している
22
- - **文字列も定数化する**: 数値リテラルの抽出は lint が強制するが、繰り返し使用する文字列や識別子も定数化し、意味の分かる名前を付ける
14
+ - **意図が不明瞭な処理は関数に抽出する**: 1 行でも抽出し、関数名で意図を表す(`if (is_eligible_for_service(user))`)
15
+ - **コメントは「なぜ」だけ**: 一行の理由だけを残す。「以前は…」の経緯・Issue 番号・計測値は書かない(git 履歴と Issue が持つ)
16
+ - **文字列も定数化する**: 繰り返す文字列や識別子にも意味の分かる名前の定数を付ける
23
17
  - **既存のコード体系に寄り添う**: そのうえで、より良く書けるなら目指す
24
- - **仕組みを足す前に原因を問う**: 設計時の判断は `prompts/collaboration-workflow/principles.md` → "elegant-design" の担当。コメントの英語限定と重複の撲滅は上の「Conventions」と `principles.md` → "no-clones" が単一ソースである
18
+ - **仕組みを足す前に原因を問う**: `prompts/collaboration-workflow/principles.md` → "elegant-design"。重複の撲滅は "no-clones"
25
19
 
26
20
  ## 📁 新規作成時の手順
27
21
 
@@ -34,16 +28,12 @@ find src -name "*.ts" -o -name "*.svelte" | grep -i [関連キーワード]
34
28
 
35
29
  ### 2. ファイル分割の指針
36
30
 
37
- - **上限に近づいたら分割を検討**: 関数やファイルが `CLAUDE.md` → "Quality limits" の上限に近づいたら分割を検討する。編集前に `pnpm josh lines <path>` で余裕を確認する
38
- - **責任が複数ある場合**: 1つのファイルが複数の責任を持つ場合は、責任ごとにファイルを分割
39
- - **再利用性**: 他のファイルからも使用される可能性があるロジックは、別ファイルに分離
40
- - **メインファイルの肥大化を避ける**: メインファイルの肥大化を避けることを優先する。再利用可能な機能や独立した責任を持つ機能は、積極的に別ファイルに分割する。メインファイルは主要な処理フローに集中し、詳細な実装は別ファイルに分離する
41
- - **過度な分割は避ける**: 小さすぎるファイルの分割は避け、関連する機能は同じファイルにまとめる
31
+ - `CLAUDE.md` → "Quality limits" の上限に近づいたら分割を検討する。編集前に `pnpm josh lines <path>` で余裕を確認する
32
+ - 責任ごと、また他ファイルからも使われうるロジックごとに別ファイルに分け、メインファイルは主要な処理フローに集中させる
33
+ - 小さすぎる分割は避け、関連する機能は同じファイルにまとめる
42
34
 
43
35
  ### 3. 名前空間オブジェクトの名付け方
44
36
 
45
- 複数の関数を名前空間オブジェクトにまとめてエクスポートする規則そのものは上記「Conventions」にある(定数は個別エクスポートでよい)。ここでは名付け方だけを述べる。
46
-
47
37
  - ファイル名と名前空間名で意図を明確にする(例: `git-command.ts` → `git_command`)
48
38
  - メソッド名は短く、名前空間で補完する(例: `exec_git_branch()` → `git_command.branch()`)
49
39