@joshuafolkken/kit 1.983.0 → 1.1003.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 (102) hide show
  1. package/.claude/skills/workflow-commands/backlogrun-child.md +4 -5
  2. package/.claude/skills/workflow-commands/backlogrun-steps.md +1 -1
  3. package/.github/workflows/sonar-qube.yml +12 -2
  4. package/CLAUDE.md +2 -2
  5. package/README.md +30 -21
  6. package/dist/CLAUDE.md +2 -2
  7. package/dist/hooks/batch-guard.js +4 -4
  8. package/dist/hooks/{chunk-ZT65LR3U.js → chunk-4GDR2YTV.js} +4 -4
  9. package/dist/hooks/{chunk-ASUZGZFT.js → chunk-56LGMJJV.js} +2 -2
  10. package/dist/hooks/{chunk-LBXQHXMC.js → chunk-6PSTVOLH.js} +263 -74
  11. package/dist/hooks/{chunk-P3UX7SFN.js → chunk-A2H5I2VD.js} +2 -2
  12. package/dist/hooks/{chunk-ERXMJJOV.js → chunk-AWTFKKFW.js} +1 -1
  13. package/dist/hooks/{chunk-IM3KM25Y.js → chunk-EZLHXKJ6.js} +10 -7
  14. package/dist/hooks/{chunk-APVOACVT.js → chunk-GBJUERYK.js} +1 -1
  15. package/dist/hooks/{chunk-5JX6HXDX.js → chunk-KPZN42RT.js} +3 -3
  16. package/dist/hooks/{chunk-47SPMGOD.js → chunk-PAXMLGSS.js} +26 -7
  17. package/dist/hooks/{chunk-RFPHKU7C.js → chunk-WMIR5SNX.js} +3 -3
  18. package/dist/hooks/codex-hook-adapter.js +10 -10
  19. package/dist/hooks/duplicate-read-guard.js +5 -5
  20. package/dist/hooks/format-edited.js +2 -2
  21. package/dist/hooks/investigation-guard.js +5 -5
  22. package/dist/hooks/pretool-guard.js +9 -9
  23. package/dist/hooks/stop-guard.js +98 -26
  24. package/dist/josh.js +5 -5
  25. package/package.json +5 -1
  26. package/prettier/basic.d.ts +3 -0
  27. package/prettier/basic.js +10 -0
  28. package/prettier/index.js +2 -2
  29. package/prettier/static.js +3 -10
  30. package/prompts/sonar-hotspot-handling.md +6 -0
  31. package/prompts/testing-guide.md +1 -1
  32. package/scripts/agent/agent-diagnostics.ts +1 -0
  33. package/scripts/agent/agent-role-profile.ts +1 -1
  34. package/scripts/behavior/behavior-rules.ts +8 -1
  35. package/scripts/build/build-claude-md.ts +13 -4
  36. package/scripts/ci/pr-classification.ts +11 -2
  37. package/scripts/document/document-byte-budget.ts +1 -1
  38. package/scripts/gate/gate-steps.ts +1 -1
  39. package/scripts/gate/project-checks.ts +12 -11
  40. package/scripts/gate/type-check-command.ts +1 -1
  41. package/scripts/git/git-branch.ts +14 -3
  42. package/scripts/git/git-command.ts +5 -2
  43. package/scripts/git/git-issue.ts +13 -5
  44. package/scripts/git/git-pr.ts +16 -10
  45. package/scripts/git/git-preflight.ts +138 -0
  46. package/scripts/git/telegram-notify.ts +21 -0
  47. package/scripts/hooks/stop-guard.ts +2 -0
  48. package/scripts/init/basic-path-migration.ts +24 -0
  49. package/scripts/init/distributed-paths.ts +22 -0
  50. package/scripts/init/init-actions.ts +27 -19
  51. package/scripts/init/init-ai-copy.ts +86 -28
  52. package/scripts/init/{init-static.ts → init-basic.ts} +6 -6
  53. package/scripts/init/init-bootstrap.ts +4 -3
  54. package/scripts/init/init-install.ts +1 -1
  55. package/scripts/init/init-logic-templates.ts +1 -1
  56. package/scripts/init/init-logic.ts +1 -1
  57. package/scripts/init/init.ts +41 -19
  58. package/scripts/init/kit-setup-state.ts +30 -0
  59. package/scripts/init/kit-written-paths.ts +33 -0
  60. package/scripts/init/project-profile-cli.ts +15 -1
  61. package/scripts/init/project-profile.ts +41 -12
  62. package/scripts/init/session-language-environment.ts +83 -0
  63. package/scripts/init/start-exec.ts +28 -0
  64. package/scripts/init/start-plan.ts +35 -13
  65. package/scripts/init/start-prompt.ts +22 -8
  66. package/scripts/init/start-setup-pr.ts +138 -0
  67. package/scripts/init/start-steps.ts +30 -30
  68. package/scripts/init/start.ts +7 -3
  69. package/scripts/josh/__snapshots__/josh-command-map.test.ts.snap +3 -3
  70. package/scripts/josh/josh-commands-development.ts +3 -3
  71. package/scripts/josh/josh-commands-project.ts +2 -2
  72. package/scripts/lane/lane-leftover.ts +143 -0
  73. package/scripts/lane/lane-open.ts +14 -1
  74. package/scripts/lint/cspell-cached.ts +3 -3
  75. package/scripts/lint/format.ts +1 -1
  76. package/scripts/lint/lint-parallel.ts +2 -2
  77. package/scripts/propagate/propagate-steps.ts +14 -1
  78. package/scripts/rules/filing-cap.ts +1 -0
  79. package/scripts/rules/issue-citation.ts +30 -1
  80. package/scripts/rules/last-prompt.ts +79 -0
  81. package/scripts/rules/stop-rules.ts +5 -3
  82. package/scripts/run/run-hold.ts +3 -3
  83. package/scripts/run/run-preflight.ts +75 -5
  84. package/scripts/run/run-progress-cli.ts +14 -2
  85. package/scripts/safe-chain/ci-installer-pin.ts +19 -12
  86. package/scripts/safe-chain/project-config.ts +1 -1
  87. package/scripts/sync/sync-ai-files.ts +204 -0
  88. package/scripts/sync/sync.ts +48 -184
  89. package/scripts/test/josh-harness-environment.ts +1 -1
  90. package/scripts/test/pilot-files.ts +0 -1
  91. package/scripts/test/test-declared-changed.ts +1 -1
  92. package/scripts/test/test-declared-logic.ts +55 -14
  93. package/scripts/test/test-declared.ts +23 -11
  94. package/scripts/test/test-unit-guard.ts +6 -6
  95. package/scripts/time-runtime/time-shell.ts +36 -2
  96. package/scripts-ai/git-workflow.ts +10 -0
  97. package/templates/CLAUDE.basic.md +8 -0
  98. package/templates/workflows/ci.yml +27 -0
  99. /package/{templates/CLAUDE.static.md → dist/CLAUDE.basic.md} +0 -0
  100. /package/templates/{cursorrules.static → cursorrules.basic} +0 -0
  101. /package/templates/{pnpm-workspace.static.yaml → pnpm-workspace.basic.yaml} +0 -0
  102. /package/templates/{prettierignore.static → prettierignore.basic} +0 -0
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  lane_child_marker,
3
3
  run_issue_number
