@joshuafolkken/kit 1.978.0 → 1.998.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 (138) hide show
  1. package/.claude/skills/epic-commands/SKILL.md +6 -5
  2. package/.claude/skills/workflow-commands/SKILL.md +9 -9
  3. package/.claude/skills/workflow-commands/background-commands.md +1 -1
  4. package/.claude/skills/workflow-commands/backlogrun-child.md +1 -1
  5. package/.claude/skills/workflow-commands/backlogrun-steps.md +1 -1
  6. package/.claude/skills/workflow-commands/fullrun-steps.md +8 -8
  7. package/.claude/skills/workflow-commands/halfrun.md +4 -5
  8. package/.claude/skills/workflow-commands/issue-comments.md +1 -1
  9. package/.claude/skills/workflow-commands/issue-scout.md +21 -22
  10. package/.claude/skills/workflow-commands/kickoff.md +8 -9
  11. package/.claude/skills/workflow-commands/observation-filing.md +9 -10
  12. package/.claude/skills/workflow-commands/prerequisite.md +7 -6
  13. package/.claude/skills/workflow-commands/retrospective.md +5 -5
  14. package/.claude/skills/workflow-commands/rule-residency.md +2 -2
  15. package/.claude/skills/workflow-commands/split-assessment.md +4 -3
  16. package/.claude/skills/workflow-commands/target-repository.md +7 -6
  17. package/.github/workflows/sonar-qube.yml +12 -2
  18. package/CLAUDE.md +2 -2
  19. package/README.md +30 -21
  20. package/dist/CLAUDE.md +2 -2
  21. package/dist/hooks/batch-guard.js +4 -4
  22. package/dist/hooks/{chunk-ZYYSBNR6.js → chunk-4GDR2YTV.js} +4 -4
  23. package/dist/hooks/{chunk-2K52BRWV.js → chunk-56LGMJJV.js} +2 -2
  24. package/dist/hooks/{chunk-BNGGEY3Z.js → chunk-762BDXDU.js} +266 -327
  25. package/dist/hooks/{chunk-Q7LE77CO.js → chunk-7WAOP42A.js} +34 -30
  26. package/dist/hooks/{chunk-NXL3SBXY.js → chunk-A2H5I2VD.js} +2 -2
  27. package/dist/hooks/{chunk-CRGJTD6E.js → chunk-AWTFKKFW.js} +1 -1
  28. package/dist/hooks/{chunk-KQG4776P.js → chunk-GBJUERYK.js} +1 -1
  29. package/dist/hooks/{chunk-BVMSPG3M.js → chunk-KPZN42RT.js} +3 -3
  30. package/dist/hooks/{chunk-ZPLXLJ7O.js → chunk-PAXMLGSS.js} +42 -8
  31. package/dist/hooks/{chunk-F6OM6SIG.js → chunk-WMIR5SNX.js} +12 -12
  32. package/dist/hooks/codex-hook-adapter.js +10 -10
  33. package/dist/hooks/duplicate-read-guard.js +5 -5
  34. package/dist/hooks/format-edited.js +2 -2
  35. package/dist/hooks/investigation-guard.js +5 -5
  36. package/dist/hooks/pretool-guard.js +9 -9
  37. package/dist/hooks/stop-guard.js +99 -27
  38. package/dist/josh.js +21 -6
  39. package/package.json +5 -1
  40. package/prettier/basic.d.ts +3 -0
  41. package/prettier/basic.js +10 -0
  42. package/prettier/index.js +2 -2
  43. package/prettier/static.js +3 -10
  44. package/prompts/collaboration-workflow/epic-bundle.md +8 -8
  45. package/prompts/collaboration-workflow/issue-template.md +5 -5
  46. package/prompts/collaboration-workflow/rule-delivery.md +43 -30
  47. package/prompts/collaboration-workflow/upstream-interrupt.md +1 -1
  48. package/prompts/collaboration-workflow/wip-cap.md +3 -3
  49. package/prompts/review.md +11 -9
  50. package/prompts/sonar-hotspot-handling.md +6 -0
  51. package/prompts/testing-guide.md +1 -1
  52. package/scripts/agent/agent-diagnostics.ts +1 -0
  53. package/scripts/agent/agent-role-profile.ts +1 -1
  54. package/scripts/behavior/behavior-rules.ts +8 -1
  55. package/scripts/build/build-claude-md.ts +13 -4
  56. package/scripts/delegation/delegation-policy.ts +9 -9
  57. package/scripts/document/document-byte-budget.ts +1 -1
  58. package/scripts/gate/gate-steps.ts +1 -1
  59. package/scripts/gate/project-checks.ts +12 -11
  60. package/scripts/gate/type-check-command.ts +1 -1
  61. package/scripts/git/git-branch.ts +14 -3
  62. package/scripts/git/git-issue.ts +13 -5
  63. package/scripts/git/git-pr.ts +16 -10
  64. package/scripts/git/git-preflight.ts +138 -0
  65. package/scripts/git/telegram-notify.ts +21 -0
  66. package/scripts/hooks/stop-guard.ts +2 -0
  67. package/scripts/init/basic-path-migration.ts +24 -0
  68. package/scripts/init/distributed-paths.ts +22 -0
  69. package/scripts/init/init-actions.ts +27 -19
  70. package/scripts/init/init-ai-copy.ts +86 -28
  71. package/scripts/init/{init-static.ts → init-basic.ts} +6 -6
  72. package/scripts/init/init-bootstrap.ts +4 -3
  73. package/scripts/init/init-install.ts +1 -1
  74. package/scripts/init/init-logic-templates.ts +1 -1
  75. package/scripts/init/init-logic.ts +1 -1
  76. package/scripts/init/init.ts +41 -19
  77. package/scripts/init/kit-setup-state.ts +30 -0
  78. package/scripts/init/kit-written-paths.ts +33 -0
  79. package/scripts/init/project-profile-cli.ts +15 -1
  80. package/scripts/init/project-profile.ts +41 -12
  81. package/scripts/init/session-language-environment.ts +83 -0
  82. package/scripts/init/start-exec.ts +28 -0
  83. package/scripts/init/start-plan.ts +35 -13
  84. package/scripts/init/start-prompt.ts +22 -8
  85. package/scripts/init/start-setup-pr.ts +138 -0
  86. package/scripts/init/start-steps.ts +30 -30
  87. package/scripts/init/start.ts +7 -3
  88. package/scripts/issue/issue-file-cli.ts +188 -0
  89. package/scripts/issue/issue-file.ts +192 -0
  90. package/scripts/issue/issue-lint-cli.ts +1 -1
  91. package/scripts/issue/issue-scout-cli.ts +41 -97
  92. package/scripts/issue/issue-scout-closed.ts +102 -0
  93. package/scripts/josh/__snapshots__/josh-command-map.test.ts.snap +12 -4
  94. package/scripts/josh/josh-command-map.ts +1 -0
  95. package/scripts/josh/josh-commands-development.ts +3 -3
  96. package/scripts/josh/josh-commands-issue.ts +11 -0
  97. package/scripts/josh/josh-commands-project.ts +7 -3
  98. package/scripts/lint/cspell-cached.ts +3 -3
  99. package/scripts/lint/format.ts +1 -1
  100. package/scripts/lint/lint-parallel.ts +2 -2
  101. package/scripts/propagate/propagate-run.ts +1 -0
  102. package/scripts/propagate/propagate-select.ts +72 -0
  103. package/scripts/propagate/propagate-targets.ts +5 -3
  104. package/scripts/propagate/propagate.ts +86 -24
  105. package/scripts/rules/bash-triggers.ts +19 -6
  106. package/scripts/rules/delivered-rules.ts +28 -32
  107. package/scripts/rules/direct-filing.ts +38 -0
  108. package/scripts/rules/filing-cap.ts +12 -8
  109. package/scripts/rules/issue-citation.ts +30 -1
  110. package/scripts/rules/issue-fold.ts +4 -4
  111. package/scripts/rules/last-prompt.ts +79 -0
  112. package/scripts/rules/oracle-consulted.ts +4 -4
  113. package/scripts/rules/oracle-firing.ts +13 -16
  114. package/scripts/rules/rule-body-guard.ts +6 -9
  115. package/scripts/rules/stop-rules.ts +8 -5
  116. package/scripts/safe-chain/ci-installer-pin.ts +19 -12
  117. package/scripts/safe-chain/project-config.ts +1 -1
  118. package/scripts/sync/sync-ai-files.ts +204 -0
  119. package/scripts/sync/sync.ts +48 -184
  120. package/scripts/test/josh-harness-environment.ts +1 -1
  121. package/scripts/test/pilot-files.ts +0 -2
  122. package/scripts/test/test-declared-changed.ts +1 -1
  123. package/scripts/test/test-declared-logic.ts +55 -14
  124. package/scripts/test/test-declared.ts +23 -11
  125. package/scripts/test/test-unit-guard.ts +6 -6
  126. package/scripts/time-runtime/time-shell.ts +36 -2
  127. package/scripts/version/fresh-metadata-cache.ts +36 -0
  128. package/scripts/version/latest-update.ts +2 -1
  129. package/scripts-ai/git-workflow.ts +10 -0
  130. package/templates/CLAUDE.basic.md +8 -0
  131. package/templates/workflows/ci.yml +27 -0
  132. package/scripts/rules/issue-bug-label.ts +0 -85
  133. package/scripts/rules/issue-filing-args.ts +0 -50
  134. package/scripts/rules/issue-scout.ts +0 -64
  135. /package/{templates/CLAUDE.static.md → dist/CLAUDE.basic.md} +0 -0
  136. /package/templates/{cursorrules.static → cursorrules.basic} +0 -0
  137. /package/templates/{pnpm-workspace.static.yaml → pnpm-workspace.basic.yaml} +0 -0
  138. /package/templates/{prettierignore.static → prettierignore.basic} +0 -0
