@joshuafolkken/kit 1.1229.0 → 1.1240.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 (67) hide show
  1. package/.claude/skills/workflow-commands/backlogrun-lanes.md +1 -1
  2. package/.claude/skills/workflow-commands/backlogrun-progress.md +2 -2
  3. package/.claude/skills/workflow-commands/followup.md +5 -0
  4. package/.claude/skills/workflow-commands/kickoff.md +1 -0
  5. package/.claude/skills/workflow-commands/latest-gate.md +1 -1
  6. package/.github/workflows/publish.yml +2 -0
  7. package/README.md +30 -31
  8. package/dist/hooks/batch-guard.js +4 -4
  9. package/dist/hooks/{chunk-JUDKDCDP.js → chunk-4TZVB44A.js} +8 -8
  10. package/dist/hooks/{chunk-RNWHN5BP.js → chunk-F3ELQ2AF.js} +3 -3
  11. package/dist/hooks/{chunk-VC3PZPZO.js → chunk-GPTFMK5E.js} +1 -1
  12. package/dist/hooks/{chunk-FIVDHQGT.js → chunk-KHGB5S3Y.js} +1 -1
  13. package/dist/hooks/{chunk-NV2JRZZO.js → chunk-KHX4U3BG.js} +17 -2
  14. package/dist/hooks/{chunk-F56MFS4B.js → chunk-KRBERBBI.js} +3 -3
  15. package/dist/hooks/{chunk-TQNPDZNH.js → chunk-QVSWU24O.js} +4 -4
  16. package/dist/hooks/{chunk-55HHG5PX.js → chunk-WK2XSHSI.js} +284 -63
  17. package/dist/hooks/{chunk-5VMKCCC4.js → chunk-XZYKEM6J.js} +2 -2
  18. package/dist/hooks/{chunk-6HJJXRBX.js → chunk-ZQGD4GBY.js} +1 -1
  19. package/dist/hooks/codex-hook-adapter.js +10 -10
  20. package/dist/hooks/duplicate-read-guard.js +5 -5
  21. package/dist/hooks/format-edited.js +2 -2
  22. package/dist/hooks/inputs.json +172 -170
  23. package/dist/hooks/investigation-guard.js +5 -5
  24. package/dist/hooks/pretool-guard.js +9 -9
  25. package/dist/hooks/stop-guard.js +3 -17
  26. package/dist/josh.js +279 -63
  27. package/package.json +1 -1
  28. package/prompts/collaboration-workflow/issue-template.md +1 -0
  29. package/scripts/gate/core-admission.ts +162 -0
  30. package/scripts/gate/core-budget.ts +121 -67
  31. package/scripts/gate/gate-plan.ts +35 -2
  32. package/scripts/gate/gate-report.ts +28 -9
  33. package/scripts/gate/machine-capacity.ts +175 -0
  34. package/scripts/gate/verification-gate.ts +7 -2
  35. package/scripts/init/init.ts +5 -1
  36. package/scripts/init/package-manager-pin.ts +35 -0
  37. package/scripts/issue/issue-auto-ok.ts +31 -6
  38. package/scripts/issue/issue-file-cli.ts +31 -8
  39. package/scripts/issue/issue-file.ts +5 -0
  40. package/scripts/issue/issue-labels.ts +13 -0
  41. package/scripts/issue/issue-release-cli.ts +155 -0
  42. package/scripts/issue/issue-release.ts +58 -0
  43. package/scripts/josh/josh-command-types.ts +3 -0
  44. package/scripts/josh/josh-commands-development.ts +8 -0
  45. package/scripts/josh/josh-commands-issue.ts +8 -1
  46. package/scripts/josh/josh-commands-lane.ts +2 -1
  47. package/scripts/josh/josh-commands-maintenance.ts +2 -2
  48. package/scripts/josh/josh-logic.ts +4 -3
  49. package/scripts/lane/lane-cli.ts +9 -1
  50. package/scripts/lane/lane-leftover.ts +43 -29
  51. package/scripts/lane/lane-open.ts +5 -5
  52. package/scripts/lane/lane-paths.ts +13 -0
  53. package/scripts/lane/lane-registry.ts +11 -0
  54. package/scripts/lane/lane-stray.ts +140 -0
  55. package/scripts/release/github-release-environment.ts +1 -0
  56. package/scripts/release/github-release-runs.ts +115 -0
  57. package/scripts/release/github-release.ts +13 -67
  58. package/scripts/run/cut/run-cut-cli.ts +16 -3
  59. package/scripts/run/event/run-event-render.ts +1 -0
  60. package/scripts/run/event/run-event-stream.ts +4 -0
  61. package/scripts/run/run-step.ts +5 -2
  62. package/scripts/run/wake/run-wake-cli.ts +2 -3
  63. package/scripts/run/wake/run-wake-describe.ts +56 -5
  64. package/scripts/run/wake/run-wake-loop.ts +5 -13
  65. package/scripts/run/wake/run-wake.ts +15 -64
  66. package/scripts/version/latest-corepack.ts +109 -78
  67. package/templates/workflows/github-release.yml +4 -0
