@joshuafolkken/kit 1.1035.0 → 1.1050.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 (118) hide show
  1. package/.claude/skills/verify-ui/SKILL.md +1 -1
  2. package/.claude/skills/workflow-commands/SKILL.md +2 -2
  3. package/.claude/skills/workflow-commands/background-commands.md +1 -1
  4. package/.claude/skills/workflow-commands/backlogrun-child.md +2 -2
  5. package/.claude/skills/workflow-commands/backlogrun-lanes.md +1 -1
  6. package/.claude/skills/workflow-commands/backlogrun-park.md +6 -0
  7. package/.claude/skills/workflow-commands/backlogrun-progress.md +30 -36
  8. package/.claude/skills/workflow-commands/backlogrun-steps.md +16 -16
  9. package/.claude/skills/workflow-commands/chain-rule.md +2 -2
  10. package/.claude/skills/workflow-commands/followup-reference.md +2 -2
  11. package/.claude/skills/workflow-commands/issue-comments.md +1 -1
  12. package/.claude/skills/workflow-commands/observation-filing.md +41 -86
  13. package/.claude/skills/workflow-commands/pre-gate-cut.md +33 -36
  14. package/.claude/skills/workflow-commands/working-tree-hold.md +2 -2
  15. package/.github/workflows/auto-tag.yml +21 -0
  16. package/.github/workflows/publish.yml +9 -10
  17. package/dist/hooks/batch-guard.js +4 -4
  18. package/dist/hooks/{chunk-HU66PWWL.js → chunk-5BK3K7V4.js} +89 -41
  19. package/dist/hooks/{chunk-GLBDBJOK.js → chunk-7VPDUBRN.js} +49 -151
  20. package/dist/hooks/{chunk-GJT4BNVE.js → chunk-DMQN45FN.js} +3 -3
  21. package/dist/hooks/{chunk-D67KVGGY.js → chunk-EJDX2TOB.js} +13 -3
  22. package/dist/hooks/{chunk-KG6PZD72.js → chunk-GQ7KP45M.js} +2 -2
  23. package/dist/hooks/{chunk-Y27M6A7X.js → chunk-HJIISEAC.js} +4 -4
  24. package/dist/hooks/{chunk-XPLP27WA.js → chunk-NAS4C7GP.js} +4 -26
  25. package/dist/hooks/{chunk-ZXNE6NY3.js → chunk-NJQOBE6L.js} +2 -2
  26. package/dist/hooks/{chunk-EIFCAJRB.js → chunk-RLDX5SOC.js} +1184 -946
  27. package/dist/hooks/{chunk-HOYJU5RM.js → chunk-WQ4OSBSS.js} +10 -3
  28. package/dist/hooks/codex-hook-adapter.js +10 -10
  29. package/dist/hooks/duplicate-read-guard.js +5 -5
  30. package/dist/hooks/format-edited.js +15 -34
  31. package/dist/hooks/investigation-guard.js +5 -5
  32. package/dist/hooks/pretool-guard.js +23 -16
  33. package/dist/hooks/stop-guard.js +13 -188
  34. package/dist/josh.js +4 -106
  35. package/dist/version/index.js +381 -9
  36. package/package.json +6 -6
  37. package/prompts/collaboration-workflow/file-edits.md +6 -53
  38. package/prompts/collaboration-workflow/residency.md +1 -1
  39. package/prompts/collaboration-workflow/rule-delivery.md +4 -35
  40. package/prompts/collaboration-workflow/shell-body.md +7 -9
  41. package/prompts/collaboration-workflow/turn-batching.md +21 -37
  42. package/prompts/collaboration-workflow/wip-cap.md +15 -18
  43. package/prompts/sonar-hotspot-handling.md +1 -1
  44. package/scripts/adopt/adopt-toolkits.ts +2 -0
  45. package/scripts/auto-ok/auto-ok-cli.ts +9 -9
  46. package/scripts/backlog/backlog-next.ts +24 -8
  47. package/scripts/backlog/backlog-plan-cli.ts +5 -1
  48. package/scripts/backlog/backlog-pool.ts +31 -11
  49. package/scripts/backlog/backlog-rank.ts +106 -0
  50. package/scripts/backlog/backlog-waves.ts +42 -29
  51. package/scripts/build/build-hooks.ts +7 -2
  52. package/scripts/delegation/delegation-policy.ts +11 -0
  53. package/scripts/document/document-byte-budget.ts +5 -5
  54. package/scripts/document/entry-read-budget.ts +5 -4
  55. package/scripts/epic/epic-lane-offer.ts +11 -22
  56. package/scripts/epic/epic-rank.ts +37 -0
  57. package/scripts/epic/epic-solo.ts +29 -28
  58. package/scripts/git/git-command.ts +1 -1
  59. package/scripts/git/git-execa-error.ts +6 -1
  60. package/scripts/git/git-next-issues.ts +34 -5
  61. package/scripts/git/git-preflight.ts +22 -4
  62. package/scripts/git/git-push-transport.ts +12 -69
  63. package/scripts/git/git-spawn.ts +79 -3
  64. package/scripts/git/git-ssh-keepalive.ts +74 -0
  65. package/scripts/git/gone-branch.ts +3 -2
  66. package/scripts/git/issue-labels.ts +12 -0
  67. package/scripts/git/issue-rank.ts +89 -0
  68. package/scripts/hooks/format-edited-cli.ts +15 -0
  69. package/scripts/hooks/format-edited-file.ts +2 -9
  70. package/scripts/hooks/pretool-guard-cli.ts +21 -0
  71. package/scripts/hooks/pretool-guard.ts +14 -15
  72. package/scripts/init/start-exec.ts +7 -1
  73. package/scripts/init/start-plan.ts +18 -5
  74. package/scripts/init/start-setup-pr.ts +46 -19
  75. package/scripts/init/start-steps.ts +41 -9
  76. package/scripts/init/start.ts +40 -10
  77. package/scripts/issue/issue-cite.ts +19 -1
  78. package/scripts/josh/josh-command-map.ts +0 -102
  79. package/scripts/josh/josh-commands-development.ts +2 -2
  80. package/scripts/josh/josh-commands-project.ts +1 -1
  81. package/scripts/lane/lane-child-marker.ts +16 -2
  82. package/scripts/lane/lane-cli.ts +32 -14
  83. package/scripts/lane/lane-report.ts +10 -4
  84. package/scripts/propagate/propagate-plan.ts +185 -0
  85. package/scripts/propagate/propagate-run.ts +5 -1
  86. package/scripts/propagate/propagate-steps.ts +16 -1
  87. package/scripts/propagate/propagate-targets.ts +13 -2
  88. package/scripts/propagate/propagate.ts +60 -42
  89. package/scripts/registry-migration/migrate-logic.ts +1 -0
  90. package/scripts/release/github-release.ts +1 -1
  91. package/scripts/review/review-attest.ts +44 -0
  92. package/scripts/review/review-brief-cli.ts +49 -2
  93. package/scripts/review/review-brief.ts +46 -1
  94. package/scripts/review/review-stamps.ts +7 -0
  95. package/scripts/rules/implementation-cut.ts +1 -1
  96. package/scripts/rules/issue-fold.ts +1 -2
  97. package/scripts/rules/lane-carry-conflict.ts +1 -2
  98. package/scripts/rules/lane-park.ts +1 -2
  99. package/scripts/rules/pre-gate-cut.ts +2 -2
  100. package/scripts/run/run-headless.ts +22 -6
  101. package/scripts/run/run-parent-cut-hook.ts +144 -0
  102. package/scripts/run/run-progress-read.ts +2 -1
  103. package/scripts/run/run-progress.ts +21 -8
  104. package/scripts/run/run-ship-cli.ts +6 -74
  105. package/scripts/run/run-ship-preflight.ts +87 -0
  106. package/scripts/run/run-ship-review-steps.ts +5 -26
  107. package/scripts/run/run-ship-review.ts +9 -0
  108. package/scripts/run/run-ship-scoped.ts +44 -0
  109. package/scripts/run/run-ship-stage.ts +5 -1
  110. package/scripts/run/run-ship-steps.ts +105 -0
  111. package/scripts/run/run-ship.ts +2 -0
  112. package/scripts/run/run-wake-cli.ts +2 -2
  113. package/scripts/run/run-wake-describe.ts +19 -1
  114. package/scripts/run/run-watcher-hook.ts +1 -1
  115. package/scripts/time-runtime/time-bundle-call.ts +2 -2
  116. package/scripts/version/npm-registry.ts +97 -0
  117. package/scripts/version/version-commands.ts +5 -4
  118. package/scripts/version/version-remote.ts +26 -12