@@ -19,20 +19,22 @@ import {
19
19
  run_hold,
20
20
  run_invocation,
21
21
  run_watcher_guard
22
- } from "./chunk-Q7LE77CO.js";
22
+ } from "./chunk-7WAOP42A.js";
23
23
  import {
24
24
  session_language
25
25
  } from "./chunk-6V5OPIUU.js";
26
26
  import {
27
27
  hook_decision,
28
28
  lane_child_marker
29
- } from "./chunk-KQG4776P.js";
29
+ } from "./chunk-GBJUERYK.js";
30
30
  import {
31
31
  PROJECT_ROOT,
32
+ json_value,
32
33
  stamp_file,
33
34
  time_density_hook,
34
- time_hook_transcript
35
- } from "./chunk-ZPLXLJ7O.js";
35
+ time_hook_transcript,
36
+ time_reported_failure
37
+ } from "./chunk-PAXMLGSS.js";
36
38
  import "./chunk-WPALEIRX.js";
37
39
  import "./chunk-RKUAD3I6.js";
38
40
 
@@ -329,6 +331,17 @@ function bare_references(message2) {
329
331
  for (const line of prose_lines(message2)) collect_line_references(line, found);
330
332
  return [...new Set(found)];
331
333
  }
334
+ function prompt_references(prompt) {
335
+ const found = /* @__PURE__ */ new Set();
336
+ for (const match of prompt.matchAll(ISSUE_NUMBER)) {
337
+ found.add(repo_prefix(prompt, match.index) + match[0]);
338
+ }
339
+ return found;
340
+ }
341
+ function unquoted_references(message2, prompt) {
342
+ const quoted = prompt_references(prompt);
343
+ return bare_references(message2).filter((reference) => !quoted.has(reference));
344
+ }
332
345
  function has_bare_reference(message2) {
333
346
  return bare_references(message2).length > 0;
334
347
  }