4
- } from "./chunk-APVOACVT.js";
4
+ } from "./chunk-GBJUERYK.js";
5
5
  import {
6
6
  PLATFORM_TEMP_ROOT,
7
7
  cost_blocks,
@@ -12,7 +12,7 @@ import {
12
12
  time_density_hook,
13
13
  time_shell,
14
14
  time_transcript_line
15
- } from "./chunk-47SPMGOD.js";
15
+ } from "./chunk-PAXMLGSS.js";
16
16
  import {
17
17
  ENV_FILE_NAME,
18
18
  LANE_SEAT_KEY,
@@ -124,6 +124,7 @@ var filing_cap = {
124
124
  ROW,
125
125
  current_turn,
126
126
  decide,
127
+ is_prompt_line,
127
128
  prior_filing_count,
128
129
  turn_filing_count
129
130
  };
@@ -263,8 +264,9 @@ var git_spawn = {
263
264
  async function branch() {
264
265
  return await git_spawn.read(["rev-parse", "--abbrev-ref", "HEAD"]);
265
266
  }
266
- async function status() {
267
- return await git_spawn.read(["status", PORCELAIN_FLAG, UNTRACKED_FILES_FLAG]);
267
+ async function status(directory) {
268
+ const location = directory === void 0 ? [] : ["-C", directory];
269
+ return await git_spawn.read([...location, "status", PORCELAIN_FLAG, UNTRACKED_FILES_FLAG]);
268
270
  }
269
271
  async function repository_root() {
270
272
  return await git_spawn.read(["rev-parse", "--show-toplevel"]);
@@ -606,9 +608,9 @@ function create_hold(target, issue, now = /* @__PURE__ */ new Date(), is_fullrun
606
608
  function create_halfrun_stop_hold(target, issue, now = /* @__PURE__ */ new Date()) {
607
609
  return stamp_file.create_stamp(target, { ...build_hold(issue, now), is_halfrun_stop: true });
608
610
  }
609
- async function is_tree_dirty() {
611
+ async function is_tree_dirty(directory) {
610
612
  try {
611
- const status2 = await git_command.status();
613
+ const status2 = await git_command.status(directory);
612
614
  return status2.trim() !== "";
613
615
  } catch {
614
616
  return true;
@@ -790,7 +792,7 @@ var IMPLEMENTATION_PHASE = "implementation";
790
792
  var PRE_GATE_PHASE = "pre-gate";
791
793
  var ANTHROPIC_PROVIDER = "anthropic";
792
794
  var OPENAI_PROVIDER = "openai";
793
- var OPENAI_MODEL = "gpt-6-sol";
795
+ var OPENAI_MODEL = "gpt-6.1-sol";
794
796
  var ANTHROPIC_MODEL = "claude-opus-5-5";
795
797
  var CODEX_SESSION_KEY = "CODEX_THREAD_ID";
796
798
  var DEFAULT_PROFILES = {
@@ -3660,6 +3662,7 @@ export {
3660
3662
  has_any_label,
3661
3663
  has_label_name,
3662
3664
  lane_park,
3665
+ repo_origin,
3663
3666
  repo_party,
3664
3667
  FULL_PAGE_QUERY,
3665
3668
  git_gh_api_path,
@@ -3,7 +3,7 @@ import {
3
3
  stamp_file,
4
4
  time_density_hook,
5
5
  time_hook_transcript
6
- } from "./chunk-47SPMGOD.js";
6
+ } from "./chunk-PAXMLGSS.js";
7
7
  import {
8
8
  josh_environment_file
9
9
  } from "./chunk-WPALEIRX.js";
@@ -1,12 +1,12 @@
1
1
  import {
2
2
  investigation_reads
3
- } from "./chunk-RFPHKU7C.js";
3
+ } from "./chunk-WMIR5SNX.js";
4
4
  import {
5
5
  lane_guard_policy
6
- } from "./chunk-ASUZGZFT.js";
6
+ } from "./chunk-56LGMJJV.js";
7
7
  import {
8
8
  hook_decision
9
- } from "./chunk-APVOACVT.js";
9
+ } from "./chunk-GBJUERYK.js";
10
10
 
11
11
  // scripts/delegation/investigation-guard.ts
12
12
  import { text } from "node:stream/consumers";
@@ -712,7 +712,7 @@ var DEV_COMMANDS = {
712
712
  },
713
713
  lint: {
714
714
  script: "scripts/lint/lint-parallel.ts",
715
- description: "Check code with prettier and eslint (skips a tool a static project lacks)",
715
+ description: "Check code with prettier and eslint (skips a tool a basic project lacks)",
716
716
  category: "Development",
717
717
  reference: ["", "developer", ["processes"]]
718
718
  },
@@ -748,7 +748,7 @@ var DEV_COMMANDS = {
748
748
  },
749
749
  format: {
750
750
  script: "scripts/lint/format.ts",
751
- description: "Format code with prettier and eslint (skips a tool a static project lacks)",
751
+ description: "Format code with prettier and eslint (skips a tool a basic project lacks)",
752
752
  category: "Development",
753
753
  reference: ["", "developer", ["files", "processes"]]
754
754
  },
@@ -861,7 +861,7 @@ var DEV_COMMANDS = {
861
861
  },
862
862
  check: {
863
863
  script: "scripts/gate/type-check-command.ts",
864
- description: "Type-check with tsc (skips a static project with no TypeScript to check)",
864
+ description: "Type-check with tsc (skips a basic project with no TypeScript to check)",
865
865
  category: "Development",
866
866
  reference: ["[arguments...]", "developer", ["processes"]]
867
867
  },
@@ -1016,7 +1016,7 @@ var MAINTENANCE_COMMANDS = {
1016
1016
  };
1017
1017
 
1018
1018
  // scripts/josh/josh-commands-project.ts
1019
- var PROFILE_ARGUMENTS = "[--profile static|node]";
1019
+ var PROFILE_ARGUMENTS = "[--profile basic|full]";
1020
1020
  var PROJECT_COMMANDS = {
1021
1021
  profile: {
1022
1022
  script: "scripts/init/project-profile-cli.ts",
@@ -1026,7 +1026,7 @@ var PROJECT_COMMANDS = {
1026
1026
  },
1027
1027
  start: {
1028
1028
  script: "scripts/init/start.ts",
1029
- description: "Create a new project for the GitHub Issue workflow, from git init to labels",
1029
+ description: "Set a project up for the GitHub Issue workflow, from git init to the setup PR",
1030
1030
  category: "Project",
1031
1031
  reference: [
1032
1032
  `${PROFILE_ARGUMENTS} [--yes] [--github] [--public]`,
@@ -1417,7 +1417,10 @@ var WHITESPACE_PATTERN = /\s+/u;
1417
1417
  var SEGMENT_PATTERN = /&&|\|\||;|\|/u;
1418
1418
  var PIPE_PATTERN = /(?<!\|)\|(?!\|)/u;
1419
1419
  var CHAIN_PATTERN = /&&|\|\||;/u;
1420
- var QUOTED_SPAN_PATTERN = /'[^']*'|"[^"]*"/gu;
1420
+ var QUOTED_SPAN_PATTERN = /\\[\s\S]|'[^']*'|"(?:\\[\s\S]|[^"\\])*"/gu;
1421
+ var HEREDOC_MARKER = /(?<!<)<<-?\s*(['"]?)(\w+)\1/u;
1422
+ var HEREDOC_DELIMITER_GROUP = 2;
1423
+ var LINE_BREAK = "\n";
1421
1424
  var PIPEFAIL_PATTERN = /\bset\s+-[a-z]*o\s+pipefail\b/u;
1422
1425
  var COMMAND_WORD_PATTERN = /^[\w./@:+][\w./@:+-]*$/u;
1423
1426
  var ASSIGNMENT_PATTERN = /^\w+=/u;
@@ -1453,8 +1456,23 @@ function command_segment(command) {
1453
1456
  function leading_word(command) {
1454
1457
  return segment_command(command_segment(command));
1455
1458
  }
1459
+ function open_heredoc(line, kept) {
1460
+ kept.push(line.replace(HEREDOC_MARKER, " "));
1461
+ return HEREDOC_MARKER.exec(line)?.[HEREDOC_DELIMITER_GROUP];
1462
+ }
1463
+ function close_heredoc(line, delimiter) {
1464
+ return line.trim() === delimiter ? void 0 : delimiter;
1465
+ }
1466
+ function without_heredoc_bodies(command) {
1467
+ const kept = [];
1468
+ const body = {};
1469
+ for (const line of command.split(LINE_BREAK)) {
1470
+ body.delimiter = body.delimiter === void 0 ? open_heredoc(line, kept) : close_heredoc(line, body.delimiter);
1471
+ }
1472
+ return kept.join(LINE_BREAK);
1473
+ }
1456
1474
  function unquoted(command) {
1457
- return command.replaceAll(QUOTED_SPAN_PATTERN, " ");
1475
+ return without_heredoc_bodies(command).replaceAll(QUOTED_SPAN_PATTERN, " ");
1458
1476
  }
1459
1477
  function discarded_commands(command) {
1460
1478
  const plain = unquoted(command);
@@ -3505,6 +3523,7 @@ export {
3505
3523
  time_bundle_call,
3506
3524
  time_format,
3507
3525
  cost_attribute,
3526
+ time_reported_failure,
3508
3527
  time_transcript_line,
3509
3528
  time_spans,
3510
3529
  time_round_trips,
@@ -1,16 +1,16 @@
1
1
  import {
2
2
  time_batch_guard
3
- } from "./chunk-ASUZGZFT.js";
3
+ } from "./chunk-56LGMJJV.js";
4
4
  import {
5
5
  hook_decision
6
- } from "./chunk-APVOACVT.js";
6
+ } from "./chunk-GBJUERYK.js";
7
7
  import {
8
8
  cost_blocks,
9
9
  cost_transcript,
10
10
  time_bundle_call,
11
11
  time_shell,
12
12
  time_spans
13
- } from "./chunk-47SPMGOD.js";
13
+ } from "./chunk-PAXMLGSS.js";
14
14
 
15
15
  // scripts/delegation/investigation-reads.ts
16
16
  import path from "node:path";
@@ -1,25 +1,25 @@
1
1
  #!/usr/bin/env tsx
2
2
  import {
3
3
  pretool_guard
4
- } from "./chunk-LBXQHXMC.js";
5
- import "./chunk-IM3KM25Y.js";
4
+ } from "./chunk-6PSTVOLH.js";
5
+ import "./chunk-EZLHXKJ6.js";
6
6
  import {
7
7
  build_envelope,
8
8
  compose_context,
9
9
  format_edited_payload
10
- } from "./chunk-ERXMJJOV.js";
10
+ } from "./chunk-AWTFKKFW.js";
11
11
  import "./chunk-3V37IID6.js";
12
- import "./chunk-P3UX7SFN.js";
13
- import "./chunk-5JX6HXDX.js";
14
- import "./chunk-ZT65LR3U.js";
15
- import "./chunk-RFPHKU7C.js";
16
- import "./chunk-ASUZGZFT.js";
12
+ import "./chunk-A2H5I2VD.js";
13
+ import "./chunk-KPZN42RT.js";
14
+ import "./chunk-4GDR2YTV.js";
15
+ import "./chunk-WMIR5SNX.js";
16
+ import "./chunk-56LGMJJV.js";
17
17
  import {
18
18
  hook_decision
19
- } from "./chunk-APVOACVT.js";
19
+ } from "./chunk-GBJUERYK.js";
20
20
  import {
21
21
  time_density_hook
22
- } from "./chunk-47SPMGOD.js";
22
+ } from "./chunk-PAXMLGSS.js";
23
23
  import "./chunk-WPALEIRX.js";
24
24
  import "./chunk-RKUAD3I6.js";
25
25
 
@@ -9,11 +9,11 @@ import {
9
9
  is_enabled,
10
10
  notice_refusal_path,
11
11
  refusal_path
12
- } from "./chunk-ZT65LR3U.js";
13
- import "./chunk-RFPHKU7C.js";
14
- import "./chunk-ASUZGZFT.js";
15
- import "./chunk-APVOACVT.js";
16
- import "./chunk-47SPMGOD.js";
12
+ } from "./chunk-4GDR2YTV.js";
13
+ import "./chunk-WMIR5SNX.js";
14
+ import "./chunk-56LGMJJV.js";
15
+ import "./chunk-GBJUERYK.js";
16
+ import "./chunk-PAXMLGSS.js";
17
17
  import "./chunk-WPALEIRX.js";
18
18
  import "./chunk-RKUAD3I6.js";
19
19
  export {
@@ -15,9 +15,9 @@ import {
15
15
  relative_to_root,
16
16
  resolve_invocations,
17
17
  select_invocation
18
- } from "./chunk-ERXMJJOV.js";
18
+ } from "./chunk-AWTFKKFW.js";
19
19
  import "./chunk-3V37IID6.js";
20
- import "./chunk-47SPMGOD.js";
20
+ import "./chunk-PAXMLGSS.js";
21
21
  import "./chunk-RKUAD3I6.js";
22
22
  export {
23
23
  ESLINT_DAEMON,
@@ -10,11 +10,11 @@ import {
10
10
  is_enabled,
11
11
  load_environment_file,
12
12
  refusal_path
13
- } from "./chunk-5JX6HXDX.js";
14
- import "./chunk-RFPHKU7C.js";
15
- import "./chunk-ASUZGZFT.js";
16
- import "./chunk-APVOACVT.js";
17
- import "./chunk-47SPMGOD.js";
13
+ } from "./chunk-KPZN42RT.js";
14
+ import "./chunk-WMIR5SNX.js";
15
+ import "./chunk-56LGMJJV.js";
16
+ import "./chunk-GBJUERYK.js";
17
+ import "./chunk-PAXMLGSS.js";
18
18
  import "./chunk-WPALEIRX.js";
19
19
  import "./chunk-RKUAD3I6.js";
20
20
  export {
@@ -3,16 +3,16 @@ import {
3
3
  pretool_guard,
4
4
  pretool_outcome,
5
5
  pretool_outcome_async
6
- } from "./chunk-LBXQHXMC.js";
7
- import "./chunk-IM3KM25Y.js";
6
+ } from "./chunk-6PSTVOLH.js";
7
+ import "./chunk-EZLHXKJ6.js";
8
8
  import "./chunk-3V37IID6.js";
9
- import "./chunk-P3UX7SFN.js";
10
- import "./chunk-5JX6HXDX.js";
11
- import "./chunk-ZT65LR3U.js";
12
- import "./chunk-RFPHKU7C.js";
13
- import "./chunk-ASUZGZFT.js";
14
- import "./chunk-APVOACVT.js";
15
- import "./chunk-47SPMGOD.js";
9
+ import "./chunk-A2H5I2VD.js";
10
+ import "./chunk-KPZN42RT.js";
11
+ import "./chunk-4GDR2YTV.js";
12
+ import "./chunk-WMIR5SNX.js";
13
+ import "./chunk-56LGMJJV.js";
14
+ import "./chunk-GBJUERYK.js";
15
+ import "./chunk-PAXMLGSS.js";
16
16
  import "./chunk-WPALEIRX.js";
17
17
  import "./chunk-RKUAD3I6.js";
18
18
  export {
@@ -19,20 +19,22 @@ import {
19
19
  run_hold,
20
20
  run_invocation,
21
21
  run_watcher_guard
22
- } from "./chunk-IM3KM25Y.js";
22
+ } from "./chunk-EZLHXKJ6.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-APVOACVT.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-47SPMGOD.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.';
@@ -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
@@ -869,7 +869,7 @@ var DEV_COMMANDS = {
869
869
  },
870
870
  lint: {
871
871
  script: "scripts/lint/lint-parallel.ts",
872
- 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)",
873
873
  category: "Development",
874
874
  reference: ["", "developer", ["processes"]]
875
875
  },
@@ -905,7 +905,7 @@ var DEV_COMMANDS = {
905
905
  },
906
906
  format: {
907
907
  script: "scripts/lint/format.ts",
908
- 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)",
909
909
  category: "Development",
910
910
  reference: ["", "developer", ["files", "processes"]]
911
911
  },
@@ -1018,7 +1018,7 @@ var DEV_COMMANDS = {
1018
1018
  },
1019
1019
  check: {
1020
1020
  script: "scripts/gate/type-check-command.ts",
1021
- 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)",
1022
1022
  category: "Development",
1023
1023
  reference: ["[arguments...]", "developer", ["processes"]]
1024
1024
  },
@@ -1173,7 +1173,7 @@ var MAINTENANCE_COMMANDS = {
1173
1173
  };
1174
1174
 
1175
1175
  // scripts/josh/josh-commands-project.ts
1176
- var PROFILE_ARGUMENTS = "[--profile static|node]";
1176
+ var PROFILE_ARGUMENTS = "[--profile basic|full]";
1177
1177
  var PROJECT_COMMANDS = {
1178
1178
  profile: {
1179
1179
  script: "scripts/init/project-profile-cli.ts",
@@ -1183,7 +1183,7 @@ var PROJECT_COMMANDS = {
1183
1183
  },
1184
1184
  start: {
1185
1185
  script: "scripts/init/start.ts",
1186
- 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",
1187
1187
  category: "Project",
1188
1188
  reference: [
1189
1189
  `${PROFILE_ARGUMENTS} [--yes] [--github] [--public]`,
package/package.json CHANGED
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "1.983.0",
2
+ "version": "1.1003.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'
@@ -17,6 +17,12 @@ comments), but it **does** wait on the required `SonarQube` CI check, so a red g
17
17
  `followup` merge. Consumers pick the workflow up verbatim via `josh sync`; do not re-implement the
18
18
  gate per consumer.
19
19
 
20
+ **A run that cannot see `SONAR_TOKEN` skips the scan and passes**, printing one line that names the
21
+ missing token (joshuafolkken/kit#2815) — a consumer that does not use SonarCloud is never blocked by
22
+ it. The same holds for any run GitHub withholds secrets from (a fork pull request, or a Dependabot
23
+ run without the secret in the Dependabot store), so a repository that relies on this gate keeps
24
+ `SONAR_TOKEN` in both secret stores.
25
+
20
26
  ### New Code vs Overall Code semantics
21
27
 
22
28
  SonarCloud's default **Sonar way** Quality Gate evaluates **New Code only** — conditions