package/dist/josh.js CHANGED
@@ -319,7 +319,7 @@ function resolve_package_bin(base_directory, package_name, bin_name) {
319
319
  // scripts/gate/core-budget.ts
320
320
  import { randomUUID as randomUUID3 } from "node:crypto";
321
321
  import { readdirSync as readdirSync2 } from "node:fs";
322
- import { availableParallelism as availableParallelism2 } from "node:os";
322
+ import { availableParallelism as availableParallelism3 } from "node:os";
323
323
  import path8 from "node:path";
324
324
 
325
325
  // scripts/josh/platform-temporary.ts
@@ -712,6 +712,159 @@ var unit_worker_share = {
712
712
 
713
713
  // scripts/gate/core-budget.ts
714
714
  import { z as z4 } from "zod";
715
+
716
+ // scripts/gate/core-admission.ts
717
+ var MS_PER_SECOND = 1e3;
718
+ var RAMP_UP_MS = 3e4;
719
+ function compare_claim(left, right) {
720
+ const by_time = left.reservation.claimed_at - right.reservation.claimed_at;
721
+ return by_time === 0 ? left.key.localeCompare(right.key) : by_time;
722
+ }
723
+ function add_load(totals, reservation) {
724
+ totals.cores += reservation.weight;
725
+ totals.memory_mb += reservation.memory_mb ?? 0;
726
+ }
727
+ function exceeds(totals, budget) {
728
+ return totals.cores > budget.cores || totals.memory_mb > budget.memory_mb;
729
+ }
730
+ function admitted_keys(reservations, budget, memory_budget = Infinity) {
731
+ const limit = { cores: budget, memory_mb: memory_budget };
732
+ const totals = { cores: 0, memory_mb: 0 };
733
+ const admitted = /* @__PURE__ */ new Set();
734
+ for (const [index, entry] of reservations.toSorted(compare_claim).entries()) {
735
+ add_load(totals, entry.reservation);
736
+ if (index !== 0 && exceeds(totals, limit)) break;
737
+ admitted.add(entry.key);
738
+ }
739
+ return admitted;
740
+ }
741
+ function is_admitted(key, reservations, budget) {
742
+ return admitted_keys(reservations, budget.cores, budget.memory_mb).has(key);
743
+ }
744
+ function sum_load(reservations) {
745
+ const load = { cores: 0, memory_mb: 0 };
746
+ for (const entry of reservations) add_load(load, entry.reservation);
747
+ return load;
748
+ }
749
+ function is_ramped(reservation, now) {
750
+ const { admitted_at } = reservation;
751
+ return admitted_at !== void 0 && now - admitted_at >= RAMP_UP_MS;
752
+ }
753
+ function ledger_load(reservations, now) {
754
+ const admitted = reservations.filter((entry) => entry.reservation.admitted_at !== void 0);
755
+ const ramped = admitted.filter((entry) => is_ramped(entry.reservation, now));
756
+ return { cores: sum_load(admitted).cores, memory_mb: sum_load(ramped).memory_mb };
757
+ }
758
+ function total_weight(reservations) {
759
+ return sum_load(reservations).cores;
760
+ }
761
+ function admitted_load(reservations, budget) {
762
+ const admitted = admitted_keys(reservations, budget);
763
+ return total_weight(reservations.filter((entry) => admitted.has(entry.key)));
764
+ }
765
+ function describe_memory(ledger, budget) {
766
+ if (!Number.isFinite(budget.memory_mb)) return "";
767
+ return ` and ${String(Math.round(ledger.memory_mb))} MB of memory against ${String(Math.round(budget.memory_mb))} MB`;
768
+ }
769
+ function describe_overflow(admission) {
770
+ const { overflow } = admission;
771
+ if (overflow === void 0) return void 0;
772
+ const { ledger, budget } = overflow;
773
+ const waited = String(Math.round(overflow.waited_ms / MS_PER_SECOND));
774
+ const cores = `the ledger held ${String(ledger.cores)} cores against a budget of ${String(budget.cores)}`;
775
+ return `started past the core budget after ${waited}s \u2014 ${cores}${describe_memory(ledger, budget)}`;
776
+ }
777
+ var core_admission = {
778
+ RAMP_UP_MS,
779
+ admitted_keys,
780
+ admitted_load,
781
+ describe_overflow,
782
+ is_admitted,
783
+ ledger_load,
784
+ sum_load
785
+ };
786
+
787
+ // scripts/gate/machine-capacity.ts
788
+ import { readFile } from "node:fs/promises";
789
+ import { availableParallelism as availableParallelism2, cpus, totalmem } from "node:os";
790
+ import { execa } from "execa";
791
+ var SAMPLE_WINDOW_MS = 250;
792
+ var BASELINE_CORES = 2;
793
+ var BYTES_PER_MB = 1048576;
794
+ var KB_PER_MB = 1024;
795
+ var PERCENT = 100;
796
+ var MEMINFO_PATH = "/proc/meminfo";
797
+ var LINUX_AVAILABLE = /^MemAvailable:\s+(?<kb>\d+) kB/mu;
798
+ var PRESSURE_ARGUMENTS = ["-n", "kern.memorystatus_level"];
799
+ var PRESSURE_LEVEL = /^\s*(?<level>\d+)\s*$/u;
800
+ function cpu_times() {
801
+ let busy = 0;
802
+ let idle = 0;
803
+ for (const { times } of cpus()) {
804
+ busy += times.user + times.nice + times.sys + times.irq;
805
+ idle += times.idle;
806
+ }
807
+ return { busy, total: busy + idle };
808
+ }
809
+ function busy_cores_between(before, after, cores) {
810
+ const total = after.total - before.total;
811
+ if (total <= 0) return void 0;
812
+ return (after.busy - before.busy) / total * cores;
813
+ }
814
+ function parse_darwin_pressure(output, total_bytes) {
815
+ const level = PRESSURE_LEVEL.exec(output)?.groups?.["level"];
816
+ if (level === void 0) return void 0;
817
+ return Number(level) / PERCENT * (total_bytes / BYTES_PER_MB);
818
+ }
819
+ function parse_linux_available(meminfo) {
820
+ const kb = LINUX_AVAILABLE.exec(meminfo)?.groups?.["kb"];
821
+ return kb === void 0 ? void 0 : Number(kb) / KB_PER_MB;
822
+ }
823
+ async function read_available_mb(platform2 = process.platform) {
824
+ try {
825
+ if (platform2 === "darwin") {
826
+ const { stdout } = await execa("sysctl", PRESSURE_ARGUMENTS);
827
+ return parse_darwin_pressure(stdout, totalmem());
828
+ }
829
+ return platform2 === "linux" ? parse_linux_available(await readFile(MEMINFO_PATH, "utf8")) : void 0;
830
+ } catch {
831
+ return void 0;
832
+ }
833
+ }
834
+ function is_unquoted() {
835
+ return cpus().length > 0 && cpus().length === availableParallelism2();
836
+ }
837
+ async function default_sleep(ms) {
838
+ await new Promise((resolve) => {
839
+ setTimeout(resolve, ms);
840
+ });
841
+ }
842
+ async function read_machine(sleep = default_sleep) {
843
+ const before = cpu_times();
844
+ const [available_mb] = await Promise.all([read_available_mb(), sleep(SAMPLE_WINDOW_MS)]);
845
+ const busy_cores = is_unquoted() ? busy_cores_between(before, cpu_times(), cpus().length) : void 0;
846
+ return { busy_cores, available_mb };
847
+ }
848
+ function external_cores(busy_cores, ledger_cores) {
849
+ if (busy_cores === void 0) return 0;
850
+ return Math.floor(Math.max(0, busy_cores - ledger_cores - BASELINE_CORES));
851
+ }
852
+ function machine_budget(cores, reading, ledger) {
853
+ return {
854
+ cores: cores - external_cores(reading.busy_cores, ledger.cores),
855
+ memory_mb: reading.available_mb === void 0 ? Infinity : reading.available_mb + ledger.memory_mb
856
+ };
857
+ }
858
+ var machine_capacity = {
859
+ BASELINE_CORES,
860
+ busy_cores_between,
861
+ machine_budget,
862
+ parse_darwin_pressure,
863
+ parse_linux_available,
864
+ read_machine
865
+ };
866
+
867
+ // scripts/gate/core-budget.ts
715
868
  var RESERVED_PREFIX = "josh-core-reserved-";
716
869
  var RESERVED_SUFFIX = ".json";
717
870
  var POLL_INTERVAL_MS = 50;
@@ -723,11 +876,20 @@ var CORE_WEIGHTS = {
723
876
  spell_check: 1,
724
877
  eslint_scan: 1
725
878
  };
879
+ var MEMORY_MB = {
880
+ lint: 2400,
881
+ type_check: 1300,
882
+ spell_check: 350,
883
+ eslint_scan: 2400,
884
+ unit_worker: 350
885
+ };
726
886
  var HELD_KEY = "JOSH_CORE_RESERVED";
727
887
  var HELD_VALUE = "1";
728
888
  var reservation_schema = process_owner_schema.extend({
729
889
  weight: z4.number(),
730
- claimed_at: z4.number()
890
+ claimed_at: z4.number(),
891
+ memory_mb: z4.number().optional(),
892
+ admitted_at: z4.number().optional()
731
893
  });
732
894
  function marker_name(key) {
733
895
  return `${RESERVED_PREFIX}${key}${RESERVED_SUFFIX}`;
@@ -760,7 +922,9 @@ function live_reservation(source) {
760
922
  }
761
923
  function marker_files2(directory) {
762
924
  try {
763
- return readdirSync2(directory).filter((name) => name.startsWith(RESERVED_PREFIX));
925
+ return readdirSync2(directory).filter(
926
+ (name) => name.startsWith(RESERVED_PREFIX) && name.endsWith(RESERVED_SUFFIX)
927
+ );
764
928
  } catch {
765
929
  return [];
766
930
  }
@@ -771,67 +935,79 @@ function live_reservations(directory = PLATFORM_TEMP_ROOT) {
771
935
  return reservation === void 0 ? [] : { key: name, reservation };
772
936
  });
773
937
  }
774
- function compare_claim(left, right) {
775
- const by_time = left.reservation.claimed_at - right.reservation.claimed_at;
776
- return by_time === 0 ? left.key.localeCompare(right.key) : by_time;
777
- }
778
- function admitted_keys(reservations, budget) {
779
- const admitted = /* @__PURE__ */ new Set();
780
- let cumulative = 0;
781
- for (const [index, entry] of reservations.toSorted(compare_claim).entries()) {
782
- cumulative += entry.reservation.weight;
783
- if (index !== 0 && cumulative > budget) break;
784
- admitted.add(entry.key);
785
- }
786
- return admitted;
787
- }
788
- function is_admitted(key, reservations, budget) {
789
- return admitted_keys(reservations, budget).has(key);
790
- }
791
- function admitted_load(reservations, budget) {
792
- const admitted = admitted_keys(reservations, budget);
793
- return reservations.filter((entry) => admitted.has(entry.key)).reduce((total, entry) => total + entry.reservation.weight, 0);
794
- }
795
938
  function normalize_budget(budget) {
796
939
  return Number.isFinite(budget) ? Math.max(MIN_BUDGET, Math.floor(budget)) : MIN_BUDGET;
797
940
  }
798
- async function default_sleep(ms) {
941
+ async function default_sleep2(ms) {
799
942
  await new Promise((resolve) => {
800
943
  setTimeout(resolve, ms);
801
944
  });
802
945
  }
803
- function write_reservation(target, weight, claimed_at) {
804
- stamp_file.write_stamp(target, { ...process_identity.own_fields(), weight, claimed_at });
946
+ function write_reservation(target, fields) {
947
+ stamp_file.replace_stamp(target, { ...process_identity.own_fields(), ...fields });
805
948
  }
806
949
  function resolve_timing(options) {
807
950
  return {
808
951
  now: options.now ?? Date.now,
809
- sleep: options.sleep ?? default_sleep,
810
- poll_interval_ms: options.poll_interval_ms ?? POLL_INTERVAL_MS
952
+ sleep: options.sleep ?? default_sleep2,
953
+ poll_interval_ms: options.poll_interval_ms ?? POLL_INTERVAL_MS,
954
+ wait_cap_ms: options.wait_cap_ms ?? WAIT_CAP_MS
811
955
  };
812
956
  }
957
+ async function current_budget(context, reservations) {
958
+ if (reservations.length <= 1) return { cores: context.budget, memory_mb: Infinity };
959
+ const reading = await context.read_machine();
960
+ const ledger = core_admission.ledger_load(reservations, context.now());
961
+ const budget = machine_capacity.machine_budget(context.budget, reading, ledger);
962
+ return { ...budget, cores: normalize_budget(budget.cores) };
963
+ }
964
+ function admit(context, overflow) {
965
+ write_reservation(context.target, { ...context.fields, admitted_at: context.now() });
966
+ return { overflow };
967
+ }
968
+ function overflow_of(context, reservations, budget) {
969
+ return {
970
+ waited_ms: context.now() - context.fields.claimed_at,
971
+ ledger: core_admission.sum_load(reservations),
972
+ budget
973
+ };
974
+ }
975
+ async function poll_admission(context) {
976
+ const reservations = live_reservations(context.directory);
977
+ const budget = await current_budget(context, reservations);
978
+ if (core_admission.is_admitted(context.key, reservations, budget)) return admit(context);
979
+ if (context.now() >= context.deadline) {
980
+ return admit(context, overflow_of(context, reservations, budget));
981
+ }
982
+ return void 0;
983
+ }
813
984
  async function await_admission(context) {
814
- while (!is_admitted(context.key, live_reservations(context.directory), context.budget)) {
815
- if (context.now() >= context.deadline) return;
985
+ let admission = await poll_admission(context);
986
+ while (admission === void 0) {
816
987
  await context.sleep(context.poll_interval_ms);
988
+ admission = await poll_admission(context);
817
989
  }
990
+ return admission;
818
991
  }
819
992
  async function reserve(weight, options = {}) {
820
993
  const timing = resolve_timing(options);
821
994
  const directory = options.directory ?? PLATFORM_TEMP_ROOT;
822
- const budget = normalize_budget(options.budget ?? availableParallelism2());
823
995
  const claimed_at = timing.now();
824
996
  const name = marker_name(randomUUID3());
825
997
  const target = path8.join(directory, name);
826
- write_reservation(target, weight, claimed_at);
827
- await await_admission({
998
+ const fields = { weight, claimed_at, memory_mb: options.memory_mb };
999
+ write_reservation(target, fields);
1000
+ const admission = await await_admission({
828
1001
  ...timing,
829
1002
  key: name,
1003
+ target,
830
1004
  directory,
831
- budget,
832
- deadline: claimed_at + (options.wait_cap_ms ?? WAIT_CAP_MS)
1005
+ budget: normalize_budget(options.budget ?? availableParallelism3()),
1006
+ deadline: claimed_at + timing.wait_cap_ms,
1007
+ fields,
1008
+ read_machine: options.read_machine ?? machine_capacity.read_machine
833
1009
  });
834
- return { target };
1010
+ return { target, admission };
835
1011
  }
836
1012
  function release(handle) {
837
1013
  sweep_marker2(handle.target);
@@ -839,7 +1015,7 @@ function release(handle) {
839
1015
  async function with_core_reservation(weight, run2, options = {}) {
840
1016
  const handle = await reserve(weight, options);
841
1017
  try {
842
- return await run2();
1018
+ return await run2(handle.admission);
843
1019
  } finally {
844
1020
  release(handle);
845
1021
  }
@@ -867,9 +1043,11 @@ var core_budget = {
867
1043
  CORE_WEIGHTS,
868
1044
  HELD_KEY,
869
1045
  HELD_VALUE,
1046
+ MEMORY_MB,
870
1047
  RESERVED_PREFIX,
871
- admitted_keys,
872
- admitted_load,
1048
+ admitted_keys: core_admission.admitted_keys,
1049
+ admitted_load: core_admission.admitted_load,
1050
+ describe_overflow: core_admission.describe_overflow,
873
1051
  is_held,
874
1052
  live_reservations,
875
1053
  release,
@@ -1116,10 +1294,16 @@ var ISSUE_COMMANDS = {
1116
1294
  description: "File an Issue with every filing step: lint, Origin, WIP cap, duplicate scout, labels, then epic:bundle",
1117
1295
  category: "AI tools",
1118
1296
  reference: [
1119
- "<title> --body-file <path> --depth <0|1|2> [--route <route>] [--label <name>] [--repo <owner/repo>] [--distinct <N,\u2026>] [--over-cap] [--no-auto-ok]",
1297
+ "<title> --body-file <path> --depth <0|1|2> [--route <route>] [--label <name>] [--repo <owner/repo>] [--distinct <N,\u2026>] [--over-cap] [--no-auto-ok] [--release]",
1120
1298
  "automation",
1121
1299
  ["network"]
1122
1300
  ]
1301
+ },
1302
+ "issue:release": {
1303
+ script: "scripts/issue/issue-release-cli.ts",
1304
+ description: "Link an Issue to the repository's open release Issue as its blocker, filing one when none is open",
1305
+ category: "AI tools",
1306
+ reference: ["<issue>", "automation", ["network"]]
1123
1307
  }
1124
1308
  };
1125
1309
 
@@ -1155,7 +1339,7 @@ var LANE_COMMANDS = {
1155
1339
  },
1156
1340
  "lane:prune": {
1157
1341
  ...LANE_ARGUMENTS,
1158
- description: "Close every lane an interruption left without its work tree",
1342
+ description: "Close every lane an interruption left without its work tree, then sweep unregistered leftovers under the lanes root",
1159
1343
  category: "AI tools",
1160
1344
  reference: ["", "automation", ["files", "git"]],
1161
1345
  default_script_arguments: ["prune"]
@@ -1546,7 +1730,7 @@ var CLONE_COMMANDS = {
1546
1730
  };
1547
1731
 
1548
1732
  // scripts/gate/gate-plan.ts
1549
- import { availableParallelism as availableParallelism3 } from "node:os";
1733
+ import { availableParallelism as availableParallelism4 } from "node:os";
1550
1734
 
1551
1735
  // scripts/lib/status-icons.ts
1552
1736
  var FAIL_ICON = "\u2717";
@@ -1596,13 +1780,24 @@ var UNIT_LABEL = "test:unit";
1596
1780
  var BEHAVIOR_LABEL = "behavior";
1597
1781
  var WARNING_CHECKER_LABELS = [LINT_LABEL, TYPE_CHECK_LABEL];
1598
1782
  var STATIC_CHECKS = [
1599
- { label: LINT_LABEL, target: "lint", reserved_cores: core_budget.CORE_WEIGHTS.lint },
1783
+ {
1784
+ label: LINT_LABEL,
1785
+ target: "lint",
1786
+ reserved_cores: core_budget.CORE_WEIGHTS.lint,
1787
+ memory_mb: core_budget.MEMORY_MB.lint
1788
+ },
1600
1789
  {
1601
1790
  label: TYPE_CHECK_LABEL,
1602
1791
  target: "check",
1603
- reserved_cores: core_budget.CORE_WEIGHTS.type_check
1792
+ reserved_cores: core_budget.CORE_WEIGHTS.type_check,
1793
+ memory_mb: core_budget.MEMORY_MB.type_check
1794
+ },
1795
+ {
1796
+ label: "cspell",
1797
+ target: "cspell:dot",
1798
+ reserved_cores: core_budget.CORE_WEIGHTS.spell_check,
1799
+ memory_mb: core_budget.MEMORY_MB.spell_check
1604
1800
  },
1605
- { label: "cspell", target: "cspell:dot", reserved_cores: core_budget.CORE_WEIGHTS.spell_check },
1606
1801
  { label: BEHAVIOR_LABEL, target: BEHAVIOR_LABEL, reserved_cores: 0 },
1607
1802
  // **The unused-member check reserves no core** (joshuafolkken/kit#2987): it builds one TypeScript
1608
1803
  // program and walks it for about 5s, and it is over well before lint and the type check. A
@@ -1655,14 +1850,24 @@ function check_weight(check, plan, available_cores) {
1655
1850
  if (check.label !== UNIT_LABEL) return check.reserved_cores;
1656
1851
  return plan.unit_worker_cap ?? solo_unit_weight(available_cores);
1657
1852
  }
1658
- function direct_unit_weight(available_cores = availableParallelism3(), live_runs = unit_worker_share.live_run_count()) {
1853
+ function unit_memory(workers) {
1854
+ return workers * core_budget.MEMORY_MB.unit_worker;
1855
+ }
1856
+ function check_memory(check, plan, available_cores) {
1857
+ if (check.label !== UNIT_LABEL) return check.memory_mb ?? 0;
1858
+ return unit_memory(check_weight(check, plan, available_cores));
1859
+ }
1860
+ function direct_unit_weight(available_cores = availableParallelism4(), live_runs = unit_worker_share.live_run_count()) {
1659
1861
  const weight = unit_worker_share.current_share(available_cores, live_runs) ?? solo_unit_weight(available_cores);
1660
1862
  return Math.max(unit_worker_share.MIN_WORKERS, weight);
1661
1863
  }
1864
+ function direct_unit_memory() {
1865
+ return unit_memory(direct_unit_weight());
1866
+ }
1662
1867
  function plan_of(concurrency, unit_worker_cap, checks = GATE_CHECKS) {
1663
1868
  return { checks, concurrency, unit_worker_cap };
1664
1869
  }
1665
- function resolve_gate_plan(available_cores = availableParallelism3(), concurrent_runs = unit_worker_share.SOLO_RUNS, is_unit_included = true) {
1870
+ function resolve_gate_plan(available_cores = availableParallelism4(), concurrent_runs = unit_worker_share.SOLO_RUNS, is_unit_included = true) {
1666
1871
  const checks = select_gate_checks(is_unit_included);
1667
1872
  return {
1668
1873
  checks,
@@ -1680,7 +1885,7 @@ function format_unit_cap(plan) {
1680
1885
  if (plan.unit_worker_cap === void 0) return `${UNIT_LABEL} unrestricted`;
1681
1886
  return `${UNIT_LABEL} at ${String(plan.unit_worker_cap)} workers`;
1682
1887
  }
1683
- function format_gate_plan(plan, available_cores = availableParallelism3(), concurrent_runs = unit_worker_share.SOLO_RUNS) {
1888
+ function format_gate_plan(plan, available_cores = availableParallelism4(), concurrent_runs = unit_worker_share.SOLO_RUNS) {
1684
1889
  const cap = format_unit_cap(plan);
1685
1890
  const count = `${String(plan.concurrency)} of ${String(plan.checks.length)}`;
1686
1891
  const width = `${count}${josh_verdict.GATE_OPENING_MARK}`;
@@ -1696,7 +1901,9 @@ var gate_plan = {
1696
1901
  TYPE_CHECK_LABEL,
1697
1902
  UNIT_LABEL,
1698
1903
  WARNING_CHECKER_LABELS,
1904
+ check_memory,
1699
1905
  check_weight,
1906
+ direct_unit_memory,
1700
1907
  direct_unit_weight,
1701
1908
  format_gate_plan,
1702
1909
  format_machine,
@@ -1732,28 +1939,32 @@ var DEV_COMMANDS = {
1732
1939
  description: "Check code with prettier and eslint (skips a tool a basic project lacks)",
1733
1940
  category: "Development",
1734
1941
  reference: ["", "developer", ["processes"]],
1735
- core_weight: core_budget.CORE_WEIGHTS.lint
1942
+ core_weight: core_budget.CORE_WEIGHTS.lint,
1943
+ memory_mb: core_budget.MEMORY_MB.lint
1736
1944
  },
1737
1945
  "lint:related": {
1738
1946
  script: "scripts/lint/lint-related.ts",
1739
1947
  description: "Check only the changed files with prettier and eslint (whole tree on fallback)",
1740
1948
  category: "Development",
1741
1949
  reference: [FILE_ARGUMENTS, "developer", ["processes"]],
1742
- core_weight: core_budget.CORE_WEIGHTS.lint
1950
+ core_weight: core_budget.CORE_WEIGHTS.lint,
1951
+ memory_mb: core_budget.MEMORY_MB.lint
1743
1952
  },
1744
1953
  lines: {
1745
1954
  script: "scripts/lines/lines-command.ts",
1746
1955
  description: "Print a file's code lines against the max-lines limit and the headroom left",
1747
1956
  category: "Development",
1748
1957
  reference: [REQUIRED_FILE_ARGUMENTS, "developer", ["none"]],
1749
- core_weight: core_budget.CORE_WEIGHTS.eslint_scan
1958
+ core_weight: core_budget.CORE_WEIGHTS.eslint_scan,
1959
+ memory_mb: core_budget.MEMORY_MB.eslint_scan
1750
1960
  },
1751
1961
  "refactor:scan": {
1752
1962
  script: "scripts/refactor/refactor-scan-cli.ts",
1753
1963
  description: "List refactoring candidates in the changed scope by category and answer clear/candidates",
1754
1964
  category: "Development",
1755
1965
  reference: ["", "automation", ["processes"]],
1756
- core_weight: core_budget.CORE_WEIGHTS.eslint_scan
1966
+ core_weight: core_budget.CORE_WEIGHTS.eslint_scan,
1967
+ memory_mb: core_budget.MEMORY_MB.eslint_scan
1757
1968
  },
1758
1969
  bytes: {
1759
1970
  script: "scripts/lines/bytes-command.ts",
@@ -1833,7 +2044,8 @@ var DEV_COMMANDS = {
1833
2044
  description: "Run spell check including dotfiles",
1834
2045
  category: "Development",
1835
2046
  reference: ["", "developer", ["processes"]],
1836
- core_weight: core_budget.CORE_WEIGHTS.spell_check
2047
+ core_weight: core_budget.CORE_WEIGHTS.spell_check,
2048
+ memory_mb: core_budget.MEMORY_MB.spell_check
1837
2049
  },
1838
2050
  behavior: {
1839
2051
  script: "scripts/behavior/behavior-cli.ts",
@@ -1852,14 +2064,16 @@ var DEV_COMMANDS = {
1852
2064
  description: "Run unit tests with Vitest (skips when Vitest is absent; fails when it has no tests)",
1853
2065
  category: "Development",
1854
2066
  reference: [FILTER_ARGUMENTS, "developer", ["processes"]],
1855
- core_weight: gate_plan.direct_unit_weight
2067
+ core_weight: gate_plan.direct_unit_weight,
2068
+ memory_mb: gate_plan.direct_unit_memory
1856
2069
  },
1857
2070
  "test:related": {
1858
2071
  script: "scripts/test/test-related.ts",
1859
2072
  description: "Run only the unit tests related to the changed files (full suite on fallback)",
1860
2073
  category: "Development",
1861
2074
  reference: [FILE_ARGUMENTS, "developer", ["processes"]],
1862
- core_weight: gate_plan.direct_unit_weight
2075
+ core_weight: gate_plan.direct_unit_weight,
2076
+ memory_mb: gate_plan.direct_unit_memory
1863
2077
  },
1864
2078
  "test:declared": {
1865
2079
  script: "scripts/test/test-declared.ts",
@@ -1903,7 +2117,8 @@ var DEV_COMMANDS = {
1903
2117
  description: "Type-check with tsc (skips a basic project with no TypeScript to check)",
1904
2118
  category: "Development",
1905
2119
  reference: ["[arguments...]", "developer", ["processes"]],
1906
- core_weight: core_budget.CORE_WEIGHTS.type_check
2120
+ core_weight: core_budget.CORE_WEIGHTS.type_check,
2121
+ memory_mb: core_budget.MEMORY_MB.type_check
1907
2122
  },
1908
2123
  port: {
1909
2124
  script: "scripts/ports/port-command.ts",
@@ -2024,9 +2239,9 @@ var MAINTENANCE_COMMANDS = {
2024
2239
  shell: [
2025
2240
  "sh",
2026
2241
  "-c",
2027
- "export NODE_AUTH_TOKEN=$(gh auth token) && pnpm josh latest:guard && pnpm josh latest:corepack && pnpm josh latest:update && pnpm josh ranges && pnpm josh audit && pnpm josh latest:scope --record"
2242
+ "export NODE_AUTH_TOKEN=$(gh auth token) && pnpm josh latest:guard && pnpm josh latest:update && pnpm josh ranges && pnpm josh audit && pnpm josh latest:corepack && pnpm josh latest:scope --record"
2028
2243
  ],
2029
- description: "Update pnpm, dependencies, and run security audit",
2244
+ description: "Update dependencies, run security audit, then update pnpm",
2030
2245
  category: "Maintenance",
2031
2246
  reference: ["", "developer", ["files", "network", "processes"]],
2032
2247
  argument_targets: ["latest:corepack", "latest:update", "audit"]
@@ -2745,15 +2960,16 @@ async function run_entry(entry, subcommand_arguments) {
2745
2960
  if (entry.shell) return run_shell_command(entry.shell, subcommand_arguments);
2746
2961
  return await run_script_entry(entry, subcommand_arguments);
2747
2962
  }
2748
- function command_weight(entry) {
2749
- return typeof entry.core_weight === "function" ? entry.core_weight() : entry.core_weight;
2963
+ function declared(value) {
2964
+ return typeof value === "function" ? value() : value;
2750
2965
  }
2751
2966
  async function dispatch_entry(entry, subcommand_arguments) {
2752
- const weight = command_weight(entry);
2967
+ const weight = declared(entry.core_weight);
2753
2968
  if (weight === void 0) return await run_entry(entry, subcommand_arguments);
2754
2969
  return await core_budget.with_command_reservation(
2755
2970
  weight,
2756
- async () => await run_entry(entry, subcommand_arguments)
2971
+ async () => await run_entry(entry, subcommand_arguments),
2972
+ { memory_mb: declared(entry.memory_mb) }
2757
2973
  );
2758
2974
  }
2759
2975
  async function run_command(cmd, subcommand_arguments, is_consumer = false) {
package/package.json CHANGED
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "1.1229.0",
2
+ "version": "1.1240.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": [
@@ -71,6 +71,7 @@ Issue には次の要素を必ず含める。
71
71
  - **`bugfix` は PR のリリース分類であり、Issue の `bug` の代わりにしない。** `enhancement` と `breaking-change` の両方を持つ Issue の PR は `breaking-change` 一つに分類する
72
72
  - **`## 発火点`** の名前は `prompts/collaboration-workflow/rule-delivery.md` の配送表と突き合わされる
73
73
  - **`## ベースライン`** の測定コマンドは、マージ後に `pnpm josh measure:rerun <N>` が再実行して before / after を印字する(作者が `OWNER` / `MEMBER` / `COLLABORATOR` の Issue に限る)
74
+ - **公開しないと利用側が使えない変更には `--release` を付ける**(既存 Issue は `pnpm josh issue:release <N>`)。リリース用 Issue の blocker になる(`docs/josh-commands-backlog.md` → `josh issue:release`)
74
75
 
75
76
  ### 起票元へのバックリンク(`## Origin` / `## Upstream issues`)
76
77