@@ -151,7 +151,7 @@ function resolve_effective_upstream_version(base_url, package_name, options = {}
151
151
  }
152
152
 
153
153
  // scripts/version/version-commands.ts
154
- import { execaSync as execaSync3 } from "execa";
154
+ import { execaSync as execaSync4 } from "execa";
155
155
 
156
156
  // scripts/version/release-age.ts
157
157
  import { readFileSync as readFileSync2 } from "node:fs";
@@ -808,6 +808,373 @@ var git_gh_exec = {
808
808
  parse_status_line
809
809
  };
810
810
 
811
+ // scripts/gh/fix-gh-packages-logic.ts
812
+ import { loadAll } from "js-yaml";
813
+ import { z as z4 } from "zod";
814
+ var GH_PACKAGES_HOST = "npm.pkg.github.com";
815
+ var RESOLUTION_BLOCK = "\n resolution:\n";
816
+ var INTEGRITY_PREFIX = " integrity: ";
817
+ var TARBALL_PREFIX = " tarball: ";
818
+ var FLOW_RESOLUTION_LINE_START = "\n resolution: {";
819
+ var FLOW_TARBALL_KEY = ", tarball: ";
820
+ var NPMRC_AUTH_TOKEN_PREFIX = `//${GH_PACKAGES_HOST}/:_authToken=`;
821
+ var REGISTRY_KEY = ":registry=";
822
+ var lockfile_resolution_schema = z4.looseObject({
823
+ integrity: z4.string().optional(),
824
+ tarball: z4.string().optional()
825
+ });
826
+ var lockfile_package_schema = z4.looseObject({
827
+ resolution: lockfile_resolution_schema.optional()
828
+ });
829
+ var lockfile_document_schema = z4.looseObject({
830
+ packages: z4.record(z4.string(), lockfile_package_schema).optional()
831
+ });
832
+ function parse_lockfile_packages(raw) {
833
+ const merged = {};
834
+ for (const document of loadAll(raw)) {
835
+ const { packages } = lockfile_document_schema.parse(document);
836
+ if (packages !== void 0) Object.assign(merged, packages);
837
+ }
838
+ return merged;
839
+ }
840
+ function extract_gh_registry_scope(line) {
841
+ const trimmed = line.trim();
842
+ if (!trimmed.startsWith("@")) return void 0;
843
+ const eq_index = trimmed.indexOf(REGISTRY_KEY);
844
+ if (eq_index === -1) return void 0;
845
+ const registry = trimmed.slice(eq_index + REGISTRY_KEY.length).trim().replace(/\/$/u, "");
846
+ if (registry !== `https://${GH_PACKAGES_HOST}`) return void 0;
847
+ return trimmed.slice(0, eq_index);
848
+ }
849
+ function parse_gh_scopes(npmrc) {
850
+ const scopes = /* @__PURE__ */ new Set();
851
+ for (const line of npmrc.split("\n")) {
852
+ const scope = extract_gh_registry_scope(line);
853
+ if (scope !== void 0) scopes.add(scope);
854
+ }
855
+ return scopes;
856
+ }
857
+ function extract_auth_token_from_line(line) {
858
+ const trimmed = line.trim();
859
+ if (!trimmed.startsWith(NPMRC_AUTH_TOKEN_PREFIX)) return void 0;
860
+ const value = trimmed.slice(NPMRC_AUTH_TOKEN_PREFIX.length);
861
+ if (value.startsWith("${") || value.length === 0) return void 0;
862
+ return value;
863
+ }
864
+ function parse_npmrc_auth_token(npmrc) {
865
+ for (const line of npmrc.split("\n")) {
866
+ const token = extract_auth_token_from_line(line);
867
+ if (token !== void 0) return token;
868
+ }
869
+ return void 0;
870
+ }
871
+ function scope_from_key(key) {
872
+ return key.startsWith("@") ? key.split("/", 1)[0] ?? "" : "";
873
+ }
874
+ function has_tarball(entry) {
875
+ return entry.resolution?.tarball !== void 0;
876
+ }
877
+ function package_path_from_key(key) {
878
+ const start = key.startsWith("@") ? 1 : 0;
879
+ const at_index = key.indexOf("@", start);
880
+ return at_index === -1 ? key : key.slice(0, at_index);
881
+ }
882
+ function package_version_from_key(key) {
883
+ const start = key.startsWith("@") ? 1 : 0;
884
+ const at_index = key.indexOf("@", start);
885
+ if (at_index === -1) return "";
886
+ return key.slice(at_index + 1).split("(", 1)[0] ?? "";
887
+ }
888
+ function should_fix_tarball(key, entry, scopes) {
889
+ if (has_tarball(entry)) return false;
890
+ const scope = scope_from_key(key);
891
+ return scope.length > 0 && scopes.has(scope);
892
+ }
893
+ function find_entry_start(content, package_key) {
894
+ const single = content.indexOf(`
895
+ '${package_key}':
896
+ `);
897
+ if (single !== -1) return single;
898
+ return content.indexOf(`
899
+ "${package_key}":
900
+ `);
901
+ }
902
+ function find_entry_end(content, entry_start) {
903
+ const next_match = /\n {2}['"]/u.exec(content.slice(entry_start + 1));
904
+ return next_match === null ? content.length : entry_start + 1 + next_match.index;
905
+ }
906
+ function find_integrity_eol_in_entry(entry_content) {
907
+ const resolution_pos = entry_content.indexOf(RESOLUTION_BLOCK);
908
+ if (resolution_pos === -1) return -1;
909
+ const integrity_pos = entry_content.indexOf(INTEGRITY_PREFIX, resolution_pos);
910
+ if (integrity_pos === -1) return -1;
911
+ return entry_content.indexOf("\n", integrity_pos);
912
+ }
913
+ function find_flow_resolution_brace(entry_content) {
914
+ const pos = entry_content.indexOf(FLOW_RESOLUTION_LINE_START);
915
+ if (pos === -1) return -1;
916
+ const line_end = entry_content.indexOf("\n", pos + 1);
917
+ const search_end = line_end === -1 ? entry_content.length : line_end;
918
+ const brace = entry_content.lastIndexOf("}", search_end);
919
+ if (brace <= pos) return -1;
920
+ return brace;
921
+ }
922
+ function insert_expanded_tarball(content, entry_start, entry_end, tarball) {
923
+ const entry_content = content.slice(entry_start, entry_end);
924
+ const integrity_eol = find_integrity_eol_in_entry(entry_content);
925
+ if (integrity_eol === -1) return void 0;
926
+ if (entry_content.slice(integrity_eol + 1).startsWith(TARBALL_PREFIX)) return content;
927
+ const patched = `${entry_content.slice(0, integrity_eol + 1)}${TARBALL_PREFIX}${tarball}
928
+ ${entry_content.slice(integrity_eol + 1)}`;
929
+ return content.slice(0, entry_start) + patched + content.slice(entry_end);
930
+ }
931
+ function insert_flow_tarball(content, entry_start, entry_end, tarball) {
932
+ const entry_content = content.slice(entry_start, entry_end);
933
+ const brace_pos = find_flow_resolution_brace(entry_content);
934
+ if (brace_pos === -1) return void 0;
935
+ const open_brace = entry_content.lastIndexOf("{", brace_pos);
936
+ if (open_brace === -1) return void 0;
937
+ const flow_body = entry_content.slice(open_brace + 1, brace_pos);
938
+ if (/\btarball\s*:/u.test(flow_body)) return content;
939
+ const patched = `${entry_content.slice(0, brace_pos)}${FLOW_TARBALL_KEY}${tarball}${entry_content.slice(brace_pos)}`;
940
+ return content.slice(0, entry_start) + patched + content.slice(entry_end);
941
+ }
942
+ function insert_tarball_for_key(content, package_key, tarball) {
943
+ const entry_start = find_entry_start(content, package_key);
944
+ if (entry_start === -1) return content;
945
+ const entry_end = find_entry_end(content, entry_start);
946
+ return insert_expanded_tarball(content, entry_start, entry_end, tarball) ?? insert_flow_tarball(content, entry_start, entry_end, tarball) ?? content;
947
+ }
948
+ function patch_lockfile(content, patches) {
949
+ let result = content;
950
+ for (const [key, tarball] of patches) {
951
+ result = insert_tarball_for_key(result, key, tarball);
952
+ }
953
+ return result;
954
+ }
955
+ function resolve_token(environment_token, npmrc_token, get_fallback_token) {
956
+ if (environment_token !== void 0 && environment_token.length > 0) return environment_token;
957
+ if (npmrc_token !== void 0) return npmrc_token;
958
+ return get_fallback_token();
959
+ }
960
+ var fix_gh_packages_logic = {
961
+ parse_gh_scopes,
962
+ parse_npmrc_auth_token,
963
+ parse_lockfile_packages,
964
+ package_path_from_key,
965
+ package_version_from_key,
966
+ needs_tarball_fix: should_fix_tarball,
967
+ insert_tarball_for_key,
968
+ patch_lockfile,
969
+ resolve_token
970
+ };
971
+
972
+ // scripts/registry-migration/migrate-logic.ts
973
+ var SCOPE = "@joshuafolkken";
974
+ var REGISTRY_KEY2 = `${SCOPE}:registry`;
975
+ var PUBLIC_REGISTRY = "https://registry.npmjs.org/";
976
+ var GITHUB_REGISTRY = "https://npm.pkg.github.com/";
977
+ var MAPPING = `${REGISTRY_KEY2}=${PUBLIC_REGISTRY}`;
978
+ var REGISTRY_VALUE_INDEX = 1;
979
+ var SPLIT_LIMIT = 2;
980
+ function normalized_registry(value) {
981
+ let normalized = value.trim();
982
+ while (normalized.endsWith("/")) normalized = normalized.slice(0, -1);
983
+ return `${normalized}/`;
984
+ }
985
+ function mapping_lines(content) {
986
+ return content.split(/\r?\n/u).filter((line) => line.trimStart().startsWith(`${REGISTRY_KEY2}=`));
987
+ }
988
+ function registry_of(content) {
989
+ const lines = mapping_lines(content);
990
+ if (lines.length !== 1) return void 0;
991
+ return normalized_registry(lines[0]?.split("=", SPLIT_LIMIT)[REGISTRY_VALUE_INDEX] ?? "");
992
+ }
993
+ function scoped_packages(lockfile) {
994
+ const packages = fix_gh_packages_logic.parse_lockfile_packages(lockfile);
995
+ return Object.keys(packages).filter((key) => key.startsWith(`${SCOPE}/`)).map((key) => fix_gh_packages_logic.package_path_from_key(key)).filter((name, index, names) => names.indexOf(name) === index);
996
+ }
997
+ function scoped_versions(lockfile) {
998
+ const packages = fix_gh_packages_logic.parse_lockfile_packages(lockfile);
999
+ return Object.keys(packages).filter((key) => key.startsWith(`${SCOPE}/`)).map(
1000
+ (key) => [
1001
+ fix_gh_packages_logic.package_path_from_key(key),
1002
+ fix_gh_packages_logic.package_version_from_key(key)
1003
+ ]
1004
+ );
1005
+ }
1006
+ function is_github_tarball(value) {
1007
+ try {
1008
+ const url = new URL(value);
1009
+ return url.protocol === "https:" && url.hostname === "npm.pkg.github.com";
1010
+ } catch {
1011
+ return false;
1012
+ }
1013
+ }
1014
+ function github_tarballs(lockfile) {
1015
+ const packages = fix_gh_packages_logic.parse_lockfile_packages(lockfile);
1016
+ return Object.entries(packages).filter(
1017
+ ([key, entry]) => key.startsWith(`${SCOPE}/`) && entry.resolution?.tarball !== void 0 && is_github_tarball(entry.resolution.tarball)
1018
+ ).map(([key]) => key);
1019
+ }
1020
+ function remove_flow_tarball(line) {
1021
+ const marker = ", tarball: https://npm.pkg.github.com/";
1022
+ const start = line.indexOf(marker);
1023
+ if (start === -1) return line;
1024
+ const end = line.indexOf("}", start);
1025
+ if (end === -1) return line;
1026
+ return `${line.slice(0, start)}${line.slice(end)}`;
1027
+ }
1028
+ function is_package_entry(line) {
1029
+ return /^ {2}[^ ]/u.test(line);
1030
+ }
1031
+ function is_github_tarball_line(line) {
1032
+ return line.trimStart().startsWith("tarball: https://npm.pkg.github.com/");
1033
+ }
1034
+ function clean_kit_line(line, version, integrities) {
1035
+ if (!version) return line;
1036
+ if (is_github_tarball_line(line)) return void 0;
1037
+ const cleaned = remove_flow_tarball(line);
1038
+ const pair = integrities.get(version);
1039
+ if (pair === void 0) return cleaned;
1040
+ return cleaned.split(`integrity: ${pair[0]}`).join(`integrity: ${pair[1]}`);
1041
+ }
1042
+ function next_kit_version(line, version) {
1043
+ if (!is_package_entry(line)) return version;
1044
+ const prefix = " '@joshuafolkken/kit@";
1045
+ return line.startsWith(prefix) ? line.slice(prefix.length).split("'", 1)[0] ?? "" : "";
1046
+ }
1047
+ function integrity_pair(old_integrity, npm_integrity) {
1048
+ if (old_integrity === void 0 || npm_integrity === void 0) return void 0;
1049
+ return [old_integrity, npm_integrity];
1050
+ }
1051
+ function lock_integrities(lockfile, npm_integrities) {
1052
+ const packages = fix_gh_packages_logic.parse_lockfile_packages(lockfile);
1053
+ const pairs = /* @__PURE__ */ new Map();
1054
+ const kit_entries = Object.entries(packages).filter(([key]) => key.startsWith(`${SCOPE}/kit@`));
1055
+ for (const [key, entry] of kit_entries) {
1056
+ const version = fix_gh_packages_logic.package_version_from_key(key);
1057
+ const pair = integrity_pair(entry.resolution?.integrity, npm_integrities.get(version));
1058
+ if (pair !== void 0) pairs.set(version, pair);
1059
+ }
1060
+ return pairs;
1061
+ }
1062
+ function push_if_defined(lines, cleaned) {
1063
+ if (cleaned !== void 0) lines.push(cleaned);
1064
+ }
1065
+ function rewrite_kit_lockfile(lockfile, npm_integrities) {
1066
+ let kit_version = "";
1067
+ const lines = [];
1068
+ const integrities = lock_integrities(lockfile, npm_integrities);
1069
+ for (const line of lockfile.split("\n")) {
1070
+ kit_version = next_kit_version(line, kit_version);
1071
+ const cleaned = clean_kit_line(line, kit_version, integrities);
1072
+ push_if_defined(lines, cleaned);
1073
+ }
1074
+ return lines.join("\n");
1075
+ }
1076
+ function append_mapping(content, eol) {
1077
+ const separator = content && !content.endsWith("\n") ? eol : "";
1078
+ return `${content}${separator}${MAPPING}${eol}`;
1079
+ }
1080
+ function replace_mapping(content) {
1081
+ const lines = mapping_lines(content);
1082
+ const eol = content.includes("\r\n") ? "\r\n" : "\n";
1083
+ if (lines.length === 0) return append_mapping(content, eol);
1084
+ return content.split(/\r?\n/u).map((line) => line === lines[0] ? MAPPING : line).join(eol);
1085
+ }
1086
+ function unsupported_registry(project_npmrc) {
1087
+ const registry = registry_of(project_npmrc);
1088
+ if (registry === void 0 || [GITHUB_REGISTRY, PUBLIC_REGISTRY].includes(registry)) {
1089
+ return void 0;
1090
+ }
1091
+ return `unsupported project registry: ${registry}`;
1092
+ }
1093
+ function has_duplicate_mapping(project_npmrc, user_npmrc) {
1094
+ return mapping_lines(project_npmrc).length > 1 || mapping_lines(user_npmrc).length > 1;
1095
+ }
1096
+ function previous_registry(project_npmrc, user_npmrc) {
1097
+ return registry_of(project_npmrc) ?? registry_of(user_npmrc) ?? "default npm";
1098
+ }
1099
+ function plan(project_npmrc, user_npmrc, lockfile) {
1100
+ const packages = scoped_packages(lockfile);
1101
+ const blocked = packages.filter((name) => name !== `${SCOPE}/kit`);
1102
+ if (has_duplicate_mapping(project_npmrc, user_npmrc)) blocked.push("duplicate registry mappings");
1103
+ const unsupported = unsupported_registry(project_npmrc);
1104
+ if (unsupported !== void 0) blocked.push(unsupported);
1105
+ const before = previous_registry(project_npmrc, user_npmrc);
1106
+ const change = `${before} \u2192 ${PUBLIC_REGISTRY}`;
1107
+ return { content: replace_mapping(project_npmrc), packages, blocked, change };
1108
+ }
1109
+ var migrate_logic = {
1110
+ plan,
1111
+ github_tarballs,
1112
+ is_github_tarball,
1113
+ rewrite_kit_lockfile,
1114
+ registry_of,
1115
+ scoped_packages,
1116
+ scoped_versions
1117
+ };
1118
+
1119
+ // scripts/version/npm-registry.ts
1120
+ import { execaSync as execaSync2 } from "execa";
1121
+ import { z as z5 } from "zod";
1122
+ var PUBLIC_REGISTRY2 = "https://registry.npmjs.org";
1123
+ var ABBREVIATED_ACCEPT = "application/vnd.npm.install-v1+json";
1124
+ var FULL_ACCEPT = "application/json";
1125
+ var REQUEST_TIMEOUT_MS = 1e4;
1126
+ var SCOPE_SEPARATOR = "/";
1127
+ var ENCODED_SCOPE_SEPARATOR = "%2f";
1128
+ var SCOPE_PATTERN = /^@[^/]+(?=\/)/u;
1129
+ var SCOPE_REGISTRY_SUFFIX = ":registry";
1130
+ var github_scopes = /* @__PURE__ */ new Map();
1131
+ var FETCH_SCRIPT = [
1132
+ "const [url, accept] = process.argv.slice(1)",
1133
+ "const response = await fetch(url, { headers: { accept } })",
1134
+ "if (!response.ok) process.exit(1)",
1135
+ "process.stdout.write(await response.text())"
1136
+ ].join("\n");
1137
+ var latest_schema = z5.looseObject({ "dist-tags": z5.looseObject({ latest: z5.string() }) });
1138
+ var times_schema = z5.looseObject({ time: release_age.release_times_schema });
1139
+ function packument_url(package_name) {
1140
+ return `${PUBLIC_REGISTRY2}/${package_name.replace(SCOPE_SEPARATOR, () => ENCODED_SCOPE_SEPARATOR)}`;
1141
+ }
1142
+ function read_packument(package_name, accept) {
1143
+ const result = execaSync2(
1144
+ process.execPath,
1145
+ ["--input-type=module", "-e", FETCH_SCRIPT, packument_url(package_name), accept],
1146
+ { reject: false, timeout: REQUEST_TIMEOUT_MS }
1147
+ );
1148
+ if (result.exitCode !== 0) return void 0;
1149
+ return safe_json_parse(result.stdout);
1150
+ }
1151
+ function is_github_scope(scope) {
1152
+ const is_cached_github = github_scopes.get(scope);
1153
+ if (is_cached_github !== void 0) return is_cached_github;
1154
+ const result = execaSync2("pnpm", ["config", "get", `${scope}${SCOPE_REGISTRY_SUFFIX}`], {
1155
+ reject: false,
1156
+ timeout: REQUEST_TIMEOUT_MS
1157
+ });
1158
+ const is_github = result.exitCode === 0 && migrate_logic.is_github_tarball(result.stdout.trim());
1159
+ github_scopes.set(scope, is_github);
1160
+ return is_github;
1161
+ }
1162
+ function is_public_source(package_name) {
1163
+ const scope = SCOPE_PATTERN.exec(package_name)?.[0];
1164
+ return scope === void 0 || !is_github_scope(scope);
1165
+ }
1166
+ function read_latest(package_name) {
1167
+ if (!is_public_source(package_name)) return void 0;
1168
+ const parsed = latest_schema.safeParse(read_packument(package_name, ABBREVIATED_ACCEPT));
1169
+ return parsed.success ? parsed.data["dist-tags"].latest : void 0;
1170
+ }
1171
+ function read_release_times(package_name) {
1172
+ if (!is_public_source(package_name)) return void 0;
1173
+ const parsed = times_schema.safeParse(read_packument(package_name, FULL_ACCEPT));
1174
+ return parsed.success ? parsed.data.time : void 0;
1175
+ }
1176
+ var npm_registry = { packument_url, read_latest, read_release_times };
1177
+
811
1178
  // scripts/version/version-remote.ts
812
1179
  var TIMES_PAGE_SIZE = 100;
813
1180
  var TIMES_JQ = "[.[] | {(.name): .created_at}] | add";
@@ -819,6 +1186,8 @@ function require_endpoint(versions_endpoint, package_name) {
819
1186
  }
820
1187
  function fetch_latest_version(versions_endpoint, package_name) {
821
1188
  const endpoint = require_endpoint(versions_endpoint, package_name);
1189
+ const public_latest = npm_registry.read_latest(package_name);
1190
+ if (public_latest !== void 0) return public_latest;
822
1191
  try {
823
1192
  return git_gh_exec.exec_gh_api_sync({ path: endpoint, jq_filter: ".[0].name" }).trim();
824
1193
  } catch (error) {
@@ -838,14 +1207,17 @@ function with_page_size(endpoint, page_size) {
838
1207
  query.set("per_page", String(page_size));
839
1208
  return `${path_part}?${query.toString()}`;
840
1209
  }
841
- function fetch_release_times(versions_endpoint) {
842
- if (versions_endpoint === void 0 || versions_endpoint.trim() === "") return void 0;
1210
+ function read_github_release_times(versions_endpoint) {
843
1211
  const endpoint = with_page_size(versions_endpoint, TIMES_PAGE_SIZE);
844
1212
  const stdout = git_gh_exec.read_gh_api_sync({ path: endpoint, jq_filter: TIMES_JQ });
845
1213
  if (stdout === void 0) return void 0;
846
1214
  const parsed = release_age.release_times_schema.safeParse(safe_json_parse(stdout));
847
1215
  return parsed.success ? parsed.data : void 0;
848
1216
  }
1217
+ function fetch_release_times(versions_endpoint, package_name) {
1218
+ if (versions_endpoint === void 0 || versions_endpoint.trim() === "") return void 0;
1219
+ return npm_registry.read_release_times(package_name) ?? read_github_release_times(versions_endpoint);
1220
+ }
849
1221
 
850
1222
  // scripts/version/version-targets.ts
851
1223
  import path4 from "node:path";
@@ -877,7 +1249,7 @@ function read_if_readable(path5) {
877
1249
  var file_reader = { read_optional, read_file_or_empty, read_if_readable };
878
1250
 
879
1251
  // scripts/version/version-targets.ts
880
- import { execaSync as execaSync2 } from "execa";
1252
+ import { execaSync as execaSync3 } from "execa";
881
1253
  var NODE_MODULES2 = "node_modules";
882
1254
  var PACKAGE_JSON3 = "package.json";
883
1255
  function build_pnpm_ls_arguments(package_name) {
@@ -894,7 +1266,7 @@ function parse_project_version(raw) {
894
1266
  return parsed.success ? parsed.data.version : void 0;
895
1267
  }
896
1268
  function read_global_version(package_name) {
897
- const result = execaSync2("pnpm", build_pnpm_ls_arguments(package_name), { reject: false });
1269
+ const result = execaSync3("pnpm", build_pnpm_ls_arguments(package_name), { reject: false });
898
1270
  return parse_global_version(result.stdout, package_name);
899
1271
  }
900
1272
  function project_package_path(cwd, package_name) {
@@ -928,12 +1300,12 @@ var version_targets = {
928
1300
  var FAILURE_EXIT_CODE = 1;
929
1301
  var ALREADY_UP_TO_DATE = "Already up to date";
930
1302
  var NO_QUARANTINE_MINUTES2 = 0;
931
- function read_release_hold(versions_endpoint, latest, versions) {
1303
+ function read_release_hold(package_config, latest, versions) {
932
1304
  if (versions.every((version) => version === void 0 || version === latest)) return void 0;
933
1305
  const minimum_age_minutes = release_age.read_nearest_minimum_release_age(process.cwd());
934
1306
  if (minimum_age_minutes <= NO_QUARANTINE_MINUTES2) return void 0;
935
1307
  const installable = release_hold.resolve_installable(
936
- fetch_release_times(versions_endpoint),
1308
+ fetch_release_times(package_config.versions_endpoint, package_config.package_name),
937
1309
  latest,
938
1310
  minimum_age_minutes,
939
1311
  Date.now()
@@ -990,7 +1362,7 @@ function read_upstream_report(upstream, config, snapshot, is_hold_wanted) {
990
1362
  const project_version = version_targets.read_project_version(process.cwd(), upstream.package_name);
991
1363
  const report = { config: upstream, project_version, latest };
992
1364
  attach_upstream_effective(report, config, snapshot, upstream);
993
- const hold = is_hold_wanted ? read_release_hold(upstream.versions_endpoint, latest, [report.effective?.version]) : void 0;
1365
+ const hold = is_hold_wanted ? read_release_hold(upstream, latest, [report.effective?.version]) : void 0;
994
1366
  if (hold !== void 0) report.hold = hold;
995
1367
  return report;
996
1368
  }
@@ -1012,7 +1384,7 @@ function run_check(config) {
1012
1384
  );
1013
1385
  }
1014
1386
  function run_upgrade_command(command) {
1015
- const result = execaSync3("sh", ["-c", command], { stdio: "inherit", reject: false });
1387
+ const result = execaSync4("sh", ["-c", command], { stdio: "inherit", reject: false });
1016
1388
  return result.exitCode ?? FAILURE_EXIT_CODE;
1017
1389
  }
1018
1390
  function run_all_upgrade_commands(commands) {
package/package.json CHANGED
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "1.1035.0",
2
+ "version": "1.1050.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": [
@@ -221,7 +221,7 @@
221
221
  "@playwright/test": "^1.63.0",
222
222
  "@secretlint/secretlint-rule-preset-recommend": "^13.0.6",
223
223
  "@stylistic/eslint-plugin": "^5.10.0",
224
- "@types/node": "^26.6.3",
224
+ "@types/node": "^26.6.4",
225
225
  "@types/semver": "^7.8.0",
226
226
  "cspell": "^10.3.6",
227
227
  "esbuild": "^0.28.2",
@@ -233,17 +233,17 @@
233
233
  "eslint-plugin-sonarjs": "^4.2.2",
234
234
  "eslint-plugin-unicorn": "^76.0.0",
235
235
  "eslint_d": "^15.0.3",
236
- "globals": "^17.12.0",
237
- "lefthook": "^2.1.15",
236
+ "globals": "^17.13.0",
237
+ "lefthook": "^2.1.16",
238
238
  "prettier": "^3.9.9",
239
239
  "prettier-plugin-svelte": "^4.1.1",
240
240
  "prettier-plugin-tailwindcss": "^0.8.1",
241
- "rollup": "^4.63.5",
241
+ "rollup": "^4.63.6",
242
242
  "rollup-plugin-dts": "^6.5.1",
243
243
  "secretlint": "^13.0.6",
244
244
  "typescript": "^6.0.3",
245
245
  "typescript-eslint": "^8.71.0",
246
- "vitest": "^5.0.2"
246
+ "vitest": "^5.0.3"
247
247
  },
248
248
  "dependencies": {
249
249
  "execa": "^10.0.1",
@@ -2,6 +2,8 @@
2
2
 
3
3
  `CLAUDE.md` →「Never carry a file's new text inside a shell command.」の正典。
4
4
 
5
+ `pnpm josh rule:guard`(file-body の行)が、既存ファイルを書き戻すヒアドキュメント・書き込みを伴うインタプリタ heredoc / `node -e`・in-place `perl -0pi -e` をその呼び出しで拒否し、規則を述べる。**このファイルが担うのはガードに見えないもの**である — Bash を通らない Edit / Write の全文書き直し、ガードを素通りする `sed -i` の 4 条件、そしてコストである。
6
+
5
7
  ### 何を禁じているか
6
8
 
7
9
  **編集後のテキストを丸ごとコマンド行に載せる形を禁じる。** 典型は、インタプリタを起動して領域を書き戻す次の形である。
@@ -40,14 +42,7 @@ PY
40
42
 
41
43
  **レビュー指摘の修正がこの規則の主戦場である。** 「この行の条件が逆」「この定数を切り出す」といった局所的な指摘ほど、部分編集は小さくなる。一方で全文書き直しのコストはファイルの大きさで決まり、指摘の小ささでは下がらない。**指摘が局所的であるほど、全文書き直しとの差は開く。**
42
44
 
43
- joshuafolkken/kit#1251 のランで実測した値(joshuafolkken/kit#1260):
44
-
45
- | ターン | 出力トークン | 内容 |
46
- | ------------------ | ------------ | -------------------------------------------------------- |
47
- | レビュー指摘の修正 | 11,104 | 2 ファイルの全文書き直し。そのランの単一ターンとして最大 |
48
- | 同じランの別ターン | 3,282 | 全文書き直し |
49
-
50
- 実効生成速度は約 87 トークン/秒なので、**この 1 ランで約 2 分 45 秒が、すでに存在する行を打ち直すことに使われている。**
45
+ 実測では 1 ランで約 2 分 45 秒が、すでに存在する行を打ち直すことに使われていた(joshuafolkken/kit#1260)。内訳は `docs/maintainers/file-edits-rationale.md` → "全文書き直しの実測"。
51
46
 
52
47
  ### `sed -i` を使う前に満たす 4 条件
53
48
 
@@ -71,54 +66,12 @@ joshuafolkken/kit#1251 のランで実測した値(joshuafolkken/kit#1260):
71
66
 
72
67
  ### なぜコストが二重になるか
73
68
 
74
- インタプリタで書き戻す形は、編集後の本文が**コマンド本文とファイルの両方**に載る。さらに悪いのは持続性である。**コマンド本文は、書いた時点以降のすべてのリクエストで読み直される。** ランの序盤に書いた編集スクリプトほど、そのランの残り全リクエストぶん課金され続ける。ファイル側は次に読んだときだけ載るのに対し、コマンド側は消えない。
75
-
76
- joshuafolkken/kit#1144 のランのトランスクリプトで実測した内訳(joshuafolkken/kit#1150):
77
-
78
- | 種別 | 割合 |
79
- | ----------------------- | --------- |
80
- | tool_result | 37.7% |
81
- | **Bash のコマンド本文** | **30.2%** |
82
- | thinking | 24.9% |
83
- | text | 4.7% |
84
-
85
- Bash コマンド本文 97,042 tok・427 呼び出しの内訳:
86
-
87
- | 種別 | 呼び出し数 | トークン | 割合 |
88
- | ------------------------------------- | ---------- | ---------- | --------- |
89
- | `python3 - <<'PY'` 形式のファイル編集 | 145 | **79,317** | **81.7%** |
90
- | git / gh / pnpm | 140 | 12,716 | 13.1% |
91
- | 読み取り・検索 | 110 | 3,215 | 3.3% |
92
- | その他 | 32 | 1,794 | 1.8% |
93
-
94
- **編集スクリプトだけでセッション全体のコンテキストの約 2 割を占めていた。** 1 回あたり平均 547 tok、上位は 1,200〜1,800 tok。総量そのものより、二重計上と持続が効いている。
95
-
96
- 適用後の再計測は joshuafolkken/kit#1159 が担当する。
69
+ インタプリタで書き戻す形は、編集後の本文が**コマンド本文とファイルの両方**に載る。さらに悪いのは持続性である。**コマンド本文は、書いた時点以降のすべてのリクエストで読み直される。** ランの序盤に書いた編集スクリプトほど、そのランの残り全リクエストぶん課金され続ける。ファイル側は次に読んだときだけ載るのに対し、コマンド側は消えない。実測の内訳は `docs/maintainers/file-edits-rationale.md` → "コマンド本文の実測内訳"。
97
70
 
98
71
  ### なぜ resident に置くか
99
72
 
100
- residency 基準(`residency.md`)は 1 問で決まる。
101
-
102
- > **その規則は、skill がロードされていないターンでも効く必要があるか。**
103
-
104
- 答えは yes である。ファイル編集はワークフローのキーワードが打たれていないターンでも起き、**編集の直前にロードされる skill は存在しない。** skill 側に本体を置いた場合、この規則は一度も発火しない — 規則を書いたのに削除したのと同じ振る舞いになる。
105
-
106
- そのうえで、常駐側に置くのは**トリガと導線だけ**である。常駐側に残すのは次の 3 点で、それだけで正しく振る舞える。
107
-
108
- 1. 領域を指定する編集は Edit で行い、インタプリタや heredoc で領域を書き戻さない
109
- 2. **Edit 自体を全文へ広げない**(joshuafolkken/kit#1260)
110
- 3. 判断基準は「本文を丸ごと運ぶか」であってツール名ではない(短い `sed -i` は許される)
111
-
112
- 実測値・可否表・二重計上の説明・全文書き直しが許される 3 条件、そして**インタプリタの具体形**(`python3 - <<'PY'` / `node -e` / `cat > file <<'EOF'`)はこのファイルにあり、常駐側からは落としている。これらは「読まなくても正しく振る舞えるが、読めばより納得できる」種類の記述だからである。**具体形を指し先へ移したのは削除ではなく移動である** — 禁止の区分は常駐側の「インタプリタや heredoc」が担い、個々の形はこのファイルの可否表が担う。
73
+ 根拠は `docs/maintainers/file-edits-rationale.md` → "なぜ resident に置くか"。
113
74
 
114
75
  ### マーカーテスト
115
76
 
116
- `scripts/document/document-markers.test.ts` が次を固定する。
117
-
118
- - `CLAUDE.md` に規則のトリガ文と判断基準の一文が resident で存在すること
119
- - `CLAUDE.md` に全文書き直しの禁止(「Edit を全文へ広げない」)が resident で存在すること
120
- - 常駐側がこのファイルを導線として指していること
121
- - このファイルが判断基準・可否表・`sed -i` の 4 条件・全文書き直しの 3 条件を持っていること
122
- - インタプリタの具体形 3 つ(`python3 - <<'PY'` / `node -e` / `cat > file <<'EOF'`)が常駐側にも residency 一覧にも残っておらず、このファイルにあること
123
- - 実測値(79,317 / 81.7% / 30.2% / 11,104 / 3,282)が常駐側にも residency 一覧にも貼り戻されていないこと
124
- - residency の一覧(`.claude/skills/workflow-commands/SKILL.md` とこのディレクトリの `residency.md`)にこの規則が載っていること
77
+ 固定している内容は `docs/maintainers/file-edits-rationale.md` → "マーカーテスト"。
@@ -77,7 +77,7 @@
77
77
  - **UI 検証ゲート** — 画面に出る変更は、実際にレンダリング結果を見るまで完了ではない。撮影の手順は `verify-ui` にある。このゲートが効くのは UI 変更の完了を報告する瞬間であり、ワークフローのキーワードが打たれておらず skill が何もロードされていないターンであることが多い
78
78
  - **レビュー上限後の後追い起票の手順** — 起票して `epic:bundle` で EPIC へ繋ぎ直すところまで。コミット前セルフレビューはワークフローの外でも回るので、そこで起票された Issue も同じように孤児になる。完全な手順は `prompts/review.md` →「Review round cap」にある(joshuafolkken/kit#946)
79
79
  - **`josh epic:*` のうちコマンドの外側で効く 3 件** — 決定の記録による `needs-decision` の解除、`epic:audit` の指摘を直すのが Tier A であること、別リポジトリの EPIC を `owner/repo#N` で参照すること。いずれも `epic:*` コマンドを走らせていないターン(Issue を起票した直後、決定を書いた瞬間)に効く。コマンド自身の手順は `.claude/skills/epic-commands/` にある
80
- - **編集後の本文をコマンドに載せない禁止** — ファイル編集はどのターンでも起き、**編集の直前にロードされる skill は存在しない**。オンデマンド側に置くとこの規則は一度も発火せず、書いたのに削除したのと同じ振る舞いになる。実測値・可否表・根拠は [`file-edits.md`](./file-edits.md) にあり、常駐に残すのは指示と判断基準(「本文を丸ごと運ぶか」であってツール名ではない)だけである(joshuafolkken/kit#1150)。**Edit 自体を全文へ広げる形も同じ規則の一部である** — 数行の指摘に対する全文書き直しは、ツールを替えただけで同じコストを払っている。常駐にはその禁止の一句だけを置き、全文を書いてよい 3 条件は同じ指し先にある(joshuafolkken/kit#1260)
80
+ - **編集後の本文をコマンドに載せない禁止** — ファイル編集はどのターンでも起き、**編集の直前にロードされる skill は存在しない**。オンデマンド側に置くとこの規則は一度も発火せず、書いたのに削除したのと同じ振る舞いになる。可否表は [`file-edits.md`](./file-edits.md)、実測値と根拠は [`docs/maintainers/file-edits-rationale.md`](../../docs/maintainers/file-edits-rationale.md) にあり、常駐に残すのは指示と判断基準(「本文を丸ごと運ぶか」であってツール名ではない)だけである(joshuafolkken/kit#1150)。**Edit 自体を全文へ広げる形も同じ規則の一部である** — 数行の指摘に対する全文書き直しは、ツールを替えただけで同じコストを払っている。常駐にはその禁止の一句だけを置き、全文を書いてよい 3 条件は同じ指し先にある(joshuafolkken/kit#1260)
81
81
 
82
82
  **第 1 問で「名指しできる」となり、引き金つき配送へ移したもの**(joshuafolkken/kit#1524)。いずれも本文は消えておらず、規則が効く瞬間にフックが突きつける。下は常駐に 1 行を残した、またはその判断に理由が要った行だけであり、配送されている規則の全体ではない。**列挙表と、引き金が発火しないターンの意味の単一ソースは [`rule-delivery.md`](./rule-delivery.md) であり、ここには行数を写さない** — 2 か所に置いた数は必ずずれる(joshuafolkken/kit#1525)。
83
83