@@ -366,7 +379,14 @@ function linkify(message2, slug) {
366
379
  }
367
380
  return out.join("\n");
368
381
  }
369
- var issue_citation = { bare_references, cite_arguments, has_bare_reference, linkify, prose_lines };
382
+ var issue_citation = {
383
+ bare_references,
384
+ cite_arguments,
385
+ has_bare_reference,
386
+ linkify,
387
+ prose_lines,
388
+ unquoted_references
389
+ };
370
390
 
371
391
  // scripts/epic/epic-triage.ts
372
392
  var TRIAGE_VERDICT = "triage";
@@ -684,6 +704,8 @@ var TASK_DEFINITIONS = {
684
704
  stalled: { icon: "\u23F3", label: "Ready work is sitting undispatched" },
685
705
  stranded: { icon: "\u{1F6A8}", label: "Run stranded \u2014 nobody is driving it" }
686
706
  };
707
+ var NOTIFY_SWITCH_KEY = "JOSH_NOTIFY";
708
+ var NOTIFY_OFF_VALUE = "off";
687
709
  var NOT_CONFIGURED_PREFIX = "Telegram is not configured";
688
710
  var SEND_FAILED_PREFIX = "Telegram notification failed";
689
711
  var REDACTED = "<redacted>";
@@ -720,6 +742,9 @@ function load_config() {
720
742
  }
721
743
  return { bot_token: result.data.telegram_bot_token, chat_id: result.data.telegram_chat_id };
722
744
  }
