@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.
- package/.claude/skills/workflow-commands/backlogrun-lanes.md +1 -1
- package/.claude/skills/workflow-commands/backlogrun-progress.md +2 -2
- package/.claude/skills/workflow-commands/followup.md +5 -0
- package/.claude/skills/workflow-commands/kickoff.md +1 -0
- package/.claude/skills/workflow-commands/latest-gate.md +1 -1
- package/.github/workflows/publish.yml +2 -0
- package/README.md +30 -31
- package/dist/hooks/batch-guard.js +4 -4
- package/dist/hooks/{chunk-JUDKDCDP.js → chunk-4TZVB44A.js} +8 -8
- package/dist/hooks/{chunk-RNWHN5BP.js → chunk-F3ELQ2AF.js} +3 -3
- package/dist/hooks/{chunk-VC3PZPZO.js → chunk-GPTFMK5E.js} +1 -1
- package/dist/hooks/{chunk-FIVDHQGT.js → chunk-KHGB5S3Y.js} +1 -1
- package/dist/hooks/{chunk-NV2JRZZO.js → chunk-KHX4U3BG.js} +17 -2
- package/dist/hooks/{chunk-F56MFS4B.js → chunk-KRBERBBI.js} +3 -3
- package/dist/hooks/{chunk-TQNPDZNH.js → chunk-QVSWU24O.js} +4 -4
- package/dist/hooks/{chunk-55HHG5PX.js → chunk-WK2XSHSI.js} +284 -63
- package/dist/hooks/{chunk-5VMKCCC4.js → chunk-XZYKEM6J.js} +2 -2
- package/dist/hooks/{chunk-6HJJXRBX.js → chunk-ZQGD4GBY.js} +1 -1
- package/dist/hooks/codex-hook-adapter.js +10 -10
- package/dist/hooks/duplicate-read-guard.js +5 -5
- package/dist/hooks/format-edited.js +2 -2
- package/dist/hooks/inputs.json +172 -170
- package/dist/hooks/investigation-guard.js +5 -5
- package/dist/hooks/pretool-guard.js +9 -9
- package/dist/hooks/stop-guard.js +3 -17
- package/dist/josh.js +279 -63
- package/package.json +1 -1
- package/prompts/collaboration-workflow/issue-template.md +1 -0
- package/scripts/gate/core-admission.ts +162 -0
- package/scripts/gate/core-budget.ts +121 -67
- package/scripts/gate/gate-plan.ts +35 -2
- package/scripts/gate/gate-report.ts +28 -9
- package/scripts/gate/machine-capacity.ts +175 -0
- package/scripts/gate/verification-gate.ts +7 -2
- package/scripts/init/init.ts +5 -1
- package/scripts/init/package-manager-pin.ts +35 -0
- package/scripts/issue/issue-auto-ok.ts +31 -6
- package/scripts/issue/issue-file-cli.ts +31 -8
- package/scripts/issue/issue-file.ts +5 -0
- package/scripts/issue/issue-labels.ts +13 -0
- package/scripts/issue/issue-release-cli.ts +155 -0
- package/scripts/issue/issue-release.ts +58 -0
- package/scripts/josh/josh-command-types.ts +3 -0
- package/scripts/josh/josh-commands-development.ts +8 -0
- package/scripts/josh/josh-commands-issue.ts +8 -1
- package/scripts/josh/josh-commands-lane.ts +2 -1
- package/scripts/josh/josh-commands-maintenance.ts +2 -2
- package/scripts/josh/josh-logic.ts +4 -3
- package/scripts/lane/lane-cli.ts +9 -1
- package/scripts/lane/lane-leftover.ts +43 -29
- package/scripts/lane/lane-open.ts +5 -5
- package/scripts/lane/lane-paths.ts +13 -0
- package/scripts/lane/lane-registry.ts +11 -0
- package/scripts/lane/lane-stray.ts +140 -0
- package/scripts/release/github-release-environment.ts +1 -0
- package/scripts/release/github-release-runs.ts +115 -0
- package/scripts/release/github-release.ts +13 -67
- package/scripts/run/cut/run-cut-cli.ts +16 -3
- package/scripts/run/event/run-event-render.ts +1 -0
- package/scripts/run/event/run-event-stream.ts +4 -0
- package/scripts/run/run-step.ts +5 -2
- package/scripts/run/wake/run-wake-cli.ts +2 -3
- package/scripts/run/wake/run-wake-describe.ts +56 -5
- package/scripts/run/wake/run-wake-loop.ts +5 -13
- package/scripts/run/wake/run-wake.ts +15 -64
- package/scripts/version/latest-corepack.ts +109 -78
- 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
|
|
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(
|
|
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
|
|
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,
|
|
804
|
-
stamp_file.
|
|
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 ??
|
|
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
|
-
|
|
815
|
-
|
|
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
|
-
|
|
827
|
-
|
|
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 +
|
|
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
|
|
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
|
-
{
|
|
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
|
|
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 =
|
|
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 =
|
|
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:
|
|
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
|
|
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
|
|
2749
|
-
return typeof
|
|
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 =
|
|
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.
|
|
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
|
|