@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
@@ -309,10 +309,16 @@ var ISSUE_COMMANDS = {
309
309
  description: "File an Issue with every filing step: lint, Origin, WIP cap, duplicate scout, labels, then epic:bundle",
310
310
  category: "AI tools",
311
311
  reference: [
312
- "<title> --body-file <path> --depth <0|1|2> [--route <route>] [--label <name>] [--repo <owner/repo>] [--distinct <N,\u2026>] [--over-cap] [--no-auto-ok]",
312
+ "<title> --body-file <path> --depth <0|1|2> [--route <route>] [--label <name>] [--repo <owner/repo>] [--distinct <N,\u2026>] [--over-cap] [--no-auto-ok] [--release]",
313
313
  "automation",
314
314
  ["network"]
315
315
  ]
316
+ },
317
+ "issue:release": {
318
+ script: "scripts/issue/issue-release-cli.ts",
319
+ description: "Link an Issue to the repository's open release Issue as its blocker, filing one when none is open",
320
+ category: "AI tools",
321
+ reference: ["<issue>", "automation", ["network"]]
316
322
  }
317
323
  };
318
324
 
@@ -348,7 +354,7 @@ var LANE_COMMANDS = {
348
354
  },
349
355
  "lane:prune": {
350
356
  ...LANE_ARGUMENTS,
351
- description: "Close every lane an interruption left without its work tree",
357
+ description: "Close every lane an interruption left without its work tree, then sweep unregistered leftovers under the lanes root",
352
358
  category: "AI tools",
353
359
  reference: ["", "automation", ["files", "git"]],
354
360
  default_script_arguments: ["prune"]
@@ -741,7 +747,7 @@ var CLONE_COMMANDS = {
741
747
  // scripts/gate/core-budget.ts
742
748
  import { randomUUID as randomUUID2 } from "node:crypto";
743
749
  import { readdirSync as readdirSync2 } from "node:fs";
744
- import { availableParallelism as availableParallelism2 } from "node:os";
750
+ import { availableParallelism as availableParallelism3 } from "node:os";
745
751
  import path3 from "node:path";
746
752
 
747
753
  // scripts/josh/process-identity.ts
@@ -1016,6 +1022,159 @@ var unit_worker_share = {
1016
1022
 
1017
1023
  // scripts/gate/core-budget.ts
1018
1024
  import { z as z3 } from "zod";
1025
+
1026
+ // scripts/gate/core-admission.ts
1027
+ var MS_PER_SECOND = 1e3;
1028
+ var RAMP_UP_MS = 3e4;
1029
+ function compare_claim(left, right) {
1030
+ const by_time = left.reservation.claimed_at - right.reservation.claimed_at;
1031
+ return by_time === 0 ? left.key.localeCompare(right.key) : by_time;
1032
+ }
1033
+ function add_load(totals, reservation) {
1034
+ totals.cores += reservation.weight;
1035
+ totals.memory_mb += reservation.memory_mb ?? 0;
1036
+ }
1037
+ function exceeds(totals, budget) {
1038
+ return totals.cores > budget.cores || totals.memory_mb > budget.memory_mb;
1039
+ }
1040
+ function admitted_keys(reservations, budget, memory_budget = Infinity) {
1041
+ const limit = { cores: budget, memory_mb: memory_budget };
1042
+ const totals = { cores: 0, memory_mb: 0 };
1043
+ const admitted = /* @__PURE__ */ new Set();
1044
+ for (const [index, entry] of reservations.toSorted(compare_claim).entries()) {
1045
+ add_load(totals, entry.reservation);
1046
+ if (index !== 0 && exceeds(totals, limit)) break;
1047
+ admitted.add(entry.key);
1048
+ }
1049
+ return admitted;
1050
+ }
1051
+ function is_admitted(key, reservations, budget) {
1052
+ return admitted_keys(reservations, budget.cores, budget.memory_mb).has(key);
1053
+ }
1054
+ function sum_load(reservations) {
1055
+ const load = { cores: 0, memory_mb: 0 };
1056
+ for (const entry of reservations) add_load(load, entry.reservation);
1057
+ return load;
1058
+ }
1059
+ function is_ramped(reservation, now) {
1060
+ const { admitted_at } = reservation;
1061
+ return admitted_at !== void 0 && now - admitted_at >= RAMP_UP_MS;
1062
+ }
1063
+ function ledger_load(reservations, now) {
1064
+ const admitted = reservations.filter((entry) => entry.reservation.admitted_at !== void 0);
1065
+ const ramped = admitted.filter((entry) => is_ramped(entry.reservation, now));
1066
+ return { cores: sum_load(admitted).cores, memory_mb: sum_load(ramped).memory_mb };
1067
+ }
1068
+ function total_weight(reservations) {
1069
+ return sum_load(reservations).cores;
1070
+ }
1071
+ function admitted_load(reservations, budget) {
1072
+ const admitted = admitted_keys(reservations, budget);
1073
+ return total_weight(reservations.filter((entry) => admitted.has(entry.key)));
1074
+ }
1075
+ function describe_memory(ledger, budget) {
1076
+ if (!Number.isFinite(budget.memory_mb)) return "";
1077
+ return ` and ${String(Math.round(ledger.memory_mb))} MB of memory against ${String(Math.round(budget.memory_mb))} MB`;
1078
+ }
1079
+ function describe_overflow(admission) {
1080
+ const { overflow } = admission;
1081
+ if (overflow === void 0) return void 0;
1082
+ const { ledger, budget } = overflow;
1083
+ const waited = String(Math.round(overflow.waited_ms / MS_PER_SECOND));
1084
+ const cores = `the ledger held ${String(ledger.cores)} cores against a budget of ${String(budget.cores)}`;
1085
+ return `started past the core budget after ${waited}s \u2014 ${cores}${describe_memory(ledger, budget)}`;
1086
+ }
1087
+ var core_admission = {
1088
+ RAMP_UP_MS,
1089
+ admitted_keys,
1090
+ admitted_load,
1091
+ describe_overflow,
1092
+ is_admitted,
1093
+ ledger_load,
1094
+ sum_load
1095
+ };
1096
+
1097
+ // scripts/gate/machine-capacity.ts
1098
+ import { readFile } from "node:fs/promises";
1099
+ import { availableParallelism as availableParallelism2, cpus, totalmem } from "node:os";
1100
+ import { execa } from "execa";
1101
+ var SAMPLE_WINDOW_MS = 250;
1102
+ var BASELINE_CORES = 2;
1103
+ var BYTES_PER_MB = 1048576;
1104
+ var KB_PER_MB = 1024;
1105
+ var PERCENT = 100;
1106
+ var MEMINFO_PATH = "/proc/meminfo";
1107
+ var LINUX_AVAILABLE = /^MemAvailable:\s+(?<kb>\d+) kB/mu;
1108
+ var PRESSURE_ARGUMENTS = ["-n", "kern.memorystatus_level"];
1109
+ var PRESSURE_LEVEL = /^\s*(?<level>\d+)\s*$/u;
1110
+ function cpu_times() {
1111
+ let busy = 0;
1112
+ let idle = 0;
1113
+ for (const { times } of cpus()) {
1114
+ busy += times.user + times.nice + times.sys + times.irq;
1115
+ idle += times.idle;
1116
+ }
1117
+ return { busy, total: busy + idle };
1118
+ }
1119
+ function busy_cores_between(before, after, cores) {
1120
+ const total = after.total - before.total;
1121
+ if (total <= 0) return void 0;
1122
+ return (after.busy - before.busy) / total * cores;
1123
+ }
1124
+ function parse_darwin_pressure(output, total_bytes) {
1125
+ const level = PRESSURE_LEVEL.exec(output)?.groups?.["level"];
1126
+ if (level === void 0) return void 0;
1127
+ return Number(level) / PERCENT * (total_bytes / BYTES_PER_MB);
1128
+ }
1129
+ function parse_linux_available(meminfo) {
1130
+ const kb = LINUX_AVAILABLE.exec(meminfo)?.groups?.["kb"];
1131
+ return kb === void 0 ? void 0 : Number(kb) / KB_PER_MB;
1132
+ }
1133
+ async function read_available_mb(platform = process.platform) {
1134
+ try {
1135
+ if (platform === "darwin") {
1136
+ const { stdout } = await execa("sysctl", PRESSURE_ARGUMENTS);
1137
+ return parse_darwin_pressure(stdout, totalmem());
1138
+ }
1139
+ return platform === "linux" ? parse_linux_available(await readFile(MEMINFO_PATH, "utf8")) : void 0;
1140
+ } catch {
1141
+ return void 0;
1142
+ }
1143
+ }
1144
+ function is_unquoted() {
1145
+ return cpus().length > 0 && cpus().length === availableParallelism2();
1146
+ }
1147
+ async function default_sleep(ms) {
1148
+ await new Promise((resolve) => {
1149
+ setTimeout(resolve, ms);
1150
+ });
1151
+ }
1152
+ async function read_machine(sleep = default_sleep) {
1153
+ const before = cpu_times();
1154
+ const [available_mb] = await Promise.all([read_available_mb(), sleep(SAMPLE_WINDOW_MS)]);
1155
+ const busy_cores = is_unquoted() ? busy_cores_between(before, cpu_times(), cpus().length) : void 0;
1156
+ return { busy_cores, available_mb };
1157
+ }
1158
+ function external_cores(busy_cores, ledger_cores) {
1159
+ if (busy_cores === void 0) return 0;
1160
+ return Math.floor(Math.max(0, busy_cores - ledger_cores - BASELINE_CORES));
1161
+ }
1162
+ function machine_budget(cores, reading, ledger) {
1163
+ return {
1164
+ cores: cores - external_cores(reading.busy_cores, ledger.cores),
1165
+ memory_mb: reading.available_mb === void 0 ? Infinity : reading.available_mb + ledger.memory_mb
1166
+ };
1167
+ }
1168
+ var machine_capacity = {
1169
+ BASELINE_CORES,
1170
+ busy_cores_between,
1171
+ machine_budget,
1172
+ parse_darwin_pressure,
1173
+ parse_linux_available,
1174
+ read_machine
1175
+ };
1176
+
1177
+ // scripts/gate/core-budget.ts
1019
1178
  var RESERVED_PREFIX = "josh-core-reserved-";
1020
1179
  var RESERVED_SUFFIX = ".json";
1021
1180
  var POLL_INTERVAL_MS = 50;
@@ -1027,11 +1186,20 @@ var CORE_WEIGHTS = {
1027
1186
  spell_check: 1,
1028
1187
  eslint_scan: 1
1029
1188
  };
1189
+ var MEMORY_MB = {
1190
+ lint: 2400,
1191
+ type_check: 1300,
1192
+ spell_check: 350,
1193
+ eslint_scan: 2400,
1194
+ unit_worker: 350
1195
+ };
1030
1196
  var HELD_KEY = "JOSH_CORE_RESERVED";
1031
1197
  var HELD_VALUE = "1";
1032
1198
  var reservation_schema = process_owner_schema.extend({
1033
1199
  weight: z3.number(),
1034
- claimed_at: z3.number()
1200
+ claimed_at: z3.number(),
1201
+ memory_mb: z3.number().optional(),
1202
+ admitted_at: z3.number().optional()
1035
1203
  });
1036
1204
  function marker_name(key) {
1037
1205
  return `${RESERVED_PREFIX}${key}${RESERVED_SUFFIX}`;
@@ -1064,7 +1232,9 @@ function live_reservation(source) {
1064
1232
  }
1065
1233
  function marker_files2(directory) {
1066
1234
  try {
1067
- return readdirSync2(directory).filter((name) => name.startsWith(RESERVED_PREFIX));
1235
+ return readdirSync2(directory).filter(
1236
+ (name) => name.startsWith(RESERVED_PREFIX) && name.endsWith(RESERVED_SUFFIX)
1237
+ );
1068
1238
  } catch {
1069
1239
  return [];
1070
1240
  }
@@ -1075,67 +1245,79 @@ function live_reservations(directory = PLATFORM_TEMP_ROOT) {
1075
1245
  return reservation === void 0 ? [] : { key: name, reservation };
1076
1246
  });
1077
1247
  }
1078
- function compare_claim(left, right) {
1079
- const by_time = left.reservation.claimed_at - right.reservation.claimed_at;
1080
- return by_time === 0 ? left.key.localeCompare(right.key) : by_time;
1081
- }
1082
- function admitted_keys(reservations, budget) {
1083
- const admitted = /* @__PURE__ */ new Set();
1084
- let cumulative = 0;
1085
- for (const [index, entry] of reservations.toSorted(compare_claim).entries()) {
1086
- cumulative += entry.reservation.weight;
1087
- if (index !== 0 && cumulative > budget) break;
1088
- admitted.add(entry.key);
1089
- }
1090
- return admitted;
1091
- }
1092
- function is_admitted(key, reservations, budget) {
1093
- return admitted_keys(reservations, budget).has(key);
1094
- }
1095
- function admitted_load(reservations, budget) {
1096
- const admitted = admitted_keys(reservations, budget);
1097
- return reservations.filter((entry) => admitted.has(entry.key)).reduce((total, entry) => total + entry.reservation.weight, 0);
1098
- }
1099
1248
  function normalize_budget(budget) {
1100
1249
  return Number.isFinite(budget) ? Math.max(MIN_BUDGET, Math.floor(budget)) : MIN_BUDGET;
1101
1250
  }
1102
- async function default_sleep(ms) {
1251
+ async function default_sleep2(ms) {
1103
1252
  await new Promise((resolve) => {
1104
1253
  setTimeout(resolve, ms);
1105
1254
  });
1106
1255
  }
1107
- function write_reservation(target, weight, claimed_at) {
1108
- stamp_file.write_stamp(target, { ...process_identity.own_fields(), weight, claimed_at });
1256
+ function write_reservation(target, fields) {
1257
+ stamp_file.replace_stamp(target, { ...process_identity.own_fields(), ...fields });
1109
1258
  }
1110
1259
  function resolve_timing(options) {
1111
1260
  return {
1112
1261
  now: options.now ?? Date.now,
1113
- sleep: options.sleep ?? default_sleep,
1114
- poll_interval_ms: options.poll_interval_ms ?? POLL_INTERVAL_MS
1262
+ sleep: options.sleep ?? default_sleep2,
1263
+ poll_interval_ms: options.poll_interval_ms ?? POLL_INTERVAL_MS,
1264
+ wait_cap_ms: options.wait_cap_ms ?? WAIT_CAP_MS
1115
1265
  };
1116
1266
  }
1267
+ async function current_budget(context, reservations) {
1268
+ if (reservations.length <= 1) return { cores: context.budget, memory_mb: Infinity };
1269
+ const reading = await context.read_machine();
1270
+ const ledger = core_admission.ledger_load(reservations, context.now());
1271
+ const budget = machine_capacity.machine_budget(context.budget, reading, ledger);
1272
+ return { ...budget, cores: normalize_budget(budget.cores) };
1273
+ }
1274
+ function admit(context, overflow) {
1275
+ write_reservation(context.target, { ...context.fields, admitted_at: context.now() });
1276
+ return { overflow };
1277
+ }
1278
+ function overflow_of(context, reservations, budget) {
1279
+ return {
1280
+ waited_ms: context.now() - context.fields.claimed_at,
1281
+ ledger: core_admission.sum_load(reservations),
1282
+ budget
1283
+ };
1284
+ }
1285
+ async function poll_admission(context) {
1286
+ const reservations = live_reservations(context.directory);
1287
+ const budget = await current_budget(context, reservations);
1288
+ if (core_admission.is_admitted(context.key, reservations, budget)) return admit(context);
1289
+ if (context.now() >= context.deadline) {
1290
+ return admit(context, overflow_of(context, reservations, budget));
1291
+ }
1292
+ return void 0;
1293
+ }
1117
1294
  async function await_admission(context) {
1118
- while (!is_admitted(context.key, live_reservations(context.directory), context.budget)) {
1119
- if (context.now() >= context.deadline) return;
1295
+ let admission = await poll_admission(context);
1296
+ while (admission === void 0) {
1120
1297
  await context.sleep(context.poll_interval_ms);
1298
+ admission = await poll_admission(context);
1121
1299
  }
1300
+ return admission;
1122
1301
  }
1123
1302
  async function reserve(weight, options = {}) {
1124
1303
  const timing = resolve_timing(options);
1125
1304
  const directory = options.directory ?? PLATFORM_TEMP_ROOT;
1126
- const budget = normalize_budget(options.budget ?? availableParallelism2());
1127
1305
  const claimed_at = timing.now();
1128
1306
  const name = marker_name(randomUUID2());
1129
1307
  const target = path3.join(directory, name);
1130
- write_reservation(target, weight, claimed_at);
1131
- await await_admission({
1308
+ const fields = { weight, claimed_at, memory_mb: options.memory_mb };
1309
+ write_reservation(target, fields);
1310
+ const admission = await await_admission({
1132
1311
  ...timing,
1133
1312
  key: name,
1313
+ target,
1134
1314
  directory,
1135
- budget,
1136
- deadline: claimed_at + (options.wait_cap_ms ?? WAIT_CAP_MS)
1315
+ budget: normalize_budget(options.budget ?? availableParallelism3()),
1316
+ deadline: claimed_at + timing.wait_cap_ms,
1317
+ fields,
1318
+ read_machine: options.read_machine ?? machine_capacity.read_machine
1137
1319
  });
1138
- return { target };
1320
+ return { target, admission };
1139
1321
  }
1140
1322
  function release(handle) {
1141
1323
  sweep_marker2(handle.target);
@@ -1143,7 +1325,7 @@ function release(handle) {
1143
1325
  async function with_core_reservation(weight, run, options = {}) {
1144
1326
  const handle = await reserve(weight, options);
1145
1327
  try {
1146
- return await run();
1328
+ return await run(handle.admission);
1147
1329
  } finally {
1148
1330
  release(handle);
1149
1331
  }
@@ -1171,9 +1353,11 @@ var core_budget = {
1171
1353
  CORE_WEIGHTS,
1172
1354
  HELD_KEY,
1173
1355
  HELD_VALUE,
1356
+ MEMORY_MB,
1174
1357
  RESERVED_PREFIX,
1175
- admitted_keys,
1176
- admitted_load,
1358
+ admitted_keys: core_admission.admitted_keys,
1359
+ admitted_load: core_admission.admitted_load,
1360
+ describe_overflow: core_admission.describe_overflow,
1177
1361
  is_held,
1178
1362
  live_reservations,
1179
1363
  release,
@@ -1184,7 +1368,7 @@ var core_budget = {
1184
1368
  };
1185
1369
 
1186
1370
  // scripts/gate/gate-plan.ts
1187
- import { availableParallelism as availableParallelism3 } from "node:os";
1371
+ import { availableParallelism as availableParallelism4 } from "node:os";
1188
1372
 
1189
1373
  // scripts/lib/status-icons.ts
1190
1374
  var FAIL_ICON = "\u2717";
@@ -1234,13 +1418,24 @@ var UNIT_LABEL = "test:unit";
1234
1418
  var BEHAVIOR_LABEL = "behavior";
1235
1419
  var WARNING_CHECKER_LABELS = [LINT_LABEL, TYPE_CHECK_LABEL];
1236
1420
  var STATIC_CHECKS = [
1237
- { label: LINT_LABEL, target: "lint", reserved_cores: core_budget.CORE_WEIGHTS.lint },
1421
+ {
1422
+ label: LINT_LABEL,
1423
+ target: "lint",
1424
+ reserved_cores: core_budget.CORE_WEIGHTS.lint,
1425
+ memory_mb: core_budget.MEMORY_MB.lint
1426
+ },
1238
1427
  {
1239
1428
  label: TYPE_CHECK_LABEL,
1240
1429
  target: "check",
1241
- reserved_cores: core_budget.CORE_WEIGHTS.type_check
1430
+ reserved_cores: core_budget.CORE_WEIGHTS.type_check,
1431
+ memory_mb: core_budget.MEMORY_MB.type_check
1432
+ },
1433
+ {
1434
+ label: "cspell",
1435
+ target: "cspell:dot",
1436
+ reserved_cores: core_budget.CORE_WEIGHTS.spell_check,
1437
+ memory_mb: core_budget.MEMORY_MB.spell_check
1242
1438
  },
1243
- { label: "cspell", target: "cspell:dot", reserved_cores: core_budget.CORE_WEIGHTS.spell_check },
1244
1439
  { label: BEHAVIOR_LABEL, target: BEHAVIOR_LABEL, reserved_cores: 0 },
1245
1440
  // **The unused-member check reserves no core** (joshuafolkken/kit#2987): it builds one TypeScript
1246
1441
  // program and walks it for about 5s, and it is over well before lint and the type check. A
@@ -1293,14 +1488,24 @@ function check_weight(check, plan, available_cores) {
1293
1488
  if (check.label !== UNIT_LABEL) return check.reserved_cores;
1294
1489
  return plan.unit_worker_cap ?? solo_unit_weight(available_cores);
1295
1490
  }
1296
- function direct_unit_weight(available_cores = availableParallelism3(), live_runs = unit_worker_share.live_run_count()) {
1491
+ function unit_memory(workers) {
1492
+ return workers * core_budget.MEMORY_MB.unit_worker;
1493
+ }
1494
+ function check_memory(check, plan, available_cores) {
1495
+ if (check.label !== UNIT_LABEL) return check.memory_mb ?? 0;
1496
+ return unit_memory(check_weight(check, plan, available_cores));
1497
+ }
1498
+ function direct_unit_weight(available_cores = availableParallelism4(), live_runs = unit_worker_share.live_run_count()) {
1297
1499
  const weight = unit_worker_share.current_share(available_cores, live_runs) ?? solo_unit_weight(available_cores);
1298
1500
  return Math.max(unit_worker_share.MIN_WORKERS, weight);
1299
1501
  }
1502
+ function direct_unit_memory() {
1503
+ return unit_memory(direct_unit_weight());
1504
+ }
1300
1505
  function plan_of(concurrency, unit_worker_cap, checks = GATE_CHECKS) {
1301
1506
  return { checks, concurrency, unit_worker_cap };
1302
1507
  }
1303
- function resolve_gate_plan(available_cores = availableParallelism3(), concurrent_runs = unit_worker_share.SOLO_RUNS, is_unit_included = true) {
1508
+ function resolve_gate_plan(available_cores = availableParallelism4(), concurrent_runs = unit_worker_share.SOLO_RUNS, is_unit_included = true) {
1304
1509
  const checks = select_gate_checks(is_unit_included);
1305
1510
  return {
1306
1511
  checks,
@@ -1318,7 +1523,7 @@ function format_unit_cap(plan) {
1318
1523
  if (plan.unit_worker_cap === void 0) return `${UNIT_LABEL} unrestricted`;
1319
1524
  return `${UNIT_LABEL} at ${String(plan.unit_worker_cap)} workers`;
1320
1525
  }
1321
- function format_gate_plan(plan, available_cores = availableParallelism3(), concurrent_runs = unit_worker_share.SOLO_RUNS) {
1526
+ function format_gate_plan(plan, available_cores = availableParallelism4(), concurrent_runs = unit_worker_share.SOLO_RUNS) {
1322
1527
  const cap = format_unit_cap(plan);
1323
1528
  const count = `${String(plan.concurrency)} of ${String(plan.checks.length)}`;
1324
1529
  const width = `${count}${josh_verdict.GATE_OPENING_MARK}`;
@@ -1334,7 +1539,9 @@ var gate_plan = {
1334
1539
  TYPE_CHECK_LABEL,
1335
1540
  UNIT_LABEL,
1336
1541
  WARNING_CHECKER_LABELS,
1542
+ check_memory,
1337
1543
  check_weight,
1544
+ direct_unit_memory,
1338
1545
  direct_unit_weight,
1339
1546
  format_gate_plan,
1340
1547
  format_machine,
@@ -1370,28 +1577,32 @@ var DEV_COMMANDS = {
1370
1577
  description: "Check code with prettier and eslint (skips a tool a basic project lacks)",
1371
1578
  category: "Development",
1372
1579
  reference: ["", "developer", ["processes"]],
1373
- core_weight: core_budget.CORE_WEIGHTS.lint
1580
+ core_weight: core_budget.CORE_WEIGHTS.lint,
1581
+ memory_mb: core_budget.MEMORY_MB.lint
1374
1582
  },
1375
1583
  "lint:related": {
1376
1584
  script: "scripts/lint/lint-related.ts",
1377
1585
  description: "Check only the changed files with prettier and eslint (whole tree on fallback)",
1378
1586
  category: "Development",
1379
1587
  reference: [FILE_ARGUMENTS, "developer", ["processes"]],
1380
- core_weight: core_budget.CORE_WEIGHTS.lint
1588
+ core_weight: core_budget.CORE_WEIGHTS.lint,
1589
+ memory_mb: core_budget.MEMORY_MB.lint
1381
1590
  },
1382
1591
  lines: {
1383
1592
  script: "scripts/lines/lines-command.ts",
1384
1593
  description: "Print a file's code lines against the max-lines limit and the headroom left",
1385
1594
  category: "Development",
1386
1595
  reference: [REQUIRED_FILE_ARGUMENTS, "developer", ["none"]],
1387
- core_weight: core_budget.CORE_WEIGHTS.eslint_scan
1596
+ core_weight: core_budget.CORE_WEIGHTS.eslint_scan,
1597
+ memory_mb: core_budget.MEMORY_MB.eslint_scan
1388
1598
  },
1389
1599
  "refactor:scan": {
1390
1600
  script: "scripts/refactor/refactor-scan-cli.ts",
1391
1601
  description: "List refactoring candidates in the changed scope by category and answer clear/candidates",
1392
1602
  category: "Development",
1393
1603
  reference: ["", "automation", ["processes"]],
1394
- core_weight: core_budget.CORE_WEIGHTS.eslint_scan
1604
+ core_weight: core_budget.CORE_WEIGHTS.eslint_scan,
1605
+ memory_mb: core_budget.MEMORY_MB.eslint_scan
1395
1606
  },
1396
1607
  bytes: {
1397
1608
  script: "scripts/lines/bytes-command.ts",
@@ -1471,7 +1682,8 @@ var DEV_COMMANDS = {
1471
1682
  description: "Run spell check including dotfiles",
1472
1683
  category: "Development",
1473
1684
  reference: ["", "developer", ["processes"]],
1474
- core_weight: core_budget.CORE_WEIGHTS.spell_check
1685
+ core_weight: core_budget.CORE_WEIGHTS.spell_check,
1686
+ memory_mb: core_budget.MEMORY_MB.spell_check
1475
1687
  },
1476
1688
  behavior: {
1477
1689
  script: "scripts/behavior/behavior-cli.ts",
@@ -1490,14 +1702,16 @@ var DEV_COMMANDS = {
1490
1702
  description: "Run unit tests with Vitest (skips when Vitest is absent; fails when it has no tests)",
1491
1703
  category: "Development",
1492
1704
  reference: [FILTER_ARGUMENTS, "developer", ["processes"]],
1493
- core_weight: gate_plan.direct_unit_weight
1705
+ core_weight: gate_plan.direct_unit_weight,
1706
+ memory_mb: gate_plan.direct_unit_memory
1494
1707
  },
1495
1708
  "test:related": {
1496
1709
  script: "scripts/test/test-related.ts",
1497
1710
  description: "Run only the unit tests related to the changed files (full suite on fallback)",
1498
1711
  category: "Development",
1499
1712
  reference: [FILE_ARGUMENTS, "developer", ["processes"]],
1500
- core_weight: gate_plan.direct_unit_weight
1713
+ core_weight: gate_plan.direct_unit_weight,
1714
+ memory_mb: gate_plan.direct_unit_memory
1501
1715
  },
1502
1716
  "test:declared": {
1503
1717
  script: "scripts/test/test-declared.ts",
@@ -1541,7 +1755,8 @@ var DEV_COMMANDS = {
1541
1755
  description: "Type-check with tsc (skips a basic project with no TypeScript to check)",
1542
1756
  category: "Development",
1543
1757
  reference: ["[arguments...]", "developer", ["processes"]],
1544
- core_weight: core_budget.CORE_WEIGHTS.type_check
1758
+ core_weight: core_budget.CORE_WEIGHTS.type_check,
1759
+ memory_mb: core_budget.MEMORY_MB.type_check
1545
1760
  },
1546
1761
  port: {
1547
1762
  script: "scripts/ports/port-command.ts",
@@ -1662,9 +1877,9 @@ var MAINTENANCE_COMMANDS = {
1662
1877
  shell: [
1663
1878
  "sh",
1664
1879
  "-c",
1665
- "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"
1880
+ "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"
1666
1881
  ],
1667
- description: "Update pnpm, dependencies, and run security audit",
1882
+ description: "Update dependencies, run security audit, then update pnpm",
1668
1883
  category: "Maintenance",
1669
1884
  reference: ["", "developer", ["files", "network", "processes"]],
1670
1885
  argument_targets: ["latest:corepack", "latest:update", "audit"]
@@ -2479,7 +2694,7 @@ var PrConflictError = class extends Error {
2479
2694
 
2480
2695
  // scripts/time-runtime/time-format.ts
2481
2696
  var MS_PER_MINUTE = 6e4;
2482
- var MS_PER_SECOND = 1e3;
2697
+ var MS_PER_SECOND2 = 1e3;
2483
2698
  var MINUTE_DECIMALS = 1;
2484
2699
  var SECOND_DECIMALS = 1;
2485
2700
  var PERCENT_SCALE = 100;
@@ -2499,7 +2714,7 @@ function format_minutes(duration_ms) {
2499
2714
  return `${(duration_ms / MS_PER_MINUTE).toFixed(MINUTE_DECIMALS)} min`;
2500
2715
  }
2501
2716
  function format_seconds(duration_ms) {
2502
- return `${(duration_ms / MS_PER_SECOND).toFixed(SECOND_DECIMALS)} s`;
2717
+ return `${(duration_ms / MS_PER_SECOND2).toFixed(SECOND_DECIMALS)} s`;
2503
2718
  }
2504
2719
  function format_share(part, whole) {
2505
2720
  if (whole === 0) return "n/a";
@@ -2596,7 +2811,7 @@ var git_followup_stages = {
2596
2811
  var LINE_SEPARATOR = "\n";
2597
2812
  var SECONDS_SUFFIX = " s";
2598
2813
  var DIGIT_OR_POINT = /[\d.]/u;
2599
- var MS_PER_SECOND2 = 1e3;
2814
+ var MS_PER_SECOND3 = 1e3;
2600
2815
  var NO_STAGES = [];
2601
2816
  function stage_body(line) {
2602
2817
  const trimmed = line.trimStart();
@@ -2619,7 +2834,7 @@ function to_stage(body) {
2619
2834
  const name = head.slice(0, start).trim();
2620
2835
  const digits = head.slice(start);
2621
2836
  if (name === "" || !is_duration(digits)) return void 0;
2622
- return { name, duration_ms: Number(digits) * MS_PER_SECOND2 };
2837
+ return { name, duration_ms: Number(digits) * MS_PER_SECOND3 };
2623
2838
  }
2624
2839
  function read_stages(text) {
2625
2840
  if (!text.includes(git_followup_stages.STAGE_LINE_PREFIX)) return NO_STAGES;
@@ -4090,10 +4305,16 @@ function lane_issue_of(directory, environment = process.env) {
4090
4305
  function lane_branch(issue) {
4091
4306
  return `${issue}${LANE_BRANCH_SUFFIX}`;
4092
4307
  }
4308
+ var SEAT_LOCK_DIR = ".seat-locks";
4309
+ function is_lane_entry(name) {
4310
+ return LANE_ISSUE_PATTERN.test(name) || DEFAULT_LANE_ROOT_PATTERN.test(name);
4311
+ }
4093
4312
  var lane_paths = {
4094
4313
  LANE_BRANCH_SUFFIX,
4095
4314
  LANE_ROOT_KEY,
4315
+ SEAT_LOCK_DIR,
4096
4316
  default_lane_root,
4317
+ is_lane_entry,
4097
4318
  lane_branch,
4098
4319
  lane_directory,
4099
4320
  lane_issue_of,
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  hook_decision
3
- } from "./chunk-6HJJXRBX.js";
3
+ } from "./chunk-ZQGD4GBY.js";
4
4
  import {
5
5
  cost_blocks,
6
6
  cost_transcript,
@@ -8,7 +8,7 @@ import {
8
8
  time_bundle_call,
9
9
  time_shell,
10
10
  time_spans
11
- } from "./chunk-55HHG5PX.js";
11
+ } from "./chunk-WK2XSHSI.js";
12
12
 
13
13
  // scripts/delegation/investigation-reads.ts
14
14
  import path2 from "node:path";
@@ -2,7 +2,7 @@ import {
2
2
  lane_paths,
3
3
  time_density_hook,
4
4
  time_hook_transcript
5
- } from "./chunk-55HHG5PX.js";
5
+ } from "./chunk-WK2XSHSI.js";
6
6
  import {
7
7
  josh_environment_file
8
8
  } from "./chunk-WPALEIRX.js";
@@ -1,28 +1,28 @@
1
1
  #!/usr/bin/env tsx
2
2
  import {
3
3
  pretool_guard
4
- } from "./chunk-JUDKDCDP.js";
5
- import "./chunk-TQNPDZNH.js";
4
+ } from "./chunk-4TZVB44A.js";
5
+ import "./chunk-QVSWU24O.js";
6
6
  import {
7
7
  bounded_pool
8
- } from "./chunk-NV2JRZZO.js";
8
+ } from "./chunk-KHX4U3BG.js";
9
9
  import {
10
10
  build_envelope,
11
11
  compose_context,
12
12
  format_edited_payload
13
- } from "./chunk-FIVDHQGT.js";
13
+ } from "./chunk-KHGB5S3Y.js";
14
14
  import "./chunk-JBBMAPC4.js";
15
15
  import "./chunk-CDY4NFQG.js";
16
- import "./chunk-RNWHN5BP.js";
17
- import "./chunk-F56MFS4B.js";
18
- import "./chunk-5VMKCCC4.js";
19
- import "./chunk-VC3PZPZO.js";
16
+ import "./chunk-F3ELQ2AF.js";
17
+ import "./chunk-KRBERBBI.js";
18
+ import "./chunk-XZYKEM6J.js";
19
+ import "./chunk-GPTFMK5E.js";
20
20
  import {
21
21
  hook_decision
22
- } from "./chunk-6HJJXRBX.js";
22
+ } from "./chunk-ZQGD4GBY.js";
23
23
  import {
24
24
  time_density_hook
25
- } from "./chunk-55HHG5PX.js";
25
+ } from "./chunk-WK2XSHSI.js";
26
26
  import "./chunk-WPALEIRX.js";
27
27
  import "./chunk-RKUAD3I6.js";
28
28
  import "./chunk-ELCN5LCH.js";
@@ -9,11 +9,11 @@ import {
9
9
  is_enabled,
10
10
  notice_refusal_path,
11
11
  refusal_path
12
- } from "./chunk-TQNPDZNH.js";
13
- import "./chunk-5VMKCCC4.js";
14
- import "./chunk-VC3PZPZO.js";
15
- import "./chunk-6HJJXRBX.js";
16
- import "./chunk-55HHG5PX.js";
12
+ } from "./chunk-QVSWU24O.js";
13
+ import "./chunk-XZYKEM6J.js";
14
+ import "./chunk-GPTFMK5E.js";
15
+ import "./chunk-ZQGD4GBY.js";
16
+ import "./chunk-WK2XSHSI.js";
17
17
  import "./chunk-WPALEIRX.js";
18
18
  import "./chunk-RKUAD3I6.js";
19
19
  import "./chunk-ELCN5LCH.js";
@@ -2,9 +2,9 @@
2
2
  import {
3
3
  report_no_payload,
4
4
  run_hook
5
- } from "./chunk-FIVDHQGT.js";
5
+ } from "./chunk-KHGB5S3Y.js";
6
6
  import "./chunk-JBBMAPC4.js";
7
- import "./chunk-55HHG5PX.js";
7
+ import "./chunk-WK2XSHSI.js";
8
8
  import "./chunk-RKUAD3I6.js";
9
9
  import "./chunk-ELCN5LCH.js";
10
10