745
+ function is_notify_disabled() {
746
+ return parse_environment_string(process.env[NOTIFY_SWITCH_KEY]).toLowerCase() === NOTIFY_OFF_VALUE;
747
+ }
723
748
  function build_header(task_type, repo_name) {
724
749
  const { icon, label: label2 } = TASK_DEFINITIONS[task_type];
725
750
  if (repo_name === void 0 || repo_name.length === 0) return `${icon} ${label2}`;
@@ -767,6 +792,12 @@ function build_send_failure(error, config) {
767
792
  return new Error(`${SEND_FAILED_PREFIX}: ${reason}`, { cause: new Error(reason) });
768
793
  }
769
794
  async function send(input) {
795
+ if (is_notify_disabled()) {
796
+ console.info(
797
+ `\u{1F515} Telegram notifications are disabled (${NOTIFY_SWITCH_KEY}=${NOTIFY_OFF_VALUE}).`
798
+ );
799
+ return;
800
+ }
770
801
  const config = load_config();
771
802
  const text2 = build_text(input);
772
803
  try {
@@ -1038,8 +1069,48 @@ async function run_stall_check(ready = backlog_ready.DEFAULT_PORTS) {
1038
1069
  }
1039
1070
  var backlog_stalled_detect = { DEFAULT_PORTS: DEFAULT_PORTS2, detect_and_report, gather, report, run_stall_check };
1040
1071
 
1041
- // scripts/rules/stop-rules.ts
1072
+ // scripts/rules/last-prompt.ts
1042
1073
  import { z as z3 } from "zod";
1074
+ var WORKFLOW_KEYWORDS = /* @__PURE__ */ new Set([
1075
+ "kickoff",
1076
+ "fullrun",
1077
+ "halfrun",
1078
+ "backlogrun"
1079
+ ]);
1080
+ var NO_PROMPT = "";
1081
+ var HUMAN_ORIGIN = "human";
1082
+ var KEYWORD_BEFORE_ARGUMENT = -2;
1083
+ var PROMPT_LINE_SCHEMA = z3.object({
1084
+ isMeta: z3.boolean().nullish(),
1085
+ origin: z3.object({ kind: z3.string().nullish() }).nullish(),
1086
+ message: z3.object({ content: z3.unknown() })
1087
+ });
1088
+ function is_person(line) {
1089
+ if (line.isMeta === true) return false;
1090
+ return line.origin === null || line.origin === void 0 || line.origin.kind === HUMAN_ORIGIN;
1091
+ }
1092
+ function person_text(line) {
1093
+ const parsed = PROMPT_LINE_SCHEMA.safeParse(json_value.parse_or_undefined(line));
1094
+ if (!parsed.success || !is_person(parsed.data)) return void 0;
1095
+ return time_reported_failure.result_text(parsed.data.message.content);
1096
+ }
1097
+ function is_invocation(prompt) {
1098
+ const words = prompt.trim().split(/\s+/u);
1099
+ return [words.at(0), words.at(KEYWORD_BEFORE_ARGUMENT)].some(
1100
+ (word) => WORKFLOW_KEYWORDS.has(word ?? NO_PROMPT)
1101
+ );
1102
+ }
1103
+ function prompt_line_text(line) {
1104
+ return filing_cap.is_prompt_line(line) ? person_text(line) : void 0;
1105
+ }
1106
+ function prompt_text(tail) {
1107
+ const text2 = tail.split("\n").map((line) => prompt_line_text(line)).findLast((one) => one !== void 0);
1108
+ return text2 === void 0 || is_invocation(text2) ? NO_PROMPT : text2;
1109
+ }
1110
+ var last_prompt = { prompt_text };
1111
+
1112
+ // scripts/rules/stop-rules.ts
1113
+ import { z as z4 } from "zod";
1043
1114
 
1044
1115
  // scripts/rules/filing-offer.ts
1045
1116
  var OFFER_PATTERNS = [
@@ -1147,10 +1218,10 @@ var reply_language = { MIN_PROSE_LETTERS, is_mismatch, script_of };
1147
1218
  // scripts/rules/stop-rules.ts
1148
1219
  var SWITCH_ENV_KEY = "JOSH_STOP_GUARD";
1149
1220
  var BLOCK_DECISION = "block";
1150
- var stop_payload_schema = z3.object({
1151
- transcript_path: z3.string().min(1),
1152
- stop_hook_active: z3.boolean().nullish(),
1153
- last_assistant_message: z3.string().nullish()
1221
+ var stop_payload_schema = z4.object({
1222
+ transcript_path: z4.string().min(1),
1223
+ stop_hook_active: z4.boolean().nullish(),
1224
+ last_assistant_message: z4.string().nullish()
1154
1225
  });
1155
1226
  var NO_OUTCOME = { reason: void 0 };
1156
1227
  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.';
@@ -1161,7 +1232,7 @@ function build_citation_reason(references) {
1161
1232
  const command = `pnpm josh issue:cite ${issue_citation.cite_arguments(references).join(" ")}`;
1162
1233
  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}`;
1163
1234
  }
1164
- var FILING_OFFER_REASON = '\u26D4 filing offer: your reply offers to file an Issue instead of filing it. Filing into a first-party repository is Tier A \u2014 the trigger is the judgement that it is worth filing, not the run\'s progress (`.claude/skills/workflow-commands/SKILL.md` \u2192 \xA72i, `observation-filing.md`). Run `pnpm josh issue:scout "<title>"`, file it, run `pnpm josh epic:bundle <new>`, then end with the one-line citation of what was filed \u2014 do not repeat your previous reply. If it is not worth filing after all, say so in one line instead.';
1235
+ var FILING_OFFER_REASON = '\u26D4 filing offer: your reply offers to file an Issue instead of filing it. Filing into a first-party repository is Tier A \u2014 the trigger is the judgement that it is worth filing, not the run\'s progress (`.claude/skills/workflow-commands/SKILL.md` \u2192 \xA72i, `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.';
1165
1236
  var HEADLESS_WAIT_MARKER = "\u26D4 headless parent:";
1166
1237
  var HEADLESS_REFUSAL_CAP = 3;
1167
1238
  var HEADLESS_WAIT_CALLS = ['"command":"pnpm josh lane:await', '"command":"pnpm josh run:progress'];
@@ -1199,14 +1270,14 @@ function needs_notify(context) {
1199
1270
  function needs_release(context) {
1200
1271
  return is_held_idle(context) && context.tree_clean;
1201
1272
  }
1202
- function citation_reason(message2) {
1203
- const references = issue_citation.bare_references(message2);
1273
+ function citation_reason(context) {
1274
+ const references = issue_citation.unquoted_references(context.message, context.prompt);
1204
1275
  if (references.length === 0) return void 0;
1205
1276
  return build_citation_reason(references);
1206
1277
  }
1207
1278
  function reply_reason(context) {
1208
1279
  if (needs_filing(context)) return FILING_OFFER_REASON;
1209
- return citation_reason(context.message) ?? language_reason(context);
1280
+ return citation_reason(context) ?? language_reason(context);
1210
1281
  }
1211
1282
  function is_headless_held(context) {
1212
1283
  if (!context.headless_waiting) return false;
@@ -1302,7 +1373,7 @@ var run_stranded = {
1302
1373
  };
1303
1374
 
1304
1375
  // scripts/run/run-wake.ts
1305
- import { z as z4 } from "zod";
1376
+ import { z as z5 } from "zod";
1306
1377
  var WAKE_PREFIX = "josh-run-wake-";
1307
1378
  var WAKE_LOG_PREFIX = "josh-run-wake-log-";
1308
1379
  var WAKE_LOG_SUFFIX = ".log";
@@ -1322,21 +1393,21 @@ var STOP_REASONS = {
1322
1393
  expired: "expired",
1323
1394
  unreadable: "unreadable"
1324
1395
  };
1325
- var run_wake_schema = z4.object({
1326
- invocation: z4.string(),
1327
- started_at: z4.string(),
1328
- pid: z4.number(),
1329
- process_start: z4.string().optional(),
1330
- woke: z4.number(),
1331
- woke_at: z4.string().optional(),
1396
+ var run_wake_schema = z5.object({
1397
+ invocation: z5.string(),
1398
+ started_at: z5.string(),
1399
+ pid: z5.number(),
1400
+ process_start: z5.string().optional(),
1401
+ woke: z5.number(),
1402
+ woke_at: z5.string().optional(),
1332
1403
  // **Every optional field of `RunWake` has to be listed here.** `z.object` strips what it does not
1333
1404
  // declare, so a field added to the interface alone round-trips through disk as `undefined` — which
1334
1405
  // reads as "no attempt has been made yet" and would restart the retry count on every pass.
1335
- attempts: z4.number().optional(),
1336
- woke_pid: z4.number().optional(),
1337
- held_at: z4.string().optional(),
1338
- spawned: z4.array(z4.string()).optional(),
1339
- idle_since: z4.string().optional(),
1406
+ attempts: z5.number().optional(),
1407
+ woke_pid: z5.number().optional(),
1408
+ held_at: z5.string().optional(),
1409
+ spawned: z5.array(z5.string()).optional(),
1410
+ idle_since: z5.string().optional(),
1340
1411
  profile: agent_role_profile.PROFILE_SCHEMA.optional()
1341
1412
  });
1342
1413
  function is_overdue(marked_at, now, limit_ms = WAKE_GRACE_MS) {
@@ -1585,6 +1656,7 @@ async function build_context(transcript_path, payload_tail) {
1585
1656
  tree_clean: !await run_hold.is_tree_dirty(),
1586
1657
  notified: lane_park.mentions_confirmation_notify(tail),
1587
1658
  message: payload_tail.message,
1659
+ prompt: last_prompt.prompt_text(tail),
1588
1660
  stop_hook_active: payload_tail.stop_hook_active,
1589
1661
  cut_pending: run_cut.carried_cut_sync() !== void 0,
1590
1662
  filed: was_filed(tail),
package/dist/josh.js CHANGED
@@ -447,6 +447,16 @@ var ISSUE_COMMANDS = {
447
447
  description: "Post one comment to an issue from a file, so no shell expands the body",
448
448
  category: "AI tools",
449
449
  reference: ["<issue> --body <text> | --body-file <path>", "automation", ["network"]]
450
+ },
451
+ "issue:file": {
452
+ script: "scripts/issue/issue-file-cli.ts",
453
+ description: "File an Issue with every filing step: lint, Origin, duplicate scout, labels, then epic:bundle",
454
+ category: "AI tools",
455
+ reference: [
456
+ "<title> --body-file <path> --depth <0|1|2> [--route <route>] [--label <name>] [--repo <owner/repo>] [--distinct <N,\u2026>]",
457
+ "automation",
458
+ ["network"]
459
+ ]
450
460
  }
451
461
  };
452
462
 
@@ -859,7 +869,7 @@ var DEV_COMMANDS = {
859
869
  },
860
870
  lint: {
861
871
  script: "scripts/lint/lint-parallel.ts",
862
- description: "Check code with prettier and eslint (skips a tool a static project lacks)",
872
+ description: "Check code with prettier and eslint (skips a tool a basic project lacks)",
863
873
  category: "Development",
864
874
  reference: ["", "developer", ["processes"]]
865
875
  },
@@ -895,7 +905,7 @@ var DEV_COMMANDS = {
895
905
  },
896
906
  format: {
897
907
  script: "scripts/lint/format.ts",
898
- description: "Format code with prettier and eslint (skips a tool a static project lacks)",
908
+ description: "Format code with prettier and eslint (skips a tool a basic project lacks)",
899
909
  category: "Development",
900
910
  reference: ["", "developer", ["files", "processes"]]
901
911
  },
@@ -1008,7 +1018,7 @@ var DEV_COMMANDS = {
1008
1018
  },
1009
1019
  check: {
1010
1020
  script: "scripts/gate/type-check-command.ts",
1011
- description: "Type-check with tsc (skips a static project with no TypeScript to check)",
1021
+ description: "Type-check with tsc (skips a basic project with no TypeScript to check)",
1012
1022
  category: "Development",
1013
1023
  reference: ["[arguments...]", "developer", ["processes"]]
1014
1024
  },
@@ -1163,7 +1173,7 @@ var MAINTENANCE_COMMANDS = {
1163
1173
  };
1164
1174
 
1165
1175
  // scripts/josh/josh-commands-project.ts
1166
- var PROFILE_ARGUMENTS = "[--profile static|node]";
1176
+ var PROFILE_ARGUMENTS = "[--profile basic|full]";
1167
1177
  var PROJECT_COMMANDS = {
1168
1178
  profile: {
1169
1179
  script: "scripts/init/project-profile-cli.ts",
@@ -1173,7 +1183,7 @@ var PROJECT_COMMANDS = {
1173
1183
  },
1174
1184
  start: {
1175
1185
  script: "scripts/init/start.ts",
1176
- description: "Create a new project for the GitHub Issue workflow, from git init to labels",
1186
+ description: "Set a project up for the GitHub Issue workflow, from git init to the setup PR",
1177
1187
  category: "Project",
1178
1188
  reference: [
1179
1189
  `${PROFILE_ARGUMENTS} [--yes] [--github] [--public]`,
@@ -1225,7 +1235,11 @@ var PROJECT_COMMANDS = {
1225
1235
  script: "scripts/propagate/propagate.ts",
1226
1236
  description: "Carry the published release into every consumer repository next to this one",
1227
1237
  category: "Project",
1228
- reference: ["[--dry-run] [--skip-publish-wait]", "maintainer", ["files", "network"]]
1238
+ reference: [
1239
+ "[--dry-run] [--skip-publish-wait] [--target <repo>]",
1240
+ "maintainer",
1241
+ ["files", "network"]
1242
+ ]
1229
1243
  },
1230
1244
  adopt: {
1231
1245
  script: "scripts/adopt/adopt.ts",
@@ -1472,6 +1486,7 @@ var ALIASES = {
1472
1486
  ird: "issue:read",
1473
1487
  ist: "issue:state",
1474
1488
  isc: "issue:scout",
1489
+ ifl: "issue:file",
1475
1490
  isf: "issue:fold",
1476
1491
  isfe: "issue:fold-existing",
1477
1492
  dfr: "defect:rate",
package/package.json CHANGED
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "1.978.0",
2
+ "version": "1.998.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": [
@@ -97,6 +97,10 @@
97
97
  "types": "./prettier/index.d.ts",
98
98
  "default": "./prettier/index.js"
99
99
  },
100
+ "./prettier/basic": {
101
+ "types": "./prettier/basic.d.ts",
102
+ "default": "./prettier/basic.js"
103
+ },
100
104
  "./prettier/static": {
101
105
  "types": "./prettier/static.d.ts",
102
106
  "default": "./prettier/static.js"
@@ -0,0 +1,3 @@
1
+ import type { Config } from 'prettier'
2
+
3
+ export const config: Config
@@ -0,0 +1,10 @@
1
+ export const config = {
2
+ useTabs: true,
3
+ singleQuote: true,
4
+ trailingComma: 'all',
5
+ printWidth: 100,
6
+ semi: false,
7
+ arrowParens: 'always',
8
+ bracketSpacing: true,
9
+ endOfLine: 'lf',
10
+ }
package/prettier/index.js CHANGED
@@ -1,7 +1,7 @@
1
- import { config as static_config } from './static.js'
1
+ import { config as basic_config } from './basic.js'
2
2
 
3
3
  export const config = {
4
- ...static_config,
4
+ ...basic_config,
5
5
  plugins: [
6
6
  '@ianvs/prettier-plugin-sort-imports',
7
7
  'prettier-plugin-svelte',
@@ -1,10 +1,3 @@
1
- export const config = {
2
- useTabs: true,
3
- singleQuote: true,
4
- trailingComma: 'all',
5
- printWidth: 100,
6
- semi: false,
7
- arrowParens: 'always',
8
- bracketSpacing: true,
9
- endOfLine: 'lf',
10
- }
1
+ // The basic profile's preset under the name it had before joshuafolkken/kit#2829. A project
2
+ // initialized earlier imports this path from its `prettier.config.mjs`, so it stays exported.
3
+ export { config } from './basic.js'
@@ -12,18 +12,18 @@
12
12
 
13
13
  **Issue を新規に起票した直後**に、既存の open Issue を調べる。`kickoff` / `fullrun` / `halfrun` が起票したとき、および実装中に Tier A で起票したとき(`backlogrun` 実行中を含む)。
14
14
 
15
- `pnpm josh epic:bundle <N>`(エイリアス `eb`)が候補を探して推奨を表示する。**このコマンドは何も書き込まない** — 候補を出すのが機械、束ねるかを決めるのは AI である。
15
+ `pnpm josh epic:bundle <N>`(エイリアス `eb`)が候補を探して推奨を表示する。起票は `pnpm josh issue:file` で行い、このコマンドが最終段として `epic:bundle` を実行して答えを表示するので、別に呼ぶのは `⚠` で再実行を案内されたときだけである。**このコマンドは何も書き込まない** — 候補を出すのが機械、束ねるかを決めるのは AI である。
16
16
 
17
17
  ### 起票の「前」に答えるのは `issue:scout`
18
18
 
19
19
  `pnpm josh issue:scout "<title>"`(エイリアス `isc`)は、まだ存在しない Issue について同じ配属先の問いに答える(joshuafolkken/kit#1252)。**配属の判定は `epic:bundle` のものをそのまま呼んでおり、実装は 1 つしかない。** 加えて、`epic:bundle` が意図的に採らないシグナル — タイトルの語の重なりによる**重複候補** — を返す。既存 Issue の束ね直しに似た見出しが立つのは強シグナルだけで十分だからだが、「もう起票されていないか」は起票前にしか意味を持たない別の問いであり、しきい値を混ぜていない。
20
20
 
21
- **両方を実行する。順番が違うだけである。**
21
+ **両方を実行する。順番が違うだけである。** どちらも `pnpm josh issue:file` が 1 回の呼び出しの中で実行する。
22
22
 
23
- | いつ | コマンド | 何について答えるか |
24
- | -------------------------- | ----------------------- | -------------------------------------------------- |
25
- | `gh api … issues` の**前** | `issue:scout "<title>"` | まだ番号を持たない下書き。タイトルと要約だけがある |
26
- | 起票の**直後** | `epic:bundle <N>` | 実在する Issue。番号と、それに記録された関係がある |
23
+ | いつ | コマンド | 何について答えるか |
24
+ | -------------- | ----------------------- | -------------------------------------------------- |
25
+ | 起票の**前** | `issue:scout "<title>"` | まだ番号を持たない下書き。タイトルと本文がある |
26
+ | 起票の**直後** | `epic:bundle <N>` | 実在する Issue。番号と、それに記録された関係がある |
27
27
 
28
28
  手順上の位置づけと、重複候補が見つかったときに起票せず止まる規則は `.claude/skills/workflow-commands/SKILL.md` → §2e が単一ソースである。
29
29
 
@@ -41,8 +41,8 @@
41
41
 
42
42
  **これは「レビューを CI と並走させる」ではない。**(ここで言うレビューは 1 周目のことであり、2 周目については下の段落で別に扱う。) joshuafolkken/kit#1216 の (b) は不採用と決定済みであり、却下の理由は規則ではなく仕組みである — あちらは**コードを変える作業**を CI と重ねるため、修正を push するたびに CI がやり直しになり、重ねた分をそのまま払い戻す。起票はコードを 1 行も変えないので、走っている CI がそのまま使える。**1 周目のレビュー**はコミットの前のままで、「コミット前セルフレビュー」は書き換えていない。**2 周目だけは CI と並走する**(joshuafolkken/kit#1261)— 同じ仕組みを逆から読んだ結果であり、2 周目は fix delta しか読まず、通常はコードを 1 行も変えない。変えた場合は同一ブランチへの追加コミット 1 つと CI のやり直し 1 回を払う。単一ソースは `.claude/skills/workflow-commands/chain-rule.md` → "The pull request opens between the rounds, so CI runs beside round 2"。
43
43
 
44
- 1. 残指摘を後追い Issue として起票し、現在の Issue を参照する
45
- 2. **現在の Issue が閉じる前に** `pnpm josh epic:bundle <新規>` を実行する。候補探索は open Issue しか読まないため、親が閉じた後では恒久的に `none` になる(joshuafolkken/kit#947)
44
+ 1. 残指摘を後追い Issue として起票し、現在の Issue を参照する。起票は `pnpm josh issue:file "<title>" --body-file <本文ファイル> --depth <n> --route review-cap` で行う
45
+ 2. **現在の Issue が閉じる前に**起票する。`issue:file` が新規 Issue について `epic:bundle` を実行する。候補探索は open Issue しか読まないため、親が閉じた後では恒久的に `none` になる(joshuafolkken/kit#947)
46
46
  3. 答えに従う。**`epic:bundle` は推奨するだけで何も書き込まない**ので、「実行する」とは書き込みコマンドを自分で打つことである。**epic 本文の手編集は禁止** — タスクリストと `blocked-by` が食い違い、`epic:next` が `error` を返す
47
47
 
48
48
  | 答え | すること | Tier |
@@ -71,14 +71,14 @@ Issue には次の要素を必ず含める。
71
71
 
72
72
  - **起票前に不具合かどうかを必ず選ぶ。** `## 背景` の直下に、不具合なら `- 種別: 不具合`、非不具合なら `- 種別: 非不具合` を置く。両方の併記も省略も `pnpm josh issue:lint` が拒否する。故障を述べる本文でも単語から自動判定せず、起票者が判断する。振る舞い変更、機能改善、互換性の宣言はこの判断と併記できる
73
73
  - **不具合修正の Issue は `- 種別: 不具合` を宣言する。** この宣言がある Issue では、`pnpm josh git -y` が追加・変更したテストを修正前のツリー(merge-base)に当てて `pnpm josh test:red` で実行し、1 本も赤にならない(`green`)ときはコミットを拒否する。修正前でも緑の回帰テストは、報告された症状を再現していないためである(joshuafolkken/kit#2448)。回帰テストは、利用者が症状を見たのと同じ粒度で書く
74
- - **起票時の `bug` ラベルは本文の宣言から決める。** `pnpm josh issue:lint <本文ファイル>` の後、同じファイルを `gh api …/issues -F body=@<本文ファイル>` で送る。`labels:` に `bug` が含まれたら `-f 'labels[]=bug'` を同じ作成呼び出しに追加する。`depth`・`route` は併記する。`bugfix` は PR のリリース分類であり、Issue の `bug` の代わりにしない
75
- - **機能追加・機能改善は目的を本文で宣言する。** `## 背景` の直下に `- 目的: 機能追加` または `- 目的: 機能改善` を書く。`pnpm josh issue:lint <本文ファイル>` が `labels: enhancement` を返したら、同じ作成呼び出しに `-f 'labels[]=enhancement'` を付ける。不具合修正、文書のみ、依存更新、保守作業はタイトルの単語から推測して宣言しない。目的が曖昧なら起票文案の期待結果と受け入れ条件を具体化してから分類する
76
- - **互換性を壊す変更は影響を本文で宣言する。** 既存の利用者、API、設定の契約を変える場合は、`## 背景` の直下に `- 互換性: 破壊的変更` を書き、廃止対象と影響を説明する。移行措置や事前案内があっても破壊的変更なら宣言する。`pnpm josh issue:lint <本文ファイル>` が `labels: breaking-change` を返したら、同じ作成呼び出しに `-f 'labels[]=breaking-change'` を付ける。互換性を保つ変更には付けない。影響が曖昧なら起票文案で対象の利用者と契約を明確にしてから分類する
77
- - **`issue:lint` が返す分類ラベルをすべて起票時に指定する。** `bug`、`enhancement`、`breaking-change` は組み合わせて表示されることがある。`depth`・`route` など既存のラベルを残し、`labels: none` のときは分類ラベルを付けない。Issue が `enhancement` と `breaking-change` の両方を持つとき、PR のリリース分類は `breaking-change` 一つにする。Issue の目的の分類と PR のリリース分類を区別する
74
+ - **起票時の `bug` ラベルは本文の宣言から決める。** 起票は `pnpm josh issue:file "<title>" --body-file <本文ファイル> --depth <n>` で行い、このコマンドが `issue:lint` と同じ検査をしたうえで、`- 種別: 不具合` の宣言があれば `bug` ラベルを同じ作成リクエストに付ける。`depth`・`route` も同じ呼び出しで付く。`bugfix` は PR のリリース分類であり、Issue の `bug` の代わりにしない
75
+ - **機能追加・機能改善は目的を本文で宣言する。** `## 背景` の直下に `- 目的: 機能追加` または `- 目的: 機能改善` を書く。この宣言があれば `pnpm josh issue:file` が `enhancement` ラベルを同じ作成リクエストに付ける。不具合修正、文書のみ、依存更新、保守作業はタイトルの単語から推測して宣言しない。目的が曖昧なら起票文案の期待結果と受け入れ条件を具体化してから分類する
76
+ - **互換性を壊す変更は影響を本文で宣言する。** 既存の利用者、API、設定の契約を変える場合は、`## 背景` の直下に `- 互換性: 破壊的変更` を書き、廃止対象と影響を説明する。移行措置や事前案内があっても破壊的変更なら宣言する。この宣言があれば `pnpm josh issue:file` が `breaking-change` ラベルを同じ作成リクエストに付ける。互換性を保つ変更には付けない。影響が曖昧なら起票文案で対象の利用者と契約を明確にしてから分類する
77
+ - **本文が宣言する分類ラベルは `pnpm josh issue:file` がすべて起票時に付ける。** `bug`、`enhancement`、`breaking-change` は組み合わせて付くことがある。`depth`・`route` などのラベルと併せて 1 回の作成リクエストで付け、宣言が無いとき(`issue:lint` の `labels: none`)は分類ラベルを付けない。Issue が `enhancement` と `breaking-change` の両方を持つとき、PR のリリース分類は `breaking-change` 一つにする。Issue の目的の分類と PR のリリース分類を区別する
78
78
  - **`## 発火点`** には、その規則が破れる瞬間に最初に呼ばれるツールコール名を 1 つ書く。名前は `prompts/collaboration-workflow/rule-delivery.md` の配送表に載る、フックで配送可能なツール(`Bash` / `Edit` / `Read` / `Write` / `AskUserQuestion`)と突き合わせる。**表に無い名前**(そもそもツールコール名でない)と**不一致**(既知のツールだが配送できない)は区別して印字され、joshuafolkken/kit#2201 の「規則は正しいが名指ししたコールが実際に破れるコールの 1 つ後ろ」を起票時に検出する
79
79
  - **`## ベースライン`** は **「コマンド + 値」** で書く。``- `<測定コマンド>` → <現在の値>`` の形に限り、自然文だけの測定説明は受け付けない(再実行できないため)。マージ後に `pnpm josh measure:rerun` が同じコマンドをやり直し、**before / after の対**を印字する。値が動かなかったとき、反証された前提として `docs/maintainers/observations.md` に 1 行追記される(既存の append-only 台帳を使い、別の台帳は作らない)
80
80
  - **`## 再現`** は **「コマンド + 実際の出力」** で書く。コマンドを backtick、出力をフェンス(``` または ~~~)で囲む。自然文の「確認した」は再実行できないため受け付けない(`## ベースライン` と同じ理由)。読みだけの起票を起票時に弾くためである
81
- - **検査は `pnpm josh issue:lint <path>` が行う。** 対象判定・3 見出しの有無・発火点の配送可否・ベースラインが「コマンド + 値」か・再現が「コマンド + 実際の出力」かと、起票時に必要な分類ラベルを、起票前の本文ファイルからまとめて答える(未リントの起票は `pnpm josh rule:guard` が拒否する)
81
+ - **検査は `pnpm josh issue:lint <path>` が行う。** 対象判定・3 見出しの有無・発火点の配送可否・ベースラインが「コマンド + 値」か・再現が「コマンド + 実際の出力」かと、起票時に必要な分類ラベルを、起票前の本文ファイルからまとめて答える(`pnpm josh issue:file` は起票前に同じ検査を行い、問題があれば起票しない)
82
82
 
83
83
  ### 起票元へのバックリンク(`## Origin` / `## Upstream issues`)
84
84